xref: /titanic_51/usr/src/cmd/loadkeys/loadkeys.y (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate %{
2*7c478bd9Sstevel@tonic-gate /*
3*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
4*7c478bd9Sstevel@tonic-gate  *
5*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
6*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
7*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
8*7c478bd9Sstevel@tonic-gate  * with the License.
9*7c478bd9Sstevel@tonic-gate  *
10*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
11*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
12*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
13*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
14*7c478bd9Sstevel@tonic-gate  *
15*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
16*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
17*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
18*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
19*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
20*7c478bd9Sstevel@tonic-gate  *
21*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
22*7c478bd9Sstevel@tonic-gate  */
23*7c478bd9Sstevel@tonic-gate 
24*7c478bd9Sstevel@tonic-gate #ifndef lint
25*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
26*7c478bd9Sstevel@tonic-gate #endif
27*7c478bd9Sstevel@tonic-gate 
28*7c478bd9Sstevel@tonic-gate /*
29*7c478bd9Sstevel@tonic-gate  * Copyright (c) 1999 by Sun Microsystems, Inc.
30*7c478bd9Sstevel@tonic-gate  * All rights reserved.
31*7c478bd9Sstevel@tonic-gate  */
32*7c478bd9Sstevel@tonic-gate 
33*7c478bd9Sstevel@tonic-gate #include <sys/param.h>
34*7c478bd9Sstevel@tonic-gate #include <ctype.h>
35*7c478bd9Sstevel@tonic-gate #include <stdio.h>
36*7c478bd9Sstevel@tonic-gate #include <search.h>
37*7c478bd9Sstevel@tonic-gate #include <string.h>
38*7c478bd9Sstevel@tonic-gate #include <malloc.h>
39*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
40*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
41*7c478bd9Sstevel@tonic-gate #include <errno.h>
42*7c478bd9Sstevel@tonic-gate #include <unistd.h>
43*7c478bd9Sstevel@tonic-gate #include <sys/kbd.h>
44*7c478bd9Sstevel@tonic-gate #include <sys/kbio.h>
45*7c478bd9Sstevel@tonic-gate 
46*7c478bd9Sstevel@tonic-gate #define	ALL	-1	/* special symbol for all tables */
47*7c478bd9Sstevel@tonic-gate 
48*7c478bd9Sstevel@tonic-gate /*
49*7c478bd9Sstevel@tonic-gate  * SunOS 4.x and Solaris 2.[1234] put Type 4 key tables into
50*7c478bd9Sstevel@tonic-gate  * the keytables directory with no type qualification.
51*7c478bd9Sstevel@tonic-gate  * If we're a SPARC, we might be using an NFS server that
52*7c478bd9Sstevel@tonic-gate  * doesn't have the new type-qualified directories.
53*7c478bd9Sstevel@tonic-gate  * (loadkeys wasn't used on non-SPARCs in 2.[1234].)
54*7c478bd9Sstevel@tonic-gate  */
55*7c478bd9Sstevel@tonic-gate #ifdef	sparc
56*7c478bd9Sstevel@tonic-gate #define	COMPATIBILITY_DIR
57*7c478bd9Sstevel@tonic-gate #endif
58*7c478bd9Sstevel@tonic-gate 
59*7c478bd9Sstevel@tonic-gate static char	keytable_dir[] = "/usr/share/lib/keytables/type_%d/";
60*7c478bd9Sstevel@tonic-gate #ifdef	COMPATIBILITY_DIR
61*7c478bd9Sstevel@tonic-gate static char	keytable_dir2[] = "/usr/share/lib/keytables/";
62*7c478bd9Sstevel@tonic-gate #endif
63*7c478bd9Sstevel@tonic-gate static char	layout_prefix[] = "layout_";
64*7c478bd9Sstevel@tonic-gate 
65*7c478bd9Sstevel@tonic-gate struct keyentry {
66*7c478bd9Sstevel@tonic-gate 	struct keyentry	*ke_next;
67*7c478bd9Sstevel@tonic-gate 	struct kiockeymap ke_entry;
68*7c478bd9Sstevel@tonic-gate };
69*7c478bd9Sstevel@tonic-gate 
70*7c478bd9Sstevel@tonic-gate typedef struct keyentry keyentry;
71*7c478bd9Sstevel@tonic-gate 
72*7c478bd9Sstevel@tonic-gate static keyentry *firstentry;
73*7c478bd9Sstevel@tonic-gate static keyentry *lastentry;
74*7c478bd9Sstevel@tonic-gate 
75*7c478bd9Sstevel@tonic-gate struct dupentry {
76*7c478bd9Sstevel@tonic-gate 	struct dupentry *de_next;
77*7c478bd9Sstevel@tonic-gate 	int	de_station;
78*7c478bd9Sstevel@tonic-gate 	int	de_otherstation;
79*7c478bd9Sstevel@tonic-gate };
80*7c478bd9Sstevel@tonic-gate 
81*7c478bd9Sstevel@tonic-gate typedef struct dupentry dupentry;
82*7c478bd9Sstevel@tonic-gate 
83*7c478bd9Sstevel@tonic-gate static dupentry *firstduplicate;
84*7c478bd9Sstevel@tonic-gate static dupentry *lastduplicate;
85*7c478bd9Sstevel@tonic-gate 
86*7c478bd9Sstevel@tonic-gate static dupentry *firstswap;
87*7c478bd9Sstevel@tonic-gate static dupentry *lastswap;
88*7c478bd9Sstevel@tonic-gate 
89*7c478bd9Sstevel@tonic-gate static char	*infilename;
90*7c478bd9Sstevel@tonic-gate static FILE	*infile;
91*7c478bd9Sstevel@tonic-gate static int	lineno;
92*7c478bd9Sstevel@tonic-gate static int	begline;
93*7c478bd9Sstevel@tonic-gate 
94*7c478bd9Sstevel@tonic-gate static char	*strings[16] = {
95*7c478bd9Sstevel@tonic-gate 	"\033[H",		/* HOMEARROW */
96*7c478bd9Sstevel@tonic-gate 	"\033[A",		/* UPARROW */
97*7c478bd9Sstevel@tonic-gate 	"\033[B",		/* DOWNARROW */
98*7c478bd9Sstevel@tonic-gate 	"\033[D",		/* LEFTARROW */
99*7c478bd9Sstevel@tonic-gate 	"\033[C",		/* RIGHTARROW */
100*7c478bd9Sstevel@tonic-gate };
101*7c478bd9Sstevel@tonic-gate 
102*7c478bd9Sstevel@tonic-gate static int	nstrings = 5;	/* start out with 5 strings */
103*7c478bd9Sstevel@tonic-gate 
104*7c478bd9Sstevel@tonic-gate typedef enum {
105*7c478bd9Sstevel@tonic-gate 	SM_INVALID,	/* this shift mask is invalid for this keyboard */
106*7c478bd9Sstevel@tonic-gate 	SM_NORMAL,	/* "normal", valid shift mask */
107*7c478bd9Sstevel@tonic-gate 	SM_NUMLOCK,	/* "Num Lock" shift mask */
108*7c478bd9Sstevel@tonic-gate 	SM_UP		/* "Up" shift mask */
109*7c478bd9Sstevel@tonic-gate } smtype_t;
110*7c478bd9Sstevel@tonic-gate 
111*7c478bd9Sstevel@tonic-gate typedef struct {
112*7c478bd9Sstevel@tonic-gate 	int	sm_mask;
113*7c478bd9Sstevel@tonic-gate 	smtype_t sm_type;
114*7c478bd9Sstevel@tonic-gate } smentry_t;
115*7c478bd9Sstevel@tonic-gate 
116*7c478bd9Sstevel@tonic-gate static	smentry_t shiftmasks[] = {
117*7c478bd9Sstevel@tonic-gate 	{ 0,		SM_NORMAL },
118*7c478bd9Sstevel@tonic-gate 	{ SHIFTMASK,	SM_NORMAL },
119*7c478bd9Sstevel@tonic-gate 	{ CAPSMASK,	SM_NORMAL },
120*7c478bd9Sstevel@tonic-gate 	{ CTRLMASK,	SM_NORMAL },
121*7c478bd9Sstevel@tonic-gate 	{ ALTGRAPHMASK,	SM_NORMAL },
122*7c478bd9Sstevel@tonic-gate 	{ NUMLOCKMASK,	SM_NUMLOCK },
123*7c478bd9Sstevel@tonic-gate 	{ UPMASK,	SM_UP },
124*7c478bd9Sstevel@tonic-gate };
125*7c478bd9Sstevel@tonic-gate 
126*7c478bd9Sstevel@tonic-gate 
127*7c478bd9Sstevel@tonic-gate #define	NSHIFTS	(sizeof (shiftmasks) / sizeof (shiftmasks[0]))
128*7c478bd9Sstevel@tonic-gate 
129*7c478bd9Sstevel@tonic-gate static void	enter_mapentry(int station, keyentry *entrylistp);
130*7c478bd9Sstevel@tonic-gate static keyentry *makeentry(int tablemask, int entry);
131*7c478bd9Sstevel@tonic-gate static int	loadkey(int kbdfd, keyentry *kep);
132*7c478bd9Sstevel@tonic-gate static int	dupkey(int kbdfd, dupentry *dep, int shiftmask);
133*7c478bd9Sstevel@tonic-gate static int	swapkey(int kbdfd, dupentry *dep, int shiftmask);
134*7c478bd9Sstevel@tonic-gate static int	yylex();
135*7c478bd9Sstevel@tonic-gate static int	readesc(FILE *stream, int delim, int single_char);
136*7c478bd9Sstevel@tonic-gate static int	wordcmp(const void *w1, const void *w2);
137*7c478bd9Sstevel@tonic-gate static int	yyerror(char *msg);
138*7c478bd9Sstevel@tonic-gate static void	usage(void);
139*7c478bd9Sstevel@tonic-gate static void	set_layout(char *arg);
140*7c478bd9Sstevel@tonic-gate static FILE	*open_mapping_file(char *pathbuf, char *name,
141*7c478bd9Sstevel@tonic-gate 			boolean_t explicit_name, int type);
142*7c478bd9Sstevel@tonic-gate 
143*7c478bd9Sstevel@tonic-gate int
144*7c478bd9Sstevel@tonic-gate main(argc, argv)
145*7c478bd9Sstevel@tonic-gate 	int argc;
146*7c478bd9Sstevel@tonic-gate 	char **argv;
147*7c478bd9Sstevel@tonic-gate {
148*7c478bd9Sstevel@tonic-gate 	register int kbdfd;
149*7c478bd9Sstevel@tonic-gate 	int type;
150*7c478bd9Sstevel@tonic-gate 	int layout;
151*7c478bd9Sstevel@tonic-gate 	/* maxint is 8 hex digits. */
152*7c478bd9Sstevel@tonic-gate 	char layout_filename[sizeof(layout_prefix)+8];
153*7c478bd9Sstevel@tonic-gate 	char pathbuf[MAXPATHLEN];
154*7c478bd9Sstevel@tonic-gate 	register int shift;
155*7c478bd9Sstevel@tonic-gate 	struct kiockeymap mapentry;
156*7c478bd9Sstevel@tonic-gate 	register keyentry *kep;
157*7c478bd9Sstevel@tonic-gate 	register dupentry *dep;
158*7c478bd9Sstevel@tonic-gate 	boolean_t explicit_name;
159*7c478bd9Sstevel@tonic-gate 
160*7c478bd9Sstevel@tonic-gate 	while(++argv, --argc) {
161*7c478bd9Sstevel@tonic-gate 		if(argv[0][0] != '-') break;
162*7c478bd9Sstevel@tonic-gate 		switch(argv[0][1]) {
163*7c478bd9Sstevel@tonic-gate 		case 'e':
164*7c478bd9Sstevel@tonic-gate 			/* -e obsolete, silently ignore */
165*7c478bd9Sstevel@tonic-gate 			break;
166*7c478bd9Sstevel@tonic-gate 		case 's':
167*7c478bd9Sstevel@tonic-gate 			if (argc != 2) {
168*7c478bd9Sstevel@tonic-gate 				usage();
169*7c478bd9Sstevel@tonic-gate 				/* NOTREACHED */
170*7c478bd9Sstevel@tonic-gate 			}
171*7c478bd9Sstevel@tonic-gate 			set_layout(argv[1]);
172*7c478bd9Sstevel@tonic-gate 			exit(0);
173*7c478bd9Sstevel@tonic-gate 		default:
174*7c478bd9Sstevel@tonic-gate 			usage();
175*7c478bd9Sstevel@tonic-gate 			/* NOTREACHED */
176*7c478bd9Sstevel@tonic-gate 		}
177*7c478bd9Sstevel@tonic-gate 	}
178*7c478bd9Sstevel@tonic-gate 
179*7c478bd9Sstevel@tonic-gate 	if (argc > 1) usage();
180*7c478bd9Sstevel@tonic-gate 
181*7c478bd9Sstevel@tonic-gate 	if ((kbdfd = open("/dev/kbd", O_WRONLY)) < 0) {
182*7c478bd9Sstevel@tonic-gate 		/* perror("loadkeys: /dev/kbd"); */
183*7c478bd9Sstevel@tonic-gate 		return (1);
184*7c478bd9Sstevel@tonic-gate 	}
185*7c478bd9Sstevel@tonic-gate 
186*7c478bd9Sstevel@tonic-gate 	if (ioctl(kbdfd, KIOCTYPE, &type) < 0) {
187*7c478bd9Sstevel@tonic-gate 		/*
188*7c478bd9Sstevel@tonic-gate 		 * There may not be a keyboard connected,
189*7c478bd9Sstevel@tonic-gate 		 * return silently
190*7c478bd9Sstevel@tonic-gate 		 */
191*7c478bd9Sstevel@tonic-gate 		return (1);
192*7c478bd9Sstevel@tonic-gate 	}
193*7c478bd9Sstevel@tonic-gate 
194*7c478bd9Sstevel@tonic-gate 	if (argc == 0) {
195*7c478bd9Sstevel@tonic-gate 		/* If no keyboard detected, exit silently. */
196*7c478bd9Sstevel@tonic-gate 		if (type == -1)
197*7c478bd9Sstevel@tonic-gate 			return (0);
198*7c478bd9Sstevel@tonic-gate 
199*7c478bd9Sstevel@tonic-gate 		if (ioctl(kbdfd, KIOCLAYOUT, &layout) < 0) {
200*7c478bd9Sstevel@tonic-gate 			perror("loadkeys: ioctl(KIOCLAYOUT)");
201*7c478bd9Sstevel@tonic-gate 			return (1);
202*7c478bd9Sstevel@tonic-gate 		}
203*7c478bd9Sstevel@tonic-gate 
204*7c478bd9Sstevel@tonic-gate 		(void) sprintf(layout_filename,
205*7c478bd9Sstevel@tonic-gate 				"%s%.2x", layout_prefix, layout);
206*7c478bd9Sstevel@tonic-gate 		infilename = layout_filename;
207*7c478bd9Sstevel@tonic-gate 		explicit_name = B_FALSE;
208*7c478bd9Sstevel@tonic-gate 	} else {
209*7c478bd9Sstevel@tonic-gate 		infilename = argv[0];
210*7c478bd9Sstevel@tonic-gate 		explicit_name = B_TRUE;
211*7c478bd9Sstevel@tonic-gate 	}
212*7c478bd9Sstevel@tonic-gate 
213*7c478bd9Sstevel@tonic-gate 	infile = open_mapping_file(pathbuf, infilename, explicit_name, type);
214*7c478bd9Sstevel@tonic-gate 	if (infile == NULL) return (1);
215*7c478bd9Sstevel@tonic-gate 
216*7c478bd9Sstevel@tonic-gate 	infilename = pathbuf;
217*7c478bd9Sstevel@tonic-gate 
218*7c478bd9Sstevel@tonic-gate 	lineno = 0;
219*7c478bd9Sstevel@tonic-gate 	begline = 1;
220*7c478bd9Sstevel@tonic-gate 	yyparse();
221*7c478bd9Sstevel@tonic-gate 	fclose(infile);
222*7c478bd9Sstevel@tonic-gate 
223*7c478bd9Sstevel@tonic-gate 	/*
224*7c478bd9Sstevel@tonic-gate 	 * See which shift masks are valid for this keyboard.
225*7c478bd9Sstevel@tonic-gate 	 * We do that by trying to get the entry for keystation 0 and that
226*7c478bd9Sstevel@tonic-gate 	 * shift mask; if the "ioctl" fails, we assume it's because the shift
227*7c478bd9Sstevel@tonic-gate 	 * mask is invalid.
228*7c478bd9Sstevel@tonic-gate 	 */
229*7c478bd9Sstevel@tonic-gate 	for (shift = 0; shift < NSHIFTS; shift++) {
230*7c478bd9Sstevel@tonic-gate 		mapentry.kio_tablemask =
231*7c478bd9Sstevel@tonic-gate 		    shiftmasks[shift].sm_mask;
232*7c478bd9Sstevel@tonic-gate 		mapentry.kio_station = 0;
233*7c478bd9Sstevel@tonic-gate 		if (ioctl(kbdfd, KIOCGKEY, &mapentry) < 0)
234*7c478bd9Sstevel@tonic-gate 			shiftmasks[shift].sm_type = SM_INVALID;
235*7c478bd9Sstevel@tonic-gate 	}
236*7c478bd9Sstevel@tonic-gate 
237*7c478bd9Sstevel@tonic-gate 	for (kep = firstentry; kep != NULL; kep = kep->ke_next) {
238*7c478bd9Sstevel@tonic-gate 		if (kep->ke_entry.kio_tablemask == ALL) {
239*7c478bd9Sstevel@tonic-gate 			for (shift = 0; shift < NSHIFTS; shift++) {
240*7c478bd9Sstevel@tonic-gate 				switch (shiftmasks[shift].sm_type) {
241*7c478bd9Sstevel@tonic-gate 
242*7c478bd9Sstevel@tonic-gate 				case SM_INVALID:
243*7c478bd9Sstevel@tonic-gate 					continue;
244*7c478bd9Sstevel@tonic-gate 
245*7c478bd9Sstevel@tonic-gate 				case SM_NUMLOCK:
246*7c478bd9Sstevel@tonic-gate 					/*
247*7c478bd9Sstevel@tonic-gate 					 * Defaults to NONL, not to a copy of
248*7c478bd9Sstevel@tonic-gate 					 * the base entry.
249*7c478bd9Sstevel@tonic-gate 					 */
250*7c478bd9Sstevel@tonic-gate 					if (kep->ke_entry.kio_entry != HOLE)
251*7c478bd9Sstevel@tonic-gate 						kep->ke_entry.kio_entry = NONL;
252*7c478bd9Sstevel@tonic-gate 					break;
253*7c478bd9Sstevel@tonic-gate 
254*7c478bd9Sstevel@tonic-gate 				case SM_UP:
255*7c478bd9Sstevel@tonic-gate 					/*
256*7c478bd9Sstevel@tonic-gate 					 * Defaults to NOP, not to a copy of
257*7c478bd9Sstevel@tonic-gate 					 * the base entry.
258*7c478bd9Sstevel@tonic-gate 					 */
259*7c478bd9Sstevel@tonic-gate 					if (kep->ke_entry.kio_entry != HOLE)
260*7c478bd9Sstevel@tonic-gate 						kep->ke_entry.kio_entry = NOP;
261*7c478bd9Sstevel@tonic-gate 					break;
262*7c478bd9Sstevel@tonic-gate 				}
263*7c478bd9Sstevel@tonic-gate 				kep->ke_entry.kio_tablemask =
264*7c478bd9Sstevel@tonic-gate 				    shiftmasks[shift].sm_mask;
265*7c478bd9Sstevel@tonic-gate 				if (!loadkey(kbdfd, kep))
266*7c478bd9Sstevel@tonic-gate 					return (1);
267*7c478bd9Sstevel@tonic-gate 			}
268*7c478bd9Sstevel@tonic-gate 		} else {
269*7c478bd9Sstevel@tonic-gate 			if (!loadkey(kbdfd, kep))
270*7c478bd9Sstevel@tonic-gate 				return (1);
271*7c478bd9Sstevel@tonic-gate 		}
272*7c478bd9Sstevel@tonic-gate 	}
273*7c478bd9Sstevel@tonic-gate 
274*7c478bd9Sstevel@tonic-gate 	for (dep = firstswap; dep != NULL; dep = dep->de_next) {
275*7c478bd9Sstevel@tonic-gate 		for (shift = 0; shift < NSHIFTS; shift++) {
276*7c478bd9Sstevel@tonic-gate 			if (shiftmasks[shift].sm_type != SM_INVALID) {
277*7c478bd9Sstevel@tonic-gate 				if (!swapkey(kbdfd, dep,
278*7c478bd9Sstevel@tonic-gate 				    shiftmasks[shift].sm_mask))
279*7c478bd9Sstevel@tonic-gate 					return (0);
280*7c478bd9Sstevel@tonic-gate 			}
281*7c478bd9Sstevel@tonic-gate 		}
282*7c478bd9Sstevel@tonic-gate 	}
283*7c478bd9Sstevel@tonic-gate 
284*7c478bd9Sstevel@tonic-gate 	for (dep = firstduplicate; dep != NULL; dep = dep->de_next) {
285*7c478bd9Sstevel@tonic-gate 		for (shift = 0; shift < NSHIFTS; shift++) {
286*7c478bd9Sstevel@tonic-gate 			if (shiftmasks[shift].sm_type != SM_INVALID) {
287*7c478bd9Sstevel@tonic-gate 				if (!dupkey(kbdfd, dep,
288*7c478bd9Sstevel@tonic-gate 				    shiftmasks[shift].sm_mask))
289*7c478bd9Sstevel@tonic-gate 					return (0);
290*7c478bd9Sstevel@tonic-gate 			}
291*7c478bd9Sstevel@tonic-gate 		}
292*7c478bd9Sstevel@tonic-gate 	}
293*7c478bd9Sstevel@tonic-gate 
294*7c478bd9Sstevel@tonic-gate 	close(kbdfd);
295*7c478bd9Sstevel@tonic-gate 	return (0);
296*7c478bd9Sstevel@tonic-gate }
297*7c478bd9Sstevel@tonic-gate 
298*7c478bd9Sstevel@tonic-gate static void
299*7c478bd9Sstevel@tonic-gate usage()
300*7c478bd9Sstevel@tonic-gate {
301*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "usage: loadkeys [ file ]\n");
302*7c478bd9Sstevel@tonic-gate 	exit(1);
303*7c478bd9Sstevel@tonic-gate }
304*7c478bd9Sstevel@tonic-gate 
305*7c478bd9Sstevel@tonic-gate static void
306*7c478bd9Sstevel@tonic-gate set_layout(char *arg)
307*7c478bd9Sstevel@tonic-gate {
308*7c478bd9Sstevel@tonic-gate 	int layout;
309*7c478bd9Sstevel@tonic-gate 	int ret;
310*7c478bd9Sstevel@tonic-gate 	int kbdfd;
311*7c478bd9Sstevel@tonic-gate 
312*7c478bd9Sstevel@tonic-gate 	layout = (int) strtol(arg, &arg, 0);
313*7c478bd9Sstevel@tonic-gate 	if (*arg != '\0') {
314*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, "usage:  loadkeys -s layoutnumber\n");
315*7c478bd9Sstevel@tonic-gate 		exit(1);
316*7c478bd9Sstevel@tonic-gate 	}
317*7c478bd9Sstevel@tonic-gate 
318*7c478bd9Sstevel@tonic-gate 	if ((kbdfd = open("/dev/kbd", O_WRONLY)) < 0) {
319*7c478bd9Sstevel@tonic-gate 		perror("/dev/kbd");
320*7c478bd9Sstevel@tonic-gate 		exit(1);
321*7c478bd9Sstevel@tonic-gate 	}
322*7c478bd9Sstevel@tonic-gate 
323*7c478bd9Sstevel@tonic-gate 	ret = ioctl(kbdfd, KIOCSLAYOUT, layout);
324*7c478bd9Sstevel@tonic-gate 	if (ret == -1) {
325*7c478bd9Sstevel@tonic-gate 		perror("KIOCSLAYOUT");
326*7c478bd9Sstevel@tonic-gate 	}
327*7c478bd9Sstevel@tonic-gate 
328*7c478bd9Sstevel@tonic-gate 	close(kbdfd);
329*7c478bd9Sstevel@tonic-gate }
330*7c478bd9Sstevel@tonic-gate 
331*7c478bd9Sstevel@tonic-gate /*
332*7c478bd9Sstevel@tonic-gate  * Attempt to find the specified mapping file.  Return a FILE * if found,
333*7c478bd9Sstevel@tonic-gate  * else print a message on stderr and return NULL.
334*7c478bd9Sstevel@tonic-gate  */
335*7c478bd9Sstevel@tonic-gate FILE *
336*7c478bd9Sstevel@tonic-gate open_mapping_file(
337*7c478bd9Sstevel@tonic-gate 	char *pathbuf,
338*7c478bd9Sstevel@tonic-gate 	char *name,
339*7c478bd9Sstevel@tonic-gate 	boolean_t explicit_name,
340*7c478bd9Sstevel@tonic-gate 	int type
341*7c478bd9Sstevel@tonic-gate ) {
342*7c478bd9Sstevel@tonic-gate 	/* If the user specified the name, try it "raw". */
343*7c478bd9Sstevel@tonic-gate 	if (explicit_name) {
344*7c478bd9Sstevel@tonic-gate 		strcpy(pathbuf, name);
345*7c478bd9Sstevel@tonic-gate 		infile = fopen(pathbuf, "r");
346*7c478bd9Sstevel@tonic-gate 		if (infile) return (infile);
347*7c478bd9Sstevel@tonic-gate 		if (errno != ENOENT) goto fopen_fail;
348*7c478bd9Sstevel@tonic-gate 	}
349*7c478bd9Sstevel@tonic-gate 
350*7c478bd9Sstevel@tonic-gate 	/* Everything after this point applies only to relative names. */
351*7c478bd9Sstevel@tonic-gate 	if (*name == '/') goto fopen_fail;
352*7c478bd9Sstevel@tonic-gate 
353*7c478bd9Sstevel@tonic-gate 	/* Try the type-qualified directory name. */
354*7c478bd9Sstevel@tonic-gate 	sprintf(pathbuf, keytable_dir, type);
355*7c478bd9Sstevel@tonic-gate 	if ((int)(strlen(pathbuf) + strlen(name) + 1) >= MAXPATHLEN) {
356*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "loadkeys: Name %s is too long\n",
357*7c478bd9Sstevel@tonic-gate 				name);
358*7c478bd9Sstevel@tonic-gate 		return (NULL);
359*7c478bd9Sstevel@tonic-gate 	}
360*7c478bd9Sstevel@tonic-gate 	(void) strcat(pathbuf, name);
361*7c478bd9Sstevel@tonic-gate 	infile = fopen(pathbuf, "r");
362*7c478bd9Sstevel@tonic-gate 	if (infile) return (infile);
363*7c478bd9Sstevel@tonic-gate 	if (errno != ENOENT) goto fopen_fail;
364*7c478bd9Sstevel@tonic-gate 
365*7c478bd9Sstevel@tonic-gate #ifdef	COMPATIBILITY_DIR
366*7c478bd9Sstevel@tonic-gate 	/* If not, and either the name was specified explicitly */
367*7c478bd9Sstevel@tonic-gate 	/*     or this is a type 4... */
368*7c478bd9Sstevel@tonic-gate 	if (explicit_name || type == KB_SUN4) {
369*7c478bd9Sstevel@tonic-gate 		/* Try the compatibility name. */
370*7c478bd9Sstevel@tonic-gate 		/* No need to check len here, it's shorter. */
371*7c478bd9Sstevel@tonic-gate 		(void) strcpy(pathbuf, keytable_dir2);
372*7c478bd9Sstevel@tonic-gate 		(void) strcat(pathbuf, infilename);
373*7c478bd9Sstevel@tonic-gate 		infile = fopen(pathbuf, "r");
374*7c478bd9Sstevel@tonic-gate 		if (infile) return (infile);
375*7c478bd9Sstevel@tonic-gate 		if (errno != ENOENT) goto fopen_fail;
376*7c478bd9Sstevel@tonic-gate 	}
377*7c478bd9Sstevel@tonic-gate #endif
378*7c478bd9Sstevel@tonic-gate 
379*7c478bd9Sstevel@tonic-gate fopen_fail:
380*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "loadkeys: ");
381*7c478bd9Sstevel@tonic-gate 	perror(name);
382*7c478bd9Sstevel@tonic-gate 	return (NULL);
383*7c478bd9Sstevel@tonic-gate }
384*7c478bd9Sstevel@tonic-gate 
385*7c478bd9Sstevel@tonic-gate /*
386*7c478bd9Sstevel@tonic-gate  * We have a list of entries for a given keystation, and the keystation number
387*7c478bd9Sstevel@tonic-gate  * for that keystation; put that keystation number into all the entries in that
388*7c478bd9Sstevel@tonic-gate  * list, and chain that list to the end of the main list of entries.
389*7c478bd9Sstevel@tonic-gate  */
390*7c478bd9Sstevel@tonic-gate static void
391*7c478bd9Sstevel@tonic-gate enter_mapentry(station, entrylistp)
392*7c478bd9Sstevel@tonic-gate 	int station;
393*7c478bd9Sstevel@tonic-gate 	keyentry *entrylistp;
394*7c478bd9Sstevel@tonic-gate {
395*7c478bd9Sstevel@tonic-gate 	register keyentry *kep;
396*7c478bd9Sstevel@tonic-gate 
397*7c478bd9Sstevel@tonic-gate 	if (lastentry == NULL)
398*7c478bd9Sstevel@tonic-gate 		firstentry = entrylistp;
399*7c478bd9Sstevel@tonic-gate 	else
400*7c478bd9Sstevel@tonic-gate 		lastentry->ke_next = entrylistp;
401*7c478bd9Sstevel@tonic-gate 	kep = entrylistp;
402*7c478bd9Sstevel@tonic-gate 	for (;;) {
403*7c478bd9Sstevel@tonic-gate 		kep->ke_entry.kio_station = (u_char)station;
404*7c478bd9Sstevel@tonic-gate 		if (kep->ke_next == NULL) {
405*7c478bd9Sstevel@tonic-gate 			lastentry = kep;
406*7c478bd9Sstevel@tonic-gate 			break;
407*7c478bd9Sstevel@tonic-gate 		}
408*7c478bd9Sstevel@tonic-gate 		kep = kep->ke_next;
409*7c478bd9Sstevel@tonic-gate 	}
410*7c478bd9Sstevel@tonic-gate }
411*7c478bd9Sstevel@tonic-gate 
412*7c478bd9Sstevel@tonic-gate /*
413*7c478bd9Sstevel@tonic-gate  * Allocate and fill in a new entry.
414*7c478bd9Sstevel@tonic-gate  */
415*7c478bd9Sstevel@tonic-gate static keyentry *
416*7c478bd9Sstevel@tonic-gate makeentry(tablemask, entry)
417*7c478bd9Sstevel@tonic-gate 	int tablemask;
418*7c478bd9Sstevel@tonic-gate 	int entry;
419*7c478bd9Sstevel@tonic-gate {
420*7c478bd9Sstevel@tonic-gate 	register keyentry *kep;
421*7c478bd9Sstevel@tonic-gate 	register int index;
422*7c478bd9Sstevel@tonic-gate 
423*7c478bd9Sstevel@tonic-gate 	if ((kep = (keyentry *) malloc((unsigned)sizeof (keyentry))) == NULL)
424*7c478bd9Sstevel@tonic-gate 		yyerror("out of memory for entries");
425*7c478bd9Sstevel@tonic-gate 	kep->ke_next = NULL;
426*7c478bd9Sstevel@tonic-gate 	kep->ke_entry.kio_tablemask = tablemask;
427*7c478bd9Sstevel@tonic-gate 	kep->ke_entry.kio_station = 0;
428*7c478bd9Sstevel@tonic-gate 	kep->ke_entry.kio_entry = (u_short)entry;
429*7c478bd9Sstevel@tonic-gate 	index = entry - STRING;
430*7c478bd9Sstevel@tonic-gate 	if (index >= 0 && index <= 15)
431*7c478bd9Sstevel@tonic-gate 		(void) strncpy(kep->ke_entry.kio_string, strings[index],
432*7c478bd9Sstevel@tonic-gate 		    KTAB_STRLEN);
433*7c478bd9Sstevel@tonic-gate 	return (kep);
434*7c478bd9Sstevel@tonic-gate }
435*7c478bd9Sstevel@tonic-gate 
436*7c478bd9Sstevel@tonic-gate /*
437*7c478bd9Sstevel@tonic-gate  * Make a set of entries for a keystation that indicate that that keystation's
438*7c478bd9Sstevel@tonic-gate  * settings should be copied from another keystation's settings.
439*7c478bd9Sstevel@tonic-gate  */
440*7c478bd9Sstevel@tonic-gate static void
441*7c478bd9Sstevel@tonic-gate duplicate_mapentry(station, otherstation)
442*7c478bd9Sstevel@tonic-gate 	int station;
443*7c478bd9Sstevel@tonic-gate 	int otherstation;
444*7c478bd9Sstevel@tonic-gate {
445*7c478bd9Sstevel@tonic-gate 	register dupentry *dep;
446*7c478bd9Sstevel@tonic-gate 
447*7c478bd9Sstevel@tonic-gate 	if ((dep = (dupentry *) malloc((unsigned)sizeof (dupentry))) == NULL)
448*7c478bd9Sstevel@tonic-gate 		yyerror("out of memory for entries");
449*7c478bd9Sstevel@tonic-gate 
450*7c478bd9Sstevel@tonic-gate 	if (lastduplicate == NULL)
451*7c478bd9Sstevel@tonic-gate 		firstduplicate = dep;
452*7c478bd9Sstevel@tonic-gate 	else
453*7c478bd9Sstevel@tonic-gate 		lastduplicate->de_next = dep;
454*7c478bd9Sstevel@tonic-gate 	lastduplicate = dep;
455*7c478bd9Sstevel@tonic-gate 	dep->de_next = NULL;
456*7c478bd9Sstevel@tonic-gate 	dep->de_station = station;
457*7c478bd9Sstevel@tonic-gate 	dep->de_otherstation = otherstation;
458*7c478bd9Sstevel@tonic-gate }
459*7c478bd9Sstevel@tonic-gate 
460*7c478bd9Sstevel@tonic-gate /*
461*7c478bd9Sstevel@tonic-gate  * Make a set of entries for a keystation that indicate that that keystation's
462*7c478bd9Sstevel@tonic-gate  * settings should be swapped with another keystation's settings.
463*7c478bd9Sstevel@tonic-gate  */
464*7c478bd9Sstevel@tonic-gate static void
465*7c478bd9Sstevel@tonic-gate swap_mapentry(station, otherstation)
466*7c478bd9Sstevel@tonic-gate 	int station;
467*7c478bd9Sstevel@tonic-gate 	int otherstation;
468*7c478bd9Sstevel@tonic-gate {
469*7c478bd9Sstevel@tonic-gate 	register dupentry *dep;
470*7c478bd9Sstevel@tonic-gate 
471*7c478bd9Sstevel@tonic-gate 	if ((dep = (dupentry *) malloc((unsigned)sizeof (dupentry))) == NULL)
472*7c478bd9Sstevel@tonic-gate 		yyerror("out of memory for entries");
473*7c478bd9Sstevel@tonic-gate 
474*7c478bd9Sstevel@tonic-gate 	if (lastswap == NULL)
475*7c478bd9Sstevel@tonic-gate 		firstswap = dep;
476*7c478bd9Sstevel@tonic-gate 	else
477*7c478bd9Sstevel@tonic-gate 		lastswap->de_next = dep;
478*7c478bd9Sstevel@tonic-gate 	lastswap = dep;
479*7c478bd9Sstevel@tonic-gate 	dep->de_next = NULL;
480*7c478bd9Sstevel@tonic-gate 	dep->de_station = station;
481*7c478bd9Sstevel@tonic-gate 	dep->de_otherstation = otherstation;
482*7c478bd9Sstevel@tonic-gate }
483*7c478bd9Sstevel@tonic-gate 
484*7c478bd9Sstevel@tonic-gate static int
485*7c478bd9Sstevel@tonic-gate loadkey(kbdfd, kep)
486*7c478bd9Sstevel@tonic-gate 	int kbdfd;
487*7c478bd9Sstevel@tonic-gate 	register keyentry *kep;
488*7c478bd9Sstevel@tonic-gate {
489*7c478bd9Sstevel@tonic-gate 	if (ioctl(kbdfd, KIOCSKEY, &kep->ke_entry) < 0) {
490*7c478bd9Sstevel@tonic-gate 		perror("loadkeys: ioctl(KIOCSKEY)");
491*7c478bd9Sstevel@tonic-gate 		return (0);
492*7c478bd9Sstevel@tonic-gate 	}
493*7c478bd9Sstevel@tonic-gate 	return (1);
494*7c478bd9Sstevel@tonic-gate }
495*7c478bd9Sstevel@tonic-gate 
496*7c478bd9Sstevel@tonic-gate static int
497*7c478bd9Sstevel@tonic-gate dupkey(kbdfd, dep, shiftmask)
498*7c478bd9Sstevel@tonic-gate 	int kbdfd;
499*7c478bd9Sstevel@tonic-gate 	register dupentry *dep;
500*7c478bd9Sstevel@tonic-gate 	int shiftmask;
501*7c478bd9Sstevel@tonic-gate {
502*7c478bd9Sstevel@tonic-gate 	struct kiockeymap entry;
503*7c478bd9Sstevel@tonic-gate 
504*7c478bd9Sstevel@tonic-gate 	entry.kio_tablemask = shiftmask;
505*7c478bd9Sstevel@tonic-gate 	entry.kio_station = dep->de_otherstation;
506*7c478bd9Sstevel@tonic-gate 	if (ioctl(kbdfd, KIOCGKEY, &entry) < 0) {
507*7c478bd9Sstevel@tonic-gate 		perror("loadkeys: ioctl(KIOCGKEY)");
508*7c478bd9Sstevel@tonic-gate 		return (0);
509*7c478bd9Sstevel@tonic-gate 	}
510*7c478bd9Sstevel@tonic-gate 	entry.kio_station = dep->de_station;
511*7c478bd9Sstevel@tonic-gate 	if (ioctl(kbdfd, KIOCSKEY, &entry) < 0) {
512*7c478bd9Sstevel@tonic-gate 		perror("loadkeys: ioctl(KIOCSKEY)");
513*7c478bd9Sstevel@tonic-gate 		return (0);
514*7c478bd9Sstevel@tonic-gate 	}
515*7c478bd9Sstevel@tonic-gate 	return (1);
516*7c478bd9Sstevel@tonic-gate }
517*7c478bd9Sstevel@tonic-gate 
518*7c478bd9Sstevel@tonic-gate 
519*7c478bd9Sstevel@tonic-gate 
520*7c478bd9Sstevel@tonic-gate static int
521*7c478bd9Sstevel@tonic-gate swapkey(kbdfd, dep, shiftmask)
522*7c478bd9Sstevel@tonic-gate 	int kbdfd;
523*7c478bd9Sstevel@tonic-gate 	register dupentry *dep;
524*7c478bd9Sstevel@tonic-gate 	int shiftmask;
525*7c478bd9Sstevel@tonic-gate {
526*7c478bd9Sstevel@tonic-gate 	struct kiockeymap entry1, entry2;
527*7c478bd9Sstevel@tonic-gate 
528*7c478bd9Sstevel@tonic-gate 	entry1.kio_tablemask = shiftmask;
529*7c478bd9Sstevel@tonic-gate 	entry1.kio_station = dep->de_station;
530*7c478bd9Sstevel@tonic-gate 	if (ioctl(kbdfd, KIOCGKEY, &entry1) < 0) {
531*7c478bd9Sstevel@tonic-gate 		perror("loadkeys: ioctl(KIOCGKEY)");
532*7c478bd9Sstevel@tonic-gate 		return (0);
533*7c478bd9Sstevel@tonic-gate 	}
534*7c478bd9Sstevel@tonic-gate 	entry2.kio_tablemask = shiftmask;
535*7c478bd9Sstevel@tonic-gate 	entry2.kio_station = dep->de_otherstation;
536*7c478bd9Sstevel@tonic-gate 	if (ioctl(kbdfd, KIOCGKEY, &entry2) < 0) {
537*7c478bd9Sstevel@tonic-gate 		perror("loadkeys: ioctl(KIOCGKEY)");
538*7c478bd9Sstevel@tonic-gate 		return (0);
539*7c478bd9Sstevel@tonic-gate 	}
540*7c478bd9Sstevel@tonic-gate 	entry1.kio_station = dep->de_otherstation;
541*7c478bd9Sstevel@tonic-gate 	if (ioctl(kbdfd, KIOCSKEY, &entry1) < 0) {
542*7c478bd9Sstevel@tonic-gate 		perror("loadkeys: ioctl(KIOCSKEY)");
543*7c478bd9Sstevel@tonic-gate 		return (0);
544*7c478bd9Sstevel@tonic-gate 	}
545*7c478bd9Sstevel@tonic-gate 	entry2.kio_station = dep->de_station;
546*7c478bd9Sstevel@tonic-gate 	if (ioctl(kbdfd, KIOCSKEY, &entry2) < 0) {
547*7c478bd9Sstevel@tonic-gate 		perror("loadkeys: ioctl(KIOCSKEY)");
548*7c478bd9Sstevel@tonic-gate 		return (0);
549*7c478bd9Sstevel@tonic-gate 	}
550*7c478bd9Sstevel@tonic-gate 	return (1);
551*7c478bd9Sstevel@tonic-gate }
552*7c478bd9Sstevel@tonic-gate %}
553*7c478bd9Sstevel@tonic-gate 
554*7c478bd9Sstevel@tonic-gate %term TABLENAME INT CHAR CHARSTRING CONSTANT FKEY KEY SAME AS SWAP WITH
555*7c478bd9Sstevel@tonic-gate 
556*7c478bd9Sstevel@tonic-gate %union {
557*7c478bd9Sstevel@tonic-gate 	keyentry *keyentry;
558*7c478bd9Sstevel@tonic-gate 	int	number;
559*7c478bd9Sstevel@tonic-gate };
560*7c478bd9Sstevel@tonic-gate 
561*7c478bd9Sstevel@tonic-gate %type <keyentry>	entrylist entry
562*7c478bd9Sstevel@tonic-gate %type <number>		CHARSTRING CHAR INT CONSTANT FKEY TABLENAME
563*7c478bd9Sstevel@tonic-gate %type <number>		code expr term number
564*7c478bd9Sstevel@tonic-gate 
565*7c478bd9Sstevel@tonic-gate %%
566*7c478bd9Sstevel@tonic-gate 
567*7c478bd9Sstevel@tonic-gate table:
568*7c478bd9Sstevel@tonic-gate 	table line
569*7c478bd9Sstevel@tonic-gate |	/* null */
570*7c478bd9Sstevel@tonic-gate ;
571*7c478bd9Sstevel@tonic-gate 
572*7c478bd9Sstevel@tonic-gate line:
573*7c478bd9Sstevel@tonic-gate 	KEY number entrylist '\n'
574*7c478bd9Sstevel@tonic-gate 		{
575*7c478bd9Sstevel@tonic-gate 		enter_mapentry($2, $3);
576*7c478bd9Sstevel@tonic-gate 		}
577*7c478bd9Sstevel@tonic-gate |	KEY number SAME AS number '\n'
578*7c478bd9Sstevel@tonic-gate 		{
579*7c478bd9Sstevel@tonic-gate 		duplicate_mapentry($2, $5);
580*7c478bd9Sstevel@tonic-gate 		}
581*7c478bd9Sstevel@tonic-gate |	SWAP number WITH number '\n'
582*7c478bd9Sstevel@tonic-gate 		{
583*7c478bd9Sstevel@tonic-gate 		swap_mapentry($2, $4);
584*7c478bd9Sstevel@tonic-gate 		}
585*7c478bd9Sstevel@tonic-gate |	'\n'
586*7c478bd9Sstevel@tonic-gate ;
587*7c478bd9Sstevel@tonic-gate 
588*7c478bd9Sstevel@tonic-gate entrylist:
589*7c478bd9Sstevel@tonic-gate 	entrylist entry
590*7c478bd9Sstevel@tonic-gate 		{
591*7c478bd9Sstevel@tonic-gate 		/*
592*7c478bd9Sstevel@tonic-gate 		 * Append this entry to the end of the entry list.
593*7c478bd9Sstevel@tonic-gate 		 */
594*7c478bd9Sstevel@tonic-gate 		register keyentry *kep;
595*7c478bd9Sstevel@tonic-gate 		kep = $1;
596*7c478bd9Sstevel@tonic-gate 		for (;;) {
597*7c478bd9Sstevel@tonic-gate 			if (kep->ke_next == NULL) {
598*7c478bd9Sstevel@tonic-gate 				kep->ke_next = $2;
599*7c478bd9Sstevel@tonic-gate 				break;
600*7c478bd9Sstevel@tonic-gate 			}
601*7c478bd9Sstevel@tonic-gate 			kep = kep->ke_next;
602*7c478bd9Sstevel@tonic-gate 		}
603*7c478bd9Sstevel@tonic-gate 		$$ = $1;
604*7c478bd9Sstevel@tonic-gate 		}
605*7c478bd9Sstevel@tonic-gate |	entry
606*7c478bd9Sstevel@tonic-gate 		{
607*7c478bd9Sstevel@tonic-gate 		$$ = $1;
608*7c478bd9Sstevel@tonic-gate 		}
609*7c478bd9Sstevel@tonic-gate ;
610*7c478bd9Sstevel@tonic-gate 
611*7c478bd9Sstevel@tonic-gate entry:
612*7c478bd9Sstevel@tonic-gate 	TABLENAME code
613*7c478bd9Sstevel@tonic-gate 		{
614*7c478bd9Sstevel@tonic-gate 		$$ = makeentry($1, $2);
615*7c478bd9Sstevel@tonic-gate 		}
616*7c478bd9Sstevel@tonic-gate ;
617*7c478bd9Sstevel@tonic-gate 
618*7c478bd9Sstevel@tonic-gate code:
619*7c478bd9Sstevel@tonic-gate 	CHARSTRING
620*7c478bd9Sstevel@tonic-gate 		{
621*7c478bd9Sstevel@tonic-gate 		$$ = $1;
622*7c478bd9Sstevel@tonic-gate 		}
623*7c478bd9Sstevel@tonic-gate |	CHAR
624*7c478bd9Sstevel@tonic-gate 		{
625*7c478bd9Sstevel@tonic-gate 		$$ = $1;
626*7c478bd9Sstevel@tonic-gate 		}
627*7c478bd9Sstevel@tonic-gate |	'('
628*7c478bd9Sstevel@tonic-gate 		{
629*7c478bd9Sstevel@tonic-gate 		$$ = '(';
630*7c478bd9Sstevel@tonic-gate 		}
631*7c478bd9Sstevel@tonic-gate |	')'
632*7c478bd9Sstevel@tonic-gate 		{
633*7c478bd9Sstevel@tonic-gate 		$$ = ')';
634*7c478bd9Sstevel@tonic-gate 		}
635*7c478bd9Sstevel@tonic-gate |	'+'
636*7c478bd9Sstevel@tonic-gate 		{
637*7c478bd9Sstevel@tonic-gate 		$$ = '+';
638*7c478bd9Sstevel@tonic-gate 		}
639*7c478bd9Sstevel@tonic-gate |	expr
640*7c478bd9Sstevel@tonic-gate 		{
641*7c478bd9Sstevel@tonic-gate 		$$ = $1;
642*7c478bd9Sstevel@tonic-gate 		}
643*7c478bd9Sstevel@tonic-gate ;
644*7c478bd9Sstevel@tonic-gate 
645*7c478bd9Sstevel@tonic-gate expr:
646*7c478bd9Sstevel@tonic-gate 	term
647*7c478bd9Sstevel@tonic-gate 		{
648*7c478bd9Sstevel@tonic-gate 		$$ = $1;
649*7c478bd9Sstevel@tonic-gate 		}
650*7c478bd9Sstevel@tonic-gate |	expr '+' term
651*7c478bd9Sstevel@tonic-gate 		{
652*7c478bd9Sstevel@tonic-gate 		$$ = $1 + $3;
653*7c478bd9Sstevel@tonic-gate 		}
654*7c478bd9Sstevel@tonic-gate ;
655*7c478bd9Sstevel@tonic-gate 
656*7c478bd9Sstevel@tonic-gate term:
657*7c478bd9Sstevel@tonic-gate 	CONSTANT
658*7c478bd9Sstevel@tonic-gate 		{
659*7c478bd9Sstevel@tonic-gate 		$$ = $1;
660*7c478bd9Sstevel@tonic-gate 		}
661*7c478bd9Sstevel@tonic-gate |	FKEY '(' number ')'
662*7c478bd9Sstevel@tonic-gate 		{
663*7c478bd9Sstevel@tonic-gate 		if ($3 < 1 || $3 > 16)
664*7c478bd9Sstevel@tonic-gate 			yyerror("invalid function key number");
665*7c478bd9Sstevel@tonic-gate 		$$ = $1 + $3 - 1;
666*7c478bd9Sstevel@tonic-gate 		}
667*7c478bd9Sstevel@tonic-gate ;
668*7c478bd9Sstevel@tonic-gate 
669*7c478bd9Sstevel@tonic-gate number:
670*7c478bd9Sstevel@tonic-gate 	INT
671*7c478bd9Sstevel@tonic-gate 		{
672*7c478bd9Sstevel@tonic-gate 		$$ = $1;
673*7c478bd9Sstevel@tonic-gate 		}
674*7c478bd9Sstevel@tonic-gate |	CHAR
675*7c478bd9Sstevel@tonic-gate 		{
676*7c478bd9Sstevel@tonic-gate 		if (isdigit($1))
677*7c478bd9Sstevel@tonic-gate 			$$ = $1 - '0';
678*7c478bd9Sstevel@tonic-gate 		else
679*7c478bd9Sstevel@tonic-gate 			yyerror("syntax error");
680*7c478bd9Sstevel@tonic-gate 		}
681*7c478bd9Sstevel@tonic-gate ;
682*7c478bd9Sstevel@tonic-gate 
683*7c478bd9Sstevel@tonic-gate %%
684*7c478bd9Sstevel@tonic-gate 
685*7c478bd9Sstevel@tonic-gate typedef struct {
686*7c478bd9Sstevel@tonic-gate 	char	*w_string;
687*7c478bd9Sstevel@tonic-gate 	int	w_type;		/* token type */
688*7c478bd9Sstevel@tonic-gate 	int	w_lval;		/* yylval for this token */
689*7c478bd9Sstevel@tonic-gate } word_t;
690*7c478bd9Sstevel@tonic-gate 
691*7c478bd9Sstevel@tonic-gate /*
692*7c478bd9Sstevel@tonic-gate  * Table must be in alphabetical order.
693*7c478bd9Sstevel@tonic-gate  */
694*7c478bd9Sstevel@tonic-gate word_t	wordtab[] = {
695*7c478bd9Sstevel@tonic-gate 	{ "all",	TABLENAME,	ALL },
696*7c478bd9Sstevel@tonic-gate 	{ "alt",	CONSTANT,	ALT },
697*7c478bd9Sstevel@tonic-gate 	{ "altg",	TABLENAME,	ALTGRAPHMASK },
698*7c478bd9Sstevel@tonic-gate 	{ "altgraph",	CONSTANT,	ALTGRAPH },
699*7c478bd9Sstevel@tonic-gate 	{ "as",		AS,		0 },
700*7c478bd9Sstevel@tonic-gate 	{ "base",	TABLENAME,	0 },
701*7c478bd9Sstevel@tonic-gate 	{ "bf",		FKEY,		BOTTOMFUNC },
702*7c478bd9Sstevel@tonic-gate 	{ "buckybits",	CONSTANT,	BUCKYBITS },
703*7c478bd9Sstevel@tonic-gate 	{ "caps",	TABLENAME,	CAPSMASK },
704*7c478bd9Sstevel@tonic-gate 	{ "capslock",	CONSTANT,	CAPSLOCK },
705*7c478bd9Sstevel@tonic-gate 	{ "compose",	CONSTANT,	COMPOSE },
706*7c478bd9Sstevel@tonic-gate 	{ "ctrl",	TABLENAME,	CTRLMASK },
707*7c478bd9Sstevel@tonic-gate 	{ "downarrow",	CONSTANT,	DOWNARROW },
708*7c478bd9Sstevel@tonic-gate 	{ "error",	CONSTANT,	ERROR },
709*7c478bd9Sstevel@tonic-gate 	{ "fa_acute",	CONSTANT,	FA_ACUTE },
710*7c478bd9Sstevel@tonic-gate 	{ "fa_cedilla",	CONSTANT,	FA_CEDILLA },
711*7c478bd9Sstevel@tonic-gate 	{ "fa_cflex",	CONSTANT,	FA_CFLEX },
712*7c478bd9Sstevel@tonic-gate 	{ "fa_grave",	CONSTANT,	FA_GRAVE },
713*7c478bd9Sstevel@tonic-gate 	{ "fa_tilde",	CONSTANT,	FA_TILDE },
714*7c478bd9Sstevel@tonic-gate 	{ "fa_umlaut",	CONSTANT,	FA_UMLAUT },
715*7c478bd9Sstevel@tonic-gate 	{ "hole",	CONSTANT,	HOLE },
716*7c478bd9Sstevel@tonic-gate 	{ "homearrow",	CONSTANT,	HOMEARROW },
717*7c478bd9Sstevel@tonic-gate 	{ "idle",	CONSTANT,	IDLE },
718*7c478bd9Sstevel@tonic-gate 	{ "key",	KEY,		0 },
719*7c478bd9Sstevel@tonic-gate 	{ "leftarrow",	CONSTANT,	LEFTARROW },
720*7c478bd9Sstevel@tonic-gate 	{ "leftctrl",	CONSTANT,	LEFTCTRL },
721*7c478bd9Sstevel@tonic-gate 	{ "leftshift",	CONSTANT,	LEFTSHIFT },
722*7c478bd9Sstevel@tonic-gate 	{ "lf",		FKEY,		LEFTFUNC },
723*7c478bd9Sstevel@tonic-gate 	{ "metabit",	CONSTANT,	METABIT },
724*7c478bd9Sstevel@tonic-gate 	{ "nonl",	CONSTANT,	NONL },
725*7c478bd9Sstevel@tonic-gate 	{ "nop",	CONSTANT,	NOP },
726*7c478bd9Sstevel@tonic-gate 	{ "numl",	TABLENAME,	NUMLOCKMASK },
727*7c478bd9Sstevel@tonic-gate 	{ "numlock",	CONSTANT,	NUMLOCK },
728*7c478bd9Sstevel@tonic-gate 	{ "oops",	CONSTANT,	OOPS },
729*7c478bd9Sstevel@tonic-gate 	{ "pad0",	CONSTANT,	PAD0 },
730*7c478bd9Sstevel@tonic-gate 	{ "pad1",	CONSTANT,	PAD1 },
731*7c478bd9Sstevel@tonic-gate 	{ "pad2",	CONSTANT,	PAD2 },
732*7c478bd9Sstevel@tonic-gate 	{ "pad3",	CONSTANT,	PAD3 },
733*7c478bd9Sstevel@tonic-gate 	{ "pad4",	CONSTANT,	PAD4 },
734*7c478bd9Sstevel@tonic-gate 	{ "pad5",	CONSTANT,	PAD5 },
735*7c478bd9Sstevel@tonic-gate 	{ "pad6",	CONSTANT,	PAD6 },
736*7c478bd9Sstevel@tonic-gate 	{ "pad7",	CONSTANT,	PAD7 },
737*7c478bd9Sstevel@tonic-gate 	{ "pad8",	CONSTANT,	PAD8 },
738*7c478bd9Sstevel@tonic-gate 	{ "pad9",	CONSTANT,	PAD9 },
739*7c478bd9Sstevel@tonic-gate 	{ "paddot",	CONSTANT,	PADDOT },
740*7c478bd9Sstevel@tonic-gate 	{ "padenter",	CONSTANT,	PADENTER },
741*7c478bd9Sstevel@tonic-gate 	{ "padequal",	CONSTANT,	PADEQUAL },
742*7c478bd9Sstevel@tonic-gate 	{ "padminus",	CONSTANT,	PADMINUS },
743*7c478bd9Sstevel@tonic-gate 	{ "padplus",	CONSTANT,	PADPLUS },
744*7c478bd9Sstevel@tonic-gate 	{ "padsep",	CONSTANT,	PADSEP },
745*7c478bd9Sstevel@tonic-gate 	{ "padslash",	CONSTANT,	PADSLASH },
746*7c478bd9Sstevel@tonic-gate 	{ "padstar",	CONSTANT,	PADSTAR },
747*7c478bd9Sstevel@tonic-gate 	{ "reset",	CONSTANT,	RESET },
748*7c478bd9Sstevel@tonic-gate 	{ "rf",		FKEY,		RIGHTFUNC },
749*7c478bd9Sstevel@tonic-gate 	{ "rightarrow",	CONSTANT,	RIGHTARROW },
750*7c478bd9Sstevel@tonic-gate 	{ "rightctrl",	CONSTANT,	RIGHTCTRL },
751*7c478bd9Sstevel@tonic-gate 	{ "rightshift",	CONSTANT,	RIGHTSHIFT },
752*7c478bd9Sstevel@tonic-gate 	{ "same",	SAME,		0 },
753*7c478bd9Sstevel@tonic-gate 	{ "shift",	TABLENAME,	SHIFTMASK },
754*7c478bd9Sstevel@tonic-gate 	{ "shiftkeys",	CONSTANT,	SHIFTKEYS },
755*7c478bd9Sstevel@tonic-gate 	{ "shiftlock",	CONSTANT,	SHIFTLOCK },
756*7c478bd9Sstevel@tonic-gate 	{ "string",	CONSTANT,	STRING },
757*7c478bd9Sstevel@tonic-gate 	{ "swap",	SWAP,		0 },
758*7c478bd9Sstevel@tonic-gate 	{ "systembit",	CONSTANT,	SYSTEMBIT },
759*7c478bd9Sstevel@tonic-gate 	{ "tf",		FKEY,		TOPFUNC },
760*7c478bd9Sstevel@tonic-gate 	{ "up",		TABLENAME,	UPMASK },
761*7c478bd9Sstevel@tonic-gate 	{ "uparrow",	CONSTANT,	UPARROW },
762*7c478bd9Sstevel@tonic-gate 	{ "with",	WITH,		0 },
763*7c478bd9Sstevel@tonic-gate };
764*7c478bd9Sstevel@tonic-gate 
765*7c478bd9Sstevel@tonic-gate #define	NWORDS		(sizeof (wordtab) / sizeof (wordtab[0]))
766*7c478bd9Sstevel@tonic-gate 
767*7c478bd9Sstevel@tonic-gate static int
768*7c478bd9Sstevel@tonic-gate yylex()
769*7c478bd9Sstevel@tonic-gate {
770*7c478bd9Sstevel@tonic-gate 	register int c;
771*7c478bd9Sstevel@tonic-gate 	char tokbuf[256+1];
772*7c478bd9Sstevel@tonic-gate 	register char *cp;
773*7c478bd9Sstevel@tonic-gate 	register int tokentype;
774*7c478bd9Sstevel@tonic-gate 
775*7c478bd9Sstevel@tonic-gate 	while ((c = getc(infile)) == ' ' || c == '\t')
776*7c478bd9Sstevel@tonic-gate 		;
777*7c478bd9Sstevel@tonic-gate 	if (begline) {
778*7c478bd9Sstevel@tonic-gate 		lineno++;
779*7c478bd9Sstevel@tonic-gate 		begline = 0;
780*7c478bd9Sstevel@tonic-gate 		if (c == '#') {
781*7c478bd9Sstevel@tonic-gate 			while ((c = getc(infile)) != EOF && c != '\n')
782*7c478bd9Sstevel@tonic-gate 				;
783*7c478bd9Sstevel@tonic-gate 		}
784*7c478bd9Sstevel@tonic-gate 	}
785*7c478bd9Sstevel@tonic-gate 	if (c == EOF)
786*7c478bd9Sstevel@tonic-gate 		return (0);	/* end marker */
787*7c478bd9Sstevel@tonic-gate 	if (c == '\n') {
788*7c478bd9Sstevel@tonic-gate 		begline = 1;
789*7c478bd9Sstevel@tonic-gate 		return (c);
790*7c478bd9Sstevel@tonic-gate 	}
791*7c478bd9Sstevel@tonic-gate 
792*7c478bd9Sstevel@tonic-gate 	switch (c) {
793*7c478bd9Sstevel@tonic-gate 
794*7c478bd9Sstevel@tonic-gate 	case '\'':
795*7c478bd9Sstevel@tonic-gate 		tokentype = CHAR;
796*7c478bd9Sstevel@tonic-gate 		if ((c = getc(infile)) == EOF)
797*7c478bd9Sstevel@tonic-gate 			yyerror("unterminated character constant");
798*7c478bd9Sstevel@tonic-gate 		if (c == '\n') {
799*7c478bd9Sstevel@tonic-gate 			(void) ungetc(c, infile);
800*7c478bd9Sstevel@tonic-gate 			yylval.number = '\'';
801*7c478bd9Sstevel@tonic-gate 		} else {
802*7c478bd9Sstevel@tonic-gate 			switch (c) {
803*7c478bd9Sstevel@tonic-gate 
804*7c478bd9Sstevel@tonic-gate 			case '\'':
805*7c478bd9Sstevel@tonic-gate 				yyerror("null character constant");
806*7c478bd9Sstevel@tonic-gate 				break;
807*7c478bd9Sstevel@tonic-gate 
808*7c478bd9Sstevel@tonic-gate 			case '\\':
809*7c478bd9Sstevel@tonic-gate 				yylval.number = readesc(infile, '\'', 1);
810*7c478bd9Sstevel@tonic-gate 				break;
811*7c478bd9Sstevel@tonic-gate 
812*7c478bd9Sstevel@tonic-gate 			default:
813*7c478bd9Sstevel@tonic-gate 				yylval.number = c;
814*7c478bd9Sstevel@tonic-gate 				break;
815*7c478bd9Sstevel@tonic-gate 			}
816*7c478bd9Sstevel@tonic-gate 			if ((c = getc(infile)) == EOF || c == '\n')
817*7c478bd9Sstevel@tonic-gate 				yyerror("unterminated character constant");
818*7c478bd9Sstevel@tonic-gate 			else if (c != '\'')
819*7c478bd9Sstevel@tonic-gate 				yyerror("only one character allowed in character constant");
820*7c478bd9Sstevel@tonic-gate 		}
821*7c478bd9Sstevel@tonic-gate 		break;
822*7c478bd9Sstevel@tonic-gate 
823*7c478bd9Sstevel@tonic-gate 	case '"':
824*7c478bd9Sstevel@tonic-gate 		if ((c = getc(infile)) == EOF)
825*7c478bd9Sstevel@tonic-gate 			yyerror("unterminated string constant");
826*7c478bd9Sstevel@tonic-gate 		if (c == '\n') {
827*7c478bd9Sstevel@tonic-gate 			(void) ungetc(c, infile);
828*7c478bd9Sstevel@tonic-gate 			tokentype = CHAR;
829*7c478bd9Sstevel@tonic-gate 			yylval.number = '"';
830*7c478bd9Sstevel@tonic-gate 		} else {
831*7c478bd9Sstevel@tonic-gate 			tokentype = CHARSTRING;
832*7c478bd9Sstevel@tonic-gate 			cp = &tokbuf[0];
833*7c478bd9Sstevel@tonic-gate 			do {
834*7c478bd9Sstevel@tonic-gate 				if (cp > &tokbuf[256])
835*7c478bd9Sstevel@tonic-gate 					yyerror("line too long");
836*7c478bd9Sstevel@tonic-gate 				if (c == '\\')
837*7c478bd9Sstevel@tonic-gate 					c = readesc(infile, '"', 0);
838*7c478bd9Sstevel@tonic-gate 				*cp++ = (char)c;
839*7c478bd9Sstevel@tonic-gate 			} while ((c = getc(infile)) != EOF && c != '\n' &&
840*7c478bd9Sstevel@tonic-gate 				c != '"');
841*7c478bd9Sstevel@tonic-gate 			if (c != '"')
842*7c478bd9Sstevel@tonic-gate 				yyerror("unterminated string constant");
843*7c478bd9Sstevel@tonic-gate 			*cp = '\0';
844*7c478bd9Sstevel@tonic-gate 			if (nstrings == 16)
845*7c478bd9Sstevel@tonic-gate 				yyerror("too many strings");
846*7c478bd9Sstevel@tonic-gate 			if ((int) strlen(tokbuf) > KTAB_STRLEN)
847*7c478bd9Sstevel@tonic-gate 				yyerror("string too long");
848*7c478bd9Sstevel@tonic-gate 			strings[nstrings] = strdup(tokbuf);
849*7c478bd9Sstevel@tonic-gate 			yylval.number = STRING+nstrings;
850*7c478bd9Sstevel@tonic-gate 			nstrings++;
851*7c478bd9Sstevel@tonic-gate 		}
852*7c478bd9Sstevel@tonic-gate 		break;
853*7c478bd9Sstevel@tonic-gate 
854*7c478bd9Sstevel@tonic-gate 	case '(':
855*7c478bd9Sstevel@tonic-gate 	case ')':
856*7c478bd9Sstevel@tonic-gate 	case '+':
857*7c478bd9Sstevel@tonic-gate 		tokentype = c;
858*7c478bd9Sstevel@tonic-gate 		break;
859*7c478bd9Sstevel@tonic-gate 
860*7c478bd9Sstevel@tonic-gate 	case '^':
861*7c478bd9Sstevel@tonic-gate 		if ((c = getc(infile)) == EOF)
862*7c478bd9Sstevel@tonic-gate 			yyerror("missing newline at end of line");
863*7c478bd9Sstevel@tonic-gate 		tokentype = CHAR;
864*7c478bd9Sstevel@tonic-gate 		if (c == ' ' || c == '\t' || c == '\n') {
865*7c478bd9Sstevel@tonic-gate 			/*
866*7c478bd9Sstevel@tonic-gate 			 * '^' by itself.
867*7c478bd9Sstevel@tonic-gate 			 */
868*7c478bd9Sstevel@tonic-gate 			yylval.number = '^';
869*7c478bd9Sstevel@tonic-gate 		} else {
870*7c478bd9Sstevel@tonic-gate 			yylval.number = c & 037;
871*7c478bd9Sstevel@tonic-gate 			if ((c = getc(infile)) == EOF)
872*7c478bd9Sstevel@tonic-gate 				yyerror("missing newline at end of line");
873*7c478bd9Sstevel@tonic-gate 			if (c != ' ' && c != '\t' && c != '\n')
874*7c478bd9Sstevel@tonic-gate 				yyerror("invalid control character");
875*7c478bd9Sstevel@tonic-gate 		}
876*7c478bd9Sstevel@tonic-gate 		(void) ungetc(c, infile);
877*7c478bd9Sstevel@tonic-gate 		break;
878*7c478bd9Sstevel@tonic-gate 
879*7c478bd9Sstevel@tonic-gate 	default:
880*7c478bd9Sstevel@tonic-gate 		cp = &tokbuf[0];
881*7c478bd9Sstevel@tonic-gate 		do {
882*7c478bd9Sstevel@tonic-gate 			if (cp > &tokbuf[256])
883*7c478bd9Sstevel@tonic-gate 				yyerror("line too long");
884*7c478bd9Sstevel@tonic-gate 			*cp++ = (char)c;
885*7c478bd9Sstevel@tonic-gate 		} while ((c = getc(infile)) != EOF && (isalnum(c) || c == '_'));
886*7c478bd9Sstevel@tonic-gate 		if (c == EOF)
887*7c478bd9Sstevel@tonic-gate 			yyerror("newline missing");
888*7c478bd9Sstevel@tonic-gate 		(void) ungetc(c, infile);
889*7c478bd9Sstevel@tonic-gate 		*cp = '\0';
890*7c478bd9Sstevel@tonic-gate 		if (strlen(tokbuf) == 1) {
891*7c478bd9Sstevel@tonic-gate 			tokentype = CHAR;
892*7c478bd9Sstevel@tonic-gate 			yylval.number = (unsigned char)tokbuf[0];
893*7c478bd9Sstevel@tonic-gate 		} else if (strlen(tokbuf) == 2 && tokbuf[0] == '^') {
894*7c478bd9Sstevel@tonic-gate 			tokentype = CHAR;
895*7c478bd9Sstevel@tonic-gate 			yylval.number = (unsigned char)(tokbuf[1] & 037);
896*7c478bd9Sstevel@tonic-gate 		} else {
897*7c478bd9Sstevel@tonic-gate 			word_t word;
898*7c478bd9Sstevel@tonic-gate 			register word_t *wptr;
899*7c478bd9Sstevel@tonic-gate 			char *ptr;
900*7c478bd9Sstevel@tonic-gate 
901*7c478bd9Sstevel@tonic-gate 			for (cp = &tokbuf[0]; (c = *cp) != '\0'; cp++) {
902*7c478bd9Sstevel@tonic-gate 				if (isupper(c))
903*7c478bd9Sstevel@tonic-gate 					*cp = tolower(c);
904*7c478bd9Sstevel@tonic-gate 			}
905*7c478bd9Sstevel@tonic-gate 			word.w_string = tokbuf;
906*7c478bd9Sstevel@tonic-gate 			wptr = (word_t *)bsearch((char *)&word,
907*7c478bd9Sstevel@tonic-gate 			    (char *)wordtab, NWORDS, sizeof (word_t),
908*7c478bd9Sstevel@tonic-gate 			    wordcmp);
909*7c478bd9Sstevel@tonic-gate 			if (wptr != NULL) {
910*7c478bd9Sstevel@tonic-gate 				yylval.number = wptr->w_lval;
911*7c478bd9Sstevel@tonic-gate 				tokentype = wptr->w_type;
912*7c478bd9Sstevel@tonic-gate 			} else {
913*7c478bd9Sstevel@tonic-gate 				yylval.number = strtol(tokbuf, &ptr, 10);
914*7c478bd9Sstevel@tonic-gate 				if (ptr == tokbuf)
915*7c478bd9Sstevel@tonic-gate 					yyerror("syntax error");
916*7c478bd9Sstevel@tonic-gate 				else
917*7c478bd9Sstevel@tonic-gate 					tokentype = INT;
918*7c478bd9Sstevel@tonic-gate 			}
919*7c478bd9Sstevel@tonic-gate 			break;
920*7c478bd9Sstevel@tonic-gate 		}
921*7c478bd9Sstevel@tonic-gate 	}
922*7c478bd9Sstevel@tonic-gate 
923*7c478bd9Sstevel@tonic-gate 	return (tokentype);
924*7c478bd9Sstevel@tonic-gate }
925*7c478bd9Sstevel@tonic-gate 
926*7c478bd9Sstevel@tonic-gate static int
927*7c478bd9Sstevel@tonic-gate readesc(stream, delim, single_char)
928*7c478bd9Sstevel@tonic-gate 	FILE *stream;
929*7c478bd9Sstevel@tonic-gate 	int delim;
930*7c478bd9Sstevel@tonic-gate 	int single_char;
931*7c478bd9Sstevel@tonic-gate {
932*7c478bd9Sstevel@tonic-gate 	register int c;
933*7c478bd9Sstevel@tonic-gate 	register int val;
934*7c478bd9Sstevel@tonic-gate 	register int i;
935*7c478bd9Sstevel@tonic-gate 
936*7c478bd9Sstevel@tonic-gate 	if ((c = getc(stream)) == EOF || c == '\n')
937*7c478bd9Sstevel@tonic-gate 		yyerror("unterminated character constant");
938*7c478bd9Sstevel@tonic-gate 
939*7c478bd9Sstevel@tonic-gate 	if (c >= '0' && c <= '7') {
940*7c478bd9Sstevel@tonic-gate 		val = 0;
941*7c478bd9Sstevel@tonic-gate 		i = 1;
942*7c478bd9Sstevel@tonic-gate 		for (;;) {
943*7c478bd9Sstevel@tonic-gate 			val = val*8 + c - '0';
944*7c478bd9Sstevel@tonic-gate 			if ((c = getc(stream)) == EOF || c == '\n')
945*7c478bd9Sstevel@tonic-gate 				yyerror("unterminated character constant");
946*7c478bd9Sstevel@tonic-gate 			if (c == delim)
947*7c478bd9Sstevel@tonic-gate 				break;
948*7c478bd9Sstevel@tonic-gate 			i++;
949*7c478bd9Sstevel@tonic-gate 			if (i > 3) {
950*7c478bd9Sstevel@tonic-gate 				if (single_char)
951*7c478bd9Sstevel@tonic-gate 					yyerror("escape sequence too long");
952*7c478bd9Sstevel@tonic-gate 				else
953*7c478bd9Sstevel@tonic-gate 					break;
954*7c478bd9Sstevel@tonic-gate 			}
955*7c478bd9Sstevel@tonic-gate 			if (c < '0' || c > '7') {
956*7c478bd9Sstevel@tonic-gate 				if (single_char)
957*7c478bd9Sstevel@tonic-gate 					yyerror("illegal character in escape sequence");
958*7c478bd9Sstevel@tonic-gate 				else
959*7c478bd9Sstevel@tonic-gate 					break;
960*7c478bd9Sstevel@tonic-gate 			}
961*7c478bd9Sstevel@tonic-gate 		}
962*7c478bd9Sstevel@tonic-gate 		(void) ungetc(c, stream);
963*7c478bd9Sstevel@tonic-gate 	} else {
964*7c478bd9Sstevel@tonic-gate 		switch (c) {
965*7c478bd9Sstevel@tonic-gate 
966*7c478bd9Sstevel@tonic-gate 		case 'n':
967*7c478bd9Sstevel@tonic-gate 			val = '\n';
968*7c478bd9Sstevel@tonic-gate 			break;
969*7c478bd9Sstevel@tonic-gate 
970*7c478bd9Sstevel@tonic-gate 		case 't':
971*7c478bd9Sstevel@tonic-gate 			val = '\t';
972*7c478bd9Sstevel@tonic-gate 			break;
973*7c478bd9Sstevel@tonic-gate 
974*7c478bd9Sstevel@tonic-gate 		case 'b':
975*7c478bd9Sstevel@tonic-gate 			val = '\b';
976*7c478bd9Sstevel@tonic-gate 			break;
977*7c478bd9Sstevel@tonic-gate 
978*7c478bd9Sstevel@tonic-gate 		case 'r':
979*7c478bd9Sstevel@tonic-gate 			val = '\r';
980*7c478bd9Sstevel@tonic-gate 			break;
981*7c478bd9Sstevel@tonic-gate 
982*7c478bd9Sstevel@tonic-gate 		case 'v':
983*7c478bd9Sstevel@tonic-gate 			val = '\v';
984*7c478bd9Sstevel@tonic-gate 			break;
985*7c478bd9Sstevel@tonic-gate 
986*7c478bd9Sstevel@tonic-gate 		case '\\':
987*7c478bd9Sstevel@tonic-gate 			val = '\\';
988*7c478bd9Sstevel@tonic-gate 			break;
989*7c478bd9Sstevel@tonic-gate 
990*7c478bd9Sstevel@tonic-gate 		default:
991*7c478bd9Sstevel@tonic-gate 			if (c == delim)
992*7c478bd9Sstevel@tonic-gate 				val = delim;
993*7c478bd9Sstevel@tonic-gate 			else
994*7c478bd9Sstevel@tonic-gate 				yyerror("illegal character in escape sequence");
995*7c478bd9Sstevel@tonic-gate 		}
996*7c478bd9Sstevel@tonic-gate 	}
997*7c478bd9Sstevel@tonic-gate 	return (val);
998*7c478bd9Sstevel@tonic-gate }
999*7c478bd9Sstevel@tonic-gate 
1000*7c478bd9Sstevel@tonic-gate static int
1001*7c478bd9Sstevel@tonic-gate wordcmp(const void *w1, const void *w2)
1002*7c478bd9Sstevel@tonic-gate {
1003*7c478bd9Sstevel@tonic-gate 	return (strcmp(
1004*7c478bd9Sstevel@tonic-gate 		((const word_t *)w1)->w_string,
1005*7c478bd9Sstevel@tonic-gate 		((const word_t *)w2)->w_string));
1006*7c478bd9Sstevel@tonic-gate }
1007*7c478bd9Sstevel@tonic-gate 
1008*7c478bd9Sstevel@tonic-gate static int
1009*7c478bd9Sstevel@tonic-gate yyerror(msg)
1010*7c478bd9Sstevel@tonic-gate 	char *msg;
1011*7c478bd9Sstevel@tonic-gate {
1012*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "%s, line %d: %s\n", infilename, lineno, msg);
1013*7c478bd9Sstevel@tonic-gate 	exit(1);
1014*7c478bd9Sstevel@tonic-gate }
1015