source: trunk/packages/libyaml/src/loader.c @ 1837

Last change on this file since 1837 was 898, checked in by hartmans, 16 years ago

Add pyyaml and libyaml packages
backported from lenny.
There is discussion about how these should go in the repository; these are added in this form
in order to make forward progress.

File size: 11.1 KB
Line 
1
2#include "yaml_private.h"
3
4/*
5 * API functions.
6 */
7
8YAML_DECLARE(int)
9yaml_parser_load(yaml_parser_t *parser, yaml_document_t *document);
10
11/*
12 * Error handling.
13 */
14
15static int
16yaml_parser_set_composer_error(yaml_parser_t *parser,
17        const char *problem, yaml_mark_t problem_mark);
18
19static int
20yaml_parser_set_composer_error_context(yaml_parser_t *parser,
21        const char *context, yaml_mark_t context_mark,
22        const char *problem, yaml_mark_t problem_mark);
23
24
25/*
26 * Alias handling.
27 */
28
29static int
30yaml_parser_register_anchor(yaml_parser_t *parser,
31        int index, yaml_char_t *anchor);
32
33/*
34 * Clean up functions.
35 */
36
37static void
38yaml_parser_delete_aliases(yaml_parser_t *parser);
39
40/*
41 * Composer functions.
42 */
43
44static int
45yaml_parser_load_document(yaml_parser_t *parser, yaml_event_t *first_event);
46
47static int
48yaml_parser_load_node(yaml_parser_t *parser, yaml_event_t *first_event);
49
50static int
51yaml_parser_load_alias(yaml_parser_t *parser, yaml_event_t *first_event);
52
53static int
54yaml_parser_load_scalar(yaml_parser_t *parser, yaml_event_t *first_event);
55
56static int
57yaml_parser_load_sequence(yaml_parser_t *parser, yaml_event_t *first_event);
58
59static int
60yaml_parser_load_mapping(yaml_parser_t *parser, yaml_event_t *first_event);
61
62/*
63 * Load the next document of the stream.
64 */
65
66YAML_DECLARE(int)
67yaml_parser_load(yaml_parser_t *parser, yaml_document_t *document)
68{
69    yaml_event_t event;
70
71    assert(parser);     /* Non-NULL parser object is expected. */
72    assert(document);   /* Non-NULL document object is expected. */
73
74    memset(document, 0, sizeof(yaml_document_t));
75    if (!STACK_INIT(parser, document->nodes, INITIAL_STACK_SIZE))
76        goto error;
77
78    if (!parser->stream_start_produced) {
79        if (!yaml_parser_parse(parser, &event)) goto error;
80        assert(event.type == YAML_STREAM_START_EVENT);
81                        /* STREAM-START is expected. */
82    }
83
84    if (parser->stream_end_produced) {
85        return 1;
86    }
87
88    if (!yaml_parser_parse(parser, &event)) goto error;
89    if (event.type == YAML_STREAM_END_EVENT) {
90        return 1;
91    }
92
93    if (!STACK_INIT(parser, parser->aliases, INITIAL_STACK_SIZE))
94        goto error;
95
96    parser->document = document;
97
98    if (!yaml_parser_load_document(parser, &event)) goto error;
99
100    yaml_parser_delete_aliases(parser);
101    parser->document = NULL;
102
103    return 1;
104
105error:
106
107    yaml_parser_delete_aliases(parser);
108    yaml_document_delete(document);
109    parser->document = NULL;
110
111    return 0;
112}
113
114/*
115 * Set composer error.
116 */
117
118static int
119yaml_parser_set_composer_error(yaml_parser_t *parser,
120        const char *problem, yaml_mark_t problem_mark)
121{
122    parser->error = YAML_COMPOSER_ERROR;
123    parser->problem = problem;
124    parser->problem_mark = problem_mark;
125
126    return 0;
127}
128
129/*
130 * Set composer error with context.
131 */
132
133static int
134yaml_parser_set_composer_error_context(yaml_parser_t *parser,
135        const char *context, yaml_mark_t context_mark,
136        const char *problem, yaml_mark_t problem_mark)
137{
138    parser->error = YAML_COMPOSER_ERROR;
139    parser->context = context;
140    parser->context_mark = context_mark;
141    parser->problem = problem;
142    parser->problem_mark = problem_mark;
143
144    return 0;
145}
146
147/*
148 * Delete the stack of aliases.
149 */
150
151static void
152yaml_parser_delete_aliases(yaml_parser_t *parser)
153{
154    while (!STACK_EMPTY(parser, parser->aliases)) {
155        yaml_free(POP(parser, parser->aliases).anchor);
156    }
157    STACK_DEL(parser, parser->aliases);
158}
159
160/*
161 * Compose a document object.
162 */
163
164static int
165yaml_parser_load_document(yaml_parser_t *parser, yaml_event_t *first_event)
166{
167    yaml_event_t event;
168
169    assert(first_event->type == YAML_DOCUMENT_START_EVENT);
170                        /* DOCUMENT-START is expected. */
171
172    parser->document->version_directive
173        = first_event->data.document_start.version_directive;
174    parser->document->tag_directives.start
175        = first_event->data.document_start.tag_directives.start;
176    parser->document->tag_directives.end
177        = first_event->data.document_start.tag_directives.end;
178    parser->document->start_implicit
179        = first_event->data.document_start.implicit;
180    parser->document->start_mark = first_event->start_mark;
181
182    if (!yaml_parser_parse(parser, &event)) return 0;
183
184    if (!yaml_parser_load_node(parser, &event)) return 0;
185
186    if (!yaml_parser_parse(parser, &event)) return 0;
187    assert(event.type == YAML_DOCUMENT_END_EVENT);
188                        /* DOCUMENT-END is expected. */
189
190    parser->document->end_implicit = event.data.document_end.implicit;
191    parser->document->end_mark = event.end_mark;
192
193    return 1;
194}
195
196/*
197 * Compose a node.
198 */
199
200static int
201yaml_parser_load_node(yaml_parser_t *parser, yaml_event_t *first_event)
202{
203    switch (first_event->type) {
204        case YAML_ALIAS_EVENT:
205            return yaml_parser_load_alias(parser, first_event);
206        case YAML_SCALAR_EVENT:
207            return yaml_parser_load_scalar(parser, first_event);
208        case YAML_SEQUENCE_START_EVENT:
209            return yaml_parser_load_sequence(parser, first_event);
210        case YAML_MAPPING_START_EVENT:
211            return yaml_parser_load_mapping(parser, first_event);
212        default:
213            assert(0);  /* Could not happen. */
214            return 0;
215    }
216
217    return 0;
218}
219
220/*
221 * Add an anchor.
222 */
223
224static int
225yaml_parser_register_anchor(yaml_parser_t *parser,
226        int index, yaml_char_t *anchor)
227{
228    yaml_alias_data_t data = { anchor, index, { 0, 0, 0 } };
229    yaml_alias_data_t *alias_data;
230
231    if (!anchor) return 1;
232
233    data.mark = parser->document->nodes.start[index-1].start_mark;
234
235    for (alias_data = parser->aliases.start;
236            alias_data != parser->aliases.top; alias_data ++) {
237        if (strcmp((char *)alias_data->anchor, (char *)anchor) == 0) {
238            yaml_free(anchor);
239            return yaml_parser_set_composer_error_context(parser,
240                    "found duplicate anchor; first occurence",
241                    alias_data->mark, "second occurence", data.mark);
242        }
243    }
244
245    if (!PUSH(parser, parser->aliases, data)) {
246        yaml_free(anchor);
247        return 0;
248    }
249
250    return 1;
251}
252
253/*
254 * Compose a node corresponding to an alias.
255 */
256
257static int
258yaml_parser_load_alias(yaml_parser_t *parser, yaml_event_t *first_event)
259{
260    yaml_char_t *anchor = first_event->data.alias.anchor;
261    yaml_alias_data_t *alias_data;
262
263    for (alias_data = parser->aliases.start;
264            alias_data != parser->aliases.top; alias_data ++) {
265        if (strcmp((char *)alias_data->anchor, (char *)anchor) == 0) {
266            yaml_free(anchor);
267            return alias_data->index;
268        }
269    }
270
271    yaml_free(anchor);
272    return yaml_parser_set_composer_error(parser, "found undefined alias",
273            first_event->start_mark);
274}
275
276/*
277 * Compose a scalar node.
278 */
279
280static int
281yaml_parser_load_scalar(yaml_parser_t *parser, yaml_event_t *first_event)
282{
283    yaml_node_t node;
284    int index;
285    yaml_char_t *tag = first_event->data.scalar.tag;
286
287    if (!tag || strcmp((char *)tag, "!") == 0) {
288        yaml_free(tag);
289        tag = yaml_strdup((yaml_char_t *)YAML_DEFAULT_SCALAR_TAG);
290        if (!tag) goto error;
291    }
292
293    SCALAR_NODE_INIT(node, tag, first_event->data.scalar.value,
294            first_event->data.scalar.length, first_event->data.scalar.style,
295            first_event->start_mark, first_event->end_mark);
296
297    if (!PUSH(parser, parser->document->nodes, node)) goto error;
298
299    index = parser->document->nodes.top - parser->document->nodes.start;
300
301    if (!yaml_parser_register_anchor(parser, index,
302                first_event->data.scalar.anchor)) return 0;
303
304    return index;
305
306error:
307    yaml_free(tag);
308    yaml_free(first_event->data.scalar.anchor);
309    yaml_free(first_event->data.scalar.value);
310    return 0;
311}
312
313/*
314 * Compose a sequence node.
315 */
316
317static int
318yaml_parser_load_sequence(yaml_parser_t *parser, yaml_event_t *first_event)
319{
320    yaml_event_t event;
321    yaml_node_t node;
322    struct {
323        yaml_node_item_t *start;
324        yaml_node_item_t *end;
325        yaml_node_item_t *top;
326    } items = { NULL, NULL, NULL };
327    int index, item_index;
328    yaml_char_t *tag = first_event->data.sequence_start.tag;
329
330    if (!tag || strcmp((char *)tag, "!") == 0) {
331        yaml_free(tag);
332        tag = yaml_strdup((yaml_char_t *)YAML_DEFAULT_SEQUENCE_TAG);
333        if (!tag) goto error;
334    }
335
336    if (!STACK_INIT(parser, items, INITIAL_STACK_SIZE)) goto error;
337
338    SEQUENCE_NODE_INIT(node, tag, items.start, items.end,
339            first_event->data.sequence_start.style,
340            first_event->start_mark, first_event->end_mark);
341
342    if (!PUSH(parser, parser->document->nodes, node)) goto error;
343
344    index = parser->document->nodes.top - parser->document->nodes.start;
345
346    if (!yaml_parser_register_anchor(parser, index,
347                first_event->data.sequence_start.anchor)) return 0;
348
349    if (!yaml_parser_parse(parser, &event)) return 0;
350
351    while (event.type != YAML_SEQUENCE_END_EVENT) {
352        item_index = yaml_parser_load_node(parser, &event);
353        if (!item_index) return 0;
354        if (!PUSH(parser,
355                    parser->document->nodes.start[index-1].data.sequence.items,
356                    item_index)) return 0;
357        if (!yaml_parser_parse(parser, &event)) return 0;
358    }
359
360    parser->document->nodes.start[index-1].end_mark = event.end_mark;
361
362    return index;
363
364error:
365    yaml_free(tag);
366    yaml_free(first_event->data.sequence_start.anchor);
367    return 0;
368}
369
370/*
371 * Compose a mapping node.
372 */
373
374static int
375yaml_parser_load_mapping(yaml_parser_t *parser, yaml_event_t *first_event)
376{
377    yaml_event_t event;
378    yaml_node_t node;
379    struct {
380        yaml_node_pair_t *start;
381        yaml_node_pair_t *end;
382        yaml_node_pair_t *top;
383    } pairs = { NULL, NULL, NULL };
384    int index;
385    yaml_node_pair_t pair;
386    yaml_char_t *tag = first_event->data.mapping_start.tag;
387
388    if (!tag || strcmp((char *)tag, "!") == 0) {
389        yaml_free(tag);
390        tag = yaml_strdup((yaml_char_t *)YAML_DEFAULT_MAPPING_TAG);
391        if (!tag) goto error;
392    }
393
394    if (!STACK_INIT(parser, pairs, INITIAL_STACK_SIZE)) goto error;
395
396    MAPPING_NODE_INIT(node, tag, pairs.start, pairs.end,
397            first_event->data.mapping_start.style,
398            first_event->start_mark, first_event->end_mark);
399
400    if (!PUSH(parser, parser->document->nodes, node)) goto error;
401
402    index = parser->document->nodes.top - parser->document->nodes.start;
403
404    if (!yaml_parser_register_anchor(parser, index,
405                first_event->data.mapping_start.anchor)) return 0;
406
407    if (!yaml_parser_parse(parser, &event)) return 0;
408
409    while (event.type != YAML_MAPPING_END_EVENT) {
410        pair.key = yaml_parser_load_node(parser, &event);
411        if (!pair.key) return 0;
412        if (!yaml_parser_parse(parser, &event)) return 0;
413        pair.value = yaml_parser_load_node(parser, &event);
414        if (!pair.value) return 0;
415        if (!PUSH(parser,
416                    parser->document->nodes.start[index-1].data.mapping.pairs,
417                    pair)) return 0;
418        if (!yaml_parser_parse(parser, &event)) return 0;
419    }
420
421    parser->document->nodes.start[index-1].end_mark = event.end_mark;
422
423    return index;
424
425error:
426    yaml_free(tag);
427    yaml_free(first_event->data.mapping_start.anchor);
428    return 0;
429}
430
Note: See TracBrowser for help on using the repository browser.