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