root/JSON-Syck/trunk/emitter.c

Revision 1750 (checked in by miyagawa, 14 years ago)

merged YAML::Syck 0.24

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