]> Pileus Git - wmpus/blob - conf.c
Work on gtk interface
[wmpus] / conf.c
1 /*
2  * Copyright (c) 2011-2012, 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 #include <getopt.h>
21
22 #include "util.h"
23 #include "conf.h"
24
25 /* Types */
26 typedef struct {
27         enum {
28                 NUMBER,
29                 STRING,
30         } type;
31         char   *key;
32         union {
33                 int   num;
34                 char *str;
35         };
36 } entry_t;
37
38 /* Global Data */
39 int    conf_argc;
40 char **conf_argv;
41
42 /* Local Data */
43 static void  *conf;
44 static char   conf_path[256];
45
46 /* Helpers */
47 static int conf_cmp(const void *_a, const void *_b)
48 {
49         const entry_t *a = _a;
50         const entry_t *b = _b;
51         return strcmp(a->key, b->key);
52 }
53
54 static entry_t *conf_get(const char *key)
55 {
56         entry_t try = { .key = (char*)key };
57         entry_t **found = tfind(&try, &conf, conf_cmp);
58         return found ? *found : NULL;
59 }
60
61 static void conf_set(const char *key, int num, const char *str)
62 {
63         entry_t *entry;
64
65         /* Free old item */
66         if ((entry = conf_get(key))) {
67                 tdelete(entry, &conf, conf_cmp);
68                 free(entry->key);
69                 if (entry->type == STRING)
70                         free(entry->str);
71                 free(entry);
72         }
73
74         /* Insert new item */
75         entry = new0(entry_t);
76         entry->key = strdup(key);
77         if (str) {
78                 entry->type = STRING;
79                 entry->str  = strdup(str);
80                 //printf("set_str: %s = %s\n", key, str);
81         } else {
82                 entry->type = NUMBER;
83                 entry->num  = num;
84                 //printf("set_num: %s = %d\n", key, num);
85         }
86         tsearch(entry, &conf, conf_cmp);
87 }
88
89 static char *strtrim(char *str)
90 {
91         while (*str == ' ' || *str == '\t' || *str == '\n')
92                 str++;
93         char *end = strchr(str, '\0');
94         while (end > str && (*end == ' '  || *end == '\t' ||
95                              *end == '\n' || *end == '\0'))
96                 *end-- = '\0';
97         return str;
98 }
99
100 /* Read an ini file into the configuration
101  *  - this does not properly handle excape sequences
102  *  - could probably make this into a real parser.. */
103 static void load_file(const char *path)
104 {
105         char line[256]={}, section[256]={};
106         char key[256]={}, val[256]={}, fullkey[256]={};
107         FILE *fd = fopen(path, "rt");
108         if (!fd) return;
109         //printf("load_file: %s\n", path);
110         while (fgets(line, sizeof(line), fd)) {
111                 /* Find special characters */
112                 char *lbrace = strchr(           line   , '[');
113                 char *rbrace = strchr((lbrace ?: line)+1, ']');
114                 char *equal  = strchr(           line   , '=');
115                 char *lquote = strchr((equal  ?: line)+1, '"');
116                 char *rquote = strchr((lquote ?: line)+1, '"');
117                 char *hash   = strchr((rquote ?: line)+1, '#');
118                 if (hash)
119                         *hash = '\0';
120
121                 if (lbrace && rbrace) {
122                         /* Check for secions */
123                         memcpy(section, lbrace+1, rbrace-lbrace-1);
124                 }
125                 else if (section[0] && equal && lquote && rquote) {
126                         /* Check for numbers/plain strings */
127                         memcpy(key, line, equal-line);
128                         memcpy(val, lquote+1, rquote-lquote-1);
129                         snprintf(fullkey, sizeof(key), "%s.%s",
130                                         section, strtrim(key));
131                         if (!strchr(fullkey, ' ')) {
132                                 conf_set_str(fullkey, val);
133                                 //printf("  [%s] = [%s]\n", fullkey, val);
134                         }
135                 }
136                 else if (section[0] && equal) {
137                         /* Check for strings */
138                         memcpy(key, line, equal-line);
139                         strcpy(val, equal+1);
140                         snprintf(fullkey, sizeof(key), "%s.%s",
141                                         section, strtrim(key));
142                         if (!strchr(fullkey, ' ')) {
143                                 char *end, *trim = strtrim(val);
144                                 int num = strtol(trim, &end, 10);
145                                 if (end != val && *end == '\0')
146                                         conf_set_int(fullkey, num);
147                                 else if (!strcasecmp(trim, "true"))
148                                         conf_set_int(fullkey, 1);
149                                 else if (!strcasecmp(trim, "false"))
150                                         conf_set_int(fullkey, 0);
151                                 else
152                                         conf_set_str(fullkey, trim);
153                                 //printf("  [%s] = [%s]\n", fullkey, trim);
154                         }
155                 }
156         }
157         fclose(fd);
158 }
159
160 /* Load config from command line options */
161 static struct option long_options[] = {
162         /* name hasarg flag val */
163         {"no-capture", 0, NULL, 'n'},
164         {"border",     2, NULL, 'b'},
165         {"margin",     2, NULL, 'm'},
166         {"int",        1, NULL, 'i'},
167         {"str",        1, NULL, 's'},
168         {"help",       0, NULL, 'h'},
169         {NULL,         0, NULL,  0 },
170 };
171
172 static void usage(int argc, char **argv)
173 {
174         printf("Usage:\n");
175         printf("  %s [OPTION...]\n", argv[0]);
176         printf("\n");
177         printf("Options:\n");
178         printf("  -n, --no-capture   Do not arrange pre existing windows\n");
179         printf("  -b, --border=n     Draw an n pixel window border\n");
180         printf("  -m, --margin=n     Leave an n pixel margin around windows\n");
181         printf("  -i, --int=key=num  Set integer config option\n");
182         printf("  -s, --str=key=str  Set string config option\n");
183         printf("  -h, --help         Print usage information\n");
184 }
185
186 static void load_args(int argc, char **argv)
187 {
188         char *key, *val;
189         while (1) {
190                 int c = getopt_long(argc, argv, "nb:m:i:s:h", long_options, NULL);
191                 if (c == -1)
192                         break;
193                 switch (c) {
194                 case 'n':
195                         conf_set_int("main.no-capture", 1);
196                         break;
197                 case 'b':
198                         conf_set_int("main.border", str2num(optarg, 2));
199                         break;
200                 case 'm':
201                         conf_set_int("main.margin", str2num(optarg, 15));
202                         break;
203                 case 'i':
204                 case 's':
205                         key = strdup(optarg);
206                         val = strchr(key, '=');
207                         if (val) {
208                                 *val++ = '\0';
209                                 if (c == 's')
210                                         conf_set_str(key, val);
211                                 else
212                                         conf_set_int(key, atol(val));
213                         }
214                         free(key);
215                         break;
216                 case 'h':
217                         usage(argc, argv);
218                         exit(0);
219                 default:
220                         usage(argc, argv);
221                         exit(-1);
222                 }
223         }
224 }
225
226
227 /* Configuration file functions */
228 int conf_get_int(const char *key, int def)
229 {
230         entry_t *entry = conf_get(key);
231         return entry && entry->type == NUMBER
232                 ? entry->num : def;
233 }
234
235 void conf_set_int(const char *key, int value)
236 {
237         conf_set(key, value, NULL);
238 }
239
240 const char *conf_get_str(const char *key, const char *def)
241 {
242         entry_t *entry = conf_get(key);
243         return entry && entry->type == STRING
244                 ? entry->str : def;
245 }
246
247 void conf_set_str(const char *key, const char *value)
248 {
249         conf_set(key, 0, value);
250 }
251
252 void conf_reload(void)
253 {
254         load_file(conf_path);
255         load_args(conf_argc, conf_argv);
256 }
257
258 void conf_init(int argc, char **argv)
259 {
260         conf_argc = argc;
261         conf_argv = argv;
262         snprintf(conf_path, sizeof(conf_path), "%s/%s",
263                         getenv("HOME") ?: getenv("HOMEPATH") ?: ".",
264                         ".wmpus");
265         conf_reload();
266 }
267
268 void conf_free(void)
269 {
270 }