Ruby 1.9.3p327(2012-11-10revision37606)
|
00001 /* 00002 * emitter.c 00003 * 00004 * $Author: naruse $ 00005 * 00006 * Copyright (C) 2003 why the lucky stiff 00007 * 00008 * All Base64 code from Ruby's pack.c. 00009 * Ruby is Copyright (C) 1993-2007 Yukihiro Matsumoto 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 * Built-in base64 (from Ruby's pack.c) 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 /*RSTRING_LEN(buf) = ptr - RSTRING_PTR(buf);*/ 00101 return ptr; 00102 } 00103 00104 /* 00105 * Allocate an emitter 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 * Free the anchor tables 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 * Free the markers tables 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 /* The root level should never be popped */ 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 * Free tables 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 * Raw write to the emitter buffer. 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 * Flush if at end of buffer 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 * Write to buffer 00313 */ 00314 S_MEMCPY( e->marker, str, char, len ); 00315 e->marker += len; 00316 } 00317 00318 /* 00319 * Write a chunk of data out. 00320 */ 00321 void 00322 syck_emitter_flush( SyckEmitter *e, long check_room ) 00323 { 00324 /* 00325 * Check for enough space in the buffer for check_room length. 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 * Commit buffer. 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 * Start emitting from the given node, check for anchoring and then 00353 * issue the callback to the emitter handler. 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 * Determine headers. 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 /* Add new level */ 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 /* Look for anchor */ 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 /* Pop the level */ 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 * Determine what tag needs to be written, based on the taguri of the node 00437 * and the implicit tag which would be assigned to this node. If a tag is 00438 * required, write the tag. 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 /* implicit */ 00448 if ( strlen( tag ) == 0 ) { 00449 syck_emitter_write( e, "! ", 2 ); 00450 00451 /* global types */ 00452 } else if ( strncmp( tag, "tag:", 4 ) == 0 ) { 00453 int taglen = (int)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 /* TODO: Invalid tag (no colon after domain) */ 00474 return; 00475 } 00476 } 00477 syck_emitter_write( e, " ", 1 ); 00478 00479 /* private types */ 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 * Emit a newline and an appropriately spaced indent. 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 /* Clear the scan */ 00507 #define SCAN_NONE 0 00508 /* All printable characters? */ 00509 #define SCAN_NONPRINT 1 00510 /* Any indented lines? */ 00511 #define SCAN_INDENTED 2 00512 /* Larger than the requested width? */ 00513 #define SCAN_WIDE 4 00514 /* Opens or closes with whitespace? */ 00515 #define SCAN_WHITEEDGE 8 00516 /* Contains a newline */ 00517 #define SCAN_NEWLINE 16 00518 /* Contains a single quote */ 00519 #define SCAN_SINGLEQ 32 00520 /* Contains a double quote */ 00521 #define SCAN_DOUBLEQ 64 00522 /* Starts with a token */ 00523 #define SCAN_INDIC_S 128 00524 /* Contains a flow indicator */ 00525 #define SCAN_INDIC_C 256 00526 /* Ends without newlines */ 00527 #define SCAN_NONL_E 512 00528 /* Ends with many newlines */ 00529 #define SCAN_MANYNL_E 1024 00530 /* Contains flow map indicators */ 00531 #define SCAN_FLOWMAP 2048 00532 /* Contains flow seq indicators */ 00533 #define SCAN_FLOWSEQ 4096 00534 /* Contains a valid doc separator */ 00535 #define SCAN_DOCSEP 8192 00536 00537 /* 00538 * Basic printable test for LATIN-1 characters. 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 /* c-indicators from the spec */ 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 /* whitespace edges */ 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 /* opening doc sep */ 00580 if ( len >= 3 && strncmp( cursor, "---", 3 ) == 0 ) 00581 flags |= SCAN_DOCSEP; 00582 00583 /* scan string */ 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 /* remember, if plain collections get implemented, to add nb-plain-flow-char */ 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 /* printf( "---STR---\n%s\nFLAGS: %d\n", cursor, flags ); */ 00635 return flags; 00636 } 00637 /* 00638 * All scalars should be emitted through this function, which determines an appropriate style, 00639 * tag and indent. 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 /* No empty nulls as map keys */ 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 /* quote strings which default to implicits */ 00665 implicit = syck_taguri( YAML_DOMAIN, match_implicit, (int)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 /* complex key */ 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 /* if still arbitrary, sniff a good block style. */ 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 /* Determine block style */ 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 /* } else if ( force_style == scalar_fold && ( ! ( scan & SCAN_WIDE ) ) ) { 00708 force_style = scalar_literal; */ 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 /* For now, all ambiguous keys are going to be double-quoted */ 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 /* If the parent is an inline, double quote anything complex */ 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 /* Fix the ending newlines */ 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 /* Write the text node */ 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 * Outputs a single-quoted block. 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 * Outputs a double-quoted block. 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 /* Escape sequences allowed within double quotes. */ 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 * Outputs a literal block. 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 * Outputs a folded block. 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 * Begins emission of a sequence. 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 /* complex key */ 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 * Begins emission of a mapping. 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 /* complex key */ 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 * Handles emitting of a collection item (for both 01042 * sequences and maps) 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 /* seq-in-map shortcut -- the lvl->anctag check should be unneccesary but 01054 * there is a nasty shift/reduce in the parser on this point and 01055 * i'm not ready to tickle it. */ 01056 if ( lvl->anctag == 0 && parent->status == syck_lvl_map && lvl->ncount == 0 ) { 01057 lvl->spaces = parent->spaces; 01058 } 01059 01060 /* seq-in-seq shortcut */ 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 /* map-in-seq shortcut */ 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 * Closes emission of a collection. 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 * Fill markers table with emitter nodes in the 01190 * soon-to-be-emitted tree. 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 * Ensure markers table is initialized. 01200 */ 01201 if ( e->markers == NULL ) 01202 { 01203 e->markers = st_init_numtable(); 01204 } 01205 01206 /* 01207 * Markers table initially marks the string position of the 01208 * object. Doesn't yet create an anchor, simply notes the 01209 * position. 01210 */ 01211 if ( ! st_lookup( e->markers, n, (st_data_t *)&oid ) ) 01212 { 01213 /* 01214 * Store all markers 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 * Second time hitting this object, let's give it an anchor 01233 */ 01234 idx = (int)(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 * Insert into anchors table 01241 */ 01242 st_insert( e->anchors, (st_data_t)oid, (st_data_t)anchor_name ); 01243 } 01244 } 01245 return oid; 01246 } 01247 01248