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

Revision 9081, 17.7 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 * Copyright 1993, 1994, 1995 by Paul Mattes.
3 *   Permission to use, copy, modify, and distribute this software and its
4 *   documentation for any purpose and without fee is hereby granted,
5 *   provided that the above copyright notice appear in all copies and that
6 *   both that copyright notice and this permission notice appear in
7 *   supporting documentation.
8 */
9
10/*
11 *      trace_ds.c
12 *              3270 data stream tracing.
13 *
14 */
15
16#include "globals.h"
17#include <X11/StringDefs.h>
18#include <X11/Xaw/Dialog.h>
19#include <errno.h>
20#include <signal.h>
21#include <time.h>
22#if defined(__STDC__)
23#include <stdarg.h>
24#else
25#include <varargs.h>
26#endif
27#include <fcntl.h>
28#include "3270ds.h"
29#include "appres.h"
30#include "resources.h"
31#include "ctlr.h"
32
33#include "ctlrc.h"
34#include "menubarc.h"
35#include "popupsc.h"
36#include "printc.h"
37#include "savec.h"
38#include "tablesc.h"
39#include "telnetc.h"
40#include "trace_dsc.h"
41#include "utilc.h"
42
43/* Externals */
44extern char    *build;
45
46/* Statics */
47static int      dscnt = 0;
48static int      tracewindow_pid = -1;
49
50/* Globals */
51FILE           *tracef = (FILE *) 0;
52struct timeval  ds_ts;
53Boolean         trace_skipping = False;
54
55char *
56unknown(value)
57unsigned char value;
58{
59        static char buf[64];
60
61        (void) sprintf(buf, "unknown[0x%x]", value);
62        return buf;
63}
64
65/* display a (row,col) */
66char *
67rcba(baddr)
68int baddr;
69{
70        static char buf[16];
71
72        (void) sprintf(buf, "(%d,%d)", baddr/COLS + 1, baddr%COLS + 1);
73        return buf;
74}
75
76char *
77see_ebc(ch)
78unsigned char ch;
79{
80        static char buf[8];
81
82        switch (ch) {
83            case FCORDER_NULL:
84                return "NULL";
85            case FCORDER_SUB:
86                return "SUB";
87            case FCORDER_DUP:
88                return "DUP";
89            case FCORDER_FM:
90                return "FM";
91            case FCORDER_FF:
92                return "FF";
93            case FCORDER_CR:
94                return "CR";
95            case FCORDER_NL:
96                return "NL";
97            case FCORDER_EM:
98                return "EM";
99            case FCORDER_EO:
100                return "EO";
101        }
102        if (ebc2asc[ch])
103                (void) sprintf(buf, "%c", ebc2asc[ch]);
104        else
105                (void) sprintf(buf, "\\%o", ch);
106        return buf;
107}
108
109char *
110see_aid(code)
111unsigned char code;
112{
113        switch (code) {
114        case AID_NO:
115                return "NoAID";
116        case AID_ENTER:
117                return "Enter";
118        case AID_PF1:
119                return "PF1";
120        case AID_PF2:
121                return "PF2";
122        case AID_PF3:
123                return "PF3";
124        case AID_PF4:
125                return "PF4";
126        case AID_PF5:
127                return "PF5";
128        case AID_PF6:
129                return "PF6";
130        case AID_PF7:
131                return "PF7";
132        case AID_PF8:
133                return "PF8";
134        case AID_PF9:
135                return "PF9";
136        case AID_PF10:
137                return "PF10";
138        case AID_PF11:
139                return "PF11";
140        case AID_PF12:
141                return "PF12";
142        case AID_PF13:
143                return "PF13";
144        case AID_PF14:
145                return "PF14";
146        case AID_PF15:
147                return "PF15";
148        case AID_PF16:
149                return "PF16";
150        case AID_PF17:
151                return "PF17";
152        case AID_PF18:
153                return "PF18";
154        case AID_PF19:
155                return "PF19";
156        case AID_PF20:
157                return "PF20";
158        case AID_PF21:
159                return "PF21";
160        case AID_PF22:
161                return "PF22";
162        case AID_PF23:
163                return "PF23";
164        case AID_PF24:
165                return "PF24";
166        case AID_OICR:
167                return "OICR";
168        case AID_MSR_MHS:
169                return "MSR_MHS";
170        case AID_SELECT:
171                return "Select";
172        case AID_PA1:
173                return "PA1";
174        case AID_PA2:
175                return "PA2";
176        case AID_PA3:
177                return "PA3";
178        case AID_CLEAR:
179                return "Clear";
180        case AID_SYSREQ:
181                return "SysReq";
182        case AID_QREPLY:
183                return "QueryReplyAID";
184        default:
185                return unknown(code);
186        }
187}
188
189char *
190see_attr(fa)
191unsigned char fa;
192{
193        static char buf[256];
194        char *paren = "(";
195
196        buf[0] = '\0';
197
198        if (fa & 0x04) {
199                (void) strcat(buf, paren);
200                (void) strcat(buf, "protected");
201                paren = ",";
202                if (fa & 0x08) {
203                        (void) strcat(buf, paren);
204                        (void) strcat(buf, "skip");
205                        paren = ",";
206                }
207        } else if (fa & 0x08) {
208                (void) strcat(buf, paren);
209                (void) strcat(buf, "numeric");
210                paren = ",";
211        }
212        switch (fa & 0x03) {
213        case 0:
214                break;
215        case 1:
216                (void) strcat(buf, paren);
217                (void) strcat(buf, "detectable");
218                paren = ",";
219                break;
220        case 2:
221                (void) strcat(buf, paren);
222                (void) strcat(buf, "intensified");
223                paren = ",";
224                break;
225        case 3:
226                (void) strcat(buf, paren);
227                (void) strcat(buf, "nondisplay");
228                paren = ",";
229                break;
230        }
231        if (fa & 0x20) {
232                (void) strcat(buf, paren);
233                (void) strcat(buf, "modified");
234                paren = ",";
235        }
236        if (strcmp(paren, "("))
237                (void) strcat(buf, ")");
238        else
239                (void) strcpy(buf, "(default)");
240
241        return buf;
242}
243
244static char *
245see_highlight(setting)
246unsigned char setting;
247{
248        switch (setting) {
249            case XAH_DEFAULT:
250                return "default";
251            case XAH_NORMAL:
252                return "normal";
253            case XAH_BLINK:
254                return "blink";
255            case XAH_REVERSE:
256                return "reverse";
257            case XAH_UNDERSCORE:
258                return "underscore";
259            case XAH_INTENSIFY:
260                return "intensify";
261            default:
262                return unknown(setting);
263        }
264}
265
266char *
267see_color(setting)
268unsigned char setting;
269{
270        static char *color_name[] = {
271            "neutralBlack",
272            "blue",
273            "red",
274            "pink",
275            "green",
276            "turquoise",
277            "yellow",
278            "neutralWhite",
279            "black",
280            "deepBlue",
281            "orange",
282            "purple",
283            "paleGreen",
284            "paleTurquoise",
285            "grey",
286            "white"
287        };
288
289        if (setting == XAC_DEFAULT)
290                return "default";
291        else if (setting < 0xf0 || setting > 0xff)
292                return unknown(setting);
293        else
294                return color_name[setting - 0xf0];
295}
296
297static char *
298see_transparency(setting)
299unsigned char setting;
300{
301        switch (setting) {
302            case XAT_DEFAULT:
303                return "default";
304            case XAT_OR:
305                return "or";
306            case XAT_XOR:
307                return "xor";
308            case XAT_OPAQUE:
309                return "opaque";
310            default:
311                return unknown(setting);
312        }
313}
314
315static char *
316see_validation(setting)
317unsigned char setting;
318{
319        static char buf[64];
320        char *paren = "(";
321
322        (void) strcpy(buf, "");
323        if (setting & XAV_FILL) {
324                (void) strcat(buf, paren);
325                (void) strcat(buf, "fill");
326                paren = ",";
327        }
328        if (setting & XAV_ENTRY) {
329                (void) strcat(buf, paren);
330                (void) strcat(buf, "entry");
331                paren = ",";
332        }
333        if (setting & XAV_TRIGGER) {
334                (void) strcat(buf, paren);
335                (void) strcat(buf, "trigger");
336                paren = ",";
337        }
338        if (strcmp(paren, "("))
339                (void) strcat(buf, ")");
340        else
341                (void) strcpy(buf, "(none)");
342        return buf;
343}
344
345static char *
346see_outline(setting)
347unsigned char setting;
348{
349        static char buf[64];
350        char *paren = "(";
351
352        (void) strcpy(buf, "");
353        if (setting & XAO_UNDERLINE) {
354                (void) strcat(buf, paren);
355                (void) strcat(buf, "underline");
356                paren = ",";
357        }
358        if (setting & XAO_RIGHT) {
359                (void) strcat(buf, paren);
360                (void) strcat(buf, "right");
361                paren = ",";
362        }
363        if (setting & XAO_OVERLINE) {
364                (void) strcat(buf, paren);
365                (void) strcat(buf, "overline");
366                paren = ",";
367        }
368        if (setting & XAO_LEFT) {
369                (void) strcat(buf, paren);
370                (void) strcat(buf, "left");
371                paren = ",";
372        }
373        if (strcmp(paren, "("))
374                (void) strcat(buf, ")");
375        else
376                (void) strcpy(buf, "(none)");
377        return buf;
378}
379
380char *
381see_efa(efa, value)
382unsigned char efa;
383unsigned char value;
384{
385        static char buf[64];
386
387        switch (efa) {
388            case XA_ALL:
389                (void) sprintf(buf, " all(%x)", value);
390                break;
391            case XA_3270:
392                (void) sprintf(buf, " 3270%s", see_attr(value));
393                break;
394            case XA_VALIDATION:
395                (void) sprintf(buf, " validation%s", see_validation(value));
396                break;
397            case XA_OUTLINING:
398                (void) sprintf(buf, " outlining(%s)", see_outline(value));
399                break;
400            case XA_HIGHLIGHTING:
401                (void) sprintf(buf, " highlighting(%s)", see_highlight(value));
402                break;
403            case XA_FOREGROUND:
404                (void) sprintf(buf, " foreground(%s)", see_color(value));
405                break;
406            case XA_CHARSET:
407                (void) sprintf(buf, " charset(%x)", value);
408                break;
409            case XA_BACKGROUND:
410                (void) sprintf(buf, " background(%s)", see_color(value));
411                break;
412            case XA_TRANSPARENCY:
413                (void) sprintf(buf, " transparency(%s)", see_transparency(value));
414                break;
415            default:
416                (void) sprintf(buf, " %s[0x%x]", unknown(efa), value);
417        }
418        return buf;
419}
420
421char *
422see_efa_only(efa)
423unsigned char efa;
424{
425        switch (efa) {
426            case XA_ALL:
427                return "all";
428            case XA_3270:
429                return "3270";
430            case XA_VALIDATION:
431                return "validation";
432            case XA_OUTLINING:
433                return "outlining";
434            case XA_HIGHLIGHTING:
435                return "highlighting";
436            case XA_FOREGROUND:
437                return "foreground";
438            case XA_CHARSET:
439                return "charset";
440            case XA_BACKGROUND:
441                return "background";
442            case XA_TRANSPARENCY:
443                return "transparency";
444            default:
445                return unknown(efa);
446        }
447}
448
449char *
450see_qcode(id)
451unsigned char id;
452{
453        static char buf[64];
454
455        switch (id) {
456            case QR_CHARSETS:
457                return "CharacterSets";
458            case QR_IMP_PART:
459                return "ImplicitPartition";
460            case QR_SUMMARY:
461                return "Summary";
462            case QR_USABLE_AREA:
463                return "UsableArea";
464            case QR_COLOR:
465                return "Color";
466            case QR_HIGHLIGHTING:
467                return "Highlighting";
468            case QR_REPLY_MODES:
469                return "ReplyModes";
470            case QR_ALPHA_PART:
471                return "AlphanumericPartitions";
472            case QR_DDM:
473                return "DistributedDataManagement";
474            default:
475                (void) sprintf(buf, "unknown[0x%x]", id);
476                return buf;
477        }
478}
479
480/* Data Stream trace print, handles line wraps */
481
482static char tdsbuf[4096];
483#define TDS_LEN 75
484
485static void
486trace_ds_s(s)
487char *s;
488{
489        int len = strlen(s);
490        Boolean nl = False;
491
492        if (!toggled(DS_TRACE))
493                return;
494
495        if (s && s[len-1] == '\n') {
496                len--;
497                nl = True;
498        }
499        while (dscnt + len >= 75) {
500                int plen = 75-dscnt;
501
502                (void) fprintf(tracef, "%.*s ...\n... ", plen, s);
503                dscnt = 4;
504                s += plen;
505                len -= plen;
506        }
507        if (len) {
508                (void) fprintf(tracef, "%.*s", len, s);
509                dscnt += len;
510        }
511        if (nl) {
512                (void) fprintf(tracef, "\n");
513                dscnt = 0;
514        }
515}
516
517#if defined(__STDC__)
518void
519trace_ds(char *fmt, ...)
520#else
521void
522trace_ds(va_alist)
523va_dcl
524#endif
525{
526        va_list args;
527
528#if defined(__STDC__)
529        va_start(args, fmt);
530#else
531        char *fmt;
532        va_start(args);
533        fmt = va_arg(args, char *);
534#endif
535        /* print out remainder of message */
536        (void) vsprintf(tdsbuf, fmt, args);
537        trace_ds_s(tdsbuf);
538        va_end(args);
539}
540
541static Widget trace_shell = (Widget)NULL;
542static int trace_reason;
543
544/* Callback for "OK" button on trace popup */
545/*ARGSUSED*/
546static void
547tracefile_callback(w, client_data, call_data)
548Widget w;
549XtPointer client_data;
550XtPointer call_data;
551{
552        char *tfn;
553        char *tracecmd;
554        char *full_cmd;
555        long clock;
556        extern char *command_string;
557        extern int children;
558
559        if (w)
560                tfn = XawDialogGetValueString((Widget)client_data);
561        else
562                tfn = (char *)client_data;
563        tfn = do_subst(tfn, True, True);
564        if (strchr(tfn, '\'') ||
565            ((int)strlen(tfn) > 0 && tfn[strlen(tfn)-1] == '\\')) {
566                popup_an_error("Illegal file name: %s\n", tfn);
567                XtFree(tfn);
568                return;
569        }
570        tracef = fopen(tfn, "a");
571        if (tracef == (FILE *)NULL) {
572                popup_an_errno(errno, tfn);
573                XtFree(tfn);
574                return;
575        }
576        (void) SETLINEBUF(tracef);
577        (void) fcntl(fileno(tracef), F_SETFD, 1);
578
579        /* Display current status */
580        clock = time((long *)0);
581        (void) fprintf(tracef, "Trace started %s", ctime(&clock));
582        (void) fprintf(tracef, " Version: %s\n", build);
583        save_yourself();
584        (void) fprintf(tracef, " Command: %s\n", command_string);
585        (void) fprintf(tracef, " Model %s", model_name);
586        (void) fprintf(tracef, ", %s display",
587            appres.mono ? "monochrome" : "color");
588        if (appres.extended)
589                (void) fprintf(tracef, ", extended data stream");
590        if (!appres.mono)
591                (void) fprintf(tracef, ", %scolor",
592                    appres.m3279 ? "full " : "pseudo-");
593        if (appres.charset)
594                (void) fprintf(tracef, ", %s charset", appres.charset);
595        if (appres.apl_mode)
596                (void) fprintf(tracef, ", APL mode");
597        (void) fprintf(tracef, "\n");
598        if (CONNECTED)
599                (void) fprintf(tracef, " Connected to %s, port %u\n",
600                    current_host, current_port);
601
602        /* Start the monitor window */
603        tracecmd = get_resource(ResTraceCommand);
604        if (!tracecmd || !strcmp(tracecmd, "none"))
605                goto done;
606        switch (tracewindow_pid = fork()) {
607            case 0:     /* child process */
608                full_cmd = xs_buffer("%s <'%s'", tracecmd, tfn);
609                (void) execlp("xterm", "xterm", "-title", tfn,
610                    "-sb", "-e", "/bin/sh", "-c", full_cmd, CN);
611                (void) perror("exec(xterm)");
612                _exit(1);
613            default:    /* parent */
614                ++children;
615                break;
616            case -1:    /* error */
617                popup_an_errno(errno, "fork()");
618                break;
619        }
620
621    done:
622        XtFree(tfn);
623
624        /* We're really tracing, turn the flag on. */
625        appres.toggle[trace_reason].value = True;
626        appres.toggle[trace_reason].changed = True;
627        menubar_retoggle(&appres.toggle[trace_reason]);
628
629        if (w)
630                XtPopdown(trace_shell);
631
632        /* Snap the current TELNET options. */
633        if (net_snap_options()) {
634                (void) fprintf(tracef, " TELNET state:\n");
635                trace_netdata('<', obuf, obptr - obuf);
636        }
637
638        /* Dump the screen contents and modes into the trace file. */
639        if (CONNECTED && formatted) {
640                (void) fprintf(tracef, " Screen contents:\n");
641                ctlr_snap_buffer();
642                space3270out(2);
643                net_add_eor(obuf, obptr - obuf);
644                obptr += 2;
645                trace_netdata('<', obuf, obptr - obuf);
646        }
647        if (CONNECTED && ctlr_snap_modes()) {
648                (void) fprintf(tracef, " 3270 modes:\n");
649                space3270out(2);
650                net_add_eor(obuf, obptr - obuf);
651                obptr += 2;
652                trace_netdata('<', obuf, obptr - obuf);
653        }
654
655        (void) fprintf(tracef, " Data stream:\n");
656}
657
658/* Open the trace file. */
659static void
660tracefile_on(reason, tt)
661int reason;
662enum toggle_type tt;
663{
664        char tracefile[256];
665
666        if (tracef)
667                return;
668
669        (void) sprintf(tracefile, "%s/x3trc.%d", appres.trace_dir,
670                getpid());
671        trace_reason = reason;
672        if (tt == TT_INITIAL) {
673                tracefile_callback((Widget)NULL, tracefile, PN);
674                return;
675        }
676        if (trace_shell == NULL) {
677                trace_shell = create_form_popup("trace",
678                    tracefile_callback, (XtCallbackProc)NULL, True);
679                XtVaSetValues(XtNameToWidget(trace_shell, "dialog"),
680                    XtNvalue, tracefile,
681                    NULL);
682        }
683
684        /* Turn the toggle _off_ until the popup succeeds. */
685        appres.toggle[reason].value = False;
686        appres.toggle[reason].changed = True;
687
688        popup_popup(trace_shell, XtGrabExclusive);
689}
690
691/* Close the trace file. */
692static void
693tracefile_off()
694{
695        long clock;
696
697        clock = time((long *)0);
698        (void) fprintf(tracef, "Trace stopped %s", ctime(&clock));
699        if (tracewindow_pid != -1)
700                (void) kill(tracewindow_pid, SIGTERM);
701        tracewindow_pid = -1;
702        (void) fclose(tracef);
703        tracef = (FILE *) NULL;
704}
705
706/*ARGSUSED*/
707void
708toggle_dsTrace(t, tt)
709struct toggle *t;
710enum toggle_type tt;
711{
712        /* If turning on trace and no trace file, open one. */
713        if (toggled(DS_TRACE) && !tracef)
714                tracefile_on(DS_TRACE, tt);
715
716        /* If turning off trace and not still tracing events, close the
717           trace file. */
718        else if (!toggled(DS_TRACE) && !toggled(EVENT_TRACE))
719                tracefile_off();
720
721        if (toggled(DS_TRACE))
722                (void) gettimeofday(&ds_ts, (struct timezone *)NULL);
723}
724
725/*ARGSUSED*/
726void
727toggle_eventTrace(t, tt)
728struct toggle *t;
729enum toggle_type tt;
730{
731        /* If turning on event debug, and no trace file, open one. */
732        if (toggled(EVENT_TRACE) && !tracef)
733                tracefile_on(EVENT_TRACE, tt);
734
735        /* If turning off event debug, and not tracing the data stream,
736           close the trace file. */
737        else if (!toggled(EVENT_TRACE) && !toggled(DS_TRACE))
738                tracefile_off();
739}
740
741/* Screen trace file support. */
742
743static Widget screentrace_shell = (Widget)NULL;
744static FILE *screentracef = (FILE *)0;
745
746/*
747 * Screen trace function, called when the host clears the screen.
748 */
749static void
750do_screentrace()
751{
752        register int i;
753
754        if (fprint_screen(screentracef, False)) {
755                for (i = 0; i < COLS; i++)
756                        (void) fputc('=', screentracef);
757                (void) fputc('\n', screentracef);
758        }
759}
760
761void
762trace_screen()
763{
764        trace_skipping = False;
765
766        if (!toggled(SCREEN_TRACE) | !screentracef)
767                return;
768        do_screentrace();
769}
770
771/* Called from ANSI emulation code to log a single character. */
772void
773trace_char(c)
774char c;
775{
776        if (!toggled(SCREEN_TRACE) | !screentracef)
777                return;
778        (void) fputc(c, screentracef);
779}
780
781/*
782 * Called when disconnecting in ANSI mode, to finish off the trace file
783 * and keep the next screen clear from re-recording the screen image.
784 * (In a gross violation of data hiding and modularity, trace_skipping is
785 * manipulated directly in ctlr_clear()).
786 */
787void
788trace_ansi_disc()
789{
790        int i;
791
792        (void) fputc('\n', screentracef);
793        for (i = 0; i < COLS; i++)
794                (void) fputc('=', screentracef);
795        (void) fputc('\n', screentracef);
796
797        trace_skipping = True;
798}
799
800/* Callback for "OK" button on screentrace popup */
801/*ARGSUSED*/
802static void
803screentrace_callback(w, client_data, call_data)
804Widget w;
805XtPointer client_data;
806XtPointer call_data;
807{
808        char *tfn;
809
810        if (w)
811                tfn = XawDialogGetValueString((Widget)client_data);
812        else
813                tfn = (char *)client_data;
814        tfn = do_subst(tfn, True, True);
815        screentracef = fopen(tfn, "a");
816        if (screentracef == (FILE *)NULL) {
817                popup_an_errno(errno, tfn);
818                XtFree(tfn);
819                return;
820        }
821        XtFree(tfn);
822        (void) SETLINEBUF(screentracef);
823        (void) fcntl(fileno(screentracef), F_SETFD, 1);
824
825        /* We're really tracing, turn the flag on. */
826        appres.toggle[SCREEN_TRACE].value = True;
827        appres.toggle[SCREEN_TRACE].changed = True;
828        menubar_retoggle(&appres.toggle[SCREEN_TRACE]);
829
830        if (w)
831                XtPopdown(screentrace_shell);
832}
833
834/* Callback for second "OK" button on screentrace popup */
835/*ARGSUSED*/
836static void
837onescreen_callback(w, client_data, call_data)
838Widget w;
839XtPointer client_data;
840XtPointer call_data;
841{
842        char *tfn;
843
844        if (w)
845                tfn = XawDialogGetValueString((Widget)client_data);
846        else
847                tfn = (char *)client_data;
848        tfn = do_subst(tfn, True, True);
849        screentracef = fopen(tfn, "a");
850        if (screentracef == (FILE *)NULL) {
851                popup_an_errno(errno, tfn);
852                XtFree(tfn);
853                return;
854        }
855        (void) fcntl(fileno(screentracef), F_SETFD, 1);
856        XtFree(tfn);
857
858        /* Save the current image, once. */
859        do_screentrace();
860
861        /* Close the file, we're done. */
862        (void) fclose(screentracef);
863        screentracef = (FILE *)NULL;
864
865        if (w)
866                XtPopdown(screentrace_shell);
867}
868
869/*ARGSUSED*/
870void
871toggle_screenTrace(t, tt)
872struct toggle *t;
873enum toggle_type tt;
874{
875        char tracefile[256];
876
877        if (toggled(SCREEN_TRACE)) {
878                (void) sprintf(tracefile, "%s/x3scr.%d", appres.trace_dir,
879                        getpid());
880                if (tt == TT_INITIAL) {
881                        screentrace_callback((Widget)NULL, tracefile, PN);
882                        return;
883                }
884                if (screentrace_shell == NULL) {
885                        screentrace_shell = create_form_popup("screentrace",
886                            screentrace_callback, onescreen_callback, True);
887                        XtVaSetValues(XtNameToWidget(screentrace_shell, "dialog"),
888                            XtNvalue, tracefile,
889                            NULL);
890                }
891                appres.toggle[SCREEN_TRACE].value = False;
892                appres.toggle[SCREEN_TRACE].changed = True;
893                popup_popup(screentrace_shell, XtGrabExclusive);
894        } else {
895                if (ctlr_any_data() && !trace_skipping)
896                        do_screentrace();
897                (void) fclose(screentracef);
898        }
899}
Note: See TracBrowser for help on using the repository browser.