File Coverage

scanner.c
Criterion Covered Total %
statement 602 1046 57.5
branch 782 2902 26.9
condition n/a
subroutine n/a
pod n/a
total 1384 3948 35.0


line stmt bran cond sub pod time code
1              
2             /*
3             * Introduction
4             * ************
5             *
6             * The following notes assume that you are familiar with the YAML specification
7             * (http://yaml.org/spec/cvs/current.html). We mostly follow it, although in
8             * some cases we are less restrictive that it requires.
9             *
10             * The process of transforming a YAML stream into a sequence of events is
11             * divided on two steps: Scanning and Parsing.
12             *
13             * The Scanner transforms the input stream into a sequence of tokens, while the
14             * parser transform the sequence of tokens produced by the Scanner into a
15             * sequence of parsing events.
16             *
17             * The Scanner is rather clever and complicated. The Parser, on the contrary,
18             * is a straightforward implementation of a recursive-descendant parser (or,
19             * LL(1) parser, as it is usually called).
20             *
21             * Actually there are two issues of Scanning that might be called "clever", the
22             * rest is quite straightforward. The issues are "block collection start" and
23             * "simple keys". Both issues are explained below in details.
24             *
25             * Here the Scanning step is explained and implemented. We start with the list
26             * of all the tokens produced by the Scanner together with short descriptions.
27             *
28             * Now, tokens:
29             *
30             * STREAM-START(encoding) # The stream start.
31             * STREAM-END # The stream end.
32             * VERSION-DIRECTIVE(major,minor) # The '%YAML' directive.
33             * TAG-DIRECTIVE(handle,prefix) # The '%TAG' directive.
34             * DOCUMENT-START # '---'
35             * DOCUMENT-END # '...'
36             * BLOCK-SEQUENCE-START # Indentation increase denoting a block
37             * BLOCK-MAPPING-START # sequence or a block mapping.
38             * BLOCK-END # Indentation decrease.
39             * FLOW-SEQUENCE-START # '['
40             * FLOW-SEQUENCE-END # ']'
41             * FLOW-MAPPING-START # '{'
42             * FLOW-MAPPING-END # '}'
43             * BLOCK-ENTRY # '-'
44             * FLOW-ENTRY # ','
45             * KEY # '?' or nothing (simple keys).
46             * VALUE # ':'
47             * ALIAS(anchor) # '*anchor'
48             * ANCHOR(anchor) # '&anchor'
49             * TAG(handle,suffix) # '!handle!suffix'
50             * SCALAR(value,style) # A scalar.
51             *
52             * The following two tokens are "virtual" tokens denoting the beginning and the
53             * end of the stream:
54             *
55             * STREAM-START(encoding)
56             * STREAM-END
57             *
58             * We pass the information about the input stream encoding with the
59             * STREAM-START token.
60             *
61             * The next two tokens are responsible for tags:
62             *
63             * VERSION-DIRECTIVE(major,minor)
64             * TAG-DIRECTIVE(handle,prefix)
65             *
66             * Example:
67             *
68             * %YAML 1.1
69             * %TAG ! !foo
70             * %TAG !yaml! tag:yaml.org,2002:
71             * ---
72             *
73             * The corresponding sequence of tokens:
74             *
75             * STREAM-START(utf-8)
76             * VERSION-DIRECTIVE(1,1)
77             * TAG-DIRECTIVE("!","!foo")
78             * TAG-DIRECTIVE("!yaml","tag:yaml.org,2002:")
79             * DOCUMENT-START
80             * STREAM-END
81             *
82             * Note that the VERSION-DIRECTIVE and TAG-DIRECTIVE tokens occupy a whole
83             * line.
84             *
85             * The document start and end indicators are represented by:
86             *
87             * DOCUMENT-START
88             * DOCUMENT-END
89             *
90             * Note that if a YAML stream contains an implicit document (without '---'
91             * and '...' indicators), no DOCUMENT-START and DOCUMENT-END tokens will be
92             * produced.
93             *
94             * In the following examples, we present whole documents together with the
95             * produced tokens.
96             *
97             * 1. An implicit document:
98             *
99             * 'a scalar'
100             *
101             * Tokens:
102             *
103             * STREAM-START(utf-8)
104             * SCALAR("a scalar",single-quoted)
105             * STREAM-END
106             *
107             * 2. An explicit document:
108             *
109             * ---
110             * 'a scalar'
111             * ...
112             *
113             * Tokens:
114             *
115             * STREAM-START(utf-8)
116             * DOCUMENT-START
117             * SCALAR("a scalar",single-quoted)
118             * DOCUMENT-END
119             * STREAM-END
120             *
121             * 3. Several documents in a stream:
122             *
123             * 'a scalar'
124             * ---
125             * 'another scalar'
126             * ---
127             * 'yet another scalar'
128             *
129             * Tokens:
130             *
131             * STREAM-START(utf-8)
132             * SCALAR("a scalar",single-quoted)
133             * DOCUMENT-START
134             * SCALAR("another scalar",single-quoted)
135             * DOCUMENT-START
136             * SCALAR("yet another scalar",single-quoted)
137             * STREAM-END
138             *
139             * We have already introduced the SCALAR token above. The following tokens are
140             * used to describe aliases, anchors, tag, and scalars:
141             *
142             * ALIAS(anchor)
143             * ANCHOR(anchor)
144             * TAG(handle,suffix)
145             * SCALAR(value,style)
146             *
147             * The following series of examples illustrate the usage of these tokens:
148             *
149             * 1. A recursive sequence:
150             *
151             * &A [ *A ]
152             *
153             * Tokens:
154             *
155             * STREAM-START(utf-8)
156             * ANCHOR("A")
157             * FLOW-SEQUENCE-START
158             * ALIAS("A")
159             * FLOW-SEQUENCE-END
160             * STREAM-END
161             *
162             * 2. A tagged scalar:
163             *
164             * !!float "3.14" # A good approximation.
165             *
166             * Tokens:
167             *
168             * STREAM-START(utf-8)
169             * TAG("!!","float")
170             * SCALAR("3.14",double-quoted)
171             * STREAM-END
172             *
173             * 3. Various scalar styles:
174             *
175             * --- # Implicit empty plain scalars do not produce tokens.
176             * --- a plain scalar
177             * --- 'a single-quoted scalar'
178             * --- "a double-quoted scalar"
179             * --- |-
180             * a literal scalar
181             * --- >-
182             * a folded
183             * scalar
184             *
185             * Tokens:
186             *
187             * STREAM-START(utf-8)
188             * DOCUMENT-START
189             * DOCUMENT-START
190             * SCALAR("a plain scalar",plain)
191             * DOCUMENT-START
192             * SCALAR("a single-quoted scalar",single-quoted)
193             * DOCUMENT-START
194             * SCALAR("a double-quoted scalar",double-quoted)
195             * DOCUMENT-START
196             * SCALAR("a literal scalar",literal)
197             * DOCUMENT-START
198             * SCALAR("a folded scalar",folded)
199             * STREAM-END
200             *
201             * Now it's time to review collection-related tokens. We will start with
202             * flow collections:
203             *
204             * FLOW-SEQUENCE-START
205             * FLOW-SEQUENCE-END
206             * FLOW-MAPPING-START
207             * FLOW-MAPPING-END
208             * FLOW-ENTRY
209             * KEY
210             * VALUE
211             *
212             * The tokens FLOW-SEQUENCE-START, FLOW-SEQUENCE-END, FLOW-MAPPING-START, and
213             * FLOW-MAPPING-END represent the indicators '[', ']', '{', and '}'
214             * correspondingly. FLOW-ENTRY represent the ',' indicator. Finally the
215             * indicators '?' and ':', which are used for denoting mapping keys and values,
216             * are represented by the KEY and VALUE tokens.
217             *
218             * The following examples show flow collections:
219             *
220             * 1. A flow sequence:
221             *
222             * [item 1, item 2, item 3]
223             *
224             * Tokens:
225             *
226             * STREAM-START(utf-8)
227             * FLOW-SEQUENCE-START
228             * SCALAR("item 1",plain)
229             * FLOW-ENTRY
230             * SCALAR("item 2",plain)
231             * FLOW-ENTRY
232             * SCALAR("item 3",plain)
233             * FLOW-SEQUENCE-END
234             * STREAM-END
235             *
236             * 2. A flow mapping:
237             *
238             * {
239             * a simple key: a value, # Note that the KEY token is produced.
240             * ? a complex key: another value,
241             * }
242             *
243             * Tokens:
244             *
245             * STREAM-START(utf-8)
246             * FLOW-MAPPING-START
247             * KEY
248             * SCALAR("a simple key",plain)
249             * VALUE
250             * SCALAR("a value",plain)
251             * FLOW-ENTRY
252             * KEY
253             * SCALAR("a complex key",plain)
254             * VALUE
255             * SCALAR("another value",plain)
256             * FLOW-ENTRY
257             * FLOW-MAPPING-END
258             * STREAM-END
259             *
260             * A simple key is a key which is not denoted by the '?' indicator. Note that
261             * the Scanner still produce the KEY token whenever it encounters a simple key.
262             *
263             * For scanning block collections, the following tokens are used (note that we
264             * repeat KEY and VALUE here):
265             *
266             * BLOCK-SEQUENCE-START
267             * BLOCK-MAPPING-START
268             * BLOCK-END
269             * BLOCK-ENTRY
270             * KEY
271             * VALUE
272             *
273             * The tokens BLOCK-SEQUENCE-START and BLOCK-MAPPING-START denote indentation
274             * increase that precedes a block collection (cf. the INDENT token in Python).
275             * The token BLOCK-END denote indentation decrease that ends a block collection
276             * (cf. the DEDENT token in Python). However YAML has some syntax pecularities
277             * that makes detections of these tokens more complex.
278             *
279             * The tokens BLOCK-ENTRY, KEY, and VALUE are used to represent the indicators
280             * '-', '?', and ':' correspondingly.
281             *
282             * The following examples show how the tokens BLOCK-SEQUENCE-START,
283             * BLOCK-MAPPING-START, and BLOCK-END are emitted by the Scanner:
284             *
285             * 1. Block sequences:
286             *
287             * - item 1
288             * - item 2
289             * -
290             * - item 3.1
291             * - item 3.2
292             * -
293             * key 1: value 1
294             * key 2: value 2
295             *
296             * Tokens:
297             *
298             * STREAM-START(utf-8)
299             * BLOCK-SEQUENCE-START
300             * BLOCK-ENTRY
301             * SCALAR("item 1",plain)
302             * BLOCK-ENTRY
303             * SCALAR("item 2",plain)
304             * BLOCK-ENTRY
305             * BLOCK-SEQUENCE-START
306             * BLOCK-ENTRY
307             * SCALAR("item 3.1",plain)
308             * BLOCK-ENTRY
309             * SCALAR("item 3.2",plain)
310             * BLOCK-END
311             * BLOCK-ENTRY
312             * BLOCK-MAPPING-START
313             * KEY
314             * SCALAR("key 1",plain)
315             * VALUE
316             * SCALAR("value 1",plain)
317             * KEY
318             * SCALAR("key 2",plain)
319             * VALUE
320             * SCALAR("value 2",plain)
321             * BLOCK-END
322             * BLOCK-END
323             * STREAM-END
324             *
325             * 2. Block mappings:
326             *
327             * a simple key: a value # The KEY token is produced here.
328             * ? a complex key
329             * : another value
330             * a mapping:
331             * key 1: value 1
332             * key 2: value 2
333             * a sequence:
334             * - item 1
335             * - item 2
336             *
337             * Tokens:
338             *
339             * STREAM-START(utf-8)
340             * BLOCK-MAPPING-START
341             * KEY
342             * SCALAR("a simple key",plain)
343             * VALUE
344             * SCALAR("a value",plain)
345             * KEY
346             * SCALAR("a complex key",plain)
347             * VALUE
348             * SCALAR("another value",plain)
349             * KEY
350             * SCALAR("a mapping",plain)
351             * BLOCK-MAPPING-START
352             * KEY
353             * SCALAR("key 1",plain)
354             * VALUE
355             * SCALAR("value 1",plain)
356             * KEY
357             * SCALAR("key 2",plain)
358             * VALUE
359             * SCALAR("value 2",plain)
360             * BLOCK-END
361             * KEY
362             * SCALAR("a sequence",plain)
363             * VALUE
364             * BLOCK-SEQUENCE-START
365             * BLOCK-ENTRY
366             * SCALAR("item 1",plain)
367             * BLOCK-ENTRY
368             * SCALAR("item 2",plain)
369             * BLOCK-END
370             * BLOCK-END
371             * STREAM-END
372             *
373             * YAML does not always require to start a new block collection from a new
374             * line. If the current line contains only '-', '?', and ':' indicators, a new
375             * block collection may start at the current line. The following examples
376             * illustrate this case:
377             *
378             * 1. Collections in a sequence:
379             *
380             * - - item 1
381             * - item 2
382             * - key 1: value 1
383             * key 2: value 2
384             * - ? complex key
385             * : complex value
386             *
387             * Tokens:
388             *
389             * STREAM-START(utf-8)
390             * BLOCK-SEQUENCE-START
391             * BLOCK-ENTRY
392             * BLOCK-SEQUENCE-START
393             * BLOCK-ENTRY
394             * SCALAR("item 1",plain)
395             * BLOCK-ENTRY
396             * SCALAR("item 2",plain)
397             * BLOCK-END
398             * BLOCK-ENTRY
399             * BLOCK-MAPPING-START
400             * KEY
401             * SCALAR("key 1",plain)
402             * VALUE
403             * SCALAR("value 1",plain)
404             * KEY
405             * SCALAR("key 2",plain)
406             * VALUE
407             * SCALAR("value 2",plain)
408             * BLOCK-END
409             * BLOCK-ENTRY
410             * BLOCK-MAPPING-START
411             * KEY
412             * SCALAR("complex key")
413             * VALUE
414             * SCALAR("complex value")
415             * BLOCK-END
416             * BLOCK-END
417             * STREAM-END
418             *
419             * 2. Collections in a mapping:
420             *
421             * ? a sequence
422             * : - item 1
423             * - item 2
424             * ? a mapping
425             * : key 1: value 1
426             * key 2: value 2
427             *
428             * Tokens:
429             *
430             * STREAM-START(utf-8)
431             * BLOCK-MAPPING-START
432             * KEY
433             * SCALAR("a sequence",plain)
434             * VALUE
435             * BLOCK-SEQUENCE-START
436             * BLOCK-ENTRY
437             * SCALAR("item 1",plain)
438             * BLOCK-ENTRY
439             * SCALAR("item 2",plain)
440             * BLOCK-END
441             * KEY
442             * SCALAR("a mapping",plain)
443             * VALUE
444             * BLOCK-MAPPING-START
445             * KEY
446             * SCALAR("key 1",plain)
447             * VALUE
448             * SCALAR("value 1",plain)
449             * KEY
450             * SCALAR("key 2",plain)
451             * VALUE
452             * SCALAR("value 2",plain)
453             * BLOCK-END
454             * BLOCK-END
455             * STREAM-END
456             *
457             * YAML also permits non-indented sequences if they are included into a block
458             * mapping. In this case, the token BLOCK-SEQUENCE-START is not produced:
459             *
460             * key:
461             * - item 1 # BLOCK-SEQUENCE-START is NOT produced here.
462             * - item 2
463             *
464             * Tokens:
465             *
466             * STREAM-START(utf-8)
467             * BLOCK-MAPPING-START
468             * KEY
469             * SCALAR("key",plain)
470             * VALUE
471             * BLOCK-ENTRY
472             * SCALAR("item 1",plain)
473             * BLOCK-ENTRY
474             * SCALAR("item 2",plain)
475             * BLOCK-END
476             */
477              
478             #include "yaml_private.h"
479              
480             /*
481             * Ensure that the buffer contains the required number of characters.
482             * Return 1 on success, 0 on failure (reader error or memory error).
483             */
484              
485             #define CACHE(parser,length) \
486             (parser->unread >= (length) \
487             ? 1 \
488             : yaml_parser_update_buffer(parser, (length)))
489              
490             /*
491             * Advance the buffer pointer.
492             */
493              
494             #define SKIP(parser) \
495             (parser->mark.index ++, \
496             parser->mark.column ++, \
497             parser->unread --, \
498             parser->buffer.pointer += WIDTH(parser->buffer))
499              
500             #define SKIP_LINE(parser) \
501             (IS_CRLF(parser->buffer) ? \
502             (parser->mark.index += 2, \
503             parser->mark.column = 0, \
504             parser->mark.line ++, \
505             parser->unread -= 2, \
506             parser->buffer.pointer += 2) : \
507             IS_BREAK(parser->buffer) ? \
508             (parser->mark.index ++, \
509             parser->mark.column = 0, \
510             parser->mark.line ++, \
511             parser->unread --, \
512             parser->buffer.pointer += WIDTH(parser->buffer)) : 0)
513              
514             /*
515             * Copy a character to a string buffer and advance pointers.
516             */
517              
518             #define READ(parser,string) \
519             (STRING_EXTEND(parser,string) ? \
520             (COPY(string,parser->buffer), \
521             parser->mark.index ++, \
522             parser->mark.column ++, \
523             parser->unread --, \
524             1) : 0)
525              
526             /*
527             * Copy a line break character to a string buffer and advance pointers.
528             */
529              
530             #define READ_LINE(parser,string) \
531             (STRING_EXTEND(parser,string) ? \
532             (((CHECK_AT(parser->buffer,'\r',0) \
533             && CHECK_AT(parser->buffer,'\n',1)) ? /* CR LF -> LF */ \
534             (*((string).pointer++) = (yaml_char_t) '\n', \
535             parser->buffer.pointer += 2, \
536             parser->mark.index += 2, \
537             parser->mark.column = 0, \
538             parser->mark.line ++, \
539             parser->unread -= 2) : \
540             (CHECK_AT(parser->buffer,'\r',0) \
541             || CHECK_AT(parser->buffer,'\n',0)) ? /* CR|LF -> LF */ \
542             (*((string).pointer++) = (yaml_char_t) '\n', \
543             parser->buffer.pointer ++, \
544             parser->mark.index ++, \
545             parser->mark.column = 0, \
546             parser->mark.line ++, \
547             parser->unread --) : \
548             (CHECK_AT(parser->buffer,'\xC2',0) \
549             && CHECK_AT(parser->buffer,'\x85',1)) ? /* NEL -> LF */ \
550             (*((string).pointer++) = (yaml_char_t) '\n', \
551             parser->buffer.pointer += 2, \
552             parser->mark.index ++, \
553             parser->mark.column = 0, \
554             parser->mark.line ++, \
555             parser->unread --) : \
556             (CHECK_AT(parser->buffer,'\xE2',0) && \
557             CHECK_AT(parser->buffer,'\x80',1) && \
558             (CHECK_AT(parser->buffer,'\xA8',2) || \
559             CHECK_AT(parser->buffer,'\xA9',2))) ? /* LS|PS -> LS|PS */ \
560             (*((string).pointer++) = *(parser->buffer.pointer++), \
561             *((string).pointer++) = *(parser->buffer.pointer++), \
562             *((string).pointer++) = *(parser->buffer.pointer++), \
563             parser->mark.index ++, \
564             parser->mark.column = 0, \
565             parser->mark.line ++, \
566             parser->unread --) : 0), \
567             1) : 0)
568              
569             /*
570             * Public API declarations: see yaml.h
571             */
572              
573             /*
574             * Error handling.
575             */
576              
577             static int
578             yaml_parser_set_scanner_error(yaml_parser_t *parser, const char *context,
579             yaml_mark_t context_mark, const char *problem);
580              
581             /*
582             * High-level token API.
583             */
584              
585             static int
586             yaml_parser_fetch_next_token(yaml_parser_t *parser);
587              
588             /*
589             * Potential simple keys.
590             */
591              
592             static int
593             yaml_parser_stale_simple_keys(yaml_parser_t *parser);
594              
595             static int
596             yaml_parser_save_simple_key(yaml_parser_t *parser);
597              
598             static int
599             yaml_parser_remove_simple_key(yaml_parser_t *parser);
600              
601             static int
602             yaml_parser_increase_flow_level(yaml_parser_t *parser);
603              
604             static int
605             yaml_parser_decrease_flow_level(yaml_parser_t *parser);
606              
607             /*
608             * Indentation treatment.
609             */
610              
611             static int
612             yaml_parser_roll_indent(yaml_parser_t *parser, ptrdiff_t column,
613             ptrdiff_t number, yaml_token_type_t type, yaml_mark_t mark);
614              
615             static int
616             yaml_parser_unroll_indent(yaml_parser_t *parser, ptrdiff_t column);
617              
618             /*
619             * Token fetchers.
620             */
621              
622             static int
623             yaml_parser_fetch_stream_start(yaml_parser_t *parser);
624              
625             static int
626             yaml_parser_fetch_stream_end(yaml_parser_t *parser);
627              
628             static int
629             yaml_parser_fetch_directive(yaml_parser_t *parser);
630              
631             static int
632             yaml_parser_fetch_document_indicator(yaml_parser_t *parser,
633             yaml_token_type_t type);
634              
635             static int
636             yaml_parser_fetch_flow_collection_start(yaml_parser_t *parser,
637             yaml_token_type_t type);
638              
639             static int
640             yaml_parser_fetch_flow_collection_end(yaml_parser_t *parser,
641             yaml_token_type_t type);
642              
643             static int
644             yaml_parser_fetch_flow_entry(yaml_parser_t *parser);
645              
646             static int
647             yaml_parser_fetch_block_entry(yaml_parser_t *parser);
648              
649             static int
650             yaml_parser_fetch_key(yaml_parser_t *parser);
651              
652             static int
653             yaml_parser_fetch_value(yaml_parser_t *parser);
654              
655             static int
656             yaml_parser_fetch_anchor(yaml_parser_t *parser, yaml_token_type_t type);
657              
658             static int
659             yaml_parser_fetch_tag(yaml_parser_t *parser);
660              
661             static int
662             yaml_parser_fetch_block_scalar(yaml_parser_t *parser, int literal);
663              
664             static int
665             yaml_parser_fetch_flow_scalar(yaml_parser_t *parser, int single);
666              
667             static int
668             yaml_parser_fetch_plain_scalar(yaml_parser_t *parser);
669              
670             /*
671             * Token scanners.
672             */
673              
674             static int
675             yaml_parser_scan_to_next_token(yaml_parser_t *parser);
676              
677             static int
678             yaml_parser_scan_directive(yaml_parser_t *parser, yaml_token_t *token);
679              
680             static int
681             yaml_parser_scan_directive_name(yaml_parser_t *parser,
682             yaml_mark_t start_mark, yaml_char_t **name);
683              
684             static int
685             yaml_parser_scan_version_directive_value(yaml_parser_t *parser,
686             yaml_mark_t start_mark, int *major, int *minor);
687              
688             static int
689             yaml_parser_scan_version_directive_number(yaml_parser_t *parser,
690             yaml_mark_t start_mark, int *number);
691              
692             static int
693             yaml_parser_scan_tag_directive_value(yaml_parser_t *parser,
694             yaml_mark_t mark, yaml_char_t **handle, yaml_char_t **prefix);
695              
696             static int
697             yaml_parser_scan_anchor(yaml_parser_t *parser, yaml_token_t *token,
698             yaml_token_type_t type);
699              
700             static int
701             yaml_parser_scan_tag(yaml_parser_t *parser, yaml_token_t *token);
702              
703             static int
704             yaml_parser_scan_tag_handle(yaml_parser_t *parser, int directive,
705             yaml_mark_t start_mark, yaml_char_t **handle);
706              
707             static int
708             yaml_parser_scan_tag_uri(yaml_parser_t *parser, int directive,
709             yaml_char_t *head, yaml_mark_t start_mark, yaml_char_t **uri);
710              
711             static int
712             yaml_parser_scan_uri_escapes(yaml_parser_t *parser, int directive,
713             yaml_mark_t start_mark, yaml_string_t *string);
714              
715             static int
716             yaml_parser_scan_block_scalar(yaml_parser_t *parser, yaml_token_t *token,
717             int literal);
718              
719             static int
720             yaml_parser_scan_block_scalar_breaks(yaml_parser_t *parser,
721             int *indent, yaml_string_t *breaks,
722             yaml_mark_t start_mark, yaml_mark_t *end_mark);
723              
724             static int
725             yaml_parser_scan_flow_scalar(yaml_parser_t *parser, yaml_token_t *token,
726             int single);
727              
728             static int
729             yaml_parser_scan_plain_scalar(yaml_parser_t *parser, yaml_token_t *token);
730              
731             /*
732             * Get the next token.
733             */
734              
735             YAML_DECLARE(int)
736 0           yaml_parser_scan(yaml_parser_t *parser, yaml_token_t *token)
737             {
738 0 0         assert(parser); /* Non-NULL parser object is expected. */
739 0 0         assert(token); /* Non-NULL token object is expected. */
740              
741             /* Erase the token object. */
742              
743 0           memset(token, 0, sizeof(yaml_token_t));
744              
745             /* No tokens after STREAM-END or error. */
746              
747 0 0         if (parser->stream_end_produced
748 0 0         || (parser->error
749             /* continue in nonstrict and READER_ERROR */
750 0 0         && (!parser->problem_nonstrict || parser->error != YAML_READER_ERROR)))
    0          
751 0           return 1;
752              
753             /* Ensure that the tokens queue contains enough tokens. */
754              
755 0 0         if (!parser->token_available) {
756 0 0         if (!yaml_parser_fetch_more_tokens(parser))
757 0           return 0;
758             }
759              
760             /* Fetch the next token from the queue. */
761              
762 0           *token = DEQUEUE(parser, parser->tokens);
763 0           parser->token_available = 0;
764 0           parser->tokens_parsed ++;
765              
766 0 0         if (token->type == YAML_STREAM_END_TOKEN) {
767 0           parser->stream_end_produced = 1;
768             }
769              
770 0           return 1;
771             }
772              
773             /*
774             * Set the scanner error and return 0.
775             */
776              
777             static int
778 5           yaml_parser_set_scanner_error(yaml_parser_t *parser, const char *context,
779             yaml_mark_t context_mark, const char *problem)
780             {
781 5           parser->error = YAML_SCANNER_ERROR;
782 5           parser->context = context;
783 5           parser->context_mark = context_mark;
784 5           parser->problem = problem;
785 5           parser->problem_mark = parser->mark;
786              
787 5           return 0;
788             }
789              
790             /*
791             * Ensure that the tokens queue contains at least one token which can be
792             * returned to the Parser.
793             */
794              
795             YAML_DECLARE(int)
796 1380           yaml_parser_fetch_more_tokens(yaml_parser_t *parser)
797             {
798             int need_more_tokens;
799              
800             /* While we need more tokens to fetch, do it. */
801              
802             while (1)
803             {
804             /*
805             * Check if we really need to fetch more tokens.
806             */
807              
808 2435           need_more_tokens = 0;
809              
810 2435 100         if (parser->tokens.head == parser->tokens.tail)
811             {
812             /* Queue is empty. */
813              
814 836           need_more_tokens = 1;
815             }
816             else
817             {
818             yaml_simple_key_t *simple_key;
819              
820             /* Check if any potential simple key may occupy the head position. */
821              
822 1599 50         if (!yaml_parser_stale_simple_keys(parser))
823 0           return 0;
824              
825 3053 100         for (simple_key = parser->simple_keys.start;
826 1454           simple_key != parser->simple_keys.top; simple_key++) {
827 1678 100         if (simple_key->possible
828 243 100         && simple_key->token_number == parser->tokens_parsed) {
829 224           need_more_tokens = 1;
830 224           break;
831             }
832             }
833             }
834              
835             /* We are finished. */
836              
837 2435 100         if (!need_more_tokens)
838 1375           break;
839              
840             /* Fetch the next token. */
841              
842 1060 100         if (!yaml_parser_fetch_next_token(parser))
843 5           return 0;
844 1055           }
845              
846 1375           parser->token_available = 1;
847              
848 1375           return 1;
849             }
850              
851             /*
852             * The dispatcher for token fetchers.
853             */
854              
855             static int
856 1060           yaml_parser_fetch_next_token(yaml_parser_t *parser)
857             {
858             /* Ensure that the buffer is initialized. */
859              
860 1060 100         if (!CACHE(parser, 1))
    100          
861 1           return 0;
862              
863             /* Check if we just started scanning. Fetch STREAM-START then. */
864              
865 1059 100         if (!parser->stream_start_produced)
866 108           return yaml_parser_fetch_stream_start(parser);
867              
868             /* Eat whitespaces and comments until we reach the next token. */
869              
870 951 50         if (!yaml_parser_scan_to_next_token(parser))
871 0           return 0;
872              
873             /* Remove obsolete potential simple keys. */
874              
875 951 50         if (!yaml_parser_stale_simple_keys(parser))
876 0           return 0;
877              
878             /* Check the indentation level against the current column. */
879              
880 951 50         if (!yaml_parser_unroll_indent(parser, parser->mark.column))
881 0           return 0;
882              
883             /*
884             * Ensure that the buffer contains at least 4 characters. 4 is the length
885             * of the longest indicators ('--- ' and '... ').
886             */
887              
888 951 100         if (!CACHE(parser, 4))
    50          
889 0           return 0;
890              
891             /* Is it the end of the stream? */
892              
893 951 100         if (IS_Z(parser->buffer))
894 101           return yaml_parser_fetch_stream_end(parser);
895              
896             /* Is it a directive? */
897              
898 850 100         if (parser->mark.column == 0 && CHECK(parser->buffer, '%'))
    50          
899 0           return yaml_parser_fetch_directive(parser);
900              
901             /* Is it the document start indicator? */
902              
903 850 100         if (parser->mark.column == 0
904 289 100         && CHECK_AT(parser->buffer, '-', 0)
905 191 100         && CHECK_AT(parser->buffer, '-', 1)
906 97 50         && CHECK_AT(parser->buffer, '-', 2)
907 97 100         && IS_BLANKZ_AT(parser->buffer, 3))
    50          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
908 97           return yaml_parser_fetch_document_indicator(parser,
909             YAML_DOCUMENT_START_TOKEN);
910              
911             /* Is it the document end indicator? */
912              
913 753 100         if (parser->mark.column == 0
914 192 50         && CHECK_AT(parser->buffer, '.', 0)
915 0 0         && CHECK_AT(parser->buffer, '.', 1)
916 0 0         && CHECK_AT(parser->buffer, '.', 2)
917 0 0         && IS_BLANKZ_AT(parser->buffer, 3))
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
918 0           return yaml_parser_fetch_document_indicator(parser,
919             YAML_DOCUMENT_END_TOKEN);
920              
921             /* Is it the flow sequence start indicator? */
922              
923 753 100         if (CHECK(parser->buffer, '['))
924 12           return yaml_parser_fetch_flow_collection_start(parser,
925             YAML_FLOW_SEQUENCE_START_TOKEN);
926              
927             /* Is it the flow mapping start indicator? */
928              
929 741 100         if (CHECK(parser->buffer, '{'))
930 14           return yaml_parser_fetch_flow_collection_start(parser,
931             YAML_FLOW_MAPPING_START_TOKEN);
932              
933             /* Is it the flow sequence end indicator? */
934              
935 727 100         if (CHECK(parser->buffer, ']'))
936 12           return yaml_parser_fetch_flow_collection_end(parser,
937             YAML_FLOW_SEQUENCE_END_TOKEN);
938              
939             /* Is it the flow mapping end indicator? */
940              
941 715 100         if (CHECK(parser->buffer, '}'))
942 14           return yaml_parser_fetch_flow_collection_end(parser,
943             YAML_FLOW_MAPPING_END_TOKEN);
944              
945             /* Is it the flow entry indicator? */
946              
947 701 100         if (CHECK(parser->buffer, ','))
948 8           return yaml_parser_fetch_flow_entry(parser);
949              
950             /* Is it the block entry indicator? */
951              
952 693 100         if (CHECK(parser->buffer, '-') && IS_BLANKZ_AT(parser->buffer, 1))
    100          
    50          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
953 113           return yaml_parser_fetch_block_entry(parser);
954              
955             /* Is it the key indicator? */
956              
957 580 50         if (CHECK(parser->buffer, '?')
958 0 0         && (parser->flow_level || IS_BLANKZ_AT(parser->buffer, 1)))
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
959 0           return yaml_parser_fetch_key(parser);
960              
961             /* Is it the value indicator? */
962              
963 580 100         if (CHECK(parser->buffer, ':')
964 126 100         && (parser->flow_level || IS_BLANKZ_AT(parser->buffer, 1)))
    100          
    50          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
965 126           return yaml_parser_fetch_value(parser);
966              
967             /* Is it an alias? */
968              
969 454 100         if (CHECK(parser->buffer, '*'))
970 19           return yaml_parser_fetch_anchor(parser, YAML_ALIAS_TOKEN);
971              
972             /* Is it an anchor? */
973              
974 435 100         if (CHECK(parser->buffer, '&'))
975 17           return yaml_parser_fetch_anchor(parser, YAML_ANCHOR_TOKEN);
976              
977             /* Is it a tag? */
978              
979 418 100         if (CHECK(parser->buffer, '!'))
980 82           return yaml_parser_fetch_tag(parser);
981              
982             /* Is it a literal scalar? */
983              
984 336 100         if (CHECK(parser->buffer, '|') && !parser->flow_level)
    50          
985 7           return yaml_parser_fetch_block_scalar(parser, 1);
986              
987             /* Is it a folded scalar? */
988              
989 329 50         if (CHECK(parser->buffer, '>') && !parser->flow_level)
    0          
990 0           return yaml_parser_fetch_block_scalar(parser, 0);
991              
992             /* Is it a single-quoted scalar? */
993              
994 329 100         if (CHECK(parser->buffer, '\''))
995 16           return yaml_parser_fetch_flow_scalar(parser, 1);
996              
997             /* Is it a double-quoted scalar? */
998              
999 313 100         if (CHECK(parser->buffer, '"'))
1000 11           return yaml_parser_fetch_flow_scalar(parser, 0);
1001              
1002             /*
1003             * Is it a plain scalar?
1004             *
1005             * A plain scalar may start with any non-blank characters except
1006             *
1007             * '-', '?', ':', ',', '[', ']', '{', '}',
1008             * '#', '&', '*', '!', '|', '>', '\'', '\"',
1009             * '%', '@', '`'.
1010             *
1011             * In the block context (and, for the '-' indicator, in the flow context
1012             * too), it may also start with the characters
1013             *
1014             * '-', '?', ':'
1015             *
1016             * if it is followed by a non-space character.
1017             *
1018             * The last rule is more restrictive than the specification requires.
1019             */
1020              
1021 604 50         if (!(IS_BLANKZ(parser->buffer) || CHECK(parser->buffer, '-')
    50          
    50          
    50          
    50          
    0          
    50          
    0          
    0          
    50          
    0          
    0          
    50          
    50          
    50          
1022 302 50         || CHECK(parser->buffer, '?') || CHECK(parser->buffer, ':')
    50          
1023 302 50         || CHECK(parser->buffer, ',') || CHECK(parser->buffer, '[')
    50          
1024 302 50         || CHECK(parser->buffer, ']') || CHECK(parser->buffer, '{')
    50          
1025 302 50         || CHECK(parser->buffer, '}') || CHECK(parser->buffer, '#')
    50          
1026 302 50         || CHECK(parser->buffer, '&') || CHECK(parser->buffer, '*')
    50          
1027 302 50         || CHECK(parser->buffer, '!') || CHECK(parser->buffer, '|')
    50          
1028 302 50         || CHECK(parser->buffer, '>') || CHECK(parser->buffer, '\'')
    50          
1029 302 50         || CHECK(parser->buffer, '"') || CHECK(parser->buffer, '%')
    50          
1030 302 50         || CHECK(parser->buffer, '@') || CHECK(parser->buffer, '`')) ||
    0          
1031 0 0         (CHECK(parser->buffer, '-') && !IS_BLANK_AT(parser->buffer, 1)) ||
    0          
    0          
1032 0 0         (!parser->flow_level &&
1033 0 0         (CHECK(parser->buffer, '?') || CHECK(parser->buffer, ':'))
1034 0 0         && !IS_BLANKZ_AT(parser->buffer, 1)))
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
1035 302           return yaml_parser_fetch_plain_scalar(parser);
1036              
1037             /*
1038             * If we don't determine the token type so far, it is an error.
1039             */
1040              
1041 0           return yaml_parser_set_scanner_error(parser,
1042             "while scanning for the next token", parser->mark,
1043             "found character that cannot start any token");
1044             }
1045              
1046             /*
1047             * Check the list of potential simple keys and remove the positions that
1048             * cannot contain simple keys anymore.
1049             */
1050              
1051             static int
1052 2550           yaml_parser_stale_simple_keys(yaml_parser_t *parser)
1053             {
1054             yaml_simple_key_t *simple_key;
1055              
1056             /* Check for a potential simple key for each flow level. */
1057              
1058 5294 100         for (simple_key = parser->simple_keys.start;
1059 2744           simple_key != parser->simple_keys.top; simple_key ++)
1060             {
1061             /*
1062             * The specification requires that a simple key
1063             *
1064             * - is limited to a single line,
1065             * - is shorter than 1024 characters.
1066             */
1067              
1068 2744 100         if (simple_key->possible
1069 556 100         && (simple_key->mark.line < parser->mark.line
1070 458 50         || simple_key->mark.index+1024 < parser->mark.index)) {
1071              
1072             /* Check if the potential simple key to be removed is required. */
1073              
1074 98 50         if (simple_key->required) {
1075 0           return yaml_parser_set_scanner_error(parser,
1076             "while scanning a simple key", simple_key->mark,
1077             "could not find expected ':'");
1078             }
1079              
1080 98           simple_key->possible = 0;
1081             }
1082             }
1083              
1084 2550           return 1;
1085             }
1086              
1087             /*
1088             * Check if a simple key may start at the current position and add it if
1089             * needed.
1090             */
1091              
1092             static int
1093 473           yaml_parser_save_simple_key(yaml_parser_t *parser)
1094             {
1095             /*
1096             * A simple key is required at the current position if the scanner is in
1097             * the block context and the current column coincides with the indentation
1098             * level.
1099             */
1100              
1101 946           int required = (!parser->flow_level
1102 473 100         && parser->indent == (ptrdiff_t)parser->mark.column);
    100          
1103              
1104             /*
1105             * If the current position may start a simple key, save it.
1106             */
1107              
1108 473 100         if (parser->simple_key_allowed)
1109             {
1110             yaml_simple_key_t simple_key;
1111 248           simple_key.possible = 1;
1112 248           simple_key.required = required;
1113 248           simple_key.token_number =
1114 248           parser->tokens_parsed + (parser->tokens.tail - parser->tokens.head);
1115 248           simple_key.mark = parser->mark;
1116              
1117 248 50         if (!yaml_parser_remove_simple_key(parser)) return 0;
1118              
1119 248           *(parser->simple_keys.top-1) = simple_key;
1120             }
1121              
1122 473           return 1;
1123             }
1124              
1125             /*
1126             * Remove a potential simple key at the current flow level.
1127             */
1128              
1129             static int
1130 600           yaml_parser_remove_simple_key(yaml_parser_t *parser)
1131             {
1132 600           yaml_simple_key_t *simple_key = parser->simple_keys.top-1;
1133              
1134 600 100         if (simple_key->possible)
1135             {
1136             /* If the key is required, it is an error. */
1137              
1138 24 50         if (simple_key->required) {
1139 0           return yaml_parser_set_scanner_error(parser,
1140             "while scanning a simple key", simple_key->mark,
1141             "could not find expected ':'");
1142             }
1143             }
1144              
1145             /* Remove the key from the stack. */
1146              
1147 600           simple_key->possible = 0;
1148              
1149 600           return 1;
1150             }
1151              
1152             /*
1153             * Increase the flow level and resize the simple key list if needed.
1154             */
1155              
1156             static int
1157 26           yaml_parser_increase_flow_level(yaml_parser_t *parser)
1158             {
1159 26           yaml_simple_key_t empty_simple_key = { 0, 0, 0, { 0, 0, 0 } };
1160              
1161             /* Reset the simple key on the next level. */
1162              
1163 26 50         if (!PUSH(parser, parser->simple_keys, empty_simple_key))
    0          
    50          
1164 0           return 0;
1165              
1166             /* Increase the flow level. */
1167              
1168 26 50         if (parser->flow_level == INT_MAX) {
1169 0           parser->error = YAML_MEMORY_ERROR;
1170 0           return 0;
1171             }
1172              
1173 26           parser->flow_level++;
1174              
1175 26           return 1;
1176             }
1177              
1178             /*
1179             * Decrease the flow level.
1180             */
1181              
1182             static int
1183 26           yaml_parser_decrease_flow_level(yaml_parser_t *parser)
1184             {
1185 26 50         if (parser->flow_level) {
1186 26           parser->flow_level --;
1187 26           (void)POP(parser, parser->simple_keys);
1188             }
1189              
1190 26           return 1;
1191             }
1192              
1193             /*
1194             * Push the current indentation level to the stack and set the new level
1195             * the current column is greater than the indentation level. In this case,
1196             * append or insert the specified token into the token queue.
1197             *
1198             */
1199              
1200             static int
1201 238           yaml_parser_roll_indent(yaml_parser_t *parser, ptrdiff_t column,
1202             ptrdiff_t number, yaml_token_type_t type, yaml_mark_t mark)
1203             {
1204             yaml_token_t token;
1205              
1206             /* In the flow context, do nothing. */
1207              
1208 238 100         if (parser->flow_level)
1209 10           return 1;
1210              
1211 228 100         if (parser->indent < column)
1212             {
1213             /*
1214             * Push the current indentation level to the stack and set the new
1215             * indentation level.
1216             */
1217              
1218 99 50         if (!PUSH(parser, parser->indents, parser->indent))
    0          
    50          
1219 0           return 0;
1220              
1221 99 50         if (column > INT_MAX) {
1222 0           parser->error = YAML_MEMORY_ERROR;
1223 0           return 0;
1224             }
1225              
1226 99           parser->indent = column;
1227              
1228             /* Create a token and insert it into the queue. */
1229              
1230 99           TOKEN_INIT(token, type, mark, mark);
1231              
1232 99 100         if (number == -1) {
1233 37 50         if (!ENQUEUE(parser, parser->tokens, token))
    0          
    50          
1234 0           return 0;
1235             }
1236             else {
1237 62 50         if (!QUEUE_INSERT(parser,
    0          
    50          
1238             parser->tokens, number - parser->tokens_parsed, token))
1239 0           return 0;
1240             }
1241             }
1242              
1243 238           return 1;
1244             }
1245              
1246             /*
1247             * Pop indentation levels from the indents stack until the current level
1248             * becomes less or equal to the column. For each indentation level, append
1249             * the BLOCK-END token.
1250             */
1251              
1252              
1253             static int
1254 1149           yaml_parser_unroll_indent(yaml_parser_t *parser, ptrdiff_t column)
1255             {
1256             yaml_token_t token;
1257              
1258             /* In the flow context, do nothing. */
1259              
1260 1149 100         if (parser->flow_level)
1261 79           return 1;
1262              
1263             /* Loop through the indentation levels in the stack. */
1264              
1265 1166 100         while (parser->indent > column)
1266             {
1267             /* Create a token and append it to the queue. */
1268              
1269 96           TOKEN_INIT(token, YAML_BLOCK_END_TOKEN, parser->mark, parser->mark);
1270              
1271 96 100         if (!ENQUEUE(parser, parser->tokens, token))
    50          
    50          
1272 0           return 0;
1273              
1274             /* Pop the indentation level. */
1275              
1276 96           parser->indent = POP(parser, parser->indents);
1277             }
1278              
1279 1149           return 1;
1280             }
1281              
1282             /*
1283             * Initialize the scanner and produce the STREAM-START token.
1284             */
1285              
1286             static int
1287 108           yaml_parser_fetch_stream_start(yaml_parser_t *parser)
1288             {
1289 108           yaml_simple_key_t simple_key = { 0, 0, 0, { 0, 0, 0 } };
1290             yaml_token_t token;
1291              
1292             /* Set the initial indentation. */
1293              
1294 108           parser->indent = -1;
1295              
1296             /* Initialize the simple key stack. */
1297              
1298 108 50         if (!PUSH(parser, parser->simple_keys, simple_key))
    0          
    50          
1299 0           return 0;
1300              
1301             /* A simple key is allowed at the beginning of the stream. */
1302              
1303 108           parser->simple_key_allowed = 1;
1304              
1305             /* We have started. */
1306              
1307 108           parser->stream_start_produced = 1;
1308              
1309             /* Create the STREAM-START token and append it to the queue. */
1310              
1311 108           STREAM_START_TOKEN_INIT(token, parser->encoding,
1312             parser->mark, parser->mark);
1313              
1314 108 50         if (!ENQUEUE(parser, parser->tokens, token))
    0          
    50          
1315 0           return 0;
1316              
1317 108           return 1;
1318             }
1319              
1320             /*
1321             * Produce the STREAM-END token and shut down the scanner.
1322             */
1323              
1324             static int
1325 101           yaml_parser_fetch_stream_end(yaml_parser_t *parser)
1326             {
1327             yaml_token_t token;
1328              
1329             /* Force new line. */
1330              
1331 101 100         if (parser->mark.column != 0) {
1332 5           parser->mark.column = 0;
1333 5           parser->mark.line ++;
1334             }
1335              
1336             /* Reset the indentation level. */
1337              
1338 101 50         if (!yaml_parser_unroll_indent(parser, -1))
1339 0           return 0;
1340              
1341             /* Reset simple keys. */
1342              
1343 101 50         if (!yaml_parser_remove_simple_key(parser))
1344 0           return 0;
1345              
1346 101           parser->simple_key_allowed = 0;
1347              
1348             /* Create the STREAM-END token and append it to the queue. */
1349              
1350 101           STREAM_END_TOKEN_INIT(token, parser->mark, parser->mark);
1351              
1352 101 100         if (!ENQUEUE(parser, parser->tokens, token))
    50          
    50          
1353 0           return 0;
1354              
1355 101           return 1;
1356             }
1357              
1358             /*
1359             * Produce a VERSION-DIRECTIVE or TAG-DIRECTIVE token.
1360             */
1361              
1362             static int
1363 0           yaml_parser_fetch_directive(yaml_parser_t *parser)
1364             {
1365             yaml_token_t token;
1366              
1367             /* Reset the indentation level. */
1368              
1369 0 0         if (!yaml_parser_unroll_indent(parser, -1))
1370 0           return 0;
1371              
1372             /* Reset simple keys. */
1373              
1374 0 0         if (!yaml_parser_remove_simple_key(parser))
1375 0           return 0;
1376              
1377 0           parser->simple_key_allowed = 0;
1378              
1379             /* Create the YAML-DIRECTIVE or TAG-DIRECTIVE token. */
1380              
1381 0 0         if (!yaml_parser_scan_directive(parser, &token))
1382 0           return 0;
1383              
1384             /* Append the token to the queue. */
1385              
1386 0 0         if (!ENQUEUE(parser, parser->tokens, token)) {
    0          
    0          
1387 0           yaml_token_delete(&token);
1388 0           return 0;
1389             }
1390              
1391 0           return 1;
1392             }
1393              
1394             /*
1395             * Produce the DOCUMENT-START or DOCUMENT-END token.
1396             */
1397              
1398             static int
1399 97           yaml_parser_fetch_document_indicator(yaml_parser_t *parser,
1400             yaml_token_type_t type)
1401             {
1402             yaml_mark_t start_mark, end_mark;
1403             yaml_token_t token;
1404              
1405             /* Reset the indentation level. */
1406              
1407 97 50         if (!yaml_parser_unroll_indent(parser, -1))
1408 0           return 0;
1409              
1410             /* Reset simple keys. */
1411              
1412 97 50         if (!yaml_parser_remove_simple_key(parser))
1413 0           return 0;
1414              
1415 97           parser->simple_key_allowed = 0;
1416              
1417             /* Consume the token. */
1418              
1419 97           start_mark = parser->mark;
1420              
1421 97 50         SKIP(parser);
    0          
    0          
    0          
1422 97 50         SKIP(parser);
    0          
    0          
    0          
1423 97 50         SKIP(parser);
    0          
    0          
    0          
1424              
1425 97           end_mark = parser->mark;
1426              
1427             /* Create the DOCUMENT-START or DOCUMENT-END token. */
1428              
1429 97           TOKEN_INIT(token, type, start_mark, end_mark);
1430              
1431             /* Append the token to the queue. */
1432              
1433 97 50         if (!ENQUEUE(parser, parser->tokens, token))
    0          
    50          
1434 0           return 0;
1435              
1436 97           return 1;
1437             }
1438              
1439             /*
1440             * Produce the FLOW-SEQUENCE-START or FLOW-MAPPING-START token.
1441             */
1442              
1443             static int
1444 26           yaml_parser_fetch_flow_collection_start(yaml_parser_t *parser,
1445             yaml_token_type_t type)
1446             {
1447             yaml_mark_t start_mark, end_mark;
1448             yaml_token_t token;
1449              
1450             /* The indicators '[' and '{' may start a simple key. */
1451              
1452 26 50         if (!yaml_parser_save_simple_key(parser))
1453 0           return 0;
1454              
1455             /* Increase the flow level. */
1456              
1457 26 50         if (!yaml_parser_increase_flow_level(parser))
1458 0           return 0;
1459              
1460             /* A simple key may follow the indicators '[' and '{'. */
1461              
1462 26           parser->simple_key_allowed = 1;
1463              
1464             /* Consume the token. */
1465              
1466 26           start_mark = parser->mark;
1467 26 50         SKIP(parser);
    0          
    0          
    0          
1468 26           end_mark = parser->mark;
1469              
1470             /* Create the FLOW-SEQUENCE-START of FLOW-MAPPING-START token. */
1471              
1472 26           TOKEN_INIT(token, type, start_mark, end_mark);
1473              
1474             /* Append the token to the queue. */
1475              
1476 26 100         if (!ENQUEUE(parser, parser->tokens, token))
    50          
    50          
1477 0           return 0;
1478              
1479 26           return 1;
1480             }
1481              
1482             /*
1483             * Produce the FLOW-SEQUENCE-END or FLOW-MAPPING-END token.
1484             */
1485              
1486             static int
1487 26           yaml_parser_fetch_flow_collection_end(yaml_parser_t *parser,
1488             yaml_token_type_t type)
1489             {
1490             yaml_mark_t start_mark, end_mark;
1491             yaml_token_t token;
1492              
1493             /* Reset any potential simple key on the current flow level. */
1494              
1495 26 50         if (!yaml_parser_remove_simple_key(parser))
1496 0           return 0;
1497              
1498             /* Decrease the flow level. */
1499              
1500 26 50         if (!yaml_parser_decrease_flow_level(parser))
1501 0           return 0;
1502              
1503             /* No simple keys after the indicators ']' and '}'. */
1504              
1505 26           parser->simple_key_allowed = 0;
1506              
1507             /* Consume the token. */
1508              
1509 26           start_mark = parser->mark;
1510 26 50         SKIP(parser);
    0          
    0          
    0          
1511 26           end_mark = parser->mark;
1512              
1513             /* Create the FLOW-SEQUENCE-END of FLOW-MAPPING-END token. */
1514              
1515 26           TOKEN_INIT(token, type, start_mark, end_mark);
1516              
1517             /* Append the token to the queue. */
1518              
1519 26 100         if (!ENQUEUE(parser, parser->tokens, token))
    50          
    50          
1520 0           return 0;
1521              
1522 26           return 1;
1523             }
1524              
1525             /*
1526             * Produce the FLOW-ENTRY token.
1527             */
1528              
1529             static int
1530 8           yaml_parser_fetch_flow_entry(yaml_parser_t *parser)
1531             {
1532             yaml_mark_t start_mark, end_mark;
1533             yaml_token_t token;
1534              
1535             /* Reset any potential simple keys on the current flow level. */
1536              
1537 8 50         if (!yaml_parser_remove_simple_key(parser))
1538 0           return 0;
1539              
1540             /* Simple keys are allowed after ','. */
1541              
1542 8           parser->simple_key_allowed = 1;
1543              
1544             /* Consume the token. */
1545              
1546 8           start_mark = parser->mark;
1547 8 50         SKIP(parser);
    0          
    0          
    0          
1548 8           end_mark = parser->mark;
1549              
1550             /* Create the FLOW-ENTRY token and append it to the queue. */
1551              
1552 8           TOKEN_INIT(token, YAML_FLOW_ENTRY_TOKEN, start_mark, end_mark);
1553              
1554 8 100         if (!ENQUEUE(parser, parser->tokens, token))
    50          
    50          
1555 0           return 0;
1556              
1557 8           return 1;
1558             }
1559              
1560             /*
1561             * Produce the BLOCK-ENTRY token.
1562             */
1563              
1564             static int
1565 113           yaml_parser_fetch_block_entry(yaml_parser_t *parser)
1566             {
1567             yaml_mark_t start_mark, end_mark;
1568             yaml_token_t token;
1569              
1570             /* Check if the scanner is in the block context. */
1571              
1572 113 50         if (!parser->flow_level)
1573             {
1574             /* Check if we are allowed to start a new entry. */
1575              
1576 113 50         if (!parser->simple_key_allowed) {
1577 0           return yaml_parser_set_scanner_error(parser, NULL, parser->mark,
1578             "block sequence entries are not allowed in this context");
1579             }
1580              
1581             /* Add the BLOCK-SEQUENCE-START token if needed. */
1582              
1583 113 50         if (!yaml_parser_roll_indent(parser, parser->mark.column, -1,
1584             YAML_BLOCK_SEQUENCE_START_TOKEN, parser->mark))
1585 0           return 0;
1586             }
1587             else
1588             {
1589             /*
1590             * It is an error for the '-' indicator to occur in the flow context,
1591             * but we let the Parser detect and report about it because the Parser
1592             * is able to point to the context.
1593             */
1594             }
1595              
1596             /* Reset any potential simple keys on the current flow level. */
1597              
1598 113 50         if (!yaml_parser_remove_simple_key(parser))
1599 0           return 0;
1600              
1601             /* Simple keys are allowed after '-'. */
1602              
1603 113           parser->simple_key_allowed = 1;
1604              
1605             /* Consume the token. */
1606              
1607 113           start_mark = parser->mark;
1608 113 50         SKIP(parser);
    0          
    0          
    0          
1609 113           end_mark = parser->mark;
1610              
1611             /* Create the BLOCK-ENTRY token and append it to the queue. */
1612              
1613 113           TOKEN_INIT(token, YAML_BLOCK_ENTRY_TOKEN, start_mark, end_mark);
1614              
1615 113 100         if (!ENQUEUE(parser, parser->tokens, token))
    50          
    50          
1616 0           return 0;
1617              
1618 113           return 1;
1619             }
1620              
1621             /*
1622             * Produce the KEY token.
1623             */
1624              
1625             static int
1626 0           yaml_parser_fetch_key(yaml_parser_t *parser)
1627             {
1628             yaml_mark_t start_mark, end_mark;
1629             yaml_token_t token;
1630              
1631             /* In the block context, additional checks are required. */
1632              
1633 0 0         if (!parser->flow_level)
1634             {
1635             /* Check if we are allowed to start a new key (not necessary simple). */
1636              
1637 0 0         if (!parser->simple_key_allowed) {
1638 0           return yaml_parser_set_scanner_error(parser, NULL, parser->mark,
1639             "mapping keys are not allowed in this context");
1640             }
1641              
1642             /* Add the BLOCK-MAPPING-START token if needed. */
1643              
1644 0 0         if (!yaml_parser_roll_indent(parser, parser->mark.column, -1,
1645             YAML_BLOCK_MAPPING_START_TOKEN, parser->mark))
1646 0           return 0;
1647             }
1648              
1649             /* Reset any potential simple keys on the current flow level. */
1650              
1651 0 0         if (!yaml_parser_remove_simple_key(parser))
1652 0           return 0;
1653              
1654             /* Simple keys are allowed after '?' in the block context. */
1655              
1656 0           parser->simple_key_allowed = (!parser->flow_level);
1657              
1658             /* Consume the token. */
1659              
1660 0           start_mark = parser->mark;
1661 0 0         SKIP(parser);
    0          
    0          
    0          
1662 0           end_mark = parser->mark;
1663              
1664             /* Create the KEY token and append it to the queue. */
1665              
1666 0           TOKEN_INIT(token, YAML_KEY_TOKEN, start_mark, end_mark);
1667              
1668 0 0         if (!ENQUEUE(parser, parser->tokens, token))
    0          
    0          
1669 0           return 0;
1670              
1671 0           return 1;
1672             }
1673              
1674             /*
1675             * Produce the VALUE token.
1676             */
1677              
1678             static int
1679 126           yaml_parser_fetch_value(yaml_parser_t *parser)
1680             {
1681             yaml_mark_t start_mark, end_mark;
1682             yaml_token_t token;
1683 126           yaml_simple_key_t *simple_key = parser->simple_keys.top-1;
1684              
1685             /* Have we found a simple key? */
1686              
1687 126 100         if (simple_key->possible)
1688             {
1689              
1690             /* Create the KEY token and insert it into the queue. */
1691              
1692 125           TOKEN_INIT(token, YAML_KEY_TOKEN, simple_key->mark, simple_key->mark);
1693              
1694 125 100         if (!QUEUE_INSERT(parser, parser->tokens,
    50          
    50          
1695             simple_key->token_number - parser->tokens_parsed, token))
1696 0           return 0;
1697              
1698             /* In the block context, we may need to add the BLOCK-MAPPING-START token. */
1699              
1700 125 50         if (!yaml_parser_roll_indent(parser, simple_key->mark.column,
1701 125           simple_key->token_number,
1702             YAML_BLOCK_MAPPING_START_TOKEN, simple_key->mark))
1703 0           return 0;
1704              
1705             /* Remove the simple key. */
1706              
1707 125           simple_key->possible = 0;
1708              
1709             /* A simple key cannot follow another simple key. */
1710              
1711 125           parser->simple_key_allowed = 0;
1712             }
1713             else
1714             {
1715             /* The ':' indicator follows a complex key. */
1716              
1717             /* In the block context, extra checks are required. */
1718              
1719 1 50         if (!parser->flow_level)
1720             {
1721             /* Check if we are allowed to start a complex value. */
1722              
1723 1 50         if (!parser->simple_key_allowed) {
1724 1           return yaml_parser_set_scanner_error(parser, NULL, parser->mark,
1725             "mapping values are not allowed in this context");
1726             }
1727              
1728             /* Add the BLOCK-MAPPING-START token if needed. */
1729              
1730 0 0         if (!yaml_parser_roll_indent(parser, parser->mark.column, -1,
1731             YAML_BLOCK_MAPPING_START_TOKEN, parser->mark))
1732 0           return 0;
1733             }
1734              
1735             /* Simple keys after ':' are allowed in the block context. */
1736              
1737 0           parser->simple_key_allowed = (!parser->flow_level);
1738             }
1739              
1740             /* Consume the token. */
1741              
1742 125           start_mark = parser->mark;
1743 125 50         SKIP(parser);
    0          
    0          
    0          
1744 125           end_mark = parser->mark;
1745              
1746             /* Create the VALUE token and append it to the queue. */
1747              
1748 125           TOKEN_INIT(token, YAML_VALUE_TOKEN, start_mark, end_mark);
1749              
1750 125 100         if (!ENQUEUE(parser, parser->tokens, token))
    50          
    50          
1751 0           return 0;
1752              
1753 126           return 1;
1754             }
1755              
1756             /*
1757             * Produce the ALIAS or ANCHOR token.
1758             */
1759              
1760             static int
1761 36           yaml_parser_fetch_anchor(yaml_parser_t *parser, yaml_token_type_t type)
1762             {
1763             yaml_token_t token;
1764              
1765             /* An anchor or an alias could be a simple key. */
1766              
1767 36 50         if (!yaml_parser_save_simple_key(parser))
1768 0           return 0;
1769              
1770             /* A simple key cannot follow an anchor or an alias. */
1771              
1772 36           parser->simple_key_allowed = 0;
1773              
1774             /* Create the ALIAS or ANCHOR token and append it to the queue. */
1775              
1776 36 100         if (!yaml_parser_scan_anchor(parser, &token, type))
1777 3           return 0;
1778              
1779 33 100         if (!ENQUEUE(parser, parser->tokens, token)) {
    50          
    50          
1780 0           yaml_token_delete(&token);
1781 0           return 0;
1782             }
1783 36           return 1;
1784             }
1785              
1786             /*
1787             * Produce the TAG token.
1788             */
1789              
1790             static int
1791 82           yaml_parser_fetch_tag(yaml_parser_t *parser)
1792             {
1793             yaml_token_t token;
1794              
1795             /* A tag could be a simple key. */
1796              
1797 82 50         if (!yaml_parser_save_simple_key(parser))
1798 0           return 0;
1799              
1800             /* A simple key cannot follow a tag. */
1801              
1802 82           parser->simple_key_allowed = 0;
1803              
1804             /* Create the TAG token and append it to the queue. */
1805              
1806 82 50         if (!yaml_parser_scan_tag(parser, &token))
1807 0           return 0;
1808              
1809 82 50         if (!ENQUEUE(parser, parser->tokens, token)) {
    0          
    50          
1810 0           yaml_token_delete(&token);
1811 0           return 0;
1812             }
1813              
1814 82           return 1;
1815             }
1816              
1817             /*
1818             * Produce the SCALAR(...,literal) or SCALAR(...,folded) tokens.
1819             */
1820              
1821             static int
1822 7           yaml_parser_fetch_block_scalar(yaml_parser_t *parser, int literal)
1823             {
1824             yaml_token_t token;
1825              
1826             /* Remove any potential simple keys. */
1827              
1828 7 50         if (!yaml_parser_remove_simple_key(parser))
1829 0           return 0;
1830              
1831             /* A simple key may follow a block scalar. */
1832              
1833 7           parser->simple_key_allowed = 1;
1834              
1835             /* Create the SCALAR token and append it to the queue. */
1836              
1837 7 50         if (!yaml_parser_scan_block_scalar(parser, &token, literal))
1838 0           return 0;
1839              
1840 7 50         if (!ENQUEUE(parser, parser->tokens, token)) {
    0          
    50          
1841 0           yaml_token_delete(&token);
1842 0           return 0;
1843             }
1844              
1845 7           return 1;
1846             }
1847              
1848             /*
1849             * Produce the SCALAR(...,single-quoted) or SCALAR(...,double-quoted) tokens.
1850             */
1851              
1852             static int
1853 27           yaml_parser_fetch_flow_scalar(yaml_parser_t *parser, int single)
1854             {
1855             yaml_token_t token;
1856              
1857             /* A plain scalar could be a simple key. */
1858              
1859 27 50         if (!yaml_parser_save_simple_key(parser))
1860 0           return 0;
1861              
1862             /* A simple key cannot follow a flow scalar. */
1863              
1864 27           parser->simple_key_allowed = 0;
1865              
1866             /* Create the SCALAR token and append it to the queue. */
1867              
1868 27 50         if (!yaml_parser_scan_flow_scalar(parser, &token, single))
1869 0           return 0;
1870              
1871 27 100         if (!ENQUEUE(parser, parser->tokens, token)) {
    50          
    50          
1872 0           yaml_token_delete(&token);
1873 0           return 0;
1874             }
1875              
1876 27           return 1;
1877             }
1878              
1879             /*
1880             * Produce the SCALAR(...,plain) token.
1881             */
1882              
1883             static int
1884 302           yaml_parser_fetch_plain_scalar(yaml_parser_t *parser)
1885             {
1886             yaml_token_t token;
1887              
1888             /* A plain scalar could be a simple key. */
1889              
1890 302 50         if (!yaml_parser_save_simple_key(parser))
1891 0           return 0;
1892              
1893             /* A simple key cannot follow a flow scalar. */
1894              
1895 302           parser->simple_key_allowed = 0;
1896              
1897             /* Create the SCALAR token and append it to the queue. */
1898              
1899 302 50         if (!yaml_parser_scan_plain_scalar(parser, &token))
1900 0           return 0;
1901              
1902 302 100         if (!ENQUEUE(parser, parser->tokens, token)) {
    50          
    50          
1903 0           yaml_token_delete(&token);
1904 0           return 0;
1905             }
1906              
1907 302           return 1;
1908             }
1909              
1910             /*
1911             * Eat whitespaces and comments until the next token is found.
1912             */
1913              
1914             static int
1915 951           yaml_parser_scan_to_next_token(yaml_parser_t *parser)
1916             {
1917             /* Until the next token is not found. */
1918              
1919             while (1)
1920             {
1921             /* Allow the BOM mark to start a line. */
1922              
1923 1114 50         if (!CACHE(parser, 1)) return 0;
    0          
1924              
1925 1114 100         if (parser->mark.column == 0 && IS_BOM(parser->buffer))
    50          
    0          
    0          
1926 0 0         SKIP(parser);
    0          
    0          
    0          
1927              
1928             /*
1929             * Eat whitespaces.
1930             *
1931             * Tabs are allowed:
1932             *
1933             * - in the flow context;
1934             * - in the block context, but not at the beginning of the line or
1935             * after '-', '?', or ':' (complex value).
1936             */
1937              
1938 1114 50         if (!CACHE(parser, 1)) return 0;
    0          
1939              
1940 1591 100         while (CHECK(parser->buffer,' ') ||
    100          
1941 1114 100         ((parser->flow_level || !parser->simple_key_allowed) &&
    50          
1942 572           CHECK(parser->buffer, '\t'))) {
1943 477 50         SKIP(parser);
    0          
    0          
    0          
1944 477 50         if (!CACHE(parser, 1)) return 0;
    0          
1945             }
1946              
1947             /* Eat a comment until a line break. */
1948              
1949 1114 100         if (CHECK(parser->buffer, '#')) {
1950 54 50         while (!IS_BREAKZ(parser->buffer)) {
    100          
    50          
    0          
    50          
    0          
    0          
    50          
    0          
    0          
    50          
1951 52 50         SKIP(parser);
    0          
    0          
    0          
1952 52 50         if (!CACHE(parser, 1)) return 0;
    0          
1953             }
1954             }
1955              
1956             /* If it is a line break, eat it. */
1957              
1958 1114 50         if (IS_BREAK(parser->buffer))
    100          
    50          
    0          
    50          
    0          
    0          
    50          
    0          
    0          
1959             {
1960 163 100         if (!CACHE(parser, 2)) return 0;
    50          
1961 163 50         SKIP_LINE(parser);
    0          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    0          
    0          
    0          
1962              
1963             /* In the block context, a new line may start a simple key. */
1964              
1965 163 100         if (!parser->flow_level) {
1966 161           parser->simple_key_allowed = 1;
1967             }
1968             }
1969             else
1970             {
1971             /* We have found a token. */
1972              
1973             break;
1974             }
1975 163           }
1976              
1977 951           return 1;
1978             }
1979              
1980             /*
1981             * Scan a YAML-DIRECTIVE or TAG-DIRECTIVE token.
1982             *
1983             * Scope:
1984             * %YAML 1.1 # a comment \n
1985             * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1986             * %TAG !yaml! tag:yaml.org,2002: \n
1987             * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1988             */
1989              
1990             int
1991 0           yaml_parser_scan_directive(yaml_parser_t *parser, yaml_token_t *token)
1992             {
1993             yaml_mark_t start_mark, end_mark;
1994 0           yaml_char_t *name = NULL;
1995             int major, minor;
1996 0           yaml_char_t *handle = NULL, *prefix = NULL;
1997              
1998             /* Eat '%'. */
1999              
2000 0           start_mark = parser->mark;
2001              
2002 0 0         SKIP(parser);
    0          
    0          
    0          
2003              
2004             /* Scan the directive name. */
2005              
2006 0 0         if (!yaml_parser_scan_directive_name(parser, start_mark, &name))
2007 0           goto error;
2008              
2009             /* Is it a YAML directive? */
2010              
2011 0 0         if (strcmp((char *)name, "YAML") == 0)
2012             {
2013             /* Scan the VERSION directive value. */
2014              
2015 0 0         if (!yaml_parser_scan_version_directive_value(parser, start_mark,
2016             &major, &minor))
2017 0           goto error;
2018              
2019 0           end_mark = parser->mark;
2020              
2021             /* Create a VERSION-DIRECTIVE token. */
2022              
2023 0           VERSION_DIRECTIVE_TOKEN_INIT(*token, major, minor,
2024             start_mark, end_mark);
2025             }
2026              
2027             /* Is it a TAG directive? */
2028              
2029 0 0         else if (strcmp((char *)name, "TAG") == 0)
2030             {
2031             /* Scan the TAG directive value. */
2032              
2033 0 0         if (!yaml_parser_scan_tag_directive_value(parser, start_mark,
2034             &handle, &prefix))
2035 0           goto error;
2036              
2037 0           end_mark = parser->mark;
2038              
2039             /* Create a TAG-DIRECTIVE token. */
2040              
2041 0           TAG_DIRECTIVE_TOKEN_INIT(*token, handle, prefix,
2042             start_mark, end_mark);
2043             }
2044              
2045             /* Unknown directive. */
2046              
2047             else
2048             {
2049 0           yaml_parser_set_scanner_error(parser, "while scanning a directive",
2050             start_mark, "found unknown directive name");
2051 0           goto error;
2052             }
2053              
2054             /* Eat the rest of the line including any comments. */
2055              
2056 0 0         if (!CACHE(parser, 1)) goto error;
    0          
2057              
2058 0 0         while (IS_BLANK(parser->buffer)) {
    0          
2059 0 0         SKIP(parser);
    0          
    0          
    0          
2060 0 0         if (!CACHE(parser, 1)) goto error;
    0          
2061             }
2062              
2063 0 0         if (CHECK(parser->buffer, '#')) {
2064 0 0         while (!IS_BREAKZ(parser->buffer)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
2065 0 0         SKIP(parser);
    0          
    0          
    0          
2066 0 0         if (!CACHE(parser, 1)) goto error;
    0          
2067             }
2068             }
2069              
2070             /* Check if we are at the end of the line. */
2071              
2072 0 0         if (!IS_BREAKZ(parser->buffer)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
2073 0           yaml_parser_set_scanner_error(parser, "while scanning a directive",
2074             start_mark, "did not find expected comment or line break");
2075 0           goto error;
2076             }
2077              
2078             /* Eat a line break. */
2079              
2080 0 0         if (IS_BREAK(parser->buffer)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
2081 0 0         if (!CACHE(parser, 2)) goto error;
    0          
2082 0 0         SKIP_LINE(parser);
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
2083             }
2084              
2085 0           yaml_free(name);
2086              
2087 0           return 1;
2088              
2089             error:
2090 0           yaml_free(prefix);
2091 0           yaml_free(handle);
2092 0           yaml_free(name);
2093 0           return 0;
2094             }
2095              
2096             /*
2097             * Scan the directive name.
2098             *
2099             * Scope:
2100             * %YAML 1.1 # a comment \n
2101             * ^^^^
2102             * %TAG !yaml! tag:yaml.org,2002: \n
2103             * ^^^
2104             */
2105              
2106             static int
2107 0           yaml_parser_scan_directive_name(yaml_parser_t *parser,
2108             yaml_mark_t start_mark, yaml_char_t **name)
2109             {
2110 0           yaml_string_t string = NULL_STRING;
2111              
2112 0 0         if (!STRING_INIT(parser, string, INITIAL_STRING_SIZE)) goto error;
    0          
2113              
2114             /* Consume the directive name. */
2115              
2116 0 0         if (!CACHE(parser, 1)) goto error;
    0          
2117              
2118 0 0         while (IS_ALPHA(parser->buffer))
    0          
    0          
    0          
    0          
    0          
    0          
    0          
2119             {
2120 0 0         if (!READ(parser, string)) goto error;
    0          
    0          
    0          
    0          
    0          
    0          
    0          
2121 0 0         if (!CACHE(parser, 1)) goto error;
    0          
2122             }
2123              
2124             /* Check if the name is empty. */
2125              
2126 0 0         if (string.start == string.pointer) {
2127 0           yaml_parser_set_scanner_error(parser, "while scanning a directive",
2128             start_mark, "could not find expected directive name");
2129 0           goto error;
2130             }
2131              
2132             /* Check for an blank character after the name. */
2133              
2134 0 0         if (!IS_BLANKZ(parser->buffer)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
2135 0           yaml_parser_set_scanner_error(parser, "while scanning a directive",
2136             start_mark, "found unexpected non-alphabetical character");
2137 0           goto error;
2138             }
2139              
2140 0           *name = string.start;
2141              
2142 0           return 1;
2143              
2144             error:
2145 0           STRING_DEL(parser, string);
2146 0           return 0;
2147             }
2148              
2149             /*
2150             * Scan the value of VERSION-DIRECTIVE.
2151             *
2152             * Scope:
2153             * %YAML 1.1 # a comment \n
2154             * ^^^^^^
2155             */
2156              
2157             static int
2158 0           yaml_parser_scan_version_directive_value(yaml_parser_t *parser,
2159             yaml_mark_t start_mark, int *major, int *minor)
2160             {
2161             /* Eat whitespaces. */
2162              
2163 0 0         if (!CACHE(parser, 1)) return 0;
    0          
2164              
2165 0 0         while (IS_BLANK(parser->buffer)) {
    0          
2166 0 0         SKIP(parser);
    0          
    0          
    0          
2167 0 0         if (!CACHE(parser, 1)) return 0;
    0          
2168             }
2169              
2170             /* Consume the major version number. */
2171              
2172 0 0         if (!yaml_parser_scan_version_directive_number(parser, start_mark, major))
2173 0           return 0;
2174              
2175             /* Eat '.'. */
2176              
2177 0 0         if (!CHECK(parser->buffer, '.')) {
2178 0           return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive",
2179             start_mark, "did not find expected digit or '.' character");
2180             }
2181              
2182 0 0         SKIP(parser);
    0          
    0          
    0          
