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
47 #include "libcfs/util/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_no_token(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_no_token,
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,
164 static char *token_type_string[] = {
165 [YAML_NO_TOKEN] = "YAML_NO_TOKEN",
166 [YAML_STREAM_START_TOKEN] = "YAML_STREAM_START_TOKEN",
167 [YAML_STREAM_END_TOKEN] = "YAML_STREAM_END_TOKEN",
168 [YAML_VERSION_DIRECTIVE_TOKEN] = "YAML_VERSION_DIRECTIVE_TOKEN",
169 [YAML_TAG_DIRECTIVE_TOKEN] = "YAML_TAG_DIRECTIVE_TOKEN",
170 [YAML_DOCUMENT_START_TOKEN] = "YAML_DOCUMENT_START_TOKEN",
171 [YAML_DOCUMENT_END_TOKEN] = "YAML_DOCUMENT_END_TOKEN",
172 [YAML_BLOCK_SEQUENCE_START_TOKEN] = "YAML_BLOCK_SEQUENCE_START_TOKEN",
173 [YAML_BLOCK_MAPPING_START_TOKEN] = "YAML_BLOCK_MAPPING_START_TOKEN",
174 [YAML_BLOCK_END_TOKEN] = "YAML_BLOCK_END_TOKEN",
175 [YAML_FLOW_SEQUENCE_START_TOKEN] = "YAML_FLOW_SEQUENCE_START_TOKEN",
176 [YAML_FLOW_SEQUENCE_END_TOKEN] = "YAML_FLOW_SEQUENCE_END_TOKEN",
177 [YAML_FLOW_MAPPING_START_TOKEN] = "YAML_FLOW_MAPPING_START_TOKEN",
178 [YAML_FLOW_MAPPING_END_TOKEN] = "YAML_FLOW_MAPPING_END_TOKEN",
179 [YAML_BLOCK_ENTRY_TOKEN] = "YAML_BLOCK_ENTRY_TOKEN",
180 [YAML_FLOW_ENTRY_TOKEN] = "YAML_FLOW_ENTRY_TOKEN",
181 [YAML_KEY_TOKEN] = "YAML_KEY_TOKEN",
182 [YAML_VALUE_TOKEN] = "YAML_VALUE_TOKEN",
183 [YAML_ALIAS_TOKEN] = "YAML_ALIAS_TOKEN",
184 [YAML_ANCHOR_TOKEN] = "YAML_ANCHOR_TOKEN",
185 [YAML_TAG_TOKEN] = "YAML_TAG_TOKEN",
186 [YAML_SCALAR_TOKEN] = "YAML_SCALAR_TOKEN",
189 static char *state_string[] = {
190 [TREE_STATE_COMPLETE] = "COMPLETE",
191 [TREE_STATE_INITED] = "INITED",
192 [TREE_STATE_TREE_STARTED] = "TREE_STARTED",
193 [TREE_STATE_BLK_STARTED] = "BLK_STARTED",
194 [TREE_STATE_KEY] = "KEY",
195 [TREE_STATE_KEY_FILLED] = "KEY_FILLED",
196 [TREE_STATE_VALUE] = "VALUE",
197 [TREE_STATE_SEQ_START] = "SEQ_START",
200 static void cYAML_ll_free(struct list_head *ll)
202 struct cYAML_ll *node, *tmp;
204 list_for_each_entry_safe(node, tmp, ll, list) {
205 free(node->print_info);
210 static int cYAML_ll_push(struct cYAML *obj,
211 const struct cYAML_print_info *print_info,
212 struct list_head *list)
214 struct cYAML_ll *node = calloc(1, sizeof(*node));
218 INIT_LIST_HEAD(&node->list);
221 node->print_info = calloc(1, sizeof(*print_info));
222 if (node->print_info == NULL) {
226 *node->print_info = *print_info;
230 list_add(&node->list, list);
235 static struct cYAML *cYAML_ll_pop(struct list_head *list,
236 struct cYAML_print_info **print_info)
238 struct cYAML_ll *pop;
239 struct cYAML *obj = NULL;
241 if (!list_empty(list)) {
242 pop = list_entry(list->next, struct cYAML_ll, list);
245 if (print_info != NULL)
246 *print_info = pop->print_info;
247 list_del(&pop->list);
249 if (print_info == NULL)
250 free(pop->print_info);
257 static int cYAML_ll_count(struct list_head *ll)
260 struct list_head *node;
262 list_for_each(node, ll)
268 static int cYAML_tree_init(struct cYAML_tree_node *tree)
270 struct cYAML *obj = NULL, *cur = NULL;
275 obj = calloc(1, sizeof(*obj));
280 /* append the node */
282 while (cur->cy_next != NULL)
289 obj->cy_type = CYAML_TYPE_OBJECT;
292 tree->state = TREE_STATE_COMPLETE;
294 /* free it and start anew */
295 if (!list_empty(&tree->ll))
296 cYAML_ll_free(&tree->ll);
301 static struct cYAML *create_child(struct cYAML *parent)
308 obj = calloc(1, sizeof(*obj));
312 /* set the type to OBJECT and let the value change that */
313 obj->cy_type = CYAML_TYPE_OBJECT;
315 parent->cy_child = obj;
320 static struct cYAML *create_sibling(struct cYAML *sibling)
327 obj = calloc(1, sizeof(*obj));
331 /* set the type to OBJECT and let the value change that */
332 obj->cy_type = CYAML_TYPE_OBJECT;
334 sibling->cy_next = obj;
335 obj->cy_prev = sibling;
340 /* Parse the input text to generate a number,
341 * and populate the result into item. */
342 static bool parse_number(struct cYAML *item, const char *input)
344 double n = 0, sign = 1, scale = 0;
345 int subscale = 0, signsubscale = 1;
346 const char *num = input;
356 if (*num >= '1' && *num <= '9') {
358 n = (n * 10.0) + (*num++ - '0');
359 } while (*num >= '0' && *num <= '9');
362 if (*num == '.' && num[1] >= '0' && num[1] <= '9') {
365 n = (n * 10.0) + (*num++ - '0');
367 } while (*num >= '0' && *num <= '9');
370 if (*num == 'e' || *num == 'E') {
374 } else if (*num == '-') {
378 while (*num >= '0' && *num <= '9')
379 subscale = (subscale * 10) + (*num++ - '0');
382 /* check to see if the entire string is consumed. If not then
383 * that means this is a string with a number in it */
384 if (num != (input + strlen(input)))
387 /* number = +/- number.fraction * 10^+/- exponent */
388 n = sign * n * pow(10.0, (scale + subscale * signsubscale));
390 item->cy_valuedouble = n;
391 item->cy_valueint = (int)n;
392 item->cy_type = CYAML_TYPE_NUMBER;
397 static int assign_type_value(struct cYAML *obj, const char *value)
402 if (strcmp(value, "null") == 0)
403 obj->cy_type = CYAML_TYPE_NULL;
404 else if (strcmp(value, "false") == 0) {
405 obj->cy_type = CYAML_TYPE_FALSE;
406 obj->cy_valueint = 0;
407 } else if (strcmp(value, "true") == 0) {
408 obj->cy_type = CYAML_TYPE_TRUE;
409 obj->cy_valueint = 1;
410 } else if (*value == '-' || (*value >= '0' && *value <= '9')) {
411 if (parse_number(obj, value) == 0) {
412 obj->cy_valuestring = strdup(value);
413 obj->cy_type = CYAML_TYPE_STRING;
416 obj->cy_valuestring = strdup(value);
417 obj->cy_type = CYAML_TYPE_STRING;
425 * Builds the YAML tree rpresentation as the tokens are passed in
427 * if token == STREAM_START && tree_state != COMPLETE
428 * something wrong. fail.
429 * else tree_state = INITIED
430 * if token == DOCUMENT_START && tree_state != COMPLETE || INITED
431 * something wrong, fail.
432 * else tree_state = TREE_STARTED
433 * if token == DOCUMENT_END
434 * tree_state = INITED if no STREAM START, else tree_state = COMPLETE
435 * erase everything on ll
436 * if token == STREAM_END && tree_state != INITED
437 * something wrong fail.
438 * else tree_state = COMPLETED
439 * if token == YAML_KEY_TOKEN && state != TREE_STARTED
440 * something wrong, fail.
441 * if token == YAML_SCALAR_TOKEN && state != KEY || VALUE
443 * else if tree_state == KEY
444 * create a new sibling under the current head of the ll (if ll is
445 * empty insert the new node there and it becomes the root.)
446 * add the scalar value in the "string"
447 * tree_state = KEY_FILLED
448 * else if tree_state == VALUE
449 * try and figure out whether this is a double, int or string and store
451 * state = TREE_STARTED
452 * else if token == YAML_BLOCK_MAPPING_START_TOKEN && tree_state != VALUE
454 * else push the current node on the ll && state = TREE_STARTED
455 * if token == YAML_BLOCK_END_TOKEN && state != TREE_STARTED
457 * else pop the current token off the ll and make it the cur
458 * if token == YAML_VALUE_TOKEN && state != KEY_FILLED
464 static enum cYAML_handler_error yaml_no_token(yaml_token_t *token,
465 struct cYAML_tree_node *tree)
467 return CYAML_ERROR_NONE;
470 static enum cYAML_handler_error yaml_stream_start(yaml_token_t *token,
471 struct cYAML_tree_node *tree)
473 enum cYAML_handler_error rc;
475 /* with each new stream initialize a new tree */
476 rc = cYAML_tree_init(tree);
478 if (rc != CYAML_ERROR_NONE)
481 tree->state = TREE_STATE_INITED;
483 return CYAML_ERROR_NONE;
486 static enum cYAML_handler_error yaml_stream_end(yaml_token_t *token,
487 struct cYAML_tree_node *tree)
489 if (tree->state != TREE_STATE_TREE_STARTED &&
490 tree->state != TREE_STATE_COMPLETE &&
491 tree->state != TREE_STATE_INITED)
492 return CYAML_ERROR_UNEXPECTED_STATE;
494 tree->state = TREE_STATE_INITED;
496 return CYAML_ERROR_NONE;
499 static enum cYAML_handler_error
500 yaml_document_start(yaml_token_t *token, struct cYAML_tree_node *tree)
502 if (tree->state != TREE_STATE_INITED)
503 return CYAML_ERROR_UNEXPECTED_STATE;
505 /* go to started state since we're expecting more tokens to come */
506 tree->state = TREE_STATE_TREE_STARTED;
508 return CYAML_ERROR_NONE;
511 static enum cYAML_handler_error yaml_document_end(yaml_token_t *token,
512 struct cYAML_tree_node *tree)
514 if (tree->state != TREE_STATE_COMPLETE)
515 return CYAML_ERROR_UNEXPECTED_STATE;
517 tree->state = TREE_STATE_TREE_STARTED;
519 return CYAML_ERROR_NONE;
522 static enum cYAML_handler_error yaml_key(yaml_token_t *token,
523 struct cYAML_tree_node *tree)
525 if (tree->state != TREE_STATE_BLK_STARTED &&
526 tree->state != TREE_STATE_VALUE)
527 return CYAML_ERROR_UNEXPECTED_STATE;
529 if (tree->from_blk_map_start == 0 ||
530 tree->state == TREE_STATE_VALUE)
531 tree->cur = create_sibling(tree->cur);
533 tree->from_blk_map_start = 0;
535 tree->state = TREE_STATE_KEY;
537 return CYAML_ERROR_NONE;
540 static enum cYAML_handler_error yaml_scalar(yaml_token_t *token,
541 struct cYAML_tree_node *tree)
543 if (tree->state == TREE_STATE_KEY) {
544 /* assign the scalar value to the key that was created */
545 tree->cur->cy_string =
546 strdup((const char *)token->data.scalar.value);
548 tree->state = TREE_STATE_KEY_FILLED;
549 } else if (tree->state == TREE_STATE_VALUE ||
550 tree->state == TREE_STATE_SEQ_START) {
551 if (assign_type_value(tree->cur,
552 (char *)token->data.scalar.value))
553 /* failed to assign a value */
554 return CYAML_ERROR_BAD_VALUE;
555 tree->state = TREE_STATE_BLK_STARTED;
557 return CYAML_ERROR_UNEXPECTED_STATE;
560 return CYAML_ERROR_NONE;
563 static enum cYAML_handler_error yaml_value(yaml_token_t *token,
564 struct cYAML_tree_node *tree)
566 if (tree->state != TREE_STATE_KEY_FILLED)
567 return CYAML_ERROR_UNEXPECTED_STATE;
569 tree->state = TREE_STATE_VALUE;
571 return CYAML_ERROR_NONE;
574 static enum cYAML_handler_error yaml_blk_seq_start(yaml_token_t *token,
575 struct cYAML_tree_node *tree)
577 if (tree->state != TREE_STATE_VALUE)
578 return CYAML_ERROR_UNEXPECTED_STATE;
580 /* Since a sequenc start event determines that this is the start
581 * of an array, then that means the current node we're at is an
582 * array and we need to flag it as such */
583 tree->cur->cy_type = CYAML_TYPE_ARRAY;
584 tree->state = TREE_STATE_SEQ_START;
586 return CYAML_ERROR_NONE;
589 static enum cYAML_handler_error yaml_entry_token(yaml_token_t *token,
590 struct cYAML_tree_node *tree)
594 if (tree->state != TREE_STATE_SEQ_START &&
595 tree->state != TREE_STATE_BLK_STARTED &&
596 tree->state != TREE_STATE_VALUE)
597 return CYAML_ERROR_UNEXPECTED_STATE;
599 if (tree->state == TREE_STATE_SEQ_START) {
600 obj = create_child(tree->cur);
602 if (cYAML_ll_push(tree->cur, NULL, &tree->ll))
603 return CYAML_ERROR_OUT_OF_MEM;
607 tree->cur = create_sibling(tree->cur);
608 tree->state = TREE_STATE_SEQ_START;
611 return CYAML_ERROR_NONE;
614 static enum cYAML_handler_error
615 yaml_blk_mapping_start(yaml_token_t *token,
616 struct cYAML_tree_node *tree)
620 if (tree->state != TREE_STATE_VALUE &&
621 tree->state != TREE_STATE_INITED &&
622 tree->state != TREE_STATE_SEQ_START &&
623 tree->state != TREE_STATE_TREE_STARTED)
624 return CYAML_ERROR_UNEXPECTED_STATE;
626 /* block_mapping_start means we're entering another block
627 * indentation, so we need to go one level deeper
628 * create a child of cur */
629 obj = create_child(tree->cur);
631 /* push cur on the stack */
632 if (cYAML_ll_push(tree->cur, NULL, &tree->ll))
633 return CYAML_ERROR_OUT_OF_MEM;
635 /* adding the new child to cur */
638 tree->state = TREE_STATE_BLK_STARTED;
640 tree->from_blk_map_start = 1;
642 return CYAML_ERROR_NONE;
645 static enum cYAML_handler_error yaml_block_end(yaml_token_t *token,
646 struct cYAML_tree_node *tree)
648 if (tree->state != TREE_STATE_BLK_STARTED &&
649 tree->state != TREE_STATE_VALUE)
650 return CYAML_ERROR_UNEXPECTED_STATE;
652 tree->cur = cYAML_ll_pop(&tree->ll, NULL);
654 /* if you have popped all the way to the top level, then move to
655 * the complete state. */
656 if (cYAML_ll_count(&tree->ll) == 0)
657 tree->state = TREE_STATE_COMPLETE;
658 else if (tree->state == TREE_STATE_VALUE)
659 tree->state = TREE_STATE_BLK_STARTED;
661 return CYAML_ERROR_NONE;
664 static enum cYAML_handler_error yaml_not_supported(yaml_token_t *token,
665 struct cYAML_tree_node *tree)
667 return CYAML_ERROR_NOT_SUPPORTED;
670 static bool clean_usr_data(struct cYAML *node, void *usr_data, void **out)
672 cYAML_user_data_free_cb free_cb = usr_data;
674 if (free_cb && node && node->cy_user_data) {
675 free_cb(node->cy_user_data);
676 node->cy_user_data = NULL;
682 static bool free_node(struct cYAML *node, void *user_data, void **out)
687 if (node->cy_type == CYAML_TYPE_STRING)
688 free(node->cy_valuestring);
690 free(node->cy_string);
696 static bool find_obj_iter(struct cYAML *node, void *usr_data, void **out)
698 char *name = usr_data;
700 if (node != NULL && node->cy_string != NULL &&
701 strcmp(node->cy_string, name) == 0) {
709 struct cYAML *cYAML_get_object_item(struct cYAML *parent, const char *name)
711 struct cYAML *node = parent, *found = NULL;
716 if (node->cy_string) {
717 if (strcmp(node->cy_string, name) == 0)
722 found = cYAML_get_object_item(node->cy_child, name);
724 if (!found && node->cy_next)
725 found = cYAML_get_object_item(node->cy_next, name);
730 struct cYAML *cYAML_get_next_seq_item(struct cYAML *seq, struct cYAML **itm)
732 if (*itm != NULL && (*itm)->cy_next != NULL) {
733 *itm = (*itm)->cy_next;
737 if (*itm == NULL && seq->cy_type == CYAML_TYPE_ARRAY) {
738 *itm = seq->cy_child;
745 bool cYAML_is_sequence(struct cYAML *node)
747 return (node != NULL ? node->cy_type == CYAML_TYPE_ARRAY : 0);
750 void cYAML_tree_recursive_walk(struct cYAML *node, cYAML_walk_cb cb,
759 if (!cb(node, usr_data, out))
764 cYAML_tree_recursive_walk(node->cy_child, cb,
765 cb_first, usr_data, out);
768 cYAML_tree_recursive_walk(node->cy_next, cb,
769 cb_first, usr_data, out);
772 if (!cb(node, usr_data, out))
777 struct cYAML *cYAML_find_object(struct cYAML *root, const char *name)
779 struct cYAML *found = NULL;
781 cYAML_tree_recursive_walk(root, find_obj_iter, true,
782 (void *)name, (void **)&found);
787 void cYAML_clean_usr_data(struct cYAML *node, cYAML_user_data_free_cb free_cb)
789 cYAML_tree_recursive_walk(node, clean_usr_data, false, free_cb, NULL);
792 void cYAML_free_tree(struct cYAML *node)
794 cYAML_tree_recursive_walk(node, free_node, false, NULL, NULL);
797 static inline void print_simple(FILE *f, struct cYAML *node,
798 struct cYAML_print_info *cpi)
800 int level = cpi->level;
801 int ind = cpi->extra_ind;
803 if (cpi->array_first_elem)
804 fprintf(f, "%*s- ", INDENT * level, "");
806 fprintf(f, "%*s""%s: %" PRId64 "\n", (cpi->array_first_elem) ? 0 :
807 INDENT * level + ind, "", node->cy_string,
811 static void print_string(FILE *f, struct cYAML *node,
812 struct cYAML_print_info *cpi)
815 int level = cpi->level;
816 int ind = cpi->extra_ind;
818 if (cpi->array_first_elem)
819 fprintf(f, "%*s- ", INDENT * level, "");
821 new_line = strchr(node->cy_valuestring, '\n');
822 if (new_line == NULL)
823 fprintf(f, "%*s""%s: %s\n", (cpi->array_first_elem) ?
824 0 : INDENT * level + ind, "",
825 node->cy_string, node->cy_valuestring);
828 fprintf(f, "%*s""%s: ", (cpi->array_first_elem) ?
829 0 : INDENT * level + ind, "",
831 char *l = node->cy_valuestring;
834 fprintf(f, "%*s""%s\n", indent, "", l);
835 indent = INDENT * level + ind +
836 strlen(node->cy_string) + 2;
839 new_line = strchr(l, '\n');
841 fprintf(f, "%*s""%s\n", indent, "", l);
845 static void print_number(FILE *f, struct cYAML *node,
846 struct cYAML_print_info *cpi)
848 double d = node->cy_valuedouble;
849 int level = cpi->level;
850 int ind = cpi->extra_ind;
852 if (cpi->array_first_elem)
853 fprintf(f, "%*s- ", INDENT * level, "");
855 if ((fabs(((double)node->cy_valueint) - d) <= DBL_EPSILON) &&
856 (d <= INT_MAX) && (d >= INT_MIN))
857 fprintf(f, "%*s""%s: %" PRId64 "\n", (cpi->array_first_elem) ? 0 :
858 INDENT * level + ind, "",
859 node->cy_string, node->cy_valueint);
861 if ((fabs(floor(d) - d) <= DBL_EPSILON) &&
863 fprintf(f, "%*s""%s: %.0f\n",
864 (cpi->array_first_elem) ? 0 :
865 INDENT * level + ind, "",
867 else if ((fabs(d) < 1.0e-6) || (fabs(d) > 1.0e9))
868 fprintf(f, "%*s""%s: %e\n",
869 (cpi->array_first_elem) ? 0 :
870 INDENT * level + ind, "",
873 fprintf(f, "%*s""%s: %f\n",
874 (cpi->array_first_elem) ? 0 :
875 INDENT * level + ind, "",
880 static void print_object(FILE *f, struct cYAML *node,
881 struct list_head *stack,
882 struct cYAML_print_info *cpi)
884 struct cYAML_print_info print_info;
885 struct cYAML *child = node->cy_child;
887 if (node->cy_string != NULL)
888 fprintf(f, "%*s""%s%s:\n", (cpi->array_first_elem) ?
889 INDENT * cpi->level :
890 INDENT * cpi->level + cpi->extra_ind,
891 "", (cpi->array_first_elem) ? "- " : "",
894 print_info.level = (node->cy_string != NULL) ? cpi->level + 1 :
896 print_info.array_first_elem = (node->cy_string == NULL) ?
897 cpi->array_first_elem : 0;
898 print_info.extra_ind = (cpi->array_first_elem) ? EXTRA_IND :
902 if (cYAML_ll_push(child, &print_info, stack) != 0)
904 print_value(f, stack);
905 print_info.array_first_elem = 0;
906 child = child->cy_next;
910 static void print_array(FILE *f, struct cYAML *node,
911 struct list_head *stack,
912 struct cYAML_print_info *cpi)
914 struct cYAML_print_info print_info;
915 struct cYAML *child = node->cy_child;
917 if (node->cy_string != NULL) {
918 fprintf(f, "%*s""%s:\n", INDENT * cpi->level + cpi->extra_ind,
919 "", node->cy_string);
922 print_info.level = (node->cy_string != NULL) ? cpi->level + 1 :
924 print_info.array_first_elem = 1;
925 print_info.extra_ind = EXTRA_IND;
928 if (cYAML_ll_push(child, &print_info, stack) != 0)
930 print_value(f, stack);
931 child = child->cy_next;
935 static void print_value(FILE *f, struct list_head *stack)
937 struct cYAML_print_info *cpi = NULL;
938 struct cYAML *node = cYAML_ll_pop(stack, &cpi);
943 switch (node->cy_type) {
944 case CYAML_TYPE_FALSE:
945 case CYAML_TYPE_TRUE:
946 case CYAML_TYPE_NULL:
947 print_simple(f, node, cpi);
949 case CYAML_TYPE_STRING:
950 print_string(f, node, cpi);
952 case CYAML_TYPE_NUMBER:
953 print_number(f, node, cpi);
955 case CYAML_TYPE_ARRAY:
956 print_array(f, node, stack, cpi);
958 case CYAML_TYPE_OBJECT:
959 print_object(f, node, stack, cpi);
969 void cYAML_print_tree(struct cYAML *node)
971 struct cYAML_print_info print_info;
972 struct list_head list;
974 INIT_LIST_HEAD(&list);
979 memset(&print_info, 0, sizeof(struct cYAML_print_info));
981 if (cYAML_ll_push(node, &print_info, &list) == 0)
982 print_value(stdout, &list);
985 void cYAML_print_tree2file(FILE *f, struct cYAML *node)
987 struct cYAML_print_info print_info;
988 struct list_head list;
990 INIT_LIST_HEAD(&list);
995 memset(&print_info, 0, sizeof(struct cYAML_print_info));
997 if (cYAML_ll_push(node, &print_info, &list) == 0)
998 print_value(f, &list);
1001 static struct cYAML *insert_item(struct cYAML *parent, char *key,
1002 enum cYAML_object_type type)
1004 struct cYAML *node = calloc(1, sizeof(*node));
1010 node->cy_string = strdup(key);
1012 node->cy_type = type;
1014 cYAML_insert_child(parent, node);
1019 struct cYAML *cYAML_create_seq(struct cYAML *parent, char *key)
1021 return insert_item(parent, key, CYAML_TYPE_ARRAY);
1024 struct cYAML *cYAML_create_seq_item(struct cYAML *seq)
1026 return insert_item(seq, NULL, CYAML_TYPE_OBJECT);
1029 struct cYAML *cYAML_create_object(struct cYAML *parent, char *key)
1031 return insert_item(parent, key, CYAML_TYPE_OBJECT);
1034 struct cYAML *cYAML_create_string(struct cYAML *parent, char *key, char *value)
1036 struct cYAML *node = calloc(1, sizeof(*node));
1040 node->cy_string = strdup(key);
1041 node->cy_valuestring = strdup(value);
1042 node->cy_type = CYAML_TYPE_STRING;
1044 cYAML_insert_child(parent, node);
1049 struct cYAML *cYAML_create_number(struct cYAML *parent, char *key, double value)
1051 struct cYAML *node = calloc(1, sizeof(*node));
1055 node->cy_string = strdup(key);
1056 node->cy_valuedouble = value;
1057 node->cy_valueint = (int)value;
1058 node->cy_type = CYAML_TYPE_NUMBER;
1060 cYAML_insert_child(parent, node);
1065 void cYAML_insert_child(struct cYAML *parent, struct cYAML *node)
1069 if (parent && node) {
1070 if (parent->cy_child == NULL) {
1071 parent->cy_child = node;
1075 cur = parent->cy_child;
1077 while (cur->cy_next)
1080 cur->cy_next = node;
1081 node->cy_prev = cur;
1085 void cYAML_insert_sibling(struct cYAML *root, struct cYAML *sibling)
1087 struct cYAML *last = NULL;
1088 if (root == NULL || sibling == NULL)
1092 while (last->cy_next != NULL)
1093 last = last->cy_next;
1095 last->cy_next = sibling;
1098 void cYAML_build_error(int rc, int seq_no, char *cmd,
1099 char *entity, char *err_str,
1100 struct cYAML **root)
1102 struct cYAML *r = NULL, *err, *s, *itm, *cmd_obj;
1106 /* add to the tail of the root that's passed in */
1107 if ((*root) == NULL) {
1108 *root = cYAML_create_object(NULL, NULL);
1109 if ((*root) == NULL)
1115 /* look for the command */
1116 cmd_obj = cYAML_get_object_item(r, (const char *)cmd);
1117 if (cmd_obj != NULL && cmd_obj->cy_type == CYAML_TYPE_ARRAY)
1118 itm = cYAML_create_seq_item(cmd_obj);
1119 else if (cmd_obj == NULL) {
1120 s = cYAML_create_seq(r, cmd);
1121 itm = cYAML_create_seq_item(s);
1122 } else if (cmd_obj != NULL && cmd_obj->cy_type != CYAML_TYPE_ARRAY)
1125 err = cYAML_create_object(itm, entity);
1130 cYAML_create_number(err, "seq_no", seq_no) == NULL)
1133 if (cYAML_create_number(err, "errno", rc) == NULL)
1136 if (cYAML_create_string(err, "descr", err_str) == NULL)
1142 /* Only reason we get here is if we run out of memory */
1145 fprintf(stderr, "error:\n\tfatal: out of memory\n");
1148 struct cYAML *cYAML_build_tree(char *yaml_file,
1149 const char *yaml_blk,
1150 size_t yaml_blk_size,
1151 struct cYAML **err_rc,
1154 yaml_parser_t parser;
1156 struct cYAML_tree_node tree;
1157 enum cYAML_handler_error rc;
1158 yaml_token_type_t token_type;
1163 memset(&tree, 0, sizeof(struct cYAML_tree_node));
1165 INIT_LIST_HEAD(&tree.ll);
1167 /* Create the Parser object. */
1168 yaml_parser_initialize(&parser);
1170 /* file always takes precedence */
1171 if (yaml_file != NULL) {
1172 /* Set a file input. */
1173 input = fopen(yaml_file, "rb");
1174 if (input == NULL) {
1175 snprintf(err_str, sizeof(err_str),
1176 "Failed to open file: %s", yaml_file);
1177 cYAML_build_error(-1, -1, "yaml", "builder",
1183 yaml_parser_set_input_file(&parser, input);
1184 } else if (yaml_blk != NULL) {
1185 yaml_parser_set_input_string(&parser,
1186 (const unsigned char *) yaml_blk,
1189 /* assume that we're getting our input froms stdin */
1190 yaml_parser_set_input_file(&parser, stdin);
1192 /* Read the event sequence. */
1195 * Go through the parser and build a cYAML representation
1196 * of the passed in YAML text
1198 yaml_parser_scan(&parser, &token);
1201 fprintf(stderr, "tree.state(%p:%d) = %s, token.type ="
1203 &tree, tree.state, state_string[tree.state],
1204 token_type_string[token.type],
1205 (token.type == YAML_SCALAR_TOKEN) ?
1206 (char*)token.data.scalar.value : "");
1207 rc = dispatch_tbl[token.type](&token, &tree);
1208 if (rc != CYAML_ERROR_NONE) {
1209 snprintf(err_str, sizeof(err_str),
1210 "Failed to handle token:%d %s"
1211 "[state=%d, rc=%d]",
1212 token.type, token_type_string[token.type],
1214 cYAML_build_error(-1, -1, "yaml", "builder",
1218 /* Are we finished? */
1219 done = (rc != CYAML_ERROR_NONE ||
1220 token.type == YAML_STREAM_END_TOKEN);
1222 token_type = token.type;
1224 yaml_token_delete(&token);
1227 /* Destroy the Parser object. */
1228 yaml_parser_delete(&parser);
1233 if (token_type == YAML_STREAM_END_TOKEN &&
1234 rc == CYAML_ERROR_NONE)
1237 cYAML_free_tree(tree.root);