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