Ruby 1.9.2p136(2010-12-25revision30365)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

# ext/syck/rubyext.c

Go to the documentation of this file.

    00001 /* -*- indent-tabs-mode: nil -*- */
    00002 /*
    00003  * rubyext.c
    00004  *
    00005  * $Author: nobu $
    00006  *
    00007  * Copyright (C) 2003-2005 why the lucky stiff
    00008  */
    00009
    00010 #include "ruby/ruby.h"
    00011 #include "ruby/encoding.h"
    00012 #include "syck.h"
    00013 #include <sys/types.h>
    00014 #include <time.h>
    00015
    00016 typedef struct RVALUE {
    00017     union {
    00018 #if 0
    00019     struct {
    00020         unsigned long flags;    /* always 0 for freed obj */
    00021         struct RVALUE *next;
    00022     } free;
    00023 #endif
    00024     struct RBasic  basic;
    00025     struct RObject object;
    00026     struct RClass  klass;
    00027     /*struct RFloat  flonum;*/
    00028     /*struct RString string;*/
    00029     struct RArray  array;
    00030     /*struct RRegexp regexp;*/
    00031     struct RHash   hash;
    00032     /*struct RData   data;*/
    00033     struct RStruct rstruct;
    00034     /*struct RBignum bignum;*/
    00035     /*struct RFile   file;*/
    00036     } as;
    00037 } RVALUE;
    00038
    00039 typedef struct {
    00040    long hash;
    00041    char *buffer;
    00042    long length;
    00043    long remaining;
    00044    int  printed;
    00045 } bytestring_t;
    00046
    00047 #define RUBY_DOMAIN   "ruby.yaml.org,2002"
    00048
    00049 /*
    00050  * symbols and constants
    00051  */
    00052 static ID s_new, s_utc, s_at, s_to_f, s_to_i, s_read, s_binmode, s_call, s_cmp, s_transfer, s_update, s_dup, s_haskey, s_match, s_keys, s_unpack, s_tr_bang, s_default_set, s_tag_read_class, s_tag_subclasses, s_resolver, s_push, s_emitter, s_level, s_detect_implicit, s_node_import, s_out, s_input, s_intern, s_transform, s_yaml_new, s_yaml_initialize, s_node_export, s_to_yaml, s_write, s_set_resolver, s_each;
    00053 static ID s_tags, s_kind, s_name, s_options, s_type_id, s_type_id_set, s_style, s_style_set, s_value, s_value_set, s_parse;
    00054 static VALUE sym_model, sym_generic, sym_input, sym_bytecode;
    00055 static VALUE sym_scalar, sym_seq, sym_map;
    00056 static VALUE sym_1quote, sym_2quote, sym_fold, sym_literal, sym_plain, sym_inline;
    00057 static VALUE cDate, cNode, cMap, cSeq, cScalar, cOut, cParser, cResolver, cPrivateType, cDomainType, cYObject, cBadAlias, cDefaultKey, cMergeKey, cEmitter, cDateTime;
    00058 static VALUE oDefaultResolver, oGenericResolver;
    00059
    00060 /*
    00061  * my private collection of numerical oddities.
    00062  */
    00063 static double S_zero(void)    { return 0.0; }
    00064 static double S_one(void) { return 1.0; }
    00065 static double S_inf(void) { return S_one() / S_zero(); }
    00066 static double S_nan(void) { return S_zero() / S_zero(); }
    00067
    00068 static VALUE syck_node_transform( VALUE );
    00069
    00070 /*
    00071  * handler prototypes
    00072  */
    00073 SYMID rb_syck_load_handler _((SyckParser *, SyckNode *));
    00074 void rb_syck_err_handler _((SyckParser *, const char *));
    00075 SyckNode * rb_syck_bad_anchor_handler _((SyckParser *, char *));
    00076 void rb_syck_output_handler _((SyckEmitter *, char *, long));
    00077 void rb_syck_emitter_handler _((SyckEmitter *, st_data_t));
    00078 int syck_parser_assign_io _((SyckParser *, VALUE *));
    00079 VALUE syck_scalar_alloc _((VALUE class));
    00080 VALUE syck_seq_alloc _((VALUE class));
    00081 VALUE syck_map_alloc _((VALUE class));
    00082
    00083 struct parser_xtra {
    00084     VALUE data;  /* Borrowed this idea from marshal.c to fix [ruby-core:8067] problem */
    00085     VALUE proc;
    00086     VALUE resolver;
    00087     int taint;
    00088 };
    00089
    00090 struct emitter_xtra {
    00091     VALUE oid;
    00092     VALUE data;
    00093     VALUE port;
    00094 };
    00095
    00096 /*
    00097  * Convert YAML to bytecode
    00098  */
    00099 VALUE
    00100 rb_syck_compile(VALUE self, VALUE port)
    00101 {
    00102     SYMID oid;
    00103     int taint;
    00104     char *ret;
    00105     VALUE bc;
    00106     bytestring_t *sav = NULL;
    00107     void *data = NULL;
    00108
    00109     SyckParser *parser = syck_new_parser();
    00110     taint = syck_parser_assign_io(parser, &port);
    00111     syck_parser_handler( parser, syck_yaml2byte_handler );
    00112     syck_parser_error_handler( parser, NULL );
    00113     syck_parser_implicit_typing( parser, 0 );
    00114     syck_parser_taguri_expansion( parser, 0 );
    00115     oid = syck_parse( parser );
    00116     if (!syck_lookup_sym( parser, oid, &data )) {
    00117         rb_raise(rb_eSyntaxError, "root node <%lx> not found", oid);
    00118     }
    00119     sav = data;
    00120
    00121     ret = S_ALLOCA_N( char, strlen( sav->buffer ) + 3 );
    00122     ret[0] = '\0';
    00123     strcat( ret, "D\n" );
    00124     strcat( ret, sav->buffer );
    00125
    00126     syck_free_parser( parser );
    00127
    00128     bc = rb_str_new2( ret );
    00129     if ( taint )      OBJ_TAINT( bc );
    00130     return bc;
    00131 }
    00132
    00133 /*
    00134  * read from io.
    00135  */
    00136 long
    00137 rb_syck_io_str_read( char *buf, SyckIoStr *str, long max_size, long skip )
    00138 {
    00139     long len = 0;
    00140
    00141     ASSERT( str != NULL );
    00142     max_size -= skip;
    00143
    00144     if ( max_size <= 0 ) max_size = 0;
    00145     else
    00146     {
    00147         /*
    00148          * call io#read.
    00149          */
    00150         VALUE src = (VALUE)str->ptr;
    00151         VALUE n = LONG2NUM(max_size);
    00152         VALUE str2 = rb_funcall2(src, s_read, 1, &n);
    00153         if (!NIL_P(str2))
    00154         {
    00155             StringValue(str2);
    00156             len = RSTRING_LEN(str2);
    00157             memcpy( buf + skip, RSTRING_PTR(str2), len );
    00158         }
    00159     }
    00160     len += skip;
    00161     buf[len] = '\0';
    00162     return len;
    00163 }
    00164
    00165 /*
    00166  * determine: are we reading from a string or io?
    00167  * (returns tainted? boolean)
    00168  */
    00169 int
    00170 syck_parser_assign_io(SyckParser *parser, VALUE *pport)
    00171 {
    00172     int taint = Qtrue;
    00173     VALUE tmp, port = *pport;
    00174     if (!NIL_P(tmp = rb_check_string_type(port))) {
    00175         taint = OBJ_TAINTED(port); /* original taintedness */
    00176         port = tmp;
    00177         syck_parser_str( parser, RSTRING_PTR(port), RSTRING_LEN(port), NULL );
    00178     }
    00179     else if (rb_respond_to(port, s_read)) {
    00180         if (rb_respond_to(port, s_binmode)) {
    00181             rb_funcall2(port, s_binmode, 0, 0);
    00182         }
    00183         syck_parser_str( parser, (char *)port, 0, rb_syck_io_str_read );
    00184     }
    00185     else {
    00186         rb_raise(rb_eTypeError, "instance of IO needed");
    00187     }
    00188     *pport = port;
    00189     return taint;
    00190 }
    00191
    00192 /*
    00193  * Get value in hash by key, forcing an empty hash if nil.
    00194  */
    00195 VALUE
    00196 syck_get_hash_aref(VALUE hsh, VALUE key)
    00197 {
    00198    VALUE val = rb_hash_aref( hsh, key );
    00199    if ( NIL_P( val ) )
    00200    {
    00201        val = rb_hash_new();
    00202        rb_hash_aset(hsh, key, val);
    00203    }
    00204    return val;
    00205 }
    00206
    00207 /*
    00208  * creating timestamps
    00209  */
    00210 struct mktime_arg {
    00211     char *str;
    00212     long len;
    00213 };
    00214
    00215 SYMID
    00216 mktime_do(struct mktime_arg *arg)
    00217 {
    00218     VALUE time;
    00219     char *str = arg->str;
    00220     long len = arg->len;
    00221     char *ptr = str;
    00222     VALUE year = INT2FIX(0);
    00223     VALUE mon = INT2FIX(0);
    00224     VALUE day = INT2FIX(0);
    00225     VALUE hour = INT2FIX(0);
    00226     VALUE min = INT2FIX(0);
    00227     VALUE sec = INT2FIX(0);
    00228     long usec;
    00229
    00230     /* Year*/
    00231     if ( ptr[0] != '\0' && len > 0 ) {
    00232         year = INT2FIX(strtol(ptr, NULL, 10));
    00233     }
    00234
    00235     /* Month*/
    00236     ptr += 4;
    00237     if ( ptr[0] != '\0' && len > ptr - str ) {
    00238         while ( !ISDIGIT( *ptr ) ) ptr++;
    00239         mon = INT2FIX(strtol(ptr, NULL, 10));
    00240     }
    00241
    00242     /* Day*/
    00243     ptr += 2;
    00244     if ( ptr[0] != '\0' && len > ptr - str ) {
    00245         while ( !ISDIGIT( *ptr ) ) ptr++;
    00246         day = INT2FIX(strtol(ptr, NULL, 10));
    00247     }
    00248
    00249     /* Hour*/
    00250     ptr += 2;
    00251     if ( ptr[0] != '\0' && len > ptr - str ) {
    00252         while ( !ISDIGIT( *ptr ) ) ptr++;
    00253         hour = INT2FIX(strtol(ptr, NULL, 10));
    00254     }
    00255
    00256     /* Minute */
    00257     ptr += 2;
    00258     if ( ptr[0] != '\0' && len > ptr - str ) {
    00259         while ( !ISDIGIT( *ptr ) ) ptr++;
    00260         min = INT2FIX(strtol(ptr, NULL, 10));
    00261     }
    00262
    00263     /* Second */
    00264     ptr += 2;
    00265     if ( ptr[0] != '\0' && len > ptr - str ) {
    00266         while ( !ISDIGIT( *ptr ) ) ptr++;
    00267         sec = INT2FIX(strtol(ptr, NULL, 10));
    00268     }
    00269
    00270     /* Millisecond */
    00271     ptr += 2;
    00272     if ( len > ptr - str && *ptr == '.' )
    00273     {
    00274         char padded[] = "000000";
    00275         char *end = ptr + 1;
    00276         char *p = end;
    00277         while ( isdigit( *end ) ) end++;
    00278         if (end - p < sizeof(padded)) {
    00279             MEMCPY(padded, ptr + 1, char, end - (ptr + 1));
    00280             p = padded;
    00281         }
    00282         usec = strtol(p, NULL, 10);
    00283     }
    00284     else
    00285     {
    00286         usec = 0;
    00287     }
    00288
    00289     /* Time Zone*/
    00290     while ( len > ptr - str && *ptr != 'Z' && *ptr != '+' && *ptr != '-' && *ptr != '\0' ) ptr++;
    00291     if ( len > ptr - str && ( *ptr == '-' || *ptr == '+' ) )
    00292     {
    00293         time_t tz_offset = strtol(ptr, NULL, 10) * 3600;
    00294         VALUE tmp;
    00295
    00296         while ( *ptr != ':' && *ptr != '\0' ) ptr++;
    00297         if ( *ptr == ':' )
    00298         {
    00299             ptr += 1;
    00300             if ( tz_offset < 0 )
    00301             {
    00302                 tz_offset -= strtol(ptr, NULL, 10) * 60;
    00303             }
    00304             else
    00305             {
    00306                 tz_offset += strtol(ptr, NULL, 10) * 60;
    00307             }
    00308         }
    00309
    00310         /* Make TZ time*/
    00311         time = rb_funcall(rb_cTime, s_utc, 6, year, mon, day, hour, min, sec);
    00312         tmp = rb_funcall(time, s_to_i, 0);
    00313         tmp = rb_funcall(tmp, '-', 1, LONG2FIX(tz_offset));
    00314         return rb_funcall(rb_cTime, s_at, 2, tmp, LONG2NUM(usec));
    00315     }
    00316     else
    00317     {
    00318         /* Make UTC time*/
    00319         return rb_funcall(rb_cTime, s_utc, 7, year, mon, day, hour, min, sec, LONG2NUM(usec));
    00320     }
    00321 }
    00322
    00323 SYMID
    00324 mktime_r(struct mktime_arg *arg)
    00325 {
    00326     if (!cDateTime) {
    00327         /*
    00328          * Load Date module
    00329          */
    00330         rb_require("date");
    00331         cDateTime = rb_const_get(rb_cObject, rb_intern("DateTime"));
    00332     }
    00333     return rb_funcall(cDateTime, s_parse, 1, rb_str_new(arg->str, arg->len));
    00334 }
    00335
    00336 SYMID
    00337 rb_syck_mktime(char *str, long len)
    00338 {
    00339     struct mktime_arg a;
    00340
    00341     a.str = str;
    00342     a.len = len;
    00343     return rb_rescue2(mktime_do, (VALUE)&a, mktime_r, (VALUE)&a, rb_eArgError, NULL);
    00344 }
    00345
    00346 /*
    00347  * handles merging of an array of hashes
    00348  * (see http://www.yaml.org/type/merge/)
    00349  */
    00350 VALUE
    00351 syck_merge_i(VALUE entry, VALUE hsh )
    00352 {
    00353     VALUE tmp;
    00354     if ( !NIL_P(tmp = rb_check_convert_type(entry, T_HASH, "Hash", "to_hash")) )
    00355     {
    00356         entry = tmp;
    00357         rb_funcall( hsh, s_update, 1, entry );
    00358     }
    00359     return Qnil;
    00360 }
    00361
    00362 /*
    00363  * default handler for ruby.yaml.org types
    00364  */
    00365 int
    00366 yaml_org_handler( SyckNode *n, VALUE *ref )
    00367 {
    00368     char *type_id = n->type_id;
    00369     int transferred = 0;
    00370     long i = 0;
    00371     VALUE obj = Qnil;
    00372
    00373     if ( type_id != NULL && strncmp( type_id, "tag:yaml.org,2002:", 18 ) == 0 )
    00374     {
    00375         type_id += 18;
    00376     }
    00377
    00378     switch (n->kind)
    00379     {
    00380         case syck_str_kind:
    00381             transferred = 1;
    00382             if ( type_id == NULL )
    00383             {
    00384                 obj = rb_str_new( n->data.str->ptr, n->data.str->len );
    00385             }
    00386             else if ( strcmp( type_id, "null" ) == 0 )
    00387             {
    00388                 obj = Qnil;
    00389             }
    00390             else if ( strcmp( type_id, "binary" ) == 0 )
    00391             {
    00392                 VALUE arr;
    00393                 obj = rb_str_new( n->data.str->ptr, n->data.str->len );
    00394                 rb_funcall( obj, s_tr_bang, 2, rb_str_new2( "\n\t " ), rb_str_new2( "" ) );
    00395                 arr = rb_funcall( obj, s_unpack, 1, rb_str_new2( "m" ) );
    00396                 obj = rb_ary_shift( arr );
    00397             }
    00398             else if ( strcmp( type_id, "bool#yes" ) == 0 )
    00399             {
    00400                 obj = Qtrue;
    00401             }
    00402             else if ( strcmp( type_id, "bool#no" ) == 0 )
    00403             {
    00404                 obj = Qfalse;
    00405             }
    00406             else if ( strcmp( type_id, "int#hex" ) == 0 )
    00407             {
    00408                 syck_str_blow_away_commas( n );
    00409                 obj = rb_cstr2inum( n->data.str->ptr, 16 );
    00410             }
    00411             else if ( strcmp( type_id, "int#oct" ) == 0 )
    00412             {
    00413                 syck_str_blow_away_commas( n );
    00414                 obj = rb_cstr2inum( n->data.str->ptr, 8 );
    00415             }
    00416             else if ( strcmp( type_id, "int#base60" ) == 0 )
    00417             {
    00418                 char *ptr, *end;
    00419                 long sixty = 1;
    00420                 long total = 0;
    00421                 syck_str_blow_away_commas( n );
    00422                 ptr = n->data.str->ptr;
    00423                 end = n->data.str->ptr + n->data.str->len;
    00424                 while ( end > ptr )
    00425                 {
    00426                     long bnum = 0;
    00427                     char *colon = end - 1;
    00428                     while ( colon >= ptr && *colon != ':' )
    00429                     {
    00430                         colon--;
    00431                     }
    00432                     if ( colon >= ptr && *colon == ':' ) *colon = '\0';
    00433
    00434                     bnum = strtol( colon + 1, NULL, 10 );
    00435                     total += bnum * sixty;
    00436                     sixty *= 60;
    00437                     end = colon;
    00438                 }
    00439                 obj = INT2FIX(total);
    00440             }
    00441             else if ( strncmp( type_id, "int", 3 ) == 0 )
    00442             {
    00443                 syck_str_blow_away_commas( n );
    00444                 obj = rb_cstr2inum( n->data.str->ptr, 10 );
    00445             }
    00446             else if ( strcmp( type_id, "float#base60" ) == 0 )
    00447             {
    00448                 char *ptr, *end;
    00449                 long sixty = 1;
    00450                 double total = 0.0;
    00451                 syck_str_blow_away_commas( n );
    00452                 ptr = n->data.str->ptr;
    00453                 end = n->data.str->ptr + n->data.str->len;
    00454                 while ( end > ptr )
    00455                 {
    00456                     double bnum = 0;
    00457                     char *colon = end - 1;
    00458                     while ( colon >= ptr && *colon != ':' )
    00459                     {
    00460                         colon--;
    00461                     }
    00462                     if ( colon >= ptr && *colon == ':' ) *colon = '\0';
    00463
    00464                     bnum = strtod( colon + 1, NULL );
    00465                     total += bnum * sixty;
    00466                     sixty *= 60;
    00467                     end = colon;
    00468                 }
    00469                 obj = rb_float_new( total );
    00470             }
    00471             else if ( strcmp( type_id, "float#nan" ) == 0 )
    00472             {
    00473                 obj = rb_float_new( S_nan() );
    00474             }
    00475             else if ( strcmp( type_id, "float#inf" ) == 0 )
    00476             {
    00477                 obj = rb_float_new( S_inf() );
    00478             }
    00479             else if ( strcmp( type_id, "float#neginf" ) == 0 )
    00480             {
    00481                 obj = rb_float_new( -S_inf() );
    00482             }
    00483             else if ( strncmp( type_id, "float", 5 ) == 0 )
    00484             {
    00485                 double f;
    00486                 syck_str_blow_away_commas( n );
    00487                 f = strtod( n->data.str->ptr, NULL );
    00488                 obj = rb_float_new( f );
    00489             }
    00490             else if ( strcmp( type_id, "timestamp#iso8601" ) == 0 )
    00491             {
    00492                 obj = rb_syck_mktime( n->data.str->ptr, n->data.str->len );
    00493             }
    00494             else if ( strcmp( type_id, "timestamp#spaced" ) == 0 )
    00495             {
    00496                 obj = rb_syck_mktime( n->data.str->ptr, n->data.str->len );
    00497             }
    00498             else if ( strcmp( type_id, "timestamp#ymd" ) == 0 )
    00499             {
    00500                 char *ptr = n->data.str->ptr;
    00501                 VALUE year, mon, day;
    00502
    00503                 /* Year*/
    00504                 ptr[4] = '\0';
    00505                 year = INT2FIX(strtol(ptr, NULL, 10));
    00506
    00507                 /* Month*/
    00508                 ptr += 4;
    00509                 while ( !ISDIGIT( *ptr ) ) ptr++;
    00510                 mon = INT2FIX(strtol(ptr, NULL, 10));
    00511
    00512                 /* Day*/
    00513                 ptr += 2;
    00514                 while ( !ISDIGIT( *ptr ) ) ptr++;
    00515                 day = INT2FIX(strtol(ptr, NULL, 10));
    00516
    00517                 if ( !cDate ) {
    00518                     /*
    00519                      * Load Date module
    00520                      */
    00521                     rb_require( "date" );
    00522                     cDate = rb_const_get( rb_cObject, rb_intern("Date") );
    00523                 }
    00524
    00525                 obj = rb_funcall( cDate, s_new, 3, year, mon, day );
    00526             }
    00527             else if ( strncmp( type_id, "timestamp", 9 ) == 0 )
    00528             {
    00529                 obj = rb_syck_mktime( n->data.str->ptr, n->data.str->len );
    00530             }
    00531             else if ( strncmp( type_id, "merge", 5 ) == 0 )
    00532             {
    00533                 obj = rb_funcall( cMergeKey, s_new, 0 );
    00534             }
    00535             else if ( strncmp( type_id, "default", 7 ) == 0 )
    00536             {
    00537                 obj = rb_funcall( cDefaultKey, s_new, 0 );
    00538             }
    00539             else if ( n->data.str->style == scalar_plain &&
    00540                       n->data.str->len > 1 &&
    00541                       strncmp( n->data.str->ptr, ":", 1 ) == 0 )
    00542             {
    00543                 obj = rb_funcall( oDefaultResolver, s_transfer, 2,
    00544                                   rb_str_new2( "tag:ruby.yaml.org,2002:sym" ),
    00545                                   rb_str_new( n->data.str->ptr + 1, n->data.str->len - 1 ) );
    00546             }
    00547             else if ( strcmp( type_id, "str" ) == 0 )
    00548             {
    00549                 obj = rb_str_new( n->data.str->ptr, n->data.str->len );
    00550                 rb_enc_associate(obj, rb_utf8_encoding());
    00551             }
    00552             else
    00553             {
    00554                 transferred = 0;
    00555                 obj = rb_str_new( n->data.str->ptr, n->data.str->len );
    00556             }
    00557         break;
    00558
    00559         case syck_seq_kind:
    00560             if ( type_id == NULL || strcmp( type_id, "seq" ) == 0 )
    00561             {
    00562                 transferred = 1;
    00563             }
    00564             obj = rb_ary_new2( n->data.list->idx );
    00565             for ( i = 0; i < n->data.list->idx; i++ )
    00566             {
    00567                 rb_ary_store( obj, i, syck_seq_read( n, i ) );
    00568             }
    00569         break;
    00570
    00571         case syck_map_kind:
    00572             if ( type_id == NULL || strcmp( type_id, "map" ) == 0 )
    00573             {
    00574                 transferred = 1;
    00575             }
    00576             obj = rb_hash_new();
    00577             for ( i = 0; i < n->data.pairs->idx; i++ )
    00578             {
    00579                 VALUE k = syck_map_read( n, map_key, i );
    00580                 VALUE v = syck_map_read( n, map_value, i );
    00581                 int skip_aset = 0;
    00582
    00583                 /*
    00584                  * Handle merge keys
    00585                  */
    00586                 if ( rb_obj_is_kind_of( k, cMergeKey ) )
    00587                 {
    00588                     VALUE tmp;
    00589                     if ( !NIL_P(tmp = rb_check_convert_type(v, T_HASH, "Hash", "to_hash")) )
    00590                     {
    00591                         VALUE dup = rb_funcall( tmp, s_dup, 0 );
    00592                         rb_funcall( dup, s_update, 1, obj );
    00593                         obj = dup;
    00594                         skip_aset = 1;
    00595                     }
    00596                     else if ( !NIL_P(tmp = rb_check_array_type(v)) )
    00597                     {
    00598                         VALUE end = rb_ary_pop( tmp );
    00599                         VALUE tmph = rb_check_convert_type(end, T_HASH, "Hash", "to_hash");
    00600                         if ( !NIL_P(tmph) )
    00601                         {
    00602                             VALUE dup = rb_funcall( tmph, s_dup, 0 );
    00603                             tmp = rb_ary_reverse( tmp );
    00604                             rb_ary_push( tmp, obj );
    00605                             rb_block_call( tmp, s_each, 0, 0, syck_merge_i, dup );
    00606                             obj = dup;
    00607                             skip_aset = 1;
    00608                         }
    00609                     }
    00610                 }
    00611                 else if ( rb_obj_is_kind_of( k, cDefaultKey ) )
    00612                 {
    00613                     rb_funcall( obj, s_default_set, 1, v );
    00614                     skip_aset = 1;
    00615                 }
    00616
    00617                 if ( ! skip_aset )
    00618                 {
    00619                     rb_hash_aset( obj, k, v );
    00620                 }
    00621             }
    00622         break;
    00623     }
    00624
    00625     *ref = obj;
    00626     return transferred;
    00627 }
    00628
    00629 static void syck_node_mark( SyckNode *n );
    00630
    00631 /*
    00632  * {native mode} node handler
    00633  * - Converts data into native Ruby types
    00634  */
    00635 SYMID
    00636 rb_syck_load_handler(SyckParser *p, SyckNode *n)
    00637 {
    00638     VALUE obj = Qnil;
    00639     struct parser_xtra *bonus = (struct parser_xtra *)p->bonus;
    00640     VALUE resolver = bonus->resolver;
    00641     if ( NIL_P( resolver ) )
    00642     {
    00643         resolver = oDefaultResolver;
    00644     }
    00645
    00646     /*
    00647      * Create node,
    00648      */
    00649     obj = rb_funcall( resolver, s_node_import, 1, Data_Wrap_Struct( cNode, NULL, NULL, n ) );
    00650
    00651     /*
    00652      * ID already set, let's alter the symbol table to accept the new object
    00653      */
    00654     if (n->id > 0 && !NIL_P(obj))
    00655     {
    00656         MEMCPY((void *)n->id, (void *)obj, RVALUE, 1);
    00657         MEMZERO((void *)obj, RVALUE, 1);
    00658         obj = n->id;
    00659     }
    00660
    00661     if ( bonus->taint)      OBJ_TAINT( obj );
    00662     if ( bonus->proc != 0 ) rb_funcall(bonus->proc, s_call, 1, obj);
    00663
    00664     rb_hash_aset(bonus->data, INT2FIX(RHASH_SIZE(bonus->data)), obj);
    00665     return obj;
    00666 }
    00667
    00668 /*
    00669  * friendly errors.
    00670  */
    00671 void
    00672 rb_syck_err_handler(SyckParser *p, const char *msg)
    00673 {
    00674     char *endl = p->cursor;
    00675
    00676     while ( *endl != '\0' && *endl != '\n' )
    00677         endl++;
    00678
    00679     endl[0] = '\0';
    00680     rb_raise(rb_eArgError, "%s on line %d, col %"PRIdPTRDIFF": `%s'",
    00681            msg,
    00682            p->linect,
    00683            p->cursor - p->lineptr,
    00684            p->lineptr);
    00685 }
    00686
    00687 /*
    00688  * provide bad anchor object to the parser.
    00689  */
    00690 SyckNode *
    00691 rb_syck_bad_anchor_handler(SyckParser *p, char *a)
    00692 {
    00693     VALUE anchor_name = rb_str_new2( a );
    00694     SyckNode *badanc = syck_new_map( rb_str_new2( "name" ), anchor_name );
    00695     badanc->type_id = syck_strndup( "tag:ruby.yaml.org,2002:object:YAML::Syck::BadAlias", 53 );
    00696     return badanc;
    00697 }
    00698
    00699 /*
    00700  * data loaded based on the model requested.
    00701  */
    00702 void
    00703 syck_set_model(VALUE p, VALUE input, VALUE model)
    00704 {
    00705     SyckParser *parser;
    00706     Data_Get_Struct(p, SyckParser, parser);
    00707     syck_parser_handler( parser, rb_syck_load_handler );
    00708     /* WARN: gonna be obsoleted soon!! */
    00709     if ( model == sym_generic )
    00710     {
    00711         rb_funcall( p, s_set_resolver, 1, oGenericResolver );
    00712     }
    00713     syck_parser_implicit_typing( parser, 1 );
    00714     syck_parser_taguri_expansion( parser, 1 );
    00715
    00716     if ( NIL_P( input ) )
    00717     {
    00718         input = rb_ivar_get( p, s_input );
    00719     }
    00720     if ( input == sym_bytecode )
    00721     {
    00722         syck_parser_set_input_type( parser, syck_bytecode_utf8 );
    00723     }
    00724     else
    00725     {
    00726         syck_parser_set_input_type( parser, syck_yaml_utf8 );
    00727     }
    00728     syck_parser_error_handler( parser, rb_syck_err_handler );
    00729     syck_parser_bad_anchor_handler( parser, rb_syck_bad_anchor_handler );
    00730 }
    00731
    00732 static int
    00733 syck_st_mark_nodes( char *key, SyckNode *n, char *arg )
    00734 {
    00735     if ( n != (void *)1 ) syck_node_mark( n );
    00736     return ST_CONTINUE;
    00737 }
    00738
    00739 /*
    00740  * mark parser nodes
    00741  */
    00742 static void
    00743 syck_mark_parser(SyckParser *parser)
    00744 {
    00745     struct parser_xtra *bonus = (struct parser_xtra *)parser->bonus;
    00746     rb_gc_mark_maybe(parser->root);
    00747     rb_gc_mark_maybe(parser->root_on_error);
    00748     rb_gc_mark( bonus->data );
    00749     rb_gc_mark( bonus->proc );
    00750     rb_gc_mark( bonus->resolver );
    00751
    00752     if ( parser->anchors != NULL )
    00753     {
    00754         st_foreach( parser->anchors, syck_st_mark_nodes, 0 );
    00755     }
    00756     if ( parser->bad_anchors != NULL )
    00757     {
    00758         st_foreach( parser->bad_anchors, syck_st_mark_nodes, 0 );
    00759     }
    00760 }
    00761
    00762 /*
    00763  * Free the parser and any bonus attachment.
    00764  */
    00765 void
    00766 rb_syck_free_parser(SyckParser *p)
    00767 {
    00768     S_FREE( p->bonus );
    00769     syck_free_parser(p);
    00770 }
    00771
    00772 /*
    00773  * YAML::Syck::Parser.allocate
    00774  */
    00775 VALUE syck_parser_s_alloc _((VALUE));
    00776 VALUE
    00777 syck_parser_s_alloc(VALUE class)
    00778 {
    00779     VALUE pobj;
    00780     SyckParser *parser = syck_new_parser();
    00781
    00782     parser->bonus = S_ALLOC( struct parser_xtra );
    00783     S_MEMZERO( parser->bonus, struct parser_xtra, 1 );
    00784
    00785     pobj = Data_Wrap_Struct( class, syck_mark_parser, rb_syck_free_parser, parser );
    00786
    00787     syck_parser_set_root_on_error( parser, Qnil );
    00788
    00789     return pobj;
    00790 }
    00791
    00792 /*
    00793  * YAML::Syck::Parser.initialize( resolver, options )
    00794  */
    00795 static VALUE
    00796 syck_parser_initialize(int argc, VALUE *argv, VALUE self)
    00797 {
    00798     VALUE options;
    00799     if (rb_scan_args(argc, argv, "01", &options) == 0)
    00800     {
    00801         options = rb_hash_new();
    00802     }
    00803     else
    00804     {
    00805         Check_Type(options, T_HASH);
    00806     }
    00807     rb_ivar_set(self, s_options, options);
    00808     rb_ivar_set(self, s_input, Qnil);
    00809     return self;
    00810 }
    00811
    00812 /*
    00813  * YAML::Syck::Parser.bufsize = Integer
    00814  */
    00815 static VALUE
    00816 syck_parser_bufsize_set(VALUE self, VALUE size)
    00817 {
    00818     SyckParser *parser;
    00819
    00820     if ( rb_respond_to( size, s_to_i ) ) {
    00821         int n = NUM2INT(rb_funcall(size, s_to_i, 0));
    00822         Data_Get_Struct(self, SyckParser, parser);
    00823         parser->bufsize = n;
    00824     }
    00825     return self;
    00826 }
    00827
    00828 /*
    00829  * YAML::Syck::Parser.bufsize => Integer
    00830  */
    00831 static VALUE
    00832 syck_parser_bufsize_get(VALUE self)
    00833 {
    00834     SyckParser *parser;
    00835
    00836     Data_Get_Struct(self, SyckParser, parser);
    00837     return INT2FIX( parser->bufsize );
    00838 }
    00839
    00840 /*
    00841  * YAML::Syck::Parser.load( IO or String )
    00842  */
    00843 VALUE
    00844 syck_parser_load(int argc, VALUE *argv, VALUE self)
    00845 {
    00846     VALUE port, proc, model, input;
    00847     SyckParser *parser;
    00848     struct parser_xtra *bonus;
    00849
    00850     rb_scan_args(argc, argv, "11", &port, &proc);
    00851
    00852     input = rb_hash_aref( rb_attr_get( self, s_options ), sym_input );
    00853     model = rb_hash_aref( rb_attr_get( self, s_options ), sym_model );
    00854     Data_Get_Struct(self, SyckParser, parser);
    00855     syck_set_model( self, input, model );
    00856
    00857     bonus = (struct parser_xtra *)parser->bonus;
    00858     bonus->taint = syck_parser_assign_io(parser, &port);
    00859     bonus->data = rb_hash_new();
    00860     bonus->resolver = rb_attr_get( self, s_resolver );
    00861     if ( NIL_P( proc ) ) bonus->proc = 0;
    00862     else                 bonus->proc = proc;
    00863
    00864     return syck_parse( parser );
    00865 }
    00866
    00867 /*
    00868  * YAML::Syck::Parser.load_documents( IO or String ) { |doc| }
    00869  */
    00870 VALUE
    00871 syck_parser_load_documents(int argc, VALUE *argv, VALUE self)
    00872 {
    00873     VALUE port, proc, v, input, model;
    00874     SyckParser *parser;
    00875     struct parser_xtra *bonus;
    00876
    00877     rb_scan_args(argc, argv, "1&", &port, &proc);
    00878
    00879     input = rb_hash_aref( rb_attr_get( self, s_options ), sym_input );
    00880     model = rb_hash_aref( rb_attr_get( self, s_options ), sym_model );
    00881     Data_Get_Struct(self, SyckParser, parser);
    00882     syck_set_model( self, input, model );
    00883
    00884     bonus = (struct parser_xtra *)parser->bonus;
    00885     bonus->taint = syck_parser_assign_io(parser, &port);
    00886     bonus->resolver = rb_attr_get( self, s_resolver );
    00887     bonus->proc = 0;
    00888
    00889     while ( 1 )
    00890     {
    00891         /* Reset hash for tracking nodes */
    00892         bonus->data = rb_hash_new();
    00893
    00894         /* Parse a document */
    00895         v = syck_parse( parser );
    00896         if ( parser->eof == 1 )
    00897         {
    00898             break;
    00899         }
    00900
    00901         /* Pass document to block */
    00902         rb_funcall( proc, s_call, 1, v );
    00903     }
    00904
    00905     return Qnil;
    00906 }
    00907
    00908 /*
    00909  * YAML::Syck::Parser#set_resolver
    00910  */
    00911 VALUE
    00912 syck_parser_set_resolver(VALUE self, VALUE resolver)
    00913 {
    00914     rb_ivar_set( self, s_resolver, resolver );
    00915     return self;
    00916 }
    00917
    00918 /*
    00919  * YAML::Syck::Resolver.initialize
    00920  */
    00921 static VALUE
    00922 syck_resolver_initialize(VALUE self)
    00923 {
    00924     rb_ivar_set(self, s_tags, rb_hash_new());
    00925     return self;
    00926 }
    00927
    00928 /*
    00929  * YAML::Syck::Resolver#add_type
    00930  */
    00931 VALUE
    00932 syck_resolver_add_type(VALUE self, VALUE taguri, VALUE cls)
    00933 {
    00934     VALUE tags = rb_attr_get(self, s_tags);
    00935     rb_hash_aset( tags, taguri, cls );
    00936     return Qnil;
    00937 }
    00938
    00939 /*
    00940  * YAML::Syck::Resolver#use_types_at
    00941  */
    00942 VALUE
    00943 syck_resolver_use_types_at(VALUE self, VALUE hsh)
    00944 {
    00945     rb_ivar_set( self, s_tags, hsh );
    00946     return Qnil;
    00947 }
    00948
    00949 /*
    00950  * YAML::Syck::Resolver#detect_implicit
    00951  */
    00952 VALUE
    00953 syck_resolver_detect_implicit(VALUE self, VALUE val)
    00954 {
    00955     return rb_str_new2( "" );
    00956 }
    00957
    00958 /*
    00959  * YAML::Syck::Resolver#node_import
    00960  */
    00961 VALUE
    00962 syck_resolver_node_import(VALUE self, VALUE node)
    00963 {
    00964     SyckNode *n;
    00965     VALUE obj = Qnil;
    00966     int i = 0;
    00967     Data_Get_Struct(node, SyckNode, n);
    00968
    00969     switch (n->kind)
    00970     {
    00971         case syck_str_kind:
    00972             obj = rb_str_new( n->data.str->ptr, n->data.str->len );
    00973         break;
    00974
    00975         case syck_seq_kind:
    00976             obj = rb_ary_new2( n->data.list->idx );
    00977             for ( i = 0; i < n->data.list->idx; i++ )
    00978             {
    00979                 rb_ary_store( obj, i, syck_seq_read( n, i ) );
    00980             }
    00981         break;
    00982
    00983         case syck_map_kind:
    00984             obj = rb_hash_new();
    00985             for ( i = 0; i < n->data.pairs->idx; i++ )
    00986             {
    00987                 VALUE k = syck_map_read( n, map_key, i );
    00988                 VALUE v = syck_map_read( n, map_value, i );
    00989                 int skip_aset = 0;
    00990
    00991                 /*
    00992                  * Handle merge keys
    00993                  */
    00994                 if ( rb_obj_is_kind_of( k, cMergeKey ) )
    00995                 {
    00996                     if ( rb_obj_is_kind_of( v, rb_cHash ) )
    00997                     {
    00998                         VALUE dup = rb_funcall( v, s_dup, 0 );
    00999                         rb_funcall( dup, s_update, 1, obj );
    01000                         obj = dup;
    01001                         skip_aset = 1;
    01002                     }
    01003                     else if ( rb_obj_is_kind_of( v, rb_cArray ) )
    01004                     {
    01005                         VALUE end = rb_ary_pop( v );
    01006                         if ( rb_obj_is_kind_of( end, rb_cHash ) )
    01007                         {
    01008                             VALUE dup = rb_funcall( end, s_dup, 0 );
    01009                             v = rb_ary_reverse( v );
    01010                             rb_ary_push( v, obj );
    01011                             rb_block_call( v, s_each, 0, 0, syck_merge_i, dup );
    01012                             obj = dup;
    01013                             skip_aset = 1;
    01014                         }
    01015                     }
    01016                 }
    01017                 else if ( rb_obj_is_kind_of( k, cDefaultKey ) )
    01018                 {
    01019                     rb_funcall( obj, s_default_set, 1, v );
    01020                     skip_aset = 1;
    01021                 }
    01022
    01023                 if ( ! skip_aset )
    01024                 {
    01025                     rb_hash_aset( obj, k, v );
    01026                 }
    01027             }
    01028         break;
    01029     }
    01030
    01031     if ( n->type_id != NULL )
    01032     {
    01033         obj = rb_funcall( self, s_transfer, 2, rb_str_new2( n->type_id ), obj );
    01034     }
    01035     return obj;
    01036 }
    01037
    01038 /*
    01039  * Set instance variables
    01040  */
    01041 VALUE
    01042 syck_set_ivars(VALUE vars, VALUE obj)
    01043 {
    01044     VALUE ivname = rb_ary_entry( vars, 0 );
    01045     char *ivn;
    01046     StringValue( ivname );
    01047     ivn = S_ALLOCA_N( char, RSTRING_LEN(ivname) + 2 );
    01048     ivn[0] = '@';
    01049     ivn[1] = '\0';
    01050     strncat( ivn, RSTRING_PTR(ivname), RSTRING_LEN(ivname) );
    01051     rb_iv_set( obj, ivn, rb_ary_entry( vars, 1 ) );
    01052     return Qnil;
    01053 }
    01054
    01055 /*
    01056  * YAML::Syck::Resolver#const_find
    01057  */
    01058 VALUE
    01059 syck_const_find(VALUE const_name)
    01060 {
    01061     VALUE tclass = rb_cObject;
    01062     VALUE tparts = rb_str_split( const_name, "::" );
    01063     int i = 0;
    01064     for ( i = 0; i < RARRAY_LEN(tparts); i++ ) {
    01065         VALUE tpart = rb_to_id( rb_ary_entry( tparts, i ) );
    01066         if ( !rb_const_defined( tclass, tpart ) ) return Qnil;
    01067         tclass = rb_const_get( tclass, tpart );
    01068     }
    01069     return tclass;
    01070 }
    01071
    01072 /*
    01073  * YAML::Syck::Resolver#transfer
    01074  */
    01075 VALUE
    01076 syck_resolver_transfer(VALUE self, VALUE type, VALUE val)
    01077 {
    01078     if (NIL_P(type) || RSTRING_LEN(StringValue(type)) == 0)
    01079     {
    01080         type = rb_funcall( self, s_detect_implicit, 1, val );
    01081     }
    01082
    01083     if ( ! (NIL_P(type) || RSTRING_LEN(StringValue(type)) == 0) )
    01084     {
    01085         VALUE str_xprivate = rb_str_new2( "x-private" );
    01086         VALUE colon = rb_str_new2( ":" );
    01087         VALUE tags = rb_attr_get(self, s_tags);
    01088         VALUE target_class = rb_hash_aref( tags, type );
    01089         VALUE subclass = target_class;
    01090         VALUE obj = Qnil;
    01091
    01092         /*
    01093          * Should no tag match exactly, check for subclass format
    01094          */
    01095         if ( NIL_P( target_class ) )
    01096         {
    01097             VALUE subclass_parts = rb_ary_new();
    01098             VALUE parts = rb_str_split( type, ":" );
    01099
    01100             while ( RARRAY_LEN(parts) > 1 )
    01101             {
    01102                 VALUE partial;
    01103                 rb_ary_unshift( subclass_parts, rb_ary_pop( parts ) );
    01104                 partial = rb_ary_join( parts, colon );
    01105                 target_class = rb_hash_aref( tags, partial );
    01106                 if ( NIL_P( target_class ) )
    01107                 {
    01108                     rb_str_append( partial, colon );
    01109                     target_class = rb_hash_aref( tags, partial );
    01110                 }
    01111
    01112                 /*
    01113                  * Possible subclass found, see if it supports subclassing
    01114                  */
    01115                 if ( ! NIL_P( target_class ) )
    01116                 {
    01117                     subclass = target_class;
    01118                     if ( RARRAY_LEN(subclass_parts) > 0 && rb_respond_to( target_class, s_tag_subclasses ) &&
    01119                          RTEST( rb_funcall( target_class, s_tag_subclasses, 0 ) ) )
    01120                     {
    01121                         VALUE subclass_v;
    01122                         subclass = rb_ary_join( subclass_parts, colon );
    01123                         subclass = rb_funcall( target_class, s_tag_read_class, 1, subclass );
    01124                         subclass_v = syck_const_find( subclass );
    01125
    01126                         if ( subclass_v != Qnil )
    01127                         {
    01128                             subclass = subclass_v;
    01129                         }
    01130                         else if ( rb_cObject == target_class && subclass_v == Qnil )
    01131                         {
    01132                             target_class = cYObject;
    01133                             type = subclass;
    01134                             subclass = cYObject;
    01135                         }
    01136                         else /* workaround for SEGV. real fix please */
    01137                         {
    01138                             rb_raise( rb_eTypeError, "invalid subclass" );
    01139                         }
    01140                     }
    01141                     break;
    01142                 }
    01143             }
    01144         }
    01145
    01146         /* rb_raise(rb_eTypeError, "invalid typing scheme: %s given",
    01147          *         scheme);
    01148          */
    01149
    01150         if ( rb_respond_to( target_class, s_call ) )
    01151         {
    01152             obj = rb_funcall( target_class, s_call, 2, type, val );
    01153         }
    01154         else
    01155         {
    01156             if ( rb_respond_to( target_class, s_yaml_new ) )
    01157             {
    01158                 obj = rb_funcall( target_class, s_yaml_new, 3, subclass, type, val );
    01159             }
    01160             else if ( !NIL_P( target_class ) )
    01161             {
    01162                 if ( subclass == rb_cBignum )
    01163                 {
    01164                     obj = rb_str2inum( val, 10 ); /* for yaml dumped by 1.8.3 [ruby-core:6159] */
    01165                 }
    01166                 else
    01167                 {
    01168                     obj = rb_obj_alloc( subclass );
    01169                 }
    01170
    01171                 if ( rb_respond_to( obj, s_yaml_initialize ) )
    01172                 {
    01173                     rb_funcall( obj, s_yaml_initialize, 2, type, val );
    01174                 }
    01175                 else if ( !NIL_P( obj ) && rb_obj_is_instance_of( val, rb_cHash ) )
    01176                 {
    01177                     rb_block_call( val, s_each, 0, 0, syck_set_ivars, obj );
    01178                 }
    01179             }
    01180             else
    01181             {
    01182                 VALUE parts = rb_str_split( type, ":" );
    01183                 VALUE scheme = rb_ary_shift( parts );
    01184                 if ( rb_str_cmp( scheme, str_xprivate ) == 0 )
    01185                 {
    01186                     VALUE name = rb_ary_join( parts, colon );
    01187                     obj = rb_funcall( cPrivateType, s_new, 2, name, val );
    01188                 }
    01189                 else
    01190                 {
    01191                     VALUE domain = rb_ary_shift( parts );
    01192                     VALUE name = rb_ary_join( parts, colon );
    01193                     obj = rb_funcall( cDomainType, s_new, 3, domain, name, val );
    01194                 }
    01195             }
    01196         }
    01197         val = obj;
    01198     }
    01199
    01200     return val;
    01201 }
    01202
    01203 /*
    01204  * YAML::Syck::Resolver#tagurize
    01205  */
    01206 VALUE
    01207 syck_resolver_tagurize(VALUE self, VALUE val)
    01208 {
    01209     VALUE tmp = rb_check_string_type(val);
    01210
    01211     if ( !NIL_P(tmp) )
    01212     {
    01213         char *taguri = syck_type_id_to_uri( RSTRING_PTR(tmp) );
    01214         val = rb_str_new2( taguri );
    01215         S_FREE( taguri );
    01216     }
    01217
    01218     return val;
    01219 }
    01220
    01221 /*
    01222  * YAML::Syck::DefaultResolver#detect_implicit
    01223  */
    01224 VALUE
    01225 syck_defaultresolver_detect_implicit(VALUE self, VALUE val)
    01226 {
    01227     const char *type_id;
    01228     VALUE tmp = rb_check_string_type(val);
    01229
    01230     if ( !NIL_P(tmp) )
    01231     {
    01232         val = tmp;
    01233         type_id = syck_match_implicit( RSTRING_PTR(val), RSTRING_LEN(val) );
    01234         return rb_str_new2( type_id );
    01235     }
    01236
    01237     return rb_str_new2( "" );
    01238 }
    01239
    01240 /*
    01241  * YAML::Syck::DefaultResolver#node_import
    01242  */
    01243 VALUE
    01244 syck_defaultresolver_node_import(VALUE self, VALUE node)
    01245 {
    01246     SyckNode *n;
    01247     VALUE obj;
    01248     Data_Get_Struct( node, SyckNode, n );
    01249     if ( !yaml_org_handler( n, &obj ) )
    01250     {
    01251         obj = rb_funcall( self, s_transfer, 2, rb_str_new2( n->type_id ), obj );
    01252     }
    01253     return obj;
    01254 }
    01255
    01256 /*
    01257  * YAML::Syck::GenericResolver#node_import
    01258  */
    01259 VALUE
    01260 syck_genericresolver_node_import(VALUE self, VALUE node)
    01261 {
    01262     SyckNode *n;
    01263     int i = 0;
    01264     VALUE t = Qnil, obj = Qnil, v = Qnil, style = Qnil;
    01265     Data_Get_Struct(node, SyckNode, n);
    01266
    01267     if ( n->type_id != NULL )
    01268     {
    01269         t = rb_str_new2(n->type_id);
    01270     }
    01271
    01272     switch (n->kind)
    01273     {
    01274         case syck_str_kind:
    01275         {
    01276             v = rb_str_new( n->data.str->ptr, n->data.str->len );
    01277             rb_enc_associate(v, rb_utf8_encoding());
    01278             if ( n->data.str->style == scalar_1quote )
    01279             {
    01280                 style = sym_1quote;
    01281             }
    01282             else if ( n->data.str->style == scalar_2quote )
    01283             {
    01284                 style = sym_2quote;
    01285             }
    01286             else if ( n->data.str->style == scalar_fold )
    01287             {
    01288                 style = sym_fold;
    01289             }
    01290             else if ( n->data.str->style == scalar_literal )
    01291             {
    01292                 style = sym_literal;
    01293             }
    01294             else if ( n->data.str->style == scalar_plain )
    01295             {
    01296                 style = sym_plain;
    01297             }
    01298             obj = rb_funcall( cScalar, s_new, 3, t, v, style );
    01299         }
    01300         break;
    01301
    01302         case syck_seq_kind:
    01303             v = rb_ary_new2( syck_seq_count( n ) );
    01304             for ( i = 0; i < syck_seq_count( n ); i++ )
    01305             {
    01306                 rb_ary_store( v, i, syck_seq_read( n, i ) );
    01307             }
    01308             if ( n->data.list->style == seq_inline )
    01309             {
    01310                 style = sym_inline;
    01311             }
    01312             obj = rb_funcall( cSeq, s_new, 3, t, v, style );
    01313             rb_iv_set(obj, "@kind", sym_seq);
    01314         break;
    01315
    01316         case syck_map_kind:
    01317             v = rb_hash_new();
    01318             for ( i = 0; i < syck_map_count( n ); i++ )
    01319             {
    01320                 rb_hash_aset( v, syck_map_read( n, map_key, i ), syck_map_read( n, map_value, i ) );
    01321             }
    01322             if ( n->data.pairs->style == map_inline )
    01323             {
    01324                 style = sym_inline;
    01325             }
    01326             obj = rb_funcall( cMap, s_new, 3, t, v, style );
    01327             rb_iv_set(obj, "@kind", sym_map);
    01328         break;
    01329     }
    01330
    01331     return obj;
    01332 }
    01333
    01334 /*
    01335  * YAML::Syck::BadAlias.initialize
    01336  */
    01337 VALUE
    01338 syck_badalias_initialize(VALUE self, VALUE val)
    01339 {
    01340     rb_iv_set( self, "@name", val );
    01341     return self;
    01342 }
    01343
    01344 /*
    01345  * YAML::Syck::BadAlias.<=>
    01346  */
    01347 VALUE
    01348 syck_badalias_cmp(VALUE alias1, VALUE alias2)
    01349 {
    01350     VALUE str1 = rb_ivar_get( alias1, s_name );
    01351     VALUE str2 = rb_ivar_get( alias2, s_name );
    01352     VALUE val = rb_funcall( str1, s_cmp, 1, str2 );
    01353     return val;
    01354 }
    01355
    01356 /*
    01357  * YAML::DomainType.initialize
    01358  */
    01359 VALUE
    01360 syck_domaintype_initialize(VALUE self, VALUE domain, VALUE type_id, VALUE val)
    01361 {
    01362     rb_iv_set( self, "@domain", domain );
    01363     rb_iv_set( self, "@type_id", type_id );
    01364     rb_iv_set( self, "@value", val );
    01365     return self;
    01366 }
    01367
    01368 /*
    01369  * YAML::Object.initialize
    01370  */
    01371 VALUE
    01372 syck_yobject_initialize(VALUE self, VALUE klass, VALUE ivars)
    01373 {
    01374     rb_iv_set( self, "@class", klass );
    01375     rb_iv_set( self, "@ivars", ivars );
    01376     return self;
    01377 }
    01378
    01379 /*
    01380  * YAML::PrivateType.initialize
    01381  */
    01382 VALUE
    01383 syck_privatetype_initialize(VALUE self, VALUE type_id, VALUE val)
    01384 {
    01385     rb_iv_set( self, "@type_id", type_id );
    01386     rb_iv_set( self, "@value", val );
    01387     return self;
    01388 }
    01389
    01390 /*
    01391  * Mark node contents.
    01392  */
    01393 static void
    01394 syck_node_mark(SyckNode *n)
    01395 {
    01396     int i;
    01397     rb_gc_mark_maybe( n->id );
    01398     switch ( n->kind )
    01399     {
    01400         case syck_seq_kind:
    01401             for ( i = 0; i < n->data.list->idx; i++ )
    01402             {
    01403                 rb_gc_mark( syck_seq_read( n, i ) );
    01404             }
    01405         break;
    01406
    01407         case syck_map_kind:
    01408             for ( i = 0; i < n->data.pairs->idx; i++ )
    01409             {
    01410                 rb_gc_mark( syck_map_read( n, map_key, i ) );
    01411                 rb_gc_mark( syck_map_read( n, map_value, i ) );
    01412             }
    01413         break;
    01414
    01415         case syck_str_kind:
    01416         default:
    01417             /* nothing */
    01418         break;
    01419     }
    01420 #if 0 /* maybe needed */
    01421     if ( n->shortcut ) syck_node_mark( n->shortcut ); /* caution: maybe cyclic */
    01422 #endif
    01423 }
    01424
    01425 /*
    01426  * YAML::Syck::Scalar.allocate
    01427  */
    01428 VALUE
    01429 syck_scalar_alloc(VALUE class)
    01430 {
    01431     SyckNode *node = syck_alloc_str();
    01432     VALUE obj = Data_Wrap_Struct( class, syck_node_mark, syck_free_node, node );
    01433     node->id = obj;
    01434     return obj;
    01435 }
    01436
    01437 /*
    01438  * YAML::Syck::Scalar.initialize
    01439  */
    01440 VALUE
    01441 syck_scalar_initialize(VALUE self, VALUE type_id, VALUE val, VALUE style)
    01442 {
    01443     rb_iv_set( self, "@kind", sym_scalar );
    01444     rb_funcall( self, s_type_id_set, 1, type_id );
    01445     rb_funcall( self, s_value_set, 1, val );
    01446     rb_funcall( self, s_style_set, 1, style );
    01447     return self;
    01448 }
    01449
    01450 /*
    01451  * YAML::Syck::Scalar.style=
    01452  */
    01453 VALUE
    01454 syck_scalar_style_set(VALUE self, VALUE style)
    01455 {
    01456     SyckNode *node;
    01457     Data_Get_Struct( self, SyckNode, node );
    01458
    01459     if ( NIL_P( style ) )
    01460     {
    01461         node->data.str->style = scalar_none;
    01462     }
    01463     else if ( style == sym_1quote )
    01464     {
    01465         node->data.str->style = scalar_1quote;
    01466     }
    01467     else if ( style == sym_2quote )
    01468     {
    01469         node->data.str->style = scalar_2quote;
    01470     }
    01471     else if ( style == sym_fold )
    01472     {
    01473         node->data.str->style = scalar_fold;
    01474     }
    01475     else if ( style == sym_literal )
    01476     {
    01477         node->data.str->style = scalar_literal;
    01478     }
    01479     else if ( style == sym_plain )
    01480     {
    01481         node->data.str->style = scalar_plain;
    01482     }
    01483
    01484     rb_iv_set( self, "@style", style );
    01485     return self;
    01486 }
    01487
    01488 /*
    01489  * YAML::Syck::Scalar.value=
    01490  */
    01491 VALUE
    01492 syck_scalar_value_set(VALUE  self, VALUE val)
    01493 {
    01494     SyckNode *node;
    01495     Data_Get_Struct( self, SyckNode, node );
    01496
    01497     StringValue( val );
    01498     node->data.str->ptr = syck_strndup( RSTRING_PTR(val), RSTRING_LEN(val) );
    01499     node->data.str->len = RSTRING_LEN(val);
    01500     node->data.str->style = scalar_none;
    01501
    01502     rb_iv_set( self, "@value", val );
    01503     return val;
    01504 }
    01505
    01506 /*
    01507  * YAML::Syck::Seq.allocate
    01508  */
    01509 VALUE
    01510 syck_seq_alloc(VALUE class)
    01511 {
    01512     SyckNode *node;
    01513     VALUE obj;
    01514     node = syck_alloc_seq();
    01515     obj = Data_Wrap_Struct( class, syck_node_mark, syck_free_node, node );
    01516     node->id = obj;
    01517     return obj;
    01518 }
    01519
    01520 /*
    01521  * YAML::Syck::Seq.initialize
    01522  */
    01523 VALUE
    01524 syck_seq_initialize(VALUE self, VALUE type_id, VALUE val, VALUE style)
    01525 {
    01526     SyckNode *node;
    01527     Data_Get_Struct( self, SyckNode, node );
    01528
    01529     rb_iv_set( self, "@kind", sym_seq );
    01530     rb_funcall( self, s_type_id_set, 1, type_id );
    01531     rb_funcall( self, s_value_set, 1, val );
    01532     rb_funcall( self, s_style_set, 1, style );
    01533     return self;
    01534 }
    01535
    01536 /*
    01537  * YAML::Syck::Seq.value=
    01538  */
    01539 VALUE
    01540 syck_seq_value_set(VALUE self, VALUE val)
    01541 {
    01542     SyckNode *node;
    01543     Data_Get_Struct( self, SyckNode, node );
    01544
    01545     val = rb_check_array_type( val );
    01546     if ( !NIL_P( val ) ) {
    01547         int i;
    01548         syck_seq_empty( node );
    01549         for ( i = 0; i < RARRAY_LEN( val ); i++ )
    01550         {
    01551             syck_seq_add( node, rb_ary_entry(val, i) );
    01552         }
    01553     }
    01554
    01555     rb_iv_set( self, "@value", val );
    01556     return val;
    01557 }
    01558
    01559 /*
    01560  * YAML::Syck::Seq.add
    01561  */
    01562 VALUE
    01563 syck_seq_add_m(VALUE self, VALUE val)
    01564 {
    01565     SyckNode *node;
    01566     VALUE emitter = rb_ivar_get( self, s_emitter );
    01567     Data_Get_Struct( self, SyckNode, node );
    01568
    01569     if ( rb_respond_to( emitter, s_node_export ) ) {
    01570         val = rb_funcall( emitter, s_node_export, 1, val );
    01571     }
    01572     syck_seq_add( node, val );
    01573     rb_ary_push( rb_ivar_get( self, s_value ), val );
    01574
    01575     return self;
    01576 }
    01577
    01578 /*
    01579  * YAML::Syck::Seq.style=
    01580  */
    01581 VALUE
    01582 syck_seq_style_set(VALUE self, VALUE style)
    01583 {
    01584     SyckNode *node;
    01585     Data_Get_Struct( self, SyckNode, node );
    01586
    01587     if ( style == sym_inline )
    01588     {
    01589         node->data.list->style = seq_inline;
    01590     }
    01591     else
    01592     {
    01593         node->data.list->style = seq_none;
    01594     }
    01595
    01596     rb_iv_set( self, "@style", style );
    01597     return self;
    01598 }
    01599
    01600 /*
    01601  * YAML::Syck::Map.allocate
    01602  */
    01603 VALUE
    01604 syck_map_alloc(VALUE class)
    01605 {
    01606     SyckNode *node;
    01607     VALUE obj;
    01608     node = syck_alloc_map();
    01609     obj = Data_Wrap_Struct( class, syck_node_mark, syck_free_node, node );
    01610     node->id = obj;
    01611     return obj;
    01612 }
    01613
    01614 /*
    01615  * YAML::Syck::Map.initialize
    01616  */
    01617 VALUE
    01618 syck_map_initialize(VALUE self, VALUE type_id, VALUE val, VALUE style)
    01619 {
    01620     SyckNode *node;
    01621     Data_Get_Struct( self, SyckNode, node );
    01622
    01623     if ( !NIL_P( val ) )
    01624     {
    01625         VALUE hsh = rb_check_convert_type(val, T_HASH, "Hash", "to_hash");
    01626         VALUE keys;
    01627         int i;
    01628         if ( NIL_P(hsh) )
    01629         {
    01630             rb_raise( rb_eTypeError, "wrong argument type" );
    01631         }
    01632
    01633         keys = rb_funcall( hsh, s_keys, 0 );
    01634         for ( i = 0; i < RARRAY_LEN(keys); i++ )
    01635         {
    01636             VALUE key = rb_ary_entry(keys, i);
    01637             syck_map_add( node, key, rb_hash_aref(hsh, key) );
    01638         }
    01639     }
    01640
    01641     rb_iv_set( self, "@kind", sym_seq );
    01642     rb_funcall( self, s_type_id_set, 1, type_id );
    01643     rb_funcall( self, s_value_set, 1, val );
    01644     rb_funcall( self, s_style_set, 1, style );
    01645     return self;
    01646 }
    01647
    01648 /*
    01649  * YAML::Syck::Map.value=
    01650  */
    01651 VALUE
    01652 syck_map_value_set(VALUE self, VALUE val)
    01653 {
    01654     SyckNode *node;
    01655     Data_Get_Struct( self, SyckNode, node );
    01656
    01657     if ( !NIL_P( val ) )
    01658     {
    01659         VALUE hsh = rb_check_convert_type(val, T_HASH, "Hash", "to_hash");
    01660         VALUE keys;
    01661         int i;
    01662         if ( NIL_P(hsh) )
    01663         {
    01664             rb_raise( rb_eTypeError, "wrong argument type" );
    01665         }
    01666
    01667         syck_map_empty( node );
    01668         keys = rb_funcall( hsh, s_keys, 0 );
    01669         for ( i = 0; i < RARRAY_LEN(keys); i++ )
    01670         {
    01671             VALUE key = rb_ary_entry(keys, i);
    01672             syck_map_add( node, key, rb_hash_aref(hsh, key) );
    01673         }
    01674     }
    01675
    01676     rb_iv_set( self, "@value", val );
    01677     return val;
    01678 }
    01679
    01680 /*
    01681  * YAML::Syck::Map.add
    01682  */
    01683 VALUE
    01684 syck_map_add_m(VALUE self, VALUE key, VALUE val)
    01685 {
    01686     SyckNode *node;
    01687     VALUE emitter = rb_ivar_get( self, s_emitter );
    01688     Data_Get_Struct( self, SyckNode, node );
    01689
    01690     if ( rb_respond_to( emitter, s_node_export ) ) {
    01691         key = rb_funcall( emitter, s_node_export, 1, key );
    01692         val = rb_funcall( emitter, s_node_export, 1, val );
    01693     }
    01694     syck_map_add( node, key, val );
    01695     rb_hash_aset( rb_ivar_get( self, s_value ), key, val );
    01696
    01697     return self;
    01698 }
    01699
    01700 /*
    01701  * YAML::Syck::Map.style=
    01702  */
    01703 VALUE
    01704 syck_map_style_set(VALUE self, VALUE style)
    01705 {
    01706     SyckNode *node;
    01707     Data_Get_Struct( self, SyckNode, node );
    01708
    01709     if ( style == sym_inline )
    01710     {
    01711         node->data.pairs->style = map_inline;
    01712     }
    01713     else
    01714     {
    01715         node->data.pairs->style = map_none;
    01716     }
    01717
    01718     rb_iv_set( self, "@style", style );
    01719     return self;
    01720 }
    01721
    01722 /*
    01723  * Cloning method for all node types
    01724  */
    01725 VALUE
    01726 syck_node_init_copy(VALUE copy, VALUE orig)
    01727 {
    01728     SyckNode *copy_n;
    01729     SyckNode *orig_n;
    01730
    01731     if ( copy == orig )
    01732         return copy;
    01733
    01734     if ( TYPE( orig ) != T_DATA )
    01735     {
    01736         rb_raise( rb_eTypeError, "wrong argument type" );
    01737     }
    01738
    01739     Data_Get_Struct( orig, SyckNode, orig_n );
    01740     Data_Get_Struct( copy, SyckNode, copy_n );
    01741     MEMCPY( copy_n, orig_n, SyckNode, 1 );
    01742     return copy;
    01743 }
    01744
    01745 /*
    01746  * YAML::Syck::Node#type_id=
    01747  */
    01748 VALUE
    01749 syck_node_type_id_set(VALUE self, VALUE type_id)
    01750 {
    01751     SyckNode *node;
    01752     Data_Get_Struct( self, SyckNode, node );
    01753
    01754     S_FREE( node->type_id );
    01755
    01756     if ( !NIL_P( type_id ) ) {
    01757         StringValue( type_id );
    01758         node->type_id = syck_strndup( RSTRING_PTR(type_id), RSTRING_LEN(type_id) );
    01759     }
    01760
    01761     rb_iv_set( self, "@type_id", type_id );
    01762     return type_id;
    01763 }
    01764
    01765 /*
    01766  * YAML::Syck::Node.transform
    01767  */
    01768 VALUE
    01769 syck_node_transform(VALUE self)
    01770 {
    01771     VALUE t;
    01772     SyckNode *n = NULL;
    01773     SyckNode *orig_n;
    01774     Data_Get_Struct(self, SyckNode, orig_n);
    01775     t = Data_Wrap_Struct( cNode, syck_node_mark, syck_free_node, 0 );
    01776
    01777     switch (orig_n->kind)
    01778     {
    01779         case syck_map_kind:
    01780             {
    01781                 int i;
    01782                 DATA_PTR(t) = n = syck_alloc_map();
    01783                 for ( i = 0; i < orig_n->data.pairs->idx; i++ )
    01784                 {
    01785                     syck_map_add( n, rb_funcall( syck_map_read( orig_n, map_key, i ), s_transform, 0 ),
    01786                                      rb_funcall( syck_map_read( orig_n, map_value, i ), s_transform, 0 ) );
    01787                 }
    01788             }
    01789         break;
    01790
    01791         case syck_seq_kind:
    01792             {
    01793                 int i;
    01794                 DATA_PTR(t) = n = syck_alloc_seq();
    01795                 for ( i = 0; i < orig_n->data.list->idx; i++ )
    01796                 {
    01797                     syck_seq_add( n, rb_funcall( syck_seq_read( orig_n, i ), s_transform, 0 ) );
    01798                 }
    01799             }
    01800         break;
    01801
    01802         case syck_str_kind:
    01803             DATA_PTR(t) = n = syck_new_str2( orig_n->data.str->ptr, orig_n->data.str->len, orig_n->data.str->style );
    01804         break;
    01805     }
    01806
    01807     if ( orig_n->type_id != NULL )
    01808     {
    01809         n->type_id = syck_strndup( orig_n->type_id, strlen( orig_n->type_id ) );
    01810     }
    01811     if ( orig_n->anchor != NULL )
    01812     {
    01813         n->anchor = syck_strndup( orig_n->anchor, strlen( orig_n->anchor ) );
    01814     }
    01815     n->id = t;
    01816     return rb_funcall( oDefaultResolver, s_node_import, 1, t );
    01817 }
    01818
    01819 /*
    01820  * Emitter callback: assembles YAML document events from
    01821  * Ruby symbols.  This is a brilliant way to do it.
    01822  * No one could possibly object.
    01823  */
    01824 void
    01825 rb_syck_emitter_handler(SyckEmitter *e, st_data_t data)
    01826 {
    01827     SyckNode *n;
    01828     Data_Get_Struct((VALUE)data, SyckNode, n);
    01829
    01830     switch (n->kind)
    01831     {
    01832         case syck_map_kind:
    01833             {
    01834                 int i;
    01835                 syck_emit_map( e, n->type_id, n->data.pairs->style );
    01836                 for ( i = 0; i < n->data.pairs->idx; i++ )
    01837                 {
    01838                     syck_emit_item( e, syck_map_read( n, map_key, i ) );
    01839                     syck_emit_item( e, syck_map_read( n, map_value, i ) );
    01840                 }
    01841                 syck_emit_end( e );
    01842             }
    01843         break;
    01844
    01845         case syck_seq_kind:
    01846             {
    01847                 int i;
    01848                 syck_emit_seq( e, n->type_id, n->data.list->style );
    01849                 for ( i = 0; i < n->data.list->idx; i++ )
    01850                 {
    01851                     syck_emit_item( e, syck_seq_read( n, i ) );
    01852                 }
    01853                 syck_emit_end( e );
    01854             }
    01855         break;
    01856
    01857         case syck_str_kind:
    01858             {
    01859                 syck_emit_scalar( e, n->type_id, n->data.str->style, 0, 0, 0, n->data.str->ptr, n->data.str->len );
    01860             }
    01861         break;
    01862     }
    01863 }
    01864
    01865 /*
    01866  * Handle output from the emitter
    01867  */
    01868 void
    01869 rb_syck_output_handler(SyckEmitter * emitter, char *str, long len)
    01870 {
    01871     struct emitter_xtra *bonus = (struct emitter_xtra *)emitter->bonus;
    01872     VALUE dest = bonus->port;
    01873     if (TYPE(dest) == T_STRING) {
    01874         rb_str_cat( dest, str, len );
    01875     } else {
    01876         rb_io_write( dest, rb_str_new( str, len ) );
    01877     }
    01878 }
    01879
    01880 /*
    01881  * Helper function for marking nodes in the anchor
    01882  * symbol table.
    01883  */
    01884 void
    01885 syck_out_mark(VALUE emitter, VALUE node)
    01886 {
    01887     SyckEmitter *emitterPtr;
    01888     struct emitter_xtra *bonus;
    01889     Data_Get_Struct(emitter, SyckEmitter, emitterPtr);
    01890     bonus = (struct emitter_xtra *)emitterPtr->bonus;
    01891     rb_ivar_set( node, s_emitter, emitter );
    01892     /* syck_emitter_mark_node( emitterPtr, (st_data_t)node ); */
    01893     if ( !NIL_P( bonus->oid ) ) {
    01894         rb_hash_aset( bonus->data, bonus->oid, node );
    01895     }
    01896 }
    01897
    01898 /*
    01899  * Mark emitter values.
    01900  */
    01901 static void
    01902 syck_mark_emitter(SyckEmitter *emitter)
    01903 {
    01904     struct emitter_xtra *bonus = (struct emitter_xtra *)emitter->bonus;
    01905     rb_gc_mark( bonus->oid  );
    01906     rb_gc_mark( bonus->data );
    01907     rb_gc_mark( bonus->port );
    01908 }
    01909
    01910 /*
    01911  * Free the emitter and any bonus attachment.
    01912  */
    01913 void
    01914 rb_syck_free_emitter(SyckEmitter *e)
    01915 {
    01916     S_FREE( e->bonus );
    01917     syck_free_emitter(e);
    01918 }
    01919
    01920 /*
    01921  * YAML::Syck::Emitter.allocate
    01922  */
    01923 VALUE syck_emitter_s_alloc _((VALUE));
    01924 VALUE
    01925 syck_emitter_s_alloc(VALUE class)
    01926 {
    01927     VALUE pobj;
    01928     SyckEmitter *emitter = syck_new_emitter();
    01929
    01930     emitter->bonus = S_ALLOC( struct emitter_xtra );
    01931     S_MEMZERO( emitter->bonus, struct emitter_xtra, 1 );
    01932
    01933     pobj = Data_Wrap_Struct( class, syck_mark_emitter, rb_syck_free_emitter, emitter );
    01934     syck_emitter_handler( emitter, rb_syck_emitter_handler );
    01935     syck_output_handler( emitter, rb_syck_output_handler );
    01936
    01937     rb_ivar_set( pobj, s_out, rb_funcall( cOut, s_new, 1, pobj ) );
    01938     return pobj;
    01939 }
    01940
    01941 static VALUE
    01942 id_hash_new(void)
    01943 {
    01944     VALUE hash;
    01945     hash = rb_hash_new();
    01946     rb_funcall(hash, rb_intern("compare_by_identity"), 0);
    01947     return hash;
    01948 }
    01949
    01950 /*
    01951  * YAML::Syck::Emitter.reset( options )
    01952  */
    01953 VALUE
    01954 syck_emitter_reset(int argc, VALUE *argv, VALUE self)
    01955 {
    01956     VALUE options, tmp;
    01957     SyckEmitter *emitter;
    01958     struct emitter_xtra *bonus;
    01959
    01960     Data_Get_Struct(self, SyckEmitter, emitter);
    01961     bonus = (struct emitter_xtra *)emitter->bonus;
    01962
    01963     bonus->oid = Qnil;
    01964     bonus->port = rb_str_new2( "" );
    01965     bonus->data = id_hash_new();
    01966
    01967     if (rb_scan_args(argc, argv, "01", &options) == 0)
    01968     {
    01969         options = rb_hash_new();
    01970         rb_ivar_set(self, s_options, options);
    01971     }
    01972     else if ( !NIL_P(tmp = rb_check_string_type(options)) )
    01973     {
    01974         bonus->port = tmp;
    01975     }
    01976     else if ( rb_respond_to( options, s_write ) )
    01977     {
    01978         bonus->port = options;
    01979     }
    01980     else
    01981     {
    01982         Check_Type(options, T_HASH);
    01983         rb_ivar_set(self, s_options, options);
    01984     }
    01985
    01986     emitter->headless = 0;
    01987     rb_ivar_set(self, s_level, INT2FIX(0));
    01988     rb_ivar_set(self, s_resolver, Qnil);
    01989     return self;
    01990 }
    01991
    01992 /*
    01993  * YAML::Syck::Emitter.emit( object_id ) { |out| ... }
    01994  */
    01995 VALUE
    01996 syck_emitter_emit(int argc, VALUE *argv, VALUE self)
    01997 {
    01998     VALUE oid, proc;
    01999     SyckEmitter *emitter;
    02000     struct emitter_xtra *bonus;
    02001     SYMID symple;
    02002     int level = FIX2INT(rb_ivar_get(self, s_level)) + 1;
    02003     rb_ivar_set(self, s_level, INT2FIX(level));
    02004
    02005     rb_scan_args(argc, argv, "1&", &oid, &proc);
    02006     Data_Get_Struct(self, SyckEmitter, emitter);
    02007     bonus = (struct emitter_xtra *)emitter->bonus;
    02008
    02009     /* Calculate anchors, normalize nodes, build a simpler symbol table */
    02010     bonus->oid = oid;
    02011     if ( !NIL_P( oid ) && RTEST( rb_funcall( bonus->data, s_haskey, 1, oid ) ) ) {
    02012         symple = rb_hash_aref( bonus->data, oid );
    02013     } else {
    02014         symple = rb_funcall( proc, s_call, 1, rb_ivar_get( self, s_out ) );
    02015     }
    02016     syck_emitter_mark_node( emitter, (st_data_t)symple );
    02017
    02018     /* Second pass, build emitted string */
    02019     level -= 1;
    02020     rb_ivar_set(self, s_level, INT2FIX(level));
    02021     if ( level == 0 )
    02022     {
    02023         syck_emit(emitter, (st_data_t)symple);
    02024         syck_emitter_flush(emitter, 0);
    02025
    02026         return bonus->port;
    02027     }
    02028
    02029     return symple;
    02030 }
    02031
    02032 /*
    02033  * YAML::Syck::Emitter#node_export
    02034  */
    02035 VALUE
    02036 syck_emitter_node_export(VALUE self, VALUE node)
    02037 {
    02038     return rb_funcall( node, s_to_yaml, 1, self );
    02039 }
    02040
    02041 /*
    02042  * YAML::Syck::Emitter#set_resolver
    02043  */
    02044 VALUE
    02045 syck_emitter_set_resolver(VALUE self, VALUE resolver)
    02046 {
    02047     rb_ivar_set( self, s_resolver, resolver );
    02048     return self;
    02049 }
    02050
    02051 /*
    02052  * YAML::Syck::Out::initialize
    02053  */
    02054 VALUE
    02055 syck_out_initialize(VALUE self, VALUE emitter)
    02056 {
    02057     rb_ivar_set( self, s_emitter, emitter );
    02058     return self;
    02059 }
    02060
    02061 /*
    02062  * YAML::Syck::Out::map
    02063  */
    02064 VALUE
    02065 syck_out_map(int argc, VALUE *argv, VALUE self)
    02066 {
    02067     VALUE type_id, style, map;
    02068     if (rb_scan_args(argc, argv, "11", &type_id, &style) == 1) {
    02069         style = Qnil;
    02070     }
    02071     map = rb_funcall( cMap, s_new, 3, type_id, rb_hash_new(), style );
    02072     syck_out_mark( rb_ivar_get( self, s_emitter ), map );
    02073     rb_yield( map );
    02074     return map;
    02075 }
    02076
    02077 /*
    02078  * YAML::Syck::Out::seq
    02079  */
    02080 VALUE
    02081 syck_out_seq(int argc, VALUE *argv, VALUE self)
    02082 {
    02083     VALUE type_id, style, seq;
    02084     if (rb_scan_args(argc, argv, "11", &type_id, &style) == 1) {
    02085         style = Qnil;
    02086     }
    02087     seq = rb_funcall( cSeq, s_new, 3, type_id, rb_ary_new(), style );
    02088     syck_out_mark( rb_ivar_get( self, s_emitter ), seq );
    02089     rb_yield( seq );
    02090     return seq;
    02091 }
    02092
    02093 /*
    02094  * YAML::Syck::Out::scalar
    02095 syck_out_scalar( self, type_id, str, style )
    02096     VALUE self, type_id, str, style;
    02097  */
    02098 VALUE
    02099 syck_out_scalar(int argc, VALUE *argv, VALUE self)
    02100 {
    02101     VALUE type_id, str, style, scalar;
    02102     rb_scan_args(argc, argv, "21", &type_id, &str, &style);
    02103     scalar = rb_funcall( cScalar, s_new, 3, type_id, str, style );
    02104     syck_out_mark( rb_ivar_get( self, s_emitter ), scalar );
    02105     return scalar;
    02106 }
    02107
    02108 /*
    02109  * Initialize Syck extension
    02110  */
    02111 void
    02112 Init_syck()
    02113 {
    02114     VALUE rb_syck = rb_define_module_under( rb_cObject, "Syck" );
    02115     rb_define_module_function( rb_syck, "compile", rb_syck_compile, 1 );
    02116
    02117     /*
    02118      * Global symbols
    02119      */
    02120     s_new = rb_intern("new");
    02121     s_utc = rb_intern("utc");
    02122     s_at = rb_intern("at");
    02123     s_to_f = rb_intern("to_f");
    02124     s_to_i = rb_intern("to_i");
    02125     s_read = rb_intern("read");
    02126     s_binmode = rb_intern("binmode");
    02127     s_transfer = rb_intern("transfer");
    02128     s_call = rb_intern("call");
    02129     s_cmp = rb_intern("<=>");
    02130     s_intern = rb_intern("intern");
    02131     s_update = rb_intern("update");
    02132     s_detect_implicit = rb_intern("detect_implicit");
    02133     s_dup = rb_intern("dup");
    02134     s_default_set = rb_intern("default=");
    02135     s_match = rb_intern("match");
    02136     s_push = rb_intern("push");
    02137     s_haskey = rb_intern("has_key?");
    02138     s_keys = rb_intern("keys");
    02139     s_node_import = rb_intern("node_import");
    02140     s_tr_bang = rb_intern("tr!");
    02141     s_unpack = rb_intern("unpack");
    02142     s_write = rb_intern("write");
    02143     s_tag_read_class = rb_intern( "yaml_tag_read_class" );
    02144     s_tag_subclasses = rb_intern( "yaml_tag_subclasses?" );
    02145     s_emitter = rb_intern( "emitter" );
    02146     s_set_resolver = rb_intern( "set_resolver" );
    02147     s_node_export = rb_intern( "node_export" );
    02148     s_to_yaml = rb_intern( "to_yaml" );
    02149     s_transform = rb_intern( "transform" );
    02150     s_yaml_new = rb_intern("yaml_new");
    02151     s_yaml_initialize = rb_intern("yaml_initialize");
    02152     s_each = rb_intern("each");
    02153     s_parse = rb_intern("parse");
    02154
    02155     s_tags = rb_intern("@tags");
    02156     s_name = rb_intern("@name");
    02157     s_options = rb_intern("@options");
    02158     s_kind = rb_intern("@kind");
    02159     s_type_id = rb_intern("@type_id");
    02160     s_type_id_set = rb_intern("type_id=");
    02161     s_resolver = rb_intern("@resolver");
    02162     s_level = rb_intern( "@level" );
    02163     s_style = rb_intern("@style");
    02164     s_style_set = rb_intern("style=");
    02165     s_value = rb_intern("@value");
    02166     s_value_set = rb_intern("value=");
    02167     s_out = rb_intern("@out");
    02168     s_input = rb_intern("@input");
    02169
    02170     sym_model = ID2SYM(rb_intern("Model"));
    02171     sym_generic = ID2SYM(rb_intern("Generic"));
    02172     sym_bytecode = ID2SYM(rb_intern("bytecode"));
    02173     sym_map = ID2SYM(rb_intern("map"));
    02174     sym_scalar = ID2SYM(rb_intern("scalar"));
    02175     sym_seq = ID2SYM(rb_intern("seq"));
    02176     sym_1quote = ID2SYM(rb_intern("quote1"));
    02177     sym_2quote = ID2SYM(rb_intern("quote2"));
    02178     sym_fold = ID2SYM(rb_intern("fold"));
    02179     sym_literal = ID2SYM(rb_intern("literal"));
    02180     sym_plain = ID2SYM(rb_intern("plain"));
    02181     sym_inline = ID2SYM(rb_intern("inline"));
    02182
    02183     /*
    02184      * Define YAML::Syck::Resolver class
    02185      */
    02186     cResolver = rb_define_class_under( rb_syck, "Resolver", rb_cObject );
    02187     rb_define_attr( cResolver, "tags", 1, 1 );
    02188     rb_define_method( cResolver, "initialize", syck_resolver_initialize, 0 );
    02189     rb_define_method( cResolver, "add_type", syck_resolver_add_type, 2 );
    02190     rb_define_method( cResolver, "use_types_at", syck_resolver_use_types_at, 1 );
    02191     rb_define_method( cResolver, "detect_implicit", syck_resolver_detect_implicit, 1 );
    02192     rb_define_method( cResolver, "transfer", syck_resolver_transfer, 2 );
    02193     rb_define_method( cResolver, "node_import", syck_resolver_node_import, 1 );
    02194     rb_define_method( cResolver, "tagurize", syck_resolver_tagurize, 1 );
    02195
    02196     rb_global_variable( &oDefaultResolver );
    02197     oDefaultResolver = rb_funcall( cResolver, rb_intern( "new" ), 0 );
    02198     rb_define_singleton_method( oDefaultResolver, "node_import", syck_defaultresolver_node_import, 1 );
    02199     rb_define_singleton_method( oDefaultResolver, "detect_implicit", syck_defaultresolver_detect_implicit, 1 );
    02200     rb_define_const( rb_syck, "DefaultResolver", oDefaultResolver );
    02201     rb_global_variable( &oGenericResolver );
    02202     oGenericResolver = rb_funcall( cResolver, rb_intern( "new" ), 0 );
    02203     rb_define_singleton_method( oGenericResolver, "node_import", syck_genericresolver_node_import, 1 );
    02204     rb_define_const( rb_syck, "GenericResolver", oGenericResolver );
    02205
    02206     /*
    02207      * Define YAML::Syck::Parser class
    02208      */
    02209     cParser = rb_define_class_under( rb_syck, "Parser", rb_cObject );
    02210     rb_define_attr( cParser, "options", 1, 1 );
    02211     rb_define_attr( cParser, "resolver", 1, 1 );
    02212     rb_define_attr( cParser, "input", 1, 1 );
    02213     rb_define_alloc_func( cParser, syck_parser_s_alloc );
    02214     rb_define_method(cParser, "initialize", syck_parser_initialize, -1 );
    02215     rb_define_method(cParser, "bufsize=", syck_parser_bufsize_set, 1 );
    02216     rb_define_method(cParser, "bufsize", syck_parser_bufsize_get, 0 );
    02217     rb_define_method(cParser, "load", syck_parser_load, -1);
    02218     rb_define_method(cParser, "load_documents", syck_parser_load_documents, -1);
    02219     rb_define_method(cParser, "set_resolver", syck_parser_set_resolver, 1);
    02220
    02221     /*
    02222      * Define YAML::Syck::Node class
    02223      */
    02224     cNode = rb_define_class_under( rb_syck, "Node", rb_cObject );
    02225     rb_define_method( cNode, "initialize_copy", syck_node_init_copy, 1 );
    02226     rb_define_attr( cNode, "emitter", 1, 1 );
    02227     rb_define_attr( cNode, "resolver", 1, 1 );
    02228     rb_define_attr( cNode, "kind", 1, 0 );
    02229     rb_define_attr( cNode, "type_id", 1, 0 );
    02230     rb_define_attr( cNode, "value", 1, 0 );
    02231     rb_define_method( cNode, "type_id=", syck_node_type_id_set, 1 );
    02232     rb_define_method( cNode, "transform", syck_node_transform, 0);
    02233
    02234     /*
    02235      * Define YAML::Syck::Scalar, YAML::Syck::Seq, YAML::Syck::Map --
    02236      *     all are the publicly usable variants of YAML::Syck::Node
    02237      */
    02238     cScalar = rb_define_class_under( rb_syck, "Scalar", cNode );
    02239     rb_define_alloc_func( cScalar, syck_scalar_alloc );
    02240     rb_define_method( cScalar, "initialize", syck_scalar_initialize, 3 );
    02241     rb_define_method( cScalar, "value=", syck_scalar_value_set, 1 );
    02242     rb_define_method( cScalar, "style=", syck_scalar_style_set, 1 );
    02243     cSeq = rb_define_class_under( rb_syck, "Seq", cNode );
    02244     rb_define_alloc_func( cSeq, syck_seq_alloc );
    02245     rb_define_method( cSeq, "initialize", syck_seq_initialize, 3 );
    02246     rb_define_method( cSeq, "value=", syck_seq_value_set, 1 );
    02247     rb_define_method( cSeq, "add", syck_seq_add_m, 1 );
    02248     rb_define_method( cSeq, "style=", syck_seq_style_set, 1 );
    02249     cMap = rb_define_class_under( rb_syck, "Map", cNode );
    02250     rb_define_alloc_func( cMap, syck_map_alloc );
    02251     rb_define_method( cMap, "initialize", syck_map_initialize, 3 );
    02252     rb_define_method( cMap, "value=", syck_map_value_set, 1 );
    02253     rb_define_method( cMap, "add", syck_map_add_m, 2 );
    02254     rb_define_method( cMap, "style=", syck_map_style_set, 1 );
    02255
    02256     /*
    02257      * Define YAML::PrivateType class
    02258      */
    02259     cPrivateType = rb_define_class_under( rb_syck, "PrivateType", rb_cObject );
    02260     rb_define_attr( cPrivateType, "type_id", 1, 1 );
    02261     rb_define_attr( cPrivateType, "value", 1, 1 );
    02262     rb_define_method( cPrivateType, "initialize", syck_privatetype_initialize, 2);
    02263
    02264     /*
    02265      * Define YAML::DomainType class
    02266      */
    02267     cDomainType = rb_define_class_under( rb_syck, "DomainType", rb_cObject );
    02268     rb_define_attr( cDomainType, "domain", 1, 1 );
    02269     rb_define_attr( cDomainType, "type_id", 1, 1 );
    02270     rb_define_attr( cDomainType, "value", 1, 1 );
    02271     rb_define_method( cDomainType, "initialize", syck_domaintype_initialize, 3);
    02272
    02273     /*
    02274      * Define YAML::Object class
    02275      */
    02276     cYObject = rb_define_class_under( rb_syck, "Object", rb_cObject );
    02277     rb_define_attr( cYObject, "class", 1, 1 );
    02278     rb_define_attr( cYObject, "ivars", 1, 1 );
    02279     rb_define_method( cYObject, "initialize", syck_yobject_initialize, 2);
    02280     rb_define_method( cYObject, "yaml_initialize", syck_yobject_initialize, 2);
    02281
    02282     /*
    02283      * Define YAML::Syck::BadAlias class
    02284      */
    02285     cBadAlias = rb_define_class_under( rb_syck, "BadAlias", rb_cObject );
    02286     rb_define_attr( cBadAlias, "name", 1, 1 );
    02287     rb_define_method( cBadAlias, "initialize", syck_badalias_initialize, 1);
    02288     rb_define_method( cBadAlias, "<=>", syck_badalias_cmp, 1);
    02289     rb_include_module( cBadAlias, rb_const_get( rb_cObject, rb_intern("Comparable") ) );
    02290
    02291     /*
    02292      * Define YAML::Syck::MergeKey class
    02293      */
    02294     cMergeKey = rb_define_class_under( rb_syck, "MergeKey", rb_cObject );
    02295
    02296     /*
    02297      * Define YAML::Syck::DefaultKey class
    02298      */
    02299     cDefaultKey = rb_define_class_under( rb_syck, "DefaultKey", rb_cObject );
    02300
    02301     /*
    02302      * Define YAML::Syck::Out classes
    02303      */
    02304     cOut = rb_define_class_under( rb_syck, "Out", rb_cObject );
    02305     rb_define_attr( cOut, "emitter", 1, 1 );
    02306     rb_define_method( cOut, "initialize", syck_out_initialize, 1 );
    02307     rb_define_method( cOut, "map", syck_out_map, -1 );
    02308     rb_define_method( cOut, "seq", syck_out_seq, -1 );
    02309     rb_define_method( cOut, "scalar", syck_out_scalar, -1 );
    02310
    02311     /*
    02312      * Define YAML::Syck::Emitter class
    02313      */
    02314     cEmitter = rb_define_class_under( rb_syck, "Emitter", rb_cObject );
    02315     rb_define_attr( cEmitter, "level", 1, 1 );
    02316     rb_define_alloc_func( cEmitter, syck_emitter_s_alloc );
    02317     rb_define_method( cEmitter, "initialize", syck_emitter_reset, -1 );
    02318     rb_define_method( cEmitter, "reset", syck_emitter_reset, -1 );
    02319     rb_define_method( cEmitter, "emit", syck_emitter_emit, -1 );
    02320     rb_define_method( cEmitter, "set_resolver", syck_emitter_set_resolver, 1);
    02321     rb_define_method( cEmitter, "node_export", syck_emitter_node_export, 1);
    02322 }
    02323
    02324