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