Whamcloud - gitweb
LU-14359 hsm: support a flatter HSM archive format
[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_entry(list->next, 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 (*num == '-') {
352                 sign = -1;
353                 num++;
354         }
355
356         if (*num == '0')
357                 num++;
358
359         if (*num >= '1' && *num <= '9') {
360                 do {
361                         n = (n * 10.0) + (*num++ - '0');
362                 } while (*num >= '0' && *num <= '9');
363         }
364
365         if (*num == '.' && num[1] >= '0' && num[1] <= '9') {
366                 num++;
367                 do {
368                         n = (n * 10.0) + (*num++ - '0');
369                         scale--;
370                 } while (*num >= '0' && *num <= '9');
371         }
372
373         if (*num == 'e' || *num == 'E') {
374                 num++;
375                 if (*num == '+') {
376                         num++;
377                 } else if (*num == '-') {
378                         signsubscale = -1;
379                         num++;
380                 }
381                 while (*num >= '0' && *num <= '9')
382                         subscale = (subscale * 10) + (*num++ - '0');
383         }
384
385         /* check to see if the entire string is consumed.  If not then
386          * that means this is a string with a number in it */
387         if (num != (input + strlen(input)))
388                 return false;
389
390         /* number = +/- number.fraction * 10^+/- exponent */
391         n = sign * n * pow(10.0, (scale + subscale * signsubscale));
392
393         item->cy_valuedouble = n;
394         item->cy_valueint = (int)n;
395         item->cy_type = CYAML_TYPE_NUMBER;
396
397         return true;
398 }
399
400 static int assign_type_value(struct cYAML *obj, const char *value)
401 {
402         if (value == NULL)
403                 return -1;
404
405         if (strcmp(value, "null") == 0)
406                 obj->cy_type = CYAML_TYPE_NULL;
407         else if (strcmp(value, "false") == 0) {
408                 obj->cy_type = CYAML_TYPE_FALSE;
409                 obj->cy_valueint = 0;
410         } else if (strcmp(value, "true") == 0) {
411                 obj->cy_type = CYAML_TYPE_TRUE;
412                 obj->cy_valueint = 1;
413         } else if (*value == '-' || (*value >= '0' && *value <= '9')) {
414                 if (parse_number(obj, value) == 0) {
415                         obj->cy_valuestring = strdup(value);
416                         obj->cy_type = CYAML_TYPE_STRING;
417                 }
418         } else {
419                 obj->cy_valuestring = strdup(value);
420                 obj->cy_type = CYAML_TYPE_STRING;
421         }
422
423         return 0;
424 }
425
426 /*
427  * yaml_handle_token
428  *  Builds the YAML tree rpresentation as the tokens are passed in
429  *
430  *  if token == STREAM_START && tree_state != COMPLETE
431  *    something wrong. fail.
432  *  else tree_state = INITIED
433  *  if token == DOCUMENT_START && tree_state != COMPLETE || INITED
434  *    something wrong, fail.
435  *  else tree_state = TREE_STARTED
436  *  if token == DOCUMENT_END
437  *    tree_state = INITED if no STREAM START, else tree_state = COMPLETE
438  *    erase everything on ll
439  *  if token == STREAM_END && tree_state != INITED
440  *    something wrong fail.
441  *  else tree_state = COMPLETED
442  *  if token == YAML_KEY_TOKEN && state != TREE_STARTED
443  *    something wrong, fail.
444  *  if token == YAML_SCALAR_TOKEN && state != KEY || VALUE
445  *    fail.
446  *  else if tree_state == KEY
447  *     create a new sibling under the current head of the ll (if ll is
448  *     empty insert the new node there and it becomes the root.)
449  *    add the scalar value in the "string"
450  *    tree_state = KEY_FILLED
451  *  else if tree_state == VALUE
452  *    try and figure out whether this is a double, int or string and store
453  *    it appropriately
454  *    state = TREE_STARTED
455  * else if token == YAML_BLOCK_MAPPING_START_TOKEN && tree_state != VALUE
456  *   fail
457  * else push the current node on the ll && state = TREE_STARTED
458  * if token == YAML_BLOCK_END_TOKEN && state != TREE_STARTED
459  *   fail.
460  * else pop the current token off the ll and make it the cur
461  * if token == YAML_VALUE_TOKEN && state != KEY_FILLED
462  *   fail.
463  * else state = VALUE
464  *
465  */
466
467 static enum cYAML_handler_error yaml_no_token(yaml_token_t *token,
468                                               struct cYAML_tree_node *tree)
469 {
470         return CYAML_ERROR_NONE;
471 }
472
473 static enum cYAML_handler_error yaml_stream_start(yaml_token_t *token,
474                                                   struct cYAML_tree_node *tree)
475 {
476         enum cYAML_handler_error rc;
477
478         /* with each new stream initialize a new tree */
479         rc = cYAML_tree_init(tree);
480
481         if (rc != CYAML_ERROR_NONE)
482                 return rc;
483
484         tree->state = TREE_STATE_INITED;
485
486         return CYAML_ERROR_NONE;
487 }
488
489 static enum cYAML_handler_error yaml_stream_end(yaml_token_t *token,
490                                                 struct cYAML_tree_node *tree)
491 {
492         if (tree->state != TREE_STATE_TREE_STARTED &&
493             tree->state != TREE_STATE_COMPLETE &&
494             tree->state != TREE_STATE_INITED)
495                 return CYAML_ERROR_UNEXPECTED_STATE;
496
497         tree->state = TREE_STATE_INITED;
498
499         return CYAML_ERROR_NONE;
500 }
501
502 static enum cYAML_handler_error
503 yaml_document_start(yaml_token_t *token, struct cYAML_tree_node *tree)
504 {
505         if (tree->state != TREE_STATE_INITED)
506                 return CYAML_ERROR_UNEXPECTED_STATE;
507
508         /* go to started state since we're expecting more tokens to come */
509         tree->state = TREE_STATE_TREE_STARTED;
510
511         return CYAML_ERROR_NONE;
512 }
513
514 static enum cYAML_handler_error yaml_document_end(yaml_token_t *token,
515                                                   struct cYAML_tree_node *tree)
516 {
517         if (tree->state != TREE_STATE_COMPLETE)
518                 return CYAML_ERROR_UNEXPECTED_STATE;
519
520         tree->state = TREE_STATE_TREE_STARTED;
521
522         return CYAML_ERROR_NONE;
523 }
524
525 static enum cYAML_handler_error yaml_key(yaml_token_t *token,
526                                          struct cYAML_tree_node *tree)
527 {
528         if (tree->state != TREE_STATE_BLK_STARTED &&
529             tree->state != TREE_STATE_VALUE)
530                 return CYAML_ERROR_UNEXPECTED_STATE;
531
532         if (tree->from_blk_map_start == 0 ||
533             tree->state == TREE_STATE_VALUE)
534                 tree->cur = create_sibling(tree->cur);
535
536         tree->from_blk_map_start = 0;
537
538         tree->state = TREE_STATE_KEY;
539
540         return CYAML_ERROR_NONE;
541 }
542
543 static enum cYAML_handler_error yaml_scalar(yaml_token_t *token,
544                                             struct cYAML_tree_node *tree)
545 {
546         if (tree->state == TREE_STATE_KEY) {
547                 /* assign the scalar value to the key that was created */
548                 tree->cur->cy_string =
549                   strdup((const char *)token->data.scalar.value);
550
551                 tree->state = TREE_STATE_KEY_FILLED;
552         } else if (tree->state == TREE_STATE_VALUE ||
553                    tree->state == TREE_STATE_SEQ_START) {
554                 if (assign_type_value(tree->cur,
555                                       (char *)token->data.scalar.value))
556                         /* failed to assign a value */
557                         return CYAML_ERROR_BAD_VALUE;
558                 tree->state = TREE_STATE_BLK_STARTED;
559         } else {
560                 return CYAML_ERROR_UNEXPECTED_STATE;
561         }
562
563         return CYAML_ERROR_NONE;
564 }
565
566 static enum cYAML_handler_error yaml_value(yaml_token_t *token,
567                                            struct cYAML_tree_node *tree)
568 {
569         if (tree->state != TREE_STATE_KEY_FILLED)
570                 return CYAML_ERROR_UNEXPECTED_STATE;
571
572         tree->state = TREE_STATE_VALUE;
573
574         return CYAML_ERROR_NONE;
575 }
576
577 static enum cYAML_handler_error yaml_blk_seq_start(yaml_token_t *token,
578                                                    struct cYAML_tree_node *tree)
579 {
580         if (tree->state != TREE_STATE_VALUE)
581                 return CYAML_ERROR_UNEXPECTED_STATE;
582
583         /* Since a sequenc start event determines that this is the start
584          * of an array, then that means the current node we're at is an
585          * array and we need to flag it as such */
586         tree->cur->cy_type = CYAML_TYPE_ARRAY;
587         tree->state = TREE_STATE_SEQ_START;
588
589         return CYAML_ERROR_NONE;
590 }
591
592 static enum cYAML_handler_error yaml_entry_token(yaml_token_t *token,
593                                                  struct cYAML_tree_node *tree)
594 {
595         struct cYAML *obj;
596
597         if (tree->state != TREE_STATE_SEQ_START &&
598             tree->state != TREE_STATE_BLK_STARTED &&
599             tree->state != TREE_STATE_VALUE)
600                 return CYAML_ERROR_UNEXPECTED_STATE;
601
602         if (tree->state == TREE_STATE_SEQ_START) {
603                 obj = create_child(tree->cur);
604
605                 if (cYAML_ll_push(tree->cur, NULL, &tree->ll))
606                         return CYAML_ERROR_OUT_OF_MEM;
607
608                 tree->cur = obj;
609         } else {
610                 tree->cur = create_sibling(tree->cur);
611                 tree->state = TREE_STATE_SEQ_START;
612         }
613
614         return CYAML_ERROR_NONE;
615 }
616
617 static enum cYAML_handler_error
618 yaml_blk_mapping_start(yaml_token_t *token,
619                        struct cYAML_tree_node *tree)
620 {
621         struct cYAML *obj;
622
623         if (tree->state != TREE_STATE_VALUE &&
624             tree->state != TREE_STATE_INITED &&
625             tree->state != TREE_STATE_SEQ_START &&
626             tree->state != TREE_STATE_TREE_STARTED)
627                 return CYAML_ERROR_UNEXPECTED_STATE;
628
629         /* block_mapping_start means we're entering another block
630          * indentation, so we need to go one level deeper
631          * create a child of cur */
632         obj = create_child(tree->cur);
633
634         /* push cur on the stack */
635         if (cYAML_ll_push(tree->cur, NULL, &tree->ll))
636                 return CYAML_ERROR_OUT_OF_MEM;
637
638         /* adding the new child to cur */
639         tree->cur = obj;
640
641         tree->state = TREE_STATE_BLK_STARTED;
642
643         tree->from_blk_map_start = 1;
644
645         return CYAML_ERROR_NONE;
646 }
647
648 static enum cYAML_handler_error yaml_block_end(yaml_token_t *token,
649                                                struct cYAML_tree_node *tree)
650 {
651         if (tree->state != TREE_STATE_BLK_STARTED &&
652             tree->state != TREE_STATE_VALUE)
653                 return CYAML_ERROR_UNEXPECTED_STATE;
654
655         tree->cur = cYAML_ll_pop(&tree->ll, NULL);
656
657         /* if you have popped all the way to the top level, then move to
658          * the complete state. */
659         if (cYAML_ll_count(&tree->ll) == 0)
660                 tree->state = TREE_STATE_COMPLETE;
661         else if (tree->state == TREE_STATE_VALUE)
662                 tree->state = TREE_STATE_BLK_STARTED;
663
664         return CYAML_ERROR_NONE;
665 }
666
667 static enum cYAML_handler_error yaml_not_supported(yaml_token_t *token,
668                                                    struct cYAML_tree_node *tree)
669 {
670         return CYAML_ERROR_NOT_SUPPORTED;
671 }
672
673 static bool clean_usr_data(struct cYAML *node, void *usr_data, void **out)
674 {
675         cYAML_user_data_free_cb free_cb = usr_data;
676
677         if (free_cb && node && node->cy_user_data) {
678                 free_cb(node->cy_user_data);
679                 node->cy_user_data = NULL;
680         }
681
682         return true;
683 }
684
685 static bool free_node(struct cYAML *node, void *user_data, void **out)
686 {
687         if (!node)
688                 return true;
689
690         if (node->cy_type == CYAML_TYPE_STRING)
691                 free(node->cy_valuestring);
692         if (node->cy_string)
693                 free(node->cy_string);
694
695         free(node);
696         return true;
697 }
698
699 static bool find_obj_iter(struct cYAML *node, void *usr_data, void **out)
700 {
701         char *name = usr_data;
702
703         if (node != NULL && node->cy_string != NULL &&
704             strcmp(node->cy_string, name) == 0) {
705                 *out = node;
706                 return false;
707         }
708
709         return true;
710 }
711
712 struct cYAML *cYAML_get_object_item(struct cYAML *parent, const char *name)
713 {
714         struct cYAML *node = parent, *found = NULL;
715
716         if (!node || !name)
717                 return NULL;
718
719         if (node->cy_string) {
720                 if (strcmp(node->cy_string, name) == 0)
721                         return node;
722         }
723
724         if (node->cy_child)
725                 found = cYAML_get_object_item(node->cy_child, name);
726
727         if (!found && node->cy_next)
728                 found = cYAML_get_object_item(node->cy_next, name);
729
730         return found;
731 }
732
733 struct cYAML *cYAML_get_next_seq_item(struct cYAML *seq, struct cYAML **itm)
734 {
735         if (*itm != NULL && (*itm)->cy_next != NULL) {
736                 *itm = (*itm)->cy_next;
737                 return *itm;
738         }
739
740         if (*itm == NULL && seq->cy_type == CYAML_TYPE_ARRAY) {
741                 *itm = seq->cy_child;
742                 return *itm;
743         }
744
745         return NULL;
746 }
747
748 bool cYAML_is_sequence(struct cYAML *node)
749 {
750         return (node != NULL ? node->cy_type == CYAML_TYPE_ARRAY : 0);
751 }
752
753 void cYAML_tree_recursive_walk(struct cYAML *node, cYAML_walk_cb cb,
754                                       bool cb_first,
755                                       void *usr_data,
756                                       void **out)
757 {
758         if (node == NULL)
759                 return;
760
761         if (cb_first) {
762                 if (!cb(node, usr_data, out))
763                         return;
764         }
765
766         if (node->cy_child)
767                 cYAML_tree_recursive_walk(node->cy_child, cb,
768                                           cb_first, usr_data, out);
769
770         if (node->cy_next)
771                 cYAML_tree_recursive_walk(node->cy_next, cb,
772                                           cb_first, usr_data, out);
773
774         if (!cb_first) {
775                 if (!cb(node, usr_data, out))
776                         return;
777         }
778 }
779
780 struct cYAML *cYAML_find_object(struct cYAML *root, const char *name)
781 {
782         struct cYAML *found = NULL;
783
784         cYAML_tree_recursive_walk(root, find_obj_iter, true,
785                                   (void *)name, (void **)&found);
786
787         return found;
788 }
789
790 void cYAML_clean_usr_data(struct cYAML *node, cYAML_user_data_free_cb free_cb)
791 {
792         cYAML_tree_recursive_walk(node, clean_usr_data, false, free_cb, NULL);
793 }
794
795 void cYAML_free_tree(struct cYAML *node)
796 {
797         cYAML_tree_recursive_walk(node, free_node, false, NULL, NULL);
798 }
799
800 static char *ensure(char *in, int len)
801 {
802         int curlen;
803         char *new = in;
804
805         if (!in)
806                 return (char*)calloc(len, 1);
807
808         curlen = strlen(in) + 1;
809
810         if (curlen <= curlen + len) {
811                 new = calloc(curlen + len, 1);
812                 if (!new) {
813                         free(in);
814                         return NULL;
815                 }
816                 strcpy(new, in);
817                 free(in);
818         }
819
820         return new;
821 }
822
823 static inline void print_simple(char **out, struct cYAML *node,
824                                 struct cYAML_print_info *cpi)
825 {
826         int level = cpi->level;
827         int ind = cpi->extra_ind;
828         char *tmp = NULL;
829         int len = (INDENT * level + ind) * 2 +
830           ((node->cy_string) ? strlen(node->cy_string) : 0) + LEAD_ROOM;
831
832         *out = ensure(*out, len);
833         if (!*out)
834                 return;
835
836         tmp = ensure(tmp, len);
837         if (!tmp)
838                 return;
839
840         if (cpi->array_first_elem) {
841                 sprintf(tmp, "%*s- ", INDENT * level, "");
842                 strcat(*out, tmp);
843         }
844
845         sprintf(tmp, "%*s""%s: %" PRId64 "\n", (cpi->array_first_elem) ? 0 :
846                 INDENT * level + ind, "", node->cy_string,
847                 node->cy_valueint);
848         strcat(*out, tmp);
849         free(tmp);
850 }
851
852 static void print_string(char **out, struct cYAML *node,
853                          struct cYAML_print_info *cpi)
854 {
855         char *new_line;
856         int level = cpi->level;
857         int ind = cpi->extra_ind;
858         char *tmp = NULL;
859         int len = INDENT * level + ind +
860           ((node->cy_valuestring) ? strlen(node->cy_valuestring) : 0) +
861           ((node->cy_string) ? strlen(node->cy_string) : 0) + LEAD_ROOM;
862
863         *out = ensure(*out, len);
864         if (!*out)
865                 return;
866
867         tmp = ensure(tmp, len);
868         if (!tmp)
869                 return;
870
871         if (cpi->array_first_elem) {
872                 sprintf(tmp, "%*s- ", INDENT * level, "");
873                 strcat(*out, tmp);
874         }
875
876         new_line = strchr(node->cy_valuestring, '\n');
877         if (new_line == NULL) {
878                 sprintf(tmp, "%*s""%s: %s\n", (cpi->array_first_elem) ?
879                         0 : INDENT * level + ind, "",
880                         node->cy_string, node->cy_valuestring);
881                 strcat(*out, tmp);
882         } else {
883                 int indent = 0;
884                 sprintf(tmp, "%*s""%s: ", (cpi->array_first_elem) ?
885                         0 : INDENT * level + ind, "",
886                         node->cy_string);
887                 strcat(*out, tmp);
888                 char *l = node->cy_valuestring;
889                 while (new_line) {
890                         *new_line = '\0';
891                         sprintf(tmp, "%*s""%s\n", indent, "", l);
892                         strcat(*out, tmp);
893                         indent = INDENT * level + ind +
894                                   strlen(node->cy_string) + 2;
895                         *new_line = '\n';
896                         l = new_line+1;
897                         new_line = strchr(l, '\n');
898                 }
899                 sprintf(tmp, "%*s""%s\n", indent, "", l);
900                 strcat(*out, tmp);
901         }
902
903         free(tmp);
904 }
905
906 static void print_number(char **out, struct cYAML *node,
907                          struct cYAML_print_info *cpi)
908 {
909         double d = node->cy_valuedouble;
910         int level = cpi->level;
911         int ind = cpi->extra_ind;
912         char *tmp = NULL;
913         int len = INDENT * level + ind + LEAD_ROOM;
914
915         *out = ensure(*out, len);
916         if (!*out)
917                 return;
918
919         tmp = ensure(tmp, len);
920         if (!tmp)
921                 return;
922
923         if (cpi->array_first_elem) {
924                 sprintf(tmp, "%*s- ", INDENT * level, "");
925                 strcat(*out, tmp);
926         }
927
928         if ((fabs(((double)node->cy_valueint) - d) <= DBL_EPSILON) &&
929             (d <= INT_MAX) && (d >= INT_MIN)) {
930                 sprintf(tmp, "%*s""%s: %" PRId64 "\n", (cpi->array_first_elem) ? 0 :
931                         INDENT * level + ind, "",
932                         node->cy_string, node->cy_valueint);
933                 strcat(*out, tmp);
934         } else {
935                 if ((fabs(floor(d) - d) <= DBL_EPSILON) &&
936                     (fabs(d) < 1.0e60)) {
937                         sprintf(tmp, "%*s""%s: %.0f\n",
938                                 (cpi->array_first_elem) ? 0 :
939                                 INDENT * level + ind, "",
940                                 node->cy_string, d);
941                         strcat(*out, tmp);
942                 } else if ((fabs(d) < 1.0e-6) || (fabs(d) > 1.0e9)) {
943                         sprintf(tmp, "%*s""%s: %e\n",
944                                 (cpi->array_first_elem) ? 0 :
945                                 INDENT * level + ind, "",
946                                 node->cy_string, d);
947                         strcat(*out, tmp);
948                 } else {
949                         sprintf(tmp, "%*s""%s: %f\n",
950                                 (cpi->array_first_elem) ? 0 :
951                                 INDENT * level + ind, "",
952                                 node->cy_string, d);
953                         strcat(*out, tmp);
954                 }
955         }
956
957         free(tmp);
958 }
959
960 static void print_object(char **out, struct cYAML *node,
961                          struct list_head *stack,
962                          struct cYAML_print_info *cpi)
963 {
964         struct cYAML_print_info print_info;
965         struct cYAML *child = node->cy_child;
966         char *tmp = NULL;
967         int len = ((cpi->array_first_elem) ? INDENT * cpi->level :
968           INDENT * cpi->level + cpi->extra_ind) +
969           ((node->cy_string) ? strlen(node->cy_string) : 0) +
970           LEAD_ROOM;
971
972         *out = ensure(*out, len);
973         if (!*out)
974                 return;
975
976         tmp = ensure(tmp, len);
977         if (!tmp)
978                 return;
979
980         if (node->cy_string != NULL) {
981                 sprintf(tmp, "%*s""%s%s:\n", (cpi->array_first_elem) ?
982                         INDENT * cpi->level :
983                         INDENT * cpi->level + cpi->extra_ind,
984                         "", (cpi->array_first_elem) ? "- " : "",
985                         node->cy_string);
986                 strcat(*out, tmp);
987         }
988
989         print_info.level = (node->cy_string != NULL) ? cpi->level + 1 :
990           cpi->level;
991         print_info.array_first_elem = (node->cy_string == NULL) ?
992           cpi->array_first_elem : 0;
993         print_info.extra_ind = (cpi->array_first_elem) ? EXTRA_IND :
994           cpi->extra_ind;
995
996         while (child) {
997                 if (cYAML_ll_push(child, &print_info, stack) != 0) {
998                         free(tmp);
999                         return;
1000                 }
1001                 print_value(out, stack);
1002                 print_info.array_first_elem = 0;
1003                 child = child->cy_next;
1004         }
1005
1006         free(tmp);
1007 }
1008
1009 static void print_array(char **out, struct cYAML *node,
1010                         struct list_head *stack,
1011                         struct cYAML_print_info *cpi)
1012 {
1013         struct cYAML_print_info print_info;
1014         struct cYAML *child = node->cy_child;
1015         char *tmp = NULL;
1016         int len = ((node->cy_string) ? strlen(node->cy_string) : 0) +
1017           INDENT * cpi->level + cpi->extra_ind + LEAD_ROOM;
1018
1019         *out = ensure(*out, len);
1020         if (!*out)
1021                 return;
1022
1023         tmp = ensure(tmp, len);
1024         if (!tmp)
1025                 return;
1026
1027         if (node->cy_string != NULL) {
1028                 sprintf(tmp, "%*s""%s:\n", INDENT * cpi->level + cpi->extra_ind,
1029                         "", node->cy_string);
1030                 strcat(*out, tmp);
1031         }
1032
1033         print_info.level = (node->cy_string != NULL) ? cpi->level + 1 :
1034           cpi->level;
1035         print_info.array_first_elem =  1;
1036         print_info.extra_ind = EXTRA_IND;
1037
1038         while (child) {
1039                 if (cYAML_ll_push(child, &print_info, stack) != 0) {
1040                         free(tmp);
1041                         return;
1042                 }
1043                 print_value(out, stack);
1044                 child = child->cy_next;
1045         }
1046
1047         free(tmp);
1048 }
1049
1050 static void print_value(char **out, struct list_head *stack)
1051 {
1052         struct cYAML_print_info *cpi = NULL;
1053         struct cYAML *node = cYAML_ll_pop(stack, &cpi);
1054
1055         if (node == NULL)
1056                 return;
1057
1058         switch (node->cy_type) {
1059         case CYAML_TYPE_FALSE:
1060         case CYAML_TYPE_TRUE:
1061         case CYAML_TYPE_NULL:
1062                 print_simple(out, node, cpi);
1063                 break;
1064         case CYAML_TYPE_STRING:
1065                 print_string(out, node, cpi);
1066                 break;
1067         case CYAML_TYPE_NUMBER:
1068                 print_number(out, node, cpi);
1069                 break;
1070         case CYAML_TYPE_ARRAY:
1071                 print_array(out, node, stack, cpi);
1072                 break;
1073         case CYAML_TYPE_OBJECT:
1074                 print_object(out, node, stack, cpi);
1075                 break;
1076         default:
1077         break;
1078         }
1079
1080         if (cpi != NULL)
1081                 free(cpi);
1082 }
1083
1084 void cYAML_dump(struct cYAML *node, char **buf)
1085 {
1086         struct cYAML_print_info print_info;
1087         struct list_head list;
1088
1089         *buf = ensure(NULL, PRINT_BUF_LEN);
1090
1091         if (!*buf)
1092                 return;
1093
1094         INIT_LIST_HEAD(&list);
1095
1096         if (node == NULL) {
1097                 *buf = NULL;
1098                 return;
1099         }
1100
1101         memset(&print_info, 0, sizeof(struct cYAML_print_info));
1102
1103         if (cYAML_ll_push(node, &print_info, &list) == 0)
1104                 print_value(buf, &list);
1105 }
1106
1107 void cYAML_print_tree(struct cYAML *node)
1108 {
1109         struct cYAML_print_info print_info;
1110         struct list_head list;
1111         char *buf = ensure(NULL, PRINT_BUF_LEN);
1112
1113         if (!buf)
1114                 return;
1115
1116         INIT_LIST_HEAD(&list);
1117
1118         if (node == NULL)
1119                 return;
1120
1121         memset(&print_info, 0, sizeof(struct cYAML_print_info));
1122
1123         if (cYAML_ll_push(node, &print_info, &list) == 0)
1124                 print_value(&buf, &list);
1125
1126         /* buf could've been freed if we ran out of memory */
1127         if (buf) {
1128                 printf("%s", buf);
1129                 free(buf);
1130         }
1131 }
1132
1133 void cYAML_print_tree2file(FILE *f, struct cYAML *node)
1134 {
1135         struct cYAML_print_info print_info;
1136         struct list_head list;
1137         char *buf = ensure(NULL, PRINT_BUF_LEN);
1138
1139         if (!buf)
1140                 return;
1141
1142         INIT_LIST_HEAD(&list);
1143
1144         if (node == NULL)
1145                 return;
1146
1147         memset(&print_info, 0, sizeof(struct cYAML_print_info));
1148
1149         if (cYAML_ll_push(node, &print_info, &list) == 0)
1150                 print_value(&buf, &list);
1151
1152         /* buf could've been freed if we ran out of memory */
1153         if (buf) {
1154                 fprintf(f, "%s", buf);
1155                 free(buf);
1156         }
1157 }
1158
1159 static struct cYAML *insert_item(struct cYAML *parent, char *key,
1160                                  enum cYAML_object_type type)
1161 {
1162         struct cYAML *node = calloc(1, sizeof(*node));
1163
1164         if (node == NULL)
1165                 return NULL;
1166
1167         if (key != NULL)
1168                 node->cy_string = strdup(key);
1169
1170         node->cy_type = type;
1171
1172         cYAML_insert_child(parent, node);
1173
1174         return node;
1175 }
1176
1177 struct cYAML *cYAML_create_seq(struct cYAML *parent, char *key)
1178 {
1179         return insert_item(parent, key, CYAML_TYPE_ARRAY);
1180 }
1181
1182 struct cYAML *cYAML_create_seq_item(struct cYAML *seq)
1183 {
1184         return insert_item(seq, NULL, CYAML_TYPE_OBJECT);
1185 }
1186
1187 struct cYAML *cYAML_create_object(struct cYAML *parent, char *key)
1188 {
1189         return insert_item(parent, key, CYAML_TYPE_OBJECT);
1190 }
1191
1192 struct cYAML *cYAML_create_string(struct cYAML *parent, char *key, char *value)
1193 {
1194         struct cYAML *node = calloc(1, sizeof(*node));
1195         if (node == NULL)
1196                 return NULL;
1197
1198         node->cy_string = strdup(key);
1199         node->cy_valuestring = strdup(value);
1200         node->cy_type = CYAML_TYPE_STRING;
1201
1202         cYAML_insert_child(parent, node);
1203
1204         return node;
1205 }
1206
1207 struct cYAML *cYAML_create_number(struct cYAML *parent, char *key, double value)
1208 {
1209         struct cYAML *node = calloc(1, sizeof(*node));
1210         if (node == NULL)
1211                 return NULL;
1212
1213         node->cy_string = strdup(key);
1214         node->cy_valuedouble = value;
1215         node->cy_valueint = (int)value;
1216         node->cy_type = CYAML_TYPE_NUMBER;
1217
1218         cYAML_insert_child(parent, node);
1219
1220         return node;
1221 }
1222
1223 void cYAML_insert_child(struct cYAML *parent, struct cYAML *node)
1224 {
1225         struct cYAML *cur;
1226
1227         if (parent && node) {
1228                 if (parent->cy_child == NULL) {
1229                         parent->cy_child = node;
1230                         return;
1231                 }
1232
1233                 cur = parent->cy_child;
1234
1235                 while (cur->cy_next)
1236                         cur = cur->cy_next;
1237
1238                 cur->cy_next = node;
1239                 node->cy_prev = cur;
1240         }
1241 }
1242
1243 void cYAML_insert_sibling(struct cYAML *root, struct cYAML *sibling)
1244 {
1245         struct cYAML *last = NULL;
1246         if (root == NULL || sibling == NULL)
1247                 return;
1248
1249         last = root;
1250         while (last->cy_next != NULL)
1251                 last = last->cy_next;
1252
1253         last->cy_next = sibling;
1254 }
1255
1256 void cYAML_build_error(int rc, int seq_no, char *cmd,
1257                        char *entity, char *err_str,
1258                        struct cYAML **root)
1259 {
1260         struct cYAML *r = NULL, *err, *s, *itm, *cmd_obj;
1261         if (root == NULL)
1262                 return;
1263
1264         /* add to the tail of the root that's passed in */
1265         if ((*root) == NULL) {
1266                 *root = cYAML_create_object(NULL, NULL);
1267                 if ((*root) == NULL)
1268                         goto failed;
1269         }
1270
1271         r = *root;
1272
1273         /* look for the command */
1274         cmd_obj = cYAML_get_object_item(r, (const char *)cmd);
1275         if (cmd_obj != NULL && cmd_obj->cy_type == CYAML_TYPE_ARRAY)
1276                 itm = cYAML_create_seq_item(cmd_obj);
1277         else if (cmd_obj == NULL) {
1278                 s = cYAML_create_seq(r, cmd);
1279                 itm = cYAML_create_seq_item(s);
1280         } else if (cmd_obj != NULL && cmd_obj->cy_type != CYAML_TYPE_ARRAY)
1281                 goto failed;
1282
1283         err = cYAML_create_object(itm, entity);
1284         if (err == NULL)
1285                 goto failed;
1286
1287         if (seq_no >= 0 &&
1288             cYAML_create_number(err, "seq_no", seq_no) == NULL)
1289                 goto failed;
1290
1291         if (cYAML_create_number(err, "errno", rc) == NULL)
1292                 goto failed;
1293
1294         if (cYAML_create_string(err, "descr", err_str) == NULL)
1295                 goto failed;
1296
1297         return;
1298
1299 failed:
1300         /* Only reason we get here is if we run out of memory */
1301         cYAML_free_tree(r);
1302         r = NULL;
1303         fprintf(stderr, "error:\n\tfatal: out of memory\n");
1304 }
1305
1306 static struct cYAML *
1307 cYAML_parser_to_tree(yaml_parser_t *parser, struct cYAML **err_rc, bool debug)
1308 {
1309         yaml_token_t token;
1310         struct cYAML_tree_node tree;
1311         enum cYAML_handler_error rc;
1312         yaml_token_type_t token_type;
1313         char err_str[256];
1314         int done = 0;
1315
1316         memset(&tree, 0, sizeof(struct cYAML_tree_node));
1317
1318         INIT_LIST_HEAD(&tree.ll);
1319
1320         /* Read the event sequence. */
1321         while (!done) {
1322                 /*
1323                  * Go through the parser and build a cYAML representation
1324                  * of the passed in YAML text
1325                  */
1326                 yaml_parser_scan(parser, &token);
1327
1328                 if (debug)
1329                         fprintf(stderr, "tree.state(%p:%d) = %s, token.type ="
1330                                         " %s: %s\n",
1331                                 &tree, tree.state, state_string[tree.state],
1332                                 token_type_string[token.type],
1333                                 (token.type == YAML_SCALAR_TOKEN) ?
1334                                 (char*)token.data.scalar.value : "");
1335                 rc = dispatch_tbl[token.type](&token, &tree);
1336                 if (rc != CYAML_ERROR_NONE) {
1337                         snprintf(err_str, sizeof(err_str),
1338                                 "Failed to handle token:%d %s [state=%d, rc=%d]",
1339                                  token.type, token_type_string[token.type],
1340                                  tree.state, rc);
1341                         cYAML_build_error(-1, -1, "yaml", "builder",
1342                                           err_str,
1343                                           err_rc);
1344                 }
1345                 /* Are we finished? */
1346                 done = (rc != CYAML_ERROR_NONE ||
1347                         token.type == YAML_STREAM_END_TOKEN);
1348
1349                 token_type = token.type;
1350
1351                 yaml_token_delete(&token);
1352         }
1353
1354         if (token_type == YAML_STREAM_END_TOKEN &&
1355             rc == CYAML_ERROR_NONE)
1356                 return tree.root;
1357
1358         cYAML_free_tree(tree.root);
1359
1360         return NULL;
1361 }
1362
1363 struct cYAML *cYAML_load(FILE *file, struct cYAML **err_rc, bool debug)
1364 {
1365         yaml_parser_t parser;
1366         struct cYAML *yaml;
1367
1368         yaml_parser_initialize(&parser);
1369         yaml_parser_set_input_file(&parser, file);
1370
1371         yaml = cYAML_parser_to_tree(&parser, err_rc, debug);
1372
1373         yaml_parser_delete(&parser);
1374
1375         return yaml;
1376 }
1377
1378 struct cYAML *cYAML_build_tree(char *path,
1379                                const char *yaml_blk,
1380                                size_t yaml_blk_size,
1381                                struct cYAML **err_rc,
1382                                bool debug)
1383 {
1384         yaml_parser_t parser;
1385         struct cYAML *yaml;
1386         char err_str[256];
1387         FILE *input = NULL;
1388
1389         /* Create the Parser object. */
1390         yaml_parser_initialize(&parser);
1391
1392         /* file always takes precedence */
1393         if (path != NULL) {
1394                 /* Set a file input. */
1395                 input = fopen(path, "rb");
1396                 if (input == NULL) {
1397                         snprintf(err_str, sizeof(err_str),
1398                                 "cannot open '%s': %s", path, strerror(errno));
1399                         cYAML_build_error(-1, -1, "yaml", "builder",
1400                                           err_str,
1401                                           err_rc);
1402                         return NULL;
1403                 }
1404
1405                 yaml_parser_set_input_file(&parser, input);
1406         } else if (yaml_blk != NULL) {
1407                 yaml_parser_set_input_string(&parser,
1408                                              (const unsigned char *) yaml_blk,
1409                                              yaml_blk_size);
1410         } else {
1411                 /* assume that we're getting our input froms stdin */
1412                 yaml_parser_set_input_file(&parser, stdin);
1413         }
1414
1415         yaml = cYAML_parser_to_tree(&parser, err_rc, debug);
1416
1417         /* Destroy the Parser object. */
1418         yaml_parser_delete(&parser);
1419
1420         if (input != NULL)
1421                 fclose(input);
1422
1423         return yaml;
1424 }