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