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