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