Stage 28b: Warn on embedded NUL in file arguments.
[m4.git] / tests / builtins.at
blob397f649c1a4a88d1cd54bfaea0839216126499a6
1 # Hand crafted tests for GNU M4.                               -*- Autotest -*-
2 # Copyright (C) 2001, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
4 # This file is part of GNU M4.
6 # GNU M4 is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation, either version 3 of the License, or
9 # (at your option) any later version.
11 # GNU M4 is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 AT_BANNER([Torturing builtins.])
22 ## -------- ##
23 ## __file__ ##
24 ## -------- ##
26 AT_SETUP([__@&t@file__])
28 dnl Unfortunately, AT_DATA does not make it easy to create files without
29 dnl a trailing newline.
30 [echo $ECHO_N "__line"__:__"file__$ECHO_C"] > nested
31 AT_DATA([outer],
32 [[__file__:__line__
33 include(`nested')
34 __file__:__line__
35 ]])
37 dnl Make sure line numbers are consistent, even if include file does not
38 dnl end with a newline
39 AT_CHECK_M4([outer], [0],
40 [[outer:1
41 1:nested
42 outer:3
43 ]])
45 AT_CLEANUP
48 ## -------- ##
49 ## __line__ ##
50 ## -------- ##
52 AT_SETUP([__@&t@line__])
54 dnl Unfortunately, AT_DATA does not make it easy to create files without
55 dnl a trailing newline.
56 [echo $ECHO_N "__file"__:__"line__$ECHO_C"] > nested
57 AT_DATA([outer],
58 [[__file__:__line__
59 include(`nested')
60 __file__:__line__
61 ]])
63 dnl Make sure line numbers are consistent, even if include file does not
64 dnl end with a newline
65 AT_CHECK_M4([outer], [0],
66 [[outer:1
67 nested:1
68 outer:3
69 ]])
71 AT_CLEANUP
74 ## -------------- ##
75 ## __m4_version__ ##
76 ## -------------- ##
78 AT_SETUP([__m4_@&t@version__])
80 AT_DATA([in], [[defn(`__m4_version__')
81 ]])
82 AT_CHECK_M4([--version], [0], [stdout])
83 AT_CHECK([[$SED -e 's/.*(GNU M4\(.*\)) \([^ ]*\).*/\2\1/;q' < stdout]],
84 [0], [stdout])
85 mv stdout expout
86 AT_CHECK_M4([in], [0], [expout])
88 dnl Prove that __m4_version__ is unquoted, by making '.' an active character.
89 AT_DATA([in], [[changesyntax(`A.')define(`.', `errprint(`hi
90 ')undefine(`.').')dnl
91 __m4_version__
92 ]])
93 AT_CHECK_M4([in], [0], [expout], [[hi
94 ]])
96 AT_CLEANUP
99 ## ------- ##
100 ## builtin ##
101 ## ------- ##
103 AT_SETUP([builtin])
105 dnl This was a regression in 1.4.10b.
106 AT_DATA([in.m4],
107 [[define(`s', `builtin(`shift', $@)')dnl
108 define(`loop', `ifelse(`$2', `', `-', `$1$2: $0(`$1', s(s($@)))')')dnl
109 loop(`1')
110 loop(`1', `2')
111 loop(`1', `2', `3')
112 loop(`1', `2', `3', `4')
113 loop(`1', `2', `3', `4', `5')
115 AT_CHECK_M4([in.m4], [0],
117 12: -
118 12: 13: -
119 12: 13: 14: -
120 12: 13: 14: 15: -
123 AT_CLEANUP
126 ## ----------- ##
127 ## changequote ##
128 ## ----------- ##
130 AT_SETUP([changequote])
132 AT_DATA([in.m4],
133 [[define(`aaaaaaaaaaaaaaaaaaaa', `A')define(`q', `"$@"')
134 changequote(`"', `"')
135 q(q("aaaaaaaaaaaaaaaaaaaa", "a"))
138 AT_CHECK_M4([in.m4], [0], [[
143 AT_CLEANUP
146 ## ----- ##
147 ## debug ##
148 ## ----- ##
150 AT_SETUP([debug])
152 AT_DATA([[debug.m4]],
153 [[define(`countdown', `$1 ifelse(eval($1 > 0), 1, `countdown(decr($1))', `Liftoff')')
154 debugmode(`aeqc')
155 traceon(`countdown')
156 countdown(2)
159 AT_DATA([[expout]],
163 2 1 0 Liftoff
166 AT_DATA([[experr]],
167 [[m4trace: -1- countdown ... = `$1 ifelse(eval($1 > 0), 1, `countdown(decr($1))', `Liftoff')'
168 m4trace: -1- countdown(`2') -> `2 ifelse(eval(2 > 0), 1, `countdown(decr(2))', `Liftoff')'
169 m4trace: -1- countdown ... = `$1 ifelse(eval($1 > 0), 1, `countdown(decr($1))', `Liftoff')'
170 m4trace: -1- countdown(`1') -> `1 ifelse(eval(1 > 0), 1, `countdown(decr(1))', `Liftoff')'
171 m4trace: -1- countdown ... = `$1 ifelse(eval($1 > 0), 1, `countdown(decr($1))', `Liftoff')'
172 m4trace: -1- countdown(`0') -> `0 ifelse(eval(0 > 0), 1, `countdown(decr(0))', `Liftoff')'
175 AT_CHECK_M4([debug.m4], 0, expout, experr)
177 dnl Test a regression introduced 2008-05-08, fixed 2008-07-30.
178 AT_DATA([debug.m4], [[debugmode(`e')traceon(`ifelse')dnl
179 define(`e', `ifelse(`$1', `$2', `ifelse(`$1', `$2', `e(shift($@))')', `$2')')
180 e(`1', `1', `a')
183 AT_CHECK_M4([debug.m4], [0], [[
185 ]], [[m4trace: -1- ifelse -> ifelse(`1', `1', `e(shift(`1',`1',`a'))')
186 m4trace: -1- ifelse -> e(shift(`1',`1',`a'))
187 m4trace: -1- ifelse -> a
190 AT_CLEANUP
193 ## ------ ##
194 ## define ##
195 ## ------ ##
197 AT_SETUP([define])
199 AT_DATA([[define.m4]],
200 [[undefine(`macro')dnl
201 pushdef(`macro', `base value')dnl
202 pushdef(`macro', `hello, world')dnl
203 pushdef(`macro', `top value')dnl
204 define(`macro', `new value')dnl
205 macro.
206 popdef(`macro')dnl
207 macro.
208 popdef(`macro')dnl
209 macro.
212 AT_CHECK_M4([define.m4], 0,
213 [[new value.
214 hello, world.
215 base value.
216 ]], [[m4:define.m4:1: Warning: undefine: undefined macro `macro'
219 AT_CHECK_M4([--traditional define.m4], 0,
220 [[new value.
221 hello, world.
222 base value.
223 ]], [[m4:define.m4:1: Warning: undefine: undefined macro `macro'
226 dnl check regression present 2008-02-22 to 2008-04-30.
227 AT_DATA([in.m4], [[define(`qq', ``$*;$@'')dnl
228 define(`foo', qq(`a', `b'))dnl
230 defn(`foo')
232 AT_CHECK_M4([in.m4], [0], [[a,b;a,b
233 a,b;`a',`b'
236 AT_CLEANUP
240 ## ---- ##
241 ## defn ##
242 ## ---- ##
244 AT_SETUP([defn])
246 AT_DATA([[in.m4]],
247 [[define(`e', `$@')define(`q', ``$@'')define(`u', `$*')
248 define(`cmp', `ifelse($1, $2, `yes', `no')')define(`d', defn(`defn'))
249 cmp(`defn(`defn')', `defn(`d')')
250 cmp(`defn(`defn')', ``<defn>'')
251 cmp(`q(defn(`defn'))', `q(defn(`d'))')
252 cmp(`q(defn(`defn'))', `q(`<defn>')')
253 cmp(`q(defn(`defn'))', ``'')
254 cmp(`q(`1', `2', defn(`defn'))', `q(`1', `2', defn(`d'))')
255 cmp(`q(`1', `2', defn(`defn'))', `q(`1', `2', `<defn>')')
256 cmp(`q(`1', `2', defn(`defn'))', ```1',`2',<defn>'')
257 cmp(`q(`1', `2', defn(`defn'))', ```1',`2',`''')
258 define(`cat', `$1`'ifelse(`$@%:@', `1', `', `$0(shift($@))')')
259 cat(`define(`foo',', defn(`divnum'), `)foo')
260 cat(e(`define(`bar',', defn(`divnum'), `)bar'))
261 m4wrap(`u('q(`cat(`define(`baz','', defn(`divnum'), ``)baz')')`)
265 AT_CHECK_M4([in.m4], [0], [[
283 AT_CLEANUP
286 ## ------ ##
287 ## divert ##
288 ## ------ ##
290 AT_SETUP([divert])
292 AT_DATA([[divert.m4]],
293 [[divert(1)Text diverted a first time.
294 divert(0)undivert(1)dnl
295 divert(1)Text diverted a second time.
296 divert(0)undivert(1)dnl
299 AT_CHECK_M4([divert.m4], 0,
300 [[Text diverted a first time.
301 Text diverted a second time.
304 dnl Test second divert argument, added for m4 2.0
305 AT_DATA([in.m4], [[define(`echo',`$1')dnl
306 divert(`-1', `discarded without warning')
307 divert`'dnl
308 echo(` world'divert(divnum, `hello'))
311 AT_CHECK_M4([-s in.m4], [0], [[#line 4 "in.m4"
312 hello world
315 dnl Test large diversions, which were broken in m4 1.4.8-1.4.10.
316 dnl Hopefully $SED doesn't choke on the over-long second line.
317 AT_CHECK([echo 'divert(1)hi
318 format(%1000000d, 1)' | $M4 | $SED -n 1p], [0], [[hi
321 AT_DATA([in.m4], [M4_ONE_MEG_DEFN[divert(`2')f`'dnl
322 divert(`1')hello
323 divert(`3')goodbye
326 dnl Rather than open-code the 1 megabyte expected output, we reduce the
327 dnl size of testsuite by constructing it.
328 AT_DATA([expout], [[
330 cat expout expout > expout2
331 cat expout2 expout2 > expout
332 cat expout expout > expout2
333 cat expout2 expout2 > expout
334 cat expout expout > expout2
335 cat expout2 expout2 > expout
336 cat expout expout > expout2
337 cat expout2 expout2 > expout
338 cat expout expout > expout2
339 cat expout2 expout2 > expout
340 cat expout expout > expout2
341 cat expout2 expout2 > expout
342 cat expout expout > expout2
343 cat expout2 expout2 > expout
344 cat expout expout > expout2
345 cat expout2 expout2 > expout
346 cat expout expout > expout2
347 cat expout2 expout2 > expout
348 cat expout expout > expout2 # 512 kilobytes
349 echo hello > expout
350 cat expout2 expout2 >> expout # 1 megabyte
351 echo goodbye >> expout
352 rm expout2
354 AT_CHECK_M4([in.m4], [0], [expout])
356 dnl Avoid quadratic copying time when transferring diversions; test
357 dnl both in-memory and diversions spilled to a file.
358 AT_DATA([in.m4], [[include(`forloop2.m4')dnl
359 divert(`1')format(`%10000s', `')dnl
360 forloop(`i', `1', `10000',
361   `divert(incr(i))undivert(i)')dnl
362 divert(`9001')format(`%1000000s', `')dnl
363 forloop(`i', `9001', `10000',
364   `divert(incr(i))undivert(i)')dnl
365 divert(`-1')undivert
368 AT_CHECK_M4([-I "$top_srcdir/examples" in.m4])
370 AT_CLEANUP
373 ## --- ##
374 ## dnl ##
375 ## --- ##
377 AT_SETUP([d@&t@nl])
379 dnl Unfortunately, AT_DATA does not make it easy to create files without
380 dnl a trailing newline.
381 [echo $ECHO_N "__file"__:__"line__ d""nl ignored$ECHO_C"] > nested
382 AT_DATA([outer],
383 [[__file__:__line__
384 include(`nested') still ignored
385 __file__:__line__
386 define(`foo', `dnl
387 __file__:__line__ include(`nested') ignored
388 dnl')dnl
389 foo ignored
390 __file__:__line__
393 dnl Make sure line numbers are consistent, even if include file does not
394 dnl end with a newline
395 AT_CHECK_M4([outer], [0],
396 [[outer:1
397 nested:1 outer:3
398 outer:7 nested:1 outer:8
401 AT_CLEANUP
404 ## ------- ##
405 ## dumpdef ##
406 ## ------- ##
408 AT_SETUP([dumpdef])
410 dnl Make sure that stderr and stdout are properly interleaved when directed
411 dnl to the same file.
412 AT_DATA([in], [[1dumpdef(`defn')3
414 AT_CHECK_M4([in], [0], [[13
415 ]], [[defn:     <defn>
417 AT_CHECK_M4([in 2>&1], [0], [[1defn:    <defn>
421 AT_CLEANUP
424 ## -------- ##
425 ## errprint ##
426 ## -------- ##
428 AT_SETUP([errprint])
430 dnl Make sure that stderr and stdout are properly interleaved when directed
431 dnl to the same file.
432 AT_DATA([in], [[1errprint(`2')3errprint(`
435 AT_CHECK_M4([in], [0], [[13
436 ]], [[2
438 AT_CHECK_M4([in 2>&1], [0], [[123
442 AT_CLEANUP
445 ## ------- ##
446 ## esyscmd ##
447 ## ------- ##
449 AT_SETUP([esyscmd])
451 AT_DATA([[esyscmd.m4]],
452 [[# Cannot use real hostname program because test would fail
453 define(`hostname', esyscmd(`echo www.gnu.org'))dnl
454 `hostname = >>'hostname`<<'
455 define(`hostname',
456 pushdef(`_tmp', `$1')_tmp(translit(esyscmd(`echo www.gnu.org'), `.', `,'))`'popdef(`_tmp'))dnl
457 `hostname = >>'hostname`<<'
460 AT_CHECK_M4([esyscmd.m4], 0,
461 [[# Cannot use real hostname program because test would fail
462 hostname = >>www.gnu.org
464 hostname = >>www<<
467 dnl Ensure that esyscmd does not inherit any unnecessary fds from trace.
468 AT_DATA([in.m4], [[esyscmd(`echo hi >&3')ifelse(sysval,
469 `0', `skipping: sh cannot detect closed fds
470 m4exit(`77')')dnl
472 AT_CHECK_M4([3>&-], [0], [], [stderr], [in.m4])
473 mv stderr experr
474 AT_CHECK_M4([--debugfile=trace -tdnl 3>&-], [0], [], [experr], [in.m4])
475 AT_CHECK([cat trace], [0], [[m4trace: -1- dnl -> `'
478 dnl Ensure that esyscmd does not inherit any unnecessary fds from diversions.
479 AT_DATA([in.m4], [M4_ONE_MEG_DEFN[divert(`1')f
480 world
481 esyscmd(`echo hi >&3')divert
482 hello
484 AT_CHECK_M4([3>&-], [0], [stdout], [experr], [in.m4])
485 AT_CHECK([$SED -ne '/./p' stdout], [0], [[hello
486 world
489 dnl Ensure that esyscmd does not inherit any unnecessary fds from input files.
490 AT_DATA([in.m4], [[hello esyscmd(`cat <&3')dnl
491 dnl this line should not be read by cat
492 world
494 AT_CHECK_M4([3>&-], [0], [[hello world
495 ]], [stderr], [in.m4])
496 mv stderr experr
497 AT_CHECK_M4([in.m4 3>&-], [0], [[hello world
498 ]], [experr])
500 AT_CLEANUP
503 ## ------ ##
504 ## ifelse ##
505 ## ------ ##
507 AT_TEST_M4([ifelse],
508 dnl ensure that comparisons work regardless of reference chains in the middle
509 [[define(`e', `$@')define(`long', `01234567890123456789')
510 dnl in isolation
511 ifelse(long, `01234567890123456789', `yes', `no')
512 ifelse(`01234567890123456789', long, `yes', `no')
513 ifelse(long, `01234567890123456789-', `yes', `no')
514 ifelse(`01234567890123456789-', long, `yes', `no')
515 dnl through macro expansion
516 ifelse(e(long), `01234567890123456789', `yes', `no')
517 ifelse(`01234567890123456789', e(long), `yes', `no')
518 ifelse(e(long), `01234567890123456789-', `yes', `no')
519 ifelse(`01234567890123456789-', e(long), `yes', `no')
520 dnl concatenate macro expansion with unquoted characters
521 ifelse(-e(long), `-01234567890123456789', `yes', `no')
522 ifelse(-`01234567890123456789', -e(long), `yes', `no')
523 ifelse(-e(long), `-01234567890123456789-', `yes', `no')
524 ifelse(`-01234567890123456789-', -e(long), `yes', `no')
525 ifelse(-e(long)-, `-01234567890123456789-', `yes', `no')
526 ifelse(-`01234567890123456789-', -e(long)-, `yes', `no')
527 ifelse(-e(long)-, `-01234567890123456789', `yes', `no')
528 ifelse(`-01234567890123456789', -e(long)-, `yes', `no')
529 dnl concatenate macro expansion with quoted characters
530 ifelse(`-'e(long), `-01234567890123456789', `yes', `no')
531 ifelse(-`01234567890123456789', `-'e(long), `yes', `no')
532 ifelse(`-'e(long), `-01234567890123456789-', `yes', `no')
533 ifelse(`-01234567890123456789-', `-'e(long), `yes', `no')
534 ifelse(`-'e(long)`-', `-01234567890123456789-', `yes', `no')
535 ifelse(-`01234567890123456789-', `-'e(long)`-', `yes', `no')
536 ifelse(`-'e(long)`-', `-01234567890123456789', `yes', `no')
537 ifelse(`-01234567890123456789', `-'e(long)`-', `yes', `no')
538 ]], [[
566 ## ------- ##
567 ## include ##
568 ## ------- ##
570 AT_SETUP([include])
572 AT_DATA([[include.m4]],
573 [[Beginning.
574 include(`NOFILE')
575 Intermediate
576 include(`incl-test.m4')
577 After
578 include(`NOFILE')
579 very late
582 AT_DATA([[incl-test.m4]],
583 [[dnl noauto
584 `include test file.'
585 define()
588 AT_DATA([[expout]],
589 [[Beginning.
591 Intermediate
592 include test file.
595 After
597 very late
600 AT_DATA([[experr]],
601 [[m4:include.m4:2: include: cannot open `NOFILE': No such file or directory
602 m4:include.m4:6: include: cannot open `NOFILE': No such file or directory
605 AT_CHECK_M4([include.m4], 1, expout, experr)
607 dnl make sure files are handled correctly even via builtin
608 AT_DATA([foo], [[bar
610 AT_DATA([in], [[builtin(`include', `foo')dnl
613 AT_CHECK_M4([in], [0], [[bar
616 AT_CLEANUP
620 ## ----- ##
621 ## index ##
622 ## ----- ##
624 AT_SETUP([index])
626 dnl This used to be quadratic, taking millions of comparisons,
627 dnl but should now operate in linear time with only several thousand checks.
628 AT_DATA([in], [M4_ONE_MEG_DEFN[dnl
629 index(substr(f, `0', `500000')-, substr(f, `0', `100000')-)
631 AT_CHECK_M4([in], [0], [[400000
634 dnl This validates that index is 8-bit safe.
635 AT_DATA([in], [[index(`1«2', `»')
636 index(`1«2', `«')
637 index(`1«2', `«1')
638 index(`1«2', `«2')
640 AT_CHECK_M4([in], [0], [[-1
646 AT_CLEANUP
650 ## ----- ##
651 ## indir ##
652 ## ----- ##
654 AT_SETUP([indir])
656 AT_DATA([[indir.m4]],
657 [[define(`%%$$##', `>>>$0<<< cnt $#')
659 # indir(`%%$$##', nonsense, nonsense)
660 indir(`%%$$##', nonsense, nonsense)
662 # indir(`indir', `%%$$##', nonsense)
663 indir(`indir', `%%$$##', nonsense)
665 # indir(`indir', `indir', `indir', `indir', `%%$$##')
666 indir(`indir', `indir', `indir', `indir', `%%$$##')
669 AT_DATA([[expout]],
672 # indir(`%%$$##', nonsense, nonsense)
673 >>>%%$$##<<< cnt 2
675 # indir(`indir', `%%$$##', nonsense)
676 >>>%%$$##<<< cnt 1
678 # indir(`indir', `indir', `indir', `indir', `%%$$##')
679 >>>%%$$##<<< cnt 0
682 AT_CHECK_M4([indir.m4], 0, expout)
684 AT_CLEANUP
687 ## ------ ##
688 ## m4exit ##
689 ## ------ ##
691 AT_SETUP([m4exit])
693 dnl Ensure that spilled diversions are gracefully cleaned up
694 AT_DATA([in.m4], [M4_ONE_MEG_DEFN[divert(`1')f
695 m4exit
697 AT_CHECK([rm -Rf tmpdir && mkdir tmpdir && test -d tmpdir])
698 TMPDIR=tmpdir
699 export TMPDIR
700 AT_CHECK_M4([in.m4], [0])
701 AT_CHECK([rmdir tmpdir])
703 AT_CLEANUP
706 ## ------- ##
707 ## mkdtemp ##
708 ## ------- ##
710 AT_SETUP([mkdtemp])
712 dnl Check that on error, the expansion is void
713 AT_DATA([[in]],
714 [[mkdtemp(`no_such_dir/m4-fooXXXXXX')
716 AT_CHECK_M4([in], [0], [[
717 ]], [[m4:in:1: Warning: mkdtemp: cannot create directory from template `no_such_dir/m4-fooXXXXXX': No such file or directory
720 dnl Check that umask has an effect.  drws--S--T is okay.
721 AT_DATA([[in]],
722 [[translit(substr(esyscmd(`ls -ld 'mkdtemp(`m4-fooXXXXXX')), `0', `10'),
723            `SsT', `-x-')
725 AT_CHECK([$M4 < in], [0], [[drwx------
727 AT_CHECK([umask 700; $M4 < in], [0], [[d---------
730 AT_CLEANUP
733 ## -------- ##
734 ## maketemp ##
735 ## -------- ##
737 AT_SETUP([mkstemp])
739 AT_KEYWORDS([maketemp])
741 dnl Check that on error, the expansion is void
742 AT_DATA([[in]],
743 [[mkstemp(`no_such_dir/m4-fooXXXXXX')
745 AT_CHECK_M4([in], [0], [[
746 ]], [[m4:in:1: Warning: mkstemp: cannot create file from template `no_such_dir/m4-fooXXXXXX': No such file or directory
749 dnl Check that extra X are appended, but not trailing NUL
750 AT_DATA([[in]], [[len(mkstemp(`m4-fooXXXXX'))
752 AT_CHECK_M4([in], [0], [[12
755 dnl Check that umask has an effect
756 AT_DATA([[in]],
757 [[substr(esyscmd(`ls -ld 'mkstemp(`m4-fooXXXXXX')), `0', `10')
759 AT_CHECK([$M4 < in], [0], [[-rw-------
761 AT_CHECK([umask 700; $M4 < in], [0], [[----------
764 dnl Check for Solaris compatibility of maketemp.  Hopefully the pid is
765 dnl less than 20 decimal digits.  Also check that --safer does not affect
766 dnl traditional behavior of maketemp, which is textual only.
767 AT_DATA([[in]],
768 [[maketemp()
769 maketemp(X)
770 maketemp(XX)
771 maketemp(XXXXXXXXXXXXXXXXXXXXX)
772 maketemp(no_such_dir/XXXXXX)
774 dnl Abuse our knowledge of AT_CHECK_M4 so that we can get stderr filtering...
775 AT_CHECK_M4([-G -Q --safer], [0], [stdout], [],
776 [in& echo $! > pid; wait $!])
777 pid=`cat pid`
778 cat >expout <<EOF
781 X`$SED -e 's/.*\(.\)$/\1/' pid`
782 X`echo "$pid" | $SED -e "s/.*/00000000000000000000&/" -e 's/.*\(.\{20\}$\)/\1/'`
783 no_such_dir/`echo "$pid" | $SED -e "s/.*/000000&/" -e 's/.*\(.\{6\}$\)/\1/'`
785 AT_CHECK([cat stdout], [0], [expout])
787 AT_CLEANUP
790 ## ------ ##
791 ## mpeval ##
792 ## ------ ##
794 AT_SETUP([mpeval])
795 AT_CHECK_DYNAMIC_MODULE
796 AT_CHECK_GMP
798 AT_DATA([[in]],
799 [[divert(-1)
800 # forloop(i, from, to, stmt)
802 define(`forloop', `pushdef(`$1', `$2')_forloop(`$1', `$2', `$3', `$4')popdef(`$1')')
803 define(`_forloop',
804        `$4`'ifelse($1, `$3', ,
805                          `define(`$1', incr($1))_forloop(`$1', `$2', `$3', `$4')')')
806 divert
807 forloop(`x', 1, 100, `2**x = mpeval(2**x)
811 AT_DATA([[expout]],
813 2**1 = 2
814 2**2 = 4
815 2**3 = 8
816 2**4 = 16
817 2**5 = 32
818 2**6 = 64
819 2**7 = 128
820 2**8 = 256
821 2**9 = 512
822 2**10 = 1024
823 2**11 = 2048
824 2**12 = 4096
825 2**13 = 8192
826 2**14 = 16384
827 2**15 = 32768
828 2**16 = 65536
829 2**17 = 131072
830 2**18 = 262144
831 2**19 = 524288
832 2**20 = 1048576
833 2**21 = 2097152
834 2**22 = 4194304
835 2**23 = 8388608
836 2**24 = 16777216
837 2**25 = 33554432
838 2**26 = 67108864
839 2**27 = 134217728
840 2**28 = 268435456
841 2**29 = 536870912
842 2**30 = 1073741824
843 2**31 = 2147483648
844 2**32 = 4294967296
845 2**33 = 8589934592
846 2**34 = 17179869184
847 2**35 = 34359738368
848 2**36 = 68719476736
849 2**37 = 137438953472
850 2**38 = 274877906944
851 2**39 = 549755813888
852 2**40 = 1099511627776
853 2**41 = 2199023255552
854 2**42 = 4398046511104
855 2**43 = 8796093022208
856 2**44 = 17592186044416
857 2**45 = 35184372088832
858 2**46 = 70368744177664
859 2**47 = 140737488355328
860 2**48 = 281474976710656
861 2**49 = 562949953421312
862 2**50 = 1125899906842624
863 2**51 = 2251799813685248
864 2**52 = 4503599627370496
865 2**53 = 9007199254740992
866 2**54 = 18014398509481984
867 2**55 = 36028797018963968
868 2**56 = 72057594037927936
869 2**57 = 144115188075855872
870 2**58 = 288230376151711744
871 2**59 = 576460752303423488
872 2**60 = 1152921504606846976
873 2**61 = 2305843009213693952
874 2**62 = 4611686018427387904
875 2**63 = 9223372036854775808
876 2**64 = 18446744073709551616
877 2**65 = 36893488147419103232
878 2**66 = 73786976294838206464
879 2**67 = 147573952589676412928
880 2**68 = 295147905179352825856
881 2**69 = 590295810358705651712
882 2**70 = 1180591620717411303424
883 2**71 = 2361183241434822606848
884 2**72 = 4722366482869645213696
885 2**73 = 9444732965739290427392
886 2**74 = 18889465931478580854784
887 2**75 = 37778931862957161709568
888 2**76 = 75557863725914323419136
889 2**77 = 151115727451828646838272
890 2**78 = 302231454903657293676544
891 2**79 = 604462909807314587353088
892 2**80 = 1208925819614629174706176
893 2**81 = 2417851639229258349412352
894 2**82 = 4835703278458516698824704
895 2**83 = 9671406556917033397649408
896 2**84 = 19342813113834066795298816
897 2**85 = 38685626227668133590597632
898 2**86 = 77371252455336267181195264
899 2**87 = 154742504910672534362390528
900 2**88 = 309485009821345068724781056
901 2**89 = 618970019642690137449562112
902 2**90 = 1237940039285380274899124224
903 2**91 = 2475880078570760549798248448
904 2**92 = 4951760157141521099596496896
905 2**93 = 9903520314283042199192993792
906 2**94 = 19807040628566084398385987584
907 2**95 = 39614081257132168796771975168
908 2**96 = 79228162514264337593543950336
909 2**97 = 158456325028528675187087900672
910 2**98 = 316912650057057350374175801344
911 2**99 = 633825300114114700748351602688
912 2**100 = 1267650600228229401496703205376
916 AT_CHECK_M4([-m mpeval in], 0, expout)
918 AT_CLEANUP
922 ## ----------- ##
923 ## multiquotes ##
924 ## ----------- ##
926 AT_SETUP([multiquotes])
928 AT_DATA([[multiquotes.m4]],
929 [[traceon
930 changequote([,])dnl
931 changequote([``], [''])dnl
932 ````traceon''''
933 define(``foo'', ````FOO'''')dnl
934 dumpdef(``foo'')dnl
935 changequote(``!'', ``!'')dnl
936 !foo!
938 dumpdef(!foo!)dnl
939 define(!bar!, !BAR!)
941 changequote(!>*>*>*>*>!, !<*<*<*<*<!)dnl five of each
942 >*>*>*>*>foo bar<*<*<*<*<
943 foo bar
944 >*>*>*>*>*>*><*<*<*<*<*<*<
945 dumpdef(>*>*>*>*>foo<*<*<*<*<, >*>*>*>*>bar<*<*<*<*<)dnl
948 AT_DATA([[expout]],
950 ``traceon''
952 ``FOO''
955 foo bar
956 ``FOO'' BAR
957 *>*>*<*<
960 AT_DATA([[experr]],
961 [[m4trace: -1- changequote(`[', `]') -> []
962 m4trace: -1- dnl -> []
963 m4trace: -1- changequote([``], ['']) -> ``''
964 m4trace: -1- dnl -> ``''
965 m4trace: -1- define(``foo'', ````FOO'''') -> ``''
966 m4trace: -1- dnl -> ``''
967 foo:    ````FOO''''
968 m4trace: -1- dumpdef(``foo'') -> ``''
969 m4trace: -1- dnl -> ``''
970 m4trace: -1- changequote(``!'', ``!'') -> !!
971 m4trace: -1- dnl -> !!
972 m4trace: -1- foo -> !``FOO''!
973 foo:    !``FOO''!
974 m4trace: -1- dumpdef(!foo!) -> !!
975 m4trace: -1- dnl -> !!
976 m4trace: -1- define(!bar!, !BAR!) -> !!
977 m4trace: -1- bar -> !BAR!
978 m4trace: -1- changequote(!>*>*>*>*>!, !<*<*<*<*<!) -> >*>*>*>*><*<*<*<*<
979 m4trace: -1- dnl -> >*>*>*>*><*<*<*<*<
980 m4trace: -1- foo -> >*>*>*>*>``FOO''<*<*<*<*<
981 m4trace: -1- bar -> >*>*>*>*>BAR<*<*<*<*<
982 bar:    >*>*>*>*>BAR<*<*<*<*<
983 foo:    >*>*>*>*>``FOO''<*<*<*<*<
984 m4trace: -1- dumpdef(>*>*>*>*>foo<*<*<*<*<, >*>*>*>*>bar<*<*<*<*<) -> >*>*>*>*><*<*<*<*<
985 m4trace: -1- dnl -> >*>*>*>*><*<*<*<*<
988 AT_CHECK_M4([multiquotes.m4], 0, expout, experr)
990 AT_CLEANUP
994 ## -------- ##
995 ## patsubst ##
996 ## -------- ##
998 AT_SETUP([patsubst])
1000 AT_DATA([[patsubst.m4]],
1001 [[# traceon(`patsubst')
1002 patsubst(`GNUs not Unix.', `^', `OBS: ')
1003 patsubst(`GNUs not Unix.', `\<', `OBS: ')
1004 patsubst(`GNUs not Unix.', `\<\w', `\&=')
1005 patsubst(`GNUs not Unix.', `\w*', `(\&)')
1006 patsubst(`GNUs not Unix.', `\w+', `(\&)')
1007 patsubst(`GNUs not Unix.', `\w+')
1008 patsubst(`GNUs   not  '`         Unix.', `[      ]+', ` ')
1011 AT_DATA([[expout]],
1012 [[# traceon(`patsubst')
1013 OBS: GNUs not Unix.
1014 OBS: GNUs OBS: not OBS: Unix.
1015 G=NUs n=ot U=nix.
1016 (GNUs)() (not)() (Unix)().()
1017 (GNUs) (not) (Unix).
1018   .
1019 GNUs not Unix.
1022 AT_CHECK_M4([patsubst.m4], 0, expout)
1024 AT_CLEANUP
1028 ## ------ ##
1029 ## regexp ##
1030 ## ------ ##
1032 AT_SETUP([regexp])
1034 AT_DATA([[regexp.m4]],
1035 [[traceon(`regexp')dnl
1036 regexp(`hej med dig', `.*', `>>\&<<')
1037 regexp(`hej med dig', `\w*', `>>\&<<')
1038 regexp(`hej med dig', `.+', `>>\&<<')
1039 regexp(`hej med dig', `m\w+', `>>\&<<')
1040 regexp(`hej med dig', `m\(.*\)', `>>\&<< >>\1<<')
1042 regexp(`hej med dig', `.*')
1043 regexp(`hej med dig', `\w*')
1044 regexp(`hej med dig', `.+')
1045 regexp(`hej med dig', `m\w+')
1046 regexp(`hej med dig', `m\(.*\)')
1049 AT_DATA([[expout]],
1050 [[>>hej med dig<<
1051 >>hej<<
1052 >>hej med dig<<
1053 >>med<<
1054 >>med dig<< >>ed dig<<
1063 AT_DATA([[experr]],
1064 [[m4trace: -1- regexp(`hej med dig', `.*', `>>\&<<') -> `>>hej med dig<<'
1065 m4trace: -1- regexp(`hej med dig', `\w*', `>>\&<<') -> `>>hej<<'
1066 m4trace: -1- regexp(`hej med dig', `.+', `>>\&<<') -> `>>hej med dig<<'
1067 m4trace: -1- regexp(`hej med dig', `m\w+', `>>\&<<') -> `>>med<<'
1068 m4trace: -1- regexp(`hej med dig', `m\(.*\)', `>>\&<< >>\1<<') -> `>>med dig<< >>ed dig<<'
1069 m4trace: -1- regexp(`hej med dig', `.*') -> `0'
1070 m4trace: -1- regexp(`hej med dig', `\w*') -> `0'
1071 m4trace: -1- regexp(`hej med dig', `.+') -> `0'
1072 m4trace: -1- regexp(`hej med dig', `m\w+') -> `4'
1073 m4trace: -1- regexp(`hej med dig', `m\(.*\)') -> `4'
1076 AT_CHECK_M4([regexp.m4], 0, expout, experr)
1078 AT_CLEANUP
1082 ## ------------ ##
1083 ## sync-lines.  ##
1084 ## ------------ ##
1086 AT_SETUP([sync-lines])
1088 AT_DATA([[in]],
1089 [[syncoutput(on)dnl
1090 # Several input lines, expanding to one
1091 define(`foo', ``foo' line one.
1092 `foo' line two.
1093 `foo' line three.') xyz
1095 # Several input lines, expanding to none
1096 define(`foo', ``foo' line one.
1097 `foo' line two.
1098 `foo' line three.')dnl
1099 # one input line, expanding to several output lines
1100 foo foo
1103 AT_CHECK_M4([[in]], 0,
1104 [[#line 2 "in"
1105 # Several input lines, expanding to one
1106 #line 5
1107  xyz
1108 foo line one.
1109 #line 6
1110 foo line two.
1111 #line 6
1112 foo line three.
1113 # Several input lines, expanding to none
1114 #line 11
1115 # one input line, expanding to several output lines
1116 foo line one.
1117 #line 12
1118 foo line two.
1119 #line 12
1120 foo line three. foo line one.
1121 #line 12
1122 foo line two.
1123 #line 12
1124 foo line three.
1127 AT_CLEANUP
1130 ## ------ ##
1131 ## syscmd ##
1132 ## ------ ##
1134 AT_SETUP([syscmd])
1136 dnl Ensure that syscmd does not inherit any unnecessary fds from trace.
1137 AT_DATA([in.m4], [[syscmd(`echo hi >&3')ifelse(sysval,
1138 `0', `skipping: sh cannot detect closed fds
1139 m4exit(`77')')dnl
1141 AT_CHECK_M4([3>&-], [0], [], [stderr], [in.m4])
1142 mv stderr experr
1143 AT_CHECK_M4([--debugfile=trace -tdnl 3>&-], [0], [], [experr], [in.m4])
1144 AT_CHECK([cat trace], [0], [[m4trace: -1- dnl -> `'
1147 dnl Ensure that syscmd does not inherit any unnecessary fds from diversions.
1148 AT_DATA([in.m4], [M4_ONE_MEG_DEFN[divert(`1')f
1149 world
1150 syscmd(`echo hi >&3')divert
1151 hello
1153 AT_CHECK_M4([3>&-], [0], [stdout], [experr], [in.m4])
1154 AT_CHECK([$SED -ne '/./p' stdout], [0], [[hello
1155 world
1158 dnl Ensure that syscmd does not inherit any unnecessary fds from input files.
1159 AT_DATA([in.m4], [[hello syscmd(`cat <&3')dnl
1160 dnl this line should not be read by cat
1161 world
1163 AT_CHECK_M4([3>&-], [0], [[hello world
1164 ]], [stderr], [in.m4])
1165 mv stderr experr
1166 AT_CHECK_M4([in.m4 3>&-], [0], [[hello world
1167 ]], [experr])
1169 AT_CLEANUP
1172 ## -------- ##
1173 ## translit ##
1174 ## -------- ##
1176 AT_SETUP([translit])
1178 AT_DATA([[translit.m4]],
1179 [[# traceon(`translit')dnl
1180 translit(`GNUs not Unix', `a-z')
1181 translit(`GNUs not Unix', `a-z', `A-Z')
1182 translit(`GNUs not Unix', `A-Z', `a-z')
1183 translit(`GNUs not Unix', `A-Z')
1184 translit(`a-z', `a-')
1185 translit(`A-Z', `A-Z-', `-A-Z')
1186 translit(`GNUs not Unix', `Z-A', `a-z')
1189 AT_CHECK_M4([translit.m4], 0,
1190 [[# traceon(`translit')dnl
1191 GNU  U
1192 GNUS NOT UNIX
1193 gnus not unix
1194 s not nix
1197 tmfs not fnix
1200 dnl This used to be quadratic, taking millions of comparisons,
1201 dnl but should now operate in linear time with only several thousand checks.
1202 AT_DATA([in], [M4_ONE_MEG_DEFN[dnl
1203 define(`a_', translit(substr(f, `0', `50000'), `
1204 ', `a'))dnl
1205 define(`b_', translit(substr(f, `0', `50000'), `
1206 ', `b'))dnl
1207 define(`d_', translit(substr(f, `0', `50000'), `
1208 ', `d'))dnl
1209 define(`c'd_, `pass')dnl
1210 translit(`a'b_, a_`b', `c'd_)
1212 AT_CHECK_M4([in], [0], [[pass
1215 dnl This validates that ranges are built using unsigned chars.
1216 AT_DATA([in], [[translit(`«abc~', `~-»')
1218 AT_CHECK_M4([in], [0], [[abc
1221 AT_CLEANUP
1225 ## -------- ##
1226 ## undivert ##
1227 ## -------- ##
1229 AT_SETUP([undivert])
1231 AT_DATA([[undivert.m4]],
1232 [[define(`undiverted', `UNDIVERTED')
1233 # undiverted file.
1234 undivert(`undivert.incl')
1235 # included file.
1236 include(`undivert.incl')
1239 AT_DATA([[undivert.incl]],
1240 [[This is to be undiverted soon.
1243 AT_CHECK_M4([undivert.m4], 0,
1245 # undiverted file.
1246 This is to be undiverted soon.
1248 # included file.
1249 This is to be UNDIVERTED soon.
1253 AT_CLEANUP
1257 ## ---- ##
1258 ## wrap ##
1259 ## ---- ##
1261 AT_SETUP([wrap])
1263 AT_DATA([[wrap.m4]],
1264 [[divert(-1)
1265 m4wrap(`Wrapper no. 1
1268 m4wrap(`Wrapper no. 2
1269 m4wrap(`Wrapper no. 3
1270 m4wrap(`Wrapper no. 4
1271 ')')')
1272 divert
1273 No. 33: The End.
1276 AT_CHECK_M4([wrap.m4], 0,
1278 No. 33: The End.
1279 Wrapper no. 1
1280 Wrapper no. 2
1281 Wrapper no. 3
1282 Wrapper no. 4
1285 AT_CLEANUP