trace.c revision 1.4 1 1.4 tv /* $NetBSD: trace.c,v 1.4 2002/01/21 21:49:58 tv Exp $ */
2 1.1 tv /* $OpenBSD: trace.c,v 1.3 2001/09/29 15:47:18 espie Exp $ */
3 1.1 tv
4 1.1 tv /*
5 1.1 tv * Copyright (c) 2001 Marc Espie.
6 1.1 tv *
7 1.1 tv * Redistribution and use in source and binary forms, with or without
8 1.1 tv * modification, are permitted provided that the following conditions
9 1.1 tv * are met:
10 1.1 tv * 1. Redistributions of source code must retain the above copyright
11 1.1 tv * notice, this list of conditions and the following disclaimer.
12 1.1 tv * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 tv * notice, this list of conditions and the following disclaimer in the
14 1.1 tv * documentation and/or other materials provided with the distribution.
15 1.1 tv *
16 1.1 tv * THIS SOFTWARE IS PROVIDED BY THE OPENBSD PROJECT AND CONTRIBUTORS
17 1.1 tv * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 1.1 tv * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 1.1 tv * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OPENBSD
20 1.1 tv * PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 1.1 tv * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 1.1 tv * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 1.1 tv * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 1.1 tv * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 1.1 tv * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 1.1 tv * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 1.1 tv */
28 1.1 tv
29 1.1 tv #include <sys/types.h>
30 1.1 tv #include <stddef.h>
31 1.1 tv #include <stdio.h>
32 1.1 tv #include <stdlib.h>
33 1.3 thorpej #include <string.h>
34 1.1 tv #include "mdef.h"
35 1.1 tv #include "stdd.h"
36 1.1 tv #include "extern.h"
37 1.1 tv
38 1.4 tv FILE *traceout;
39 1.1 tv
40 1.1 tv int traced_macros = 0;
41 1.1 tv
42 1.1 tv #define TRACE_ARGS 1
43 1.1 tv #define TRACE_EXPANSION 2
44 1.1 tv #define TRACE_QUOTE 4
45 1.1 tv #define TRACE_FILENAME 8
46 1.1 tv #define TRACE_LINENO 16
47 1.1 tv #define TRACE_CONT 32
48 1.1 tv #define TRACE_ID 64
49 1.1 tv #define TRACE_NEWFILE 128 /* not implemented yet */
50 1.1 tv #define TRACE_INPUT 256 /* not implemented yet */
51 1.1 tv #define TRACE_ALL 512
52 1.1 tv
53 1.1 tv static struct t {
54 1.1 tv struct t *next;
55 1.1 tv char *name;
56 1.1 tv int on;
57 1.1 tv } *l;
58 1.1 tv
59 1.1 tv static unsigned int letter_to_flag __P((int));
60 1.1 tv static void print_header __P((struct input_file *));
61 1.1 tv static struct t *find_trace_entry __P((const char *));
62 1.1 tv static int frame_level __P((void));
63 1.1 tv
64 1.1 tv static unsigned int flags = TRACE_QUOTE | TRACE_EXPANSION;
65 1.1 tv
66 1.1 tv static struct t *
67 1.1 tv find_trace_entry(name)
68 1.1 tv const char *name;
69 1.1 tv {
70 1.1 tv struct t *n;
71 1.1 tv
72 1.1 tv for (n = l; n != NULL; n = n->next)
73 1.1 tv if (STREQ(n->name, name))
74 1.1 tv return n;
75 1.1 tv return NULL;
76 1.1 tv }
77 1.1 tv
78 1.1 tv
79 1.1 tv void
80 1.1 tv mark_traced(name, on)
81 1.1 tv const char *name;
82 1.1 tv int on;
83 1.1 tv {
84 1.1 tv struct t *n, *n2;
85 1.1 tv
86 1.1 tv traced_macros = 1;
87 1.1 tv
88 1.1 tv if (name == NULL) {
89 1.1 tv if (on)
90 1.1 tv flags |= TRACE_ALL;
91 1.1 tv else {
92 1.1 tv flags &= ~TRACE_ALL;
93 1.1 tv traced_macros = 0;
94 1.1 tv }
95 1.1 tv for (n = l; n != NULL; n = n2) {
96 1.1 tv n2 = n->next;
97 1.1 tv free(n->name);
98 1.1 tv free(n);
99 1.1 tv }
100 1.1 tv l = NULL;
101 1.1 tv } else {
102 1.1 tv n = find_trace_entry(name);
103 1.1 tv if (n == NULL) {
104 1.1 tv n = xalloc(sizeof(struct t));
105 1.1 tv n->name = xstrdup(name);
106 1.1 tv n->next = l;
107 1.1 tv l = n;
108 1.1 tv }
109 1.1 tv n->on = on;
110 1.1 tv }
111 1.1 tv }
112 1.1 tv
113 1.1 tv int
114 1.1 tv is_traced(name)
115 1.1 tv const char *name;
116 1.1 tv {
117 1.1 tv struct t *n;
118 1.1 tv
119 1.1 tv for (n = l; n != NULL; n = n->next)
120 1.1 tv if (STREQ(n->name, name))
121 1.1 tv return n->on;
122 1.1 tv return (flags & TRACE_ALL) ? 1 : 0;
123 1.1 tv }
124 1.1 tv
125 1.1 tv void
126 1.1 tv trace_file(name)
127 1.1 tv const char *name;
128 1.1 tv {
129 1.4 tv if (traceout)
130 1.1 tv fclose(traceout);
131 1.1 tv traceout = fopen(name, "w");
132 1.1 tv if (!traceout)
133 1.1 tv err(1, "can't open %s", name);
134 1.1 tv }
135 1.1 tv
136 1.1 tv static unsigned int
137 1.1 tv letter_to_flag(c)
138 1.1 tv int c;
139 1.1 tv {
140 1.1 tv switch(c) {
141 1.1 tv case 'a':
142 1.1 tv return TRACE_ARGS;
143 1.1 tv case 'e':
144 1.1 tv return TRACE_EXPANSION;
145 1.1 tv case 'q':
146 1.1 tv return TRACE_QUOTE;
147 1.1 tv case 'c':
148 1.1 tv return TRACE_CONT;
149 1.1 tv case 'x':
150 1.1 tv return TRACE_ID;
151 1.1 tv case 'f':
152 1.1 tv return TRACE_FILENAME;
153 1.1 tv case 'l':
154 1.1 tv return TRACE_LINENO;
155 1.1 tv case 'p':
156 1.1 tv return TRACE_NEWFILE;
157 1.1 tv case 'i':
158 1.1 tv return TRACE_INPUT;
159 1.1 tv case 't':
160 1.1 tv return TRACE_ALL;
161 1.1 tv case 'V':
162 1.1 tv return ~0;
163 1.1 tv default:
164 1.1 tv return 0;
165 1.1 tv }
166 1.1 tv }
167 1.1 tv
168 1.1 tv void
169 1.1 tv set_trace_flags(s)
170 1.1 tv const char *s;
171 1.1 tv {
172 1.1 tv char mode = 0;
173 1.1 tv unsigned int f = 0;
174 1.1 tv
175 1.1 tv traced_macros = 1;
176 1.1 tv
177 1.1 tv if (*s == '+' || *s == '-')
178 1.1 tv mode = *s++;
179 1.1 tv while (*s)
180 1.1 tv f |= letter_to_flag(*s++);
181 1.1 tv switch(mode) {
182 1.1 tv case 0:
183 1.1 tv flags = f;
184 1.1 tv break;
185 1.1 tv case '+':
186 1.1 tv flags |= f;
187 1.1 tv break;
188 1.1 tv case '-':
189 1.1 tv flags &= ~f;
190 1.1 tv break;
191 1.1 tv }
192 1.1 tv }
193 1.1 tv
194 1.1 tv static int
195 1.1 tv frame_level()
196 1.1 tv {
197 1.1 tv int level;
198 1.1 tv int framep;
199 1.1 tv
200 1.1 tv for (framep = fp, level = 0; framep != 0;
201 1.1 tv level++,framep = mstack[framep-2].sfra)
202 1.1 tv ;
203 1.1 tv return level;
204 1.1 tv }
205 1.1 tv
206 1.1 tv static void
207 1.1 tv print_header(inp)
208 1.1 tv struct input_file *inp;
209 1.1 tv {
210 1.4 tv FILE *out = traceout ? traceout : stderr;
211 1.4 tv
212 1.4 tv fprintf(out, "m4trace:");
213 1.1 tv if (flags & TRACE_FILENAME)
214 1.4 tv fprintf(out, "%s:", inp->name);
215 1.1 tv if (flags & TRACE_LINENO)
216 1.4 tv fprintf(out, "%lu:", inp->lineno);
217 1.4 tv fprintf(out, " -%d- ", frame_level());
218 1.1 tv if (flags & TRACE_ID)
219 1.4 tv fprintf(out, "id %lu: ", expansion_id);
220 1.1 tv }
221 1.1 tv
222 1.1 tv ssize_t
223 1.1 tv trace(argv, argc, inp)
224 1.1 tv const char **argv;
225 1.1 tv int argc;
226 1.1 tv struct input_file *inp;
227 1.1 tv {
228 1.4 tv FILE *out = traceout ? traceout : stderr;
229 1.4 tv
230 1.1 tv print_header(inp);
231 1.1 tv if (flags & TRACE_CONT) {
232 1.4 tv fprintf(out, "%s ...\n", argv[1]);
233 1.1 tv print_header(inp);
234 1.1 tv }
235 1.4 tv fprintf(out, "%s", argv[1]);
236 1.1 tv if ((flags & TRACE_ARGS) && argc > 2) {
237 1.1 tv char delim[3];
238 1.1 tv int i;
239 1.1 tv
240 1.1 tv delim[0] = LPAREN;
241 1.1 tv delim[1] = EOS;
242 1.1 tv for (i = 2; i < argc; i++) {
243 1.4 tv fprintf(out, "%s%s%s%s", delim,
244 1.1 tv (flags & TRACE_QUOTE) ? lquote : "",
245 1.1 tv argv[i],
246 1.1 tv (flags & TRACE_QUOTE) ? rquote : "");
247 1.1 tv delim[0] = COMMA;
248 1.1 tv delim[1] = ' ';
249 1.1 tv delim[2] = EOS;
250 1.1 tv }
251 1.4 tv fprintf(out, "%c", RPAREN);
252 1.1 tv }
253 1.1 tv if (flags & TRACE_CONT) {
254 1.4 tv fprintf(out, " -> ???\n");
255 1.1 tv print_header(inp);
256 1.4 tv fprintf(out, argc > 2 ? "%s(...)" : "%s", argv[1]);
257 1.1 tv }
258 1.1 tv if (flags & TRACE_EXPANSION)
259 1.1 tv return buffer_mark();
260 1.1 tv else {
261 1.4 tv fprintf(out, "\n");
262 1.1 tv return -1;
263 1.1 tv }
264 1.1 tv }
265 1.1 tv
266 1.1 tv void
267 1.1 tv finish_trace(mark)
268 1.1 tv size_t mark;
269 1.1 tv {
270 1.4 tv FILE *out = traceout ? traceout : stderr;
271 1.4 tv
272 1.4 tv fprintf(out, " -> ");
273 1.1 tv if (flags & TRACE_QUOTE)
274 1.4 tv fprintf(out, "%s", lquote);
275 1.4 tv dump_buffer(out, mark);
276 1.1 tv if (flags & TRACE_QUOTE)
277 1.4 tv fprintf(out, "%s", rquote);
278 1.4 tv fprintf(out, "\n");
279 1.1 tv }
280