]> git.sur5r.net Git - i3/i3status/blob - config.c
Make everything configurable
[i3/i3status] / config.c
1 #include <stdio.h>
2 #include <ctype.h>
3 #include <string.h>
4 #include <stdlib.h>
5 #include <stdbool.h>
6 #include <sys/stat.h>
7 #include <sys/types.h>
8 #include <fcntl.h>
9 #include <glob.h>
10 #include <unistd.h>
11
12 #define _IS_CONFIG_C
13 #include "config.h"
14 #undef _IS_CONFIG_C
15
16 const char *wlan_interface;
17 const char *eth_interface;
18 const char *wmii_path;
19 const char *time_format;
20 const char *battery_path;
21 bool use_colors;
22 const char *wmii_normcolors;
23 char order[MAX_ORDER][2];
24 const char **run_watches;
25 unsigned int num_run_watches;
26
27 void die(const char *fmt, ...);
28
29 /*
30  * This function exists primarily for resolving ~ in pathnames. However, you
31  * can also specify ~/Movies/ *, which will only return the first match!
32  *
33  */
34 char *glob_path(const char *path) {
35         static glob_t globbuf;
36         if (glob(path, GLOB_NOCHECK | GLOB_TILDE, NULL, &globbuf) < 0)
37                 die("glob() failed");
38         char *result = strdup(globbuf.gl_pathc > 0 ? globbuf.gl_pathv[0] : path);
39         globfree(&globbuf);
40         return result;
41 }
42
43 /*
44  * Loads configuration from configfile
45  *
46  */
47 static void get_next_config_entry(FILE *handle, char **dest_name, char **dest_value, char *whole_buffer, int whole_buffer_size) {
48         char *ret;
49         if ((ret = fgets(whole_buffer, whole_buffer_size, handle)) == whole_buffer) {
50                 char *c = whole_buffer;
51                 /* Skip whitespaces in the beginning */
52                 while (isspace((int)*c) && *c != '\0')
53                         c++;
54                 *dest_name = c;
55                 while (!isspace((int)*c))
56                         c++;
57                 /* Terminate string as soon as whitespaces begin or it's terminated anyway */
58                 *(c++) = '\0';
59
60                 /* Same for the value: strip whitespaces */
61                 while (isspace((int)*c) && *c != '\0')
62                         c++;
63                 *dest_value = c;
64                 /* Whitespace is allowed, newline/carriage return is not */
65                 while ((*c != '\n') && (*c != '\r') && (*c != '\0'))
66                         c++;
67                 *c = 0;
68         } else if (ret != NULL)
69                 die("Could not read line in configuration file");
70 }
71
72 /*
73  * Reads the configuration from the given file
74  *
75  */
76 int load_configuration(const char *configfile) {
77         #define OPT(x) else if (strcasecmp(dest_name, x) == 0)
78
79         /* Check if the file exists */
80         struct stat buf;
81         if (stat(configfile, &buf) < 0)
82                 return -1;
83
84         int result = 0;
85         FILE *handle = fopen(configfile, "r");
86         if (handle == NULL)
87                 die("Could not open configfile");
88         char *dest_name = NULL, *dest_value = NULL, whole_buffer[1026];
89         struct stat stbuf;
90         while (!feof(handle)) {
91                 get_next_config_entry(handle, &dest_name, &dest_value, whole_buffer, 1024);
92                 /* No more entries? We're done! */
93                 if (dest_name == NULL)
94                         break;
95                 /* Skip comments and empty lines */
96                 if (dest_name[0] == '#' || strlen(dest_name) < 3)
97                         continue;
98
99                 OPT("wlan")
100                 {
101                         wlan_interface = strdup(dest_value);
102                 }
103                 OPT("eth")
104                 {
105                         eth_interface = strdup(dest_value);
106                 }
107                 OPT("wmii_path")
108                 {
109                         char *globbed = glob_path(dest_value);
110                         if ((stat(globbed, &stbuf)) == -1)
111                                 die("wmii_path contains an invalid path");
112                         if (globbed[strlen(globbed)-1] != '/')
113                                 die("wmii_path is not terminated by /");
114                         wmii_path = globbed;
115                 }
116                 OPT("time_format")
117                 {
118                         time_format = strdup(dest_value);
119                 }
120                 OPT("battery_path")
121                 {
122                         if ((stat(dest_value, &stbuf)) == -1)
123                                 die("battery_path contains an invalid path");
124                         battery_path = strdup(dest_value);
125                 }
126                 OPT("run_watch")
127                 {
128                         char *name = strdup(dest_value);
129                         char *path = name;
130                         while (*path != ' ')
131                                 path++;
132                         *(path++) = '\0';
133                         num_run_watches += 2;
134                         run_watches = realloc(run_watches, sizeof(char*) * num_run_watches);
135                         run_watches[num_run_watches-2] = name;
136                         run_watches[num_run_watches-1] = path;
137                 }
138                 OPT("order")
139                 {
140                         #define SET_ORDER(opt, idx) { if (strcasecmp(token, opt) == 0) sprintf(order[idx], "%d", c++); }
141                         char *walk, *token;
142                         int c = 0;
143                         walk = token = dest_value;
144                         while (*walk != '\0') {
145                                 while ((*walk != ',') && (*walk != '\0'))
146                                         walk++;
147                                 *(walk++) = '\0';
148                                 SET_ORDER("run", ORDER_RUN);
149                                 SET_ORDER("wlan", ORDER_WLAN);
150                                 SET_ORDER("eth", ORDER_ETH);
151                                 SET_ORDER("battery", ORDER_BATTERY);
152                                 SET_ORDER("load", ORDER_LOAD);
153                                 SET_ORDER("time", ORDER_TIME);
154                                 token = walk;
155                         }
156                 }
157                 OPT("color")
158                 {
159                         use_colors = true;
160                 }
161                 OPT("normcolors")
162                 {
163                         wmii_normcolors = strdup(dest_value);
164                 }
165                 else
166                 {
167                         result = -2;
168                         die("Unknown configfile option: %s\n", dest_name);
169                 }
170                 dest_name = dest_value = NULL;
171         }
172         fclose(handle);
173
174         if (wmii_path == NULL)
175                 die("No wmii_path specified in configuration file");
176
177         return result;
178 }