trace.c revision 1.4 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