2 * Copyright (c) 2011-2012, 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
42 static char **conf_argv;
43 static char conf_path[256];
46 static int entry_cmp(const void *_a, const void *_b)
48 const entry_t *a = _a;
49 const entry_t *b = _b;
50 return strcmp(a->key, b->key);
53 static entry_t *entry_get(const char *key)
55 entry_t try = { .key = (char*)key };
56 entry_t **found = tfind(&try, &conf, entry_cmp);
57 return found ? *found : NULL;
60 static void entry_free(entry_t *entry)
63 if (entry->type == STRING)
68 static void entry_set(const char *key, int num, const char *str)
73 if ((entry = entry_get(key))) {
74 tdelete(entry, &conf, entry_cmp);
79 entry = new0(entry_t);
80 entry->key = strdup(key);
83 entry->str = strdup(str);
84 //printf("set_str: %s = %s\n", key, str);
88 //printf("set_num: %s = %d\n", key, num);
90 tsearch(entry, &conf, entry_cmp);
93 static char *strtrim(char *str)
95 while (*str == ' ' || *str == '\t' || *str == '\n')
97 char *end = strchr(str, '\0');
98 while (end > str && (*end == ' ' || *end == '\t' ||
99 *end == '\n' || *end == '\0'))
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)
109 char line[256]={}, section[256]={};
110 char key[256]={}, val[256]={}, fullkey[256]={};
111 FILE *fd = fopen(path, "rt");
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, '#');
125 if (lbrace && rbrace) {
126 /* Check for secions */
127 memcpy(section, lbrace+1, rbrace-lbrace-1);
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);
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);
156 conf_set_str(fullkey, trim);
157 //printf(" [%s] = [%s]\n", fullkey, trim);
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'},
176 static void usage(int argc, char **argv)
179 printf(" %s [OPTION...]\n", argv[0]);
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");
190 static void load_args(int argc, char **argv)
194 int c = getopt_long(argc, argv, "nb:m:i:s:h", long_options, NULL);
199 conf_set_int("main.no-capture", 1);
202 conf_set_int("main.border", str2num(optarg, 2));
205 conf_set_int("main.margin", str2num(optarg, 15));
209 key = strdup(optarg);
210 val = strchr(key, '=');
214 conf_set_str(key, val);
216 conf_set_int(key, atol(val));
231 /* Configuration file functions */
232 int conf_get_int(const char *key, int def)
234 entry_t *entry = entry_get(key);
235 return entry && entry->type == NUMBER
239 void conf_set_int(const char *key, int value)
241 entry_set(key, value, NULL);
244 const char *conf_get_str(const char *key, const char *def)
246 entry_t *entry = entry_get(key);
247 return entry && entry->type == STRING
251 void conf_set_str(const char *key, const char *value)
253 entry_set(key, 0, value);
256 void conf_reload(void)
258 load_file(conf_path);
259 load_args(conf_argc, conf_argv);
262 void conf_init(int argc, char **argv)
266 snprintf(conf_path, sizeof(conf_path), "%s/%s",
267 getenv("HOME") ?: getenv("HOMEPATH") ?: ".",
274 tdestroy(conf, (void(*)(void*))entry_free);