source: libyaml/trunk/src/api.c @ 267

Revision 267, 70.7 KB checked in by xi, 6 years ago (diff)

Minor API updates.

Line 
1/*****************************************************************************
2 * LibYAML API Implementation
3 *
4 * Copyright (c) 2006 Kirill Simonov
5 *
6 * LibYAML is free software; you can use, modify and/or redistribute it under
7 * the terms of the MIT license; see the file LICENCE for more details.
8 *****************************************************************************/
9
10#include "yaml_private.h"
11
12/*****************************************************************************
13 * Version Information
14 *****************************************************************************/
15
16/*
17 * Get the library version as a static string.
18 */
19
20YAML_DECLARE(const char *)
21yaml_get_version_string(void)
22{
23    return YAML_VERSION_STRING;
24}
25
26/*
27 * Get the library version numbers.
28 */
29
30YAML_DECLARE(void)
31yaml_get_version(int *major, int *minor, int *patch)
32{
33    *major = YAML_VERSION_MAJOR;
34    *minor = YAML_VERSION_MINOR;
35    *patch = YAML_VERSION_PATCH;
36}
37
38/*****************************************************************************
39 * Memory Management
40 *****************************************************************************/
41
42/*
43 * Allocate a dynamic memory block.
44 */
45
46YAML_DECLARE(void *)
47yaml_malloc(size_t size)
48{
49    return malloc(size ? size : 1);
50}
51
52/*
53 * Reallocate a dynamic memory block.
54 */
55
56YAML_DECLARE(void *)
57yaml_realloc(void *ptr, size_t size)
58{
59    return ptr ? realloc(ptr, size ? size : 1) : malloc(size ? size : 1);
60}
61
62/*
63 * Free a dynamic memory block.
64 */
65
66YAML_DECLARE(void)
67yaml_free(void *ptr)
68{
69    if (ptr) free(ptr);
70}
71
72/*
73 * Duplicate a string.
74 */
75
76YAML_DECLARE(yaml_char_t *)
77yaml_strdup(const yaml_char_t *str)
78{
79    if (!str)
80        return NULL;
81
82    return (yaml_char_t *)strdup((char *)str);
83}
84
85/*****************************************************************************
86 * Error Handling
87 *****************************************************************************/
88
89/*
90 * Format an error message.
91 */
92
93YAML_DECLARE(int)
94yaml_error_message(yaml_error_t *error, char *buffer, size_t capacity)
95{
96    char *prefixes[] = {
97        "No error",
98        "Memory error",
99        "Reader error",
100        "Decoder error",
101        "Scanner error",
102        "Parser error",
103        "Composer error",
104        "Writer error",
105        "Emitter error",
106        "Serializer error",
107        "Resolver error",
108    };
109    int length;
110
111    assert(error);  /* Non-NULL error is expected. */
112    assert(buffer); /* Non-NULL buffer is expected. */
113
114    switch (error->type)
115    {
116        case YAML_NO_ERROR:
117        case YAML_MEMORY_ERROR:
118            length = snprintf(buffer, capacity, "%s",
119                    prefixes[error->type]);
120            break;
121
122        case YAML_READER_ERROR:
123        case YAML_DECODER_ERROR:
124            if (error->data.reading.value == -1) {
125                length = snprintf(buffer, capacity,
126                        "%s: %s at byte %d",
127                        prefixes[error->type],
128                        error->data.reading.problem,
129                        error->data.reading.offset);
130            }
131            else {
132                length = snprintf(buffer, capacity,
133                        "%s: %s (#%X) at byte %d",
134                        prefixes[error->type],
135                        error->data.reading.problem,
136                        error->data.reading.value,
137                        error->data.reading.offset);
138            }
139            break;
140
141        case YAML_SCANNER_ERROR:
142        case YAML_PARSER_ERROR:
143        case YAML_COMPOSER_ERROR:
144            if (!error->data.loading.context) {
145                length = snprintf(buffer, capacity,
146                        "%s: %s at line %d, column %d",
147                        prefixes[error->type],
148                        error->data.loading.problem,
149                        error->data.loading.problem_mark.line+1,
150                        error->data.loading.problem_mark.column+1);
151            }
152            else {
153                length = snprintf(buffer, capacity,
154                        "%s: %s at line %d, column %d, %s at line %d, column %d",
155                        prefixes[error->type],
156                        error->data.loading.context,
157                        error->data.loading.context_mark.line+1,
158                        error->data.loading.context_mark.column+1,
159                        error->data.loading.problem,
160                        error->data.loading.problem_mark.line+1,
161                        error->data.loading.problem_mark.column+1);
162            }
163            break;
164
165        case YAML_WRITER_ERROR:
166            length = snprintf(buffer, capacity,
167                    "%s: %s at byte %d",
168                    prefixes[error->type],
169                    error->data.writing.problem,
170                    error->data.writing.offset);
171            break;
172
173        case YAML_EMITTER_ERROR:
174        case YAML_SERIALIZER_ERROR:
175            length = snprintf(buffer, capacity, "%s: %s",
176                    prefixes[error->type],
177                    error->data.dumping.problem);
178            break;
179
180        case YAML_RESOLVER_ERROR:
181            length = snprintf(buffer, capacity, "%s: %s",
182                    prefixes[error->type],
183                    error->data.resolving.problem);
184            break;
185
186        default:
187            assert(0);  /* Should never happen. */
188    }
189
190    return (length >= 0 && length < capacity);
191}
192
193/*****************************************************************************
194 * String, Stack and Queue Management
195 *****************************************************************************/
196
197/*
198 * Extend a string.
199 */
200
201YAML_DECLARE(int)
202yaml_ostring_extend(yaml_char_t **buffer, size_t *capacity)
203{
204    yaml_char_t *new_buffer = yaml_realloc(*buffer, (*capacity)*2);
205
206    if (!new_buffer) return 0;
207
208    memset(new_buffer + *capacity, 0, *capacity);
209
210    *buffer = new_buffer;
211    *capacity *= 2;
212
213    return 1;
214}
215
216/*
217 * Append an adjunct string to a base string.
218 */
219
220YAML_DECLARE(int)
221yaml_ostring_join(
222        yaml_char_t **base_buffer, size_t *base_pointer, size_t *base_capacity,
223        yaml_char_t *adj_buffer, size_t adj_pointer)
224{
225    if (!adj_pointer)
226        return 1;
227
228    while (*base_capacity - *base_pointer <= adj_pointer) {
229        if (!yaml_ostring_extend(base_buffer, base_capacity))
230            return 0;
231    }
232
233    memcpy(*base_buffer+*base_pointer, adj_buffer, adj_pointer);
234    *base_pointer += adj_pointer;
235
236    return 1;
237}
238
239/*
240 * Extend a stack.
241 */
242
243YAML_DECLARE(int)
244yaml_stack_extend(void **list, size_t size, size_t *length, size_t *capacity)
245{
246    void *new_list = yaml_realloc(*list, (*capacity)*size*2);
247
248    if (!new_list) return 0;
249
250    *list = new_list;
251    *capacity *= 2;
252
253    return 1;
254}
255
256/*
257 * Extend or move a queue.
258 */
259
260YAML_DECLARE(int)
261yaml_queue_extend(void **list, size_t size,
262        size_t *head, size_t *tail, size_t *capacity)
263{
264    /* Check if we need to resize the queue. */
265
266    if (*head == 0 && *tail == *capacity) {
267        void *new_list = yaml_realloc(*list, (*capacity)*size*2);
268
269        if (!new_list) return 0;
270
271        *list = new_list;
272        *capacity *= 2;
273    }
274
275    /* Check if we need to move the queue at the beginning of the buffer. */
276
277    if (*tail == *capacity) {
278        if (*head != *tail) {
279            memmove((char *)*list, (char *)*list + (*head)*size,
280                    (*tail-*head)*size);
281        }
282        *tail -= *head;
283        *head = 0;
284    }
285
286    return 1;
287}
288
289/*****************************************************************************
290 * Token API
291 *****************************************************************************/
292
293/*
294 * Allocate a token object.
295 */
296
297YAML_DECLARE(yaml_token_t *)
298yaml_token_new(void)
299{
300    yaml_token_t *token = yaml_malloc(sizeof(yaml_token_t));
301
302    if (!token)
303        return NULL;
304
305    memset(token, 0, sizeof(yaml_token_t));
306
307    return token;
308}
309
310/*
311 * Deallocate a token object.
312 */
313
314YAML_DECLARE(void)
315yaml_token_delete(yaml_token_t *token)
316{
317    assert(token);  /* Non-NULL token object expected. */
318
319    yaml_token_clear(token);
320    yaml_free(token);
321}
322
323/*
324 * Duplicate a token object.
325 */
326
327YAML_DECLARE(int)
328yaml_token_duplicate(yaml_token_t *token, const yaml_token_t *model)
329{
330    assert(token);  /* Non-NULL token object is expected. */
331    assert(model);  /* Non-NULL model token object is expected. */
332    assert(!token->type);   /* The token must be empty. */
333
334    memset(token, 0, sizeof(yaml_token_t));
335
336    token->type = model->type;
337    token->start_mark = model->start_mark;
338    token->end_mark = model->end_mark;
339
340    switch (token->type)
341    {
342        case YAML_STREAM_START_TOKEN:
343            token->data.stream_start.encoding =
344                model->data.stream_start.encoding;
345            break;
346
347        case YAML_VERSION_DIRECTIVE_TOKEN:
348            token->data.version_directive.major =
349                model->data.version_directive.major;
350            token->data.version_directive.minor =
351                model->data.version_directive.minor;
352            break;
353
354        case YAML_TAG_DIRECTIVE_TOKEN:
355            if (!(token->data.tag_directive.handle =
356                        yaml_strdup(model->data.tag_directive.handle)))
357                goto error;
358            if (!(token->data.tag_directive.prefix =
359                        yaml_strdup(model->data.tag_directive.prefix)))
360                goto error;
361            break;
362
363        case YAML_ALIAS_TOKEN:
364            if (!(token->data.alias.value =
365                        yaml_strdup(model->data.alias.value)))
366                goto error;
367            break;
368
369        case YAML_ANCHOR_TOKEN:
370            if (!(token->data.anchor.value =
371                        yaml_strdup(model->data.anchor.value)))
372                goto error;
373            break;
374
375        case YAML_TAG_TOKEN:
376            if (!(token->data.tag.handle = yaml_strdup(model->data.tag.handle)))
377                goto error;
378            if (!(token->data.tag.suffix = yaml_strdup(model->data.tag.suffix)))
379                goto error;
380            break;
381
382        case YAML_SCALAR_TOKEN:
383            if (!(token->data.scalar.value =
384                        yaml_malloc(model->data.scalar.length+1)))
385                goto error;
386            memcpy(token->data.scalar.value, model->data.scalar.value,
387                    model->data.scalar.length+1);
388            token->data.scalar.length = model->data.scalar.length;
389            token->data.scalar.style = model->data.scalar.style;
390            break;
391
392        default:
393            break;
394    }
395
396    return 1;
397
398error:
399    yaml_token_clear(token);
400
401    return 0;
402}
403
404/*
405 * Clear a token object.
406 */
407
408YAML_DECLARE(void)
409yaml_token_clear(yaml_token_t *token)
410{
411    assert(token);  /* Non-NULL token object expected. */
412
413    switch (token->type)
414    {
415        case YAML_TAG_DIRECTIVE_TOKEN:
416            yaml_free(token->data.tag_directive.handle);
417            yaml_free(token->data.tag_directive.prefix);
418            break;
419
420        case YAML_ALIAS_TOKEN:
421            yaml_free(token->data.alias.value);
422            break;
423
424        case YAML_ANCHOR_TOKEN:
425            yaml_free(token->data.anchor.value);
426            break;
427
428        case YAML_TAG_TOKEN:
429            yaml_free(token->data.tag.handle);
430            yaml_free(token->data.tag.suffix);
431            break;
432
433        case YAML_SCALAR_TOKEN:
434            yaml_free(token->data.scalar.value);
435            break;
436
437        default:
438            break;
439    }
440
441    memset(token, 0, sizeof(yaml_token_t));
442}
443
444/*****************************************************************************
445 * Event API
446 *****************************************************************************/
447
448/*
449 * Allocate an event object.
450 */
451
452YAML_DECLARE(yaml_event_t *)
453yaml_event_new(void)
454{
455    yaml_event_t *event = yaml_malloc(sizeof(yaml_event_t));
456
457    if (!event)
458        return NULL;
459
460    memset(event, 0, sizeof(yaml_event_t));
461
462    return event;
463}
464
465/*
466 * Deallocate an event object.
467 */
468
469YAML_DECLARE(void)
470yaml_event_delete(yaml_event_t *event)
471{
472    assert(event);  /* Non-NULL event object expected. */
473
474    yaml_event_clear(event);
475    yaml_free(event);
476}
477
478/*
479 * Duplicate an event object.
480 */
481
482YAML_DECLARE(int)
483yaml_event_duplicate(yaml_event_t *event, const yaml_event_t *model)
484{
485    struct {
486        yaml_error_t error;
487    } self;
488
489    assert(event);  /* Non-NULL event object is expected. */
490    assert(model);  /* Non-NULL model event object is expected. */
491    assert(!event->type);   /* The event must be empty. */
492
493    memset(event, 0, sizeof(yaml_event_t));
494
495    event->type = model->type;
496    event->start_mark = model->start_mark;
497    event->end_mark = model->end_mark;
498
499    switch (event->type)
500    {
501        case YAML_STREAM_START_EVENT:
502            event->data.stream_start.encoding =
503                model->data.stream_start.encoding;
504            break;
505
506        case YAML_DOCUMENT_START_EVENT:
507            if (model->data.document_start.version_directive) {
508                if (!(event->data.document_start.version_directive =
509                            yaml_malloc(sizeof(yaml_version_directive_t))))
510                    goto error;
511                *event->data.document_start.version_directive =
512                    *model->data.document_start.version_directive;
513            }
514            if (model->data.document_start.tag_directives.length) {
515                yaml_tag_directive_t *tag_directives =
516                    model->data.document_start.tag_directives.list;
517                if (!STACK_INIT(&self, event->data.document_start.tag_directives,
518                            model->data.document_start.tag_directives.capacity))
519                    goto error;
520                while (event->data.document_start.tag_directives.length !=
521                        model->data.document_start.tag_directives.length) {
522                    yaml_tag_directive_t value;
523                    value.handle = yaml_strdup(tag_directives->handle);
524                    value.prefix = yaml_strdup(tag_directives->prefix);
525                    PUSH(&self, event->data.document_start.tag_directives, value);
526                    if (!value.handle || !value.prefix)
527                        goto error;
528                    tag_directives ++;
529                }
530            }
531            event->data.document_start.is_implicit =
532                model->data.document_start.is_implicit;
533            break;
534
535        case YAML_DOCUMENT_END_EVENT:
536            event->data.document_end.is_implicit =
537                model->data.document_end.is_implicit;
538            break;
539
540        case YAML_ALIAS_EVENT:
541            if (!(event->data.alias.anchor =
542                        yaml_strdup(model->data.alias.anchor)))
543                goto error;
544            break;
545
546        case YAML_SCALAR_EVENT:
547            if (model->data.scalar.anchor &&
548                    !(event->data.scalar.anchor =
549                        yaml_strdup(model->data.scalar.anchor)))
550                goto error;
551            if (model->data.scalar.tag &&
552                    !(event->data.scalar.tag =
553                        yaml_strdup(model->data.scalar.tag)))
554                goto error;
555            if (!(event->data.scalar.value =
556                        yaml_malloc(model->data.scalar.length+1)))
557                goto error;
558            memcpy(event->data.scalar.value, model->data.scalar.value,
559                    model->data.scalar.length+1);
560            event->data.scalar.length = model->data.scalar.length;
561            event->data.scalar.is_plain_nonspecific =
562                model->data.scalar.is_plain_nonspecific;
563            event->data.scalar.is_quoted_nonspecific =
564                model->data.scalar.is_quoted_nonspecific;
565            event->data.scalar.style = model->data.scalar.style;
566            break;
567
568        case YAML_SEQUENCE_START_EVENT:
569            if (model->data.sequence_start.anchor &&
570                    !(event->data.sequence_start.anchor =
571                        yaml_strdup(model->data.sequence_start.anchor)))
572                goto error;
573            if (model->data.sequence_start.tag &&
574                    !(event->data.sequence_start.tag =
575                        yaml_strdup(model->data.sequence_start.tag)))
576                goto error;
577            event->data.sequence_start.is_nonspecific =
578                model->data.sequence_start.is_nonspecific;
579            event->data.sequence_start.style =
580                model->data.sequence_start.style;
581            break;
582
583        case YAML_MAPPING_START_EVENT:
584            if (model->data.mapping_start.anchor &&
585                    !(event->data.mapping_start.anchor =
586                        yaml_strdup(model->data.mapping_start.anchor)))
587                goto error;
588            if (model->data.mapping_start.tag &&
589                    !(event->data.mapping_start.tag =
590                        yaml_strdup(model->data.mapping_start.tag)))
591                goto error;
592            event->data.mapping_start.is_nonspecific =
593                model->data.mapping_start.is_nonspecific;
594            event->data.mapping_start.style =
595                model->data.mapping_start.style;
596            break;
597
598        default:
599            break;
600    }
601
602    return 1;
603
604error:
605    yaml_event_clear(event);
606
607    return 0;
608}
609
610/*
611 * Clear an event object.
612 */
613
614YAML_DECLARE(void)
615yaml_event_clear(yaml_event_t *event)
616{
617    struct {
618        yaml_error_t error;
619    } self;
620
621    assert(event);  /* Non-NULL event object expected. */
622
623    switch (event->type)
624    {
625        case YAML_DOCUMENT_START_EVENT:
626            yaml_free(event->data.document_start.version_directive);
627            while (!STACK_EMPTY(&self, event->data.document_start.tag_directives)) {
628                yaml_tag_directive_t value = POP(&self,
629                        event->data.document_start.tag_directives);
630                yaml_free(value.handle);
631                yaml_free(value.prefix);
632            }
633            STACK_DEL(&self, event->data.document_start.tag_directives);
634            break;
635
636        case YAML_ALIAS_EVENT:
637            yaml_free(event->data.alias.anchor);
638            break;
639
640        case YAML_SCALAR_EVENT:
641            yaml_free(event->data.scalar.anchor);
642            yaml_free(event->data.scalar.tag);
643            yaml_free(event->data.scalar.value);
644            break;
645
646        case YAML_SEQUENCE_START_EVENT:
647            yaml_free(event->data.sequence_start.anchor);
648            yaml_free(event->data.sequence_start.tag);
649            break;
650
651        case YAML_MAPPING_START_EVENT:
652            yaml_free(event->data.mapping_start.anchor);
653            yaml_free(event->data.mapping_start.tag);
654            break;
655
656        default:
657            break;
658    }
659
660    memset(event, 0, sizeof(yaml_event_t));
661}
662
663/*
664 * Create STREAM-START.
665 */
666
667YAML_DECLARE(int)
668yaml_event_create_stream_start(yaml_event_t *event,
669        yaml_encoding_t encoding)
670{
671    yaml_mark_t mark = { 0, 0, 0 };
672
673    assert(event);  /* Non-NULL event object is expected. */
674    assert(!event->type);   /* The event must be empty. */
675
676    STREAM_START_EVENT_INIT(*event, encoding, mark, mark);
677
678    return 1;
679}
680
681/*
682 * Create STREAM-END.
683 */
684
685YAML_DECLARE(int)
686yaml_event_create_stream_end(yaml_event_t *event)
687{
688    yaml_mark_t mark = { 0, 0, 0 };
689
690    assert(event);  /* Non-NULL event object is expected. */
691    assert(!event->type);   /* The event must be empty. */
692
693    STREAM_END_EVENT_INIT(*event, mark, mark);
694
695    return 1;
696}
697
698/*
699 * Create DOCUMENT-START.
700 */
701
702YAML_DECLARE(int)
703yaml_event_create_document_start(yaml_event_t *event,
704        const yaml_version_directive_t *version_directive,
705        const yaml_tag_directive_t *tag_directives_list,
706        size_t tag_directives_length, int is_implicit)
707{
708    struct {
709        yaml_error_t error;
710    } self;
711    yaml_mark_t mark = { 0, 0, 0 };
712    yaml_version_directive_t *version_directive_copy = NULL;
713    struct {
714        yaml_tag_directive_t *list;
715        size_t length;
716        size_t capacity;
717    } tag_directives_copy = { NULL, 0, 0 };
718    int idx;
719
720    assert(event);          /* Non-NULL event object is expected. */
721    assert(!event->type);   /* The event must be empty. */
722
723    if (version_directive) {
724        version_directive_copy = yaml_malloc(sizeof(yaml_version_directive_t));
725        if (!version_directive_copy) goto error;
726        *version_directive_copy = *version_directive;
727    }
728
729    if (tag_directives_list && tag_directives_length) {
730        if (!STACK_INIT(&self, tag_directives_copy, tag_directives_length))
731            goto error;
732        for (idx = 0; idx < tag_directives_length; idx++) {
733            yaml_tag_directive_t value = tag_directives_list[idx];
734            assert(value.handle);
735            assert(value.prefix);
736            value.handle = yaml_strdup(value.handle);
737            value.prefix = yaml_strdup(value.prefix);
738            PUSH(&self, tag_directives_copy, value);
739            if (!value.handle || !value.prefix)
740                goto error;
741        }
742    }
743
744    DOCUMENT_START_EVENT_INIT(*event, version_directive_copy,
745            tag_directives_copy.list, tag_directives_copy.length,
746            tag_directives_copy.capacity, is_implicit, mark, mark);
747
748    return 1;
749
750error:
751    yaml_free(version_directive_copy);
752    while (!STACK_EMPTY(&self, tag_directives_copy)) {
753        yaml_tag_directive_t value = POP(&self, tag_directives_copy);
754        yaml_free(value.handle);
755        yaml_free(value.prefix);
756    }
757    STACK_DEL(&self, tag_directives_copy);
758
759    return 0;
760}
761
762/*
763 * Create DOCUMENT-END.
764 */
765
766YAML_DECLARE(int)
767yaml_event_create_document_end(yaml_event_t *event, int is_implicit)
768{
769    yaml_mark_t mark = { 0, 0, 0 };
770
771    assert(event);      /* Non-NULL emitter object is expected. */
772    assert(!event->type);   /* The event must be empty. */
773
774    DOCUMENT_END_EVENT_INIT(*event, is_implicit, mark, mark);
775
776    return 1;
777}
778
779/*
780 * Create ALIAS.
781 */
782
783YAML_DECLARE(int)
784yaml_event_create_alias(yaml_event_t *event, const yaml_char_t *anchor)
785{
786    yaml_mark_t mark = { 0, 0, 0 };
787    yaml_char_t *anchor_copy = NULL;
788
789    assert(event);      /* Non-NULL event object is expected. */
790    assert(!event->type);   /* The event must be empty. */
791    assert(anchor);     /* Non-NULL anchor is expected. */
792
793    anchor_copy = yaml_strdup(anchor);
794    if (!anchor_copy)
795        return 0;
796
797    ALIAS_EVENT_INIT(*event, anchor_copy, mark, mark);
798
799    return 1;
800}
801
802/*
803 * Create SCALAR.
804 */
805
806YAML_DECLARE(int)
807yaml_event_create_scalar(yaml_event_t *event,
808        const yaml_char_t *anchor, const yaml_char_t *tag,
809        const yaml_char_t *value, int length,
810        int is_plain_nonspecific, int is_quoted_nonspecific,
811        yaml_scalar_style_t style)
812{
813    yaml_mark_t mark = { 0, 0, 0 };
814    yaml_char_t *anchor_copy = NULL;
815    yaml_char_t *tag_copy = NULL;
816    yaml_char_t *value_copy = NULL;
817
818    assert(event);      /* Non-NULL event object is expected. */
819    assert(!event->type);   /* The event must be empty. */
820    assert(value);      /* Non-NULL anchor is expected. */
821
822    if (anchor) {
823        anchor_copy = yaml_strdup(anchor);
824        if (!anchor_copy)
825            goto error;
826    }
827
828    if (tag) {
829        tag_copy = yaml_strdup(tag);
830        if (!tag_copy)
831            goto error;
832    }
833
834    if (length < 0) {
835        length = strlen((char *)value);
836    }
837
838    value_copy = yaml_malloc(length+1);
839    if (!value_copy)
840        goto error;
841    memcpy(value_copy, value, length);
842    value_copy[length] = '\0';
843
844    SCALAR_EVENT_INIT(*event, anchor_copy, tag_copy, value_copy, length,
845            is_plain_nonspecific, is_quoted_nonspecific, style, mark, mark);
846
847    return 1;
848
849error:
850    yaml_free(anchor_copy);
851    yaml_free(tag_copy);
852    yaml_free(value_copy);
853
854    return 0;
855}
856
857/*
858 * Create SEQUENCE-START.
859 */
860
861YAML_DECLARE(int)
862yaml_event_create_sequence_start(yaml_event_t *event,
863        const yaml_char_t *anchor, const yaml_char_t *tag,
864        int is_nonspecific, yaml_sequence_style_t style)
865{
866    yaml_mark_t mark = { 0, 0, 0 };
867    yaml_char_t *anchor_copy = NULL;
868    yaml_char_t *tag_copy = NULL;
869
870    assert(event);      /* Non-NULL event object is expected. */
871    assert(!event->type);   /* The event must be empty. */
872
873    if (anchor) {
874        anchor_copy = yaml_strdup(anchor);
875        if (!anchor_copy)
876            goto error;
877    }
878
879    if (tag) {
880        tag_copy = yaml_strdup(tag);
881        if (!tag_copy)
882            goto error;
883    }
884
885    SEQUENCE_START_EVENT_INIT(*event, anchor_copy, tag_copy,
886            is_nonspecific, style, mark, mark);
887
888    return 1;
889
890error:
891    yaml_free(anchor_copy);
892    yaml_free(tag_copy);
893
894    return 0;
895}
896
897/*
898 * Create SEQUENCE-END.
899 */
900
901YAML_DECLARE(int)
902yaml_event_create_sequence_end(yaml_event_t *event)
903{
904    yaml_mark_t mark = { 0, 0, 0 };
905
906    assert(event);      /* Non-NULL event object is expected. */
907    assert(!event->type);   /* The event must be empty. */
908
909    SEQUENCE_END_EVENT_INIT(*event, mark, mark);
910
911    return 1;
912}
913
914/*
915 * Create MAPPING-START.
916 */
917
918YAML_DECLARE(int)
919yaml_event_create_mapping_start(yaml_event_t *event,
920        const yaml_char_t *anchor, const yaml_char_t *tag,
921        int is_nonspecific, yaml_mapping_style_t style)
922{
923    yaml_mark_t mark = { 0, 0, 0 };
924    yaml_char_t *anchor_copy = NULL;
925    yaml_char_t *tag_copy = NULL;
926
927    assert(event);      /* Non-NULL event object is expected. */
928    assert(!event->type);   /* The event must be empty. */
929
930    if (anchor) {
931        anchor_copy = yaml_strdup(anchor);
932        if (!anchor_copy)
933            goto error;
934    }
935
936    if (tag) {
937        tag_copy = yaml_strdup(tag);
938        if (!tag_copy)
939            goto error;
940    }
941
942    MAPPING_START_EVENT_INIT(*event, anchor_copy, tag_copy,
943            is_nonspecific, style, mark, mark);
944
945    return 1;
946
947error:
948    yaml_free(anchor_copy);
949    yaml_free(tag_copy);
950
951    return 0;
952}
953
954/*
955 * Create MAPPING-END.
956 */
957
958YAML_DECLARE(int)
959yaml_event_create_mapping_end(yaml_event_t *event)
960{
961    yaml_mark_t mark = { 0, 0, 0 };
962
963    assert(event);      /* Non-NULL event object is expected. */
964    assert(!event->type);   /* The event must be empty. */
965
966    MAPPING_END_EVENT_INIT(*event, mark, mark);
967
968    return 1;
969}
970
971/*****************************************************************************
972 * Document API
973 *****************************************************************************/
974
975/*
976 * Allocate a document object.
977 */
978
979YAML_DECLARE(yaml_document_t *)
980yaml_document_new(void)
981{
982    yaml_document_t *document = yaml_malloc(sizeof(yaml_document_t));
983
984    if (!document)
985        return NULL;
986
987    memset(document, 0, sizeof(yaml_document_t));
988
989    return document;
990}
991
992/*
993 * Deallocate a document object.
994 */
995
996YAML_DECLARE(void)
997yaml_document_delete(yaml_document_t *document)
998{
999    assert(document);   /* Non-NULL document object is expected. */
1000
1001    yaml_document_clear(document);
1002    yaml_free(document);
1003}
1004
1005/*
1006 * Duplicate a document object.
1007 */
1008
1009YAML_DECLARE(int)
1010yaml_document_duplicate(yaml_document_t *document, yaml_document_t *model)
1011{
1012    struct {
1013        yaml_error_t error;
1014    } self;
1015    yaml_char_t *anchor = NULL;
1016    yaml_char_t *tag = NULL;
1017    yaml_char_t *value = NULL;
1018    yaml_node_item_t *item_list = NULL;
1019    yaml_node_pair_t *pair_list = NULL;
1020    int idx;
1021
1022    assert(document);   /* Non-NULL document object is expected. */
1023    assert(!document->type);    /* The document must be empty. */
1024    assert(model);      /* Non-NULL model object is expected. */
1025
1026    if (model->type != YAML_DOCUMENT)
1027        return 1;
1028
1029    if (!yaml_document_create(document, model->version_directive,
1030                model->tag_directives.list, model->tag_directives.length,
1031                model->is_start_implicit, model->is_end_implicit))
1032        return 0;
1033
1034    document->start_mark = model->start_mark;
1035    document->end_mark = model->end_mark;
1036
1037    for (idx = 0; idx < model->nodes.length; idx++)
1038    {
1039        yaml_node_t *node = STACK_ITER(&self, model->nodes, idx);
1040        yaml_node_t copy;
1041        if (node->anchor) {
1042            anchor = yaml_strdup(node->anchor);
1043            if (!anchor) goto error;
1044        }
1045        tag = yaml_strdup(node->tag);
1046        if (!tag) goto error;
1047        switch (node->type)
1048        {
1049            case YAML_SCALAR_NODE:
1050                value = yaml_malloc(node->data.scalar.length+1);
1051                if (!value)
1052                    goto error;
1053                memcpy(value, node->data.scalar.value,
1054                        node->data.scalar.length);
1055                value[node->data.scalar.length] = '\0';
1056                SCALAR_NODE_INIT(copy, anchor, tag, value,
1057                        node->data.scalar.length, node->data.scalar.style,
1058                        node->start_mark, node->end_mark);
1059                break;
1060
1061            case YAML_SEQUENCE_NODE:
1062                item_list = yaml_malloc(node->data.sequence.items.capacity
1063                        * sizeof(yaml_node_item_t));
1064                if (!item_list) goto error;
1065                memcpy(item_list, node->data.sequence.items.list,
1066                        node->data.sequence.items.capacity
1067                        * sizeof(yaml_node_item_t));
1068                SEQUENCE_NODE_INIT(copy, anchor, tag, item_list,
1069                        node->data.sequence.items.length,
1070                        node->data.sequence.items.capacity,
1071                        node->data.sequence.style,
1072                        node->start_mark, node->end_mark);
1073                break;
1074
1075            case YAML_MAPPING_NODE:
1076                pair_list = yaml_malloc(node->data.mapping.pairs.capacity
1077                        * sizeof(yaml_node_pair_t));
1078                if (!pair_list) goto error;
1079                memcpy(pair_list, node->data.mapping.pairs.list,
1080                        node->data.mapping.pairs.capacity
1081                        * sizeof(yaml_node_pair_t));
1082                MAPPING_NODE_INIT(copy, anchor, tag, pair_list,
1083                        node->data.mapping.pairs.length,
1084                        node->data.mapping.pairs.capacity,
1085                        node->data.mapping.style,
1086                        node->start_mark, node->end_mark);
1087                break;
1088
1089            default:
1090                assert(0);  /* Should never happen. */
1091        }
1092
1093        if (!PUSH(&self, document->nodes, copy))
1094            goto error;
1095
1096        anchor = NULL;
1097        tag = NULL;
1098        value = NULL;
1099        item_list = NULL;
1100        pair_list = NULL;
1101    }
1102
1103error:
1104    yaml_free(anchor);
1105    yaml_free(tag);
1106    yaml_free(value);
1107    yaml_free(item_list);
1108    yaml_free(pair_list);
1109
1110    yaml_document_clear(document);
1111
1112    return 0;
1113}
1114
1115/*
1116 * Clear a document object.
1117 */
1118
1119YAML_DECLARE(void)
1120yaml_document_clear(yaml_document_t *document)
1121{
1122    struct {
1123        yaml_error_type_t error;
1124    } self;
1125    yaml_tag_directive_t *tag_directive;
1126
1127    self.error = YAML_NO_ERROR;  /* Eliminate a compliler warning. */
1128
1129    assert(document);   /* Non-NULL document object is expected. */
1130
1131    if (!document->type)
1132        return;
1133
1134    while (!STACK_EMPTY(&context, document->nodes)) {
1135        yaml_node_t node = POP(&context, document->nodes);
1136        yaml_free(node.tag);
1137        switch (node.type) {
1138            case YAML_SCALAR_NODE:
1139                yaml_free(node.data.scalar.value);
1140                break;
1141            case YAML_SEQUENCE_NODE:
1142                STACK_DEL(&context, node.data.sequence.items);
1143                break;
1144            case YAML_MAPPING_NODE:
1145                STACK_DEL(&context, node.data.mapping.pairs);
1146                break;
1147            default:
1148                assert(0);  /* Should not happen. */
1149        }
1150    }
1151    STACK_DEL(&self, document->nodes);
1152
1153    yaml_free(document->version_directive);
1154    while (!STACK_EMPTY(&self, document->tag_directives)) {
1155        yaml_tag_directive_t tag_directive = POP(&self, document->tag_directives);
1156        yaml_free(tag_directive.handle);
1157        yaml_free(tag_directive.prefix);
1158    }
1159    STACK_DEL(&self, document->tag_directives);
1160
1161    memset(document, 0, sizeof(yaml_document_t));
1162}
1163
1164/*
1165 * Create a document.
1166 */
1167
1168YAML_DECLARE(int)
1169yaml_document_create(yaml_document_t *document,
1170        const yaml_version_directive_t *version_directive,
1171        const yaml_tag_directive_t *tag_directives_list,
1172        size_t tag_directives_length,
1173        int is_start_implicit, int is_end_implicit)
1174{
1175    struct {
1176        yaml_error_t error;
1177    } self;
1178    yaml_mark_t mark = { 0, 0, 0 };
1179    struct {
1180        yaml_node_t *list;
1181        size_t length;
1182        size_t capacity;
1183    } nodes;
1184    yaml_version_directive_t *version_directive_copy = NULL;
1185    struct {
1186        yaml_tag_directive_t *list;
1187        size_t length;
1188        size_t capacity;
1189    } tag_directives_copy = { NULL, 0, 0 };
1190    int idx;
1191
1192    assert(document);           /* Non-NULL event object is expected. */
1193    assert(!document->type);    /* The document must be empty. */
1194   
1195    if (!STACK_INIT(&self, nodes, INITIAL_STACK_CAPACITY))
1196        goto error;
1197
1198    if (version_directive) {
1199        version_directive_copy = yaml_malloc(sizeof(yaml_version_directive_t));
1200        if (!version_directive_copy) goto error;
1201        *version_directive_copy = *version_directive;
1202    }
1203
1204    if (tag_directives_list && tag_directives_length) {
1205        if (!STACK_INIT(&self, tag_directives_copy, tag_directives_length))
1206            goto error;
1207        for (idx = 0; idx < tag_directives_length; idx++) {
1208            yaml_tag_directive_t value = tag_directives_list[idx];
1209            assert(value.handle);
1210            assert(value.prefix);
1211            value.handle = yaml_strdup(value.handle);
1212            value.prefix = yaml_strdup(value.prefix);
1213            PUSH(&self, tag_directives_copy, value);
1214            if (!value.handle || !value.prefix)
1215                goto error;
1216        }
1217    }
1218
1219    DOCUMENT_INIT(*document, nodes.list, nodes.length, nodes.capacity,
1220            version_directive_copy, tag_directives_copy.list,
1221            tag_directives_copy.length, tag_directives_copy.capacity,
1222            is_start_implicit, is_end_implicit, mark, mark);
1223
1224    return 1;
1225
1226error:
1227    STACK_DEL(&self, nodes);
1228
1229    yaml_free(version_directive_copy);
1230
1231    while (!STACK_EMPTY(&self, tag_directives_copy)) {
1232        yaml_tag_directive_t value = POP(&self, tag_directives_copy);
1233        yaml_free(value.handle);
1234        yaml_free(value.prefix);
1235    }
1236    STACK_DEL(&self, tag_directives_copy);
1237
1238    return 0;
1239}
1240
1241/*
1242 * Get a document node.
1243 */
1244
1245YAML_DECLARE(yaml_node_t *)
1246yaml_document_get_node(yaml_document_t *document, int node_id)
1247{
1248    assert(document);   /* Non-NULL document object is expected. */
1249    assert(document->type); /* Initialized document is expected. */
1250
1251    if (node_id < 0) {
1252        node_id += document->nodes.length;
1253    }
1254
1255    if (node_id >= 0 && node_id < document->nodes.length) {
1256        return document->nodes.list + node_id;
1257    }
1258    return NULL;
1259}
1260
1261/*
1262 * Add a scalar node to a document.
1263 */
1264
1265YAML_DECLARE(int)
1266yaml_document_add_scalar(yaml_document_t *document, int *node_id,
1267        const yaml_char_t *anchor, const yaml_char_t *tag,
1268        const yaml_char_t *value, int length,
1269        yaml_scalar_style_t style)
1270{
1271    struct {
1272        yaml_error_t error;
1273    } self;
1274    yaml_mark_t mark = { 0, 0, 0 };
1275    yaml_char_t *anchor_copy = NULL;
1276    yaml_char_t *tag_copy = NULL;
1277    yaml_char_t *value_copy = NULL;
1278    yaml_node_t node;
1279
1280    assert(document);   /* Non-NULL document object is expected. */
1281    assert(document->type); /* Initialized document is required. */
1282    assert(tag);        /* Non-NULL tag is expected. */
1283    assert(value);      /* Non-NULL value is expected. */
1284
1285    if (anchor) {
1286        anchor_copy = yaml_strdup(anchor);
1287        if (!anchor_copy) goto error;
1288    }
1289
1290    tag_copy = yaml_strdup(tag);
1291    if (!tag_copy) goto error;
1292
1293    if (length < 0) {
1294        length = strlen((char *)value);
1295    }
1296
1297    value_copy = yaml_malloc(length+1);
1298    if (!value_copy) goto error;
1299    memcpy(value_copy, value, length);
1300    value_copy[length] = '\0';
1301
1302    SCALAR_NODE_INIT(node, anchor_copy, tag_copy, value_copy, length,
1303            style, mark, mark);
1304    if (!PUSH(&self, document->nodes, node)) goto error;
1305
1306    if (node_id) {
1307        *node_id = document->nodes.length-1;
1308    }
1309
1310    return 1;
1311
1312error:
1313    yaml_free(anchor_copy);
1314    yaml_free(tag_copy);
1315    yaml_free(value_copy);
1316
1317    return 0;
1318}
1319
1320/*
1321 * Add a sequence node to a document.
1322 */
1323
1324YAML_DECLARE(int)
1325yaml_document_add_sequence(yaml_document_t *document, int *node_id,
1326        const yaml_char_t *anchor, const yaml_char_t *tag,
1327        yaml_sequence_style_t style)
1328{
1329    struct {
1330        yaml_error_t error;
1331    } self;
1332    yaml_mark_t mark = { 0, 0, 0 };
1333    yaml_char_t *anchor_copy = NULL;
1334    yaml_char_t *tag_copy = NULL;
1335    struct {
1336        yaml_node_item_t *list;
1337        size_t length;
1338        size_t capacity;
1339    } items = { NULL, 0, 0 };
1340    yaml_node_t node;
1341
1342    assert(document);   /* Non-NULL document object is expected. */
1343    assert(document->type); /* Initialized document is required. */
1344    assert(tag);        /* Non-NULL tag is expected. */
1345
1346    if (anchor) {
1347        anchor_copy = yaml_strdup(anchor);
1348        if (!anchor_copy) goto error;
1349    }
1350
1351    tag_copy = yaml_strdup(tag);
1352    if (!tag_copy) goto error;
1353
1354    if (!STACK_INIT(&self, items, INITIAL_STACK_CAPACITY)) goto error;
1355
1356    SEQUENCE_NODE_INIT(node, anchor_copy, tag_copy,
1357            items.list, items.length, items.capacity, style, mark, mark);
1358    if (!PUSH(&self, document->nodes, node)) goto error;
1359
1360    if (node_id) {
1361        *node_id = document->nodes.length-1;
1362    }
1363
1364    return 1;
1365
1366error:
1367    STACK_DEL(&self, items);
1368    yaml_free(anchor_copy);
1369    yaml_free(tag_copy);
1370
1371    return 0;
1372}
1373
1374/*
1375 * Add a mapping node to a document.
1376 */
1377
1378YAML_DECLARE(int)
1379yaml_document_add_mapping(yaml_document_t *document, int *node_id,
1380        const yaml_char_t *anchor, const yaml_char_t *tag,
1381        yaml_mapping_style_t style)
1382{
1383    struct {
1384        yaml_error_t error;
1385    } self;
1386    yaml_mark_t mark = { 0, 0, 0 };
1387    yaml_char_t *anchor_copy = NULL;
1388    yaml_char_t *tag_copy = NULL;
1389    struct {
1390        yaml_node_pair_t *list;
1391        size_t length;
1392        size_t capacity;
1393    } pairs = { NULL, 0, 0 };
1394    yaml_node_t node;
1395
1396    assert(document);   /* Non-NULL document object is expected. */
1397    assert(document->type); /* Initialized document is required. */
1398    assert(tag);        /* Non-NULL tag is expected. */
1399
1400    if (anchor) {
1401        anchor_copy = yaml_strdup(anchor);
1402        if (!anchor_copy) goto error;
1403    }
1404
1405    tag_copy = yaml_strdup(tag);
1406    if (!tag_copy) goto error;
1407
1408    if (!STACK_INIT(&self, pairs, INITIAL_STACK_CAPACITY)) goto error;
1409
1410    MAPPING_NODE_INIT(node, anchor_copy, tag_copy,
1411            pairs.list, pairs.length, pairs.capacity, style, mark, mark);
1412    if (!PUSH(&self, document->nodes, node)) goto error;
1413
1414    if (node_id) {
1415        *node_id = document->nodes.length-1;
1416    }
1417
1418    return 1;
1419
1420error:
1421    STACK_DEL(&self, pairs);
1422    yaml_free(anchor_copy);
1423    yaml_free(tag_copy);
1424
1425    return 0;
1426}
1427
1428/*
1429 * Append an item to a sequence node.
1430 */
1431
1432YAML_DECLARE(int)
1433yaml_document_append_sequence_item(yaml_document_t *document,
1434        int sequence_id, int item_id)
1435{
1436    struct {
1437        yaml_error_t error;
1438    } self;
1439
1440    assert(document);       /* Non-NULL document is required. */
1441    assert(document->type); /* Initialized document is expected. */
1442
1443    if (sequence_id) {
1444        sequence_id += document->nodes.length;
1445    }
1446    if (item_id) {
1447        item_id += document->nodes.length;
1448    }
1449
1450    assert(sequence_id >= 0 && sequence_id < document->nodes.length);
1451                            /* Valid sequence id is required. */
1452    assert(item_id >= 0 && item_id < document->nodes.length);
1453                            /* Valid item id is required. */
1454    assert(document->nodes.list[sequence_id].type == YAML_SEQUENCE_NODE);
1455                            /* A sequence node is expected. */
1456
1457    if (!PUSH(&self,
1458                document->nodes.list[sequence_id].data.sequence.items, item_id))
1459        return 0;
1460
1461    return 1;
1462}
1463
1464/*
1465 * Append a pair of a key and a value to a mapping node.
1466 */
1467
1468YAML_DECLARE(int)
1469yaml_document_append_mapping_pair(yaml_document_t *document,
1470        int mapping_id, int key_id, int value_id)
1471{
1472    struct {
1473        yaml_error_t error;
1474    } self;
1475    yaml_node_pair_t pair = { key_id, value_id };
1476
1477    assert(document);       /* Non-NULL document is required. */
1478    assert(document->type); /* Initialized document is expected. */
1479
1480    if (mapping_id < 0) {
1481        mapping_id += document->nodes.length;
1482    }
1483    if (key_id < 0) {
1484        key_id += document->nodes.length;
1485    }
1486    if (value_id < 0) {
1487        value_id += document->nodes.length;
1488    }
1489
1490    assert(mapping_id >= 0 && mapping_id < document->nodes.length);
1491                            /* Valid mapping id is required. */
1492    assert(key_id >= 0 && key_id < document->nodes.length);
1493                            /* Valid key id is required. */
1494    assert(value_id >= 0 && value_id < document->nodes.length);
1495                            /* Valid value id is required. */
1496    assert(document->nodes.list[mapping_id].type == YAML_MAPPING_NODE);
1497                            /* A mapping node is expected. */
1498
1499    if (!PUSH(&self,
1500                document->nodes.list[mapping_id].data.mapping.pairs, pair))
1501        return 0;
1502
1503    return 1;
1504}
1505
1506/*
1507 * Ensure that the node is a `!!null` SCALAR node.
1508 */
1509
1510YAML_DECLARE(int)
1511yaml_document_get_null_node(yaml_document_t *document, int node_id)
1512{
1513    yaml_node_t *node;
1514    yaml_char_t *scalar;
1515
1516    assert(document);       /* Non-NULL document is required. */
1517    assert(document->type); /* Initialized document is expected. */
1518
1519    if (node_id < 0) {
1520        node_id += document->nodes.length;
1521    }
1522
1523    assert(node_id >= 0 && node_id < document->nodes.length);
1524                            /* Valid node id is required. */
1525
1526    node = document->nodes.list + node_id;
1527
1528    if (node->type != YAML_SCALAR_NODE)
1529        return 0;
1530
1531    if (strcmp(node->tag, YAML_NULL_TAG))
1532        return 0;
1533
1534    if (node->data.scalar.length != strlen(node->data.scalar.value))
1535        return 0;
1536
1537    scalar = node->data.scalar.value;
1538
1539    if (!strcmp(scalar, "") || !strcmp(scalar, "~") || !strcmp(scalar, "null")
1540            || !strcmp(scalar, "Null") || !strcmp(scalar, "NULL"))
1541        return 1;
1542
1543    return 0;
1544}
1545
1546/*
1547 * Ensure that the node is a `!!bool` SCALAR node.
1548 */
1549
1550YAML_DECLARE(int)
1551yaml_document_get_bool_node(yaml_document_t *document, int node_id, int *value)
1552{
1553    yaml_node_t *node;
1554    yaml_char_t *scalar;
1555
1556    assert(document);       /* Non-NULL document is required. */
1557    assert(document->type); /* Initialized document is expected. */
1558
1559    if (node_id < 0) {
1560        node_id += document->nodes.length;
1561    }
1562
1563    assert(node_id >= 0 && node_id < document->nodes.length);
1564                            /* Valid node id is required. */
1565
1566    node = document->nodes.list + node_id;
1567
1568    if (node->type != YAML_SCALAR_NODE)
1569        return 0;
1570
1571    if (strcmp(node->tag, YAML_BOOL_TAG))
1572        return 0;
1573
1574    if (node->data.scalar.length != strlen(node->data.scalar.value))
1575        return 0;
1576
1577    scalar = node->data.scalar.value;
1578
1579    if (!strcmp(scalar, "yes") || !strcmp(scalar, "Yes") || !strcmp(scalar, "YES") ||
1580            !strcmp(scalar, "true") || !strcmp(scalar, "True") || !strcmp(scalar, "TRUE") ||
1581            !strcmp(scalar, "on") || !strcmp(scalar, "On") || !strcmp(scalar, "ON")) {
1582        if (value) {
1583            *value = 1;
1584        }
1585        return 1;
1586    }
1587
1588    if (!strcmp(scalar, "no") || !strcmp(scalar, "No") || !strcmp(scalar, "NO") ||
1589            !strcmp(scalar, "false") || !strcmp(scalar, "False") || !strcmp(scalar, "FALSE") ||
1590            !strcmp(scalar, "off") || !strcmp(scalar, "Off") || !strcmp(scalar, "OFF")) {
1591        if (value) {
1592            *value = 0;
1593        }
1594        return 1;
1595    }
1596
1597    return 0;
1598}
1599
1600/*
1601 * Ensure that the node is a `!!str` SCALAR node.
1602 */
1603
1604YAML_DECLARE(int)
1605yaml_document_get_str_node(yaml_document_t *document, int node_id,
1606        char **value)
1607{
1608    yaml_node_t *node;
1609
1610    assert(document);       /* Non-NULL document is required. */
1611    assert(document->type); /* Initialized document is expected. */
1612
1613    if (node_id < 0) {
1614        node_id += document->nodes.length;
1615    }
1616
1617    assert(node_id >= 0 && node_id < document->nodes.length);
1618                            /* Valid node id is required. */
1619
1620    node = document->nodes.list + node_id;
1621
1622    if (node->type != YAML_SCALAR_NODE)
1623        return 0;
1624
1625    if (strcmp(node->tag, YAML_STR_TAG))
1626        return 0;
1627
1628    if (node->data.scalar.length != strlen(node->data.scalar.value))
1629        return 0;
1630
1631    if (value) {
1632        *value = node->data.scalar.value;
1633    }
1634
1635    return 1;
1636}
1637
1638/*
1639 * Ensure that the node is an `!!int` SCALAR node.
1640 */
1641
1642YAML_DECLARE(int)
1643yaml_document_get_int_node(yaml_document_t *document, int node_id,
1644        long *value)
1645{
1646    yaml_node_t *node;
1647    yaml_char_t *scalar;
1648    char *tail;
1649    long integer;
1650    int old_errno = errno, new_errno;
1651
1652    assert(document);       /* Non-NULL document is required. */
1653    assert(document->type); /* Initialized document is expected. */
1654
1655    if (node_id < 0) {
1656        node_id += document->nodes.length;
1657    }
1658
1659    assert(node_id >= 0 && node_id < document->nodes.length);
1660                            /* Valid node id is required. */
1661
1662    node = document->nodes.list + node_id;
1663
1664    if (node->type != YAML_SCALAR_NODE)
1665        return 0;
1666
1667    if (strcmp(node->tag, YAML_INT_TAG))
1668        return 0;
1669
1670    if (node->data.scalar.length != strlen(node->data.scalar.value))
1671        return 0;
1672
1673    if (!node->data.scalar.length)
1674        return 0;
1675
1676    scalar = node->data.scalar.value;
1677
1678    errno = 0;
1679
1680    integer = strtol((char *)scalar, &tail, 0);
1681
1682    new_errno = errno;
1683    errno = old_errno;
1684
1685    if (new_errno || *tail) {
1686        return 0;
1687    }
1688
1689    if (value) {
1690        *value = integer;
1691    }
1692
1693    return 1;
1694}
1695
1696/*
1697 * Ensure that the node is a `!!float` SCALAR node.
1698 */
1699
1700YAML_DECLARE(int)
1701yaml_document_get_float_node(yaml_document_t *document, int node_id,
1702        double *value)
1703{
1704    yaml_node_t *node;
1705    yaml_char_t *scalar;
1706    char buffer[128];
1707    char *pointer;
1708    char *tail;
1709    double real;
1710    int old_errno = errno, new_errno;
1711    char decimal_point = localeconv()->decimal_point[0];
1712
1713    assert(document);       /* Non-NULL document is required. */
1714    assert(document->type); /* Initialized document is expected. */
1715
1716    if (node_id < 0) {
1717        node_id += document->nodes.length;
1718    }
1719
1720    assert(node_id >= 0 && node_id < document->nodes.length);
1721                            /* Valid node id is required. */
1722
1723    node = document->nodes.list + node_id;
1724
1725    if (node->type != YAML_SCALAR_NODE)
1726        return 0;
1727
1728    if (strcmp(node->tag, YAML_FLOAT_TAG) && strcmp(node->tag, YAML_INT_TAG))
1729        return 0;
1730
1731    if (node->data.scalar.length != strlen(node->data.scalar.value))
1732        return 0;
1733
1734    if (!node->data.scalar.length)
1735        return 0;
1736
1737    scalar = node->data.scalar.value;
1738
1739    if (!strcmp(scalar, ".nan") || !strcmp(scalar, ".NaN") || !strcmp(scalar, ".NAN")) {
1740        if (value) {
1741            *value = 0.0/0.0;
1742        }
1743        return 1;
1744    }
1745
1746    if (!strcmp(scalar, ".inf") || !strcmp(scalar, ".Inf") || !strcmp(scalar, ".INF") ||
1747            !strcmp(scalar, "+.inf") || !strcmp(scalar, "+.Inf") || !strcmp(scalar, "+.INF")) {
1748        if (value) {
1749            *value = 1.0/0.0;
1750        }
1751        return 1;
1752    }
1753
1754    if (!strcmp(scalar, "-.inf") || !strcmp(scalar, "-.Inf") || !strcmp(scalar, "-.INF")) {
1755        if (value) {
1756            *value = -1.0/0.0;
1757        }
1758        return 1;
1759    }
1760
1761    if (strlen(scalar) >= sizeof(buffer))
1762        return 0;
1763
1764    strcpy(buffer, (const char *)scalar);
1765
1766    /* Replace a locale-dependent decimal point with a dot. */
1767
1768    for (pointer = buffer; *pointer; pointer++) {
1769        if (*pointer == decimal_point) {
1770            *pointer = '.';
1771            break;
1772        }
1773    }
1774
1775    errno = 0;
1776
1777    real = strtod(buffer, &tail);
1778
1779    new_errno = errno;
1780    errno = old_errno;
1781
1782    if (new_errno || *tail) {
1783        return 0;
1784    }
1785
1786    if (value) {
1787        *value = real;
1788    }
1789
1790    return 1;
1791}
1792
1793/*
1794 * Ensure that the node is a `!!seq` SEQUENCE node.
1795 */
1796
1797YAML_DECLARE(int)
1798yaml_document_get_seq_node(yaml_document_t *document, int node_id,
1799        yaml_node_item_t **items, size_t *length)
1800{
1801    yaml_node_t *node;
1802
1803    assert(document);       /* Non-NULL document is required. */
1804    assert(document->type); /* Initialized document is expected. */
1805
1806    assert((items && length) || (!items && !length));
1807                /* items and length must be equal to NULL simultaneously. */
1808
1809    if (node_id < 0) {
1810        node_id += document->nodes.length;
1811    }
1812
1813    assert(node_id >= 0 && node_id < document->nodes.length);
1814                            /* Valid node id is required. */
1815
1816    node = document->nodes.list + node_id;
1817
1818    if (node->type != YAML_SEQUENCE_NODE)
1819        return 0;
1820
1821    if (strcmp(node->tag, YAML_SEQ_TAG))
1822        return 0;
1823
1824    if (items && length) {
1825        *items = node->data.sequence.items.list;
1826        *length = node->data.sequence.items.length;
1827    }
1828
1829    return 1;
1830}
1831
1832/*
1833 * Ensure that the node is a `!!map` MAPPING node.
1834 */
1835
1836YAML_DECLARE(int)
1837yaml_document_get_map_node(yaml_document_t *document, int node_id,
1838        yaml_node_pair_t **pairs, size_t *length)
1839{
1840    yaml_node_t *node;
1841
1842    assert(document);       /* Non-NULL document is required. */
1843    assert(document->type); /* Initialized document is expected. */
1844
1845    assert((pairs && length) || (!pairs && !length));
1846                /* pairs and length must be equal to NULL simultaneously. */
1847
1848    if (node_id < 0) {
1849        node_id += document->nodes.length;
1850    }
1851
1852    assert(node_id >= 0 && node_id < document->nodes.length);
1853                            /* Valid node id is required. */
1854
1855    node = document->nodes.list + node_id;
1856
1857    if (node->type != YAML_MAPPING_NODE)
1858        return 0;
1859
1860    if (strcmp(node->tag, YAML_MAP_TAG))
1861        return 0;
1862
1863    if (pairs && length) {
1864        *pairs = node->data.mapping.pairs.list;
1865        *length = node->data.mapping.pairs.length;
1866    }
1867
1868    return 1;
1869}
1870
1871/*
1872 * Add a `!!null` SCALAR node.
1873 */
1874
1875YAML_DECLARE(int)
1876yaml_document_add_null_node(yaml_document_t *document, int *node_id)
1877{
1878    return yaml_document_add_scalar(document, node_id, NULL,
1879            YAML_NULL_TAG, "null", -1, YAML_ANY_SCALAR_STYLE);
1880}
1881
1882/*
1883 * Add a `!!bool` SCALAR node.
1884 */
1885
1886YAML_DECLARE(int)
1887yaml_document_add_bool_node(yaml_document_t *document, int *node_id,
1888        int value)
1889{
1890    return yaml_document_add_scalar(document, node_id, NULL, YAML_BOOL_TAG,
1891            (value ? "true" : "false"), -1, YAML_ANY_SCALAR_STYLE);
1892}
1893
1894/*
1895 * Add a `!!str` SCALAR node.
1896 */
1897
1898YAML_DECLARE(int)
1899yaml_document_add_str_node(yaml_document_t *document, int *node_id,
1900        const char *value)
1901{
1902    return yaml_document_add_scalar(document, node_id, NULL, YAML_STR_TAG,
1903            (const yaml_char_t *) value, -1, YAML_ANY_SCALAR_STYLE);
1904}
1905
1906/*
1907 * Add an `!!int` SCALAR node.
1908 */
1909
1910YAML_DECLARE(int)
1911yaml_document_add_int_node(yaml_document_t *document, int *node_id,
1912        long value)
1913{
1914    char buffer[128];   /* 128 bytes should be enough for everybody. */
1915    int length;
1916
1917    length = snprintf(buffer, sizeof(buffer), "%ld", value);
1918    if (length < 0 || length >= sizeof(buffer)) return 0;
1919
1920    return yaml_document_add_scalar(document, node_id, NULL, YAML_INT_TAG,
1921            (const yaml_char_t *) buffer, -1, YAML_ANY_SCALAR_STYLE);
1922}
1923
1924/*
1925 * Add a `!!float` SCALAR node.
1926 */
1927
1928YAML_DECLARE(int)
1929yaml_document_add_float_node(yaml_document_t *document, int *node_id,
1930        double value)
1931{
1932    char buffer[128];   /* 128 bytes should be enough for everybody. */
1933    char *pointer;
1934    int length;
1935    char decimal_point = *localeconv()->decimal_point;
1936
1937    length = snprintf(buffer, sizeof(buffer), "%.12g", value);
1938        /* .12 is a reasonable precision; it is used by str(float) in Python. */
1939    if (length < 0 || length >= sizeof(buffer)-3) return 0;
1940
1941    /* Replace a locale-dependent decimal point with a dot. */
1942
1943    for (pointer = buffer; *pointer; pointer++) {
1944        if (*pointer == decimal_point) {
1945            *pointer = '.';
1946            break;
1947        }
1948    }
1949
1950    /* Check if the formatted number contains a decimal dot. */
1951
1952    for (pointer = buffer; *pointer; pointer++) {
1953        if (*pointer != '+' && *pointer != '-' && !isdigit(*pointer)) {
1954            break;
1955        }
1956    }
1957
1958    /* Add .0 at the end of the buffer if needed. */
1959
1960    if (!*pointer) {
1961        *(pointer++) = '.';
1962        *(pointer++) = '0';
1963        *(pointer++) = '\0';
1964    }
1965
1966    return yaml_document_add_scalar(document, node_id, NULL, YAML_FLOAT_TAG,
1967            (const yaml_char_t *) buffer, -1, YAML_ANY_SCALAR_STYLE);
1968}
1969
1970/*
1971 * Add a `!!seq` SEQUENCE node.
1972 */
1973
1974YAML_DECLARE(int)
1975yaml_document_add_seq_node(yaml_document_t *document, int *node_id)
1976{
1977    return yaml_document_add_sequence(document, node_id, NULL,
1978            YAML_SEQ_TAG, YAML_ANY_SEQUENCE_STYLE);
1979}
1980
1981/*
1982 * Add a `!!map` MAPPING node.
1983 */
1984
1985YAML_DECLARE(int)
1986yaml_document_add_map_node(yaml_document_t *document, int *node_id)
1987{
1988    return yaml_document_add_mapping(document, node_id, NULL,
1989            YAML_MAP_TAG, YAML_ANY_MAPPING_STYLE);
1990}
1991
1992/*****************************************************************************
1993 * Standard Handlers
1994 *****************************************************************************/
1995
1996/*
1997 * Standard string read handler.
1998 */
1999
2000static int
2001yaml_string_reader(void *untyped_data, unsigned char *buffer, size_t capacity,
2002        size_t *length)
2003{
2004    yaml_standard_reader_data_t *data = untyped_data;
2005
2006    if (data->string.pointer == data->string.length) {
2007        *length = 0;
2008        return 1;
2009    }
2010
2011    if (capacity > (size_t)(data->string.length - data->string.pointer)) {
2012        capacity = data->string.length - data->string.pointer;
2013    }
2014
2015    memcpy(buffer, data->string.buffer + data->string.pointer, capacity);
2016    data->string.pointer += capacity;
2017    *length = capacity;
2018    return 1;
2019}
2020
2021/*
2022 * Standard file read handler.
2023 */
2024
2025static int
2026yaml_file_reader(void *untyped_data, unsigned char *buffer, size_t capacity,
2027        size_t *length)
2028{
2029    yaml_standard_reader_data_t *data = untyped_data;
2030
2031    *length = fread(buffer, 1, capacity, data->file);
2032    return !ferror(data->file);
2033}
2034
2035/*
2036 * String write handler.
2037 */
2038
2039static int
2040yaml_string_writer(void *untyped_data, const unsigned char *buffer, size_t length)
2041{
2042    yaml_standard_writer_data_t *data = untyped_data;
2043    int result = 1;
2044
2045    if (data->string.capacity - data->string.pointer < length) {
2046        length = data->string.capacity - data->string.pointer;
2047        result = 0;
2048    }
2049
2050    memcpy(data->string.buffer + data->string.pointer, buffer, length);
2051    data->string.pointer += length;
2052    *data->length += length;
2053
2054    return result;
2055}
2056
2057/*
2058 * File write handler.
2059 */
2060
2061static int
2062yaml_file_writer(void *untyped_data, const unsigned char *buffer, size_t length)
2063{
2064    yaml_standard_writer_data_t *data = untyped_data;
2065
2066    return (fwrite(buffer, 1, length, data->file) == length);
2067}
2068
2069/*
2070 * Standard resolve handler.
2071 *
2072 * The standard resolve handler recognizes the following scalars:
2073 *
2074 * - `!!null`: `~|null|Null|NULL|<empty string>`.
2075 *
2076 * - `!!bool`: `yes|Yes|YES|no|No|NO|true|True|TRUE|false|False|FALSE|
2077 *              on|On|ON|off|Off|OFF`
2078 *
2079 * - `!!int`: any string that is successfully converted using `strtol()`.
2080 *
2081 * - `!!float`: `[+-]?(.inf|.Inf|.INF)|.nan|.NaN|.NAN` or any string
2082 *   successfully converted using `strtod()`.
2083 */
2084
2085static int
2086yaml_standard_resolver(void *untyped_data, yaml_incomplete_node_t *node,
2087        const yaml_char_t **tag)
2088{
2089    if (node->type == YAML_SCALAR_NODE && node->data.scalar.is_plain)
2090    {
2091        yaml_char_t *value = node->data.scalar.value;
2092        char buffer[128];
2093        char *pointer;
2094        char *tail;
2095        int old_errno, new_errno;
2096        char decimal_point = *(localeconv()->decimal_point);
2097
2098        if (strlen(value) != node->data.scalar.length) {
2099            *tag = YAML_STR_TAG;
2100            return 1;
2101        }
2102
2103        if (!strcmp(value, "") || !strcmp(value, "~") ||
2104                !strcmp(value, "null") || !strcmp(value, "Null") || !strcmp(value, "NULL")) {
2105            *tag = YAML_NULL_TAG;
2106            return 1;
2107        }
2108
2109        if (!strcmp(value, "yes") || !strcmp(value, "Yes") || !strcmp(value, "YES") ||
2110                !strcmp(value, "no") || !strcmp(value, "No") || !strcmp(value, "NO") ||
2111                !strcmp(value, "true") || !strcmp(value, "True") || !strcmp(value, "TRUE") ||
2112                !strcmp(value, "false") || !strcmp(value, "False") || !strcmp(value, "FALSE") ||
2113                !strcmp(value, "on") || !strcmp(value, "On") || !strcmp(value, "ON") ||
2114                !strcmp(value, "off") || !strcmp(value, "Off") || !strcmp(value, "OFF")) {
2115            *tag = YAML_BOOL_TAG;
2116            return 1;
2117        }
2118
2119        if (!strcmp(value, ".inf") || !strcmp(value, ".Inf") || !strcmp(value, ".INF") ||
2120                !strcmp(value, "+.inf") || !strcmp(value, "+.Inf") || !strcmp(value, "+.INF") ||
2121                !strcmp(value, "-.inf") || !strcmp(value, "-.Inf") || !strcmp(value, "-.INF") ||
2122                !strcmp(value, ".nan") || !strcmp(value, ".NaN") || !strcmp(value, ".NAN")) {
2123            *tag = YAML_FLOAT_TAG;
2124            return 1;
2125        }
2126
2127        old_errno = errno;
2128        errno = 0;
2129
2130        strtol((const char *)value, &tail, 0);
2131
2132        new_errno = errno;
2133        errno = old_errno;
2134
2135        if (!new_errno && !*tail) {
2136            *tag = YAML_INT_TAG;
2137            return 1;
2138        }
2139
2140        if (strlen(value) < sizeof(buffer))
2141        {
2142            strcpy(buffer, (const char *)value);
2143
2144            /* Replace a locale-dependent decimal point with a dot. */
2145
2146            for (pointer = buffer; *pointer; pointer++) {
2147                if (*pointer == decimal_point) {
2148                    *pointer = '.';
2149                    break;
2150                }
2151            }
2152
2153            old_errno = errno;
2154            errno = 0;
2155
2156            strtod(buffer, &tail);
2157
2158            new_errno = errno;
2159            errno = old_errno;
2160
2161            if (!new_errno && !*tail) {
2162                *tag = YAML_FLOAT_TAG;
2163                return 1;
2164            }
2165        }
2166    }
2167
2168    switch (node->type)
2169    {
2170        case YAML_SCALAR_NODE:
2171            *tag = YAML_STR_TAG;
2172            break;
2173        case YAML_SEQUENCE_NODE:
2174            *tag = YAML_SEQ_TAG;
2175            break;
2176        case YAML_MAPPING_NODE:
2177            *tag = YAML_MAP_TAG;
2178            break;
2179        default:
2180            assert(0);      /* Should never happen. */
2181    }
2182
2183    return 1;
2184}
2185
2186
2187/*****************************************************************************
2188 * Parser API
2189 *****************************************************************************/
2190
2191/*
2192 * Allocate a new parser object.
2193 */
2194
2195YAML_DECLARE(yaml_parser_t *)
2196yaml_parser_new(void)
2197{
2198    yaml_parser_t *parser = yaml_malloc(sizeof(yaml_parser_t));
2199
2200    if (!parser)
2201        return NULL;
2202
2203    memset(parser, 0, sizeof(yaml_parser_t));
2204
2205    if (!IOSTRING_INIT(parser, parser->raw_input, RAW_INPUT_BUFFER_CAPACITY))
2206        goto error;
2207    if (!IOSTRING_INIT(parser, parser->input, INPUT_BUFFER_CAPACITY))
2208        goto error;
2209    if (!QUEUE_INIT(parser, parser->tokens, INITIAL_QUEUE_CAPACITY))
2210        goto error;
2211    if (!STACK_INIT(parser, parser->indents, INITIAL_STACK_CAPACITY))
2212        goto error;
2213    if (!STACK_INIT(parser, parser->simple_keys, INITIAL_STACK_CAPACITY))
2214        goto error;
2215    if (!STACK_INIT(parser, parser->states, INITIAL_STACK_CAPACITY))
2216        goto error;
2217    if (!STACK_INIT(parser, parser->marks, INITIAL_STACK_CAPACITY))
2218        goto error;
2219    if (!STACK_INIT(parser, parser->tag_directives, INITIAL_STACK_CAPACITY))
2220        goto error;
2221
2222    return parser;
2223
2224error:
2225    yaml_parser_delete(parser);
2226
2227    return NULL;
2228}
2229
2230/*
2231 * Deallocate a parser object.
2232 */
2233
2234YAML_DECLARE(void)
2235yaml_parser_delete(yaml_parser_t *parser)
2236{
2237    assert(parser); /* Non-NULL parser object expected. */
2238
2239    IOSTRING_DEL(parser, parser->raw_input);
2240    IOSTRING_DEL(parser, parser->input);
2241    while (!QUEUE_EMPTY(parser, parser->tokens)) {
2242        yaml_token_destroy(&DEQUEUE(parser, parser->tokens));
2243    }
2244    QUEUE_DEL(parser, parser->tokens);
2245    STACK_DEL(parser, parser->indents);
2246    STACK_DEL(parser, parser->simple_keys);
2247    STACK_DEL(parser, parser->states);
2248    STACK_DEL(parser, parser->marks);
2249    while (!STACK_EMPTY(parser, parser->tag_directives)) {
2250        yaml_tag_directive_t tag_directive = POP(parser, parser->tag_directives);
2251        yaml_free(tag_directive.handle);
2252        yaml_free(tag_directive.prefix);
2253    }
2254    STACK_DEL(parser, parser->tag_directives);
2255
2256    memset(parser, 0, sizeof(yaml_parser_t));
2257
2258    yaml_free(parser);
2259}
2260
2261/*
2262 * Reset a parser object.
2263 */
2264
2265YAML_DECLARE(void)
2266yaml_parser_reset(yaml_parser_t *parser)
2267{
2268    yaml_parser_t copy = *parser;
2269
2270    assert(parser); /* Non-NULL parser object expected. */
2271
2272    while (!QUEUE_EMPTY(parser, parser->tokens)) {
2273        yaml_token_destroy(&DEQUEUE(parser, parser->tokens));
2274    }
2275    while (!STACK_EMPTY(parser, parser->tag_directives)) {
2276        yaml_tag_directive_t tag_directive = POP(parser, parser->tag_directives);
2277        yaml_free(tag_directive.handle);
2278        yaml_free(tag_directive.prefix);
2279    }
2280
2281    memset(parser, 0, sizeof(yaml_parser_t));
2282
2283    IOSTRING_SET(parser, parser->raw_input,
2284            copy.raw_input.buffer, copy.raw_input.capacity);
2285    IOSTRING_SET(parser, parser->input,
2286            copy.input.buffer, copy.input.capacity);
2287    QUEUE_SET(parser, parser->tokens,
2288            copy.tokens.list, copy.tokens.capacity);
2289    STACK_SET(parser, parser->indents,
2290            copy.indents.list, copy.indents.capacity);
2291    STACK_SET(parser, parser->simple_keys,
2292            copy.simple_keys.list, copy.simple_keys.capacity);
2293    STACK_SET(parser, parser->states,
2294            copy.states.list, copy.states.capacity);
2295    STACK_SET(parser, parser->marks,
2296            copy.marks.list, copy.marks.capacity);
2297    STACK_SET(parse, parser->tag_directives,
2298            copy.tag_directives.list, copy.tag_directives.capacity);
2299}
2300
2301/*
2302 * Get the current parser error.
2303 */
2304
2305YAML_DECLARE(yaml_error_t *)
2306yaml_parser_get_error(yaml_parser_t *parser)
2307{
2308    assert(parser); /* Non-NULL parser object expected. */
2309
2310    return &(parser->error);
2311}
2312
2313/*
2314 * Set a string input.
2315 */
2316
2317YAML_DECLARE(void)
2318yaml_parser_set_string_reader(yaml_parser_t *parser,
2319        const unsigned char *buffer, size_t length)
2320{
2321    assert(parser); /* Non-NULL parser object expected. */
2322    assert(!parser->reader);    /* You can set the input handler only once. */
2323    assert(buffer); /* Non-NULL input string expected. */
2324
2325    parser->reader = yaml_string_reader;
2326    parser->reader_data = &(parser->standard_reader_data);
2327
2328    parser->standard_reader_data.string.buffer = buffer;
2329    parser->standard_reader_data.string.pointer = 0;
2330    parser->standard_reader_data.string.length = length;
2331}
2332
2333/*
2334 * Set a file input.
2335 */
2336
2337YAML_DECLARE(void)
2338yaml_parser_set_file_reader(yaml_parser_t *parser, FILE *file)
2339{
2340    assert(parser); /* Non-NULL parser object expected. */
2341    assert(!parser->reader);    /* You can set the input handler only once. */
2342    assert(file);   /* Non-NULL file object expected. */
2343
2344    parser->reader = yaml_file_reader;
2345    parser->reader_data = &(parser->standard_reader_data);
2346
2347    parser->standard_reader_data.file = file;
2348}
2349
2350/*
2351 * Set a generic input.
2352 */
2353
2354YAML_DECLARE(void)
2355yaml_parser_set_reader(yaml_parser_t *parser,
2356        yaml_reader_t *reader, void *data)
2357{
2358    assert(parser); /* Non-NULL parser object expected. */
2359    assert(!parser->reader);    /* You can set the input handler only once. */
2360    assert(reader); /* Non-NULL read handler expected. */
2361
2362    parser->reader = reader;
2363    parser->reader_data = data;
2364}
2365
2366/*
2367 * Set a standard tag resolver.
2368 */
2369
2370YAML_DECLARE(void)
2371yaml_parser_set_standard_resolver(yaml_parser_t *parser)
2372{
2373    assert(parser); /* Non-NULL parser object expected. */
2374    assert(!parser->resolver);  /* You can set the tag resolver only once. */
2375
2376    parser->resolver = yaml_standard_resolver;
2377    parser->resolver_data = NULL;
2378}
2379
2380/*
2381 * Set a generic tag resolver.
2382 */
2383
2384YAML_DECLARE(void)
2385yaml_parser_set_resolver(yaml_parser_t *parser,
2386        yaml_resolver_t *resolver, void *data)
2387{
2388    assert(parser);     /* Non-NULL parser object expected. */
2389    assert(!parser->resolver);  /* You can set the tag resolver only once. */
2390    assert(resolver);   /* Non-NULL resolver is expected. */
2391
2392    parser->resolver = resolver;
2393    parser->resolver_data = data;
2394}
2395
2396/*
2397 * Set the source encoding.
2398 */
2399
2400YAML_DECLARE(void)
2401yaml_parser_set_encoding(yaml_parser_t *parser, yaml_encoding_t encoding)
2402{
2403    assert(parser); /* Non-NULL parser object expected. */
2404    assert(!parser->encoding);  /* Encoding is already set or detected. */
2405
2406    parser->encoding = encoding;
2407}
2408
2409/*****************************************************************************
2410 * Parser API
2411 *****************************************************************************/
2412
2413/*
2414 * Create a new emitter object.
2415 */
2416
2417YAML_DECLARE(yaml_emitter_t *)
2418yaml_emitter_new(void)
2419{
2420    yaml_emitter_t *emitter = yaml_malloc(sizeof(yaml_emitter_t));
2421
2422    if (!emitter)
2423        return NULL;
2424
2425    memset(emitter, 0, sizeof(yaml_emitter_t));
2426    if (!IOSTRING_INIT(emitter, emitter->output, OUTPUT_BUFFER_CAPACITY))
2427        goto error;
2428    if (!IOSTRING_INIT(emitter, emitter->raw_output, RAW_OUTPUT_BUFFER_CAPACITY))
2429        goto error;
2430    if (!STACK_INIT(emitter, emitter->states, INITIAL_STACK_CAPACITY))
2431        goto error;
2432    if (!QUEUE_INIT(emitter, emitter->events, INITIAL_QUEUE_CAPACITY))
2433        goto error;
2434    if (!STACK_INIT(emitter, emitter->indents, INITIAL_STACK_CAPACITY))
2435        goto error;
2436    if (!STACK_INIT(emitter, emitter->tag_directives, INITIAL_STACK_CAPACITY))
2437        goto error;
2438
2439    return emitter;
2440
2441error:
2442    yaml_emitter_delete(emitter);
2443
2444    return NULL;
2445}
2446
2447/*
2448 * Destroy an emitter object.
2449 */
2450
2451YAML_DECLARE(void)
2452yaml_emitter_delete(yaml_emitter_t *emitter)
2453{
2454    assert(emitter);    /* Non-NULL emitter object expected. */
2455
2456    IOSTRING_DEL(emitter, emitter->output);
2457    IOSTRING_DEL(emitter, emitter->raw_output);
2458    STACK_DEL(emitter, emitter->states);
2459    while (!QUEUE_EMPTY(emitter, emitter->events)) {
2460        yaml_event_destroy(&DEQUEUE(emitter, emitter->events));
2461    }
2462    QUEUE_DEL(emitter, emitter->events);
2463    STACK_DEL(emitter, emitter->indents);
2464    while (!STACK_EMPTY(empty, emitter->tag_directives)) {
2465        yaml_tag_directive_t tag_directive = POP(emitter, emitter->tag_directives);
2466        yaml_free(tag_directive.handle);
2467        yaml_free(tag_directive.prefix);
2468    }
2469    STACK_DEL(emitter, emitter->tag_directives);
2470    yaml_free(emitter->anchors);
2471
2472    memset(emitter, 0, sizeof(yaml_emitter_t));
2473    yaml_free(emitter);
2474}
2475
2476/*
2477 * Reset an emitter object.
2478 */
2479
2480YAML_DECLARE(void)
2481yaml_emitter_reset(yaml_emitter_t *emitter)
2482{
2483    yaml_emitter_t copy = *emitter;
2484
2485    assert(emitter);    /* Non-NULL emitter object expected. */
2486
2487    while (!QUEUE_EMPTY(emitter, emitter->events)) {
2488        yaml_event_destroy(&DEQUEUE(emitter, emitter->events));
2489    }
2490    while (!STACK_EMPTY(empty, emitter->tag_directives)) {
2491        yaml_tag_directive_t tag_directive = POP(emitter, emitter->tag_directives);
2492        yaml_free(tag_directive.handle);
2493        yaml_free(tag_directive.prefix);
2494    }
2495
2496    memset(emitter, 0, sizeof(yaml_emitter_t));
2497
2498    IOSTRING_SET(emitter, emitter->output,
2499            copy.output.buffer, copy.output.capacity);
2500    IOSTRING_SET(emitter, emitter->raw_output,
2501            copy.raw_output.buffer, copy.raw_output.capacity);
2502    STACK_SET(emitter, emitter->states,
2503            copy.states.list, copy.states.capacity);
2504    QUEUE_SET(emitter, emitter->events,
2505            copy.events.list, copy.events.capacity);
2506    STACK_SET(emitter, emitter->indents,
2507            copy.indents.list, copy.indents.capacity);
2508    STACK_SET(emitter, emitter->tag_directives,
2509            copy.tag_directives.list, copy.tag_directives.capacity);
2510}
2511
2512/*
2513 * Get the current emitter error.
2514 */
2515
2516YAML_DECLARE(yaml_error_t *)
2517yaml_emitter_get_error(yaml_emitter_t *emitter)
2518{
2519    assert(emitter);    /* Non-NULL emitter object expected. */
2520
2521    return &(emitter->error);
2522}
2523
2524/*
2525 * Set a string output.
2526 */
2527
2528YAML_DECLARE(void)
2529yaml_emitter_set_string_writer(yaml_emitter_t *emitter,
2530        unsigned char *buffer, size_t capacity, size_t *length)
2531{
2532    assert(emitter);    /* Non-NULL emitter object expected. */
2533    assert(!emitter->writer);   /* You can set the output only once. */
2534    assert(buffer);     /* Non-NULL output string expected. */
2535
2536    emitter->writer = yaml_string_writer;
2537    emitter->writer_data = &(emitter->standard_writer_data);
2538
2539    emitter->standard_writer_data.string.buffer = buffer;
2540    emitter->standard_writer_data.string.pointer = 0;
2541    emitter->standard_writer_data.string.capacity = capacity;
2542    emitter->standard_writer_data.length = length;
2543
2544    *length = 0;
2545}
2546
2547/*
2548 * Set a file output.
2549 */
2550
2551YAML_DECLARE(void)
2552yaml_emitter_set_file_writer(yaml_emitter_t *emitter, FILE *file)
2553{
2554    assert(emitter);    /* Non-NULL emitter object expected. */
2555    assert(!emitter->writer);   /* You can set the output only once. */
2556    assert(file);       /* Non-NULL file object expected. */
2557
2558    emitter->writer = yaml_string_writer;
2559    emitter->writer_data = &(emitter->standard_writer_data);
2560
2561    emitter->standard_writer_data.file = file;
2562}
2563
2564/*
2565 * Set a generic output handler.
2566 */
2567
2568YAML_DECLARE(void)
2569yaml_emitter_set_writer(yaml_emitter_t *emitter,
2570        yaml_writer_t *writer, void *data)
2571{
2572    assert(emitter);    /* Non-NULL emitter object expected. */
2573    assert(!emitter->writer);   /* You can set the output only once. */
2574    assert(writer); /* Non-NULL handler object expected. */
2575
2576    emitter->writer = writer;
2577    emitter->writer_data = data;
2578}
2579
2580/*
2581 * Set a standard tag resolver.
2582 */
2583
2584YAML_DECLARE(void)
2585yaml_emitter_set_standard_resolver(yaml_emitter_t *emitter)
2586{
2587    assert(emitter);    /* Non-NULL emitter object expected. */
2588    assert(!emitter->resolver); /* You can set the tag resolver only once. */
2589
2590    emitter->resolver = yaml_standard_resolver;
2591    emitter->resolver_data = NULL;
2592}
2593
2594/*
2595 * Set a generic tag resolver.
2596 */
2597
2598YAML_DECLARE(void)
2599yaml_emitter_set_resolver(yaml_emitter_t *emitter,
2600        yaml_resolver_t *resolver, void *data)
2601{
2602    assert(emitter);    /* Non-NULL emitter object expected. */
2603    assert(!emitter->resolver); /* You can set the tag resolver only once. */
2604    assert(resolver);   /* Non-NULL resolver is expected. */
2605
2606    emitter->resolver = resolver;
2607    emitter->resolver_data = data;
2608}
2609
2610/*
2611 * Set the output encoding.
2612 */
2613
2614YAML_DECLARE(void)
2615yaml_emitter_set_encoding(yaml_emitter_t *emitter, yaml_encoding_t encoding)
2616{
2617    assert(emitter);    /* Non-NULL emitter object expected. */
2618    assert(!emitter->encoding);     /* You can set encoding only once. */
2619
2620    emitter->encoding = encoding;
2621}
2622
2623/*
2624 * Set the canonical output style.
2625 */
2626
2627YAML_DECLARE(void)
2628yaml_emitter_set_canonical(yaml_emitter_t *emitter, int is_canonical)
2629{
2630    assert(emitter);    /* Non-NULL emitter object expected. */
2631
2632    emitter->is_canonical = (is_canonical != 0);
2633}
2634
2635/*
2636 * Set the indentation increment.
2637 */
2638
2639YAML_DECLARE(void)
2640yaml_emitter_set_indent(yaml_emitter_t *emitter, int indent)
2641{
2642    assert(emitter);    /* Non-NULL emitter object expected. */
2643
2644    emitter->best_indent = (1 < indent && indent < 10) ? indent : 2;
2645}
2646
2647/*
2648 * Set the preferred line width.
2649 */
2650
2651YAML_DECLARE(void)
2652yaml_emitter_set_width(yaml_emitter_t *emitter, int width)
2653{
2654    assert(emitter);    /* Non-NULL emitter object expected. */
2655
2656    emitter->best_width = (width >= 0) ? width : -1;
2657}
2658
2659/*
2660 * Set if unescaped non-ASCII characters are allowed.
2661 */
2662
2663YAML_DECLARE(void)
2664yaml_emitter_set_unicode(yaml_emitter_t *emitter, int is_unicode)
2665{
2666    assert(emitter);    /* Non-NULL emitter object expected. */
2667
2668    emitter->is_unicode = (is_unicode != 0);
2669}
2670
2671/*
2672 * Set the preferred line break character.
2673 */
2674
2675YAML_DECLARE(void)
2676yaml_emitter_set_break(yaml_emitter_t *emitter, yaml_break_t line_break)
2677{
2678    assert(emitter);    /* Non-NULL emitter object expected. */
2679
2680    emitter->line_break = line_break;
2681}
2682
Note: See TracBrowser for help on using the repository browser.