I'm hoping to add a debugmode(+r) to toggle whether to warn on
suspicious regex constructs. But I couldn't do it in m4 1.4.x, in
part because debugmode() warns on unrecognized flags. It will be
easier to add new flags in the future if it is also possible to query
the set of flags known by m4, as well as the current state of those
flags. And the easiest way to do that was to have debugmode(?) output
a string containing both the set and cleared flags, which means the
parser has to accept that as well. For back-compat with 1.4.x,
debugmode(-) is once again synonymous with clearing the default flags
but leaving others in place. And the earlier change to make 'm4 -d'
behave like 'm4 -d+adeq' but 'debugmode()' behave like
'debugmode(aeqt)' is too complex to maintain; it's simpler to have the
empty argument set the default rather than add the default.
* doc/m4.texi (Debugging options): Tweak example to match code.
(Debugmode): Mention qindir, missed in previous patch. Document new
ability to support + and - in same string, and new ? for query.
* src/builtin.c (m4_debugmode): Handle new "?" case.
* src/m4.h (debug_dump): New declaration.
* src/debug.c (debug_dump): New function.
(debug_set): New helper, factored out of...
(debug_decode): ...here. Restore 1.4.x compatibility with parsing
"", "-", and "+". Support more than one "-" and "+" in a string.
* NEWS: Document this.
---
NEWS | 9 ++++-
doc/m4.texi | 60 ++++++++++++++++++++++++----
src/builtin.c | 9 +++--
src/debug.c | 106 +++++++++++++++++++++++++++++++++++++-------------
src/m4.h | 1 +
5 files changed, 144 insertions(+), 41 deletions(-)
diff --git a/NEWS b/NEWS
index 89cafe6e..97c4d9c0 100644
--- a/NEWS
+++ b/NEWS
@@ -68,15 +68,20 @@ GNU M4 NEWS - User visible changes.
** The `-d'/`--debug' command-line option now understands `-' and `+'
modifiers, the way the builtin `debugmode' has always done; this allows
`-d-V' to disable prior debug settings from the command line, similar to
- using the builtin `debugmode' without arguments. The option
+ using the builtin `debugmode' without arguments. The mode string can
+ now contain `-' or `+' at more than just the first byte. The option
`--debugmode' is added as an alias for `-d'. The new flag `d' is added
to control whether dereferencing an undefined macro causes a warning.
The new flag `o' is added to control whether `dumpdef' outputs to stderr
or the current `debugfile' location. When the command line option is
- given the empty string, the mode is treated as `+adeq' instead of `aeq'.
+ given the empty string, the mode is treated as `adeq' instead of `aeq'.
Also, the position of `-d' with respect to files on the command line is
now significant.
+** The `debugmode' builtin (but not the `-d' command line option) now
+ understands an argument of "?" as a request to expand to a quoted string
+ describing the current debug flag settings.
+
** A new `qindir' builtin is added, similar to `indir', but where the
output is quoted rather than rescanned for further macro expansion.
diff --git a/doc/m4.texi b/doc/m4.texi
index 23052e0d..bdfe9c0c 100644
--- a/doc/m4.texi
+++ b/doc/m4.texi
@@ -918,7 +918,7 @@ Debugging options
controls the format and amount of information presented by the debugging
functions. @xref{Debugmode}, for more details on the format and
meaning of @var{flags}. If @var{flags} is omitted, it defaults to
-@samp{+adeq}. If the option occurs multiple times, @var{flags} starting
+@samp{adeq}. If the option occurs multiple times, @var{flags} starting
with @samp{-} or @samp{+} are cumulative, while @var{flags} starting
with a letter override all earlier settings. The debug-level starts
with no flags enabled. To disable all
@@ -933,9 +933,9 @@ Debugging options
The cumulative effect of the various options in this example is
equivalent to a single invocation of @code{debugmode(`adlqx')}:
-@comment options: -d-V -d+lx --debug --debugmode=-e
+@comment options: -d-V --debug -d+x --debugmode=-e+l
@example
-$ @kbd{m4 -d+lx --debug --debugmode=-e}
+$ @kbd{m4 --debug -d+x --debugmode=-e+l}
traceon(`len')
@result{}
len(`123')
@@ -4579,14 +4579,15 @@ Debugmode
@item d
Output a warning on any attempt to dereference an undefined macro via
@code{builtin}, @code{defn}, @code{dumpdef}, @code{indir},
-@code{popdef}, or @code{undefine}. Note that @code{indef},
+@code{popdef}, @code{qindir}, or @code{undefine}. Note that @code{ifdef},
@code{traceon}, and @code{traceoff} do not dereference undefined macros.
Like any other warning, the warnings enabled by this flag go to standard
error regardless of the current @code{debugfile} setting, and will
change exit status if the command line option @option{--fatal-warnings}
was specified. This flag is useful in diagnosing spelling mistakes in
macro names. It is enabled by default when neither @option{--debug} nor
-@option{--fatal-warnings} are specified on the command line.
+@option{--fatal-warnings} are specified on the command line. This flag
+was introduced in M4 1.6.
@item e
In trace output, show the expansion of each macro call, if it is not
@@ -4610,7 +4611,8 @@ Debugmode
@item o
Output @code{dumpdef} data to standard error instead of the current
debug file. This can be useful when post-processing trace output, where
-interleaving dumpdef and trace output can cause ambiguities.
+interleaving dumpdef and trace output can cause ambiguities. This flag
+was introduced in M4 1.6.
@item p
In debug output, print a message when a named file is found through the
@@ -4652,9 +4654,15 @@ Debugmode
added to the current debug flags, and if it starts with a @samp{-}, they
are removed. If no argument is present, all debugging flags are cleared
(as if by @samp{-V}), and with an empty argument the flags are reset to
-the default of @samp{+adeq}.
+the default of @samp{+adeq}. As of M4 1.6, it is possible to use both
+@samp{+} and @samp{-} in the same invocation. M4 1.6 also added the
+ability to query the current debug flags, by passing @var{flags} of
+exactly @samp{?}.
-The expansion of @code{debugmode} is void.
+The expansion of @code{debugmode} is void, unless @var{flags} is
+@samp{?}; in that case, the output is a quoted string that can be
+passed back to a future @code{debugmode} call to restore flags to the
+current state.
@end deffn
@comment options: -d-V
@@ -4728,6 +4736,42 @@ Debugmode
@error{}m4debug: input exhausted
@end example
+This example shows how to query the current flags, then change them for
+a bit, before restoring them. Since future versions of M4 may
+understand additional flags, the ability to query known flags also
+serves as a way to learn if a given flag is understood by the current
+version of M4, when writing a script that wants to take advantage of a
+new flag when available but still operate without warnings on older M4.
+
+@example
+$ @kbd{m4 -d}
+debugmode(`?')
+@result{}+adeq-cfiloptx
+popdef(`unknown')
+@result{}
+@error{}m4:stdin:2: warning: popdef: undefined macro 'unknown'
+define(`flags', debugmode(?))dnl
+ifelse(index(defn(`flags'), `d'), -1, ``flag d unknown'',
+ `debugmode(`-d')')
+@result{}
+popdef(`unknown')
+@result{}
+debugmode(`?')
+@result{}+aeq-cdfiloptx
+debugmode(defn(`flags'))
+@result{}
+debugmode(`?')
+@result{}+adeq-cfiloptx
+define(`x', `X')
+@result{}
+debugmode(`+x')
+@result{}
+debugmode(`-')
+@result{}
+debugmode(`?')
+@result{}+x-acdefilopqt
+@end example
+
@node Debugfile
@section Saving debugging output
diff --git a/src/builtin.c b/src/builtin.c
index ce00e9eb..bf0d1798 100644
--- a/src/builtin.c
+++ b/src/builtin.c
@@ -1794,10 +1794,11 @@ m4_traceoff (struct obstack *obs MAYBE_UNUSED, int argc,
/* On-the-fly control of the format of the tracing output. It takes
one argument, which is a character string like that given to the -d
- option, or none in which case the debug_level is zeroed. */
+ option, or none in which case the debug_level is zeroed. In
+ addition to the strings accepted by -d, a single argument of "?"
+ results in a quoted representation of the current flag setting. */
static void
-m4_debugmode (struct obstack *obs MAYBE_UNUSED, int argc,
- macro_arguments *argv)
+m4_debugmode (struct obstack *obs, int argc, macro_arguments *argv)
{
const call_info *me = arg_info (argv);
const char *str = ARG (1);
@@ -1807,6 +1808,8 @@ m4_debugmode (struct obstack *obs MAYBE_UNUSED, int argc,
if (argc == 1)
debug_level = 0;
+ else if (len == 1 && *str == '?')
+ debug_dump (obs);
else if (debug_decode (str, len) < 0)
m4_warn (0, me, _("bad debug flags: %s"),
quotearg_style_mem (locale_quoting_style, str, len));
diff --git a/src/debug.c b/src/debug.c
index 918aabf8..55fedde9 100644
--- a/src/debug.c
+++ b/src/debug.c
@@ -40,6 +40,68 @@ debug_init (void)
obstack_init (&trace);
}
+/* Dump the current set of debug flags into OBS, in a way that can be
+ be passed back to debugmode to restore that state. */
+void
+debug_dump (struct obstack *obs)
+{
+ int i;
+
+ obstack_grow (obs, curr_quote.str1, curr_quote.len1);
+
+#define DEBUG_DUMP(bit, ch) \
+ if (!(debug_level & bit) == (i != '+')) \
+ obstack_1grow (obs, ch)
+
+ /* Both ASCII and EBCDIC sort '+' before '-'. */
+ for (i = '+'; i <= '-'; i += '-' - '+') {
+ obstack_1grow (obs, i);
+ DEBUG_DUMP (DEBUG_TRACE_ARGS, 'a');
+ DEBUG_DUMP (DEBUG_TRACE_CALL, 'c');
+ DEBUG_DUMP (DEBUG_TRACE_DEREF, 'd');
+ DEBUG_DUMP (DEBUG_TRACE_EXPANSION, 'e');
+ DEBUG_DUMP (DEBUG_TRACE_FILE, 'f');
+ DEBUG_DUMP (DEBUG_TRACE_INPUT, 'i');
+ DEBUG_DUMP (DEBUG_TRACE_LINE, 'l');
+ DEBUG_DUMP (DEBUG_TRACE_OUTPUT_DUMPDEF, 'o');
+ DEBUG_DUMP (DEBUG_TRACE_PATH, 'p');
+ DEBUG_DUMP (DEBUG_TRACE_QUOTE, 'q');
+ DEBUG_DUMP (DEBUG_TRACE_ALL, 't');
+ DEBUG_DUMP (DEBUG_TRACE_CALLID, 'x');
+ }
+#undef DEBUG_DUMP
+
+ obstack_grow (obs, curr_quote.str2, curr_quote.len2);
+}
+
+/* Merge LEVEL into ACCUM according to MODE, then set LEVEL to 0. */
+static void
+debug_set (char mode, int *accum, int *level)
+{
+ switch (mode)
+ {
+ case '\0':
+ /* Replace old level. */
+ *accum = *level;
+ break;
+
+ case '-':
+ /* Subtract flags. */
+ *accum &= ~*level;
+ break;
+
+ case '+':
+ /* Add flags. */
+ *accum |= *level;
+ break;
+
+ default:
+ assert (!"debug_set");
+ abort ();
+ }
+ *level = 0;
+}
+
/* Function to decode the debugging flags OPTS of length LEN. If LEN
is SIZE_MAX, use strlen (OPTS) instead. Used by main while
processing option -d, and by the builtin debugmode. Return -1 if
@@ -47,6 +109,7 @@ debug_init (void)
int
debug_decode (const char *opts, size_t len)
{
+ int accum = debug_level;
int level;
char mode = '\0';
@@ -54,15 +117,15 @@ debug_decode (const char *opts, size_t len)
opts = "";
if (len == SIZE_MAX)
len = strlen (opts);
+ if (*opts == '-' || *opts == '+')
+ {
+ len--;
+ mode = *opts++;
+ }
if (!len)
- level = DEBUG_TRACE_DEFAULT | debug_level;
+ level = DEBUG_TRACE_DEFAULT;
else
{
- if (*opts == '-' || *opts == '+')
- {
- len--;
- mode = *opts++;
- }
for (level = 0; len--; opts++)
{
switch (*opts)
@@ -119,33 +182,20 @@ debug_decode (const char *opts, size_t len)
level |= DEBUG_TRACE_VERBOSE;
break;
+ case '-':
+ case '+':
+ debug_set (mode, &accum, &level);
+ mode = *opts;
+ break;
+
default:
return -1;
}
}
}
- switch (mode)
- {
- case '\0':
- /* Replace old level. */
- break;
-
- case '-':
- /* Subtract flags. */
- level = debug_level & ~level;
- break;
-
- case '+':
- /* Add flags. */
- level |= debug_level;
- break;
-
- default:
- assert (!"debug_decode");
- abort ();
- }
- debug_level = level;
- return level;
+ debug_set (mode, &accum, &level);
+ debug_level = accum;
+ return 0;
}
/* Change the debug output stream to FP. If the underlying file is
diff --git a/src/m4.h b/src/m4.h
index 4e5ca5fd..79dca438 100644
--- a/src/m4.h
+++ b/src/m4.h
@@ -206,6 +206,7 @@ extern FILE *debug;
extern void debug_init (void);
extern int debug_decode (const char *, size_t);
+extern void debug_dump (struct obstack *obs);
extern void debug_flush_files (void);
extern bool debug_set_output (const call_info *, const char *);
base-commit: de2ad6ddc904ea07fe9a6f61fa9418b15ffbfc0b
--
2.49.0
_______________________________________________
M4-patches mailing list
[email protected]
https://lists.gnu.org/mailman/listinfo/m4-patches