1 /* $OpenBSD: trace.c,v 1.10 2003/06/30 22:13:33 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 #define TRACE_ARGS 1 39 #define TRACE_EXPANSION 2 40 #define TRACE_QUOTE 4 41 #define TRACE_FILENAME 8 42 #define TRACE_LINENO 16 43 #define TRACE_CONT 32 44 #define TRACE_ID 64 45 #define TRACE_NEWFILE 128 /* not implemented yet */ 46 #define TRACE_INPUT 256 /* not implemented yet */ 47 48 static unsigned int letter_to_flag(int); 49 static void print_header(struct input_file *); 50 static struct t *find_trace_entry(const char *); 51 static int frame_level(void); 52 53 54 unsigned int trace_flags = TRACE_QUOTE | TRACE_EXPANSION; 55 56 void 57 trace_file(const char *name) 58 { 59 60 if (traceout != stderr) 61 fclose(traceout); 62 traceout = fopen(name, "w"); 63 if (!traceout) 64 err(1, "can't open %s", name); 65 } 66 67 static unsigned int 68 letter_to_flag(int c) 69 { 70 switch(c) { 71 case 'a': 72 return TRACE_ARGS; 73 case 'e': 74 return TRACE_EXPANSION; 75 case 'q': 76 return TRACE_QUOTE; 77 case 'c': 78 return TRACE_CONT; 79 case 'x': 80 return TRACE_ID; 81 case 'f': 82 return TRACE_FILENAME; 83 case 'l': 84 return TRACE_LINENO; 85 case 'p': 86 return TRACE_NEWFILE; 87 case 'i': 88 return TRACE_INPUT; 89 case 't': 90 return TRACE_ALL; 91 case 'V': 92 return ~0; 93 default: 94 return 0; 95 } 96 } 97 98 void 99 set_trace_flags(const char *s) 100 { 101 char mode = 0; 102 unsigned int f = 0; 103 104 if (*s == '+' || *s == '-') 105 mode = *s++; 106 while (*s) 107 f |= letter_to_flag(*s++); 108 switch(mode) { 109 case 0: 110 trace_flags = f; 111 break; 112 case '+': 113 trace_flags |= f; 114 break; 115 case '-': 116 trace_flags &= ~f; 117 break; 118 } 119 } 120 121 static int 122 frame_level() 123 { 124 int level; 125 int framep; 126 127 for (framep = fp, level = 0; framep != 0; 128 level++,framep = mstack[framep-3].sfra) 129 ; 130 return level; 131 } 132 133 static void 134 print_header(struct input_file *inp) 135 { 136 fprintf(traceout, "m4trace:"); 137 if (trace_flags & TRACE_FILENAME) 138 fprintf(traceout, "%s:", inp->name); 139 if (trace_flags & TRACE_LINENO) 140 fprintf(traceout, "%lu:", inp->lineno); 141 fprintf(traceout, " -%d- ", frame_level()); 142 if (trace_flags & TRACE_ID) 143 fprintf(traceout, "id %lu: ", expansion_id); 144 } 145 146 ssize_t 147 trace(const char *argv[], int argc, struct input_file *inp) 148 { 149 print_header(inp); 150 if (trace_flags & TRACE_CONT) { 151 fprintf(traceout, "%s ...\n", argv[1]); 152 print_header(inp); 153 } 154 fprintf(traceout, "%s", argv[1]); 155 if ((trace_flags & TRACE_ARGS) && argc > 2) { 156 char delim[3]; 157 int i; 158 159 delim[0] = LPAREN; 160 delim[1] = EOS; 161 for (i = 2; i < argc; i++) { 162 fprintf(traceout, "%s%s%s%s", delim, 163 (trace_flags & TRACE_QUOTE) ? lquote : "", 164 argv[i], 165 (trace_flags & TRACE_QUOTE) ? rquote : ""); 166 delim[0] = COMMA; 167 delim[1] = ' '; 168 delim[2] = EOS; 169 } 170 fprintf(traceout, "%c", RPAREN); 171 } 172 if (trace_flags & TRACE_CONT) { 173 fprintf(traceout, " -> ???\n"); 174 print_header(inp); 175 fprintf(traceout, argc > 2 ? "%s(...)" : "%s", argv[1]); 176 } 177 if (trace_flags & TRACE_EXPANSION) 178 return buffer_mark(); 179 else { 180 fprintf(traceout, "\n"); 181 return -1; 182 } 183 } 184 185 void 186 finish_trace(size_t mark) 187 { 188 fprintf(traceout, " -> "); 189 if (trace_flags & TRACE_QUOTE) 190 fprintf(traceout, "%s", lquote); 191 dump_buffer(traceout, mark); 192 if (trace_flags & TRACE_QUOTE) 193 fprintf(traceout, "%s", rquote); 194 fprintf(traceout, "\n"); 195 } 196