2183              
2184             /* Consume the minor version number. */
2185              
2186 0 0         if (!yaml_parser_scan_version_directive_number(parser, start_mark, minor))
2187 0           return 0;
2188              
2189 0           return 1;
2190             }
2191              
2192             #define MAX_NUMBER_LENGTH 9
2193              
2194             /*
2195             * Scan the version number of VERSION-DIRECTIVE.
2196             *
2197             * Scope:
2198             * %YAML 1.1 # a comment \n
2199             * ^
2200             * %YAML 1.1 # a comment \n
2201             * ^
2202             */
2203              
2204             static int
2205 0           yaml_parser_scan_version_directive_number(yaml_parser_t *parser,
2206             yaml_mark_t start_mark, int *number)
2207             {
2208 0           int value = 0;
2209 0           size_t length = 0;
2210              
2211             /* Repeat while the next character is digit. */
2212              
2213 0 0         if (!CACHE(parser, 1)) return 0;
    0          
2214              
2215 0 0         while (IS_DIGIT(parser->buffer))
    0          
2216             {
2217             /* Check if the number is too long. */
2218              
2219 0 0         if (++length > MAX_NUMBER_LENGTH) {
2220 0           return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive",
2221             start_mark, "found extremely long version number");
2222             }
2223              
2224 0           value = value*10 + AS_DIGIT(parser->buffer);
2225              
2226 0 0         SKIP(parser);
    0          
    0          
    0          
2227              
2228 0 0         if (!CACHE(parser, 1)) return 0;
    0          
2229             }
2230              
2231             /* Check if the number was present. */
2232              
2233 0 0         if (!length) {
2234 0           return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive",
2235             start_mark, "did not find expected version number");
2236             }
2237              
2238 0           *number = value;
2239              
2240 0           return 1;
2241             }
2242              
2243             /*
2244             * Scan the value of a TAG-DIRECTIVE token.
2245             *
2246             * Scope:
2247             * %TAG !yaml! tag:yaml.org,2002: \n
2248             * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2249             */
2250              
2251             static int
2252 0           yaml_parser_scan_tag_directive_value(yaml_parser_t *parser,
2253             yaml_mark_t start_mark, yaml_char_t **handle, yaml_char_t **prefix)
2254             {
2255 0           yaml_char_t *handle_value = NULL;
2256 0           yaml_char_t *prefix_value = NULL;
2257              
2258             /* Eat whitespaces. */
2259              
2260 0 0         if (!CACHE(parser, 1)) goto error;
    0          
2261              
2262 0 0         while (IS_BLANK(parser->buffer)) {
    0          
2263 0 0         SKIP(parser);
    0          
    0          
    0          
2264 0 0         if (!CACHE(parser, 1)) goto error;
    0          
2265             }
2266              
2267             /* Scan a handle. */
2268              
2269 0 0         if (!yaml_parser_scan_tag_handle(parser, 1, start_mark, &handle_value))
2270 0           goto error;
2271              
2272             /* Expect a whitespace. */
2273              
2274 0 0         if (!CACHE(parser, 1)) goto error;
    0          
2275              
2276 0 0         if (!IS_BLANK(parser->buffer)) {
    0          
2277 0           yaml_parser_set_scanner_error(parser, "while scanning a %TAG directive",
2278             start_mark, "did not find expected whitespace");
2279 0           goto error;
2280             }
2281              
2282             /* Eat whitespaces. */
2283              
2284 0 0         while (IS_BLANK(parser->buffer)) {
    0          
2285 0 0         SKIP(parser);
    0          
    0          
    0          
2286 0 0         if (!CACHE(parser, 1)) goto error;
    0          
2287             }
2288              
2289             /* Scan a prefix. */
2290              
2291 0 0         if (!yaml_parser_scan_tag_uri(parser, 1, NULL, start_mark, &prefix_value))
2292 0           goto error;
2293              
2294             /* Expect a whitespace or line break. */
2295              
2296 0 0         if (!CACHE(parser, 1)) goto error;
    0          
2297              
2298 0 0         if (!IS_BLANKZ(parser->buffer)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
2299 0           yaml_parser_set_scanner_error(parser, "while scanning a %TAG directive",
2300             start_mark, "did not find expected whitespace or line break");
2301 0           goto error;
2302             }
2303              
2304 0           *handle = handle_value;
2305 0           *prefix = prefix_value;
2306              
2307 0           return 1;
2308              
2309             error:
2310 0           yaml_free(handle_value);
2311 0           yaml_free(prefix_value);
2312 0           return 0;
2313             }
2314              
2315             static int
2316 36           yaml_parser_scan_anchor(yaml_parser_t *parser, yaml_token_t *token,
2317             yaml_token_type_t type)
2318             {
2319 36           int length = 0;
2320             yaml_mark_t start_mark, end_mark;
2321 36           yaml_string_t string = NULL_STRING;
2322              
2323 36 50         if (!STRING_INIT(parser, string, INITIAL_STRING_SIZE)) goto error;
    50          
2324              
2325             /* Eat the indicator character. */
2326              
2327 36           start_mark = parser->mark;
2328              
2329 36 50         SKIP(parser);
    0          
    0          
    0          
2330              
2331             /* Consume the value. */
2332              
2333 36 50         if (!CACHE(parser, 1)) goto error;
    0          
2334              
2335 129 100         while (IS_ALPHA(parser->buffer)) {
    100          
    100          
    50          
    100          
    50          
    50          
    50          
2336 93 50         if (!READ(parser, string)) goto error;
    0          
    50          
    50          
    0          
    0          
    0          
    50          
2337 93 50         if (!CACHE(parser, 1)) goto error;
    0          
2338 93           length ++;
2339             }
2340              
2341 36           end_mark = parser->mark;
2342              
2343             /*
2344             * Check if length of the anchor is greater than 0 and it is followed by
2345             * a whitespace character or one of the indicators:
2346             *
2347             * '?', ':', ',', ']', '}', '%', '@', '`'.
2348             */
2349              
2350 36 100         if (!length || !(IS_BLANKZ(parser->buffer) || CHECK(parser->buffer, '?')
    100          
    50          
    50          
    100          
    50          
    0          
    50          
    0          
    0          
    50          
    0          
    0          
    50          
    50          
    0          
2351 2 50         || CHECK(parser->buffer, ':') || CHECK(parser->buffer, ',')
    100          
2352 1 50         || CHECK(parser->buffer, ']') || CHECK(parser->buffer, '}')
    0          
2353 0 0         || CHECK(parser->buffer, '%') || CHECK(parser->buffer, '@')
    0          
2354 0           || CHECK(parser->buffer, '`'))) {
2355 3 50         yaml_parser_set_scanner_error(parser, type == YAML_ANCHOR_TOKEN ?
2356             "while scanning an anchor" : "while scanning an alias", start_mark,
2357             "did not find expected alphabetic or numeric character");
2358 3           goto error;
2359             }
2360              
2361             /* Create a token. */
2362              
2363 33 100         if (type == YAML_ANCHOR_TOKEN) {
2364 17           ANCHOR_TOKEN_INIT(*token, string.start, start_mark, end_mark);
2365             }
2366             else {
2367 16           ALIAS_TOKEN_INIT(*token, string.start, start_mark, end_mark);
2368             }
2369              
2370 33           return 1;
2371              
2372             error:
2373 3           STRING_DEL(parser, string);
2374 36           return 0;
2375             }
2376              
2377             /*
2378             * Scan a TAG token.
2379             */
2380              
2381             static int
2382 82           yaml_parser_scan_tag(yaml_parser_t *parser, yaml_token_t *token)
2383             {
2384 82           yaml_char_t *handle = NULL;
2385 82           yaml_char_t *suffix = NULL;
2386             yaml_mark_t start_mark, end_mark;
2387              
2388 82           start_mark = parser->mark;
2389              
2390             /* Check if the tag is in the canonical form. */
2391              
2392 82 50         if (!CACHE(parser, 2)) goto error;
    0          
2393              
2394 82 100         if (CHECK_AT(parser->buffer, '<', 1))
2395             {
2396             /* Set the handle to '' */
2397              
2398 2           handle = YAML_MALLOC(1);
2399 2 50         if (!handle) goto error;
2400 2           handle[0] = '\0';
2401              
2402             /* Eat '!<' */
2403              
2404 2 50         SKIP(parser);
    0          
    0          
    0          
2405 2 50         SKIP(parser);
    0          
    0          
    0          
2406              
2407             /* Consume the tag value. */
2408              
2409 2 50         if (!yaml_parser_scan_tag_uri(parser, 0, NULL, start_mark, &suffix))
2410 0           goto error;
2411              
2412             /* Check for '>' and eat it. */
2413              
2414 2 50         if (!CHECK(parser->buffer, '>')) {
2415 0           yaml_parser_set_scanner_error(parser, "while scanning a tag",
2416             start_mark, "did not find the expected '>'");
2417 0           goto error;
2418             }
2419              
2420 2 50         SKIP(parser);
    0          
    0          
    0          
2421             }
2422             else
2423             {
2424             /* The tag has either the '!suffix' or the '!handle!suffix' form. */
2425              
2426             /* First, try to scan a handle. */
2427              
2428 80 50         if (!yaml_parser_scan_tag_handle(parser, 0, start_mark, &handle))
2429 0           goto error;
2430              
2431             /* Check if it is, indeed, handle. */
2432              
2433 80 50         if (handle[0] == '!' && handle[1] != '\0' && handle[strlen((char *)handle)-1] == '!')
    50          
    100          
2434             {
2435             /* Scan the suffix now. */
2436              
2437 71 50         if (!yaml_parser_scan_tag_uri(parser, 0, NULL, start_mark, &suffix))
2438 0           goto error;
2439             }
2440             else
2441             {
2442             /* It wasn't a handle after all. Scan the rest of the tag. */
2443              
2444 9 50         if (!yaml_parser_scan_tag_uri(parser, 0, handle, start_mark, &suffix))
2445 0           goto error;
2446              
2447             /* Set the handle to '!'. */
2448              
2449 9           yaml_free(handle);
2450 9           handle = YAML_MALLOC(2);
2451 9 50         if (!handle) goto error;
2452 9           handle[0] = '!';
2453 9           handle[1] = '\0';
2454              
2455             /*
2456             * A special case: the '!' tag. Set the handle to '' and the
2457             * suffix to '!'.
2458             */
2459              
2460 9 50         if (suffix[0] == '\0') {
2461 0           yaml_char_t *tmp = handle;
2462 0           handle = suffix;
2463 0           suffix = tmp;
2464             }
2465             }
2466             }
2467              
2468             /* Check the character which ends the tag. */
2469              
2470 82 50         if (!CACHE(parser, 1)) goto error;
    0          
2471              
2472 82 100         if (!IS_BLANKZ(parser->buffer)) {
    50          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
2473 0           yaml_parser_set_scanner_error(parser, "while scanning a tag",
2474             start_mark, "did not find expected whitespace or line break");
2475 0           goto error;
2476             }
2477              
2478 82           end_mark = parser->mark;
2479              
2480             /* Create a token. */
2481              
2482 82           TAG_TOKEN_INIT(*token, handle, suffix, start_mark, end_mark);
2483              
2484 82           return 1;
2485              
2486             error:
2487 0           yaml_free(handle);
2488 0           yaml_free(suffix);
2489 82           return 0;
2490             }
2491              
2492             /*
2493             * Scan a tag handle.
2494             */
2495              
2496             static int
2497 80           yaml_parser_scan_tag_handle(yaml_parser_t *parser, int directive,
2498             yaml_mark_t start_mark, yaml_char_t **handle)
2499             {
2500 80           yaml_string_t string = NULL_STRING;
2501              
2502 80 50         if (!STRING_INIT(parser, string, INITIAL_STRING_SIZE)) goto error;
    50          
2503              
2504             /* Check the initial '!' character. */
2505              
2506 80 50         if (!CACHE(parser, 1)) goto error;
    0          
2507              
2508 80 50         if (!CHECK(parser->buffer, '!')) {
2509 0 0         yaml_parser_set_scanner_error(parser, directive ?
2510             "while scanning a tag directive" : "while scanning a tag",
2511             start_mark, "did not find expected '!'");
2512 0           goto error;
2513             }
2514              
2515             /* Copy the '!' character. */
2516              
2517 80 50         if (!READ(parser, string)) goto error;
    0          
    50          
    50          
    0          
    0          
    0          
    50          
2518              
2519             /* Copy all subsequent alphabetical and numerical characters. */
2520              
2521 80 50         if (!CACHE(parser, 1)) goto error;
    0          
2522              
2523 108 100         while (IS_ALPHA(parser->buffer))
    50          
    100          
    100          
    100          
    50          
    50          
    50          
2524             {
2525 28 50         if (!READ(parser, string)) goto error;
    0          
    50          
    50          
    0          
    0          
    0          
    50          
2526 28 50         if (!CACHE(parser, 1)) goto error;
    0          
2527             }
2528              
2529             /* Check if the trailing character is '!' and copy it. */
2530              
2531 80 100         if (CHECK(parser->buffer, '!'))
2532             {
2533 71 50         if (!READ(parser, string)) goto error;
    0          
    50          
    50          
    0          
    0          
    0          
    50          
2534             }
2535             else
2536             {
2537             /*
2538             * It's either the '!' tag or not really a tag handle. If it's a %TAG
2539             * directive, it's an error. If it's a tag token, it must be a part of
2540             * URI.
2541             */
2542              
2543 9 50         if (directive && !(string.start[0] == '!' && string.start[1] == '\0')) {
    0          
    0          
2544 0           yaml_parser_set_scanner_error(parser, "while parsing a tag directive",
2545             start_mark, "did not find expected '!'");
2546 0           goto error;
2547             }
2548             }
2549              
2550 80           *handle = string.start;
2551              
2552 80           return 1;
2553              
2554             error:
2555 0           STRING_DEL(parser, string);
2556 80           return 0;
2557             }
2558              
2559             /*
2560             * Scan a tag.
2561             */
2562              
2563             static int
2564 82           yaml_parser_scan_tag_uri(yaml_parser_t *parser, int directive,
2565             yaml_char_t *head, yaml_mark_t start_mark, yaml_char_t **uri)
2566             {
2567 82 100         size_t length = head ? strlen((char *)head) : 0;
2568 82           yaml_string_t string = NULL_STRING;
2569              
2570 82 50         if (!STRING_INIT(parser, string, INITIAL_STRING_SIZE)) goto error;
    50          
2571              
2572             /* Resize the string to include the head. */
2573              
2574 82 50         while ((size_t)(string.end - string.start) <= length) {
2575 0 0         if (!yaml_string_extend(&string.start, &string.pointer, &string.end)) {
2576 0           parser->error = YAML_MEMORY_ERROR;
2577 0           goto error;
2578             }
2579             }
2580              
2581             /*
2582             * Copy the head if needed.
2583             *
2584             * Note that we don't copy the leading '!' character.
2585             */
2586              
2587 82 100         if (length > 1) {
2588 9           memcpy(string.start, head+1, length-1);
2589 9           string.pointer += length-1;
2590             }
2591              
2592             /* Scan the tag. */
2593              
2594 82 50         if (!CACHE(parser, 1)) goto error;
    0          
2595              
2596             /*
2597             * The set of characters that may appear in URI is as follows:
2598             *
2599             * '0'-'9', 'A'-'Z', 'a'-'z', '_', '-', ';', '/', '?', ':', '@', '&',
2600             * '=', '+', '$', ',', '.', '!', '~', '*', '\'', '(', ')', '[', ']',
2601             * '%'.
2602             */
2603              
2604 1025 100         while (IS_ALPHA(parser->buffer) || CHECK(parser->buffer, ';')
    100          
    100          
    100          
    100          
    50          
    50          
    50          
    50          
2605 235 100         || CHECK(parser->buffer, '/') || CHECK(parser->buffer, '?')
    50          
2606 178 100         || CHECK(parser->buffer, ':') || CHECK(parser->buffer, '@')
    50          
2607 87 50         || CHECK(parser->buffer, '&') || CHECK(parser->buffer, '=')
    50          
2608 87 50         || CHECK(parser->buffer, '+') || CHECK(parser->buffer, '$')
    50          
2609 87 100         || CHECK(parser->buffer, ',') || CHECK(parser->buffer, '.')
    100          
2610 83 100         || CHECK(parser->buffer, '!') || CHECK(parser->buffer, '~')
    50          
2611 82 50         || CHECK(parser->buffer, '*') || CHECK(parser->buffer, '\'')
    50          
2612 82 50         || CHECK(parser->buffer, '(') || CHECK(parser->buffer, ')')
    50          
2613 82 50         || CHECK(parser->buffer, '[') || CHECK(parser->buffer, ']')
    50          
2614 82 50         || CHECK(parser->buffer, '%'))
2615             {
2616             /* Check if it is a URI-escape sequence. */
2617              
2618 943 50         if (CHECK(parser->buffer, '%')) {
2619 0 0         if (!STRING_EXTEND(parser, string))
    0          
    0          
2620 0           goto error;
2621              
2622 0 0         if (!yaml_parser_scan_uri_escapes(parser,
2623 0           directive, start_mark, &string)) goto error;
2624             }
2625             else {
2626 943 100         if (!READ(parser, string)) goto error;
    50          
    50          
    50          
    0          
    0          
    0          
    50          
2627             }
2628              
2629 943           length ++;
2630 943 50         if (!CACHE(parser, 1)) goto error;
    0          
2631             }
2632              
2633             /* Check if the tag is non-empty. */
2634              
2635 82 50         if (!length) {
2636 0 0         if (!STRING_EXTEND(parser, string))
    0          
    0          
2637 0           goto error;
2638              
2639 0 0         yaml_parser_set_scanner_error(parser, directive ?
2640             "while parsing a %TAG directive" : "while parsing a tag",
2641             start_mark, "did not find expected tag URI");
2642 0           goto error;
2643             }
2644              
2645 82           *uri = string.start;
2646              
2647 82           return 1;
2648              
2649             error:
2650 0           STRING_DEL(parser, string);
2651 82           return 0;
2652             }
2653              
2654             /*
2655             * Decode an URI-escape sequence corresponding to a single UTF-8 character.
2656             */
2657              
2658             static int
2659 0           yaml_parser_scan_uri_escapes(yaml_parser_t *parser, int directive,
2660             yaml_mark_t start_mark, yaml_string_t *string)
2661             {
2662 0           int width = 0;
2663              
2664             /* Decode the required number of characters. */
2665              
2666             do {
2667              
2668 0           unsigned char octet = 0;
2669              
2670             /* Check for a URI-escaped octet. */
2671              
2672 0 0         if (!CACHE(parser, 3)) return 0;
    0          
2673              
2674 0 0         if (!(CHECK(parser->buffer, '%')
    0          
2675 0 0         && IS_HEX_AT(parser->buffer, 1)
    0          
    0          
    0          
    0          
    0          
2676 0 0         && IS_HEX_AT(parser->buffer, 2))) {
    0          
    0          
    0          
    0          
2677 0 0         return yaml_parser_set_scanner_error(parser, directive ?
2678             "while parsing a %TAG directive" : "while parsing a tag",
2679             start_mark, "did not find URI escaped octet");
2680             }
2681              
2682             /* Get the octet. */
2683              
2684 0 0         octet = (AS_HEX_AT(parser->buffer, 1) << 4) + AS_HEX_AT(parser->buffer, 2);
    0          
    0          
    0          
    0          
    0          
    0          
    0          
2685              
2686             /* If it is the leading octet, determine the length of the UTF-8 sequence. */
2687              
2688 0 0         if (!width)
2689             {
2690 0 0         width = (octet & 0x80) == 0x00 ? 1 :
2691 0 0         (octet & 0xE0) == 0xC0 ? 2 :
2692 0 0         (octet & 0xF0) == 0xE0 ? 3 :
2693 0 0         (octet & 0xF8) == 0xF0 ? 4 : 0;
2694 0 0         if (!width) {
2695 0 0         return yaml_parser_set_scanner_error(parser, directive ?
2696             "while parsing a %TAG directive" : "while parsing a tag",
2697             start_mark, "found an incorrect leading UTF-8 octet");
2698             }
2699             }
2700             else
2701             {
2702             /* Check if the trailing octet is correct. */
2703              
2704 0 0         if ((octet & 0xC0) != 0x80) {
2705 0 0         return yaml_parser_set_scanner_error(parser, directive ?
2706             "while parsing a %TAG directive" : "while parsing a tag",
2707             start_mark, "found an incorrect trailing UTF-8 octet");
2708             }
2709             }
2710              
2711             /* Copy the octet and move the pointers. */
2712              
2713 0           *(string->pointer++) = octet;
2714 0 0         SKIP(parser);
    0          
    0          
    0          
2715 0 0         SKIP(parser);
    0          
    0          
    0          
2716 0 0         SKIP(parser);
    0          
    0          
    0          
2717              
2718 0 0         } while (--width);
2719              
2720 0           return 1;
2721             }
2722              
2723             /*
2724             * Scan a block scalar.
2725             */
2726              
2727             static int
2728 7           yaml_parser_scan_block_scalar(yaml_parser_t *parser, yaml_token_t *token,
2729             int literal)
2730             {
2731             yaml_mark_t start_mark;
2732             yaml_mark_t end_mark;
2733 7           yaml_string_t string = NULL_STRING;
2734 7           yaml_string_t leading_break = NULL_STRING;
2735 7           yaml_string_t trailing_breaks = NULL_STRING;
2736 7           int chomping = 0;
2737 7           int increment = 0;
2738 7           int indent = 0;
2739 7           int leading_blank = 0;
2740 7           int trailing_blank = 0;
2741              
2742 7 50         if (!STRING_INIT(parser, string, INITIAL_STRING_SIZE)) goto error;
    50          
2743 7 50         if (!STRING_INIT(parser, leading_break, INITIAL_STRING_SIZE)) goto error;
    50          
2744 7 50         if (!STRING_INIT(parser, trailing_breaks, INITIAL_STRING_SIZE)) goto error;
    50          
2745              
2746             /* Eat the indicator '|' or '>'. */
2747              
2748 7           start_mark = parser->mark;
2749              
2750 7 50         SKIP(parser);
    0          
    0          
    0          
2751              
2752             /* Scan the additional block scalar indicators. */
2753              
2754 7 50         if (!CACHE(parser, 1)) goto error;
    0          
2755              
2756             /* Check for a chomping indicator. */
2757              
2758 7 50         if (CHECK(parser->buffer, '+') || CHECK(parser->buffer, '-'))
    100          
2759             {
2760             /* Set the chomping method and eat the indicator. */
2761              
2762 6 50         chomping = CHECK(parser->buffer, '+') ? +1 : -1;
2763              
2764 6 50         SKIP(parser);
    0          
    0          
    0          
2765              
2766             /* Check for an indentation indicator. */
2767              
2768 6 50         if (!CACHE(parser, 1)) goto error;
    0          
2769              
2770 6 50         if (IS_DIGIT(parser->buffer))
    0          
2771             {
2772             /* Check that the indentation is greater than 0. */
2773              
2774 0 0         if (CHECK(parser->buffer, '0')) {
2775 0           yaml_parser_set_scanner_error(parser, "while scanning a block scalar",
2776             start_mark, "found an indentation indicator equal to 0");
2777 0           goto error;
2778             }
2779              
2780             /* Get the indentation level and eat the indicator. */
2781              
2782 0           increment = AS_DIGIT(parser->buffer);
2783              
2784 0 0         SKIP(parser);
    0          
    0          
    0          
2785             }
2786             }
2787              
2788             /* Do the same as above, but in the opposite order. */
2789              
2790 1 50         else if (IS_DIGIT(parser->buffer))
    0          
2791             {
2792 0 0         if (CHECK(parser->buffer, '0')) {
2793 0           yaml_parser_set_scanner_error(parser, "while scanning a block scalar",
2794             start_mark, "found an indentation indicator equal to 0");
2795 0           goto error;
2796             }
2797              
2798 0           increment = AS_DIGIT(parser->buffer);
2799              
2800 0 0         SKIP(parser);
    0          
    0          
    0          
2801              
2802 0 0         if (!CACHE(parser, 1)) goto error;
    0          
2803              
2804 0 0         if (CHECK(parser->buffer, '+') || CHECK(parser->buffer, '-')) {
    0          
2805 0 0         chomping = CHECK(parser->buffer, '+') ? +1 : -1;
2806              
2807 0 0         SKIP(parser);
    0          
    0          
    0          
2808             }
2809             }
2810              
2811             /* Eat whitespaces and comments to the end of the line. */
2812              
2813 7 50         if (!CACHE(parser, 1)) goto error;
    0          
2814              
2815 7 50         while (IS_BLANK(parser->buffer)) {
    50          
2816 0 0         SKIP(parser);
    0          
    0          
    0          
2817 0 0         if (!CACHE(parser, 1)) goto error;
    0          
2818             }
2819              
2820 7 50         if (CHECK(parser->buffer, '#')) {
2821 0 0         while (!IS_BREAKZ(parser->buffer)) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
2822 0 0         SKIP(parser);
    0          
    0          
    0          
2823 0 0         if (!CACHE(parser, 1)) goto error;
    0          
2824             }
2825             }
2826              
2827             /* Check if we are at the end of the line. */
2828              
2829 7 50         if (!IS_BREAKZ(parser->buffer)) {
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
2830 0           yaml_parser_set_scanner_error(parser, "while scanning a block scalar",
2831             start_mark, "did not find expected comment or line break");
2832 0           goto error;
2833             }
2834              
2835             /* Eat a line break. */
2836              
2837 7 50         if (IS_BREAK(parser->buffer)) {
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
2838 7 50         if (!CACHE(parser, 2)) goto error;
    0          
2839 7 50         SKIP_LINE(parser);
    0          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    0          
    0          
    0          
2840             }
2841              
2842 7           end_mark = parser->mark;
2843              
2844             /* Set the indentation level if it was specified. */
2845              
2846 7 50         if (increment) {
2847 0 0         indent = parser->indent >= 0 ? parser->indent+increment : increment;
2848             }
2849              
2850             /* Scan the leading line breaks and determine the indentation level if needed. */
2851              
2852 7 50         if (!yaml_parser_scan_block_scalar_breaks(parser, &indent, &trailing_breaks,
2853 0           start_mark, &end_mark)) goto error;
2854              
2855             /* Scan the block scalar content. */
2856              
2857 7 50         if (!CACHE(parser, 1)) goto error;
    0          
