3 #include <unistd.h> /* readlink */
15 int stack_push(struct keymap *kmap, lkfile_t *fp, void *scanner);
16 int stack_pop(struct keymap *kmap, void *scanner);
22 %option never-interactive
26 %option noyy_top_state
28 %option extra-type="struct keymap *"
32 stack_push(struct keymap *kmap, lkfile_t *fp, void *scanner)
36 while (kmap->stack[i]) i++;
38 if (i == MAX_INCLUDE_DEPTH) {
39 ERR(kmap, _("includes are nested too deeply"));
43 kmap->stack[i] = malloc(sizeof(lkfile_t));
44 if (kmap->stack[i] == NULL) {
45 ERR(kmap, _("out of memory"));
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';
54 yypush_buffer_state(yy_create_buffer(fp->fd, YY_BUF_SIZE, scanner), scanner);
59 stack_pop(struct keymap *kmap, void *scanner)
63 while (kmap->stack[i]) i++;
68 lk_fpclose(kmap->stack[i]);
71 kmap->stack[i] = NULL;
73 yypop_buffer_state(scanner);
78 * Where shall we look for an include file?
79 * Current strategy (undocumented, may change):
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.
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=...
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.)
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.
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
111 static const char *const include_suffixes[] = { "", ".inc", 0 };
114 find_incl_file_near_fn(struct keymap *kmap, char *s, char *fn, lkfile_t *fp)
116 const char *include_dirpath2[] = { 0, 0, 0, 0 };
117 char *t, *te, *t1, *t2;
127 te = strrchr(t, '/');
131 include_dirpath2[0] = t;
132 include_dirpath2[1] = t1 = malloc(len + 12);
133 include_dirpath2[2] = t2 = malloc(len + 15);
135 if (t1 == NULL || t2 == NULL)
139 strcat(t1, "../include/");
141 strcat(t2, "../../include/");
142 rc = lk_findfile(s, include_dirpath2, include_suffixes, fp);
150 nomem: ERR(kmap, _("out of memory"));
155 find_standard_incl_file(struct keymap *kmap, char *s, lkfile_t *fp)
161 while (kmap->stack[i]) i++;
165 pathname = kmap->stack[i]->pathname;
167 if (lk_findfile(s, include_dirpath1, include_suffixes, fp)) {
168 if ((rc = find_incl_file_near_fn(kmap, s, pathname, fp)) == -1)
172 /* If filename is a symlink, also look near its target. */
174 char buf[MAXPATHLEN], path[MAXPATHLEN], *ptr;
177 n = readlink(pathname, buf, sizeof(buf));
178 if (n > 0 && n < sizeof(buf)) {
181 rc = find_incl_file_near_fn(kmap, s, buf, fp);
183 } else if (strlen(pathname) + n < sizeof(path)) {
184 strcpy(path, pathname);
185 path[sizeof(path) - 1] = 0;
186 ptr = strrchr(path, '/');
190 rc = find_incl_file_near_fn(kmap, s, path, fp);
196 rc = lk_findfile(s, include_dirpath3, include_suffixes, fp);
201 find_incl_file(struct keymap *kmap, char *s, lkfile_t *fp)
208 if (*s == '/') /* no path required */
209 return (lk_findfile(s, include_dirpath0, include_suffixes, fp));
211 if ((ev = getenv("LOADKEYS_INCLUDE_PATH")) != NULL) {
212 /* try user-specified path */
213 const char *user_dir[2] = { 0, 0 };
216 char *t = strchr(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);
236 return find_standard_incl_file(kmap, s, fp);
240 open_include(struct keymap *kmap, char *s, yyscan_t scanner)
245 INFO(kmap, _("switching to %s"), s);
247 rc = find_incl_file(kmap, s, &fp);
249 ERR(kmap, _("cannot open include file %s"), s);
252 } else if (rc == -1) {
259 return stack_push(kmap, &fp, scanner);
270 Include include[ \t]*
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]*
277 Charset charset|Charset|CharSet|CHARSET
278 Keymaps keymaps|Keymaps|KeyMaps|KEYMAPS
279 Keycode keycode|Keycode|KeyCode|KEYCODE
280 String string|String|STRING
282 Plain plain|Plain|PLAIN
283 Shift shift|Shift|SHIFT
284 Control control|Control|CONTROL
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
296 Usual usual|Usual|USUAL
304 yy_push_state(INCLSTR, yyscanner);
305 yyextra->state_ptr++;
307 <INCLSTR>\"[^\"\n]+\" {
308 char *s = strndup(yytext+1, strlen(yytext)-2);
310 ERR(yyextra, _("out of memory"));
314 if (open_include(yyextra, s, yyscanner) == -1)
317 while (yyextra->state_ptr > 0) {
318 yy_pop_state(yyscanner);
319 yyextra->state_ptr--;
322 <INCLSTR>[^"]|\"\"|\"[^"\n]*{Eol} {
323 ERR(yyextra, _("expected filename between quotes"));
327 stack_pop(yyextra, yyscanner);
328 if (!YY_CURRENT_BUFFER)
332 yyset_lineno(yyget_lineno(yyscanner) + 1, yyscanner);
335 yyset_lineno(yyget_lineno(yyscanner) + 1, yyscanner);
337 while (yyextra->state_ptr > 0) {
338 yy_pop_state(yyscanner);
339 yyextra->state_ptr--;
343 {Blank}+ ; /* do nothing */
344 {Comment}.*/{Eol} ; /* do nothing */
346 yy_push_state(RVALUE, yyscanner);
347 yyextra->state_ptr++;
352 yy_push_state(RVALUE, yyscanner);
353 yyextra->state_ptr++;
357 yy_push_state(RVALUE, yyscanner);
358 yyextra->state_ptr++;
362 yylval->num = strtol(yytext + 1, NULL, 16);
363 if (yylval->num >= 0xf000) {
364 ERR(yyextra, _("unicode keysym out of range: %s"),
370 {Decimal}|{Octal}|{Hex} {
371 yylval->num = strtol(yytext, NULL, 0);
374 <RVALUE>{Literal} { return((yylval->num = ksymtocode(yyextra, yytext, TO_AUTO)) == -1 ? ERROR : LITERAL); }
376 \, { return(COMMA); }
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); }
395 {Usual} { return(USUAL); }
397 {For} { return(FOR); }
399 yylval->num = strtol(yytext + 2, NULL, 8);
403 yylval->num = (unsigned char) yytext[2];
407 yylval->num = (unsigned char) yytext[1];
411 yylval->str.data[0] = '\0';
414 yy_push_state(STR, yyscanner);
415 yyextra->state_ptr++;
418 if (yylval->str.len == MAX_PARSER_STRING) {
419 ERR(yyextra, _("string too long"));
422 yylval->str.data[yylval->str.len++] = strtol(yytext + 1, NULL, 8);
425 if (yylval->str.len == MAX_PARSER_STRING) {
426 ERR(yyextra, _("string too long"));
429 yylval->str.data[yylval->str.len++] = '"';
432 if (yylval->str.len == MAX_PARSER_STRING) {
433 ERR(yyextra, _("string too long"));
436 yylval->str.data[yylval->str.len++] = '\\';
439 if (yylval->str.len == MAX_PARSER_STRING) {
440 ERR(yyextra, _("string too long"));
443 yylval->str.data[yylval->str.len++] = '\n';
446 int len = strlen(yytext);
448 if (yylval->str.len + len >= MAX_PARSER_STRING) {
449 ERR(yyextra, _("string too long"));
453 strcpy((char *) yylval->str.data + yylval->str.len, yytext);
454 yylval->str.len += len;
457 yylval->str.data[yylval->str.len] = '\0';
458 while (yyextra->state_ptr > 0) {
459 yy_pop_state(yyscanner);
460 yyextra->state_ptr--;