diff options
| -rw-r--r-- | examples/incorrect.ini | 27 | ||||
| -rw-r--r-- | examples/ini_file_create.c | 6 | ||||
| -rw-r--r-- | examples/ini_file_read.c | 7 | ||||
| -rw-r--r-- | examples/ini_file_search.c | 7 | ||||
| -rw-r--r-- | ini_file.c | 371 | ||||
| -rw-r--r-- | ini_file.h | 36 |
6 files changed, 281 insertions, 173 deletions
diff --git a/examples/incorrect.ini b/examples/incorrect.ini index 5f8e285..06c474f 100644 --- a/examples/incorrect.ini +++ b/examples/incorrect.ini @@ -1,18 +1,20 @@ - # Test a comment +# This is the global scope, where properties are sab=ved in a global section + + # A comment # a = 5 -a = 1 - ; Test another type of comment + ; Another type of comment ; b = 3 - b = 2 ; comment c = a+b # comment + b = 2 ; comment +a = 1 [ section 1 ] test=2 beta=96 # We allow for spaces and special characters inside values, but not on keys -erro r = 56 -correct = al bel gam +erro r = 56 ; spaces inside keys are not allowed +correct = al bel gam ; spaces inside values are allowed # Section names can have special characters and spaces [ section 2 ] @@ -25,10 +27,19 @@ a = ; 15 alpha = beta +[repeated] ; Properties inside repeated sections are stored in the same section +asf = 5 +invalid = 2 +invalid = 8 ; Repeated keys are not allowed + [section 3 -[section 4] dfg +; Characters after the end of the declaration of new sections are ignored +[section 4] dfg [numbers] integer = 25 -real = 2.8e-3
\ No newline at end of file +real = 2.8e-3 + +[repeated] ; Properties inside repeated sections are stored in the same section +asd = 2 diff --git a/examples/ini_file_create.c b/examples/ini_file_create.c index e1cfd21..2aeb5a6 100644 --- a/examples/ini_file_create.c +++ b/examples/ini_file_create.c @@ -31,9 +31,9 @@ */ int main(void) { - char filename[MAX_STRING_SIZE], key[MAX_STRING_SIZE], value[MAX_STRING_SIZE]; - /* The first section is global to the file */ - char section[MAX_STRING_SIZE] = "global"; + char filename[MAX_STRING_SIZE]; + char section[MAX_STRING_SIZE]; + char key[MAX_STRING_SIZE], value[MAX_STRING_SIZE]; struct Ini_File *ini_file = ini_file_new(); /* Instruction on how to use this application */ printf("Following, type the requested fields of keys, values and section names.\n"); diff --git a/examples/ini_file_read.c b/examples/ini_file_read.c index b54bebd..2775986 100644 --- a/examples/ini_file_read.c +++ b/examples/ini_file_read.c @@ -5,6 +5,7 @@ #include <stdio.h> #include <stdlib.h> +#include <time.h> #include "../ini_file.h" @@ -20,11 +21,15 @@ int error_callback(const char *const filename, const size_t line_number, const s int main(const int argc, const char **const argv) { struct Ini_File *ini_file; + clock_t start_time, end_time; + double total_time; if (argc < 2) { fprintf(stderr, "Usage: %s ini_file_name\n", argv[0]); return EXIT_FAILURE; } + start_time = clock(); ini_file = ini_file_parse(argv[1], error_callback); + end_time = clock(); if (ini_file == NULL) { fprintf(stderr, "Was not possible to parse the ini_file \"%s\"\n", argv[1]); return EXIT_FAILURE; @@ -33,6 +38,8 @@ int main(const int argc, const char **const argv) { ini_file_print_to(ini_file, stdout); printf("\nCheck out this information of the INI file data structure:\n"); ini_file_info(ini_file); + total_time = 1000.0 * ((double)(end_time - start_time)) / CLOCKS_PER_SEC; + printf("Time needed to parse the INI file: %f ms\n\n", total_time); ini_file_free(ini_file); return EXIT_SUCCESS; } diff --git a/examples/ini_file_search.c b/examples/ini_file_search.c index 43d3ccc..b36a9dc 100644 --- a/examples/ini_file_search.c +++ b/examples/ini_file_search.c @@ -32,6 +32,13 @@ int main(const int argc, const char **const argv) { ini_file_print_to(ini_file, stdout); break; case 3: + /* First, try to find this name as a property in the global section */ + error = ini_file_find_property(ini_file, NULL, argv[2], &value); + if (error == ini_no_error) { + puts(value); + break; + } + /* If it wasn't a property, try to fnd it as a section */ error = ini_file_find_section(ini_file, argv[2], &ini_section); if (error != ini_no_error) { fprintf(stderr, "%s\n", ini_file_error_to_string(error)); @@ -64,16 +64,22 @@ struct Ini_File *ini_file_new(void) { return NULL; } memset(ini_file, 0, sizeof(struct Ini_File)); - /* TODO: If we sort the sections, we shall think in another way to store - * and retrieve the data of this global section */ - /* The first section is global to the file */ - if (ini_file_add_section(ini_file, "global") != 0) { - ini_file_free(ini_file); - return NULL; - } + ini_file->current_section = &ini_file->global_section; return ini_file; } +static void ini_section_free(struct Ini_Section *const ini_section) { +#ifndef USE_CUSTOM_STRING_ALLOCATOR + size_t i; + free(ini_section->name); + for (i = 0; i < ini_section->properties_size; i++) { + free(ini_section->properties[i].key); + free(ini_section->properties[i].value); + } +#endif + free(ini_section->properties); +} + void ini_file_free(struct Ini_File *const ini_file) { size_t i; if (ini_file == NULL) { @@ -83,16 +89,9 @@ void ini_file_free(struct Ini_File *const ini_file) { string_buffer_free(ini_file->strings); #endif for (i = 0; i < ini_file->sections_size; i++) { -#ifndef USE_CUSTOM_STRING_ALLOCATOR - size_t j; - free(ini_file->sections[i].name); - for (j = 0; j < ini_file->sections[i].properties_size; j++) { - free(ini_file->sections[i].properties[j].key); - free(ini_file->sections[i].properties[j].value); - } -#endif - free(ini_file->sections[i].properties); + ini_section_free(&ini_file->sections[i]); } + ini_section_free(&ini_file->global_section); free(ini_file->sections); free(ini_file); } @@ -102,26 +101,25 @@ void ini_section_print_to(const struct Ini_Section *const ini_section, FILE *con if (ini_section == NULL) { return; } - fprintf(sink, "[%s]\n", ini_section->name); + if ((ini_section->name != NULL) && (ini_section->name[0] != '\0')) { + fprintf(sink, "[%s]\n", ini_section->name); + } for (property_index = 0; property_index < ini_section->properties_size; property_index++) { fprintf(sink, "%s = %s\n", ini_section->properties[property_index].key, ini_section->properties[property_index].value); } } void ini_file_print_to(const struct Ini_File *const ini_file, FILE *const sink) { - size_t section_index, property_index; + size_t section_index; if (ini_file == NULL) { return; } + if (ini_file->global_section.properties_size > 0) { + ini_section_print_to(&ini_file->global_section, sink); + putchar('\n'); + } for (section_index = 0; section_index < ini_file->sections_size; section_index++) { - if (section_index != 0) { - fprintf(sink, "[%s]\n", ini_file->sections[section_index].name); - } - for (property_index = 0; property_index < ini_file->sections[section_index].properties_size; property_index++) { - fprintf(sink, "%s = %s\n", - ini_file->sections[section_index].properties[property_index].key, - ini_file->sections[section_index].properties[property_index].value); - } + ini_section_print_to(&ini_file->sections[section_index], sink); putchar('\n'); } } @@ -137,6 +135,7 @@ char *ini_file_error_to_string(const enum Ini_File_Errors error) { "A section name was not provided", "A key was not provided", "A value was not provided", + "This key already exists", "Didn't found the requested section", "Didn't found the requested property", "The requested property is not a valid integer number", @@ -152,11 +151,25 @@ char *ini_file_error_to_string(const enum Ini_File_Errors error) { /* This function is usefull for debug purposes */ void ini_file_info(const struct Ini_File *const ini_file) { - size_t siz, i, allocs = 1, properties = 0; + size_t siz, i, allocs = 1, properties = 0, sections = ini_file->sections_size; if (ini_file == NULL) { return; } siz = sizeof(*ini_file) + sizeof(*ini_file->sections) * ini_file->sections_capacity; + if (ini_file->global_section.properties_size > 0) { +#ifndef USE_CUSTOM_STRING_ALLOCATOR + size_t j; + for (j = 0; j < ini_file->global_section.properties_size; j++) { + siz += 1 + strlen(ini_file->global_section.properties[j].key); + siz += 1 + strlen(ini_file->global_section.properties[j].value); + } + allocs += 2 * ini_file->global_section.properties_size; +#endif + properties += ini_file->global_section.properties_size; + siz += sizeof(*ini_file->global_section.properties) * ini_file->global_section.properties_capacity; + allocs++; + sections++; + } if (ini_file->sections_size > 0) { allocs++; } @@ -186,7 +199,7 @@ void ini_file_info(const struct Ini_File *const ini_file) { allocs++; } } - printf("Sections: %lu\n", ini_file->sections_size); + printf("Sections: %lu\n", sections); printf("Properties: %lu\n", properties); printf("Allocated chunks: %lu\n", allocs); printf("Memory used: %lu bytes\n", siz); @@ -246,9 +259,6 @@ static int ini_file_parse_handle_error(Ini_File_Error_Callback callback, const c return 0; } -/* TODO: Check for repeated section and key names? */ -/* TODO: Sort the sections and keys? This would allow us to use binary search */ - /* Remember to free the memory allocated for the returned ini file structure */ struct Ini_File *ini_file_parse(const char *const filename, Ini_File_Error_Callback callback) { enum Ini_File_Errors error; @@ -286,7 +296,7 @@ struct Ini_File *ini_file_parse(const char *const filename, Ini_File_Error_Callb name = cursor; advance_string_until(&cursor, "]#;\r\n"); if (*cursor != ']') { - if (ini_file_parse_handle_error(callback, filename, line_number, (size_t)(cursor-line+1), line, ini_expected_clocing_bracket) != 0) { + if (ini_file_parse_handle_error(callback, filename, line_number, (size_t)(cursor-line+1), line, ini_expected_closing_bracket) != 0) { goto ini_file_parse_error; } continue; @@ -346,152 +356,96 @@ ini_file_parse_error: return NULL; } -static size_t max_size(const size_t a, const size_t b) { - return ((a > b) ? a : b); -} - -enum Ini_File_Errors ini_file_add_section_sized(struct Ini_File *const ini_file, const char *const name, const size_t name_len) { - struct Ini_Section *ini_section; - if (ini_file == NULL) { - return ini_invalid_parameters; - } - if ((name == NULL) || (name_len == 0)) { - return ini_section_not_provided; - } - /* Check if we need expand our array of sections */ - if ((ini_file->sections_size + 1) >= ini_file->sections_capacity) { - const size_t new_cap = max_size(2 * ini_file->sections_capacity, INITIAL_SECTIONS_CAPACITY); - struct Ini_Section *const new_sections = realloc(ini_file->sections, new_cap * sizeof(struct Ini_Section)); - if (new_sections == NULL) { - return ini_allocation; - } - ini_file->sections = new_sections; - ini_file->sections_capacity = new_cap; - } - /* Insert a new section at the end of the array */ - ini_section = &ini_file->sections[ini_file->sections_size]; - memset(ini_section, 0, sizeof(struct Ini_Section)); - ini_section->name = copy_sized_string(ini_file, name, name_len); - if (ini_section->name == NULL) { - return ini_allocation; - } - ini_file->sections_size++; - return ini_no_error; -} - -enum Ini_File_Errors ini_file_add_section(struct Ini_File *const ini_file, const char *const name) { - if (name == NULL) { - return ini_section_not_provided; +/* This function compares a sized-string str1 with a null-terminated string str2 */ +static int compare_sized_str_to_cstr(const char* str1, const char* str2, size_t len1) { + const int comp = strncmp(str1, str2, len1); + /* If str1 is equal to the first len characters of str2, + * but str2 is longer than len characters, str1 is considered + * less than str2 */ + if ((comp == 0) && (str2[len1] > '\0')) { + return -1; } - return ini_file_add_section_sized(ini_file, name, strlen(name)); + return comp; } -enum Ini_File_Errors ini_file_add_property_sized(struct Ini_File *const ini_file, const char *const key, const size_t key_len, const char *const value, const size_t value_len) { - struct Ini_Section *ini_section; - struct Key_Value_Pair *property; - if (ini_file == NULL) { - return ini_invalid_parameters; - } - if ((key == NULL) || (key_len == 0)) { - return ini_key_not_provided; - } - if ((value == NULL) || (value_len == 0)) { - return ini_value_not_provided; - } - if (ini_file->sections_size == 0) { - return ini_allocation; - } - /* Insert the new property at the last section */ - ini_section = &ini_file->sections[ini_file->sections_size - 1]; - if ((ini_section->properties_size + 1) >= ini_section->properties_capacity) { - const size_t new_cap = max_size(2 * ini_section->properties_capacity, INITIAL_PROPERTIES_CAPACITY); - struct Key_Value_Pair *const new_properties = realloc(ini_section->properties, new_cap * sizeof(struct Key_Value_Pair)); - if (new_properties == NULL) { - return ini_allocation; +/* Binary search in the array of sections */ +static enum Ini_File_Errors ini_file_find_section_index(struct Ini_File *const ini_file, const char *const section, const size_t section_len, size_t *const index) { + size_t low = 0; + size_t high = ini_file->sections_size - 1; + while ((low <= high) && (high < ini_file->sections_size)) { + int comp; + *index = (low + high) / 2; + comp = compare_sized_str_to_cstr(section, ini_file->sections[*index].name, section_len); + if (comp < 0) { + high = *index - 1; + } else if (comp > 0) { + low = *index + 1; + } else { + return ini_no_error; } - ini_section->properties = new_properties; - ini_section->properties_capacity = new_cap; } - property = &ini_section->properties[ini_section->properties_size]; - property->key = copy_sized_string(ini_file, key, key_len); - if (property->key == NULL) { - return ini_allocation; - } - property->value = copy_sized_string(ini_file, value, value_len); - if (property->value == NULL) { -#ifndef USE_CUSTOM_STRING_ALLOCATOR - free(property->key); -#endif - return ini_allocation; - } - ini_section->properties_size++; - return ini_no_error; -} - -enum Ini_File_Errors ini_file_add_property(struct Ini_File *const ini_file, const char *const key, const char *const value) { - if (key == NULL) { - return ini_key_not_provided; - } - if (value == NULL) { - return ini_value_not_provided; - } - return ini_file_add_property_sized(ini_file, key, strlen(key), value, strlen(value)); + /* Didn't found the requested section, so return the correct index to insert the new element, keeping the order of the array */ + *index = low; + return ini_no_such_section; } -enum Ini_File_Errors ini_file_save(const struct Ini_File *const ini_file, const char *const filename) { - FILE *file; - if (ini_file == NULL) { - return ini_invalid_parameters; - } - file = fopen(filename, "wb"); - if (file == NULL) { - return ini_couldnt_open_file; +/* Binary search in the array of properties */ +static enum Ini_File_Errors ini_file_find_key_index(struct Ini_Section *const ini_section, const char *const key, const size_t key_len, size_t *const index) { + size_t low = 0; + size_t high = ini_section->properties_size - 1; + while ((low <= high) && (high < ini_section->properties_size)) { + int comp; + *index = (low + high) / 2; + comp = compare_sized_str_to_cstr(key, ini_section->properties[*index].key, key_len); + if (comp < 0) { + high = *index - 1; + } else if (comp > 0) { + low = *index + 1; + } else { + return ini_no_error; + } } - ini_file_print_to(ini_file, file); - fclose(file); - return ini_no_error; + /* Didn't found the requested key, so return the correct index to insert the new element, keeping the order of the array */ + *index = low; + return ini_no_such_section; } enum Ini_File_Errors ini_file_find_section(struct Ini_File *const ini_file, const char *const section, struct Ini_Section **ini_section) { + enum Ini_File_Errors error; size_t section_index; - if ((ini_file == NULL) || (section == NULL) || (ini_section == NULL)) { + if ((ini_file == NULL) || (ini_section == NULL)) { return ini_invalid_parameters; } - if (strlen(section) == 0) { - return ini_invalid_parameters; + if ((section == NULL) || (section[0] == '\0')) { + *ini_section = &ini_file->global_section; + return ini_no_error; } - for (section_index = 0; section_index < ini_file->sections_size; section_index++) { - if (strcmp(ini_file->sections[section_index].name, section) == 0) { - *ini_section = &ini_file->sections[section_index]; - return ini_no_error; - } + error = ini_file_find_section_index(ini_file, section, strlen(section), §ion_index); + if (error == ini_no_error) { + *ini_section = &ini_file->sections[section_index]; } - /* Didn't found the requested section */ - return ini_no_such_section; + return error; } enum Ini_File_Errors ini_file_find_property(struct Ini_File *const ini_file, const char *const section, const char *const key, char **value) { + enum Ini_File_Errors error; struct Ini_Section *ini_section; size_t property_index; - enum Ini_File_Errors error; - if ((ini_file == NULL) || (section == NULL) || (key == NULL) || (value == NULL)) { + if ((ini_file == NULL) || (key == NULL) || (value == NULL)) { return ini_invalid_parameters; } - if (strlen(key) == 0) { + if (key[0] == '\0') { return ini_invalid_parameters; } error = ini_file_find_section(ini_file, section, &ini_section); if (error != ini_no_error) { return error; } - for (property_index = 0; property_index < ini_section->properties_size; property_index++) { - if (strcmp(ini_section->properties[property_index].key, key) == 0) { - *value = ini_section->properties[property_index].value; - return ini_no_error; - } + error = ini_file_find_key_index(ini_section, key, strlen(key), &property_index); + if (error == ini_no_error) { + *value = ini_section->properties[property_index].value; } - /* Didn't found the requested property */ - return ini_no_such_property; + return error; } enum Ini_File_Errors ini_file_find_integer(struct Ini_File *const ini_file, const char *const section, const char *const key, long *integer) { @@ -551,6 +505,127 @@ enum Ini_File_Errors ini_file_find_float(struct Ini_File *const ini_file, const return ini_no_error; } +static size_t max_size(const size_t a, const size_t b) { + return ((a > b) ? a : b); +} + +enum Ini_File_Errors ini_file_add_section_sized(struct Ini_File *const ini_file, const char *const name, const size_t name_len) { + size_t section_index; + char *copied_name; + if (ini_file == NULL) { + return ini_invalid_parameters; + } + if ((name == NULL) || (name_len == 0)) { + return ini_section_not_provided; + } + if (ini_file_find_section_index(ini_file, name, name_len, §ion_index) == ini_no_error) { + /* There is already a section with that name so we just update the current section */ + ini_file->current_section = &ini_file->sections[section_index]; + return ini_no_error; + } + /* Check if we need expand our array of sections */ + if ((ini_file->sections_size + 1) >= ini_file->sections_capacity) { + const size_t new_cap = max_size(2 * ini_file->sections_capacity, INITIAL_SECTIONS_CAPACITY); + struct Ini_Section *const new_sections = realloc(ini_file->sections, new_cap * sizeof(struct Ini_Section)); + if (new_sections == NULL) { + return ini_allocation; + } + ini_file->sections = new_sections; + ini_file->sections_capacity = new_cap; + } + /* Allocates memory to store the section name */ + copied_name = copy_sized_string(ini_file, name, name_len); + if (copied_name == NULL) { + return ini_allocation; + } + /* Updates the current section */ + ini_file->current_section = &ini_file->sections[section_index]; + /* Moves the sections to insert the new section in the middle, keeping the array sorted by names */ + memmove((ini_file->current_section + 1), ini_file->current_section, (ini_file->sections_size - section_index)*sizeof(struct Ini_Section)); + memset(ini_file->current_section, 0, sizeof(struct Ini_Section)); + ini_file->current_section->name = copied_name; + ini_file->sections_size++; + return ini_no_error; +} + +enum Ini_File_Errors ini_file_add_section(struct Ini_File *const ini_file, const char *const name) { + if (name == NULL) { + return ini_section_not_provided; + } + return ini_file_add_section_sized(ini_file, name, strlen(name)); +} + +enum Ini_File_Errors ini_file_add_property_sized(struct Ini_File *const ini_file, const char *const key, const size_t key_len, const char *const value, const size_t value_len) { + size_t property_index; + struct Key_Value_Pair *property; + char *copied_key, *copied_value; + if (ini_file == NULL) { + return ini_invalid_parameters; + } + if ((key == NULL) || (key_len == 0)) { + return ini_key_not_provided; + } + if ((value == NULL) || (value_len == 0)) { + return ini_value_not_provided; + } + if (ini_file_find_key_index(ini_file->current_section, key, key_len, &property_index) == ini_no_error) { + /* There is already a property with that key name, which is not allowed */ + return ini_repeated_key; + } + if ((ini_file->current_section->properties_size + 1) >= ini_file->current_section->properties_capacity) { + const size_t new_cap = max_size(2 * ini_file->current_section->properties_capacity, INITIAL_PROPERTIES_CAPACITY); + struct Key_Value_Pair *const new_properties = realloc(ini_file->current_section->properties, new_cap * sizeof(struct Key_Value_Pair)); + if (new_properties == NULL) { + return ini_allocation; + } + ini_file->current_section->properties = new_properties; + ini_file->current_section->properties_capacity = new_cap; + } + copied_key = copy_sized_string(ini_file, key, key_len); + if (copied_key == NULL) { + return ini_allocation; + } + copied_value = copy_sized_string(ini_file, value, value_len); + if (copied_value == NULL) { +#ifndef USE_CUSTOM_STRING_ALLOCATOR + free(copied_key); +#endif + return ini_allocation; + } + property = &ini_file->current_section->properties[property_index]; + /* Moves the sections to insert the new section in the middle, keeping the array sorted by names */ + memmove((property + 1), property, (ini_file->current_section->properties_size - property_index)*sizeof(struct Key_Value_Pair)); + /* Update the values to the new property */ + property->key = copied_key; + property->value = copied_value; + ini_file->current_section->properties_size++; + return ini_no_error; +} + +enum Ini_File_Errors ini_file_add_property(struct Ini_File *const ini_file, const char *const key, const char *const value) { + if (key == NULL) { + return ini_key_not_provided; + } + if (value == NULL) { + return ini_value_not_provided; + } + return ini_file_add_property_sized(ini_file, key, strlen(key), value, strlen(value)); +} + +enum Ini_File_Errors ini_file_save(const struct Ini_File *const ini_file, const char *const filename) { + FILE *file; + if (ini_file == NULL) { + return ini_invalid_parameters; + } + file = fopen(filename, "wb"); + if (file == NULL) { + return ini_couldnt_open_file; + } + ini_file_print_to(ini_file, file); + fclose(file); + return ini_no_error; +} + /*------------------------------------------------------------------------------ * END *------------------------------------------------------------------------------ @@ -37,10 +37,13 @@ * allowed in key names. However, spaces and the = character can be used when * defining values, as long as the characters # and ; are not used. Section names * can have spaces, but cannot include the characters ], #, and ;. Nested sections - * are not currently implemented, and duplicate names are allowed (for now). Quoted - * strings and escaped characters are not supported in this implementation. + * are not implemented. Duplicate section names are allowed and their key value + * pairs are inserted under the same section data structure. Duplicate key names + * results in error. Quoted strings and escaped characters are not supported in + * this implementation. * If a key-value pair appears in the INI file before the first section is declared, - * it will be treated as belonging to the "global" section. This allows properties + * it will be treated as belonging to a global section which can be searched by + * using NULL or empty strings for the section name field. This allows properties * to be defined outside of any specific section and still be easily accessible in * the program. */ @@ -84,10 +87,14 @@ struct Ini_File { /* This index points to the next valid location in the buffer to store the string. */ size_t string_index; #endif + /* The global section of the INI file. It's name is always empty */ + struct Ini_Section global_section; /* The sections of the ini file are stored in a dynamic array */ size_t sections_size; size_t sections_capacity; struct Ini_Section *sections; + /* Index of the section in which the properties should be inserted */ + struct Ini_Section *current_section; }; enum Ini_File_Errors { @@ -95,11 +102,12 @@ enum Ini_File_Errors { ini_allocation, ini_invalid_parameters, ini_couldnt_open_file, - ini_expected_clocing_bracket, + ini_expected_closing_bracket, ini_expected_equals, ini_section_not_provided, ini_key_not_provided, ini_value_not_provided, + ini_repeated_key, ini_no_such_section, ini_no_such_property, ini_not_integer, @@ -129,23 +137,23 @@ void ini_file_info(const struct Ini_File *const ini_file); /* Remember to free the memory allocated for the returned ini file structure */ struct Ini_File *ini_file_parse(const char *const filename, Ini_File_Error_Callback callback); -/* These functions returns ini_no_error = 0 if everything worked correctly */ -enum Ini_File_Errors ini_file_add_section_sized(struct Ini_File *const ini_file, const char *const name, const size_t name_len); -enum Ini_File_Errors ini_file_add_section(struct Ini_File *const ini_file, const char *const name); -enum Ini_File_Errors ini_file_add_property_sized(struct Ini_File *const ini_file, const char *const key, const size_t key_len, const char *const value, const size_t value_len); -enum Ini_File_Errors ini_file_add_property(struct Ini_File *const ini_file, const char *const key, const char *const value); -enum Ini_File_Errors ini_file_save(const struct Ini_File *const ini_file, const char *const filename); - -/* These functions use sequential search algorithm to find the requested section and properties. +/* These functions use binary search algorithm to find the requested section and properties. * They return ini_no_error = 0 if everything worked correctly. - * The found value will be stores at the memory address provided by the caller. - * If no value is found, the function will not modify the value stored at the address provided. */ + * The found value will be stored at the memory address provided by the caller. + * Note that the function may modify the value stored at the address provided even if the section/property isn't found. */ enum Ini_File_Errors ini_file_find_section(struct Ini_File *const ini_file, const char *const section, struct Ini_Section **ini_section); enum Ini_File_Errors ini_file_find_property(struct Ini_File *const ini_file, const char *const section, const char *const key, char **value); enum Ini_File_Errors ini_file_find_integer(struct Ini_File *const ini_file, const char *const section, const char *const key, long *integer); enum Ini_File_Errors ini_file_find_unsigned(struct Ini_File *const ini_file, const char *const section, const char *const key, unsigned long *uint); enum Ini_File_Errors ini_file_find_float(struct Ini_File *const ini_file, const char *const section, const char *const key, double *real); +/* These functions returns ini_no_error = 0 if everything worked correctly */ +enum Ini_File_Errors ini_file_add_section_sized(struct Ini_File *const ini_file, const char *const name, const size_t name_len); +enum Ini_File_Errors ini_file_add_section(struct Ini_File *const ini_file, const char *const name); +enum Ini_File_Errors ini_file_add_property_sized(struct Ini_File *const ini_file, const char *const key, const size_t key_len, const char *const value, const size_t value_len); +enum Ini_File_Errors ini_file_add_property(struct Ini_File *const ini_file, const char *const key, const char *const value); +enum Ini_File_Errors ini_file_save(const struct Ini_File *const ini_file, const char *const filename); + #endif /* __INI_FILE */ /*------------------------------------------------------------------------------ |
