trace.c revision 90744
1/* $OpenBSD: trace.c,v 1.4 2002/02/16 21:27:48 millert Exp $ */
2/*
3 * Copyright (c) 2001 Marc Espie.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE OPENBSD PROJECT AND CONTRIBUTORS
15 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17 * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OPENBSD
18 * PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
20 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include <sys/types.h>
28#include <stddef.h>
29#include <stdio.h>
30#include <err.h>
31#include <stdlib.h>
32#include "mdef.h"
33#include "stdd.h"
34#include "extern.h"
35
36FILE *traceout = stderr;
37
38int traced_macros = 0;
39
40#define TRACE_ARGS 	1
41#define TRACE_EXPANSION 2
42#define TRACE_QUOTE	4
43#define TRACE_FILENAME	8
44#define TRACE_LINENO	16
45#define TRACE_CONT	32
46#define TRACE_ID	64
47#define TRACE_NEWFILE	128	/* not implemented yet */
48#define TRACE_INPUT	256	/* not implemented yet */
49#define TRACE_ALL	512
50
51static struct t {
52	struct t *next;
53	char 	 *name;
54	int	  on;
55} *l;
56
57static unsigned int letter_to_flag(int);
58static void print_header(struct input_file *);
59static struct t *find_trace_entry(const char *);
60static int frame_level(void);
61
62static unsigned int flags = TRACE_QUOTE | TRACE_EXPANSION;
63
64static struct t *
65find_trace_entry(name)
66	const char *name;
67{
68	struct t *n;
69
70	for (n = l; n != NULL; n = n->next)
71		if (STREQ(n->name, name))
72			return n;
73	return NULL;
74}
75
76
77void
78mark_traced(name, on)
79	const char *name;
80	int on;
81{
82	struct t *n, *n2;
83
84	traced_macros = 1;
85
86	if (name == NULL) {
87		if (on)
88			flags |= TRACE_ALL;
89		else {
90			flags &= ~TRACE_ALL;
91			traced_macros = 0;
92		}
93		for (n = l; n != NULL; n = n2) {
94			n2 = n->next;
95			free(n->name);
96			free(n);
97		}
98		l = NULL;
99	} else {
100	    n = find_trace_entry(name);
101	    if (n == NULL) {
102	n = xalloc(sizeof(struct t));
103	n->name = xstrdup(name);
104	n->next = l;
105	l = n;
106	    }
107	    n->on = on;
108	}
109}
110
111int
112is_traced(name)
113	const char *name;
114{
115	struct t *n;
116
117	for (n = l; n != NULL; n = n->next)
118		if (STREQ(n->name, name))
119			return n->on;
120	return (flags & TRACE_ALL) ? 1 : 0;
121}
122
123void
124trace_file(name)
125	const char *name;
126{
127
128	if (traceout != stderr)
129		fclose(traceout);
130	traceout = fopen(name, "w");
131	if (!traceout)
132		err(1, "can't open %s", name);
133}
134
135static unsigned int
136letter_to_flag(c)
137	int c;
138{
139	switch(c) {
140	case 'a':
141		return TRACE_ARGS;
142	case 'e':
143		return TRACE_EXPANSION;
144	case 'q':
145		return TRACE_QUOTE;
146	case 'c':
147		return TRACE_CONT;
148	case 'x':
149		return TRACE_ID;
150	case 'f':
151		return TRACE_FILENAME;
152	case 'l':
153		return TRACE_LINENO;
154	case 'p':
155		return TRACE_NEWFILE;
156	case 'i':
157		return TRACE_INPUT;
158	case 't':
159		return TRACE_ALL;
160	case 'V':
161		return ~0;
162	default:
163		return 0;
164	}
165}
166
167void
168set_trace_flags(s)
169	const char *s;
170{
171	char mode = 0;
172	unsigned int f = 0;
173
174	traced_macros = 1;
175
176	if (*s == '+' || *s == '-')
177		mode = *s++;
178	while (*s)
179		f |= letter_to_flag(*s++);
180	switch(mode) {
181	case 0:
182		flags = f;
183		break;
184	case '+':
185		flags |= f;
186		break;
187	case '-':
188		flags &= ~f;
189		break;
190	}
191}
192
193static int
194frame_level()
195{
196	int level;
197	int framep;
198
199	for (framep = fp, level = 0; framep != 0;
200		level++,framep = mstack[framep-2].sfra)
201		;
202	return level;
203}
204
205static void
206print_header(inp)
207	struct input_file *inp;
208{
209	fprintf(traceout, "m4trace:");
210	if (flags & TRACE_FILENAME)
211		fprintf(traceout, "%s:", inp->name);
212	if (flags & TRACE_LINENO)
213		fprintf(traceout, "%lu:", inp->lineno);
214	fprintf(traceout, " -%d- ", frame_level());
215	if (flags & TRACE_ID)
216		fprintf(traceout, "id %lu: ", expansion_id);
217}
218
219ssize_t
220trace(argv, argc, inp)
221	const char **argv;
222	int argc;
223	struct input_file *inp;
224{
225	print_header(inp);
226	if (flags & TRACE_CONT) {
227		fprintf(traceout, "%s ...\n", argv[1]);
228		print_header(inp);
229	}
230	fprintf(traceout, "%s", argv[1]);
231	if ((flags & TRACE_ARGS) && argc > 2) {
232		char delim[3];
233		int i;
234
235		delim[0] = LPAREN;
236		delim[1] = EOS;
237		for (i = 2; i < argc; i++) {
238			fprintf(traceout, "%s%s%s%s", delim,
239			    (flags & TRACE_QUOTE) ? lquote : "",
240			    argv[i],
241			    (flags & TRACE_QUOTE) ? rquote : "");
242			delim[0] = COMMA;
243			delim[1] = ' ';
244			delim[2] = EOS;
245		}
246		fprintf(traceout, "%c", RPAREN);
247	}
248	if (flags & TRACE_CONT) {
249		fprintf(traceout, " -> ???\n");
250		print_header(inp);
251		fprintf(traceout, argc > 2 ? "%s(...)" : "%s", argv[1]);
252	}
253	if (flags & TRACE_EXPANSION)
254		return buffer_mark();
255	else {
256		fprintf(traceout, "\n");
257		return -1;
258	}
259}
260
261void
262finish_trace(mark)
263size_t mark;
264{
265	fprintf(traceout, " -> ");
266	if (flags & TRACE_QUOTE)
267		fprintf(traceout, "%s", lquote);
268	dump_buffer(traceout, mark);
269	if (flags & TRACE_QUOTE)
270		fprintf(traceout, "%s", rquote);
271	fprintf(traceout, "\n");
272}
273