1
2#include "yaml_private.h"
3
4/*
5 * Get the library version.
6 */
7
8YAML_DECLARE(const char *)
9yaml_get_version_string(void)
10{
11    return YAML_VERSION_STRING;
12}
13
14/*
15 * Get the library version numbers.
16 */
17
18YAML_DECLARE(void)
19yaml_get_version(int *major, int *minor, int *patch)
20{
21    *major = YAML_VERSION_MAJOR;
22    *minor = YAML_VERSION_MINOR;
23    *patch = YAML_VERSION_PATCH;
24}
25
26/*
27 * Allocate a dynamic memory block.
28 */
29
30YAML_DECLARE(void *)
31yaml_malloc(size_t size)
32{
33    return malloc(size ? size : 1);
34}
35
36/*
37 * Reallocate a dynamic memory block.
38 */
39
40YAML_DECLARE(void *)
41yaml_realloc(void *ptr, size_t size)
42{
43    return ptr ? realloc(ptr, size ? size : 1) : malloc(size ? size : 1);
44}
45
46/*
47 * Free a dynamic memory block.
48 */
49
50YAML_DECLARE(void)
51yaml_free(void *ptr)
52{
53    if (ptr) free(ptr);
54}
55
56/*
57 * Duplicate a string.
58 */
59
60YAML_DECLARE(yaml_char_t *)
61yaml_strdup(const yaml_char_t *str)
62{
63    if (!str)
64        return NULL;
65
66    return (yaml_char_t *)strdup((char *)str);
67}
68
69/*
70 * Extend a string.
71 */
72
73YAML_DECLARE(int)
74yaml_string_extend(yaml_char_t **start,
75        yaml_char_t **pointer, yaml_char_t **end)
76{
77    yaml_char_t *new_start = yaml_realloc(*start, (*end - *start)*2);
78
79    if (!new_start) return 0;
80
81    memset(new_start + (*end - *start), 0, *end - *start);
82
83    *pointer = new_start + (*pointer - *start);
84    *end = new_start + (*end - *start)*2;
85    *start = new_start;
86
87    return 1;
88}
89
90/*
91 * Append a string B to a string A.
92 */
93
94YAML_DECLARE(int)
95yaml_string_join(
96        yaml_char_t **a_start, yaml_char_t **a_pointer, yaml_char_t **a_end,
97        yaml_char_t **b_start, yaml_char_t **b_pointer, yaml_char_t **b_end)
98{
99    if (*b_start == *b_pointer)
100        return 1;
101
102    while (*a_end - *a_pointer <= *b_pointer - *b_start) {
103        if (!yaml_string_extend(a_start, a_pointer, a_end))
104            return 0;
105    }
106
107    memcpy(*a_pointer, *b_start, *b_pointer - *b_start);
108    *a_pointer += *b_pointer - *b_start;
109
110    return 1;
111}
112
113/*
114 * Extend a stack.
115 */
116
117YAML_DECLARE(int)
118yaml_stack_extend(void **start, void **top, void **end)
119{
120    void *new_start = yaml_realloc(*start, ((char *)*end - (char *)*start)*2);
121
122    if (!new_start) return 0;
123
124    *top = (char *)new_start + ((char *)*top - (char *)*start);
125    *end = (char *)new_start + ((char *)*end - (char *)*start)*2;
126    *start = new_start;
127
128    return 1;
129}
130
131/*
132 * Extend or move a queue.
133 */
134
135YAML_DECLARE(int)
136yaml_queue_extend(void **start, void **head, void **tail, void **end)
137{
138    /* Check if we need to resize the queue. */
139
140    if (*start == *head && *tail == *end) {
141        void *new_start = yaml_realloc(*start,
142                ((char *)*end - (char *)*start)*2);
143
144        if (!new_start) return 0;
145
146        *head = (char *)new_start + ((char *)*head - (char *)*start);
147        *tail = (char *)new_start + ((char *)*tail - (char *)*start);
148        *end = (char *)new_start + ((char *)*end - (char *)*start)*2;
149        *start = new_start;
150    }
151
152    /* Check if we need to move the queue at the beginning of the buffer. */
153
154    if (*tail == *end) {
155        if (*head != *tail) {
156            memmove(*start, *head, (char *)*tail - (char *)*head);
157        }
158        *tail = (char *)*tail - (char *)*head + (char *)*start;
159        *head = *start;
160    }
161
162    return 1;
163}
164
165
166/*
167 * Create a new parser object.
168 */
169
170YAML_DECLARE(int)
171yaml_parser_initialize(yaml_parser_t *parser)
172{
173    assert(parser);     /* Non-NULL parser object expected. */
174
175    memset(parser, 0, sizeof(yaml_parser_t));
176    if (!BUFFER_INIT(parser, parser->raw_buffer, INPUT_RAW_BUFFER_SIZE))
177        goto error;
178    if (!BUFFER_INIT(parser, parser->buffer, INPUT_BUFFER_SIZE))
179        goto error;
180    if (!QUEUE_INIT(parser, parser->tokens, INITIAL_QUEUE_SIZE))
181        goto error;
182    if (!STACK_INIT(parser, parser->indents, INITIAL_STACK_SIZE))
183        goto error;
184    if (!STACK_INIT(parser, parser->simple_keys, INITIAL_STACK_SIZE))
185        goto error;
186    if (!STACK_INIT(parser, parser->states, INITIAL_STACK_SIZE))
187        goto error;
188    if (!STACK_INIT(parser, parser->marks, INITIAL_STACK_SIZE))
189        goto error;
190    if (!STACK_INIT(parser, parser->tag_directives, INITIAL_STACK_SIZE))
191        goto error;
192
193    return 1;
194
195error:
196
197    BUFFER_DEL(parser, parser->raw_buffer);
198    BUFFER_DEL(parser, parser->buffer);
199    QUEUE_DEL(parser, parser->tokens);
200    STACK_DEL(parser, parser->indents);
201    STACK_DEL(parser, parser->simple_keys);
202    STACK_DEL(parser, parser->states);
203    STACK_DEL(parser, parser->marks);
204    STACK_DEL(parser, parser->tag_directives);
205
206    return 0;
207}
208
209/*
210 * Destroy a parser object.
211 */
212
213YAML_DECLARE(void)
214yaml_parser_delete(yaml_parser_t *parser)
215{
216    assert(parser); /* Non-NULL parser object expected. */
217
218    BUFFER_DEL(parser, parser->raw_buffer);
219    BUFFER_DEL(parser, parser->buffer);
220    while (!QUEUE_EMPTY(parser, parser->tokens)) {
221        yaml_token_delete(&DEQUEUE(parser, parser->tokens));
222    }
223    QUEUE_DEL(parser, parser->tokens);
224    STACK_DEL(parser, parser->indents);
225    STACK_DEL(parser, parser->simple_keys);
226    STACK_DEL(parser, parser->states);
227    STACK_DEL(parser, parser->marks);
228    while (!STACK_EMPTY(parser, parser->tag_directives)) {
229        yaml_tag_directive_t tag_directive = POP(parser, parser->tag_directives);
230        yaml_free(tag_directive.handle);
231        yaml_free(tag_directive.prefix);
232    }
233    STACK_DEL(parser, parser->tag_directives);
234
235    memset(parser, 0, sizeof(yaml_parser_t));
236}
237
238/*
239 * String read handler.
240 */
241
242static int
243yaml_string_read_handler(void *data, unsigned char *buffer, size_t size,
244        size_t *size_read)
245{
246    yaml_parser_t *parser = data;
247
248    if (parser->input.string.current == parser->input.string.end) {
249        *size_read = 0;
250        return 1;
251    }
252
253    if (size > (size_t)(parser->input.string.end
254                - parser->input.string.current)) {
255        size = parser->input.string.end - parser->input.string.current;
256    }
257
258    memcpy(buffer, parser->input.string.current, size);
259    parser->input.string.current += size;
260    *size_read = size;
261    return 1;
262}
263
264/*
265 * File read handler.
266 */
267
268static int
269yaml_file_read_handler(void *data, unsigned char *buffer, size_t size,
270        size_t *size_read)
271{
272    yaml_parser_t *parser = data;
273
274    *size_read = fread(buffer, 1, size, parser->input.file);
275    return !ferror(parser->input.file);
276}
277
278/*
279 * Set a string input.
280 */
281
282YAML_DECLARE(void)
283yaml_parser_set_input_string(yaml_parser_t *parser,
284        const unsigned char *input, size_t size)
285{
286    assert(parser); /* Non-NULL parser object expected. */
287    assert(!parser->read_handler);  /* You can set the source only once. */
288    assert(input);  /* Non-NULL input string expected. */
289
290    parser->read_handler = yaml_string_read_handler;
291    parser->read_handler_data = parser;
292
293    parser->input.string.start = input;
294    parser->input.string.current = input;
295    parser->input.string.end = input+size;
296}
297
298/*
299 * Set a file input.
300 */
301
302YAML_DECLARE(void)
303yaml_parser_set_input_file(yaml_parser_t *parser, FILE *file)
304{
305    assert(parser); /* Non-NULL parser object expected. */
306    assert(!parser->read_handler);  /* You can set the source only once. */
307    assert(file);   /* Non-NULL file object expected. */
308
309    parser->read_handler = yaml_file_read_handler;
310    parser->read_handler_data = parser;
311
312    parser->input.file = file;
313}
314
315/*
316 * Set a generic input.
317 */
318
319YAML_DECLARE(void)
320yaml_parser_set_input(yaml_parser_t *parser,
321        yaml_read_handler_t *handler, void *data)
322{
323    assert(parser); /* Non-NULL parser object expected. */
324    assert(!parser->read_handler);  /* You can set the source only once. */
325    assert(handler);    /* Non-NULL read handler expected. */
326
327    parser->read_handler = handler;
328    parser->read_handler_data = data;
329}
330
331/*
332 * Set the source encoding.
333 */
334
335YAML_DECLARE(void)
336yaml_parser_set_encoding(yaml_parser_t *parser, yaml_encoding_t encoding)
337{
338    assert(parser); /* Non-NULL parser object expected. */
339    assert(!parser->encoding); /* Encoding is already set or detected. */
340
341    parser->encoding = encoding;
342}
343
344/*
345 * Create a new emitter object.
346 */
347
348YAML_DECLARE(int)
349yaml_emitter_initialize(yaml_emitter_t *emitter)
350{
351    assert(emitter);    /* Non-NULL emitter object expected. */
352
353    memset(emitter, 0, sizeof(yaml_emitter_t));
354    if (!BUFFER_INIT(emitter, emitter->buffer, OUTPUT_BUFFER_SIZE))
355        goto error;
356    if (!BUFFER_INIT(emitter, emitter->raw_buffer, OUTPUT_RAW_BUFFER_SIZE))
357        goto error;
358    if (!STACK_INIT(emitter, emitter->states, INITIAL_STACK_SIZE))
359        goto error;
360    if (!QUEUE_INIT(emitter, emitter->events, INITIAL_QUEUE_SIZE))
361        goto error;
362    if (!STACK_INIT(emitter, emitter->indents, INITIAL_STACK_SIZE))
363        goto error;
364    if (!STACK_INIT(emitter, emitter->tag_directives, INITIAL_STACK_SIZE))
365        goto error;
366
367    return 1;
368
369error:
370
371    BUFFER_DEL(emitter, emitter->buffer);
372    BUFFER_DEL(emitter, emitter->raw_buffer);
373    STACK_DEL(emitter, emitter->states);
374    QUEUE_DEL(emitter, emitter->events);
375    STACK_DEL(emitter, emitter->indents);
376    STACK_DEL(emitter, emitter->tag_directives);
377
378    return 0;
379}
380
381/*
382 * Destroy an emitter object.
383 */
384
385YAML_DECLARE(void)
386yaml_emitter_delete(yaml_emitter_t *emitter)
387{
388    assert(emitter);    /* Non-NULL emitter object expected. */
389
390    BUFFER_DEL(emitter, emitter->buffer);
391    BUFFER_DEL(emitter, emitter->raw_buffer);
392    STACK_DEL(emitter, emitter->states);
393    while (!QUEUE_EMPTY(emitter, emitter->events)) {
394        yaml_event_delete(&DEQUEUE(emitter, emitter->events));
395    }
396    QUEUE_DEL(emitter, emitter->events);
397    STACK_DEL(emitter, emitter->indents);
398    while (!STACK_EMPTY(empty, emitter->tag_directives)) {
399        yaml_tag_directive_t tag_directive = POP(emitter, emitter->tag_directives);
400        yaml_free(tag_directive.handle);
401        yaml_free(tag_directive.prefix);
402    }
403    STACK_DEL(emitter, emitter->tag_directives);
404    yaml_free(emitter->anchors);
405
406    memset(emitter, 0, sizeof(yaml_emitter_t));
407}
408
409/*
410 * String write handler.
411 */
412
413static int
414yaml_string_write_handler(void *data, unsigned char *buffer, size_t size)
415{
416    yaml_emitter_t *emitter = data;
417
418    if (emitter->output.string.size + *emitter->output.string.size_written
419            < size) {
420        memcpy(emitter->output.string.buffer
421                + *emitter->output.string.size_written,
422                buffer,
423                emitter->output.string.size
424                - *emitter->output.string.size_written);
425        *emitter->output.string.size_written = emitter->output.string.size;
426        return 0;
427    }
428
429    memcpy(emitter->output.string.buffer
430            + *emitter->output.string.size_written, buffer, size);
431    *emitter->output.string.size_written += size;
432    return 1;
433}
434
435/*
436 * File write handler.
437 */
438
439static int
440yaml_file_write_handler(void *data, unsigned char *buffer, size_t size)
441{
442    yaml_emitter_t *emitter = data;
443
444    return (fwrite(buffer, 1, size, emitter->output.file) == size);
445}
446/*
447 * Set a string output.
448 */
449
450YAML_DECLARE(void)
451yaml_emitter_set_output_string(yaml_emitter_t *emitter,
452        unsigned char *output, size_t size, size_t *size_written)
453{
454    assert(emitter);    /* Non-NULL emitter object expected. */
455    assert(!emitter->write_handler);    /* You can set the output only once. */
456    assert(output);     /* Non-NULL output string expected. */
457
458    emitter->write_handler = yaml_string_write_handler;
459    emitter->write_handler_data = emitter;
460
461    emitter->output.string.buffer = output;
462    emitter->output.string.size = size;
463    emitter->output.string.size_written = size_written;
464    *size_written = 0;
465}
466
467/*
468 * Set a file output.
469 */
470
471YAML_DECLARE(void)
472yaml_emitter_set_output_file(yaml_emitter_t *emitter, FILE *file)
473{
474    assert(emitter);    /* Non-NULL emitter object expected. */
475    assert(!emitter->write_handler);    /* You can set the output only once. */
476    assert(file);       /* Non-NULL file object expected. */
477
478    emitter->write_handler = yaml_file_write_handler;
479    emitter->write_handler_data = emitter;
480
481    emitter->output.file = file;
482}
483
484/*
485 * Set a generic output handler.
486 */
487
488YAML_DECLARE(void)
489yaml_emitter_set_output(yaml_emitter_t *emitter,
490        yaml_write_handler_t *handler, void *data)
491{
492    assert(emitter);    /* Non-NULL emitter object expected. */
493    assert(!emitter->write_handler);    /* You can set the output only once. */
494    assert(handler);    /* Non-NULL handler object expected. */
495
496    emitter->write_handler = handler;
497    emitter->write_handler_data = data;
498}
499
500/*
501 * Set the output encoding.
502 */
503
504YAML_DECLARE(void)
505yaml_emitter_set_encoding(yaml_emitter_t *emitter, yaml_encoding_t encoding)
506{
507    assert(emitter);    /* Non-NULL emitter object expected. */
508    assert(!emitter->encoding);     /* You can set encoding only once. */
509
510    emitter->encoding = encoding;
511}
512
513/*
514 * Set the canonical output style.
515 */
516
517YAML_DECLARE(void)
518yaml_emitter_set_canonical(yaml_emitter_t *emitter, int canonical)
519{
520    assert(emitter);    /* Non-NULL emitter object expected. */
521
522    emitter->canonical = (canonical != 0);
523}
524
525/*
526 * Set the indentation increment.
527 */
528
529YAML_DECLARE(void)
530yaml_emitter_set_indent(yaml_emitter_t *emitter, int indent)
531{
532    assert(emitter);    /* Non-NULL emitter object expected. */
533
534    emitter->best_indent = (1 < indent && indent < 10) ? indent : 2;
535}
536
537/*
538 * Set the preferred line width.
539 */
540
541YAML_DECLARE(void)
542yaml_emitter_set_width(yaml_emitter_t *emitter, int width)
543{
544    assert(emitter);    /* Non-NULL emitter object expected. */
545
546    emitter->best_width = (width >= 0) ? width : -1;
547}
548
549/*
550 * Set if unescaped non-ASCII characters are allowed.
551 */
552
553YAML_DECLARE(void)
554yaml_emitter_set_unicode(yaml_emitter_t *emitter, int unicode)
555{
556    assert(emitter);    /* Non-NULL emitter object expected. */
557
558    emitter->unicode = (unicode != 0);
559}
560
561/*
562 * Set the preferred line break character.
563 */
564
565YAML_DECLARE(void)
566yaml_emitter_set_break(yaml_emitter_t *emitter, yaml_break_t line_break)
567{
568    assert(emitter);    /* Non-NULL emitter object expected. */
569
570    emitter->line_break = line_break;
571}
572
573/*
574 * Destroy a token object.
575 */
576
577YAML_DECLARE(void)
578yaml_token_delete(yaml_token_t *token)
579{
580    assert(token);  /* Non-NULL token object expected. */
581
582    switch (token->type)
583    {
584        case YAML_TAG_DIRECTIVE_TOKEN:
585            yaml_free(token->data.tag_directive.handle);
586            yaml_free(token->data.tag_directive.prefix);
587            break;
588
589        case YAML_ALIAS_TOKEN:
590            yaml_free(token->data.alias.value);
591            break;
592
593        case YAML_ANCHOR_TOKEN:
594            yaml_free(token->data.anchor.value);
595            break;
596
597        case YAML_TAG_TOKEN:
598            yaml_free(token->data.tag.handle);
599            yaml_free(token->data.tag.suffix);
600            break;
601
602        case YAML_SCALAR_TOKEN:
603            yaml_free(token->data.scalar.value);
604            break;
605
606        default:
607            break;
608    }
609
610    memset(token, 0, sizeof(yaml_token_t));
611}
612
613/*
614 * Check if a string is a valid UTF-8 sequence.
615 *
616 * Check 'reader.c' for more details on UTF-8 encoding.
617 */
618
619static int
620yaml_check_utf8(yaml_char_t *start, size_t length)
621{
622    yaml_char_t *end = start+length;
623    yaml_char_t *pointer = start;
624
625    while (pointer < end) {
626        unsigned char octet;
627        unsigned int width;
628        unsigned int value;
629        size_t k;
630
631        octet = pointer[0];
632        width = (octet & 0x80) == 0x00 ? 1 :
633                (octet & 0xE0) == 0xC0 ? 2 :
634                (octet & 0xF0) == 0xE0 ? 3 :
635                (octet & 0xF8) == 0xF0 ? 4 : 0;
636        value = (octet & 0x80) == 0x00 ? octet & 0x7F :
637                (octet & 0xE0) == 0xC0 ? octet & 0x1F :
638                (octet & 0xF0) == 0xE0 ? octet & 0x0F :
639                (octet & 0xF8) == 0xF0 ? octet & 0x07 : 0;
640        if (!width) return 0;
641        if (pointer+width > end) return 0;
642        for (k = 1; k < width; k ++) {
643            octet = pointer[k];
644            if ((octet & 0xC0) != 0x80) return 0;
645            value = (value << 6) + (octet & 0x3F);
646        }
647        if (!((width == 1) ||
648            (width == 2 && value >= 0x80) ||
649            (width == 3 && value >= 0x800) ||
650            (width == 4 && value >= 0x10000))) return 0;
651
652        pointer += width;
653    }
654
655    return 1;
656}
657
658/*
659 * Create STREAM-START.
660 */
661
662YAML_DECLARE(int)
663yaml_stream_start_event_initialize(yaml_event_t *event,
664        yaml_encoding_t encoding)
665{
666    yaml_mark_t mark = { 0, 0, 0 };
667
668    assert(event);  /* Non-NULL event object is expected. */
669
670    STREAM_START_EVENT_INIT(*event, encoding, mark, mark);
671
672    return 1;
673}
674
675/*
676 * Create STREAM-END.
677 */
678
679YAML_DECLARE(int)
680yaml_stream_end_event_initialize(yaml_event_t *event)
681{
682    yaml_mark_t mark = { 0, 0, 0 };
683
684    assert(event);  /* Non-NULL event object is expected. */
685
686    STREAM_END_EVENT_INIT(*event, mark, mark);
687
688    return 1;
689}
690
691/*
692 * Create DOCUMENT-START.
693 */
694
695YAML_DECLARE(int)
696yaml_document_start_event_initialize(yaml_event_t *event,
697        yaml_version_directive_t *version_directive,
698        yaml_tag_directive_t *tag_directives_start,
699        yaml_tag_directive_t *tag_directives_end,
700        int implicit)
701{
702    struct {
703        yaml_error_type_t error;
704    } context;
705    yaml_mark_t mark = { 0, 0, 0 };
706    yaml_version_directive_t *version_directive_copy = NULL;
707    struct {
708        yaml_tag_directive_t *start;
709        yaml_tag_directive_t *end;
710        yaml_tag_directive_t *top;
711    } tag_directives_copy = { NULL, NULL, NULL };
712    yaml_tag_directive_t value = { NULL, NULL };
713
714    assert(event);          /* Non-NULL event object is expected. */
715    assert((tag_directives_start && tag_directives_end) ||
716            (tag_directives_start == tag_directives_end));
717                            /* Valid tag directives are expected. */
718
719    if (version_directive) {
720        version_directive_copy = yaml_malloc(sizeof(yaml_version_directive_t));
721        if (!version_directive_copy) goto error;
722        version_directive_copy->major = version_directive->major;
723        version_directive_copy->minor = version_directive->minor;
724    }
725
726    if (tag_directives_start != tag_directives_end) {
727        yaml_tag_directive_t *tag_directive;
728        if (!STACK_INIT(&context, tag_directives_copy, INITIAL_STACK_SIZE))
729            goto error;
730        for (tag_directive = tag_directives_start;
731                tag_directive != tag_directives_end; tag_directive ++) {
732            assert(tag_directive->handle);
733            assert(tag_directive->prefix);
734            if (!yaml_check_utf8(tag_directive->handle,
735                        strlen((char *)tag_directive->handle)))
736                goto error;
737            if (!yaml_check_utf8(tag_directive->prefix,
738                        strlen((char *)tag_directive->prefix)))
739                goto error;
740            value.handle = yaml_strdup(tag_directive->handle);
741            value.prefix = yaml_strdup(tag_directive->prefix);
742            if (!value.handle || !value.prefix) goto error;
743            if (!PUSH(&context, tag_directives_copy, value))
744                goto error;
745            value.handle = NULL;
746            value.prefix = NULL;
747        }
748    }
749
750    DOCUMENT_START_EVENT_INIT(*event, version_directive_copy,
751            tag_directives_copy.start, tag_directives_copy.top,
752            implicit, mark, mark);
753
754    return 1;
755
756error:
757    yaml_free(version_directive_copy);
758    while (!STACK_EMPTY(context, tag_directives_copy)) {
759        yaml_tag_directive_t value = POP(context, tag_directives_copy);
760        yaml_free(value.handle);
761        yaml_free(value.prefix);
762    }
763    STACK_DEL(context, tag_directives_copy);
764    yaml_free(value.handle);
765    yaml_free(value.prefix);
766
767    return 0;
768}
769
770/*
771 * Create DOCUMENT-END.
772 */
773
774YAML_DECLARE(int)
775yaml_document_end_event_initialize(yaml_event_t *event, int implicit)
776{
777    yaml_mark_t mark = { 0, 0, 0 };
778
779    assert(event);      /* Non-NULL emitter object is expected. */
780
781    DOCUMENT_END_EVENT_INIT(*event, implicit, mark, mark);
782
783    return 1;
784}
785
786/*
787 * Create ALIAS.
788 */
789
790YAML_DECLARE(int)
791yaml_alias_event_initialize(yaml_event_t *event, yaml_char_t *anchor)
792{
793    yaml_mark_t mark = { 0, 0, 0 };
794    yaml_char_t *anchor_copy = NULL;
795
796    assert(event);      /* Non-NULL event object is expected. */
797    assert(anchor);     /* Non-NULL anchor is expected. */
798
799    if (!yaml_check_utf8(anchor, strlen((char *)anchor))) return 0;
800
801    anchor_copy = yaml_strdup(anchor);
802    if (!anchor_copy)
803        return 0;
804
805    ALIAS_EVENT_INIT(*event, anchor_copy, mark, mark);
806
807    return 1;
808}
809
810/*
811 * Create SCALAR.
812 */
813
814YAML_DECLARE(int)
815yaml_scalar_event_initialize(yaml_event_t *event,
816        yaml_char_t *anchor, yaml_char_t *tag,
817        yaml_char_t *value, int length,
818        int plain_implicit, int quoted_implicit,
819        yaml_scalar_style_t style)
820{
821    yaml_mark_t mark = { 0, 0, 0 };
822    yaml_char_t *anchor_copy = NULL;
823    yaml_char_t *tag_copy = NULL;
824    yaml_char_t *value_copy = NULL;
825
826    assert(event);      /* Non-NULL event object is expected. */
827    assert(value);      /* Non-NULL anchor is expected. */
828
829    if (anchor) {
830        if (!yaml_check_utf8(anchor, strlen((char *)anchor))) goto error;
831        anchor_copy = yaml_strdup(anchor);
832        if (!anchor_copy) goto error;
833    }
834
835    if (tag) {
836        if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error;
837        tag_copy = yaml_strdup(tag);
838        if (!tag_copy) goto error;
839    }
840
841    if (length < 0) {
842        length = strlen((char *)value);
843    }
844
845    if (!yaml_check_utf8(value, length)) goto error;
846    value_copy = yaml_malloc(length+1);
847    if (!value_copy) goto error;
848    memcpy(value_copy, value, length);
849    value_copy[length] = '\0';
850
851    SCALAR_EVENT_INIT(*event, anchor_copy, tag_copy, value_copy, length,
852            plain_implicit, quoted_implicit, style, mark, mark);
853
854    return 1;
855
856error:
857    yaml_free(anchor_copy);
858    yaml_free(tag_copy);
859    yaml_free(value_copy);
860
861    return 0;
862}
863
864/*
865 * Create SEQUENCE-START.
866 */
867
868YAML_DECLARE(int)
869yaml_sequence_start_event_initialize(yaml_event_t *event,
870        yaml_char_t *anchor, yaml_char_t *tag, int implicit,
871        yaml_sequence_style_t style)
872{
873    yaml_mark_t mark = { 0, 0, 0 };
874    yaml_char_t *anchor_copy = NULL;
875    yaml_char_t *tag_copy = NULL;
876
877    assert(event);      /* Non-NULL event object is expected. */
878
879    if (anchor) {
880        if (!yaml_check_utf8(anchor, strlen((char *)anchor))) goto error;
881        anchor_copy = yaml_strdup(anchor);
882        if (!anchor_copy) goto error;
883    }
884
885    if (tag) {
886        if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error;
887        tag_copy = yaml_strdup(tag);
888        if (!tag_copy) goto error;
889    }
890
891    SEQUENCE_START_EVENT_INIT(*event, anchor_copy, tag_copy,
892            implicit, style, mark, mark);
893
894    return 1;
895
896error:
897    yaml_free(anchor_copy);
898    yaml_free(tag_copy);
899
900    return 0;
901}
902
903/*
904 * Create SEQUENCE-END.
905 */
906
907YAML_DECLARE(int)
908yaml_sequence_end_event_initialize(yaml_event_t *event)
909{
910    yaml_mark_t mark = { 0, 0, 0 };
911
912    assert(event);      /* Non-NULL event object is expected. */
913
914    SEQUENCE_END_EVENT_INIT(*event, mark, mark);
915
916    return 1;
917}
918
919/*
920 * Create MAPPING-START.
921 */
922
923YAML_DECLARE(int)
924yaml_mapping_start_event_initialize(yaml_event_t *event,
925        yaml_char_t *anchor, yaml_char_t *tag, int implicit,
926        yaml_mapping_style_t style)
927{
928    yaml_mark_t mark = { 0, 0, 0 };
929    yaml_char_t *anchor_copy = NULL;
930    yaml_char_t *tag_copy = NULL;
931
932    assert(event);      /* Non-NULL event object is expected. */
933
934    if (anchor) {
935        if (!yaml_check_utf8(anchor, strlen((char *)anchor))) goto error;
936        anchor_copy = yaml_strdup(anchor);
937        if (!anchor_copy) goto error;
938    }
939
940    if (tag) {
941        if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error;
942        tag_copy = yaml_strdup(tag);
943        if (!tag_copy) goto error;
944    }
945
946    MAPPING_START_EVENT_INIT(*event, anchor_copy, tag_copy,
947            implicit, style, mark, mark);
948
949    return 1;
950
951error:
952    yaml_free(anchor_copy);
953    yaml_free(tag_copy);
954
955    return 0;
956}
957
958/*
959 * Create MAPPING-END.
960 */
961
962YAML_DECLARE(int)
963yaml_mapping_end_event_initialize(yaml_event_t *event)
964{
965    yaml_mark_t mark = { 0, 0, 0 };
966
967    assert(event);      /* Non-NULL event object is expected. */
968
969    MAPPING_END_EVENT_INIT(*event, mark, mark);
970
971    return 1;
972}
973
974/*
975 * Destroy an event object.
976 */
977
978YAML_DECLARE(void)
979yaml_event_delete(yaml_event_t *event)
980{
981    yaml_tag_directive_t *tag_directive;
982
983    assert(event);  /* Non-NULL event object expected. */
984
985    switch (event->type)
986    {
987        case YAML_DOCUMENT_START_EVENT:
988            yaml_free(event->data.document_start.version_directive);
989            for (tag_directive = event->data.document_start.tag_directives.start;
990                    tag_directive != event->data.document_start.tag_directives.end;
991                    tag_directive++) {
992                yaml_free(tag_directive->handle);
993                yaml_free(tag_directive->prefix);
994            }
995            yaml_free(event->data.document_start.tag_directives.start);
996            break;
997
998        case YAML_ALIAS_EVENT:
999            yaml_free(event->data.alias.anchor);
1000            break;
1001
1002        case YAML_SCALAR_EVENT:
1003            yaml_free(event->data.scalar.anchor);
1004            yaml_free(event->data.scalar.tag);
1005            yaml_free(event->data.scalar.value);
1006            break;
1007
1008        case YAML_SEQUENCE_START_EVENT:
1009            yaml_free(event->data.sequence_start.anchor);
1010            yaml_free(event->data.sequence_start.tag);
1011            break;
1012
1013        case YAML_MAPPING_START_EVENT:
1014            yaml_free(event->data.mapping_start.anchor);
1015            yaml_free(event->data.mapping_start.tag);
1016            break;
1017
1018        default:
1019            break;
1020    }
1021
1022    memset(event, 0, sizeof(yaml_event_t));
1023}
1024
1025/*
1026 * Create a document object.
1027 */
1028
1029YAML_DECLARE(int)
1030yaml_document_initialize(yaml_document_t *document,
1031        yaml_version_directive_t *version_directive,
1032        yaml_tag_directive_t *tag_directives_start,
1033        yaml_tag_directive_t *tag_directives_end,
1034        int start_implicit, int end_implicit)
1035{
1036    struct {
1037        yaml_error_type_t error;
1038    } context;
1039    struct {
1040        yaml_node_t *start;
1041        yaml_node_t *end;
1042        yaml_node_t *top;
1043    } nodes = { NULL, NULL, NULL };
1044    yaml_version_directive_t *version_directive_copy = NULL;
1045    struct {
1046        yaml_tag_directive_t *start;
1047        yaml_tag_directive_t *end;
1048        yaml_tag_directive_t *top;
1049    } tag_directives_copy = { NULL, NULL, NULL };
1050    yaml_tag_directive_t value = { NULL, NULL };
1051    yaml_mark_t mark = { 0, 0, 0 };
1052
1053    assert(document);       /* Non-NULL document object is expected. */
1054    assert((tag_directives_start && tag_directives_end) ||
1055            (tag_directives_start == tag_directives_end));
1056                            /* Valid tag directives are expected. */
1057
1058    if (!STACK_INIT(&context, nodes, INITIAL_STACK_SIZE)) goto error;
1059
1060    if (version_directive) {
1061        version_directive_copy = yaml_malloc(sizeof(yaml_version_directive_t));
1062        if (!version_directive_copy) goto error;
1063        version_directive_copy->major = version_directive->major;
1064        version_directive_copy->minor = version_directive->minor;
1065    }
1066
1067    if (tag_directives_start != tag_directives_end) {
1068        yaml_tag_directive_t *tag_directive;
1069        if (!STACK_INIT(&context, tag_directives_copy, INITIAL_STACK_SIZE))
1070            goto error;
1071        for (tag_directive = tag_directives_start;
1072                tag_directive != tag_directives_end; tag_directive ++) {
1073            assert(tag_directive->handle);
1074            assert(tag_directive->prefix);
1075            if (!yaml_check_utf8(tag_directive->handle,
1076                        strlen((char *)tag_directive->handle)))
1077                goto error;
1078            if (!yaml_check_utf8(tag_directive->prefix,
1079                        strlen((char *)tag_directive->prefix)))
1080                goto error;
1081            value.handle = yaml_strdup(tag_directive->handle);
1082            value.prefix = yaml_strdup(tag_directive->prefix);
1083            if (!value.handle || !value.prefix) goto error;
1084            if (!PUSH(&context, tag_directives_copy, value))
1085                goto error;
1086            value.handle = NULL;
1087            value.prefix = NULL;
1088        }
1089    }
1090
1091    DOCUMENT_INIT(*document, nodes.start, nodes.end, version_directive_copy,
1092            tag_directives_copy.start, tag_directives_copy.top,
1093            start_implicit, end_implicit, mark, mark);
1094
1095    return 1;
1096
1097error:
1098    STACK_DEL(&context, nodes);
1099    yaml_free(version_directive_copy);
1100    while (!STACK_EMPTY(&context, tag_directives_copy)) {
1101        yaml_tag_directive_t value = POP(&context, tag_directives_copy);
1102        yaml_free(value.handle);
1103        yaml_free(value.prefix);
1104    }
1105    STACK_DEL(&context, tag_directives_copy);
1106    yaml_free(value.handle);
1107    yaml_free(value.prefix);
1108
1109    return 0;
1110}
1111
1112/*
1113 * Destroy a document object.
1114 */
1115
1116YAML_DECLARE(void)
1117yaml_document_delete(yaml_document_t *document)
1118{
1119    struct {
1120        yaml_error_type_t error;
1121    } context;
1122    yaml_tag_directive_t *tag_directive;
1123
1124    context.error = YAML_NO_ERROR;  /* Eliminate a compliler warning. */
1125
1126    assert(document);   /* Non-NULL document object is expected. */
1127
1128    while (!STACK_EMPTY(&context, document->nodes)) {
1129        yaml_node_t node = POP(&context, document->nodes);
1130        yaml_free(node.tag);
1131        switch (node.type) {
1132            case YAML_SCALAR_NODE:
1133                yaml_free(node.data.scalar.value);
1134                break;
1135            case YAML_SEQUENCE_NODE:
1136                STACK_DEL(&context, node.data.sequence.items);
1137                break;
1138            case YAML_MAPPING_NODE:
1139                STACK_DEL(&context, node.data.mapping.pairs);
1140                break;
1141            default:
1142                assert(0);  /* Should not happen. */
1143        }
1144    }
1145    STACK_DEL(&context, document->nodes);
1146
1147    yaml_free(document->version_directive);
1148    for (tag_directive = document->tag_directives.start;
1149            tag_directive != document->tag_directives.end;
1150            tag_directive++) {
1151        yaml_free(tag_directive->handle);
1152        yaml_free(tag_directive->prefix);
1153    }
1154    yaml_free(document->tag_directives.start);
1155
1156    memset(document, 0, sizeof(yaml_document_t));
1157}
1158
1159/**
1160 * Get a document node.
1161 */
1162
1163YAML_DECLARE(yaml_node_t *)
1164yaml_document_get_node(yaml_document_t *document, int index)
1165{
1166    assert(document);   /* Non-NULL document object is expected. */
1167
1168    if (index > 0 && document->nodes.start + index <= document->nodes.top) {
1169        return document->nodes.start + index - 1;
1170    }
1171    return NULL;
1172}
1173
1174/**
1175 * Get the root object.
1176 */
1177
1178YAML_DECLARE(yaml_node_t *)
1179yaml_document_get_root_node(yaml_document_t *document)
1180{
1181    assert(document);   /* Non-NULL document object is expected. */
1182
1183    if (document->nodes.top != document->nodes.start) {
1184        return document->nodes.start;
1185    }
1186    return NULL;
1187}
1188
1189/*
1190 * Add a scalar node to a document.
1191 */
1192
1193YAML_DECLARE(int)
1194yaml_document_add_scalar(yaml_document_t *document,
1195        yaml_char_t *tag, yaml_char_t *value, int length,
1196        yaml_scalar_style_t style)
1197{
1198    struct {
1199        yaml_error_type_t error;
1200    } context;
1201    yaml_mark_t mark = { 0, 0, 0 };
1202    yaml_char_t *tag_copy = NULL;
1203    yaml_char_t *value_copy = NULL;
1204    yaml_node_t node;
1205
1206    assert(document);   /* Non-NULL document object is expected. */
1207    assert(value);      /* Non-NULL value is expected. */
1208
1209    if (!tag) {
1210        tag = (yaml_char_t *)YAML_DEFAULT_SCALAR_TAG;
1211    }
1212
1213    if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error;
1214    tag_copy = yaml_strdup(tag);
1215    if (!tag_copy) goto error;
1216
1217    if (length < 0) {
1218        length = strlen((char *)value);
1219    }
1220
1221    if (!yaml_check_utf8(value, length)) goto error;
1222    value_copy = yaml_malloc(length+1);
1223    if (!value_copy) goto error;
1224    memcpy(value_copy, value, length);
1225    value_copy[length] = '\0';
1226
1227    SCALAR_NODE_INIT(node, tag_copy, value_copy, length, style, mark, mark);
1228    if (!PUSH(&context, document->nodes, node)) goto error;
1229
1230    return document->nodes.top - document->nodes.start;
1231
1232error:
1233    yaml_free(tag_copy);
1234    yaml_free(value_copy);
1235
1236    return 0;
1237}
1238
1239/*
1240 * Add a sequence node to a document.
1241 */
1242
1243YAML_DECLARE(int)
1244yaml_document_add_sequence(yaml_document_t *document,
1245        yaml_char_t *tag, yaml_sequence_style_t style)
1246{
1247    struct {
1248        yaml_error_type_t error;
1249    } context;
1250    yaml_mark_t mark = { 0, 0, 0 };
1251    yaml_char_t *tag_copy = NULL;
1252    struct {
1253        yaml_node_item_t *start;
1254        yaml_node_item_t *end;
1255        yaml_node_item_t *top;
1256    } items = { NULL, NULL, NULL };
1257    yaml_node_t node;
1258
1259    assert(document);   /* Non-NULL document object is expected. */
1260
1261    if (!tag) {
1262        tag = (yaml_char_t *)YAML_DEFAULT_SEQUENCE_TAG;
1263    }
1264
1265    if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error;
1266    tag_copy = yaml_strdup(tag);
1267    if (!tag_copy) goto error;
1268
1269    if (!STACK_INIT(&context, items, INITIAL_STACK_SIZE)) goto error;
1270
1271    SEQUENCE_NODE_INIT(node, tag_copy, items.start, items.end,
1272            style, mark, mark);
1273    if (!PUSH(&context, document->nodes, node)) goto error;
1274
1275    return document->nodes.top - document->nodes.start;
1276
1277error:
1278    STACK_DEL(&context, items);
1279    yaml_free(tag_copy);
1280
1281    return 0;
1282}
1283
1284/*
1285 * Add a mapping node to a document.
1286 */
1287
1288YAML_DECLARE(int)
1289yaml_document_add_mapping(yaml_document_t *document,
1290        yaml_char_t *tag, yaml_mapping_style_t style)
1291{
1292    struct {
1293        yaml_error_type_t error;
1294    } context;
1295    yaml_mark_t mark = { 0, 0, 0 };
1296    yaml_char_t *tag_copy = NULL;
1297    struct {
1298        yaml_node_pair_t *start;
1299        yaml_node_pair_t *end;
1300        yaml_node_pair_t *top;
1301    } pairs = { NULL, NULL, NULL };
1302    yaml_node_t node;
1303
1304    assert(document);   /* Non-NULL document object is expected. */
1305
1306    if (!tag) {
1307        tag = (yaml_char_t *)YAML_DEFAULT_MAPPING_TAG;
1308    }
1309
1310    if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error;
1311    tag_copy = yaml_strdup(tag);
1312    if (!tag_copy) goto error;
1313
1314    if (!STACK_INIT(&context, pairs, INITIAL_STACK_SIZE)) goto error;
1315
1316    MAPPING_NODE_INIT(node, tag_copy, pairs.start, pairs.end,
1317            style, mark, mark);
1318    if (!PUSH(&context, document->nodes, node)) goto error;
1319
1320    return document->nodes.top - document->nodes.start;
1321
1322error:
1323    STACK_DEL(&context, pairs);
1324    yaml_free(tag_copy);
1325
1326    return 0;
1327}
1328
1329/*
1330 * Append an item to a sequence node.
1331 */
1332
1333YAML_DECLARE(int)
1334yaml_document_append_sequence_item(yaml_document_t *document,
1335        int sequence, int item)
1336{
1337    struct {
1338        yaml_error_type_t error;
1339    } context;
1340
1341    assert(document);       /* Non-NULL document is required. */
1342    assert(sequence > 0
1343            && document->nodes.start + sequence <= document->nodes.top);
1344                            /* Valid sequence id is required. */
1345    assert(document->nodes.start[sequence-1].type == YAML_SEQUENCE_NODE);
1346                            /* A sequence node is required. */
1347    assert(item > 0 && document->nodes.start + item <= document->nodes.top);
1348                            /* Valid item id is required. */
1349
1350    if (!PUSH(&context,
1351                document->nodes.start[sequence-1].data.sequence.items, item))
1352        return 0;
1353
1354    return 1;
1355}
1356
1357/*
1358 * Append a pair of a key and a value to a mapping node.
1359 */
1360
1361YAML_DECLARE(int)
1362yaml_document_append_mapping_pair(yaml_document_t *document,
1363        int mapping, int key, int value)
1364{
1365    struct {
1366        yaml_error_type_t error;
1367    } context;
1368
1369    yaml_node_pair_t pair;
1370
1371    assert(document);       /* Non-NULL document is required. */
1372    assert(mapping > 0
1373            && document->nodes.start + mapping <= document->nodes.top);
1374                            /* Valid mapping id is required. */
1375    assert(document->nodes.start[mapping-1].type == YAML_MAPPING_NODE);
1376                            /* A mapping node is required. */
1377    assert(key > 0 && document->nodes.start + key <= document->nodes.top);
1378                            /* Valid key id is required. */
1379    assert(value > 0 && document->nodes.start + value <= document->nodes.top);
1380                            /* Valid value id is required. */
1381
1382    pair.key = key;
1383    pair.value = value;
1384
1385    if (!PUSH(&context,
1386                document->nodes.start[mapping-1].data.mapping.pairs, pair))
1387        return 0;
1388
1389    return 1;
1390}
1391
1392
1393