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