rubysl-syck 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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
+