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