Ruby
2.0.0p247(2013-06-27revision41674)
|
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 /* call-seq: Psych::Emitter.new(io, options = Psych::Emitter::OPTIONS) 00046 * 00047 * Create a new Psych::Emitter that writes to +io+. 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 /* call-seq: emitter.start_stream(encoding) 00075 * 00076 * Start a stream emission with +encoding+ 00077 * 00078 * See Psych::Handler#start_stream 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 /* call-seq: emitter.end_stream 00095 * 00096 * End a stream emission 00097 * 00098 * See Psych::Handler#end_stream 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 /* call-seq: emitter.start_document(version, tags, implicit) 00114 * 00115 * Start a document emission with YAML +version+, +tags+, and an +implicit+ 00116 * start. 00117 * 00118 * See Psych::Handler#start_document 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 /* call-seq: emitter.end_document(implicit) 00192 * 00193 * End a document emission with an +implicit+ ending. 00194 * 00195 * See Psych::Handler#end_document 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 /* call-seq: emitter.scalar(value, anchor, tag, plain, quoted, style) 00211 * 00212 * Emit a scalar with +value+, +anchor+, +tag+, and a +plain+ or +quoted+ 00213 * string type with +style+. 00214 * 00215 * See Psych::Handler#scalar 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 /* call-seq: emitter.start_sequence(anchor, tag, implicit, style) 00268 * 00269 * Start emitting a sequence with +anchor+, a +tag+, +implicit+ sequence 00270 * start and end, along with +style+. 00271 * 00272 * See Psych::Handler#start_sequence 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 /* call-seq: emitter.end_sequence 00314 * 00315 * End sequence emission. 00316 * 00317 * See Psych::Handler#end_sequence 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 /* call-seq: emitter.start_mapping(anchor, tag, implicit, style) 00333 * 00334 * Start emitting a YAML map with +anchor+, +tag+, an +implicit+ start 00335 * and end, and +style+. 00336 * 00337 * See Psych::Handler#start_mapping 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 /* call-seq: emitter.end_mapping 00381 * 00382 * Emit the end of a mapping. 00383 * 00384 * See Psych::Handler#end_mapping 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 /* call-seq: emitter.alias(anchor) 00400 * 00401 * Emit an alias with +anchor+. 00402 * 00403 * See Psych::Handler#alias 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 /* call-seq: emitter.canonical = true 00429 * 00430 * Set the output style to canonical, or not. 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 /* call-seq: emitter.canonical 00443 * 00444 * Get the output style, canonical or not. 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 /* call-seq: emitter.indentation = level 00455 * 00456 * Set the indentation level to +level+. The level must be less than 10 and 00457 * greater than 1. 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 /* call-seq: emitter.indentation 00470 * 00471 * Get the indentation level. 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 /* call-seq: emitter.line_width 00482 * 00483 * Get the preferred line width. 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 /* call-seq: emitter.line_width = width 00494 * 00495 * Set the preferred line with to +width+. 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 /* vim: set noet sws=4 sw=4: */ 00539