2008-10-31 Eric Blake <ebb9@byu.net>
+ Simplify diversion stack handling.
+ * lib/m4sugar/m4sugar.m4 (m4_divert_stack): Use fewer macros, and
+ avoid extra newlines.
+ (m4_divert_stack_push): Compute location here, rather than caller.
+ (m4_divert_push): Update caller.
+ (m4_divert): Likewise, and also adjust current diversion name.
+ (m4_divert_pop): Simplify rule that diversion stack must never go
+ empty.
+ (_m4_require_call): Bypass diversion stack when collecting
+ required macro text.
+ (m4_init): Set current diversion without requiring m4_init.
+ * lib/m4sugar/m4sh.m4 (AS_INIT): Avoid too many pops.
+ * lib/autotest/general.m4 (AT_INIT): Likewise.
+ * lib/autoconf/general.m4 (_AC_INIT_DEFAULTS): Schedule wrapped
+ text to run prior to m4sugar cleanup.
+ * doc/autoconf.texi (Text processing Macros) <m4_newline>: Mention
+ optional argument.
+ (Conditional constructs) <m4_ifvaln, m4_n>: Mention use of dnl.
+ * NEWS: Undo blurb about m4_divert.
+ * tests/m4sugar.at (m4@&t@_divert_stack): New test.
+
Simplify expansion stack handling.
* lib/m4sugar/m4sugar.m4 (m4_expansion_stack): Use fewer macros;
always output 'top level'.
** Configure scripts now use shell functions.
-** m4sugar requires m4_init in order to use m4_divert.
-
** The following documented m4sugar macros are new:
m4_curry m4_default_quoted m4_map_args m4_map_args_pair
m4_set_map
@defmac m4_ifvaln (@var{cond}, @ovar{if-true}, @ovar{if-false})
@msindex{ifvaln}
Similar to @code{m4_ifval}, except guarantee that a newline is present
-after any non-empty expansion.
+after any non-empty expansion. Often followed by @code{dnl}.
@end defmac
@defmac m4_n (@var{text})
@msindex{n}
Expand to @var{text}, and add a newline if @var{text} is not empty.
+Often followed by @code{dnl}.
@end defmac
efficient to use @code{m4_dquote}.
@end defmac
-@defmac m4_newline
+@defmac m4_newline (@ovar{text})
@msindex{newline}
-This macro was introduced in Autoconf 2.62, and expands to a newline.
+This macro was introduced in Autoconf 2.62, and expands to a newline,
+followed by any @var{text}.
It is primarily useful for maintaining macro formatting, and ensuring
that M4 does not discard leading whitespace during argument collection.
@end defmac
[m4_ifdef([AC_PACKAGE_BUGREPORT], ['AC_PACKAGE_BUGREPORT'])])dnl
m4_divert_pop([DEFAULTS])dnl
-m4_wrap([m4_divert_text([DEFAULTS],
+m4_wrap_lifo([m4_divert_text([DEFAULTS],
[ac_subst_vars='m4_set_dump([_AC_SUBST_VARS], m4_newline)'
ac_subst_files='m4_ifdef([_AC_SUBST_FILES], [m4_defn([_AC_SUBST_FILES])])'
ac_user_opts='
dnl End of AT_INIT: divert to KILL, only test groups are to be
dnl output, the rest is ignored. Current diversion is BODY, inherited
dnl from M4sh.
-m4_divert_pop([BODY])
-m4_divert_push([KILL])
+m4_divert([KILL])
])# AT_INIT
as_shell=$as_dir/$as_base
AS_IF([{ test -f "$as_shell" || test -f "$as_shell.exe"; } &&
_AS_RUN(["$as_required"], ["$as_shell"])],
- [CONFIG_SHELL=$as_shell as_have_required=yes
- m4_set_empty([_AS_DETECT_SUGGESTED_BODY], [break 2],
+ [CONFIG_SHELL=$as_shell as_have_required=yes
+ m4_set_empty([_AS_DETECT_SUGGESTED_BODY], [break 2],
[AS_IF([_AS_RUN(["$as_suggested"], ["$as_shell"])],
[break 2])])])
done;;
m4_divert_text([M4SH-INIT-FN], [m4_text_box([M4sh Shell Functions.])])
# Let's go!
-m4_divert_pop([KILL])[]dnl
-m4_divert_push([BODY])
+m4_divert([BODY])dnl
m4_text_box([Main body of script.])
_AS_DETECT_REQUIRED([_AS_SHELL_FN_WORK])dnl
AS_REQUIRE([_AS_UNSET_PREPARE], [], [M4SH-INIT-FN])dnl
# m4_divert_stack
# ------------------
-# Print m4_divert_stack with newline prepended, if it's nonempty.
+# Print the diversion stack, if it's nonempty. The caller is
+# responsible for any leading or trailing newline.
m4_define([m4_divert_stack],
-[m4_stack_foreach_lifo([_m4_divert_stack], [m4_newline])])
+[m4_stack_foreach_sep_lifo([_m4_divert_stack], [], [], [
+])])
-# m4_divert_stack_push(LOCATION, MACRO-NAME, DIVERSION-NAME)
-# -----------------------------------------------------------
-# Form an entry of the diversion stack and push it.
+# m4_divert_stack_push(MACRO-NAME, DIVERSION-NAME)
+# ------------------------------------------------
+# Form an entry of the diversion stack from caller MACRO-NAME and
+# entering DIVERSION-NAME and push it.
m4_define([m4_divert_stack_push],
-[m4_pushdef([_m4_divert_stack], [[$1: $2: $3]])])
+[m4_pushdef([_m4_divert_stack], m4_location[: $1: $2])])
# m4_divert(DIVERSION-NAME)
# Change the diversion stream to DIVERSION-NAME.
m4_define([m4_divert],
[m4_popdef([_m4_divert_stack])]dnl
-[m4_divert_stack_push(m4_location, [$0], [$1])]dnl
+[m4_define([_m4_divert_diversion], [$1])]dnl
+[m4_divert_stack_push([$0], [$1])]dnl
[m4_builtin([divert], _m4_divert([$1]))])
# ------------------------------
# Change the diversion stream to DIVERSION-NAME, while stacking old values.
m4_define([m4_divert_push],
-[m4_divert_stack_push(m4_location, [$0], [$1])]dnl
+[m4_divert_stack_push([$0], [$1])]dnl
[m4_pushdef([_m4_divert_diversion], [$1])]dnl
[m4_builtin([divert], _m4_divert([$1]))])
# If specified, verify we left DIVERSION-NAME.
# When we pop the last value from the stack, we divert to -1.
m4_define([m4_divert_pop],
-[m4_ifndef([_m4_divert_diversion],
- [m4_fatal([too many m4_divert_pop])])]dnl
[m4_if([$1], [], [],
[$1], _m4_defn([_m4_divert_diversion]), [],
- [m4_fatal([$0($1): diversion mismatch: ]m4_divert_stack)])]dnl
+ [m4_fatal([$0($1): diversion mismatch:
+]m4_divert_stack)])]dnl
[_m4_popdef([_m4_divert_stack], [_m4_divert_diversion])]dnl
-[m4_builtin([divert],
- m4_ifdef([_m4_divert_diversion],
- [_m4_divert(_m4_defn([_m4_divert_diversion]))],
- -1))])
+[m4_ifdef([_m4_divert_diversion], [],
+ [m4_fatal([too many m4_divert_pop])])]dnl
+[m4_builtin([divert], _m4_divert(_m4_defn([_m4_divert_diversion])))])
# m4_divert_text(DIVERSION-NAME, CONTENT)
[],
[m4_warn([syntax],
[$1 is m4_require'd but not m4_defun'd])])]],
- [[m4_divert($3)]],
- [[m4_undivert(_m4_divert_grow)]],
+ [[m4_builtin([divert], _m4_divert($3))]],
+ [[m4_builtin([undivert], _m4_divert_grow)]],
[[m4_divert_pop(_m4_divert_grow)]],
[[m4_define([_m4_divert_grow], m4_incr(_m4_divert_grow))]]))
## 17. Setting M4sugar up. ##
## ------------------------ ##
+# _m4_divert_diversion should be defined.
+m4_divert_push([KILL])
# m4_init
# -------
m4_define([m4_undefine], _m4_defn([m4_undefine]))],
[m4_builtin([include], [m4sugar/foreach.m4])])
-# _m4_divert_diversion should be defined:
-m4_divert_push([KILL])
+# Rewrite the first entry of the diversion stack.
+m4_divert([KILL])
# Check the divert push/pop perfect balance.
-m4_wrap([m4_divert_pop([])
- m4_ifdef([_m4_divert_diversion],
- [m4_fatal([$0: unbalanced m4_divert_push:]m4_divert_stack)])[]])
+# Some users are prone to also use m4_wrap to register last-minute
+# m4_divert_text; so after our diversion cleanups, we restore
+# KILL as the bottom of the diversion stack.
+m4_wrap([m4_popdef([_m4_divert_diversion])m4_ifdef(
+ [_m4_divert_diversion], [m4_fatal([$0: unbalanced m4_divert_push:
+]m4_divert_stack)])_m4_popdef([_m4_divert_stack])m4_divert_push([KILL])])
])
AT_CLEANUP
+## ----------------- ##
+## m4_divert_stack. ##
+## ----------------- ##
+
+AT_SETUP([m4@&t@_divert_stack])
+
+AT_CHECK_M4SUGAR_TEXT([[1.m4_divert_stack
+m4_divert_push([10])2.m4_divert_stack
+m4_divert_text([20], [3.m4_divert_stack])dnl
+m4_divert([30])4.m4_divert_stack
+m4_divert_pop([30])dnl
+5.m4_undivert([20])
+6.m4_undivert([30])
+m4_pattern_allow([^m4_divert])dnl
+]], [[1.script.4s:2: m4@&t@_divert_push: 0
+script.4s:1: m4@&t@_divert: KILL
+5.3.script.4s:5: m4@&t@_divert_push: 20
+script.4s:4: m4@&t@_divert_push: 10
+script.4s:2: m4@&t@_divert_push: 0
+script.4s:1: m4@&t@_divert: KILL
+
+6.4.script.4s:6: m4@&t@_divert: 30
+script.4s:2: m4@&t@_divert_push: 0
+script.4s:1: m4@&t@_divert: KILL
+
+2.script.4s:4: m4@&t@_divert_push: 10
+script.4s:2: m4@&t@_divert_push: 0
+script.4s:1: m4@&t@_divert: KILL
+]])
+
+AT_DATA_M4SUGAR([script.4s],
+[[m4_divert_pop
+]])
+AT_CHECK_M4SUGAR([-o-], [1], [],
+[[script.4s:1: error: too many m4@&t@_divert_pop
+script.4s:1: the top level
+autom4te: m4 failed with exit status: 1
+]])
+
+AT_DATA_M4SUGAR([script.4s],
+[[m4_init
+m4_divert_push([1])
+m4_divert_pop([2])
+]])
+AT_CHECK_M4SUGAR([-o-], [1], [],
+[[script.4s:3: error: m4@&t@_divert_pop(2): diversion mismatch:
+script.4s:2: m4@&t@_divert_push: 1
+script.4s:1: m4@&t@_divert: KILL
+script.4s:3: the top level
+autom4te: m4 failed with exit status: 1
+]])
+
+AT_DATA_M4SUGAR([script.4s],
+[[m4_divert([1])
+m4_init
+m4_divert_push([2])
+]])
+AT_CHECK_M4SUGAR([-o-], [1], [],
+[[script.4s:2: error: m4@&t@_init: unbalanced m4@&t@_divert_push:
+script.4s:3: m4@&t@_divert_push: 2
+script.4s:2: m4@&t@_divert: KILL
+script.4s:2: the top level
+autom4te: m4 failed with exit status: 1
+]])
+
+AT_CLEANUP
+
+
## -------------------- ##
## m4_expansion_stack. ##
## -------------------- ##