xref: /netbsd-src/usr.bin/m4/trace.c (revision 220b5c059a84c51ea44107ea8951a57ffaecdc8c)
1 /*	$NetBSD: trace.c,v 1.2 2001/11/14 14:44:29 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 <err.h>
31 #include <stddef.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include "mdef.h"
35 #include "stdd.h"
36 #include "extern.h"
37 
38 FILE *traceout = stderr;
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 != stderr)
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 	fprintf(traceout, "m4trace:");
211 	if (flags & TRACE_FILENAME)
212 		fprintf(traceout, "%s:", inp->name);
213 	if (flags & TRACE_LINENO)
214 		fprintf(traceout, "%lu:", inp->lineno);
215 	fprintf(traceout, " -%d- ", frame_level());
216 	if (flags & TRACE_ID)
217 		fprintf(traceout, "id %lu: ", expansion_id);
218 }
219 
220 ssize_t
221 trace(argv, argc, inp)
222 	const char **argv;
223 	int argc;
224 	struct input_file *inp;
225 {
226 	print_header(inp);
227 	if (flags & TRACE_CONT) {
228 		fprintf(traceout, "%s ...\n", argv[1]);
229 		print_header(inp);
230 	}
231 	fprintf(traceout, "%s", argv[1]);
232 	if ((flags & TRACE_ARGS) && argc > 2) {
233 		char delim[3];
234 		int i;
235 
236 		delim[0] = LPAREN;
237 		delim[1] = EOS;
238 		for (i = 2; i < argc; i++) {
239 			fprintf(traceout, "%s%s%s%s", delim,
240 			    (flags & TRACE_QUOTE) ? lquote : "",
241 			    argv[i],
242 			    (flags & TRACE_QUOTE) ? rquote : "");
243 			delim[0] = COMMA;
244 			delim[1] = ' ';
245 			delim[2] = EOS;
246 		}
247 		fprintf(traceout, "%c", RPAREN);
248 	}
249 	if (flags & TRACE_CONT) {
250 		fprintf(traceout, " -> ???\n");
251 		print_header(inp);
252 		fprintf(traceout, argc > 2 ? "%s(...)" : "%s", argv[1]);
253 	}
254 	if (flags & TRACE_EXPANSION)
255 		return buffer_mark();
256 	else {
257 		fprintf(traceout, "\n");
258 		return -1;
259 	}
260 }
261 
262 void
263 finish_trace(mark)
264 size_t mark;
265 {
266 	fprintf(traceout, " -> ");
267 	if (flags & TRACE_QUOTE)
268 		fprintf(traceout, "%s", lquote);
269 	dump_buffer(traceout, mark);
270 	if (flags & TRACE_QUOTE)
271 		fprintf(traceout, "%s", rquote);
272 	fprintf(traceout, "\n");
273 }
274