1 /* -*- indent-tabs-mode: nil -*- */
2 /*
3 * rubyext.c
4 *
5 * $Author$
6 * $Date$
7 *
8 * Copyright (C) 2003-2005 why the lucky stiff
9 */
10
11 #include "ruby.h"
12 #include "syck.h"
13 #include <sys/types.h>
14 #include <time.h>
15
16 typedef struct RVALUE {
17 union {
18 #if 0
19 struct {
20 unsigned long flags; /* always 0 for freed obj */
21 struct RVALUE *next;
22 } free;
23 #endif
24 struct RBasic basic;
25 struct RObject object;
26 struct RClass klass;
27 /*struct RFloat flonum;*/
28 /*struct RString string;*/
29 struct RArray array;
30 /*struct RRegexp regexp;*/
31 struct RHash hash;
32 /*struct RData data;*/
33 struct RStruct rstruct;
34 /*struct RBignum bignum;*/
35 /*struct RFile file;*/
36 } as;
37 } RVALUE;
38
39 typedef struct {
40 long hash;
41 char *buffer;
42 long length;
43 long remaining;
44 int printed;
45 } bytestring_t;
46
47 #define RUBY_DOMAIN "ruby.yaml.org,2002"
48
49 #ifndef StringValue
50 #define StringValue(v) (v)
51 #endif
52 #ifndef rb_attr_get
53 #define rb_attr_get(o, i) rb_ivar_get(o, i)
54 #endif
55
56 #ifdef RARRAY_LEN
57 #undef T_SYMBOL
58 #define T_SYMBOL T_STRING
rb_str_len(VALUE s)59 static inline long rb_str_len(VALUE s) {return RSTRING_LEN(s);}
rb_str_ptr(VALUE s)60 static inline char *rb_str_ptr(VALUE s) {return RSTRING_PTR(s);}
rb_ary_len(VALUE s)61 static inline long rb_ary_len(VALUE s) {return RARRAY_LEN(s);}
rb_ary_ptr(VALUE s)62 static inline VALUE *rb_ary_ptr(VALUE s) {return RARRAY_PTR(s);}
63 #else
rb_str_len(VALUE s)64 static inline long rb_str_len(VALUE s) {return rb_str_len(s);}
rb_str_ptr(VALUE s)65 static inline char *rb_str_ptr(VALUE s) {return rb_str_ptr(s);}
rb_ary_len(VALUE s)66 static inline long rb_ary_len(VALUE s) {return rb_ary_len(s);}
rb_ary_ptr(VALUE s)67 static inline VALUE *rb_ary_ptr(VALUE s) {return rb_ary_ptr(s);}
68 #endif
69
70 /*
71 * symbols and constants
72 */
73 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;
74 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;
75 static VALUE sym_model, sym_generic, sym_input, sym_bytecode;
76 static VALUE sym_scalar, sym_seq, sym_map;
77 static VALUE sym_1quote, sym_2quote, sym_fold, sym_literal, sym_plain, sym_inline;
78 static VALUE cDate, cNode, cMap, cSeq, cScalar, cOut, cParser, cResolver, cPrivateType, cDomainType, cYObject, cBadAlias, cDefaultKey, cMergeKey, cEmitter;
79 static VALUE oDefaultResolver, oGenericResolver;
80
81 /*
82 * my private collection of numerical oddities.
83 */
S_zero()84 static double S_zero() { return 0.0; }
S_one()85 static double S_one() { return 1.0; }
S_inf()86 static double S_inf() { return S_one() / S_zero(); }
S_nan()87 static double S_nan() { return S_zero() / S_zero(); }
88
89 static VALUE syck_node_transform( VALUE );
90
91 /*
92 * handler prototypes
93 */
94 SYMID rb_syck_load_handler _((SyckParser *, SyckNode *));
95 void rb_syck_err_handler _((SyckParser *, char *));
96 SyckNode * rb_syck_bad_anchor_handler _((SyckParser *, char *));
97 void rb_syck_output_handler _((SyckEmitter *, char *, long));
98 void rb_syck_emitter_handler _((SyckEmitter *, st_data_t));
99 int syck_parser_assign_io _((SyckParser *, VALUE *));
100 VALUE syck_scalar_alloc _((VALUE class));
101 VALUE syck_seq_alloc _((VALUE class));
102 VALUE syck_map_alloc _((VALUE class));
103
104 struct parser_xtra {
105 VALUE data; /* Borrowed this idea from marshal.c to fix [ruby-core:8067] problem */
106 VALUE proc;
107 VALUE resolver;
108 int taint;
109 };
110
111 struct emitter_xtra {
112 VALUE oid;
113 VALUE data;
114 VALUE port;
115 };
116
117 /*
118 * Convert YAML to bytecode
119 */
120 VALUE
rb_syck_compile(VALUE self,VALUE port)121 rb_syck_compile(VALUE self, VALUE port)
122 {
123 SYMID oid;
124 int taint;
125 char *ret;
126 VALUE bc;
127 bytestring_t *sav;
128
129 SyckParser *parser = syck_new_parser();
130 taint = syck_parser_assign_io(parser, &port);
131 syck_parser_handler( parser, syck_yaml2byte_handler );
132 syck_parser_error_handler( parser, NULL );
133 syck_parser_implicit_typing( parser, 0 );
134 syck_parser_taguri_expansion( parser, 0 );
135 oid = syck_parse( parser );
136 syck_lookup_sym( parser, oid, (char **)&sav );
137
138 ret = S_ALLOCA_N( char, strlen( sav->buffer ) + 3 );
139 ret[0] = '\0';
140 strcat( ret, "D\n" );
141 strcat( ret, sav->buffer );
142
143 syck_free_parser( parser );
144
145 bc = rb_str_new2( ret );
146 if ( taint ) OBJ_TAINT( bc );
147 return bc;
148 }
149
150 /*
151 * read from io.
152 */
153 long
rb_syck_io_str_read(char * buf,SyckIoStr * str,long max_size,long skip)154 rb_syck_io_str_read( char *buf, SyckIoStr *str, long max_size, long skip )
155 {
156 long len = 0;
157
158 ASSERT( str != NULL );
159 max_size -= skip;
160
161 if ( max_size <= 0 ) max_size = 0;
162 else
163 {
164 /*
165 * call io#read.
166 */
167 VALUE src = (VALUE)str->ptr;
168 VALUE n = LONG2NUM(max_size);
169 VALUE str2 = rb_funcall2(src, s_read, 1, &n);
170 if (!NIL_P(str2))
171 {
172 StringValue(str2);
173 len = rb_str_len(str2);
174 memcpy( buf + skip, rb_str_ptr(str2), len );
175 }
176 }
177 len += skip;
178 buf[len] = '\0';
179 return len;
180 }
181
182 /*
183 * determine: are we reading from a string or io?
184 * (returns tainted? boolean)
185 */
186 int
syck_parser_assign_io(SyckParser * parser,VALUE * pport)187 syck_parser_assign_io(SyckParser *parser, VALUE *pport)
188 {
189 int taint = Qtrue;
190 VALUE tmp, port = *pport;
191 if (!NIL_P(tmp = rb_check_string_type(port))) {
192 taint = OBJ_TAINTED(port); /* original taintedness */
193 port = tmp;
194 syck_parser_str( parser, rb_str_ptr(port), rb_str_len(port), NULL );
195 }
196 else if (rb_respond_to(port, s_read)) {
197 if (rb_respond_to(port, s_binmode)) {
198 rb_funcall2(port, s_binmode, 0, 0);
199 }
200 syck_parser_str( parser, (char *)port, 0, rb_syck_io_str_read );
201 }
202 else {
203 rb_raise(rb_eTypeError, "instance of IO needed");
204 }
205 *pport = port;
206 return taint;
207 }
208
209 /*
210 * Get value in hash by key, forcing an empty hash if nil.
211 */
212 VALUE
syck_get_hash_aref(VALUE hsh,VALUE key)213 syck_get_hash_aref(VALUE hsh, VALUE key)
214 {
215 VALUE val = rb_hash_aref( hsh, key );
216 if ( NIL_P( val ) )
217 {
218 val = rb_hash_new();
219 rb_hash_aset(hsh, key, val);
220 }
221 return val;
222 }
223
224 /*
225 * creating timestamps
226 */
227 SYMID
rb_syck_mktime(char * str,long len)228 rb_syck_mktime(char *str, long len)
229 {
230 VALUE time;
231 char *ptr = str;
232 VALUE year = INT2FIX(0);
233 VALUE mon = INT2FIX(0);
234 VALUE day = INT2FIX(0);
235 VALUE hour = INT2FIX(0);
236 VALUE min = INT2FIX(0);
237 VALUE sec = INT2FIX(0);
238 long usec;
239
240 /* Year*/
241 if ( ptr[0] != '\0' && len > 0 ) {
242 year = INT2FIX(strtol(ptr, NULL, 10));
243 }
244
245 /* Month*/
246 ptr += 4;
247 if ( ptr[0] != '\0' && len > ptr - str ) {
248 while ( !ISDIGIT( *ptr ) ) ptr++;
249 mon = INT2FIX(strtol(ptr, NULL, 10));
250 }
251
252 /* Day*/
253 ptr += 2;
254 if ( ptr[0] != '\0' && len > ptr - str ) {
255 while ( !ISDIGIT( *ptr ) ) ptr++;
256 day = INT2FIX(strtol(ptr, NULL, 10));
257 }
258
259 /* Hour*/
260 ptr += 2;
261 if ( ptr[0] != '\0' && len > ptr - str ) {
262 while ( !ISDIGIT( *ptr ) ) ptr++;
263 hour = INT2FIX(strtol(ptr, NULL, 10));
264 }
265
266 /* Minute */
267 ptr += 2;
268 if ( ptr[0] != '\0' && len > ptr - str ) {
269 while ( !ISDIGIT( *ptr ) ) ptr++;
270 min = INT2FIX(strtol(ptr, NULL, 10));
271 }
272
273 /* Second */
274 ptr += 2;
275 if ( ptr[0] != '\0' && len > ptr - str ) {
276 while ( !ISDIGIT( *ptr ) ) ptr++;
277 sec = INT2FIX(strtol(ptr, NULL, 10));
278 }
279
280 /* Millisecond */
281 ptr += 2;
282 if ( len > ptr - str && *ptr == '.' )
283 {
284 char padded[] = "000000";
285 char *end = ptr + 1;
286 while ( isdigit( *end ) ) end++;
287 MEMCPY(padded, ptr + 1, char, end - (ptr + 1));
288 usec = strtol(padded, NULL, 10);
289 }
290 else
291 {
292 usec = 0;
293 }
294
295 /* Time Zone*/
296 while ( len > ptr - str && *ptr != 'Z' && *ptr != '+' && *ptr != '-' && *ptr != '\0' ) ptr++;
297 if ( len > ptr - str && ( *ptr == '-' || *ptr == '+' ) )
298 {
299 time_t tz_offset = strtol(ptr, NULL, 10) * 3600;
300 time_t tmp;
301
302 while ( *ptr != ':' && *ptr != '\0' ) ptr++;
303 if ( *ptr == ':' )
304 {
305 ptr += 1;
306 if ( tz_offset < 0 )
307 {
308 tz_offset -= strtol(ptr, NULL, 10) * 60;
309 }
310 else
311 {
312 tz_offset += strtol(ptr, NULL, 10) * 60;
313 }
314 }
315
316 /* Make TZ time*/
317 time = rb_funcall(rb_cTime, s_utc, 6, year, mon, day, hour, min, sec);
318 tmp = NUM2LONG(rb_funcall(time, s_to_i, 0)) - tz_offset;
319 return rb_funcall(rb_cTime, s_at, 2, LONG2NUM(tmp), LONG2NUM(usec));
320 }
321 else
322 {
323 /* Make UTC time*/
324 return rb_funcall(rb_cTime, s_utc, 7, year, mon, day, hour, min, sec, LONG2NUM(usec));
325 }
326 }
327
328 /*
329 * handles merging of an array of hashes
330 * (see http://www.yaml.org/type/merge/)
331 */
332 VALUE
syck_merge_i(VALUE entry,VALUE hsh)333 syck_merge_i(VALUE entry, VALUE hsh)
334 {
335 VALUE tmp;
336 if ( !NIL_P(tmp = rb_check_convert_type(entry, T_HASH, "Hash", "to_hash")) )
337 {
338 entry = tmp;
339 rb_funcall( hsh, s_update, 1, entry );
340 }
341 return Qnil;
342 }
343
344 /*
345 * default handler for ruby.yaml.org types
346 */
347 int
yaml_org_handler(SyckNode * n,VALUE * ref)348 yaml_org_handler(SyckNode *n, VALUE *ref)
349 {
350 char *type_id = n->type_id;
351 int transferred = 0;
352 long i = 0;
353 VALUE obj = Qnil;
354
355 if ( type_id != NULL && strncmp( type_id, "tag:yaml.org,2002:", 18 ) == 0 )
356 {
357 type_id += 18;
358 }
359
360 switch (n->kind)
361 {
362 case syck_str_kind:
363 transferred = 1;
364 if ( type_id == NULL )
365 {
366 obj = rb_str_new( n->data.str->ptr, n->data.str->len );
367 }
368 else if ( strcmp( type_id, "null" ) == 0 )
369 {
370 obj = Qnil;
371 }
372 else if ( strcmp( type_id, "binary" ) == 0 )
373 {
374 VALUE arr;
375 obj = rb_str_new( n->data.str->ptr, n->data.str->len );
376 rb_funcall( obj, s_tr_bang, 2, rb_str_new2( "\n\t " ), rb_str_new2( "" ) );
377 arr = rb_funcall( obj, s_unpack, 1, rb_str_new2( "m" ) );
378 obj = rb_ary_shift( arr );
379 }
380 else if ( strcmp( type_id, "bool#yes" ) == 0 )
381 {
382 obj = Qtrue;
383 }
384 else if ( strcmp( type_id, "bool#no" ) == 0 )
385 {
386 obj = Qfalse;
387 }
388 else if ( strcmp( type_id, "int#hex" ) == 0 )
389 {
390 syck_str_blow_away_commas( n );
391 obj = rb_cstr2inum( n->data.str->ptr, 16 );
392 }
393 else if ( strcmp( type_id, "int#oct" ) == 0 )
394 {
395 syck_str_blow_away_commas( n );
396 obj = rb_cstr2inum( n->data.str->ptr, 8 );
397 }
398 else if ( strcmp( type_id, "int#base60" ) == 0 )
399 {
400 char *ptr, *end;
401 long sixty = 1;
402 long total = 0;
403 syck_str_blow_away_commas( n );
404 ptr = n->data.str->ptr;
405 end = n->data.str->ptr + n->data.str->len;
406 while ( end > ptr )
407 {
408 long bnum = 0;
409 char *colon = end - 1;
410 while ( colon >= ptr && *colon != ':' )
411 {
412 colon--;
413 }
414 if ( colon >= ptr && *colon == ':' ) *colon = '\0';
415
416 bnum = strtol( colon + 1, NULL, 10 );
417 total += bnum * sixty;
418 sixty *= 60;
419 end = colon;
420 }
421 obj = INT2FIX(total);
422 }
423 else if ( strncmp( type_id, "int", 3 ) == 0 )
424 {
425 syck_str_blow_away_commas( n );
426 obj = rb_cstr2inum( n->data.str->ptr, 10 );
427 }
428 else if ( strcmp( type_id, "float#base60" ) == 0 )
429 {
430 char *ptr, *end;
431 long sixty = 1;
432 double total = 0.0;
433 syck_str_blow_away_commas( n );
434 ptr = n->data.str->ptr;
435 end = n->data.str->ptr + n->data.str->len;
436 while ( end > ptr )
437 {
438 double bnum = 0;
439 char *colon = end - 1;
440 while ( colon >= ptr && *colon != ':' )
441 {
442 colon--;
443 }
444 if ( colon >= ptr && *colon == ':' ) *colon = '\0';
445
446 bnum = strtod( colon + 1, NULL );
447 total += bnum * sixty;
448 sixty *= 60;
449 end = colon;
450 }
451 obj = rb_float_new( total );
452 }
453 else if ( strcmp( type_id, "float#nan" ) == 0 )
454 {
455 obj = rb_float_new( S_nan() );
456 }
457 else if ( strcmp( type_id, "float#inf" ) == 0 )
458 {
459 obj = rb_float_new( S_inf() );
460 }
461 else if ( strcmp( type_id, "float#neginf" ) == 0 )
462 {
463 obj = rb_float_new( -S_inf() );
464 }
465 else if ( strncmp( type_id, "float", 5 ) == 0 )
466 {
467 double f;
468 syck_str_blow_away_commas( n );
469 obj = rb_str_new( n->data.str->ptr, n->data.str->len );
470 obj = rb_funcall( obj, s_to_f, 0 );
471 }
472 else if ( strcmp( type_id, "timestamp#iso8601" ) == 0 )
473 {
474 obj = rb_syck_mktime( n->data.str->ptr, n->data.str->len );
475 }
476 else if ( strcmp( type_id, "timestamp#spaced" ) == 0 )
477 {
478 obj = rb_syck_mktime( n->data.str->ptr, n->data.str->len );
479 }
480 else if ( strcmp( type_id, "timestamp#ymd" ) == 0 )
481 {
482 char *ptr = n->data.str->ptr;
483 VALUE year, mon, day;
484
485 /* Year*/
486 ptr[4] = '\0';
487 year = INT2FIX(strtol(ptr, NULL, 10));
488
489 /* Month*/
490 ptr += 4;
491 while ( !ISDIGIT( *ptr ) ) ptr++;
492 mon = INT2FIX(strtol(ptr, NULL, 10));
493
494 /* Day*/
495 ptr += 2;
496 while ( !ISDIGIT( *ptr ) ) ptr++;
497 day = INT2FIX(strtol(ptr, NULL, 10));
498
499 if ( !cDate ) {
500 /*
501 * Load Date module
502 */
503 rb_require( "date" );
504 cDate = rb_const_get( rb_cObject, rb_intern("Date") );
505 }
506
507 obj = rb_funcall( cDate, s_new, 3, year, mon, day );
508 }
509 else if ( strncmp( type_id, "timestamp", 9 ) == 0 )
510 {
511 obj = rb_syck_mktime( n->data.str->ptr, n->data.str->len );
512 }
513 else if ( strncmp( type_id, "merge", 5 ) == 0 )
514 {
515 obj = rb_funcall( cMergeKey, s_new, 0 );
516 }
517 else if ( strncmp( type_id, "default", 7 ) == 0 )
518 {
519 obj = rb_funcall( cDefaultKey, s_new, 0 );
520 }
521 else if ( n->data.str->style == scalar_plain &&
522 n->data.str->len > 1 &&
523 strncmp( n->data.str->ptr, ":", 1 ) == 0 )
524 {
525 obj = rb_funcall( oDefaultResolver, s_transfer, 2,
526 rb_str_new2( "tag:ruby.yaml.org,2002:sym" ),
527 rb_str_new( n->data.str->ptr + 1, n->data.str->len - 1 ) );
528 }
529 else if ( strcmp( type_id, "str" ) == 0 )
530 {
531 obj = rb_str_new( n->data.str->ptr, n->data.str->len );
532 }
533 else
534 {
535 transferred = 0;
536 obj = rb_str_new( n->data.str->ptr, n->data.str->len );
537 }
538 break;
539
540 case syck_seq_kind:
541 if ( type_id == NULL || strcmp( type_id, "seq" ) == 0 )
542 {
543 transferred = 1;
544 }
545 obj = rb_ary_new2( n->data.list->idx );
546 for ( i = 0; i < n->data.list->idx; i++ )
547 {
548 rb_ary_store( obj, i, syck_seq_read( n, i ) );
549 }
550 break;
551
552 case syck_map_kind:
553 if ( type_id == NULL || strcmp( type_id, "map" ) == 0 )
554 {
555 transferred = 1;
556 }
557 obj = rb_hash_new();
558 for ( i = 0; i < n->data.pairs->idx; i++ )
559 {
560 VALUE k = syck_map_read( n, map_key, i );
561 VALUE v = syck_map_read( n, map_value, i );
562 int skip_aset = 0;
563
564 /*
565 * Handle merge keys
566 */
567 if ( rb_obj_is_kind_of( k, cMergeKey ) )
568 {
569 VALUE tmp;
570 if ( !NIL_P(tmp = rb_check_convert_type(v, T_HASH, "Hash", "to_hash")) )
571 {
572 VALUE dup = rb_funcall( tmp, s_dup, 0 );
573 rb_funcall( dup, s_update, 1, obj );
574 obj = dup;
575 skip_aset = 1;
576 }
577 else if ( !NIL_P(tmp = rb_check_array_type(v)) )
578 {
579 VALUE end = rb_ary_pop( tmp );
580 VALUE tmph = rb_check_convert_type(end, T_HASH, "Hash", "to_hash");
581 if ( !NIL_P(tmph) )
582 {
583 VALUE dup = rb_funcall( tmph, s_dup, 0 );
584 tmp = rb_ary_reverse( tmp );
585 rb_ary_push( tmp, obj );
586 rb_iterate( rb_each, tmp, syck_merge_i, dup );
587 obj = dup;
588 skip_aset = 1;
589 }
590 }
591 }
592 else if ( rb_obj_is_kind_of( k, cDefaultKey ) )
593 {
594 rb_funcall( obj, s_default_set, 1, v );
595 skip_aset = 1;
596 }
597
598 if ( ! skip_aset )
599 {
600 rb_hash_aset( obj, k, v );
601 }
602 }
603 break;
604 }
605
606 *ref = obj;
607 return transferred;
608 }
609
610 static void syck_node_mark( SyckNode *n );
611
612 /*
613 * {native mode} node handler
614 * - Converts data into native Ruby types
615 */
616 SYMID
rb_syck_load_handler(SyckParser * p,SyckNode * n)617 rb_syck_load_handler(SyckParser *p, SyckNode *n)
618 {
619 VALUE obj = Qnil;
620 struct parser_xtra *bonus = (struct parser_xtra *)p->bonus;
621 VALUE resolver = bonus->resolver;
622 if ( NIL_P( resolver ) )
623 {
624 resolver = oDefaultResolver;
625 }
626
627 /*
628 * Create node,
629 */
630 obj = rb_funcall( resolver, s_node_import, 1, Data_Wrap_Struct( cNode, NULL, NULL, n ) );
631
632 /*
633 * ID already set, let's alter the symbol table to accept the new object
634 */
635 if (n->id > 0 && !NIL_P(obj))
636 {
637 MEMCPY((void *)n->id, (void *)obj, RVALUE, 1);
638 MEMZERO((void *)obj, RVALUE, 1);
639 obj = n->id;
640 }
641
642 if ( bonus->taint) OBJ_TAINT( obj );
643 if ( bonus->proc != 0 ) rb_funcall(bonus->proc, s_call, 1, obj);
644
645 rb_hash_aset(bonus->data, INT2FIX(RHASH(bonus->data)->tbl->num_entries), obj);
646 return obj;
647 }
648
649 /*
650 * friendly errors.
651 */
652 void
rb_syck_err_handler(SyckParser * p,char * msg)653 rb_syck_err_handler(SyckParser *p, char *msg)
654 {
655 char *endl = p->cursor;
656
657 while ( *endl != '\0' && *endl != '\n' )
658 endl++;
659
660 endl[0] = '\0';
661 rb_raise(rb_eArgError, "%s on line %d, col %d: `%s'",
662 msg,
663 p->linect,
664 p->cursor - p->lineptr,
665 p->lineptr);
666 }
667
668 /*
669 * provide bad anchor object to the parser.
670 */
671 SyckNode *
rb_syck_bad_anchor_handler(SyckParser * p,char * a)672 rb_syck_bad_anchor_handler(SyckParser *p, char *a)
673 {
674 VALUE anchor_name = rb_str_new2( a );
675 SyckNode *badanc = syck_new_map( rb_str_new2( "name" ), anchor_name );
676 badanc->type_id = syck_strndup( "tag:ruby.yaml.org,2002:object:YAML::Syck::BadAlias", 53 );
677 return badanc;
678 }
679
680 /*
681 * data loaded based on the model requested.
682 */
683 void
syck_set_model(VALUE p,VALUE input,VALUE model)684 syck_set_model(VALUE p, VALUE input, VALUE model)
685 {
686 SyckParser *parser;
687 Data_Get_Struct(p, SyckParser, parser);
688 syck_parser_handler( parser, rb_syck_load_handler );
689 /* WARN: gonna be obsoleted soon!! */
690 if ( model == sym_generic )
691 {
692 rb_funcall( p, s_set_resolver, 1, oGenericResolver );
693 }
694 syck_parser_implicit_typing( parser, 1 );
695 syck_parser_taguri_expansion( parser, 1 );
696
697 if ( NIL_P( input ) )
698 {
699 input = rb_ivar_get( p, s_input );
700 }
701 if ( input == sym_bytecode )
702 {
703 syck_parser_set_input_type( parser, syck_bytecode_utf8 );
704 }
705 else
706 {
707 syck_parser_set_input_type( parser, syck_yaml_utf8 );
708 }
709 syck_parser_error_handler( parser, rb_syck_err_handler );
710 syck_parser_bad_anchor_handler( parser, rb_syck_bad_anchor_handler );
711 }
712
713 static int
syck_st_mark_nodes(char * key,SyckNode * n,char * arg)714 syck_st_mark_nodes( char *key, SyckNode *n, char *arg )
715 {
716 if ( n != (void *)1 ) syck_node_mark( n );
717 return ST_CONTINUE;
718 }
719
720 /*
721 * mark parser nodes
722 */
723 static void
syck_mark_parser(SyckParser * parser)724 syck_mark_parser(SyckParser *parser)
725 {
726 struct parser_xtra *bonus = (struct parser_xtra *)parser->bonus;
727 rb_gc_mark_maybe(parser->root);
728 rb_gc_mark_maybe(parser->root_on_error);
729 rb_gc_mark( bonus->data );
730 rb_gc_mark( bonus->proc );
731 rb_gc_mark( bonus->resolver );
732
733 if ( parser->anchors != NULL )
734 {
735 st_foreach( parser->anchors, syck_st_mark_nodes, 0 );
736 }
737 if ( parser->bad_anchors != NULL )
738 {
739 st_foreach( parser->bad_anchors, syck_st_mark_nodes, 0 );
740 }
741 }
742
743 /*
744 * Free the parser and any bonus attachment.
745 */
746 void
rb_syck_free_parser(SyckParser * p)747 rb_syck_free_parser(SyckParser *p)
748 {
749 S_FREE( p->bonus );
750 syck_free_parser(p);
751 }
752
753 /*
754 * YAML::Syck::Parser.allocate
755 */
756 VALUE syck_parser_s_alloc _((VALUE));
757 VALUE
syck_parser_s_alloc(VALUE class)758 syck_parser_s_alloc(VALUE class)
759 {
760 VALUE pobj;
761 SyckParser *parser = syck_new_parser();
762
763 parser->bonus = S_ALLOC( struct parser_xtra );
764 S_MEMZERO( parser->bonus, struct parser_xtra, 1 );
765
766 pobj = Data_Wrap_Struct( class, syck_mark_parser, rb_syck_free_parser, parser );
767
768 syck_parser_set_root_on_error( parser, Qnil );
769
770 return pobj;
771 }
772
773 /*
774 * YAML::Syck::Parser.initialize( resolver, options )
775 */
776 static VALUE
syck_parser_initialize(int argc,VALUE * argv,VALUE self)777 syck_parser_initialize(int argc, VALUE *argv, VALUE self)
778 {
779 VALUE options;
780 if (rb_scan_args(argc, argv, "01", &options) == 0)
781 {
782 options = rb_hash_new();
783 }
784 else
785 {
786 Check_Type(options, T_HASH);
787 }
788 rb_ivar_set(self, s_options, options);
789 rb_ivar_set(self, s_input, Qnil);
790 rb_ivar_set(self, s_resolver, Qnil);
791 return self;
792 }
793
794 /*
795 * YAML::Syck::Parser.bufsize = Integer
796 */
797 static VALUE
syck_parser_bufsize_set(VALUE self,VALUE size)798 syck_parser_bufsize_set(VALUE self, VALUE size)
799 {
800 SyckParser *parser;
801
802 if ( rb_respond_to( size, s_to_i ) ) {
803 int n = NUM2INT(rb_funcall(size, s_to_i, 0));
804 Data_Get_Struct(self, SyckParser, parser);
805 parser->bufsize = n;
806 }
807 return self;
808 }
809
810 /*
811 * YAML::Syck::Parser.bufsize => Integer
812 */
813 static VALUE
syck_parser_bufsize_get(VALUE self)814 syck_parser_bufsize_get(VALUE self)
815 {
816 SyckParser *parser;
817
818 Data_Get_Struct(self, SyckParser, parser);
819 return INT2FIX( parser->bufsize );
820 }
821
822 /*
823 * YAML::Syck::Parser.load( IO or String )
824 */
825 VALUE
syck_parser_load(int argc,VALUE * argv,VALUE self)826 syck_parser_load(int argc, VALUE *argv, VALUE self)
827 {
828 VALUE port, proc, model, input;
829 SyckParser *parser;
830 struct parser_xtra *bonus;
831
832 rb_scan_args(argc, argv, "11", &port, &proc);
833
834 input = rb_hash_aref( rb_attr_get( self, s_options ), sym_input );
835 model = rb_hash_aref( rb_attr_get( self, s_options ), sym_model );
836 Data_Get_Struct(self, SyckParser, parser);
837 syck_set_model( self, input, model );
838
839 bonus = (struct parser_xtra *)parser->bonus;
840 bonus->taint = syck_parser_assign_io(parser, &port);
841 bonus->data = rb_hash_new();
842 bonus->resolver = rb_attr_get( self, s_resolver );
843 if ( NIL_P( proc ) ) bonus->proc = 0;
844 else bonus->proc = proc;
845
846 return syck_parse( parser );
847 }
848
849 /*
850 * YAML::Syck::Parser.load_documents( IO or String ) { |doc| }
851 */
852 VALUE
syck_parser_load_documents(int argc,VALUE * argv,VALUE self)853 syck_parser_load_documents(int argc, VALUE *argv, VALUE self)
854 {
855 VALUE port, proc, v, input, model;
856 SyckParser *parser;
857 struct parser_xtra *bonus;
858
859 rb_scan_args(argc, argv, "1&", &port, &proc);
860
861 input = rb_hash_aref( rb_attr_get( self, s_options ), sym_input );
862 model = rb_hash_aref( rb_attr_get( self, s_options ), sym_model );
863 Data_Get_Struct(self, SyckParser, parser);
864 syck_set_model( self, input, model );
865
866 bonus = (struct parser_xtra *)parser->bonus;
867 bonus->taint = syck_parser_assign_io(parser, &port);
868 bonus->resolver = rb_attr_get( self, s_resolver );
869 bonus->proc = 0;
870
871 while ( 1 )
872 {
873 /* Reset hash for tracking nodes */
874 bonus->data = rb_hash_new();
875
876 /* Parse a document */
877 v = syck_parse( parser );
878 if ( parser->eof == 1 )
879 {
880 break;
881 }
882
883 /* Pass document to block */
884 rb_funcall( proc, s_call, 1, v );
885 }
886
887 return Qnil;
888 }
889
890 /*
891 * YAML::Syck::Parser#set_resolver
892 */
893 VALUE
syck_parser_set_resolver(VALUE self,VALUE resolver)894 syck_parser_set_resolver(VALUE self, VALUE resolver)
895 {
896 rb_ivar_set( self, s_resolver, resolver );
897 return self;
898 }
899
900 /*
901 * YAML::Syck::Resolver.initialize
902 */
903 static VALUE
syck_resolver_initialize(VALUE self)904 syck_resolver_initialize(VALUE self)
905 {
906 VALUE tags = rb_hash_new();
907 rb_ivar_set(self, s_tags, rb_hash_new());
908 return self;
909 }
910
911 /*
912 * YAML::Syck::Resolver#add_type
913 */
914 VALUE
syck_resolver_add_type(VALUE self,VALUE taguri,VALUE cls)915 syck_resolver_add_type(VALUE self, VALUE taguri, VALUE cls)
916 {
917 VALUE tags = rb_attr_get(self, s_tags);
918 rb_hash_aset( tags, taguri, cls );
919 return Qnil;
920 }
921
922 /*
923 * YAML::Syck::Resolver#use_types_at
924 */
925 VALUE
syck_resolver_use_types_at(VALUE self,VALUE hsh)926 syck_resolver_use_types_at(VALUE self, VALUE hsh)
927 {
928 rb_ivar_set( self, s_tags, hsh );
929 return Qnil;
930 }
931
932 /*
933 * YAML::Syck::Resolver#detect_implicit
934 */
935 VALUE
syck_resolver_detect_implicit(VALUE self,VALUE val)936 syck_resolver_detect_implicit(VALUE self, VALUE val)
937 {
938 char *type_id;
939 return rb_str_new2( "" );
940 }
941
942 /*
943 * YAML::Syck::Resolver#node_import
944 */
945 VALUE
syck_resolver_node_import(VALUE self,VALUE node)946 syck_resolver_node_import(VALUE self, VALUE node)
947 {
948 SyckNode *n;
949 VALUE obj;
950 int i = 0;
951 Data_Get_Struct(node, SyckNode, n);
952
953 switch (n->kind)
954 {
955 case syck_str_kind:
956 obj = rb_str_new( n->data.str->ptr, n->data.str->len );
957 break;
958
959 case syck_seq_kind:
960 obj = rb_ary_new2( n->data.list->idx );
961 for ( i = 0; i < n->data.list->idx; i++ )
962 {
963 rb_ary_store( obj, i, syck_seq_read( n, i ) );
964 }
965 break;
966
967 case syck_map_kind:
968 obj = rb_hash_new();
969 for ( i = 0; i < n->data.pairs->idx; i++ )
970 {
971 VALUE k = syck_map_read( n, map_key, i );
972 VALUE v = syck_map_read( n, map_value, i );
973 int skip_aset = 0;
974
975 /*
976 * Handle merge keys
977 */
978 if ( rb_obj_is_kind_of( k, cMergeKey ) )
979 {
980 if ( rb_obj_is_kind_of( v, rb_cHash ) )
981 {
982 VALUE dup = rb_funcall( v, s_dup, 0 );
983 rb_funcall( dup, s_update, 1, obj );
984 obj = dup;
985 skip_aset = 1;
986 }
987 else if ( rb_obj_is_kind_of( v, rb_cArray ) )
988 {
989 VALUE end = rb_ary_pop( v );
990 if ( rb_obj_is_kind_of( end, rb_cHash ) )
991 {
992 VALUE dup = rb_funcall( end, s_dup, 0 );
993 v = rb_ary_reverse( v );
994 rb_ary_push( v, obj );
995 rb_iterate( rb_each, v, syck_merge_i, dup );
996 obj = dup;
997 skip_aset = 1;
998 }
999 }
1000 }
1001 else if ( rb_obj_is_kind_of( k, cDefaultKey ) )
1002 {
1003 rb_funcall( obj, s_default_set, 1, v );
1004 skip_aset = 1;
1005 }
1006
1007 if ( ! skip_aset )
1008 {
1009 rb_hash_aset( obj, k, v );
1010 }
1011 }
1012 break;
1013 }
1014
1015 if ( n->type_id != NULL )
1016 {
1017 obj = rb_funcall( self, s_transfer, 2, rb_str_new2( n->type_id ), obj );
1018 }
1019 return obj;
1020 }
1021
1022 /*
1023 * Set instance variables
1024 */
1025 VALUE
syck_set_ivars(VALUE vars,VALUE obj)1026 syck_set_ivars(VALUE vars, VALUE obj)
1027 {
1028 VALUE ivname = rb_ary_entry( vars, 0 );
1029 char *ivn;
1030 StringValue( ivname );
1031 ivn = S_ALLOCA_N( char, rb_str_len(ivname) + 2 );
1032 ivn[0] = '@';
1033 ivn[1] = '\0';
1034 strncat( ivn, rb_str_ptr(ivname), rb_str_len(ivname) );
1035 rb_iv_set( obj, ivn, rb_ary_entry( vars, 1 ) );
1036 return Qnil;
1037 }
1038
1039 /*
1040 * YAML::Syck::Resolver#const_find
1041 */
1042 VALUE
syck_const_find(VALUE const_name)1043 syck_const_find(VALUE const_name)
1044 {
1045 VALUE tclass = rb_cObject;
1046 VALUE tparts = rb_str_split( const_name, "::" );
1047 int i = 0;
1048 for ( i = 0; i < rb_ary_len(tparts); i++ ) {
1049 VALUE tpart = rb_to_id( rb_ary_entry( tparts, i ) );
1050 if ( !rb_const_defined( tclass, tpart ) ) return Qnil;
1051 tclass = rb_const_get( tclass, tpart );
1052 }
1053 return tclass;
1054 }
1055
1056 /*
1057 * YAML::Syck::Resolver#transfer
1058 */
1059 VALUE
syck_resolver_transfer(VALUE self,VALUE type,VALUE val)1060 syck_resolver_transfer(VALUE self, VALUE type, VALUE val)
1061 {
1062 if (NIL_P(type) || rb_str_len(StringValue(type)) == 0)
1063 {
1064 type = rb_funcall( self, s_detect_implicit, 1, val );
1065 }
1066
1067 if ( ! (NIL_P(type) || rb_str_len(StringValue(type)) == 0) )
1068 {
1069 VALUE str_xprivate = rb_str_new2( "x-private" );
1070 VALUE colon = rb_str_new2( ":" );
1071 VALUE tags = rb_attr_get(self, s_tags);
1072 VALUE target_class = rb_hash_aref( tags, type );
1073 VALUE subclass = target_class;
1074 VALUE obj = Qnil;
1075
1076 /*
1077 * Should no tag match exactly, check for subclass format
1078 */
1079 if ( NIL_P( target_class ) )
1080 {
1081 VALUE subclass_parts = rb_ary_new();
1082 VALUE parts = rb_str_split( type, ":" );
1083
1084 while ( rb_ary_len(parts) > 1 )
1085 {
1086 VALUE partial;
1087 rb_ary_unshift( subclass_parts, rb_ary_pop( parts ) );
1088 partial = rb_ary_join( parts, colon );
1089 target_class = rb_hash_aref( tags, partial );
1090 if ( NIL_P( target_class ) )
1091 {
1092 rb_str_append( partial, colon );
1093 target_class = rb_hash_aref( tags, partial );
1094 }
1095
1096 /*
1097 * Possible subclass found, see if it supports subclassing
1098 */
1099 if ( ! NIL_P( target_class ) )
1100 {
1101 subclass = target_class;
1102 if ( rb_ary_len(subclass_parts) > 0 && rb_respond_to( target_class, s_tag_subclasses ) &&
1103 RTEST( rb_funcall( target_class, s_tag_subclasses, 0 ) ) )
1104 {
1105 VALUE subclass_v;
1106 subclass = rb_ary_join( subclass_parts, colon );
1107 subclass = rb_funcall( target_class, s_tag_read_class, 1, subclass );
1108 subclass_v = syck_const_find( subclass );
1109
1110 if ( subclass_v != Qnil )
1111 {
1112 subclass = subclass_v;
1113 }
1114 else if ( rb_cObject == target_class && subclass_v == Qnil )
1115 {
1116 target_class = cYObject;
1117 type = subclass;
1118 subclass = cYObject;
1119 }
1120 else /* workaround for SEGV. real fix please */
1121 {
1122 rb_raise( rb_eTypeError, "invalid subclass" );
1123 }
1124 }
1125 break;
1126 }
1127 }
1128 }
1129
1130 /* rb_raise(rb_eTypeError, "invalid typing scheme: %s given",
1131 * scheme);
1132 */
1133
1134 if ( rb_respond_to( target_class, s_call ) )
1135 {
1136 obj = rb_funcall( target_class, s_call, 2, type, val );
1137 }
1138 else
1139 {
1140 if ( rb_respond_to( target_class, s_yaml_new ) )
1141 {
1142 obj = rb_funcall( target_class, s_yaml_new, 3, subclass, type, val );
1143 }
1144 else if ( !NIL_P( target_class ) )
1145 {
1146 if ( subclass == rb_cBignum )
1147 {
1148 obj = rb_str2inum( val, 10 ); /* for yaml dumped by 1.8.3 [ruby-core:6159] */
1149 }
1150 else
1151 {
1152 obj = rb_obj_alloc( subclass );
1153 }
1154
1155 if ( rb_respond_to( obj, s_yaml_initialize ) )
1156 {
1157 rb_funcall( obj, s_yaml_initialize, 2, type, val );
1158 }
1159 else if ( !NIL_P( obj ) && rb_obj_is_instance_of( val, rb_cHash ) )
1160 {
1161 rb_iterate( rb_each, val, syck_set_ivars, obj );
1162 }
1163 }
1164 else
1165 {
1166 VALUE parts = rb_str_split( type, ":" );
1167 VALUE scheme = rb_ary_shift( parts );
1168 if ( rb_str_cmp( scheme, str_xprivate ) == 0 )
1169 {
1170 VALUE name = rb_ary_join( parts, colon );
1171 obj = rb_funcall( cPrivateType, s_new, 2, name, val );
1172 }
1173 else
1174 {
1175 VALUE domain = rb_ary_shift( parts );
1176 VALUE name = rb_ary_join( parts, colon );
1177 obj = rb_funcall( cDomainType, s_new, 3, domain, name, val );
1178 }
1179 }
1180 }
1181 val = obj;
1182 }
1183
1184 return val;
1185 }
1186
1187 /*
1188 * YAML::Syck::Resolver#tagurize
1189 */
1190 VALUE
syck_resolver_tagurize(VALUE self,VALUE val)1191 syck_resolver_tagurize(VALUE self, VALUE val)
1192 {
1193 VALUE tmp = rb_check_string_type(val);
1194
1195 if ( !NIL_P(tmp) )
1196 {
1197 char *taguri = syck_type_id_to_uri( rb_str_ptr(tmp) );
1198 val = rb_str_new2( taguri );
1199 S_FREE( taguri );
1200 }
1201
1202 return val;
1203 }
1204
1205 /*
1206 * YAML::Syck::DefaultResolver#detect_implicit
1207 */
1208 VALUE
syck_defaultresolver_detect_implicit(VALUE self,VALUE val)1209 syck_defaultresolver_detect_implicit(VALUE self, VALUE val)
1210 {
1211 char *type_id;
1212 VALUE tmp = rb_check_string_type(val);
1213
1214 if ( !NIL_P(tmp) )
1215 {
1216 val = tmp;
1217 type_id = syck_match_implicit( rb_str_ptr(val), rb_str_len(val) );
1218 return rb_str_new2( type_id );
1219 }
1220
1221 return rb_str_new2( "" );
1222 }
1223
1224 /*
1225 * YAML::Syck::DefaultResolver#node_import
1226 */
1227 VALUE
syck_defaultresolver_node_import(VALUE self,VALUE node)1228 syck_defaultresolver_node_import(VALUE self, VALUE node)
1229 {
1230 SyckNode *n;
1231 VALUE obj;
1232 Data_Get_Struct( node, SyckNode, n );
1233 if ( !yaml_org_handler( n, &obj ) )
1234 {
1235 obj = rb_funcall( self, s_transfer, 2, rb_str_new2( n->type_id ), obj );
1236 }
1237 return obj;
1238 }
1239
1240 /*
1241 * YAML::Syck::GenericResolver#node_import
1242 */
1243 VALUE
syck_genericresolver_node_import(VALUE self,VALUE node)1244 syck_genericresolver_node_import(VALUE self, VALUE node)
1245 {
1246 SyckNode *n;
1247 int i = 0;
1248 VALUE t = Qnil, obj = Qnil, v = Qnil, style = Qnil;
1249 Data_Get_Struct(node, SyckNode, n);
1250
1251 if ( n->type_id != NULL )
1252 {
1253 t = rb_str_new2(n->type_id);
1254 }
1255
1256 switch (n->kind)
1257 {
1258 case syck_str_kind:
1259 {
1260 v = rb_str_new( n->data.str->ptr, n->data.str->len );
1261 if ( n->data.str->style == scalar_1quote )
1262 {
1263 style = sym_1quote;
1264 }
1265 else if ( n->data.str->style == scalar_2quote )
1266 {
1267 style = sym_2quote;
1268 }
1269 else if ( n->data.str->style == scalar_fold )
1270 {
1271 style = sym_fold;
1272 }
1273 else if ( n->data.str->style == scalar_literal )
1274 {
1275 style = sym_literal;
1276 }
1277 else if ( n->data.str->style == scalar_plain )
1278 {
1279 style = sym_plain;
1280 }
1281 obj = rb_funcall( cScalar, s_new, 3, t, v, style );
1282 }
1283 break;
1284
1285 case syck_seq_kind:
1286 rb_iv_set(obj, "@kind", sym_seq);
1287 v = rb_ary_new2( syck_seq_count( n ) );
1288 for ( i = 0; i < syck_seq_count( n ); i++ )
1289 {
1290 rb_ary_store( v, i, syck_seq_read( n, i ) );
1291 }
1292 if ( n->data.list->style == seq_inline )
1293 {
1294 style = sym_inline;
1295 }
1296 obj = rb_funcall( cSeq, s_new, 3, t, v, style );
1297 break;
1298
1299 case syck_map_kind:
1300 rb_iv_set(obj, "@kind", sym_map);
1301 v = rb_hash_new();
1302 for ( i = 0; i < syck_map_count( n ); i++ )
1303 {
1304 rb_hash_aset( v, syck_map_read( n, map_key, i ), syck_map_read( n, map_value, i ) );
1305 }
1306 if ( n->data.pairs->style == map_inline )
1307 {
1308 style = sym_inline;
1309 }
1310 obj = rb_funcall( cMap, s_new, 3, t, v, style );
1311 break;
1312 }
1313
1314 return obj;
1315 }
1316
1317 /*
1318 * YAML::Syck::BadAlias.initialize
1319 */
1320 VALUE
syck_badalias_initialize(VALUE self,VALUE val)1321 syck_badalias_initialize(VALUE self, VALUE val)
1322 {
1323 rb_iv_set( self, "@name", val );
1324 return self;
1325 }
1326
1327 /*
1328 * YAML::Syck::BadAlias.<=>
1329 */
1330 VALUE
syck_badalias_cmp(VALUE alias1,VALUE alias2)1331 syck_badalias_cmp(VALUE alias1, VALUE alias2)
1332 {
1333 VALUE str1 = rb_ivar_get( alias1, s_name );
1334 VALUE str2 = rb_ivar_get( alias2, s_name );
1335 VALUE val = rb_funcall( str1, s_cmp, 1, str2 );
1336 return val;
1337 }
1338
1339 /*
1340 * YAML::DomainType.initialize
1341 */
1342 VALUE
syck_domaintype_initialize(VALUE self,VALUE domain,VALUE type_id,VALUE val)1343 syck_domaintype_initialize(VALUE self, VALUE domain, VALUE type_id, VALUE val)
1344 {
1345 rb_iv_set( self, "@domain", domain );
1346 rb_iv_set( self, "@type_id", type_id );
1347 rb_iv_set( self, "@value", val );
1348 return self;
1349 }
1350
1351 /*
1352 * YAML::Object.initialize
1353 */
1354 VALUE
syck_yobject_initialize(VALUE self,VALUE klass,VALUE ivars)1355 syck_yobject_initialize(VALUE self, VALUE klass, VALUE ivars)
1356 {
1357 rb_iv_set( self, "@class", klass );
1358 rb_iv_set( self, "@ivars", ivars );
1359 return self;
1360 }
1361
1362 /*
1363 * YAML::PrivateType.initialize
1364 */
1365 VALUE
syck_privatetype_initialize(VALUE self,VALUE type_id,VALUE val)1366 syck_privatetype_initialize(VALUE self, VALUE type_id, VALUE val)
1367 {
1368 rb_iv_set( self, "@type_id", type_id );
1369 rb_iv_set( self, "@value", val );
1370 return self;
1371 }
1372
1373 /*
1374 * Mark node contents.
1375 */
1376 static void
syck_node_mark(SyckNode * n)1377 syck_node_mark(SyckNode *n)
1378 {
1379 int i;
1380 rb_gc_mark_maybe( n->id );
1381 switch ( n->kind )
1382 {
1383 case syck_seq_kind:
1384 for ( i = 0; i < n->data.list->idx; i++ )
1385 {
1386 rb_gc_mark( syck_seq_read( n, i ) );
1387 }
1388 break;
1389
1390 case syck_map_kind:
1391 for ( i = 0; i < n->data.pairs->idx; i++ )
1392 {
1393 rb_gc_mark( syck_map_read( n, map_key, i ) );
1394 rb_gc_mark( syck_map_read( n, map_value, i ) );
1395 }
1396 break;
1397 }
1398 #if 0 /* maybe needed */
1399 if ( n->shortcut ) syck_node_mark( n->shortcut ); /* caution: maybe cyclic */
1400 #endif
1401 }
1402
1403 /*
1404 * YAML::Syck::Scalar.allocate
1405 */
1406 VALUE
syck_scalar_alloc(VALUE class)1407 syck_scalar_alloc(VALUE class)
1408 {
1409 SyckNode *node = syck_alloc_str();
1410 VALUE obj = Data_Wrap_Struct( class, syck_node_mark, syck_free_node, node );
1411 node->id = obj;
1412 return obj;
1413 }
1414
1415 /*
1416 * YAML::Syck::Scalar.initialize
1417 */
1418 VALUE
syck_scalar_initialize(VALUE self,VALUE type_id,VALUE val,VALUE style)1419 syck_scalar_initialize(VALUE self, VALUE type_id, VALUE val, VALUE style)
1420 {
1421 rb_iv_set( self, "@kind", sym_scalar );
1422 rb_funcall( self, s_type_id_set, 1, type_id );
1423 rb_funcall( self, s_value_set, 1, val );
1424 rb_funcall( self, s_style_set, 1, style );
1425 return self;
1426 }
1427
1428 /*
1429 * YAML::Syck::Scalar.style=
1430 */
1431 VALUE
syck_scalar_style_set(VALUE self,VALUE style)1432 syck_scalar_style_set(VALUE self, VALUE style)
1433 {
1434 SyckNode *node;
1435 Data_Get_Struct( self, SyckNode, node );
1436
1437 if ( NIL_P( style ) )
1438 {
1439 node->data.str->style = scalar_none;
1440 }
1441 else if ( style == sym_1quote )
1442 {
1443 node->data.str->style = scalar_1quote;
1444 }
1445 else if ( style == sym_2quote )
1446 {
1447 node->data.str->style = scalar_2quote;
1448 }
1449 else if ( style == sym_fold )
1450 {
1451 node->data.str->style = scalar_fold;
1452 }
1453 else if ( style == sym_literal )
1454 {
1455 node->data.str->style = scalar_literal;
1456 }
1457 else if ( style == sym_plain )
1458 {
1459 node->data.str->style = scalar_plain;
1460 }
1461
1462 rb_iv_set( self, "@style", style );
1463 return self;
1464 }
1465
1466 /*
1467 * YAML::Syck::Scalar.value=
1468 */
1469 VALUE
syck_scalar_value_set(VALUE self,VALUE val)1470 syck_scalar_value_set(VALUE self, VALUE val)
1471 {
1472 SyckNode *node;
1473 Data_Get_Struct( self, SyckNode, node );
1474
1475 StringValue( val );
1476 node->data.str->ptr = syck_strndup( rb_str_ptr(val), rb_str_len(val) );
1477 node->data.str->len = rb_str_len(val);
1478 node->data.str->style = scalar_none;
1479
1480 rb_iv_set( self, "@value", val );
1481 return val;
1482 }
1483
1484 /*
1485 * YAML::Syck::Seq.allocate
1486 */
1487 VALUE
syck_seq_alloc(VALUE class)1488 syck_seq_alloc(VALUE class)
1489 {
1490 SyckNode *node;
1491 VALUE obj;
1492 node = syck_alloc_seq();
1493 obj = Data_Wrap_Struct( class, syck_node_mark, syck_free_node, node );
1494 node->id = obj;
1495 return obj;
1496 }
1497
1498 /*
1499 * YAML::Syck::Seq.initialize
1500 */
1501 VALUE
syck_seq_initialize(VALUE self,VALUE type_id,VALUE val,VALUE style)1502 syck_seq_initialize(VALUE self, VALUE type_id, VALUE val, VALUE style)
1503 {
1504 SyckNode *node;
1505 Data_Get_Struct( self, SyckNode, node );
1506
1507 rb_iv_set( self, "@kind", sym_seq );
1508 rb_funcall( self, s_type_id_set, 1, type_id );
1509 rb_funcall( self, s_value_set, 1, val );
1510 rb_funcall( self, s_style_set, 1, style );
1511 return self;
1512 }
1513
1514 /*
1515 * YAML::Syck::Seq.value=
1516 */
1517 VALUE
syck_seq_value_set(VALUE self,VALUE val)1518 syck_seq_value_set(VALUE self, VALUE val)
1519 {
1520 SyckNode *node;
1521 Data_Get_Struct( self, SyckNode, node );
1522
1523 val = rb_check_array_type( val );
1524 if ( !NIL_P( val ) ) {
1525 int i;
1526 syck_seq_empty( node );
1527 for ( i = 0; i < rb_ary_len( val ); i++ )
1528 {
1529 syck_seq_add( node, rb_ary_entry(val, i) );
1530 }
1531 }
1532
1533 rb_iv_set( self, "@value", val );
1534 return val;
1535 }
1536
1537 /*
1538 * YAML::Syck::Seq.add
1539 */
1540 VALUE
syck_seq_add_m(VALUE self,VALUE val)1541 syck_seq_add_m(VALUE self, VALUE val)
1542 {
1543 SyckNode *node;
1544 VALUE emitter = rb_ivar_get( self, s_emitter );
1545 Data_Get_Struct( self, SyckNode, node );
1546
1547 if ( rb_respond_to( emitter, s_node_export ) ) {
1548 val = rb_funcall( emitter, s_node_export, 1, val );
1549 }
1550 syck_seq_add( node, val );
1551 rb_ary_push( rb_ivar_get( self, s_value ), val );
1552
1553 return self;
1554 }
1555
1556 /*
1557 * YAML::Syck::Seq.style=
1558 */
1559 VALUE
syck_seq_style_set(VALUE self,VALUE style)1560 syck_seq_style_set(VALUE self, VALUE style)
1561 {
1562 SyckNode *node;
1563 Data_Get_Struct( self, SyckNode, node );
1564
1565 if ( style == sym_inline )
1566 {
1567 node->data.list->style = seq_inline;
1568 }
1569 else
1570 {
1571 node->data.list->style = seq_none;
1572 }
1573
1574 rb_iv_set( self, "@style", style );
1575 return self;
1576 }
1577
1578 /*
1579 * YAML::Syck::Map.allocate
1580 */
1581 VALUE
syck_map_alloc(VALUE class)1582 syck_map_alloc(VALUE class)
1583 {
1584 SyckNode *node;
1585 VALUE obj;
1586 node = syck_alloc_map();
1587 obj = Data_Wrap_Struct( class, syck_node_mark, syck_free_node, node );
1588 node->id = obj;
1589 return obj;
1590 }
1591
1592 /*
1593 * YAML::Syck::Map.initialize
1594 */
1595 VALUE
syck_map_initialize(VALUE self,VALUE type_id,VALUE val,VALUE style)1596 syck_map_initialize(VALUE self, VALUE type_id, VALUE val, VALUE style)
1597 {
1598 SyckNode *node;
1599 Data_Get_Struct( self, SyckNode, node );
1600
1601 if ( !NIL_P( val ) )
1602 {
1603 VALUE hsh = rb_check_convert_type(val, T_HASH, "Hash", "to_hash");
1604 VALUE keys;
1605 int i;
1606 if ( NIL_P(hsh) )
1607 {
1608 rb_raise( rb_eTypeError, "wrong argument type" );
1609 }
1610
1611 keys = rb_funcall( hsh, s_keys, 0 );
1612 for ( i = 0; i < rb_ary_len(keys); i++ )
1613 {
1614 VALUE key = rb_ary_entry(keys, i);
1615 syck_map_add( node, key, rb_hash_aref(hsh, key) );
1616 }
1617 }
1618
1619 rb_iv_set( self, "@kind", sym_seq );
1620 rb_funcall( self, s_type_id_set, 1, type_id );
1621 rb_funcall( self, s_value_set, 1, val );
1622 rb_funcall( self, s_style_set, 1, style );
1623 return self;
1624 }
1625
1626 /*
1627 * YAML::Syck::Map.value=
1628 */
1629 VALUE
syck_map_value_set(VALUE self,VALUE val)1630 syck_map_value_set(VALUE self, VALUE val)
1631 {
1632 SyckNode *node;
1633 Data_Get_Struct( self, SyckNode, node );
1634
1635 if ( !NIL_P( val ) )
1636 {
1637 VALUE hsh = rb_check_convert_type(val, T_HASH, "Hash", "to_hash");
1638 VALUE keys;
1639 int i;
1640 if ( NIL_P(hsh) )
1641 {
1642 rb_raise( rb_eTypeError, "wrong argument type" );
1643 }
1644
1645 syck_map_empty( node );
1646 keys = rb_funcall( hsh, s_keys, 0 );
1647 for ( i = 0; i < rb_ary_len(keys); i++ )
1648 {
1649 VALUE key = rb_ary_entry(keys, i);
1650 syck_map_add( node, key, rb_hash_aref(hsh, key) );
1651 }
1652 }
1653
1654 rb_iv_set( self, "@value", val );
1655 return val;
1656 }
1657
1658 /*
1659 * YAML::Syck::Map.add
1660 */
1661 VALUE
syck_map_add_m(VALUE self,VALUE key,VALUE val)1662 syck_map_add_m(VALUE self, VALUE key, VALUE val)
1663 {
1664 SyckNode *node;
1665 VALUE emitter = rb_ivar_get( self, s_emitter );
1666 Data_Get_Struct( self, SyckNode, node );
1667
1668 if ( rb_respond_to( emitter, s_node_export ) ) {
1669 key = rb_funcall( emitter, s_node_export, 1, key );
1670 val = rb_funcall( emitter, s_node_export, 1, val );
1671 }
1672 syck_map_add( node, key, val );
1673 rb_hash_aset( rb_ivar_get( self, s_value ), key, val );
1674
1675 return self;
1676 }
1677
1678 /*
1679 * YAML::Syck::Map.style=
1680 */
1681 VALUE
syck_map_style_set(VALUE self,VALUE style)1682 syck_map_style_set(VALUE self, VALUE style)
1683 {
1684 SyckNode *node;
1685 Data_Get_Struct( self, SyckNode, node );
1686
1687 if ( style == sym_inline )
1688 {
1689 node->data.pairs->style = map_inline;
1690 }
1691 else
1692 {
1693 node->data.pairs->style = map_none;
1694 }
1695
1696 rb_iv_set( self, "@style", style );
1697 return self;
1698 }
1699
1700 /*
1701 * Cloning method for all node types
1702 */
1703 VALUE
syck_node_init_copy(VALUE copy,VALUE orig)1704 syck_node_init_copy(VALUE copy, VALUE orig)
1705 {
1706 SyckNode *copy_n;
1707 SyckNode *orig_n;
1708
1709 if ( copy == orig )
1710 return copy;
1711
1712 if ( TYPE( orig ) != T_DATA )
1713 {
1714 rb_raise( rb_eTypeError, "wrong argument type" );
1715 }
1716
1717 Data_Get_Struct( orig, SyckNode, orig_n );
1718 Data_Get_Struct( copy, SyckNode, copy_n );
1719 MEMCPY( copy_n, orig_n, SyckNode, 1 );
1720 return copy;
1721 }
1722
1723 /*
1724 * YAML::Syck::Node#type_id=
1725 */
1726 VALUE
syck_node_type_id_set(VALUE self,VALUE type_id)1727 syck_node_type_id_set(VALUE self, VALUE type_id)
1728 {
1729 SyckNode *node;
1730 Data_Get_Struct( self, SyckNode, node );
1731
1732 S_FREE( node->type_id );
1733
1734 if ( !NIL_P( type_id ) ) {
1735 StringValue( type_id );
1736 node->type_id = syck_strndup( rb_str_ptr(type_id), rb_str_len(type_id) );
1737 }
1738
1739 rb_iv_set( self, "@type_id", type_id );
1740 return type_id;
1741 }
1742
1743 /*
1744 * YAML::Syck::Node.transform
1745 */
1746 VALUE
syck_node_transform(VALUE self)1747 syck_node_transform(VALUE self)
1748 {
1749 VALUE t;
1750 SyckNode *n;
1751 SyckNode *orig_n;
1752 Data_Get_Struct(self, SyckNode, orig_n);
1753 t = Data_Wrap_Struct( cNode, syck_node_mark, syck_free_node, 0 );
1754
1755 switch (orig_n->kind)
1756 {
1757 case syck_map_kind:
1758 {
1759 int i;
1760 DATA_PTR(t) = n = syck_alloc_map();
1761 for ( i = 0; i < orig_n->data.pairs->idx; i++ )
1762 {
1763 syck_map_add( n, rb_funcall( syck_map_read( orig_n, map_key, i ), s_transform, 0 ),
1764 rb_funcall( syck_map_read( orig_n, map_value, i ), s_transform, 0 ) );
1765 }
1766 }
1767 break;
1768
1769 case syck_seq_kind:
1770 {
1771 int i;
1772 DATA_PTR(t) = n = syck_alloc_seq();
1773 for ( i = 0; i < orig_n->data.list->idx; i++ )
1774 {
1775 syck_seq_add( n, rb_funcall( syck_seq_read( orig_n, i ), s_transform, 0 ) );
1776 }
1777 }
1778 break;
1779
1780 case syck_str_kind:
1781 DATA_PTR(t) = n = syck_new_str2( orig_n->data.str->ptr, orig_n->data.str->len, orig_n->data.str->style );
1782 break;
1783 }
1784
1785 if ( orig_n->type_id != NULL )
1786 {
1787 n->type_id = syck_strndup( orig_n->type_id, strlen( orig_n->type_id ) );
1788 }
1789 if ( orig_n->anchor != NULL )
1790 {
1791 n->anchor = syck_strndup( orig_n->anchor, strlen( orig_n->anchor ) );
1792 }
1793 n->id = t;
1794 return rb_funcall( oDefaultResolver, s_node_import, 1, t );
1795 }
1796
1797 /*
1798 * Emitter callback: assembles YAML document events from
1799 * Ruby symbols. This is a brilliant way to do it.
1800 * No one could possibly object.
1801 */
1802 void
rb_syck_emitter_handler(SyckEmitter * e,st_data_t data)1803 rb_syck_emitter_handler(SyckEmitter *e, st_data_t data)
1804 {
1805 SyckNode *n;
1806 Data_Get_Struct((VALUE)data, SyckNode, n);
1807
1808 switch (n->kind)
1809 {
1810 case syck_map_kind:
1811 {
1812 int i;
1813 syck_emit_map( e, n->type_id, n->data.pairs->style );
1814 for ( i = 0; i < n->data.pairs->idx; i++ )
1815 {
1816 syck_emit_item( e, syck_map_read( n, map_key, i ) );
1817 syck_emit_item( e, syck_map_read( n, map_value, i ) );
1818 }
1819 syck_emit_end( e );
1820 }
1821 break;
1822
1823 case syck_seq_kind:
1824 {
1825 int i;
1826 syck_emit_seq( e, n->type_id, n->data.list->style );
1827 for ( i = 0; i < n->data.list->idx; i++ )
1828 {
1829 syck_emit_item( e, syck_seq_read( n, i ) );
1830 }
1831 syck_emit_end( e );
1832 }
1833 break;
1834
1835 case syck_str_kind:
1836 {
1837 syck_emit_scalar( e, n->type_id, n->data.str->style, 0, 0, 0, n->data.str->ptr, n->data.str->len );
1838 }
1839 break;
1840 }
1841 }
1842
1843 /*
1844 * Handle output from the emitter
1845 */
1846 void
rb_syck_output_handler(SyckEmitter * emitter,char * str,long len)1847 rb_syck_output_handler(SyckEmitter * emitter, char *str, long len)
1848 {
1849 struct emitter_xtra *bonus = (struct emitter_xtra *)emitter->bonus;
1850 VALUE dest = bonus->port;
1851 if (TYPE(dest) == T_STRING) {
1852 rb_str_cat( dest, str, len );
1853 } else {
1854 rb_io_write( dest, rb_str_new( str, len ) );
1855 }
1856 }
1857
1858 /*
1859 * Helper function for marking nodes in the anchor
1860 * symbol table.
1861 */
1862 void
syck_out_mark(VALUE emitter,VALUE node)1863 syck_out_mark(VALUE emitter, VALUE node)
1864 {
1865 SyckEmitter *emitterPtr;
1866 struct emitter_xtra *bonus;
1867 Data_Get_Struct(emitter, SyckEmitter, emitterPtr);
1868 bonus = (struct emitter_xtra *)emitterPtr->bonus;
1869 rb_ivar_set( node, s_emitter, emitter );
1870 /* syck_emitter_mark_node( emitterPtr, (st_data_t)node ); */
1871 if ( !NIL_P( bonus->oid ) ) {
1872 rb_hash_aset( bonus->data, bonus->oid, node );
1873 }
1874 }
1875
1876 /*
1877 * Mark emitter values.
1878 */
1879 static void
syck_mark_emitter(SyckEmitter * emitter)1880 syck_mark_emitter(SyckEmitter *emitter)
1881 {
1882 struct emitter_xtra *bonus = (struct emitter_xtra *)emitter->bonus;
1883 rb_gc_mark( bonus->oid );
1884 rb_gc_mark( bonus->data );
1885 rb_gc_mark( bonus->port );
1886 }
1887
1888 /*
1889 * Free the emitter and any bonus attachment.
1890 */
1891 void
rb_syck_free_emitter(SyckEmitter * e)1892 rb_syck_free_emitter(SyckEmitter *e)
1893 {
1894 S_FREE( e->bonus );
1895 syck_free_emitter(e);
1896 }
1897
1898 /*
1899 * YAML::Syck::Emitter.allocate
1900 */
1901 VALUE syck_emitter_s_alloc _((VALUE));
1902 VALUE
syck_emitter_s_alloc(VALUE class)1903 syck_emitter_s_alloc(VALUE class)
1904 {
1905 VALUE pobj;
1906 SyckEmitter *emitter = syck_new_emitter();
1907
1908 emitter->bonus = S_ALLOC( struct emitter_xtra );
1909 S_MEMZERO( emitter->bonus, struct emitter_xtra, 1 );
1910
1911 pobj = Data_Wrap_Struct( class, syck_mark_emitter, rb_syck_free_emitter, emitter );
1912 syck_emitter_handler( emitter, rb_syck_emitter_handler );
1913 syck_output_handler( emitter, rb_syck_output_handler );
1914
1915 rb_ivar_set( pobj, s_out, rb_funcall( cOut, s_new, 1, pobj ) );
1916 return pobj;
1917 }
1918
1919 /*
1920 * YAML::Syck::Emitter.reset( options )
1921 */
1922 VALUE
syck_emitter_reset(int argc,VALUE * argv,VALUE self)1923 syck_emitter_reset(int argc, VALUE *argv, VALUE self)
1924 {
1925 VALUE options, tmp;
1926 SyckEmitter *emitter;
1927 struct emitter_xtra *bonus;
1928
1929 Data_Get_Struct(self, SyckEmitter, emitter);
1930 bonus = (struct emitter_xtra *)emitter->bonus;
1931
1932 bonus->oid = Qnil;
1933 bonus->port = rb_str_new2( "" );
1934 bonus->data = rb_hash_new();
1935
1936 if (rb_scan_args(argc, argv, "01", &options) == 0)
1937 {
1938 options = rb_hash_new();
1939 rb_ivar_set(self, s_options, options);
1940 }
1941 else if ( !NIL_P(tmp = rb_check_string_type(options)) )
1942 {
1943 bonus->port = tmp;
1944 }
1945 else if ( rb_respond_to( options, s_write ) )
1946 {
1947 bonus->port = options;
1948 }
1949 else
1950 {
1951 Check_Type(options, T_HASH);
1952 rb_ivar_set(self, s_options, options);
1953 }
1954
1955 emitter->headless = 0;
1956 rb_ivar_set(self, s_level, INT2FIX(0));
1957 rb_ivar_set(self, s_resolver, Qnil);
1958 return self;
1959 }
1960
1961 /*
1962 * YAML::Syck::Emitter.emit( object_id ) { |out| ... }
1963 */
1964 VALUE
syck_emitter_emit(int argc,VALUE * argv,VALUE self)1965 syck_emitter_emit(int argc, VALUE *argv, VALUE self)
1966 {
1967 VALUE oid, proc;
1968 char *anchor_name;
1969 SyckEmitter *emitter;
1970 struct emitter_xtra *bonus;
1971 SYMID symple;
1972 int level = FIX2INT(rb_ivar_get(self, s_level)) + 1;
1973 rb_ivar_set(self, s_level, INT2FIX(level));
1974
1975 rb_scan_args(argc, argv, "1&", &oid, &proc);
1976 Data_Get_Struct(self, SyckEmitter, emitter);
1977 bonus = (struct emitter_xtra *)emitter->bonus;
1978
1979 /* Calculate anchors, normalize nodes, build a simpler symbol table */
1980 bonus->oid = oid;
1981 if ( !NIL_P( oid ) && RTEST( rb_funcall( bonus->data, s_haskey, 1, oid ) ) ) {
1982 symple = rb_hash_aref( bonus->data, oid );
1983 } else {
1984 symple = rb_funcall( proc, s_call, 1, rb_ivar_get( self, s_out ) );
1985 }
1986 syck_emitter_mark_node( emitter, (st_data_t)symple );
1987
1988 /* Second pass, build emitted string */
1989 level -= 1;
1990 rb_ivar_set(self, s_level, INT2FIX(level));
1991 if ( level == 0 )
1992 {
1993 syck_emit(emitter, (st_data_t)symple);
1994 syck_emitter_flush(emitter, 0);
1995
1996 return bonus->port;
1997 }
1998
1999 return symple;
2000 }
2001
2002 /*
2003 * YAML::Syck::Emitter#node_export
2004 */
2005 VALUE
syck_emitter_node_export(VALUE self,VALUE node)2006 syck_emitter_node_export(VALUE self, VALUE node)
2007 {
2008 return rb_funcall( node, s_to_yaml, 1, self );
2009 }
2010
2011 /*
2012 * YAML::Syck::Emitter#set_resolver
2013 */
2014 VALUE
syck_emitter_set_resolver(VALUE self,VALUE resolver)2015 syck_emitter_set_resolver(VALUE self, VALUE resolver)
2016 {
2017 rb_ivar_set( self, s_resolver, resolver );
2018 return self;
2019 }
2020
2021 /*
2022 * YAML::Syck::Out::initialize
2023 */
2024 VALUE
syck_out_initialize(VALUE self,VALUE emitter)2025 syck_out_initialize(VALUE self, VALUE emitter)
2026 {
2027 rb_ivar_set( self, s_emitter, emitter );
2028 return self;
2029 }
2030
2031 /*
2032 * YAML::Syck::Out::map
2033 */
2034 VALUE
syck_out_map(int argc,VALUE * argv,VALUE self)2035 syck_out_map(int argc, VALUE *argv, VALUE self)
2036 {
2037 VALUE type_id, style, map;
2038 if (rb_scan_args(argc, argv, "11", &type_id, &style) == 1) {
2039 style = Qnil;
2040 }
2041 map = rb_funcall( cMap, s_new, 3, type_id, rb_hash_new(), style );
2042 syck_out_mark( rb_ivar_get( self, s_emitter ), map );
2043 rb_yield( map );
2044 return map;
2045 }
2046
2047 /*
2048 * YAML::Syck::Out::seq
2049 */
2050 VALUE
syck_out_seq(int argc,VALUE * argv,VALUE self)2051 syck_out_seq(int argc, VALUE *argv, VALUE self)
2052 {
2053 VALUE type_id, style, seq;
2054 if (rb_scan_args(argc, argv, "11", &type_id, &style) == 1) {
2055 style = Qnil;
2056 }
2057 seq = rb_funcall( cSeq, s_new, 3, type_id, rb_ary_new(), style );
2058 syck_out_mark( rb_ivar_get( self, s_emitter ), seq );
2059 rb_yield( seq );
2060 return seq;
2061 }
2062
2063 /*
2064 * YAML::Syck::Out::scalar
2065 syck_out_scalar( self, type_id, str, style )
2066 VALUE self, type_id, str, style;
2067 */
2068 VALUE
syck_out_scalar(int argc,VALUE * argv,VALUE self)2069 syck_out_scalar(int argc, VALUE *argv, VALUE self)
2070 {
2071 VALUE type_id, str, style, scalar;
2072 if (rb_scan_args(argc, argv, "21", &type_id, &str, &style) == 2) {
2073 style = Qnil;
2074 }
2075 scalar = rb_funcall( cScalar, s_new, 3, type_id, str, style );
2076 syck_out_mark( rb_ivar_get( self, s_emitter ), scalar );
2077 return scalar;
2078 }
2079
2080 /*
2081 * Initialize Syck extension
2082 */
2083 void
Init_syck()2084 Init_syck()
2085 {
2086 VALUE rb_yaml = rb_define_module( "YAML" );
2087 VALUE rb_syck = rb_define_module_under( rb_yaml, "Syck" );
2088 rb_define_const( rb_syck, "VERSION", rb_str_new2( SYCK_VERSION ) );
2089 rb_define_module_function( rb_syck, "compile", rb_syck_compile, 1 );
2090
2091 /*
2092 * Global symbols
2093 */
2094 s_new = rb_intern("new");
2095 s_utc = rb_intern("utc");
2096 s_at = rb_intern("at");
2097 s_to_f = rb_intern("to_f");
2098 s_to_i = rb_intern("to_i");
2099 s_read = rb_intern("read");
2100 s_binmode = rb_intern("binmode");
2101 s_transfer = rb_intern("transfer");
2102 s_call = rb_intern("call");
2103 s_cmp = rb_intern("<=>");
2104 s_intern = rb_intern("intern");
2105 s_update = rb_intern("update");
2106 s_detect_implicit = rb_intern("detect_implicit");
2107 s_dup = rb_intern("dup");
2108 s_default_set = rb_intern("default=");
2109 s_match = rb_intern("match");
2110 s_push = rb_intern("push");
2111 s_haskey = rb_intern("has_key?");
2112 s_keys = rb_intern("keys");
2113 s_node_import = rb_intern("node_import");
2114 s_tr_bang = rb_intern("tr!");
2115 s_unpack = rb_intern("unpack");
2116 s_write = rb_intern("write");
2117 s_tag_read_class = rb_intern( "yaml_tag_read_class" );
2118 s_tag_subclasses = rb_intern( "yaml_tag_subclasses?" );
2119 s_emitter = rb_intern( "emitter" );
2120 s_set_resolver = rb_intern( "set_resolver" );
2121 s_node_export = rb_intern( "node_export" );
2122 s_to_yaml = rb_intern( "to_yaml" );
2123 s_transform = rb_intern( "transform" );
2124 s_yaml_new = rb_intern("yaml_new");
2125 s_yaml_initialize = rb_intern("yaml_initialize");
2126 s_each = rb_intern("each");
2127
2128 s_tags = rb_intern("@tags");
2129 s_name = rb_intern("@name");
2130 s_options = rb_intern("@options");
2131 s_kind = rb_intern("@kind");
2132 s_type_id = rb_intern("@type_id");
2133 s_type_id_set = rb_intern("type_id=");
2134 s_resolver = rb_intern("@resolver");
2135 s_level = rb_intern( "@level" );
2136 s_style = rb_intern("@style");
2137 s_style_set = rb_intern("style=");
2138 s_value = rb_intern("@value");
2139 s_value_set = rb_intern("value=");
2140 s_out = rb_intern("@out");
2141 s_input = rb_intern("@input");
2142
2143 sym_model = ID2SYM(rb_intern("Model"));
2144 sym_generic = ID2SYM(rb_intern("Generic"));
2145 sym_bytecode = ID2SYM(rb_intern("bytecode"));
2146 sym_map = ID2SYM(rb_intern("map"));
2147 sym_scalar = ID2SYM(rb_intern("scalar"));
2148 sym_seq = ID2SYM(rb_intern("seq"));
2149 sym_1quote = ID2SYM(rb_intern("quote1"));
2150 sym_2quote = ID2SYM(rb_intern("quote2"));
2151 sym_fold = ID2SYM(rb_intern("fold"));
2152 sym_literal = ID2SYM(rb_intern("literal"));
2153 sym_plain = ID2SYM(rb_intern("plain"));
2154 sym_inline = ID2SYM(rb_intern("inline"));
2155
2156 /*
2157 * Define YAML::Syck::Resolver class
2158 */
2159 cResolver = rb_define_class_under( rb_syck, "Resolver", rb_cObject );
2160 rb_define_attr( cResolver, "tags", 1, 1 );
2161 rb_define_method( cResolver, "initialize", syck_resolver_initialize, 0 );
2162 rb_define_method( cResolver, "add_type", syck_resolver_add_type, 2 );
2163 rb_define_method( cResolver, "use_types_at", syck_resolver_use_types_at, 1 );
2164 rb_define_method( cResolver, "detect_implicit", syck_resolver_detect_implicit, 1 );
2165 rb_define_method( cResolver, "transfer", syck_resolver_transfer, 2 );
2166 rb_define_method( cResolver, "node_import", syck_resolver_node_import, 1 );
2167 rb_define_method( cResolver, "tagurize", syck_resolver_tagurize, 1 );
2168
2169 rb_global_variable( &oDefaultResolver );
2170 oDefaultResolver = rb_funcall( cResolver, rb_intern( "new" ), 0 );
2171 rb_define_singleton_method( oDefaultResolver, "node_import", syck_defaultresolver_node_import, 1 );
2172 rb_define_singleton_method( oDefaultResolver, "detect_implicit", syck_defaultresolver_detect_implicit, 1 );
2173 rb_define_const( rb_syck, "DefaultResolver", oDefaultResolver );
2174 rb_global_variable( &oGenericResolver );
2175 oGenericResolver = rb_funcall( cResolver, rb_intern( "new" ), 0 );
2176 rb_define_singleton_method( oGenericResolver, "node_import", syck_genericresolver_node_import, 1 );
2177 rb_define_const( rb_syck, "GenericResolver", oGenericResolver );
2178
2179 /*
2180 * Define YAML::Syck::Parser class
2181 */
2182 cParser = rb_define_class_under( rb_syck, "Parser", rb_cObject );
2183 rb_define_attr( cParser, "options", 1, 1 );
2184 rb_define_attr( cParser, "resolver", 1, 1 );
2185 rb_define_attr( cParser, "input", 1, 1 );
2186 rb_define_alloc_func( cParser, syck_parser_s_alloc );
2187 rb_define_method(cParser, "initialize", syck_parser_initialize, -1 );
2188 rb_define_method(cParser, "bufsize=", syck_parser_bufsize_set, 1 );
2189 rb_define_method(cParser, "bufsize", syck_parser_bufsize_get, 0 );
2190 rb_define_method(cParser, "load", syck_parser_load, -1);
2191 rb_define_method(cParser, "load_documents", syck_parser_load_documents, -1);
2192 rb_define_method(cParser, "set_resolver", syck_parser_set_resolver, 1);
2193
2194 /*
2195 * Define YAML::Syck::Node class
2196 */
2197 cNode = rb_define_class_under( rb_syck, "Node", rb_cObject );
2198 rb_define_method( cNode, "initialize_copy", syck_node_init_copy, 1 );
2199 rb_define_attr( cNode, "emitter", 1, 1 );
2200 rb_define_attr( cNode, "resolver", 1, 1 );
2201 rb_define_attr( cNode, "kind", 1, 0 );
2202 rb_define_attr( cNode, "type_id", 1, 0 );
2203 rb_define_attr( cNode, "value", 1, 0 );
2204 rb_define_method( cNode, "type_id=", syck_node_type_id_set, 1 );
2205 rb_define_method( cNode, "transform", syck_node_transform, 0);
2206
2207 /*
2208 * Define YAML::Syck::Scalar, YAML::Syck::Seq, YAML::Syck::Map --
2209 * all are the publicly usable variants of YAML::Syck::Node
2210 */
2211 cScalar = rb_define_class_under( rb_syck, "Scalar", cNode );
2212 rb_define_alloc_func( cScalar, syck_scalar_alloc );
2213 rb_define_attr( cNode, "value", 1, 0 );
2214 rb_define_method( cScalar, "initialize", syck_scalar_initialize, 3 );
2215 rb_define_method( cScalar, "value=", syck_scalar_value_set, 1 );
2216 rb_define_method( cScalar, "style=", syck_scalar_style_set, 1 );
2217 cSeq = rb_define_class_under( rb_syck, "Seq", cNode );
2218 rb_define_alloc_func( cSeq, syck_seq_alloc );
2219 rb_define_method( cSeq, "initialize", syck_seq_initialize, 3 );
2220 rb_define_method( cSeq, "value=", syck_seq_value_set, 1 );
2221 rb_define_method( cSeq, "add", syck_seq_add_m, 1 );
2222 rb_define_method( cSeq, "style=", syck_seq_style_set, 1 );
2223 cMap = rb_define_class_under( rb_syck, "Map", cNode );
2224 rb_define_alloc_func( cMap, syck_map_alloc );
2225 rb_define_method( cMap, "initialize", syck_map_initialize, 3 );
2226 rb_define_method( cMap, "value=", syck_map_value_set, 1 );
2227 rb_define_method( cMap, "add", syck_map_add_m, 2 );
2228 rb_define_method( cMap, "style=", syck_map_style_set, 1 );
2229
2230 /*
2231 * Define YAML::PrivateType class
2232 */
2233 cPrivateType = rb_define_class_under( rb_yaml, "PrivateType", rb_cObject );
2234 rb_define_attr( cPrivateType, "type_id", 1, 1 );
2235 rb_define_attr( cPrivateType, "value", 1, 1 );
2236 rb_define_method( cPrivateType, "initialize", syck_privatetype_initialize, 2);
2237
2238 /*
2239 * Define YAML::DomainType class
2240 */
2241 cDomainType = rb_define_class_under( rb_yaml, "DomainType", rb_cObject );
2242 rb_define_attr( cDomainType, "domain", 1, 1 );
2243 rb_define_attr( cDomainType, "type_id", 1, 1 );
2244 rb_define_attr( cDomainType, "value", 1, 1 );
2245 rb_define_method( cDomainType, "initialize", syck_domaintype_initialize, 3);
2246
2247 /*
2248 * Define YAML::Object class
2249 */
2250 cYObject = rb_define_class_under( rb_yaml, "Object", rb_cObject );
2251 rb_define_attr( cYObject, "class", 1, 1 );
2252 rb_define_attr( cYObject, "ivars", 1, 1 );
2253 rb_define_method( cYObject, "initialize", syck_yobject_initialize, 2);
2254 rb_define_method( cYObject, "yaml_initialize", syck_yobject_initialize, 2);
2255
2256 /*
2257 * Define YAML::Syck::BadAlias class
2258 */
2259 cBadAlias = rb_define_class_under( rb_syck, "BadAlias", rb_cObject );
2260 rb_define_attr( cBadAlias, "name", 1, 1 );
2261 rb_define_method( cBadAlias, "initialize", syck_badalias_initialize, 1);
2262 rb_define_method( cBadAlias, "<=>", syck_badalias_cmp, 1);
2263 rb_include_module( cBadAlias, rb_const_get( rb_cObject, rb_intern("Comparable") ) );
2264
2265 /*
2266 * Define YAML::Syck::MergeKey class
2267 */
2268 cMergeKey = rb_define_class_under( rb_syck, "MergeKey", rb_cObject );
2269
2270 /*
2271 * Define YAML::Syck::DefaultKey class
2272 */
2273 cDefaultKey = rb_define_class_under( rb_syck, "DefaultKey", rb_cObject );
2274
2275 /*
2276 * Define YAML::Syck::Out classes
2277 */
2278 cOut = rb_define_class_under( rb_syck, "Out", rb_cObject );
2279 rb_define_attr( cOut, "emitter", 1, 1 );
2280 rb_define_method( cOut, "initialize", syck_out_initialize, 1 );
2281 rb_define_method( cOut, "map", syck_out_map, -1 );
2282 rb_define_method( cOut, "seq", syck_out_seq, -1 );
2283 rb_define_method( cOut, "scalar", syck_out_scalar, -1 );
2284
2285 /*
2286 * Define YAML::Syck::Emitter class
2287 */
2288 cEmitter = rb_define_class_under( rb_syck, "Emitter", rb_cObject );
2289 rb_define_attr( cEmitter, "level", 1, 1 );
2290 rb_define_alloc_func( cEmitter, syck_emitter_s_alloc );
2291 rb_define_method( cEmitter, "initialize", syck_emitter_reset, -1 );
2292 rb_define_method( cEmitter, "reset", syck_emitter_reset, -1 );
2293 rb_define_method( cEmitter, "emit", syck_emitter_emit, -1 );
2294 rb_define_method( cEmitter, "set_resolver", syck_emitter_set_resolver, 1);
2295 rb_define_method( cEmitter, "node_export", syck_emitter_node_export, 1);
2296 }
2297
2298