4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as
8 * published by the Free Software Foundation; either version 2.1 of the
9 * License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
21 * Copyright (c) 2014, 2017, Intel Corporation.
24 * Amir Shehata <amir.shehata@intel.com>
28 * The cYAML tree is constructed as an n-tree.
32 * cmd 2 -> attr1 -> attr2
35 * attr2.1 -> attr2.1.1 -> attr2.1.2
48 #include "libcfs/util/list.h"
54 #define PRINT_BUF_LEN 2048
58 * This structure contains print information
59 * required when printing the node
61 struct cYAML_print_info {
69 * Linked list of different trees representing YAML
73 struct list_head list;
75 struct cYAML_print_info *print_info;
78 static void print_value(char **out, struct list_head *stack);
80 enum cYAML_handler_error {
82 CYAML_ERROR_UNEXPECTED_STATE = -1,
83 CYAML_ERROR_NOT_SUPPORTED = -2,
84 CYAML_ERROR_OUT_OF_MEM = -3,
85 CYAML_ERROR_BAD_VALUE = -4,
86 CYAML_ERROR_PARSE = -5,
89 enum cYAML_tree_state {
90 TREE_STATE_COMPLETE = 0,
92 TREE_STATE_TREE_STARTED,
93 TREE_STATE_BLK_STARTED,
95 TREE_STATE_KEY_FILLED,
100 struct cYAML_tree_node {
102 /* cur is the current node we're operating on */
104 enum cYAML_tree_state state;
105 int from_blk_map_start;
106 /* represents the tree depth */
110 typedef enum cYAML_handler_error (*yaml_token_handler)(yaml_token_t *token,
111 struct cYAML_tree_node *);
113 static enum cYAML_handler_error yaml_no_token(yaml_token_t *token,
114 struct cYAML_tree_node *tree);
115 static enum cYAML_handler_error yaml_stream_start(yaml_token_t *token,
116 struct cYAML_tree_node *tree);
117 static enum cYAML_handler_error yaml_stream_end(yaml_token_t *token,
118 struct cYAML_tree_node *tree);
119 static enum cYAML_handler_error yaml_not_supported(yaml_token_t *token,
120 struct cYAML_tree_node *tree);
121 static enum cYAML_handler_error yaml_document_start(yaml_token_t *token,
122 struct cYAML_tree_node *tree);
123 static enum cYAML_handler_error yaml_document_end(yaml_token_t *token,
124 struct cYAML_tree_node *tree);
125 static enum cYAML_handler_error yaml_blk_seq_start(yaml_token_t *token,
126 struct cYAML_tree_node *tree);
127 static enum cYAML_handler_error yaml_blk_mapping_start(yaml_token_t *token,
128 struct cYAML_tree_node *tree);
129 static enum cYAML_handler_error yaml_block_end(yaml_token_t *token,
130 struct cYAML_tree_node *tree);
131 static enum cYAML_handler_error yaml_key(yaml_token_t *token,
132 struct cYAML_tree_node *tree);
133 static enum cYAML_handler_error yaml_value(yaml_token_t *token,
134 struct cYAML_tree_node *tree);
135 static enum cYAML_handler_error yaml_scalar(yaml_token_t *token,
136 struct cYAML_tree_node *tree);
137 static enum cYAML_handler_error yaml_entry_token(yaml_token_t *token,
138 struct cYAML_tree_node *tree);
141 static yaml_token_handler dispatch_tbl[] = {
142 [YAML_NO_TOKEN] = yaml_no_token,
143 [YAML_STREAM_START_TOKEN] = yaml_stream_start,
144 [YAML_STREAM_END_TOKEN] = yaml_stream_end,
145 [YAML_VERSION_DIRECTIVE_TOKEN] = yaml_not_supported,
146 [YAML_TAG_DIRECTIVE_TOKEN] = yaml_not_supported,
147 [YAML_DOCUMENT_START_TOKEN] = yaml_document_start,
148 [YAML_DOCUMENT_END_TOKEN] = yaml_document_end,
149 [YAML_BLOCK_SEQUENCE_START_TOKEN] = yaml_blk_seq_start,
150 [YAML_BLOCK_MAPPING_START_TOKEN] = yaml_blk_mapping_start,
151 [YAML_BLOCK_END_TOKEN] = yaml_block_end,
152 [YAML_FLOW_SEQUENCE_START_TOKEN] = yaml_not_supported,
153 [YAML_FLOW_SEQUENCE_END_TOKEN] = yaml_not_supported,
154 [YAML_FLOW_MAPPING_START_TOKEN] = yaml_not_supported,
155 [YAML_FLOW_MAPPING_END_TOKEN] = yaml_not_supported,
156 [YAML_BLOCK_ENTRY_TOKEN] = yaml_entry_token,
157 [YAML_FLOW_ENTRY_TOKEN] = yaml_not_supported,
158 [YAML_KEY_TOKEN] = yaml_key,
159 [YAML_VALUE_TOKEN] = yaml_value,
160 [YAML_ALIAS_TOKEN] = yaml_not_supported,
161 [YAML_ANCHOR_TOKEN] = yaml_not_supported,
162 [YAML_TAG_TOKEN] = yaml_not_supported,
163 [YAML_SCALAR_TOKEN] = yaml_scalar,
167 static const char * const token_type_string[] = {
168 [YAML_NO_TOKEN] = "YAML_NO_TOKEN",
169 [YAML_STREAM_START_TOKEN] = "YAML_STREAM_START_TOKEN",
170 [YAML_STREAM_END_TOKEN] = "YAML_STREAM_END_TOKEN",
171 [YAML_VERSION_DIRECTIVE_TOKEN] = "YAML_VERSION_DIRECTIVE_TOKEN",
172 [YAML_TAG_DIRECTIVE_TOKEN] = "YAML_TAG_DIRECTIVE_TOKEN",
173 [YAML_DOCUMENT_START_TOKEN] = "YAML_DOCUMENT_START_TOKEN",
174 [YAML_DOCUMENT_END_TOKEN] = "YAML_DOCUMENT_END_TOKEN",
175 [YAML_BLOCK_SEQUENCE_START_TOKEN] = "YAML_BLOCK_SEQUENCE_START_TOKEN",
176 [YAML_BLOCK_MAPPING_START_TOKEN] = "YAML_BLOCK_MAPPING_START_TOKEN",
177 [YAML_BLOCK_END_TOKEN] = "YAML_BLOCK_END_TOKEN",
178 [YAML_FLOW_SEQUENCE_START_TOKEN] = "YAML_FLOW_SEQUENCE_START_TOKEN",
179 [YAML_FLOW_SEQUENCE_END_TOKEN] = "YAML_FLOW_SEQUENCE_END_TOKEN",
180 [YAML_FLOW_MAPPING_START_TOKEN] = "YAML_FLOW_MAPPING_START_TOKEN",
181 [YAML_FLOW_MAPPING_END_TOKEN] = "YAML_FLOW_MAPPING_END_TOKEN",
182 [YAML_BLOCK_ENTRY_TOKEN] = "YAML_BLOCK_ENTRY_TOKEN",
183 [YAML_FLOW_ENTRY_TOKEN] = "YAML_FLOW_ENTRY_TOKEN",
184 [YAML_KEY_TOKEN] = "YAML_KEY_TOKEN",
185 [YAML_VALUE_TOKEN] = "YAML_VALUE_TOKEN",
186 [YAML_ALIAS_TOKEN] = "YAML_ALIAS_TOKEN",
187 [YAML_ANCHOR_TOKEN] = "YAML_ANCHOR_TOKEN",
188 [YAML_TAG_TOKEN] = "YAML_TAG_TOKEN",
189 [YAML_SCALAR_TOKEN] = "YAML_SCALAR_TOKEN",
192 static const char * const state_string[] = {
193 [TREE_STATE_COMPLETE] = "COMPLETE",
194 [TREE_STATE_INITED] = "INITED",
195 [TREE_STATE_TREE_STARTED] = "TREE_STARTED",
196 [TREE_STATE_BLK_STARTED] = "BLK_STARTED",
197 [TREE_STATE_KEY] = "KEY",
198 [TREE_STATE_KEY_FILLED] = "KEY_FILLED",
199 [TREE_STATE_VALUE] = "VALUE",
200 [TREE_STATE_SEQ_START] = "SEQ_START",
203 static void cYAML_ll_free(struct list_head *ll)
205 struct cYAML_ll *node, *tmp;
207 list_for_each_entry_safe(node, tmp, ll, list) {
208 free(node->print_info);
213 static int cYAML_ll_push(struct cYAML *obj,
214 const struct cYAML_print_info *print_info,
215 struct list_head *list)
217 struct cYAML_ll *node = calloc(1, sizeof(*node));
221 INIT_LIST_HEAD(&node->list);
224 node->print_info = calloc(1, sizeof(*print_info));
225 if (node->print_info == NULL) {
229 *node->print_info = *print_info;
233 list_add(&node->list, list);
238 static struct cYAML *cYAML_ll_pop(struct list_head *list,
239 struct cYAML_print_info **print_info)
241 struct cYAML_ll *pop;
242 struct cYAML *obj = NULL;
244 if (!list_empty(list)) {
245 pop = list_first_entry(list, struct cYAML_ll, list);
248 if (print_info != NULL)
249 *print_info = pop->print_info;
250 list_del(&pop->list);
252 if (print_info == NULL)
253 free(pop->print_info);
260 static int cYAML_ll_count(struct list_head *ll)
263 struct list_head *node;
265 list_for_each(node, ll)
271 static int cYAML_tree_init(struct cYAML_tree_node *tree)
273 struct cYAML *obj = NULL, *cur = NULL;
278 obj = calloc(1, sizeof(*obj));
283 /* append the node */
285 while (cur->cy_next != NULL)
292 obj->cy_type = CYAML_TYPE_OBJECT;
295 tree->state = TREE_STATE_COMPLETE;
297 /* free it and start anew */
298 if (!list_empty(&tree->ll))
299 cYAML_ll_free(&tree->ll);
304 static struct cYAML *create_child(struct cYAML *parent)
311 obj = calloc(1, sizeof(*obj));
315 /* set the type to OBJECT and let the value change that */
316 obj->cy_type = CYAML_TYPE_OBJECT;
318 parent->cy_child = obj;
323 static struct cYAML *create_sibling(struct cYAML *sibling)
330 obj = calloc(1, sizeof(*obj));
334 /* set the type to OBJECT and let the value change that */
335 obj->cy_type = CYAML_TYPE_OBJECT;
337 sibling->cy_next = obj;
338 obj->cy_prev = sibling;
343 /* Parse the input text to generate a number,
344 * and populate the result into item. */
345 static bool parse_number(struct cYAML *item, const char *input)
347 double n = 0, sign = 1, scale = 0;
348 int subscale = 0, signsubscale = 1;
349 const char *num = input;
351 if (!strncmp(input, "0x", 2)) {
352 int64_t hex; /* hex input is always an integer */
353 char *invalid = NULL;
356 hex = strtoll(input, &invalid, 16);
362 item->cy_valuedouble = (double) hex;
363 item->cy_valueint = hex;
364 item->cy_type = CYAML_TYPE_NUMBER;
376 if (*num >= '1' && *num <= '9') {
378 n = (n * 10.0) + (*num++ - '0');
379 } while (*num >= '0' && *num <= '9');
382 if (*num == '.' && num[1] >= '0' && num[1] <= '9') {
385 n = (n * 10.0) + (*num++ - '0');
387 } while (*num >= '0' && *num <= '9');
390 if (*num == 'e' || *num == 'E') {
394 } else if (*num == '-') {
398 while (*num >= '0' && *num <= '9')
399 subscale = (subscale * 10) + (*num++ - '0');
402 /* check to see if the entire string is consumed. If not then
403 * that means this is a string with a number in it */
404 if (num != (input + strlen(input)))
407 /* number = +/- number.fraction * 10^+/- exponent */
408 n = sign * n * pow(10.0, (scale + subscale * signsubscale));
410 item->cy_valuedouble = n;
411 item->cy_valueint = (int64_t)n;
412 item->cy_type = CYAML_TYPE_NUMBER;
417 static int assign_type_value(struct cYAML *obj, const char *value)
422 if (strcmp(value, "null") == 0)
423 obj->cy_type = CYAML_TYPE_NULL;
424 else if (strcmp(value, "false") == 0) {
425 obj->cy_type = CYAML_TYPE_FALSE;
426 obj->cy_valueint = 0;
427 } else if (strcmp(value, "true") == 0) {
428 obj->cy_type = CYAML_TYPE_TRUE;
429 obj->cy_valueint = 1;
430 } else if (*value == '-' || (*value >= '0' && *value <= '9')) {
431 if (parse_number(obj, value) == 0) {
432 obj->cy_valuestring = strdup(value);
433 obj->cy_type = CYAML_TYPE_STRING;
436 obj->cy_valuestring = strdup(value);
437 obj->cy_type = CYAML_TYPE_STRING;
445 * Builds the YAML tree rpresentation as the tokens are passed in
447 * if token == STREAM_START && tree_state != COMPLETE
448 * something wrong. fail.
449 * else tree_state = INITIED
450 * if token == DOCUMENT_START && tree_state != COMPLETE || INITED
451 * something wrong, fail.
452 * else tree_state = TREE_STARTED
453 * if token == DOCUMENT_END
454 * tree_state = INITED if no STREAM START, else tree_state = COMPLETE
455 * erase everything on ll
456 * if token == STREAM_END && tree_state != INITED
457 * something wrong fail.
458 * else tree_state = COMPLETED
459 * if token == YAML_KEY_TOKEN && state != TREE_STARTED
460 * something wrong, fail.
461 * if token == YAML_SCALAR_TOKEN && state != KEY || VALUE
463 * else if tree_state == KEY
464 * create a new sibling under the current head of the ll (if ll is
465 * empty insert the new node there and it becomes the root.)
466 * add the scalar value in the "string"
467 * tree_state = KEY_FILLED
468 * else if tree_state == VALUE
469 * try and figure out whether this is a double, int or string and store
471 * state = TREE_STARTED
472 * else if token == YAML_BLOCK_MAPPING_START_TOKEN && tree_state != VALUE
474 * else push the current node on the ll && state = TREE_STARTED
475 * if token == YAML_BLOCK_END_TOKEN && state != TREE_STARTED
477 * else pop the current token off the ll and make it the cur
478 * if token == YAML_VALUE_TOKEN && state != KEY_FILLED
484 static enum cYAML_handler_error yaml_no_token(yaml_token_t *token,
485 struct cYAML_tree_node *tree)
487 return CYAML_ERROR_NONE;
490 static enum cYAML_handler_error yaml_stream_start(yaml_token_t *token,
491 struct cYAML_tree_node *tree)
493 enum cYAML_handler_error rc;
495 /* with each new stream initialize a new tree */
496 rc = cYAML_tree_init(tree);
498 if (rc != CYAML_ERROR_NONE)
501 tree->state = TREE_STATE_INITED;
503 return CYAML_ERROR_NONE;
506 static enum cYAML_handler_error yaml_stream_end(yaml_token_t *token,
507 struct cYAML_tree_node *tree)
509 if (tree->state != TREE_STATE_TREE_STARTED &&
510 tree->state != TREE_STATE_COMPLETE &&
511 tree->state != TREE_STATE_INITED)
512 return CYAML_ERROR_UNEXPECTED_STATE;
514 tree->state = TREE_STATE_INITED;
516 return CYAML_ERROR_NONE;
519 static enum cYAML_handler_error
520 yaml_document_start(yaml_token_t *token, struct cYAML_tree_node *tree)
522 if (tree->state != TREE_STATE_INITED)
523 return CYAML_ERROR_UNEXPECTED_STATE;
525 /* go to started state since we're expecting more tokens to come */
526 tree->state = TREE_STATE_TREE_STARTED;
528 return CYAML_ERROR_NONE;
531 static enum cYAML_handler_error yaml_document_end(yaml_token_t *token,
532 struct cYAML_tree_node *tree)
534 if (tree->state != TREE_STATE_COMPLETE)
535 return CYAML_ERROR_UNEXPECTED_STATE;
537 tree->state = TREE_STATE_TREE_STARTED;
539 return CYAML_ERROR_NONE;
542 static enum cYAML_handler_error yaml_key(yaml_token_t *token,
543 struct cYAML_tree_node *tree)
545 if (tree->state != TREE_STATE_BLK_STARTED &&
546 tree->state != TREE_STATE_VALUE)
547 return CYAML_ERROR_UNEXPECTED_STATE;
549 if (tree->from_blk_map_start == 0 ||
550 tree->state == TREE_STATE_VALUE)
551 tree->cur = create_sibling(tree->cur);
553 tree->from_blk_map_start = 0;
555 tree->state = TREE_STATE_KEY;
557 return CYAML_ERROR_NONE;
560 static enum cYAML_handler_error yaml_scalar(yaml_token_t *token,
561 struct cYAML_tree_node *tree)
563 if (tree->state == TREE_STATE_KEY) {
564 /* assign the scalar value to the key that was created */
565 tree->cur->cy_string =
566 strdup((const char *)token->data.scalar.value);
568 tree->state = TREE_STATE_KEY_FILLED;
569 } else if (tree->state == TREE_STATE_VALUE ||
570 tree->state == TREE_STATE_SEQ_START) {
571 if (assign_type_value(tree->cur,
572 (char *)token->data.scalar.value))
573 /* failed to assign a value */
574 return CYAML_ERROR_BAD_VALUE;
575 tree->state = TREE_STATE_BLK_STARTED;
577 return CYAML_ERROR_UNEXPECTED_STATE;
580 return CYAML_ERROR_NONE;
583 static enum cYAML_handler_error yaml_value(yaml_token_t *token,
584 struct cYAML_tree_node *tree)
586 if (tree->state != TREE_STATE_KEY_FILLED)
587 return CYAML_ERROR_UNEXPECTED_STATE;
589 tree->state = TREE_STATE_VALUE;
591 return CYAML_ERROR_NONE;
594 static enum cYAML_handler_error yaml_blk_seq_start(yaml_token_t *token,
595 struct cYAML_tree_node *tree)
597 if (tree->state != TREE_STATE_VALUE)
598 return CYAML_ERROR_UNEXPECTED_STATE;
600 /* Since a sequenc start event determines that this is the start
601 * of an array, then that means the current node we're at is an
602 * array and we need to flag it as such */
603 tree->cur->cy_type = CYAML_TYPE_ARRAY;
604 tree->state = TREE_STATE_SEQ_START;
606 return CYAML_ERROR_NONE;
609 static enum cYAML_handler_error yaml_entry_token(yaml_token_t *token,
610 struct cYAML_tree_node *tree)
614 if (tree->state != TREE_STATE_SEQ_START &&
615 tree->state != TREE_STATE_BLK_STARTED &&
616 tree->state != TREE_STATE_VALUE)
617 return CYAML_ERROR_UNEXPECTED_STATE;
619 if (tree->state == TREE_STATE_SEQ_START) {
620 obj = create_child(tree->cur);
622 if (cYAML_ll_push(tree->cur, NULL, &tree->ll))
623 return CYAML_ERROR_OUT_OF_MEM;
627 tree->cur = create_sibling(tree->cur);
628 tree->state = TREE_STATE_SEQ_START;
631 return CYAML_ERROR_NONE;
634 static enum cYAML_handler_error
635 yaml_blk_mapping_start(yaml_token_t *token,
636 struct cYAML_tree_node *tree)
640 if (tree->state != TREE_STATE_VALUE &&
641 tree->state != TREE_STATE_INITED &&
642 tree->state != TREE_STATE_SEQ_START &&
643 tree->state != TREE_STATE_TREE_STARTED)
644 return CYAML_ERROR_UNEXPECTED_STATE;
646 /* block_mapping_start means we're entering another block
647 * indentation, so we need to go one level deeper
648 * create a child of cur */
649 obj = create_child(tree->cur);
651 /* push cur on the stack */
652 if (cYAML_ll_push(tree->cur, NULL, &tree->ll))
653 return CYAML_ERROR_OUT_OF_MEM;
655 /* adding the new child to cur */
658 tree->state = TREE_STATE_BLK_STARTED;
660 tree->from_blk_map_start = 1;
662 return CYAML_ERROR_NONE;
665 static enum cYAML_handler_error yaml_block_end(yaml_token_t *token,
666 struct cYAML_tree_node *tree)
668 if (tree->state != TREE_STATE_BLK_STARTED &&
669 tree->state != TREE_STATE_VALUE)
670 return CYAML_ERROR_UNEXPECTED_STATE;
672 tree->cur = cYAML_ll_pop(&tree->ll, NULL);
674 /* if you have popped all the way to the top level, then move to
675 * the complete state. */
676 if (cYAML_ll_count(&tree->ll) == 0)
677 tree->state = TREE_STATE_COMPLETE;
678 else if (tree->state == TREE_STATE_VALUE)
679 tree->state = TREE_STATE_BLK_STARTED;
681 return CYAML_ERROR_NONE;
684 static enum cYAML_handler_error yaml_not_supported(yaml_token_t *token,
685 struct cYAML_tree_node *tree)
687 return CYAML_ERROR_NOT_SUPPORTED;
690 static bool clean_usr_data(struct cYAML *node, void *usr_data, void **out)
692 cYAML_user_data_free_cb free_cb = usr_data;
694 if (free_cb && node && node->cy_user_data) {
695 free_cb(node->cy_user_data);
696 node->cy_user_data = NULL;
702 static bool free_node(struct cYAML *node, void *user_data, void **out)
707 if (node->cy_type == CYAML_TYPE_STRING)
708 free(node->cy_valuestring);
710 free(node->cy_string);
716 static bool find_obj_iter(struct cYAML *node, void *usr_data, void **out)
718 char *name = usr_data;
720 if (node != NULL && node->cy_string != NULL &&
721 strcmp(node->cy_string, name) == 0) {
729 struct cYAML *cYAML_get_object_item(struct cYAML *parent, const char *name)
731 struct cYAML *node = parent, *found = NULL;
736 if (node->cy_string) {
737 if (strcmp(node->cy_string, name) == 0)
742 found = cYAML_get_object_item(node->cy_child, name);
744 if (!found && node->cy_next)
745 found = cYAML_get_object_item(node->cy_next, name);
750 struct cYAML *cYAML_get_next_seq_item(struct cYAML *seq, struct cYAML **itm)
752 if (*itm != NULL && (*itm)->cy_next != NULL) {
753 *itm = (*itm)->cy_next;
757 if (*itm == NULL && seq->cy_type == CYAML_TYPE_ARRAY) {
758 *itm = seq->cy_child;
765 bool cYAML_is_sequence(struct cYAML *node)
767 return (node != NULL ? node->cy_type == CYAML_TYPE_ARRAY : 0);
770 static void cYAML_tree_recursive_walk(struct cYAML *node, cYAML_walk_cb cb,
779 if (!cb(node, usr_data, out))
784 cYAML_tree_recursive_walk(node->cy_child, cb,
785 cb_first, usr_data, out);
788 cYAML_tree_recursive_walk(node->cy_next, cb,
789 cb_first, usr_data, out);
792 if (!cb(node, usr_data, out))
797 struct cYAML *cYAML_find_object(struct cYAML *root, const char *name)
799 struct cYAML *found = NULL;
801 cYAML_tree_recursive_walk(root, find_obj_iter, true,
802 (void *)name, (void **)&found);
807 void cYAML_clean_usr_data(struct cYAML *node, cYAML_user_data_free_cb free_cb)
809 cYAML_tree_recursive_walk(node, clean_usr_data, false, free_cb, NULL);
812 void cYAML_free_tree(struct cYAML *node)
814 cYAML_tree_recursive_walk(node, free_node, false, NULL, NULL);
817 static char *ensure(char *in, int len)
823 return (char*)calloc(len, 1);
825 curlen = strlen(in) + 1;
827 if (curlen <= curlen + len) {
828 new = calloc(curlen + len, 1);
840 static inline void print_simple(char **out, struct cYAML *node,
841 struct cYAML_print_info *cpi)
843 int level = cpi->level;
844 int ind = cpi->extra_ind;
846 int len = (INDENT * level + ind) * 2 +
847 ((node->cy_string) ? strlen(node->cy_string) : 0) + LEAD_ROOM;
849 *out = ensure(*out, len);
853 tmp = ensure(tmp, len);
857 if (cpi->array_first_elem) {
858 sprintf(tmp, "%*s- ", INDENT * level, "");
862 sprintf(tmp, "%*s""%s: %" PRId64 "\n", (cpi->array_first_elem) ? 0 :
863 INDENT * level + ind, "", node->cy_string,
869 static void print_string(char **out, struct cYAML *node,
870 struct cYAML_print_info *cpi)
873 int level = cpi->level;
874 int ind = cpi->extra_ind;
876 int len = INDENT * level + ind +
877 ((node->cy_valuestring) ? strlen(node->cy_valuestring) : 0) +
878 ((node->cy_string) ? strlen(node->cy_string) : 0) + LEAD_ROOM;
880 *out = ensure(*out, len);
884 tmp = ensure(tmp, len);
888 if (cpi->array_first_elem) {
889 sprintf(tmp, "%*s- ", INDENT * level, "");
893 new_line = strchr(node->cy_valuestring, '\n');
894 if (new_line == NULL) {
895 sprintf(tmp, "%*s""%s: %s\n", (cpi->array_first_elem) ?
896 0 : INDENT * level + ind, "",
897 node->cy_string, node->cy_valuestring);
901 sprintf(tmp, "%*s""%s: ", (cpi->array_first_elem) ?
902 0 : INDENT * level + ind, "",
905 char *l = node->cy_valuestring;
908 sprintf(tmp, "%*s""%s\n", indent, "", l);
910 indent = INDENT * level + ind +
911 strlen(node->cy_string) + 2;
914 new_line = strchr(l, '\n');
916 sprintf(tmp, "%*s""%s\n", indent, "", l);
923 static void print_number(char **out, struct cYAML *node,
924 struct cYAML_print_info *cpi)
926 double d = node->cy_valuedouble;
927 int level = cpi->level;
928 int ind = cpi->extra_ind;
930 int len = INDENT * level + ind + LEAD_ROOM;
932 *out = ensure(*out, len);
936 tmp = ensure(tmp, len);
940 if (cpi->array_first_elem) {
941 sprintf(tmp, "%*s- ", INDENT * level, "");
945 if ((fabs(((double)node->cy_valueint) - d) <= DBL_EPSILON) &&
946 (d <= INT_MAX) && (d >= INT_MIN)) {
947 sprintf(tmp, "%*s""%s: %" PRId64 "\n", (cpi->array_first_elem) ? 0 :
948 INDENT * level + ind, "",
949 node->cy_string, node->cy_valueint);
952 if ((fabs(floor(d) - d) <= DBL_EPSILON) &&
953 (fabs(d) < 1.0e60)) {
954 sprintf(tmp, "%*s""%s: %.0f\n",
955 (cpi->array_first_elem) ? 0 :
956 INDENT * level + ind, "",
959 } else if ((fabs(d) < 1.0e-6) || (fabs(d) > 1.0e9)) {
960 sprintf(tmp, "%*s""%s: %e\n",
961 (cpi->array_first_elem) ? 0 :
962 INDENT * level + ind, "",
966 sprintf(tmp, "%*s""%s: %f\n",
967 (cpi->array_first_elem) ? 0 :
968 INDENT * level + ind, "",
977 static void print_object(char **out, struct cYAML *node,
978 struct list_head *stack,
979 struct cYAML_print_info *cpi)
981 struct cYAML_print_info print_info;
982 struct cYAML *child = node->cy_child;
984 int len = ((cpi->array_first_elem) ? INDENT * cpi->level :
985 INDENT * cpi->level + cpi->extra_ind) +
986 ((node->cy_string) ? strlen(node->cy_string) : 0) +
989 *out = ensure(*out, len);
993 tmp = ensure(tmp, len);
997 if (node->cy_string != NULL) {
998 sprintf(tmp, "%*s""%s%s:\n", (cpi->array_first_elem) ?
999 INDENT * cpi->level :
1000 INDENT * cpi->level + cpi->extra_ind,
1001 "", (cpi->array_first_elem) ? "- " : "",
1006 print_info.level = (node->cy_string != NULL) ? cpi->level + 1 :
1008 print_info.array_first_elem = (node->cy_string == NULL) ?
1009 cpi->array_first_elem : 0;
1010 print_info.extra_ind = (cpi->array_first_elem) ? EXTRA_IND :
1014 if (cYAML_ll_push(child, &print_info, stack) != 0) {
1018 print_value(out, stack);
1019 print_info.array_first_elem = 0;
1020 child = child->cy_next;
1026 static void print_array(char **out, struct cYAML *node,
1027 struct list_head *stack,
1028 struct cYAML_print_info *cpi)
1030 struct cYAML_print_info print_info;
1031 struct cYAML *child = node->cy_child;
1033 int len = ((node->cy_string) ? strlen(node->cy_string) : 0) +
1034 INDENT * cpi->level + cpi->extra_ind + LEAD_ROOM;
1036 *out = ensure(*out, len);
1040 tmp = ensure(tmp, len);
1044 if (node->cy_string != NULL) {
1045 sprintf(tmp, "%*s""%s:\n", INDENT * cpi->level + cpi->extra_ind,
1046 "", node->cy_string);
1050 print_info.level = (node->cy_string != NULL) ? cpi->level + 1 :
1052 print_info.array_first_elem = 1;
1053 print_info.extra_ind = EXTRA_IND;
1056 if (cYAML_ll_push(child, &print_info, stack) != 0) {
1060 print_value(out, stack);
1061 child = child->cy_next;
1067 static void print_value(char **out, struct list_head *stack)
1069 struct cYAML_print_info *cpi = NULL;
1070 struct cYAML *node = cYAML_ll_pop(stack, &cpi);
1075 switch (node->cy_type) {
1076 case CYAML_TYPE_FALSE:
1077 case CYAML_TYPE_TRUE:
1078 case CYAML_TYPE_NULL:
1079 print_simple(out, node, cpi);
1081 case CYAML_TYPE_STRING:
1082 print_string(out, node, cpi);
1084 case CYAML_TYPE_NUMBER:
1085 print_number(out, node, cpi);
1087 case CYAML_TYPE_ARRAY:
1088 print_array(out, node, stack, cpi);
1090 case CYAML_TYPE_OBJECT:
1091 print_object(out, node, stack, cpi);
1101 void cYAML_dump(struct cYAML *node, char **buf)
1103 struct cYAML_print_info print_info;
1104 struct list_head list;
1106 *buf = ensure(NULL, PRINT_BUF_LEN);
1111 INIT_LIST_HEAD(&list);
1118 memset(&print_info, 0, sizeof(struct cYAML_print_info));
1120 if (cYAML_ll_push(node, &print_info, &list) == 0)
1121 print_value(buf, &list);
1124 void cYAML_print_tree(struct cYAML *node)
1126 struct cYAML_print_info print_info;
1127 struct list_head list;
1128 char *buf = ensure(NULL, PRINT_BUF_LEN);
1133 INIT_LIST_HEAD(&list);
1138 memset(&print_info, 0, sizeof(struct cYAML_print_info));
1140 if (cYAML_ll_push(node, &print_info, &list) == 0)
1141 print_value(&buf, &list);
1143 /* buf could've been freed if we ran out of memory */
1150 void cYAML_print_tree2file(FILE *f, struct cYAML *node)
1152 struct cYAML_print_info print_info;
1153 struct list_head list;
1154 char *buf = ensure(NULL, PRINT_BUF_LEN);
1159 INIT_LIST_HEAD(&list);
1164 memset(&print_info, 0, sizeof(struct cYAML_print_info));
1166 if (cYAML_ll_push(node, &print_info, &list) == 0)
1167 print_value(&buf, &list);
1169 /* buf could've been freed if we ran out of memory */
1171 fprintf(f, "%s", buf);
1176 static struct cYAML *insert_item(struct cYAML *parent, char *key,
1177 enum cYAML_object_type type)
1179 struct cYAML *node = calloc(1, sizeof(*node));
1185 node->cy_string = strdup(key);
1187 node->cy_type = type;
1189 cYAML_insert_child(parent, node);
1194 struct cYAML *cYAML_create_seq(struct cYAML *parent, char *key)
1196 return insert_item(parent, key, CYAML_TYPE_ARRAY);
1199 struct cYAML *cYAML_create_seq_item(struct cYAML *seq)
1201 return insert_item(seq, NULL, CYAML_TYPE_OBJECT);
1204 struct cYAML *cYAML_create_object(struct cYAML *parent, char *key)
1206 return insert_item(parent, key, CYAML_TYPE_OBJECT);
1209 struct cYAML *cYAML_create_string(struct cYAML *parent, char *key, char *value)
1211 struct cYAML *node = calloc(1, sizeof(*node));
1215 node->cy_string = strdup(key);
1216 node->cy_valuestring = strdup(value);
1217 node->cy_type = CYAML_TYPE_STRING;
1219 cYAML_insert_child(parent, node);
1224 struct cYAML *cYAML_create_number(struct cYAML *parent, char *key, double value)
1226 struct cYAML *node = calloc(1, sizeof(*node));
1230 node->cy_string = strdup(key);
1231 node->cy_valuedouble = value;
1232 node->cy_valueint = (int)value;
1233 node->cy_type = CYAML_TYPE_NUMBER;
1235 cYAML_insert_child(parent, node);
1240 void cYAML_insert_child(struct cYAML *parent, struct cYAML *node)
1244 if (parent && node) {
1245 if (parent->cy_child == NULL) {
1246 parent->cy_child = node;
1250 cur = parent->cy_child;
1252 while (cur->cy_next)
1255 cur->cy_next = node;
1256 node->cy_prev = cur;
1260 void cYAML_insert_sibling(struct cYAML *root, struct cYAML *sibling)
1262 struct cYAML *last = NULL;
1263 if (root == NULL || sibling == NULL)
1267 while (last->cy_next != NULL)
1268 last = last->cy_next;
1270 last->cy_next = sibling;
1273 void cYAML_build_error(int rc, int seq_no, char *cmd,
1274 char *entity, char *err_str,
1275 struct cYAML **root)
1277 struct cYAML *r = NULL, *err, *s, *itm = NULL, *cmd_obj;
1281 /* add to the tail of the root that's passed in */
1282 if ((*root) == NULL) {
1283 *root = cYAML_create_object(NULL, NULL);
1284 if ((*root) == NULL)
1290 /* look for the command */
1291 cmd_obj = cYAML_get_object_item(r, (const char *)cmd);
1292 if (cmd_obj != NULL && cmd_obj->cy_type == CYAML_TYPE_ARRAY)
1293 itm = cYAML_create_seq_item(cmd_obj);
1294 else if (cmd_obj == NULL) {
1295 s = cYAML_create_seq(r, cmd);
1296 itm = cYAML_create_seq_item(s);
1297 } else if (cmd_obj != NULL && cmd_obj->cy_type != CYAML_TYPE_ARRAY) {
1301 err = cYAML_create_object(itm, entity);
1306 cYAML_create_number(err, "seq_no", seq_no) == NULL)
1309 if (cYAML_create_number(err, "errno", rc) == NULL)
1312 if (cYAML_create_string(err, "descr", err_str) == NULL)
1318 /* Only reason we get here is if we run out of memory */
1321 fprintf(stderr, "error:\n\tfatal: out of memory\n");
1324 static struct cYAML *
1325 cYAML_parser_to_tree(yaml_parser_t *parser, struct cYAML **err_rc, bool debug)
1328 struct cYAML_tree_node tree;
1329 enum cYAML_handler_error rc;
1330 yaml_token_type_t token_type;
1334 memset(&tree, 0, sizeof(struct cYAML_tree_node));
1336 INIT_LIST_HEAD(&tree.ll);
1338 /* Read the event sequence. */
1341 * Go through the parser and build a cYAML representation
1342 * of the passed in YAML text
1344 yaml_parser_scan(parser, &token);
1347 fprintf(stderr, "tree.state(%p:%d) = %s, token.type ="
1349 &tree, tree.state, state_string[tree.state],
1350 token_type_string[token.type],
1351 (token.type == YAML_SCALAR_TOKEN) ?
1352 (char*)token.data.scalar.value : "");
1353 rc = dispatch_tbl[token.type](&token, &tree);
1354 if (rc != CYAML_ERROR_NONE) {
1355 snprintf(err_str, sizeof(err_str),
1356 "Failed to handle token:%d %s [state=%d, rc=%d]",
1357 token.type, token_type_string[token.type],
1359 cYAML_build_error(-1, -1, "yaml", "builder",
1363 /* Are we finished? */
1364 done = (rc != CYAML_ERROR_NONE ||
1365 token.type == YAML_STREAM_END_TOKEN);
1367 token_type = token.type;
1369 yaml_token_delete(&token);
1372 if (token_type == YAML_STREAM_END_TOKEN &&
1373 rc == CYAML_ERROR_NONE)
1376 cYAML_free_tree(tree.root);
1381 struct cYAML *cYAML_load(FILE *file, struct cYAML **err_rc, bool debug)
1383 yaml_parser_t parser;
1386 yaml_parser_initialize(&parser);
1387 yaml_parser_set_input_file(&parser, file);
1389 yaml = cYAML_parser_to_tree(&parser, err_rc, debug);
1391 yaml_parser_delete(&parser);
1396 struct cYAML *cYAML_build_tree(char *path,
1397 const char *yaml_blk,
1398 size_t yaml_blk_size,
1399 struct cYAML **err_rc,
1402 yaml_parser_t parser;
1407 /* Create the Parser object. */
1408 yaml_parser_initialize(&parser);
1410 /* file always takes precedence */
1412 /* Set a file input. */
1413 input = fopen(path, "rb");
1414 if (input == NULL) {
1415 snprintf(err_str, sizeof(err_str),
1416 "cannot open '%s': %s", path, strerror(errno));
1417 cYAML_build_error(-1, -1, "yaml", "builder",
1423 yaml_parser_set_input_file(&parser, input);
1424 } else if (yaml_blk != NULL) {
1425 yaml_parser_set_input_string(&parser,
1426 (const unsigned char *) yaml_blk,
1429 /* assume that we're getting our input froms stdin */
1430 yaml_parser_set_input_file(&parser, stdin);
1433 yaml = cYAML_parser_to_tree(&parser, err_rc, debug);
1435 /* Destroy the Parser object. */
1436 yaml_parser_delete(&parser);