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