* src/Makefile.am (m4_LDADD): Add any gnulib dependent libraries.
[m4/ericb.git] / src / debug.c
blob3dfe0f3f53c54caa5fd091cfeb7d6e6e74451156
1 /* GNU m4 -- A simple macro processor
3 Copyright (C) 1991, 1992, 1993, 1994, 2004, 2006 Free Software
4 Foundation, Inc.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA
22 #include "m4.h"
24 #include <stdarg.h>
25 #include <sys/stat.h>
27 /* File for debugging output. */
28 FILE *debug = NULL;
30 /* Obstack for trace messages. */
31 static struct obstack trace;
33 extern int expansion_level;
35 static void debug_set_file (FILE *);
37 /*----------------------------------.
38 | Initialise the debugging module. |
39 `----------------------------------*/
41 void
42 debug_init (void)
44 debug_set_file (stderr);
45 obstack_init (&trace);
48 /*-----------------------------------------------------------------.
49 | Function to decode the debugging flags OPTS. Used by main while |
50 | processing option -d, and by the builtin debugmode (). |
51 `-----------------------------------------------------------------*/
53 int
54 debug_decode (const char *opts)
56 int level;
58 if (opts == NULL || *opts == '\0')
59 level = DEBUG_TRACE_DEFAULT;
60 else
62 for (level = 0; *opts; opts++)
64 switch (*opts)
66 case 'a':
67 level |= DEBUG_TRACE_ARGS;
68 break;
70 case 'e':
71 level |= DEBUG_TRACE_EXPANSION;
72 break;
74 case 'q':
75 level |= DEBUG_TRACE_QUOTE;
76 break;
78 case 't':
79 level |= DEBUG_TRACE_ALL;
80 break;
82 case 'l':
83 level |= DEBUG_TRACE_LINE;
84 break;
86 case 'f':
87 level |= DEBUG_TRACE_FILE;
88 break;
90 case 'p':
91 level |= DEBUG_TRACE_PATH;
92 break;
94 case 'c':
95 level |= DEBUG_TRACE_CALL;
96 break;
98 case 'i':
99 level |= DEBUG_TRACE_INPUT;
100 break;
102 case 'x':
103 level |= DEBUG_TRACE_CALLID;
104 break;
106 case 'V':
107 level |= DEBUG_TRACE_VERBOSE;
108 break;
110 default:
111 return -1;
116 /* This is to avoid screwing up the trace output due to changes in the
117 debug_level. */
119 obstack_free (&trace, obstack_finish (&trace));
121 return level;
124 /*------------------------------------------------------------------------.
125 | Change the debug output stream to FP. If the underlying file is the |
126 | same as stdout, use stdout instead so that debug messages appear in the |
127 | correct relative position. |
128 `------------------------------------------------------------------------*/
130 static void
131 debug_set_file (FILE *fp)
133 struct stat stdout_stat, debug_stat;
135 if (debug != NULL && debug != stderr && debug != stdout
136 && close_stream (debug) != 0)
138 M4ERROR ((warning_status, errno, "error writing to debug stream"));
139 retcode = EXIT_FAILURE;
141 debug = fp;
143 if (debug != NULL && debug != stdout)
145 if (fstat (STDOUT_FILENO, &stdout_stat) < 0)
146 return;
147 if (fstat (fileno (debug), &debug_stat) < 0)
148 return;
150 /* mingw has a bug where fstat on a regular file reports st_ino
151 of 0. On normal system, st_ino should never be 0. */
152 if (stdout_stat.st_ino == debug_stat.st_ino
153 && stdout_stat.st_dev == debug_stat.st_dev
154 && stdout_stat.st_ino != 0)
156 if (debug != stderr && close_stream (debug) != 0)
158 M4ERROR ((warning_status, errno,
159 "error writing to debug stream"));
160 retcode = EXIT_FAILURE;
162 debug = stdout;
167 /*-----------------------------------------------------------.
168 | Serialize files. Used before executing a system command. |
169 `-----------------------------------------------------------*/
171 void
172 debug_flush_files (void)
174 fflush (stdout);
175 fflush (stderr);
176 if (debug != NULL && debug != stdout && debug != stderr)
177 fflush (debug);
178 /* POSIX requires that if m4 doesn't consume all input, but stdin is
179 opened on a seekable file, that the file pointer be left at the
180 next character on exit (but places no restrictions on the file
181 pointer location on a non-seekable file). It also requires that
182 fflush() followed by fseek() on an input file set the underlying
183 file pointer. However, fflush() on a non-seekable file can lose
184 buffered data, which we might otherwise want to process after
185 syscmd. Hence, we must check whether stdin is seekable. We must
186 also be tolerant of operating with stdin closed, so we don't
187 report any failures in this attempt. The stdio-safer module and
188 friends are essential, so that if stdin was closed, this lseek is
189 not on some other file that we have since opened. Mingw has bugs
190 when using fseek on text files, so we only strive for POSIX
191 behavior when we detect a UNIX environment. */
192 #if UNIX
193 if (lseek (STDIN_FILENO, 0, SEEK_CUR) >= 0
194 && fflush (stdin) == 0)
196 fseek (stdin, 0, SEEK_CUR);
198 #endif /* UNIX */
201 /*-------------------------------------------------------------------------.
202 | Change the debug output to file NAME. If NAME is NULL, debug output is |
203 | reverted to stderr, and if empty debug output is discarded. Return TRUE |
204 | iff the output stream was changed. |
205 `-------------------------------------------------------------------------*/
207 boolean
208 debug_set_output (const char *name)
210 FILE *fp;
212 if (name == NULL)
213 debug_set_file (stderr);
214 else if (*name == '\0')
215 debug_set_file (NULL);
216 else
218 fp = fopen (name, "a");
219 if (fp == NULL)
220 return FALSE;
222 if (set_cloexec_flag (fileno (fp), true) != 0)
223 M4ERROR ((warning_status, errno,
224 "Warning: cannot protect debug file across forks"));
225 debug_set_file (fp);
227 return TRUE;
230 /*-----------------------------------------------------------------------.
231 | Print the header of a one-line debug message, starting by "m4 debug". |
232 `-----------------------------------------------------------------------*/
234 void
235 debug_message_prefix (void)
237 fprintf (debug, "m4debug:");
238 if (current_line)
240 if (debug_level & DEBUG_TRACE_FILE)
241 fprintf (debug, "%s:", current_file);
242 if (debug_level & DEBUG_TRACE_LINE)
243 fprintf (debug, "%d:", current_line);
245 putc (' ', debug);
248 /* The rest of this file contains the functions for macro tracing output.
249 All tracing output for a macro call is collected on an obstack TRACE,
250 and printed whenever the line is complete. This prevents tracing
251 output from interfering with other debug messages generated by the
252 various builtins. */
254 /*---------------------------------------------------------------------.
255 | Tracing output is formatted here, by a simplified printf-to-obstack |
256 | function trace_format (). Understands only %S, %s, %d, %l (optional |
257 | left quote) and %r (optional right quote). |
258 `---------------------------------------------------------------------*/
260 static void
261 trace_format (const char *fmt, ...)
263 va_list args;
264 char ch;
266 int d;
267 char nbuf[32];
268 const char *s;
269 int slen;
270 int maxlen;
272 va_start (args, fmt);
274 while (TRUE)
276 while ((ch = *fmt++) != '\0' && ch != '%')
277 obstack_1grow (&trace, ch);
279 if (ch == '\0')
280 break;
282 maxlen = 0;
283 switch (*fmt++)
285 case 'S':
286 maxlen = max_debug_argument_length;
287 /* fall through */
289 case 's':
290 s = va_arg (args, const char *);
291 break;
293 case 'l':
294 s = (debug_level & DEBUG_TRACE_QUOTE) ? lquote.string : "";
295 break;
297 case 'r':
298 s = (debug_level & DEBUG_TRACE_QUOTE) ? rquote.string : "";
299 break;
301 case 'd':
302 d = va_arg (args, int);
303 sprintf (nbuf, "%d", d);
304 s = nbuf;
305 break;
307 default:
308 s = "";
309 break;
312 slen = strlen (s);
313 if (maxlen == 0 || maxlen > slen)
314 obstack_grow (&trace, s, slen);
315 else
317 obstack_grow (&trace, s, maxlen);
318 obstack_grow (&trace, "...", 3);
322 va_end (args);
325 /*------------------------------------------------------------------.
326 | Format the standard header attached to all tracing output lines. |
327 `------------------------------------------------------------------*/
329 static void
330 trace_header (int id)
332 trace_format ("m4trace:");
333 if (current_line)
335 if (debug_level & DEBUG_TRACE_FILE)
336 trace_format ("%s:", current_file);
337 if (debug_level & DEBUG_TRACE_LINE)
338 trace_format ("%d:", current_line);
340 trace_format (" -%d- ", expansion_level);
341 if (debug_level & DEBUG_TRACE_CALLID)
342 trace_format ("id %d: ", id);
345 /*----------------------------------------------------.
346 | Print current tracing line, and clear the obstack. |
347 `----------------------------------------------------*/
349 static void
350 trace_flush (void)
352 char *line;
354 obstack_1grow (&trace, '\0');
355 line = obstack_finish (&trace);
356 DEBUG_PRINT1 ("%s\n", line);
357 obstack_free (&trace, line);
360 /*-------------------------------------------------------------.
361 | Do pre-argument-collction tracing for macro NAME. Used from |
362 | expand_macro (). |
363 `-------------------------------------------------------------*/
365 void
366 trace_prepre (const char *name, int id)
368 trace_header (id);
369 trace_format ("%s ...", name);
370 trace_flush ();
373 /*-----------------------------------------------------------------------.
374 | Format the parts of a trace line, that can be made before the macro is |
375 | actually expanded. Used from expand_macro (). |
376 `-----------------------------------------------------------------------*/
378 void
379 trace_pre (const char *name, int id, int argc, token_data **argv)
381 int i;
382 const builtin *bp;
384 trace_header (id);
385 trace_format ("%s", name);
387 if (argc > 1 && (debug_level & DEBUG_TRACE_ARGS))
389 trace_format ("(");
391 for (i = 1; i < argc; i++)
393 if (i != 1)
394 trace_format (", ");
396 switch (TOKEN_DATA_TYPE (argv[i]))
398 case TOKEN_TEXT:
399 trace_format ("%l%S%r", TOKEN_DATA_TEXT (argv[i]));
400 break;
402 case TOKEN_FUNC:
403 bp = find_builtin_by_addr (TOKEN_DATA_FUNC (argv[i]));
404 if (bp == NULL)
406 M4ERROR ((warning_status, 0, "\
407 INTERNAL ERROR: builtin not found in builtin table! (trace_pre ())"));
408 abort ();
410 trace_format ("<%s>", bp->name);
411 break;
413 default:
414 M4ERROR ((warning_status, 0,
415 "INTERNAL ERROR: bad token data type (trace_pre ())"));
416 abort ();
420 trace_format (")");
423 if (debug_level & DEBUG_TRACE_CALL)
425 trace_format (" -> ???");
426 trace_flush ();
430 /*-------------------------------------------------------------------.
431 | Format the final part of a trace line and print it all. Used from |
432 | expand_macro (). |
433 `-------------------------------------------------------------------*/
435 void
436 trace_post (const char *name, int id, int argc, token_data **argv,
437 const char *expanded)
439 if (debug_level & DEBUG_TRACE_CALL)
441 trace_header (id);
442 trace_format ("%s%s", name, (argc > 1) ? "(...)" : "");
445 if (expanded && (debug_level & DEBUG_TRACE_EXPANSION))
446 trace_format (" -> %l%S%r", expanded);
447 trace_flush ();