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

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