source: libyaml/trunk/src/yaml_private.h @ 263

Revision 263, 45.5 KB checked in by xi, 6 years ago (diff)

Completed the first phase of API refactoring.

Line 
1
2#if HAVE_CONFIG_H
3#include <config.h>
4#endif
5
6#include <yaml.h>
7
8#include <assert.h>
9#include <limits.h>
10
11/*
12 * Memory management.
13 */
14
15YAML_DECLARE(void *)
16yaml_malloc(size_t size);
17
18YAML_DECLARE(void *)
19yaml_realloc(void *ptr, size_t size);
20
21YAML_DECLARE(void)
22yaml_free(void *ptr);
23
24YAML_DECLARE(yaml_char_t *)
25yaml_strdup(const yaml_char_t *);
26
27/*
28 * Error management.
29 */
30
31#define ERROR_INIT(error,error_type)                                            \
32    (memset(&(error), 0, sizeof(error)),                                        \
33     (error).type = (error_type),                                               \
34     0)
35
36#define READING_ERROR_INIT(error,error_type,error_problem,error_offset,error_value) \
37    (memset(&(error), 0, sizeof(error)),                                        \
38     (error).type = (error_type),                                               \
39     (error).data.reading.problem = (error_problem),                            \
40     (error).data.reading.offset = (error_offset),                              \
41     (error).data.reading.value = (error_value),                                \
42     0)
43
44#define LOADING_ERROR_INIT(error,error_type,error_problem,error_problem_mark)   \
45    (memset(&(error), 0, sizeof(error)),                                        \
46     (error).type = (error_type),                                               \
47     (error).data.loading.context = NULL,                                       \
48     (error).data.loading.context_mark.index = 0,                               \
49     (error).data.loading.context_mark.line = 0,                                \
50     (error).data.loading.context_mark.column = 0,                              \
51     (error).data.loading.problem = (error_problem),                            \
52     (error).data.loading.problem_mark = (error_problem_mark),                  \
53     0)
54
55#define LOADING_ERROR_WITH_CONTEXT_INIT(error,error_type,error_context,error_context_mark,error_problem,error_problem_mark) \
56    (memset(&(error), 0, sizeof(error)),                                        \
57     (error).type = (error_type),                                               \
58     (error).data.loading.context = (error_context),                            \
59     (error).data.loading.context_mark = (error_context_mark),                  \
60     (error).data.loading.problem = (error_problem),                            \
61     (error).data.loading.problem_mark = (error_problem_mark),                  \
62     0)
63
64#define WRITING_ERROR_INIT(error,error_type,error_problem,error_offset)         \
65    (memset(&(error), 0, sizeof(error)),                                        \
66     (error).type = (error_type),                                               \
67     (error).data.writing.problem = (error_problem),                            \
68     (error).data.writing.offset = (error_offset),                              \
69     0)
70
71#define DUMPING_ERROR_INIT(error,error_type,error_problem)                      \
72    (memset(&(error), 0, sizeof(error)),                                        \
73     (error).type = (error_type),                                               \
74     (error).data.dumping.problem = (error_problem),                            \
75     0)
76
77#define MEMORY_ERROR_INIT(self)                                                 \
78    ERROR_INIT((self)->error,YAML_MEMORY_ERROR)
79
80#define READER_ERROR_INIT(self,problem,offset)                                  \
81    READING_ERROR_INIT((self)->error,YAML_READER_ERROR,problem,offset,-1)
82
83#define DECODER_ERROR_INIT(self,problem,offset,value)                           \
84    READING_ERROR_INIT((self)->error,YAML_DECODER_ERROR,problem,offset,value)
85
86#define SCANNER_ERROR_INIT(self,problem,problem_mark)                           \
87    LOADING_ERROR_INIT((self)->error,YAML_SCANNER_ERROR,problem,problem_mark)
88
89#define SCANNER_ERROR_WITH_CONTEXT_INIT(self,context,context_mark,problem,problem_mark) \
90    LOADING_ERROR_WITH_CONTEXT_INIT((self)->error,YAML_SCANNER_ERROR,context,context_mark,problem,problem_mark)
91
92#define PARSER_ERROR_INIT(self,problem,problem_mark)                            \
93    LOADING_ERROR_INIT((self)->error,YAML_PARSER_ERROR,problem,problem_mark)
94
95#define PARSER_ERROR_WITH_CONTEXT_INIT(self,context,context_mark,problem,problem_mark)  \
96    LOADING_ERROR_WITH_CONTEXT_INIT((self)->error,YAML_PARSER_ERROR,context,context_mark,problem,problem_mark)
97
98#define COMPOSER_ERROR_INIT(self,problem,problem_mark)                          \
99    LOADING_ERROR_INIT((self)->error,YAML_COMPOSER_ERROR,problem,problem_mark)
100
101#define COMPOSER_ERROR_WITH_CONTEXT_INIT(self,context,context_mark,problem,problem_mark)    \
102    LOADING_ERROR_WITH_CONTEXT_INIT((self)->error,YAML_COMPOSER_ERROR,context,context_mark,problem,problem_mark)
103
104#define WRITER_ERROR_INIT(self,problem,offset)                                  \
105    WRITING_ERROR_INIT((self)->error,YAML_WRITER_ERROR,problem,offset)
106
107#define EMITTER_ERROR_INIT(self,problem)                                        \
108    DUMPING_ERROR_INIT((self)->error,YAML_EMITTER_ERROR,problem)
109
110#define SERIALIZER_ERROR_INIT(self,context)                                     \
111    DUMPING_ERROR_INIT((self)->error,YAML_SERIALIZER_ERROR,problem)
112
113/*
114 * The size of the input raw buffer.
115 */
116
117#define RAW_INPUT_BUFFER_CAPACITY   16384
118
119/*
120 * The size of the input buffer.
121 *
122 * The input buffer should be large enough to hold the content of the raw
123 * buffer after it is decoded.
124 */
125
126#define INPUT_BUFFER_CAPACITY   (RAW_INPUT_BUFFER_CAPACITY*3)
127
128/*
129 * The size of the output buffer.
130 */
131
132#define OUTPUT_BUFFER_CAPACITY  16384
133
134/*
135 * The size of the output raw buffer.
136 *
137 * The raw buffer should be able to hold the content of the output buffer
138 * after it is encoded.
139 */
140
141#define RAW_OUTPUT_BUFFER_CAPACITY  (OUTPUT_BUFFER_CAPACITY*2+2)
142
143/*
144 * The size of other stacks and queues.
145 */
146
147#define INITIAL_STACK_CAPACITY  16
148#define INITIAL_QUEUE_CAPACITY  16
149#define INITIAL_STRING_CAPACITY 16
150
151/*
152 * String management.
153 */
154
155typedef struct yaml_string_s {
156    yaml_char_t *buffer;
157    size_t pointer;
158    size_t capacity;
159} yaml_string_t;
160
161YAML_DECLARE(int)
162yaml_string_extend(yaml_char_t **buffer, size_t *capacity);
163
164YAML_DECLARE(int)
165yaml_string_join(
166        yaml_char_t **base_buffer, size_t *base_pointer, size_t *base_capacity,
167        yaml_char_t *adj_buffer, size_t adj_pointer, size_t adj_capacity);
168
169#define NULL_STRING { NULL, 0, 0 }
170
171#define STRING(string,capacity)   { (string), 0, (capacity) }
172
173#define STRING_INIT(self,string,string_capacity)                                \
174    (((string).buffer = yaml_malloc(string_capacity)) ?                         \
175        ((string).pointer = 0,                                                  \
176         (string).capacity = (string_capacity),                                 \
177         memset((string).buffer, 0, (string_capacity)),                         \
178         1) :                                                                   \
179        ((self)->error.type = YAML_MEMORY_ERROR,                                \
180         0))
181
182#define STRING_DEL(self,string)                                                 \
183    (yaml_free((string).buffer),                                                \
184     (string).buffer = NULL,                                                    \
185     ((string).pointer = (string).capacity = 0))
186
187#define STRING_EXTEND(self,string)                                              \
188    ((((string).pointer+5 < (string).capacity)                                  \
189        || yaml_string_extend(&(string).buffer, &(string).capacity)) ?          \
190     1 :                                                                        \
191     ((self)->error.type = YAML_MEMORY_ERROR,                                   \
192      0))
193
194#define CLEAR(self,string)                                                      \
195    ((string).pointer = 0,                                                      \
196     memset((string).buffer, 0, (string).capacity))
197
198#define JOIN(self,base_string,adj_string)                                       \
199    ((yaml_string_join(&(base_string).buffer, &(base_string).pointer,           \
200                       &(base_string).capacity, (adj_string).buffer,            \
201                       (adj_string).pointer, (adj_string).capacity)) ?          \
202        ((adj_string).pointer = 0,                                              \
203         1) :                                                                   \
204        ((self)->error.type = YAML_MEMORY_ERROR,                                \
205         0))
206
207/*
208 * String check operations.
209 */
210
211/*
212 * Get the octet at the specified position.
213 */
214
215#define OCTET_AT(string,offset)                                                 \
216    ((string).buffer[(string).pointer+(offset)])
217
218/*
219 * Get the current offset.
220 */
221
222#define OCTET(string)   OCTET_AT((string),0)
223
224/*
225 * Check the octet at the specified position.
226 */
227
228#define CHECK_AT(string,octet,offset)                                           \
229    (OCTET_AT((string),(offset)) == (yaml_char_t)(octet))
230
231/*
232 * Check the current octet in the buffer.
233 */
234
235#define CHECK(string,octet) CHECK_AT((string),(octet),0)
236
237/*
238 * Check if the character at the specified position is an alphabetical
239 * character, a digit, '_', or '-'.
240 */
241
242#define IS_ALPHA_AT(string,offset)                                              \
243     ((OCTET_AT((string),(offset)) >= (yaml_char_t) '0' &&                      \
244       OCTET_AT((string),(offset)) <= (yaml_char_t) '9') ||                     \
245      (OCTET_AT((string),(offset)) >= (yaml_char_t) 'A' &&                      \
246       OCTET_AT((string),(offset)) <= (yaml_char_t) 'Z') ||                     \
247      (OCTET_AT((string),(offset)) >= (yaml_char_t) 'a' &&                      \
248       OCTET_AT((string),(offset)) <= (yaml_char_t) 'z') ||                     \
249      OCTET_AT((string),(offset)) == '_' ||                                     \
250      OCTET_AT((string),(offset)) == '-')
251
252#define IS_ALPHA(string)    IS_ALPHA_AT((string),0)
253
254/*
255 * Check if the character at the specified position is a digit.
256 */
257
258#define IS_DIGIT_AT(string,offset)                                              \
259     ((OCTET_AT((string),(offset)) >= (yaml_char_t) '0' &&                      \
260       OCTET_AT((string),(offset)) <= (yaml_char_t) '9'))
261
262#define IS_DIGIT(string)    IS_DIGIT_AT((string),0)
263
264/*
265 * Get the value of a digit.
266 */
267
268#define AS_DIGIT_AT(string,offset)                                              \
269     (OCTET_AT((string),(offset)) - (yaml_char_t) '0')
270
271#define AS_DIGIT(string)    AS_DIGIT_AT((string),0)
272
273/*
274 * Check if the character at the specified position is a hex-digit.
275 */
276
277#define IS_HEX_AT(string,offset)                                                \
278     ((OCTET_AT((string),(offset)) >= (yaml_char_t) '0' &&                      \
279       OCTET_AT((string),(offset)) <= (yaml_char_t) '9') ||                     \
280      (OCTET_AT((string),(offset)) >= (yaml_char_t) 'A' &&                      \
281       OCTET_AT((string),(offset)) <= (yaml_char_t) 'F') ||                     \
282      (OCTET_AT((string),(offset)) >= (yaml_char_t) 'a' &&                      \
283       OCTET_AT((string),(offset)) <= (yaml_char_t) 'f'))
284
285#define IS_HEX(string)    IS_HEX_AT((string),0)
286
287/*
288 * Get the value of a hex-digit.
289 */
290
291#define AS_HEX_AT(string,offset)                                                \
292      ((OCTET_AT((string),(offset)) >= (yaml_char_t) 'A' &&                     \
293        OCTET_AT((string),(offset)) <= (yaml_char_t) 'F') ?                     \
294       (OCTET_AT((string),(offset)) - (yaml_char_t) 'A' + 10) :                 \
295       (OCTET_AT((string),(offset)) >= (yaml_char_t) 'a' &&                     \
296        OCTET_AT((string),(offset)) <= (yaml_char_t) 'f') ?                     \
297       (OCTET_AT((string),(offset)) - (yaml_char_t) 'a' + 10) :                 \
298       (OCTET_AT((string),(offset)) - (yaml_char_t) '0'))
299 
300#define AS_HEX(string)  AS_HEX_AT((string),0)
301 
302/*
303 * Check if the character is ASCII.
304 */
305
306#define IS_ASCII_AT(string,offset)                                              \
307    (OCTET_AT((string),(offset)) <= (yaml_char_t) '\x7F')
308
309#define IS_ASCII(string)    IS_ASCII_AT((string),0)
310
311/*
312 * Check if the character can be printed unescaped.
313 */
314
315#define IS_PRINTABLE_AT(string,offset)                                          \
316    ((OCTET_AT((string),(offset)) == 0x0A)          /* . == #x0A */             \
317     || (OCTET_AT((string),(offset)) >= 0x20        /* #x20 <= . <= #x7E */     \
318         && OCTET_AT((string),(offset)) <= 0x7E)                                \
319     || (OCTET_AT((string),(offset)) == 0xC2        /* #0xA0 <= . <= #xD7FF */  \
320         && OCTET_AT((string),(offset)+1) >= 0xA0)                              \
321     || (OCTET_AT((string),(offset)) > 0xC2                                     \
322         && OCTET_AT((string),(offset)) < 0xED)                                 \
323     || (OCTET_AT((string),(offset)) == 0xED                                    \
324         && OCTET_AT((string),(offset)+1) < 0xA0)                               \
325     || (OCTET_AT((string),(offset)) == 0xEE)                                   \
326     || (OCTET_AT((string),(offset)) == 0xEF        /* #xE000 <= . <= #xFFFD */ \
327         && !(OCTET_AT((string),(offset)+1) == 0xBB        /* && . != #xFEFF */ \
328             && OCTET_AT((string),(offset)+2) == 0xBF)                          \
329         && !(OCTET_AT((string),(offset)+1) == 0xBF                             \
330             && (OCTET_AT((string),(offset)+2) == 0xBE                          \
331                 || OCTET_AT((string),(offset)+2) == 0xBF))))
332
333#define IS_PRINTABLE(string)    IS_PRINTABLE_AT((string),0)
334
335/*
336 * Check if the character at the specified position is NUL.
337 */
338
339#define IS_Z_AT(string,offset)    CHECK_AT((string),'\0',(offset))
340
341#define IS_Z(string)    IS_Z_AT((string),0)
342
343/*
344 * Check if the character at the specified position is BOM.
345 */
346
347#define IS_BOM_AT(string,offset)                                                \
348     (CHECK_AT((string),'\xEF',(offset))                                        \
349      && CHECK_AT((string),'\xBB',(offset)+1)                                   \
350      && CHECK_AT((string),'\xBF',(offset)+2))  /* BOM (#xFEFF) */
351
352#define IS_BOM(string)  IS_BOM_AT(string,0)
353
354/*
355 * Check if the character at the specified position is space.
356 */
357
358#define IS_SPACE_AT(string,offset)  CHECK_AT((string),' ',(offset))
359
360#define IS_SPACE(string)    IS_SPACE_AT((string),0)
361
362/*
363 * Check if the character at the specified position is tab.
364 */
365
366#define IS_TAB_AT(string,offset)    CHECK_AT((string),'\t',(offset))
367
368#define IS_TAB(string)  IS_TAB_AT((string),0)
369
370/*
371 * Check if the character at the specified position is blank (space or tab).
372 */
373
374#define IS_BLANK_AT(string,offset)                                              \
375    (IS_SPACE_AT((string),(offset)) || IS_TAB_AT((string),(offset)))
376
377#define IS_BLANK(string)    IS_BLANK_AT((string),0)
378
379/*
380 * Check if the character at the specified position is a line break.
381 */
382
383#define IS_BREAK_AT(string,offset)                                              \
384    (CHECK_AT((string),'\r',(offset))               /* CR (#xD)*/               \
385     || CHECK_AT((string),'\n',(offset))            /* LF (#xA) */              \
386     || (CHECK_AT((string),'\xC2',(offset))                                     \
387         && CHECK_AT((string),'\x85',(offset)+1))   /* NEL (#x85) */            \
388     || (CHECK_AT((string),'\xE2',(offset))                                     \
389         && CHECK_AT((string),'\x80',(offset)+1)                                \
390         && CHECK_AT((string),'\xA8',(offset)+2))   /* LS (#x2028) */           \
391     || (CHECK_AT((string),'\xE2',(offset))                                     \
392         && CHECK_AT((string),'\x80',(offset)+1)                                \
393         && CHECK_AT((string),'\xA9',(offset)+2)))  /* PS (#x2029) */
394
395#define IS_BREAK(string)    IS_BREAK_AT((string),0)
396
397#define IS_CRLF_AT(string,offset)                                               \
398     (CHECK_AT((string),'\r',(offset)) && CHECK_AT((string),'\n',(offset)+1))
399
400#define IS_CRLF(string) IS_CRLF_AT((string),0)
401
402/*
403 * Check if the character is a line break or NUL.
404 */
405
406#define IS_BREAKZ_AT(string,offset)                                             \
407    (IS_BREAK_AT((string),(offset)) || IS_Z_AT((string),(offset)))
408
409#define IS_BREAKZ(string)   IS_BREAKZ_AT((string),0)
410
411/*
412 * Check if the character is a line break, space, or NUL.
413 */
414
415#define IS_SPACEZ_AT(string,offset)                                             \
416    (IS_SPACE_AT((string),(offset)) || IS_BREAKZ_AT((string),(offset)))
417
418#define IS_SPACEZ(string)   IS_SPACEZ_AT((string),0)
419
420/*
421 * Check if the character is a line break, space, tab, or NUL.
422 */
423
424#define IS_BLANKZ_AT(string,offset)                                             \
425    (IS_BLANK_AT((string),(offset)) || IS_BREAKZ_AT((string),(offset)))
426
427#define IS_BLANKZ(string)   IS_BLANKZ_AT((string),0)
428
429/*
430 * Determine the width of the character.
431 */
432
433#define WIDTH_AT(string,offset)                                                 \
434     ((OCTET_AT((string),(offset)) & 0x80) == 0x00 ? 1 :                        \
435      (OCTET_AT((string),(offset)) & 0xE0) == 0xC0 ? 2 :                        \
436      (OCTET_AT((string),(offset)) & 0xF0) == 0xE0 ? 3 :                        \
437      (OCTET_AT((string),(offset)) & 0xF8) == 0xF0 ? 4 : 0)
438
439#define WIDTH(string)   WIDTH_AT((string),0)
440
441/*
442 * Move the string pointer to the next character.
443 */
444
445#define MOVE(string)    ((string).pointer += WIDTH((string)))
446
447/*
448 * Write a single octet and bump the pointer.
449 */
450
451#define JOIN_OCTET(string,octet)                                                \
452    ((string).buffer[(string).pointer++] = (octet))
453
454/*
455 * Copy a single octet and bump the pointers.
456 */
457
458#define COPY_OCTET(string_a,string_b)                                           \
459    ((string_a).buffer[(string_a).pointer++]                                    \
460     = (string_b).buffer[(string_b).pointer++])
461
462/*
463 * Copy a character and move the pointers of both strings.
464 */
465
466#define COPY(string_a,string_b)                                                 \
467    ((OCTET(string_b) & 0x80) == 0x00 ?                                         \
468     COPY_OCTET((string_a),(string_b)) :                                        \
469     (OCTET(string_b) & 0xE0) == 0xC0 ?                                         \
470     (COPY_OCTET((string_a),(string_b)),                                        \
471      COPY_OCTET((string_a),(string_b))) :                                      \
472     (OCTET(string_b) & 0xF0) == 0xE0 ?                                         \
473     (COPY_OCTET((string_a),(string_b)),                                        \
474      COPY_OCTET((string_a),(string_b)),                                        \
475      COPY_OCTET((string_a),(string_b))) :                                      \
476     (OCTET(string_b) & 0xF8) == 0xF0 ?                                         \
477     (COPY_OCTET((string_a),(string_b)),                                        \
478      COPY_OCTET((string_a),(string_b)),                                        \
479      COPY_OCTET((string_a),(string_b)),                                        \
480      COPY_OCTET((string_a),(string_b))) : 0)                                   \
481
482/*
483 * Stack and queue management.
484 */
485
486YAML_DECLARE(int)
487yaml_stack_extend(void **list, size_t size, size_t *length, size_t *capacity);
488
489YAML_DECLARE(int)
490yaml_queue_extend(void **list, size_t size,
491        size_t *head, size_t *tail, size_t *capacity);
492
493#define STACK_INIT(self,stack,stack_capacity)                                   \
494    (((stack).list = yaml_malloc((stack_capacity)*sizeof(*(stack).list))) ?     \
495        ((stack).length = 0,                                                    \
496         (stack).capacity = (stack_capacity),                                   \
497         1) :                                                                   \
498        ((self)->error.type = YAML_MEMORY_ERROR,                                \
499         0))
500
501#define STACK_DEL(self,stack)                                                   \
502    (yaml_free((stack).list),                                                   \
503     (stack).list = NULL,                                                       \
504     (stack).length = (stack).capacity = 0)
505
506#define STACK_EMPTY(self,stack)                                                 \
507    ((stack).length == 0)
508
509#define PUSH(self,stack,value)                                                  \
510    (((stack).length < (stack).capacity                                         \
511      || yaml_stack_extend((void **)&(stack).list, sizeof(*(stack).list),       \
512              &(stack).length, &(stack).capacity)) ?                            \
513        ((stack).list[(stack).length++] = (value),                              \
514         1) :                                                                   \
515        ((self)->error.type = YAML_MEMORY_ERROR,                                \
516         0))
517
518#define POP(self,stack)                                                         \
519    ((stack).list[--(stack).length])
520
521#define QUEUE_INIT(self,queue,queue_capacity)                                   \
522    (((queue).list = yaml_malloc((queue_capacity)*sizeof(*(queue).list))) ?     \
523        ((queue).head = (queue).tail = 0,                                       \
524         (queue).capacity = (queue_capacity),                                   \
525         1) :                                                                   \
526        ((self)->error.type = YAML_MEMORY_ERROR,                                \
527         0))
528
529#define QUEUE_DEL(self,queue)                                                   \
530    (yaml_free((queue).list),                                                   \
531     (queue).list = NULL,                                                       \
532     (queue).head = (queue).tail = (queue).capacity = 0)
533
534#define QUEUE_EMPTY(self,queue)                                                 \
535    ((queue).head == (queue).tail)
536
537#define ENQUEUE(self,queue,value)                                               \
538    (((queue).tail != (queue).capacity                                          \
539      || yaml_queue_extend((void **)&(queue).list, sizeof(*(queue).list),       \
540          &(queue).head, &(queue).tail, &(queue).capacity)) ?                   \
541        ((queue).list[(queue).tail++] = (value),                                \
542         1) :                                                                   \
543        ((self)->error.type = YAML_MEMORY_ERROR,                                \
544         0))
545
546#define DEQUEUE(self,queue)                                                     \
547    ((queue).list[(queue).head++])
548
549#define QUEUE_INSERT(self,queue,index,value)                                    \
550    (((queue).tail != (queue).capacity                                          \
551      || yaml_queue_extend((void **)&(queue).list, sizeof(*(queue).list),       \
552          &(queue).head, &(queue).tail, &(queue).capacity)) ?                   \
553        (memmove((queue).list+(queue).head+(index)+1,                           \
554                 (queue).list+(queue).head+(index),                             \
555            ((queue).tail-(queue).head-(index))*sizeof(*(queue).list)),         \
556         (queue).list[(queue).head+(index)] = (value),                          \
557         (queue).tail++,                                                        \
558         1) :                                                                   \
559        ((self)->error.type = YAML_MEMORY_ERROR,                                \
560         0))
561
562/*
563 * Token initializers.
564 */
565
566#define TOKEN_INIT(token,token_type,token_start_mark,token_end_mark)            \
567    (memset(&(token), 0, sizeof(yaml_token_t)),                                 \
568     (token).type = (token_type),                                               \
569     (token).start_mark = (token_start_mark),                                   \
570     (token).end_mark = (token_end_mark))
571
572#define STREAM_START_TOKEN_INIT(token,token_encoding,start_mark,end_mark)       \
573    (TOKEN_INIT((token),YAML_STREAM_START_TOKEN,(start_mark),(end_mark)),       \
574     (token).data.stream_start.encoding = (token_encoding))
575
576#define STREAM_END_TOKEN_INIT(token,start_mark,end_mark)                        \
577    (TOKEN_INIT((token),YAML_STREAM_END_TOKEN,(start_mark),(end_mark)))
578
579#define ALIAS_TOKEN_INIT(token,token_value,start_mark,end_mark)                 \
580    (TOKEN_INIT((token),YAML_ALIAS_TOKEN,(start_mark),(end_mark)),              \
581     (token).data.alias.value = (token_value))
582
583#define ANCHOR_TOKEN_INIT(token,token_value,start_mark,end_mark)                \
584    (TOKEN_INIT((token),YAML_ANCHOR_TOKEN,(start_mark),(end_mark)),             \
585     (token).data.anchor.value = (token_value))
586
587#define TAG_TOKEN_INIT(token,token_handle,token_suffix,start_mark,end_mark)     \
588    (TOKEN_INIT((token),YAML_TAG_TOKEN,(start_mark),(end_mark)),                \
589     (token).data.tag.handle = (token_handle),                                  \
590     (token).data.tag.suffix = (token_suffix))
591
592#define SCALAR_TOKEN_INIT(token,token_value,token_length,token_style,start_mark,end_mark)   \
593    (TOKEN_INIT((token),YAML_SCALAR_TOKEN,(start_mark),(end_mark)),             \
594     (token).data.scalar.value = (token_value),                                 \
595     (token).data.scalar.length = (token_length),                               \
596     (token).data.scalar.style = (token_style))
597
598#define VERSION_DIRECTIVE_TOKEN_INIT(token,token_major,token_minor,start_mark,end_mark)     \
599    (TOKEN_INIT((token),YAML_VERSION_DIRECTIVE_TOKEN,(start_mark),(end_mark)),  \
600     (token).data.version_directive.major = (token_major),                      \
601     (token).data.version_directive.minor = (token_minor))
602
603#define TAG_DIRECTIVE_TOKEN_INIT(token,token_handle,token_prefix,start_mark,end_mark)       \
604    (TOKEN_INIT((token),YAML_TAG_DIRECTIVE_TOKEN,(start_mark),(end_mark)),      \
605     (token).data.tag_directive.handle = (token_handle),                        \
606     (token).data.tag_directive.prefix = (token_prefix))
607
608/*
609 * Event initializers.
610 */
611
612#define EVENT_INIT(event,event_type,event_start_mark,event_end_mark)            \
613    (memset(&(event), 0, sizeof(yaml_event_t)),                                 \
614     (event).type = (event_type),                                               \
615     (event).start_mark = (event_start_mark),                                   \
616     (event).end_mark = (event_end_mark))
617
618#define STREAM_START_EVENT_INIT(event,event_encoding,start_mark,end_mark)       \
619    (EVENT_INIT((event),YAML_STREAM_START_EVENT,(start_mark),(end_mark)),       \
620     (event).data.stream_start.encoding = (event_encoding))
621
622#define STREAM_END_EVENT_INIT(event,start_mark,end_mark)                        \
623    (EVENT_INIT((event),YAML_STREAM_END_EVENT,(start_mark),(end_mark)))
624
625#define DOCUMENT_START_EVENT_INIT(event,event_version_directive,                \
626        event_tag_directives_list,event_tag_directives_length,                  \
627        event_tag_directives_capacity,event_is_implicit,start_mark,end_mark)    \
628    (EVENT_INIT((event),YAML_DOCUMENT_START_EVENT,(start_mark),(end_mark)),     \
629     (event).data.document_start.version_directive = (event_version_directive), \
630     (event).data.document_start.tag_directives.list = (event_tag_directives_list), \
631     (event).data.document_start.tag_directives.length = (event_tag_directives_length), \
632     (event).data.document_start.tag_directives.capacity = (event_tag_directives_capacity), \
633     (event).data.document_start.is_implicit = (event_is_implicit))
634
635#define DOCUMENT_END_EVENT_INIT(event,event_is_implicit,start_mark,end_mark)    \
636    (EVENT_INIT((event),YAML_DOCUMENT_END_EVENT,(start_mark),(end_mark)),       \
637     (event).data.document_end.is_implicit = (event_is_implicit))
638
639#define ALIAS_EVENT_INIT(event,event_anchor,start_mark,end_mark)                \
640    (EVENT_INIT((event),YAML_ALIAS_EVENT,(start_mark),(end_mark)),              \
641     (event).data.alias.anchor = (event_anchor))
642
643#define SCALAR_EVENT_INIT(event,event_anchor,event_tag,event_value,             \
644        event_length,event_is_plain_implicit,event_is_quoted_implicit,          \
645        event_style,start_mark,end_mark)                                        \
646    (EVENT_INIT((event),YAML_SCALAR_EVENT,(start_mark),(end_mark)),             \
647     (event).data.scalar.anchor = (event_anchor),                               \
648     (event).data.scalar.tag = (event_tag),                                     \
649     (event).data.scalar.value = (event_value),                                 \
650     (event).data.scalar.length = (event_length),                               \
651     (event).data.scalar.is_plain_implicit = (event_is_plain_implicit),         \
652     (event).data.scalar.is_quoted_implicit = (event_is_quoted_implicit),       \
653     (event).data.scalar.style = (event_style))
654
655#define SEQUENCE_START_EVENT_INIT(event,event_anchor,event_tag,                 \
656        event_is_implicit,event_style,start_mark,end_mark)                      \
657    (EVENT_INIT((event),YAML_SEQUENCE_START_EVENT,(start_mark),(end_mark)),     \
658     (event).data.sequence_start.anchor = (event_anchor),                       \
659     (event).data.sequence_start.tag = (event_tag),                             \
660     (event).data.sequence_start.is_implicit = (event_is_implicit),             \
661     (event).data.sequence_start.style = (event_style))
662
663#define SEQUENCE_END_EVENT_INIT(event,start_mark,end_mark)                      \
664    (EVENT_INIT((event),YAML_SEQUENCE_END_EVENT,(start_mark),(end_mark)))
665
666#define MAPPING_START_EVENT_INIT(event,event_anchor,event_tag,                  \
667        event_is_implicit,event_style,start_mark,end_mark)                      \
668    (EVENT_INIT((event),YAML_MAPPING_START_EVENT,(start_mark),(end_mark)),      \
669     (event).data.mapping_start.anchor = (event_anchor),                        \
670     (event).data.mapping_start.tag = (event_tag),                              \
671     (event).data.mapping_start.is_implicit = (event_is_implicit),              \
672     (event).data.mapping_start.style = (event_style))
673
674#define MAPPING_END_EVENT_INIT(event,start_mark,end_mark)                       \
675    (EVENT_INIT((event),YAML_MAPPING_END_EVENT,(start_mark),(end_mark)))
676
677/*
678 * Document initializer.
679 */
680
681#define DOCUMENT_INIT(document,document_nodes_start,document_nodes_end,         \
682        document_version_directive,document_tag_directives_start,               \
683        document_tag_directives_end,document_start_implicit,                    \
684        document_end_implicit,document_start_mark,document_end_mark)            \
685    (memset(&(document), 0, sizeof(yaml_document_t)),                           \
686     (document).nodes.start = (document_nodes_start),                           \
687     (document).nodes.end = (document_nodes_end),                               \
688     (document).nodes.top = (document_nodes_start),                             \
689     (document).version_directive = (document_version_directive),               \
690     (document).tag_directives.start = (document_tag_directives_start),         \
691     (document).tag_directives.end = (document_tag_directives_end),             \
692     (document).start_implicit = (document_start_implicit),                     \
693     (document).end_implicit = (document_end_implicit),                         \
694     (document).start_mark = (document_start_mark),                             \
695     (document).end_mark = (document_end_mark))
696
697/*
698 * Node initializers.
699 */
700
701#define NODE_INIT(node,node_type,node_tag,node_start_mark,node_end_mark)        \
702    (memset(&(node), 0, sizeof(yaml_node_t)),                                   \
703     (node).type = (node_type),                                                 \
704     (node).tag = (node_tag),                                                   \
705     (node).start_mark = (node_start_mark),                                     \
706     (node).end_mark = (node_end_mark))
707
708#define SCALAR_NODE_INIT(node,node_tag,node_value,node_length,                  \
709        node_style,start_mark,end_mark)                                         \
710    (NODE_INIT((node),YAML_SCALAR_NODE,(node_tag),(start_mark),(end_mark)),     \
711     (node).data.scalar.value = (node_value),                                   \
712     (node).data.scalar.length = (node_length),                                 \
713     (node).data.scalar.style = (node_style))
714
715#define SEQUENCE_NODE_INIT(node,node_tag,node_items_start,node_items_end,       \
716        node_style,start_mark,end_mark)                                         \
717    (NODE_INIT((node),YAML_SEQUENCE_NODE,(node_tag),(start_mark),(end_mark)),   \
718     (node).data.sequence.items.start = (node_items_start),                     \
719     (node).data.sequence.items.end = (node_items_end),                         \
720     (node).data.sequence.items.top = (node_items_start),                       \
721     (node).data.sequence.style = (node_style))
722
723#define MAPPING_NODE_INIT(node,node_tag,node_pairs_start,node_pairs_end,        \
724        node_style,start_mark,end_mark)                                         \
725    (NODE_INIT((node),YAML_MAPPING_NODE,(node_tag),(start_mark),(end_mark)),    \
726     (node).data.mapping.pairs.start = (node_pairs_start),                      \
727     (node).data.mapping.pairs.end = (node_pairs_end),                          \
728     (node).data.mapping.pairs.top = (node_pairs_start),                        \
729     (node).data.mapping.style = (node_style))
730
731/*
732 * This structure holds information about a potential simple key.
733 */
734
735typedef struct yaml_simple_key_s {
736    /* Is a simple key possible? */
737    int is_possible;
738    /* Is a simple key required? */
739    int is_required;
740    /* The number of the token. */
741    size_t token_number;
742    /* The position mark. */
743    yaml_mark_t mark;
744} yaml_simple_key_t;
745
746/*
747 * The states of the parser.
748 */
749
750typedef enum yaml_parser_state_e {
751    /* Expect STREAM-START. */
752    YAML_PARSE_STREAM_START_STATE,
753    /* Expect the beginning of an implicit document. */
754    YAML_PARSE_IMPLICIT_DOCUMENT_START_STATE,
755    /* Expect DOCUMENT-START. */
756    YAML_PARSE_DOCUMENT_START_STATE,
757    /* Expect the content of a document. */
758    YAML_PARSE_DOCUMENT_CONTENT_STATE,
759    /* Expect DOCUMENT-END. */
760    YAML_PARSE_DOCUMENT_END_STATE,
761    /* Expect a block node. */
762    YAML_PARSE_BLOCK_NODE_STATE,
763    /* Expect a block node or indentless sequence. */
764    YAML_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE,
765    /* Expect a flow node. */
766    YAML_PARSE_FLOW_NODE_STATE,
767    /* Expect the first entry of a block sequence. */
768    YAML_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE,
769    /* Expect an entry of a block sequence. */
770    YAML_PARSE_BLOCK_SEQUENCE_ENTRY_STATE,
771    /* Expect an entry of an indentless sequence. */
772    YAML_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE,
773    /* Expect the first key of a block mapping. */
774    YAML_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE,
775    /* Expect a block mapping key. */
776    YAML_PARSE_BLOCK_MAPPING_KEY_STATE,
777    /* Expect a block mapping value. */
778    YAML_PARSE_BLOCK_MAPPING_VALUE_STATE,
779    /* Expect the first entry of a flow sequence. */
780    YAML_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE,
781    /* Expect an entry of a flow sequence. */
782    YAML_PARSE_FLOW_SEQUENCE_ENTRY_STATE,
783    /* Expect a key of an ordered mapping. */
784    YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE,
785    /* Expect a value of an ordered mapping. */
786    YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE,
787    /* Expect the and of an ordered mapping entry. */
788    YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE,
789    /* Expect the first key of a flow mapping. */
790    YAML_PARSE_FLOW_MAPPING_FIRST_KEY_STATE,
791    /* Expect a key of a flow mapping. */
792    YAML_PARSE_FLOW_MAPPING_KEY_STATE,
793    /* Expect a value of a flow mapping. */
794    YAML_PARSE_FLOW_MAPPING_VALUE_STATE,
795    /* Expect an empty value of a flow mapping. */
796    YAML_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE,
797    /* Expect nothing. */
798    YAML_PARSE_END_STATE
799} yaml_parser_state_t;
800
801/*
802 * This structure holds aliases data.
803 */
804
805typedef struct yaml_alias_data_s {
806    /* The anchor. */
807    yaml_char_t *anchor;
808    /* The node id. */
809    int index;
810    /* The anchor mark. */
811    yaml_mark_t mark;
812} yaml_alias_data_t;
813
814/*
815 * The structure that holds data used by the file and string readers.
816 */
817
818typedef union yaml_standard_reader_data_u {
819    /* String input data. */
820    yaml_string_t string;
821    /* File input data. */
822    FILE *file;
823} yaml_standard_reader_data_t;
824
825/*
826 * The internal parser structure.
827 */
828
829struct yaml_parser_s {
830
831    /*
832     * Error stuff.
833     */
834
835    yaml_error_t error;
836
837    /*
838     * Reader stuff.
839     */
840
841    /* The read handler. */
842    yaml_reader_t *reader;
843
844    /* The application data to be passed to the reader. */
845    void *reader_data;
846
847    /* Standard (string or file) input data. */
848    yaml_standard_reader_data_t standard_reader_data;
849
850    /* EOF flag. */
851    int is_eof;
852
853    /* The working buffer. */
854    struct {
855        yaml_char_t *buffer;
856        size_t pointer;
857        size_t capacity;
858    } input;
859
860    /* The number of unread characters in the buffer. */
861    size_t unread;
862
863    /* The raw buffer. */
864    struct {
865        unsigned char *buffer;
866        size_t pointer;
867        size_t capacity;
868    } raw_input;
869
870    /* The input encoding. */
871    yaml_encoding_t encoding;
872
873    /* The offset of the current position (in bytes). */
874    size_t offset;
875
876    /* The mark of the current position. */
877    yaml_mark_t mark;
878
879    /*
880     * Scanner stuff.
881     */
882
883    /* Have we started to scan the input stream? */
884    int is_stream_start_produced;
885
886    /* Have we reached the end of the input stream? */
887    int is_stream_end_produced;
888
889    /* The number of unclosed '[' and '{' indicators. */
890    int flow_level;
891
892    /* The tokens queue. */
893    struct {
894        yaml_token_t *list;
895        size_t head;
896        size_t tail;
897        size_t capacity;
898    } tokens;
899
900    /* The number of tokens fetched from the queue. */
901    size_t tokens_parsed;
902
903    /* Does the tokens queue contain a token ready for dequeueing. */
904    int is_token_available;
905
906    /* The indentation levels stack. */
907    struct {
908        int *list;
909        size_t length;
910        size_t capacity;
911    } indents;
912
913    /* The current indentation level. */
914    int indent;
915
916    /* May a simple key occur at the current position? */
917    int is_simple_key_allowed;
918
919    /* The stack of simple keys. */
920    struct {
921        yaml_simple_key_t *list;
922        size_t length;
923        size_t capacity;
924    } simple_keys;
925
926    /*
927     * Parser stuff.
928     */
929
930    /* The parser states stack. */
931    struct {
932        yaml_parser_state_t *list;
933        size_t length;
934        size_t capacity;
935    } states;
936
937    /* The current parser state. */
938    yaml_parser_state_t state;
939
940    /* The stack of marks. */
941    struct {
942        yaml_mark_t *list;
943        size_t length;
944        size_t capacity;
945    } marks;
946
947    /* The list of TAG directives. */
948    struct {
949        yaml_tag_directive_t *list;
950        size_t length;
951        size_t capacity;
952    } tag_directives;
953
954    /*
955     * Dumper stuff.
956     */
957
958    /* The resolve handler. */
959    yaml_resolver_t *resolver;
960
961    /* The application data to be passed to the resolver. */
962    void *resolver_data;
963
964    /* The alias data. */
965    struct {
966        yaml_alias_data_t *list;
967        size_t length;
968        size_t capacity;
969    } aliases;
970
971    /* The currently parsed document. */
972    yaml_document_t *document;
973
974};
975
976/*
977 * The emitter states.
978 */
979
980typedef enum yaml_emitter_state_e {
981    /** Expect STREAM-START. */
982    YAML_EMIT_STREAM_START_STATE,
983    /** Expect the first DOCUMENT-START or STREAM-END. */
984    YAML_EMIT_FIRST_DOCUMENT_START_STATE,
985    /** Expect DOCUMENT-START or STREAM-END. */
986    YAML_EMIT_DOCUMENT_START_STATE,
987    /** Expect the content of a document. */
988    YAML_EMIT_DOCUMENT_CONTENT_STATE,
989    /** Expect DOCUMENT-END. */
990    YAML_EMIT_DOCUMENT_END_STATE,
991    /** Expect the first item of a flow sequence. */
992    YAML_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE,
993    /** Expect an item of a flow sequence. */
994    YAML_EMIT_FLOW_SEQUENCE_ITEM_STATE,
995    /** Expect the first key of a flow mapping. */
996    YAML_EMIT_FLOW_MAPPING_FIRST_KEY_STATE,
997    /** Expect a key of a flow mapping. */
998    YAML_EMIT_FLOW_MAPPING_KEY_STATE,
999    /** Expect a value for a simple key of a flow mapping. */
1000    YAML_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE,
1001    /** Expect a value of a flow mapping. */
1002    YAML_EMIT_FLOW_MAPPING_VALUE_STATE,
1003    /** Expect the first item of a block sequence. */
1004    YAML_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE,
1005    /** Expect an item of a block sequence. */
1006    YAML_EMIT_BLOCK_SEQUENCE_ITEM_STATE,
1007    /** Expect the first key of a block mapping. */
1008    YAML_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE,
1009    /** Expect the key of a block mapping. */
1010    YAML_EMIT_BLOCK_MAPPING_KEY_STATE,
1011    /** Expect a value for a simple key of a block mapping. */
1012    YAML_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE,
1013    /** Expect a value of a block mapping. */
1014    YAML_EMIT_BLOCK_MAPPING_VALUE_STATE,
1015    /** Expect nothing. */
1016    YAML_EMIT_END_STATE
1017} yaml_emitter_state_t;
1018
1019/*
1020 * The structure that holds data used by the file and string readers.
1021 */
1022
1023typedef union yaml_standard_writer_data_u {
1024    /* String output data. */
1025    yaml_string_t string;
1026    size_t *length;
1027    /* File output data. */
1028    FILE *file;
1029} yaml_standard_writer_data_t;
1030
1031/*
1032 * The internals emitter structure.
1033 */
1034
1035struct yaml_emitter_s {
1036
1037    /*
1038     * Error stuff.
1039     */
1040
1041    yaml_error_t error;
1042
1043    /*
1044     * Writer stuff.
1045     */
1046
1047    /* Write handler. */
1048    yaml_writer_t *writer;
1049
1050    /* A pointer for passing to the white handler. */
1051    void *writer_data;
1052
1053    /* Standard (string or file) output data. */
1054    yaml_standard_writer_data_t standard_writer_data;
1055
1056    /* The working buffer. */
1057    struct {
1058        yaml_char_t *buffer;
1059        size_t pointer;
1060        size_t capacity;
1061    } output;
1062
1063    /* The raw buffer. */
1064    struct {
1065        yaml_char_t *buffer;
1066        size_t pointer;
1067        size_t capacity;
1068    } raw_output;
1069
1070    /* The offset of the current position (in bytes). */
1071    size_t offset;
1072
1073    /* The stream encoding. */
1074    yaml_encoding_t encoding;
1075
1076    /*
1077     * Emitter stuff.
1078     */
1079
1080    /* If the output is in the canonical style? */
1081    int is_canonical;
1082    /* The number of indentation spaces. */
1083    int best_indent;
1084    /* The preferred width of the output lines. */
1085    int best_width;
1086    /* Allow unescaped non-ASCII characters? */
1087    int is_unicode;
1088    /* The preferred line break. */
1089    yaml_break_t line_break;
1090
1091    /* The stack of states. */
1092    struct {
1093        yaml_emitter_state_t *list;
1094        size_t length;
1095        size_t capacity;
1096    } states;
1097
1098    /* The current emitter state. */
1099    yaml_emitter_state_t state;
1100
1101    /* The event queue. */
1102    struct {
1103        yaml_event_t *list;
1104        size_t head;
1105        size_t tail;
1106        size_t capacity;
1107    } events;
1108
1109    /* The stack of indentation levels. */
1110    struct {
1111        int *list;
1112        size_t length;
1113        size_t capacity;
1114    } indents;
1115
1116    /* The list of tag directives. */
1117    struct {
1118        yaml_tag_directive_t *list;
1119        size_t length;
1120        size_t capacity;
1121    } tag_directives;
1122
1123    /* The current indentation level. */
1124    int indent;
1125
1126    /* The current flow level. */
1127    int flow_level;
1128
1129    /* Is it the document root context? */
1130    int is_root_context;
1131    /* Is it a sequence context? */
1132    int is_sequence_context;
1133    /* Is it a mapping context? */
1134    int is_mapping_context;
1135    /* Is it a simple mapping key context? */
1136    int is_simple_key_context;
1137
1138    /* The current line. */
1139    int line;
1140    /* The current column. */
1141    int column;
1142    /* If the last character was a whitespace? */
1143    int is_whitespace;
1144    /* If the last character was an indentation character (' ', '-', '?', ':')? */
1145    int is_indention;
1146
1147    /* Anchor analysis. */
1148    struct {
1149        /* The anchor value. */
1150        yaml_char_t *anchor;
1151        /* The anchor length. */
1152        size_t anchor_length;
1153        /* Is it an alias? */
1154        int is_alias;
1155    } anchor_data;
1156
1157    /* Tag analysis. */
1158    struct {
1159        /* The tag handle. */
1160        yaml_char_t *handle;
1161        /* The tag handle length. */
1162        size_t handle_length;
1163        /* The tag suffix. */
1164        yaml_char_t *suffix;
1165        /* The tag suffix length. */
1166        size_t suffix_length;
1167    } tag_data;
1168
1169    /* Scalar analysis. */
1170    struct {
1171        /* The scalar value. */
1172        yaml_char_t *value;
1173        /* The scalar length. */
1174        size_t length;
1175        /* Does the scalar contain line breaks? */
1176        int is_multiline;
1177        /* Can the scalar be expessed in the flow plain style? */
1178        int is_flow_plain_allowed;
1179        /* Can the scalar be expressed in the block plain style? */
1180        int is_block_plain_allowed;
1181        /* Can the scalar be expressed in the single quoted style? */
1182        int is_single_quoted_allowed;
1183        /* Can the scalar be expressed in the literal or folded styles? */
1184        int is_block_allowed;
1185        /* The output style. */
1186        yaml_scalar_style_t style;
1187    } scalar_data;
1188
1189    /*
1190     * Dumper stuff.
1191     */
1192
1193    /* If the stream was already opened? */
1194    int is_opened;
1195    /* If the stream was already closed? */
1196    int is_closed;
1197
1198    /* The information associated with the document nodes. */
1199    struct {
1200        /* The number of references. */
1201        size_t references;
1202        /* The anchor id. */
1203        int anchor;
1204        /* If the node has been emitted? */
1205        int is_serialized;
1206    } *anchors;
1207
1208    /* The last assigned anchor id. */
1209    int last_anchor_id;
1210
1211    /* The currently emitted document. */
1212    yaml_document_t *document;
1213
1214};
1215
1216/*
1217 * Reader: Ensure that the buffer contains at least `length` characters.
1218 */
1219
1220YAML_DECLARE(int)
1221yaml_parser_update_buffer(yaml_parser_t *parser, size_t length);
1222
1223/*
1224 * Scanner: Ensure that the token stack contains at least one token ready.
1225 */
1226
1227YAML_DECLARE(int)
1228yaml_parser_fetch_more_tokens(yaml_parser_t *parser);
1229
Note: See TracBrowser for help on using the repository browser.