Ruby 2.7.0p0(2019-12-25revision647ee6f091eafcce70ffb75ddf7e121e192ab217)

psych_emitter.c
Go to the documentation of this file.
1 #include <psych.h>
2
3 #if !defined(RARRAY_CONST_PTR)
4 #define RARRAY_CONST_PTR(s) (const VALUE *)RARRAY_PTR(s)
5 #endif
6 #if !defined(RARRAY_AREF)
7 #define RARRAY_AREF(a, i) RARRAY_CONST_PTR(a)[i]
8 #endif
9
10 VALUE cPsychEmitter;
11 static ID id_io;
12 static ID id_write;
13 static ID id_line_width;
14 static ID id_indentation;
15 static ID id_canonical;
16
17 static void emit(yaml_emitter_t * emitter, yaml_event_t * event)
18 {
19 if(!yaml_emitter_emit(emitter, event))
20 rb_raise(rb_eRuntimeError, "%s", emitter->problem);
21 }
22
23 static int writer(void *ctx, unsigned char *buffer, size_t size)
24 {
25 VALUE self = (VALUE)ctx, io = rb_attr_get(self, id_io);
26 VALUE str = rb_enc_str_new((const char *)buffer, (long)size, rb_utf8_encoding());
27 VALUE wrote = rb_funcall(io, id_write, 1, str);
28 return (int)NUM2INT(wrote);
29 }
30
31 static void dealloc(void * ptr)
32 {
33 yaml_emitter_t * emitter;
34
35 emitter = (yaml_emitter_t *)ptr;
36 yaml_emitter_delete(emitter);
37 xfree(emitter);
38 }
39
40 #if 0
41 static size_t memsize(const void *ptr)
42 {
43 const yaml_emitter_t *emitter = ptr;
44 /* TODO: calculate emitter's size */
45 return 0;
46 }
47 #endif
48
49 static const rb_data_type_t psych_emitter_type = {
50 "Psych/emitter",
51 {0, dealloc, 0,},
52 0, 0,
53 #ifdef RUBY_TYPED_FREE_IMMEDIATELY
54 RUBY_TYPED_FREE_IMMEDIATELY,
55 #endif
56 };
57
58 static VALUE allocate(VALUE klass)
59 {
60 yaml_emitter_t * emitter;
61 VALUE obj = TypedData_Make_Struct(klass, yaml_emitter_t, &psych_emitter_type, emitter);
62
63 yaml_emitter_initialize(emitter);
64 yaml_emitter_set_unicode(emitter, 1);
65 yaml_emitter_set_indent(emitter, 2);
66
67 return obj;
68 }
69
70 /* call-seq: Psych::Emitter.new(io, options = Psych::Emitter::OPTIONS)
71 *
72 * Create a new Psych::Emitter that writes to +io+.
73 */
74 static VALUE initialize(int argc, VALUE *argv, VALUE self)
75 {
76 yaml_emitter_t * emitter;
77 VALUE io, options;
78 VALUE line_width;
79 VALUE indent;
80 VALUE canonical;
81
82 TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter);
83
84 if (rb_scan_args(argc, argv, "11", &io, &options) == 2) {
85 line_width = rb_funcall(options, id_line_width, 0);
86 indent = rb_funcall(options, id_indentation, 0);
87 canonical = rb_funcall(options, id_canonical, 0);
88
89 yaml_emitter_set_width(emitter, NUM2INT(line_width));
90 yaml_emitter_set_indent(emitter, NUM2INT(indent));
91 yaml_emitter_set_canonical(emitter, Qtrue == canonical ? 1 : 0);
92 }
93
94 rb_ivar_set(self, id_io, io);
95 yaml_emitter_set_output(emitter, writer, (void *)self);
96
97 return self;
98 }
99
100 /* call-seq: emitter.start_stream(encoding)
101 *
102 * Start a stream emission with +encoding+
103 *
104 * See Psych::Handler#start_stream
105 */
106 static VALUE start_stream(VALUE self, VALUE encoding)
107 {
108 yaml_emitter_t * emitter;
109 yaml_event_t event;
110 TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter);
111 Check_Type(encoding, T_FIXNUM);
112
113 yaml_stream_start_event_initialize(&event, (yaml_encoding_t)NUM2INT(encoding));
114
115 emit(emitter, &event);
116
117 return self;
118 }
119
120 /* call-seq: emitter.end_stream
121 *
122 * End a stream emission
123 *
124 * See Psych::Handler#end_stream
125 */
126 static VALUE end_stream(VALUE self)
127 {
128 yaml_emitter_t * emitter;
129 yaml_event_t event;
130 TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter);
131
132 yaml_stream_end_event_initialize(&event);
133
134 emit(emitter, &event);
135
136 return self;
137 }
138
139 /* call-seq: emitter.start_document(version, tags, implicit)
140 *
141 * Start a document emission with YAML +version+, +tags+, and an +implicit+
142 * start.
143 *
144 * See Psych::Handler#start_document
145 */
146 static VALUE start_document(VALUE self, VALUE version, VALUE tags, VALUE imp)
147 {
148 yaml_emitter_t * emitter;
149 yaml_tag_directive_t * head = NULL;
150 yaml_tag_directive_t * tail = NULL;
151 yaml_event_t event;
152 yaml_version_directive_t version_directive;
153 TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter);
154
155
156 Check_Type(version, T_ARRAY);
157
158 if(RARRAY_LEN(version) > 0) {
159 VALUE major = rb_ary_entry(version, (long)0);
160 VALUE minor = rb_ary_entry(version, (long)1);
161
162 version_directive.major = NUM2INT(major);
163 version_directive.minor = NUM2INT(minor);
164 }
165
166 if(RTEST(tags)) {
167 long i = 0;
168 long len;
169 rb_encoding * encoding = rb_utf8_encoding();
170
171 Check_Type(tags, T_ARRAY);
172
173 len = RARRAY_LEN(tags);
174 head = xcalloc((size_t)len, sizeof(yaml_tag_directive_t));
175 tail = head;
176
177 for(i = 0; i < len && i < RARRAY_LEN(tags); i++) {
178 VALUE tuple = RARRAY_AREF(tags, i);
179 VALUE name;
180 VALUE value;
181
182 Check_Type(tuple, T_ARRAY);
183
184 if(RARRAY_LEN(tuple) < 2) {
185 xfree(head);
186 rb_raise(rb_eRuntimeError, "tag tuple must be of length 2");
187 }
188 name = RARRAY_AREF(tuple, 0);
189 value = RARRAY_AREF(tuple, 1);
190 StringValue(name);
191 StringValue(value);
192 name = rb_str_export_to_enc(name, encoding);
193 value = rb_str_export_to_enc(value, encoding);
194
195 tail->handle = (yaml_char_t *)StringValueCStr(name);
196 tail->prefix = (yaml_char_t *)StringValueCStr(value);
197
198 tail++;
199 }
200 }
201
202 yaml_document_start_event_initialize(
203 &event,
204 (RARRAY_LEN(version) > 0) ? &version_directive : NULL,
205 head,
206 tail,
207 imp ? 1 : 0
208 );
209
210 emit(emitter, &event);
211
212 if(head) xfree(head);
213
214 return self;
215 }
216
217 /* call-seq: emitter.end_document(implicit)
218 *
219 * End a document emission with an +implicit+ ending.
220 *
221 * See Psych::Handler#end_document
222 */
223 static VALUE end_document(VALUE self, VALUE imp)
224 {
225 yaml_emitter_t * emitter;
226 yaml_event_t event;
227 TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter);
228
229 yaml_document_end_event_initialize(&event, imp ? 1 : 0);
230
231 emit(emitter, &event);
232
233 return self;
234 }
235
236 /* call-seq: emitter.scalar(value, anchor, tag, plain, quoted, style)
237 *
238 * Emit a scalar with +value+, +anchor+, +tag+, and a +plain+ or +quoted+
239 * string type with +style+.
240 *
241 * See Psych::Handler#scalar
242 */
243 static VALUE scalar(
244 VALUE self,
245 VALUE value,
246 VALUE anchor,
247 VALUE tag,
248 VALUE plain,
249 VALUE quoted,
250 VALUE style
251 ) {
252 yaml_emitter_t * emitter;
253 yaml_event_t event;
254 rb_encoding *encoding;
255 TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter);
256
257 Check_Type(value, T_STRING);
258
259 encoding = rb_utf8_encoding();
260
261 value = rb_str_export_to_enc(value, encoding);
262
263 if(!NIL_P(anchor)) {
264 Check_Type(anchor, T_STRING);
265 anchor = rb_str_export_to_enc(anchor, encoding);
266 }
267
268 if(!NIL_P(tag)) {
269 Check_Type(tag, T_STRING);
270 tag = rb_str_export_to_enc(tag, encoding);
271 }
272
273 yaml_scalar_event_initialize(
274 &event,
275 (yaml_char_t *)(NIL_P(anchor) ? NULL : StringValueCStr(anchor)),
276 (yaml_char_t *)(NIL_P(tag) ? NULL : StringValueCStr(tag)),
277 (yaml_char_t*)StringValuePtr(value),
278 (int)RSTRING_LEN(value),
279 plain ? 1 : 0,
280 quoted ? 1 : 0,
281 (yaml_scalar_style_t)NUM2INT(style)
282 );
283
284 emit(emitter, &event);
285
286 return self;
287 }
288
289 /* call-seq: emitter.start_sequence(anchor, tag, implicit, style)
290 *
291 * Start emitting a sequence with +anchor+, a +tag+, +implicit+ sequence
292 * start and end, along with +style+.
293 *
294 * See Psych::Handler#start_sequence
295 */
296 static VALUE start_sequence(
297 VALUE self,
298 VALUE anchor,
299 VALUE tag,
300 VALUE implicit,
301 VALUE style
302 ) {
303 yaml_emitter_t * emitter;
304 yaml_event_t event;
305
306 rb_encoding * encoding = rb_utf8_encoding();
307
308 if(!NIL_P(anchor)) {
309 Check_Type(anchor, T_STRING);
310 anchor = rb_str_export_to_enc(anchor, encoding);
311 }
312
313 if(!NIL_P(tag)) {
314 Check_Type(tag, T_STRING);
315 tag = rb_str_export_to_enc(tag, encoding);
316 }
317
318 TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter);
319
320 yaml_sequence_start_event_initialize(
321 &event,
322 (yaml_char_t *)(NIL_P(anchor) ? NULL : StringValueCStr(anchor)),
323 (yaml_char_t *)(NIL_P(tag) ? NULL : StringValueCStr(tag)),
324 implicit ? 1 : 0,
325 (yaml_sequence_style_t)NUM2INT(style)
326 );
327
328 emit(emitter, &event);
329
330 return self;
331 }
332
333 /* call-seq: emitter.end_sequence
334 *
335 * End sequence emission.
336 *
337 * See Psych::Handler#end_sequence
338 */
339 static VALUE end_sequence(VALUE self)
340 {
341 yaml_emitter_t * emitter;
342 yaml_event_t event;
343 TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter);
344
345 yaml_sequence_end_event_initialize(&event);
346
347 emit(emitter, &event);
348
349 return self;
350 }
351
352 /* call-seq: emitter.start_mapping(anchor, tag, implicit, style)
353 *
354 * Start emitting a YAML map with +anchor+, +tag+, an +implicit+ start
355 * and end, and +style+.
356 *
357 * See Psych::Handler#start_mapping
358 */
359 static VALUE start_mapping(
360 VALUE self,
361 VALUE anchor,
362 VALUE tag,
363 VALUE implicit,
364 VALUE style
365 ) {
366 yaml_emitter_t * emitter;
367 yaml_event_t event;
368 rb_encoding *encoding;
369
370 TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter);
371
372 encoding = rb_utf8_encoding();
373
374 if(!NIL_P(anchor)) {
375 Check_Type(anchor, T_STRING);
376 anchor = rb_str_export_to_enc(anchor, encoding);
377 }
378
379 if(!NIL_P(tag)) {
380 Check_Type(tag, T_STRING);
381 tag = rb_str_export_to_enc(tag, encoding);
382 }
383
384 yaml_mapping_start_event_initialize(
385 &event,
386 (yaml_char_t *)(NIL_P(anchor) ? NULL : StringValueCStr(anchor)),
387 (yaml_char_t *)(NIL_P(tag) ? NULL : StringValueCStr(tag)),
388 implicit ? 1 : 0,
389 (yaml_mapping_style_t)NUM2INT(style)
390 );
391
392 emit(emitter, &event);
393
394 return self;
395 }
396
397 /* call-seq: emitter.end_mapping
398 *
399 * Emit the end of a mapping.
400 *
401 * See Psych::Handler#end_mapping
402 */
403 static VALUE end_mapping(VALUE self)
404 {
405 yaml_emitter_t * emitter;
406 yaml_event_t event;
407 TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter);
408
409 yaml_mapping_end_event_initialize(&event);
410
411 emit(emitter, &event);
412
413 return self;
414 }
415
416 /* call-seq: emitter.alias(anchor)
417 *
418 * Emit an alias with +anchor+.
419 *
420 * See Psych::Handler#alias
421 */
422 static VALUE alias(VALUE self, VALUE anchor)
423 {
424 yaml_emitter_t * emitter;
425 yaml_event_t event;
426 TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter);
427
428 if(!NIL_P(anchor)) {
429 Check_Type(anchor, T_STRING);
430 anchor = rb_str_export_to_enc(anchor, rb_utf8_encoding());
431 }
432
433 yaml_alias_event_initialize(
434 &event,
435 (yaml_char_t *)(NIL_P(anchor) ? NULL : StringValueCStr(anchor))
436 );
437
438 emit(emitter, &event);
439
440 return self;
441 }
442
443 /* call-seq: emitter.canonical = true
444 *
445 * Set the output style to canonical, or not.
446 */
447 static VALUE set_canonical(VALUE self, VALUE style)
448 {
449 yaml_emitter_t * emitter;
450 TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter);
451
452 yaml_emitter_set_canonical(emitter, Qtrue == style ? 1 : 0);
453
454 return style;
455 }
456
457 /* call-seq: emitter.canonical
458 *
459 * Get the output style, canonical or not.
460 */
461 static VALUE canonical(VALUE self)
462 {
463 yaml_emitter_t * emitter;
464 TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter);
465
466 return (emitter->canonical == 0) ? Qfalse : Qtrue;
467 }
468
469 /* call-seq: emitter.indentation = level
470 *
471 * Set the indentation level to +level+. The level must be less than 10 and
472 * greater than 1.
473 */
474 static VALUE set_indentation(VALUE self, VALUE level)
475 {
476 yaml_emitter_t * emitter;
477 TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter);
478
479 yaml_emitter_set_indent(emitter, NUM2INT(level));
480
481 return level;
482 }
483
484 /* call-seq: emitter.indentation
485 *
486 * Get the indentation level.
487 */
488 static VALUE indentation(VALUE self)
489 {
490 yaml_emitter_t * emitter;
491 TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter);
492
493 return INT2NUM(emitter->best_indent);
494 }
495
496 /* call-seq: emitter.line_width
497 *
498 * Get the preferred line width.
499 */
500 static VALUE line_width(VALUE self)
501 {
502 yaml_emitter_t * emitter;
503 TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter);
504
505 return INT2NUM(emitter->best_width);
506 }
507
508 /* call-seq: emitter.line_width = width
509 *
510 * Set the preferred line with to +width+.
511 */
512 static VALUE set_line_width(VALUE self, VALUE width)
513 {
514 yaml_emitter_t * emitter;
515 TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter);
516
517 yaml_emitter_set_width(emitter, NUM2INT(width));
518
519 return width;
520 }
521
522 void Init_psych_emitter(void)
523 {
524 #undef rb_intern
525 VALUE psych = rb_define_module("Psych");
526 VALUE handler = rb_define_class_under(psych, "Handler", rb_cObject);
527 cPsychEmitter = rb_define_class_under(psych, "Emitter", handler);
528
529 rb_define_alloc_func(cPsychEmitter, allocate);
530
531 rb_define_method(cPsychEmitter, "initialize", initialize, -1);
532 rb_define_method(cPsychEmitter, "start_stream", start_stream, 1);
533 rb_define_method(cPsychEmitter, "end_stream", end_stream, 0);
534 rb_define_method(cPsychEmitter, "start_document", start_document, 3);
535 rb_define_method(cPsychEmitter, "end_document", end_document, 1);
536 rb_define_method(cPsychEmitter, "scalar", scalar, 6);
537 rb_define_method(cPsychEmitter, "start_sequence", start_sequence, 4);
538 rb_define_method(cPsychEmitter, "end_sequence", end_sequence, 0);
539 rb_define_method(cPsychEmitter, "start_mapping", start_mapping, 4);
540 rb_define_method(cPsychEmitter, "end_mapping", end_mapping, 0);
541 rb_define_method(cPsychEmitter, "alias", alias, 1);
542 rb_define_method(cPsychEmitter, "canonical", canonical, 0);
543 rb_define_method(cPsychEmitter, "canonical=", set_canonical, 1);
544 rb_define_method(cPsychEmitter, "indentation", indentation, 0);
545 rb_define_method(cPsychEmitter, "indentation=", set_indentation, 1);
546 rb_define_method(cPsychEmitter, "line_width", line_width, 0);
547 rb_define_method(cPsychEmitter, "line_width=", set_line_width, 1);
548
549 id_io = rb_intern("io");
550 id_write = rb_intern("write");
551 id_line_width = rb_intern("line_width");
552 id_indentation = rb_intern("indentation");
553 id_canonical = rb_intern("canonical");
554 }
555 /* vim: set noet sws=4 sw=4: */
ID
unsigned long ID
Definition: ruby.h:103
TypedData_Make_Struct
#define TypedData_Make_Struct(klass, type, data_type, sval)
Definition: ruby.h:1244
Check_Type
#define Check_Type(v, t)
Definition: ruby.h:595
xcalloc
#define xcalloc
Definition: defines.h:213
rb_scan_args
#define rb_scan_args(argc, argvp, fmt,...)
Definition: rb_mjit_min_header-2.7.0.h:6372
rb_attr_get
VALUE rb_attr_get(VALUE, ID)
Definition: variable.c:1084
VALUE
unsigned long VALUE
Definition: ruby.h:102
rb_intern
#define rb_intern(str)
rb_str_export_to_enc
VALUE rb_str_export_to_enc(VALUE, rb_encoding *)
Definition: string.c:1135
rb_define_module
VALUE rb_define_module(const char *name)
Definition: class.c:772
alias
const char * alias
Definition: nkf.c:1159
StringValue
use StringValue() instead")))
cPsychEmitter
VALUE cPsychEmitter
Definition: psych_emitter.c:10
rb_define_method
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Definition: class.c:1551
INT2NUM
#define INT2NUM(x)
Definition: ruby.h:1609
ptr
struct RIMemo * ptr
Definition: debug.c:74
Qfalse
#define Qfalse
Definition: ruby.h:467
NULL
#define NULL
Definition: _sdbm.c:101
major
#define major(dev)
Definition: rb_mjit_min_header-2.7.0.h:1436
psych.h
rb_raise
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:2669
rb_ary_entry
VALUE rb_ary_entry(VALUE ary, long offset)
Definition: array.c:1512
obj
const VALUE VALUE obj
Definition: rb_mjit_min_header-2.7.0.h:5742
Init_psych_emitter
void Init_psych_emitter(void)
Definition: psych_emitter.c:522
rb_encoding
const typedef OnigEncodingType rb_encoding
Definition: encoding.h:115
T_FIXNUM
#define T_FIXNUM
Definition: ruby.h:535
i
uint32_t i
Definition: rb_mjit_min_header-2.7.0.h:5464
rb_eRuntimeError
VALUE rb_eRuntimeError
Definition: error.c:920
RARRAY_AREF
#define RARRAY_AREF(a, i)
Definition: ruby.h:1101
StringValuePtr
#define StringValuePtr(v)
Definition: ruby.h:603
size
int size
Definition: encoding.c:58
StringValueCStr
#define StringValueCStr(v)
Definition: ruby.h:604
RARRAY_LEN
#define RARRAY_LEN(a)
Definition: ruby.h:1070
rb_cObject
RUBY_EXTERN VALUE rb_cObject
Definition: ruby.h:2010
TypedData_Get_Struct
#define TypedData_Get_Struct(obj, type, data_type, sval)
Definition: ruby.h:1252
rb_funcall
#define rb_funcall(recv, mid, argc,...)
Definition: rb_mjit_min_header-2.7.0.h:6585
T_ARRAY
#define T_ARRAY
Definition: ruby.h:530
argv
char ** argv
Definition: ruby.c:223
klass
VALUE klass
Definition: rb_mjit_min_header-2.7.0.h:13254
rb_utf8_encoding
rb_encoding * rb_utf8_encoding(void)
Definition: encoding.c:1328
str
char str[HTML_ESCAPE_MAX_LEN+1]
Definition: escape.c:18
RUBY_TYPED_FREE_IMMEDIATELY
#define RUBY_TYPED_FREE_IMMEDIATELY
Definition: ruby.h:1207
NIL_P
#define NIL_P(v)
Definition: ruby.h:482
argc
int argc
Definition: ruby.c:222
minor
#define minor(dev)
Definition: rb_mjit_min_header-2.7.0.h:1437
rb_data_type_struct
Definition: ruby.h:1148
xfree
#define xfree
Definition: defines.h:216
Qtrue
#define Qtrue
Definition: ruby.h:468
len
uint8_t len
Definition: escape.c:17
rb_ivar_set
VALUE rb_ivar_set(VALUE, ID, VALUE)
Definition: variable.c:1300
T_STRING
#define T_STRING
Definition: ruby.h:528
rb_define_class_under
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition: class.c:698
NUM2INT
#define NUM2INT(x)
Definition: ruby.h:715
RSTRING_LEN
#define RSTRING_LEN(str)
Definition: ruby.h:1005
rb_enc_str_new
VALUE rb_enc_str_new(const char *, long, rb_encoding *)
Definition: string.c:796
rb_define_alloc_func
void rb_define_alloc_func(VALUE, rb_alloc_func_t)
RTEST
#define RTEST(v)
Definition: ruby.h:481
name
const char * name
Definition: nkf.c:208