1 /*-
2 * Copyright (c) 1988 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #ifndef lint
35 static char sccsid[] = "@(#)inbound.c 4.3 (Berkeley) 4/26/91";
36 #endif /* not lint */
37
38 #include <stdio.h>
39
40 #include "../general/general.h"
41 #include "function.h"
42 #include "hostctlr.h"
43 #include "oia.h"
44 #include "scrnctlr.h"
45 #include "screen.h"
46 #include "options.h"
47 #include "../api/dctype.h"
48 #include "../api/ebc_disp.h"
49
50 #include "../general/globals.h"
51 #include "externs.h"
52 #include "declare.h"
53
54 #define EmptyChar() (ourPTail == ourPHead)
55 #define FullChar() (ourPHead == ourBuffer+sizeof ourBuffer)
56
57
58 /*
59 * We define something to allow us to to IsProtected() quickly
60 * on unformatted screens (with the current algorithm for fields,
61 * unprotected takes exponential time...).
62 *
63 * The idea is to call SetXIsProtected() BEFORE the
64 * loop, then use XIsProtected().
65 */
66
67 #define SetXIsProtected() (XWasSF = 1)
68 #define XIsProtected(p) (IsStartField(p)? \
69 XWasSF = 1 : \
70 (XWasSF? \
71 (XWasSF = 0, XProtected = IsProtected(p)) : \
72 XProtected))
73
74 static char ourBuffer[400];
75
76 static char *ourPHead = ourBuffer,
77 *ourPTail = ourBuffer;
78
79 static int HadAid; /* Had an AID haven't sent */
80
81 static int InsertMode; /* is the terminal in insert mode? */
82
83 static unsigned int
84 rememberedshiftstate; /* Shift (alt) state of terminal */
85
86 # define HITNUM(s) ((((s)&(SHIFT_CAPS|SHIFT_UPSHIFT))? 1:0) \
87 + ((((s)&SHIFT_ALT)? 1:0)<<1))
88
89 static int XWasSF, XProtected; /* For optimizations */
90 #if !defined(PURE3274)
91 extern int TransparentClock, OutputClock;
92 #endif /* !defined(PURE3274) */
93
94 #include "kbd.out" /* Get keyboard mapping function */
95
96 /* the following are global variables */
97
98 extern int UnLocked; /* keyboard is UnLocked? */
99
100
101 /*
102 * init_inbound :
103 *
104 * Reset variables to initial state.
105 */
106
107 void
init_inbound()108 init_inbound()
109 {
110 ourPHead = ourPTail = ourBuffer;
111 HadAid = 0;
112 rememberedshiftstate = 0;
113 InsertMode = 0;
114 }
115
116
117 /* Tab() - sets cursor to the start of the next unprotected field */
118 static void
Tab()119 Tab()
120 {
121 register int i, j;
122
123 i = CursorAddress;
124 j = WhereAttrByte(CursorAddress);
125 do {
126 if (IsStartField(i) && IsUnProtected(ScreenInc(i))) {
127 break;
128 }
129 i = FieldInc(i);
130 } while (i != j);
131 if (IsStartField(i) && IsUnProtected(ScreenInc(i))) {
132 CursorAddress = ScreenInc(i);
133 } else {
134 CursorAddress = SetBufferAddress(0,0);
135 }
136 }
137
138
139 /* BackTab() - sets cursor to the start of the most recent field */
140
141 static void
BackTab()142 BackTab()
143 {
144 register int i;
145
146 i = ScreenDec(CursorAddress);
147 for (;;) {
148 if (IsStartField(ScreenDec(i)) && IsUnProtected(i)) {
149 CursorAddress = i;
150 break;
151 }
152 if (i == CursorAddress) {
153 CursorAddress = SetBufferAddress(0,0);
154 break;
155 }
156 i = ScreenDec(i);
157 }
158 }
159
160 /*
161 * ModifyMdt() - Turn a modified data tag bit on or off (watch
162 * out for unformatted screens).
163 */
164
ModifyMdt(x,on)165 ModifyMdt(x,on)
166 int x;
167 int on;
168 {
169 int i = x;
170
171 if (IsStartField(i)) { /* If we are at a start field position... */
172 if (on) {
173 ModifyHost(i, |= ATTR_MDT); /* Turn it on */
174 } else {
175 ModifyHost(i, &= ~ATTR_MDT); /* Turn it off */
176 }
177 } else {
178 i = WhereAttrByte(i); /* Find beginning of field */
179 if (IsStartField(i)) { /* Is there one? */
180 if (on) {
181 ModifyHost(i, |= ATTR_MDT); /* Turn it on */
182 } else {
183 ModifyHost(i, &= ~ATTR_MDT); /* Turn it off */
184 }
185 } /* else, don't modify - this is an unformatted screen */
186 }
187 }
188
189
190 /* EraseEndOfField - erase all characters to the end of a field */
191
192 static void
EraseEndOfField()193 EraseEndOfField()
194 {
195 register int i;
196
197 if (IsProtected(CursorAddress)) {
198 RingBell("Protected Field");
199 } else {
200 TurnOnMdt(CursorAddress);
201 if (FormattedScreen()) {
202 i = CursorAddress;
203 do {
204 AddHost(i, 0);
205 i = ScreenInc(i);
206 } while ((i != CursorAddress) && !IsStartField(i));
207 } else { /* Screen is Unformatted */
208 i = CursorAddress;
209 do {
210 AddHost(i, 0);
211 i = ScreenInc(i);
212 } while (i != HighestScreen());
213 }
214 }
215 }
216
217 /* Delete() - deletes a character from the screen
218 *
219 * What we want to do is delete the section
220 * [where, from-1] from the screen,
221 * filling in with what comes at from.
222 *
223 * The deleting continues to the end of the field (or
224 * until the cursor wraps).
225 *
226 * From can be a start of a field. We
227 * check for that. However, there can't be any
228 * fields that start between where and from.
229 * We don't check for that.
230 *
231 * Also, we assume that the protection status of
232 * everything has been checked by the caller.
233 *
234 */
235
236 static void
Delete(where,from)237 Delete(where, from)
238 register int where, /* Where to start deleting from */
239 from; /* Where to pull back from */
240 {
241 register int i;
242
243 TurnOnMdt(where); /* Only do this once in this field */
244 i = where;
245 do {
246 if (IsStartField(from)) {
247 AddHost(i, 0); /* Stick the edge at the start field */
248 } else {
249 AddHost(i, (char)GetHost(from));
250 from = ScreenInc(from); /* Move the edge */
251 }
252 i = ScreenInc(i);
253 } while ((!IsStartField(i)) && (i != where));
254 }
255
256 static void
ColBak()257 ColBak()
258 {
259 register int i;
260
261 i = ScreenLineOffset(CursorAddress);
262 for (i = i-1; i >= 0; i--) {
263 if (OptColTabs[i]) {
264 break;
265 }
266 }
267 if (i < 0) {
268 i = 0;
269 }
270 CursorAddress = SetBufferAddress(ScreenLine(CursorAddress), i);
271 }
272
273 static void
ColTab()274 ColTab()
275 {
276 register int i;
277
278 i = ScreenLineOffset(CursorAddress);
279 for (i = i+1; i < NumberColumns; i++) {
280 if (OptColTabs[i]) {
281 break;
282 }
283 }
284 if (i >= NumberColumns) {
285 i = NumberColumns-1;
286 }
287 CursorAddress = SetBufferAddress(ScreenLine(CursorAddress), i);
288 }
289
290 static void
Home()291 Home()
292 {
293 register int i;
294 register int j;
295
296 i = SetBufferAddress(OptHome, 0);
297 j = WhereLowByte(i);
298 /*
299 * If the initial value of i points to the field attribute of
300 * an unprotected field, we need to return the address of the
301 * first data byte in the field (assuming there are any!).
302 */
303 if (IsStartField(i) && IsUnProtected(j)) {
304 CursorAddress = j;
305 return;
306 }
307 do {
308 if (IsUnProtected(i)) {
309 CursorAddress = i;
310 return;
311 }
312 /* the following could be a problem if we got here with an
313 * unformatted screen. However, this is "impossible", since
314 * with an unformatted screen, the IsUnProtected(i) above
315 * should be true.
316 */
317 i = ScreenInc(FieldInc(i));
318 } while (i != j);
319 CursorAddress = LowestScreen();
320 }
321
322 static
LastOfField(i)323 LastOfField(i)
324 register int i; /* position to start from */
325 {
326 register int j;
327 register int k;
328
329 k = j = i;
330 SetXIsProtected();
331 while (XIsProtected(i) || Disspace(GetHost(i))) {
332 i = ScreenInc(i);
333 if (i == j) {
334 break;
335 }
336 }
337 /* We are now IN a word IN an unprotected field (or wrapped) */
338 while (!XIsProtected(i)) {
339 if (!Disspace(GetHost(i))) {
340 k = i;
341 }
342 i = ScreenInc(i);
343 if (i == j) {
344 break;
345 }
346 }
347 return(k);
348 }
349
350
351 static void
FlushChar()352 FlushChar()
353 {
354 ourPTail = ourPHead = ourBuffer;
355 }
356
357
358 /*
359 * Add one EBCDIC (NOT display code) character to the buffer.
360 */
361
362 static void
AddChar(character)363 AddChar(character)
364 char character;
365 {
366 if (FullChar()) {
367 ourPTail += DataToNetwork(ourPTail, ourPHead-ourPTail, 0);
368 if (EmptyChar()) {
369 FlushChar();
370 } else {
371 char buffer[100];
372
373 sprintf(buffer, "File %s, line %d: No room in network buffer!\n",
374 __FILE__, __LINE__);
375 ExitString(buffer, 1);
376 /*NOTREACHED*/
377 }
378 }
379 *ourPHead++ = character;
380 }
381
382
383 static void
SendUnformatted()384 SendUnformatted()
385 {
386 register int i, j;
387 register int Nulls;
388 register int c;
389
390 /* look for start of field */
391 Nulls = 0;
392 i = j = LowestScreen();
393 do {
394 c = GetHost(i);
395 if (c == 0) {
396 Nulls++;
397 } else {
398 while (Nulls) {
399 Nulls--;
400 AddChar(EBCDIC_BLANK); /* put in blanks */
401 }
402 AddChar((char)disp_ebc[c]);
403 }
404 i = ScreenInc(i);
405 } while (i != j);
406 }
407
408 static
SendField(i,cmd)409 SendField(i, cmd)
410 register int i; /* where we saw MDT bit */
411 int cmd; /* The command code (type of read) */
412 {
413 register int j;
414 register int k;
415 register int Nulls;
416 register int c;
417
418 /* look for start of field */
419 i = j = WhereLowByte(i);
420
421 /* On a test_request_read, don't send sba and address */
422 if ((AidByte != AID_TREQ)
423 || (cmd == CMD_SNA_READ_MODIFIED_ALL)) {
424 AddChar(ORDER_SBA); /* set start field */
425 AddChar(BufferTo3270_0(j)); /* set address of this field */
426 AddChar(BufferTo3270_1(j));
427 }
428 /*
429 * Only on read_modified_all do we return the contents
430 * of the field when the attention was caused by a
431 * selector pen.
432 */
433 if ((AidByte != AID_SELPEN)
434 || (cmd == CMD_SNA_READ_MODIFIED_ALL)) {
435 if (!IsStartField(j)) {
436 Nulls = 0;
437 k = ScreenInc(WhereHighByte(j));
438 do {
439 c = GetHost(j);
440 if (c == 0) {
441 Nulls++;
442 } else {
443 while (Nulls) {
444 Nulls--;
445 AddChar(EBCDIC_BLANK); /* put in blanks */
446 }
447 AddChar((char)disp_ebc[c]);
448 }
449 j = ScreenInc(j);
450 } while ((j != k) && (j != i));
451 }
452 } else {
453 j = FieldInc(j);
454 }
455 return(j);
456 }
457
458 /* Various types of reads... */
459 void
DoReadModified(cmd)460 DoReadModified(cmd)
461 int cmd; /* The command sent */
462 {
463 register int i, j;
464
465 if (AidByte) {
466 if (AidByte != AID_TREQ) {
467 AddChar(AidByte);
468 } else {
469 /* Test Request Read header */
470 AddChar(EBCDIC_SOH);
471 AddChar(EBCDIC_PERCENT);
472 AddChar(EBCDIC_SLASH);
473 AddChar(EBCDIC_STX);
474 }
475 } else {
476 AddChar(AID_NONE);
477 }
478 if (((AidByte != AID_PA1) && (AidByte != AID_PA2)
479 && (AidByte != AID_PA3) && (AidByte != AID_CLEAR))
480 || (cmd == CMD_SNA_READ_MODIFIED_ALL)) {
481 if ((AidByte != AID_TREQ)
482 || (cmd == CMD_SNA_READ_MODIFIED_ALL)) {
483 /* Test request read_modified doesn't give cursor address */
484 AddChar(BufferTo3270_0(CursorAddress));
485 AddChar(BufferTo3270_1(CursorAddress));
486 }
487 i = j = WhereAttrByte(LowestScreen());
488 /* Is this an unformatted screen? */
489 if (!IsStartField(i)) { /* yes, handle separate */
490 SendUnformatted();
491 } else {
492 do {
493 if (HasMdt(i)) {
494 i = SendField(i, cmd);
495 } else {
496 i = FieldInc(i);
497 }
498 } while (i != j);
499 }
500 }
501 ourPTail += DataToNetwork(ourPTail, ourPHead-ourPTail, 1);
502 if (EmptyChar()) {
503 FlushChar();
504 HadAid = 0; /* killed that buffer */
505 }
506 }
507
508 /* A read buffer operation... */
509
510 void
DoReadBuffer()511 DoReadBuffer()
512 {
513 register int i, j;
514
515 if (AidByte) {
516 AddChar(AidByte);
517 } else {
518 AddChar(AID_NONE);
519 }
520 AddChar(BufferTo3270_0(CursorAddress));
521 AddChar(BufferTo3270_1(CursorAddress));
522 i = j = LowestScreen();
523 do {
524 if (IsStartField(i)) {
525 AddChar(ORDER_SF);
526 AddChar(BufferTo3270_1(FieldAttributes(i)));
527 } else {
528 AddChar((char)disp_ebc[GetHost(i)]);
529 }
530 i = ScreenInc(i);
531 } while (i != j);
532 ourPTail += DataToNetwork(ourPTail, ourPHead-ourPTail, 1);
533 if (EmptyChar()) {
534 FlushChar();
535 HadAid = 0; /* killed that buffer */
536 }
537 }
538
539 /* Send some transparent data to the host */
540
541 void
SendTransparent(buffer,count)542 SendTransparent(buffer, count)
543 char *buffer;
544 int count;
545 {
546 char stuff[3];
547
548 stuff[0] = AID_NONE_PRINTER;
549 stuff[1] = BufferTo3270_0(count);
550 stuff[2] = BufferTo3270_1(count);
551 DataToNetwork(stuff, sizeof stuff, 0);
552 DataToNetwork(buffer, count, 1);
553 }
554
555
556 /* Try to send some data to host */
557
558 void
SendToIBM()559 SendToIBM()
560 {
561 #if !defined(PURE3274)
562 if (TransparentClock >= OutputClock) {
563 if (HadAid) {
564 AddChar(AidByte);
565 HadAid = 0;
566 } else {
567 AddChar(AID_NONE_PRINTER);
568 }
569 do {
570 ourPTail += DataToNetwork(ourPTail, ourPHead-ourPTail, 1);
571 } while (!EmptyChar());
572 FlushChar();
573 } else if (HadAid) {
574 DoReadModified(CMD_READ_MODIFIED);
575 }
576 #else /* !defined(PURE3274) */
577 if (HadAid) {
578 DoReadModified(CMD_READ_MODIFIED);
579 }
580 #endif /* !defined(PURE3274) */
581 }
582
583 /* This takes in one character from the keyboard and places it on the
584 * screen.
585 */
586
587 static void
OneCharacter(c,insert)588 OneCharacter(c, insert)
589 int c; /* character (Ebcdic) to be shoved in */
590 int insert; /* are we in insert mode? */
591 {
592 register int i, j;
593
594 if (IsProtected(CursorAddress)) {
595 RingBell("Protected Field");
596 return;
597 }
598 if (insert) {
599 /* is the last character in the field a blank or null? */
600 i = ScreenDec(FieldInc(CursorAddress));
601 j = GetHost(i);
602 if (!Disspace(j)) {
603 RingBell("No more room for insert");
604 return;
605 } else {
606 for (j = ScreenDec(i); i != CursorAddress;
607 j = ScreenDec(j), i = ScreenDec(i)) {
608 AddHost(i, (char)GetHost(j));
609 }
610 }
611 }
612 AddHost(CursorAddress, c);
613 TurnOnMdt(CursorAddress);
614 CursorAddress = ScreenInc(CursorAddress);
615 if (IsStartField(CursorAddress) &&
616 ((FieldAttributes(CursorAddress)&ATTR_AUTO_SKIP_MASK) ==
617 ATTR_AUTO_SKIP_VALUE)) {
618 Tab();
619 }
620 }
621
622 /*
623 * AcceptKeystroke()
624 *
625 * Processes one keystroke.
626 *
627 * Returns:
628 *
629 * 0 if this keystroke was NOT processed.
630 * 1 if everything went OK.
631 */
632
633 int
AcceptKeystroke(scancode,shiftstate)634 AcceptKeystroke(scancode, shiftstate)
635 unsigned int
636 scancode, /* 3270 scancode */
637 shiftstate; /* The shift state */
638 {
639 register int c;
640 register int i;
641 register int j;
642 enum ctlrfcn ctlrfcn;
643
644 if (scancode >= numberof(hits)) {
645 ExitString(
646 "Unknown scancode encountered in AcceptKeystroke.\n", 1);
647 /*NOTREACHED*/
648 }
649 ctlrfcn = hits[scancode].hit[HITNUM(shiftstate)].ctlrfcn;
650 c = hits[scancode].hit[HITNUM(shiftstate)].code;
651
652 if (!UnLocked || HadAid) {
653 if (HadAid) {
654 SendToIBM();
655 if (!EmptyChar()) {
656 return 0; /* nothing to do */
657 }
658 }
659 #if !defined(PURE3274)
660 if (!HadAid && EmptyChar()) {
661 if ((ctlrfcn == FCN_RESET) || (ctlrfcn == FCN_MASTER_RESET)) {
662 UnLocked = 1;
663 }
664 }
665 #endif /* !defined(PURE3274) */
666 if (!UnLocked) {
667 return 0;
668 }
669 }
670
671 /* now, either empty, or haven't seen aid yet */
672
673 #if !defined(PURE3274)
674 /*
675 * If we are in transparent (output) mode, do something special
676 * with keystrokes.
677 */
678 if (TransparentClock == OutputClock) {
679 if (ctlrfcn == FCN_AID) {
680 UnLocked = 0;
681 InsertMode = 0;
682 AidByte = (c);
683 HadAid = 1;
684 } else {
685 switch (ctlrfcn) {
686 case FCN_ESCAPE:
687 StopScreen(1);
688 command(0);
689 if (shell_active == 0) {
690 ConnectScreen();
691 }
692 break;
693
694 case FCN_RESET:
695 case FCN_MASTER_RESET:
696 UnLocked = 1;
697 break;
698
699 default:
700 return 0;
701 }
702 }
703 }
704 #endif /* !defined(PURE3274) */
705
706 if (ctlrfcn == FCN_CHARACTER) {
707 /* Add the character to the buffer */
708 OneCharacter(c, InsertMode);
709 } else if (ctlrfcn == FCN_AID) { /* got Aid */
710 if (c == AID_CLEAR) {
711 LocalClearScreen(); /* Side effect is to clear 3270 */
712 }
713 ResetOiaOnlineA(&OperatorInformationArea);
714 SetOiaTWait(&OperatorInformationArea);
715 ResetOiaInsert(&OperatorInformationArea);
716 InsertMode = 0; /* just like a 3278 */
717 SetOiaSystemLocked(&OperatorInformationArea);
718 SetOiaModified();
719 UnLocked = 0;
720 AidByte = c;
721 HadAid = 1;
722 SendToIBM();
723 } else {
724 switch (ctlrfcn) {
725
726 case FCN_CURSEL:
727 c = FieldAttributes(CursorAddress)&ATTR_DSPD_MASK;
728 if (!FormattedScreen()
729 || ((c != ATTR_DSPD_DSPD) && (c != ATTR_DSPD_HIGH))) {
730 RingBell("Cursor not in selectable field");
731 } else {
732 i = ScreenInc(WhereAttrByte(CursorAddress));
733 c = GetHost(i);
734 if (c == DISP_QUESTION) {
735 AddHost(i, DISP_GREATER_THAN);
736 TurnOnMdt(i);
737 } else if (c == DISP_GREATER_THAN) {
738 AddHost(i, DISP_QUESTION);
739 TurnOffMdt(i);
740 } else if (c == DISP_BLANK || c == DISP_NULL
741 || c == DISP_AMPERSAND) {
742 UnLocked = 0;
743 InsertMode = 0;
744 ResetOiaOnlineA(&OperatorInformationArea);
745 SetOiaTWait(&OperatorInformationArea);
746 SetOiaSystemLocked(&OperatorInformationArea);
747 ResetOiaInsert(&OperatorInformationArea);
748 SetOiaModified();
749 if (c == DISP_AMPERSAND) {
750 TurnOnMdt(i); /* Only for & type */
751 AidByte = AID_ENTER;
752 } else {
753 AidByte = AID_SELPEN;
754 }
755 HadAid = 1;
756 SendToIBM();
757 } else {
758 RingBell(
759 "Cursor not in a selectable field (designator)");
760 }
761 }
762 break;
763
764 #if !defined(PURE3274)
765 case FCN_ERASE:
766 if (IsProtected(ScreenDec(CursorAddress))) {
767 RingBell("Protected Field");
768 } else {
769 CursorAddress = ScreenDec(CursorAddress);
770 Delete(CursorAddress, ScreenInc(CursorAddress));
771 }
772 break;
773 case FCN_WERASE:
774 j = CursorAddress;
775 i = ScreenDec(j);
776 if (IsProtected(i)) {
777 RingBell("Protected Field");
778 } else {
779 SetXIsProtected();
780 while ((!XIsProtected(i) && Disspace(GetHost(i)))
781 && (i != j)) {
782 i = ScreenDec(i);
783 }
784 /* we are pointing at a character in a word, or
785 * at a protected position
786 */
787 while ((!XIsProtected(i) && !Disspace(GetHost(i)))
788 && (i != j)) {
789 i = ScreenDec(i);
790 }
791 /* we are pointing at a space, or at a protected
792 * position
793 */
794 CursorAddress = ScreenInc(i);
795 Delete(CursorAddress, j);
796 }
797 break;
798
799 case FCN_FERASE:
800 if (IsProtected(CursorAddress)) {
801 RingBell("Protected Field");
802 } else {
803 CursorAddress = ScreenInc(CursorAddress); /* for btab */
804 BackTab();
805 EraseEndOfField();
806 }
807 break;
808
809 case FCN_RESET:
810 if (InsertMode) {
811 InsertMode = 0;
812 ResetOiaInsert(&OperatorInformationArea);
813 SetOiaModified();
814 }
815 break;
816 case FCN_MASTER_RESET:
817 if (InsertMode) {
818 InsertMode = 0;
819 ResetOiaInsert(&OperatorInformationArea);
820 SetOiaModified();
821 }
822 RefreshScreen();
823 break;
824 #endif /* !defined(PURE3274) */
825
826 case FCN_UP:
827 CursorAddress = ScreenUp(CursorAddress);
828 break;
829
830 case FCN_LEFT:
831 CursorAddress = ScreenDec(CursorAddress);
832 break;
833
834 case FCN_RIGHT:
835 CursorAddress = ScreenInc(CursorAddress);
836 break;
837
838 case FCN_DOWN:
839 CursorAddress = ScreenDown(CursorAddress);
840 break;
841
842 case FCN_DELETE:
843 if (IsProtected(CursorAddress)) {
844 RingBell("Protected Field");
845 } else {
846 Delete(CursorAddress, ScreenInc(CursorAddress));
847 }
848 break;
849
850 case FCN_INSRT:
851 InsertMode = !InsertMode;
852 if (InsertMode) {
853 SetOiaInsert(&OperatorInformationArea);
854 } else {
855 ResetOiaInsert(&OperatorInformationArea);
856 }
857 SetOiaModified();
858 break;
859
860 case FCN_HOME:
861 Home();
862 break;
863
864 case FCN_NL:
865 /* The algorithm is to look for the first unprotected
866 * column after column 0 of the following line. Having
867 * found that unprotected column, we check whether the
868 * cursor-address-at-entry is at or to the right of the
869 * LeftMargin AND the LeftMargin column of the found line
870 * is unprotected. If this conjunction is true, then
871 * we set the found pointer to the address of the LeftMargin
872 * column in the found line.
873 * Then, we set the cursor address to the found address.
874 */
875 i = SetBufferAddress(ScreenLine(ScreenDown(CursorAddress)), 0);
876 j = ScreenInc(WhereAttrByte(CursorAddress));
877 do {
878 if (IsUnProtected(i)) {
879 break;
880 }
881 /* Again (see comment in Home()), this COULD be a problem
882 * with an unformatted screen.
883 */
884 /* If there was a field with only an attribute byte,
885 * we may be pointing to the attribute byte of the NEXT
886 * field, so just look at the next byte.
887 */
888 if (IsStartField(i)) {
889 i = ScreenInc(i);
890 } else {
891 i = ScreenInc(FieldInc(i));
892 }
893 } while (i != j);
894 if (!IsUnProtected(i)) { /* couldn't find unprotected */
895 i = SetBufferAddress(0,0);
896 }
897 if (OptLeftMargin <= ScreenLineOffset(CursorAddress)) {
898 if (IsUnProtected(SetBufferAddress(ScreenLine(i),
899 OptLeftMargin))) {
900 i = SetBufferAddress(ScreenLine(i), OptLeftMargin);
901 }
902 }
903 CursorAddress = i;
904 break;
905
906 case FCN_EINP:
907 if (!FormattedScreen()) {
908 i = CursorAddress;
909 TurnOffMdt(i);
910 do {
911 AddHost(i, 0);
912 i = ScreenInc(i);
913 } while (i != CursorAddress);
914 } else {
915 /*
916 * The algorithm is: go through each unprotected
917 * field on the screen, clearing it out. When
918 * we are at the start of a field, skip that field
919 * if its contents are protected.
920 */
921 i = j = FieldInc(CursorAddress);
922 do {
923 if (IsUnProtected(ScreenInc(i))) {
924 i = ScreenInc(i);
925 TurnOffMdt(i);
926 do {
927 AddHost(i, 0);
928 i = ScreenInc(i);
929 } while (!IsStartField(i));
930 } else {
931 i = FieldInc(i);
932 }
933 } while (i != j);
934 }
935 Home();
936 break;
937
938 case FCN_EEOF:
939 EraseEndOfField();
940 break;
941
942 case FCN_SPACE:
943 OneCharacter(DISP_BLANK, InsertMode); /* Add cent */
944 break;
945
946 case FCN_CENTSIGN:
947 OneCharacter(DISP_CENTSIGN, InsertMode); /* Add cent */
948 break;
949
950 case FCN_FM:
951 OneCharacter(DISP_FM, InsertMode); /* Add field mark */
952 break;
953
954 case FCN_DP:
955 if (IsProtected(CursorAddress)) {
956 RingBell("Protected Field");
957 } else {
958 OneCharacter(DISP_DUP, InsertMode);/* Add dup character */
959 Tab();
960 }
961 break;
962
963 case FCN_TAB:
964 Tab();
965 break;
966
967 case FCN_BTAB:
968 BackTab();
969 break;
970
971 #ifdef NOTUSED /* Actually, this is superseded by unix flow
972 * control.
973 */
974 case FCN_XOFF:
975 Flow = 0; /* stop output */
976 break;
977
978 case FCN_XON:
979 if (!Flow) {
980 Flow = 1; /* turn it back on */
981 DoTerminalOutput();
982 }
983 break;
984 #endif /* NOTUSED */
985
986 #if !defined(PURE3274)
987 case FCN_ESCAPE:
988 /* FlushChar(); do we want to flush characters from before? */
989 StopScreen(1);
990 command(0);
991 if (shell_active == 0) {
992 ConnectScreen();
993 }
994 break;
995
996 case FCN_DISC:
997 StopScreen(1);
998 suspend();
999 setconnmode();
1000 ConnectScreen();
1001 break;
1002
1003 case FCN_RESHOW:
1004 RefreshScreen();
1005 break;
1006
1007 case FCN_SETTAB:
1008 OptColTabs[ScreenLineOffset(CursorAddress)] = 1;
1009 break;
1010
1011 case FCN_DELTAB:
1012 OptColTabs[ScreenLineOffset(CursorAddress)] = 0;
1013 break;
1014
1015 /*
1016 * Clear all tabs, home line, and left margin.
1017 */
1018 case FCN_CLRTAB:
1019 for (i = 0; i < sizeof OptColTabs; i++) {
1020 OptColTabs[i] = 0;
1021 }
1022 OptHome = 0;
1023 OptLeftMargin = 0;
1024 break;
1025
1026 case FCN_COLTAB:
1027 ColTab();
1028 break;
1029
1030 case FCN_COLBAK:
1031 ColBak();
1032 break;
1033
1034 case FCN_INDENT:
1035 ColTab();
1036 OptLeftMargin = ScreenLineOffset(CursorAddress);
1037 break;
1038
1039 case FCN_UNDENT:
1040 ColBak();
1041 OptLeftMargin = ScreenLineOffset(CursorAddress);
1042 break;
1043
1044 case FCN_SETMRG:
1045 OptLeftMargin = ScreenLineOffset(CursorAddress);
1046 break;
1047
1048 case FCN_SETHOM:
1049 OptHome = ScreenLine(CursorAddress);
1050 break;
1051
1052 /*
1053 * Point to first character of next unprotected word on
1054 * screen.
1055 */
1056 case FCN_WORDTAB:
1057 i = CursorAddress;
1058 SetXIsProtected();
1059 while (!XIsProtected(i) && !Disspace(GetHost(i))) {
1060 i = ScreenInc(i);
1061 if (i == CursorAddress) {
1062 break;
1063 }
1064 }
1065 /* i is either protected, a space (blank or null),
1066 * or wrapped
1067 */
1068 while (XIsProtected(i) || Disspace(GetHost(i))) {
1069 i = ScreenInc(i);
1070 if (i == CursorAddress) {
1071 break;
1072 }
1073 }
1074 CursorAddress = i;
1075 break;
1076
1077 case FCN_WORDBACKTAB:
1078 i = ScreenDec(CursorAddress);
1079 SetXIsProtected();
1080 while (XIsProtected(i) || Disspace(GetHost(i))) {
1081 i = ScreenDec(i);
1082 if (i == CursorAddress) {
1083 break;
1084 }
1085 }
1086 /* i is pointing to a character IN an unprotected word
1087 * (or i wrapped)
1088 */
1089 while (!Disspace(GetHost(i))) {
1090 i = ScreenDec(i);
1091 if (i == CursorAddress) {
1092 break;
1093 }
1094 }
1095 CursorAddress = ScreenInc(i);
1096 break;
1097
1098 /* Point to last non-blank character of this/next
1099 * unprotected word.
1100 */
1101 case FCN_WORDEND:
1102 i = ScreenInc(CursorAddress);
1103 SetXIsProtected();
1104 while (XIsProtected(i) || Disspace(GetHost(i))) {
1105 i = ScreenInc(i);
1106 if (i == CursorAddress) {
1107 break;
1108 }
1109 }
1110 /* we are pointing at a character IN an
1111 * unprotected word (or we wrapped)
1112 */
1113 while (!Disspace(GetHost(i))) {
1114 i = ScreenInc(i);
1115 if (i == CursorAddress) {
1116 break;
1117 }
1118 }
1119 CursorAddress = ScreenDec(i);
1120 break;
1121
1122 /* Get to last non-blank of this/next unprotected
1123 * field.
1124 */
1125 case FCN_FIELDEND:
1126 i = LastOfField(CursorAddress);
1127 if (i != CursorAddress) {
1128 CursorAddress = i; /* We moved; take this */
1129 } else {
1130 j = FieldInc(CursorAddress); /* Move to next field */
1131 i = LastOfField(j);
1132 if (i != j) {
1133 CursorAddress = i; /* We moved; take this */
1134 }
1135 /* else - nowhere else on screen to be; stay here */
1136 }
1137 break;
1138 #endif /* !defined(PURE3274) */
1139
1140 default:
1141 /* We don't handle this yet */
1142 RingBell("Function not implemented");
1143 }
1144 }
1145 return 1; /* We did something! */
1146 }
1147
1148
1149 /*
1150 * We get data from the terminal. We keep track of the shift state
1151 * (including ALT, CONTROL), and then call AcceptKeystroke to actually
1152 * process any non-shift keys.
1153 */
1154
1155 int
DataFrom3270(buffer,count)1156 DataFrom3270(buffer, count)
1157 unsigned char *buffer; /* where the data is */
1158 int count; /* how much data there is */
1159 {
1160 int origCount;
1161
1162 origCount = count;
1163
1164 while (count) {
1165 if (*buffer >= numberof(hits)) {
1166 ExitString("Unknown scancode encountered in DataFrom3270.\n", 1);
1167 /*NOTREACHED*/
1168 }
1169
1170 switch (hits[*buffer].hit[HITNUM(rememberedshiftstate)].ctlrfcn) {
1171
1172 case FCN_MAKE_SHIFT:
1173 rememberedshiftstate |= (SHIFT_RIGHT|SHIFT_UPSHIFT);
1174 break;
1175 case FCN_BREAK_SHIFT:
1176 rememberedshiftstate &= ~(SHIFT_RIGHT|SHIFT_UPSHIFT);
1177 break;
1178 case FCN_MAKE_ALT:
1179 rememberedshiftstate |= SHIFT_ALT;
1180 break;
1181 case FCN_BREAK_ALT:
1182 rememberedshiftstate &= ~SHIFT_ALT;
1183 break;
1184 default:
1185 if (AcceptKeystroke(*buffer, rememberedshiftstate) == 0) {
1186 return(origCount-count);
1187 }
1188 break;
1189 }
1190 buffer++;
1191 count--;
1192 }
1193 return(origCount-count);
1194 }
1195