1/****************************************************************************
2 * Copyright (c) 1998-2004,2005 Free Software Foundation, Inc.              *
3 *                                                                          *
4 * Permission is hereby granted, free of charge, to any person obtaining a  *
5 * copy of this software and associated documentation files (the            *
6 * "Software"), to deal in the Software without restriction, including      *
7 * without limitation the rights to use, copy, modify, merge, publish,      *
8 * distribute, distribute with modifications, sublicense, and/or sell       *
9 * copies of the Software, and to permit persons to whom the Software is    *
10 * furnished to do so, subject to the following conditions:                 *
11 *                                                                          *
12 * The above copyright notice and this permission notice shall be included  *
13 * in all copies or substantial portions of the Software.                   *
14 *                                                                          *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
16 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
18 * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
21 * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
22 *                                                                          *
23 * Except as contained in this notice, the name(s) of the above copyright   *
24 * holders shall not be used in advertising or otherwise to promote the     *
25 * sale, use or other dealings in this Software without prior written       *
26 * authorization.                                                           *
27 ****************************************************************************/
28
29/****************************************************************************
30 *  Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
31 *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
32 *     and: Thomas E. Dickey                        1996-on                 *
33 ****************************************************************************/
34
35/*
36 *	lib_trace.c - Tracing/Debugging routines
37 */
38
39#include <curses.priv.h>
40#include <tic.h>
41
42#include <ctype.h>
43
44MODULE_ID("$Id: lib_trace.c,v 1.58 2005/04/16 16:15:24 tom Exp $")
45
46NCURSES_EXPORT_VAR(unsigned) _nc_tracing = 0; /* always define this */
47
48#ifdef TRACE
49NCURSES_EXPORT_VAR(const char *) _nc_tputs_trace = "";
50NCURSES_EXPORT_VAR(long) _nc_outchars = 0;
51
52static FILE *tracefp = 0;	/* default to writing to stderr */
53
54NCURSES_EXPORT(void)
55trace(const unsigned int tracelevel)
56{
57    static bool been_here = FALSE;
58    static char my_name[PATH_MAX];
59
60    if ((tracefp == 0) && tracelevel) {
61	const char *mode = been_here ? "ab" : "wb";
62
63	if (*my_name == '\0') {
64	    if (getcwd(my_name, sizeof(my_name) - 10) == 0) {
65		perror("curses: Can't get working directory");
66		exit(EXIT_FAILURE);
67	    }
68	    strcat(my_name, "/trace");
69	}
70
71	been_here = TRUE;
72	_nc_tracing = tracelevel;
73	if (_nc_access(my_name, W_OK) < 0
74	    || (tracefp = fopen(my_name, mode)) == 0) {
75	    perror("curses: Can't open 'trace' file");
76	    exit(EXIT_FAILURE);
77	}
78	/* Try to set line-buffered mode, or (failing that) unbuffered,
79	 * so that the trace-output gets flushed automatically at the
80	 * end of each line.  This is useful in case the program dies.
81	 */
82#if HAVE_SETVBUF		/* ANSI */
83	(void) setvbuf(tracefp, (char *) 0, _IOLBF, 0);
84#elif HAVE_SETBUF		/* POSIX */
85	(void) setbuffer(tracefp, (char *) 0);
86#endif
87	_tracef("TRACING NCURSES version %s.%d (tracelevel=%#x)",
88		NCURSES_VERSION,
89		NCURSES_VERSION_PATCH,
90		tracelevel);
91    } else if (tracelevel == 0) {
92	if (tracefp != 0) {
93	    fclose(tracefp);
94	    tracefp = 0;
95	}
96	_nc_tracing = tracelevel;
97    } else if (_nc_tracing != tracelevel) {
98	_nc_tracing = tracelevel;
99	_tracef("tracelevel=%#x", tracelevel);
100    }
101}
102
103NCURSES_EXPORT(void)
104_tracef(const char *fmt,...)
105{
106    static const char Called[] = T_CALLED("");
107    static const char Return[] = T_RETURN("");
108    static int level;
109    va_list ap;
110    bool before = FALSE;
111    bool after = FALSE;
112    unsigned doit = _nc_tracing;
113    int save_err = errno;
114
115    if (strlen(fmt) >= sizeof(Called) - 1) {
116	if (!strncmp(fmt, Called, sizeof(Called) - 1)) {
117	    before = TRUE;
118	    level++;
119	} else if (!strncmp(fmt, Return, sizeof(Return) - 1)) {
120	    after = TRUE;
121	}
122	if (before || after) {
123	    if ((level <= 1)
124		|| (doit & TRACE_ICALLS) != 0)
125		doit &= (TRACE_CALLS | TRACE_CCALLS);
126	    else
127		doit = 0;
128	}
129    }
130
131    if (doit != 0) {
132	if (tracefp == 0)
133	    tracefp = stderr;
134	if (before || after) {
135	    int n;
136	    for (n = 1; n < level; n++)
137		fputs("+ ", tracefp);
138	}
139	va_start(ap, fmt);
140	vfprintf(tracefp, fmt, ap);
141	fputc('\n', tracefp);
142	va_end(ap);
143	fflush(tracefp);
144    }
145
146    if (after && level)
147	level--;
148    errno = save_err;
149}
150
151/* Trace 'bool' return-values */
152NCURSES_EXPORT(NCURSES_BOOL)
153_nc_retrace_bool(NCURSES_BOOL code)
154{
155    T((T_RETURN("%s"), code ? "TRUE" : "FALSE"));
156    return code;
157}
158
159/* Trace 'int' return-values */
160NCURSES_EXPORT(int)
161_nc_retrace_int(int code)
162{
163    T((T_RETURN("%d"), code));
164    return code;
165}
166
167/* Trace 'unsigned' return-values */
168NCURSES_EXPORT(unsigned)
169_nc_retrace_unsigned(unsigned code)
170{
171    T((T_RETURN("%#x"), code));
172    return code;
173}
174
175/* Trace 'char*' return-values */
176NCURSES_EXPORT(char *)
177_nc_retrace_ptr(char *code)
178{
179    T((T_RETURN("%s"), _nc_visbuf(code)));
180    return code;
181}
182
183/* Trace 'const char*' return-values */
184NCURSES_EXPORT(const char *)
185_nc_retrace_cptr(const char *code)
186{
187    T((T_RETURN("%s"), _nc_visbuf(code)));
188    return code;
189}
190
191/* Trace 'NCURSES_CONST void*' return-values */
192NCURSES_EXPORT(NCURSES_CONST void *)
193_nc_retrace_cvoid_ptr(NCURSES_CONST void *code)
194{
195    T((T_RETURN("%p"), code));
196    return code;
197}
198
199/* Trace 'void*' return-values */
200NCURSES_EXPORT(void *)
201_nc_retrace_void_ptr(void *code)
202{
203    T((T_RETURN("%p"), code));
204    return code;
205}
206
207/* Trace 'SCREEN *' return-values */
208NCURSES_EXPORT(SCREEN *)
209_nc_retrace_sp(SCREEN *code)
210{
211    T((T_RETURN("%p"), code));
212    return code;
213}
214
215/* Trace 'WINDOW *' return-values */
216NCURSES_EXPORT(WINDOW *)
217_nc_retrace_win(WINDOW *code)
218{
219    T((T_RETURN("%p"), code));
220    return code;
221}
222#endif /* TRACE */
223