]> git.sur5r.net Git - i3/i3/blob - src/cfgparse.y
f3c552f9ddbb270f8f3246d67ca9340b1550df37
[i3/i3] / src / cfgparse.y
1 %{
2 #include <stdio.h>
3 #include <string.h>
4 #include <xcb/xcb.h>
5 #include <sys/types.h>
6 #include <sys/stat.h>
7 #include <unistd.h>
8 #include <fcntl.h>
9 #include <stdlib.h>
10 #include <errno.h>
11
12 #include "data.h"
13 #include "config.h"
14 #include "i3.h"
15 #include "util.h"
16 #include "queue.h"
17 #include "table.h"
18
19 extern int yylex(void);
20 extern FILE *yyin;
21
22 int yydebug = 1;
23
24 void yyerror(const char *str) {
25         fprintf(stderr,"error: %s\n",str);
26 }
27
28 int yywrap() {
29         return 1;
30 }
31
32 void parse_file(const char *f) {
33         SLIST_HEAD(variables_head, Variable) variables = SLIST_HEAD_INITIALIZER(&variables);
34         int fd, ret, read_bytes = 0;
35         struct stat stbuf;
36         char *buf;
37         FILE *fstr;
38         char buffer[1026], key[512], value[512];
39
40         if ((fd = open(f, O_RDONLY)) == -1)
41                 die("Could not open configuration file: %s\n", strerror(errno));
42
43         if (fstat(fd, &stbuf) == -1)
44                 die("Could not fstat file: %s\n", strerror(errno));
45
46         buf = smalloc(stbuf.st_size * sizeof(char));
47         while (read_bytes < stbuf.st_size) {
48                 if ((ret = read(fd, buf + read_bytes, (stbuf.st_size - read_bytes))) < 0)
49                         die("Could not read(): %s\n", strerror(errno));
50                 read_bytes += ret;
51         }
52
53         if (lseek(fd, 0, SEEK_SET) == (off_t)-1)
54                 die("Could not lseek: %s\n", strerror(errno));
55
56         if ((fstr = fdopen(fd, "r")) == NULL)
57                 die("Could not fdopen: %s\n", strerror(errno));
58
59         while (!feof(fstr)) {
60                 if (fgets(buffer, 1024, fstr) == NULL) {
61                         if (feof(fstr))
62                                 break;
63                         die("Could not read configuration file\n");
64                 }
65
66                 /* sscanf implicitly strips whitespace. Also, we skip comments and empty lines. */
67                 if (sscanf(buffer, "%s %[^\n]", key, value) < 1 ||
68                     key[0] == '#' || strlen(key) < 3)
69                         continue;
70
71                 if (strcasecmp(key, "set") == 0) {
72                         if (value[0] != '$')
73                                 die("Malformed variable assignment, name has to start with $\n");
74
75                         /* get key/value for this variable */
76                         char *v_key = value, *v_value;
77                         if ((v_value = strstr(value, " ")) == NULL)
78                                 die("Malformed variable assignment, need a value\n");
79
80                         *(v_value++) = '\0';
81
82                         struct Variable *new = scalloc(sizeof(struct Variable));
83                         new->key = sstrdup(v_key);
84                         new->value = sstrdup(v_value);
85                         SLIST_INSERT_HEAD(&variables, new, variables);
86                         LOG("Got new variable %s = %s\n", v_key, v_value);
87                         continue;
88                 }
89         }
90
91         /* For every custom variable, see how often it occurs in the file and
92          * how much extra bytes it requires when replaced. */
93         struct Variable *current, *nearest;
94         int extra_bytes = 0;
95         SLIST_FOREACH(current, &variables, variables) {
96                 int extra = (strlen(current->value) - strlen(current->key));
97                 char *next;
98                 for (next = buf;
99                      (next = strcasestr(buf + (next - buf), current->key)) != NULL;
100                      next += strlen(current->key))
101                         extra_bytes += extra;
102         }
103
104         /* Then, allocate a new buffer and copy the file over to the new one,
105          * but replace occurences of our variables */
106         char *walk = buf, *destwalk;
107         char *new = smalloc((stbuf.st_size + extra_bytes) * sizeof(char));
108         destwalk = new;
109         while (walk < (buf + stbuf.st_size)) {
110                 /* Find the next variable */
111                 SLIST_FOREACH(current, &variables, variables)
112                         current->next_match = strcasestr(walk, current->key);
113                 nearest = NULL;
114                 int distance = stbuf.st_size;
115                 SLIST_FOREACH(current, &variables, variables) {
116                         if (current->next_match == NULL)
117                                 continue;
118                         if ((current->next_match - walk) < distance) {
119                                 distance = (current->next_match - walk);
120                                 nearest = current;
121                         }
122                 }
123                 if (nearest == NULL) {
124                         /* If there are no more variables, we just copy the rest */
125                         strncpy(destwalk, walk, (buf + stbuf.st_size) - walk);
126                         destwalk += (buf + stbuf.st_size) - walk;
127                         *destwalk = '\0';
128                         break;
129                 } else {
130                         /* Copy until the next variable, then copy its value */
131                         strncpy(destwalk, walk, distance);
132                         strncpy(destwalk + distance, nearest->value, strlen(nearest->value));
133                         walk += distance + strlen(nearest->key);
134                         destwalk += distance + strlen(nearest->value);
135                 }
136         }
137
138         yy_scan_string(new);
139
140         if (yyparse() != 0) {
141                 fprintf(stderr, "Could not parse configfile\n");
142                 exit(1);
143         }
144
145         free(new);
146         free(buf);
147 }
148
149 %}
150
151 %union {
152         int number;
153         char *string;
154         struct Colortriple *color;
155 }
156
157 %token <number>NUMBER
158 %token <string>WORD
159 %token <string>STR
160 %token <string>STR_NG
161 %token <string>HEX
162 %token TOKBIND
163 %token TOKTERMINAL
164 %token TOKCOMMENT
165 %token TOKFONT
166 %token TOKBINDSYM
167 %token MODIFIER
168 %token TOKCONTROL
169 %token TOKSHIFT
170 %token WHITESPACE
171 %token TOKFLOATING_MODIFIER
172 %token QUOTEDSTRING
173 %token TOKWORKSPACE
174 %token TOKSCREEN
175 %token TOKASSIGN
176 %token TOKSET
177 %token TOKIPCSOCKET
178 %token TOKEXEC
179 %token TOKCOLOR
180 %token TOKARROW
181
182 %%
183
184 lines: /* empty */
185         | lines WHITESPACE line
186         | lines line
187         ;
188
189 line:
190         bind
191         | bindsym
192         | floating_modifier
193         | workspace
194         | assign
195         | ipcsocket
196         | exec
197         | color
198         | terminal
199         | font
200         | comment
201         ;
202
203 comment:
204         TOKCOMMENT
205         ;
206
207 command:
208         STR
209         ;
210
211 bind:
212         TOKBIND WHITESPACE binding_modifiers NUMBER WHITESPACE command
213         {
214                 printf("\tFound binding mod%d with key %d and command %s\n", $<number>3, $4, $<string>6);
215                 Binding *new = scalloc(sizeof(Binding));
216
217                 new->keycode = $<number>4;
218                 new->mods = $<number>3;
219                 new->command = sstrdup($<string>6);
220
221                 TAILQ_INSERT_TAIL(&bindings, new, bindings);
222         }
223         ;
224
225 bindsym:
226         TOKBINDSYM WHITESPACE binding_modifiers WORD WHITESPACE command
227         {
228                 printf("\tFound symbolic mod%d with key %s and command %s\n", $<number>3, $4, $<string>6);
229                 Binding *new = scalloc(sizeof(Binding));
230
231                 new->symbol = sstrdup($4);
232                 new->mods = $<number>3;
233                 new->command = sstrdup($<string>6);
234
235                 TAILQ_INSERT_TAIL(&bindings, new, bindings);
236         }
237         ;
238
239 floating_modifier:
240         TOKFLOATING_MODIFIER WHITESPACE binding_modifiers
241         {
242                 LOG("floating modifier = %d\n", $<number>3);
243                 config.floating_modifier = $<number>3;
244         }
245         ;
246
247 workspace:
248         TOKWORKSPACE WHITESPACE NUMBER WHITESPACE TOKSCREEN WHITESPACE screen workspace_name
249         {
250                 int ws_num = $<number>3;
251                 if (ws_num < 1 || ws_num > 10) {
252                         LOG("Invalid workspace assignment, workspace number %d out of range\n", ws_num);
253                 } else {
254                         workspaces[ws_num - 1].preferred_screen = sstrdup($<string>7);
255                         if ($<string>8 != NULL)
256                                 workspace_set_name(&(workspaces[ws_num - 1]), $<string>8);
257                 }
258         }
259         ;
260
261 workspace_name:
262         /* NULL */                      { $<string>$ = NULL; }
263         | WHITESPACE QUOTEDSTRING       { $<string>$ = $<string>2; }
264         | WHITESPACE STR                { $<string>$ = $<string>2; }
265         ;
266
267 screen:
268         NUMBER              { asprintf(&$<string>$, "%d", $<number>1); }
269         | NUMBER 'x'        { asprintf(&$<string>$, "%d", $<number>1); }
270         | NUMBER 'x' NUMBER { asprintf(&$<string>$, "%dx%d", $<number>1, $<number>3); }
271         | 'x' NUMBER        { asprintf(&$<string>$, "x%d", $<number>2); }
272         ;
273
274 assign:
275         TOKASSIGN WHITESPACE window_class WHITESPACE optional_arrow NUMBER
276         {
277                 /* TODO */
278                 printf("assignment of %s to %d\n", $<string>3, $<number>6);
279         }
280         ;
281
282 window_class:
283         QUOTEDSTRING
284         | STR_NG
285         ;
286
287 optional_arrow:
288         /* NULL */
289         | TOKARROW WHITESPACE
290         ;
291
292 ipcsocket:
293         TOKIPCSOCKET WHITESPACE STR
294         {
295                 config.ipc_socket_path = sstrdup($<string>3);
296         }
297         ;
298
299 exec:
300         TOKEXEC WHITESPACE STR
301         {
302                 struct Autostart *new = smalloc(sizeof(struct Autostart));
303                 new->command = sstrdup($<string>3);
304                 TAILQ_INSERT_TAIL(&autostarts, new, autostarts);
305         }
306         ;
307
308 terminal:
309         TOKTERMINAL WHITESPACE STR
310         {
311                 config.terminal = sstrdup($<string>3);
312                 printf("terminal %s\n", config.terminal);
313         }
314         ;
315
316 font:
317         TOKFONT WHITESPACE STR
318         {
319                 config.font = sstrdup($<string>3);
320                 printf("font %s\n", config.font);
321         }
322         ;
323
324
325 color:
326         TOKCOLOR WHITESPACE colorpixel WHITESPACE colorpixel WHITESPACE colorpixel
327         {
328                 struct Colortriple *dest = $<color>1;
329
330                 dest->border = $<number>3;
331                 dest->background = $<number>5;
332                 dest->text = $<number>7;
333         }
334         ;
335
336 colorpixel:
337         '#' HEX         { $<number>$ = get_colorpixel(global_conn, $<string>2); }
338         ;
339
340
341 binding_modifiers:
342         /* NULL */                               { $<number>$ = 0; }
343         | binding_modifier
344         | binding_modifiers '+' binding_modifier { $<number>$ = $<number>1 | $<number>3; }
345         | binding_modifiers '+'                  { $<number>$ = $<number>1; }
346         ;
347
348 binding_modifier:
349         MODIFIER        { $<number>$ = $<number>1; }
350         | TOKCONTROL    { $<number>$ = BIND_CONTROL; }
351         | TOKSHIFT      { $<number>$ = BIND_SHIFT; }
352         ;