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