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