vita-toolchain

git clone https://git.neptards.moe/neptards/vita-toolchain.git
Log | Files | Refs | README | LICENSE

yamltree.c (10049B)


      1 /*
      2 
      3 Copyright (C) 2016, David "Davee" Morgan
      4 
      5 Permission is hereby granted, free of charge, to any person obtaining a
      6 copy of this software and associated documentation files (the "Software"),
      7 to deal in the Software without restriction, including without limitation
      8 the rights to use, copy, modify, merge, publish, distribute, sublicense,
      9 and/or sell copies of the Software, and to permit persons to whom the
     10 Software is furnished to do so, subject to the following conditions:
     11 
     12 The above copyright notice and this permission notice shall be included in
     13 all copies or substantial portions of the Software.
     14 
     15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     18 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     19 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     20 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
     21 DEALINGS IN THE SOFTWARE.
     22 
     23 */
     24 
     25 #include "yamltree.h"
     26 #include <yaml.h>
     27 #include <stdio.h>
     28 #include <string.h>
     29 #include <assert.h>
     30 
     31 typedef struct 
     32 {
     33 	yaml_parser_t parser;
     34 	yaml_event_t event;
     35 	yaml_event_t next_event;
     36 	yaml_error *error;
     37 } parser_context;
     38 
     39 static yaml_node *process_node(parser_context *ctx);
     40 
     41 char *format_error_string(parser_context *ctx)
     42 {
     43 	assert(ctx->parser.error != YAML_NO_ERROR);
     44 	char *ptr;
     45 	
     46 	switch (ctx->parser.error)
     47 	{
     48 		case YAML_MEMORY_ERROR:
     49 			asprintf(&ptr, "libyaml: failed to allocate or reallocate a block of memory.");
     50 			break;
     51 			
     52 		case YAML_READER_ERROR:
     53 			if (ctx->parser.problem_value != -1)
     54 				asprintf(&ptr, "libyaml: reader error: '%s:#%X' at line %d, column %d.", ctx->parser.problem, ctx->parser.problem_value, ctx->parser.problem_mark.line, ctx->parser.problem_mark.column);
     55 			else
     56 				asprintf(&ptr, "libyaml: reader error: '%s' at line %d, column %d.", ctx->parser.problem, ctx->parser.problem_mark.line, ctx->parser.problem_mark.column);
     57 			break;
     58 			
     59 		case YAML_SCANNER_ERROR:
     60 			asprintf(&ptr, "libyaml: scanner error: '%s' at line %d, column %d.", ctx->parser.problem, ctx->parser.problem_mark.line, ctx->parser.problem_mark.column);
     61 			break;
     62 			
     63 		case YAML_PARSER_ERROR:
     64 			asprintf(&ptr, "libyaml: parser error: '%s' at line %d, column %d.", ctx->parser.problem, ctx->parser.problem_mark.line, ctx->parser.problem_mark.column);
     65 			break;
     66 			
     67 		case YAML_COMPOSER_ERROR:
     68 			asprintf(&ptr, "libyaml: composer error: '%s' at line %d, column %d.", ctx->parser.problem, ctx->parser.problem_mark.line, ctx->parser.problem_mark.column);
     69 			break;
     70 			
     71 		case YAML_WRITER_ERROR:
     72 			asprintf(&ptr, "libyaml: writer error: '%s' at line %d, column %d.", ctx->parser.problem, ctx->parser.problem_mark.line, ctx->parser.problem_mark.column);
     73 			break;
     74 			
     75 		case YAML_EMITTER_ERROR:
     76 			asprintf(&ptr, "libyaml: emitter error: '%s' at line %d, column %d.", ctx->parser.problem, ctx->parser.problem_mark.line, ctx->parser.problem_mark.column);
     77 			break;
     78 			
     79 		default:
     80 			asprintf(&ptr, "unknown error code (%i) from libyaml. possible memory corruption?", ctx->parser.error);
     81 			break;
     82 	}
     83 	
     84 	assert(ptr);
     85 	return ptr;
     86 }
     87 
     88 static const char *event_to_string(yaml_event_type_t event)
     89 {
     90 	switch (event)
     91 	{
     92 		case YAML_NO_EVENT:
     93 			return "YAML_NO_EVENT";
     94 		case YAML_STREAM_START_EVENT:
     95 			return "YAML_STREAM_START_EVENT";
     96 		case YAML_STREAM_END_EVENT:
     97 			return "YAML_STREAM_END_EVENT";
     98 		case YAML_DOCUMENT_START_EVENT:
     99 			return "YAML_DOCUMENT_START_EVENT";
    100 		case YAML_DOCUMENT_END_EVENT:
    101 			return "YAML_DOCUMENT_END_EVENT";
    102 		case YAML_ALIAS_EVENT:
    103 			return "YAML_ALIAS_EVENT";
    104 		case YAML_SCALAR_EVENT:
    105 			return "YAML_SCALAR_EVENT";
    106 		case YAML_SEQUENCE_START_EVENT:
    107 			return "YAML_SEQUENCE_START_EVENT";
    108 		case YAML_SEQUENCE_END_EVENT:
    109 			return "YAML_SEQUENCE_END_EVENT";
    110 		case YAML_MAPPING_START_EVENT:
    111 			return "YAML_MAPPING_START_EVENT";
    112 		case YAML_MAPPING_END_EVENT:
    113 			return "YAML_MAPPING_END_EVENT";
    114 		default:
    115 			return "UNKNOWN";
    116 	}
    117 	
    118 	assert(0);
    119 	return "UNKNOWN";
    120 }
    121 
    122 static int is_error_set(parser_context *ctx)
    123 {
    124 	return ctx->error->problem != NULL;
    125 }
    126 
    127 static int set_error(parser_context *ctx)
    128 {
    129 	if (!is_error_set(ctx) && ctx->parser.error)
    130 	{
    131 		ctx->error->problem = format_error_string(ctx);
    132 		return 1;
    133 	}
    134 	
    135 	return 0;
    136 }
    137 
    138 static int process_event(parser_context *ctx) 
    139 {
    140 	memcpy(&ctx->event, &ctx->next_event, sizeof(yaml_event_t));
    141 	yaml_parser_parse(&ctx->parser, &ctx->next_event);
    142 	return set_error(ctx) ? (-1) : (0);
    143 }
    144 
    145 static yaml_event_type_t peek_next_event(parser_context *ctx) 
    146 {
    147 	// just peek the next event
    148 	return ctx->next_event.type;
    149 }
    150 
    151 static yaml_event_type_t next_event(parser_context *ctx) 
    152 {
    153 	// process event and return it
    154 	if (process_event(ctx) < 0)
    155 		return YAML_NO_EVENT;
    156 	
    157 	return ctx->event.type;
    158 }
    159 
    160 static yaml_node *process_scalar(parser_context *ctx) 
    161 {
    162 	yaml_node *scalar = malloc(sizeof(yaml_node));
    163 	scalar->type = NODE_SCALAR;
    164 	scalar->position.line = ctx->event.start_mark.line;
    165 	scalar->position.column = ctx->event.start_mark.column;
    166 	scalar->data.scalar.value = strdup(ctx->event.data.scalar.value);
    167 	scalar->data.scalar.len = ctx->event.data.scalar.length;
    168 	return scalar;
    169 }
    170 
    171 static yaml_node *process_sequence(parser_context *ctx) 
    172 {
    173 	yaml_node *sequence = (yaml_node *)malloc(sizeof(yaml_node));
    174 	if (!sequence)
    175 		return NULL;
    176 	yaml_sequence *seq = &sequence->data.sequence;
    177 	
    178 	sequence->type = NODE_SEQUENCE;
    179 	sequence->position.line = ctx->event.start_mark.line;
    180 	sequence->position.column = ctx->event.start_mark.column;
    181 	
    182 	// zero out values
    183 	seq->count = 0;
    184 	seq->nodes = NULL;
    185 	
    186 	while (peek_next_event(ctx) != YAML_SEQUENCE_END_EVENT)
    187 	{
    188 		yaml_node *node = process_node(ctx);
    189 		
    190 		if (!node)
    191 		{
    192 			free(sequence);
    193 			return NULL;
    194 		}
    195 		
    196 		// extend space
    197 		seq->nodes = realloc(seq->nodes, (seq->count+1)*sizeof(yaml_node*));
    198 		seq->nodes[seq->count++] = node;
    199 	}
    200 	
    201 	if (process_event(ctx) < 0)
    202 	{
    203 		free(sequence);
    204 		return NULL;
    205 	}
    206 	
    207 	return sequence;
    208 }
    209 
    210 static yaml_node *process_mapping(parser_context *ctx)
    211 {
    212 	yaml_node *mapping = (yaml_node *)malloc(sizeof(yaml_node));
    213 	if (!mapping)
    214 		return NULL;
    215 	yaml_mapping *map = &mapping->data.mapping;
    216 	
    217 	mapping->type = NODE_MAPPING;
    218 	mapping->position.line = ctx->event.start_mark.line;
    219 	mapping->position.column = ctx->event.start_mark.column;
    220 	
    221 	// zero out values
    222 	map->count = 0;
    223 	map->pairs = NULL;
    224 	
    225 	while (peek_next_event(ctx) != YAML_MAPPING_END_EVENT)
    226 	{
    227 		yaml_node_pair *pair = malloc(sizeof(yaml_node_pair));
    228 		
    229 		pair->lhs = process_node(ctx);
    230 		
    231 		if (!pair->lhs)
    232 		{
    233 			free(mapping);
    234 			return NULL;
    235 		}
    236 		
    237 		pair->rhs = process_node(ctx);
    238 		
    239 		if (!pair->rhs)
    240 		{
    241 			free(mapping);
    242 			return NULL;
    243 		}
    244 		
    245 		// extend space as needed
    246 		map->pairs = realloc(map->pairs, (map->count+1)*sizeof(yaml_node_pair*));
    247 		map->pairs[map->count++] = pair;
    248 	}
    249 	
    250 	if (process_event(ctx) < 0)
    251 	{
    252 		free(mapping);
    253 		return NULL;
    254 	}
    255 	
    256 	return mapping;
    257 }
    258 
    259 static yaml_node *process_node(parser_context *ctx)
    260 {
    261 	// we expect either: alias, scalar, sequence or mapping
    262 	switch (next_event(ctx)) 
    263 	{
    264 		case YAML_ALIAS_EVENT:
    265 			// TODO: we dont support aliases for now
    266 			asprintf(&ctx->error->problem, "yamltree: there is no support for aliases implemented.");
    267 			return NULL;
    268 			
    269 		case YAML_SCALAR_EVENT:
    270 			return process_scalar(ctx);
    271 		
    272 		case YAML_SEQUENCE_START_EVENT:
    273 			return process_sequence(ctx);
    274 			
    275 		case YAML_MAPPING_START_EVENT:
    276 			return process_mapping(ctx);
    277 			
    278 		default:
    279 			// probably an error
    280 			break;
    281 	}
    282 	
    283 	return NULL;
    284 }
    285 
    286 static yaml_document *process_document(parser_context *ctx)
    287 {
    288 	// look for document start event.
    289 	if (next_event(ctx) != YAML_DOCUMENT_START_EVENT)
    290 	{
    291 		if (!is_error_set(ctx))
    292 		{
    293 			asprintf(&ctx->error->problem, "yamltree: expecting YAML_DOCUMENT_START_EVENT got '%s'.", event_to_string(ctx->event.type));
    294 		}
    295 		
    296 		return NULL;
    297 	}
    298 	
    299 	// a document is basically a fancy name for a root node
    300 	yaml_document *doc = process_node(ctx);
    301 	
    302 	if (!doc)
    303 		return NULL;
    304 	
    305 	// get end of document
    306 	if (next_event(ctx) != YAML_DOCUMENT_END_EVENT)
    307 	{
    308 		if (!is_error_set(ctx))
    309 		{
    310 			asprintf(&ctx->error->problem, "yamltree: expecting YAML_DOCUMENT_END_EVENT got '%s'.", event_to_string(ctx->event.type));
    311 		}
    312 		
    313 		return NULL;
    314 	}
    315 	
    316 	return doc;
    317 }
    318 
    319 yaml_tree *parse_yaml_stream(FILE *input, yaml_error *error)
    320 {
    321 	parser_context ctx;
    322 	ctx.error = error;
    323 	yaml_parser_initialize(&ctx.parser);
    324 	yaml_parser_set_input_file(&ctx.parser, input);
    325 	
    326 	if (process_event(&ctx) < 0)
    327 		goto error;
    328 	
    329 	if (ctx.next_event.type != YAML_STREAM_START_EVENT)
    330 	{
    331 		asprintf(&ctx.error->problem, "yamltree: expecting YAML_STREAM_START_EVENT got '%s'.", event_to_string(ctx.next_event.type));
    332 		goto error;
    333 	}
    334 	
    335 	yaml_tree *stream = malloc(sizeof(yaml_tree));
    336 	
    337 	stream->count = 0;
    338 	stream->docs = NULL;
    339 	
    340 	while (next_event(&ctx) != YAML_STREAM_END_EVENT)
    341 	{
    342 		// check error
    343 		if (is_error_set(&ctx))
    344 		{
    345 			goto error;
    346 		}
    347 		
    348 		yaml_document *document = process_document(&ctx);
    349 		
    350 		if (!document)
    351 		{
    352 			// TODO: clean up structure
    353 			goto error;
    354 		}
    355 		
    356 		stream->docs = realloc(stream->docs, (stream->count+1)*sizeof(yaml_tree));
    357 		stream->docs[stream->count++] = document;
    358 	}
    359 	
    360 	yaml_parser_delete(&ctx.parser);
    361 	return stream;
    362 	
    363 error:
    364 	yaml_parser_delete(&ctx.parser);
    365 	return NULL;
    366 }
    367 
    368 void free_yaml_tree(yaml_tree *tree)
    369 {
    370 	// TODO: implement
    371 }
    372 
    373 const char *node_type_str(yaml_node *node)
    374 {
    375 	switch (node->type)
    376 	{
    377 		case NODE_MAPPING:
    378 			return "mapping";
    379 		case NODE_SEQUENCE:
    380 			return "sequence";
    381 		case NODE_SCALAR:
    382 			return "scalar";
    383 		default:
    384 			assert(0);
    385 			break;
    386 	}
    387 	
    388 	assert(0);
    389 	return NULL;
    390 }