xref: /netbsd-src/usr.bin/m4/trace.c (revision 1ca5c1b28139779176bd5c13ad7c5f25c0bcd5f8)
1 /*	$NetBSD: trace.c,v 1.3 2001/12/31 18:34:52 thorpej 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 #include <sys/types.h>
30 #include <err.h>
31 #include <stddef.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include "mdef.h"
36 #include "stdd.h"
37 #include "extern.h"
38 
39 FILE *traceout = stderr;
40 
41 int 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 
54 static struct t {
55 	struct t *next;
56 	char 	 *name;
57 	int	  on;
58 } *l;
59 
60 static unsigned int letter_to_flag __P((int));
61 static void print_header __P((struct input_file *));
62 static struct t *find_trace_entry __P((const char *));
63 static int frame_level __P((void));
64 
65 static unsigned int flags = TRACE_QUOTE | TRACE_EXPANSION;
66 
67 static struct t *
68 find_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 
80 void
81 mark_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 
114 int
115 is_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 
126 void
127 trace_file(name)
128 	const char *name;
129 {
130 	if (traceout != stderr)
131 		fclose(traceout);
132 	traceout = fopen(name, "w");
133 	if (!traceout)
134 		err(1, "can't open %s", name);
135 }
136 
137 static unsigned int
138 letter_to_flag(c)
139 	int c;
140 {
141 	switch(c) {
142 	case 'a':
143 		return TRACE_ARGS;
144 	case 'e':
145 		return TRACE_EXPANSION;
146 	case 'q':
147 		return TRACE_QUOTE;
148 	case 'c':
149 		return TRACE_CONT;
150 	case 'x':
151 		return TRACE_ID;
152 	case 'f':
153 		return TRACE_FILENAME;
154 	case 'l':
155 		return TRACE_LINENO;
156 	case 'p':
157 		return TRACE_NEWFILE;
158 	case 'i':
159 		return TRACE_INPUT;
160 	case 't':
161 		return TRACE_ALL;
162 	case 'V':
163 		return ~0;
164 	default:
165 		return 0;
166 	}
167 }
168 
169 void
170 set_trace_flags(s)
171 	const char *s;
172 {
173 	char mode = 0;
174 	unsigned int f = 0;
175 
176 	traced_macros = 1;
177 
178 	if (*s == '+' || *s == '-')
179 		mode = *s++;
180 	while (*s)
181 		f |= letter_to_flag(*s++);
182 	switch(mode) {
183 	case 0:
184 		flags = f;
185 		break;
186 	case '+':
187 		flags |= f;
188 		break;
189 	case '-':
190 		flags &= ~f;
191 		break;
192 	}
193 }
194 
195 static int
196 frame_level()
197 {
198 	int level;
199 	int framep;
200 
201 	for (framep = fp, level = 0; framep != 0;
202 		level++,framep = mstack[framep-2].sfra)
203 		;
204 	return level;
205 }
206 
207 static void
208 print_header(inp)
209 	struct input_file *inp;
210 {
211 	fprintf(traceout, "m4trace:");
212 	if (flags & TRACE_FILENAME)
213 		fprintf(traceout, "%s:", inp->name);
214 	if (flags & TRACE_LINENO)
215 		fprintf(traceout, "%lu:", inp->lineno);
216 	fprintf(traceout, " -%d- ", frame_level());
217 	if (flags & TRACE_ID)
218 		fprintf(traceout, "id %lu: ", expansion_id);
219 }
220 
221 ssize_t
222 trace(argv, argc, inp)
223 	const char **argv;
224 	int argc;
225 	struct input_file *inp;
226 {
227 	print_header(inp);
228 	if (flags & TRACE_CONT) {
229 		fprintf(traceout, "%s ...\n", argv[1]);
230 		print_header(inp);
231 	}
232 	fprintf(traceout, "%s", argv[1]);
233 	if ((flags & TRACE_ARGS) && argc > 2) {
234 		char delim[3];
235 		int i;
236 
237 		delim[0] = LPAREN;
238 		delim[1] = EOS;
239 		for (i = 2; i < argc; i++) {
240 			fprintf(traceout, "%s%s%s%s", delim,
241 			    (flags & TRACE_QUOTE) ? lquote : "",
242 			    argv[i],
243 			    (flags & TRACE_QUOTE) ? rquote : "");
244 			delim[0] = COMMA;
245 			delim[1] = ' ';
246 			delim[2] = EOS;
247 		}
248 		fprintf(traceout, "%c", RPAREN);
249 	}
250 	if (flags & TRACE_CONT) {
251 		fprintf(traceout, " -> ???\n");
252 		print_header(inp);
253 		fprintf(traceout, argc > 2 ? "%s(...)" : "%s", argv[1]);
254 	}
255 	if (flags & TRACE_EXPANSION)
256 		return buffer_mark();
257 	else {
258 		fprintf(traceout, "\n");
259 		return -1;
260 	}
261 }
262 
263 void
264 finish_trace(mark)
265 size_t mark;
266 {
267 	fprintf(traceout, " -> ");
268 	if (flags & TRACE_QUOTE)
269 		fprintf(traceout, "%s", lquote);
270 	dump_buffer(traceout, mark);
271 	if (flags & TRACE_QUOTE)
272 		fprintf(traceout, "%s", rquote);
273 	fprintf(traceout, "\n");
274 }
275