Coverage Report

Created: 2026-07-30 06:35

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