rubysl-syck 1.0.1

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