[PATCH] Improve compatibility between M4 and CPP.

"Raphael 'kena' Poss" <[email protected]>
Newsgroups gmane.comp.gnu.m4.patches
Message-ID <[email protected]>
* 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 --undefine=@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 @code{@w{__file__}} and @code{@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 @code{@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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.