2858              
2859 24 100         while ((int)parser->mark.column == indent && !(IS_Z(parser->buffer)))
    50          
2860             {
2861             /*
2862             * We are at the beginning of a non-empty line.
2863             */
2864              
2865             /* Is it a trailing whitespace? */
2866              
2867 17 100         trailing_blank = IS_BLANK(parser->buffer);
    50          
2868              
2869             /* Check if we need to fold the leading line break. */
2870              
2871 17 50         if (!literal && (*leading_break.start == '\n')
    0          
2872 0 0         && !leading_blank && !trailing_blank)
    0          
2873             {
2874             /* Do we need to join the lines by space? */
2875              
2876 0 0         if (*trailing_breaks.start == '\0') {
2877 0 0         if (!STRING_EXTEND(parser, string)) goto error;
    0          
    0          
2878 0           *(string.pointer ++) = ' ';
2879             }
2880              
2881 0           CLEAR(parser, leading_break);
2882             }
2883             else {
2884 17 50         if (!JOIN(parser, string, leading_break)) goto error;
    50          
2885 17           CLEAR(parser, leading_break);
2886             }
2887              
2888             /* Append the remaining line breaks. */
2889              
2890 17 50         if (!JOIN(parser, string, trailing_breaks)) goto error;
    50          
2891 17           CLEAR(parser, trailing_breaks);
2892              
2893             /* Is it a leading whitespace? */
2894              
2895 17 100         leading_blank = IS_BLANK(parser->buffer);
    50          
2896              
2897             /* Consume the current line. */
2898              
2899 215 50         while (!IS_BREAKZ(parser->buffer)) {
    100          
    50          
    0          
    50          
    0          
    0          
    50          
    0          
    0          
    50          
2900 198 100         if (!READ(parser, string)) goto error;
    50          
    50          
    50          
    0          
    0          
    0          
    50          
2901 198 50         if (!CACHE(parser, 1)) goto error;
    0          
2902             }
2903              
2904             /* Consume the line break. */
2905              
2906 17 100         if (!CACHE(parser, 2)) goto error;
    50          
2907              
2908 17 50         if (!READ_LINE(parser, leading_break)) goto error;
    0          
    50          
    50          
    0          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
2909              
2910             /* Eat the following indentation spaces and line breaks. */
2911              
2912 17 50         if (!yaml_parser_scan_block_scalar_breaks(parser,
2913 0           &indent, &trailing_breaks, start_mark, &end_mark)) goto error;
2914             }
2915              
2916             /* Chomp the tail. */
2917              
2918 7 100         if (chomping != -1) {
2919 1 50         if (!JOIN(parser, string, leading_break)) goto error;
    50          
2920             }
2921 7 50         if (chomping == 1) {
2922 0 0         if (!JOIN(parser, string, trailing_breaks)) goto error;
    0          
2923             }
2924              
2925             /* Create a token. */
2926              
2927 7 50         SCALAR_TOKEN_INIT(*token, string.start, string.pointer-string.start,
2928             literal ? YAML_LITERAL_SCALAR_STYLE : YAML_FOLDED_SCALAR_STYLE,
2929             start_mark, end_mark);
2930              
2931 7           STRING_DEL(parser, leading_break);
2932 7           STRING_DEL(parser, trailing_breaks);
2933              
2934 7           return 1;
2935              
2936             error:
2937 0           STRING_DEL(parser, string);
2938 0           STRING_DEL(parser, leading_break);
2939 0           STRING_DEL(parser, trailing_breaks);
2940              
2941 7           return 0;
2942             }
2943              
2944             /*
2945             * Scan indentation spaces and line breaks for a block scalar. Determine the
2946             * indentation level if needed.
2947             */
2948              
2949             static int
2950 24           yaml_parser_scan_block_scalar_breaks(yaml_parser_t *parser,
2951             int *indent, yaml_string_t *breaks,
2952             yaml_mark_t start_mark, yaml_mark_t *end_mark)
2953             {
2954 24           int max_indent = 0;
2955              
2956 24           *end_mark = parser->mark;
2957              
2958             /* Eat the indentation spaces and line breaks. */
2959              
2960             while (1)
2961             {
2962             /* Eat the indentation spaces. */
2963              
2964 24 50         if (!CACHE(parser, 1)) return 0;
    0          
2965              
2966 58 100         while ((!*indent || (int)parser->mark.column < *indent)
    100          
2967 48 100         && IS_SPACE(parser->buffer)) {
2968 34 50         SKIP(parser);
    0          
    0          
    0          
2969 34 50         if (!CACHE(parser, 1)) return 0;
    0          
2970             }
2971              
2972 24 100         if ((int)parser->mark.column > max_indent)
2973 17           max_indent = (int)parser->mark.column;
2974              
2975             /* Check for a tab character messing the indentation. */
2976              
2977 24 100         if ((!*indent || (int)parser->mark.column < *indent)
    100          
2978 14 50         && IS_TAB(parser->buffer)) {
2979 0           return yaml_parser_set_scanner_error(parser, "while scanning a block scalar",
2980             start_mark, "found a tab character where an indentation space is expected");
2981             }
2982              
2983             /* Have we found a non-empty line? */
2984              
2985 24 50         if (!IS_BREAK(parser->buffer)) break;
    50          
    50          
    0          
    50          
    0          
    0          
    50          
    0          
    0          
2986              
2987             /* Consume the line break. */
2988              
2989 0 0         if (!CACHE(parser, 2)) return 0;
    0          
2990 0 0         if (!READ_LINE(parser, *breaks)) return 0;
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
2991 0           *end_mark = parser->mark;
2992 0           }
2993              
2994             /* Determine the indentation level if needed. */
2995              
2996 24 100         if (!*indent) {
2997 7           *indent = max_indent;
2998 7 50         if (*indent < parser->indent + 1)
2999 0           *indent = parser->indent + 1;
3000 7 50         if (*indent < 1)
3001 0           *indent = 1;
3002             }
3003              
3004 24           return 1;
3005             }
3006              
3007             /*
3008             * Scan a quoted scalar.
3009             */
3010              
3011             static int
3012 27           yaml_parser_scan_flow_scalar(yaml_parser_t *parser, yaml_token_t *token,
3013             int single)
3014             {
3015             yaml_mark_t start_mark;
3016             yaml_mark_t end_mark;
3017 27           yaml_string_t string = NULL_STRING;
3018 27           yaml_string_t leading_break = NULL_STRING;
3019 27           yaml_string_t trailing_breaks = NULL_STRING;
3020 27           yaml_string_t whitespaces = NULL_STRING;
3021             int leading_blanks;
3022              
3023 27 50         if (!STRING_INIT(parser, string, INITIAL_STRING_SIZE)) goto error;
    50          
3024 27 50         if (!STRING_INIT(parser, leading_break, INITIAL_STRING_SIZE)) goto error;
    50          
3025 27 50         if (!STRING_INIT(parser, trailing_breaks, INITIAL_STRING_SIZE)) goto error;
    50          
3026 27 50         if (!STRING_INIT(parser, whitespaces, INITIAL_STRING_SIZE)) goto error;
    50          
3027              
3028             /* Eat the left quote. */
3029              
3030 27           start_mark = parser->mark;
3031              
3032 27 50         SKIP(parser);
    0          
    0          
    0          
3033              
3034             /* Consume the content of the quoted scalar. */
3035              
3036             while (1)
3037             {
3038             /* Check that there are no document indicators at the beginning of the line. */
3039              
3040 34 100         if (!CACHE(parser, 4)) goto error;
    50          
3041              
3042 34 100         if (parser->mark.column == 0 &&
    50          
3043 0 0         ((CHECK_AT(parser->buffer, '-', 0) &&
3044 0 0         CHECK_AT(parser->buffer, '-', 1) &&
3045 1 50         CHECK_AT(parser->buffer, '-', 2)) ||
3046 0 0         (CHECK_AT(parser->buffer, '.', 0) &&
3047 0 0         CHECK_AT(parser->buffer, '.', 1) &&
3048 0 0         CHECK_AT(parser->buffer, '.', 2))) &&
3049 0 0         IS_BLANKZ_AT(parser->buffer, 3))
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3050             {
3051 0           yaml_parser_set_scanner_error(parser, "while scanning a quoted scalar",
3052             start_mark, "found unexpected document indicator");
3053 0           goto error;
3054             }
3055              
3056             /* Check for EOF. */
3057              
3058 34 50         if (IS_Z(parser->buffer)) {
3059 0           yaml_parser_set_scanner_error(parser, "while scanning a quoted scalar",
3060             start_mark, "found unexpected end of stream");
3061 0           goto error;
3062             }
3063              
3064             /* Consume non-blank characters. */
3065              
3066 34 50         if (!CACHE(parser, 2)) goto error;
    0          
3067              
3068 34           leading_blanks = 0;
3069              
3070 257 100         while (!IS_BLANKZ(parser->buffer))
    50          
    50          
    100          
    50          
    0          
    50          
    0          
    0          
    50          
    0          
    0          
    50          
3071             {
3072             /* Check for an escaped single quote. */
3073              
3074 250 100         if (single && CHECK_AT(parser->buffer, '\'', 0)
    100          
3075 16 50         && CHECK_AT(parser->buffer, '\'', 1))
3076             {
3077 0 0         if (!STRING_EXTEND(parser, string)) goto error;
    0          
    0          
3078 0           *(string.pointer++) = '\'';
3079 0 0         SKIP(parser);
    0          
    0          
    0          
3080 0 0         SKIP(parser);
    0          
    0          
    0          
3081             }
3082              
3083             /* Check for the right quote. */
3084              
3085 250 100         else if (CHECK(parser->buffer, single ? '\'' : '"'))
    100          
3086             {
3087 27           break;
3088             }
3089              
3090             /* Check for an escaped line break. */
3091              
3092 223 100         else if (!single && CHECK(parser->buffer, '\\')
    100          
3093 4 50         && IS_BREAK_AT(parser->buffer, 1))
    50          
    50          
    0          
    50          
    0          
    0          
    50          
    0          
    0          
3094             {
3095 0 0         if (!CACHE(parser, 3)) goto error;
    0          
3096 0 0         SKIP(parser);
    0          
    0          
    0          
3097 0 0         SKIP_LINE(parser);
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3098 0           leading_blanks = 1;
3099 0           break;
3100             }
3101              
3102             /* Check for an escape sequence. */
3103              
3104 223 100         else if (!single && CHECK(parser->buffer, '\\'))
    100          
3105 4           {
3106 4           size_t code_length = 0;
3107              
3108 4 50         if (!STRING_EXTEND(parser, string)) goto error;
    0          
    50          
3109              
3110             /* Check the escape character. */
3111              
3112 4           switch (parser->buffer.pointer[1])
3113             {
3114             case '0':
3115 1           *(string.pointer++) = '\0';
3116 1           break;
3117              
3118             case 'a':
3119 0           *(string.pointer++) = '\x07';
3120 0           break;
3121              
3122             case 'b':
3123 0           *(string.pointer++) = '\x08';
3124 0           break;
3125              
3126             case 't':
3127             case '\t':
3128 0           *(string.pointer++) = '\x09';
3129 0           break;
3130              
3131             case 'n':
3132 2           *(string.pointer++) = '\x0A';
3133 2           break;
3134              
3135             case 'v':
3136 0           *(string.pointer++) = '\x0B';
3137 0           break;
3138              
3139             case 'f':
3140 0           *(string.pointer++) = '\x0C';
3141 0           break;
3142              
3143             case 'r':
3144 0           *(string.pointer++) = '\x0D';
3145 0           break;
3146              
3147             case 'e':
3148 0           *(string.pointer++) = '\x1B';
3149 0           break;
3150              
3151             case ' ':
3152 0           *(string.pointer++) = '\x20';
3153 0           break;
3154              
3155             case '"':
3156 0           *(string.pointer++) = '"';
3157 0           break;
3158              
3159             case '/':
3160 0           *(string.pointer++) = '/';
3161 0           break;
3162              
3163             case '\\':
3164 0           *(string.pointer++) = '\\';
3165 0           break;
3166              
3167             case 'N': /* NEL (#x85) */
3168 0           *(string.pointer++) = '\xC2';
3169 0           *(string.pointer++) = '\x85';
3170 0           break;
3171              
3172             case '_': /* #xA0 */
3173 0           *(string.pointer++) = '\xC2';
3174 0           *(string.pointer++) = '\xA0';
3175 0           break;
3176              
3177             case 'L': /* LS (#x2028) */
3178 0           *(string.pointer++) = '\xE2';
3179 0           *(string.pointer++) = '\x80';
3180 0           *(string.pointer++) = '\xA8';
3181 0           break;
3182              
3183             case 'P': /* PS (#x2029) */
3184 0           *(string.pointer++) = '\xE2';
3185 0           *(string.pointer++) = '\x80';
3186 0           *(string.pointer++) = '\xA9';
3187 0           break;
3188              
3189             case 'x':
3190 0           code_length = 2;
3191 0           break;
3192              
3193             case 'u':
3194 0           code_length = 4;
3195 0           break;
3196              
3197             case 'U':
3198 0           code_length = 8;
3199 0           break;
3200              
3201             default:
3202 1           yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar",
3203             start_mark, "found unknown escape character");
3204 1 50         if (!parser->problem_nonstrict) {
3205 0           goto error;
3206             } else { /* all other parsers allow any quoted char, like \. in strings */
3207 1           parser->error = YAML_READER_ERROR; /* fake for the YAML_PARSE_END_STATE check */
3208 1           *(string.pointer++) = '\\';
3209 1           *(string.pointer++) = parser->buffer.pointer[1];
3210             }
3211             }
3212              
3213 4 50         SKIP(parser);
    0          
    0          
    0          
3214 4 50         SKIP(parser);
    0          
    0          
    0          
3215              
3216             /* Consume an arbitrary escape code. */
3217              
3218 4 50         if (code_length)
3219             {
3220 0           unsigned int value = 0;
3221             size_t k;
3222              
3223             /* Scan the character value. */
3224              
3225 0 0         if (!CACHE(parser, code_length)) goto error;
    0          
3226              
3227 0 0         for (k = 0; k < code_length; k ++) {
3228 0 0         if (!IS_HEX_AT(parser->buffer, k)) {
    0          
    0          
    0          
    0          
    0          
3229 0           yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar",
3230             start_mark, "did not find expected hexdecimal number");
3231 0           goto error;
3232             }
3233 0 0         value = (value << 4) + AS_HEX_AT(parser->buffer, k);
    0          
    0          
    0          
3234             }
3235              
3236             /* Check the value and write the character. */
3237              
3238 0 0         if ((value >= 0xD800 && value <= 0xDFFF) || value > 0x10FFFF) {
    0          
    0          
3239 0           yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar",
3240             start_mark, "found invalid Unicode character escape code");
3241 0           goto error;
3242             }
3243              
3244 0 0         if (value <= 0x7F) {
3245 0           *(string.pointer++) = value;
3246             }
3247 0 0         else if (value <= 0x7FF) {
3248 0           *(string.pointer++) = 0xC0 + (value >> 6);
3249 0           *(string.pointer++) = 0x80 + (value & 0x3F);
3250             }
3251 0 0         else if (value <= 0xFFFF) {
3252 0           *(string.pointer++) = 0xE0 + (value >> 12);
3253 0           *(string.pointer++) = 0x80 + ((value >> 6) & 0x3F);
3254 0           *(string.pointer++) = 0x80 + (value & 0x3F);
3255             }
3256             else {
3257 0           *(string.pointer++) = 0xF0 + (value >> 18);
3258 0           *(string.pointer++) = 0x80 + ((value >> 12) & 0x3F);
3259 0           *(string.pointer++) = 0x80 + ((value >> 6) & 0x3F);
3260 0           *(string.pointer++) = 0x80 + (value & 0x3F);
3261             }
3262              
3263             /* Advance the pointer. */
3264              
3265 0 0         for (k = 0; k < code_length; k ++) {
3266 0 0         SKIP(parser);
    0          
    0          
    0          
3267             }
3268             }
3269             }
3270              
3271             else
3272             {
3273             /* It is a non-escaped non-blank character. */
3274              
3275 219 100         if (!READ(parser, string)) goto error;
    50          
    50          
    50          
    0          
    0          
    0          
    50          
3276             }
3277              
3278 223 50         if (!CACHE(parser, 2)) goto error;
    0          
