xref: /dragonfly/contrib/dialog/trace.c (revision ec1c3f3a)
1 /*
2  *  $Id: trace.c,v 1.34 2022/04/03 22:38:16 tom Exp $
3  *
4  *  trace.c -- implements screen-dump and keystroke-logging
5  *
6  *  Copyright 2007-2020,2022	Thomas E. Dickey
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU Lesser General Public License, version 2.1
10  *  as published by the Free Software Foundation.
11  *
12  *  This program is distributed in the hope that it will be useful, but
13  *  WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  *  Lesser General Public License for more details.
16  *
17  *  You should have received a copy of the GNU Lesser General Public
18  *  License along with this program; if not, write to
19  *	Free Software Foundation, Inc.
20  *	51 Franklin St., Fifth Floor
21  *	Boston, MA 02110, USA.
22  */
23 
24 #include <dlg_internals.h>
25 
26 #ifdef HAVE_DLG_TRACE
27 
28 #include <dlg_keys.h>
29 
30 #define myFP dialog_state.trace_output
31 
32 static void
33 dlg_trace_time(const char *tag)
34 {
35     time_t now = time((time_t *) 0);
36     fprintf(myFP, "%s %s", tag, ctime(&now));
37 }
38 
39 void
40 dlg_trace_msg(const char *fmt, ...)
41 {
42     if (myFP != 0) {
43 	va_list ap;
44 	va_start(ap, fmt);
45 	vfprintf(myFP, fmt, ap);
46 	va_end(ap);
47 	fflush(myFP);
48     }
49 }
50 
51 void
52 dlg_trace_va_msg(const char *fmt, va_list ap)
53 {
54     if (myFP != 0) {
55 	vfprintf(myFP, fmt, ap);
56 	fflush(myFP);
57     }
58 }
59 
60 void
61 dlg_trace_2s(const char *name, const char *value)
62 {
63     bool first = TRUE;
64     int left, right = 0;
65 
66     if (value == 0)
67 	value = "<NULL>";
68 
69     while (value[right] != '\0') {
70 	const char *next;
71 
72 	value += right;
73 	if ((next = strchr(value, '\n')) != 0) {
74 	    left = (int) (next - value);
75 	    right = left + 1;
76 	} else {
77 	    left = (int) strlen(value);
78 	    right = left;
79 	}
80 	if (first) {
81 	    first = FALSE;
82 	    dlg_trace_msg("#%14s = %.*s\n", name, left, value);
83 	} else {
84 	    dlg_trace_msg("#+%13s%.*s\n", " ", left, value);
85 	}
86     }
87 }
88 
89 void
90 dlg_trace_2n(const char *name, int value)
91 {
92     dlg_trace_msg("#%14s = %d\n", name, value);
93 }
94 
95 void
96 dlg_trace_win(WINDOW *win)
97 {
98     if (myFP != 0) {
99 	WINDOW *top = wgetparent(win);
100 
101 	while (top != 0 && top != stdscr) {
102 	    win = top;
103 	    top = wgetparent(win);
104 	}
105 
106 	if (win != 0) {
107 	    int rc = getmaxy(win);
108 	    int cc = getmaxx(win);
109 	    chtype ch, c2;
110 	    int y, x;
111 	    int j, k;
112 
113 	    fprintf(myFP, "window %dx%d at %d,%d\n",
114 		    rc, cc, getbegy(win), getbegx(win));
115 
116 	    getyx(win, y, x);
117 	    for (j = 0; j < rc; ++j) {
118 		fprintf(myFP, "%3d:", j);
119 		for (k = 0; k < cc; ++k) {
120 #ifdef USE_WIDE_CURSES
121 		    char buffer[80];
122 
123 		    ch = mvwinch(win, j, k) & (A_CHARTEXT | A_ALTCHARSET);
124 		    if (ch & A_ALTCHARSET) {
125 			c2 = dlg_asciibox(ch);
126 			if (c2 != 0) {
127 			    ch = c2;
128 			}
129 			buffer[0] = (char) ch;
130 			buffer[1] = '\0';
131 		    } else {
132 			cchar_t cch;
133 			const wchar_t *uc;
134 
135 			if (win_wch(win, &cch) == ERR
136 			    || (uc = wunctrl((&cch))) == 0
137 			    || uc[1] != 0
138 			    || wcwidth(uc[0]) <= 0) {
139 			    buffer[0] = '.';
140 			    buffer[1] = '\0';
141 			} else {
142 			    mbstate_t state;
143 			    const wchar_t *ucp = uc;
144 
145 			    memset(&state, 0, sizeof(state));
146 			    wcsrtombs(buffer, &ucp, sizeof(buffer), &state);
147 			    k += wcwidth(uc[0]) - 1;
148 			}
149 		    }
150 		    fputs(buffer, myFP);
151 #else
152 		    ch = mvwinch(win, j, k) & (A_CHARTEXT | A_ALTCHARSET);
153 		    c2 = dlg_asciibox(ch);
154 		    if (c2 != 0) {
155 			ch = c2;
156 		    } else if (unctrl(ch) == 0 || strlen(unctrl(ch)) > 1) {
157 			ch = '.';
158 		    }
159 		    fputc((int) (ch & 0xff), myFP);
160 #endif
161 		}
162 		fputc('\n', myFP);
163 	    }
164 	    wmove(win, y, x);
165 	    fflush(myFP);
166 	}
167     }
168 }
169 
170 void
171 dlg_trace_chr(int ch, int fkey)
172 {
173     static int last_err = 0;
174 
175     /*
176      * Do not bother to trace ERR's indefinitely, since those are usually due
177      * to relatively short polling timeouts.
178      */
179     if (last_err && !fkey && ch == ERR) {
180 	++last_err;
181     } else if (myFP != 0) {
182 	const char *fkey_name = "?";
183 
184 	if (last_err) {
185 	    fprintf(myFP, "skipped %d ERR's\n", last_err);
186 	    last_err = 0;
187 	}
188 
189 	if (fkey) {
190 	    if (fkey > KEY_MAX || (fkey_name = keyname(fkey)) == 0) {
191 #define CASE(name) case name: fkey_name = #name; break
192 		switch ((DLG_KEYS_ENUM) fkey) {
193 		    CASE(DLGK_MIN);
194 		    CASE(DLGK_OK);
195 		    CASE(DLGK_CANCEL);
196 		    CASE(DLGK_EXTRA);
197 		    CASE(DLGK_HELP);
198 		    CASE(DLGK_ESC);
199 		    CASE(DLGK_PAGE_FIRST);
200 		    CASE(DLGK_PAGE_LAST);
201 		    CASE(DLGK_PAGE_NEXT);
202 		    CASE(DLGK_PAGE_PREV);
203 		    CASE(DLGK_ITEM_FIRST);
204 		    CASE(DLGK_ITEM_LAST);
205 		    CASE(DLGK_ITEM_NEXT);
206 		    CASE(DLGK_ITEM_PREV);
207 		    CASE(DLGK_FIELD_FIRST);
208 		    CASE(DLGK_FIELD_LAST);
209 		    CASE(DLGK_FIELD_NEXT);
210 		    CASE(DLGK_FIELD_PREV);
211 		    CASE(DLGK_FORM_FIRST);
212 		    CASE(DLGK_FORM_LAST);
213 		    CASE(DLGK_FORM_NEXT);
214 		    CASE(DLGK_FORM_PREV);
215 		    CASE(DLGK_GRID_UP);
216 		    CASE(DLGK_GRID_DOWN);
217 		    CASE(DLGK_GRID_LEFT);
218 		    CASE(DLGK_GRID_RIGHT);
219 		    CASE(DLGK_DELETE_LEFT);
220 		    CASE(DLGK_DELETE_RIGHT);
221 		    CASE(DLGK_DELETE_ALL);
222 		    CASE(DLGK_ENTER);
223 		    CASE(DLGK_BEGIN);
224 		    CASE(DLGK_FINAL);
225 		    CASE(DLGK_SELECT);
226 		    CASE(DLGK_HELPFILE);
227 		    CASE(DLGK_TRACE);
228 		    CASE(DLGK_TOGGLE);
229 		    CASE(DLGK_LEAVE);
230 		}
231 	    }
232 	} else if (ch == ERR) {
233 	    fkey_name = "ERR";
234 	    last_err = 1;
235 	} else {
236 	    fkey_name = unctrl((chtype) ch);
237 	    if (fkey_name == 0)
238 		fkey_name = "UNKNOWN";
239 	}
240 	if (ch >= 0) {
241 	    fprintf(myFP, "chr %s (ch=%#x, fkey=%d)\n", fkey_name, ch, fkey);
242 	} else {
243 	    fprintf(myFP, "chr %s (ch=%d, fkey=%d)\n", fkey_name, ch, fkey);
244 	}
245 	fflush(myFP);
246     }
247 }
248 
249 void
250 dlg_trace(const char *fname)
251 {
252     if (fname != 0) {
253 	if (myFP == 0) {
254 	    myFP = fopen(fname, "a");
255 	    if (myFP != 0) {
256 		dlg_trace_time("## opened at");
257 		DLG_TRACE(("## dialog %s\n", dialog_version()));
258 		DLG_TRACE(("## vile: confmode\n"));
259 	    }
260 	}
261     } else if (myFP != 0) {
262 	dlg_trace_time("## closed at");
263 	fclose(myFP);
264 	myFP = 0;
265     }
266 }
267 #else
268 #undef dlg_trace
269 extern void dlg_trace(const char *);
270 void
271 dlg_trace(const char *fname)
272 {
273     (void) fname;
274 }
275 #endif
276