1228063Sbapt/* $OpenBSD: trace.c,v 1.16 2010/09/07 19:58:09 marco Exp $ */ 290744Sjmallett/* 390744Sjmallett * Copyright (c) 2001 Marc Espie. 490744Sjmallett * 590744Sjmallett * Redistribution and use in source and binary forms, with or without 690744Sjmallett * modification, are permitted provided that the following conditions 790744Sjmallett * are met: 890744Sjmallett * 1. Redistributions of source code must retain the above copyright 990744Sjmallett * notice, this list of conditions and the following disclaimer. 1090744Sjmallett * 2. Redistributions in binary form must reproduce the above copyright 1190744Sjmallett * notice, this list of conditions and the following disclaimer in the 1290744Sjmallett * documentation and/or other materials provided with the distribution. 1390744Sjmallett * 1490744Sjmallett * THIS SOFTWARE IS PROVIDED BY THE OPENBSD PROJECT AND CONTRIBUTORS 1590744Sjmallett * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1690744Sjmallett * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1790744Sjmallett * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OPENBSD 1890744Sjmallett * PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 1990744Sjmallett * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 2090744Sjmallett * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2190744Sjmallett * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2290744Sjmallett * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2390744Sjmallett * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 2490744Sjmallett * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2590744Sjmallett */ 2695060Sjmallett#include <sys/cdefs.h> 2795060Sjmallett__FBSDID("$FreeBSD$"); 2895060Sjmallett 29228063Sbapt#include <err.h> 3090744Sjmallett#include <stddef.h> 31228063Sbapt#include <stdint.h> 3290744Sjmallett#include <stdio.h> 3390744Sjmallett#include <stdlib.h> 3490744Sjmallett#include "mdef.h" 3590744Sjmallett#include "stdd.h" 3690744Sjmallett#include "extern.h" 3790744Sjmallett 3895060SjmallettFILE *traceout; 3990744Sjmallett 40228063Sbapt#define TRACE_ARGS 1 4190744Sjmallett#define TRACE_EXPANSION 2 4290744Sjmallett#define TRACE_QUOTE 4 4390744Sjmallett#define TRACE_FILENAME 8 4490744Sjmallett#define TRACE_LINENO 16 4590744Sjmallett#define TRACE_CONT 32 4690744Sjmallett#define TRACE_ID 64 4790744Sjmallett#define TRACE_NEWFILE 128 /* not implemented yet */ 4890744Sjmallett#define TRACE_INPUT 256 /* not implemented yet */ 4990744Sjmallett 5090744Sjmallettstatic unsigned int letter_to_flag(int); 5190744Sjmallettstatic void print_header(struct input_file *); 5290744Sjmallettstatic int frame_level(void); 5390744Sjmallett 5490744Sjmallett 55228063Sbaptunsigned int trace_flags = TRACE_QUOTE | TRACE_EXPANSION; 5690744Sjmallett 5790744Sjmallettvoid 5895887Sjmalletttrace_file(const char *name) 5990744Sjmallett{ 6090744Sjmallett 61228063Sbapt if (traceout && traceout != stderr) 6290744Sjmallett fclose(traceout); 6390744Sjmallett traceout = fopen(name, "w"); 6490744Sjmallett if (!traceout) 6590744Sjmallett err(1, "can't open %s", name); 6690744Sjmallett} 6790744Sjmallett 6890744Sjmallettstatic unsigned int 6995887Sjmallettletter_to_flag(int c) 7090744Sjmallett{ 7190744Sjmallett switch(c) { 7290744Sjmallett case 'a': 7390744Sjmallett return TRACE_ARGS; 7490744Sjmallett case 'e': 7590744Sjmallett return TRACE_EXPANSION; 7690744Sjmallett case 'q': 7790744Sjmallett return TRACE_QUOTE; 7890744Sjmallett case 'c': 7990744Sjmallett return TRACE_CONT; 8090744Sjmallett case 'x': 8190744Sjmallett return TRACE_ID; 8290744Sjmallett case 'f': 8390744Sjmallett return TRACE_FILENAME; 8490744Sjmallett case 'l': 8590744Sjmallett return TRACE_LINENO; 8690744Sjmallett case 'p': 8790744Sjmallett return TRACE_NEWFILE; 8890744Sjmallett case 'i': 8990744Sjmallett return TRACE_INPUT; 9090744Sjmallett case 't': 9190744Sjmallett return TRACE_ALL; 9290744Sjmallett case 'V': 9390744Sjmallett return ~0; 9490744Sjmallett default: 9590744Sjmallett return 0; 9690744Sjmallett } 9790744Sjmallett} 9890744Sjmallett 9990744Sjmallettvoid 10095887Sjmallettset_trace_flags(const char *s) 10190744Sjmallett{ 10290744Sjmallett char mode = 0; 10390744Sjmallett unsigned int f = 0; 10490744Sjmallett 10590744Sjmallett if (*s == '+' || *s == '-') 10690744Sjmallett mode = *s++; 10790744Sjmallett while (*s) 10890744Sjmallett f |= letter_to_flag(*s++); 10990744Sjmallett switch(mode) { 11090744Sjmallett case 0: 111228063Sbapt trace_flags = f; 11290744Sjmallett break; 11390744Sjmallett case '+': 114228063Sbapt trace_flags |= f; 11590744Sjmallett break; 11690744Sjmallett case '-': 117228063Sbapt trace_flags &= ~f; 11890744Sjmallett break; 11990744Sjmallett } 12090744Sjmallett} 12190744Sjmallett 12290744Sjmallettstatic int 12399939Sjmallettframe_level(void) 12490744Sjmallett{ 12590744Sjmallett int level; 12690744Sjmallett int framep; 12790744Sjmallett 128100014Sjmallett for (framep = fp, level = 0; framep != 0; 129228063Sbapt level++,framep = mstack[framep-3].sfra) 13090744Sjmallett ; 13190744Sjmallett return level; 13290744Sjmallett} 13390744Sjmallett 13490744Sjmallettstatic void 13595887Sjmallettprint_header(struct input_file *inp) 13690744Sjmallett{ 13790744Sjmallett fprintf(traceout, "m4trace:"); 138228063Sbapt if (trace_flags & TRACE_FILENAME) 13990744Sjmallett fprintf(traceout, "%s:", inp->name); 140228063Sbapt if (trace_flags & TRACE_LINENO) 14190744Sjmallett fprintf(traceout, "%lu:", inp->lineno); 14290744Sjmallett fprintf(traceout, " -%d- ", frame_level()); 143228063Sbapt if (trace_flags & TRACE_ID) 14490744Sjmallett fprintf(traceout, "id %lu: ", expansion_id); 14590744Sjmallett} 14690744Sjmallett 147228063Sbaptsize_t 14895887Sjmalletttrace(const char *argv[], int argc, struct input_file *inp) 14990744Sjmallett{ 150228063Sbapt if (!traceout) 151228063Sbapt traceout = stderr; 15290744Sjmallett print_header(inp); 153228063Sbapt if (trace_flags & TRACE_CONT) { 15490744Sjmallett fprintf(traceout, "%s ...\n", argv[1]); 15590744Sjmallett print_header(inp); 15690744Sjmallett } 15790744Sjmallett fprintf(traceout, "%s", argv[1]); 158228063Sbapt if ((trace_flags & TRACE_ARGS) && argc > 2) { 15990744Sjmallett char delim[3]; 16090744Sjmallett int i; 16190744Sjmallett 16290744Sjmallett delim[0] = LPAREN; 16390744Sjmallett delim[1] = EOS; 16490744Sjmallett for (i = 2; i < argc; i++) { 165100014Sjmallett fprintf(traceout, "%s%s%s%s", delim, 166228063Sbapt (trace_flags & TRACE_QUOTE) ? lquote : "", 167100014Sjmallett argv[i], 168228063Sbapt (trace_flags & TRACE_QUOTE) ? rquote : ""); 16990744Sjmallett delim[0] = COMMA; 17090744Sjmallett delim[1] = ' '; 17190744Sjmallett delim[2] = EOS; 17290744Sjmallett } 17390744Sjmallett fprintf(traceout, "%c", RPAREN); 17490744Sjmallett } 175228063Sbapt if (trace_flags & TRACE_CONT) { 17690744Sjmallett fprintf(traceout, " -> ???\n"); 17790744Sjmallett print_header(inp); 17890744Sjmallett fprintf(traceout, argc > 2 ? "%s(...)" : "%s", argv[1]); 17990744Sjmallett } 180228063Sbapt if (trace_flags & TRACE_EXPANSION) 18190744Sjmallett return buffer_mark(); 18290744Sjmallett else { 18390744Sjmallett fprintf(traceout, "\n"); 184228063Sbapt return SIZE_MAX; 18590744Sjmallett } 18690744Sjmallett} 18790744Sjmallett 188100014Sjmallettvoid 18995887Sjmallettfinish_trace(size_t mark) 19090744Sjmallett{ 19190744Sjmallett fprintf(traceout, " -> "); 192228063Sbapt if (trace_flags & TRACE_QUOTE) 19390744Sjmallett fprintf(traceout, "%s", lquote); 19490744Sjmallett dump_buffer(traceout, mark); 195228063Sbapt if (trace_flags & TRACE_QUOTE) 19690744Sjmallett fprintf(traceout, "%s", rquote); 19790744Sjmallett fprintf(traceout, "\n"); 19890744Sjmallett} 199