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