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
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);
77 //printf("set_str: %s = %s\n", key, str);
81 //printf("set_num: %s = %d\n", key, num);
83 tsearch(entry, &conf, conf_cmp);
86 static char *strtrim(char *str)
88 while (*str == ' ' || *str == '\t' || *str == '\n')
90 char *end = strchr(str, '\0');
91 while (end > str && (*end == ' ' || *end == '\t' ||
92 *end == '\n' || *end == '\0'))
97 /* Read an ini file into the configuration
98 * - this does not properly handle excape sequences
99 * - could probably make this into a real parser.. */
100 static void load_file(const char *path)
102 char line[256]={}, section[256]={};
103 char key[256]={}, val[256]={}, fullkey[256]={};
104 FILE *fd = fopen(path, "rt");
106 //printf("load_file: %s\n", path);
107 while (fgets(line, sizeof(line), fd)) {
108 /* Find special characters */
109 char *lbrace = strchr( line , '[');
110 char *rbrace = strchr((lbrace ?: line)+1, ']');
111 char *equal = strchr( line , '=');
112 char *lquote = strchr((equal ?: line)+1, '"');
113 char *rquote = strchr((lquote ?: line)+1, '"');
114 char *hash = strchr((rquote ?: line)+1, '#');
118 if (lbrace && rbrace) {
119 /* Check for secions */
120 memcpy(section, lbrace+1, rbrace-lbrace-1);
122 else if (section[0] && equal && lquote && rquote) {
123 /* Check for numbers/plain strings */
124 memcpy(key, line, equal-line);
125 memcpy(val, lquote+1, rquote-lquote-1);
126 snprintf(fullkey, sizeof(key), "%s.%s",
127 section, strtrim(key));
128 if (!strchr(fullkey, ' ')) {
129 conf_set_str(fullkey, val);
130 //printf(" [%s] = [%s]\n", fullkey, val);
133 else if (section[0] && equal) {
134 /* Check for strings */
135 memcpy(key, line, equal-line);
136 strcpy(val, equal+1);
137 snprintf(fullkey, sizeof(key), "%s.%s",
138 section, strtrim(key));
139 if (!strchr(fullkey, ' ')) {
140 char *end, *trim = strtrim(val);
141 int num = strtol(trim, &end, 10);
142 if (end != val && *end == '\0')
143 conf_set_int(fullkey, num);
144 else if (!strcasecmp(trim, "true"))
145 conf_set_int(fullkey, 1);
146 else if (!strcasecmp(trim, "false"))
147 conf_set_int(fullkey, 0);
149 conf_set_str(fullkey, trim);
150 //printf(" [%s] = [%s]\n", fullkey, trim);
157 /* Load config from command line options */
158 static struct option long_options[] = {
159 /* name hasarg flag val */
160 {"no-capture", 0, NULL, 'n'},
161 {"border", 2, NULL, 'b'},
162 {"margin", 2, NULL, 'm'},
163 {"int", 1, NULL, 'i'},
164 {"str", 1, NULL, 's'},
165 {"help", 0, NULL, 'h'},
169 static void usage(int argc, char **argv)
172 printf(" %s [OPTION...]\n", argv[0]);
174 printf("Options:\n");
175 printf(" -n, --no-capture Do not arrange pre existing windows\n");
176 printf(" -b, --border=n Draw an n pixel window border\n");
177 printf(" -m, --margin=n Leave an n pixel margin around windows\n");
178 printf(" -i, --int=key=num Set integer config option\n");
179 printf(" -s, --str=key=str Set string config option\n");
180 printf(" -h, --help Print usage information\n");
183 static void load_args(int argc, char **argv)
187 int c = getopt_long(argc, argv, "nb:m:i:s:h", long_options, NULL);
192 conf_set_int("main.no-capture", 1);
195 conf_set_int("main.border", str2num(optarg, 2));
198 conf_set_int("main.margin", str2num(optarg, 15));
202 key = strdup(optarg);
203 val = strchr(key, '=');
207 conf_set_str(key, val);
209 conf_set_int(key, atol(val));
224 /* Configuration file functions */
225 int conf_get_int(const char *key, int def)
227 entry_t *entry = conf_get(key);
228 return entry && entry->type == NUMBER
232 void conf_set_int(const char *key, int value)
234 conf_set(key, value, NULL);
237 const char *conf_get_str(const char *key, const char *def)
239 entry_t *entry = conf_get(key);
240 return entry && entry->type == STRING
244 void conf_set_str(const char *key, const char *value)
246 conf_set(key, 0, value);
249 void conf_reload(void)
251 load_file(conf_path);
252 load_args(conf_argc, conf_argv);
255 void conf_init(int argc, char **argv)
259 snprintf(conf_path, sizeof(conf_path), "%s/%s",
260 getenv("HOME") ?: getenv("HOMEPATH") ?: ".",