| # -*- Autotest -*- |
| |
| AT_BANNER([M4sugar.]) |
| |
| # Copyright (C) 2000-2002, 2005-2017, 2020-2026 Free Software |
| # Foundation, Inc. |
| # |
| # This program is free software: you can redistribute it and/or modify |
| # it under the terms of the GNU General Public License as published by |
| # the Free Software Foundation, either version 3 of the License, or |
| # (at your option) any later version. |
| # |
| # This program is distributed in the hope that it will be useful, |
| # but WITHOUT ANY WARRANTY; without even the implied warranty of |
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| # GNU General Public License for more details. |
| # |
| # You should have received a copy of the GNU General Public License |
| # along with this program. If not, see <https://www.gnu.org/licenses/>. |
| |
| |
| # AT_CHECK_M4SUGAR_TEXT(CODE, STDOUT, STDERR, FLAGS) |
| # -------------------------------------------------- |
| # Check that m4sugar CODE expands to STDOUT and emits STDERR. |
| m4_define([AT_CHECK_M4SUGAR_TEXT], |
| [ |
| AT_DATA_M4SUGAR([script.4s], |
| [[m4_init |
| m4_divert_push([])[]dnl |
| ]$1[[]dnl |
| m4_divert_pop([]) |
| ]]) |
| |
| AT_CHECK_M4SUGAR([$4 -o-],, [$2], [$3]) |
| ])# AT_CHECK_M4SUGAR_TEXT |
| |
| |
| ## ------------------ ## |
| ## m4_stack_foreach. ## |
| ## ------------------ ## |
| |
| AT_SETUP([m4@&t@_stack]) |
| |
| AT_KEYWORDS([m4@&t@_stack_foreach m4@&t@_stack_foreach_lifo]) |
| AT_KEYWORDS([m4@&t@_stack_foreach_sep m4@&t@_stack_foreach_sep_lifo]) |
| AT_KEYWORDS([m4@&t@_copy m4@&t@_n]) |
| |
| # Test the semantics of macros to walk stacked macro definitions. |
| AT_CHECK_M4SUGAR_TEXT([[dnl |
| m4_pushdef([abc], [def])dnl |
| m4_pushdef([abc], [ghi])dnl |
| m4_pushdef([abc], [jkl])dnl |
| m4_stack_foreach([abc], [m4_n]) |
| abc |
| m4_stack_foreach_lifo([abc], [m4_n]) |
| m4_stack_foreach([abc], [m4_n]) |
| m4_copy([abc], [foo])dnl |
| m4_stack_foreach([foo], [m4_n]) |
| m4_stack_foreach_lifo([foo], [m4_n]) |
| m4_stack_foreach_sep([abc], [ m4_index([abcdefghijkl],], [)]) |
| m4_define([colon], [:])m4_define([lt], [<])m4_define([gt], [>])dnl |
| m4_stack_foreach_sep_lifo([abc], [lt], [gt], [colon]) |
| m4_pushdef([xyz], [123])dnl |
| m4_pushdef([xyz], [456])dnl |
| m4_define([doit], [[$1](m4_stack_foreach_sep([xyz], [m4_dquote(], [)], [,])) |
| ])dnl |
| m4_stack_foreach([abc], [doit])]], |
| [[def |
| ghi |
| jkl |
| |
| jkl |
| jkl |
| ghi |
| def |
| |
| def |
| ghi |
| jkl |
| |
| def |
| ghi |
| jkl |
| |
| jkl |
| ghi |
| def |
| |
| 3 6 9 |
| <jkl>:<ghi>:<def> |
| def([123],[456]) |
| ghi([123],[456]) |
| jkl([123],[456]) |
| ]]) |
| |
| AT_CLEANUP |
| |
| |
| ## --------- ## |
| ## m4_defn. ## |
| ## --------- ## |
| |
| AT_SETUP([m4@&t@_defn]) |
| |
| AT_KEYWORDS([m4@&t@_popdef m4@&t@_undefine m4@&t@_copy m4@&t@_rename |
| m4@&t@_copy_force m4@&t@_rename_force]) |
| |
| # Ensure that m4sugar dies when dereferencing undefined macros, whether |
| # this is provided by m4 natively or faked by wrappers in m4sugar. |
| |
| AT_DATA_M4SUGAR([script.4s], |
| [[m4_define([good]) |
| m4_defn([good], [oops]) |
| ]]) |
| |
| AT_CHECK_M4SUGAR([-o-], 1, [], [stderr]) |
| AT_CHECK([grep good stderr], [1]) |
| AT_CHECK([grep 'm4@&t@_defn: undefined.*oops' stderr], [0], [ignore]) |
| |
| AT_DATA_M4SUGAR([script.4s], |
| [[m4_define([good]) |
| m4_popdef([good], [oops]) |
| ]]) |
| |
| AT_CHECK_M4SUGAR([-o-], 1, [], [stderr]) |
| AT_CHECK([grep good stderr], [1]) |
| AT_CHECK([grep 'm4@&t@_popdef: undefined.*oops' stderr], [0], [ignore]) |
| |
| AT_DATA_M4SUGAR([script.4s], |
| [[m4_define([good]) |
| m4_undefine([good], [oops]) |
| ]]) |
| |
| AT_CHECK_M4SUGAR([-o-], 1, [], [stderr]) |
| AT_CHECK([grep good stderr], [1]) |
| AT_CHECK([grep 'm4@&t@_undefine: undefined.*oops' stderr], [0], [ignore]) |
| |
| # Cannot rename an undefined macro. |
| AT_DATA_M4SUGAR([script.4s], |
| [[m4_rename([oops], [good]) |
| ]]) |
| |
| AT_CHECK_M4SUGAR([-o-], 1, [], [stderr]) |
| AT_CHECK([grep 'm4@&t@_undefine: undefined.*oops' stderr], [0], [ignore]) |
| |
| # Check that pushdef stacks can be renamed. |
| AT_CHECK_M4SUGAR_TEXT([[m4_pushdef([a], [1])dnl |
| m4_pushdef([a], [2])dnl |
| m4_pushdef([a], m4_defn([m4_divnum]))dnl |
| a b c |
| m4_rename([a], [b])dnl |
| a b c |
| m4_copy([b], [c])dnl |
| a b c |
| m4_popdef([b], [c])dnl |
| a b c |
| m4_popdef([b], [c])dnl |
| a b c |
| m4_popdef([b], [c])dnl |
| a b c |
| dnl m4_copy is intentionally a no-op on undefined source |
| m4_copy([oops], [dummy])m4_ifdef([dummy], [[oops]])dnl |
| dnl allow forceful overwrites |
| m4_define([d], [4])m4_define([e], [5])m4_define([f], [6])dnl |
| m4_copy_force([d], [e])dnl |
| m4_rename_force([d], [f])dnl |
| d e f |
| m4_popdef([e], [f])dnl |
| d e f |
| ]], [[0 b c |
| a 0 c |
| a 0 0 |
| a 2 2 |
| a 1 1 |
| a b c |
| d 4 4 |
| d e f |
| ]]) |
| |
| AT_CLEANUP |
| |
| |
| ## ------------ ## |
| ## m4_dumpdef. ## |
| ## ------------ ## |
| |
| AT_SETUP([m4@&t@_dumpdef]) |
| |
| AT_KEYWORDS([m4@&t@_dumpdefs]) |
| |
| # Ensure that m4sugar dies when dereferencing undefined macros. |
| |
| AT_DATA_M4SUGAR([script.4s], |
| [[m4_define([good], [yep]) |
| m4_dumpdef([good], [oops]) |
| ]]) |
| |
| AT_CHECK_M4SUGAR([-o-], 1, [], [stderr]) |
| AT_CHECK([grep '^good: \[[yep]]$' stderr], [0], [ignore]) |
| AT_CHECK([grep 'm4@&t@_dumpdef: undefined.*oops' stderr], [0], [ignore]) |
| |
| # Check that pushdef stacks can be dumped. |
| AT_CHECK_M4SUGAR_TEXT([[m4_divert_push([KILL]) |
| m4_pushdef([a], [1]) |
| m4_pushdef([a], [2]) |
| m4_dumpdef([a]) |
| m4_dumpdefs([oops], [a]) |
| m4_divert_pop([KILL])dnl |
| ]], [], |
| [[a: [2] |
| a: [2] |
| a: [1] |
| ]]) |
| |
| # Check behavior when dumping builtins. Unfortunately, when using M4 1.4.x |
| # (or more precisely, when __m4_version__ is undefined), builtins get |
| # flattened to an empty string. It takes M4 1.6 to work around this. |
| AT_DATA_M4SUGAR([script.4s], |
| [[m4_ifdef([__m4_version__], [_m4_undefine([__m4_version__])]) |
| m4_init |
| m4_dumpdef([m4_define]) |
| ]]) |
| |
| AT_CHECK_M4SUGAR([-o-], [0], [], |
| [[m4_define: [] |
| ]]) |
| |
| AT_DATA_M4SUGAR([script.4s], |
| [[m4_init |
| m4_ifdef([__m4_version__], |
| [m4_dumpdef([m4_define])], |
| [m4_errprintn([m4_define: <define>])]) |
| ]]) |
| |
| AT_CHECK_M4SUGAR([-o-], [0], [], |
| [[m4_define: <define> |
| ]]) |
| |
| AT_CLEANUP |
| |
| |
| ## --------- ## |
| ## m4_warn. ## |
| ## --------- ## |
| |
| AT_SETUP([m4@&t@_warn]) |
| AT_KEYWORDS([m4@&t@_warn]) |
| |
| AT_DATA_M4SUGAR([script.4s], |
| [[m4_init |
| m4_defun([cross_warning], [m4_warn([cross], [cross])]) |
| |
| m4_divert([0])dnl |
| m4_warn([obsolete], [obsolete])dnl |
| cross_warning[]dnl |
| m4_warn([syntax], [syntax])dnl |
| cross_warning[]dnl |
| m4_warn([syntax], [syntax])dnl |
| ]]) |
| |
| AT_CHECK_M4SUGAR([-o-], 0, [], |
| [script.4s:4: warning: prefer named diversions |
| script.4s:5: warning: obsolete |
| script.4s:7: warning: syntax |
| script.4s:9: warning: syntax |
| ]) |
| |
| AT_CHECK_M4SUGAR([-o- -Wall], 0, [], |
| [script.4s:4: warning: prefer named diversions |
| script.4s:5: warning: obsolete |
| script.4s:6: warning: cross |
| script.4s:2: cross_warning is expanded from... |
| script.4s:6: the top level |
| script.4s:7: warning: syntax |
| script.4s:8: warning: cross |
| script.4s:2: cross_warning is expanded from... |
| script.4s:8: the top level |
| script.4s:9: warning: syntax |
| ]) |
| |
| AT_CHECK_M4SUGAR([-o- -Wnone,cross], 0, [], |
| [script.4s:6: warning: cross |
| script.4s:2: cross_warning is expanded from... |
| script.4s:6: the top level |
| script.4s:8: warning: cross |
| script.4s:2: cross_warning is expanded from... |
| script.4s:8: the top level |
| ]) |
| |
| AT_CHECK_M4SUGAR([-o- -Wnone,cross,error], 1, [], |
| [[script.4s:6: warning: cross |
| script.4s:2: cross_warning is expanded from... |
| script.4s:6: the top level |
| script.4s:8: warning: cross |
| script.4s:2: cross_warning is expanded from... |
| script.4s:8: the top level |
| ]]) |
| |
| AT_CLEANUP |
| |
| ## ----------------------------------------------- ## |
| ## Bad m4_warn categories (Autoconf bug #110872). ## |
| ## ----------------------------------------------- ## |
| |
| AT_SETUP([m4@&t@_warn (bad categories)]) |
| AT_KEYWORDS([m4@&t@_warn]) |
| |
| AT_DATA_M4SUGAR([script.4s], |
| [[m4_init |
| m4_warn([], [empty category])dnl |
| m4_warn([bogus], [invalid category])dnl |
| m4_warn([!"\ %^&*], [line noise category])dnl " unconfuse editor |
| m4_warn([all], ['all' used as a category])dnl |
| m4_warn([none], ['none' used as a category])dnl |
| m4_warn([no-syntax], ['no-syntax' used as a category])dnl |
| m4_warn([no-bogus], ['no-bogus' used as a category])dnl |
| m4_warn([error], [oddly enough, this works])dnl |
| ]]) |
| |
| AT_CHECK_M4SUGAR([-o- -Wnone], 1, [], |
| [script.4s:3: error: unknown diagnostic category "bogus" |
| script.4s:4: error: unknown diagnostic category "!\"\\\x09%^&*" |
| script.4s:6: error: -W accepts "none", but it is not a diagnostic category |
| script.4s:7: error: -W accepts "no-syntax", but it is not a diagnostic category |
| script.4s:8: error: unknown diagnostic category "no-bogus" |
| script.4s:9: error: oddly enough, this works |
| ]) |
| |
| AT_CHECK_M4SUGAR([-o- -Wnone,obsolete], 1, [], |
| [script.4s:2: warning: use of "" as a diagnostic category is obsolete |
| script.4s:2: (see automake --help for a list of valid categories) |
| script.4s:3: error: unknown diagnostic category "bogus" |
| script.4s:4: error: unknown diagnostic category "!\"\\\x09%^&*" |
| script.4s:5: warning: use of "all" as a diagnostic category is obsolete |
| script.4s:5: (see automake --help for a list of valid categories) |
| script.4s:6: error: -W accepts "none", but it is not a diagnostic category |
| script.4s:7: error: -W accepts "no-syntax", but it is not a diagnostic category |
| script.4s:8: error: unknown diagnostic category "no-bogus" |
| script.4s:9: error: oddly enough, this works |
| ]) |
| |
| AT_CHECK_M4SUGAR([-o- -Wnone,obsolete,syntax], 1, [], |
| [script.4s:2: warning: use of "" as a diagnostic category is obsolete |
| script.4s:2: (see automake --help for a list of valid categories) |
| script.4s:2: warning: empty category |
| script.4s:3: error: unknown diagnostic category "bogus" |
| script.4s:3: warning: invalid category |
| script.4s:4: error: unknown diagnostic category "!\"\\\x09%^&*" |
| script.4s:4: warning: line noise category |
| script.4s:5: warning: use of "all" as a diagnostic category is obsolete |
| script.4s:5: (see automake --help for a list of valid categories) |
| script.4s:5: warning: 'all' used as a category |
| script.4s:6: error: -W accepts "none", but it is not a diagnostic category |
| script.4s:6: warning: 'none' used as a category |
| script.4s:7: error: -W accepts "no-syntax", but it is not a diagnostic category |
| script.4s:7: warning: 'no-syntax' used as a category |
| script.4s:8: error: unknown diagnostic category "no-bogus" |
| script.4s:8: warning: 'no-bogus' used as a category |
| script.4s:9: error: oddly enough, this works |
| ]) |
| |
| AT_CLEANUP |
| |
| ## ----------------- ## |
| ## m4_divert_stack. ## |
| ## ----------------- ## |
| |
| AT_SETUP([m4@&t@_divert_stack]) |
| AT_KEYWORDS([m4@&t@_divert m4@&t@_divert_push m4@&t@_divert_pop |
| m4@&t@_undivert m4@&t@_cleardivert m4@&t@_divert_text]) |
| |
| dnl This test names some diversions to avoid a warning. |
| AT_CHECK_M4SUGAR_TEXT([[m4_define([_m4_divert(ten)], [10])dnl |
| m4_define([_m4_divert(twenty)], [20])dnl |
| m4_define([_m4_divert(thirty)], [30])dnl |
| 1.m4_divert_stack |
| m4_divert_push([ten])2.m4_divert_stack |
| m4_divert_text([twenty], [3.m4_divert_stack])dnl |
| m4_divert([thirty])4.m4_divert_stack |
| m4_divert_pop([thirty])dnl |
| 5.m4_undivert([twenty], [thirty]) |
| m4_pattern_allow([^m4_divert])dnl |
| ]], [[1.script.4s:2: m4@&t@_divert_push: |
| script.4s:1: m4@&t@_divert: KILL |
| 5.3.script.4s:8: m4@&t@_divert_push: twenty |
| script.4s:7: m4@&t@_divert_push: ten |
| script.4s:2: m4@&t@_divert_push: |
| script.4s:1: m4@&t@_divert: KILL |
| 4.script.4s:9: m4@&t@_divert: thirty |
| script.4s:2: m4@&t@_divert_push: |
| script.4s:1: m4@&t@_divert: KILL |
| |
| 2.script.4s:7: m4@&t@_divert_push: ten |
| script.4s:2: m4@&t@_divert_push: |
| script.4s:1: m4@&t@_divert: KILL |
| ]]) |
| |
| AT_CHECK_M4SUGAR_TEXT([[dnl |
| m4_divert_text([3], [three])dnl |
| m4_divert_text([4], [four])dnl |
| m4_divert_text([1], [one])dnl |
| m4_divert_text([2], [two])dnl |
| m4_cleardivert([2], [3])dnl |
| ]], |
| [[one |
| four |
| ]], |
| [[script.4s:4: warning: prefer named diversions |
| script.4s:5: warning: prefer named diversions |
| script.4s:6: warning: prefer named diversions |
| script.4s:7: warning: prefer named diversions |
| script.4s:8: warning: prefer named diversions |
| ]]) |
| |
| 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: error: 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: error: 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: error: m4 failed with exit status: 1 |
| ]]) |
| |
| AT_CLEANUP |
| |
| |
| ## -------------------- ## |
| ## m4_expansion_stack. ## |
| ## -------------------- ## |
| |
| AT_SETUP([m4@&t@_expansion_stack]) |
| |
| AT_CHECK_M4SUGAR_TEXT([[1.m4_expansion_stack |
| m4_defun([a], [b])dnl |
| m4_define([c], [d])dnl |
| m4_defun([d], [2.m4_expansion_stack])dnl |
| m4_defun([b], [c])dnl |
| a |
| 3.m4_ifdef([_m4_expansion_stack], [m4_expansion_stack]) |
| ]], [[1.script.4s:3: the top level |
| 2.script.4s:6: d is expanded from... |
| script.4s:7: b is expanded from... |
| script.4s:4: a is expanded from... |
| script.4s:8: the top level |
| 3. |
| ]]) |
| |
| AT_CLEANUP |
| |
| |
| ## --------------------------- ## |
| ## m4_require: error message. ## |
| ## --------------------------- ## |
| |
| AT_SETUP([m4@&t@_require: error message]) |
| AT_KEYWORDS([m4@&t@_require]) |
| |
| AT_DATA_M4SUGAR([script.4s], |
| [[m4_defun([foo], [FOO]) |
| m4_require([foo]) |
| ]]) |
| |
| AT_CHECK_M4SUGAR([], 1, [], |
| [[script.4s:2: error: m4@&t@_require(foo): cannot be used outside of an m4_defun'd macro |
| script.4s:2: the top level |
| autom4te: error: m4 failed with exit status: 1 |
| ]]) |
| AT_CLEANUP |
| |
| |
| ## ----------------------------- ## |
| ## m4_require: warning message. ## |
| ## ----------------------------- ## |
| |
| AT_SETUP([m4@&t@_require: warning message]) |
| AT_KEYWORDS([m4@&t@_require m4@&t@_require_silent_probe]) |
| |
| # Mirror the job of aclocal on a typical scenario: the user invokes a |
| # single macro that comes from one included file, which in turn requires |
| # another macro from a second file. When using the incomplete set of |
| # files, we want a warning, unless we are merely learning which additional |
| # macros are needed in order to regenerate the list of files to include. |
| AT_DATA_M4SUGAR([script.4s], |
| [[m4_init |
| m4_include([script1.4s]) |
| foo |
| ]]) |
| |
| AT_DATA_M4SUGAR([script1.4s], |
| [[m4_defun([foo], [m4_require([bar])]) |
| ]]) |
| |
| AT_DATA_M4SUGAR([script2.4s], |
| [[m4_defun([bar], [BAR]) |
| ]]) |
| |
| AT_CHECK_M4SUGAR([], [0], [], |
| [[script.4s:3: warning: bar is m4@&t@_require'd but not m4@&t@_defun'd |
| script1.4s:1: foo is expanded from... |
| script.4s:3: the top level |
| ]]) |
| |
| # Inline expansion of AT_CHECK_M4SUGAR, mirroring how aclocal will |
| # inject a definition of our witness macro for a silent run. |
| echo 'm4@&t@_define([m4@&t@_require_silent_probe])' | |
| AT_CHECK_AUTOM4TE([--language=m4sugar - script.4s -o script], |
| [0], [], []) |
| |
| # Now that we have recomputed the set of include files, things should work. |
| AT_DATA_M4SUGAR([script.4s], |
| [[m4_init |
| m4_include([script1.4s]) |
| m4_include([script2.4s]) |
| foo |
| ]]) |
| |
| AT_CHECK_M4SUGAR([], [0], [], []) |
| |
| AT_CLEANUP |
| |
| |
| ## ----------------------------------- ## |
| ## m4_require: circular dependencies. ## |
| ## ----------------------------------- ## |
| |
| AT_SETUP([m4@&t@_require: circular dependencies]) |
| AT_KEYWORDS([m4@&t@_require]) |
| |
| AT_DATA_M4SUGAR([script.4s], |
| [[m4_defun([foo], [m4_require([bar])]) |
| |
| m4_defun([bar], [m4_require([foo])]) |
| |
| m4_defun([baz], [m4_require([foo])]) |
| |
| m4_init |
| m4_divert([0])dnl |
| baz |
| ]]) |
| |
| AT_CHECK_M4SUGAR([], 1, [], |
| [[script.4s:9: error: m4@&t@_require: circular dependency of foo |
| script.4s:3: bar is expanded from... |
| script.4s:1: foo is expanded from... |
| script.4s:5: baz is expanded from... |
| script.4s:9: the top level |
| autom4te: error: m4 failed with exit status: 1 |
| ]]) |
| AT_CLEANUP |
| |
| |
| ## ---------------------- ## |
| ## m4_require: one-shot. ## |
| ## ---------------------- ## |
| |
| AT_SETUP([m4@&t@_require: one-shot initialization]) |
| AT_KEYWORDS([m4@&t@_require]) |
| AT_KEYWORDS([m4@&t@_defun_init m4@&t@_copy m4@&t@_defun_once]) |
| |
| dnl check out m4_defun_init, m4_copy, and odd macro names |
| AT_CHECK_M4SUGAR_TEXT([[ |
| m4_define([t], [text])dnl |
| m4_defun_init([a], [[init a |
| ]], [[common a] t])dnl |
| m4_defun([b], [[b]m4_require([a])])dnl |
| m4_defun([c], [[c]m4_require([a])])dnl |
| b |
| c |
| a()dnl |
| |
| m4_defun_init([-], [hello, ], [m4_if([$#], [0], [world], [[$1]])])dnl |
| m4_copy([-], [.])dnl |
| m4_indir([.]) |
| m4_indir([.], [goodbye]) |
| m4_indir([-], [again]) |
| ]], [[ |
| init a |
| common a text |
| b |
| c |
| common a text |
| hello, world |
| goodbye |
| hello, again |
| ]]) |
| |
| dnl Check m4_defun_once behavior |
| AT_CHECK_M4SUGAR_TEXT([[ |
| m4_defun_once([a], [[a]])dnl |
| m4_defun([b], [[b]m4_require([a])])dnl |
| m4_defun([c], [[c]a[]m4_require([b])])dnl |
| c |
| a |
| m4_defun_once([d], [[d]m4_require([a])])dnl |
| d |
| m4_defun_once([e], [[e]])dnl |
| m4_defun([f], [[f]m4_require([e])e])dnl |
| f |
| ]], [[ |
| a |
| b |
| c |
| |
| d |
| e |
| f |
| ]]) |
| |
| |
| AT_CLEANUP |
| |
| |
| ## -------------------- ## |
| ## m4_require: nested. ## |
| ## -------------------- ## |
| |
| AT_SETUP([m4@&t@_require: nested]) |
| AT_KEYWORDS([m4@&t@_require m4@&t@_defun]) |
| |
| dnl From the m4sugar.m4 discourse: Require chains, top level |
| AT_CHECK_M4SUGAR_TEXT([[dnl |
| m4_defun([a], [[a]])dnl aka TEST2a |
| m4_defun([b], [[b]m4_require([a])])dnl aka TEST3 |
| m4_defun([c], [[c]m4_require([b])])dnl aka TEST2b |
| m4_defun([d], [[d]m4_require([a])m4_require([c])])dnl aka TEST1 |
| pre |
| d |
| d |
| post |
| ]], |
| [[pre |
| a |
| b |
| c |
| d |
| d |
| post |
| ]]) |
| |
| dnl From the m4sugar.m4 discourse: Require chains, nested |
| AT_CHECK_M4SUGAR_TEXT([[dnl |
| m4_defun([a], [[a]])dnl aka TEST2a |
| m4_defun([b], [[b]m4_require([a])])dnl aka TEST3 |
| m4_defun([c], [[c]m4_require([b])])dnl aka TEST2b |
| m4_defun([d], [[d]m4_require([a])m4_require([c])])dnl aka TEST1 |
| m4_defun([wrap], |
| [pre |
| d |
| d |
| post])dnl |
| wrap |
| ]], |
| [[a |
| b |
| c |
| pre |
| d |
| d |
| post |
| ]]) |
| |
| dnl Direct invocation, nested requires, top level |
| AT_CHECK_M4SUGAR_TEXT([[dnl |
| m4_defun([a], [[a]])dnl |
| m4_defun([b], [[b]m4_require([a])])dnl |
| m4_defun([c], [[c]m4_require([b])])dnl |
| pre |
| a |
| c |
| a |
| c |
| post |
| ]], |
| [[pre |
| a |
| b |
| c |
| a |
| c |
| post |
| ]]) |
| |
| dnl Direct invocation, nested requires, nested defun. This is an example |
| dnl of expansion before requirement, such that b occurs before its |
| dnl prerequisite a. This indicates a bug in the macros (but not in |
| dnl autoconf), so we should be emitting a warning. |
| AT_CHECK_M4SUGAR_TEXT([[dnl |
| m4_defun([a], [[a]])dnl |
| m4_defun([b], [[b]m4_require([a])])dnl |
| m4_defun([c], [[c]m4_require([b])])dnl |
| dnl the extra macro layer works around line number differences in older m4 |
| m4_define([foo], [m4_defun([outer], |
| [pre |
| a |
| c |
| a |
| c |
| post])])foo[]dnl |
| outer |
| ]], |
| [[a |
| b |
| pre |
| a |
| c |
| a |
| c |
| post |
| ]], |
| [[script.4s:15: warning: m4@&t@_require: 'a' was expanded before it was required |
| script.4s:15: https://www.gnu.org/software/autoconf/manual/autoconf.html#Expanded-Before-Required |
| script.4s:5: b is expanded from... |
| script.4s:6: c is expanded from... |
| script.4s:14: outer is expanded from... |
| script.4s:15: the top level |
| ]]) |
| |
| dnl Direct invocation, expand-before-require but no nested require. As this |
| dnl is common in real life, but does not result in out-of-order expansion, |
| dnl we silently permit this. |
| AT_CHECK_M4SUGAR_TEXT([[dnl |
| m4_defun([a], [[a]])dnl |
| m4_defun([b], [[b]m4_require([a])])dnl |
| m4_defun([c], [[c]])dnl |
| m4_defun([d], [[d]m4_require([c])])dnl |
| pre1 |
| a |
| b |
| a |
| b |
| post1 |
| m4_defun([outer], |
| [pre2 |
| c |
| d |
| c |
| d |
| post2])dnl |
| outer |
| m4_defun([e], [[e]])dnl |
| m4_defun([f], [[f]m4_require([e])])dnl |
| m4_defun([g], [[g] |
| e |
| f])dnl |
| m4_defun([h], [[h]m4_require([g])])dnl |
| h |
| m4_defun([i], [[i]])dnl |
| m4_defun([j], [[j] |
| i])dnl |
| m4_defun([k], [[k]m4_require([i])])dnl |
| m4_defun([l], [[l]m4_require([k])])dnl |
| m4_defun([m], [[m]m4_require([j])m4_require([l])])dnl |
| m |
| ]], |
| [[pre1 |
| a |
| b |
| a |
| b |
| post1 |
| pre2 |
| c |
| d |
| c |
| d |
| post2 |
| g |
| e |
| f |
| h |
| j |
| i |
| k |
| l |
| m |
| ]]) |
| |
| AT_CLEANUP |
| |
| |
| ## ------------------------------------------------- ## |
| ## m4_ifval, m4_ifblank, m4_ifset, m4_default, etc. ## |
| ## ------------------------------------------------- ## |
| |
| AT_SETUP([m4sugar shorthand conditionals]) |
| AT_KEYWORDS([m4@&t@_ifval m4@&t@_ifblank m4@&t@_ifnblank m4@&t@_ifset |
| m4@&t@_default m4@&t@_default_quoted m4@&t@_default_nblank |
| m4@&t@_default_nblank_quoted]) |
| |
| AT_CHECK_M4SUGAR_TEXT([[m4_define([active], [ACTIVE])m4_define([empty]) |
| m4_ifval([active], [yes], [no]) |
| m4_ifval([empty], [yes], [no]) |
| m4_ifval([ ], [yes], [no]) |
| m4_ifval([], [yes], [no]) |
| m4_ifblank([active], [yes], [no]) |
| m4_ifblank([empty], [yes], [no]) |
| m4_ifblank([ ], [yes], [no]) |
| m4_ifblank([], [yes], [no]) |
| m4_ifnblank([active], [yes], [no]) |
| m4_ifnblank([empty], [yes], [no]) |
| m4_ifnblank([ ], [yes], [no]) |
| m4_ifnblank([], [yes], [no]) |
| m4_ifset([active], [yes], [no]) |
| m4_ifset([empty], [yes], [no]) |
| m4_ifset([ ], [yes], [no]) |
| m4_ifset([], [yes], [no]) |
| --- |
| m4_define([demo1], [m4_default([$1], [$2])])dnl |
| m4_define([demo2], [m4_default_quoted([$1], [$2])])dnl |
| m4_define([demo3], [m4_default_nblank([$1], [$2])])dnl |
| m4_define([demo4], [m4_default_nblank_quoted([$1], [$2])])dnl |
| demo1([active], [default]) |
| demo1([], [active]) |
| demo1([empty], [text]) |
| -demo1([ ], [active])- |
| demo2([active], [default]) |
| demo2([], [active]) |
| demo2([empty], [text]) |
| -demo2([ ], [active])- |
| demo3([active], [default]) |
| demo3([], [active]) |
| demo3([empty], [text]) |
| -demo3([ ], [active])- |
| demo4([active], [default]) |
| demo4([], [active]) |
| demo4([empty], [text]) |
| -demo4([ ], [active])- |
| ]], [[ |
| yes |
| yes |
| yes |
| no |
| no |
| no |
| yes |
| yes |
| yes |
| yes |
| no |
| no |
| yes |
| no |
| no |
| no |
| --- |
| ACTIVE |
| ACTIVE |
| |
| - - |
| active |
| active |
| empty |
| - - |
| ACTIVE |
| ACTIVE |
| |
| -ACTIVE- |
| active |
| active |
| empty |
| -active- |
| ]]) |
| |
| AT_CLEANUP |
| |
| ## --------- ## |
| ## m4_cond. ## |
| ## --------- ## |
| |
| AT_SETUP([m4@&t@_cond]) |
| |
| AT_CHECK_M4SUGAR_TEXT([[m4_define([side], [m4_errprintn([$1])$1]) |
| m4_cond([side(1)], [1], [a], |
| [side(1)], [1], [b], |
| [side(1)], [2], [c]) |
| m4_cond([side(2)], [1], [a], |
| [side(2)], [1], [b], |
| [side(2)], [2], [c], |
| [side(2)]) |
| m4_cond([side(3)], [1], [a], |
| [side(3)], [1], [b], |
| [side(3)], [2], [c], |
| [side(3)]) |
| m4_cond([a,a], [a,a], [yes], [no]) |
| m4_cond([[a,a]], [a,a], [yes]) |
| m4_cond([a,a], [a,b], [yes], [no]) |
| m4_cond([a,a], [a,b], [yes]) |
| m4_cond([m4_eval([0xa])]) |
| m4_define([ab], [AB])dnl |
| m4_cond([a])b |
| m4_cond([1], [1], [a])b |
| m4_cond([1], [2], [3], [a])b |
| ]], [[ |
| a |
| c |
| 3 |
| yes |
| yes |
| no |
| |
| 10 |
| AB |
| AB |
| AB |
| ]], [[1 |
| 2 |
| 2 |
| 2 |
| 3 |
| 3 |
| 3 |
| 3 |
| ]]) |
| |
| AT_CLEANUP |
| |
| |
| ## ---------- ## |
| ## m4 lists. ## |
| ## ---------- ## |
| |
| AT_SETUP([m4 lists]) |
| |
| AT_KEYWORDS([m4@&t@_car m4@&t@_cdr m4@&t@_argn _m4@&t_cdr]) |
| |
| AT_CHECK_M4SUGAR_TEXT([[dnl |
| m4_define([a], [A])m4_define([b], [B])m4_define([c], [C]) |
| m4_argn([1], [a], [b], [c]) |
| m4_argn([2], [a], [b], [c]) |
| m4_argn([3], [a], [b], [c]) |
| m4_argn([4], [a], [b], [c]) |
| m4_car([a], [b], [c]) |
| m4_cdr([a], [b], [c]) |
| m4_cdr([a], [b]) |
| m4_cdr([a]) |
| _m4_cdr([a], [b], [c]) |
| _m4_cdr([a], [b]) |
| _m4_cdr([a]) |
| m4_if(m4_cdr([], []), [[]], [good], [bad]) |
| m4_if(m4_cdr([]), [], [good], [bad]) |
| ]], [[ |
| a |
| b |
| c |
| |
| a |
| [b],[c] |
| [b] |
| |
| , [b],[c] |
| , [b] |
| |
| good |
| good |
| ]]) |
| |
| AT_DATA_M4SUGAR([script.4s], |
| [[m4_init |
| m4_argn([0], [a], [b], [c]) |
| ]]) |
| AT_CHECK_M4SUGAR([-o-], [1], [], |
| [[script.4s:2: error: assert failed: 0 < 0 |
| script.4s:2: the top level |
| autom4te: error: m4 failed with exit status: 1 |
| ]]) |
| |
| AT_CLEANUP |
| |
| |
| ## ---------- ## |
| ## m4_split. ## |
| ## ---------- ## |
| |
| AT_SETUP([m4@&t@_split]) |
| |
| AT_CHECK_M4SUGAR_TEXT( |
| [[m4_define([active], [ACT, IVE])m4_define([bd], [oops]) |
| m4_split |
| m4_split([[]]) |
| m4_split([ ]) |
| m4_split([active]) |
| m4_split([ active active ])end |
| m4_split([ ], [ ]) |
| m4_split([active], [ ]) |
| m4_split([ active active ], [ ])end |
| m4_split([abcde], [bd]) |
| m4_split([abcde], [[bd]]) |
| m4_split([foo=`` bar='']) |
| m4_split([foo='' bar=``]) |
| dnl these next two are from the manual; keep this in sync if the internal |
| dnl quoting strings in m4_split are changed |
| m4_define([a], [A])m4_define([b], [B])m4_define([c], [C])dnl |
| m4_split([a )}>=- b -=<{( c]) |
| m4_split([a )}@&t@>=- b -=<@&t@{( c]) |
| ]], |
| [[ |
| |
| [[]] |
| [], [] |
| [active] |
| [], [active], [active], []end |
| [], [] |
| [active] |
| [], [active active], []end |
| [abcde] |
| [a], [c], [e] |
| [foo=``], [bar=''] |
| [foo=''], [bar=``] |
| [a], [], [B], [], [c] |
| [a], [)}>=@&t@-], [b], [-@&t@=<{(], [c] |
| ]]) |
| |
| AT_CLEANUP |
| |
| |
| ## ------- ## |
| ## m4_do. ## |
| ## ------- ## |
| |
| AT_SETUP([m4@&t@_do]) |
| |
| AT_CHECK_M4SUGAR_TEXT( |
| [[m4_define([ab], [1])m4_define([bc], [2])m4_define([abc], [3])dnl |
| m4_define([AB], [4])m4_define([BC], [5])m4_define([ABC], [6])dnl |
| m4_do |
| m4_do([a]) |
| m4_do([a], [b])c |
| m4_unquote(m4_join([], [a], [b]))c |
| m4_define([a], [A])m4_define([b], [B])m4_define([c], [C])dnl |
| m4_do([a], [b])c |
| m4_unquote(m4_join([], [a], [b]))c |
| ]], |
| [[ |
| a |
| abc |
| 3 |
| ABC |
| 3 |
| ]]) |
| |
| AT_CLEANUP |
| |
| |
| ## ----------- ## |
| ## m4_append. ## |
| ## ----------- ## |
| |
| AT_SETUP([m4@&t@_append]) |
| AT_KEYWORDS([m4@&t@_append_uniq m4@&t@_append_uniq_w]) |
| |
| AT_CHECK_M4SUGAR_TEXT( |
| [[m4_define([active], [ACTIVE])dnl |
| m4_append([sentence], [This is an])dnl |
| m4_append([sentence], [ active ])dnl |
| m4_append([sentence], [symbol.])dnl |
| sentence |
| m4_undefine([active])dnl |
| sentence |
| m4_define([active], [ACTIVE])dnl |
| m4_append([hooks], [m4_define([act1], [act2])])dnl |
| m4_append([hooks], [m4_define([act2], [active])])dnl |
| m4_undefine([active])dnl |
| act1 |
| hooks |
| act1 |
| dnl Test for bug fixed in 2.62 when separator is active. |
| m4_define([a], [A])dnl |
| m4_append_uniq([foo], [-], [a])dnl |
| m4_append_uniq([foo], [-], [a])dnl |
| m4_append_uniq([bar], [-], [a])dnl |
| m4_append_uniq([bar], [~], [a])dnl |
| m4_append_uniq([bar], [-], [a])dnl |
| m4_defn([foo]) |
| m4_defn([bar]) |
| foo |
| bar |
| m4_append_uniq([blah], [one], [, ], [new], [existing]) |
| m4_append_uniq([blah], [two], [, ], [new], [existing]) |
| m4_append_uniq([blah], [two], [, ], [new], [existing]) |
| m4_append_uniq([blah], [three], [, ], [new], [existing]) |
| m4_append([blah], [two], [, ])dnl |
| blah |
| m4_dquote(blah) |
| m4_append([list], [one], [[, ]])dnl |
| m4_append([list], [two], [[, ]])dnl |
| m4_append([list], [three], [[, ]])dnl |
| list |
| m4_dquote(list) |
| m4_append_uniq_w([numbers], [1 1 2])dnl |
| m4_append_uniq_w([numbers], [ 2 3 ])dnl |
| numbers |
| ]], |
| [[This is an ACTIVE symbol. |
| This is an active symbol. |
| act1 |
| |
| active |
| - |
| -a~ |
| - |
| -A~ |
| new |
| new |
| existing |
| new |
| one, two, three, two |
| [one],[two],[three],[two] |
| one, two, three |
| [one, two, three] |
| 1 2 3 |
| ]]) |
| |
| AT_DATA_M4SUGAR([script.4s], |
| [[m4_init[]dnl |
| m4_append_uniq([str], [a], [ ]) |
| m4_append_uniq([str], [a b], [ ]) |
| m4_divert([])dnl |
| str |
| ]]) |
| |
| AT_CHECK_M4SUGAR([-o-], 0, [[a a b |
| ]], [[script.4s:3: warning: m4@&t@_append_uniq: 'a b' contains ' ' |
| ]]) |
| |
| AT_CLEANUP |
| |
| |
| ## --------- ## |
| ## m4_join. ## |
| ## --------- ## |
| |
| AT_SETUP([m4@&t@_join]) |
| |
| AT_KEYWORDS([m4@&t@_joinall]) |
| |
| AT_CHECK_M4SUGAR_TEXT( |
| [[m4_define([active], [ACTIVE])dnl |
| m4_join |
| m4_join([|]) |
| m4_join([|], [one]) |
| m4_join([|], [one], [two]) |
| m4_join([|], [one], [], [two]) |
| m4_join([], [one], [two]) |
| m4_join([], [one], [], [two]) |
| m4_join([, ], [one], [two]) |
| m4_dquote(m4_join([, ], [one], [two])) |
| m4_join([|], [active], [active]) |
| m4_join([|], [active], [], [active]) |
| m4_join([ active ], [one], , [two]) |
| m4_join([|], ,,,[one]) |
| m4_join([|], [one],,,) |
| m4_join([], ,,,[two]) |
| m4_join([], [two],,,) |
| m4_join([|], [], [], [three], [], []) |
| ---- |
| m4_joinall |
| m4_joinall([-]) |
| m4_joinall([-], [one]) |
| m4_joinall([-], [one], [two]) |
| m4_joinall([-], [one], [], [two]) |
| m4_joinall([], [one], [two]) |
| m4_joinall([], [one], [], [two]) |
| m4_joinall([, ], [one], [two]) |
| m4_dquote(m4_joinall([, ], [one], [two])) |
| m4_joinall([-], [active], [active]) |
| m4_joinall([-], [active], [], [active]) |
| m4_joinall([ active ], [one], , [two]) |
| m4_joinall([-], ,,,[one]) |
| m4_joinall([-], [one],,,) |
| m4_joinall([], ,,,[two]) |
| m4_joinall([], [two],,,) |
| m4_joinall([-], [], [], [three], [], []) |
| ]], |
| [[ |
| |
| one |
| one|two |
| one|two |
| onetwo |
| onetwo |
| one, two |
| [one, two] |
| active|active |
| active|active |
| one active two |
| one |
| one |
| two |
| two |
| three |
| ---- |
| |
| |
| one |
| one-two |
| one--two |
| onetwo |
| onetwo |
| one, two |
| [one, two] |
| active-active |
| active--active |
| one active active two |
| ---one |
| one--- |
| two |
| two |
| --three-- |
| ]]) |
| |
| AT_CLEANUP |
| |
| |
| ## ----------- ## |
| ## m4_expand. ## |
| ## ----------- ## |
| |
| AT_SETUP([m4@&t@_expand]) |
| |
| AT_CHECK_M4SUGAR_TEXT( |
| [[m4_define([active], [ACTIVE])dnl |
| m4_expand([#active |
| active]) |
| m4_expand([[active]]) |
| dnl properly quoted case statements |
| m4_expand([case a in @%:@( |
| *) echo active, ;; |
| esac |
| case b in |
| *[)] echo active, ;; |
| esac]) |
| dnl unbalanced underquoted ')', but we manage anyway (gasp!) |
| m4_expand([case c in #( |
| *) echo active, ;; |
| esac |
| case d in |
| *) echo active, ;; |
| esac]) |
| dnl unterminated comment/dnl |
| m4_expand([active # active]) |
| m4_expand([a |
| dnl]) |
| m4_expand([a |
| -dnl]) |
| ]], |
| [[#active |
| ACTIVE |
| active |
| case a in #( |
| *) echo ACTIVE, ;; |
| esac |
| case b in |
| *) echo ACTIVE, ;; |
| esac |
| case c in #( |
| *) echo ACTIVE, ;; |
| esac |
| case d in |
| *) echo ACTIVE, ;; |
| esac |
| ACTIVE # active |
| a |
| a |
| - |
| ]]) |
| |
| AT_CLEANUP |
| |
| |
| ## ------------- ## |
| ## m4_text_box. ## |
| ## ------------- ## |
| |
| AT_SETUP([m4@&t@_text_box]) |
| |
| AT_CHECK_M4SUGAR_TEXT([[ |
| m4_text_box([a $1 @&t@b]) |
| m4_text_box([a $1 @&t@b], [$]) |
| m4_text_box([a $1 @&t@b], [,]) |
| ]], [[ |
| ## ------ ## |
| ## a $1 b ## |
| ## ------ ## |
| ## $$$$$$ ## |
| ## a $1 b ## |
| ## $$$$$$ ## |
| ## ,,,,,, ## |
| ## a $1 b ## |
| ## ,,,,,, ## |
| ]]) |
| |
| AT_CLEANUP |
| |
| ## -------------- ## |
| ## m4_text_wrap. ## |
| ## -------------- ## |
| |
| AT_SETUP([m4@&t@_text_wrap]) |
| AT_KEYWORDS([m4@&t@_escape]) |
| |
| # m4_text_wrap is used to display the help strings. Also, check that |
| # commas and $ are not swallowed. This can easily happen because of |
| # m4-listification. |
| |
| AT_DATA_M4SUGAR([script.4s], |
| [[m4_init[]m4_divert([])dnl |
| m4_define([a], [OOPS])dnl |
| m4_escape([a[b $c#]d]) |
| m4_if(m4_escape([a[b $c#]d]), [a[b $c#]d], [oops], |
| m4_escape([a[b $c#]d]), [a@<:@b @S|@c@%:@@:>@d], [pass], [oops]) |
| |
| m4_text_wrap([Short string */], [ ], [/* ], 20) |
| |
| m4_text_wrap([Much longer string */], [ ], [/* ], 20) |
| |
| m4_text_wrap([Short doc.], [ ], [ --short ], 30) |
| |
| m4_text_wrap([Short doc.], [ ], [ --too-wide], 30) |
| |
| m4_text_wrap([Super long documentation.], [ ], [ --too-wide], 30) |
| |
| m4_text_wrap([First, second , third, [,quoted space]]) |
| m4_define([xfff], [oops]) |
| m4_text_wrap([Some $1 $2 $3 $4 embedded dollars.], [ $* ], [ $@ ], [0xfff & 20]) |
| ]]) |
| |
| AT_DATA([expout], |
| [[a[b $c#]d |
| pass |
| |
| /* Short string */ |
| |
| /* Much longer |
| string */ |
| |
| --short Short doc. |
| |
| --too-wide |
| Short doc. |
| |
| --too-wide |
| Super long |
| documentation. |
| |
| First, second , third, [,quoted space] |
| |
| $@ Some $1 $2 $3 |
| $* $4 embedded |
| $* dollars. |
| ]]) |
| |
| AT_CHECK_M4SUGAR([-o-], 0, [expout]) |
| |
| AT_CLEANUP |
| |
| ## -------------------- ## |
| ## m4_version_compare. ## |
| ## -------------------- ## |
| |
| AT_SETUP([m4@&t@_version_compare]) |
| |
| AT_KEYWORDS([m4@&t@_list_cmp]) |
| |
| AT_CHECK_M4SUGAR_TEXT( |
| [[m4_version_compare([1.1], [2.0]) |
| m4_version_compare([2.0b], [2.0a]) |
| m4_version_compare([2.0z], [2.0y]) |
| m4_version_compare([1.1.1], [1.1.1a]) |
| m4_version_compare([1.2], [1.1.1a]) |
| m4_version_compare([1.0], [1]) |
| m4_version_compare([1.0a], [1.0a]) |
| m4_version_compare([1.1a], [1.1a.1]) |
| m4_version_compare([1.10], [1.1a]) |
| m4_version_compare([1-1a], [1,1A]) |
| m4_define([a], [oops])dnl |
| m4_version_compare([1.1a], [1.1A]) |
| m4_version_compare([1z], [1aa]) |
| m4_version_compare([2.61a], [2.61a-248-dc51]) |
| m4_version_compare([2.61b], [2.61a-248-dc51]) |
| m4_version_compare([08], [09]) |
| m4_version_compare([010], [8]) |
| dnl Test that side effects to m4_list_cmp occur exactly once |
| m4_list_cmp([[0], [0], [0]m4_errprintn([hi])], |
| [[0], [0], [0]m4_errprintn([hi])]) |
| m4_list_cmp([[0], [0], [0]m4_errprintn([hi])], |
| [[0], [0], [0]m4_errprintn([bye])]) |
| ]], |
| [[-1 |
| 1 |
| 1 |
| -1 |
| 1 |
| 0 |
| 0 |
| -1 |
| 1 |
| 0 |
| 0 |
| -1 |
| -1 |
| 1 |
| -1 |
| 1 |
| 0 |
| 0 |
| ]], [[hi |
| hi |
| hi |
| bye |
| ]]) |
| |
| AT_CLEANUP |
| |
| ## ------------------------------ ## |
| ## Standard regular expressions. ## |
| ## ------------------------------ ## |
| |
| AT_SETUP([Standard regular expressions]) |
| |
| # AT_CHECK_M4RE(RE-NAME, TEXT, INTENT = 'ok' | '') |
| # ------------------------------------------------ |
| # Check whether RE-NAME (a macro whose definition is a regular expression) |
| # matches TEXT. INTENT = 'ok' if the match should succeed or else empty. |
| m4_define([AT_CHECK_M4RE], |
| [AT_CHECK_M4SUGAR_TEXT( |
| [[m4_bregexp([$2], ^m4_defn([$1])$, [ok]) |
| ]], [$3 |
| ])]) |
| |
| AT_CHECK_M4RE([m4_re_word], [ab9_c], [ok]) |
| AT_CHECK_M4RE([m4_re_word], [_9abc], [ok]) |
| AT_CHECK_M4RE([m4_re_word], [9ab_c]) |
| |
| AT_CHECK_M4RE([m4_re_string], [ab9_c], [ok]) |
| AT_CHECK_M4RE([m4_re_string], [_9abc], [ok]) |
| AT_CHECK_M4RE([m4_re_string], [9ab_c], [ok]) |
| AT_CHECK_M4RE([m4_re_string], [9a@_c]) |
| |
| AT_CLEANUP |
| |
| ## ----------- ## |
| ## m4_bmatch. ## |
| ## ----------- ## |
| |
| AT_SETUP([m4@&t@_bmatch]) |
| |
| AT_CHECK_M4SUGAR_TEXT( |
| [[m4_bmatch([abc], [default\]) |
| m4_bmatch([abc], [^a], [yes]) |
| m4_bmatch([abc], [^a], [yes], [no]) |
| m4_bmatch([abc], [^.a], [yes]) |
| m4_bmatch([abc], [^.a], [yes], [no\]) |
| m4_bmatch([abc], [a], [1], [b], [2]) |
| m4_bmatch([abc], [A], [1], [b], [2]) |
| m4_define([ab], [AB])dnl |
| m4_bmatch([$*], [a])b |
| m4_bmatch([$*], [\*], [a])b |
| m4_bmatch([$*], [1], [2], [a])b |
| ]], [[default\ |
| yes |
| yes |
| |
| no\ |
| 1 |
| 2 |
| AB |
| AB |
| AB |
| ]]) |
| |
| AT_CLEANUP |
| |
| ## ------------------------ ## |
| ## m4_toupper, m4_tolower. ## |
| ## ------------------------ ## |
| |
| AT_SETUP([m4@&t@_toupper and m4@&t@_tolower]) |
| |
| AT_CHECK_M4SUGAR_TEXT( |
| [[m4_define([abc], [hI])m4_define([ABC], [Hi]) |
| m4_toupper(abc aBc ABC) |
| m4_tolower(abc aBc ABC) |
| m4_toupper([abc aBc ABC]) |
| m4_tolower([abc aBc ABC]) |
| m4_echo(m4_toupper(abc aBc ABC)) |
| m4_echo(m4_tolower(abc aBc ABC)) |
| m4_echo(m4_toupper([abc aBc ABC])) |
| m4_echo(m4_tolower([abc aBc ABC])) |
| m4_do(m4_toupper(abc aBc ABC)) |
| m4_do(m4_tolower(abc aBc ABC)) |
| m4_do(m4_toupper([abc aBc ABC])) |
| m4_do(m4_tolower([abc aBc ABC])) |
| ]], [[ |
| HI ABC HI |
| hi abc hi |
| ABC ABC ABC |
| abc abc abc |
| HI ABC HI |
| hi abc hi |
| ABC ABC ABC |
| abc abc abc |
| HI Hi HI |
| hi hI hi |
| Hi Hi Hi |
| hI hI hI |
| ]]) |
| |
| AT_CLEANUP |
| |
| ## --------------- ## |
| ## m4_bpatsubsts. ## |
| ## --------------- ## |
| |
| AT_SETUP([m4@&t@_bpatsubsts]) |
| |
| AT_CHECK_M4SUGAR_TEXT( |
| [[m4_bpatsubsts([11], [^..$]) |
| m4_bpatsubsts([11], [\(.\)1], [\12]) |
| m4_bpatsubsts([11], [^..$], [], [1], [2]) |
| m4_bpatsubsts([11], [\(.\)1], [\12], [1], [3]) |
| m4_define([a], [oops])m4_define([c], [oops])dnl |
| m4_define([AB], [good])m4_define([bc], [good])dnl |
| m4_bpatsubsts([abc], [a], [A], [b], [B], [c]) |
| m4_bpatsubsts([ab], [a])c |
| m4_bpatsubsts([ab], [c], [C], [a])c |
| m4_bpatsubsts([$1$*$@], [\$\*], [$#]) |
| ]], [[11 |
| 21 |
| 22 |
| 23 |
| good |
| good |
| good |
| $1$#$@ |
| ]]) |
| |
| AT_CLEANUP |
| |
| ## -------------- ## |
| ## m4_esyscmd_s. ## |
| ## -------------- ## |
| |
| AT_SETUP([m4@&t@_esyscmd_s]) |
| AT_KEYWORDS([m4@&t@_chomp m4@&t@_chomp_all]) |
| |
| AT_CHECK_M4SUGAR_TEXT( |
| [[m4_define([world], [WORLD])dnl |
| m4_chomp([abc]) |
| m4_chomp([world |
| |
| ]) |
| m4_esyscmd_s([echo hello world]) |
| m4_esyscmd_s([echo '[goodbye, |
| cruel world |
| |
| ]']) |
| ]], [[abc |
| world |
| |
| hello WORLD |
| goodbye, |
| cruel world |
| ]]) |
| |
| AT_CLEANUP |
| |
| ## ---------- ## |
| ## M4 Loops. ## |
| ## ---------- ## |
| |
| AT_SETUP([M4 loops]) |
| |
| AT_KEYWORDS([m4@&t@_for m4@&t@_foreach m4@&t@_foreach_w m4@&t@_map_args_w]) |
| |
| AT_CHECK_M4SUGAR_TEXT([[dnl |
| m4_define([myvar], [outer value])dnl |
| m4_for([myvar], 1, 3, 1, [ myvar]) |
| m4_for([myvar], 1, 3, , [ myvar]) |
| m4_for([myvar], 3, 1,-1, [ myvar]) |
| m4_for([myvar], 3, 1, , [ myvar]) |
| m4_for([myvar], 1, 3, 2, [ myvar]) |
| m4_for([myvar], 3, 1,-2, [ myvar]) |
| m4_for([myvar],-1,-3,-2, [ myvar]) |
| m4_for([myvar],-3,-1, 2, [ myvar]) |
| dnl Make sure we recalculate the bounds correctly: |
| m4_for([myvar], 1, 3, 3, [ myvar]) |
| m4_for([myvar], 1, 6, 3, [ myvar]) |
| m4_for([myvar],22,-7,-5, [ myvar]) |
| m4_for([myvar],-2,-7,-4, [ myvar]) |
| m4_for([myvar],-7,-2, 4, [ myvar]) |
| dnl Make sure we are not exposed to division truncation: |
| m4_for([myvar], 2, 5, 2, [ myvar]) |
| m4_for([myvar],-5,-2, 2, [ myvar]) |
| m4_for([myvar], 5, 2,-2, [ myvar]) |
| m4_for([myvar],-2,-5,-2, [ myvar]) |
| dnl Make sure we do not divide by zero: |
| m4_for([myvar], 1, 1, , [ myvar]) |
| m4_for([myvar], 1, 1,+2, [ myvar]) |
| m4_for([myvar], 1, 1,-2, [ myvar]) |
| dnl Make sure we do not loop endlessly |
| m4_for([myval], 1, 1, 0, [ myval]) |
| dnl Make sure to properly parenthesize |
| m4_for([myvar], 3-5, -2+8, , [ myvar]) |
| m4_for([myvar], -2+8, 3-5, , [ myvar]) |
| m4_for([myvar], 8, 16, 3 * 2, [ myvar]) |
| m4_for([myvar], 8, 16, -3 * -2, [ myvar]) |
| m4_for([myvar], [2<<2], [2<<3], [-3 * (-2)], [ myvar]) |
| dnl Modifying var does not affect the number of iterations |
| m4_for([myvar], 1, 5, , [ myvar[]m4_define([myvar], 5)]) |
| dnl Make sure we can do nameless iteration |
| m4_for(, 1, 10, , -) |
| dnl foreach tests |
| m4_foreach([myvar], [[a], [b, c], [d], [e |
| ],[f]], [ myvar|]) |
| m4_foreach_w([myvar], [a b c, d,e f |
| g], [ myvar|]) |
| myvar |
| m4_map_args_w([a b c, d,e f |
| g], [ ], [|]) |
| m4_map_args_w([a b], [\1], [/]) |
| m4_define([dashes], [--])dnl |
| m4_map_args_w([a b c], [/], [\1], [dashes]) |
| dnl only one side effect expansion, prior to visiting list elements |
| m4_foreach([i], [[1], [2], [3]m4_errprintn([hi])], [m4_errprintn(i)])dnl |
| dnl shifting forms an important part of loops |
| m4_shift3:m4_shift3(1,2,3):m4_shift3(1,2,3,4) |
| m4_shiftn(3,1,2,3):m4_shiftn(3,1,2,3,4) |
| ]], |
| [[ 1 2 3 |
| 1 2 3 |
| 3 2 1 |
| 3 2 1 |
| 1 3 |
| 3 1 |
| -1 -3 |
| -3 -1 |
| 1 |
| 1 4 |
| 22 17 12 7 2 -3 |
| -2 -6 |
| -7 -3 |
| 2 4 |
| -5 -3 |
| 5 3 |
| -2 -4 |
| 1 |
| 1 |
| 1 |
| 1 |
| -2 -1 0 1 2 3 4 5 6 |
| 6 5 4 3 2 1 0 -1 -2 |
| 8 14 |
| 8 14 |
| 8 14 |
| 1 2 3 4 5 |
| ---------- |
| a| b, c| d| e |
| | f| |
| a| b| c,| d,e| f| g| |
| outer value |
| a| b| c,| d,e| f| g| |
| \1a/\1b/ |
| /a\1--/b\1--/c\1 |
| ::4 |
| :4 |
| ]], [[hi |
| 1 |
| 2 |
| 3 |
| ]]) |
| |
| dnl bounds checking in m4_for |
| AT_DATA_M4SUGAR([script.4s], |
| [[m4_init |
| m4_divert([0])dnl |
| m4_for([myvar], 1, 3,-1, [ myvar]) |
| ]]) |
| AT_CHECK_M4SUGAR([], 1, [], |
| [[script.4s:3: error: assert failed: -1 > 0 |
| script.4s:3: the top level |
| autom4te: error: m4 failed with exit status: 1 |
| ]]) |
| |
| AT_DATA_M4SUGAR([script.4s], |
| [[m4_init |
| m4_divert([0])dnl |
| m4_for([myvar], 1, 2, 0, [ myvar]) |
| ]]) |
| AT_CHECK_M4SUGAR([], 1, [], |
| [[script.4s:3: error: assert failed: 0 > 0 |
| script.4s:3: the top level |
| autom4te: error: m4 failed with exit status: 1 |
| ]]) |
| |
| AT_DATA_M4SUGAR([script.4s], |
| [[m4_init |
| m4_divert([0])dnl |
| m4_for([myvar], 2, 1, 0, [ myvar]) |
| ]]) |
| AT_CHECK_M4SUGAR([], 1, [], |
| [[script.4s:3: error: assert failed: 0 < 0 |
| script.4s:3: the top level |
| autom4te: error: m4 failed with exit status: 1 |
| ]]) |
| |
| dnl m4_shiftn also does bounds checking |
| AT_DATA_M4SUGAR([script.4s], |
| [[m4_init |
| m4_divert([0])dnl |
| m4_shiftn(3,1,2) |
| ]]) |
| AT_CHECK_M4SUGAR([], 1, [], |
| [[script.4s:3: error: assert failed: 0 < 3 && 3 < 3 |
| script.4s:3: the top level |
| autom4te: error: m4 failed with exit status: 1 |
| ]]) |
| |
| AT_CLEANUP |
| |
| |
| ## --------------------- ## |
| ## m4_map{,all}{,_sep}. ## |
| ## --------------------- ## |
| |
| AT_SETUP([m4@&t@_map]) |
| AT_KEYWORDS([m4@&t@_apply m4@&t@_map_sep m4@&t@_mapall m4@&t@_mapall_sep]) |
| AT_KEYWORDS([m4@&t@_count]) |
| |
| AT_CHECK_M4SUGAR_TEXT([[dnl |
| m4_map([m4_count], []) |
| m4_map([ m4_count], [[], |
| [[1]], |
| [[1], [2]]]) |
| m4_mapall([ m4_count], [[], |
| [[1]], |
| [[1], [2]]]) |
| m4_map_sep([m4_eval], [,], [[[1+2]], |
| [[10], [16]]]) |
| m4_count(m4_map_sep([m4_echo], [,], [[], [[1]], [[2]]])) |
| m4_count(m4_mapall_sep([m4_echo], [,], [[], [[1]], [[2]]])) |
| m4_map_sep([m4_eval], [[,]], [[[1+2]], |
| [[10], [16]]]) |
| m4_count(m4_map_sep([m4_echo], [[,]], [[], [[1]], [[2]]])) |
| m4_count(m4_mapall_sep([m4_echo], [[,]], [[], [[1]], [[2]]])) |
| m4_map([-], [[]]) |
| m4_mapall([-], [[]]) |
| m4_map_sep([-], [:], [[]]) |
| m4_mapall_sep([-], [:], [[]]) |
| m4_define([a], [m4_if([$#], [0], [oops], [$1], [a], [pass], [oops])])dnl |
| m4_define([a1], [oops])dnl |
| m4_define([pass1], [oops])dnl |
| m4_map([a], [[[a]]])1 |
| m4_map([m4_unquote([a])], [m4_dquote([a])]) |
| dnl only one side effect expansion, prior to visiting list elements |
| m4_map([m4_errprintn], [[[1]], [[2]], [[3]]m4_errprintn([hi])])dnl |
| m4_map_sep([m4_errprintn], [], [[[1]], [[2]], [[3]]m4_errprintn([hi])])dnl |
| m4_mapall([m4_errprintn], [[[1]], [[2]], [[3]]m4_errprintn([hi])])dnl |
| m4_mapall_sep([m4_errprintn], [], [[[1]], [[2]], [[3]]m4_errprintn([hi])])dnl |
| ]], |
| [[ |
| 1 2 |
| 0 1 2 |
| 3,a |
| 2 |
| 3 |
| 3,a |
| 1 |
| 1 |
| |
| - |
| |
| - |
| pass1 |
| pass |
| ]], [[hi |
| 1 |
| 2 |
| 3 |
| hi |
| 1 |
| 2 |
| 3 |
| hi |
| 1 |
| 2 |
| 3 |
| hi |
| 1 |
| 2 |
| 3 |
| ]]) |
| |
| AT_CLEANUP |
| |
| |
| ## --------------------------------------- ## |
| ## m4_map_args{,_sep,_pair} and m4_curry. ## |
| ## --------------------------------------- ## |
| |
| AT_SETUP([m4@&t@_map_args and m4@&t@_curry]) |
| AT_KEYWORDS([m4@&t@_map_args_sep m4@&t@_map_args_pair m4@&t@_reverse |
| m4@&t@_map]) |
| |
| dnl First, make sure we can curry in isolation. |
| AT_CHECK_M4SUGAR_TEXT( |
| [[m4_curry([m4_echo])([1]) |
| m4_curry([m4_curry], [m4_reverse], [1])([2])([3]) |
| m4_define([add], [m4_eval(([$1]) + ([$2]))])dnl |
| m4_define([add_one], [m4_curry([add], [1])])dnl |
| add_one()([4]) |
| ]], |
| [[1 |
| 3, 2, 1 |
| 5 |
| ]]) |
| |
| dnl Now, check that we can map a list of arguments. |
| AT_CHECK_M4SUGAR_TEXT([[m4_define([active], [ACTIVE])dnl |
| m4_map_args([ m4_echo]) |
| m4_map_args([ m4_echo], [plain], [active]) |
| m4_map_args([m4_unquote], [plain], [active]) |
| m4_map_args_pair([, m4_reverse], []) |
| m4_map_args_pair([, m4_reverse], [], [1]) |
| m4_map_args_pair([, m4_reverse], [], [1], [2]) |
| m4_map_args_pair([, m4_reverse], [], [1], [2], [3]) |
| m4_map_args_pair([, m4_reverse], [], [1], [2], [3], [4]) |
| m4_map_args_pair([, m4_reverse], [, m4_dquote], [1]) |
| m4_map_args_pair([, m4_reverse], [, m4_dquote], [1], [2]) |
| m4_map_args_pair([, m4_reverse], [, m4_dquote], [1], [2], [3]) |
| m4_map_args_pair([, m4_reverse], [, m4_dquote], [1], [2], [3], [4]) |
| m4_map_args_sep([<], [>], [:], [1], [2], [3]) |
| m4_map_args_sep([m4_echo(], [)], [ ], [plain], [active]) |
| ]], |
| [[ |
| plain active |
| plainACTIVE |
| |
| , 1 |
| , 2, 1 |
| , 2, 1, 3 |
| , 2, 1, 4, 3 |
| , [1] |
| , 2, 1 |
| , 2, 1, [3] |
| , 2, 1, 4, 3 |
| <1>:<2>:<3> |
| plain active |
| ]]) |
| |
| dnl Finally, put the two concepts together, to show the real power of the API. |
| AT_CHECK_M4SUGAR_TEXT( |
| [[m4_define([add], [m4_eval(([$1]) + ([$2]))])dnl |
| m4_define([list], [[-1], [0], [1]])dnl |
| dnl list_add_n(value, arg...) |
| dnl add VALUE to each ARG and output the resulting list |
| m4_define([list_add_n], |
| [m4_shift(m4_map_args([,m4_curry([add], [$1])], m4_shift($@)))]) |
| list_add_n([1], list) |
| list_add_n([2], list) |
| ]], [[ |
| 0,1,2 |
| 1,2,3 |
| ]]) |
| |
| AT_CLEANUP |
| |
| |
| ## ------------ ## |
| ## m4_combine. ## |
| ## ------------ ## |
| |
| AT_SETUP([m4@&t@_combine]) |
| |
| AT_CHECK_M4SUGAR_TEXT([[m4_define([a], [oops])dnl |
| m4_combine([, ], [[a], [b], [c]], [-], [1], [2], [3]) |
| m4_combine([, ], [[a], [b]], [-]) |
| m4_combine([, ], [[a], [b]], [-], []) |
| m4_combine([, ], [], [-], [a], [b]) |
| m4_combine([, ], [[]], [-], [a], [b]) |
| m4_combine([ a ], [[-], [+]], [a], [-], [+]) |
| m4_combine([$* ], [[$1], [$2]], [$#], [$@]) |
| ]], |
| [[a-1, a-2, a-3, b-1, b-2, b-3, c-1, c-2, c-3 |
| |
| a-, b- |
| |
| -a, -b |
| -a- a -a+ a +a- a +a+ |
| $1$#$@$* $2$#$@ |
| ]], []) |
| |
| AT_CLEANUP |
| |
| |
| ## -------------- ## |
| ## m4_{max,min}. ## |
| ## -------------- ## |
| |
| AT_SETUP([m4@&t@_max and m4@&t@_min]) |
| |
| AT_DATA_M4SUGAR([script.4s], |
| [[m4_max |
| ]]) |
| |
| AT_CHECK_M4SUGAR([], 1, [], |
| [[script.4s:1: error: too few arguments to m4@&t@_max |
| script.4s:1: the top level |
| autom4te: error: m4 failed with exit status: 1 |
| ]]) |
| |
| AT_DATA_M4SUGAR([script.4s], |
| [[m4_min |
| ]]) |
| |
| AT_CHECK_M4SUGAR([], 1, [], |
| [[script.4s:1: error: too few arguments to m4@&t@_min |
| script.4s:1: the top level |
| autom4te: error: m4 failed with exit status: 1 |
| ]]) |
| |
| AT_CHECK_M4SUGAR_TEXT([[dnl |
| m4_min(0) |
| m4_min(0xa) |
| m4_min(0, 0) |
| m4_min(0, 1) |
| m4_min(1, 0) |
| m4_min(0+1, 1+1) |
| m4_min(0+1, 1+0) |
| m4_min(0, 1, 2) |
| m4_min(2, 1, 0) |
| m4_min(1m4_for([i], 2, 100, , [,i])) |
| m4_min(m4_for([i], 100, 2, , [i,])1) |
| ---- |
| m4_max(0) |
| m4_max(0xa) |
| m4_max(0, 0) |
| m4_max(0, 1) |
| m4_max(1, 0) |
| m4_max(1+0, 1+1) |
| m4_max(1+0, 1+0) |
| m4_max(0, 1, 2) |
| m4_max(2, 1, 0) |
| m4_max(1m4_for([i], 2, 100, , [,i])) |
| m4_max(m4_for([i], 100, 2, , [i,])1) |
| ]], |
| [[0 |
| 10 |
| 0 |
| 0 |
| 0 |
| 1 |
| 1 |
| 0 |
| 0 |
| 1 |
| 1 |
| ---- |
| 0 |
| 10 |
| 0 |
| 1 |
| 1 |
| 2 |
| 1 |
| 2 |
| 2 |
| 100 |
| 100 |
| ]], []) |
| |
| AT_CLEANUP |
| |
| |
| ## ----------- ## |
| ## Recursion. ## |
| ## ----------- ## |
| |
| AT_SETUP([recursion]) |
| |
| AT_KEYWORDS([m4@&t@_foreach m4@&t@_foreach_w m4@&t@_case m4@&t@_cond |
| m4@&t@_bpatsubsts m4@&t@_shiftn m4@&t@_do m4@&t@_dquote_elt m4@&t@_reverse |
| m4@&t@_map m4@&t@_join m4@&t@_joinall m4@&t@_list_cmp m4@&t@_max m4@&t@_min |
| m4@&t@_bmatch m4@&t@_map_args m4@&t@_map_args_pair]) |
| |
| dnl This test completes in a reasonable time if m4_foreach is linear, |
| dnl but thrashes if it is quadratic. If we are testing with m4 1.4.x, |
| dnl only the slower foreach.m4 implementation will work. But if we |
| dnl are testing with m4 1.6, we can rerun the test with __m4_version__ |
| dnl undefined to exercise the alternate code path. |
| AT_DATA_M4SUGAR([script.4s], |
| [[m4_init |
| m4_divert_push([])[]dnl |
| m4_len(m4_foreach_w([j], m4_do(m4_for([i], [1], [10000], [], [,i ])), [j ])) |
| m4_shiftn(9998m4_for([i], [1], [10000], [], [,i])) |
| m4_len(m4_join([--],, m4_dquote_elt(m4_for([i], [1], [10000], [], [,i])),)) |
| m4_len(m4_joinall([--], m4_map([, m4_echo], |
| m4_dquote([1]m4_for([i], [2], [10000], [], [,i]))))) |
| m4_max(m4_min([1]m4_for([i], [2], [10000], [], |
| [,i]))m4_for([i], [2], [10000], [], [,i])) |
| m4_case([10000]m4_for([i], [1], [10000], [], [,i]),[end]) |
| m4_list_cmp(m4_dquote(1m4_for([i], [2], [10000], [], [,i])), |
| m4_dquote(m4_reverse(10000m4_for([i], [9999], [1], [], [,i])), [0])) |
| m4_list_cmp([0], [0m4_for([i], [1], [10000], [], [,0])]) |
| m4_list_cmp([0m4_for([i], [1], [10000], [], [,0])], [0]) |
| m4_for([i], [1], [10000], [], [m4_define(i)])dnl |
| m4_undefine(1m4_for([i], [2], [10000], [], [,i]))dnl |
| m4_bpatsubsts([a1]m4_for([i], [1], [10000], [], [,i]), [a2], [A]) |
| m4_bmatch([9997]m4_for([i], [1], [10000], [], [,^i$])) |
| m4_define([up], [m4_define([$1], m4_incr($1))$1])m4_define([j], 0)dnl |
| m4_cond(m4_for([i], [1], [10000], [], [[up([j])], [9990], i,]) [oops]) j |
| m4_count(m4_map_args_pair([,m4_quote], []m4_map_args([,m4_echo]m4_for([i], |
| [1], [10000], [], [,i])))) |
| m4_divert_pop([]) |
| ]]) |
| |
| AT_CHECK_M4SUGAR([-o-], [0], [[48894 |
| 9999,10000 |
| 78896 |
| 58894 |
| 10000 |
| end |
| 0 |
| 0 |
| 0 |
| A |
| ^9998$ |
| 9990 9990 |
| 5001 |
| ]]) |
| |
| AT_DATA_M4SUGAR([script.4s], |
| [[m4_ifdef([__m4_version__], |
| [m4_undefine([__m4_version__])], |
| [m4_divert_push([])48894 |
| 9999,10000 |
| 78896 |
| 58894 |
| 10000 |
| end |
| 0 |
| 0 |
| 0 |
| A |
| ^9998$ |
| 9990 9990 |
| 5001 |
| m4_exit([0])]) |
| m4_init |
| m4_divert_push([])[]dnl |
| m4_len(m4_foreach_w([j], m4_do(m4_for([i], [1], [10000], [], [,i ])), [j ])) |
| m4_shiftn(9998m4_for([i], [1], [10000], [], [,i])) |
| m4_len(m4_join([--],, m4_dquote_elt(m4_for([i], [1], [10000], [], [,i])),)) |
| m4_len(m4_joinall([--], m4_map([, m4_echo], |
| m4_dquote([1]m4_for([i], [2], [10000], [], [,i]))))) |
| m4_max(m4_min([1]m4_for([i], [2], [10000], [], |
| [,i]))m4_for([i], [2], [10000], [], [,i])) |
| m4_case([10000]m4_for([i], [1], [10000], [], [,i]),[end]) |
| m4_list_cmp(m4_dquote(1m4_for([i], [2], [10000], [], [,i])), |
| m4_dquote(m4_reverse(10000m4_for([i], [9999], [1], [], [,i])), [0])) |
| m4_list_cmp([0], [0m4_for([i], [1], [10000], [], [,0])]) |
| m4_list_cmp([0m4_for([i], [1], [10000], [], [,0])], [0]) |
| m4_for([i], [1], [10000], [], [m4_define(i)])dnl |
| m4_undefine(1m4_for([i], [2], [10000], [], [,i]))dnl |
| m4_bpatsubsts([a1]m4_for([i], [1], [10000], [], [,i]), [a2], [A]) |
| m4_bmatch([9997]m4_for([i], [1], [10000], [], [,^i$])) |
| m4_define([up], [m4_define([$1], m4_incr($1))$1])m4_define([j], 0)dnl |
| m4_cond(m4_for([i], [1], [10000], [], [[up([j])], [9990], i,]) [oops]) j |
| m4_count(m4_map_args_pair([,m4_quote], []m4_map_args([,m4_echo]m4_for([i], |
| [1], [10000], [], [,i])))) |
| m4_divert_pop([]) |
| ]]) |
| |
| AT_CHECK_M4SUGAR([-o-], [0], [[48894 |
| 9999,10000 |
| 78896 |
| 58894 |
| 10000 |
| end |
| 0 |
| 0 |
| 0 |
| A |
| ^9998$ |
| 9990 9990 |
| 5001 |
| ]]) |
| |
| AT_CLEANUP |
| |
| |
| ## ---------- ## |
| ## m4_set_*. ## |
| ## ---------- ## |
| |
| AT_SETUP([m4@&t@_set]) |
| |
| AT_KEYWORDS([m4@&t@_set_add m4@&t@_set_add_all m4@&t@_set_contains |
| m4@&t@_set_contents m4@&t@_set_delete m4@&t@_set_difference m4@&t@_set_dump |
| m4@&t@_set_empty m4@&t@_set_foreach m4@&t@_set_intersection m4@&t@_set_list |
| m4@&t@_set_listc m4@&t@_set_map m4@&t@_set_remove m4@&t@_set_size |
| m4@&t@_set_union]) |
| |
| # Simple tests |
| AT_CHECK_M4SUGAR_TEXT([[m4_set_contains([a], [1], [yes], [no]) |
| m4_set_add([a], [1], [added], [dup]) |
| m4_set_contains([a], [1], [yes], [no]) |
| m4_set_add([a], [1], [added], [dup]) |
| m4_set_contents([a]) |
| m4_set_remove([a], [1], [removed], [missing]) |
| m4_set_contains([a], [1], [yes], [no]) |
| m4_set_remove([a], [1], [removed], [missing]) |
| m4_set_add([a], [2], [added], [dup]) |
| m4_set_empty([a], [yes], [no]) |
| m4_set_delete([a]) |
| m4_set_empty([a], [yes], [no]) |
| m4_set_add_all([c], [1], [2], [3]) |
| m4_set_add_all([a]m4_set_listc([c])) |
| m4_set_contents([c], [-]) |
| m4_set_dump([a], [-]) |
| m4_set_contents([a]) |
| m4_set_add_all([a], [1], [2], [3])m4_set_add_all([b], [3], [], [4]) |
| m4_set_difference([a], [b]) |
| m4_set_difference([b], [a]) |
| m4_set_intersection([a], [b]) |
| m4_set_union([a], [b]) |
| m4_define([printodd], [m4_if(m4_eval([$1 & 1]), [1], [:$1])])dnl |
| m4_set_map([a], [printodd]) |
| m4_set_foreach([a], [i], [m4_if(m4_eval(i & 1), [1], [m4_set_remove([a], i)])]) |
| m4_set_list([a]) |
| m4_set_add([a], []) |
| m4_set_list([a]) |
| m4_set_remove([a], [2]) |
| m4_dquote(m4_set_list([a])) |
| m4_set_listc([a]) |
| m4_set_size([a]) |
| m4_set_delete([a]) |
| m4_dquote(m4_set_list([a])) |
| m4_indir([m4_dquote]m4_set_listc([a])) |
| m4_set_listc([a]) |
| m4_set_size([a]) |
| ]], [[no |
| added |
| yes |
| dup |
| 1 |
| removed |
| no |
| missing |
| added |
| no |
| |
| yes |
| |
| |
| 1-2-3 |
| 3-2-1 |
| |
| |
| ,1,2 |
| ,,4 |
| ,3 |
| ,1,2,3,,4 |
| :1:3 |
| |
| 2 |
| |
| 2, |
| |
| [] |
| , |
| 1 |
| |
| [] |
| |
| |
| 0 |
| ]]) |
| |
| # Stress tests - check for unusual names/values |
| AT_CHECK_M4SUGAR_TEXT([[m4_define([a], [oops])dnl |
| m4_set_add([a], [a])dnl |
| m4_set_remove([a], [oops], [yes], [no]) |
| m4_set_add([a,b], [c])dnl |
| m4_set_add([a,b], [$*[]])dnl |
| m4_set_add_all([a], [b,c])dnl |
| m4_set_size([a]) |
| m4_count(m4_set_contents([a], [,])) |
| m4_count(m4_set_list([a], [,])) |
| m4_set_dump([a], [,]) |
| m4_set_contents([a,b], [,]) |
| m4_set_list([a,b]) |
| m4_set_foreach([$*[]], [$*[]], [oops]) |
| m4_set_add([$*[]], [])dnl |
| m4_set_remove([$*[]], [a], [yes], [no]) |
| m4_set_add([$*[]], [a])dnl |
| m4_set_foreach([$*[]], [$*[]], [-m4_defn([$*[]])m4_indir([$*[]])-]) |
| m4_set_remove([$*[]], [], [yes], [no]) |
| m4_set_add([c], [,])dnl |
| m4_set_foreach([a,b], [set], [:m4_set_listc(_m4_defn([set])):]) |
| ]],[[no |
| 2 |
| 1 |
| 2 |
| b,c,a |
| c,$*[] |
| c,$*[] |
| |
| no |
| ---aoops- |
| yes |
| :,,::,a: |
| ]]) |
| |
| # Stress tests - check for linear scaling (won't necessarily fail if |
| # quadratic, but hopefully users will complain if it appears to hang) |
| AT_CHECK_M4SUGAR_TEXT([[dnl |
| m4_for([i], [1], [10000], [], [m4_set_add([a], i)])dnl |
| m4_set_add_all([b]m4_for([i], [1], [10000], [], [,i]))dnl |
| m4_set_remove([a], [1])dnl |
| m4_set_remove([b], [10000])dnl |
| m4_set_add_all([a]m4_for([i], [1], [10000], [], [,i]))dnl |
| m4_for([i], [1], [10000], [], [m4_set_add([b], i)])dnl |
| m4_len(m4_set_contents([a])) |
| m4_len(m4_set_foreach([b], [b], [m4_if(m4_eval(b & 1), [1], |
| [m4_set_remove([b], b, [-])])])) |
| m4_set_size([b]) |
| m4_define([prune3x], [m4_if(m4_eval([$1 % 3]), [0], |
| [m4_set_remove([a], [$1], [-])])])dnl |
| m4_len(m4_set_map([a], [prune3x])) |
| m4_count(m4_shift(m4_set_intersection([a], [b]))) |
| ]], [[38894 |
| 5000 |
| 5000 |
| 3333 |
| 3334 |
| ]]) |
| |
| # Implementation corner cases. |
| |
| # m4_set_add_all dispatches to one of two different helper macros |
| # depending on whether the set has any tombstones; verify their |
| # effects are equivalent. N.B. m4_set_dump, m4_set_list, etc. produce |
| # elements in an arbitrary order, so this test is more brittle than |
| # I'd like. |
| AT_CHECK_M4SUGAR_TEXT([[dnl |
| m4_define([echo_if_member], [m4_set_contains([$1], [$2], [$2])])dnl |
| m4_set_add_all([a], [1])dnl |
| m4_set_add_all([a], [2], [3])dnl |
| m4_set_add_all([a], [4], [5], [6])dnl |
| m4_set_size([a]) |
| m4_map_args_sep([echo_if_member([a],], [)], [,], |
| [1], [2], [3], [4], [5], [6], [x], [y]) |
| m4_set_dump([a], [,]) |
| |
| m4_set_add([b], [x])dnl |
| m4_set_add([b], [y])dnl |
| m4_set_remove([b], [x])dnl |
| m4_set_add_all([b], [1])dnl |
| m4_set_add_all([b], [2], [3])dnl |
| m4_set_add_all([b], [4], [5], [6])dnl |
| m4_set_remove([b], [y])dnl |
| m4_set_size([b]) |
| m4_map_args_sep([echo_if_member([b],], [)], [,], |
| [1], [2], [3], [4], [5], [6], [x], [y]) |
| m4_set_dump([b], [,]) |
| |
| m4_set_add([c], [x])dnl |
| m4_set_add([c], [y])dnl |
| m4_set_remove([c], [y])dnl |
| m4_set_add_all([c], [1])dnl |
| m4_set_add_all([c], [2], [3])dnl |
| m4_set_add_all([c], [4], [5], [6])dnl |
| m4_set_remove([c], [x])dnl |
| m4_set_size([c]) |
| m4_map_args_sep([echo_if_member([c],], [)], [,], |
| [1], [2], [3], [4], [5], [6], [x], [y]) |
| m4_set_dump([c], [,]) |
| ]], [[6 |
| 1,2,3,4,5,6,, |
| 6,5,4,3,2,1 |
| |
| 6 |
| 1,2,3,4,5,6,, |
| 6,5,4,3,2,1 |
| |
| 6 |
| 1,2,3,4,5,6,, |
| 6,5,4,3,2,1 |
| ]]) |
| |
| AT_CLEANUP |
| |
| |
| ## ---------------------- ## |
| ## __file__ and __line__. ## |
| ## ---------------------- ## |
| |
| AT_SETUP([[__file__ and __line__]]) |
| |
| # Check that __file__ and __line__ work. |
| # Check that m4__file__ and m4__line__ are not defined |
| # (and get them to pass by the undefined-macro check). |
| # Try to not assume too much about AT_CHECK_M4SUGAR_TEXT. |
| AT_CHECK_M4SUGAR_TEXT([[dnl |
| m4_pattern_allow([m4__file__])dnl |
| m4_pattern_allow([m4__line__])dnl |
| m4__file__ |
| m4__line__ |
| __file__ |
| m4_define([first], __line__)dnl |
| m4_define([second], __line__)dnl |
| m4_assert(first + 1 == second)dnl |
| ]], [[m4@&t@__@&t@file__ |
| m4@&t@__@&t@line__ |
| script.4s |
| ]]) |
| |
| AT_CLEANUP |