]> Pileus Git - wmpus/blob - conf.c
Add configuration interface
[wmpus] / conf.c
1 /*
2  * Copyright (c) 2011, Andy Spencer <andy753421@gmail.com>
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  */
15
16 #include <stdlib.h>
17 #include <stdio.h>
18 #include <string.h>
19 #include <search.h>
20
21 #include "util.h"
22 #include "conf.h"
23
24 /* Types */
25 typedef enum { number, string } type_t;
26
27 typedef struct {
28         type_t  type;
29         char   *key;
30         union {
31                 int   num;
32                 char *str;
33         };
34 } entry_t;
35
36 /* Data */
37 static void *conf;
38
39 /* Helpers */
40 static int conf_cmp(const void *_a, const void *_b)
41 {
42         const entry_t *a = _a;
43         const entry_t *b = _b;
44         return strcmp(a->key, b->key);
45 }
46
47 static entry_t *conf_get(const char *key)
48 {
49         entry_t try = { .key = (char*)key };
50         entry_t **found = tfind(&try, &conf, conf_cmp);
51         return found ? *found : NULL;
52 }
53
54 static void conf_set(const char *key, int num, const char *str)
55 {
56         entry_t *entry;
57
58         /* Free old item */
59         if ((entry = conf_get(key))) {
60                 tdelete(entry, &conf, conf_cmp);
61                 free(entry->key);
62                 if (entry->type == string)
63                         free(entry->str);
64                 free(entry);
65         }
66
67         /* Insert new item */
68         entry = new0(entry_t);
69         entry->key = strdup(key);
70         if (str) {
71                 entry->type = string;
72                 entry->str  = strdup(str);
73         } else {
74                 entry->type = number;
75                 entry->num  = num;
76         }
77         tsearch(entry, &conf, conf_cmp);
78 }
79
80 static char *strtrim(char *str)
81 {
82         while (*str == ' ' || *str == '\t' || *str == '\n')
83                 str++;
84         char *end = strchr(str, '\0');
85         while (end > str && (*end == ' '  || *end == '\t' ||
86                              *end == '\n' || *end == '\0'))
87                 *end-- = '\0';
88         return str;
89 }
90
91 /* Read an ini file into the configuration
92  *  - this does not properly handle excape sequences
93  *  - could probably make this into a real parser.. */
94 static void load_file(const char *path)
95 {
96         char line[256]={}, section[256]={};
97         char key[256]={}, val[256]={};
98         FILE *fd = fopen(path, "rt");
99         if (!fd) return;
100         printf("load_file: %s\n", path);
101         while (fgets(line, sizeof(line), fd)) {
102                 /* Find special characters */
103                 char *lbrace = strchr(           line   , '[');
104                 char *rbrace = strchr((lbrace ?: line)+1, ']');
105                 char *equal  = strchr(           line   , '=');
106                 char *lquote = strchr((equal  ?: line)+1, '"');
107                 char *rquote = strchr((lquote ?: line)+1, '"');
108                 char *hash   = strchr((rquote ?: line)+1, '#');
109                 if (hash)
110                         *hash = '\0';
111
112                 if (lbrace && rbrace) {
113                         /* Check for secions */
114                         memcpy(section, lbrace+1, rbrace-lbrace-1);
115                 }
116                 else if (section[0] && equal && lquote && rquote) {
117                         /* Check for numbers/plain strings */
118                         memcpy(key, line, equal-line);
119                         memcpy(val, lquote+1, rquote-lquote-1);
120                         char *_key = strtrim(key);
121                         conf_set_str(_key, val);
122                         printf("  [%s.%s] = [%s]\n", section, _key, val);
123                 }
124                 else if (section[0] && equal) {
125                         /* Check for strings */
126                         memcpy(key, line, equal-line);
127                         strcpy(val, equal+1);
128                         char *_key = strtrim(key);
129                         char *_val = strtrim(val);
130                         char *end;
131                         int num = strtol(_val, &end, 10);
132                         if (end != val && *end == '\0')
133                                 conf_set_int(_key, num);
134                         else if (!strcasecmp(_val, "true"))
135                                 conf_set_int(_key, 1);
136                         else if (!strcasecmp(_val, "false"))
137                                 conf_set_int(_key, 0);
138                         else
139                                 conf_set_str(_key, _val);
140                         printf("  [%s.%s] = [%s]\n", section, _key, _val);
141                 }
142         }
143         fclose(fd);
144 }
145
146 static void load_args(int argc, char **argv)
147 {
148         /* ... */
149 }
150
151
152 /* Configuration file functions */
153 int conf_get_int(const char *key)
154 {
155         entry_t *entry = conf_get(key);
156         return entry ? entry->num : 0;
157 }
158
159 void conf_set_int(const char *key, int value)
160 {
161         conf_set(key, value, NULL);
162 }
163
164 const char *conf_get_str(const char *key)
165 {
166         entry_t *entry = conf_get(key);
167         return entry ? entry->str : NULL;
168 }
169
170 void conf_set_str(const char *key, const char *value)
171 {
172         conf_set(key, 0, value);
173 }
174
175 void conf_init(int argc, char **argv)
176 {
177         /* Load configuration */
178         char path[256];
179         snprintf(path, sizeof(path), "%s/%s", getenv("HOME"), ".wmpus");
180         load_file(path);
181         load_args(argc, argv);
182 }
183
184 void conf_free(void)
185 {
186 }