autoconf-patches
[Top][All Lists]
Advanced

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

m4_cond [was: [RFA] autotest speedup]


From: Eric Blake
Subject: m4_cond [was: [RFA] autotest speedup]
Date: Fri, 05 Oct 2007 11:41:51 -0600
User-agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.6) Gecko/20070728 Thunderbird/2.0.0.6 Mnenhy/0.7.5.666

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

According to Paolo Bonzini on 10/5/2007 1:42 AM:
> 
>> I debated about making:
>> m4_cond(TEST, [not,] VAL1, IF-[NOT-]VAL1, ...)
> 
> I think it is more complicated than necessary.

OK, I won't add that extra bit - tests for inequality will still require
the user to involve a nested m4_if or m4_eval.

>  The lazy m4_if is nice,
> though I'm not sure I like the name.

Suggestions for a better name?  m4_lazy_if?  I'm committing the following
patch; we can rename the macro later if someone comes up with an idea.

>  Also, it adds one more "quoting
> rule" for the "non-initiated" (it took me already a while to get used
> not to quote m4_if arguments...).

As it is, m4sugar is woefully underdocumented in the manual.  So I added
m4_cond and a couple others in the process.

        Provide better short-circuiting operation.
        * lib/m4sugar/m4sugar.m4 (m4_cond, m4_newline): New macros.
        (m4_text_wrap): Use it.  Also avoid useless m4_for.
        * lib/m4sugar/m4sh.m4 (_AS_QUOTE_IFELSE, AS_LITERAL_IF): Use
        new macro.
        (_AS_IDENTIFIER_IF): Likewise, and fix bug when $1 is [,].
        * lib/autotest/general.m4 (_AT_DECIDE_TRACEABLE): Use new macros
        to avoid regexps.
        * doc/autoconf.texi (Redefined M4 Macros): Expand m4_if
        documentation.  Sort m4_mkstemp, m4_undefine.  Move m4_ifndef...
        (Conditional constructs): ...here, to new section.  Also document
        m4_cond, m4_ifval, m4_n, m4_ifvaln, m4_ifset, m4_case, m4_bmatch,
        m4_bpatsubsts, and m4_default.
        (Looping constructs): Document m4_shiftn, m4_shift2, m4_shift3,
        m4_do.

- --
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

iD8DBQFHBndf84KuGfSFAYARAuTQAJ4/WZRn34IPbNV0dMsUd8Qeg3SOowCgl7/o
6AihNn1X8IS8qs6nCBjPeRQ=
=UmwF
-----END PGP SIGNATURE-----
>From 4e9078ba0b9a919ee35a1ff8b6bd8c764362f33e Mon Sep 17 00:00:00 2001
From: Eric Blake <address@hidden>
Date: Thu, 4 Oct 2007 12:29:45 -0600
Subject: [PATCH] Provide better short-circuiting operation.

* lib/m4sugar/m4sugar.m4 (m4_cond, m4_newline): New macros.
(m4_text_wrap): Use it.  Also avoid useless m4_for.
* lib/m4sugar/m4sh.m4 (_AS_QUOTE_IFELSE, AS_LITERAL_IF): Use
new macro.
(_AS_IDENTIFIER_IF): Likewise, and fix bug when $1 is [,].
* lib/autotest/general.m4 (_AT_DECIDE_TRACEABLE): Use new macros
to avoid regexps.
* doc/autoconf.texi (Redefined M4 Macros): Expand m4_if
documentation.  Sort m4_mkstemp, m4_undefine.  Move m4_ifndef...
(Conditional constructs): ...here, to new section.  Also document
m4_cond, m4_ifval, m4_n, m4_ifvaln, m4_ifset, m4_case, m4_bmatch,
m4_bpatsubsts, and m4_default.
(Looping constructs): Document m4_shiftn, m4_shift2, m4_shift3,
m4_do.

