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