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