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