5 * The contents of this file are subject to the terms of the
6 * Common Development and Distribution License, Version 1.0 only
7 * (the "License"). You may not use this file except in compliance
10 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
11 * or http://www.opensolaris.org/os/licensing.
12 * See the License for the specific language governing permissions
13 * and limitations under the License.
15 * When distributing Covered Code, include this CDDL HEADER in each
16 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
17 * If applicable, add the following below this CDDL HEADER, with the
18 * fields enclosed by brackets "[]" replaced with your own identifying
19 * information: Portions Copyright [yyyy] [name of copyright owner]
25 * Copyright (c) 1999 by Sun Microsystems, Inc.
26 * All rights reserved.
29 #include <sys/param.h>
42 #define ALL -1 /* special symbol for all tables */
44 static char keytable_dir
[] = "/usr/share/lib/keytables/type_%d/";
45 static char layout_prefix
[] = "layout_";
48 struct keyentry
*ke_next
;
49 struct kiockeymap ke_entry
;
52 typedef
struct keyentry keyentry
;
54 static keyentry
*firstentry
;
55 static keyentry
*lastentry
;
58 struct dupentry
*de_next
;
63 typedef
struct dupentry dupentry
;
65 static dupentry
*firstduplicate
;
66 static dupentry
*lastduplicate
;
68 static dupentry
*firstswap
;
69 static dupentry
*lastswap
;
71 static char *infilename
;
76 static char *strings
[16] = {
77 "\033[H", /* HOMEARROW */
78 "\033[A", /* UPARROW */
79 "\033[B", /* DOWNARROW */
80 "\033[D", /* LEFTARROW */
81 "\033[C", /* RIGHTARROW */
84 static int nstrings
= 5; /* start out with 5 strings */
87 SM_INVALID
, /* this shift mask is invalid for this keyboard */
88 SM_NORMAL
, /* "normal", valid shift mask */
89 SM_NUMLOCK
, /* "Num Lock" shift mask */
90 SM_UP
/* "Up" shift mask */
98 static smentry_t shiftmasks
[] = {
100 { SHIFTMASK
, SM_NORMAL
},
101 { CAPSMASK
, SM_NORMAL
},
102 { CTRLMASK
, SM_NORMAL
},
103 { ALTGRAPHMASK
, SM_NORMAL
},
104 { NUMLOCKMASK
, SM_NUMLOCK
},
109 #define NSHIFTS (sizeof (shiftmasks) / sizeof (shiftmasks[0]))
111 static void enter_mapentry
(int station
, keyentry
*entrylistp
);
112 static keyentry
*makeentry
(int tablemask
, int entry
);
113 static int loadkey
(int kbdfd
, keyentry
*kep
);
114 static int dupkey
(int kbdfd
, dupentry
*dep
, int shiftmask
);
115 static int swapkey
(int kbdfd
, dupentry
*dep
, int shiftmask
);
117 extern
int yyparse(void);
118 static int readesc
(FILE *stream
, int delim
, int single_char
);
119 static int wordcmp
(const void *w1
, const void *w2
);
120 static int yyerror(char *msg
);
121 static void usage
(void);
122 static void set_layout
(char *arg
);
123 static FILE *open_mapping_file
(char *pathbuf
, char *name
,
124 boolean_t explicit_name
, int type
);
127 main
(int argc
, char **argv
)
132 /* maxint is 8 hex digits. */
133 char layout_filename
[sizeof
(layout_prefix
)+8];
134 char pathbuf
[MAXPATHLEN
];
136 struct kiockeymap mapentry
;
139 boolean_t explicit_name
;
141 while
(++argv
, --argc
) {
142 if
(argv
[0][0] != '-') break
;
145 /* -e obsolete, silently ignore */
160 if
(argc
> 1) usage
();
162 if
((kbdfd
= open
("/dev/kbd", O_WRONLY
)) < 0) {
163 /* perror("loadkeys: /dev/kbd"); */
167 if
(ioctl
(kbdfd
, KIOCTYPE
, &type
) < 0) {
169 * There may not be a keyboard connected,
176 /* If no keyboard detected, exit silently. */
180 if
(ioctl
(kbdfd
, KIOCLAYOUT
, &layout
) < 0) {
181 perror
("loadkeys: ioctl(KIOCLAYOUT)");
185 (void) sprintf
(layout_filename
,
186 "%s%.2x", layout_prefix
, layout
);
187 infilename
= layout_filename
;
188 explicit_name
= B_FALSE
;
190 infilename
= argv
[0];
191 explicit_name
= B_TRUE
;
194 infile
= open_mapping_file
(pathbuf
, infilename
, explicit_name
, type
);
195 if
(infile
== NULL
) return
(1);
197 infilename
= pathbuf
;
205 * See which shift masks are valid for this keyboard.
206 * We do that by trying to get the entry for keystation 0 and that
207 * shift mask; if the "ioctl" fails, we assume it's because the shift
210 for
(shift
= 0; shift
< NSHIFTS
; shift
++) {
211 mapentry.kio_tablemask
=
212 shiftmasks
[shift
].sm_mask
;
213 mapentry.kio_station
= 0;
214 if
(ioctl
(kbdfd
, KIOCGKEY
, &mapentry
) < 0)
215 shiftmasks
[shift
].sm_type
= SM_INVALID
;
218 for
(kep
= firstentry
; kep
!= NULL
; kep
= kep
->ke_next
) {
219 if
(kep
->ke_entry.kio_tablemask
== ALL
) {
220 for
(shift
= 0; shift
< NSHIFTS
; shift
++) {
221 switch
(shiftmasks
[shift
].sm_type
) {
228 * Defaults to NONL, not to a copy of
231 if
(kep
->ke_entry.kio_entry
!= HOLE
)
232 kep
->ke_entry.kio_entry
= NONL
;
237 * Defaults to NOP, not to a copy of
240 if
(kep
->ke_entry.kio_entry
!= HOLE
)
241 kep
->ke_entry.kio_entry
= NOP
;
244 kep
->ke_entry.kio_tablemask
=
245 shiftmasks
[shift
].sm_mask
;
246 if
(!loadkey
(kbdfd
, kep
))
250 if
(!loadkey
(kbdfd
, kep
))
255 for
(dep
= firstswap
; dep
!= NULL
; dep
= dep
->de_next
) {
256 for
(shift
= 0; shift
< NSHIFTS
; shift
++) {
257 if
(shiftmasks
[shift
].sm_type
!= SM_INVALID
) {
258 if
(!swapkey
(kbdfd
, dep
,
259 shiftmasks
[shift
].sm_mask
))
265 for
(dep
= firstduplicate
; dep
!= NULL
; dep
= dep
->de_next
) {
266 for
(shift
= 0; shift
< NSHIFTS
; shift
++) {
267 if
(shiftmasks
[shift
].sm_type
!= SM_INVALID
) {
268 if
(!dupkey
(kbdfd
, dep
,
269 shiftmasks
[shift
].sm_mask
))
282 (void) fprintf
(stderr
, "usage: loadkeys [ file ]\n");
287 set_layout
(char *arg
)
293 layout
= (int) strtol
(arg
, &arg
, 0);
295 fprintf
(stderr
, "usage: loadkeys -s layoutnumber\n");
299 if
((kbdfd
= open
("/dev/kbd", O_WRONLY
)) < 0) {
304 ret
= ioctl
(kbdfd
, KIOCSLAYOUT
, layout
);
306 perror
("KIOCSLAYOUT");
313 * Attempt to find the specified mapping file. Return a FILE * if found,
314 * else print a message on stderr and return NULL.
317 open_mapping_file
(char *pathbuf
, char *name
, boolean_t explicit_name
, int type
)
319 /* If the user specified the name, try it "raw". */
321 strcpy
(pathbuf
, name
);
322 infile
= fopen
(pathbuf
, "r");
323 if
(infile
) return
(infile
);
324 if
(errno
!= ENOENT
) goto fopen_fail
;
327 /* Everything after this point applies only to relative names. */
328 if
(*name
== '/') goto fopen_fail
;
330 /* Try the type-qualified directory name. */
331 sprintf
(pathbuf
, keytable_dir
, type
);
332 if
((int)(strlen
(pathbuf
) + strlen
(name
) + 1) >= MAXPATHLEN
) {
333 (void) fprintf
(stderr
, "loadkeys: Name %s is too long\n",
337 (void) strcat
(pathbuf
, name
);
338 if
((infile
= fopen
(pathbuf
, "r")) != NULL
)
342 (void) fprintf
(stderr
, "loadkeys: ");
348 * We have a list of entries for a given keystation, and the keystation number
349 * for that keystation; put that keystation number into all the entries in that
350 * list, and chain that list to the end of the main list of entries.
353 enter_mapentry
(station
, entrylistp
)
355 keyentry
*entrylistp
;
357 register keyentry
*kep
;
359 if
(lastentry
== NULL
)
360 firstentry
= entrylistp
;
362 lastentry
->ke_next
= entrylistp
;
365 kep
->ke_entry.kio_station
= (u_char
)station
;
366 if
(kep
->ke_next
== NULL
) {
375 * Allocate and fill in a new entry.
378 makeentry
(tablemask
, entry
)
382 register keyentry
*kep
;
385 if
((kep
= (keyentry
*) malloc
((unsigned)sizeof
(keyentry
))) == NULL
)
386 yyerror("out of memory for entries");
388 kep
->ke_entry.kio_tablemask
= tablemask
;
389 kep
->ke_entry.kio_station
= 0;
390 kep
->ke_entry.kio_entry
= entry
;
391 index
= entry
- STRING
;
392 if
(index
>= 0 && index
<= 15)
393 (void) strncpy
(kep
->ke_entry.kio_string
, strings
[index
],
399 * Make a set of entries for a keystation that indicate that that keystation's
400 * settings should be copied from another keystation's settings.
403 duplicate_mapentry
(station
, otherstation
)
407 register dupentry
*dep
;
409 if
((dep
= (dupentry
*) malloc
((unsigned)sizeof
(dupentry
))) == NULL
)
410 yyerror("out of memory for entries");
412 if
(lastduplicate
== NULL
)
413 firstduplicate
= dep
;
415 lastduplicate
->de_next
= dep
;
418 dep
->de_station
= station
;
419 dep
->de_otherstation
= otherstation
;
423 * Make a set of entries for a keystation that indicate that that keystation's
424 * settings should be swapped with another keystation's settings.
427 swap_mapentry
(station
, otherstation
)
431 register dupentry
*dep
;
433 if
((dep
= (dupentry
*) malloc
((unsigned)sizeof
(dupentry
))) == NULL
)
434 yyerror("out of memory for entries");
436 if
(lastswap
== NULL
)
439 lastswap
->de_next
= dep
;
442 dep
->de_station
= station
;
443 dep
->de_otherstation
= otherstation
;
449 register keyentry
*kep
;
451 if
(ioctl
(kbdfd
, KIOCSKEY
, &kep
->ke_entry
) < 0) {
452 perror
("loadkeys: ioctl(KIOCSKEY)");
459 dupkey
(kbdfd
, dep
, shiftmask
)
461 register dupentry
*dep
;
464 struct kiockeymap entry
;
466 entry.kio_tablemask
= shiftmask
;
467 entry.kio_station
= dep
->de_otherstation
;
468 if
(ioctl
(kbdfd
, KIOCGKEY
, &entry
) < 0) {
469 perror
("loadkeys: ioctl(KIOCGKEY)");
472 entry.kio_station
= dep
->de_station
;
473 if
(ioctl
(kbdfd
, KIOCSKEY
, &entry
) < 0) {
474 perror
("loadkeys: ioctl(KIOCSKEY)");
483 swapkey
(kbdfd
, dep
, shiftmask
)
485 register dupentry
*dep
;
488 struct kiockeymap entry1
, entry2
;
490 entry1.kio_tablemask
= shiftmask
;
491 entry1.kio_station
= dep
->de_station
;
492 if
(ioctl
(kbdfd
, KIOCGKEY
, &entry1
) < 0) {
493 perror
("loadkeys: ioctl(KIOCGKEY)");
496 entry2.kio_tablemask
= shiftmask
;
497 entry2.kio_station
= dep
->de_otherstation
;
498 if
(ioctl
(kbdfd
, KIOCGKEY
, &entry2
) < 0) {
499 perror
("loadkeys: ioctl(KIOCGKEY)");
502 entry1.kio_station
= dep
->de_otherstation
;
503 if
(ioctl
(kbdfd
, KIOCSKEY
, &entry1
) < 0) {
504 perror
("loadkeys: ioctl(KIOCSKEY)");
507 entry2.kio_station
= dep
->de_station
;
508 if
(ioctl
(kbdfd
, KIOCSKEY
, &entry2
) < 0) {
509 perror
("loadkeys: ioctl(KIOCSKEY)");
516 %term TABLENAME INT CHAR CHARSTRING CONSTANT FKEY KEY SAME AS SWAP WITH
523 %type
<keyentry
> entrylist entry
524 %type
<number
> CHARSTRING CHAR INT CONSTANT FKEY TABLENAME
525 %type
<number
> code expr term number
535 KEY number entrylist
'\n'
537 enter_mapentry
($2, $3);
539 | KEY number SAME AS number
'\n'
541 duplicate_mapentry
($2, $5);
543 | SWAP number WITH number
'\n'
545 swap_mapentry
($2, $4);
554 * Append this entry to the end of the entry list.
556 register keyentry
*kep
;
559 if
(kep
->ke_next
== NULL
) {
576 $$
= makeentry
($1, $2);
627 | FKEY
'(' number
')'
629 if
($3 < 1 ||
$3 > 16)
630 yyerror("invalid function key number");
645 yyerror("syntax error");
653 int w_type
; /* token type */
654 int w_lval
; /* yylval for this token */
658 * Table must be in alphabetical order.
661 { "all", TABLENAME
, ALL
},
662 { "alt", CONSTANT
, ALT
},
663 { "altg", TABLENAME
, ALTGRAPHMASK
},
664 { "altgraph", CONSTANT
, ALTGRAPH
},
666 { "base", TABLENAME
, 0 },
667 { "bf", FKEY
, BOTTOMFUNC
},
668 { "buckybits", CONSTANT
, BUCKYBITS
},
669 { "caps", TABLENAME
, CAPSMASK
},
670 { "capslock", CONSTANT
, CAPSLOCK
},
671 { "compose", CONSTANT
, COMPOSE
},
672 { "ctrl", TABLENAME
, CTRLMASK
},
673 { "downarrow", CONSTANT
, DOWNARROW
},
674 { "error", CONSTANT
, ERROR
},
675 { "fa_acute", CONSTANT
, FA_ACUTE
},
676 { "fa_apostrophe", CONSTANT
, FA_APOSTROPHE
},
677 { "fa_breve", CONSTANT
, FA_BREVE
},
678 { "fa_caron", CONSTANT
, FA_CARON
},
679 { "fa_cedilla", CONSTANT
, FA_CEDILLA
},
680 { "fa_cflex", CONSTANT
, FA_CFLEX
},
681 { "fa_dacute", CONSTANT
, FA_DACUTE
},
682 { "fa_dot", CONSTANT
, FA_DOT
},
683 { "fa_grave", CONSTANT
, FA_GRAVE
},
684 { "fa_macron", CONSTANT
, FA_MACRON
},
685 { "fa_ogonek", CONSTANT
, FA_OGONEK
},
686 { "fa_ring", CONSTANT
, FA_RING
},
687 { "fa_slash", CONSTANT
, FA_SLASH
},
688 { "fa_tilde", CONSTANT
, FA_TILDE
},
689 { "fa_umlaut", CONSTANT
, FA_UMLAUT
},
690 { "hole", CONSTANT
, HOLE
},
691 { "homearrow", CONSTANT
, HOMEARROW
},
692 { "idle", CONSTANT
, IDLE
},
694 { "leftarrow", CONSTANT
, LEFTARROW
},
695 { "leftctrl", CONSTANT
, LEFTCTRL
},
696 { "leftshift", CONSTANT
, LEFTSHIFT
},
697 { "lf", FKEY
, LEFTFUNC
},
698 { "metabit", CONSTANT
, METABIT
},
699 { "nonl", CONSTANT
, NONL
},
700 { "nop", CONSTANT
, NOP
},
701 { "numl", TABLENAME
, NUMLOCKMASK
},
702 { "numlock", CONSTANT
, NUMLOCK
},
703 { "oops", CONSTANT
, OOPS
},
704 { "pad0", CONSTANT
, PAD0
},
705 { "pad1", CONSTANT
, PAD1
},
706 { "pad2", CONSTANT
, PAD2
},
707 { "pad3", CONSTANT
, PAD3
},
708 { "pad4", CONSTANT
, PAD4
},
709 { "pad5", CONSTANT
, PAD5
},
710 { "pad6", CONSTANT
, PAD6
},
711 { "pad7", CONSTANT
, PAD7
},
712 { "pad8", CONSTANT
, PAD8
},
713 { "pad9", CONSTANT
, PAD9
},
714 { "paddot", CONSTANT
, PADDOT
},
715 { "padenter", CONSTANT
, PADENTER
},
716 { "padequal", CONSTANT
, PADEQUAL
},
717 { "padminus", CONSTANT
, PADMINUS
},
718 { "padplus", CONSTANT
, PADPLUS
},
719 { "padsep", CONSTANT
, PADSEP
},
720 { "padslash", CONSTANT
, PADSLASH
},
721 { "padstar", CONSTANT
, PADSTAR
},
722 { "reset", CONSTANT
, RESET
},
723 { "rf", FKEY
, RIGHTFUNC
},
724 { "rightarrow", CONSTANT
, RIGHTARROW
},
725 { "rightctrl", CONSTANT
, RIGHTCTRL
},
726 { "rightshift", CONSTANT
, RIGHTSHIFT
},
728 { "shift", TABLENAME
, SHIFTMASK
},
729 { "shiftkeys", CONSTANT
, SHIFTKEYS
},
730 { "shiftlock", CONSTANT
, SHIFTLOCK
},
731 { "string", CONSTANT
, STRING
},
733 { "systembit", CONSTANT
, SYSTEMBIT
},
734 { "tf", FKEY
, TOPFUNC
},
735 { "up", TABLENAME
, UPMASK
},
736 { "uparrow", CONSTANT
, UPARROW
},
740 #define NWORDS (sizeof (wordtab) / sizeof (wordtab[0]))
748 register
int tokentype
;
750 while
((c
= getc
(infile
)) == ' ' || c
== '\t')
756 while
((c
= getc
(infile
)) != EOF
&& c
!= '\n')
761 return
(0); /* end marker */
771 if
((c
= getc
(infile
)) == EOF
)
772 yyerror("unterminated character constant");
774 (void) ungetc
(c
, infile
);
775 yylval.number
= '\'';
780 yyerror("null character constant");
784 yylval.number
= readesc
(infile
, '\'', 1);
791 if
((c
= getc
(infile
)) == EOF || c
== '\n')
792 yyerror("unterminated character constant");
794 yyerror("only one character allowed in character constant");
799 if
((c
= getc
(infile
)) == EOF
)
800 yyerror("unterminated string constant");
802 (void) ungetc
(c
, infile
);
806 tokentype
= CHARSTRING
;
809 if
(cp
> &tokbuf
[256])
810 yyerror("line too long");
812 c
= readesc
(infile
, '"', 0);
814 } while
((c
= getc
(infile
)) != EOF
&& c
!= '\n' &&
817 yyerror("unterminated string constant");
820 yyerror("too many strings");
821 if
((int) strlen
(tokbuf
) > KTAB_STRLEN
)
822 yyerror("string too long");
823 strings
[nstrings
] = strdup
(tokbuf
);
824 yylval.number
= STRING
+nstrings
;
836 if
((c
= getc
(infile
)) == EOF
)
837 yyerror("missing newline at end of line");
839 if
(c
== ' ' || c
== '\t' || c
== '\n') {
845 yylval.number
= c
& 037;
846 if
((c
= getc
(infile
)) == EOF
)
847 yyerror("missing newline at end of line");
848 if
(c
!= ' ' && c
!= '\t' && c
!= '\n')
849 yyerror("invalid control character");
851 (void) ungetc
(c
, infile
);
857 if
(cp
> &tokbuf
[256])
858 yyerror("line too long");
860 } while
((c
= getc
(infile
)) != EOF
&& (isalnum
(c
) || c
== '_'));
862 yyerror("newline missing");
863 (void) ungetc
(c
, infile
);
865 if
(strlen
(tokbuf
) == 1) {
867 yylval.number
= (unsigned char)tokbuf
[0];
868 } else if
(strlen
(tokbuf
) == 2 && tokbuf
[0] == '^') {
870 yylval.number
= (unsigned char)(tokbuf
[1] & 037);
873 register word_t
*wptr
;
876 for
(cp
= &tokbuf
[0]; (c
= *cp
) != '\0'; cp
++) {
880 word.w_string
= tokbuf
;
881 wptr
= (word_t
*)bsearch
((char *)&word
,
882 (char *)wordtab
, NWORDS
, sizeof
(word_t
),
885 yylval.number
= wptr
->w_lval
;
886 tokentype
= wptr
->w_type
;
888 yylval.number
= strtol
(tokbuf
, &ptr
, 0);
890 yyerror("syntax error");
902 readesc
(stream
, delim
, single_char
)
911 if
((c
= getc
(stream
)) == EOF || c
== '\n')
912 yyerror("unterminated character constant");
914 if
(c
>= '0' && c
<= '7') {
918 val
= val
*8 + c
- '0';
919 if
((c
= getc
(stream
)) == EOF || c
== '\n')
920 yyerror("unterminated character constant");
926 yyerror("escape sequence too long");
930 if
(c
< '0' || c
> '7') {
932 yyerror("illegal character in escape sequence");
937 (void) ungetc
(c
, stream
);
969 yyerror("illegal character in escape sequence");
976 wordcmp
(const void *w1
, const void *w2
)
979 ((const word_t
*)w1
)->w_string
,
980 ((const word_t
*)w2
)->w_string
));
987 (void) fprintf
(stderr
, "%s, line %d: %s\n", infilename
, lineno
, msg
);