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