* src/m4.c: Add new option `--synclines-cpp'. * src/output.c: Change syncline format when --synclines-cpp is set.
* src/input.c: Allow to change input line number and file name. * src/m4.h: Expose new primitives from input.c. * src/builtin.c: Use them in __file__ and __line__. * doc/m4.texinfo: Document the new features. * NEWS: Announce them. --- Hi Eric, as you suggested I reworked the patch from 1.6, and included documentation with example and test code. Let me know if there is anything else to improve. Cheers, k NEWS | 6 ++++++ doc/m4.texinfo | 48 +++++++++++++++++++++++++++++++++++++++++++----- src/builtin.c | 26 ++++++++++++++++++++------ src/input.c | 19 +++++++++++++++++++ src/m4.c | 8 ++++++++ src/m4.h | 5 +++++ src/output.c | 2 +- 7 files changed, 102 insertions(+), 12 deletions(-) diff --git a/NEWS b/NEWS index f1d641a..72f0d50 100644 --- a/NEWS +++ b/NEWS @@ -147,6 +147,12 @@ contains the following beta features that were deemed worth deferring until algorithms based on `$@' operate in linear, rather than quadratic, time and memory. +** Enhance the `__file__' and `__line__' builtins so that the input + line number and file name can be reset. + +** A new `--synclines-cpp' option changes the format of synchronization + lines to mimic the C preprocessor. + ** A number of portability improvements inherited from gnulib. * Noteworthy changes in Version 1.4.13 (2009-04-01) [stable] diff --git a/doc/m4.texinfo b/doc/m4.texinfo index 0182979..0a4305f 100644 --- a/doc/m4.texinfo +++ b/doc/m4.texinfo @@ -780,6 +780,15 @@ @result{}goodbye @end example +...@item --synclines-cpp + +This provides identical behavior to @option{-s} or @option{--synclines}, +but with a different synchronization line format suitable for a C +compiler without a C preprocessor. With this option synchronization +lines are of the form @samp{# @var{line} "@var{file}"}. This format is +suitable when M4 is used as a substitute to the C preprocessor or as a +filter between preprocessing and compilation. + @item -U @var{name} @itemx --undefi...@var{name} This deletes any predefined meaning @var{name} might have. Obviously, @@ -7711,11 +7720,12 @@ Line numbers start at 1 for each file. If the file was found due to the @option{-I} option or @env{M4PATH} environment variable, that is reflected in the file name. The syncline option (@option{-s}, -...@pxref{preprocessor features, , Invoking m4}), and the -...@samp{f} and @samp{l} flags of @code{debugmode} (@pxref{Debugmode}), -also use this notion of current file and line. Redefining the three -location macros has no effect on syncline, debug, warning, or error -message output. +...@pxref{preprocessor features, , Invoking m4}), and the @samp{f} and +...@samp{l} flags of @code{debugmode} (@pxref{Debugmode}), also use this +notion of current file and line. Redefining the three location macros +has no effect on syncline, debug, warning, or error message output, +although the line numbers and file names can be reset as described +below. This example reuses the file @file{incl.m4} mentioned earlier (@pxref{Include}): @@ -7773,6 +7783,34 @@ @result{}12 @end example +The @co...@w{__file__}} and @co...@w{__line__}} macros take an optional +argument which allow to reset the current input file name and line +number, respectively. If @option{-s} is enabled, a synchronization line +will be emitted at the next newline in the input. Input line numbers +will autoincrement from the new value, and the file name will stay +active for the current input source until the input source is exhausted +or the name is reset again. This feature can be used when the input to +M4 already contains synchronization information, as when M4 is used as a +filter between a preprocessor and a compiler. + +...@comment options: -s +...@example +$ @kbd{m4 -s} +foo __line__(42)bar __line__ +baz __line__ +__line__ +...@result{}#line 1 "stdin" +...@result{}foo bar 42 +...@result{}#line 43 +...@result{}baz 43 +...@result{}44 +foo __file__(`newname')bar __file__ +baz __file__ +...@result{}foo bar newname +...@result{}#line 46 "newname" +...@result{}baz newname +...@end example + The @co...@w{__program__}} macro behaves like @samp{$0} in shell terminology. If you invoke @code{m4} through an absolute path or a link with a different spelling, rather than by relying on a @env{PATH} search diff --git a/src/builtin.c b/src/builtin.c index 191e05d..f9f35a6 100644 --- a/src/builtin.c +++ b/src/builtin.c @@ -1700,17 +1700,31 @@ m4_errprint (struct obstack *obs, int argc, macro_arguments *argv) static void m4___file__ (struct obstack *obs, int argc, macro_arguments *argv) { - bad_argc (arg_info (argv), argc, 0, 0); - obstack_grow (obs, curr_quote.str1, curr_quote.len1); - obstack_grow (obs, current_file, strlen (current_file)); - obstack_grow (obs, curr_quote.str2, curr_quote.len2); + bad_argc (arg_info (argv), argc, 0, 1); + if (argc > 1) + reset_file (ARG (1)); + else + { + obstack_grow (obs, curr_quote.str1, curr_quote.len1); + obstack_grow (obs, current_file, strlen (current_file)); + obstack_grow (obs, curr_quote.str2, curr_quote.len2); + } } static void m4___line__ (struct obstack *obs, int argc, macro_arguments *argv) { - bad_argc (arg_info (argv), argc, 0, 0); - shipout_int (obs, current_line); + int line; + + bad_argc (arg_info (argv), argc, 0, 1); + if (argc > 1) + { + if (!numeric_arg (arg_info (argv), ARG (1), ARG_LEN (1), &line)) + return; + reset_line (line); + } + else + shipout_int (obs, current_line); } static void diff --git a/src/input.c b/src/input.c index 129a5f2..940f975 100644 --- a/src/input.c +++ b/src/input.c @@ -2301,3 +2301,22 @@ lex_debug (void) print_token ("lex", t, &td); } #endif /* DEBUG_INPUT */ + +/*---------------------------------. + | Reset the current line counter. | + `--------------------------------*/ +void reset_line(int line) +{ + isp->line = line; + input_change = true; +} + +/*-------------------------------. + | Reset the current file title. | + `------------------------------*/ +void reset_file(const char *title) +{ + isp->file = (char *) obstack_copy0 (&file_names, title, strlen (title)); + output_current_line = -1; + input_change = true; +} diff --git a/src/m4.c b/src/m4.c index 0caf868..9189298 100644 --- a/src/m4.c +++ b/src/m4.c @@ -237,6 +237,7 @@ Preprocessor features:\n\ -D, --define=NAME[=VALUE] define NAME as having VALUE, or empty\n\ -I, --include=DIRECTORY append DIRECTORY to include path\n\ -s, --synclines generate `#line NUM \"FILE\"' lines\n\ + --synclines-cpp generate `# NUM \"FILE\" lines\n\ -U, --undefine=NAME undefine NAME\n\ "), stdout); puts (""); @@ -307,6 +308,7 @@ enum { DEBUGFILE_OPTION = CHAR_MAX + 1, /* no short opt */ WARN_MACRO_SEQUENCE_OPTION, /* no short opt */ + SYNCLINES_CPP_OPTION, /* no short opt */ HELP_OPTION, /* no short opt */ VERSION_OPTION /* no short opt */ @@ -331,6 +333,7 @@ static const struct option long_options[] = {"reload-state", required_argument, NULL, 'R'}, {"silent", no_argument, NULL, 'Q'}, {"synclines", no_argument, NULL, 's'}, + {"synclines-cpp", no_argument, NULL, SYNCLINES_CPP_OPTION}, {"trace", required_argument, NULL, 't'}, {"traditional", no_argument, NULL, 'G'}, {"undefine", required_argument, NULL, 'U'}, @@ -463,6 +466,7 @@ main (int argc, char *const *argv, char *const *envp) case 's': case 't': case DEBUGFILE_OPTION: + case SYNCLINES_CPP_OPTION: defer: /* Arguments that cannot be handled until later are accumulated. */ @@ -652,6 +656,10 @@ main (int argc, char *const *argv, char *const *envp) sync_output = 1; break; + case SYNCLINES_CPP_OPTION: + sync_output = 2; + break; + case '\1': process_file (arg); break; diff --git a/src/m4.h b/src/m4.h index 17184b2..6ed671d 100644 --- a/src/m4.h +++ b/src/m4.h @@ -562,6 +562,11 @@ void expand_format (struct obstack *, int, macro_arguments *); void produce_frozen_state (const char *); void reload_frozen_state (const char *); +/* File: input.c --- input sources. */ + +void reset_line (int); +void reset_file (const char *); + /* Debugging the memory allocator. */ #ifdef WITH_DMALLOC diff --git a/src/output.c b/src/output.c index e31f94b..0c09c5b 100644 --- a/src/output.c +++ b/src/output.c @@ -665,7 +665,7 @@ divert_text (struct obstack *obs, const char *text, int length, int line) if (output_current_line != line) { static char line_buf[sizeof "#line " + INT_BUFSIZE_BOUND (line)]; - sprintf (line_buf, "#line %d", line); + sprintf (line_buf, (sync_output == 1) ? "#line %d" : "# %d", line); output_text (line_buf, strlen (line_buf)); assert (strlen (line_buf) < sizeof line_buf); if (output_current_line < 1 && current_file[0] != '\0') -- 1.6.3.2 _______________________________________________ M4-patches mailing list M4-patches@gnu.org http://lists.gnu.org/mailman/listinfo/m4-patches