* io.c (rb_open_file): encoding in mode string was ignored if perm is
[ruby-svn.git] / ext / syck / syck.c
blob92b7566d1a19de378716047ce1eb5b37b3c49c54
1 /*
2 * syck.c
4 * $Author$
6 * Copyright (C) 2003 why the lucky stiff
7 */
8 #include "ruby/ruby.h"
10 #include <stdio.h>
11 #include <string.h>
13 #include "syck.h"
15 void syck_parser_pop_level( SyckParser * );
18 * Custom assert
20 void
21 syck_assert( const char *file_name, unsigned line_num, const char *expr )
23 fflush( NULL );
24 fprintf( stderr, "\nAssertion failed: %s, line %u: %s\n",
25 file_name, line_num, expr );
26 fflush( stderr );
27 abort();
31 * Allocates and copies a string
33 char *
34 syck_strndup( const char *buf, long len )
36 char *new = S_ALLOC_N( char, len + 1 );
37 S_MEMZERO( new, char, len + 1 );
38 S_MEMCPY( new, buf, char, len );
39 return new;
43 * Default FILE IO function
45 long
46 syck_io_file_read( char *buf, SyckIoFile *file, long max_size, long skip )
48 long len = 0;
50 ASSERT( file != NULL );
52 max_size -= skip;
53 len = fread( buf + skip, sizeof( char ), max_size, file->ptr );
54 len += skip;
55 buf[len] = '\0';
57 return len;
61 * Default string IO function
63 long
64 syck_io_str_read( char *buf, SyckIoStr *str, long max_size, long skip )
66 char *beg;
67 long len = 0;
69 ASSERT( str != NULL );
70 beg = str->ptr;
71 if ( max_size >= 0 )
73 max_size -= skip;
74 if ( max_size <= 0 ) max_size = 0;
75 else str->ptr += max_size;
77 if ( str->ptr > str->end )
79 str->ptr = str->end;
82 else
84 /* Use exact string length */
85 while ( str->ptr < str->end ) {
86 if (*(str->ptr++) == '\n') break;
89 if ( beg < str->ptr )
91 len = ( str->ptr - beg );
92 S_MEMCPY( buf + skip, beg, char, len );
94 len += skip;
95 buf[len] = '\0';
97 return len;
100 void
101 syck_parser_reset_levels( SyckParser *p )
103 while ( p->lvl_idx > 1 )
105 syck_parser_pop_level( p );
108 if ( p->lvl_idx < 1 )
110 p->lvl_idx = 1;
111 p->levels[0].spaces = -1;
112 p->levels[0].ncount = 0;
113 p->levels[0].domain = syck_strndup( "", 0 );
115 p->levels[0].status = syck_lvl_header;
118 void
119 syck_parser_reset_cursor( SyckParser *p )
121 if ( p->buffer == NULL )
123 p->buffer = S_ALLOC_N( char, p->bufsize );
124 S_MEMZERO( p->buffer, char, p->bufsize );
126 p->buffer[0] = '\0';
128 p->cursor = NULL;
129 p->lineptr = NULL;
130 p->linectptr = NULL;
131 p->token = NULL;
132 p->toktmp = NULL;
133 p->marker = NULL;
134 p->limit = NULL;
136 p->root = 0;
137 p->root_on_error = 0;
138 p->linect = 0;
139 p->eof = 0;
140 p->last_token = 0;
141 p->force_token = 0;
145 * Value to return on a parse error
147 void
148 syck_parser_set_root_on_error( SyckParser *p, SYMID roer )
150 p->root_on_error = roer;
154 * Allocate the parser
156 SyckParser *
157 syck_new_parser(void)
159 SyckParser *p;
160 p = S_ALLOC( SyckParser );
161 S_MEMZERO( p, SyckParser, 1 );
162 p->lvl_capa = ALLOC_CT;
163 p->levels = S_ALLOC_N( SyckLevel, p->lvl_capa );
164 p->input_type = syck_yaml_utf8;
165 p->io_type = syck_io_str;
166 p->io.str = NULL;
167 p->syms = NULL;
168 p->anchors = NULL;
169 p->bad_anchors = NULL;
170 p->implicit_typing = 1;
171 p->taguri_expansion = 0;
172 p->bufsize = SYCK_BUFFERSIZE;
173 p->buffer = NULL;
174 p->lvl_idx = 0;
175 syck_parser_reset_levels( p );
176 return p;
180 syck_add_sym( SyckParser *p, void *data )
182 SYMID id = 0;
183 if ( p->syms == NULL )
185 p->syms = st_init_numtable();
187 id = p->syms->num_entries + 1;
188 st_insert( p->syms, id, (st_data_t)data );
189 return id;
193 syck_lookup_sym( SyckParser *p, SYMID id, void **datap )
195 st_data_t data = (st_data_t)*datap;
196 int ret;
197 if ( p->syms == NULL ) return 0;
198 ret = st_lookup( p->syms, id, &data );
199 *datap = (void *)data;
200 return ret;
204 syck_st_free_nodes( char *key, SyckNode *n, char *arg )
206 if ( n != (void *)1 ) syck_free_node( n );
207 n = NULL;
208 return ST_CONTINUE;
211 void
212 syck_st_free( SyckParser *p )
215 * Free the anchor tables
217 if ( p->anchors != NULL )
219 st_foreach( p->anchors, syck_st_free_nodes, 0 );
220 st_free_table( p->anchors );
221 p->anchors = NULL;
224 if ( p->bad_anchors != NULL )
226 st_foreach( p->bad_anchors, syck_st_free_nodes, 0 );
227 st_free_table( p->bad_anchors );
228 p->bad_anchors = NULL;
232 typedef struct {
233 long hash;
234 char *buffer;
235 long length;
236 long remaining;
237 int printed;
238 } bytestring_t;
241 syck_st_free_syms( void *key, bytestring_t *sav, void *dummy )
243 S_FREE(sav->buffer);
244 S_FREE(sav);
245 return ST_CONTINUE;
248 void
249 syck_free_parser( SyckParser *p )
252 * Free the adhoc symbol table
254 if ( p->syms != NULL )
256 st_foreach( p->syms, syck_st_free_syms, 0 );
257 st_free_table( p->syms );
258 p->syms = NULL;
262 * Free tables, levels
264 syck_st_free( p );
265 syck_parser_reset_levels( p );
266 S_FREE( p->levels[0].domain );
267 S_FREE( p->levels );
269 if ( p->buffer != NULL )
271 S_FREE( p->buffer );
273 free_any_io( p );
274 S_FREE( p );
277 void
278 syck_parser_handler( SyckParser *p, SyckNodeHandler hdlr )
280 ASSERT( p != NULL );
281 p->handler = hdlr;
284 void
285 syck_parser_implicit_typing( SyckParser *p, int flag )
287 p->implicit_typing = ( flag == 0 ? 0 : 1 );
290 void
291 syck_parser_taguri_expansion( SyckParser *p, int flag )
293 p->taguri_expansion = ( flag == 0 ? 0 : 1 );
296 void
297 syck_parser_error_handler( SyckParser *p, SyckErrorHandler hdlr )
299 ASSERT( p != NULL );
300 p->error_handler = hdlr;
303 void
304 syck_parser_bad_anchor_handler( SyckParser *p, SyckBadAnchorHandler hdlr )
306 ASSERT( p != NULL );
307 p->bad_anchor_handler = hdlr;
310 void
311 syck_parser_set_input_type( SyckParser *p, enum syck_parser_input input_type )
313 ASSERT( p != NULL );
314 p->input_type = input_type;
317 void
318 syck_parser_file( SyckParser *p, FILE *fp, SyckIoFileRead read )
320 ASSERT( p != NULL );
321 free_any_io( p );
322 syck_parser_reset_cursor( p );
323 p->io_type = syck_io_file;
324 p->io.file = S_ALLOC( SyckIoFile );
325 p->io.file->ptr = fp;
326 if ( read != NULL )
328 p->io.file->read = read;
330 else
332 p->io.file->read = syck_io_file_read;
336 void
337 syck_parser_str( SyckParser *p, char *ptr, long len, SyckIoStrRead read )
339 ASSERT( p != NULL );
340 free_any_io( p );
341 syck_parser_reset_cursor( p );
342 p->io_type = syck_io_str;
343 p->io.str = S_ALLOC( SyckIoStr );
344 p->io.str->beg = ptr;
345 p->io.str->ptr = ptr;
346 p->io.str->end = ptr + len;
347 if ( read != NULL )
349 p->io.str->read = read;
351 else
353 p->io.str->read = syck_io_str_read;
357 void
358 syck_parser_str_auto( SyckParser *p, char *ptr, SyckIoStrRead read )
360 syck_parser_str( p, ptr, strlen( ptr ), read );
363 SyckLevel *
364 syck_parser_current_level( SyckParser *p )
366 return &p->levels[p->lvl_idx-1];
369 void
370 syck_parser_pop_level( SyckParser *p )
372 ASSERT( p != NULL );
374 /* The root level should never be popped */
375 if ( p->lvl_idx <= 1 ) return;
377 p->lvl_idx -= 1;
378 free( p->levels[p->lvl_idx].domain );
381 void
382 syck_parser_add_level( SyckParser *p, int len, enum syck_level_status status )
384 ASSERT( p != NULL );
385 if ( p->lvl_idx + 1 > p->lvl_capa )
387 p->lvl_capa += ALLOC_CT;
388 S_REALLOC_N( p->levels, SyckLevel, p->lvl_capa );
391 ASSERT( len > p->levels[p->lvl_idx-1].spaces );
392 p->levels[p->lvl_idx].spaces = len;
393 p->levels[p->lvl_idx].ncount = 0;
394 p->levels[p->lvl_idx].domain = syck_strndup( p->levels[p->lvl_idx-1].domain, strlen( p->levels[p->lvl_idx-1].domain ) );
395 p->levels[p->lvl_idx].status = status;
396 p->lvl_idx += 1;
399 void
400 free_any_io( SyckParser *p )
402 ASSERT( p != NULL );
403 switch ( p->io_type )
405 case syck_io_str:
406 if ( p->io.str != NULL )
408 S_FREE( p->io.str );
409 p->io.str = NULL;
411 break;
413 case syck_io_file:
414 if ( p->io.file != NULL )
416 S_FREE( p->io.file );
417 p->io.file = NULL;
419 break;
423 long
424 syck_move_tokens( SyckParser *p )
426 long count, skip;
427 ASSERT( p->buffer != NULL );
429 if ( p->token == NULL )
430 return 0;
432 skip = p->limit - p->token;
433 if ( ( count = p->token - p->buffer ) )
435 if (skip > 0)
436 S_MEMMOVE( p->buffer, p->token, char, skip );
437 p->token = p->buffer;
438 p->marker -= count;
439 p->cursor -= count;
440 p->toktmp -= count;
441 p->limit -= count;
442 p->lineptr -= count;
443 p->linectptr -= count;
445 return skip;
448 void
449 syck_check_limit( SyckParser *p, long len )
451 if ( p->cursor == NULL )
453 p->cursor = p->buffer;
454 p->lineptr = p->buffer;
455 p->linectptr = p->buffer;
456 p->marker = p->buffer;
458 p->limit = p->buffer + len;
461 long
462 syck_parser_read( SyckParser *p )
464 long len = 0;
465 long skip = 0;
466 ASSERT( p != NULL );
467 switch ( p->io_type )
469 case syck_io_str:
470 skip = syck_move_tokens( p );
471 len = (p->io.str->read)( p->buffer, p->io.str, SYCK_BUFFERSIZE - 1, skip );
472 break;
474 case syck_io_file:
475 skip = syck_move_tokens( p );
476 len = (p->io.file->read)( p->buffer, p->io.file, SYCK_BUFFERSIZE - 1, skip );
477 break;
479 syck_check_limit( p, len );
480 return len;
483 long
484 syck_parser_readlen( SyckParser *p, long max_size )
486 long len = 0;
487 long skip = 0;
488 ASSERT( p != NULL );
489 switch ( p->io_type )
491 case syck_io_str:
492 skip = syck_move_tokens( p );
493 len = (p->io.str->read)( p->buffer, p->io.str, max_size, skip );
494 break;
496 case syck_io_file:
497 skip = syck_move_tokens( p );
498 len = (p->io.file->read)( p->buffer, p->io.file, max_size, skip );
499 break;
501 syck_check_limit( p, len );
502 return len;
505 SYMID
506 syck_parse( SyckParser *p )
508 ASSERT( p != NULL );
510 syck_st_free( p );
511 syck_parser_reset_levels( p );
512 syckparse( p );
513 return p->root;
516 void
517 syck_default_error_handler( SyckParser *p, const char *msg )
519 printf( "Error at [Line %d, Col %"PRIdPTRDIFF"]: %s\n",
520 p->linect,
521 p->cursor - p->lineptr,
522 msg );