|
Ruby 1.9.2p180(2011-02-18revision30909)
|
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
1.7.3