1 /* $NetBSD: inbound.c,v 1.6 2002/06/13 23:41:19 wiz Exp $ */
4 * Copyright (c) 1988 The Regents of the University of California.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 #include <sys/cdefs.h>
35 static char sccsid
[] = "@(#)inbound.c 4.3 (Berkeley) 4/26/91";
37 __RCSID("$NetBSD: inbound.c,v 1.6 2002/06/13 23:41:19 wiz Exp $");
43 #include "../general/general.h"
50 #include "../api/dctype.h"
51 #include "../api/ebc_disp.h"
53 #include "../general/globals.h"
54 #include "../sys_curses/telextrn.h"
58 #define EmptyChar() (ourPTail == ourPHead)
59 #define FullChar() (ourPHead == ourBuffer+sizeof ourBuffer)
63 * We define something to allow us to to IsProtected() quickly
64 * on unformatted screens (with the current algorithm for fields,
65 * unprotected takes exponential time...).
67 * The idea is to call SetXIsProtected() BEFORE the
68 * loop, then use XIsProtected().
71 #define SetXIsProtected() (XWasSF = 1)
72 #define XIsProtected(p) (IsStartField(p) ? \
75 (XWasSF = 0, XProtected = IsProtected(p)) : \
78 static char ourBuffer
[400];
80 static char *ourPHead
= ourBuffer
,
81 *ourPTail
= ourBuffer
;
83 static int HadAid
; /* Had an AID haven't sent */
85 static int InsertMode
; /* is the terminal in insert mode? */
88 rememberedshiftstate
; /* Shift (alt) state of terminal */
90 # define HITNUM(s) ((((s)&(SHIFT_CAPS|SHIFT_UPSHIFT))? 1:0) \
91 + ((((s)&SHIFT_ALT)? 1:0)<<1))
93 static int XWasSF
, XProtected
; /* For optimizations */
94 #if !defined(PURE3274)
95 extern int TransparentClock
, OutputClock
;
96 #endif /* !defined(PURE3274) */
98 #include "kbd.out" /* Get keyboard mapping function */
100 /* the following are global variables */
102 extern int UnLocked
; /* keyboard is UnLocked? */
105 static void Tab(void);
106 static void BackTab(void);
107 static void EraseEndOfField(void);
108 static void Delete(int, int );
109 static void ColBak(void);
110 static void ColTab(void);
111 static void Home(void);
112 static int LastOfField(int);
113 static void FlushChar(void);
114 static void AddChar(int);
115 static void SendUnformatted(void);
116 static int SendField(int, int);
117 static void OneCharacter(int, int);
122 * Reset variables to initial state.
128 ourPHead
= ourPTail
= ourBuffer
;
130 rememberedshiftstate
= 0;
135 /* Tab() - sets cursor to the start of the next unprotected field */
142 j
= WhereAttrByte(CursorAddress
);
144 if (IsStartField(i
) && IsUnProtected(ScreenInc(i
))) {
149 if (IsStartField(i
) && IsUnProtected(ScreenInc(i
))) {
150 CursorAddress
= ScreenInc(i
);
152 CursorAddress
= SetBufferAddress(0,0);
157 /* BackTab() - sets cursor to the start of the most recent field */
164 i
= ScreenDec(CursorAddress
);
166 if (IsStartField(ScreenDec(i
)) && IsUnProtected(i
)) {
170 if (i
== CursorAddress
) {
171 CursorAddress
= SetBufferAddress(0,0);
179 * ModifyMdt() - Turn a modified data tag bit on or off (watch
180 * out for unformatted screens).
190 if (IsStartField(i
)) { /* If we are at a start field position... */
192 ModifyHost(i
, |= ATTR_MDT
); /* Turn it on */
194 ModifyHost(i
, &= ~ATTR_MDT
); /* Turn it off */
197 i
= WhereAttrByte(i
); /* Find beginning of field */
198 if (IsStartField(i
)) { /* Is there one? */
200 ModifyHost(i
, |= ATTR_MDT
); /* Turn it on */
202 ModifyHost(i
, &= ~ATTR_MDT
); /* Turn it off */
204 } /* else, don't modify - this is an unformatted screen */
209 /* EraseEndOfField - erase all characters to the end of a field */
216 if (IsProtected(CursorAddress
)) {
217 RingBell("Protected Field");
219 TurnOnMdt(CursorAddress
);
220 if (FormattedScreen()) {
225 } while ((i
!= CursorAddress
) && !IsStartField(i
));
226 } else { /* Screen is Unformatted */
231 } while (i
!= HighestScreen());
236 /* Delete() - deletes a character from the screen
238 * What we want to do is delete the section
239 * [where, from-1] from the screen,
240 * filling in with what comes at from.
242 * The deleting continues to the end of the field (or
243 * until the cursor wraps).
245 * From can be a start of a field. We
246 * check for that. However, there can't be any
247 * fields that start between where and from.
248 * We don't check for that.
250 * Also, we assume that the protection status of
251 * everything has been checked by the caller.
257 int where
, /* Where to start deleting from */
258 from
; /* Where to pull back from */
262 TurnOnMdt(where
); /* Only do this once in this field */
265 if (IsStartField(from
)) {
266 AddHost(i
, 0); /* Stick the edge at the start field */
268 AddHost(i
, (char)GetHost(from
));
269 from
= ScreenInc(from
); /* Move the edge */
272 } while ((!IsStartField(i
)) && (i
!= where
));
280 i
= ScreenLineOffset(CursorAddress
);
281 for (i
= i
-1; i
>= 0; i
--) {
289 CursorAddress
= SetBufferAddress(ScreenLine(CursorAddress
), i
);
297 i
= ScreenLineOffset(CursorAddress
);
298 for (i
= i
+1; i
< NumberColumns
; i
++) {
303 if (i
>= NumberColumns
) {
306 CursorAddress
= SetBufferAddress(ScreenLine(CursorAddress
), i
);
315 i
= SetBufferAddress(OptHome
, 0);
318 * If the initial value of i points to the field attribute of
319 * an unprotected field, we need to return the address of the
320 * first data byte in the field (assuming there are any!).
322 if (IsStartField(i
) && IsUnProtected(j
)) {
327 if (IsUnProtected(i
)) {
331 /* the following could be a problem if we got here with an
332 * unformatted screen. However, this is "impossible", since
333 * with an unformatted screen, the IsUnProtected(i) above
336 i
= ScreenInc(FieldInc(i
));
338 CursorAddress
= LowestScreen();
343 int i
; /* position to start from */
350 while (XIsProtected(i
) || Disspace(GetHost(i
))) {
356 /* We are now IN a word IN an unprotected field (or wrapped) */
357 while (!XIsProtected(i
)) {
358 if (!Disspace(GetHost(i
))) {
373 ourPTail
= ourPHead
= ourBuffer
;
378 * Add one EBCDIC (NOT display code) character to the buffer.
386 ourPTail
+= DataToNetwork(ourPTail
, ourPHead
-ourPTail
, 0);
392 sprintf(buffer
, "File %s, line %d: No room in network buffer!\n",
394 ExitString(buffer
, 1);
398 *ourPHead
++ = character
;
409 /* look for start of field */
411 i
= j
= LowestScreen();
419 AddChar(EBCDIC_BLANK
); /* put in blanks */
421 AddChar((char)disp_ebc
[c
]);
429 int i
; /* where we saw MDT bit */
430 int cmd
; /* The command code (type of read) */
437 /* look for start of field */
438 i
= j
= WhereLowByte(i
);
440 /* On a test_request_read, don't send sba and address */
441 if ((AidByte
!= AID_TREQ
)
442 || (cmd
== CMD_SNA_READ_MODIFIED_ALL
)) {
443 AddChar(ORDER_SBA
); /* set start field */
444 AddChar(BufferTo3270_0(j
)); /* set address of this field */
445 AddChar(BufferTo3270_1(j
));
448 * Only on read_modified_all do we return the contents
449 * of the field when the attention was caused by a
452 if ((AidByte
!= AID_SELPEN
)
453 || (cmd
== CMD_SNA_READ_MODIFIED_ALL
)) {
454 if (!IsStartField(j
)) {
456 k
= ScreenInc(WhereHighByte(j
));
464 AddChar(EBCDIC_BLANK
); /* put in blanks */
466 AddChar((char)disp_ebc
[c
]);
469 } while ((j
!= k
) && (j
!= i
));
477 /* Various types of reads... */
480 int cmd
; /* The command sent */
485 if (AidByte
!= AID_TREQ
) {
488 /* Test Request Read header */
490 AddChar(EBCDIC_PERCENT
);
491 AddChar(EBCDIC_SLASH
);
497 if (((AidByte
!= AID_PA1
) && (AidByte
!= AID_PA2
)
498 && (AidByte
!= AID_PA3
) && (AidByte
!= AID_CLEAR
))
499 || (cmd
== CMD_SNA_READ_MODIFIED_ALL
)) {
500 if ((AidByte
!= AID_TREQ
)
501 || (cmd
== CMD_SNA_READ_MODIFIED_ALL
)) {
502 /* Test request read_modified doesn't give cursor address */
503 AddChar(BufferTo3270_0(CursorAddress
));
504 AddChar(BufferTo3270_1(CursorAddress
));
506 i
= j
= WhereAttrByte(LowestScreen());
507 /* Is this an unformatted screen? */
508 if (!IsStartField(i
)) { /* yes, handle separate */
513 i
= SendField(i
, cmd
);
520 ourPTail
+= DataToNetwork(ourPTail
, ourPHead
-ourPTail
, 1);
523 HadAid
= 0; /* killed that buffer */
527 /* A read buffer operation... */
539 AddChar(BufferTo3270_0(CursorAddress
));
540 AddChar(BufferTo3270_1(CursorAddress
));
541 i
= j
= LowestScreen();
543 if (IsStartField(i
)) {
545 AddChar(BufferTo3270_1(FieldAttributes(i
)));
547 AddChar((char)disp_ebc
[GetHost(i
)]);
551 ourPTail
+= DataToNetwork(ourPTail
, ourPHead
-ourPTail
, 1);
554 HadAid
= 0; /* killed that buffer */
558 /* Send some transparent data to the host */
561 SendTransparent(buffer
, count
)
567 stuff
[0] = AID_NONE_PRINTER
;
568 stuff
[1] = BufferTo3270_0(count
);
569 stuff
[2] = BufferTo3270_1(count
);
570 DataToNetwork(stuff
, sizeof stuff
, 0);
571 DataToNetwork(buffer
, count
, 1);
575 /* Try to send some data to host */
580 #if !defined(PURE3274)
581 if (TransparentClock
>= OutputClock
) {
586 AddChar(AID_NONE_PRINTER
);
589 ourPTail
+= DataToNetwork(ourPTail
, ourPHead
-ourPTail
, 1);
590 } while (!EmptyChar());
593 DoReadModified(CMD_READ_MODIFIED
);
595 #else /* !defined(PURE3274) */
597 DoReadModified(CMD_READ_MODIFIED
);
599 #endif /* !defined(PURE3274) */
602 /* This takes in one character from the keyboard and places it on the
607 OneCharacter(c
, insert
)
608 int c
; /* character (Ebcdic) to be shoved in */
609 int insert
; /* are we in insert mode? */
613 if (IsProtected(CursorAddress
)) {
614 RingBell("Protected Field");
618 /* is the last character in the field a blank or null? */
619 i
= ScreenDec(FieldInc(CursorAddress
));
622 RingBell("No more room for insert");
625 for (j
= ScreenDec(i
); i
!= CursorAddress
;
626 j
= ScreenDec(j
), i
= ScreenDec(i
)) {
627 AddHost(i
, (char)GetHost(j
));
631 AddHost(CursorAddress
, c
);
632 TurnOnMdt(CursorAddress
);
633 CursorAddress
= ScreenInc(CursorAddress
);
634 if (IsStartField(CursorAddress
) &&
635 ((FieldAttributes(CursorAddress
)&ATTR_AUTO_SKIP_MASK
) ==
636 ATTR_AUTO_SKIP_VALUE
)) {
644 * Processes one keystroke.
648 * 0 if this keystroke was NOT processed.
649 * 1 if everything went OK.
653 AcceptKeystroke(scancode
, shiftstate
)
655 scancode
, /* 3270 scancode */
656 shiftstate
; /* The shift state */
661 enum ctlrfcn ctlrfcn
;
663 if (scancode
>= numberof(hits
)) {
665 "Unknown scancode encountered in AcceptKeystroke.\n", 1);
668 ctlrfcn
= hits
[scancode
].hit
[HITNUM(shiftstate
)].ctlrfcn
;
669 c
= hits
[scancode
].hit
[HITNUM(shiftstate
)].code
;
671 if (!UnLocked
|| HadAid
) {
675 return 0; /* nothing to do */
678 #if !defined(PURE3274)
679 if (!HadAid
&& EmptyChar()) {
680 if ((ctlrfcn
== FCN_RESET
) || (ctlrfcn
== FCN_MASTER_RESET
)) {
684 #endif /* !defined(PURE3274) */
690 /* now, either empty, or haven't seen aid yet */
692 #if !defined(PURE3274)
694 * If we are in transparent (output) mode, do something special
697 if (TransparentClock
== OutputClock
) {
698 if (ctlrfcn
== FCN_AID
) {
708 if (shell_active
== 0) {
714 case FCN_MASTER_RESET
:
723 #endif /* !defined(PURE3274) */
725 if (ctlrfcn
== FCN_CHARACTER
) {
726 /* Add the character to the buffer */
727 OneCharacter(c
, InsertMode
);
728 } else if (ctlrfcn
== FCN_AID
) { /* got Aid */
729 if (c
== AID_CLEAR
) {
730 LocalClearScreen(); /* Side effect is to clear 3270 */
732 ResetOiaOnlineA(&OperatorInformationArea
);
733 SetOiaTWait(&OperatorInformationArea
);
734 ResetOiaInsert(&OperatorInformationArea
);
735 InsertMode
= 0; /* just like a 3278 */
736 SetOiaSystemLocked(&OperatorInformationArea
);
746 c
= FieldAttributes(CursorAddress
)&ATTR_DSPD_MASK
;
747 if (!FormattedScreen()
748 || ((c
!= ATTR_DSPD_DSPD
) && (c
!= ATTR_DSPD_HIGH
))) {
749 RingBell("Cursor not in selectable field");
751 i
= ScreenInc(WhereAttrByte(CursorAddress
));
753 if (c
== DISP_QUESTION
) {
754 AddHost(i
, DISP_GREATER_THAN
);
756 } else if (c
== DISP_GREATER_THAN
) {
757 AddHost(i
, DISP_QUESTION
);
759 } else if (c
== DISP_BLANK
|| c
== DISP_NULL
760 || c
== DISP_AMPERSAND
) {
763 ResetOiaOnlineA(&OperatorInformationArea
);
764 SetOiaTWait(&OperatorInformationArea
);
765 SetOiaSystemLocked(&OperatorInformationArea
);
766 ResetOiaInsert(&OperatorInformationArea
);
768 if (c
== DISP_AMPERSAND
) {
769 TurnOnMdt(i
); /* Only for & type */
772 AidByte
= AID_SELPEN
;
778 "Cursor not in a selectable field (designator)");
783 #if !defined(PURE3274)
785 if (IsProtected(ScreenDec(CursorAddress
))) {
786 RingBell("Protected Field");
788 CursorAddress
= ScreenDec(CursorAddress
);
789 Delete(CursorAddress
, ScreenInc(CursorAddress
));
795 if (IsProtected(i
)) {
796 RingBell("Protected Field");
799 while ((!XIsProtected(i
) && Disspace(GetHost(i
)))
803 /* we are pointing at a character in a word, or
804 * at a protected position
806 while ((!XIsProtected(i
) && !Disspace(GetHost(i
)))
810 /* we are pointing at a space, or at a protected
813 CursorAddress
= ScreenInc(i
);
814 Delete(CursorAddress
, j
);
819 if (IsProtected(CursorAddress
)) {
820 RingBell("Protected Field");
822 CursorAddress
= ScreenInc(CursorAddress
); /* for btab */
831 ResetOiaInsert(&OperatorInformationArea
);
835 case FCN_MASTER_RESET
:
838 ResetOiaInsert(&OperatorInformationArea
);
843 #endif /* !defined(PURE3274) */
846 CursorAddress
= ScreenUp(CursorAddress
);
850 CursorAddress
= ScreenDec(CursorAddress
);
854 CursorAddress
= ScreenInc(CursorAddress
);
858 CursorAddress
= ScreenDown(CursorAddress
);
862 if (IsProtected(CursorAddress
)) {
863 RingBell("Protected Field");
865 Delete(CursorAddress
, ScreenInc(CursorAddress
));
870 InsertMode
= !InsertMode
;
872 SetOiaInsert(&OperatorInformationArea
);
874 ResetOiaInsert(&OperatorInformationArea
);
884 /* The algorithm is to look for the first unprotected
885 * column after column 0 of the following line. Having
886 * found that unprotected column, we check whether the
887 * cursor-address-at-entry is at or to the right of the
888 * LeftMargin AND the LeftMargin column of the found line
889 * is unprotected. If this conjunction is true, then
890 * we set the found pointer to the address of the LeftMargin
891 * column in the found line.
892 * Then, we set the cursor address to the found address.
894 i
= SetBufferAddress(ScreenLine(ScreenDown(CursorAddress
)), 0);
895 j
= ScreenInc(WhereAttrByte(CursorAddress
));
897 if (IsUnProtected(i
)) {
900 /* Again (see comment in Home()), this COULD be a problem
901 * with an unformatted screen.
903 /* If there was a field with only an attribute byte,
904 * we may be pointing to the attribute byte of the NEXT
905 * field, so just look at the next byte.
907 if (IsStartField(i
)) {
910 i
= ScreenInc(FieldInc(i
));
913 if (!IsUnProtected(i
)) { /* couldn't find unprotected */
914 i
= SetBufferAddress(0,0);
916 if (OptLeftMargin
<= ScreenLineOffset(CursorAddress
)) {
917 if (IsUnProtected(SetBufferAddress(ScreenLine(i
),
919 i
= SetBufferAddress(ScreenLine(i
), OptLeftMargin
);
926 if (!FormattedScreen()) {
932 } while (i
!= CursorAddress
);
935 * The algorithm is: go through each unprotected
936 * field on the screen, clearing it out. When
937 * we are at the start of a field, skip that field
938 * if its contents are protected.
940 i
= j
= FieldInc(CursorAddress
);
942 if (IsUnProtected(ScreenInc(i
))) {
948 } while (!IsStartField(i
));
962 OneCharacter(DISP_BLANK
, InsertMode
); /* Add cent */
966 OneCharacter(DISP_CENTSIGN
, InsertMode
); /* Add cent */
970 OneCharacter(DISP_FM
, InsertMode
); /* Add field mark */
974 if (IsProtected(CursorAddress
)) {
975 RingBell("Protected Field");
977 OneCharacter(DISP_DUP
, InsertMode
);/* Add dup character */
990 #ifdef NOTUSED /* Actually, this is superseded by unix flow
994 Flow
= 0; /* stop output */
999 Flow
= 1; /* turn it back on */
1003 #endif /* NOTUSED */
1005 #if !defined(PURE3274)
1007 /* FlushChar(); do we want to flush characters from before? */
1009 command(0, NULL
, 0);
1010 if (shell_active
== 0) {
1027 OptColTabs
[ScreenLineOffset(CursorAddress
)] = 1;
1031 OptColTabs
[ScreenLineOffset(CursorAddress
)] = 0;
1035 * Clear all tabs, home line, and left margin.
1038 for (i
= 0; i
< sizeof OptColTabs
; i
++) {
1055 OptLeftMargin
= ScreenLineOffset(CursorAddress
);
1060 OptLeftMargin
= ScreenLineOffset(CursorAddress
);
1064 OptLeftMargin
= ScreenLineOffset(CursorAddress
);
1068 OptHome
= ScreenLine(CursorAddress
);
1072 * Point to first character of next unprotected word on
1078 while (!XIsProtected(i
) && !Disspace(GetHost(i
))) {
1080 if (i
== CursorAddress
) {
1084 /* i is either protected, a space (blank or null),
1087 while (XIsProtected(i
) || Disspace(GetHost(i
))) {
1089 if (i
== CursorAddress
) {
1096 case FCN_WORDBACKTAB
:
1097 i
= ScreenDec(CursorAddress
);
1099 while (XIsProtected(i
) || Disspace(GetHost(i
))) {
1101 if (i
== CursorAddress
) {
1105 /* i is pointing to a character IN an unprotected word
1108 while (!Disspace(GetHost(i
))) {
1110 if (i
== CursorAddress
) {
1114 CursorAddress
= ScreenInc(i
);
1117 /* Point to last non-blank character of this/next
1121 i
= ScreenInc(CursorAddress
);
1123 while (XIsProtected(i
) || Disspace(GetHost(i
))) {
1125 if (i
== CursorAddress
) {
1129 /* we are pointing at a character IN an
1130 * unprotected word (or we wrapped)
1132 while (!Disspace(GetHost(i
))) {
1134 if (i
== CursorAddress
) {
1138 CursorAddress
= ScreenDec(i
);
1141 /* Get to last non-blank of this/next unprotected
1145 i
= LastOfField(CursorAddress
);
1146 if (i
!= CursorAddress
) {
1147 CursorAddress
= i
; /* We moved; take this */
1149 j
= FieldInc(CursorAddress
); /* Move to next field */
1152 CursorAddress
= i
; /* We moved; take this */
1154 /* else - nowhere else on screen to be; stay here */
1157 #endif /* !defined(PURE3274) */
1160 /* We don't handle this yet */
1161 RingBell("Function not implemented");
1164 return 1; /* We did something! */
1169 * We get data from the terminal. We keep track of the shift state
1170 * (including ALT, CONTROL), and then call AcceptKeystroke to actually
1171 * process any non-shift keys.
1175 DataFrom3270(buffer
, count
)
1176 unsigned char *buffer
; /* where the data is */
1177 int count
; /* how much data there is */
1184 if (*buffer
>= numberof(hits
)) {
1185 ExitString("Unknown scancode encountered in DataFrom3270.\n", 1);
1189 switch (hits
[*buffer
].hit
[HITNUM(rememberedshiftstate
)].ctlrfcn
) {
1191 case FCN_MAKE_SHIFT
:
1192 rememberedshiftstate
|= (SHIFT_RIGHT
|SHIFT_UPSHIFT
);
1194 case FCN_BREAK_SHIFT
:
1195 rememberedshiftstate
&= ~(SHIFT_RIGHT
|SHIFT_UPSHIFT
);
1198 rememberedshiftstate
|= SHIFT_ALT
;
1201 rememberedshiftstate
&= ~SHIFT_ALT
;
1204 if (AcceptKeystroke(*buffer
, rememberedshiftstate
) == 0) {
1205 return(origCount
-count
);
1212 return(origCount
-count
);