📄 m4sugar.m4
字号:
# ------------------# This macro invokes all its arguments (in sequence, of course). It is# useful for making your macros more structured and readable by dropping# unnecessary dnl's and have the macros indented properly.m4_define([m4_do],[m4_if($#, 0, [], $#, 1, [$1], [$1[]m4_do(m4_shift($@))])])# m4_define_default(MACRO, VALUE)# -------------------------------# If MACRO is undefined, set it to VALUE.m4_define([m4_define_default],[m4_ifndef([$1], [m4_define($@)])])# m4_default(EXP1, EXP2)# ----------------------# Returns EXP1 if non empty, otherwise EXP2.m4_define([m4_default],[m4_ifval([$1], [$1], [$2])])# m4_defn(NAME)# -------------# Unlike to the original, don't tolerate popping something which is# undefined.m4_define([m4_defn],[m4_ifndef([$1], [m4_fatal([$0: undefined macro: $1])])dnlm4_builtin([defn], $@)])# _m4_dumpdefs_up(NAME)# ---------------------m4_define([_m4_dumpdefs_up],[m4_ifdef([$1], [m4_pushdef([_m4_dumpdefs], m4_defn([$1]))dnlm4_dumpdef([$1])dnlm4_popdef([$1])dnl_m4_dumpdefs_up([$1])])])# _m4_dumpdefs_down(NAME)# -----------------------m4_define([_m4_dumpdefs_down],[m4_ifdef([_m4_dumpdefs], [m4_pushdef([$1], m4_defn([_m4_dumpdefs]))dnlm4_popdef([_m4_dumpdefs])dnl_m4_dumpdefs_down([$1])])])# m4_dumpdefs(NAME)# -----------------# Similar to `m4_dumpdef(NAME)', but if NAME was m4_pushdef'ed, display its# value stack (most recent displayed first).m4_define([m4_dumpdefs],[_m4_dumpdefs_up([$1])dnl_m4_dumpdefs_down([$1])])# m4_popdef(NAME)# ---------------# Unlike to the original, don't tolerate popping something which is# undefined.m4_define([m4_popdef],[m4_ifndef([$1], [m4_fatal([$0: undefined macro: $1])])dnlm4_builtin([popdef], $@)])# m4_quote(ARGS)# --------------# Return ARGS as a single arguments.## It is important to realize the difference between `m4_quote(exp)' and# `[exp]': in the first case you obtain the quoted *result* of the# expansion of EXP, while in the latter you just obtain the string# `exp'.m4_define([m4_quote], [[$*]])m4_define([m4_dquote], [[$@]])# m4_noquote(STRING)# ------------------# Return the result of ignoring all quotes in STRING and invoking the# macros it contains. Amongst other things useful for enabling macro# invocations inside strings with [] blocks (for instance regexps and# help-strings).m4_define([m4_noquote],[m4_changequote(-=<{,}>=-)$1-=<{}>=-m4_changequote([,])])# m4_shiftn(N, ...)# -----------------# Returns ... shifted N times. Useful for recursive "varargs" constructs.m4_define([m4_shiftn],[m4_assert(($1 >= 0) && ($# > $1))dnl_m4_shiftn($@)])m4_define([_m4_shiftn],[m4_if([$1], 0, [m4_shift($@)], [_m4_shiftn(m4_eval([$1]-1), m4_shift(m4_shift($@)))])])# m4_undefine(NAME)# -----------------# Unlike to the original, don't tolerate undefining something which is# undefined.m4_define([m4_undefine],[m4_ifndef([$1], [m4_fatal([$0: undefined macro: $1])])dnlm4_builtin([undefine], $@)])## -------------------------- #### 7. Implementing m4 loops. #### -------------------------- ### m4_for(VARIABLE, FIRST, LAST, [STEP = +/-1], EXPRESSION)# --------------------------------------------------------# Expand EXPRESSION defining VARIABLE to FROM, FROM + 1, ..., TO.# Both limits are included, and bounds are checked for consistency.m4_define([m4_for],[m4_pushdef([$1], m4_eval([$2]))dnlm4_if(m4_eval(([$3]) > $1), 1,[m4_pushdef([_m4_step], m4_eval(m4_default([$4], 1)))dnlm4_assert(_m4_step > 0)dnl_m4_for([$1], m4_eval((([$3]) - $1) / _m4_step * _m4_step + $1), _m4_step, [$5])], m4_eval(([$3]) < $1), 1,[m4_pushdef([_m4_step], m4_eval(m4_default([$4], -1)))dnlm4_assert(_m4_step < 0)dnl_m4_for([$1], m4_eval(($1 - ([$3])) / -(_m4_step) * _m4_step + $1), _m4_step, [$5])], [m4_pushdef(_m4_step,[])dnl$5])[]dnlm4_popdef([_m4_step])dnlm4_popdef([$1])])# _m4_for(VARIABLE, LAST, STEP, EXPRESSION)# -----------------------------------------# Core of the loop, no consistency checks, all arguments are plain numbers.m4_define([_m4_for],[$4[]dnlm4_if($1, [$2], [], [m4_define([$1], m4_eval($1+[$3]))_m4_for([$1], [$2], [$3], [$4])])])# Implementing `foreach' loops in m4 is much more tricky than it may# seem. Actually, the example of a `foreach' loop in the m4# documentation is wrong: it does not quote the arguments properly,# which leads to undesirable expansions.## The example in the documentation is:## | # foreach(VAR, (LIST), STMT)# | m4_define([foreach],# | [m4_pushdef([$1])_foreach([$1], [$2], [$3])m4_popdef([$1])])# | m4_define([_arg1], [$1])# | m4_define([_foreach],# | [m4_if([$2], [()], ,# | [m4_define([$1], _arg1$2)$3[]_foreach([$1],# | (shift$2),# | [$3])])])## But then if you run## | m4_define(a, 1)# | m4_define(b, 2)# | m4_define(c, 3)# | foreach([f], [([a], [(b], [c)])], [echo f# | ])## it gives## => echo 1# => echo (2,3)## which is not what is expected.## Of course the problem is that many quotes are missing. So you add# plenty of quotes at random places, until you reach the expected# result. Alternatively, if you are a quoting wizard, you directly# reach the following implementation (but if you really did, then# apply to the maintenance of m4sugar!).## | # foreach(VAR, (LIST), STMT)# | m4_define([foreach], [m4_pushdef([$1])_foreach($@)m4_popdef([$1])])# | m4_define([_arg1], [[$1]])# | m4_define([_foreach],# | [m4_if($2, [()], ,# | [m4_define([$1], [_arg1$2])$3[]_foreach([$1],# | [(shift$2)],# | [$3])])])## which this time answers## => echo a# => echo (b# => echo c)## Bingo!## Well, not quite.## With a better look, you realize that the parens are more a pain than# a help: since anyway you need to quote properly the list, you end up# with always using an outermost pair of parens and an outermost pair# of quotes. Rejecting the parens both eases the implementation, and# simplifies the use:## | # foreach(VAR, (LIST), STMT)# | m4_define([foreach], [m4_pushdef([$1])_foreach($@)m4_popdef([$1])])# | m4_define([_arg1], [$1])# | m4_define([_foreach],# | [m4_if($2, [], ,# | [m4_define([$1], [_arg1($2)])$3[]_foreach([$1],# | [shift($2)],# | [$3])])])### Now, just replace the `$2' with `m4_quote($2)' in the outer `m4_if'# to improve robustness, and you come up with a quite satisfactory# implementation.# m4_foreach(VARIABLE, LIST, EXPRESSION)# --------------------------------------## Expand EXPRESSION assigning each value of the LIST to VARIABLE.# LIST should have the form `item_1, item_2, ..., item_n', i.e. the# whole list must *quoted*. Quote members too if you don't want them# to be expanded.## This macro is robust to active symbols:# | m4_define(active, [ACT, IVE])# | m4_foreach(Var, [active, active], [-Var-])# => -ACT--IVE--ACT--IVE-## | m4_foreach(Var, [[active], [active]], [-Var-])# => -ACT, IVE--ACT, IVE-## | m4_foreach(Var, [[[active]], [[active]]], [-Var-])# => -active--active-m4_define([m4_foreach],[m4_pushdef([$1])_m4_foreach($@)m4_popdef([$1])])m4_define([_m4_foreach],[m4_ifval([$2], [m4_define([$1], m4_car($2))$3[]dnl_m4_foreach([$1], m4_cdr($2), [$3])])])# m4_foreach_w(VARIABLE, LIST, EXPRESSION)# ----------------------------------------## Like m4_foreach, but the list is whitespace separated.## This macro is robust to active symbols:# m4_foreach_w([Var], [ active# b act\# ive ], [-Var-])end# => -active--b--active-end#m4_define([m4_foreach_w],[m4_foreach([$1], m4_split(m4_normalize([$2])), [$3])])## --------------------------- #### 8. More diversion support. #### --------------------------- ### _m4_divert(DIVERSION-NAME or NUMBER)# ------------------------------------# If DIVERSION-NAME is the name of a diversion, return its number,# otherwise if it is a NUMBER return it.m4_define([_m4_divert],[m4_ifdef([_m4_divert($1)], [m4_indir([_m4_divert($1)])], [$1])])# KILL is only used to suppress output.m4_define([_m4_divert(KILL)], -1)# _m4_divert_n_stack# ------------------# Print m4_divert_stack with newline prepended, if it's nonempty.m4_define([_m4_divert_n_stack],[m4_ifdef([m4_divert_stack], [m4_defn([m4_divert_stack])])])# m4_divert(DIVERSION-NAME)# -------------------------# Change the diversion stream to DIVERSION-NAME.m4_define([m4_divert],[m4_define([m4_divert_stack], m4_location[: $0: $1]_m4_divert_n_stack)dnlm4_builtin([divert], _m4_divert([$1]))dnl])# m4_divert_push(DIVERSION-NAME)# ------------------------------# Change the diversion stream to DIVERSION-NAME, while stacking old values.m4_define([m4_divert_push],[m4_pushdef([m4_divert_stack], m4_location[: $0: $1]_m4_divert_n_stack)dnlm4_pushdef([_m4_divert_diversion], [$1])dnlm4_builtin([divert], _m4_divert([$1]))dnl])# m4_divert_pop([DIVERSION-NAME])# -------------------------------# Change the diversion stream to its previous value, unstacking it.# 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])])dnlm4_if([$1], [], [], [$1], m4_defn([_m4_divert_diversion]), [], [m4_fatal([$0($1): diversion mismatch: ]_m4_divert_n_stack)])dnlm4_popdef([m4_divert_stack])dnlm4_popdef([_m4_divert_diversion])dnlm4_builtin([divert], m4_ifdef([_m4_divert_diversion], [_m4_divert(m4_defn([_m4_divert_diversion]))], -1))dnl])# m4_divert_text(DIVERSION-NAME, CONTENT)# ---------------------------------------# Output CONTENT into DIVERSION-NAME (which may be a number actually).# An end of line is appended for free to CONTENT.m4_define([m4_divert_text],[m4_divert_push([$1])dnl$2m4_divert_pop([$1])dnl])# m4_divert_once(DIVERSION-NAME, CONTENT)# ---------------------------------------# Output once CONTENT into DIVERSION-NAME (which may be a number# actually). An end of line is appended for free to CONTENT.m4_define([m4_divert_once],[m4_expand_once([m4_divert_text([$1], [$2])])])# m4_undivert(DIVERSION-NAME)# ---------------------------# Undivert DIVERSION-NAME.m4_define([m4_undivert],[m4_builtin([undivert], _m4_divert([$1]))])## -------------------------------------------- #### 8. Defining macros with bells and whistles. #### -------------------------------------------- ### `m4_defun' is basically `m4_define' but it equips the macro with the# needed machinery for `m4_require'. A macro must be m4_defun'd if# either it is m4_require'd, or it m4_require's.## Two things deserve attention and are detailed below:# 1. Implementation of m4_require# 2. Keeping track of the expansion stack## 1. Implementation of m4_require# ===============================## Of course m4_defun AC_PROVIDE's the macro, so that a macro which has# been expanded is not expanded again when m4_require'd, but the# difficult part is the proper expansion of macros when they are# m4_require'd.## The implementation is based on two ideas, (i) using diversions to# prepare the expansion of the macro and its dependencies (by Franc,ois# Pinard), and (ii) expand the most recently m4_require'd macros _after_# the previous macros (by Axel Thimm).### The first idea: why using diversions?# -------------------------------------## When a macro requires another, the other macro is expanded in new# diversion, GROW. When the outer macro is fully expanded, we first# undivert the most nested diversions (GROW - 1...), and finally# undivert GROW. To understand why we need several diversions,# consider the following example:## | m4_defun([TEST1], [Test...REQUIRE([TEST2])1])# | m4_defun([TEST2], [Test...REQUIRE([TEST3])2])# | m4_defun([TEST3], [Test...3])## Because m4_require is not required to be first in the outer macros, we# must keep the expansions of the various level of m4_require separated.# Right before executing the epilogue of TEST1, we have:## GROW - 2: Test...3# GROW - 1: Test...2# GROW: Test...1# BODY:## Finally the epilogue of TEST1 undiverts GROW - 2, GROW - 1, and# GROW into the regular flow, BODY.## GROW - 2:# GROW - 1:# GROW:# BODY: Test...3; Test...2; Test...1## (The semicolons are here for clarification, but of course are not# emitted.) This is what Autoconf 2.0 (I think) to 2.13 (I'm sure)# implement.### The second idea: first required first out# -----------------------------------------## The natural implementation of the idea above is buggy and produces# very surprising results in some situations. Let's consider the# following example to explain the bug:## | m4_defun([TEST1], [REQUIRE([TEST2a])REQUIRE([TEST2b])])# | m4_defun([TEST2a], [])# | m4_defun([TEST2b], [REQUIRE([TEST3])])# | m4_defun([TEST3], [REQUIRE([TEST2a])])# |# | AC_INIT# | TEST1## The dependencies between the macros are:## 3 --- 2b# / \ is m4_require'd by# / \ left -------------------- right# 2a ------------ 1#
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -