1 #include "r_ext.h"
2
3 extern SEXP Ryaml_KeysSymbol;
4 extern SEXP Ryaml_IdenticalFunc;
5 extern SEXP Ryaml_Sentinel;
6 extern SEXP Ryaml_SequenceStart;
7 extern SEXP Ryaml_MappingStart;
8 extern SEXP Ryaml_MappingEnd;
9 extern char Ryaml_error_msg[ERROR_MSG_SIZE];
10
11 /* Compare two R objects (with the R identical function).
12 * Returns 0 or 1 */
13 static int
Ryaml_cmp(s_first,s_second)14 Ryaml_cmp(s_first, s_second)
15 SEXP s_first;
16 SEXP s_second;
17 {
18 int i = 0, retval = 0, *arr = NULL;
19 SEXP s_call = NULL, s_result = NULL, s_bool = NULL;
20
21 PROTECT(s_bool = allocVector(LGLSXP, 1));
22 LOGICAL(s_bool)[0] = 1;
23 PROTECT(s_call = LCONS(Ryaml_IdenticalFunc, list4(s_first, s_second, s_bool, s_bool)));
24 PROTECT(s_result = eval(s_call, R_GlobalEnv));
25
26 arr = LOGICAL(s_result);
27 for(i = 0; i < length(s_result); i++) {
28 if (!arr[i]) {
29 retval = 1;
30 break;
31 }
32 }
33 UNPROTECT(3);
34 return retval;
35 }
36
37 /* Returns the index of the first instance of needle in haystack */
38 static int
Ryaml_index(s_haystack,s_needle,character,upper_bound)39 Ryaml_index(s_haystack, s_needle, character, upper_bound)
40 SEXP s_haystack;
41 SEXP s_needle;
42 int character;
43 int upper_bound;
44 {
45 int i = 0;
46
47 if (character) {
48 for (i = 0; i < upper_bound; i++) {
49 if (strcmp(CHAR(s_needle), CHAR(STRING_ELT(s_haystack, i))) == 0) {
50 return i;
51 }
52 }
53 }
54 else {
55 for (i = 0; i < upper_bound; i++) {
56 if (Ryaml_cmp(s_needle, VECTOR_ELT(s_haystack, i)) == 0) {
57 return i;
58 }
59 }
60 }
61
62 return -1;
63 }
64
65 /* Returns true if obj is a list with a keys attribute */
66 static int
Ryaml_is_pseudo_hash(s_obj)67 Ryaml_is_pseudo_hash(s_obj)
68 SEXP s_obj;
69 {
70 SEXP s_keys = NULL;
71 if (TYPEOF(s_obj) != VECSXP)
72 return 0;
73
74 s_keys = getAttrib(s_obj, Ryaml_KeysSymbol);
75 return (s_keys != R_NilValue && TYPEOF(s_keys) == VECSXP);
76 }
77
78 /* Set a character attribute on an R object */
79 static void
Ryaml_set_str_attrib(s_obj,s_sym,str)80 Ryaml_set_str_attrib(s_obj, s_sym, str)
81 SEXP s_obj;
82 SEXP s_sym;
83 char *str;
84 {
85 SEXP s_val = NULL;
86 PROTECT(s_val = ScalarString(mkCharCE(str, CE_UTF8)));
87 setAttrib(s_obj, s_sym, s_val);
88 UNPROTECT(1);
89 }
90
91 /* Set the R object's class attribute */
92 static void
Ryaml_set_class(s_obj,name)93 Ryaml_set_class(s_obj, name)
94 SEXP s_obj;
95 char *name;
96 {
97 Ryaml_set_str_attrib(s_obj, R_ClassSymbol, name);
98 }
99
100 /* Get the type part of the tag, throw away any !'s */
101 static char *
process_tag(tag)102 process_tag(tag)
103 char *tag;
104 {
105 char *retval = tag;
106
107 if (strncmp(retval, "tag:yaml.org,2002:", 18) == 0) {
108 retval = retval + 18;
109 }
110 else {
111 while (*retval == '!') {
112 retval++;
113 }
114 }
115 return retval;
116 }
117
118 static int
handle_alias(event,s_stack_tail,s_aliases_head)119 handle_alias(event, s_stack_tail, s_aliases_head)
120 yaml_event_t *event;
121 SEXP *s_stack_tail;
122 SEXP s_aliases_head;
123 {
124 SEXP s_curr = NULL, s_obj = NULL;
125 int handled = 0;
126 const char *name = NULL, *anchor = NULL;
127
128 /* Try to find object with the supplied anchor */
129 anchor = (const char *)event->data.alias.anchor;
130 s_curr = CDR(s_aliases_head);
131 while (s_curr != R_NilValue) {
132 s_obj = CAR(s_curr);
133 name = CHAR(TAG(s_curr));
134 if (strcmp(name, anchor) == 0) {
135 /* Found object, push onto stack */
136 SETCDR(*s_stack_tail, list1(s_obj));
137 *s_stack_tail = CDR(*s_stack_tail);
138
139 MARK_NOT_MUTABLE(s_obj);
140 handled = 1;
141 break;
142 }
143 s_curr = CDR(s_curr);
144 }
145
146 if (!handled) {
147 warning("Unknown anchor: %s", (char *)event->data.alias.anchor);
148 PROTECT(s_obj = ScalarString(mkCharCE("_yaml.bad-anchor_", CE_UTF8)));
149 Ryaml_set_class(s_obj, "_yaml.bad-anchor_");
150 UNPROTECT(1);
151
152 SETCDR(*s_stack_tail, list1(s_obj));
153 *s_stack_tail = CDR(*s_stack_tail);
154 }
155
156 return 0;
157 }
158
159 static int
handle_scalar(event,s_stack_tail,s_handlers,eval_expr,eval_warning)160 handle_scalar(event, s_stack_tail, s_handlers, eval_expr, eval_warning)
161 yaml_event_t *event;
162 SEXP *s_stack_tail;
163 SEXP s_handlers;
164 int eval_expr;
165 int eval_warning;
166 {
167 SEXP s_obj = NULL, s_handler = NULL, s_new_obj = NULL, s_expr = NULL;
168 const char *value = NULL, *tag = NULL, *nptr = NULL;
169 char *endptr = NULL;
170 size_t len = 0;
171 int handled = 0, coercion_err = 0, base = 0, n = 0;
172 long int long_n = 0;
173 double f = 0.0f;
174 ParseStatus parse_status;
175
176 tag = (const char *)event->data.scalar.tag;
177 value = (const char *)event->data.scalar.value;
178 len = event->data.scalar.length;
179 if (tag == NULL || strcmp(tag, "!") == 0) {
180 /* There's no tag! */
181
182 /* If this is a quoted string, leave it as a string */
183 switch (event->data.scalar.style) {
184 case YAML_SINGLE_QUOTED_SCALAR_STYLE:
185 case YAML_DOUBLE_QUOTED_SCALAR_STYLE:
186 tag = "str";
187 break;
188 default:
189 /* Try to tag it */
190 tag = Ryaml_find_implicit_tag(value, len);
191 }
192 }
193 else {
194 tag = process_tag(tag);
195 }
196
197 #if DEBUG
198 Rprintf("Value: (%s), Tag: (%s)\n", value, tag);
199 #endif
200
201 /* 'Vanilla' object */
202 PROTECT(s_obj = ScalarString(mkCharCE(value, CE_UTF8)));
203
204 /* Look for a custom R handler */
205 PROTECT(s_handler = Ryaml_find_handler(s_handlers, (const char *)tag));
206 if (s_handler != R_NilValue) {
207 if (Ryaml_run_handler(s_handler, s_obj, &s_new_obj) != 0) {
208 warning("an error occurred when handling type '%s'; using default handler", tag);
209 }
210 else {
211 handled = 1;
212 }
213 }
214 UNPROTECT(1); /* s_handler */
215
216 if (!handled) {
217 /* Default handlers */
218
219 if (strcmp(tag, "str") == 0) {
220 /* already a string */
221 }
222 else if (strcmp(tag, "seq") == 0) {
223 coercion_err = 1;
224 }
225 else if (strcmp(tag, "int#na") == 0) {
226 s_new_obj = ScalarInteger(NA_INTEGER);
227 }
228 else if (strcmp(tag, "int") == 0 || strncmp(tag, "int#", 4) == 0) {
229 base = -1;
230 if (strcmp(tag, "int") == 0) {
231 base = 10;
232 }
233 else if (strcmp(tag, "int#hex") == 0) {
234 base = 16;
235 }
236 else if (strcmp(tag, "int#oct") == 0) {
237 base = 8;
238 }
239
240 if (base >= 0) {
241 errno = 0;
242 nptr = CHAR(STRING_ELT(s_obj, 0));
243 long_n = strtol(nptr, &endptr, base);
244 if (*endptr != 0) {
245 /* strtol is perfectly happy converting partial strings to
246 * integers, but R isn't. If you call as.integer() on a
247 * string that isn't completely an integer, you get back
248 * an NA. So I'm reproducing that behavior here. */
249
250 warning("NAs introduced by coercion: %s is not an integer", nptr);
251 n = NA_INTEGER;
252 } else if (errno == ERANGE) {
253 warning("NAs introduced by coercion: %s is out of integer range", nptr);
254 n = NA_INTEGER;
255 } else if (long_n < INT_MIN || long_n > INT_MAX || (int)long_n == NA_INTEGER) {
256 warning("NAs introduced by coercion: %s is out of integer range", nptr);
257 n = NA_INTEGER;
258 } else {
259 n = (int)long_n;
260 }
261
262 s_new_obj = ScalarInteger(n);
263 }
264 else {
265 /* unknown integer base; no-op */
266 }
267 }
268 else if (strcmp(tag, "float") == 0 || strcmp(tag, "float#fix") == 0 || strcmp(tag, "float#exp") == 0) {
269 errno = 0;
270 nptr = CHAR(STRING_ELT(s_obj, 0));
271 f = strtod(nptr, &endptr);
272 if (*endptr != 0) {
273 /* No valid floats found (see note above about integers) */
274 warning("NAs introduced by coercion: %s is not a real", nptr);
275 f = NA_REAL;
276 } else if (errno == ERANGE || f == NA_REAL) {
277 warning("NAs introduced by coercion: %s is out of real range", nptr);
278 f = NA_REAL;
279 }
280
281 s_new_obj = ScalarReal(f);
282 }
283 else if (strcmp(tag, "bool") == 0) {
284 /* This would happen if someone explicitly specified a tag of 'bool' */
285 tag = Ryaml_find_implicit_tag(value, len);
286 if (strcmp(tag, "bool#yes") == 0) {
287 s_new_obj = ScalarLogical(TRUE);
288 }
289 else if (strcmp(tag, "bool#no") == 0) {
290 s_new_obj = ScalarLogical(FALSE);
291 }
292 else if (strcmp(tag, "bool#na") == 0) {
293 s_new_obj = ScalarLogical(NA_LOGICAL);
294 }
295 else {
296 warning("NAs introduced by coercion: %s is not a recognized boolean value", value);
297 s_new_obj = ScalarLogical(NA_LOGICAL);
298 }
299 }
300 else if (strcmp(tag, "bool#yes") == 0) {
301 s_new_obj = ScalarLogical(TRUE);
302 }
303 else if (strcmp(tag, "bool#no") == 0) {
304 s_new_obj = ScalarLogical(FALSE);
305 }
306 else if (strcmp(tag, "bool#na") == 0) {
307 s_new_obj = ScalarLogical(NA_LOGICAL);
308 }
309 else if (strcmp(tag, "omap") == 0) {
310 coercion_err = 1;
311 }
312 else if (strcmp(tag, "merge") == 0) {
313 /* see http://yaml.org/type/merge.html */
314 PROTECT(s_new_obj = ScalarString(mkCharCE("_yaml.merge_", CE_UTF8)));
315 Ryaml_set_class(s_new_obj, "_yaml.merge_");
316 UNPROTECT(1);
317 }
318 else if (strcmp(tag, "float#na") == 0) {
319 s_new_obj = ScalarReal(NA_REAL);
320 }
321 else if (strcmp(tag, "float#nan") == 0) {
322 s_new_obj = ScalarReal(R_NaN);
323 }
324 else if (strcmp(tag, "float#inf") == 0) {
325 s_new_obj = ScalarReal(R_PosInf);
326 }
327 else if (strcmp(tag, "float#neginf") == 0) {
328 s_new_obj = ScalarReal(R_NegInf);
329 }
330 else if (strcmp(tag, "str#na") == 0) {
331 s_new_obj = ScalarString(NA_STRING);
332 }
333 else if (strcmp(tag, "null") == 0) {
334 s_new_obj = R_NilValue;
335 }
336 else if (strcmp(tag, "expr") == 0) {
337 if (eval_expr) {
338 PROTECT(s_obj);
339 s_expr = R_ParseVector(s_obj, 1, &parse_status, R_NilValue);
340 UNPROTECT(1);
341
342 if (parse_status != PARSE_OK) {
343 coercion_err = 1;
344 Ryaml_set_error_msg("Could not parse expression: %s", CHAR(STRING_ELT(s_obj, 0)));
345 }
346 else {
347 /* NOTE: R_tryEval will not return if R_Interactive is FALSE. */
348 PROTECT(s_expr);
349 PROTECT(s_new_obj = R_tryEval(VECTOR_ELT(s_expr, 0), R_GlobalEnv, &coercion_err));
350
351 if (coercion_err) {
352 Ryaml_set_error_msg("Could not evaluate expression: %s", CHAR(STRING_ELT(s_obj, 0)));
353 } else if (eval_warning) {
354 warning("Evaluating R expressions (!expr) will soon require explicit `eval.expr` option (see yaml.load help)");
355 }
356 UNPROTECT(2); /* s_expr, s_new_obj */
357 }
358 }
359 }
360 }
361 UNPROTECT(1); /* s_obj */
362
363 if (coercion_err == 1) {
364 if (Ryaml_error_msg[0] == 0) {
365 Ryaml_set_error_msg("Invalid tag for scalar: %s", tag);
366 }
367 return 1;
368 }
369
370 SETCDR(*s_stack_tail, list1(s_new_obj == NULL ? s_obj : s_new_obj));
371 *s_stack_tail = CDR(*s_stack_tail);
372
373 return 0;
374 }
375
376 static void
handle_structure_start(event,s_stack_tail,is_map)377 handle_structure_start(event, s_stack_tail, is_map)
378 yaml_event_t *event;
379 SEXP *s_stack_tail;
380 int is_map;
381 {
382 SEXP s_sym = NULL, s_tag_obj = NULL, s_anchor_obj = NULL, s_tag = NULL;
383 yaml_char_t *tag = NULL, *anchor = NULL;
384
385 if (is_map) {
386 s_sym = Ryaml_MappingStart;
387 tag = event->data.mapping_start.tag;
388 anchor = event->data.mapping_start.anchor;
389 } else {
390 s_sym = Ryaml_SequenceStart;
391 tag = event->data.sequence_start.tag;
392 anchor = event->data.sequence_start.anchor;
393 }
394
395 SETCDR(*s_stack_tail, list1(s_sym));
396 *s_stack_tail = CDR(*s_stack_tail);
397
398 /* Create pairlist tag */
399 if (tag == NULL) {
400 s_tag_obj = R_NilValue;
401 }
402 else {
403 s_tag_obj = mkCharCE((const char *)tag, CE_UTF8);
404 }
405 if (anchor == NULL) {
406 s_anchor_obj = R_NilValue;
407 }
408 else {
409 PROTECT(s_tag_obj);
410 s_anchor_obj = mkCharCE((const char *)anchor, CE_UTF8);
411 UNPROTECT(1);
412 }
413 s_tag = list2(s_tag_obj, s_anchor_obj);
414 SET_TAG(*s_stack_tail, s_tag);
415 }
416
417 static int
handle_sequence(event,s_stack_head,s_stack_tail,s_handlers,coerce_keys)418 handle_sequence(event, s_stack_head, s_stack_tail, s_handlers, coerce_keys)
419 yaml_event_t *event;
420 SEXP s_stack_head;
421 SEXP *s_stack_tail;
422 SEXP s_handlers;
423 int coerce_keys;
424 {
425 SEXP s_curr = NULL, s_obj = NULL, s_sequence_start = NULL, s_list = NULL,
426 s_handler = NULL, s_new_obj = NULL, s_keys = NULL, s_key = NULL,
427 s_tag = NULL, s_inspect = NULL;
428 int count = 0, i = 0, j = 0, type = 0, child_type = 0, handled = 0,
429 coercion_err = 0, len = 0, total_len = 0, dup_key = 0, idx = 0,
430 obj_len = 0;
431 const char *tag = NULL, *inspect = NULL;
432
433 /* Find start of sequence and count elements */
434 s_curr = CDR(s_stack_head);
435 count = 0;
436 while (s_curr != R_NilValue) {
437 if (CAR(s_curr) == Ryaml_SequenceStart) {
438 s_sequence_start = s_curr;
439 count = 0;
440 } else if (s_sequence_start != NULL) {
441 count++;
442 }
443 s_curr = CDR(s_curr);
444 }
445 if (s_sequence_start == NULL) {
446 Ryaml_set_error_msg("Internal error: couldn't find start of sequence!");
447 return 1;
448 }
449
450 s_tag = CAR(TAG(s_sequence_start));
451 tag = s_tag == R_NilValue ? NULL : CHAR(s_tag);
452
453 /* Initialize list */
454 PROTECT(s_list = allocVector(VECSXP, count));
455
456 /* Populate the list, popping items off the stack as we go */
457 type = -2;
458 s_curr = CDR(s_sequence_start);
459 for (i = 0; i < count; i++) {
460 s_obj = CAR(s_curr);
461 s_curr = CDR(s_curr);
462 SET_VECTOR_ELT(s_list, i, s_obj);
463
464 /* Treat primitive vectors with more than one element as a list for
465 * coercion purposes. */
466 child_type = TYPEOF(s_obj);
467 switch (child_type) {
468 case LGLSXP:
469 case INTSXP:
470 case REALSXP:
471 case STRSXP:
472 if (length(s_obj) != 1) {
473 child_type = VECSXP;
474 }
475 break;
476 }
477
478 if (type == -2) {
479 type = child_type;
480 }
481 else if (type != -1 && child_type != type) {
482 type = -1;
483 }
484 }
485
486 /* Tags! */
487 if (tag == NULL) {
488 tag = "seq";
489 }
490 else {
491 tag = process_tag(tag);
492 }
493
494 /* Look for a custom R handler */
495 s_handler = Ryaml_find_handler(s_handlers, (const char *)tag);
496 if (s_handler != R_NilValue) {
497 if (Ryaml_run_handler(s_handler, s_list, &s_new_obj) != 0) {
498 warning("an error occurred when handling type '%s'; using default handler", tag);
499 }
500 else {
501 handled = 1;
502 }
503 }
504
505 if (!handled) {
506 /* default handlers, ordered by most-used */
507
508 if (strcmp(tag, "seq") == 0) {
509 /* Let's try to coerce this list! */
510 switch (type) {
511 case LGLSXP:
512 case INTSXP:
513 case REALSXP:
514 case STRSXP:
515 s_new_obj = coerceVector(s_list, type);
516 break;
517 }
518 }
519 else if (strcmp(tag, "str") == 0) {
520 coercion_err = 1;
521 }
522 else if (strcmp(tag, "int#na") == 0) {
523 coercion_err = 1;
524 }
525 else if (strcmp(tag, "int") == 0 || strncmp(tag, "int#", 4) == 0) {
526 coercion_err = 1;
527 }
528 else if (strcmp(tag, "float") == 0 || strcmp(tag, "float#fix") == 0 || strcmp(tag, "float#exp") == 0) {
529 coercion_err = 1;
530 }
531 else if (strcmp(tag, "bool#yes") == 0) {
532 coercion_err = 1;
533 }
534 else if (strcmp(tag, "bool#no") == 0) {
535 coercion_err = 1;
536 }
537 else if (strcmp(tag, "bool#na") == 0) {
538 coercion_err = 1;
539 }
540 else if (strcmp(tag, "omap") == 0) {
541 /* NOTE: This is here mostly because of backwards compatibility
542 * with R yaml 1.x package. All maps are ordered in 2.x, so there's
543 * no real need to use omap */
544
545 len = length(s_list);
546 total_len = 0;
547 for (i = 0; i < len; i++) {
548 s_obj = VECTOR_ELT(s_list, i);
549 if ((coerce_keys && !Ryaml_is_named_list(s_obj)) || (!coerce_keys && !Ryaml_is_pseudo_hash(s_obj))) {
550 Ryaml_set_error_msg("omap must be a sequence of maps");
551 coercion_err = 1;
552 break;
553 }
554 total_len += length(s_obj);
555 }
556
557 /* Construct the list! */
558 if (!coercion_err) {
559 PROTECT(s_new_obj = allocVector(VECSXP, total_len));
560 if (coerce_keys) {
561 s_keys = allocVector(STRSXP, total_len);
562 SET_NAMES(s_new_obj, s_keys);
563 }
564 else {
565 s_keys = allocVector(VECSXP, total_len);
566 setAttrib(s_new_obj, Ryaml_KeysSymbol, s_keys);
567 }
568
569 for (i = 0, idx = 0; i < len && dup_key == 0; i++) {
570 s_obj = VECTOR_ELT(s_list, i);
571 obj_len = length(s_obj);
572 for (j = 0; j < obj_len && dup_key == 0; j++) {
573 SET_VECTOR_ELT(s_new_obj, idx, VECTOR_ELT(s_obj, j));
574
575 if (coerce_keys) {
576 PROTECT(s_key = STRING_ELT(GET_NAMES(s_obj), j));
577 SET_STRING_ELT(s_keys, idx, s_key);
578
579 if (Ryaml_index(s_keys, s_key, 1, idx) >= 0) {
580 dup_key = 1;
581 Ryaml_set_error_msg("Duplicate omap key: '%s'", CHAR(s_key));
582 }
583 UNPROTECT(1); /* s_key */
584 }
585 else {
586 s_key = VECTOR_ELT(getAttrib(s_obj, Ryaml_KeysSymbol), j);
587 SET_VECTOR_ELT(s_keys, idx, s_key);
588
589 if (Ryaml_index(s_keys, s_key, 0, idx) >= 0) {
590 dup_key = 1;
591
592 PROTECT(s_inspect = Ryaml_inspect(s_key));
593 inspect = CHAR(STRING_ELT(s_inspect, 0));
594 Ryaml_set_error_msg("Duplicate omap key: %s", inspect);
595 UNPROTECT(1);
596 }
597 }
598 idx++;
599 }
600 }
601 UNPROTECT(1); /* s_new_obj */
602
603 if (dup_key == 1) {
604 coercion_err = 1;
605 }
606 }
607 }
608 else if (strcmp(tag, "merge") == 0) {
609 coercion_err = 1;
610 }
611 else if (strcmp(tag, "float#na") == 0) {
612 coercion_err = 1;
613 }
614 else if (strcmp(tag, "float#nan") == 0) {
615 coercion_err = 1;
616 }
617 else if (strcmp(tag, "float#inf") == 0) {
618 coercion_err = 1;
619 }
620 else if (strcmp(tag, "float#neginf") == 0) {
621 coercion_err = 1;
622 }
623 else if (strcmp(tag, "str#na") == 0) {
624 coercion_err = 1;
625 }
626 else if (strcmp(tag, "null") == 0) {
627 s_new_obj = R_NilValue;
628 }
629 else if (strcmp(tag, "expr") == 0) {
630 coercion_err = 1;
631 }
632 }
633 UNPROTECT(1); /* s_list */
634
635 if (coercion_err == 1) {
636 if (Ryaml_error_msg[0] == 0) {
637 Ryaml_set_error_msg("Invalid tag: %s for sequence", tag);
638 }
639 return 1;
640 }
641
642 SETCAR(s_sequence_start, s_new_obj == NULL ? s_list : s_new_obj);
643 SETCDR(s_sequence_start, R_NilValue);
644 *s_stack_tail = s_sequence_start;
645
646 return 0;
647 }
648
649 static SEXP
find_map_entry(s_map_head,s_key,character)650 find_map_entry(s_map_head, s_key, character)
651 SEXP s_map_head;
652 SEXP s_key;
653 int character;
654 {
655 SEXP s_curr = NULL;
656
657 s_curr = CDR(s_map_head);
658 if (character) {
659 while (s_curr != R_NilValue) {
660 if (strcmp(CHAR(s_key), CHAR(CAR(TAG(s_curr)))) == 0) {
661 return s_curr;
662 }
663 s_curr = CDR(s_curr);
664 }
665 }
666 else {
667 while (CAR(s_curr) != R_NilValue) {
668 if (Ryaml_cmp(s_key, CAR(TAG(s_curr))) == 0) {
669 return s_curr;
670 }
671 s_curr = CDR(s_curr);
672 }
673 }
674
675 return NULL;
676 }
677
678 static int
expand_merge(s_merge_list,s_map_head,s_map_tail,coerce_keys,merge_warning)679 expand_merge(s_merge_list, s_map_head, s_map_tail, coerce_keys, merge_warning)
680 SEXP s_merge_list;
681 SEXP s_map_head;
682 SEXP *s_map_tail;
683 int coerce_keys;
684 int merge_warning;
685 {
686 SEXP s_merge_keys = NULL, s_value = NULL, s_key = NULL, s_result = NULL,
687 s_inspect = NULL;
688 int i = 0, count = 0;
689 const char *inspect = NULL;
690
691 s_merge_keys = coerce_keys ? GET_NAMES(s_merge_list) : getAttrib(s_merge_list, Ryaml_KeysSymbol);
692 for (i = 0; i < length(s_merge_list); i++) {
693 s_value = VECTOR_ELT(s_merge_list, i);
694 if (coerce_keys) {
695 s_key = STRING_ELT(s_merge_keys, i);
696 }
697 else {
698 s_key = VECTOR_ELT(s_merge_keys, i);
699 }
700
701 PROTECT(s_key);
702 s_result = find_map_entry(s_map_head, s_key, coerce_keys);
703 if (s_result != NULL) {
704 /* A matching key is already in the map, so ignore this one. */
705 if (merge_warning) {
706 if (coerce_keys) {
707 inspect = CHAR(s_key);
708 }
709 else {
710 PROTECT(s_inspect = Ryaml_inspect(s_key));
711 inspect = CHAR(STRING_ELT(s_inspect, 0));
712 }
713 warning("Duplicate map key ignored during merge: '%s'", inspect);
714
715 if (!coerce_keys) {
716 UNPROTECT(1); /* s_inspect */
717 }
718 }
719 }
720 else {
721 SETCDR(*s_map_tail, list1(s_value));
722 *s_map_tail = CDR(*s_map_tail);
723
724 SET_TAG(*s_map_tail, list2(s_key, ScalarLogical(TRUE)));
725 count++;
726 }
727 UNPROTECT(1); /* s_key */
728 }
729
730 return count;
731 }
732
733 static int
is_mergeable(s_merge_list,coerce_keys)734 is_mergeable(s_merge_list, coerce_keys)
735 SEXP s_merge_list;
736 int coerce_keys;
737 {
738 return (coerce_keys && Ryaml_is_named_list(s_merge_list)) ||
739 (!coerce_keys && Ryaml_is_pseudo_hash(s_merge_list));
740 }
741
742 /* Return -1 on error or number of entries added to map. */
743 static int
handle_map_entry(s_key,s_value,s_map_head,s_map_tail,coerce_keys,merge_warning)744 handle_map_entry(s_key, s_value, s_map_head, s_map_tail, coerce_keys, merge_warning)
745 SEXP s_key;
746 SEXP s_value;
747 SEXP s_map_head;
748 SEXP *s_map_tail;
749 int coerce_keys;
750 int merge_warning;
751 {
752 SEXP s_result = NULL, s_tag = NULL, s_inspect = NULL;
753 const char *inspect = NULL;
754 int len = 0, count = 0;
755
756 if (coerce_keys) {
757 /* (Possibly) convert this key to a character vector, and then save
758 * the first element in the vector (CHARSXP element). Throw away
759 * the containing vector, since it's not needed anymore. */
760 PROTECT(s_key = AS_CHARACTER(s_key));
761 len = length(s_key);
762
763 if (len == 0) {
764 warning("Empty character vector used as a list name");
765 s_key = mkCharCE("", CE_UTF8);
766 } else {
767 if (len > 1) {
768 warning("Character vector of length greater than 1 used as a list name");
769 }
770 s_key = STRING_ELT(s_key, 0);
771 }
772 UNPROTECT(1);
773 }
774
775 PROTECT(s_key);
776 s_result = find_map_entry(s_map_head, s_key, coerce_keys);
777 if (s_result != NULL) {
778 /* A matching key is already in the map. If the existing key is from a
779 * merge, it's okay to ignore it. If not, it's a duplicate key error. */
780 s_tag = TAG(s_result);
781 if (coerce_keys) {
782 inspect = CHAR(s_key);
783 }
784 else {
785 PROTECT(s_inspect = Ryaml_inspect(s_key));
786 inspect = CHAR(STRING_ELT(s_inspect, 0));
787 }
788
789 if (LOGICAL(CADR(s_tag))[0] == FALSE) {
790 Ryaml_set_error_msg("Duplicate map key: '%s'", inspect);
791 count = -1;
792 }
793 else if (merge_warning) {
794 warning("Duplicate map key ignored after merge: '%s'", inspect);
795 }
796
797 if (!coerce_keys) {
798 UNPROTECT(1); /* s_inspect */
799 }
800 } else {
801 SETCDR(*s_map_tail, list1(s_value));
802 *s_map_tail = CDR(*s_map_tail);
803 SET_TAG(*s_map_tail, list2(s_key, ScalarLogical(FALSE)));
804 count = 1;
805 }
806 UNPROTECT(1); /* s_key */
807
808 return count;
809 }
810
811 /* Return -1 on error or number of entries added to map. */
812 static int
handle_merge(s_value,s_map_head,s_map_tail,coerce_keys,merge_warning)813 handle_merge(s_value, s_map_head, s_map_tail, coerce_keys, merge_warning)
814 SEXP s_value;
815 SEXP s_map_head;
816 SEXP *s_map_tail;
817 int coerce_keys;
818 int merge_warning;
819 {
820 SEXP s_obj = NULL, s_inspect = NULL;
821 const char *inspect = NULL;
822 int i = 0, count = 0, len = 0;
823
824 if (is_mergeable(s_value, coerce_keys)) {
825 /* i.e.
826 * - &bar { hey: dude }
827 * - foo:
828 * hello: friend
829 * <<: *bar
830 */
831 count = expand_merge(s_value, s_map_head, s_map_tail, coerce_keys, merge_warning);
832 }
833 else if (TYPEOF(s_value) == VECSXP) {
834 /* i.e.
835 * - &bar { hey: dude }
836 * - &baz { hi: buddy }
837 * - foo:
838 * hello: friend
839 * <<: [*bar, *baz]
840 */
841
842 for (i = 0; i < length(s_value); i++) {
843 s_obj = VECTOR_ELT(s_value, i);
844 if (is_mergeable(s_obj, coerce_keys)) {
845 len = expand_merge(s_obj, s_map_head, s_map_tail, coerce_keys, merge_warning);
846 if (len >= 0) {
847 count += len;
848 }
849 else {
850 count = -1;
851 break;
852 }
853 }
854 else {
855 /* Illegal merge */
856 PROTECT(s_inspect = Ryaml_inspect(s_value));
857 inspect = CHAR(STRING_ELT(s_inspect, 0));
858 Ryaml_set_error_msg("Illegal merge: %s", inspect);
859 UNPROTECT(1);
860
861 count = -1;
862 break;
863 }
864 }
865 }
866 else {
867 /* Illegal merge */
868 PROTECT(s_inspect = Ryaml_inspect(s_value));
869 inspect = CHAR(STRING_ELT(s_inspect, 0));
870 Ryaml_set_error_msg("Illegal merge: %s", inspect);
871 UNPROTECT(1);
872
873 count = -1;
874 }
875
876 return count;
877 }
878
879 static int
handle_map(event,s_stack_head,s_stack_tail,s_handlers,coerce_keys,merge_override,merge_warning)880 handle_map(event, s_stack_head, s_stack_tail, s_handlers, coerce_keys, merge_override, merge_warning)
881 yaml_event_t *event;
882 SEXP s_stack_head;
883 SEXP *s_stack_tail;
884 SEXP s_handlers;
885 int coerce_keys;
886 int merge_override;
887 int merge_warning;
888 {
889 SEXP s_list = NULL, s_keys = NULL, s_key = NULL, s_value = NULL,
890 s_prev = NULL, s_curr = NULL, s_mapping_start = NULL,
891 s_interim_map_head = NULL, s_interim_map_tail = NULL, s_new_obj = NULL,
892 s_handler = NULL, s_tag = NULL;
893 int count = 0, i = 0, map_err = 0, handled = 0, coercion_err = 0, len = 0;
894 const char *tag = NULL, *original_tag = NULL;
895
896 /* Find beginning of last map */
897 s_curr = CDR(s_stack_head);
898 while (s_curr != R_NilValue) {
899 if (CAR(s_curr) == Ryaml_MappingStart) {
900 s_mapping_start = s_curr;
901 }
902 s_curr = CDR(s_curr);
903 }
904 if (s_mapping_start == NULL) {
905 Ryaml_set_error_msg("Internal error: couldn't find start of mapping!");
906 return 1;
907 }
908
909 /* Set up interim map */
910 PROTECT(s_interim_map_head = s_interim_map_tail = list1(Ryaml_MappingStart));
911
912 if (merge_override) {
913 /* If merge override is turned on, then normal map entries always take
914 * precedence over any merged map entries. Therefore, go through and look
915 * for any normal entries and place them in the interim map first. */
916
917 s_prev = s_mapping_start;
918 s_curr = CDR(s_mapping_start);
919 while (!map_err && s_curr != R_NilValue) {
920 s_key = CAR(s_curr);
921 s_value = CADR(s_curr);
922
923 if (!Ryaml_has_class(s_key, "_yaml.merge_")) {
924 len = handle_map_entry(s_key, s_value, s_interim_map_head, &s_interim_map_tail, coerce_keys, merge_warning);
925 if (len >= 0) {
926 count += len;
927
928 /* Remove key/value from stack to prevent double processing */
929 SETCDR(s_prev, CDDR(s_curr));
930 s_curr = CDDR(s_curr);
931 }
932 else {
933 map_err = 1;
934 }
935 }
936 else {
937 /* Skip over merge key/value */
938 s_prev = CDR(s_curr);
939 s_curr = CDDR(s_curr);
940 }
941 }
942 }
943
944 /* Iterate keys and values */
945 s_curr = CDR(s_mapping_start);
946 while (!map_err && s_curr != R_NilValue) {
947 s_key = CAR(s_curr);
948 s_value = CADR(s_curr);
949 s_curr = CDDR(s_curr);
950
951 if (Ryaml_has_class(s_key, "_yaml.merge_")) {
952 len = handle_merge(s_value, s_interim_map_head, &s_interim_map_tail, coerce_keys, merge_warning);
953 }
954 else {
955 if (merge_override) {
956 /* If merge override is turned on, merges should have already been processed. */
957 Ryaml_set_error_msg("Merge override failed");
958 map_err = 1;
959 break;
960 }
961
962 len = handle_map_entry(s_key, s_value, s_interim_map_head, &s_interim_map_tail, coerce_keys, merge_warning);
963 }
964
965 if (len >= 0) {
966 count += len;
967 }
968 else {
969 map_err = 1;
970 }
971 }
972
973 if (map_err) {
974 UNPROTECT(1); /* s_map */
975 return 1;
976 }
977
978 /* Initialize value list */
979 PROTECT(s_list = allocVector(VECSXP, count));
980
981 /* Initialize key list/vector */
982 if (coerce_keys) {
983 s_keys = NEW_STRING(count);
984 SET_NAMES(s_list, s_keys);
985 }
986 else {
987 s_keys = allocVector(VECSXP, count);
988 setAttrib(s_list, Ryaml_KeysSymbol, s_keys);
989 }
990
991 /* Iterate map entries */
992 s_curr = CDR(s_interim_map_head);
993 for (i = 0; i < count; i++) {
994 s_value = CAR(s_curr);
995 s_key = CAR(TAG(s_curr));
996 s_curr = CDR(s_curr);
997
998 SET_VECTOR_ELT(s_list, i, s_value);
999
1000 /* map key */
1001 if (coerce_keys) {
1002 SET_STRING_ELT(s_keys, i, s_key);
1003 }
1004 else {
1005 SET_VECTOR_ELT(s_keys, i, s_key);
1006 }
1007 }
1008 UNPROTECT(2); /* s_interim_map_head, s_list */
1009
1010 /* Tags! */
1011 s_tag = CAR(TAG(s_mapping_start));
1012 original_tag = tag = (s_tag == R_NilValue ? NULL : CHAR(s_tag));
1013 if (tag == NULL) {
1014 tag = "map";
1015 }
1016 else {
1017 tag = process_tag(tag);
1018 }
1019
1020 /* Look for a custom R handler */
1021 PROTECT(s_list);
1022 s_handler = Ryaml_find_handler(s_handlers, (const char *) tag);
1023 if (s_handler != R_NilValue) {
1024 if (Ryaml_run_handler(s_handler, s_list, &s_new_obj) != 0) {
1025 warning("an error occurred when handling type '%s'; using default handler", tag);
1026 }
1027 else {
1028 handled = 1;
1029 }
1030 }
1031 UNPROTECT(1); /* s_list */
1032
1033 if (!handled) {
1034 /* default handlers, ordered by most-used */
1035
1036 if (strcmp(tag, "map") == 0) {
1037 /* already a map */
1038 }
1039 else if (strcmp(tag, "str") == 0) {
1040 coercion_err = 1;
1041 }
1042 else if (strcmp(tag, "seq") == 0) {
1043 coercion_err = 1;
1044 }
1045 else if (strcmp(tag, "int#na") == 0) {
1046 coercion_err = 1;
1047 }
1048 else if (strcmp(tag, "int") == 0 || strncmp(tag, "int#", 4) == 0) {
1049 coercion_err = 1;
1050 }
1051 else if (strcmp(tag, "float") == 0 || strcmp(tag, "float#fix") == 0 || strcmp(tag, "float#exp") == 0) {
1052 coercion_err = 1;
1053 }
1054 else if (strcmp(tag, "bool#yes") == 0) {
1055 coercion_err = 1;
1056 }
1057 else if (strcmp(tag, "bool#no") == 0) {
1058 coercion_err = 1;
1059 }
1060 else if (strcmp(tag, "bool#na") == 0) {
1061 coercion_err = 1;
1062 }
1063 else if (strcmp(tag, "omap") == 0) {
1064 coercion_err = 1;
1065 }
1066 else if (strcmp(tag, "merge") == 0) {
1067 coercion_err = 1;
1068 }
1069 else if (strcmp(tag, "float#na") == 0) {
1070 coercion_err = 1;
1071 }
1072 else if (strcmp(tag, "float#nan") == 0) {
1073 coercion_err = 1;
1074 }
1075 else if (strcmp(tag, "float#inf") == 0) {
1076 coercion_err = 1;
1077 }
1078 else if (strcmp(tag, "float#neginf") == 0) {
1079 coercion_err = 1;
1080 }
1081 else if (strcmp(tag, "str#na") == 0) {
1082 coercion_err = 1;
1083 }
1084 else if (strcmp(tag, "null") == 0) {
1085 s_new_obj = R_NilValue;
1086 }
1087 else if (strcmp(tag, "expr") == 0) {
1088 coercion_err = 1;
1089 }
1090 }
1091
1092 if (coercion_err == 1) {
1093 if (Ryaml_error_msg[0] == 0) {
1094 Ryaml_set_error_msg("Invalid tag: %s for map", original_tag);
1095 }
1096 return 1;
1097 }
1098
1099 SETCAR(s_mapping_start, s_new_obj == NULL ? s_list : s_new_obj);
1100 SETCDR(s_mapping_start, R_NilValue);
1101 *s_stack_tail = s_mapping_start;
1102
1103 return 0;
1104 }
1105
1106 static void
possibly_record_alias(s_anchor,s_aliases_tail,s_obj)1107 possibly_record_alias(s_anchor, s_aliases_tail, s_obj)
1108 SEXP s_anchor;
1109 SEXP *s_aliases_tail;
1110 SEXP s_obj;
1111 {
1112 if (s_anchor == NULL || TYPEOF(s_anchor) != CHARSXP) return;
1113
1114 SETCDR(*s_aliases_tail, list1(s_obj));
1115 *s_aliases_tail = CDR(*s_aliases_tail);
1116 SET_TAG(*s_aliases_tail, s_anchor);
1117 }
1118
1119 SEXP
Ryaml_unserialize_from_yaml(s_string,s_as_named_list,s_handlers,s_error_label,s_eval_expr,s_eval_warning,s_merge_precedence,s_merge_warning)1120 Ryaml_unserialize_from_yaml(s_string, s_as_named_list, s_handlers, s_error_label,
1121 s_eval_expr, s_eval_warning, s_merge_precedence, s_merge_warning)
1122 SEXP s_string;
1123 SEXP s_as_named_list;
1124 SEXP s_handlers;
1125 SEXP s_error_label;
1126 SEXP s_eval_expr;
1127 SEXP s_eval_warning;
1128 SEXP s_merge_precedence;
1129 SEXP s_merge_warning;
1130 {
1131 SEXP s_retval = NULL, s_stack_head = NULL, s_stack_tail = NULL,
1132 s_aliases_head = NULL, s_aliases_tail = NULL, s_anchor = NULL;
1133 yaml_parser_t parser;
1134 yaml_event_t event;
1135 const char *string = NULL, *error_label = NULL, *merge_precedence = NULL;
1136 char *error_msg_copy = NULL;
1137 long len = 0;
1138 int as_named_list = 0, done = 0, err = 0, eval_expr = 0, eval_warning = 0,
1139 merge_override = 0, merge_warning = 0;
1140
1141 if (!isString(s_string) || length(s_string) != 1) {
1142 error("string argument must be a character vector of length 1");
1143 return R_NilValue;
1144 }
1145
1146 if (!isLogical(s_as_named_list) || length(s_as_named_list) != 1) {
1147 error("as.named.list argument must be a logical vector of length 1");
1148 return R_NilValue;
1149 }
1150
1151 if (s_error_label == R_NilValue) {
1152 error_label = NULL;
1153 }
1154 else if (!isString(s_error_label) || length(s_error_label) != 1) {
1155 error("error.label argument must be either NULL or a character vector of length 1");
1156 return R_NilValue;
1157 } else {
1158 error_label = CHAR(STRING_ELT(s_error_label, 0));
1159 }
1160
1161 if (!isLogical(s_eval_expr) || length(s_eval_expr) != 1) {
1162 error("eval.expr argument must be a logical vector of length 1");
1163 return R_NilValue;
1164 }
1165
1166 if (!isLogical(s_eval_warning) || length(s_eval_warning) != 1) {
1167 error("eval.warning argument must be a logical vector of length 1");
1168 return R_NilValue;
1169 }
1170
1171 if (!isString(s_merge_precedence) || length(s_merge_precedence) != 1) {
1172 error("merge.precedence argument must be a character vector of length 1");
1173 return R_NilValue;
1174 }
1175 else {
1176 merge_precedence = CHAR(STRING_ELT(s_merge_precedence, 0));
1177 if (strcmp(merge_precedence, "order") == 0) {
1178 merge_override = 0;
1179 }
1180 else if (strcmp(merge_precedence, "override") == 0) {
1181 merge_override = 1;
1182 }
1183 else {
1184 error("merge.precedence must be either 'ordered' or 'override'");
1185 return R_NilValue;
1186 }
1187 }
1188
1189 if (!isLogical(s_merge_warning) || length(s_merge_warning) != 1) {
1190 error("merge.warning argument must be a logical vector of length 1");
1191 return R_NilValue;
1192 }
1193
1194 PROTECT(s_handlers = Ryaml_sanitize_handlers(s_handlers));
1195
1196 string = CHAR(STRING_ELT(s_string, 0));
1197 len = length(STRING_ELT(s_string, 0));
1198 as_named_list = LOGICAL(s_as_named_list)[0];
1199 eval_expr = LOGICAL(s_eval_expr)[0];
1200 eval_warning = LOGICAL(s_eval_warning)[0];
1201 merge_warning = LOGICAL(s_merge_warning)[0];
1202
1203 yaml_parser_initialize(&parser);
1204 yaml_parser_set_input_string(&parser, (const unsigned char *)string, len);
1205
1206 PROTECT(s_stack_head = s_stack_tail = list1(Ryaml_Sentinel));
1207 PROTECT(s_aliases_head = s_aliases_tail = list1(Ryaml_Sentinel));
1208 Ryaml_error_msg[0] = 0;
1209 while (!done) {
1210 if (yaml_parser_parse(&parser, &event)) {
1211 err = 0;
1212
1213 switch (event.type) {
1214 case YAML_NO_EVENT:
1215 case YAML_STREAM_START_EVENT:
1216 case YAML_DOCUMENT_START_EVENT:
1217 case YAML_DOCUMENT_END_EVENT:
1218 break;
1219
1220 case YAML_ALIAS_EVENT:
1221 #if DEBUG
1222 Rprintf("ALIAS: %s\n", event.data.alias.anchor);
1223 #endif
1224 handle_alias(&event, &s_stack_tail, s_aliases_head);
1225 break;
1226
1227 case YAML_SCALAR_EVENT:
1228 #if DEBUG
1229 Rprintf("SCALAR: %s (%s) [%s]\n", event.data.scalar.value, event.data.scalar.tag, event.data.scalar.anchor);
1230 #endif
1231 err = handle_scalar(&event, &s_stack_tail, s_handlers, eval_expr, eval_warning);
1232 if (!err && event.data.scalar.anchor != NULL) {
1233 PROTECT(s_anchor = mkCharCE((char *)event.data.scalar.anchor, CE_UTF8));
1234 possibly_record_alias(s_anchor, &s_aliases_tail, CAR(s_stack_tail));
1235 UNPROTECT(1);
1236 }
1237 break;
1238
1239 case YAML_SEQUENCE_START_EVENT:
1240 #if DEBUG
1241 Rprintf("SEQUENCE START: (%s) [%s]\n", event.data.sequence_start.tag, event.data.sequence_start.anchor);
1242 #endif
1243 handle_structure_start(&event, &s_stack_tail, 0);
1244 break;
1245
1246 case YAML_SEQUENCE_END_EVENT:
1247 #if DEBUG
1248 Rprintf("SEQUENCE END\n");
1249 #endif
1250 err = handle_sequence(&event, s_stack_head, &s_stack_tail, s_handlers, as_named_list);
1251 if (!err) {
1252 s_anchor = CADR(TAG(s_stack_tail));
1253 possibly_record_alias(s_anchor, &s_aliases_tail, CAR(s_stack_tail));
1254 SET_TAG(s_stack_tail, R_NilValue);
1255 }
1256 break;
1257
1258 case YAML_MAPPING_START_EVENT:
1259 #if DEBUG
1260 Rprintf("MAPPING START: (%s) [%s]\n", event.data.mapping_start.tag, event.data.mapping_start.anchor);
1261 #endif
1262 handle_structure_start(&event, &s_stack_tail, 1);
1263 break;
1264
1265 case YAML_MAPPING_END_EVENT:
1266 #if DEBUG
1267 Rprintf("MAPPING END\n");
1268 #endif
1269 err = handle_map(&event, s_stack_head, &s_stack_tail, s_handlers, as_named_list, merge_override, merge_warning);
1270 if (!err) {
1271 s_anchor = CADR(TAG(s_stack_tail));
1272 possibly_record_alias(s_anchor, &s_aliases_tail, CAR(s_stack_tail));
1273 SET_TAG(s_stack_tail, R_NilValue);
1274 }
1275
1276 break;
1277
1278 case YAML_STREAM_END_EVENT:
1279 if (CADR(s_stack_head) != Ryaml_Sentinel) {
1280 s_retval = CADR(s_stack_head);
1281 }
1282 else {
1283 s_retval = R_NilValue;
1284 }
1285
1286 done = 1;
1287 break;
1288 }
1289
1290 if (err) {
1291 s_retval = R_NilValue;
1292 done = 1;
1293 }
1294 }
1295 else {
1296 s_retval = R_NilValue;
1297
1298 /* Parser error */
1299 switch (parser.error) {
1300 case YAML_MEMORY_ERROR:
1301 Ryaml_set_error_msg("Memory error: Not enough memory for parsing");
1302 break;
1303
1304 case YAML_READER_ERROR:
1305 if (parser.problem_value != -1) {
1306 Ryaml_set_error_msg("Reader error: %s: #%X at %d", parser.problem,
1307 parser.problem_value, (int)parser.problem_offset);
1308 }
1309 else {
1310 Ryaml_set_error_msg("Reader error: %s at %d", parser.problem,
1311 (int)parser.problem_offset);
1312 }
1313 break;
1314
1315 case YAML_SCANNER_ERROR:
1316 if (parser.context) {
1317 Ryaml_set_error_msg("Scanner error: %s at line %d, column %d "
1318 "%s at line %d, column %d\n", parser.context,
1319 (int)parser.context_mark.line+1,
1320 (int)parser.context_mark.column+1,
1321 parser.problem, (int)parser.problem_mark.line+1,
1322 (int)parser.problem_mark.column+1);
1323 }
1324 else {
1325 Ryaml_set_error_msg("Scanner error: %s at line %d, column %d",
1326 parser.problem, (int)parser.problem_mark.line+1,
1327 (int)parser.problem_mark.column+1);
1328 }
1329 break;
1330
1331 case YAML_PARSER_ERROR:
1332 if (parser.context) {
1333 Ryaml_set_error_msg("Parser error: %s at line %d, column %d "
1334 "%s at line %d, column %d", parser.context,
1335 (int)parser.context_mark.line+1,
1336 (int)parser.context_mark.column+1,
1337 parser.problem, (int)parser.problem_mark.line+1,
1338 (int)parser.problem_mark.column+1);
1339 }
1340 else {
1341 Ryaml_set_error_msg("Parser error: %s at line %d, column %d",
1342 parser.problem, (int)parser.problem_mark.line+1,
1343 (int)parser.problem_mark.column+1);
1344 }
1345 break;
1346
1347 default:
1348 /* Couldn't happen unless there is an undocumented/unhandled error
1349 * from LibYAML. */
1350 Ryaml_set_error_msg("Internal error: unknown parser error");
1351 break;
1352 }
1353 done = 1;
1354 }
1355
1356 yaml_event_delete(&event);
1357 }
1358 yaml_parser_delete(&parser);
1359
1360 if (Ryaml_error_msg[0] != 0) {
1361 /* Prepend label to error message if specified */
1362 if (error_label != NULL) {
1363 error_msg_copy = (char *)malloc(sizeof(char) * ERROR_MSG_SIZE);
1364 if (error_msg_copy == NULL) {
1365 Ryaml_set_error_msg("Ran out of memory!");
1366 } else {
1367 memcpy(error_msg_copy, Ryaml_error_msg, ERROR_MSG_SIZE);
1368 Ryaml_set_error_msg("(%s) %s", error_label, error_msg_copy);
1369 free(error_msg_copy);
1370 }
1371 }
1372 error(Ryaml_error_msg);
1373 }
1374
1375 UNPROTECT(3); /* s_stack_head, s_aliases_head, s_handlers */
1376
1377 return s_retval;
1378 }
1379