Signed-off-by: Eric Blake <address@hidden>
---
 ChangeLog               |   18 ++++
 doc/autoconf.texi       |  209 +++++++++++++++++++++++++++++++++++++++-------
 lib/autotest/general.m4 |   22 +++---
 lib/m4sugar/m4sh.m4     |   35 ++++----
 lib/m4sugar/m4sugar.m4  |   58 +++++++++++--
 5 files changed, 274 insertions(+), 68 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 9052228..57dfbb5 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,21 @@
+2007-10-05  Eric Blake  <address@hidden>
+
+       Provide better short-circuiting operation.
+       * lib/m4sugar/m4sugar.m4 (m4_cond, m4_newline): New macros.
+       (m4_text_wrap): Use it.  Also avoid useless m4_for.
+       * lib/m4sugar/m4sh.m4 (_AS_QUOTE_IFELSE, AS_LITERAL_IF): Use
+       new macro.
+       (_AS_IDENTIFIER_IF): Likewise, and fix bug when $1 is [,].
+       * lib/autotest/general.m4 (_AT_DECIDE_TRACEABLE): Use new macros
+       to avoid regexps.
+       * doc/autoconf.texi (Redefined M4 Macros): Expand m4_if
+       documentation.  Sort m4_mkstemp, m4_undefine.  Move m4_ifndef...
+       (Conditional constructs): ...here, to new section.  Also document
+       m4_cond, m4_ifval, m4_n, m4_ifvaln, m4_ifset, m4_case, m4_bmatch,
+       m4_bpatsubsts, and m4_default.
+       (Looping constructs): Document m4_shiftn, m4_shift2, m4_shift3,
+       m4_do.
+
 2007-10-04  Eric Blake  <address@hidden>
 
        Fix recent testsuite failures.
diff --git a/doc/autoconf.texi b/doc/autoconf.texi
index bd67ab1..ecc496b 100644
--- a/doc/autoconf.texi
+++ b/doc/autoconf.texi
@@ -449,6 +449,7 @@ Using @command{autom4te}
 Programming in M4sugar
 
 * Redefined M4 Macros::         M4 builtins changed in M4sugar
+* Conditional constructs::      Conditions in M4
 * Looping constructs::          Iteration in M4
 * Evaluation Macros::           More quotation and evaluation control
 * Text processing Macros::      String manipulation in M4
@@ -10070,6 +10071,7 @@ M4sugar''.
 
 @menu
 * Redefined M4 Macros::         M4 builtins changed in M4sugar
+* Conditional constructs::      Conditions in M4
 * Looping constructs::          Iteration in M4
 * Evaluation Macros::           More quotation and evaluation control
 * Text processing Macros::      String manipulation in M4
@@ -10136,15 +10138,10 @@ This macro corresponds to @code{m4exit}.
 @defmacx m4_if (@var{string-1}, @var{string-2}, @var{equal}, @ovar{not-equal})
 @defmacx m4_if (@var{string-1}, @var{string-2}, @var{equal}, @dots{})
 @msindex{if}
-This macro corresponds to @code{ifelse}.
address@hidden defmac
-
address@hidden m4_ifndef (@var{macro}, @var{if-not-defined}, @ovar{if-defined})
address@hidden
-This is shorthand for:
address@hidden
-m4_ifdef(address@hidden, address@hidden, address@hidden)
address@hidden example
+This macro corresponds to @code{ifelse}.  @var{string-1} and
address@hidden are compared literally, so usually one of the two
+arguments is passed unquoted.  @xref{Conditional constructs} for more
+conditional idioms.
 @end defmac
 
 @defmac m4_include (@var{file})
@@ -10154,11 +10151,26 @@ m4_ifdef(address@hidden, address@hidden, 
address@hidden)
 Like the M4 builtins, but warn against multiple inclusions of @var{file}.
 @end defmac
 
address@hidden m4_mkstemp (@var{template})
address@hidden m4_maketemp (@var{template})
address@hidden
address@hidden
+Posix requires @code{maketemp} to replace the trailing @samp{X}
+characters in @var{template} with the process id, without regards to the
+existence of a file by that name, but this a security hole.  When this
+was pointed out to the Posix folks, they agreed to invent a new macro
address@hidden that always creates a uniquely named file, but not all
+versions of @acronym{GNU} M4 support the new macro.  In M4sugar,
address@hidden and @code{m4_mkstemp} are synonyms for each other,
+and both have the secure semantics regardless of which macro the
+underlying M4 provides.
address@hidden defmac
+
 @defmac m4_bpatsubst (@var{string}, @var{regexp}, @ovar{replacement})
 @msindex{bpatsubst}
 This macro corresponds to @code{patsubst}.  The name @code{m4_patsubst}
