Kaltenberg/modules/utility/src-c/serial/ini/loader.c

240 lines
6.3 KiB
C
Raw Normal View History

#include <voxula/internals/utility/ini.h>
#include <stdlib.h>
#include <string.h>
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, &section.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;
}
}