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