From ac4e202fc3afcea4e7698413ce8b4764fcdc4f6b Mon Sep 17 00:00:00 2001
From: Raphael 'kena' Poss <r.c.poss@uva.nl>
Date: Wed, 6 Oct 2010 22:52:44 +0200
Subject: [PATCH] Add support for resetting '__file__' and '__line__'.

* src/input.c (reset_line, reset_file): Add functions to reset the
current location.
* src/m4.h: Declare them.
* src/builtin.c (m4___file__, m4___line__): Use them.

* doc/m4.texinfo (Location): Document the new feature. Add a
test.
* NEWS: Document the new feature.
---
 ChangeLog     | 12 ++++++++++++
 NEWS          |  1 +
 doc/m4.texi   | 32 +++++++++++++++++++++++++++++++-
 src/builtin.c | 26 ++++++++++++++++++++------
 src/input.c   | 19 +++++++++++++++++++
 src/m4.h      |  5 +++++
 6 files changed, 88 insertions(+), 7 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 5643bea..97ff1a5 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2014-10-17  Raphael 'kena' Poss  <knz@thaumogen.net>
+
+	Add support for resetting '__file__' and '__line__'.
+	* src/input.c (reset_line, reset_file): Add functions to reset the
+	current location.
+	* src/m4.h: Declare them.
+	* src/builtin.c (m4___file__, m4___line__): Use them.
+
+	* doc/m4.texinfo (Location): Document the new feature. Add a
+	test.
+	* NEWS: Document the new feature.
+
 2014-05-13  Eric Blake  <eblake@redhat.com>
 
 	doc: fix line-wrapped macro definitions
diff --git a/NEWS b/NEWS
index 029b34a..2bbc7c8 100644
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,7 @@ GNU M4 NEWS - User visible changes.
 
 * Noteworthy changes in release ?.? (????-??-??) [?]
 
+** Add support for resetting '__file__' and '__line__'.
 
 * Noteworthy changes in release 1.4.17 (2013-09-22) [stable]
 
diff --git a/doc/m4.texi b/doc/m4.texi
index 2960cff..973d6cf 100644
--- a/doc/m4.texi
+++ b/doc/m4.texi
@@ -6992,7 +6992,9 @@
 @samp{f} and @samp{l} flags of @code{debugmode} (@pxref{Debug Levels}),
 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.
+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}):
@@ -7050,6 +7052,34 @@
 @result{}6
 @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 e101838..c4fe0d5 100644
--- a/src/builtin.c
+++ b/src/builtin.c
@@ -1495,19 +1495,33 @@ m4_errprint (struct obstack *obs, int argc, token_data **argv)
 static void
 m4___file__ (struct obstack *obs, int argc, token_data **argv)
 {
-  if (bad_argc (argv[0], argc, 1, 1))
+  if (bad_argc (argv[0], argc, 0, 2))
     return;
-  obstack_grow (obs, lquote.string, lquote.length);
-  obstack_grow (obs, current_file, strlen (current_file));
-  obstack_grow (obs, rquote.string, rquote.length);
+  if (argc > 1)
+    reset_file (ARG (1));
+  else
+    {
+      obstack_grow (obs, lquote.string, lquote.length);
+      obstack_grow (obs, current_file, strlen (current_file));
+      obstack_grow (obs, rquote.string, rquote.length);
+    }
 }
 
 static void
 m4___line__ (struct obstack *obs, int argc, token_data **argv)
 {
-  if (bad_argc (argv[0], argc, 1, 1))
+    int line;
+
+  if (bad_argc (argv[0], argc, 0, 2))
     return;
-  shipout_int (obs, current_line);
+  if (argc > 1)
+    {
+      if (!numeric_arg (argv[0], ARG (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 80d5b34..5d84a3e 100644
--- a/src/input.c
+++ b/src/input.c
@@ -1154,3 +1154,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.h b/src/m4.h
index 0889d91..f7e772d 100644
--- a/src/m4.h
+++ b/src/m4.h
@@ -461,6 +461,11 @@ extern void expand_format (struct obstack *, int, token_data **);
 extern void produce_frozen_state (const char *);
 extern 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
-- 
1.8.2.2

