m4-discuss
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Macro + diversion issue


From: Eric Blake
Subject: Re: Macro + diversion issue
Date: Thu, 31 May 2007 07:25:22 -0600
User-agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.10) Gecko/20070221 Thunderbird/1.5.0.10 Mnenhy/0.7.5.666

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

According to Daniel Richard G. on 5/21/2007 1:43 AM:
> In fact, it's a fairly simple patch. See attached for my stab at it. (Also, 
> there's a more straightforward test input file.) I did the two-arg 
> divert(), since that seems more natural than coming up with a new/separate 
> builtin for this.
> 
> I think this fills a hole in the core m4 feature set---right now, as I 
> understand it, the only way to send text to a diversion is at the point 
> when the text is actually being written out. With this, you can send text 
> to a diversion in the same way that errprint() sends text to stderr: 
> immediately upon evaluation of the builtin. Without regard to the invoking 
> context.

Thanks again for the idea.  And in the process of checking this in, I
discovered a regression from a couple days ago in handling hand-crafted
frozen files.  Here's what I'm checking in to head.  I'm porting the
regression fix, but not the new feature, to the branch.

2007-05-31  Eric Blake  <address@hidden>

        Add extension to divert builtin.
        * modules/m4.c (builtin_divert): Immediately divert second
        argument.
        * m4/output.c (m4_output_text): Allow 0 length.  Fixes regression
        from two days ago.
        (m4_shipout_text): Short-circuit on zero length.
        * tests/freeze.at (loading format 2): Expand test to catch
        regression.  Also check out-of-range version.
        * tests/builtins.at (divert): Expand test to check corner cases
        of extension.
        * NEWS: Document the extension.
        Reported by Daniel Richard G.


- --
Don't work too hard, make some time for fun as well!

Eric Blake             address@hidden
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.5 (Cygwin)
Comment: Public key at home.comcast.net/~ericblake/eblake.gpg
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iD8DBQFGXszC84KuGfSFAYARApeAAKDV+0R/8Xxr9rRqn454PGWSASqvrQCfdMJm
yJJrW4hk+IlM9MxWjN8PlwY=
=aDjR
-----END PGP SIGNATURE-----
Index: NEWS
===================================================================
RCS file: /sources/m4/m4/NEWS,v
retrieving revision 1.42
diff -u -p -r1.42 NEWS
--- NEWS        24 Mar 2007 21:29:41 -0000      1.42
+++ NEWS        31 May 2007 13:21:59 -0000
@@ -157,6 +157,11 @@ promoted to 2.0.
     information to the first line to show the definition of the macro being
     expanded.  The 'e' flag has been updated to output non-text expansions.
 
+*** The `divert' builtin now accepts an optional second argument of text
+    that is immediately placed on the new diversion, regardless of whether
+    the current expansion is nested within argument collection of another
+    macro.
+
 *** The `dumpdef' builtin now always outputs to standard error, rather than
     the debug file specified by the `--debugfile' option or `debugfile'
     macro.
Index: doc/m4.texinfo
===================================================================
RCS file: /sources/m4/m4/doc/m4.texinfo,v
retrieving revision 1.105
diff -u -p -r1.105 m4.texinfo
--- doc/m4.texinfo      30 May 2007 13:36:58 -0000      1.105
+++ doc/m4.texinfo      31 May 2007 13:21:59 -0000
@@ -5008,11 +5008,17 @@ input file.
 @cindex files, diverting output to
 Output is diverted using @code{divert}:
 
address@hidden {Builtin (m4)} divert (@dvar{number, 0})
address@hidden {Builtin (m4)} divert (@dvar{number, 0}, @ovar{text})
 The current diversion is changed to @var{number}.  If @var{number} is left
 out or empty, it is assumed to be zero.  If @var{number} cannot be
 parsed, the diversion is unchanged.
 
address@hidden @acronym{GNU} extensions
+As a @acronym{GNU} extension, if optional @var{text} is supplied and
address@hidden was valid, then @var{text} is immediately output to the
+new diversion, regardless of whether the expansion of @code{divert}
+occurred while collecting arguments for another macro.
+
 The expansion of @code{divert} is void.
 @end deffn
 
