trace.c revision 95060
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/cdefs.h>
28__FBSDID("$FreeBSD: head/usr.bin/m4/trace.c 95060 2002-04-19 17:26:21Z jmallett $");
29
30#include <sys/types.h>
31#include <stddef.h>
32#include <stdio.h>
33#include <err.h>
34#include <stdlib.h>
35#include "mdef.h"
36#include "stdd.h"
37#include "extern.h"
38
39FILE *traceout;
40
41int traced_macros = 0;
42
43#define TRACE_ARGS 	1
44#define TRACE_EXPANSION 2
45#define TRACE_QUOTE	4
46#define TRACE_FILENAME	8
47#define TRACE_LINENO	16
48#define TRACE_CONT	32
49#define TRACE_ID	64
50#define TRACE_NEWFILE	128	/* not implemented yet */
51#define TRACE_INPUT	256	/* not implemented yet */
52#define TRACE_ALL	512
53
54static struct t {
55	struct t *next;
56	char 	 *name;
57	int	  on;
58} *l;
59
60static unsigned int letter_to_flag(int);
61static void print_header(struct input_file *);
62static struct t *find_trace_entry(const char *);
63static int frame_level(void);
64
65static unsigned int flags = TRACE_QUOTE | TRACE_EXPANSION;
66
67static struct t *
68find_trace_entry(name)
69	const char *name;
70{
71	struct t *n;
72
73	for (n = l; n != NULL; n = n->next)
74		if (STREQ(n->name, name))
75			return n;
76	return NULL;
77}
78
79
80void
81mark_traced(name, on)
82	const char *name;
83	int on;
84{
85	struct t *n, *n2;
86
87	traced_macros = 1;
88
89	if (name == NULL) {
90		if (on)
91			flags |= TRACE_ALL;
92		else {
93			flags &= ~TRACE_ALL;
94			traced_macros = 0;
95		}
96		for (n = l; n != NULL; n = n2) {
97			n2 = n->next;
98			free(n->name);
99			free(n);
100		}
101		l = NULL;
102	} else {
103	    n = find_trace_entry(name);
104	    if (n == NULL) {
105	n = xalloc(sizeof(struct t));
106	n->name = xstrdup(name);
107	n->next = l;
108	l = n;
109	    }
110	    n->on = on;
111	}
112}
113
114int
115is_traced(name)
116	const char *name;
117{
118	struct t *n;
119
120	for (n = l; n != NULL; n = n->next)
121		if (STREQ(n->name, name))
122			return n->on;
123	return (flags & TRACE_ALL) ? 1 : 0;
124}
125
126void
127trace_file(name)
128	const char *name;
129{
130
131	if (traceout != stderr)
132		fclose(traceout);
133	traceout = fopen(name, "w");
134	if (!traceout)
135		err(1, "can't open %s", name);
136}
137
138static unsigned int
139letter_to_flag(c)
140	int c;
141{
142	switch(c) {
143	case 'a':
144		return TRACE_ARGS;
145	case 'e':
146		return TRACE_EXPANSION;
147	case 'q':
148		return TRACE_QUOTE;
149	case 'c':
150		return TRACE_CONT;
151	case 'x':
152		return TRACE_ID;
153	case 'f':
154		return TRACE_FILENAME;
155	case 'l':
156		return TRACE_LINENO;
157	case 'p':
158		return TRACE_NEWFILE;
159	case 'i':
160		return TRACE_INPUT;
161	case 't':
162		return TRACE_ALL;
163	case 'V':
164		return ~0;
165	default:
166		return 0;
167	}
168}
169
170void
171set_trace_flags(s)
172	const char *s;
173{
174	char mode = 0;
175	unsigned int f = 0;
176
177	traced_macros = 1;
178
179	if (*s == '+' || *s == '-')
180		mode = *s++;
181	while (*s)
182		f |= letter_to_flag(*s++);
183	switch(mode) {
184	case 0:
185		flags = f;
186		break;
187	case '+':
188		flags |= f;
189		break;
190	case '-':
191		flags &= ~f;
192		break;
193	}
194}
195
196static int
197frame_level()
198{
199	int level;
200	int framep;
201
202	for (framep = fp, level = 0; framep != 0;
203		level++,framep = mstack[framep-2].sfra)
204		;
205	return level;
206}
207
208static void
209print_header(inp)
210	struct input_file *inp;
211{
212	fprintf(traceout, "m4trace:");
213	if (flags & TRACE_FILENAME)
214		fprintf(traceout, "%s:", inp->name);
215	if (flags & TRACE_LINENO)
216		fprintf(traceout, "%lu:", inp->lineno);
217	fprintf(traceout, " -%d- ", frame_level());
218	if (flags & TRACE_ID)
219		fprintf(traceout, "id %lu: ", expansion_id);
220}
221
222ssize_t
223trace(argv, argc, inp)
224	const char **argv;
225	int argc;
226	struct input_file *inp;
227{
228	print_header(inp);
229	if (flags & TRACE_CONT) {
230		fprintf(traceout, "%s ...\n", argv[1]);
231		print_header(inp);
232	}
233	fprintf(traceout, "%s", argv[1]);
234	if ((flags & TRACE_ARGS) && argc > 2) {
235		char delim[3];
236		int i;
237
238		delim[0] = LPAREN;
239		delim[1] = EOS;
240		for (i = 2; i < argc; i++) {
241			fprintf(traceout, "%s%s%s%s", delim,
242			    (flags & TRACE_QUOTE) ? lquote : "",
243			    argv[i],
244			    (flags & TRACE_QUOTE) ? rquote : "");
245			delim[0] = COMMA;
246			delim[1] = ' ';
247			delim[2] = EOS;
248		}
249		fprintf(traceout, "%c", RPAREN);
250	}
251	if (flags & TRACE_CONT) {
252		fprintf(traceout, " -> ???\n");
253		print_header(inp);
254		fprintf(traceout, argc > 2 ? "%s(...)" : "%s", argv[1]);
255	}
256	if (flags & TRACE_EXPANSION)
257		return buffer_mark();
258	else {
259		fprintf(traceout, "\n");
260		return -1;
261	}
262}
263
264void
265finish_trace(mark)
266size_t mark;
267{
268	fprintf(traceout, " -> ");
269	if (flags & TRACE_QUOTE)
270		fprintf(traceout, "%s", lquote);
271	dump_buffer(traceout, mark);
272	if (flags & TRACE_QUOTE)
273		fprintf(traceout, "%s", rquote);
274	fprintf(traceout, "\n");
275}
276