00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include "ruby/ruby.h"
00012
00013 #include <stdio.h>
00014 #include <string.h>
00015
00016 #include "syck.h"
00017
00018 #define DEFAULT_ANCHOR_FORMAT "id%03d"
00019
00020 const char hex_table[] =
00021 "0123456789ABCDEF";
00022 static char b64_table[] =
00023 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
00024
00025
00026
00027
00028 char *
00029 syck_base64enc( char *s, long len )
00030 {
00031 long i = 0;
00032 int padding = '=';
00033 char *buff = S_ALLOC_N(char, len * 4 / 3 + 6);
00034
00035 while (len >= 3) {
00036 buff[i++] = b64_table[077 & (*s >> 2)];
00037 buff[i++] = b64_table[077 & (((*s << 4) & 060) | ((s[1] >> 4) & 017))];
00038 buff[i++] = b64_table[077 & (((s[1] << 2) & 074) | ((s[2] >> 6) & 03))];
00039 buff[i++] = b64_table[077 & s[2]];
00040 s += 3;
00041 len -= 3;
00042 }
00043 if (len == 2) {
00044 buff[i++] = b64_table[077 & (*s >> 2)];
00045 buff[i++] = b64_table[077 & (((*s << 4) & 060) | ((s[1] >> 4) & 017))];
00046 buff[i++] = b64_table[077 & (((s[1] << 2) & 074) | (('\0' >> 6) & 03))];
00047 buff[i++] = padding;
00048 }
00049 else if (len == 1) {
00050 buff[i++] = b64_table[077 & (*s >> 2)];
00051 buff[i++] = b64_table[077 & (((*s << 4) & 060) | (('\0' >> 4) & 017))];
00052 buff[i++] = padding;
00053 buff[i++] = padding;
00054 }
00055 buff[i++] = '\n';
00056 return buff;
00057 }
00058
00059 char *
00060 syck_base64dec( char *s, long len )
00061 {
00062 int a = -1,b = -1,c = 0,d;
00063 static int first = 1;
00064 static int b64_xtable[256];
00065 char *ptr = syck_strndup( s, len );
00066 char *end = ptr;
00067 char *send = s + len;
00068
00069 if (first) {
00070 int i;
00071 first = 0;
00072
00073 for (i = 0; i < 256; i++) {
00074 b64_xtable[i] = -1;
00075 }
00076 for (i = 0; i < 64; i++) {
00077 b64_xtable[(int)b64_table[i]] = i;
00078 }
00079 }
00080 while (s < send) {
00081 while (s[0] == '\r' || s[0] == '\n') { s++; }
00082 if ((a = b64_xtable[(int)s[0]]) == -1) break;
00083 if ((b = b64_xtable[(int)s[1]]) == -1) break;
00084 if ((c = b64_xtable[(int)s[2]]) == -1) break;
00085 if ((d = b64_xtable[(int)s[3]]) == -1) break;
00086 *end++ = a << 2 | b >> 4;
00087 *end++ = b << 4 | c >> 2;
00088 *end++ = c << 6 | d;
00089 s += 4;
00090 }
00091 if (a != -1 && b != -1) {
00092 if (s + 2 < send && s[2] == '=')
00093 *end++ = a << 2 | b >> 4;
00094 if (c != -1 && s + 3 < send && s[3] == '=') {
00095 *end++ = a << 2 | b >> 4;
00096 *end++ = b << 4 | c >> 2;
00097 }
00098 }
00099 *end = '\0';
00100
00101 return ptr;
00102 }
00103
00104
00105
00106
00107 SyckEmitter *
00108 syck_new_emitter(void)
00109 {
00110 SyckEmitter *e;
00111 e = S_ALLOC( SyckEmitter );
00112 e->headless = 0;
00113 e->use_header = 0;
00114 e->use_version = 0;
00115 e->sort_keys = 0;
00116 e->anchor_format = NULL;
00117 e->explicit_typing = 0;
00118 e->best_width = 80;
00119 e->style = scalar_none;
00120 e->stage = doc_open;
00121 e->indent = 2;
00122 e->level = -1;
00123 e->anchors = NULL;
00124 e->markers = NULL;
00125 e->anchored = NULL;
00126 e->bufsize = SYCK_BUFFERSIZE;
00127 e->buffer = NULL;
00128 e->marker = NULL;
00129 e->bufpos = 0;
00130 e->emitter_handler = NULL;
00131 e->output_handler = NULL;
00132 e->lvl_idx = 0;
00133 e->lvl_capa = ALLOC_CT;
00134 e->levels = S_ALLOC_N( SyckLevel, e->lvl_capa );
00135 syck_emitter_reset_levels( e );
00136 e->bonus = NULL;
00137 return e;
00138 }
00139
00140 int
00141 syck_st_free_anchors( char *key, char *name, char *arg )
00142 {
00143 S_FREE( name );
00144 return ST_CONTINUE;
00145 }
00146
00147 void
00148 syck_emitter_st_free( SyckEmitter *e )
00149 {
00150
00151
00152
00153 if ( e->anchors != NULL )
00154 {
00155 st_foreach( e->anchors, syck_st_free_anchors, 0 );
00156 st_free_table( e->anchors );
00157 e->anchors = NULL;
00158 }
00159
00160 if ( e->anchored != NULL )
00161 {
00162 st_free_table( e->anchored );
00163 e->anchored = NULL;
00164 }
00165
00166
00167
00168
00169 if ( e->markers != NULL )
00170 {
00171 st_free_table( e->markers );
00172 e->markers = NULL;
00173 }
00174 }
00175
00176 SyckLevel *
00177 syck_emitter_current_level( SyckEmitter *e )
00178 {
00179 return &e->levels[e->lvl_idx-1];
00180 }
00181
00182 SyckLevel *
00183 syck_emitter_parent_level( SyckEmitter *e )
00184 {
00185 return &e->levels[e->lvl_idx-2];
00186 }
00187
00188 void
00189 syck_emitter_pop_level( SyckEmitter *e )
00190 {
00191 ASSERT( e != NULL );
00192
00193
00194 if ( e->lvl_idx <= 1 ) return;
00195
00196 e->lvl_idx -= 1;
00197 free( e->levels[e->lvl_idx].domain );
00198 }
00199
00200 void
00201 syck_emitter_add_level( SyckEmitter *e, int len, enum syck_level_status status )
00202 {
00203 ASSERT( e != NULL );
00204 if ( e->lvl_idx + 1 > e->lvl_capa )
00205 {
00206 e->lvl_capa += ALLOC_CT;
00207 S_REALLOC_N( e->levels, SyckLevel, e->lvl_capa );
00208 }
00209
00210 ASSERT( len > e->levels[e->lvl_idx-1].spaces );
00211 e->levels[e->lvl_idx].spaces = len;
00212 e->levels[e->lvl_idx].ncount = 0;
00213 e->levels[e->lvl_idx].domain = syck_strndup( e->levels[e->lvl_idx-1].domain, strlen( e->levels[e->lvl_idx-1].domain ) );
00214 e->levels[e->lvl_idx].status = status;
00215 e->levels[e->lvl_idx].anctag = 0;
00216 e->lvl_idx += 1;
00217 }
00218
00219 void
00220 syck_emitter_reset_levels( SyckEmitter *e )
00221 {
00222 while ( e->lvl_idx > 1 )
00223 {
00224 syck_emitter_pop_level( e );
00225 }
00226
00227 if ( e->lvl_idx < 1 )
00228 {
00229 e->lvl_idx = 1;
00230 e->levels[0].spaces = -1;
00231 e->levels[0].ncount = 0;
00232 e->levels[0].domain = syck_strndup( "", 0 );
00233 e->levels[0].anctag = 0;
00234 }
00235 e->levels[0].status = syck_lvl_header;
00236 }
00237
00238 void
00239 syck_emitter_handler( SyckEmitter *e, SyckEmitterHandler hdlr )
00240 {
00241 e->emitter_handler = hdlr;
00242 }
00243
00244 void
00245 syck_output_handler( SyckEmitter *e, SyckOutputHandler hdlr )
00246 {
00247 e->output_handler = hdlr;
00248 }
00249
00250 void
00251 syck_free_emitter( SyckEmitter *e )
00252 {
00253
00254
00255
00256 syck_emitter_st_free( e );
00257 syck_emitter_reset_levels( e );
00258 S_FREE( e->levels[0].domain );
00259 S_FREE( e->levels );
00260 if ( e->buffer != NULL )
00261 {
00262 S_FREE( e->buffer );
00263 }
00264 S_FREE( e );
00265 }
00266
00267 void
00268 syck_emitter_clear( SyckEmitter *e )
00269 {
00270 if ( e->buffer == NULL )
00271 {
00272 e->buffer = S_ALLOC_N( char, e->bufsize );
00273 S_MEMZERO( e->buffer, char, e->bufsize );
00274 }
00275 e->buffer[0] = '\0';
00276 e->marker = e->buffer;
00277 e->bufpos = 0;
00278 }
00279
00280
00281
00282
00283 void
00284 syck_emitter_write( SyckEmitter *e, const char *str, long len )
00285 {
00286 long at;
00287 ASSERT( str != NULL );
00288 if ( e->buffer == NULL )
00289 {
00290 syck_emitter_clear( e );
00291 }
00292
00293
00294
00295
00296 at = e->marker - e->buffer;
00297 if ( len + at >= (long)e->bufsize )
00298 {
00299 syck_emitter_flush( e, 0 );
00300 for (;;) {
00301 long rest = e->bufsize - (e->marker - e->buffer);
00302 if (len <= rest) break;
00303 S_MEMCPY( e->marker, str, char, rest );
00304 e->marker += rest;
00305 str += rest;
00306 len -= rest;
00307 syck_emitter_flush( e, 0 );
00308 }
00309 }
00310
00311
00312
00313
00314 S_MEMCPY( e->marker, str, char, len );
00315 e->marker += len;
00316 }
00317
00318
00319
00320
00321 void
00322 syck_emitter_flush( SyckEmitter *e, long check_room )
00323 {
00324
00325
00326
00327 if ( check_room > 0 )
00328 {
00329 if ( (long)e->bufsize > ( e->marker - e->buffer ) + check_room )
00330 {
00331 return;
00332 }
00333 }
00334 else
00335 {
00336 check_room = e->bufsize;
00337 }
00338
00339
00340
00341
00342 if ( check_room > e->marker - e->buffer )
00343 {
00344 check_room = e->marker - e->buffer;
00345 }
00346 (e->output_handler)( e, e->buffer, check_room );
00347 e->bufpos += check_room;
00348 e->marker -= check_room;
00349 }
00350
00351
00352
00353
00354
00355 void
00356 syck_emit( SyckEmitter *e, st_data_t n )
00357 {
00358 SYMID oid;
00359 char *anchor_name = NULL;
00360 int indent = 0;
00361 long x = 0;
00362 SyckLevel *lvl = syck_emitter_current_level( e );
00363
00364
00365
00366
00367 if ( e->stage == doc_open && ( e->headless == 0 || e->use_header == 1 ) )
00368 {
00369 if ( e->use_version == 1 )
00370 {
00371 char *header = S_ALLOC_N( char, 64 );
00372 S_MEMZERO( header, char, 64 );
00373 sprintf( header, "--- %%YAML:%d.%d ", SYCK_YAML_MAJOR, SYCK_YAML_MINOR );
00374 syck_emitter_write( e, header, strlen( header ) );
00375 S_FREE( header );
00376 }
00377 else
00378 {
00379 syck_emitter_write( e, "--- ", 4 );
00380 }
00381 e->stage = doc_processing;
00382 }
00383
00384
00385 if ( lvl->spaces >= 0 ) {
00386 indent = lvl->spaces + e->indent;
00387 }
00388 syck_emitter_add_level( e, indent, syck_lvl_open );
00389 lvl = syck_emitter_current_level( e );
00390
00391
00392 if ( e->anchors != NULL &&
00393 st_lookup( e->markers, n, (st_data_t *)&oid ) &&
00394 st_lookup( e->anchors, (st_data_t)oid, (void *)&anchor_name ) )
00395 {
00396 if ( e->anchored == NULL )
00397 {
00398 e->anchored = st_init_numtable();
00399 }
00400
00401 if ( ! st_lookup( e->anchored, (st_data_t)anchor_name, (st_data_t *)&x ) )
00402 {
00403 char *an = S_ALLOC_N( char, strlen( anchor_name ) + 3 );
00404 sprintf( an, "&%s ", anchor_name );
00405 syck_emitter_write( e, an, strlen( anchor_name ) + 2 );
00406 free( an );
00407
00408 x = 1;
00409 st_insert( e->anchored, (st_data_t)anchor_name, (st_data_t)x );
00410 lvl->anctag = 1;
00411 }
00412 else
00413 {
00414 char *an = S_ALLOC_N( char, strlen( anchor_name ) + 2 );
00415 sprintf( an, "*%s", anchor_name );
00416 syck_emitter_write( e, an, strlen( anchor_name ) + 1 );
00417 free( an );
00418
00419 goto end_emit;
00420 }
00421 }
00422
00423 (e->emitter_handler)( e, n );
00424
00425
00426 end_emit:
00427 syck_emitter_pop_level( e );
00428 if ( e->lvl_idx == 1 ) {
00429 syck_emitter_write( e, "\n", 1 );
00430 e->headless = 0;
00431 e->stage = doc_open;
00432 }
00433 }
00434
00435
00436
00437
00438
00439
00440 void syck_emit_tag( SyckEmitter *e, const char *tag, const char *ignore )
00441 {
00442 SyckLevel *lvl;
00443 if ( tag == NULL ) return;
00444 if ( ignore != NULL && syck_tagcmp( tag, ignore ) == 0 && e->explicit_typing == 0 ) return;
00445 lvl = syck_emitter_current_level( e );
00446
00447
00448 if ( strlen( tag ) == 0 ) {
00449 syck_emitter_write( e, "! ", 2 );
00450
00451
00452 } else if ( strncmp( tag, "tag:", 4 ) == 0 ) {
00453 int taglen = strlen( tag );
00454 syck_emitter_write( e, "!", 1 );
00455 if ( strncmp( tag + 4, YAML_DOMAIN, strlen( YAML_DOMAIN ) ) == 0 ) {
00456 int skip = 4 + strlen( YAML_DOMAIN ) + 1;
00457 syck_emitter_write( e, tag + skip, taglen - skip );
00458 } else {
00459 const char *subd = tag + 4;
00460 while ( *subd != ':' && *subd != '\0' ) subd++;
00461 if ( *subd == ':' ) {
00462 if ( subd - tag > ( (long)( strlen( YAML_DOMAIN ) + 5 )) &&
00463 strncmp( subd - strlen( YAML_DOMAIN ), YAML_DOMAIN, strlen( YAML_DOMAIN ) ) == 0 ) {
00464 syck_emitter_write( e, tag + 4, subd - strlen( YAML_DOMAIN ) - ( tag + 4 ) - 1 );
00465 syck_emitter_write( e, "/", 1 );
00466 syck_emitter_write( e, subd + 1, ( tag + taglen ) - ( subd + 1 ) );
00467 } else {
00468 syck_emitter_write( e, tag + 4, subd - ( tag + 4 ) );
00469 syck_emitter_write( e, "/", 1 );
00470 syck_emitter_write( e, subd + 1, ( tag + taglen ) - ( subd + 1 ) );
00471 }
00472 } else {
00473
00474 return;
00475 }
00476 }
00477 syck_emitter_write( e, " ", 1 );
00478
00479
00480 } else if ( strncmp( tag, "x-private:", 10 ) == 0 ) {
00481 syck_emitter_write( e, "!!", 2 );
00482 syck_emitter_write( e, tag + 10, strlen( tag ) - 10 );
00483 syck_emitter_write( e, " ", 1 );
00484 }
00485 lvl->anctag = 1;
00486 }
00487
00488
00489
00490
00491 void syck_emit_indent( SyckEmitter *e )
00492 {
00493 int i;
00494 SyckLevel *lvl = syck_emitter_current_level( e );
00495 if ( e->bufpos == 0 && ( e->marker - e->buffer ) == 0 ) return;
00496 if ( lvl->spaces >= 0 ) {
00497 char *spcs = S_ALLOC_N( char, lvl->spaces + 2 );
00498
00499 spcs[0] = '\n'; spcs[lvl->spaces + 1] = '\0';
00500 for ( i = 0; i < lvl->spaces; i++ ) spcs[i+1] = ' ';
00501 syck_emitter_write( e, spcs, lvl->spaces + 1 );
00502 free( spcs );
00503 }
00504 }
00505
00506
00507 #define SCAN_NONE 0
00508
00509 #define SCAN_NONPRINT 1
00510
00511 #define SCAN_INDENTED 2
00512
00513 #define SCAN_WIDE 4
00514
00515 #define SCAN_WHITEEDGE 8
00516
00517 #define SCAN_NEWLINE 16
00518
00519 #define SCAN_SINGLEQ 32
00520
00521 #define SCAN_DOUBLEQ 64
00522
00523 #define SCAN_INDIC_S 128
00524
00525 #define SCAN_INDIC_C 256
00526
00527 #define SCAN_NONL_E 512
00528
00529 #define SCAN_MANYNL_E 1024
00530
00531 #define SCAN_FLOWMAP 2048
00532
00533 #define SCAN_FLOWSEQ 4096
00534
00535 #define SCAN_DOCSEP 8192
00536
00537
00538
00539
00540 int
00541 syck_scan_scalar( int req_width, const char *cursor, long len )
00542 {
00543 long i = 0, start = 0;
00544 int flags = SCAN_NONE;
00545
00546 if ( len < 1 ) return flags;
00547
00548
00549 if ( cursor[0] == '[' || cursor[0] == ']' ||
00550 cursor[0] == '{' || cursor[0] == '}' ||
00551 cursor[0] == '!' || cursor[0] == '*' ||
00552 cursor[0] == '&' || cursor[0] == '|' ||
00553 cursor[0] == '>' || cursor[0] == '\'' ||
00554 cursor[0] == '"' || cursor[0] == '#' ||
00555 cursor[0] == '%' || cursor[0] == '@' ||
00556 cursor[0] == '&' ) {
00557 flags |= SCAN_INDIC_S;
00558 }
00559 if ( ( cursor[0] == '-' || cursor[0] == ':' ||
00560 cursor[0] == '?' || cursor[0] == ',' ) &&
00561 ( len == 1 || cursor[1] == ' ' || cursor[1] == '\n' ) )
00562 {
00563 flags |= SCAN_INDIC_S;
00564 }
00565
00566
00567 if ( cursor[len-1] != '\n' ) {
00568 flags |= SCAN_NONL_E;
00569 } else if ( len > 1 && cursor[len-2] == '\n' ) {
00570 flags |= SCAN_MANYNL_E;
00571 }
00572 if (
00573 ( len > 0 && ( cursor[0] == ' ' || cursor[0] == '\t' || cursor[0] == '\n' || cursor[0] == '\r' ) ) ||
00574 ( len > 1 && ( cursor[len-1] == ' ' || cursor[len-1] == '\t' ) )
00575 ) {
00576 flags |= SCAN_WHITEEDGE;
00577 }
00578
00579
00580 if ( len >= 3 && strncmp( cursor, "---", 3 ) == 0 )
00581 flags |= SCAN_DOCSEP;
00582
00583
00584 for ( i = 0; i < len; i++ ) {
00585
00586 if ( ! ( cursor[i] == 0x9 ||
00587 cursor[i] == 0xA ||
00588 cursor[i] == 0xD ||
00589 ( cursor[i] >= 0x20 && cursor[i] <= 0x7E ) )
00590 ) {
00591 flags |= SCAN_NONPRINT;
00592 }
00593 else if ( cursor[i] == '\n' ) {
00594 flags |= SCAN_NEWLINE;
00595 if ( len - i >= 3 && strncmp( &cursor[i+1], "---", 3 ) == 0 )
00596 flags |= SCAN_DOCSEP;
00597 if ( cursor[i+1] == ' ' || cursor[i+1] == '\t' )
00598 flags |= SCAN_INDENTED;
00599 if ( req_width > 0 && i - start > req_width )
00600 flags |= SCAN_WIDE;
00601 start = i;
00602 }
00603 else if ( cursor[i] == '\'' )
00604 {
00605 flags |= SCAN_SINGLEQ;
00606 }
00607 else if ( cursor[i] == '"' )
00608 {
00609 flags |= SCAN_DOUBLEQ;
00610 }
00611 else if ( cursor[i] == ']' )
00612 {
00613 flags |= SCAN_FLOWSEQ;
00614 }
00615 else if ( cursor[i] == '}' )
00616 {
00617 flags |= SCAN_FLOWMAP;
00618 }
00619
00620 else if ( ( cursor[i] == ' ' && cursor[i+1] == '#' ) ||
00621 ( cursor[i] == ':' &&
00622 ( cursor[i+1] == ' ' || cursor[i+1] == '\n' || i == len - 1 ) ) )
00623 {
00624 flags |= SCAN_INDIC_C;
00625 }
00626 else if ( cursor[i] == ',' &&
00627 ( cursor[i+1] == ' ' || cursor[i+1] == '\n' || i == len - 1 ) )
00628 {
00629 flags |= SCAN_FLOWMAP;
00630 flags |= SCAN_FLOWSEQ;
00631 }
00632 }
00633
00634
00635 return flags;
00636 }
00637
00638
00639
00640
00641 void syck_emit_scalar( SyckEmitter *e, const char *tag, enum scalar_style force_style, int force_indent, int force_width,
00642 char keep_nl, const char *str, long len )
00643 {
00644 enum scalar_style favor_style = scalar_literal;
00645 SyckLevel *parent = syck_emitter_parent_level( e );
00646 SyckLevel *lvl = syck_emitter_current_level( e );
00647 int scan = 0;
00648 const char *match_implicit;
00649 char *implicit;
00650
00651 if ( str == NULL ) str = "";
00652
00653
00654 if ( len == 0 && ( parent->status == syck_lvl_map || parent->status == syck_lvl_imap ) &&
00655 parent->ncount % 2 == 1 && syck_tagcmp( tag, "tag:yaml.org,2002:null" ) == 0 )
00656 {
00657 str = "~";
00658 len = 1;
00659 }
00660
00661 scan = syck_scan_scalar( force_width, str, len );
00662 match_implicit = syck_match_implicit( str, len );
00663
00664
00665 implicit = syck_taguri( YAML_DOMAIN, match_implicit, strlen( match_implicit ) );
00666 if ( syck_tagcmp( tag, implicit ) != 0 && syck_tagcmp( tag, "tag:yaml.org,2002:str" ) == 0 ) {
00667 force_style = scalar_2quote;
00668 } else {
00669
00670 if ( parent->status == syck_lvl_map && parent->ncount % 2 == 1 &&
00671 ( !( tag == NULL ||
00672 ( implicit != NULL && syck_tagcmp( tag, implicit ) == 0 && e->explicit_typing == 0 ) ) ) )
00673 {
00674 syck_emitter_write( e, "? ", 2 );
00675 parent->status = syck_lvl_mapx;
00676 }
00677 syck_emit_tag( e, tag, implicit );
00678 }
00679 S_FREE( implicit );
00680
00681
00682 if ( force_style == scalar_none ) {
00683 if ( scan & SCAN_NEWLINE ) {
00684 force_style = scalar_literal;
00685 } else {
00686 force_style = scalar_plain;
00687 }
00688 }
00689
00690 if ( e->style == scalar_fold ) {
00691 favor_style = scalar_fold;
00692 }
00693
00694
00695 if ( scan & SCAN_NONPRINT ) {
00696 force_style = scalar_2quote;
00697 } else if ( scan & SCAN_WHITEEDGE ) {
00698 force_style = scalar_2quote;
00699 } else if ( force_style != scalar_fold && ( scan & SCAN_INDENTED ) ) {
00700 force_style = scalar_literal;
00701 } else if ( force_style == scalar_plain && ( scan & SCAN_NEWLINE ) ) {
00702 force_style = favor_style;
00703 } else if ( force_style == scalar_plain && parent->status == syck_lvl_iseq && ( scan & SCAN_FLOWSEQ ) ) {
00704 force_style = scalar_2quote;
00705 } else if ( force_style == scalar_plain && parent->status == syck_lvl_imap && ( scan & SCAN_FLOWMAP ) ) {
00706 force_style = scalar_2quote;
00707
00708
00709 } else if ( force_style == scalar_plain && ( scan & SCAN_INDIC_S || scan & SCAN_INDIC_C ) ) {
00710 if ( scan & SCAN_NEWLINE ) {
00711 force_style = favor_style;
00712 } else {
00713 force_style = scalar_2quote;
00714 }
00715 }
00716
00717 if ( force_indent > 0 ) {
00718 lvl->spaces = parent->spaces + force_indent;
00719 } else if ( scan & SCAN_DOCSEP ) {
00720 lvl->spaces = parent->spaces + e->indent;
00721 }
00722
00723
00724 if ( ( parent->status == syck_lvl_map || parent->status == syck_lvl_mapx ) && parent->ncount % 2 == 1 ) {
00725 if ( force_style != scalar_plain ) {
00726 force_style = scalar_2quote;
00727 }
00728 }
00729
00730
00731 if ( parent->status == syck_lvl_imap || parent->status == syck_lvl_iseq ) {
00732 if ( force_style != scalar_plain && force_style != scalar_1quote ) {
00733 force_style = scalar_2quote;
00734 }
00735 }
00736
00737
00738 if ( scan & SCAN_NONL_E ) {
00739 keep_nl = NL_CHOMP;
00740 } else if ( scan & SCAN_MANYNL_E ) {
00741 keep_nl = NL_KEEP;
00742 }
00743
00744
00745 switch ( force_style )
00746 {
00747 case scalar_1quote:
00748 syck_emit_1quoted( e, force_width, str, len );
00749 break;
00750
00751 case scalar_none:
00752 case scalar_2quote:
00753 syck_emit_2quoted( e, force_width, str, len );
00754 break;
00755
00756 case scalar_fold:
00757 syck_emit_folded( e, force_width, keep_nl, str, len );
00758 break;
00759
00760 case scalar_literal:
00761 syck_emit_literal( e, keep_nl, str, len );
00762 break;
00763
00764 case scalar_plain:
00765 syck_emitter_write( e, str, len );
00766 break;
00767 }
00768
00769 if ( parent->status == syck_lvl_mapx )
00770 {
00771 syck_emitter_write( e, "\n", 1 );
00772 }
00773 }
00774
00775 void
00776 syck_emitter_escape( SyckEmitter *e, const char *src, long len )
00777 {
00778 int i;
00779 for( i = 0; i < len; i++ )
00780 {
00781 if( (src[i] < 0x20) || (0x7E < src[i]) )
00782 {
00783 syck_emitter_write( e, "\\", 1 );
00784 if( '\0' == src[i] )
00785 syck_emitter_write( e, "0", 1 );
00786 else
00787 {
00788 syck_emitter_write( e, "x", 1 );
00789 syck_emitter_write( e, (const char *)hex_table + ((src[i] & 0xF0) >> 4), 1 );
00790 syck_emitter_write( e, (const char *)hex_table + (src[i] & 0x0F), 1 );
00791 }
00792 }
00793 else
00794 {
00795 syck_emitter_write( e, src + i, 1 );
00796 if( '\\' == src[i] )
00797 syck_emitter_write( e, "\\", 1 );
00798 }
00799 }
00800 }
00801
00802
00803
00804
00805 void
00806 syck_emit_1quoted( SyckEmitter *e, int width, const char *str, long len )
00807 {
00808 char do_indent = 0;
00809 const char *mark = str;
00810 const char *start = str;
00811 const char *end = str;
00812 syck_emitter_write( e, "'", 1 );
00813 while ( mark < str + len ) {
00814 if ( do_indent ) {
00815 syck_emit_indent( e );
00816 do_indent = 0;
00817 }
00818 switch ( *mark ) {
00819 case '\'': syck_emitter_write( e, "'", 1 ); break;
00820
00821 case '\n':
00822 end = mark + 1;
00823 if ( *start != ' ' && *start != '\n' && *end != '\n' && *end != ' ' ) {
00824 syck_emitter_write( e, "\n\n", 2 );
00825 } else {
00826 syck_emitter_write( e, "\n", 1 );
00827 }
00828 do_indent = 1;
00829 start = mark + 1;
00830 break;
00831
00832 case ' ':
00833 if ( width > 0 && *start != ' ' && mark - end > width ) {
00834 do_indent = 1;
00835 end = mark + 1;
00836 } else {
00837 syck_emitter_write( e, " ", 1 );
00838 }
00839 break;
00840
00841 default:
00842 syck_emitter_write( e, mark, 1 );
00843 break;
00844 }
00845 mark++;
00846 }
00847 syck_emitter_write( e, "'", 1 );
00848 }
00849
00850
00851
00852
00853 void
00854 syck_emit_2quoted( SyckEmitter *e, int width, const char *str, long len )
00855 {
00856 char do_indent = 0;
00857 const char *mark = str;
00858 const char *start = str;
00859 const char *end = str;
00860 syck_emitter_write( e, "\"", 1 );
00861 while ( mark < str + len ) {
00862 if ( do_indent > 0 ) {
00863 if ( do_indent == 2 ) {
00864 syck_emitter_write( e, "\\", 1 );
00865 }
00866 syck_emit_indent( e );
00867 do_indent = 0;
00868 }
00869 switch ( *mark ) {
00870
00871
00872 case '"': syck_emitter_write( e, "\\\"", 2 ); break;
00873 case '\\': syck_emitter_write( e, "\\\\", 2 ); break;
00874 case '\0': syck_emitter_write( e, "\\0", 2 ); break;
00875 case '\a': syck_emitter_write( e, "\\a", 2 ); break;
00876 case '\b': syck_emitter_write( e, "\\b", 2 ); break;
00877 case '\f': syck_emitter_write( e, "\\f", 2 ); break;
00878 case '\r': syck_emitter_write( e, "\\r", 2 ); break;
00879 case '\t': syck_emitter_write( e, "\\t", 2 ); break;
00880 case '\v': syck_emitter_write( e, "\\v", 2 ); break;
00881 case 0x1b: syck_emitter_write( e, "\\e", 2 ); break;
00882
00883 case '\n':
00884 end = mark + 1;
00885 syck_emitter_write( e, "\\n", 2 );
00886 do_indent = 2;
00887 start = mark + 1;
00888 if ( start < str + len && ( *start == ' ' || *start == '\n' ) ) {
00889 do_indent = 0;
00890 }
00891 break;
00892
00893 case ' ':
00894 if ( width > 0 && *start != ' ' && mark - end > width ) {
00895 do_indent = 1;
00896 end = mark + 1;
00897 } else {
00898 syck_emitter_write( e, " ", 1 );
00899 }
00900 break;
00901
00902 default:
00903 syck_emitter_escape( e, mark, 1 );
00904 break;
00905 }
00906 mark++;
00907 }
00908 syck_emitter_write( e, "\"", 1 );
00909 }
00910
00911
00912
00913
00914 void
00915 syck_emit_literal( SyckEmitter *e, char keep_nl, const char *str, long len )
00916 {
00917 const char *mark = str;
00918 const char *start = str;
00919 const char *end = str;
00920 syck_emitter_write( e, "|", 1 );
00921 if ( keep_nl == NL_CHOMP ) {
00922 syck_emitter_write( e, "-", 1 );
00923 } else if ( keep_nl == NL_KEEP ) {
00924 syck_emitter_write( e, "+", 1 );
00925 }
00926 syck_emit_indent( e );
00927 while ( mark < str + len ) {
00928 if ( *mark == '\n' ) {
00929 end = mark;
00930 if ( *start != ' ' && *start != '\n' && *end != '\n' && *end != ' ' ) end += 1;
00931 syck_emitter_write( e, start, end - start );
00932 if ( mark + 1 == str + len ) {
00933 if ( keep_nl != NL_KEEP ) syck_emitter_write( e, "\n", 1 );
00934 } else {
00935 syck_emit_indent( e );
00936 }
00937 start = mark + 1;
00938 }
00939 mark++;
00940 }
00941 end = str + len;
00942 if ( start < end ) {
00943 syck_emitter_write( e, start, end - start );
00944 }
00945 }
00946
00947
00948
00949
00950 void
00951 syck_emit_folded( SyckEmitter *e, int width, char keep_nl, const char *str, long len )
00952 {
00953 const char *mark = str;
00954 const char *start = str;
00955 const char *end = str;
00956 syck_emitter_write( e, ">", 1 );
00957 if ( keep_nl == NL_CHOMP ) {
00958 syck_emitter_write( e, "-", 1 );
00959 } else if ( keep_nl == NL_KEEP ) {
00960 syck_emitter_write( e, "+", 1 );
00961 }
00962 syck_emit_indent( e );
00963 if ( width <= 0 ) width = e->best_width;
00964 while ( mark < str + len ) {
00965 switch ( *mark ) {
00966 case '\n':
00967 syck_emitter_write( e, end, mark - end );
00968 end = mark + 1;
00969 if ( *start != ' ' && *start != '\n' && *end != '\n' && *end != ' ' ) {
00970 syck_emitter_write( e, "\n", 1 );
00971 }
00972 if ( mark + 1 == str + len ) {
00973 if ( keep_nl != NL_KEEP ) syck_emitter_write( e, "\n", 1 );
00974 } else {
00975 syck_emit_indent( e );
00976 }
00977 start = mark + 1;
00978 break;
00979
00980 case ' ':
00981 if ( *start != ' ' ) {
00982 if ( mark - end > width ) {
00983 syck_emitter_write( e, end, mark - end );
00984 syck_emit_indent( e );
00985 end = mark + 1;
00986 }
00987 }
00988 break;
00989 }
00990 mark++;
00991 }
00992 if ( end < mark ) {
00993 syck_emitter_write( e, end, mark - end );
00994 }
00995 }
00996
00997
00998
00999
01000 void syck_emit_seq( SyckEmitter *e, const char *tag, enum seq_style style )
01001 {
01002 SyckLevel *parent = syck_emitter_parent_level( e );
01003 SyckLevel *lvl = syck_emitter_current_level( e );
01004 syck_emit_tag( e, tag, "tag:yaml.org,2002:seq" );
01005 if ( style == seq_inline || ( parent->status == syck_lvl_imap || parent->status == syck_lvl_iseq ) ) {
01006 syck_emitter_write( e, "[", 1 );
01007 lvl->status = syck_lvl_iseq;
01008 } else {
01009
01010 if ( parent->status == syck_lvl_map && parent->ncount % 2 == 1 ) {
01011 syck_emitter_write( e, "? ", 2 );
01012 parent->status = syck_lvl_mapx;
01013 }
01014 lvl->status = syck_lvl_seq;
01015 }
01016 }
01017
01018
01019
01020
01021 void
01022 syck_emit_map( SyckEmitter *e, const char *tag, enum map_style style )
01023 {
01024 SyckLevel *parent = syck_emitter_parent_level( e );
01025 SyckLevel *lvl = syck_emitter_current_level( e );
01026 syck_emit_tag( e, tag, "tag:yaml.org,2002:map" );
01027 if ( style == map_inline || ( parent->status == syck_lvl_imap || parent->status == syck_lvl_iseq ) ) {
01028 syck_emitter_write( e, "{", 1 );
01029 lvl->status = syck_lvl_imap;
01030 } else {
01031
01032 if ( parent->status == syck_lvl_map && parent->ncount % 2 == 1 ) {
01033 syck_emitter_write( e, "? ", 2 );
01034 parent->status = syck_lvl_mapx;
01035 }
01036 lvl->status = syck_lvl_map;
01037 }
01038 }
01039
01040
01041
01042
01043
01044 void syck_emit_item( SyckEmitter *e, st_data_t n )
01045 {
01046 SyckLevel *lvl = syck_emitter_current_level( e );
01047 switch ( lvl->status )
01048 {
01049 case syck_lvl_seq:
01050 {
01051 SyckLevel *parent = syck_emitter_parent_level( e );
01052
01053
01054
01055
01056 if ( lvl->anctag == 0 && parent->status == syck_lvl_map && lvl->ncount == 0 ) {
01057 lvl->spaces = parent->spaces;
01058 }
01059
01060
01061 else if ( lvl->anctag == 0 && parent->status == syck_lvl_seq && lvl->ncount == 0 ) {
01062 int spcs = ( lvl->spaces - parent->spaces ) - 2;
01063 if ( spcs >= 0 ) {
01064 int i = 0;
01065 for ( i = 0; i < spcs; i++ ) {
01066 syck_emitter_write( e, " ", 1 );
01067 }
01068 syck_emitter_write( e, "- ", 2 );
01069 break;
01070 }
01071 }
01072
01073 syck_emit_indent( e );
01074 syck_emitter_write( e, "- ", 2 );
01075 }
01076 break;
01077
01078 case syck_lvl_iseq:
01079 {
01080 if ( lvl->ncount > 0 ) {
01081 syck_emitter_write( e, ", ", 2 );
01082 }
01083 }
01084 break;
01085
01086 case syck_lvl_map:
01087 {
01088 SyckLevel *parent = syck_emitter_parent_level( e );
01089
01090
01091 if ( lvl->anctag == 0 && parent->status == syck_lvl_seq && lvl->ncount == 0 ) {
01092 int spcs = ( lvl->spaces - parent->spaces ) - 2;
01093 if ( spcs >= 0 ) {
01094 int i = 0;
01095 for ( i = 0; i < spcs; i++ ) {
01096 syck_emitter_write( e, " ", 1 );
01097 }
01098 break;
01099 }
01100 }
01101
01102 if ( lvl->ncount % 2 == 0 ) {
01103 syck_emit_indent( e );
01104 } else {
01105 syck_emitter_write( e, ": ", 2 );
01106 }
01107 }
01108 break;
01109
01110 case syck_lvl_mapx:
01111 {
01112 if ( lvl->ncount % 2 == 0 ) {
01113 syck_emit_indent( e );
01114 lvl->status = syck_lvl_map;
01115 } else {
01116 int i;
01117 if ( lvl->spaces > 0 ) {
01118 char *spcs = S_ALLOC_N( char, lvl->spaces + 1 );
01119
01120 spcs[lvl->spaces] = '\0';
01121 for ( i = 0; i < lvl->spaces; i++ ) spcs[i] = ' ';
01122 syck_emitter_write( e, spcs, lvl->spaces );
01123 S_FREE( spcs );
01124 }
01125 syck_emitter_write( e, ": ", 2 );
01126 }
01127 }
01128 break;
01129
01130 case syck_lvl_imap:
01131 {
01132 if ( lvl->ncount > 0 ) {
01133 if ( lvl->ncount % 2 == 0 ) {
01134 syck_emitter_write( e, ", ", 2 );
01135 } else {
01136 syck_emitter_write( e, ": ", 2 );
01137 }
01138 }
01139 }
01140 break;
01141
01142 default: break;
01143 }
01144 lvl->ncount++;
01145
01146 syck_emit( e, n );
01147 }
01148
01149
01150
01151
01152 void syck_emit_end( SyckEmitter *e )
01153 {
01154 SyckLevel *lvl = syck_emitter_current_level( e );
01155 SyckLevel *parent = syck_emitter_parent_level( e );
01156 switch ( lvl->status )
01157 {
01158 case syck_lvl_seq:
01159 if ( lvl->ncount == 0 ) {
01160 syck_emitter_write( e, "[]\n", 3 );
01161 } else if ( parent->status == syck_lvl_mapx ) {
01162 syck_emitter_write( e, "\n", 1 );
01163 }
01164 break;
01165
01166 case syck_lvl_iseq:
01167 syck_emitter_write( e, "]\n", 1 );
01168 break;
01169
01170 case syck_lvl_map:
01171 if ( lvl->ncount == 0 ) {
01172 syck_emitter_write( e, "{}\n", 3 );
01173 } else if ( lvl->ncount % 2 == 1 ) {
01174 syck_emitter_write( e, ":\n", 1 );
01175 } else if ( parent->status == syck_lvl_mapx ) {
01176 syck_emitter_write( e, "\n", 1 );
01177 }
01178 break;
01179
01180 case syck_lvl_imap:
01181 syck_emitter_write( e, "}\n", 1 );
01182 break;
01183
01184 default: break;
01185 }
01186 }
01187
01188
01189
01190
01191
01192 SYMID
01193 syck_emitter_mark_node( SyckEmitter *e, st_data_t n )
01194 {
01195 SYMID oid = 0;
01196 char *anchor_name = NULL;
01197
01198
01199
01200
01201 if ( e->markers == NULL )
01202 {
01203 e->markers = st_init_numtable();
01204 }
01205
01206
01207
01208
01209
01210
01211 if ( ! st_lookup( e->markers, n, (st_data_t *)&oid ) )
01212 {
01213
01214
01215
01216 oid = e->markers->num_entries + 1;
01217 st_insert( e->markers, n, (st_data_t)oid );
01218 }
01219 else
01220 {
01221 if ( e->anchors == NULL )
01222 {
01223 e->anchors = st_init_numtable();
01224 }
01225
01226 if ( ! st_lookup( e->anchors, (st_data_t)oid, (void *)&anchor_name ) )
01227 {
01228 int idx = 0;
01229 const char *anc = ( e->anchor_format == NULL ? DEFAULT_ANCHOR_FORMAT : e->anchor_format );
01230
01231
01232
01233
01234 idx = e->anchors->num_entries + 1;
01235 anchor_name = S_ALLOC_N( char, strlen( anc ) + 10 );
01236 S_MEMZERO( anchor_name, char, strlen( anc ) + 10 );
01237 sprintf( anchor_name, anc, idx );
01238
01239
01240
01241
01242 st_insert( e->anchors, (st_data_t)oid, (st_data_t)anchor_name );
01243 }
01244 }
01245 return oid;
01246 }
01247
01248