root/JSON-Syck/trunk/emitter.c

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

merge audrey's changes and added Unicode test: still failing

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 = 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->stage = doc_open;
431     }
432 }
433
434 /*
435  * Determine what tag needs to be written, based on the taguri of the node
436  * and the implicit tag which would be assigned to this node.  If a tag is
437  * required, write the tag.
438  */
439 void syck_emit_tag( SyckEmitter *e, char *tag, char *ignore )
440 {
441     SyckLevel *lvl;
442     if ( tag == NULL ) return;
443     if ( ignore != NULL && syck_tagcmp( tag, ignore ) == 0 && e->explicit_typing == 0 ) return;
444     lvl = syck_emitter_current_level( e );
445
446     /* implicit */
447     if ( strlen( tag ) == 0 ) {
448         syck_emitter_write( e, "! ", 2 );
449
450     /* global types */
451     } else if ( strncmp( tag, "tag:", 4 ) == 0 ) {
452         int taglen = strlen( tag );
453         syck_emitter_write( e, "!", 1 );
454         if ( strncmp( tag + 4, YAML_DOMAIN, strlen( YAML_DOMAIN ) ) == 0 ) {
455             int skip = 4 + strlen( YAML_DOMAIN ) + 1;
456             syck_emitter_write( e, tag + skip, taglen - skip );
457         } else {
458             char *subd = tag + 4;
459             while ( *subd != ':' && *subd != '\0' ) subd++;
460             if ( *subd == ':' ) {
461                 if ( subd - tag > ( strlen( YAML_DOMAIN ) + 5 ) &&
462                      strncmp( subd - strlen( YAML_DOMAIN ), YAML_DOMAIN, strlen( YAML_DOMAIN ) ) == 0 ) {
463                     syck_emitter_write( e, tag + 4, subd - strlen( YAML_DOMAIN ) - ( tag + 4 ) - 1 );
464                     syck_emitter_write( e, "/", 1 );
465                     syck_emitter_write( e, subd + 1, ( tag + taglen ) - ( subd + 1 ) );
466                 } else {
467                     syck_emitter_write( e, tag + 4, subd - ( tag + 4 ) );
468                     syck_emitter_write( e, "/", 1 );
469                     syck_emitter_write( e, subd + 1, ( tag + taglen ) - ( subd + 1 ) );
470                 }
471             } else {
472                 /* TODO: Invalid tag (no colon after domain) */
473                 return;
474             }
475         }
476         syck_emitter_write( e, " ", 1 );
477
478     /* private types */
479     } else if ( strncmp( tag, "x-private:", 10 ) == 0 ) {
480         syck_emitter_write( e, "!!", 2 );
481         syck_emitter_write( e, tag + 10, strlen( tag ) - 10 );
482         syck_emitter_write( e, " ", 1 );
483     }
484     lvl->anctag = 1;
485 }
486
487 /*
488  * Emit a newline and an appropriately spaced indent.
489  */
490 void syck_emit_indent( SyckEmitter *e )
491 {
492     int i;
493     SyckLevel *lvl = syck_emitter_current_level( e );
494     if ( lvl->spaces >= 0 ) {
495         char *spcs = S_ALLOC_N( char, lvl->spaces + 2 );
496
497         spcs[0] = '\n'; spcs[lvl->spaces + 1] = '\0';
498         for ( i = 0; i < lvl->spaces; i++ ) spcs[i+1] = ' ';
499         syck_emitter_write( e, spcs, lvl->spaces + 1 );
500         free( spcs );
501     }
502 }
503
504 /* Clear the scan */
505 #define SCAN_NONE       0
506 /* All printable characters? */
507 #define SCAN_NONPRINT   1
508 /* Any indented lines? */
509 #define SCAN_INDENTED   2
510 /* Larger than the requested width? */
511 #define SCAN_WIDE       4
512 /* Opens with whitespace? */
513 #define SCAN_WHITESTART 8
514 /* Contains a newline */
515 #define SCAN_NEWLINE    16
516 /* Contains a single quote */
517 #define SCAN_SINGLEQ    32
518 /* Contains a double quote */
519 #define SCAN_DOUBLEQ    64
520 /* Starts with a token */
521 #define SCAN_INDIC_S    128
522 /* Contains a flow indicator */
523 #define SCAN_INDIC_C    256
524 /* Ends without newlines */
525 #define SCAN_NONL_E     512
526 /* Ends with many newlines */
527 #define SCAN_MANYNL_E   1024
528 /* Contains flow map indicators */
529 #define SCAN_FLOWMAP    2048
530 /* Contains flow seq indicators */
531 #define SCAN_FLOWSEQ    4096
532 /* Contains a valid doc separator */
533 #define SCAN_DOCSEP     8192
534
535 /*
536  * Basic printable test for LATIN-1 characters.
537  */
538 int
539 syck_scan_scalar( int req_width, char *cursor, long len )
540 {
541     long i = 0, start = 0;
542     int flags = SCAN_NONE;
543
544     if ( len < 1 )  return flags;
545
546     /* c-indicators from the spec */
547     if ( cursor[0] == '[' || cursor[0] == ']' ||
548          cursor[0] == '{' || cursor[0] == '}' ||
549          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] == '&' ) {
555             flags |= SCAN_INDIC_S;
556     }
557     if ( ( cursor[0] == '-' || cursor[0] == ':' ||
558            cursor[0] == '?' || cursor[0] == ',' ) &&
559            cursor[1] == ' ' ) {
560             flags |= SCAN_INDIC_S;
561     }
562
563     /* ending newlines */
564     if ( cursor[len-1] != '\n' ) {
565         flags |= SCAN_NONL_E;
566     } else if ( len > 1 && cursor[len-2] == '\n' ) {
567         flags |= SCAN_MANYNL_E;
568     }
569
570     /* opening doc sep */
571     if ( len >= 3 && strncmp( cursor, "---", 3 ) == 0 )
572         flags |= SCAN_DOCSEP;
573
574     /* scan string */
575     for ( i = 0; i < len; i++ ) {
576
577         if ( ! ( cursor[i] == 0x9 ||
578                  cursor[i] == 0xA ||
579                  cursor[i] == 0xD ||
580                ( cursor[i] >= 0x20 && cursor[i] <= 0x7E ) )
581         ) {
582             flags |= SCAN_NONPRINT;
583         }
584         else if ( cursor[i] == '\n' ) {
585             flags |= SCAN_NEWLINE;
586             if ( len - i >= 3 && strncmp( &cursor[i+1], "---", 3 ) == 0 )
587                 flags |= SCAN_DOCSEP;
588             if ( cursor[i+1] == ' ' || cursor[i+1] == '\t' )
589                 flags |= SCAN_INDENTED;
590             if ( req_width > 0 && i - start > req_width )
591                 flags |= SCAN_WIDE;
592             start = i;
593         }
594         else if ( cursor[i] == '\'' )
595         {
596             flags |= SCAN_SINGLEQ;
597         }
598         else if ( cursor[i] == '"' )
599         {
600             flags |= SCAN_DOUBLEQ;
601         }
602         else if ( cursor[i] == ']' )
603         {
604             flags |= SCAN_FLOWSEQ;
605         }
606         else if ( cursor[i] == '}' )
607         {
608             flags |= SCAN_FLOWMAP;
609         }
610         /* remember, if plain collections get implemented, to add nb-plain-flow-char */
611         else if ( ( cursor[i] == ' ' && cursor[i+1] == '#' ) ||
612                   ( cursor[i] == ':' && cursor[i+1] == ' ' ) )
613         {
614             flags |= SCAN_INDIC_C;
615         }
616         else if ( cursor[i] == ',' && cursor[i+1] == ' ' )
617         {
618             flags |= SCAN_FLOWMAP;
619             flags |= SCAN_FLOWSEQ;
620         }
621
622         if ( i == 0 &&
623             ( cursor[i] == ' ' || cursor[i] == '\t' )
624         ) {
625             flags |= SCAN_WHITESTART;
626         }
627     }
628
629     /* printf( "---STR---\n%s\nFLAGS: %d\n", cursor, flags ); */
630     return flags;
631 }
632 /*
633  * All scalars should be emitted through this function, which determines an appropriate style,
634  * tag and indent.
635  */
636 void syck_emit_scalar( SyckEmitter *e, char *tag, enum scalar_style force_style, int force_indent, int force_width,
637                        char keep_nl, char *str, long len )
638 {
639     enum scalar_style favor_style = scalar_literal;
640     SyckLevel *parent = syck_emitter_parent_level( e );
641     SyckLevel *lvl = syck_emitter_current_level( e );
642     int scan;
643     char *implicit;
644    
645     if ( str == NULL ) str = "";
646
647     /* No empty nulls as map keys */
648     if ( len == 0 && ( parent->status == syck_lvl_map || parent->status == syck_lvl_imap ) &&
649          parent->ncount % 2 == 1 && syck_tagcmp( tag, "tag:yaml.org,2002:null" ) == 0 )
650     {
651         str = "~";
652         len = 1;
653     }
654
655     scan = syck_scan_scalar( force_width, str, len );
656     implicit = syck_match_implicit( str, len );
657
658     /* quote strings which default to implicits */
659     implicit = syck_taguri( YAML_DOMAIN, implicit, strlen( implicit ) );
660     if ( syck_tagcmp( tag, implicit ) != 0 && syck_tagcmp( tag, "tag:yaml.org,2002:str" ) == 0 ) {
661         force_style = scalar_2quote;
662     } else {
663         syck_emit_tag( e, tag, implicit );
664     }
665     S_FREE( implicit );
666
667     /* if still arbitrary, sniff a good block style. */
668     if ( force_style == scalar_none ) {
669         if ( scan & SCAN_NEWLINE ) {
670             force_style = scalar_literal;
671         } else {
672             force_style = scalar_plain;
673         }
674     }
675
676     if ( e->style == scalar_fold ) {
677         favor_style = scalar_fold;
678     }
679
680     /* Determine block style */
681     if ( scan & SCAN_NONPRINT ) {
682         force_style = scalar_2quote;
683     } else if ( scan & SCAN_WHITESTART ) {
684         force_style = scalar_2quote;
685     } else if ( force_style != scalar_fold && ( scan & SCAN_INDENTED ) ) {
686         force_style = scalar_literal;
687     } else if ( force_style == scalar_plain && ( scan & SCAN_NEWLINE ) ) {
688         force_style = favor_style;
689     } else if ( force_style == scalar_plain && parent->status == syck_lvl_iseq && ( scan & SCAN_FLOWSEQ ) ) {
690         force_style = scalar_2quote;
691     } else if ( force_style == scalar_plain && parent->status == syck_lvl_imap && ( scan & SCAN_FLOWMAP ) ) {
692         force_style = scalar_2quote;
693     /* } else if ( force_style == scalar_fold && ( ! ( scan & SCAN_WIDE ) ) ) {
694         force_style = scalar_literal; */
695     } else if ( force_style == scalar_plain && ( scan & SCAN_INDIC_S || scan & SCAN_INDIC_C ) ) {
696         if ( scan & SCAN_NEWLINE ) {
697             force_style = favor_style;
698         } else {
699             force_style = scalar_2quote;
700         }
701     }
702
703     if ( force_indent > 0 ) {
704         lvl->spaces = parent->spaces + force_indent;
705     } else if ( scan & SCAN_DOCSEP ) {
706         lvl->spaces = parent->spaces + e->indent;
707     }
708
709     /* For now, all ambiguous keys are going to be double-quoted */
710     if ( parent->status == syck_lvl_map && parent->ncount % 2 == 1 ) {
711         if ( force_style != scalar_plain ) {
712             force_style = scalar_2quote;
713         }
714     }
715
716     /* If the parent is an inline, double quote anything complex */
717     if ( parent->status == syck_lvl_imap || parent->status == syck_lvl_iseq ) {
718         if ( force_style != scalar_plain && force_style != scalar_1quote ) {
719             force_style = scalar_2quote;
720         }
721     }
722
723     /* Fix the ending newlines */
724     if ( scan & SCAN_NONL_E ) {
725         keep_nl = NL_CHOMP;
726     } else if ( scan & SCAN_MANYNL_E ) {
727         keep_nl = NL_KEEP;
728     }
729
730     /* Write the text node */
731     switch ( force_style )
732     {
733         case scalar_1quote:
734             syck_emit_1quoted( e, force_width, str, len );
735         break;
736
737         case scalar_2quote:
738             syck_emit_2quoted( e, force_width, str, len );
739         break;
740
741         case scalar_fold:
742             syck_emit_folded( e, force_width, keep_nl, str, len );
743         break;
744
745         case scalar_literal:
746             syck_emit_literal( e, keep_nl, str, len );
747         break;
748
749         case scalar_plain:
750             syck_emitter_write( e, str, len );
751         break;
752     }
753 }
754
755 void
756 syck_emitter_escape( SyckEmitter *e, char *src, long len )
757 {
758     int i;
759     for( i = 0; i < len; i++ )
760     {
761         if( (e->style == scalar_fold)
762                 ? ((src[i] < 0x20) && (0 < src[i]))
763                 : ((src[i] < 0x20) || (0x7E < src[i])) )
764         {
765             syck_emitter_write( e, "\\", 1 );
766             if( '\0' == src[i] )
767                 syck_emitter_write( e, "0", 1 );
768             else
769             {
770                 syck_emitter_write( e, "x", 1 );
771                 syck_emitter_write( e, (char *)hex_table + ((src[i] & 0xF0) >> 4), 1 );
772                 syck_emitter_write( e, (char *)hex_table + (src[i] & 0x0F), 1 );
773             }
774         }
775         else
776         {
777             syck_emitter_write( e, src + i, 1 );
778             if( '\\' == src[i] )
779                 syck_emitter_write( e, "\\", 1 );
780         }
781     }
782 }
783
784 /*
785  * Outputs a single-quoted block.
786  */
787 void syck_emit_1quoted( SyckEmitter *e, int width, char *str, long len )
788 {
789     char do_indent = 0;
790     char *mark = str;
791     char *start = str;
792     char *end = str;
793     syck_emitter_write( e, "'", 1 );
794     while ( mark < str + len ) {
795         if ( do_indent ) {
796             syck_emit_indent( e );
797             do_indent = 0;
798         }
799         switch ( *mark ) {
800             case '\'':  syck_emitter_write( e, "'", 1 ); break;
801
802             case '\n':
803                 end = mark + 1;
804                 if ( *start != ' ' && *start != '\n' && *end != '\n' && *end != ' ' ) {
805                     syck_emitter_write( e, "\n\n", 2 );
806                 } else {
807                     syck_emitter_write( e, "\n", 1 );
808                 }
809                 do_indent = 1;
810                 start = mark + 1;
811             break;
812
813             case ' ':
814                 if ( width > 0 && *start != ' ' && mark - end > width ) {
815                     do_indent = 1;
816                     end = mark + 1;
817                 } else {
818                     syck_emitter_write( e, " ", 1 );
819                 }
820             break;
821
822             default:
823                 syck_emitter_write( e, mark, 1 );
824             break;
825         }
826         mark++;
827     }
828     syck_emitter_write( e, "'", 1 );
829 }
830
831 /*
832  * Outputs a double-quoted block.
833  */
834 void syck_emit_2quoted( SyckEmitter *e, int width, char *str, long len )
835 {
836     char do_indent = 0;
837     char *mark = str;
838     char *start = str;
839     char *end = str;
840     syck_emitter_write( e, "\"", 1 );
841     while ( mark < str + len ) {
842         if ( do_indent > 0 ) {
843             if ( do_indent == 2 ) {
844                 syck_emitter_write( e, "\\", 1 );
845             }
846             syck_emit_indent( e );
847             do_indent = 0;
848         }
849         switch ( *mark ) {
850
851             /* Escape sequences allowed within double quotes. */
852             case '"':  syck_emitter_write( e, "\\\"", 2 ); break;
853             case '\\': syck_emitter_write( e, "\\\\", 2 ); break;
854             case '\0': syck_emitter_write( e, "\\0",  2 ); break;
855             case '\a': syck_emitter_write( e, "\\a",  2 ); break;
856             case '\b': syck_emitter_write( e, "\\b",  2 ); break;
857             case '\f': syck_emitter_write( e, "\\f",  2 ); break;
858             case '\r': syck_emitter_write( e, "\\r",  2 ); break;
859             case '\t': syck_emitter_write( e, "\\t",  2 ); break;
860             case '\v': syck_emitter_write( e, "\\v",  2 ); break;
861             case 0x1b: syck_emitter_write( e, "\\e",  2 ); break;
862
863             case '\n':
864                 end = mark + 1;
865                 syck_emitter_write( e, "\\n", 2 );
866                 do_indent = 2;
867                 start = mark + 1;
868                 if ( start < str + len && ( *start == ' ' || *start == '\n' ) ) {
869                     do_indent = 0;
870                 }
871             break;
872
873             case ' ':
874                 if ( width > 0 && *start != ' ' && mark - end > width ) {
875                     do_indent = 1;
876                     end = mark + 1;
877                 } else {
878                     syck_emitter_write( e, " ", 1 );
879                 }
880             break;
881
882             default:
883                 syck_emitter_escape( e, mark, 1 );
884             break;
885         }
886         mark++;
887     }
888     syck_emitter_write( e, "\"", 1 );
889 }
890
891 /*
892  * Outputs a literal block.
893  */
894 void syck_emit_literal( SyckEmitter *e, char keep_nl, char *str, long len )
895 {
896     char *mark = str;
897     char *start = str;
898     char *end = str;
899     syck_emitter_write( e, "|", 1 );
900     if ( keep_nl == NL_CHOMP ) {
901         syck_emitter_write( e, "-", 1 );
902     } else if ( keep_nl == NL_KEEP ) {
903         syck_emitter_write( e, "+", 1 );
904     }
905     syck_emit_indent( e );
906     while ( mark < str + len ) {
907         if ( *mark == '\n' ) {
908             end = mark;
909             if ( *start != ' ' && *start != '\n' && *end != '\n' && *end != ' ' ) end += 1;
910             syck_emitter_write( e, start, end - start );
911             if ( mark + 1 == str + len ) {
912                 if ( keep_nl != NL_KEEP ) syck_emitter_write( e, "\n", 1 );
913             } else {
914                 syck_emit_indent( e );
915             }
916             start = mark + 1;
917         }
918         mark++;
919     }
920     end = str + len;
921     if ( start < end ) {
922         syck_emitter_write( e, start, end - start );
923     }
924 }
925
926 /*
927  * Outputs a folded block.
928  */
929 void syck_emit_folded( SyckEmitter *e, int width, char keep_nl, char *str, long len )
930 {
931     char *mark = str;
932     char *start = str;
933     char *end = str;
934     syck_emitter_write( e, ">", 1 );
935     if ( keep_nl == NL_CHOMP ) {
936         syck_emitter_write( e, "-", 1 );
937     } else if ( keep_nl == NL_KEEP ) {
938         syck_emitter_write( e, "+", 1 );
939     }
940     syck_emit_indent( e );
941     if ( width <= 0 ) width = e->best_width;
942     while ( mark < str + len ) {
943         switch ( *mark ) {
944             case '\n':
945                 syck_emitter_write( e, end, mark - end );
946                 end = mark + 1;
947                 if ( *start != ' ' && *start != '\n' && *end != '\n' && *end != ' ' ) {
948                     syck_emitter_write( e, "\n", 1 );
949                 }
950                 if ( mark + 1 == str + len ) {
951                     if ( keep_nl != NL_KEEP ) syck_emitter_write( e, "\n", 1 );
952                 } else {
953                     syck_emit_indent( e );
954                 }
955                 start = mark + 1;
956             break;
957
958             case ' ':
959                 if ( *start != ' ' ) {
960                     if ( mark - end > width ) {
961                         syck_emitter_write( e, end, mark - end );
962                         syck_emit_indent( e );
963                         end = mark + 1;
964                     }
965                 }
966             break;
967         }
968         mark++;
969     }
970     if ( end < mark ) {
971         syck_emitter_write( e, end, mark - end );
972     }
973 }
974
975 /*
976  * Begins emission of a sequence.
977  */
978 void syck_emit_seq( SyckEmitter *e, char *tag, enum seq_style style )
979 {
980     SyckLevel *parent = syck_emitter_parent_level( e );
981     SyckLevel *lvl = syck_emitter_current_level( e );
982     syck_emit_tag( e, tag, "tag:yaml.org,2002:seq" );
983     if ( style == seq_inline || ( parent->status == syck_lvl_imap || parent->status == syck_lvl_iseq ) ) {
984         syck_emitter_write( e, "[", 1 );
985         lvl->status = syck_lvl_iseq;
986     } else {
987         lvl->status = syck_lvl_seq;
988     }
989 }
990
991 /*
992  * Begins emission of a mapping.
993  */
994 void syck_emit_map( SyckEmitter *e, char *tag, enum map_style style )
995 {
996     SyckLevel *parent = syck_emitter_parent_level( e );
997     SyckLevel *lvl = syck_emitter_current_level( e );
998     syck_emit_tag( e, tag, "tag:yaml.org,2002:map" );
999     if ( style == map_inline || ( parent->status == syck_lvl_imap || parent->status == syck_lvl_iseq ) ) {
1000         syck_emitter_write( e, "{", 1 );
1001         lvl->status = syck_lvl_imap;
1002     } else {
1003         lvl->status = syck_lvl_map;
1004     }
1005 }
1006
1007 /*
1008  * Handles emitting of a collection item (for both
1009  * sequences and maps)
1010  */
1011 void syck_emit_item( SyckEmitter *e, st_data_t n )
1012 {
1013     SyckLevel *lvl = syck_emitter_current_level( e );
1014     switch ( lvl->status )
1015     {
1016         case syck_lvl_seq:
1017         {
1018             SyckLevel *parent = syck_emitter_parent_level( e );
1019
1020             /* seq-in-map shortcut */
1021             if ( parent->status == syck_lvl_map && lvl->ncount == 0 ) {
1022                 /* complex key */
1023                 if ( parent->ncount % 2 == 1 ) {
1024                     syck_emitter_write( e, "?", 1 );
1025                     parent->status = syck_lvl_mapx;
1026                 /* shortcut -- the lvl->anctag check should be unneccesary but
1027                  * there is a nasty shift/reduce in the parser on this point and
1028                  * i'm not ready to tickle it. */
1029                 } else if ( lvl->anctag == 0 ) {
1030                     lvl->spaces = parent->spaces;
1031                 }
1032             }
1033
1034             /* seq-in-seq shortcut */
1035             else if ( lvl->anctag == 0 && parent->status == syck_lvl_seq && lvl->ncount == 0 ) {
1036                 int spcs = ( lvl->spaces - parent->spaces ) - 2;
1037                 if ( spcs >= 0 ) {
1038                     int i = 0;
1039                     for ( i = 0; i < spcs; i++ ) {
1040                         syck_emitter_write( e, " ", 1 );
1041                     }
1042                     syck_emitter_write( e, "- ", 2 );
1043                     break;
1044                 }
1045             }
1046
1047             syck_emit_indent( e );
1048             syck_emitter_write( e, "- ", 2 );
1049         }
1050         break;
1051
1052         case syck_lvl_iseq:
1053         {
1054             if ( lvl->ncount > 0 ) {
1055                 syck_emitter_write( e, ", ", 2 );
1056             }
1057         }
1058         break;
1059
1060         case syck_lvl_map:
1061         {
1062             SyckLevel *parent = syck_emitter_parent_level( e );
1063
1064             /* map-in-map */
1065             if ( parent->status == syck_lvl_map && lvl->ncount == 0 ) {
1066                 /* complex key */
1067                 if ( parent->ncount % 2 == 1 ) {
1068                     syck_emitter_write( e, "?", 1 );
1069                     parent->status = syck_lvl_mapx;
1070                 }
1071             }
1072
1073             /* map-in-seq shortcut */
1074             if ( lvl->anctag == 0 && parent->status == syck_lvl_seq && lvl->ncount == 0 ) {
1075                 int spcs = ( lvl->spaces - parent->spaces ) - 2;
1076                 if ( spcs >= 0 ) {
1077                     int i = 0;
1078                     for ( i = 0; i < spcs; i++ ) {
1079                         syck_emitter_write( e, " ", 1 );
1080                     }
1081                     break;
1082                 }
1083             }
1084
1085             if ( lvl->ncount % 2 == 0 ) {
1086                 syck_emit_indent( e );
1087             } else {
1088                 syck_emitter_write( e, ": ", 2 );
1089             }
1090         }
1091         break;
1092
1093         case syck_lvl_mapx:
1094         {
1095             if ( lvl->ncount % 2 == 0 ) {
1096                 syck_emit_indent( e );
1097                 lvl->status = syck_lvl_map;
1098             } else {
1099                 int i;
1100                 if ( lvl->spaces > 0 ) {
1101                     char *spcs = S_ALLOC_N( char, lvl->spaces + 1 );
1102
1103                     spcs[lvl->spaces] = '\0';
1104                     for ( i = 0; i < lvl->spaces; i++ ) spcs[i] = ' ';
1105                     syck_emitter_write( e, spcs, lvl->spaces );
1106                     S_FREE( spcs );
1107                 }
1108                 syck_emitter_write( e, ": ", 2 );
1109             }
1110         }
1111         break;
1112
1113         case syck_lvl_imap:
1114         {
1115             if ( lvl->ncount > 0 ) {
1116                 if ( lvl->ncount % 2 == 0 ) {
1117                     syck_emitter_write( e, ", ", 2 );
1118                 } else {
1119                     syck_emitter_write( e, ": ", 2 );
1120                 }
1121             }
1122         }
1123         break;
1124     }
1125     lvl->ncount++;
1126
1127     syck_emit( e, n );
1128 }
1129
1130 /*
1131  * Closes emission of a collection.
1132  */
1133 void syck_emit_end( SyckEmitter *e )
1134 {
1135     SyckLevel *lvl = syck_emitter_current_level( e );
1136     SyckLevel *parent = syck_emitter_parent_level( e );
1137     switch ( lvl->status )
1138     {
1139         case syck_lvl_seq:
1140             if ( lvl->ncount == 0 ) {
1141                 syck_emitter_write( e, "[]\n", 3 );
1142             } else if ( parent->status == syck_lvl_mapx ) {
1143                 syck_emitter_write( e, "\n", 1 );
1144             }
1145         break;
1146
1147         case syck_lvl_iseq:
1148             syck_emitter_write( e, "]\n", 1 );
1149         break;
1150
1151         case syck_lvl_map:
1152             if ( lvl->ncount == 0 ) {
1153                 syck_emitter_write( e, "{}\n", 3 );
1154             } else if ( lvl->ncount % 2 == 1 ) {
1155                 syck_emitter_write( e, ":\n", 1 );
1156             } else if ( parent->status == syck_lvl_mapx ) {
1157                 syck_emitter_write( e, "\n", 1 );
1158             }
1159         break;
1160
1161         case syck_lvl_imap:
1162             syck_emitter_write( e, "}\n", 1 );
1163         break;
1164     }
1165 }
1166
1167 /*
1168  * Fill markers table with emitter nodes in the
1169  * soon-to-be-emitted tree.
1170  */
1171 SYMID
1172 syck_emitter_mark_node( SyckEmitter *e, st_data_t n )
1173 {
1174     SYMID oid = 0;
1175     char *anchor_name = NULL;
1176
1177     /*
1178      * Ensure markers table is initialized.
1179      */
1180     if ( e->markers == NULL )
1181     {
1182         e->markers = st_init_numtable();
1183     }
1184
1185     /*
1186      * Markers table initially marks the string position of the
1187      * object.  Doesn't yet create an anchor, simply notes the
1188      * position.
1189      */
1190     if ( ! st_lookup( e->markers, n, (st_data_t *)&oid ) )
1191     {
1192         /*
1193          * Store all markers
1194          */
1195         oid = e->markers->num_entries + 1;
1196         st_insert( e->markers, n, (st_data_t)oid );
1197     }
1198     else
1199     {
1200         if ( e->anchors == NULL )
1201         {
1202             e->anchors = st_init_numtable();
1203         }
1204
1205         if ( ! st_lookup( e->anchors, (st_data_t)oid, (st_data_t *)&anchor_name ) )
1206         {
1207             int idx = 0;
1208             char *anc = ( e->anchor_format == NULL ? DEFAULT_ANCHOR_FORMAT : e->anchor_format );
1209
1210             /*
1211              * Second time hitting this object, let's give it an anchor
1212              */
1213             idx = e->anchors->num_entries + 1;
1214             anchor_name = S_ALLOC_N( char, strlen( anc ) + 10 );
1215             S_MEMZERO( anchor_name, char, strlen( anc ) + 10 );
1216             sprintf( anchor_name, anc, idx );
1217
1218             /*
1219              * Insert into anchors table
1220              */
1221             st_insert( e->anchors, (st_data_t)oid, (st_data_t)anchor_name );
1222
1223             /* XXX - Added by Audrey Tang to handle self-recursive structures - XXX */
1224             return 0;
1225         }
1226     }
1227     return oid;
1228 }
1229
Note: See TracBrowser for help on using the browser.