14c8945a0SNathan Whitehorn /*
2*a96ef450SBaptiste Daroussin * $Id: trace.c,v 1.33 2020/11/23 23:32:43 tom Exp $
34c8945a0SNathan Whitehorn *
44c8945a0SNathan Whitehorn * trace.c -- implements screen-dump and keystroke-logging
54c8945a0SNathan Whitehorn *
6*a96ef450SBaptiste Daroussin * Copyright 2007-2019,2020 Thomas E. Dickey
74c8945a0SNathan Whitehorn *
84c8945a0SNathan Whitehorn * This program is free software; you can redistribute it and/or modify
94c8945a0SNathan Whitehorn * it under the terms of the GNU Lesser General Public License, version 2.1
10*a96ef450SBaptiste Daroussin * as published by the Free Software Foundation.
114c8945a0SNathan Whitehorn *
124c8945a0SNathan Whitehorn * This program is distributed in the hope that it will be useful, but
134c8945a0SNathan Whitehorn * WITHOUT ANY WARRANTY; without even the implied warranty of
144c8945a0SNathan Whitehorn * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
154c8945a0SNathan Whitehorn * Lesser General Public License for more details.
164c8945a0SNathan Whitehorn *
174c8945a0SNathan Whitehorn * You should have received a copy of the GNU Lesser General Public
184c8945a0SNathan Whitehorn * License along with this program; if not, write to
194c8945a0SNathan Whitehorn * Free Software Foundation, Inc.
204c8945a0SNathan Whitehorn * 51 Franklin St., Fifth Floor
214c8945a0SNathan Whitehorn * Boston, MA 02110, USA.
224c8945a0SNathan Whitehorn */
234c8945a0SNathan Whitehorn
244c8945a0SNathan Whitehorn #include <dialog.h>
254c8945a0SNathan Whitehorn
264c8945a0SNathan Whitehorn #ifdef HAVE_DLG_TRACE
274c8945a0SNathan Whitehorn
282a3e3873SBaptiste Daroussin #ifdef NEED_WCHAR_H
292a3e3873SBaptiste Daroussin #include <wchar.h>
302a3e3873SBaptiste Daroussin #endif
312a3e3873SBaptiste Daroussin
324c8945a0SNathan Whitehorn #include <dlg_keys.h>
334c8945a0SNathan Whitehorn #include <time.h>
344c8945a0SNathan Whitehorn
354c8945a0SNathan Whitehorn #define myFP dialog_state.trace_output
364c8945a0SNathan Whitehorn
377a1c0d96SNathan Whitehorn static void
dlg_trace_time(const char * tag)387a1c0d96SNathan Whitehorn dlg_trace_time(const char *tag)
397a1c0d96SNathan Whitehorn {
407a1c0d96SNathan Whitehorn time_t now = time((time_t *) 0);
417a1c0d96SNathan Whitehorn fprintf(myFP, "%s %s", tag, ctime(&now));
427a1c0d96SNathan Whitehorn }
437a1c0d96SNathan Whitehorn
444c8945a0SNathan Whitehorn void
dlg_trace_msg(const char * fmt,...)454c8945a0SNathan Whitehorn dlg_trace_msg(const char *fmt, ...)
464c8945a0SNathan Whitehorn {
474c8945a0SNathan Whitehorn if (myFP != 0) {
484c8945a0SNathan Whitehorn va_list ap;
494c8945a0SNathan Whitehorn va_start(ap, fmt);
504c8945a0SNathan Whitehorn vfprintf(myFP, fmt, ap);
514c8945a0SNathan Whitehorn va_end(ap);
524c8945a0SNathan Whitehorn fflush(myFP);
534c8945a0SNathan Whitehorn }
544c8945a0SNathan Whitehorn }
554c8945a0SNathan Whitehorn
564c8945a0SNathan Whitehorn void
dlg_trace_va_msg(const char * fmt,va_list ap)57*a96ef450SBaptiste Daroussin dlg_trace_va_msg(const char *fmt, va_list ap)
58*a96ef450SBaptiste Daroussin {
59*a96ef450SBaptiste Daroussin if (myFP != 0) {
60*a96ef450SBaptiste Daroussin vfprintf(myFP, fmt, ap);
61*a96ef450SBaptiste Daroussin fflush(myFP);
62*a96ef450SBaptiste Daroussin }
63*a96ef450SBaptiste Daroussin }
64*a96ef450SBaptiste Daroussin
65*a96ef450SBaptiste Daroussin void
dlg_trace_2s(const char * name,const char * value)66f4f33ea0SBaptiste Daroussin dlg_trace_2s(const char *name, const char *value)
67f4f33ea0SBaptiste Daroussin {
68f4f33ea0SBaptiste Daroussin bool first = TRUE;
69f4f33ea0SBaptiste Daroussin int left, right = 0;
70f4f33ea0SBaptiste Daroussin
71f4f33ea0SBaptiste Daroussin if (value == 0)
72f4f33ea0SBaptiste Daroussin value = "<NULL>";
73f4f33ea0SBaptiste Daroussin
74f4f33ea0SBaptiste Daroussin while (value[right] != '\0') {
75*a96ef450SBaptiste Daroussin const char *next;
76*a96ef450SBaptiste Daroussin
77f4f33ea0SBaptiste Daroussin value += right;
78f4f33ea0SBaptiste Daroussin if ((next = strchr(value, '\n')) != 0) {
79f4f33ea0SBaptiste Daroussin left = (int) (next - value);
80f4f33ea0SBaptiste Daroussin right = left + 1;
81f4f33ea0SBaptiste Daroussin } else {
82f4f33ea0SBaptiste Daroussin left = (int) strlen(value);
83f4f33ea0SBaptiste Daroussin right = left;
84f4f33ea0SBaptiste Daroussin }
85f4f33ea0SBaptiste Daroussin if (first) {
86f4f33ea0SBaptiste Daroussin first = FALSE;
87f4f33ea0SBaptiste Daroussin dlg_trace_msg("#%14s = %.*s\n", name, left, value);
88f4f33ea0SBaptiste Daroussin } else {
89*a96ef450SBaptiste Daroussin dlg_trace_msg("#+%13s%.*s\n", " ", left, value);
90f4f33ea0SBaptiste Daroussin }
91f4f33ea0SBaptiste Daroussin }
92f4f33ea0SBaptiste Daroussin }
93f4f33ea0SBaptiste Daroussin
94f4f33ea0SBaptiste Daroussin void
dlg_trace_2n(const char * name,int value)95f4f33ea0SBaptiste Daroussin dlg_trace_2n(const char *name, int value)
96f4f33ea0SBaptiste Daroussin {
97*a96ef450SBaptiste Daroussin dlg_trace_msg("#%14s = %d\n", name, value);
98f4f33ea0SBaptiste Daroussin }
99f4f33ea0SBaptiste Daroussin
100f4f33ea0SBaptiste Daroussin void
dlg_trace_win(WINDOW * win)1014c8945a0SNathan Whitehorn dlg_trace_win(WINDOW *win)
1024c8945a0SNathan Whitehorn {
1034c8945a0SNathan Whitehorn if (myFP != 0) {
1042a3e3873SBaptiste Daroussin WINDOW *top = wgetparent(win);
1052a3e3873SBaptiste Daroussin
1062a3e3873SBaptiste Daroussin while (top != 0 && top != stdscr) {
1072a3e3873SBaptiste Daroussin win = top;
1082a3e3873SBaptiste Daroussin top = wgetparent(win);
1092a3e3873SBaptiste Daroussin }
1102a3e3873SBaptiste Daroussin
1112a3e3873SBaptiste Daroussin if (win != 0) {
1124c8945a0SNathan Whitehorn int rc = getmaxy(win);
1134c8945a0SNathan Whitehorn int cc = getmaxx(win);
1144c8945a0SNathan Whitehorn chtype ch, c2;
115*a96ef450SBaptiste Daroussin int y, x;
116*a96ef450SBaptiste Daroussin int j, k;
1174c8945a0SNathan Whitehorn
1184c8945a0SNathan Whitehorn fprintf(myFP, "window %dx%d at %d,%d\n",
1194c8945a0SNathan Whitehorn rc, cc, getbegy(win), getbegx(win));
1204c8945a0SNathan Whitehorn
1214c8945a0SNathan Whitehorn getyx(win, y, x);
1224c8945a0SNathan Whitehorn for (j = 0; j < rc; ++j) {
1234c8945a0SNathan Whitehorn fprintf(myFP, "%3d:", j);
1244c8945a0SNathan Whitehorn for (k = 0; k < cc; ++k) {
1252a3e3873SBaptiste Daroussin #ifdef USE_WIDE_CURSES
1262a3e3873SBaptiste Daroussin char buffer[80];
1272a3e3873SBaptiste Daroussin
1282a3e3873SBaptiste Daroussin ch = mvwinch(win, j, k) & (A_CHARTEXT | A_ALTCHARSET);
1292a3e3873SBaptiste Daroussin if (ch & A_ALTCHARSET) {
1302a3e3873SBaptiste Daroussin c2 = dlg_asciibox(ch);
1312a3e3873SBaptiste Daroussin if (c2 != 0) {
1322a3e3873SBaptiste Daroussin ch = c2;
1332a3e3873SBaptiste Daroussin }
1342a3e3873SBaptiste Daroussin buffer[0] = (char) ch;
1352a3e3873SBaptiste Daroussin buffer[1] = '\0';
1362a3e3873SBaptiste Daroussin } else {
1372a3e3873SBaptiste Daroussin cchar_t cch;
138*a96ef450SBaptiste Daroussin const wchar_t *uc;
1392a3e3873SBaptiste Daroussin
1402a3e3873SBaptiste Daroussin if (win_wch(win, &cch) == ERR
141f4f33ea0SBaptiste Daroussin || (uc = wunctrl((&cch))) == 0
1422a3e3873SBaptiste Daroussin || uc[1] != 0
1432a3e3873SBaptiste Daroussin || wcwidth(uc[0]) <= 0) {
1442a3e3873SBaptiste Daroussin buffer[0] = '.';
1452a3e3873SBaptiste Daroussin buffer[1] = '\0';
1462a3e3873SBaptiste Daroussin } else {
1472a3e3873SBaptiste Daroussin mbstate_t state;
1482a3e3873SBaptiste Daroussin const wchar_t *ucp = uc;
1492a3e3873SBaptiste Daroussin
1502a3e3873SBaptiste Daroussin memset(&state, 0, sizeof(state));
1512a3e3873SBaptiste Daroussin wcsrtombs(buffer, &ucp, sizeof(buffer), &state);
1522a3e3873SBaptiste Daroussin k += wcwidth(uc[0]) - 1;
1532a3e3873SBaptiste Daroussin }
1542a3e3873SBaptiste Daroussin }
1552a3e3873SBaptiste Daroussin fputs(buffer, myFP);
1562a3e3873SBaptiste Daroussin #else
1574c8945a0SNathan Whitehorn ch = mvwinch(win, j, k) & (A_CHARTEXT | A_ALTCHARSET);
1584c8945a0SNathan Whitehorn c2 = dlg_asciibox(ch);
1594c8945a0SNathan Whitehorn if (c2 != 0) {
1604c8945a0SNathan Whitehorn ch = c2;
1614c8945a0SNathan Whitehorn } else if (unctrl(ch) == 0 || strlen(unctrl(ch)) > 1) {
1624c8945a0SNathan Whitehorn ch = '.';
1634c8945a0SNathan Whitehorn }
1644c8945a0SNathan Whitehorn fputc((int) (ch & 0xff), myFP);
1652a3e3873SBaptiste Daroussin #endif
1664c8945a0SNathan Whitehorn }
1674c8945a0SNathan Whitehorn fputc('\n', myFP);
1684c8945a0SNathan Whitehorn }
1694c8945a0SNathan Whitehorn wmove(win, y, x);
1704c8945a0SNathan Whitehorn fflush(myFP);
1714c8945a0SNathan Whitehorn }
1724c8945a0SNathan Whitehorn }
1732a3e3873SBaptiste Daroussin }
1744c8945a0SNathan Whitehorn
1754c8945a0SNathan Whitehorn void
dlg_trace_chr(int ch,int fkey)1764c8945a0SNathan Whitehorn dlg_trace_chr(int ch, int fkey)
1774c8945a0SNathan Whitehorn {
1782a3e3873SBaptiste Daroussin static int last_err = 0;
1792a3e3873SBaptiste Daroussin
1802a3e3873SBaptiste Daroussin /*
1812a3e3873SBaptiste Daroussin * Do not bother to trace ERR's indefinitely, since those are usually due
1822a3e3873SBaptiste Daroussin * to relatively short polling timeouts.
1832a3e3873SBaptiste Daroussin */
1842a3e3873SBaptiste Daroussin if (last_err && !fkey && ch == ERR) {
1852a3e3873SBaptiste Daroussin ++last_err;
1862a3e3873SBaptiste Daroussin } else if (myFP != 0) {
1874c8945a0SNathan Whitehorn const char *fkey_name = "?";
1882a3e3873SBaptiste Daroussin
1892a3e3873SBaptiste Daroussin if (last_err) {
1902a3e3873SBaptiste Daroussin fprintf(myFP, "skipped %d ERR's\n", last_err);
1912a3e3873SBaptiste Daroussin last_err = 0;
1922a3e3873SBaptiste Daroussin }
1932a3e3873SBaptiste Daroussin
1944c8945a0SNathan Whitehorn if (fkey) {
1954c8945a0SNathan Whitehorn if (fkey > KEY_MAX || (fkey_name = keyname(fkey)) == 0) {
1964c8945a0SNathan Whitehorn #define CASE(name) case name: fkey_name = #name; break
1974c8945a0SNathan Whitehorn switch ((DLG_KEYS_ENUM) fkey) {
1984c8945a0SNathan Whitehorn CASE(DLGK_MIN);
1994c8945a0SNathan Whitehorn CASE(DLGK_OK);
2004c8945a0SNathan Whitehorn CASE(DLGK_CANCEL);
2014c8945a0SNathan Whitehorn CASE(DLGK_EXTRA);
2024c8945a0SNathan Whitehorn CASE(DLGK_HELP);
2034c8945a0SNathan Whitehorn CASE(DLGK_ESC);
2044c8945a0SNathan Whitehorn CASE(DLGK_PAGE_FIRST);
2054c8945a0SNathan Whitehorn CASE(DLGK_PAGE_LAST);
2064c8945a0SNathan Whitehorn CASE(DLGK_PAGE_NEXT);
2074c8945a0SNathan Whitehorn CASE(DLGK_PAGE_PREV);
2084c8945a0SNathan Whitehorn CASE(DLGK_ITEM_FIRST);
2094c8945a0SNathan Whitehorn CASE(DLGK_ITEM_LAST);
2104c8945a0SNathan Whitehorn CASE(DLGK_ITEM_NEXT);
2114c8945a0SNathan Whitehorn CASE(DLGK_ITEM_PREV);
2124c8945a0SNathan Whitehorn CASE(DLGK_FIELD_FIRST);
2134c8945a0SNathan Whitehorn CASE(DLGK_FIELD_LAST);
2144c8945a0SNathan Whitehorn CASE(DLGK_FIELD_NEXT);
2154c8945a0SNathan Whitehorn CASE(DLGK_FIELD_PREV);
2162a3e3873SBaptiste Daroussin CASE(DLGK_FORM_FIRST);
2172a3e3873SBaptiste Daroussin CASE(DLGK_FORM_LAST);
2182a3e3873SBaptiste Daroussin CASE(DLGK_FORM_NEXT);
2192a3e3873SBaptiste Daroussin CASE(DLGK_FORM_PREV);
2204c8945a0SNathan Whitehorn CASE(DLGK_GRID_UP);
2214c8945a0SNathan Whitehorn CASE(DLGK_GRID_DOWN);
2224c8945a0SNathan Whitehorn CASE(DLGK_GRID_LEFT);
2234c8945a0SNathan Whitehorn CASE(DLGK_GRID_RIGHT);
2244c8945a0SNathan Whitehorn CASE(DLGK_DELETE_LEFT);
2254c8945a0SNathan Whitehorn CASE(DLGK_DELETE_RIGHT);
2264c8945a0SNathan Whitehorn CASE(DLGK_DELETE_ALL);
2274c8945a0SNathan Whitehorn CASE(DLGK_ENTER);
2284c8945a0SNathan Whitehorn CASE(DLGK_BEGIN);
2294c8945a0SNathan Whitehorn CASE(DLGK_FINAL);
2304c8945a0SNathan Whitehorn CASE(DLGK_SELECT);
231682c9e0fSNathan Whitehorn CASE(DLGK_HELPFILE);
2324c8945a0SNathan Whitehorn CASE(DLGK_TRACE);
233f4f33ea0SBaptiste Daroussin CASE(DLGK_TOGGLE);
234*a96ef450SBaptiste Daroussin CASE(DLGK_LEAVE);
2354c8945a0SNathan Whitehorn }
2364c8945a0SNathan Whitehorn }
2377a1c0d96SNathan Whitehorn } else if (ch == ERR) {
2387a1c0d96SNathan Whitehorn fkey_name = "ERR";
2392a3e3873SBaptiste Daroussin last_err = 1;
2404c8945a0SNathan Whitehorn } else {
2414c8945a0SNathan Whitehorn fkey_name = unctrl((chtype) ch);
2424c8945a0SNathan Whitehorn if (fkey_name == 0)
2434c8945a0SNathan Whitehorn fkey_name = "UNKNOWN";
2444c8945a0SNathan Whitehorn }
245f4f33ea0SBaptiste Daroussin if (ch >= 0) {
246f4f33ea0SBaptiste Daroussin fprintf(myFP, "chr %s (ch=%#x, fkey=%d)\n", fkey_name, ch, fkey);
247f4f33ea0SBaptiste Daroussin } else {
248f4f33ea0SBaptiste Daroussin fprintf(myFP, "chr %s (ch=%d, fkey=%d)\n", fkey_name, ch, fkey);
249f4f33ea0SBaptiste Daroussin }
2504c8945a0SNathan Whitehorn fflush(myFP);
2514c8945a0SNathan Whitehorn }
2524c8945a0SNathan Whitehorn }
2534c8945a0SNathan Whitehorn
2544c8945a0SNathan Whitehorn void
dlg_trace(const char * fname)2554c8945a0SNathan Whitehorn dlg_trace(const char *fname)
2564c8945a0SNathan Whitehorn {
2574c8945a0SNathan Whitehorn if (fname != 0) {
2584c8945a0SNathan Whitehorn if (myFP == 0) {
2594c8945a0SNathan Whitehorn myFP = fopen(fname, "a");
2604c8945a0SNathan Whitehorn if (myFP != 0) {
261f4f33ea0SBaptiste Daroussin dlg_trace_time("## opened at");
262f4f33ea0SBaptiste Daroussin DLG_TRACE(("## dialog %s\n", dialog_version()));
263f4f33ea0SBaptiste Daroussin DLG_TRACE(("## vile: confmode\n"));
2644c8945a0SNathan Whitehorn }
2654c8945a0SNathan Whitehorn }
2664c8945a0SNathan Whitehorn } else if (myFP != 0) {
267f4f33ea0SBaptiste Daroussin dlg_trace_time("## closed at");
2684c8945a0SNathan Whitehorn fclose(myFP);
2694c8945a0SNathan Whitehorn myFP = 0;
2704c8945a0SNathan Whitehorn }
2714c8945a0SNathan Whitehorn }
2724c8945a0SNathan Whitehorn #else
2734c8945a0SNathan Whitehorn #undef dlg_trace
2744c8945a0SNathan Whitehorn extern void dlg_trace(const char *);
2754c8945a0SNathan Whitehorn void
dlg_trace(const char * fname)2764c8945a0SNathan Whitehorn dlg_trace(const char *fname)
2774c8945a0SNathan Whitehorn {
2784c8945a0SNathan Whitehorn (void) fname;
2794c8945a0SNathan Whitehorn }
2804c8945a0SNathan Whitehorn #endif
281