Whamcloud - gitweb
LU-6142 lnet: SPDX for lnet/util/lnetconfig/
[fs/lustre-release.git] / lnet / utils / lnetconfig / cyaml.c
1 // SPDX-License-Identifier: LGPL-2.0
2
3 /*
4  * Copyright (c) 2014, 2017, Intel Corporation.
5  */
6
7 /*
8  * This file is part of Lustre, http://www.lustre.org/
9  *
10  *  The cYAML tree is constructed as an n-tree.
11  *  root -> cmd 1
12  *          ||
13  *          \/
14  *          cmd 2 -> attr1 -> attr2
15  *                              ||
16  *                              \/
17  *                            attr2.1 -> attr2.1.1 -> attr2.1.2
18  *
19  * Author: Amir Shehata <amir.shehata@intel.com>
20  */
21
22 #include <yaml.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <stdio.h>
26 #include <math.h>
27 #include <stdlib.h>
28 #include <errno.h>
29 #include <float.h>
30 #include <limits.h>
31 #include <ctype.h>
32 #include "libcfs/util/list.h"
33 #include <cyaml.h>
34
35 #define INDENT          4
36 #define EXTRA_IND       2
37 #define LEAD_ROOM       128
38 #define PRINT_BUF_LEN   2048
39
40 /*
41  * cYAML_print_info
42  *   This structure contains print information
43  *   required when printing the node
44  */
45 struct cYAML_print_info {
46         int level;
47         int array_first_elem;
48         int extra_ind;
49 };
50
51 /*
52  *  cYAML_ll
53  *  Linked list of different trees representing YAML
54  *  documents.
55  */
56 struct cYAML_ll {
57         struct list_head list;
58         struct cYAML *obj;
59         struct cYAML_print_info *print_info;
60 };
61
62 static void print_value(char **out, struct list_head *stack);
63
64 enum cYAML_handler_error {
65         CYAML_ERROR_NONE = 0,
66         CYAML_ERROR_UNEXPECTED_STATE = -1,
67         CYAML_ERROR_NOT_SUPPORTED = -2,
68         CYAML_ERROR_OUT_OF_MEM = -3,
69         CYAML_ERROR_BAD_VALUE = -4,
70         CYAML_ERROR_PARSE = -5,
71 };
72
73 enum cYAML_tree_state {
74         TREE_STATE_COMPLETE = 0,
75         TREE_STATE_INITED,
76         TREE_STATE_TREE_STARTED,
77         TREE_STATE_BLK_STARTED,
78         TREE_STATE_KEY,
79         TREE_STATE_KEY_FILLED,
80         TREE_STATE_VALUE,
81         TREE_STATE_SEQ_START,
82 };
83
84 struct cYAML_tree_node {
85         struct cYAML *root;
86         /* cur is the current node we're operating on */
87         struct cYAML *cur;
88         enum cYAML_tree_state state;
89         int from_blk_map_start;
90         /* represents the tree depth */
91         struct list_head ll;
92 };
93
94 typedef enum cYAML_handler_error (*yaml_token_handler)(yaml_token_t *token,
95                                                 struct cYAML_tree_node *);
96
97 static enum cYAML_handler_error yaml_no_token(yaml_token_t *token,
98                                         struct cYAML_tree_node *tree);
99 static enum cYAML_handler_error yaml_stream_start(yaml_token_t *token,
100                                         struct cYAML_tree_node *tree);
101 static enum cYAML_handler_error yaml_stream_end(yaml_token_t *token,
102                                         struct cYAML_tree_node *tree);
103 static enum cYAML_handler_error yaml_not_supported(yaml_token_t *token,
104                                                 struct cYAML_tree_node *tree);
105 static enum cYAML_handler_error yaml_document_start(yaml_token_t *token,
106                                                 struct cYAML_tree_node *tree);
107 static enum cYAML_handler_error yaml_document_end(yaml_token_t *token,
108                                                struct cYAML_tree_node *tree);
109 static enum cYAML_handler_error yaml_blk_seq_start(yaml_token_t *token,
110                                                 struct cYAML_tree_node *tree);
111 static enum cYAML_handler_error yaml_blk_mapping_start(yaml_token_t *token,
112                                                 struct cYAML_tree_node *tree);
113 static enum cYAML_handler_error yaml_block_end(yaml_token_t *token,
114                                         struct cYAML_tree_node *tree);
115 static enum cYAML_handler_error yaml_key(yaml_token_t *token,
116                                 struct cYAML_tree_node *tree);
117 static enum cYAML_handler_error yaml_value(yaml_token_t *token,
118                                         struct cYAML_tree_node *tree);
119 static enum cYAML_handler_error yaml_scalar(yaml_token_t *token,
120                                         struct cYAML_tree_node *tree);
121 static enum cYAML_handler_error yaml_entry_token(yaml_token_t *token,
122                                         struct cYAML_tree_node *tree);
123
124 /* dispatch table */
125 static yaml_token_handler dispatch_tbl[] = {
126         [YAML_NO_TOKEN] = yaml_no_token,
127         [YAML_STREAM_START_TOKEN] = yaml_stream_start,
128         [YAML_STREAM_END_TOKEN] = yaml_stream_end,
129         [YAML_VERSION_DIRECTIVE_TOKEN] = yaml_not_supported,
130         [YAML_TAG_DIRECTIVE_TOKEN] = yaml_not_supported,
131         [YAML_DOCUMENT_START_TOKEN] = yaml_document_start,
132         [YAML_DOCUMENT_END_TOKEN] = yaml_document_end,
133         [YAML_BLOCK_SEQUENCE_START_TOKEN] = yaml_blk_seq_start,
134         [YAML_BLOCK_MAPPING_START_TOKEN] = yaml_blk_mapping_start,
135         [YAML_BLOCK_END_TOKEN] = yaml_block_end,
136         [YAML_FLOW_SEQUENCE_START_TOKEN] = yaml_not_supported,
137         [YAML_FLOW_SEQUENCE_END_TOKEN] = yaml_not_supported,
138         [YAML_FLOW_MAPPING_START_TOKEN] = yaml_not_supported,
139         [YAML_FLOW_MAPPING_END_TOKEN] = yaml_not_supported,
140         [YAML_BLOCK_ENTRY_TOKEN] = yaml_entry_token,
141         [YAML_FLOW_ENTRY_TOKEN] = yaml_not_supported,
142         [YAML_KEY_TOKEN] = yaml_key,
143         [YAML_VALUE_TOKEN] = yaml_value,
144         [YAML_ALIAS_TOKEN] = yaml_not_supported,
145         [YAML_ANCHOR_TOKEN] = yaml_not_supported,
146         [YAML_TAG_TOKEN] = yaml_not_supported,
147         [YAML_SCALAR_TOKEN] = yaml_scalar,
148 };
149
150 /* dispatch table */
151 static const char * const token_type_string[] = {
152         [YAML_NO_TOKEN] = "YAML_NO_TOKEN",
153         [YAML_STREAM_START_TOKEN] = "YAML_STREAM_START_TOKEN",
154         [YAML_STREAM_END_TOKEN] = "YAML_STREAM_END_TOKEN",
155         [YAML_VERSION_DIRECTIVE_TOKEN] = "YAML_VERSION_DIRECTIVE_TOKEN",
156         [YAML_TAG_DIRECTIVE_TOKEN] = "YAML_TAG_DIRECTIVE_TOKEN",
157         [YAML_DOCUMENT_START_TOKEN] = "YAML_DOCUMENT_START_TOKEN",
158         [YAML_DOCUMENT_END_TOKEN] = "YAML_DOCUMENT_END_TOKEN",
159         [YAML_BLOCK_SEQUENCE_START_TOKEN] = "YAML_BLOCK_SEQUENCE_START_TOKEN",
160         [YAML_BLOCK_MAPPING_START_TOKEN] = "YAML_BLOCK_MAPPING_START_TOKEN",
161         [YAML_BLOCK_END_TOKEN] = "YAML_BLOCK_END_TOKEN",
162         [YAML_FLOW_SEQUENCE_START_TOKEN] = "YAML_FLOW_SEQUENCE_START_TOKEN",
163         [YAML_FLOW_SEQUENCE_END_TOKEN] = "YAML_FLOW_SEQUENCE_END_TOKEN",
164         [YAML_FLOW_MAPPING_START_TOKEN] = "YAML_FLOW_MAPPING_START_TOKEN",
165         [YAML_FLOW_MAPPING_END_TOKEN] = "YAML_FLOW_MAPPING_END_TOKEN",
166         [YAML_BLOCK_ENTRY_TOKEN] = "YAML_BLOCK_ENTRY_TOKEN",
167         [YAML_FLOW_ENTRY_TOKEN] = "YAML_FLOW_ENTRY_TOKEN",
168         [YAML_KEY_TOKEN] = "YAML_KEY_TOKEN",
169         [YAML_VALUE_TOKEN] = "YAML_VALUE_TOKEN",
170         [YAML_ALIAS_TOKEN] = "YAML_ALIAS_TOKEN",
171         [YAML_ANCHOR_TOKEN] = "YAML_ANCHOR_TOKEN",
172         [YAML_TAG_TOKEN] = "YAML_TAG_TOKEN",
173         [YAML_SCALAR_TOKEN] = "YAML_SCALAR_TOKEN",
174 };
175
176 static const char * const state_string[] = {
177         [TREE_STATE_COMPLETE] = "COMPLETE",
178         [TREE_STATE_INITED] = "INITED",
179         [TREE_STATE_TREE_STARTED] = "TREE_STARTED",
180         [TREE_STATE_BLK_STARTED] = "BLK_STARTED",
181         [TREE_STATE_KEY] = "KEY",
182         [TREE_STATE_KEY_FILLED] = "KEY_FILLED",
183         [TREE_STATE_VALUE] = "VALUE",
184         [TREE_STATE_SEQ_START] = "SEQ_START",
185 };
186
187 static void cYAML_ll_free(struct list_head *ll)
188 {
189         struct cYAML_ll *node, *tmp;
190
191         list_for_each_entry_safe(node, tmp, ll, list) {
192                 free(node->print_info);
193                 free(node);
194         }
195 }
196
197 static int cYAML_ll_push(struct cYAML *obj,
198                          const struct cYAML_print_info *print_info,
199                          struct list_head *list)
200 {
201         struct cYAML_ll *node = calloc(1, sizeof(*node));
202         if (node == NULL)
203                 return -1;
204
205         INIT_LIST_HEAD(&node->list);
206
207         if (print_info) {
208                 node->print_info = calloc(1, sizeof(*print_info));
209                 if (node->print_info == NULL) {
210                         free(node);
211                         return -1;
212                 }
213                 *node->print_info = *print_info;
214         }
215         node->obj = obj;
216
217         list_add(&node->list, list);
218
219         return 0;
220 }
221
222 static struct cYAML *cYAML_ll_pop(struct list_head *list,
223                                   struct cYAML_print_info **print_info)
224 {
225         struct cYAML_ll *pop;
226         struct cYAML *obj = NULL;
227
228         if (!list_empty(list)) {
229                 pop = list_first_entry(list, struct cYAML_ll, list);
230
231                 obj = pop->obj;
232                 if (print_info != NULL)
233                         *print_info = pop->print_info;
234                 list_del(&pop->list);
235
236                 if (print_info == NULL)
237                         free(pop->print_info);
238
239                 free(pop);
240         }
241         return obj;
242 }
243
244 static int cYAML_ll_count(struct list_head *ll)
245 {
246         int i = 0;
247         struct list_head *node;
248
249         list_for_each(node, ll)
250                 i++;
251
252         return i;
253 }
254
255 static int cYAML_tree_init(struct cYAML_tree_node *tree)
256 {
257         struct cYAML *obj = NULL, *cur = NULL;
258
259         if (tree == NULL)
260                 return -1;
261
262         obj = calloc(1, sizeof(*obj));
263         if (obj == NULL)
264                 return -1;
265
266         if (tree->root) {
267                 /* append the node */
268                 cur = tree->root;
269                 while (cur->cy_next != NULL)
270                         cur = cur->cy_next;
271                 cur->cy_next = obj;
272         } else {
273                 tree->root = obj;
274         }
275
276         obj->cy_type = CYAML_TYPE_OBJECT;
277
278         tree->cur = obj;
279         tree->state = TREE_STATE_COMPLETE;
280
281         /* free it and start anew */
282         if (!list_empty(&tree->ll))
283                 cYAML_ll_free(&tree->ll);
284
285         return 0;
286 }
287
288 static struct cYAML *create_child(struct cYAML *parent)
289 {
290         struct cYAML *obj;
291
292         if (parent == NULL)
293                 return NULL;
294
295         obj = calloc(1, sizeof(*obj));
296         if (obj == NULL)
297                 return NULL;
298
299         /* set the type to OBJECT and let the value change that */
300         obj->cy_type = CYAML_TYPE_OBJECT;
301
302         parent->cy_child = obj;
303
304         return obj;
305 }
306
307 static struct cYAML *create_sibling(struct cYAML *sibling)
308 {
309         struct cYAML *obj;
310
311         if (sibling == NULL)
312                 return NULL;
313
314         obj = calloc(1, sizeof(*obj));
315         if (obj == NULL)
316                 return NULL;
317
318         /* set the type to OBJECT and let the value change that */
319         obj->cy_type = CYAML_TYPE_OBJECT;
320
321         sibling->cy_next = obj;
322         obj->cy_prev = sibling;
323
324         return obj;
325 }
326
327 /* Parse the input text to generate a number,
328  * and populate the result into item. */
329 static bool parse_number(struct cYAML *item, const char *input)
330 {
331         double n = 0, sign = 1, scale = 0;
332         int subscale = 0, signsubscale = 1;
333         const char *num = input;
334
335         if (!strncmp(input, "0x", 2)) {
336                 int64_t hex; /* hex input is always an integer */
337                 char *invalid = NULL;
338
339                 errno = 0;
340                 hex = strtoll(input, &invalid, 16);
341                 if (errno)
342                         return false;
343                 if (*invalid)
344                         return false;
345
346                 item->cy_valuedouble = (double) hex;
347                 item->cy_valueint = hex;
348                 item->cy_type = CYAML_TYPE_NUMBER;
349                 return true;
350         }
351
352         if (*num == '-') {
353                 sign = -1;
354                 num++;
355         }
356
357         if (*num == '0')
358                 num++;
359
360         if (*num >= '1' && *num <= '9') {
361                 do {
362                         n = (n * 10.0) + (*num++ - '0');
363                 } while (*num >= '0' && *num <= '9');
364         }
365
366         if (*num == '.' && num[1] >= '0' && num[1] <= '9') {
367                 num++;
368                 do {
369                         n = (n * 10.0) + (*num++ - '0');
370                         scale--;
371                 } while (*num >= '0' && *num <= '9');
372         }
373
374         if (*num == 'e' || *num == 'E') {
375                 num++;
376                 if (*num == '+') {
377                         num++;
378                 } else if (*num == '-') {
379                         signsubscale = -1;
380                         num++;
381                 }
382                 while (*num >= '0' && *num <= '9')
383                         subscale = (subscale * 10) + (*num++ - '0');
384         }
385
386         /* check to see if the entire string is consumed.  If not then
387          * that means this is a string with a number in it */
388         if (num != (input + strlen(input)))
389                 return false;
390
391         /* number = +/- number.fraction * 10^+/- exponent */
392         n = sign * n * pow(10.0, (scale + subscale * signsubscale));
393
394         item->cy_valuedouble = n;
395         item->cy_valueint = (int64_t)n;
396         item->cy_type = CYAML_TYPE_NUMBER;
397
398         return true;
399 }
400
401 static int assign_type_value(struct cYAML *obj, const char *value)
402 {
403         if (value == NULL)
404                 return -1;
405
406         if (strcmp(value, "null") == 0)
407                 obj->cy_type = CYAML_TYPE_NULL;
408         else if (strcmp(value, "false") == 0) {
409                 obj->cy_type = CYAML_TYPE_FALSE;
410                 obj->cy_valueint = 0;
411         } else if (strcmp(value, "true") == 0) {
412                 obj->cy_type = CYAML_TYPE_TRUE;
413                 obj->cy_valueint = 1;
414         } else if (*value == '-' || (*value >= '0' && *value <= '9')) {
415                 if (parse_number(obj, value) == 0) {
416                         obj->cy_valuestring = strdup(value);
417                         obj->cy_type = CYAML_TYPE_STRING;
418                 }
419         } else {
420                 obj->cy_valuestring = strdup(value);
421                 obj->cy_type = CYAML_TYPE_STRING;
422         }
423
424         return 0;
425 }
426
427 /*
428  * yaml_handle_token
429  *  Builds the YAML tree rpresentation as the tokens are passed in
430  *
431  *  if token == STREAM_START && tree_state != COMPLETE
432  *    something wrong. fail.
433  *  else tree_state = INITIED
434  *  if token == DOCUMENT_START && tree_state != COMPLETE || INITED
435  *    something wrong, fail.
436  *  else tree_state = TREE_STARTED
437  *  if token == DOCUMENT_END
438  *    tree_state = INITED if no STREAM START, else tree_state = COMPLETE
439  *    erase everything on ll
440  *  if token == STREAM_END && tree_state != INITED
441  *    something wrong fail.
442  *  else tree_state = COMPLETED
443  *  if token == YAML_KEY_TOKEN && state != TREE_STARTED
444  *    something wrong, fail.
445  *  if token == YAML_SCALAR_TOKEN && state != KEY || VALUE
446  *    fail.
447  *  else if tree_state == KEY
448  *     create a new sibling under the current head of the ll (if ll is
449  *     empty insert the new node there and it becomes the root.)
450  *    add the scalar value in the "string"
451  *    tree_state = KEY_FILLED
452  *  else if tree_state == VALUE
453  *    try and figure out whether this is a double, int or string and store
454  *    it appropriately
455  *    state = TREE_STARTED
456  * else if token == YAML_BLOCK_MAPPING_START_TOKEN && tree_state != VALUE
457  *   fail
458  * else push the current node on the ll && state = TREE_STARTED
459  * if token == YAML_BLOCK_END_TOKEN && state != TREE_STARTED
460  *   fail.
461  * else pop the current token off the ll and make it the cur
462  * if token == YAML_VALUE_TOKEN && state != KEY_FILLED
463  *   fail.
464  * else state = VALUE
465  *
466  */
467
468 static enum cYAML_handler_error yaml_no_token(yaml_token_t *token,
469                                               struct cYAML_tree_node *tree)
470 {
471         return CYAML_ERROR_NONE;
472 }
473
474 static enum cYAML_handler_error yaml_stream_start(yaml_token_t *token,
475                                                   struct cYAML_tree_node *tree)
476 {
477         enum cYAML_handler_error rc;
478
479         /* with each new stream initialize a new tree */
480         rc = cYAML_tree_init(tree);
481
482         if (rc != CYAML_ERROR_NONE)
483                 return rc;
484
485         tree->state = TREE_STATE_INITED;
486
487         return CYAML_ERROR_NONE;
488 }
489
490 static enum cYAML_handler_error yaml_stream_end(yaml_token_t *token,
491                                                 struct cYAML_tree_node *tree)
492 {
493         if (tree->state != TREE_STATE_TREE_STARTED &&
494             tree->state != TREE_STATE_COMPLETE &&
495             tree->state != TREE_STATE_INITED)
496                 return CYAML_ERROR_UNEXPECTED_STATE;
497
498         tree->state = TREE_STATE_INITED;
499
500         return CYAML_ERROR_NONE;
501 }
502
503 static enum cYAML_handler_error
504 yaml_document_start(yaml_token_t *token, struct cYAML_tree_node *tree)
505 {
506         if (tree->state != TREE_STATE_INITED)
507                 return CYAML_ERROR_UNEXPECTED_STATE;
508
509         /* go to started state since we're expecting more tokens to come */
510         tree->state = TREE_STATE_TREE_STARTED;
511
512         return CYAML_ERROR_NONE;
513 }
514
515 static enum cYAML_handler_error yaml_document_end(yaml_token_t *token,
516                                                   struct cYAML_tree_node *tree)
517 {
518         if (tree->state != TREE_STATE_COMPLETE)
519                 return CYAML_ERROR_UNEXPECTED_STATE;
520
521         tree->state = TREE_STATE_TREE_STARTED;
522
523         return CYAML_ERROR_NONE;
524 }
525
526 static enum cYAML_handler_error yaml_key(yaml_token_t *token,
527                                          struct cYAML_tree_node *tree)
528 {
529         if (tree->state != TREE_STATE_BLK_STARTED &&
530             tree->state != TREE_STATE_VALUE)
531                 return CYAML_ERROR_UNEXPECTED_STATE;
532
533         if (tree->from_blk_map_start == 0 ||
534             tree->state == TREE_STATE_VALUE)
535                 tree->cur = create_sibling(tree->cur);
536
537         tree->from_blk_map_start = 0;
538
539         tree->state = TREE_STATE_KEY;
540
541         return CYAML_ERROR_NONE;
542 }
543
544 static enum cYAML_handler_error yaml_scalar(yaml_token_t *token,
545                                             struct cYAML_tree_node *tree)
546 {
547         if (tree->state == TREE_STATE_KEY) {
548                 /* assign the scalar value to the key that was created */
549                 tree->cur->cy_string =
550                   strdup((const char *)token->data.scalar.value);
551
552                 tree->state = TREE_STATE_KEY_FILLED;
553         } else if (tree->state == TREE_STATE_VALUE ||
554                    tree->state == TREE_STATE_SEQ_START) {
555                 if (assign_type_value(tree->cur,
556                                       (char *)token->data.scalar.value))
557                         /* failed to assign a value */
558                         return CYAML_ERROR_BAD_VALUE;
559                 tree->state = TREE_STATE_BLK_STARTED;
560         } else {
561                 return CYAML_ERROR_UNEXPECTED_STATE;
562         }
563
564         return CYAML_ERROR_NONE;
565 }
566
567 static enum cYAML_handler_error yaml_value(yaml_token_t *token,
568                                            struct cYAML_tree_node *tree)
569 {
570         if (tree->state != TREE_STATE_KEY_FILLED)
571                 return CYAML_ERROR_UNEXPECTED_STATE;
572
573         tree->state = TREE_STATE_VALUE;
574
575         return CYAML_ERROR_NONE;
576 }
577
578 static enum cYAML_handler_error yaml_blk_seq_start(yaml_token_t *token,
579                                                    struct cYAML_tree_node *tree)
580 {
581         if (tree->state != TREE_STATE_VALUE)
582                 return CYAML_ERROR_UNEXPECTED_STATE;
583
584         /* Since a sequenc start event determines that this is the start
585          * of an array, then that means the current node we're at is an
586          * array and we need to flag it as such */
587         tree->cur->cy_type = CYAML_TYPE_ARRAY;
588         tree->state = TREE_STATE_SEQ_START;
589
590         return CYAML_ERROR_NONE;
591 }
592
593 static enum cYAML_handler_error yaml_entry_token(yaml_token_t *token,
594                                                  struct cYAML_tree_node *tree)
595 {
596         struct cYAML *obj;
597
598         if (tree->state != TREE_STATE_SEQ_START &&
599             tree->state != TREE_STATE_BLK_STARTED &&
600             tree->state != TREE_STATE_VALUE)
601                 return CYAML_ERROR_UNEXPECTED_STATE;
602
603         if (tree->state == TREE_STATE_SEQ_START) {
604                 obj = create_child(tree->cur);
605
606                 if (cYAML_ll_push(tree->cur, NULL, &tree->ll))
607                         return CYAML_ERROR_OUT_OF_MEM;
608
609                 tree->cur = obj;
610         } else {
611                 tree->cur = create_sibling(tree->cur);
612                 tree->state = TREE_STATE_SEQ_START;
613         }
614
615         return CYAML_ERROR_NONE;
616 }
617
618 static enum cYAML_handler_error
619 yaml_blk_mapping_start(yaml_token_t *token,
620                        struct cYAML_tree_node *tree)
621 {
622         struct cYAML *obj;
623
624         if (tree->state != TREE_STATE_VALUE &&
625             tree->state != TREE_STATE_INITED &&
626             tree->state != TREE_STATE_SEQ_START &&
627             tree->state != TREE_STATE_TREE_STARTED)
628                 return CYAML_ERROR_UNEXPECTED_STATE;
629
630         /* block_mapping_start means we're entering another block
631          * indentation, so we need to go one level deeper
632          * create a child of cur */
633         obj = create_child(tree->cur);
634
635         /* push cur on the stack */
636         if (cYAML_ll_push(tree->cur, NULL, &tree->ll))
637                 return CYAML_ERROR_OUT_OF_MEM;
638
639         /* adding the new child to cur */
640         tree->cur = obj;
641
642         tree->state = TREE_STATE_BLK_STARTED;
643
644         tree->from_blk_map_start = 1;
645
646         return CYAML_ERROR_NONE;
647 }
648
649 static enum cYAML_handler_error yaml_block_end(yaml_token_t *token,
650                                                struct cYAML_tree_node *tree)
651 {
652         if (tree->state != TREE_STATE_BLK_STARTED &&
653             tree->state != TREE_STATE_VALUE)
654                 return CYAML_ERROR_UNEXPECTED_STATE;
655
656         tree->cur = cYAML_ll_pop(&tree->ll, NULL);
657
658         /* if you have popped all the way to the top level, then move to
659          * the complete state. */
660         if (cYAML_ll_count(&tree->ll) == 0)
661                 tree->state = TREE_STATE_COMPLETE;
662         else if (tree->state == TREE_STATE_VALUE)
663                 tree->state = TREE_STATE_BLK_STARTED;
664
665         return CYAML_ERROR_NONE;
666 }
667
668 static enum cYAML_handler_error yaml_not_supported(yaml_token_t *token,
669                                                    struct cYAML_tree_node *tree)
670 {
671         return CYAML_ERROR_NOT_SUPPORTED;
672 }
673
674 static bool clean_usr_data(struct cYAML *node, void *usr_data, void **out)
675 {
676         cYAML_user_data_free_cb free_cb = usr_data;
677
678         if (free_cb && node && node->cy_user_data) {
679                 free_cb(node->cy_user_data);
680                 node->cy_user_data = NULL;
681         }
682
683         return true;
684 }
685
686 static bool free_node(struct cYAML *node, void *user_data, void **out)
687 {
688         if (!node)
689                 return true;
690
691         if (node->cy_type == CYAML_TYPE_STRING)
692                 free(node->cy_valuestring);
693         if (node->cy_string)
694                 free(node->cy_string);
695
696         free(node);
697         return true;
698 }
699
700 static bool find_obj_iter(struct cYAML *node, void *usr_data, void **out)
701 {
702         char *name = usr_data;
703
704         if (node != NULL && node->cy_string != NULL &&
705             strcmp(node->cy_string, name) == 0) {
706                 *out = node;
707                 return false;
708         }
709
710         return true;
711 }
712
713 struct cYAML *cYAML_get_object_item(struct cYAML *parent, const char *name)
714 {
715         struct cYAML *node = parent, *found = NULL;
716
717         if (!node || !name)
718                 return NULL;
719
720         if (node->cy_string) {
721                 if (strcmp(node->cy_string, name) == 0)
722                         return node;
723         }
724
725         if (node->cy_child)
726                 found = cYAML_get_object_item(node->cy_child, name);
727
728         if (!found && node->cy_next)
729                 found = cYAML_get_object_item(node->cy_next, name);
730
731         return found;
732 }
733
734 struct cYAML *cYAML_get_next_seq_item(struct cYAML *seq, struct cYAML **itm)
735 {
736         if (*itm != NULL && (*itm)->cy_next != NULL) {
737                 *itm = (*itm)->cy_next;
738                 return *itm;
739         }
740
741         if (*itm == NULL && seq->cy_type == CYAML_TYPE_ARRAY) {
742                 *itm = seq->cy_child;
743                 return *itm;
744         }
745
746         return NULL;
747 }
748
749 bool cYAML_is_sequence(struct cYAML *node)
750 {
751         return (node != NULL ? node->cy_type == CYAML_TYPE_ARRAY : 0);
752 }
753
754 static void cYAML_tree_recursive_walk(struct cYAML *node, cYAML_walk_cb cb,
755                                       bool cb_first,
756                                       void *usr_data,
757                                       void **out)
758 {
759         if (node == NULL)
760                 return;
761
762         if (cb_first) {
763                 if (!cb(node, usr_data, out))
764                         return;
765         }
766
767         if (node->cy_child)
768                 cYAML_tree_recursive_walk(node->cy_child, cb,
769                                           cb_first, usr_data, out);
770
771         if (node->cy_next)
772                 cYAML_tree_recursive_walk(node->cy_next, cb,
773                                           cb_first, usr_data, out);
774
775         if (!cb_first) {
776                 if (!cb(node, usr_data, out))
777                         return;
778         }
779 }
780
781 struct cYAML *cYAML_find_object(struct cYAML *root, const char *name)
782 {
783         struct cYAML *found = NULL;
784
785         cYAML_tree_recursive_walk(root, find_obj_iter, true,
786                                   (void *)name, (void **)&found);
787
788         return found;
789 }
790
791 void cYAML_clean_usr_data(struct cYAML *node, cYAML_user_data_free_cb free_cb)
792 {
793         cYAML_tree_recursive_walk(node, clean_usr_data, false, free_cb, NULL);
794 }
795
796 void cYAML_free_tree(struct cYAML *node)
797 {
798         cYAML_tree_recursive_walk(node, free_node, false, NULL, NULL);
799 }
800
801 static char *ensure(char *in, int len)
802 {
803         int curlen;
804         char *new = in;
805
806         if (!in)
807                 return (char*)calloc(len, 1);
808
809         curlen = strlen(in) + 1;
810
811         if (curlen <= curlen + len) {
812                 new = calloc(curlen + len, 1);
813                 if (!new) {
814                         free(in);
815                         return NULL;
816                 }
817                 strcpy(new, in);
818                 free(in);
819         }
820
821         return new;
822 }
823
824 static inline void print_simple(char **out, struct cYAML *node,
825                                 struct cYAML_print_info *cpi)
826 {
827         int level = cpi->level;
828         int ind = cpi->extra_ind;
829         char *tmp = NULL;
830         int len = (INDENT * level + ind) * 2 +
831           ((node->cy_string) ? strlen(node->cy_string) : 0) + LEAD_ROOM;
832
833         *out = ensure(*out, len);
834         if (!*out)
835                 return;
836
837         tmp = ensure(tmp, len);
838         if (!tmp)
839                 return;
840
841         if (cpi->array_first_elem) {
842                 sprintf(tmp, "%*s- ", INDENT * level, "");
843                 strcat(*out, tmp);
844         }
845
846         sprintf(tmp, "%*s""%s: %" PRId64 "\n", (cpi->array_first_elem) ? 0 :
847                 INDENT * level + ind, "", node->cy_string,
848                 node->cy_valueint);
849         strcat(*out, tmp);
850         free(tmp);
851 }
852
853 static void print_string(char **out, struct cYAML *node,
854                          struct cYAML_print_info *cpi)
855 {
856         char *new_line;
857         int level = cpi->level;
858         int ind = cpi->extra_ind;
859         char *tmp = NULL;
860         int len = INDENT * level + ind +
861           ((node->cy_valuestring) ? strlen(node->cy_valuestring) : 0) +
862           ((node->cy_string) ? strlen(node->cy_string) : 0) + LEAD_ROOM;
863
864         *out = ensure(*out, len);
865         if (!*out)
866                 return;
867
868         tmp = ensure(tmp, len);
869         if (!tmp)
870                 return;
871
872         if (cpi->array_first_elem) {
873                 sprintf(tmp, "%*s- ", INDENT * level, "");
874                 strcat(*out, tmp);
875         }
876
877         new_line = strchr(node->cy_valuestring, '\n');
878         if (new_line == NULL) {
879                 sprintf(tmp, "%*s""%s: %s\n", (cpi->array_first_elem) ?
880                         0 : INDENT * level + ind, "",
881                         node->cy_string, node->cy_valuestring);
882                 strcat(*out, tmp);
883         } else {
884                 int indent = 0;
885                 sprintf(tmp, "%*s""%s: ", (cpi->array_first_elem) ?
886                         0 : INDENT * level + ind, "",
887                         node->cy_string);
888                 strcat(*out, tmp);
889                 char *l = node->cy_valuestring;
890                 while (new_line) {
891                         *new_line = '\0';
892                         sprintf(tmp, "%*s""%s\n", indent, "", l);
893                         strcat(*out, tmp);
894                         indent = INDENT * level + ind +
895                                   strlen(node->cy_string) + 2;
896                         *new_line = '\n';
897                         l = new_line+1;
898                         new_line = strchr(l, '\n');
899                 }
900                 sprintf(tmp, "%*s""%s\n", indent, "", l);
901                 strcat(*out, tmp);
902         }
903
904         free(tmp);
905 }
906
907 static void print_number(char **out, struct cYAML *node,
908                          struct cYAML_print_info *cpi)
909 {
910         double d = node->cy_valuedouble;
911         int level = cpi->level;
912         int ind = cpi->extra_ind;
913         char *tmp = NULL;
914         int len = INDENT * level + ind + LEAD_ROOM;
915
916         *out = ensure(*out, len);
917         if (!*out)
918                 return;
919
920         tmp = ensure(tmp, len);
921         if (!tmp)
922                 return;
923
924         if (cpi->array_first_elem) {
925                 sprintf(tmp, "%*s- ", INDENT * level, "");
926                 strcat(*out, tmp);
927         }
928
929         if ((fabs(((double)node->cy_valueint) - d) <= DBL_EPSILON) &&
930             (d <= INT_MAX) && (d >= INT_MIN)) {
931                 sprintf(tmp, "%*s""%s: %" PRId64 "\n", (cpi->array_first_elem) ? 0 :
932                         INDENT * level + ind, "",
933                         node->cy_string, node->cy_valueint);
934                 strcat(*out, tmp);
935         } else {
936                 if ((fabs(floor(d) - d) <= DBL_EPSILON) &&
937                     (fabs(d) < 1.0e60)) {
938                         sprintf(tmp, "%*s""%s: %.0f\n",
939                                 (cpi->array_first_elem) ? 0 :
940                                 INDENT * level + ind, "",
941                                 node->cy_string, d);
942                         strcat(*out, tmp);
943                 } else if ((fabs(d) < 1.0e-6) || (fabs(d) > 1.0e9)) {
944                         sprintf(tmp, "%*s""%s: %e\n",
945                                 (cpi->array_first_elem) ? 0 :
946                                 INDENT * level + ind, "",
947                                 node->cy_string, d);
948                         strcat(*out, tmp);
949                 } else {
950                         sprintf(tmp, "%*s""%s: %f\n",
951                                 (cpi->array_first_elem) ? 0 :
952                                 INDENT * level + ind, "",
953                                 node->cy_string, d);
954                         strcat(*out, tmp);
955                 }
956         }
957
958         free(tmp);
959 }
960
961 static void print_object(char **out, struct cYAML *node,
962                          struct list_head *stack,
963                          struct cYAML_print_info *cpi)
964 {
965         struct cYAML_print_info print_info;
966         struct cYAML *child = node->cy_child;
967         char *tmp = NULL;
968         int len = ((cpi->array_first_elem) ? INDENT * cpi->level :
969           INDENT * cpi->level + cpi->extra_ind) +
970           ((node->cy_string) ? strlen(node->cy_string) : 0) +
971           LEAD_ROOM;
972
973         *out = ensure(*out, len);
974         if (!*out)
975                 return;
976
977         tmp = ensure(tmp, len);
978         if (!tmp)
979                 return;
980
981         if (node->cy_string != NULL) {
982                 sprintf(tmp, "%*s""%s%s:\n", (cpi->array_first_elem) ?
983                         INDENT * cpi->level :
984                         INDENT * cpi->level + cpi->extra_ind,
985                         "", (cpi->array_first_elem) ? "- " : "",
986                         node->cy_string);
987                 strcat(*out, tmp);
988         }
989
990         print_info.level = (node->cy_string != NULL) ? cpi->level + 1 :
991           cpi->level;
992         print_info.array_first_elem = (node->cy_string == NULL) ?
993           cpi->array_first_elem : 0;
994         print_info.extra_ind = (cpi->array_first_elem) ? EXTRA_IND :
995           cpi->extra_ind;
996
997         while (child) {
998                 if (cYAML_ll_push(child, &print_info, stack) != 0) {
999                         free(tmp);
1000                         return;
1001                 }
1002                 print_value(out, stack);
1003                 print_info.array_first_elem = 0;
1004                 child = child->cy_next;
1005         }
1006
1007         free(tmp);
1008 }
1009
1010 static void print_array(char **out, struct cYAML *node,
1011                         struct list_head *stack,
1012                         struct cYAML_print_info *cpi)
1013 {
1014         struct cYAML_print_info print_info;
1015         struct cYAML *child = node->cy_child;
1016         char *tmp = NULL;
1017         int len = ((node->cy_string) ? strlen(node->cy_string) : 0) +
1018           INDENT * cpi->level + cpi->extra_ind + LEAD_ROOM;
1019
1020         *out = ensure(*out, len);
1021         if (!*out)
1022                 return;
1023
1024         tmp = ensure(tmp, len);
1025         if (!tmp)
1026                 return;
1027
1028         if (node->cy_string != NULL) {
1029                 sprintf(tmp, "%*s""%s:\n", INDENT * cpi->level + cpi->extra_ind,
1030                         "", node->cy_string);
1031                 strcat(*out, tmp);
1032         }
1033
1034         print_info.level = (node->cy_string != NULL) ? cpi->level + 1 :
1035           cpi->level;
1036         print_info.array_first_elem =  1;
1037         print_info.extra_ind = EXTRA_IND;
1038
1039         while (child) {
1040                 if (cYAML_ll_push(child, &print_info, stack) != 0) {
1041                         free(tmp);
1042                         return;
1043                 }
1044                 print_value(out, stack);
1045                 child = child->cy_next;
1046         }
1047
1048         free(tmp);
1049 }
1050
1051 static void print_value(char **out, struct list_head *stack)
1052 {
1053         struct cYAML_print_info *cpi = NULL;
1054         struct cYAML *node = cYAML_ll_pop(stack, &cpi);
1055
1056         if (node == NULL)
1057                 return;
1058
1059         switch (node->cy_type) {
1060         case CYAML_TYPE_FALSE:
1061         case CYAML_TYPE_TRUE:
1062         case CYAML_TYPE_NULL:
1063                 print_simple(out, node, cpi);
1064                 break;
1065         case CYAML_TYPE_STRING:
1066                 print_string(out, node, cpi);
1067                 break;
1068         case CYAML_TYPE_NUMBER:
1069                 print_number(out, node, cpi);
1070                 break;
1071         case CYAML_TYPE_ARRAY:
1072                 print_array(out, node, stack, cpi);
1073                 break;
1074         case CYAML_TYPE_OBJECT:
1075                 print_object(out, node, stack, cpi);
1076                 break;
1077         default:
1078         break;
1079         }
1080
1081         if (cpi != NULL)
1082                 free(cpi);
1083 }
1084
1085 void cYAML_dump(struct cYAML *node, char **buf)
1086 {
1087         struct cYAML_print_info print_info;
1088         struct list_head list;
1089
1090         *buf = ensure(NULL, PRINT_BUF_LEN);
1091
1092         if (!*buf)
1093                 return;
1094
1095         INIT_LIST_HEAD(&list);
1096
1097         if (node == NULL) {
1098                 *buf = NULL;
1099                 return;
1100         }
1101
1102         memset(&print_info, 0, sizeof(struct cYAML_print_info));
1103
1104         if (cYAML_ll_push(node, &print_info, &list) == 0)
1105                 print_value(buf, &list);
1106 }
1107
1108 void cYAML_print_tree(struct cYAML *node)
1109 {
1110         struct cYAML_print_info print_info;
1111         struct list_head list;
1112         char *buf = ensure(NULL, PRINT_BUF_LEN);
1113
1114         if (!buf)
1115                 return;
1116
1117         INIT_LIST_HEAD(&list);
1118
1119         if (node == NULL)
1120                 return;
1121
1122         memset(&print_info, 0, sizeof(struct cYAML_print_info));
1123
1124         if (cYAML_ll_push(node, &print_info, &list) == 0)
1125                 print_value(&buf, &list);
1126
1127         /* buf could've been freed if we ran out of memory */
1128         if (buf) {
1129                 printf("%s", buf);
1130                 free(buf);
1131         }
1132 }
1133
1134 void cYAML_print_tree2file(FILE *f, struct cYAML *node)
1135 {
1136         struct cYAML_print_info print_info;
1137         struct list_head list;
1138         char *buf = ensure(NULL, PRINT_BUF_LEN);
1139
1140         if (!buf)
1141                 return;
1142
1143         INIT_LIST_HEAD(&list);
1144
1145         if (node == NULL)
1146                 return;
1147
1148         memset(&print_info, 0, sizeof(struct cYAML_print_info));
1149
1150         if (cYAML_ll_push(node, &print_info, &list) == 0)
1151                 print_value(&buf, &list);
1152
1153         /* buf could've been freed if we ran out of memory */
1154         if (buf) {
1155                 fprintf(f, "%s", buf);
1156                 free(buf);
1157         }
1158 }
1159
1160 static struct cYAML *insert_item(struct cYAML *parent, char *key,
1161                                  enum cYAML_object_type type)
1162 {
1163         struct cYAML *node = calloc(1, sizeof(*node));
1164
1165         if (node == NULL)
1166                 return NULL;
1167
1168         if (key != NULL)
1169                 node->cy_string = strdup(key);
1170
1171         node->cy_type = type;
1172
1173         cYAML_insert_child(parent, node);
1174
1175         return node;
1176 }
1177
1178 struct cYAML *cYAML_create_seq(struct cYAML *parent, char *key)
1179 {
1180         return insert_item(parent, key, CYAML_TYPE_ARRAY);
1181 }
1182
1183 struct cYAML *cYAML_create_seq_item(struct cYAML *seq)
1184 {
1185         return insert_item(seq, NULL, CYAML_TYPE_OBJECT);
1186 }
1187
1188 struct cYAML *cYAML_create_object(struct cYAML *parent, char *key)
1189 {
1190         return insert_item(parent, key, CYAML_TYPE_OBJECT);
1191 }
1192
1193 struct cYAML *cYAML_create_string(struct cYAML *parent, char *key, char *value)
1194 {
1195         struct cYAML *node = calloc(1, sizeof(*node));
1196         if (node == NULL)
1197                 return NULL;
1198
1199         node->cy_string = strdup(key);
1200         node->cy_valuestring = strdup(value);
1201         node->cy_type = CYAML_TYPE_STRING;
1202
1203         cYAML_insert_child(parent, node);
1204
1205         return node;
1206 }
1207
1208 struct cYAML *cYAML_create_number(struct cYAML *parent, char *key, double value)
1209 {
1210         struct cYAML *node = calloc(1, sizeof(*node));
1211         if (node == NULL)
1212                 return NULL;
1213
1214         node->cy_string = strdup(key);
1215         node->cy_valuedouble = value;
1216         node->cy_valueint = (int)value;
1217         node->cy_type = CYAML_TYPE_NUMBER;
1218
1219         cYAML_insert_child(parent, node);
1220
1221         return node;
1222 }
1223
1224 void cYAML_insert_child(struct cYAML *parent, struct cYAML *node)
1225 {
1226         struct cYAML *cur;
1227
1228         if (parent && node) {
1229                 if (parent->cy_child == NULL) {
1230                         parent->cy_child = node;
1231                         return;
1232                 }
1233
1234                 cur = parent->cy_child;
1235
1236                 while (cur->cy_next)
1237                         cur = cur->cy_next;
1238
1239                 cur->cy_next = node;
1240                 node->cy_prev = cur;
1241         }
1242 }
1243
1244 void cYAML_insert_sibling(struct cYAML *root, struct cYAML *sibling)
1245 {
1246         struct cYAML *last = NULL;
1247         if (root == NULL || sibling == NULL)
1248                 return;
1249
1250         last = root;
1251         while (last->cy_next != NULL)
1252                 last = last->cy_next;
1253
1254         last->cy_next = sibling;
1255 }
1256
1257 void cYAML_build_error(int rc, int seq_no, char *cmd,
1258                        char *entity, char *err_str,
1259                        struct cYAML **root)
1260 {
1261         struct cYAML *r = NULL, *err, *s, *itm = NULL, *cmd_obj;
1262         if (root == NULL)
1263                 return;
1264
1265         /* add to the tail of the root that's passed in */
1266         if ((*root) == NULL) {
1267                 *root = cYAML_create_object(NULL, NULL);
1268                 if ((*root) == NULL)
1269                         goto failed;
1270         }
1271
1272         r = *root;
1273
1274         /* look for the command */
1275         cmd_obj = cYAML_get_object_item(r, (const char *)cmd);
1276         if (cmd_obj != NULL && cmd_obj->cy_type == CYAML_TYPE_ARRAY)
1277                 itm = cYAML_create_seq_item(cmd_obj);
1278         else if (cmd_obj == NULL) {
1279                 s = cYAML_create_seq(r, cmd);
1280                 itm = cYAML_create_seq_item(s);
1281         } else if (cmd_obj != NULL && cmd_obj->cy_type != CYAML_TYPE_ARRAY) {
1282                 goto failed;
1283         }
1284
1285         err = cYAML_create_object(itm, entity);
1286         if (err == NULL)
1287                 goto failed;
1288
1289         if (seq_no >= 0 &&
1290             cYAML_create_number(err, "seq_no", seq_no) == NULL)
1291                 goto failed;
1292
1293         if (cYAML_create_number(err, "errno", rc) == NULL)
1294                 goto failed;
1295
1296         if (cYAML_create_string(err, "descr", err_str) == NULL)
1297                 goto failed;
1298
1299         return;
1300
1301 failed:
1302         /* Only reason we get here is if we run out of memory */
1303         cYAML_free_tree(r);
1304         r = NULL;
1305         fprintf(stderr, "error:\n\tfatal: out of memory\n");
1306 }
1307
1308 static struct cYAML *
1309 cYAML_parser_to_tree(yaml_parser_t *parser, struct cYAML **err_rc, bool debug)
1310 {
1311         yaml_token_t token;
1312         struct cYAML_tree_node tree;
1313         enum cYAML_handler_error rc;
1314         yaml_token_type_t token_type;
1315         char err_str[256];
1316         int done = 0;
1317
1318         memset(&tree, 0, sizeof(struct cYAML_tree_node));
1319
1320         INIT_LIST_HEAD(&tree.ll);
1321
1322         /* Read the event sequence. */
1323         while (!done) {
1324                 /*
1325                  * Go through the parser and build a cYAML representation
1326                  * of the passed in YAML text
1327                  */
1328                 yaml_parser_scan(parser, &token);
1329
1330                 if (debug)
1331                         fprintf(stderr, "tree.state(%p:%d) = %s, token.type ="
1332                                         " %s: %s\n",
1333                                 &tree, tree.state, state_string[tree.state],
1334                                 token_type_string[token.type],
1335                                 (token.type == YAML_SCALAR_TOKEN) ?
1336                                 (char*)token.data.scalar.value : "");
1337                 rc = dispatch_tbl[token.type](&token, &tree);
1338                 if (rc != CYAML_ERROR_NONE) {
1339                         snprintf(err_str, sizeof(err_str),
1340                                 "Failed to handle token:%d %s [state=%d, rc=%d]",
1341                                  token.type, token_type_string[token.type],
1342                                  tree.state, rc);
1343                         cYAML_build_error(-1, -1, "yaml", "builder",
1344                                           err_str,
1345                                           err_rc);
1346                 }
1347                 /* Are we finished? */
1348                 done = (rc != CYAML_ERROR_NONE ||
1349                         token.type == YAML_STREAM_END_TOKEN);
1350
1351                 token_type = token.type;
1352
1353                 yaml_token_delete(&token);
1354         }
1355
1356         if (token_type == YAML_STREAM_END_TOKEN &&
1357             rc == CYAML_ERROR_NONE)
1358                 return tree.root;
1359
1360         cYAML_free_tree(tree.root);
1361
1362         return NULL;
1363 }
1364
1365 struct cYAML *cYAML_load(FILE *file, struct cYAML **err_rc, bool debug)
1366 {
1367         yaml_parser_t parser;
1368         struct cYAML *yaml;
1369
1370         yaml_parser_initialize(&parser);
1371         yaml_parser_set_input_file(&parser, file);
1372
1373         yaml = cYAML_parser_to_tree(&parser, err_rc, debug);
1374
1375         yaml_parser_delete(&parser);
1376
1377         return yaml;
1378 }
1379
1380 struct cYAML *cYAML_build_tree(char *path,
1381                                const char *yaml_blk,
1382                                size_t yaml_blk_size,
1383                                struct cYAML **err_rc,
1384                                bool debug)
1385 {
1386         yaml_parser_t parser;
1387         struct cYAML *yaml = NULL;
1388         char err_str[256];
1389         FILE *input = NULL;
1390
1391         /* Create the Parser object. */
1392         if (yaml_parser_initialize(&parser) == 0)
1393                 goto out_init;
1394
1395         /* file always takes precedence */
1396         if (path != NULL) {
1397                 /* Set a file input. */
1398                 input = fopen(path, "rb");
1399                 if (input == NULL) {
1400                         snprintf(err_str, sizeof(err_str),
1401                                 "cannot open '%s': %s", path, strerror(errno));
1402                         cYAML_build_error(-1, -1, "yaml", "builder",
1403                                           err_str,
1404                                           err_rc);
1405                         return NULL;
1406                 }
1407
1408                 yaml_parser_set_input_file(&parser, input);
1409         } else if (yaml_blk != NULL) {
1410                 yaml_parser_set_input_string(&parser,
1411                                              (const unsigned char *) yaml_blk,
1412                                              yaml_blk_size);
1413         } else {
1414                 /* assume that we're getting our input froms stdin */
1415                 yaml_parser_set_input_file(&parser, stdin);
1416         }
1417
1418         yaml = cYAML_parser_to_tree(&parser, err_rc, debug);
1419
1420         /* Destroy the Parser object. */
1421         yaml_parser_delete(&parser);
1422
1423         if (input != NULL)
1424                 fclose(input);
1425 out_init:
1426         return yaml;
1427 }