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