10#include "tests/test.h"
17 #define strcasecmp _stricmp
34 const char *default_value;
39#define MAX_NUMERIC_LIST 8
43 char host[MAX_STR_LEN];
44 char log_level[MAX_STR_LEN];
45 char description[MAX_STR_LEN];
49 uint32_t max_connections;
51 uint32_t bet_amounts[MAX_NUMERIC_LIST];
52 uint8_t bet_amount_count;
53 uint32_t difficulty_levels[MAX_NUMERIC_LIST];
54 uint8_t difficulty_level_count;
55 uint32_t port_list[MAX_NUMERIC_LIST];
56 uint8_t port_list_count;
60 {
"host", CFG_TYPE_STRING,
"localhost", offsetof(
AppConfig_t, host), MAX_STR_LEN },
61 {
"log_level", CFG_TYPE_STRING,
"info", offsetof(
AppConfig_t, log_level), MAX_STR_LEN },
62 {
"description", CFG_TYPE_STRING,
"", offsetof(
AppConfig_t, description), MAX_STR_LEN },
63 {
"port", CFG_TYPE_UINT16,
"8080", offsetof(
AppConfig_t, port),
sizeof(uint16_t) },
64 {
"timeout", CFG_TYPE_INT,
"-5", offsetof(
AppConfig_t, timeout),
sizeof(int) },
65 {
"max_retries", CFG_TYPE_UINT8,
"3", offsetof(
AppConfig_t, max_retries),
sizeof(uint8_t) },
66 {
"max_connections", CFG_TYPE_UINT32,
"100", offsetof(
AppConfig_t, max_connections),
sizeof(uint32_t) },
67 {
"verbose", CFG_TYPE_BOOL,
"no", offsetof(
AppConfig_t, verbose),
sizeof(bool) },
73 void *field = (uint8_t *)cfg + entry->offset;
77 snprintf((
char *)field, entry->size,
"%s", val);
80 *(
int *)field = (
int)strtol(val, NULL, 10);
83 *(uint8_t *)field = (uint8_t)strtoul(val, NULL, 10);
86 *(uint16_t *)field = (uint16_t)strtoul(val, NULL, 10);
89 *(uint32_t *)field = (uint32_t)strtoul(val, NULL, 10);
92 *(
bool *)field = (strcasecmp(val,
"yes") == 0
93 || strcasecmp(val,
"true") == 0
94 || strcmp(val,
"1") == 0);
100print_uint32_list(
const char *label,
const uint32_t *arr, uint8_t count)
102 printf(
" %-20s", label);
103 for (uint8_t i = 0; i < count; i++)
104 printf(
"%s%u", i ?
", " :
"", arr[i]);
111 printf(
"\n--- Parsed config ---\n");
112 printf(
" %-20s%s\n",
"host:", cfg->host);
113 printf(
" %-20s%s\n",
"log_level:", cfg->log_level);
114 printf(
" %-20s%s\n",
"description:", cfg->description);
115 printf(
" %-20s%u\n",
"port:", cfg->port);
116 printf(
" %-20s%d\n",
"timeout:", cfg->timeout);
117 printf(
" %-20s%u\n",
"max_retries:", cfg->max_retries);
118 printf(
" %-20s%u\n",
"max_connections:", cfg->max_connections);
119 printf(
" %-20s%s\n",
"verbose:", cfg->verbose ?
"true" :
"false");
120 print_uint32_list(
"bet_amounts:", cfg->bet_amounts, cfg->bet_amount_count);
121 print_uint32_list(
"difficulty_levels:", cfg->difficulty_levels, cfg->difficulty_level_count);
122 print_uint32_list(
"port_list:", cfg->port_list, cfg->port_list_count);
123 printf(
"---------------------\n");
127parse_numeric_list(
struct Canfigger *node, uint32_t *out, uint8_t *count)
130 canfigger_free_current_attr_str_advance(node->attributes, &attr);
131 while (attr && *count < MAX_NUMERIC_LIST)
133 printf(
" attribute: %s\n", attr);
134 out[(*count)++] = (uint32_t)strtoul(attr, NULL, 10);
135 canfigger_free_current_attr_str_advance(node->attributes, &attr);
140main(
int argc,
char *argv[])
142 char *default_filename = SOURCE_DIR
"/example-02.conf";
143 char *filename_ptr = default_filename;
146 filename_ptr = argv[1];
150 fputs(
"This example program only accepts a single argument:\n\n", stderr);
151 fprintf(stderr,
"%s <config-file>\n\n", argv[0]);
161 bool found_keys[ARRAY_SIZE(entries)];
162 memset(found_keys, 0,
sizeof(found_keys));
164 printf(
"--- Parsing %s ---\n", filename_ptr);
169 printf(
"key: %s, value: %s\n", node->key,
170 node->value ? node->value :
"NULL");
172 if (strcmp(node->key,
"bet_amounts") == 0)
173 parse_numeric_list(node, config.bet_amounts, &config.bet_amount_count);
174 else if (strcmp(node->key,
"difficulty_levels") == 0)
175 parse_numeric_list(node, config.difficulty_levels, &config.difficulty_level_count);
176 else if (strcmp(node->key,
"port_list") == 0)
177 parse_numeric_list(node, config.port_list, &config.port_list_count);
180 for (
size_t i = 0; i < ARRAY_SIZE(entries); i++)
182 if (strcmp(node->key, entries[i].key) == 0)
184 config_set_field(&config, &entries[i],
185 node->value ? node->value : entries[i].default_value);
186 found_keys[i] =
true;
195 for (
size_t i = 0; i < ARRAY_SIZE(entries); i++)
197 config_set_field(&config, &entries[i], entries[i].default_value);
199 if (filename_ptr != default_filename)
202 print_config(&config);
204 assert(strcmp(config.host,
"example.com") == 0);
205 assert(strcmp(config.log_level,
"debug") == 0);
206 assert(strcmp(config.description,
"A sample configuration file") == 0);
207 assert(config.port == 9000);
208 assert(config.timeout == -10);
209 assert(config.max_retries == 5);
210 assert(config.max_connections == 200);
211 assert(config.verbose ==
true);
213 const uint32_t expected_bet[] = { 100, 250, 500, 1000 };
214 const uint32_t expected_difficulty[] = { 1, 2, 3, 5, 8 };
215 const uint32_t expected_ports[] = { 8080, 9090 };
217 assert(config.bet_amount_count == ARRAY_SIZE(expected_bet));
218 for (
size_t i = 0; i < config.bet_amount_count; i++)
219 assert(config.bet_amounts[i] == expected_bet[i]);
221 assert(config.difficulty_level_count == ARRAY_SIZE(expected_difficulty));
222 for (
size_t i = 0; i < config.difficulty_level_count; i++)
223 assert(config.difficulty_levels[i] == expected_difficulty[i]);
225 assert(config.port_list_count == ARRAY_SIZE(expected_ports));
226 for (
size_t i = 0; i < config.port_list_count; i++)
227 assert(config.port_list[i] == expected_ports[i]);
struct Canfigger * canfigger_parse_file(const char *file, const int delimiter)
Parse a configuration file into a linked list of key-value nodes.
void canfigger_free_current_key_node_advance(struct Canfigger **node)
Free the current node and advance the list pointer to the next node.
A single node in the parsed configuration linked list.