Previous: Changeword, Up: Input Control [Contents][Index]
It is possible to ‘save’ some text until the end of the normal input has
been seen. Text can be saved, to be read again by m4
when the
normal input has been exhausted. This feature is normally used to
initiate cleanup actions before normal exit, e.g., deleting temporary
files.
To save input text, use the builtin m4wrap
:
Stores string in a safe place, to be reread when end of input is reached. As a GNU extension, additional arguments are concatenated with a space to the string.
The expansion of m4wrap
is void.
The macro m4wrap
is recognized only with parameters.
define(`cleanup', `This is the `cleanup' action. ') ⇒ m4wrap(`cleanup') ⇒ This is the first and last normal input line. ⇒This is the first and last normal input line. ^D ⇒This is the cleanup action.
The saved input is only reread when the end of normal input is seen, and
not if m4exit
is used to exit m4
.
It is safe to call m4wrap
from saved text, but then the order in
which the saved text is reread is undefined. If m4wrap
is not used
recursively, the saved pieces of text are reread in the opposite order
in which they were saved (LIFO—last in, first out). However, this
behavior is likely to change in a future release, to match
POSIX, so you should not depend on this order.
It is possible to emulate POSIX behavior even with older versions of GNU M4 by including the file m4-1.4.19/examples/wrapfifo.m4 from the distribution:
$ m4 -I examples undivert(`wrapfifo.m4')dnl ⇒dnl Redefine m4wrap to have FIFO semantics. ⇒define(`_m4wrap_level', `0')dnl ⇒define(`m4wrap', ⇒`ifdef(`m4wrap'_m4wrap_level, ⇒ `define(`m4wrap'_m4wrap_level, ⇒ defn(`m4wrap'_m4wrap_level)`$1')', ⇒ `builtin(`m4wrap', `define(`_m4wrap_level', ⇒ incr(_m4wrap_level))dnl ⇒m4wrap'_m4wrap_level)dnl ⇒define(`m4wrap'_m4wrap_level, `$1')')')dnl include(`wrapfifo.m4') ⇒ m4wrap(`a`'m4wrap(`c ', `d')')m4wrap(`b') ⇒ ^D ⇒abc
It is likewise possible to emulate LIFO behavior without resorting to
the GNU M4 extension of builtin
, by including the file
m4-1.4.19/examples/wraplifo.m4 from the
distribution. (Unfortunately, both examples shown here share some
subtle bugs. See if you can find and correct them; or see Answers).
$ m4 -I examples undivert(`wraplifo.m4')dnl ⇒dnl Redefine m4wrap to have LIFO semantics. ⇒define(`_m4wrap_level', `0')dnl ⇒define(`_m4wrap', defn(`m4wrap'))dnl ⇒define(`m4wrap', ⇒`ifdef(`m4wrap'_m4wrap_level, ⇒ `define(`m4wrap'_m4wrap_level, ⇒ `$1'defn(`m4wrap'_m4wrap_level))', ⇒ `_m4wrap(`define(`_m4wrap_level', incr(_m4wrap_level))dnl ⇒m4wrap'_m4wrap_level)dnl ⇒define(`m4wrap'_m4wrap_level, `$1')')')dnl include(`wraplifo.m4') ⇒ m4wrap(`a`'m4wrap(`c ', `d')')m4wrap(`b') ⇒ ^D ⇒bac
Here is an example of implementing a factorial function using
m4wrap
:
define(`f', `ifelse(`$1', `0', `Answer: 0!=1 ', eval(`$1>1'), `0', `Answer: $2$1=eval(`$2$1') ', `m4wrap(`f(decr(`$1'), `$2$1*')')')') ⇒ f(`10') ⇒ ^D ⇒Answer: 10*9*8*7*6*5*4*3*2*1=3628800
Invocations of m4wrap
at the same recursion level are
concatenated and rescanned as usual:
define(`aa', `AA ') ⇒ m4wrap(`a')m4wrap(`a') ⇒ ^D ⇒AA
however, the transition between recursion levels behaves like an end of file condition between two input files.
m4wrap(`m4wrap(`)')len(abc') ⇒ ^D error→m4:stdin:1: ERROR: end of file in argument list
Previous: Changeword, Up: Input Control [Contents][Index]