Whamcloud - gitweb
5d153c5d8e8dac7a582fa6903d364571c42d07d0
[fs/lustre-release.git] / lnet / utils / lnetconfig / cyaml.c
1 /*
2  * LGPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
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.
10  *
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.
15  *
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/>.
18  *
19  * LGPL HEADER END
20  *
21  * Copyright (c) 2014, 2017, Intel Corporation.
22  *
23  * Author:
24  *   Amir Shehata <amir.shehata@intel.com>
25  */
26
27 /*
28  *  The cYAML tree is constructed as an n-tree.
29  *  root -> cmd 1
30  *          ||
31  *          \/
32  *          cmd 2 -> attr1 -> attr2
33  *                              ||
34  *                              \/
35  *                            attr2.1 -> attr2.1.1 -> attr2.1.2
36  */
37
38 #include <yaml.h>
39 #include <stdio.h>
40 #include <string.h>
41 #include <stdio.h>
42 #include <math.h>
43 #include <stdlib.h>
44 #include <errno.h>
45 #include <float.h>
46 #include <limits.h>
47 #include <ctype.h>
48 #include "libcfs/util/list.h"
49 #include <cyaml.h>
50
51 #define INDENT          4
52 #define EXTRA_IND       2
53 #define LEAD_ROOM       128
54 #define PRINT_BUF_LEN   2048
55
56 /*
57  * cYAML_print_info
58  *   This structure contains print information
59  *   required when printing the node
60  */
61 struct cYAML_print_info {
62         int level;
63         int array_first_elem;
64         int extra_ind;
65 };
66
67 /*
68  *  cYAML_ll
69  *  Linked list of different trees representing YAML
70  *  documents.
71  */
72 struct cYAML_ll {
73         struct list_head list;
74         struct cYAML *obj;
75         struct cYAML_print_info *print_info;
76 };
77
78 static void print_value(char **out, struct list_head *stack);
79
80 enum cYAML_handler_error {
81         CYAML_ERROR_NONE = 0,
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,
87 };
88
89 enum cYAML_tree_state {
90         TREE_STATE_COMPLETE = 0,
91         TREE_STATE_INITED,
92         TREE_STATE_TREE_STARTED,
93         TREE_STATE_BLK_STARTED,
94         TREE_STATE_KEY,
95         TREE_STATE_KEY_FILLED,
96         TREE_STATE_VALUE,
97         TREE_STATE_SEQ_START,
98 };
99
100 struct cYAML_tree_node {
101         struct cYAML *root;
102         /* cur is the current node we're operating on */
103         struct cYAML *cur;
104         enum cYAML_tree_state state;
105         int from_blk_map_start;
106         /* represents the tree depth */
107         struct list_head ll;
108 };
109
110 typedef enum cYAML_handler_error (*yaml_token_handler)(yaml_token_t *token,
111                                                 struct cYAML_tree_node *);
112
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);
139
140 /* dispatch table */
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,
164 };
165
166 /* dispatch table */
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",
190 };
191
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",
201 };
202
203 static void cYAML_ll_free(struct list_head *ll)
204 {
205         struct cYAML_ll *node, *tmp;
206
207         list_for_each_entry_safe(node, tmp, ll, list) {
208                 free(node->print_info);
209                 free(node);
210         }
211 }
212
213 static int cYAML_ll_push(struct cYAML *obj,
214                          const struct cYAML_print_info *print_info,
215                          struct list_head *list)
216 {
217         struct cYAML_ll *node = calloc(1, sizeof(*node));
218         if (node == NULL)
219                 return -1;
220
221         INIT_LIST_HEAD(&node->list);
222
223         if (print_info) {
224                 node->print_info = calloc(1, sizeof(*print_info));
225                 if (node->print_info == NULL) {
226                         free(node);
227                         return -1;
228                 }
229                 *node->print_info = *print_info;
230         }
231         node->obj = obj;
232
233         list_add(&node->list, list);
234
235         return 0;
236 }
237
238 static struct cYAML *cYAML_ll_pop(struct list_head *list,
239                                   struct cYAML_print_info **print_info)
240 {
241         struct cYAML_ll *pop;
242         struct cYAML *obj = NULL;
243
244         if (!list_empty(list)) {
245                 pop = list_first_entry(list, struct cYAML_ll, list);
246
247                 obj = pop->obj;
248                 if (print_info != NULL)
249                         *print_info = pop->print_info;
250                 list_del(&pop->list);
251
252                 if (print_info == NULL)
253                         free(pop->print_info);
254
255                 free(pop);
256         }
257         return obj;
258 }
259
260 static int cYAML_ll_count(struct list_head *ll)
261 {
262         int i = 0;
263         struct list_head *node;
264
265         list_for_each(node, ll)
266                 i++;
267
268         return i;
269 }
270
271 static int cYAML_tree_init(struct cYAML_tree_node *tree)
272 {
273         struct cYAML *obj = NULL, *cur = NULL;
274
275         if (tree == NULL)
276                 return -1;
277
278         obj = calloc(1, sizeof(*obj));
279         if (obj == NULL)
280                 return -1;
281
282         if (tree->root) {
283                 /* append the node */
284                 cur = tree->root;
285                 while (cur->cy_next != NULL)
286                         cur = cur->cy_next;
287                 cur->cy_next = obj;
288         } else {
289                 tree->root = obj;
290         }
291
292         obj->cy_type = CYAML_TYPE_OBJECT;
293
294         tree->cur = obj;
295         tree->state = TREE_STATE_COMPLETE;
296
297         /* free it and start anew */
298         if (!list_empty(&tree->ll))
299                 cYAML_ll_free(&tree->ll);
300
301         return 0;
302 }
303
304 static struct cYAML *create_child(struct cYAML *parent)
305 {
306         struct cYAML *obj;
307
308         if (parent == NULL)
309                 return NULL;
310
311         obj = calloc(1, sizeof(*obj));
312         if (obj == NULL)
313                 return NULL;
314
315         /* set the type to OBJECT and let the value change that */
316         obj->cy_type = CYAML_TYPE_OBJECT;
317
318         parent->cy_child = obj;
319
320         return obj;
321 }
322
323 static struct cYAML *create_sibling(struct cYAML *sibling)
324 {
325         struct cYAML *obj;
326
327         if (sibling == NULL)
328                 return NULL;
329
330         obj = calloc(1, sizeof(*obj));
331         if (obj == NULL)
332                 return NULL;
333
334         /* set the type to OBJECT and let the value change that */
335         obj->cy_type = CYAML_TYPE_OBJECT;
336
337         sibling->cy_next = obj;
338         obj->cy_prev = sibling;
339
340         return obj;
341 }
342
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)
346 {
347         double n = 0, sign = 1, scale = 0;
348         int subscale = 0, signsubscale = 1;
349         const char *num = input;
350
351         if (!strncmp(input, "0x", 2)) {
352                 int64_t hex; /* hex input is always an integer */
353                 char *invalid = NULL;
354
355                 errno = 0;
356                 hex = strtoll(input, &invalid, 16);
357                 if (errno)
358                         return false;
359                 if (*invalid)
360                         return false;
361
362                 item->cy_valuedouble = (double) hex;
363                 item->cy_valueint = hex;
364                 item->cy_type = CYAML_TYPE_NUMBER;
365                 return true;
366         }
367
368         if (*num == '-') {
369                 sign = -1;
370                 num++;
371         }
372
373         if (*num == '0')
374                 num++;
375
376         if (*num >= '1' && *num <= '9') {
377                 do {
378                         n = (n * 10.0) + (*num++ - '0');
379                 } while (*num >= '0' && *num <= '9');
380         }
381
382         if (*num == '.' && num[1] >= '0' && num[1] <= '9') {
383                 num++;
384                 do {
385                         n = (n * 10.0) + (*num++ - '0');
386                         scale--;
387                 } while (*num >= '0' && *num <= '9');
388         }
389
390         if (*num == 'e' || *num == 'E') {
391                 num++;
392                 if (*num == '+') {
393                         num++;
394                 } else if (*num == '-') {
395                         signsubscale = -1;
396                         num++;
397                 }
398                 while (*num >= '0' && *num <= '9')
399                         subscale = (subscale * 10) + (*num++ - '0');
400         }
401
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)))
405                 return false;
406
407         /* number = +/- number.fraction * 10^+/- exponent */
408         n = sign * n * pow(10.0, (scale + subscale * signsubscale));
409
410         item->cy_valuedouble = n;
411         item->cy_valueint = (int64_t)n;
412         item->cy_type = CYAML_TYPE_NUMBER;
413
414         return true;
415 }
416
417 static int assign_type_value(struct cYAML *obj, const char *value)
418 {
419         if (value == NULL)
420                 return -1;
421
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;
434                 }
435         } else {
436                 obj->cy_valuestring = strdup(value);
437                 obj->cy_type = CYAML_TYPE_STRING;
438         }
439
440         return 0;
441 }
442
443 /*
444  * yaml_handle_token
445  *  Builds the YAML tree rpresentation as the tokens are passed in
446  *
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
462  *    fail.
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
470  *    it appropriately
471  *    state = TREE_STARTED
472  * else if token == YAML_BLOCK_MAPPING_START_TOKEN && tree_state != VALUE
473  *   fail
474  * else push the current node on the ll && state = TREE_STARTED
475  * if token == YAML_BLOCK_END_TOKEN && state != TREE_STARTED
476  *   fail.
477  * else pop the current token off the ll and make it the cur
478  * if token == YAML_VALUE_TOKEN && state != KEY_FILLED
479  *   fail.
480  * else state = VALUE
481  *
482  */
483
484 static enum cYAML_handler_error yaml_no_token(yaml_token_t *token,
485                                               struct cYAML_tree_node *tree)
486 {
487         return CYAML_ERROR_NONE;
488 }
489
490 static enum cYAML_handler_error yaml_stream_start(yaml_token_t *token,
491                                                   struct cYAML_tree_node *tree)
492 {
493         enum cYAML_handler_error rc;
494
495         /* with each new stream initialize a new tree */
496         rc = cYAML_tree_init(tree);
497
498         if (rc != CYAML_ERROR_NONE)
499                 return rc;
500
501         tree->state = TREE_STATE_INITED;
502
503         return CYAML_ERROR_NONE;
504 }
505
506 static enum cYAML_handler_error yaml_stream_end(yaml_token_t *token,
507                                                 struct cYAML_tree_node *tree)
508 {
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;
513
514         tree->state = TREE_STATE_INITED;
515
516         return CYAML_ERROR_NONE;
517 }
518
519 static enum cYAML_handler_error
520 yaml_document_start(yaml_token_t *token, struct cYAML_tree_node *tree)
521 {
522         if (tree->state != TREE_STATE_INITED)
523                 return CYAML_ERROR_UNEXPECTED_STATE;
524
525         /* go to started state since we're expecting more tokens to come */
526         tree->state = TREE_STATE_TREE_STARTED;
527
528         return CYAML_ERROR_NONE;
529 }
530
531 static enum cYAML_handler_error yaml_document_end(yaml_token_t *token,
532                                                   struct cYAML_tree_node *tree)
533 {
534         if (tree->state != TREE_STATE_COMPLETE)
535                 return CYAML_ERROR_UNEXPECTED_STATE;
536
537         tree->state = TREE_STATE_TREE_STARTED;
538
539         return CYAML_ERROR_NONE;
540 }
541
542 static enum cYAML_handler_error yaml_key(yaml_token_t *token,
543                                          struct cYAML_tree_node *tree)
544 {
545         if (tree->state != TREE_STATE_BLK_STARTED &&
546             tree->state != TREE_STATE_VALUE)
547                 return CYAML_ERROR_UNEXPECTED_STATE;
548
549         if (tree->from_blk_map_start == 0 ||
550             tree->state == TREE_STATE_VALUE)
551                 tree->cur = create_sibling(tree->cur);
552
553         tree->from_blk_map_start = 0;
554
555         tree->state = TREE_STATE_KEY;
556
557         return CYAML_ERROR_NONE;
558 }
559
560 static enum cYAML_handler_error yaml_scalar(yaml_token_t *token,
561                                             struct cYAML_tree_node *tree)
562 {
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);
567
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;
576         } else {
577                 return CYAML_ERROR_UNEXPECTED_STATE;
578         }
579
580         return CYAML_ERROR_NONE;
581 }
582
583 static enum cYAML_handler_error yaml_value(yaml_token_t *token,
584                                            struct cYAML_tree_node *tree)
585 {
586         if (tree->state != TREE_STATE_KEY_FILLED)
587                 return CYAML_ERROR_UNEXPECTED_STATE;
588
589         tree->state = TREE_STATE_VALUE;
590
591         return CYAML_ERROR_NONE;
592 }
593
594 static enum cYAML_handler_error yaml_blk_seq_start(yaml_token_t *token,
595                                                    struct cYAML_tree_node *tree)
596 {
597         if (tree->state != TREE_STATE_VALUE)
598                 return CYAML_ERROR_UNEXPECTED_STATE;
599
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;
605
606         return CYAML_ERROR_NONE;
607 }
608
609 static enum cYAML_handler_error yaml_entry_token(yaml_token_t *token,
610                                                  struct cYAML_tree_node *tree)
611 {
612         struct cYAML *obj;
613
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;
618
619         if (tree->state == TREE_STATE_SEQ_START) {
620                 obj = create_child(tree->cur);
621
622                 if (cYAML_ll_push(tree->cur, NULL, &tree->ll))
623                         return CYAML_ERROR_OUT_OF_MEM;
624
625                 tree->cur = obj;
626         } else {
627                 tree->cur = create_sibling(tree->cur);
628                 tree->state = TREE_STATE_SEQ_START;
629         }
630
631         return CYAML_ERROR_NONE;
632 }
633
634 static enum cYAML_handler_error
635 yaml_blk_mapping_start(yaml_token_t *token,
636                        struct cYAML_tree_node *tree)
637 {
638         struct cYAML *obj;
639
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;
645
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);
650
651         /* push cur on the stack */
652         if (cYAML_ll_push(tree->cur, NULL, &tree->ll))
653                 return CYAML_ERROR_OUT_OF_MEM;
654
655         /* adding the new child to cur */
656         tree->cur = obj;
657
658         tree->state = TREE_STATE_BLK_STARTED;
659
660         tree->from_blk_map_start = 1;
661
662         return CYAML_ERROR_NONE;
663 }
664
665 static enum cYAML_handler_error yaml_block_end(yaml_token_t *token,
666                                                struct cYAML_tree_node *tree)
667 {
668         if (tree->state != TREE_STATE_BLK_STARTED &&
669             tree->state != TREE_STATE_VALUE)
670                 return CYAML_ERROR_UNEXPECTED_STATE;
671
672         tree->cur = cYAML_ll_pop(&tree->ll, NULL);
673
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;
680
681         return CYAML_ERROR_NONE;
682 }
683
684 static enum cYAML_handler_error yaml_not_supported(yaml_token_t *token,
685                                                    struct cYAML_tree_node *tree)
686 {
687         return CYAML_ERROR_NOT_SUPPORTED;
688 }
689
690 static bool clean_usr_data(struct cYAML *node, void *usr_data, void **out)
691 {
692         cYAML_user_data_free_cb free_cb = usr_data;
693
694         if (free_cb && node && node->cy_user_data) {
695                 free_cb(node->cy_user_data);
696                 node->cy_user_data = NULL;
697         }
698
699         return true;
700 }
701
702 static bool free_node(struct cYAML *node, void *user_data, void **out)
703 {
704         if (!node)
705                 return true;
706
707         if (node->cy_type == CYAML_TYPE_STRING)
708                 free(node->cy_valuestring);
709         if (node->cy_string)
710                 free(node->cy_string);
711
712         free(node);
713         return true;
714 }
715
716 static bool find_obj_iter(struct cYAML *node, void *usr_data, void **out)
717 {
718         char *name = usr_data;
719
720         if (node != NULL && node->cy_string != NULL &&
721             strcmp(node->cy_string, name) == 0) {
722                 *out = node;
723                 return false;
724         }
725
726         return true;
727 }
728
729 struct cYAML *cYAML_get_object_item(struct cYAML *parent, const char *name)
730 {
731         struct cYAML *node = parent, *found = NULL;
732
733         if (!node || !name)
734                 return NULL;
735
736         if (node->cy_string) {
737                 if (strcmp(node->cy_string, name) == 0)
738                         return node;
739         }
740
741         if (node->cy_child)
742                 found = cYAML_get_object_item(node->cy_child, name);
743
744         if (!found && node->cy_next)
745                 found = cYAML_get_object_item(node->cy_next, name);
746
747         return found;
748 }
749
750 struct cYAML *cYAML_get_next_seq_item(struct cYAML *seq, struct cYAML **itm)
751 {
752         if (*itm != NULL && (*itm)->cy_next != NULL) {
753                 *itm = (*itm)->cy_next;
754                 return *itm;
755         }
756
757         if (*itm == NULL && seq->cy_type == CYAML_TYPE_ARRAY) {
758                 *itm = seq->cy_child;
759                 return *itm;
760         }
761
762         return NULL;
763 }
764
765 bool cYAML_is_sequence(struct cYAML *node)
766 {
767         return (node != NULL ? node->cy_type == CYAML_TYPE_ARRAY : 0);
768 }
769
770 static void cYAML_tree_recursive_walk(struct cYAML *node, cYAML_walk_cb cb,
771                                       bool cb_first,
772                                       void *usr_data,
773                                       void **out)
774 {
775         if (node == NULL)
776                 return;
777
778         if (cb_first) {
779                 if (!cb(node, usr_data, out))
780                         return;
781         }
782
783         if (node->cy_child)
784                 cYAML_tree_recursive_walk(node->cy_child, cb,
785                                           cb_first, usr_data, out);
786
787         if (node->cy_next)
788                 cYAML_tree_recursive_walk(node->cy_next, cb,
789                                           cb_first, usr_data, out);
790
791         if (!cb_first) {
792                 if (!cb(node, usr_data, out))
793                         return;
794         }
795 }
796
797 struct cYAML *cYAML_find_object(struct cYAML *root, const char *name)
798 {
799         struct cYAML *found = NULL;
800
801         cYAML_tree_recursive_walk(root, find_obj_iter, true,
802                                   (void *)name, (void **)&found);
803
804         return found;
805 }
806
807 void cYAML_clean_usr_data(struct cYAML *node, cYAML_user_data_free_cb free_cb)
808 {
809         cYAML_tree_recursive_walk(node, clean_usr_data, false, free_cb, NULL);
810 }
811
812 void cYAML_free_tree(struct cYAML *node)
813 {
814         cYAML_tree_recursive_walk(node, free_node, false, NULL, NULL);
815 }
816
817 static char *ensure(char *in, int len)
818 {
819         int curlen;
820         char *new = in;
821
822         if (!in)
823                 return (char*)calloc(len, 1);
824
825         curlen = strlen(in) + 1;
826
827         if (curlen <= curlen + len) {
828                 new = calloc(curlen + len, 1);
829                 if (!new) {
830                         free(in);
831                         return NULL;
832                 }
833                 strcpy(new, in);
834                 free(in);
835         }
836
837         return new;
838 }
839
840 static inline void print_simple(char **out, struct cYAML *node,
841                                 struct cYAML_print_info *cpi)
842 {
843         int level = cpi->level;
844         int ind = cpi->extra_ind;
845         char *tmp = NULL;
846         int len = (INDENT * level + ind) * 2 +
847           ((node->cy_string) ? strlen(node->cy_string) : 0) + LEAD_ROOM;
848
849         *out = ensure(*out, len);
850         if (!*out)
851                 return;
852
853         tmp = ensure(tmp, len);
854         if (!tmp)
855                 return;
856
857         if (cpi->array_first_elem) {
858                 sprintf(tmp, "%*s- ", INDENT * level, "");
859                 strcat(*out, tmp);
860         }
861
862         sprintf(tmp, "%*s""%s: %" PRId64 "\n", (cpi->array_first_elem) ? 0 :
863                 INDENT * level + ind, "", node->cy_string,
864                 node->cy_valueint);
865         strcat(*out, tmp);
866         free(tmp);
867 }
868
869 static void print_string(char **out, struct cYAML *node,
870                          struct cYAML_print_info *cpi)
871 {
872         char *new_line;
873         int level = cpi->level;
874         int ind = cpi->extra_ind;
875         char *tmp = NULL;
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;
879
880         *out = ensure(*out, len);
881         if (!*out)
882                 return;
883
884         tmp = ensure(tmp, len);
885         if (!tmp)
886                 return;
887
888         if (cpi->array_first_elem) {
889                 sprintf(tmp, "%*s- ", INDENT * level, "");
890                 strcat(*out, tmp);
891         }
892
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);
898                 strcat(*out, tmp);
899         } else {
900                 int indent = 0;
901                 sprintf(tmp, "%*s""%s: ", (cpi->array_first_elem) ?
902                         0 : INDENT * level + ind, "",
903                         node->cy_string);
904                 strcat(*out, tmp);
905                 char *l = node->cy_valuestring;
906                 while (new_line) {
907                         *new_line = '\0';
908                         sprintf(tmp, "%*s""%s\n", indent, "", l);
909                         strcat(*out, tmp);
910                         indent = INDENT * level + ind +
911                                   strlen(node->cy_string) + 2;
912                         *new_line = '\n';
913                         l = new_line+1;
914                         new_line = strchr(l, '\n');
915                 }
916                 sprintf(tmp, "%*s""%s\n", indent, "", l);
917                 strcat(*out, tmp);
918         }
919
920         free(tmp);
921 }
922
923 static void print_number(char **out, struct cYAML *node,
924                          struct cYAML_print_info *cpi)
925 {
926         double d = node->cy_valuedouble;
927         int level = cpi->level;
928         int ind = cpi->extra_ind;
929         char *tmp = NULL;
930         int len = INDENT * level + ind + LEAD_ROOM;
931
932         *out = ensure(*out, len);
933         if (!*out)
934                 return;
935
936         tmp = ensure(tmp, len);
937         if (!tmp)
938                 return;
939
940         if (cpi->array_first_elem) {
941                 sprintf(tmp, "%*s- ", INDENT * level, "");
942                 strcat(*out, tmp);
943         }
944
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);
950                 strcat(*out, tmp);
951         } else {
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, "",
957                                 node->cy_string, d);
958                         strcat(*out, tmp);
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, "",
963                                 node->cy_string, d);
964                         strcat(*out, tmp);
965                 } else {
966                         sprintf(tmp, "%*s""%s: %f\n",
967                                 (cpi->array_first_elem) ? 0 :
968                                 INDENT * level + ind, "",
969                                 node->cy_string, d);
970                         strcat(*out, tmp);
971                 }
972         }
973
974         free(tmp);
975 }
976
977 static void print_object(char **out, struct cYAML *node,
978                          struct list_head *stack,
979                          struct cYAML_print_info *cpi)
980 {
981         struct cYAML_print_info print_info;
982         struct cYAML *child = node->cy_child;
983         char *tmp = NULL;
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) +
987           LEAD_ROOM;
988
989         *out = ensure(*out, len);
990         if (!*out)
991                 return;
992
993         tmp = ensure(tmp, len);
994         if (!tmp)
995                 return;
996
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) ? "- " : "",
1002                         node->cy_string);
1003                 strcat(*out, tmp);
1004         }
1005
1006         print_info.level = (node->cy_string != NULL) ? cpi->level + 1 :
1007           cpi->level;
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 :
1011           cpi->extra_ind;
1012
1013         while (child) {
1014                 if (cYAML_ll_push(child, &print_info, stack) != 0) {
1015                         free(tmp);
1016                         return;
1017                 }
1018                 print_value(out, stack);
1019                 print_info.array_first_elem = 0;
1020                 child = child->cy_next;
1021         }
1022
1023         free(tmp);
1024 }
1025
1026 static void print_array(char **out, struct cYAML *node,
1027                         struct list_head *stack,
1028                         struct cYAML_print_info *cpi)
1029 {
1030         struct cYAML_print_info print_info;
1031         struct cYAML *child = node->cy_child;
1032         char *tmp = NULL;
1033         int len = ((node->cy_string) ? strlen(node->cy_string) : 0) +
1034           INDENT * cpi->level + cpi->extra_ind + LEAD_ROOM;
1035
1036         *out = ensure(*out, len);
1037         if (!*out)
1038                 return;
1039
1040         tmp = ensure(tmp, len);
1041         if (!tmp)
1042                 return;
1043
1044         if (node->cy_string != NULL) {
1045                 sprintf(tmp, "%*s""%s:\n", INDENT * cpi->level + cpi->extra_ind,
1046                         "", node->cy_string);
1047                 strcat(*out, tmp);
1048         }
1049
1050         print_info.level = (node->cy_string != NULL) ? cpi->level + 1 :
1051           cpi->level;
1052         print_info.array_first_elem =  1;
1053         print_info.extra_ind = EXTRA_IND;
1054
1055         while (child) {
1056                 if (cYAML_ll_push(child, &print_info, stack) != 0) {
1057                         free(tmp);
1058                         return;
1059                 }
1060                 print_value(out, stack);
1061                 child = child->cy_next;
1062         }
1063
1064         free(tmp);
1065 }
1066
1067 static void print_value(char **out, struct list_head *stack)
1068 {
1069         struct cYAML_print_info *cpi = NULL;
1070         struct cYAML *node = cYAML_ll_pop(stack, &cpi);
1071
1072         if (node == NULL)
1073                 return;
1074
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);
1080                 break;
1081         case CYAML_TYPE_STRING:
1082                 print_string(out, node, cpi);
1083                 break;
1084         case CYAML_TYPE_NUMBER:
1085                 print_number(out, node, cpi);
1086                 break;
1087         case CYAML_TYPE_ARRAY:
1088                 print_array(out, node, stack, cpi);
1089                 break;
1090         case CYAML_TYPE_OBJECT:
1091                 print_object(out, node, stack, cpi);
1092                 break;
1093         default:
1094         break;
1095         }
1096
1097         if (cpi != NULL)
1098                 free(cpi);
1099 }
1100
1101 void cYAML_dump(struct cYAML *node, char **buf)
1102 {
1103         struct cYAML_print_info print_info;
1104         struct list_head list;
1105
1106         *buf = ensure(NULL, PRINT_BUF_LEN);
1107
1108         if (!*buf)
1109                 return;
1110
1111         INIT_LIST_HEAD(&list);
1112
1113         if (node == NULL) {
1114                 *buf = NULL;
1115                 return;
1116         }
1117
1118         memset(&print_info, 0, sizeof(struct cYAML_print_info));
1119
1120         if (cYAML_ll_push(node, &print_info, &list) == 0)
1121                 print_value(buf, &list);
1122 }
1123
1124 void cYAML_print_tree(struct cYAML *node)
1125 {
1126         struct cYAML_print_info print_info;
1127         struct list_head list;
1128         char *buf = ensure(NULL, PRINT_BUF_LEN);
1129
1130         if (!buf)
1131                 return;
1132
1133         INIT_LIST_HEAD(&list);
1134
1135         if (node == NULL)
1136                 return;
1137
1138         memset(&print_info, 0, sizeof(struct cYAML_print_info));
1139
1140         if (cYAML_ll_push(node, &print_info, &list) == 0)
1141                 print_value(&buf, &list);
1142
1143         /* buf could've been freed if we ran out of memory */
1144         if (buf) {
1145                 printf("%s", buf);
1146                 free(buf);
1147         }
1148 }
1149
1150 void cYAML_print_tree2file(FILE *f, struct cYAML *node)
1151 {
1152         struct cYAML_print_info print_info;
1153         struct list_head list;
1154         char *buf = ensure(NULL, PRINT_BUF_LEN);
1155
1156         if (!buf)
1157                 return;
1158
1159         INIT_LIST_HEAD(&list);
1160
1161         if (node == NULL)
1162                 return;
1163
1164         memset(&print_info, 0, sizeof(struct cYAML_print_info));
1165
1166         if (cYAML_ll_push(node, &print_info, &list) == 0)
1167                 print_value(&buf, &list);
1168
1169         /* buf could've been freed if we ran out of memory */
1170         if (buf) {
1171                 fprintf(f, "%s", buf);
1172                 free(buf);
1173         }
1174 }
1175
1176 static struct cYAML *insert_item(struct cYAML *parent, char *key,
1177                                  enum cYAML_object_type type)
1178 {
1179         struct cYAML *node = calloc(1, sizeof(*node));
1180
1181         if (node == NULL)
1182                 return NULL;
1183
1184         if (key != NULL)
1185                 node->cy_string = strdup(key);
1186
1187         node->cy_type = type;
1188
1189         cYAML_insert_child(parent, node);
1190
1191         return node;
1192 }
1193
1194 struct cYAML *cYAML_create_seq(struct cYAML *parent, char *key)
1195 {
1196         return insert_item(parent, key, CYAML_TYPE_ARRAY);
1197 }
1198
1199 struct cYAML *cYAML_create_seq_item(struct cYAML *seq)
1200 {
1201         return insert_item(seq, NULL, CYAML_TYPE_OBJECT);
1202 }
1203
1204 struct cYAML *cYAML_create_object(struct cYAML *parent, char *key)
1205 {
1206         return insert_item(parent, key, CYAML_TYPE_OBJECT);
1207 }
1208
1209 struct cYAML *cYAML_create_string(struct cYAML *parent, char *key, char *value)
1210 {
1211         struct cYAML *node = calloc(1, sizeof(*node));
1212         if (node == NULL)
1213                 return NULL;
1214
1215         node->cy_string = strdup(key);
1216         node->cy_valuestring = strdup(value);
1217         node->cy_type = CYAML_TYPE_STRING;
1218
1219         cYAML_insert_child(parent, node);
1220
1221         return node;
1222 }
1223
1224 struct cYAML *cYAML_create_number(struct cYAML *parent, char *key, double value)
1225 {
1226         struct cYAML *node = calloc(1, sizeof(*node));
1227         if (node == NULL)
1228                 return NULL;
1229
1230         node->cy_string = strdup(key);
1231         node->cy_valuedouble = value;
1232         node->cy_valueint = (int)value;
1233         node->cy_type = CYAML_TYPE_NUMBER;
1234
1235         cYAML_insert_child(parent, node);
1236
1237         return node;
1238 }
1239
1240 void cYAML_insert_child(struct cYAML *parent, struct cYAML *node)
1241 {
1242         struct cYAML *cur;
1243
1244         if (parent && node) {
1245                 if (parent->cy_child == NULL) {
1246                         parent->cy_child = node;
1247                         return;
1248                 }
1249
1250                 cur = parent->cy_child;
1251
1252                 while (cur->cy_next)
1253                         cur = cur->cy_next;
1254
1255                 cur->cy_next = node;
1256                 node->cy_prev = cur;
1257         }
1258 }
1259
1260 void cYAML_insert_sibling(struct cYAML *root, struct cYAML *sibling)
1261 {
1262         struct cYAML *last = NULL;
1263         if (root == NULL || sibling == NULL)
1264                 return;
1265
1266         last = root;
1267         while (last->cy_next != NULL)
1268                 last = last->cy_next;
1269
1270         last->cy_next = sibling;
1271 }
1272
1273 void cYAML_build_error(int rc, int seq_no, char *cmd,
1274                        char *entity, char *err_str,
1275                        struct cYAML **root)
1276 {
1277         struct cYAML *r = NULL, *err, *s, *itm = NULL, *cmd_obj;
1278         if (root == NULL)
1279                 return;
1280
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)
1285                         goto failed;
1286         }
1287
1288         r = *root;
1289
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) {
1298                 goto failed;
1299         }
1300
1301         err = cYAML_create_object(itm, entity);
1302         if (err == NULL)
1303                 goto failed;
1304
1305         if (seq_no >= 0 &&
1306             cYAML_create_number(err, "seq_no", seq_no) == NULL)
1307                 goto failed;
1308
1309         if (cYAML_create_number(err, "errno", rc) == NULL)
1310                 goto failed;
1311
1312         if (cYAML_create_string(err, "descr", err_str) == NULL)
1313                 goto failed;
1314
1315         return;
1316
1317 failed:
1318         /* Only reason we get here is if we run out of memory */
1319         cYAML_free_tree(r);
1320         r = NULL;
1321         fprintf(stderr, "error:\n\tfatal: out of memory\n");
1322 }
1323
1324 static struct cYAML *
1325 cYAML_parser_to_tree(yaml_parser_t *parser, struct cYAML **err_rc, bool debug)
1326 {
1327         yaml_token_t token;
1328         struct cYAML_tree_node tree;
1329         enum cYAML_handler_error rc;
1330         yaml_token_type_t token_type;
1331         char err_str[256];
1332         int done = 0;
1333
1334         memset(&tree, 0, sizeof(struct cYAML_tree_node));
1335
1336         INIT_LIST_HEAD(&tree.ll);
1337
1338         /* Read the event sequence. */
1339         while (!done) {
1340                 /*
1341                  * Go through the parser and build a cYAML representation
1342                  * of the passed in YAML text
1343                  */
1344                 yaml_parser_scan(parser, &token);
1345
1346                 if (debug)
1347                         fprintf(stderr, "tree.state(%p:%d) = %s, token.type ="
1348                                         " %s: %s\n",
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],
1358                                  tree.state, rc);
1359                         cYAML_build_error(-1, -1, "yaml", "builder",
1360                                           err_str,
1361                                           err_rc);
1362                 }
1363                 /* Are we finished? */
1364                 done = (rc != CYAML_ERROR_NONE ||
1365                         token.type == YAML_STREAM_END_TOKEN);
1366
1367                 token_type = token.type;
1368
1369                 yaml_token_delete(&token);
1370         }
1371
1372         if (token_type == YAML_STREAM_END_TOKEN &&
1373             rc == CYAML_ERROR_NONE)
1374                 return tree.root;
1375
1376         cYAML_free_tree(tree.root);
1377
1378         return NULL;
1379 }
1380
1381 struct cYAML *cYAML_load(FILE *file, struct cYAML **err_rc, bool debug)
1382 {
1383         yaml_parser_t parser;
1384         struct cYAML *yaml;
1385
1386         yaml_parser_initialize(&parser);
1387         yaml_parser_set_input_file(&parser, file);
1388
1389         yaml = cYAML_parser_to_tree(&parser, err_rc, debug);
1390
1391         yaml_parser_delete(&parser);
1392
1393         return yaml;
1394 }
1395
1396 struct cYAML *cYAML_build_tree(char *path,
1397                                const char *yaml_blk,
1398                                size_t yaml_blk_size,
1399                                struct cYAML **err_rc,
1400                                bool debug)
1401 {
1402         yaml_parser_t parser;
1403         struct cYAML *yaml;
1404         char err_str[256];
1405         FILE *input = NULL;
1406
1407         /* Create the Parser object. */
1408         yaml_parser_initialize(&parser);
1409
1410         /* file always takes precedence */
1411         if (path != NULL) {
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",
1418                                           err_str,
1419                                           err_rc);
1420                         return NULL;
1421                 }
1422
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,
1427                                              yaml_blk_size);
1428         } else {
1429                 /* assume that we're getting our input froms stdin */
1430                 yaml_parser_set_input_file(&parser, stdin);
1431         }
1432
1433         yaml = cYAML_parser_to_tree(&parser, err_rc, debug);
1434
1435         /* Destroy the Parser object. */
1436         yaml_parser_delete(&parser);
1437
1438         if (input != NULL)
1439                 fclose(input);
1440
1441         return yaml;
1442 }