source: trunk/third/x3270/ctlr.c @ 11123

Revision 11123, 42.0 KB checked in by ghudson, 27 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r11122, which included commits to RCS files with non-trunk default branches.
RevLine 
[9080]1/*
2 * Modifications Copyright 1993, 1994, 1995, 1996 by Paul Mattes.
3 * Original X11 Port Copyright 1990 by Jeff Sparkes.
4 *  Permission to use, copy, modify, and distribute this software and its
5 *  documentation for any purpose and without fee is hereby granted,
6 *  provided that the above copyright notice appear in all copies and that
7 *  both that copyright notice and this permission notice appear in
8 *  supporting documentation.
9 *
10 * Copyright 1989 by Georgia Tech Research Corporation, Atlanta, GA 30332.
11 *  All Rights Reserved.  GTRC hereby grants public use of this software.
12 *  Derivative works based on this software must incorporate this copyright
13 *  notice.
14 */
15
16/*
17 *      ctlr.c
18 *              This module handles interpretation of the 3270 data stream and
19 *              maintenance of the 3270 device state.  It was split out from
20 *              screen.c, which handles X operations.
21 *
22 */
23
24#include "globals.h"
25#include <errno.h>
26#include "3270ds.h"
27#include "appres.h"
28#include "ctlr.h"
29#include "screen.h"
30#include "cg.h"
31#include "resources.h"
32
33#include "ctlrc.h"
34#include "ft_cutc.h"
35#include "ftc.h"
36#include "kybdc.h"
37#include "macrosc.h"
38#include "popupsc.h"
39#include "screenc.h"
40#include "scrollc.h"
41#include "selectc.h"
42#include "sfc.h"
43#include "statusc.h"
44#include "tablesc.h"
45#include "telnetc.h"
46#include "trace_dsc.h"
47#include "utilc.h"
48
49/* Externals: kybd.c */
50extern unsigned char aid;
51
52/* Globals */
53int             ROWS, COLS;
54int             maxROWS, maxCOLS;
55int             cursor_addr, buffer_addr;
56Boolean         screen_alt = True;      /* alternate screen? */
57Boolean         is_altbuffer = False;
58unsigned char  *screen_buf;     /* 3270 display buffer */
59struct ea      *ea_buf;         /* 3270 extended attribute buffer */
60Boolean         formatted = False;      /* set in screen_disp */
61Boolean         screen_changed = False;
62int             first_changed = -1;
63int             last_changed = -1;
64unsigned char   reply_mode = SF_SRM_FIELD;
65int             crm_nattr = 0;
66unsigned char   crm_attr[16];
67
68/* Statics */
69static unsigned char *ascreen_buf;      /* alternate 3270 display buffer */
70static struct ea *aea_buf;      /* alternate 3270 extended attribute buffer */
71static unsigned char *zero_buf; /* empty buffer, for area clears */
72static void     set_formatted();
73static void     ctlr_blanks();
74static unsigned char fake_fa;
75static struct ea fake_ea;
76static Boolean  trace_primed = False;
77static unsigned char default_fg;
78static unsigned char default_gr;
79static unsigned char default_cs;
80
81/*
82 * code_table is used to translate buffer addresses and attributes to the 3270
83 * datastream representation
84 */
85static unsigned char    code_table[64] = {
86        0x40, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
87        0xC8, 0xC9, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
88        0x50, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7,
89        0xD8, 0xD9, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
90        0x60, 0x61, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
91        0xE8, 0xE9, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
92        0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
93        0xF8, 0xF9, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
94};
95
96#define IsBlank(c)      ((c == CG_null) || (c == CG_space))
97
98#define ALL_CHANGED     { \
99        screen_changed = True; \
100        if (IN_ANSI) { first_changed = 0; last_changed = ROWS*COLS; } }
101#define REGION_CHANGED(f, l)    { \
102        screen_changed = True; \
103        if (IN_ANSI) { \
104            if (first_changed == -1 || f < first_changed) first_changed = f; \
105            if (last_changed == -1 || l > last_changed) last_changed = l; } }
106#define ONE_CHANGED(n)  REGION_CHANGED(n, n+1)
107
108#define DECODE_BADDR(c1, c2) \
109        ((((c1) & 0xC0) == 0x00) ? \
110        (((c1) & 0x3F) << 8) | (c2) : \
111        (((c1) & 0x3F) << 6) | ((c2) & 0x3F))
112
113#define ENCODE_BADDR(ptr, addr) { \
114        if ((addr) > 0xfff) { \
115                *(ptr)++ = ((addr) >> 8) & 0x3F; \
116                *(ptr)++ = (addr) & 0xFF; \
117        } else { \
118                *(ptr)++ = code_table[((addr) >> 6) & 0x3F]; \
119                *(ptr)++ = code_table[(addr) & 0x3F]; \
120        } \
121    }
122
123/*
124 * Initialize the emulated 3270 hardware.
125 */
126void
127ctlr_init(keep_contents, model_changed)
128Boolean keep_contents;
129Boolean model_changed;
130{
131        /* Allocate buffers */
132
133        if (model_changed) {
134                if (screen_buf)
135                        XtFree((char *)screen_buf);
136                screen_buf = (unsigned char *)XtCalloc(sizeof(unsigned char),
137                    maxROWS * maxCOLS);
138                if (ea_buf)
139                        XtFree((char *)ea_buf);
140                ea_buf = (struct ea *)XtCalloc(sizeof(struct ea),
141                    maxROWS * maxCOLS);
142                if (ascreen_buf)
143                        XtFree((char *)ascreen_buf);
144                ascreen_buf = (unsigned char *)XtCalloc(sizeof(unsigned char),
145                    maxROWS * maxCOLS);
146                if (aea_buf)
147                        XtFree((char *)aea_buf);
148                aea_buf = (struct ea *)XtCalloc(sizeof(struct ea),
149                    maxROWS * maxCOLS);
150                if (zero_buf)
151                        XtFree((char *)zero_buf);
152                zero_buf = (unsigned char *)XtCalloc(sizeof(unsigned char),
153                    maxROWS * maxCOLS);
154        }
155
156        if (!keep_contents) {
157                cursor_addr = 0;
158                buffer_addr = 0;
159        }
160}
161
162/*
163 * Deal with the relationships between model numbers and rows/cols.
164 */
165void
166set_rows_cols(mn, ovc, ovr)
167int mn;
168int ovc, ovr;
169{
170        int defmod;
171
172        switch (mn) {
173        case 2:
174                maxCOLS = COLS = 80;
175                maxROWS = ROWS = 24;
176                model_num = 2;
177                break;
178        case 3:
179                maxCOLS = COLS = 80;
180                maxROWS = ROWS = 32;
181                model_num = 3;
182                break;
183        case 4:
184#if defined(RESTRICT_3279) /*[*/
185                if (appres.m3279) {
186                        XtWarning("No 3279 Model 4, defaulting to Model 3");
187                        set_rows_cols("3", ovc, ovr);
188                        return;
189                }
190#endif /*]*/
191                maxCOLS = COLS = 80;
192                maxROWS = ROWS = 43;
193                model_num = 4;
194                break;
195        case 5:
196#if defined(RESTRICT_3279) /*[*/
197                if (appres.m3279) {
198                        XtWarning("No 3279 Model 5, defaulting to Model 3");
199                        set_rows_cols(3, ovc, ovr);
200                        return;
201                }
202#endif /*]*/
203                maxCOLS = COLS = 132;
204                maxROWS = ROWS = 27;
205                model_num = 5;
206                break;
207        default:
208#if defined(RESTRICT_3279) /*[*/
209                defmod = appres.m3279 ? 3 : 4;
210#else /*][*/
211                defmod = 4;
212#endif
213                {
214                        char mnb[2];
215
216                        mnb[0] = defmod + '0';
217                        mnb[1] = '\0';
218                        xs_warning("Unknown model, defaulting to %s", mnb);
219                }
220                set_rows_cols(defmod, ovc, ovr);
221                return;
222        }
223
224        /* Apply oversize. */
225        ov_cols = 0;
226        ov_rows = 0;
[11122]227        if (ovc != 0 || ovr != 0) {
228                if (ovc <= 0 || ovr <= 0)
229                        popup_an_error("Invalid %s %dx%d:\nNegative or zero",
230                            ResOversize, ovc, ovr);
231                else if (ovc * ovr >= 0x4000)
232                        popup_an_error("Invalid %s %dx%d:\nToo big",
233                            ResOversize, ovc, ovr);
234                else if (ovc > 0 && ovc < maxCOLS)
235                        popup_an_error("Invalid %s cols (%d):\nLess than model %d cols (%d)",
236                            ResOversize, ovc, model_num, maxCOLS);
237                else if (ovr > 0 && ovr < maxROWS)
238                        popup_an_error("Invalid %s rows (%d):\nLess than model %d rows (%d)",
239                            ResOversize, ovr, model_num, maxROWS);
240                else {
241                        ov_cols = maxCOLS = COLS = ovc;
242                        ov_rows = maxROWS = ROWS = ovr;
243                }
[9080]244        }
245
246        /* Update the model name. */
247        (void) sprintf(model_name, "327%c-%d%s",
248            appres.m3279 ? '9' : '8',
249            model_num,
250            appres.extended ? "-E" : "");
251}
252
253
254/*
255 * Set the formatted screen flag.  A formatted screen is a screen that
256 * has at least one field somewhere on it.
257 */
258static void
259set_formatted()
260{
261        register int    baddr;
262
263        formatted = False;
264        baddr = 0;
265        do {
266                if (IS_FA(screen_buf[baddr])) {
267                        formatted = True;
268                        break;
269                }
270                INC_BA(baddr);
271        } while (baddr != 0);
272}
273
274/*
275 * Called when a host connects, disconnects, or changes ANSI/3270 modes.
276 */
277void
278ctlr_connect()
279{
280        if (ever_3270)
281                fake_fa = 0xE0;
282        else
283                fake_fa = 0xC4;
284
285        default_fg = 0x00;
286        default_gr = 0x00;
287        default_cs = 0x00;
288        reply_mode = SF_SRM_FIELD;
289        crm_nattr = 0;
290}
291
292
293/*
294 * Find the field attribute for the given buffer address.  Return its address
295 * rather than its value.
296 */
297unsigned char *
298get_field_attribute(baddr)
299register int    baddr;
300{
301        int     sbaddr;
302
303        if (!formatted)
304                return &fake_fa;
305
306        sbaddr = baddr;
307        do {
308                if (IS_FA(screen_buf[baddr]))
309                        return &(screen_buf[baddr]);
310                DEC_BA(baddr);
311        } while (baddr != sbaddr);
312        return &fake_fa;
313}
314
315/*
316 * Find the field attribute for the given buffer address, bounded by another
317 * buffer address.  Return the attribute in a parameter.
318 *
319 * Returns True if an attribute is found, False if boundary hit.
320 */
321Boolean
322get_bounded_field_attribute(baddr, bound, fa_out)
323register int    baddr;
324register int    bound;
325unsigned char   *fa_out;
326{
327        int     sbaddr;
328
329        if (!formatted) {
330                *fa_out = fake_fa;
331                return True;
332        }
333
334        sbaddr = baddr;
335        do {
336                if (IS_FA(screen_buf[baddr])) {
337                        *fa_out = screen_buf[baddr];
338                        return True;
339                }
340                DEC_BA(baddr);
341        } while (baddr != sbaddr && baddr != bound);
342
343        /* Screen is unformatted (and 'formatted' is inaccurate). */
344        if (baddr == sbaddr) {
345                *fa_out = fake_fa;
346                return True;
347        }
348
349        /* Wrapped to boundary. */
350        return False;
351}
352
353/*
354 * Given the address of a field attribute, return the address of the
355 * extended attribute structure.
356 */
357struct ea *
358fa2ea(fa)
359unsigned char *fa;
360{
361        if (fa == &fake_fa)
362                return &fake_ea;
363        else
364                return &ea_buf[fa - screen_buf];
365}
366
367/*
368 * Find the next unprotected field.  Returns the address following the
369 * unprotected attribute byte, or 0 if no nonzero-width unprotected field
370 * can be found.
371 */
372int
373next_unprotected(baddr0)
374int baddr0;
375{
376        register int baddr, nbaddr;
377
378        nbaddr = baddr0;
379        do {
380                baddr = nbaddr;
381                INC_BA(nbaddr);
382                if (IS_FA(screen_buf[baddr]) &&
383                    !FA_IS_PROTECTED(screen_buf[baddr]) &&
384                    !IS_FA(screen_buf[nbaddr]))
385                        return nbaddr;
386        } while (nbaddr != baddr0);
387        return 0;
388}
389
390/*
391 * Perform an erase command, which may include changing the (virtual) screen
392 * size.
393 */
394void
395ctlr_erase(alt)
396Boolean alt;
397{
398        kybd_inhibit(False);
399
400        ctlr_clear(True);
401
402        if (alt == screen_alt)
403                return;
404
405        screen_disp();
406
407        if (alt) {
408                /* Going from 24x80 to maximum. */
409                screen_disp();
410                ROWS = maxROWS;
411                COLS = maxCOLS;
412        } else {
413                /* Going from maximum to 24x80. */
414                if (maxROWS > 24 || maxCOLS > 80) {
415                        if (*debugging_font) {
416                                ctlr_blanks();
417                                screen_disp();
418                        }
419                        ROWS = 24;
420                        COLS = 80;
421                }
422        }
423
424        screen_alt = alt;
425}
426
427
428/*
429 * Interpret an incoming 3270 command.
430 */
431int
432process_ds(buf, buflen)
433unsigned char   *buf;
434int     buflen;
435{
436        if (!buflen)
437                return 0;
438
439        scroll_to_bottom();
440
441        trace_ds("< ");
442
443        switch (buf[0]) {       /* 3270 command */
444        case CMD_EAU:   /* erase all unprotected */
445        case SNA_CMD_EAU:
446                trace_ds("EraseAllUnprotected\n");
447                ctlr_erase_all_unprotected();
448                break;
449        case CMD_EWA:   /* erase/write alternate */
450        case SNA_CMD_EWA:
451                trace_ds("EraseWriteAlternate");
452                ctlr_erase(True);
453                ctlr_write(buf, buflen, True);
454                break;
455        case CMD_EW:    /* erase/write */
456        case SNA_CMD_EW:
457                trace_ds("EraseWrite");
458                ctlr_erase(False);
459                ctlr_write(buf, buflen, True);
460                break;
461        case CMD_W:     /* write */
462        case SNA_CMD_W:
463                trace_ds("Write");
464                ctlr_write(buf, buflen, False);
465                break;
466        case CMD_RB:    /* read buffer */
467        case SNA_CMD_RB:
468                trace_ds("ReadBuffer\n");
469                ctlr_read_buffer(aid);
470                break;
471        case CMD_RM:    /* read modifed */
472        case SNA_CMD_RM:
473                trace_ds("ReadModified\n");
474                ctlr_read_modified(aid, False);
475                break;
476        case CMD_RMA:   /* read modifed all */
477        case SNA_CMD_RMA:
478                trace_ds("ReadModifiedAll\n");
479                ctlr_read_modified(aid, True);
480                break;
481        case CMD_WSF:   /* write structured field */
482        case SNA_CMD_WSF:
483                trace_ds("WriteStructuredField");
484                write_structured_field(buf, buflen);
485                break;
486        case CMD_NOP:   /* no-op */
487                trace_ds("NoOp\n");
488                break;
489        default:
490                /* unknown 3270 command */
491                popup_an_error("Unknown 3270 Data Stream command: 0x%X\n",
492                    buf[0]);
493                return -1;
494        }
495
496        return 0;
497}
498
499/*
500 * Functions to insert SA attributes into the inbound data stream.
501 */
502static void
503insert_sa1(attr, value, currentp, anyp)
504unsigned char attr;
505unsigned char value;
506unsigned char *currentp;
507Boolean *anyp;
508{
509        if (value == *currentp)
510                return;
511        *currentp = value;
512        space3270out(3);
513        *obptr++ = ORDER_SA;
514        *obptr++ = attr;
515        *obptr++ = value;
516        if (*anyp)
517                trace_ds("'");
518        trace_ds(" SetAttribute(%s)", see_efa(attr, value));
519        *anyp = False;
520}
521
522static void
[11122]523insert_sa(baddr, current_fgp, current_grp, current_csp, anyp)
[9080]524int baddr;
525unsigned char *current_fgp;
526unsigned char *current_grp;
[11122]527unsigned char *current_csp;
[9080]528Boolean *anyp;
529{
530        if (reply_mode != SF_SRM_CHAR)
531                return;
532
533        if (memchr((char *)crm_attr, XA_FOREGROUND, crm_nattr))
534                insert_sa1(XA_FOREGROUND, ea_buf[baddr].fg, current_fgp, anyp);
535        if (memchr((char *)crm_attr, XA_HIGHLIGHTING, crm_nattr)) {
536                unsigned char gr;
537
538                gr = ea_buf[baddr].gr;
539                if (gr)
540                        gr |= 0xf0;
541                insert_sa1(XA_HIGHLIGHTING, gr, current_grp, anyp);
542        }
[11122]543        if (memchr((char *)crm_attr, XA_CHARSET, crm_nattr)) {
544                unsigned char cs;
545
546                cs = ea_buf[baddr].cs & CS_MASK;
547                if (cs)
548                        cs |= 0xf0;
549                insert_sa1(XA_CHARSET, cs, current_csp, anyp);
550        }
551
[9080]552}
553
554
555/*
556 * Process a 3270 Read-Modified command and transmit the data back to the
557 * host.
558 */
559void
560ctlr_read_modified(aid_byte, all)
561unsigned char aid_byte;
562Boolean all;
563{
564        register int    baddr, sbaddr;
565        Boolean         send_data = True;
566        Boolean         short_read = False;
567        unsigned char   current_fg = 0x00;
568        unsigned char   current_gr = 0x00;
[11122]569        unsigned char   current_cs = 0x00;
[9080]570
571        trace_ds("> ");
572        obptr = obuf;
573
574        switch (aid_byte) {
575
576            case AID_SYSREQ:                    /* test request */
577                space3270out(4);
578                *obptr++ = 0x01;        /* soh */
579                *obptr++ = 0x5b;        /*  %  */
580                *obptr++ = 0x61;        /*  /  */
581                *obptr++ = 0x02;        /* stx */
582                trace_ds("SYSREQ");
583                break;
584
585            case AID_PA1:                       /* short-read AIDs */
586            case AID_PA2:
587            case AID_PA3:
588            case AID_CLEAR:
589                short_read = True;
590                /* fall through... */
591
592            case AID_SELECT:                    /* No data on READ MODIFIED */
593                if (!all)
594                        send_data = False;
595                /* fall through... */
596
597            default:                            /* ordinary AID */
598                space3270out(3);
599                *obptr++ = aid_byte;
600                trace_ds(see_aid(aid_byte));
601                if (short_read)
602                    goto rm_done;
603                ENCODE_BADDR(obptr, cursor_addr);
604                trace_ds(rcba(cursor_addr));
605                break;
606        }
607
608        baddr = 0;
609        if (formatted) {
610                /* find first field attribute */
611                do {
612                        if (IS_FA(screen_buf[baddr]))
613                                break;
614                        INC_BA(baddr);
615                } while (baddr != 0);
616                sbaddr = baddr;
617                do {
618                        if (FA_IS_MODIFIED(screen_buf[baddr])) {
619                                Boolean any = False;
620
621                                INC_BA(baddr);
622                                space3270out(3);
623                                *obptr++ = ORDER_SBA;
624                                ENCODE_BADDR(obptr, baddr);
625                                trace_ds(" SetBufferAddress%s", rcba(baddr));
626                                while (!IS_FA(screen_buf[baddr])) {
627                                        if (send_data &&
628                                            screen_buf[baddr]) {
629                                                insert_sa(baddr,
[11122]630                                                    &current_fg,
631                                                    &current_gr,
632                                                    &current_cs,
[9080]633                                                    &any);
[11122]634                                                if (ea_buf[baddr].cs & CS_GE) {
[9080]635                                                        space3270out(1);
636                                                        *obptr++ = ORDER_GE;
637                                                        if (any)
638                                                                trace_ds("'");
639                                                        trace_ds(" GraphicEscape");
640                                                        any = False;
641                                                }
642                                                space3270out(1);
643                                                *obptr++ = cg2ebc[screen_buf[baddr]];
644                                                if (!any)
645                                                        trace_ds(" '");
646                                                trace_ds(see_ebc(cg2ebc[screen_buf[baddr]]));
647                                                any = True;
648                                        }
649                                        INC_BA(baddr);
650                                }
651                                if (any)
652                                        trace_ds("'");
653                        }
654                        else {  /* not modified - skip */
655                                do {
656                                        INC_BA(baddr);
657                                } while (!IS_FA(screen_buf[baddr]));
658                        }
659                } while (baddr != sbaddr);
660        } else {
661                Boolean any = False;
662
663                do {
664                        if (screen_buf[baddr]) {
665                                insert_sa(baddr,
[11122]666                                    &current_fg,
667                                    &current_gr,
668                                    &current_cs,
669                                    &any);
670                                if (ea_buf[baddr].cs & CS_GE) {
[9080]671                                        space3270out(1);
672                                        *obptr++ = ORDER_GE;
673                                        if (any)
674                                                trace_ds("' ");
675                                        trace_ds(" GraphicEscape ");
676                                        any = False;
677                                }
678                                space3270out(1);
679                                *obptr++ = cg2ebc[screen_buf[baddr]];
680                                if (!any)
681                                        trace_ds("'");
682                                trace_ds(see_ebc(cg2ebc[screen_buf[baddr]]));
683                                any = True;
684                        }
685                        INC_BA(baddr);
686                } while (baddr != 0);
687                if (any)
688                        trace_ds("'");
689        }
690
691    rm_done:
692        trace_ds("\n");
693        net_output();
694}
695
696/*
697 * Calculate the proper 3270 DS value for an internal field attribute.
698 */
699static unsigned char
700calc_fa(fa)
701unsigned char fa;
702{
703        register unsigned char r = 0x00;
704
705        if (FA_IS_PROTECTED(fa))
706                r |= 0x20;
707        if (FA_IS_NUMERIC(fa))
708                r |= 0x10;
709        if (FA_IS_MODIFIED(fa))
710                r |= 0x01;
711        r |= ((fa & FA_INTENSITY) << 2);
712        return r;
713}
714
715/*
716 * Process a 3270 Read-Buffer command and transmit the data back to the
717 * host.
718 */
719void
720ctlr_read_buffer(aid_byte)
721unsigned char aid_byte;
722{
723        register int    baddr;
724        unsigned char   fa;
725        Boolean         any = False;
726        int             attr_count;
727        unsigned char   current_fg = 0x00;
728        unsigned char   current_gr = 0x00;
[11122]729        unsigned char   current_cs = 0x00;
[9080]730
731        trace_ds("> ");
732        obptr = obuf;
733
734        space3270out(3);
735        *obptr++ = aid_byte;
736        ENCODE_BADDR(obptr, cursor_addr);
737        trace_ds("%s%s", see_aid(aid_byte), rcba(cursor_addr));
738
739        baddr = 0;
740        do {
741                if (IS_FA(screen_buf[baddr])) {
742                        if (reply_mode == SF_SRM_FIELD) {
743                                space3270out(2);
744                                *obptr++ = ORDER_SF;
745                        } else {
746                                space3270out(4);
747                                *obptr++ = ORDER_SFE;
748                                attr_count = obptr - obuf;
749                                *obptr++ = 1; /* for now */
750                                *obptr++ = XA_3270;
751                        }
752                        fa = calc_fa(screen_buf[baddr]);
753                        *obptr++ = code_table[fa];
754                        if (any)
755                                trace_ds("'");
756                        trace_ds(" StartField%s%s%s",
757                            (reply_mode == SF_SRM_FIELD) ? "" : "Extended",
758                            rcba(baddr), see_attr(fa));
759                        if (reply_mode != SF_SRM_FIELD) {
760                                if (ea_buf[baddr].fg) {
761                                        space3270out(2);
762                                        *obptr++ = XA_FOREGROUND;
763                                        *obptr++ = ea_buf[baddr].fg;
764                                        trace_ds("%s", see_efa(XA_FOREGROUND,
765                                            ea_buf[baddr].fg));
766                                        (*(obuf + attr_count))++;
767                                }
768                                if (ea_buf[baddr].gr) {
769                                        space3270out(2);
770                                        *obptr++ = XA_HIGHLIGHTING;
771                                        *obptr++ = ea_buf[baddr].gr | 0xf0;
772                                        trace_ds("%s", see_efa(XA_HIGHLIGHTING,
773                                            ea_buf[baddr].gr | 0xf0));
774                                        (*(obuf + attr_count))++;
775                                }
[11122]776                                if (ea_buf[baddr].cs & CS_MASK) {
777                                        space3270out(2);
778                                        *obptr++ = XA_CHARSET;
779                                        *obptr++ =
780                                            (ea_buf[baddr].cs & CS_MASK) | 0xf0;
781                                        trace_ds("%s", see_efa(XA_CHARSET,
782                                            (ea_buf[baddr].cs & CS_MASK) | 0xf0));
783                                        (*(obuf + attr_count))++;
784                                }
[9080]785                        }
786                        any = False;
787                } else {
[11122]788                        insert_sa(baddr,
789                            &current_fg,
790                            &current_gr,
791                            &current_cs,
792                            &any);
793                        if (ea_buf[baddr].cs & CS_GE) {
[9080]794                                space3270out(1);
795                                *obptr++ = ORDER_GE;
796                                if (any)
797                                        trace_ds("'");
798                                trace_ds(" GraphicEscape");
799                                any = False;
800                        }
801                        space3270out(1);
802                        *obptr++ = cg2ebc[screen_buf[baddr]];
803                        if (cg2ebc[screen_buf[baddr]] <= 0x3f ||
804                            cg2ebc[screen_buf[baddr]] == 0xff) {
805                                if (any)
806                                        trace_ds("'");
807
808                                trace_ds(" %s", see_ebc(cg2ebc[screen_buf[baddr]]));
809                                any = False;
810                        } else {
811                                if (!any)
812                                        trace_ds(" '");
813                                trace_ds(see_ebc(cg2ebc[screen_buf[baddr]]));
814                                any = True;
815                        }
816                }
817                INC_BA(baddr);
818        } while (baddr != 0);
819        if (any)
820                trace_ds("'");
821
822        trace_ds("\n");
823        net_output();
824}
825
826/*
827 * Construct a 3270 command to reproduce the current state of the display.
828 */
829void
830ctlr_snap_buffer()
831{
832        register int    baddr = 0;
833        int             attr_count;
834        unsigned char   current_fg = 0x00;
835        unsigned char   current_gr = 0x00;
[11122]836        unsigned char   current_cs = 0x00;
[9080]837        unsigned char   av;
838
839        obptr = obuf;
840        space3270out(2);
841        *obptr++ = screen_alt ? CMD_EWA : CMD_EW;
842        *obptr++ = code_table[0];
843
844        do {
845                if (IS_FA(screen_buf[baddr])) {
846                        space3270out(4);
847                        *obptr++ = ORDER_SFE;
848                        attr_count = obptr - obuf;
849                        *obptr++ = 1; /* for now */
850                        *obptr++ = XA_3270;
851                        *obptr++ = code_table[calc_fa(screen_buf[baddr])];
852                        if (ea_buf[baddr].fg) {
853                                space3270out(2);
854                                *obptr++ = XA_FOREGROUND;
855                                *obptr++ = ea_buf[baddr].fg;
856                                (*(obuf + attr_count))++;
857                        }
858                        if (ea_buf[baddr].gr) {
859                                space3270out(2);
860                                *obptr++ = XA_HIGHLIGHTING;
861                                *obptr++ = ea_buf[baddr].gr | 0xf0;
862                                (*(obuf + attr_count))++;
863                        }
[11122]864                        if (ea_buf[baddr].cs & CS_MASK) {
865                                space3270out(2);
866                                *obptr++ = XA_CHARSET;
867                                *obptr++ = (ea_buf[baddr].cs & CS_MASK) | 0xf0;
868                                (*(obuf + attr_count))++;
869                        }
[9080]870                } else {
871                        av = ea_buf[baddr].fg;
872                        if (current_fg != av) {
873                                current_fg = av;
874                                space3270out(3);
875                                *obptr++ = ORDER_SA;
876                                *obptr++ = XA_FOREGROUND;
877                                *obptr++ = av;
878                        }
879                        av = ea_buf[baddr].gr;
880                        if (av)
881                                av |= 0xf0;
882                        if (current_gr != av) {
883                                current_gr = av;
884                                space3270out(3);
885                                *obptr++ = ORDER_SA;
886                                *obptr++ = XA_HIGHLIGHTING;
887                                *obptr++ = av;
888                        }
[11122]889                        av = ea_buf[baddr].cs & CS_MASK;
890                        if (av)
891                                av |= 0xf0;
892                        if (current_cs != av) {
893                                current_cs = av;
894                                space3270out(3);
895                                *obptr++ = ORDER_SA;
896                                *obptr++ = XA_CHARSET;
897                                *obptr++ = av;
898                        }
899                        if (ea_buf[baddr].cs & CS_GE) {
[9080]900                                space3270out(1);
901                                *obptr++ = ORDER_GE;
902                        }
903                        space3270out(1);
904                        *obptr++ = cg2ebc[screen_buf[baddr]];
905                }
906                INC_BA(baddr);
907        } while (baddr != 0);
908
909        space3270out(4);
910        *obptr++ = ORDER_SBA;
911        ENCODE_BADDR(obptr, cursor_addr);
912        *obptr++ = ORDER_IC;
913}
914
915/*
916 * Construct a 3270 command to reproduce the reply mode.
917 * Returns a Boolean indicating if one is necessary.
918 */
919Boolean
920ctlr_snap_modes()
921{
922        int i;
923
924        if (!IN_3270 || reply_mode == SF_SRM_FIELD)
925                return False;
926
927        obptr = obuf;
928        space3270out(6 + crm_nattr);
929        *obptr++ = CMD_WSF;
930        *obptr++ = 0x00;        /* implicit length */
931        *obptr++ = 0x00;
932        *obptr++ = SF_SET_REPLY_MODE;
933        *obptr++ = 0x00;        /* partition 0 */
934        *obptr++ = reply_mode;
935        if (reply_mode == SF_SRM_CHAR)
936                for (i = 0; i < crm_nattr; i++)
937                        *obptr++ = crm_attr[i];
938        return True;
939}
940
941
942/*
943 * Process a 3270 Erase All Unprotected command.
944 */
945void
946ctlr_erase_all_unprotected()
947{
948        register int    baddr, sbaddr;
949        unsigned char   fa;
950        Boolean         f;
951
952        kybd_inhibit(False);
953
954        ALL_CHANGED;
955        if (formatted) {
956                /* find first field attribute */
957                baddr = 0;
958                do {
959                        if (IS_FA(screen_buf[baddr]))
960                                break;
961                        INC_BA(baddr);
962                } while (baddr != 0);
963                sbaddr = baddr;
964                f = False;
965                do {
966                        fa = screen_buf[baddr];
967                        if (!FA_IS_PROTECTED(fa)) {
968                                mdt_clear(&screen_buf[baddr]);
969                                do {
970                                        INC_BA(baddr);
971                                        if (!f) {
972                                                cursor_move(baddr);
973                                                f = True;
974                                        }
975                                        if (!IS_FA(screen_buf[baddr])) {
976                                                ctlr_add(baddr, CG_null, 0);
977                                        }
978                                } while (!IS_FA(screen_buf[baddr]));
979                        }
980                        else {
981                                do {
982                                        INC_BA(baddr);
983                                } while (!IS_FA(screen_buf[baddr]));
984                        }
985                } while (baddr != sbaddr);
986                if (!f)
987                        cursor_move(0);
988        } else {
989                ctlr_clear(True);
990        }
991        aid = AID_NO;
992        do_reset(False);
993}
994
995
996
997/*
998 * Process a 3270 Write command.
999 */
1000void
1001ctlr_write(buf, buflen, erase)
1002unsigned char   buf[];
1003int     buflen;
1004Boolean erase;
1005{
1006        register unsigned char  *cp;
1007        register int    baddr;
1008        unsigned char   *current_fa;
1009        unsigned char   new_attr;
1010        Boolean         last_cmd;
1011        Boolean         last_zpt;
1012        Boolean         wcc_keyboard_restore, wcc_sound_alarm;
1013        Boolean         ra_ge;
1014        int             i;
1015        unsigned char   na;
1016        int             any_fa;
1017        unsigned char   efa_fg;
1018        unsigned char   efa_gr;
[11122]1019        unsigned char   efa_cs;
[9080]1020        char            *paren = "(";
1021        enum { NONE, ORDER, SBA, TEXT, NULLCH } previous = NONE;
1022
1023#define END_TEXT0       { if (previous == TEXT) trace_ds("'"); }
1024#define END_TEXT(cmd)   { END_TEXT0; trace_ds(" %s", cmd); }
1025
[11122]1026#define ATTR2FA(attr) \
1027        (FA_BASE | \
1028         (((attr) & 0x20) ? FA_PROTECT : 0) | \
1029         (((attr) & 0x10) ? FA_NUMERIC : 0) | \
1030         (((attr) & 0x01) ? FA_MODIFY : 0) | \
1031         (((attr) >> 2) & FA_INTENSITY))
[9080]1032#define START_FIELDx(fa) { \
1033                        current_fa = &(screen_buf[buffer_addr]); \
1034                        ctlr_add(buffer_addr, fa, 0); \
1035                        ctlr_add_fg(buffer_addr, 0); \
1036                        ctlr_add_gr(buffer_addr, 0); \
1037                        trace_ds(see_attr(fa)); \
1038                        formatted = True; \
1039                }
1040#define START_FIELD0    { START_FIELDx(FA_BASE); }
1041#define START_FIELD(attr) { \
[11122]1042                        new_attr = ATTR2FA(attr); \
[9080]1043                        START_FIELDx(new_attr); \
1044                }
1045
1046        kybd_inhibit(False);
1047
1048        if (buflen < 2)
1049                return;
1050
1051        default_fg = 0;
1052        default_gr = 0;
1053        default_cs = 0;
1054        trace_primed = True;
1055        buffer_addr = cursor_addr;
1056        if (WCC_RESET(buf[1])) {
1057                if (erase)
1058                        reply_mode = SF_SRM_FIELD;
1059                trace_ds("%sreset", paren);
1060                paren = ",";
1061        }
1062        wcc_sound_alarm = WCC_SOUND_ALARM(buf[1]);
1063        if (wcc_sound_alarm) {
1064                trace_ds("%salarm", paren);
1065                paren = ",";
1066        }
1067        wcc_keyboard_restore = WCC_KEYBOARD_RESTORE(buf[1]);
1068        if (wcc_keyboard_restore)
1069                ticking_stop();
1070        if (wcc_keyboard_restore) {
1071                trace_ds("%srestore", paren);
1072                paren = ",";
1073        }
1074
1075        if (WCC_RESET_MDT(buf[1])) {
1076                trace_ds("%sresetMDT", paren);
1077                paren = ",";
1078                baddr = 0;
1079                if (appres.modified_sel)
1080                        ALL_CHANGED;
1081                do {
1082                        if (IS_FA(screen_buf[baddr])) {
1083                                mdt_clear(&screen_buf[baddr]);
1084                        }
1085                        INC_BA(baddr);
1086                } while (baddr != 0);
1087        }
1088        if (strcmp(paren, "("))
1089                trace_ds(")");
1090
1091        last_cmd = True;
1092        last_zpt = False;
1093        current_fa = get_field_attribute(buffer_addr);
1094        for (cp = &buf[2]; cp < (buf + buflen); cp++) {
1095                switch (*cp) {
1096                case ORDER_SF:  /* start field */
1097                        END_TEXT("StartField");
1098                        if (previous != SBA)
1099                                trace_ds(rcba(buffer_addr));
1100                        previous = ORDER;
1101                        cp++;           /* skip field attribute */
1102                        START_FIELD(*cp);
1103                        ctlr_add_fg(buffer_addr, 0);
1104                        INC_BA(buffer_addr);
1105                        last_cmd = True;
1106                        last_zpt = False;
1107                        break;
1108                case ORDER_SBA: /* set buffer address */
1109                        cp += 2;        /* skip buffer address */
1110                        buffer_addr = DECODE_BADDR(*(cp-1), *cp);
1111                        END_TEXT("SetBufferAddress");
1112                        previous = SBA;
1113                        trace_ds(rcba(buffer_addr));
1114                        if (buffer_addr >= COLS * ROWS) {
1115                                trace_ds(" [invalid address, write command terminated]\n");
1116                                return;
1117                        }
1118                        current_fa = get_field_attribute(buffer_addr);
1119                        last_cmd = True;
1120                        last_zpt = False;
1121                        break;
1122                case ORDER_IC:  /* insert cursor */
1123                        END_TEXT("InsertCursor");
1124                        if (previous != SBA)
1125                                trace_ds(rcba(buffer_addr));
1126                        previous = ORDER;
1127                        cursor_move(buffer_addr);
1128                        last_cmd = True;
1129                        last_zpt = False;
1130                        break;
1131                case ORDER_PT:  /* program tab */
1132                        END_TEXT("ProgramTab");
1133                        previous = ORDER;
[11122]1134                        /*
1135                         * If the buffer address is the field attribute of
1136                         * of an unprotected field, simply advance one
1137                         * position.
1138                         */
1139                        if (IS_FA(screen_buf[buffer_addr]) &&
1140                            !FA_IS_PROTECTED(screen_buf[buffer_addr])) {
1141                                INC_BA(buffer_addr);
1142                                last_zpt = False;
1143                                last_cmd = True;
1144                                break;
1145                        }
1146                        /*
1147                         * Otherwise, advance to the first position of the
1148                         * next unprotected field.
1149                         */
[9080]1150                        baddr = next_unprotected(buffer_addr);
1151                        if (baddr < buffer_addr)
1152                                baddr = 0;
1153                        /*
1154                         * Null out the remainder of the current field -- even
1155                         * if protected -- if the PT doesn't follow a command
1156                         * or order, or (honestly) if the last order we saw was
1157                         * a null-filling PT that left the buffer address at 0.
1158                         */
1159                        if (!last_cmd || last_zpt) {
1160                                trace_ds("(nulling)");
1161                                while ((buffer_addr != baddr) &&
1162                                       (!IS_FA(screen_buf[buffer_addr]))) {
1163                                        ctlr_add(buffer_addr, CG_null, 0);
1164                                        INC_BA(buffer_addr);
1165                                }
1166                                if (baddr == 0)
1167                                        last_zpt = True;
[11122]1168
[9080]1169                        } else
1170                                last_zpt = False;
1171                        buffer_addr = baddr;
1172                        last_cmd = True;
1173                        break;
1174                case ORDER_RA:  /* repeat to address */
1175                        END_TEXT("RepeatToAddress");
1176                        cp += 2;        /* skip buffer address */
1177                        baddr = DECODE_BADDR(*(cp-1), *cp);
1178                        trace_ds(rcba(baddr));
1179                        cp++;           /* skip char to repeat */
1180                        if (*cp == ORDER_GE){
1181                                ra_ge = True;
1182                                trace_ds("GraphicEscape");
1183                                cp++;
1184                        } else
1185                                ra_ge = False;
1186                        previous = ORDER;
1187                        if (*cp)
1188                                trace_ds("'");
1189                        trace_ds(see_ebc(*cp));
1190                        if (*cp)
1191                                trace_ds("'");
1192                        if (baddr >= COLS * ROWS) {
1193                                trace_ds(" [invalid address, write command terminated]\n");
1194                                return;
1195                        }
1196                        do {
[11122]1197                                if (ra_ge)
1198                                        ctlr_add(buffer_addr, ebc2cg0[*cp],
1199                                            CS_GE);
1200                                else if (default_cs)
[9080]1201                                        ctlr_add(buffer_addr, ebc2cg0[*cp], 1);
1202                                else
1203                                        ctlr_add(buffer_addr, ebc2cg[*cp], 0);
1204                                ctlr_add_fg(buffer_addr, default_fg);
1205                                ctlr_add_gr(buffer_addr, default_gr);
1206                                INC_BA(buffer_addr);
1207                        } while (buffer_addr != baddr);
1208                        current_fa = get_field_attribute(buffer_addr);
1209                        last_cmd = True;
1210                        last_zpt = False;
1211                        break;
1212                case ORDER_EUA: /* erase unprotected to address */
1213                        cp += 2;        /* skip buffer address */
1214                        baddr = DECODE_BADDR(*(cp-1), *cp);
1215                        END_TEXT("EraseUnprotectedAll");
1216                        if (previous != SBA)
1217                                trace_ds(rcba(baddr));
1218                        previous = ORDER;
1219                        if (baddr >= COLS * ROWS) {
1220                                trace_ds(" [invalid address, write command terminated]\n");
1221                                return;
1222                        }
1223                        do {
1224                                if (IS_FA(screen_buf[buffer_addr]))
1225                                        current_fa = &(screen_buf[buffer_addr]);
1226                                else if (!FA_IS_PROTECTED(*current_fa)) {
1227                                        ctlr_add(buffer_addr, CG_null, 0);
1228                                }
1229                                INC_BA(buffer_addr);
1230                        } while (buffer_addr != baddr);
1231                        current_fa = get_field_attribute(buffer_addr);
1232                        last_cmd = True;
1233                        last_zpt = False;
1234                        break;
1235                case ORDER_GE:  /* graphic escape */
1236                        END_TEXT("GraphicEscape ");
1237                        cp++;           /* skip char */
1238                        previous = ORDER;
1239                        if (*cp)
1240                                trace_ds("'");
1241                        trace_ds(see_ebc(*cp));
1242                        if (*cp)
1243                                trace_ds("'");
[11122]1244                        ctlr_add(buffer_addr, ebc2cg0[*cp], CS_GE);
[9080]1245                        ctlr_add_fg(buffer_addr, default_fg);
1246                        ctlr_add_gr(buffer_addr, default_gr);
1247                        INC_BA(buffer_addr);
1248                        current_fa = get_field_attribute(buffer_addr);
1249                        last_cmd = False;
1250                        last_zpt = False;
1251                        break;
1252                case ORDER_MF:  /* modify field */
1253                        END_TEXT("ModifyField");
1254                        if (previous != SBA)
1255                                trace_ds(rcba(buffer_addr));
1256                        previous = ORDER;
1257                        cp++;
1258                        na = *cp;
1259                        if (IS_FA(screen_buf[buffer_addr])) {
1260                                if (na == 0) {
1261                                        INC_BA(buffer_addr);
1262                                } else {
1263                                        for (i = 0; i < (int)na; i++) {
1264                                                cp++;
1265                                                if (*cp == XA_3270) {
1266                                                        trace_ds(" 3270");
1267                                                        cp++;
[11122]1268                                                        new_attr = ATTR2FA(*cp);
1269                                                        ctlr_add(buffer_addr,
1270                                                            new_attr,
1271                                                            0);
1272                                                        trace_ds(see_attr(new_attr));
[9080]1273                                                } else if (*cp == XA_FOREGROUND) {
1274                                                        trace_ds("%s",
1275                                                            see_efa(*cp,
1276                                                                *(cp + 1)));
1277                                                        cp++;
1278                                                        if (appres.m3279)
1279                                                                ctlr_add_fg(buffer_addr, *cp);
1280                                                } else if (*cp == XA_HIGHLIGHTING) {
1281                                                        trace_ds("%s",
1282                                                            see_efa(*cp,
1283                                                                *(cp + 1)));
1284                                                        cp++;
1285                                                        ctlr_add_gr(buffer_addr, *cp & 0x07);
[11122]1286                                                } else if (*cp == XA_CHARSET) {
1287                                                        int cs = 0;
1288
1289                                                        trace_ds("%s",
1290                                                            see_efa(*cp,
1291                                                                *(cp + 1)));
1292                                                        cp++;
1293                                                        if (*cp == 0xf1)
1294                                                                cs = 1;
1295                                                        ctlr_add(buffer_addr,
1296                                                            screen_buf[buffer_addr], cs);
[9080]1297                                                } else if (*cp == XA_ALL) {
1298                                                        trace_ds("%s",
1299                                                            see_efa(*cp,
1300                                                                *(cp + 1)));
1301                                                        cp++;
1302                                                } else {
1303                                                        trace_ds("%s[unsupported]", see_efa(*cp, *(cp + 1)));
1304                                                        cp++;
1305                                                }
1306                                        }
1307                                }
1308                                INC_BA(buffer_addr);
1309                        } else
1310                                cp += na * 2;
1311                        last_cmd = True;
1312                        last_zpt = False;
1313                        break;
1314                case ORDER_SFE: /* start field extended */
1315                        END_TEXT("StartFieldExtended");
1316                        if (previous != SBA)
1317                                trace_ds(rcba(buffer_addr));
1318                        previous = ORDER;
1319                        cp++;   /* skip order */
1320                        na = *cp;
1321                        any_fa = 0;
1322                        efa_fg = 0;
1323                        efa_gr = 0;
[11122]1324                        efa_cs = 0;
[9080]1325                        for (i = 0; i < (int)na; i++) {
1326                                cp++;
1327                                if (*cp == XA_3270) {
1328                                        trace_ds(" 3270");
1329                                        cp++;
1330                                        START_FIELD(*cp);
1331                                        any_fa++;
1332                                } else if (*cp == XA_FOREGROUND) {
1333                                        trace_ds("%s", see_efa(*cp, *(cp + 1)));
1334                                        cp++;
1335                                        if (appres.m3279)
1336                                                efa_fg = *cp;
1337                                } else if (*cp == XA_HIGHLIGHTING) {
1338                                        trace_ds("%s", see_efa(*cp, *(cp + 1)));
1339                                        cp++;
1340                                        efa_gr = *cp & 0x07;
[11122]1341                                } else if (*cp == XA_CHARSET) {
1342                                        trace_ds("%s", see_efa(*cp, *(cp + 1)));
1343                                        cp++;
1344                                        if (*cp == 0xf1)
1345                                                efa_cs = 1;
[9080]1346                                } else if (*cp == XA_ALL) {
1347                                        trace_ds("%s", see_efa(*cp, *(cp + 1)));
1348                                        cp++;
1349                                } else {
1350                                        trace_ds("%s[unsupported]", see_efa(*cp, *(cp + 1)));
1351                                        cp++;
1352                                }
1353                        }
1354                        if (!any_fa)
1355                                START_FIELD0;
[11122]1356                        ctlr_add(buffer_addr, screen_buf[buffer_addr], efa_cs);
[9080]1357                        ctlr_add_fg(buffer_addr, efa_fg);
1358                        ctlr_add_gr(buffer_addr, efa_gr);
1359                        INC_BA(buffer_addr);
1360                        last_cmd = True;
1361                        last_zpt = False;
1362                        break;
1363                case ORDER_SA:  /* set attribute */
1364                        END_TEXT("SetAttribtue");
1365                        previous = ORDER;
1366                        cp++;
1367                        if (*cp == XA_FOREGROUND)  {
1368                                trace_ds("%s", see_efa(*cp, *(cp + 1)));
1369                                if (appres.m3279)
1370                                        default_fg = *(cp + 1);
1371                        } else if (*cp == XA_HIGHLIGHTING)  {
1372                                trace_ds("%s", see_efa(*cp, *(cp + 1)));
1373                                default_gr = *(cp + 1) & 0x07;
1374                        } else if (*cp == XA_ALL)  {
1375                                trace_ds("%s", see_efa(*cp, *(cp + 1)));
1376                                default_fg = 0;
1377                                default_gr = 0;
[11122]1378                                default_cs = 0;
1379                        } else if (*cp == XA_CHARSET) {
1380                                trace_ds("%s", see_efa(*cp, *(cp + 1)));
1381                                default_cs = (*(cp + 1) == 0xf1) ? 1 : 0;
[9080]1382                        } else
1383                                trace_ds("%s[unsupported]",
1384                                    see_efa(*cp, *(cp + 1)));
1385                        cp++;
1386                        last_cmd = True;
1387                        last_zpt = False;
1388                        break;
1389                case FCORDER_SUB:       /* format control orders */
1390                case FCORDER_DUP:
1391                case FCORDER_FM:
1392                case FCORDER_FF:
1393                case FCORDER_CR:
1394                case FCORDER_NL:
1395                case FCORDER_EM:
1396                case FCORDER_EO:
1397                        END_TEXT(see_ebc(*cp));
1398                        previous = ORDER;
1399                        ctlr_add(buffer_addr, ebc2cg[*cp], default_cs);
1400                        ctlr_add_fg(buffer_addr, default_fg);
1401                        ctlr_add_gr(buffer_addr, default_gr);
1402                        INC_BA(buffer_addr);
1403                        last_cmd = True;
1404                        last_zpt = False;
1405                        break;
1406                case FCORDER_NULL:
1407                        END_TEXT("NULL");
1408                        previous = NULLCH;
1409                        ctlr_add(buffer_addr, ebc2cg[*cp], default_cs);
1410                        ctlr_add_fg(buffer_addr, default_fg);
1411                        ctlr_add_gr(buffer_addr, default_gr);
1412                        INC_BA(buffer_addr);
1413                        last_cmd = False;
1414                        last_zpt = False;
1415                        break;
1416                default:        /* enter character */
1417                        if (*cp <= 0x3F) {
1418                                END_TEXT("ILLEGAL_ORDER");
1419                                trace_ds(see_ebc(*cp));
1420                                last_cmd = True;
1421                                last_zpt = False;
1422                                break;
1423                        }
1424                        if (previous != TEXT)
1425                                trace_ds(" '");
1426                        previous = TEXT;
1427                        trace_ds(see_ebc(*cp));
1428                        ctlr_add(buffer_addr, ebc2cg[*cp], default_cs);
1429                        ctlr_add_fg(buffer_addr, default_fg);
1430                        ctlr_add_gr(buffer_addr, default_gr);
1431                        INC_BA(buffer_addr);
1432                        last_cmd = False;
1433                        last_zpt = False;
1434                        break;
1435                }
1436        }
1437        set_formatted();
1438        END_TEXT0;
1439        trace_ds("\n");
1440        if (wcc_keyboard_restore) {
1441                aid = AID_NO;
1442                do_reset(False);
1443        } else if (kybdlock & KL_OIA_TWAIT) {
1444                kybdlock_clr(KL_OIA_TWAIT, "ctlr_write");
1445                status_syswait();
1446        }
1447        if (wcc_sound_alarm)
1448                ring_bell();
1449
1450        trace_primed = False;
1451
1452        ps_process();
1453}
1454
1455#undef START_FIELDx
1456#undef START_FIELD0
1457#undef START_FIELD
1458#undef END_TEXT0
1459#undef END_TEXT
1460
1461
1462/*
1463 * Process pending input.
1464 */
1465void
1466ps_process()
1467{
1468        /* Process typeahead. */
1469        while (run_ta())
1470                ;
1471
1472        /* Process pending scripts and macros. */
1473        sms_continue();
1474
1475        /* Process file transfers. */
1476        if (ft_state != FT_NONE &&      /* transfer in progress */
1477            formatted &&                /* screen is formatted */
1478            !screen_alt &&              /* 24x80 screen */
1479            !kybdlock &&                /* keyboard not locked */
1480                                        /* magic field */
1481            IS_FA(screen_buf[1919]) && FA_IS_SKIP(screen_buf[1919]))
1482                ft_cut_data();
1483}
1484
1485/*
1486 * Tell me if there is any data on the screen.
1487 */
1488Boolean
1489ctlr_any_data()
1490{
1491        register unsigned char *c = screen_buf;
1492        register int i;
1493        register unsigned char oc;
1494
1495        for (i = 0; i < ROWS*COLS; i++) {
1496                oc = *c++;
1497                if (!IS_FA(oc) && !IsBlank(oc))
1498                        return True;
1499        }
1500        return False;
1501}
1502
1503/*
1504 * Clear the text (non-status) portion of the display.  Also resets the cursor
1505 * and buffer addresses and extended attributes.
1506 */
1507void
1508ctlr_clear(can_snap)
1509Boolean can_snap;
1510{
1511        extern Boolean trace_skipping;
1512
1513        /* Snap any data that is about to be lost into the trace file. */
1514        if (ctlr_any_data()) {
1515                if (can_snap && !trace_skipping && toggled(SCREEN_TRACE))
1516                        trace_screen();
1517                scroll_save(maxROWS, ever_3270 ? False : True);
1518        }
1519        trace_skipping = False;
1520
1521        /* Clear the screen. */
1522        (void) memset((char *)screen_buf, 0, ROWS*COLS);
1523        (void) memset((char *)ea_buf, 0, ROWS*COLS*sizeof(struct ea));
1524        ALL_CHANGED;
1525        cursor_move(0);
1526        buffer_addr = 0;
1527        (void) unselect(0, ROWS*COLS);
1528        formatted = False;
1529        default_fg = 0;
1530        default_gr = 0;
1531}
1532
1533/*
1534 * Fill the screen buffer with blanks.
1535 */
1536static void
1537ctlr_blanks()
1538{
1539        (void) memset((char *)screen_buf, CG_space, ROWS*COLS);
1540        ALL_CHANGED;
1541        cursor_move(0);
1542        buffer_addr = 0;
1543        (void) unselect(0, ROWS*COLS);
1544        formatted = False;
1545}
1546
1547
1548/*
1549 * Change a character in the 3270 buffer.
1550 */
1551void
1552ctlr_add(baddr, c, cs)
1553int     baddr;          /* buffer address */
1554unsigned char   c;      /* character */
1555unsigned char   cs;     /* character set */
1556{
1557        unsigned char oc;
1558
1559        if ((oc = screen_buf[baddr]) != c || ea_buf[baddr].cs != cs) {
1560                if (trace_primed && !IsBlank(oc)) {
1561                        if (toggled(SCREEN_TRACE))
1562                                trace_screen();
1563                        scroll_save(maxROWS, False);
1564                        trace_primed = False;
1565                }
1566                if (SELECTED(baddr))
1567                        (void) unselect(baddr, 1);
1568                ONE_CHANGED(baddr);
1569                screen_buf[baddr] = c;
1570                ea_buf[baddr].cs = cs;
1571        }
1572}
1573
1574/*
1575 * Change the graphic rendition of a character in the 3270 buffer.
1576 */
1577void
1578ctlr_add_gr(baddr, gr)
1579int     baddr;
1580unsigned char   gr;
1581{
1582        if (ea_buf[baddr].gr != gr) {
1583                if (SELECTED(baddr))
1584                        (void) unselect(baddr, 1);
1585                ONE_CHANGED(baddr);
1586                ea_buf[baddr].gr = gr;
1587                if (gr & GR_BLINK)
1588                        blink_start();
1589        }
1590}
1591
1592/*
1593 * Change the foreground color for a character in the 3270 buffer.
1594 */
1595void
1596ctlr_add_fg(baddr, color)
1597int     baddr;
1598unsigned char   color;
1599{
1600        if (!appres.m3279)
1601                return;
1602        if ((color & 0xf0) != 0xf0)
1603                color = 0;
1604        if (ea_buf[baddr].fg != color) {
1605                if (SELECTED(baddr))
1606                        (void) unselect(baddr, 1);
1607                ONE_CHANGED(baddr);
1608                ea_buf[baddr].fg = color;
1609        }
1610}
1611
1612/*
1613 * Change the background color for a character in the 3270 buffer.
1614 */
1615void
1616ctlr_add_bg(baddr, color)
1617int     baddr;
1618unsigned char   color;
1619{
1620        if (!appres.m3279)
1621                return;
1622        if ((color & 0xf0) != 0xf0)
1623                color = 0;
1624        if (ea_buf[baddr].bg != color) {
1625                if (SELECTED(baddr))
1626                        (void) unselect(baddr, 1);
1627                ONE_CHANGED(baddr);
1628                ea_buf[baddr].bg = color;
1629        }
1630}
1631
1632/*
1633 * Copy a block of characters in the 3270 buffer, optionally including all of
1634 * the extended attributes.  (The character set, which is actually kept in the
1635 * extended attributes, is considered part of the characters here.)
1636 */
1637void
1638ctlr_bcopy(baddr_from, baddr_to, count, move_ea)
1639int     baddr_from;
1640int     baddr_to;
1641int     count;
1642int     move_ea;
1643{
1644        /* Move the characters. */
1645        if (memcmp((char *) &screen_buf[baddr_from],
1646                   (char *) &screen_buf[baddr_to],
1647                   count)) {
1648                (void) MEMORY_MOVE((char *) &screen_buf[baddr_to],
1649                                   (char *) &screen_buf[baddr_from],
1650                                   count);
1651                REGION_CHANGED(baddr_to, baddr_to + count);
1652                /*
1653                 * For the time being, if any selected text shifts around on
1654                 * the screen, unhighlight it.  Eventually there should be
1655                 * logic for preserving the highlight if the *all* of the
1656                 * selected text moves.
1657                 */
1658                if (area_is_selected(baddr_to, count))
1659                        (void) unselect(baddr_to, count);
1660        }
1661
1662        /*
1663         * If we aren't supposed to move all the extended attributes, move
1664         * the character sets separately.
1665         */
1666        if (!move_ea) {
1667                int i;
1668                int any = 0;
1669                int start, end, inc;
1670
1671                if (baddr_to < baddr_from || baddr_from + count < baddr_to) {
1672                        /* Scan forward. */
1673                        start = 0;
1674                        end = count + 1;
1675                        inc = 1;
1676                } else {
1677                        /* Scan backward. */
1678                        start = count - 1;
1679                        end = -1;
1680                        inc = -1;
1681                }
1682
1683                for (i = start; i != end; i += inc) {
1684                        if (ea_buf[baddr_to+i].cs != ea_buf[baddr_from+i].cs) {
1685                                ea_buf[baddr_to+i].cs = ea_buf[baddr_from+i].cs;
1686                                REGION_CHANGED(baddr_to + i, baddr_to + i + 1);
1687                                any++;
1688                        }
1689                }
1690                if (any && area_is_selected(baddr_to, count))
1691                        (void) unselect(baddr_to, count);
1692        }
1693
1694        /* Move extended attributes. */
1695        if (move_ea && memcmp((char *) &ea_buf[baddr_from],
1696                              (char *) &ea_buf[baddr_to],
1697                              count*sizeof(struct ea))) {
1698                (void) MEMORY_MOVE((char *) &ea_buf[baddr_to],
1699                                   (char *) &ea_buf[baddr_from],
1700                                   count*sizeof(struct ea));
1701                REGION_CHANGED(baddr_to, baddr_to + count);
1702        }
1703}
1704
1705/*
1706 * Erase a region of the 3270 buffer, optionally clearing extended attributes
1707 * as well.
1708 */
1709void
1710ctlr_aclear(baddr, count, clear_ea)
1711int     baddr;
1712int     count;
1713int     clear_ea;
1714{
1715        if (memcmp((char *) &screen_buf[baddr], (char *) zero_buf, count)) {
1716                (void) memset((char *) &screen_buf[baddr], 0, count);
1717                REGION_CHANGED(baddr, baddr + count);
1718                if (area_is_selected(baddr, count))
1719                        (void) unselect(baddr, count);
1720        }
1721        if (clear_ea && memcmp((char *) &ea_buf[baddr], (char *) zero_buf, count*sizeof(struct ea))) {
1722                (void) memset((char *) &ea_buf[baddr], 0, count*sizeof(struct ea));
1723                REGION_CHANGED(baddr, baddr + count);
1724        }
1725}
1726
1727/*
1728 * Scroll the screen 1 row.
1729 *
1730 * This could be accomplished with ctlr_bcopy() and ctlr_aclear(), but this
1731 * operation is common enough to warrant a separate path.
1732 */
1733void
1734ctlr_scroll()
1735{
1736        int qty = (ROWS - 1) * COLS;
1737        Boolean obscured;
1738
1739        /* Make sure nothing is selected. (later this can be fixed) */
1740        (void) unselect(0, ROWS*COLS);
1741
1742        /* Synchronize pending changes prior to this. */
1743        obscured = screen_obscured();
1744        if (!obscured && screen_changed)
1745                screen_disp();
1746
1747        /* Move screen_buf and ea_buf. */
1748        (void) MEMORY_MOVE((char *) &screen_buf[0],
1749            (char *) &screen_buf[COLS],
1750            qty);
1751        (void) MEMORY_MOVE((char *) &ea_buf[0],
1752            (char *) &ea_buf[COLS],
1753            qty * sizeof(struct ea));
1754
1755        /* Clear the last line. */
1756        (void) memset((char *) &screen_buf[qty], 0, COLS);
1757        (void) memset((char *) &ea_buf[qty], 0, COLS * sizeof(struct ea));
1758
1759        /* Update the screen. */
1760        if (obscured) {
1761                ALL_CHANGED;
1762        } else
1763                screen_scroll();
1764}
1765
1766/*
1767 * Note that a particular region of the screen has changed.
1768 */
1769void
1770ctlr_changed(bstart, bend)
1771int bstart;     /* first changed location */
1772int bend;       /* last changed location, plus 1 */
1773{
1774        REGION_CHANGED(bstart, bend);
1775}
1776
1777/*
1778 * Swap the regular and alternate screen buffers
1779 */
1780void
1781ctlr_altbuffer(alt)
1782Boolean alt;
1783{
1784        unsigned char *stmp;
1785        struct ea *etmp;
1786
1787        if (alt != is_altbuffer) {
1788
1789                stmp = screen_buf;
1790                screen_buf = ascreen_buf;
1791                ascreen_buf = stmp;
1792
1793                etmp = ea_buf;
1794                ea_buf = aea_buf;
1795                aea_buf = etmp;
1796
1797                is_altbuffer = alt;
1798                ALL_CHANGED;
1799                (void) unselect(0, ROWS*COLS);
1800
1801                /*
1802                 * There may be blinkers on the alternate screen; schedule one
1803                 * iteration just in case.
1804                 */
1805                blink_start();
1806        }
1807}
1808#undef SWAP
1809
1810
1811/*
1812 * Set or clear the MDT on an attribute
1813 */
1814void
1815mdt_set(fa)
1816unsigned char *fa;
1817{
1818        if (*fa & FA_MODIFY)
1819                return;
1820        *fa |= FA_MODIFY;
1821        if (appres.modified_sel)
1822                ALL_CHANGED;
1823}
1824
1825void
1826mdt_clear(fa)
1827unsigned char *fa;
1828{
1829        if (!(*fa & FA_MODIFY))
1830                return;
1831        *fa &= ~FA_MODIFY;
1832        if (appres.modified_sel)
1833                ALL_CHANGED;
1834}
1835
1836
1837/*
1838 * Support for screen-size swapping for scrolling
1839 */
1840void
1841ctlr_shrink()
1842{
1843        (void) memset((char *)screen_buf,
1844            *debugging_font ? CG_space : CG_null,
1845            ROWS*COLS);
1846        ALL_CHANGED;
1847        screen_disp();
1848}
1849
1850
1851/*
1852 * Transaction timing.  The time between sending an interrupt (PF, PA, Enter,
1853 * Clear) and the host unlocking the keyboard is indicated on the status line
1854 * to an accuracy of 0.1 seconds.  If we don't repaint the screen before we see
1855 * the unlock, the time should be fairly accurate.
1856 */
1857static struct timeval t_start;
1858static Boolean ticking = False;
1859static XtIntervalId tick_id;
1860static struct timeval t_want;
1861
1862/* Return the difference in milliseconds between two timevals. */
1863static long
1864delta_msec(t1, t0)
1865struct timeval *t1, *t0;
1866{
1867        return (t1->tv_sec - t0->tv_sec) * 1000 +
1868               (t1->tv_usec - t0->tv_usec + 500) / 1000;
1869}
1870
1871/*ARGSUSED*/
1872static void
1873keep_ticking(closure, id)
1874XtPointer closure;
1875XtIntervalId *id;
1876{
1877        struct timeval t1;
1878        long msec;
1879
1880        do {
1881                (void) gettimeofday(&t1, (struct timezone *) 0);
1882                t_want.tv_sec++;
1883                msec = delta_msec(&t_want, &t1);
1884        } while (msec <= 0);
1885        tick_id = XtAppAddTimeOut(appcontext, msec, keep_ticking, 0);
1886        status_timing(&t_start, &t1);
1887}
1888
1889void
1890ticking_start(anyway)
1891Boolean anyway;
1892{
1893        if (!toggled(SHOW_TIMING) && !anyway)
1894                return;
1895        status_untiming();
1896        if (ticking)
1897                XtRemoveTimeOut(tick_id);
1898        ticking = True;
1899        (void) gettimeofday(&t_start, (struct timezone *) 0);
1900        tick_id = XtAppAddTimeOut(appcontext, 1000, keep_ticking, 0);
1901        t_want = t_start;
1902}
1903
1904void
1905ticking_stop()
1906{
1907        struct timeval t1;
1908
1909        if (!ticking)
1910                return;
1911        XtRemoveTimeOut(tick_id);
1912        (void) gettimeofday(&t1, (struct timezone *) 0);
1913        ticking = False;
1914        status_timing(&t_start, &t1);
1915}
1916
1917/*ARGSUSED*/
1918void
1919toggle_showTiming(t, tt)
1920struct toggle *t;
1921enum toggle_type tt;
1922{
1923        if (!toggled(SHOW_TIMING))
1924                status_untiming();
1925}
1926
1927
1928/*
1929 * No-op toggle.
1930 */
1931/*ARGSUSED*/
1932void
1933toggle_nop(t, tt)
1934struct toggle *t;
1935enum toggle_type tt;
1936{
1937}
Note: See TracBrowser for help on using the repository browser.