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