summaryrefslogtreecommitdiff
path: root/usr.bin/tn3270/ctlr/inbound.c
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>1995-10-18 08:53:40 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>1995-10-18 08:53:40 +0000
commitd6583bb2a13f329cf0332ef2570eb8bb8fc0e39c (patch)
treeece253b876159b39c620e62b6c9b1174642e070e /usr.bin/tn3270/ctlr/inbound.c
initial import of NetBSD tree
Diffstat (limited to 'usr.bin/tn3270/ctlr/inbound.c')
-rw-r--r--usr.bin/tn3270/ctlr/inbound.c1195
1 files changed, 1195 insertions, 0 deletions
diff --git a/usr.bin/tn3270/ctlr/inbound.c b/usr.bin/tn3270/ctlr/inbound.c
new file mode 100644
index 00000000000..babadac867b
--- /dev/null
+++ b/usr.bin/tn3270/ctlr/inbound.c
@@ -0,0 +1,1195 @@
+/*-
+ * Copyright (c) 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+/*static char sccsid[] = "from: @(#)inbound.c 4.3 (Berkeley) 4/26/91";*/
+static char rcsid[] = "$Id: inbound.c,v 1.1 1995/10/18 08:46:21 deraadt Exp $";
+#endif /* not lint */
+
+#include <stdio.h>
+
+#include "../general/general.h"
+#include "function.h"
+#include "hostctlr.h"
+#include "oia.h"
+#include "scrnctlr.h"
+#include "screen.h"
+#include "options.h"
+#include "../api/dctype.h"
+#include "../api/ebc_disp.h"
+
+#include "../general/globals.h"
+#include "externs.h"
+#include "declare.h"
+
+#define EmptyChar() (ourPTail == ourPHead)
+#define FullChar() (ourPHead == ourBuffer+sizeof ourBuffer)
+
+
+/*
+ * We define something to allow us to to IsProtected() quickly
+ * on unformatted screens (with the current algorithm for fields,
+ * unprotected takes exponential time...).
+ *
+ * The idea is to call SetXIsProtected() BEFORE the
+ * loop, then use XIsProtected().
+ */
+
+#define SetXIsProtected() (XWasSF = 1)
+#define XIsProtected(p) (IsStartField(p)? \
+ XWasSF = 1 : \
+ (XWasSF? \
+ (XWasSF = 0, XProtected = IsProtected(p)) : \
+ XProtected))
+
+static char ourBuffer[400];
+
+static char *ourPHead = ourBuffer,
+ *ourPTail = ourBuffer;
+
+static int HadAid; /* Had an AID haven't sent */
+
+static int InsertMode; /* is the terminal in insert mode? */
+
+static unsigned int
+ rememberedshiftstate; /* Shift (alt) state of terminal */
+
+# define HITNUM(s) ((((s)&(SHIFT_CAPS|SHIFT_UPSHIFT))? 1:0) \
+ + ((((s)&SHIFT_ALT)? 1:0)<<1))
+
+static int XWasSF, XProtected; /* For optimizations */
+#if !defined(PURE3274)
+extern int TransparentClock, OutputClock;
+#endif /* !defined(PURE3274) */
+
+#include "kbd.out" /* Get keyboard mapping function */
+
+/* the following are global variables */
+
+extern int UnLocked; /* keyboard is UnLocked? */
+
+
+/*
+ * init_inbound :
+ *
+ * Reset variables to initial state.
+ */
+
+void
+init_inbound()
+{
+ ourPHead = ourPTail = ourBuffer;
+ HadAid = 0;
+ rememberedshiftstate = 0;
+ InsertMode = 0;
+}
+
+
+/* Tab() - sets cursor to the start of the next unprotected field */
+static void
+Tab()
+{
+ register int i, j;
+
+ i = CursorAddress;
+ j = WhereAttrByte(CursorAddress);
+ do {
+ if (IsStartField(i) && IsUnProtected(ScreenInc(i))) {
+ break;
+ }
+ i = FieldInc(i);
+ } while (i != j);
+ if (IsStartField(i) && IsUnProtected(ScreenInc(i))) {
+ CursorAddress = ScreenInc(i);
+ } else {
+ CursorAddress = SetBufferAddress(0,0);
+ }
+}
+
+
+/* BackTab() - sets cursor to the start of the most recent field */
+
+static void
+BackTab()
+{
+ register int i;
+
+ i = ScreenDec(CursorAddress);
+ for (;;) {
+ if (IsStartField(ScreenDec(i)) && IsUnProtected(i)) {
+ CursorAddress = i;
+ break;
+ }
+ if (i == CursorAddress) {
+ CursorAddress = SetBufferAddress(0,0);
+ break;
+ }
+ i = ScreenDec(i);
+ }
+}
+
+/*
+ * ModifyMdt() - Turn a modified data tag bit on or off (watch
+ * out for unformatted screens).
+ */
+
+ModifyMdt(x,on)
+int x;
+int on;
+{
+ int i = x;
+
+ if (IsStartField(i)) { /* If we are at a start field position... */
+ if (on) {
+ ModifyHost(i, |= ATTR_MDT); /* Turn it on */
+ } else {
+ ModifyHost(i, &= ~ATTR_MDT); /* Turn it off */
+ }
+ } else {
+ i = WhereAttrByte(i); /* Find beginning of field */
+ if (IsStartField(i)) { /* Is there one? */
+ if (on) {
+ ModifyHost(i, |= ATTR_MDT); /* Turn it on */
+ } else {
+ ModifyHost(i, &= ~ATTR_MDT); /* Turn it off */
+ }
+ } /* else, don't modify - this is an unformatted screen */
+ }
+}
+
+
+/* EraseEndOfField - erase all characters to the end of a field */
+
+static void
+EraseEndOfField()
+{
+ register int i;
+
+ if (IsProtected(CursorAddress)) {
+ RingBell("Protected Field");
+ } else {
+ TurnOnMdt(CursorAddress);
+ if (FormattedScreen()) {
+ i = CursorAddress;
+ do {
+ AddHost(i, 0);
+ i = ScreenInc(i);
+ } while ((i != CursorAddress) && !IsStartField(i));
+ } else { /* Screen is Unformatted */
+ i = CursorAddress;
+ do {
+ AddHost(i, 0);
+ i = ScreenInc(i);
+ } while (i != HighestScreen());
+ }
+ }
+}
+
+/* Delete() - deletes a character from the screen
+ *
+ * What we want to do is delete the section
+ * [where, from-1] from the screen,
+ * filling in with what comes at from.
+ *
+ * The deleting continues to the end of the field (or
+ * until the cursor wraps).
+ *
+ * From can be a start of a field. We
+ * check for that. However, there can't be any
+ * fields that start between where and from.
+ * We don't check for that.
+ *
+ * Also, we assume that the protection status of
+ * everything has been checked by the caller.
+ *
+ */
+
+static void
+Delete(where, from)
+register int where, /* Where to start deleting from */
+ from; /* Where to pull back from */
+{
+ register int i;
+
+ TurnOnMdt(where); /* Only do this once in this field */
+ i = where;
+ do {
+ if (IsStartField(from)) {
+ AddHost(i, 0); /* Stick the edge at the start field */
+ } else {
+ AddHost(i, (char)GetHost(from));
+ from = ScreenInc(from); /* Move the edge */
+ }
+ i = ScreenInc(i);
+ } while ((!IsStartField(i)) && (i != where));
+}
+
+static void
+ColBak()
+{
+ register int i;
+
+ i = ScreenLineOffset(CursorAddress);
+ for (i = i-1; i >= 0; i--) {
+ if (OptColTabs[i]) {
+ break;
+ }
+ }
+ if (i < 0) {
+ i = 0;
+ }
+ CursorAddress = SetBufferAddress(ScreenLine(CursorAddress), i);
+}
+
+static void
+ColTab()
+{
+ register int i;
+
+ i = ScreenLineOffset(CursorAddress);
+ for (i = i+1; i < NumberColumns; i++) {
+ if (OptColTabs[i]) {
+ break;
+ }
+ }
+ if (i >= NumberColumns) {
+ i = NumberColumns-1;
+ }
+ CursorAddress = SetBufferAddress(ScreenLine(CursorAddress), i);
+}
+
+static void
+Home()
+{
+ register int i;
+ register int j;
+
+ i = SetBufferAddress(OptHome, 0);
+ j = WhereLowByte(i);
+ /*
+ * If the initial value of i points to the field attribute of
+ * an unprotected field, we need to return the address of the
+ * first data byte in the field (assuming there are any!).
+ */
+ if (IsStartField(i) && IsUnProtected(j)) {
+ CursorAddress = j;
+ return;
+ }
+ do {
+ if (IsUnProtected(i)) {
+ CursorAddress = i;
+ return;
+ }
+ /* the following could be a problem if we got here with an
+ * unformatted screen. However, this is "impossible", since
+ * with an unformatted screen, the IsUnProtected(i) above
+ * should be true.
+ */
+ i = ScreenInc(FieldInc(i));
+ } while (i != j);
+ CursorAddress = LowestScreen();
+}
+
+static
+LastOfField(i)
+register int i; /* position to start from */
+{
+ register int j;
+ register int k;
+
+ k = j = i;
+ SetXIsProtected();
+ while (XIsProtected(i) || Disspace(GetHost(i))) {
+ i = ScreenInc(i);
+ if (i == j) {
+ break;
+ }
+ }
+ /* We are now IN a word IN an unprotected field (or wrapped) */
+ while (!XIsProtected(i)) {
+ if (!Disspace(GetHost(i))) {
+ k = i;
+ }
+ i = ScreenInc(i);
+ if (i == j) {
+ break;
+ }
+ }
+ return(k);
+}
+
+
+static void
+FlushChar()
+{
+ ourPTail = ourPHead = ourBuffer;
+}
+
+
+/*
+ * Add one EBCDIC (NOT display code) character to the buffer.
+ */
+
+static void
+AddChar(character)
+char character;
+{
+ if (FullChar()) {
+ ourPTail += DataToNetwork(ourPTail, ourPHead-ourPTail, 0);
+ if (EmptyChar()) {
+ FlushChar();
+ } else {
+ char buffer[100];
+
+ sprintf(buffer, "File %s, line %d: No room in network buffer!\n",
+ __FILE__, __LINE__);
+ ExitString(buffer, 1);
+ /*NOTREACHED*/
+ }
+ }
+ *ourPHead++ = character;
+}
+
+
+static void
+SendUnformatted()
+{
+ register int i, j;
+ register int Nulls;
+ register int c;
+
+ /* look for start of field */
+ Nulls = 0;
+ i = j = LowestScreen();
+ do {
+ c = GetHost(i);
+ if (c == 0) {
+ Nulls++;
+ } else {
+ while (Nulls) {
+ Nulls--;
+ AddChar(EBCDIC_BLANK); /* put in blanks */
+ }
+ AddChar((char)disp_ebc[c]);
+ }
+ i = ScreenInc(i);
+ } while (i != j);
+}
+
+static
+SendField(i, cmd)
+register int i; /* where we saw MDT bit */
+int cmd; /* The command code (type of read) */
+{
+ register int j;
+ register int k;
+ register int Nulls;
+ register int c;
+
+ /* look for start of field */
+ i = j = WhereLowByte(i);
+
+ /* On a test_request_read, don't send sba and address */
+ if ((AidByte != AID_TREQ)
+ || (cmd == CMD_SNA_READ_MODIFIED_ALL)) {
+ AddChar(ORDER_SBA); /* set start field */
+ AddChar(BufferTo3270_0(j)); /* set address of this field */
+ AddChar(BufferTo3270_1(j));
+ }
+ /*
+ * Only on read_modified_all do we return the contents
+ * of the field when the attention was caused by a
+ * selector pen.
+ */
+ if ((AidByte != AID_SELPEN)
+ || (cmd == CMD_SNA_READ_MODIFIED_ALL)) {
+ if (!IsStartField(j)) {
+ Nulls = 0;
+ k = ScreenInc(WhereHighByte(j));
+ do {
+ c = GetHost(j);
+ if (c == 0) {
+ Nulls++;
+ } else {
+ while (Nulls) {
+ Nulls--;
+ AddChar(EBCDIC_BLANK); /* put in blanks */
+ }
+ AddChar((char)disp_ebc[c]);
+ }
+ j = ScreenInc(j);
+ } while ((j != k) && (j != i));
+ }
+ } else {
+ j = FieldInc(j);
+ }
+ return(j);
+}
+
+/* Various types of reads... */
+void
+DoReadModified(cmd)
+int cmd; /* The command sent */
+{
+ register int i, j;
+
+ if (AidByte) {
+ if (AidByte != AID_TREQ) {
+ AddChar(AidByte);
+ } else {
+ /* Test Request Read header */
+ AddChar(EBCDIC_SOH);
+ AddChar(EBCDIC_PERCENT);
+ AddChar(EBCDIC_SLASH);
+ AddChar(EBCDIC_STX);
+ }
+ } else {
+ AddChar(AID_NONE);
+ }
+ if (((AidByte != AID_PA1) && (AidByte != AID_PA2)
+ && (AidByte != AID_PA3) && (AidByte != AID_CLEAR))
+ || (cmd == CMD_SNA_READ_MODIFIED_ALL)) {
+ if ((AidByte != AID_TREQ)
+ || (cmd == CMD_SNA_READ_MODIFIED_ALL)) {
+ /* Test request read_modified doesn't give cursor address */
+ AddChar(BufferTo3270_0(CursorAddress));
+ AddChar(BufferTo3270_1(CursorAddress));
+ }
+ i = j = WhereAttrByte(LowestScreen());
+ /* Is this an unformatted screen? */
+ if (!IsStartField(i)) { /* yes, handle separate */
+ SendUnformatted();
+ } else {
+ do {
+ if (HasMdt(i)) {
+ i = SendField(i, cmd);
+ } else {
+ i = FieldInc(i);
+ }
+ } while (i != j);
+ }
+ }
+ ourPTail += DataToNetwork(ourPTail, ourPHead-ourPTail, 1);
+ if (EmptyChar()) {
+ FlushChar();
+ HadAid = 0; /* killed that buffer */
+ }
+}
+
+/* A read buffer operation... */
+
+void
+DoReadBuffer()
+{
+ register int i, j;
+
+ if (AidByte) {
+ AddChar(AidByte);
+ } else {
+ AddChar(AID_NONE);
+ }
+ AddChar(BufferTo3270_0(CursorAddress));
+ AddChar(BufferTo3270_1(CursorAddress));
+ i = j = LowestScreen();
+ do {
+ if (IsStartField(i)) {
+ AddChar(ORDER_SF);
+ AddChar(BufferTo3270_1(FieldAttributes(i)));
+ } else {
+ AddChar((char)disp_ebc[GetHost(i)]);
+ }
+ i = ScreenInc(i);
+ } while (i != j);
+ ourPTail += DataToNetwork(ourPTail, ourPHead-ourPTail, 1);
+ if (EmptyChar()) {
+ FlushChar();
+ HadAid = 0; /* killed that buffer */
+ }
+}
+
+/* Send some transparent data to the host */
+
+void
+SendTransparent(buffer, count)
+char *buffer;
+int count;
+{
+ char stuff[3];
+
+ stuff[0] = AID_NONE_PRINTER;
+ stuff[1] = BufferTo3270_0(count);
+ stuff[2] = BufferTo3270_1(count);
+ DataToNetwork(stuff, sizeof stuff, 0);
+ DataToNetwork(buffer, count, 1);
+}
+
+
+/* Try to send some data to host */
+
+void
+SendToIBM()
+{
+#if !defined(PURE3274)
+ if (TransparentClock >= OutputClock) {
+ if (HadAid) {
+ AddChar(AidByte);
+ HadAid = 0;
+ } else {
+ AddChar(AID_NONE_PRINTER);
+ }
+ do {
+ ourPTail += DataToNetwork(ourPTail, ourPHead-ourPTail, 1);
+ } while (!EmptyChar());
+ FlushChar();
+ } else if (HadAid) {
+ DoReadModified(CMD_READ_MODIFIED);
+ }
+#else /* !defined(PURE3274) */
+ if (HadAid) {
+ DoReadModified(CMD_READ_MODIFIED);
+ }
+#endif /* !defined(PURE3274) */
+}
+
+/* This takes in one character from the keyboard and places it on the
+ * screen.
+ */
+
+static void
+OneCharacter(c, insert)
+int c; /* character (Ebcdic) to be shoved in */
+int insert; /* are we in insert mode? */
+{
+ register int i, j;
+
+ if (IsProtected(CursorAddress)) {
+ RingBell("Protected Field");
+ return;
+ }
+ if (insert) {
+ /* is the last character in the field a blank or null? */
+ i = ScreenDec(FieldInc(CursorAddress));
+ j = GetHost(i);
+ if (!Disspace(j)) {
+ RingBell("No more room for insert");
+ return;
+ } else {
+ for (j = ScreenDec(i); i != CursorAddress;
+ j = ScreenDec(j), i = ScreenDec(i)) {
+ AddHost(i, (char)GetHost(j));
+ }
+ }
+ }
+ AddHost(CursorAddress, c);
+ TurnOnMdt(CursorAddress);
+ CursorAddress = ScreenInc(CursorAddress);
+ if (IsStartField(CursorAddress) &&
+ ((FieldAttributes(CursorAddress)&ATTR_AUTO_SKIP_MASK) ==
+ ATTR_AUTO_SKIP_VALUE)) {
+ Tab();
+ }
+}
+
+/*
+ * AcceptKeystroke()
+ *
+ * Processes one keystroke.
+ *
+ * Returns:
+ *
+ * 0 if this keystroke was NOT processed.
+ * 1 if everything went OK.
+ */
+
+int
+AcceptKeystroke(scancode, shiftstate)
+unsigned int
+ scancode, /* 3270 scancode */
+ shiftstate; /* The shift state */
+{
+ register int c;
+ register int i;
+ register int j;
+ enum ctlrfcn ctlrfcn;
+
+ if (scancode >= numberof(hits)) {
+ ExitString(
+ "Unknown scancode encountered in AcceptKeystroke.\n", 1);
+ /*NOTREACHED*/
+ }
+ ctlrfcn = hits[scancode].hit[HITNUM(shiftstate)].ctlrfcn;
+ c = hits[scancode].hit[HITNUM(shiftstate)].code;
+
+ if (!UnLocked || HadAid) {
+ if (HadAid) {
+ SendToIBM();
+ if (!EmptyChar()) {
+ return 0; /* nothing to do */
+ }
+ }
+#if !defined(PURE3274)
+ if (!HadAid && EmptyChar()) {
+ if ((ctlrfcn == FCN_RESET) || (ctlrfcn == FCN_MASTER_RESET)) {
+ UnLocked = 1;
+ }
+ }
+#endif /* !defined(PURE3274) */
+ if (!UnLocked) {
+ return 0;
+ }
+ }
+
+ /* now, either empty, or haven't seen aid yet */
+
+#if !defined(PURE3274)
+ /*
+ * If we are in transparent (output) mode, do something special
+ * with keystrokes.
+ */
+ if (TransparentClock == OutputClock) {
+ if (ctlrfcn == FCN_AID) {
+ UnLocked = 0;
+ InsertMode = 0;
+ AidByte = (c);
+ HadAid = 1;
+ } else {
+ switch (ctlrfcn) {
+ case FCN_ESCAPE:
+ StopScreen(1);
+ command(0, NULL, 0);
+ if (shell_active == 0) {
+ ConnectScreen();
+ }
+ break;
+
+ case FCN_RESET:
+ case FCN_MASTER_RESET:
+ UnLocked = 1;
+ break;
+
+ default:
+ return 0;
+ }
+ }
+ }
+#endif /* !defined(PURE3274) */
+
+ if (ctlrfcn == FCN_CHARACTER) {
+ /* Add the character to the buffer */
+ OneCharacter(c, InsertMode);
+ } else if (ctlrfcn == FCN_AID) { /* got Aid */
+ if (c == AID_CLEAR) {
+ LocalClearScreen(); /* Side effect is to clear 3270 */
+ }
+ ResetOiaOnlineA(&OperatorInformationArea);
+ SetOiaTWait(&OperatorInformationArea);
+ ResetOiaInsert(&OperatorInformationArea);
+ InsertMode = 0; /* just like a 3278 */
+ SetOiaSystemLocked(&OperatorInformationArea);
+ SetOiaModified();
+ UnLocked = 0;
+ AidByte = c;
+ HadAid = 1;
+ SendToIBM();
+ } else {
+ switch (ctlrfcn) {
+
+ case FCN_CURSEL:
+ c = FieldAttributes(CursorAddress)&ATTR_DSPD_MASK;
+ if (!FormattedScreen()
+ || ((c != ATTR_DSPD_DSPD) && (c != ATTR_DSPD_HIGH))) {
+ RingBell("Cursor not in selectable field");
+ } else {
+ i = ScreenInc(WhereAttrByte(CursorAddress));
+ c = GetHost(i);
+ if (c == DISP_QUESTION) {
+ AddHost(i, DISP_GREATER_THAN);
+ TurnOnMdt(i);
+ } else if (c == DISP_GREATER_THAN) {
+ AddHost(i, DISP_QUESTION);
+ TurnOffMdt(i);
+ } else if (c == DISP_BLANK || c == DISP_NULL
+ || c == DISP_AMPERSAND) {
+ UnLocked = 0;
+ InsertMode = 0;
+ ResetOiaOnlineA(&OperatorInformationArea);
+ SetOiaTWait(&OperatorInformationArea);
+ SetOiaSystemLocked(&OperatorInformationArea);
+ ResetOiaInsert(&OperatorInformationArea);
+ SetOiaModified();
+ if (c == DISP_AMPERSAND) {
+ TurnOnMdt(i); /* Only for & type */
+ AidByte = AID_ENTER;
+ } else {
+ AidByte = AID_SELPEN;
+ }
+ HadAid = 1;
+ SendToIBM();
+ } else {
+ RingBell(
+ "Cursor not in a selectable field (designator)");
+ }
+ }
+ break;
+
+#if !defined(PURE3274)
+ case FCN_ERASE:
+ if (IsProtected(ScreenDec(CursorAddress))) {
+ RingBell("Protected Field");
+ } else {
+ CursorAddress = ScreenDec(CursorAddress);
+ Delete(CursorAddress, ScreenInc(CursorAddress));
+ }
+ break;
+ case FCN_WERASE:
+ j = CursorAddress;
+ i = ScreenDec(j);
+ if (IsProtected(i)) {
+ RingBell("Protected Field");
+ } else {
+ SetXIsProtected();
+ while ((!XIsProtected(i) && Disspace(GetHost(i)))
+ && (i != j)) {
+ i = ScreenDec(i);
+ }
+ /* we are pointing at a character in a word, or
+ * at a protected position
+ */
+ while ((!XIsProtected(i) && !Disspace(GetHost(i)))
+ && (i != j)) {
+ i = ScreenDec(i);
+ }
+ /* we are pointing at a space, or at a protected
+ * position
+ */
+ CursorAddress = ScreenInc(i);
+ Delete(CursorAddress, j);
+ }
+ break;
+
+ case FCN_FERASE:
+ if (IsProtected(CursorAddress)) {
+ RingBell("Protected Field");
+ } else {
+ CursorAddress = ScreenInc(CursorAddress); /* for btab */
+ BackTab();
+ EraseEndOfField();
+ }
+ break;
+
+ case FCN_RESET:
+ if (InsertMode) {
+ InsertMode = 0;
+ ResetOiaInsert(&OperatorInformationArea);
+ SetOiaModified();
+ }
+ break;
+ case FCN_MASTER_RESET:
+ if (InsertMode) {
+ InsertMode = 0;
+ ResetOiaInsert(&OperatorInformationArea);
+ SetOiaModified();
+ }
+ RefreshScreen();
+ break;
+#endif /* !defined(PURE3274) */
+
+ case FCN_UP:
+ CursorAddress = ScreenUp(CursorAddress);
+ break;
+
+ case FCN_LEFT:
+ CursorAddress = ScreenDec(CursorAddress);
+ break;
+
+ case FCN_RIGHT:
+ CursorAddress = ScreenInc(CursorAddress);
+ break;
+
+ case FCN_DOWN:
+ CursorAddress = ScreenDown(CursorAddress);
+ break;
+
+ case FCN_DELETE:
+ if (IsProtected(CursorAddress)) {
+ RingBell("Protected Field");
+ } else {
+ Delete(CursorAddress, ScreenInc(CursorAddress));
+ }
+ break;
+
+ case FCN_INSRT:
+ InsertMode = !InsertMode;
+ if (InsertMode) {
+ SetOiaInsert(&OperatorInformationArea);
+ } else {
+ ResetOiaInsert(&OperatorInformationArea);
+ }
+ SetOiaModified();
+ break;
+
+ case FCN_HOME:
+ Home();
+ break;
+
+ case FCN_NL:
+ /* The algorithm is to look for the first unprotected
+ * column after column 0 of the following line. Having
+ * found that unprotected column, we check whether the
+ * cursor-address-at-entry is at or to the right of the
+ * LeftMargin AND the LeftMargin column of the found line
+ * is unprotected. If this conjunction is true, then
+ * we set the found pointer to the address of the LeftMargin
+ * column in the found line.
+ * Then, we set the cursor address to the found address.
+ */
+ i = SetBufferAddress(ScreenLine(ScreenDown(CursorAddress)), 0);
+ j = ScreenInc(WhereAttrByte(CursorAddress));
+ do {
+ if (IsUnProtected(i)) {
+ break;
+ }
+ /* Again (see comment in Home()), this COULD be a problem
+ * with an unformatted screen.
+ */
+ /* If there was a field with only an attribute byte,
+ * we may be pointing to the attribute byte of the NEXT
+ * field, so just look at the next byte.
+ */
+ if (IsStartField(i)) {
+ i = ScreenInc(i);
+ } else {
+ i = ScreenInc(FieldInc(i));
+ }
+ } while (i != j);
+ if (!IsUnProtected(i)) { /* couldn't find unprotected */
+ i = SetBufferAddress(0,0);
+ }
+ if (OptLeftMargin <= ScreenLineOffset(CursorAddress)) {
+ if (IsUnProtected(SetBufferAddress(ScreenLine(i),
+ OptLeftMargin))) {
+ i = SetBufferAddress(ScreenLine(i), OptLeftMargin);
+ }
+ }
+ CursorAddress = i;
+ break;
+
+ case FCN_EINP:
+ if (!FormattedScreen()) {
+ i = CursorAddress;
+ TurnOffMdt(i);
+ do {
+ AddHost(i, 0);
+ i = ScreenInc(i);
+ } while (i != CursorAddress);
+ } else {
+ /*
+ * The algorithm is: go through each unprotected
+ * field on the screen, clearing it out. When
+ * we are at the start of a field, skip that field
+ * if its contents are protected.
+ */
+ i = j = FieldInc(CursorAddress);
+ do {
+ if (IsUnProtected(ScreenInc(i))) {
+ i = ScreenInc(i);
+ TurnOffMdt(i);
+ do {
+ AddHost(i, 0);
+ i = ScreenInc(i);
+ } while (!IsStartField(i));
+ } else {
+ i = FieldInc(i);
+ }
+ } while (i != j);
+ }
+ Home();
+ break;
+
+ case FCN_EEOF:
+ EraseEndOfField();
+ break;
+
+ case FCN_SPACE:
+ OneCharacter(DISP_BLANK, InsertMode); /* Add cent */
+ break;
+
+ case FCN_CENTSIGN:
+ OneCharacter(DISP_CENTSIGN, InsertMode); /* Add cent */
+ break;
+
+ case FCN_FM:
+ OneCharacter(DISP_FM, InsertMode); /* Add field mark */
+ break;
+
+ case FCN_DP:
+ if (IsProtected(CursorAddress)) {
+ RingBell("Protected Field");
+ } else {
+ OneCharacter(DISP_DUP, InsertMode);/* Add dup character */
+ Tab();
+ }
+ break;
+
+ case FCN_TAB:
+ Tab();
+ break;
+
+ case FCN_BTAB:
+ BackTab();
+ break;
+
+#ifdef NOTUSED /* Actually, this is superseded by unix flow
+ * control.
+ */
+ case FCN_XOFF:
+ Flow = 0; /* stop output */
+ break;
+
+ case FCN_XON:
+ if (!Flow) {
+ Flow = 1; /* turn it back on */
+ DoTerminalOutput();
+ }
+ break;
+#endif /* NOTUSED */
+
+#if !defined(PURE3274)
+ case FCN_ESCAPE:
+ /* FlushChar(); do we want to flush characters from before? */
+ StopScreen(1);
+ command(0, NULL, 0);
+ if (shell_active == 0) {
+ ConnectScreen();
+ }
+ break;
+
+ case FCN_DISC:
+ StopScreen(1);
+ suspend();
+ setconnmode();
+ ConnectScreen();
+ break;
+
+ case FCN_RESHOW:
+ RefreshScreen();
+ break;
+
+ case FCN_SETTAB:
+ OptColTabs[ScreenLineOffset(CursorAddress)] = 1;
+ break;
+
+ case FCN_DELTAB:
+ OptColTabs[ScreenLineOffset(CursorAddress)] = 0;
+ break;
+
+ /*
+ * Clear all tabs, home line, and left margin.
+ */
+ case FCN_CLRTAB:
+ for (i = 0; i < sizeof OptColTabs; i++) {
+ OptColTabs[i] = 0;
+ }
+ OptHome = 0;
+ OptLeftMargin = 0;
+ break;
+
+ case FCN_COLTAB:
+ ColTab();
+ break;
+
+ case FCN_COLBAK:
+ ColBak();
+ break;
+
+ case FCN_INDENT:
+ ColTab();
+ OptLeftMargin = ScreenLineOffset(CursorAddress);
+ break;
+
+ case FCN_UNDENT:
+ ColBak();
+ OptLeftMargin = ScreenLineOffset(CursorAddress);
+ break;
+
+ case FCN_SETMRG:
+ OptLeftMargin = ScreenLineOffset(CursorAddress);
+ break;
+
+ case FCN_SETHOM:
+ OptHome = ScreenLine(CursorAddress);
+ break;
+
+ /*
+ * Point to first character of next unprotected word on
+ * screen.
+ */
+ case FCN_WORDTAB:
+ i = CursorAddress;
+ SetXIsProtected();
+ while (!XIsProtected(i) && !Disspace(GetHost(i))) {
+ i = ScreenInc(i);
+ if (i == CursorAddress) {
+ break;
+ }
+ }
+ /* i is either protected, a space (blank or null),
+ * or wrapped
+ */
+ while (XIsProtected(i) || Disspace(GetHost(i))) {
+ i = ScreenInc(i);
+ if (i == CursorAddress) {
+ break;
+ }
+ }
+ CursorAddress = i;
+ break;
+
+ case FCN_WORDBACKTAB:
+ i = ScreenDec(CursorAddress);
+ SetXIsProtected();
+ while (XIsProtected(i) || Disspace(GetHost(i))) {
+ i = ScreenDec(i);
+ if (i == CursorAddress) {
+ break;
+ }
+ }
+ /* i is pointing to a character IN an unprotected word
+ * (or i wrapped)
+ */
+ while (!Disspace(GetHost(i))) {
+ i = ScreenDec(i);
+ if (i == CursorAddress) {
+ break;
+ }
+ }
+ CursorAddress = ScreenInc(i);
+ break;
+
+ /* Point to last non-blank character of this/next
+ * unprotected word.
+ */
+ case FCN_WORDEND:
+ i = ScreenInc(CursorAddress);
+ SetXIsProtected();
+ while (XIsProtected(i) || Disspace(GetHost(i))) {
+ i = ScreenInc(i);
+ if (i == CursorAddress) {
+ break;
+ }
+ }
+ /* we are pointing at a character IN an
+ * unprotected word (or we wrapped)
+ */
+ while (!Disspace(GetHost(i))) {
+ i = ScreenInc(i);
+ if (i == CursorAddress) {
+ break;
+ }
+ }
+ CursorAddress = ScreenDec(i);
+ break;
+
+ /* Get to last non-blank of this/next unprotected
+ * field.
+ */
+ case FCN_FIELDEND:
+ i = LastOfField(CursorAddress);
+ if (i != CursorAddress) {
+ CursorAddress = i; /* We moved; take this */
+ } else {
+ j = FieldInc(CursorAddress); /* Move to next field */
+ i = LastOfField(j);
+ if (i != j) {
+ CursorAddress = i; /* We moved; take this */
+ }
+ /* else - nowhere else on screen to be; stay here */
+ }
+ break;
+#endif /* !defined(PURE3274) */
+
+ default:
+ /* We don't handle this yet */
+ RingBell("Function not implemented");
+ }
+ }
+ return 1; /* We did something! */
+}
+
+
+/*
+ * We get data from the terminal. We keep track of the shift state
+ * (including ALT, CONTROL), and then call AcceptKeystroke to actually
+ * process any non-shift keys.
+ */
+
+int
+DataFrom3270(buffer, count)
+unsigned char *buffer; /* where the data is */
+int count; /* how much data there is */
+{
+ int origCount;
+
+ origCount = count;
+
+ while (count) {
+ if (*buffer >= numberof(hits)) {
+ ExitString("Unknown scancode encountered in DataFrom3270.\n", 1);
+ /*NOTREACHED*/
+ }
+
+ switch (hits[*buffer].hit[HITNUM(rememberedshiftstate)].ctlrfcn) {
+
+ case FCN_MAKE_SHIFT:
+ rememberedshiftstate |= (SHIFT_RIGHT|SHIFT_UPSHIFT);
+ break;
+ case FCN_BREAK_SHIFT:
+ rememberedshiftstate &= ~(SHIFT_RIGHT|SHIFT_UPSHIFT);
+ break;
+ case FCN_MAKE_ALT:
+ rememberedshiftstate |= SHIFT_ALT;
+ break;
+ case FCN_BREAK_ALT:
+ rememberedshiftstate &= ~SHIFT_ALT;
+ break;
+ default:
+ if (AcceptKeystroke(*buffer, rememberedshiftstate) == 0) {
+ return(origCount-count);
+ }
+ break;
+ }
+ buffer++;
+ count--;
+ }
+ return(origCount-count);
+}