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(const char *msg) __NORETURN; 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 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 280 usage() 281 { 282 (void) fprintf(stderr, "usage: loadkeys [ file ]\n"); 283 exit(1); 284 } 285 286 static void 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 * 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 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 * 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 (void) 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 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 (void) 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 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 (void) 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 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 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 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 (void) 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 (void) 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 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 (void) 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 (void) 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 (void) yyerror( 793 "unterminated character constant"); 794 else if (c != '\'') 795 (void) yyerror("only one character allowed " 796 "in character constant"); 797 } 798 break; 799 800 case '"': 801 if ((c = getc(infile)) == EOF) 802 (void) yyerror("unterminated string constant"); 803 if (c == '\n') { 804 (void) ungetc(c, infile); 805 tokentype = CHAR; 806 yylval.number = '"'; 807 } else { 808 tokentype = CHARSTRING; 809 cp = &tokbuf[0]; 810 do { 811 if (cp > &tokbuf[256]) 812 (void) yyerror("line too long"); 813 if (c == '\\') 814 c = readesc(infile, '"', 0); 815 *cp++ = (char)c; 816 } while ((c = getc(infile)) != EOF && c != '\n' && 817 c != '"'); 818 if (c != '"') 819 (void) yyerror("unterminated string constant"); 820 *cp = '\0'; 821 if (nstrings == 16) 822 (void) yyerror("too many strings"); 823 if ((int) strlen(tokbuf) > KTAB_STRLEN) 824 (void) yyerror("string too long"); 825 strings[nstrings] = strdup(tokbuf); 826 yylval.number = STRING+nstrings; 827 nstrings++; 828 } 829 break; 830 831 case '(': 832 case ')': 833 case '+': 834 tokentype = c; 835 break; 836 837 case '^': 838 if ((c = getc(infile)) == EOF) 839 (void) yyerror("missing newline at end of line"); 840 tokentype = CHAR; 841 if (c == ' ' || c == '\t' || c == '\n') { 842 /* 843 * '^' by itself. 844 */ 845 yylval.number = '^'; 846 } else { 847 yylval.number = c & 037; 848 if ((c = getc(infile)) == EOF) 849 (void) yyerror("missing newline at end of line"); 850 if (c != ' ' && c != '\t' && c != '\n') 851 (void) yyerror("invalid control character"); 852 } 853 (void) ungetc(c, infile); 854 break; 855 856 default: 857 cp = &tokbuf[0]; 858 do { 859 if (cp > &tokbuf[256]) 860 (void) yyerror("line too long"); 861 *cp++ = (char)c; 862 } while ((c = getc(infile)) != EOF && (isalnum(c) || c == '_')); 863 if (c == EOF) 864 (void) yyerror("newline missing"); 865 (void) ungetc(c, infile); 866 *cp = '\0'; 867 if (strlen(tokbuf) == 1) { 868 tokentype = CHAR; 869 yylval.number = (unsigned char)tokbuf[0]; 870 } else if (strlen(tokbuf) == 2 && tokbuf[0] == '^') { 871 tokentype = CHAR; 872 yylval.number = (unsigned char)(tokbuf[1] & 037); 873 } else { 874 word_t word; 875 register word_t *wptr; 876 char *ptr; 877 878 for (cp = &tokbuf[0]; (c = *cp) != '\0'; cp++) { 879 if (isupper(c)) 880 *cp = tolower(c); 881 } 882 word.w_string = tokbuf; 883 wptr = (word_t *)bsearch((char *)&word, 884 (char *)wordtab, NWORDS, sizeof (word_t), 885 wordcmp); 886 if (wptr != NULL) { 887 yylval.number = wptr->w_lval; 888 tokentype = wptr->w_type; 889 } else { 890 yylval.number = strtol(tokbuf, &ptr, 0); 891 if (ptr == tokbuf) 892 (void) yyerror("syntax error"); 893 else 894 tokentype = INT; 895 } 896 break; 897 } 898 } 899 900 return (tokentype); 901 } 902 903 static int 904 readesc(stream, delim, single_char) 905 FILE *stream; 906 int delim; 907 int single_char; 908 { 909 register int c; 910 register int val; 911 register int i; 912 913 if ((c = getc(stream)) == EOF || c == '\n') 914 (void) yyerror("unterminated character constant"); 915 916 if (c >= '0' && c <= '7') { 917 val = 0; 918 i = 1; 919 for (;;) { 920 val = val*8 + c - '0'; 921 if ((c = getc(stream)) == EOF || c == '\n') 922 (void) yyerror( 923 "unterminated character constant"); 924 if (c == delim) 925 break; 926 i++; 927 if (i > 3) { 928 if (single_char) 929 (void) yyerror( 930 "escape sequence too long"); 931 else 932 break; 933 } 934 if (c < '0' || c > '7') { 935 if (single_char) 936 (void) yyerror("illegal character " 937 "in escape sequence"); 938 else 939 break; 940 } 941 } 942 (void) ungetc(c, stream); 943 } else { 944 switch (c) { 945 946 case 'n': 947 val = '\n'; 948 break; 949 950 case 't': 951 val = '\t'; 952 break; 953 954 case 'b': 955 val = '\b'; 956 break; 957 958 case 'r': 959 val = '\r'; 960 break; 961 962 case 'v': 963 val = '\v'; 964 break; 965 966 case '\\': 967 val = '\\'; 968 break; 969 970 default: 971 if (c == delim) 972 val = delim; 973 else 974 (void) yyerror("illegal character " 975 "in escape sequence"); 976 } 977 } 978 return (val); 979 } 980 981 static int 982 wordcmp(const void *w1, const void *w2) 983 { 984 return (strcmp( 985 ((const word_t *)w1)->w_string, 986 ((const word_t *)w2)->w_string)); 987 } 988 989 static int 990 yyerror(const char *msg) 991 { 992 (void) fprintf(stderr, "%s, line %d: %s\n", infilename, lineno, msg); 993 exit(1); 994 } 995