cwist
Modern C web framework with libttak runtime
Loading...
Searching...
No Matches
config.c
Go to the documentation of this file.
1
4#define _POSIX_C_SOURCE 200809L
7#include <stdlib.h>
8#include <stdio.h>
9#include <string.h>
10#include <strings.h>
11#include <ctype.h>
12
13#define CWIST_CONFIG_BUCKETS 64
14
19static size_t cwist_config_hash(const char *key) {
20 size_t hash = 5381;
21 int c;
22 while ((c = *key++)) hash = ((hash << 5) + hash) + c;
23 return hash;
24}
25
31 if (!cfg) return NULL;
33 cfg->buckets =
35 if (!cfg->buckets) {
36 cwist_free(cfg);
37 return NULL;
38 }
39 return cfg;
40}
41
46 if (!cfg) return;
47 for (size_t i = 0; i < cfg->bucket_count; i++) {
49 while (curr) {
51 cwist_free(curr->key);
52 cwist_free(curr->value);
54 curr = next;
55 }
56 }
57 cwist_free(cfg->buckets);
58 cwist_free(cfg);
59}
60
66void cwist_config_set(cwist_config *cfg, const char *key, const char *value) {
67 if (!cfg || !key) return;
68 size_t idx = cwist_config_hash(key) % cfg->bucket_count;
70 while (curr) {
71 if (strcmp(curr->key, key) == 0) {
72 /* Keep the old value if the copy fails, so get() never sees NULL. */
73 char *copy = cwist_strdup(value ? value : "");
74 if (!copy) return;
75 cwist_free(curr->value);
76 curr->value = copy;
77 return;
78 }
79 curr = curr->next;
80 }
82 if (!bucket) return;
83 bucket->key = cwist_strdup(key);
84 bucket->value = cwist_strdup(value ? value : "");
85 if (!bucket->key || !bucket->value) {
86 cwist_free(bucket->key);
87 cwist_free(bucket->value);
88 cwist_free(bucket);
89 return;
90 }
91 bucket->next = cfg->buckets[idx];
92 cfg->buckets[idx] = bucket;
93}
94
102const char *cwist_config_get(cwist_config *cfg, const char *key) {
103 if (!cfg || !key) return NULL;
104 size_t idx = cwist_config_hash(key) % cfg->bucket_count;
106 while (curr) {
107 if (strcmp(curr->key, key) == 0) {
108 return curr->value;
109 }
110 curr = curr->next;
111 }
112 return NULL;
113}
114
122int cwist_config_get_int(cwist_config *cfg, const char *key, int default_val) {
123 const char *val = cwist_config_get(cfg, key);
124 if (!val) return default_val;
125 char *endptr;
126 long l = strtol(val, &endptr, 10);
127 if (endptr == val || *endptr != '\0') return default_val;
128 return (int)l;
129}
130
140bool cwist_config_get_bool(cwist_config *cfg, const char *key, bool default_val) {
141 const char *val = cwist_config_get(cfg, key);
142 if (!val) return default_val;
143 if (strcasecmp(val, "true") == 0 || strcasecmp(val, "1") == 0 || strcasecmp(val, "yes") == 0)
144 return true;
145 if (strcasecmp(val, "false") == 0 || strcasecmp(val, "0") == 0 || strcasecmp(val, "no") == 0)
146 return false;
147 return default_val;
148}
149
157void cwist_config_load_env(cwist_config *cfg, const char *prefix) {
158 if (!cfg) return;
159 extern char **environ;
160 size_t prefix_len = prefix ? strlen(prefix) : 0;
161 for (char **env = environ; *env; env++) {
162 char *eq = strchr(*env, '=');
163 if (!eq) continue;
164 size_t key_len = (size_t)(eq - *env);
165 if (prefix_len > 0) {
166 if (key_len < prefix_len || strncmp(*env, prefix, prefix_len) != 0) continue;
167 }
168 char *key CWIST_DEFER_FREE = (char *)cwist_alloc(key_len + 1);
169 if (!key) continue; /* skip this variable rather than crash */
170 memcpy(key, *env, key_len);
171 key[key_len] = '\0';
172 cwist_config_set(cfg, key, eq + 1);
173 }
174}
175
184void cwist_config_load_file(cwist_config *cfg, const char *path) {
185 if (!cfg || !path) return;
186 FILE *f = fopen(path, "r");
187 if (!f) return;
188 char line[1024];
189 while (fgets(line, sizeof(line), f)) {
190 char *p = line;
191 while (isspace((unsigned char)*p)) p++;
192 if (*p == '#' || *p == '\0') continue;
193 char *eq = strchr(p, '=');
194 if (!eq) continue;
195 *eq = '\0';
196 char *key = p;
197 char *value = eq + 1;
198 // trim key
199 char *ke = key + strlen(key) - 1;
200 while (ke > key && isspace((unsigned char)*ke)) *ke-- = '\0';
201 // trim value
202 while (isspace((unsigned char)*value)) value++;
203 char *ve = value + strlen(value) - 1;
204 while (ve > value && isspace((unsigned char)*ve)) *ve-- = '\0';
205 // unquote value
206 if (value[0] == '"' && ve == value + strlen(value) - 1 && *ve == '"') {
207 value++;
208 *ve = '\0';
209 }
210 cwist_config_set(cfg, key, value);
211 }
212 fclose(f);
213}
Memory allocation wrappers backed by libttak.
void cwist_free(void *ptr)
Free memory obtained via cwist_alloc/cwist_strdup/etc.
Definition alloc.c:52
char * cwist_strdup(const char *src)
Duplicate a string using libttak-backed storage.
Definition alloc.c:32
#define CWIST_DEFER_FREE
Attach to a pointer variable's declaration to cwist_free() it automatically when that variable's encl...
Definition alloc.h:101
void * cwist_alloc_array(size_t count, size_t elem_size)
Allocate zeroed memory for count elements.
Definition alloc.c:21
void * cwist_alloc(size_t size)
Allocate zeroed memory tracked by libttak.
Definition alloc.c:17
int cwist_config_get_int(cwist_config *cfg, const char *key, int default_val)
Get a config value parsed as an integer.
Definition config.c:122
#define CWIST_CONFIG_BUCKETS
Definition config.c:13
void cwist_config_load_file(cwist_config *cfg, const char *path)
Load key/value pairs from a simple properties-style file. Each non-blank, non-comment line must be ke...
Definition config.c:184
void cwist_config_load_env(cwist_config *cfg, const char *prefix)
Load key/value pairs from the process environment into the config. Entries without '=' are skipped....
Definition config.c:157
cwist_config * cwist_config_create(void)
Create an empty config store.
Definition config.c:29
void cwist_config_destroy(cwist_config *cfg)
Free a config store and all of its key/value entries.
Definition config.c:45
bool cwist_config_get_bool(cwist_config *cfg, const char *key, bool default_val)
Get a config value parsed as a boolean. Accepted true spellings (case-insensitive): "true",...
Definition config.c:140
void cwist_config_set(cwist_config *cfg, const char *key, const char *value)
Set a config key to a value, replacing any existing entry.
Definition config.c:66
const char * cwist_config_get(cwist_config *cfg, const char *key)
Look up the value for a key.
Definition config.c:102
Application configuration management (.env, environment variables).
size_t cap
Definition otel.c:56
struct cwist_config_bucket * next
Definition config.h:15
size_t bucket_count
Definition config.h:20
cwist_config_bucket ** buckets
Definition config.h:19