1 /* 2 * Copyright (c) 1984, 1985, 1986 by the Regents of the 3 * University of California and by Gregory Glenn Minshall. 4 * 5 * Permission to use, copy, modify, and distribute these 6 * programs and their documentation for any purpose and 7 * without fee is hereby granted, provided that this 8 * copyright and permission appear on all copies and 9 * supporting documentation, the name of the Regents of 10 * the University of California not be used in advertising 11 * or publicity pertaining to distribution of the programs 12 * without specific prior permission, and notice be given in 13 * supporting documentation that copying and distribution is 14 * by permission of the Regents of the University of California 15 * and by Gregory Glenn Minshall. Neither the Regents of the 16 * University of California nor Gregory Glenn Minshall make 17 * representations about the suitability of this software 18 * for any purpose. It is provided "as is" without 19 * express or implied warranty. 20 */ 21 22 #ifndef lint 23 static char sccsid[] = "@(#)map3270.c 3.1 10/29/86"; 24 #endif /* ndef lint */ 25 26 27 /* This program reads a description file, somewhat like /etc/termcap, 28 that describes the mapping between the current terminal's keyboard and 29 a 3270 keyboard. 30 */ 31 #ifdef DOCUMENTATION_ONLY 32 /* here is a sample (very small) entry... 33 34 # this table is sensitive to position on a line. In particular, 35 # a terminal definition for a terminal is terminated whenever a 36 # (non-comment) line beginning in column one is found. 37 # 38 # this is an entry to map tvi924 to 3270 keys... 39 v8|tvi924|924|televideo model 924 { 40 pfk1 = '\E1'; 41 pfk2 = '\E2'; 42 clear = '^z'; # clear the screen 43 } 44 */ 45 #endif /* DOCUMENTATION_ONLY */ 46 47 #include <stdio.h> 48 #include <ctype.h> 49 #if defined(unix) 50 #include <strings.h> 51 #else /* defined(unix) */ 52 #include <string.h> 53 #endif /* defined(unix) */ 54 55 #define IsPrint(c) ((isprint(c) && !isspace(c)) || ((c) == ' ')) 56 57 #define LETS_SEE_ASCII 58 #include "m4.out" 59 60 #include "state.h" 61 62 #include "../general/globals.h" 63 #include "map3270.ext" 64 65 /* this is the list of types returned by the lex processor */ 66 #define LEX_CHAR TC_HIGHEST /* plain unadorned character */ 67 #define LEX_ESCAPED LEX_CHAR+1 /* escaped with \ */ 68 #define LEX_CARETED LEX_ESCAPED+1 /* escaped with ^ */ 69 #define LEX_END_OF_FILE LEX_CARETED+1 /* end of file encountered */ 70 #define LEX_ILLEGAL LEX_END_OF_FILE+1 /* trailing escape character */ 71 72 /* the following is part of our character set dependancy... */ 73 #define ESCAPE 0x1b 74 #define TAB 0x09 75 #define NEWLINE 0x0a 76 #define CARRIAGE_RETURN 0x0d 77 78 typedef struct { 79 int type; /* LEX_* - type of character */ 80 int value; /* character this was */ 81 } lexicon; 82 83 typedef struct { 84 int length; /* length of character string */ 85 char array[500]; /* character string */ 86 } stringWithLength; 87 88 #define panic(s) { fprintf(stderr, s); exit(1); } 89 90 static state firstentry = { 0, TC_NULL, 0, 0 }; 91 static state *headOfQueue = &firstentry; 92 93 /* the following is a primitive adm3a table, to be used when nothing 94 * else seems to be avaliable. 95 */ 96 97 #ifdef DEBUG 98 static int debug = 0; /* debug flag (for debuggin tables) */ 99 #endif /* DEBUG */ 100 101 static int doPaste = 1; /* should we have side effects */ 102 static int picky = 0; /* do we complain of unknown TC's? */ 103 static char usePointer = 0; /* use pointer, or file */ 104 static FILE *ourFile= 0; 105 static char *environPointer = 0; /* if non-zero, point to input 106 * string in core. 107 */ 108 static char **whichkey = 0; 109 static char *keysgeneric[] = { 110 #include "default.map" /* Define the default default */ 111 112 0, /* Terminate list of entries */ 113 }; 114 ; 115 116 static int Empty = 1, /* is the unget lifo empty? */ 117 Full = 0; /* is the unget lifo full? */ 118 static lexicon lifo[200] = { 0 }; /* character stack for parser */ 119 static int rp = 0, /* read pointer into lifo */ 120 wp = 0; /* write pointer into lifo */ 121 122 static int 123 GetC() 124 { 125 int character; 126 127 if (usePointer) { 128 if ((*environPointer) == 0) { 129 /* 130 * If we have reached the end of this string, go on to 131 * the next (if there is a next). 132 */ 133 if (whichkey == 0) { 134 static char suffix = 'A'; /* From environment */ 135 char envname[9]; 136 extern char *getenv(); 137 138 (void) sprintf(envname, "MAP3270%c", suffix++); 139 environPointer = getenv(envname); 140 } else { 141 whichkey++; /* default map */ 142 environPointer = *whichkey; 143 } 144 } 145 if (*environPointer) { 146 character = 0xff&*environPointer++; 147 } else { 148 character = EOF; 149 } 150 } else { 151 character = getc(ourFile); 152 } 153 return(character); 154 } 155 156 static lexicon 157 Get() 158 { 159 lexicon c; 160 register lexicon *pC = &c; 161 register int character; 162 163 if (!Empty) { 164 *pC = lifo[rp]; 165 rp++; 166 if (rp == sizeof lifo/sizeof (lexicon)) { 167 rp = 0; 168 } 169 if (rp == wp) { 170 Empty = 1; 171 } 172 Full = 0; 173 } else { 174 character = GetC(); 175 switch (character) { 176 case EOF: 177 pC->type = LEX_END_OF_FILE; 178 break; 179 case '^': 180 character = GetC(); 181 if (!IsPrint(character)) { 182 pC->type = LEX_ILLEGAL; 183 } else { 184 pC->type = LEX_CARETED; 185 if (character == '?') { 186 character |= 0x40; /* rubout */ 187 } else { 188 character &= 0x1f; 189 } 190 } 191 break; 192 case '\\': 193 character = GetC(); 194 if (!IsPrint(character)) { 195 pC->type = LEX_ILLEGAL; 196 } else { 197 pC->type = LEX_ESCAPED; 198 switch (character) { 199 case 'E': case 'e': 200 character = ESCAPE; 201 break; 202 case 't': 203 character = TAB; 204 break; 205 case 'n': 206 character = NEWLINE; 207 break; 208 case 'r': 209 character = CARRIAGE_RETURN; 210 break; 211 default: 212 pC->type = LEX_ILLEGAL; 213 break; 214 } 215 } 216 break; 217 default: 218 if ((IsPrint(character)) || isspace(character)) { 219 pC->type = LEX_CHAR; 220 } else { 221 pC->type = LEX_ILLEGAL; 222 } 223 break; 224 } 225 pC->value = character; 226 } 227 return(*pC); 228 } 229 230 static void 231 UnGet(c) 232 lexicon c; /* character to unget */ 233 { 234 if (Full) { 235 fprintf(stderr, "attempt to put too many characters in lifo\n"); 236 panic("map3270"); 237 /* NOTREACHED */ 238 } else { 239 lifo[wp] = c; 240 wp++; 241 if (wp == sizeof lifo/sizeof (lexicon)) { 242 wp = 0; 243 } 244 if (wp == rp) { 245 Full = 1; 246 } 247 Empty = 0; 248 } 249 } 250 251 /* 252 * Construct a control character sequence 253 * for a special character. 254 */ 255 char * 256 uncontrol(c) 257 register int c; 258 { 259 static char buf[3]; 260 261 if (c == 0x7f) 262 return ("^?"); 263 if (c == '\377') { 264 return "-1"; 265 } 266 if (c >= 0x20) { 267 buf[0] = c; 268 buf[1] = 0; 269 } else { 270 buf[0] = '^'; 271 buf[1] = '@'+c; 272 buf[2] = 0; 273 } 274 return (buf); 275 } 276 277 /* compare two strings, ignoring case */ 278 279 ustrcmp(string1, string2) 280 register char *string1; 281 register char *string2; 282 { 283 register int c1, c2; 284 285 while ((c1 = (unsigned char) *string1++) != 0) { 286 if (isupper(c1)) { 287 c1 = tolower(c1); 288 } 289 if (isupper(c2 = (unsigned char) *string2++)) { 290 c2 = tolower(c2); 291 } 292 if (c1 < c2) { 293 return(-1); 294 } else if (c1 > c2) { 295 return(1); 296 } 297 } 298 if (*string2) { 299 return(-1); 300 } else { 301 return(0); 302 } 303 } 304 305 306 static stringWithLength * 307 GetQuotedString() 308 { 309 lexicon lex; 310 static stringWithLength output = { 0 }; /* where return value is held */ 311 char *pointer = output.array; 312 313 lex = Get(); 314 if ((lex.type != LEX_CHAR) || (lex.value != '\'')) { 315 UnGet(lex); 316 return(0); 317 } 318 while (1) { 319 lex = Get(); 320 if ((lex.type == LEX_CHAR) && (lex.value == '\'')) { 321 break; 322 } 323 if ((lex.type == LEX_CHAR) && !IsPrint(lex.value)) { 324 UnGet(lex); 325 return(0); /* illegal character in quoted string */ 326 } 327 if (pointer >= output.array+sizeof output.array) { 328 return(0); /* too long */ 329 } 330 *pointer++ = lex.value; 331 } 332 output.length = pointer-output.array; 333 return(&output); 334 } 335 336 #ifdef NOTUSED 337 static stringWithLength * 338 GetCharString() 339 { 340 lexicon lex; 341 static stringWithLength output; 342 char *pointer = output.array; 343 344 lex = Get(); 345 346 while ((lex.type == LEX_CHAR) && 347 !isspace(lex.value) && (lex.value != '=')) { 348 *pointer++ = lex.value; 349 lex = Get(); 350 if (pointer >= output.array + sizeof output.array) { 351 return(0); /* too long */ 352 } 353 } 354 UnGet(lex); 355 output.length = pointer-output.array; 356 return(&output); 357 } 358 #endif /* NOTUSED */ 359 360 static 361 GetCharacter(character) 362 int character; /* desired character */ 363 { 364 lexicon lex; 365 366 lex = Get(); 367 368 if ((lex.type != LEX_CHAR) || (lex.value != character)) { 369 UnGet(lex); 370 return(0); 371 } 372 return(1); 373 } 374 375 #ifdef NOTUSED 376 static 377 GetString(string) 378 char *string; /* string to get */ 379 { 380 lexicon lex; 381 382 while (*string) { 383 lex = Get(); 384 if ((lex.type != LEX_CHAR) || (lex.value != *string&0xff)) { 385 UnGet(lex); 386 return(0); /* XXX restore to state on entry */ 387 } 388 string++; 389 } 390 return(1); 391 } 392 #endif /* NOTUSED */ 393 394 395 static stringWithLength * 396 GetAlphaMericString() 397 { 398 lexicon lex; 399 static stringWithLength output = { 0 }; 400 char *pointer = output.array; 401 # define IsAlnum(c) (isalnum(c) || (c == '_') \ 402 || (c == '-') || (c == '.')) 403 404 lex = Get(); 405 406 if ((lex.type != LEX_CHAR) || !IsAlnum(lex.value)) { 407 UnGet(lex); 408 return(0); 409 } 410 411 while ((lex.type == LEX_CHAR) && IsAlnum(lex.value)) { 412 *pointer++ = lex.value; 413 lex = Get(); 414 } 415 UnGet(lex); 416 *pointer = 0; 417 output.length = pointer-output.array; 418 return(&output); 419 } 420 421 422 /* eat up characters until a new line, or end of file. returns terminating 423 character. 424 */ 425 426 static lexicon 427 EatToNL() 428 { 429 lexicon lex; 430 431 lex = Get(); 432 433 while (!((lex.type != LEX_ESCAPED) && (lex.type != LEX_CARETED) && 434 (lex.value == '\n')) && (!(lex.type == LEX_END_OF_FILE))) { 435 lex = Get(); 436 } 437 if (lex.type != LEX_END_OF_FILE) { 438 return(Get()); 439 } else { 440 return(lex); 441 } 442 } 443 444 445 static void 446 GetWS() 447 { 448 lexicon lex; 449 450 lex = Get(); 451 452 while ((lex.type == LEX_CHAR) && 453 (isspace(lex.value) || (lex.value == '#'))) { 454 if (lex.value == '#') { 455 lex = EatToNL(); 456 } else { 457 lex = Get(); 458 } 459 } 460 UnGet(lex); 461 } 462 463 static void 464 FreeState(pState) 465 state *pState; 466 { 467 extern void free(); 468 469 free((char *)pState); 470 } 471 472 473 static state * 474 GetState() 475 { 476 state *pState; 477 extern char *malloc(); 478 479 pState = (state *) malloc(sizeof (state)); 480 481 pState->result = TC_NULL; 482 pState->next = 0; 483 484 return(pState); 485 } 486 487 488 static state * 489 FindMatchAtThisLevel(pState, character) 490 state *pState; 491 int character; 492 { 493 while (pState) { 494 if (pState->match == character) { 495 return(pState); 496 } 497 pState = pState->next; 498 } 499 return(0); 500 } 501 502 503 static state * 504 PasteEntry(head, string, count, identifier) 505 state *head; /* points to who should point here... */ 506 char *string; /* which characters to paste */ 507 int count; /* number of character to do */ 508 char *identifier; /* for error messages */ 509 { 510 state *pState, *other; 511 512 if (!doPaste) { /* flag to not have any side effects */ 513 return((state *)1); 514 } 515 if (!count) { 516 return(head); /* return pointer to the parent */ 517 } 518 if ((head->result != TC_NULL) && (head->result != TC_GOTO)) { 519 /* this means that a previously defined sequence is an initial 520 * part of this one. 521 */ 522 fprintf(stderr, "Conflicting entries found when scanning %s\n", 523 identifier); 524 return(0); 525 } 526 # ifdef DEBUG 527 if (debug) { 528 fprintf(stderr, "%s", uncontrol(*string)); 529 } 530 # endif /* DEBUG */ 531 pState = GetState(); 532 pState->match = *string; 533 if (head->result == TC_NULL) { 534 head->result = TC_GOTO; 535 head->address = pState; 536 other = pState; 537 } else { /* search for same character */ 538 if ((other = FindMatchAtThisLevel(head->address, *string)) != 0) { 539 FreeState(pState); 540 } else { 541 pState->next = head->address; 542 head->address = pState; 543 other = pState; 544 } 545 } 546 return(PasteEntry(other, string+1, count-1, identifier)); 547 } 548 549 static 550 GetInput(tc, identifier) 551 int tc; 552 char *identifier; /* entry being parsed (for error messages) */ 553 { 554 stringWithLength *outputString; 555 state *head; 556 state fakeQueue; 557 558 if (doPaste) { 559 head = headOfQueue; /* always points to level above this one */ 560 } else { 561 head = &fakeQueue; /* don't have any side effects... */ 562 } 563 564 if ((outputString = GetQuotedString()) == 0) { 565 return(0); 566 } else if (IsPrint(outputString->array[0])) { 567 fprintf(stderr, 568 "first character of sequence for %s is not a control type character\n", 569 identifier); 570 return(0); 571 } else { 572 if ((head = PasteEntry(head, outputString->array, 573 outputString->length, identifier)) == 0) { 574 return(0); 575 } 576 GetWS(); 577 while ((outputString = GetQuotedString()) != 0) { 578 if ((head = PasteEntry(head, outputString->array, 579 outputString->length, identifier)) == 0) { 580 return(0); 581 } 582 GetWS(); 583 } 584 } 585 if (!doPaste) { 586 return(1); 587 } 588 if ((head->result != TC_NULL) && (head->result != tc)) { 589 /* this means that this sequence is an initial part 590 * of a previously defined one. 591 */ 592 fprintf(stderr, "Conflicting entries found when scanning %s\n", 593 identifier); 594 return(0); 595 } else { 596 head->result = tc; 597 return(1); /* done */ 598 } 599 } 600 601 static 602 GetTc(string) 603 char *string; 604 { 605 register TC_Ascii_t *Tc; 606 607 for (Tc = TC_Ascii; 608 Tc < TC_Ascii+sizeof TC_Ascii/sizeof (TC_Ascii_t); Tc++) { 609 if (!ustrcmp(string, Tc->tc_name)) { 610 # ifdef DEBUG 611 if (debug) { 612 fprintf(stderr, "%s = ", Tc->tc_name); 613 } 614 # endif /* DEBUG */ 615 return(Tc->tc_value&0xff); 616 } 617 } 618 return(0); 619 } 620 static 621 GetDefinition() 622 { 623 stringWithLength *string; 624 int Tc; 625 626 GetWS(); 627 if ((string = GetAlphaMericString()) == 0) { 628 return(0); 629 } 630 string->array[string->length] = 0; 631 if (doPaste) { 632 if ((Tc = GetTc(string->array)) == 0) { 633 if (picky) { 634 fprintf(stderr, "%s: unknown 3270 key identifier\n", 635 string->array); 636 } 637 Tc = TC_NULL; 638 } else if (Tc < TC_LOWEST_USER) { 639 fprintf(stderr, "%s is not allowed to be specified by a user.\n", 640 string->array); 641 return(0); 642 } 643 } else { 644 Tc = TC_LOWEST_USER; 645 } 646 GetWS(); 647 if (!GetCharacter('=')) { 648 fprintf(stderr, 649 "Required equal sign after 3270 key identifier %s missing\n", 650 string->array); 651 return(0); 652 } 653 GetWS(); 654 if (!GetInput(Tc, string->array)) { 655 fprintf(stderr, "Missing definition part for 3270 key %s\n", 656 string->array); 657 return(0); 658 } else { 659 GetWS(); 660 while (GetCharacter('|')) { 661 # ifdef DEBUG 662 if (debug) { 663 fprintf(stderr, " or "); 664 } 665 # endif /* DEBUG */ 666 GetWS(); 667 if (!GetInput(Tc, string->array)) { 668 fprintf(stderr, "Missing definition part for 3270 key %s\n", 669 string->array); 670 return(0); 671 } 672 GetWS(); 673 } 674 } 675 GetWS(); 676 if (!GetCharacter(';')) { 677 fprintf(stderr, "Missing semi-colon for 3270 key %s\n", string->array); 678 return(0); 679 } 680 # ifdef DEBUG 681 if (debug) { 682 fprintf(stderr, ";\n"); 683 } 684 # endif /* DEBUG */ 685 return(1); 686 } 687 688 689 static 690 GetDefinitions() 691 { 692 if (!GetDefinition()) { 693 return(0); 694 } else { 695 while (GetDefinition()) { 696 ; 697 } 698 } 699 return(1); 700 } 701 702 static 703 GetBegin() 704 { 705 GetWS(); 706 if (!GetCharacter('{')) { 707 return(0); 708 } 709 return(1); 710 } 711 712 static 713 GetEnd() 714 { 715 GetWS(); 716 if (!GetCharacter('}')) { 717 return(0); 718 } 719 return(1); 720 } 721 722 static 723 GetName() 724 { 725 if (!GetAlphaMericString()) { 726 return(0); 727 } 728 GetWS(); 729 while (GetAlphaMericString()) { 730 GetWS(); 731 } 732 return(1); 733 } 734 735 static 736 GetNames() 737 { 738 GetWS(); 739 if (!GetName()) { 740 return(0); 741 } else { 742 GetWS(); 743 while (GetCharacter('|')) { 744 GetWS(); 745 if (!GetName()) { 746 return(0); 747 } 748 } 749 } 750 return(1); 751 } 752 753 static 754 GetEntry0() 755 { 756 if (!GetBegin()) { 757 fprintf(stderr, "no '{'\n"); 758 return(0); 759 } else if (!GetDefinitions()) { 760 fprintf(stderr, "unable to parse the definitions\n"); 761 return(0); 762 } else if (!GetEnd()) { 763 fprintf(stderr, "No '}' or scanning stopped early due to error.\n"); 764 return(0); 765 } else { 766 /* done */ 767 return(1); 768 } 769 } 770 771 772 static 773 GetEntry() 774 { 775 if (!GetNames()) { 776 fprintf(stderr, "Invalid name field in entry.\n"); 777 return(0); 778 } else { 779 return(GetEntry0()); 780 } 781 } 782 783 /* position ourselves within a given filename to the entry for the current 784 * KEYBD (or TERM) variable 785 */ 786 787 Position(filename, keybdPointer) 788 char *filename; 789 char *keybdPointer; 790 { 791 lexicon lex; 792 stringWithLength *name = 0; 793 stringWithLength *oldName; 794 # define Return(x) {doPaste = 1; return(x);} 795 796 doPaste = 0; 797 798 if ((ourFile = fopen(filename, "r")) == NULL) { 799 # if !defined(MSDOS) 800 fprintf(stderr, "Unable to open file %s\n", filename); 801 # endif /* !defined(MSDOS) */ 802 Return(0); 803 } 804 lex = Get(); 805 while (lex.type != LEX_END_OF_FILE) { 806 UnGet(lex); 807 /* now, find an entry that is our type. */ 808 GetWS(); 809 oldName = name; 810 if ((name = GetAlphaMericString()) != 0) { 811 if (!ustrcmp(name->array, keybdPointer)) { 812 /* need to make sure there is a name here... */ 813 lex.type = LEX_CHAR; 814 lex.value = 'a'; 815 UnGet(lex); 816 Return(1); 817 } 818 } else if (GetCharacter('|')) { 819 ; /* more names coming */ 820 } else { 821 lex = Get(); 822 UnGet(lex); 823 if (lex.type != LEX_END_OF_FILE) { 824 if (!GetEntry0()) { /* start of an entry */ 825 fprintf(stderr, 826 "error was in entry for %s in file %s\n", 827 (oldName)? oldName->array:"(unknown)", filename); 828 Return(0); 829 } 830 } 831 } 832 lex = Get(); 833 } 834 #if !defined(MSDOS) 835 fprintf(stderr, "Unable to find entry for %s in file %s\n", keybdPointer, 836 filename); 837 #endif /* !defined(MSDOS) */ 838 Return(0); 839 } 840 841 char * 842 strsave(string) 843 char *string; 844 { 845 char *p; 846 extern char *malloc(); 847 848 p = malloc(strlen(string)+1); 849 if (p != 0) { 850 strcpy(p, string); 851 } 852 return(p); 853 } 854 855 856 /* 857 * InitControl - our interface to the outside. What we should 858 * do is figure out keyboard (or terminal) type, set up file pointer 859 * (or string pointer), etc. 860 */ 861 862 state * 863 InitControl(keybdPointer, pickyarg) 864 char *keybdPointer; 865 int pickyarg; /* Should we be picky? */ 866 { 867 extern char *getenv(); 868 int GotIt; 869 870 picky = pickyarg; 871 872 if (keybdPointer == 0) { 873 keybdPointer = getenv("KEYBD"); 874 } 875 if (keybdPointer == 0) { 876 keybdPointer = getenv("TERM"); 877 } 878 879 /* 880 * Some environments have getenv() return 881 * out of a static area. So, save the keyboard name. 882 */ 883 if (keybdPointer) { 884 keybdPointer = strsave(keybdPointer); 885 } 886 environPointer = getenv("MAP3270"); 887 if (environPointer 888 && (environPointer[0] != '/') 889 #if defined(MSDOS) 890 && (environPointer[0] != '\\') 891 #endif /* defined(MSDOS) */ 892 && (strncmp(keybdPointer, environPointer, 893 strlen(keybdPointer) != 0) 894 || (environPointer[strlen(keybdPointer)] != '{'))) /* } */ 895 { 896 environPointer = 0; 897 } 898 899 if ((!environPointer) 900 #if defined(MSDOS) 901 || (*environPointer == '\\') 902 #endif /* defined(MSDOS) */ 903 || (*environPointer == '/')) { 904 usePointer = 0; 905 GotIt = 0; 906 if (!keybdPointer) { 907 #if !defined(MSDOS) 908 fprintf(stderr, "%s%s%s%s", 909 "Neither the KEYBD environment variable nor the TERM ", 910 "environment variable\n(one of which is needed to determine ", 911 "the type of keyboard you are using)\n", 912 "is set. To set it, say 'setenv KEYBD <type>'\n"); 913 #endif /* !defined(MSDOS) */ 914 } else { 915 if (environPointer) { 916 GotIt = Position(environPointer, keybdPointer); 917 } 918 if (!GotIt) { 919 GotIt = Position("/etc/map3270", keybdPointer); 920 } 921 } 922 if (!GotIt) { 923 if (environPointer) { 924 GotIt = Position(environPointer, "unknown"); 925 } 926 if (!GotIt) { 927 GotIt = Position("/etc/map3270", keybdPointer); 928 } 929 } 930 if (!GotIt) { 931 #if !defined(MSDOS) 932 fprintf(stderr, "Using default key mappings.\n"); 933 #endif /* !defined(MSDOS) */ 934 usePointer = 1; /* flag use of non-file */ 935 whichkey = keysgeneric; 936 environPointer = *whichkey; /* use default table */ 937 } 938 } else { 939 usePointer = 1; 940 } 941 (void) GetEntry(); 942 return(firstentry.address); 943 } 944