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, 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
47 #include "libcfs/list.h"
55 * This structure contains print information
56 * required when printing the node
58 struct cYAML_print_info {
66 * Linked list of different trees representing YAML
70 struct list_head list;
72 struct cYAML_print_info *print_info;
75 static void print_value(FILE *f, struct list_head *stack);
77 enum cYAML_handler_error {
79 CYAML_ERROR_UNEXPECTED_STATE = -1,
80 CYAML_ERROR_NOT_SUPPORTED = -2,
81 CYAML_ERROR_OUT_OF_MEM = -3,
82 CYAML_ERROR_BAD_VALUE = -4,
83 CYAML_ERROR_PARSE = -5,
86 enum cYAML_tree_state {
87 TREE_STATE_COMPLETE = 0,
89 TREE_STATE_TREE_STARTED,
90 TREE_STATE_BLK_STARTED,
92 TREE_STATE_KEY_FILLED,
97 struct cYAML_tree_node {
99 /* cur is the current node we're operating on */
101 enum cYAML_tree_state state;
102 int from_blk_map_start;
103 /* represents the tree depth */
107 typedef enum cYAML_handler_error (*yaml_token_handler)(yaml_token_t *token,
108 struct cYAML_tree_node *);
110 static enum cYAML_handler_error yaml_parse_error(yaml_token_t *token,
111 struct cYAML_tree_node *tree);
112 static enum cYAML_handler_error yaml_stream_start(yaml_token_t *token,
113 struct cYAML_tree_node *tree);
114 static enum cYAML_handler_error yaml_stream_end(yaml_token_t *token,
115 struct cYAML_tree_node *tree);
116 static enum cYAML_handler_error yaml_not_supported(yaml_token_t *token,
117 struct cYAML_tree_node *tree);
118 static enum cYAML_handler_error yaml_document_start(yaml_token_t *token,
119 struct cYAML_tree_node *tree);
120 static enum cYAML_handler_error yaml_document_end(yaml_token_t *token,
121 struct cYAML_tree_node *tree);
122 static enum cYAML_handler_error yaml_blk_seq_start(yaml_token_t *token,
123 struct cYAML_tree_node *tree);
124 static enum cYAML_handler_error yaml_blk_mapping_start(yaml_token_t *token,
125 struct cYAML_tree_node *tree);
126 static enum cYAML_handler_error yaml_block_end(yaml_token_t *token,
127 struct cYAML_tree_node *tree);
128 static enum cYAML_handler_error yaml_key(yaml_token_t *token,
129 struct cYAML_tree_node *tree);
130 static enum cYAML_handler_error yaml_value(yaml_token_t *token,
131 struct cYAML_tree_node *tree);
132 static enum cYAML_handler_error yaml_scalar(yaml_token_t *token,
133 struct cYAML_tree_node *tree);
134 static enum cYAML_handler_error yaml_entry_token(yaml_token_t *token,
135 struct cYAML_tree_node *tree);
138 static yaml_token_handler dispatch_tbl[] = {
139 [YAML_NO_TOKEN] = yaml_parse_error,
140 [YAML_STREAM_START_TOKEN] = yaml_stream_start,
141 [YAML_STREAM_END_TOKEN] = yaml_stream_end,
142 [YAML_VERSION_DIRECTIVE_TOKEN] = yaml_not_supported,
143 [YAML_TAG_DIRECTIVE_TOKEN] = yaml_not_supported,
144 [YAML_DOCUMENT_START_TOKEN] = yaml_document_start,
145 [YAML_DOCUMENT_END_TOKEN] = yaml_document_end,
146 [YAML_BLOCK_SEQUENCE_START_TOKEN] = yaml_blk_seq_start,
147 [YAML_BLOCK_MAPPING_START_TOKEN] = yaml_blk_mapping_start,
148 [YAML_BLOCK_END_TOKEN] = yaml_block_end,
149 [YAML_FLOW_SEQUENCE_START_TOKEN] = yaml_not_supported,
150 [YAML_FLOW_SEQUENCE_END_TOKEN] = yaml_not_supported,
151 [YAML_FLOW_MAPPING_START_TOKEN] = yaml_not_supported,
152 [YAML_FLOW_MAPPING_END_TOKEN] = yaml_not_supported,
153 [YAML_BLOCK_ENTRY_TOKEN] = yaml_entry_token,
154 [YAML_FLOW_ENTRY_TOKEN] = yaml_not_supported,
155 [YAML_KEY_TOKEN] = yaml_key,
156 [YAML_VALUE_TOKEN] = yaml_value,
157 [YAML_ALIAS_TOKEN] = yaml_not_supported,
158 [YAML_ANCHOR_TOKEN] = yaml_not_supported,
159 [YAML_TAG_TOKEN] = yaml_not_supported,
160 [YAML_SCALAR_TOKEN] = yaml_scalar,
163 static void cYAML_ll_free(struct list_head *ll)
165 struct cYAML_ll *node, *tmp;
167 list_for_each_entry_safe(node, tmp, ll, list) {
168 free(node->print_info);
173 static int cYAML_ll_push(struct cYAML *obj,
174 const struct cYAML_print_info *print_info,
175 struct list_head *list)
177 struct cYAML_ll *node = calloc(1, sizeof(*node));
181 INIT_LIST_HEAD(&node->list);
184 node->print_info = calloc(1, sizeof(*print_info));
185 if (node->print_info == NULL) {
189 *node->print_info = *print_info;
193 list_add(&node->list, list);
198 static struct cYAML *cYAML_ll_pop(struct list_head *list,
199 struct cYAML_print_info **print_info)
201 struct cYAML_ll *pop;
202 struct cYAML *obj = NULL;
204 if (!list_empty(list)) {
205 pop = list_entry(list->next, struct cYAML_ll, list);
208 if (print_info != NULL)
209 *print_info = pop->print_info;
210 list_del(&pop->list);
212 if (print_info == NULL)
213 free(pop->print_info);
220 static int cYAML_ll_count(struct list_head *ll)
223 struct list_head *node;
225 list_for_each(node, ll)
231 static int cYAML_tree_init(struct cYAML_tree_node *tree)
233 struct cYAML *obj = NULL, *cur = NULL;
238 obj = calloc(1, sizeof(*obj));
243 /* append the node */
245 while (cur->cy_next != NULL)
252 obj->cy_type = CYAML_TYPE_OBJECT;
255 tree->state = TREE_STATE_COMPLETE;
257 /* free it and start anew */
258 if (!list_empty(&tree->ll))
259 cYAML_ll_free(&tree->ll);
264 static struct cYAML *create_child(struct cYAML *parent)
271 obj = calloc(1, sizeof(*obj));
275 /* set the type to OBJECT and let the value change that */
276 obj->cy_type = CYAML_TYPE_OBJECT;
278 parent->cy_child = obj;
283 static struct cYAML *create_sibling(struct cYAML *sibling)
290 obj = calloc(1, sizeof(*obj));
294 /* set the type to OBJECT and let the value change that */
295 obj->cy_type = CYAML_TYPE_OBJECT;
297 sibling->cy_next = obj;
298 obj->cy_prev = sibling;
303 /* Parse the input text to generate a number,
304 * and populate the result into item. */
305 static bool parse_number(struct cYAML *item, const char *input)
307 double n = 0, sign = 1, scale = 0;
308 int subscale = 0, signsubscale = 1;
309 const char *num = input;
319 if (*num >= '1' && *num <= '9') {
321 n = (n * 10.0) + (*num++ - '0');
322 } while (*num >= '0' && *num <= '9');
325 if (*num == '.' && num[1] >= '0' && num[1] <= '9') {
328 n = (n * 10.0) + (*num++ - '0');
330 } while (*num >= '0' && *num <= '9');
333 if (*num == 'e' || *num == 'E') {
337 } else if (*num == '-') {
341 while (*num >= '0' && *num <= '9')
342 subscale = (subscale * 10) + (*num++ - '0');
345 /* check to see if the entire string is consumed. If not then
346 * that means this is a string with a number in it */
347 if (num != (input + strlen(input)))
350 /* number = +/- number.fraction * 10^+/- exponent */
351 n = sign * n * pow(10.0, (scale + subscale * signsubscale));
353 item->cy_valuedouble = n;
354 item->cy_valueint = (int)n;
355 item->cy_type = CYAML_TYPE_NUMBER;
360 static int assign_type_value(struct cYAML *obj, const char *value)
365 if (strcmp(value, "null") == 0)
366 obj->cy_type = CYAML_TYPE_NULL;
367 else if (strcmp(value, "false") == 0) {
368 obj->cy_type = CYAML_TYPE_FALSE;
369 obj->cy_valueint = 0;
370 } else if (strcmp(value, "true") == 0) {
371 obj->cy_type = CYAML_TYPE_TRUE;
372 obj->cy_valueint = 1;
373 } else if (*value == '-' || (*value >= '0' && *value <= '9')) {
374 if (parse_number(obj, value) == 0) {
375 obj->cy_valuestring = strdup(value);
376 obj->cy_type = CYAML_TYPE_STRING;
379 obj->cy_valuestring = strdup(value);
380 obj->cy_type = CYAML_TYPE_STRING;
388 * Builds the YAML tree rpresentation as the tokens are passed in
390 * if token == STREAM_START && tree_state != COMPLETE
391 * something wrong. fail.
392 * else tree_state = INITIED
393 * if token == DOCUMENT_START && tree_state != COMPLETE || INITED
394 * something wrong, fail.
395 * else tree_state = TREE_STARTED
396 * if token == DOCUMENT_END
397 * tree_state = INITED if no STREAM START, else tree_state = COMPLETE
398 * erase everything on ll
399 * if token == STREAM_END && tree_state != INITED
400 * something wrong fail.
401 * else tree_state = COMPLETED
402 * if token == YAML_KEY_TOKEN && state != TREE_STARTED
403 * something wrong, fail.
404 * if token == YAML_SCALAR_TOKEN && state != KEY || VALUE
406 * else if tree_state == KEY
407 * create a new sibling under the current head of the ll (if ll is
408 * empty insert the new node there and it becomes the root.)
409 * add the scalar value in the "string"
410 * tree_state = KEY_FILLED
411 * else if tree_state == VALUE
412 * try and figure out whether this is a double, int or string and store
414 * state = TREE_STARTED
415 * else if token == YAML_BLOCK_MAPPING_START_TOKEN && tree_state != VALUE
417 * else push the current node on the ll && state = TREE_STARTED
418 * if token == YAML_BLOCK_END_TOKEN && state != TREE_STARTED
420 * else pop the current token off the ll and make it the cur
421 * if token == YAML_VALUE_TOKEN && state != KEY_FILLED
426 static enum cYAML_handler_error yaml_parse_error(yaml_token_t *token,
427 struct cYAML_tree_node *tree)
429 return CYAML_ERROR_PARSE;
432 static enum cYAML_handler_error yaml_stream_start(yaml_token_t *token,
433 struct cYAML_tree_node *tree)
435 enum cYAML_handler_error rc;
437 /* with each new stream initialize a new tree */
438 rc = cYAML_tree_init(tree);
440 if (rc != CYAML_ERROR_NONE)
443 tree->state = TREE_STATE_INITED;
445 return CYAML_ERROR_NONE;
448 static enum cYAML_handler_error yaml_stream_end(yaml_token_t *token,
449 struct cYAML_tree_node *tree)
451 if (tree->state != TREE_STATE_TREE_STARTED &&
452 tree->state != TREE_STATE_COMPLETE)
453 return CYAML_ERROR_UNEXPECTED_STATE;
455 tree->state = TREE_STATE_INITED;
457 return CYAML_ERROR_NONE;
460 static enum cYAML_handler_error
461 yaml_document_start(yaml_token_t *token, struct cYAML_tree_node *tree)
463 if (tree->state != TREE_STATE_INITED)
464 return CYAML_ERROR_UNEXPECTED_STATE;
466 /* go to started state since we're expecting more tokens to come */
467 tree->state = TREE_STATE_TREE_STARTED;
469 return CYAML_ERROR_NONE;
472 static enum cYAML_handler_error yaml_document_end(yaml_token_t *token,
473 struct cYAML_tree_node *tree)
475 if (tree->state != TREE_STATE_COMPLETE)
476 return CYAML_ERROR_UNEXPECTED_STATE;
478 tree->state = TREE_STATE_TREE_STARTED;
480 return CYAML_ERROR_NONE;
483 static enum cYAML_handler_error yaml_key(yaml_token_t *token,
484 struct cYAML_tree_node *tree)
486 if (tree->state != TREE_STATE_BLK_STARTED &&
487 tree->state != TREE_STATE_VALUE)
488 return CYAML_ERROR_UNEXPECTED_STATE;
490 if (tree->from_blk_map_start == 0 ||
491 tree->state == TREE_STATE_VALUE)
492 tree->cur = create_sibling(tree->cur);
494 tree->from_blk_map_start = 0;
496 tree->state = TREE_STATE_KEY;
498 return CYAML_ERROR_NONE;
501 static enum cYAML_handler_error yaml_scalar(yaml_token_t *token,
502 struct cYAML_tree_node *tree)
504 if (tree->state == TREE_STATE_KEY) {
505 /* assign the scalar value to the key that was created */
506 tree->cur->cy_string =
507 strdup((const char *)token->data.scalar.value);
509 tree->state = TREE_STATE_KEY_FILLED;
510 } else if (tree->state == TREE_STATE_VALUE) {
511 if (assign_type_value(tree->cur,
512 (char *)token->data.scalar.value))
513 /* failed to assign a value */
514 return CYAML_ERROR_BAD_VALUE;
515 tree->state = TREE_STATE_BLK_STARTED;
517 return CYAML_ERROR_UNEXPECTED_STATE;
520 return CYAML_ERROR_NONE;
523 static enum cYAML_handler_error yaml_value(yaml_token_t *token,
524 struct cYAML_tree_node *tree)
526 if (tree->state != TREE_STATE_KEY_FILLED)
527 return CYAML_ERROR_UNEXPECTED_STATE;
529 tree->state = TREE_STATE_VALUE;
531 return CYAML_ERROR_NONE;
534 static enum cYAML_handler_error yaml_blk_seq_start(yaml_token_t *token,
535 struct cYAML_tree_node *tree)
537 if (tree->state != TREE_STATE_VALUE)
538 return CYAML_ERROR_UNEXPECTED_STATE;
540 /* Since a sequenc start event determines that this is the start
541 * of an array, then that means the current node we're at is an
542 * array and we need to flag it as such */
543 tree->cur->cy_type = CYAML_TYPE_ARRAY;
544 tree->state = TREE_STATE_SEQ_START;
546 return CYAML_ERROR_NONE;
549 static enum cYAML_handler_error yaml_entry_token(yaml_token_t *token,
550 struct cYAML_tree_node *tree)
554 if (tree->state != TREE_STATE_SEQ_START &&
555 tree->state != TREE_STATE_BLK_STARTED)
556 return CYAML_ERROR_UNEXPECTED_STATE;
558 if (tree->state == TREE_STATE_SEQ_START) {
559 obj = create_child(tree->cur);
561 if (cYAML_ll_push(tree->cur, NULL, &tree->ll))
562 return CYAML_ERROR_OUT_OF_MEM;
566 tree->cur = create_sibling(tree->cur);
567 tree->state = TREE_STATE_SEQ_START;
570 return CYAML_ERROR_NONE;
573 static enum cYAML_handler_error
574 yaml_blk_mapping_start(yaml_token_t *token,
575 struct cYAML_tree_node *tree)
579 if (tree->state != TREE_STATE_VALUE &&
580 tree->state != TREE_STATE_INITED &&
581 tree->state != TREE_STATE_SEQ_START &&
582 tree->state != TREE_STATE_TREE_STARTED)
583 return CYAML_ERROR_UNEXPECTED_STATE;
585 /* block_mapping_start means we're entering another block
586 * indentation, so we need to go one level deeper
587 * create a child of cur */
588 obj = create_child(tree->cur);
590 /* push cur on the stack */
591 if (cYAML_ll_push(tree->cur, NULL, &tree->ll))
592 return CYAML_ERROR_OUT_OF_MEM;
594 /* adding the new child to cur */
597 tree->state = TREE_STATE_BLK_STARTED;
599 tree->from_blk_map_start = 1;
601 return CYAML_ERROR_NONE;
604 static enum cYAML_handler_error yaml_block_end(yaml_token_t *token,
605 struct cYAML_tree_node *tree)
607 if (tree->state != TREE_STATE_BLK_STARTED &&
608 tree->state != TREE_STATE_VALUE)
609 return CYAML_ERROR_UNEXPECTED_STATE;
611 tree->cur = cYAML_ll_pop(&tree->ll, NULL);
613 /* if you have popped all the way to the top level, then move to
614 * the complete state. */
615 if (cYAML_ll_count(&tree->ll) == 0)
616 tree->state = TREE_STATE_COMPLETE;
617 else if (tree->state == TREE_STATE_VALUE)
618 tree->state = TREE_STATE_BLK_STARTED;
620 return CYAML_ERROR_NONE;
623 static enum cYAML_handler_error yaml_not_supported(yaml_token_t *token,
624 struct cYAML_tree_node *tree)
626 return CYAML_ERROR_NOT_SUPPORTED;
629 static bool clean_usr_data(struct cYAML *node, void *usr_data, void **out)
631 cYAML_user_data_free_cb free_cb = usr_data;
633 if (free_cb && node && node->cy_user_data) {
634 free_cb(node->cy_user_data);
635 node->cy_user_data = NULL;
641 static bool free_node(struct cYAML *node, void *user_data, void **out)
649 static bool find_obj_iter(struct cYAML *node, void *usr_data, void **out)
651 char *name = usr_data;
653 if (node != NULL && node->cy_string != NULL &&
654 strcmp(node->cy_string, name) == 0) {
662 struct cYAML *cYAML_get_object_item(struct cYAML *parent, const char *name)
666 if (parent == NULL || parent->cy_child == NULL || name == NULL)
669 node = parent->cy_child;
671 while (node != NULL &&
672 strcmp(node->cy_string, name) != 0) {
673 node = node->cy_next;
679 struct cYAML *cYAML_get_next_seq_item(struct cYAML *seq, struct cYAML **itm)
681 if (*itm != NULL && (*itm)->cy_next != NULL) {
682 *itm = (*itm)->cy_next;
686 if (*itm == NULL && seq->cy_type == CYAML_TYPE_ARRAY) {
687 *itm = seq->cy_child;
694 bool cYAML_is_sequence(struct cYAML *node)
696 return (node != NULL ? node->cy_type == CYAML_TYPE_ARRAY : 0);
699 void cYAML_tree_recursive_walk(struct cYAML *node, cYAML_walk_cb cb,
708 if (!cb(node, usr_data, out))
713 cYAML_tree_recursive_walk(node->cy_child, cb,
714 cb_first, usr_data, out);
717 cYAML_tree_recursive_walk(node->cy_next, cb,
718 cb_first, usr_data, out);
721 if (!cb(node, usr_data, out))
726 struct cYAML *cYAML_find_object(struct cYAML *root, const char *name)
728 struct cYAML *found = NULL;
730 cYAML_tree_recursive_walk(root, find_obj_iter, true,
731 (void *)name, (void **)&found);
736 void cYAML_clean_usr_data(struct cYAML *node, cYAML_user_data_free_cb free_cb)
738 cYAML_tree_recursive_walk(node, clean_usr_data, false, free_cb, NULL);
741 void cYAML_free_tree(struct cYAML *node)
743 cYAML_tree_recursive_walk(node, free_node, false, NULL, NULL);
746 static inline void print_simple(FILE *f, struct cYAML *node,
747 struct cYAML_print_info *cpi)
749 int level = cpi->level;
750 int ind = cpi->extra_ind;
752 if (cpi->array_first_elem)
753 fprintf(f, "%*s- ", INDENT * level, "");
755 fprintf(f, "%*s""%s: %d\n", (cpi->array_first_elem) ? 0 :
756 INDENT * level + ind, "", node->cy_string,
760 static void print_string(FILE *f, struct cYAML *node,
761 struct cYAML_print_info *cpi)
764 int level = cpi->level;
765 int ind = cpi->extra_ind;
767 if (cpi->array_first_elem)
768 fprintf(f, "%*s- ", INDENT * level, "");
770 new_line = strchr(node->cy_valuestring, '\n');
771 if (new_line == NULL)
772 fprintf(f, "%*s""%s: %s\n", (cpi->array_first_elem) ?
773 0 : INDENT * level + ind, "",
774 node->cy_string, node->cy_valuestring);
777 fprintf(f, "%*s""%s: ", (cpi->array_first_elem) ?
778 0 : INDENT * level + ind, "",
780 char *l = node->cy_valuestring;
783 fprintf(f, "%*s""%s\n", indent, "", l);
784 indent = INDENT * level + ind +
785 strlen(node->cy_string) + 2;
788 new_line = strchr(l, '\n');
790 fprintf(f, "%*s""%s\n", indent, "", l);
794 static void print_number(FILE *f, struct cYAML *node,
795 struct cYAML_print_info *cpi)
797 double d = node->cy_valuedouble;
798 int level = cpi->level;
799 int ind = cpi->extra_ind;
801 if (cpi->array_first_elem)
802 fprintf(f, "%*s- ", INDENT * level, "");
804 if ((fabs(((double)node->cy_valueint) - d) <= DBL_EPSILON) &&
805 (d <= INT_MAX) && (d >= INT_MIN))
806 fprintf(f, "%*s""%s: %d\n", (cpi->array_first_elem) ? 0 :
807 INDENT * level + ind, "",
808 node->cy_string, node->cy_valueint);
810 if ((fabs(floor(d) - d) <= DBL_EPSILON) &&
812 fprintf(f, "%*s""%s: %.0f\n",
813 (cpi->array_first_elem) ? 0 :
814 INDENT * level + ind, "",
816 else if ((fabs(d) < 1.0e-6) || (fabs(d) > 1.0e9))
817 fprintf(f, "%*s""%s: %e\n",
818 (cpi->array_first_elem) ? 0 :
819 INDENT * level + ind, "",
822 fprintf(f, "%*s""%s: %f\n",
823 (cpi->array_first_elem) ? 0 :
824 INDENT * level + ind, "",
829 static void print_object(FILE *f, struct cYAML *node,
830 struct list_head *stack,
831 struct cYAML_print_info *cpi)
833 struct cYAML_print_info print_info;
834 struct cYAML *child = node->cy_child;
836 if (node->cy_string != NULL)
837 fprintf(f, "%*s""%s%s:\n", (cpi->array_first_elem) ?
838 INDENT * cpi->level :
839 INDENT * cpi->level + cpi->extra_ind,
840 "", (cpi->array_first_elem) ? "- " : "",
843 print_info.level = (node->cy_string != NULL) ? cpi->level + 1 :
845 print_info.array_first_elem = (node->cy_string == NULL) ?
846 cpi->array_first_elem : 0;
847 print_info.extra_ind = (cpi->array_first_elem) ? EXTRA_IND :
851 if (cYAML_ll_push(child, &print_info, stack) != 0)
853 print_value(f, stack);
854 print_info.array_first_elem = 0;
855 child = child->cy_next;
859 static void print_array(FILE *f, struct cYAML *node,
860 struct list_head *stack,
861 struct cYAML_print_info *cpi)
863 struct cYAML_print_info print_info;
864 struct cYAML *child = node->cy_child;
866 if (node->cy_string != NULL) {
867 fprintf(f, "%*s""%s:\n", INDENT * cpi->level + cpi->extra_ind,
868 "", node->cy_string);
871 print_info.level = (node->cy_string != NULL) ? cpi->level + 1 :
873 print_info.array_first_elem = 1;
874 print_info.extra_ind = EXTRA_IND;
877 if (cYAML_ll_push(child, &print_info, stack) != 0)
879 print_value(f, stack);
880 child = child->cy_next;
884 static void print_value(FILE *f, struct list_head *stack)
886 struct cYAML_print_info *cpi = NULL;
887 struct cYAML *node = cYAML_ll_pop(stack, &cpi);
892 switch (node->cy_type) {
893 case CYAML_TYPE_FALSE:
894 case CYAML_TYPE_TRUE:
895 case CYAML_TYPE_NULL:
896 print_simple(f, node, cpi);
898 case CYAML_TYPE_STRING:
899 print_string(f, node, cpi);
901 case CYAML_TYPE_NUMBER:
902 print_number(f, node, cpi);
904 case CYAML_TYPE_ARRAY:
905 print_array(f, node, stack, cpi);
907 case CYAML_TYPE_OBJECT:
908 print_object(f, node, stack, cpi);
918 void cYAML_print_tree(struct cYAML *node)
920 struct cYAML_print_info print_info;
921 struct list_head list;
923 INIT_LIST_HEAD(&list);
928 memset(&print_info, 0, sizeof(struct cYAML_print_info));
930 if (cYAML_ll_push(node, &print_info, &list) == 0)
931 print_value(stdout, &list);
934 void cYAML_print_tree2file(FILE *f, struct cYAML *node)
936 struct cYAML_print_info print_info;
937 struct list_head list;
939 INIT_LIST_HEAD(&list);
944 memset(&print_info, 0, sizeof(struct cYAML_print_info));
946 if (cYAML_ll_push(node, &print_info, &list) == 0)
947 print_value(f, &list);
950 static struct cYAML *insert_item(struct cYAML *parent, char *key,
951 enum cYAML_object_type type)
953 struct cYAML *node = calloc(1, sizeof(*node));
959 node->cy_string = strdup(key);
961 node->cy_type = type;
963 cYAML_insert_child(parent, node);
968 struct cYAML *cYAML_create_seq(struct cYAML *parent, char *key)
970 return insert_item(parent, key, CYAML_TYPE_ARRAY);
973 struct cYAML *cYAML_create_seq_item(struct cYAML *seq)
975 return insert_item(seq, NULL, CYAML_TYPE_OBJECT);
978 struct cYAML *cYAML_create_object(struct cYAML *parent, char *key)
980 return insert_item(parent, key, CYAML_TYPE_OBJECT);
983 struct cYAML *cYAML_create_string(struct cYAML *parent, char *key, char *value)
985 struct cYAML *node = calloc(1, sizeof(*node));
989 node->cy_string = strdup(key);
990 node->cy_valuestring = strdup(value);
991 node->cy_type = CYAML_TYPE_STRING;
993 cYAML_insert_child(parent, node);
998 struct cYAML *cYAML_create_number(struct cYAML *parent, char *key, double value)
1000 struct cYAML *node = calloc(1, sizeof(*node));
1004 node->cy_string = strdup(key);
1005 node->cy_valuedouble = value;
1006 node->cy_valueint = (int)value;
1007 node->cy_type = CYAML_TYPE_NUMBER;
1009 cYAML_insert_child(parent, node);
1014 void cYAML_insert_child(struct cYAML *parent, struct cYAML *node)
1018 if (parent && node) {
1019 if (parent->cy_child == NULL) {
1020 parent->cy_child = node;
1024 cur = parent->cy_child;
1026 while (cur->cy_next)
1029 cur->cy_next = node;
1030 node->cy_prev = cur;
1034 void cYAML_insert_sibling(struct cYAML *root, struct cYAML *sibling)
1036 struct cYAML *last = NULL;
1037 if (root == NULL || sibling == NULL)
1041 while (last->cy_next != NULL)
1042 last = last->cy_next;
1044 last->cy_next = sibling;
1047 void cYAML_build_error(int rc, int seq_no, char *cmd,
1048 char *entity, char *err_str,
1049 struct cYAML **root)
1051 struct cYAML *r = NULL, *err, *s, *itm, *cmd_obj;
1055 /* add to the tail of the root that's passed in */
1056 if ((*root) == NULL) {
1057 *root = cYAML_create_object(NULL, NULL);
1058 if ((*root) == NULL)
1064 /* look for the command */
1065 cmd_obj = cYAML_get_object_item(r, (const char *)cmd);
1066 if (cmd_obj != NULL && cmd_obj->cy_type == CYAML_TYPE_ARRAY)
1067 itm = cYAML_create_seq_item(cmd_obj);
1068 else if (cmd_obj == NULL) {
1069 s = cYAML_create_seq(r, cmd);
1070 itm = cYAML_create_seq_item(s);
1071 } else if (cmd_obj != NULL && cmd_obj->cy_type != CYAML_TYPE_ARRAY)
1074 err = cYAML_create_object(itm, entity);
1079 cYAML_create_number(err, "seq_no", seq_no) == NULL)
1082 if (cYAML_create_number(err, "errno", rc) == NULL)
1085 if (cYAML_create_string(err, "descr", err_str) == NULL)
1095 struct cYAML *cYAML_build_tree(char *yaml_file,
1096 const char *yaml_blk,
1097 size_t yaml_blk_size,
1098 struct cYAML **err_rc)
1100 yaml_parser_t parser;
1102 struct cYAML_tree_node tree;
1103 enum cYAML_handler_error rc;
1104 yaml_token_type_t token_type;
1109 memset(&tree, 0, sizeof(struct cYAML_tree_node));
1111 INIT_LIST_HEAD(&tree.ll);
1113 /* Create the Parser object. */
1114 yaml_parser_initialize(&parser);
1116 /* file alwyas takes precedence */
1117 if (yaml_file != NULL) {
1118 /* Set a file input. */
1119 input = fopen(yaml_file, "rb");
1120 if (input == NULL) {
1121 snprintf(err_str, sizeof(err_str),
1122 "Failed to open file: %s", yaml_file);
1123 cYAML_build_error(-1, -1, "yaml", "builder",
1129 yaml_parser_set_input_file(&parser, input);
1130 } else if (yaml_blk != NULL) {
1131 yaml_parser_set_input_string(&parser,
1132 (const unsigned char *) yaml_blk,
1135 /* assume that we're getting our input froms stdin */
1136 yaml_parser_set_input_file(&parser, stdin);
1138 /* Read the event sequence. */
1141 * Go through the parser and build a cYAML representation
1142 * of the passed in YAML text
1144 yaml_parser_scan(&parser, &token);
1146 rc = dispatch_tbl[token.type](&token, &tree);
1147 if (rc != CYAML_ERROR_NONE) {
1148 snprintf(err_str, sizeof(err_str),
1149 "Failed to handle token:%d "
1150 "[state=%d, rc=%d]",
1151 token.type, tree.state, rc);
1152 cYAML_build_error(-1, -1, "yaml", "builder",
1156 /* Are we finished? */
1157 done = (rc != CYAML_ERROR_NONE ||
1158 token.type == YAML_STREAM_END_TOKEN ||
1159 token.type == YAML_NO_TOKEN);
1161 token_type = token.type;
1163 yaml_token_delete(&token);
1166 /* Destroy the Parser object. */
1167 yaml_parser_delete(&parser);
1172 if (token_type == YAML_STREAM_END_TOKEN &&
1173 rc == CYAML_ERROR_NONE)
1176 cYAML_free_tree(tree.root);