diff options
Diffstat (limited to 'pom.c')
-rw-r--r-- | pom.c | 146 |
1 files changed, 86 insertions, 60 deletions
@@ -1,7 +1,7 @@ /* TODO: - clean up read_conf.c example -- tests +- interpretation tests */ #include "pom.h" @@ -88,6 +88,7 @@ struct main_conf { // can return this from pom_conf_section when the section is mpety // (so we don't have to store empty sections) pom_conf empty_section; + pom_settings settings; }; struct pom_item_iter { @@ -146,6 +147,7 @@ struct parser { size_t (*read_func)(void *, char *, size_t); void *userdata; pom_error *out_of_memory_error; + const pom_settings *settings; struct { char *array; size_t capacity; @@ -193,24 +195,29 @@ struct parser { #include "errors.c" -void -pom_set_error_language(const char *lang) { - if (lang) - snprintf(error_language, sizeof error_language-1, "%s", lang); - else - strcpy(error_language, "en-US"); +static void * +pom_calloc(const pom_settings *settings, size_t nmemb, size_t sz) { + return settings->calloc(settings->allocator_udata, nmemb, sz); +} +static void * +pom_realloc(const pom_settings *settings, void *ptr, size_t sz) { + return settings->realloc(settings->allocator_udata, ptr, sz); +} +static void +pom_free(const pom_settings *settings, void *ptr) { + return settings->free(settings->allocator_udata, ptr); } - static const char * -get_error_message(enum error_id id) { +get_error_message(const pom_settings *settings, enum error_id id) { assert(id < ERROR_COUNT); const char *const *messages = error_messages_en; + const char *error_lang = settings->error_lang; for (size_t i = 0; i < sizeof error_messages / sizeof error_messages[0]; i++) { const char *lang = error_messages[i].lang; size_t lang_len = strlen(lang); - if (strncmp(error_language, lang, lang_len) == 0 - && (error_language[lang_len] == 0 || error_language[lang_len] == '-')) { + if (strncmp(error_lang, lang, lang_len) == 0 + && (error_lang[lang_len] == 0 || error_lang[lang_len] == '-')) { // language match messages = error_messages[i].messages; break; @@ -240,8 +247,8 @@ fatal_error(const char *fmt, ...) { // Make an error with no next-error. static pom_error * -make_error(const char *file, uint64_t line, enum error_id id, ...) { - const char *fmt = get_error_message(id); +make_error(const pom_settings *settings, const char *file, uint64_t line, enum error_id id, ...) { + const char *fmt = get_error_message(settings, id); va_list args, args_copy; va_start(args, id); va_copy(args_copy, args); @@ -253,7 +260,7 @@ make_error(const char *file, uint64_t line, enum error_id id, ...) { bad_fmt = true; len = strlen(fmt); } - pom_error *err = malloc(sizeof(pom_error) + len * 2 + strlen(file) + 64); + pom_error *err = pom_calloc(settings, sizeof(pom_error) + len * 2 + strlen(file) + 64, 1); if (err) { char *message = (char *)(err + 1); if (bad_fmt) { @@ -271,7 +278,7 @@ make_error(const char *file, uint64_t line, enum error_id id, ...) { #pragma GCC diagnostic ignored "-Wrestrict" #endif sprintf(string, "%s\n%s:%" PRIu64 ": %s\n", - get_error_message(ERROR_HEADER), + get_error_message(settings, ERROR_HEADER), file, line, message); #if !__clang__ && __GNUC__ >= 4 #pragma GCC diagnostic pop @@ -346,7 +353,7 @@ parser_realloc_(struct parser *parser, void *ptr, size_t elem_size, size_t *pcap void **parray = ptr; void *array = *parray; new_capacity = new_capacity * 3 / 2 + 2; - array = realloc(array, new_capacity * elem_size); + array = pom_realloc(parser->settings, array, new_capacity * elem_size); if (!array) { parser_out_of_memory(parser); return false; @@ -405,7 +412,7 @@ static void parser_error(struct parser *parser, enum error_id id, ...) { if (parser->out_of_memory) return; if (parser->errors.count >= 1000) return; // don't bother at this point. - const char *fmt = get_error_message(id); + const char *fmt = get_error_message(parser->settings, id); va_list args, args_copy; va_start(args, id); va_copy(args_copy, args); @@ -852,7 +859,7 @@ parse_line(struct parser *parser) { } static void -set_error(pom_error **error, pom_error *e) { +set_error(const pom_settings *settings, pom_error **error, pom_error *e) { if (error) { *error = e; } else { @@ -874,7 +881,7 @@ conf_free_list_append(struct main_conf *conf, struct to_free *mem) { static void * conf_calloc(struct main_conf *conf, size_t nmemb, size_t sz) { if (nmemb > SIZE_MAX / (2*sz)) return NULL; - struct to_free *mem = calloc(1, sizeof(struct to_free) + nmemb * sz); + struct to_free *mem = pom_calloc(&conf->settings, 1, sizeof(struct to_free) + nmemb * sz); if (!mem) return NULL; conf_free_list_append(conf, mem); return &mem->data[0]; @@ -885,9 +892,9 @@ conf_free(struct main_conf *conf) { if (!conf) return; for (struct to_free *next, *f = conf->to_free_head; f; f = next) { next = f->next; - free(f); + pom_free(&conf->settings, f); } - free(conf); + pom_free(&conf->settings, conf); } static int @@ -1020,11 +1027,12 @@ parser_finish(struct parser *parser) { if (parser->out_of_memory || parser->errors.count) { return NULL; } - struct main_conf *conf = calloc(1, sizeof *conf); + struct main_conf *conf = pom_calloc(parser->settings, 1, sizeof *conf); if (!conf) { parser_out_of_memory(parser); return NULL; } + conf->settings = *parser->settings; conf->empty_section.main = conf; size_t items_count = parser->items.count; struct conf_item *items = conf_calloc(conf, items_count, sizeof(struct conf_item)); @@ -1090,30 +1098,48 @@ parser_finish(struct parser *parser) { return root; } +static void *libc_calloc(void *udata, size_t n, size_t sz) { + return calloc(n, sz); +} + +static void *libc_realloc(void *udata, void *ptr, size_t new_size) { + return realloc(ptr, new_size); +} + +static void libc_free(void *udata, void *ptr) { + free(ptr); +} + pom_conf * -pom_load(const char *filename, +pom_load(const pom_settings *psettings, const char *filename, size_t (*read_func)(void *userdata, char *buf, size_t len), void *userdata, pom_error **error) { if (!filename) fatal_error("%s called with NULL file name", __func__); if (!read_func) fatal_error("%s called with NULL read function", __func__); + pom_settings settings_data = {0}, *settings = &settings_data; + if (psettings) settings_data = *psettings; + if (!settings->calloc) settings->calloc = libc_calloc; + if (!settings->realloc) settings->realloc = libc_realloc; + if (!settings->free) settings->free = libc_free; if (error) *error = NULL; // Start by allocating out-of-memory error, so we can just return // it if we run out of memory. - pom_error *out_of_memory = make_error(filename, 1, ERROR_OUT_OF_MEMORY); + pom_error *out_of_memory = make_error(settings, filename, 1, ERROR_OUT_OF_MEMORY); if (!out_of_memory) return NULL; - char *current_section = calloc(1, 1); + char *current_section = pom_calloc(settings, 1, 1); if (!current_section) { - set_error(error, out_of_memory); + set_error(settings, error, out_of_memory); return NULL; } - struct parser *parser = calloc(1, sizeof *parser); + struct parser *parser = pom_calloc(settings, 1, sizeof *parser); if (!parser) { - free(current_section); - set_error(error, out_of_memory); + pom_free(settings, current_section); + set_error(settings, error, out_of_memory); return NULL; } + parser->settings = settings; parser->filename = filename; parser->out_of_memory_error = out_of_memory; parser->read_func = read_func; @@ -1128,14 +1154,14 @@ pom_load(const char *filename, pom_conf *conf = parser_finish(parser); if (parser->out_of_memory) { - set_error(error, out_of_memory); + set_error(settings, error, out_of_memory); } else if (parser->errors.count) { if (error) { // shouldn't realistically overflow given that we cut off at 1000 errors size_t len = (parser->errors.count + 1) * (sizeof(pom_error) + strlen(filename) + 32) + parser->error_messages.count * 2 + 64; // convert parser_errors to pom_error. - pom_error *errors = malloc(len); + pom_error *errors = pom_calloc(settings, 1, len); if (errors) { char *messages = (char *)(errors + parser->errors.count); memcpy(messages, @@ -1153,7 +1179,7 @@ pom_load(const char *filename, } // create string containing all error messages char *string = strchr(filename, '\0') + 1, *s = string; - sprintf(s, "%s\n", get_error_message(ERROR_HEADER)); + sprintf(s, "%s\n", get_error_message(settings, ERROR_HEADER)); s = strchr(s, 0); for (size_t i = 0; i < parser->errors.count; i++) { const pom_error *e = &errors[i]; @@ -1166,17 +1192,17 @@ pom_load(const char *filename, *error = parser->out_of_memory_error; } } - free(parser->errors.array); - free(parser->error_messages.array); + pom_free(settings, parser->errors.array); + pom_free(settings, parser->error_messages.array); } if (!error || *error != out_of_memory) { - free(out_of_memory); + pom_free(settings, out_of_memory); } - free(parser->line.array); - free(parser->current_section.array); - free(parser->string_data.array); - free(parser->items.array); - free(parser); + pom_free(settings, parser->line.array); + pom_free(settings, parser->current_section.array); + pom_free(settings, parser->string_data.array); + pom_free(settings, parser->items.array); + pom_free(settings, parser); return conf; } @@ -1194,8 +1220,8 @@ read_string(void *vpstring, char *buf, size_t len) { } pom_conf * -pom_load_string(const char *filename, const char *string, pom_error **error) { - return pom_load(filename, read_string, &string, error); +pom_load_string(const pom_settings *settings, const char *filename, const char *string, pom_error **error) { + return pom_load(settings, filename, read_string, &string, error); } #ifndef POM_NO_STDIO @@ -1205,16 +1231,16 @@ read_file(void *file, char *buf, size_t len) { } pom_conf * -pom_load_file(const char *filename, FILE *file, pom_error **error) { +pom_load_file(const pom_settings *settings, const char *filename, FILE *file, pom_error **error) { if (!filename) fatal_error("%s called with NULL file name", __func__); if (!file) fatal_error("%s called with NULL file", __func__); - pom_conf *conf = pom_load(filename, read_file, file, error); + pom_conf *conf = pom_load(settings, filename, read_file, file, error); if (ferror(file)) { if (error) { - free(*error); - *error = make_error(filename, 1, ERROR_FILE_READ); + pom_free(settings, *error); + *error = make_error(settings, filename, 1, ERROR_FILE_READ); } pom_conf_free(conf); conf = NULL; @@ -1223,18 +1249,18 @@ pom_load_file(const char *filename, FILE *file, pom_error **error) { } pom_conf * -pom_load_path(const char *path, pom_error **error) { +pom_load_path(const pom_settings *settings, const char *path, pom_error **error) { if (!path) fatal_error("%s called with NULL file name", __func__); FILE *fp = fopen(path, "rb"); if (!fp) { if (error) { const char *message = strerror(errno); - *error = make_error(path, 1, ERROR_CANT_OPEN_FILE, message); + *error = make_error(settings, path, 1, ERROR_CANT_OPEN_FILE, message); } return NULL; } - pom_conf *conf = pom_load_file(path, fp, error); + pom_conf *conf = pom_load_file(settings, path, fp, error); fclose(fp); return conf; } @@ -1257,7 +1283,7 @@ pom_conf_next_item(const pom_conf *conf, pom_item_iter **p_iter) { check_conf(conf); if (!p_iter) fatal_error("NULL iter passed to %s", __func__); if (!*p_iter) { - *p_iter = calloc(1, sizeof **p_iter); + *p_iter = pom_calloc(&conf->main->settings, 1, sizeof **p_iter); if (!*p_iter) return NULL; (*p_iter)->conf = conf; (*p_iter)->conf_item = conf->items; @@ -1266,7 +1292,7 @@ pom_conf_next_item(const pom_conf *conf, pom_item_iter **p_iter) { if (iter->conf != conf) fatal_error("%s being called with inconsistent configurations for a single iterator", __func__); if (iter->conf_item >= conf->items + conf->items_count) { - free(iter); + pom_free(&conf->main->settings, iter); *p_iter = NULL; return NULL; } @@ -1283,7 +1309,7 @@ pom_conf_next_unread_key(const pom_conf *conf, pom_unread_key_iter **p_iter) { check_conf(conf); if (!p_iter) fatal_error("NULL iter passed to %s", __func__); if (!*p_iter) { - *p_iter = malloc(sizeof **p_iter); + *p_iter = pom_calloc(&conf->main->settings, 1, sizeof **p_iter); if (!*p_iter) return NULL; (*p_iter)->conf = conf; (*p_iter)->conf_item = conf->items; @@ -1304,7 +1330,7 @@ pom_conf_next_unread_key(const pom_conf *conf, pom_unread_key_iter **p_iter) { return key; } } - free(iter); + pom_free(&conf->main->settings, iter); *p_iter = NULL; return NULL; } @@ -1314,7 +1340,7 @@ pom_conf_next_key(const pom_conf *conf, pom_key_iter **p_iter) { check_conf(conf); if (!p_iter) fatal_error("NULL iter passed to %s", __func__); if (!*p_iter) { - *p_iter = malloc(sizeof **p_iter); + *p_iter = pom_calloc(&conf->main->settings, 1, sizeof **p_iter); if (!*p_iter) return NULL; (*p_iter)->conf = conf; (*p_iter)->conf_item = conf->items; @@ -1328,7 +1354,7 @@ pom_conf_next_key(const pom_conf *conf, pom_key_iter **p_iter) { size_t first_component_len = strcspn(key, "."); if (!iter->prev_key || strncmp(iter->prev_key, key, first_component_len) != 0) { // new first component - char *first_component = realloc(iter->prev_key, first_component_len + 1); + char *first_component = pom_realloc(&conf->main->settings, iter->prev_key, first_component_len + 1); if (!first_component) return NULL; iter->prev_key = first_component; memcpy(first_component, key, first_component_len); @@ -1337,8 +1363,8 @@ pom_conf_next_key(const pom_conf *conf, pom_key_iter **p_iter) { return first_component; } } - free(iter->prev_key); - free(iter); + pom_free(&conf->main->settings, iter->prev_key); + pom_free(&conf->main->settings, iter); *p_iter = NULL; return NULL; } @@ -1538,7 +1564,7 @@ pom_conf_print(const pom_conf *conf) { pom_conf * pom_conf_copy(const pom_conf *conf) { check_conf(conf); - struct main_conf *new_main = calloc(1, sizeof *new_main); + struct main_conf *new_main = pom_calloc(&conf->main->settings, 1, sizeof *new_main); if (!new_main) return NULL; pom_conf *new_root = conf_calloc(new_main, 1, sizeof *new_root); if (!new_root) { @@ -1823,13 +1849,13 @@ pom_conf_get_list(const pom_conf *conf, const char *key) { size_t max_entries = 1; // upper bound on # of entries for (const char *p = value_str; *p; p++) max_entries += *p == ','; - if (max_entries > SIZE_MAX / 16) { + if (max_entries > SIZE_MAX / 4 / sizeof(char *)) { // too many entries (avoid arithmetic overflow) return NULL; } size_t bytes_needed = (max_entries+1) * sizeof (char *) + strlen(value_str) + 1; - char **list = malloc(bytes_needed); + char **list = pom_calloc(&conf->main->settings, 1, bytes_needed); if (!list) return NULL; char **entry = list; char *strings = (char *)(list + max_entries+1); |