Ruby 1.9.2p136(2010-12-25revision30365)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

# ext/syck/syck.c

Go to the documentation of this file.

    00001 /*
    00002  * syck.c
    00003  *
    00004  * $Author: nobu $
    00005  *
    00006  * Copyright (C) 2003 why the lucky stiff
    00007  */
    00008 #include "ruby/ruby.h"
    00009
    00010 #include <stdio.h>
    00011 #include <string.h>
    00012
    00013 #include "syck.h"
    00014
    00015 void syck_parser_pop_level( SyckParser * );
    00016
    00017 /*
    00018  * Custom assert
    00019  */
    00020 void
    00021 syck_assert( const char *file_name, unsigned line_num, const char *expr )
    00022 {
    00023     fflush( NULL );
    00024     fprintf( stderr, "\nAssertion failed: %s, line %u: %s\n",
    00025              file_name, line_num, expr );
    00026     fflush( stderr );
    00027     abort();
    00028 }
    00029
    00030 /*
    00031  * Allocates and copies a string
    00032  */
    00033 char *
    00034 syck_strndup( const char *buf, long len )
    00035 {
    00036     char *new = S_ALLOC_N( char, len + 1 );
    00037     S_MEMZERO( new, char, len + 1 );
    00038     S_MEMCPY( new, buf, char, len );
    00039     return new;
    00040 }
    00041
    00042 /*
    00043  * Default FILE IO function
    00044  */
    00045 long
    00046 syck_io_file_read( char *buf, SyckIoFile *file, long max_size, long skip )
    00047 {
    00048     long len = 0;
    00049
    00050     ASSERT( file != NULL );
    00051
    00052     max_size -= skip;
    00053     len = fread( buf + skip, sizeof( char ), max_size, file->ptr );
    00054     len += skip;
    00055     buf[len] = '\0';
    00056
    00057     return len;
    00058 }
    00059
    00060 /*
    00061  * Default string IO function
    00062  */
    00063 long
    00064 syck_io_str_read( char *buf, SyckIoStr *str, long max_size, long skip )
    00065 {
    00066     char *beg;
    00067     long len = 0;
    00068
    00069     ASSERT( str != NULL );
    00070     beg = str->ptr;
    00071     if ( max_size >= 0 )
    00072     {
    00073         max_size -= skip;
    00074         if ( max_size <= 0 )  max_size = 0;
    00075         else                  str->ptr += max_size;
    00076
    00077         if ( str->ptr > str->end )
    00078         {
    00079             str->ptr = str->end;
    00080         }
    00081     }
    00082     else
    00083     {
    00084         /* Use exact string length */
    00085         while ( str->ptr < str->end ) {
    00086             if (*(str->ptr++) == '\n') break;
    00087         }
    00088     }
    00089     if ( beg < str->ptr )
    00090     {
    00091         len = ( str->ptr - beg );
    00092         S_MEMCPY( buf + skip, beg, char, len );
    00093     }
    00094     len += skip;
    00095     buf[len] = '\0';
    00096
    00097     return len;
    00098 }
    00099
    00100 void
    00101 syck_parser_reset_levels( SyckParser *p )
    00102 {
    00103     while ( p->lvl_idx > 1 )
    00104     {
    00105         syck_parser_pop_level( p );
    00106     }
    00107
    00108     if ( p->lvl_idx < 1 )
    00109     {
    00110         p->lvl_idx = 1;
    00111         p->levels[0].spaces = -1;
    00112         p->levels[0].ncount = 0;
    00113         p->levels[0].domain = syck_strndup( "", 0 );
    00114     }
    00115     p->levels[0].status = syck_lvl_header;
    00116 }
    00117
    00118 void
    00119 syck_parser_reset_cursor( SyckParser *p )
    00120 {
    00121     if ( p->buffer == NULL )
    00122     {
    00123         p->buffer = S_ALLOC_N( char, p->bufsize );
    00124         S_MEMZERO( p->buffer, char, p->bufsize );
    00125     }
    00126     p->buffer[0] = '\0';
    00127
    00128     p->cursor = NULL;
    00129     p->lineptr = NULL;
    00130     p->linectptr = NULL;
    00131     p->token = NULL;
    00132     p->toktmp = NULL;
    00133     p->marker = NULL;
    00134     p->limit = NULL;
    00135
    00136     p->root = 0;
    00137     p->root_on_error = 0;
    00138     p->linect = 0;
    00139     p->eof = 0;
    00140     p->last_token = 0;
    00141     p->force_token = 0;
    00142 }
    00143
    00144 /*
    00145  * Value to return on a parse error
    00146  */
    00147 void
    00148 syck_parser_set_root_on_error( SyckParser *p, SYMID roer )
    00149 {
    00150     p->root_on_error = roer;
    00151 }
    00152
    00153 /*
    00154  * Allocate the parser
    00155  */
    00156 SyckParser *
    00157 syck_new_parser(void)
    00158 {
    00159     SyckParser *p;
    00160     p = S_ALLOC( SyckParser );
    00161     S_MEMZERO( p, SyckParser, 1 );
    00162     p->lvl_capa = ALLOC_CT;
    00163     p->levels = S_ALLOC_N( SyckLevel, p->lvl_capa );
    00164     p->input_type = syck_yaml_utf8;
    00165     p->io_type = syck_io_str;
    00166     p->io.str = NULL;
    00167     p->syms = NULL;
    00168     p->anchors = NULL;
    00169     p->bad_anchors = NULL;
    00170     p->implicit_typing = 1;
    00171     p->taguri_expansion = 0;
    00172     p->bufsize = SYCK_BUFFERSIZE;
    00173     p->buffer = NULL;
    00174     p->lvl_idx = 0;
    00175     syck_parser_reset_levels( p );
    00176     return p;
    00177 }
    00178
    00179 int
    00180 syck_add_sym( SyckParser *p, void *data )
    00181 {
    00182     SYMID id = 0;
    00183     if ( p->syms == NULL )
    00184     {
    00185         p->syms = st_init_numtable();
    00186     }
    00187     id = p->syms->num_entries + 1;
    00188     st_insert( p->syms, id, (st_data_t)data );
    00189     return id;
    00190 }
    00191
    00192 int
    00193 syck_lookup_sym( SyckParser *p, SYMID id, void **datap )
    00194 {
    00195     st_data_t data;
    00196     int ret;
    00197     if ( p->syms == NULL ) return 0;
    00198     ret = st_lookup( p->syms, id, &data );
    00199     if(ret) *datap = (void *)data;
    00200     return ret;
    00201 }
    00202
    00203 int
    00204 syck_st_free_nodes( char *key, SyckNode *n, char *arg )
    00205 {
    00206     if ( n != (void *)1 ) syck_free_node( n );
    00207     n = NULL;
    00208     return ST_CONTINUE;
    00209 }
    00210
    00211 void
    00212 syck_st_free( SyckParser *p )
    00213 {
    00214     /*
    00215      * Free the anchor tables
    00216      */
    00217     if ( p->anchors != NULL )
    00218     {
    00219         st_foreach( p->anchors, syck_st_free_nodes, 0 );
    00220         st_free_table( p->anchors );
    00221         p->anchors = NULL;
    00222     }
    00223
    00224     if ( p->bad_anchors != NULL )
    00225     {
    00226         st_foreach( p->bad_anchors, syck_st_free_nodes, 0 );
    00227         st_free_table( p->bad_anchors );
    00228         p->bad_anchors = NULL;
    00229     }
    00230 }
    00231
    00232 typedef struct {
    00233    long hash;
    00234    char *buffer;
    00235    long length;
    00236    long remaining;
    00237    int  printed;
    00238 } bytestring_t;
    00239
    00240 int
    00241 syck_st_free_syms( void *key, bytestring_t *sav, void *dummy )
    00242 {
    00243     S_FREE(sav->buffer);
    00244     S_FREE(sav);
    00245     return ST_CONTINUE;
    00246 }
    00247
    00248 void
    00249 syck_free_parser( SyckParser *p )
    00250 {
    00251     /*
    00252      * Free the adhoc symbol table
    00253      */
    00254     if ( p->syms != NULL )
    00255     {
    00256         st_foreach( p->syms, syck_st_free_syms, 0 );
    00257         st_free_table( p->syms );
    00258         p->syms = NULL;
    00259     }
    00260
    00261     /*
    00262      * Free tables, levels
    00263      */
    00264     syck_st_free( p );
    00265     syck_parser_reset_levels( p );
    00266     S_FREE( p->levels[0].domain );
    00267     S_FREE( p->levels );
    00268
    00269     if ( p->buffer != NULL )
    00270     {
    00271         S_FREE( p->buffer );
    00272     }
    00273     free_any_io( p );
    00274     S_FREE( p );
    00275 }
    00276
    00277 void
    00278 syck_parser_handler( SyckParser *p, SyckNodeHandler hdlr )
    00279 {
    00280     ASSERT( p != NULL );
    00281     p->handler = hdlr;
    00282 }
    00283
    00284 void
    00285 syck_parser_implicit_typing( SyckParser *p, int flag )
    00286 {
    00287     p->implicit_typing = ( flag == 0 ? 0 : 1 );
    00288 }
    00289
    00290 void
    00291 syck_parser_taguri_expansion( SyckParser *p, int flag )
    00292 {
    00293     p->taguri_expansion = ( flag == 0 ? 0 : 1 );
    00294 }
    00295
    00296 void
    00297 syck_parser_error_handler( SyckParser *p, SyckErrorHandler hdlr )
    00298 {
    00299     ASSERT( p != NULL );
    00300     p->error_handler = hdlr;
    00301 }
    00302
    00303 void
    00304 syck_parser_bad_anchor_handler( SyckParser *p, SyckBadAnchorHandler hdlr )
    00305 {
    00306     ASSERT( p != NULL );
    00307     p->bad_anchor_handler = hdlr;
    00308 }
    00309
    00310 void
    00311 syck_parser_set_input_type( SyckParser *p, enum syck_parser_input input_type )
    00312 {
    00313     ASSERT( p != NULL );
    00314     p->input_type = input_type;
    00315 }
    00316
    00317 void
    00318 syck_parser_file( SyckParser *p, FILE *fp, SyckIoFileRead read )
    00319 {
    00320     ASSERT( p != NULL );
    00321     free_any_io( p );
    00322         syck_parser_reset_cursor( p );
    00323     p->io_type = syck_io_file;
    00324     p->io.file = S_ALLOC( SyckIoFile );
    00325     p->io.file->ptr = fp;
    00326     if ( read != NULL )
    00327     {
    00328         p->io.file->read = read;
    00329     }
    00330     else
    00331     {
    00332         p->io.file->read = syck_io_file_read;
    00333     }
    00334 }
    00335
    00336 void
    00337 syck_parser_str( SyckParser *p, char *ptr, long len, SyckIoStrRead read )
    00338 {
    00339     ASSERT( p != NULL );
    00340     free_any_io( p );
    00341         syck_parser_reset_cursor( p );
    00342     p->io_type = syck_io_str;
    00343     p->io.str = S_ALLOC( SyckIoStr );
    00344     p->io.str->beg = ptr;
    00345     p->io.str->ptr = ptr;
    00346     p->io.str->end = ptr + len;
    00347     if ( read != NULL )
    00348     {
    00349         p->io.str->read = read;
    00350     }
    00351     else
    00352     {
    00353         p->io.str->read = syck_io_str_read;
    00354     }
    00355 }
    00356
    00357 void
    00358 syck_parser_str_auto( SyckParser *p, char *ptr, SyckIoStrRead read )
    00359 {
    00360     syck_parser_str( p, ptr, strlen( ptr ), read );
    00361 }
    00362
    00363 SyckLevel *
    00364 syck_parser_current_level( SyckParser *p )
    00365 {
    00366     return &p->levels[p->lvl_idx-1];
    00367 }
    00368
    00369 void
    00370 syck_parser_pop_level( SyckParser *p )
    00371 {
    00372     ASSERT( p != NULL );
    00373
    00374     /* The root level should never be popped */
    00375     if ( p->lvl_idx <= 1 ) return;
    00376
    00377     p->lvl_idx -= 1;
    00378     free( p->levels[p->lvl_idx].domain );
    00379 }
    00380
    00381 void
    00382 syck_parser_add_level( SyckParser *p, int len, enum syck_level_status status )
    00383 {
    00384     ASSERT( p != NULL );
    00385     if ( p->lvl_idx + 1 > p->lvl_capa )
    00386     {
    00387         p->lvl_capa += ALLOC_CT;
    00388         S_REALLOC_N( p->levels, SyckLevel, p->lvl_capa );
    00389     }
    00390
    00391     ASSERT( len > p->levels[p->lvl_idx-1].spaces );
    00392     p->levels[p->lvl_idx].spaces = len;
    00393     p->levels[p->lvl_idx].ncount = 0;
    00394     p->levels[p->lvl_idx].domain = syck_strndup( p->levels[p->lvl_idx-1].domain, strlen( p->levels[p->lvl_idx-1].domain ) );
    00395     p->levels[p->lvl_idx].status = status;
    00396     p->lvl_idx += 1;
    00397 }
    00398
    00399 void
    00400 free_any_io( SyckParser *p )
    00401 {
    00402     ASSERT( p != NULL );
    00403     switch ( p->io_type )
    00404     {
    00405         case syck_io_str:
    00406             if ( p->io.str != NULL )
    00407             {
    00408                 S_FREE( p->io.str );
    00409                 p->io.str = NULL;
    00410             }
    00411         break;
    00412
    00413         case syck_io_file:
    00414             if ( p->io.file != NULL )
    00415             {
    00416                 S_FREE( p->io.file );
    00417                 p->io.file = NULL;
    00418             }
    00419         break;
    00420     }
    00421 }
    00422
    00423 long
    00424 syck_move_tokens( SyckParser *p )
    00425 {
    00426     long count, skip;
    00427     ASSERT( p->buffer != NULL );
    00428
    00429     if ( p->token == NULL )
    00430         return 0;
    00431
    00432     skip = p->limit - p->token;
    00433     if ( ( count = p->token - p->buffer ) )
    00434     {
    00435         if (skip > 0)
    00436             S_MEMMOVE( p->buffer, p->token, char, skip );
    00437         p->token = p->buffer;
    00438         p->marker -= count;
    00439         p->cursor -= count;
    00440         p->toktmp -= count;
    00441         p->limit -= count;
    00442         p->lineptr -= count;
    00443         p->linectptr -= count;
    00444     }
    00445     return skip;
    00446 }
    00447
    00448 void
    00449 syck_check_limit( SyckParser *p, long len )
    00450 {
    00451     if ( p->cursor == NULL )
    00452     {
    00453         p->cursor = p->buffer;
    00454         p->lineptr = p->buffer;
    00455         p->linectptr = p->buffer;
    00456         p->marker = p->buffer;
    00457     }
    00458     p->limit = p->buffer + len;
    00459 }
    00460
    00461 long
    00462 syck_parser_read( SyckParser *p )
    00463 {
    00464     long len = 0;
    00465     long skip = 0;
    00466     ASSERT( p != NULL );
    00467     switch ( p->io_type )
    00468     {
    00469         case syck_io_str:
    00470             skip = syck_move_tokens( p );
    00471             len = (p->io.str->read)( p->buffer, p->io.str, SYCK_BUFFERSIZE - 1, skip );
    00472             break;
    00473
    00474         case syck_io_file:
    00475             skip = syck_move_tokens( p );
    00476             len = (p->io.file->read)( p->buffer, p->io.file, SYCK_BUFFERSIZE - 1, skip );
    00477             break;
    00478     }
    00479     syck_check_limit( p, len );
    00480     return len;
    00481 }
    00482
    00483 long
    00484 syck_parser_readlen( SyckParser *p, long max_size )
    00485 {
    00486     long len = 0;
    00487     long skip = 0;
    00488     ASSERT( p != NULL );
    00489     switch ( p->io_type )
    00490     {
    00491         case syck_io_str:
    00492             skip = syck_move_tokens( p );
    00493             len = (p->io.str->read)( p->buffer, p->io.str, max_size, skip );
    00494             break;
    00495
    00496         case syck_io_file:
    00497             skip = syck_move_tokens( p );
    00498             len = (p->io.file->read)( p->buffer, p->io.file, max_size, skip );
    00499             break;
    00500     }
    00501     syck_check_limit( p, len );
    00502     return len;
    00503 }
    00504
    00505 SYMID
    00506 syck_parse( SyckParser *p )
    00507 {
    00508     ASSERT( p != NULL );
    00509
    00510     syck_st_free( p );
    00511     syck_parser_reset_levels( p );
    00512     syckparse( p );
    00513     return p->root;
    00514 }
    00515
    00516 void
    00517 syck_default_error_handler( SyckParser *p, const char *msg )
    00518 {
    00519     printf( "Error at [Line %d, Col %"PRIdPTRDIFF"]: %s\n",
    00520         p->linect,
    00521         p->cursor - p->lineptr,
    00522         msg );
    00523 }
    00524
    00525