m4: M4wrap

 
 8.5 Saving text until end of input
 ==================================
 
 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':
 
  -- Builtin: m4wrap (STRING, ...)
      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.18/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.18/examples/wraplifo.m4' from the distribution.  (Unfortunately,
 both examples shown here share some subtle bugs.  See if you can find
 and correct them; or ⇒Answers Improved m4wrap.).
 
      $ 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