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