Ruby 1.9.2p136(2010-12-25revision30365)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

# ext/psych/emitter.c

Go to the documentation of this file.

    00001 #include <psych.h>
    00002
    00003 VALUE cPsychEmitter;
    00004 static ID id_write;
    00005
    00006 static void emit(yaml_emitter_t * emitter, yaml_event_t * event)
    00007 {
    00008     if(!yaml_emitter_emit(emitter, event))
    00009         rb_raise(rb_eRuntimeError, "%s", emitter->problem);
    00010 }
    00011
    00012 static int writer(void *ctx, unsigned char *buffer, size_t size)
    00013 {
    00014     VALUE io = (VALUE)ctx;
    00015     VALUE str = rb_str_new((const char *)buffer, (long)size);
    00016     VALUE wrote = rb_funcall(io, id_write, 1, str);
    00017     return (int)NUM2INT(wrote);
    00018 }
    00019
    00020 static void dealloc(yaml_emitter_t * emitter)
    00021 {
    00022     yaml_emitter_delete(emitter);
    00023     free(emitter);
    00024 }
    00025
    00026 static VALUE allocate(VALUE klass)
    00027 {
    00028     yaml_emitter_t * emitter = malloc(sizeof(yaml_emitter_t));
    00029     yaml_emitter_initialize(emitter);
    00030     yaml_emitter_set_unicode(emitter, 1);
    00031     yaml_emitter_set_indent(emitter, 2);
    00032
    00033     return Data_Wrap_Struct(klass, 0, dealloc, emitter);
    00034 }
    00035
    00036 /* call-seq: Psych::Emitter.new(io)
    00037  *
    00038  * Create a new Psych::Emitter that writes to +io+.
    00039  */
    00040 static VALUE initialize(VALUE self, VALUE io)
    00041 {
    00042     yaml_emitter_t * emitter;
    00043     Data_Get_Struct(self, yaml_emitter_t, emitter);
    00044
    00045     yaml_emitter_set_output(emitter, writer, (void *)io);
    00046
    00047     return self;
    00048 }
    00049
    00050 /* call-seq: emitter.start_stream(encoding)
    00051  *
    00052  * Start a stream emission with +encoding+
    00053  *
    00054  * See Psych::Handler#start_stream
    00055  */
    00056 static VALUE start_stream(VALUE self, VALUE encoding)
    00057 {
    00058     yaml_emitter_t * emitter;
    00059     yaml_event_t event;
    00060     Data_Get_Struct(self, yaml_emitter_t, emitter);
    00061     Check_Type(encoding, T_FIXNUM);
    00062
    00063     yaml_stream_start_event_initialize(&event, (yaml_encoding_t)NUM2INT(encoding));
    00064
    00065     emit(emitter, &event);
    00066
    00067     return self;
    00068 }
    00069
    00070 /* call-seq: emitter.end_stream
    00071  *
    00072  * End a stream emission
    00073  *
    00074  * See Psych::Handler#end_stream
    00075  */
    00076 static VALUE end_stream(VALUE self)
    00077 {
    00078     yaml_emitter_t * emitter;
    00079     yaml_event_t event;
    00080     Data_Get_Struct(self, yaml_emitter_t, emitter);
    00081
    00082     yaml_stream_end_event_initialize(&event);
    00083
    00084     emit(emitter, &event);
    00085
    00086     return self;
    00087 }
    00088
    00089 /* call-seq: emitter.start_document(version, tags, implicit)
    00090  *
    00091  * Start a document emission with YAML +version+, +tags+, and an +implicit+
    00092  * start.
    00093  *
    00094  * See Psych::Handler#start_document
    00095  */
    00096 static VALUE start_document(VALUE self, VALUE version, VALUE tags, VALUE imp)
    00097 {
    00098     yaml_emitter_t * emitter;
    00099     yaml_tag_directive_t * head = NULL;
    00100     yaml_tag_directive_t * tail = NULL;
    00101     yaml_event_t event;
    00102     yaml_version_directive_t version_directive;
    00103     Data_Get_Struct(self, yaml_emitter_t, emitter);
    00104
    00105
    00106     Check_Type(version, T_ARRAY);
    00107
    00108     if(RARRAY_LEN(version) > 0) {
    00109         VALUE major = rb_ary_entry(version, (long)0);
    00110         VALUE minor = rb_ary_entry(version, (long)1);
    00111
    00112         version_directive.major = NUM2INT(major);
    00113         version_directive.minor = NUM2INT(minor);
    00114     }
    00115
    00116     if(RTEST(tags)) {
    00117         int i = 0;
    00118
    00119         Check_Type(tags, T_ARRAY);
    00120
    00121         head  = xcalloc((size_t)RARRAY_LEN(tags), sizeof(yaml_tag_directive_t));
    00122         tail  = head;
    00123
    00124         for(i = 0; i < RARRAY_LEN(tags); i++) {
    00125             VALUE tuple = RARRAY_PTR(tags)[i];
    00126             Check_Type(tuple, T_ARRAY);
    00127
    00128             if(RARRAY_LEN(tuple) < 2) {
    00129                 xfree(head);
    00130                 rb_raise(rb_eRuntimeError, "tag tuple must be of length 2");
    00131             }
    00132
    00133             tail->handle = (yaml_char_t *)StringValuePtr(RARRAY_PTR(tuple)[0]);
    00134             tail->prefix = (yaml_char_t *)StringValuePtr(RARRAY_PTR(tuple)[1]);
    00135
    00136             tail++;
    00137         }
    00138     }
    00139
    00140     yaml_document_start_event_initialize(
    00141             &event,
    00142             (RARRAY_LEN(version) > 0) ? &version_directive : NULL,
    00143             head,
    00144             tail,
    00145             imp ? 1 : 0
    00146             );
    00147
    00148     emit(emitter, &event);
    00149
    00150     if(head) xfree(head);
    00151
    00152     return self;
    00153 }
    00154
    00155 /* call-seq: emitter.end_document(implicit)
    00156  *
    00157  * End a document emission with an +implicit+ ending.
    00158  *
    00159  * See Psych::Handler#end_document
    00160  */
    00161 static VALUE end_document(VALUE self, VALUE imp)
    00162 {
    00163     yaml_emitter_t * emitter;
    00164     yaml_event_t event;
    00165     Data_Get_Struct(self, yaml_emitter_t, emitter);
    00166
    00167     yaml_document_end_event_initialize(&event, imp ? 1 : 0);
    00168
    00169     emit(emitter, &event);
    00170
    00171     return self;
    00172 }
    00173
    00174 /* call-seq: emitter.scalar(value, anchor, tag, plain, quoted, style)
    00175  *
    00176  * Emit a scalar with +value+, +anchor+, +tag+, and a +plain+ or +quoted+
    00177  * string type with +style+.
    00178  *
    00179  * See Psych::Handler#scalar
    00180  */
    00181 static VALUE scalar(
    00182         VALUE self,
    00183         VALUE value,
    00184         VALUE anchor,
    00185         VALUE tag,
    00186         VALUE plain,
    00187         VALUE quoted,
    00188         VALUE style
    00189         ) {
    00190     yaml_emitter_t * emitter;
    00191     yaml_event_t event;
    00192     Data_Get_Struct(self, yaml_emitter_t, emitter);
    00193
    00194     Check_Type(value, T_STRING);
    00195
    00196     yaml_scalar_event_initialize(
    00197             &event,
    00198             (yaml_char_t *)(NIL_P(anchor) ? NULL : StringValuePtr(anchor)),
    00199             (yaml_char_t *)(NIL_P(tag) ? NULL : StringValuePtr(tag)),
    00200             (yaml_char_t*)StringValuePtr(value),
    00201             (int)RSTRING_LEN(value),
    00202             plain ? 1 : 0,
    00203             quoted ? 1 : 0,
    00204             (yaml_scalar_style_t)NUM2INT(style)
    00205             );
    00206
    00207     emit(emitter, &event);
    00208
    00209     return self;
    00210 }
    00211
    00212 /* call-seq: emitter.start_sequence(anchor, tag, implicit, style)
    00213  *
    00214  * Start emitting a sequence with +anchor+, a +tag+, +implicit+ sequence
    00215  * start and end, along with +style+.
    00216  *
    00217  * See Psych::Handler#start_sequence
    00218  */
    00219 static VALUE start_sequence(
    00220         VALUE self,
    00221         VALUE anchor,
    00222         VALUE tag,
    00223         VALUE implicit,
    00224         VALUE style
    00225         ) {
    00226     yaml_emitter_t * emitter;
    00227     yaml_event_t event;
    00228     Data_Get_Struct(self, yaml_emitter_t, emitter);
    00229
    00230     yaml_sequence_start_event_initialize(
    00231             &event,
    00232             (yaml_char_t *)(NIL_P(anchor) ? NULL : StringValuePtr(anchor)),
    00233             (yaml_char_t *)(NIL_P(tag) ? NULL : StringValuePtr(tag)),
    00234             implicit ? 1 : 0,
    00235             (yaml_sequence_style_t)NUM2INT(style)
    00236             );
    00237
    00238     emit(emitter, &event);
    00239
    00240     return self;
    00241 }
    00242
    00243 /* call-seq: emitter.end_sequence
    00244  *
    00245  * End sequence emission.
    00246  *
    00247  * See Psych::Handler#end_sequence
    00248  */
    00249 static VALUE end_sequence(VALUE self)
    00250 {
    00251     yaml_emitter_t * emitter;
    00252     yaml_event_t event;
    00253     Data_Get_Struct(self, yaml_emitter_t, emitter);
    00254
    00255     yaml_sequence_end_event_initialize(&event);
    00256
    00257     emit(emitter, &event);
    00258
    00259     return self;
    00260 }
    00261
    00262 /* call-seq: emitter.start_mapping(anchor, tag, implicit, style)
    00263  *
    00264  * Start emitting a YAML map with +anchor+, +tag+, an +implicit+ start
    00265  * and end, and +style+.
    00266  *
    00267  * See Psych::Handler#start_mapping
    00268  */
    00269 static VALUE start_mapping(
    00270         VALUE self,
    00271         VALUE anchor,
    00272         VALUE tag,
    00273         VALUE implicit,
    00274         VALUE style
    00275         ) {
    00276     yaml_emitter_t * emitter;
    00277     yaml_event_t event;
    00278     Data_Get_Struct(self, yaml_emitter_t, emitter);
    00279
    00280     yaml_mapping_start_event_initialize(
    00281             &event,
    00282             (yaml_char_t *)(NIL_P(anchor) ? NULL : StringValuePtr(anchor)),
    00283             (yaml_char_t *)(NIL_P(tag) ? NULL : StringValuePtr(tag)),
    00284             implicit ? 1 : 0,
    00285             (yaml_sequence_style_t)NUM2INT(style)
    00286             );
    00287
    00288     emit(emitter, &event);
    00289
    00290     return self;
    00291 }
    00292
    00293 /* call-seq: emitter.end_mapping
    00294  *
    00295  * Emit the end of a mapping.
    00296  *
    00297  * See Psych::Handler#end_mapping
    00298  */
    00299 static VALUE end_mapping(VALUE self)
    00300 {
    00301     yaml_emitter_t * emitter;
    00302     yaml_event_t event;
    00303     Data_Get_Struct(self, yaml_emitter_t, emitter);
    00304
    00305     yaml_mapping_end_event_initialize(&event);
    00306
    00307     emit(emitter, &event);
    00308
    00309     return self;
    00310 }
    00311
    00312 /* call-seq: emitter.alias(anchor)
    00313  *
    00314  * Emit an alias with +anchor+.
    00315  *
    00316  * See Psych::Handler#alias
    00317  */
    00318 static VALUE alias(VALUE self, VALUE anchor)
    00319 {
    00320     yaml_emitter_t * emitter;
    00321     yaml_event_t event;
    00322     Data_Get_Struct(self, yaml_emitter_t, emitter);
    00323
    00324     yaml_alias_event_initialize(
    00325             &event,
    00326             (yaml_char_t *)(NIL_P(anchor) ? NULL : StringValuePtr(anchor))
    00327             );
    00328
    00329     emit(emitter, &event);
    00330
    00331     return self;
    00332 }
    00333
    00334 /* call-seq: emitter.canonical = true
    00335  *
    00336  * Set the output style to canonical, or not.
    00337  */
    00338 static VALUE set_canonical(VALUE self, VALUE style)
    00339 {
    00340     yaml_emitter_t * emitter;
    00341     Data_Get_Struct(self, yaml_emitter_t, emitter);
    00342
    00343     yaml_emitter_set_canonical(emitter, Qtrue == style ? 1 : 0);
    00344
    00345     return style;
    00346 }
    00347
    00348 /* call-seq: emitter.canonical
    00349  *
    00350  * Get the output style, canonical or not.
    00351  */
    00352 static VALUE canonical(VALUE self)
    00353 {
    00354     yaml_emitter_t * emitter;
    00355     Data_Get_Struct(self, yaml_emitter_t, emitter);
    00356
    00357     return (emitter->canonical == 0) ? Qfalse : Qtrue;
    00358 }
    00359
    00360 /* call-seq: emitter.indentation = level
    00361  *
    00362  * Set the indentation level to +level+.
    00363  */
    00364 static VALUE set_indentation(VALUE self, VALUE level)
    00365 {
    00366     yaml_emitter_t * emitter;
    00367     Data_Get_Struct(self, yaml_emitter_t, emitter);
    00368
    00369     yaml_emitter_set_indent(emitter, NUM2INT(level));
    00370
    00371     return level;
    00372 }
    00373
    00374 /* call-seq: emitter.indentation
    00375  *
    00376  * Get the indentation level.
    00377  */
    00378 static VALUE indentation(VALUE self)
    00379 {
    00380     yaml_emitter_t * emitter;
    00381     Data_Get_Struct(self, yaml_emitter_t, emitter);
    00382
    00383     return INT2NUM(emitter->best_indent);
    00384 }
    00385
    00386 void Init_psych_emitter()
    00387 {
    00388     VALUE psych     = rb_define_module("Psych");
    00389     VALUE handler   = rb_define_class_under(psych, "Handler", rb_cObject);
    00390     cPsychEmitter   = rb_define_class_under(psych, "Emitter", handler);
    00391
    00392     rb_define_alloc_func(cPsychEmitter, allocate);
    00393
    00394     rb_define_method(cPsychEmitter, "initialize", initialize, 1);
    00395     rb_define_method(cPsychEmitter, "start_stream", start_stream, 1);
    00396     rb_define_method(cPsychEmitter, "end_stream", end_stream, 0);
    00397     rb_define_method(cPsychEmitter, "start_document", start_document, 3);
    00398     rb_define_method(cPsychEmitter, "end_document", end_document, 1);
    00399     rb_define_method(cPsychEmitter, "scalar", scalar, 6);
    00400     rb_define_method(cPsychEmitter, "start_sequence", start_sequence, 4);
    00401     rb_define_method(cPsychEmitter, "end_sequence", end_sequence, 0);
    00402     rb_define_method(cPsychEmitter, "start_mapping", start_mapping, 4);
    00403     rb_define_method(cPsychEmitter, "end_mapping", end_mapping, 0);
    00404     rb_define_method(cPsychEmitter, "alias", alias, 1);
    00405     rb_define_method(cPsychEmitter, "canonical", canonical, 0);
    00406     rb_define_method(cPsychEmitter, "canonical=", set_canonical, 1);
    00407     rb_define_method(cPsychEmitter, "indentation", indentation, 0);
    00408     rb_define_method(cPsychEmitter, "indentation=", set_indentation, 1);
    00409
    00410     id_write = rb_intern("write");
    00411 }
    00412 /* vim: set noet sws=4 sw=4: */
    00413