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