2 * Copyright (c) 2011, Andy Spencer <andy753421@gmail.com>
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.
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
26 typedef enum { number, string } type_t;
40 static char **conf_argv;
41 static char conf_path[256];
44 static int conf_cmp(const void *_a, const void *_b)
46 const entry_t *a = _a;
47 const entry_t *b = _b;
48 return strcmp(a->key, b->key);
51 static entry_t *conf_get(const char *key)
53 entry_t try = { .key = (char*)key };
54 entry_t **found = tfind(&try, &conf, conf_cmp);
55 return found ? *found : NULL;
58 static void conf_set(const char *key, int num, const char *str)
63 if ((entry = conf_get(key))) {
64 tdelete(entry, &conf, conf_cmp);
66 if (entry->type == string)
72 entry = new0(entry_t);
73 entry->key = strdup(key);
76 entry->str = strdup(str);
81 tsearch(entry, &conf, conf_cmp);
84 static char *strtrim(char *str)
86 while (*str == ' ' || *str == '\t' || *str == '\n')
88 char *end = strchr(str, '\0');
89 while (end > str && (*end == ' ' || *end == '\t' ||
90 *end == '\n' || *end == '\0'))
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)
100 char line[256]={}, section[256]={};
101 char key[256]={}, val[256]={};
102 FILE *fd = fopen(path, "rt");
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, '#');
116 if (lbrace && rbrace) {
117 /* Check for secions */
118 memcpy(section, lbrace+1, rbrace-lbrace-1);
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);
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);
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);
143 conf_set_str(_key, _val);
144 printf(" [%s.%s] = [%s]\n", section, _key, _val);
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'},
162 static void usage(int argc, char **argv)
165 printf(" %s [OPTION...]\n", argv[0]);
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");
176 static void load_args(int argc, char **argv)
180 int c = getopt_long(argc, argv, "b:m:ch", long_options, NULL);
185 conf_set_int("main.border", str2num(optarg, 2));
188 conf_set_int("main.margin", str2num(optarg, 15));
191 conf_set_int("main.capture", 1);
195 key = strdup(optarg);
196 val = strchr(key, '=');
200 conf_set_str(key, val);
202 conf_set_int(key, atol(val));
217 /* Configuration file functions */
218 int conf_get_int(const char *key)
220 entry_t *entry = conf_get(key);
221 return entry ? entry->num : 0;
224 void conf_set_int(const char *key, int value)
226 conf_set(key, value, NULL);
229 const char *conf_get_str(const char *key)
231 entry_t *entry = conf_get(key);
232 return entry ? entry->str : NULL;
235 void conf_set_str(const char *key, const char *value)
237 conf_set(key, 0, value);
240 void conf_reload(void)
242 load_file(conf_path);
243 load_args(conf_argc, conf_argv);
246 void conf_init(int argc, char **argv)
250 snprintf(conf_path, sizeof(conf_path),
251 "%s/%s", getenv("HOME"), ".wmpus");