summaryrefslogtreecommitdiff
path: root/src/config.c
diff options
context:
space:
mode:
authorGravatar moon <moon@coffin.ir> 2025-09-13 23:18:10 +0330
committerGravatar moon <moon@coffin.ir> 2025-09-13 23:18:10 +0330
commitc74e4db86e5c0cd267688ddce47029f46c0d3ccb (patch)
tree0b5d980dab8e2365645171a43557fafeaefda26c /src/config.c
parentfeature impls + directories (diff)
plugin file support
Diffstat (limited to 'src/config.c')
-rw-r--r--src/config.c151
1 files changed, 127 insertions, 24 deletions
diff --git a/src/config.c b/src/config.c
index ef55387..fb3cb2b 100644
--- a/src/config.c
+++ b/src/config.c
@@ -5,12 +5,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-//
-// .
-// .
-// warning: slices are not NULL-terminated, and should not be modified!
-// strdup them if you need to make modifications.
typedef struct slice {
char* ref;
size_t len;
@@ -24,13 +19,109 @@ typedef struct pair {
pair_t* global_arg_table = NULL;
size_t args_count = 0;
+void parse_config_file(const char* filename) {
+ FILE* file = fopen(filename, "r");
+ if (!file) {
+ fprintf(stderr, "failed to open config file: %s\n", filename);
+ exit(1);
+ }
+
+ char* line = NULL;
+ size_t len = 0;
+ ssize_t read;
+ size_t new_args_count = args_count;
+
+ while ((read = getline(&line, &len, file)) != -1) {
+ if (read > 0 && line[0] != '#' && line[0] != '\n') {
+ new_args_count++;
+ }
+ }
+ rewind(file);
+
+ if (new_args_count > args_count) {
+ pair_t* new_table = realloc(global_arg_table, new_args_count * sizeof(pair_t));
+ if (!new_table) {
+ fprintf(stderr, "realloc failed for config file parsing\n");
+ fclose(file);
+ free(line);
+ exit(1);
+ }
+ global_arg_table = new_table;
+ }
+
+ while ((read = getline(&line, &len, file)) != -1) {
+ if (read <= 1 || line[0] == '#' || line[0] == '\n') continue;
+
+ if (line[read - 1] == '\n') line[read - 1] = '\0';
+
+ char* current = line;
+ char* eq_sign = strchr(current, '=');
+ if (eq_sign == NULL) {
+ fprintf(stderr, "config file error: expected 'key=value' in '%s'\n", current);
+ continue;
+ }
+
+ // key
+ size_t key_len = eq_sign - current;
+ size_t key_start = 0;
+ while (key_start < key_len && isspace(current[key_start])) {
+ key_start++;
+ key_len--;
+ }
+ while (key_len > 0 && isspace(current[key_start + key_len - 1])) {
+ key_len--;
+ }
+
+ if (key_len == 0) {
+ fprintf(stderr, "config file error: empty key in '%s'\n", current);
+ continue;
+ }
+
+ // value
+ size_t value_start = eq_sign - current + 1;
+ size_t value_len = strlen(current) - value_start;
+ while (value_start < strlen(current) && isspace(current[value_start])) {
+ value_start++;
+ value_len--;
+ }
+ while (value_len > 0 && isspace(current[value_start + value_len - 1])) {
+ value_len--;
+ }
+
+ // store
+ char* key_str = strndup(current + key_start, key_len);
+ char* value_str = strndup(current + value_start, value_len);
+ if (!key_str || !value_str) {
+ fprintf(stderr, "strndup failed for config file parsing\n");
+ free(key_str);
+ free(value_str);
+ fclose(file);
+ free(line);
+ exit(1);
+ }
+
+ global_arg_table[args_count].key.ref = key_str;
+ global_arg_table[args_count].key.len = key_len;
+ global_arg_table[args_count].value.ref = value_str;
+ global_arg_table[args_count].value.len = value_len;
+ args_count++;
+ }
+
+ fclose(file);
+ free(line);
+}
+
void parse_arguments(int argc, char** argv) {
if (argc <= 1) return;
global_arg_table = calloc(argc - 1, sizeof(pair_t));
+ if (!global_arg_table) {
+ fprintf(stderr, "calloc failed for argument parsing\n");
+ exit(1);
+ }
for (int i = 1; i < argc; i++) {
- char* current = argv[ i ];
+ char* current = argv[i];
char* eq_sign = strchr(current, '=');
if (eq_sign == NULL) {
printf(
@@ -41,14 +132,14 @@ void parse_arguments(int argc, char** argv) {
exit(1);
}
- // key
- size_t key_len = eq_sign - current;
+ // Key
+ size_t key_len = eq_sign - current;
size_t key_start = 0;
- while (key_start < key_len && isspace(current[ key_start ])) { // trim start
+ while (key_start < key_len && isspace(current[key_start])) {
key_start++;
key_len--;
}
- while (key_len > 0 && isspace(current[ key_start + key_len - 1 ])) { // trim end
+ while (key_len > 0 && isspace(current[key_start + key_len - 1])) {
key_len--;
}
@@ -62,38 +153,50 @@ void parse_arguments(int argc, char** argv) {
// value
size_t value_start = eq_sign - current + 1;
- size_t value_len = strlen(current) - value_start;
- while (value_start < strlen(current) && isspace(current[ value_start ])) { // trim start
+ size_t value_len = strlen(current) - value_start;
+ while (value_start < strlen(current) && isspace(current[value_start])) {
value_start++;
value_len--;
}
- while (value_len > 0 && isspace(current[ value_start + value_len - 1 ])) { // trim end
+ while (value_len > 0 && isspace(current[value_start + value_len - 1])) {
value_len--;
}
+ // config file
+ if (key_len == 6 && strncmp(current + key_start, "config", 6) == 0) {
+ char* config_file = strndup(current + value_start, value_len);
+ if (!config_file) {
+ fprintf(stderr, "strndup failed for config file path\n");
+ exit(1);
+ }
+ parse_config_file(config_file);
+ free(config_file);
+ continue;
+ }
+
// store
- global_arg_table[ args_count ].key.ref = current + key_start;
- global_arg_table[ args_count ].key.len = key_len;
- global_arg_table[ args_count ].value.ref = current + value_start;
- global_arg_table[ args_count ].value.len = value_len;
+ global_arg_table[args_count].key.ref = current + key_start;
+ global_arg_table[args_count].key.len = key_len;
+ global_arg_table[args_count].value.ref = current + value_start;
+ global_arg_table[args_count].value.len = value_len;
args_count++;
}
}
-// get a config option's value from argv.
-// if mandatory == true -> program errors
char* get_config(char* key, bool mandatory) {
size_t len = strlen(key);
for (int i = 0; i < args_count; i++) {
- if (global_arg_table[ i ].key.len != len) continue;
- if (strncmp(key, global_arg_table[ i ].key.ref, len) != 0) continue;
- char* new_str = malloc(global_arg_table[ i ].value.len);
- memcpy(new_str, global_arg_table[ i ].value.ref, global_arg_table[ i ].value.len);
+ if (global_arg_table[i].key.len != len) continue;
+ if (strncmp(key, global_arg_table[i].key.ref, len) != 0) continue;
+ char* new_str = strndup(global_arg_table[i].value.ref, global_arg_table[i].value.len);
+ if (!new_str && mandatory) {
+ fprintf(stderr, "strndup failed for config value\n");
+ exit(1);
+ }
return new_str; // free me!
}
if (!mandatory) return NULL;
fprintf(stderr, "program expected argument %s but did not receive it.\n", key);
- // __builtin_unreachable();
return NULL;
} \ No newline at end of file