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