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 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 299 usage() 300 { 301 (void) fprintf(stderr, "usage: loadkeys [ file ]\n"); 302 exit(1); 303 } 304 305 static void 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 * 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 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 * 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 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 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 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 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 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 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 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 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 1009 yyerror(msg) 1010 char *msg; 1011 { 1012 (void) fprintf(stderr, "%s, line %d: %s\n", infilename, lineno, msg); 1013 exit(1); 1014 } 1015