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
44 static char conf_path[256];
47 static int conf_cmp(const void *_a, const void *_b)
49 const entry_t *a = _a;
50 const entry_t *b = _b;
51 return strcmp(a->key, b->key);
54 static entry_t *conf_get(const char *key)
56 entry_t try = { .key = (char*)key };
57 entry_t **found = tfind(&try, &conf, conf_cmp);
58 return found ? *found : NULL;
61 static void conf_set(const char *key, int num, const char *str)
66 if ((entry = conf_get(key))) {
67 tdelete(entry, &conf, conf_cmp);
69 if (entry->type == STRING)
75 entry = new0(entry_t);
76 entry->key = strdup(key);
79 entry->str = strdup(str);
80 //printf("set_str: %s = %s\n", key, str);
84 //printf("set_num: %s = %d\n", key, num);
86 tsearch(entry, &conf, conf_cmp);
89 static char *strtrim(char *str)
91 while (*str == ' ' || *str == '\t' || *str == '\n')
93 char *end = strchr(str, '\0');
94 while (end > str && (*end == ' ' || *end == '\t' ||
95 *end == '\n' || *end == '\0'))
100 /* Read an ini file into the configuration
101 * - this does not properly handle excape sequences
102 * - could probably make this into a real parser.. */
103 static void load_file(const char *path)
105 char line[256]={}, section[256]={};
106 char key[256]={}, val[256]={}, fullkey[256]={};
107 FILE *fd = fopen(path, "rt");
109 //printf("load_file: %s\n", path);
110 while (fgets(line, sizeof(line), fd)) {
111 /* Find special characters */
112 char *lbrace = strchr( line , '[');
113 char *rbrace = strchr((lbrace ?: line)+1, ']');
114 char *equal = strchr( line , '=');
115 char *lquote = strchr((equal ?: line)+1, '"');
116 char *rquote = strchr((lquote ?: line)+1, '"');
117 char *hash = strchr((rquote ?: line)+1, '#');
121 if (lbrace && rbrace) {
122 /* Check for secions */
123 memcpy(section, lbrace+1, rbrace-lbrace-1);
125 else if (section[0] && equal && lquote && rquote) {
126 /* Check for numbers/plain strings */
127 memcpy(key, line, equal-line);
128 memcpy(val, lquote+1, rquote-lquote-1);
129 snprintf(fullkey, sizeof(key), "%s.%s",
130 section, strtrim(key));
131 if (!strchr(fullkey, ' ')) {
132 conf_set_str(fullkey, val);
133 //printf(" [%s] = [%s]\n", fullkey, val);
136 else if (section[0] && equal) {
137 /* Check for strings */
138 memcpy(key, line, equal-line);
139 strcpy(val, equal+1);
140 snprintf(fullkey, sizeof(key), "%s.%s",
141 section, strtrim(key));
142 if (!strchr(fullkey, ' ')) {
143 char *end, *trim = strtrim(val);
144 int num = strtol(trim, &end, 10);
145 if (end != val && *end == '\0')
146 conf_set_int(fullkey, num);
147 else if (!strcasecmp(trim, "true"))
148 conf_set_int(fullkey, 1);
149 else if (!strcasecmp(trim, "false"))
150 conf_set_int(fullkey, 0);
152 conf_set_str(fullkey, trim);
153 //printf(" [%s] = [%s]\n", fullkey, trim);
160 /* Load config from command line options */
161 static struct option long_options[] = {
162 /* name hasarg flag val */
163 {"no-capture", 0, NULL, 'n'},
164 {"border", 2, NULL, 'b'},
165 {"margin", 2, NULL, 'm'},
166 {"int", 1, NULL, 'i'},
167 {"str", 1, NULL, 's'},
168 {"help", 0, NULL, 'h'},
172 static void usage(int argc, char **argv)
175 printf(" %s [OPTION...]\n", argv[0]);
177 printf("Options:\n");
178 printf(" -n, --no-capture Do not arrange pre existing windows\n");
179 printf(" -b, --border=n Draw an n pixel window border\n");
180 printf(" -m, --margin=n Leave an n pixel margin around windows\n");
181 printf(" -i, --int=key=num Set integer config option\n");
182 printf(" -s, --str=key=str Set string config option\n");
183 printf(" -h, --help Print usage information\n");
186 static void load_args(int argc, char **argv)
190 int c = getopt_long(argc, argv, "nb:m:i:s:h", long_options, NULL);
195 conf_set_int("main.no-capture", 1);
198 conf_set_int("main.border", str2num(optarg, 2));
201 conf_set_int("main.margin", str2num(optarg, 15));
205 key = strdup(optarg);
206 val = strchr(key, '=');
210 conf_set_str(key, val);
212 conf_set_int(key, atol(val));
227 /* Configuration file functions */
228 int conf_get_int(const char *key, int def)
230 entry_t *entry = conf_get(key);
231 return entry && entry->type == NUMBER
235 void conf_set_int(const char *key, int value)
237 conf_set(key, value, NULL);
240 const char *conf_get_str(const char *key, const char *def)
242 entry_t *entry = conf_get(key);
243 return entry && entry->type == STRING
247 void conf_set_str(const char *key, const char *value)
249 conf_set(key, 0, value);
252 void conf_reload(void)
254 load_file(conf_path);
255 load_args(conf_argc, conf_argv);
258 void conf_init(int argc, char **argv)
262 snprintf(conf_path, sizeof(conf_path), "%s/%s",
263 getenv("HOME") ?: getenv("HOMEPATH") ?: ".",