From a1e257ec48911d3ca1aaeda0127061c244f36147 Mon Sep 17 00:00:00 2001 From: why Date: Fri, 11 Jul 2003 22:52:14 +0000 Subject: * ext/syck/emitter.c: new emitter code. * ext/syck/rubyext.c: Emitter class. * lib/yaml.rb: Load Syck emitter, if available. * lib/yaml/stream.rb: ditto. * lib/yaml/baseemitter.rb: underlying class for all emitters. * lib/yaml/rubytypes.rb: use BaseEmitter abstraction. * lib/yaml/emitter.rb: ditto. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@4066 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ext/syck/rubyext.c | 173 ++++++++++++++++++++++++++++++++++++++++++++++++++++- ext/syck/syck.c | 37 ++++-------- ext/syck/syck.h | 104 ++++++++++++++++++++++++++++++-- 3 files changed, 285 insertions(+), 29 deletions(-) (limited to 'ext/syck') diff --git a/ext/syck/rubyext.c b/ext/syck/rubyext.c index 724dd7a912..6a26cd45f8 100644 --- a/ext/syck/rubyext.c +++ b/ext/syck/rubyext.c @@ -40,7 +40,7 @@ typedef struct RVALUE { static ID s_new, s_utc, s_at, s_to_f, s_read, s_binmode, s_call, s_transfer, s_update, s_dup, s_match; static VALUE sym_model, sym_generic; static VALUE sym_scalar, sym_seq, sym_map; -VALUE cDate, cParser, cLoader, cNode, cPrivateType, cDomainType, cBadAlias, cMergeKey; +VALUE cDate, cParser, cLoader, cNode, cPrivateType, cDomainType, cBadAlias, cMergeKey, cEmitter; VALUE oDefaultLoader; /* @@ -57,6 +57,7 @@ SYMID rb_syck_parse_handler _((SyckParser *, SyckNode *)); SYMID rb_syck_load_handler _((SyckParser *, SyckNode *)); void rb_syck_err_handler _((SyckParser *, char *)); SyckNode * rb_syck_bad_anchor_handler _((SyckParser *, char *)); +void rb_syck_output_handler _((SyckEmitter *, char *, long)); struct parser_xtra { VALUE data; /* Borrowed this idea from marshal.c to fix [ruby-core:8067] problem */ @@ -1015,6 +1016,162 @@ syck_node_transform( self ) return rb_funcall( oDefaultLoader, s_transfer, 2, type_id, t ); } +/* + * Handle output from the emitter + */ +void +rb_syck_output_handler( emitter, str, len ) + SyckEmitter *emitter; + char *str; + long len; +{ + rb_str_cat( (VALUE)emitter->bonus, str, len ); +} + +/* + * Mark emitter values. + */ +static void +syck_mark_emitter(emitter) + SyckEmitter *emitter; +{ + rb_gc_mark(emitter->ignore_id); +} + +/* + * YAML::Syck::Emitter.new + */ +VALUE +syck_emitter_new(argc, argv, class) + int argc; + VALUE *argv; + VALUE class; +{ + VALUE pobj, options, init_argv[1]; + SyckEmitter *emitter = syck_new_emitter(); + syck_emitter_ignore_id( emitter, Qnil ); + syck_emitter_handler( emitter, rb_syck_output_handler ); + + emitter->bonus = (void *)rb_str_new2( "" ); + + rb_scan_args(argc, argv, "01", &options); + pobj = Data_Wrap_Struct( class, syck_mark_emitter, syck_free_emitter, emitter ); + + if ( ! rb_obj_is_instance_of( options, rb_cHash ) ) + { + options = rb_hash_new(); + } + init_argv[0] = options; + rb_obj_call_init(pobj, 1, init_argv); + return pobj; +} + +/* + * YAML::Syck::Emitter.initialize( options ) + */ +static VALUE +syck_emitter_initialize( self, options ) + VALUE self, options; +{ + rb_iv_set(self, "@options", options); + return self; +} + +/* + * YAML::Syck::Emitter.level + */ +VALUE +syck_emitter_level_m( self ) + VALUE self; +{ + SyckEmitter *emitter; + + Data_Get_Struct(self, SyckEmitter, emitter); + return LONG2NUM( emitter->level ); +} + +/* + * YAML::Syck::Emitter.flush + */ +VALUE +syck_emitter_flush_m( self ) + VALUE self; +{ + SyckEmitter *emitter; + + Data_Get_Struct(self, SyckEmitter, emitter); + syck_emitter_flush( emitter ); + return self; +} + +/* + * YAML::Syck::Emitter.write( str ) + */ +VALUE +syck_emitter_write_m( self, str ) + VALUE str; +{ + SyckEmitter *emitter; + + Data_Get_Struct(self, SyckEmitter, emitter); + syck_emitter_write( emitter, RSTRING(str)->ptr, RSTRING(str)->len ); + return self; +} + +/* + * YAML::Syck::Emitter.simple( str ) + */ +VALUE +syck_emitter_simple_write( self, str ) + VALUE str; +{ + SyckEmitter *emitter; + + Data_Get_Struct(self, SyckEmitter, emitter); + syck_emitter_simple( emitter, RSTRING(str)->ptr, RSTRING(str)->len ); + return self; +} + +/* + * YAML::Syck::Emitter.start_object( object_id ) + */ +VALUE +syck_emitter_start_object( self, oid ) + VALUE self, oid; +{ + char *anchor_name; + SyckEmitter *emitter; + + Data_Get_Struct(self, SyckEmitter, emitter); + anchor_name = syck_emitter_start_obj( emitter, oid ); + + if ( anchor_name == NULL ) + { + return Qnil; + } + + return rb_str_new2( anchor_name ); +} + +/* + * YAML::Syck::Emitter.end_object( object_id ) + */ +VALUE +syck_emitter_end_object( self, oid ) + VALUE self, oid; +{ + SyckEmitter *emitter; + + Data_Get_Struct(self, SyckEmitter, emitter); + syck_emitter_end_obj( emitter ); + + if ( emitter->level < 0 ) + { + syck_emitter_flush( emitter ); + } + return (VALUE)emitter->bonus; +} + /* * Initialize Syck extension */ @@ -1118,5 +1275,19 @@ Init_syck() * Define YAML::Syck::MergeKey class */ cMergeKey = rb_define_class_under( rb_syck, "MergeKey", rb_cObject ); + + /* + * Define YAML::Syck::Emitter class + */ + cEmitter = rb_define_class_under( rb_syck, "Emitter", rb_cObject ); + rb_define_singleton_method( cEmitter, "new", syck_emitter_new, -1 ); + rb_define_method( cEmitter, "initialize", syck_emitter_initialize, 1 ); + rb_define_method( cEmitter, "level", syck_emitter_level_m, 0 ); + rb_define_method( cEmitter, "write", syck_emitter_write_m, 1 ); + rb_define_method( cEmitter, "<<", syck_emitter_write_m, 1 ); + rb_define_method( cEmitter, "simple", syck_emitter_simple_write, 1 ); + rb_define_method( cEmitter, "flush", syck_emitter_flush_m, 0 ); + rb_define_method( cEmitter, "start_object", syck_emitter_start_object, 1 ); + rb_define_method( cEmitter, "end_object", syck_emitter_end_object, 0 ); } diff --git a/ext/syck/syck.c b/ext/syck/syck.c index a7955b448b..4b7be32a18 100644 --- a/ext/syck/syck.c +++ b/ext/syck/syck.c @@ -11,10 +11,6 @@ #include "syck.h" -#define SYCK_YAML_MAJOR 1 -#define SYCK_YAML_MINOR 0 -#define SYCK_BUFFERSIZE 262144 - void syck_parser_pop_level( SyckParser * ); /* @@ -30,6 +26,9 @@ syck_assert( char *file_name, unsigned line_num ) abort(); } +/* + * Allocates and copies a string + */ char * syck_strndup( char *buf, long len ) { @@ -40,7 +39,7 @@ syck_strndup( char *buf, long len ) } /* - * Default IO functions + * Default FILE IO function */ long syck_io_file_read( char *buf, SyckIoFile *file, long max_size, long skip ) @@ -52,18 +51,15 @@ syck_io_file_read( char *buf, SyckIoFile *file, long max_size, long skip ) max_size -= skip; len = fread( buf + skip, max_size, sizeof( char ), file->ptr ); -#if REDEBUG - printf( "LEN: %d\n", len ); -#endif len += skip; buf[len] = '\0'; -#if REDEBUG - printf( "POS: %d\n", len ); - printf( "BUFFER: %s\n", buf ); -#endif + return len; } +/* + * Default string IO function + */ long syck_io_str_read( char *buf, SyckIoStr *str, long max_size, long skip ) { @@ -95,15 +91,9 @@ syck_io_str_read( char *buf, SyckIoStr *str, long max_size, long skip ) len = str->ptr - beg; S_MEMCPY( buf + skip, beg, char, len ); } -#if REDEBUG - printf( "LEN: %d\n", len ); -#endif len += skip; buf[len] = '\0'; -#if REDEBUG - printf( "POS: %d\n", len ); - printf( "BUFFER: %s\n", buf ); -#endif + return len; } @@ -150,6 +140,9 @@ syck_parser_reset_cursor( SyckParser *p ) p->force_token = 0; } +/* + * Value to return on a parse error + */ void syck_parser_set_root_on_error( SyckParser *p, SYMID roer ) { @@ -212,7 +205,7 @@ syck_st_free( SyckParser *p ) { /* * Free the adhoc symbol table - */ + */ if ( p->syms != NULL ) { st_free_table( p->syms ); @@ -410,10 +403,6 @@ syck_move_tokens( SyckParser *p ) if ( skip < 1 ) return 0; -#if REDEBUG - printf( "DIFF: %d\n", skip ); -#endif - if ( ( count = p->token - p->buffer ) ) { S_MEMMOVE( p->buffer, p->token, char, skip ); diff --git a/ext/syck/syck.h b/ext/syck/syck.h index 20ad18a843..259a4cdfbd 100644 --- a/ext/syck/syck.h +++ b/ext/syck/syck.h @@ -10,6 +10,9 @@ #ifndef SYCK_H #define SYCK_H +#define SYCK_YAML_MAJOR 1 +#define SYCK_YAML_MINOR 0 + #define SYCK_VERSION "0.35" #define YAML_DOMAIN "yaml.org,2002" @@ -43,6 +46,7 @@ extern "C" { #endif #define ALLOC_CT 8 +#define SYCK_BUFFERSIZE 262144 #define S_ALLOC_N(type,n) (type*)malloc(sizeof(type)*(n)) #define S_ALLOC(type) (type*)malloc(sizeof(type)) #define S_REALLOC_N(var,type,n) (var)=(type*)realloc((char*)(var),sizeof(type)*(n)) @@ -66,11 +70,7 @@ extern "C" { */ #define SYMID unsigned long -typedef struct _syck_parser SyckParser; -typedef struct _syck_file SyckIoFile; -typedef struct _syck_str SyckIoStr; typedef struct _syck_node SyckNode; -typedef struct _syck_level SyckLevel; enum syck_kind_tag { syck_map_kind, @@ -83,6 +83,9 @@ enum map_part { map_value }; +/* + * Node metadata struct + */ struct _syck_node { /* Symbol table ID */ SYMID id; @@ -119,6 +122,11 @@ struct _syck_node { /* * Parser definitions */ +typedef struct _syck_parser SyckParser; +typedef struct _syck_file SyckIoFile; +typedef struct _syck_str SyckIoStr; +typedef struct _syck_level SyckLevel; + typedef SYMID (*SyckNodeHandler)(SyckParser *, SyckNode *); typedef void (*SyckErrorHandler)(SyckParser *, char *); typedef SyckNode * (*SyckBadAnchorHandler)(SyckParser *, char *); @@ -142,6 +150,9 @@ enum syck_level_status { syck_lvl_pause }; +/* + * Parser struct + */ struct _syck_parser { /* Root node */ SYMID root, root_on_error; @@ -192,6 +203,82 @@ struct _syck_parser { void *bonus; }; +/* + * Emitter definitions + */ +typedef struct _syck_emitter SyckEmitter; +typedef struct _syck_emitter_node SyckEmitterNode; + +typedef void (*SyckOutputHandler)(SyckEmitter *, char *, long); + +enum doc_stage { + doc_open, + doc_need_header, + doc_processing +}; + +enum block_styles { + block_arbitrary, + block_fold, + block_literal +}; + +/* + * Emitter struct + */ +struct _syck_emitter { + /* Headerless doc flag */ + int headless; + /* Sequence map shortcut flag */ + int seq_map; + /* Force header? */ + int use_header; + /* Force version? */ + int use_version; + /* Sort hash keys */ + int sort_keys; + /* Anchor format */ + char *anchor_format; + /* Explicit typing on all collections? */ + int explicit_typing; + /* Best width on folded scalars */ + int best_width; + /* Use literal[1] or folded[2] blocks on all text? */ + enum block_styles block_style; + /* Stage of written document */ + enum doc_stage stage; + /* Level counter */ + int level; + /* Default indentation */ + int indent; + /* Object ignore ID */ + SYMID ignore_id; + /* Symbol table for anchors */ + st_table *markers, *anchors; + /* Custom buffer size */ + size_t bufsize; + /* Buffer */ + char *buffer, *marker; + /* Absolute position of the buffer */ + long bufpos; + /* Handler for output */ + SyckOutputHandler handler; + /* Pointer for extension's use */ + void *bonus; +}; + +/* + * Emitter node metadata struct + */ +struct _syck_emitter_node { + /* Node buffer position */ + long pos; + /* Current indent */ + long indent; + /* Collection? */ + int is_shortcut; +}; + /* * Handler prototypes */ @@ -215,6 +302,15 @@ char *syck_match_implicit( char *, size_t ); char *syck_strndup( char *, long ); long syck_io_file_read( char *, SyckIoFile *, long, long ); long syck_io_str_read( char *, SyckIoStr *, long, long ); +SyckEmitter *syck_new_emitter(); +void syck_emitter_ignore_id( SyckEmitter *, SYMID ); +void syck_emitter_handler( SyckEmitter *, SyckOutputHandler ); +void syck_free_emitter( SyckEmitter * ); +void syck_emitter_clear( SyckEmitter * ); +void syck_emitter_write( SyckEmitter *, char *, long ); +void syck_emitter_flush( SyckEmitter * ); +char *syck_emitter_start_obj( SyckEmitter *, SYMID ); +void syck_emitter_end_obj( SyckEmitter * ); SyckParser *syck_new_parser(); void syck_free_parser( SyckParser * ); void syck_parser_set_root_on_error( SyckParser *, SYMID ); -- cgit v1.2.3