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