Ruby 1.9.2p136(2010-12-25revision30365)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

# ext/syck/emitter.c

Go to the documentation of this file.

    00001 /*
    00002  * emitter.c
    00003  *
    00004  * $Author: nobu $
    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 = 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, 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 = 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