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