1 // SPDX-License-Identifier: LGPL-2.0
4 * Copyright (c) 2014, 2017, Intel Corporation.
8 * This file is part of Lustre, http://www.lustre.org/
10 * The cYAML tree is constructed as an n-tree.
14 * cmd 2 -> attr1 -> attr2
17 * attr2.1 -> attr2.1.1 -> attr2.1.2
19 * Author: Amir Shehata <amir.shehata@intel.com>
32 #include "libcfs/util/list.h"
38 #define PRINT_BUF_LEN 2048
42 * This structure contains print information
43 * required when printing the node
45 struct cYAML_print_info {
53 * Linked list of different trees representing YAML
57 struct list_head list;
59 struct cYAML_print_info *print_info;
62 static void print_value(char **out, struct list_head *stack);
64 enum cYAML_handler_error {
66 CYAML_ERROR_UNEXPECTED_STATE = -1,
67 CYAML_ERROR_NOT_SUPPORTED = -2,
68 CYAML_ERROR_OUT_OF_MEM = -3,
69 CYAML_ERROR_BAD_VALUE = -4,
70 CYAML_ERROR_PARSE = -5,
73 enum cYAML_tree_state {
74 TREE_STATE_COMPLETE = 0,
76 TREE_STATE_TREE_STARTED,
77 TREE_STATE_BLK_STARTED,
79 TREE_STATE_KEY_FILLED,
84 struct cYAML_tree_node {
86 /* cur is the current node we're operating on */
88 enum cYAML_tree_state state;
89 int from_blk_map_start;
90 /* represents the tree depth */
94 typedef enum cYAML_handler_error (*yaml_token_handler)(yaml_token_t *token,
95 struct cYAML_tree_node *);
97 static enum cYAML_handler_error yaml_no_token(yaml_token_t *token,
98 struct cYAML_tree_node *tree);
99 static enum cYAML_handler_error yaml_stream_start(yaml_token_t *token,
100 struct cYAML_tree_node *tree);
101 static enum cYAML_handler_error yaml_stream_end(yaml_token_t *token,
102 struct cYAML_tree_node *tree);
103 static enum cYAML_handler_error yaml_not_supported(yaml_token_t *token,
104 struct cYAML_tree_node *tree);
105 static enum cYAML_handler_error yaml_document_start(yaml_token_t *token,
106 struct cYAML_tree_node *tree);
107 static enum cYAML_handler_error yaml_document_end(yaml_token_t *token,
108 struct cYAML_tree_node *tree);
109 static enum cYAML_handler_error yaml_blk_seq_start(yaml_token_t *token,
110 struct cYAML_tree_node *tree);
111 static enum cYAML_handler_error yaml_blk_mapping_start(yaml_token_t *token,
112 struct cYAML_tree_node *tree);
113 static enum cYAML_handler_error yaml_block_end(yaml_token_t *token,
114 struct cYAML_tree_node *tree);
115 static enum cYAML_handler_error yaml_key(yaml_token_t *token,
116 struct cYAML_tree_node *tree);
117 static enum cYAML_handler_error yaml_value(yaml_token_t *token,
118 struct cYAML_tree_node *tree);
119 static enum cYAML_handler_error yaml_scalar(yaml_token_t *token,
120 struct cYAML_tree_node *tree);
121 static enum cYAML_handler_error yaml_entry_token(yaml_token_t *token,
122 struct cYAML_tree_node *tree);
125 static yaml_token_handler dispatch_tbl[] = {
126 [YAML_NO_TOKEN] = yaml_no_token,
127 [YAML_STREAM_START_TOKEN] = yaml_stream_start,
128 [YAML_STREAM_END_TOKEN] = yaml_stream_end,
129 [YAML_VERSION_DIRECTIVE_TOKEN] = yaml_not_supported,
130 [YAML_TAG_DIRECTIVE_TOKEN] = yaml_not_supported,
131 [YAML_DOCUMENT_START_TOKEN] = yaml_document_start,
132 [YAML_DOCUMENT_END_TOKEN] = yaml_document_end,
133 [YAML_BLOCK_SEQUENCE_START_TOKEN] = yaml_blk_seq_start,
134 [YAML_BLOCK_MAPPING_START_TOKEN] = yaml_blk_mapping_start,
135 [YAML_BLOCK_END_TOKEN] = yaml_block_end,
136 [YAML_FLOW_SEQUENCE_START_TOKEN] = yaml_not_supported,
137 [YAML_FLOW_SEQUENCE_END_TOKEN] = yaml_not_supported,
138 [YAML_FLOW_MAPPING_START_TOKEN] = yaml_not_supported,
139 [YAML_FLOW_MAPPING_END_TOKEN] = yaml_not_supported,
140 [YAML_BLOCK_ENTRY_TOKEN] = yaml_entry_token,
141 [YAML_FLOW_ENTRY_TOKEN] = yaml_not_supported,
142 [YAML_KEY_TOKEN] = yaml_key,
143 [YAML_VALUE_TOKEN] = yaml_value,
144 [YAML_ALIAS_TOKEN] = yaml_not_supported,
145 [YAML_ANCHOR_TOKEN] = yaml_not_supported,
146 [YAML_TAG_TOKEN] = yaml_not_supported,
147 [YAML_SCALAR_TOKEN] = yaml_scalar,
151 static const char * const token_type_string[] = {
152 [YAML_NO_TOKEN] = "YAML_NO_TOKEN",
153 [YAML_STREAM_START_TOKEN] = "YAML_STREAM_START_TOKEN",
154 [YAML_STREAM_END_TOKEN] = "YAML_STREAM_END_TOKEN",
155 [YAML_VERSION_DIRECTIVE_TOKEN] = "YAML_VERSION_DIRECTIVE_TOKEN",
156 [YAML_TAG_DIRECTIVE_TOKEN] = "YAML_TAG_DIRECTIVE_TOKEN",
157 [YAML_DOCUMENT_START_TOKEN] = "YAML_DOCUMENT_START_TOKEN",
158 [YAML_DOCUMENT_END_TOKEN] = "YAML_DOCUMENT_END_TOKEN",
159 [YAML_BLOCK_SEQUENCE_START_TOKEN] = "YAML_BLOCK_SEQUENCE_START_TOKEN",
160 [YAML_BLOCK_MAPPING_START_TOKEN] = "YAML_BLOCK_MAPPING_START_TOKEN",
161 [YAML_BLOCK_END_TOKEN] = "YAML_BLOCK_END_TOKEN",
162 [YAML_FLOW_SEQUENCE_START_TOKEN] = "YAML_FLOW_SEQUENCE_START_TOKEN",
163 [YAML_FLOW_SEQUENCE_END_TOKEN] = "YAML_FLOW_SEQUENCE_END_TOKEN",
164 [YAML_FLOW_MAPPING_START_TOKEN] = "YAML_FLOW_MAPPING_START_TOKEN",
165 [YAML_FLOW_MAPPING_END_TOKEN] = "YAML_FLOW_MAPPING_END_TOKEN",
166 [YAML_BLOCK_ENTRY_TOKEN] = "YAML_BLOCK_ENTRY_TOKEN",
167 [YAML_FLOW_ENTRY_TOKEN] = "YAML_FLOW_ENTRY_TOKEN",
168 [YAML_KEY_TOKEN] = "YAML_KEY_TOKEN",
169 [YAML_VALUE_TOKEN] = "YAML_VALUE_TOKEN",
170 [YAML_ALIAS_TOKEN] = "YAML_ALIAS_TOKEN",
171 [YAML_ANCHOR_TOKEN] = "YAML_ANCHOR_TOKEN",
172 [YAML_TAG_TOKEN] = "YAML_TAG_TOKEN",
173 [YAML_SCALAR_TOKEN] = "YAML_SCALAR_TOKEN",
176 static const char * const state_string[] = {
177 [TREE_STATE_COMPLETE] = "COMPLETE",
178 [TREE_STATE_INITED] = "INITED",
179 [TREE_STATE_TREE_STARTED] = "TREE_STARTED",
180 [TREE_STATE_BLK_STARTED] = "BLK_STARTED",
181 [TREE_STATE_KEY] = "KEY",
182 [TREE_STATE_KEY_FILLED] = "KEY_FILLED",
183 [TREE_STATE_VALUE] = "VALUE",
184 [TREE_STATE_SEQ_START] = "SEQ_START",
187 static void cYAML_ll_free(struct list_head *ll)
189 struct cYAML_ll *node, *tmp;
191 list_for_each_entry_safe(node, tmp, ll, list) {
192 free(node->print_info);
197 static int cYAML_ll_push(struct cYAML *obj,
198 const struct cYAML_print_info *print_info,
199 struct list_head *list)
201 struct cYAML_ll *node = calloc(1, sizeof(*node));
205 INIT_LIST_HEAD(&node->list);
208 node->print_info = calloc(1, sizeof(*print_info));
209 if (node->print_info == NULL) {
213 *node->print_info = *print_info;
217 list_add(&node->list, list);
222 static struct cYAML *cYAML_ll_pop(struct list_head *list,
223 struct cYAML_print_info **print_info)
225 struct cYAML_ll *pop;
226 struct cYAML *obj = NULL;
228 if (!list_empty(list)) {
229 pop = list_first_entry(list, struct cYAML_ll, list);
232 if (print_info != NULL)
233 *print_info = pop->print_info;
234 list_del(&pop->list);
236 if (print_info == NULL)
237 free(pop->print_info);
244 static int cYAML_ll_count(struct list_head *ll)
247 struct list_head *node;
249 list_for_each(node, ll)
255 static int cYAML_tree_init(struct cYAML_tree_node *tree)
257 struct cYAML *obj = NULL, *cur = NULL;
262 obj = calloc(1, sizeof(*obj));
267 /* append the node */
269 while (cur->cy_next != NULL)
276 obj->cy_type = CYAML_TYPE_OBJECT;
279 tree->state = TREE_STATE_COMPLETE;
281 /* free it and start anew */
282 if (!list_empty(&tree->ll))
283 cYAML_ll_free(&tree->ll);
288 static struct cYAML *create_child(struct cYAML *parent)
295 obj = calloc(1, sizeof(*obj));
299 /* set the type to OBJECT and let the value change that */
300 obj->cy_type = CYAML_TYPE_OBJECT;
302 parent->cy_child = obj;
307 static struct cYAML *create_sibling(struct cYAML *sibling)
314 obj = calloc(1, sizeof(*obj));
318 /* set the type to OBJECT and let the value change that */
319 obj->cy_type = CYAML_TYPE_OBJECT;
321 sibling->cy_next = obj;
322 obj->cy_prev = sibling;
327 /* Parse the input text to generate a number,
328 * and populate the result into item. */
329 static bool parse_number(struct cYAML *item, const char *input)
331 double n = 0, sign = 1, scale = 0;
332 int subscale = 0, signsubscale = 1;
333 const char *num = input;
335 if (!strncmp(input, "0x", 2)) {
336 int64_t hex; /* hex input is always an integer */
337 char *invalid = NULL;
340 hex = strtoll(input, &invalid, 16);
346 item->cy_valuedouble = (double) hex;
347 item->cy_valueint = hex;
348 item->cy_type = CYAML_TYPE_NUMBER;
360 if (*num >= '1' && *num <= '9') {
362 n = (n * 10.0) + (*num++ - '0');
363 } while (*num >= '0' && *num <= '9');
366 if (*num == '.' && num[1] >= '0' && num[1] <= '9') {
369 n = (n * 10.0) + (*num++ - '0');
371 } while (*num >= '0' && *num <= '9');
374 if (*num == 'e' || *num == 'E') {
378 } else if (*num == '-') {
382 while (*num >= '0' && *num <= '9')
383 subscale = (subscale * 10) + (*num++ - '0');
386 /* check to see if the entire string is consumed. If not then
387 * that means this is a string with a number in it */
388 if (num != (input + strlen(input)))
391 /* number = +/- number.fraction * 10^+/- exponent */
392 n = sign * n * pow(10.0, (scale + subscale * signsubscale));
394 item->cy_valuedouble = n;
395 item->cy_valueint = (int64_t)n;
396 item->cy_type = CYAML_TYPE_NUMBER;
401 static int assign_type_value(struct cYAML *obj, const char *value)
406 if (strcmp(value, "null") == 0)
407 obj->cy_type = CYAML_TYPE_NULL;
408 else if (strcmp(value, "false") == 0) {
409 obj->cy_type = CYAML_TYPE_FALSE;
410 obj->cy_valueint = 0;
411 } else if (strcmp(value, "true") == 0) {
412 obj->cy_type = CYAML_TYPE_TRUE;
413 obj->cy_valueint = 1;
414 } else if (*value == '-' || (*value >= '0' && *value <= '9')) {
415 if (parse_number(obj, value) == 0) {
416 obj->cy_valuestring = strdup(value);
417 obj->cy_type = CYAML_TYPE_STRING;
420 obj->cy_valuestring = strdup(value);
421 obj->cy_type = CYAML_TYPE_STRING;
429 * Builds the YAML tree rpresentation as the tokens are passed in
431 * if token == STREAM_START && tree_state != COMPLETE
432 * something wrong. fail.
433 * else tree_state = INITIED
434 * if token == DOCUMENT_START && tree_state != COMPLETE || INITED
435 * something wrong, fail.
436 * else tree_state = TREE_STARTED
437 * if token == DOCUMENT_END
438 * tree_state = INITED if no STREAM START, else tree_state = COMPLETE
439 * erase everything on ll
440 * if token == STREAM_END && tree_state != INITED
441 * something wrong fail.
442 * else tree_state = COMPLETED
443 * if token == YAML_KEY_TOKEN && state != TREE_STARTED
444 * something wrong, fail.
445 * if token == YAML_SCALAR_TOKEN && state != KEY || VALUE
447 * else if tree_state == KEY
448 * create a new sibling under the current head of the ll (if ll is
449 * empty insert the new node there and it becomes the root.)
450 * add the scalar value in the "string"
451 * tree_state = KEY_FILLED
452 * else if tree_state == VALUE
453 * try and figure out whether this is a double, int or string and store
455 * state = TREE_STARTED
456 * else if token == YAML_BLOCK_MAPPING_START_TOKEN && tree_state != VALUE
458 * else push the current node on the ll && state = TREE_STARTED
459 * if token == YAML_BLOCK_END_TOKEN && state != TREE_STARTED
461 * else pop the current token off the ll and make it the cur
462 * if token == YAML_VALUE_TOKEN && state != KEY_FILLED
468 static enum cYAML_handler_error yaml_no_token(yaml_token_t *token,
469 struct cYAML_tree_node *tree)
471 return CYAML_ERROR_NONE;
474 static enum cYAML_handler_error yaml_stream_start(yaml_token_t *token,
475 struct cYAML_tree_node *tree)
477 enum cYAML_handler_error rc;
479 /* with each new stream initialize a new tree */
480 rc = cYAML_tree_init(tree);
482 if (rc != CYAML_ERROR_NONE)
485 tree->state = TREE_STATE_INITED;
487 return CYAML_ERROR_NONE;
490 static enum cYAML_handler_error yaml_stream_end(yaml_token_t *token,
491 struct cYAML_tree_node *tree)
493 if (tree->state != TREE_STATE_TREE_STARTED &&
494 tree->state != TREE_STATE_COMPLETE &&
495 tree->state != TREE_STATE_INITED)
496 return CYAML_ERROR_UNEXPECTED_STATE;
498 tree->state = TREE_STATE_INITED;
500 return CYAML_ERROR_NONE;
503 static enum cYAML_handler_error
504 yaml_document_start(yaml_token_t *token, struct cYAML_tree_node *tree)
506 if (tree->state != TREE_STATE_INITED)
507 return CYAML_ERROR_UNEXPECTED_STATE;
509 /* go to started state since we're expecting more tokens to come */
510 tree->state = TREE_STATE_TREE_STARTED;
512 return CYAML_ERROR_NONE;
515 static enum cYAML_handler_error yaml_document_end(yaml_token_t *token,
516 struct cYAML_tree_node *tree)
518 if (tree->state != TREE_STATE_COMPLETE)
519 return CYAML_ERROR_UNEXPECTED_STATE;
521 tree->state = TREE_STATE_TREE_STARTED;
523 return CYAML_ERROR_NONE;
526 static enum cYAML_handler_error yaml_key(yaml_token_t *token,
527 struct cYAML_tree_node *tree)
529 if (tree->state != TREE_STATE_BLK_STARTED &&
530 tree->state != TREE_STATE_VALUE)
531 return CYAML_ERROR_UNEXPECTED_STATE;
533 if (tree->from_blk_map_start == 0 ||
534 tree->state == TREE_STATE_VALUE)
535 tree->cur = create_sibling(tree->cur);
537 tree->from_blk_map_start = 0;
539 tree->state = TREE_STATE_KEY;
541 return CYAML_ERROR_NONE;
544 static enum cYAML_handler_error yaml_scalar(yaml_token_t *token,
545 struct cYAML_tree_node *tree)
547 if (tree->state == TREE_STATE_KEY) {
548 /* assign the scalar value to the key that was created */
549 tree->cur->cy_string =
550 strdup((const char *)token->data.scalar.value);
552 tree->state = TREE_STATE_KEY_FILLED;
553 } else if (tree->state == TREE_STATE_VALUE ||
554 tree->state == TREE_STATE_SEQ_START) {
555 if (assign_type_value(tree->cur,
556 (char *)token->data.scalar.value))
557 /* failed to assign a value */
558 return CYAML_ERROR_BAD_VALUE;
559 tree->state = TREE_STATE_BLK_STARTED;
561 return CYAML_ERROR_UNEXPECTED_STATE;
564 return CYAML_ERROR_NONE;
567 static enum cYAML_handler_error yaml_value(yaml_token_t *token,
568 struct cYAML_tree_node *tree)
570 if (tree->state != TREE_STATE_KEY_FILLED)
571 return CYAML_ERROR_UNEXPECTED_STATE;
573 tree->state = TREE_STATE_VALUE;
575 return CYAML_ERROR_NONE;
578 static enum cYAML_handler_error yaml_blk_seq_start(yaml_token_t *token,
579 struct cYAML_tree_node *tree)
581 if (tree->state != TREE_STATE_VALUE)
582 return CYAML_ERROR_UNEXPECTED_STATE;
584 /* Since a sequenc start event determines that this is the start
585 * of an array, then that means the current node we're at is an
586 * array and we need to flag it as such */
587 tree->cur->cy_type = CYAML_TYPE_ARRAY;
588 tree->state = TREE_STATE_SEQ_START;
590 return CYAML_ERROR_NONE;
593 static enum cYAML_handler_error yaml_entry_token(yaml_token_t *token,
594 struct cYAML_tree_node *tree)
598 if (tree->state != TREE_STATE_SEQ_START &&
599 tree->state != TREE_STATE_BLK_STARTED &&
600 tree->state != TREE_STATE_VALUE)
601 return CYAML_ERROR_UNEXPECTED_STATE;
603 if (tree->state == TREE_STATE_SEQ_START) {
604 obj = create_child(tree->cur);
606 if (cYAML_ll_push(tree->cur, NULL, &tree->ll))
607 return CYAML_ERROR_OUT_OF_MEM;
611 tree->cur = create_sibling(tree->cur);
612 tree->state = TREE_STATE_SEQ_START;
615 return CYAML_ERROR_NONE;
618 static enum cYAML_handler_error
619 yaml_blk_mapping_start(yaml_token_t *token,
620 struct cYAML_tree_node *tree)
624 if (tree->state != TREE_STATE_VALUE &&
625 tree->state != TREE_STATE_INITED &&
626 tree->state != TREE_STATE_SEQ_START &&
627 tree->state != TREE_STATE_TREE_STARTED)
628 return CYAML_ERROR_UNEXPECTED_STATE;
630 /* block_mapping_start means we're entering another block
631 * indentation, so we need to go one level deeper
632 * create a child of cur */
633 obj = create_child(tree->cur);
635 /* push cur on the stack */
636 if (cYAML_ll_push(tree->cur, NULL, &tree->ll))
637 return CYAML_ERROR_OUT_OF_MEM;
639 /* adding the new child to cur */
642 tree->state = TREE_STATE_BLK_STARTED;
644 tree->from_blk_map_start = 1;
646 return CYAML_ERROR_NONE;
649 static enum cYAML_handler_error yaml_block_end(yaml_token_t *token,
650 struct cYAML_tree_node *tree)
652 if (tree->state != TREE_STATE_BLK_STARTED &&
653 tree->state != TREE_STATE_VALUE)
654 return CYAML_ERROR_UNEXPECTED_STATE;
656 tree->cur = cYAML_ll_pop(&tree->ll, NULL);
658 /* if you have popped all the way to the top level, then move to
659 * the complete state. */
660 if (cYAML_ll_count(&tree->ll) == 0)
661 tree->state = TREE_STATE_COMPLETE;
662 else if (tree->state == TREE_STATE_VALUE)
663 tree->state = TREE_STATE_BLK_STARTED;
665 return CYAML_ERROR_NONE;
668 static enum cYAML_handler_error yaml_not_supported(yaml_token_t *token,
669 struct cYAML_tree_node *tree)
671 return CYAML_ERROR_NOT_SUPPORTED;
674 static bool clean_usr_data(struct cYAML *node, void *usr_data, void **out)
676 cYAML_user_data_free_cb free_cb = usr_data;
678 if (free_cb && node && node->cy_user_data) {
679 free_cb(node->cy_user_data);
680 node->cy_user_data = NULL;
686 static bool free_node(struct cYAML *node, void *user_data, void **out)
691 if (node->cy_type == CYAML_TYPE_STRING)
692 free(node->cy_valuestring);
694 free(node->cy_string);
700 static bool find_obj_iter(struct cYAML *node, void *usr_data, void **out)
702 char *name = usr_data;
704 if (node != NULL && node->cy_string != NULL &&
705 strcmp(node->cy_string, name) == 0) {
713 struct cYAML *cYAML_get_object_item(struct cYAML *parent, const char *name)
715 struct cYAML *node = parent, *found = NULL;
720 if (node->cy_string) {
721 if (strcmp(node->cy_string, name) == 0)
726 found = cYAML_get_object_item(node->cy_child, name);
728 if (!found && node->cy_next)
729 found = cYAML_get_object_item(node->cy_next, name);
734 struct cYAML *cYAML_get_next_seq_item(struct cYAML *seq, struct cYAML **itm)
736 if (*itm != NULL && (*itm)->cy_next != NULL) {
737 *itm = (*itm)->cy_next;
741 if (*itm == NULL && seq->cy_type == CYAML_TYPE_ARRAY) {
742 *itm = seq->cy_child;
749 bool cYAML_is_sequence(struct cYAML *node)
751 return (node != NULL ? node->cy_type == CYAML_TYPE_ARRAY : 0);
754 static void cYAML_tree_recursive_walk(struct cYAML *node, cYAML_walk_cb cb,
763 if (!cb(node, usr_data, out))
768 cYAML_tree_recursive_walk(node->cy_child, cb,
769 cb_first, usr_data, out);
772 cYAML_tree_recursive_walk(node->cy_next, cb,
773 cb_first, usr_data, out);
776 if (!cb(node, usr_data, out))
781 struct cYAML *cYAML_find_object(struct cYAML *root, const char *name)
783 struct cYAML *found = NULL;
785 cYAML_tree_recursive_walk(root, find_obj_iter, true,
786 (void *)name, (void **)&found);
791 void cYAML_clean_usr_data(struct cYAML *node, cYAML_user_data_free_cb free_cb)
793 cYAML_tree_recursive_walk(node, clean_usr_data, false, free_cb, NULL);
796 void cYAML_free_tree(struct cYAML *node)
798 cYAML_tree_recursive_walk(node, free_node, false, NULL, NULL);
801 static char *ensure(char *in, int len)
807 return (char*)calloc(len, 1);
809 curlen = strlen(in) + 1;
811 if (curlen <= curlen + len) {
812 new = calloc(curlen + len, 1);
824 static inline void print_simple(char **out, struct cYAML *node,
825 struct cYAML_print_info *cpi)
827 int level = cpi->level;
828 int ind = cpi->extra_ind;
830 int len = (INDENT * level + ind) * 2 +
831 ((node->cy_string) ? strlen(node->cy_string) : 0) + LEAD_ROOM;
833 *out = ensure(*out, len);
837 tmp = ensure(tmp, len);
841 if (cpi->array_first_elem) {
842 sprintf(tmp, "%*s- ", INDENT * level, "");
846 sprintf(tmp, "%*s""%s: %" PRId64 "\n", (cpi->array_first_elem) ? 0 :
847 INDENT * level + ind, "", node->cy_string,
853 static void print_string(char **out, struct cYAML *node,
854 struct cYAML_print_info *cpi)
857 int level = cpi->level;
858 int ind = cpi->extra_ind;
860 int len = INDENT * level + ind +
861 ((node->cy_valuestring) ? strlen(node->cy_valuestring) : 0) +
862 ((node->cy_string) ? strlen(node->cy_string) : 0) + LEAD_ROOM;
864 *out = ensure(*out, len);
868 tmp = ensure(tmp, len);
872 if (cpi->array_first_elem) {
873 sprintf(tmp, "%*s- ", INDENT * level, "");
877 new_line = strchr(node->cy_valuestring, '\n');
878 if (new_line == NULL) {
879 sprintf(tmp, "%*s""%s: %s\n", (cpi->array_first_elem) ?
880 0 : INDENT * level + ind, "",
881 node->cy_string, node->cy_valuestring);
885 sprintf(tmp, "%*s""%s: ", (cpi->array_first_elem) ?
886 0 : INDENT * level + ind, "",
889 char *l = node->cy_valuestring;
892 sprintf(tmp, "%*s""%s\n", indent, "", l);
894 indent = INDENT * level + ind +
895 strlen(node->cy_string) + 2;
898 new_line = strchr(l, '\n');
900 sprintf(tmp, "%*s""%s\n", indent, "", l);
907 static void print_number(char **out, struct cYAML *node,
908 struct cYAML_print_info *cpi)
910 double d = node->cy_valuedouble;
911 int level = cpi->level;
912 int ind = cpi->extra_ind;
914 int len = INDENT * level + ind + LEAD_ROOM;
916 *out = ensure(*out, len);
920 tmp = ensure(tmp, len);
924 if (cpi->array_first_elem) {
925 sprintf(tmp, "%*s- ", INDENT * level, "");
929 if ((fabs(((double)node->cy_valueint) - d) <= DBL_EPSILON) &&
930 (d <= INT_MAX) && (d >= INT_MIN)) {
931 sprintf(tmp, "%*s""%s: %" PRId64 "\n", (cpi->array_first_elem) ? 0 :
932 INDENT * level + ind, "",
933 node->cy_string, node->cy_valueint);
936 if ((fabs(floor(d) - d) <= DBL_EPSILON) &&
937 (fabs(d) < 1.0e60)) {
938 sprintf(tmp, "%*s""%s: %.0f\n",
939 (cpi->array_first_elem) ? 0 :
940 INDENT * level + ind, "",
943 } else if ((fabs(d) < 1.0e-6) || (fabs(d) > 1.0e9)) {
944 sprintf(tmp, "%*s""%s: %e\n",
945 (cpi->array_first_elem) ? 0 :
946 INDENT * level + ind, "",
950 sprintf(tmp, "%*s""%s: %f\n",
951 (cpi->array_first_elem) ? 0 :
952 INDENT * level + ind, "",
961 static void print_object(char **out, struct cYAML *node,
962 struct list_head *stack,
963 struct cYAML_print_info *cpi)
965 struct cYAML_print_info print_info;
966 struct cYAML *child = node->cy_child;
968 int len = ((cpi->array_first_elem) ? INDENT * cpi->level :
969 INDENT * cpi->level + cpi->extra_ind) +
970 ((node->cy_string) ? strlen(node->cy_string) : 0) +
973 *out = ensure(*out, len);
977 tmp = ensure(tmp, len);
981 if (node->cy_string != NULL) {
982 sprintf(tmp, "%*s""%s%s:\n", (cpi->array_first_elem) ?
983 INDENT * cpi->level :
984 INDENT * cpi->level + cpi->extra_ind,
985 "", (cpi->array_first_elem) ? "- " : "",
990 print_info.level = (node->cy_string != NULL) ? cpi->level + 1 :
992 print_info.array_first_elem = (node->cy_string == NULL) ?
993 cpi->array_first_elem : 0;
994 print_info.extra_ind = (cpi->array_first_elem) ? EXTRA_IND :
998 if (cYAML_ll_push(child, &print_info, stack) != 0) {
1002 print_value(out, stack);
1003 print_info.array_first_elem = 0;
1004 child = child->cy_next;
1010 static void print_array(char **out, struct cYAML *node,
1011 struct list_head *stack,
1012 struct cYAML_print_info *cpi)
1014 struct cYAML_print_info print_info;
1015 struct cYAML *child = node->cy_child;
1017 int len = ((node->cy_string) ? strlen(node->cy_string) : 0) +
1018 INDENT * cpi->level + cpi->extra_ind + LEAD_ROOM;
1020 *out = ensure(*out, len);
1024 tmp = ensure(tmp, len);
1028 if (node->cy_string != NULL) {
1029 sprintf(tmp, "%*s""%s:\n", INDENT * cpi->level + cpi->extra_ind,
1030 "", node->cy_string);
1034 print_info.level = (node->cy_string != NULL) ? cpi->level + 1 :
1036 print_info.array_first_elem = 1;
1037 print_info.extra_ind = EXTRA_IND;
1040 if (cYAML_ll_push(child, &print_info, stack) != 0) {
1044 print_value(out, stack);
1045 child = child->cy_next;
1051 static void print_value(char **out, struct list_head *stack)
1053 struct cYAML_print_info *cpi = NULL;
1054 struct cYAML *node = cYAML_ll_pop(stack, &cpi);
1059 switch (node->cy_type) {
1060 case CYAML_TYPE_FALSE:
1061 case CYAML_TYPE_TRUE:
1062 case CYAML_TYPE_NULL:
1063 print_simple(out, node, cpi);
1065 case CYAML_TYPE_STRING:
1066 print_string(out, node, cpi);
1068 case CYAML_TYPE_NUMBER:
1069 print_number(out, node, cpi);
1071 case CYAML_TYPE_ARRAY:
1072 print_array(out, node, stack, cpi);
1074 case CYAML_TYPE_OBJECT:
1075 print_object(out, node, stack, cpi);
1085 void cYAML_dump(struct cYAML *node, char **buf)
1087 struct cYAML_print_info print_info;
1088 struct list_head list;
1090 *buf = ensure(NULL, PRINT_BUF_LEN);
1095 INIT_LIST_HEAD(&list);
1102 memset(&print_info, 0, sizeof(struct cYAML_print_info));
1104 if (cYAML_ll_push(node, &print_info, &list) == 0)
1105 print_value(buf, &list);
1108 void cYAML_print_tree(struct cYAML *node)
1110 struct cYAML_print_info print_info;
1111 struct list_head list;
1112 char *buf = ensure(NULL, PRINT_BUF_LEN);
1117 INIT_LIST_HEAD(&list);
1122 memset(&print_info, 0, sizeof(struct cYAML_print_info));
1124 if (cYAML_ll_push(node, &print_info, &list) == 0)
1125 print_value(&buf, &list);
1127 /* buf could've been freed if we ran out of memory */
1134 void cYAML_print_tree2file(FILE *f, struct cYAML *node)
1136 struct cYAML_print_info print_info;
1137 struct list_head list;
1138 char *buf = ensure(NULL, PRINT_BUF_LEN);
1143 INIT_LIST_HEAD(&list);
1148 memset(&print_info, 0, sizeof(struct cYAML_print_info));
1150 if (cYAML_ll_push(node, &print_info, &list) == 0)
1151 print_value(&buf, &list);
1153 /* buf could've been freed if we ran out of memory */
1155 fprintf(f, "%s", buf);
1160 static struct cYAML *insert_item(struct cYAML *parent, char *key,
1161 enum cYAML_object_type type)
1163 struct cYAML *node = calloc(1, sizeof(*node));
1169 node->cy_string = strdup(key);
1171 node->cy_type = type;
1173 cYAML_insert_child(parent, node);
1178 struct cYAML *cYAML_create_seq(struct cYAML *parent, char *key)
1180 return insert_item(parent, key, CYAML_TYPE_ARRAY);
1183 struct cYAML *cYAML_create_seq_item(struct cYAML *seq)
1185 return insert_item(seq, NULL, CYAML_TYPE_OBJECT);
1188 struct cYAML *cYAML_create_object(struct cYAML *parent, char *key)
1190 return insert_item(parent, key, CYAML_TYPE_OBJECT);
1193 struct cYAML *cYAML_create_string(struct cYAML *parent, char *key, char *value)
1195 struct cYAML *node = calloc(1, sizeof(*node));
1199 node->cy_string = strdup(key);
1200 node->cy_valuestring = strdup(value);
1201 node->cy_type = CYAML_TYPE_STRING;
1203 cYAML_insert_child(parent, node);
1208 struct cYAML *cYAML_create_number(struct cYAML *parent, char *key, double value)
1210 struct cYAML *node = calloc(1, sizeof(*node));
1214 node->cy_string = strdup(key);
1215 node->cy_valuedouble = value;
1216 node->cy_valueint = (int)value;
1217 node->cy_type = CYAML_TYPE_NUMBER;
1219 cYAML_insert_child(parent, node);
1224 void cYAML_insert_child(struct cYAML *parent, struct cYAML *node)
1228 if (parent && node) {
1229 if (parent->cy_child == NULL) {
1230 parent->cy_child = node;
1234 cur = parent->cy_child;
1236 while (cur->cy_next)
1239 cur->cy_next = node;
1240 node->cy_prev = cur;
1244 void cYAML_insert_sibling(struct cYAML *root, struct cYAML *sibling)
1246 struct cYAML *last = NULL;
1247 if (root == NULL || sibling == NULL)
1251 while (last->cy_next != NULL)
1252 last = last->cy_next;
1254 last->cy_next = sibling;
1257 void cYAML_build_error(int rc, int seq_no, char *cmd,
1258 char *entity, char *err_str,
1259 struct cYAML **root)
1261 struct cYAML *r = NULL, *err, *s, *itm = NULL, *cmd_obj;
1265 /* add to the tail of the root that's passed in */
1266 if ((*root) == NULL) {
1267 *root = cYAML_create_object(NULL, NULL);
1268 if ((*root) == NULL)
1274 /* look for the command */
1275 cmd_obj = cYAML_get_object_item(r, (const char *)cmd);
1276 if (cmd_obj != NULL && cmd_obj->cy_type == CYAML_TYPE_ARRAY)
1277 itm = cYAML_create_seq_item(cmd_obj);
1278 else if (cmd_obj == NULL) {
1279 s = cYAML_create_seq(r, cmd);
1280 itm = cYAML_create_seq_item(s);
1281 } else if (cmd_obj != NULL && cmd_obj->cy_type != CYAML_TYPE_ARRAY) {
1285 err = cYAML_create_object(itm, entity);
1290 cYAML_create_number(err, "seq_no", seq_no) == NULL)
1293 if (cYAML_create_number(err, "errno", rc) == NULL)
1296 if (cYAML_create_string(err, "descr", err_str) == NULL)
1302 /* Only reason we get here is if we run out of memory */
1305 fprintf(stderr, "error:\n\tfatal: out of memory\n");
1308 static struct cYAML *
1309 cYAML_parser_to_tree(yaml_parser_t *parser, struct cYAML **err_rc, bool debug)
1312 struct cYAML_tree_node tree;
1313 enum cYAML_handler_error rc;
1314 yaml_token_type_t token_type;
1318 memset(&tree, 0, sizeof(struct cYAML_tree_node));
1320 INIT_LIST_HEAD(&tree.ll);
1322 /* Read the event sequence. */
1325 * Go through the parser and build a cYAML representation
1326 * of the passed in YAML text
1328 yaml_parser_scan(parser, &token);
1331 fprintf(stderr, "tree.state(%p:%d) = %s, token.type ="
1333 &tree, tree.state, state_string[tree.state],
1334 token_type_string[token.type],
1335 (token.type == YAML_SCALAR_TOKEN) ?
1336 (char*)token.data.scalar.value : "");
1337 rc = dispatch_tbl[token.type](&token, &tree);
1338 if (rc != CYAML_ERROR_NONE) {
1339 snprintf(err_str, sizeof(err_str),
1340 "Failed to handle token:%d %s [state=%d, rc=%d]",
1341 token.type, token_type_string[token.type],
1343 cYAML_build_error(-1, -1, "yaml", "builder",
1347 /* Are we finished? */
1348 done = (rc != CYAML_ERROR_NONE ||
1349 token.type == YAML_STREAM_END_TOKEN);
1351 token_type = token.type;
1353 yaml_token_delete(&token);
1356 if (token_type == YAML_STREAM_END_TOKEN &&
1357 rc == CYAML_ERROR_NONE)
1360 cYAML_free_tree(tree.root);
1365 struct cYAML *cYAML_load(FILE *file, struct cYAML **err_rc, bool debug)
1367 yaml_parser_t parser;
1370 yaml_parser_initialize(&parser);
1371 yaml_parser_set_input_file(&parser, file);
1373 yaml = cYAML_parser_to_tree(&parser, err_rc, debug);
1375 yaml_parser_delete(&parser);
1380 struct cYAML *cYAML_build_tree(char *path,
1381 const char *yaml_blk,
1382 size_t yaml_blk_size,
1383 struct cYAML **err_rc,
1386 yaml_parser_t parser;
1387 struct cYAML *yaml = NULL;
1391 /* Create the Parser object. */
1392 if (yaml_parser_initialize(&parser) == 0)
1395 /* file always takes precedence */
1397 /* Set a file input. */
1398 input = fopen(path, "rb");
1399 if (input == NULL) {
1400 snprintf(err_str, sizeof(err_str),
1401 "cannot open '%s': %s", path, strerror(errno));
1402 cYAML_build_error(-1, -1, "yaml", "builder",
1408 yaml_parser_set_input_file(&parser, input);
1409 } else if (yaml_blk != NULL) {
1410 yaml_parser_set_input_string(&parser,
1411 (const unsigned char *) yaml_blk,
1414 /* assume that we're getting our input froms stdin */
1415 yaml_parser_set_input_file(&parser, stdin);
1418 yaml = cYAML_parser_to_tree(&parser, err_rc, debug);
1420 /* Destroy the Parser object. */
1421 yaml_parser_delete(&parser);