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
41 static char **conf_argv;
42 static char conf_path[256];
45 static int conf_cmp(const void *_a, const void *_b)
47 const entry_t *a = _a;
48 const entry_t *b = _b;
49 return strcmp(a->key, b->key);
52 static entry_t *conf_get(const char *key)
54 entry_t try = { .key = (char*)key };
55 entry_t **found = tfind(&try, &conf, conf_cmp);
56 return found ? *found : NULL;
59 static void conf_set(const char *key, int num, const char *str)
64 if ((entry = conf_get(key))) {
65 tdelete(entry, &conf, conf_cmp);
67 if (entry->type == STRING)
73 entry = new0(entry_t);
74 entry->key = strdup(key);
77 entry->str = strdup(str);
78 //printf("set_str: %s = %s\n", key, str);
82 //printf("set_num: %s = %d\n", key, num);
84 tsearch(entry, &conf, conf_cmp);
87 static char *strtrim(char *str)
89 while (*str == ' ' || *str == '\t' || *str == '\n')
91 char *end = strchr(str, '\0');
92 while (end > str && (*end == ' ' || *end == '\t' ||
93 *end == '\n' || *end == '\0'))
98 /* Read an ini file into the configuration
99 * - this does not properly handle excape sequences
100 * - could probably make this into a real parser.. */
101 static void load_file(const char *path)
103 char line[256]={}, section[256]={};
104 char key[256]={}, val[256]={}, fullkey[256]={};
105 FILE *fd = fopen(path, "rt");
107 //printf("load_file: %s\n", path);
108 while (fgets(line, sizeof(line), fd)) {
109 /* Find special characters */
110 char *lbrace = strchr( line , '[');
111 char *rbrace = strchr((lbrace ?: line)+1, ']');
112 char *equal = strchr( line , '=');
113 char *lquote = strchr((equal ?: line)+1, '"');
114 char *rquote = strchr((lquote ?: line)+1, '"');
115 char *hash = strchr((rquote ?: line)+1, '#');
119 if (lbrace && rbrace) {
120 /* Check for secions */
121 memcpy(section, lbrace+1, rbrace-lbrace-1);
123 else if (section[0] && equal && lquote && rquote) {
124 /* Check for numbers/plain strings */
125 memcpy(key, line, equal-line);
126 memcpy(val, lquote+1, rquote-lquote-1);
127 snprintf(fullkey, sizeof(key), "%s.%s",
128 section, strtrim(key));
129 if (!strchr(fullkey, ' ')) {
130 conf_set_str(fullkey, val);
131 //printf(" [%s] = [%s]\n", fullkey, val);
134 else if (section[0] && equal) {
135 /* Check for strings */
136 memcpy(key, line, equal-line);
137 strcpy(val, equal+1);
138 snprintf(fullkey, sizeof(key), "%s.%s",
139 section, strtrim(key));
140 if (!strchr(fullkey, ' ')) {
141 char *end, *trim = strtrim(val);
142 int num = strtol(trim, &end, 10);
143 if (end != val && *end == '\0')
144 conf_set_int(fullkey, num);
145 else if (!strcasecmp(trim, "true"))
146 conf_set_int(fullkey, 1);
147 else if (!strcasecmp(trim, "false"))
148 conf_set_int(fullkey, 0);
150 conf_set_str(fullkey, trim);
151 //printf(" [%s] = [%s]\n", fullkey, trim);
158 /* Load config from command line options */
159 static struct option long_options[] = {
160 /* name hasarg flag val */
161 {"no-capture", 0, NULL, 'n'},
162 {"border", 2, NULL, 'b'},
163 {"margin", 2, NULL, 'm'},
164 {"int", 1, NULL, 'i'},
165 {"str", 1, NULL, 's'},
166 {"help", 0, NULL, 'h'},
170 static void usage(int argc, char **argv)
173 printf(" %s [OPTION...]\n", argv[0]);
175 printf("Options:\n");
176 printf(" -n, --no-capture Do not arrange pre existing windows\n");
177 printf(" -b, --border=n Draw an n pixel window border\n");
178 printf(" -m, --margin=n Leave an n pixel margin around windows\n");
179 printf(" -i, --int=key=num Set integer config option\n");
180 printf(" -s, --str=key=str Set string config option\n");
181 printf(" -h, --help Print usage information\n");
184 static void load_args(int argc, char **argv)
188 int c = getopt_long(argc, argv, "nb:m:i:s:h", long_options, NULL);
193 conf_set_int("main.no-capture", 1);
196 conf_set_int("main.border", str2num(optarg, 2));
199 conf_set_int("main.margin", str2num(optarg, 15));
203 key = strdup(optarg);
204 val = strchr(key, '=');
208 conf_set_str(key, val);
210 conf_set_int(key, atol(val));
225 /* Configuration file functions */
226 int conf_get_int(const char *key, int def)
228 entry_t *entry = conf_get(key);
229 return entry && entry->type == NUMBER
233 void conf_set_int(const char *key, int value)
235 conf_set(key, value, NULL);
238 const char *conf_get_str(const char *key, const char *def)
240 entry_t *entry = conf_get(key);
241 return entry && entry->type == STRING
245 void conf_set_str(const char *key, const char *value)
247 conf_set(key, 0, value);
250 void conf_reload(void)
252 load_file(conf_path);
253 load_args(conf_argc, conf_argv);
256 void conf_init(int argc, char **argv)
260 snprintf(conf_path, sizeof(conf_path), "%s/%s",
261 getenv("HOME") ?: getenv("HOMEPATH") ?: ".",