-is kept for future versions of M4sh, on top of @acronym{GNU} M4 which will
-provide extended regular expression syntax via @code{epatsubst}.
+is kept for future versions of M4sugar, once @acronym{GNU} M4 2.0 is
+released and supports extended regular expression syntax.
 @end defmac
 
 @defmac m4_popdef (@var{macro})
@@ -10170,8 +10182,21 @@ defined.  See @code{m4_undefine}.
 @defmac m4_bregexp (@var{string}, @var{regexp}, @ovar{replacement})
 @msindex{bregexp}
 This macro corresponds to @code{regexp}.  The name @code{m4_regexp}
-is kept for future versions of M4sh, on top of @acronym{GNU} M4 which will
-provide extended regular expression syntax via @code{eregexp}.
+is kept for future versions of M4sugar, once @acronym{GNU} M4 2.0 is
+released and supports extended regular expression syntax.
address@hidden defmac
+
address@hidden m4_undefine (@var{macro})
address@hidden
+Unlike the M4 builtin, this macro fails if @var{macro} is not
+defined.  Use
+
address@hidden
+m4_ifdef(address@hidden, [m4_undefine(address@hidden)])
address@hidden example
+
address@hidden
+to recover the behavior of the builtin.
 @end defmac
 
 @defmac m4_wrap (@var{text})
@@ -10200,32 +10225,131 @@ m4_wrap([foo])
 @end example
 @end defmac
 
address@hidden m4_undefine (@var{macro})
address@hidden
-Unlike the M4 builtin, this macro fails if @var{macro} is not
-defined.  Use
 
address@hidden Conditional constructs
address@hidden Conditional constructs
+
+The following macros provide additional conditional contructs, as
+convenience wrappers around @code{m4_if}.
+
address@hidden m4_bmatch (@var{string}, @var{regex-1}, @var{value-1}, @dots{}, @
+  @ovar{default})
address@hidden
+The string @var{string} is repeatedly compared against a series of
address@hidden arguments; if a match is found, the expansion is the
+corresponding @var{value}, otherwise, the macro moves on to the next
address@hidden  If no @var{regex} match, then the result is the optional
address@hidden, or nothing.
address@hidden defmac
+
address@hidden m4_bpatsubsts (@var{string}, @var{regex-1}, @var{subst-1}, 
@dots{})
address@hidden
+The string @var{string} is altered by @var{regex-1} and @var{subst-1},
+as if by:
 @example
-m4_ifdef(address@hidden, [m4_undefine(address@hidden)])
+m4_bpatsubst(address@hidden, address@hidden, address@hidden)
 @end example
 
 @noindent
