Ruby  1.9.3p448(2013-06-27revision41675)
emitter.c
Go to the documentation of this file.
1 /*
2  * emitter.c
3  *
4  * $Author: naruse $
5  *
6  * Copyright (C) 2003 why the lucky stiff
7  *
8  * All Base64 code from Ruby's pack.c.
9  * Ruby is Copyright (C) 1993-2007 Yukihiro Matsumoto
10  */
11 #include "ruby/ruby.h"
12 
13 #include <stdio.h>
14 #include <string.h>
15 
16 #include "syck.h"
17 
18 #define DEFAULT_ANCHOR_FORMAT "id%03d"
19 
20 const char hex_table[] =
21 "0123456789ABCDEF";
22 static char b64_table[] =
23 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
24 
25 /*
26  * Built-in base64 (from Ruby's pack.c)
27  */
28 char *
29 syck_base64enc( char *s, long len )
30 {
31  long i = 0;
32  int padding = '=';
33  char *buff = S_ALLOC_N(char, len * 4 / 3 + 6);
34 
35  while (len >= 3) {
36  buff[i++] = b64_table[077 & (*s >> 2)];
37  buff[i++] = b64_table[077 & (((*s << 4) & 060) | ((s[1] >> 4) & 017))];
38  buff[i++] = b64_table[077 & (((s[1] << 2) & 074) | ((s[2] >> 6) & 03))];
39  buff[i++] = b64_table[077 & s[2]];
40  s += 3;
41  len -= 3;
42  }
43  if (len == 2) {
44  buff[i++] = b64_table[077 & (*s >> 2)];
45  buff[i++] = b64_table[077 & (((*s << 4) & 060) | ((s[1] >> 4) & 017))];
46  buff[i++] = b64_table[077 & (((s[1] << 2) & 074) | (('\0' >> 6) & 03))];
47  buff[i++] = padding;
48  }
49  else if (len == 1) {
50  buff[i++] = b64_table[077 & (*s >> 2)];
51  buff[i++] = b64_table[077 & (((*s << 4) & 060) | (('\0' >> 4) & 017))];
52  buff[i++] = padding;
53  buff[i++] = padding;
54  }
55  buff[i++] = '\n';
56  return buff;
57 }
58 
59 char *
60 syck_base64dec( char *s, long len )
61 {
62  int a = -1,b = -1,c = 0,d;
63  static int first = 1;
64  static int b64_xtable[256];
65  char *ptr = syck_strndup( s, len );
66  char *end = ptr;
67  char *send = s + len;
68 
69  if (first) {
70  int i;
71  first = 0;
72 
73  for (i = 0; i < 256; i++) {
74  b64_xtable[i] = -1;
75  }
76  for (i = 0; i < 64; i++) {
77  b64_xtable[(int)b64_table[i]] = i;
78  }
79  }
80  while (s < send) {
81  while (s[0] == '\r' || s[0] == '\n') { s++; }
82  if ((a = b64_xtable[(int)s[0]]) == -1) break;
83  if ((b = b64_xtable[(int)s[1]]) == -1) break;
84  if ((c = b64_xtable[(int)s[2]]) == -1) break;
85  if ((d = b64_xtable[(int)s[3]]) == -1) break;
86  *end++ = a << 2 | b >> 4;
87  *end++ = b << 4 | c >> 2;
88  *end++ = c << 6 | d;
89  s += 4;
90  }
91  if (a != -1 && b != -1) {
92  if (s + 2 < send && s[2] == '=')
93  *end++ = a << 2 | b >> 4;
94  if (c != -1 && s + 3 < send && s[3] == '=') {
95  *end++ = a << 2 | b >> 4;
96  *end++ = b << 4 | c >> 2;
97  }
98  }
99  *end = '\0';
100  /*RSTRING_LEN(buf) = ptr - RSTRING_PTR(buf);*/
101  return ptr;
102 }
103 
104 /*
105  * Allocate an emitter
106  */
107 SyckEmitter *
109 {
110  SyckEmitter *e;
111  e = S_ALLOC( SyckEmitter );
112  e->headless = 0;
113  e->use_header = 0;
114  e->use_version = 0;
115  e->sort_keys = 0;
116  e->anchor_format = NULL;
117  e->explicit_typing = 0;
118  e->best_width = 80;
119  e->style = scalar_none;
120  e->stage = doc_open;
121  e->indent = 2;
122  e->level = -1;
123  e->anchors = NULL;
124  e->markers = NULL;
125  e->anchored = NULL;
127  e->buffer = NULL;
128  e->marker = NULL;
129  e->bufpos = 0;
130  e->emitter_handler = NULL;
131  e->output_handler = NULL;
132  e->lvl_idx = 0;
133  e->lvl_capa = ALLOC_CT;
134  e->levels = S_ALLOC_N( SyckLevel, e->lvl_capa );
136  e->bonus = NULL;
137  return e;
138 }
139 
140 int
141 syck_st_free_anchors( char *key, char *name, char *arg )
142 {
143  S_FREE( name );
144  return ST_CONTINUE;
145 }
146 
147 void
149 {
150  /*
151  * Free the anchor tables
152  */
153  if ( e->anchors != NULL )
154  {
156  st_free_table( e->anchors );
157  e->anchors = NULL;
158  }
159 
160  if ( e->anchored != NULL )
161  {
162  st_free_table( e->anchored );
163  e->anchored = NULL;
164  }
165 
166  /*
167  * Free the markers tables
168  */
169  if ( e->markers != NULL )
170  {
171  st_free_table( e->markers );
172  e->markers = NULL;
173  }
174 }
175 
176 SyckLevel *
178 {
179  return &e->levels[e->lvl_idx-1];
180 }
181 
182 SyckLevel *
184 {
185  return &e->levels[e->lvl_idx-2];
186 }
187 
188 void
190 {
191  ASSERT( e != NULL );
192 
193  /* The root level should never be popped */
194  if ( e->lvl_idx <= 1 ) return;
195 
196  e->lvl_idx -= 1;
197  free( e->levels[e->lvl_idx].domain );
198 }
199 
200 void
202 {
203  ASSERT( e != NULL );
204  if ( e->lvl_idx + 1 > e->lvl_capa )
205  {
206  e->lvl_capa += ALLOC_CT;
208  }
209 
210  ASSERT( len > e->levels[e->lvl_idx-1].spaces );
211  e->levels[e->lvl_idx].spaces = len;
212  e->levels[e->lvl_idx].ncount = 0;
213  e->levels[e->lvl_idx].domain = syck_strndup( e->levels[e->lvl_idx-1].domain, strlen( e->levels[e->lvl_idx-1].domain ) );
214  e->levels[e->lvl_idx].status = status;
215  e->levels[e->lvl_idx].anctag = 0;
216  e->lvl_idx += 1;
217 }
218 
219 void
221 {
222  while ( e->lvl_idx > 1 )
223  {
225  }
226 
227  if ( e->lvl_idx < 1 )
228  {
229  e->lvl_idx = 1;
230  e->levels[0].spaces = -1;
231  e->levels[0].ncount = 0;
232  e->levels[0].domain = syck_strndup( "", 0 );
233  e->levels[0].anctag = 0;
234  }
235  e->levels[0].status = syck_lvl_header;
236 }
237 
238 void
240 {
241  e->emitter_handler = hdlr;
242 }
243 
244 void
246 {
247  e->output_handler = hdlr;
248 }
249 
250 void
252 {
253  /*
254  * Free tables
255  */
258  S_FREE( e->levels[0].domain );
259  S_FREE( e->levels );
260  if ( e->buffer != NULL )
261  {
262  S_FREE( e->buffer );
263  }
264  S_FREE( e );
265 }
266 
267 void
269 {
270  if ( e->buffer == NULL )
271  {
272  e->buffer = S_ALLOC_N( char, e->bufsize );
273  S_MEMZERO( e->buffer, char, e->bufsize );
274  }
275  e->buffer[0] = '\0';
276  e->marker = e->buffer;
277  e->bufpos = 0;
278 }
279 
280 /*
281  * Raw write to the emitter buffer.
282  */
283 void
284 syck_emitter_write( SyckEmitter *e, const char *str, long len )
285 {
286  long at;
287  ASSERT( str != NULL );
288  if ( e->buffer == NULL )
289  {
290  syck_emitter_clear( e );
291  }
292 
293  /*
294  * Flush if at end of buffer
295  */
296  at = e->marker - e->buffer;
297  if ( len + at >= (long)e->bufsize )
298  {
299  syck_emitter_flush( e, 0 );
300  for (;;) {
301  long rest = e->bufsize - (e->marker - e->buffer);
302  if (len <= rest) break;
303  S_MEMCPY( e->marker, str, char, rest );
304  e->marker += rest;
305  str += rest;
306  len -= rest;
307  syck_emitter_flush( e, 0 );
308  }
309  }
310 
311  /*
312  * Write to buffer
313  */
314  S_MEMCPY( e->marker, str, char, len );
315  e->marker += len;
316 }
317 
318 /*
319  * Write a chunk of data out.
320  */
321 void
322 syck_emitter_flush( SyckEmitter *e, long check_room )
323 {
324  /*
325  * Check for enough space in the buffer for check_room length.
326  */
327  if ( check_room > 0 )
328  {
329  if ( (long)e->bufsize > ( e->marker - e->buffer ) + check_room )
330  {
331  return;
332  }
333  }
334  else
335  {
336  check_room = e->bufsize;
337  }
338 
339  /*
340  * Commit buffer.
341  */
342  if ( check_room > e->marker - e->buffer )
343  {
344  check_room = e->marker - e->buffer;
345  }
346  (e->output_handler)( e, e->buffer, check_room );
347  e->bufpos += check_room;
348  e->marker -= check_room;
349 }
350 
351 /*
352  * Start emitting from the given node, check for anchoring and then
353  * issue the callback to the emitter handler.
354  */
355 void
357 {
358  SYMID oid;
359  char *anchor_name = NULL;
360  int indent = 0;
361  long x = 0;
363 
364  /*
365  * Determine headers.
366  */
367  if ( e->stage == doc_open && ( e->headless == 0 || e->use_header == 1 ) )
368  {
369  if ( e->use_version == 1 )
370  {
371  char *header = S_ALLOC_N( char, 64 );
372  S_MEMZERO( header, char, 64 );
373  sprintf( header, "--- %%YAML:%d.%d ", SYCK_YAML_MAJOR, SYCK_YAML_MINOR );
374  syck_emitter_write( e, header, strlen( header ) );
375  S_FREE( header );
376  }
377  else
378  {
379  syck_emitter_write( e, "--- ", 4 );
380  }
381  e->stage = doc_processing;
382  }
383 
384  /* Add new level */
385  if ( lvl->spaces >= 0 ) {
386  indent = lvl->spaces + e->indent;
387  }
389  lvl = syck_emitter_current_level( e );
390 
391  /* Look for anchor */
392  if ( e->anchors != NULL &&
393  st_lookup( e->markers, n, (st_data_t *)&oid ) &&
394  st_lookup( e->anchors, (st_data_t)oid, (void *)&anchor_name ) )
395  {
396  if ( e->anchored == NULL )
397  {
398  e->anchored = st_init_numtable();
399  }
400 
401  if ( ! st_lookup( e->anchored, (st_data_t)anchor_name, (st_data_t *)&x ) )
402  {
403  char *an = S_ALLOC_N( char, strlen( anchor_name ) + 3 );
404  sprintf( an, "&%s ", anchor_name );
405  syck_emitter_write( e, an, strlen( anchor_name ) + 2 );
406  free( an );
407 
408  x = 1;
409  st_insert( e->anchored, (st_data_t)anchor_name, (st_data_t)x );
410  lvl->anctag = 1;
411  }
412  else
413  {
414  char *an = S_ALLOC_N( char, strlen( anchor_name ) + 2 );
415  sprintf( an, "*%s", anchor_name );
416  syck_emitter_write( e, an, strlen( anchor_name ) + 1 );
417  free( an );
418 
419  goto end_emit;
420  }
421  }
422 
423  (e->emitter_handler)( e, n );
424 
425  /* Pop the level */
426 end_emit:
428  if ( e->lvl_idx == 1 ) {
429  syck_emitter_write( e, "\n", 1 );
430  e->headless = 0;
431  e->stage = doc_open;
432  }
433 }
434 
435 /*
436  * Determine what tag needs to be written, based on the taguri of the node
437  * and the implicit tag which would be assigned to this node. If a tag is
438  * required, write the tag.
439  */
440 void syck_emit_tag( SyckEmitter *e, const char *tag, const char *ignore )
441 {
442  SyckLevel *lvl;
443  if ( tag == NULL ) return;
444  if ( ignore != NULL && syck_tagcmp( tag, ignore ) == 0 && e->explicit_typing == 0 ) return;
445  lvl = syck_emitter_current_level( e );
446 
447  /* implicit */
448  if ( strlen( tag ) == 0 ) {
449  syck_emitter_write( e, "! ", 2 );
450 
451  /* global types */
452  } else if ( strncmp( tag, "tag:", 4 ) == 0 ) {
453  int taglen = (int)strlen( tag );
454  syck_emitter_write( e, "!", 1 );
455  if ( strncmp( tag + 4, YAML_DOMAIN, strlen( YAML_DOMAIN ) ) == 0 ) {
456  int skip = 4 + strlen( YAML_DOMAIN ) + 1;
457  syck_emitter_write( e, tag + skip, taglen - skip );
458  } else {
459  const char *subd = tag + 4;
460  while ( *subd != ':' && *subd != '\0' ) subd++;
461  if ( *subd == ':' ) {
462  if ( subd - tag > ( (long)( strlen( YAML_DOMAIN ) + 5 )) &&
463  strncmp( subd - strlen( YAML_DOMAIN ), YAML_DOMAIN, strlen( YAML_DOMAIN ) ) == 0 ) {
464  syck_emitter_write( e, tag + 4, subd - strlen( YAML_DOMAIN ) - ( tag + 4 ) - 1 );
465  syck_emitter_write( e, "/", 1 );
466  syck_emitter_write( e, subd + 1, ( tag + taglen ) - ( subd + 1 ) );
467  } else {
468  syck_emitter_write( e, tag + 4, subd - ( tag + 4 ) );
469  syck_emitter_write( e, "/", 1 );
470  syck_emitter_write( e, subd + 1, ( tag + taglen ) - ( subd + 1 ) );
471  }
472  } else {
473  /* TODO: Invalid tag (no colon after domain) */
474  return;
475  }
476  }
477  syck_emitter_write( e, " ", 1 );
478 
479  /* private types */
480  } else if ( strncmp( tag, "x-private:", 10 ) == 0 ) {
481  syck_emitter_write( e, "!!", 2 );
482  syck_emitter_write( e, tag + 10, strlen( tag ) - 10 );
483  syck_emitter_write( e, " ", 1 );
484  }
485  lvl->anctag = 1;
486 }
487 
488 /*
489  * Emit a newline and an appropriately spaced indent.
490  */
492 {
493  int i;
495  if ( e->bufpos == 0 && ( e->marker - e->buffer ) == 0 ) return;
496  if ( lvl->spaces >= 0 ) {
497  char *spcs = S_ALLOC_N( char, lvl->spaces + 2 );
498 
499  spcs[0] = '\n'; spcs[lvl->spaces + 1] = '\0';
500  for ( i = 0; i < lvl->spaces; i++ ) spcs[i+1] = ' ';
501  syck_emitter_write( e, spcs, lvl->spaces + 1 );
502  free( spcs );
503  }
504 }
505 
506 /* Clear the scan */
507 #define SCAN_NONE 0
508 /* All printable characters? */
509 #define SCAN_NONPRINT 1
510 /* Any indented lines? */
511 #define SCAN_INDENTED 2
512 /* Larger than the requested width? */
513 #define SCAN_WIDE 4
514 /* Opens or closes with whitespace? */
515 #define SCAN_WHITEEDGE 8
516 /* Contains a newline */
517 #define SCAN_NEWLINE 16
518 /* Contains a single quote */
519 #define SCAN_SINGLEQ 32
520 /* Contains a double quote */
521 #define SCAN_DOUBLEQ 64
522 /* Starts with a token */
523 #define SCAN_INDIC_S 128
524 /* Contains a flow indicator */
525 #define SCAN_INDIC_C 256
526 /* Ends without newlines */
527 #define SCAN_NONL_E 512
528 /* Ends with many newlines */
529 #define SCAN_MANYNL_E 1024
530 /* Contains flow map indicators */
531 #define SCAN_FLOWMAP 2048
532 /* Contains flow seq indicators */
533 #define SCAN_FLOWSEQ 4096
534 /* Contains a valid doc separator */
535 #define SCAN_DOCSEP 8192
536 
537 /*
538  * Basic printable test for LATIN-1 characters.
539  */
540 int
541 syck_scan_scalar( int req_width, const char *cursor, long len )
542 {
543  long i = 0, start = 0;
544  int flags = SCAN_NONE;
545 
546  if ( len < 1 ) return flags;
547 
548  /* c-indicators from the spec */
549  if ( cursor[0] == '[' || cursor[0] == ']' ||
550  cursor[0] == '{' || cursor[0] == '}' ||
551  cursor[0] == '!' || cursor[0] == '*' ||
552  cursor[0] == '&' || cursor[0] == '|' ||
553  cursor[0] == '>' || cursor[0] == '\'' ||
554  cursor[0] == '"' || cursor[0] == '#' ||
555  cursor[0] == '%' || cursor[0] == '@' ||
556  cursor[0] == '&' ) {
557  flags |= SCAN_INDIC_S;
558  }
559  if ( ( cursor[0] == '-' || cursor[0] == ':' ||
560  cursor[0] == '?' || cursor[0] == ',' ) &&
561  ( len == 1 || cursor[1] == ' ' || cursor[1] == '\n' ) )
562  {
563  flags |= SCAN_INDIC_S;
564  }
565 
566  /* whitespace edges */
567  if ( cursor[len-1] != '\n' ) {
568  flags |= SCAN_NONL_E;
569  } else if ( len > 1 && cursor[len-2] == '\n' ) {
570  flags |= SCAN_MANYNL_E;
571  }
572  if (
573  ( len > 0 && ( cursor[0] == ' ' || cursor[0] == '\t' || cursor[0] == '\n' || cursor[0] == '\r' ) ) ||
574  ( len > 1 && ( cursor[len-1] == ' ' || cursor[len-1] == '\t' ) )
575  ) {
576  flags |= SCAN_WHITEEDGE;
577  }
578 
579  /* opening doc sep */
580  if ( len >= 3 && strncmp( cursor, "---", 3 ) == 0 )
581  flags |= SCAN_DOCSEP;
582 
583  /* scan string */
584  for ( i = 0; i < len; i++ ) {
585 
586  if ( ! ( cursor[i] == 0x9 ||
587  cursor[i] == 0xA ||
588  cursor[i] == 0xD ||
589  ( cursor[i] >= 0x20 && cursor[i] <= 0x7E ) )
590  ) {
591  flags |= SCAN_NONPRINT;
592  }
593  else if ( cursor[i] == '\n' ) {
594  flags |= SCAN_NEWLINE;
595  if ( len - i >= 3 && strncmp( &cursor[i+1], "---", 3 ) == 0 )
596  flags |= SCAN_DOCSEP;
597  if ( cursor[i+1] == ' ' || cursor[i+1] == '\t' )
598  flags |= SCAN_INDENTED;
599  if ( req_width > 0 && i - start > req_width )
600  flags |= SCAN_WIDE;
601  start = i;
602  }
603  else if ( cursor[i] == '\'' )
604  {
605  flags |= SCAN_SINGLEQ;
606  }
607  else if ( cursor[i] == '"' )
608  {
609  flags |= SCAN_DOUBLEQ;
610  }
611  else if ( cursor[i] == ']' )
612  {
613  flags |= SCAN_FLOWSEQ;
614  }
615  else if ( cursor[i] == '}' )
616  {
617  flags |= SCAN_FLOWMAP;
618  }
619  /* remember, if plain collections get implemented, to add nb-plain-flow-char */
620  else if ( ( cursor[i] == ' ' && cursor[i+1] == '#' ) ||
621  ( cursor[i] == ':' &&
622  ( cursor[i+1] == ' ' || cursor[i+1] == '\n' || i == len - 1 ) ) )
623  {
624  flags |= SCAN_INDIC_C;
625  }
626  else if ( cursor[i] == ',' &&
627  ( cursor[i+1] == ' ' || cursor[i+1] == '\n' || i == len - 1 ) )
628  {
629  flags |= SCAN_FLOWMAP;
630  flags |= SCAN_FLOWSEQ;
631  }
632  }
633 
634  /* printf( "---STR---\n%s\nFLAGS: %d\n", cursor, flags ); */
635  return flags;
636 }
637 /*
638  * All scalars should be emitted through this function, which determines an appropriate style,
639  * tag and indent.
640  */
641 void syck_emit_scalar( SyckEmitter *e, const char *tag, enum scalar_style force_style, int force_indent, int force_width,
642  char keep_nl, const char *str, long len )
643 {
644  enum scalar_style favor_style = scalar_literal;
645  SyckLevel *parent = syck_emitter_parent_level( e );
647  int scan = 0;
648  const char *match_implicit;
649  char *implicit;
650 
651  if ( str == NULL ) str = "";
652 
653  /* No empty nulls as map keys */
654  if ( len == 0 && ( parent->status == syck_lvl_map || parent->status == syck_lvl_imap ) &&
655  parent->ncount % 2 == 1 && syck_tagcmp( tag, "tag:yaml.org,2002:null" ) == 0 )
656  {
657  str = "~";
658  len = 1;
659  }
660 
661  scan = syck_scan_scalar( force_width, str, len );
662  match_implicit = syck_match_implicit( str, len );
663 
664  /* quote strings which default to implicits */
665  implicit = syck_taguri( YAML_DOMAIN, match_implicit, (int)strlen( match_implicit ) );
666  if ( syck_tagcmp( tag, implicit ) != 0 && syck_tagcmp( tag, "tag:yaml.org,2002:str" ) == 0 ) {
667  force_style = scalar_2quote;
668  } else {
669  /* complex key */
670  if ( parent->status == syck_lvl_map && parent->ncount % 2 == 1 &&
671  ( !( tag == NULL ||
672  ( implicit != NULL && syck_tagcmp( tag, implicit ) == 0 && e->explicit_typing == 0 ) ) ) )
673  {
674  syck_emitter_write( e, "? ", 2 );
675  parent->status = syck_lvl_mapx;
676  }
677  syck_emit_tag( e, tag, implicit );
678  }
679  S_FREE( implicit );
680 
681  /* if still arbitrary, sniff a good block style. */
682  if ( force_style == scalar_none ) {
683  if ( scan & SCAN_NEWLINE ) {
684  force_style = scalar_literal;
685  } else {
686  force_style = scalar_plain;
687  }
688  }
689 
690  if ( e->style == scalar_fold ) {
691  favor_style = scalar_fold;
692  }
693 
694  /* Determine block style */
695  if ( scan & SCAN_NONPRINT ) {
696  force_style = scalar_2quote;
697  } else if ( scan & SCAN_WHITEEDGE ) {
698  force_style = scalar_2quote;
699  } else if ( force_style != scalar_fold && ( scan & SCAN_INDENTED ) ) {
700  force_style = scalar_literal;
701  } else if ( force_style == scalar_plain && ( scan & SCAN_NEWLINE ) ) {
702  force_style = favor_style;
703  } else if ( force_style == scalar_plain && parent->status == syck_lvl_iseq && ( scan & SCAN_FLOWSEQ ) ) {
704  force_style = scalar_2quote;
705  } else if ( force_style == scalar_plain && parent->status == syck_lvl_imap && ( scan & SCAN_FLOWMAP ) ) {
706  force_style = scalar_2quote;
707  /* } else if ( force_style == scalar_fold && ( ! ( scan & SCAN_WIDE ) ) ) {
708  force_style = scalar_literal; */
709  } else if ( force_style == scalar_plain && ( scan & SCAN_INDIC_S || scan & SCAN_INDIC_C ) ) {
710  if ( scan & SCAN_NEWLINE ) {
711  force_style = favor_style;
712  } else {
713  force_style = scalar_2quote;
714  }
715  }
716 
717  if ( force_indent > 0 ) {
718  lvl->spaces = parent->spaces + force_indent;
719  } else if ( scan & SCAN_DOCSEP ) {
720  lvl->spaces = parent->spaces + e->indent;
721  }
722 
723  /* For now, all ambiguous keys are going to be double-quoted */
724  if ( ( parent->status == syck_lvl_map || parent->status == syck_lvl_mapx ) && parent->ncount % 2 == 1 ) {
725  if ( force_style != scalar_plain ) {
726  force_style = scalar_2quote;
727  }
728  }
729 
730  /* If the parent is an inline, double quote anything complex */
731  if ( parent->status == syck_lvl_imap || parent->status == syck_lvl_iseq ) {
732  if ( force_style != scalar_plain && force_style != scalar_1quote ) {
733  force_style = scalar_2quote;
734  }
735  }
736 
737  /* Fix the ending newlines */
738  if ( scan & SCAN_NONL_E ) {
739  keep_nl = NL_CHOMP;
740  } else if ( scan & SCAN_MANYNL_E ) {
741  keep_nl = NL_KEEP;
742  }
743 
744  /* Write the text node */
745  switch ( force_style )
746  {
747  case scalar_1quote:
748  syck_emit_1quoted( e, force_width, str, len );
749  break;
750 
751  case scalar_none:
752  case scalar_2quote:
753  syck_emit_2quoted( e, force_width, str, len );
754  break;
755 
756  case scalar_fold:
757  syck_emit_folded( e, force_width, keep_nl, str, len );
758  break;
759 
760  case scalar_literal:
761  syck_emit_literal( e, keep_nl, str, len );
762  break;
763 
764  case scalar_plain:
765  syck_emitter_write( e, str, len );
766  break;
767  }
768 
769  if ( parent->status == syck_lvl_mapx )
770  {
771  syck_emitter_write( e, "\n", 1 );
772  }
773 }
774 
775 void
776 syck_emitter_escape( SyckEmitter *e, const char *src, long len )
777 {
778  int i;
779  for( i = 0; i < len; i++ )
780  {
781  if( (src[i] < 0x20) || (0x7E < src[i]) )
782  {
783  syck_emitter_write( e, "\\", 1 );
784  if( '\0' == src[i] )
785  syck_emitter_write( e, "0", 1 );
786  else
787  {
788  syck_emitter_write( e, "x", 1 );
789  syck_emitter_write( e, (const char *)hex_table + ((src[i] & 0xF0) >> 4), 1 );
790  syck_emitter_write( e, (const char *)hex_table + (src[i] & 0x0F), 1 );
791  }
792  }
793  else
794  {
795  syck_emitter_write( e, src + i, 1 );
796  if( '\\' == src[i] )
797  syck_emitter_write( e, "\\", 1 );
798  }
799  }
800 }
801 
802 /*
803  * Outputs a single-quoted block.
804  */
805 void
806 syck_emit_1quoted( SyckEmitter *e, int width, const char *str, long len )
807 {
808  char do_indent = 0;
809  const char *mark = str;
810  const char *start = str;
811  const char *end = str;
812  syck_emitter_write( e, "'", 1 );
813  while ( mark < str + len ) {
814  if ( do_indent ) {
815  syck_emit_indent( e );
816  do_indent = 0;
817  }
818  switch ( *mark ) {
819  case '\'': syck_emitter_write( e, "'", 1 ); break;
820 
821  case '\n':
822  end = mark + 1;
823  if ( *start != ' ' && *start != '\n' && *end != '\n' && *end != ' ' ) {
824  syck_emitter_write( e, "\n\n", 2 );
825  } else {
826  syck_emitter_write( e, "\n", 1 );
827  }
828  do_indent = 1;
829  start = mark + 1;
830  break;
831 
832  case ' ':
833  if ( width > 0 && *start != ' ' && mark - end > width ) {
834  do_indent = 1;
835  end = mark + 1;
836  } else {
837  syck_emitter_write( e, " ", 1 );
838  }
839  break;
840 
841  default:
842  syck_emitter_write( e, mark, 1 );
843  break;
844  }
845  mark++;
846  }
847  syck_emitter_write( e, "'", 1 );
848 }
849 
850 /*
851  * Outputs a double-quoted block.
852  */
853 void
854 syck_emit_2quoted( SyckEmitter *e, int width, const char *str, long len )
855 {
856  char do_indent = 0;
857  const char *mark = str;
858  const char *start = str;
859  const char *end = str;
860  syck_emitter_write( e, "\"", 1 );
861  while ( mark < str + len ) {
862  if ( do_indent > 0 ) {
863  if ( do_indent == 2 ) {
864  syck_emitter_write( e, "\\", 1 );
865  }
866  syck_emit_indent( e );
867  do_indent = 0;
868  }
869  switch ( *mark ) {
870 
871  /* Escape sequences allowed within double quotes. */
872  case '"': syck_emitter_write( e, "\\\"", 2 ); break;
873  case '\\': syck_emitter_write( e, "\\\\", 2 ); break;
874  case '\0': syck_emitter_write( e, "\\0", 2 ); break;
875  case '\a': syck_emitter_write( e, "\\a", 2 ); break;
876  case '\b': syck_emitter_write( e, "\\b", 2 ); break;
877  case '\f': syck_emitter_write( e, "\\f", 2 ); break;
878  case '\r': syck_emitter_write( e, "\\r", 2 ); break;
879  case '\t': syck_emitter_write( e, "\\t", 2 ); break;
880  case '\v': syck_emitter_write( e, "\\v", 2 ); break;
881  case 0x1b: syck_emitter_write( e, "\\e", 2 ); break;
882 
883  case '\n':
884  end = mark + 1;
885  syck_emitter_write( e, "\\n", 2 );
886  do_indent = 2;
887  start = mark + 1;
888  if ( start < str + len && ( *start == ' ' || *start == '\n' ) ) {
889  do_indent = 0;
890  }
891  break;
892 
893  case ' ':
894  if ( width > 0 && *start != ' ' && mark - end > width ) {
895  do_indent = 1;
896  end = mark + 1;
897  } else {
898  syck_emitter_write( e, " ", 1 );
899  }
900  break;
901 
902  default:
903  syck_emitter_escape( e, mark, 1 );
904  break;
905  }
906  mark++;
907  }
908  syck_emitter_write( e, "\"", 1 );
909 }
910 
911 /*
912  * Outputs a literal block.
913  */
914 void
915 syck_emit_literal( SyckEmitter *e, char keep_nl, const char *str, long len )
916 {
917  const char *mark = str;
918  const char *start = str;
919  const char *end = str;
920  syck_emitter_write( e, "|", 1 );
921  if ( keep_nl == NL_CHOMP ) {
922  syck_emitter_write( e, "-", 1 );
923  } else if ( keep_nl == NL_KEEP ) {
924  syck_emitter_write( e, "+", 1 );
925  }
926  syck_emit_indent( e );
927  while ( mark < str + len ) {
928  if ( *mark == '\n' ) {
929  end = mark;
930  if ( *start != ' ' && *start != '\n' && *end != '\n' && *end != ' ' ) end += 1;
931  syck_emitter_write( e, start, end - start );
932  if ( mark + 1 == str + len ) {
933  if ( keep_nl != NL_KEEP ) syck_emitter_write( e, "\n", 1 );
934  } else {
935  syck_emit_indent( e );
936  }
937  start = mark + 1;
938  }
939  mark++;
940  }
941  end = str + len;
942  if ( start < end ) {
943  syck_emitter_write( e, start, end - start );
944  }
945 }
946 
947 /*
948  * Outputs a folded block.
949  */
950 void
951 syck_emit_folded( SyckEmitter *e, int width, char keep_nl, const char *str, long len )
952 {
953  const char *mark = str;
954  const char *start = str;
955  const char *end = str;
956  syck_emitter_write( e, ">", 1 );
957  if ( keep_nl == NL_CHOMP ) {
958  syck_emitter_write( e, "-", 1 );
959  } else if ( keep_nl == NL_KEEP ) {
960  syck_emitter_write( e, "+", 1 );
961  }
962  syck_emit_indent( e );
963  if ( width <= 0 ) width = e->best_width;
964  while ( mark < str + len ) {
965  switch ( *mark ) {
966  case '\n':
967  syck_emitter_write( e, end, mark - end );
968  end = mark + 1;
969  if ( *start != ' ' && *start != '\n' && *end != '\n' && *end != ' ' ) {
970  syck_emitter_write( e, "\n", 1 );
971  }
972  if ( mark + 1 == str + len ) {
973  if ( keep_nl != NL_KEEP ) syck_emitter_write( e, "\n", 1 );
974  } else {
975  syck_emit_indent( e );
976  }
977  start = mark + 1;
978  break;
979 
980  case ' ':
981  if ( *start != ' ' ) {
982  if ( mark - end > width ) {
983  syck_emitter_write( e, end, mark - end );
984  syck_emit_indent( e );
985  end = mark + 1;
986  }
987  }
988  break;
989  }
990  mark++;
991  }
992  if ( end < mark ) {
993  syck_emitter_write( e, end, mark - end );
994  }
995 }
996 
997 /*
998  * Begins emission of a sequence.
999  */
1000 void syck_emit_seq( SyckEmitter *e, const char *tag, enum seq_style style )
1001 {
1002  SyckLevel *parent = syck_emitter_parent_level( e );
1004  syck_emit_tag( e, tag, "tag:yaml.org,2002:seq" );
1005  if ( style == seq_inline || ( parent->status == syck_lvl_imap || parent->status == syck_lvl_iseq ) ) {
1006  syck_emitter_write( e, "[", 1 );
1007  lvl->status = syck_lvl_iseq;
1008  } else {
1009  /* complex key */
1010  if ( parent->status == syck_lvl_map && parent->ncount % 2 == 1 ) {
1011  syck_emitter_write( e, "? ", 2 );
1012  parent->status = syck_lvl_mapx;
1013  }
1014  lvl->status = syck_lvl_seq;
1015  }
1016 }
1017 
1018 /*
1019  * Begins emission of a mapping.
1020  */
1021 void
1022 syck_emit_map( SyckEmitter *e, const char *tag, enum map_style style )
1023 {
1024  SyckLevel *parent = syck_emitter_parent_level( e );
1026  syck_emit_tag( e, tag, "tag:yaml.org,2002:map" );
1027  if ( style == map_inline || ( parent->status == syck_lvl_imap || parent->status == syck_lvl_iseq ) ) {
1028  syck_emitter_write( e, "{", 1 );
1029  lvl->status = syck_lvl_imap;
1030  } else {
1031  /* complex key */
1032  if ( parent->status == syck_lvl_map && parent->ncount % 2 == 1 ) {
1033  syck_emitter_write( e, "? ", 2 );
1034  parent->status = syck_lvl_mapx;
1035  }
1036  lvl->status = syck_lvl_map;
1037  }
1038 }
1039 
1040 /*
1041  * Handles emitting of a collection item (for both
1042  * sequences and maps)
1043  */
1045 {
1047  switch ( lvl->status )
1048  {
1049  case syck_lvl_seq:
1050  {
1051  SyckLevel *parent = syck_emitter_parent_level( e );
1052 
1053  /* seq-in-map shortcut -- the lvl->anctag check should be unneccesary but
1054  * there is a nasty shift/reduce in the parser on this point and
1055  * i'm not ready to tickle it. */
1056  if ( lvl->anctag == 0 && parent->status == syck_lvl_map && lvl->ncount == 0 ) {
1057  lvl->spaces = parent->spaces;
1058  }
1059 
1060  /* seq-in-seq shortcut */
1061  else if ( lvl->anctag == 0 && parent->status == syck_lvl_seq && lvl->ncount == 0 ) {
1062  int spcs = ( lvl->spaces - parent->spaces ) - 2;
1063  if ( spcs >= 0 ) {
1064  int i = 0;
1065  for ( i = 0; i < spcs; i++ ) {
1066  syck_emitter_write( e, " ", 1 );
1067  }
1068  syck_emitter_write( e, "- ", 2 );
1069  break;
1070  }
1071  }
1072 
1073  syck_emit_indent( e );
1074  syck_emitter_write( e, "- ", 2 );
1075  }
1076  break;
1077 
1078  case syck_lvl_iseq:
1079  {
1080  if ( lvl->ncount > 0 ) {
1081  syck_emitter_write( e, ", ", 2 );
1082  }
1083  }
1084  break;
1085 
1086  case syck_lvl_map:
1087  {
1088  SyckLevel *parent = syck_emitter_parent_level( e );
1089 
1090  /* map-in-seq shortcut */
1091  if ( lvl->anctag == 0 && parent->status == syck_lvl_seq && lvl->ncount == 0 ) {
1092  int spcs = ( lvl->spaces - parent->spaces ) - 2;
1093  if ( spcs >= 0 ) {
1094  int i = 0;
1095  for ( i = 0; i < spcs; i++ ) {
1096  syck_emitter_write( e, " ", 1 );
1097  }
1098  break;
1099  }
1100  }
1101 
1102  if ( lvl->ncount % 2 == 0 ) {
1103  syck_emit_indent( e );
1104  } else {
1105  syck_emitter_write( e, ": ", 2 );
1106  }
1107  }
1108  break;
1109 
1110  case syck_lvl_mapx:
1111  {
1112  if ( lvl->ncount % 2 == 0 ) {
1113  syck_emit_indent( e );
1114  lvl->status = syck_lvl_map;
1115  } else {
1116  int i;
1117  if ( lvl->spaces > 0 ) {
1118  char *spcs = S_ALLOC_N( char, lvl->spaces + 1 );
1119 
1120  spcs[lvl->spaces] = '\0';
1121  for ( i = 0; i < lvl->spaces; i++ ) spcs[i] = ' ';
1122  syck_emitter_write( e, spcs, lvl->spaces );
1123  S_FREE( spcs );
1124  }
1125  syck_emitter_write( e, ": ", 2 );
1126  }
1127  }
1128  break;
1129 
1130  case syck_lvl_imap:
1131  {
1132  if ( lvl->ncount > 0 ) {
1133  if ( lvl->ncount % 2 == 0 ) {
1134  syck_emitter_write( e, ", ", 2 );
1135  } else {
1136  syck_emitter_write( e, ": ", 2 );
1137  }
1138  }
1139  }
1140  break;
1141 
1142  default: break;
1143  }
1144  lvl->ncount++;
1145 
1146  syck_emit( e, n );
1147 }
1148 
1149 /*
1150  * Closes emission of a collection.
1151  */
1153 {
1155  SyckLevel *parent = syck_emitter_parent_level( e );
1156  switch ( lvl->status )
1157  {
1158  case syck_lvl_seq:
1159  if ( lvl->ncount == 0 ) {
1160  syck_emitter_write( e, "[]\n", 3 );
1161  } else if ( parent->status == syck_lvl_mapx ) {
1162  syck_emitter_write( e, "\n", 1 );
1163  }
1164  break;
1165 
1166  case syck_lvl_iseq:
1167  syck_emitter_write( e, "]\n", 1 );
1168  break;
1169 
1170  case syck_lvl_map:
1171  if ( lvl->ncount == 0 ) {
1172  syck_emitter_write( e, "{}\n", 3 );
1173  } else if ( lvl->ncount % 2 == 1 ) {
1174  syck_emitter_write( e, ":\n", 1 );
1175  } else if ( parent->status == syck_lvl_mapx ) {
1176  syck_emitter_write( e, "\n", 1 );
1177  }
1178  break;
1179 
1180  case syck_lvl_imap:
1181  syck_emitter_write( e, "}\n", 1 );
1182  break;
1183 
1184  default: break;
1185  }
1186 }
1187 
1188 /*
1189  * Fill markers table with emitter nodes in the
1190  * soon-to-be-emitted tree.
1191  */
1192 SYMID
1194 {
1195  SYMID oid = 0;
1196  char *anchor_name = NULL;
1197 
1198  /*
1199  * Ensure markers table is initialized.
1200  */
1201  if ( e->markers == NULL )
1202  {
1203  e->markers = st_init_numtable();
1204  }
1205 
1206  /*
1207  * Markers table initially marks the string position of the
1208  * object. Doesn't yet create an anchor, simply notes the
1209  * position.
1210  */
1211  if ( ! st_lookup( e->markers, n, (st_data_t *)&oid ) )
1212  {
1213  /*
1214  * Store all markers
1215  */
1216  oid = e->markers->num_entries + 1;
1217  st_insert( e->markers, n, (st_data_t)oid );
1218  }
1219  else
1220  {
1221  if ( e->anchors == NULL )
1222  {
1223  e->anchors = st_init_numtable();
1224  }
1225 
1226  if ( ! st_lookup( e->anchors, (st_data_t)oid, (void *)&anchor_name ) )
1227  {
1228  int idx = 0;
1229  const char *anc = ( e->anchor_format == NULL ? DEFAULT_ANCHOR_FORMAT : e->anchor_format );
1230 
1231  /*
1232  * Second time hitting this object, let's give it an anchor
1233  */
1234  idx = (int)(e->anchors->num_entries + 1);
1235  anchor_name = S_ALLOC_N( char, strlen( anc ) + 10 );
1236  S_MEMZERO( anchor_name, char, strlen( anc ) + 10 );
1237  sprintf( anchor_name, anc, idx );
1238 
1239  /*
1240  * Insert into anchors table
1241  */
1242  st_insert( e->anchors, (st_data_t)oid, (st_data_t)anchor_name );
1243  }
1244  }
1245  return oid;
1246 }
1247 
#define ASSERT(f)
Definition: syck.h:38
void * bonus
Definition: syck.h:321
void syck_emitter_st_free(SyckEmitter *e)
Definition: emitter.c:148
seq_style
Definition: syck.h:92
enum syck_level_status status
Definition: syck.h:216
size_t strlen(const char *)
void syck_emitter_flush(SyckEmitter *e, long check_room)
Definition: emitter.c:322
int i
Definition: win32ole.c:776
#define NL_CHOMP
Definition: syck.h:62
#define S_ALLOC_N(type, n)
Definition: syck.h:47
int lvl_idx
Definition: syck.h:318
static char b64_table[]
Definition: emitter.c:22
int sort_keys
Definition: syck.h:287
int use_header
Definition: syck.h:283
#define st_foreach
Definition: regint.h:150
long bufpos
Definition: syck.h:311
SyckEmitter * syck_new_emitter(void)
Definition: emitter.c:108
void syck_emit_tag(SyckEmitter *e, const char *tag, const char *ignore)
Definition: emitter.c:440
syck_level_status
Definition: syck.h:171
void(* SyckOutputHandler)(SyckEmitter *, char *, long)
Definition: syck.h:268
Definition: syck.h:272
#define SCAN_NEWLINE
Definition: emitter.c:517
st_table * markers
Definition: syck.h:305
#define SCAN_INDIC_C
Definition: emitter.c:525
int indent
Definition: syck.h:301
SYMID syck_emitter_mark_node(SyckEmitter *e, st_data_t n)
Definition: emitter.c:1193
int level
Definition: syck.h:299
#define SCAN_MANYNL_E
Definition: emitter.c:529
int anctag
Definition: syck.h:212
void syck_emitter_clear(SyckEmitter *e)
Definition: emitter.c:268
#define st_lookup
Definition: regint.h:149
int headless
Definition: syck.h:281
#define SCAN_FLOWSEQ
Definition: emitter.c:533
static VALUE mark(VALUE self)
Definition: parser.c:523
#define SCAN_DOUBLEQ
Definition: emitter.c:521
#define SCAN_INDENTED
Definition: emitter.c:511
char * syck_base64dec(char *s, long len)
Definition: emitter.c:60
int use_version
Definition: syck.h:285
char * syck_strndup(const char *buf, long len)
Definition: syck.c:34
void syck_emit_scalar(SyckEmitter *e, const char *tag, enum scalar_style force_style, int force_indent, int force_width, char keep_nl, const char *str, long len)
Definition: emitter.c:641
const char * syck_match_implicit(const char *str, size_t len)
Definition: implicit.c:48
int ncount
Definition: syck.h:210
void syck_free_emitter(SyckEmitter *e)
Definition: emitter.c:251
void syck_emitter_pop_level(SyckEmitter *e)
Definition: emitter.c:189
#define S_FREE(n)
Definition: syck.h:50
map_style
Definition: syck.h:87
void syck_emit_seq(SyckEmitter *e, const char *tag, enum seq_style style)
Definition: emitter.c:1000
int best_width
Definition: syck.h:293
int spaces
Definition: syck.h:207
st_table * anchored
Definition: syck.h:305
#define SCAN_NONE
Definition: emitter.c:507
int syck_tagcmp(const char *tag1, const char *tag2)
Definition: implicit.c:1588
void syck_emitter_handler(SyckEmitter *e, SyckEmitterHandler hdlr)
Definition: emitter.c:239
#define SCAN_NONPRINT
Definition: emitter.c:509
#define SYCK_YAML_MAJOR
Definition: syck.h:12
size_t bufsize
Definition: syck.h:307
SyckOutputHandler output_handler
Definition: syck.h:315
#define S_MEMCPY(p1, p2, type, n)
Definition: syck.h:55
#define SCAN_NONL_E
Definition: emitter.c:527
arg
Definition: ripper.y:1283
char * domain
Definition: syck.h:214
void syck_emitter_reset_levels(SyckEmitter *e)
Definition: emitter.c:220
char * buffer
Definition: syck.h:309
char * anchor_format
Definition: syck.h:289
const char hex_table[]
Definition: emitter.c:20
#define S_REALLOC_N(var, type, n)
Definition: syck.h:49
#define ALLOC_CT
Definition: syck.h:45
scalar_style
Definition: syck.h:97
int syck_st_free_anchors(char *key, char *name, char *arg)
Definition: emitter.c:141
void syck_emit_end(SyckEmitter *e)
Definition: emitter.c:1152
void syck_emit(SyckEmitter *e, st_data_t n)
Definition: emitter.c:356
#define NULL
int explicit_typing
Definition: syck.h:291
void syck_emit_indent(SyckEmitter *e)
Definition: emitter.c:491
register unsigned int len
Definition: name2ctype.h:22210
void syck_emit_map(SyckEmitter *e, const char *tag, enum map_style style)
Definition: emitter.c:1022
SyckLevel * levels
Definition: syck.h:317
long st_data_t
Definition: syck.h:69
#define SYCK_BUFFERSIZE
Definition: syck.h:46
SyckEmitterHandler emitter_handler
Definition: syck.h:313
void syck_emit_literal(SyckEmitter *e, char keep_nl, const char *str, long len)
Definition: emitter.c:915
void syck_output_handler(SyckEmitter *e, SyckOutputHandler hdlr)
Definition: emitter.c:245
int syck_scan_scalar(int req_width, const char *cursor, long len)
Definition: emitter.c:541
#define st_init_numtable
Definition: regint.h:142
char * syck_taguri(const char *domain, const char *type_id, int type_len)
Definition: handler.c:157
enum doc_stage stage
Definition: syck.h:297
SyckLevel * syck_emitter_parent_level(SyckEmitter *e)
Definition: emitter.c:183
void syck_emit_item(SyckEmitter *e, st_data_t n)
Definition: emitter.c:1044
uint8_t key[16]
Definition: random.c:1284
st_table * anchors
Definition: syck.h:305
#define SCAN_WIDE
Definition: emitter.c:513
char * marker
Definition: syck.h:309
#define S_ALLOC(type)
Definition: syck.h:48
#define st_insert
Definition: regint.h:148
#define YAML_DOMAIN
Definition: syck.h:15
void syck_emitter_write(SyckEmitter *e, const char *str, long len)
Definition: emitter.c:284
#define SCAN_INDIC_S
Definition: emitter.c:523
#define SCAN_WHITEEDGE
Definition: emitter.c:515
const char * name
Definition: nkf.c:208
#define st_free_table
Definition: regint.h:152
void(* SyckEmitterHandler)(SyckEmitter *, st_data_t)
Definition: syck.h:269
SyckLevel * syck_emitter_current_level(SyckEmitter *e)
Definition: emitter.c:177
void syck_emit_2quoted(SyckEmitter *e, int width, const char *str, long len)
Definition: emitter.c:854
void syck_emitter_escape(SyckEmitter *e, const char *src, long len)
Definition: emitter.c:776
char * syck_base64enc(char *s, long len)
Definition: emitter.c:29
#define SCAN_SINGLEQ
Definition: emitter.c:519
st_index_t num_entries
Definition: st.h:93
void syck_emitter_add_level(SyckEmitter *e, int len, enum syck_level_status status)
Definition: emitter.c:201
#define SCAN_FLOWMAP
Definition: emitter.c:531
#define SYMID
Definition: syck.h:72
free(psz)
#define SYCK_YAML_MINOR
Definition: syck.h:13
#define DEFAULT_ANCHOR_FORMAT
Definition: emitter.c:18
void syck_emit_1quoted(SyckEmitter *e, int width, const char *str, long len)
Definition: emitter.c:806
int lvl_capa
Definition: syck.h:319
void syck_emit_folded(SyckEmitter *e, int width, char keep_nl, const char *str, long len)
Definition: emitter.c:951
#define SCAN_DOCSEP
Definition: emitter.c:535
#define NL_KEEP
Definition: syck.h:63
enum scalar_style style
Definition: syck.h:295
#define S_MEMZERO(p, type, n)
Definition: syck.h:54