Parse a "key: value" or "key:" line. */
| 199 | |
| 200 | /* Parse a "key: value" or "key:" line. */ |
| 201 | static void parse_key_line(const char *content, int content_len, int indent, |
| 202 | cbm_yaml_node_t *parent, stack_entry_t *stack, int *stack_depth, |
| 203 | const char *eol, const char *end) { |
| 204 | const char *colon = memchr(content, ':', (size_t)content_len); |
| 205 | if (!colon) { |
| 206 | return; |
| 207 | } |
| 208 | |
| 209 | char *key = trim_dup(content, colon); |
| 210 | if (!key) { |
| 211 | return; |
| 212 | } |
| 213 | |
| 214 | /* After colon: value or nothing */ |
| 215 | const char *after = colon + SKIP_ONE; |
| 216 | int after_len = content_len - (int)(after - content); |
| 217 | while (after_len > 0 && isspace((unsigned char)*after)) { |
| 218 | after++; |
| 219 | after_len--; |
| 220 | } |
| 221 | |
| 222 | after_len = strip_inline_comment(after, after_len); |
| 223 | |
| 224 | if (after_len > 0) { |
| 225 | /* "key: value" — scalar */ |
| 226 | cbm_yaml_node_t *child = node_new(YAML_SCALAR); |
| 227 | if (child) { |
| 228 | child->key = key; |
| 229 | child->value = trim_dup(after, after + after_len); |
| 230 | if (!node_add_child(parent, child)) { |
| 231 | cbm_yaml_free(child); |
| 232 | } |
| 233 | } else { |
| 234 | free(key); |
| 235 | } |
| 236 | } else { |
| 237 | /* "key:" — could be map or list (determined by next lines) */ |
| 238 | bool is_list = peek_is_list(eol, end); |
| 239 | cbm_yaml_node_t *child = node_new(is_list ? YAML_LIST : YAML_MAP); |
| 240 | if (child) { |
| 241 | child->key = key; |
| 242 | if (!node_add_child(parent, child)) { |
| 243 | cbm_yaml_free(child); |
| 244 | } else if (*stack_depth < CBM_SZ_32) { |
| 245 | stack[(*stack_depth)++] = (stack_entry_t){.node = child, .indent = indent}; |
| 246 | } |
| 247 | } else { |
| 248 | free(key); |
| 249 | } |
| 250 | } |
| 251 | } |
| 252 | |
| 253 | cbm_yaml_node_t *cbm_yaml_parse(const char *text, int len) { |
| 254 | if (!text || len <= 0) { |
no test coverage detected