-to recover the behavior of the builtin.
+The result of the substitution is then passed through the next set of
address@hidden and @var{subst}, and so forth.  An empty @var{subst} implies
+deletion of any matched portions in the current string.  Note that this
+macro over-quotes @var{string}; this behavior is intentional, so that
+the result of each step of the recursion remains as a quoted string.
+However, it means that anchors (@samp{^} and @samp{$} in the @var{regex}
+will line up with the extra quotations, and not the characters of the
+original string.
address@hidden defmac
+
address@hidden m4_case (@var{string}, @var{value-1}, @var{if-value-1}, @dots{}, 
@
+  @ovar{default})
address@hidden
+Test @var{string} against multiple @var{value} possibilities, resulting
+in the first @var{if-value} for a match, or in the optional
address@hidden  This is shorthand for:
address@hidden
+m4_if(address@hidden, address@hidden, address@hidden,
+      address@hidden, address@hidden, address@hidden, @dots{},
+      address@hidden)
address@hidden example
address@hidden defmac
+
address@hidden m4_cond (@var{test-1}, @var{value-1}, @var{if-value-1}, @
+  @var{test-2}, @var{value-2}, @var{if-value-2}, @dots{}, @ovar{default})
address@hidden
+Similar to @code{m4_if}, except that each @var{test} is expanded only
+when it is encountered.  This is useful for short-circuiting expensive
+tests; while @code{m4_if} requires all its strings to be expanded up
+front before doing comparisons, @code{m4_cond} only expands a @var{test}
+when all earlier tests have failed.
+
+For an example, these two sequences give the same result, but in the
+case where @samp{$1} does not contain a backslash, the @code{m4_cond}
+version only expands @code{m4_index} once, instead of five times, for
+faster computation if this is a common case for @samp{$1}.  Notice that
+every third argument is unquoted for @code{m4_if}, and quoted for
address@hidden:
+
address@hidden
+m4_if(m4_index([$1], [\]), [-1], [$2],
+      m4_eval(m4_index([$1], [\\]) >= 0), [1], [$2],
+      m4_eval(m4_index([$1], [\$]) >= 0), [1], [$2],
+      m4_eval(m4_index([$1], [\`]) >= 0), [1], [$3],
+      m4_eval(m4_index([$1], [\"]) >= 0), [1], [$3],
+      [$2])
+m4_cond([m4_index([$1], [\])], [-1], [$2],
+        [m4_eval(m4_index([$1], [\\]) >= 0)], [1], [$2],
+        [m4_eval(m4_index([$1], [\$]) >= 0)], [1], [$2],
+        [m4_eval(m4_index([$1], [\`]) >= 0)], [1], [$3],
+        [m4_eval(m4_index([$1], [\"]) >= 0)], [1], [$3],
+        [$2])
address@hidden example
address@hidden defmac
+
address@hidden m4_default (@var{expr-1}, @var{expr-2})
address@hidden
+If @var{expr-1} is not empty, use it.  Otherwise, expand to
address@hidden  Useful for providing a fixed default if the expression
+that results in @var{expr-1} would otherwise be empty.
 @end defmac
 
address@hidden m4_maketemp (@var{template})
address@hidden m4_mkstemp (@var{template})
address@hidden
address@hidden
-Posix requires @code{maketemp} to replace the trailing @samp{X}
-characters in @var{template} with the process id, without regards to the
-existence of a file by that name, but this a security hole.  When this
-was pointed out to the Posix folks, they agreed to invent a new macro
address@hidden that always creates a uniquely named file, but not all
-versions of @acronym{GNU} M4 support the new macro.  In M4sugar,
address@hidden and @code{m4_mkstemp} are synonyms for each other,
-and both have the secure semantics regardless of which macro the
-underlying M4 provides.
address@hidden m4_ifndef (@var{macro}, @var{if-not-defined}, @ovar{if-defined})
address@hidden
+This is shorthand for:
address@hidden
+m4_ifdef(address@hidden, address@hidden, address@hidden)
address@hidden example
address@hidden defmac
+
address@hidden m4_ifset (@var{macro}, @ovar{if-true}, @ovar{if-false})
address@hidden
+If @var{macro} is undefined, or is defined as the empty string, expand
+to @var{if-false}.  Otherwise, expands to @var{if-true}.  Similar to:
address@hidden
+m4_ifval(m4_defn(address@hidden), address@hidden, address@hidden)
address@hidden example
address@hidden
+except that it is not an error if @var{macro} is undefined.
address@hidden defmac
+
address@hidden m4_ifval (@var{cond}, @ovar{if-true}, @ovar{if-false})
address@hidden
+Expands to @var{if-true} if @var{cond} is not empty, otherwise to
address@hidden  This is shorthand for:
address@hidden
+m4_if(address@hidden, [], address@hidden, address@hidden)
address@hidden example
address@hidden defmac
+
address@hidden m4_ifvaln (@var{cond}, @ovar{if-true}, @ovar{if-false})
address@hidden
+Similar to @code{m4_ifval}, except guarantee that a newline is present
+after any non-empty expansion.
address@hidden defmac
+
address@hidden m4_n (@var{text})
address@hidden
+Expand to @var{text}, and add a newline if @var{text} is not empty.
 @end defmac
 
 
@@ -10269,6 +10393,27 @@ The deprecated macro @code{AC_FOREACH} is an alias of
 @code{m4_foreach_w}.
 @end defmac
 
+The following macros are useful in implementing recursive algorithms.
+
address@hidden m4_do(@dots{})
address@hidden
+This macro loops over its arguments and expands each one in sequence.
+Its main use is for readability; it allows the use of indentation and
+fewer @code{dnl} to result in the same expansion.
address@hidden defmac
+
address@hidden m4_shiftn (@var{count}, @dots{})
address@hidden m4_shift2 (@dots{})
address@hidden m4_shift3 (@dots{})
address@hidden
address@hidden
address@hidden
address@hidden performs @var{count} iterations of @code{m4_shift},
+along with validation that enough arguments were passed in to match the
+shift count.  @code{m4_shift2} and @code{m4_shift3} are specializations
+of @code{m4_shiftn} that are more efficient for two and three shifts,
+respectively.
address@hidden defmac
 
 
 @node Evaluation Macros
diff --git a/lib/autotest/general.m4 b/lib/autotest/general.m4
index 5390d49..0986424 100644
--- a/lib/autotest/general.m4
+++ b/lib/autotest/general.m4
@@ -1426,18 +1426,19 @@ m4_define([AT_CHECK_NOESCAPE],
 # to safely expand arbitrary COMMANDS in an argument list, so the below tests
 # examine COMMANDS unexpanded.
 m4_define([_AT_DECIDE_TRACEABLE],
-[dnl Utility macros.
-m4_pushdef([at_lf], [
-])[]dnl
+dnl Utility macro.
 dnl
 dnl Examine COMMANDS for a reason to never trace COMMANDS.
-m4_pushdef([at_reason],
-          m4_bmatch([$1],
-                    [`.*`], [[a `...` command substitution]],
-                    [\$(],  [[a $(...) command substitution]],
-                    [\${],  [[a ${...} parameter expansion]],
-                    at_lf,  [[an embedded newline]],
-                    [[]]dnl No reason.
+[m4_pushdef([at_reason],
+m4_cond([m4_eval(m4_index([$1], [`]) >= 0)], [1],
+               [[a `...` command substitution]],
+       [m4_eval(m4_index([$1], [$(]) >= 0)], [1],
+               [[a $(...) command substitution]],
+       [m4_eval(m4_index([$1], [${]) >= 0)], [1],
+               [[a ${...} parameter expansion]],
+       [m4_eval(m4_index([$1], m4_newline) >= 0)], [1],
+               [[an embedded newline]],
+       []dnl No reason.
 ))dnl
 dnl
 m4_ifval(m4_defn([at_reason]),
@@ -1447,7 +1448,6 @@ dnl We know at build time that tracing COMMANDS is always 
safe.
 [test -n "$at_traceon"],
 dnl COMMANDS may contain parameter expansions; expand them at runtime.
 [test -n "$at_traceon" && at_check_newline "AS_ESCAPE([$1], [`\"])"])])[]dnl
