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