92df05939f88dfa58d93cab0ec6bd714f5eb743a
[platform/upstream/kbd.git] / src / libkeymap / analyze.l
1 %{
2 #include <stdlib.h>
3 #include <unistd.h> /* readlink */
4
5 #include "ksyms.h"
6 #include "nls.h"
7 #include "kbd.h"
8 #include "paths.h"
9
10 #include "parser.h"
11 %}
12
13 %top {
14 #include "keymap.h"
15 int stack_push(struct keymap *kmap, lkfile_t *fp, void *scanner);
16 int stack_pop(struct keymap *kmap, void *scanner);
17 }
18
19 %option reentrant
20 %option bison-bridge
21 %option stack
22 %option never-interactive
23 %option noyywrap
24 %option nounput
25 %option noinput
26 %option noyy_top_state
27
28 %option extra-type="struct keymap *"
29
30 %{
31 int
32 stack_push(struct keymap *kmap, lkfile_t *fp, void *scanner)
33 {
34         int i = 0;
35
36         while (kmap->stack[i]) i++;
37
38         if (i == MAX_INCLUDE_DEPTH) {
39                 ERR(kmap, _("includes are nested too deeply"));
40                 return -1;
41         }
42
43         kmap->stack[i] = malloc(sizeof(lkfile_t));
44         if (kmap->stack[i] == NULL) {
45                 ERR(kmap, _("out of memory"));
46                 return -1;
47         }
48
49         kmap->stack[i]->fd   = fp->fd;
50         kmap->stack[i]->pipe = fp->pipe;
51         strncpy(kmap->stack[i]->pathname, fp->pathname, sizeof(kmap->stack[i]->pathname) - 1);
52         kmap->stack[i]->pathname[sizeof(kmap->stack[i]->pathname)] = '\0';
53
54         yypush_buffer_state(yy_create_buffer(fp->fd, YY_BUF_SIZE, scanner), scanner);
55         return 0;
56 }
57
58 int
59 stack_pop(struct keymap *kmap, void *scanner)
60 {
61         int i = 0;
62
63         while (kmap->stack[i]) i++;
64         if (i == 0)
65                 return 0;
66         i--;
67
68         lk_fpclose(kmap->stack[i]);
69
70         free(kmap->stack[i]);
71         kmap->stack[i] = NULL;
72
73         yypop_buffer_state(scanner);
74         return 0;
75 }
76
77 /*
78  * Where shall we look for an include file?
79  * Current strategy (undocumented, may change):
80  *
81  * 1. Look for a user-specified LOADKEYS_INCLUDE_PATH
82  * 2. Try . and ../include and ../../include
83  * 3. Try D and D/../include and D/../../include
84  *    where D is the directory from where we are loading the current file.
85  * 4. Try KD/include and KD/#/include where KD = DATADIR/KEYMAPDIR.
86  *
87  * Expected layout:
88  * KD has subdirectories amiga, atari, i386, mac, sun, include
89  * KD/include contains architecture-independent stuff
90  * like strings and iso-8859-x compose tables.
91  * KD/i386 has subdirectories qwerty, ... and include;
92  * this latter include dir contains stuff with keycode=...
93  *
94  * (Of course, if the present setup turns out to be reasonable,
95  * then later also the other architectures will grow and get
96  * subdirectories, and the hard-coded i386 below will go again.)
97  *
98  * People that dislike a dozen lookups for loadkeys
99  * can easily do "loadkeys file_with_includes; dumpkeys > my_keymap"
100  * and afterwards use only "loadkeys /fullpath/mykeymap", where no
101  * lookups are required.
102  */
103 static const char *const include_dirpath0[] = { "", 0 };
104 static const char *const include_dirpath1[] = { "", "../include/", "../../include/", 0 };
105 static const char *const include_dirpath3[] = {
106         DATADIR "/" KEYMAPDIR "/include/",
107         DATADIR "/" KEYMAPDIR "/i386/include/",
108         DATADIR "/" KEYMAPDIR "/mac/include/", 0
109 };
110
111 static const char *const include_suffixes[] = { "", ".inc", 0 };
112
113 static int
114 find_incl_file_near_fn(struct keymap *kmap, char *s, char *fn, lkfile_t *fp)
115 {
116         const char *include_dirpath2[] = { 0, 0, 0, 0 };
117         char *t, *te, *t1, *t2;
118         int len, rc = 1;
119
120         if (!fn)
121                 return 1;
122
123         t = strdup(fn);
124         if (t == NULL)
125                 goto nomem;
126
127         te = strrchr(t, '/');
128         if (te) {
129                 te[1] = 0;
130                 len = strlen(t);
131                 include_dirpath2[0] = t;
132                 include_dirpath2[1] = t1 = malloc(len + 12);
133                 include_dirpath2[2] = t2 = malloc(len + 15);
134
135                 if (t1 == NULL || t2 == NULL)
136                         goto nomem;
137
138                 strcpy(t1, t);
139                 strcat(t1, "../include/");
140                 strcpy(t2, t);
141                 strcat(t2, "../../include/");
142                 rc = lk_findfile(s, include_dirpath2, include_suffixes, fp);
143                 free(t1);
144                 free(t2);
145         }
146         free(t);
147         return rc;
148
149         /* FIXME: free */
150 nomem:  ERR(kmap, _("out of memory"));
151         return -1;
152 }
153
154 static int
155 find_standard_incl_file(struct keymap *kmap, char *s, lkfile_t *fp)
156 {
157         char *pathname;
158         int rc = 1;
159         int i = 0;
160
161         while (kmap->stack[i]) i++;
162         if (i == 0)
163                 return -1;
164         i--;
165         pathname = kmap->stack[i]->pathname;
166
167         if (lk_findfile(s, include_dirpath1, include_suffixes, fp)) {
168                 if ((rc = find_incl_file_near_fn(kmap, s, pathname, fp)) == -1)
169                         return rc;
170         }
171
172         /* If filename is a symlink, also look near its target. */
173         if (rc) {
174                 char buf[MAXPATHLEN], path[MAXPATHLEN], *ptr;
175                 unsigned int n;
176
177                 n = readlink(pathname, buf, sizeof(buf));
178                 if (n > 0 && n < sizeof(buf)) {
179                         buf[n] = 0;
180                         if (buf[0] == '/') {
181                                 rc = find_incl_file_near_fn(kmap, s, buf, fp);
182
183                         } else if (strlen(pathname) + n < sizeof(path)) {
184                                 strcpy(path, pathname);
185                                 path[sizeof(path) - 1] = 0;
186                                 ptr = strrchr(path, '/');
187                                 if (ptr)
188                                         ptr[1] = 0;
189                                 strcat(path, buf);
190                                 rc = find_incl_file_near_fn(kmap, s, path, fp);
191                         }
192                 }
193         }
194
195         if (rc)
196                 rc = lk_findfile(s, include_dirpath3, include_suffixes, fp);
197         return rc;
198 }
199
200 static int
201 find_incl_file(struct keymap *kmap, char *s, lkfile_t *fp)
202 {
203         char *ev;
204
205         if (!s || !*s)
206                 return 1;
207
208         if (*s == '/')          /* no path required */
209                 return (lk_findfile(s, include_dirpath0, include_suffixes, fp));
210
211         if ((ev = getenv("LOADKEYS_INCLUDE_PATH")) != NULL) {
212                 /* try user-specified path */
213                 const char *user_dir[2] = { 0, 0 };
214                 while (ev) {
215                         int rc;
216                         char *t = strchr(ev, ':');
217                         char sv = 0;
218                         if (t) {
219                                 sv = *t;
220                                 *t = 0;
221                         }
222                         user_dir[0] = ev;
223                         if (*ev)
224                                 rc = lk_findfile(s, user_dir, include_suffixes, fp);
225                         else    /* empty string denotes system path */
226                                 rc = find_standard_incl_file(kmap, s, fp);
227
228                         if (rc <= 0)
229                                 return rc;
230                         if (t)
231                                 *t++ = sv;
232                         ev = t;
233                 }
234                 return 1;
235         }
236         return find_standard_incl_file(kmap, s, fp);
237 }
238
239 static int
240 open_include(struct keymap *kmap, char *s, yyscan_t scanner)
241 {
242         int rc;
243         lkfile_t fp;
244
245         INFO(kmap, _("switching to %s"), s);
246
247         rc = find_incl_file(kmap, s, &fp);
248         if (rc > 0) {
249                 ERR(kmap, _("cannot open include file %s"), s);
250                 free(s);
251                 return -1;
252         } else if (rc == -1) {
253                 free(s);
254                 return -1;
255         }
256
257         free(s);
258
259         return stack_push(kmap, &fp, scanner);
260 }
261
262 %}
263 %s RVALUE
264 %x STR
265 %x INCLSTR
266 Comment                 #|!
267 Continuation            \\\n
268 Eol                     \n
269 Blank                   [ \t]
270 Include                 include[ \t]*
271 Decimal                 [1-9][0-9]*
272 Octal                   0[0-7]*
273 Hex                     0[xX][0-9a-fA-F]+
274 Unicode                 U\+([0-9a-fA-F]){4}
275 Literal                 [a-zA-Z][a-zA-Z_0-9]*
276 Octa                    ([0-7]){1,3}
277 Charset                 charset|Charset|CharSet|CHARSET
278 Keymaps                 keymaps|Keymaps|KeyMaps|KEYMAPS
279 Keycode                 keycode|Keycode|KeyCode|KEYCODE
280 String                  string|String|STRING
281 Equals                  =
282 Plain                   plain|Plain|PLAIN
283 Shift                   shift|Shift|SHIFT
284 Control                 control|Control|CONTROL
285 Alt                     alt|Alt|ALT
286 AltGr                   altgr|Altgr|AltGr|ALTGR
287 ShiftL                  shiftl|ShiftL|SHIFTL
288 ShiftR                  shiftr|ShiftR|SHIFTR
289 CtrlL                   ctrll|CtrlL|CTRLL
290 CtrlR                   ctrlr|CtrlR|CTRLR
291 CapsShift               capsshift|Capsshift|CapsShift|CAPSSHIFT
292 AltIsMeta               [aA][lL][tT][-_][iI][sS][-_][mM][eE][tT][aA]
293 Strings                 strings|Strings|STRINGS
294 Compose                 compose|Compose|COMPOSE
295 As                      as|As|AS
296 Usual                   usual|Usual|USUAL
297 For                     for|For|FOR
298 On                      on|On|ON
299 To                      to|To|TO
300
301 %%
302
303 {Include}               {
304                                 yy_push_state(INCLSTR, yyscanner);
305                                 yyextra->state_ptr++;
306                         }
307 <INCLSTR>\"[^\"\n]+\"   {
308                                 char *s = strndup(yytext+1, strlen(yytext)-2);
309                                 if (s == NULL) {
310                                         ERR(yyextra, _("out of memory"));
311                                         return(ERROR);
312                                 }
313
314                                 if (open_include(yyextra, s, yyscanner) == -1)
315                                         return(ERROR);
316
317                                 while (yyextra->state_ptr > 0) {
318                                         yy_pop_state(yyscanner);
319                                         yyextra->state_ptr--;
320                                 }
321                         }
322 <INCLSTR>[^"]|\"\"|\"[^"\n]*{Eol}       {
323                                 ERR(yyextra, _("expected filename between quotes"));
324                                 return(ERROR);
325                         }
326 <<EOF>>                 {
327                                 stack_pop(yyextra, yyscanner);
328                                 if (!YY_CURRENT_BUFFER)
329                                         yyterminate();
330                         }
331 {Continuation}          {
332                                 yyset_lineno(yyget_lineno(yyscanner) + 1, yyscanner);
333                         }
334 {Eol}                   {
335                                 yyset_lineno(yyget_lineno(yyscanner) + 1, yyscanner);
336
337                                 while (yyextra->state_ptr > 0) {
338                                         yy_pop_state(yyscanner);
339                                         yyextra->state_ptr--;
340                                 }
341                                 return(EOL);
342                         }
343 {Blank}+                ; /* do nothing */
344 {Comment}.*/{Eol}       ; /* do nothing */
345 {Equals}                {
346                                 yy_push_state(RVALUE, yyscanner);
347                                 yyextra->state_ptr++;
348                                 yyextra->rvalct = 0;
349                                 return(EQUALS);
350                         }
351 {String}                {
352                                 yy_push_state(RVALUE, yyscanner);
353                                 yyextra->state_ptr++;
354                                 return(STRING);
355                         }
356 {To}                    {
357                                 yy_push_state(RVALUE, yyscanner);
358                                 yyextra->state_ptr++;
359                                 return(TO);
360                         }
361 {Unicode}               {
362                                 yylval->num = strtol(yytext + 1, NULL, 16);
363                                 if (yylval->num >= 0xf000) {
364                                         ERR(yyextra, _("unicode keysym out of range: %s"),
365                                                 yytext);
366                                         return(ERROR);
367                                 }
368                                 return(UNUMBER);
369                         }
370 {Decimal}|{Octal}|{Hex} {
371                                 yylval->num = strtol(yytext, NULL, 0);
372                                 return(NUMBER);
373                         }
374 <RVALUE>{Literal}       {       return((yylval->num = ksymtocode(yyextra, yytext, TO_AUTO)) == -1 ? ERROR : LITERAL);   }
375 \-                      {       return(DASH);           }
376 \,                      {       return(COMMA);          }
377 \+                      {       return(PLUS);           }
378 {Charset}               {       return(CHARSET);        }
379 {Keymaps}               {       return(KEYMAPS);        }
380 {Keycode}               {       return(KEYCODE);        }
381 {Plain}                 {       return(PLAIN);          }
382 {Shift}                 {       return(SHIFT);          }
383 {Control}               {       return(CONTROL);        }
384 {Alt}                   {       return(ALT);            }
385 {AltGr}                 {       return(ALTGR);          }
386 {ShiftL}                {       return(SHIFTL);         }
387 {ShiftR}                {       return(SHIFTR);         }
388 {CtrlL}                 {       return(CTRLL);          }
389 {CtrlR}                 {       return(CTRLR);          }
390 {CapsShift}             {       return(CAPSSHIFT);      }
391 {AltIsMeta}             {       return(ALT_IS_META);    }
392 {Strings}               {       return(STRINGS);        }
393 {Compose}               {       return(COMPOSE);        }
394 {As}                    {       return(AS);             }
395 {Usual}                 {       return(USUAL);          }
396 {On}                    {       return(ON);             }
397 {For}                   {       return(FOR);            }
398 '\\{Octa}'              {
399                                 yylval->num = strtol(yytext + 2, NULL, 8);
400                                 return(CCHAR);
401                         }
402 '\\.'                   {
403                                 yylval->num = (unsigned char) yytext[2];
404                                 return(CCHAR);
405                         }
406 '.'                     {
407                                 yylval->num = (unsigned char) yytext[1];
408                                 return(CCHAR);
409                         }
410 \"                      {
411                                 yylval->str.data[0] = '\0';
412                                 yylval->str.len = 0;
413
414                                 yy_push_state(STR, yyscanner);
415                                 yyextra->state_ptr++;
416                         }
417 <STR>\\{Octa}           {
418                                 if (yylval->str.len == MAX_PARSER_STRING) {
419                                         ERR(yyextra, _("string too long"));
420                                         return(ERROR);
421                                 }
422                                 yylval->str.data[yylval->str.len++] = strtol(yytext + 1, NULL, 8);
423                         }
424 <STR>\\\"               {
425                                 if (yylval->str.len == MAX_PARSER_STRING) {
426                                         ERR(yyextra, _("string too long"));
427                                         return(ERROR);
428                                 }
429                                 yylval->str.data[yylval->str.len++] = '"';
430                         }
431 <STR>\\\\               {
432                                 if (yylval->str.len == MAX_PARSER_STRING) {
433                                         ERR(yyextra, _("string too long"));
434                                         return(ERROR);
435                                 }
436                                 yylval->str.data[yylval->str.len++] = '\\';
437                         }
438 <STR>\\n                {
439                                 if (yylval->str.len == MAX_PARSER_STRING) {
440                                         ERR(yyextra, _("string too long"));
441                                         return(ERROR);
442                                 }
443                                 yylval->str.data[yylval->str.len++] = '\n';
444                         }
445 <STR>[^\"\\]*           {
446                                 int len = strlen(yytext);
447
448                                 if (yylval->str.len + len >= MAX_PARSER_STRING) {
449                                         ERR(yyextra, _("string too long"));
450                                         return(ERROR);
451                                 }
452
453                                 strcpy((char *) yylval->str.data + yylval->str.len, yytext);
454                                 yylval->str.len += len;
455                         }
456 <STR>\"                 {
457                                 yylval->str.data[yylval->str.len] = '\0';
458                                 while (yyextra->state_ptr > 0) {
459                                         yy_pop_state(yyscanner);
460                                         yyextra->state_ptr--;
461                                 }
462                                 return(STRLITERAL);
463                         }
464 .                       {
465                                 return(ERROR);
466                         }
467 %%