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