1 /* GNU m4 -- A simple macro processor
2 Copyright (C) 1991-1994, 2006-2010, 2013-2014 Free Software
5 This file is part of GNU M4.
7 GNU M4 is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 GNU M4 is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
26 #include "m4private.h"
27 #include "close-stream.h"
29 static void set_debug_file (m4
*, const m4_call_info
*, FILE *);
33 /* Function to decode the debugging flags OPTS of length LEN; or
34 SIZE_MAX if OPTS is NUL-terminated. If OPTS is NULL, use the
35 default flags. Used by main while processing option -d, and by the
36 builtin debugmode (). */
38 m4_debug_decode (m4
*context
, const char *opts
, size_t len
)
40 int previous
= context
->debug_level
;
49 level
= M4_DEBUG_TRACE_DEFAULT
| previous
;
52 if (*opts
== '-' || *opts
== '+')
57 for (level
= 0; len
--; opts
++)
62 level
|= M4_DEBUG_TRACE_ARGS
;
66 level
|= M4_DEBUG_TRACE_EXPANSION
;
70 level
|= M4_DEBUG_TRACE_QUOTE
;
74 level
|= M4_DEBUG_TRACE_ALL
;
78 level
|= M4_DEBUG_TRACE_LINE
;
82 level
|= M4_DEBUG_TRACE_FILE
;
86 level
|= M4_DEBUG_TRACE_PATH
;
90 level
|= M4_DEBUG_TRACE_CALL
;
94 level
|= M4_DEBUG_TRACE_INPUT
;
98 level
|= M4_DEBUG_TRACE_CALLID
;
102 level
|= M4_DEBUG_TRACE_MODULE
;
106 level
|= M4_DEBUG_TRACE_STACK
;
110 level
|= M4_DEBUG_TRACE_DEREF
;
114 level
|= M4_DEBUG_TRACE_OUTPUT_DUMPDEF
;
118 level
|= M4_DEBUG_TRACE_VERBOSE
;
130 /* Replace old level. */
134 /* Subtract flags. */
135 level
= previous
& ~level
;
144 assert (!"m4_debug_decode");
146 context
->debug_level
= level
;
150 /* Change the debug output stream to FP. If the underlying file is the
151 same as stdout, use stdout instead so that debug messages appear in the
152 correct relative position. Report errors on behalf of CALLER. */
154 set_debug_file (m4
*context
, const m4_call_info
*caller
, FILE *fp
)
157 struct stat stdout_stat
, debug_stat
;
161 debug_file
= m4_get_debug_file (context
);
162 if (debug_file
!= NULL
&& debug_file
!= stderr
&& debug_file
!= stdout
163 && close_stream (debug_file
) != 0)
164 m4_error (context
, 0, errno
, caller
, _("error writing to debug stream"));
167 m4_set_debug_file (context
, fp
);
169 if (debug_file
!= NULL
&& debug_file
!= stdout
)
171 if (fstat (fileno (stdout
), &stdout_stat
) < 0)
173 if (fstat (fileno (debug_file
), &debug_stat
) < 0)
176 /* mingw has a bug where fstat on a regular file reports st_ino
177 of 0. On normal system, st_ino should never be 0. */
178 if (stdout_stat
.st_ino
== debug_stat
.st_ino
179 && stdout_stat
.st_dev
== debug_stat
.st_dev
180 && stdout_stat
.st_ino
!= 0)
182 if (debug_file
!= stderr
&& close_stream (debug_file
) != 0)
183 m4_error (context
, 0, errno
, caller
,
184 _("error writing to debug stream"));
185 m4_set_debug_file (context
, stdout
);
190 /* Change the debug output to file NAME. If NAME is NULL, debug
191 output is reverted to stderr, and if empty debug output is
192 discarded. Return true iff the output stream was changed. Report
193 errors on behalf of CALLER. */
195 m4_debug_set_output (m4
*context
, const m4_call_info
*caller
, const char *name
)
202 set_debug_file (context
, caller
, stderr
);
203 else if (*name
== '\0')
204 set_debug_file (context
, caller
, NULL
);
207 fp
= fopen (name
, "a");
211 if (set_cloexec_flag (fileno (fp
), true) != 0)
212 m4_warn (context
, errno
, caller
,
213 _("cannot protect debug file across forks"));
214 set_debug_file (context
, caller
, fp
);
219 /* Print the header of a one-line debug message, starting with "m4debug:". */
221 m4_debug_message_prefix (m4
*context
)
227 debug_file
= m4_get_debug_file (context
);
228 fputs ("m4debug:", debug_file
);
229 if (m4_get_current_line (context
))
231 if (m4_is_debug_bit (context
, M4_DEBUG_TRACE_FILE
))
232 xfprintf (debug_file
, "%s:", m4_get_current_file (context
));
233 if (m4_is_debug_bit (context
, M4_DEBUG_TRACE_LINE
))
234 xfprintf (debug_file
, "%d:", m4_get_current_line (context
));
236 putc (' ', debug_file
);
239 /* If the current debug mode includes MODE, and there is a current
240 debug file, then output a debug message described by FORMAT. A
241 message header is supplied, as well as a trailing newline. */
243 m4_debug_message (m4
*context
, int mode
, const char *format
, ...)
245 /* Check that mode has exactly one bit set. */
246 assert (mode
&& (mode
& (mode
- 1)) == 0);
249 if (m4_get_debug_file (context
) != NULL
250 && m4_is_debug_bit (context
, mode
))
254 m4_debug_message_prefix (context
);
255 va_start (args
, format
);
256 xvfprintf (m4_get_debug_file (context
), format
, args
);
258 putc ('\n', m4_get_debug_file (context
));