Initial import
This commit is contained in:
8
third_party/m4/COPYING
vendored
Normal file
8
third_party/m4/COPYING
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
.ident "\n
|
||||
m4 (BSD-3)
|
||||
Copyright (c) 1989, 1993
|
||||
The Regents of the University of California. All rights reserved.
|
||||
Copyright (c) 1999 Marc Espie
|
||||
This code is derived from software contributed to Berkeley by
|
||||
Ozan Yigit at York University."
|
||||
.include "libc/disclaimer.inc"
|
||||
64
third_party/m4/NOTES
vendored
Normal file
64
third_party/m4/NOTES
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
m4 - macro processor
|
||||
|
||||
PD m4 is based on the macro tool distributed with the software
|
||||
tools (VOS) package, and described in the "SOFTWARE TOOLS" and
|
||||
"SOFTWARE TOOLS IN PASCAL" books. It has been expanded to include
|
||||
most of the command set of SysV m4, the standard UN*X macro processor.
|
||||
|
||||
Since both PD m4 and UN*X m4 are based on SOFTWARE TOOLS macro,
|
||||
there may be certain implementation similarities between
|
||||
the two. The PD m4 was produced without ANY references to m4
|
||||
sources.
|
||||
|
||||
written by: Ozan S. Yigit
|
||||
|
||||
References:
|
||||
|
||||
Software Tools distribution: macro
|
||||
|
||||
Kernighan, Brian W. and P. J. Plauger, SOFTWARE
|
||||
TOOLS IN PASCAL, Addison-Wesley, Mass. 1981
|
||||
|
||||
Kernighan, Brian W. and P. J. Plauger, SOFTWARE
|
||||
TOOLS, Addison-Wesley, Mass. 1976
|
||||
|
||||
Kernighan, Brian W. and Dennis M. Ritchie,
|
||||
THE M4 MACRO PROCESSOR, Unix Programmer's Manual,
|
||||
Seventh Edition, Vol. 2, Bell Telephone Labs, 1979
|
||||
|
||||
System V man page for M4
|
||||
|
||||
|
||||
Implementation Notes:
|
||||
|
||||
[1] PD m4 uses a different (and simpler) stack mechanism than the one
|
||||
described in Software Tools and Software Tools in Pascal books.
|
||||
The triple stack thing is replaced with a single stack containing
|
||||
the call frames and the arguments. Each frame is back-linked to a
|
||||
previous stack frame, which enables us to rewind the stack after
|
||||
each nested call is completed. Each argument is a character pointer
|
||||
to the beginning of the argument string within the string space.
|
||||
The only exceptions to this are (*) arg 0 and arg 1, which are
|
||||
the macro definition and macro name strings, stored dynamically
|
||||
for the hash table.
|
||||
|
||||
. .
|
||||
| . | <-- sp | . |
|
||||
+-------+ +-----+
|
||||
| arg 3 ------------------------------->| str |
|
||||
+-------+ | . |
|
||||
| arg 2 --------------+ .
|
||||
+-------+ |
|
||||
* | | |
|
||||
+-------+ | +-----+
|
||||
| plev | <-- fp +---------------->| str |
|
||||
+-------+ | . |
|
||||
| type | .
|
||||
+-------+
|
||||
| prcf -----------+ plev: paren level
|
||||
+-------+ | type: call type
|
||||
| . | | prcf: prev. call frame
|
||||
. |
|
||||
+-------+ |
|
||||
| <----------+
|
||||
+-------+
|
||||
380
third_party/m4/README.txt
vendored
Normal file
380
third_party/m4/README.txt
vendored
Normal file
@@ -0,0 +1,380 @@
|
||||
M4(1) Cosmopolitan General Commands Manual -*-text-*-
|
||||
|
||||
𝐍𝐀𝐌𝐄
|
||||
𝗺𝟰 — macro language processor
|
||||
|
||||
𝐒𝐘𝐍𝐎𝐏𝐒𝐈𝐒
|
||||
𝗺𝟰 [-𝐄𝗴𝐏𝘀] [-𝐃n̲a̲m̲e̲[=v̲a̲l̲u̲e̲]] [-𝗱 f̲l̲a̲g̲s̲] [-𝐈 d̲i̲r̲n̲a̲m̲e̲] [-𝗼 f̲i̲l̲e̲n̲a̲m̲e̲]
|
||||
[-𝘁 m̲a̲c̲r̲o̲] [-𝐔n̲a̲m̲e̲] [f̲i̲l̲e̲ .̲.̲.̲]
|
||||
|
||||
𝐃𝐄𝐒𝐂𝐑𝐈𝐏𝐓𝐈𝐎𝐍
|
||||
The 𝗺𝟰 utility is a macro processor that can be used as a front end
|
||||
to any language (e.g., C, ratfor, fortran, lex, and yacc). If no
|
||||
input files are given, 𝗺𝟰 reads from the standard input, otherwise
|
||||
files specified on the command line are processed in the given
|
||||
order. Input files can be regular files, files in the m4 include
|
||||
paths, or a single dash (‘-’), denoting standard input. 𝗺𝟰 writes
|
||||
the processed text to the standard output, unless told otherwise.
|
||||
|
||||
Macro calls have the form name(argument1[, argument2, ..., argu‐
|
||||
mentN]).
|
||||
|
||||
There cannot be any space following the macro name and the open
|
||||
parenthesis (‘(’). If the macro name is not followed by an open
|
||||
parenthesis it is processed with no arguments.
|
||||
|
||||
Macro names consist of a leading alphabetic or underscore possibly
|
||||
followed by alphanumeric or underscore characters, e.g., valid
|
||||
macro names match the pattern “[a-zA-Z_][a-zA-Z0-9_]*”.
|
||||
|
||||
In arguments to macros, leading unquoted space, tab, and newline
|
||||
(‘\n’) characters are ignored. To quote strings, use left and
|
||||
right single quotes (e.g., ‘ this is a string with a leading
|
||||
space’). You can change the quote characters with the 𝗰𝗵𝗮𝗻𝗴𝗲𝗾𝘂𝗼𝘁𝗲
|
||||
built-in macro.
|
||||
|
||||
Most built-ins don't make any sense without arguments, and hence
|
||||
are not recognized as special when not followed by an open paren‐
|
||||
thesis.
|
||||
|
||||
The options are as follows:
|
||||
|
||||
-𝐃n̲a̲m̲e̲[=v̲a̲l̲u̲e̲]
|
||||
Define the symbol n̲a̲m̲e̲ to have some value (or NULL).
|
||||
|
||||
-𝗱 f̲l̲a̲g̲s̲
|
||||
Set trace flags. f̲l̲a̲g̲s̲ may hold the following:
|
||||
|
||||
a̲ print macro arguments.
|
||||
|
||||
c̲ print macro expansion over several lines.
|
||||
|
||||
e̲ print result of macro expansion.
|
||||
|
||||
f̲ print filename location.
|
||||
|
||||
l̲ print line number.
|
||||
|
||||
q̲ quote arguments and expansion with the current
|
||||
quotes.
|
||||
|
||||
t̲ start with all macros traced.
|
||||
|
||||
x̲ number macro expansions.
|
||||
|
||||
V̲ turn on all options.
|
||||
|
||||
By default, trace is set to "eq".
|
||||
|
||||
-𝐄 Set warnings to be fatal. When a single -𝐄 flag is speci‐
|
||||
fied, if warnings are issued, execution continues but 𝗺𝟰
|
||||
will exit with a non-zero exit status. When multiple -𝐄
|
||||
flags are specified, execution will halt upon issuing the
|
||||
first warning and 𝗺𝟰 will exit with a non-zero exit status.
|
||||
This behaviour matches GNU-m4 1.4.9 and later.
|
||||
|
||||
-𝗴 Activate GNU-m4 compatibility mode. In this mode, translit
|
||||
handles simple character ranges (e.g., a-z), regular
|
||||
expressions mimic emacs behavior, multiple m4wrap calls are
|
||||
handled as a stack, the number of diversions is unlimited,
|
||||
empty names for macro definitions are allowed, and eval
|
||||
understands ‘0rbase:value’ numbers.
|
||||
|
||||
-𝐈 d̲i̲r̲n̲a̲m̲e̲
|
||||
Add directory d̲i̲r̲n̲a̲m̲e̲ to the include path.
|
||||
|
||||
-𝗼 f̲i̲l̲e̲n̲a̲m̲e̲
|
||||
Send trace output to f̲i̲l̲e̲n̲a̲m̲e̲.
|
||||
|
||||
-𝐏 Prefix all built-in macros with ‘m4_’. For example,
|
||||
instead of writing 𝗱𝗲𝗳𝗶𝗻𝗲, use 𝗺𝟰_𝗱𝗲𝗳𝗶𝗻𝗲.
|
||||
|
||||
-𝘀 Output line synchronization directives, suitable for
|
||||
cpp(1).
|
||||
|
||||
-𝘁 m̲a̲c̲r̲o̲
|
||||
Turn tracing on for m̲a̲c̲r̲o̲.
|
||||
|
||||
-𝐔n̲a̲m̲e̲ Undefine the symbol n̲a̲m̲e̲.
|
||||
|
||||
𝐒𝐘𝐍𝐓𝐀𝐗
|
||||
𝗺𝟰 provides the following built-in macros. They may be redefined,
|
||||
losing their original meaning. Return values are null unless oth‐
|
||||
erwise stated.
|
||||
|
||||
𝗯𝘂𝗶𝗹𝘁𝗶𝗻(n̲a̲m̲e̲)
|
||||
Calls a built-in by its n̲a̲m̲e̲, overriding possible
|
||||
redefinitions.
|
||||
|
||||
𝗰𝗵𝗮𝗻𝗴𝗲𝗰𝗼𝗺(s̲t̲a̲r̲t̲c̲o̲m̲m̲e̲n̲t̲, e̲n̲d̲c̲o̲m̲m̲e̲n̲t̲)
|
||||
Changes the start comment and end comment sequences.
|
||||
Comment sequences may be up to five characters long.
|
||||
The default values are the hash sign and the newline
|
||||
character.
|
||||
|
||||
# This is a comment
|
||||
|
||||
With no arguments, comments are turned off. With one
|
||||
single argument, the end comment sequence is set to
|
||||
the newline character.
|
||||
|
||||
𝗰𝗵𝗮𝗻𝗴𝗲𝗾𝘂𝗼𝘁𝗲(b̲e̲g̲i̲n̲q̲u̲o̲t̲e̲, e̲n̲d̲q̲u̲o̲t̲e̲)
|
||||
Defines the open quote and close quote sequences.
|
||||
Quote sequences may be up to five characters long.
|
||||
The default values are the backquote character and the
|
||||
quote character.
|
||||
|
||||
`Here is a quoted string'
|
||||
|
||||
With no arguments, the default quotes are restored.
|
||||
With one single argument, the close quote sequence is
|
||||
set to the newline character.
|
||||
|
||||
𝗱𝗲𝗰𝗿(a̲r̲g̲) Decrements the argument a̲r̲g̲ by 1. The argument a̲r̲g̲
|
||||
must be a valid numeric string.
|
||||
|
||||
𝗱𝗲𝗳𝗶𝗻𝗲(n̲a̲m̲e̲, v̲a̲l̲u̲e̲)
|
||||
Define a new macro named by the first argument n̲a̲m̲e̲ to
|
||||
have the value of the second argument v̲a̲l̲u̲e̲. Each
|
||||
occurrence of ‘$n’ (where n̲ is 0 through 9) is
|
||||
replaced by the n̲'th argument. ‘$0’ is the name of
|
||||
the calling macro. Undefined arguments are replaced
|
||||
by a null string. ‘$#’ is replaced by the number of
|
||||
arguments; ‘$*’ is replaced by all arguments comma
|
||||
separated; ‘$@’ is the same as ‘$*’ but all arguments
|
||||
are quoted against further expansion.
|
||||
|
||||
𝗱𝗲𝗳𝗻(n̲a̲m̲e̲, .̲.̲.̲)
|
||||
Returns the quoted definition for each argument. This
|
||||
can be used to rename macro definitions (even for
|
||||
built-in macros).
|
||||
|
||||
𝗱𝗶𝘃𝗲𝗿𝘁(n̲u̲m̲) There are 10 output queues (numbered 0-9). At the end
|
||||
of processing 𝗺𝟰 concatenates all the queues in numer‐
|
||||
ical order to produce the final output. Initially the
|
||||
output queue is 0. The divert macro allows you to
|
||||
select a new output queue (an invalid argument passed
|
||||
to divert causes output to be discarded).
|
||||
|
||||
𝗱𝗶𝘃𝗻𝘂𝗺 Returns the current output queue number.
|
||||
|
||||
𝗱𝗻𝗹 Discard input characters up to and including the next
|
||||
newline.
|
||||
|
||||
𝗱𝘂𝗺𝗽𝗱𝗲𝗳(n̲a̲m̲e̲, .̲.̲.̲)
|
||||
Prints the names and definitions for the named items,
|
||||
or for everything if no arguments are passed.
|
||||
|
||||
𝗲𝗿𝗿𝗽𝗿𝗶𝗻𝘁(m̲s̲g̲)
|
||||
Prints the first argument on the standard error output
|
||||
stream.
|
||||
|
||||
𝗲𝘀𝘆𝘀𝗰𝗺𝗱(c̲m̲d̲)
|
||||
Passes its first argument to a shell and returns the
|
||||
shell's standard output. Note that the shell shares
|
||||
its standard input and standard error with 𝗺𝟰.
|
||||
|
||||
𝗲𝘃𝗮𝗹(e̲x̲p̲r̲[̲,̲r̲a̲d̲i̲x̲[̲,̲m̲i̲n̲i̲m̲u̲m̲]̲]̲)
|
||||
Computes the first argument as an arithmetic expres‐
|
||||
sion using 32-bit arithmetic. Operators are the stan‐
|
||||
dard C ternary, arithmetic, logical, shift, rela‐
|
||||
tional, bitwise, and parentheses operators. You can
|
||||
specify octal, decimal, and hexadecimal numbers as in
|
||||
C. The optional second argument r̲a̲d̲i̲x̲ specifies the
|
||||
radix for the result and the optional third argument
|
||||
m̲i̲n̲i̲m̲u̲m̲ specifies the minimum number of digits in the
|
||||
result.
|
||||
|
||||
𝗲𝘅𝗽𝗿(e̲x̲p̲r̲) This is an alias for 𝗲𝘃𝗮𝗹.
|
||||
|
||||
𝗳𝗼𝗿𝗺𝗮𝘁(f̲o̲r̲m̲a̲t̲s̲t̲r̲i̲n̲g̲, a̲r̲g̲1̲, .̲.̲.̲)
|
||||
Returns f̲o̲r̲m̲a̲t̲s̲t̲r̲i̲n̲g̲ with escape sequences substituted
|
||||
with a̲r̲g̲1̲ and following arguments, in a way similar to
|
||||
printf(3). This built-in is only available in GNU-m4
|
||||
compatibility mode, and the only parameters imple‐
|
||||
mented are there for autoconf compatibility: left-pad‐
|
||||
ding flag, an optional field width, a maximum field
|
||||
width, *-specified field widths, and the %s and %c
|
||||
data type.
|
||||
|
||||
𝗶𝗳𝗱𝗲𝗳(n̲a̲m̲e̲, y̲e̲s̲, n̲o̲)
|
||||
If the macro named by the first argument is defined
|
||||
then return the second argument, otherwise the third.
|
||||
If there is no third argument, the value is NULL. The
|
||||
word "unix" is predefined.
|
||||
|
||||
𝗶𝗳𝗲𝗹𝘀𝗲(a̲, b̲, y̲e̲s̲, .̲.̲.̲)
|
||||
If the first argument a̲ matches the second argument b̲
|
||||
then 𝗶𝗳𝗲𝗹𝘀𝗲() returns the third argument y̲e̲s̲. If the
|
||||
match fails the three arguments are discarded and the
|
||||
next three arguments are used until there is zero or
|
||||
one arguments left, either this last argument or NULL
|
||||
is returned if no other matches were found.
|
||||
|
||||
𝗶𝗻𝗰𝗹𝘂𝗱𝗲(n̲a̲m̲e̲)
|
||||
Returns the contents of the file specified in the
|
||||
first argument. If the file is not found as is, look
|
||||
through the include path: first the directories speci‐
|
||||
fied with -𝐈 on the command line, then the environment
|
||||
variable M4PATH, as a colon-separated list of directo‐
|
||||
ries. Include aborts with an error message if the
|
||||
file cannot be included.
|
||||
|
||||
𝗶𝗻𝗰𝗿(a̲r̲g̲) Increments the argument by 1. The argument must be a
|
||||
valid numeric string.
|
||||
|
||||
𝗶𝗻𝗱𝗲𝘅(s̲t̲r̲i̲n̲g̲, s̲u̲b̲s̲t̲r̲i̲n̲g̲)
|
||||
Returns the index of the second argument in the first
|
||||
argument (e.g., 𝗶𝗻𝗱𝗲𝘅(𝘁𝗵𝗲 𝗾𝘂𝗶𝗰𝗸 𝗯𝗿𝗼𝘄𝗻 𝗳𝗼𝘅 𝗷𝘂𝗺𝗽𝗲𝗱, 𝗳𝗼𝘅)
|
||||
returns 16). If the second argument is not found
|
||||
index returns -1.
|
||||
|
||||
𝗶𝗻𝗱𝗶𝗿(m̲a̲c̲r̲o̲, a̲r̲g̲1̲, .̲.̲.̲)
|
||||
Indirectly calls the macro whose name is passed as the
|
||||
first argument, with the remaining arguments passed as
|
||||
first, ... arguments.
|
||||
|
||||
𝗹𝗲𝗻(a̲r̲g̲) Returns the number of characters in the first argu‐
|
||||
ment. Extra arguments are ignored.
|
||||
|
||||
𝗺𝟰𝗲𝘅𝗶𝘁(c̲o̲d̲e̲)
|
||||
Immediately exits with the return value specified by
|
||||
the first argument, 0 if none.
|
||||
|
||||
𝗺𝟰𝘄𝗿𝗮𝗽(t̲o̲d̲o̲)
|
||||
Allows you to define what happens at the final EOF,
|
||||
usually for cleanup purposes (e.g.,
|
||||
𝗺𝟰𝘄𝗿𝗮𝗽("𝗰𝗹𝗲𝗮𝗻𝘂𝗽(𝘁𝗲𝗺𝗽𝗳𝗶𝗹𝗲)") causes the macro cleanup
|
||||
to be invoked after all other processing is done).
|
||||
|
||||
Multiple calls to 𝗺𝟰𝘄𝗿𝗮𝗽() get inserted in sequence at
|
||||
the final EOF.
|
||||
|
||||
𝗺𝗮𝗸𝗲𝘁𝗲𝗺𝗽(t̲e̲m̲p̲l̲a̲t̲e̲)
|
||||
Like 𝗺𝗸𝘀𝘁𝗲𝗺𝗽.
|
||||
|
||||
𝗺𝗸𝘀𝘁𝗲𝗺𝗽(t̲e̲m̲p̲l̲a̲t̲e̲)
|
||||
Invokes mkstemp(3) on the first argument, and returns
|
||||
the modified string. This can be used to create
|
||||
unique temporary file names.
|
||||
|
||||
𝗽𝗮𝘀𝘁𝗲(f̲i̲l̲e̲) Includes the contents of the file specified by the
|
||||
first argument without any macro processing. Aborts
|
||||
with an error message if the file cannot be included.
|
||||
|
||||
𝗽𝗮𝘁𝘀𝘂𝗯𝘀𝘁(s̲t̲r̲i̲n̲g̲, r̲e̲g̲e̲x̲p̲, r̲e̲p̲l̲a̲c̲e̲m̲e̲n̲t̲)
|
||||
Substitutes a regular expression in a string with a
|
||||
replacement string. Usual substitution patterns
|
||||
apply: an ampersand (‘&’) is replaced by the string
|
||||
matching the regular expression. The string ‘\#’,
|
||||
where ‘#’ is a digit, is replaced by the corresponding
|
||||
back-reference.
|
||||
|
||||
𝗽𝗼𝗽𝗱𝗲𝗳(a̲r̲g̲, .̲.̲.̲)
|
||||
Restores the 𝗽𝘂𝘀𝗵𝗱𝗲𝗳ed definition for each argument.
|
||||
|
||||
𝗽𝘂𝘀𝗵𝗱𝗲𝗳(m̲a̲c̲r̲o̲, d̲e̲f̲)
|
||||
Takes the same arguments as 𝗱𝗲𝗳𝗶𝗻𝗲, but it saves the
|
||||
definition on a stack for later retrieval by 𝗽𝗼𝗽𝗱𝗲𝗳().
|
||||
|
||||
𝗿𝗲𝗴𝗲𝘅𝗽(s̲t̲r̲i̲n̲g̲, r̲e̲g̲e̲x̲p̲, r̲e̲p̲l̲a̲c̲e̲m̲e̲n̲t̲)
|
||||
Finds a regular expression in a string. If no further
|
||||
arguments are given, it returns the first match posi‐
|
||||
tion or -1 if no match. If a third argument is pro‐
|
||||
vided, it returns the replacement string, with sub-
|
||||
patterns replaced.
|
||||
|
||||
𝘀𝗵𝗶𝗳𝘁(a̲r̲g̲1̲, .̲.̲.̲)
|
||||
Returns all but the first argument, the remaining
|
||||
arguments are quoted and pushed back with commas in
|
||||
between. The quoting nullifies the effect of the
|
||||
extra scan that will subsequently be performed.
|
||||
|
||||
𝘀𝗶𝗻𝗰𝗹𝘂𝗱𝗲(f̲i̲l̲e̲)
|
||||
Similar to 𝗶𝗻𝗰𝗹𝘂𝗱𝗲, except it ignores any errors.
|
||||
|
||||
𝘀𝗽𝗮𝘀𝘁𝗲(f̲i̲l̲e̲)
|
||||
Similar to 𝗽𝗮𝘀𝘁𝗲(), except it ignores any errors.
|
||||
|
||||
𝘀𝘂𝗯𝘀𝘁𝗿(s̲t̲r̲i̲n̲g̲, o̲f̲f̲s̲e̲t̲, l̲e̲n̲g̲t̲h̲)
|
||||
Returns a substring of the first argument starting at
|
||||
the offset specified by the second argument and the
|
||||
length specified by the third argument. If no third
|
||||
argument is present it returns the rest of the string.
|
||||
|
||||
𝘀𝘆𝘀𝗰𝗺𝗱(c̲m̲d̲) Passes the first argument to the shell. Nothing is
|
||||
returned.
|
||||
|
||||
𝘀𝘆𝘀𝘃𝗮𝗹 Returns the return value from the last 𝘀𝘆𝘀𝗰𝗺𝗱.
|
||||
|
||||
𝘁𝗿𝗮𝗰𝗲𝗼𝗻(a̲r̲g̲, .̲.̲.̲)
|
||||
Enables tracing of macro expansions for the given
|
||||
arguments, or for all macros if no argument is given.
|
||||
|
||||
𝘁𝗿𝗮𝗰𝗲𝗼𝗳𝗳(a̲r̲g̲, .̲.̲.̲)
|
||||
Disables tracing of macro expansions for the given
|
||||
arguments, or for all macros if no argument is given.
|
||||
|
||||
𝘁𝗿𝗮𝗻𝘀𝗹𝗶𝘁(s̲t̲r̲i̲n̲g̲, m̲a̲p̲f̲r̲o̲m̲, m̲a̲p̲t̲o̲)
|
||||
Transliterate the characters in the first argument
|
||||
from the set given by the second argument to the set
|
||||
given by the third. You cannot use tr(1) style abbre‐
|
||||
viations.
|
||||
|
||||
𝘂𝗻𝗱𝗲𝗳𝗶𝗻𝗲(n̲a̲m̲e̲1̲, .̲.̲.̲)
|
||||
Removes the definition for the macros specified by its
|
||||
arguments.
|
||||
|
||||
𝘂𝗻𝗱𝗶𝘃𝗲𝗿𝘁(a̲r̲g̲, .̲.̲.̲)
|
||||
Flushes the named output queues (or all queues if no
|
||||
arguments).
|
||||
|
||||
𝘂𝗻𝗶𝘅 A pre-defined macro for testing the OS platform.
|
||||
|
||||
__𝗹𝗶𝗻𝗲__ Returns the current file's line number.
|
||||
|
||||
__𝗳𝗶𝗹𝗲__ Returns the current file's name.
|
||||
|
||||
𝐄𝐗𝐈𝐓 𝐒𝐓𝐀𝐓𝐔𝐒
|
||||
The 𝗺𝟰 utility exits 0 on success, and >0 if an error occurs.
|
||||
|
||||
But note that the 𝗺𝟰𝗲𝘅𝗶𝘁 macro can modify the exit status, as can
|
||||
the -𝐄 flag.
|
||||
|
||||
𝐒𝐓𝐀𝐍𝐃𝐀𝐑𝐃𝐒
|
||||
The 𝗺𝟰 utility is compliant with the IEEE Std 1003.1-2008
|
||||
(“POSIX.1”) specification.
|
||||
|
||||
The flags [-𝗱𝐄𝗴𝐈𝐏𝗼𝘁] and the macros 𝗯𝘂𝗶𝗹𝘁𝗶𝗻, 𝗲𝘀𝘆𝘀𝗰𝗺𝗱, 𝗲𝘅𝗽𝗿, 𝗳𝗼𝗿𝗺𝗮𝘁,
|
||||
𝗶𝗻𝗱𝗶𝗿, 𝗽𝗮𝘀𝘁𝗲, 𝗽𝗮𝘁𝘀𝘂𝗯𝘀𝘁, 𝗿𝗲𝗴𝗲𝘅𝗽, 𝘀𝗽𝗮𝘀𝘁𝗲, 𝘂𝗻𝗶𝘅, __𝗹𝗶𝗻𝗲__, and
|
||||
__𝗳𝗶𝗹𝗲__ are extensions to that specification.
|
||||
|
||||
𝗺𝗮𝗸𝗲𝘁𝗲𝗺𝗽 is not supposed to be a synonym for 𝗺𝗸𝘀𝘁𝗲𝗺𝗽, but instead
|
||||
to be an insecure temporary file name creation function. It is
|
||||
marked by IEEE Std 1003.1-2008 (“POSIX.1”) as being obsolescent and
|
||||
should not be used if portability is a concern.
|
||||
|
||||
The output format of 𝘁𝗿𝗮𝗰𝗲𝗼𝗻 and 𝗱𝘂𝗺𝗽𝗱𝗲𝗳 are not specified in any
|
||||
standard, are likely to change and should not be relied upon. The
|
||||
current format of tracing is closely modelled on 𝗴𝗻𝘂-𝗺𝟰, to allow
|
||||
𝗮𝘂𝘁𝗼𝗰𝗼𝗻𝗳 to work.
|
||||
|
||||
The built-ins 𝗽𝘂𝘀𝗵𝗱𝗲𝗳 and 𝗽𝗼𝗽𝗱𝗲𝗳 handle macro definitions as a
|
||||
stack. However, 𝗱𝗲𝗳𝗶𝗻𝗲 interacts with the stack in an undefined
|
||||
way. In this implementation, 𝗱𝗲𝗳𝗶𝗻𝗲 replaces the top-most defini‐
|
||||
tion only. Other implementations may erase all definitions on the
|
||||
stack instead.
|
||||
|
||||
All built-ins do expand without arguments in many other 𝗺𝟰.
|
||||
|
||||
Many other 𝗺𝟰 have dire size limitations with respect to buffer
|
||||
sizes.
|
||||
|
||||
𝐀𝐔𝐓𝐇𝐎𝐑𝐒
|
||||
Ozan Yigit <o̲z̲@̲s̲i̲s̲.̲y̲o̲r̲k̲u̲.̲c̲a̲> and Richard A. O'Keefe
|
||||
<o̲k̲@̲g̲o̲a̲n̲n̲a̲.̲c̲s̲.̲r̲m̲i̲t̲.̲O̲Z̲.̲A̲U̲>.
|
||||
|
||||
GNU-m4 compatibility extensions by Marc Espie
|
||||
<e̲s̲p̲i̲e̲@̲c̲v̲s̲.̲o̲p̲e̲n̲b̲s̲d̲.̲o̲r̲g̲>.
|
||||
|
||||
COSMOPOLITAN June 15, 2017 BSD
|
||||
38
third_party/m4/TEST/ack.m4
vendored
Normal file
38
third_party/m4/TEST/ack.m4
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
# $OpenBSD: ack.m4,v 1.3 2003/06/03 02:56:11 millert Exp $
|
||||
# $NetBSD: ack.m4,v 1.4 1995/09/28 05:37:54 tls Exp $
|
||||
#
|
||||
# Copyright (c) 1989, 1993
|
||||
# The Regents of the University of California. All rights reserved.
|
||||
#
|
||||
# This code is derived from software contributed to Berkeley by
|
||||
# Ozan Yigit.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# 3. Neither the name of the University nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
# SUCH DAMAGE.
|
||||
#
|
||||
# @(#)ack.m4 8.1 (Berkeley) 6/6/93
|
||||
#
|
||||
|
||||
define(ack, `ifelse($1,0,incr($2),$2,0,`ack(DECR($1),1)',
|
||||
`ack(DECR($1), ack($1,DECR($2)))')')
|
||||
43
third_party/m4/TEST/hanoi.m4
vendored
Normal file
43
third_party/m4/TEST/hanoi.m4
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
# $OpenBSD: hanoi.m4,v 1.3 2003/06/03 02:56:11 millert Exp $
|
||||
# $NetBSD: hanoi.m4,v 1.4 1995/09/28 05:37:56 tls Exp $
|
||||
#
|
||||
# Copyright (c) 1989, 1993
|
||||
# The Regents of the University of California. All rights reserved.
|
||||
#
|
||||
# This code is derived from software contributed to Berkeley by
|
||||
# Ozan Yigit.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# 3. Neither the name of the University nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
# SUCH DAMAGE.
|
||||
#
|
||||
# @(#)hanoi.m4 8.1 (Berkeley) 6/6/93
|
||||
#
|
||||
|
||||
define(hanoi, `trans(A, B, C, $1)')
|
||||
|
||||
define(moved,`move disk from $1 to $2
|
||||
')
|
||||
|
||||
define(trans, `ifelse($4,1,`moved($1,$2)',
|
||||
`trans($1,$3,$2,DECR($4))moved($1,$2)trans($3,$2,$1,DECR($4))')')
|
||||
53
third_party/m4/TEST/hash.m4
vendored
Normal file
53
third_party/m4/TEST/hash.m4
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
# $OpenBSD: hash.m4,v 1.3 2003/06/03 02:56:11 millert Exp $
|
||||
# $NetBSD: hash.m4,v 1.4 1995/09/28 05:37:58 tls Exp $
|
||||
#
|
||||
# Copyright (c) 1989, 1993
|
||||
# The Regents of the University of California. All rights reserved.
|
||||
#
|
||||
# This code is derived from software contributed to Berkeley by
|
||||
# Ozan Yigit.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# 3. Neither the name of the University nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
# SUCH DAMAGE.
|
||||
#
|
||||
# @(#)hash.m4 8.1 (Berkeley) 6/6/93
|
||||
#
|
||||
|
||||
dnl This probably will not run on any m4 that cannot
|
||||
dnl handle char constants in eval.
|
||||
dnl
|
||||
changequote(<,>) define(HASHVAL,99) dnl
|
||||
define(hash,<eval(str(substr($1,1),0)%HASHVAL)>) dnl
|
||||
define(str,
|
||||
<ifelse($1,",$2,
|
||||
<str(substr(<$1>,1),<eval($2+'substr($1,0,1)')>)>)
|
||||
>) dnl
|
||||
define(KEYWORD,<$1,hash($1),>) dnl
|
||||
define(TSTART,
|
||||
<struct prehash {
|
||||
char *keyword;
|
||||
int hashval;
|
||||
} keytab[] = {>) dnl
|
||||
define(TEND,< "",0
|
||||
};>) dnl
|
||||
43
third_party/m4/TEST/sqroot.m4
vendored
Normal file
43
third_party/m4/TEST/sqroot.m4
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
# $OpenBSD: sqroot.m4,v 1.3 2003/06/03 02:56:11 millert Exp $
|
||||
# $NetBSD: sqroot.m4,v 1.4 1995/09/28 05:38:01 tls Exp $
|
||||
#
|
||||
# Copyright (c) 1989, 1993
|
||||
# The Regents of the University of California. All rights reserved.
|
||||
#
|
||||
# This code is derived from software contributed to Berkeley by
|
||||
# Ozan Yigit.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# 3. Neither the name of the University nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
# SUCH DAMAGE.
|
||||
#
|
||||
# @(#)sqroot.m4 8.1 (Berkeley) 6/6/93
|
||||
#
|
||||
|
||||
define(square_root,
|
||||
`ifelse(eval($1<0),1,negative-square-root,
|
||||
`square_root_aux($1, 1, eval(($1+1)/2))')')
|
||||
define(square_root_aux,
|
||||
`ifelse($3, $2, $3,
|
||||
$3, eval($1/$2), $3,
|
||||
`square_root_aux($1, $3, eval(($3+($1/$3))/2))')')
|
||||
43
third_party/m4/TEST/string.m4
vendored
Normal file
43
third_party/m4/TEST/string.m4
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
# $OpenBSD: string.m4,v 1.3 2003/06/03 02:56:11 millert Exp $
|
||||
# $NetBSD: string.m4,v 1.4 1995/09/28 05:38:03 tls Exp $
|
||||
#
|
||||
# Copyright (c) 1989, 1993
|
||||
# The Regents of the University of California. All rights reserved.
|
||||
#
|
||||
# This code is derived from software contributed to Berkeley by
|
||||
# Ozan Yigit.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# 3. Neither the name of the University nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
# SUCH DAMAGE.
|
||||
#
|
||||
# @(#)string.m4 8.1 (Berkeley) 6/6/93
|
||||
#
|
||||
|
||||
define(string,`integer $1(len(substr($2,1)))
|
||||
str($1,substr($2,1),0)
|
||||
data $1(len(substr($2,1)))/EOS/
|
||||
')
|
||||
|
||||
define(str,`ifelse($2,",,data $1(incr($3))/`LET'substr($2,0,1)/
|
||||
`str($1,substr($2,1),incr($3))')')
|
||||
241
third_party/m4/TEST/test.m4
vendored
Normal file
241
third_party/m4/TEST/test.m4
vendored
Normal file
@@ -0,0 +1,241 @@
|
||||
# $OpenBSD: test.m4,v 1.3 2003/06/03 02:56:11 millert Exp $
|
||||
# $NetBSD: test.m4,v 1.4 1995/09/28 05:38:05 tls Exp $
|
||||
#
|
||||
# Copyright (c) 1989, 1993
|
||||
# The Regents of the University of California. All rights reserved.
|
||||
#
|
||||
# This code is derived from software contributed to Berkeley by
|
||||
# Ozan Yigit.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# 3. Neither the name of the University nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
# SUCH DAMAGE.
|
||||
#
|
||||
# @(#)test.m4 8.1 (Berkeley) 6/6/93
|
||||
#
|
||||
|
||||
# test file for mp (not comprehensive)
|
||||
#
|
||||
# v7 m4 does not have `decr'.
|
||||
#
|
||||
define(DECR,`eval($1-1)')
|
||||
#
|
||||
# include string macros
|
||||
#
|
||||
include(third_party/m4/TEST/string.m4)
|
||||
#
|
||||
# create some fortrash strings for an even uglier language
|
||||
#
|
||||
string(TEXT, "text")
|
||||
string(DATA, "data")
|
||||
string(BEGIN, "begin")
|
||||
string(END, "end")
|
||||
string(IF, "if")
|
||||
string(THEN, "then")
|
||||
string(ELSE, "else")
|
||||
string(CASE, "case")
|
||||
string(REPEAT, "repeat")
|
||||
string(WHILE, "while")
|
||||
string(DEFAULT, "default")
|
||||
string(UNTIL, "until")
|
||||
string(FUNCTION, "function")
|
||||
string(PROCEDURE, "procedure")
|
||||
string(EXTERNAL, "external")
|
||||
string(FORWARD, "forward")
|
||||
string(TYPE, "type")
|
||||
string(VAR, "var")
|
||||
string(CONST, "const")
|
||||
string(PROGRAM, "program")
|
||||
string(INPUT, "input")
|
||||
string(OUTPUT, "output")
|
||||
#
|
||||
divert(2)
|
||||
diversion #1
|
||||
divert(3)
|
||||
diversion #2
|
||||
divert(4)
|
||||
diversion #3
|
||||
divert(5)
|
||||
diversion #4
|
||||
divert(0)
|
||||
define(abc,xxx)
|
||||
ifdef(`abc',defined,undefined)
|
||||
#
|
||||
# v7 m4 does this wrong. The right output is
|
||||
# this is A vEry lon sEntEnCE
|
||||
# see m4 documentation for translit.
|
||||
#
|
||||
translit(`this is a very long sentence', abcdefg, ABCDEF)
|
||||
#
|
||||
# include towers-of-hanoi
|
||||
#
|
||||
include(third_party/m4/TEST/hanoi.m4)
|
||||
#
|
||||
# some reasonable set of disks
|
||||
#
|
||||
hanoi(6)
|
||||
#
|
||||
# include ackermann's function
|
||||
#
|
||||
include(third_party/m4/TEST/ack.m4)
|
||||
#
|
||||
# something like (3,3) will blow away un*x m4.
|
||||
#
|
||||
ack(2,3)
|
||||
#
|
||||
# include a square_root function for fixed nums
|
||||
#
|
||||
include(third_party/m4/TEST/sqroot.m4)
|
||||
#
|
||||
# some square roots.
|
||||
#
|
||||
square_root(15)
|
||||
square_root(100)
|
||||
square_root(-4)
|
||||
square_root(21372)
|
||||
#
|
||||
# some textual material for enjoyment.
|
||||
#
|
||||
[taken from the 'Clemson University Computer Newsletter',
|
||||
September 1981, pp. 6-7]
|
||||
|
||||
I am a wizard in the magical Kingdom of Transformation and I
|
||||
slay dragons for a living. Actually, I am a systems programmer.
|
||||
One of the problems with systems programming is explaining to
|
||||
non-computer enthusiasts what that is. All of the terms I use to
|
||||
describe my job are totally meaningless to them. Usually my response
|
||||
to questions about my work is to say as little as possible. For
|
||||
instance, if someone asks what happened at work this week, I say
|
||||
"Nothing much" and then I change the subject.
|
||||
|
||||
With the assistance of my brother, a mechanical engineer, I have devised
|
||||
an analogy that everyone can understand. The analogy describes the
|
||||
"Kingdom of Transformation" where travelers wander and are magically
|
||||
transformed. This kingdom is the computer and the travelers are information.
|
||||
The purpose of the computer is to change information to a more meaningful
|
||||
forma. The law of conservation applies here: The computer never creates
|
||||
and never intentionally destroys data. With no further ado, let us travel
|
||||
to the Kingdom of Transformation:
|
||||
|
||||
In a land far, far away, there is a magical kingdom called the Kingdom of
|
||||
Transformation. A king rules over this land and employs a Council of
|
||||
Wizardry. The main purpose of this kingdom is to provide a way for
|
||||
neighboring kingdoms to transform citizens into more useful citizens. This
|
||||
is done by allowing the citizens to enter the kingdom at one of its ports
|
||||
and to travel any of the many routes in the kingdom. They are magically
|
||||
transformed along the way. The income of the Kingdom of Transformation
|
||||
comes from the many toll roads within its boundaries.
|
||||
|
||||
The Kingdom of Transformation was created when several kingdoms got
|
||||
together and discovered a mutual need for new talents and abilities for
|
||||
citizens. They employed CTK, Inc. (Creators of Transformation, Inc.) to
|
||||
create this kingdom. CTK designed the country, its transportation routes,
|
||||
and its laws of transformation, and created the major highway system.
|
||||
|
||||
Hazards
|
||||
=======
|
||||
|
||||
Because magic is not truly controllable, CTK invariably, but unknowingly,
|
||||
creates dragons. Dragons are huge fire-breathing beasts which sometimes
|
||||
injure or kill travelers. Fortunately, they do not travel, but always
|
||||
remain near their den.
|
||||
|
||||
Other hazards also exist which are potentially harmful. As the roads
|
||||
become older and more weatherbeaten, pot-holes will develop, trees will
|
||||
fall on travelers, etc. CTK maintenance men are called to fix these
|
||||
problems.
|
||||
|
||||
Wizards
|
||||
=======
|
||||
|
||||
The wizards play a major role in creating and maintaining the kingdom but
|
||||
get little credit for their work because it is performed secretly. The
|
||||
wizards do not wan the workers or travelers to learn their incantations
|
||||
because many laws would be broken and chaos would result.
|
||||
|
||||
CTK's grand design is always general enough to be applicable in many
|
||||
different situations. As a result, it is often difficult to use. The
|
||||
first duty of the wizards is to tailor the transformation laws so as to be
|
||||
more beneficial and easier to use in their particular environment.
|
||||
|
||||
After creation of the kingdom, a major duty of the wizards is to search for
|
||||
and kill dragons. If travelers do not return on time or if they return
|
||||
injured, the ruler of the country contacts the wizards. If the wizards
|
||||
determine that the injury or death occurred due to the traveler's
|
||||
negligence, they provide the traveler's country with additional warnings.
|
||||
If not, they must determine if the cause was a road hazard or a dragon. If
|
||||
the suspect a road hazard, they call in a CTK maintenance man to locate the
|
||||
hazard and to eliminate it, as in repairing the pothole in the road. If
|
||||
they think that cause was a dragon, then they must find and slay it.
|
||||
|
||||
The most difficult part of eliminating a dragon is finding it. Sometimes
|
||||
the wizard magically knows where the dragon's lair it, but often the wizard
|
||||
must send another traveler along the same route and watch to see where he
|
||||
disappears. This sounds like a failsafe method for finding dragons (and a
|
||||
suicide mission for thr traveler) but the second traveler does not always
|
||||
disappear. Some dragons eat any traveler who comes too close; others are
|
||||
very picky.
|
||||
|
||||
The wizards may call in CTK who designed the highway system and
|
||||
transformation laws to help devise a way to locate the dragon. CTK also
|
||||
helps provide the right spell or incantation to slay the dragon. (There is
|
||||
no general spell to slay dragons; each dragon must be eliminated with a
|
||||
different spell.)
|
||||
|
||||
Because neither CTK nor wizards are perfect, spells to not always work
|
||||
correctly. At best, nothing happens when the wrong spell is uttered. At
|
||||
worst, the dragon becomes a much larger dragon or multiplies into several
|
||||
smaller ones. In either case, new spells must be found.
|
||||
|
||||
If all existing dragons are quiet (i.e. have eaten sufficiently), wizards
|
||||
have time to do other things. They hide in castles and practice spells and
|
||||
incatations. They also devise shortcuts for travelers and new laws of
|
||||
transformation.
|
||||
|
||||
Changes in the Kingdom
|
||||
======================
|
||||
|
||||
As new transformation kingdoms are created and old ones are maintained,
|
||||
CTK, Inc. is constantly learning new things. It learns ways to avoid
|
||||
creating some of the dragons that they have previously created. It also
|
||||
discovers new and better laws of transformation. As a result, CTK will
|
||||
periodically create a new grand design which is far better than the old.
|
||||
The wizards determine when is a good time to implement this new design.
|
||||
This is when the tourist season is slow or when no important travelers
|
||||
(VIPs) are to arrive. The kingdom must be closed for the actual
|
||||
implementation and is leter reopened as a new and better place to go.
|
||||
|
||||
A final question you might ask is what happens when the number of tourists
|
||||
becomes too great for the kingdom to handle in a reasonable period of time
|
||||
(i.e., the tourist lines at the ports are too long). The Kingdom of
|
||||
Transformation has three options: (1) shorten the paths that a tourist must
|
||||
travel, or (2) convince CTK to develop a faster breed of horses so that the
|
||||
travelers can finish sooner, or (3) annex more territories so that the
|
||||
kingdom can handle more travelers.
|
||||
|
||||
Thus ends the story of the Kingdom of Transformation. I hope this has
|
||||
explained my job to you: I slay dragons for a living.
|
||||
|
||||
#
|
||||
#should do an automatic undivert..
|
||||
#
|
||||
640
third_party/m4/TEST/test.m4.golden
vendored
Normal file
640
third_party/m4/TEST/test.m4.golden
vendored
Normal file
@@ -0,0 +1,640 @@
|
||||
# $OpenBSD: test.m4,v 1.3 2003/06/03 02:56:11 millert Exp $
|
||||
# $NetBSD: test.m4,v 1.4 1995/09/28 05:38:05 tls Exp $
|
||||
#
|
||||
# Copyright (c) 1989, 1993
|
||||
# The Regents of the University of California. All rights reserved.
|
||||
#
|
||||
# This code is derived from software contributed to Berkeley by
|
||||
# Ozan Yigit.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# 3. Neither the name of the University nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
# SUCH DAMAGE.
|
||||
#
|
||||
# @(#)test.m4 8.1 (Berkeley) 6/6/93
|
||||
#
|
||||
|
||||
# test file for mp (not comprehensive)
|
||||
#
|
||||
# v7 m4 does not have `decr'.
|
||||
#
|
||||
|
||||
#
|
||||
# include string macros
|
||||
#
|
||||
# $OpenBSD: string.m4,v 1.3 2003/06/03 02:56:11 millert Exp $
|
||||
# $NetBSD: string.m4,v 1.4 1995/09/28 05:38:03 tls Exp $
|
||||
#
|
||||
# Copyright (c) 1989, 1993
|
||||
# The Regents of the University of California. All rights reserved.
|
||||
#
|
||||
# This code is derived from software contributed to Berkeley by
|
||||
# Ozan Yigit.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# 3. Neither the name of the University nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
# SUCH DAMAGE.
|
||||
#
|
||||
# @(#)string.m4 8.1 (Berkeley) 6/6/93
|
||||
#
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#
|
||||
# create some fortrash strings for an even uglier language
|
||||
#
|
||||
integer TEXT(5)
|
||||
data TEXT(1)/LETt/
|
||||
data TEXT(2)/LETe/
|
||||
data TEXT(3)/LETx/
|
||||
data TEXT(4)/LETt/
|
||||
|
||||
data TEXT(5)/EOS/
|
||||
|
||||
integer DATA(5)
|
||||
data DATA(1)/LETd/
|
||||
data DATA(2)/LETa/
|
||||
data DATA(3)/LETt/
|
||||
data DATA(4)/LETa/
|
||||
|
||||
data DATA(5)/EOS/
|
||||
|
||||
integer BEGIN(6)
|
||||
data BEGIN(1)/LETb/
|
||||
data BEGIN(2)/LETe/
|
||||
data BEGIN(3)/LETg/
|
||||
data BEGIN(4)/LETi/
|
||||
data BEGIN(5)/LETn/
|
||||
|
||||
data BEGIN(6)/EOS/
|
||||
|
||||
integer END(4)
|
||||
data END(1)/LETe/
|
||||
data END(2)/LETn/
|
||||
data END(3)/LETd/
|
||||
|
||||
data END(4)/EOS/
|
||||
|
||||
integer IF(3)
|
||||
data IF(1)/LETi/
|
||||
data IF(2)/LETf/
|
||||
|
||||
data IF(3)/EOS/
|
||||
|
||||
integer THEN(5)
|
||||
data THEN(1)/LETt/
|
||||
data THEN(2)/LETh/
|
||||
data THEN(3)/LETe/
|
||||
data THEN(4)/LETn/
|
||||
|
||||
data THEN(5)/EOS/
|
||||
|
||||
integer ELSE(5)
|
||||
data ELSE(1)/LETe/
|
||||
data ELSE(2)/LETl/
|
||||
data ELSE(3)/LETs/
|
||||
data ELSE(4)/LETe/
|
||||
|
||||
data ELSE(5)/EOS/
|
||||
|
||||
integer CASE(5)
|
||||
data CASE(1)/LETc/
|
||||
data CASE(2)/LETa/
|
||||
data CASE(3)/LETs/
|
||||
data CASE(4)/LETe/
|
||||
|
||||
data CASE(5)/EOS/
|
||||
|
||||
integer REPEAT(7)
|
||||
data REPEAT(1)/LETr/
|
||||
data REPEAT(2)/LETe/
|
||||
data REPEAT(3)/LETp/
|
||||
data REPEAT(4)/LETe/
|
||||
data REPEAT(5)/LETa/
|
||||
data REPEAT(6)/LETt/
|
||||
|
||||
data REPEAT(7)/EOS/
|
||||
|
||||
integer WHILE(6)
|
||||
data WHILE(1)/LETw/
|
||||
data WHILE(2)/LETh/
|
||||
data WHILE(3)/LETi/
|
||||
data WHILE(4)/LETl/
|
||||
data WHILE(5)/LETe/
|
||||
|
||||
data WHILE(6)/EOS/
|
||||
|
||||
integer DEFAULT(8)
|
||||
data DEFAULT(1)/LETd/
|
||||
data DEFAULT(2)/LETe/
|
||||
data DEFAULT(3)/LETf/
|
||||
data DEFAULT(4)/LETa/
|
||||
data DEFAULT(5)/LETu/
|
||||
data DEFAULT(6)/LETl/
|
||||
data DEFAULT(7)/LETt/
|
||||
|
||||
data DEFAULT(8)/EOS/
|
||||
|
||||
integer UNTIL(6)
|
||||
data UNTIL(1)/LETu/
|
||||
data UNTIL(2)/LETn/
|
||||
data UNTIL(3)/LETt/
|
||||
data UNTIL(4)/LETi/
|
||||
data UNTIL(5)/LETl/
|
||||
|
||||
data UNTIL(6)/EOS/
|
||||
|
||||
integer FUNCTION(9)
|
||||
data FUNCTION(1)/LETf/
|
||||
data FUNCTION(2)/LETu/
|
||||
data FUNCTION(3)/LETn/
|
||||
data FUNCTION(4)/LETc/
|
||||
data FUNCTION(5)/LETt/
|
||||
data FUNCTION(6)/LETi/
|
||||
data FUNCTION(7)/LETo/
|
||||
data FUNCTION(8)/LETn/
|
||||
|
||||
data FUNCTION(9)/EOS/
|
||||
|
||||
integer PROCEDURE(10)
|
||||
data PROCEDURE(1)/LETp/
|
||||
data PROCEDURE(2)/LETr/
|
||||
data PROCEDURE(3)/LETo/
|
||||
data PROCEDURE(4)/LETc/
|
||||
data PROCEDURE(5)/LETe/
|
||||
data PROCEDURE(6)/LETd/
|
||||
data PROCEDURE(7)/LETu/
|
||||
data PROCEDURE(8)/LETr/
|
||||
data PROCEDURE(9)/LETe/
|
||||
|
||||
data PROCEDURE(10)/EOS/
|
||||
|
||||
integer EXTERNAL(9)
|
||||
data EXTERNAL(1)/LETe/
|
||||
data EXTERNAL(2)/LETx/
|
||||
data EXTERNAL(3)/LETt/
|
||||
data EXTERNAL(4)/LETe/
|
||||
data EXTERNAL(5)/LETr/
|
||||
data EXTERNAL(6)/LETn/
|
||||
data EXTERNAL(7)/LETa/
|
||||
data EXTERNAL(8)/LETl/
|
||||
|
||||
data EXTERNAL(9)/EOS/
|
||||
|
||||
integer FORWARD(8)
|
||||
data FORWARD(1)/LETf/
|
||||
data FORWARD(2)/LETo/
|
||||
data FORWARD(3)/LETr/
|
||||
data FORWARD(4)/LETw/
|
||||
data FORWARD(5)/LETa/
|
||||
data FORWARD(6)/LETr/
|
||||
data FORWARD(7)/LETd/
|
||||
|
||||
data FORWARD(8)/EOS/
|
||||
|
||||
integer TYPE(5)
|
||||
data TYPE(1)/LETt/
|
||||
data TYPE(2)/LETy/
|
||||
data TYPE(3)/LETp/
|
||||
data TYPE(4)/LETe/
|
||||
|
||||
data TYPE(5)/EOS/
|
||||
|
||||
integer VAR(4)
|
||||
data VAR(1)/LETv/
|
||||
data VAR(2)/LETa/
|
||||
data VAR(3)/LETr/
|
||||
|
||||
data VAR(4)/EOS/
|
||||
|
||||
integer CONST(6)
|
||||
data CONST(1)/LETc/
|
||||
data CONST(2)/LETo/
|
||||
data CONST(3)/LETn/
|
||||
data CONST(4)/LETs/
|
||||
data CONST(5)/LETt/
|
||||
|
||||
data CONST(6)/EOS/
|
||||
|
||||
integer PROGRAM(8)
|
||||
data PROGRAM(1)/LETp/
|
||||
data PROGRAM(2)/LETr/
|
||||
data PROGRAM(3)/LETo/
|
||||
data PROGRAM(4)/LETg/
|
||||
data PROGRAM(5)/LETr/
|
||||
data PROGRAM(6)/LETa/
|
||||
data PROGRAM(7)/LETm/
|
||||
|
||||
data PROGRAM(8)/EOS/
|
||||
|
||||
integer INPUT(6)
|
||||
data INPUT(1)/LETi/
|
||||
data INPUT(2)/LETn/
|
||||
data INPUT(3)/LETp/
|
||||
data INPUT(4)/LETu/
|
||||
data INPUT(5)/LETt/
|
||||
|
||||
data INPUT(6)/EOS/
|
||||
|
||||
integer OUTPUT(7)
|
||||
data OUTPUT(1)/LETo/
|
||||
data OUTPUT(2)/LETu/
|
||||
data OUTPUT(3)/LETt/
|
||||
data OUTPUT(4)/LETp/
|
||||
data OUTPUT(5)/LETu/
|
||||
data OUTPUT(6)/LETt/
|
||||
|
||||
data OUTPUT(7)/EOS/
|
||||
|
||||
#
|
||||
|
||||
|
||||
defined
|
||||
#
|
||||
# v7 m4 does this wrong. The right output is
|
||||
# this is A vEry lon sEntEnCE
|
||||
# see m4 documentation for translit.
|
||||
#
|
||||
this is A vEry lon sEntEnCE
|
||||
#
|
||||
# include towers-of-hanoi
|
||||
#
|
||||
# $OpenBSD: hanoi.m4,v 1.3 2003/06/03 02:56:11 millert Exp $
|
||||
# $NetBSD: hanoi.m4,v 1.4 1995/09/28 05:37:56 tls Exp $
|
||||
#
|
||||
# Copyright (c) 1989, 1993
|
||||
# The Regents of the University of California. All rights reserved.
|
||||
#
|
||||
# This code is derived from software contributed to Berkeley by
|
||||
# Ozan Yigit.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# 3. Neither the name of the University nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
# SUCH DAMAGE.
|
||||
#
|
||||
# @(#)hanoi.m4 8.1 (Berkeley) 6/6/93
|
||||
#
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#
|
||||
# some reasonable set of disks
|
||||
#
|
||||
move disk from A to C
|
||||
move disk from A to B
|
||||
move disk from C to B
|
||||
move disk from A to C
|
||||
move disk from B to A
|
||||
move disk from B to C
|
||||
move disk from A to C
|
||||
move disk from A to B
|
||||
move disk from C to B
|
||||
move disk from C to A
|
||||
move disk from B to A
|
||||
move disk from C to B
|
||||
move disk from A to C
|
||||
move disk from A to B
|
||||
move disk from C to B
|
||||
move disk from A to C
|
||||
move disk from B to A
|
||||
move disk from B to C
|
||||
move disk from A to C
|
||||
move disk from B to A
|
||||
move disk from C to B
|
||||
move disk from C to A
|
||||
move disk from B to A
|
||||
move disk from B to C
|
||||
move disk from A to C
|
||||
move disk from A to B
|
||||
move disk from C to B
|
||||
move disk from A to C
|
||||
move disk from B to A
|
||||
move disk from B to C
|
||||
move disk from A to C
|
||||
move disk from A to B
|
||||
move disk from C to B
|
||||
move disk from C to A
|
||||
move disk from B to A
|
||||
move disk from C to B
|
||||
move disk from A to C
|
||||
move disk from A to B
|
||||
move disk from C to B
|
||||
move disk from C to A
|
||||
move disk from B to A
|
||||
move disk from B to C
|
||||
move disk from A to C
|
||||
move disk from B to A
|
||||
move disk from C to B
|
||||
move disk from C to A
|
||||
move disk from B to A
|
||||
move disk from C to B
|
||||
move disk from A to C
|
||||
move disk from A to B
|
||||
move disk from C to B
|
||||
move disk from A to C
|
||||
move disk from B to A
|
||||
move disk from B to C
|
||||
move disk from A to C
|
||||
move disk from A to B
|
||||
move disk from C to B
|
||||
move disk from C to A
|
||||
move disk from B to A
|
||||
move disk from C to B
|
||||
move disk from A to C
|
||||
move disk from A to B
|
||||
move disk from C to B
|
||||
|
||||
#
|
||||
# include ackermann's function
|
||||
#
|
||||
# $OpenBSD: ack.m4,v 1.3 2003/06/03 02:56:11 millert Exp $
|
||||
# $NetBSD: ack.m4,v 1.4 1995/09/28 05:37:54 tls Exp $
|
||||
#
|
||||
# Copyright (c) 1989, 1993
|
||||
# The Regents of the University of California. All rights reserved.
|
||||
#
|
||||
# This code is derived from software contributed to Berkeley by
|
||||
# Ozan Yigit.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# 3. Neither the name of the University nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
# SUCH DAMAGE.
|
||||
#
|
||||
# @(#)ack.m4 8.1 (Berkeley) 6/6/93
|
||||
#
|
||||
|
||||
|
||||
|
||||
#
|
||||
# something like (3,3) will blow away un*x m4.
|
||||
#
|
||||
9
|
||||
#
|
||||
# include a square_root function for fixed nums
|
||||
#
|
||||
# $OpenBSD: sqroot.m4,v 1.3 2003/06/03 02:56:11 millert Exp $
|
||||
# $NetBSD: sqroot.m4,v 1.4 1995/09/28 05:38:01 tls Exp $
|
||||
#
|
||||
# Copyright (c) 1989, 1993
|
||||
# The Regents of the University of California. All rights reserved.
|
||||
#
|
||||
# This code is derived from software contributed to Berkeley by
|
||||
# Ozan Yigit.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# 3. Neither the name of the University nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
# SUCH DAMAGE.
|
||||
#
|
||||
# @(#)sqroot.m4 8.1 (Berkeley) 6/6/93
|
||||
#
|
||||
|
||||
|
||||
|
||||
|
||||
#
|
||||
# some square roots.
|
||||
#
|
||||
3
|
||||
10
|
||||
negative-square-root
|
||||
146
|
||||
#
|
||||
# some textual material for enjoyment.
|
||||
#
|
||||
[taken from the 'Clemson University Computer Newsletter',
|
||||
September 1981, pp. 6-7]
|
||||
|
||||
I am a wizard in the magical Kingdom of Transformation and I
|
||||
slay dragons for a living. Actually, I am a systems programmer.
|
||||
One of the problems with systems programming is explaining to
|
||||
non-computer enthusiasts what that is. All of the terms I use to
|
||||
describe my job are totally meaningless to them. Usually my response
|
||||
to questions about my work is to say as little as possible. For
|
||||
instance, if someone asks what happened at work this week, I say
|
||||
"Nothing much" and then I change the subject.
|
||||
|
||||
With the assistance of my brother, a mechanical engineer, I have devised
|
||||
an analogy that everyone can understand. The analogy describes the
|
||||
"Kingdom of Transformation" where travelers wander and are magically
|
||||
transformed. This kingdom is the computer and the travelers are information.
|
||||
The purpose of the computer is to change information to a more meaningful
|
||||
forma. The law of conservation applies here: The computer never creates
|
||||
and never intentionally destroys data. With no further ado, let us travel
|
||||
to the Kingdom of Transformation:
|
||||
|
||||
In a land far, far away, there is a magical kingdom called the Kingdom of
|
||||
Transformation. A king rules over this land and employs a Council of
|
||||
Wizardry. The main purpose of this kingdom is to provide a way for
|
||||
neighboring kingdoms to transform citizens into more useful citizens. This
|
||||
is done by allowing the citizens to enter the kingdom at one of its ports
|
||||
and to travel any of the many routes in the kingdom. They are magically
|
||||
transformed along the way. The income of the Kingdom of Transformation
|
||||
comes from the many toll roads within its boundaries.
|
||||
|
||||
The Kingdom of Transformation was created when several kingdoms got
|
||||
together and discovered a mutual need for new talents and abilities for
|
||||
citizens. They employed CTK, Inc. (Creators of Transformation, Inc.) to
|
||||
create this kingdom. CTK designed the country, its transportation routes,
|
||||
and its laws of transformation, and created the major highway system.
|
||||
|
||||
Hazards
|
||||
=======
|
||||
|
||||
Because magic is not truly controllable, CTK invariably, but unknowingly,
|
||||
creates dragons. Dragons are huge fire-breathing beasts which sometimes
|
||||
injure or kill travelers. Fortunately, they do not travel, but always
|
||||
remain near their den.
|
||||
|
||||
Other hazards also exist which are potentially harmful. As the roads
|
||||
become older and more weatherbeaten, pot-holes will develop, trees will
|
||||
fall on travelers, etc. CTK maintenance men are called to fix these
|
||||
problems.
|
||||
|
||||
Wizards
|
||||
=======
|
||||
|
||||
The wizards play a major role in creating and maintaining the kingdom but
|
||||
get little credit for their work because it is performed secretly. The
|
||||
wizards do not wan the workers or travelers to learn their incantations
|
||||
because many laws would be broken and chaos would result.
|
||||
|
||||
CTK's grand design is always general enough to be applicable in many
|
||||
different situations. As a result, it is often difficult to use. The
|
||||
first duty of the wizards is to tailor the transformation laws so as to be
|
||||
more beneficial and easier to use in their particular environment.
|
||||
|
||||
After creation of the kingdom, a major duty of the wizards is to search for
|
||||
and kill dragons. If travelers do not return on time or if they return
|
||||
injured, the ruler of the country contacts the wizards. If the wizards
|
||||
determine that the injury or death occurred due to the traveler's
|
||||
negligence, they provide the traveler's country with additional warnings.
|
||||
If not, they must determine if the cause was a road hazard or a dragon. If
|
||||
the suspect a road hazard, they call in a CTK maintenance man to locate the
|
||||
hazard and to eliminate it, as in repairing the pothole in the road. If
|
||||
they think that cause was a dragon, then they must find and slay it.
|
||||
|
||||
The most difficult part of eliminating a dragon is finding it. Sometimes
|
||||
the wizard magically knows where the dragon's lair it, but often the wizard
|
||||
must send another traveler along the same route and watch to see where he
|
||||
disappears. This sounds like a failsafe method for finding dragons (and a
|
||||
suicide mission for thr traveler) but the second traveler does not always
|
||||
disappear. Some dragons eat any traveler who comes too close; others are
|
||||
very picky.
|
||||
|
||||
The wizards may call in CTK who designed the highway system and
|
||||
transformation laws to help devise a way to locate the dragon. CTK also
|
||||
helps provide the right spell or incantation to slay the dragon. (There is
|
||||
no general spell to slay dragons; each dragon must be eliminated with a
|
||||
different spell.)
|
||||
|
||||
Because neither CTK nor wizards are perfect, spells to not always work
|
||||
correctly. At best, nothing happens when the wrong spell is uttered. At
|
||||
worst, the dragon becomes a much larger dragon or multiplies into several
|
||||
smaller ones. In either case, new spells must be found.
|
||||
|
||||
If all existing dragons are quiet (i.e. have eaten sufficiently), wizards
|
||||
have time to do other things. They hide in castles and practice spells and
|
||||
incatations. They also devise shortcuts for travelers and new laws of
|
||||
transformation.
|
||||
|
||||
Changes in the Kingdom
|
||||
======================
|
||||
|
||||
As new transformation kingdoms are created and old ones are maintained,
|
||||
CTK, Inc. is constantly learning new things. It learns ways to avoid
|
||||
creating some of the dragons that they have previously created. It also
|
||||
discovers new and better laws of transformation. As a result, CTK will
|
||||
periodically create a new grand design which is far better than the old.
|
||||
The wizards determine when is a good time to implement this new design.
|
||||
This is when the tourist season is slow or when no important travelers
|
||||
(VIPs) are to arrive. The kingdom must be closed for the actual
|
||||
implementation and is leter reopened as a new and better place to go.
|
||||
|
||||
A final question you might ask is what happens when the number of tourists
|
||||
becomes too great for the kingdom to handle in a reasonable period of time
|
||||
(i.e., the tourist lines at the ports are too long). The Kingdom of
|
||||
Transformation has three options: (1) shorten the paths that a tourist must
|
||||
travel, or (2) convince CTK to develop a faster breed of horses so that the
|
||||
travelers can finish sooner, or (3) annex more territories so that the
|
||||
kingdom can handle more travelers.
|
||||
|
||||
Thus ends the story of the Kingdom of Transformation. I hope this has
|
||||
explained my job to you: I slay dragons for a living.
|
||||
|
||||
#
|
||||
#should do an automatic undivert..
|
||||
#
|
||||
|
||||
diversion #1
|
||||
|
||||
diversion #2
|
||||
|
||||
diversion #3
|
||||
|
||||
diversion #4
|
||||
1031
third_party/m4/eval.c
vendored
Normal file
1031
third_party/m4/eval.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
37
third_party/m4/expr.c
vendored
Normal file
37
third_party/m4/expr.c
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
/* $OpenBSD: expr.c,v 1.18 2010/09/07 19:58:09 marco Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2004 Marc Espie <espie@cvs.openbsd.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
#include "third_party/m4/mdef.h"
|
||||
/**/
|
||||
#include "third_party/m4/extern.h"
|
||||
|
||||
int32_t end_result;
|
||||
const char *copy_toeval;
|
||||
|
||||
extern void yy_scan_string(const char *);
|
||||
extern int yyparse(void);
|
||||
|
||||
int yyerror(const char *msg) {
|
||||
fprintf(stderr, "m4: %s in expr %s\n", msg, copy_toeval);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int expr(const char *toeval) {
|
||||
copy_toeval = toeval;
|
||||
yy_scan_string(toeval);
|
||||
yyparse();
|
||||
return end_result;
|
||||
}
|
||||
183
third_party/m4/extern.h
vendored
Normal file
183
third_party/m4/extern.h
vendored
Normal file
@@ -0,0 +1,183 @@
|
||||
/* clang-format off */
|
||||
/* $OpenBSD: extern.h,v 1.55 2017/06/15 13:48:42 bcallah Exp $ */
|
||||
/* $NetBSD: extern.h,v 1.3 1996/01/13 23:25:24 pk Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Ozan Yigit at York University.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)extern.h 8.1 (Berkeley) 6/6/93
|
||||
*/
|
||||
|
||||
/* eval.c */
|
||||
extern void eval(const char *[], int, int, int);
|
||||
extern void dodefine(const char *, const char *);
|
||||
extern unsigned long expansion_id;
|
||||
|
||||
/* expr.c */
|
||||
extern int expr(const char *);
|
||||
|
||||
/* gnum4.c */
|
||||
extern void addtoincludepath(const char *);
|
||||
extern struct input_file *fopen_trypath(struct input_file *, const char *);
|
||||
extern void doindir(const char *[], int);
|
||||
extern void dobuiltin(const char *[], int);
|
||||
extern void dopatsubst(const char *[], int);
|
||||
extern void doregexp(const char *[], int);
|
||||
|
||||
extern void doprintlineno(struct input_file *);
|
||||
extern void doprintfilename(struct input_file *);
|
||||
|
||||
extern void doesyscmd(const char *);
|
||||
extern void getdivfile(const char *);
|
||||
extern void doformat(const char *[], int);
|
||||
|
||||
extern void m4_warnx(const char *, ...);
|
||||
|
||||
/* look.c */
|
||||
|
||||
#define FLAG_UNTRACED 0
|
||||
#define FLAG_TRACED 1
|
||||
#define FLAG_NO_TRACE 2
|
||||
|
||||
extern void init_macros(void);
|
||||
extern ndptr lookup(const char *);
|
||||
extern void mark_traced(const char *, int);
|
||||
extern struct ohash macros;
|
||||
|
||||
extern struct macro_definition *lookup_macro_definition(const char *);
|
||||
extern void macro_define(const char *, const char *);
|
||||
extern void macro_pushdef(const char *, const char *);
|
||||
extern void macro_popdef(const char *);
|
||||
extern void macro_undefine(const char *);
|
||||
extern void setup_builtin(const char *, unsigned int);
|
||||
extern void macro_for_all(void (*)(const char *, struct macro_definition *));
|
||||
#define macro_getdef(p) ((p)->d)
|
||||
#define macro_name(p) ((p)->name)
|
||||
#define macro_builtin_type(p) ((p)->builtin_type)
|
||||
#define is_traced(p) ((p)->trace_flags == FLAG_NO_TRACE ? (trace_flags & TRACE_ALL) : (p)->trace_flags)
|
||||
|
||||
extern ndptr macro_getbuiltin(const char *);
|
||||
|
||||
/* main.c */
|
||||
extern void outputstr(const char *);
|
||||
extern void do_emit_synchline(void);
|
||||
extern int exit_code;
|
||||
#define emit_synchline() do { if (synch_lines) do_emit_synchline(); } while(0)
|
||||
|
||||
/* misc.c */
|
||||
extern void chrsave(int);
|
||||
extern char *compute_prevep(void);
|
||||
extern void getdiv(int);
|
||||
extern ptrdiff_t indx(const char *, const char *);
|
||||
extern void initspaces(void);
|
||||
extern void killdiv(void);
|
||||
extern void onintr(int);
|
||||
extern void pbnum(int);
|
||||
extern void pbnumbase(int, int, int);
|
||||
extern void pbunsigned(unsigned long);
|
||||
extern void pbstr(const char *);
|
||||
extern void pushback(int);
|
||||
extern void *xalloc(size_t, const char *, ...);
|
||||
extern void *xcalloc(size_t, size_t, const char *, ...);
|
||||
extern void *xrealloc(void *, size_t, const char *, ...);
|
||||
extern void *xreallocarray(void *, size_t, size_t, const char *, ...);
|
||||
extern char *xstrdup(const char *);
|
||||
extern void usage(void);
|
||||
extern void resizedivs(int);
|
||||
extern size_t buffer_mark(void);
|
||||
extern void dump_buffer(FILE *, size_t);
|
||||
extern void m4errx(int, const char *, ...) noreturn;
|
||||
|
||||
extern int obtain_char(struct input_file *);
|
||||
extern void set_input(struct input_file *, FILE *, const char *);
|
||||
extern void release_input(struct input_file *);
|
||||
|
||||
/* speeded-up versions of chrsave/pushback */
|
||||
#define PUSHBACK(c) \
|
||||
do { \
|
||||
if (bp >= endpbb) \
|
||||
enlarge_bufspace(); \
|
||||
*bp++ = (c); \
|
||||
} while(0)
|
||||
|
||||
#define CHRSAVE(c) \
|
||||
do { \
|
||||
if (ep >= endest) \
|
||||
enlarge_strspace(); \
|
||||
*ep++ = (c); \
|
||||
} while(0)
|
||||
|
||||
/* and corresponding exposure for local symbols */
|
||||
extern void enlarge_bufspace(void);
|
||||
extern void enlarge_strspace(void);
|
||||
extern unsigned char *endpbb;
|
||||
extern char *endest;
|
||||
|
||||
/* trace.c */
|
||||
extern unsigned int trace_flags;
|
||||
#define TRACE_ALL 512
|
||||
extern void trace_file(const char *);
|
||||
extern size_t trace(const char **, int, struct input_file *);
|
||||
extern void finish_trace(size_t);
|
||||
extern void set_trace_flags(const char *);
|
||||
extern FILE *traceout;
|
||||
|
||||
extern stae *mstack; /* stack of m4 machine */
|
||||
extern char *sstack; /* shadow stack, for string space extension */
|
||||
extern FILE *active; /* active output file pointer */
|
||||
extern struct input_file infile[];/* input file stack (0=stdin) */
|
||||
extern FILE **outfile; /* diversion array(0=bitbucket) */
|
||||
extern int maxout; /* maximum number of diversions */
|
||||
extern int fp; /* m4 call frame pointer */
|
||||
extern int ilevel; /* input file stack pointer */
|
||||
extern int oindex; /* diversion index. */
|
||||
extern int sp; /* current m4 stack pointer */
|
||||
extern unsigned char *bp; /* first available character */
|
||||
extern unsigned char *buf; /* push-back buffer */
|
||||
extern unsigned char *bufbase; /* buffer base for this ilevel */
|
||||
extern unsigned char *bbase[]; /* buffer base per ilevel */
|
||||
extern char ecommt[MAXCCHARS+1];/* end character for comment */
|
||||
extern char *ep; /* first free char in strspace */
|
||||
extern char lquote[MAXCCHARS+1];/* left quote character (`) */
|
||||
extern char **m4wraps; /* m4wrap string default. */
|
||||
extern int maxwraps; /* size of m4wraps array */
|
||||
extern int wrapindex; /* current index in m4wraps */
|
||||
|
||||
extern char *null; /* as it says.. just a null. */
|
||||
extern char rquote[MAXCCHARS+1];/* right quote character (') */
|
||||
extern char scommt[MAXCCHARS+1];/* start character for comment */
|
||||
extern int synch_lines; /* line synchronisation directives */
|
||||
|
||||
extern int mimic_gnu; /* behaves like gnu-m4 */
|
||||
extern int prefix_builtins; /* prefix builtin macros with m4_ */
|
||||
extern int error_warns; /* make warnings cause exit_code = 1 */
|
||||
extern int fatal_warns; /* make warnings fatal */
|
||||
|
||||
689
third_party/m4/gnum4.c
vendored
Normal file
689
third_party/m4/gnum4.c
vendored
Normal file
@@ -0,0 +1,689 @@
|
||||
/* clang-format off */
|
||||
/* $OpenBSD: gnum4.c,v 1.52 2017/08/21 21:41:13 deraadt Exp $ */
|
||||
/*
|
||||
* Copyright (c) 1999 Marc Espie
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* functions needed to support gnu-m4 extensions, including a fake freezing
|
||||
*/
|
||||
|
||||
#include "third_party/regex/regex.h"
|
||||
#include "third_party/m4/mdef.h"
|
||||
#include "third_party/m4/stdd.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/log/bsd.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/conv/conv.h"
|
||||
#include "libc/calls/weirdtypes.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/paths.h"
|
||||
#include "third_party/m4/extern.h"
|
||||
|
||||
|
||||
int mimic_gnu = 0;
|
||||
|
||||
/*
|
||||
* Support for include path search
|
||||
* First search in the current directory.
|
||||
* If not found, and the path is not absolute, include path kicks in.
|
||||
* First, -I options, in the order found on the command line.
|
||||
* Then M4PATH env variable
|
||||
*/
|
||||
|
||||
struct path_entry {
|
||||
char *name;
|
||||
struct path_entry *next;
|
||||
} *first, *last;
|
||||
|
||||
static struct path_entry *new_path_entry(const char *);
|
||||
static void ensure_m4path(void);
|
||||
static struct input_file *dopath(struct input_file *, const char *);
|
||||
|
||||
static struct path_entry *
|
||||
new_path_entry(const char *dirname)
|
||||
{
|
||||
struct path_entry *n;
|
||||
|
||||
n = malloc(sizeof(struct path_entry));
|
||||
if (!n)
|
||||
errx(1, "out of memory");
|
||||
n->name = xstrdup(dirname);
|
||||
n->next = 0;
|
||||
return n;
|
||||
}
|
||||
|
||||
void
|
||||
addtoincludepath(const char *dirname)
|
||||
{
|
||||
struct path_entry *n;
|
||||
|
||||
n = new_path_entry(dirname);
|
||||
|
||||
if (last) {
|
||||
last->next = n;
|
||||
last = n;
|
||||
}
|
||||
else
|
||||
last = first = n;
|
||||
}
|
||||
|
||||
static void
|
||||
ensure_m4path()
|
||||
{
|
||||
static int envpathdone = 0;
|
||||
char *envpath;
|
||||
char *sweep;
|
||||
char *path;
|
||||
|
||||
if (envpathdone)
|
||||
return;
|
||||
envpathdone = TRUE;
|
||||
envpath = getenv("M4PATH");
|
||||
if (!envpath)
|
||||
return;
|
||||
/* for portability: getenv result is read-only */
|
||||
envpath = xstrdup(envpath);
|
||||
for (sweep = envpath;
|
||||
(path = strsep(&sweep, ":")) != NULL;)
|
||||
addtoincludepath(path);
|
||||
free(envpath);
|
||||
}
|
||||
|
||||
static
|
||||
struct input_file *
|
||||
dopath(struct input_file *i, const char *filename)
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
struct path_entry *pe;
|
||||
FILE *f;
|
||||
|
||||
for (pe = first; pe; pe = pe->next) {
|
||||
snprintf(path, sizeof(path), "%s/%s", pe->name, filename);
|
||||
if ((f = fopen(path, "r")) != 0) {
|
||||
set_input(i, f, path);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct input_file *
|
||||
fopen_trypath(struct input_file *i, const char *filename)
|
||||
{
|
||||
FILE *f;
|
||||
|
||||
f = fopen(filename, "r");
|
||||
if (f != NULL) {
|
||||
set_input(i, f, filename);
|
||||
return i;
|
||||
}
|
||||
if (filename[0] == '/')
|
||||
return NULL;
|
||||
|
||||
ensure_m4path();
|
||||
|
||||
return dopath(i, filename);
|
||||
}
|
||||
|
||||
void
|
||||
doindir(const char *argv[], int argc)
|
||||
{
|
||||
ndptr n;
|
||||
struct macro_definition *p;
|
||||
|
||||
n = lookup(argv[2]);
|
||||
if (n == NULL || (p = macro_getdef(n)) == NULL)
|
||||
m4errx(1, "indir: undefined macro %s.", argv[2]);
|
||||
argv[1] = p->defn;
|
||||
|
||||
eval(argv+1, argc-1, p->type, is_traced(n));
|
||||
}
|
||||
|
||||
void
|
||||
dobuiltin(const char *argv[], int argc)
|
||||
{
|
||||
ndptr p;
|
||||
|
||||
argv[1] = NULL;
|
||||
p = macro_getbuiltin(argv[2]);
|
||||
if (p != NULL)
|
||||
eval(argv+1, argc-1, macro_builtin_type(p), is_traced(p));
|
||||
else
|
||||
m4errx(1, "unknown builtin %s.", argv[2]);
|
||||
}
|
||||
|
||||
|
||||
/* We need some temporary buffer space, as pb pushes BACK and substitution
|
||||
* proceeds forward... */
|
||||
static char *buffer;
|
||||
static size_t bufsize = 0;
|
||||
static size_t current = 0;
|
||||
|
||||
static void addchars(const char *, size_t);
|
||||
static void addchar(int);
|
||||
static char *twiddle(const char *);
|
||||
static char *getstring(void);
|
||||
static void exit_regerror(int, regex_t *, const char *);
|
||||
static void do_subst(const char *, regex_t *, const char *, const char *,
|
||||
regmatch_t *);
|
||||
static void do_regexpindex(const char *, regex_t *, const char *, regmatch_t *);
|
||||
static void do_regexp(const char *, regex_t *, const char *, const char *,
|
||||
regmatch_t *);
|
||||
static void add_sub(int, const char *, regex_t *, regmatch_t *);
|
||||
static void add_replace(const char *, regex_t *, const char *, regmatch_t *);
|
||||
#define addconstantstring(s) addchars((s), sizeof(s)-1)
|
||||
|
||||
static void
|
||||
addchars(const char *c, size_t n)
|
||||
{
|
||||
if (n == 0)
|
||||
return;
|
||||
while (current + n > bufsize) {
|
||||
if (bufsize == 0)
|
||||
bufsize = 1024;
|
||||
else if (bufsize <= SIZE_MAX/2) {
|
||||
bufsize *= 2;
|
||||
} else {
|
||||
errx(1, "size overflow");
|
||||
}
|
||||
buffer = xrealloc(buffer, bufsize, NULL);
|
||||
}
|
||||
memcpy(buffer+current, c, n);
|
||||
current += n;
|
||||
}
|
||||
|
||||
static void
|
||||
addchar(int c)
|
||||
{
|
||||
if (current +1 > bufsize) {
|
||||
if (bufsize == 0)
|
||||
bufsize = 1024;
|
||||
else
|
||||
bufsize *= 2;
|
||||
buffer = xrealloc(buffer, bufsize, NULL);
|
||||
}
|
||||
buffer[current++] = c;
|
||||
}
|
||||
|
||||
static char *
|
||||
getstring(void)
|
||||
{
|
||||
addchar('\0');
|
||||
current = 0;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
exit_regerror(int er, regex_t *re, const char *source)
|
||||
{
|
||||
size_t errlen;
|
||||
char *errbuf;
|
||||
|
||||
errlen = regerror(er, re, NULL, 0);
|
||||
errbuf = xalloc(errlen,
|
||||
"malloc in regerror: %lu", (unsigned long)errlen);
|
||||
regerror(er, re, errbuf, errlen);
|
||||
m4errx(1, "regular expression error in %s: %s.", source, errbuf);
|
||||
}
|
||||
|
||||
/* warnx() plus check to see if we need to change exit code or exit.
|
||||
* -E flag functionality.
|
||||
*/
|
||||
void
|
||||
m4_warnx(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vwarnx(fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (fatal_warns)
|
||||
exit(1);
|
||||
if (error_warns)
|
||||
exit_code = 1;
|
||||
}
|
||||
|
||||
static void
|
||||
add_sub(int n, const char *string, regex_t *re, regmatch_t *pm)
|
||||
{
|
||||
if (n > re->re_nsub)
|
||||
m4_warnx("No subexpression %d", n);
|
||||
/* Subexpressions that did not match are
|
||||
* not an error. */
|
||||
else if (pm[n].rm_so != -1 &&
|
||||
pm[n].rm_eo != -1) {
|
||||
addchars(string + pm[n].rm_so,
|
||||
pm[n].rm_eo - pm[n].rm_so);
|
||||
}
|
||||
}
|
||||
|
||||
/* Add replacement string to the output buffer, recognizing special
|
||||
* constructs and replacing them with substrings of the original string.
|
||||
*/
|
||||
static void
|
||||
add_replace(const char *string, regex_t *re, const char *replace, regmatch_t *pm)
|
||||
{
|
||||
const char *p;
|
||||
|
||||
for (p = replace; *p != '\0'; p++) {
|
||||
if (*p == '&' && !mimic_gnu) {
|
||||
add_sub(0, string, re, pm);
|
||||
continue;
|
||||
}
|
||||
if (*p == '\\') {
|
||||
if (p[1] == '\\') {
|
||||
addchar(p[1]);
|
||||
p++;
|
||||
continue;
|
||||
}
|
||||
if (p[1] == '&') {
|
||||
if (mimic_gnu)
|
||||
add_sub(0, string, re, pm);
|
||||
else
|
||||
addchar(p[1]);
|
||||
p++;
|
||||
continue;
|
||||
}
|
||||
if (isdigit((unsigned char)p[1])) {
|
||||
add_sub(*(++p) - '0', string, re, pm);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
addchar(*p);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
do_subst(const char *string, regex_t *re, const char *source,
|
||||
const char *replace, regmatch_t *pm)
|
||||
{
|
||||
int error;
|
||||
int flags = 0;
|
||||
const char *last_match = NULL;
|
||||
|
||||
while ((error = regexec(re, string, re->re_nsub+1, pm, flags)) == 0) {
|
||||
if (pm[0].rm_eo != 0) {
|
||||
if (string[pm[0].rm_eo-1] == '\n')
|
||||
flags = 0;
|
||||
else
|
||||
flags = REG_NOTBOL;
|
||||
}
|
||||
|
||||
/* NULL length matches are special... We use the `vi-mode'
|
||||
* rule: don't allow a NULL-match at the last match
|
||||
* position.
|
||||
*/
|
||||
if (pm[0].rm_so == pm[0].rm_eo &&
|
||||
string + pm[0].rm_so == last_match) {
|
||||
if (*string == '\0')
|
||||
return;
|
||||
addchar(*string);
|
||||
if (*string++ == '\n')
|
||||
flags = 0;
|
||||
else
|
||||
flags = REG_NOTBOL;
|
||||
continue;
|
||||
}
|
||||
last_match = string + pm[0].rm_so;
|
||||
addchars(string, pm[0].rm_so);
|
||||
add_replace(string, re, replace, pm);
|
||||
string += pm[0].rm_eo;
|
||||
}
|
||||
if (error != REG_NOMATCH)
|
||||
exit_regerror(error, re, source);
|
||||
pbstr(string);
|
||||
}
|
||||
|
||||
static void
|
||||
do_regexp(const char *string, regex_t *re, const char *source,
|
||||
const char *replace, regmatch_t *pm)
|
||||
{
|
||||
int error;
|
||||
|
||||
switch(error = regexec(re, string, re->re_nsub+1, pm, 0)) {
|
||||
case 0:
|
||||
add_replace(string, re, replace, pm);
|
||||
pbstr(getstring());
|
||||
break;
|
||||
case REG_NOMATCH:
|
||||
break;
|
||||
default:
|
||||
exit_regerror(error, re, source);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
do_regexpindex(const char *string, regex_t *re, const char *source,
|
||||
regmatch_t *pm)
|
||||
{
|
||||
int error;
|
||||
|
||||
switch(error = regexec(re, string, re->re_nsub+1, pm, 0)) {
|
||||
case 0:
|
||||
pbunsigned(pm[0].rm_so);
|
||||
break;
|
||||
case REG_NOMATCH:
|
||||
pbnum(-1);
|
||||
break;
|
||||
default:
|
||||
exit_regerror(error, re, source);
|
||||
}
|
||||
}
|
||||
|
||||
/* In Gnu m4 mode, parentheses for backmatch don't work like POSIX 1003.2
|
||||
* says. So we twiddle with the regexp before passing it to regcomp.
|
||||
*/
|
||||
static char *
|
||||
twiddle(const char *p)
|
||||
{
|
||||
/* + at start of regexp is a normal character for Gnu m4 */
|
||||
if (*p == '^') {
|
||||
addchar(*p);
|
||||
p++;
|
||||
}
|
||||
if (*p == '+') {
|
||||
addchar('\\');
|
||||
}
|
||||
/* This could use strcspn for speed... */
|
||||
while (*p != '\0') {
|
||||
if (*p == '\\') {
|
||||
switch(p[1]) {
|
||||
case '(':
|
||||
case ')':
|
||||
case '|':
|
||||
addchar(p[1]);
|
||||
break;
|
||||
case 'w':
|
||||
addconstantstring("[_a-zA-Z0-9]");
|
||||
break;
|
||||
case 'W':
|
||||
addconstantstring("[^_a-zA-Z0-9]");
|
||||
break;
|
||||
case '<':
|
||||
addconstantstring("[[:<:]]");
|
||||
break;
|
||||
case '>':
|
||||
addconstantstring("[[:>:]]");
|
||||
break;
|
||||
default:
|
||||
addchars(p, 2);
|
||||
break;
|
||||
}
|
||||
p+=2;
|
||||
continue;
|
||||
}
|
||||
if (*p == '(' || *p == ')' || *p == '|')
|
||||
addchar('\\');
|
||||
|
||||
addchar(*p);
|
||||
p++;
|
||||
}
|
||||
return getstring();
|
||||
}
|
||||
|
||||
/* patsubst(string, regexp, opt replacement) */
|
||||
/* argv[2]: string
|
||||
* argv[3]: regexp
|
||||
* argv[4]: opt rep
|
||||
*/
|
||||
void
|
||||
dopatsubst(const char *argv[], int argc)
|
||||
{
|
||||
if (argc <= 3) {
|
||||
m4_warnx("Too few arguments to patsubst");
|
||||
return;
|
||||
}
|
||||
/* special case: empty regexp */
|
||||
if (argv[3][0] == '\0') {
|
||||
const char *s;
|
||||
size_t len;
|
||||
if (argc > 4 && argv[4])
|
||||
len = strlen(argv[4]);
|
||||
else
|
||||
len = 0;
|
||||
for (s = argv[2]; *s != '\0'; s++) {
|
||||
addchars(argv[4], len);
|
||||
addchar(*s);
|
||||
}
|
||||
} else {
|
||||
int error;
|
||||
regex_t re;
|
||||
regmatch_t *pmatch;
|
||||
int mode = REG_EXTENDED;
|
||||
const char *source;
|
||||
size_t l = strlen(argv[3]);
|
||||
|
||||
if (!mimic_gnu ||
|
||||
(argv[3][0] == '^') ||
|
||||
(l > 0 && argv[3][l-1] == '$'))
|
||||
mode |= REG_NEWLINE;
|
||||
|
||||
source = mimic_gnu ? twiddle(argv[3]) : argv[3];
|
||||
error = regcomp(&re, source, mode);
|
||||
if (error != 0)
|
||||
exit_regerror(error, &re, source);
|
||||
|
||||
pmatch = xreallocarray(NULL, re.re_nsub+1, sizeof(regmatch_t),
|
||||
NULL);
|
||||
do_subst(argv[2], &re, source,
|
||||
argc > 4 && argv[4] != NULL ? argv[4] : "", pmatch);
|
||||
free(pmatch);
|
||||
regfree(&re);
|
||||
}
|
||||
pbstr(getstring());
|
||||
}
|
||||
|
||||
void
|
||||
doregexp(const char *argv[], int argc)
|
||||
{
|
||||
int error;
|
||||
regex_t re;
|
||||
regmatch_t *pmatch;
|
||||
const char *source;
|
||||
|
||||
if (argc <= 3) {
|
||||
m4_warnx("Too few arguments to regexp");
|
||||
return;
|
||||
}
|
||||
/* special gnu case */
|
||||
if (argv[3][0] == '\0' && mimic_gnu) {
|
||||
if (argc == 4 || argv[4] == NULL)
|
||||
return;
|
||||
else
|
||||
pbstr(argv[4]);
|
||||
}
|
||||
source = mimic_gnu ? twiddle(argv[3]) : argv[3];
|
||||
error = regcomp(&re, source, REG_EXTENDED|REG_NEWLINE);
|
||||
if (error != 0)
|
||||
exit_regerror(error, &re, source);
|
||||
|
||||
pmatch = xreallocarray(NULL, re.re_nsub+1, sizeof(regmatch_t), NULL);
|
||||
if (argc == 4 || argv[4] == NULL)
|
||||
do_regexpindex(argv[2], &re, source, pmatch);
|
||||
else
|
||||
do_regexp(argv[2], &re, source, argv[4], pmatch);
|
||||
free(pmatch);
|
||||
regfree(&re);
|
||||
}
|
||||
|
||||
void
|
||||
doformat(const char *argv[], int argc)
|
||||
{
|
||||
const char *format = argv[2];
|
||||
int pos = 3;
|
||||
int left_padded;
|
||||
long width;
|
||||
size_t l;
|
||||
const char *thisarg;
|
||||
char temp[2];
|
||||
long extra;
|
||||
|
||||
while (*format != 0) {
|
||||
if (*format != '%') {
|
||||
addchar(*format++);
|
||||
continue;
|
||||
}
|
||||
|
||||
format++;
|
||||
if (*format == '%') {
|
||||
addchar(*format++);
|
||||
continue;
|
||||
}
|
||||
if (*format == 0) {
|
||||
addchar('%');
|
||||
break;
|
||||
}
|
||||
|
||||
if (*format == '*') {
|
||||
format++;
|
||||
if (pos >= argc)
|
||||
m4errx(1,
|
||||
"Format with too many format specifiers.");
|
||||
width = strtol(argv[pos++], NULL, 10);
|
||||
} else {
|
||||
width = strtol(format, (char **)&format, 10);
|
||||
}
|
||||
if (width < 0) {
|
||||
left_padded = 1;
|
||||
width = -width;
|
||||
} else {
|
||||
left_padded = 0;
|
||||
}
|
||||
if (*format == '.') {
|
||||
format++;
|
||||
if (*format == '*') {
|
||||
format++;
|
||||
if (pos >= argc)
|
||||
m4errx(1,
|
||||
"Format with too many format specifiers.");
|
||||
extra = strtol(argv[pos++], NULL, 10);
|
||||
} else {
|
||||
extra = strtol(format, (char **)&format, 10);
|
||||
}
|
||||
} else {
|
||||
extra = LONG_MAX;
|
||||
}
|
||||
if (pos >= argc)
|
||||
m4errx(1, "Format with too many format specifiers.");
|
||||
switch(*format) {
|
||||
case 's':
|
||||
thisarg = argv[pos++];
|
||||
break;
|
||||
case 'c':
|
||||
temp[0] = strtoul(argv[pos++], NULL, 10);
|
||||
temp[1] = 0;
|
||||
thisarg = temp;
|
||||
break;
|
||||
default:
|
||||
m4errx(1, "Unsupported format specification: %s.",
|
||||
argv[2]);
|
||||
}
|
||||
format++;
|
||||
l = strlen(thisarg);
|
||||
if (l > extra)
|
||||
l = extra;
|
||||
if (!left_padded) {
|
||||
while (l < width--)
|
||||
addchar(' ');
|
||||
}
|
||||
addchars(thisarg, l);
|
||||
if (left_padded) {
|
||||
while (l < width--)
|
||||
addchar(' ');
|
||||
}
|
||||
}
|
||||
pbstr(getstring());
|
||||
}
|
||||
|
||||
void
|
||||
doesyscmd(const char *cmd)
|
||||
{
|
||||
int p[2];
|
||||
pid_t cpid;
|
||||
char *argv[4];
|
||||
int cc;
|
||||
int status;
|
||||
|
||||
/* Follow gnu m4 documentation: first flush buffers. */
|
||||
fflush(NULL);
|
||||
|
||||
argv[0] = "sh";
|
||||
argv[1] = "-c";
|
||||
argv[2] = (char *)cmd;
|
||||
argv[3] = NULL;
|
||||
|
||||
/* Just set up standard output, share stderr and stdin with m4 */
|
||||
if (pipe(p) == -1)
|
||||
err(1, "bad pipe");
|
||||
switch(cpid = fork()) {
|
||||
case -1:
|
||||
err(1, "bad fork");
|
||||
/* NOTREACHED */
|
||||
case 0:
|
||||
(void) close(p[0]);
|
||||
(void) dup2(p[1], 1);
|
||||
(void) close(p[1]);
|
||||
execv(_PATH_BSHELL, argv);
|
||||
exit(1);
|
||||
default:
|
||||
/* Read result in two stages, since m4's buffer is
|
||||
* pushback-only. */
|
||||
(void) close(p[1]);
|
||||
do {
|
||||
char result[1024];
|
||||
cc = read(p[0], result, sizeof result);
|
||||
if (cc > 0)
|
||||
addchars(result, cc);
|
||||
} while (cc > 0 || (cc == -1 && errno == EINTR));
|
||||
|
||||
(void) close(p[0]);
|
||||
while (waitpid(cpid, &status, 0) == -1) {
|
||||
if (errno != EINTR)
|
||||
break;
|
||||
}
|
||||
pbstr(getstring());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
getdivfile(const char *name)
|
||||
{
|
||||
FILE *f;
|
||||
int c;
|
||||
|
||||
f = fopen(name, "r");
|
||||
if (!f)
|
||||
return;
|
||||
|
||||
while ((c = getc(f))!= EOF)
|
||||
putc(c, active);
|
||||
(void) fclose(f);
|
||||
}
|
||||
333
third_party/m4/look.c
vendored
Normal file
333
third_party/m4/look.c
vendored
Normal file
@@ -0,0 +1,333 @@
|
||||
/* clang-format off */
|
||||
/* $OpenBSD: look.c,v 1.24 2014/12/21 09:33:12 espie Exp $ */
|
||||
/*
|
||||
* Copyright (c) 1989, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Ozan Yigit at York University.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* look.c
|
||||
* Facility: m4 macro processor
|
||||
* by: oz
|
||||
*/
|
||||
|
||||
#include "third_party/m4/mdef.h"
|
||||
#include "third_party/m4/stdd.h"
|
||||
#include "third_party/m4/extern.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "third_party/m4/ohash.h"
|
||||
|
||||
static void *hash_calloc(size_t, size_t, void *);
|
||||
static void hash_free(void *, void *);
|
||||
static void *element_alloc(size_t, void *);
|
||||
static void setup_definition(struct macro_definition *, const char *,
|
||||
const char *);
|
||||
static void free_definition(char *);
|
||||
static void keep(char *);
|
||||
static int string_in_use(const char *);
|
||||
|
||||
static struct ohash_info macro_info = {
|
||||
offsetof(struct ndblock, name),
|
||||
NULL, hash_calloc, hash_free, element_alloc };
|
||||
|
||||
struct ohash macros;
|
||||
|
||||
/* Support routines for hash tables. */
|
||||
void *
|
||||
hash_calloc(size_t n, size_t s, void *u UNUSED)
|
||||
{
|
||||
void *storage = xcalloc(n, s, "hash alloc");
|
||||
return storage;
|
||||
}
|
||||
|
||||
void
|
||||
hash_free(void *p, void *u UNUSED)
|
||||
{
|
||||
free(p);
|
||||
}
|
||||
|
||||
void *
|
||||
element_alloc(size_t s, void *u UNUSED)
|
||||
{
|
||||
return xalloc(s, "element alloc");
|
||||
}
|
||||
|
||||
void
|
||||
init_macros()
|
||||
{
|
||||
ohash_init(¯os, 10, ¯o_info);
|
||||
}
|
||||
|
||||
/*
|
||||
* find name in the hash table
|
||||
*/
|
||||
ndptr
|
||||
lookup(const char *name)
|
||||
{
|
||||
return ohash_find(¯os, ohash_qlookup(¯os, name));
|
||||
}
|
||||
|
||||
struct macro_definition *
|
||||
lookup_macro_definition(const char *name)
|
||||
{
|
||||
ndptr p;
|
||||
|
||||
p = ohash_find(¯os, ohash_qlookup(¯os, name));
|
||||
if (p)
|
||||
return p->d;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
setup_definition(struct macro_definition *d, const char *defn, const char *name)
|
||||
{
|
||||
ndptr p;
|
||||
|
||||
if (strncmp(defn, BUILTIN_MARKER, sizeof(BUILTIN_MARKER)-1) == 0 &&
|
||||
(p = macro_getbuiltin(defn+sizeof(BUILTIN_MARKER)-1)) != NULL) {
|
||||
d->type = macro_builtin_type(p);
|
||||
d->defn = xstrdup(defn+sizeof(BUILTIN_MARKER)-1);
|
||||
} else {
|
||||
if (!*defn)
|
||||
d->defn = null;
|
||||
else
|
||||
d->defn = xstrdup(defn);
|
||||
d->type = MACRTYPE;
|
||||
}
|
||||
if (STREQ(name, defn))
|
||||
d->type |= RECDEF;
|
||||
}
|
||||
|
||||
static ndptr
|
||||
create_entry(const char *name)
|
||||
{
|
||||
const char *end = NULL;
|
||||
unsigned int i;
|
||||
ndptr n;
|
||||
|
||||
i = ohash_qlookupi(¯os, name, &end);
|
||||
n = ohash_find(¯os, i);
|
||||
if (n == NULL) {
|
||||
n = ohash_create_entry(¯o_info, name, &end);
|
||||
ohash_insert(¯os, i, n);
|
||||
n->trace_flags = FLAG_NO_TRACE;
|
||||
n->builtin_type = MACRTYPE;
|
||||
n->d = NULL;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
void
|
||||
macro_define(const char *name, const char *defn)
|
||||
{
|
||||
ndptr n = create_entry(name);
|
||||
if (n->d != NULL) {
|
||||
if (n->d->defn != null)
|
||||
free_definition(n->d->defn);
|
||||
} else {
|
||||
n->d = xalloc(sizeof(struct macro_definition), NULL);
|
||||
n->d->next = NULL;
|
||||
}
|
||||
setup_definition(n->d, defn, name);
|
||||
}
|
||||
|
||||
void
|
||||
macro_pushdef(const char *name, const char *defn)
|
||||
{
|
||||
ndptr n;
|
||||
struct macro_definition *d;
|
||||
|
||||
n = create_entry(name);
|
||||
d = xalloc(sizeof(struct macro_definition), NULL);
|
||||
d->next = n->d;
|
||||
n->d = d;
|
||||
setup_definition(n->d, defn, name);
|
||||
}
|
||||
|
||||
void
|
||||
macro_undefine(const char *name)
|
||||
{
|
||||
ndptr n = lookup(name);
|
||||
if (n != NULL) {
|
||||
struct macro_definition *r, *r2;
|
||||
|
||||
for (r = n->d; r != NULL; r = r2) {
|
||||
r2 = r->next;
|
||||
if (r->defn != null)
|
||||
free(r->defn);
|
||||
free(r);
|
||||
}
|
||||
n->d = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
macro_popdef(const char *name)
|
||||
{
|
||||
ndptr n = lookup(name);
|
||||
|
||||
if (n != NULL) {
|
||||
struct macro_definition *r = n->d;
|
||||
if (r != NULL) {
|
||||
n->d = r->next;
|
||||
if (r->defn != null)
|
||||
free(r->defn);
|
||||
free(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
macro_for_all(void (*f)(const char *, struct macro_definition *))
|
||||
{
|
||||
ndptr n;
|
||||
unsigned int i;
|
||||
|
||||
for (n = ohash_first(¯os, &i); n != NULL;
|
||||
n = ohash_next(¯os, &i))
|
||||
if (n->d != NULL)
|
||||
f(n->name, n->d);
|
||||
}
|
||||
|
||||
void
|
||||
setup_builtin(const char *name, unsigned int type)
|
||||
{
|
||||
ndptr n;
|
||||
char *name2;
|
||||
|
||||
if (prefix_builtins) {
|
||||
name2 = xalloc(strlen(name)+3+1, NULL);
|
||||
memcpy(name2, "m4_", 3);
|
||||
memcpy(name2 + 3, name, strlen(name)+1);
|
||||
} else
|
||||
name2 = xstrdup(name);
|
||||
|
||||
n = create_entry(name2);
|
||||
n->builtin_type = type;
|
||||
n->d = xalloc(sizeof(struct macro_definition), NULL);
|
||||
n->d->defn = name2;
|
||||
n->d->type = type;
|
||||
n->d->next = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
mark_traced(const char *name, int on)
|
||||
{
|
||||
ndptr p;
|
||||
unsigned int i;
|
||||
|
||||
if (name == NULL) {
|
||||
if (on)
|
||||
trace_flags |= TRACE_ALL;
|
||||
else
|
||||
trace_flags &= ~TRACE_ALL;
|
||||
for (p = ohash_first(¯os, &i); p != NULL;
|
||||
p = ohash_next(¯os, &i))
|
||||
p->trace_flags = FLAG_NO_TRACE;
|
||||
} else {
|
||||
p = create_entry(name);
|
||||
p->trace_flags = on;
|
||||
}
|
||||
}
|
||||
|
||||
ndptr
|
||||
macro_getbuiltin(const char *name)
|
||||
{
|
||||
ndptr p;
|
||||
|
||||
p = lookup(name);
|
||||
if (p == NULL || p->builtin_type == MACRTYPE)
|
||||
return NULL;
|
||||
else
|
||||
return p;
|
||||
}
|
||||
|
||||
/* XXX things are slightly more complicated than they seem.
|
||||
* a macro may actually be "live" (in the middle of an expansion
|
||||
* on the stack.
|
||||
* So we actually may need to place it in an array for later...
|
||||
*/
|
||||
|
||||
static int kept_capacity = 0;
|
||||
static int kept_size = 0;
|
||||
static char **kept = NULL;
|
||||
|
||||
static void
|
||||
keep(char *ptr)
|
||||
{
|
||||
if (kept_capacity <= kept_size) {
|
||||
if (kept_capacity)
|
||||
kept_capacity *= 2;
|
||||
else
|
||||
kept_capacity = 50;
|
||||
kept = xreallocarray(kept, kept_capacity,
|
||||
sizeof(char *), "Out of memory while saving %d strings\n",
|
||||
kept_capacity);
|
||||
}
|
||||
kept[kept_size++] = ptr;
|
||||
}
|
||||
|
||||
static int
|
||||
string_in_use(const char *ptr)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i <= sp; i++) {
|
||||
if (sstack[i] == STORAGE_MACRO && mstack[i].sstr == ptr)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
free_definition(char *ptr)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* first try to free old strings */
|
||||
for (i = 0; i < kept_size; i++) {
|
||||
if (!string_in_use(kept[i])) {
|
||||
kept_size--;
|
||||
free(kept[i]);
|
||||
if (i != kept_size)
|
||||
kept[i] = kept[kept_size];
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
/* then deal with us */
|
||||
if (string_in_use(ptr))
|
||||
keep(ptr);
|
||||
else
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
524
third_party/m4/m4.1
vendored
Normal file
524
third_party/m4/m4.1
vendored
Normal file
@@ -0,0 +1,524 @@
|
||||
.\" @(#) $OpenBSD: m4.1,v 1.64 2017/06/15 13:48:42 bcallah Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1989, 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
.\"
|
||||
.\" This code is derived from software contributed to Berkeley by
|
||||
.\" Ozan Yigit at York University.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\" 3. Neither the name of the University nor the names of its contributors
|
||||
.\" may be used to endorse or promote products derived from this software
|
||||
.\" without specific prior written permission.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd $Mdocdate: June 15 2017 $
|
||||
.Dt M4 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm m4
|
||||
.Nd macro language processor
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl EgPs
|
||||
.Oo
|
||||
.Sm off
|
||||
.Fl D Ar name Op No = Ar value
|
||||
.Sm on
|
||||
.Oc
|
||||
.Op Fl d Ar flags
|
||||
.Op Fl I Ar dirname
|
||||
.Op Fl o Ar filename
|
||||
.Op Fl t Ar macro
|
||||
.Op Fl U Ns Ar name
|
||||
.Op Ar
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
utility is a macro processor that can be used as a front end to any
|
||||
language (e.g., C, ratfor, fortran, lex, and yacc).
|
||||
If no input files are given,
|
||||
.Nm
|
||||
reads from the standard input,
|
||||
otherwise files specified on the command line are
|
||||
processed in the given order.
|
||||
Input files can be regular files, files in the m4 include paths, or a
|
||||
single dash
|
||||
.Pq Sq - ,
|
||||
denoting standard input.
|
||||
.Nm
|
||||
writes
|
||||
the processed text to the standard output, unless told otherwise.
|
||||
.Pp
|
||||
Macro calls have the form name(argument1[, argument2, ..., argumentN]).
|
||||
.Pp
|
||||
There cannot be any space following the macro name and the open
|
||||
parenthesis
|
||||
.Pq Sq \&( .
|
||||
If the macro name is not followed by an open
|
||||
parenthesis it is processed with no arguments.
|
||||
.Pp
|
||||
Macro names consist of a leading alphabetic or underscore
|
||||
possibly followed by alphanumeric or underscore characters, e.g.,
|
||||
valid macro names match the pattern
|
||||
.Dq [a-zA-Z_][a-zA-Z0-9_]* .
|
||||
.Pp
|
||||
In arguments to macros, leading unquoted space, tab, and newline
|
||||
.Pq Sq \en
|
||||
characters are ignored.
|
||||
To quote strings, use left and right single quotes
|
||||
.Pq e.g., Sq \ \&this is a string with a leading space .
|
||||
You can change the quote characters with the
|
||||
.Ic changequote
|
||||
built-in macro.
|
||||
.Pp
|
||||
Most built-ins don't make any sense without arguments, and hence are not
|
||||
recognized as special when not followed by an open parenthesis.
|
||||
.Pp
|
||||
The options are as follows:
|
||||
.Bl -tag -width Ds
|
||||
.It Fl D Ns Ar name Ns Op = Ns Ar value
|
||||
Define the symbol
|
||||
.Ar name
|
||||
to have some value (or
|
||||
.Dv NULL ) .
|
||||
.It Fl d Ar "flags"
|
||||
Set trace flags.
|
||||
.Ar flags
|
||||
may hold the following:
|
||||
.Bl -tag -width Ds
|
||||
.It Ar a
|
||||
print macro arguments.
|
||||
.It Ar c
|
||||
print macro expansion over several lines.
|
||||
.It Ar e
|
||||
print result of macro expansion.
|
||||
.It Ar f
|
||||
print filename location.
|
||||
.It Ar l
|
||||
print line number.
|
||||
.It Ar q
|
||||
quote arguments and expansion with the current quotes.
|
||||
.It Ar t
|
||||
start with all macros traced.
|
||||
.It Ar x
|
||||
number macro expansions.
|
||||
.It Ar V
|
||||
turn on all options.
|
||||
.El
|
||||
.Pp
|
||||
By default, trace is set to
|
||||
.Qq eq .
|
||||
.It Fl E
|
||||
Set warnings to be fatal.
|
||||
When a single
|
||||
.Fl E
|
||||
flag is specified, if warnings are issued, execution continues but
|
||||
.Nm
|
||||
will exit with a non-zero exit status.
|
||||
When multiple
|
||||
.Fl E
|
||||
flags are specified, execution will halt upon issuing the first warning and
|
||||
.Nm
|
||||
will exit with a non-zero exit status.
|
||||
This behaviour matches GNU-m4 1.4.9 and later.
|
||||
.It Fl g
|
||||
Activate GNU-m4 compatibility mode.
|
||||
In this mode, translit handles simple character
|
||||
ranges (e.g., a-z), regular expressions mimic emacs behavior,
|
||||
multiple m4wrap calls are handled as a stack,
|
||||
the number of diversions is unlimited,
|
||||
empty names for macro definitions are allowed,
|
||||
and eval understands
|
||||
.Sq 0rbase:value
|
||||
numbers.
|
||||
.It Fl I Ar "dirname"
|
||||
Add directory
|
||||
.Ar dirname
|
||||
to the include path.
|
||||
.It Fl o Ar filename
|
||||
Send trace output to
|
||||
.Ar filename .
|
||||
.It Fl P
|
||||
Prefix all built-in macros with
|
||||
.Sq m4_ .
|
||||
For example, instead of writing
|
||||
.Ic define ,
|
||||
use
|
||||
.Ic m4_define .
|
||||
.It Fl s
|
||||
Output line synchronization directives, suitable for
|
||||
.Xr cpp 1 .
|
||||
.It Fl t Ar macro
|
||||
Turn tracing on for
|
||||
.Ar macro .
|
||||
.It Fl "U" Ns Ar "name"
|
||||
Undefine the symbol
|
||||
.Ar name .
|
||||
.El
|
||||
.Sh SYNTAX
|
||||
.Nm
|
||||
provides the following built-in macros.
|
||||
They may be redefined, losing their original meaning.
|
||||
Return values are null unless otherwise stated.
|
||||
.Bl -tag -width changequote
|
||||
.It Fn builtin name
|
||||
Calls a built-in by its
|
||||
.Fa name ,
|
||||
overriding possible redefinitions.
|
||||
.It Fn changecom startcomment endcomment
|
||||
Changes the start comment and end comment sequences.
|
||||
Comment sequences may be up to five characters long.
|
||||
The default values are the hash sign
|
||||
and the newline character.
|
||||
.Bd -literal -offset indent
|
||||
# This is a comment
|
||||
.Ed
|
||||
.Pp
|
||||
With no arguments, comments are turned off.
|
||||
With one single argument, the end comment sequence is set
|
||||
to the newline character.
|
||||
.It Fn changequote beginquote endquote
|
||||
Defines the open quote and close quote sequences.
|
||||
Quote sequences may be up to five characters long.
|
||||
The default values are the backquote character and the quote
|
||||
character.
|
||||
.Bd -literal -offset indent
|
||||
`Here is a quoted string'
|
||||
.Ed
|
||||
.Pp
|
||||
With no arguments, the default quotes are restored.
|
||||
With one single argument, the close quote sequence is set
|
||||
to the newline character.
|
||||
.It Fn decr arg
|
||||
Decrements the argument
|
||||
.Fa arg
|
||||
by 1.
|
||||
The argument
|
||||
.Fa arg
|
||||
must be a valid numeric string.
|
||||
.It Fn define name value
|
||||
Define a new macro named by the first argument
|
||||
.Fa name
|
||||
to have the
|
||||
value of the second argument
|
||||
.Fa value .
|
||||
Each occurrence of
|
||||
.Sq $n
|
||||
(where
|
||||
.Ar n
|
||||
is 0 through 9) is replaced by the
|
||||
.Ar n Ns 'th
|
||||
argument.
|
||||
.Sq $0
|
||||
is the name of the calling macro.
|
||||
Undefined arguments are replaced by a null string.
|
||||
.Sq $#
|
||||
is replaced by the number of arguments;
|
||||
.Sq $*
|
||||
is replaced by all arguments comma separated;
|
||||
.Sq $@
|
||||
is the same as
|
||||
.Sq $*
|
||||
but all arguments are quoted against further expansion.
|
||||
.It Fn defn name ...
|
||||
Returns the quoted definition for each argument.
|
||||
This can be used to rename
|
||||
macro definitions (even for built-in macros).
|
||||
.It Fn divert num
|
||||
There are 10 output queues (numbered 0-9).
|
||||
At the end of processing
|
||||
.Nm
|
||||
concatenates all the queues in numerical order to produce the
|
||||
final output.
|
||||
Initially the output queue is 0.
|
||||
The divert
|
||||
macro allows you to select a new output queue (an invalid argument
|
||||
passed to divert causes output to be discarded).
|
||||
.It Ic divnum
|
||||
Returns the current output queue number.
|
||||
.It Ic dnl
|
||||
Discard input characters up to and including the next newline.
|
||||
.It Fn dumpdef name ...
|
||||
Prints the names and definitions for the named items, or for everything
|
||||
if no arguments are passed.
|
||||
.It Fn errprint msg
|
||||
Prints the first argument on the standard error output stream.
|
||||
.It Fn esyscmd cmd
|
||||
Passes its first argument to a shell and returns the shell's standard output.
|
||||
Note that the shell shares its standard input and standard error with
|
||||
.Nm .
|
||||
.It Fn eval expr[,radix[,minimum]]
|
||||
Computes the first argument as an arithmetic expression using 32-bit
|
||||
arithmetic.
|
||||
Operators are the standard C ternary, arithmetic, logical,
|
||||
shift, relational, bitwise, and parentheses operators.
|
||||
You can specify
|
||||
octal, decimal, and hexadecimal numbers as in C.
|
||||
The optional second argument
|
||||
.Fa radix
|
||||
specifies the radix for the result and the optional third argument
|
||||
.Fa minimum
|
||||
specifies the minimum number of digits in the result.
|
||||
.It Fn expr expr
|
||||
This is an alias for
|
||||
.Ic eval .
|
||||
.It Fn format formatstring arg1 ...
|
||||
Returns
|
||||
.Fa formatstring
|
||||
with escape sequences substituted with
|
||||
.Fa arg1
|
||||
and following arguments, in a way similar to
|
||||
.Xr printf 3 .
|
||||
This built-in is only available in GNU-m4 compatibility mode, and the only
|
||||
parameters implemented are there for autoconf compatibility:
|
||||
left-padding flag, an optional field width, a maximum field width,
|
||||
*-specified field widths, and the %s and %c data type.
|
||||
.It Fn ifdef name yes no
|
||||
If the macro named by the first argument is defined then return the second
|
||||
argument, otherwise the third.
|
||||
If there is no third argument, the value is
|
||||
.Dv NULL .
|
||||
The word
|
||||
.Qq unix
|
||||
is predefined.
|
||||
.It Fn ifelse a b yes ...
|
||||
If the first argument
|
||||
.Fa a
|
||||
matches the second argument
|
||||
.Fa b
|
||||
then
|
||||
.Fn ifelse
|
||||
returns
|
||||
the third argument
|
||||
.Fa yes .
|
||||
If the match fails the three arguments are
|
||||
discarded and the next three arguments are used until there is
|
||||
zero or one arguments left, either this last argument or
|
||||
.Dv NULL
|
||||
is returned if no other matches were found.
|
||||
.It Fn include name
|
||||
Returns the contents of the file specified in the first argument.
|
||||
If the file is not found as is, look through the include path:
|
||||
first the directories specified with
|
||||
.Fl I
|
||||
on the command line, then the environment variable
|
||||
.Ev M4PATH ,
|
||||
as a colon-separated list of directories.
|
||||
Include aborts with an error message if the file cannot be included.
|
||||
.It Fn incr arg
|
||||
Increments the argument by 1.
|
||||
The argument must be a valid numeric string.
|
||||
.It Fn index string substring
|
||||
Returns the index of the second argument in the first argument (e.g.,
|
||||
.Ic index(the quick brown fox jumped, fox)
|
||||
returns 16).
|
||||
If the second
|
||||
argument is not found index returns \-1.
|
||||
.It Fn indir macro arg1 ...
|
||||
Indirectly calls the macro whose name is passed as the first argument,
|
||||
with the remaining arguments passed as first, ... arguments.
|
||||
.It Fn len arg
|
||||
Returns the number of characters in the first argument.
|
||||
Extra arguments
|
||||
are ignored.
|
||||
.It Fn m4exit code
|
||||
Immediately exits with the return value specified by the first argument,
|
||||
0 if none.
|
||||
.It Fn m4wrap todo
|
||||
Allows you to define what happens at the final
|
||||
.Dv EOF ,
|
||||
usually for cleanup purposes (e.g.,
|
||||
.Ic m4wrap("cleanup(tempfile)")
|
||||
causes the macro cleanup to be
|
||||
invoked after all other processing is done).
|
||||
.Pp
|
||||
Multiple calls to
|
||||
.Fn m4wrap
|
||||
get inserted in sequence at the final
|
||||
.Dv EOF .
|
||||
.It Fn maketemp template
|
||||
Like
|
||||
.Ic mkstemp .
|
||||
.It Fn mkstemp template
|
||||
Invokes
|
||||
.Xr mkstemp 3
|
||||
on the first argument, and returns the modified string.
|
||||
This can be used to create unique
|
||||
temporary file names.
|
||||
.It Fn paste file
|
||||
Includes the contents of the file specified by the first argument without
|
||||
any macro processing.
|
||||
Aborts with an error message if the file cannot be
|
||||
included.
|
||||
.It Fn patsubst string regexp replacement
|
||||
Substitutes a regular expression in a string with a replacement string.
|
||||
Usual substitution patterns apply: an ampersand
|
||||
.Pq Sq \&&
|
||||
is replaced by the string matching the regular expression.
|
||||
The string
|
||||
.Sq \e# ,
|
||||
where
|
||||
.Sq #
|
||||
is a digit, is replaced by the corresponding back-reference.
|
||||
.It Fn popdef arg ...
|
||||
Restores the
|
||||
.Ic pushdef Ns ed
|
||||
definition for each argument.
|
||||
.It Fn pushdef macro def
|
||||
Takes the same arguments as
|
||||
.Ic define ,
|
||||
but it saves the definition on a
|
||||
stack for later retrieval by
|
||||
.Fn popdef .
|
||||
.It Fn regexp string regexp replacement
|
||||
Finds a regular expression in a string.
|
||||
If no further arguments are given,
|
||||
it returns the first match position or \-1 if no match.
|
||||
If a third argument
|
||||
is provided, it returns the replacement string, with sub-patterns replaced.
|
||||
.It Fn shift arg1 ...
|
||||
Returns all but the first argument, the remaining arguments are
|
||||
quoted and pushed back with commas in between.
|
||||
The quoting
|
||||
nullifies the effect of the extra scan that will subsequently be
|
||||
performed.
|
||||
.It Fn sinclude file
|
||||
Similar to
|
||||
.Ic include ,
|
||||
except it ignores any errors.
|
||||
.It Fn spaste file
|
||||
Similar to
|
||||
.Fn paste ,
|
||||
except it ignores any errors.
|
||||
.It Fn substr string offset length
|
||||
Returns a substring of the first argument starting at the offset specified
|
||||
by the second argument and the length specified by the third argument.
|
||||
If no third argument is present it returns the rest of the string.
|
||||
.It Fn syscmd cmd
|
||||
Passes the first argument to the shell.
|
||||
Nothing is returned.
|
||||
.It Ic sysval
|
||||
Returns the return value from the last
|
||||
.Ic syscmd .
|
||||
.It Fn traceon arg ...
|
||||
Enables tracing of macro expansions for the given arguments, or for all
|
||||
macros if no argument is given.
|
||||
.It Fn traceoff arg ...
|
||||
Disables tracing of macro expansions for the given arguments, or for all
|
||||
macros if no argument is given.
|
||||
.It Fn translit string mapfrom mapto
|
||||
Transliterate the characters in the first argument from the set
|
||||
given by the second argument to the set given by the third.
|
||||
You cannot use
|
||||
.Xr tr 1
|
||||
style abbreviations.
|
||||
.It Fn undefine name1 ...
|
||||
Removes the definition for the macros specified by its arguments.
|
||||
.It Fn undivert arg ...
|
||||
Flushes the named output queues (or all queues if no arguments).
|
||||
.It Ic unix
|
||||
A pre-defined macro for testing the OS platform.
|
||||
.It Ic __line__
|
||||
Returns the current file's line number.
|
||||
.It Ic __file__
|
||||
Returns the current file's name.
|
||||
.El
|
||||
.Sh EXIT STATUS
|
||||
.Ex -std m4
|
||||
.Pp
|
||||
But note that the
|
||||
.Ic m4exit
|
||||
macro can modify the exit status, as can the
|
||||
.Fl E
|
||||
flag.
|
||||
.Sh STANDARDS
|
||||
The
|
||||
.Nm
|
||||
utility is compliant with the
|
||||
.St -p1003.1-2008
|
||||
specification.
|
||||
.Pp
|
||||
The flags
|
||||
.Op Fl dEgIPot
|
||||
and the macros
|
||||
.Ic builtin ,
|
||||
.Ic esyscmd ,
|
||||
.Ic expr ,
|
||||
.Ic format ,
|
||||
.Ic indir ,
|
||||
.Ic paste ,
|
||||
.Ic patsubst ,
|
||||
.Ic regexp ,
|
||||
.Ic spaste ,
|
||||
.Ic unix ,
|
||||
.Ic __line__ ,
|
||||
and
|
||||
.Ic __file__
|
||||
are extensions to that specification.
|
||||
.Pp
|
||||
.Ic maketemp
|
||||
is not supposed to be a synonym for
|
||||
.Ic mkstemp ,
|
||||
but instead to be an insecure temporary file name creation function.
|
||||
It is marked by
|
||||
.St -p1003.1-2008
|
||||
as being obsolescent and should not be used if portability is a concern.
|
||||
.Pp
|
||||
The output format of
|
||||
.Ic traceon
|
||||
and
|
||||
.Ic dumpdef
|
||||
are not specified in any standard,
|
||||
are likely to change and should not be relied upon.
|
||||
The current format of tracing is closely modelled on
|
||||
.Nm gnu-m4 ,
|
||||
to allow
|
||||
.Nm autoconf
|
||||
to work.
|
||||
.Pp
|
||||
The built-ins
|
||||
.Ic pushdef
|
||||
and
|
||||
.Ic popdef
|
||||
handle macro definitions as a stack.
|
||||
However,
|
||||
.Ic define
|
||||
interacts with the stack in an undefined way.
|
||||
In this implementation,
|
||||
.Ic define
|
||||
replaces the top-most definition only.
|
||||
Other implementations may erase all definitions on the stack instead.
|
||||
.Pp
|
||||
All built-ins do expand without arguments in many other
|
||||
.Nm .
|
||||
.Pp
|
||||
Many other
|
||||
.Nm
|
||||
have dire size limitations with respect to buffer sizes.
|
||||
.Sh AUTHORS
|
||||
.An -nosplit
|
||||
.An Ozan Yigit Aq Mt oz@sis.yorku.ca
|
||||
and
|
||||
.An Richard A. O'Keefe Aq Mt ok@goanna.cs.rmit.OZ.AU .
|
||||
.Pp
|
||||
GNU-m4 compatibility extensions by
|
||||
.An Marc Espie Aq Mt espie@cvs.openbsd.org .
|
||||
71
third_party/m4/m4.mk
vendored
Normal file
71
third_party/m4/m4.mk
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
|
||||
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
|
||||
# Description:
|
||||
# m4 is an old skool macro processing language.
|
||||
|
||||
PKGS += THIRD_PARTY_M4
|
||||
|
||||
THIRD_PARTY_M4 = \
|
||||
o/$(MODE)/third_party/m4/m4.com
|
||||
|
||||
THIRD_PARTY_M4_OBJS = \
|
||||
o/$(MODE)/third_party/m4/eval.o \
|
||||
o/$(MODE)/third_party/m4/expr.o \
|
||||
o/$(MODE)/third_party/m4/look.o \
|
||||
o/$(MODE)/third_party/m4/main.o \
|
||||
o/$(MODE)/third_party/m4/misc.o \
|
||||
o/$(MODE)/third_party/m4/ohash.o \
|
||||
o/$(MODE)/third_party/m4/gnum4.o \
|
||||
o/$(MODE)/third_party/m4/trace.o \
|
||||
o/$(MODE)/third_party/m4/tokenizer.o \
|
||||
o/$(MODE)/third_party/m4/parser.o
|
||||
|
||||
THIRD_PARTY_M4_DEPS := $(call uniq, \
|
||||
$(LIBC_LOG) \
|
||||
$(LIBC_MATH) \
|
||||
$(LIBC_COMPAT) \
|
||||
$(LIBC_UNICODE) \
|
||||
$(THIRD_PARTY_REGEX) \
|
||||
$(THIRD_PARTY_GETOPT))
|
||||
|
||||
$(THIRD_PARTY_M4_OBJS): \
|
||||
DEFAULT_CPPFLAGS += \
|
||||
$(LIBC_COMPAT_CPPFLAGS) \
|
||||
-isystem third_party/m4
|
||||
|
||||
$(THIRD_PARTY_M4_OBJS): \
|
||||
DEFAULT_CFLAGS += \
|
||||
-Wno-unused \
|
||||
-Wno-char-subscripts \
|
||||
-Wno-sign-compare
|
||||
|
||||
o/$(MODE)/third_party/m4/m4.com.dbg: \
|
||||
$(THIRD_PARTY_M4_DEPS) \
|
||||
$(THIRD_PARTY_M4_OBJS) \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
@$(APELINK)
|
||||
|
||||
THIRD_PARTY_M4_CHECKS = o/$(MODE)/third_party/m4/m4.com.ok
|
||||
o/$(MODE)/third_party/m4/test.m4.out: \
|
||||
third_party/m4/TEST/test.m4 \
|
||||
third_party/m4/TEST/ack.m4 \
|
||||
third_party/m4/TEST/hanoi.m4 \
|
||||
third_party/m4/TEST/hash.m4 \
|
||||
third_party/m4/TEST/sqroot.m4 \
|
||||
third_party/m4/TEST/string.m4 \
|
||||
$(THIRD_PARTY_M4)
|
||||
@ACTION=M4 TARGET=$@ build/do \
|
||||
$(THIRD_PARTY_M4) third_party/m4/TEST/test.m4 >$@
|
||||
o/$(MODE)/third_party/m4/m4.com.ok: \
|
||||
o/$(MODE)/third_party/m4/test.m4.out \
|
||||
third_party/m4/TEST/test.m4.golden
|
||||
@ACTION=CMP TARGET=$@ build/do cmp -s $^
|
||||
@ACTION=TOUCH TARGET=$@ build/do touch $@
|
||||
|
||||
$(THIRD_PARTY_M4_OBJS): \
|
||||
$(BUILD_FILES) \
|
||||
third_party/m4/m4.mk
|
||||
|
||||
.PHONY: o/$(MODE)/third_party/m4
|
||||
o/$(MODE)/third_party/m4: $(THIRD_PARTY_M4_CHECKS)
|
||||
967
third_party/m4/m4.ms
vendored
Normal file
967
third_party/m4/m4.ms
vendored
Normal file
@@ -0,0 +1,967 @@
|
||||
.\" $OpenBSD: m4.ms,v 1.2 2003/06/26 16:18:48 mickey Exp $
|
||||
.\"
|
||||
.\" Copyright (C) Caldera International Inc. 2001-2002.
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code and documentation must retain the above
|
||||
.\" copyright notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\" 3. All advertising materials mentioning features or use of this software
|
||||
.\" must display the following acknowledgement:
|
||||
.\" This product includes software developed or owned by Caldera
|
||||
.\" International, Inc.
|
||||
.\" 4. Neither the name of Caldera International, Inc. nor the names of other
|
||||
.\" contributors may be used to endorse or promote products derived from
|
||||
.\" this software without specific prior written permission.
|
||||
.\"
|
||||
.\" USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
|
||||
.\" INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
|
||||
.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
.\" IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE FOR ANY DIRECT,
|
||||
.\" INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
.\" (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
.\" SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
.\" STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
.\" IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
.\" POSSIBILITY OF SUCH DAMAGE.
|
||||
.\"
|
||||
.\" @(#)m4.ms 6.3 (Berkeley) 6/5/93
|
||||
.\"
|
||||
.EH 'PSD:17-%''The M4 Macro Processor'
|
||||
.OH 'The M4 Macro Processor''PSD:17-%'
|
||||
.if n .ls 2
|
||||
.tr _\(em
|
||||
.tr *\(**
|
||||
.de UC
|
||||
\&\\$3\s-1\\$1\\s0\&\\$2
|
||||
..
|
||||
.de IT
|
||||
.if n .ul
|
||||
\&\\$3\f2\\$1\fP\&\\$2
|
||||
..
|
||||
.de UL
|
||||
.if n .ul
|
||||
\&\\$3\f3\\$1\fP\&\\$2
|
||||
..
|
||||
.de P1
|
||||
.DS I 3n
|
||||
.if n .ls 2
|
||||
.nf
|
||||
.if n .ta 5 10 15 20 25 30 35 40 45 50 55 60
|
||||
.if t .ta .4i .8i 1.2i 1.6i 2i 2.4i 2.8i 3.2i 3.6i 4i 4.4i 4.8i 5.2i 5.6i
|
||||
.if t .tr -\(mi|\(bv'\(fm^\(no*\(**
|
||||
.tr `\(ga'\(aa
|
||||
.if t .tr _\(ul
|
||||
.ft 3
|
||||
.lg 0
|
||||
..
|
||||
.de P2
|
||||
.ps \\n(PS
|
||||
.vs \\n(VSp
|
||||
.ft R
|
||||
.if n .ls 2
|
||||
.tr --||''^^!!
|
||||
.if t .tr _\(em
|
||||
.fi
|
||||
.lg
|
||||
.DE
|
||||
.if t .tr _\(em
|
||||
..
|
||||
.hw semi-colon
|
||||
.hw estab-lished
|
||||
.hy 14
|
||||
. \"2=not last lines; 4= no -xx; 8=no xx-
|
||||
. \"special chars in programs
|
||||
. \" start of text
|
||||
.\".RP
|
||||
.....TR 59
|
||||
.....TM 77-1273-6 39199 39199-11
|
||||
.ND "July 1, 1977"
|
||||
.TL
|
||||
The M4 Macro Processor
|
||||
.AU "MH 2C-518" 6021
|
||||
Brian W. Kernighan
|
||||
.AU "MH 2C-517" 3770
|
||||
Dennis M. Ritchie
|
||||
.AI
|
||||
.MH
|
||||
.AB
|
||||
.PP
|
||||
M4 is a macro processor available on
|
||||
.UX
|
||||
and
|
||||
.UC GCOS .
|
||||
Its primary use has been as a
|
||||
front end for Ratfor for those
|
||||
cases where parameterless macros
|
||||
are not adequately powerful.
|
||||
It has also been used for languages as disparate as C and Cobol.
|
||||
M4 is particularly suited for functional languages like Fortran, PL/I and C
|
||||
since macros are specified in a functional notation.
|
||||
.PP
|
||||
M4 provides features seldom found even in much larger
|
||||
macro processors,
|
||||
including
|
||||
.IP " \(bu"
|
||||
arguments
|
||||
.IP " \(bu"
|
||||
condition testing
|
||||
.IP " \(bu"
|
||||
arithmetic capabilities
|
||||
.IP " \(bu"
|
||||
string and substring functions
|
||||
.IP " \(bu"
|
||||
file manipulation
|
||||
.LP
|
||||
.PP
|
||||
This paper is a user's manual for M4.
|
||||
.AE
|
||||
.CS 6 0 6 0 0 1
|
||||
.if t .2C
|
||||
.SH
|
||||
Introduction
|
||||
.PP
|
||||
A macro processor is a useful way to enhance a programming language,
|
||||
to make it more palatable
|
||||
or more readable,
|
||||
or to tailor it to a particular application.
|
||||
The
|
||||
.UL #define
|
||||
statement in C
|
||||
and the analogous
|
||||
.UL define
|
||||
in Ratfor
|
||||
are examples of the basic facility provided by
|
||||
any macro processor _
|
||||
replacement of text by other text.
|
||||
.PP
|
||||
The M4 macro processor is an extension of a macro processor called M3
|
||||
which was written by D. M. Ritchie
|
||||
for the AP-3 minicomputer;
|
||||
M3 was in turn based on a macro processor implemented for [1].
|
||||
Readers unfamiliar with the basic ideas of macro processing
|
||||
may wish to read some of the discussion there.
|
||||
.PP
|
||||
M4 is a suitable front end for Ratfor and C,
|
||||
and has also been used successfully with Cobol.
|
||||
Besides the straightforward replacement of one string of text by another,
|
||||
it provides
|
||||
macros with arguments,
|
||||
conditional macro expansion,
|
||||
arithmetic,
|
||||
file manipulation,
|
||||
and some specialized string processing functions.
|
||||
.PP
|
||||
The basic operation of M4
|
||||
is to copy its input to its output.
|
||||
As the input is read, however, each alphanumeric ``token''
|
||||
(that is, string of letters and digits) is checked.
|
||||
If it is the name of a macro,
|
||||
then the name of the macro is replaced by its defining text,
|
||||
and the resulting string is pushed back onto the
|
||||
input to be rescanned.
|
||||
Macros may be called with arguments, in which case the arguments are collected
|
||||
and substituted into the right places in the defining text
|
||||
before it is rescanned.
|
||||
.PP
|
||||
M4 provides a collection of about twenty built-in
|
||||
macros
|
||||
which perform various useful operations;
|
||||
in addition, the user can define new macros.
|
||||
Built-ins and user-defined macros work exactly the same way, except that
|
||||
some of the built-in macros have side effects
|
||||
on the state of the process.
|
||||
.SH
|
||||
Usage
|
||||
.PP
|
||||
On
|
||||
.UC UNIX ,
|
||||
use
|
||||
.P1
|
||||
m4 [files]
|
||||
.P2
|
||||
Each argument file is processed in order;
|
||||
if there are no arguments, or if an argument
|
||||
is `\-',
|
||||
the standard input is read at that point.
|
||||
The processed text is written on the standard output,
|
||||
which may be captured for subsequent processing with
|
||||
.P1
|
||||
m4 [files] >outputfile
|
||||
.P2
|
||||
On
|
||||
.UC GCOS ,
|
||||
usage is identical, but the program is called
|
||||
.UL \&./m4 .
|
||||
.SH
|
||||
Defining Macros
|
||||
.PP
|
||||
The primary built-in function of M4
|
||||
is
|
||||
.UL define ,
|
||||
which is used to define new macros.
|
||||
The input
|
||||
.P1
|
||||
define(name, stuff)
|
||||
.P2
|
||||
causes the string
|
||||
.UL name
|
||||
to be defined as
|
||||
.UL stuff .
|
||||
All subsequent occurrences of
|
||||
.UL name
|
||||
will be replaced by
|
||||
.UL stuff .
|
||||
.UL name
|
||||
must be alphanumeric and must begin with a letter
|
||||
(the underscore \(ul counts as a letter).
|
||||
.UL stuff
|
||||
is any text that contains balanced parentheses;
|
||||
it may stretch over multiple lines.
|
||||
.PP
|
||||
Thus, as a typical example,
|
||||
.P1
|
||||
define(N, 100)
|
||||
...
|
||||
if (i > N)
|
||||
.P2
|
||||
defines
|
||||
.UL N
|
||||
to be 100, and uses this ``symbolic constant'' in a later
|
||||
.UL if
|
||||
statement.
|
||||
.PP
|
||||
The left parenthesis must immediately follow the word
|
||||
.UL define ,
|
||||
to signal that
|
||||
.UL define
|
||||
has arguments.
|
||||
If a macro or built-in name is not followed immediately by `(',
|
||||
it is assumed to have no arguments.
|
||||
This is the situation for
|
||||
.UL N
|
||||
above;
|
||||
it is actually a macro with no arguments,
|
||||
and thus when it is used there need be no (...) following it.
|
||||
.PP
|
||||
You should also notice that a macro name is only recognized as such
|
||||
if it appears surrounded by non-alphanumerics.
|
||||
For example, in
|
||||
.P1
|
||||
define(N, 100)
|
||||
...
|
||||
if (NNN > 100)
|
||||
.P2
|
||||
the variable
|
||||
.UL NNN
|
||||
is absolutely unrelated to the defined macro
|
||||
.UL N ,
|
||||
even though it contains a lot of
|
||||
.UL N 's.
|
||||
.PP
|
||||
Things may be defined in terms of other things.
|
||||
For example,
|
||||
.P1
|
||||
define(N, 100)
|
||||
define(M, N)
|
||||
.P2
|
||||
defines both M and N to be 100.
|
||||
.PP
|
||||
What happens if
|
||||
.UL N
|
||||
is redefined?
|
||||
Or, to say it another way, is
|
||||
.UL M
|
||||
defined as
|
||||
.UL N
|
||||
or as 100?
|
||||
In M4,
|
||||
the latter is true _
|
||||
.UL M
|
||||
is 100, so even if
|
||||
.UL N
|
||||
subsequently changes,
|
||||
.UL M
|
||||
does not.
|
||||
.PP
|
||||
This behavior arises because
|
||||
M4 expands macro names into their defining text as soon as it possibly can.
|
||||
Here, that means that when the string
|
||||
.UL N
|
||||
is seen as the arguments of
|
||||
.UL define
|
||||
are being collected, it is immediately replaced by 100;
|
||||
it's just as if you had said
|
||||
.P1
|
||||
define(M, 100)
|
||||
.P2
|
||||
in the first place.
|
||||
.PP
|
||||
If this isn't what you really want, there are two ways out of it.
|
||||
The first, which is specific to this situation,
|
||||
is to interchange the order of the definitions:
|
||||
.P1
|
||||
define(M, N)
|
||||
define(N, 100)
|
||||
.P2
|
||||
Now
|
||||
.UL M
|
||||
is defined to be the string
|
||||
.UL N ,
|
||||
so when you ask for
|
||||
.UL M
|
||||
later, you'll always get the value of
|
||||
.UL N
|
||||
at that time
|
||||
(because the
|
||||
.UL M
|
||||
will be replaced by
|
||||
.UL N
|
||||
which will be replaced by 100).
|
||||
.SH
|
||||
Quoting
|
||||
.PP
|
||||
The more general solution is to delay the expansion of
|
||||
the arguments of
|
||||
.UL define
|
||||
by
|
||||
.ul
|
||||
quoting
|
||||
them.
|
||||
Any text surrounded by the single quotes \(ga and \(aa
|
||||
is not expanded immediately, but has the quotes stripped off.
|
||||
If you say
|
||||
.P1
|
||||
define(N, 100)
|
||||
define(M, `N')
|
||||
.P2
|
||||
the quotes around the
|
||||
.UL N
|
||||
are stripped off as the argument is being collected,
|
||||
but they have served their purpose, and
|
||||
.UL M
|
||||
is defined as
|
||||
the string
|
||||
.UL N ,
|
||||
not 100.
|
||||
The general rule is that M4 always strips off
|
||||
one level of single quotes whenever it evaluates
|
||||
something.
|
||||
This is true even outside of
|
||||
macros.
|
||||
If you want the word
|
||||
.UL define
|
||||
to appear in the output,
|
||||
you have to quote it in the input,
|
||||
as in
|
||||
.P1
|
||||
`define' = 1;
|
||||
.P2
|
||||
.PP
|
||||
As another instance of the same thing, which is a bit more surprising,
|
||||
consider redefining
|
||||
.UL N :
|
||||
.P1
|
||||
define(N, 100)
|
||||
...
|
||||
define(N, 200)
|
||||
.P2
|
||||
Perhaps regrettably, the
|
||||
.UL N
|
||||
in the second definition is
|
||||
evaluated as soon as it's seen;
|
||||
that is, it is
|
||||
replaced by
|
||||
100, so it's as if you had written
|
||||
.P1
|
||||
define(100, 200)
|
||||
.P2
|
||||
This statement is ignored by M4, since you can only define things that look
|
||||
like names, but it obviously doesn't have the effect you wanted.
|
||||
To really redefine
|
||||
.UL N ,
|
||||
you must delay the evaluation by quoting:
|
||||
.P1
|
||||
define(N, 100)
|
||||
...
|
||||
define(`N', 200)
|
||||
.P2
|
||||
In M4,
|
||||
it is often wise to quote the first argument of a macro.
|
||||
.PP
|
||||
If \` and \' are not convenient for some reason,
|
||||
the quote characters can be changed with the built-in
|
||||
.UL changequote :
|
||||
.P1
|
||||
changequote([, ])
|
||||
.P2
|
||||
makes the new quote characters the left and right brackets.
|
||||
You can restore the original characters with just
|
||||
.P1
|
||||
changequote
|
||||
.P2
|
||||
.PP
|
||||
There are two additional built-ins related to
|
||||
.UL define .
|
||||
.UL undefine
|
||||
removes the definition of some macro or built-in:
|
||||
.P1
|
||||
undefine(`N')
|
||||
.P2
|
||||
removes the definition of
|
||||
.UL N .
|
||||
(Why are the quotes absolutely necessary?)
|
||||
Built-ins can be removed with
|
||||
.UL undefine ,
|
||||
as in
|
||||
.P1
|
||||
undefine(`define')
|
||||
.P2
|
||||
but once you remove one, you can never get it back.
|
||||
.PP
|
||||
The built-in
|
||||
.UL ifdef
|
||||
provides a way to determine if a macro is currently defined.
|
||||
In particular, M4 has pre-defined the names
|
||||
.UL unix
|
||||
and
|
||||
.UL gcos
|
||||
on the corresponding systems, so you can
|
||||
tell which one you're using:
|
||||
.P1
|
||||
ifdef(`unix', `define(wordsize,16)' )
|
||||
ifdef(`gcos', `define(wordsize,36)' )
|
||||
.P2
|
||||
makes a definition appropriate for the particular machine.
|
||||
Don't forget the quotes!
|
||||
.PP
|
||||
.UL ifdef
|
||||
actually permits three arguments;
|
||||
if the name is undefined, the value of
|
||||
.UL ifdef
|
||||
is then the third argument, as in
|
||||
.P1
|
||||
ifdef(`unix', on UNIX, not on UNIX)
|
||||
.P2
|
||||
.SH
|
||||
Arguments
|
||||
.PP
|
||||
So far we have discussed the simplest form of macro processing _
|
||||
replacing one string by another (fixed) string.
|
||||
User-defined macros may also have arguments, so different invocations
|
||||
can have different results.
|
||||
Within the replacement text for a macro
|
||||
(the second argument of its
|
||||
.UL define )
|
||||
any occurrence of
|
||||
.UL $n
|
||||
will be replaced by the
|
||||
.UL n th
|
||||
argument when the macro
|
||||
is actually used.
|
||||
Thus, the macro
|
||||
.UL bump ,
|
||||
defined as
|
||||
.P1
|
||||
define(bump, $1 = $1 + 1)
|
||||
.P2
|
||||
generates code to increment its argument by 1:
|
||||
.P1
|
||||
bump(x)
|
||||
.P2
|
||||
is
|
||||
.P1
|
||||
x = x + 1
|
||||
.P2
|
||||
.PP
|
||||
A macro can have as many arguments as you want,
|
||||
but only the first nine are accessible,
|
||||
through
|
||||
.UL $1
|
||||
to
|
||||
.UL $9 .
|
||||
(The macro name itself is
|
||||
.UL $0 ,
|
||||
although that is less commonly used.)
|
||||
Arguments that are not supplied are replaced by null strings,
|
||||
so
|
||||
we can define a macro
|
||||
.UL cat
|
||||
which simply concatenates its arguments, like this:
|
||||
.P1
|
||||
define(cat, $1$2$3$4$5$6$7$8$9)
|
||||
.P2
|
||||
Thus
|
||||
.P1
|
||||
cat(x, y, z)
|
||||
.P2
|
||||
is equivalent to
|
||||
.P1
|
||||
xyz
|
||||
.P2
|
||||
.UL $4
|
||||
through
|
||||
.UL $9
|
||||
are null, since no corresponding arguments were provided.
|
||||
.PP
|
||||
.PP
|
||||
Leading unquoted blanks, tabs, or newlines that occur during argument collection
|
||||
are discarded.
|
||||
All other white space is retained.
|
||||
Thus
|
||||
.P1
|
||||
define(a, b c)
|
||||
.P2
|
||||
defines
|
||||
.UL a
|
||||
to be
|
||||
.UL b\ \ \ c .
|
||||
.PP
|
||||
Arguments are separated by commas, but parentheses are counted properly,
|
||||
so a comma ``protected'' by parentheses does not terminate an argument.
|
||||
That is, in
|
||||
.P1
|
||||
define(a, (b,c))
|
||||
.P2
|
||||
there are only two arguments;
|
||||
the second is literally
|
||||
.UL (b,c) .
|
||||
And of course a bare comma or parenthesis can be inserted by quoting it.
|
||||
.SH
|
||||
Arithmetic Built-ins
|
||||
.PP
|
||||
M4 provides two built-in functions for doing arithmetic
|
||||
on integers (only).
|
||||
The simplest is
|
||||
.UL incr ,
|
||||
which increments its numeric argument by 1.
|
||||
Thus to handle the common programming situation
|
||||
where you want a variable to be defined as ``one more than N'',
|
||||
write
|
||||
.P1
|
||||
define(N, 100)
|
||||
define(N1, `incr(N)')
|
||||
.P2
|
||||
Then
|
||||
.UL N1
|
||||
is defined as one more than the current value of
|
||||
.UL N .
|
||||
.PP
|
||||
The more general mechanism for arithmetic is a built-in
|
||||
called
|
||||
.UL eval ,
|
||||
which is capable of arbitrary arithmetic on integers.
|
||||
It provides the operators
|
||||
(in decreasing order of precedence)
|
||||
.DS
|
||||
unary + and \(mi
|
||||
** or ^ (exponentiation)
|
||||
* / % (modulus)
|
||||
+ \(mi
|
||||
== != < <= > >=
|
||||
! (not)
|
||||
& or && (logical and)
|
||||
\(or or \(or\(or (logical or)
|
||||
.DE
|
||||
Parentheses may be used to group operations where needed.
|
||||
All the operands of
|
||||
an expression given to
|
||||
.UL eval
|
||||
must ultimately be numeric.
|
||||
The numeric value of a true relation
|
||||
(like 1>0)
|
||||
is 1, and false is 0.
|
||||
The precision in
|
||||
.UL eval
|
||||
is
|
||||
32 bits on
|
||||
.UC UNIX
|
||||
and 36 bits on
|
||||
.UC GCOS .
|
||||
.PP
|
||||
As a simple example, suppose we want
|
||||
.UL M
|
||||
to be
|
||||
.UL 2**N+1 .
|
||||
Then
|
||||
.P1
|
||||
define(N, 3)
|
||||
define(M, `eval(2**N+1)')
|
||||
.P2
|
||||
As a matter of principle, it is advisable
|
||||
to quote the defining text for a macro
|
||||
unless it is very simple indeed
|
||||
(say just a number);
|
||||
it usually gives the result you want,
|
||||
and is a good habit to get into.
|
||||
.SH
|
||||
File Manipulation
|
||||
.PP
|
||||
You can include a new file in the input at any time by
|
||||
the built-in function
|
||||
.UL include :
|
||||
.P1
|
||||
include(filename)
|
||||
.P2
|
||||
inserts the contents of
|
||||
.UL filename
|
||||
in place of the
|
||||
.UL include
|
||||
command.
|
||||
The contents of the file is often a set of definitions.
|
||||
The value
|
||||
of
|
||||
.UL include
|
||||
(that is, its replacement text)
|
||||
is the contents of the file;
|
||||
this can be captured in definitions, etc.
|
||||
.PP
|
||||
It is a fatal error if the file named in
|
||||
.UL include
|
||||
cannot be accessed.
|
||||
To get some control over this situation, the alternate form
|
||||
.UL sinclude
|
||||
can be used;
|
||||
.UL sinclude
|
||||
(``silent include'')
|
||||
says nothing and continues if it can't access the file.
|
||||
.PP
|
||||
It is also possible to divert the output of M4 to temporary files during processing,
|
||||
and output the collected material upon command.
|
||||
M4 maintains nine of these diversions, numbered 1 through 9.
|
||||
If you say
|
||||
.P1
|
||||
divert(n)
|
||||
.P2
|
||||
all subsequent output is put onto the end of a temporary file
|
||||
referred to as
|
||||
.UL n .
|
||||
Diverting to this file is stopped by another
|
||||
.UL divert
|
||||
command;
|
||||
in particular,
|
||||
.UL divert
|
||||
or
|
||||
.UL divert(0)
|
||||
resumes the normal output process.
|
||||
.PP
|
||||
Diverted text is normally output all at once
|
||||
at the end of processing,
|
||||
with the diversions output in numeric order.
|
||||
It is possible, however, to bring back diversions
|
||||
at any time,
|
||||
that is, to append them to the current diversion.
|
||||
.P1
|
||||
undivert
|
||||
.P2
|
||||
brings back all diversions in numeric order, and
|
||||
.UL undivert
|
||||
with arguments brings back the selected diversions
|
||||
in the order given.
|
||||
The act of undiverting discards the diverted stuff,
|
||||
as does diverting into a diversion
|
||||
whose number is not between 0 and 9 inclusive.
|
||||
.PP
|
||||
The value of
|
||||
.UL undivert
|
||||
is
|
||||
.ul
|
||||
not
|
||||
the diverted stuff.
|
||||
Furthermore, the diverted material is
|
||||
.ul
|
||||
not
|
||||
rescanned for macros.
|
||||
.PP
|
||||
The built-in
|
||||
.UL divnum
|
||||
returns the number of the currently active diversion.
|
||||
This is zero during normal processing.
|
||||
.SH
|
||||
System Command
|
||||
.PP
|
||||
You can run any program in the local operating system
|
||||
with the
|
||||
.UL syscmd
|
||||
built-in.
|
||||
For example,
|
||||
.P1
|
||||
syscmd(date)
|
||||
.P2
|
||||
on
|
||||
.UC UNIX
|
||||
runs the
|
||||
.UL date
|
||||
command.
|
||||
Normally
|
||||
.UL syscmd
|
||||
would be used to create a file
|
||||
for a subsequent
|
||||
.UL include .
|
||||
.PP
|
||||
To facilitate making unique file names, the built-in
|
||||
.UL maketemp
|
||||
is provided, with specifications identical to the system function
|
||||
.ul
|
||||
mktemp:
|
||||
a string of XXXXX in the argument is replaced
|
||||
by the process id of the current process.
|
||||
.SH
|
||||
Conditionals
|
||||
.PP
|
||||
There is a built-in called
|
||||
.UL ifelse
|
||||
which enables you to perform arbitrary conditional testing.
|
||||
In the simplest form,
|
||||
.P1
|
||||
ifelse(a, b, c, d)
|
||||
.P2
|
||||
compares the two strings
|
||||
.UL a
|
||||
and
|
||||
.UL b .
|
||||
If these are identical,
|
||||
.UL ifelse
|
||||
returns
|
||||
the string
|
||||
.UL c ;
|
||||
otherwise it returns
|
||||
.UL d .
|
||||
Thus we might define a macro called
|
||||
.UL compare
|
||||
which compares two strings and returns ``yes'' or ``no''
|
||||
if they are the same or different.
|
||||
.P1
|
||||
define(compare, `ifelse($1, $2, yes, no)')
|
||||
.P2
|
||||
Note the quotes,
|
||||
which prevent too-early evaluation of
|
||||
.UL ifelse .
|
||||
.PP
|
||||
If the fourth argument is missing, it is treated as empty.
|
||||
.PP
|
||||
.UL ifelse
|
||||
can actually have any number of arguments,
|
||||
and thus provides a limited form of multi-way decision capability.
|
||||
In the input
|
||||
.P1
|
||||
ifelse(a, b, c, d, e, f, g)
|
||||
.P2
|
||||
if the string
|
||||
.UL a
|
||||
matches the string
|
||||
.UL b ,
|
||||
the result is
|
||||
.UL c .
|
||||
Otherwise, if
|
||||
.UL d
|
||||
is the same as
|
||||
.UL e ,
|
||||
the result is
|
||||
.UL f .
|
||||
Otherwise the result is
|
||||
.UL g .
|
||||
If the final argument
|
||||
is omitted, the result is null,
|
||||
so
|
||||
.P1
|
||||
ifelse(a, b, c)
|
||||
.P2
|
||||
is
|
||||
.UL c
|
||||
if
|
||||
.UL a
|
||||
matches
|
||||
.UL b ,
|
||||
and null otherwise.
|
||||
.SH
|
||||
String Manipulation
|
||||
.PP
|
||||
The built-in
|
||||
.UL len
|
||||
returns the length of the string that makes up its argument.
|
||||
Thus
|
||||
.P1
|
||||
len(abcdef)
|
||||
.P2
|
||||
is 6, and
|
||||
.UL len((a,b))
|
||||
is 5.
|
||||
.PP
|
||||
The built-in
|
||||
.UL substr
|
||||
can be used to produce substrings of strings.
|
||||
.UL substr(s,\ i,\ n)
|
||||
returns the substring of
|
||||
.UL s
|
||||
that starts at the
|
||||
.UL i th
|
||||
position
|
||||
(origin zero),
|
||||
and is
|
||||
.UL n
|
||||
characters long.
|
||||
If
|
||||
.UL n
|
||||
is omitted, the rest of the string is returned,
|
||||
so
|
||||
.P1
|
||||
substr(`now is the time', 1)
|
||||
.P2
|
||||
is
|
||||
.P1
|
||||
ow is the time
|
||||
.P2
|
||||
If
|
||||
.UL i
|
||||
or
|
||||
.UL n
|
||||
are out of range, various sensible things happen.
|
||||
.PP
|
||||
.UL index(s1,\ s2)
|
||||
returns the index (position) in
|
||||
.UL s1
|
||||
where the string
|
||||
.UL s2
|
||||
occurs, or \-1
|
||||
if it doesn't occur.
|
||||
As with
|
||||
.UL substr ,
|
||||
the origin for strings is 0.
|
||||
.PP
|
||||
The built-in
|
||||
.UL translit
|
||||
performs character transliteration.
|
||||
.P1
|
||||
translit(s, f, t)
|
||||
.P2
|
||||
modifies
|
||||
.UL s
|
||||
by replacing any character found in
|
||||
.UL f
|
||||
by the corresponding character of
|
||||
.UL t .
|
||||
That is,
|
||||
.P1
|
||||
translit(s, aeiou, 12345)
|
||||
.P2
|
||||
replaces the vowels by the corresponding digits.
|
||||
If
|
||||
.UL t
|
||||
is shorter than
|
||||
.UL f ,
|
||||
characters which don't have an entry in
|
||||
.UL t
|
||||
are deleted; as a limiting case,
|
||||
if
|
||||
.UL t
|
||||
is not present at all,
|
||||
characters from
|
||||
.UL f
|
||||
are deleted from
|
||||
.UL s .
|
||||
So
|
||||
.P1
|
||||
translit(s, aeiou)
|
||||
.P2
|
||||
deletes vowels from
|
||||
.UL s .
|
||||
.PP
|
||||
There is also a built-in called
|
||||
.UL dnl
|
||||
which deletes all characters that follow it up to
|
||||
and including the next newline;
|
||||
it is useful mainly for throwing away
|
||||
empty lines that otherwise tend to clutter up M4 output.
|
||||
For example, if you say
|
||||
.P1
|
||||
define(N, 100)
|
||||
define(M, 200)
|
||||
define(L, 300)
|
||||
.P2
|
||||
the newline at the end of each line is not part of the definition,
|
||||
so it is copied into the output, where it may not be wanted.
|
||||
If you add
|
||||
.UL dnl
|
||||
to each of these lines, the newlines will disappear.
|
||||
.PP
|
||||
Another way to achieve this, due to J. E. Weythman,
|
||||
is
|
||||
.P1
|
||||
divert(-1)
|
||||
define(...)
|
||||
...
|
||||
divert
|
||||
.P2
|
||||
.SH
|
||||
Printing
|
||||
.PP
|
||||
The built-in
|
||||
.UL errprint
|
||||
writes its arguments out on the standard error file.
|
||||
Thus you can say
|
||||
.P1
|
||||
errprint(`fatal error')
|
||||
.P2
|
||||
.PP
|
||||
.UL dumpdef
|
||||
is a debugging aid which
|
||||
dumps the current definitions of defined terms.
|
||||
If there are no arguments, you get everything;
|
||||
otherwise you get the ones you name as arguments.
|
||||
Don't forget to quote the names!
|
||||
.SH
|
||||
Summary of Built-ins
|
||||
.PP
|
||||
Each entry is preceded by the
|
||||
page number where it is described.
|
||||
.DS
|
||||
.tr '\'`\`
|
||||
.ta .25i
|
||||
3 changequote(L, R)
|
||||
1 define(name, replacement)
|
||||
4 divert(number)
|
||||
4 divnum
|
||||
5 dnl
|
||||
5 dumpdef(`name', `name', ...)
|
||||
5 errprint(s, s, ...)
|
||||
4 eval(numeric expression)
|
||||
3 ifdef(`name', this if true, this if false)
|
||||
5 ifelse(a, b, c, d)
|
||||
4 include(file)
|
||||
3 incr(number)
|
||||
5 index(s1, s2)
|
||||
5 len(string)
|
||||
4 maketemp(...XXXXX...)
|
||||
4 sinclude(file)
|
||||
5 substr(string, position, number)
|
||||
4 syscmd(s)
|
||||
5 translit(str, from, to)
|
||||
3 undefine(`name')
|
||||
4 undivert(number,number,...)
|
||||
.DE
|
||||
.SH
|
||||
Acknowledgements
|
||||
.PP
|
||||
We are indebted to Rick Becker, John Chambers,
|
||||
Doug McIlroy,
|
||||
and especially Jim Weythman,
|
||||
whose pioneering use of M4 has led to several valuable improvements.
|
||||
We are also deeply grateful to Weythman for several substantial contributions
|
||||
to the code.
|
||||
.SG
|
||||
.SH
|
||||
References
|
||||
.LP
|
||||
.IP [1]
|
||||
B. W. Kernighan and P. J. Plauger,
|
||||
.ul
|
||||
Software Tools,
|
||||
Addison-Wesley, Inc., 1976.
|
||||
642
third_party/m4/main.c
vendored
Normal file
642
third_party/m4/main.c
vendored
Normal file
@@ -0,0 +1,642 @@
|
||||
/* clang-format off */
|
||||
asm(".include \"third_party/m4/COPYING\"");
|
||||
|
||||
/* $OpenBSD: main.c,v 1.87 2017/06/15 13:48:42 bcallah Exp $ */
|
||||
/* $NetBSD: main.c,v 1.12 1997/02/08 23:54:49 cgd Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1989, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Ozan Yigit at York University.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* main.c
|
||||
* Facility: m4 macro processor
|
||||
* by: oz
|
||||
*/
|
||||
|
||||
#include "libc/assert.h"
|
||||
#include "libc/log/bsd.h"
|
||||
#include "libc/calls/openbsd.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "third_party/getopt/getopt.h"
|
||||
#include "third_party/m4/mdef.h"
|
||||
#include "third_party/m4/pathnames.h"
|
||||
#include "third_party/m4/stdd.h"
|
||||
/**/
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "third_party/m4/extern.h"
|
||||
#include "third_party/m4/ohash.h"
|
||||
|
||||
stae *mstack; /* stack of m4 machine */
|
||||
char *sstack; /* shadow stack, for string space extension */
|
||||
static size_t STACKMAX; /* current maximum size of stack */
|
||||
int sp; /* current m4 stack pointer */
|
||||
int fp; /* m4 call frame pointer */
|
||||
struct input_file infile[MAXINP];/* input file stack (0=stdin) */
|
||||
FILE **outfile; /* diversion array(0=bitbucket)*/
|
||||
int maxout;
|
||||
FILE *active; /* active output file pointer */
|
||||
int ilevel = 0; /* input file stack pointer */
|
||||
int oindex = 0; /* diversion index.. */
|
||||
char *null = ""; /* as it says.. just a null.. */
|
||||
char **m4wraps = NULL; /* m4wraps array. */
|
||||
int maxwraps = 0; /* size of m4wraps array */
|
||||
int wrapindex = 0; /* current offset in m4wraps */
|
||||
char lquote[MAXCCHARS+1] = {LQUOTE}; /* left quote character (`) */
|
||||
char rquote[MAXCCHARS+1] = {RQUOTE}; /* right quote character (') */
|
||||
char scommt[MAXCCHARS+1] = {SCOMMT}; /* start character for comment */
|
||||
char ecommt[MAXCCHARS+1] = {ECOMMT}; /* end character for comment */
|
||||
int synch_lines = 0; /* line synchronisation for C preprocessor */
|
||||
int prefix_builtins = 0; /* -P option to prefix builtin keywords */
|
||||
int error_warns = 0; /* -E option to make warnings exit_code = 1 */
|
||||
int fatal_warns = 0; /* -E -E option to make warnings fatal */
|
||||
|
||||
struct keyblk {
|
||||
char *knam; /* keyword name */
|
||||
int ktyp; /* keyword type */
|
||||
};
|
||||
|
||||
struct keyblk keywrds[] = { /* m4 keywords to be installed */
|
||||
{ "include", INCLTYPE },
|
||||
{ "sinclude", SINCTYPE },
|
||||
{ "define", DEFITYPE },
|
||||
{ "defn", DEFNTYPE },
|
||||
{ "divert", DIVRTYPE | NOARGS },
|
||||
{ "expr", EXPRTYPE },
|
||||
{ "eval", EXPRTYPE },
|
||||
{ "substr", SUBSTYPE },
|
||||
{ "ifelse", IFELTYPE },
|
||||
{ "ifdef", IFDFTYPE },
|
||||
{ "len", LENGTYPE },
|
||||
{ "incr", INCRTYPE },
|
||||
{ "decr", DECRTYPE },
|
||||
{ "dnl", DNLNTYPE | NOARGS },
|
||||
{ "changequote", CHNQTYPE | NOARGS },
|
||||
{ "changecom", CHNCTYPE | NOARGS },
|
||||
{ "index", INDXTYPE },
|
||||
#ifdef EXTENDED
|
||||
{ "paste", PASTTYPE },
|
||||
{ "spaste", SPASTYPE },
|
||||
/* Newer extensions, needed to handle gnu-m4 scripts */
|
||||
{ "indir", INDIRTYPE},
|
||||
{ "builtin", BUILTINTYPE},
|
||||
{ "patsubst", PATSTYPE},
|
||||
{ "regexp", REGEXPTYPE},
|
||||
{ "esyscmd", ESYSCMDTYPE},
|
||||
{ "__file__", FILENAMETYPE | NOARGS},
|
||||
{ "__line__", LINETYPE | NOARGS},
|
||||
#endif
|
||||
{ "popdef", POPDTYPE },
|
||||
{ "pushdef", PUSDTYPE },
|
||||
{ "dumpdef", DUMPTYPE | NOARGS },
|
||||
{ "shift", SHIFTYPE | NOARGS },
|
||||
{ "translit", TRNLTYPE },
|
||||
{ "undefine", UNDFTYPE },
|
||||
{ "undivert", UNDVTYPE | NOARGS },
|
||||
{ "divnum", DIVNTYPE | NOARGS },
|
||||
{ "maketemp", MKTMTYPE },
|
||||
{ "mkstemp", MKTMTYPE },
|
||||
{ "errprint", ERRPTYPE | NOARGS },
|
||||
{ "m4wrap", M4WRTYPE | NOARGS },
|
||||
{ "m4exit", EXITTYPE | NOARGS },
|
||||
{ "syscmd", SYSCTYPE },
|
||||
{ "sysval", SYSVTYPE | NOARGS },
|
||||
{ "traceon", TRACEONTYPE | NOARGS },
|
||||
{ "traceoff", TRACEOFFTYPE | NOARGS },
|
||||
|
||||
{ "unix", SELFTYPE | NOARGS },
|
||||
};
|
||||
|
||||
#define MAXKEYS (sizeof(keywrds)/sizeof(struct keyblk))
|
||||
|
||||
/* extern int optind; */
|
||||
/* extern char *optarg; */
|
||||
|
||||
#define MAXRECORD 50
|
||||
static struct position {
|
||||
char *name;
|
||||
unsigned long line;
|
||||
} quotes[MAXRECORD], paren[MAXRECORD];
|
||||
|
||||
static void record(struct position *, int);
|
||||
static void dump_stack(struct position *, int);
|
||||
|
||||
static void macro(void);
|
||||
static void initkwds(void);
|
||||
static ndptr inspect(int, char *);
|
||||
static int do_look_ahead(int, const char *);
|
||||
static void reallyoutputstr(const char *);
|
||||
static void reallyputchar(int);
|
||||
|
||||
static void enlarge_stack(void);
|
||||
|
||||
int main(int, char *[]);
|
||||
|
||||
int exit_code = 0;
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int c;
|
||||
int n;
|
||||
char *p;
|
||||
|
||||
pledge("stdio rpath wpath cpath tmppath proc exec", NULL);
|
||||
|
||||
if (signal(SIGINT, SIG_IGN) != SIG_IGN)
|
||||
signal(SIGINT, onintr);
|
||||
|
||||
init_macros();
|
||||
initspaces();
|
||||
STACKMAX = INITSTACKMAX;
|
||||
|
||||
mstack = xreallocarray(NULL, STACKMAX, sizeof(stae), NULL);
|
||||
sstack = xalloc(STACKMAX, NULL);
|
||||
|
||||
maxout = 0;
|
||||
outfile = NULL;
|
||||
resizedivs(MAXOUT);
|
||||
|
||||
while ((c = getopt(argc, argv, "gst:d:D:EU:o:I:P")) != -1)
|
||||
switch(c) {
|
||||
|
||||
case 'D': /* define something..*/
|
||||
for (p = optarg; *p; p++)
|
||||
if (*p == '=')
|
||||
break;
|
||||
if (*p)
|
||||
*p++ = EOS;
|
||||
dodefine(optarg, p);
|
||||
break;
|
||||
case 'E': /* like GNU m4 1.4.9+ */
|
||||
if (error_warns == 0)
|
||||
error_warns = 1;
|
||||
else
|
||||
fatal_warns = 1;
|
||||
break;
|
||||
case 'I':
|
||||
addtoincludepath(optarg);
|
||||
break;
|
||||
case 'P':
|
||||
prefix_builtins = 1;
|
||||
break;
|
||||
case 'U': /* undefine... */
|
||||
macro_popdef(optarg);
|
||||
break;
|
||||
case 'g':
|
||||
mimic_gnu = 1;
|
||||
break;
|
||||
case 'd':
|
||||
set_trace_flags(optarg);
|
||||
break;
|
||||
case 's':
|
||||
synch_lines = 1;
|
||||
break;
|
||||
case 't':
|
||||
mark_traced(optarg, 1);
|
||||
break;
|
||||
case 'o':
|
||||
trace_file(optarg);
|
||||
break;
|
||||
case '?':
|
||||
usage();
|
||||
}
|
||||
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
initkwds();
|
||||
if (mimic_gnu)
|
||||
setup_builtin("format", FORMATTYPE);
|
||||
|
||||
active = stdout; /* default active output */
|
||||
bbase[0] = bufbase;
|
||||
if (!argc) {
|
||||
sp = -1; /* stack pointer initialized */
|
||||
fp = 0; /* frame pointer initialized */
|
||||
set_input(infile+0, stdin, "stdin");
|
||||
/* default input (naturally) */
|
||||
macro();
|
||||
} else
|
||||
for (; argc--; ++argv) {
|
||||
p = *argv;
|
||||
if (p[0] == '-' && p[1] == EOS)
|
||||
set_input(infile, stdin, "stdin");
|
||||
else if (fopen_trypath(infile, p) == NULL)
|
||||
err(1, "%s", p);
|
||||
sp = -1;
|
||||
fp = 0;
|
||||
macro();
|
||||
release_input(infile);
|
||||
}
|
||||
|
||||
if (wrapindex) {
|
||||
int i;
|
||||
|
||||
ilevel = 0; /* in case m4wrap includes.. */
|
||||
bufbase = bp = buf; /* use the entire buffer */
|
||||
if (mimic_gnu) {
|
||||
while (wrapindex != 0) {
|
||||
for (i = 0; i < wrapindex; i++)
|
||||
pbstr(m4wraps[i]);
|
||||
wrapindex =0;
|
||||
macro();
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < wrapindex; i++) {
|
||||
pbstr(m4wraps[i]);
|
||||
macro();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (active != stdout)
|
||||
active = stdout; /* reset output just in case */
|
||||
for (n = 1; n < maxout; n++) /* default wrap-up: undivert */
|
||||
if (outfile[n] != NULL)
|
||||
getdiv(n);
|
||||
/* remove bitbucket if used */
|
||||
if (outfile[0] != NULL) {
|
||||
(void) fclose(outfile[0]);
|
||||
}
|
||||
|
||||
return exit_code;
|
||||
}
|
||||
|
||||
/*
|
||||
* Look ahead for `token'.
|
||||
* (on input `t == token[0]')
|
||||
* Used for comment and quoting delimiters.
|
||||
* Returns 1 if `token' present; copied to output.
|
||||
* 0 if `token' not found; all characters pushed back
|
||||
*/
|
||||
static int
|
||||
do_look_ahead(int t, const char *token)
|
||||
{
|
||||
int i;
|
||||
|
||||
assert((unsigned char)t == (unsigned char)token[0]);
|
||||
|
||||
for (i = 1; *++token; i++) {
|
||||
t = gpbc();
|
||||
if (t == EOF || (unsigned char)t != (unsigned char)*token) {
|
||||
pushback(t);
|
||||
while (--i)
|
||||
pushback(*--token);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define LOOK_AHEAD(t, token) (t != EOF && \
|
||||
(unsigned char)(t)==(unsigned char)(token)[0] && \
|
||||
do_look_ahead(t,token))
|
||||
|
||||
/*
|
||||
* macro - the work horse..
|
||||
*/
|
||||
static void
|
||||
macro(void)
|
||||
{
|
||||
char token[MAXTOK+1];
|
||||
int t, l;
|
||||
ndptr p;
|
||||
int nlpar;
|
||||
l = -1; /* TODO(jart): why does compiler complain? */
|
||||
|
||||
cycle {
|
||||
t = gpbc();
|
||||
|
||||
if (LOOK_AHEAD(t,lquote)) { /* strip quotes */
|
||||
nlpar = 0;
|
||||
record(quotes, nlpar++);
|
||||
/*
|
||||
* Opening quote: scan forward until matching
|
||||
* closing quote has been found.
|
||||
*/
|
||||
do {
|
||||
|
||||
l = gpbc();
|
||||
if (LOOK_AHEAD(l,rquote)) {
|
||||
if (--nlpar > 0)
|
||||
outputstr(rquote);
|
||||
} else if (LOOK_AHEAD(l,lquote)) {
|
||||
record(quotes, nlpar++);
|
||||
outputstr(lquote);
|
||||
} else if (l == EOF) {
|
||||
if (nlpar == 1)
|
||||
warnx("unclosed quote:");
|
||||
else
|
||||
warnx("%d unclosed quotes:", nlpar);
|
||||
dump_stack(quotes, nlpar);
|
||||
exit(1);
|
||||
} else {
|
||||
if (nlpar > 0) {
|
||||
if (sp < 0)
|
||||
reallyputchar(l);
|
||||
else
|
||||
CHRSAVE(l);
|
||||
}
|
||||
}
|
||||
}
|
||||
while (nlpar != 0);
|
||||
} else if (sp < 0 && LOOK_AHEAD(t, scommt)) {
|
||||
reallyoutputstr(scommt);
|
||||
|
||||
for(;;) {
|
||||
t = gpbc();
|
||||
if (LOOK_AHEAD(t, ecommt)) {
|
||||
reallyoutputstr(ecommt);
|
||||
break;
|
||||
}
|
||||
if (t == EOF)
|
||||
break;
|
||||
reallyputchar(t);
|
||||
}
|
||||
} else if (t == '_' || isalpha(t)) {
|
||||
p = inspect(t, token);
|
||||
if (p != NULL)
|
||||
pushback(l = gpbc());
|
||||
if (p == NULL || (l != LPAREN &&
|
||||
(macro_getdef(p)->type & NEEDARGS) != 0))
|
||||
outputstr(token);
|
||||
else {
|
||||
/*
|
||||
* real thing.. First build a call frame:
|
||||
*/
|
||||
pushf(fp); /* previous call frm */
|
||||
pushf(macro_getdef(p)->type); /* type of the call */
|
||||
pushf(is_traced(p));
|
||||
pushf(0); /* parenthesis level */
|
||||
fp = sp; /* new frame pointer */
|
||||
/*
|
||||
* now push the string arguments:
|
||||
*/
|
||||
pushdef(p); /* defn string */
|
||||
pushs1((char *)macro_name(p)); /* macro name */
|
||||
pushs(ep); /* start next..*/
|
||||
|
||||
if (l != LPAREN && PARLEV == 0) {
|
||||
/* no bracks */
|
||||
chrsave(EOS);
|
||||
|
||||
if (sp == STACKMAX)
|
||||
errx(1, "internal stack overflow");
|
||||
eval((const char **) mstack+fp+1, 2,
|
||||
CALTYP, TRACESTATUS);
|
||||
|
||||
ep = PREVEP; /* flush strspace */
|
||||
sp = PREVSP; /* previous sp.. */
|
||||
fp = PREVFP; /* rewind stack...*/
|
||||
}
|
||||
}
|
||||
} else if (t == EOF) {
|
||||
if (!mimic_gnu /* you can puke right there */
|
||||
&& sp > -1 && ilevel <= 0) {
|
||||
warnx( "unexpected end of input, unclosed parenthesis:");
|
||||
dump_stack(paren, PARLEV);
|
||||
exit(1);
|
||||
}
|
||||
if (ilevel <= 0)
|
||||
break; /* all done thanks.. */
|
||||
release_input(infile+ilevel--);
|
||||
emit_synchline();
|
||||
bufbase = bbase[ilevel];
|
||||
continue;
|
||||
} else if (sp < 0) { /* not in a macro at all */
|
||||
reallyputchar(t); /* output directly.. */
|
||||
}
|
||||
|
||||
else switch(t) {
|
||||
|
||||
case LPAREN:
|
||||
if (PARLEV > 0)
|
||||
chrsave(t);
|
||||
while (isspace(l = gpbc())) /* skip blank, tab, nl.. */
|
||||
if (PARLEV > 0)
|
||||
chrsave(l);
|
||||
pushback(l);
|
||||
record(paren, PARLEV++);
|
||||
break;
|
||||
|
||||
case RPAREN:
|
||||
if (--PARLEV > 0)
|
||||
chrsave(t);
|
||||
else { /* end of argument list */
|
||||
chrsave(EOS);
|
||||
|
||||
if (sp == STACKMAX)
|
||||
errx(1, "internal stack overflow");
|
||||
|
||||
eval((const char **) mstack+fp+1, sp-fp,
|
||||
CALTYP, TRACESTATUS);
|
||||
|
||||
ep = PREVEP; /* flush strspace */
|
||||
sp = PREVSP; /* previous sp.. */
|
||||
fp = PREVFP; /* rewind stack...*/
|
||||
}
|
||||
break;
|
||||
|
||||
case COMMA:
|
||||
if (PARLEV == 1) {
|
||||
chrsave(EOS); /* new argument */
|
||||
while (isspace(l = gpbc()))
|
||||
;
|
||||
pushback(l);
|
||||
pushs(ep);
|
||||
} else
|
||||
chrsave(t);
|
||||
break;
|
||||
|
||||
default:
|
||||
if (LOOK_AHEAD(t, scommt)) {
|
||||
char *p2;
|
||||
for (p2 = scommt; *p2; p2++)
|
||||
chrsave(*p2);
|
||||
for(;;) {
|
||||
t = gpbc();
|
||||
if (LOOK_AHEAD(t, ecommt)) {
|
||||
for (p2 = ecommt; *p2; p2++)
|
||||
chrsave(*p2);
|
||||
break;
|
||||
}
|
||||
if (t == EOF)
|
||||
break;
|
||||
CHRSAVE(t);
|
||||
}
|
||||
} else
|
||||
CHRSAVE(t); /* stack the char */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* output string directly, without pushing it for reparses.
|
||||
*/
|
||||
void
|
||||
outputstr(const char *s)
|
||||
{
|
||||
if (sp < 0)
|
||||
reallyoutputstr(s);
|
||||
else
|
||||
while (*s)
|
||||
CHRSAVE(*s++);
|
||||
}
|
||||
|
||||
void
|
||||
reallyoutputstr(const char *s)
|
||||
{
|
||||
if (synch_lines) {
|
||||
while (*s) {
|
||||
fputc(*s, active);
|
||||
if (*s++ == '\n') {
|
||||
infile[ilevel].synch_lineno++;
|
||||
if (infile[ilevel].synch_lineno !=
|
||||
infile[ilevel].lineno)
|
||||
do_emit_synchline();
|
||||
}
|
||||
}
|
||||
} else
|
||||
fputs(s, active);
|
||||
}
|
||||
|
||||
void
|
||||
reallyputchar(int c)
|
||||
{
|
||||
putc(c, active);
|
||||
if (synch_lines && c == '\n') {
|
||||
infile[ilevel].synch_lineno++;
|
||||
if (infile[ilevel].synch_lineno != infile[ilevel].lineno)
|
||||
do_emit_synchline();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* build an input token..
|
||||
* consider only those starting with _ or A-Za-z.
|
||||
*/
|
||||
static ndptr
|
||||
inspect(int c, char *tp)
|
||||
{
|
||||
char *name = tp;
|
||||
char *etp = tp+MAXTOK;
|
||||
ndptr p;
|
||||
|
||||
*tp++ = c;
|
||||
|
||||
while ((isalnum(c = gpbc()) || c == '_') && tp < etp)
|
||||
*tp++ = c;
|
||||
if (c != EOF)
|
||||
PUSHBACK(c);
|
||||
*tp = EOS;
|
||||
/* token is too long, it won't match anything, but it can still
|
||||
* be output. */
|
||||
if (tp == ep) {
|
||||
outputstr(name);
|
||||
while (isalnum(c = gpbc()) || c == '_') {
|
||||
if (sp < 0)
|
||||
reallyputchar(c);
|
||||
else
|
||||
CHRSAVE(c);
|
||||
}
|
||||
*name = EOS;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
p = ohash_find(¯os, ohash_qlookupi(¯os, name, (const char **)&tp));
|
||||
if (p == NULL)
|
||||
return NULL;
|
||||
if (macro_getdef(p) == NULL)
|
||||
return NULL;
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
* initkwds - initialise m4 keywords as fast as possible.
|
||||
* This very similar to install, but without certain overheads,
|
||||
* such as calling lookup. Malloc is not used for storing the
|
||||
* keyword strings, since we simply use the static pointers
|
||||
* within keywrds block.
|
||||
*/
|
||||
static void
|
||||
initkwds(void)
|
||||
{
|
||||
unsigned int type;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAXKEYS; i++) {
|
||||
type = keywrds[i].ktyp & TYPEMASK;
|
||||
if ((keywrds[i].ktyp & NOARGS) == 0)
|
||||
type |= NEEDARGS;
|
||||
setup_builtin(keywrds[i].knam, type);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
record(struct position *t, int lev)
|
||||
{
|
||||
if (lev < MAXRECORD) {
|
||||
t[lev].name = CURRENT_NAME;
|
||||
t[lev].line = CURRENT_LINE;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dump_stack(struct position *t, int lev)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < lev; i++) {
|
||||
if (i == MAXRECORD) {
|
||||
fprintf(stderr, " ...\n");
|
||||
break;
|
||||
}
|
||||
fprintf(stderr, " %s at line %lu\n",
|
||||
t[i].name, t[i].line);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
enlarge_stack(void)
|
||||
{
|
||||
STACKMAX += STACKMAX/2;
|
||||
mstack = xreallocarray(mstack, STACKMAX, sizeof(stae),
|
||||
"Evaluation stack overflow (%lu)",
|
||||
(unsigned long)STACKMAX);
|
||||
sstack = xrealloc(sstack, STACKMAX,
|
||||
"Evaluation stack overflow (%lu)",
|
||||
(unsigned long)STACKMAX);
|
||||
}
|
||||
239
third_party/m4/mdef.h
vendored
Normal file
239
third_party/m4/mdef.h
vendored
Normal file
@@ -0,0 +1,239 @@
|
||||
/* clang-format off */
|
||||
/* $OpenBSD: mdef.h,v 1.33 2015/11/03 16:21:47 deraadt Exp $ */
|
||||
/* $NetBSD: mdef.h,v 1.7 1996/01/13 23:25:27 pk Exp $ */
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
/*
|
||||
* Copyright (c) 1989, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Ozan Yigit at York University.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)mdef.h 8.1 (Berkeley) 6/6/93
|
||||
*/
|
||||
|
||||
#ifdef __GNUC__
|
||||
# define UNUSED __attribute__((__unused__))
|
||||
#else
|
||||
# define UNUSED
|
||||
#endif
|
||||
|
||||
#define MACRTYPE 1
|
||||
#define DEFITYPE 2
|
||||
#define EXPRTYPE 3
|
||||
#define SUBSTYPE 4
|
||||
#define IFELTYPE 5
|
||||
#define LENGTYPE 6
|
||||
#define CHNQTYPE 7
|
||||
#define SYSCTYPE 8
|
||||
#define UNDFTYPE 9
|
||||
#define INCLTYPE 10
|
||||
#define SINCTYPE 11
|
||||
#define PASTTYPE 12
|
||||
#define SPASTYPE 13
|
||||
#define INCRTYPE 14
|
||||
#define IFDFTYPE 15
|
||||
#define PUSDTYPE 16
|
||||
#define POPDTYPE 17
|
||||
#define SHIFTYPE 18
|
||||
#define DECRTYPE 19
|
||||
#define DIVRTYPE 20
|
||||
#define UNDVTYPE 21
|
||||
#define DIVNTYPE 22
|
||||
#define MKTMTYPE 23
|
||||
#define ERRPTYPE 24
|
||||
#define M4WRTYPE 25
|
||||
#define TRNLTYPE 26
|
||||
#define DNLNTYPE 27
|
||||
#define DUMPTYPE 28
|
||||
#define CHNCTYPE 29
|
||||
#define INDXTYPE 30
|
||||
#define SYSVTYPE 31
|
||||
#define EXITTYPE 32
|
||||
#define DEFNTYPE 33
|
||||
#define SELFTYPE 34
|
||||
#define INDIRTYPE 35
|
||||
#define BUILTINTYPE 36
|
||||
#define PATSTYPE 37
|
||||
#define FILENAMETYPE 38
|
||||
#define LINETYPE 39
|
||||
#define REGEXPTYPE 40
|
||||
#define ESYSCMDTYPE 41
|
||||
#define TRACEONTYPE 42
|
||||
#define TRACEOFFTYPE 43
|
||||
#define FORMATTYPE 44
|
||||
|
||||
#define BUILTIN_MARKER "__builtin_"
|
||||
|
||||
#define TYPEMASK 63 /* Keep bits really corresponding to a type. */
|
||||
#define RECDEF 256 /* Pure recursive def, don't expand it */
|
||||
#define NOARGS 512 /* builtin needs no args */
|
||||
#define NEEDARGS 1024 /* mark builtin that need args with this */
|
||||
|
||||
/*
|
||||
* m4 special characters
|
||||
*/
|
||||
|
||||
#define ARGFLAG '$'
|
||||
#define LPAREN '('
|
||||
#define RPAREN ')'
|
||||
#define LQUOTE '`'
|
||||
#define RQUOTE '\''
|
||||
#define COMMA ','
|
||||
#define SCOMMT '#'
|
||||
#define ECOMMT '\n'
|
||||
|
||||
/*
|
||||
* other important constants
|
||||
*/
|
||||
|
||||
#define EOS '\0'
|
||||
#define MAXINP 10 /* maximum include files */
|
||||
#define MAXOUT 10 /* maximum # of diversions */
|
||||
#define BUFSIZE 4096 /* starting size of pushback buffer */
|
||||
#define INITSTACKMAX 4096 /* starting size of call stack */
|
||||
#define STRSPMAX 4096 /* starting size of string space */
|
||||
#define MAXTOK 512 /* maximum chars in a tokn */
|
||||
#define MAXCCHARS 5 /* max size of comment/quote delim */
|
||||
|
||||
#define ALL 1
|
||||
#define TOP 0
|
||||
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
#define cycle for(;;)
|
||||
|
||||
/*
|
||||
* m4 data structures
|
||||
*/
|
||||
|
||||
typedef struct ndblock *ndptr;
|
||||
|
||||
struct macro_definition {
|
||||
struct macro_definition *next;
|
||||
char *defn; /* definition.. */
|
||||
unsigned int type; /* type of the entry.. */
|
||||
};
|
||||
|
||||
|
||||
struct ndblock { /* hashtable structure */
|
||||
unsigned int builtin_type;
|
||||
unsigned int trace_flags;
|
||||
struct macro_definition *d;
|
||||
char name[1]; /* entry name.. */
|
||||
};
|
||||
|
||||
typedef union { /* stack structure */
|
||||
int sfra; /* frame entry */
|
||||
char *sstr; /* string entry */
|
||||
} stae;
|
||||
|
||||
struct input_file {
|
||||
FILE *file;
|
||||
char *name;
|
||||
unsigned long lineno;
|
||||
unsigned long synch_lineno; /* used for -s */
|
||||
int c;
|
||||
};
|
||||
|
||||
#define STORAGE_STRSPACE 0
|
||||
#define STORAGE_MACRO 1
|
||||
#define STORAGE_OTHER 2
|
||||
|
||||
#define CURRENT_NAME (infile[ilevel].name)
|
||||
#define CURRENT_LINE (infile[ilevel].lineno)
|
||||
/*
|
||||
* macros for readibility and/or speed
|
||||
*
|
||||
* gpbc() - get a possibly pushed-back character
|
||||
* pushf() - push a call frame entry onto stack
|
||||
* pushs() - push a string pointer onto stack
|
||||
*/
|
||||
#define gpbc() (bp > bufbase) ? *--bp : obtain_char(infile+ilevel)
|
||||
#define pushf(x) \
|
||||
do { \
|
||||
if (++sp == STACKMAX) \
|
||||
enlarge_stack();\
|
||||
mstack[sp].sfra = (x); \
|
||||
sstack[sp] = STORAGE_OTHER; \
|
||||
} while (0)
|
||||
|
||||
#define pushs(x) \
|
||||
do { \
|
||||
if (++sp == STACKMAX) \
|
||||
enlarge_stack();\
|
||||
mstack[sp].sstr = (x); \
|
||||
sstack[sp] = STORAGE_STRSPACE; \
|
||||
} while (0)
|
||||
|
||||
#define pushs1(x) \
|
||||
do { \
|
||||
if (++sp == STACKMAX) \
|
||||
enlarge_stack();\
|
||||
mstack[sp].sstr = (x); \
|
||||
sstack[sp] = STORAGE_OTHER; \
|
||||
} while (0)
|
||||
|
||||
#define pushdef(p) \
|
||||
do { \
|
||||
if (++sp == STACKMAX) \
|
||||
enlarge_stack();\
|
||||
mstack[sp].sstr = macro_getdef(p)->defn;\
|
||||
sstack[sp] = STORAGE_MACRO; \
|
||||
} while (0)
|
||||
|
||||
|
||||
/*
|
||||
* . .
|
||||
* | . | <-- sp | . |
|
||||
* +-------+ +-----+
|
||||
* | arg 3 ----------------------->| str |
|
||||
* +-------+ | . |
|
||||
* | arg 2 ---PREVEP-----+ .
|
||||
* +-------+ |
|
||||
* . | | |
|
||||
* +-------+ | +-----+
|
||||
* | plev | PARLEV +-------->| str |
|
||||
* +-------+ | . |
|
||||
* | type | CALTYP .
|
||||
* +-------+
|
||||
* | prcf ---PREVFP--+
|
||||
* +-------+ |
|
||||
* | . | PREVSP |
|
||||
* . |
|
||||
* +-------+ |
|
||||
* | <----------+
|
||||
* +-------+
|
||||
*
|
||||
*/
|
||||
#define PARLEV (mstack[fp].sfra)
|
||||
#define CALTYP (mstack[fp-2].sfra)
|
||||
#define TRACESTATUS (mstack[fp-1].sfra)
|
||||
#define PREVEP (mstack[fp+3].sstr)
|
||||
#define PREVSP (fp-4)
|
||||
#define PREVFP (mstack[fp-3].sfra)
|
||||
466
third_party/m4/misc.c
vendored
Normal file
466
third_party/m4/misc.c
vendored
Normal file
@@ -0,0 +1,466 @@
|
||||
/* clang-format off */
|
||||
/* $OpenBSD: misc.c,v 1.47 2017/06/15 13:48:42 bcallah Exp $ */
|
||||
/* $NetBSD: misc.c,v 1.6 1995/09/28 05:37:41 tls Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1989, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Ozan Yigit at York University.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "third_party/m4/mdef.h"
|
||||
#include "third_party/m4/stdd.h"
|
||||
#include "third_party/m4/extern.h"
|
||||
#include "libc/alg/alg.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/log/bsd.h"
|
||||
#include "libc/sysv/consts/fileno.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "third_party/m4/pathnames.h"
|
||||
|
||||
|
||||
char *ep; /* first free char in strspace */
|
||||
static char *strspace; /* string space for evaluation */
|
||||
char *endest; /* end of string space */
|
||||
static size_t strsize = STRSPMAX;
|
||||
static size_t bufsize = BUFSIZE;
|
||||
|
||||
unsigned char *buf; /* push-back buffer */
|
||||
unsigned char *bufbase; /* the base for current ilevel */
|
||||
unsigned char *bbase[MAXINP]; /* the base for each ilevel */
|
||||
unsigned char *bp; /* first available character */
|
||||
unsigned char *endpbb; /* end of push-back buffer */
|
||||
|
||||
|
||||
/*
|
||||
* find the index of second str in the first str.
|
||||
*/
|
||||
ptrdiff_t
|
||||
indx(const char *s1, const char *s2)
|
||||
{
|
||||
char *t;
|
||||
|
||||
t = strstr(s1, s2);
|
||||
if (t == NULL)
|
||||
return (-1);
|
||||
else
|
||||
return (t - s1);
|
||||
}
|
||||
/*
|
||||
* pushback - push character back onto input
|
||||
*/
|
||||
void
|
||||
pushback(int c)
|
||||
{
|
||||
if (c == EOF)
|
||||
return;
|
||||
if (bp >= endpbb)
|
||||
enlarge_bufspace();
|
||||
*bp++ = c;
|
||||
}
|
||||
|
||||
/*
|
||||
* pbstr - push string back onto input
|
||||
* pushback is replicated to improve
|
||||
* performance.
|
||||
*/
|
||||
void
|
||||
pbstr(const char *s)
|
||||
{
|
||||
size_t n;
|
||||
|
||||
n = strlen(s);
|
||||
while (endpbb - bp <= n)
|
||||
enlarge_bufspace();
|
||||
while (n > 0)
|
||||
*bp++ = s[--n];
|
||||
}
|
||||
|
||||
/*
|
||||
* pbnum - convert number to string, push back on input.
|
||||
*/
|
||||
void
|
||||
pbnum(int n)
|
||||
{
|
||||
pbnumbase(n, 10, 0);
|
||||
}
|
||||
|
||||
void
|
||||
pbnumbase(int n, int base, int d)
|
||||
{
|
||||
static char digits[36] = "0123456789abcdefghijklmnopqrstuvwxyz";
|
||||
int num;
|
||||
int printed = 0;
|
||||
|
||||
if (base > 36)
|
||||
m4errx(1, "base %d > 36: not supported.", base);
|
||||
|
||||
if (base < 2)
|
||||
m4errx(1, "bad base %d for conversion.", base);
|
||||
|
||||
num = (n < 0) ? -n : n;
|
||||
do {
|
||||
pushback(digits[num % base]);
|
||||
printed++;
|
||||
}
|
||||
while ((num /= base) > 0);
|
||||
|
||||
if (n < 0)
|
||||
printed++;
|
||||
while (printed++ < d)
|
||||
pushback('0');
|
||||
|
||||
if (n < 0)
|
||||
pushback('-');
|
||||
}
|
||||
|
||||
/*
|
||||
* pbunsigned - convert unsigned long to string, push back on input.
|
||||
*/
|
||||
void
|
||||
pbunsigned(unsigned long n)
|
||||
{
|
||||
do {
|
||||
pushback(n % 10 + '0');
|
||||
}
|
||||
while ((n /= 10) > 0);
|
||||
}
|
||||
|
||||
void
|
||||
initspaces()
|
||||
{
|
||||
int i;
|
||||
|
||||
strspace = xalloc(strsize+1, NULL);
|
||||
ep = strspace;
|
||||
endest = strspace+strsize;
|
||||
buf = xalloc(bufsize, NULL);
|
||||
bufbase = buf;
|
||||
bp = buf;
|
||||
endpbb = buf + bufsize;
|
||||
for (i = 0; i < MAXINP; i++)
|
||||
bbase[i] = buf;
|
||||
}
|
||||
|
||||
void
|
||||
enlarge_strspace()
|
||||
{
|
||||
char *newstrspace;
|
||||
int i;
|
||||
|
||||
strsize *= 2;
|
||||
newstrspace = malloc(strsize + 1);
|
||||
if (!newstrspace)
|
||||
errx(1, "string space overflow");
|
||||
memcpy(newstrspace, strspace, strsize/2);
|
||||
for (i = 0; i <= sp; i++)
|
||||
if (sstack[i] == STORAGE_STRSPACE)
|
||||
mstack[i].sstr = (mstack[i].sstr - strspace)
|
||||
+ newstrspace;
|
||||
ep = (ep-strspace) + newstrspace;
|
||||
free(strspace);
|
||||
strspace = newstrspace;
|
||||
endest = strspace + strsize;
|
||||
}
|
||||
|
||||
void
|
||||
enlarge_bufspace()
|
||||
{
|
||||
unsigned char *newbuf;
|
||||
int i;
|
||||
|
||||
bufsize += bufsize/2;
|
||||
newbuf = xrealloc(buf, bufsize, "too many characters pushed back");
|
||||
for (i = 0; i < MAXINP; i++)
|
||||
bbase[i] = (bbase[i]-buf)+newbuf;
|
||||
bp = (bp-buf)+newbuf;
|
||||
bufbase = (bufbase-buf)+newbuf;
|
||||
buf = newbuf;
|
||||
endpbb = buf+bufsize;
|
||||
}
|
||||
|
||||
/*
|
||||
* chrsave - put single char on string space
|
||||
*/
|
||||
void
|
||||
chrsave(int c)
|
||||
{
|
||||
if (ep >= endest)
|
||||
enlarge_strspace();
|
||||
*ep++ = c;
|
||||
}
|
||||
|
||||
/*
|
||||
* read in a diversion file, and dispose it.
|
||||
*/
|
||||
void
|
||||
getdiv(int n)
|
||||
{
|
||||
int c;
|
||||
|
||||
if (active == outfile[n])
|
||||
m4errx(1, "undivert: diversion still active.");
|
||||
rewind(outfile[n]);
|
||||
while ((c = getc(outfile[n])) != EOF)
|
||||
putc(c, active);
|
||||
(void) fclose(outfile[n]);
|
||||
outfile[n] = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
onintr(int signo)
|
||||
{
|
||||
#define intrmessage "m4: interrupted.\n"
|
||||
write(STDERR_FILENO, intrmessage, sizeof(intrmessage)-1);
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* killdiv - get rid of the diversion files
|
||||
*/
|
||||
void
|
||||
killdiv()
|
||||
{
|
||||
int n;
|
||||
|
||||
for (n = 0; n < maxout; n++)
|
||||
if (outfile[n] != NULL) {
|
||||
(void) fclose(outfile[n]);
|
||||
}
|
||||
}
|
||||
|
||||
extern char *__progname;
|
||||
|
||||
void
|
||||
m4errx(int eval, const char *fmt, ...)
|
||||
{
|
||||
fprintf(stderr, "%s: ", __progname);
|
||||
fprintf(stderr, "%s at line %lu: ", CURRENT_NAME, CURRENT_LINE);
|
||||
if (fmt != NULL) {
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
exit(eval);
|
||||
}
|
||||
|
||||
/*
|
||||
* resizedivs: allocate more diversion files */
|
||||
void
|
||||
resizedivs(int n)
|
||||
{
|
||||
int i;
|
||||
|
||||
outfile = xreallocarray(outfile, n, sizeof(FILE *),
|
||||
"too many diverts %d", n);
|
||||
for (i = maxout; i < n; i++)
|
||||
outfile[i] = NULL;
|
||||
maxout = n;
|
||||
}
|
||||
|
||||
void *
|
||||
xalloc(size_t n, const char *fmt, ...)
|
||||
{
|
||||
void *p = malloc(n);
|
||||
|
||||
if (p == NULL) {
|
||||
if (fmt == NULL)
|
||||
err(1, "malloc");
|
||||
else {
|
||||
va_list va;
|
||||
|
||||
va_start(va, fmt);
|
||||
verr(1, fmt, va);
|
||||
va_end(va);
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
void *
|
||||
xcalloc(size_t n, size_t s, const char *fmt, ...)
|
||||
{
|
||||
void *p = calloc(n, s);
|
||||
|
||||
if (p == NULL) {
|
||||
if (fmt == NULL)
|
||||
err(1, "calloc");
|
||||
else {
|
||||
va_list va;
|
||||
|
||||
va_start(va, fmt);
|
||||
verr(1, fmt, va);
|
||||
va_end(va);
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
void *
|
||||
xrealloc(void *old, size_t n, const char *fmt, ...)
|
||||
{
|
||||
char *p = realloc(old, n);
|
||||
|
||||
if (p == NULL) {
|
||||
free(old);
|
||||
if (fmt == NULL)
|
||||
err(1, "realloc");
|
||||
else {
|
||||
va_list va;
|
||||
|
||||
va_start(va, fmt);
|
||||
verr(1, fmt, va);
|
||||
va_end(va);
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
void *
|
||||
xreallocarray(void *old, size_t s1, size_t s2, const char *fmt, ...)
|
||||
{
|
||||
void *p = reallocarray(old, s1, s2);
|
||||
|
||||
if (p == NULL) {
|
||||
free(old);
|
||||
if (fmt == NULL)
|
||||
err(1, "reallocarray");
|
||||
else {
|
||||
va_list va;
|
||||
|
||||
va_start(va, fmt);
|
||||
verr(1, fmt, va);
|
||||
va_end(va);
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
char *
|
||||
xstrdup(const char *s)
|
||||
{
|
||||
char *p = strdup(s);
|
||||
if (p == NULL)
|
||||
err(1, "strdup");
|
||||
return p;
|
||||
}
|
||||
|
||||
void
|
||||
usage(void)
|
||||
{
|
||||
fprintf(stderr, "usage: %s [-EgPs] [-Dname[=value]] [-d flags] "
|
||||
"[-I dirname] [-o filename]\n"
|
||||
"\t[-t macro] [-Uname] [file ...]\n", g_argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int
|
||||
obtain_char(struct input_file *f)
|
||||
{
|
||||
if (f->c == EOF)
|
||||
return EOF;
|
||||
|
||||
f->c = fgetc(f->file);
|
||||
if (f->c == '\n')
|
||||
f->lineno++;
|
||||
|
||||
return f->c;
|
||||
}
|
||||
|
||||
void
|
||||
set_input(struct input_file *f, FILE *real, const char *name)
|
||||
{
|
||||
f->file = real;
|
||||
f->lineno = 1;
|
||||
f->c = 0;
|
||||
f->name = xstrdup(name);
|
||||
emit_synchline();
|
||||
}
|
||||
|
||||
void
|
||||
do_emit_synchline()
|
||||
{
|
||||
fprintf(active, "#line %lu \"%s\"\n",
|
||||
infile[ilevel].lineno, infile[ilevel].name);
|
||||
infile[ilevel].synch_lineno = infile[ilevel].lineno;
|
||||
}
|
||||
|
||||
void
|
||||
release_input(struct input_file *f)
|
||||
{
|
||||
if (ferror(f->file))
|
||||
errx(1, "Fatal error reading from %s\n", f->name);
|
||||
if (f->file != stdin)
|
||||
fclose(f->file);
|
||||
f->c = EOF;
|
||||
/*
|
||||
* XXX can't free filename, as there might still be
|
||||
* error information pointing to it.
|
||||
*/
|
||||
}
|
||||
|
||||
void
|
||||
doprintlineno(struct input_file *f)
|
||||
{
|
||||
pbunsigned(f->lineno);
|
||||
}
|
||||
|
||||
void
|
||||
doprintfilename(struct input_file *f)
|
||||
{
|
||||
pbstr(rquote);
|
||||
pbstr(f->name);
|
||||
pbstr(lquote);
|
||||
}
|
||||
|
||||
/*
|
||||
* buffer_mark/dump_buffer: allows one to save a mark in a buffer,
|
||||
* and later dump everything that was added since then to a file.
|
||||
*/
|
||||
size_t
|
||||
buffer_mark()
|
||||
{
|
||||
return bp - buf;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
dump_buffer(FILE *f, size_t m)
|
||||
{
|
||||
unsigned char *s;
|
||||
|
||||
for (s = bp; s-buf > m;)
|
||||
fputc(*--s, f);
|
||||
}
|
||||
325
third_party/m4/ohash.c
vendored
Normal file
325
third_party/m4/ohash.c
vendored
Normal file
@@ -0,0 +1,325 @@
|
||||
/* clang-format off */
|
||||
/* $OpenBSD: ohash.c,v 1.1 2014/06/02 18:52:03 deraadt Exp $ */
|
||||
|
||||
/* Copyright (c) 1999, 2004 Marc Espie <espie@openbsd.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/limits.h"
|
||||
#include "third_party/m4/ohash.h"
|
||||
|
||||
struct _ohash_record {
|
||||
uint32_t hv;
|
||||
const char *p;
|
||||
};
|
||||
|
||||
#define DELETED ((const char *)h)
|
||||
#define NONE (h->size)
|
||||
|
||||
/* Don't bother changing the hash table if the change is small enough. */
|
||||
#define MINSIZE (1UL << 4)
|
||||
#define MINDELETED 4
|
||||
|
||||
static void ohash_resize(struct ohash *);
|
||||
|
||||
|
||||
/* This handles the common case of variable length keys, where the
|
||||
* key is stored at the end of the record.
|
||||
*/
|
||||
void *
|
||||
ohash_create_entry(struct ohash_info *i, const char *start, const char **end)
|
||||
{
|
||||
char *p;
|
||||
|
||||
if (!*end)
|
||||
*end = start + strlen(start);
|
||||
p = (i->alloc)(i->key_offset + (*end - start) + 1, i->data);
|
||||
if (p) {
|
||||
memcpy(p+i->key_offset, start, *end-start);
|
||||
p[i->key_offset + (*end - start)] = '\0';
|
||||
}
|
||||
return (void *)p;
|
||||
}
|
||||
|
||||
/* hash_delete only frees the hash structure. Use hash_first/hash_next
|
||||
* to free entries as well. */
|
||||
void
|
||||
ohash_delete(struct ohash *h)
|
||||
{
|
||||
(h->info.free)(h->t, h->info.data);
|
||||
#ifndef NDEBUG
|
||||
h->t = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
ohash_resize(struct ohash *h)
|
||||
{
|
||||
struct _ohash_record *n;
|
||||
size_t ns;
|
||||
unsigned int j;
|
||||
unsigned int i, incr;
|
||||
|
||||
if (4 * h->deleted < h->total) {
|
||||
if (h->size >= ((int32_t)-1 >> 1U))
|
||||
ns = UINT_MAX;
|
||||
else
|
||||
ns = h->size << 1U;
|
||||
} else if (3 * h->deleted > 2 * h->total)
|
||||
ns = h->size >> 1U;
|
||||
else
|
||||
ns = h->size;
|
||||
if (ns < MINSIZE)
|
||||
ns = MINSIZE;
|
||||
#ifdef STATS_HASH
|
||||
STAT_HASH_EXPAND++;
|
||||
STAT_HASH_SIZE += ns - h->size;
|
||||
#endif
|
||||
|
||||
n = (h->info.calloc)(ns, sizeof(struct _ohash_record), h->info.data);
|
||||
if (!n)
|
||||
return;
|
||||
|
||||
for (j = 0; j < h->size; j++) {
|
||||
if (h->t[j].p != NULL && h->t[j].p != DELETED) {
|
||||
i = h->t[j].hv % ns;
|
||||
incr = ((h->t[j].hv % (ns - 2)) & ~1) + 1;
|
||||
while (n[i].p != NULL) {
|
||||
i += incr;
|
||||
if (i >= ns)
|
||||
i -= ns;
|
||||
}
|
||||
n[i].hv = h->t[j].hv;
|
||||
n[i].p = h->t[j].p;
|
||||
}
|
||||
}
|
||||
(h->info.free)(h->t, h->info.data);
|
||||
h->t = n;
|
||||
h->size = ns;
|
||||
h->total -= h->deleted;
|
||||
h->deleted = 0;
|
||||
}
|
||||
|
||||
void *
|
||||
ohash_remove(struct ohash *h, unsigned int i)
|
||||
{
|
||||
void *result = (void *)h->t[i].p;
|
||||
|
||||
if (result == NULL || result == DELETED)
|
||||
return NULL;
|
||||
|
||||
#ifdef STATS_HASH
|
||||
STAT_HASH_ENTRIES--;
|
||||
#endif
|
||||
h->t[i].p = DELETED;
|
||||
h->deleted++;
|
||||
if (h->deleted >= MINDELETED && 4 * h->deleted > h->total)
|
||||
ohash_resize(h);
|
||||
return result;
|
||||
}
|
||||
|
||||
void *
|
||||
ohash_find(struct ohash *h, unsigned int i)
|
||||
{
|
||||
if (h->t[i].p == DELETED)
|
||||
return NULL;
|
||||
else
|
||||
return (void *)h->t[i].p;
|
||||
}
|
||||
|
||||
void *
|
||||
ohash_insert(struct ohash *h, unsigned int i, void *p)
|
||||
{
|
||||
#ifdef STATS_HASH
|
||||
STAT_HASH_ENTRIES++;
|
||||
#endif
|
||||
if (h->t[i].p == DELETED) {
|
||||
h->deleted--;
|
||||
h->t[i].p = p;
|
||||
} else {
|
||||
h->t[i].p = p;
|
||||
/* Arbitrary resize boundary. Tweak if not efficient enough. */
|
||||
if (++h->total * 4 > h->size * 3)
|
||||
ohash_resize(h);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
ohash_entries(struct ohash *h)
|
||||
{
|
||||
return h->total - h->deleted;
|
||||
}
|
||||
|
||||
void *
|
||||
ohash_first(struct ohash *h, unsigned int *pos)
|
||||
{
|
||||
*pos = 0;
|
||||
return ohash_next(h, pos);
|
||||
}
|
||||
|
||||
void *
|
||||
ohash_next(struct ohash *h, unsigned int *pos)
|
||||
{
|
||||
for (; *pos < h->size; (*pos)++)
|
||||
if (h->t[*pos].p != DELETED && h->t[*pos].p != NULL)
|
||||
return (void *)h->t[(*pos)++].p;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
ohash_init(struct ohash *h, unsigned int size, struct ohash_info *info)
|
||||
{
|
||||
h->size = 1UL << size;
|
||||
if (h->size < MINSIZE)
|
||||
h->size = MINSIZE;
|
||||
#ifdef STATS_HASH
|
||||
STAT_HASH_CREATION++;
|
||||
STAT_HASH_SIZE += h->size;
|
||||
#endif
|
||||
/* Copy info so that caller may free it. */
|
||||
h->info.key_offset = info->key_offset;
|
||||
h->info.calloc = info->calloc;
|
||||
h->info.free = info->free;
|
||||
h->info.alloc = info->alloc;
|
||||
h->info.data = info->data;
|
||||
h->t = (h->info.calloc)(h->size, sizeof(struct _ohash_record),
|
||||
h->info.data);
|
||||
h->total = h->deleted = 0;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ohash_interval(const char *s, const char **e)
|
||||
{
|
||||
uint32_t k;
|
||||
|
||||
if (!*e)
|
||||
*e = s + strlen(s);
|
||||
if (s == *e)
|
||||
k = 0;
|
||||
else
|
||||
k = *s++;
|
||||
while (s != *e)
|
||||
k = ((k << 2) | (k >> 30)) ^ *s++;
|
||||
return k;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
ohash_lookup_interval(struct ohash *h, const char *start, const char *end,
|
||||
uint32_t hv)
|
||||
{
|
||||
unsigned int i, incr;
|
||||
unsigned int empty;
|
||||
|
||||
#ifdef STATS_HASH
|
||||
STAT_HASH_LOOKUP++;
|
||||
#endif
|
||||
empty = NONE;
|
||||
i = hv % h->size;
|
||||
incr = ((hv % (h->size-2)) & ~1) + 1;
|
||||
while (h->t[i].p != NULL) {
|
||||
#ifdef STATS_HASH
|
||||
STAT_HASH_LENGTH++;
|
||||
#endif
|
||||
if (h->t[i].p == DELETED) {
|
||||
if (empty == NONE)
|
||||
empty = i;
|
||||
} else if (h->t[i].hv == hv &&
|
||||
strncmp(h->t[i].p+h->info.key_offset, start,
|
||||
end - start) == 0 &&
|
||||
(h->t[i].p+h->info.key_offset)[end-start] == '\0') {
|
||||
if (empty != NONE) {
|
||||
h->t[empty].hv = hv;
|
||||
h->t[empty].p = h->t[i].p;
|
||||
h->t[i].p = DELETED;
|
||||
return empty;
|
||||
} else {
|
||||
#ifdef STATS_HASH
|
||||
STAT_HASH_POSITIVE++;
|
||||
#endif
|
||||
return i;
|
||||
}
|
||||
}
|
||||
i += incr;
|
||||
if (i >= h->size)
|
||||
i -= h->size;
|
||||
}
|
||||
|
||||
/* Found an empty position. */
|
||||
if (empty != NONE)
|
||||
i = empty;
|
||||
h->t[i].hv = hv;
|
||||
return i;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
ohash_lookup_memory(struct ohash *h, const char *k, size_t size, uint32_t hv)
|
||||
{
|
||||
unsigned int i, incr;
|
||||
unsigned int empty;
|
||||
|
||||
#ifdef STATS_HASH
|
||||
STAT_HASH_LOOKUP++;
|
||||
#endif
|
||||
empty = NONE;
|
||||
i = hv % h->size;
|
||||
incr = ((hv % (h->size-2)) & ~1) + 1;
|
||||
while (h->t[i].p != NULL) {
|
||||
#ifdef STATS_HASH
|
||||
STAT_HASH_LENGTH++;
|
||||
#endif
|
||||
if (h->t[i].p == DELETED) {
|
||||
if (empty == NONE)
|
||||
empty = i;
|
||||
} else if (h->t[i].hv == hv &&
|
||||
memcmp(h->t[i].p+h->info.key_offset, k, size) == 0) {
|
||||
if (empty != NONE) {
|
||||
h->t[empty].hv = hv;
|
||||
h->t[empty].p = h->t[i].p;
|
||||
h->t[i].p = DELETED;
|
||||
return empty;
|
||||
} else {
|
||||
#ifdef STATS_HASH
|
||||
STAT_HASH_POSITIVE++;
|
||||
#endif
|
||||
} return i;
|
||||
}
|
||||
i += incr;
|
||||
if (i >= h->size)
|
||||
i -= h->size;
|
||||
}
|
||||
|
||||
/* Found an empty position. */
|
||||
if (empty != NONE)
|
||||
i = empty;
|
||||
h->t[i].hv = hv;
|
||||
return i;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
ohash_qlookup(struct ohash *h, const char *s)
|
||||
{
|
||||
const char *e = NULL;
|
||||
return ohash_qlookupi(h, s, &e);
|
||||
}
|
||||
|
||||
unsigned int
|
||||
ohash_qlookupi(struct ohash *h, const char *s, const char **e)
|
||||
{
|
||||
uint32_t hv;
|
||||
|
||||
hv = ohash_interval(s, e);
|
||||
return ohash_lookup_interval(h, s, *e, hv);
|
||||
}
|
||||
75
third_party/m4/ohash.h
vendored
Normal file
75
third_party/m4/ohash.h
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
/* clang-format off */
|
||||
/* $OpenBSD: ohash.h,v 1.2 2014/06/02 18:52:03 deraadt Exp $ */
|
||||
|
||||
/* Copyright (c) 1999, 2004 Marc Espie <espie@openbsd.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef OHASH_H
|
||||
#define OHASH_H
|
||||
|
||||
/* Open hashing support.
|
||||
* Open hashing was chosen because it is much lighter than other hash
|
||||
* techniques, and more efficient in most cases.
|
||||
*/
|
||||
|
||||
/* user-visible data structure */
|
||||
struct ohash_info {
|
||||
ptrdiff_t key_offset;
|
||||
void *data; /* user data */
|
||||
void *(*calloc)(size_t, size_t, void *);
|
||||
void (*free)(void *, void *);
|
||||
void *(*alloc)(size_t, void *);
|
||||
};
|
||||
|
||||
struct _ohash_record;
|
||||
|
||||
/* private structure. It's there just so you can do a sizeof */
|
||||
struct ohash {
|
||||
struct _ohash_record *t;
|
||||
struct ohash_info info;
|
||||
unsigned int size;
|
||||
unsigned int total;
|
||||
unsigned int deleted;
|
||||
};
|
||||
|
||||
/* For this to be tweakable, we use small primitives, and leave part of the
|
||||
* logic to the client application. e.g., hashing is left to the client
|
||||
* application. We also provide a simple table entry lookup that yields
|
||||
* a hashing table index (opaque) to be used in find/insert/remove.
|
||||
* The keys are stored at a known position in the client data.
|
||||
*/
|
||||
/* __BEGIN_DECLS */
|
||||
void ohash_init(struct ohash *, unsigned, struct ohash_info *);
|
||||
void ohash_delete(struct ohash *);
|
||||
|
||||
unsigned int ohash_lookup_interval(struct ohash *, const char *,
|
||||
const char *, uint32_t);
|
||||
unsigned int ohash_lookup_memory(struct ohash *, const char *,
|
||||
size_t, uint32_t)
|
||||
/* __attribute__ ((__bounded__(__string__,2,3))) */;
|
||||
void *ohash_find(struct ohash *, unsigned int);
|
||||
void *ohash_remove(struct ohash *, unsigned int);
|
||||
void *ohash_insert(struct ohash *, unsigned int, void *);
|
||||
void *ohash_first(struct ohash *, unsigned int *);
|
||||
void *ohash_next(struct ohash *, unsigned int *);
|
||||
unsigned int ohash_entries(struct ohash *);
|
||||
|
||||
void *ohash_create_entry(struct ohash_info *, const char *, const char **);
|
||||
uint32_t ohash_interval(const char *, const char **);
|
||||
|
||||
unsigned int ohash_qlookupi(struct ohash *, const char *, const char **);
|
||||
unsigned int ohash_qlookup(struct ohash *, const char *);
|
||||
/* __END_DECLS */
|
||||
#endif
|
||||
713
third_party/m4/parser.c
vendored
Normal file
713
third_party/m4/parser.c
vendored
Normal file
@@ -0,0 +1,713 @@
|
||||
#include "libc/limits.h"
|
||||
#include "libc/math.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
#define YYBYACC 1
|
||||
#define YYMAJOR 1
|
||||
#define YYMINOR 9
|
||||
#define YYLEX yylex()
|
||||
#define YYEMPTY -1
|
||||
#define yyclearin (yychar = (YYEMPTY))
|
||||
#define yyerrok (yyerrflag = 0)
|
||||
#define YYRECOVERING() (yyerrflag != 0)
|
||||
#define YYPREFIX "yy"
|
||||
|
||||
/* clang-format off */
|
||||
/* #line 2 "parser.y" */
|
||||
/* $OpenBSD: parser.y,v 1.7 2012/04/12 17:00:11 espie Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2004 Marc Espie <espie@cvs.openbsd.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
#define YYSTYPE int32_t
|
||||
extern int32_t end_result;
|
||||
extern int yylex(void);
|
||||
extern int yyerror(const char *);
|
||||
/* #line 36 "parser.c" */
|
||||
#define NUMBER 257
|
||||
#define ERROR 258
|
||||
#define LOR 259
|
||||
#define LAND 260
|
||||
#define EQ 261
|
||||
#define NE 262
|
||||
#define LE 263
|
||||
#define GE 264
|
||||
#define LSHIFT 265
|
||||
#define RSHIFT 266
|
||||
#define EXPONENT 267
|
||||
#define UMINUS 268
|
||||
#define UPLUS 269
|
||||
#define YYERRCODE 256
|
||||
const short yylhs[] =
|
||||
{ -1,
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1,
|
||||
};
|
||||
const short yylen[] =
|
||||
{ 2,
|
||||
1, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
3, 2, 2, 2, 2, 1,
|
||||
};
|
||||
const short yydefred[] =
|
||||
{ 0,
|
||||
26, 0, 0, 0, 0, 0, 0, 0, 23, 22,
|
||||
24, 25, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 21, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0,
|
||||
};
|
||||
const short yydgoto[] =
|
||||
{ 7,
|
||||
8,
|
||||
};
|
||||
const short yysindex[] =
|
||||
{ 95,
|
||||
0, 95, 95, 95, 95, 95, 0, 397, 0, 0,
|
||||
0, 0, 383, 95, 95, 95, 95, 95, 95, 95,
|
||||
95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
|
||||
95, 95, 0, 428, 471, 482, 185, 437, 493, 493,
|
||||
-10, -10, -10, -10, -23, -23, -34, -34, -267, -267,
|
||||
-267, -267,};
|
||||
const short yyrindex[] =
|
||||
{ 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 2, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 11, 62, 23, 101, 308, 201, 243,
|
||||
124, 130, 144, 155, 79, 116, 51, 67, 1, 12,
|
||||
28, 40,};
|
||||
const short yygindex[] =
|
||||
{ 0,
|
||||
582,
|
||||
};
|
||||
#define YYTABLESIZE 760
|
||||
const short yytable[] =
|
||||
{ 32,
|
||||
5, 1, 31, 0, 0, 0, 0, 29, 0, 0,
|
||||
20, 6, 30, 31, 0, 0, 0, 0, 29, 27,
|
||||
0, 28, 18, 30, 0, 0, 31, 7, 0, 0,
|
||||
0, 29, 27, 0, 28, 0, 30, 5, 5, 4,
|
||||
0, 5, 5, 5, 0, 5, 0, 5, 6, 6,
|
||||
2, 20, 6, 6, 6, 0, 6, 0, 6, 0,
|
||||
5, 19, 5, 18, 7, 7, 3, 0, 7, 7,
|
||||
7, 6, 7, 6, 7, 0, 4, 4, 8, 0,
|
||||
4, 4, 4, 0, 4, 0, 4, 7, 2, 7,
|
||||
0, 2, 0, 2, 5, 2, 0, 0, 0, 4,
|
||||
17, 4, 19, 0, 3, 6, 0, 3, 0, 3,
|
||||
2, 3, 2, 0, 0, 9, 8, 0, 0, 8,
|
||||
0, 7, 0, 10, 5, 0, 3, 4, 3, 12,
|
||||
0, 0, 0, 4, 6, 6, 0, 2, 8, 3,
|
||||
8, 17, 0, 11, 2, 0, 18, 0, 0, 0,
|
||||
0, 7, 0, 9, 13, 0, 9, 0, 0, 0,
|
||||
3, 10, 0, 4, 10, 0, 0, 12, 0, 0,
|
||||
12, 0, 8, 0, 2, 9, 0, 9, 0, 0,
|
||||
0, 11, 0, 10, 11, 10, 0, 0, 0, 12,
|
||||
3, 12, 13, 0, 17, 13, 0, 0, 0, 0,
|
||||
14, 0, 8, 11, 0, 11, 0, 0, 0, 9,
|
||||
0, 0, 0, 0, 13, 0, 13, 10, 0, 0,
|
||||
5, 31, 18, 12, 17, 0, 29, 27, 0, 28,
|
||||
0, 30, 32, 0, 0, 0, 0, 11, 14, 9,
|
||||
0, 14, 15, 32, 21, 0, 23, 10, 13, 0,
|
||||
0, 0, 0, 12, 25, 26, 32, 0, 0, 5,
|
||||
5, 5, 5, 5, 5, 5, 5, 11, 0, 20,
|
||||
6, 6, 6, 6, 6, 6, 6, 6, 13, 0,
|
||||
15, 18, 18, 15, 0, 0, 7, 7, 7, 7,
|
||||
7, 7, 7, 7, 14, 0, 0, 0, 4, 4,
|
||||
4, 4, 4, 4, 4, 4, 0, 16, 0, 2,
|
||||
2, 2, 2, 2, 2, 2, 2, 0, 0, 0,
|
||||
19, 19, 0, 0, 14, 3, 3, 3, 3, 3,
|
||||
3, 3, 3, 0, 0, 0, 15, 8, 8, 8,
|
||||
8, 8, 8, 8, 8, 16, 0, 0, 16, 0,
|
||||
0, 1, 0, 0, 0, 0, 0, 0, 0, 17,
|
||||
17, 0, 0, 0, 0, 0, 15, 0, 0, 0,
|
||||
0, 0, 0, 0, 9, 9, 9, 9, 9, 9,
|
||||
9, 9, 10, 10, 10, 10, 10, 10, 12, 12,
|
||||
12, 12, 12, 12, 0, 0, 0, 0, 0, 0,
|
||||
0, 16, 11, 11, 11, 11, 11, 11, 0, 0,
|
||||
0, 0, 0, 13, 13, 13, 13, 13, 13, 31,
|
||||
18, 0, 0, 33, 29, 27, 0, 28, 0, 30,
|
||||
0, 16, 0, 31, 18, 0, 0, 0, 29, 27,
|
||||
0, 28, 21, 30, 23, 19, 20, 22, 24, 25,
|
||||
26, 32, 0, 0, 0, 0, 21, 0, 23, 14,
|
||||
14, 14, 14, 0, 31, 18, 0, 0, 0, 29,
|
||||
27, 0, 28, 31, 30, 0, 17, 0, 29, 27,
|
||||
0, 28, 0, 30, 0, 0, 0, 21, 0, 23,
|
||||
17, 0, 0, 0, 0, 0, 21, 0, 23, 0,
|
||||
0, 15, 15, 15, 15, 0, 16, 31, 18, 0,
|
||||
0, 0, 29, 27, 0, 28, 0, 30, 31, 18,
|
||||
16, 17, 0, 29, 27, 0, 28, 0, 30, 31,
|
||||
21, 0, 23, 0, 29, 27, 0, 28, 0, 30,
|
||||
0, 21, 0, 23, 0, 0, 0, 0, 0, 0,
|
||||
0, 16, 21, 0, 23, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 17, 0, 16, 16, 0, 0,
|
||||
0, 0, 0, 0, 0, 17, 0, 0, 0, 0,
|
||||
0, 0, 0, 9, 10, 11, 12, 13, 0, 0,
|
||||
0, 0, 0, 0, 16, 34, 35, 36, 37, 38,
|
||||
39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
|
||||
49, 50, 51, 52, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 14, 15, 19, 20, 22, 24, 25, 26, 32,
|
||||
0, 0, 0, 0, 0, 14, 15, 19, 20, 22,
|
||||
24, 25, 26, 32, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 15, 19, 20,
|
||||
22, 24, 25, 26, 32, 0, 0, 19, 20, 22,
|
||||
24, 25, 26, 32, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 19, 20, 22, 24, 25, 26, 32, 0, 0,
|
||||
0, 0, 19, 20, 22, 24, 25, 26, 32, 0,
|
||||
0, 0, 0, 0, 0, 22, 24, 25, 26, 32,
|
||||
};
|
||||
const short yycheck[] =
|
||||
{ 267,
|
||||
0, 0, 37, -1, -1, -1, -1, 42, -1, -1,
|
||||
0, 0, 47, 37, -1, -1, -1, -1, 42, 43,
|
||||
-1, 45, 0, 47, -1, -1, 37, 0, -1, -1,
|
||||
-1, 42, 43, -1, 45, -1, 47, 37, 38, 0,
|
||||
-1, 41, 42, 43, -1, 45, -1, 47, 37, 38,
|
||||
0, 41, 41, 42, 43, -1, 45, -1, 47, -1,
|
||||
60, 0, 62, 41, 37, 38, 0, -1, 41, 42,
|
||||
43, 60, 45, 62, 47, -1, 37, 38, 0, -1,
|
||||
41, 42, 43, -1, 45, -1, 47, 60, 38, 62,
|
||||
-1, 41, -1, 43, 94, 45, -1, -1, -1, 60,
|
||||
0, 62, 41, -1, 38, 94, -1, 41, -1, 43,
|
||||
60, 45, 62, -1, -1, 0, 38, -1, -1, 41,
|
||||
-1, 94, -1, 0, 124, -1, 60, 33, 62, 0,
|
||||
-1, -1, -1, 94, 40, 124, -1, 43, 60, 45,
|
||||
62, 41, -1, 0, 94, -1, 124, -1, -1, -1,
|
||||
-1, 124, -1, 38, 0, -1, 41, -1, -1, -1,
|
||||
94, 38, -1, 124, 41, -1, -1, 38, -1, -1,
|
||||
41, -1, 94, -1, 124, 60, -1, 62, -1, -1,
|
||||
-1, 38, -1, 60, 41, 62, -1, -1, -1, 60,
|
||||
124, 62, 38, -1, 94, 41, -1, -1, -1, -1,
|
||||
0, -1, 124, 60, -1, 62, -1, -1, -1, 94,
|
||||
-1, -1, -1, -1, 60, -1, 62, 94, -1, -1,
|
||||
126, 37, 38, 94, 124, -1, 42, 43, -1, 45,
|
||||
-1, 47, 267, -1, -1, -1, -1, 94, 38, 124,
|
||||
-1, 41, 0, 267, 60, -1, 62, 124, 94, -1,
|
||||
-1, -1, -1, 124, 265, 266, 267, -1, -1, 259,
|
||||
260, 261, 262, 263, 264, 265, 266, 124, -1, 259,
|
||||
259, 260, 261, 262, 263, 264, 265, 266, 124, -1,
|
||||
38, 259, 260, 41, -1, -1, 259, 260, 261, 262,
|
||||
263, 264, 265, 266, 94, -1, -1, -1, 259, 260,
|
||||
261, 262, 263, 264, 265, 266, -1, 0, -1, 259,
|
||||
260, 261, 262, 263, 264, 265, 266, -1, -1, -1,
|
||||
259, 260, -1, -1, 124, 259, 260, 261, 262, 263,
|
||||
264, 265, 266, -1, -1, -1, 94, 259, 260, 261,
|
||||
262, 263, 264, 265, 266, 38, -1, -1, 41, -1,
|
||||
-1, 257, -1, -1, -1, -1, -1, -1, -1, 259,
|
||||
260, -1, -1, -1, -1, -1, 124, -1, -1, -1,
|
||||
-1, -1, -1, -1, 259, 260, 261, 262, 263, 264,
|
||||
265, 266, 259, 260, 261, 262, 263, 264, 259, 260,
|
||||
261, 262, 263, 264, -1, -1, -1, -1, -1, -1,
|
||||
-1, 94, 259, 260, 261, 262, 263, 264, -1, -1,
|
||||
-1, -1, -1, 259, 260, 261, 262, 263, 264, 37,
|
||||
38, -1, -1, 41, 42, 43, -1, 45, -1, 47,
|
||||
-1, 124, -1, 37, 38, -1, -1, -1, 42, 43,
|
||||
-1, 45, 60, 47, 62, 261, 262, 263, 264, 265,
|
||||
266, 267, -1, -1, -1, -1, 60, -1, 62, 259,
|
||||
260, 261, 262, -1, 37, 38, -1, -1, -1, 42,
|
||||
43, -1, 45, 37, 47, -1, 94, -1, 42, 43,
|
||||
-1, 45, -1, 47, -1, -1, -1, 60, -1, 62,
|
||||
94, -1, -1, -1, -1, -1, 60, -1, 62, -1,
|
||||
-1, 259, 260, 261, 262, -1, 124, 37, 38, -1,
|
||||
-1, -1, 42, 43, -1, 45, -1, 47, 37, 38,
|
||||
124, 94, -1, 42, 43, -1, 45, -1, 47, 37,
|
||||
60, -1, 62, -1, 42, 43, -1, 45, -1, 47,
|
||||
-1, 60, -1, 62, -1, -1, -1, -1, -1, -1,
|
||||
-1, 124, 60, -1, 62, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, 94, -1, 259, 260, -1, -1,
|
||||
-1, -1, -1, -1, -1, 94, -1, -1, -1, -1,
|
||||
-1, -1, -1, 2, 3, 4, 5, 6, -1, -1,
|
||||
-1, -1, -1, -1, 124, 14, 15, 16, 17, 18,
|
||||
19, 20, 21, 22, 23, 24, 25, 26, 27, 28,
|
||||
29, 30, 31, 32, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, 259, 260, 261, 262, 263, 264, 265, 266, 267,
|
||||
-1, -1, -1, -1, -1, 259, 260, 261, 262, 263,
|
||||
264, 265, 266, 267, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, 260, 261, 262,
|
||||
263, 264, 265, 266, 267, -1, -1, 261, 262, 263,
|
||||
264, 265, 266, 267, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, 261, 262, 263, 264, 265, 266, 267, -1, -1,
|
||||
-1, -1, 261, 262, 263, 264, 265, 266, 267, -1,
|
||||
-1, -1, -1, -1, -1, 263, 264, 265, 266, 267,
|
||||
};
|
||||
#define YYFINAL 7
|
||||
#ifndef YYDEBUG
|
||||
#define YYDEBUG 0
|
||||
#endif
|
||||
#define YYMAXTOKEN 269
|
||||
#if YYDEBUG
|
||||
const char * const yyname[] =
|
||||
{
|
||||
"end-of-file",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
"'!'",0,0,0,"'%'","'&'",0,"'('","')'","'*'","'+'",0,"'-'",0,"'/'",0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,"'<'",0,"'>'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,"'^'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"'|'",0,
|
||||
"'~'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,"NUMBER","ERROR","LOR","LAND","EQ","NE","LE","GE",
|
||||
"LSHIFT","RSHIFT","EXPONENT","UMINUS","UPLUS",
|
||||
};
|
||||
const char * const yyrule[] =
|
||||
{"$accept : top",
|
||||
"top : expr",
|
||||
"expr : expr '+' expr",
|
||||
"expr : expr '-' expr",
|
||||
"expr : expr EXPONENT expr",
|
||||
"expr : expr '*' expr",
|
||||
"expr : expr '/' expr",
|
||||
"expr : expr '%' expr",
|
||||
"expr : expr LSHIFT expr",
|
||||
"expr : expr RSHIFT expr",
|
||||
"expr : expr '<' expr",
|
||||
"expr : expr '>' expr",
|
||||
"expr : expr LE expr",
|
||||
"expr : expr GE expr",
|
||||
"expr : expr EQ expr",
|
||||
"expr : expr NE expr",
|
||||
"expr : expr '&' expr",
|
||||
"expr : expr '^' expr",
|
||||
"expr : expr '|' expr",
|
||||
"expr : expr LAND expr",
|
||||
"expr : expr LOR expr",
|
||||
"expr : '(' expr ')'",
|
||||
"expr : '-' expr",
|
||||
"expr : '+' expr",
|
||||
"expr : '!' expr",
|
||||
"expr : '~' expr",
|
||||
"expr : NUMBER",
|
||||
};
|
||||
#endif
|
||||
#ifndef YYSTYPE
|
||||
typedef int YYSTYPE;
|
||||
#endif
|
||||
#ifdef YYSTACKSIZE
|
||||
#undef YYMAXDEPTH
|
||||
#define YYMAXDEPTH YYSTACKSIZE
|
||||
#else
|
||||
#ifdef YYMAXDEPTH
|
||||
#define YYSTACKSIZE YYMAXDEPTH
|
||||
#else
|
||||
#define YYSTACKSIZE 10000
|
||||
#define YYMAXDEPTH 10000
|
||||
#endif
|
||||
#endif
|
||||
#define YYINITSTACKSIZE 200
|
||||
/* LINTUSED */
|
||||
int yydebug;
|
||||
int yynerrs;
|
||||
int yyerrflag;
|
||||
int yychar;
|
||||
short *yyssp;
|
||||
YYSTYPE *yyvsp;
|
||||
YYSTYPE yyval;
|
||||
YYSTYPE yylval;
|
||||
short *yyss;
|
||||
short *yysslim;
|
||||
YYSTYPE *yyvs;
|
||||
unsigned int yystacksize;
|
||||
int yyparse(void);
|
||||
/* #line 83 "parser.y" */
|
||||
|
||||
/* #line 326 "parser.c" */
|
||||
/* allocate initial stack or double stack size, up to YYMAXDEPTH */
|
||||
static int yygrowstack(void)
|
||||
{
|
||||
unsigned int newsize;
|
||||
long sslen;
|
||||
short *newss;
|
||||
YYSTYPE *newvs;
|
||||
|
||||
if ((newsize = yystacksize) == 0)
|
||||
newsize = YYINITSTACKSIZE;
|
||||
else if (newsize >= YYMAXDEPTH)
|
||||
return -1;
|
||||
else if ((newsize *= 2) > YYMAXDEPTH)
|
||||
newsize = YYMAXDEPTH;
|
||||
sslen = yyssp - yyss;
|
||||
#ifdef SIZE_MAX
|
||||
#define YY_SIZE_MAX SIZE_MAX
|
||||
#else
|
||||
#define YY_SIZE_MAX 0xffffffffU
|
||||
#endif
|
||||
if (newsize && YY_SIZE_MAX / newsize < sizeof *newss)
|
||||
goto bail;
|
||||
newss = yyss ? (short *)realloc(yyss, newsize * sizeof *newss) :
|
||||
(short *)malloc(newsize * sizeof *newss); /* overflow check above */
|
||||
if (newss == NULL)
|
||||
goto bail;
|
||||
yyss = newss;
|
||||
yyssp = newss + sslen;
|
||||
if (newsize && YY_SIZE_MAX / newsize < sizeof *newvs)
|
||||
goto bail;
|
||||
newvs = yyvs ? (YYSTYPE *)realloc(yyvs, newsize * sizeof *newvs) :
|
||||
(YYSTYPE *)malloc(newsize * sizeof *newvs); /* overflow check above */
|
||||
if (newvs == NULL)
|
||||
goto bail;
|
||||
yyvs = newvs;
|
||||
yyvsp = newvs + sslen;
|
||||
yystacksize = newsize;
|
||||
yysslim = yyss + newsize - 1;
|
||||
return 0;
|
||||
bail:
|
||||
if (yyss)
|
||||
free(yyss);
|
||||
if (yyvs)
|
||||
free(yyvs);
|
||||
yyss = yyssp = NULL;
|
||||
yyvs = yyvsp = NULL;
|
||||
yystacksize = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
#define YYABORT goto yyabort
|
||||
#define YYREJECT goto yyabort
|
||||
#define YYACCEPT goto yyaccept
|
||||
#define YYERROR goto yyerrlab
|
||||
int
|
||||
yyparse(void)
|
||||
{
|
||||
int yym, yyn, yystate;
|
||||
#if YYDEBUG
|
||||
const char *yys;
|
||||
|
||||
if ((yys = getenv("YYDEBUG")))
|
||||
{
|
||||
yyn = *yys;
|
||||
if (yyn >= '0' && yyn <= '9')
|
||||
yydebug = yyn - '0';
|
||||
}
|
||||
#endif /* YYDEBUG */
|
||||
|
||||
yynerrs = 0;
|
||||
yyerrflag = 0;
|
||||
yychar = (-1);
|
||||
|
||||
if (yyss == NULL && yygrowstack()) goto yyoverflow;
|
||||
yyssp = yyss;
|
||||
yyvsp = yyvs;
|
||||
*yyssp = yystate = 0;
|
||||
|
||||
yyloop:
|
||||
if ((yyn = yydefred[yystate]) != 0) goto yyreduce;
|
||||
if (yychar < 0)
|
||||
{
|
||||
if ((yychar = yylex()) < 0) yychar = 0;
|
||||
#if YYDEBUG
|
||||
if (yydebug)
|
||||
{
|
||||
yys = 0;
|
||||
if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
|
||||
if (!yys) yys = "illegal-symbol";
|
||||
printf("%sdebug: state %d, reading %d (%s)\n",
|
||||
YYPREFIX, yystate, yychar, yys);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if ((yyn = yysindex[yystate]) && (yyn += yychar) >= 0 &&
|
||||
yyn <= YYTABLESIZE && yycheck[yyn] == yychar)
|
||||
{
|
||||
#if YYDEBUG
|
||||
if (yydebug)
|
||||
printf("%sdebug: state %d, shifting to state %d\n",
|
||||
YYPREFIX, yystate, yytable[yyn]);
|
||||
#endif
|
||||
if (yyssp >= yysslim && yygrowstack())
|
||||
{
|
||||
goto yyoverflow;
|
||||
}
|
||||
*++yyssp = yystate = yytable[yyn];
|
||||
*++yyvsp = yylval;
|
||||
yychar = (-1);
|
||||
if (yyerrflag > 0) --yyerrflag;
|
||||
goto yyloop;
|
||||
}
|
||||
if ((yyn = yyrindex[yystate]) && (yyn += yychar) >= 0 &&
|
||||
yyn <= YYTABLESIZE && yycheck[yyn] == yychar)
|
||||
{
|
||||
yyn = yytable[yyn];
|
||||
goto yyreduce;
|
||||
}
|
||||
if (yyerrflag) goto yyinrecovery;
|
||||
#if defined(__GNUC__)
|
||||
goto yynewerror;
|
||||
#endif
|
||||
yynewerror:
|
||||
yyerror("syntax error");
|
||||
#if defined(__GNUC__)
|
||||
goto yyerrlab;
|
||||
#endif
|
||||
yyerrlab:
|
||||
++yynerrs;
|
||||
yyinrecovery:
|
||||
if (yyerrflag < 3)
|
||||
{
|
||||
yyerrflag = 3;
|
||||
for (;;)
|
||||
{
|
||||
if ((yyn = yysindex[*yyssp]) && (yyn += YYERRCODE) >= 0 &&
|
||||
yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE)
|
||||
{
|
||||
#if YYDEBUG
|
||||
if (yydebug)
|
||||
printf("%sdebug: state %d, error recovery shifting\
|
||||
to state %d\n", YYPREFIX, *yyssp, yytable[yyn]);
|
||||
#endif
|
||||
if (yyssp >= yysslim && yygrowstack())
|
||||
{
|
||||
goto yyoverflow;
|
||||
}
|
||||
*++yyssp = yystate = yytable[yyn];
|
||||
*++yyvsp = yylval;
|
||||
goto yyloop;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if YYDEBUG
|
||||
if (yydebug)
|
||||
printf("%sdebug: error recovery discarding state %d\n",
|
||||
YYPREFIX, *yyssp);
|
||||
#endif
|
||||
if (yyssp <= yyss) goto yyabort;
|
||||
--yyssp;
|
||||
--yyvsp;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (yychar == 0) goto yyabort;
|
||||
#if YYDEBUG
|
||||
if (yydebug)
|
||||
{
|
||||
yys = 0;
|
||||
if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
|
||||
if (!yys) yys = "illegal-symbol";
|
||||
printf("%sdebug: state %d, error recovery discards token %d (%s)\n",
|
||||
YYPREFIX, yystate, yychar, yys);
|
||||
}
|
||||
#endif
|
||||
yychar = (-1);
|
||||
goto yyloop;
|
||||
}
|
||||
yyreduce:
|
||||
#if YYDEBUG
|
||||
if (yydebug)
|
||||
printf("%sdebug: state %d, reducing by rule %d (%s)\n",
|
||||
YYPREFIX, yystate, yyn, yyrule[yyn]);
|
||||
#endif
|
||||
yym = yylen[yyn];
|
||||
if (yym)
|
||||
yyval = yyvsp[1-yym];
|
||||
else
|
||||
memset(&yyval, 0, sizeof yyval);
|
||||
switch (yyn)
|
||||
{
|
||||
case 1:
|
||||
/* #line 42 "parser.y" */
|
||||
{ end_result = yyvsp[0]; }
|
||||
break;
|
||||
case 2:
|
||||
/* #line 44 "parser.y" */
|
||||
{ yyval = yyvsp[-2] + yyvsp[0]; }
|
||||
break;
|
||||
case 3:
|
||||
/* #line 45 "parser.y" */
|
||||
{ yyval = yyvsp[-2] - yyvsp[0]; }
|
||||
break;
|
||||
case 4:
|
||||
/* #line 46 "parser.y" */
|
||||
{ yyval = pow(yyvsp[-2], yyvsp[0]); }
|
||||
break;
|
||||
case 5:
|
||||
/* #line 47 "parser.y" */
|
||||
{ yyval = yyvsp[-2] * yyvsp[0]; }
|
||||
break;
|
||||
case 6:
|
||||
/* #line 48 "parser.y" */
|
||||
{
|
||||
if (yyvsp[0] == 0) {
|
||||
yyerror("division by zero");
|
||||
exit(1);
|
||||
}
|
||||
yyval = yyvsp[-2] / yyvsp[0];
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
/* #line 55 "parser.y" */
|
||||
{
|
||||
if (yyvsp[0] == 0) {
|
||||
yyerror("modulo zero");
|
||||
exit(1);
|
||||
}
|
||||
yyval = yyvsp[-2] % yyvsp[0];
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
/* #line 62 "parser.y" */
|
||||
{ yyval = yyvsp[-2] << yyvsp[0]; }
|
||||
break;
|
||||
case 9:
|
||||
/* #line 63 "parser.y" */
|
||||
{ yyval = yyvsp[-2] >> yyvsp[0]; }
|
||||
break;
|
||||
case 10:
|
||||
/* #line 64 "parser.y" */
|
||||
{ yyval = yyvsp[-2] < yyvsp[0]; }
|
||||
break;
|
||||
case 11:
|
||||
/* #line 65 "parser.y" */
|
||||
{ yyval = yyvsp[-2] > yyvsp[0]; }
|
||||
break;
|
||||
case 12:
|
||||
/* #line 66 "parser.y" */
|
||||
{ yyval = yyvsp[-2] <= yyvsp[0]; }
|
||||
break;
|
||||
case 13:
|
||||
/* #line 67 "parser.y" */
|
||||
{ yyval = yyvsp[-2] >= yyvsp[0]; }
|
||||
break;
|
||||
case 14:
|
||||
/* #line 68 "parser.y" */
|
||||
{ yyval = yyvsp[-2] == yyvsp[0]; }
|
||||
break;
|
||||
case 15:
|
||||
/* #line 69 "parser.y" */
|
||||
{ yyval = yyvsp[-2] != yyvsp[0]; }
|
||||
break;
|
||||
case 16:
|
||||
/* #line 70 "parser.y" */
|
||||
{ yyval = yyvsp[-2] & yyvsp[0]; }
|
||||
break;
|
||||
case 17:
|
||||
/* #line 71 "parser.y" */
|
||||
{ yyval = yyvsp[-2] ^ yyvsp[0]; }
|
||||
break;
|
||||
case 18:
|
||||
/* #line 72 "parser.y" */
|
||||
{ yyval = yyvsp[-2] | yyvsp[0]; }
|
||||
break;
|
||||
case 19:
|
||||
/* #line 73 "parser.y" */
|
||||
{ yyval = yyvsp[-2] && yyvsp[0]; }
|
||||
break;
|
||||
case 20:
|
||||
/* #line 74 "parser.y" */
|
||||
{ yyval = yyvsp[-2] || yyvsp[0]; }
|
||||
break;
|
||||
case 21:
|
||||
/* #line 75 "parser.y" */
|
||||
{ yyval = yyvsp[-1]; }
|
||||
break;
|
||||
case 22:
|
||||
/* #line 76 "parser.y" */
|
||||
{ yyval = -yyvsp[0]; }
|
||||
break;
|
||||
case 23:
|
||||
/* #line 77 "parser.y" */
|
||||
{ yyval = yyvsp[0]; }
|
||||
break;
|
||||
case 24:
|
||||
/* #line 78 "parser.y" */
|
||||
{ yyval = !yyvsp[0]; }
|
||||
break;
|
||||
case 25:
|
||||
/* #line 79 "parser.y" */
|
||||
{ yyval = ~yyvsp[0]; }
|
||||
break;
|
||||
/* #line 632 "parser.c" */
|
||||
}
|
||||
yyssp -= yym;
|
||||
yystate = *yyssp;
|
||||
yyvsp -= yym;
|
||||
yym = yylhs[yyn];
|
||||
if (yystate == 0 && yym == 0)
|
||||
{
|
||||
#if YYDEBUG
|
||||
if (yydebug)
|
||||
printf("%sdebug: after reduction, shifting from state 0 to\
|
||||
state %d\n", YYPREFIX, YYFINAL);
|
||||
#endif
|
||||
yystate = YYFINAL;
|
||||
*++yyssp = YYFINAL;
|
||||
*++yyvsp = yyval;
|
||||
if (yychar < 0)
|
||||
{
|
||||
if ((yychar = yylex()) < 0) yychar = 0;
|
||||
#if YYDEBUG
|
||||
if (yydebug)
|
||||
{
|
||||
yys = 0;
|
||||
if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
|
||||
if (!yys) yys = "illegal-symbol";
|
||||
printf("%sdebug: state %d, reading %d (%s)\n",
|
||||
YYPREFIX, YYFINAL, yychar, yys);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (yychar == 0) goto yyaccept;
|
||||
goto yyloop;
|
||||
}
|
||||
if ((yyn = yygindex[yym]) && (yyn += yystate) >= 0 &&
|
||||
yyn <= YYTABLESIZE && yycheck[yyn] == yystate)
|
||||
yystate = yytable[yyn];
|
||||
else
|
||||
yystate = yydgoto[yym];
|
||||
#if YYDEBUG
|
||||
if (yydebug)
|
||||
printf("%sdebug: after reduction, shifting from state %d \
|
||||
to state %d\n", YYPREFIX, *yyssp, yystate);
|
||||
#endif
|
||||
if (yyssp >= yysslim && yygrowstack())
|
||||
{
|
||||
goto yyoverflow;
|
||||
}
|
||||
*++yyssp = yystate;
|
||||
*++yyvsp = yyval;
|
||||
goto yyloop;
|
||||
yyoverflow:
|
||||
yyerror("yacc stack overflow");
|
||||
yyabort:
|
||||
if (yyss)
|
||||
free(yyss);
|
||||
if (yyvs)
|
||||
free(yyvs);
|
||||
yyss = yyssp = NULL;
|
||||
yyvs = yyvsp = NULL;
|
||||
yystacksize = 0;
|
||||
return (1);
|
||||
yyaccept:
|
||||
if (yyss)
|
||||
free(yyss);
|
||||
if (yyvs)
|
||||
free(yyvs);
|
||||
yyss = yyssp = NULL;
|
||||
yyvs = yyvsp = NULL;
|
||||
yystacksize = 0;
|
||||
return (0);
|
||||
}
|
||||
13
third_party/m4/parser.h
vendored
Normal file
13
third_party/m4/parser.h
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
#define NUMBER 257
|
||||
#define ERROR 258
|
||||
#define LOR 259
|
||||
#define LAND 260
|
||||
#define EQ 261
|
||||
#define NE 262
|
||||
#define LE 263
|
||||
#define GE 264
|
||||
#define LSHIFT 265
|
||||
#define RSHIFT 266
|
||||
#define EXPONENT 267
|
||||
#define UMINUS 268
|
||||
#define UPLUS 269
|
||||
81
third_party/m4/parser.y
vendored
Normal file
81
third_party/m4/parser.y
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
%{
|
||||
/* $OpenBSD: parser.y,v 1.7 2012/04/12 17:00:11 espie Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2004 Marc Espie <espie@cvs.openbsd.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
#define YYSTYPE int32_t
|
||||
extern int32_t end_result;
|
||||
extern int yylex(void);
|
||||
extern int yyerror(const char *);
|
||||
%}
|
||||
%token NUMBER
|
||||
%token ERROR
|
||||
%left LOR
|
||||
%left LAND
|
||||
%left '|'
|
||||
%left '^'
|
||||
%left '&'
|
||||
%left EQ NE
|
||||
%left '<' LE '>' GE
|
||||
%left LSHIFT RSHIFT
|
||||
%left '+' '-'
|
||||
%left '*' '/' '%'
|
||||
%right EXPONENT
|
||||
%right UMINUS UPLUS '!' '~'
|
||||
|
||||
%%
|
||||
|
||||
top : expr { end_result = $1; }
|
||||
;
|
||||
expr : expr '+' expr { $$ = $1 + $3; }
|
||||
| expr '-' expr { $$ = $1 - $3; }
|
||||
| expr EXPONENT expr { $$ = pow($1, $3); }
|
||||
| expr '*' expr { $$ = $1 * $3; }
|
||||
| expr '/' expr {
|
||||
if ($3 == 0) {
|
||||
yyerror("division by zero");
|
||||
exit(1);
|
||||
}
|
||||
$$ = $1 / $3;
|
||||
}
|
||||
| expr '%' expr {
|
||||
if ($3 == 0) {
|
||||
yyerror("modulo zero");
|
||||
exit(1);
|
||||
}
|
||||
$$ = $1 % $3;
|
||||
}
|
||||
| expr LSHIFT expr { $$ = $1 << $3; }
|
||||
| expr RSHIFT expr { $$ = $1 >> $3; }
|
||||
| expr '<' expr { $$ = $1 < $3; }
|
||||
| expr '>' expr { $$ = $1 > $3; }
|
||||
| expr LE expr { $$ = $1 <= $3; }
|
||||
| expr GE expr { $$ = $1 >= $3; }
|
||||
| expr EQ expr { $$ = $1 == $3; }
|
||||
| expr NE expr { $$ = $1 != $3; }
|
||||
| expr '&' expr { $$ = $1 & $3; }
|
||||
| expr '^' expr { $$ = $1 ^ $3; }
|
||||
| expr '|' expr { $$ = $1 | $3; }
|
||||
| expr LAND expr { $$ = $1 && $3; }
|
||||
| expr LOR expr { $$ = $1 || $3; }
|
||||
| '(' expr ')' { $$ = $2; }
|
||||
| '-' expr %prec UMINUS { $$ = -$2; }
|
||||
| '+' expr %prec UPLUS { $$ = $2; }
|
||||
| '!' expr { $$ = !$2; }
|
||||
| '~' expr { $$ = ~$2; }
|
||||
| NUMBER
|
||||
;
|
||||
%%
|
||||
|
||||
38
third_party/m4/pathnames.h
vendored
Normal file
38
third_party/m4/pathnames.h
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
/* $OpenBSD: pathnames.h,v 1.6 2015/11/03 16:21:47 deraadt Exp $ */
|
||||
/* $NetBSD: pathnames.h,v 1.6 1995/09/29 00:27:55 cgd Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1989, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Ozan Yigit at York University.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)pathnames.h 8.1 (Berkeley) 6/6/93
|
||||
*/
|
||||
|
||||
#define _PATH_DIVNAME "/tmp/m4.0XXXXXXXXXX" /* unix diversion files */
|
||||
55
third_party/m4/stdd.h
vendored
Normal file
55
third_party/m4/stdd.h
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
/* $OpenBSD: stdd.h,v 1.6 2010/09/07 19:58:09 marco Exp $ */
|
||||
/* $NetBSD: stdd.h,v 1.2 1995/09/28 05:37:50 tls Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Ozan Yigit at York University.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)stdd.h 8.1 (Berkeley) 6/6/93
|
||||
*/
|
||||
|
||||
/*
|
||||
* standard defines
|
||||
*/
|
||||
|
||||
/* #define max(a,b) ((a) > (b)? (a): (b)) */
|
||||
/* #define min(a,b) ((a) < (b)? (a): (b)) */
|
||||
|
||||
#define iswhite(c) ((c) == ' ' || (c) == '\t')
|
||||
|
||||
/*
|
||||
* STREQ is an optimised strcmp(a,b)==0
|
||||
* STREQN is an optimised strncmp(a,b,n)==0; assumes n > 0
|
||||
*/
|
||||
#define STREQ(a, b) ((a)[0] == (b)[0] && strcmp(a, b) == 0)
|
||||
#define STREQN(a, b, n) ((a)[0] == (b)[0] && strncmp(a, b, n) == 0)
|
||||
|
||||
#define YES 1
|
||||
#define NO 0
|
||||
1898
third_party/m4/tokenizer.c
vendored
Normal file
1898
third_party/m4/tokenizer.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
104
third_party/m4/tokenizer.l
vendored
Normal file
104
third_party/m4/tokenizer.l
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
%{
|
||||
/* $OpenBSD: tokenizer.l,v 1.10 2017/06/17 01:55:16 bcallah Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2004 Marc Espie <espie@cvs.openbsd.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
#include "third_party/m4/parser.h"
|
||||
|
||||
extern void m4_warnx(const char *, ...);
|
||||
extern int mimic_gnu;
|
||||
extern int32_t yylval;
|
||||
|
||||
int32_t number(void);
|
||||
int32_t parse_radix(void);
|
||||
%}
|
||||
|
||||
delim [ \t\n]
|
||||
ws {delim}+
|
||||
hex 0[xX][0-9a-fA-F]+
|
||||
oct 0[0-7]*
|
||||
dec [1-9][0-9]*
|
||||
radix 0[rR][0-9]+:[0-9a-zA-Z]+
|
||||
|
||||
%option noyywrap
|
||||
|
||||
%%
|
||||
{ws} {/* just skip it */}
|
||||
{hex}|{oct}|{dec} { yylval = number(); return(NUMBER); }
|
||||
{radix} { if (mimic_gnu) {
|
||||
yylval = parse_radix(); return(NUMBER);
|
||||
} else {
|
||||
return(ERROR);
|
||||
}
|
||||
}
|
||||
"<=" { return(LE); }
|
||||
">=" { return(GE); }
|
||||
"<<" { return(LSHIFT); }
|
||||
">>" { return(RSHIFT); }
|
||||
"==" { return(EQ); }
|
||||
"!=" { return(NE); }
|
||||
"&&" { return(LAND); }
|
||||
"||" { return(LOR); }
|
||||
"**" { if (mimic_gnu) { return (EXPONENT); } }
|
||||
. { return yytext[0]; }
|
||||
%%
|
||||
|
||||
int32_t
|
||||
number()
|
||||
{
|
||||
long l;
|
||||
|
||||
errno = 0;
|
||||
l = strtol(yytext, NULL, 0);
|
||||
if (((l == LONG_MAX || l == LONG_MIN) && errno == ERANGE) ||
|
||||
l > INT32_MAX || l < INT32_MIN)
|
||||
m4_warnx("numeric overflow in expr: %s", yytext);
|
||||
return l;
|
||||
}
|
||||
|
||||
int32_t
|
||||
parse_radix()
|
||||
{
|
||||
long base;
|
||||
char *next = NULL;
|
||||
long l;
|
||||
int d;
|
||||
|
||||
l = 0;
|
||||
base = strtol(yytext+2, &next, 0);
|
||||
if (base > 36 || next == NULL) {
|
||||
m4_warnx("error in number %s", yytext);
|
||||
} else {
|
||||
next++;
|
||||
while (*next != 0) {
|
||||
if (*next >= '0' && *next <= '9')
|
||||
d = *next - '0';
|
||||
else if (*next >= 'a' && *next <= 'z')
|
||||
d = *next - 'a' + 10;
|
||||
else {
|
||||
assert(*next >= 'A' && *next <= 'Z');
|
||||
d = *next - 'A' + 10;
|
||||
}
|
||||
if (d >= base) {
|
||||
m4_warnx("error in number %s", yytext);
|
||||
return 0;
|
||||
}
|
||||
l = base * l + d;
|
||||
next++;
|
||||
}
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
195
third_party/m4/trace.c
vendored
Normal file
195
third_party/m4/trace.c
vendored
Normal file
@@ -0,0 +1,195 @@
|
||||
/* clang-format off */
|
||||
/* $OpenBSD: trace.c,v 1.16 2010/09/07 19:58:09 marco Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2001 Marc Espie.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE OPENBSD PROJECT AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OPENBSD
|
||||
* PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "third_party/m4/mdef.h"
|
||||
#include "third_party/m4/stdd.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/log/bsd.h"
|
||||
#include "third_party/m4/extern.h"
|
||||
|
||||
FILE *traceout;
|
||||
|
||||
#define TRACE_ARGS 1
|
||||
#define TRACE_EXPANSION 2
|
||||
#define TRACE_QUOTE 4
|
||||
#define TRACE_FILENAME 8
|
||||
#define TRACE_LINENO 16
|
||||
#define TRACE_CONT 32
|
||||
#define TRACE_ID 64
|
||||
#define TRACE_NEWFILE 128 /* not implemented yet */
|
||||
#define TRACE_INPUT 256 /* not implemented yet */
|
||||
|
||||
static unsigned int letter_to_flag(int);
|
||||
static void print_header(struct input_file *);
|
||||
static int frame_level(void);
|
||||
|
||||
|
||||
unsigned int trace_flags = TRACE_QUOTE | TRACE_EXPANSION;
|
||||
|
||||
void
|
||||
trace_file(const char *name)
|
||||
{
|
||||
|
||||
if (traceout && traceout != stderr)
|
||||
fclose(traceout);
|
||||
traceout = fopen(name, "w");
|
||||
if (!traceout)
|
||||
err(1, "can't open %s", name);
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
letter_to_flag(int c)
|
||||
{
|
||||
switch(c) {
|
||||
case 'a':
|
||||
return TRACE_ARGS;
|
||||
case 'e':
|
||||
return TRACE_EXPANSION;
|
||||
case 'q':
|
||||
return TRACE_QUOTE;
|
||||
case 'c':
|
||||
return TRACE_CONT;
|
||||
case 'x':
|
||||
return TRACE_ID;
|
||||
case 'f':
|
||||
return TRACE_FILENAME;
|
||||
case 'l':
|
||||
return TRACE_LINENO;
|
||||
case 'p':
|
||||
return TRACE_NEWFILE;
|
||||
case 'i':
|
||||
return TRACE_INPUT;
|
||||
case 't':
|
||||
return TRACE_ALL;
|
||||
case 'V':
|
||||
return ~0;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
set_trace_flags(const char *s)
|
||||
{
|
||||
char mode = 0;
|
||||
unsigned int f = 0;
|
||||
|
||||
if (*s == '+' || *s == '-')
|
||||
mode = *s++;
|
||||
while (*s)
|
||||
f |= letter_to_flag(*s++);
|
||||
switch(mode) {
|
||||
case 0:
|
||||
trace_flags = f;
|
||||
break;
|
||||
case '+':
|
||||
trace_flags |= f;
|
||||
break;
|
||||
case '-':
|
||||
trace_flags &= ~f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
frame_level()
|
||||
{
|
||||
int level;
|
||||
int framep;
|
||||
|
||||
for (framep = fp, level = 0; framep != 0;
|
||||
level++,framep = mstack[framep-3].sfra)
|
||||
;
|
||||
return level;
|
||||
}
|
||||
|
||||
static void
|
||||
print_header(struct input_file *inp)
|
||||
{
|
||||
fprintf(traceout, "m4trace:");
|
||||
if (trace_flags & TRACE_FILENAME)
|
||||
fprintf(traceout, "%s:", inp->name);
|
||||
if (trace_flags & TRACE_LINENO)
|
||||
fprintf(traceout, "%lu:", inp->lineno);
|
||||
fprintf(traceout, " -%d- ", frame_level());
|
||||
if (trace_flags & TRACE_ID)
|
||||
fprintf(traceout, "id %lu: ", expansion_id);
|
||||
}
|
||||
|
||||
size_t
|
||||
trace(const char *argv[], int argc, struct input_file *inp)
|
||||
{
|
||||
if (!traceout)
|
||||
traceout = stderr;
|
||||
print_header(inp);
|
||||
if (trace_flags & TRACE_CONT) {
|
||||
fprintf(traceout, "%s ...\n", argv[1]);
|
||||
print_header(inp);
|
||||
}
|
||||
fprintf(traceout, "%s", argv[1]);
|
||||
if ((trace_flags & TRACE_ARGS) && argc > 2) {
|
||||
char delim[3];
|
||||
int i;
|
||||
|
||||
delim[0] = LPAREN;
|
||||
delim[1] = EOS;
|
||||
for (i = 2; i < argc; i++) {
|
||||
fprintf(traceout, "%s%s%s%s", delim,
|
||||
(trace_flags & TRACE_QUOTE) ? lquote : "",
|
||||
argv[i],
|
||||
(trace_flags & TRACE_QUOTE) ? rquote : "");
|
||||
delim[0] = COMMA;
|
||||
delim[1] = ' ';
|
||||
delim[2] = EOS;
|
||||
}
|
||||
fprintf(traceout, "%c", RPAREN);
|
||||
}
|
||||
if (trace_flags & TRACE_CONT) {
|
||||
fprintf(traceout, " -> ???\n");
|
||||
print_header(inp);
|
||||
fprintf(traceout, argc > 2 ? "%s(...)" : "%s", argv[1]);
|
||||
}
|
||||
if (trace_flags & TRACE_EXPANSION)
|
||||
return buffer_mark();
|
||||
else {
|
||||
fprintf(traceout, "\n");
|
||||
return SIZE_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
finish_trace(size_t mark)
|
||||
{
|
||||
fprintf(traceout, " -> ");
|
||||
if (trace_flags & TRACE_QUOTE)
|
||||
fprintf(traceout, "%s", lquote);
|
||||
dump_buffer(traceout, mark);
|
||||
if (trace_flags & TRACE_QUOTE)
|
||||
fprintf(traceout, "%s", rquote);
|
||||
fprintf(traceout, "\n");
|
||||
}
|
||||
Reference in New Issue
Block a user