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