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