Unleashed v1.4
[unleashed.git] / usr / src / cmd / loadkeys / loadkeys.y
blobeb146480e6dd41d0167ffb5990a33467415c278a
1 %{
2 /*
3 * CDDL HEADER START
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
8 * with the License.
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]
21 * CDDL HEADER END
25 * Copyright (c) 1999 by Sun Microsystems, Inc.
26 * All rights reserved.
29 #include <sys/param.h>
30 #include <ctype.h>
31 #include <stdio.h>
32 #include <search.h>
33 #include <string.h>
34 #include <malloc.h>
35 #include <fcntl.h>
36 #include <stdlib.h>
37 #include <errno.h>
38 #include <unistd.h>
39 #include <sys/kbd.h>
40 #include <sys/kbio.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_";
47 struct keyentry {
48 struct keyentry *ke_next;
49 struct kiockeymap ke_entry;
52 typedef struct keyentry keyentry;
54 static keyentry *firstentry;
55 static keyentry *lastentry;
57 struct dupentry {
58 struct dupentry *de_next;
59 int de_station;
60 int de_otherstation;
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;
72 static FILE *infile;
73 static int lineno;
74 static int begline;
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 */
86 typedef enum {
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 */
91 } smtype_t;
93 typedef struct {
94 int sm_mask;
95 smtype_t sm_type;
96 } smentry_t;
98 static smentry_t shiftmasks[] = {
99 { 0, SM_NORMAL },
100 { SHIFTMASK, SM_NORMAL },
101 { CAPSMASK, SM_NORMAL },
102 { CTRLMASK, SM_NORMAL },
103 { ALTGRAPHMASK, SM_NORMAL },
104 { NUMLOCKMASK, SM_NUMLOCK },
105 { UPMASK, SM_UP },
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);
116 static int yylex();
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)
129 int kbdfd;
130 int type;
131 int layout;
132 /* maxint is 8 hex digits. */
133 char layout_filename[sizeof(layout_prefix)+8];
134 char pathbuf[MAXPATHLEN];
135 int shift;
136 struct kiockeymap mapentry;
137 keyentry *kep;
138 dupentry *dep;
139 boolean_t explicit_name;
141 while(++argv, --argc) {
142 if(argv[0][0] != '-') break;
143 switch(argv[0][1]) {
144 case 'e':
145 /* -e obsolete, silently ignore */
146 break;
147 case 's':
148 if (argc != 2) {
149 usage();
150 /* NOTREACHED */
152 set_layout(argv[1]);
153 exit(0);
154 default:
155 usage();
156 /* NOTREACHED */
160 if (argc > 1) usage();
162 if ((kbdfd = open("/dev/kbd", O_WRONLY)) < 0) {
163 /* perror("loadkeys: /dev/kbd"); */
164 return (1);
167 if (ioctl(kbdfd, KIOCTYPE, &type) < 0) {
169 * There may not be a keyboard connected,
170 * return silently
172 return (1);
175 if (argc == 0) {
176 /* If no keyboard detected, exit silently. */
177 if (type == -1)
178 return (0);
180 if (ioctl(kbdfd, KIOCLAYOUT, &layout) < 0) {
181 perror("loadkeys: ioctl(KIOCLAYOUT)");
182 return (1);
185 (void) sprintf(layout_filename,
186 "%s%.2x", layout_prefix, layout);
187 infilename = layout_filename;
188 explicit_name = B_FALSE;
189 } else {
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;
199 lineno = 0;
200 begline = 1;
201 yyparse();
202 fclose(infile);
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
208 * mask is invalid.
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) {
223 case SM_INVALID:
224 continue;
226 case SM_NUMLOCK:
228 * Defaults to NONL, not to a copy of
229 * the base entry.
231 if (kep->ke_entry.kio_entry != HOLE)
232 kep->ke_entry.kio_entry = NONL;
233 break;
235 case SM_UP:
237 * Defaults to NOP, not to a copy of
238 * the base entry.
240 if (kep->ke_entry.kio_entry != HOLE)
241 kep->ke_entry.kio_entry = NOP;
242 break;
244 kep->ke_entry.kio_tablemask =
245 shiftmasks[shift].sm_mask;
246 if (!loadkey(kbdfd, kep))
247 return (1);
249 } else {
250 if (!loadkey(kbdfd, kep))
251 return (1);
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))
260 return (0);
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))
270 return (0);
275 close(kbdfd);
276 return (0);
279 static void
280 usage()
282 (void) fprintf(stderr, "usage: loadkeys [ file ]\n");
283 exit(1);
286 static void
287 set_layout(char *arg)
289 int layout;
290 int ret;
291 int kbdfd;
293 layout = (int) strtol(arg, &arg, 0);
294 if (*arg != '\0') {
295 fprintf(stderr, "usage: loadkeys -s layoutnumber\n");
296 exit(1);
299 if ((kbdfd = open("/dev/kbd", O_WRONLY)) < 0) {
300 perror("/dev/kbd");
301 exit(1);
304 ret = ioctl(kbdfd, KIOCSLAYOUT, layout);
305 if (ret == -1) {
306 perror("KIOCSLAYOUT");
309 close(kbdfd);
313 * Attempt to find the specified mapping file. Return a FILE * if found,
314 * else print a message on stderr and return NULL.
316 FILE *
317 open_mapping_file(char *pathbuf, char *name, boolean_t explicit_name, int type)
319 /* If the user specified the name, try it "raw". */
320 if (explicit_name) {
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",
334 name);
335 return (NULL);
337 (void) strcat(pathbuf, name);
338 if ((infile = fopen(pathbuf, "r")) != NULL)
339 return (infile);
341 fopen_fail:
342 (void) fprintf(stderr, "loadkeys: ");
343 perror(name);
344 return (NULL);
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.
352 static void
353 enter_mapentry(station, entrylistp)
354 int station;
355 keyentry *entrylistp;
357 register keyentry *kep;
359 if (lastentry == NULL)
360 firstentry = entrylistp;
361 else
362 lastentry->ke_next = entrylistp;
363 kep = entrylistp;
364 for (;;) {
365 kep->ke_entry.kio_station = (u_char)station;
366 if (kep->ke_next == NULL) {
367 lastentry = kep;
368 break;
370 kep = kep->ke_next;
375 * Allocate and fill in a new entry.
377 static keyentry *
378 makeentry(tablemask, entry)
379 int tablemask;
380 int entry;
382 register keyentry *kep;
383 register int index;
385 if ((kep = (keyentry *) malloc((unsigned)sizeof (keyentry))) == NULL)
386 yyerror("out of memory for entries");
387 kep->ke_next = NULL;
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],
394 KTAB_STRLEN);
395 return (kep);
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.
402 static void
403 duplicate_mapentry(station, otherstation)
404 int station;
405 int 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;
414 else
415 lastduplicate->de_next = dep;
416 lastduplicate = dep;
417 dep->de_next = NULL;
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.
426 static void
427 swap_mapentry(station, otherstation)
428 int station;
429 int 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)
437 firstswap = dep;
438 else
439 lastswap->de_next = dep;
440 lastswap = dep;
441 dep->de_next = NULL;
442 dep->de_station = station;
443 dep->de_otherstation = otherstation;
446 static int
447 loadkey(kbdfd, kep)
448 int kbdfd;
449 register keyentry *kep;
451 if (ioctl(kbdfd, KIOCSKEY, &kep->ke_entry) < 0) {
452 perror("loadkeys: ioctl(KIOCSKEY)");
453 return (0);
455 return (1);
458 static int
459 dupkey(kbdfd, dep, shiftmask)
460 int kbdfd;
461 register dupentry *dep;
462 int shiftmask;
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)");
470 return (0);
472 entry.kio_station = dep->de_station;
473 if (ioctl(kbdfd, KIOCSKEY, &entry) < 0) {
474 perror("loadkeys: ioctl(KIOCSKEY)");
475 return (0);
477 return (1);
482 static int
483 swapkey(kbdfd, dep, shiftmask)
484 int kbdfd;
485 register dupentry *dep;
486 int shiftmask;
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)");
494 return (0);
496 entry2.kio_tablemask = shiftmask;
497 entry2.kio_station = dep->de_otherstation;
498 if (ioctl(kbdfd, KIOCGKEY, &entry2) < 0) {
499 perror("loadkeys: ioctl(KIOCGKEY)");
500 return (0);
502 entry1.kio_station = dep->de_otherstation;
503 if (ioctl(kbdfd, KIOCSKEY, &entry1) < 0) {
504 perror("loadkeys: ioctl(KIOCSKEY)");
505 return (0);
507 entry2.kio_station = dep->de_station;
508 if (ioctl(kbdfd, KIOCSKEY, &entry2) < 0) {
509 perror("loadkeys: ioctl(KIOCSKEY)");
510 return (0);
512 return (1);
516 %term TABLENAME INT CHAR CHARSTRING CONSTANT FKEY KEY SAME AS SWAP WITH
518 %union {
519 keyentry *keyentry;
520 int number;
523 %type <keyentry> entrylist entry
524 %type <number> CHARSTRING CHAR INT CONSTANT FKEY TABLENAME
525 %type <number> code expr term number
529 table:
530 table line
531 | /* null */
534 line:
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);
547 | '\n'
550 entrylist:
551 entrylist entry
554 * Append this entry to the end of the entry list.
556 register keyentry *kep;
557 kep = $1;
558 for (;;) {
559 if (kep->ke_next == NULL) {
560 kep->ke_next = $2;
561 break;
563 kep = kep->ke_next;
565 $$ = $1;
567 | entry
569 $$ = $1;
573 entry:
574 TABLENAME code
576 $$ = makeentry($1, $2);
580 code:
581 CHARSTRING
583 $$ = $1;
585 | CHAR
587 $$ = $1;
589 | INT
591 $$ = $1;
593 | '('
595 $$ = '(';
597 | ')'
599 $$ = ')';
601 | '+'
603 $$ = '+';
605 | expr
607 $$ = $1;
611 expr:
612 term
614 $$ = $1;
616 | expr '+' term
618 $$ = $1 + $3;
622 term:
623 CONSTANT
625 $$ = $1;
627 | FKEY '(' number ')'
629 if ($3 < 1 || $3 > 16)
630 yyerror("invalid function key number");
631 $$ = $1 + $3 - 1;
635 number:
638 $$ = $1;
640 | CHAR
642 if (isdigit($1))
643 $$ = $1 - '0';
644 else
645 yyerror("syntax error");
651 typedef struct {
652 char *w_string;
653 int w_type; /* token type */
654 int w_lval; /* yylval for this token */
655 } word_t;
658 * Table must be in alphabetical order.
660 word_t wordtab[] = {
661 { "all", TABLENAME, ALL },
662 { "alt", CONSTANT, ALT },
663 { "altg", TABLENAME, ALTGRAPHMASK },
664 { "altgraph", CONSTANT, ALTGRAPH },
665 { "as", AS, 0 },
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 },
693 { "key", KEY, 0 },
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 },
727 { "same", SAME, 0 },
728 { "shift", TABLENAME, SHIFTMASK },
729 { "shiftkeys", CONSTANT, SHIFTKEYS },
730 { "shiftlock", CONSTANT, SHIFTLOCK },
731 { "string", CONSTANT, STRING },
732 { "swap", SWAP, 0 },
733 { "systembit", CONSTANT, SYSTEMBIT },
734 { "tf", FKEY, TOPFUNC },
735 { "up", TABLENAME, UPMASK },
736 { "uparrow", CONSTANT, UPARROW },
737 { "with", WITH, 0 },
740 #define NWORDS (sizeof (wordtab) / sizeof (wordtab[0]))
742 static int
743 yylex()
745 register int c;
746 char tokbuf[256+1];
747 register char *cp;
748 register int tokentype;
750 while ((c = getc(infile)) == ' ' || c == '\t')
752 if (begline) {
753 lineno++;
754 begline = 0;
755 if (c == '#') {
756 while ((c = getc(infile)) != EOF && c != '\n')
760 if (c == EOF)
761 return (0); /* end marker */
762 if (c == '\n') {
763 begline = 1;
764 return (c);
767 switch (c) {
769 case '\'':
770 tokentype = CHAR;
771 if ((c = getc(infile)) == EOF)
772 yyerror("unterminated character constant");
773 if (c == '\n') {
774 (void) ungetc(c, infile);
775 yylval.number = '\'';
776 } else {
777 switch (c) {
779 case '\'':
780 yyerror("null character constant");
781 break;
783 case '\\':
784 yylval.number = readesc(infile, '\'', 1);
785 break;
787 default:
788 yylval.number = c;
789 break;
791 if ((c = getc(infile)) == EOF || c == '\n')
792 yyerror("unterminated character constant");
793 else if (c != '\'')
794 yyerror("only one character allowed in character constant");
796 break;
798 case '"':
799 if ((c = getc(infile)) == EOF)
800 yyerror("unterminated string constant");
801 if (c == '\n') {
802 (void) ungetc(c, infile);
803 tokentype = CHAR;
804 yylval.number = '"';
805 } else {
806 tokentype = CHARSTRING;
807 cp = &tokbuf[0];
808 do {
809 if (cp > &tokbuf[256])
810 yyerror("line too long");
811 if (c == '\\')
812 c = readesc(infile, '"', 0);
813 *cp++ = (char)c;
814 } while ((c = getc(infile)) != EOF && c != '\n' &&
815 c != '"');
816 if (c != '"')
817 yyerror("unterminated string constant");
818 *cp = '\0';
819 if (nstrings == 16)
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;
825 nstrings++;
827 break;
829 case '(':
830 case ')':
831 case '+':
832 tokentype = c;
833 break;
835 case '^':
836 if ((c = getc(infile)) == EOF)
837 yyerror("missing newline at end of line");
838 tokentype = CHAR;
839 if (c == ' ' || c == '\t' || c == '\n') {
841 * '^' by itself.
843 yylval.number = '^';
844 } else {
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);
852 break;
854 default:
855 cp = &tokbuf[0];
856 do {
857 if (cp > &tokbuf[256])
858 yyerror("line too long");
859 *cp++ = (char)c;
860 } while ((c = getc(infile)) != EOF && (isalnum(c) || c == '_'));
861 if (c == EOF)
862 yyerror("newline missing");
863 (void) ungetc(c, infile);
864 *cp = '\0';
865 if (strlen(tokbuf) == 1) {
866 tokentype = CHAR;
867 yylval.number = (unsigned char)tokbuf[0];
868 } else if (strlen(tokbuf) == 2 && tokbuf[0] == '^') {
869 tokentype = CHAR;
870 yylval.number = (unsigned char)(tokbuf[1] & 037);
871 } else {
872 word_t word;
873 register word_t *wptr;
874 char *ptr;
876 for (cp = &tokbuf[0]; (c = *cp) != '\0'; cp++) {
877 if (isupper(c))
878 *cp = tolower(c);
880 word.w_string = tokbuf;
881 wptr = (word_t *)bsearch((char *)&word,
882 (char *)wordtab, NWORDS, sizeof (word_t),
883 wordcmp);
884 if (wptr != NULL) {
885 yylval.number = wptr->w_lval;
886 tokentype = wptr->w_type;
887 } else {
888 yylval.number = strtol(tokbuf, &ptr, 0);
889 if (ptr == tokbuf)
890 yyerror("syntax error");
891 else
892 tokentype = INT;
894 break;
898 return (tokentype);
901 static int
902 readesc(stream, delim, single_char)
903 FILE *stream;
904 int delim;
905 int single_char;
907 register int c;
908 register int val;
909 register int i;
911 if ((c = getc(stream)) == EOF || c == '\n')
912 yyerror("unterminated character constant");
914 if (c >= '0' && c <= '7') {
915 val = 0;
916 i = 1;
917 for (;;) {
918 val = val*8 + c - '0';
919 if ((c = getc(stream)) == EOF || c == '\n')
920 yyerror("unterminated character constant");
921 if (c == delim)
922 break;
923 i++;
924 if (i > 3) {
925 if (single_char)
926 yyerror("escape sequence too long");
927 else
928 break;
930 if (c < '0' || c > '7') {
931 if (single_char)
932 yyerror("illegal character in escape sequence");
933 else
934 break;
937 (void) ungetc(c, stream);
938 } else {
939 switch (c) {
941 case 'n':
942 val = '\n';
943 break;
945 case 't':
946 val = '\t';
947 break;
949 case 'b':
950 val = '\b';
951 break;
953 case 'r':
954 val = '\r';
955 break;
957 case 'v':
958 val = '\v';
959 break;
961 case '\\':
962 val = '\\';
963 break;
965 default:
966 if (c == delim)
967 val = delim;
968 else
969 yyerror("illegal character in escape sequence");
972 return (val);
975 static int
976 wordcmp(const void *w1, const void *w2)
978 return (strcmp(
979 ((const word_t *)w1)->w_string,
980 ((const word_t *)w2)->w_string));
983 static int
984 yyerror(msg)
985 char *msg;
987 (void) fprintf(stderr, "%s, line %d: %s\n", infilename, lineno, msg);
988 exit(1);