#include #include #include char * vx_parse_ini_section_name( vx_arena_s *arena, const char *source, uint32_t offset, uint32_t *len_name ) { ++offset; // Jump over the starting square bracket uint32_t start_offset = offset; while(source[offset] != 0) { if(source[offset] == ']') { ++offset; } ++offset; } uint32_t name_word_length = offset - start_offset; char *name = malloc(name_word_length + 1); memcpy(name, &source[start_offset], name_word_length); name[name_word_length] = 0; if(len_name) { *len_name = name_word_length; } return name; } vx_ini_value_s vx_parse_ini_value(vx_ini_s *ini, const char *source, uint32_t offset, uint32_t *out_length) { // For string values if(source[offset] == '"') { vx_ini_value_s value; uint32_t start_offset = offset; if(source[offset + 1] == '"') { // If this is an empty string if(source[offset + 2] != '"') { value.type = VX_INI_VALUE_STRING; value.specifics.string = vx_arena_alloc(ini->string_arena, 1); value.specifics.string[0] = 0; return value; } // If this is a multi-line string offset += 3; // Jump over the quotation marks so they can't be picked up as the ending ones. uint32_t string_data_start = offset; while(source[offset != 0]) { if(source[offset] != '"') { ++offset; continue; } if(source[offset + 1] != '"') { ++offset; continue; } if(source[offset + 2] != '"') { ++offset; continue; } break; } value.type = VX_INI_VALUE_STRING; value.specifics.string = vx_arena_dupe_string_up_to(ini->string_arena, &source[string_data_start], offset - string_data_start); return value; } // A regular, single-line string ++offset; while(source[offset] != 0) { if(source[offset] == '\n') { break; } if(source[offset] == '"') { break; } ++offset; } value.type = VX_INI_VALUE_STRING; value.specifics.string = vx_arena_dupe_string_up_to(ini->string_arena, &source[start_offset], offset - start_offset); return value; } if(vx_is_ascii_digit(source[offset])) { vx_ini_value_s value; uint32_t start_offset = offset; while(source[offset] != 0) { if( ! vx_is_ascii_digit(source[offset])) { break; } ++offset; } // todo(delayed): Add floating-point numbers char *integer_string = vx_arena_dupe_string_up_to(ini->string_arena, &source[start_offset], offset - start_offset); value.type = VX_INI_VALUE_INTEGER; value.specifics.integer = atol(integer_string); return value; } vx_ini_value_s value; value.type = VX_INI_VALUE_NULL; return value; } vx_ini_field_s vx_parse_ini_field(vx_ini_s *ini, const char *source, uint32_t offset, uint32_t *out_length) { uint32_t start_offset = offset; // Get the field's name while(source[offset] != 0) { if( ! vx_is_ascii_letter(source[offset]) && (source[offset] != '_')) { break; } ++offset; } vx_ini_field_s field; field.len_name = offset - start_offset; field.name = vx_arena_dupe_string_up_to(ini->string_arena, &source[offset], field.len_name); uint32_t len_value; field.value = vx_parse_ini_value(ini, source, offset, &len_value); if(out_length) { *out_length = (offset - start_offset) + len_value; } return field; } vx_ini_section_s vx_parse_ini_section(vx_ini_s *ini, const char *source, uint32_t offset, uint32_t *out_length) { uint32_t start_offset = offset; vx_ini_section_s section; section.name = vx_parse_ini_section_name(ini->string_arena, source, offset, §ion.len_name); offset += section.len_name + 2; section.num_fields = 0; section.fields_capacity = 32; section.fields = malloc(section.fields_capacity * sizeof(vx_ini_field_s)); while(source[offset] != 0) { // Skip comments if(source[offset] == '#') { while(source[offset] != 0) { if(source[offset] == '\n') { break; } ++offset; } ++offset; } // Get all the fields of this section while(source[offset] != 0) { if(vx_is_ascii_letter(source[offset] || (source[offset] == '_')) ) { break; } if(source[offset] == '[') { break; } } if(source[offset] == '[') { break; } uint32_t bytes_to_jump = 0; vx_parse_ini_field(ini, source, offset, &bytes_to_jump); offset += bytes_to_jump; } ++offset; return section; } vx_ini_s vx_parse_ini(const char *source) { uint32_t len_source = strlen(source); vx_ini_s ini; ini.num_sections = 0; ini.sections_capacity = 64; ini.sections = malloc(ini.sections_capacity * sizeof(vx_ini_section_s)); ini.string_arena = vx_new_arena(len_source * 2); uint32_t offset = 0; while(offset < len_source) { if(source[offset] == '[') { uint32_t len_section; ini.sections[ini.num_sections] = vx_parse_ini_section(&ini, source, offset, &len_section); offset += len_section; } } return ini; } void vx_delete_ini(vx_ini_s *ini) { } vx_ini_value_s vx_get_ini(vx_ini_s *ini, const char *field) { uint32_t splitter = 0; while(field[splitter] != 0) { if(field[splitter] == '.') { break; } ++splitter; } }