root/JSON-Syck/trunk/emitter.c

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

apply audrey's patch

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( (src[i] < 0x20) ) // || (0x7E < src[i]) )
762         {
763             syck_emitter_write( e, "\\", 1 );
764             if( '\0' == src[i] )
765                 syck_emitter_write( e, "0", 1 );
766             else
767             {
768                 syck_emitter_write( e, "x", 1 );
769                 syck_emitter_write( e, (char *)hex_table + ((src[i] & 0xF0) >> 4), 1 );
770                 syck_emitter_write( e, (char *)hex_table + (src[i] & 0x0F), 1 );
771             }
772         }
773         else
774         {
775             syck_emitter_write( e, src + i, 1 );
776             if( '\\' == src[i] )
777                 syck_emitter_write( e, "\\", 1 );
778         }
779     }
780 }
781
782 /*
783  * Outputs a single-quoted block.
784  */
785 void syck_emit_1quoted( SyckEmitter *e, int width, char *str, long len )
786 {
787     char do_indent = 0;
788     char *mark = str;
789     char *start = str;
790     char *end = str;
791     syck_emitter_write( e, "'", 1 );
792     while ( mark < str + len ) {
793         if ( do_indent ) {
794             syck_emit_indent( e );
795             do_indent = 0;
796         }
797         switch ( *mark ) {
798             case '\'':  syck_emitter_write( e, "'", 1 ); break;
799
800             case '\n':
801                 end = mark + 1;
802                 if ( *start != ' ' && *start != '\n' && *end != '\n' && *end != ' ' ) {
803                     syck_emitter_write( e, "\n\n", 2 );
804                 } else {
805                     syck_emitter_write( e, "\n", 1 );
806                 }
807                 do_indent = 1;
808                 start = mark + 1;
809             break;
810
811             case ' ':
812                 if ( width > 0 && *start != ' ' && mark - end > width ) {
813                     do_indent = 1;
814                     end = mark + 1;
815                 } else {
816                     syck_emitter_write( e, " ", 1 );
817                 }
818             break;
819
820             default:
821                 syck_emitter_write( e, mark, 1 );
822             break;
823         }
824         mark++;
825     }
826     syck_emitter_write( e, "'", 1 );
827 }
828
829 /*
830  * Outputs a double-quoted block.
831  */
832 void syck_emit_2quoted( SyckEmitter *e, int width, char *str, long len )
833 {
834     char do_indent = 0;
835     char *mark = str;
836     char *start = str;
837     char *end = str;
838     syck_emitter_write( e, "\"", 1 );
839     while ( mark < str + len ) {
840         if ( do_indent > 0 ) {
841             if ( do_indent == 2 ) {
842                 syck_emitter_write( e, "\\", 1 );
843             }
844             syck_emit_indent( e );
845             do_indent = 0;
846         }
847         switch ( *mark ) {
848
849             /* Escape sequences allowed within double quotes. */
850             case '"':  syck_emitter_write( e, "\\\"", 2 ); break;
851             case '\\': syck_emitter_write( e, "\\\\", 2 ); break;
852             case '\0': syck_emitter_write( e, "\\0",  2 ); break;
853             case '\a': syck_emitter_write( e, "\\a",  2 ); break;
854             case '\b': syck_emitter_write( e, "\\b",  2 ); break;
855             case '\f': syck_emitter_write( e, "\\f",  2 ); break;
856             case '\r': syck_emitter_write( e, "\\r",  2 ); break;
857             case '\t': syck_emitter_write( e, "\\t",  2 ); break;
858             case '\v': syck_emitter_write( e, "\\v",  2 ); break;
859             case 0x1b: syck_emitter_write( e, "\\e",  2 ); break;
860
861             case '\n':
862                 end = mark + 1;
863                 syck_emitter_write( e, "\\n", 2 );
864                 do_indent = 2;
865                 start = mark + 1;
866                 if ( start < str + len && ( *start == ' ' || *start == '\n' ) ) {
867                     do_indent = 0;
868                 }
869             break;
870
871             case ' ':
872                 if ( width > 0 && *start != ' ' && mark - end > width ) {
873                     do_indent = 1;
874                     end = mark + 1;
875                 } else {
876                     syck_emitter_write( e, " ", 1 );
877                 }
878             break;
879
880             default:
881                 syck_emitter_escape( e, mark, 1 );
882             break;
883         }
884         mark++;
885     }
886     syck_emitter_write( e, "\"", 1 );
887 }
888
889 /*
890  * Outputs a literal block.
891  */
892 void syck_emit_literal( SyckEmitter *e, char keep_nl, char *str, long len )
893 {
894     char *mark = str;
895     char *start = str;
896     char *end = str;
897     syck_emitter_write( e, "|", 1 );
898     if ( keep_nl == NL_CHOMP ) {
899         syck_emitter_write( e, "-", 1 );
900     } else if ( keep_nl == NL_KEEP ) {
901         syck_emitter_write( e, "+", 1 );
902     }
903     syck_emit_indent( e );
904     while ( mark < str + len ) {
905         if ( *mark == '\n' ) {
906             end = mark;
907             if ( *start != ' ' && *start != '\n' && *end != '\n' && *end != ' ' ) end += 1;
908             syck_emitter_write( e, start, end - start );
909             if ( mark + 1 == str + len ) {
910                 if ( keep_nl != NL_KEEP ) syck_emitter_write( e, "\n", 1 );
911             } else {
912                 syck_emit_indent( e );
913             }
914             start = mark + 1;
915         }
916         mark++;
917     }
918     end = str + len;
919     if ( start < end ) {
920         syck_emitter_write( e, start, end - start );
921     }
922 }
923
924 /*
925  * Outputs a folded block.
926  */
927 void syck_emit_folded( SyckEmitter *e, int width, char keep_nl, char *str, long len )
928 {
929     char *mark = str;
930     char *start = str;
931     char *end = str;
932     syck_emitter_write( e, ">", 1 );
933     if ( keep_nl == NL_CHOMP ) {
934         syck_emitter_write( e, "-", 1 );
935     } else if ( keep_nl == NL_KEEP ) {
936         syck_emitter_write( e, "+", 1 );
937     }
938     syck_emit_indent( e );
939     if ( width <= 0 ) width = e->best_width;
940     while ( mark < str + len ) {
941         switch ( *mark ) {
942             case '\n':
943                 syck_emitter_write( e, end, mark - end );
944                 end = mark + 1;
945                 if ( *start != ' ' && *start != '\n' && *end != '\n' && *end != ' ' ) {
946                     syck_emitter_write( e, "\n", 1 );
947                 }
948                 if ( mark + 1 == str + len ) {
949                     if ( keep_nl != NL_KEEP ) syck_emitter_write( e, "\n", 1 );
950                 } else {
951                     syck_emit_indent( e );
952                 }
953                 start = mark + 1;
954             break;
955
956             case ' ':
957                 if ( *start != ' ' ) {
958                     if ( mark - end > width ) {
959                         syck_emitter_write( e, end, mark - end );
960                         syck_emit_indent( e );
961                         end = mark + 1;
962                     }
963                 }
964             break;
965         }
966         mark++;
967     }
968     if ( end < mark ) {
969         syck_emitter_write( e, end, mark - end );
970     }
971 }
972
973 /*
974  * Begins emission of a sequence.
975  */
976 void syck_emit_seq( SyckEmitter *e, char *tag, enum seq_style style )
977 {
978     SyckLevel *parent = syck_emitter_parent_level( e );
979     SyckLevel *lvl = syck_emitter_current_level( e );
980     syck_emit_tag( e, tag, "tag:yaml.org,2002:seq" );
981     if ( style == seq_inline || ( parent->status == syck_lvl_imap || parent->status == syck_lvl_iseq ) ) {
982         syck_emitter_write( e, "[", 1 );
983         lvl->status = syck_lvl_iseq;
984     } else {
985         lvl->status = syck_lvl_seq;
986     }
987 }
988
989 /*
990  * Begins emission of a mapping.
991  */
992 void syck_emit_map( SyckEmitter *e, char *tag, enum map_style style )
993 {
994     SyckLevel *parent = syck_emitter_parent_level( e );
995     SyckLevel *lvl = syck_emitter_current_level( e );
996     syck_emit_tag( e, tag, "tag:yaml.org,2002:map" );
997     if ( style == map_inline || ( parent->status == syck_lvl_imap || parent->status == syck_lvl_iseq ) ) {
998         syck_emitter_write( e, "{", 1 );
999         lvl->status = syck_lvl_imap;
1000     } else {
1001         lvl->status = syck_lvl_map;
1002     }
1003 }
1004
1005 /*
1006  * Handles emitting of a collection item (for both
1007  * sequences and maps)
1008  */
1009 void syck_emit_item( SyckEmitter *e, st_data_t n )
1010 {
1011     SyckLevel *lvl = syck_emitter_current_level( e );
1012     switch ( lvl->status )
1013     {
1014         case syck_lvl_seq:
1015         {
1016             SyckLevel *parent = syck_emitter_parent_level( e );
1017
1018             /* seq-in-map shortcut */
1019             if ( parent->status == syck_lvl_map && lvl->ncount == 0 ) {
1020                 /* complex key */
1021                 if ( parent->ncount % 2 == 1 ) {
1022                     syck_emitter_write( e, "?", 1 );
1023                     parent->status = syck_lvl_mapx;
1024                 /* shortcut -- the lvl->anctag check should be unneccesary but
1025                  * there is a nasty shift/reduce in the parser on this point and
1026                  * i'm not ready to tickle it. */
1027                 } else if ( lvl->anctag == 0 ) {
1028                     lvl->spaces = parent->spaces;
1029                 }
1030             }
1031
1032             /* seq-in-seq shortcut */
1033             else if ( lvl->anctag == 0 && parent->status == syck_lvl_seq && lvl->ncount == 0 ) {
1034                 int spcs = ( lvl->spaces - parent->spaces ) - 2;
1035                 if ( spcs >= 0 ) {
1036                     int i = 0;
1037                     for ( i = 0; i < spcs; i++ ) {
1038                         syck_emitter_write( e, " ", 1 );
1039                     }
1040                     syck_emitter_write( e, "- ", 2 );
1041                     break;
1042                 }
1043             }
1044
1045             syck_emit_indent( e );
1046             syck_emitter_write( e, "- ", 2 );
1047         }
1048         break;
1049
1050         case syck_lvl_iseq:
1051         {
1052             if ( lvl->ncount > 0 ) {
1053                 syck_emitter_write( e, ", ", 2 );
1054             }
1055         }
1056         break;
1057
1058         case syck_lvl_map:
1059         {
1060             SyckLevel *parent = syck_emitter_parent_level( e );
1061
1062             /* map-in-map */
1063             if ( parent->status == syck_lvl_map && lvl->ncount == 0 ) {
1064                 /* complex key */
1065                 if ( parent->ncount % 2 == 1 ) {
1066                     syck_emitter_write( e, "?", 1 );
1067                     parent->status = syck_lvl_mapx;
1068                 }
1069             }
1070
1071             /* map-in-seq shortcut */
1072             if ( lvl->anctag == 0 && parent->status == syck_lvl_seq && lvl->ncount == 0 ) {
1073                 int spcs = ( lvl->spaces - parent->spaces ) - 2;
1074                 if ( spcs >= 0 ) {
1075                     int i = 0;
1076                     for ( i = 0; i < spcs; i++ ) {
1077                         syck_emitter_write( e, " ", 1 );
1078                     }
1079                     break;
1080                 }
1081             }
1082
1083             if ( lvl->ncount % 2 == 0 ) {
1084                 syck_emit_indent( e );
1085             } else {
1086                 syck_emitter_write( e, ": ", 2 );
1087             }
1088         }
1089         break;
1090
1091         case syck_lvl_mapx:
1092         {
1093             if ( lvl->ncount % 2 == 0 ) {
1094                 syck_emit_indent( e );
1095                 lvl->status = syck_lvl_map;
1096             } else {
1097                 int i;
1098                 if ( lvl->spaces > 0 ) {
1099                     char *spcs = S_ALLOC_N( char, lvl->spaces + 1 );
1100
1101                     spcs[lvl->spaces] = '\0';
1102                     for ( i = 0; i < lvl->spaces; i++ ) spcs[i] = ' ';
1103                     syck_emitter_write( e, spcs, lvl->spaces );
1104                     S_FREE( spcs );
1105                 }
1106                 syck_emitter_write( e, ": ", 2 );
1107             }
1108         }
1109         break;
1110
1111         case syck_lvl_imap:
1112         {
1113             if ( lvl->ncount > 0 ) {
1114                 if ( lvl->ncount % 2 == 0 ) {
1115                     syck_emitter_write( e, ", ", 2 );
1116                 } else {
1117                     syck_emitter_write( e, ": ", 2 );
1118                 }
1119             }
1120         }
1121         break;
1122     }
1123     lvl->ncount++;
1124
1125     syck_emit( e, n );
1126 }
1127
1128 /*
1129  * Closes emission of a collection.
1130  */
1131 void syck_emit_end( SyckEmitter *e )
1132 {
1133     SyckLevel *lvl = syck_emitter_current_level( e );
1134     SyckLevel *parent = syck_emitter_parent_level( e );
1135     switch ( lvl->status )
1136     {
1137         case syck_lvl_seq:
1138             if ( lvl->ncount == 0 ) {
1139                 syck_emitter_write( e, "[]\n", 3 );
1140             } else if ( parent->status == syck_lvl_mapx ) {
1141                 syck_emitter_write( e, "\n", 1 );
1142             }
1143         break;
1144
1145         case syck_lvl_iseq:
1146             syck_emitter_write( e, "]\n", 1 );
1147         break;
1148
1149         case syck_lvl_map:
1150             if ( lvl->ncount == 0 ) {
1151                 syck_emitter_write( e, "{}\n", 3 );
1152             } else if ( lvl->ncount % 2 == 1 ) {
1153                 syck_emitter_write( e, ":\n", 1 );
1154             } else if ( parent->status == syck_lvl_mapx ) {
1155                 syck_emitter_write( e, "\n", 1 );
1156             }
1157         break;
1158
1159         case syck_lvl_imap:
1160             syck_emitter_write( e, "}\n", 1 );
1161         break;
1162     }
1163 }
1164
1165 /*
1166  * Fill markers table with emitter nodes in the
1167  * soon-to-be-emitted tree.
1168  */
1169 SYMID
1170 syck_emitter_mark_node( SyckEmitter *e, st_data_t n )
1171 {
1172     SYMID oid = 0;
1173     char *anchor_name = NULL;
1174
1175     /*
1176      * Ensure markers table is initialized.
1177      */
1178     if ( e->markers == NULL )
1179     {
1180         e->markers = st_init_numtable();
1181     }
1182
1183     /*
1184      * Markers table initially marks the string position of the
1185      * object.  Doesn't yet create an anchor, simply notes the
1186      * position.
1187      */
1188     if ( ! st_lookup( e->markers, n, (st_data_t *)&oid ) )
1189     {
1190         /*
1191          * Store all markers
1192          */
1193         oid = e->markers->num_entries + 1;
1194         st_insert( e->markers, n, (st_data_t)oid );
1195     }
1196     else
1197     {
1198         if ( e->anchors == NULL )
1199         {
1200             e->anchors = st_init_numtable();
1201         }
1202
1203         if ( ! st_lookup( e->anchors, (st_data_t)oid, (st_data_t *)&anchor_name ) )
1204         {
1205             int idx = 0;
1206             char *anc = ( e->anchor_format == NULL ? DEFAULT_ANCHOR_FORMAT : e->anchor_format );
1207
1208             /*
1209              * Second time hitting this object, let's give it an anchor
1210              */
1211             idx = e->anchors->num_entries + 1;
1212             anchor_name = S_ALLOC_N( char, strlen( anc ) + 10 );
1213             S_MEMZERO( anchor_name, char, strlen( anc ) + 10 );
1214             sprintf( anchor_name, anc, idx );
1215
1216             /*
1217              * Insert into anchors table
1218              */
1219             st_insert( e->anchors, (st_data_t)oid, (st_data_t)anchor_name );
1220         }
1221     }
1222     return oid;
1223 }
1224
Note: See TracBrowser for help on using the browser.