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