3279             }
3280              
3281             /* Check if we are at the end of the scalar. */
3282              
3283             /* Fix for crash unitialized value crash
3284             * Credit for the bug and input is to OSS Fuzz
3285             * Credit for the fix to Alex Gaynor
3286             */
3287 34 50         if (!CACHE(parser, 1)) goto error;
    0          
3288 34 100         if (CHECK(parser->buffer, single ? '\'' : '"'))
    100          
3289 27           break;
3290              
3291             /* Consume blank characters. */
3292              
3293 7 50         if (!CACHE(parser, 1)) goto error;
    0          
3294              
3295 14 100         while (IS_BLANK(parser->buffer) || IS_BREAK(parser->buffer))
    50          
    50          
    100          
    50          
    0          
    50          
    0          
    0          
    50          
    0          
    0          
3296             {
3297 7 100         if (IS_BLANK(parser->buffer))
    50          
3298             {
3299             /* Consume a space or a tab character. */
3300              
3301 12 50         if (!leading_blanks) {
3302 6 50         if (!READ(parser, whitespaces)) goto error;
    0          
    50          
    50          
    0          
    0          
    0          
    50          
3303             }
3304             else {
3305 0 0         SKIP(parser);
    0          
    0          
    0          
3306             }
3307             }
3308             else
3309             {
3310 1 50         if (!CACHE(parser, 2)) goto error;
    0          
3311              
3312             /* Check if it is a first line break. */
3313              
3314 1 50         if (!leading_blanks)
3315             {
3316 1           CLEAR(parser, whitespaces);
3317 1 50         if (!READ_LINE(parser, leading_break)) goto error;
    0          
    50          
    50          
    0          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
3318 1           leading_blanks = 1;
3319             }
3320             else
3321             {
3322 0 0         if (!READ_LINE(parser, trailing_breaks)) goto error;
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3323             }
3324             }
3325 7 50         if (!CACHE(parser, 1)) goto error;
    0          
3326             }
3327              
3328             /* Join the whitespaces or fold line breaks. */
3329              
3330 7 100         if (leading_blanks)
3331             {
3332             /* Do we need to fold line breaks? */
3333              
3334 1 50         if (leading_break.start[0] == '\n') {
3335 1 50         if (trailing_breaks.start[0] == '\0') {
3336 1 50         if (!STRING_EXTEND(parser, string)) goto error;
    0          
    50          
3337 1           *(string.pointer++) = ' ';
3338             }
3339             else {
3340 0 0         if (!JOIN(parser, string, trailing_breaks)) goto error;
    0          
3341 0           CLEAR(parser, trailing_breaks);
3342             }
3343 1           CLEAR(parser, leading_break);
3344             }
3345             else {
3346 0 0         if (!JOIN(parser, string, leading_break)) goto error;
    0          
3347 0 0         if (!JOIN(parser, string, trailing_breaks)) goto error;
    0          
3348 0           CLEAR(parser, leading_break);
3349 1           CLEAR(parser, trailing_breaks);
3350             }
3351             }
3352             else
3353             {
3354 6 50         if (!JOIN(parser, string, whitespaces)) goto error;
    50          
3355 6           CLEAR(parser, whitespaces);
3356             }
3357 7           }
3358              
3359             /* Eat the right quote. */
3360              
3361 27 50         SKIP(parser);
    0          
    0          
    0          
