aboutsummaryrefslogtreecommitdiff
path: root/src/Config.c
diff options
context:
space:
mode:
authorfrosty <gabriel@bwaaa.monster>2026-09-06 17:19:08 -0400
committerfrosty <gabriel@bwaaa.monster>2026-09-06 17:19:08 -0400
commitf41fa9e4b3c29e80d9071120113ec33a9d27d005 (patch)
treef55a564a4c2b96aea4419bf19c0ae9efa1ba6eb9 /src/Config.c
parentacdff2d3a2f9283db61f5bbc08a303c69635304f (diff)
downloadomnisearch-f41fa9e4b3c29e80d9071120113ec33a9d27d005.tar.gz
refactor: clean up config parsing with minor QoL tweaksindev
Diffstat (limited to 'src/Config.c')
-rw-r--r--src/Config.c225
1 files changed, 151 insertions, 74 deletions
diff --git a/src/Config.c b/src/Config.c
index 3d2790b..aef7504 100644
--- a/src/Config.c
+++ b/src/Config.c
@@ -1,112 +1,189 @@
#include "Config.h"
+
+#include <errno.h>
+#include <limits.h>
+#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <strings.h>
+
+typedef enum {
+ CONFIG_STRING,
+ CONFIG_INTEGER,
+ CONFIG_BOOLEAN,
+} ConfigValueType;
+
+typedef struct {
+ const char *section;
+ const char *key;
+ ConfigValueType type;
+ size_t offset;
+ size_t size;
+} ConfigOption;
+
+#define STRING_OPTION(section_name, key_name, field) \
+ {section_name, key_name, CONFIG_STRING, offsetof(Config, field), \
+ sizeof(((Config *)0)->field)}
+#define INTEGER_OPTION(section_name, key_name, field) \
+ {section_name, key_name, CONFIG_INTEGER, offsetof(Config, field), 0}
+#define BOOLEAN_OPTION(section_name, key_name, field) \
+ {section_name, key_name, CONFIG_BOOLEAN, offsetof(Config, field), 0}
+
+static const ConfigOption CONFIG_OPTIONS[] = {
+ STRING_OPTION("server", "host", host),
+ INTEGER_OPTION("server", "port", port),
+ STRING_OPTION("server", "locale", default_locale),
+ STRING_OPTION("proxy", "proxy", proxy),
+ STRING_OPTION("proxy", "list_file", proxy_list_file),
+ INTEGER_OPTION("proxy", "max_retries", max_proxy_retries),
+ BOOLEAN_OPTION("proxy", "randomize_username", randomize_username),
+ BOOLEAN_OPTION("proxy", "randomize_password", randomize_password),
+ STRING_OPTION("cache", "dir", cache_dir),
+ INTEGER_OPTION("cache", "ttl_search", cache_ttl_search),
+ INTEGER_OPTION("cache", "ttl_infobox", cache_ttl_infobox),
+ INTEGER_OPTION("cache", "ttl_image", cache_ttl_image),
+ STRING_OPTION("engines", "engines", engines),
+ STRING_OPTION("engines", "yacy_instance", yacy_instance),
+ INTEGER_OPTION("rate_limit", "search_requests", rate_limit_search_requests),
+ INTEGER_OPTION("rate_limit", "search_interval", rate_limit_search_interval),
+ INTEGER_OPTION("rate_limit", "images_requests", rate_limit_images_requests),
+ INTEGER_OPTION("rate_limit", "images_interval", rate_limit_images_interval),
+};
+
+void config_set_defaults(Config *config) {
+ if (!config) {
+ return;
+ }
+
+ *config = (Config){
+ .host = DEFAULT_HOST,
+ .port = DEFAULT_PORT,
+ .default_locale = "en_gb",
+ .max_proxy_retries = DEFAULT_MAX_PROXY_RETRIES,
+ .cache_dir = DEFAULT_CACHE_DIR,
+ .cache_ttl_search = DEFAULT_CACHE_TTL_SEARCH,
+ .cache_ttl_infobox = DEFAULT_CACHE_TTL_INFOBOX,
+ .cache_ttl_image = DEFAULT_CACHE_TTL_IMAGE,
+ };
+}
static char *trim(char *value) {
- while (*value == ' ' || *value == '\t')
+ while (*value == ' ' || *value == '\t') {
value++;
+ }
char *end = value + strlen(value);
- while (end > value && (end[-1] == ' ' || end[-1] == '\t'))
+ while (end > value && (end[-1] == ' ' || end[-1] == '\t')) {
end--;
+ }
*end = '\0';
return value;
}
+static char *unquote(char *value) {
+ size_t length = strlen(value);
+ if (length >= 2 && (value[0] == '"' || value[0] == '\'') &&
+ value[length - 1] == value[0]) {
+ value[length - 1] = '\0';
+ return value + 1;
+ }
+ return value;
+}
+
+static int parse_integer(const char *value, int *result) {
+ char *end;
+ errno = 0;
+ long parsed = strtol(value, &end, 10);
+
+ if (value == end || *end != '\0' || errno == ERANGE || parsed < INT_MIN ||
+ parsed > INT_MAX) {
+ return -1;
+ }
+
+ *result = (int)parsed;
+ return 0;
+}
+
+static int parse_boolean(const char *value, int *result) {
+ if (strcmp(value, "1") == 0 || strcasecmp(value, "true") == 0 ||
+ strcasecmp(value, "yes") == 0 || strcasecmp(value, "on") == 0) {
+ *result = 1;
+ return 0;
+ }
+ if (strcmp(value, "0") == 0 || strcasecmp(value, "false") == 0 ||
+ strcasecmp(value, "no") == 0 || strcasecmp(value, "off") == 0) {
+ *result = 0;
+ return 0;
+ }
+ return -1;
+}
+
+static void set_option(Config *config, const char *section, const char *key,
+ const char *value) {
+ size_t option_count = sizeof(CONFIG_OPTIONS) / sizeof(CONFIG_OPTIONS[0]);
+
+ for (size_t i = 0; i < option_count; i++) {
+ const ConfigOption *option = &CONFIG_OPTIONS[i];
+ if (strcmp(section, option->section) != 0 ||
+ strcmp(key, option->key) != 0) {
+ continue;
+ }
+
+ void *destination = (char *)config + option->offset;
+ if (option->type == CONFIG_STRING) {
+ snprintf(destination, option->size, "%s", value);
+ } else if (option->type == CONFIG_INTEGER) {
+ parse_integer(value, destination);
+ } else {
+ parse_boolean(value, destination);
+ }
+ return;
+ }
+}
+
int load_config(const char *filename, Config *config) {
+ if (!filename || !config) {
+ return -1;
+ }
+
FILE *file = fopen(filename, "r");
if (!file) {
return -1;
}
- char line[512];
+ char line[1024];
char section[64] = "";
while (fgets(line, sizeof(line), file)) {
- line[strcspn(line, "\r\n")] = 0;
+ line[strcspn(line, "\r\n")] = '\0';
+ char *content = trim(line);
- if (line[0] == '\0' || line[0] == '#' || line[0] == ';') {
+ if (*content == '\0' || *content == '#' || *content == ';') {
continue;
}
- if (line[0] == '[') {
- char *end = strchr(line, ']');
+ if (*content == '[') {
+ char *end = strchr(content + 1, ']');
if (end) {
*end = '\0';
- snprintf(section, sizeof(section), "%.*s", (int)(sizeof(section) - 1),
- line + 1);
- section[sizeof(section) - 1] = '\0';
+ snprintf(section, sizeof(section), "%s", trim(content + 1));
}
continue;
}
- char *delimiter = strchr(line, '=');
- if (delimiter) {
- *delimiter = '\0';
- char *key = trim(line);
- char *value = trim(delimiter + 1);
-
- char *value_end = value + strlen(value);
- while (value_end > value &&
- (value_end[-1] == '"' || value_end[-1] == '\''))
- *--value_end = '\0';
- while (*value == '"' || *value == '\'')
- value++;
-
- if (strcmp(section, "server") == 0) {
- if (strcmp(key, "host") == 0) {
- snprintf(config->host, sizeof(config->host), "%s", value);
- } else if (strcmp(key, "port") == 0) {
- config->port = atoi(value);
- } else if (strcmp(key, "locale") == 0) {
- snprintf(config->default_locale, sizeof(config->default_locale), "%s",
- value);
- }
- } else if (strcmp(section, "proxy") == 0) {
- if (strcmp(key, "proxy") == 0) {
- snprintf(config->proxy, sizeof(config->proxy), "%s", value);
- } else if (strcmp(key, "list_file") == 0) {
- snprintf(config->proxy_list_file, sizeof(config->proxy_list_file),
- "%s", value);
- } else if (strcmp(key, "max_retries") == 0) {
- config->max_proxy_retries = atoi(value);
- } else if (strcmp(key, "randomize_username") == 0) {
- config->randomize_username = atoi(value);
- } else if (strcmp(key, "randomize_password") == 0) {
- config->randomize_password = atoi(value);
- }
- } else if (strcmp(section, "cache") == 0) {
- if (strcmp(key, "dir") == 0) {
- snprintf(config->cache_dir, sizeof(config->cache_dir), "%s", value);
- } else if (strcmp(key, "ttl_search") == 0) {
- config->cache_ttl_search = atoi(value);
- } else if (strcmp(key, "ttl_infobox") == 0) {
- config->cache_ttl_infobox = atoi(value);
- } else if (strcmp(key, "ttl_image") == 0) {
- config->cache_ttl_image = atoi(value);
- }
- } else if (strcmp(section, "engines") == 0) {
- if (strcmp(key, "engines") == 0) {
- snprintf(config->engines, sizeof(config->engines), "%s", value);
- } else if (strcmp(key, "yacy_instance") == 0) {
- snprintf(config->yacy_instance, sizeof(config->yacy_instance), "%s",
- value);
- }
- } else if (strcmp(section, "rate_limit") == 0) {
- if (strcmp(key, "search_requests") == 0) {
- config->rate_limit_search_requests = atoi(value);
- } else if (strcmp(key, "search_interval") == 0) {
- config->rate_limit_search_interval = atoi(value);
- } else if (strcmp(key, "images_requests") == 0) {
- config->rate_limit_images_requests = atoi(value);
- } else if (strcmp(key, "images_interval") == 0) {
- config->rate_limit_images_interval = atoi(value);
- }
- }
+ char *delimiter = strchr(content, '=');
+ if (!delimiter) {
+ continue;
}
+
+ *delimiter = '\0';
+ char *key = trim(content);
+ char *value = unquote(trim(delimiter + 1));
+ set_option(config, section, key, value);
}
+ int result = ferror(file) ? -1 : 0;
fclose(file);
- return 0;
+ return result;
}