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