6 * Copyright (C) 2003 why the lucky stiff
8 * All Base64 code from Ruby's pack.c.
9 * Ruby is Copyright (C) 1993-2007 Yukihiro Matsumoto
11 #include "ruby/ruby.h"
18 #define DEFAULT_ANCHOR_FORMAT "id%03d"
20 const char hex_table
[] =
22 static char b64_table
[] =
23 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
26 * Built-in base64 (from Ruby's pack.c)
29 syck_base64enc( char *s
, long len
)
33 char *buff
= S_ALLOC_N(char, len
* 4 / 3 + 6);
36 buff
[i
++] = b64_table
[077 & (*s
>> 2)];
37 buff
[i
++] = b64_table
[077 & (((*s
<< 4) & 060) | ((s
[1] >> 4) & 017))];
38 buff
[i
++] = b64_table
[077 & (((s
[1] << 2) & 074) | ((s
[2] >> 6) & 03))];
39 buff
[i
++] = b64_table
[077 & s
[2]];
44 buff
[i
++] = b64_table
[077 & (*s
>> 2)];
45 buff
[i
++] = b64_table
[077 & (((*s
<< 4) & 060) | ((s
[1] >> 4) & 017))];
46 buff
[i
++] = b64_table
[077 & (((s
[1] << 2) & 074) | (('\0' >> 6) & 03))];
50 buff
[i
++] = b64_table
[077 & (*s
>> 2)];
51 buff
[i
++] = b64_table
[077 & (((*s
<< 4) & 060) | (('\0' >> 4) & 017))];
60 syck_base64dec( char *s
, long len
)
62 int a
= -1,b
= -1,c
= 0,d
;
64 static int b64_xtable
[256];
65 char *ptr
= syck_strndup( s
, len
);
73 for (i
= 0; i
< 256; i
++) {
76 for (i
= 0; i
< 64; i
++) {
77 b64_xtable
[(int)b64_table
[i
]] = i
;
81 while (s
[0] == '\r' || s
[0] == '\n') { s
++; }
82 if ((a
= b64_xtable
[(int)s
[0]]) == -1) break;
83 if ((b
= b64_xtable
[(int)s
[1]]) == -1) break;
84 if ((c
= b64_xtable
[(int)s
[2]]) == -1) break;
85 if ((d
= b64_xtable
[(int)s
[3]]) == -1) break;
86 *end
++ = a
<< 2 | b
>> 4;
87 *end
++ = b
<< 4 | c
>> 2;
91 if (a
!= -1 && b
!= -1) {
92 if (s
+ 2 < send
&& s
[2] == '=')
93 *end
++ = a
<< 2 | b
>> 4;
94 if (c
!= -1 && s
+ 3 < send
&& s
[3] == '=') {
95 *end
++ = a
<< 2 | b
>> 4;
96 *end
++ = b
<< 4 | c
>> 2;
100 /*RSTRING_LEN(buf) = ptr - RSTRING_PTR(buf);*/
105 * Allocate an emitter
108 syck_new_emitter(void)
111 e
= S_ALLOC( SyckEmitter
);
116 e
->anchor_format
= NULL
;
117 e
->explicit_typing
= 0;
119 e
->style
= scalar_none
;
126 e
->bufsize
= SYCK_BUFFERSIZE
;
130 e
->emitter_handler
= NULL
;
131 e
->output_handler
= NULL
;
133 e
->lvl_capa
= ALLOC_CT
;
134 e
->levels
= S_ALLOC_N( SyckLevel
, e
->lvl_capa
);
135 syck_emitter_reset_levels( e
);
141 syck_st_free_anchors( char *key
, char *name
, char *arg
)
148 syck_emitter_st_free( SyckEmitter
*e
)
151 * Free the anchor tables
153 if ( e
->anchors
!= NULL
)
155 st_foreach( e
->anchors
, syck_st_free_anchors
, 0 );
156 st_free_table( e
->anchors
);
160 if ( e
->anchored
!= NULL
)
162 st_free_table( e
->anchored
);
167 * Free the markers tables
169 if ( e
->markers
!= NULL
)
171 st_free_table( e
->markers
);
177 syck_emitter_current_level( SyckEmitter
*e
)
179 return &e
->levels
[e
->lvl_idx
-1];
183 syck_emitter_parent_level( SyckEmitter
*e
)
185 return &e
->levels
[e
->lvl_idx
-2];
189 syck_emitter_pop_level( SyckEmitter
*e
)
193 /* The root level should never be popped */
194 if ( e
->lvl_idx
<= 1 ) return;
197 free( e
->levels
[e
->lvl_idx
].domain
);
201 syck_emitter_add_level( SyckEmitter
*e
, int len
, enum syck_level_status status
)
204 if ( e
->lvl_idx
+ 1 > e
->lvl_capa
)
206 e
->lvl_capa
+= ALLOC_CT
;
207 S_REALLOC_N( e
->levels
, SyckLevel
, e
->lvl_capa
);
210 ASSERT( len
> e
->levels
[e
->lvl_idx
-1].spaces
);
211 e
->levels
[e
->lvl_idx
].spaces
= len
;
212 e
->levels
[e
->lvl_idx
].ncount
= 0;
213 e
->levels
[e
->lvl_idx
].domain
= syck_strndup( e
->levels
[e
->lvl_idx
-1].domain
, strlen( e
->levels
[e
->lvl_idx
-1].domain
) );
214 e
->levels
[e
->lvl_idx
].status
= status
;
215 e
->levels
[e
->lvl_idx
].anctag
= 0;
220 syck_emitter_reset_levels( SyckEmitter
*e
)
222 while ( e
->lvl_idx
> 1 )
224 syck_emitter_pop_level( e
);
227 if ( e
->lvl_idx
< 1 )
230 e
->levels
[0].spaces
= -1;
231 e
->levels
[0].ncount
= 0;
232 e
->levels
[0].domain
= syck_strndup( "", 0 );
233 e
->levels
[0].anctag
= 0;
235 e
->levels
[0].status
= syck_lvl_header
;
239 syck_emitter_handler( SyckEmitter
*e
, SyckEmitterHandler hdlr
)
241 e
->emitter_handler
= hdlr
;
245 syck_output_handler( SyckEmitter
*e
, SyckOutputHandler hdlr
)
247 e
->output_handler
= hdlr
;
251 syck_free_emitter( SyckEmitter
*e
)
256 syck_emitter_st_free( e
);
257 syck_emitter_reset_levels( e
);
258 S_FREE( e
->levels
[0].domain
);
260 if ( e
->buffer
!= NULL
)
268 syck_emitter_clear( SyckEmitter
*e
)
270 if ( e
->buffer
== NULL
)
272 e
->buffer
= S_ALLOC_N( char, e
->bufsize
);
273 S_MEMZERO( e
->buffer
, char, e
->bufsize
);
276 e
->marker
= e
->buffer
;
281 * Raw write to the emitter buffer.
284 syck_emitter_write( SyckEmitter
*e
, const char *str
, long len
)
287 ASSERT( str
!= NULL
);
288 if ( e
->buffer
== NULL
)
290 syck_emitter_clear( e
);
294 * Flush if at end of buffer
296 at
= e
->marker
- e
->buffer
;
297 if ( len
+ at
>= e
->bufsize
)
299 syck_emitter_flush( e
, 0 );
301 long rest
= e
->bufsize
- (e
->marker
- e
->buffer
);
302 if (len
<= rest
) break;
303 S_MEMCPY( e
->marker
, str
, char, rest
);
307 syck_emitter_flush( e
, 0 );
314 S_MEMCPY( e
->marker
, str
, char, len
);
319 * Write a chunk of data out.
322 syck_emitter_flush( SyckEmitter
*e
, long check_room
)
325 * Check for enough space in the buffer for check_room length.
327 if ( check_room
> 0 )
329 if ( e
->bufsize
> ( e
->marker
- e
->buffer
) + check_room
)
336 check_room
= e
->bufsize
;
342 if ( check_room
> e
->marker
- e
->buffer
)
344 check_room
= e
->marker
- e
->buffer
;
346 (e
->output_handler
)( e
, e
->buffer
, check_room
);
347 e
->bufpos
+= check_room
;
348 e
->marker
-= check_room
;
352 * Start emitting from the given node, check for anchoring and then
353 * issue the callback to the emitter handler.
356 syck_emit( SyckEmitter
*e
, st_data_t n
)
359 char *anchor_name
= NULL
;
362 SyckLevel
*lvl
= syck_emitter_current_level( e
);
367 if ( e
->stage
== doc_open
&& ( e
->headless
== 0 || e
->use_header
== 1 ) )
369 if ( e
->use_version
== 1 )
371 char *header
= S_ALLOC_N( char, 64 );
372 S_MEMZERO( header
, char, 64 );
373 sprintf( header
, "--- %%YAML:%d.%d ", SYCK_YAML_MAJOR
, SYCK_YAML_MINOR
);
374 syck_emitter_write( e
, header
, strlen( header
) );
379 syck_emitter_write( e
, "--- ", 4 );
381 e
->stage
= doc_processing
;
385 if ( lvl
->spaces
>= 0 ) {
386 indent
= lvl
->spaces
+ e
->indent
;
388 syck_emitter_add_level( e
, indent
, syck_lvl_open
);
389 lvl
= syck_emitter_current_level( e
);
391 /* Look for anchor */
392 if ( e
->anchors
!= NULL
&&
393 st_lookup( e
->markers
, n
, (st_data_t
*)&oid
) &&
394 st_lookup( e
->anchors
, (st_data_t
)oid
, (void *)&anchor_name
) )
396 if ( e
->anchored
== NULL
)
398 e
->anchored
= st_init_numtable();
401 if ( ! st_lookup( e
->anchored
, (st_data_t
)anchor_name
, (st_data_t
*)&x
) )
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 );
409 st_insert( e
->anchored
, (st_data_t
)anchor_name
, (st_data_t
)x
);
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 );
423 (e
->emitter_handler
)( e
, n
);
427 syck_emitter_pop_level( e
);
428 if ( e
->lvl_idx
== 1 ) {
429 syck_emitter_write( e
, "\n", 1 );
436 * Determine what tag needs to be written, based on the taguri of the node
437 * and the implicit tag which would be assigned to this node. If a tag is
438 * required, write the tag.
440 void syck_emit_tag( SyckEmitter
*e
, const char *tag
, const char *ignore
)
443 if ( tag
== NULL
) return;
444 if ( ignore
!= NULL
&& syck_tagcmp( tag
, ignore
) == 0 && e
->explicit_typing
== 0 ) return;
445 lvl
= syck_emitter_current_level( e
);
448 if ( strlen( tag
) == 0 ) {
449 syck_emitter_write( e
, "! ", 2 );
452 } else if ( strncmp( tag
, "tag:", 4 ) == 0 ) {
453 int taglen
= strlen( tag
);
454 syck_emitter_write( e
, "!", 1 );
455 if ( strncmp( tag
+ 4, YAML_DOMAIN
, strlen( YAML_DOMAIN
) ) == 0 ) {
456 int skip
= 4 + strlen( YAML_DOMAIN
) + 1;
457 syck_emitter_write( e
, tag
+ skip
, taglen
- skip
);
459 const char *subd
= tag
+ 4;
460 while ( *subd
!= ':' && *subd
!= '\0' ) subd
++;
461 if ( *subd
== ':' ) {
462 if ( subd
- tag
> ( strlen( YAML_DOMAIN
) + 5 ) &&
463 strncmp( subd
- strlen( YAML_DOMAIN
), YAML_DOMAIN
, strlen( YAML_DOMAIN
) ) == 0 ) {
464 syck_emitter_write( e
, tag
+ 4, subd
- strlen( YAML_DOMAIN
) - ( tag
+ 4 ) - 1 );
465 syck_emitter_write( e
, "/", 1 );
466 syck_emitter_write( e
, subd
+ 1, ( tag
+ taglen
) - ( subd
+ 1 ) );
468 syck_emitter_write( e
, tag
+ 4, subd
- ( tag
+ 4 ) );
469 syck_emitter_write( e
, "/", 1 );
470 syck_emitter_write( e
, subd
+ 1, ( tag
+ taglen
) - ( subd
+ 1 ) );
473 /* TODO: Invalid tag (no colon after domain) */
477 syck_emitter_write( e
, " ", 1 );
480 } else if ( strncmp( tag
, "x-private:", 10 ) == 0 ) {
481 syck_emitter_write( e
, "!!", 2 );
482 syck_emitter_write( e
, tag
+ 10, strlen( tag
) - 10 );
483 syck_emitter_write( e
, " ", 1 );
489 * Emit a newline and an appropriately spaced indent.
491 void syck_emit_indent( SyckEmitter
*e
)
494 SyckLevel
*lvl
= syck_emitter_current_level( e
);
495 if ( e
->bufpos
== 0 && ( e
->marker
- e
->buffer
) == 0 ) return;
496 if ( lvl
->spaces
>= 0 ) {
497 char *spcs
= S_ALLOC_N( char, lvl
->spaces
+ 2 );
499 spcs
[0] = '\n'; spcs
[lvl
->spaces
+ 1] = '\0';
500 for ( i
= 0; i
< lvl
->spaces
; i
++ ) spcs
[i
+1] = ' ';
501 syck_emitter_write( e
, spcs
, lvl
->spaces
+ 1 );
508 /* All printable characters? */
509 #define SCAN_NONPRINT 1
510 /* Any indented lines? */
511 #define SCAN_INDENTED 2
512 /* Larger than the requested width? */
514 /* Opens or closes with whitespace? */
515 #define SCAN_WHITEEDGE 8
516 /* Contains a newline */
517 #define SCAN_NEWLINE 16
518 /* Contains a single quote */
519 #define SCAN_SINGLEQ 32
520 /* Contains a double quote */
521 #define SCAN_DOUBLEQ 64
522 /* Starts with a token */
523 #define SCAN_INDIC_S 128
524 /* Contains a flow indicator */
525 #define SCAN_INDIC_C 256
526 /* Ends without newlines */
527 #define SCAN_NONL_E 512
528 /* Ends with many newlines */
529 #define SCAN_MANYNL_E 1024
530 /* Contains flow map indicators */
531 #define SCAN_FLOWMAP 2048
532 /* Contains flow seq indicators */
533 #define SCAN_FLOWSEQ 4096
534 /* Contains a valid doc separator */
535 #define SCAN_DOCSEP 8192
538 * Basic printable test for LATIN-1 characters.
541 syck_scan_scalar( int req_width
, const char *cursor
, long len
)
543 long i
= 0, start
= 0;
544 int flags
= SCAN_NONE
;
546 if ( len
< 1 ) return flags
;
548 /* c-indicators from the spec */
549 if ( cursor
[0] == '[' || cursor
[0] == ']' ||
550 cursor
[0] == '{' || cursor
[0] == '}' ||
551 cursor
[0] == '!' || cursor
[0] == '*' ||
552 cursor
[0] == '&' || cursor
[0] == '|' ||
553 cursor
[0] == '>' || cursor
[0] == '\'' ||
554 cursor
[0] == '"' || cursor
[0] == '#' ||
555 cursor
[0] == '%' || cursor
[0] == '@' ||
557 flags
|= SCAN_INDIC_S
;
559 if ( ( cursor
[0] == '-' || cursor
[0] == ':' ||
560 cursor
[0] == '?' || cursor
[0] == ',' ) &&
561 ( len
== 1 || cursor
[1] == ' ' || cursor
[1] == '\n' ) )
563 flags
|= SCAN_INDIC_S
;
566 /* whitespace edges */
567 if ( cursor
[len
-1] != '\n' ) {
568 flags
|= SCAN_NONL_E
;
569 } else if ( len
> 1 && cursor
[len
-2] == '\n' ) {
570 flags
|= SCAN_MANYNL_E
;
573 ( len
> 0 && ( cursor
[0] == ' ' || cursor
[0] == '\t' ) ) ||
574 ( len
> 1 && ( cursor
[len
-1] == ' ' || cursor
[len
-1] == '\t' ) )
576 flags
|= SCAN_WHITEEDGE
;
579 /* opening doc sep */
580 if ( len
>= 3 && strncmp( cursor
, "---", 3 ) == 0 )
581 flags
|= SCAN_DOCSEP
;
584 for ( i
= 0; i
< len
; i
++ ) {
586 if ( ! ( cursor
[i
] == 0x9 ||
589 ( cursor
[i
] >= 0x20 && cursor
[i
] <= 0x7E ) )
591 flags
|= SCAN_NONPRINT
;
593 else if ( cursor
[i
] == '\n' ) {
594 flags
|= SCAN_NEWLINE
;
595 if ( len
- i
>= 3 && strncmp( &cursor
[i
+1], "---", 3 ) == 0 )
596 flags
|= SCAN_DOCSEP
;
597 if ( cursor
[i
+1] == ' ' || cursor
[i
+1] == '\t' )
598 flags
|= SCAN_INDENTED
;
599 if ( req_width
> 0 && i
- start
> req_width
)
603 else if ( cursor
[i
] == '\'' )
605 flags
|= SCAN_SINGLEQ
;
607 else if ( cursor
[i
] == '"' )
609 flags
|= SCAN_DOUBLEQ
;
611 else if ( cursor
[i
] == ']' )
613 flags
|= SCAN_FLOWSEQ
;
615 else if ( cursor
[i
] == '}' )
617 flags
|= SCAN_FLOWMAP
;
619 /* remember, if plain collections get implemented, to add nb-plain-flow-char */
620 else if ( ( cursor
[i
] == ' ' && cursor
[i
+1] == '#' ) ||
621 ( cursor
[i
] == ':' &&
622 ( cursor
[i
+1] == ' ' || cursor
[i
+1] == '\n' || i
== len
- 1 ) ) )
624 flags
|= SCAN_INDIC_C
;
626 else if ( cursor
[i
] == ',' &&
627 ( cursor
[i
+1] == ' ' || cursor
[i
+1] == '\n' || i
== len
- 1 ) )
629 flags
|= SCAN_FLOWMAP
;
630 flags
|= SCAN_FLOWSEQ
;
634 /* printf( "---STR---\n%s\nFLAGS: %d\n", cursor, flags ); */
638 * All scalars should be emitted through this function, which determines an appropriate style,
641 void syck_emit_scalar( SyckEmitter
*e
, const char *tag
, enum scalar_style force_style
, int force_indent
, int force_width
,
642 char keep_nl
, const char *str
, long len
)
644 enum scalar_style favor_style
= scalar_literal
;
645 SyckLevel
*parent
= syck_emitter_parent_level( e
);
646 SyckLevel
*lvl
= syck_emitter_current_level( e
);
648 const char *match_implicit
;
651 if ( str
== NULL
) str
= "";
653 /* No empty nulls as map keys */
654 if ( len
== 0 && ( parent
->status
== syck_lvl_map
|| parent
->status
== syck_lvl_imap
) &&
655 parent
->ncount
% 2 == 1 && syck_tagcmp( tag
, "tag:yaml.org,2002:null" ) == 0 )
661 scan
= syck_scan_scalar( force_width
, str
, len
);
662 match_implicit
= syck_match_implicit( str
, len
);
664 /* quote strings which default to implicits */
665 implicit
= syck_taguri( YAML_DOMAIN
, match_implicit
, strlen( match_implicit
) );
666 if ( syck_tagcmp( tag
, implicit
) != 0 && syck_tagcmp( tag
, "tag:yaml.org,2002:str" ) == 0 ) {
667 force_style
= scalar_2quote
;
670 if ( parent
->status
== syck_lvl_map
&& parent
->ncount
% 2 == 1 &&
672 ( implicit
!= NULL
&& syck_tagcmp( tag
, implicit
) == 0 && e
->explicit_typing
== 0 ) ) ) )
674 syck_emitter_write( e
, "? ", 2 );
675 parent
->status
= syck_lvl_mapx
;
677 syck_emit_tag( e
, tag
, implicit
);
681 /* if still arbitrary, sniff a good block style. */
682 if ( force_style
== scalar_none
) {
683 if ( scan
& SCAN_NEWLINE
) {
684 force_style
= scalar_literal
;
686 force_style
= scalar_plain
;
690 if ( e
->style
== scalar_fold
) {
691 favor_style
= scalar_fold
;
694 /* Determine block style */
695 if ( scan
& SCAN_NONPRINT
) {
696 force_style
= scalar_2quote
;
697 } else if ( scan
& SCAN_WHITEEDGE
) {
698 force_style
= scalar_2quote
;
699 } else if ( force_style
!= scalar_fold
&& ( scan
& SCAN_INDENTED
) ) {
700 force_style
= scalar_literal
;
701 } else if ( force_style
== scalar_plain
&& ( scan
& SCAN_NEWLINE
) ) {
702 force_style
= favor_style
;
703 } else if ( force_style
== scalar_plain
&& parent
->status
== syck_lvl_iseq
&& ( scan
& SCAN_FLOWSEQ
) ) {
704 force_style
= scalar_2quote
;
705 } else if ( force_style
== scalar_plain
&& parent
->status
== syck_lvl_imap
&& ( scan
& SCAN_FLOWMAP
) ) {
706 force_style
= scalar_2quote
;
707 /* } else if ( force_style == scalar_fold && ( ! ( scan & SCAN_WIDE ) ) ) {
708 force_style = scalar_literal; */
709 } else if ( force_style
== scalar_plain
&& ( scan
& SCAN_INDIC_S
|| scan
& SCAN_INDIC_C
) ) {
710 if ( scan
& SCAN_NEWLINE
) {
711 force_style
= favor_style
;
713 force_style
= scalar_2quote
;
717 if ( force_indent
> 0 ) {
718 lvl
->spaces
= parent
->spaces
+ force_indent
;
719 } else if ( scan
& SCAN_DOCSEP
) {
720 lvl
->spaces
= parent
->spaces
+ e
->indent
;
723 /* For now, all ambiguous keys are going to be double-quoted */
724 if ( ( parent
->status
== syck_lvl_map
|| parent
->status
== syck_lvl_mapx
) && parent
->ncount
% 2 == 1 ) {
725 if ( force_style
!= scalar_plain
) {
726 force_style
= scalar_2quote
;
730 /* If the parent is an inline, double quote anything complex */
731 if ( parent
->status
== syck_lvl_imap
|| parent
->status
== syck_lvl_iseq
) {
732 if ( force_style
!= scalar_plain
&& force_style
!= scalar_1quote
) {
733 force_style
= scalar_2quote
;
737 /* Fix the ending newlines */
738 if ( scan
& SCAN_NONL_E
) {
740 } else if ( scan
& SCAN_MANYNL_E
) {
744 /* Write the text node */
745 switch ( force_style
)
748 syck_emit_1quoted( e
, force_width
, str
, len
);
753 syck_emit_2quoted( e
, force_width
, str
, len
);
757 syck_emit_folded( e
, force_width
, keep_nl
, str
, len
);
761 syck_emit_literal( e
, keep_nl
, str
, len
);
765 syck_emitter_write( e
, str
, len
);
769 if ( parent
->status
== syck_lvl_mapx
)
771 syck_emitter_write( e
, "\n", 1 );
776 syck_emitter_escape( SyckEmitter
*e
, const char *src
, long len
)
779 for( i
= 0; i
< len
; i
++ )
781 if( (src
[i
] < 0x20) || (0x7E < src
[i
]) )
783 syck_emitter_write( e
, "\\", 1 );
785 syck_emitter_write( e
, "0", 1 );
788 syck_emitter_write( e
, "x", 1 );
789 syck_emitter_write( e
, (const char *)hex_table
+ ((src
[i
] & 0xF0) >> 4), 1 );
790 syck_emitter_write( e
, (const char *)hex_table
+ (src
[i
] & 0x0F), 1 );
795 syck_emitter_write( e
, src
+ i
, 1 );
797 syck_emitter_write( e
, "\\", 1 );
803 * Outputs a single-quoted block.
806 syck_emit_1quoted( SyckEmitter
*e
, int width
, const char *str
, long len
)
809 const char *mark
= str
;
810 const char *start
= str
;
811 const char *end
= str
;
812 syck_emitter_write( e
, "'", 1 );
813 while ( mark
< str
+ len
) {
815 syck_emit_indent( e
);
819 case '\'': syck_emitter_write( e
, "'", 1 ); break;
823 if ( *start
!= ' ' && *start
!= '\n' && *end
!= '\n' && *end
!= ' ' ) {
824 syck_emitter_write( e
, "\n\n", 2 );
826 syck_emitter_write( e
, "\n", 1 );
833 if ( width
> 0 && *start
!= ' ' && mark
- end
> width
) {
837 syck_emitter_write( e
, " ", 1 );
842 syck_emitter_write( e
, mark
, 1 );
847 syck_emitter_write( e
, "'", 1 );
851 * Outputs a double-quoted block.
854 syck_emit_2quoted( SyckEmitter
*e
, int width
, const char *str
, long len
)
857 const char *mark
= str
;
858 const char *start
= str
;
859 const char *end
= str
;
860 syck_emitter_write( e
, "\"", 1 );
861 while ( mark
< str
+ len
) {
862 if ( do_indent
> 0 ) {
863 if ( do_indent
== 2 ) {
864 syck_emitter_write( e
, "\\", 1 );
866 syck_emit_indent( e
);
871 /* Escape sequences allowed within double quotes. */
872 case '"': syck_emitter_write( e
, "\\\"", 2 ); break;
873 case '\\': syck_emitter_write( e
, "\\\\", 2 ); break;
874 case '\0': syck_emitter_write( e
, "\\0", 2 ); break;
875 case '\a': syck_emitter_write( e
, "\\a", 2 ); break;
876 case '\b': syck_emitter_write( e
, "\\b", 2 ); break;
877 case '\f': syck_emitter_write( e
, "\\f", 2 ); break;
878 case '\r': syck_emitter_write( e
, "\\r", 2 ); break;
879 case '\t': syck_emitter_write( e
, "\\t", 2 ); break;
880 case '\v': syck_emitter_write( e
, "\\v", 2 ); break;
881 case 0x1b: syck_emitter_write( e
, "\\e", 2 ); break;
885 syck_emitter_write( e
, "\\n", 2 );
888 if ( start
< str
+ len
&& ( *start
== ' ' || *start
== '\n' ) ) {
894 if ( width
> 0 && *start
!= ' ' && mark
- end
> width
) {
898 syck_emitter_write( e
, " ", 1 );
903 syck_emitter_escape( e
, mark
, 1 );
908 syck_emitter_write( e
, "\"", 1 );
912 * Outputs a literal block.
915 syck_emit_literal( SyckEmitter
*e
, char keep_nl
, const char *str
, long len
)
917 const char *mark
= str
;
918 const char *start
= str
;
919 const char *end
= str
;
920 syck_emitter_write( e
, "|", 1 );
921 if ( keep_nl
== NL_CHOMP
) {
922 syck_emitter_write( e
, "-", 1 );
923 } else if ( keep_nl
== NL_KEEP
) {
924 syck_emitter_write( e
, "+", 1 );
926 syck_emit_indent( e
);
927 while ( mark
< str
+ len
) {
928 if ( *mark
== '\n' ) {
930 if ( *start
!= ' ' && *start
!= '\n' && *end
!= '\n' && *end
!= ' ' ) end
+= 1;
931 syck_emitter_write( e
, start
, end
- start
);
932 if ( mark
+ 1 == str
+ len
) {
933 if ( keep_nl
!= NL_KEEP
) syck_emitter_write( e
, "\n", 1 );
935 syck_emit_indent( e
);
943 syck_emitter_write( e
, start
, end
- start
);
948 * Outputs a folded block.
951 syck_emit_folded( SyckEmitter
*e
, int width
, char keep_nl
, const char *str
, long len
)
953 const char *mark
= str
;
954 const char *start
= str
;
955 const char *end
= str
;
956 syck_emitter_write( e
, ">", 1 );
957 if ( keep_nl
== NL_CHOMP
) {
958 syck_emitter_write( e
, "-", 1 );
959 } else if ( keep_nl
== NL_KEEP
) {
960 syck_emitter_write( e
, "+", 1 );
962 syck_emit_indent( e
);
963 if ( width
<= 0 ) width
= e
->best_width
;
964 while ( mark
< str
+ len
) {
967 syck_emitter_write( e
, end
, mark
- end
);
969 if ( *start
!= ' ' && *start
!= '\n' && *end
!= '\n' && *end
!= ' ' ) {
970 syck_emitter_write( e
, "\n", 1 );
972 if ( mark
+ 1 == str
+ len
) {
973 if ( keep_nl
!= NL_KEEP
) syck_emitter_write( e
, "\n", 1 );
975 syck_emit_indent( e
);
981 if ( *start
!= ' ' ) {
982 if ( mark
- end
> width
) {
983 syck_emitter_write( e
, end
, mark
- end
);
984 syck_emit_indent( e
);
993 syck_emitter_write( e
, end
, mark
- end
);
998 * Begins emission of a sequence.
1000 void syck_emit_seq( SyckEmitter
*e
, const char *tag
, enum seq_style style
)
1002 SyckLevel
*parent
= syck_emitter_parent_level( e
);
1003 SyckLevel
*lvl
= syck_emitter_current_level( e
);
1004 syck_emit_tag( e
, tag
, "tag:yaml.org,2002:seq" );
1005 if ( style
== seq_inline
|| ( parent
->status
== syck_lvl_imap
|| parent
->status
== syck_lvl_iseq
) ) {
1006 syck_emitter_write( e
, "[", 1 );
1007 lvl
->status
= syck_lvl_iseq
;
1010 if ( parent
->status
== syck_lvl_map
&& parent
->ncount
% 2 == 1 ) {
1011 syck_emitter_write( e
, "? ", 2 );
1012 parent
->status
= syck_lvl_mapx
;
1014 lvl
->status
= syck_lvl_seq
;
1019 * Begins emission of a mapping.
1022 syck_emit_map( SyckEmitter
*e
, const char *tag
, enum map_style style
)
1024 SyckLevel
*parent
= syck_emitter_parent_level( e
);
1025 SyckLevel
*lvl
= syck_emitter_current_level( e
);
1026 syck_emit_tag( e
, tag
, "tag:yaml.org,2002:map" );
1027 if ( style
== map_inline
|| ( parent
->status
== syck_lvl_imap
|| parent
->status
== syck_lvl_iseq
) ) {
1028 syck_emitter_write( e
, "{", 1 );
1029 lvl
->status
= syck_lvl_imap
;
1032 if ( parent
->status
== syck_lvl_map
&& parent
->ncount
% 2 == 1 ) {
1033 syck_emitter_write( e
, "? ", 2 );
1034 parent
->status
= syck_lvl_mapx
;
1036 lvl
->status
= syck_lvl_map
;
1041 * Handles emitting of a collection item (for both
1042 * sequences and maps)
1044 void syck_emit_item( SyckEmitter
*e
, st_data_t n
)
1046 SyckLevel
*lvl
= syck_emitter_current_level( e
);
1047 switch ( lvl
->status
)
1051 SyckLevel
*parent
= syck_emitter_parent_level( e
);
1053 /* seq-in-map shortcut -- the lvl->anctag check should be unneccesary but
1054 * there is a nasty shift/reduce in the parser on this point and
1055 * i'm not ready to tickle it. */
1056 if ( lvl
->anctag
== 0 && parent
->status
== syck_lvl_map
&& lvl
->ncount
== 0 ) {
1057 lvl
->spaces
= parent
->spaces
;
1060 /* seq-in-seq shortcut */
1061 else if ( lvl
->anctag
== 0 && parent
->status
== syck_lvl_seq
&& lvl
->ncount
== 0 ) {
1062 int spcs
= ( lvl
->spaces
- parent
->spaces
) - 2;
1065 for ( i
= 0; i
< spcs
; i
++ ) {
1066 syck_emitter_write( e
, " ", 1 );
1068 syck_emitter_write( e
, "- ", 2 );
1073 syck_emit_indent( e
);
1074 syck_emitter_write( e
, "- ", 2 );
1080 if ( lvl
->ncount
> 0 ) {
1081 syck_emitter_write( e
, ", ", 2 );
1088 SyckLevel
*parent
= syck_emitter_parent_level( e
);
1090 /* map-in-seq shortcut */
1091 if ( lvl
->anctag
== 0 && parent
->status
== syck_lvl_seq
&& lvl
->ncount
== 0 ) {
1092 int spcs
= ( lvl
->spaces
- parent
->spaces
) - 2;
1095 for ( i
= 0; i
< spcs
; i
++ ) {
1096 syck_emitter_write( e
, " ", 1 );
1102 if ( lvl
->ncount
% 2 == 0 ) {
1103 syck_emit_indent( e
);
1105 syck_emitter_write( e
, ": ", 2 );
1112 if ( lvl
->ncount
% 2 == 0 ) {
1113 syck_emit_indent( e
);
1114 lvl
->status
= syck_lvl_map
;
1117 if ( lvl
->spaces
> 0 ) {
1118 char *spcs
= S_ALLOC_N( char, lvl
->spaces
+ 1 );
1120 spcs
[lvl
->spaces
] = '\0';
1121 for ( i
= 0; i
< lvl
->spaces
; i
++ ) spcs
[i
] = ' ';
1122 syck_emitter_write( e
, spcs
, lvl
->spaces
);
1125 syck_emitter_write( e
, ": ", 2 );
1132 if ( lvl
->ncount
> 0 ) {
1133 if ( lvl
->ncount
% 2 == 0 ) {
1134 syck_emitter_write( e
, ", ", 2 );
1136 syck_emitter_write( e
, ": ", 2 );
1150 * Closes emission of a collection.
1152 void syck_emit_end( SyckEmitter
*e
)
1154 SyckLevel
*lvl
= syck_emitter_current_level( e
);
1155 SyckLevel
*parent
= syck_emitter_parent_level( e
);
1156 switch ( lvl
->status
)
1159 if ( lvl
->ncount
== 0 ) {
1160 syck_emitter_write( e
, "[]\n", 3 );
1161 } else if ( parent
->status
== syck_lvl_mapx
) {
1162 syck_emitter_write( e
, "\n", 1 );
1167 syck_emitter_write( e
, "]\n", 1 );
1171 if ( lvl
->ncount
== 0 ) {
1172 syck_emitter_write( e
, "{}\n", 3 );
1173 } else if ( lvl
->ncount
% 2 == 1 ) {
1174 syck_emitter_write( e
, ":\n", 1 );
1175 } else if ( parent
->status
== syck_lvl_mapx
) {
1176 syck_emitter_write( e
, "\n", 1 );
1181 syck_emitter_write( e
, "}\n", 1 );
1189 * Fill markers table with emitter nodes in the
1190 * soon-to-be-emitted tree.
1193 syck_emitter_mark_node( SyckEmitter
*e
, st_data_t n
)
1196 char *anchor_name
= NULL
;
1199 * Ensure markers table is initialized.
1201 if ( e
->markers
== NULL
)
1203 e
->markers
= st_init_numtable();
1207 * Markers table initially marks the string position of the
1208 * object. Doesn't yet create an anchor, simply notes the
1211 if ( ! st_lookup( e
->markers
, n
, (st_data_t
*)&oid
) )
1216 oid
= e
->markers
->num_entries
+ 1;
1217 st_insert( e
->markers
, n
, (st_data_t
)oid
);
1221 if ( e
->anchors
== NULL
)
1223 e
->anchors
= st_init_numtable();
1226 if ( ! st_lookup( e
->anchors
, (st_data_t
)oid
, (void *)&anchor_name
) )
1229 const char *anc
= ( e
->anchor_format
== NULL
? DEFAULT_ANCHOR_FORMAT
: e
->anchor_format
);
1232 * Second time hitting this object, let's give it an anchor
1234 idx
= e
->anchors
->num_entries
+ 1;
1235 anchor_name
= S_ALLOC_N( char, strlen( anc
) + 10 );
1236 S_MEMZERO( anchor_name
, char, strlen( anc
) + 10 );
1237 sprintf( anchor_name
, anc
, idx
);
1240 * Insert into anchors table
1242 st_insert( e
->anchors
, (st_data_t
)oid
, (st_data_t
)anchor_name
);