diff --git a/modules/utility/inc-c/voxula/internals/utility.h b/modules/utility/inc-c/voxula/internals/utility.h index 2996556..b20e516 100644 --- a/modules/utility/inc-c/voxula/internals/utility.h +++ b/modules/utility/inc-c/voxula/internals/utility.h @@ -22,6 +22,43 @@ typedef struct vx_pool vx_pool_s; typedef struct vx_pool_slot_header vx_pool_slot_header_s; typedef struct vx_arena vx_arena_s; +typedef enum +{ + VX_ASCII_EXCLAMATION_MARK = '!', + VX_ASCII_DOUBLE_QUOTATION_MARK = '"', + VX_ASCII_NUMBER_SIGN = '#', + VX_ASCII_DOLLAR_SIGN = '$', + VX_ASCII_PERCENT_SIGN = '%', + VX_ASCII_AMPERSAND = '&', + VX_ASCII_SINGLE_QUOTATION_MARK = '\'', + VX_ASCII_OPENING_PARENTHESIS = '(', + VX_ASCII_CLOSING_PARENTHESIS = ')', + VX_ASCII_ASTERISK = '*', + VX_ASCII_ADDITION_SIGN = '+', + VX_ASCII_COMMA = ',', + VX_ASCII_HYPHEN = '-', + VX_ASCII_DOT = '.', + VX_ASCII_FORWARD_SLASH = '/', + VX_ASCII_COLON = ':', + VX_ASCII_SEMICOLON = ';', + VX_ASCII_LESS_THAN_SIGN = '<', + VX_ASCII_EQUALS_SIGN = '=', + VX_ASCII_GREATER_THAN_SIGN = '>', + VX_ASCII_QUESTION_MARK = '?', + VX_ASCII_AT_SIGN = '@', + VX_ASCII_OPENING_BRACKET = '[', + VX_ASCII_BACKSLASH = '\\', + VX_ASCII_CLOSING_BRACKET = ']', + VX_ASCII_CARET = '^', + VX_ASCII_UNDERSCORE = '_', + VX_ASCII_BACKTICK = '`', + VX_ASCII_OPENING_BRACE = '{', + VX_ASCII_VERTICAL_BAR = '|', + VX_ASCII_CLOSING_BRACE = '}', + VX_ACII_TILDE = '~' + +} vx_ascii_sign_e; + struct vx_uuid_entry { vx_uuid_d uuid; @@ -171,5 +208,25 @@ void vx_free_arena(vx_arena_s *arena); void * vx_arena_alloc(vx_arena_s *arena, uint32_t length); char * vx_arena_dupe_string(vx_arena_s *arena, const char *string); char * vx_arena_dupe_string_up_to(vx_arena_s *arena, const char *string, uint32_t maximum); - + +// Character Functions + +bool vx_is_ascii_sign(char character); +bool vx_is_ascii_sign_of_block_1(char character); +bool vx_is_ascii_sign_of_block_2(char character); +bool vx_is_ascii_sign_of_block_3(char character); +bool vx_is_ascii_sign_of_block_4(char character); + +bool vx_is_ascii_letter(char character); +bool vx_is_ascii_lower(char character); +bool vx_is_ascii_upper(char character); + +bool vx_is_ascii_digit(char character); + +bool vx_is_ascii_blank(char character); +bool vx_is_ascii_control(char character); + +uint8_t vx_digits_for_decimal(uint32_t decimal); +void vx_write_spaces(FILE *output, uint32_t count); + #endif // VOXULA_UTILITY_H diff --git a/modules/utility/inc-c/voxula/internals/utility/ini.h b/modules/utility/inc-c/voxula/internals/utility/ini.h new file mode 100644 index 0000000..12dda98 --- /dev/null +++ b/modules/utility/inc-c/voxula/internals/utility/ini.h @@ -0,0 +1,81 @@ + +#ifndef VOXULA_INI_H +#define VOXULA_INI_H + +#include +#include + +#include + +typedef struct vx_ini vx_ini_s; +typedef struct vx_ini_section vx_ini_section_s; +typedef struct vx_ini_field vx_ini_field_s; +typedef struct vx_ini_value vx_ini_value_s; + +typedef enum +{ + VX_INI_VALUE_NULL = 0, + + VX_INI_VALUE_BOOLEAN, + VX_INI_VALUE_STRING, + VX_INI_VALUE_INTEGER, + VX_INI_VALUE_REAL, + VX_INI_VALUE_ARRAY + +} vx_ini_value_e; + +struct vx_ini_value +{ + vx_ini_value_e type; + union vx_ini_value_specifics + { + bool boolean; + char *string; + int64_t integer; + double real; + struct vx_ini_array + { + uint32_t values_capacity; + uint32_t num_values; + vx_ini_value_s *values; + + } array; + } specifics; +}; + +struct vx_ini_field +{ + uint32_t line; + uint32_t column; + + uint32_t len_name; + char *name; + + vx_ini_value_s value; +}; + +struct vx_ini_section +{ + uint32_t len_name; + char *name; + + uint32_t fields_capacity; + uint32_t num_fields; + vx_ini_field_s *fields; +}; + +struct vx_ini +{ + uint32_t sections_capacity; + uint32_t num_sections; + vx_ini_section_s *sections; + + vx_arena_s *string_arena; +}; + +vx_ini_s vx_parse_ini(const char *source); +void vx_delete_ini(vx_ini_s *ini); + +vx_ini_value_s vx_get_ini(vx_ini_s *ini, const char *field); + +#endif // VOXULA_INI_H \ No newline at end of file diff --git a/modules/utility/inc-c/voxula/internals/utility/text.h b/modules/utility/inc-c/voxula/internals/utility/text.h new file mode 100644 index 0000000..eed19ae --- /dev/null +++ b/modules/utility/inc-c/voxula/internals/utility/text.h @@ -0,0 +1,64 @@ + +#ifndef VOXULA_ASCII_H +#define VOXULA_ASCII_H + +#include +#include +#include + +typedef enum +{ + VX_ASCII_EXCLAMATION_MARK = '!', + VX_ASCII_DOUBLE_QUOTATION_MARK = '"', + VX_ASCII_NUMBER_SIGN = '#', + VX_ASCII_DOLLAR_SIGN = '$', + VX_ASCII_PERCENT_SIGN = '%', + VX_ASCII_AMPERSAND = '&', + VX_ASCII_SINGLE_QUOTATION_MARK = '\'', + VX_ASCII_OPENING_PARENTHESIS = '(', + VX_ASCII_CLOSING_PARENTHESIS = ')', + VX_ASCII_ASTERISK = '*', + VX_ASCII_ADDITION_SIGN = '+', + VX_ASCII_COMMA = ',', + VX_ASCII_HYPHEN = '-', + VX_ASCII_DOT = '.', + VX_ASCII_FORWARD_SLASH = '/', + VX_ASCII_COLON = ':', + VX_ASCII_SEMICOLON = ';', + VX_ASCII_LESS_THAN_SIGN = '<', + VX_ASCII_EQUALS_SIGN = '=', + VX_ASCII_GREATER_THAN_SIGN = '>', + VX_ASCII_QUESTION_MARK = '?', + VX_ASCII_AT_SIGN = '@', + VX_ASCII_OPENING_BRACKET = '[', + VX_ASCII_BACKSLASH = '\\', + VX_ASCII_CLOSING_BRACKET = ']', + VX_ASCII_CARET = '^', + VX_ASCII_UNDERSCORE = '_', + VX_ASCII_BACKTICK = '`', + VX_ASCII_OPENING_BRACE = '{', + VX_ASCII_VERTICAL_BAR = '|', + VX_ASCII_CLOSING_BRACE = '}', + VX_ACII_TILDE = '~' + +} vx_ascii_sign_e; + +bool vx_is_ascii_sign(char character); +bool vx_is_ascii_sign_of_block_1(char character); +bool vx_is_ascii_sign_of_block_2(char character); +bool vx_is_ascii_sign_of_block_3(char character); +bool vx_is_ascii_sign_of_block_4(char character); + +bool vx_is_ascii_letter(char character); +bool vx_is_ascii_lower(char character); +bool vx_is_ascii_upper(char character); + +bool vx_is_ascii_digit(char character); + +bool vx_is_ascii_blank(char character); +bool vx_is_ascii_control(char character); + +uint8_t vx_digits_for_decimal(uint32_t decimal); +void vx_write_spaces(FILE *output, uint32_t count); + +#endif // VOXULA_ASCII_H diff --git a/modules/utility/src-c/serial/ini/loader.c b/modules/utility/src-c/serial/ini/loader.c new file mode 100644 index 0000000..49a4016 --- /dev/null +++ b/modules/utility/src-c/serial/ini/loader.c @@ -0,0 +1,239 @@ +#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; + } + +} diff --git a/modules/utility/src-c/text.c b/modules/utility/src-c/text.c new file mode 100644 index 0000000..0848f17 --- /dev/null +++ b/modules/utility/src-c/text.c @@ -0,0 +1,191 @@ +#include + +bool vx_is_ascii_sign(char character) +{ + if( vx_is_ascii_sign_of_block_1(character) + || vx_is_ascii_sign_of_block_2(character) + || vx_is_ascii_sign_of_block_3(character) + || vx_is_ascii_sign_of_block_4(character) + ) { + return true; + } + return false; +} + +bool vx_is_ascii_sign_of_block_1(char character) +{ + if(character < 0x21) + { + return false; + } + if(character > 0x2f) + { + return false; + } + return true; +} + +bool vx_is_ascii_sign_of_block_2(char character) +{ + if(character < 0x3a) + { + return false; + } + if(character > 0x40) + { + return false; + } + return true; +} + +bool vx_is_ascii_sign_of_block_3(char character) +{ + if(character < 0x5b) + { + return false; + } + if(character > 0x60) + { + return false; + } + return true; +} + +bool vx_is_ascii_sign_of_block_4(char character) +{ + if(character < 0x7b) + { + return false; + } + if(character > 0x7e) + { + return false; + } + return true; +} + +bool vx_is_ascii_letter(char character) +{ + if( vx_is_ascii_lower(character) + || vx_is_ascii_upper(character) + ) { + return true; + } + return false; +} + +bool vx_is_ascii_lower(char character) +{ + if(character < 'a') + { + return false; + } + if(character > 'z') + { + return false; + } + return true; +} + +bool vx_is_ascii_upper(char character) +{ + if(character < 'A') + { + return false; + } + if(character > 'Z') + { + return false; + } + return true; +} + +bool vx_is_ascii_digit(char character) +{ + if(character < '0') + { + return false; + } + if(character > '9') + { + return false; + } + return true; +} + +bool vx_is_ascii_blank(char character) +{ + if(character == ' ') + { + return true; + } + if(character == '\t') + { + return true; + } + return false; +} + +bool vx_is_ascii_control(char character) +{ + if(character < 32) + { + return true; + } + if(character == 127) + { + return true; + } + return false; +} + +void vx_write_spaces(FILE *output, uint32_t count) +{ + uint32_t space_index = 0; + while(space_index < count) + { + fputc(' ', output); + ++space_index; + } +} + +uint8_t vx_digits_for_decimal(uint32_t decimal) +{ + if(decimal < 10) + { + return 1; + } + if(decimal < 100) + { + return 2; + } + if(decimal < 1000) + { + return 3; + } + if(decimal < 10000) + { + return 4; + } + if(decimal < 100000) + { + return 5; + } + if(decimal < 1000000) + { + return 6; + } + if(decimal < 10000000) + { + return 7; + } + if(decimal < 100000000) + { + return 8; + } + if(decimal < 1000000000) + { + return 9; + } + return 10; +}