3362              
3363 27           end_mark = parser->mark;
3364              
3365             /* Create a token. */
3366              
3367 27 100         SCALAR_TOKEN_INIT(*token, string.start, string.pointer-string.start,
3368             single ? YAML_SINGLE_QUOTED_SCALAR_STYLE : YAML_DOUBLE_QUOTED_SCALAR_STYLE,
3369             start_mark, end_mark);
3370              
3371 27           STRING_DEL(parser, leading_break);
3372 27           STRING_DEL(parser, trailing_breaks);
3373 27           STRING_DEL(parser, whitespaces);
3374              
3375 27           return 1;
3376              
3377             error:
3378 0           STRING_DEL(parser, string);
3379 0           STRING_DEL(parser, leading_break);
3380 0           STRING_DEL(parser, trailing_breaks);
3381 0           STRING_DEL(parser, whitespaces);
3382              
3383 27           return 0;
3384             }
3385              
3386             /*
3387             * Scan a plain scalar.
3388             */
3389              
3390             static int
3391 302           yaml_parser_scan_plain_scalar(yaml_parser_t *parser, yaml_token_t *token)
3392             {
3393             yaml_mark_t start_mark;
3394             yaml_mark_t end_mark;
3395 302           yaml_string_t string = NULL_STRING;
3396 302           yaml_string_t leading_break = NULL_STRING;
3397 302           yaml_string_t trailing_breaks = NULL_STRING;
3398 302           yaml_string_t whitespaces = NULL_STRING;
3399 302           int leading_blanks = 0;
3400 302           int indent = parser->indent+1;
3401              
3402 302 50         if (!STRING_INIT(parser, string, INITIAL_STRING_SIZE)) goto error;
    50          
3403 302 50         if (!STRING_INIT(parser, leading_break, INITIAL_STRING_SIZE)) goto error;
    50          
3404 302 50         if (!STRING_INIT(parser, trailing_breaks, INITIAL_STRING_SIZE)) goto error;
    50          
3405 302 50         if (!STRING_INIT(parser, whitespaces, INITIAL_STRING_SIZE)) goto error;
    50          
3406              
3407 302           start_mark = end_mark = parser->mark;
3408              
3409             /* Consume the content of the plain scalar. */
3410              
3411             while (1)
3412             {
3413             /* Check for a document indicator. */
3414              
3415 378 100         if (!CACHE(parser, 4)) goto error;
    50          
3416              
3417 378 100         if (parser->mark.column == 0 &&
    100          
3418 7 50         ((CHECK_AT(parser->buffer, '-', 0) &&
3419 7 50         CHECK_AT(parser->buffer, '-', 1) &&
3420 114 50         CHECK_AT(parser->buffer, '-', 2)) ||
3421 0 0         (CHECK_AT(parser->buffer, '.', 0) &&
3422 0 0         CHECK_AT(parser->buffer, '.', 1) &&
3423 7 50         CHECK_AT(parser->buffer, '.', 2))) &&
3424 0 0         IS_BLANKZ_AT(parser->buffer, 3)) break;
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3425              
3426             /* Check for a comment. */
3427              
3428 371 50         if (CHECK(parser->buffer, '#'))
3429 0           break;
3430              
3431             /* Consume non-blank characters. */
3432              
3433 1633 100         while (!IS_BLANKZ(parser->buffer))
    50          
    50          
    100          
    50          
    0          
    50          
    0          
    0          
    50          
    0          
    0          
    100          
3434             {
3435             /* Check for "x:" + one of ',?[]{}' in the flow context. TODO: Fix the test "spec-08-13".
3436             * This is not completely according to the spec
3437             * See http://yaml.org/spec/1.1/#id907281 9.1.3. Plain
3438             */
3439              
3440 1406 100         if (parser->flow_level
3441 72 100         && CHECK(parser->buffer, ':')
3442 7 50         && (
3443 7           CHECK_AT(parser->buffer, ',', 1)
3444 7 50         || CHECK_AT(parser->buffer, '?', 1)
3445 7 50         || CHECK_AT(parser->buffer, '[', 1)
3446 7 50         || CHECK_AT(parser->buffer, ']', 1)
3447 7 50         || CHECK_AT(parser->buffer, '{', 1)
3448 7 50         || CHECK_AT(parser->buffer, '}', 1)
3449             )
3450             ) {
3451 0           yaml_parser_set_scanner_error(parser, "while scanning a plain scalar",
3452             start_mark, "found unexpected ':'");
3453 0           goto error;
3454             }
3455              
3456             /* Check for indicators that may end a plain scalar. */
3457              
3458 1406 100         if ((CHECK(parser->buffer, ':') && IS_BLANKZ_AT(parser->buffer, 1))
    100          
    50          
    50          
    100          
    50          
    0          
    50          
    0          
    0          
    50          
    0          
    0          
    50          
3459 1282 100         || (parser->flow_level &&
    100          
3460 65           (CHECK(parser->buffer, ',')
3461 61 50         || CHECK(parser->buffer, '?') || CHECK(parser->buffer, '[')
    50          
3462 61 100         || CHECK(parser->buffer, ']') || CHECK(parser->buffer, '{')
    50          
3463 53 100         || CHECK(parser->buffer, '}'))))
3464             break;
3465              
3466             /* Check if we need to join whitespaces and breaks. */
3467              
3468 1262 100         if (leading_blanks || whitespaces.start != whitespaces.pointer)
    100          
3469             {
3470 45 100         if (leading_blanks)
3471             {
3472             /* Do we need to fold line breaks? */
3473              
3474 1 50         if (leading_break.start[0] == '\n') {
3475 1 50         if (trailing_breaks.start[0] == '\0') {
3476 1 50         if (!STRING_EXTEND(parser, string)) goto error;
    0          
    50          
3477 1           *(string.pointer++) = ' ';
3478             }
3479             else {
3480 0 0         if (!JOIN(parser, string, trailing_breaks)) goto error;
    0          
3481 0           CLEAR(parser, trailing_breaks);
3482             }
3483 1           CLEAR(parser, leading_break);
3484             }
3485             else {
3486 0 0         if (!JOIN(parser, string, leading_break)) goto error;
    0          
3487 0 0         if (!JOIN(parser, string, trailing_breaks)) goto error;
    0          
3488 0           CLEAR(parser, leading_break);
3489 0           CLEAR(parser, trailing_breaks);
3490             }
3491              
3492 1           leading_blanks = 0;
3493             }
3494             else
3495             {
3496 44 50         if (!JOIN(parser, string, whitespaces)) goto error;
    50          
3497 44           CLEAR(parser, whitespaces);
3498             }
3499             }
3500              
3501             /* Copy the character. */
3502              
3503 1262 100         if (!READ(parser, string)) goto error;
    50          
    50          
    100          
    100          
    50          
    0          
    50          
3504              
3505 1262           end_mark = parser->mark;
3506              
3507 1262 100         if (!CACHE(parser, 2)) goto error;
    50          
3508             }
3509              
3510             /* Is it the end? */
3511              
3512 371 100         if (!(IS_BLANK(parser->buffer) || IS_BREAK(parser->buffer)))
    50          
    50          
    100          
    50          
    0          
    50          
    0          
    0          
    50          
    0          
    0          
3513             break;
3514              
3515             /* Consume blank characters. */
3516              
3517 202 50         if (!CACHE(parser, 1)) goto error;
    0          
3518              
3519 447 100         while (IS_BLANK(parser->buffer) || IS_BREAK(parser->buffer))
    50          
    50          
    100          
    50          
    0          
    50          
    0          
    0          
    50          
    0          
    0          
3520             {
3521 245 100         if (IS_BLANK(parser->buffer))
    50          
3522             {
3523             /* Check for tab characters that abuse indentation. */
3524              
3525 91 100         if (leading_blanks && (int)parser->mark.column < indent
    50          
3526 43 50         && IS_TAB(parser->buffer)) {
3527 0           yaml_parser_set_scanner_error(parser, "while scanning a plain scalar",
3528             start_mark, "found a tab character that violate indentation");
3529 0           goto error;
3530             }
3531              
3532             /* Consume a space or a tab character. */
3533              
3534 182 100         if (!leading_blanks) {
3535 48 50         if (!READ(parser, whitespaces)) goto error;
    0          
    50          
    50          
    0          
    0          
    0          
    50          
3536             }
3537             else {
3538 43 50         SKIP(parser);
    0          
    0          
    0          
3539             }
3540             }
3541             else
3542             {
3543 154 50         if (!CACHE(parser, 2)) goto error;
    0          
3544              
3545             /* Check if it is a first line break. */
3546              
3547 154 50         if (!leading_blanks)
3548             {
3549 154           CLEAR(parser, whitespaces);
3550 154 50         if (!READ_LINE(parser, leading_break)) goto error;
    0          
    50          
    50          
    0          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
3551 154           leading_blanks = 1;
3552             }
3553             else
3554             {
3555 0 0         if (!READ_LINE(parser, trailing_breaks)) goto error;
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3556             }
3557             }
3558 245 50         if (!CACHE(parser, 1)) goto error;
    0          
3559             }
3560              
3561             /* Check indentation level. */
3562              
3563 202 100         if (!parser->flow_level && (int)parser->mark.column < indent)
    100          
3564 126           break;
3565 76           }
3566              
3567             /* Create a token. */
3568              
3569 302           SCALAR_TOKEN_INIT(*token, string.start, string.pointer-string.start,
3570             YAML_PLAIN_SCALAR_STYLE, start_mark, end_mark);
3571              
3572             /* Note that we change the 'simple_key_allowed' flag. */
3573              
3574 302 100         if (leading_blanks) {
3575 153           parser->simple_key_allowed = 1;
3576             }
3577              
3578 302           STRING_DEL(parser, leading_break);
3579 302           STRING_DEL(parser, trailing_breaks);
3580 302           STRING_DEL(parser, whitespaces);
3581              
3582 302           return 1;
3583              
3584             error:
3585 0           STRING_DEL(parser, string);
3586 0           STRING_DEL(parser, leading_break);
3587 0           STRING_DEL(parser, trailing_breaks);
3588 0           STRING_DEL(parser, whitespaces);
3589              
3590 302           return 0;
3591             }