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