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