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