* doc/m4.texinfo (Compatibility): Sync with head.
[m4/ericb.git] / src / debug.c
blob2c4860f207912305b35505080a7707a7844feb56
1 /* GNU m4 -- A simple macro processor
3 Copyright (C) 1991, 1992, 1993, 1994, 2004, 2006, 2007 Free Software
4 Foundation, Inc.
6 This file is part of GNU M4.
8 GNU M4 is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
13 GNU M4 is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
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 fseeko() on an input file set the underlying
183 file pointer, and gnulib guarantees these semantics. However,
184 fflush() on a non-seekable file can lose buffered data, which we
185 might otherwise want to process after syscmd. Hence, we must
186 check whether stdin is seekable. We must also be tolerant of
187 operating with stdin closed, so we don't report any failures in
188 this attempt. The stdio-safer module and friends are essential,
189 so that if stdin was closed, this lseek is not on some other file
190 that we have since opened. */
191 if (lseek (STDIN_FILENO, 0, SEEK_CUR) >= 0
192 && fflush (stdin) == 0)
194 fseeko (stdin, 0, SEEK_CUR);
198 /*-------------------------------------------------------------------------.
199 | Change the debug output to file NAME. If NAME is NULL, debug output is |
200 | reverted to stderr, and if empty debug output is discarded. Return true |
201 | iff the output stream was changed. |
202 `-------------------------------------------------------------------------*/
204 bool
205 debug_set_output (const char *name)
207 FILE *fp;
209 if (name == NULL)
210 debug_set_file (stderr);
211 else if (*name == '\0')
212 debug_set_file (NULL);
213 else
215 fp = fopen (name, "a");
216 if (fp == NULL)
217 return false;
219 if (set_cloexec_flag (fileno (fp), true) != 0)
220 M4ERROR ((warning_status, errno,
221 "Warning: cannot protect debug file across forks"));
222 debug_set_file (fp);
224 return true;
227 /*-----------------------------------------------------------------------.
228 | Print the header of a one-line debug message, starting by "m4 debug". |
229 `-----------------------------------------------------------------------*/
231 void
232 debug_message_prefix (void)
234 fprintf (debug, "m4debug:");
235 if (current_line)
237 if (debug_level & DEBUG_TRACE_FILE)
238 fprintf (debug, "%s:", current_file);
239 if (debug_level & DEBUG_TRACE_LINE)
240 fprintf (debug, "%d:", current_line);
242 putc (' ', debug);
245 /* The rest of this file contains the functions for macro tracing output.
246 All tracing output for a macro call is collected on an obstack TRACE,
247 and printed whenever the line is complete. This prevents tracing
248 output from interfering with other debug messages generated by the
249 various builtins. */
251 /*---------------------------------------------------------------------.
252 | Tracing output is formatted here, by a simplified printf-to-obstack |
253 | function trace_format (). Understands only %S, %s, %d, %l (optional |
254 | left quote) and %r (optional right quote). |
255 `---------------------------------------------------------------------*/
257 static void
258 trace_format (const char *fmt, ...)
260 va_list args;
261 char ch;
263 int d;
264 char nbuf[32];
265 const char *s;
266 int slen;
267 int maxlen;
269 va_start (args, fmt);
271 while (true)
273 while ((ch = *fmt++) != '\0' && ch != '%')
274 obstack_1grow (&trace, ch);
276 if (ch == '\0')
277 break;
279 maxlen = 0;
280 switch (*fmt++)
282 case 'S':
283 maxlen = max_debug_argument_length;
284 /* fall through */
286 case 's':
287 s = va_arg (args, const char *);
288 break;
290 case 'l':
291 s = (debug_level & DEBUG_TRACE_QUOTE) ? lquote.string : "";
292 break;
294 case 'r':
295 s = (debug_level & DEBUG_TRACE_QUOTE) ? rquote.string : "";
296 break;
298 case 'd':
299 d = va_arg (args, int);
300 sprintf (nbuf, "%d", d);
301 s = nbuf;
302 break;
304 default:
305 s = "";
306 break;
309 slen = strlen (s);
310 if (maxlen == 0 || maxlen > slen)
311 obstack_grow (&trace, s, slen);
312 else
314 obstack_grow (&trace, s, maxlen);
315 obstack_grow (&trace, "...", 3);
319 va_end (args);
322 /*------------------------------------------------------------------.
323 | Format the standard header attached to all tracing output lines. |
324 `------------------------------------------------------------------*/
326 static void
327 trace_header (int id)
329 trace_format ("m4trace:");
330 if (current_line)
332 if (debug_level & DEBUG_TRACE_FILE)
333 trace_format ("%s:", current_file);
334 if (debug_level & DEBUG_TRACE_LINE)
335 trace_format ("%d:", current_line);
337 trace_format (" -%d- ", expansion_level);
338 if (debug_level & DEBUG_TRACE_CALLID)
339 trace_format ("id %d: ", id);
342 /*----------------------------------------------------.
343 | Print current tracing line, and clear the obstack. |
344 `----------------------------------------------------*/
346 static void
347 trace_flush (void)
349 char *line;
351 obstack_1grow (&trace, '\0');
352 line = (char *) obstack_finish (&trace);
353 DEBUG_PRINT1 ("%s\n", line);
354 obstack_free (&trace, line);
357 /*-------------------------------------------------------------.
358 | Do pre-argument-collction tracing for macro NAME. Used from |
359 | expand_macro (). |
360 `-------------------------------------------------------------*/
362 void
363 trace_prepre (const char *name, int id)
365 trace_header (id);
366 trace_format ("%s ...", name);
367 trace_flush ();
370 /*-----------------------------------------------------------------------.
371 | Format the parts of a trace line, that can be made before the macro is |
372 | actually expanded. Used from expand_macro (). |
373 `-----------------------------------------------------------------------*/
375 void
376 trace_pre (const char *name, int id, int argc, token_data **argv)
378 int i;
379 const builtin *bp;
381 trace_header (id);
382 trace_format ("%s", name);
384 if (argc > 1 && (debug_level & DEBUG_TRACE_ARGS))
386 trace_format ("(");
388 for (i = 1; i < argc; i++)
390 if (i != 1)
391 trace_format (", ");
393 switch (TOKEN_DATA_TYPE (argv[i]))
395 case TOKEN_TEXT:
396 trace_format ("%l%S%r", TOKEN_DATA_TEXT (argv[i]));
397 break;
399 case TOKEN_FUNC:
400 bp = find_builtin_by_addr (TOKEN_DATA_FUNC (argv[i]));
401 if (bp == NULL)
403 M4ERROR ((warning_status, 0, "\
404 INTERNAL ERROR: builtin not found in builtin table! (trace_pre ())"));
405 abort ();
407 trace_format ("<%s>", bp->name);
408 break;
410 default:
411 M4ERROR ((warning_status, 0,
412 "INTERNAL ERROR: bad token data type (trace_pre ())"));
413 abort ();
417 trace_format (")");
420 if (debug_level & DEBUG_TRACE_CALL)
422 trace_format (" -> ???");
423 trace_flush ();
427 /*-------------------------------------------------------------------.
428 | Format the final part of a trace line and print it all. Used from |
429 | expand_macro (). |
430 `-------------------------------------------------------------------*/
432 void
433 trace_post (const char *name, int id, int argc, token_data **argv,
434 const char *expanded)
436 if (debug_level & DEBUG_TRACE_CALL)
438 trace_header (id);
439 trace_format ("%s%s", name, (argc > 1) ? "(...)" : "");
442 if (expanded && (debug_level & DEBUG_TRACE_EXPANSION))
443 trace_format (" -> %l%S%r", expanded);
444 trace_flush ();