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