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