]> git.sur5r.net Git - i3/i3/blob - src/cfgparse.y
parser: Implement parsing mode sections
[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                 printf("\t now in mode %s\n", $<string>3);
266                 printf("\t current bindings = %p\n", current_bindings);
267         }
268         ;
269
270 modelines:
271         /* empty */
272         | modelines WHITESPACE modeline
273         | modelines modeline
274         ;
275
276 modeline:
277         comment
278         | binding
279         {
280                 if (current_bindings == NULL) {
281                         current_bindings = scalloc(sizeof(struct bindings_head));
282                         TAILQ_INIT(current_bindings);
283                 }
284
285                 TAILQ_INSERT_TAIL(current_bindings, $<binding>1, bindings);
286         }
287         ;
288
289 floating_modifier:
290         TOKFLOATING_MODIFIER WHITESPACE binding_modifiers
291         {
292                 LOG("floating modifier = %d\n", $<number>3);
293                 config.floating_modifier = $<number>3;
294         }
295         ;
296
297 workspace:
298         TOKWORKSPACE WHITESPACE NUMBER WHITESPACE TOKSCREEN WHITESPACE screen workspace_name
299         {
300                 int ws_num = $<number>3;
301                 if (ws_num < 1 || ws_num > 10) {
302                         LOG("Invalid workspace assignment, workspace number %d out of range\n", ws_num);
303                 } else {
304                         workspaces[ws_num - 1].preferred_screen = sstrdup($<string>7);
305                         if ($<string>8 != NULL)
306                                 workspace_set_name(&(workspaces[ws_num - 1]), $<string>8);
307                 }
308         }
309         | TOKWORKSPACE WHITESPACE NUMBER workspace_name
310         {
311                 int ws_num = $<number>3;
312                 if (ws_num < 1 || ws_num > 10) {
313                         LOG("Invalid workspace assignment, workspace number %d out of range\n", ws_num);
314                 } else {
315                         if ($<string>4 != NULL)
316                                         workspace_set_name(&(workspaces[ws_num - 1]), $<string>4);
317                 }
318         }
319         ;
320
321 workspace_name:
322         /* NULL */                      { $<string>$ = NULL; }
323         | WHITESPACE QUOTEDSTRING       { $<string>$ = $<string>2; }
324         | WHITESPACE STR                { $<string>$ = $<string>2; }
325         ;
326
327 screen:
328         NUMBER              { asprintf(&$<string>$, "%d", $<number>1); }
329         | NUMBER 'x'        { asprintf(&$<string>$, "%d", $<number>1); }
330         | NUMBER 'x' NUMBER { asprintf(&$<string>$, "%dx%d", $<number>1, $<number>3); }
331         | 'x' NUMBER        { asprintf(&$<string>$, "x%d", $<number>2); }
332         ;
333
334 assign:
335         TOKASSIGN WHITESPACE window_class WHITESPACE optional_arrow assign_target
336         {
337                 printf("assignment of %s to %d\n", $<string>3, $<number>6);
338
339                 struct Assignment *new = $<assignment>6;
340                 new->windowclass_title = strdup($<string>3);
341                 TAILQ_INSERT_TAIL(&assignments, new, assignments);
342         }
343         ;
344
345 assign_target:
346         NUMBER
347         {
348                 struct Assignment *new = scalloc(sizeof(struct Assignment));
349                 new->workspace = $<number>1;
350                 new->floating = ASSIGN_FLOATING_NO;
351                 $<assignment>$ = new;
352         }
353         | '~'
354         {
355                 struct Assignment *new = scalloc(sizeof(struct Assignment));
356                 new->floating = ASSIGN_FLOATING_ONLY;
357                 $<assignment>$ = new;
358         }
359         | '~' NUMBER
360         {
361                 struct Assignment *new = scalloc(sizeof(struct Assignment));
362                 new->workspace = $<number>2;
363                 new->floating = ASSIGN_FLOATING;
364                 $<assignment>$ = new;
365         }
366         ;
367
368 window_class:
369         QUOTEDSTRING
370         | STR_NG
371         ;
372
373 optional_arrow:
374         /* NULL */
375         | TOKARROW WHITESPACE
376         ;
377
378 ipcsocket:
379         TOKIPCSOCKET WHITESPACE STR
380         {
381                 config.ipc_socket_path = sstrdup($<string>3);
382         }
383         ;
384
385 exec:
386         TOKEXEC WHITESPACE STR
387         {
388                 struct Autostart *new = smalloc(sizeof(struct Autostart));
389                 new->command = sstrdup($<string>3);
390                 TAILQ_INSERT_TAIL(&autostarts, new, autostarts);
391         }
392         ;
393
394 terminal:
395         TOKTERMINAL WHITESPACE STR
396         {
397                 config.terminal = sstrdup($<string>3);
398                 printf("terminal %s\n", config.terminal);
399         }
400         ;
401
402 font:
403         TOKFONT WHITESPACE STR
404         {
405                 config.font = sstrdup($<string>3);
406                 printf("font %s\n", config.font);
407         }
408         ;
409
410
411 color:
412         TOKCOLOR WHITESPACE colorpixel WHITESPACE colorpixel WHITESPACE colorpixel
413         {
414                 struct Colortriple *dest = $<color>1;
415
416                 dest->border = $<number>3;
417                 dest->background = $<number>5;
418                 dest->text = $<number>7;
419         }
420         ;
421
422 colorpixel:
423         '#' HEX         { $<number>$ = get_colorpixel(global_conn, $<string>2); }
424         ;
425
426
427 binding_modifiers:
428         /* NULL */                               { $<number>$ = 0; }
429         | binding_modifier
430         | binding_modifiers '+' binding_modifier { $<number>$ = $<number>1 | $<number>3; }
431         | binding_modifiers '+'                  { $<number>$ = $<number>1; }
432         ;
433
434 binding_modifier:
435         MODIFIER        { $<number>$ = $<number>1; }
436         | TOKCONTROL    { $<number>$ = BIND_CONTROL; }
437         | TOKSHIFT      { $<number>$ = BIND_SHIFT; }
438         ;