]>
Commit | Line | Data |
---|---|---|
a51447c9 | 1 | |
625fcfe9 | 2 | #include "yaml_private.h" |
a51447c9 | 3 | |
625fcfe9 KS |
4 | /* |
5 | * Get the library version. | |
6 | */ | |
95b98ba9 | 7 | |
5eff53a4 KS |
8 | YAML_DECLARE(const char *) |
9 | yaml_get_version_string(void) | |
10 | { | |
11 | return YAML_VERSION_STRING; | |
12 | } | |
13 | ||
625fcfe9 KS |
14 | /* |
15 | * Get the library version numbers. | |
16 | */ | |
17 | ||
5eff53a4 KS |
18 | YAML_DECLARE(void) |
19 | yaml_get_version(int *major, int *minor, int *patch) | |
20 | { | |
21 | *major = YAML_VERSION_MAJOR; | |
22 | *minor = YAML_VERSION_MINOR; | |
23 | *patch = YAML_VERSION_PATCH; | |
24 | } | |
25 | ||
95b98ba9 KS |
26 | /* |
27 | * Allocate a dynamic memory block. | |
28 | */ | |
29 | ||
f642fd11 | 30 | YAML_DECLARE(void *) |
95b98ba9 KS |
31 | yaml_malloc(size_t size) |
32 | { | |
33 | return malloc(size ? size : 1); | |
34 | } | |
35 | ||
36 | /* | |
37 | * Reallocate a dynamic memory block. | |
38 | */ | |
39 | ||
f642fd11 | 40 | YAML_DECLARE(void *) |
95b98ba9 KS |
41 | yaml_realloc(void *ptr, size_t size) |
42 | { | |
43 | return ptr ? realloc(ptr, size ? size : 1) : malloc(size ? size : 1); | |
44 | } | |
45 | ||
a51447c9 | 46 | /* |
95b98ba9 KS |
47 | * Free a dynamic memory block. |
48 | */ | |
49 | ||
f642fd11 | 50 | YAML_DECLARE(void) |
95b98ba9 KS |
51 | yaml_free(void *ptr) |
52 | { | |
53 | if (ptr) free(ptr); | |
54 | } | |
55 | ||
56 | /* | |
625fcfe9 | 57 | * Duplicate a string. |
a51447c9 KS |
58 | */ |
59 | ||
cf616166 KS |
60 | YAML_DECLARE(yaml_char_t *) |
61 | yaml_strdup(const yaml_char_t *str) | |
a51447c9 | 62 | { |
cf616166 KS |
63 | if (!str) |
64 | return NULL; | |
65 | ||
66 | return (yaml_char_t *)strdup((char *)str); | |
625fcfe9 | 67 | } |
a51447c9 | 68 | |
625fcfe9 KS |
69 | /* |
70 | * Extend a string. | |
71 | */ | |
6eb1ded4 | 72 | |
625fcfe9 KS |
73 | YAML_DECLARE(int) |
74 | yaml_string_extend(yaml_char_t **start, | |
75 | yaml_char_t **pointer, yaml_char_t **end) | |
76 | { | |
fc2dd942 | 77 | yaml_char_t *new_start = (yaml_char_t *)yaml_realloc((void*)*start, (*end - *start)*2); |
f2b59d4d | 78 | |
625fcfe9 | 79 | if (!new_start) return 0; |
6eb1ded4 | 80 | |
625fcfe9 | 81 | memset(new_start + (*end - *start), 0, *end - *start); |
6eb1ded4 | 82 | |
625fcfe9 KS |
83 | *pointer = new_start + (*pointer - *start); |
84 | *end = new_start + (*end - *start)*2; | |
85 | *start = new_start; | |
f2b59d4d | 86 | |
625fcfe9 KS |
87 | return 1; |
88 | } | |
6eb1ded4 | 89 | |
625fcfe9 KS |
90 | /* |
91 | * Append a string B to a string A. | |
92 | */ | |
f2b59d4d | 93 | |
625fcfe9 KS |
94 | YAML_DECLARE(int) |
95 | yaml_string_join( | |
96 | yaml_char_t **a_start, yaml_char_t **a_pointer, yaml_char_t **a_end, | |
fc2dd942 | 97 | yaml_char_t **b_start, yaml_char_t **b_pointer, SHIM(yaml_char_t **b_end)) |
625fcfe9 | 98 | { |
fc2dd942 | 99 | UNUSED_PARAM(b_end) |
625fcfe9 KS |
100 | if (*b_start == *b_pointer) |
101 | return 1; | |
f2b59d4d | 102 | |
625fcfe9 KS |
103 | while (*a_end - *a_pointer <= *b_pointer - *b_start) { |
104 | if (!yaml_string_extend(a_start, a_pointer, a_end)) | |
105 | return 0; | |
106 | } | |
f2b59d4d | 107 | |
625fcfe9 KS |
108 | memcpy(*a_pointer, *b_start, *b_pointer - *b_start); |
109 | *a_pointer += *b_pointer - *b_start; | |
f2b59d4d | 110 | |
625fcfe9 KS |
111 | return 1; |
112 | } | |
f2b59d4d | 113 | |
625fcfe9 KS |
114 | /* |
115 | * Extend a stack. | |
116 | */ | |
f2b59d4d | 117 | |
625fcfe9 KS |
118 | YAML_DECLARE(int) |
119 | yaml_stack_extend(void **start, void **top, void **end) | |
120 | { | |
96a49a1d FW |
121 | void *new_start; |
122 | ||
123 | if ((char *)*end - (char *)*start >= INT_MAX / 2) | |
124 | return 0; | |
125 | ||
126 | new_start = yaml_realloc(*start, ((char *)*end - (char *)*start)*2); | |
f2b59d4d | 127 | |
625fcfe9 | 128 | if (!new_start) return 0; |
f2b59d4d | 129 | |
0174ed6e KS |
130 | *top = (char *)new_start + ((char *)*top - (char *)*start); |
131 | *end = (char *)new_start + ((char *)*end - (char *)*start)*2; | |
625fcfe9 | 132 | *start = new_start; |
f2b59d4d | 133 | |
625fcfe9 KS |
134 | return 1; |
135 | } | |
1eb01be7 | 136 | |
625fcfe9 KS |
137 | /* |
138 | * Extend or move a queue. | |
139 | */ | |
1eb01be7 | 140 | |
625fcfe9 KS |
141 | YAML_DECLARE(int) |
142 | yaml_queue_extend(void **start, void **head, void **tail, void **end) | |
143 | { | |
144 | /* Check if we need to resize the queue. */ | |
1eb01be7 | 145 | |
625fcfe9 | 146 | if (*start == *head && *tail == *end) { |
0174ed6e KS |
147 | void *new_start = yaml_realloc(*start, |
148 | ((char *)*end - (char *)*start)*2); | |
1eb01be7 | 149 | |
625fcfe9 | 150 | if (!new_start) return 0; |
1eb01be7 | 151 | |
0174ed6e KS |
152 | *head = (char *)new_start + ((char *)*head - (char *)*start); |
153 | *tail = (char *)new_start + ((char *)*tail - (char *)*start); | |
154 | *end = (char *)new_start + ((char *)*end - (char *)*start)*2; | |
625fcfe9 KS |
155 | *start = new_start; |
156 | } | |
ab01bac8 | 157 | |
625fcfe9 | 158 | /* Check if we need to move the queue at the beginning of the buffer. */ |
ab01bac8 | 159 | |
625fcfe9 KS |
160 | if (*tail == *end) { |
161 | if (*head != *tail) { | |
0174ed6e | 162 | memmove(*start, *head, (char *)*tail - (char *)*head); |
625fcfe9 | 163 | } |
0174ed6e | 164 | *tail = (char *)*tail - (char *)*head + (char *)*start; |
625fcfe9 KS |
165 | *head = *start; |
166 | } | |
ab01bac8 | 167 | |
625fcfe9 KS |
168 | return 1; |
169 | } | |
1eb01be7 | 170 | |
1eb01be7 | 171 | |
625fcfe9 KS |
172 | /* |
173 | * Create a new parser object. | |
174 | */ | |
1eb01be7 | 175 | |
625fcfe9 KS |
176 | YAML_DECLARE(int) |
177 | yaml_parser_initialize(yaml_parser_t *parser) | |
178 | { | |
179 | assert(parser); /* Non-NULL parser object expected. */ | |
f2b59d4d | 180 | |
625fcfe9 | 181 | memset(parser, 0, sizeof(yaml_parser_t)); |
b1a54000 | 182 | if (!BUFFER_INIT(parser, parser->raw_buffer, INPUT_RAW_BUFFER_SIZE)) |
625fcfe9 | 183 | goto error; |
b1a54000 | 184 | if (!BUFFER_INIT(parser, parser->buffer, INPUT_BUFFER_SIZE)) |
625fcfe9 | 185 | goto error; |
fc2dd942 | 186 | if (!QUEUE_INIT(parser, parser->tokens, INITIAL_QUEUE_SIZE, yaml_token_t*)) |
625fcfe9 | 187 | goto error; |
fc2dd942 | 188 | if (!STACK_INIT(parser, parser->indents, int*)) |
625fcfe9 | 189 | goto error; |
fc2dd942 | 190 | if (!STACK_INIT(parser, parser->simple_keys, yaml_simple_key_t*)) |
625fcfe9 | 191 | goto error; |
fc2dd942 | 192 | if (!STACK_INIT(parser, parser->states, yaml_parser_state_t*)) |
625fcfe9 | 193 | goto error; |
fc2dd942 | 194 | if (!STACK_INIT(parser, parser->marks, yaml_mark_t*)) |
625fcfe9 | 195 | goto error; |
fc2dd942 | 196 | if (!STACK_INIT(parser, parser->tag_directives, yaml_tag_directive_t*)) |
625fcfe9 | 197 | goto error; |
f2b59d4d | 198 | |
625fcfe9 | 199 | return 1; |
f2b59d4d KS |
200 | |
201 | error: | |
202 | ||
625fcfe9 KS |
203 | BUFFER_DEL(parser, parser->raw_buffer); |
204 | BUFFER_DEL(parser, parser->buffer); | |
205 | QUEUE_DEL(parser, parser->tokens); | |
206 | STACK_DEL(parser, parser->indents); | |
207 | STACK_DEL(parser, parser->simple_keys); | |
208 | STACK_DEL(parser, parser->states); | |
209 | STACK_DEL(parser, parser->marks); | |
210 | STACK_DEL(parser, parser->tag_directives); | |
f2b59d4d | 211 | |
625fcfe9 | 212 | return 0; |
a51447c9 KS |
213 | } |
214 | ||
215 | /* | |
216 | * Destroy a parser object. | |
217 | */ | |
218 | ||
f642fd11 | 219 | YAML_DECLARE(void) |
a51447c9 KS |
220 | yaml_parser_delete(yaml_parser_t *parser) |
221 | { | |
95b98ba9 KS |
222 | assert(parser); /* Non-NULL parser object expected. */ |
223 | ||
625fcfe9 KS |
224 | BUFFER_DEL(parser, parser->raw_buffer); |
225 | BUFFER_DEL(parser, parser->buffer); | |
226 | while (!QUEUE_EMPTY(parser, parser->tokens)) { | |
227 | yaml_token_delete(&DEQUEUE(parser, parser->tokens)); | |
228 | } | |
229 | QUEUE_DEL(parser, parser->tokens); | |
230 | STACK_DEL(parser, parser->indents); | |
231 | STACK_DEL(parser, parser->simple_keys); | |
232 | STACK_DEL(parser, parser->states); | |
233 | STACK_DEL(parser, parser->marks); | |
234 | while (!STACK_EMPTY(parser, parser->tag_directives)) { | |
235 | yaml_tag_directive_t tag_directive = POP(parser, parser->tag_directives); | |
236 | yaml_free(tag_directive.handle); | |
237 | yaml_free(tag_directive.prefix); | |
238 | } | |
239 | STACK_DEL(parser, parser->tag_directives); | |
95b98ba9 KS |
240 | |
241 | memset(parser, 0, sizeof(yaml_parser_t)); | |
95b98ba9 KS |
242 | } |
243 | ||
244 | /* | |
6eb1ded4 | 245 | * String read handler. |
95b98ba9 KS |
246 | */ |
247 | ||
248 | static int | |
249 | yaml_string_read_handler(void *data, unsigned char *buffer, size_t size, | |
250 | size_t *size_read) | |
251 | { | |
fc2dd942 | 252 | yaml_parser_t *parser = (yaml_parser_t *)data; |
6eb1ded4 | 253 | |
625fcfe9 | 254 | if (parser->input.string.current == parser->input.string.end) { |
6eb1ded4 KS |
255 | *size_read = 0; |
256 | return 1; | |
257 | } | |
258 | ||
0174ed6e KS |
259 | if (size > (size_t)(parser->input.string.end |
260 | - parser->input.string.current)) { | |
625fcfe9 | 261 | size = parser->input.string.end - parser->input.string.current; |
6eb1ded4 KS |
262 | } |
263 | ||
625fcfe9 KS |
264 | memcpy(buffer, parser->input.string.current, size); |
265 | parser->input.string.current += size; | |
6eb1ded4 | 266 | *size_read = size; |
95b98ba9 KS |
267 | return 1; |
268 | } | |
269 | ||
270 | /* | |
271 | * File read handler. | |
272 | */ | |
273 | ||
274 | static int | |
275 | yaml_file_read_handler(void *data, unsigned char *buffer, size_t size, | |
276 | size_t *size_read) | |
277 | { | |
fc2dd942 | 278 | yaml_parser_t *parser = (yaml_parser_t *)data; |
625fcfe9 KS |
279 | |
280 | *size_read = fread(buffer, 1, size, parser->input.file); | |
281 | return !ferror(parser->input.file); | |
95b98ba9 KS |
282 | } |
283 | ||
284 | /* | |
285 | * Set a string input. | |
286 | */ | |
287 | ||
f642fd11 | 288 | YAML_DECLARE(void) |
95b98ba9 | 289 | yaml_parser_set_input_string(yaml_parser_t *parser, |
a907bf85 | 290 | const unsigned char *input, size_t size) |
95b98ba9 KS |
291 | { |
292 | assert(parser); /* Non-NULL parser object expected. */ | |
6eb1ded4 | 293 | assert(!parser->read_handler); /* You can set the source only once. */ |
95b98ba9 KS |
294 | assert(input); /* Non-NULL input string expected. */ |
295 | ||
6eb1ded4 | 296 | parser->read_handler = yaml_string_read_handler; |
625fcfe9 KS |
297 | parser->read_handler_data = parser; |
298 | ||
299 | parser->input.string.start = input; | |
300 | parser->input.string.current = input; | |
301 | parser->input.string.end = input+size; | |
95b98ba9 KS |
302 | } |
303 | ||
304 | /* | |
305 | * Set a file input. | |
306 | */ | |
307 | ||
f642fd11 | 308 | YAML_DECLARE(void) |
95b98ba9 KS |
309 | yaml_parser_set_input_file(yaml_parser_t *parser, FILE *file) |
310 | { | |
311 | assert(parser); /* Non-NULL parser object expected. */ | |
6eb1ded4 | 312 | assert(!parser->read_handler); /* You can set the source only once. */ |
95b98ba9 KS |
313 | assert(file); /* Non-NULL file object expected. */ |
314 | ||
315 | parser->read_handler = yaml_file_read_handler; | |
625fcfe9 KS |
316 | parser->read_handler_data = parser; |
317 | ||
318 | parser->input.file = file; | |
95b98ba9 KS |
319 | } |
320 | ||
321 | /* | |
322 | * Set a generic input. | |
323 | */ | |
324 | ||
f642fd11 | 325 | YAML_DECLARE(void) |
95b98ba9 KS |
326 | yaml_parser_set_input(yaml_parser_t *parser, |
327 | yaml_read_handler_t *handler, void *data) | |
328 | { | |
329 | assert(parser); /* Non-NULL parser object expected. */ | |
6eb1ded4 | 330 | assert(!parser->read_handler); /* You can set the source only once. */ |
95b98ba9 KS |
331 | assert(handler); /* Non-NULL read handler expected. */ |
332 | ||
333 | parser->read_handler = handler; | |
6eb1ded4 | 334 | parser->read_handler_data = data; |
95b98ba9 KS |
335 | } |
336 | ||
337 | /* | |
338 | * Set the source encoding. | |
339 | */ | |
340 | ||
f642fd11 | 341 | YAML_DECLARE(void) |
95b98ba9 KS |
342 | yaml_parser_set_encoding(yaml_parser_t *parser, yaml_encoding_t encoding) |
343 | { | |
344 | assert(parser); /* Non-NULL parser object expected. */ | |
345 | assert(!parser->encoding); /* Encoding is already set or detected. */ | |
346 | ||
347 | parser->encoding = encoding; | |
a51447c9 KS |
348 | } |
349 | ||
b1a54000 KS |
350 | /* |
351 | * Create a new emitter object. | |
352 | */ | |
353 | ||
354 | YAML_DECLARE(int) | |
355 | yaml_emitter_initialize(yaml_emitter_t *emitter) | |
356 | { | |
357 | assert(emitter); /* Non-NULL emitter object expected. */ | |
358 | ||
359 | memset(emitter, 0, sizeof(yaml_emitter_t)); | |
360 | if (!BUFFER_INIT(emitter, emitter->buffer, OUTPUT_BUFFER_SIZE)) | |
361 | goto error; | |
362 | if (!BUFFER_INIT(emitter, emitter->raw_buffer, OUTPUT_RAW_BUFFER_SIZE)) | |
363 | goto error; | |
fc2dd942 | 364 | if (!STACK_INIT(emitter, emitter->states, yaml_emitter_state_t*)) |
b1a54000 | 365 | goto error; |
fc2dd942 | 366 | if (!QUEUE_INIT(emitter, emitter->events, INITIAL_QUEUE_SIZE, yaml_event_t*)) |
b1a54000 | 367 | goto error; |
fc2dd942 | 368 | if (!STACK_INIT(emitter, emitter->indents, int*)) |
b1a54000 | 369 | goto error; |
fc2dd942 | 370 | if (!STACK_INIT(emitter, emitter->tag_directives, yaml_tag_directive_t*)) |
b1a54000 KS |
371 | goto error; |
372 | ||
373 | return 1; | |
374 | ||
375 | error: | |
376 | ||
377 | BUFFER_DEL(emitter, emitter->buffer); | |
378 | BUFFER_DEL(emitter, emitter->raw_buffer); | |
379 | STACK_DEL(emitter, emitter->states); | |
380 | QUEUE_DEL(emitter, emitter->events); | |
381 | STACK_DEL(emitter, emitter->indents); | |
382 | STACK_DEL(emitter, emitter->tag_directives); | |
383 | ||
384 | return 0; | |
385 | } | |
386 | ||
387 | /* | |
388 | * Destroy an emitter object. | |
389 | */ | |
390 | ||
391 | YAML_DECLARE(void) | |
392 | yaml_emitter_delete(yaml_emitter_t *emitter) | |
393 | { | |
394 | assert(emitter); /* Non-NULL emitter object expected. */ | |
395 | ||
396 | BUFFER_DEL(emitter, emitter->buffer); | |
397 | BUFFER_DEL(emitter, emitter->raw_buffer); | |
398 | STACK_DEL(emitter, emitter->states); | |
399 | while (!QUEUE_EMPTY(emitter, emitter->events)) { | |
400 | yaml_event_delete(&DEQUEUE(emitter, emitter->events)); | |
401 | } | |
6d167281 | 402 | QUEUE_DEL(emitter, emitter->events); |
b1a54000 KS |
403 | STACK_DEL(emitter, emitter->indents); |
404 | while (!STACK_EMPTY(empty, emitter->tag_directives)) { | |
405 | yaml_tag_directive_t tag_directive = POP(emitter, emitter->tag_directives); | |
406 | yaml_free(tag_directive.handle); | |
407 | yaml_free(tag_directive.prefix); | |
408 | } | |
409 | STACK_DEL(emitter, emitter->tag_directives); | |
e27a3c88 | 410 | yaml_free(emitter->anchors); |
b1a54000 KS |
411 | |
412 | memset(emitter, 0, sizeof(yaml_emitter_t)); | |
413 | } | |
414 | ||
415 | /* | |
416 | * String write handler. | |
417 | */ | |
418 | ||
419 | static int | |
420 | yaml_string_write_handler(void *data, unsigned char *buffer, size_t size) | |
421 | { | |
fc2dd942 | 422 | yaml_emitter_t *emitter = (yaml_emitter_t *)data; |
b1a54000 | 423 | |
686b2d85 | 424 | if (emitter->output.string.size - *emitter->output.string.size_written |
b1a54000 KS |
425 | < size) { |
426 | memcpy(emitter->output.string.buffer | |
427 | + *emitter->output.string.size_written, | |
428 | buffer, | |
429 | emitter->output.string.size | |
430 | - *emitter->output.string.size_written); | |
431 | *emitter->output.string.size_written = emitter->output.string.size; | |
432 | return 0; | |
433 | } | |
434 | ||
435 | memcpy(emitter->output.string.buffer | |
436 | + *emitter->output.string.size_written, buffer, size); | |
437 | *emitter->output.string.size_written += size; | |
438 | return 1; | |
439 | } | |
440 | ||
441 | /* | |
442 | * File write handler. | |
443 | */ | |
444 | ||
445 | static int | |
446 | yaml_file_write_handler(void *data, unsigned char *buffer, size_t size) | |
447 | { | |
fc2dd942 | 448 | yaml_emitter_t *emitter = (yaml_emitter_t *)data; |
b1a54000 KS |
449 | |
450 | return (fwrite(buffer, 1, size, emitter->output.file) == size); | |
451 | } | |
452 | /* | |
453 | * Set a string output. | |
454 | */ | |
455 | ||
456 | YAML_DECLARE(void) | |
457 | yaml_emitter_set_output_string(yaml_emitter_t *emitter, | |
458 | unsigned char *output, size_t size, size_t *size_written) | |
459 | { | |
460 | assert(emitter); /* Non-NULL emitter object expected. */ | |
461 | assert(!emitter->write_handler); /* You can set the output only once. */ | |
462 | assert(output); /* Non-NULL output string expected. */ | |
463 | ||
464 | emitter->write_handler = yaml_string_write_handler; | |
465 | emitter->write_handler_data = emitter; | |
466 | ||
467 | emitter->output.string.buffer = output; | |
468 | emitter->output.string.size = size; | |
469 | emitter->output.string.size_written = size_written; | |
470 | *size_written = 0; | |
471 | } | |
472 | ||
473 | /* | |
474 | * Set a file output. | |
475 | */ | |
476 | ||
477 | YAML_DECLARE(void) | |
478 | yaml_emitter_set_output_file(yaml_emitter_t *emitter, FILE *file) | |
479 | { | |
480 | assert(emitter); /* Non-NULL emitter object expected. */ | |
481 | assert(!emitter->write_handler); /* You can set the output only once. */ | |
482 | assert(file); /* Non-NULL file object expected. */ | |
483 | ||
484 | emitter->write_handler = yaml_file_write_handler; | |
485 | emitter->write_handler_data = emitter; | |
486 | ||
487 | emitter->output.file = file; | |
488 | } | |
489 | ||
490 | /* | |
491 | * Set a generic output handler. | |
492 | */ | |
493 | ||
494 | YAML_DECLARE(void) | |
495 | yaml_emitter_set_output(yaml_emitter_t *emitter, | |
496 | yaml_write_handler_t *handler, void *data) | |
497 | { | |
498 | assert(emitter); /* Non-NULL emitter object expected. */ | |
499 | assert(!emitter->write_handler); /* You can set the output only once. */ | |
500 | assert(handler); /* Non-NULL handler object expected. */ | |
501 | ||
502 | emitter->write_handler = handler; | |
503 | emitter->write_handler_data = data; | |
504 | } | |
505 | ||
506 | /* | |
507 | * Set the output encoding. | |
508 | */ | |
509 | ||
510 | YAML_DECLARE(void) | |
511 | yaml_emitter_set_encoding(yaml_emitter_t *emitter, yaml_encoding_t encoding) | |
512 | { | |
513 | assert(emitter); /* Non-NULL emitter object expected. */ | |
514 | assert(!emitter->encoding); /* You can set encoding only once. */ | |
515 | ||
516 | emitter->encoding = encoding; | |
517 | } | |
518 | ||
519 | /* | |
520 | * Set the canonical output style. | |
521 | */ | |
522 | ||
523 | YAML_DECLARE(void) | |
524 | yaml_emitter_set_canonical(yaml_emitter_t *emitter, int canonical) | |
525 | { | |
526 | assert(emitter); /* Non-NULL emitter object expected. */ | |
527 | ||
528 | emitter->canonical = (canonical != 0); | |
529 | } | |
530 | ||
531 | /* | |
532 | * Set the indentation increment. | |
533 | */ | |
534 | ||
535 | YAML_DECLARE(void) | |
536 | yaml_emitter_set_indent(yaml_emitter_t *emitter, int indent) | |
537 | { | |
538 | assert(emitter); /* Non-NULL emitter object expected. */ | |
539 | ||
540 | emitter->best_indent = (1 < indent && indent < 10) ? indent : 2; | |
541 | } | |
542 | ||
543 | /* | |
544 | * Set the preferred line width. | |
545 | */ | |
546 | ||
547 | YAML_DECLARE(void) | |
548 | yaml_emitter_set_width(yaml_emitter_t *emitter, int width) | |
549 | { | |
550 | assert(emitter); /* Non-NULL emitter object expected. */ | |
551 | ||
cf616166 | 552 | emitter->best_width = (width >= 0) ? width : -1; |
b1a54000 KS |
553 | } |
554 | ||
555 | /* | |
556 | * Set if unescaped non-ASCII characters are allowed. | |
557 | */ | |
558 | ||
559 | YAML_DECLARE(void) | |
560 | yaml_emitter_set_unicode(yaml_emitter_t *emitter, int unicode) | |
561 | { | |
562 | assert(emitter); /* Non-NULL emitter object expected. */ | |
563 | ||
564 | emitter->unicode = (unicode != 0); | |
565 | } | |
566 | ||
567 | /* | |
568 | * Set the preferred line break character. | |
569 | */ | |
570 | ||
571 | YAML_DECLARE(void) | |
572 | yaml_emitter_set_break(yaml_emitter_t *emitter, yaml_break_t line_break) | |
573 | { | |
574 | assert(emitter); /* Non-NULL emitter object expected. */ | |
575 | ||
576 | emitter->line_break = line_break; | |
577 | } | |
578 | ||
f642fd11 KS |
579 | /* |
580 | * Destroy a token object. | |
581 | */ | |
582 | ||
583 | YAML_DECLARE(void) | |
584 | yaml_token_delete(yaml_token_t *token) | |
585 | { | |
586 | assert(token); /* Non-NULL token object expected. */ | |
587 | ||
588 | switch (token->type) | |
589 | { | |
590 | case YAML_TAG_DIRECTIVE_TOKEN: | |
591 | yaml_free(token->data.tag_directive.handle); | |
592 | yaml_free(token->data.tag_directive.prefix); | |
593 | break; | |
594 | ||
595 | case YAML_ALIAS_TOKEN: | |
26687d7d KS |
596 | yaml_free(token->data.alias.value); |
597 | break; | |
598 | ||
f642fd11 | 599 | case YAML_ANCHOR_TOKEN: |
26687d7d | 600 | yaml_free(token->data.anchor.value); |
f642fd11 KS |
601 | break; |
602 | ||
603 | case YAML_TAG_TOKEN: | |
604 | yaml_free(token->data.tag.handle); | |
605 | yaml_free(token->data.tag.suffix); | |
606 | break; | |
607 | ||
608 | case YAML_SCALAR_TOKEN: | |
609 | yaml_free(token->data.scalar.value); | |
610 | break; | |
54815ffd KS |
611 | |
612 | default: | |
613 | break; | |
f642fd11 KS |
614 | } |
615 | ||
616 | memset(token, 0, sizeof(yaml_token_t)); | |
26687d7d KS |
617 | } |
618 | ||
5a00d8fe KS |
619 | /* |
620 | * Check if a string is a valid UTF-8 sequence. | |
621 | * | |
622 | * Check 'reader.c' for more details on UTF-8 encoding. | |
623 | */ | |
624 | ||
625 | static int | |
626 | yaml_check_utf8(yaml_char_t *start, size_t length) | |
627 | { | |
628 | yaml_char_t *end = start+length; | |
629 | yaml_char_t *pointer = start; | |
630 | ||
631 | while (pointer < end) { | |
632 | unsigned char octet; | |
633 | unsigned int width; | |
634 | unsigned int value; | |
0174ed6e | 635 | size_t k; |
5a00d8fe KS |
636 | |
637 | octet = pointer[0]; | |
638 | width = (octet & 0x80) == 0x00 ? 1 : | |
639 | (octet & 0xE0) == 0xC0 ? 2 : | |
640 | (octet & 0xF0) == 0xE0 ? 3 : | |
641 | (octet & 0xF8) == 0xF0 ? 4 : 0; | |
784340c2 | 642 | value = (octet & 0x80) == 0x00 ? octet & 0x7F : |
5a00d8fe KS |
643 | (octet & 0xE0) == 0xC0 ? octet & 0x1F : |
644 | (octet & 0xF0) == 0xE0 ? octet & 0x0F : | |
645 | (octet & 0xF8) == 0xF0 ? octet & 0x07 : 0; | |
646 | if (!width) return 0; | |
647 | if (pointer+width > end) return 0; | |
648 | for (k = 1; k < width; k ++) { | |
649 | octet = pointer[k]; | |
650 | if ((octet & 0xC0) != 0x80) return 0; | |
651 | value = (value << 6) + (octet & 0x3F); | |
652 | } | |
653 | if (!((width == 1) || | |
654 | (width == 2 && value >= 0x80) || | |
655 | (width == 3 && value >= 0x800) || | |
656 | (width == 4 && value >= 0x10000))) return 0; | |
657 | ||
658 | pointer += width; | |
659 | } | |
660 | ||
661 | return 1; | |
662 | } | |
663 | ||
664 | /* | |
665 | * Create STREAM-START. | |
666 | */ | |
667 | ||
668 | YAML_DECLARE(int) | |
669 | yaml_stream_start_event_initialize(yaml_event_t *event, | |
670 | yaml_encoding_t encoding) | |
671 | { | |
672 | yaml_mark_t mark = { 0, 0, 0 }; | |
673 | ||
674 | assert(event); /* Non-NULL event object is expected. */ | |
675 | ||
676 | STREAM_START_EVENT_INIT(*event, encoding, mark, mark); | |
677 | ||
678 | return 1; | |
679 | } | |
680 | ||
681 | /* | |
682 | * Create STREAM-END. | |
683 | */ | |
684 | ||
685 | YAML_DECLARE(int) | |
686 | yaml_stream_end_event_initialize(yaml_event_t *event) | |
687 | { | |
688 | yaml_mark_t mark = { 0, 0, 0 }; | |
689 | ||
690 | assert(event); /* Non-NULL event object is expected. */ | |
691 | ||
692 | STREAM_END_EVENT_INIT(*event, mark, mark); | |
693 | ||
694 | return 1; | |
695 | } | |
696 | ||
697 | /* | |
698 | * Create DOCUMENT-START. | |
699 | */ | |
700 | ||
701 | YAML_DECLARE(int) | |
702 | yaml_document_start_event_initialize(yaml_event_t *event, | |
703 | yaml_version_directive_t *version_directive, | |
704 | yaml_tag_directive_t *tag_directives_start, | |
705 | yaml_tag_directive_t *tag_directives_end, | |
706 | int implicit) | |
707 | { | |
708 | struct { | |
709 | yaml_error_type_t error; | |
710 | } context; | |
711 | yaml_mark_t mark = { 0, 0, 0 }; | |
712 | yaml_version_directive_t *version_directive_copy = NULL; | |
713 | struct { | |
714 | yaml_tag_directive_t *start; | |
715 | yaml_tag_directive_t *end; | |
716 | yaml_tag_directive_t *top; | |
717 | } tag_directives_copy = { NULL, NULL, NULL }; | |
718 | yaml_tag_directive_t value = { NULL, NULL }; | |
719 | ||
720 | assert(event); /* Non-NULL event object is expected. */ | |
721 | assert((tag_directives_start && tag_directives_end) || | |
722 | (tag_directives_start == tag_directives_end)); | |
723 | /* Valid tag directives are expected. */ | |
724 | ||
725 | if (version_directive) { | |
fc2dd942 | 726 | version_directive_copy = YAML_MALLOC_STATIC(yaml_version_directive_t); |
5a00d8fe KS |
727 | if (!version_directive_copy) goto error; |
728 | version_directive_copy->major = version_directive->major; | |
729 | version_directive_copy->minor = version_directive->minor; | |
730 | } | |
731 | ||
732 | if (tag_directives_start != tag_directives_end) { | |
733 | yaml_tag_directive_t *tag_directive; | |
fc2dd942 | 734 | if (!STACK_INIT(&context, tag_directives_copy, yaml_tag_directive_t*)) |
5a00d8fe KS |
735 | goto error; |
736 | for (tag_directive = tag_directives_start; | |
737 | tag_directive != tag_directives_end; tag_directive ++) { | |
738 | assert(tag_directive->handle); | |
739 | assert(tag_directive->prefix); | |
740 | if (!yaml_check_utf8(tag_directive->handle, | |
741 | strlen((char *)tag_directive->handle))) | |
742 | goto error; | |
743 | if (!yaml_check_utf8(tag_directive->prefix, | |
744 | strlen((char *)tag_directive->prefix))) | |
745 | goto error; | |
746 | value.handle = yaml_strdup(tag_directive->handle); | |
747 | value.prefix = yaml_strdup(tag_directive->prefix); | |
748 | if (!value.handle || !value.prefix) goto error; | |
749 | if (!PUSH(&context, tag_directives_copy, value)) | |
750 | goto error; | |
751 | value.handle = NULL; | |
752 | value.prefix = NULL; | |
753 | } | |
754 | } | |
755 | ||
756 | DOCUMENT_START_EVENT_INIT(*event, version_directive_copy, | |
6d167281 | 757 | tag_directives_copy.start, tag_directives_copy.top, |
5a00d8fe KS |
758 | implicit, mark, mark); |
759 | ||
760 | return 1; | |
761 | ||
762 | error: | |
763 | yaml_free(version_directive_copy); | |
764 | while (!STACK_EMPTY(context, tag_directives_copy)) { | |
765 | yaml_tag_directive_t value = POP(context, tag_directives_copy); | |
766 | yaml_free(value.handle); | |
767 | yaml_free(value.prefix); | |
768 | } | |
769 | STACK_DEL(context, tag_directives_copy); | |
770 | yaml_free(value.handle); | |
771 | yaml_free(value.prefix); | |
772 | ||
773 | return 0; | |
774 | } | |
775 | ||
776 | /* | |
777 | * Create DOCUMENT-END. | |
778 | */ | |
779 | ||
780 | YAML_DECLARE(int) | |
781 | yaml_document_end_event_initialize(yaml_event_t *event, int implicit) | |
782 | { | |
783 | yaml_mark_t mark = { 0, 0, 0 }; | |
784 | ||
785 | assert(event); /* Non-NULL emitter object is expected. */ | |
786 | ||
787 | DOCUMENT_END_EVENT_INIT(*event, implicit, mark, mark); | |
788 | ||
789 | return 1; | |
790 | } | |
791 | ||
792 | /* | |
793 | * Create ALIAS. | |
794 | */ | |
795 | ||
796 | YAML_DECLARE(int) | |
797 | yaml_alias_event_initialize(yaml_event_t *event, yaml_char_t *anchor) | |
798 | { | |
799 | yaml_mark_t mark = { 0, 0, 0 }; | |
800 | yaml_char_t *anchor_copy = NULL; | |
801 | ||
802 | assert(event); /* Non-NULL event object is expected. */ | |
803 | assert(anchor); /* Non-NULL anchor is expected. */ | |
804 | ||
805 | if (!yaml_check_utf8(anchor, strlen((char *)anchor))) return 0; | |
806 | ||
807 | anchor_copy = yaml_strdup(anchor); | |
808 | if (!anchor_copy) | |
809 | return 0; | |
810 | ||
811 | ALIAS_EVENT_INIT(*event, anchor_copy, mark, mark); | |
812 | ||
813 | return 1; | |
814 | } | |
815 | ||
816 | /* | |
817 | * Create SCALAR. | |
818 | */ | |
819 | ||
820 | YAML_DECLARE(int) | |
821 | yaml_scalar_event_initialize(yaml_event_t *event, | |
822 | yaml_char_t *anchor, yaml_char_t *tag, | |
2a02dfd2 | 823 | yaml_char_t *value, int length, |
5a00d8fe KS |
824 | int plain_implicit, int quoted_implicit, |
825 | yaml_scalar_style_t style) | |
826 | { | |
827 | yaml_mark_t mark = { 0, 0, 0 }; | |
828 | yaml_char_t *anchor_copy = NULL; | |
829 | yaml_char_t *tag_copy = NULL; | |
830 | yaml_char_t *value_copy = NULL; | |
831 | ||
832 | assert(event); /* Non-NULL event object is expected. */ | |
833 | assert(value); /* Non-NULL anchor is expected. */ | |
834 | ||
5a00d8fe KS |
835 | if (anchor) { |
836 | if (!yaml_check_utf8(anchor, strlen((char *)anchor))) goto error; | |
837 | anchor_copy = yaml_strdup(anchor); | |
838 | if (!anchor_copy) goto error; | |
839 | } | |
840 | ||
841 | if (tag) { | |
842 | if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error; | |
843 | tag_copy = yaml_strdup(tag); | |
844 | if (!tag_copy) goto error; | |
845 | } | |
846 | ||
2a02dfd2 KS |
847 | if (length < 0) { |
848 | length = strlen((char *)value); | |
849 | } | |
850 | ||
5a00d8fe | 851 | if (!yaml_check_utf8(value, length)) goto error; |
fc2dd942 | 852 | value_copy = YAML_MALLOC(length+1); |
5a00d8fe KS |
853 | if (!value_copy) goto error; |
854 | memcpy(value_copy, value, length); | |
855 | value_copy[length] = '\0'; | |
856 | ||
857 | SCALAR_EVENT_INIT(*event, anchor_copy, tag_copy, value_copy, length, | |
858 | plain_implicit, quoted_implicit, style, mark, mark); | |
859 | ||
860 | return 1; | |
861 | ||
862 | error: | |
863 | yaml_free(anchor_copy); | |
864 | yaml_free(tag_copy); | |
865 | yaml_free(value_copy); | |
866 | ||
867 | return 0; | |
868 | } | |
869 | ||
870 | /* | |
871 | * Create SEQUENCE-START. | |
872 | */ | |
873 | ||
874 | YAML_DECLARE(int) | |
875 | yaml_sequence_start_event_initialize(yaml_event_t *event, | |
876 | yaml_char_t *anchor, yaml_char_t *tag, int implicit, | |
877 | yaml_sequence_style_t style) | |
878 | { | |
879 | yaml_mark_t mark = { 0, 0, 0 }; | |
880 | yaml_char_t *anchor_copy = NULL; | |
881 | yaml_char_t *tag_copy = NULL; | |
882 | ||
883 | assert(event); /* Non-NULL event object is expected. */ | |
884 | ||
885 | if (anchor) { | |
886 | if (!yaml_check_utf8(anchor, strlen((char *)anchor))) goto error; | |
887 | anchor_copy = yaml_strdup(anchor); | |
888 | if (!anchor_copy) goto error; | |
889 | } | |
890 | ||
891 | if (tag) { | |
892 | if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error; | |
893 | tag_copy = yaml_strdup(tag); | |
894 | if (!tag_copy) goto error; | |
895 | } | |
896 | ||
897 | SEQUENCE_START_EVENT_INIT(*event, anchor_copy, tag_copy, | |
898 | implicit, style, mark, mark); | |
899 | ||
900 | return 1; | |
901 | ||
902 | error: | |
903 | yaml_free(anchor_copy); | |
904 | yaml_free(tag_copy); | |
905 | ||
906 | return 0; | |
907 | } | |
908 | ||
909 | /* | |
910 | * Create SEQUENCE-END. | |
911 | */ | |
912 | ||
913 | YAML_DECLARE(int) | |
914 | yaml_sequence_end_event_initialize(yaml_event_t *event) | |
915 | { | |
916 | yaml_mark_t mark = { 0, 0, 0 }; | |
917 | ||
918 | assert(event); /* Non-NULL event object is expected. */ | |
919 | ||
920 | SEQUENCE_END_EVENT_INIT(*event, mark, mark); | |
921 | ||
922 | return 1; | |
923 | } | |
924 | ||
925 | /* | |
926 | * Create MAPPING-START. | |
927 | */ | |
928 | ||
929 | YAML_DECLARE(int) | |
930 | yaml_mapping_start_event_initialize(yaml_event_t *event, | |
931 | yaml_char_t *anchor, yaml_char_t *tag, int implicit, | |
932 | yaml_mapping_style_t style) | |
933 | { | |
934 | yaml_mark_t mark = { 0, 0, 0 }; | |
935 | yaml_char_t *anchor_copy = NULL; | |
936 | yaml_char_t *tag_copy = NULL; | |
937 | ||
938 | assert(event); /* Non-NULL event object is expected. */ | |
939 | ||
940 | if (anchor) { | |
941 | if (!yaml_check_utf8(anchor, strlen((char *)anchor))) goto error; | |
942 | anchor_copy = yaml_strdup(anchor); | |
943 | if (!anchor_copy) goto error; | |
944 | } | |
945 | ||
946 | if (tag) { | |
947 | if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error; | |
948 | tag_copy = yaml_strdup(tag); | |
949 | if (!tag_copy) goto error; | |
950 | } | |
951 | ||
952 | MAPPING_START_EVENT_INIT(*event, anchor_copy, tag_copy, | |
953 | implicit, style, mark, mark); | |
954 | ||
955 | return 1; | |
956 | ||
957 | error: | |
958 | yaml_free(anchor_copy); | |
959 | yaml_free(tag_copy); | |
960 | ||
961 | return 0; | |
962 | } | |
963 | ||
964 | /* | |
965 | * Create MAPPING-END. | |
966 | */ | |
967 | ||
968 | YAML_DECLARE(int) | |
969 | yaml_mapping_end_event_initialize(yaml_event_t *event) | |
970 | { | |
971 | yaml_mark_t mark = { 0, 0, 0 }; | |
972 | ||
973 | assert(event); /* Non-NULL event object is expected. */ | |
974 | ||
975 | MAPPING_END_EVENT_INIT(*event, mark, mark); | |
976 | ||
977 | return 1; | |
978 | } | |
979 | ||
26687d7d KS |
980 | /* |
981 | * Destroy an event object. | |
982 | */ | |
983 | ||
984 | YAML_DECLARE(void) | |
985 | yaml_event_delete(yaml_event_t *event) | |
986 | { | |
625fcfe9 KS |
987 | yaml_tag_directive_t *tag_directive; |
988 | ||
26687d7d KS |
989 | assert(event); /* Non-NULL event object expected. */ |
990 | ||
991 | switch (event->type) | |
992 | { | |
993 | case YAML_DOCUMENT_START_EVENT: | |
625fcfe9 KS |
994 | yaml_free(event->data.document_start.version_directive); |
995 | for (tag_directive = event->data.document_start.tag_directives.start; | |
996 | tag_directive != event->data.document_start.tag_directives.end; | |
997 | tag_directive++) { | |
998 | yaml_free(tag_directive->handle); | |
999 | yaml_free(tag_directive->prefix); | |
1000 | } | |
1001 | yaml_free(event->data.document_start.tag_directives.start); | |
26687d7d KS |
1002 | break; |
1003 | ||
1004 | case YAML_ALIAS_EVENT: | |
1005 | yaml_free(event->data.alias.anchor); | |
1006 | break; | |
1007 | ||
1008 | case YAML_SCALAR_EVENT: | |
1009 | yaml_free(event->data.scalar.anchor); | |
1010 | yaml_free(event->data.scalar.tag); | |
1011 | yaml_free(event->data.scalar.value); | |
1012 | break; | |
1013 | ||
1014 | case YAML_SEQUENCE_START_EVENT: | |
1015 | yaml_free(event->data.sequence_start.anchor); | |
1016 | yaml_free(event->data.sequence_start.tag); | |
1017 | break; | |
1018 | ||
1019 | case YAML_MAPPING_START_EVENT: | |
1020 | yaml_free(event->data.mapping_start.anchor); | |
1021 | yaml_free(event->data.mapping_start.tag); | |
1022 | break; | |
54815ffd KS |
1023 | |
1024 | default: | |
1025 | break; | |
26687d7d KS |
1026 | } |
1027 | ||
1028 | memset(event, 0, sizeof(yaml_event_t)); | |
26687d7d KS |
1029 | } |
1030 | ||
e27a3c88 KS |
1031 | /* |
1032 | * Create a document object. | |
1033 | */ | |
1034 | ||
1035 | YAML_DECLARE(int) | |
1036 | yaml_document_initialize(yaml_document_t *document, | |
1037 | yaml_version_directive_t *version_directive, | |
1038 | yaml_tag_directive_t *tag_directives_start, | |
1039 | yaml_tag_directive_t *tag_directives_end, | |
1040 | int start_implicit, int end_implicit) | |
1041 | { | |
1042 | struct { | |
1043 | yaml_error_type_t error; | |
1044 | } context; | |
1045 | struct { | |
1046 | yaml_node_t *start; | |
1047 | yaml_node_t *end; | |
1048 | yaml_node_t *top; | |
1049 | } nodes = { NULL, NULL, NULL }; | |
1050 | yaml_version_directive_t *version_directive_copy = NULL; | |
1051 | struct { | |
1052 | yaml_tag_directive_t *start; | |
1053 | yaml_tag_directive_t *end; | |
1054 | yaml_tag_directive_t *top; | |
1055 | } tag_directives_copy = { NULL, NULL, NULL }; | |
1056 | yaml_tag_directive_t value = { NULL, NULL }; | |
1057 | yaml_mark_t mark = { 0, 0, 0 }; | |
1058 | ||
1059 | assert(document); /* Non-NULL document object is expected. */ | |
1060 | assert((tag_directives_start && tag_directives_end) || | |
1061 | (tag_directives_start == tag_directives_end)); | |
1062 | /* Valid tag directives are expected. */ | |
1063 | ||
fc2dd942 | 1064 | if (!STACK_INIT(&context, nodes, yaml_node_t*)) goto error; |
e27a3c88 KS |
1065 | |
1066 | if (version_directive) { | |
fc2dd942 | 1067 | version_directive_copy = YAML_MALLOC_STATIC(yaml_version_directive_t); |
e27a3c88 KS |
1068 | if (!version_directive_copy) goto error; |
1069 | version_directive_copy->major = version_directive->major; | |
1070 | version_directive_copy->minor = version_directive->minor; | |
1071 | } | |
1072 | ||
1073 | if (tag_directives_start != tag_directives_end) { | |
1074 | yaml_tag_directive_t *tag_directive; | |
fc2dd942 | 1075 | if (!STACK_INIT(&context, tag_directives_copy, yaml_tag_directive_t*)) |
e27a3c88 KS |
1076 | goto error; |
1077 | for (tag_directive = tag_directives_start; | |
1078 | tag_directive != tag_directives_end; tag_directive ++) { | |
1079 | assert(tag_directive->handle); | |
1080 | assert(tag_directive->prefix); | |
1081 | if (!yaml_check_utf8(tag_directive->handle, | |
1082 | strlen((char *)tag_directive->handle))) | |
1083 | goto error; | |
1084 | if (!yaml_check_utf8(tag_directive->prefix, | |
1085 | strlen((char *)tag_directive->prefix))) | |
1086 | goto error; | |
1087 | value.handle = yaml_strdup(tag_directive->handle); | |
1088 | value.prefix = yaml_strdup(tag_directive->prefix); | |
1089 | if (!value.handle || !value.prefix) goto error; | |
1090 | if (!PUSH(&context, tag_directives_copy, value)) | |
1091 | goto error; | |
1092 | value.handle = NULL; | |
1093 | value.prefix = NULL; | |
1094 | } | |
1095 | } | |
1096 | ||
1097 | DOCUMENT_INIT(*document, nodes.start, nodes.end, version_directive_copy, | |
1098 | tag_directives_copy.start, tag_directives_copy.top, | |
1099 | start_implicit, end_implicit, mark, mark); | |
1100 | ||
1101 | return 1; | |
1102 | ||
1103 | error: | |
1104 | STACK_DEL(&context, nodes); | |
1105 | yaml_free(version_directive_copy); | |
1106 | while (!STACK_EMPTY(&context, tag_directives_copy)) { | |
1107 | yaml_tag_directive_t value = POP(&context, tag_directives_copy); | |
1108 | yaml_free(value.handle); | |
1109 | yaml_free(value.prefix); | |
1110 | } | |
1111 | STACK_DEL(&context, tag_directives_copy); | |
1112 | yaml_free(value.handle); | |
1113 | yaml_free(value.prefix); | |
1114 | ||
1115 | return 0; | |
1116 | } | |
1117 | ||
1118 | /* | |
1119 | * Destroy a document object. | |
1120 | */ | |
1121 | ||
1122 | YAML_DECLARE(void) | |
1123 | yaml_document_delete(yaml_document_t *document) | |
1124 | { | |
e27a3c88 KS |
1125 | yaml_tag_directive_t *tag_directive; |
1126 | ||
1127 | assert(document); /* Non-NULL document object is expected. */ | |
1128 | ||
1129 | while (!STACK_EMPTY(&context, document->nodes)) { | |
1130 | yaml_node_t node = POP(&context, document->nodes); | |
1131 | yaml_free(node.tag); | |
1132 | switch (node.type) { | |
1133 | case YAML_SCALAR_NODE: | |
1134 | yaml_free(node.data.scalar.value); | |
1135 | break; | |
1136 | case YAML_SEQUENCE_NODE: | |
1137 | STACK_DEL(&context, node.data.sequence.items); | |
1138 | break; | |
1139 | case YAML_MAPPING_NODE: | |
1140 | STACK_DEL(&context, node.data.mapping.pairs); | |
1141 | break; | |
1142 | default: | |
1143 | assert(0); /* Should not happen. */ | |
1144 | } | |
1145 | } | |
1146 | STACK_DEL(&context, document->nodes); | |
1147 | ||
1148 | yaml_free(document->version_directive); | |
1149 | for (tag_directive = document->tag_directives.start; | |
1150 | tag_directive != document->tag_directives.end; | |
1151 | tag_directive++) { | |
1152 | yaml_free(tag_directive->handle); | |
1153 | yaml_free(tag_directive->prefix); | |
1154 | } | |
1155 | yaml_free(document->tag_directives.start); | |
1156 | ||
1157 | memset(document, 0, sizeof(yaml_document_t)); | |
1158 | } | |
1159 | ||
1160 | /** | |
1161 | * Get a document node. | |
1162 | */ | |
1163 | ||
1164 | YAML_DECLARE(yaml_node_t *) | |
c9b74def | 1165 | yaml_document_get_node(yaml_document_t *document, int index) |
e27a3c88 KS |
1166 | { |
1167 | assert(document); /* Non-NULL document object is expected. */ | |
1168 | ||
c9b74def KS |
1169 | if (index > 0 && document->nodes.start + index <= document->nodes.top) { |
1170 | return document->nodes.start + index - 1; | |
e27a3c88 KS |
1171 | } |
1172 | return NULL; | |
1173 | } | |
1174 | ||
1175 | /** | |
1176 | * Get the root object. | |
1177 | */ | |
1178 | ||
1179 | YAML_DECLARE(yaml_node_t *) | |
1180 | yaml_document_get_root_node(yaml_document_t *document) | |
1181 | { | |
1182 | assert(document); /* Non-NULL document object is expected. */ | |
1183 | ||
1184 | if (document->nodes.top != document->nodes.start) { | |
1185 | return document->nodes.start; | |
1186 | } | |
1187 | return NULL; | |
1188 | } | |
a907bf85 KS |
1189 | |
1190 | /* | |
e27a3c88 | 1191 | * Add a scalar node to a document. |
a907bf85 KS |
1192 | */ |
1193 | ||
1194 | YAML_DECLARE(int) | |
e27a3c88 | 1195 | yaml_document_add_scalar(yaml_document_t *document, |
a907bf85 KS |
1196 | yaml_char_t *tag, yaml_char_t *value, int length, |
1197 | yaml_scalar_style_t style) | |
1198 | { | |
e27a3c88 KS |
1199 | struct { |
1200 | yaml_error_type_t error; | |
1201 | } context; | |
a907bf85 KS |
1202 | yaml_mark_t mark = { 0, 0, 0 }; |
1203 | yaml_char_t *tag_copy = NULL; | |
1204 | yaml_char_t *value_copy = NULL; | |
e27a3c88 | 1205 | yaml_node_t node; |
a907bf85 | 1206 | |
e27a3c88 KS |
1207 | assert(document); /* Non-NULL document object is expected. */ |
1208 | assert(value); /* Non-NULL value is expected. */ | |
a907bf85 KS |
1209 | |
1210 | if (!tag) { | |
c9b74def | 1211 | tag = (yaml_char_t *)YAML_DEFAULT_SCALAR_TAG; |
a907bf85 KS |
1212 | } |
1213 | ||
1214 | if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error; | |
1215 | tag_copy = yaml_strdup(tag); | |
1216 | if (!tag_copy) goto error; | |
1217 | ||
1218 | if (length < 0) { | |
1219 | length = strlen((char *)value); | |
1220 | } | |
1221 | ||
1222 | if (!yaml_check_utf8(value, length)) goto error; | |
fc2dd942 | 1223 | value_copy = YAML_MALLOC(length+1); |
a907bf85 KS |
1224 | if (!value_copy) goto error; |
1225 | memcpy(value_copy, value, length); | |
1226 | value_copy[length] = '\0'; | |
1227 | ||
e27a3c88 KS |
1228 | SCALAR_NODE_INIT(node, tag_copy, value_copy, length, style, mark, mark); |
1229 | if (!PUSH(&context, document->nodes, node)) goto error; | |
a907bf85 | 1230 | |
e27a3c88 | 1231 | return document->nodes.top - document->nodes.start; |
a907bf85 KS |
1232 | |
1233 | error: | |
1234 | yaml_free(tag_copy); | |
1235 | yaml_free(value_copy); | |
1236 | ||
1237 | return 0; | |
1238 | } | |
1239 | ||
1240 | /* | |
e27a3c88 | 1241 | * Add a sequence node to a document. |
a907bf85 KS |
1242 | */ |
1243 | ||
1244 | YAML_DECLARE(int) | |
e27a3c88 | 1245 | yaml_document_add_sequence(yaml_document_t *document, |
a907bf85 KS |
1246 | yaml_char_t *tag, yaml_sequence_style_t style) |
1247 | { | |
1248 | struct { | |
1249 | yaml_error_type_t error; | |
1250 | } context; | |
1251 | yaml_mark_t mark = { 0, 0, 0 }; | |
1252 | yaml_char_t *tag_copy = NULL; | |
1253 | struct { | |
1254 | yaml_node_item_t *start; | |
1255 | yaml_node_item_t *end; | |
1256 | yaml_node_item_t *top; | |
1257 | } items = { NULL, NULL, NULL }; | |
e27a3c88 | 1258 | yaml_node_t node; |
a907bf85 | 1259 | |
e27a3c88 | 1260 | assert(document); /* Non-NULL document object is expected. */ |
a907bf85 KS |
1261 | |
1262 | if (!tag) { | |
c9b74def | 1263 | tag = (yaml_char_t *)YAML_DEFAULT_SEQUENCE_TAG; |
a907bf85 KS |
1264 | } |
1265 | ||
e27a3c88 KS |
1266 | if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error; |
1267 | tag_copy = yaml_strdup(tag); | |
1268 | if (!tag_copy) goto error; | |
a907bf85 | 1269 | |
fc2dd942 | 1270 | if (!STACK_INIT(&context, items, yaml_node_item_t*)) goto error; |
a907bf85 | 1271 | |
e27a3c88 KS |
1272 | SEQUENCE_NODE_INIT(node, tag_copy, items.start, items.end, |
1273 | style, mark, mark); | |
1274 | if (!PUSH(&context, document->nodes, node)) goto error; | |
a907bf85 | 1275 | |
e27a3c88 | 1276 | return document->nodes.top - document->nodes.start; |
a907bf85 KS |
1277 | |
1278 | error: | |
e27a3c88 | 1279 | STACK_DEL(&context, items); |
a907bf85 | 1280 | yaml_free(tag_copy); |
a907bf85 KS |
1281 | |
1282 | return 0; | |
1283 | } | |
1284 | ||
1285 | /* | |
e27a3c88 | 1286 | * Add a mapping node to a document. |
a907bf85 KS |
1287 | */ |
1288 | ||
1289 | YAML_DECLARE(int) | |
e27a3c88 | 1290 | yaml_document_add_mapping(yaml_document_t *document, |
a907bf85 KS |
1291 | yaml_char_t *tag, yaml_mapping_style_t style) |
1292 | { | |
1293 | struct { | |
1294 | yaml_error_type_t error; | |
1295 | } context; | |
1296 | yaml_mark_t mark = { 0, 0, 0 }; | |
1297 | yaml_char_t *tag_copy = NULL; | |
1298 | struct { | |
1299 | yaml_node_pair_t *start; | |
1300 | yaml_node_pair_t *end; | |
1301 | yaml_node_pair_t *top; | |
1302 | } pairs = { NULL, NULL, NULL }; | |
e27a3c88 | 1303 | yaml_node_t node; |
a907bf85 | 1304 | |
e27a3c88 | 1305 | assert(document); /* Non-NULL document object is expected. */ |
a907bf85 KS |
1306 | |
1307 | if (!tag) { | |
c9b74def | 1308 | tag = (yaml_char_t *)YAML_DEFAULT_MAPPING_TAG; |
a907bf85 KS |
1309 | } |
1310 | ||
e27a3c88 KS |
1311 | if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error; |
1312 | tag_copy = yaml_strdup(tag); | |
1313 | if (!tag_copy) goto error; | |
a907bf85 | 1314 | |
fc2dd942 | 1315 | if (!STACK_INIT(&context, pairs, yaml_node_pair_t*)) goto error; |
a907bf85 | 1316 | |
e27a3c88 KS |
1317 | MAPPING_NODE_INIT(node, tag_copy, pairs.start, pairs.end, |
1318 | style, mark, mark); | |
1319 | if (!PUSH(&context, document->nodes, node)) goto error; | |
a907bf85 | 1320 | |
e27a3c88 | 1321 | return document->nodes.top - document->nodes.start; |
a907bf85 KS |
1322 | |
1323 | error: | |
e27a3c88 | 1324 | STACK_DEL(&context, pairs); |
a907bf85 | 1325 | yaml_free(tag_copy); |
a907bf85 KS |
1326 | |
1327 | return 0; | |
1328 | } | |
1329 | ||
1330 | /* | |
e27a3c88 | 1331 | * Append an item to a sequence node. |
a907bf85 KS |
1332 | */ |
1333 | ||
e27a3c88 KS |
1334 | YAML_DECLARE(int) |
1335 | yaml_document_append_sequence_item(yaml_document_t *document, | |
1336 | int sequence, int item) | |
a907bf85 KS |
1337 | { |
1338 | struct { | |
1339 | yaml_error_type_t error; | |
1340 | } context; | |
a907bf85 | 1341 | |
e27a3c88 KS |
1342 | assert(document); /* Non-NULL document is required. */ |
1343 | assert(sequence > 0 | |
1344 | && document->nodes.start + sequence <= document->nodes.top); | |
1345 | /* Valid sequence id is required. */ | |
1346 | assert(document->nodes.start[sequence-1].type == YAML_SEQUENCE_NODE); | |
1347 | /* A sequence node is required. */ | |
1348 | assert(item > 0 && document->nodes.start + item <= document->nodes.top); | |
1349 | /* Valid item id is required. */ | |
1350 | ||
1351 | if (!PUSH(&context, | |
1352 | document->nodes.start[sequence-1].data.sequence.items, item)) | |
1353 | return 0; | |
a907bf85 | 1354 | |
e27a3c88 KS |
1355 | return 1; |
1356 | } | |
a907bf85 | 1357 | |
e27a3c88 KS |
1358 | /* |
1359 | * Append a pair of a key and a value to a mapping node. | |
1360 | */ | |
a907bf85 | 1361 | |
e27a3c88 KS |
1362 | YAML_DECLARE(int) |
1363 | yaml_document_append_mapping_pair(yaml_document_t *document, | |
1364 | int mapping, int key, int value) | |
1365 | { | |
1366 | struct { | |
1367 | yaml_error_type_t error; | |
1368 | } context; | |
252c575a KS |
1369 | |
1370 | yaml_node_pair_t pair; | |
e27a3c88 KS |
1371 | |
1372 | assert(document); /* Non-NULL document is required. */ | |
1373 | assert(mapping > 0 | |
1374 | && document->nodes.start + mapping <= document->nodes.top); | |
1375 | /* Valid mapping id is required. */ | |
1376 | assert(document->nodes.start[mapping-1].type == YAML_MAPPING_NODE); | |
1377 | /* A mapping node is required. */ | |
1378 | assert(key > 0 && document->nodes.start + key <= document->nodes.top); | |
1379 | /* Valid key id is required. */ | |
1380 | assert(value > 0 && document->nodes.start + value <= document->nodes.top); | |
1381 | /* Valid value id is required. */ | |
1382 | ||
252c575a KS |
1383 | pair.key = key; |
1384 | pair.value = value; | |
1385 | ||
e27a3c88 KS |
1386 | if (!PUSH(&context, |
1387 | document->nodes.start[mapping-1].data.mapping.pairs, pair)) | |
1388 | return 0; | |
a907bf85 | 1389 | |
e27a3c88 KS |
1390 | return 1; |
1391 | } | |
a907bf85 | 1392 | |
0174ed6e | 1393 |