Provided by: makepp_2.0.98.5-2.1_all bug

NAME

       makepp_builtins -- Builtin commands in makepp

DESCRIPTION

       A: awk,  C: &cat,
         chgrp,
         &chmod,
         chown,
         &cp,
         cpp,
         &cut,  D: date,  E: &echo,
         &expr,  F: false,
         fmt,  G: &grep,  H: head,  I: &install,  L: &ln,  M: m4,
         &mkdir,
         &mv,  P: &perl,
         &preprocess,
         &printf,  R: &rm,
         rmdir,  S: &sed,
         &sort,  T: tail,
         &template,
         &touch,
         tr,  U: &uninstall,
         &uniq,  Y: &yes

       There is a special Shell-like possibility to call built-in commands in a rule.  The only
       metacharacters recognized are comment signs, backslashes, single and double quotes.  Only
       one command may be given per line, and I/O redirection is not available (see "-i" and "-o"
       below instead).

       These commands start with "&", which is the function character in Perl and not a valid
       first character in Shell.  If no builtin command of that name can be found, this is also
       the syntax for calling an external script within the Perl instance performing the rule.
       See "run".

       These commands, as well as your self defined ones and Perl scripts can also be called as a
       make function, returning the standard output.  This requires perl to be built for PerlIO.
       The newlines are converted to spaces, except when evaluated within a "define" statement.

           FIRST-WORDS ;= $(&cut -d' ' -f0 $(FILES))

       When these commands are not indented as rule actions, they get performed while reading the
       makefile.  You can also access these commands stand-alone, e.g. if you need some features
       not available in the Unix counterpart, via the makeppbuiltin command.

       These commands are mostly based on the GNU variant.  But many options (like --backup,
       --interactive or --recursive) don't really make sense in a makefile.  So, even though
       they'd be easy to implement in Perl, they have been left out.  Also many Unix commands
       offer a variety of options that cover fairly complicated cases (e.g. sort field
       specifications) while still being inherently limited.  Allowing access to Perl, which is
       present anyway, gives much more power here.

       Lists of filenames may be empty, making it safe to call these commands with an unchecked
       list.  Options in their short form may be glued together as in "-ab" instead of "-a -b".
       In the long form arguments may be given either glued on with an "=" sign or separately.
       In the short form they may be given either glued on directly or separately.

   Standard options
       A few options are common to several builtins, though the short form is sometimes hidden by
       a command's own option (as in "&cut -f"):

       -A filename
       --args-file=filename
       --arguments-file=filename
           Read the file and parse it as possibly quoted whitespace- and/or newline-separated
           options.

       -f
       --force
           Force the creation of the file(s) intended by the parameters, even if a different kind
           of file or empty directory of that name already exists.  This must precede the "-o,
           --output=filename" option if it is to have any effect on that.

       -i shellcommand
       --inpipe=shellcommand
           Start the Shell command(s) and pipe the output into the builtin.  There may optionally
           be a trailing "|" character, to indicate this is a pipe.  With this option no
           filenames need to be given.  But if you want to perform the builtin on both files and
           the pipe output, you must use "-" as a filename for the pipe output.  The pipe is
           emptied, but, unless you also give "--infail", the command is not waited for, so it
           can terminate in parallel.  This option is necessary because there is no redirection
           syntax.

       -I
       --infail
           If an "--inpipe" Shell command fails, that also causes the current builtin to fail.
           This doesn't currently work on Strawberry and Win ActiveState, because of the
           halfhearted way they emulate Unix fork/exec.  Cygwin gets it right though.

       -o filename
       --output=filename
           Write the output to this file, rather than stdout.  Filename may have any of these
           forms:

           filename
           >filename
               Simply write to file.

           >>filename
               Append to (not necessarily) existing file.

           +<filename
               Also open the file for input, allowing inplace editing.  With this option variant
               no input filenames need to be given.  But if you want to perform the builtin on
               more files, you must use "-" as an input filename for this one.  In fact the
               output gets written to a temporary file which gets moved to filename at the end.

           |shellcommand
               Pipe the builtin's output to the Shell command(s).

           This option is necessary because there is no redirection syntax.

       -O
       --outfail
           If an "--output" Shell command fails, that also causes the current builtin to fail.

       -r number
       --record-size=number
           Locally sets $/ for the current builtin.  This splits input into records of length
           number rather than line by line.  If number is zero, each input file as a whole is one
           record.

       -s string
       --separator=string
           Locally sets $/ for the current builtin.  This splits input on string rather than line
           by line.

       -S
       --synclines
           Generate "#line ""NO"" """FILE"""" and "#line ""NO" lines, understood by many C-like
           languages.

       -v
       --verbose
           Document the changes to the file system.  This must precede other options if it is to
           document their effect.  If you pass this option to makepp itself, it is as if you had
           given it for every single builtin command.

   Builtin commands
       There are two motivations for having builtin commands in makepp.  The first is to offer a
       set of utilities, which, unlike Shell commands, are guaranteed to work the same
       everywhere, like "&echo -n" or "&mkdir -p", and saving you the hassle of finding the path
       to &install and figuring out its wildly varying options.  In a compilation environment,
       it's useful to have the "--synclines" option, which normally only "m4" provides, on all
       filters.

       The other is a question of efficiency.  In general costly fork/execs should be avoided
       where reasonably possible.  On Unix emulations like Cygwin or BS2000/Posix, this becomes a
       noticeable win.  But, even on Linux, when the makepp test suite was converted from
       external commands to builtins, there was an overall saving of 3% user CPU usage and 15%
       system CPU usage.  (The tests are of course heavy on primitive actions and hardly call the
       compiler.)

       Consistency is also an issue, though we're not going to reform Unix.  Normally commands
       have various nuances of regular expressions.  And many invent sort of languages, each
       different of course, for doing something (e.g. "expr", "sed" ...), or complex options for
       specifying fields, delimiters, columns (e.g. "cut", "sort" ...).

       Here instead, anything fancy simply gets handled by Perl, giving both consistency across
       all commands, and far more power than a whole bunch of options.  Better yet, any Perlcode
       these commands run for you, gets run in the package of the Makefile.  So, rather than
       stuff Perl code into the rule action, you can define functions and variables and use them
       within the commands:

           sub my_filter {
             # Return true iff $_ is desirable
           }
           %.out: %.in Makeppfile
               &grep &my_filter $(input) -o $(output)

       If you use Perl functions or variables in your commands, makepp does not recognize this as
       a dependency.  It is generally safer to tell makepp everything, so rules which use Perl
       elements should depend on the makefile or module providing those elements, as shown in the
       above example.

       On the other hand ignorance may be desirable if you have a program that mixes programmatic
       and configuration aspects in one file.  An example would be a WSDL file containing both a
       web service interface definition and an IP address.  You could preprocess this file with
       the &template command to patch in the configuration, but not let makepp notice.

       &cat [option ...] filename ...
           Concatenates all the files into a single one.

           "Standard options": "-A, --args-file, --arguments-file=filename, -f, --force, -i,
           --inpipe=shellcommand, -I, --infail, -o, --output=filename, -O, --outfail, -S,
           --synclines, -v, --verbose"

       &chmod [option ...] mode filename ...
           Sets mode for all given files.  Mode must be an octal string.

           "Standard options": "-A, --args-file, --arguments-file=filename, -v, --verbose"

       &cp [option ...] sourcefile destfile
       &cp [option ...] sourcefile
       &cp [option ...] sourcefile ... destdir
           Copy sourcefile to destfile, one sourcefile to current directory or multiple
           sourcefiles to destdir with the same name.

           "Standard options": "-A, --args-file, --arguments-file=filename, -f, --force, -v,
           --verbose"

           -l
           --link
               Try to link the files.  If that fails, try symbolic link, if that is also
               requested, else copy.

           -s
           --symbolic
           --symbolic-link
           --symlink
               Try to symbolically link the files.  If that fails, copy.

           See the note under &ln.

       &cut [option ...] filename ...
           Print selected parts of lines from each file or selected lines, counting across all
           files.  The output is separated by the delimiter which defaults to TAB for fields and
           empty string for characters.

           "Standard options": "-A, --args-file, --arguments-file=filename, --force, -i,
           --inpipe=shellcommand, -I, --infail, -o, --output=filename, -O, --outfail, -r,
           --record-size=number, --separator=string, -S, --synclines, -v, --verbose"

           -c list
           --characters=list
               Print all the characters specified by list.  List may be any Perl expression
               returning a list of integers.  The integers can be either positive, starting at
               zero to count from the beginning, or negative to count from the end.  Unlike Unix
               "cut", the order you request is respected.

               Unlike in Perl's slice operator where a ".." range must be either positive or
               negative, &cut allows starting with a positive and ending with a negative.  But
               this is only available if your expression consists only of numbers, commas and
               "..".  E.g. "1..-2" means everything but the first (0) and the last (-1).

               The list expression can look at the whole line in $_.  Changes to that will be
               ignored, however, because when this expression is evaluated the line has already
               been split to Perl's autosplit variable @::F.  The numbers you return are in fact
               indices to that list.

           -d string
           --delimiter=string
               Set a new delimiter for input fields and output.  Unlike Unix "cut", this may have
               any length.

           -E
           --noescape
               Treat "\" as normal literals for "-p, --printf=format".

           -f list
           --fields=list
               Print all the groups specified by list.  List is as described under "-c,
               --characters=list".  Note that this hides the standard option "-f" which must be
               given as "--force".

           -l list
           --lines=list
               Print all the lines specified by list.  List is as described under "-c,
               --characters=list" with one major difference: The first line has number 1, there
               is no line 0.  This is definitely inefficient for big files, if you have a mixed
               positive to negative range in your list, as it reads everything to memory.
               Otherwise Perl could optimize this, but I don't know if it does.

           -m
           --matching
               Print only matching lines, i.e. ones which have enough characters or fields.  This
               implies "--only-delimited", which is why you will miss single-field lines with
               "--fields=0".

           -p format
           --printf=format
               Apply format (with \escapes) to all fields or characters.

           -s
           --only-delimited
               Print only lines containing delimiters.

               &cut -c 10-20,-5,25- $(input)
               &cut -c 'grep $$_ % 3, 0..99' $(input) # 1st 100 columns not multiple of 3
               &cut -d: --fields 0,4 --printf='%10s is %s\n' /etc/passwd

       &echo [option ...] string ...
       &printf [option ...] format argument ...
       &yes [option ...] string ...
           Writes all strings to stdout or the given outfile.  Both &echo and &yes add a newline
           at the end.  The strings, or for &printf the format, may contain "\" escapes, as they
           are known from C or modern Unix or Shell "echo".  They are however as in Perl double-
           quotes, which means some differences, like that a single trailing "\" is not allowed.
           Perl has a few more interesting escapes, but the ones you might expect to do something
           different are:

           \cA Is a control character ^A.

           \u  Upcases the following letter.

           \U  Upcases the rest, or up to the next "\E" or "\L" if found.

           \xHH, \x{HHHH}
               Is the character value of the given Hex code.  Note that numeric codes are not
               portable to EBCDIC platforms!

           Unlike Unix "yes", &yes is exactly like &echo, except that it repeats the output for
           as long as it can, typically until an "--output '| command'" terminates.  And, if &yes
           has no arguments, it defaults to "y".

           "Standard options": "-A, --args-file, --arguments-file=filename, -f, --force, -o,
           --output=filename, -O, --outfail, -v, --verbose"

           -E
           --noescape
               Treat "\" as normal literals.

           -n
           --nonewline
               Do not add a newline after the last string.  (Not understood by &printf.)

       &expr [option ...] perlcode ...
           Print the scalar value of perlcode, which may be written as one or several arguments.
           Note that builtin commands are not parsed by the Shell, so "*", "(" or ">" are not
           special.  But string quotes are parsed by makepp, so Perl strings must be quoted
           twice, unless you want to use barewords.  If the value is false, this fails.  Note
           that -- unlike in Unix "expr" -- Perl's index function starts at 0 (false) and returns
           -1 (true) for failure.

           "Standard options": "-A, --args-file, --arguments-file=filename, -f, --force, -o,
           --output=filename, -O, --outfail, -v, --verbose"

           -n
           --nonewline
               Do not add a newline after the output.

               &expr ($(VAR) - 3) * 2 < 1 && -1 || 1
               &expr "$(VAR) - 3 * 2 < 1 ? 'joy' : 'sorrow'" -o $(output)
               -&expr $(VAR) - 3 * 2 -o >>$(output)

       &grep [option ...] perlcode filename ...
       &perl [option ...] perlcode filename ...
       &sed [option ...] perlcode filename ...
           All the files get read line by line (unless you gave a "--separator" option), and
           perlcode gets evaluated for each line, before it gets printed.  &sed is similar to
           "perl -pe", while &grep only outputs those lines for which perlcode returns a true
           value.  &perl is similar to "perl -ne", only outputting whatever you explicitly print
           in the perlcode.  The line content is available in $_, which may be modified.

           Of these three, only &grep will fail if it outputs nothing.  Note that there is no
           ignore-case option, since you would do that with "/regexp/i".

           "Standard options": "-A, --args-file, --arguments-file=filename, -f, --force, -i,
           --inpipe=shellcommand, -I, --infail, -o, --output=filename, -O, --outfail, -r,
           --record-size=number, -s, --separator=string, -S, --synclines, --verbose"

           The option "--synclines" only makes sence with &perl if you use &Mpp::Cmds::print to
           output $_.  Only &grep has extra options:

           -c
           --count
               Suppress normal output; instead print a count of matching lines.  With the "-v,
               --invert-match" option (see below), count non-matching lines.

           -l
           --list
           --files-with-matches
               Output only the name of those files with matches.  When this is combined with "-v,
               --invert-match", output the name of files with lines that don't match (a bit
               absurdly but compatible with Unix -vl).  When this is combined with a doubled
               "-vv", output the name of files with no matches.

           -v
           --vice-versa
           --revert-match
           --invert-match
               Invert the sense of matching, to select non-matching lines.  Note that this hides
               the standard option "-v" which must be given as "--verbose".

           -w filename
           --waste-file=filename
               An optional waste basket for collecting the rejected lines.  This is not only for
               debugging your selection code, but also for splitting your input in two.  As with
               the normal output, you may modify $_ before returning false.

               &sed s/foo/bar/ f1 f2 f3 -o outfile # like sed s/foo/bar/ f1 f2 f3 >outfile
               &sed '$$_ = uc' f1 f2 f3 -o outfile # like tr '[:lower:]' '[:upper:]' f1 f2 f3
               &grep '$$. % 3' f1 f2 f3 -o outfile # eliminate every 3rd line
               &grep -c /match/i f1 f2 f3          # count the lines matching 'match' to STDOUT

           Without pushing you to mass generate accessors, here's how you could do it by simply
           putting a comment of RO or RW between each type and desired variable name, all on one
           line.  The generated getter and optionally setter methods go into the next found
           public or protected section:

               # Create get and maybe set method from "type /* R[OW] */ member;".
               sub cxx_accessors {
                 $acc ||= '';              # Candidate for 5.10.0 state
                 if( m!^\s*(.+?)\s*/\*\s*R([OW])\s*\*/\s*(.+?)\s*;! ) {
                   $acc .= "#line $.\n";   # Tell C++ where this came from
                   $acc .= "void set\u$3( const $1 &__tmp ) { $3 = __tmp; }"
                     if $2 eq 'W';
                   $acc .= "const $1 &get\u$3() const { return $3; }\n";
                 } elsif( /^\s*(?:public|protected)\s*:/ ) {
                   $_ .= $acc;
                   $acc = '';
                 }
               }

               %.cc: %.cc.in               # Use &sed for I/O handling
                   &sed --sync-lines &cxx_accessors $(input) -o $(output)

       &install [option ...] sourcefile destfile
       &install [option ...] sourcefile ... destdir
       &install --directory [option ...] directory ...
           Move or rename sourcefile to destfile, or multiple sourcefiles to destdir with the
           same name.  This is the preferred way of transferring build results to their final
           installation locations.

           Every file system modification performed by &install gets logged to the end of the
           file pointed to by the environment variable $INSTALL_LOG, or, if that is not set but
           we are under a directory with a RootMakeppfile(.mk), to a file of .install_log in that
           directory, or else to that file in the current directory.  You may want to delete the
           logfile before a series of &install invocations.

           "Standard options": "-A, --args-file, --arguments-file=filename, -v, --verbose"

           -c
           --copy
               Copy the files rather than moving them.  This is preferable, as it doesn't force
               makepp to rebuild the file next time.  But it is not the default, for
               compatibility with other install programs.

           -d
           --directory
               In the third form form of this command create all the given directories and any
               necessary parent directories.

           -g group
           --group=group
               Change the group ownership of the destination files.  The group may be given by
               name or numerically.

           -l
           --link
               Try to link the files.  If that fails, copy.

           --log=filename
           --logfile=filename
               Use filename instead of normal logfile.

           -m mode
           --mode=mode
               Sets mode for all destination files or directories.  Mode must be an octal string.

           -o owner
           --owner=owner
               Change the ownership of the destination files.  The owner may be given by name or
               numerically.

           -r
           --resolve
           --resolve-symbolic
           --resolve-symbolic-link
           --resolve-symlink
           -S
           --symbolic
           --symbolic-link
           --symlink
               Creates symbolic links instead of moving.  These options are passed to &ln and are
               described there.

           -s
           --strip
               Calls the "strip" utility, which must be in the $PATH, on the destination files.

       &ln [option ...] sourcefile destfile
       &ln [option ...] sourcefile
       &ln [option ...] sourcefile ... destdir
           Link sourcefile to destfile, one sourcefile to current directory or multiple
           sourcefiles to destdir with the same name.

           "Standard options": "-A, --args-file, --arguments-file=filename, -f, --force, -v,
           --verbose"

           -r
           --resolve
           --resolve-symbolic
           --resolve-symbolic-link
           --resolve-symlink
               This is what you always wanted "ln -s" to do.  Create symbolic rather than hard
               links, not to the strings specified, but really to the given files.

           -s
           --symbolic
           --symbolic-link
           --symlink
               Create symbolic rather than hard links.

           Note: On various file or operating systems, this operation is not supported.  Or it
           is, e.g. by Cygwin, but not understood by native Windows compilers, if you use one.
           For a makefile you can't change, to get at least some sort of result, &ln and "&cp -l
           -s" can copy the files for you instead (not directories though).  To achieve this, you
           need to export the following variable before calling makepp:

           export MAKEPP_LN_CP=1
               &ln --resolve or --symbolic will copy the files instead of creating a symbolic
               link.

           export MAKEPP_LN_CP=2
               &ln will copy the files instead of creating a hard link.

           export MAKEPP_LN_CP=3
               All invocations of &ln will copy the files instead of creating either kind of
               link.

       &mkdir [option ...] directory ...
           Create the directories.

           "Standard options": "-A, --args-file, --arguments-file=filename, -f, --force, -v,
           --verbose"

           -m mode
           --mode=mode
               Sets mode for all created directories, irrespective of the umask.  Mode must be an
               octal string.

           -p
           --parent
               Also create any necessary parent directories.  Ignore directory creation failure
               due to the directory already existing (even if it was created concurrently by
               another process).

       &mv [option ...] sourcefile destfile
       &mv [option ...] sourcefile
       &mv [option ...] sourcefile ... destdir
           Move or rename sourcefile to destfile, one sourcefile to current directory or multiple
           sourcefiles to destdir with the same name.

           "Standard options": "-A, --args-file, --arguments-file=filename, -f, --force, -v,
           --verbose"

       &preprocess [option ...] variable=definition ... filename ...
           This preprocesses the files exactly the same way makepp does for makefiles.  This is
           more powerful than &template but syntactically not suited to files with lots of
           "$"-signs, like Makefiles or scripts.

           Conditional statements, as well as the statements "include"/"_include" (which here
           neither build the file nor search upwards), "perl"/"makeperl"/"perl_begin" or
           "sub"/"makesub", or any statements you define within the file, are processed.  Empty
           and comment lines are eliminated.

           But, instead of learning build rules, it will output all remaining lines after
           "$(...)" expression expansion.  To prevent statement from being recognized as such,
           you can precede them with an empty expression "$()".  The same applies to lines you
           want to stay empty or which shall retain a leading comment sign.  Likewise, if a
           trailing backslash is not to join a line with the next, put "$()" after it.

               A normal line gets output as is.
               A line with $(MAKEEXPRESSIONS) gets expanded and output.
               ifdef WANTTHIS      # does not get output whether defined or not
               might not get output
               endif
               include some files
               _include some files that might not exist # or -include
               $()include empty expression prevents keyword from being recognized.
               # Comment lines and empty lines get swallowed.

               $()# Unless they get masked with an empty expression.
               $()
               Empty expression prevents \$()
               backslash continuation from being recognized.

           might give:

               A normal line gets output as is.
               A line with whatever gets expanded and output.
               lots of slurped in content here...
               include empty expression prevents keyword from being recognized.
               # Unless they get masked with an empty expression.

               Empty expression prevents \
               backslash continuation from being recognized.

           "Standard options": "-A, --args-file, --arguments-file=filename, -f, --force, -o,
           --output=filename, -O, --outfail, -S, --synclines, -v, --verbose"

           -a
           --assignment
               Also treat assignments within the files as makepp would.  Alas such lines can't be
               masked with an empty "$()", because it is legal to construct variable names with
               expressions.  This additionally recognizes the statements "define",
               "export"/"unexport" and "override" (these can be masked with "$()").

           -h \\%hash
           --hashref=\\%hash
               This allows preallocation of the variable values, including long ones not easily
               passed in a command.  The passed expression may be any Perl code that returns a
               hash reference.  This is merged with any other variables passed to the command,
               including from another "--hashref" option.

       &rm [option ...] filename ...
           Delete files if you have directory write permission.  This is what Unix "rm -f" would
           delete, since it has a special protection for interactive use not needed in a
           Makefile.

           "Standard options": "-A, --args-file, --arguments-file=filename, -v, --verbose"

           -f
           --force
               This prevents complaining about inexistent files.  That is a side effect this
               option has in Unix, and the only one that makes sense here.

           -m
           --metainfo
               In addition to the given files, this also deletes the meta information makepp
               stores about them in the .makepp directory.  Thus makepp forgets all it ever knew
               about the given files.  If the .makepp directory becomes empty after this, it too
               is deleted.

           This will also delete given directories, but only if they are empty.  To facilitate
           this, it will delete directories last, in the order of descending depth.  So you can
           use "**" expressions to delete whole hierarchies.  Here's an example to be found in
           many top level make files.  Note that there is a "makeppclean" utility that can do
           this more efficiently.

               $(phony cleanold):
                   &rm -fm $(only-stale **/*)

               $(phony clean): cleanold
                   &rm -f $(wildcard **/*.[ao])

               $(phony distclean): clean
                   &rm -fm $(only-targets **/*)

       &sort [option ...] filename ...
           Sorts all files together in lexicographic order.  This is inefficient for rather big
           files, because it happens completely in memory.  It will fail if the combined size of
           all files exceeds the memory you are entitled to.

           "Standard options": "-A, --args-file, --arguments-file=filename, -f, --force, -i,
           --inpipe=shellcommand, -I, --infail, -o, --output=filename, -O, --outfail,
           --record-size=number, -s, --separator=string, -v, --verbose"

           -c perlcode
           --compare=perlcode
               perlcode represents a Perl sort block, with the two sorting candidates in $a and
               $b.

           -n
           --numeric
           --numeric-sort
               This sorts sorts numerically on the beginnings of records.  Leading whitespace is
               skipped.  You can use "--transform" and "--detransform" if the numbers are not at
               the beginning.

           -r
           --reverse
               Output the results in the reverse order.  Note that this hides the standard option
               "-r" which must be given as "--record-size".

           -t perlcode
           --transform=perlcode
           -d perlcode
           --detransform=perlcode
               If you have a complex code, sorting gets more and more expensive in proportion to
               the number of records n, because the code gets called O(n log(n)) times.  To avoid
               that, you can allow Perl to concentrate on sorting, by first modifying the
               strings, such that complicated search criteria extraction happens once per record,
               and modifying them back, once they are sorted.

               If these options are given, the "--transform" perlcode gets mapped to the records
               in $_ one after another, and can modify them.  After sorting, the "--detransform"
               perlcode gets mapped to the modified records in $_ one after another, and can
               modify them back.  You will usually use neither or both of these options, unless
               you want to output modified lines.

               Turning the strings into a structure of extracted sort criteria, which your
               "--compare" perlcode can pick up is known as the Schwartzian Transform (ST).
               Packing everything into the string itself, so that no "--compare" perlcode is
               needed, allowing the whole sorting to happen without performing expensive Perl
               code, is known as the Guttmann-Rosler Transform (GRT).  You can find tips by
               searching for those names on the web.

                   # Expensively sort numerical expressions by value ($$ protects $ from makepp expansion)
                   &sort --compare 'eval( $$a ) <=> eval( $$b )' $(input) -o >>$(output)

                   # ST for case insensitive sorting
                   &sort -t '[lc, $$_]' -c '$$a->[0] cmp $$b->[0]' -d '$$_->[1]' $(input) -o >>$(output)

                   # GRT using modification functions defined elsewhere in the Makeppfile
                   &sort -t &transform -d &detransform $(input) -o >>$(output)

           -u
           --uniq
           --unique
               After sorting, eliminate duplicates.  These are either identical lines, or if the
               "--compare" option is given, ones which that perlcode reports as equivalent.

       &template [option ...] macro=definition ... filename ...
           This is a macro preprocessor, not quite as powerful as the C preprocessor or "m4".
           See &preprocess for a more powerful alternative.  It was inspired by automake's macro
           replacement in Makefile.am and Makefile.in.  But it goes beyond that.  Any normal text
           goes through unchanged.  Special constructs are by default delimited with "@".  They
           must fit on one line unless you pass one of "-r, --record-size" or "--separator".

           @# comment @
               Note that despite borrowing from script "#" line end comment syntax, this one is
               an inline comment.

           @MACRO@
               This construct is replaced by the value of the MACRO.  Macro names must start with
               a letter or underscore, followed by any number of letters, underscores, minuses or
               dots.  Unlike in makepp names, underscore and minus are not equivalent.

           @MACRO(arg1,arg2...)@
               Like the first one, but parametrized.  The args replace $1 through $9 or
               "${number}" in the value.  Or, if the value is a Perl function, they are passed as
               normal parameters.  The result then replaces the whole construct.  One level of
               macro nesting is possible in that the args in parenthesis may contain plain
               "@MACRO@" invocations, as in "@f(@x@)@", where "@x@" gets expanded before being
               replaced into the body of "f".

           @include(filename)@
               This is the only predefined macro.  It is replaced by the &template-processed
               content of the named file.  Like all macros this can occur in the middle of a
               line.  Alas, because of that, "-S, --synclines" ignores the file inclusion, making
               everything seem to come from the including file.

           @MACRO=definition@
           @MACRO?=definition@
               This defines a macro within the file.  This is replaced by nothing.  The second
               form only takes effect if the macro was not defined, presumably on the command
               line.

           @MACRO { Perlcode }@
               This also defines a macro, the body of which is a Perl sub.  The arguments, if
               there are any, get passed in as @_.

           @{ Perlcode }@
               This runs the Perlcode immediately and gets replaced by the return value.

           So far we have only seen one syntax for embedding special things.  There is another
           multiline syntax, and both allow a variation to suppress a newline.  These are the
           builtin syntaxes (which can be configured by options below).  Here SPECIAL stands for
           any of the constructs shown above:

           @SPECIAL@
           @SPECIAL@\
               This can appear multiply anywhere on a line.  The variant immediately followed by
               "\" only works at the end of the line.  It also replaces the following line break.

           @@SPECIAL@@ Normal text @@
           @@SPECIAL@@ Normal text @@\
               This is like the previous one.  However the normal text, which also gets replaced,
               can span multiple lines.  You can put the special parts on comment lines around
               source code that is only needed in an uninstalled script, to be eliminated or
               replaced during the installation process:

                   # @@# the next 2 lines will disappear @@
                   echo You are running the uninstalled version of this script
                   # @@
                   # @@REPLAMCENT@@
                   echo Something else will be here
                   # @@

           A meaningless example showing the various possibilities:

               @m1=some definition@\
               @m2=foo $1 bar@\
               @middle_of_arg=iddl@\
               @m1@ @m2(m@middle_of_arg@e)@
               @@m2(many lines)@@
               ...
               @@ plain text 1 + 2 = @{ 1 + 2 }@

           becomes

               some definition foo middle bar
               foo many lines bar plain text 1 + 2 = 3

           "Standard options": "-A, --args-file, --arguments-file=filename, -f, --force, -i,
           --inpipe=shellcommand, -I, --infail, -o, --output=filename, -O, --outfail, -r,
           --record-size=number, --separator=string, -S, --synclines, -v, --verbose"

           -d
           --defined
               Replace only instances of macros which are actually defined.  Without this option
               the undefined ones will all be replaced by nothing.

           -h \\%hash
           --hashref=\\%hash
               This allows preallocation of the macro values, including long ones not easily
               passed in a command.  The passed expression may be any Perl code that returns a
               hash reference.  This is merged with any other macros passed to the command,
               including from another "--hashref" option.  A hash value may also be a code
               reference, in that case the function gets called, as with "@macro { Perlcode }@"
               definitions.

           -s /prefix/suffix/
           --simple=/prefix/suffix/
               Use prefix and suffix before and after SPECIAL respectively instead of "@".  The
               first character is the separator and need not be a slash.  These values are Perl
               regexps.  You must not introduce grouping like "(...)", but "(?:...)" is ok.

           -m /prefix/suffix/afterprefix/[aftersuffix/]
           --multiline=/prefix/suffix/afterprefix/[aftersuffix/]
               Use prefix, suffix and afterprefix before and after SPECIAL and at the end of the
               block respectively instead of "@@".  If aftersuffix is also given, the macro name
               must get repeated before it.  The first character is the separator and need not be
               a slash.  E.g. an XML-ish, to which you must add "--defined" if you want to
               preserve other tags, not defined by you:

                   --defined --simple=|<|/>| --multiline=|<|>|</|>|

               Or, better, use processing instructions "<?...?>", intended for such a purpose:

                   --defined --simple='|<\?|\?>|'

               Or, if you want to combine this with "&entity;" syntax for the simple macro
               replacements (preserving numeric entities "&#x263A;" which are not comments):

                   --defined --simple='_(?:&(?!#)|<\?)_(?:;|\?>)_'

       &touch [option ...] filename ...
           Updates the modification and access timestamps of each file to now.  If the file
           doesn't exist, it gets created.

           "Standard options": "-A, --args-file, --arguments-file=filename, -v, --verbose"

       &uninstall [option ...] [filename ...]
           Uninstall files previously installed by &install.  The filenames are logfiles written
           by &install.  If none are given, nor an "--inpipe" option, reads the default logfile
           of &install.

           "Standard options": "-A, --args-file, --arguments-file=filename, -i,
           --inpipe=shellcommand, -I, --infail, -v, --verbose"

       &uniq [option ...] filename ...
           Discard all but one of successive equal lines.

           "Standard options": "-A, --args-file, --arguments-file=filename, -f, --force, -i,
           --inpipe=shellcommand, -I, --infail, -o, --output=filename, -O, --outfail, -r,
           --record-size=number, -s, --separator=string, -S, --synclines, -v, --verbose"

           -c perlcode
           --compare=perlcode
               This Perlcode gets the previous and current lines in $a and $b and shall return
               true if it considers the two lines equal.

               &uniq --compare='lc( $$a ) eq lc $$b' $(inputs) -o $(output)

   Emulatable commands
       Various things are not built in, but can be achieved with other commands:

       awk Use &sed.

       chgrp
       chown
           These commands are mostly not portable!  They will either quietly do nothing or fail,
           depending on the system.  Generally only root may perform these operations, which is
           why they are only available through the &install command.

       cpp Use &preprocess or &template.

       date
           Either of these partially does the same thing:

               &expr localtime
               &expr gmtime

       false
           Use &expr with no argument or 0.

       head
       tail
           You can achieve the same result with &grep or "&cut --lines":

               &grep 1..10 file            # first ten lines
               &grep 10..eof file          # all lines from tenth onwards
               &cut --lines -10..-1 file   # last ten lines

           Note that 1..10 in &grep is Perl's line number flip-flop operator, which annoyingly
           starts at 1.  Don't start at 0, or the flip-flop will never become true.

       fmt This is mentioned here since Perl provides a related functionality.  However I had
           problems using the "format" declaration in a makefile.  What does work is the
           underlying "formline" function.  E.g. to transform a csv file consisting of names and
           prices to a tabular format:

               sub csv2txt {
                 formline "\@<<<<<<<<<<<<<<< ^###########.##\n", split ',';
                 $_ = $^A;
                 $^A = '';
               }

               %.txt: %.csv
                   &sed &csv2txt $(input) -o $(output)

       m4  Use &preprocess or &template.

       rmdir
           Use &rm.

       tr  Use &sed.

AUTHOR

       Daniel Pfeiffer (occitan@esperanto.org)