OSDN Git Service

ruby-1.9.1-rc1
[splhack/AndroidRuby.git] / lib / ruby-1.9.1-rc1 / ext / syck / emitter.c
1 /*
2  * emitter.c
3  *
4  * $Author: nobu $
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 *
108 syck_new_emitter(void)
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;
126     e->bufsize = SYCK_BUFFERSIZE;
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 ); 
135     syck_emitter_reset_levels( e );
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
148 syck_emitter_st_free( SyckEmitter *e )
149 {
150     /*
151      * Free the anchor tables
152      */
153     if ( e->anchors != NULL )
154     {
155         st_foreach( e->anchors, syck_st_free_anchors, 0 );
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 *
177 syck_emitter_current_level( SyckEmitter *e )
178 {
179     return &e->levels[e->lvl_idx-1];
180 }
181
182 SyckLevel *
183 syck_emitter_parent_level( SyckEmitter *e )
184 {
185     return &e->levels[e->lvl_idx-2];
186 }
187
188 void
189 syck_emitter_pop_level( SyckEmitter *e )
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 
201 syck_emitter_add_level( SyckEmitter *e, int len, enum syck_level_status status )
202 {
203     ASSERT( e != NULL );
204     if ( e->lvl_idx + 1 > e->lvl_capa )
205     {
206         e->lvl_capa += ALLOC_CT;
207         S_REALLOC_N( e->levels, SyckLevel, e->lvl_capa );
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
220 syck_emitter_reset_levels( SyckEmitter *e )
221 {
222     while ( e->lvl_idx > 1 )
223     {
224         syck_emitter_pop_level( e );
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
239 syck_emitter_handler( SyckEmitter *e, SyckEmitterHandler hdlr )
240 {
241     e->emitter_handler = hdlr;
242 }
243
244 void
245 syck_output_handler( SyckEmitter *e, SyckOutputHandler hdlr )
246 {
247     e->output_handler = hdlr;
248 }
249
250 void
251 syck_free_emitter( SyckEmitter *e )
252 {
253     /*
254      * Free tables
255      */
256     syck_emitter_st_free( e );
257     syck_emitter_reset_levels( e );
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
268 syck_emitter_clear( SyckEmitter *e )
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 >= 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 ( 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
356 syck_emit( SyckEmitter *e, st_data_t n )
357 {
358     SYMID oid;
359     char *anchor_name = NULL;
360     int indent = 0;
361     long x = 0;
362     SyckLevel *lvl = syck_emitter_current_level( e );
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     }
388     syck_emitter_add_level( e, indent, syck_lvl_open );
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:
427     syck_emitter_pop_level( e );
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 = 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 > ( 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  */
491 void syck_emit_indent( SyckEmitter *e )
492 {
493     int i;
494     SyckLevel *lvl = syck_emitter_current_level( e );
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' ) ) ||
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 );
646     SyckLevel *lvl = syck_emitter_current_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, 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 );
1003     SyckLevel *lvl = syck_emitter_current_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 );
1025     SyckLevel *lvl = syck_emitter_current_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  */
1044 void syck_emit_item( SyckEmitter *e, st_data_t n )
1045 {
1046     SyckLevel *lvl = syck_emitter_current_level( e );
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  */
1152 void syck_emit_end( SyckEmitter *e )
1153 {
1154     SyckLevel *lvl = syck_emitter_current_level( e );
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
1193 syck_emitter_mark_node( SyckEmitter *e, st_data_t n )
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 = 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