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