Ruby  2.5.0dev(2017-10-22revision60238)
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 
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
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 : StringValuePtr(anchor)),
276  (yaml_char_t *)(NIL_P(tag) ? NULL : StringValuePtr(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 : StringValuePtr(anchor)),
323  (yaml_char_t *)(NIL_P(tag) ? NULL : StringValuePtr(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 : StringValuePtr(anchor)),
387  (yaml_char_t *)(NIL_P(tag) ? NULL : StringValuePtr(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 : StringValuePtr(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 
523 {
524  VALUE psych = rb_define_module("Psych");
525  VALUE handler = rb_define_class_under(psych, "Handler", rb_cObject);
526  cPsychEmitter = rb_define_class_under(psych, "Emitter", handler);
527 
529 
530  rb_define_method(cPsychEmitter, "initialize", initialize, -1);
531  rb_define_method(cPsychEmitter, "start_stream", start_stream, 1);
532  rb_define_method(cPsychEmitter, "end_stream", end_stream, 0);
533  rb_define_method(cPsychEmitter, "start_document", start_document, 3);
534  rb_define_method(cPsychEmitter, "end_document", end_document, 1);
535  rb_define_method(cPsychEmitter, "scalar", scalar, 6);
536  rb_define_method(cPsychEmitter, "start_sequence", start_sequence, 4);
537  rb_define_method(cPsychEmitter, "end_sequence", end_sequence, 0);
538  rb_define_method(cPsychEmitter, "start_mapping", start_mapping, 4);
539  rb_define_method(cPsychEmitter, "end_mapping", end_mapping, 0);
540  rb_define_method(cPsychEmitter, "alias", alias, 1);
541  rb_define_method(cPsychEmitter, "canonical", canonical, 0);
542  rb_define_method(cPsychEmitter, "canonical=", set_canonical, 1);
543  rb_define_method(cPsychEmitter, "indentation", indentation, 0);
544  rb_define_method(cPsychEmitter, "indentation=", set_indentation, 1);
545  rb_define_method(cPsychEmitter, "line_width", line_width, 0);
546  rb_define_method(cPsychEmitter, "line_width=", set_line_width, 1);
547 
548  id_io = rb_intern("io");
549  id_write = rb_intern("write");
550  id_line_width = rb_intern("line_width");
551  id_indentation = rb_intern("indentation");
552  id_canonical = rb_intern("canonical");
553 }
554 /* vim: set noet sws=4 sw=4: */
VALUE rb_ary_entry(VALUE ary, long offset)
Definition: array.c:1215
#define RARRAY_LEN(a)
Definition: ruby.h:1019
#define RUBY_TYPED_FREE_IMMEDIATELY
Definition: ruby.h:1138
#define INT2NUM(x)
Definition: ruby.h:1538
#define T_FIXNUM
Definition: ruby.h:503
void Init_psych_emitter(void)
#define NUM2INT(x)
Definition: ruby.h:684
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:2284
#define Qtrue
Definition: ruby.h:437
#define TypedData_Get_Struct(obj, type, data_type, sval)
Definition: ruby.h:1183
VALUE rb_funcall(VALUE, ID, int,...)
Calls a method.
Definition: vm_eval.c:774
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition: class.c:693
#define Check_Type(v, t)
Definition: ruby.h:562
void rb_define_alloc_func(VALUE, rb_alloc_func_t)
const char * alias
Definition: nkf.c:1151
#define T_ARRAY
Definition: ruby.h:498
rb_encoding * rb_utf8_encoding(void)
Definition: encoding.c:1320
#define level
RUBY_EXTERN VALUE rb_cObject
Definition: ruby.h:1893
VALUE cPsychEmitter
Definition: psych_emitter.c:10
#define NIL_P(v)
Definition: ruby.h:451
int argc
Definition: ruby.c:187
#define Qfalse
Definition: ruby.h:436
#define RSTRING_LEN(str)
Definition: ruby.h:971
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Definition: class.c:1908
VALUE rb_ivar_set(VALUE, ID, VALUE)
Definition: variable.c:1315
unsigned long ID
Definition: ruby.h:86
unsigned long VALUE
Definition: ruby.h:85
register unsigned int len
Definition: zonetab.h:51
#define StringValueCStr(v)
Definition: ruby.h:571
int size
Definition: encoding.c:57
#define RARRAY_AREF(a, i)
Definition: ruby.h:1033
VALUE rb_eRuntimeError
Definition: error.c:800
#define RTEST(v)
Definition: ruby.h:450
#define T_STRING
Definition: ruby.h:496
VALUE rb_str_export_to_enc(VALUE, rb_encoding *)
Definition: string.c:1103
#define TypedData_Make_Struct(klass, type, data_type, sval)
Definition: ruby.h:1175
VALUE rb_enc_str_new(const char *, long, rb_encoding *)
Definition: string.c:759
const char * name
Definition: nkf.c:208
#define StringValuePtr(v)
Definition: ruby.h:570
void void xfree(void *)
VALUE rb_define_module(const char *name)
Definition: class.c:768
#define rb_intern(str)
#define NULL
Definition: _sdbm.c:102
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Definition: class.c:1515
VALUE rb_attr_get(VALUE, ID)
Definition: variable.c:1224
char ** argv
Definition: ruby.c:188
#define StringValue(v)
Definition: ruby.h:569
#define xcalloc
Definition: defines.h:185