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