ext/syck/rubyext.c

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

Generated on Wed Aug 10 09:17:05 2011 for Ruby by  doxygen 1.4.7