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