dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / loadkeys / loadkeys.y
blobfae5f7850a13afe6f82d7cb67d9d7db01cd84707
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
24 #pragma ident "%Z%%M% %I% %E% SMI"
27 * Copyright (c) 1999 by Sun Microsystems, Inc.
28 * All rights reserved.
31 #include <sys/param.h>
32 #include <ctype.h>
33 #include <stdio.h>
34 #include <search.h>
35 #include <string.h>
36 #include <malloc.h>
37 #include <fcntl.h>
38 #include <stdlib.h>
39 #include <errno.h>
40 #include <unistd.h>
41 #include <sys/kbd.h>
42 #include <sys/kbio.h>
44 #define ALL -1 /* special symbol for all tables */
47 * SunOS 4.x and Solaris 2.[1234] put Type 4 key tables into
48 * the keytables directory with no type qualification.
49 * If we're a SPARC, we might be using an NFS server that
50 * doesn't have the new type-qualified directories.
51 * (loadkeys wasn't used on non-SPARCs in 2.[1234].)
53 #ifdef sparc
54 #define COMPATIBILITY_DIR
55 #endif
57 static char keytable_dir[] = "/usr/share/lib/keytables/type_%d/";
58 #ifdef COMPATIBILITY_DIR
59 static char keytable_dir2[] = "/usr/share/lib/keytables/";
60 #endif
61 static char layout_prefix[] = "layout_";
63 struct keyentry {
64 struct keyentry *ke_next;
65 struct kiockeymap ke_entry;
68 typedef struct keyentry keyentry;
70 static keyentry *firstentry;
71 static keyentry *lastentry;
73 struct dupentry {
74 struct dupentry *de_next;
75 int de_station;
76 int de_otherstation;
79 typedef struct dupentry dupentry;
81 static dupentry *firstduplicate;
82 static dupentry *lastduplicate;
84 static dupentry *firstswap;
85 static dupentry *lastswap;
87 static char *infilename;
88 static FILE *infile;
89 static int lineno;
90 static int begline;
92 static char *strings[16] = {
93 "\033[H", /* HOMEARROW */
94 "\033[A", /* UPARROW */
95 "\033[B", /* DOWNARROW */
96 "\033[D", /* LEFTARROW */
97 "\033[C", /* RIGHTARROW */
100 static int nstrings = 5; /* start out with 5 strings */
102 typedef enum {
103 SM_INVALID, /* this shift mask is invalid for this keyboard */
104 SM_NORMAL, /* "normal", valid shift mask */
105 SM_NUMLOCK, /* "Num Lock" shift mask */
106 SM_UP /* "Up" shift mask */
107 } smtype_t;
109 typedef struct {
110 int sm_mask;
111 smtype_t sm_type;
112 } smentry_t;
114 static smentry_t shiftmasks[] = {
115 { 0, SM_NORMAL },
116 { SHIFTMASK, SM_NORMAL },
117 { CAPSMASK, SM_NORMAL },
118 { CTRLMASK, SM_NORMAL },
119 { ALTGRAPHMASK, SM_NORMAL },
120 { NUMLOCKMASK, SM_NUMLOCK },
121 { UPMASK, SM_UP },
125 #define NSHIFTS (sizeof (shiftmasks) / sizeof (shiftmasks[0]))
127 static void enter_mapentry(int station, keyentry *entrylistp);
128 static keyentry *makeentry(int tablemask, int entry);
129 static int loadkey(int kbdfd, keyentry *kep);
130 static int dupkey(int kbdfd, dupentry *dep, int shiftmask);
131 static int swapkey(int kbdfd, dupentry *dep, int shiftmask);
132 static int yylex();
133 static int readesc(FILE *stream, int delim, int single_char);
134 static int wordcmp(const void *w1, const void *w2);
135 static int yyerror(char *msg);
136 static void usage(void);
137 static void set_layout(char *arg);
138 static FILE *open_mapping_file(char *pathbuf, char *name,
139 boolean_t explicit_name, int type);
142 main(argc, argv)
143 int argc;
144 char **argv;
146 register int kbdfd;
147 int type;
148 int layout;
149 /* maxint is 8 hex digits. */
150 char layout_filename[sizeof(layout_prefix)+8];
151 char pathbuf[MAXPATHLEN];
152 register int shift;
153 struct kiockeymap mapentry;
154 register keyentry *kep;
155 register dupentry *dep;
156 boolean_t explicit_name;
158 while(++argv, --argc) {
159 if(argv[0][0] != '-') break;
160 switch(argv[0][1]) {
161 case 'e':
162 /* -e obsolete, silently ignore */
163 break;
164 case 's':
165 if (argc != 2) {
166 usage();
167 /* NOTREACHED */
169 set_layout(argv[1]);
170 exit(0);
171 default:
172 usage();
173 /* NOTREACHED */
177 if (argc > 1) usage();
179 if ((kbdfd = open("/dev/kbd", O_WRONLY)) < 0) {
180 /* perror("loadkeys: /dev/kbd"); */
181 return (1);
184 if (ioctl(kbdfd, KIOCTYPE, &type) < 0) {
186 * There may not be a keyboard connected,
187 * return silently
189 return (1);
192 if (argc == 0) {
193 /* If no keyboard detected, exit silently. */
194 if (type == -1)
195 return (0);
197 if (ioctl(kbdfd, KIOCLAYOUT, &layout) < 0) {
198 perror("loadkeys: ioctl(KIOCLAYOUT)");
199 return (1);
202 (void) sprintf(layout_filename,
203 "%s%.2x", layout_prefix, layout);
204 infilename = layout_filename;
205 explicit_name = B_FALSE;
206 } else {
207 infilename = argv[0];
208 explicit_name = B_TRUE;
211 infile = open_mapping_file(pathbuf, infilename, explicit_name, type);
212 if (infile == NULL) return (1);
214 infilename = pathbuf;
216 lineno = 0;
217 begline = 1;
218 yyparse();
219 fclose(infile);
222 * See which shift masks are valid for this keyboard.
223 * We do that by trying to get the entry for keystation 0 and that
224 * shift mask; if the "ioctl" fails, we assume it's because the shift
225 * mask is invalid.
227 for (shift = 0; shift < NSHIFTS; shift++) {
228 mapentry.kio_tablemask =
229 shiftmasks[shift].sm_mask;
230 mapentry.kio_station = 0;
231 if (ioctl(kbdfd, KIOCGKEY, &mapentry) < 0)
232 shiftmasks[shift].sm_type = SM_INVALID;
235 for (kep = firstentry; kep != NULL; kep = kep->ke_next) {
236 if (kep->ke_entry.kio_tablemask == ALL) {
237 for (shift = 0; shift < NSHIFTS; shift++) {
238 switch (shiftmasks[shift].sm_type) {
240 case SM_INVALID:
241 continue;
243 case SM_NUMLOCK:
245 * Defaults to NONL, not to a copy of
246 * the base entry.
248 if (kep->ke_entry.kio_entry != HOLE)
249 kep->ke_entry.kio_entry = NONL;
250 break;
252 case SM_UP:
254 * Defaults to NOP, not to a copy of
255 * the base entry.
257 if (kep->ke_entry.kio_entry != HOLE)
258 kep->ke_entry.kio_entry = NOP;
259 break;
261 kep->ke_entry.kio_tablemask =
262 shiftmasks[shift].sm_mask;
263 if (!loadkey(kbdfd, kep))
264 return (1);
266 } else {
267 if (!loadkey(kbdfd, kep))
268 return (1);
272 for (dep = firstswap; dep != NULL; dep = dep->de_next) {
273 for (shift = 0; shift < NSHIFTS; shift++) {
274 if (shiftmasks[shift].sm_type != SM_INVALID) {
275 if (!swapkey(kbdfd, dep,
276 shiftmasks[shift].sm_mask))
277 return (0);
282 for (dep = firstduplicate; dep != NULL; dep = dep->de_next) {
283 for (shift = 0; shift < NSHIFTS; shift++) {
284 if (shiftmasks[shift].sm_type != SM_INVALID) {
285 if (!dupkey(kbdfd, dep,
286 shiftmasks[shift].sm_mask))
287 return (0);
292 close(kbdfd);
293 return (0);
296 static void
297 usage()
299 (void) fprintf(stderr, "usage: loadkeys [ file ]\n");
300 exit(1);
303 static void
304 set_layout(char *arg)
306 int layout;
307 int ret;
308 int kbdfd;
310 layout = (int) strtol(arg, &arg, 0);
311 if (*arg != '\0') {
312 fprintf(stderr, "usage: loadkeys -s layoutnumber\n");
313 exit(1);
316 if ((kbdfd = open("/dev/kbd", O_WRONLY)) < 0) {
317 perror("/dev/kbd");
318 exit(1);
321 ret = ioctl(kbdfd, KIOCSLAYOUT, layout);
322 if (ret == -1) {
323 perror("KIOCSLAYOUT");
326 close(kbdfd);
330 * Attempt to find the specified mapping file. Return a FILE * if found,
331 * else print a message on stderr and return NULL.
333 FILE *
334 open_mapping_file(
335 char *pathbuf,
336 char *name,
337 boolean_t explicit_name,
338 int type
340 /* If the user specified the name, try it "raw". */
341 if (explicit_name) {
342 strcpy(pathbuf, name);
343 infile = fopen(pathbuf, "r");
344 if (infile) return (infile);
345 if (errno != ENOENT) goto fopen_fail;
348 /* Everything after this point applies only to relative names. */
349 if (*name == '/') goto fopen_fail;
351 /* Try the type-qualified directory name. */
352 sprintf(pathbuf, keytable_dir, type);
353 if ((int)(strlen(pathbuf) + strlen(name) + 1) >= MAXPATHLEN) {
354 (void) fprintf(stderr, "loadkeys: Name %s is too long\n",
355 name);
356 return (NULL);
358 (void) strcat(pathbuf, name);
359 infile = fopen(pathbuf, "r");
360 if (infile) return (infile);
361 if (errno != ENOENT) goto fopen_fail;
363 #ifdef COMPATIBILITY_DIR
364 /* If not, and either the name was specified explicitly */
365 /* or this is a type 4... */
366 if (explicit_name || type == KB_SUN4) {
367 /* Try the compatibility name. */
368 /* No need to check len here, it's shorter. */
369 (void) strcpy(pathbuf, keytable_dir2);
370 (void) strcat(pathbuf, infilename);
371 infile = fopen(pathbuf, "r");
372 if (infile) return (infile);
373 if (errno != ENOENT) goto fopen_fail;
375 #endif
377 fopen_fail:
378 (void) fprintf(stderr, "loadkeys: ");
379 perror(name);
380 return (NULL);
384 * We have a list of entries for a given keystation, and the keystation number
385 * for that keystation; put that keystation number into all the entries in that
386 * list, and chain that list to the end of the main list of entries.
388 static void
389 enter_mapentry(station, entrylistp)
390 int station;
391 keyentry *entrylistp;
393 register keyentry *kep;
395 if (lastentry == NULL)
396 firstentry = entrylistp;
397 else
398 lastentry->ke_next = entrylistp;
399 kep = entrylistp;
400 for (;;) {
401 kep->ke_entry.kio_station = (u_char)station;
402 if (kep->ke_next == NULL) {
403 lastentry = kep;
404 break;
406 kep = kep->ke_next;
411 * Allocate and fill in a new entry.
413 static keyentry *
414 makeentry(tablemask, entry)
415 int tablemask;
416 int entry;
418 register keyentry *kep;
419 register int index;
421 if ((kep = (keyentry *) malloc((unsigned)sizeof (keyentry))) == NULL)
422 yyerror("out of memory for entries");
423 kep->ke_next = NULL;
424 kep->ke_entry.kio_tablemask = tablemask;
425 kep->ke_entry.kio_station = 0;
426 kep->ke_entry.kio_entry = (u_short)entry;
427 index = entry - STRING;
428 if (index >= 0 && index <= 15)
429 (void) strncpy(kep->ke_entry.kio_string, strings[index],
430 KTAB_STRLEN);
431 return (kep);
435 * Make a set of entries for a keystation that indicate that that keystation's
436 * settings should be copied from another keystation's settings.
438 static void
439 duplicate_mapentry(station, otherstation)
440 int station;
441 int otherstation;
443 register dupentry *dep;
445 if ((dep = (dupentry *) malloc((unsigned)sizeof (dupentry))) == NULL)
446 yyerror("out of memory for entries");
448 if (lastduplicate == NULL)
449 firstduplicate = dep;
450 else
451 lastduplicate->de_next = dep;
452 lastduplicate = dep;
453 dep->de_next = NULL;
454 dep->de_station = station;
455 dep->de_otherstation = otherstation;
459 * Make a set of entries for a keystation that indicate that that keystation's
460 * settings should be swapped with another keystation's settings.
462 static void
463 swap_mapentry(station, otherstation)
464 int station;
465 int otherstation;
467 register dupentry *dep;
469 if ((dep = (dupentry *) malloc((unsigned)sizeof (dupentry))) == NULL)
470 yyerror("out of memory for entries");
472 if (lastswap == NULL)
473 firstswap = dep;
474 else
475 lastswap->de_next = dep;
476 lastswap = dep;
477 dep->de_next = NULL;
478 dep->de_station = station;
479 dep->de_otherstation = otherstation;
482 static int
483 loadkey(kbdfd, kep)
484 int kbdfd;
485 register keyentry *kep;
487 if (ioctl(kbdfd, KIOCSKEY, &kep->ke_entry) < 0) {
488 perror("loadkeys: ioctl(KIOCSKEY)");
489 return (0);
491 return (1);
494 static int
495 dupkey(kbdfd, dep, shiftmask)
496 int kbdfd;
497 register dupentry *dep;
498 int shiftmask;
500 struct kiockeymap entry;
502 entry.kio_tablemask = shiftmask;
503 entry.kio_station = dep->de_otherstation;
504 if (ioctl(kbdfd, KIOCGKEY, &entry) < 0) {
505 perror("loadkeys: ioctl(KIOCGKEY)");
506 return (0);
508 entry.kio_station = dep->de_station;
509 if (ioctl(kbdfd, KIOCSKEY, &entry) < 0) {
510 perror("loadkeys: ioctl(KIOCSKEY)");
511 return (0);
513 return (1);
518 static int
519 swapkey(kbdfd, dep, shiftmask)
520 int kbdfd;
521 register dupentry *dep;
522 int shiftmask;
524 struct kiockeymap entry1, entry2;
526 entry1.kio_tablemask = shiftmask;
527 entry1.kio_station = dep->de_station;
528 if (ioctl(kbdfd, KIOCGKEY, &entry1) < 0) {
529 perror("loadkeys: ioctl(KIOCGKEY)");
530 return (0);
532 entry2.kio_tablemask = shiftmask;
533 entry2.kio_station = dep->de_otherstation;
534 if (ioctl(kbdfd, KIOCGKEY, &entry2) < 0) {
535 perror("loadkeys: ioctl(KIOCGKEY)");
536 return (0);
538 entry1.kio_station = dep->de_otherstation;
539 if (ioctl(kbdfd, KIOCSKEY, &entry1) < 0) {
540 perror("loadkeys: ioctl(KIOCSKEY)");
541 return (0);
543 entry2.kio_station = dep->de_station;
544 if (ioctl(kbdfd, KIOCSKEY, &entry2) < 0) {
545 perror("loadkeys: ioctl(KIOCSKEY)");
546 return (0);
548 return (1);
552 %term TABLENAME INT CHAR CHARSTRING CONSTANT FKEY KEY SAME AS SWAP WITH
554 %union {
555 keyentry *keyentry;
556 int number;
559 %type <keyentry> entrylist entry
560 %type <number> CHARSTRING CHAR INT CONSTANT FKEY TABLENAME
561 %type <number> code expr term number
565 table:
566 table line
567 | /* null */
570 line:
571 KEY number entrylist '\n'
573 enter_mapentry($2, $3);
575 | KEY number SAME AS number '\n'
577 duplicate_mapentry($2, $5);
579 | SWAP number WITH number '\n'
581 swap_mapentry($2, $4);
583 | '\n'
586 entrylist:
587 entrylist entry
590 * Append this entry to the end of the entry list.
592 register keyentry *kep;
593 kep = $1;
594 for (;;) {
595 if (kep->ke_next == NULL) {
596 kep->ke_next = $2;
597 break;
599 kep = kep->ke_next;
601 $$ = $1;
603 | entry
605 $$ = $1;
609 entry:
610 TABLENAME code
612 $$ = makeentry($1, $2);
616 code:
617 CHARSTRING
619 $$ = $1;
621 | CHAR
623 $$ = $1;
625 | '('
627 $$ = '(';
629 | ')'
631 $$ = ')';
633 | '+'
635 $$ = '+';
637 | expr
639 $$ = $1;
643 expr:
644 term
646 $$ = $1;
648 | expr '+' term
650 $$ = $1 + $3;
654 term:
655 CONSTANT
657 $$ = $1;
659 | FKEY '(' number ')'
661 if ($3 < 1 || $3 > 16)
662 yyerror("invalid function key number");
663 $$ = $1 + $3 - 1;
667 number:
670 $$ = $1;
672 | CHAR
674 if (isdigit($1))
675 $$ = $1 - '0';
676 else
677 yyerror("syntax error");
683 typedef struct {
684 char *w_string;
685 int w_type; /* token type */
686 int w_lval; /* yylval for this token */
687 } word_t;
690 * Table must be in alphabetical order.
692 word_t wordtab[] = {
693 { "all", TABLENAME, ALL },
694 { "alt", CONSTANT, ALT },
695 { "altg", TABLENAME, ALTGRAPHMASK },
696 { "altgraph", CONSTANT, ALTGRAPH },
697 { "as", AS, 0 },
698 { "base", TABLENAME, 0 },
699 { "bf", FKEY, BOTTOMFUNC },
700 { "buckybits", CONSTANT, BUCKYBITS },
701 { "caps", TABLENAME, CAPSMASK },
702 { "capslock", CONSTANT, CAPSLOCK },
703 { "compose", CONSTANT, COMPOSE },
704 { "ctrl", TABLENAME, CTRLMASK },
705 { "downarrow", CONSTANT, DOWNARROW },
706 { "error", CONSTANT, ERROR },
707 { "fa_acute", CONSTANT, FA_ACUTE },
708 { "fa_cedilla", CONSTANT, FA_CEDILLA },
709 { "fa_cflex", CONSTANT, FA_CFLEX },
710 { "fa_grave", CONSTANT, FA_GRAVE },
711 { "fa_tilde", CONSTANT, FA_TILDE },
712 { "fa_umlaut", CONSTANT, FA_UMLAUT },
713 { "hole", CONSTANT, HOLE },
714 { "homearrow", CONSTANT, HOMEARROW },
715 { "idle", CONSTANT, IDLE },
716 { "key", KEY, 0 },
717 { "leftarrow", CONSTANT, LEFTARROW },
718 { "leftctrl", CONSTANT, LEFTCTRL },
719 { "leftshift", CONSTANT, LEFTSHIFT },
720 { "lf", FKEY, LEFTFUNC },
721 { "metabit", CONSTANT, METABIT },
722 { "nonl", CONSTANT, NONL },
723 { "nop", CONSTANT, NOP },
724 { "numl", TABLENAME, NUMLOCKMASK },
725 { "numlock", CONSTANT, NUMLOCK },
726 { "oops", CONSTANT, OOPS },
727 { "pad0", CONSTANT, PAD0 },
728 { "pad1", CONSTANT, PAD1 },
729 { "pad2", CONSTANT, PAD2 },
730 { "pad3", CONSTANT, PAD3 },
731 { "pad4", CONSTANT, PAD4 },
732 { "pad5", CONSTANT, PAD5 },
733 { "pad6", CONSTANT, PAD6 },
734 { "pad7", CONSTANT, PAD7 },
735 { "pad8", CONSTANT, PAD8 },
736 { "pad9", CONSTANT, PAD9 },
737 { "paddot", CONSTANT, PADDOT },
738 { "padenter", CONSTANT, PADENTER },
739 { "padequal", CONSTANT, PADEQUAL },
740 { "padminus", CONSTANT, PADMINUS },
741 { "padplus", CONSTANT, PADPLUS },
742 { "padsep", CONSTANT, PADSEP },
743 { "padslash", CONSTANT, PADSLASH },
744 { "padstar", CONSTANT, PADSTAR },
745 { "reset", CONSTANT, RESET },
746 { "rf", FKEY, RIGHTFUNC },
747 { "rightarrow", CONSTANT, RIGHTARROW },
748 { "rightctrl", CONSTANT, RIGHTCTRL },
749 { "rightshift", CONSTANT, RIGHTSHIFT },
750 { "same", SAME, 0 },
751 { "shift", TABLENAME, SHIFTMASK },
752 { "shiftkeys", CONSTANT, SHIFTKEYS },
753 { "shiftlock", CONSTANT, SHIFTLOCK },
754 { "string", CONSTANT, STRING },
755 { "swap", SWAP, 0 },
756 { "systembit", CONSTANT, SYSTEMBIT },
757 { "tf", FKEY, TOPFUNC },
758 { "up", TABLENAME, UPMASK },
759 { "uparrow", CONSTANT, UPARROW },
760 { "with", WITH, 0 },
763 #define NWORDS (sizeof (wordtab) / sizeof (wordtab[0]))
765 static int
766 yylex()
768 register int c;
769 char tokbuf[256+1];
770 register char *cp;
771 register int tokentype;
773 while ((c = getc(infile)) == ' ' || c == '\t')
775 if (begline) {
776 lineno++;
777 begline = 0;
778 if (c == '#') {
779 while ((c = getc(infile)) != EOF && c != '\n')
783 if (c == EOF)
784 return (0); /* end marker */
785 if (c == '\n') {
786 begline = 1;
787 return (c);
790 switch (c) {
792 case '\'':
793 tokentype = CHAR;
794 if ((c = getc(infile)) == EOF)
795 yyerror("unterminated character constant");
796 if (c == '\n') {
797 (void) ungetc(c, infile);
798 yylval.number = '\'';
799 } else {
800 switch (c) {
802 case '\'':
803 yyerror("null character constant");
804 break;
806 case '\\':
807 yylval.number = readesc(infile, '\'', 1);
808 break;
810 default:
811 yylval.number = c;
812 break;
814 if ((c = getc(infile)) == EOF || c == '\n')
815 yyerror("unterminated character constant");
816 else if (c != '\'')
817 yyerror("only one character allowed in character constant");
819 break;
821 case '"':
822 if ((c = getc(infile)) == EOF)
823 yyerror("unterminated string constant");
824 if (c == '\n') {
825 (void) ungetc(c, infile);
826 tokentype = CHAR;
827 yylval.number = '"';
828 } else {
829 tokentype = CHARSTRING;
830 cp = &tokbuf[0];
831 do {
832 if (cp > &tokbuf[256])
833 yyerror("line too long");
834 if (c == '\\')
835 c = readesc(infile, '"', 0);
836 *cp++ = (char)c;
837 } while ((c = getc(infile)) != EOF && c != '\n' &&
838 c != '"');
839 if (c != '"')
840 yyerror("unterminated string constant");
841 *cp = '\0';
842 if (nstrings == 16)
843 yyerror("too many strings");
844 if ((int) strlen(tokbuf) > KTAB_STRLEN)
845 yyerror("string too long");
846 strings[nstrings] = strdup(tokbuf);
847 yylval.number = STRING+nstrings;
848 nstrings++;
850 break;
852 case '(':
853 case ')':
854 case '+':
855 tokentype = c;
856 break;
858 case '^':
859 if ((c = getc(infile)) == EOF)
860 yyerror("missing newline at end of line");
861 tokentype = CHAR;
862 if (c == ' ' || c == '\t' || c == '\n') {
864 * '^' by itself.
866 yylval.number = '^';
867 } else {
868 yylval.number = c & 037;
869 if ((c = getc(infile)) == EOF)
870 yyerror("missing newline at end of line");
871 if (c != ' ' && c != '\t' && c != '\n')
872 yyerror("invalid control character");
874 (void) ungetc(c, infile);
875 break;
877 default:
878 cp = &tokbuf[0];
879 do {
880 if (cp > &tokbuf[256])
881 yyerror("line too long");
882 *cp++ = (char)c;
883 } while ((c = getc(infile)) != EOF && (isalnum(c) || c == '_'));
884 if (c == EOF)
885 yyerror("newline missing");
886 (void) ungetc(c, infile);
887 *cp = '\0';
888 if (strlen(tokbuf) == 1) {
889 tokentype = CHAR;
890 yylval.number = (unsigned char)tokbuf[0];
891 } else if (strlen(tokbuf) == 2 && tokbuf[0] == '^') {
892 tokentype = CHAR;
893 yylval.number = (unsigned char)(tokbuf[1] & 037);
894 } else {
895 word_t word;
896 register word_t *wptr;
897 char *ptr;
899 for (cp = &tokbuf[0]; (c = *cp) != '\0'; cp++) {
900 if (isupper(c))
901 *cp = tolower(c);
903 word.w_string = tokbuf;
904 wptr = (word_t *)bsearch((char *)&word,
905 (char *)wordtab, NWORDS, sizeof (word_t),
906 wordcmp);
907 if (wptr != NULL) {
908 yylval.number = wptr->w_lval;
909 tokentype = wptr->w_type;
910 } else {
911 yylval.number = strtol(tokbuf, &ptr, 10);
912 if (ptr == tokbuf)
913 yyerror("syntax error");
914 else
915 tokentype = INT;
917 break;
921 return (tokentype);
924 static int
925 readesc(stream, delim, single_char)
926 FILE *stream;
927 int delim;
928 int single_char;
930 register int c;
931 register int val;
932 register int i;
934 if ((c = getc(stream)) == EOF || c == '\n')
935 yyerror("unterminated character constant");
937 if (c >= '0' && c <= '7') {
938 val = 0;
939 i = 1;
940 for (;;) {
941 val = val*8 + c - '0';
942 if ((c = getc(stream)) == EOF || c == '\n')
943 yyerror("unterminated character constant");
944 if (c == delim)
945 break;
946 i++;
947 if (i > 3) {
948 if (single_char)
949 yyerror("escape sequence too long");
950 else
951 break;
953 if (c < '0' || c > '7') {
954 if (single_char)
955 yyerror("illegal character in escape sequence");
956 else
957 break;
960 (void) ungetc(c, stream);
961 } else {
962 switch (c) {
964 case 'n':
965 val = '\n';
966 break;
968 case 't':
969 val = '\t';
970 break;
972 case 'b':
973 val = '\b';
974 break;
976 case 'r':
977 val = '\r';
978 break;
980 case 'v':
981 val = '\v';
982 break;
984 case '\\':
985 val = '\\';
986 break;
988 default:
989 if (c == delim)
990 val = delim;
991 else
992 yyerror("illegal character in escape sequence");
995 return (val);
998 static int
999 wordcmp(const void *w1, const void *w2)
1001 return (strcmp(
1002 ((const word_t *)w1)->w_string,
1003 ((const word_t *)w2)->w_string));
1006 static int
1007 yyerror(msg)
1008 char *msg;
1010 (void) fprintf(stderr, "%s, line %d: %s\n", infilename, lineno, msg);
1011 exit(1);