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