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