m4: Improved m4wrap

 
 17.5 Solution for 'm4wrap'
 ==========================
 
 The replacement 'm4wrap' versions presented above, designed to guarantee
 FIFO or LIFO order regardless of the underlying M4 implementation, share
 a bug when dealing with wrapped text that looks like parameter
 expansion.  Note how the invocation of 'm4wrapN' interprets these
 parameters, while using the builtin preserves them for their intended
 use.
 
      $ m4 -I examples
      include(`wraplifo.m4')
      =>
      m4wrap(`define(`foo', ``$0:'-$1-$*-$#-')foo(`a', `b')
      ')
      =>
      builtin(`m4wrap', ``'define(`bar', ``$0:'-$1-$*-$#-')bar(`a', `b')
      ')
      =>
      ^D
      =>bar:-a-a,b-2-
      =>m4wrap0:---0-
 
    Additionally, the computation of '_m4wrap_level' and creation of
 multiple 'm4wrapN' placeholders in the original examples is more
 expensive in time and memory than strictly necessary.  Notice how the
 improved version grabs the wrapped text via 'defn' to avoid parameter
 expansion, then undefines '_m4wrap_text', before stripping a level of
 quotes with '_arg1' to expand the text.  That way, each level of
 wrapping reuses the single placeholder, which starts each nesting level
 in an undefined state.
 
    Finally, it is worth emulating the GNU M4 extension of saving all
 arguments to 'm4wrap', separated by a space, rather than saving just the
 first argument.  This is done with the 'join' macro documented
 previously (⇒Shift).  The improved LIFO example is shipped as
 'm4-1.4.18/examples/wraplifo2.m4', and can easily be converted to a FIFO
 solution by swapping the adjacent invocations of 'joinall' and 'defn'.
 
      $ m4 -I examples
      include(`wraplifo2.m4')
      =>
      undivert(`wraplifo2.m4')dnl
      =>dnl Redefine m4wrap to have LIFO semantics, improved example.
      =>include(`join.m4')dnl
      =>define(`_m4wrap', defn(`m4wrap'))dnl
      =>define(`_arg1', `$1')dnl
      =>define(`m4wrap',
      =>`ifdef(`_$0_text',
      =>       `define(`_$0_text', joinall(` ', $@)defn(`_$0_text'))',
      =>       `_$0(`_arg1(defn(`_$0_text')undefine(`_$0_text'))')dnl
      =>define(`_$0_text', joinall(` ', $@))')')dnl
      m4wrap(`define(`foo', ``$0:'-$1-$*-$#-')foo(`a', `b')
      ')
      =>
      m4wrap(`lifo text
      m4wrap(`nested', `', `$@
      ')')
      =>
      ^D
      =>lifo text
      =>foo:-a-a,b-2-
      =>nested  $@