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

Generated on Thu Sep 8 2011 03:50:39 for Ruby by  doxygen 1.7.1