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