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