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