diff --git a/src/common/parser.c b/src/common/parser.c index 89304a6..513c298 100644 --- a/src/common/parser.c +++ b/src/common/parser.c @@ -1,20 +1,18 @@ #include "parser.h" #include "hashmap.h" +#include "array.h" #include "log.h" +#include "string_utils.h" #include #include +#include +#include #define MAX_LINE_LEN 512 #define MAX_VALUE_LEN 512 -struct Parser_Object -{ - int type; - char* key; - char* value; - char* object_data; -}; +static int parser_object_type_from_str(const char* str); bool parser_load(FILE* file, const char* filename, Parser_Assign_Func assign_func, bool return_on_emptyline, int current_line) { @@ -37,6 +35,7 @@ bool parser_load(FILE* file, const char* filename, Parser_Assign_Func assign_fun char line_buffer[MAX_LINE_LEN]; memset(key_str, '\0', HASH_MAX_KEY_LEN); memset(line_buffer, '\0', MAX_LINE_LEN); + memset(format_str, '\0', 64); snprintf(format_str, 64, " %%%d[^: ] : %%%d[^\n]", HASH_MAX_KEY_LEN, MAX_VALUE_LEN); while(fgets(line_buffer, MAX_LINE_LEN - 1, file)) @@ -67,7 +66,7 @@ bool parser_load(FILE* file, const char* filename, Parser_Assign_Func assign_fun return true; } -bool parser_load_objects(FILE* file, const char* filename) +struct Parser* parser_load_objects(FILE* file, const char* filename) { /* Note, this is isn't really a proper parser and might have lurking bugs, it just has to be good enough for my needs. For example, multiple opening and closing braces on them @@ -82,6 +81,16 @@ bool parser_load_objects(FILE* file, const char* filename) return false; } + struct Parser* parser = malloc(sizeof(*parser)); + if(!parser) + { + log_error("parser:load_objects", "Out of memeory"); + return parser; + } + + parser->filename = str_new(filename); + parser->objects = array_new(struct Parser_Object); + int current_line = 0; char line_buffer[MAX_LINE_LEN]; char type_str[HASH_MAX_KEY_LEN]; @@ -136,7 +145,7 @@ bool parser_load_objects(FILE* file, const char* filename) if(c == '{') { - obj_beginning = ftell(file) - 1; + obj_beginning = ftell(file); c = ' '; while(!feof(file)) { @@ -158,7 +167,7 @@ bool parser_load_objects(FILE* file, const char* filename) if(c == '}') { - obj_ending = ftell(file); + obj_ending = ftell(file) - 1; break; } } @@ -185,8 +194,73 @@ bool parser_load_objects(FILE* file, const char* filename) memset(line_buffer, '\0', MAX_LINE_LEN); fseek(file, obj_beginning, SEEK_SET); fread(obj_str, obj_ending - obj_beginning, 1, file); - log_to_stdout("Object found\nType: %s\n%s\n\n", type_str, obj_str); + fseek(file, obj_ending + 1, SEEK_SET); // Position cursor after closing brace '}' + + // Read into intermediate parser object and add it to the objects list + struct Parser_Object* object = array_grow(parser->objects, struct Parser_Object); + object->type = parser_object_type_from_str(type_str); + object->data = hashmap_new(); + + char format_str[64]; + char key_str[HASH_MAX_KEY_LEN]; + char value_str[MAX_VALUE_LEN]; + + memset(format_str, '\0', 64); + snprintf(format_str, 64, " %%%d[^: ] : %%%d[^\n]", HASH_MAX_KEY_LEN, MAX_VALUE_LEN); + char* line = strtok(obj_str, "\n"); + do + { + memset(key_str, '\0', HASH_MAX_KEY_LEN); + memset(value_str, '\0', MAX_VALUE_LEN); + + if(strlen(line) == 0) + { + continue; + } + + if(line[0] == '#') + continue; + + if(sscanf(line, format_str, key_str, value_str) != 2) + { + log_warning("Malformed value in config file %s, line %d", filename, current_line); + continue; + } + hashmap_str_set(object->data, key_str, value_str); + } + while((line = strtok(NULL, "\n")) != NULL); + + //log_to_stdout("Object found\nType: %s\n%s\n\n", type_str, obj_str); } - return true; + return parser; +} + +int parser_object_type_from_str(const char* str) +{ + int object_type = PO_UNKNOWN; + + if(strncmp(str, "Entity", HASH_MAX_KEY_LEN) == 0) object_type = PO_ENTITY; + else if(strncmp(str, "Model", HASH_MAX_KEY_LEN) == 0) object_type = PO_MODEL; + else if(strncmp(str, "Material", HASH_MAX_KEY_LEN) == 0) object_type = PO_MATERIAL; + + return object_type; +} + +void parser_free(struct Parser *parser) +{ + assert(parser); + if(parser->filename) + { + free(parser->filename); + parser->filename = NULL; + } + + for(int i = 0; i < array_len(parser->objects); i++) + { + struct Parser_Object* object = &parser->objects[i]; + hashmap_free(object->data); + object->data = NULL; + object->type = PO_UNKNOWN; + } } diff --git a/src/common/parser.h b/src/common/parser.h index 42fdb43..4bf7b1e 100644 --- a/src/common/parser.h +++ b/src/common/parser.h @@ -3,11 +3,30 @@ #include "common.h" -struct Hashmap; +enum Parser_Object_Type +{ + PO_ENTITY, + PO_MATERIAL, + PO_MODEL, + PO_UNKNOWN +}; + +struct Parser_Object +{ + int type; + struct Hashmap* data; +}; + +struct Parser +{ + char* filename; + struct Parser_Object* objects; +}; typedef void (*Parser_Assign_Func)(const char* key, const char* value, const char* filename, int current_line); -bool parser_load(FILE* file, const char* filename, Parser_Assign_Func assign_func, bool return_on_emptyline, int current_line); -bool parser_load_objects(FILE* file, const char* filename); +bool parser_load(FILE* file, const char* filename, Parser_Assign_Func assign_func, bool return_on_emptyline, int current_line); +struct Parser* parser_load_objects(FILE* file, const char* filename); +void parser_free(struct Parser* parser); #endif diff --git a/src/libsymmetry/game.c b/src/libsymmetry/game.c index 0530261..1593a1e 100644 --- a/src/libsymmetry/game.c +++ b/src/libsymmetry/game.c @@ -217,10 +217,24 @@ void scene_setup(void) game_state->player_node = player->id; } - FILE* obj_file = platform->file.open(DIRT_INSTALL, "test_scene.symtres", "rb"); + FILE* obj_file = platform->file.open(DIRT_INSTALL, "obj_test.symtres", "rb"); if(obj_file) { - parser_load_objects(obj_file, "obj_test.symtres"); + struct Parser* parsed_file = parser_load_objects(obj_file, "obj_test.symtres"); + log_message("%d objects read from %s", array_len(parsed_file->objects), "obj_test.symtres"); + for(int i = 0; i < array_len(parsed_file->objects); i++) + { + struct Parser_Object* object = &parsed_file->objects[i]; + if(object->type == PO_UNKNOWN) + log_message("Type : Unknown"); + else if(object->type == PO_ENTITY) + log_message("Type : Entity"); + else if(object->type == PO_MATERIAL) + log_message("Type : Material"); + else if(object->type == PO_MODEL) + log_message("Type : Model"); + hashmap_debug_print(object->data); + } fclose(obj_file); } else