xref: /freebsd/usr.bin/m4/trace.c (revision e3d8671772982f3135d8d6997f3cd698cca4df19)
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 
36 FILE *traceout = stderr;
37 
38 int 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 
51 static struct t {
52 	struct t *next;
53 	char 	 *name;
54 	int	  on;
55 } *l;
56 
57 static unsigned int letter_to_flag(int);
58 static void print_header(struct input_file *);
59 static struct t *find_trace_entry(const char *);
60 static int frame_level(void);
61 
62 static unsigned int flags = TRACE_QUOTE | TRACE_EXPANSION;
63 
64 static struct t *
65 find_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 
77 void
78 mark_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 
111 int
112 is_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 
123 void
124 trace_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 
135 static unsigned int
136 letter_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 
167 void
168 set_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 
193 static int
194 frame_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 
205 static void
206 print_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 
219 ssize_t
220 trace(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 
261 void
262 finish_trace(mark)
263 size_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