|
|
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:
24: /* test stub for DataFrom3270, etc. */
25:
26: #define DEFINEAIDS
27: #include "m4.out" /* output of termcodes.m4 */
28: #include "ascebc.h"
29: #include "3270.h"
30: #include "screen.h"
31: #include "options.h"
32: #include "ectype.h"
33:
34: #ifndef lint
35: static char sccsid[] = "@(#)keyboard.c 2.6 4/4/86";
36: #endif /* ndef lint */
37:
38: #define EmptyChar (ourPTail == ourBuffer)
39: #define FullChar (ourPTail == ourBuffer+sizeof ourBuffer)
40:
41: extern char ascebc[NASCEBC][NASCII];
42:
43: static char ourBuffer[4000];
44:
45: static char *ourPHead = ourBuffer,
46: *ourPTail = ourBuffer;
47:
48: static int trTbl = AE_IN; /* which ascii->ebcdic tr table */
49:
50: static int HadAid = 0; /* Had an AID haven't sent */
51:
52: /* the following are global variables */
53:
54: extern int UnLocked; /* keyboard is UnLocked? */
55:
56: /* Tab() - sets cursor to the start of the next unprotected field */
57: static void
58: Tab()
59: {
60: register int i, j;
61:
62: i = CursorAddress;
63: j = WhereAttrByte(CursorAddress);
64: do {
65: if (IsStartField(i) && IsUnProtected(ScreenInc(i))) {
66: break;
67: }
68: i = FieldInc(i);
69: } while (i != j);
70: if (IsStartField(i) && IsUnProtected(ScreenInc(i))) {
71: CursorAddress = ScreenInc(i);
72: } else {
73: CursorAddress = SetBufferAddress(0,0);
74: }
75: }
76:
77:
78: /* BackTab() - sets cursor to the start of the most recent field */
79:
80: static void
81: BackTab()
82: {
83: register int i;
84:
85: i = ScreenDec(CursorAddress);
86: for (;;) {
87: if (IsStartField(ScreenDec(i)) && IsUnProtected(i)) {
88: CursorAddress = i;
89: break;
90: }
91: if (i == CursorAddress) {
92: CursorAddress = SetBufferAddress(0,0);
93: break;
94: }
95: i = ScreenDec(i);
96: }
97: }
98:
99:
100: /* EraseEndOfField - erase all characters to the end of a field */
101:
102: static
103: EraseEndOfField()
104: {
105: register int i;
106:
107: if (IsProtected(CursorAddress)) {
108: RingBell();
109: } else {
110: TurnOnMdt(CursorAddress);
111: i = CursorAddress;
112: do {
113: AddHost(i, 0);
114: i = ScreenInc(i);
115: } while ((i != CursorAddress) && IsUnProtected(i));
116: }
117: }
118:
119: /* Delete() - deletes a character from the screen
120: *
121: * What we want to do is delete the section
122: * [where, from-1] from the screen,
123: * filling in with what comes at from.
124: *
125: * The deleting continues to the end of the field (or
126: * until the cursor wraps).
127: *
128: * From can be a start of a field. We
129: * check for that. However, there can't be any
130: * fields that start between where and from.
131: * We don't check for that.
132: *
133: * Also, we assume that the protection status of
134: * everything has been checked by the caller.
135: *
136: */
137:
138: static
139: Delete(where, from)
140: register int where, /* Where to start deleting from */
141: from; /* Where to pull back from */
142: {
143: register int i;
144:
145: TurnOnMdt(where); /* Only do this once in this field */
146: i = where;
147: do {
148: if (IsStartField(from)) {
149: AddHost(i, 0); /* Stick the edge at the start field */
150: } else {
151: AddHost(i, GetHost(from));
152: from = ScreenInc(from); /* Move the edge */
153: }
154: i = ScreenInc(i);
155: } while ((!IsStartField(i)) && (i != where));
156: }
157:
158: ColBak()
159: {
160: register int i;
161:
162: i = ScreenLineOffset(CursorAddress);
163: for (i = i-1; i >= 0; i--) {
164: if (OptColTabs[i]) {
165: break;
166: }
167: }
168: if (i < 0) {
169: i = 0;
170: }
171: CursorAddress = SetBufferAddress(ScreenLine(CursorAddress), i);
172: }
173:
174: ColTab()
175: {
176: register int i;
177:
178: i = ScreenLineOffset(CursorAddress);
179: for (i = i+1; i < LINESIZE; i++) {
180: if (OptColTabs[i]) {
181: break;
182: }
183: }
184: if (i >= LINESIZE) {
185: i = LINESIZE-1;
186: }
187: CursorAddress = SetBufferAddress(ScreenLine(CursorAddress), i);
188: }
189:
190: static
191: Home()
192: {
193: register int i;
194: register int j;
195:
196: i = SetBufferAddress(OptHome, 0);
197: j = WhereLowByte(i);
198: do {
199: if (IsUnProtected(i)) {
200: CursorAddress = i;
201: return;
202: }
203: /* the following could be a problem if we got here with an
204: * unformatted screen. However, this is "impossible", since
205: * with an unformatted screen, the IsUnProtected(i) above
206: * should be true.
207: */
208: i = ScreenInc(FieldInc(i));
209: } while (i != j);
210: CursorAddress = LowestScreen();
211: }
212:
213: static
214: LastOfField(i)
215: register int i; /* position to start from */
216: {
217: register int j;
218: register int k;
219:
220: k = j = i;
221: while (IsProtected(i) || Eisspace(GetHost(i))) {
222: i = ScreenInc(i);
223: if (i == j) {
224: break;
225: }
226: }
227: /* We are now IN a word IN an unprotected field (or wrapped) */
228: while (!IsProtected(i)) {
229: if (!Eisspace(GetHost(i))) {
230: k = i;
231: }
232: i = ScreenInc(i);
233: if (i == j) {
234: break;
235: }
236: }
237: return(k);
238: }
239:
240:
241: static
242: FlushChar()
243: {
244: ourPTail = ourPHead = ourBuffer;
245: }
246:
247:
248: static
249: AddChar(character)
250: char character;
251: {
252: *ourPHead++ = character;
253: }
254:
255:
256: static void
257: SendUnformatted()
258: {
259: register int i, j;
260: register int Nulls;
261: register int c;
262:
263: /* look for start of field */
264: Nulls = 0;
265: i = j = LowestScreen();
266: do {
267: c = GetHost(i);
268: if (c == 0) {
269: Nulls++;
270: } else {
271: while (Nulls) {
272: Nulls--;
273: AddChar(0x40); /* put in blanks */
274: }
275: AddChar(c);
276: }
277: i = ScreenInc(i);
278: } while (i != j);
279: }
280:
281: static
282: SendField(i)
283: register int i; /* where we saw MDT bit */
284: {
285: register int j;
286: register int k;
287: register int Nulls;
288: register int c;
289:
290: /* look for start of field */
291: i = j = WhereLowByte(i);
292:
293: AddChar(ORDER_SBA); /* set start field */
294: AddChar(BufferTo3270_0(j)); /* set address of this field */
295: AddChar(BufferTo3270_1(j));
296:
297: if (!IsStartField(j)) {
298: Nulls = 0;
299: k = ScreenInc(WhereHighByte(j));
300: do {
301: c = GetHost(j);
302: if (c == 0) {
303: Nulls++;
304: } else {
305: while (Nulls) {
306: Nulls--;
307: AddChar(0x40); /* put in blanks */
308: }
309: AddChar(c);
310: }
311: j = ScreenInc(j);
312: } while ((j != k) && (j != i));
313: }
314: return(j);
315: }
316:
317: /* Various types of reads... */
318: DoReadModified()
319: {
320: register int i, j;
321:
322: if (AidByte) {
323: AddChar(AidByte);
324: } else {
325: AddChar(0x60);
326: }
327: if ((AidByte != AID_PA1) && (AidByte != AID_PA2) && (AidByte != AID_PA3)
328: && (AidByte != AID_CLEAR)) {
329: AddChar(BufferTo3270_0(CursorAddress));
330: AddChar(BufferTo3270_1(CursorAddress));
331: i = j = WhereAttrByte(LowestScreen());
332: /* Is this an unformatted screen? */
333: if (!IsStartField(i)) { /* yes, handle separate */
334: SendUnformatted();
335: } else {
336: do {
337: if (HasMdt(i)) {
338: i = SendField(i);
339: } else {
340: i = FieldInc(i);
341: }
342: } while (i != j);
343: }
344: }
345: ourPTail += DataToNetwork(ourPTail, ourPHead-ourPTail);
346: if (ourPTail == ourPHead) {
347: FlushChar();
348: HadAid = 0; /* killed that buffer */
349: }
350: }
351:
352: /* A read buffer operation... */
353:
354: DoReadBuffer()
355: {
356: register int i, j;
357:
358: if (AidByte) {
359: AddChar(AidByte);
360: } else {
361: AddChar(0x60);
362: }
363: AddChar(BufferTo3270_0(CursorAddress));
364: AddChar(BufferTo3270_1(CursorAddress));
365: i = j = LowestScreen();
366: do {
367: if (IsStartField(i)) {
368: AddChar(ORDER_SF);
369: AddChar(BufferTo3270_1(FieldAttributes(i)));
370: } else {
371: AddChar(GetHost(i));
372: }
373: i = ScreenInc(i);
374: } while (i != j);
375: ourPTail += DataToNetwork(ourPTail, ourPHead-ourPTail);
376: if (ourPTail == ourPHead) {
377: FlushChar();
378: HadAid = 0; /* killed that buffer */
379: }
380: }
381: /* Try to send some data to host */
382:
383: SendToIBM()
384: {
385: extern int TransparentClock, OutputClock;
386:
387: if (TransparentClock == OutputClock) {
388: if (HadAid) {
389: AddChar(AidByte);
390: HadAid = 0;
391: } else {
392: AddChar(0xe8);
393: }
394: do {
395: ourPTail += DataToNetwork(ourPTail, ourPHead-ourPTail);
396: } while (ourPTail != ourPHead);
397: FlushChar();
398: } else if (HadAid) {
399: DoReadModified();
400: }
401: netflush();
402: }
403:
404: /* This takes in one character from the keyboard and places it on the
405: * screen.
406: */
407:
408: static
409: OneCharacter(c, insert)
410: int c; /* character (Ebcdic) to be shoved in */
411: int insert; /* are we in insert mode? */
412: {
413: register int i, j;
414:
415: if (IsProtected(CursorAddress)) {
416: RingBell();
417: return;
418: }
419: if (insert) {
420: /* is the last character in the field a blank or null? */
421: i = ScreenDec(FieldInc(CursorAddress));
422: j = GetHost(i);
423: if (!Eisspace(j)) {
424: RingBell();
425: return;
426: } else {
427: for (j = ScreenDec(i); i != CursorAddress;
428: j = ScreenDec(j), i = ScreenDec(i)) {
429: AddHost(i, GetHost(j));
430: }
431: }
432: }
433: AddHost(CursorAddress, c);
434: TurnOnMdt(CursorAddress);
435: CursorAddress = ScreenInc(CursorAddress);
436: if (IsStartField(CursorAddress) &&
437: ((FieldAttributes(CursorAddress)&ATTR_AUTO_SKIP_MASK) ==
438: ATTR_AUTO_SKIP_VALUE)) {
439: Tab();
440: }
441: }
442:
443: /* go through data until an AID character is hit, then generate an interrupt */
444:
445: DataFrom3270(buffer, count)
446: char *buffer; /* where the data is */
447: int count; /* how much data there is */
448: {
449: int origCount;
450: register int c;
451: register int i;
452: register int j;
453: static int InsertMode = 0; /* is the terminal in insert mode? */
454:
455: extern int OutputClock, TransparentClock;
456:
457: if (!UnLocked || HadAid) {
458: if (HadAid) {
459: SendToIBM();
460: if (!EmptyChar) {
461: return(0); /* nothing to do */
462: }
463: }
464: if (!HadAid && (((*buffer&0xff) == TC_RESET) ||
465: ((*buffer&0xff) == TC_MASTER_RESET)) && EmptyChar) {
466: UnLocked = 1;
467: }
468: if (!UnLocked) {
469: return(0);
470: }
471: }
472: /* now, either empty, or haven't seen aid yet */
473:
474: origCount = count;
475:
476: if (TransparentClock == OutputClock) {
477: while (count) {
478: c = (*buffer++)&0xff;
479: count--;
480: if (IsAid(c)) {
481: UnLocked = 0;
482: InsertMode = 0;
483: AidByte = TCtoAid(c);
484: HadAid = 1;
485: } else {
486: switch (c) {
487: case TC_ESCAPE:
488: Stop3270(1);
489: command(0);
490: ConnectScreen();
491: break;
492:
493: case TC_RESET:
494: case TC_MASTER_RESET:
495: UnLocked = 1;
496: break;
497:
498: default:
499: return(origCount-(count+1));
500: }
501: }
502: }
503: }
504:
505: while (count) {
506: c = (*buffer++)&0xff;
507: count--;
508:
509: if (!IsTc(c)) {
510: /* Add the character to the buffer */
511: OneCharacter(ascebc[trTbl][c], InsertMode);
512: } else if (IsAid(c)) { /* got Aid */
513: if (c == TC_CLEAR) {
514: LocalClear3270();
515: }
516: UnLocked = 0;
517: InsertMode = 0; /* just like a 3278 */
518: AidByte = TCtoAid(c);
519: HadAid = 1;
520: SendToIBM();
521: return(origCount-count);
522: } else {
523:
524: /* non-AID TC character */
525: switch (c) {
526:
527: case TC_ERASE:
528: if (IsProtected(ScreenDec(CursorAddress))) {
529: RingBell();
530: } else {
531: CursorAddress = ScreenDec(CursorAddress);
532: Delete(CursorAddress, ScreenInc(CursorAddress));
533: }
534: break;
535:
536: case TC_WERASE:
537: j = CursorAddress;
538: i = ScreenDec(j);
539: if (IsProtected(i)) {
540: RingBell();
541: } else {
542: while ((!IsProtected(i) && Eisspace(GetHost(i)))
543: && (i != j)) {
544: i = ScreenDec(i);
545: }
546: /* we are pointing at a character in a word, or
547: * at a protected position
548: */
549: while ((!IsProtected(i) && !Eisspace(GetHost(i)))
550: && (i != j)) {
551: i = ScreenDec(i);
552: }
553: /* we are pointing at a space, or at a protected
554: * position
555: */
556: CursorAddress = ScreenInc(i);
557: Delete(CursorAddress, j);
558: }
559: break;
560:
561: case TC_FERASE:
562: if (IsProtected(CursorAddress)) {
563: RingBell();
564: } else {
565: CursorAddress = ScreenInc(CursorAddress); /* for btab */
566: BackTab();
567: EraseEndOfField();
568: }
569: break;
570:
571: case TC_RESET:
572: InsertMode = 0;
573: break;
574:
575: case TC_MASTER_RESET:
576: InsertMode = 0;
577: RefreshScreen();
578: break;
579:
580: case TC_UP:
581: CursorAddress = ScreenUp(CursorAddress);
582: break;
583:
584: case TC_LEFT:
585: CursorAddress = ScreenDec(CursorAddress);
586: break;
587:
588: case TC_RIGHT:
589: CursorAddress = ScreenInc(CursorAddress);
590: break;
591:
592: case TC_DOWN:
593: CursorAddress = ScreenDown(CursorAddress);
594: break;
595:
596: case TC_DELETE:
597: if (IsProtected(CursorAddress)) {
598: RingBell();
599: } else {
600: Delete(CursorAddress, ScreenInc(CursorAddress));
601: }
602: break;
603:
604: case TC_INSRT:
605: InsertMode = !InsertMode;
606: break;
607:
608: case TC_HOME:
609: Home();
610: break;
611:
612: case TC_NL:
613: /* The algorithm is to look for the first unprotected
614: * column after column 0 of the following line. Having
615: * found that unprotected column, we check whether the
616: * cursor-address-at-entry is at or to the right of the
617: * LeftMargin AND the LeftMargin column of the found line
618: * is unprotected. If this conjunction is true, then
619: * we set the found pointer to the address of the LeftMargin
620: * column in the found line.
621: * Then, we set the cursor address to the found address.
622: */
623: i = SetBufferAddress(ScreenLine(ScreenDown(CursorAddress)), 0);
624: j = ScreenInc(WhereAttrByte(CursorAddress));
625: do {
626: if (IsUnProtected(i)) {
627: break;
628: }
629: /* Again (see comment in Home()), this COULD be a problem
630: * with an unformatted screen.
631: */
632: /* If there was a field with only an attribute byte,
633: * we may be pointing to the attribute byte of the NEXT
634: * field, so just look at the next byte.
635: */
636: if (IsStartField(i)) {
637: i = ScreenInc(i);
638: } else {
639: i = ScreenInc(FieldInc(i));
640: }
641: } while (i != j);
642: if (!IsUnProtected(i)) { /* couldn't find unprotected */
643: i = SetBufferAddress(0,0);
644: }
645: if (OptLeftMargin <= ScreenLineOffset(CursorAddress)) {
646: if (IsUnProtected(SetBufferAddress(ScreenLine(i),
647: OptLeftMargin))) {
648: i = SetBufferAddress(ScreenLine(i), OptLeftMargin);
649: }
650: }
651: CursorAddress = i;
652: break;
653:
654: case TC_EINP:
655: i = j = ScreenInc(WhereAttrByte(LowestScreen()));
656: do {
657: if (IsUnProtected(i)) {
658: AddHost(i, 0);
659: TurnOnMdt(i);
660: } else {
661: /* FieldInc() puts us at the start of the next
662: * field.
663: *
664: * We don't want to skip to the start of the
665: * next field if we are on the attribute byte,
666: * since we may be skipping over an otherwise
667: * unprotected field.
668: *
669: * Also, j points at the first byte of the first
670: * field on the screen, unprotected or not. If
671: * we never point there, we might loop here for
672: * ever.
673: */
674: if (!IsStartField(i)) {
675: i = FieldInc(i);
676: }
677: }
678: i = ScreenInc(i);
679: } while (i != j);
680: Home(); /* get to home position */
681: break;
682:
683: case TC_EEOF:
684: EraseEndOfField();
685: break;
686:
687: case TC_FM:
688: if (IsProtected(CursorAddress)) {
689: RingBell();
690: } else {
691: OneCharacter(EBCDIC_FM, InsertMode); /* Add field mark */
692: }
693: break;
694:
695: case TC_DP:
696: if (IsProtected(CursorAddress)) {
697: RingBell();
698: break;
699: }
700: OneCharacter(EBCDIC_DUP, InsertMode); /* Add dup character */
701: Tab();
702: break;
703:
704: case TC_TAB:
705: Tab();
706: break;
707:
708: case TC_BTAB:
709: BackTab();
710: break;
711:
712: #ifdef NOTUSED /* Actually, this is superseded by unix flow
713: * control.
714: */
715: case TC_XOFF:
716: Flow = 0; /* stop output */
717: break;
718:
719: case TC_XON:
720: if (!Flow) {
721: Flow = 1; /* turn it back on */
722: DoTerminalOutput();
723: }
724: break;
725: #endif /* NOTUSED */
726:
727: case TC_ESCAPE:
728: /* FlushChar(); do we want to flush characters from before? */
729: Stop3270(1);
730: command(0);
731: ConnectScreen();
732: break;
733:
734: case TC_DISC:
735: Stop3270(1);
736: suspend();
737: ConnectScreen();
738: break;
739:
740: case TC_RESHOW:
741: RefreshScreen();
742: break;
743:
744: case TC_SETTAB:
745: OptColTabs[ScreenLineOffset(CursorAddress)] = 1;
746: break;
747:
748: case TC_DELTAB:
749: OptColTabs[ScreenLineOffset(CursorAddress)] = 0;
750: break;
751:
752: case TC_CLRTAB:
753: for (i = 0; i < sizeof OptColTabs; i++) {
754: OptColTabs[i] = 0;
755: }
756: break;
757:
758: case TC_COLTAB:
759: ColTab();
760: break;
761:
762: case TC_COLBAK:
763: ColBak();
764: break;
765:
766: case TC_INDENT:
767: ColTab();
768: OptLeftMargin = ScreenLineOffset(CursorAddress);
769: break;
770:
771: case TC_UNDENT:
772: ColBak();
773: OptLeftMargin = ScreenLineOffset(CursorAddress);
774: break;
775:
776: case TC_SETMRG:
777: OptLeftMargin = ScreenLineOffset(CursorAddress);
778: break;
779:
780: case TC_SETHOM:
781: OptHome = ScreenLine(CursorAddress);
782: break;
783:
784: /*
785: * Point to first character of next unprotected word on
786: * screen.
787: */
788: case TC_WORDTAB:
789: i = CursorAddress;
790: while (!IsProtected(i) && !Eisspace(GetHost(i))) {
791: i = ScreenInc(i);
792: if (i == CursorAddress) {
793: break;
794: }
795: }
796: /* i is either protected, a space (blank or null),
797: * or wrapped
798: */
799: while (IsProtected(i) || Eisspace(GetHost(i))) {
800: i = ScreenInc(i);
801: if (i == CursorAddress) {
802: break;
803: }
804: }
805: CursorAddress = i;
806: break;
807:
808: case TC_WORDBACKTAB:
809: i = ScreenDec(CursorAddress);
810: while (IsProtected(i) || Eisspace(GetHost(i))) {
811: i = ScreenDec(i);
812: if (i == CursorAddress) {
813: break;
814: }
815: }
816: /* i is pointing to a character IN an unprotected word
817: * (or i wrapped)
818: */
819: while (!Eisspace(GetHost(i))) {
820: i = ScreenDec(i);
821: if (i == CursorAddress) {
822: break;
823: }
824: }
825: CursorAddress = ScreenInc(i);
826: break;
827:
828: /* Point to last non-blank character of this/next
829: * unprotected word.
830: */
831: case TC_WORDEND:
832: i = ScreenInc(CursorAddress);
833: while (IsProtected(i) || Eisspace(GetHost(i))) {
834: i = ScreenInc(i);
835: if (i == CursorAddress) {
836: break;
837: }
838: }
839: /* we are pointing at a character IN an
840: * unprotected word (or we wrapped)
841: */
842: while (!Eisspace(GetHost(i))) {
843: i = ScreenInc(i);
844: if (i == CursorAddress) {
845: break;
846: }
847: }
848: CursorAddress = ScreenDec(i);
849: break;
850:
851: /* Get to last non-blank of this/next unprotected
852: * field.
853: */
854: case TC_FIELDEND:
855: i = LastOfField(CursorAddress);
856: if (i != CursorAddress) {
857: CursorAddress = i; /* We moved; take this */
858: } else {
859: j = FieldInc(CursorAddress); /* Move to next field */
860: i = LastOfField(j);
861: if (i != j) {
862: CursorAddress = i; /* We moved; take this */
863: }
864: /* else - nowhere else on screen to be; stay here */
865: }
866: break;
867:
868: default:
869: RingBell(); /* We don't handle this yet */
870: }
871: }
872: }
873: return(origCount-count);
874: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.