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