00001 #include <psych.h>
00002
00003 VALUE cPsychEmitter;
00004 static ID id_write;
00005 static ID id_line_width;
00006 static ID id_indentation;
00007 static ID id_canonical;
00008
00009 static void emit(yaml_emitter_t * emitter, yaml_event_t * event)
00010 {
00011 if(!yaml_emitter_emit(emitter, event))
00012 rb_raise(rb_eRuntimeError, "%s", emitter->problem);
00013 }
00014
00015 static int writer(void *ctx, unsigned char *buffer, size_t size)
00016 {
00017 VALUE io = (VALUE)ctx;
00018 VALUE str = rb_str_new((const char *)buffer, (long)size);
00019 VALUE wrote = rb_funcall(io, id_write, 1, str);
00020 return (int)NUM2INT(wrote);
00021 }
00022
00023 static void dealloc(void * ptr)
00024 {
00025 yaml_emitter_t * emitter;
00026
00027 emitter = (yaml_emitter_t *)ptr;
00028 yaml_emitter_delete(emitter);
00029 xfree(emitter);
00030 }
00031
00032 static VALUE allocate(VALUE klass)
00033 {
00034 yaml_emitter_t * emitter;
00035
00036 emitter = xmalloc(sizeof(yaml_emitter_t));
00037
00038 yaml_emitter_initialize(emitter);
00039 yaml_emitter_set_unicode(emitter, 1);
00040 yaml_emitter_set_indent(emitter, 2);
00041
00042 return Data_Wrap_Struct(klass, 0, dealloc, emitter);
00043 }
00044
00045
00046
00047
00048
00049 static VALUE initialize(int argc, VALUE *argv, VALUE self)
00050 {
00051 yaml_emitter_t * emitter;
00052 VALUE io, options;
00053 VALUE line_width;
00054 VALUE indent;
00055 VALUE canonical;
00056
00057 Data_Get_Struct(self, yaml_emitter_t, emitter);
00058
00059 if (rb_scan_args(argc, argv, "11", &io, &options) == 2) {
00060 line_width = rb_funcall(options, id_line_width, 0);
00061 indent = rb_funcall(options, id_indentation, 0);
00062 canonical = rb_funcall(options, id_canonical, 0);
00063
00064 yaml_emitter_set_width(emitter, NUM2INT(line_width));
00065 yaml_emitter_set_indent(emitter, NUM2INT(indent));
00066 yaml_emitter_set_canonical(emitter, Qtrue == canonical ? 1 : 0);
00067 }
00068
00069 yaml_emitter_set_output(emitter, writer, (void *)io);
00070
00071 return self;
00072 }
00073
00074
00075
00076
00077
00078
00079
00080 static VALUE start_stream(VALUE self, VALUE encoding)
00081 {
00082 yaml_emitter_t * emitter;
00083 yaml_event_t event;
00084 Data_Get_Struct(self, yaml_emitter_t, emitter);
00085 Check_Type(encoding, T_FIXNUM);
00086
00087 yaml_stream_start_event_initialize(&event, (yaml_encoding_t)NUM2INT(encoding));
00088
00089 emit(emitter, &event);
00090
00091 return self;
00092 }
00093
00094
00095
00096
00097
00098
00099
00100 static VALUE end_stream(VALUE self)
00101 {
00102 yaml_emitter_t * emitter;
00103 yaml_event_t event;
00104 Data_Get_Struct(self, yaml_emitter_t, emitter);
00105
00106 yaml_stream_end_event_initialize(&event);
00107
00108 emit(emitter, &event);
00109
00110 return self;
00111 }
00112
00113
00114
00115
00116
00117
00118
00119
00120 static VALUE start_document(VALUE self, VALUE version, VALUE tags, VALUE imp)
00121 {
00122 yaml_emitter_t * emitter;
00123 yaml_tag_directive_t * head = NULL;
00124 yaml_tag_directive_t * tail = NULL;
00125 yaml_event_t event;
00126 yaml_version_directive_t version_directive;
00127 Data_Get_Struct(self, yaml_emitter_t, emitter);
00128
00129
00130 Check_Type(version, T_ARRAY);
00131
00132 if(RARRAY_LEN(version) > 0) {
00133 VALUE major = rb_ary_entry(version, (long)0);
00134 VALUE minor = rb_ary_entry(version, (long)1);
00135
00136 version_directive.major = NUM2INT(major);
00137 version_directive.minor = NUM2INT(minor);
00138 }
00139
00140 if(RTEST(tags)) {
00141 int i = 0;
00142 #ifdef HAVE_RUBY_ENCODING_H
00143 rb_encoding * encoding = rb_utf8_encoding();
00144 #endif
00145
00146 Check_Type(tags, T_ARRAY);
00147
00148 head = xcalloc((size_t)RARRAY_LEN(tags), sizeof(yaml_tag_directive_t));
00149 tail = head;
00150
00151 for(i = 0; i < RARRAY_LEN(tags); i++) {
00152 VALUE tuple = RARRAY_PTR(tags)[i];
00153 VALUE name;
00154 VALUE value;
00155
00156 Check_Type(tuple, T_ARRAY);
00157
00158 if(RARRAY_LEN(tuple) < 2) {
00159 xfree(head);
00160 rb_raise(rb_eRuntimeError, "tag tuple must be of length 2");
00161 }
00162 name = RARRAY_PTR(tuple)[0];
00163 value = RARRAY_PTR(tuple)[1];
00164 #ifdef HAVE_RUBY_ENCODING_H
00165 name = rb_str_export_to_enc(name, encoding);
00166 value = rb_str_export_to_enc(value, encoding);
00167 #endif
00168
00169 tail->handle = (yaml_char_t *)StringValuePtr(name);
00170 tail->prefix = (yaml_char_t *)StringValuePtr(value);
00171
00172 tail++;
00173 }
00174 }
00175
00176 yaml_document_start_event_initialize(
00177 &event,
00178 (RARRAY_LEN(version) > 0) ? &version_directive : NULL,
00179 head,
00180 tail,
00181 imp ? 1 : 0
00182 );
00183
00184 emit(emitter, &event);
00185
00186 if(head) xfree(head);
00187
00188 return self;
00189 }
00190
00191
00192
00193
00194
00195
00196
00197 static VALUE end_document(VALUE self, VALUE imp)
00198 {
00199 yaml_emitter_t * emitter;
00200 yaml_event_t event;
00201 Data_Get_Struct(self, yaml_emitter_t, emitter);
00202
00203 yaml_document_end_event_initialize(&event, imp ? 1 : 0);
00204
00205 emit(emitter, &event);
00206
00207 return self;
00208 }
00209
00210
00211
00212
00213
00214
00215
00216
00217 static VALUE scalar(
00218 VALUE self,
00219 VALUE value,
00220 VALUE anchor,
00221 VALUE tag,
00222 VALUE plain,
00223 VALUE quoted,
00224 VALUE style
00225 ) {
00226 yaml_emitter_t * emitter;
00227 yaml_event_t event;
00228 #ifdef HAVE_RUBY_ENCODING_H
00229 rb_encoding *encoding;
00230 #endif
00231 Data_Get_Struct(self, yaml_emitter_t, emitter);
00232
00233 Check_Type(value, T_STRING);
00234
00235 #ifdef HAVE_RUBY_ENCODING_H
00236 encoding = rb_utf8_encoding();
00237
00238 value = rb_str_export_to_enc(value, encoding);
00239
00240 if(!NIL_P(anchor)) {
00241 Check_Type(anchor, T_STRING);
00242 anchor = rb_str_export_to_enc(anchor, encoding);
00243 }
00244
00245 if(!NIL_P(tag)) {
00246 Check_Type(tag, T_STRING);
00247 tag = rb_str_export_to_enc(tag, encoding);
00248 }
00249 #endif
00250
00251 yaml_scalar_event_initialize(
00252 &event,
00253 (yaml_char_t *)(NIL_P(anchor) ? NULL : StringValuePtr(anchor)),
00254 (yaml_char_t *)(NIL_P(tag) ? NULL : StringValuePtr(tag)),
00255 (yaml_char_t*)StringValuePtr(value),
00256 (int)RSTRING_LEN(value),
00257 plain ? 1 : 0,
00258 quoted ? 1 : 0,
00259 (yaml_scalar_style_t)NUM2INT(style)
00260 );
00261
00262 emit(emitter, &event);
00263
00264 return self;
00265 }
00266
00267
00268
00269
00270
00271
00272
00273
00274 static VALUE start_sequence(
00275 VALUE self,
00276 VALUE anchor,
00277 VALUE tag,
00278 VALUE implicit,
00279 VALUE style
00280 ) {
00281 yaml_emitter_t * emitter;
00282 yaml_event_t event;
00283
00284 #ifdef HAVE_RUBY_ENCODING_H
00285 rb_encoding * encoding = rb_utf8_encoding();
00286
00287 if(!NIL_P(anchor)) {
00288 Check_Type(anchor, T_STRING);
00289 anchor = rb_str_export_to_enc(anchor, encoding);
00290 }
00291
00292 if(!NIL_P(tag)) {
00293 Check_Type(tag, T_STRING);
00294 tag = rb_str_export_to_enc(tag, encoding);
00295 }
00296 #endif
00297
00298 Data_Get_Struct(self, yaml_emitter_t, emitter);
00299
00300 yaml_sequence_start_event_initialize(
00301 &event,
00302 (yaml_char_t *)(NIL_P(anchor) ? NULL : StringValuePtr(anchor)),
00303 (yaml_char_t *)(NIL_P(tag) ? NULL : StringValuePtr(tag)),
00304 implicit ? 1 : 0,
00305 (yaml_sequence_style_t)NUM2INT(style)
00306 );
00307
00308 emit(emitter, &event);
00309
00310 return self;
00311 }
00312
00313
00314
00315
00316
00317
00318
00319 static VALUE end_sequence(VALUE self)
00320 {
00321 yaml_emitter_t * emitter;
00322 yaml_event_t event;
00323 Data_Get_Struct(self, yaml_emitter_t, emitter);
00324
00325 yaml_sequence_end_event_initialize(&event);
00326
00327 emit(emitter, &event);
00328
00329 return self;
00330 }
00331
00332
00333
00334
00335
00336
00337
00338
00339 static VALUE start_mapping(
00340 VALUE self,
00341 VALUE anchor,
00342 VALUE tag,
00343 VALUE implicit,
00344 VALUE style
00345 ) {
00346 yaml_emitter_t * emitter;
00347 yaml_event_t event;
00348 #ifdef HAVE_RUBY_ENCODING_H
00349 rb_encoding *encoding;
00350 #endif
00351 Data_Get_Struct(self, yaml_emitter_t, emitter);
00352
00353 #ifdef HAVE_RUBY_ENCODING_H
00354 encoding = rb_utf8_encoding();
00355
00356 if(!NIL_P(anchor)) {
00357 Check_Type(anchor, T_STRING);
00358 anchor = rb_str_export_to_enc(anchor, encoding);
00359 }
00360
00361 if(!NIL_P(tag)) {
00362 Check_Type(tag, T_STRING);
00363 tag = rb_str_export_to_enc(tag, encoding);
00364 }
00365 #endif
00366
00367 yaml_mapping_start_event_initialize(
00368 &event,
00369 (yaml_char_t *)(NIL_P(anchor) ? NULL : StringValuePtr(anchor)),
00370 (yaml_char_t *)(NIL_P(tag) ? NULL : StringValuePtr(tag)),
00371 implicit ? 1 : 0,
00372 (yaml_mapping_style_t)NUM2INT(style)
00373 );
00374
00375 emit(emitter, &event);
00376
00377 return self;
00378 }
00379
00380
00381
00382
00383
00384
00385
00386 static VALUE end_mapping(VALUE self)
00387 {
00388 yaml_emitter_t * emitter;
00389 yaml_event_t event;
00390 Data_Get_Struct(self, yaml_emitter_t, emitter);
00391
00392 yaml_mapping_end_event_initialize(&event);
00393
00394 emit(emitter, &event);
00395
00396 return self;
00397 }
00398
00399
00400
00401
00402
00403
00404
00405 static VALUE alias(VALUE self, VALUE anchor)
00406 {
00407 yaml_emitter_t * emitter;
00408 yaml_event_t event;
00409 Data_Get_Struct(self, yaml_emitter_t, emitter);
00410
00411 #ifdef HAVE_RUBY_ENCODING_H
00412 if(!NIL_P(anchor)) {
00413 Check_Type(anchor, T_STRING);
00414 anchor = rb_str_export_to_enc(anchor, rb_utf8_encoding());
00415 }
00416 #endif
00417
00418 yaml_alias_event_initialize(
00419 &event,
00420 (yaml_char_t *)(NIL_P(anchor) ? NULL : StringValuePtr(anchor))
00421 );
00422
00423 emit(emitter, &event);
00424
00425 return self;
00426 }
00427
00428
00429
00430
00431
00432 static VALUE set_canonical(VALUE self, VALUE style)
00433 {
00434 yaml_emitter_t * emitter;
00435 Data_Get_Struct(self, yaml_emitter_t, emitter);
00436
00437 yaml_emitter_set_canonical(emitter, Qtrue == style ? 1 : 0);
00438
00439 return style;
00440 }
00441
00442
00443
00444
00445
00446 static VALUE canonical(VALUE self)
00447 {
00448 yaml_emitter_t * emitter;
00449 Data_Get_Struct(self, yaml_emitter_t, emitter);
00450
00451 return (emitter->canonical == 0) ? Qfalse : Qtrue;
00452 }
00453
00454
00455
00456
00457
00458
00459 static VALUE set_indentation(VALUE self, VALUE level)
00460 {
00461 yaml_emitter_t * emitter;
00462 Data_Get_Struct(self, yaml_emitter_t, emitter);
00463
00464 yaml_emitter_set_indent(emitter, NUM2INT(level));
00465
00466 return level;
00467 }
00468
00469
00470
00471
00472
00473 static VALUE indentation(VALUE self)
00474 {
00475 yaml_emitter_t * emitter;
00476 Data_Get_Struct(self, yaml_emitter_t, emitter);
00477
00478 return INT2NUM(emitter->best_indent);
00479 }
00480
00481
00482
00483
00484
00485 static VALUE line_width(VALUE self)
00486 {
00487 yaml_emitter_t * emitter;
00488 Data_Get_Struct(self, yaml_emitter_t, emitter);
00489
00490 return INT2NUM(emitter->best_width);
00491 }
00492
00493
00494
00495
00496
00497 static VALUE set_line_width(VALUE self, VALUE width)
00498 {
00499 yaml_emitter_t * emitter;
00500 Data_Get_Struct(self, yaml_emitter_t, emitter);
00501
00502 yaml_emitter_set_width(emitter, NUM2INT(width));
00503
00504 return width;
00505 }
00506
00507 void Init_psych_emitter()
00508 {
00509 VALUE psych = rb_define_module("Psych");
00510 VALUE handler = rb_define_class_under(psych, "Handler", rb_cObject);
00511 cPsychEmitter = rb_define_class_under(psych, "Emitter", handler);
00512
00513 rb_define_alloc_func(cPsychEmitter, allocate);
00514
00515 rb_define_method(cPsychEmitter, "initialize", initialize, -1);
00516 rb_define_method(cPsychEmitter, "start_stream", start_stream, 1);
00517 rb_define_method(cPsychEmitter, "end_stream", end_stream, 0);
00518 rb_define_method(cPsychEmitter, "start_document", start_document, 3);
00519 rb_define_method(cPsychEmitter, "end_document", end_document, 1);
00520 rb_define_method(cPsychEmitter, "scalar", scalar, 6);
00521 rb_define_method(cPsychEmitter, "start_sequence", start_sequence, 4);
00522 rb_define_method(cPsychEmitter, "end_sequence", end_sequence, 0);
00523 rb_define_method(cPsychEmitter, "start_mapping", start_mapping, 4);
00524 rb_define_method(cPsychEmitter, "end_mapping", end_mapping, 0);
00525 rb_define_method(cPsychEmitter, "alias", alias, 1);
00526 rb_define_method(cPsychEmitter, "canonical", canonical, 0);
00527 rb_define_method(cPsychEmitter, "canonical=", set_canonical, 1);
00528 rb_define_method(cPsychEmitter, "indentation", indentation, 0);
00529 rb_define_method(cPsychEmitter, "indentation=", set_indentation, 1);
00530 rb_define_method(cPsychEmitter, "line_width", line_width, 0);
00531 rb_define_method(cPsychEmitter, "line_width=", set_line_width, 1);
00532
00533 id_write = rb_intern("write");
00534 id_line_width = rb_intern("line_width");
00535 id_indentation = rb_intern("indentation");
00536 id_canonical = rb_intern("canonical");
00537 }
00538
00539