xref: /csrg-svn/usr.bin/tn3270/ascii/map3270.c (revision 31100)
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