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