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 /*
25 * Copyright (c) 1999 by Sun Microsystems, Inc.
26 * All rights reserved.
27 */
28
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>
41
42 #define ALL -1 /* special symbol for all tables */
43
44 static char keytable_dir[] = "/usr/share/lib/keytables/type_%d/";
45 static char layout_prefix[] = "layout_";
46
47 struct keyentry {
48 struct keyentry *ke_next;
49 struct kiockeymap ke_entry;
50 };
51
52 typedef struct keyentry keyentry;
53
54 static keyentry *firstentry;
55 static keyentry *lastentry;
56
57 struct dupentry {
58 struct dupentry *de_next;
59 int de_station;
60 int de_otherstation;
61 };
62
63 typedef struct dupentry dupentry;
64
65 static dupentry *firstduplicate;
66 static dupentry *lastduplicate;
67
68 static dupentry *firstswap;
69 static dupentry *lastswap;
70
71 static char *infilename;
72 static FILE *infile;
73 static int lineno;
74 static int begline;
75
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 */
82 };
83
84 static int nstrings = 5; /* start out with 5 strings */
85
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;
92
93 typedef struct {
94 int sm_mask;
95 smtype_t sm_type;
96 } smentry_t;
97
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 },
106 };
107
108
109 #define NSHIFTS (sizeof (shiftmasks) / sizeof (shiftmasks[0]))
110
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);
125
126 int
main(int argc,char ** argv)127 main(int argc, char **argv)
128 {
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;
140
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 */
151 }
152 set_layout(argv[1]);
153 exit(0);
154 default:
155 usage();
156 /* NOTREACHED */
157 }
158 }
159
160 if (argc > 1) usage();
161
162 if ((kbdfd = open("/dev/kbd", O_WRONLY)) < 0) {
163 /* perror("loadkeys: /dev/kbd"); */
164 return (1);
165 }
166
167 if (ioctl(kbdfd, KIOCTYPE, &type) < 0) {
168 /*
169 * There may not be a keyboard connected,
170 * return silently
171 */
172 return (1);
173 }
174
175 if (argc == 0) {
176 /* If no keyboard detected, exit silently. */
177 if (type == -1)
178 return (0);
179
180 if (ioctl(kbdfd, KIOCLAYOUT, &layout) < 0) {
181 perror("loadkeys: ioctl(KIOCLAYOUT)");
182 return (1);
183 }
184
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;
192 }
193
194 infile = open_mapping_file(pathbuf, infilename, explicit_name, type);
195 if (infile == NULL) return (1);
196
197 infilename = pathbuf;
198
199 lineno = 0;
200 begline = 1;
201 yyparse();
202 fclose(infile);
203
204 /*
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.
209 */
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;
216 }
217
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) {
222
223 case SM_INVALID:
224 continue;
225
226 case SM_NUMLOCK:
227 /*
228 * Defaults to NONL, not to a copy of
229 * the base entry.
230 */
231 if (kep->ke_entry.kio_entry != HOLE)
232 kep->ke_entry.kio_entry = NONL;
233 break;
234
235 case SM_UP:
236 /*
237 * Defaults to NOP, not to a copy of
238 * the base entry.
239 */
240 if (kep->ke_entry.kio_entry != HOLE)
241 kep->ke_entry.kio_entry = NOP;
242 break;
243 }
244 kep->ke_entry.kio_tablemask =
245 shiftmasks[shift].sm_mask;
246 if (!loadkey(kbdfd, kep))
247 return (1);
248 }
249 } else {
250 if (!loadkey(kbdfd, kep))
251 return (1);
252 }
253 }
254
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);
261 }
262 }
263 }
264
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);
271 }
272 }
273 }
274
275 close(kbdfd);
276 return (0);
277 }
278
279 static void
usage()280 usage()
281 {
282 (void) fprintf(stderr, "usage: loadkeys [ file ]\n");
283 exit(1);
284 }
285
286 static void
set_layout(char * arg)287 set_layout(char *arg)
288 {
289 int layout;
290 int ret;
291 int kbdfd;
292
293 layout = (int) strtol(arg, &arg, 0);
294 if (*arg != '\0') {
295 fprintf(stderr, "usage: loadkeys -s layoutnumber\n");
296 exit(1);
297 }
298
299 if ((kbdfd = open("/dev/kbd", O_WRONLY)) < 0) {
300 perror("/dev/kbd");
301 exit(1);
302 }
303
304 ret = ioctl(kbdfd, KIOCSLAYOUT, layout);
305 if (ret == -1) {
306 perror("KIOCSLAYOUT");
307 }
308
309 close(kbdfd);
310 }
311
312 /*
313 * Attempt to find the specified mapping file. Return a FILE * if found,
314 * else print a message on stderr and return NULL.
315 */
316 FILE *
open_mapping_file(char * pathbuf,char * name,boolean_t explicit_name,int type)317 open_mapping_file(char *pathbuf, char *name, boolean_t explicit_name, int type)
318 {
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;
325 }
326
327 /* Everything after this point applies only to relative names. */
328 if (*name == '/') goto fopen_fail;
329
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);
336 }
337 (void) strcat(pathbuf, name);
338 if ((infile = fopen(pathbuf, "r")) != NULL)
339 return (infile);
340
341 fopen_fail:
342 (void) fprintf(stderr, "loadkeys: ");
343 perror(name);
344 return (NULL);
345 }
346
347 /*
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.
351 */
352 static void
enter_mapentry(station,entrylistp)353 enter_mapentry(station, entrylistp)
354 int station;
355 keyentry *entrylistp;
356 {
357 register keyentry *kep;
358
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;
369 }
370 kep = kep->ke_next;
371 }
372 }
373
374 /*
375 * Allocate and fill in a new entry.
376 */
377 static keyentry *
makeentry(tablemask,entry)378 makeentry(tablemask, entry)
379 int tablemask;
380 int entry;
381 {
382 register keyentry *kep;
383 register int index;
384
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);
396 }
397
398 /*
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.
401 */
402 static void
duplicate_mapentry(station,otherstation)403 duplicate_mapentry(station, otherstation)
404 int station;
405 int otherstation;
406 {
407 register dupentry *dep;
408
409 if ((dep = (dupentry *) malloc((unsigned)sizeof (dupentry))) == NULL)
410 yyerror("out of memory for entries");
411
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;
420 }
421
422 /*
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.
425 */
426 static void
swap_mapentry(station,otherstation)427 swap_mapentry(station, otherstation)
428 int station;
429 int otherstation;
430 {
431 register dupentry *dep;
432
433 if ((dep = (dupentry *) malloc((unsigned)sizeof (dupentry))) == NULL)
434 yyerror("out of memory for entries");
435
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;
444 }
445
446 static int
loadkey(kbdfd,kep)447 loadkey(kbdfd, kep)
448 int kbdfd;
449 register keyentry *kep;
450 {
451 if (ioctl(kbdfd, KIOCSKEY, &kep->ke_entry) < 0) {
452 perror("loadkeys: ioctl(KIOCSKEY)");
453 return (0);
454 }
455 return (1);
456 }
457
458 static int
dupkey(kbdfd,dep,shiftmask)459 dupkey(kbdfd, dep, shiftmask)
460 int kbdfd;
461 register dupentry *dep;
462 int shiftmask;
463 {
464 struct kiockeymap entry;
465
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);
471 }
472 entry.kio_station = dep->de_station;
473 if (ioctl(kbdfd, KIOCSKEY, &entry) < 0) {
474 perror("loadkeys: ioctl(KIOCSKEY)");
475 return (0);
476 }
477 return (1);
478 }
479
480
481
482 static int
swapkey(kbdfd,dep,shiftmask)483 swapkey(kbdfd, dep, shiftmask)
484 int kbdfd;
485 register dupentry *dep;
486 int shiftmask;
487 {
488 struct kiockeymap entry1, entry2;
489
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);
495 }
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);
501 }
502 entry1.kio_station = dep->de_otherstation;
503 if (ioctl(kbdfd, KIOCSKEY, &entry1) < 0) {
504 perror("loadkeys: ioctl(KIOCSKEY)");
505 return (0);
506 }
507 entry2.kio_station = dep->de_station;
508 if (ioctl(kbdfd, KIOCSKEY, &entry2) < 0) {
509 perror("loadkeys: ioctl(KIOCSKEY)");
510 return (0);
511 }
512 return (1);
513 }
514 %}
515
516 %term TABLENAME INT CHAR CHARSTRING CONSTANT FKEY KEY SAME AS SWAP WITH
517
518 %union {
519 keyentry *keyentry;
520 int number;
521 };
522
523 %type <keyentry> entrylist entry
524 %type <number> CHARSTRING CHAR INT CONSTANT FKEY TABLENAME
525 %type <number> code expr term number
526
527 %%
528
529 table:
530 table line
531 | /* null */
532 ;
533
534 line:
535 KEY number entrylist '\n'
536 {
537 enter_mapentry($2, $3);
538 }
539 | KEY number SAME AS number '\n'
540 {
541 duplicate_mapentry($2, $5);
542 }
543 | SWAP number WITH number '\n'
544 {
545 swap_mapentry($2, $4);
546 }
547 | '\n'
548 ;
549
550 entrylist:
551 entrylist entry
552 {
553 /*
554 * Append this entry to the end of the entry list.
555 */
556 register keyentry *kep;
557 kep = $1;
558 for (;;) {
559 if (kep->ke_next == NULL) {
560 kep->ke_next = $2;
561 break;
562 }
563 kep = kep->ke_next;
564 }
565 $$ = $1;
566 }
567 | entry
568 {
569 $$ = $1;
570 }
571 ;
572
573 entry:
574 TABLENAME code
575 {
576 $$ = makeentry($1, $2);
577 }
578 ;
579
580 code:
581 CHARSTRING
582 {
583 $$ = $1;
584 }
585 | CHAR
586 {
587 $$ = $1;
588 }
589 | INT
590 {
591 $$ = $1;
592 }
593 | '('
594 {
595 $$ = '(';
596 }
597 | ')'
598 {
599 $$ = ')';
600 }
601 | '+'
602 {
603 $$ = '+';
604 }
605 | expr
606 {
607 $$ = $1;
608 }
609 ;
610
611 expr:
612 term
613 {
614 $$ = $1;
615 }
616 | expr '+' term
617 {
618 $$ = $1 + $3;
619 }
620 ;
621
622 term:
623 CONSTANT
624 {
625 $$ = $1;
626 }
627 | FKEY '(' number ')'
628 {
629 if ($3 < 1 || $3 > 16)
630 yyerror("invalid function key number");
631 $$ = $1 + $3 - 1;
632 }
633 ;
634
635 number:
636 INT
637 {
638 $$ = $1;
639 }
640 | CHAR
641 {
642 if (isdigit($1))
643 $$ = $1 - '0';
644 else
645 yyerror("syntax error");
646 }
647 ;
648
649 %%
650
651 typedef struct {
652 char *w_string;
653 int w_type; /* token type */
654 int w_lval; /* yylval for this token */
655 } word_t;
656
657 /*
658 * Table must be in alphabetical order.
659 */
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 },
738 };
739
740 #define NWORDS (sizeof (wordtab) / sizeof (wordtab[0]))
741
742 static int
yylex()743 yylex()
744 {
745 register int c;
746 char tokbuf[256+1];
747 register char *cp;
748 register int tokentype;
749
750 while ((c = getc(infile)) == ' ' || c == '\t')
751 ;
752 if (begline) {
753 lineno++;
754 begline = 0;
755 if (c == '#') {
756 while ((c = getc(infile)) != EOF && c != '\n')
757 ;
758 }
759 }
760 if (c == EOF)
761 return (0); /* end marker */
762 if (c == '\n') {
763 begline = 1;
764 return (c);
765 }
766
767 switch (c) {
768
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) {
778
779 case '\'':
780 yyerror("null character constant");
781 break;
782
783 case '\\':
784 yylval.number = readesc(infile, '\'', 1);
785 break;
786
787 default:
788 yylval.number = c;
789 break;
790 }
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");
795 }
796 break;
797
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++;
826 }
827 break;
828
829 case '(':
830 case ')':
831 case '+':
832 tokentype = c;
833 break;
834
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') {
840 /*
841 * '^' by itself.
842 */
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");
850 }
851 (void) ungetc(c, infile);
852 break;
853
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;
875
876 for (cp = &tokbuf[0]; (c = *cp) != '\0'; cp++) {
877 if (isupper(c))
878 *cp = tolower(c);
879 }
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;
893 }
894 break;
895 }
896 }
897
898 return (tokentype);
899 }
900
901 static int
readesc(stream,delim,single_char)902 readesc(stream, delim, single_char)
903 FILE *stream;
904 int delim;
905 int single_char;
906 {
907 register int c;
908 register int val;
909 register int i;
910
911 if ((c = getc(stream)) == EOF || c == '\n')
912 yyerror("unterminated character constant");
913
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;
929 }
930 if (c < '0' || c > '7') {
931 if (single_char)
932 yyerror("illegal character in escape sequence");
933 else
934 break;
935 }
936 }
937 (void) ungetc(c, stream);
938 } else {
939 switch (c) {
940
941 case 'n':
942 val = '\n';
943 break;
944
945 case 't':
946 val = '\t';
947 break;
948
949 case 'b':
950 val = '\b';
951 break;
952
953 case 'r':
954 val = '\r';
955 break;
956
957 case 'v':
958 val = '\v';
959 break;
960
961 case '\\':
962 val = '\\';
963 break;
964
965 default:
966 if (c == delim)
967 val = delim;
968 else
969 yyerror("illegal character in escape sequence");
970 }
971 }
972 return (val);
973 }
974
975 static int
wordcmp(const void * w1,const void * w2)976 wordcmp(const void *w1, const void *w2)
977 {
978 return (strcmp(
979 ((const word_t *)w1)->w_string,
980 ((const word_t *)w2)->w_string));
981 }
982
983 static int
yyerror(msg)984 yyerror(msg)
985 char *msg;
986 {
987 (void) fprintf(stderr, "%s, line %d: %s\n", infilename, lineno, msg);
988 exit(1);
989 }
990