-m4_popdef([at_lf])[]dnl
 m4_popdef([at_reason])])
 
 
diff --git a/lib/m4sugar/m4sh.m4 b/lib/m4sugar/m4sh.m4
index 26326f5..8d441ab 100644
--- a/lib/m4sugar/m4sh.m4
+++ b/lib/m4sugar/m4sh.m4
@@ -588,12 +588,12 @@ m4_define([_AS_ESCAPE],
 # The current implementation caters to the common case of no backslashes,
 # to minimize m4_index expansions (hence the nested if).
 m4_define([_AS_QUOTE_IFELSE],
-[m4_if(m4_index([$1], [\]), [-1], [$2],
-       [m4_if(m4_eval(m4_index([$1], [\\]) >= 0), [1], [$2],
-             m4_eval(m4_index([$1], [\$]) >= 0), [1], [$2],
-             m4_eval(m4_index([$1], [\`]) >= 0), [1], [$3],
-             m4_eval(m4_index([$1], [\"]) >= 0), [1], [$3],
-             [$2])])])
+[m4_cond([m4_index([$1], [\])], [-1], [$2],
+        [m4_eval(m4_index([$1], [\\]) >= 0)], [1], [$2],
+        [m4_eval(m4_index([$1], [\$]) >= 0)], [1], [$2],
+        [m4_eval(m4_index([$1], [\`]) >= 0)], [1], [$3],
+        [m4_eval(m4_index([$1], [\"]) >= 0)], [1], [$3],
+        [$2])])
 
 
 # _AS_QUOTE(STRING, [CHARS = `"])
@@ -1248,11 +1248,12 @@ m4_define([AS_IDENTIFIER_IF],
        [_$0($@)],
        [_$0(m4_bpatsubst([[$1]], [@&address@hidden), [$2], [$3])])])
 m4_define([_AS_IDENTIFIER_IF],
-[m4_if([$1], [], [$3],
-       m4_translit([[$1]], ]m4_dquote(m4_defn([m4_cr_symbols2]))[), [],
-       [m4_if(m4_len(m4_translit(m4_format([[%.1s]], [$1]), ]]dnl
-m4_dquote(m4_dquote(m4_defn([m4_cr_symbols1])))[[)), [0], [$2], [$3])],
-       [$3])])
+[m4_cond([[$1]], [], [$3],
+        [m4_eval(m4_len(m4_translit([[$1]], ]]dnl
+m4_dquote(m4_dquote(m4_defn([m4_cr_symbols2])))[[)) > 0)], [1], [$3],
+        [m4_len(m4_translit(m4_format([[%.1s]], [$1]), ]]dnl
+m4_dquote(m4_dquote(m4_defn([m4_cr_symbols1])))[[))], [0], [$2], [$3])])
+
 
 # AS_LITERAL_IF(EXPRESSION, IF-LITERAL, IF-NOT-LITERAL)
 # -----------------------------------------------------
@@ -1280,12 +1281,12 @@ m4_dquote(m4_dquote(m4_defn([m4_cr_symbols1])))[[)), 
[0], [$2], [$3])],
 # Rather than expand m4_defn every time AS_LITERAL_IF is expanded, we
 # inline its expansion up front.
 m4_define([AS_LITERAL_IF],
-[m4_if(m4_eval(m4_index(m4_quote($1), address@hidden|@]) == -1), [0], [$3],
-       m4_index(m4_translit(m4_quote($1),
-                           [[]`,#]]m4_dquote(m4_defn([m4_cr_symbols2]))[,
-                           [$$$]),
-               [$]), [-1], [$2],
-       [$3])])
+[m4_cond([m4_eval(m4_index(m4_quote($1), address@hidden|@]) == -1)], [0], [$3],
+        [m4_index(m4_translit(m4_quote($1),
+                              [[]`,#]]m4_dquote(m4_defn([m4_cr_symbols2]))[,
+                              [$$$]),
+                  [$])], [-1], [$2],
+        [$3])])
 
 
 # AS_TMPDIR(PREFIX, [DIRECTORY = $TMPDIR [= /tmp]])
diff --git a/lib/m4sugar/m4sugar.m4 b/lib/m4sugar/m4sugar.m4
index d9cf142..1da5220 100644
--- a/lib/m4sugar/m4sugar.m4
+++ b/lib/m4sugar/m4sugar.m4
@@ -399,6 +399,42 @@ m4_define([m4_cdr],
        [m4_dquote(m4_shift($@))])])
 
 
+# m4_cond(TEST1, VAL1, IF-VAL1, TEST2, VAL2, IF-VAL2, ..., [DEFAULT])
+# -------------------------------------------------------------------
+# Similar to m4_if, except that each TEST is expanded when encountered.
+# If the expansion of TESTn matches the string VALn, the result is IF-VALn.
+# The result is DEFAULT if no tests passed.  This macro allows
+# short-circuiting of expensive tests, where it pays to arrange quick
+# filter tests to run first.
+#
+# For an example, consider a previous implementation of _AS_QUOTE_IFELSE:
+#
+#    m4_if(m4_index([$1], [\]), [-1], [$2],
+#          m4_eval(m4_index([$1], [\\]) >= 0), [1], [$2],
+#          m4_eval(m4_index([$1], [\$]) >= 0), [1], [$2],
+#          m4_eval(m4_index([$1], [\`]) >= 0), [1], [$3],
+#          m4_eval(m4_index([$1], [\"]) >= 0), [1], [$3],
+#          [$2])
+#
+# Here, m4_index is computed 5 times, and m4_eval 4, even if $1 contains
+# no backslash.  It is more efficient to do:
+#
+#    m4_cond([m4_index([$1], [\])], [-1], [$2],
+#            [m4_eval(m4_index([$1], [\\]) >= 0)], [1], [$2],
+#            [m4_eval(m4_index([$1], [\$]) >= 0)], [1], [$2],
+#            [m4_eval(m4_index([$1], [\`]) >= 0)], [1], [$3],
+#            [m4_eval(m4_index([$1], [\"]) >= 0)], [1], [$3],
+#            [$2])
+#
+# In the common case of $1 with no backslash, only one m4_index expansion
+# occurs, and m4_eval is avoided altogether.
+m4_define([m4_cond],
+[m4_if([$#], [0], [m4_fatal([$0: cannot be called without arguments])],
+       [$#], [1], [$1],
+       [$#], [2], [m4_fatal([$0: missing an argument])],
+       [m4_if($1, [$2], [$3], [$0(m4_shift3($@))])])])
+
+
 # m4_map(MACRO, LIST)
 # -------------------
 # Invoke MACRO($1), MACRO($2) etc. where $1, $2... are the elements
@@ -1448,6 +1484,13 @@ _m4_define_cr_not([symbols1])
 _m4_define_cr_not([symbols2])
 
 
+# m4_newline
+# ----------
+# Expands to a newline.  Exists for formatting reasons.
+m4_define([m4_newline], [
+])
+
+
 # m4_re_escape(STRING)
 # --------------------
 # Escape RE active characters in STRING.
@@ -1696,15 +1739,14 @@ m4_pushdef([m4_Width], m4_default([$4], 79))dnl
 m4_pushdef([m4_Cursor], m4_qlen(m4_defn([m4_Prefix1])))dnl
 m4_pushdef([m4_Separator], [])dnl
 m4_defn([m4_Prefix1])[]dnl
-m4_if(m4_eval(m4_qlen(m4_defn([m4_Prefix1])) > m4_len(m4_Prefix)),
-      1, [m4_define([m4_Cursor], m4_len(m4_Prefix))
+m4_cond([m4_eval(m4_qlen(m4_defn([m4_Prefix1])) > m4_len(m4_Prefix))],
+       [1], [m4_define([m4_Cursor], m4_len(m4_Prefix))
 m4_Prefix],
-      m4_if(m4_eval(m4_qlen(m4_defn([m4_Prefix1])) < m4_len(m4_Prefix)),
-           [0], [],
-           [m4_define([m4_Cursor], m4_len(m4_Prefix))[]dnl
-m4_for(m4_Space, m4_qlen(m4_defn([m4_Prefix1])), m4_eval(m4_len(m4_Prefix) - 
1),
-                   [], [ ])])[]dnl
-)[]dnl
+       [m4_eval(m4_qlen(m4_defn([m4_Prefix1])) < m4_len(m4_Prefix))],
+       [0], [],
+       [m4_define([m4_Cursor], m4_len(m4_Prefix))[]dnl
+m4_format(%m4_eval(m4_len(m4_Prefix) - 1 - m4_qlen(m4_defn([m4_Prefix1])))[s],
+         [])])[]dnl
 m4_foreach_w([m4_Word], [$1],
 [m4_define([m4_Cursor], m4_eval(m4_Cursor + m4_qlen(m4_defn([m4_Word])) + 
1))dnl
 dnl New line if too long, else insert a space unless it is the first
-- 
1.5.3.2


reply via email to

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