1e3d86717SJuli Mallett /* $OpenBSD: trace.c,v 1.4 2002/02/16 21:27:48 millert 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> 35e3d86717SJuli Mallett #include "mdef.h" 36e3d86717SJuli Mallett #include "stdd.h" 37e3d86717SJuli Mallett #include "extern.h" 38e3d86717SJuli Mallett 39acc9d408SJuli Mallett FILE *traceout; 40e3d86717SJuli Mallett 41e3d86717SJuli Mallett int traced_macros = 0; 42e3d86717SJuli Mallett 43e3d86717SJuli Mallett #define TRACE_ARGS 1 44e3d86717SJuli Mallett #define TRACE_EXPANSION 2 45e3d86717SJuli Mallett #define TRACE_QUOTE 4 46e3d86717SJuli Mallett #define TRACE_FILENAME 8 47e3d86717SJuli Mallett #define TRACE_LINENO 16 48e3d86717SJuli Mallett #define TRACE_CONT 32 49e3d86717SJuli Mallett #define TRACE_ID 64 50e3d86717SJuli Mallett #define TRACE_NEWFILE 128 /* not implemented yet */ 51e3d86717SJuli Mallett #define TRACE_INPUT 256 /* not implemented yet */ 52e3d86717SJuli Mallett #define TRACE_ALL 512 53e3d86717SJuli Mallett 54e3d86717SJuli Mallett static struct t { 55e3d86717SJuli Mallett struct t *next; 56e3d86717SJuli Mallett char *name; 57e3d86717SJuli Mallett int on; 58e3d86717SJuli Mallett } *l; 59e3d86717SJuli Mallett 60e3d86717SJuli Mallett static unsigned int letter_to_flag(int); 61e3d86717SJuli Mallett static void print_header(struct input_file *); 62e3d86717SJuli Mallett static struct t *find_trace_entry(const char *); 63e3d86717SJuli Mallett static int frame_level(void); 64e3d86717SJuli Mallett 65e3d86717SJuli Mallett static unsigned int flags = TRACE_QUOTE | TRACE_EXPANSION; 66e3d86717SJuli Mallett 67e3d86717SJuli Mallett static struct t * 68e3d86717SJuli Mallett find_trace_entry(name) 69e3d86717SJuli Mallett 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 81e3d86717SJuli Mallett mark_traced(name, on) 82e3d86717SJuli Mallett const char *name; 83e3d86717SJuli Mallett int on; 84e3d86717SJuli Mallett { 85e3d86717SJuli Mallett struct t *n, *n2; 86e3d86717SJuli Mallett 87e3d86717SJuli Mallett traced_macros = 1; 88e3d86717SJuli Mallett 89e3d86717SJuli Mallett if (name == NULL) { 90e3d86717SJuli Mallett if (on) 91e3d86717SJuli Mallett flags |= TRACE_ALL; 92e3d86717SJuli Mallett else { 93e3d86717SJuli Mallett flags &= ~TRACE_ALL; 94e3d86717SJuli Mallett traced_macros = 0; 95e3d86717SJuli Mallett } 96e3d86717SJuli Mallett for (n = l; n != NULL; n = n2) { 97e3d86717SJuli Mallett n2 = n->next; 98e3d86717SJuli Mallett free(n->name); 99e3d86717SJuli Mallett free(n); 100e3d86717SJuli Mallett } 101e3d86717SJuli Mallett l = NULL; 102e3d86717SJuli Mallett } else { 103e3d86717SJuli Mallett n = find_trace_entry(name); 104e3d86717SJuli Mallett if (n == NULL) { 105e3d86717SJuli Mallett n = xalloc(sizeof(struct t)); 106e3d86717SJuli Mallett n->name = xstrdup(name); 107e3d86717SJuli Mallett n->next = l; 108e3d86717SJuli Mallett l = n; 109e3d86717SJuli Mallett } 110e3d86717SJuli Mallett n->on = on; 111e3d86717SJuli Mallett } 112e3d86717SJuli Mallett } 113e3d86717SJuli Mallett 114e3d86717SJuli Mallett int 115e3d86717SJuli Mallett is_traced(name) 116e3d86717SJuli Mallett const char *name; 117e3d86717SJuli Mallett { 118e3d86717SJuli Mallett struct t *n; 119e3d86717SJuli Mallett 120e3d86717SJuli Mallett for (n = l; n != NULL; n = n->next) 121e3d86717SJuli Mallett if (STREQ(n->name, name)) 122e3d86717SJuli Mallett return n->on; 123e3d86717SJuli Mallett return (flags & TRACE_ALL) ? 1 : 0; 124e3d86717SJuli Mallett } 125e3d86717SJuli Mallett 126e3d86717SJuli Mallett void 127e3d86717SJuli Mallett trace_file(name) 128e3d86717SJuli Mallett const char *name; 129e3d86717SJuli Mallett { 130e3d86717SJuli Mallett 131e3d86717SJuli Mallett if (traceout != stderr) 132e3d86717SJuli Mallett fclose(traceout); 133e3d86717SJuli Mallett traceout = fopen(name, "w"); 134e3d86717SJuli Mallett if (!traceout) 135e3d86717SJuli Mallett err(1, "can't open %s", name); 136e3d86717SJuli Mallett } 137e3d86717SJuli Mallett 138e3d86717SJuli Mallett static unsigned int 139e3d86717SJuli Mallett letter_to_flag(c) 140e3d86717SJuli Mallett int c; 141e3d86717SJuli Mallett { 142e3d86717SJuli Mallett switch(c) { 143e3d86717SJuli Mallett case 'a': 144e3d86717SJuli Mallett return TRACE_ARGS; 145e3d86717SJuli Mallett case 'e': 146e3d86717SJuli Mallett return TRACE_EXPANSION; 147e3d86717SJuli Mallett case 'q': 148e3d86717SJuli Mallett return TRACE_QUOTE; 149e3d86717SJuli Mallett case 'c': 150e3d86717SJuli Mallett return TRACE_CONT; 151e3d86717SJuli Mallett case 'x': 152e3d86717SJuli Mallett return TRACE_ID; 153e3d86717SJuli Mallett case 'f': 154e3d86717SJuli Mallett return TRACE_FILENAME; 155e3d86717SJuli Mallett case 'l': 156e3d86717SJuli Mallett return TRACE_LINENO; 157e3d86717SJuli Mallett case 'p': 158e3d86717SJuli Mallett return TRACE_NEWFILE; 159e3d86717SJuli Mallett case 'i': 160e3d86717SJuli Mallett return TRACE_INPUT; 161e3d86717SJuli Mallett case 't': 162e3d86717SJuli Mallett return TRACE_ALL; 163e3d86717SJuli Mallett case 'V': 164e3d86717SJuli Mallett return ~0; 165e3d86717SJuli Mallett default: 166e3d86717SJuli Mallett return 0; 167e3d86717SJuli Mallett } 168e3d86717SJuli Mallett } 169e3d86717SJuli Mallett 170e3d86717SJuli Mallett void 171e3d86717SJuli Mallett set_trace_flags(s) 172e3d86717SJuli Mallett const char *s; 173e3d86717SJuli Mallett { 174e3d86717SJuli Mallett char mode = 0; 175e3d86717SJuli Mallett unsigned int f = 0; 176e3d86717SJuli Mallett 177e3d86717SJuli Mallett traced_macros = 1; 178e3d86717SJuli Mallett 179e3d86717SJuli Mallett if (*s == '+' || *s == '-') 180e3d86717SJuli Mallett mode = *s++; 181e3d86717SJuli Mallett while (*s) 182e3d86717SJuli Mallett f |= letter_to_flag(*s++); 183e3d86717SJuli Mallett switch(mode) { 184e3d86717SJuli Mallett case 0: 185e3d86717SJuli Mallett flags = f; 186e3d86717SJuli Mallett break; 187e3d86717SJuli Mallett case '+': 188e3d86717SJuli Mallett flags |= f; 189e3d86717SJuli Mallett break; 190e3d86717SJuli Mallett case '-': 191e3d86717SJuli Mallett flags &= ~f; 192e3d86717SJuli Mallett break; 193e3d86717SJuli Mallett } 194e3d86717SJuli Mallett } 195e3d86717SJuli Mallett 196e3d86717SJuli Mallett static int 197e3d86717SJuli Mallett frame_level() 198e3d86717SJuli Mallett { 199e3d86717SJuli Mallett int level; 200e3d86717SJuli Mallett int framep; 201e3d86717SJuli Mallett 202e3d86717SJuli Mallett for (framep = fp, level = 0; framep != 0; 203e3d86717SJuli Mallett level++,framep = mstack[framep-2].sfra) 204e3d86717SJuli Mallett ; 205e3d86717SJuli Mallett return level; 206e3d86717SJuli Mallett } 207e3d86717SJuli Mallett 208e3d86717SJuli Mallett static void 209e3d86717SJuli Mallett print_header(inp) 210e3d86717SJuli Mallett struct input_file *inp; 211e3d86717SJuli Mallett { 212e3d86717SJuli Mallett fprintf(traceout, "m4trace:"); 213e3d86717SJuli Mallett if (flags & TRACE_FILENAME) 214e3d86717SJuli Mallett fprintf(traceout, "%s:", inp->name); 215e3d86717SJuli Mallett if (flags & TRACE_LINENO) 216e3d86717SJuli Mallett fprintf(traceout, "%lu:", inp->lineno); 217e3d86717SJuli Mallett fprintf(traceout, " -%d- ", frame_level()); 218e3d86717SJuli Mallett if (flags & TRACE_ID) 219e3d86717SJuli Mallett fprintf(traceout, "id %lu: ", expansion_id); 220e3d86717SJuli Mallett } 221e3d86717SJuli Mallett 222e3d86717SJuli Mallett ssize_t 223e3d86717SJuli Mallett trace(argv, argc, inp) 224e3d86717SJuli Mallett const char **argv; 225e3d86717SJuli Mallett int argc; 226e3d86717SJuli Mallett struct input_file *inp; 227e3d86717SJuli Mallett { 228e3d86717SJuli Mallett print_header(inp); 229e3d86717SJuli Mallett if (flags & TRACE_CONT) { 230e3d86717SJuli Mallett fprintf(traceout, "%s ...\n", argv[1]); 231e3d86717SJuli Mallett print_header(inp); 232e3d86717SJuli Mallett } 233e3d86717SJuli Mallett fprintf(traceout, "%s", argv[1]); 234e3d86717SJuli Mallett if ((flags & TRACE_ARGS) && argc > 2) { 235e3d86717SJuli Mallett char delim[3]; 236e3d86717SJuli Mallett int i; 237e3d86717SJuli Mallett 238e3d86717SJuli Mallett delim[0] = LPAREN; 239e3d86717SJuli Mallett delim[1] = EOS; 240e3d86717SJuli Mallett for (i = 2; i < argc; i++) { 241e3d86717SJuli Mallett fprintf(traceout, "%s%s%s%s", delim, 242e3d86717SJuli Mallett (flags & TRACE_QUOTE) ? lquote : "", 243e3d86717SJuli Mallett argv[i], 244e3d86717SJuli Mallett (flags & TRACE_QUOTE) ? rquote : ""); 245e3d86717SJuli Mallett delim[0] = COMMA; 246e3d86717SJuli Mallett delim[1] = ' '; 247e3d86717SJuli Mallett delim[2] = EOS; 248e3d86717SJuli Mallett } 249e3d86717SJuli Mallett fprintf(traceout, "%c", RPAREN); 250e3d86717SJuli Mallett } 251e3d86717SJuli Mallett if (flags & TRACE_CONT) { 252e3d86717SJuli Mallett fprintf(traceout, " -> ???\n"); 253e3d86717SJuli Mallett print_header(inp); 254e3d86717SJuli Mallett fprintf(traceout, argc > 2 ? "%s(...)" : "%s", argv[1]); 255e3d86717SJuli Mallett } 256e3d86717SJuli Mallett if (flags & TRACE_EXPANSION) 257e3d86717SJuli Mallett return buffer_mark(); 258e3d86717SJuli Mallett else { 259e3d86717SJuli Mallett fprintf(traceout, "\n"); 260e3d86717SJuli Mallett return -1; 261e3d86717SJuli Mallett } 262e3d86717SJuli Mallett } 263e3d86717SJuli Mallett 264e3d86717SJuli Mallett void 265e3d86717SJuli Mallett finish_trace(mark) 266e3d86717SJuli Mallett size_t mark; 267e3d86717SJuli Mallett { 268e3d86717SJuli Mallett fprintf(traceout, " -> "); 269e3d86717SJuli Mallett if (flags & TRACE_QUOTE) 270e3d86717SJuli Mallett fprintf(traceout, "%s", lquote); 271e3d86717SJuli Mallett dump_buffer(traceout, mark); 272e3d86717SJuli Mallett if (flags & TRACE_QUOTE) 273e3d86717SJuli Mallett fprintf(traceout, "%s", rquote); 274e3d86717SJuli Mallett fprintf(traceout, "\n"); 275e3d86717SJuli Mallett } 276