@@ -5076,6 +5082,44 @@ divert(`2')hello
 @result{}world
 @end example
 
+The ability to immediately output extra text is a @acronym{GNU}
+extension, but it can prove useful for ensuring that text goes to a
+particular diversion no matter how many pending macro expansions are in
+progress.  For a demonstration of why this is useful, it is important to
+understand in the example below why @samp{one} is output in diversion 2,
+not diversion 1, while @samp{three} and @samp{five} both end up in the
+correctly numbered diversion.  The key point is that when @code{divert}
+is executed unquoted as part of the argument collection of another
+macro, the side effect takes place immediately, but the text @samp{one}
+is not passed to any diversion until after the @samp{divert(`2')} and
+the enclosing @code{echo} have also taken place.  The example with
address@hidden shows how following the quoting rule of thumb delays the
+invocation of @code{divert} until it is not nested in any argument
+collection context, while the example with @samp{five} shows the use of
+the optional argument to speed up the output process.
+
address@hidden
+define(`echo', `$1')
address@hidden
+echo(divert(`1')`one'divert(`2'))`'dnl
+echo(`divert(`3')three`'divert(`4')')`'dnl
+echo(divert(`5', `five')divert(`6'))`'dnl
+divert
address@hidden
+undivert(`1')
address@hidden
+undivert(`2')
address@hidden
+undivert(`3')
address@hidden
+undivert(`4')
address@hidden
+undivert(`5')
address@hidden
+undivert(`6')
address@hidden
address@hidden example
+
 Note that @code{divert} is an English word, but also an active macro
 without arguments.  When processing plain text, the word might appear in
 normal text and be unintentionally swallowed as a macro invocation.  One
Index: m4/output.c
===================================================================
RCS file: /sources/m4/m4/m4/output.c,v
retrieving revision 1.44
diff -u -p -r1.44 output.c
--- m4/output.c 28 May 2007 21:48:41 -0000      1.44
+++ m4/output.c 31 May 2007 13:21:59 -0000
@@ -423,6 +423,9 @@ m4_output_text (m4 *context, const char 
 {
   size_t count;
 
+  if (!output_diversion || !length)
+    return;
+
   if (!output_file && length > output_unused)
     make_room_for (context, length);
 
@@ -470,7 +473,7 @@ m4_shipout_text (m4 *context, m4_obstack
 
   /* Do nothing if TEXT should be discarded.  */
 
-  if (output_diversion == NULL)
+  if (!output_diversion || !length)
     return;
 
   /* Output TEXT to a file, or in-memory diversion buffer.  */
Index: modules/m4.c
===================================================================
RCS file: /sources/m4/m4/modules/m4.c,v
retrieving revision 1.109
diff -u -p -r1.109 m4.c
--- modules/m4.c        24 May 2007 20:13:44 -0000      1.109
+++ modules/m4.c        31 May 2007 13:21:59 -0000
@@ -70,7 +70,7 @@ extern void m4_make_temp     (m4 *contex
   BUILTIN (decr,       false,  true,   true,   1,      1  )    \
   BUILTIN (define,     true,   true,   false,  1,      2  )    \
   BUILTIN (defn,       false,  true,   false,  1,      -1 )    \
-  BUILTIN (divert,     false,  false,  false,  0,      1  )    \
+  BUILTIN (divert,     false,  false,  false,  0,      2  )    \
   BUILTIN (divnum,     false,  false,  false,  0,      0  )    \
   BUILTIN (dnl,                false,  false,  false,  0,      0  )    \
   BUILTIN (dumpdef,    false,  false,  false,  0,      -1 )    \
@@ -578,11 +578,16 @@ M4BUILTIN_HANDLER (decr)
 M4BUILTIN_HANDLER (divert)
 {
   int i = 0;
+  const char *text;
 
   if (argc >= 2 && !m4_numeric_arg (context, argc, argv, 1, &i))
     return;
 
   m4_make_diversion (context, i);
+
+  text = M4ARG (2);
+  m4_shipout_text (context, NULL, text, strlen (text),
+                  m4_get_current_line (context));
 }
 
 /* Expand to the current diversion number.  */
Index: tests/builtins.at
===================================================================
RCS file: /sources/m4/m4/tests/builtins.at,v
retrieving revision 1.40
diff -u -p -r1.40 builtins.at
--- tests/builtins.at   12 Apr 2007 17:41:35 -0000      1.40
+++ tests/builtins.at   31 May 2007 13:21:59 -0000
@@ -177,6 +177,17 @@ AT_CHECK_M4([divert.m4], 0,
 Text diverted a second time.
 ]])
 
+dnl Test second divert argument, added for m4 2.0
+AT_DATA([in.m4], [[define(`echo',`$1')dnl
+divert(`-1', `discarded without warning')
+divert`'dnl
+echo(` world'divert(divnum, `hello'))
+]])
+
+AT_CHECK_M4([-s in.m4], [0], [[#line 4 "in.m4"
+hello world
+]])
+
 AT_CLEANUP
 
 
Index: tests/freeze.at
===================================================================
RCS file: /sources/m4/m4/tests/freeze.at,v
retrieving revision 1.11
diff -u -p -r1.11 freeze.at
--- tests/freeze.at     28 May 2007 20:10:02 -0000      1.11
+++ tests/freeze.at     31 May 2007 13:21:59 -0000
@@ -163,6 +163,12 @@ M3
 gnu
 F7,7,3
 builtinbuiltingnu
+# Text to negative diversion must not crash.  Catches a regression
+# introduced 2007-05-28 and fixed 2007-05-31.
+D-1,5
+12345
+D0,0
+
 # Testing escape sequences
 T4,5
 blah\t\477\040\X5C
@@ -188,6 +194,13 @@ bar
        '7 \
 ]])
 
+dnl We don't support anything larger than format 2; make sure of that...
+AT_DATA([bogus.m4f], [[V3
+]])
+AT_CHECK_M4([-R bogus.m4f], [63], [],
+[[m4: frozen file version 3 greater than max supported of 2
+]])
+
 AT_CLEANUP
 
 

reply via email to

[Prev in Thread] Current Thread [Next in Thread]