x3270 v3.0.1 Patch Set #3, 29. November 1993 This file is in 'patch' format. To apply, run 'patch value = !(t)->value) ! extern enum placement { Center, Bottom, Right }; extern enum kp_placement { kp_right, kp_bottom, kp_integral } kp_placement; extern struct trans_list { --- 111,117 ---- #define toggled(ix) (appres.toggle[ix].value) #define toggle_toggle(t) ((t)->value = !(t)->value) ! enum placement { Center, Bottom, Right }; extern enum kp_placement { kp_right, kp_bottom, kp_integral } kp_placement; extern struct trans_list { Fix can't-ever-happen which apparently did. *** telnet.c.orig Thu Nov 4 12:50:22 1993 --- telnet.c Thu Nov 4 12:50:23 1993 *************** *** 288,293 **** --- 288,295 ---- nr = read(sock, (char *) netrbuf, BUFSZ); if (nr < 0) { + if (errno == EWOULDBLOCK) + return; if (HALF_CONNECTED && errno == EAGAIN) { if (non_blocking(False) < 0) { x_disconnect(); Fix for error in the response to the READ BUFFER command, which wasn't properly encoding attribute bytes. *** ctlr.c.orig Mon Nov 15 11:35:56 1993 --- ctlr.c Mon Nov 15 11:35:57 1993 *************** *** 62,68 **** static void do_erase_all_unprotected(); static void do_write(); ! /* code_table is used to translate buffer addresses to the 3270 * datastream representation */ static unsigned char code_table[64] = { --- 62,68 ---- static void do_erase_all_unprotected(); static void do_write(); ! /* code_table is used to translate buffer addresses and attributes to the 3270 * datastream representation */ static unsigned char code_table[64] = { *************** *** 595,601 **** if (FA_IS_MODIFIED(screen_buf[baddr])) fa |= 0x01; fa |= ((screen_buf[baddr] & FA_INTENSITY) << 2); ! *obptr++ = fa; if (toggled(TRACE3270)) { if (!last_fa) (void) printf("'"); --- 595,601 ---- if (FA_IS_MODIFIED(screen_buf[baddr])) fa |= 0x01; fa |= ((screen_buf[baddr] & FA_INTENSITY) << 2); ! *obptr++ = code_table[fa]; if (toggled(TRACE3270)) { if (!last_fa) (void) printf("'"); Fix OpenWindows font targets in Makefile.aux. *** Makefile.aux.orig Wed Nov 17 13:49:46 1993 --- Makefile.aux Wed Nov 17 13:49:47 1993 *************** *** 62,68 **** OWFONTOBJS = $(FONTS:%.bdf=%.fb) .bdf.fb: ! convertfont -d. $< .SUFFIXES: .bdf .fb $(SUFFIXES) LIBS = -lXaw -lXmu -lX11 -lXt -lXext -lX11 -lm --- 62,68 ---- OWFONTOBJS = $(FONTS:%.bdf=%.fb) .bdf.fb: ! $(OPENWINHOME)/bin/convertfont -d. -o `basename $@ .fb` $< .SUFFIXES: .bdf .fb $(SUFFIXES) LIBS = -lXaw -lXmu -lX11 -lXt -lXext -lX11 -lm *************** *** 90,96 **** @$(RM) version.c # Make x3270 for OpenWindows 3 ! ow3: x3270 # Install x3270 under OpenWindows 3: assumes you want to put everything in # $OPENWINHOME. --- 90,96 ---- @$(RM) version.c # Make x3270 for OpenWindows 3 ! ow3: x3270 $(OWFONTOBJS) # Install x3270 under OpenWindows 3: assumes you want to put everything in # $OPENWINHOME. *************** *** 97,103 **** ow3.install: ow3 install -m 755 x3270 $(OPENWINHOME)/bin cp $(OWFONTOBJS) $(OPENWINHOME)/lib/fonts ! mkfontdir $(OPENWINHOME)/lib/fonts cp X3270.ad $(OPENWINHOME)/lib/app-defaults/X3270 cp x3270.man $(OPENWINHOME)/man/man1/x3270.1 cp ibm_hosts.man $(OPENWINHOME)/man/man5/ibm_hosts.5 --- 97,103 ---- ow3.install: ow3 install -m 755 x3270 $(OPENWINHOME)/bin cp $(OWFONTOBJS) $(OPENWINHOME)/lib/fonts ! $(OPENWINHOME)/bin/mkfontdir $(OPENWINHOME)/lib/fonts cp X3270.ad $(OPENWINHOME)/lib/app-defaults/X3270 cp x3270.man $(OPENWINHOME)/man/man1/x3270.1 cp ibm_hosts.man $(OPENWINHOME)/man/man5/ibm_hosts.5 Fix a typo in X3270.ad. *** X3270.ad.orig Wed Nov 17 13:51:25 1993 --- X3270.ad Wed Nov 17 13:51:25 1993 *************** *** 9,15 **** ! easily uncomment and change them. ! ! Fonts ! ! x3270.eumlatorFont: 3270 ! ! Colors ! x3270.colorBackground: black --- 9,15 ---- ! easily uncomment and change them. ! ! Fonts ! ! x3270.emulatorFont: 3270 ! ! Colors ! x3270.colorBackground: black Fix a spelling error in x3270.man. *** x3270.man.orig Wed Nov 17 13:53:41 1993 --- x3270.man Wed Nov 17 13:53:42 1993 *************** *** 669,675 **** .B Note: The default keymap defines the "Multi_key" keysym as the "Compose" key. If your keyboard lacks such a key, you may set up your own "Compose" key with ! a keymap that maps smoe other keysym onto the "Compose" action. .SH "APL SUPPORT" .B x3270 supports an --- 669,675 ---- .B Note: The default keymap defines the "Multi_key" keysym as the "Compose" key. If your keyboard lacks such a key, you may set up your own "Compose" key with ! a keymap that maps some other keysym onto the "Compose" action. .SH "APL SUPPORT" .B x3270 supports an Proper fix for the problem with the nulling-out behavior of PT orders. Versions 1.2 through 3.0.1.1 did it too often; v3.0.1.2 didn't do it at all. [Identified by a number of people; primary help from Ilia Levi.] *** 3270.h.orig Wed Nov 17 14:04:44 1993 --- 3270.h Wed Nov 17 14:04:45 1993 *************** *** 45,50 **** --- 45,60 ---- #define ORDER_GE 0x08 /* graphic escape */ #define ORDER_YALE 0x2B /* Yale sub command */ + #define FCORDER_NULL 0x00 /* format control: null */ + #define FCORDER_SUB 0x3F /* substitute */ + #define FCORDER_DUP 0x1C /* duplicate */ + #define FCORDER_FM 0x1E /* field mark */ + #define FCORDER_FF 0x0C /* form feed */ + #define FCORDER_CR 0x0D /* carriage return */ + #define FCORDER_NL 0x15 /* new line */ + #define FCORDER_EM 0x19 /* end of medium */ + #define FCORDER_EO 0xFF /* eight ones */ + #define fCHAR_WIDTH(f) ((f)->max_bounds.width) #define CHAR_WIDTH fCHAR_WIDTH(*efontinfo) #define fCHAR_HEIGHT(f) ((f)->ascent + (f)->descent) *** kybd.c.orig Wed Nov 17 14:04:50 1993 --- kybd.c Wed Nov 17 14:04:52 1993 *************** *** 85,114 **** /* - * Find the next unprotected field. Returns the address following the - * unprotected attribute byte, or 0 if no nonzero-width unprotected field - * can be found. - */ - static int - next_unprotected(baddr0) - int baddr0; - { - register int baddr, nbaddr; - - nbaddr = baddr0; - do { - baddr = nbaddr; - INC_BA(nbaddr); - if (IS_FA(screen_buf[baddr]) && - !FA_IS_PROTECTED(screen_buf[baddr]) && - !IS_FA(screen_buf[nbaddr])) - return nbaddr; - } while (nbaddr != baddr0); - return 0; - } - - - /* * Handle an AID (Attention IDentifier) key. This is the common stuff that * gets executed for all AID keys (PFs, PAs, Clear and etc). */ --- 85,90 ---- *** globals.h.orig Wed Nov 17 14:04:56 1993 --- globals.h Wed Nov 17 14:04:57 1993 *************** *** 181,186 **** --- 181,187 ---- extern unsigned char *get_field_attribute(); extern void mdt_clear(); extern void mdt_set(); + extern int next_unprotected(); extern int process_ds(); extern void ps_process(); extern void ps_set(); *** ctlr.c.orig Wed Nov 17 14:05:02 1993 --- ctlr.c Wed Nov 17 14:05:03 1993 *************** *** 166,171 **** --- 166,191 ---- { static char buf[8]; + switch (ch) { + case FCORDER_NULL: + return "NULL"; + case FCORDER_SUB: + return "SUB"; + case FCORDER_DUP: + return "DUP"; + case FCORDER_FM: + return "FM"; + case FCORDER_FF: + return "FF"; + case FCORDER_CR: + return "CR"; + case FCORDER_NL: + return "NL"; + case FCORDER_EM: + return "EM"; + case FCORDER_EO: + return "EO"; + } if (ebc2asc[ch]) (void) sprintf(buf, "%c", ebc2asc[ch]); else *************** *** 230,235 **** --- 250,278 ---- } /* + * Find the next unprotected field. Returns the address following the + * unprotected attribute byte, or 0 if no nonzero-width unprotected field + * can be found. + */ + int + next_unprotected(baddr0) + int baddr0; + { + register int baddr, nbaddr; + + nbaddr = baddr0; + do { + baddr = nbaddr; + INC_BA(nbaddr); + if (IS_FA(screen_buf[baddr]) && + !FA_IS_PROTECTED(screen_buf[baddr]) && + !IS_FA(screen_buf[nbaddr])) + return nbaddr; + } while (nbaddr != baddr0); + return 0; + } + + /* * Perform an erase command, which may include changing the (virtual) screen * size. */ *************** *** 337,343 **** { switch (code) { case AID_NO: ! return "None?"; case AID_ENTER: return "Enter"; case AID_PF1: --- 380,386 ---- { switch (code) { case AID_NO: ! return "NoAID"; case AID_ENTER: return "Enter"; case AID_PF1: *************** *** 601,618 **** (void) printf("'"); (void) printf(" SF%s%s", rcba(baddr), see_attr(fa)); } ! last_fa = False; ! } ! else { *obptr++ = cg2ebc[screen_buf[baddr]]; if (toggled(TRACE3270)) { ! if (last_fa) ! (void) printf(" '"); } - if (toggled(TRACE3270)) - (void) printf("%s", see_ebc(cg2ebc[screen_buf[baddr]])); - last_fa = False; } INC_BA(baddr); } while (baddr != 0); --- 644,670 ---- (void) printf("'"); (void) printf(" SF%s%s", rcba(baddr), see_attr(fa)); + last_fa = True; } ! } else { *obptr++ = cg2ebc[screen_buf[baddr]]; if (toggled(TRACE3270)) { ! if (cg2ebc[screen_buf[baddr]] <= 0x3f || ! cg2ebc[screen_buf[baddr]] == 0xff) { ! if (!last_fa) ! (void) printf("'"); ! ! (void) printf(" %s", ! see_ebc(cg2ebc[screen_buf[baddr]])); ! last_fa = True; ! } else { ! if (last_fa) ! (void) printf(" '"); ! (void) printf("%s", ! see_ebc(cg2ebc[screen_buf[baddr]])); ! last_fa = False; ! } } } INC_BA(baddr); } while (baddr != 0); *************** *** 692,697 **** --- 744,750 ---- unsigned char *current_fa; unsigned char new_attr; Boolean last_cmd; + Boolean last_zpt; Boolean wcc_keyboard_restore, wcc_sound_alarm; unsigned char temp_aid2; char paren = '('; *************** *** 731,744 **** (void) printf(")"); last_cmd = True; current_fa = get_field_attribute(buffer_addr); for (cp = &buf[2]; cp < (buf + buflen); cp++) { switch (*cp) { - case ORDER_GE: /* graphic escape - ignore */ - if (toggled(TRACE3270)) - END_TEXT("GE"); - last_cmd = True; - break; case ORDER_SF: /* start field */ if (toggled(TRACE3270)) { END_TEXT("SF"); --- 784,793 ---- (void) printf(")"); last_cmd = True; + last_zpt = False; current_fa = get_field_attribute(buffer_addr); for (cp = &buf[2]; cp < (buf + buflen); cp++) { switch (*cp) { case ORDER_SF: /* start field */ if (toggled(TRACE3270)) { END_TEXT("SF"); *************** *** 760,765 **** --- 809,815 ---- formatted = True; INC_BA(buffer_addr); last_cmd = True; + last_zpt = False; break; case ORDER_SBA: /* set buffer address */ cp += 2; /* skip buffer address */ *************** *** 774,779 **** --- 824,830 ---- } current_fa = get_field_attribute(buffer_addr); last_cmd = True; + last_zpt = False; break; case ORDER_IC: /* insert cursor */ if (toggled(TRACE3270)) *************** *** 780,820 **** END_TEXT("IC"); cursor_move(buffer_addr); last_cmd = True; break; case ORDER_PT: /* program tab */ if (toggled(TRACE3270)) END_TEXT("PT"); ! baddr = buffer_addr; ! while (True) { ! if (IS_FA(screen_buf[baddr]) ! && (!FA_IS_PROTECTED(screen_buf[baddr]))) { ! current_fa = &screen_buf[baddr]; ! INC_BA(baddr); ! buffer_addr = baddr; ! #ifdef notdef ! /* ! * Under certain conditions, PT is ! * supposed to null out the field, ! * but these ain't them. ! */ ! if (!last_cmd) { ! while (!IS_FA(screen_buf[baddr])) { ! ctlr_add(baddr, CG_NULLBLANK); ! INC_BA(baddr); ! } ! } ! #endif ! break; } ! else { ! INC_BA(baddr); ! if (baddr == 0) { ! buffer_addr = baddr; ! current_fa = get_field_attribute(baddr); ! break; ! } ! } ! } last_cmd = True; break; case ORDER_RA: /* repeat to address */ --- 831,863 ---- END_TEXT("IC"); cursor_move(buffer_addr); last_cmd = True; + last_zpt = False; break; case ORDER_PT: /* program tab */ if (toggled(TRACE3270)) END_TEXT("PT"); ! baddr = next_unprotected(buffer_addr); ! if (baddr < buffer_addr) ! baddr = 0; ! /* ! * Null out the remainder of the current field -- even ! * if protected -- if the PT doesn't follow a command ! * or order, or (honestly) if the last order we saw was ! * a null-filling PT that left the buffer address at 0. ! */ ! if (!last_cmd || last_zpt) { ! if (toggled(TRACE3270)) ! (void) printf("(nulling)"); ! while ((buffer_addr != baddr) && ! (!IS_FA(screen_buf[buffer_addr]))) { ! ctlr_add(buffer_addr, CG_NULLBLANK); ! INC_BA(buffer_addr); } ! if (baddr == 0) ! last_zpt = True; ! } else ! last_zpt = False; ! buffer_addr = baddr; last_cmd = True; break; case ORDER_RA: /* repeat to address */ *************** *** 842,847 **** --- 885,891 ---- } current_fa = get_field_attribute(buffer_addr); last_cmd = True; + last_zpt = False; break; case ORDER_EUA: /* erase unprotected to address */ cp += 2; /* skip buffer address */ *************** *** 864,886 **** } while (buffer_addr != baddr); current_fa = get_field_attribute(buffer_addr); last_cmd = True; break; case ORDER_MF: /* modify field */ if (toggled(TRACE3270)) ! (void) printf(" MF"); ! /* unsupported 3270 order */ break; case ORDER_SFE: /* start field extended */ if (toggled(TRACE3270)) ! (void) printf(" SFE"); ! /* unsupported 3270 order */ break; case ORDER_SA: /* set attribute */ if (toggled(TRACE3270)) ! (void) printf(" SA"); ! /* unsupported 3270 order */ break; default: /* enter character */ if (toggled(TRACE3270)) { START_TEXT; (void) printf("%s", see_ebc(*cp)); --- 908,969 ---- } while (buffer_addr != baddr); current_fa = get_field_attribute(buffer_addr); last_cmd = True; + last_zpt = False; break; + case ORDER_GE: /* graphic escape */ + if (toggled(TRACE3270)) + END_TEXT("GE[unsupported]"); + cp++; + last_cmd = True; + last_zpt = False; + break; case ORDER_MF: /* modify field */ if (toggled(TRACE3270)) ! END_TEXT("MF[unsupported]"); ! cp += *(cp + 1) * 2; ! last_cmd = True; ! last_zpt = False; break; case ORDER_SFE: /* start field extended */ if (toggled(TRACE3270)) ! END_TEXT("SFE[unsupported]"); ! cp += *(cp + 1) * 2; ! last_cmd = True; ! last_zpt = False; break; case ORDER_SA: /* set attribute */ if (toggled(TRACE3270)) ! END_TEXT("SA[unsupported]"); ! cp += 2; ! last_cmd = True; ! last_zpt = False; break; + case FCORDER_NULL: /* format control orders */ + case FCORDER_SUB: + case FCORDER_DUP: + case FCORDER_FM: + case FCORDER_FF: + case FCORDER_CR: + case FCORDER_NL: + case FCORDER_EM: + case FCORDER_EO: + if (toggled(TRACE3270)) + END_TEXT(see_ebc(*cp)); + ctlr_add(buffer_addr, ebc2cg[*cp]); + INC_BA(buffer_addr); + last_cmd = True; + last_zpt = False; + break; default: /* enter character */ + if (*cp <= 0x3F) { + if (toggled(TRACE3270)) { + END_TEXT("ILLEGAL_ORDER"); + (void) printf("%s", see_ebc(*cp)); + } + last_cmd = True; + last_zpt = False; + break; + } if (toggled(TRACE3270)) { START_TEXT; (void) printf("%s", see_ebc(*cp)); *************** *** 888,893 **** --- 971,977 ---- ctlr_add(buffer_addr, ebc2cg[*cp]); INC_BA(buffer_addr); last_cmd = False; + last_zpt = False; break; } } Filter the output of the "Trace 3270 DS" option so it doesn't generate huge lines. *** ctlr.c.orig Wed Nov 17 14:10:20 1993 --- ctlr.c Wed Nov 17 14:10:21 1993 *************** *** 61,66 **** --- 61,67 ---- static void do_read_buffer(); static void do_erase_all_unprotected(); static void do_write(); + static void trace_ds(); /* code_table is used to translate buffer addresses and attributes to the 3270 * datastream representation *************** *** 313,363 **** unsigned char *buf; int buflen; { ! if (toggled(TRACE3270)) ! (void) printf("< "); switch (buf[0]) { /* 3270 command */ case CMD_EAU: /* erase all unprotected */ case SNA_CMD_EAU: ! if (toggled(TRACE3270)) ! (void) printf("EAU\n"); do_erase_all_unprotected(); break; case CMD_EWA: /* erase/write alternate */ case SNA_CMD_EWA: ! if (toggled(TRACE3270)) ! (void) printf("EWA"); ctlr_erase(True); do_write(buf, buflen); break; case CMD_EW: /* erase/write */ case SNA_CMD_EW: ! if (toggled(TRACE3270)) ! (void) printf("EW"); ctlr_erase(False); do_write(buf, buflen); break; case CMD_W: /* write */ case SNA_CMD_W: ! if (toggled(TRACE3270)) ! (void) printf("W"); do_write(buf, buflen); break; case CMD_RB: /* read buffer */ case SNA_CMD_RB: ! if (toggled(TRACE3270)) ! (void) printf("RB\n"); do_read_buffer(); break; case CMD_RM: /* read modifed */ case SNA_CMD_RM: ! if (toggled(TRACE3270)) ! (void) printf("RM\n"); ctlr_read_modified(); break; case CMD_NOP: /* no-op */ ! if (toggled(TRACE3270)) ! (void) printf("NOP\n"); break; default: { /* unknown 3270 command */ --- 314,356 ---- unsigned char *buf; int buflen; { ! trace_ds("< "); switch (buf[0]) { /* 3270 command */ case CMD_EAU: /* erase all unprotected */ case SNA_CMD_EAU: ! trace_ds("EAU\n"); do_erase_all_unprotected(); break; case CMD_EWA: /* erase/write alternate */ case SNA_CMD_EWA: ! trace_ds("EWA"); ctlr_erase(True); do_write(buf, buflen); break; case CMD_EW: /* erase/write */ case SNA_CMD_EW: ! trace_ds("EW"); ctlr_erase(False); do_write(buf, buflen); break; case CMD_W: /* write */ case SNA_CMD_W: ! trace_ds("W"); do_write(buf, buflen); break; case CMD_RB: /* read buffer */ case SNA_CMD_RB: ! trace_ds("RB\n"); do_read_buffer(); break; case CMD_RM: /* read modifed */ case SNA_CMD_RM: ! trace_ds("RM\n"); ctlr_read_modified(); break; case CMD_NOP: /* no-op */ ! trace_ds("NOP\n"); break; default: { /* unknown 3270 command */ *************** *** 461,468 **** { register int baddr, sbaddr; ! if (toggled(TRACE3270)) ! (void) printf("> "); obptr = &obuf[0]; if (aid != AID_PA1 && aid != AID_PA2 && aid != AID_PA3 && aid != AID_CLEAR) { --- 454,460 ---- { register int baddr, sbaddr; ! trace_ds("> "); obptr = &obuf[0]; if (aid != AID_PA1 && aid != AID_PA2 && aid != AID_PA3 && aid != AID_CLEAR) { *************** *** 471,486 **** *obptr++ = 0x5B; /* % */ *obptr++ = 0x61; /* / */ *obptr++ = 0x02; /* stx */ ! if (toggled(TRACE3270)) ! (void) printf("SYSREQ"); } else { *obptr++ = aid; *obptr++ = code_table[(cursor_addr >> 6) & 0x3F]; *obptr++ = code_table[cursor_addr & 0x3F]; ! if (toggled(TRACE3270)) ! (void) printf("%s%s", see_aid(aid), ! rcba(cursor_addr)); } baddr = 0; if (formatted) { --- 463,476 ---- *obptr++ = 0x5B; /* % */ *obptr++ = 0x61; /* / */ *obptr++ = 0x02; /* stx */ ! trace_ds("SYSREQ"); } else { *obptr++ = aid; *obptr++ = code_table[(cursor_addr >> 6) & 0x3F]; *obptr++ = code_table[cursor_addr & 0x3F]; ! trace_ds(see_aid(aid)); ! trace_ds(rcba(cursor_addr)); } baddr = 0; if (formatted) { *************** *** 499,521 **** *obptr++ = ORDER_SBA; *obptr++ = code_table[(baddr >> 6) & 0x3F]; *obptr++ = code_table[baddr & 0x3F]; ! if (toggled(TRACE3270)) ! (void) printf(" SBA%s", ! rcba(baddr)); do { if (screen_buf[baddr]) { *obptr++ = cg2ebc[screen_buf[baddr]]; ! if (toggled(TRACE3270)) { ! if (!any) ! (void) printf(" '"); ! (void) printf("%s", see_ebc(cg2ebc[screen_buf[baddr]])); ! } any = True; } INC_BA(baddr); } while (!IS_FA(screen_buf[baddr])); ! if (toggled(TRACE3270) && any) ! (void) printf("'"); } else { /* not modified - skip */ do { --- 489,508 ---- *obptr++ = ORDER_SBA; *obptr++ = code_table[(baddr >> 6) & 0x3F]; *obptr++ = code_table[baddr & 0x3F]; ! trace_ds(" SBA"); ! trace_ds(rcba(baddr)); do { if (screen_buf[baddr]) { *obptr++ = cg2ebc[screen_buf[baddr]]; ! if (!any) ! trace_ds(" '"); ! trace_ds(see_ebc(cg2ebc[screen_buf[baddr]])); any = True; } INC_BA(baddr); } while (!IS_FA(screen_buf[baddr])); ! if (any) ! trace_ds("'"); } else { /* not modified - skip */ do { *************** *** 530,555 **** do { if (screen_buf[baddr]) { *obptr++ = cg2ebc[screen_buf[baddr]]; ! if (toggled(TRACE3270)) { ! if (!any) ! (void) printf("'"); ! (void) printf("%s", see_ebc(cg2ebc[screen_buf[baddr]])); ! } any = True; } INC_BA(baddr); } while (baddr != 0); ! if (toggled(TRACE3270) && any) ! (void) printf("'"); } } else { *obptr++ = aid; ! if (toggled(TRACE3270)) ! (void) printf("%s", see_aid(aid)); } ! if (toggled(TRACE3270)) ! (void) printf("\n"); net_output(obuf, obptr - obuf); } --- 517,538 ---- do { if (screen_buf[baddr]) { *obptr++ = cg2ebc[screen_buf[baddr]]; ! if (!any) ! trace_ds("'"); ! trace_ds(see_ebc(cg2ebc[screen_buf[baddr]])); any = True; } INC_BA(baddr); } while (baddr != 0); ! if (any) ! trace_ds("'"); } } else { *obptr++ = aid; ! trace_ds(see_aid(aid)); } ! trace_ds("\n"); net_output(obuf, obptr - obuf); } *************** *** 618,631 **** unsigned char fa; Boolean last_fa = True; ! if (toggled(TRACE3270)) ! (void) printf("> "); obptr = &obuf[0]; *obptr++ = aid; *obptr++ = code_table[(cursor_addr >> 6) & 0x3F]; *obptr++ = code_table[cursor_addr & 0x3F]; ! if (toggled(TRACE3270)) ! (void) printf("%s%s", see_aid(aid), rcba(cursor_addr)); baddr = 0; do { if (IS_FA(screen_buf[baddr])) { --- 601,613 ---- unsigned char fa; Boolean last_fa = True; ! trace_ds("> "); obptr = &obuf[0]; *obptr++ = aid; *obptr++ = code_table[(cursor_addr >> 6) & 0x3F]; *obptr++ = code_table[cursor_addr & 0x3F]; ! trace_ds(see_aid(aid)); ! trace_ds(rcba(cursor_addr)); baddr = 0; do { if (IS_FA(screen_buf[baddr])) { *************** *** 639,678 **** fa |= 0x01; fa |= ((screen_buf[baddr] & FA_INTENSITY) << 2); *obptr++ = code_table[fa]; ! if (toggled(TRACE3270)) { ! if (!last_fa) ! (void) printf("'"); ! (void) printf(" SF%s%s", rcba(baddr), ! see_attr(fa)); ! last_fa = True; ! } } else { *obptr++ = cg2ebc[screen_buf[baddr]]; ! if (toggled(TRACE3270)) { ! if (cg2ebc[screen_buf[baddr]] <= 0x3f || ! cg2ebc[screen_buf[baddr]] == 0xff) { ! if (!last_fa) ! (void) printf("'"); ! (void) printf(" %s", ! see_ebc(cg2ebc[screen_buf[baddr]])); ! last_fa = True; ! } else { ! if (last_fa) ! (void) printf(" '"); ! (void) printf("%s", ! see_ebc(cg2ebc[screen_buf[baddr]])); ! last_fa = False; ! } } } INC_BA(baddr); } while (baddr != 0); ! if (toggled(TRACE3270)) { ! if (!last_fa) ! (void) printf("'"); ! (void) printf("\n"); ! } net_output(obuf, obptr - obuf); } --- 621,654 ---- fa |= 0x01; fa |= ((screen_buf[baddr] & FA_INTENSITY) << 2); *obptr++ = code_table[fa]; ! if (!last_fa) ! trace_ds("'"); ! trace_ds(" SF"); ! trace_ds(rcba(baddr)); ! trace_ds(see_attr(fa)); ! last_fa = True; } else { *obptr++ = cg2ebc[screen_buf[baddr]]; ! if (cg2ebc[screen_buf[baddr]] <= 0x3f || ! cg2ebc[screen_buf[baddr]] == 0xff) { ! if (!last_fa) ! trace_ds("'"); ! trace_ds(" "); ! trace_ds(see_ebc(cg2ebc[screen_buf[baddr]])); ! last_fa = True; ! } else { ! if (last_fa) ! trace_ds(" '"); ! trace_ds(see_ebc(cg2ebc[screen_buf[baddr]])); ! last_fa = False; } } INC_BA(baddr); } while (baddr != 0); ! if (!last_fa) ! trace_ds("'"); ! trace_ds("\n"); net_output(obuf, obptr - obuf); } *************** *** 747,776 **** Boolean last_zpt; Boolean wcc_keyboard_restore, wcc_sound_alarm; unsigned char temp_aid2; ! char paren = '('; ! #define START_TEXT { if (last_cmd) (void) printf(" '"); } ! #define END_TEXT(cmd) { if (!last_cmd) (void) printf("'"); if (cmd) (void) printf(" %s", cmd); } buffer_addr = cursor_addr; wcc_sound_alarm = WCC_SOUND_ALARM(buf[1]); ! if (toggled(TRACE3270) && wcc_sound_alarm) { ! (void) printf("%calarm", paren); ! paren = ','; } wcc_keyboard_restore = WCC_KEYBOARD_RESTORE(buf[1]); if (wcc_keyboard_restore) ticking_stop(); ! if (toggled(TRACE3270) && wcc_keyboard_restore) { ! (void) printf("%crestore", paren); ! paren = ','; } if (WCC_RESET_MDT(buf[1])) { ! if (toggled(TRACE3270)) { ! (void) printf("%cresetMDT", paren); ! paren = ','; ! } baddr = 0; screen_changed = True; do { --- 723,754 ---- Boolean last_zpt; Boolean wcc_keyboard_restore, wcc_sound_alarm; unsigned char temp_aid2; ! char *paren = "("; ! #define START_TEXT { if (last_cmd) trace_ds(" '"); } ! #define END_TEXT(cmd) { if (!last_cmd) trace_ds("'"); \ ! if (cmd) { trace_ds(" "); trace_ds(cmd); } } buffer_addr = cursor_addr; wcc_sound_alarm = WCC_SOUND_ALARM(buf[1]); ! if (wcc_sound_alarm) { ! trace_ds(paren); ! trace_ds("alarm"); ! paren = ","; } wcc_keyboard_restore = WCC_KEYBOARD_RESTORE(buf[1]); if (wcc_keyboard_restore) ticking_stop(); ! if (wcc_keyboard_restore) { ! trace_ds(paren); ! trace_ds("restore"); ! paren = ","; } if (WCC_RESET_MDT(buf[1])) { ! trace_ds(paren); ! trace_ds("resetMDT"); ! paren = ","; baddr = 0; screen_changed = True; do { *************** *** 780,787 **** INC_BA(baddr); } while (baddr != 0); } ! if (toggled(TRACE3270) && paren != '(') ! (void) printf(")"); last_cmd = True; last_zpt = False; --- 758,765 ---- INC_BA(baddr); } while (baddr != 0); } ! if (strcmp(paren, "(")) ! trace_ds(")"); last_cmd = True; last_zpt = False; *************** *** 789,798 **** for (cp = &buf[2]; cp < (buf + buflen); cp++) { switch (*cp) { case ORDER_SF: /* start field */ ! if (toggled(TRACE3270)) { ! END_TEXT("SF"); ! (void) printf("%s", rcba(buffer_addr)); ! } cp++; /* skip field attribute */ new_attr = FA_BASE; if (*cp & 0x20) --- 767,774 ---- for (cp = &buf[2]; cp < (buf + buflen); cp++) { switch (*cp) { case ORDER_SF: /* start field */ ! END_TEXT("SF"); ! trace_ds(rcba(buffer_addr)); cp++; /* skip field attribute */ new_attr = FA_BASE; if (*cp & 0x20) *************** *** 804,811 **** new_attr |= (*cp >> 2) & FA_INTENSITY; current_fa = &(screen_buf[buffer_addr]); ctlr_add(buffer_addr, new_attr); ! if (toggled(TRACE3270)) ! (void) printf("%s", see_attr(new_attr)); formatted = True; INC_BA(buffer_addr); last_cmd = True; --- 780,786 ---- new_attr |= (*cp >> 2) & FA_INTENSITY; current_fa = &(screen_buf[buffer_addr]); ctlr_add(buffer_addr, new_attr); ! trace_ds(see_attr(new_attr)); formatted = True; INC_BA(buffer_addr); last_cmd = True; *************** *** 818,841 **** else /* 12-bit coded */ buffer_addr = ((*(cp-1) & 0x3F) << 6) | (*cp & 0x3F); buffer_addr %= (COLS * ROWS); ! if (toggled(TRACE3270)) { ! END_TEXT("SBA"); ! (void) printf("%s", rcba(buffer_addr)); ! } current_fa = get_field_attribute(buffer_addr); last_cmd = True; last_zpt = False; break; case ORDER_IC: /* insert cursor */ ! if (toggled(TRACE3270)) ! END_TEXT("IC"); cursor_move(buffer_addr); last_cmd = True; last_zpt = False; break; case ORDER_PT: /* program tab */ ! if (toggled(TRACE3270)) ! END_TEXT("PT"); baddr = next_unprotected(buffer_addr); if (baddr < buffer_addr) baddr = 0; --- 793,812 ---- else /* 12-bit coded */ buffer_addr = ((*(cp-1) & 0x3F) << 6) | (*cp & 0x3F); buffer_addr %= (COLS * ROWS); ! END_TEXT("SBA"); ! trace_ds(rcba(buffer_addr)); current_fa = get_field_attribute(buffer_addr); last_cmd = True; last_zpt = False; break; case ORDER_IC: /* insert cursor */ ! END_TEXT("IC"); cursor_move(buffer_addr); last_cmd = True; last_zpt = False; break; case ORDER_PT: /* program tab */ ! END_TEXT("PT"); baddr = next_unprotected(buffer_addr); if (baddr < buffer_addr) baddr = 0; *************** *** 846,853 **** * a null-filling PT that left the buffer address at 0. */ if (!last_cmd || last_zpt) { ! if (toggled(TRACE3270)) ! (void) printf("(nulling)"); while ((buffer_addr != baddr) && (!IS_FA(screen_buf[buffer_addr]))) { ctlr_add(buffer_addr, CG_NULLBLANK); --- 817,823 ---- * a null-filling PT that left the buffer address at 0. */ if (!last_cmd || last_zpt) { ! trace_ds("(nulling)"); while ((buffer_addr != baddr) && (!IS_FA(screen_buf[buffer_addr]))) { ctlr_add(buffer_addr, CG_NULLBLANK); *************** *** 870,880 **** cp++; /* skip char to repeat */ if (*cp == ORDER_GE) cp++; ! if (toggled(TRACE3270)) { ! END_TEXT("RA"); ! (void) printf("%s'%s'", rcba(baddr), ! see_ebc(*cp)); ! } if (buffer_addr == baddr) { ctlr_add(buffer_addr, ebc2cg[*cp]); INC_BA(buffer_addr); --- 840,850 ---- cp++; /* skip char to repeat */ if (*cp == ORDER_GE) cp++; ! END_TEXT("RA"); ! trace_ds(rcba(baddr)); ! trace_ds("'"); ! trace_ds(see_ebc(*cp)); ! trace_ds("'"); if (buffer_addr == baddr) { ctlr_add(buffer_addr, ebc2cg[*cp]); INC_BA(buffer_addr); *************** *** 894,903 **** else /* 12-bit coded */ baddr = ((*(cp-1) & 0x3F) << 6) | (*cp & 0x3F); baddr %= (COLS * ROWS); ! if (toggled(TRACE3270)) { ! END_TEXT("EUA"); ! (void) printf("%s", rcba(baddr)); ! } do { if (IS_FA(screen_buf[buffer_addr])) current_fa = &(screen_buf[buffer_addr]); --- 864,871 ---- else /* 12-bit coded */ baddr = ((*(cp-1) & 0x3F) << 6) | (*cp & 0x3F); baddr %= (COLS * ROWS); ! END_TEXT("EUA"); ! trace_ds(rcba(baddr)); do { if (IS_FA(screen_buf[buffer_addr])) current_fa = &(screen_buf[buffer_addr]); *************** *** 911,939 **** last_zpt = False; break; case ORDER_GE: /* graphic escape */ ! if (toggled(TRACE3270)) ! END_TEXT("GE[unsupported]"); cp++; last_cmd = True; last_zpt = False; break; case ORDER_MF: /* modify field */ ! if (toggled(TRACE3270)) ! END_TEXT("MF[unsupported]"); cp += *(cp + 1) * 2; last_cmd = True; last_zpt = False; break; case ORDER_SFE: /* start field extended */ ! if (toggled(TRACE3270)) ! END_TEXT("SFE[unsupported]"); cp += *(cp + 1) * 2; last_cmd = True; last_zpt = False; break; case ORDER_SA: /* set attribute */ ! if (toggled(TRACE3270)) ! END_TEXT("SA[unsupported]"); cp += 2; last_cmd = True; last_zpt = False; --- 879,903 ---- last_zpt = False; break; case ORDER_GE: /* graphic escape */ ! END_TEXT("GE[unsupported]"); cp++; last_cmd = True; last_zpt = False; break; case ORDER_MF: /* modify field */ ! END_TEXT("MF[unsupported]"); cp += *(cp + 1) * 2; last_cmd = True; last_zpt = False; break; case ORDER_SFE: /* start field extended */ ! END_TEXT("SFE[unsupported]"); cp += *(cp + 1) * 2; last_cmd = True; last_zpt = False; break; case ORDER_SA: /* set attribute */ ! END_TEXT("SA[unsupported]"); cp += 2; last_cmd = True; last_zpt = False; *************** *** 947,954 **** case FCORDER_NL: case FCORDER_EM: case FCORDER_EO: ! if (toggled(TRACE3270)) ! END_TEXT(see_ebc(*cp)); ctlr_add(buffer_addr, ebc2cg[*cp]); INC_BA(buffer_addr); last_cmd = True; --- 911,917 ---- case FCORDER_NL: case FCORDER_EM: case FCORDER_EO: ! END_TEXT(see_ebc(*cp)); ctlr_add(buffer_addr, ebc2cg[*cp]); INC_BA(buffer_addr); last_cmd = True; *************** *** 956,973 **** break; default: /* enter character */ if (*cp <= 0x3F) { ! if (toggled(TRACE3270)) { ! END_TEXT("ILLEGAL_ORDER"); ! (void) printf("%s", see_ebc(*cp)); ! } last_cmd = True; last_zpt = False; break; } ! if (toggled(TRACE3270)) { ! START_TEXT; ! (void) printf("%s", see_ebc(*cp)); ! } ctlr_add(buffer_addr, ebc2cg[*cp]); INC_BA(buffer_addr); last_cmd = False; --- 919,932 ---- break; default: /* enter character */ if (*cp <= 0x3F) { ! END_TEXT("ILLEGAL_ORDER"); ! trace_ds(see_ebc(*cp)); last_cmd = True; last_zpt = False; break; } ! START_TEXT; ! trace_ds(see_ebc(*cp)); ctlr_add(buffer_addr, ebc2cg[*cp]); INC_BA(buffer_addr); last_cmd = False; *************** *** 976,985 **** } } set_formatted(); ! if (toggled(TRACE3270)) { ! END_TEXT((char *)0); ! (void) printf("\n"); ! } if (wcc_keyboard_restore) { aid = AID_NO; if (oia_locked) { --- 935,942 ---- } } set_formatted(); ! END_TEXT((char *)0); ! trace_ds("\n"); if (wcc_keyboard_restore) { aid = AID_NO; if (oia_locked) { *************** *** 1285,1288 **** --- 1242,1283 ---- void toggle_nop() { + } + + + /* + * 3270 Data Stream Tracing + */ + static int dscnt = 0; + + static void + trace_ds(s) + char *s; + { + int len = strlen(s); + Boolean nl = False; + + if (!toggled(TRACE3270)) + return; + + if (s && s[len-1] == '\n') { + len--; + nl = True; + } + while (dscnt + len >= 72) { + int plen = 72-dscnt; + + (void) printf("%.*s ...\n... ", plen, s); + dscnt = 4; + s += plen; + len -= plen; + } + if (len) { + (void) printf("%.*s", len, s); + dscnt += len; + } + if (nl) { + (void) printf("\n"); + dscnt = 0; + } } Up the program version number to 3.0.1.3, but no need to change the app-defaults version. *** x3270.c.orig Wed Nov 17 14:35:56 1993 --- x3270.c Wed Nov 17 14:35:57 1993 *************** *** 27,33 **** /* Externals */ extern int n_read; ! extern char *version; /* Globals */ Display *display; --- 27,33 ---- /* Externals */ extern int n_read; ! extern char *app_defaults_version; /* Globals */ Display *display; *************** *** 243,251 **** XtError("Outdated app-defaults file"); else if (!strcmp(appres.ad_version, "fallback")) XtError("No app-defaults file"); ! else if (strcmp(appres.ad_version, version)) { char *msg = xs_buffer2("app-defaults version mismatch: want %s, got %s", ! version, appres.ad_version); XtError(msg); } --- 243,251 ---- XtError("Outdated app-defaults file"); else if (!strcmp(appres.ad_version, "fallback")) XtError("No app-defaults file"); ! else if (strcmp(appres.ad_version, app_defaults_version)) { char *msg = xs_buffer2("app-defaults version mismatch: want %s, got %s", ! app_defaults_version, appres.ad_version); XtError(msg); } *** version.txt.orig Wed Nov 17 14:36:02 1993 --- version.txt Wed Nov 17 14:36:02 1993 *************** *** 1 **** ! 3.0.1.2 --- 1,2 ---- ! char *version = "3.0.1.3"; ! char *app_defaults_version = "3.0.1.2"; *** popups.c.orig Wed Nov 17 14:36:06 1993 --- popups.c Wed Nov 17 14:36:07 1993 *************** *** 476,481 **** --- 476,482 ---- extern int ns_bsent; extern int ns_rsent; extern int linemode; + extern char *version; extern char *build; extern char ttype_val[]; extern Pixmap icon; *************** *** 616,625 **** /* Miscellany */ (void) XtVaCreateManagedWidget( "build", labelWidgetClass, options_form, XtNborderWidth, 0, ! XtNlabel, build, XtNfromHoriz, w, XtNleft, XtChainLeft, NULL); --- 617,627 ---- /* Miscellany */ + sprintf(fbuf, "x3270 v%s, %s", version, build); (void) XtVaCreateManagedWidget( "build", labelWidgetClass, options_form, XtNborderWidth, 0, ! XtNlabel, fbuf, XtNfromHoriz, w, XtNleft, XtChainLeft, NULL); *** Imakefile.orig Wed Nov 17 14:36:10 1993 --- Imakefile Wed Nov 17 14:36:11 1993 *************** *** 26,32 **** FontTarget(3270ab) version.o: $(VOBJS) version.txt ! @echo "char *build = \"x3270 v`cat version.txt`, `date`\"; char *version = \"`cat version.txt`\";" >version.c @$(CC) -c version.c @$(RM) version.c --- 26,32 ---- FontTarget(3270ab) version.o: $(VOBJS) version.txt ! @(cat version.txt; echo "char *build = \"`date`\";") >version.c @$(CC) -c version.c @$(RM) version.c *** Makefile.aux.orig Wed Nov 17 14:36:14 1993 --- Makefile.aux Wed Nov 17 14:36:15 1993 *************** *** 85,91 **** @$(RM) version.o version.o: $(OBJECTS) version.txt ! @echo "char *build = \"x3270 v`cat version.txt`, `date`\"; char *version = \"`cat version.txt`\";" >version.c @$(CC) -c version.c @$(RM) version.c --- 85,91 ---- @$(RM) version.o version.o: $(OBJECTS) version.txt ! @(cat version.txt; echo "char *build = \"`date`\";") >version.c @$(CC) -c version.c @$(RM) version.c Correct the handling of illegal buffer addresses. *** ctlr.c.orig Mon Nov 29 16:15:07 1993 --- ctlr.c Mon Nov 29 16:15:08 1993 *************** *** 792,800 **** buffer_addr = ((*(cp-1) & 0x3F) << 8) | *cp; else /* 12-bit coded */ buffer_addr = ((*(cp-1) & 0x3F) << 6) | (*cp & 0x3F); - buffer_addr %= (COLS * ROWS); END_TEXT("SBA"); trace_ds(rcba(buffer_addr)); current_fa = get_field_attribute(buffer_addr); last_cmd = True; last_zpt = False; --- 792,803 ---- buffer_addr = ((*(cp-1) & 0x3F) << 8) | *cp; else /* 12-bit coded */ buffer_addr = ((*(cp-1) & 0x3F) << 6) | (*cp & 0x3F); END_TEXT("SBA"); trace_ds(rcba(buffer_addr)); + if (buffer_addr >= COLS * ROWS) { + trace_ds(" [invalid address, write command terminated]\n"); + return; + } current_fa = get_field_attribute(buffer_addr); last_cmd = True; last_zpt = False; *************** *** 836,842 **** baddr = ((*(cp-1) & 0x3F) << 8) | *cp; else /* 12-bit coded */ baddr = ((*(cp-1) & 0x3F) << 6) | (*cp & 0x3F); - baddr %= (COLS * ROWS); cp++; /* skip char to repeat */ if (*cp == ORDER_GE) cp++; --- 839,844 ---- *************** *** 845,858 **** trace_ds("'"); trace_ds(see_ebc(*cp)); trace_ds("'"); ! if (buffer_addr == baddr) { ! ctlr_add(buffer_addr, ebc2cg[*cp]); ! INC_BA(buffer_addr); } ! while (buffer_addr != baddr) { ctlr_add(buffer_addr, ebc2cg[*cp]); INC_BA(buffer_addr); ! } current_fa = get_field_attribute(buffer_addr); last_cmd = True; last_zpt = False; --- 847,860 ---- trace_ds("'"); trace_ds(see_ebc(*cp)); trace_ds("'"); ! if (baddr >= COLS * ROWS) { ! trace_ds(" [invalid address, write command terminated]\n"); ! return; } ! do { ctlr_add(buffer_addr, ebc2cg[*cp]); INC_BA(buffer_addr); ! } while (buffer_addr != baddr); current_fa = get_field_attribute(buffer_addr); last_cmd = True; last_zpt = False; *************** *** 863,871 **** baddr = ((*(cp-1) & 0x3F) << 8) | *cp; else /* 12-bit coded */ baddr = ((*(cp-1) & 0x3F) << 6) | (*cp & 0x3F); - baddr %= (COLS * ROWS); END_TEXT("EUA"); trace_ds(rcba(baddr)); do { if (IS_FA(screen_buf[buffer_addr])) current_fa = &(screen_buf[buffer_addr]); --- 865,876 ---- baddr = ((*(cp-1) & 0x3F) << 8) | *cp; else /* 12-bit coded */ baddr = ((*(cp-1) & 0x3F) << 6) | (*cp & 0x3F); END_TEXT("EUA"); trace_ds(rcba(baddr)); + if (baddr >= COLS * ROWS) { + trace_ds(" [invalid address, write command terminated]\n"); + return; + } do { if (IS_FA(screen_buf[buffer_addr])) current_fa = &(screen_buf[buffer_addr]); README changes. *** README.3.0.orig Mon Nov 29 16:27:09 1993 --- README.3.0 Mon Nov 29 16:27:10 1993 *************** *** 1,4 **** ! x3270 3.0.1.2 -- (Version 3.0, Update 1, Patch Set 2) =============================================================================== 0. Introduction --- 1,4 ---- ! x3270 3.0.1.3 -- (Version 3.0, Update 1, Patch Set 3) =============================================================================== 0. Introduction *************** *** 20,38 **** x3270 (cut and paste, hollowing cursor, etc.) and a number of significant changes and improvements. ! Thanks to -- ! Robert Viduya, for the original SunView 3270tool; ! Jeff Sparkes, for the original X port and for inspiring so many of us to ! improve on it; ! Peter Johnston, for insisting that each new function he wanted was just an ! itty bitty change, honest; ! Thomas Vogler, for requesting the original ASCII functionality and helping ! debug it; ! Pekka Nikander, for helpful advice in internationalization and X trivia, ! and yet more porting and debug help; ! Distinguished bug hunters: David Summers, Ian Daniel, Kevin Murphy, George ! Pallas; ! and everyone else who has put up with my naive stumblings through X. 1. Enhancements from Release 1.2 --- 20,29 ---- x3270 (cut and paste, hollowing cursor, etc.) and a number of significant changes and improvements. ! Despite its name, x3270 3.0 is a separate line of development from other ! versions of x3270, most notably v1.2-cutpaste-iso8859-1, and v2.65. Patches ! for those versions will not apply to x3270 3.0, and some of the features found ! in those versions may not yet be in v3.0. 1. Enhancements from Release 1.2 *************** *** 436,441 **** --- 427,460 ---- xmkmf (or without one that works). ow3.install Install x3270 in /usr/openwin. + + 5.9 Bug Fixes in Patch Set 3 (v3.0.1.3) + + Fixed typo which most compilers let pass. [Reported by Marc Morin.] + + Fixed EWOULDBLOCK can't-ever-happen which apparently did. [Reported by Marc + Morin.] + + Fixed an error in the response to the READ BUFFER command, which wasn't + properly encoding attribute bytes. [Reported by Eric M. Boehm.] + + Fixed OpenWindows font targets in Makefile.aux. [Fixed by Raymond A. Wiker.] + + Fixed a typo in X3270.ad. [Found by Eric M. Boehm.] + + Fixed a spelling error in x3270.man. + + Properly fixed the problem with the nulling-out behavior of PT orders. + Versions 1.2 through 3.0.1.1 did it too often; v3.0.1.2 didn't do it at all. + [Identified by a number of people; primary help from Ilia Levi.] + + Corrected the handling of illegal buffer addresses. [Reported by Soren B. + Poulsen.] + + 5.10 Enhancements in Patch Set 3 (v3.0.1.3) + + Filter the output of the "Trace 3270 DS" option so it doesn't generate huge + lines. =====