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