GNU M4 1.4.16 macro processor
Table of Contents
- GNU M4
- 1 Introduction and preliminaries
- 2 Invoking
m4
- 3 Lexical and syntactic conventions
- 4 How to invoke macros
- 5 How to define new macros
- 6 Conditionals, loops, and recursion
- 7 How to debug macros and input
- 8 Input control
- 9 File inclusion
- 10 Diverting and undiverting output
- 11 Macros for text handling
- 12 Macros for doing arithmetic
- 13 Macros for running shell commands
- 14 Miscellaneous builtin macros
- 15 Fast loading of frozen state
- 16 Compatibility with other versions of
m4
- 17 Correct version of some examples
- Appendix A How to make copies of the overall M4 package
- Appendix B How to make copies of this manual
- Appendix C Indices of concepts and macros
GNU M4
This manual (28 February 2011) is for GNU M4 (version1.4.16), a package containing an implementation of the m4 macrolanguage.
Copyright © 1989-1994, 2004-2011 Free Software Foundation,Inc.
Permission is granted to copy, distribute and/or modify this documentunder the terms of the GNU Free Documentation License,Version 1.3 or any later version published by the Free SoftwareFoundation; with no Invariant Sections, no Front-Cover Texts, and noBack-Cover Texts. A copy of the license is included in the sectionentitled “GNU Free Documentation License.”
GNU m4
is an implementation of the traditional UNIX macroprocessor. It is mostly SVR4 compatible, although it has someextensions (for example, handling more than 9 positional parametersto macros).m4
also has builtin functions for includingfiles, running shell commands, doing arithmetic, etc. Autoconf needsGNUm4
for generating configure scripts, but not forrunning them.
GNU m4
was originally written by René Seindal, withsubsequent changes by François Pinard and other volunteerson the Internet. All names and email addresses can be found in thefilesm4-1.4.16/AUTHORS andm4-1.4.16/THANKS from the GNU M4distribution.
This is release 1.4.16. It is now considered stable: futurereleases in the 1.4.x series are only meant to fix bugs, increase speed,or improve documentation. However...
An experimental feature, which would improve m4
usefulness,allows for changing the syntax for what is aword in m4
. You should use:
./configure --enable-changeword
if you want this feature compiled in. The current implementationslows downm4
considerably and is hardly acceptable. In thefuture, m4
2.0 will come with a different set of new featuresthat provide similar capabilities, but without the inefficiencies, sochangeword will go away andyou should not count on it.
--- The Detailed Node Listing ---
Introduction and preliminaries
Invoking m4
Lexical and syntactic conventions
How to invoke macros
How to define new macros
Conditionals, loops, and recursion
How to debug macros and input
Input control
File inclusion
Diverting and undiverting output
Macros for text handling
Macros for doing arithmetic
Macros for running shell commands
Miscellaneous builtin macros
Fast loading of frozen state
Compatibility with other versions of m4
Correct version of some examples
How to make copies of the overall M4 package
How to make copies of this manual
Indices of concepts and macros
1 Introduction and preliminaries
This first chapter explains what GNU m4
is, where m4
comes from, how to read and use this documentation, how to call them4
program, and how to report bugs about it. It concludes bygiving tips for reading the remainder of the manual.
The following chapters then detail all the features of the m4
language.
1.1 Introduction to m4
m4
is a macro processor, in the sense that it copies itsinput to the output, expanding macros as it goes. Macros are eitherbuiltin or user-defined, and can take any number of arguments. Besides just doing macro expansion, m4
has builtin functionsfor including named files, running shell commands, doing integerarithmetic, manipulating text in various ways, performing recursion,etc....m4
can be used either as a front-end to a compiler,or as a macro processor in its own right.
The m4
macro processor is widely available on all UNIXes, and hasbeen standardized by POSIX. Usually, only a small percentage of users are aware of its existence. However, those who find it often become committed users. Thepopularity of GNU Autoconf, which requires GNUm4
for generating configure scripts, is an incentivefor many to install it, while these people will not themselvesprogram inm4
. GNU m4
is mostly compatible with theSystem V, Release 3 version, except for some minor differences. SeeCompatibility, for more details.
Some people find m4
to be fairly addictive. They first usem4
for simple problems, then take bigger and bigger challenges,learning how to write complex sets ofm4
macros along the way. Once really addicted, users pursue writing of sophisticatedm4
applications even to solve simple problems, devoting more timedebugging theirm4
scripts than doing real work. Beware thatm4
may be dangerous for the health of compulsive programmers.
1.2 Historical references
GPM
was an important ancestor ofm4
. SeeC. Strachey: “A General Purpose Macro generator”, Computer Journal8,3 (1965), pp. 225 ff.GPM
is also succinctly described intoDavid Gries classic “Compiler Construction for Digital Computers”.
The classic B. Kernighan and P.J. Plauger: “Software Tools”,Addison-Wesley, Inc. (1976) describes and implements a Unixmacro-processor language, which inspired Dennis Ritchie to writem3
, a macro processor for the AP-3 minicomputer.
Kernighan and Ritchie then joined forces to develop the originalm4
, as described in “The M4 Macro Processor”, BellLaboratories (1977). It had only 21 builtin macros.
While GPM
was more pure, m4
is meant to deal withthe true intricacies of real life: macros can be recognized withoutbeing pre-announced, skipping whitespace or end-of-lines is easier,more constructs are builtin instead of derived, etc.
Originally, the Kernighan and Plauger macro-processor, and thenm3
, formed the engine for the Rational FORTRAN preprocessor,that is, theRatfor
equivalent of cpp
. Later, m4
was used as a front-end forRatfor
, C
and Cobol
.
René Seindal released his implementation of m4
, GNUm4
,in 1990, with the aim of removing the artificial limitations in manyof the traditionalm4
implementations, such as maximum linelength, macro size, or number of macros.
The late Professor A. Dain Samples described and implemented a furtherevolution in the form ofM5
: “User's Guide to the M5 MacroLanguage: 2nd edition”, Electronic Announcement on comp.compilersnewsgroup (1992).
François Pinard took over maintenance of GNU m4
in1992, until 1994 when he released GNUm4
1.4, which wasthe stable release for 10 years. It was at this time that GNUAutoconf decided to require GNUm4
as its underlyingengine, since all other implementations of m4
had too manylimitations.
More recently, in 2004, Paul Eggert released 1.4.1 and 1.4.2 whichaddressed some long standing bugs in the venerable 1.4 release. Then in2005, Gary V. Vaughan collected together the many patches toGNUm4
1.4 that were floating around the net andreleased 1.4.3 and 1.4.4. And in 2006, Eric Blake joined the team andprepared patches for the release of 1.4.5, 1.4.6, 1.4.7, and 1.4.8. More bug fixes were incorporated in 2007, with releases 1.4.9 and1.4.10. Eric continued with some portability fixes for 1.4.11 and1.4.12 in 2008, 1.4.13 in 2009, 1.4.14 and 1.4.15 in 2010, and 1.4.16 in2011.
Meanwhile, development has continued on new features for m4
, suchas dynamic module loading and additional builtins. When complete,GNUm4
2.0 will start a new series of releases.
1.3 Problems and bugs
If you have problems with GNU M4 or think you've found a bug,please report it. Before reporting a bug, make sure you've actuallyfound a real bug. Carefully reread the documentation and see if itreally says you can do what you're trying to do. If it's not clearwhether you should be able to do something or not, report that too; it'sa bug in the documentation!
Before reporting a bug or trying to fix it yourself, try to isolate itto the smallest possible input file that reproduces the problem. Thensend us the input file and the exact resultsm4
gave you. Alsosay what you expected to occur; this will help us decide whether theproblem was really in the documentation.
Once you've got a precise problem, send e-mail tobug-m4@gnu.org. Please include the version number ofm4
you are using. You can get this information with the commandm4 --version. Also provide details about the platform you areexecuting on.
Non-bug suggestions are always welcome as well. If you have questionsabout things that are unclear in the documentation or are just obscurefeatures, please report them too.
1.4 Using this manual
This manual contains a number of examples ofm4
input and output,and a simple notation is used to distinguish input, output and errormessages fromm4
. Examples are set out from the normal text, andshown in a fixed width font, like this
This is an example of an example!
To distinguish input from output, all output from m4
is prefixedby the string ‘⇒’, and all error messages by the string‘error-->’. When showing how command line options affect matters,the command line is shown with a prompt ‘$like this’,otherwise, you can assume that a simple m4 invocation will work. Thus:
$ command line to invoke m4 Example of input line ⇒Output line from m4 error-->and an error message
The sequence ‘^D’ in an example indicates the end of the inputfile. The sequence ‘<NL>’ refers to the newline character. The majority of these examples are self-contained, and you can run themwith similar results by invoking m4 -d. In fact, the testsuitethat is bundled in the GNU M4 package consists of the examplesin this document! Some of the examples assume that your currentdirectory is located where you unpacked the installation, so if you planon following along, you may find it helpful to do this now:
$ cd m4-1.4.16
As each of the predefined macros in m4
is described, a prototypecall of the macro will be shown, giving descriptive names to thearguments, e.g.,
This is a sample prototype. There is not really a macro named
example
, but this documents that if there were, it would be aComposite macro, rather than a Builtin. It requires at least oneargument,string. Remember that inm4
, there must not be aspace between the macro name and the opening parenthesis, unless it wasintended to call the macro without any arguments. The brackets aroundcount andargument show that these arguments are optional. If count is omitted, the macro behaves as if count were ‘1’,whereas ifargument is omitted, the macro behaves as if it werethe empty string. A blank argument is not the same as an omittedargument. For example, ‘example(`a')’, ‘example(`a',`1')’,and ‘example(`a',`1',)’ would behave identically withcountset to ‘1’; while ‘example(`a',)’ and ‘example(`a',`')’would explicitly pass the empty string forcount. The ellipses(‘...’) show that the macro processes additional argumentsafterargument, rather than ignoring them.
All macro arguments in m4
are strings, but some are givenspecial interpretation, e.g., as numbers, file names, regularexpressions, etc. The documentation for each macro will state how theparameters are interpreted, and what happens if the argument cannot beparsed according to the desired interpretation. Unless specifiedotherwise, a parameter specified to be a number is parsed as a decimal,even if the argument has leading zeros; and parsing the empty string asa number results in 0 rather than an error, although a warning will beissued.
This document consistently writes and uses builtin, without ahyphen, as if it were an English word. This is how thebuiltin
primitive is spelled within m4
.
2 Invoking m4
The format of them4
command is:
m4
[option...] [file...]
All options begin with ‘-’, or if long option names are used, with‘--’. A long option name need not be written completely, anyunambiguous prefix is sufficient. POSIX requiresm4
torecognize arguments intermixed with files, even whenPOSIXLY_CORRECT is set in the environment. Most options takeeffect at startup regardless of their position, but some are documentedbelow as taking effect after any files that occurred earlier in thecommand line. The argument -- is a marker to denote the end ofoptions.
With short options, options that do not take arguments may be combinedinto a single command line argument with subsequent options, optionswith mandatory arguments may be provided either as a single command lineargument or as two arguments, and options with optional arguments mustbe provided as a single argument. In other words,m4 -QPDfoo -d a -df is equivalent tom4 -Q -P -D foo -d -df -- ./a, although the latter form isconsidered canonical.
With long options, options with mandatory arguments may be provided withan equal sign (‘=’) in a single argument, or as two arguments, andoptions with optional arguments must be provided as a single argument. In other words, m4 --def foo --debug a is equivalent tom4 --define=foo --debug= -- ./a, although the latter form isconsidered canonical (not to mention more robust, in case a futureversion ofm4
introduces an option named --default).
m4
understands the following options, grouped by functionality.
2.1 Command line options for operation modes
Several options control the overall operation of m4
:
-
Print a help summary on standard output, then immediately exit
m4
without reading any input files or performing any otheractions.
-
Print the version number of the program on standard output, thenimmediately exit
m4
without reading any input files orperforming any other actions.
-
Controls the effect of warnings. If unspecified, then executioncontinues and exit status is unaffected when a warning is printed. Ifspecified exactly once, warnings become fatal; when one is issued,execution continues, but the exit status will be non-zero. If specifiedmultiple times, then execution halts with non-zero status the first timea warning is issued. The introduction of behavior levels is new to M41.4.9; for behavior consistent with earlier versions, you should specify
-E twice.
-
Makes this invocation of
m4
interactive. This means that alloutput will be unbuffered, and interrupts will be ignored. Thespelling -e exists for compatibility with otherm4
implementations, and issues a warning because it may be withdrawn in afuture version of GNU M4.
-
Internally modify
all builtin macro names so they all start withthe prefix ‘
m4_’. For example, using this option, one should write‘
m4_define’ instead of ‘
define’, and ‘
m4___file__’instead of ‘
__file__’. This option has no effect if
-Ris also specified.
-
Suppress warnings, such as missing or superfluous arguments in macrocalls, or treating the empty string as zero.
-
Issue a warning if the regular expression
regexp has a non-emptymatch in any macro definition (either by
define
orpushdef
). Empty matches are ignored; therefore, supplying theempty string as regexp disables any warning. If the optional regexp is not supplied, then the default regular expression is‘ \$\({[^}]*}\|[0-9][0-9]+\)’ (a literal ‘ $’ followed bymultiple digits or by an open brace), since these sequences willchange semantics in the default operation of GNU M4 2.0 (dueto a change in how more than 9 arguments in a macro definition will behandled, see Arguments). Providing an alternate regularexpression can provide a useful reverse lookup feature of findingwhere a macro is defined to have a given definition.
-
Use
regexp as an alternative syntax for macro names. Thisexperimental option will not be present in all GNU
m4
implementations (see Changeword).
--help
--version
-E
--fatal-warnings
-i
--interactive
-e
-P
--prefix-builtins
-Q
--quiet
--silent
--warn-macro-sequence
[
=
regexp
]
-W
regexp
--word-regexp=
regexp
2.2 Command line options for preprocessor features
Several options allowm4
to behave more like a preprocessor. Macro definitions and deletions can be made on the command line, thesearch path can be altered, and the output file can track where theinput came from. These features occur with the following options:
-
This enters
name into the symbol table. If ‘
=value’ ismissing, the value is taken to be the empty string. The
value canbe any string, and the macro can be defined to take arguments, just asif it was defined from within the input. This option may be given morethan once; order with respect to file names is significant, andredefining the same
name loses the previous value.
-
Make
m4
search directory for included files that are notfound in the current working directory. See Search Path, for moredetails. This option may be given more than once.
-
Generate synchronization lines, for use by the C preprocessor or othersimilar tools. Order is significant with respect to file names. Thisoption is useful, for example, when
m4
is used as afront end to a compiler. Source file name and line number informationis conveyed by directives of the form ‘ #linelinenum"file"’, which are inserted as needed into the middle of theoutput. Such directives mean that the following line originated or wasexpanded from the contents of input file file at line linenum. The ‘ "file"’ part is often omitted whenthe file name did not change from the previous directive.Synchronization directives are always given on complete lines bythemselves. When a synchronization discrepancy occurs in the middle ofan output line, the associated synchronization directive is delayeduntil the next newline that does not occur in the middle of a quotedstring or comment.
define(`twoline', `1 2') ⇒#line 2 "stdin" ⇒ changecom(`/*', `*/') ⇒ define(`comment', `/*1 2*/') ⇒#line 5 ⇒ dnl no line hello ⇒#line 7 ⇒hello twoline ⇒1 ⇒#line 8 ⇒2 comment ⇒/*1 ⇒2*/ one comment `two three' ⇒#line 10 ⇒one /*1 ⇒2*/ two ⇒three goodbye ⇒#line 12 ⇒goodbye
- This deletes any predefined meaning name might have. Obviously,only predefined macros can be deleted in this way. This option may begiven more than once; undefining a name that does not have adefinition is silently ignored. Order is significant with respect tofile names.
-D
name
[
=
value
]
--define=
name
[
=
value
]
-I
directory
--include=
directory
-s
--synclines
-U
name
--undefine=
name
2.3 Command line options for limits control
There are some limits within m4
that can be tuned. Forcompatibility,m4
also accepts some options that control limitsin other implementations, but which are automatically unbounded (limitedonly by your hardware and operating system constraints) in GNUm4
.
-
Enable all the extensions in this implementation. In this release ofM4, this option is always on by default; it is currently only usefulwhen overriding a prior use of
--traditional. However, havingGNU behavior as default makes it impossible to write astrictly POSIX-compliant client that avoids all incompatibleGNU M4 extensions, since such a client would have to use thenon-POSIX command-line option to force full POSIXbehavior. Thus, a future version of M4 will be changed to implicitlyuse the option
--traditional if the environment variable
POSIXLY_CORRECT is set. Projects that intentionally useGNU extensions should consider using
--gnu to statetheir intentions, so that the project will not mysteriously break if theuser upgrades to a newer M4 and has
POSIXLY_CORRECT set in theirenvironment.
-
Suppress all the extensions made in this implementation, compared to theSystem V version. See
Compatibility, for a list of these.
-
Make the internal hash table for symbol lookup be
num entries big. For better performance, the number should be prime, but this is notchecked. The default is 509 entries. It should not be necessary toincrease this value, unless you define an excessive number of macros.
-
Artificially limit the nesting of macro calls to
num levels,stopping program execution if this limit is ever exceeded. When notspecified, nesting defaults to unlimited on platforms that can detectstack overflow, and to 1024 levels otherwise. A value of zero meansunlimited; but then heavily nested code could potentially cause a stackoverflow.
The precise effect of this option is more correctly associatedwith textual nesting than dynamic recursion. It has been usefulwhen some complex
m4
input was generated by mechanical means, andalso in diagnosing recursive algorithms that do not scale well. Most users never need to change this option from its default.This option does not have the ability to break endlessrescanning loops, since these do not necessarily consume much memoryor stack space. Through clever usage of rescanning loops, one canrequest complex, time-consuming computations from
m4
with usefulresults. Putting limitations in this area would breakm4
power. There are many pathological cases: ‘define(`a', `a')a’ isonly the simplest example (but seeCompatibility). Expecting GNUm4
to detect these would be a little like expecting a compilersystem to detect and diagnose endless loops: it is a quitehardproblem in general, if not undecidable!
-
These options are present for compatibility with System V
m4
, butdo nothing in this implementation. They may disappear in futurereleases, and issue a warning to that effect.
-
These options are present only for compatibility with previousversions of GNU
m4
, and were controlling the number ofpossible diversions which could be used at the same time. They do nothing,because there is no fixed limit anymore. They may disappear in futurereleases, and issue a warning to that effect.
-g
--gnu
-G
--traditional
-H
num
--hashsize=
num
-L
num
--nesting-limit=
num
-B
num
-S
num
-T
num
-N
num
--diversions=
num
2.4 Command line options for frozen state
GNU m4
comes with a feature of freezing internal state(see Frozen files). This can be used to speed up m4
execution when reusing a common initialization script.
-
Once execution is finished, write out the frozen state on the specified
file. It is conventional, but not required, for
file to endin ‘
.m4f’.
- Before execution starts, recover the internal state from the specifiedfrozen file. The options -D, -U, and -t take effect after state is reloaded, but before the inputfiles are read.
-F
file
--freeze-state=
file
-R
file
--reload-state=
file
2.5 Command line options for debugging
Finally, there are several options for aiding in debugging m4
scripts.
-
Set the debug-level according to the flags
flags. The debug-levelcontrols the format and amount of information presented by the debuggingfunctions. See
Debug Levels, for more details on the format andmeaning of
flags. If omitted,
flags defaults to ‘
aeq’.
-
Redirect
dumpdef
output, debug messages, and trace output to thenamed file. Warnings, error messages, anderrprint
outputare still printed to standard error. If these options are not used, orif file is unspecified (only possible for --debugfile),debug output goes to standard error; if file is the empty string,debug output is discarded. See Debug Output, for more details. Theoption --debugfile may be given more than once, and order issignificant with respect to file names. The spellings -o and --error-output are misleading and inconsistent with otherGNU tools; for now they are silently accepted as synonyms of --debugfile and only recognized once, but in a future versionof M4, using them will cause a warning to be issued.
-
Restrict the size of the output generated by macro tracing to
numcharacters per trace line. If unspecified or zero, output isunlimited. See
Debug Levels, for more details.
- This enables tracing for the macro name, at any point where it isdefined. name need not be defined when this option is given. This option may be given more than once, and order is significant withrespect to file names. See Trace, for more details.
-d
[
flags
]
--debug
[
=
flags
]
--debugfile
[
=
file
]
-o
file
--error-output=
file
-l
num
--arglength=
num
-t
name
--trace=
name
2.6 Specifying input files on the command line
The remaining arguments on the command line are taken to be input filenames. If no names are present, standard input is read. A filename of - is taken to mean standard input. It isconventional, but not required, for input files to end in ‘.m4’.
The input files are read in the sequence given. Standard input can beread more than once, so the file name- may appear multiple timeson the command line; this makes a difference when input is from aterminal or other special file type. It is an error if an input fileends in the middle of argument collection, a comment, or a quotedstring.
The options --define (-D),--undefine(-U),--synclines (-s), and--trace(-t) only take effect after processing input from any filenames that occur earlier on the command line. For example, assume thefilefoo contains:
$ cat foo bar
The text ‘bar’ can then be redefined over multiple uses offoo:
$ m4 -Dbar=hello foo -Dbar=world foo ⇒hello ⇒world
If none of the input files invoked m4exit
(see M4exit), theexit status of m4
will be 0 for success, 1 for general failure(such as problems with reading an input file), and 63 for versionmismatch (seeUsing frozen files).
If you need to read a file whose name starts with a -, you canspecify it as ‘./-file’, or use-- to mark the end ofoptions.
3 Lexical and syntactic conventions
As m4
reads its input, it separates it intotokens. Atoken is either a name, a quoted string, or any single character, thatis not a part of either a name or a string. Input tom4
can alsocontain comments. GNU m4
does not yet understandmultibyte locales; all operations are byte-oriented rather thancharacter-oriented (although if your locale uses a single byteencoding, such asISO-8859-1, you will not notice a difference). However, m4
is eight-bit clean, so you canuse non-ascii characters in quoted strings (seeChangequote),comments (see Changecom), and macro names (seeIndir), with theexception of the nul character (the zero byte ‘'\0'’).
3.1 Macro names
A name is any sequence of letters, digits, and the character ‘_’(underscore), where the first character is not a digit.m4
willuse the longest such sequence found in the input. If a name has amacro definition, it will be subject to macro expansion(seeMacros). Names are case-sensitive.
Examples of legal names are: ‘foo’, ‘_tmp’, and ‘name01’.
3.2 Quoting input to m4
A quoted string is a sequence of characters surrounded by quotestrings, defaulting to‘`’ and ‘'’, where the nested begin and end quotes within thestring are balanced. The value of a string token is the text, with onelevel of quotes stripped off. Thus
`' ⇒
is the empty string, and double-quoting turns into single-quoting.
``quoted'' ⇒`quoted'
The quote characters can be changed at any time, using the builtin macrochangequote
. SeeChangequote, for more information.
3.3 Comments in m4
input
Comments in m4
are normally delimited by the characters ‘#’and newline. All characters between the comment delimiters are ignored,but the entire comment (including the delimiters) is passed through tothe output—comments are not discarded by m4
.
Comments cannot be nested, so the first newline after a ‘#’ endsthe comment. The commenting effect of the begin-comment stringcan be inhibited by quoting it.
$ m4 `quoted text' # `commented text' ⇒quoted text # `commented text' `quoting inhibits' `#' `comments' ⇒quoting inhibits # comments
The comment delimiters can be changed to any string at any time, usingthe builtin macrochangecom
. See Changecom, for moreinformation.
3.4 Other kinds of input tokens
Any character, that is neither a part of a name, nor of a quoted string,nor a comment, is a token by itself. When not in the context of macroexpansion, all of these tokens are just copied to output. However,during macro expansion, whitespace characters (space, tab, newline,formfeed, carriage return, vertical tab), parentheses (‘(’ and‘)’), comma (‘,’), and dollar (‘$’) have additionalroles, explained later.
3.5 How m4
copies input to output
As m4
reads the input token by token, it will copy each tokendirectly to the output immediately.
The exception is when it finds a word with a macro definition. In thatcase m4
will calculate the macro's expansion, possibly readingmore input to get the arguments. It then inserts the expansion in frontof the remaining input. In other words, the resulting text from a macrocall will be read and parsed into tokens again.
m4
expands a macro as soon as possible. If it finds a macro callwhen collecting the arguments to another, it will expand the second callfirst. This process continues until there are no more macro calls toexpand and all the input has been consumed.
For a running example, examine how m4
handles this input:
format(`Result is %d', eval(`2**15'))
First, m4
sees that the token ‘format’ is a macro name, soit collects the tokens ‘(’, ‘`Result is %d'’, ‘,’,and ‘ ’, before encountering another potential macro. Sureenough, ‘eval’ is a macro name, so the nested argument collectionpicks up ‘(’, ‘`2**15'’, and ‘)’, invoking the eval macrowith the lone argument of ‘2**15’. The expansion of‘eval(2**15)’ is ‘32768’, which is then rescanned as the fivetokens ‘3’, ‘2’, ‘7’, ‘6’, and ‘8’; andcombined with the next ‘)’, the format macro now has all itsarguments, as if the user had typed:
format(`Result is %d', 32768)
The format macro expands to ‘Result is 32768’, and we have anotherround of scanning for the tokens ‘Result’, ‘ ’,‘is’, ‘ ’, ‘3’, ‘2’, ‘7’, ‘6’, and‘8’. None of these are macros, so the final output is
⇒Result is 32768
As a more complicated example, we will contrast an actual codeexample from the Gnulib project1,showing both a buggy approach and the desired results. The user desiresto output a shell assignment statement that takes its argument and turnsit into a shell variable by converting it to uppercase and prepending aprefix. The original attempt looks like this:
changequote([,])dnl define([gl_STRING_MODULE_INDICATOR], [ dnl comment GNULIB_]translit([$1],[a-z],[A-Z])[=1 ])dnl gl_STRING_MODULE_INDICATOR([strcase]) ⇒ ⇒ GNULIB_strcase=1 ⇒
Oops – the argument did not get capitalized. And although the manualis not able to easily show it, both lines that appear empty actuallycontain two trailing spaces. By stepping through the parse, it is easyto see what happened. First,m4
sees the token‘changequote’, which it recognizes as a macro, followed by‘(’, ‘[’, ‘,’, ‘]’, and ‘)’ to form theargument list. The macro expands to the empty string, but changes thequoting characters to something more useful for generating shell code(unbalanced ‘`’ and ‘'’ appear all the time in shell scripts,but unbalanced ‘[]’ tend to be rare). Also in the first line,m4
sees the token ‘dnl’, which it recognizes as a builtinmacro that consumes the rest of the line, resulting in no output forthat line.
The second line starts a macro definition. m4
sees the token‘define’, which it recognizes as a macro, followed by a ‘(’,‘[gl_STRING_MODULE_INDICATOR]’, and ‘,’. Because an unquotedcomma was encountered, the first argument is known to be the expansionof the single-quoted string token, or ‘gl_STRING_MODULE_INDICATOR’. Next,m4
sees ‘<NL>’, ‘ ’, and ‘ ’, but thiswhitespace is discarded as part of argument collection. Then comes arather lengthy single-quoted string token, ‘[<NL> dnlcomment<NL> GNULIB_]’. This is followed by the token‘translit’, which m4
recognizes as a macro name, so a nestedmacro expansion has started.
The arguments to the translit
are found by the tokens ‘(’,‘[$1]’, ‘,’, ‘[a-z]’, ‘,’, ‘[A-Z]’, and finally‘)’. All three string arguments are expanded (or in other words,the quotes are stripped), and since neither ‘$’ nor ‘1’ needcapitalization, the result of the macro is ‘$1’. This expansion isrescanned, resulting in the two literal characters ‘$’ and‘1’.
Scanning of the outer macro resumes, and picks up with‘[=1<NL> ]’, and finally ‘)’. The collected pieces ofexpanded text are concatenated, with the end result that the macro‘gl_STRING_MODULE_INDICATOR’ is now defined to be the sequence‘<NL> dnl comment<NL> GNULIB_$1=1<NL>’. Once again, ‘dnl’ is recognized and avoids a newline in the output.
The final line is then parsed, beginning with ‘ ’ and ‘ ’that are output literally. Then ‘gl_STRING_MODULE_INDICATOR’ isrecognized as a macro name, with an argument list of ‘(’,‘[strcase]’, and ‘)’. Since the definition of the macrocontains the sequence ‘$1’, that sequence is replaced with theargument ‘strcase’ prior to starting the rescan. The rescan sees‘<NL>’ and four spaces, which are output literally, then‘dnl’, which discards the text ‘ comment<NL>’. Nextcomes four more spaces, also output literally, and the token‘GNULIB_strcase’, which resulted from the earlier parametersubstitution. Since that is not a macro name, it is output literally,followed by the literal tokens ‘=’, ‘1’, ‘<NL>’, andtwo more spaces. Finally, the original ‘<NL>’ seen after themacro invocation is scanned and output literally.
Now for a corrected approach. This rearranges the use of newlines andwhitespace so that less whitespace is output (which, although harmlessto shell scripts, can be visually unappealing), and fixes the quotingissues so that the capitalization occurs when the macro‘gl_STRING_MODULE_INDICATOR’ is invoked, rather then when it isdefined. It also adds another layer of quoting to the first argument oftranslit
, to ensure that the output will be rescanned as a stringrather than a potential uppercase macro name needing further expansion.
changequote([,])dnl define([gl_STRING_MODULE_INDICATOR], [dnl comment GNULIB_[]translit([[$1]], [a-z], [A-Z])=1dnl ])dnl gl_STRING_MODULE_INDICATOR([strcase]) ⇒ GNULIB_STRCASE=1
The parsing of the first line is unchanged. The second line sees thename of the macro to define, then sees the discarded ‘<NL>’and two spaces, as before. But this time, the next token is‘[dnl comment<NL> GNULIB_[]translit([[$1]], [a-z],[A-Z])=1dnl<NL>]’, which includes nested quotes, followed by‘)’ to end the macro definition and ‘dnl’ to skip thenewline. No early expansion of translit
occurs, so the entirestring becomes the definition of the macro.
The final line is then parsed, beginning with two spaces that areoutput literally, and an invocation ofgl_STRING_MODULE_INDICATOR
with the argument ‘strcase’. Again, the ‘$1’ in the macro definition is substituted prior torescanning. Rescanning first encounters ‘dnl’, and discards‘ comment<NL>’. Then two spaces are output literally. Nextcomes the token ‘GNULIB_’, but that is not a macro, so it isoutput literally. The token ‘[]’ is an empty string, so it doesnot affect output. Then the token ‘translit’ is encountered.
This time, the arguments to translit
are parsed as ‘(’,‘[[strcase]]’, ‘,’, ‘’, ‘[a-z]’, ‘,’, ‘’,‘[A-Z]’, and ‘)’. The two spaces are discarded, and thetranslit results in the desired result ‘[STRCASE]’. This isrescanned, but since it is a string, the quotes are stripped and theonly output is a literal ‘STRCASE’. Then the scanner sees ‘=’ and ‘1’, which are outputliterally, followed by ‘dnl’ which discards the rest of thedefinition ofgl_STRING_MODULE_INDICATOR
. The newline at theend of output is the literal ‘<NL>’ that appeared after theinvocation of the macro.
The order in which m4
expands the macros can be further exploredusing the trace facilities of GNUm4
(see Trace).
4 How to invoke macros
This chapter covers macro invocation, macro arguments and how macroexpansion is treated.
4.1 Macro invocation
Macro invocations has one of the forms
name
which is a macro invocation without any arguments, or
name(arg1, arg2, ..., argn)
which is a macro invocation with n arguments. Macros can have anynumber of arguments. All arguments are strings, but different macrosmight interpret the arguments in different ways.
The opening parenthesis must follow the name directly, withno spaces in between. If it does not, the macro is called with noarguments at all.
For a macro call to have no arguments, the parentheses must beleft out. The macro call
name()
is a macro call with one argument, which is the empty string, not a callwith no arguments.
4.2 Preventing macro invocation
An innovation of the m4
language, compared to some of itspredecessors (like Strachey'sGPM
, for example), is the abilityto recognize macro calls without resorting to any special, prefixedinvocation character. While generally useful, this feature mightsometimes be the source of spurious, unwanted macro calls. So, GNUm4
offers several mechanisms or techniques for inhibiting therecognition of names as macro calls.
First of all, many builtin macros cannot meaningfully be called withoutarguments. As a GNU extension, for any of these macros,whenever an opening parenthesis does not immediately follow their name,the builtin macro call is not triggered. This solves the most usualcases, like for ‘include’ or ‘eval’. Later in this document,the sentence “This macro is recognized only with parameters” refers tothis specific provision of GNU M4, also known as a blindbuiltin macro. For the builtins defined by POSIX that bearthis disclaimer, POSIX specifically states that invoking thosebuiltins without arguments is unspecified, because many otherimplementations simply invoke the builtin as though it were given oneempty argument instead.
$ m4 eval ⇒eval eval(`1') ⇒1
There is also a command line option (--prefix-builtins, or-P, seeInvoking m4) that renames allbuiltin macros with a prefix of ‘m4_’ at startup. The option hasno effect whatsoever on user defined macros. For example, with this option,one has to writem4_dnl
and even m4_m4exit
. It also hasno effect on whether a macro requires parameters.
$ m4 -P eval ⇒eval eval(`1') ⇒eval(1) m4_eval ⇒m4_eval m4_eval(`1') ⇒1
Another alternative is to redefine problematic macros to a name lesslikely to cause conflicts, SeeDefinitions.
If your version of GNU m4
has the changeword
featurecompiled in, it offers far more flexibility in specifying thesyntax of macro names, both builtin or user-defined. SeeChangeword,for more information on this experimental feature.
Of course, the simplest way to prevent a name from being interpretedas a call to an existing macro is to quote it. The remainder ofthis section studies a little more deeply how quoting affects macroinvocation, and how quoting can be used to inhibit macro invocation.
Even if quoting is usually done over the whole macro name, it can alsobe done over only a few characters of this name (provided, of course,that the unquoted portions are not also a macro). It is also possibleto quote the empty string, but this works onlyinside the name. For example:
`divert' ⇒divert `d'ivert ⇒divert di`ver't ⇒divert div`'ert ⇒divert
all yield the string ‘divert’. While in both:
`'divert ⇒ divert`' ⇒
the divert
builtin macro will be called, which expands to theempty string.
The output of macro evaluations is always rescanned. In the followingexample, the input ‘x`'y’ yields the string ‘bCD’, exactly asifm4
has been given ‘substr(ab`'cde, `1', `3')’ as input:
define(`cde', `CDE') ⇒ define(`x', `substr(ab') ⇒ define(`y', `cde, `1', `3')') ⇒ x`'y ⇒bCD
Unquoted strings on either side of a quoted string are subject tobeing recognized as macro names. In the following example, quoting theempty string allows for the secondmacro
to be recognized as such:
define(`macro', `m') ⇒ macro(`m')macro ⇒mmacro macro(`m')`'macro ⇒mm
Quoting may prevent recognizing as a macro name the concatenation of amacro expansion with the surrounding characters. In this example:
define(`macro', `di$1') ⇒ macro(`v')`ert' ⇒divert macro(`v')ert ⇒
the input will produce the string ‘divert’. When the quotes wereremoved, thedivert
builtin was called instead.
4.3 Macro arguments
When a name is seen, and it has a macro definition, it will be expandedas a macro.
If the name is followed by an opening parenthesis, the arguments will becollected before the macro is called. If too few arguments aresupplied, the missing arguments are taken to be the empty string. However, some builtins are documented to behave differently for amissing optional argument than for an explicit empty string. If thereare too many arguments, the excess arguments are ignored. Unquotedleading whitespace is stripped off all arguments, but whitespacegenerated by a macro expansion or occurring after a macro that expandedto an empty string remains intact. Whitespace includes space, tab,newline, carriage return, vertical tab, and formfeed.
define(`macro', `$1') ⇒ macro( unquoted leading space lost) ⇒unquoted leading space lost macro(` quoted leading space kept') ⇒ quoted leading space kept macro( divert `unquoted space kept after expansion') ⇒ unquoted space kept after expansion macro(macro(` ')`whitespace from expansion kept') ⇒ ⇒whitespace from expansion kept macro(`unquoted trailing whitespace kept' ) ⇒unquoted trailing whitespace kept ⇒
Normallym4
will issue warnings if a builtin macro is calledwith an inappropriate number of arguments, but it can be suppressed withthe--quiet command line option (or --silent, or-Q, seeInvoking m4). For userdefined macros, there is no check of the number of arguments given.
$ m4 index(`abc') error-->m4:stdin:1: Warning: too few arguments to builtin `index' ⇒0 index(`abc',) ⇒0 index(`abc', `b', `ignored') error-->m4:stdin:3: Warning: excess arguments to builtin `index' ignored ⇒1
$ m4 -Q index(`abc') ⇒0 index(`abc',) ⇒0 index(`abc', `b', `ignored') ⇒1
Macros are expanded normally during argument collection, and whatevercommas, quotes and parentheses that might show up in the resultingexpanded text will serve to define the arguments as well. Thus, iffoo expands to ‘, b, c’, the macro call
bar(a foo, d)
is a macro call with four arguments, which are ‘a’, ‘b’,‘c’ and ‘d’. To understand why the first argument containswhitespace, remember that unquoted leading whitespace is never partof an argument, but trailing whitespace always is.
It is possible for a macro's definition to change during argumentcollection, in which case the expansion uses the definition that was ineffect at the time the opening ‘(’ was seen.
define(`f', `1') ⇒ f(define(`f', `2')) ⇒1 f ⇒2
It is an error if the end of file occurs while collecting arguments.
hello world ⇒hello world define( ^D error-->m4:stdin:2: ERROR: end of file in argument list
4.4 On Quoting Arguments to macros
Each argument has unquoted leading whitespace removed. Within eachargument, all unquoted parentheses must match. For example, iffoo is a macro,
foo(() (`(') `(')
is a macro call, with one argument, whose value is ‘() (() (’. Commas separate arguments, except when they occur inside quotes,comments, or unquoted parentheses. SeePseudo Arguments, forexamples.
It is common practice to quote all arguments to macros, unless you aresure you want the arguments expanded. Thus, in the aboveexample with the parentheses, the `right' way to do it is like this:
foo(`() (() (')
It is, however, in certain cases necessary (because nested expansionmust occur to create the arguments for the outer macro) or convenient(because it uses fewer characters) to leave out quotes for somearguments, and there is nothing wrong in doing it. It just makes life abit harder, if you are not careful to follow a consistent quoting style. For consistency, this manual follows the rule of thumb that each layerof parentheses introduces another layer of single quoting, except whenshowing the consequences of quoting rules. This is done even when thequoted string cannot be a macro, such as with integers when you have notchanged the syntax viachangeword
(see Changeword).
The quoting rule of thumb of one level of quoting per parentheses has anice property: when a macro name appears inside parentheses, you candetermine when it will be expanded. If it is not quoted, it will beexpanded prior to the outer macro, so that its expansion becomes theargument. If it is single-quoted, it will be expanded after the outermacro. And if it is double-quoted, it will be used as literal textinstead of a macro name.
define(`active', `ACT, IVE') ⇒ define(`show', `$1 $1') ⇒ show(active) ⇒ACT ACT show(`active') ⇒ACT, IVE ACT, IVE show(``active'') ⇒active active
4.5 Macro expansion
When the arguments, if any, to a macro call have been collected, themacro is expanded, and the expansion text is pushed back onto the input(unquoted), and reread. The expansion text from one macro call mighttherefore result in more macros being called, if the calls are included,completely or partially, in the first macro calls' expansion.
Taking a very simple example, if foo expands to ‘bar’, andbar expands to ‘Hello’, the input
$ m4 -Dbar=Hello -Dfoo=bar foo ⇒Hello
will expand first to ‘bar’, and when this is reread andexpanded, into ‘Hello’.
5 How to define new macros
Macros can be defined, redefined and deleted in several different ways. Also, it is possible to redefine a macro without losing a previousvalue, and bring back the original value at a later time.
5.1 Defining a macro
The normal way to define or redefine macros is to use the builtindefine
:
Defines name to expand to expansion. Ifexpansion is not given, it is taken to be empty.
The expansion of
define
is void. The macrodefine
is recognized only with parameters.
The following example defines the macro foo to expand to the text‘Hello World.’.
define(`foo', `Hello world.') ⇒ foo ⇒Hello world.
The empty line in the output is there because the newline is nota part of the macro definition, and it is consequently copied tothe output. This can be avoided by use of the macrodnl
. See Dnl, for details.
The first argument to define
should be quoted; otherwise, if themacro is already defined, you will be defining a different macro. Thisexample shows the problems with underquoting, since we did not want toredefineone
:
define(foo, one) ⇒ define(foo, two) ⇒ one ⇒two
GNU m4
normally replaces only thetopmostdefinition of a macro if it has several definitions from pushdef
(seePushdef). Some other implementations of m4
replace alldefinitions of a macro withdefine
. See Incompatibilities,for more details.
As a GNU extension, the first argument to define
doesnot have to be a simple word. It can be any text string, even the empty string. A macro with anon-standard name cannot be invoked in the normal way, as the name isnot recognized. It can only be referenced by the builtins indir
(see Indir) anddefn
(see Defn).
Arrays and associative arrays can be simulated by using non-standardmacro names.
— Composite: array_set ( index, [ value ])
Provide access to entries within an array.
array
reads the entryat locationindex, andarray_set
assigns value tolocation index.
define(`array', `defn(format(``array[%d]'', `$1'))') ⇒ define(`array_set', `define(format(``array[%d]'', `$1'), `$2')') ⇒ array_set(`4', `array element no. 4') ⇒ array_set(`17', `array element no. 17') ⇒ array(`4') ⇒array element no. 4 array(eval(`10 + 7')) ⇒array element no. 17
Change the ‘%d’ to ‘%s’ and it is an associative array.
5.2 Arguments to macros
Macros can have arguments. Thenth argument is denoted by$n
in the expansion text, and is replaced by thenth actualargument, when the macro is expanded. Replacement of arguments happensbefore rescanning, regardless of how many nesting levels of quotingappear in the expansion. Here is an example of a macro withtwo arguments.
Expands to arg2 followed by arg1, effectively exchangingtheir order.
define(`exch', `$2, $1') ⇒ exch(`arg1', `arg2') ⇒arg2, arg1
This can be used, for example, if you like the arguments todefine
to be reversed.
define(`exch', `$2, $1') ⇒ define(exch(``expansion text'', ``macro'')) ⇒ macro ⇒expansion text
See Quoting Arguments, for an explanation of the double quotes. (You should try and improve this example so that clients ofexch
do not have to double quote; or see Answers).
As a special case, the zeroth argument, $0
, is always the nameof the macro being expanded.
define(`test', ``Macro name: $0'') ⇒ test ⇒Macro name: test
If you want quoted text to appear as part of the expansion text,remember that quotes can be nested in quoted strings. Thus, in
define(`foo', `This is macro `foo'.') ⇒ foo ⇒This is macro foo.
The ‘foo’ in the expansion text isnot expanded, since it isa quoted string, and not a name.
GNUm4
allows the number following the ‘$’ toconsist of one or more digits, allowing macros to have any number ofarguments. The extension of accepting multiple digits is incompatiblewith POSIX, and is different than traditional implementationsof m4
, which only recognize one digit. Therefore, futureversions of GNU M4 will phase out this feature. To portablyaccess beyond the ninth argument, you can use theargn
macrodocumented later (see Shift).
POSIX also states that ‘$’ followed immediately by‘{’ in a macro definition is implementation-defined. This versionof M4 passes the literal characters ‘${’ through unchanged, but M42.0 will implement an optional feature similar to sh, where‘${11}’ expands to the eleventh argument, to replace the currentrecognition of ‘$11’. Meanwhile, if you want to guarantee that youwill get a literal ‘${’ in output when expanding a macro, evenwhen you upgrade to M4 2.0, you can use nested quoting to youradvantage:
define(`foo', `single quoted $`'{1} output') ⇒ define(`bar', ``double quoted $'`{2} output'') ⇒ foo(`a', `b') ⇒single quoted ${1} output bar(`a', `b') ⇒double quoted ${2} output
To help you detect places in your M4 input files that might change inbehavior due to the changed behavior of M4 2.0, you can use the--warn-macro-sequence command-line option (seeInvoking m4) with the default regular expression. This willadd a warning any time a macro definition includes ‘$’ followed bymultiple digits, or by ‘{’. The warning is not enabled bydefault, because it triggers a number of warnings in Autoconf 2.61 (andAutoconf uses-E to treat warnings as errors), and because itwill still be possible to restore older behavior in M4 2.0.
$ m4 --warn-macro-sequence define(`foo', `$001 ${1} $1') error-->m4:stdin:1: Warning: definition of `foo' contains sequence `$001' error-->m4:stdin:1: Warning: definition of `foo' contains sequence `${1}' ⇒ foo(`bar') ⇒bar ${1} bar
5.3 Special arguments to macros
There is a special notation for the number of actual arguments supplied,and for all the actual arguments.
The number of actual arguments in a macro call is denoted by $#
in the expansion text.
define(`nargs', `$#') ⇒ nargs ⇒0 nargs() ⇒1 nargs(`arg1', `arg2', `arg3') ⇒3 nargs(`commas can be quoted, like this') ⇒1 nargs(arg1#inside comments, commas do not separate arguments still arg1) ⇒1 nargs((unquoted parentheses, like this, group arguments)) ⇒1
Remember that ‘#’ defaults to the comment character; if you forgetquotes to inhibit the comment behavior, your macro definition may notend where you expected.
dnl Attempt to define a macro to just `$#' define(underquoted, $#) oops) ⇒ underquoted ⇒0) ⇒oops
The notation $*
can be used in the expansion text to denote allthe actual arguments, unquoted, with commas in between. For example
define(`echo', `$*') ⇒ echo(arg1, arg2, arg3 , arg4) ⇒arg1,arg2,arg3 ,arg4
Often each argument should be quoted, and the notation $@
handlesthat. It is just like$*
, except that it quotes each argument. A simple example of that is:
define(`echo', `$@') ⇒ echo(arg1, arg2, arg3 , arg4) ⇒arg1,arg2,arg3 ,arg4
Where did the quotes go? Of course, they were eaten, when the expandedtext were reread bym4
. To show the difference, try
define(`echo1', `$*') ⇒ define(`echo2', `$@') ⇒ define(`foo', `This is macro `foo'.') ⇒ echo1(foo) ⇒This is macro This is macro foo.. echo1(`foo') ⇒This is macro foo. echo2(foo) ⇒This is macro foo. echo2(`foo') ⇒foo
See Trace, if you do not understand this. As another example of thedifference, remember that comments encountered in arguments are passeduntouched to the macro, and that quoting disables comments.
define(`echo1', `$*') ⇒ define(`echo2', `$@') ⇒ define(`foo', `bar') ⇒ echo1(#foo'foo foo) ⇒#foo'foo ⇒bar echo2(#foo'foo foo) ⇒#foobar ⇒bar'
A ‘$’ sign in the expansion text, that is not followed by anythingm4
understands, is simply copied to the macro expansion, as anyother text is.
define(`foo', `$$$ hello $$$') ⇒ foo ⇒$$$ hello $$$
If you want a macro to expand to something like ‘$12’, thejudicious use of nested quoting can put a safe character between the$
and the next character, relying on the rescanning to remove thenested quote. This will preventm4
from interpreting the$
sign as a reference to an argument.
define(`foo', `no nested quote: $1') ⇒ foo(`arg') ⇒no nested quote: arg define(`foo', `nested quote around $: `$'1') ⇒ foo(`arg') ⇒nested quote around $: $1 define(`foo', `nested empty quote after $: $`'1') ⇒ foo(`arg') ⇒nested empty quote after $: $1 define(`foo', `nested quote around next character: $`1'') ⇒ foo(`arg') ⇒nested quote around next character: $1 define(`foo', `nested quote around both: `$1'') ⇒ foo(`arg') ⇒nested quote around both: arg
5.4 Deleting a macro
A macro definition can be removed withundefine
:
For each argument, remove the macro name. The macro names mustnecessarily be quoted, since they will be expanded otherwise.
The expansion of
undefine
is void. The macroundefine
is recognized only with parameters.
foo bar blah ⇒foo bar blah define(`foo', `some')define(`bar', `other')define(`blah', `text') ⇒ foo bar blah ⇒some other text undefine(`foo') ⇒ foo bar blah ⇒foo other text undefine(`bar', `blah') ⇒ foo bar blah ⇒foo bar blah
Undefining a macro inside that macro's expansion is safe; the macrostill expands to the definition that was in effect at the ‘(’.
define(`f', ``$0':$1') ⇒ f(f(f(undefine(`f')`hello world'))) ⇒f:f:f:hello world f(`bye') ⇒f(bye)
It is not an error for name to have no macro definition. In thatcase,undefine
does nothing.
5.5 Renaming macros
It is possible to rename an already defined macro. To do this, you needthe builtin defn
:
Expands to the quoted definition of each name. If anargument is not a defined macro, the expansion for that argument isempty.
If name is a user-defined macro, the quoted definition is simplythe quoted expansion text. If, instead, there is only onenameand it is a builtin, theexpansion is a special token, which points to the builtin's internaldefinition. This token is only meaningful as the second argument to
define
(andpushdef
), and is silently converted to anempty string in most other contexts. Combining a builtin with anythingelse is not supported; a warning is issued and the builtin is omittedfrom the final expansion.The macro
defn
is recognized only with parameters.
Its normal use is best understood through an example, which shows how torenameundefine
to zap
:
define(`zap', defn(`undefine')) ⇒ zap(`undefine') ⇒ undefine(`zap') ⇒undefine(zap)
In this way, defn
can be used to copy macro definitions, and alsodefinitions of builtin macros. Even if the original macro is removed,the other name can still be used to access the definition.
The fact that macro definitions can be transferred also explains why youshould use$0
, rather than retyping a macro's name in itsdefinition:
define(`foo', `This is `$0'') ⇒ define(`bar', defn(`foo')) ⇒ bar ⇒This is bar
Macros used as string variables should be referred through defn
,to avoid unwanted expansion of the text:
define(`string', `The macro dnl is very useful ') ⇒ string ⇒The macro defn(`string') ⇒The macro dnl is very useful ⇒
However, it is important to remember that m4
rescanning is purelytextual. If an unbalanced end-quote string occurs in a macrodefinition, the rescan will see that embedded quote as the terminationof the quoted string, and the remainder of the macro's definition willbe rescanned unquoted. Thus it is a good idea to avoid unbalancedend-quotes in macro definitions or arguments to macros.
define(`foo', a'a) ⇒ define(`a', `A') ⇒ define(`echo', `$@') ⇒ foo ⇒A'A defn(`foo') ⇒aA' echo(foo) ⇒AA'
On the other hand, it is possible to exploit the fact that defn
can concatenate multiple macros prior to the rescanning phase, in orderto join the definitions of macros that, in isolation, have unbalancedquotes. This is particularly useful when one has used several macros toaccumulate text that M4 should rescan as a whole. In the example below,note how the use ofdefn
on l
in isolation opens a string,which is not closed until the next line; but used onl
andr
together results in nested quoting.
define(`l', `<[>')define(`r', `<]>') ⇒ changequote(`[', `]') ⇒ defn([l])defn([r]) ]) ⇒<[>]defn([r]) ⇒) defn([l], [r]) ⇒<[>][<]>
Usingdefn
to generate special tokens for builtin macros outsideof expected contexts can sometimes trigger warnings. But most of thetime, such tokens are silently converted to the empty string.
$ m4 -d defn(`defn') ⇒ define(defn(`divnum'), `cannot redefine a builtin token') error-->m4:stdin:2: Warning: define: invalid macro name ignored ⇒ divnum ⇒0 len(defn(`divnum')) ⇒0
Also note that defn
with multiple arguments can only join textmacros, not builtins, although a future version of GNU M4 maylift this restriction.
$ m4 -d define(`a', `A')define(`AA', `b') ⇒ traceon(`defn', `define') ⇒ defn(`a', `divnum', `a') error-->m4:stdin:3: Warning: cannot concatenate builtin `divnum' error-->m4trace: -1- defn(`a', `divnum', `a') -> ``A'`A'' ⇒AA define(`mydivnum', defn(`divnum', `divnum'))mydivnum error-->m4:stdin:4: Warning: cannot concatenate builtin `divnum' error-->m4:stdin:4: Warning: cannot concatenate builtin `divnum' error-->m4trace: -2- defn(`divnum', `divnum') error-->m4trace: -1- define(`mydivnum', `') ⇒ traceoff(`defn', `define') ⇒
5.6 Temporarily redefining macros
It is possible to redefine a macro temporarily, reverting to theprevious definition at a later time. This is done with the builtinspushdef
andpopdef
:
— Builtin: popdef ( name...)
Analogous to
define
andundefine
.These macros work in a stack-like fashion. A macro is temporarilyredefined with
pushdef
, which replaces an existing definition ofname, while saving the previous definition, before the new one isinstalled. If there is no previous definition,pushdef
behavesexactly likedefine
.If a macro has several definitions (of which only one is accessible),the topmost definition can be removed with
popdef
. If there isno previous definition,popdef
behaves likeundefine
.The expansion of both
pushdef
andpopdef
is void. The macrospushdef
andpopdef
are recognized only withparameters.
define(`foo', `Expansion one.') ⇒ foo ⇒Expansion one. pushdef(`foo', `Expansion two.') ⇒ foo ⇒Expansion two. pushdef(`foo', `Expansion three.') ⇒ pushdef(`foo', `Expansion four.') ⇒ popdef(`foo') ⇒ foo ⇒Expansion three. popdef(`foo', `foo') ⇒ foo ⇒Expansion one. popdef(`foo') ⇒ foo ⇒foo
If a macro with several definitions is redefined with define
, thetopmost definition isreplaced with the new definition. If it isremoved with undefine
,all the definitions are removed,and not only the topmost one. However, POSIX allows otherimplementations that treatdefine
as replacing an entire stackof definitions with a single new definition, so to be portable to otherimplementations, it may be worth explicitly usingpopdef
andpushdef
rather than relying on the GNU behavior ofdefine
.
define(`foo', `Expansion one.') ⇒ foo ⇒Expansion one. pushdef(`foo', `Expansion two.') ⇒ foo ⇒Expansion two. define(`foo', `Second expansion two.') ⇒ foo ⇒Second expansion two. undefine(`foo') ⇒ foo ⇒foo
Local variables within macros are made withpushdef
andpopdef
. At the start of the macro a new definition is pushed,within the macro it is manipulated and at the end it is popped,revealing the former definition.
It is possible to temporarily redefine a builtin with pushdef
and defn
.
5.7 Indirect call of macros
Any macro can be called indirectly withindir
:
Results in a call to the macro name, which is passed therest of the argumentsargs. If name is not defined, anerror message is printed, and the expansion is void.
The macro
indir
is recognized only with parameters.
This can be used to call macros with computed or “invalid”names (define
allows such names to be defined):
define(`$$internal$macro', `Internal macro (name `$0')') ⇒ $$internal$macro ⇒$$internal$macro indir(`$$internal$macro') ⇒Internal macro (name $$internal$macro)
The point is, here, that larger macro packages can have private macrosdefined, that will not be called by accident. They canonly becalled through the builtin indir
.
One other point to observe is that argument collection occurs beforeindir
invokesname, so if argument collection changes thevalue of name, that will be reflected in the final expansion. This is different than the behavior when invoking macros directly,where the definition that was in effect before argument collection isused.
$ m4 -d define(`f', `1') ⇒ f(define(`f', `2')) ⇒1 indir(`f', define(`f', `3')) ⇒3 indir(`f', undefine(`f')) error-->m4:stdin:4: undefined macro `f' ⇒
When handed the result of defn
(see Defn) as one of itsarguments,indir
defers to the invoked name for whether atoken representing a builtin is recognized or flattened to the emptystring.
$ m4 -d indir(defn(`defn'), `divnum') error-->m4:stdin:1: Warning: indir: invalid macro name ignored ⇒ indir(`define', defn(`defn'), `divnum') error-->m4:stdin:2: Warning: define: invalid macro name ignored ⇒ indir(`define', `foo', defn(`divnum')) ⇒ foo ⇒0 indir(`divert', defn(`foo')) error-->m4:stdin:5: empty string treated as 0 in builtin `divert' ⇒
5.8 Indirect call of builtins
Builtin macros can be called indirectly withbuiltin
:
Results in a call to the builtin name, which is passed therest of the argumentsargs. If name does not name abuiltin, an error message is printed, and the expansion is void.
The macro
builtin
is recognized only with parameters.
This can be used even if name has been given another definitionthat has covered the original, or been undefined so that no macromaps to the builtin.
pushdef(`define', `hidden') ⇒ undefine(`undefine') ⇒ define(`foo', `bar') ⇒hidden foo ⇒foo builtin(`define', `foo', defn(`divnum')) ⇒ foo ⇒0 builtin(`define', `foo', `BAR') ⇒ foo ⇒BAR undefine(`foo') ⇒undefine(foo) foo ⇒BAR builtin(`undefine', `foo') ⇒ foo ⇒foo
The name argument only matches the original name of the builtin,even when the--prefix-builtins option (or -P,seeInvoking m4) is in effect. This is differentfrom indir
, which only tracks current macro names.
$ m4 -P m4_builtin(`divnum') ⇒0 m4_builtin(`m4_divnum') error-->m4:stdin:2: undefined builtin `m4_divnum' ⇒ m4_indir(`divnum') error-->m4:stdin:3: undefined macro `divnum' ⇒ m4_indir(`m4_divnum') ⇒0
Note that indir
and builtin
can be used to invoke builtinswithout arguments, even when they normally require parameters to berecognized; but it will provoke a warning, and result in a void expansion.
builtin ⇒builtin builtin() error-->m4:stdin:2: undefined builtin `' ⇒ builtin(`builtin') error-->m4:stdin:3: Warning: too few arguments to builtin `builtin' ⇒ builtin(`builtin',) error-->m4:stdin:4: undefined builtin `' ⇒ builtin(`builtin', ``' ') error-->m4:stdin:5: undefined builtin ``' error-->' ⇒ indir(`index') error-->m4:stdin:7: Warning: too few arguments to builtin `index' ⇒
6 Conditionals, loops, and recursion
Macros, expanding to plain text, perhaps with arguments, are not quiteenough. We would like to have macros expand to different things, basedon decisions taken at run-time. For that, we need some kind of conditionals. Also, we would like to have some kind of loop construct, so we could dosomething a number of times, or while some condition is true.
6.1 Testing if a macro is defined
There are two different builtin conditionals inm4
. The first isifdef
:
If name is defined as a macro,
ifdef
expands tostring-1, otherwise tostring-2. If string-2 isomitted, it is taken to be the empty string (according to the normalrules).The macro
ifdef
is recognized only with parameters.
ifdef(`foo', ``foo' is defined', ``foo' is not defined') ⇒foo is not defined define(`foo', `') ⇒ ifdef(`foo', ``foo' is defined', ``foo' is not defined') ⇒foo is defined ifdef(`no_such_macro', `yes', `no', `extra argument') error-->m4:stdin:4: Warning: excess arguments to builtin `ifdef' ignored ⇒no
6.2 If-else construct, or multibranch
The other conditional,ifelse
, is much more powerful. It can beused as a way to introduce a long comment, as an if-else construct, oras a multibranch, depending on the number of arguments supplied:
— Builtin: ifelse ( string-1, string-2, equal, [ not-equal ])
— Builtin: ifelse ( string-1, string-2, equal-1, string-3, string-4, equal-2,..., [ not-equal ])
Used with only one argument, the
ifelse
simply discards it andproduces no output.If called with three or four arguments,
ifelse
expands intoequal, ifstring-1 and string-2 are equal (characterfor character), otherwise it expands tonot-equal. A final fifthargument is ignored, after triggering a warning.If called with six or more arguments, and string-1 andstring-2 are equal,
ifelse
expands into equal-1,otherwise the first three arguments are discarded and the processingstarts again.The macro
ifelse
is recognized only with parameters.
Using only one argument is a common m4
idiom for introducing ablock comment, as an alternative to repeatedly usingdnl
. Thisspecial usage is recognized by GNU m4
, so that in thiscase, the warning about missing arguments is never triggered.
ifelse(`some comments') ⇒ ifelse(`foo', `bar') error-->m4:stdin:2: Warning: too few arguments to builtin `ifelse' ⇒
Using three or four arguments provides decision points.
ifelse(`foo', `bar', `true') ⇒ ifelse(`foo', `foo', `true') ⇒true define(`foo', `bar') ⇒ ifelse(foo, `bar', `true', `false') ⇒true ifelse(foo, `foo', `true', `false') ⇒false
Notice how the first argument was used unquoted; it is common to comparethe expansion of a macro with a string. With this macro, you can nowreproduce the behavior of blind builtins, where the macro is recognizedonly with arguments.
define(`foo', `ifelse(`$#', `0', ``$0'', `arguments:$#')') ⇒ foo ⇒foo foo() ⇒arguments:1 foo(`a', `b', `c') ⇒arguments:3
For an example of a way to make defining blind macros easier, seeComposition.
The macroifelse
can take more than four arguments. If given morethan four arguments,ifelse
works like a case
or switch
statement in traditional programming languages. Ifstring-1 andstring-2 are equal, ifelse
expands intoequal-1, otherwisethe procedure is repeated with the first three arguments discarded. Thiscalls for an example:
ifelse(`foo', `bar', `third', `gnu', `gnats') error-->m4:stdin:1: Warning: excess arguments to builtin `ifelse' ignored ⇒gnu ifelse(`foo', `bar', `third', `gnu', `gnats', `sixth') ⇒ ifelse(`foo', `bar', `third', `gnu', `gnats', `sixth', `seventh') ⇒seventh ifelse(`foo', `bar', `3', `gnu', `gnats', `6', `7', `8') error-->m4:stdin:4: Warning: excess arguments to builtin `ifelse' ignored ⇒7
Naturally, the normal case will be slightly more advanced than theseexamples. A common use ofifelse
is in macros implementing loopsof various kinds.
6.3 Recursion in m4
There is no direct support for loops inm4
, but macros can berecursive. There is no limit on the number of recursion levels, otherthan those enforced by your hardware and operating system.
Loops can be programmed using recursion and the conditionals describedpreviously.
There is a builtin macro, shift
, which can, among other things,be used for iterating through the actual arguments to a macro:
Takes any number of arguments, and expands to all its arguments exceptarg1, separated by commas, with each argument quoted.
The macro
shift
is recognized only with parameters.
shift ⇒shift shift(`bar') ⇒ shift(`foo', `bar', `baz') ⇒bar,baz
An example of the use of shift
is this macro:
It is implemented as:
define(`reverse', `ifelse(`$#', `0', , `$#', `1', ``$1'', `reverse(shift($@)), `$1'')') ⇒ reverse ⇒ reverse(`foo') ⇒foo reverse(`foo', `bar', `gnats', `and gnus') ⇒and gnus, gnats, bar, foo
While not a very interesting macro, it does show how simple loops can bemade withshift
, ifelse
and recursion. It also showsthat shift
is usually used with ‘$@’. Another example ofthis is an implementation of a short-circuiting conditional operator.
Similar to
ifelse
, where an equal comparison between the firsttwo strings results in the third, otherwise the first three argumentsare discarded and the process repeats. The difference is that eachtest-<n> is expanded only when it is encountered. This means thatevery third argument tocond
is normally given one more level ofquoting than the corresponding argument toifelse
.
Here is the implementation of cond
, along with a demonstration ofhow it can short-circuit the side effects inside
. Notice howall the unquoted side effects happen regardless of how many comparisonsare made withifelse
, compared with only the relevant effectswith cond
.
define(`cond', `ifelse(`$#', `1', `$1', `ifelse($1, `$2', `$3', `$0(shift(shift(shift($@))))')')')dnl define(`side', `define(`counter', incr(counter))$1')dnl define(`example1', `define(`counter', `0')dnl ifelse(side(`$1'), `yes', `one comparison: ', side(`$1'), `no', `two comparisons: ', side(`$1'), `maybe', `three comparisons: ', `side(`default answer: ')')counter')dnl define(`example2', `define(`counter', `0')dnl cond(`side(`$1')', `yes', `one comparison: ', `side(`$1')', `no', `two comparisons: ', `side(`$1')', `maybe', `three comparisons: ', `side(`default answer: ')')counter')dnl example1(`yes') ⇒one comparison: 3 example1(`no') ⇒two comparisons: 3 example1(`maybe') ⇒three comparisons: 3 example1(`feeling rather indecisive today') ⇒default answer: 4 example2(`yes') ⇒one comparison: 1 example2(`no') ⇒two comparisons: 2 example2(`maybe') ⇒three comparisons: 3 example2(`feeling rather indecisive today') ⇒default answer: 4
Another common task that requires iteration is joining a list ofarguments into a single string.
— Composite: joinall ( [ separator ] , [ args... ])
Generate a single-quoted string, consisting of each arg separatedbyseparator. While
joinall
always outputs aseparator between arguments,join
avoids theseparator for an empty arg.
Here are some examples of its usage, based on the implementationm4-1.4.16/examples/join.m4 distributed in thispackage:
$ m4 -I examples include(`join.m4') ⇒ join,join(`-'),join(`-', `'),join(`-', `', `') ⇒,,, joinall,joinall(`-'),joinall(`-', `'),joinall(`-', `', `') ⇒,,,- join(`-', `1') ⇒1 join(`-', `1', `2', `3') ⇒1-2-3 join(`', `1', `2', `3') ⇒123 join(`-', `', `1', `', `', `2', `') ⇒1-2 joinall(`-', `', `1', `', `', `2', `') ⇒-1---2- join(`,', `1', `2', `3') ⇒1,2,3 define(`nargs', `$#')dnl nargs(join(`,', `1', `2', `3')) ⇒1
Examining the implementation shows some interesting points about severalm4 programming idioms.
$ m4 -I examples undivert(`join.m4')dnl ⇒divert(`-1') ⇒# join(sep, args) - join each non-empty ARG into a single ⇒# string, with each element separated by SEP ⇒define(`join', ⇒`ifelse(`$#', `2', ``$2'', ⇒ `ifelse(`$2', `', `', ``$2'_')$0(`$1', shift(shift($@)))')') ⇒define(`_join', ⇒`ifelse(`$#$2', `2', `', ⇒ `ifelse(`$2', `', `', ``$1$2'')$0(`$1', shift(shift($@)))')') ⇒# joinall(sep, args) - join each ARG, including empty ones, ⇒# into a single string, with each element separated by SEP ⇒define(`joinall', ``$2'_$0(`$1', shift($@))') ⇒define(`_joinall', ⇒`ifelse(`$#', `2', `', ``$1$3'$0(`$1', shift(shift($@)))')') ⇒divert`'dnl
First, notice that this implementation creates helper macros_join
and_joinall
. This division of labor makes iteasier to output the correct number ofseparator instances:join
and joinall
are responsible for the first argument,without a separator, while_join
and _joinall
areresponsible for all remaining arguments, always outputting a separatorwhen outputting an argument.
Next, observe how join
decides to iterate to itself, because thefirstarg was empty, or to output the argument and swap over to_join
. If the argument is non-empty, then the nestedifelse
results in an unquoted ‘_’, which is concatenatedwith the ‘$0’ to form the next macro name to invoke. Thejoinall
implementation is simpler since it does not have tosuppress emptyarg; it always executes once then defers to_joinall
.
Another important idiom is the idea that separator is reused foreach iteration. Each iteration has one less argument, but rather thandiscarding ‘$1’ by iterating with$0(shift($@))
, the macrodiscards ‘$2’ by using$0(`$1', shift(shift($@)))
.
Next, notice that it is possible to compare more than one condition in asingleifelse
test. The test of ‘$#$2’ against ‘2’allows_join
to iterate for two separate reasons—either thereare still more than two arguments, or there are exactly two argumentsbut the last argument is not empty.
Finally, notice that these macros require exactly two arguments toterminate recursion, but that they still correctly result in emptyoutput when given noargs (i.e., zero or one macro argument). Onthe first pass when there are too few arguments, theshift
results in no output, but leaves an empty string to serve as therequired second argument for the second pass. Put another way,‘`$1', shift($@)’ is not the same as ‘$@’, since only theformer guarantees at least two arguments.
Sometimes, a recursive algorithm requires adding quotes to each element,or treating multiple arguments as a single element:
— Composite: dquote ( ...)
— Composite: dquote_elt ( ...)
Takes any number of arguments, and adds quoting. With
quote
,only one level of quoting is added, effectively removing whitespaceafter commas and turning multiple arguments into a single string. Withdquote
, two levels of quoting are added, one around each element,and one around the list. And withdquote_elt
, two levels ofquoting are added around each element.
An actual implementation of these three macros is distributed asm4-1.4.16/examples/quote.m4 in this package. First,let's examine their usage:
$ m4 -I examples include(`quote.m4') ⇒ -quote-dquote-dquote_elt- ⇒---- -quote()-dquote()-dquote_elt()- ⇒--`'-`'- -quote(`1')-dquote(`1')-dquote_elt(`1')- ⇒-1-`1'-`1'- -quote(`1', `2')-dquote(`1', `2')-dquote_elt(`1', `2')- ⇒-1,2-`1',`2'-`1',`2'- define(`n', `$#')dnl -n(quote(`1', `2'))-n(dquote(`1', `2'))-n(dquote_elt(`1', `2'))- ⇒-1-1-2- dquote(dquote_elt(`1', `2')) ⇒``1'',``2'' dquote_elt(dquote(`1', `2')) ⇒``1',`2''
The last two lines show that when given two arguments, dquote
results in one string, whiledquote_elt
results in two. Now,examine the implementation. Note thatquote
anddquote_elt
make decisions based on their number of arguments, sothat when called without arguments, they result in nothing instead of aquoted empty string; this is so that it is possible to distinguishbetween no arguments and an empty first argument. dquote
, on theother hand, results in a string no matter what, since it is stillpossible to tell whether it was invoked without arguments based on theresulting string.
$ m4 -I examples undivert(`quote.m4')dnl ⇒divert(`-1') ⇒# quote(args) - convert args to single-quoted string ⇒define(`quote', `ifelse(`$#', `0', `', ``$*'')') ⇒# dquote(args) - convert args to quoted list of quoted strings ⇒define(`dquote', ``$@'') ⇒# dquote_elt(args) - convert args to list of double-quoted strings ⇒define(`dquote_elt', `ifelse(`$#', `0', `', `$#', `1', ```$1''', ⇒ ```$1'',$0(shift($@))')') ⇒divert`'dnl
It is worth pointing out that ‘quote(args)’ is more efficientthan ‘joinall(`,',args)’ for producing the same output.
One more useful macro based onshift
allows portably selectingan arbitrary argument (usually greater than the ninth argument), withoutrelying on the GNU extension of multi-digit arguments(seeArguments).
Expands to argument n out of the remaining arguments. nmust be a positive number. Usually invoked as‘argn(`n',$@)’.
It is implemented as:
define(`argn', `ifelse(`$1', 1, ``$2'', `argn(decr(`$1'), shift(shift($@)))')') ⇒ argn(`1', `a') ⇒a define(`foo', `argn(`11', $@)') ⇒ foo(`a', `b', `c', `d', `e', `f', `g', `h', `i', `j', `k', `l') ⇒k
6.4 Iteration by counting
Here is an example of a loop macro that implements a simple for loop.
Takes the name in iterator, which must be a valid macro name, andsuccessively assign it each integer value fromstart to end,inclusive. For each assignment to iterator, appendtext tothe expansion of the
forloop
. text may refer toiterator. Any definition ofiterator prior to thisinvocation is restored.
It can, for example, be used for simple counting:
$ m4 -I examples include(`forloop.m4') ⇒ forloop(`i', `1', `8', `i ') ⇒1 2 3 4 5 6 7 8
For-loops can be nested, like:
$ m4 -I examples include(`forloop.m4') ⇒ forloop(`i', `1', `4', `forloop(`j', `1', `8', ` (i, j)') ') ⇒ (1, 1) (1, 2) (1, 3) (1, 4) (1, 5) (1, 6) (1, 7) (1, 8) ⇒ (2, 1) (2, 2) (2, 3) (2, 4) (2, 5) (2, 6) (2, 7) (2, 8) ⇒ (3, 1) (3, 2) (3, 3) (3, 4) (3, 5) (3, 6) (3, 7) (3, 8) ⇒ (4, 1) (4, 2) (4, 3) (4, 4) (4, 5) (4, 6) (4, 7) (4, 8) ⇒
The implementation of the forloop
macro is fairlystraightforward. Theforloop
macro itself is simply a wrapper,which saves the previous definition of the first argument, calls theinternal macro_forloop
, and re-establishes the saveddefinition of the first argument.
The macro _forloop
expands the fourth argument once, andtests to see if the iterator has reached the final value. If it hasnot finished, it increments the iterator (using the predefined macroincr
, seeIncr), and recurses.
Here is an actual implementation of forloop
, distributed asm4-1.4.16/examples/forloop.m4 in this package:
$ m4 -I examples undivert(`forloop.m4')dnl ⇒divert(`-1') ⇒# forloop(var, from, to, stmt) - simple version ⇒define(`forloop', `pushdef(`$1', `$2')_forloop($@)popdef(`$1')') ⇒define(`_forloop', ⇒ `$4`'ifelse($1, `$3', `', `define(`$1', incr($1))$0($@)')') ⇒divert`'dnl
Notice the careful use of quotes. Certain macro arguments are leftunquoted, each for its own reason. Try to find outwhy thesearguments are left unquoted, and see what happens if they are quoted. (As presented, these two macros are useful but not very robust forgeneral use. They lack even basic error handling for cases likestart less thanend, end not numeric, oriterator not being a macro name. See if you can improve thesemacros; or seeAnswers).
6.5 Iteration by list contents
Here is an example of a loop macro that implements list iteration.
— Composite: foreachq ( iterator, quote-list, text)
Takes the name in iterator, which must be a valid macro name, andsuccessively assign it each value fromparen-list orquote-list. In
foreach
, paren-list is acomma-separated list of elements contained in parentheses. Inforeachq
,quote-list is a comma-separated list of elementscontained in a quoted string. For each assignment toiterator,append text to the overall expansion. text may refer toiterator. Any definition ofiterator prior to thisinvocation is restored.
As an example, this displays each word in a list inside of a sentence,using an implementation offoreach
distributed asm4-1.4.16/examples/foreach.m4, andforeachq
in m4-1.4.16/examples/foreachq.m4.
$ m4 -I examples include(`foreach.m4') ⇒ foreach(`x', (foo, bar, foobar), `Word was: x ')dnl ⇒Word was: foo ⇒Word was: bar ⇒Word was: foobar include(`foreachq.m4') ⇒ foreachq(`x', `foo, bar, foobar', `Word was: x ')dnl ⇒Word was: foo ⇒Word was: bar ⇒Word was: foobar
It is possible to be more complex; each element of the paren-listorquote-list can itself be a list, to pass as further argumentsto a helper macro. This example generates a shell case statement:
$ m4 -I examples include(`foreach.m4') ⇒ define(`_case', ` $1) $2=" $1";; ')dnl define(`_cat', `$1$2')dnl case $`'1 in ⇒case $1 in foreach(`x', `(`(`a', `vara')', `(`b', `varb')', `(`c', `varc')')', `_cat(`_case', x)')dnl ⇒ a) ⇒ vara=" a";; ⇒ b) ⇒ varb=" b";; ⇒ c) ⇒ varc=" c";; esac ⇒esac
The implementation of the foreach
macro is a bit more involved;it is a wrapper around two helper macros. First,_arg1
isneeded to grab the first element of a list. Second,_foreach
implements the recursion, successively walkingthrough the original list. Here is a simple implementation offoreach
:
$ m4 -I examples undivert(`foreach.m4')dnl ⇒divert(`-1') ⇒# foreach(x, (item_1, item_2, ..., item_n), stmt) ⇒# parenthesized list, simple version ⇒define(`foreach', `pushdef(`$1')_foreach($@)popdef(`$1')') ⇒define(`_arg1', `$1') ⇒define(`_foreach', `ifelse(`$2', `()', `', ⇒ `define(`$1', _arg1$2)$3`'$0(`$1', (shift$2), `$3')')') ⇒divert`'dnl
Unfortunately, that implementation is not robust to macro names as listelements. Each iteration of_foreach
is stripping anotherlayer of quotes, leading to erratic results if list elements are notalready fully expanded. The first cut at implementingforeachq
takes this into account. Also, when using quoted elements in aparen-list, the overall list must be quoted. Aquote-listhas the nice property of requiring fewer characters to create a listcontaining the same quoted elements. To see the difference between thetwo macros, we attempt to pass double-quoted macro names in a list,expecting the macro name on output after one layer of quotes is removedduring list iteration and the final layer removed during the finalrescan:
$ m4 -I examples define(`a', `1')define(`b', `2')define(`c', `3') ⇒ include(`foreach.m4') ⇒ include(`foreachq.m4') ⇒ foreach(`x', `(``a'', ``(b'', ``c)'')', `x ') ⇒1 ⇒(2)1 ⇒ ⇒, x ⇒) foreachq(`x', ```a'', ``(b'', ``c)''', `x ')dnl ⇒a ⇒(b ⇒c)
Obviously, foreachq
did a better job; here is its implementation:
$ m4 -I examples undivert(`foreachq.m4')dnl ⇒include(`quote.m4')dnl ⇒divert(`-1') ⇒# foreachq(x, `item_1, item_2, ..., item_n', stmt) ⇒# quoted list, simple version ⇒define(`foreachq', `pushdef(`$1')_foreachq($@)popdef(`$1')') ⇒define(`_arg1', `$1') ⇒define(`_foreachq', `ifelse(quote($2), `', `', ⇒ `define(`$1', `_arg1($2)')$3`'$0(`$1', `shift($2)', `$3')')') ⇒divert`'dnl
Notice that _foreachq
had to use the helper macroquote
defined earlier (seeShift), to ensure that theembedded ifelse
call does not go haywire if a list elementcontains a comma. Unfortunately, this implementation offoreachq
has its own severe flaw. Whereas the foreach
implementation waslinear, this macro is quadratic in the number of list elements, and ismuch more likely to trip up the limit set by the command line option--nesting-limit (or -L, see Invoking m4). Additionally, this implementation does not expand‘defn(`iterator')’ very well, when compared withforeach
.
$ m4 -I examples include(`foreach.m4')include(`foreachq.m4') ⇒ foreach(`name', `(`a', `b')', ` defn(`name')') ⇒ a b foreachq(`name', ``a', `b'', ` defn(`name')') ⇒ _arg1(`a', `b') _arg1(shift(`a', `b'))
It is possible to have robust iteration with linear behavior and saneiterator contents for either list style. See if you can learnfrom the best elements of both of these implementations to create robustmacros (or seeAnswers).
6.6 Working with definition stacks
Thanks topushdef
, manipulation of a stack is an intrinsicoperation in m4
. Normally, only the topmost definition in astack is important, but sometimes, it is desirable to manipulate theentire definition stack.
— Composite: stack_foreach_lifo ( macro, action)
For each of the
pushdef
definitions associated with macro,invoke the macroaction with a single argument of that definition.stack_foreach
visits the oldest definition first, whilestack_foreach_lifo
visits the current definition first.action should not modify or dereference macro. There are afew special macros, such asdefn
, which cannot be used as themacro parameter.
A sample implementation of these macros is distributed in the filem4-1.4.16/examples/stack.m4.
$ m4 -I examples include(`stack.m4') ⇒ pushdef(`a', `1')pushdef(`a', `2')pushdef(`a', `3') ⇒ define(`show', ``$1' ') ⇒ stack_foreach(`a', `show')dnl ⇒1 ⇒2 ⇒3 stack_foreach_lifo(`a', `show')dnl ⇒3 ⇒2 ⇒1
Now for the implementation. Note the definition of a helper macro,_stack_reverse
, which destructively swaps the contents of onestack of definitions into the reverse order in the temporary macro‘tmp-$1’. By calling the helper twice, the original order isrestored back into the macro ‘$1’; since the operation isdestructive, this explains why ‘$1’ must not be modified ordereferenced during the traversal. The caller can then injectadditional code to pass the definition currently being visited to‘$2’. The choice of helper names is intentional; since ‘-’ isnot valid as part of a macro name, there is no risk of conflict with avalid macro name, and the code is guaranteed to usedefn
wherenecessary. Finally, note that any macro used in the traversal of apushdef
stack, such aspushdef
or defn
, cannot behandled by stack_foreach
, since the macro would temporarily beundefined during the algorithm.
$ m4 -I examples undivert(`stack.m4')dnl ⇒divert(`-1') ⇒# stack_foreach(macro, action) ⇒# Invoke ACTION with a single argument of each definition ⇒# from the definition stack of MACRO, starting with the oldest. ⇒define(`stack_foreach', ⇒`_stack_reverse(`$1', `tmp-$1')'dnl ⇒`_stack_reverse(`tmp-$1', `$1', `$2(defn(`$1'))')') ⇒# stack_foreach_lifo(macro, action) ⇒# Invoke ACTION with a single argument of each definition ⇒# from the definition stack of MACRO, starting with the newest. ⇒define(`stack_foreach_lifo', ⇒`_stack_reverse(`$1', `tmp-$1', `$2(defn(`$1'))')'dnl ⇒`_stack_reverse(`tmp-$1', `$1')') ⇒define(`_stack_reverse', ⇒`ifdef(`$1', `pushdef(`$2', defn(`$1'))$3`'popdef(`$1')$0($@)')') ⇒divert`'dnl
6.7 Building macros with macros
Since m4 is a macro language, it is possible to write macros thatcan build other macros. First on the list is a way to automate thecreation of blind macros.
Defines name as a blind macro, such that name will expand tovalue only when given explicit arguments.value should notbe the result of
defn
(see Defn). This macro is onlyrecognized with parameters, and results in an empty string.
Defining a macro to define another macro can be a bit tricky. We wantto use a literal ‘$#’ in the argument to the nesteddefine
. However, if ‘$’ and ‘#’ are adjacent in the definition ofdefine_blind
, then it would be expanded as the number ofarguments todefine_blind
rather than the intended number ofarguments to name. The solution is to pass the difficultcharacters through extra arguments to a helper macro_define_blind
. When composing macros, it is a common idiom toneed a helper macro to concatenate text that forms parameters in thecomposed macro, rather than interpreting the text as a parameter of thecomposing macro.
As for the limitation against using defn
, there are two reasons. If a macro was previously defined withdefine_blind
, then it cansafely be renamed to a new blind macro using plaindefine
; usingdefine_blind
to rename it just adds another layer ofifelse
, occupying memory and slowing down execution. And if amacro is a builtin, then it would result in an attempt to define a macroconsisting of both text and a builtin token; this is not supported, andthe builtin token is flattened to an empty string.
With that explanation, here's the definition, and some sample usage. Notice thatdefine_blind
is itself a blind macro.
$ m4 -d define(`define_blind', `ifelse(`$#', `0', ``$0'', `_$0(`$1', `$2', `$'`#', `$'`0')')') ⇒ define(`_define_blind', `define(`$1', `ifelse(`$3', `0', ``$4'', `$2')')') ⇒ define_blind ⇒define_blind define_blind(`foo', `arguments were $*') ⇒ foo ⇒foo foo(`bar') ⇒arguments were bar define(`blah', defn(`foo')) ⇒ blah ⇒blah blah(`a', `b') ⇒arguments were a,b defn(`blah') ⇒ifelse(`$#', `0', ``$0'', `arguments were $*')
Another interesting composition tactic is argumentcurrying, orfactoring a macro that takes multiple arguments for use in a contextthat provides exactly one argument.
Expand to a macro call that takes exactly one argument, then appendsthat argument to the original arguments and invokesmacro with theresulting list of arguments.
A demonstration of currying makes the intent of this macro a little moreobvious. The macrostack_foreach
mentioned earlier is an exampleof a context that provides exactly one argument to a macro name. Butcoupled with currying, we can invokereverse
with two argumentsfor each definition of a macro stack. This example uses the filem4-1.4.16/examples/curry.m4 included in thedistribution.
$ m4 -I examples include(`curry.m4')include(`stack.m4') ⇒ define(`reverse', `ifelse(`$#', `0', , `$#', `1', ``$1'', `reverse(shift($@)), `$1'')') ⇒ pushdef(`a', `1')pushdef(`a', `2')pushdef(`a', `3') ⇒ stack_foreach(`a', `:curry(`reverse', `4')') ⇒:1, 4:2, 4:3, 4 curry(`curry', `reverse', `1')(`2')(`3') ⇒3, 2, 1
Now for the implementation. Notice how curry
leaves off with amacro name but no open parenthesis, while still in the middle ofcollecting arguments for ‘$1’. The macro_curry
is thehelper macro that takes one argument, then adds it to the list andfinally supplies the closing parenthesis. The use of a comma inside theshift
call allows currying to also work for a macro that takesone argument, although it often makes more sense to invoke that macrodirectly rather than going throughcurry
.
$ m4 -I examples undivert(`curry.m4')dnl ⇒divert(`-1') ⇒# curry(macro, args) ⇒# Expand to a macro call that takes one argument, then invoke ⇒# macro(args, extra). ⇒define(`curry', `$1(shift($@,)_$0') ⇒define(`_curry', ``$1')') ⇒divert`'dnl
Unfortunately, with M4 1.4.x, curry
is unable to handle builtintokens, which are silently flattened to the empty string when passedthrough another text macro. This limitation will be lifted in a futurerelease of M4.
Putting the last few concepts together, it is possible to copy or renamean entire stack of macro definitions.
— Composite: rename ( source, dest)
Ensure that dest is undefined, then define it to the same stack ofdefinitions currently insource.
copy
leaves sourceunchanged, whilerename
undefines source. There are only afew macros, such ascopy
ordefn
, which cannot be copiedvia this macro.
The implementation is relatively straightforward (although since it usescurry
, it is unable to copy builtin macros, such as the seconddefinition ofa
as a synonym for divnum
. See if you candesign a version that works around this limitation, or seeAnswers).
$ m4 -I examples include(`curry.m4')include(`stack.m4') ⇒ define(`rename', `copy($@)undefine(`$1')')dnl define(`copy', `ifdef(`$2', `errprint(`$2 already defined ')m4exit(`1')', `stack_foreach(`$1', `curry(`pushdef', `$2')')')')dnl pushdef(`a', `1')pushdef(`a', defn(`divnum'))pushdef(`a', `2') ⇒ copy(`a', `b') ⇒ rename(`b', `c') ⇒ a b c ⇒2 b 2 popdef(`a', `c')c a ⇒ 0 popdef(`a', `c')a c ⇒1 1
7 How to debug macros and input
When writing macros form4
, they often do not work as intended onthe first try (as is the case with most programming languages). Fortunately, there is support for macro debugging inm4
.
7.1 Displaying macro definitions
If you want to see what a name expands into, you can use the builtindumpdef
:
Accepts any number of arguments. If called without any arguments,it displays the definitions of all known names, otherwise it displaysthe definitions of thenames given. The output is printed to thecurrent debug file (usually standard error), and is sorted by name. Ifan unknown name is encountered, a warning is printed.
The expansion of
dumpdef
is void.
$ m4 -d define(`foo', `Hello world.') ⇒ dumpdef(`foo') error-->foo: `Hello world.' ⇒ dumpdef(`define') error-->define: <define> ⇒
The last example shows how builtin macros definitions are displayed. The definition that is dumped corresponds to what would occur if themacro were to be called at that point, even if other definitions arestill live due to redefining a macro during argument collection.
$ m4 -d pushdef(`f', ``$0'1')pushdef(`f', ``$0'2') ⇒ f(popdef(`f')dumpdef(`f')) error-->f: ``$0'1' ⇒f2 f(popdef(`f')dumpdef(`f')) error-->m4:stdin:3: undefined macro `f' ⇒f1
See Debug Levels, for information on controlling the details of thedisplay.
7.2 Tracing macro calls
It is possible to trace macro calls and expansions through the builtinstraceon
and traceoff
:
— Builtin: traceoff ( [ names... ])
When called without any arguments,
traceon
andtraceoff
will turn tracing on and off, respectively, for all currently definedmacros.When called with arguments, only the macros listed in names areaffected, whether or not they are currently defined.
The expansion of
traceon
andtraceoff
is void.
Whenever a traced macro is called and the arguments have been collected,the call is displayed. If the expansion of the macro call is not void,the expansion can be displayed after the call. The output is printedto the current debug file (defaulting to standard error, see Debug Output).
$ m4 -d define(`foo', `Hello World.') ⇒ define(`echo', `$@') ⇒ traceon(`foo', `echo') ⇒ foo error-->m4trace: -1- foo -> `Hello World.' ⇒Hello World. echo(`gnus', `and gnats') error-->m4trace: -1- echo(`gnus', `and gnats') -> ``gnus',`and gnats'' ⇒gnus,and gnats
The number between dashes is the depth of the expansion. It is one mostof the time, signifying an expansion at the outermost level, but itincreases when macro arguments contain unquoted macro calls. Themaximum number that will appear between dashes is controlled by theoption --nesting-limit (or -L, see Invoking m4). Additionally, the option--trace (or-t) can be used to invoketraceon(
name)
beforeparsing input.
$ m4 -L 3 -t ifelse ifelse(`one level') error-->m4trace: -1- ifelse ⇒ ifelse(ifelse(ifelse(`three levels'))) error-->m4trace: -3- ifelse error-->m4trace: -2- ifelse error-->m4trace: -1- ifelse ⇒ ifelse(ifelse(ifelse(ifelse(`four levels')))) error-->m4:stdin:3: recursion limit of 3 exceeded, use -L<N> to change it
Tracing by name is an attribute that is preserved whether the macro isdefined or not. This allows the selection of macros to trace beforethose macros are defined.
$ m4 -d traceoff(`foo') ⇒ traceon(`foo') ⇒ foo ⇒foo defn(`foo') ⇒ define(`foo', `bar') ⇒ foo error-->m4trace: -1- foo -> `bar' ⇒bar undefine(`foo') ⇒ ifdef(`foo', `yes', `no') ⇒no indir(`foo') error-->m4:stdin:9: undefined macro `foo' ⇒ define(`foo', `blah') ⇒ foo error-->m4trace: -1- foo -> `blah' ⇒blah traceoff ⇒ foo ⇒blah
Tracing even works on builtins. However, defn
(see Defn)does not transfer tracing status.
$ m4 -d traceon(`traceon') ⇒ traceon(`traceoff') error-->m4trace: -1- traceon(`traceoff') ⇒ traceoff(`traceoff') error-->m4trace: -1- traceoff(`traceoff') ⇒ traceoff(`traceon') ⇒ traceon(`eval', `m4_divnum') ⇒ define(`m4_eval', defn(`eval')) ⇒ define(`m4_divnum', defn(`divnum')) ⇒ eval(divnum) error-->m4trace: -1- eval(`0') -> `0' ⇒0 m4_eval(m4_divnum) error-->m4trace: -2- m4_divnum -> `0' ⇒0
See Debug Levels, for information on controlling the details of thedisplay. The format of the trace output is not specified byPOSIX, and varies between implementations ofm4
.
7.3 Controlling debugging output
The-d option to m4
(or --debug,seeInvoking m4) controls the amount of detailspresented in threecategories of output. Trace output is requested bytraceon
(see Trace), and each line is prefixed by ‘m4trace:’ inrelation to a macro invocation. Debug output tracks useful events notassociated with a macro invocation, and each line is prefixed by‘m4debug:’. Finally, dumpdef
(seeDumpdef) output isaffected, with no prefix added to the output lines.
The flags following the option can be one or more of thefollowing:
-
In trace output, show the actual arguments that were collected beforeinvoking the macro. This applies to all macro calls if the ‘
t’flag is used, otherwise only the macros covered by calls of
traceon
. Arguments are subject to length truncation specified bythe command line option --arglength (or -l).
-
In trace output, show several trace lines for each macro call. A lineis shown when the macro is seen, but before the arguments are collected;a second line when the arguments have been collected and a third lineafter the call has completed.
-
In trace output, show the expansion of each macro call, if it is notvoid. This applies to all macro calls if the ‘
t’ flag is used,otherwise only the macros covered by calls of
traceon
. Theexpansion is subject to length truncation specified by the command lineoption --arglength (or -l).
-
In debug and trace output, include the name of the current input file inthe output line.
-
In debug output, print a message each time the current input file ischanged.
-
In debug and trace output, include the current input line number in theoutput line.
-
In debug output, print a message when a named file is found through thepath search mechanism (see
Search Path), giving the actual file nameused.
-
In trace and dumpdef output, quote actual arguments and macro expansionsin the display with the current quotes. This is useful in connectionwith the ‘
a’ and ‘
e’ flags above.
-
In trace output, trace all macro calls made in this invocation of
m4
, regardless of the settings oftraceon
.
-
In trace output, add a unique `macro call id' to each line of the traceoutput. This is useful in connection with the ‘
c’ flag above.
- A shorthand for all of the above flags.
a
c
e
f
i
l
p
q
t
x
V
If no flags are specified with the -d option, the default is‘aeq’. The examples throughout this manual assume the defaultflags.
There is a builtin macro debugmode
, which allows on-the-fly control ofthe debugging output format:
The argument flags should be a subset of the letters listed above. As special cases, if the argument starts with a ‘+’, the flags areadded to the current debug flags, and if it starts with a ‘-’, theyare removed. If no argument is present, all debugging flags are cleared(as if no-d was given), and with an empty argument the flagsare reset to the default of ‘aeq’.
The expansion of
debugmode
is void.
$ m4 define(`foo', `FOO') ⇒ traceon(`foo') ⇒ debugmode() ⇒ foo error-->m4trace: -1- foo -> `FOO' ⇒FOO debugmode ⇒ foo error-->m4trace: -1- foo ⇒FOO debugmode(`+l') ⇒ foo error-->m4trace:8: -1- foo ⇒FOO
The following example demonstrates the behavior of length truncation,when specified on the command line. Note that each argument and thefinal result are individually truncated. Also, the special tokens forbuiltin functions are not truncated.
$ m4 -d -l 6 define(`echo', `$@')debugmode(`+t') ⇒ echo(`1', `long string') error-->m4trace: -1- echo(`1', `long s...') -> ``1',`l...' ⇒1,long string indir(`echo', defn(`changequote')) error-->m4trace: -2- defn(`change...') error-->m4trace: -1- indir(`echo', <changequote>) -> ``'' ⇒
This example shows the effects of the debug flags that are not relatedto macro tracing.
$ m4 -dip -I examples error-->m4debug: input read from stdin include(`foo')dnl error-->m4debug: path search for `foo' found `examples/foo' error-->m4debug: input read from examples/foo ⇒bar error-->m4debug: input reverted to stdin, line 1 ^D error-->m4debug: input exhausted
7.4 Saving debugging output
Debug and tracing output can be redirected to files using either the--debugfile option to m4
(seeInvoking m4), or with the builtin macro debugfile
:
Sends all further debug and trace output to file, opened in appendmode. Iffile is the empty string, debug and trace output arediscarded. If
debugfile
is called without any arguments, debugand trace output are sent to standard error. This does not affectwarnings, error messages, orerrprint
output, which arealways sent to standard error. If file cannot be opened, thecurrent debug file is unchanged, and an error is issued.The expansion of
debugfile
is void.
$ m4 -d traceon(`divnum') ⇒ divnum(`extra') error-->m4:stdin:2: Warning: excess arguments to builtin `divnum' ignored error-->m4trace: -1- divnum(`extra') -> `0' ⇒0 debugfile() ⇒ divnum(`extra') error-->m4:stdin:4: Warning: excess arguments to builtin `divnum' ignored ⇒0 debugfile ⇒ divnum error-->m4trace: -1- divnum -> `0' ⇒0
8 Input control
This chapter describes various builtin macros for controlling the inputto m4
.
8.1 Deleting whitespace in input
The builtindnl
stands for “Discard to Next Line”:
All characters, up to and including the next newline, are discardedwithout performing any macro expansion. A warning is issued if the endof the file is encountered without a newline.
The expansion of
dnl
is void.
It is often used in connection with define
, to remove thenewline that follows the call todefine
. Thus
define(`foo', `Macro `foo'.')dnl A very simple macro, indeed. foo ⇒Macro foo.
The input up to and including the next newline is discarded, as opposedto the way comments are treated (seeComments).
Usually, dnl
is immediately followed by an end of line or someother whitespace. GNUm4
will produce a warning diagnostic ifdnl
is followed by an open parenthesis. In this case,dnl
will collect and process all arguments, looking for a matching closeparenthesis. All predictable side effects resulting from thiscollection will take place.dnl
will return no output. Theinput following the matching close parenthesis up to and including thenext newline, on whatever line containing it, will still be discarded.
dnl(`args are ignored, but side effects occur', define(`foo', `like this')) while this text is ignored: undefine(`foo') error-->m4:stdin:1: Warning: excess arguments to builtin `dnl' ignored See how `foo' was defined, foo? ⇒See how foo was defined, like this?
If the end of file is encountered without a newline character, awarning is issued and dnl stops consuming input.
m4wrap(`m4wrap(`2 hi ')0 hi dnl 1 hi') ⇒ define(`hi', `HI') ⇒ ^D error-->m4:stdin:1: Warning: end of file treated as newline ⇒0 HI 2 HI
8.2 Changing the quote characters
The default quote delimiters can be changed with the builtinchangequote
:
This sets start as the new begin-quote delimiter and end asthe new end-quote delimiter. If both arguments are missing, the defaultquotes (
`
and'
) are used. If start is void, thenquoting is disabled. Otherwise, ifend is missing or void, thedefault end-quote delimiter ('
) is used. The quote delimiterscan be of any length.The expansion of
changequote
is void.
changequote(`[', `]') ⇒ define([foo], [Macro [foo].]) ⇒ foo ⇒Macro foo.
The quotation strings can safely contain eight-bit characters. If no single character is appropriate,start and end can beof any length. Other implementations cap the delimiter length to fivecharacters, but GNU has no inherent limit.
changequote(`[[[', `]]]') ⇒ define([[[foo]]], [[[Macro [[[[[foo]]]]].]]]) ⇒ foo ⇒Macro [[foo]].
Calling changequote
with start as the empty string willeffectively disable the quoting mechanism, leaving no way to quote text. However, using an empty string is not portable, as some otherimplementations ofm4
revert to the default quoting, while otherspreserve the prior non-empty delimiter. Ifstart is not empty,then an empty end will use the default end-quote delimiter of‘'’, as otherwise, it would be impossible to end a quoted string. Again, this is not portable, as some otherm4
implementationsreuse start as the end-quote delimiter, while others preserve theprevious non-empty value. Omitting both arguments restores the defaultbegin-quote and end-quote delimiters; fortunately this behavior isportable to all implementations of m4
.
define(`foo', `Macro `FOO'.') ⇒ changequote(`', `') ⇒ foo ⇒Macro `FOO'. `foo' ⇒`Macro `FOO'.' changequote(`,) ⇒ foo ⇒Macro FOO.
There is no way in m4
to quote a string containing an unmatchedbegin-quote, except usingchangequote
to change the currentquotes.
If the quotes should be changed from, say, ‘[’ to ‘[[’,temporary quote characters have to be defined. To achieve this, twocalls ofchangequote
must be made, one for the temporary quotesand one for the new quotes.
Macros are recognized in preference to the begin-quote string, so if aprefix ofstart can be recognized as part of a potential macroname, the quoting mechanism is effectively disabled. Unless you usechangeword
(seeChangeword), this means that startshould not begin with a letter, digit, or ‘_’ (underscore). However, even though quoted strings are not recognized, the quotecharacters can still be discerned in macro expansion and in traceoutput.
define(`echo', `$@') ⇒ define(`hi', `HI') ⇒ changequote(`q', `Q') ⇒ q hi Q hi ⇒q HI Q HI echo(hi) ⇒qHIQ changequote ⇒ changequote(`-', `EOF') ⇒ - hi EOF hi ⇒ hi HI changequote ⇒ changequote(`1', `2') ⇒ hi1hi2 ⇒hi1hi2 hi 1hi2 ⇒HI hi
Quotes are recognized in preference to argument collection. Inparticular, if start is a single ‘(’, then argumentcollection is effectively disabled. For portability with otherimplementations, it is a good idea to avoid ‘(’, ‘,’, and‘)’ as the first character in start.
define(`echo', `$#:$@:') ⇒ define(`hi', `HI') ⇒ changequote(`(',`)') ⇒ echo(hi) ⇒0::hi changequote ⇒ changequote(`((', `))') ⇒ echo(hi) ⇒1:HI: echo((hi)) ⇒0::hi changequote ⇒ changequote(`,', `)') ⇒ echo(hi,hi)bye) ⇒1:HIhibye:
However, if you are not worried about portability, using ‘(’ and‘)’ as quoting characters has an interesting property—you can useit to compute a quoted string containing the expansion of any quotedtext, as long as the expansion results in both balanced quotes andbalanced parentheses. The trick is realizingexpand
uses‘$1’ unquoted, to trigger its expansion using the normal quotingcharacters, but uses extra parentheses to group unquoted commas thatoccur in the expansion without consuming whitespace following thosecommas. Then _expand
uses changequote
to convert theextra parentheses back into quoting characters. Note that it takes twomorechangequote
invocations to restore the original quotes. Contrast the behavior on whitespace when using ‘$*’, viaquote
, to attempt the same task.
changequote(`[', `]')dnl define([a], [1, (b)])dnl define([b], [2])dnl define([quote], [[$*]])dnl define([expand], [_$0(($1))])dnl define([_expand], [changequote([(], [)])$1changequote`'changequote(`[', `]')])dnl expand([a, a, [a, a], [[a, a]]]) ⇒1, (2), 1, (2), a, a, [a, a] quote(a, a, [a, a], [[a, a]]) ⇒1,(2),1,(2),a, a,[a, a]
If end is a prefix of start, the end-quote will berecognized in preference to a nested begin-quote. In particular,changing the quotes to have the same string forstart andend disables nesting of quotes. When quote nesting is disabled,it is impossible to double-quote strings across macro expansions, sousing the same string is not done very often.
define(`hi', `HI') ⇒ changequote(`""', `"') ⇒ ""hi"""hi" ⇒hihi ""hi" ""hi" ⇒hi hi ""hi"" "hi" ⇒hi" "HI" changequote ⇒ `hi`hi'hi' ⇒hi`hi'hi changequote(`"', `"') ⇒ "hi"hi"hi" ⇒hiHIhi
It is an error if the end of file occurs within a quoted string.
`hello world' ⇒hello world `dangling quote ^D error-->m4:stdin:2: ERROR: end of file in string
ifelse(`dangling quote ^D error-->m4:stdin:1: ERROR: end of file in string
8.3 Changing the comment delimiters
The default comment delimiters can be changed with the builtinmacrochangecom
:
This sets start as the new begin-comment delimiter and endas the new end-comment delimiter. If both arguments are missing, orstart is void, then comments are disabled. Otherwise, ifend is missing or void, the default end-comment delimiter ofnewline is used. The comment delimiters can be of any length.
The expansion of
changecom
is void.
define(`comment', `COMMENT') ⇒ # A normal comment ⇒# A normal comment changecom(`/*', `*/') ⇒ # Not a comment anymore ⇒# Not a COMMENT anymore But: /* this is a comment now */ while this is not a comment ⇒But: /* this is a comment now */ while this is not a COMMENT
Note how comments are copied to the output, much as if they were quotedstrings. If you want the text inside a comment expanded, quote thebegin-comment delimiter.
Calling changecom
without any arguments, or with start asthe empty string, will effectively disable the commenting mechanism. Torestore the original comment start of ‘#’, you must explicitly askfor it. If start is not empty, then an empty end will usethe default end-comment delimiter of newline, as otherwise, it would beimpossible to end a comment. However, this is not portable, as someotherm4
implementations preserve the previous non-emptydelimiters instead.
define(`comment', `COMMENT') ⇒ changecom ⇒ # Not a comment anymore ⇒# Not a COMMENT anymore changecom(`#', `') ⇒ # comment again ⇒# comment again
The comment strings can safely contain eight-bit characters. If no single character is appropriate,start and end can beof any length. Other implementations cap the delimiter length to fivecharacters, but GNU has no inherent limit.
Comments are recognized in preference to macros. However, this is notcompatible with other implementations, where macros and even quotingtakes precedence over comments, so it may change in a future release. For portability, this means thatstart should not begin with aletter, digit, or ‘_’ (underscore), and that neither thestart-quote nor the start-comment string should be a prefix of theother.
define(`hi', `HI') ⇒ define(`hi1hi2', `hello') ⇒ changecom(`q', `Q') ⇒ q hi Q hi ⇒q hi Q HI changecom(`1', `2') ⇒ hi1hi2 ⇒hello hi 1hi2 ⇒HI 1hi2
Comments are recognized in preference to argument collection. Inparticular, ifstart is a single ‘(’, then argumentcollection is effectively disabled. For portability with otherimplementations, it is a good idea to avoid ‘(’, ‘,’, and‘)’ as the first character in start.
define(`echo', `$#:$*:$@:') ⇒ define(`hi', `HI') ⇒ changecom(`(',`)') ⇒ echo(hi) ⇒0:::(hi) changecom ⇒ changecom(`((', `))') ⇒ echo(hi) ⇒1:HI:HI: echo((hi)) ⇒0:::((hi)) changecom(`,', `)') ⇒ echo(hi,hi)bye) ⇒1:HI,hi)bye:HI,hi)bye: changecom ⇒ echo(hi,`,`'hi',hi) ⇒3:HI,,HI,HI:HI,,`'hi,HI: echo(hi,`,`'hi',hi`'changecom(`,,', `hi')) ⇒3:HI,,`'hi,HI:HI,,`'hi,HI:
It is an error if the end of file occurs within a comment.
changecom(`/*', `*/') ⇒ /*dangling comment ^D error-->m4:stdin:2: ERROR: end of file in comment
8.4 Changing the lexical structure of words
The macrochangeword
and all associated functionality isexperimental. It is only available if the --enable-changewordoption was given to configure, at GNUm4
installationtime. The functionality will go away in the future, to be replaced byother new features that are more efficient at providing the samecapabilities. Do not rely on it. Please direct your commentsabout it the same way you would do for bugs.
A file being processed by m4
is split into quoted strings, words(potential macro names) and simple tokens (any other single character). Initially a word is defined by the following regular expression:
[_a-zA-Z][_a-zA-Z0-9]*
Using changeword
, you can change this regular expression:
Changes the regular expression for recognizing macro names to beregex. Ifregex is empty, use‘[_a-zA-Z][_a-zA-Z0-9]*’.regex must obey the constraintthat every prefix of the desired final pattern is also accepted by theregular expression. Ifregex contains grouping parentheses, themacro invoked is the portion that matched the first group, rather thanthe entire matching string.
The expansion of
changeword
is void. The macrochangeword
is recognized only with parameters.
Relaxing the lexical rules of m4
might be useful (for example) ifyou wanted to apply translations to a file of numbers:
ifdef(`changeword', `', `errprint(` skipping: no changeword support ')m4exit(`77')')dnl changeword(`[_a-zA-Z0-9]+') ⇒ define(`1', `0')1 ⇒0
Tightening the lexical rules is less useful, because it will generallymake some of the builtins unavailable. You could use it to preventaccidental call of builtins, for example:
ifdef(`changeword', `', `errprint(` skipping: no changeword support ')m4exit(`77')')dnl define(`_indir', defn(`indir')) ⇒ changeword(`_[_a-zA-Z0-9]*') ⇒ esyscmd(`foo') ⇒esyscmd(foo) _indir(`esyscmd', `echo hi') ⇒hi ⇒
Because m4
constructs its words a character at a time, thereis a restriction on the regular expressions that may be passed tochangeword
. This is that if your regular expression accepts‘foo’, it must also accept ‘f’ and ‘fo’.
ifdef(`changeword', `', `errprint(` skipping: no changeword support ')m4exit(`77')')dnl define(`foo ', `bar ') ⇒ dnl This example wants to recognize changeword, dnl, and `foo\n'. dnl First, we check that our regexp will match. regexp(`changeword', `[cd][a-z]*\|foo[ ]') ⇒0 regexp(`foo ', `[cd][a-z]*\|foo[ ]') ⇒0 regexp(`f', `[cd][a-z]*\|foo[ ]') ⇒-1 foo ⇒foo changeword(`[cd][a-z]*\|foo[ ]') ⇒ dnl Even though `foo\n' matches, we forgot to allow `f'. foo ⇒foo changeword(`[cd][a-z]*\|fo*[ ]?') ⇒ dnl Now we can call `foo\n'. foo ⇒bar
changeword
has another function. If the regular expressionsupplied contains any grouped subexpressions, then text outsidethe first of these is discarded before symbol lookup. So:
ifdef(`changeword', `', `errprint(` skipping: no changeword support ')m4exit(`77')')dnl ifdef(`__unix__', , `errprint(` skipping: syscmd does not have unix semantics ')m4exit(`77')')dnl changecom(`/*', `*/')dnl define(`foo', `bar')dnl changeword(`#\([_a-zA-Z0-9]*\)') ⇒ #esyscmd(`echo foo \#foo') ⇒foo bar ⇒
m4
now requires a ‘#’ mark at the beginning of everymacro invocation, so one can usem4
to preprocess plaintext without losing various words like ‘divert’.
In m4
, macro substitution is based on text, while in TeX, itis based on tokens.changeword
can throw this difference intorelief. For example, here is the same idea represented in TeX andm4
. First, the TeX version:
\def\a{\message{Hello}} \catcode`\@=0 \catcode`\\=12 @a @bye ⇒Hello
Then, the m4
version:
ifdef(`changeword', `', `errprint(` skipping: no changeword support ')m4exit(`77')')dnl define(`a', `errprint(`Hello')')dnl changeword(`@\([_a-zA-Z0-9]*\)') ⇒ @a ⇒errprint(Hello)
In the TeX example, the first line defines a macro a
toprint the message ‘Hello’. The second line defines <@> tobe usable instead of <\> as an escape character. The third linedefines <\> to be a normal printing character, not an escape. The fourth line invokes the macro a
. So, when TeX is runon this file, it displays the message ‘Hello’.
When the m4
example is passed through m4
, it outputs‘errprint(Hello)’. The reason for this is that TeX doeslexical analysis of macro definition when the macro isdefined. m4
just stores the text, postponing the lexical analysis untilthe macro isused.
You should note that using changeword
will slow m4
downby a factor of about seven, once it is changed to something otherthan the default regular expression. You can invokechangeword
with the empty string to restore the default word definition, and regainthe parsing speed.
8.5 Saving text until end of input
It is possible to `save' some text until the end of the normal input hasbeen seen. Text can be saved, to be read again by m4
when thenormal input has been exhausted. This feature is normally used toinitiate cleanup actions before normal exit, e.g., deleting temporaryfiles.
To save input text, use the builtin m4wrap
:
Stores string in a safe place, to be reread when end of input isreached. As a GNU extension, additional arguments areconcatenated with a space to thestring.
The expansion of
m4wrap
is void. The macrom4wrap
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, andnot ifm4exit
is used to exit m4
.
It is safe to call m4wrap
from saved text, but then the order inwhich the saved text is reread is undefined. Ifm4wrap
is not usedrecursively, the saved pieces of text are reread in the opposite orderin which they were saved (LIFO—last in, first out). However, thisbehavior is likely to change in a future release, to matchPOSIX, so you should not depend on this order.
It is possible to emulate POSIX behavior evenwith older versions of GNU M4 by including the filem4-1.4.16/examples/wrapfifo.m4 from thedistribution:
$ 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 tothe GNU M4 extension ofbuiltin
, by including the filem4-1.4.16/examples/wraplifo.m4 from thedistribution. (Unfortunately, both examples shown here share somesubtle bugs. See if you can find and correct them; or seeAnswers).
$ 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 usingm4wrap
:
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 areconcatenated and rescanned as usual:
define(`aa', `AA ') ⇒ m4wrap(`a')m4wrap(`a') ⇒ ^D ⇒AA
however, the transition between recursion levels behaves like an end offile condition between two input files.
m4wrap(`m4wrap(`)')len(abc') ⇒ ^D error-->m4:stdin:1: ERROR: end of file in argument list
9 File inclusion
m4
allows you to include named files at any point in the input.
9.1 Including named files
There are two builtin macros in m4
for including files:
— Builtin: sinclude ( file)
Both macros cause the file named file to be read by
m4
. When the end of the file is reached, input is resumed fromthe previous input file.The expansion of
include
andsinclude
is therefore thecontents offile.If file does not exist, is a directory, or cannot otherwise beread, the expansion is void,and
include
will fail with an error whilesinclude
issilent. The empty string counts as a file that does not exist.The macros
include
andsinclude
are recognized only withparameters.
include(`none') error-->m4:stdin:1: cannot open `none': No such file or directory ⇒ include() error-->m4:stdin:2: cannot open `': No such file or directory ⇒ sinclude(`none') ⇒ sinclude() ⇒
The rest of this section assumes that m4
is invoked with the-I option (seeInvoking m4)pointing to the m4-1.4.16/examplesdirectory shipped as part of the GNUm4
package. Thefile m4-1.4.16/examples/incl.m4 in the distributioncontains the lines:
$ cat examples/incl.m4 ⇒Include file start ⇒foo ⇒Include file end
Normally file inclusion is used to insert the contents of a fileinto the input stream. The contents of the file will be read bym4
and macro calls in the file will be expanded:
$ m4 -I examples define(`foo', `FOO') ⇒ include(`incl.m4') ⇒Include file start ⇒FOO ⇒Include file end ⇒
The fact that include
and sinclude
expand to the contentsof the file can be used to define macros that operate on entire files. Here is an example, which defines ‘bar’ to expand to the contentsofincl.m4:
$ m4 -I examples define(`bar', include(`incl.m4')) ⇒ This is `bar': >>bar<< ⇒This is bar: >>Include file start ⇒foo ⇒Include file end ⇒<<
This use of include
is not trivial, though, as files can containquotes, commas, and parentheses, which can interfere with the way them4
parser works. GNUm4
seamlessly concatenatesthe file contents with the next character, even if the included fileended in the middle of a comment, string, or macro call. Theseconditions are only treated as end of file errors if specified as inputfiles on the command line.
In GNU m4
, an alternative method of reading files isusing undivert
(seeUndivert) on a named file.
9.2 Searching for include files
GNUm4
allows included files to be found in other directoriesthan the current working directory.
If the --prepend-include or-B command-line option wasprovided (see Invoking m4), thosedirectories are searched first, in reverse order that those options werelisted on the command line. Thenm4
looks in the current workingdirectory. Next comes the directories specified with the--include or-I option, in the order found on thecommand line. Finally, if theM4PATH environment variable is set,it is expected to contain a colon-separated list of directories, whichwill be searched in order.
If the automatic search for include-files causes trouble, the ‘p’debug flag (seeDebug Levels) can help isolate the problem.
10 Diverting and undiverting output
Diversions are a way of temporarily saving output. The output ofm4
can at any time be diverted to a temporary file, and bereinserted into the output stream,undiverted, again at a latertime.
Numbered diversions are counted from 0 upwards, diversion number 0being the normal output stream. GNUm4
tries to keep diversions in memory. However, there is alimit to the overall memory usable by all diversions taken together(512K, currently). When this maximum is about to be exceeded,a temporary file is opened to receive the contents of the biggestdiversion still in memory, freeing this memory for other diversions. When creating the temporary file,m4
honors the value of theenvironment variable TMPDIR, and falls back to/tmp. Thus, the amount of available disk space provides the only real limit onthe number and aggregate size of diversions.
Diversions make it possible to generate output in a different order thanthe input was read. It is possible to implement topological sortingdependencies. For example, GNU Autoconf makes use ofdiversions under the hood to ensure that the expansion of a prerequisitemacro appears in the output prior to the expansion of a dependent macro,regardless of which order the two macros were invoked in the user'sinput file.
10.1 Diverting output
Output is diverted usingdivert
:
The current diversion is changed to number. If number is leftout or empty, it is assumed to be zero. Ifnumber cannot beparsed, the diversion is unchanged.
The expansion of
divert
is void.
When all the m4
input will have been processed, all existingdiversions are automatically undiverted, in numerical order.
divert(`1') This text is diverted. divert ⇒ This text is not diverted. ⇒This text is not diverted. ^D ⇒ ⇒This text is diverted.
Several calls of divert
with the same argument do not overwritethe previous diverted text, but append to it. Diversions are printedafter any wrapped text is expanded.
define(`text', `TEXT') ⇒ divert(`1')`diverted text.' divert ⇒ m4wrap(`Wrapped text precedes ') ⇒ ^D ⇒Wrapped TEXT precedes diverted text.
If output is diverted to a negative diversion, it is simply discarded. This can be used to suppress unwanted output. A common example ofunwanted output is the trailing newlines after macro definitions. Hereis a common programming idiom in m4
for avoiding them.
divert(`-1') define(`foo', `Macro `foo'.') define(`bar', `Macro `bar'.') divert ⇒
Traditional implementations only supported ten diversions. But as aGNU extension, diversion numbers can be as large as positiveintegers will allow, rather than treating a multi-digit diversion numberas a request to discard text.
divert(eval(`1<<28'))world divert(`2')hello ^D ⇒hello ⇒world
Note that divert
is an English word, but also an active macrowithout arguments. When processing plain text, the word might appear innormal text and be unintentionally swallowed as a macro invocation. Oneway to avoid this is to use the-P option to rename allbuiltins (see Invoking m4). Another is to writea wrapper that requires a parameter to be recognized.
We decided to divert the stream for irrigation. ⇒We decided to the stream for irrigation. define(`divert', `ifelse(`$#', `0', ``$0'', `builtin(`$0', $@)')') ⇒ divert(`-1') Ignored text. divert(`0') ⇒ We decided to divert the stream for irrigation. ⇒We decided to divert the stream for irrigation.
10.2 Undiverting output
Diverted text can be undiverted explicitly using the builtinundivert
:
Undiverts the numeric diversions given by the arguments, in theorder given. If no arguments are supplied, all diversions areundiverted, in numerical order.
As a GNU extension,diversions may contain non-numericstrings, which are treated as the names of files to copy into the outputwithout expansion. A warning is issued if a file could not be opened.
The expansion of
undivert
is void.
divert(`1') This text is diverted. divert ⇒ This text is not diverted. ⇒This text is not diverted. undivert(`1') ⇒ ⇒This text is diverted. ⇒
Notice the last two blank lines. One of them comes from the newlinefollowing undivert
, the other from the newline that followed thedivert
! A diversion often starts with a blank line like this.
When diverted text is undiverted, it is not reread by m4
,but rather copied directly to the current output, and it is thereforenot an error to undivert into a diversion. Undiverting the empty stringis the same as specifying diversion 0; in either case nothing happenssince the output has already been flushed.
divert(`1')diverted text divert ⇒ undivert() ⇒ undivert(`0') ⇒ undivert ⇒diverted text ⇒ divert(`1')more divert(`2')undivert(`1')diverted text`'divert ⇒ undivert(`1') ⇒ undivert(`2') ⇒more ⇒diverted text
When a diversion has been undiverted, the diverted text is discarded,and it is not possible to bring back diverted text more than once.
divert(`1') This text is diverted first. divert(`0')undivert(`1')dnl ⇒ ⇒This text is diverted first. undivert(`1') ⇒ divert(`1') This text is also diverted but not appended. divert(`0')undivert(`1')dnl ⇒ ⇒This text is also diverted but not appended.
Attempts to undivert the current diversion are silently ignored. Thus,when the current diversion is not 0, the current diversion does not getrearranged among the other diversions.
divert(`1')one divert(`2')two divert(`3')three divert(`2')undivert`'dnl divert`'undivert`'dnl ⇒two ⇒one ⇒three
GNUm4
allows named files to be undiverted. Given anon-numeric argument, the contents of the file named will be copied,uninterpreted, to the current output. This complements the builtininclude
(seeInclude). To illustrate the difference, assumethe file foo contains:
$ cat foo bar
then
define(`bar', `BAR') ⇒ undivert(`foo') ⇒bar ⇒ include(`foo') ⇒BAR ⇒
If the file is not found (or cannot be read), an error message isissued, and the expansion is void. It is possible to intermix filesand diversion numbers.
divert(`1')diversion one divert(`2')undivert(`foo')dnl divert(`3')diversion three divert`'dnl undivert(`1', `2', `foo', `3')dnl ⇒diversion one ⇒bar ⇒bar ⇒diversion three
10.3 Diversion numbers
The current diversion is tracked by the builtindivnum
:
Initial divnum ⇒Initial 0 divert(`1') Diversion one: divnum divert(`2') Diversion two: divnum ^D ⇒ ⇒Diversion one: 1 ⇒ ⇒Diversion two: 2
10.4 Discarding diverted text
Often it is not known, when output is diverted, whether the divertedtext is actually needed. Since all non-empty diversion are brought backon the main output stream when the end of input is seen, a method ofdiscarding a diversion is needed. If all diversions should bediscarded, the easiest is to end the input tom4
with‘divert(`-1')’ followed by an explicit ‘undivert’:
divert(`1') Diversion one: divnum divert(`2') Diversion two: divnum divert(`-1') undivert ^D
No output is produced at all.
Clearing selected diversions can be done with the following macro:
Discard the contents of each of the listed numeric diversions.
define(`cleardivert', `pushdef(`_n', divnum)divert(`-1')undivert($@)divert(_n)popdef(`_n')') ⇒
It is called just like undivert
, but the effect is to clear thediversions, given by the arguments. (This macro has a nasty bug! Youshould try to see if you can find it and correct it; or seeAnswers).
11 Macros for text handling
There are a number of builtins in m4
for manipulating text invarious ways, extracting substrings, searching, substituting, and so on.
11.1 Calculating length of strings
The length of a string can be calculated bylen
:
Expands to the length of string, as a decimal number.
The macro
len
is recognized only with parameters.
len() ⇒0 len(`abcdef') ⇒6
11.2 Searching for substrings
Searching for substrings is done withindex
:
Expands to the index of the first occurrence of substring instring. The first character instring has index 0. Ifsubstring does not occur in string,
index
expands to‘-1’.The macro
index
is recognized only with parameters.
index(`gnus, gnats, and armadillos', `nat') ⇒7 index(`gnus, gnats, and armadillos', `dag') ⇒-1
Omitting substring evokes a warning, but still produces output;contrast this with an emptysubstring.
index(`abc') error-->m4:stdin:1: Warning: too few arguments to builtin `index' ⇒0 index(`abc', `') ⇒0 index(`abc', `b') ⇒1
11.3 Searching for regular expressions
Searching for regular expressions is done with the builtinregexp
:
Searches for regexp in string. The syntax for regularexpressions is the same as in GNU Emacs, which is similar toBRE, Basic Regular Expressions in POSIX. SeeSyntax of Regular Expressions in the GNU Emacs Manual. Support for ERE, Extended Regular Expressions is notavailable, but will be added in GNU M4 2.0.
If replacement is omitted,
regexp
expands to the index ofthe first match ofregexp in string. If regexp doesnot match anywhere instring, it expands to -1.If replacement is supplied, and there was a match,
regexp
changes the expansion to this argument, with ‘\n’ substitutedby the text matched by thenth parenthesized sub-expression ofregexp, up to nine sub-expressions. The escape ‘\&’ isreplaced by the text of the entire regular expression matched. Forall other characters, ‘\’ treats the next character literally. Awarning is issued if there were fewer sub-expressions than the‘\n’ requested, or if there is a trailing ‘\’. If therewas no match,regexp
expands to the empty string.The macro
regexp
is recognized only with parameters.
regexp(`GNUs not Unix', `\<[a-z]\w+') ⇒5 regexp(`GNUs not Unix', `\<Q\w*') ⇒-1 regexp(`GNUs not Unix', `\w\(\w+\)$', `*** \& *** \1 ***') ⇒*** Unix *** nix *** regexp(`GNUs not Unix', `\<Q\w*', `*** \& *** \1 ***') ⇒
Here are some more examples on the handling of backslash:
regexp(`abc', `\(b\)', `\\\10\a') ⇒\b0a regexp(`abc', `b', `\1\') error-->m4:stdin:2: Warning: sub-expression 1 not present error-->m4:stdin:2: Warning: trailing \ ignored in replacement ⇒ regexp(`abc', `\(\(d\)?\)\(c\)', `\1\2\3\4\5\6') error-->m4:stdin:3: Warning: sub-expression 4 not present error-->m4:stdin:3: Warning: sub-expression 5 not present error-->m4:stdin:3: Warning: sub-expression 6 not present ⇒c
Omitting regexp evokes a warning, but still produces output;contrast this with an emptyregexp argument.
regexp(`abc') error-->m4:stdin:1: Warning: too few arguments to builtin `regexp' ⇒0 regexp(`abc', `') ⇒0 regexp(`abc', `', `\\def') ⇒\def
11.4 Extracting substrings
Substrings are extracted withsubstr
:
Expands to the substring of string, which starts at indexfrom, and extends forlength characters, or to the end ofstring, if length is omitted. The starting index of a stringis always 0. The expansion is empty if there is an error parsingfrom orlength, if from is beyond the end ofstring, or iflength is negative.
The macro
substr
is recognized only with parameters.
substr(`gnus, gnats, and armadillos', `6') ⇒gnats, and armadillos substr(`gnus, gnats, and armadillos', `6', `5') ⇒gnats
Omitting from evokes a warning, but still produces output.
substr(`abc') error-->m4:stdin:1: Warning: too few arguments to builtin `substr' ⇒abc substr(`abc',) error-->m4:stdin:2: empty string treated as 0 in builtin `substr' ⇒abc
11.5 Translating characters
Character translation is done withtranslit
:
Expands to string, with each character that occurs inchars translated into the character fromreplacement withthe same index.
If replacement is shorter than chars, the excess charactersofchars are deleted from the expansion; if chars isshorter, the excess characters inreplacement are silentlyignored. If replacement is omitted, all characters instring that are present inchars are deleted from theexpansion. If a character appears more than once inchars, onlythe first instance is used in making the translation. Only a singletranslation pass is made, even if characters inreplacement alsoappear in chars.
As a GNU extension, both chars and replacement cancontain character-ranges, e.g., ‘a-z’ (meaning all lowercaseletters) or ‘0-9’ (meaning all digits). To include a dash ‘-’in chars or replacement, place it first or last in theentire string, or as the last character of a range. Back-to-back rangescan share a common endpoint. It is not an error for the last characterin the range to be `larger' than the first. In that case, the rangeruns backwards, i.e., ‘9-0’ means the string ‘9876543210’. The expansion of a range is dependent on the underlying encoding ofcharacters, so using ranges is not always portable between machines.
The macro
translit
is recognized only with parameters.
translit(`GNUs not Unix', `A-Z') ⇒s not nix translit(`GNUs not Unix', `a-z', `A-Z') ⇒GNUS NOT UNIX translit(`GNUs not Unix', `A-Z', `z-a') ⇒tmfs not fnix translit(`+,-12345', `+--1-5', `<;>a-c-a') ⇒<;>abcba translit(`abcdef', `aabdef', `bcged') ⇒bgced
In the ascii encoding, the first example deletes all uppercaseletters, the second converts lowercase to uppercase, and the third`mirrors' all uppercase letters, while converting them to lowercase. The two first cases are by far the most common, even though they are notportable to ebcdic or other encodings. The fourth example shows arange ending in ‘-’, as well as back-to-back ranges. The finalexample shows that ‘a’ is mapped to ‘b’, not ‘c’; theresulting ‘b’ is not further remapped to ‘g’; the ‘d’ and‘e’ are swapped, and the ‘f’ is discarded.
Omitting chars evokes a warning, but still produces output.
translit(`abc') error-->m4:stdin:1: Warning: too few arguments to builtin `translit' ⇒abc
11.6 Substituting text by regular expression
Global substitution in a string is done by patsubst
:
Searches string for matches of regexp, and substitutesreplacement for each match. The syntax for regular expressionsis the same as in GNU Emacs (seeRegexp).
The parts of string that are not covered by any match ofregexp are copied to the expansion. Whenever a match is found, thesearch proceeds from the end of the match, so a character fromstring will never be substituted twice. If regexp matches astring of zero length, the start position for the search is incremented,to avoid infinite loops.
When a replacement is to be made, replacement is inserted intothe expansion, with ‘\n’ substituted by the text matched bythenth parenthesized sub-expression of patsubst, for up tonine sub-expressions. The escape ‘\&’ is replaced by the text ofthe entire regular expression matched. For all other characters,‘\’ treats the next character literally. A warning is issued ifthere were fewer sub-expressions than the ‘\n’ requested, orif there is a trailing ‘\’.
The replacement argument can be omitted, in which case the textmatched byregexp is deleted.
The macro
patsubst
is recognized only with parameters.
patsubst(`GNUs not Unix', `^', `OBS: ') ⇒OBS: GNUs not Unix patsubst(`GNUs not Unix', `\<', `OBS: ') ⇒OBS: GNUs OBS: not OBS: Unix patsubst(`GNUs not Unix', `\w*', `(\&)') ⇒(GNUs)() (not)() (Unix)() patsubst(`GNUs not Unix', `\w+', `(\&)') ⇒(GNUs) (not) (Unix) patsubst(`GNUs not Unix', `[A-Z][a-z]+') ⇒GN not patsubst(`GNUs not Unix', `not', `NOT\') error-->m4:stdin:6: Warning: trailing \ ignored in replacement ⇒GNUs NOT Unix
Here is a slightly more realistic example, which capitalizes individualwords or whole sentences, by substituting calls of the macrosupcase
anddowncase
into the strings.
— Composite: downcase ( text)
— Composite: capitalize ( text)
Expand to text, but with capitalization changed:
upcase
changes all letters to upper case,downcase
changes all lettersto lower case, andcapitalize
changes the first character of eachword to upper case and the remaining characters to lower case.
First, an example of their usage, using implementations distributed inm4-1.4.16/examples/capitalize.m4.
$ m4 -I examples include(`capitalize.m4') ⇒ upcase(`GNUs not Unix') ⇒GNUS NOT UNIX downcase(`GNUs not Unix') ⇒gnus not unix capitalize(`GNUs not Unix') ⇒Gnus Not Unix
Now for the implementation. There is a helper macro _capitalize
which puts only its first word in mixed case. Thencapitalize
merely parses out the words, and replaces them with an invocation of_capitalize
. (As presented here, thecapitalize
macro hassome subtle flaws. You should try to see if you can find and correctthem; or seeAnswers).
$ m4 -I examples undivert(`capitalize.m4')dnl ⇒divert(`-1') ⇒# upcase(text) ⇒# downcase(text) ⇒# capitalize(text) ⇒# change case of text, simple version ⇒define(`upcase', `translit(`$*', `a-z', `A-Z')') ⇒define(`downcase', `translit(`$*', `A-Z', `a-z')') ⇒define(`_capitalize', ⇒ `regexp(`$1', `^\(\w\)\(\w*\)', ⇒ `upcase(`\1')`'downcase(`\2')')') ⇒define(`capitalize', `patsubst(`$1', `\w+', `_$0(`\&')')') ⇒divert`'dnl
While regexp
replaces the whole input with the replacement assoon as there is a match,patsubst
replaces eachoccurrence of a match and preserves non-matching pieces:
define(`patreg', `patsubst($@) regexp($@)')dnl patreg(`bar foo baz Foo', `foo\|Foo', `FOO') ⇒bar FOO baz FOO ⇒FOO patreg(`aba abb 121', `\(.\)\(.\)\1', `\2\1\2') ⇒bab abb 212 ⇒bab
Omitting regexp evokes a warning, but still produces output;contrast this with an emptyregexp argument.
patsubst(`abc') error-->m4:stdin:1: Warning: too few arguments to builtin `patsubst' ⇒abc patsubst(`abc', `') ⇒abc patsubst(`abc', `', `\\-') ⇒\-a\-b\-c\-
11.7 Formatting strings (printf-like)
Formatted output can be made withformat
:
Works much like the C function
printf
. The first argumentformat-string can contain ‘%’ specifications which aresatisfied by additional arguments, and the expansion offormat
isthe formatted string.The macro
format
is recognized only with parameters.
Its use is best described by a few examples:
define(`foo', `The brown fox jumped over the lazy dog') ⇒ format(`The string "%s" uses %d characters', foo, len(foo)) ⇒The string "The brown fox jumped over the lazy dog" uses 38 characters format(`%*.*d', `-1', `-1', `1') ⇒1 format(`%.0f', `56789.9876') ⇒56790 len(format(`%-*X', `5000', `1')) ⇒5000 ifelse(format(`%010F', `infinity'), ` INF', `success', format(`%010F', `infinity'), ` INFINITY', `success', format(`%010F', `infinity')) ⇒success ifelse(format(`%.1A', `1.999'), `0X1.0P+1', `success', format(`%.1A', `1.999'), `0X2.0P+0', `success', format(`%.1A', `1.999')) ⇒success format(`%g', `0xa.P+1') ⇒20
Using the forloop
macro defined earlier (see Forloop), thisexample shows howformat
can be used to produce tabular output.
$ m4 -I examples include(`forloop.m4') ⇒ forloop(`i', `1', `10', `format(`%6d squared is %10d ', i, eval(i**2))') ⇒ 1 squared is 1 ⇒ 2 squared is 4 ⇒ 3 squared is 9 ⇒ 4 squared is 16 ⇒ 5 squared is 25 ⇒ 6 squared is 36 ⇒ 7 squared is 49 ⇒ 8 squared is 64 ⇒ 9 squared is 81 ⇒ 10 squared is 100 ⇒
The builtin format
is modeled after the ANSI C ‘printf’function, and supports these ‘%’ specifiers: ‘c’, ‘s’,‘d’, ‘o’, ‘x’, ‘X’, ‘u’, ‘a’, ‘A’,‘e’, ‘E’, ‘f’, ‘F’, ‘g’, ‘G’, and‘%’; it supports field widths and precisions, and the flags‘+’, ‘-’, ‘’, ‘0’, ‘#’, and ‘'’. Forinteger specifiers, the width modifiers ‘hh’, ‘h’, and‘l’ are recognized, and for floating point specifiers, the widthmodifier ‘l’ is recognized. Items not yet supported includepositional arguments, the ‘n’, ‘p’, ‘S’, and ‘C’specifiers, the ‘z’, ‘t’, ‘j’, ‘L’ and ‘ll’modifiers, and any platform extensions available in the nativeprintf
. For more details on the functioning ofprintf
,see the C Library Manual, or the POSIX specification (forexample, ‘%a’ is supported even on platforms that haven't yetimplemented C99 hexadecimal floating point output natively).
Unrecognized specifiers result in a warning. It is anticipated that afuture release of GNUm4
will support more specifiers,and give better warnings when various problems such as overflow areencountered. Likewise, escape sequences are not yet recognized.
format(`%p', `0') error-->m4:stdin:1: Warning: unrecognized specifier in `%p' ⇒
12 Macros for doing arithmetic
Integer arithmetic is included inm4
, with a C-like syntax. Asconvenient shorthands, there are builtins for simple increment anddecrement operations.
12.1 Decrement and increment operators
Increment and decrement of integers are supported using the builtinsincr
anddecr
:
— Builtin: decr ( number)
Expand to the numerical value of number, incrementedor decremented, respectively, by one. Except for the empty string, theexpansion is empty ifnumber could not be parsed.
The macros
incr
anddecr
are recognized only withparameters.
incr(`4') ⇒5 decr(`7') ⇒6 incr() error-->m4:stdin:3: empty string treated as 0 in builtin `incr' ⇒1 decr() error-->m4:stdin:4: empty string treated as 0 in builtin `decr' ⇒-1
12.2 Evaluating integer expressions
Integer expressions are evaluated witheval
:
Expands to the value of expression. The expansion is emptyif a problem is encountered while parsing the arguments. If specified,radix andwidth control the format of the output.
Calculations are done with 32-bit signed numbers. Overflow silentlyresults in wraparound. A warning is issued if division by zero isattempted, or ifexpression could not be parsed.
Expressions can contain the following operators, listed in order ofdecreasing precedence.
‘ ()’
- Parentheses
‘ + - ~ !’
- Unary plus and minus, and bitwise and logical negation
‘ **’
- Exponentiation
‘ * / %’
- Multiplication, division, and modulo
‘ + -’
- Addition and subtraction
‘ << >>’
- Shift left or right
‘ > >= < <=’
- Relational operators
‘ == !=’
- Equality operators
‘ &’
- Bitwise and
‘ ^’
- Bitwise exclusive-or
‘ |’
- Bitwise or
‘ &&’
- Logical and
‘ ||’
- Logical or
The macro
eval
is recognized only with parameters.
All binary operators, except exponentiation, are left associative. Coperators that perform variable assignment, such as ‘+=’ or‘--’, are not implemented, sinceeval
only operates onconstants, not variables. Attempting to use them results in an error. However, since traditional implementations treated ‘=’ as anundocumented alias for ‘==’ as opposed to an assignment operator,this usage is supported as a special case. Be aware that a futureversion of GNU M4 may support assignment semantics as anextension when POSIX mode is not requested, and that using‘=’ to check equality is not portable.
eval(`2 = 2') error-->m4:stdin:1: Warning: recommend ==, not =, for equality operator ⇒1 eval(`++0') error-->m4:stdin:2: invalid operator in eval: ++0 ⇒ eval(`0 |= 1') error-->m4:stdin:3: invalid operator in eval: 0 |= 1 ⇒
Note that some older m4
implementations use ‘^’ as analternate operator for the exponentiation, although POSIXrequires the C behavior of bitwise exclusive-or. The precedence of thenegation operators, ‘~’ and ‘!’, was traditionally lower thanequality. The unary operators could not be used reliably more than onceon the same term without intervening parentheses. The traditionalprecedence of the equality operators ‘==’ and ‘!=’ wasidentical instead of lower than the relational operators such as‘<’, even through GNU M4 1.4.8. Starting with version1.4.9, GNU M4 correctly follows POSIX precedencerules. M4 scripts designed to be portable between releases must beaware that parentheses may be required to enforce C precedence rules. Likewise, division by zero, even in the unused branch of ashort-circuiting operator, is not always well-defined in otherimplementations.
Following are some examples where the current version of M4 follows Cprecedence rules, but where older versions and some otherimplementations ofm4
require explicit parentheses to get thecorrect result:
eval(`1 == 2 > 0') ⇒1 eval(`(1 == 2) > 0') ⇒0 eval(`! 0 * 2') ⇒2 eval(`! (0 * 2)') ⇒1 eval(`1 | 1 ^ 1') ⇒1 eval(`(1 | 1) ^ 1') ⇒0 eval(`+ + - ~ ! ~ 0') ⇒1 eval(`2 || 1 / 0') ⇒1 eval(`0 || 1 / 0') error-->m4:stdin:9: divide by zero in eval: 0 || 1 / 0 ⇒ eval(`0 && 1 % 0') ⇒0 eval(`2 && 1 % 0') error-->m4:stdin:11: modulo by zero in eval: 2 && 1 % 0 ⇒
As a GNU extension, the operator ‘**’ performs integralexponentiation. The operator is right-associative, and if evaluated,the exponent must be non-negative, and at least one of the argumentsmust be non-zero, or a warning is issued.
eval(`2 ** 3 ** 2') ⇒512 eval(`(2 ** 3) ** 2') ⇒64 eval(`0 ** 1') ⇒0 eval(`2 ** 0') ⇒1 eval(`0 ** 0') ⇒ error-->m4:stdin:5: divide by zero in eval: 0 ** 0 eval(`4 ** -2') error-->m4:stdin:6: negative exponent in eval: 4 ** -2 ⇒
Within expression, (but not radix or width), numberswithout a special prefix are decimal. A simple ‘0’ prefixintroduces an octal number. ‘0x’ introduces a hexadecimal number. As GNU extensions, ‘0b’ introduces a binary number. ‘0r’ introduces a number expressed in any radix between 1 and 36:the prefix should be immediately followed by the decimal expression ofthe radix, a colon, then the digits making the number. For radix 1,leading zeros are ignored, and all remaining digits must be ‘1’;for all other radices, the digits are ‘0’, ‘1’, ‘2’,.... Beyond ‘9’, the digits are ‘a’, ‘b’... upto ‘z’. Lower and upper case letters can be used interchangeablyin numbers prefixes and as number digits.
Parentheses may be used to group subexpressions whenever needed. For therelational operators, a true relation returns1
, and a falserelation return 0
.
Here are a few examples of use of eval
.
eval(`-3 * 5') ⇒-15 eval(`-99 / 10') ⇒-9 eval(`-99 % 10') ⇒-9 eval(`99 % -10') ⇒9 eval(index(`Hello world', `llo') >= 0) ⇒1 eval(`0r1:0111 + 0b100 + 0r3:12') ⇒12 define(`square', `eval(`($1) ** 2')') ⇒ square(`9') ⇒81 square(square(`5')` + 1') ⇒676 define(`foo', `666') ⇒ eval(`foo / 6') error-->m4:stdin:11: bad expression in eval: foo / 6 ⇒ eval(foo / 6) ⇒111
As the last two lines show, eval
does not handle macronames, even if they expand to a valid expression (or part of a validexpression). Therefore all macros must be expanded before they arepassed toeval
.
Some calculations are not portable to other implementations, since theyhave undefined semantics in C, but GNUm4
haswell-defined behavior on overflow. When shifting, an out-of-range shiftamount is implicitly brought into the range of 32-bit signed integersusing an implicit bit-wise and with 0x1f).
define(`max_int', eval(`0x7fffffff')) ⇒ define(`min_int', incr(max_int)) ⇒ eval(min_int` < 0') ⇒1 eval(max_int` > 0') ⇒1 ifelse(eval(min_int` / -1'), min_int, `overflow occurred') ⇒overflow occurred min_int ⇒-2147483648 eval(`0x80000000 % -1') ⇒0 eval(`-4 >> 1') ⇒-2 eval(`-4 >> 33') ⇒-2
If radix is specified, it specifies the radix to be used in theexpansion. The default radix is 10; this is also the case ifradix is the empty string. A warning results if the radix isoutside the range of 1 through 36, inclusive. The result of eval
is always taken to be signed. No radix prefix is output, and forradices greater than 10, the digits are lower case. Thewidthargument specifies the minimum output width, excluding any negativesign. The result is zero-padded to extend the expansion to therequested width. A warning results if the width is negative. Ifradix orwidth is out of bounds, the expansion ofeval
is empty.
eval(`666', `10') ⇒666 eval(`666', `11') ⇒556 eval(`666', `6') ⇒3030 eval(`666', `6', `10') ⇒0000003030 eval(`-666', `6', `10') ⇒-0000003030 eval(`10', `', `0') ⇒10 `0r1:'eval(`10', `1', `11') ⇒0r1:01111111111 eval(`10', `16') ⇒a eval(`1', `37') error-->m4:stdin:9: radix 37 in builtin `eval' out of range ⇒ eval(`1', , `-1') error-->m4:stdin:10: negative width to builtin `eval' ⇒ eval() error-->m4:stdin:11: empty string treated as 0 in builtin `eval' ⇒0
13 Macros for running shell commands
There are a few builtin macros in m4
that allow you to run shellcommands from withinm4
.
Note that the definition of a valid shell command is system dependent. On UNIX systems, this is the typical/bin/sh. But on othersystems, such as native Windows, the shell has a different syntax ofcommands that it understands. Some examples in this chapter assume/bin/sh, and also demonstrate how to quit early with a knownexit value if this is not the case.
13.1 Determining the platform
Sometimes it is desirable for an input file to know which platformm4
is running on. GNUm4
provides severalmacros that are predefined to expand to the empty string; checking fortheir existence will confirm platform details.
— Optional builtin: __os2__
— Optional builtin: os2
— Optional builtin: __unix__
— Optional builtin: unix
— Optional builtin: __windows__
— Optional builtin: windows
Each of these macros is conditionally defined as needed to describe theenvironment of
m4
. If defined, each macro expands to the emptystring. For now, these macros silently ignore all arguments, but in afuture release of M4, they might warn if arguments are present.
When GNU extensions are in effect (that is, when you did notuse the -G option, seeInvoking m4),GNU m4
will define the macro__gnu__
toexpand to the empty string.
$ m4 __gnu__ ⇒ __gnu__(`ignored') ⇒ Extensions are ifdef(`__gnu__', `active', `inactive') ⇒Extensions are active
$ m4 -G __gnu__ ⇒__gnu__ __gnu__(`ignored') ⇒__gnu__(ignored) Extensions are ifdef(`__gnu__', `active', `inactive') ⇒Extensions are inactive
On UNIX systems, GNU m4
will define __unix__
by default, orunix
when the -G option is specified.
On native Windows systems, GNU m4
will define__windows__
by default, orwindows
when the-G option is specified.
On OS/2 systems, GNU m4
will define __os2__
by default, oros2
when the -G option is specified.
If GNU m4
does not provide a platform macro for your system,please report that as a bug.
define(`provided', `0') ⇒ ifdef(`__unix__', `define(`provided', incr(provided))') ⇒ ifdef(`__windows__', `define(`provided', incr(provided))') ⇒ ifdef(`__os2__', `define(`provided', incr(provided))') ⇒ provided ⇒1
13.2 Executing simple commands
Any shell command can be executed, using syscmd
:
Executes shell-command as a shell command.
The expansion of
syscmd
is void, not the output fromshell-command! Output or error messages fromshell-commandare not read bym4
. See Esyscmd, if you need to process thecommand output.Prior to executing the command,
m4
flushes its buffers. The default standard input, output and error ofshell-command arethe same as those ofm4
.By default, the shell-command will be used as the argument to the-c option of the/bin/sh shell (or the version ofsh specified by ‘command -p getconf PATH’, if your systemsupports that). If you prefer a different shell, theconfigure script can be given the option--with-syscmd-shell=location to set the location of analternative shell at GNU
m4
installation; thealternative shell must still support -c.The macro
syscmd
is recognized only with parameters.
define(`foo', `FOO') ⇒ syscmd(`echo foo') ⇒foo ⇒
Note how the expansion of syscmd
keeps the trailing newline ofthe command, as well as using the newline that appeared after the macro.
The following is an example of shell-command using the samestandard input asm4
:
$ echo "m4wrap(\`syscmd(\`cat')')" | m4 ⇒
It tells m4
to read all of its input before executing the wrappedtext, then hand a valid (albeit emptied) pipe as standard input for thecat
subcommand. Therefore, you should be careful when usingstandard input (either by specifying no files, or by passing ‘-’ asa file name on the command line, seeInvoking m4), and also invoking subcommands viasyscmd
or esyscmd
that consume data from standard input. When standard input is aseekable file, the subprocess will pick up with the next character notyet processed bym4
; when it is a pipe or other non-seekablefile, there is no guarantee how much data will already be buffered bym4
and thus unavailable to the child.
13.3 Reading the output of commands
If you want m4
to read the output of a shell command, useesyscmd
:
Expands to the standard output of the shell commandshell-command.
Prior to executing the command,
m4
flushes its buffers. The default standard input and standard error ofshell-command arethe same as those ofm4
. The error output ofshell-commandis not a part of the expansion: it will appear along with the erroroutput ofm4
.By default, the shell-command will be used as the argument to the-c option of the/bin/sh shell (or the version ofsh specified by ‘command -p getconf PATH’, if your systemsupports that). If you prefer a different shell, theconfigure script can be given the option--with-syscmd-shell=location to set the location of analternative shell at GNU
m4
installation; thealternative shell must still support -c.The macro
esyscmd
is recognized only with parameters.
define(`foo', `FOO') ⇒ esyscmd(`echo foo') ⇒FOO ⇒
Note how the expansion of esyscmd
keeps the trailing newline ofthe command, as well as using the newline that appeared after the macro.
Just as with syscmd
, care must be exercised when sharing standardinput betweenm4
and the child process of esyscmd
.
13.4 Exit status
To see whether a shell command succeeded, use sysval
:
Expands to the exit status of the last shell command run with
syscmd
oresyscmd
. Expands to 0 if no command has beenrun yet.
sysval ⇒0 syscmd(`false') ⇒ ifelse(sysval, `0', `zero', `non-zero') ⇒non-zero syscmd(`exit 2') ⇒ sysval ⇒2 syscmd(`true') ⇒ sysval ⇒0 esyscmd(`false') ⇒ ifelse(sysval, `0', `zero', `non-zero') ⇒non-zero esyscmd(`echo dnl && exit 127') ⇒ sysval ⇒127 esyscmd(`true') ⇒ sysval ⇒0
sysval
results in 127 if there was a problem executing thecommand, for example, if the system-imposed argument length is exceeded,or if there were not enough resources to fork. It is not possible todistinguish between failed execution and successful execution that hadan exit status of 127, unless there was output from the child process.
On UNIX platforms, where it is possible to detect when command executionis terminated by a signal, rather than a normal exit, the result is thesignal number shifted left by eight bits.
dnl This test assumes kill is a shell builtin, and that signals are dnl recognizable. ifdef(`__unix__', , `errprint(` skipping: syscmd does not have unix semantics ')m4exit(`77')')dnl syscmd(`kill -9 $$') ⇒ sysval ⇒2304 syscmd() ⇒ sysval ⇒0 esyscmd(`kill -9 $$') ⇒ sysval ⇒2304
13.5 Making temporary files
Commands specified tosyscmd
or esyscmd
might need atemporary file, for output or for some other purpose. There is abuiltin macro,mkstemp
, for making a temporary file:
— Builtin: maketemp ( template)
Expands to the quoted name of a new, empty file, made from the stringtemplate, which should end with the string ‘XXXXXX’. The six‘X’ characters are then replaced with random characters matchingthe regular expression ‘[a-zA-Z0-9._-]’, in order to make the filename unique. If fewer than six ‘X’ characters are found at the endof
template
, the result will be longer than the template. Thecreated file will have access permissions as if bychmod =rw,go=,meaning that the current umask of them4
process is taken intoaccount, and at most only the current user can read and write the file.The traditional behavior, standardized by POSIX, is that
maketemp
merely replaces the trailing ‘X’ with the processid, without creating a file or quoting the expansion, and withoutensuring that the resultingstring is a unique file name. In part, this means that using the sametemplate twice in the same input file will result in the sameexpansion. This behavior is a security hole, as it is very easy foranother process to guess the name that will be generated, and thusinterfere with a subsequent use ofsyscmd
trying to manipulatethat file name. Hence, POSIX has recommended that all newimplementations ofm4
provide the securemkstemp
builtin,and that users ofm4
check for its existence.The expansion is void and an error issued if a temporary file couldnot be created.
The macros
mkstemp
andmaketemp
are recognized only withparameters.
If you try this next example, you will most likely get different outputfor the two file names, since the replacement characters are randomlychosen:
$ m4 define(`tmp', `oops') ⇒ maketemp(`/tmp/fooXXXXXX') ⇒/tmp/fooa07346 ifdef(`mkstemp', `define(`maketemp', defn(`mkstemp'))', `define(`mkstemp', defn(`maketemp'))dnl errprint(`warning: potentially insecure maketemp implementation ')') ⇒ mkstemp(`doc') ⇒docQv83Uw
Unless you use the --traditional command line option (or-G, seeInvoking m4), the GNUversion of maketemp
is secure. This means that using the sametemplate to multiple calls will generate multiple files. However, werecommend that you use the newmkstemp
macro, introduced inGNU M4 1.4.8, which is secure even in traditional mode. Also,as of M4 1.4.11, the secure implementation quotes the resulting filename, so that you are guaranteed to know what file was created even ifthe random file name happens to match an existing macro. Notice thatthis example is careful to use defn
to avoid unintended expansionof ‘foo’.
$ m4 define(`foo', `errprint(`oops')') ⇒ syscmd(`rm -f foo-??????')sysval ⇒0 define(`file1', maketemp(`foo-XXXXXX'))dnl ifelse(esyscmd(`echo \` foo-?????? \''), ` foo-?????? ', `no file', `created') ⇒created define(`file2', maketemp(`foo-XX'))dnl define(`file3', mkstemp(`foo-XXXXXX'))dnl ifelse(len(defn(`file1')), len(defn(`file2')), `same length', `different') ⇒same length ifelse(defn(`file1'), defn(`file2'), `same', `different file') ⇒different file ifelse(defn(`file2'), defn(`file3'), `same', `different file') ⇒different file ifelse(defn(`file1'), defn(`file3'), `same', `different file') ⇒different file syscmd(`rm 'defn(`file1') defn(`file2') defn(`file3')) ⇒ sysval ⇒0
14 Miscellaneous builtin macros
This chapter describes various builtins, that do not really belong inany of the previous chapters.
14.1 Printing error messages
You can print error messages usingerrprint
:
Prints message and the rest of the arguments to standard error,separated by spaces. Standard error is used, regardless of the--debugfile option (seeInvoking m4).
The expansion of
errprint
is void. The macroerrprint
is recognized only with parameters.
errprint(`Invalid arguments to forloop ') error-->Invalid arguments to forloop ⇒ errprint(`1')errprint(`2',`3 ') error-->12 3 ⇒
A trailing newline is not printed automatically, so it should besupplied as part of the argument, as in the example. Unfortunately, theexact output oferrprint
is not very portable to other m4
implementations: POSIX requires that all arguments be printed,but some implementations ofm4
only print the first. Furthermore, some BSD implementations always append a newlinefor eacherrprint
call, regardless of whether the last argumentalready had one, and POSIX is silent on whether this isacceptable.
14.2 Printing current location
To make it possible to specify the location of an error, threeutility builtins exist:
— Builtin: __line__
— Builtin: __program__
Expand to the quoted name of the current input file, thecurrent input line number in that file, and the quoted name of thecurrent invocation of
m4
.
errprint(__program__:__file__:__line__: `input error ') error-->m4:stdin:1: input error ⇒
Line numbers start at 1 for each file. If the file was found due to the-I option orM4PATH environment variable, that isreflected in the file name. The syncline option (-s,seeInvoking m4), and the‘f’ and ‘l’ flags ofdebugmode
(see Debug Levels),also use this notion of current file and line. Redefining the threelocation macros has no effect on syncline, debug, warning, or errormessage output.
This example reuses the file incl.m4 mentioned earlier(seeInclude):
$ m4 -I examples define(`foo', ``$0' called at __file__:__line__') ⇒ foo ⇒foo called at stdin:2 include(`incl.m4') ⇒Include file start ⇒foo called at examples/incl.m4:2 ⇒Include file end ⇒
The location of macros invoked during the rescanning of macro expansiontext corresponds to the location in the file where the expansion wastriggered, regardless of how many newline characters the expansion textcontains. As of GNU M4 1.4.8, the location of text wrappedwith m4wrap
(see M4wrap) is the point at which them4wrap
was invoked. Previous versions, however, behaved asthough wrapped text came from line 0 of the file “”.
define(`echo', `$@') ⇒ define(`foo', `echo(__line__ __line__)') ⇒ echo(__line__ __line__) ⇒4 ⇒5 m4wrap(`foo ') ⇒ foo(errprint(__line__ __line__ )) error-->8 error-->9 ⇒8 ⇒8 __line__ ⇒11 m4wrap(`__line__ ') ⇒ ^D ⇒12 ⇒6 ⇒6
The __program__
macro behaves like ‘$0’ in shellterminology. If you invokem4
through an absolute path or a linkwith a different spelling, rather than by relying on aPATH searchfor plain ‘m4’, it will affect how__program__
expands. The intent is that you can use it to produce error messages with thesame formatting thatm4
produces internally. It can also be usedwithin syscmd
(seeSyscmd) to pick the same version ofm4
that is currently running, rather than whatever version ofm4
happens to be first inPATH. It was first introduced inGNU M4 1.4.6.
14.3 Exiting from m4
If you need to exit fromm4
before the entire input has beenread, you can use m4exit
:
Causes
m4
to exit, with exit status code. If code isleft out, the exit status is zero. Ifcode cannot be parsed, oris outside the range of 0 to 255, the exit status is one. No furtherinput is read, and all wrapped and diverted text is discarded.
m4wrap(`This text is lost due to `m4exit'.') ⇒ divert(`1') So is this. divert ⇒ m4exit And this is never read.
A common use of this is to abort processing:
Abort processing with an error message and non-zero status. Prefixmessage with details about where the error occurred, and print theresulting string to standard error.
define(`fatal_error', `errprint(__program__:__file__:__line__`: fatal error: $* ')m4exit(`1')') ⇒ fatal_error(`this is a BAD one, buster') error-->m4:stdin:4: fatal error: this is a BAD one, buster
After this macro call, m4
will exit with exit status 1. This macrois only intended for error exits, since the normal exit procedures arenot followed, i.e., diverted text is not undiverted, and saved text(seeM4wrap) is not reread. (This macro could be made more robustto earlier versions ofm4
. You should try to see if you can findweaknesses and correct them; or seeAnswers).
Note that it is still possible for the exit status to be different thanwhat was requested bym4exit
. If m4
detects some othererror, such as a write error on standard output, the exit status will benon-zero even ifm4exit
requested zero.
If standard input is seekable, then the file will be positioned at thenext unread character. If it is a pipe or other non-seekable file,then there are no guarantees how much datam4
might have readinto buffers, and thus discarded.
15 Fast loading of frozen state
Some bigger m4
applications may be built over a common basecontaining hundreds of definitions and other costly initializations. Usually, the common base is kept in one or more declarative files,which files are listed on eachm4
invocation prior to theuser's input file, or else each input file usesinclude
.
Reading the common base of a big application, over and over again, maybe time consuming. GNUm4
offers some machinery tospeed up the start of an application using lengthy common bases.
15.1 Using frozen files
Suppose a user has a library of m4
initializations inbase.m4, which is then used with multiple input files:
$ m4 base.m4 input1.m4 $ m4 base.m4 input2.m4 $ m4 base.m4 input3.m4
Rather than spending time parsing the fixed contents of base.m4every time, the user might rather execute:
$ m4 -F base.m4f base.m4
once, and further execute, as often as needed:
$ m4 -R base.m4f input1.m4 $ m4 -R base.m4f input2.m4 $ m4 -R base.m4f input3.m4
with the varying input. The first call, containing the -Foption, only reads and executes file base.m4, definingvarious application macros and computing other initializations. Once the input filebase.m4 has been completely processed, GNUm4
produces inbase.m4f a frozen file, that is, afile which contains a kind of snapshot of them4
internal state.
Later calls, containing the -R option, are able to reloadthe internal state ofm4
, from base.m4f,prior to reading any other input files. This meansinstead of starting with a virgin copy ofm4
, input will beread after having effectively recovered the effect of a prior run. In our example, the effect is the same as if filebase.m4 hasbeen read anew. However, this effect is achieved a lot faster.
Only one frozen file may be created or read in any one m4
invocation. It is not possible to recover two frozen files at once. However, frozen files may be updated incrementally, through using-R and-F options simultaneously. For example, ifsome care is taken, the command:
$ m4 file1.m4 file2.m4 file3.m4 file4.m4
could be broken down in the following sequence, accumulating the sameoutput:
$ m4 -F file1.m4f file1.m4 $ m4 -R file1.m4f -F file2.m4f file2.m4 $ m4 -R file2.m4f -F file3.m4f file3.m4 $ m4 -R file3.m4f file4.m4
Some care is necessary because not every effort has been made forthis to work in all cases. In particular, the trace attribute ofmacros is not handled, nor the current setting ofchangeword
. Currently, m4wrap
and sysval
also have problems. Also, interactions for some options ofm4
, being used in one calland not in the next, have not been fully analyzed yet. On the otherend, you may be confident that stacks ofpushdef
definitionsare handled correctly, as well as undefined or renamed builtins, andchanged strings for quotes or comments. And future releases ofGNU M4 will improve on the utility of frozen files.
When an m4
run is to be frozen, the automatic undiversionwhich takes place at end of execution is inhibited. Instead, allpositively numbered diversions are saved into the frozen file. The active diversion number is also transmitted.
A frozen file to be reloaded need not reside in the current directory. It is looked up the same way as aninclude
file (see Search Path).
If the frozen file was generated with a newer version of m4
, andcontains directives that an olderm4
cannot parse, attempting toload the frozen file with option -R will cause m4
toexit with status 63 to indicate version mismatch.
15.2 Frozen file format
Frozen files are sharable across architectures. It is safe to writea frozen file on one machine and read it on another, given that thesecond machine uses the same or newer version of GNU m4
. It is conventional, but not required, to give a frozen file the suffixof.m4f
.
These are simple (editable) text files, made up of directives,each starting with a capital letter and ending with a newline(<NL>). Wherever a directive is expected, the character‘#’ introduces a comment line; empty lines are also ignored if theyare not part of an embedded string. In the following descriptions, eachlen refers to the length ofthe corresponding strings str in the next line of input. Numbersare always expressed in decimal. There are no escape characters. Thedirectives are:
-
Uses
str1 and
str2 as the begin-comment andend-comment strings. If omitted, then ‘
#’ and <NL> are thecomment delimiters.
-
Selects diversion
number, making it current, then copy
str in the current diversion.
number may be a negativenumber for a non-existing diversion. To merely specify an activeselection, use this command with an empty
str. With 0 as thediversion
number,
str will be issued on standard outputat reload time. GNU
m4
will not produce the ‘ D’directive with non-zero length for diversion 0, but this can be donewith manual edits. This directive mayappear more than once for the same diversion, in which case thediversion is the concatenation of the various uses. If omitted, thendiversion 0 is current.
-
Defines, through
pushdef
, a definition for str1expanding to the function whose builtin name is str2. If thebuiltin does not exist (for example, if the frozen file was produced bya copy ofm4
compiled with changeword support, but the versionofm4
reloading was compiled without it), the reload is silent,but any subsequent use of the definition of str1 will result ina warning. This directive may appear more than once for the same name,and its order, along with ‘ T’, is important. If omitted, you willhave no access to any builtins.
-
Uses
str1 and
str2 as the begin-quote and end-quotestrings. If omitted, then ‘
`’ and ‘
'’ are the quotedelimiters.
-
Defines, though
pushdef
, a definition for str1expanding to the text given by str2. This directive may appearmore than once for the same name, and its order, along with ‘ F’, isimportant.
-
Confirms the format of the file.
m4
1.4.16 only createsand understands frozen files where number is 1. This directivemust be the first non-comment in the file, and may not appear more thanonce.
C
len1
,
len2
<NL>
str1
str2
<NL>
D
number
,
len
<NL>
str
<NL>
F
len1
,
len2
<NL>
str1
str2
<NL>
Q
len1
,
len2
<NL>
str1
str2
<NL>
T
len1
,
len2
<NL>
str1
str2
<NL>
V
number
<NL>
16 Compatibility with other versions of m4
This chapter describes the many of the differences between thisimplementation ofm4
, and of other implementations found underUNIX, such as System V Release 3, Solaris, and BSD flavors. In particular, it lists the known differences and extensions toPOSIX. However, the list is not necessarily comprehensive.
At the time of this writing, POSIX 2001 (also known as IEEEStd 1003.1-2001) is the latest standard, although a new version ofPOSIX is under development and includes several proposals formodifying whatm4
is required to do. The requirements form4
are shared between SUSv3 and POSIX, andcan be viewed athttp://www.opengroup.org/onlinepubs/000095399/utilities/m4.html.
16.1 Extensions in GNU M4
This version ofm4
contains a few facilities that do not existin System V m4
. These extra facilities are all suppressed byusing the-G command line option (see Invoking m4), unless overridden by other command line options.
- In the
$
n notation for macro arguments, n can containseveral digits, while the System Vm4
only accepts one digit. This allows macros in GNUm4
to take any number ofarguments, and not only nine (seeArguments).This means that
define(`foo', `$11')
is ambiguous betweenimplementations. To portably choose between grabbing the firstparameter and appending 1 to the expansion, or grabbing the eleventhparameter, you can do the following:define(`a1', `A1') ⇒ dnl First argument, concatenated with 1 define(`_1', `$1')define(`first1', `_1($@)1') ⇒ dnl Eleventh argument, portable define(`_9', `$9')define(`eleventh', `_9(shift(shift($@)))') ⇒ dnl Eleventh argument, GNU style define(`Eleventh', `$11') ⇒ first1(`a', `b', `c', `d', `e', `f', `g', `h', `i', `j', `k') ⇒A1 eleventh(`a', `b', `c', `d', `e', `f', `g', `h', `i', `j', `k') ⇒k Eleventh(`a', `b', `c', `d', `e', `f', `g', `h', `i', `j', `k') ⇒k
Also see the
argn
macro (see Shift). - The
divert
(see Divert) macro can manage more than 9diversions. GNUm4
treats all positive numbers as validdiversions, rather than discarding diversions greater than 9. - Files included with
include
andsinclude
are sought in auser specified search path, if they are not found in the workingdirectory. The search path is specified by the-I option and theM4PATH environment variable (seeSearch Path). - Arguments to
undivert
can be non-numeric, in which case the namedfile will be included uninterpreted in the output (seeUndivert). - Formatted output is supported through the
format
builtin, whichis modeled after the C library functionprintf
(see Format). - Searches and text substitution through basic regular expressions aresupported by the
regexp
(see Regexp) andpatsubst
(seePatsubst) builtins. Some BSD implementations useextended regular expressions instead. - The output of shell commands can be read into
m4
withesyscmd
(seeEsyscmd). - There is indirect access to any builtin macro with
builtin
(see Builtin). - Macros can be called indirectly through
indir
(see Indir). - The name of the program, the current input file, and the current inputline number are accessible through the builtins
__program__
,__file__
, and__line__
(see Location). - The format of the output from
dumpdef
and macro tracing can becontrolled withdebugmode
(see Debug Levels). - The destination of trace and debug output can be controlled with
debugfile
(seeDebug Output). - The
maketemp
(see Mkstemp) macro behaves likemkstemp
,creating a new file with a unique name on every invocation, rather thanfollowing the insecure behavior of replacing the trailing ‘X’characters with them4
process id. - POSIX only requires support for the command line options-s,-D, and -U, so all other options acceptedby GNU M4 are extensions. SeeInvoking m4, for adescription of these options.
The debugging and tracing facilities in GNU
m4
are muchmore extensive than in most other versions ofm4
.
16.2 Facilities in System V m4
not in GNU m4
The version of m4
from System V contains a few facilities thathave not been implemented in GNUm4
yet. Additionally,POSIX requires some behaviors that GNU m4
has notimplemented yet. Relying on these behaviors is non-portable, as afuture release of GNUm4
may change.
- POSIX requires support for multiple arguments to
defn
,without any clarification on howdefn
behaves when one of themultiple arguments names a builtin. System Vm4
and some otherimplementations allow mixing builtins and text macros into a singlemacro. GNUm4
only supports joining multiple textarguments, although a future implementation may lift this restriction tobehave more like System V. The only portable way to join text macroswith builtins is via helper macros and implicit concatenation of macroresults. - POSIX requires an application to exit with non-zero status ifit wrote an error message to stderr. This has not yet been consistentlyimplemented for the various builtins that are required to issue an error(such as
eval
(see Eval) when an argument cannot be parsed). - Some traditional implementations only allow reading standard inputonce, but GNU
m4
correctly handles multiple instancesof ‘-’ on the command line. - POSIX requires
m4wrap
(see M4wrap) to act in FIFO(first-in, first-out) order, but GNUm4
currently usesLIFO order. Furthermore, POSIX states that only the firstargument tom4wrap
is saved for later evaluation, butGNUm4
saves and processes all arguments, with outputseparated by spaces. - POSIX states that builtins that require arguments, but arecalled without arguments, have undefined behavior. Traditionalimplementations simply behave as though empty strings had been passed. For example,
a`'define`'b
would expand toab
. ButGNUm4
ignores certain builtins if they have missingarguments, givingadefineb
for the above example. - Traditional implementations handle
define(`f',`1')
(see Define)by undefining the entire stack of previous definitions, and if doingundefine(`f')
first. GNUm4
replaces just the topdefinition on the stack, as if doingpopdef(`f')
followed bypushdef(`f',`1')
. POSIX allows either behavior. - POSIX 2001 requires
syscmd
(see Syscmd) to evaluatecommand output for macro expansion, but this was a mistake that isanticipated to be corrected in the next version of POSIX. GNUm4
follows traditional behavior insyscmd
where output is not rescanned, and provides the extensionesyscmd
that does scan the output. - At one point, POSIX required
changequote(
arg)
(seeChangequote) to use newline as the close quote, but this was abug, and the next version of POSIX is anticipated to statethat using empty strings or just one argument is unspecified. Meanwhile, the GNUm4
behavior of treating an emptyend-quote delimiter as ‘'’ is not portable, as Solaris treats it asrepeating the start-quote delimiter, and BSD treats it as leaving theprevious end-quote delimiter unchanged. For predictable results, nevercall changequote with just one argument, or with empty strings forarguments. - At one point, POSIX required
changecom(
arg,)
(seeChangecom) to make it impossible to end a comment, but this isa bug, and the next version of POSIX is anticipated to statethat using empty strings is unspecified. Meanwhile, the GNUm4
behavior of treating an empty end-comment delimiter as newlineis not portable, as BSD treats it as leaving the previous end-commentdelimiter unchanged. It is also impossible in BSD implementations todisable comments, even though that is required by POSIX. Forpredictable results, never call changecom with empty strings forarguments. - Most implementations of
m4
give macros a higher precedence thancomments when parsing, meaning that if the start delimiter given tochangecom
(seeChangecom) starts with a macro name, commentsare effectively disabled. POSIX does not specify what theprecedence is, so this version of GNUm4
parserrecognizes comments, then macros, then quoted strings. - Traditional implementations allow argument collection, but not stringand comment processing, to span file boundaries. Thus, ifa.m4contains ‘len(’, andb.m4 contains ‘abc)’,m4 a.m4 b.m4 outputs ‘3’ with traditional
m4
, butgives an error message that the end of file was encountered inside amacro with GNUm4
. On the other hand, traditionalimplementations do end of file processing for files included withinclude
orsinclude
(see Include), while GNUm4
seamlessly integrates the content of those files. Thusinclude(`a.m4')include(`b.m4')
will output ‘3’ instead ofgiving an error. - Traditional
m4
treatstraceon
(see Trace) withoutarguments as a global variable, independent of named macro tracing. Also, once a macro is undefined, named tracing of that macro is lost. On the other hand, when GNUm4
encounterstraceon
withoutarguments, it turns tracing on for all existing definitions at the time,but does not trace future definitions;traceoff
without argumentsturns tracing off for all definitions regardless of whether they werealso traced by name; and tracing by name, such as with-tfoo atthe command line ortraceon(`foo')
in the input, is an attributethat is preserved even if the macro is currently undefined.Additionally, while POSIX requires trace output, it makes nodemands on the formatting of that output. Parsing trace output is notguaranteed to be reliable, even between different releases ofGNU M4; however, the intent is that any future changes intrace output will only occur under the direction of additional
debugmode
flags (seeDebug Levels). - POSIX requires
eval
(see Eval) to treat alloperators with the same precedence as C. However, earlier versions ofGNUm4
followed the traditional behavior of otherm4
implementations, where bitwise and logical negation (‘~’and ‘!’) have lower precedence than equality operators; and whereequality operators (‘==’ and ‘!=’) had the same precedence asrelational operators (such as ‘<’). Use explicit parentheses toensure proper precedence. As extensions to POSIX,GNUm4
gives well-defined semantics to operations thatC leaves undefined, such as when overflow occurs, when shifting negativenumbers, or when performing division by zero. POSIX alsorequires ‘=’ to cause an error, but many traditionalimplementations allowed it as an alias for ‘==’. - POSIX 2001 requires
translit
(see Translit) totreat each character of the second and third arguments literally. However, it is anticipated that the next version of POSIX willallow the GNUm4
behavior of treating ‘-’ as arange operator. - POSIX requires
m4
to honor the locale environmentvariables of LANG, LC_ALL,LC_CTYPE,LC_MESSAGES, andNLSPATH, but this has not yet beenimplemented in GNUm4
. - POSIX states that only unquoted leading newlines and blanks(that is, space and tab) are ignored when collecting macro arguments. However, this appears to be a bug in POSIX, since mosttraditional implementations also ignore all whitespace (formfeed,carriage return, and vertical tab). GNU
m4
followstradition and ignores all leading unquoted whitespace. - A strictly-compliant POSIX client is not allowed to usecommand-line arguments not specified by POSIX. However, sincethis version of M4 ignoresPOSIXLY_CORRECT and enables the option
--gnu
by default (seeInvoking m4), aclient desiring to be strictly compliant has no way to disableGNU extensions that conflict with POSIX whendirectly invoking the compiledm4
. A future version ofGNU
M4 will honor the environment variablePOSIXLY_CORRECT,implicitly enabling --traditional if it is set, in order toallow a strictly-compliant client. In the meantime, a client needingstrict POSIX compliance can use the workaround of invoking ashell script wrapper, where the wrapper then adds --traditionalto the arguments passed to the compiledm4
.
16.3 Other incompatibilities
There are a few other incompatibilities between this implementation ofm4
, and the System V version.
- GNU
m4
implements sync lines differently from System Vm4
, when text is being diverted. GNUm4
outputsthe sync lines when the text is being diverted, and System Vm4
when the diverted text is being brought back.The problem is which lines and file names should be attached to textthat is being, or has been, diverted. System V
m4
regards allthe diverted text as being generated by the source line containing theundivert
call, whereas GNUm4
regards thediverted text as being generated at the time it is diverted.The sync line option is used mostly when using
m4
asa front end to a compiler. If a diverted line causes a compiler error,the error messages should most probably refer to the place where thediversion was made, and not where it was inserted again.divert(2)2 divert(1)1 divert`'0 ⇒#line 3 "stdin" ⇒0 ^D ⇒#line 2 "stdin" ⇒1 ⇒#line 1 "stdin" ⇒2
The current
m4
implementation has a limitation that the synclineoutput at the start of each diversion occurs no matter what, even if theprevious diversion did not end with a newline. This goes contrary tothe claim that synclines appear on a line by themselves, so thislimitation may be corrected in a future version ofm4
. In themeantime, when using -s, it is wisest to make sure alldiversions end with newline. - GNU
m4
makes no attempt at prohibiting self-referentialdefinitions like:define(`x', `x') ⇒ define(`x', `x ') ⇒
There is nothing inherently wrong with defining ‘x’ toreturn ‘x’. The wrong thing is to expand ‘x’ unquoted,because that would cause an infinite rescan loop. In
m4
, one might use macros to hold strings, as we do forvariables in other programming languages, further checking them with:ifelse(defn(`holder'), `value', ...)
In cases like this one, an interdiction for a macro to hold its own namewould be a useless limitation. Of course, this leaves more rope for theGNU
m4
user to hang himself! Rescanning hangs may beavoided through careful programming, a little like for endless loops intraditional programming languages.
17 Correct version of some examples
Some of the examples in this manuals are buggy or not very robust, fordemonstration purposes. Improved versions of these composite macros arepresented here.
17.1 Solution for exch
The exch
macro (see Arguments) as presented requires clientsto double quote their arguments. A nicer definition, which letsclients follow the rule of thumb of one level of quoting per level ofparentheses, involves adding quotes in the definition of exch
, asfollows:
define(`exch', ``$2', `$1'') ⇒ define(exch(`expansion text', `macro')) ⇒ macro ⇒expansion text
17.2 Solution for forloop
The forloop
macro (see Forloop) as presented earlier can gointo an infinite loop if given an iterator that is not parsed as a macroname. It does not do any sanity checking on its numeric bounds, andonly permits decimal numbers for bounds. Here is an improved version,shipped as m4-1.4.16/examples/forloop2.m4; thisversion also optimizes overhead by calling four macros instead of sixper iteration (excluding those intext), by not dereferencing theiterator in the helper _forloop
.
$ m4 -d -I examples undivert(`forloop2.m4')dnl ⇒divert(`-1') ⇒# forloop(var, from, to, stmt) - improved version: ⇒# works even if VAR is not a strict macro name ⇒# performs sanity check that FROM is larger than TO ⇒# allows complex numerical expressions in TO and FROM ⇒define(`forloop', `ifelse(eval(`($2) <= ($3)'), `1', ⇒ `pushdef(`$1')_$0(`$1', eval(`$2'), ⇒ eval(`$3'), `$4')popdef(`$1')')') ⇒define(`_forloop', ⇒ `define(`$1', `$2')$4`'ifelse(`$2', `$3', `', ⇒ `$0(`$1', incr(`$2'), `$3', `$4')')') ⇒divert`'dnl include(`forloop2.m4') ⇒ forloop(`i', `2', `1', `no iteration occurs') ⇒ forloop(`', `1', `2', ` odd iterator name') ⇒ odd iterator name odd iterator name forloop(`i', `5 + 5', `0xc', ` 0x`'eval(i, `16')') ⇒ 0xa 0xb 0xc forloop(`i', `a', `b', `non-numeric bounds') error-->m4:stdin:6: bad expression in eval (bad input): (a) <= (b) ⇒
One other change to notice is that the improved version used ‘_$0’rather than ‘_foreach’ to invoke the helper routine. In general,this is a good practice to follow, because then the set of macros can beuniformly transformed. The following example shows a transformationthat doubles the current quoting and appends a suffix ‘2’ to eachtransformed macro. Ifforeach
refers to the literal‘_foreach’, thenforeach2
invokes _foreach
instead ofthe intended _foreach2
, and the mixing of quoting paradigms leadsto an infinite recursion loop in this example.
$ m4 -d -L 9 -I examples define(`arg1', `$1')include(`forloop2.m4')include(`quote.m4') ⇒ define(`double', `define(`$1'`2', arg1(patsubst(dquote(defn(`$1')), `[`']', `\&\&')))') ⇒ double(`forloop')double(`_forloop')defn(`forloop2') ⇒ifelse(eval(``($2) <= ($3)''), ``1'', ⇒ ``pushdef(``$1'')_$0(``$1'', eval(``$2''), ⇒ eval(``$3''), ``$4'')popdef(``$1'')'') forloop(i, 1, 5, `ifelse(')forloop(i, 1, 5, `)') ⇒ changequote(`[', `]')changequote([``], ['']) ⇒ forloop2(i, 1, 5, ``ifelse('')forloop2(i, 1, 5, ``)'') ⇒ changequote`'include(`forloop.m4') ⇒ double(`forloop')double(`_forloop')defn(`forloop2') ⇒pushdef(``$1'', ``$2'')_forloop($@)popdef(``$1'') forloop(i, 1, 5, `ifelse(')forloop(i, 1, 5, `)') ⇒ changequote(`[', `]')changequote([``], ['']) ⇒ forloop2(i, 1, 5, ``ifelse('')forloop2(i, 1, 5, ``)'') error-->m4:stdin:12: recursion limit of 9 exceeded, use -L<N> to change it
One more optimization is still possible. Instead of repeatedlyassigning a variable then invoking or dereferencing it, it is possibleto pass the current iterator value as a single argument. Coupled withcurry
if other arguments are needed (seeComposition), orwith helper macros if the argument is needed in more than one place inthe expansion, the output can be generated with three, rather than four,macros of overhead per iteration. Notice how the filem4-1.4.16/examples/forloop3.m4 rearranges thearguments of the helper _forloop
to take two arguments that areplaced around the current value. By splitting a balanced set ofparantheses across multiple arguments, the helper macro can now beshared byforloop
and the new forloop_arg
.
$ m4 -I examples include(`forloop3.m4') ⇒ undivert(`forloop3.m4')dnl ⇒divert(`-1') ⇒# forloop_arg(from, to, macro) - invoke MACRO(value) for ⇒# each value between FROM and TO, without define overhead ⇒define(`forloop_arg', `ifelse(eval(`($1) <= ($2)'), `1', ⇒ `_forloop(`$1', eval(`$2'), `$3(', `)')')') ⇒# forloop(var, from, to, stmt) - refactored to share code ⇒define(`forloop', `ifelse(eval(`($2) <= ($3)'), `1', ⇒ `pushdef(`$1')_forloop(eval(`$2'), eval(`$3'), ⇒ `define(`$1',', `)$4')popdef(`$1')')') ⇒define(`_forloop', ⇒ `$3`$1'$4`'ifelse(`$1', `$2', `', ⇒ `$0(incr(`$1'), `$2', `$3', `$4')')') ⇒divert`'dnl forloop(`i', `1', `3', ` i') ⇒ 1 2 3 define(`echo', `$@') ⇒ forloop_arg(`1', `3', ` echo') ⇒ 1 2 3 include(`curry.m4') ⇒ forloop_arg(`1', `3', `curry(`pushdef', `a')') ⇒ a ⇒3 popdef(`a')a ⇒2 popdef(`a')a ⇒1 popdef(`a')a ⇒a
Of course, it is possible to make even more improvements, such asadding an optional step argument, or allowing iteration throughdescending sequences. GNU Autoconf provides some of theseadditional bells and whistles in itsm4_for
macro.
17.3 Solution for foreach
The foreach
and foreachq
macros (see Foreach) aspresented earlier each have flaws. First, we will examine and fix thequadratic behavior offoreachq
:
$ m4 -I examples include(`foreachq.m4') ⇒ traceon(`shift')debugmode(`aq') ⇒ foreachq(`x', ``1', `2', `3', `4'', `x ')dnl ⇒1 error-->m4trace: -3- shift(`1', `2', `3', `4') error-->m4trace: -2- shift(`1', `2', `3', `4') ⇒2 error-->m4trace: -4- shift(`1', `2', `3', `4') error-->m4trace: -3- shift(`2', `3', `4') error-->m4trace: -3- shift(`1', `2', `3', `4') error-->m4trace: -2- shift(`2', `3', `4') ⇒3 error-->m4trace: -5- shift(`1', `2', `3', `4') error-->m4trace: -4- shift(`2', `3', `4') error-->m4trace: -3- shift(`3', `4') error-->m4trace: -4- shift(`1', `2', `3', `4') error-->m4trace: -3- shift(`2', `3', `4') error-->m4trace: -2- shift(`3', `4') ⇒4 error-->m4trace: -6- shift(`1', `2', `3', `4') error-->m4trace: -5- shift(`2', `3', `4') error-->m4trace: -4- shift(`3', `4') error-->m4trace: -3- shift(`4')
Each successive iteration was adding more quotedshift
invocations, and the entire list contents were passing through everyiteration. In general, when recursing, it is a good idea to make therecursion use fewer arguments, rather than adding additional quoteduses ofshift
. By doing so, m4
uses less memory, invokesfewer macros, is less likely to run into machine limits, and mostimportantly, performs faster. The fixed version offoreachq
canbe found in m4-1.4.16/examples/foreachq2.m4:
$ m4 -I examples include(`foreachq2.m4') ⇒ undivert(`foreachq2.m4')dnl ⇒include(`quote.m4')dnl ⇒divert(`-1') ⇒# foreachq(x, `item_1, item_2, ..., item_n', stmt) ⇒# quoted list, improved version ⇒define(`foreachq', `pushdef(`$1')_$0($@)popdef(`$1')') ⇒define(`_arg1q', ``$1'') ⇒define(`_rest', `ifelse(`$#', `1', `', `dquote(shift($@))')') ⇒define(`_foreachq', `ifelse(`$2', `', `', ⇒ `define(`$1', _arg1q($2))$3`'$0(`$1', _rest($2), `$3')')') ⇒divert`'dnl traceon(`shift')debugmode(`aq') ⇒ foreachq(`x', ``1', `2', `3', `4'', `x ')dnl ⇒1 error-->m4trace: -3- shift(`1', `2', `3', `4') ⇒2 error-->m4trace: -3- shift(`2', `3', `4') ⇒3 error-->m4trace: -3- shift(`3', `4') ⇒4
Note that the fixed version calls unquoted helper macros in_foreachq
to trim elements immediately; those helper macrosin turn must re-supply the layer of quotes lost in the macro invocation. Contrast the use of_arg1q
, which quotes the first listelement, with _arg1
of the earlier implementation thatreturned the first list element directly. Additionally, by calling thehelper method immediately, the ‘defn(`iterator')’ no longercontains unexpanded macros.
The astute m4 programmer might notice that the solution above still usesmore memory and macro invocations, and thus more time, than strictlynecessary. Note that ‘$2’, which contains an arbitrarily longquoted list, is expanded and rescanned three times per iteration of_foreachq
. Furthermore, every iteration of the algorithmeffectively unboxes then reboxes the list, which costs a couple of macroinvocations. It is possible to rewrite the algorithm for a bit morespeed by swapping the order of the arguments to _foreachq
inorder to operate on an unboxed list in the first place, and by using thefixed-length ‘$#’ instead of an arbitrary length list as the key toend recursion. The result is an overhead of six macro invocations perloop (excluding any macros intext), instead of eight. Thisalternative approach is available asm4-1.4.16/examples/foreach3.m4:
$ m4 -I examples include(`foreachq3.m4') ⇒ undivert(`foreachq3.m4')dnl ⇒divert(`-1') ⇒# foreachq(x, `item_1, item_2, ..., item_n', stmt) ⇒# quoted list, alternate improved version ⇒define(`foreachq', `ifelse(`$2', `', `', ⇒ `pushdef(`$1')_$0(`$1', `$3', `', $2)popdef(`$1')')') ⇒define(`_foreachq', `ifelse(`$#', `3', `', ⇒ `define(`$1', `$4')$2`'$0(`$1', `$2', ⇒ shift(shift(shift($@))))')') ⇒divert`'dnl traceon(`shift')debugmode(`aq') ⇒ foreachq(`x', ``1', `2', `3', `4'', `x ')dnl ⇒1 error-->m4trace: -4- shift(`x', `x error-->', `', `1', `2', `3', `4') error-->m4trace: -3- shift(`x error-->', `', `1', `2', `3', `4') error-->m4trace: -2- shift(`', `1', `2', `3', `4') ⇒2 error-->m4trace: -4- shift(`x', `x error-->', `1', `2', `3', `4') error-->m4trace: -3- shift(`x error-->', `1', `2', `3', `4') error-->m4trace: -2- shift(`1', `2', `3', `4') ⇒3 error-->m4trace: -4- shift(`x', `x error-->', `2', `3', `4') error-->m4trace: -3- shift(`x error-->', `2', `3', `4') error-->m4trace: -2- shift(`2', `3', `4') ⇒4 error-->m4trace: -4- shift(`x', `x error-->', `3', `4') error-->m4trace: -3- shift(`x error-->', `3', `4') error-->m4trace: -2- shift(`3', `4')
In the current version of M4, every instance of ‘$@’ is rescannedas it is encountered. Thus, theforeachq3.m4 alternative usesmuch less memory thanforeachq2.m4, and executes as much as 10%faster, since each iteration encounters fewer ‘$@’. However, theimplementation of rescanning every byte in ‘$@’ is quadratic inthe number of bytes scanned (for example, making the broken version inforeachq.m4 cubic, rather than quadratic, in behavior). A futurerelease of M4 will improve the underlying implementation by reusingresults of previous scans, so that both styles of foreachq
canbecome linear in the number of bytes scanned. Notice how theimplementation injects an empty argument prior to expanding ‘$2’withinforeachq
; the helper macro _foreachq
then ignoresthe third argument altogether, and ends recursion when there are threearguments left because there was nothing left to pass throughshift
. Thus, each iteration only needs one ifelse
, ratherthan the two conditionals used in the version fromforeachq2.m4.
So far, all of the implementations offoreachq
presented havebeen quadratic with M4 1.4.x. But forloop
is linear, becauseeach iteration parses a constant amount of arguments. So, it ispossible to design a variant that usesforloop
to do theiteration, then uses ‘$@’ only once at the end, giving a linearresult even with older M4 implementations. This implementation relieson the GNU extension that ‘$10’ expands to the tenthargument rather than the first argument concatenated with ‘0’. Thetrick is to define an intermediate macro that repeats the textm4_define(`$1', `$
n')$2`'
, with ‘n’ set to successiveintegers corresponding to each argument. The helper macro_foreachq_
is needed in order to generate the literal sequencessuch as ‘$1’ into the intermediate macro, rather than expandingthem as the arguments of _foreachq
. With this approach, noshift
calls are even needed! Even though there are seven macrosof overhead per iteration instead of six inforeachq3.m4, thelinear scaling is apparent at relatively small list sizes. However,this approach will need adjustment when a future version of M4 followsPOSIX by no longer treating ‘$10’ as the tenth argument;the anticipation is that ‘${10}’ can be used instead, althoughthat alternative syntax is not yet supported.
$ m4 -I examples include(`foreachq4.m4') ⇒ undivert(`foreachq4.m4')dnl ⇒include(`forloop2.m4')dnl ⇒divert(`-1') ⇒# foreachq(x, `item_1, item_2, ..., item_n', stmt) ⇒# quoted list, version based on forloop ⇒define(`foreachq', ⇒`ifelse(`$2', `', `', `_$0(`$1', `$3', $2)')') ⇒define(`_foreachq', ⇒`pushdef(`$1', forloop(`$1', `3', `$#', ⇒ `$0_(`1', `2', indir(`$1'))')`popdef( ⇒ `$1')')indir(`$1', $@)') ⇒define(`_foreachq_', ⇒``define(`$$1', `$$3')$$2`''') ⇒divert`'dnl traceon(`shift')debugmode(`aq') ⇒ foreachq(`x', ``1', `2', `3', `4'', `x ')dnl ⇒1 ⇒2 ⇒3 ⇒4
For yet another approach, the improved version of foreach
,available inm4-1.4.16/examples/foreach2.m4, simplyoverquotes the arguments to_foreach
to begin with, usingdquote_elt
. Then _foreach
can just use_arg1
to remove the extra layer of quoting that was added upfront:
$ m4 -I examples include(`foreach2.m4') ⇒ undivert(`foreach2.m4')dnl ⇒include(`quote.m4')dnl ⇒divert(`-1') ⇒# foreach(x, (item_1, item_2, ..., item_n), stmt) ⇒# parenthesized list, improved version ⇒define(`foreach', `pushdef(`$1')_$0(`$1', ⇒ (dquote(dquote_elt$2)), `$3')popdef(`$1')') ⇒define(`_arg1', `$1') ⇒define(`_foreach', `ifelse(`$2', `(`')', `', ⇒ `define(`$1', _arg1$2)$3`'$0(`$1', (dquote(shift$2)), `$3')')') ⇒divert`'dnl traceon(`shift')debugmode(`aq') ⇒ foreach(`x', `(`1', `2', `3', `4')', `x ')dnl error-->m4trace: -4- shift(`1', `2', `3', `4') error-->m4trace: -4- shift(`2', `3', `4') error-->m4trace: -4- shift(`3', `4') ⇒1 error-->m4trace: -3- shift(``1'', ``2'', ``3'', ``4'') ⇒2 error-->m4trace: -3- shift(``2'', ``3'', ``4'') ⇒3 error-->m4trace: -3- shift(``3'', ``4'') ⇒4 error-->m4trace: -3- shift(``4'')
It is likewise possible to write a variant of foreach
thatperforms in linear time on M4 1.4.x; the easiest method is probablywriting a version offoreach
that unboxes its list, then invokes_foreachq
as previously defined inforeachq4.m4.
In summary, recursion over list elements is trickier than it appeared atfirst glance, but provides a powerful idiom withinm4
processing. As a final demonstration, both list styles are now able to handleseveral scenarios that would wreak havoc on one or both of the originalimplementations. This points out one other difference between thelist styles.foreach
evaluates unquoted list elements only once,in preparation for calling_foreach
, similary forforeachq
as provided by foreachq3.m4 orforeachq4.m4. Butforeachq
, as provided byforeachq2.m4,evaluates unquoted list elements twice while visiting the first listelement, once in_arg1q
and once in _rest
. Whendeciding which list style to use, one must take into account whetherrepeating the side effects of unquoted list elements will have anydetrimental effects.
$ m4 -I examples include(`foreach2.m4') ⇒ include(`foreachq2.m4') ⇒ dnl 0-element list: foreach(`x', `', `<x>') / foreachq(`x', `', `<x>') ⇒ / dnl 1-element list of empty element foreach(`x', `()', `<x>') / foreachq(`x', ``'', `<x>') ⇒<> / <> dnl 2-element list of empty elements foreach(`x', `(`',`')', `<x>') / foreachq(`x', ``',`'', `<x>') ⇒<><> / <><> dnl 1-element list of a comma foreach(`x', `(`,')', `<x>') / foreachq(`x', ``,'', `<x>') ⇒<,> / <,> dnl 2-element list of unbalanced parentheses foreach(`x', `(`(', `)')', `<x>') / foreachq(`x', ``(', `)'', `<x>') ⇒<(><)> / <(><)> define(`ab', `oops')dnl using defn(`iterator') foreach(`x', `(`a', `b')', `defn(`x')') /dnl foreachq(`x', ``a', `b'', `defn(`x')') ⇒ab / ab define(`active', `ACT, IVE') ⇒ traceon(`active') ⇒ dnl list of unquoted macros; expansion occurs before recursion foreach(`x', `(active, active)', `<x> ')dnl error-->m4trace: -4- active -> `ACT, IVE' error-->m4trace: -4- active -> `ACT, IVE' ⇒<ACT> ⇒<IVE> ⇒<ACT> ⇒<IVE> foreachq(`x', `active, active', `<x> ')dnl error-->m4trace: -3- active -> `ACT, IVE' error-->m4trace: -3- active -> `ACT, IVE' ⇒<ACT> error-->m4trace: -3- active -> `ACT, IVE' error-->m4trace: -3- active -> `ACT, IVE' ⇒<IVE> ⇒<ACT> ⇒<IVE> dnl list of quoted macros; expansion occurs during recursion foreach(`x', `(`active', `active')', `<x> ')dnl error-->m4trace: -1- active -> `ACT, IVE' ⇒<ACT, IVE> error-->m4trace: -1- active -> `ACT, IVE' ⇒<ACT, IVE> foreachq(`x', ``active', `active'', `<x> ')dnl error-->m4trace: -1- active -> `ACT, IVE' ⇒<ACT, IVE> error-->m4trace: -1- active -> `ACT, IVE' ⇒<ACT, IVE> dnl list of double-quoted macro names; no expansion foreach(`x', `(``active'', ``active'')', `<x> ')dnl ⇒<active> ⇒<active> foreachq(`x', ```active'', ``active''', `<x> ')dnl ⇒<active> ⇒<active>
17.4 Solution for copy
The macro copy
presented aboveis unable to handle builtin tokens with M4 1.4.x, because it tries topass the builtin token through the macrocurry
, where it issilently flattened to an empty string (see Composition). Ratherthan using the problematic curry
to work around the limitationthatstack_foreach
expects to invoke a macro that takes exactlyone argument, we can write a new macro that lets us form the exacttwo-argumentpushdef
call sequence needed, so that we are nolonger passing a builtin token through a text macro.
— Composite: stack_foreach_sep_lifo ( macro, pre, post, sep)
For each of the
pushdef
definitions associated with macro,expand the sequence ‘pre`'definition`'post’. Additionally, expandsep between definitions.stack_foreach_sep
visits the oldest definition first, whilestack_foreach_sep_lifo
visits the current definition first. Theexpansion may dereferencemacro, but should not modify it. Thereare a few special macros, such asdefn
, which cannot be used asthe macro parameter.
Note that stack_foreach(`
macro', `
action')
isequivalent tostack_foreach_sep(`
macro', `
action(',`)')
. By supplying explicit parentheses, split among thepre andpost arguments to stack_foreach_sep
, it is now possible toconstruct macro calls with more than one argument, without passingbuiltin tokens through a macro call. It is likewise possible todirectly reference the stack definitions without a macro call, byleaving pre and post empty. Thus, in addition to fixingcopy
on builtin tokens, it also executes with fewer macroinvocations.
The new macro also adds a separator that is only output after the firstiteration of the helper_stack_reverse_sep
, implemented byprepending the original sep topre and omitting a separgument in subsequent iterations. Note that the empty string thatseparatessep from pre is provided as part of the fourthargument when originally calling_stack_reverse_sep
, and not bywriting $4`'$3
as the third argument in the recursive call; whilethe other approach would give the same output, it does so at the expenseof increasing the argument size on each iteration of_stack_reverse_sep
, which results in quadratic instead of linearexecution time. The improved stack walking macros are available inm4-1.4.16/examples/stack_sep.m4:
$ m4 -I examples include(`stack_sep.m4') ⇒ define(`copy', `ifdef(`$2', `errprint(`$2 already defined ')m4exit(`1')', `stack_foreach_sep(`$1', `pushdef(`$2',', `)')')')dnl pushdef(`a', `1')pushdef(`a', defn(`divnum')) ⇒ copy(`a', `b') ⇒ b ⇒0 popdef(`b') ⇒ b ⇒1 pushdef(`c', `1')pushdef(`c', `2') ⇒ stack_foreach_sep_lifo(`c', `', `', `, ') ⇒2, 1 undivert(`stack_sep.m4')dnl ⇒divert(`-1') ⇒# stack_foreach_sep(macro, pre, post, sep) ⇒# Invoke PRE`'defn`'POST with a single argument of each definition ⇒# from the definition stack of MACRO, starting with the oldest, and ⇒# separated by SEP between definitions. ⇒define(`stack_foreach_sep', ⇒`_stack_reverse_sep(`$1', `tmp-$1')'dnl ⇒`_stack_reverse_sep(`tmp-$1', `$1', `$2`'defn(`$1')$3', `$4`'')') ⇒# stack_foreach_sep_lifo(macro, pre, post, sep) ⇒# Like stack_foreach_sep, but starting with the newest definition. ⇒define(`stack_foreach_sep_lifo', ⇒`_stack_reverse_sep(`$1', `tmp-$1', `$2`'defn(`$1')$3', `$4`'')'dnl ⇒`_stack_reverse_sep(`tmp-$1', `$1')') ⇒define(`_stack_reverse_sep', ⇒`ifdef(`$1', `pushdef(`$2', defn(`$1'))$3`'popdef(`$1')$0( ⇒ `$1', `$2', `$4$3')')') ⇒divert`'dnl
17.5 Solution for m4wrap
The replacement m4wrap
versions presented above, designed toguarantee FIFO or LIFO order regardless of the underlying M4implementation, share a bug when dealing with wrapped text that lookslike parameter expansion. Note how the invocation ofm4wrap
n interprets these parameters, while using thebuiltin 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 ofmultiplem4wrap
n placeholders in the original examples ismore expensive in time and memory than strictly necessary. Notice howthe improved version grabs the wrapped text viadefn
to avoidparameter expansion, then undefines _m4wrap_text
, beforestripping a level of quotes with_arg1
to expand the text. Thatway, each level of wrapping reuses the single placeholder, which startseach nesting level in an undefined state.
Finally, it is worth emulating the GNU M4 extension of savingall arguments to m4wrap
, separated by a space, rather than savingjust the first argument. This is done with thejoin
macrodocumented previously (see Shift). The improved LIFO example isshipped asm4-1.4.16/examples/wraplifo2.m4, and caneasily be converted to a FIFO solution by swapping the adjacentinvocations ofjoinall
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 $@
17.6 Solution for cleardivert
The cleardivert
macro (see Cleardivert) cannot, as it stands, becalled without arguments to clear all pending diversions. That isbecause using undivert with an empty string for an argument is differentthan using it with no arguments at all. Compare the earlier definitionwith one that takes the number of arguments into account:
define(`cleardivert', `pushdef(`_n', divnum)divert(`-1')undivert($@)divert(_n)popdef(`_n')') ⇒ divert(`1')one divert ⇒ cleardivert ⇒ undivert ⇒one ⇒ define(`cleardivert', `pushdef(`_num', divnum)divert(`-1')ifelse(`$#', `0', `undivert`'', `undivert($@)')divert(_num)popdef(`_num')') ⇒ divert(`2')two divert ⇒ cleardivert ⇒ undivert ⇒
17.7 Solution for capitalize
The capitalize
macro (see Patsubst) as presented earlier doesnot allow clients to follow the quoting rule of thumb. Consider thethree macrosactive
, Active
, and ACTIVE
, and thedifference between callingcapitalize
with the expansion of amacro, expanding the result of a case change, and changing the case of adouble-quoted string:
$ m4 -I examples include(`capitalize.m4')dnl define(`active', `act1, ive')dnl define(`Active', `Act2, Ive')dnl define(`ACTIVE', `ACT3, IVE')dnl upcase(active) ⇒ACT1,IVE upcase(`active') ⇒ACT3, IVE upcase(``active'') ⇒ACTIVE downcase(ACTIVE) ⇒act3,ive downcase(`ACTIVE') ⇒act1, ive downcase(``ACTIVE'') ⇒active capitalize(active) ⇒Act1 capitalize(`active') ⇒Active capitalize(``active'') ⇒_capitalize(`active') define(`A', `OOPS') ⇒ capitalize(active) ⇒OOPSct1 capitalize(`active') ⇒OOPSctive
First, when capitalize
is called with more than one argument, itwas throwing away later arguments, whereasupcase
anddowncase
used ‘$*’ to collect them all. The fix is simple:use ‘$*’ consistently.
Next, with single-quoting, capitalize
outputs a single character,a set of quotes, then the rest of the characters, making it impossibleto invokeActive
after the fact, and allowing the alternate macroA
to interfere. Here, the solution is to use additional quotingin the helper macros, then pass the final over-quoted output stringthrough_arg1
to remove the extra quoting and finally invoke theconcatenated portions as a single string.
Finally, when passed a double-quoted string, the nested macro_capitalize
is never invoked because it ended up nested insidequotes. This one is the toughest to fix. In short, we have no idea howmany levels of quotes are in effect on the substring being altered bypatsubst
. If the replacement string cannot be expressed entirelyin terms of literal text and backslash substitutions, then we need amechanism to guarantee that the helper macros are invoked outside ofquotes. In other words, this sounds like a job for changequote
(see Changequote). By changing the active quoting characters, wecan guarantee that replacement text injected bypatsubst
alwaysoccurs in the middle of a string that has exactly one level ofover-quoting using alternate quotes; so the replacement text closes thequoted string, invokes the helper macros, then reopens the quotedstring. In turn, that means the replacement text has unbalanced quotes,necessitating another round of changequote
.
In the fixed version below, (also shipped asm4-1.4.16/examples/capitalize2.m4),capitalize
uses the alternate quotes of ‘<<[’ and ‘]>>’ (the longerstrings are chosen so as to be less likely to appear in the text beingconverted). The helpers_to_alt
and _from_alt
merelyreduce the number of characters required to perform achangequote
, since the definition changes twice. The outermostpair means thatpatsubst
and _capitalize_alt
are invokedwith alternate quoting; the innermost pair is used so that the thirdargument topatsubst
can contain an unbalanced‘]>>’/‘<<[’ pair. Note thatupcase
and downcase
must be redefined as _upcase_alt
and_downcase_alt
, sincethey contain nested quotes but are invoked with the alternate quotingscheme in effect.
$ m4 -I examples include(`capitalize2.m4')dnl define(`active', `act1, ive')dnl define(`Active', `Act2, Ive')dnl define(`ACTIVE', `ACT3, IVE')dnl define(`A', `OOPS')dnl capitalize(active; `active'; ``active''; ```actIVE''') ⇒Act1,Ive; Act2, Ive; Active; `Active' undivert(`capitalize2.m4')dnl ⇒divert(`-1') ⇒# upcase(text) ⇒# downcase(text) ⇒# capitalize(text) ⇒# change case of text, improved version ⇒define(`upcase', `translit(`$*', `a-z', `A-Z')') ⇒define(`downcase', `translit(`$*', `A-Z', `a-z')') ⇒define(`_arg1', `$1') ⇒define(`_to_alt', `changequote(`<<[', `]>>')') ⇒define(`_from_alt', `changequote(<<[`]>>, <<[']>>)') ⇒define(`_upcase_alt', `translit(<<[$*]>>, <<[a-z]>>, <<[A-Z]>>)') ⇒define(`_downcase_alt', `translit(<<[$*]>>, <<[A-Z]>>, <<[a-z]>>)') ⇒define(`_capitalize_alt', ⇒ `regexp(<<[$1]>>, <<[^\(\w\)\(\w*\)]>>, ⇒ <<[_upcase_alt(<<[<<[\1]>>]>>)_downcase_alt(<<[<<[\2]>>]>>)]>>)') ⇒define(`capitalize', ⇒ `_arg1(_to_alt()patsubst(<<[<<[$*]>>]>>, <<[\w+]>>, ⇒ _from_alt()`]>>_$0_alt(<<[\&]>>)<<['_to_alt())_from_alt())') ⇒divert`'dnl
17.8 Solution for fatal_error
The fatal_error
macro (see M4exit) is not robust to versionsof GNU M4 earlier than 1.4.8, where invoking__file__
(seeLocation) inside m4wrap
would resultin an empty string, and__line__
resulted in ‘0’ eventhough all files start at line 1. Furthermore, versions earlier than1.4.6 did not support the__program__
macro. If you wantfatal_error
to work across the entire 1.4.x release series, abetter implementation would be:
define(`fatal_error', `errprint(ifdef(`__program__', `__program__', ``m4'')'dnl `:ifelse(__line__, `0', `', `__file__:__line__:')` fatal error: $* ')m4exit(`1')') ⇒ m4wrap(`divnum(`demo of internal message') fatal_error(`inside wrapped text')') ⇒ ^D error-->m4:stdin:6: Warning: excess arguments to builtin `divnum' ignored ⇒0 error-->m4:stdin:6: fatal error: inside wrapped text
Appendix A How to make copies of the overall M4 package
This appendix covers the license for copying the source code of theoverall M4 package. This manual is under a different set ofrestrictions, covered later (seeCopying This Manual).
A.1 License for copying the M4 package
Copyright © 2007 Free Software Foundation, Inc. http://fsf.org/ Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license forsoftware and other kinds of works.
The licenses for most software and other practical works are designedto take away your freedom to share and change the works. By contrast,the GNU General Public License is intended to guarantee your freedomto share and change all versions of a program—to make sure it remainsfree software for all its users. We, the Free Software Foundation,use the GNU General Public License for most of our software; itapplies also to any other work released this way by its authors. Youcan apply it to your programs, too.
When we speak of free software, we are referring to freedom, notprice. Our General Public Licenses are designed to make sure that youhave the freedom to distribute copies of free software (and charge forthem if you wish), that you receive source code or can get it if youwant it, that you can change the software or use pieces of it in newfree programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying youthese rights or asking you to surrender the rights. Therefore, youhave certain responsibilities if you distribute copies of thesoftware, or if you modify it: responsibilities to respect the freedomof others.
For example, if you distribute copies of such a program, whethergratis or for a fee, you must pass on to the recipients the samefreedoms that you received. You must make sure that they, too,receive or can get the source code. And you must show them theseterms so they know their rights.
Developers that use the GNU GPL protect your rights with two steps:(1) assert copyright on the software, and (2) offer you this Licensegiving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explainsthat there is no warranty for this free software. For both users' andauthors' sake, the GPL requires that modified versions be marked aschanged, so that their problems will not be attributed erroneously toauthors of previous versions.
Some devices are designed to deny users access to install or runmodified versions of the software inside them, although themanufacturer can do so. This is fundamentally incompatible with theaim of protecting users' freedom to change the software. Thesystematic pattern of such abuse occurs in the area of products forindividuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit thepractice for those products. If such problems arise substantially inother domains, we stand ready to extend this provision to thosedomains in future versions of the GPL, as needed to protect thefreedom of users.
Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use ofsoftware on general-purpose computers, but in those that do, we wishto avoid the special danger that patents applied to a free programcould make it effectively proprietary. To prevent this, the GPLassures that patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution andmodification follow.
TERMS AND CONDITIONS
- Definitions.
“This License” refers to version 3 of the GNU General Public License.
“Copyright” also means copyright-like laws that apply to other kindsof works, such as semiconductor masks.
“The Program” refers to any copyrightable work licensed under thisLicense. Each licensee is addressed as “you”. “Licensees” and“recipients” may be individuals or organizations.
To “modify” a work means to copy from or adapt all or part of the workin a fashion requiring copyright permission, other than the making ofan exact copy. The resulting work is called a “modified version” ofthe earlier work or a work “based on” the earlier work.
A “covered work” means either the unmodified Program or a work basedon the Program.
To “propagate” a work means to do anything with it that, withoutpermission, would make you directly or secondarily liable forinfringement under applicable copyright law, except executing it on acomputer or modifying a private copy. Propagation includes copying,distribution (with or without modification), making available to thepublic, and in some countries other activities as well.
To “convey” a work means any kind of propagation that enables otherparties to make or receive copies. Mere interaction with a userthrough a computer network, with no transfer of a copy, is notconveying.
An interactive user interface displays “Appropriate Legal Notices” tothe extent that it includes a convenient and prominently visiblefeature that (1) displays an appropriate copyright notice, and (2)tells the user that there is no warranty for the work (except to theextent that warranties are provided), that licensees may convey thework under this License, and how to view a copy of this License. Ifthe interface presents a list of user commands or options, such as amenu, a prominent item in the list meets this criterion.
- Source Code.
The “source code” for a work means the preferred form of the work formaking modifications to it. “Object code” means any non-source formof a work.
A “Standard Interface” means an interface that either is an officialstandard defined by a recognized standards body, or, in the case ofinterfaces specified for a particular programming language, one thatis widely used among developers working in that language.
The “System Libraries” of an executable work include anything, otherthan the work as a whole, that (a) is included in the normal form ofpackaging a Major Component, but which is not part of that MajorComponent, and (b) serves only to enable use of the work with thatMajor Component, or to implement a Standard Interface for which animplementation is available to the public in source code form. A“Major Component”, in this context, means a major essential component(kernel, window system, and so on) of the specific operating system(if any) on which the executable work runs, or a compiler used toproduce the work, or an object code interpreter used to run it.
The “Corresponding Source” for a work in object code form means allthe source code needed to generate, install, and (for an executablework) run the object code and to modify the work, including scripts tocontrol those activities. However, it does not include the work'sSystem Libraries, or general-purpose tools or generally available freeprograms which are used unmodified in performing those activities butwhich are not part of the work. For example, Corresponding Sourceincludes interface definition files associated with source files forthe work, and the source code for shared libraries and dynamicallylinked subprograms that the work is specifically designed to require,such as by intimate data communication or control flow between thosesubprograms and other parts of the work.
The Corresponding Source need not include anything that users canregenerate automatically from other parts of the Corresponding Source.
The Corresponding Source for a work in source code form is that samework.
- Basic Permissions.
All rights granted under this License are granted for the term ofcopyright on the Program, and are irrevocable provided the statedconditions are met. This License explicitly affirms your unlimitedpermission to run the unmodified Program. The output from running acovered work is covered by this License only if the output, given itscontent, constitutes a covered work. This License acknowledges yourrights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not convey,without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of havingthem make modifications exclusively for you, or provide you withfacilities for running those works, provided that you comply with theterms of this License in conveying all material for which you do notcontrol copyright. Those thus making or running the covered works foryou must do so exclusively on your behalf, under your direction andcontrol, on terms that prohibit them from making any copies of yourcopyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under theconditions stated below. Sublicensing is not allowed; section 10makes it unnecessary.
- Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technologicalmeasure under any applicable law fulfilling obligations under article11 of the WIPO copyright treaty adopted on 20 December 1996, orsimilar laws prohibiting or restricting circumvention of suchmeasures.
When you convey a covered work, you waive any legal power to forbidcircumvention of technological measures to the extent suchcircumvention is effected by exercising rights under this License withrespect to the covered work, and you disclaim any intention to limitoperation or modification of the work as a means of enforcing, againstthe work's users, your or third parties' legal rights to forbidcircumvention of technological measures.
- Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as youreceive it, in any medium, provided that you conspicuously andappropriately publish on each copy an appropriate copyright notice;keep intact all notices stating that this License and anynon-permissive terms added in accord with section 7 apply to the code;keep intact all notices of the absence of any warranty; and give allrecipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,and you may offer support or warranty protection for a fee.
- Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications toproduce it from the Program, in the form of source code under theterms of section 4, provided that you also meet all of theseconditions:
- The work must carry prominent notices stating that you modified it,and giving a relevant date.
- The work must carry prominent notices stating that it is releasedunder this License and any conditions added under section 7. Thisrequirement modifies the requirement in section 4 to “keep intact allnotices”.
- You must license the entire work, as a whole, under this License toanyone who comes into possession of a copy. This License willtherefore apply, along with any applicable section 7 additional terms,to the whole of the work, and all its parts, regardless of how theyare packaged. This License gives no permission to license the work inany other way, but it does not invalidate such permission if you haveseparately received it.
- If the work has interactive user interfaces, each must displayAppropriate Legal Notices; however, if the Program has interactiveinterfaces that do not display Appropriate Legal Notices, your workneed not make them do so.
A compilation of a covered work with other separate and independentworks, which are not by their nature extensions of the covered work,and which are not combined with it such as to form a larger program,in or on a volume of a storage or distribution medium, is called an“aggregate” if the compilation and its resulting copyright are notused to limit the access or legal rights of the compilation's usersbeyond what the individual works permit. Inclusion of a covered workin an aggregate does not cause this License to apply to the otherparts of the aggregate.
- Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms ofsections 4 and 5, provided that you also convey the machine-readableCorresponding Source under the terms of this License, in one of theseways:
- Convey the object code in, or embodied in, a physical product(including a physical distribution medium), accompanied by theCorresponding Source fixed on a durable physical medium customarilyused for software interchange.
- Convey the object code in, or embodied in, a physical product(including a physical distribution medium), accompanied by a writtenoffer, valid for at least three years and valid for as long as youoffer spare parts or customer support for that product model, to giveanyone who possesses the object code either (1) a copy of theCorresponding Source for all the software in the product that iscovered by this License, on a durable physical medium customarily usedfor software interchange, for a price no more than your reasonablecost of physically performing this conveying of source, or (2) accessto copy the Corresponding Source from a network server at no charge.
- Convey individual copies of the object code with a copy of the writtenoffer to provide the Corresponding Source. This alternative isallowed only occasionally and noncommercially, and only if youreceived the object code with such an offer, in accord with subsection6b.
- Convey the object code by offering access from a designated place(gratis or for a charge), and offer equivalent access to theCorresponding Source in the same way through the same place at nofurther charge. You need not require recipients to copy theCorresponding Source along with the object code. If the place to copythe object code is a network server, the Corresponding Source may beon a different server (operated by you or a third party) that supportsequivalent copying facilities, provided you maintain clear directionsnext to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remainobligated to ensure that it is available for as long as needed tosatisfy these requirements.
- Convey the object code using peer-to-peer transmission, provided youinform other peers where the object code and Corresponding Source ofthe work are being offered to the general public at no charge undersubsection 6d.
A separable portion of the object code, whose source code is excludedfrom the Corresponding Source as a System Library, need not beincluded in conveying the object code work.
A “User Product” is either (1) a “consumer product”, which means anytangible personal property which is normally used for personal,family, or household purposes, or (2) anything designed or sold forincorporation into a dwelling. In determining whether a product is aconsumer product, doubtful cases shall be resolved in favor ofcoverage. For a particular product received by a particular user,“normally used” refers to a typical or common use of that class ofproduct, regardless of the status of the particular user or of the wayin which the particular user actually uses, or expects or is expectedto use, the product. A product is a consumer product regardless ofwhether the product has substantial commercial, industrial ornon-consumer uses, unless such uses represent the only significantmode of use of the product.
“Installation Information” for a User Product means any methods,procedures, authorization keys, or other information required toinstall and execute modified versions of a covered work in that UserProduct from a modified version of its Corresponding Source. Theinformation must suffice to ensure that the continued functioning ofthe modified object code is in no case prevented or interfered withsolely because modification has been made.
If you convey an object code work under this section in, or with, orspecifically for use in, a User Product, and the conveying occurs aspart of a transaction in which the right of possession and use of theUser Product is transferred to the recipient in perpetuity or for afixed term (regardless of how the transaction is characterized), theCorresponding Source conveyed under this section must be accompaniedby the Installation Information. But this requirement does not applyif neither you nor any third party retains the ability to installmodified object code on the User Product (for example, the work hasbeen installed in ROM).
The requirement to provide Installation Information does not include arequirement to continue to provide support service, warranty, orupdates for a work that has been modified or installed by therecipient, or for the User Product in which it has been modified orinstalled. Access to a network may be denied when the modificationitself materially and adversely affects the operation of the networkor violates the rules and protocols for communication across thenetwork.
Corresponding Source conveyed, and Installation Information provided,in accord with this section must be in a format that is publiclydocumented (and with an implementation available to the public insource code form), and must require no special password or key forunpacking, reading or copying.
- Additional Terms.
“Additional permissions” are terms that supplement the terms of thisLicense by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shallbe treated as though they were included in this License, to the extentthat they are valid under applicable law. If additional permissionsapply only to part of the Program, that part may be used separatelyunder those permissions, but the entire Program remains governed bythis License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your optionremove any additional permissions from that copy, or from any part ofit. (Additional permissions may be written to require their ownremoval in certain cases when you modify the work.) You may placeadditional permissions on material, added by you to a covered work,for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material youadd to a covered work, you may (if authorized by the copyright holdersof that material) supplement the terms of this License with terms:
- Disclaiming warranty or limiting liability differently from the termsof sections 15 and 16 of this License; or
- Requiring preservation of specified reasonable legal notices or authorattributions in that material or in the Appropriate Legal Noticesdisplayed by works containing it; or
- Prohibiting misrepresentation of the origin of that material, orrequiring that modified versions of such material be marked inreasonable ways as different from the original version; or
- Limiting the use for publicity purposes of names of licensors orauthors of the material; or
- Declining to grant rights under trademark law for use of some tradenames, trademarks, or service marks; or
- Requiring indemnification of licensors and authors of that material byanyone who conveys the material (or modified versions of it) withcontractual assumptions of liability to the recipient, for anyliability that these contractual assumptions directly impose on thoselicensors and authors.
All other non-permissive additional terms are considered “furtherrestrictions” within the meaning of section 10. If the Program as youreceived it, or any part of it, contains a notice stating that it isgoverned by this License along with a term that is a furtherrestriction, you may remove that term. If a license document containsa further restriction but permits relicensing or conveying under thisLicense, you may add to a covered work material governed by the termsof that license document, provided that the further restriction doesnot survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, youmust place, in the relevant source files, a statement of theadditional terms that apply to those files, or a notice indicatingwhere to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in theform of a separately written license, or stated as exceptions; theabove requirements apply either way.
- Termination.
You may not propagate or modify a covered work except as expresslyprovided under this License. Any attempt otherwise to propagate ormodify it is void, and will automatically terminate your rights underthis License (including any patent licenses granted under the thirdparagraph of section 11).
However, if you cease all violation of this License, then your licensefrom a particular copyright holder is reinstated (a) provisionally,unless and until the copyright holder explicitly and finallyterminates your license, and (b) permanently, if the copyright holderfails to notify you of the violation by some reasonable means prior to60 days after the cessation.
Moreover, your license from a particular copyright holder isreinstated permanently if the copyright holder notifies you of theviolation by some reasonable means, this is the first time you havereceived notice of violation of this License (for any work) from thatcopyright holder, and you cure the violation prior to 30 days afteryour receipt of the notice.
Termination of your rights under this section does not terminate thelicenses of parties who have received copies or rights from you underthis License. If your rights have been terminated and not permanentlyreinstated, you do not qualify to receive new licenses for the samematerial under section 10.
- Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or runa copy of the Program. Ancillary propagation of a covered workoccurring solely as a consequence of using peer-to-peer transmissionto receive a copy likewise does not require acceptance. However,nothing other than this License grants you permission to propagate ormodify any covered work. These actions infringe copyright if you donot accept this License. Therefore, by modifying or propagating acovered work, you indicate your acceptance of this License to do so.
- Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automaticallyreceives a license from the original licensors, to run, modify andpropagate that work, subject to this License. You are not responsiblefor enforcing compliance by third parties with this License.
An “entity transaction” is a transaction transferring control of anorganization, or substantially all assets of one, or subdividing anorganization, or merging organizations. If propagation of a coveredwork results from an entity transaction, each party to thattransaction who receives a copy of the work also receives whateverlicenses to the work the party's predecessor in interest had or couldgive under the previous paragraph, plus a right to possession of theCorresponding Source of the work from the predecessor in interest, ifthe predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of therights granted or affirmed under this License. For example, you maynot impose a license fee, royalty, or other charge for exercise ofrights granted under this License, and you may not initiate litigation(including a cross-claim or counterclaim in a lawsuit) alleging thatany patent claim is infringed by making, using, selling, offering forsale, or importing the Program or any portion of it.
- Patents.
A “contributor” is a copyright holder who authorizes use under thisLicense of the Program or a work on which the Program is based. Thework thus licensed is called the contributor's “contributor version”.
A contributor's “essential patent claims” are all patent claims ownedor controlled by the contributor, whether already acquired orhereafter acquired, that would be infringed by some manner, permittedby this License, of making, using, or selling its contributor version,but do not include claims that would be infringed only as aconsequence of further modification of the contributor version. Forpurposes of this definition, “control” includes the right to grantpatent sublicenses in a manner consistent with the requirements ofthis License.
Each contributor grants you a non-exclusive, worldwide, royalty-freepatent license under the contributor's essential patent claims, tomake, use, sell, offer for sale, import and otherwise run, modify andpropagate the contents of its contributor version.
In the following three paragraphs, a “patent license” is any expressagreement or commitment, however denominated, not to enforce a patent(such as an express permission to practice a patent or covenant not tosue for patent infringement). To “grant” such a patent license to aparty means to make such an agreement or commitment not to enforce apatent against the party.
If you convey a covered work, knowingly relying on a patent license,and the Corresponding Source of the work is not available for anyoneto copy, free of charge and under the terms of this License, through apublicly available network server or other readily accessible means,then you must either (1) cause the Corresponding Source to be soavailable, or (2) arrange to deprive yourself of the benefit of thepatent license for this particular work, or (3) arrange, in a mannerconsistent with the requirements of this License, to extend the patentlicense to downstream recipients. “Knowingly relying” means you haveactual knowledge that, but for the patent license, your conveying thecovered work in a country, or your recipient's use of the covered workin a country, would infringe one or more identifiable patents in thatcountry that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction orarrangement, you convey, or propagate by procuring conveyance of, acovered work, and grant a patent license to some of the partiesreceiving the covered work authorizing them to use, propagate, modifyor convey a specific copy of the covered work, then the patent licenseyou grant is automatically extended to all recipients of the coveredwork and works based on it.
A patent license is “discriminatory” if it does not include within thescope of its coverage, prohibits the exercise of, or is conditioned onthe non-exercise of one or more of the rights that are specificallygranted under this License. You may not convey a covered work if youare a party to an arrangement with a third party that is in thebusiness of distributing software, under which you make payment to thethird party based on the extent of your activity of conveying thework, and under which the third party grants, to any of the partieswho would receive the covered work from you, a discriminatory patentlicense (a) in connection with copies of the covered work conveyed byyou (or copies made from those copies), or (b) primarily for and inconnection with specific products or compilations that contain thecovered work, unless you entered into that arrangement, or that patentlicense was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limitingany implied license or other defenses to infringement that mayotherwise be available to you under applicable patent law.
- No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement orotherwise) that contradict the conditions of this License, they do notexcuse you from the conditions of this License. If you cannot conveya covered work so as to satisfy simultaneously your obligations underthis License and any other pertinent obligations, then as aconsequence you may not convey it at all. For example, if you agreeto terms that obligate you to collect a royalty for further conveyingfrom those to whom you convey the Program, the only way you couldsatisfy both those terms and this License would be to refrain entirelyfrom conveying the Program.
- Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you havepermission to link or combine any covered work with a work licensedunder version 3 of the GNU Affero General Public License into a singlecombined work, and to convey the resulting work. The terms of thisLicense will continue to apply to the part which is the covered work,but the special requirements of the GNU Affero General Public License,section 13, concerning interaction through a network will apply to thecombination as such.
- Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versionsof the GNU General Public License from time to time. Such newversions will be similar in spirit to the present version, but maydiffer in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Programspecifies that a certain numbered version of the GNU General PublicLicense “or any later version” applies to it, you have the option offollowing the terms and conditions either of that numbered version orof any later version published by the Free Software Foundation. Ifthe Program does not specify a version number of the GNU GeneralPublic License, you may choose any version ever published by the FreeSoftware Foundation.
If the Program specifies that a proxy can decide which future versionsof the GNU General Public License can be used, that proxy's publicstatement of acceptance of a version permanently authorizes you tochoose that version for the Program.
Later license versions may give you additional or differentpermissions. However, no additional obligations are imposed on anyauthor or copyright holder as a result of your choosing to follow alater version.
- Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BYAPPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHTHOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM “AS IS” WITHOUTWARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOTLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FORA PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY ANDPERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVEDEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR ORCORRECTION.
- Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITINGWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/ORCONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGESARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUTNOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE ORLOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAMTO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHERPARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
- Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability providedabove cannot be given local legal effect according to their terms,reviewing courts shall apply local law that most closely approximatesan absolute waiver of all civil liability in connection with theProgram, unless a warranty or assumption of liability accompanies acopy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatestpossible use to the public, the best way to achieve this is to make itfree software which everyone can redistribute and change under theseterms.
To do so, attach the following notices to the program. It is safestto attach them to the start of each source file to most effectivelystate the exclusion of warranty; and each file should have at leastthe “copyright” line and a pointer to where the full notice is found.
one line to give the program's name and a brief idea of what it does. Copyright (C) year name of author This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a shortnotice like this when it starts in an interactive mode:
program Copyright (C) year name of author This program comes with ABSOLUTELY NO WARRANTY; for details type ‘show w’. This is free software, and you are welcome to redistribute it under certain conditions; type ‘show c’ for details.
The hypothetical commands ‘show w’ and ‘show c’ should showthe appropriate parts of the General Public License. Of course, yourprogram's commands might be different; for a GUI interface, you woulduse an “about box”.
You should also get your employer (if you work as a programmer) or school,if any, to sign a “copyright disclaimer” for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, seehttp://www.gnu.org/licenses/.
The GNU General Public License does not permit incorporating yourprogram into proprietary programs. If your program is a subroutinelibrary, you may consider it more useful to permit linking proprietaryapplications with the library. If this is what you want to do, usethe GNU Lesser General Public License instead of this License. Butfirst, please readhttp://www.gnu.org/philosophy/why-not-lgpl.html.
Appendix B How to make copies of this manual
This appendix covers the license for copying this manual. Note thatsome of the longer examples in this manual are also distributed in thedirectorym4-1.4.16/examples/, where a morepermissive license is in effect when copying just the examples.
B.1 License for copying this manual
Copyright © 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc. http://fsf.org/ Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
- PREAMBLE
The purpose of this License is to make a manual, textbook, or otherfunctional and useful documentfree in the sense of freedom: toassure everyone the effective freedom to copy and redistribute it,with or without modifying it, either commercially or noncommercially. Secondarily, this License preserves for the author and publisher a wayto get credit for their work, while not being considered responsiblefor modifications made by others.
This License is a kind of “copyleft”, which means that derivativeworks of the document must themselves be free in the same sense. Itcomplements the GNU General Public License, which is a copyleftlicense designed for free software.
We have designed this License in order to use it for manuals for freesoftware, because free software needs free documentation: a freeprogram should come with manuals providing the same freedoms that thesoftware does. But this License is not limited to software manuals;it can be used for any textual work, regardless of subject matter orwhether it is published as a printed book. We recommend this Licenseprincipally for works whose purpose is instruction or reference.
- APPLICABILITY AND DEFINITIONS
This License applies to any manual or other work, in any medium, thatcontains a notice placed by the copyright holder saying it can bedistributed under the terms of this License. Such a notice grants aworld-wide, royalty-free license, unlimited in duration, to use thatwork under the conditions stated herein. The “Document”, below,refers to any such manual or work. Any member of the public is alicensee, and is addressed as “you”. You accept the license if youcopy, modify or distribute the work in a way requiring permissionunder copyright law.
A “Modified Version” of the Document means any work containing theDocument or a portion of it, either copied verbatim, or withmodifications and/or translated into another language.
A “Secondary Section” is a named appendix or a front-matter sectionof the Document that deals exclusively with the relationship of thepublishers or authors of the Document to the Document's overallsubject (or to related matters) and contains nothing that could falldirectly within that overall subject. (Thus, if the Document is inpart a textbook of mathematics, a Secondary Section may not explainany mathematics.) The relationship could be a matter of historicalconnection with the subject or with related matters, or of legal,commercial, philosophical, ethical or political position regardingthem.
The “Invariant Sections” are certain Secondary Sections whose titlesare designated, as being those of Invariant Sections, in the noticethat says that the Document is released under this License. If asection does not fit the above definition of Secondary then it is notallowed to be designated as Invariant. The Document may contain zeroInvariant Sections. If the Document does not identify any InvariantSections then there are none.
The “Cover Texts” are certain short passages of text that are listed,as Front-Cover Texts or Back-Cover Texts, in the notice that says thatthe Document is released under this License. A Front-Cover Text maybe at most 5 words, and a Back-Cover Text may be at most 25 words.
A “Transparent” copy of the Document means a machine-readable copy,represented in a format whose specification is available to thegeneral public, that is suitable for revising the documentstraightforwardly with generic text editors or (for images composed ofpixels) generic paint programs or (for drawings) some widely availabledrawing editor, and that is suitable for input to text formatters orfor automatic translation to a variety of formats suitable for inputto text formatters. A copy made in an otherwise Transparent fileformat whose markup, or absence of markup, has been arranged to thwartor discourage subsequent modification by readers is not Transparent. An image format is not Transparent if used for any substantial amountof text. A copy that is not “Transparent” is called “Opaque”.
Examples of suitable formats for Transparent copies include plainASCII without markup, Texinfo input format, LaTeX inputformat, SGML or XML using a publicly availableDTD, and standard-conforming simple HTML,PostScript or PDF designed for human modification. Examplesof transparent image formats include PNG, XCF andJPG. Opaque formats include proprietary formats that can beread and edited only by proprietary word processors, SGML orXML for which the DTD and/or processing tools arenot generally available, and the machine-generated HTML,PostScript or PDF produced by some word processors foroutput purposes only.
The “Title Page” means, for a printed book, the title page itself,plus such following pages as are needed to hold, legibly, the materialthis License requires to appear in the title page. For works informats which do not have any title page as such, “Title Page” meansthe text near the most prominent appearance of the work's title,preceding the beginning of the body of the text.
The “publisher” means any person or entity that distributes copiesof the Document to the public.
A section “Entitled XYZ” means a named subunit of the Document whosetitle either is precisely XYZ or contains XYZ in parentheses followingtext that translates XYZ in another language. (Here XYZ stands for aspecific section name mentioned below, such as “Acknowledgements”,“Dedications”, “Endorsements”, or “History”.) To “Preserve the Title”of such a section when you modify the Document means that it remains asection “Entitled XYZ” according to this definition.
The Document may include Warranty Disclaimers next to the notice whichstates that this License applies to the Document. These WarrantyDisclaimers are considered to be included by reference in thisLicense, but only as regards disclaiming warranties: any otherimplication that these Warranty Disclaimers may have is void and hasno effect on the meaning of this License.
- VERBATIM COPYING
You may copy and distribute the Document in any medium, eithercommercially or noncommercially, provided that this License, thecopyright notices, and the license notice saying this License appliesto the Document are reproduced in all copies, and that you add no otherconditions whatsoever to those of this License. You may not usetechnical measures to obstruct or control the reading or furthercopying of the copies you make or distribute. However, you may acceptcompensation in exchange for copies. If you distribute a large enoughnumber of copies you must also follow the conditions in section 3.
You may also lend copies, under the same conditions stated above, andyou may publicly display copies.
- COPYING IN QUANTITY
If you publish printed copies (or copies in media that commonly haveprinted covers) of the Document, numbering more than 100, and theDocument's license notice requires Cover Texts, you must enclose thecopies in covers that carry, clearly and legibly, all these CoverTexts: Front-Cover Texts on the front cover, and Back-Cover Texts onthe back cover. Both covers must also clearly and legibly identifyyou as the publisher of these copies. The front cover must presentthe full title with all words of the title equally prominent andvisible. You may add other material on the covers in addition. Copying with changes limited to the covers, as long as they preservethe title of the Document and satisfy these conditions, can be treatedas verbatim copying in other respects.
If the required texts for either cover are too voluminous to fitlegibly, you should put the first ones listed (as many as fitreasonably) on the actual cover, and continue the rest onto adjacentpages.
If you publish or distribute Opaque copies of the Document numberingmore than 100, you must either include a machine-readable Transparentcopy along with each Opaque copy, or state in or with each Opaque copya computer-network location from which the general network-usingpublic has access to download using public-standard network protocolsa complete Transparent copy of the Document, free of added material. If you use the latter option, you must take reasonably prudent steps,when you begin distribution of Opaque copies in quantity, to ensurethat this Transparent copy will remain thus accessible at the statedlocation until at least one year after the last time you distribute anOpaque copy (directly or through your agents or retailers) of thatedition to the public.
It is requested, but not required, that you contact the authors of theDocument well before redistributing any large number of copies, to givethem a chance to provide you with an updated version of the Document.
- MODIFICATIONS
You may copy and distribute a Modified Version of the Document underthe conditions of sections 2 and 3 above, provided that you releasethe Modified Version under precisely this License, with the ModifiedVersion filling the role of the Document, thus licensing distributionand modification of the Modified Version to whoever possesses a copyof it. In addition, you must do these things in the Modified Version:
- Use in the Title Page (and on the covers, if any) a title distinctfrom that of the Document, and from those of previous versions(which should, if there were any, be listed in the History sectionof the Document). You may use the same title as a previous versionif the original publisher of that version gives permission.
- List on the Title Page, as authors, one or more persons or entitiesresponsible for authorship of the modifications in the ModifiedVersion, together with at least five of the principal authors of theDocument (all of its principal authors, if it has fewer than five),unless they release you from this requirement.
- State on the Title page the name of the publisher of theModified Version, as the publisher.
- Preserve all the copyright notices of the Document.
- Add an appropriate copyright notice for your modificationsadjacent to the other copyright notices.
- Include, immediately after the copyright notices, a license noticegiving the public permission to use the Modified Version under theterms of this License, in the form shown in the Addendum below.
- Preserve in that license notice the full lists of Invariant Sectionsand required Cover Texts given in the Document's license notice.
- Include an unaltered copy of this License.
- Preserve the section Entitled “History”, Preserve its Title, and addto it an item stating at least the title, year, new authors, andpublisher of the Modified Version as given on the Title Page. Ifthere is no section Entitled “History” in the Document, create onestating the title, year, authors, and publisher of the Document asgiven on its Title Page, then add an item describing the ModifiedVersion as stated in the previous sentence.
- Preserve the network location, if any, given in the Document forpublic access to a Transparent copy of the Document, and likewisethe network locations given in the Document for previous versionsit was based on. These may be placed in the “History” section. You may omit a network location for a work that was published atleast four years before the Document itself, or if the originalpublisher of the version it refers to gives permission.
- For any section Entitled “Acknowledgements” or “Dedications”, Preservethe Title of the section, and preserve in the section all thesubstance and tone of each of the contributor acknowledgements and/ordedications given therein.
- Preserve all the Invariant Sections of the Document,unaltered in their text and in their titles. Section numbersor the equivalent are not considered part of the section titles.
- Delete any section Entitled “Endorsements”. Such a sectionmay not be included in the Modified Version.
- Do not retitle any existing section to be Entitled “Endorsements” orto conflict in title with any Invariant Section.
- Preserve any Warranty Disclaimers.
If the Modified Version includes new front-matter sections orappendices that qualify as Secondary Sections and contain no materialcopied from the Document, you may at your option designate some or allof these sections as invariant. To do this, add their titles to thelist of Invariant Sections in the Modified Version's license notice. These titles must be distinct from any other section titles.
You may add a section Entitled “Endorsements”, provided it containsnothing but endorsements of your Modified Version by variousparties—for example, statements of peer review or that the text hasbeen approved by an organization as the authoritative definition of astandard.
You may add a passage of up to five words as a Front-Cover Text, and apassage of up to 25 words as a Back-Cover Text, to the end of the listof Cover Texts in the Modified Version. Only one passage ofFront-Cover Text and one of Back-Cover Text may be added by (orthrough arrangements made by) any one entity. If the Document alreadyincludes a cover text for the same cover, previously added by you orby arrangement made by the same entity you are acting on behalf of,you may not add another; but you may replace the old one, on explicitpermission from the previous publisher that added the old one.
The author(s) and publisher(s) of the Document do not by this Licensegive permission to use their names for publicity for or to assert orimply endorsement of any Modified Version.
- COMBINING DOCUMENTS
You may combine the Document with other documents released under thisLicense, under the terms defined in section 4 above for modifiedversions, provided that you include in the combination all of theInvariant Sections of all of the original documents, unmodified, andlist them all as Invariant Sections of your combined work in itslicense notice, and that you preserve all their Warranty Disclaimers.
The combined work need only contain one copy of this License, andmultiple identical Invariant Sections may be replaced with a singlecopy. If there are multiple Invariant Sections with the same name butdifferent contents, make the title of each such section unique byadding at the end of it, in parentheses, the name of the originalauthor or publisher of that section if known, or else a unique number. Make the same adjustment to the section titles in the list ofInvariant Sections in the license notice of the combined work.
In the combination, you must combine any sections Entitled “History”in the various original documents, forming one section Entitled“History”; likewise combine any sections Entitled “Acknowledgements”,and any sections Entitled “Dedications”. You must delete allsections Entitled “Endorsements.”
- COLLECTIONS OF DOCUMENTS
You may make a collection consisting of the Document and other documentsreleased under this License, and replace the individual copies of thisLicense in the various documents with a single copy that is included inthe collection, provided that you follow the rules of this License forverbatim copying of each of the documents in all other respects.
You may extract a single document from such a collection, and distributeit individually under this License, provided you insert a copy of thisLicense into the extracted document, and follow this License in allother respects regarding verbatim copying of that document.
- AGGREGATION WITH INDEPENDENT WORKS
A compilation of the Document or its derivatives with other separateand independent documents or works, in or on a volume of a storage ordistribution medium, is called an “aggregate” if the copyrightresulting from the compilation is not used to limit the legal rightsof the compilation's users beyond what the individual works permit. When the Document is included in an aggregate, this License does notapply to the other works in the aggregate which are not themselvesderivative works of the Document.
If the Cover Text requirement of section 3 is applicable to thesecopies of the Document, then if the Document is less than one half ofthe entire aggregate, the Document's Cover Texts may be placed oncovers that bracket the Document within the aggregate, or theelectronic equivalent of covers if the Document is in electronic form. Otherwise they must appear on printed covers that bracket the wholeaggregate.
- TRANSLATION
Translation is considered a kind of modification, so you maydistribute translations of the Document under the terms of section 4. Replacing Invariant Sections with translations requires specialpermission from their copyright holders, but you may includetranslations of some or all Invariant Sections in addition to theoriginal versions of these Invariant Sections. You may include atranslation of this License, and all the license notices in theDocument, and any Warranty Disclaimers, provided that you also includethe original English version of this License and the original versionsof those notices and disclaimers. In case of a disagreement betweenthe translation and the original version of this License or a noticeor disclaimer, the original version will prevail.
If a section in the Document is Entitled “Acknowledgements”,“Dedications”, or “History”, the requirement (section 4) to Preserveits Title (section 1) will typically require changing the actualtitle.
- TERMINATION
You may not copy, modify, sublicense, or distribute the Documentexcept as expressly provided under this License. Any attemptotherwise to copy, modify, sublicense, or distribute it is void, andwill automatically terminate your rights under this License.
However, if you cease all violation of this License, then your licensefrom a particular copyright holder is reinstated (a) provisionally,unless and until the copyright holder explicitly and finallyterminates your license, and (b) permanently, if the copyright holderfails to notify you of the violation by some reasonable means prior to60 days after the cessation.
Moreover, your license from a particular copyright holder isreinstated permanently if the copyright holder notifies you of theviolation by some reasonable means, this is the first time you havereceived notice of violation of this License (for any work) from thatcopyright holder, and you cure the violation prior to 30 days afteryour receipt of the notice.
Termination of your rights under this section does not terminate thelicenses of parties who have received copies or rights from you underthis License. If your rights have been terminated and not permanentlyreinstated, receipt of a copy of some or all of the same material doesnot give you any rights to use it.
- FUTURE REVISIONS OF THIS LICENSE
The Free Software Foundation may publish new, revised versionsof the GNU Free Documentation License from time to time. Such newversions will be similar in spirit to the present version, but maydiffer in detail to address new problems or concerns. Seehttp://www.gnu.org/copyleft/.
Each version of the License is given a distinguishing version number. If the Document specifies that a particular numbered version of thisLicense “or any later version” applies to it, you have the option offollowing the terms and conditions either of that specified version orof any later version that has been published (not as a draft) by theFree Software Foundation. If the Document does not specify a versionnumber of this License, you may choose any version ever published (notas a draft) by the Free Software Foundation. If the Documentspecifies that a proxy can decide which future versions of thisLicense can be used, that proxy's public statement of acceptance of aversion permanently authorizes you to choose that version for theDocument.
- RELICENSING
“Massive Multiauthor Collaboration Site” (or “MMC Site”) means anyWorld Wide Web server that publishes copyrightable works and alsoprovides prominent facilities for anybody to edit those works. Apublic wiki that anybody can edit is an example of such a server. A“Massive Multiauthor Collaboration” (or “MMC”) contained in thesite means any set of copyrightable works thus published on the MMCsite.
“CC-BY-SA” means the Creative Commons Attribution-Share Alike 3.0license published by Creative Commons Corporation, a not-for-profitcorporation with a principal place of business in San Francisco,California, as well as future copyleft versions of that licensepublished by that same organization.
“Incorporate” means to publish or republish a Document, in whole orin part, as part of another Document.
An MMC is “eligible for relicensing” if it is licensed under thisLicense, and if all works that were first published under this Licensesomewhere other than this MMC, and subsequently incorporated in wholeor in part into the MMC, (1) had no cover texts or invariant sections,and (2) were thus incorporated prior to November 1, 2008.
The operator of an MMC Site may republish an MMC contained in the siteunder CC-BY-SA on the same site at any time before August 1, 2009,provided the MMC is eligible for relicensing.
ADDENDUM: How to use this License for your documents
To use this License in a document you have written, include a copy ofthe License in the document and put the following copyright andlicense notices just after the title page:
Copyright (C) year your name. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled ``GNU Free Documentation License''.
If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts,replace the “with...Texts.” line with this:
with the Invariant Sections being list their titles, with the Front-Cover Texts being list, and with the Back-Cover Texts being list.
If you have Invariant Sections without Cover Texts, or some othercombination of the three, merge those two alternatives to suit thesituation.
If your document contains nontrivial examples of program code, werecommend releasing these examples in parallel under your choice offree software license, such as the GNU General Public License,to permit their use in free software.
Appendix C Indices of concepts and macros
C.1 Index for all m4
macros
This index covers all m4
builtins, as well as several usefulcomposite macros. References are exclusively to the places where amacro is introduced the first time.
__file__
: Location__gnu__
: Platform macros__line__
: Location__os2__
: Platform macros__program__
:Location__unix__
: Platform macros__windows__
:Platform macrosargn
: Shiftarray
: Definearray_set
: Definebuiltin
: Builtincapitalize
: Patsubstchangecom
: Changecomchangequote
: Changequotechangeword
: Changewordcleardivert
: Cleardivertcond
: Shiftcopy
: Compositioncurry
: Compositiondebugfile
: Debug Outputdebugmode
: Debug Levelsdecr
: Incrdefine
: Definedefine_blind
: Compositiondefn
: Defndivert
: Divertdivnum
: Divnumdnl
: Dnldowncase
: Patsubstdquote
: Shiftdquote_elt
: Shiftdumpdef
: Dumpdeferrprint
: Errprintesyscmd
: Esyscmdeval
: Evalexample
: Manualexch
: Argumentsfatal_error
: M4exitforeach
: Foreachforeachq
: Foreachforloop
: Forloopformat
: Formatifdef
: Ifdefifelse
: Ifelseinclude
: Includeincr
: Incrindex
: Index macroindir
: Indirjoin
: Shiftjoinall
: Shiftlen
: Lenm4exit
: M4exitm4wrap
: M4wrapmaketemp
: Mkstempmkstemp
: Mkstempnargs
: Pseudo Argumentsos2
: Platform macrospatsubst
: Patsubstpopdef
: Pushdefpushdef
: Pushdefquote
: Shiftregexp
: Regexprename
: Compositionreverse
: Shiftshift
: Shiftsinclude
: Includestack_foreach
: Stacksstack_foreach_lifo
:Stacksstack_foreach_sep
:Improved copystack_foreach_sep_lifo
:Improved copysubstr
: Substrsyscmd
: Syscmdsysval
: Sysvaltraceoff
: Tracetraceon
: Tracetranslit
: Translitundefine
: Undefineundivert
: Undivertunix
: Platform macrosupcase
: Patsubstwindows
: Platform macros
C.2 Index for many concepts
- argument currying: Composition
- arguments to macros: Arguments
- arguments to macros: Macro Arguments
- arguments to macros, special:Pseudo Arguments
- arguments, joining: Shift
- arguments, more than nine:Improved foreach
- arguments, more than nine:Shift
- arguments, more than nine:Arguments
- arguments, quoted macro: Quoting Arguments
- arguments, reversing: Shift
- arithmetic: Arithmetic
- arrays: Define
- avoiding quadratic behavior:Improved foreach
- basic regular expressions:Patsubst
- basic regular expressions:Regexp
- blind macro: Composition
- blind macro: Ifelse
- blind macro: Inhibiting Invocation
- bug reports: Bugs
- builtins, indirect call of:Builtin
- builtins, special tokens:Defn
- call of builtins, indirect:Builtin
- call of macros, indirect:Indir
- case statement: Ifelse
- changing comment delimiters:Changecom
- changing quote delimiters:Changequote
- changing syntax: Changeword
- characters, translating:Translit
- command line: Invoking m4
- command line, file names on the:Command line files
- command line, macro definitions on the:Preprocessor features
- command line, options: Invoking m4
- commands, exit status from shell:Sysval
- commands, running shell:Shell commands
- comment delimiters, changing:Changecom
- comments: Comments
- comments, copied to output:Changecom
- comparing strings: Ifelse
- compatibility: Compatibility
- composing macros: Composition
- concatenating arguments: Shift
- conditional, short-circuiting:Shift
- conditionals: Ifdef
- controlling debugging output:Debug Levels
- copying macros: Composition
- counting loops: Forloop
- currying arguments: Composition
- debugging macros: Debugging
- debugging output, controlling:Debug Levels
- debugging output, saving:Debug Output
- decrement operator: Incr
- deferring expansion: M4wrap
- deferring output: Diversions
- defining new macros: Definitions
- definition stack: Stacks
- definition stack: Pushdef
- definitions, displaying macro:Dumpdef
- definitions, displaying macro:Defn
- deleting macros: Undefine
- deleting whitespace in input:Dnl
- delimiters, changing: Changecom
- delimiters, changing: Changequote
- discarding diverted text: Cleardivert
- discarding input: Divert
- discarding input: Dnl
- discarding input: Ifelse
- displaying macro definitions:Dumpdef
- diversion numbers: Divnum
- diverted text, discarding:Cleardivert
- diverting output to files:Divert
- dumping into frozen file: Using frozen files
- error messages, printing:Errprint
- errors, fatal: Operation modes
- evaluation, of integer expressions:Eval
- examples, understanding: Manual
- executing shell commands: Shell commands
- exit status from shell commands:Sysval
- exiting from
m4
:M4exit - expansion of macros: Macro expansion
- expansion, deferring: M4wrap
- expansion, tracing macro:Trace
- expressions, evaluation of integer:Eval
- expressions, regular: Patsubst
- expressions, regular: Regexp
- extracting substrings: Substr
- fast loading of frozen files:Using frozen files
- fatal errors: Operation modes
- FDL, GNU Free Documentation License:GNU Free Documentation License
- file format, frozen file:Frozen file format
- file inclusion: Undivert
- file inclusion: File Inclusion
- file names, on the command line:Command line files
- files, diverting output to:Divert
- files, names of temporary:Mkstemp
- for each loops: Foreach
- for loops: Forloop
- formatted output: Format
- Free Documentation License (FDL), GNU:GNU Free Documentation License
- frozen file format: Frozen file format
- frozen files for fast loading:Using frozen files
- General Public License (GPL), GNU:GNU General Public License
- GNU extensions: Extensions
- GNU extensions: Using frozen files
- GNU extensions: Mkstemp
- GNU extensions: Esyscmd
- GNU extensions: Eval
- GNU extensions: Format
- GNU extensions: Patsubst
- GNU extensions: Regexp
- GNU extensions: Undivert
- GNU extensions: Divert
- GNU extensions: Search Path
- GNU extensions: Debug Output
- GNU extensions: Debug Levels
- GNU extensions: Builtin
- GNU extensions: Indir
- GNU extensions: Arguments
- GNU extensions: Define
- GNU extensions: Inhibiting Invocation
- GNU Free Documentation License:GNU Free Documentation License
- GNU General Public License:GNU General Public License
- GNU M4, history of: History
- GPL, GNU General Public License:GNU General Public License
- history of
m4
:History - included files, search path for:Search Path
- inclusion, of files: Undivert
- inclusion, of files: File Inclusion
- increment operator: Incr
- indirect call of builtins:Builtin
- indirect call of macros: Indir
- initialization, frozen state:Using frozen files
- input location: Location
- input location: Preprocessor features
- input tokens: Syntax
- input, discarding: Divert
- input, discarding: Dnl
- input, discarding: Ifelse
- input, saving: M4wrap
- integer arithmetic: Arithmetic
- integer expression evaluation:Eval
- invoking
m4
:Invoking m4 - invoking macros: Invocation
- iterating over lists: Foreach
- joining arguments: Shift
- length of strings: Len
- lexical structure of words:Changeword
- License, code: Copying This Package
- License, manual: Copying This Manual
- limit, nesting: Limits control
- literal output: Pseudo Arguments
- local variables: Pushdef
- location, input: Location
- location, input: Preprocessor features
- loops: Shift
- loops, counting: Forloop
- loops, list iteration: Foreach
- M4PATH:Search Path
- macro composition: Composition
- macro definitions, on the command line:Preprocessor features
- macro expansion, tracing:Trace
- macro invocation: Invocation
- macro, blind: Composition
- macro, blind: Ifelse
- macro, blind: Inhibiting Invocation
- macros, arguments to: Arguments
- macros, arguments to: Macro Arguments
- macros, copying: Composition
- macros, debugging: Debugging
- macros, displaying definitions:Dumpdef
- macros, displaying definitions:Defn
- macros, expansion of: Macro expansion
- macros, how to define new:Definitions
- macros, how to delete: Undefine
- macros, how to rename: Defn
- macros, indirect call of:Indir
- macros, quoted arguments to:Quoting Arguments
- macros, recursive: Shift
- macros, special arguments to:Pseudo Arguments
- macros, temporary redefinition of:Pushdef
- manipulating quotes: Shift
- messages, printing error:Errprint
- more than nine arguments: Improved foreach
- more than nine arguments: Shift
- more than nine arguments: Arguments
- multibranches: Ifelse
- names: Names
- nesting limit: Limits control
- nine arguments, more than:Improved foreach
- nine arguments, more than:Shift
- nine arguments, more than:Arguments
- numbers: Manual
- options, command line: Invoking m4
- output, diverting to files:Divert
- output, formatted: Format
- output, literal: Pseudo Arguments
- output, saving debugging:Debug Output
- overview of
m4
:Intro - pattern substitution: Patsubst
- platform macros: Platform macros
- positional parameters, more than nine:Arguments
- POSIX: Extensions
- POSIXLY_CORRECT:Incompatibilities
- POSIXLY_CORRECT:Invoking m4
- preprocessor features: Preprocessor features
- printing error messages: Errprint
- pushdef stack: Stacks
- pushdef stack: Pushdef
- quadratic behavior, avoiding:Improved foreach
- quote delimiters, changing:Changequote
- quote manipulation: Shift
- quoted macro arguments: Quoting Arguments
- quoted string: Quoted strings
- quoting rule of thumb: Quoting Arguments
- recursive macros: Shift
- redefinition of macros, temporary:Pushdef
- regular expressions: Patsubst
- regular expressions: Regexp
- regular expressions: Changeword
- reloading a frozen file: Using frozen files
- renaming macros: Composition
- renaming macros: Defn
- reporting bugs: Bugs
- rescanning: Other Incompatibilities
- rescanning: Defn
- rescanning: Pseudo Arguments
- rescanning: Inhibiting Invocation
- rescanning: Limits control
- reversing arguments: Shift
- rule of thumb, quoting: Quoting Arguments
- running shell commands: Shell commands
- saving debugging output: Debug Output
- saving input: M4wrap
- search path for included files:Search Path
- shell commands, exit status from:Sysval
- shell commands, running:Shell commands
- short-circuiting conditional:Shift
- special arguments to macros:Pseudo Arguments
- stack, macro definition:Stacks
- stack, macro definition: Pushdef
- standard error, output to:Errprint
- standard error, output to:Trace
- standard error, output to:Dumpdef
- status of shell commands: Sysval
- status, setting
m4
exit: M4exit - string, quoted: Quoted strings
- strings, length of: Len
- substitution by regular expression:Patsubst
- substrings, extracting: Substr
- substrings, locating: Index macro
- suggestions, reporting: Bugs
- suppressing warnings: Macro Arguments
- switch statement: Ifelse
- synchronization lines: Preprocessor features
- syntax, changing: Changeword
- temporary file names: Mkstemp
- temporary redefinition of macros:Pushdef
- TMPDIR:Diversions
- tokens: Syntax
- tokens, builtin macro: Defn
- tokens, special: Other tokens
- tracing macro expansion: Trace
- translating characters: Translit
- undefining macros: Undefine
- UNIX commands, exit status from:Sysval
- UNIX commands, running: Shell commands
- variables, local: Pushdef
- warnings, suppressing: Macro Arguments
- words: Names
- words, lexical structure of:Changeword
Footnotes
[1] Derived from a patch inhttp://lists.gnu.org/archive/html/bug-gnulib/2007-01/msg00389.html,and a followup patch inhttp://lists.gnu.org/archive/html/bug-gnulib/2007-02/msg00000.html