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