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