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