]> git.sur5r.net Git - i3/i3/blob - src/cfgparse.y
Merge branch 'lex' into next
[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         struct Assignment *assignment;
156 }
157
158 %token <number>NUMBER
159 %token <string>WORD
160 %token <string>STR
161 %token <string>STR_NG
162 %token <string>HEX
163 %token TOKBIND
164 %token TOKTERMINAL
165 %token TOKCOMMENT
166 %token TOKFONT
167 %token TOKBINDSYM
168 %token MODIFIER
169 %token TOKCONTROL
170 %token TOKSHIFT
171 %token WHITESPACE
172 %token TOKFLOATING_MODIFIER
173 %token QUOTEDSTRING
174 %token TOKWORKSPACE
175 %token TOKSCREEN
176 %token TOKASSIGN
177 %token TOKSET
178 %token TOKIPCSOCKET
179 %token TOKEXEC
180 %token TOKCOLOR
181 %token TOKARROW
182
183 %%
184
185 lines: /* empty */
186         | lines WHITESPACE line
187         | lines line
188         ;
189
190 line:
191         bind
192         | bindsym
193         | floating_modifier
194         | workspace
195         | assign
196         | ipcsocket
197         | exec
198         | color
199         | terminal
200         | font
201         | comment
202         ;
203
204 comment:
205         TOKCOMMENT
206         ;
207
208 command:
209         STR
210         ;
211
212 bind:
213         TOKBIND WHITESPACE binding_modifiers NUMBER WHITESPACE command
214         {
215                 printf("\tFound binding mod%d with key %d and command %s\n", $<number>3, $4, $<string>6);
216                 Binding *new = scalloc(sizeof(Binding));
217
218                 new->keycode = $<number>4;
219                 new->mods = $<number>3;
220                 new->command = sstrdup($<string>6);
221
222                 TAILQ_INSERT_TAIL(&bindings, new, bindings);
223         }
224         ;
225
226 bindsym:
227         TOKBINDSYM WHITESPACE binding_modifiers WORD WHITESPACE command
228         {
229                 printf("\tFound symbolic mod%d with key %s and command %s\n", $<number>3, $4, $<string>6);
230                 Binding *new = scalloc(sizeof(Binding));
231
232                 new->symbol = sstrdup($4);
233                 new->mods = $<number>3;
234                 new->command = sstrdup($<string>6);
235
236                 TAILQ_INSERT_TAIL(&bindings, new, bindings);
237         }
238         ;
239
240 floating_modifier:
241         TOKFLOATING_MODIFIER WHITESPACE binding_modifiers
242         {
243                 LOG("floating modifier = %d\n", $<number>3);
244                 config.floating_modifier = $<number>3;
245         }
246         ;
247
248 workspace:
249         TOKWORKSPACE WHITESPACE NUMBER WHITESPACE TOKSCREEN WHITESPACE screen workspace_name
250         {
251                 int ws_num = $<number>3;
252                 if (ws_num < 1 || ws_num > 10) {
253                         LOG("Invalid workspace assignment, workspace number %d out of range\n", ws_num);
254                 } else {
255                         workspaces[ws_num - 1].preferred_screen = sstrdup($<string>7);
256                         if ($<string>8 != NULL)
257                                 workspace_set_name(&(workspaces[ws_num - 1]), $<string>8);
258                 }
259         }
260         ;
261
262 workspace_name:
263         /* NULL */                      { $<string>$ = NULL; }
264         | WHITESPACE QUOTEDSTRING       { $<string>$ = $<string>2; }
265         | WHITESPACE STR                { $<string>$ = $<string>2; }
266         ;
267
268 screen:
269         NUMBER              { asprintf(&$<string>$, "%d", $<number>1); }
270         | NUMBER 'x'        { asprintf(&$<string>$, "%d", $<number>1); }
271         | NUMBER 'x' NUMBER { asprintf(&$<string>$, "%dx%d", $<number>1, $<number>3); }
272         | 'x' NUMBER        { asprintf(&$<string>$, "x%d", $<number>2); }
273         ;
274
275 assign:
276         TOKASSIGN WHITESPACE window_class WHITESPACE optional_arrow assign_target
277         {
278                 printf("assignment of %s to %d\n", $<string>3, $<number>6);
279
280                 struct Assignment *new = $<assignment>6;
281                 new->windowclass_title = strdup($<string>3);
282                 TAILQ_INSERT_TAIL(&assignments, new, assignments);
283         }
284         ;
285
286 assign_target:
287         NUMBER
288         {
289                 struct Assignment *new = scalloc(sizeof(struct Assignment));
290                 new->workspace = $<number>1;
291                 new->floating = ASSIGN_FLOATING_NO;
292                 $<assignment>$ = new;
293         }
294         | '~'
295         {
296                 struct Assignment *new = scalloc(sizeof(struct Assignment));
297                 new->floating = ASSIGN_FLOATING_ONLY;
298                 $<assignment>$ = new;
299         }
300         | '~' NUMBER
301         {
302                 struct Assignment *new = scalloc(sizeof(struct Assignment));
303                 new->workspace = $<number>2;
304                 new->floating = ASSIGN_FLOATING;
305                 $<assignment>$ = new;
306         }
307         ;
308
309 window_class:
310         QUOTEDSTRING
311         | STR_NG
312         ;
313
314 optional_arrow:
315         /* NULL */
316         | TOKARROW WHITESPACE
317         ;
318
319 ipcsocket:
320         TOKIPCSOCKET WHITESPACE STR
321         {
322                 config.ipc_socket_path = sstrdup($<string>3);
323         }
324         ;
325
326 exec:
327         TOKEXEC WHITESPACE STR
328         {
329                 struct Autostart *new = smalloc(sizeof(struct Autostart));
330                 new->command = sstrdup($<string>3);
331                 TAILQ_INSERT_TAIL(&autostarts, new, autostarts);
332         }
333         ;
334
335 terminal:
336         TOKTERMINAL WHITESPACE STR
337         {
338                 config.terminal = sstrdup($<string>3);
339                 printf("terminal %s\n", config.terminal);
340         }
341         ;
342
343 font:
344         TOKFONT WHITESPACE STR
345         {
346                 config.font = sstrdup($<string>3);
347                 printf("font %s\n", config.font);
348         }
349         ;
350
351
352 color:
353         TOKCOLOR WHITESPACE colorpixel WHITESPACE colorpixel WHITESPACE colorpixel
354         {
355                 struct Colortriple *dest = $<color>1;
356
357                 dest->border = $<number>3;
358                 dest->background = $<number>5;
359                 dest->text = $<number>7;
360         }
361         ;
362
363 colorpixel:
364         '#' HEX         { $<number>$ = get_colorpixel(global_conn, $<string>2); }
365         ;
366
367
368 binding_modifiers:
369         /* NULL */                               { $<number>$ = 0; }
370         | binding_modifier
371         | binding_modifiers '+' binding_modifier { $<number>$ = $<number>1 | $<number>3; }
372         | binding_modifiers '+'                  { $<number>$ = $<number>1; }
373         ;
374
375 binding_modifier:
376         MODIFIER        { $<number>$ = $<number>1; }
377         | TOKCONTROL    { $<number>$ = BIND_CONTROL; }
378         | TOKSHIFT      { $<number>$ = BIND_SHIFT; }
379         ;