Initial import

This commit is contained in:
Justine Tunney
2020-06-15 07:18:57 -07:00
commit c91b3c5006
14915 changed files with 590219 additions and 0 deletions

8
third_party/m4/COPYING vendored Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

37
third_party/m4/expr.c vendored Normal file
View 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
View 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
View 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
View 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(&macros, 10, &macro_info);
}
/*
* find name in the hash table
*/
ndptr
lookup(const char *name)
{
return ohash_find(&macros, ohash_qlookup(&macros, name));
}
struct macro_definition *
lookup_macro_definition(const char *name)
{
ndptr p;
p = ohash_find(&macros, ohash_qlookup(&macros, 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(&macros, name, &end);
n = ohash_find(&macros, i);
if (n == NULL) {
n = ohash_create_entry(&macro_info, name, &end);
ohash_insert(&macros, 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(&macros, &i); n != NULL;
n = ohash_next(&macros, &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(&macros, &i); p != NULL;
p = ohash_next(&macros, &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
View 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
View 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
View 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
View 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(&macros, ohash_qlookupi(&macros, 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

104
third_party/m4/tokenizer.l vendored Normal file
View 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
View 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");
}