Delete unused third party projects

This commit is contained in:
Justine Tunney 2020-12-19 13:49:39 -08:00
parent 113eeabd85
commit 04caf6f9ad
105 changed files with 0 additions and 66614 deletions

View file

@ -138,8 +138,6 @@ include libc/dns/dns.mk # │
include libc/crypto/crypto.mk # │
include net/http/http.mk #─┘
include third_party/lemon/lemon.mk
include third_party/linenoise/linenoise.mk
include third_party/editline/editline.mk
include third_party/duktape/duktape.mk
include third_party/regex/regex.mk
include third_party/avir/avir.mk
@ -148,10 +146,7 @@ include third_party/third_party.mk
include libc/testlib/testlib.mk
include tool/viz/lib/vizlib.mk
include examples/examples.mk
include third_party/lex/lex.mk
include third_party/m4/m4.mk
include third_party/lz4cli/lz4cli.mk
include third_party/bzip2/bzip2.mk
include tool/build/lib/buildlib.mk
include third_party/chibicc/chibicc.mk
include third_party/chibicc/test/test.mk

View file

@ -1,125 +0,0 @@
---
Language: Cpp
# BasedOnStyle: WebKit
AccessModifierOffset: -4
AlignAfterOpenBracket: DontAlign
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlines: Right
AlignOperands: false
AlignTrailingComments: false
AllowAllArgumentsOnNextLine: true
AllowAllConstructorInitializersOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: All
AllowShortLambdasOnASingleLine: All
AllowShortIfStatementsOnASingleLine: Never
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: MultiLine
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
AfterControlStatement: false
AfterEnum: false
AfterFunction: true
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: All
BreakBeforeBraces: WebKit
BreakBeforeInheritanceComma: false
BreakInheritanceList: BeforeColon
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeComma
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 80
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: false
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: false
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
Priority: 2
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
Priority: 3
- Regex: '.*'
Priority: 1
IncludeIsMainRegex: '(Test)?$'
IndentCaseLabels: false
IndentPPDirectives: None
IndentWidth: 4
IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: true
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: Inner
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 4
ObjCSpaceAfterProperty: true
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Right
ReflowComments: true
SortIncludes: true
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: true
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp11
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
TabWidth: 4
UseTab: Always
...

View file

@ -1,33 +0,0 @@
#-*-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:
# bzip2 is a compression format.
PKGS += THIRD_PARTY_BZIP2
THIRD_PARTY_BZIP2_BINS = \
o/$(MODE)/third_party/bzip2/µbunzip2.com \
o/$(MODE)/third_party/bzip2/µbunzip2.com.dbg
THIRD_PARTY_BZIP2_OBJS = \
o/$(MODE)/third_party/bzip2/µbunzip2.o
THIRD_PARTY_BZIP2_DEPS := $(call uniq, \
$(LIBC_STR) \
$(LIBC_STDIO))
$(THIRD_PARTY_BZIP2_OBJS): \
DEFAULT_CPPFLAGS += \
-DHAVE_CONFIG_H
o/$(MODE)/third_party/bzip2/µbunzip2.com.dbg: \
$(THIRD_PARTY_BZIP2_DEPS) \
$(THIRD_PARTY_BZIP2_OBJS) \
$(CRT) \
$(APE)
@$(APELINK)
$(THIRD_PARTY_BZIP2_OBJS): third_party/bzip2/bzip2.mk
.PHONY: o/$(MODE)/third_party/bzip2
o/$(MODE)/third_party/bzip2: $(THIRD_PARTY_BZIP2_BINS)

View file

@ -1,569 +0,0 @@
/* micro-bunzip, a small, simple bzip2 decompression implementation.
Copyright 2003 by Rob Landley (rob@landley.net).
Based on bzip2 decompression code by Julian R Seward (jseward@acm.org),
which also acknowledges contributions by Mike Burrows, David Wheeler,
Peter Fenwick, Alistair Moffat, Radford Neal, Ian H. Witten,
Robert Sedgewick, and Jon L. Bentley.
I hereby release this code under the GNU Library General Public License
(LGPL) version 2, available at http://www.gnu.org/copyleft/lgpl.html
*/
#include "libc/calls/calls.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/fileno.h"
/* Constants for huffman coding */
#define MAX_GROUPS 6
#define GROUP_SIZE 50 /* 64 would have been more efficient */
#define MAX_HUFCODE_BITS 20 /* Longest huffman code allowed */
#define MAX_SYMBOLS 258 /* 256 literals + RUNA + RUNB */
#define SYMBOL_RUNA 0
#define SYMBOL_RUNB 1
/* Status return values */
#define RETVAL_OK 0
#define RETVAL_LAST_BLOCK (-1)
#define RETVAL_NOT_BZIP_DATA (-2)
#define RETVAL_UNEXPECTED_INPUT_EOF (-3)
#define RETVAL_UNEXPECTED_OUTPUT_EOF (-4)
#define RETVAL_DATA_ERROR (-5)
#define RETVAL_OUT_OF_MEMORY (-6)
#define RETVAL_OBSOLETE_INPUT (-7)
/* Other housekeeping constants */
#define IOBUF_SIZE 4096
char *bunzip_errors[] = { NULL, "Bad file checksum", "Not bzip data",
"Unexpected input EOF", "Unexpected output EOF", "Data error",
"Out of memory", "Obsolete (pre 0.9.5) bzip format not supported." };
/* This is what we know about each huffman coding group */
struct group_data {
int limit[MAX_HUFCODE_BITS], base[MAX_HUFCODE_BITS], permute[MAX_SYMBOLS];
char minLen, maxLen;
};
/* Structure holding all the housekeeping data, including IO buffers and
memory that persists between calls to bunzip */
typedef struct {
/* For I/O error handling */
jmp_buf jmpbuf;
/* Input stream, input buffer, input bit buffer */
int64_t in_fd, inbufCount, inbufPos;
unsigned char *inbuf;
unsigned int inbufBitCount, inbufBits;
/* Output buffer */
char outbuf[IOBUF_SIZE];
int outbufPos;
/* The CRC values stored in the block header and calculated from the data */
unsigned int crc32Table[256], headerCRC, dataCRC, totalCRC;
/* Intermediate buffer and its size (in bytes) */
unsigned int *dbuf, dbufSize;
/* State for interrupting output loop */
int writePos, writeRun, writeCount, writeCurrent;
/* These things are a bit too big to go on the stack */
unsigned char selectors[32768]; /* nSelectors=15 bits */
struct group_data groups[MAX_GROUPS]; /* huffman coding tables */
} bunzip_data;
/* Return the next nnn bits of input. All reads from the compressed
input are done through this function. All reads are big endian */
static unsigned int get_bits(bunzip_data *bd, char bits_wanted)
{
unsigned int bits = 0;
/* If we need to get more data from the byte buffer, do so. (Loop
getting one byte at a time to enforce endianness and avoid
unaligned access.) */
while (bd->inbufBitCount < bits_wanted) {
/* If we need to read more data from file into byte buffer, do so */
if (bd->inbufPos == bd->inbufCount) {
if (!(bd->inbufCount = read(bd->in_fd, bd->inbuf, IOBUF_SIZE)))
longjmp(bd->jmpbuf, RETVAL_UNEXPECTED_INPUT_EOF);
bd->inbufPos = 0;
}
/* Avoid 32-bit overflow (dump bit buffer to top of output) */
if (bd->inbufBitCount >= 24) {
bits = bd->inbufBits & ((1u << bd->inbufBitCount) - 1);
bits_wanted -= bd->inbufBitCount;
bits <<= bits_wanted;
bd->inbufBitCount = 0;
}
/* Grab next 8 bits of input from buffer. */
bd->inbufBits = (bd->inbufBits << 8) | bd->inbuf[bd->inbufPos++];
bd->inbufBitCount += 8;
}
/* Calculate result */
bd->inbufBitCount -= bits_wanted;
bits |= (bd->inbufBits >> bd->inbufBitCount) & ((1u << bits_wanted) - 1);
return bits;
}
/* Decompress a block of text to into intermediate buffer */
static int read_bunzip_data(bunzip_data *bd)
{
struct group_data *hufGroup;
int dbufCount, nextSym, dbufSize, origPtr, groupCount, *base, *limit,
selector, i, j, k, t, runPos, symCount, symTotal, nSelectors,
byteCount[256];
unsigned char uc, symToByte[256], mtfSymbol[256], *selectors;
unsigned int *dbuf;
/* Read in header signature (borrowing mtfSymbol for temp space). */
for (i = 0; i < 6; i++)
mtfSymbol[i] = get_bits(bd, 8);
mtfSymbol[6] = 0;
/* Read CRC (which is stored big endian). */
bd->headerCRC = get_bits(bd, 32);
/* Is this the last block (with CRC for file)? */
if (!strcmp((char *)mtfSymbol, "\x17\x72\x45\x38\x50\x90"))
return RETVAL_LAST_BLOCK;
/* If it's not a valid data block, barf. */
if (strcmp((char *)mtfSymbol, "\x31\x41\x59\x26\x53\x59"))
return RETVAL_NOT_BZIP_DATA;
dbuf = bd->dbuf;
dbufSize = bd->dbufSize;
selectors = bd->selectors;
/* We can add support for blockRandomised if anybody complains.
There was some code for this in busybox 1.0.0-pre3, but nobody
ever noticed that it didn't actually work. */
if (get_bits(bd, 1))
return RETVAL_OBSOLETE_INPUT;
if ((origPtr = get_bits(bd, 24)) > dbufSize)
return RETVAL_DATA_ERROR;
/* mapping table: if some byte values are never used (encoding
things like ascii text), the compression code removes the gaps to
have fewer symbols to deal with, and writes a sparse bitfield
indicating which values were present. We make a translation table
to convert the symbols back to the corresponding bytes. */
t = get_bits(bd, 16);
memset(symToByte, 0, 256);
symTotal = 0;
for (i = 0; i < 16; i++) {
if (t & (1u << (15 - i))) {
k = get_bits(bd, 16);
for (j = 0; j < 16; j++)
if (k & (1u << (15 - j)))
symToByte[symTotal++] = (16 * i) + j;
}
}
/* How many different huffman coding groups does this block use? */
groupCount = get_bits(bd, 3);
if (groupCount < 2 || groupCount > MAX_GROUPS)
return RETVAL_DATA_ERROR;
/* nSelectors: Every GROUP_SIZE many symbols we select a new huffman
coding group. Read in the group selector list, which is stored as
MTF encoded bit runs. */
if (!(nSelectors = get_bits(bd, 15)))
return RETVAL_DATA_ERROR;
for (i = 0; i < groupCount; i++)
mtfSymbol[i] = i;
for (i = 0; i < nSelectors; i++) {
/* Get next value */
for (j = 0; get_bits(bd, 1); j++)
if (j >= groupCount)
return RETVAL_DATA_ERROR;
/* Decode MTF to get the next selector */
uc = mtfSymbol[j];
memmove(mtfSymbol + 1, mtfSymbol, j);
mtfSymbol[0] = selectors[i] = uc;
}
/* Read the huffman coding tables for each group, which code for symTotal
literal symbols, plus two run symbols (RUNA, RUNB) */
symCount = symTotal + 2;
for (j = 0; j < groupCount; j++) {
unsigned char length[MAX_SYMBOLS], temp[MAX_HUFCODE_BITS + 1];
int minLen, maxLen, pp;
/* Read lengths */
t = get_bits(bd, 5);
for (i = 0; i < symCount; i++) {
for (;;) {
if (t < 1 || t > MAX_HUFCODE_BITS)
return RETVAL_DATA_ERROR;
if (!get_bits(bd, 1))
break;
if (!get_bits(bd, 1))
t++;
else
t--;
}
length[i] = t;
}
/* Find largest and smallest lengths in this group */
minLen = maxLen = length[0];
for (i = 1; i < symCount; i++) {
if (length[i] > maxLen)
maxLen = length[i];
else if (length[i] < minLen)
minLen = length[i];
}
/* Calculate permute[], base[], and limit[] tables from length[].
*
* permute[] is the lookup table for converting huffman coded symbols
* into decoded symbols. base[] is the amount to subtract from the
* value of a huffman symbol of a given length when using permute[].
*
* limit[] indicates the largest numerical value a symbol with a given
* number of bits can have. It lets us know when to stop reading.
*
* To use these, keep reading bits until value<=limit[bitcount] or
* you've read over 20 bits (error). Then the decoded symbol
* equals permute[hufcode_value-base[hufcode_bitcount]].
*/
hufGroup = bd->groups + j;
hufGroup->minLen = minLen;
hufGroup->maxLen = maxLen;
/* Note that minLen can't be smaller than 1, so we adjust the
base and limit array pointers so we're not always wasting the
first entry. We do this again when using them (during symbol
decoding).*/
base = hufGroup->base - 1;
limit = hufGroup->limit - 1;
/* Calculate permute[] */
pp = 0;
for (i = minLen; i <= maxLen; i++)
for (t = 0; t < symCount; t++)
if (length[t] == i)
hufGroup->permute[pp++] = t;
/* Count cumulative symbols coded for at each bit length */
for (i = minLen; i <= maxLen; i++)
temp[i] = limit[i] = 0;
for (i = 0; i < symCount; i++)
temp[length[i]]++;
/* Calculate limit[] (the largest symbol-coding value at each
bit length, which is (previous limit<<1)+symbols at this
level), and base[] (number of symbols to ignore at each bit
length, which is limit-cumulative count of symbols coded for
already). */
pp = t = 0;
for (i = minLen; i < maxLen; i++) {
pp += temp[i];
limit[i] = pp - 1;
pp <<= 1;
base[i + 1] = pp - (t += temp[i]);
}
limit[maxLen] = pp + temp[maxLen] - 1;
base[minLen] = 0;
}
/* We've finished reading and digesting the block header. Now read this
block's huffman coded symbols from the file and undo the huffman
coding and run length encoding, saving the result into
dbuf[dbufCount++]=uc */
/* Initialize symbol occurrence counters and symbol mtf table */
memset(byteCount, 0, 256 * sizeof(int));
for (i = 0; i < 256; i++)
mtfSymbol[i] = (unsigned char)i;
/* Loop through compressed symbols */
runPos = dbufCount = symCount = selector = 0;
for (;;) {
/* Determine which huffman coding group to use. */
if (!(symCount--)) {
symCount = GROUP_SIZE - 1;
if (selector >= nSelectors)
return RETVAL_DATA_ERROR;
hufGroup = bd->groups + selectors[selector++];
base = hufGroup->base - 1;
limit = hufGroup->limit - 1;
}
/* Read next huffman-coded symbol */
i = hufGroup->minLen;
j = get_bits(bd, i);
for (;;) {
if (i > hufGroup->maxLen)
return RETVAL_DATA_ERROR;
if (j <= limit[i])
break;
i++;
j = (j << 1) | get_bits(bd, 1);
}
/* Huffman decode nextSym (with bounds checking) */
j -= base[i];
if (j < 0 || j >= MAX_SYMBOLS)
return RETVAL_DATA_ERROR;
nextSym = hufGroup->permute[j];
/* If this is a repeated run, loop collecting data */
if (nextSym == SYMBOL_RUNA || nextSym == SYMBOL_RUNB) {
/* If this is the start of a new run, zero out counter */
if (!runPos) {
runPos = 1;
t = 0;
}
/* Neat trick that saves 1 symbol: instead of or-ing 0 or 1
at each bit position, add 1 or 2 instead. For example,
1011 is 1<<0 + 1<<1 + 2<<2. 1010 is 2<<0 + 2<<1 + 1<<2.
You can make any bit pattern that way using 1 less symbol
than the basic or 0/1 method (except all bits 0, which
would use no symbols, but a run of length 0 doesn't mean
anything in this context). Thus space is saved. */
if (nextSym == SYMBOL_RUNA)
t += runPos;
else
t += 2 * runPos;
runPos <<= 1;
continue;
}
/* When we hit the first non-run symbol after a run, we now know
how many times to repeat the last literal, so append that
many copies to our buffer of decoded symbols (dbuf) now. (The
last literal used is the one at the head of the mtfSymbol
array.) */
if (runPos) {
runPos = 0;
if (dbufCount + t >= dbufSize)
return RETVAL_DATA_ERROR;
uc = symToByte[mtfSymbol[0]];
byteCount[uc] += t;
while (t--)
dbuf[dbufCount++] = uc;
}
/* Is this the terminating symbol? */
if (nextSym > symTotal)
break;
/* At this point, the symbol we just decoded indicates a new
literal character. Subtract one to get the position in the
MTF array at which this literal is currently to be found.
(Note that the result can't be -1 or 0, because 0 and 1 are
RUNA and RUNB. Another instance of the first symbol in the
mtf array, position 0, would have been handled as part of a
run.) */
if (dbufCount >= dbufSize)
return RETVAL_DATA_ERROR;
i = nextSym - 1;
uc = mtfSymbol[i];
memmove(mtfSymbol + 1, mtfSymbol, i);
mtfSymbol[0] = uc;
uc = symToByte[uc];
/* We have our literal byte. Save it into dbuf. */
byteCount[uc]++;
dbuf[dbufCount++] = (unsigned int)uc;
}
/* At this point, we've finished reading huffman-coded symbols and
compressed runs from the input stream. There are dbufCount many
of them in dbuf[]. Now undo the Burrows-Wheeler transform on
dbuf. See http://dogma.net/markn/articles/bwt/bwt.htm */
/* Now we know what dbufCount is, do a better sanity check on origPtr. */
if (origPtr < 0 || origPtr >= dbufCount)
return RETVAL_DATA_ERROR;
/* Turn byteCount into cumulative occurrence counts of 0 to n-1. */
j = 0;
for (i = 0; i < 256; i++) {
k = j + byteCount[i];
byteCount[i] = j;
j = k;
}
/* Figure out what order dbuf would be in if we sorted it. */
for (i = 0; i < dbufCount; i++) {
uc = (unsigned char)(dbuf[i] & 0xff);
dbuf[byteCount[uc]] |= (i << 8);
byteCount[uc]++;
}
/* blockRandomised support would go here. */
/* Using i as position, j as previous character, t as current character,
and uc as run count */
bd->dataCRC = 0xffffffffL;
/* Decode first byte by hand to initialize "previous" byte. Note
that it doesn't get output, and if the first three characters are
identical it doesn't qualify as a run (hence uc=255, which will
either wrap to 1 or get reset). */
if (dbufCount) {
bd->writePos = dbuf[origPtr];
bd->writeCurrent = (unsigned char)(bd->writePos & 0xff);
bd->writePos >>= 8;
bd->writeRun = -1;
}
bd->writeCount = dbufCount;
return RETVAL_OK;
}
/* Flush output buffer to disk */
static void flush_bunzip_outbuf(bunzip_data *bd, int64_t out_fd)
{
if (bd->outbufPos) {
if (write(out_fd, bd->outbuf, bd->outbufPos) != bd->outbufPos)
longjmp(bd->jmpbuf, RETVAL_UNEXPECTED_OUTPUT_EOF);
bd->outbufPos = 0;
}
}
/* Undo burrows-wheeler transform on intermediate buffer to produce output.
If !len, write up to len bytes of data to buf. Otherwise write to out_fd.
Returns len ? bytes written : RETVAL_OK. Notice all errors negative #'s. */
static int write_bunzip_data(
bunzip_data *bd, int64_t out_fd, char *outbuf, int len)
{
unsigned int *dbuf = bd->dbuf;
int count, pos, current, run, copies, outbyte, previous, gotcount = 0;
for (;;) {
/* If last read was short due to end of file, return last block now */
if (bd->writeCount < 0)
return bd->writeCount;
/* If we need to refill dbuf, do it. */
if (!bd->writeCount) {
int i = read_bunzip_data(bd);
if (i) {
if (i == RETVAL_LAST_BLOCK) {
bd->writeCount = i;
return gotcount;
} else
return i;
}
}
/* Loop generating output */
count = bd->writeCount;
pos = bd->writePos;
current = bd->writeCurrent;
run = bd->writeRun;
while (count) {
/* If somebody (like busybox tar) wants a certain number of
bytes of data from memory instead of written to a file,
humor them */
if (len && bd->outbufPos >= len)
goto dataus_interruptus;
count--;
/* Follow sequence vector to undo Burrows-Wheeler transform */
previous = current;
pos = dbuf[pos];
current = pos & 0xff;
pos >>= 8;
/* Whenever we see 3 consecutive copies of the same byte,
the 4th is a repeat count */
if (run++ == 3) {
copies = current;
outbyte = previous;
current = -1;
} else {
copies = 1;
outbyte = current;
}
/* Output bytes to buffer, flushing to file if necessary */
while (copies--) {
if (bd->outbufPos == IOBUF_SIZE)
flush_bunzip_outbuf(bd, out_fd);
bd->outbuf[bd->outbufPos++] = outbyte;
bd->dataCRC = (bd->dataCRC << 8)
^ bd->crc32Table[(bd->dataCRC >> 24) ^ outbyte];
}
if (current != previous)
run = 0;
}
/* Decompression of this block completed successfully */
bd->dataCRC = ~(bd->dataCRC);
bd->totalCRC
= ((bd->totalCRC << 1) | (bd->totalCRC >> 31)) ^ bd->dataCRC;
/* If this block had a CRC error, force file level CRC error. */
if (bd->dataCRC != bd->headerCRC) {
bd->totalCRC = bd->headerCRC + 1;
return RETVAL_LAST_BLOCK;
}
dataus_interruptus:
bd->writeCount = count;
if (len) {
gotcount += bd->outbufPos;
memcpy(outbuf, bd->outbuf, len);
/* If we got enough data, checkpoint loop state and return */
if ((len -= bd->outbufPos) < 1) {
bd->outbufPos -= len;
if (bd->outbufPos)
memmove(bd->outbuf, bd->outbuf + len, bd->outbufPos);
bd->writePos = pos;
bd->writeCurrent = current;
bd->writeRun = run;
return gotcount;
}
}
}
}
/* Allocate the structure, read file header. If !len, src_fd contains
filehandle to read from. Else inbuf contains data. */
static int start_bunzip(bunzip_data **bdp, int64_t src_fd, char *inbuf, int len)
{
bunzip_data *bd;
unsigned int i, j, c;
/* Figure out how much data to allocate */
i = sizeof(bunzip_data);
if (!len)
i += IOBUF_SIZE;
/* Allocate bunzip_data. Most fields initialize to zero. */
if (!(bd = *bdp = malloc(i)))
return RETVAL_OUT_OF_MEMORY;
memset(bd, 0, sizeof(bunzip_data));
if (len) {
bd->inbuf = (unsigned char *)inbuf;
bd->inbufCount = len;
bd->in_fd = -1;
} else {
bd->inbuf = (unsigned char *)(bd + 1);
bd->in_fd = src_fd;
}
/* Init the CRC32 table (big endian) */
for (i = 0; i < 256; i++) {
c = i << 24;
for (j = 8; j; j--)
c = c & 0x80000000 ? (c << 1) ^ 0x04c11db7 : (c << 1);
bd->crc32Table[i] = c;
}
/* Setup for I/O error handling via longjmp */
i = setjmp(bd->jmpbuf);
if (i)
return i;
/* Ensure that file starts with "BZh" */
for (i = 0; i < 3; i++)
if (get_bits(bd, 8) != "BZh"[i])
return RETVAL_NOT_BZIP_DATA;
/* Next byte ascii '1'-'9', indicates block size in units of 100k of
uncompressed data. Allocate intermediate buffer for block. */
i = get_bits(bd, 8);
if (i < '1' || i > '9')
return RETVAL_NOT_BZIP_DATA;
bd->dbufSize = 100000 * (i - '0');
if (!(bd->dbuf = malloc(bd->dbufSize * sizeof(int))))
return RETVAL_OUT_OF_MEMORY;
return RETVAL_OK;
}
/* Example usage: decompress src_fd to dst_fd. (Stops at end of bzip data,
not end of file.) */
static char *uncompressStream(int64_t src_fd, int64_t dst_fd)
{
bunzip_data *bd;
int i;
if (!(i = start_bunzip(&bd, src_fd, 0, 0))) {
i = write_bunzip_data(bd, dst_fd, 0, 0);
if (i == RETVAL_LAST_BLOCK && bd->headerCRC == bd->totalCRC)
i = RETVAL_OK;
}
flush_bunzip_outbuf(bd, dst_fd);
if (bd->dbuf)
free(bd->dbuf);
free(bd);
return bunzip_errors[-i];
}
int main(int argc, char *argv[])
{
char *err;
if (!(err = uncompressStream(STDIN_FILENO, STDOUT_FILENO))) {
return 0;
} else {
fprintf(stderr, "\n%s\n", err);
return 1;
}
}

View file

@ -1,26 +0,0 @@
Copyright 2006-2011, the V8 project authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* 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.
* Neither the name of Google Inc. 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 COPYRIGHT HOLDERS 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 COPYRIGHT
OWNER 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.

View file

@ -1 +0,0 @@
google/double-conversion@1dce44c4313a6f356fcfa4b3e8887f037ac0bf23

View file

@ -1,621 +0,0 @@
// Copyright 2010 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * 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.
// * Neither the name of Google Inc. 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 COPYRIGHT HOLDERS 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 COPYRIGHT
// OWNER 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 "libc/macros.h"
#include "libc/math.h"
#include "third_party/double-conversion/bignum-dtoa.h"
#include "third_party/double-conversion/bignum.h"
#include "third_party/double-conversion/ieee.h"
asm(".ident\t\"\\n\\n\
double-conversion (BSD-3)\\n\
Copyright 2010 the V8 project authors\"");
asm(".include \"libc/disclaimer.inc\"");
namespace double_conversion {
static int NormalizedExponent(uint64_t significand, int exponent) {
DOUBLE_CONVERSION_ASSERT(significand != 0);
while ((significand & Double::kHiddenBit) == 0) {
significand = significand << 1;
exponent = exponent - 1;
}
return exponent;
}
// Forward declarations:
// Returns an estimation of k such that 10^(k-1) <= v < 10^k.
static int EstimatePower(int exponent);
// Computes v / 10^estimated_power exactly, as a ratio of two bignums, numerator
// and denominator.
static void InitialScaledStartValues(uint64_t significand, int exponent,
bool lower_boundary_is_closer,
int estimated_power,
bool need_boundary_deltas,
Bignum* numerator, Bignum* denominator,
Bignum* delta_minus, Bignum* delta_plus);
// Multiplies numerator/denominator so that its values lies in the range 1-10.
// Returns decimal_point s.t.
// v = numerator'/denominator' * 10^(decimal_point-1)
// where numerator' and denominator' are the values of numerator and
// denominator after the call to this function.
static void FixupMultiply10(int estimated_power, bool is_even,
int* decimal_point, Bignum* numerator,
Bignum* denominator, Bignum* delta_minus,
Bignum* delta_plus);
// Generates digits from the left to the right and stops when the generated
// digits yield the shortest decimal representation of v.
static void GenerateShortestDigits(Bignum* numerator, Bignum* denominator,
Bignum* delta_minus, Bignum* delta_plus,
bool is_even, Vector<char> buffer,
int* length);
// Generates 'requested_digits' after the decimal point.
static void BignumToFixed(int requested_digits, int* decimal_point,
Bignum* numerator, Bignum* denominator,
Vector<char> buffer, int* length);
// Generates 'count' digits of numerator/denominator.
// Once 'count' digits have been produced rounds the result depending on the
// remainder (remainders of exactly .5 round upwards). Might update the
// decimal_point when rounding up (for example for 0.9999).
static void GenerateCountedDigits(int count, int* decimal_point,
Bignum* numerator, Bignum* denominator,
Vector<char> buffer, int* length);
void BignumDtoa(double v, BignumDtoaMode mode, int requested_digits,
Vector<char> buffer, int* length, int* decimal_point) {
DOUBLE_CONVERSION_ASSERT(v > 0);
DOUBLE_CONVERSION_ASSERT(!Double(v).IsSpecial());
uint64_t significand;
int exponent;
bool lower_boundary_is_closer;
if (mode == BIGNUM_DTOA_SHORTEST_SINGLE) {
float f = static_cast<float>(v);
DOUBLE_CONVERSION_ASSERT(f == v);
significand = Single(f).Significand();
exponent = Single(f).Exponent();
lower_boundary_is_closer = Single(f).LowerBoundaryIsCloser();
} else {
significand = Double(v).Significand();
exponent = Double(v).Exponent();
lower_boundary_is_closer = Double(v).LowerBoundaryIsCloser();
}
bool need_boundary_deltas =
(mode == BIGNUM_DTOA_SHORTEST || mode == BIGNUM_DTOA_SHORTEST_SINGLE);
bool is_even = (significand & 1) == 0;
int normalized_exponent = NormalizedExponent(significand, exponent);
// estimated_power might be too low by 1.
int estimated_power = EstimatePower(normalized_exponent);
// Shortcut for Fixed.
// The requested digits correspond to the digits after the point. If the
// number is much too small, then there is no need in trying to get any
// digits.
if (mode == BIGNUM_DTOA_FIXED && -estimated_power - 1 > requested_digits) {
buffer[0] = '\0';
*length = 0;
// Set decimal-point to -requested_digits. This is what Gay does.
// Note that it should not have any effect anyways since the string is
// empty.
*decimal_point = -requested_digits;
return;
}
Bignum numerator;
Bignum denominator;
Bignum delta_minus;
Bignum delta_plus;
// Make sure the bignum can grow large enough. The smallest double equals
// 4e-324. In this case the denominator needs fewer than 324*4 binary digits.
// The maximum double is 1.7976931348623157e308 which needs fewer than
// 308*4 binary digits.
DOUBLE_CONVERSION_ASSERT(Bignum::kMaxSignificantBits >= 324 * 4);
InitialScaledStartValues(significand, exponent, lower_boundary_is_closer,
estimated_power, need_boundary_deltas, &numerator,
&denominator, &delta_minus, &delta_plus);
// We now have v = (numerator / denominator) * 10^estimated_power.
FixupMultiply10(estimated_power, is_even, decimal_point, &numerator,
&denominator, &delta_minus, &delta_plus);
// We now have v = (numerator / denominator) * 10^(decimal_point-1), and
// 1 <= (numerator + delta_plus) / denominator < 10
switch (mode) {
case BIGNUM_DTOA_SHORTEST:
case BIGNUM_DTOA_SHORTEST_SINGLE:
GenerateShortestDigits(&numerator, &denominator, &delta_minus,
&delta_plus, is_even, buffer, length);
break;
case BIGNUM_DTOA_FIXED:
BignumToFixed(requested_digits, decimal_point, &numerator, &denominator,
buffer, length);
break;
case BIGNUM_DTOA_PRECISION:
GenerateCountedDigits(requested_digits, decimal_point, &numerator,
&denominator, buffer, length);
break;
default:
DOUBLE_CONVERSION_UNREACHABLE();
}
buffer[*length] = '\0';
}
// The procedure starts generating digits from the left to the right and stops
// when the generated digits yield the shortest decimal representation of v. A
// decimal representation of v is a number lying closer to v than to any other
// double, so it converts to v when read.
//
// This is true if d, the decimal representation, is between m- and m+, the
// upper and lower boundaries. d must be strictly between them if !is_even.
// m- := (numerator - delta_minus) / denominator
// m+ := (numerator + delta_plus) / denominator
//
// Precondition: 0 <= (numerator+delta_plus) / denominator < 10.
// If 1 <= (numerator+delta_plus) / denominator < 10 then no leading 0 digit
// will be produced. This should be the standard precondition.
static void GenerateShortestDigits(Bignum* numerator, Bignum* denominator,
Bignum* delta_minus, Bignum* delta_plus,
bool is_even, Vector<char> buffer,
int* length) {
// Small optimization: if delta_minus and delta_plus are the same just reuse
// one of the two bignums.
if (Bignum::Equal(*delta_minus, *delta_plus)) {
delta_plus = delta_minus;
}
*length = 0;
for (;;) {
uint16_t digit;
digit = numerator->DivideModuloIntBignum(*denominator);
DOUBLE_CONVERSION_ASSERT(
digit <= 9); // digit is a uint16_t and therefore always positive.
// digit = numerator / denominator (integer division).
// numerator = numerator % denominator.
buffer[(*length)++] = static_cast<char>(digit + '0');
// Can we stop already?
// If the remainder of the division is less than the distance to the lower
// boundary we can stop. In this case we simply round down (discarding the
// remainder).
// Similarly we test if we can round up (using the upper boundary).
bool in_delta_room_minus;
bool in_delta_room_plus;
if (is_even) {
in_delta_room_minus = Bignum::LessEqual(*numerator, *delta_minus);
} else {
in_delta_room_minus = Bignum::Less(*numerator, *delta_minus);
}
if (is_even) {
in_delta_room_plus =
Bignum::PlusCompare(*numerator, *delta_plus, *denominator) >= 0;
} else {
in_delta_room_plus =
Bignum::PlusCompare(*numerator, *delta_plus, *denominator) > 0;
}
if (!in_delta_room_minus && !in_delta_room_plus) {
// Prepare for next iteration.
numerator->Times10();
delta_minus->Times10();
// We optimized delta_plus to be equal to delta_minus (if they share the
// same value). So don't multiply delta_plus if they point to the same
// object.
if (delta_minus != delta_plus) {
delta_plus->Times10();
}
} else if (in_delta_room_minus && in_delta_room_plus) {
// Let's see if 2*numerator < denominator.
// If yes, then the next digit would be < 5 and we can round down.
int compare = Bignum::PlusCompare(*numerator, *numerator, *denominator);
if (compare < 0) {
// Remaining digits are less than .5. -> Round down (== do nothing).
} else if (compare > 0) {
// Remaining digits are more than .5 of denominator. -> Round up.
// Note that the last digit could not be a '9' as otherwise the whole
// loop would have stopped earlier.
// We still have an assert here in case the preconditions were not
// satisfied.
DOUBLE_CONVERSION_ASSERT(buffer[(*length) - 1] != '9');
buffer[(*length) - 1]++;
} else {
// Halfway case.
// TODO(floitsch): need a way to solve half-way cases.
// For now let's round towards even (since this is what Gay seems to
// do).
if ((buffer[(*length) - 1] - '0') % 2 == 0) {
// Round down => Do nothing.
} else {
DOUBLE_CONVERSION_ASSERT(buffer[(*length) - 1] != '9');
buffer[(*length) - 1]++;
}
}
return;
} else if (in_delta_room_minus) {
// Round down (== do nothing).
return;
} else { // in_delta_room_plus
// Round up.
// Note again that the last digit could not be '9' since this would have
// stopped the loop earlier.
// We still have an DOUBLE_CONVERSION_ASSERT here, in case the
// preconditions were not satisfied.
DOUBLE_CONVERSION_ASSERT(buffer[(*length) - 1] != '9');
buffer[(*length) - 1]++;
return;
}
}
}
// Let v = numerator / denominator < 10.
// Then we generate 'count' digits of d = x.xxxxx... (without the decimal point)
// from left to right. Once 'count' digits have been produced we decide wether
// to round up or down. Remainders of exactly .5 round upwards. Numbers such
// as 9.999999 propagate a carry all the way, and change the
// exponent (decimal_point), when rounding upwards.
static void GenerateCountedDigits(int count, int* decimal_point,
Bignum* numerator, Bignum* denominator,
Vector<char> buffer, int* length) {
DOUBLE_CONVERSION_ASSERT(count >= 0);
for (int i = 0; i < count - 1; ++i) {
uint16_t digit;
digit = numerator->DivideModuloIntBignum(*denominator);
DOUBLE_CONVERSION_ASSERT(
digit <= 9); // digit is a uint16_t and therefore always positive.
// digit = numerator / denominator (integer division).
// numerator = numerator % denominator.
buffer[i] = static_cast<char>(digit + '0');
// Prepare for next iteration.
numerator->Times10();
}
// Generate the last digit.
uint16_t digit;
digit = numerator->DivideModuloIntBignum(*denominator);
if (Bignum::PlusCompare(*numerator, *numerator, *denominator) >= 0) {
digit++;
}
DOUBLE_CONVERSION_ASSERT(digit <= 10);
buffer[count - 1] = static_cast<char>(digit + '0');
// Correct bad digits (in case we had a sequence of '9's). Propagate the
// carry until we hat a non-'9' or til we reach the first digit.
for (int i = count - 1; i > 0; --i) {
if (buffer[i] != '0' + 10) break;
buffer[i] = '0';
buffer[i - 1]++;
}
if (buffer[0] == '0' + 10) {
// Propagate a carry past the top place.
buffer[0] = '1';
(*decimal_point)++;
}
*length = count;
}
// Generates 'requested_digits' after the decimal point. It might omit
// trailing '0's. If the input number is too small then no digits at all are
// generated (ex.: 2 fixed digits for 0.00001).
//
// Input verifies: 1 <= (numerator + delta) / denominator < 10.
static void BignumToFixed(int requested_digits, int* decimal_point,
Bignum* numerator, Bignum* denominator,
Vector<char> buffer, int* length) {
// Note that we have to look at more than just the requested_digits, since
// a number could be rounded up. Example: v=0.5 with requested_digits=0.
// Even though the power of v equals 0 we can't just stop here.
if (-(*decimal_point) > requested_digits) {
// The number is definitively too small.
// Ex: 0.001 with requested_digits == 1.
// Set decimal-point to -requested_digits. This is what Gay does.
// Note that it should not have any effect anyways since the string is
// empty.
*decimal_point = -requested_digits;
*length = 0;
return;
} else if (-(*decimal_point) == requested_digits) {
// We only need to verify if the number rounds down or up.
// Ex: 0.04 and 0.06 with requested_digits == 1.
DOUBLE_CONVERSION_ASSERT(*decimal_point == -requested_digits);
// Initially the fraction lies in range (1, 10]. Multiply the denominator
// by 10 so that we can compare more easily.
denominator->Times10();
if (Bignum::PlusCompare(*numerator, *numerator, *denominator) >= 0) {
// If the fraction is >= 0.5 then we have to include the rounded
// digit.
buffer[0] = '1';
*length = 1;
(*decimal_point)++;
} else {
// Note that we caught most of similar cases earlier.
*length = 0;
}
return;
} else {
// The requested digits correspond to the digits after the point.
// The variable 'needed_digits' includes the digits before the point.
int needed_digits = (*decimal_point) + requested_digits;
GenerateCountedDigits(needed_digits, decimal_point, numerator, denominator,
buffer, length);
}
}
// Returns an estimation of k such that 10^(k-1) <= v < 10^k where
// v = f * 2^exponent and 2^52 <= f < 2^53.
// v is hence a normalized double with the given exponent. The output is an
// approximation for the exponent of the decimal approimation .digits * 10^k.
//
// The result might undershoot by 1 in which case 10^k <= v < 10^k+1.
// Note: this property holds for v's upper boundary m+ too.
// 10^k <= m+ < 10^k+1.
// (see explanation below).
//
// Examples:
// EstimatePower(0) => 16
// EstimatePower(-52) => 0
//
// Note: e >= 0 => EstimatedPower(e) > 0. No similar claim can be made for e<0.
static int EstimatePower(int exponent) {
// This function estimates log10 of v where v = f*2^e (with e == exponent).
// Note that 10^floor(log10(v)) <= v, but v <= 10^ceil(log10(v)).
// Note that f is bounded by its container size. Let p = 53 (the double's
// significand size). Then 2^(p-1) <= f < 2^p.
//
// Given that log10(v) == log2(v)/log2(10) and e+(len(f)-1) is quite close
// to log2(v) the function is simplified to (e+(len(f)-1)/log2(10)).
// The computed number undershoots by less than 0.631 (when we compute log3
// and not log10).
//
// Optimization: since we only need an approximated result this computation
// can be performed on 64 bit integers. On x86/x64 architecture the speedup is
// not really measurable, though.
//
// Since we want to avoid overshooting we decrement by 1e10 so that
// floating-point imprecisions don't affect us.
//
// Explanation for v's boundary m+: the computation takes advantage of
// the fact that 2^(p-1) <= f < 2^p. Boundaries still satisfy this requirement
// (even for denormals where the delta can be much more important).
const double k1Log10 = 0.30102999566398114; // 1/lg(10)
// For doubles len(f) == 53 (don't forget the hidden bit).
const int kSignificandSize = Double::kSignificandSize;
double estimate = ceil((exponent + kSignificandSize - 1) * k1Log10 - 1e-10);
return static_cast<int>(estimate);
}
// See comments for InitialScaledStartValues.
static void InitialScaledStartValuesPositiveExponent(
uint64_t significand, int exponent, int estimated_power,
bool need_boundary_deltas, Bignum* numerator, Bignum* denominator,
Bignum* delta_minus, Bignum* delta_plus) {
// A positive exponent implies a positive power.
DOUBLE_CONVERSION_ASSERT(estimated_power >= 0);
// Since the estimated_power is positive we simply multiply the denominator
// by 10^estimated_power.
// numerator = v.
numerator->AssignUInt64(significand);
numerator->ShiftLeft(exponent);
// denominator = 10^estimated_power.
denominator->AssignPowerUInt16(10, estimated_power);
if (need_boundary_deltas) {
// Introduce a common denominator so that the deltas to the boundaries are
// integers.
denominator->ShiftLeft(1);
numerator->ShiftLeft(1);
// Let v = f * 2^e, then m+ - v = 1/2 * 2^e; With the common
// denominator (of 2) delta_plus equals 2^e.
delta_plus->AssignUInt16(1);
delta_plus->ShiftLeft(exponent);
// Same for delta_minus. The adjustments if f == 2^p-1 are done later.
delta_minus->AssignUInt16(1);
delta_minus->ShiftLeft(exponent);
}
}
// See comments for InitialScaledStartValues
static void InitialScaledStartValuesNegativeExponentPositivePower(
uint64_t significand, int exponent, int estimated_power,
bool need_boundary_deltas, Bignum* numerator, Bignum* denominator,
Bignum* delta_minus, Bignum* delta_plus) {
// v = f * 2^e with e < 0, and with estimated_power >= 0.
// This means that e is close to 0 (have a look at how estimated_power is
// computed).
// numerator = significand
// since v = significand * 2^exponent this is equivalent to
// numerator = v * / 2^-exponent
numerator->AssignUInt64(significand);
// denominator = 10^estimated_power * 2^-exponent (with exponent < 0)
denominator->AssignPowerUInt16(10, estimated_power);
denominator->ShiftLeft(-exponent);
if (need_boundary_deltas) {
// Introduce a common denominator so that the deltas to the boundaries are
// integers.
denominator->ShiftLeft(1);
numerator->ShiftLeft(1);
// Let v = f * 2^e, then m+ - v = 1/2 * 2^e; With the common
// denominator (of 2) delta_plus equals 2^e.
// Given that the denominator already includes v's exponent the distance
// to the boundaries is simply 1.
delta_plus->AssignUInt16(1);
// Same for delta_minus. The adjustments if f == 2^p-1 are done later.
delta_minus->AssignUInt16(1);
}
}
// See comments for InitialScaledStartValues
static void InitialScaledStartValuesNegativeExponentNegativePower(
uint64_t significand, int exponent, int estimated_power,
bool need_boundary_deltas, Bignum* numerator, Bignum* denominator,
Bignum* delta_minus, Bignum* delta_plus) {
// Instead of multiplying the denominator with 10^estimated_power we
// multiply all values (numerator and deltas) by 10^-estimated_power.
// Use numerator as temporary container for power_ten.
Bignum* power_ten = numerator;
power_ten->AssignPowerUInt16(10, -estimated_power);
if (need_boundary_deltas) {
// Since power_ten == numerator we must make a copy of 10^estimated_power
// before we complete the computation of the numerator.
// delta_plus = delta_minus = 10^estimated_power
delta_plus->AssignBignum(*power_ten);
delta_minus->AssignBignum(*power_ten);
}
// numerator = significand * 2 * 10^-estimated_power
// since v = significand * 2^exponent this is equivalent to
// numerator = v * 10^-estimated_power * 2 * 2^-exponent.
// Remember: numerator has been abused as power_ten. So no need to assign it
// to itself.
DOUBLE_CONVERSION_ASSERT(numerator == power_ten);
numerator->MultiplyByUInt64(significand);
// denominator = 2 * 2^-exponent with exponent < 0.
denominator->AssignUInt16(1);
denominator->ShiftLeft(-exponent);
if (need_boundary_deltas) {
// Introduce a common denominator so that the deltas to the boundaries are
// integers.
numerator->ShiftLeft(1);
denominator->ShiftLeft(1);
// With this shift the boundaries have their correct value, since
// delta_plus = 10^-estimated_power, and
// delta_minus = 10^-estimated_power.
// These assignments have been done earlier.
// The adjustments if f == 2^p-1 (lower boundary is closer) are done later.
}
}
// Let v = significand * 2^exponent.
// Computes v / 10^estimated_power exactly, as a ratio of two bignums, numerator
// and denominator. The functions GenerateShortestDigits and
// GenerateCountedDigits will then convert this ratio to its decimal
// representation d, with the required accuracy.
// Then d * 10^estimated_power is the representation of v.
// (Note: the fraction and the estimated_power might get adjusted before
// generating the decimal representation.)
//
// The initial start values consist of:
// - a scaled numerator: s.t. numerator/denominator == v / 10^estimated_power.
// - a scaled (common) denominator.
// optionally (used by GenerateShortestDigits to decide if it has the shortest
// decimal converting back to v):
// - v - m-: the distance to the lower boundary.
// - m+ - v: the distance to the upper boundary.
//
// v, m+, m-, and therefore v - m- and m+ - v all share the same denominator.
//
// Let ep == estimated_power, then the returned values will satisfy:
// v / 10^ep = numerator / denominator.
// v's boundarys m- and m+:
// m- / 10^ep == v / 10^ep - delta_minus / denominator
// m+ / 10^ep == v / 10^ep + delta_plus / denominator
// Or in other words:
// m- == v - delta_minus * 10^ep / denominator;
// m+ == v + delta_plus * 10^ep / denominator;
//
// Since 10^(k-1) <= v < 10^k (with k == estimated_power)
// or 10^k <= v < 10^(k+1)
// we then have 0.1 <= numerator/denominator < 1
// or 1 <= numerator/denominator < 10
//
// It is then easy to kickstart the digit-generation routine.
//
// The boundary-deltas are only filled if the mode equals BIGNUM_DTOA_SHORTEST
// or BIGNUM_DTOA_SHORTEST_SINGLE.
static void InitialScaledStartValues(uint64_t significand, int exponent,
bool lower_boundary_is_closer,
int estimated_power,
bool need_boundary_deltas,
Bignum* numerator, Bignum* denominator,
Bignum* delta_minus, Bignum* delta_plus) {
if (exponent >= 0) {
InitialScaledStartValuesPositiveExponent(
significand, exponent, estimated_power, need_boundary_deltas, numerator,
denominator, delta_minus, delta_plus);
} else if (estimated_power >= 0) {
InitialScaledStartValuesNegativeExponentPositivePower(
significand, exponent, estimated_power, need_boundary_deltas, numerator,
denominator, delta_minus, delta_plus);
} else {
InitialScaledStartValuesNegativeExponentNegativePower(
significand, exponent, estimated_power, need_boundary_deltas, numerator,
denominator, delta_minus, delta_plus);
}
if (need_boundary_deltas && lower_boundary_is_closer) {
// The lower boundary is closer at half the distance of "normal" numbers.
// Increase the common denominator and adapt all but the delta_minus.
denominator->ShiftLeft(1); // *2
numerator->ShiftLeft(1); // *2
delta_plus->ShiftLeft(1); // *2
}
}
// This routine multiplies numerator/denominator so that its values lies in the
// range 1-10. That is after a call to this function we have:
// 1 <= (numerator + delta_plus) /denominator < 10.
// Let numerator the input before modification and numerator' the argument
// after modification, then the output-parameter decimal_point is such that
// numerator / denominator * 10^estimated_power ==
// numerator' / denominator' * 10^(decimal_point - 1)
// In some cases estimated_power was too low, and this is already the case. We
// then simply adjust the power so that 10^(k-1) <= v < 10^k (with k ==
// estimated_power) but do not touch the numerator or denominator.
// Otherwise the routine multiplies the numerator and the deltas by 10.
static void FixupMultiply10(int estimated_power, bool is_even,
int* decimal_point, Bignum* numerator,
Bignum* denominator, Bignum* delta_minus,
Bignum* delta_plus) {
bool in_range;
if (is_even) {
// For IEEE doubles half-way cases (in decimal system numbers ending with 5)
// are rounded to the closest floating-point number with even significand.
in_range = Bignum::PlusCompare(*numerator, *delta_plus, *denominator) >= 0;
} else {
in_range = Bignum::PlusCompare(*numerator, *delta_plus, *denominator) > 0;
}
if (in_range) {
// Since numerator + delta_plus >= denominator we already have
// 1 <= numerator/denominator < 10. Simply update the estimated_power.
*decimal_point = estimated_power + 1;
} else {
*decimal_point = estimated_power;
numerator->Times10();
if (Bignum::Equal(*delta_minus, *delta_plus)) {
delta_minus->Times10();
delta_plus->AssignBignum(*delta_minus);
} else {
delta_minus->Times10();
delta_plus->Times10();
}
}
}
} // namespace double_conversion

View file

@ -1,84 +0,0 @@
// Copyright 2010 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * 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.
// * Neither the name of Google Inc. 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 COPYRIGHT HOLDERS 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 COPYRIGHT
// OWNER 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.
#ifndef DOUBLE_CONVERSION_BIGNUM_DTOA_H_
#define DOUBLE_CONVERSION_BIGNUM_DTOA_H_
#include "utils.h"
namespace double_conversion {
enum BignumDtoaMode {
// Return the shortest correct representation.
// For example the output of 0.299999999999999988897 is (the less accurate but
// correct) 0.3.
BIGNUM_DTOA_SHORTEST,
// Same as BIGNUM_DTOA_SHORTEST but for single-precision floats.
BIGNUM_DTOA_SHORTEST_SINGLE,
// Return a fixed number of digits after the decimal point.
// For instance fixed(0.1, 4) becomes 0.1000
// If the input number is big, the output will be big.
BIGNUM_DTOA_FIXED,
// Return a fixed number of digits, no matter what the exponent is.
BIGNUM_DTOA_PRECISION
};
// Converts the given double 'v' to ascii.
// The result should be interpreted as buffer * 10^(point-length).
// The buffer will be null-terminated.
//
// The input v must be > 0 and different from NaN, and Infinity.
//
// The output depends on the given mode:
// - SHORTEST: produce the least amount of digits for which the internal
// identity requirement is still satisfied. If the digits are printed
// (together with the correct exponent) then reading this number will give
// 'v' again. The buffer will choose the representation that is closest to
// 'v'. If there are two at the same distance, than the number is round up.
// In this mode the 'requested_digits' parameter is ignored.
// - FIXED: produces digits necessary to print a given number with
// 'requested_digits' digits after the decimal point. The produced digits
// might be too short in which case the caller has to fill the gaps with '0's.
// Example: toFixed(0.001, 5) is allowed to return buffer="1", point=-2.
// Halfway cases are rounded up. The call toFixed(0.15, 2) thus returns
// buffer="2", point=0.
// Note: the length of the returned buffer has no meaning wrt the significance
// of its digits. That is, just because it contains '0's does not mean that
// any other digit would not satisfy the internal identity requirement.
// - PRECISION: produces 'requested_digits' where the first digit is not '0'.
// Even though the length of produced digits usually equals
// 'requested_digits', the function is allowed to return fewer digits, in
// which case the caller has to fill the missing digits with '0's.
// Halfway cases are again rounded up.
// 'BignumDtoa' expects the given buffer to be big enough to hold all digits
// and a terminating null-character.
void BignumDtoa(double v, BignumDtoaMode mode, int requested_digits,
Vector<char> buffer, int* length, int* point);
} // namespace double_conversion
#endif // DOUBLE_CONVERSION_BIGNUM_DTOA_H_

View file

@ -1,775 +0,0 @@
// Copyright 2010 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * 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.
// * Neither the name of Google Inc. 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 COPYRIGHT HOLDERS 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 COPYRIGHT
// OWNER 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 "libc/macros.h"
#include "third_party/double-conversion/bignum.h"
#include "third_party/double-conversion/utils.h"
asm(".ident\t\"\\n\\n\
double-conversion (BSD-3)\\n\
Copyright 2010 the V8 project authors\"");
asm(".include \"libc/disclaimer.inc\"");
namespace double_conversion {
Bignum::Chunk& Bignum::RawBigit(const int index) {
DOUBLE_CONVERSION_ASSERT(static_cast<unsigned>(index) < kBigitCapacity);
return bigits_buffer_[index];
}
const Bignum::Chunk& Bignum::RawBigit(const int index) const {
DOUBLE_CONVERSION_ASSERT(static_cast<unsigned>(index) < kBigitCapacity);
return bigits_buffer_[index];
}
template <typename S>
static int BitSize(const S value) {
(void)value; // Mark variable as used.
return 8 * sizeof(value);
}
// Guaranteed to lie in one Bigit.
void Bignum::AssignUInt16(const uint16_t value) {
DOUBLE_CONVERSION_ASSERT(kBigitSize >= BitSize(value));
Zero();
if (value > 0) {
RawBigit(0) = value;
used_bigits_ = 1;
}
}
void Bignum::AssignUInt64(uint64_t value) {
Zero();
for (int i = 0; value > 0; ++i) {
RawBigit(i) = value & kBigitMask;
value >>= kBigitSize;
++used_bigits_;
}
}
void Bignum::AssignBignum(const Bignum& other) {
exponent_ = other.exponent_;
for (int i = 0; i < other.used_bigits_; ++i) {
RawBigit(i) = other.RawBigit(i);
}
used_bigits_ = other.used_bigits_;
}
static uint64_t ReadUInt64(const Vector<const char> buffer, const int from,
const int digits_to_read) {
uint64_t result = 0;
for (int i = from; i < from + digits_to_read; ++i) {
const int digit = buffer[i] - '0';
DOUBLE_CONVERSION_ASSERT(0 <= digit && digit <= 9);
result = result * 10 + digit;
}
return result;
}
void Bignum::AssignDecimalString(const Vector<const char> value) {
// 2^64 = 18446744073709551616 > 10^19
static const int kMaxUint64DecimalDigits = 19;
Zero();
int length = value.length();
unsigned pos = 0;
// Let's just say that each digit needs 4 bits.
while (length >= kMaxUint64DecimalDigits) {
const uint64_t digits = ReadUInt64(value, pos, kMaxUint64DecimalDigits);
pos += kMaxUint64DecimalDigits;
length -= kMaxUint64DecimalDigits;
MultiplyByPowerOfTen(kMaxUint64DecimalDigits);
AddUInt64(digits);
}
const uint64_t digits = ReadUInt64(value, pos, length);
MultiplyByPowerOfTen(length);
AddUInt64(digits);
Clamp();
}
static uint64_t HexCharValue(const int c) {
if ('0' <= c && c <= '9') {
return c - '0';
}
if ('a' <= c && c <= 'f') {
return 10 + c - 'a';
}
DOUBLE_CONVERSION_ASSERT('A' <= c && c <= 'F');
return 10 + c - 'A';
}
// Unlike AssignDecimalString(), this function is "only" used
// for unit-tests and therefore not performance critical.
void Bignum::AssignHexString(Vector<const char> value) {
Zero();
// Required capacity could be reduced by ignoring leading zeros.
EnsureCapacity(((value.length() * 4) + kBigitSize - 1) / kBigitSize);
DOUBLE_CONVERSION_ASSERT(sizeof(uint64_t) * 8 >=
kBigitSize + 4); // TODO: static_assert
// Accumulates converted hex digits until at least kBigitSize bits.
// Works with non-factor-of-four kBigitSizes.
uint64_t tmp = 0; // Accumulates converted hex digits until at least
for (int cnt = 0; !value.is_empty(); value.pop_back()) {
tmp |= (HexCharValue(value.last()) << cnt);
if ((cnt += 4) >= kBigitSize) {
RawBigit(used_bigits_++) = (tmp & kBigitMask);
cnt -= kBigitSize;
tmp >>= kBigitSize;
}
}
if (tmp > 0) {
RawBigit(used_bigits_++) = tmp;
}
Clamp();
}
void Bignum::AddUInt64(const uint64_t operand) {
if (operand == 0) {
return;
}
Bignum other;
other.AssignUInt64(operand);
AddBignum(other);
}
void Bignum::AddBignum(const Bignum& other) {
DOUBLE_CONVERSION_ASSERT(IsClamped());
DOUBLE_CONVERSION_ASSERT(other.IsClamped());
// If this has a greater exponent than other append zero-bigits to this.
// After this call exponent_ <= other.exponent_.
Align(other);
// There are two possibilities:
// aaaaaaaaaaa 0000 (where the 0s represent a's exponent)
// bbbbb 00000000
// ----------------
// ccccccccccc 0000
// or
// aaaaaaaaaa 0000
// bbbbbbbbb 0000000
// -----------------
// cccccccccccc 0000
// In both cases we might need a carry bigit.
EnsureCapacity(1 + MAX(BigitLength(), other.BigitLength()) - exponent_);
Chunk carry = 0;
int bigit_pos = other.exponent_ - exponent_;
DOUBLE_CONVERSION_ASSERT(bigit_pos >= 0);
for (int i = used_bigits_; i < bigit_pos; ++i) {
RawBigit(i) = 0;
}
for (int i = 0; i < other.used_bigits_; ++i) {
const Chunk my = (bigit_pos < used_bigits_) ? RawBigit(bigit_pos) : 0;
const Chunk sum = my + other.RawBigit(i) + carry;
RawBigit(bigit_pos) = sum & kBigitMask;
carry = sum >> kBigitSize;
++bigit_pos;
}
while (carry != 0) {
const Chunk my = (bigit_pos < used_bigits_) ? RawBigit(bigit_pos) : 0;
const Chunk sum = my + carry;
RawBigit(bigit_pos) = sum & kBigitMask;
carry = sum >> kBigitSize;
++bigit_pos;
}
used_bigits_ = MAX(bigit_pos, static_cast<int>(used_bigits_));
DOUBLE_CONVERSION_ASSERT(IsClamped());
}
void Bignum::SubtractBignum(const Bignum& other) {
DOUBLE_CONVERSION_ASSERT(IsClamped());
DOUBLE_CONVERSION_ASSERT(other.IsClamped());
// We require this to be bigger than other.
DOUBLE_CONVERSION_ASSERT(LessEqual(other, *this));
Align(other);
const int offset = other.exponent_ - exponent_;
Chunk borrow = 0;
int i;
for (i = 0; i < other.used_bigits_; ++i) {
DOUBLE_CONVERSION_ASSERT((borrow == 0) || (borrow == 1));
const Chunk difference = RawBigit(i + offset) - other.RawBigit(i) - borrow;
RawBigit(i + offset) = difference & kBigitMask;
borrow = difference >> (kChunkSize - 1);
}
while (borrow != 0) {
const Chunk difference = RawBigit(i + offset) - borrow;
RawBigit(i + offset) = difference & kBigitMask;
borrow = difference >> (kChunkSize - 1);
++i;
}
Clamp();
}
void Bignum::ShiftLeft(const int shift_amount) {
if (used_bigits_ == 0) {
return;
}
exponent_ += (shift_amount / kBigitSize);
const int local_shift = shift_amount % kBigitSize;
EnsureCapacity(used_bigits_ + 1);
BigitsShiftLeft(local_shift);
}
void Bignum::MultiplyByUInt32(const uint32_t factor) {
if (factor == 1) {
return;
}
if (factor == 0) {
Zero();
return;
}
if (used_bigits_ == 0) {
return;
}
// The product of a bigit with the factor is of size kBigitSize + 32.
// Assert that this number + 1 (for the carry) fits into double chunk.
DOUBLE_CONVERSION_ASSERT(kDoubleChunkSize >= kBigitSize + 32 + 1);
DoubleChunk carry = 0;
for (int i = 0; i < used_bigits_; ++i) {
const DoubleChunk product =
static_cast<DoubleChunk>(factor) * RawBigit(i) + carry;
RawBigit(i) = static_cast<Chunk>(product & kBigitMask);
carry = (product >> kBigitSize);
}
while (carry != 0) {
EnsureCapacity(used_bigits_ + 1);
RawBigit(used_bigits_) = carry & kBigitMask;
used_bigits_++;
carry >>= kBigitSize;
}
}
void Bignum::MultiplyByUInt64(const uint64_t factor) {
if (factor == 1) {
return;
}
if (factor == 0) {
Zero();
return;
}
if (used_bigits_ == 0) {
return;
}
DOUBLE_CONVERSION_ASSERT(kBigitSize < 32);
uint64_t carry = 0;
const uint64_t low = factor & 0xFFFFFFFF;
const uint64_t high = factor >> 32;
for (int i = 0; i < used_bigits_; ++i) {
const uint64_t product_low = low * RawBigit(i);
const uint64_t product_high = high * RawBigit(i);
const uint64_t tmp = (carry & kBigitMask) + product_low;
RawBigit(i) = tmp & kBigitMask;
carry = (carry >> kBigitSize) + (tmp >> kBigitSize) +
(product_high << (32 - kBigitSize));
}
while (carry != 0) {
EnsureCapacity(used_bigits_ + 1);
RawBigit(used_bigits_) = carry & kBigitMask;
used_bigits_++;
carry >>= kBigitSize;
}
}
void Bignum::MultiplyByPowerOfTen(const int exponent) {
static const uint64_t kFive27 =
DOUBLE_CONVERSION_UINT64_2PART_C(0x6765c793, fa10079d);
static const uint16_t kFive1 = 5;
static const uint16_t kFive2 = kFive1 * 5;
static const uint16_t kFive3 = kFive2 * 5;
static const uint16_t kFive4 = kFive3 * 5;
static const uint16_t kFive5 = kFive4 * 5;
static const uint16_t kFive6 = kFive5 * 5;
static const uint32_t kFive7 = kFive6 * 5;
static const uint32_t kFive8 = kFive7 * 5;
static const uint32_t kFive9 = kFive8 * 5;
static const uint32_t kFive10 = kFive9 * 5;
static const uint32_t kFive11 = kFive10 * 5;
static const uint32_t kFive12 = kFive11 * 5;
static const uint32_t kFive13 = kFive12 * 5;
static const uint32_t kFive1_to_12[] = {kFive1, kFive2, kFive3, kFive4,
kFive5, kFive6, kFive7, kFive8,
kFive9, kFive10, kFive11, kFive12};
DOUBLE_CONVERSION_ASSERT(exponent >= 0);
if (exponent == 0) {
return;
}
if (used_bigits_ == 0) {
return;
}
// We shift by exponent at the end just before returning.
int remaining_exponent = exponent;
while (remaining_exponent >= 27) {
MultiplyByUInt64(kFive27);
remaining_exponent -= 27;
}
while (remaining_exponent >= 13) {
MultiplyByUInt32(kFive13);
remaining_exponent -= 13;
}
if (remaining_exponent > 0) {
MultiplyByUInt32(kFive1_to_12[remaining_exponent - 1]);
}
ShiftLeft(exponent);
}
void Bignum::Square() {
DOUBLE_CONVERSION_ASSERT(IsClamped());
const int product_length = 2 * used_bigits_;
EnsureCapacity(product_length);
// Comba multiplication: compute each column separately.
// Example: r = a2a1a0 * b2b1b0.
// r = 1 * a0b0 +
// 10 * (a1b0 + a0b1) +
// 100 * (a2b0 + a1b1 + a0b2) +
// 1000 * (a2b1 + a1b2) +
// 10000 * a2b2
//
// In the worst case we have to accumulate nb-digits products of digit*digit.
//
// Assert that the additional number of bits in a DoubleChunk are enough to
// sum up used_digits of Bigit*Bigit.
if ((1 << (2 * (kChunkSize - kBigitSize))) <= used_bigits_) {
DOUBLE_CONVERSION_UNIMPLEMENTED();
}
DoubleChunk accumulator = 0;
// First shift the digits so we don't overwrite them.
const int copy_offset = used_bigits_;
for (int i = 0; i < used_bigits_; ++i) {
RawBigit(copy_offset + i) = RawBigit(i);
}
// We have two loops to avoid some 'if's in the loop.
for (int i = 0; i < used_bigits_; ++i) {
// Process temporary digit i with power i.
// The sum of the two indices must be equal to i.
int bigit_index1 = i;
int bigit_index2 = 0;
// Sum all of the sub-products.
while (bigit_index1 >= 0) {
const Chunk chunk1 = RawBigit(copy_offset + bigit_index1);
const Chunk chunk2 = RawBigit(copy_offset + bigit_index2);
accumulator += static_cast<DoubleChunk>(chunk1) * chunk2;
bigit_index1--;
bigit_index2++;
}
RawBigit(i) = static_cast<Chunk>(accumulator) & kBigitMask;
accumulator >>= kBigitSize;
}
for (int i = used_bigits_; i < product_length; ++i) {
int bigit_index1 = used_bigits_ - 1;
int bigit_index2 = i - bigit_index1;
// Invariant: sum of both indices is again equal to i.
// Inner loop runs 0 times on last iteration, emptying accumulator.
while (bigit_index2 < used_bigits_) {
const Chunk chunk1 = RawBigit(copy_offset + bigit_index1);
const Chunk chunk2 = RawBigit(copy_offset + bigit_index2);
accumulator += static_cast<DoubleChunk>(chunk1) * chunk2;
bigit_index1--;
bigit_index2++;
}
// The overwritten RawBigit(i) will never be read in further loop
// iterations, because bigit_index1 and bigit_index2 are always greater than
// i - used_bigits_.
RawBigit(i) = static_cast<Chunk>(accumulator) & kBigitMask;
accumulator >>= kBigitSize;
}
// Since the result was guaranteed to lie inside the number the
// accumulator must be 0 now.
DOUBLE_CONVERSION_ASSERT(accumulator == 0);
// Don't forget to update the used_digits and the exponent.
used_bigits_ = product_length;
exponent_ *= 2;
Clamp();
}
void Bignum::AssignPowerUInt16(uint16_t base, const int power_exponent) {
DOUBLE_CONVERSION_ASSERT(base != 0);
DOUBLE_CONVERSION_ASSERT(power_exponent >= 0);
if (power_exponent == 0) {
AssignUInt16(1);
return;
}
Zero();
int shifts = 0;
// We expect base to be in range 2-32, and most often to be 10.
// It does not make much sense to implement different algorithms for counting
// the bits.
while ((base & 1) == 0) {
base >>= 1;
shifts++;
}
int bit_size = 0;
int tmp_base = base;
while (tmp_base != 0) {
tmp_base >>= 1;
bit_size++;
}
const int final_size = bit_size * power_exponent;
// 1 extra bigit for the shifting, and one for rounded final_size.
EnsureCapacity(final_size / kBigitSize + 2);
// Left to Right exponentiation.
int mask = 1;
while (power_exponent >= mask) mask <<= 1;
// The mask is now pointing to the bit above the most significant 1-bit of
// power_exponent.
// Get rid of first 1-bit;
mask >>= 2;
uint64_t this_value = base;
bool delayed_multiplication = false;
const uint64_t max_32bits = 0xFFFFFFFF;
while (mask != 0 && this_value <= max_32bits) {
this_value = this_value * this_value;
// Verify that there is enough space in this_value to perform the
// multiplication. The first bit_size bits must be 0.
if ((power_exponent & mask) != 0) {
DOUBLE_CONVERSION_ASSERT(bit_size > 0);
const uint64_t base_bits_mask =
~((static_cast<uint64_t>(1) << (64 - bit_size)) - 1);
const bool high_bits_zero = (this_value & base_bits_mask) == 0;
if (high_bits_zero) {
this_value *= base;
} else {
delayed_multiplication = true;
}
}
mask >>= 1;
}
AssignUInt64(this_value);
if (delayed_multiplication) {
MultiplyByUInt32(base);
}
// Now do the same thing as a bignum.
while (mask != 0) {
Square();
if ((power_exponent & mask) != 0) {
MultiplyByUInt32(base);
}
mask >>= 1;
}
// And finally add the saved shifts.
ShiftLeft(shifts * power_exponent);
}
// Precondition: this/other < 16bit.
uint16_t Bignum::DivideModuloIntBignum(const Bignum& other) {
DOUBLE_CONVERSION_ASSERT(IsClamped());
DOUBLE_CONVERSION_ASSERT(other.IsClamped());
DOUBLE_CONVERSION_ASSERT(other.used_bigits_ > 0);
// Easy case: if we have less digits than the divisor than the result is 0.
// Note: this handles the case where this == 0, too.
if (BigitLength() < other.BigitLength()) {
return 0;
}
Align(other);
uint16_t result = 0;
// Start by removing multiples of 'other' until both numbers have the same
// number of digits.
while (BigitLength() > other.BigitLength()) {
// This naive approach is extremely inefficient if `this` divided by other
// is big. This function is implemented for doubleToString where
// the result should be small (less than 10).
DOUBLE_CONVERSION_ASSERT(other.RawBigit(other.used_bigits_ - 1) >=
((1 << kBigitSize) / 16));
DOUBLE_CONVERSION_ASSERT(RawBigit(used_bigits_ - 1) < 0x10000);
// Remove the multiples of the first digit.
// Example this = 23 and other equals 9. -> Remove 2 multiples.
result += static_cast<uint16_t>(RawBigit(used_bigits_ - 1));
SubtractTimes(other, RawBigit(used_bigits_ - 1));
}
DOUBLE_CONVERSION_ASSERT(BigitLength() == other.BigitLength());
// Both bignums are at the same length now.
// Since other has more than 0 digits we know that the access to
// RawBigit(used_bigits_ - 1) is safe.
const Chunk this_bigit = RawBigit(used_bigits_ - 1);
const Chunk other_bigit = other.RawBigit(other.used_bigits_ - 1);
if (other.used_bigits_ == 1) {
// Shortcut for easy (and common) case.
int quotient = this_bigit / other_bigit;
RawBigit(used_bigits_ - 1) = this_bigit - other_bigit * quotient;
DOUBLE_CONVERSION_ASSERT(quotient < 0x10000);
result += static_cast<uint16_t>(quotient);
Clamp();
return result;
}
const int division_estimate = this_bigit / (other_bigit + 1);
DOUBLE_CONVERSION_ASSERT(division_estimate < 0x10000);
result += static_cast<uint16_t>(division_estimate);
SubtractTimes(other, division_estimate);
if (other_bigit * (division_estimate + 1) > this_bigit) {
// No need to even try to subtract. Even if other's remaining digits were 0
// another subtraction would be too much.
return result;
}
while (LessEqual(other, *this)) {
SubtractBignum(other);
result++;
}
return result;
}
template <typename S>
static int SizeInHexChars(S number) {
DOUBLE_CONVERSION_ASSERT(number > 0);
int result = 0;
while (number != 0) {
number >>= 4;
result++;
}
return result;
}
static char HexCharOfValue(const int value) {
DOUBLE_CONVERSION_ASSERT(0 <= value && value <= 16);
if (value < 10) {
return static_cast<char>(value + '0');
}
return static_cast<char>(value - 10 + 'A');
}
bool Bignum::ToHexString(char* buffer, const int buffer_size) const {
DOUBLE_CONVERSION_ASSERT(IsClamped());
// Each bigit must be printable as separate hex-character.
DOUBLE_CONVERSION_ASSERT(kBigitSize % 4 == 0);
static const int kHexCharsPerBigit = kBigitSize / 4;
if (used_bigits_ == 0) {
if (buffer_size < 2) {
return false;
}
buffer[0] = '0';
buffer[1] = '\0';
return true;
}
// We add 1 for the terminating '\0' character.
const int needed_chars = (BigitLength() - 1) * kHexCharsPerBigit +
SizeInHexChars(RawBigit(used_bigits_ - 1)) + 1;
if (needed_chars > buffer_size) {
return false;
}
int string_index = needed_chars - 1;
buffer[string_index--] = '\0';
for (int i = 0; i < exponent_; ++i) {
for (int j = 0; j < kHexCharsPerBigit; ++j) {
buffer[string_index--] = '0';
}
}
for (int i = 0; i < used_bigits_ - 1; ++i) {
Chunk current_bigit = RawBigit(i);
for (int j = 0; j < kHexCharsPerBigit; ++j) {
buffer[string_index--] = HexCharOfValue(current_bigit & 0xF);
current_bigit >>= 4;
}
}
// And finally the last bigit.
Chunk most_significant_bigit = RawBigit(used_bigits_ - 1);
while (most_significant_bigit != 0) {
buffer[string_index--] = HexCharOfValue(most_significant_bigit & 0xF);
most_significant_bigit >>= 4;
}
return true;
}
Bignum::Chunk Bignum::BigitOrZero(const int index) const {
if (index >= BigitLength()) {
return 0;
}
if (index < exponent_) {
return 0;
}
return RawBigit(index - exponent_);
}
int Bignum::Compare(const Bignum& a, const Bignum& b) {
DOUBLE_CONVERSION_ASSERT(a.IsClamped());
DOUBLE_CONVERSION_ASSERT(b.IsClamped());
const int bigit_length_a = a.BigitLength();
const int bigit_length_b = b.BigitLength();
if (bigit_length_a < bigit_length_b) {
return -1;
}
if (bigit_length_a > bigit_length_b) {
return +1;
}
for (int i = bigit_length_a - 1; i >= MIN(a.exponent_, b.exponent_); --i) {
const Chunk bigit_a = a.BigitOrZero(i);
const Chunk bigit_b = b.BigitOrZero(i);
if (bigit_a < bigit_b) {
return -1;
}
if (bigit_a > bigit_b) {
return +1;
}
// Otherwise they are equal up to this digit. Try the next digit.
}
return 0;
}
int Bignum::PlusCompare(const Bignum& a, const Bignum& b, const Bignum& c) {
DOUBLE_CONVERSION_ASSERT(a.IsClamped());
DOUBLE_CONVERSION_ASSERT(b.IsClamped());
DOUBLE_CONVERSION_ASSERT(c.IsClamped());
if (a.BigitLength() < b.BigitLength()) {
return PlusCompare(b, a, c);
}
if (a.BigitLength() + 1 < c.BigitLength()) {
return -1;
}
if (a.BigitLength() > c.BigitLength()) {
return +1;
}
// The exponent encodes 0-bigits. So if there are more 0-digits in 'a' than
// 'b' has digits, then the bigit-length of 'a'+'b' must be equal to the one
// of 'a'.
if (a.exponent_ >= b.BigitLength() && a.BigitLength() < c.BigitLength()) {
return -1;
}
Chunk borrow = 0;
// Starting at min_exponent all digits are == 0. So no need to compare them.
const int min_exponent = MIN(MIN(a.exponent_, b.exponent_), c.exponent_);
for (int i = c.BigitLength() - 1; i >= min_exponent; --i) {
const Chunk chunk_a = a.BigitOrZero(i);
const Chunk chunk_b = b.BigitOrZero(i);
const Chunk chunk_c = c.BigitOrZero(i);
const Chunk sum = chunk_a + chunk_b;
if (sum > chunk_c + borrow) {
return +1;
} else {
borrow = chunk_c + borrow - sum;
if (borrow > 1) {
return -1;
}
borrow <<= kBigitSize;
}
}
if (borrow == 0) {
return 0;
}
return -1;
}
void Bignum::Clamp() {
while (used_bigits_ > 0 && RawBigit(used_bigits_ - 1) == 0) {
used_bigits_--;
}
if (used_bigits_ == 0) {
// Zero.
exponent_ = 0;
}
}
void Bignum::Align(const Bignum& other) {
if (exponent_ > other.exponent_) {
// If "X" represents a "hidden" bigit (by the exponent) then we are in the
// following case (a == this, b == other):
// a: aaaaaaXXXX or a: aaaaaXXX
// b: bbbbbbX b: bbbbbbbbXX
// We replace some of the hidden digits (X) of a with 0 digits.
// a: aaaaaa000X or a: aaaaa0XX
const int zero_bigits = exponent_ - other.exponent_;
EnsureCapacity(used_bigits_ + zero_bigits);
for (int i = used_bigits_ - 1; i >= 0; --i) {
RawBigit(i + zero_bigits) = RawBigit(i);
}
for (int i = 0; i < zero_bigits; ++i) {
RawBigit(i) = 0;
}
used_bigits_ += zero_bigits;
exponent_ -= zero_bigits;
DOUBLE_CONVERSION_ASSERT(used_bigits_ >= 0);
DOUBLE_CONVERSION_ASSERT(exponent_ >= 0);
}
}
void Bignum::BigitsShiftLeft(const int shift_amount) {
DOUBLE_CONVERSION_ASSERT(shift_amount < kBigitSize);
DOUBLE_CONVERSION_ASSERT(shift_amount >= 0);
Chunk carry = 0;
for (int i = 0; i < used_bigits_; ++i) {
const Chunk new_carry = RawBigit(i) >> (kBigitSize - shift_amount);
RawBigit(i) = ((RawBigit(i) << shift_amount) + carry) & kBigitMask;
carry = new_carry;
}
if (carry != 0) {
RawBigit(used_bigits_) = carry;
used_bigits_++;
}
}
void Bignum::SubtractTimes(const Bignum& other, const int factor) {
DOUBLE_CONVERSION_ASSERT(exponent_ <= other.exponent_);
if (factor < 3) {
for (int i = 0; i < factor; ++i) {
SubtractBignum(other);
}
return;
}
Chunk borrow = 0;
const int exponent_diff = other.exponent_ - exponent_;
for (int i = 0; i < other.used_bigits_; ++i) {
const DoubleChunk product =
static_cast<DoubleChunk>(factor) * other.RawBigit(i);
const DoubleChunk remove = borrow + product;
const Chunk difference =
RawBigit(i + exponent_diff) - (remove & kBigitMask);
RawBigit(i + exponent_diff) = difference & kBigitMask;
borrow = static_cast<Chunk>((difference >> (kChunkSize - 1)) +
(remove >> kBigitSize));
}
for (int i = other.used_bigits_ + exponent_diff; i < used_bigits_; ++i) {
if (borrow == 0) {
return;
}
const Chunk difference = RawBigit(i) - borrow;
RawBigit(i) = difference & kBigitMask;
borrow = difference >> (kChunkSize - 1);
}
Clamp();
}
} // namespace double_conversion

View file

@ -1,153 +0,0 @@
// Copyright 2010 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * 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.
// * Neither the name of Google Inc. 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 COPYRIGHT HOLDERS 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 COPYRIGHT
// OWNER 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.
#ifndef DOUBLE_CONVERSION_BIGNUM_H_
#define DOUBLE_CONVERSION_BIGNUM_H_
#include "third_party/double-conversion/utils.h"
namespace double_conversion {
class Bignum {
public:
// 3584 = 128 * 28. We can represent 2^3584 > 10^1000 accurately.
// This bignum can encode much bigger numbers, since it contains an
// exponent.
static const int kMaxSignificantBits = 3584;
Bignum() : used_bigits_(0), exponent_(0) {}
void AssignUInt16(const uint16_t value);
void AssignUInt64(uint64_t value);
void AssignBignum(const Bignum& other);
void AssignDecimalString(const Vector<const char> value);
void AssignHexString(const Vector<const char> value);
void AssignPowerUInt16(uint16_t base, const int exponent);
void AddUInt64(const uint64_t operand);
void AddBignum(const Bignum& other);
// Precondition: this >= other.
void SubtractBignum(const Bignum& other);
void Square();
void ShiftLeft(const int shift_amount);
void MultiplyByUInt32(const uint32_t factor);
void MultiplyByUInt64(const uint64_t factor);
void MultiplyByPowerOfTen(const int exponent);
void Times10() { return MultiplyByUInt32(10); }
// Pseudocode:
// int result = this / other;
// this = this % other;
// In the worst case this function is in O(this/other).
uint16_t DivideModuloIntBignum(const Bignum& other);
bool ToHexString(char* buffer, const int buffer_size) const;
// Returns
// -1 if a < b,
// 0 if a == b, and
// +1 if a > b.
static int Compare(const Bignum& a, const Bignum& b);
static bool Equal(const Bignum& a, const Bignum& b) {
return Compare(a, b) == 0;
}
static bool LessEqual(const Bignum& a, const Bignum& b) {
return Compare(a, b) <= 0;
}
static bool Less(const Bignum& a, const Bignum& b) {
return Compare(a, b) < 0;
}
// Returns Compare(a + b, c);
static int PlusCompare(const Bignum& a, const Bignum& b, const Bignum& c);
// Returns a + b == c
static bool PlusEqual(const Bignum& a, const Bignum& b, const Bignum& c) {
return PlusCompare(a, b, c) == 0;
}
// Returns a + b <= c
static bool PlusLessEqual(const Bignum& a, const Bignum& b, const Bignum& c) {
return PlusCompare(a, b, c) <= 0;
}
// Returns a + b < c
static bool PlusLess(const Bignum& a, const Bignum& b, const Bignum& c) {
return PlusCompare(a, b, c) < 0;
}
private:
typedef uint32_t Chunk;
typedef uint64_t DoubleChunk;
static const int kChunkSize = sizeof(Chunk) * 8;
static const int kDoubleChunkSize = sizeof(DoubleChunk) * 8;
// With bigit size of 28 we loose some bits, but a double still fits easily
// into two chunks, and more importantly we can use the Comba multiplication.
static const int kBigitSize = 28;
static const Chunk kBigitMask = (1 << kBigitSize) - 1;
// Every instance allocates kBigitLength chunks on the stack. Bignums cannot
// grow. There are no checks if the stack-allocated space is sufficient.
static const int kBigitCapacity = kMaxSignificantBits / kBigitSize;
static void EnsureCapacity(const int size) {
if (size > kBigitCapacity) {
DOUBLE_CONVERSION_UNREACHABLE();
}
}
void Align(const Bignum& other);
void Clamp();
bool IsClamped() const {
return used_bigits_ == 0 || RawBigit(used_bigits_ - 1) != 0;
}
void Zero() {
used_bigits_ = 0;
exponent_ = 0;
}
// Requires this to have enough capacity (no tests done).
// Updates used_bigits_ if necessary.
// shift_amount must be < kBigitSize.
void BigitsShiftLeft(const int shift_amount);
// BigitLength includes the "hidden" bigits encoded in the exponent.
int BigitLength() const { return used_bigits_ + exponent_; }
Chunk& RawBigit(const int index);
const Chunk& RawBigit(const int index) const;
Chunk BigitOrZero(const int index) const;
void SubtractTimes(const Bignum& other, const int factor);
// The Bignum's value is value(bigits_buffer_) * 2^(exponent_ * kBigitSize),
// where the value of the buffer consists of the lower kBigitSize bits of
// the first used_bigits_ Chunks in bigits_buffer_, first chunk has lowest
// significant bits.
int16_t used_bigits_;
int16_t exponent_;
Chunk bigits_buffer_[kBigitCapacity];
DOUBLE_CONVERSION_DISALLOW_COPY_AND_ASSIGN(Bignum);
};
} // namespace double_conversion
#endif // DOUBLE_CONVERSION_BIGNUM_H_

View file

@ -1,140 +0,0 @@
// Copyright 2010 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * 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.
// * Neither the name of Google Inc. 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 COPYRIGHT HOLDERS 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 COPYRIGHT
// OWNER 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.
#ifndef DOUBLE_CONVERSION_DIY_FP_H_
#define DOUBLE_CONVERSION_DIY_FP_H_
#include "third_party/double-conversion/utils.h"
namespace double_conversion {
// This "Do It Yourself Floating Point" class implements a floating-point number
// with a uint64 significand and an int exponent. Normalized DiyFp numbers will
// have the most significant bit of the significand set.
// Multiplication and Subtraction do not normalize their results.
// DiyFp store only non-negative numbers and are not designed to contain special
// doubles (NaN and Infinity).
class DiyFp {
public:
static const int kSignificandSize = 64;
DiyFp() : f_(0), e_(0) {}
DiyFp(const uint64_t significand, const int32_t exponent)
: f_(significand), e_(exponent) {}
// this -= other.
// The exponents of both numbers must be the same and the significand of this
// must be greater or equal than the significand of other.
// The result will not be normalized.
void Subtract(const DiyFp& other) {
DOUBLE_CONVERSION_ASSERT(e_ == other.e_);
DOUBLE_CONVERSION_ASSERT(f_ >= other.f_);
f_ -= other.f_;
}
// Returns a - b.
// The exponents of both numbers must be the same and a must be greater
// or equal than b. The result will not be normalized.
static DiyFp Minus(const DiyFp& a, const DiyFp& b) {
DiyFp result = a;
result.Subtract(b);
return result;
}
// this *= other.
void Multiply(const DiyFp& other) {
// Simply "emulates" a 128 bit multiplication.
// However: the resulting number only contains 64 bits. The least
// significant 64 bits are only used for rounding the most significant 64
// bits.
const uint64_t kM32 = 0xFFFFFFFFU;
const uint64_t a = f_ >> 32;
const uint64_t b = f_ & kM32;
const uint64_t c = other.f_ >> 32;
const uint64_t d = other.f_ & kM32;
const uint64_t ac = a * c;
const uint64_t bc = b * c;
const uint64_t ad = a * d;
const uint64_t bd = b * d;
// By adding 1U << 31 to tmp we round the final result.
// Halfway cases will be rounded up.
const uint64_t tmp = (bd >> 32) + (ad & kM32) + (bc & kM32) + (1U << 31);
e_ += other.e_ + 64;
f_ = ac + (ad >> 32) + (bc >> 32) + (tmp >> 32);
}
// returns a * b;
static DiyFp Times(const DiyFp& a, const DiyFp& b) {
DiyFp result = a;
result.Multiply(b);
return result;
}
void Normalize() {
DOUBLE_CONVERSION_ASSERT(f_ != 0);
uint64_t significand = f_;
int32_t exponent = e_;
// This method is mainly called for normalizing boundaries. In general,
// boundaries need to be shifted by 10 bits, and we optimize for this case.
const uint64_t k10MSBits =
DOUBLE_CONVERSION_UINT64_2PART_C(0xFFC00000, 00000000);
while ((significand & k10MSBits) == 0) {
significand <<= 10;
exponent -= 10;
}
while ((significand & kUint64MSB) == 0) {
significand <<= 1;
exponent--;
}
f_ = significand;
e_ = exponent;
}
static DiyFp Normalize(const DiyFp& a) {
DiyFp result = a;
result.Normalize();
return result;
}
uint64_t f() const { return f_; }
int32_t e() const { return e_; }
void set_f(uint64_t new_value) { f_ = new_value; }
void set_e(int32_t new_value) { e_ = new_value; }
private:
static const uint64_t kUint64MSB =
DOUBLE_CONVERSION_UINT64_2PART_C(0x80000000, 00000000);
uint64_t f_;
int32_t e_;
};
} // namespace double_conversion
#endif // DOUBLE_CONVERSION_DIY_FP_H_

View file

@ -1,54 +0,0 @@
#-*-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───────────────────────┘
PKGS += THIRD_PARTY_DOUBLE_CONVERSION
THIRD_PARTY_DOUBLE_CONVERSION_ARTIFACTS += THIRD_PARTY_DOUBLE_CONVERSION_A
THIRD_PARTY_DOUBLE_CONVERSION = $(THIRD_PARTY_DOUBLE_CONVERSION_A_DEPS) $(THIRD_PARTY_DOUBLE_CONVERSION_A)
THIRD_PARTY_DOUBLE_CONVERSION_A = o/$(MODE)/third_party/double-conversion/double-conversion.a
THIRD_PARTY_DOUBLE_CONVERSION_A_FILES := $(wildcard third_party/double-conversion/*)
THIRD_PARTY_DOUBLE_CONVERSION_A_HDRS = $(filter %.h,$(THIRD_PARTY_DOUBLE_CONVERSION_A_FILES))
THIRD_PARTY_DOUBLE_CONVERSION_A_SRCS_CC = $(filter %.cc,$(THIRD_PARTY_DOUBLE_CONVERSION_A_FILES))
THIRD_PARTY_DOUBLE_CONVERSION_A_SRCS = \
$(THIRD_PARTY_DOUBLE_CONVERSION_A_SRCS_CC)
THIRD_PARTY_DOUBLE_CONVERSION_A_OBJS = \
$(THIRD_PARTY_DOUBLE_CONVERSION_A_SRCS:%=o/$(MODE)/%.zip.o) \
$(THIRD_PARTY_DOUBLE_CONVERSION_A_SRCS_CC:%.cc=o/$(MODE)/%.o)
THIRD_PARTY_DOUBLE_CONVERSION_A_CHECKS = \
$(THIRD_PARTY_DOUBLE_CONVERSION_A).pkg \
$(THIRD_PARTY_DOUBLE_CONVERSION_A_HDRS:%=o/$(MODE)/%.ok)
THIRD_PARTY_DOUBLE_CONVERSION_A_DIRECTDEPS = \
LIBC_STUBS
THIRD_PARTY_DOUBLE_CONVERSION_A_DEPS := \
$(call uniq,$(foreach x,$(THIRD_PARTY_DOUBLE_CONVERSION_A_DIRECTDEPS),$($(x))))
$(THIRD_PARTY_DOUBLE_CONVERSION_A): \
third_party/double-conversion/ \
$(THIRD_PARTY_DOUBLE_CONVERSION_A).pkg \
$(THIRD_PARTY_DOUBLE_CONVERSION_A_OBJS)
$(THIRD_PARTY_DOUBLE_CONVERSION_A).pkg: \
$(THIRD_PARTY_DOUBLE_CONVERSION_A_OBJS) \
$(foreach x,$(THIRD_PARTY_DOUBLE_CONVERSION_A_DIRECTDEPS),$($(x)_A).pkg)
$(THIRD_PARTY_DOUBLE_CONVERSION_A_OBJS): \
OVERRIDE_CXXFLAGS += \
$(IEEE_MATH) \
-fvisibility=hidden \
-ffunction-sections \
-fdata-sections
THIRD_PARTY_DOUBLE_CONVERSION_LIBS = $(foreach x,$(THIRD_PARTY_DOUBLE_CONVERSION_ARTIFACTS),$($(x)))
THIRD_PARTY_DOUBLE_CONVERSION_SRCS = $(foreach x,$(THIRD_PARTY_DOUBLE_CONVERSION_ARTIFACTS),$($(x)_SRCS))
THIRD_PARTY_DOUBLE_CONVERSION_HDRS = $(foreach x,$(THIRD_PARTY_DOUBLE_CONVERSION_ARTIFACTS),$($(x)_HDRS))
THIRD_PARTY_DOUBLE_CONVERSION_CHECKS = $(foreach x,$(THIRD_PARTY_DOUBLE_CONVERSION_ARTIFACTS),$($(x)_CHECKS))
THIRD_PARTY_DOUBLE_CONVERSION_OBJS = $(foreach x,$(THIRD_PARTY_DOUBLE_CONVERSION_ARTIFACTS),$($(x)_OBJS))
$(THIRD_PARTY_DOUBLE_CONVERSION_OBJS): third_party/double-conversion/double-conversion.mk
.PHONY: o/$(MODE)/third_party/double-conversion
o/$(MODE)/third_party/double-conversion: $(THIRD_PARTY_DOUBLE_CONVERSION_CHECKS)

View file

@ -1,395 +0,0 @@
// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * 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.
// * Neither the name of Google Inc. 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 COPYRIGHT HOLDERS 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 COPYRIGHT
// OWNER 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.
#ifndef DOUBLE_CONVERSION_DOUBLE_H_
#define DOUBLE_CONVERSION_DOUBLE_H_
#include "third_party/double-conversion/diy-fp.h"
namespace double_conversion {
// We assume that doubles and uint64_t have the same endianness.
static uint64_t double_to_uint64(double d) { return BitCast<uint64_t>(d); }
static double uint64_to_double(uint64_t d64) { return BitCast<double>(d64); }
static uint32_t float_to_uint32(float f) { return BitCast<uint32_t>(f); }
static float uint32_to_float(uint32_t d32) { return BitCast<float>(d32); }
// Helper functions for doubles.
class Double {
public:
static const uint64_t kSignMask =
DOUBLE_CONVERSION_UINT64_2PART_C(0x80000000, 00000000);
static const uint64_t kExponentMask =
DOUBLE_CONVERSION_UINT64_2PART_C(0x7FF00000, 00000000);
static const uint64_t kSignificandMask =
DOUBLE_CONVERSION_UINT64_2PART_C(0x000FFFFF, FFFFFFFF);
static const uint64_t kHiddenBit =
DOUBLE_CONVERSION_UINT64_2PART_C(0x00100000, 00000000);
static const int kPhysicalSignificandSize = 52; // Excludes the hidden bit.
static const int kSignificandSize = 53;
static const int kExponentBias = 0x3FF + kPhysicalSignificandSize;
static const int kMaxExponent = 0x7FF - kExponentBias;
Double() : d64_(0) {}
explicit Double(double d) : d64_(double_to_uint64(d)) {}
explicit Double(uint64_t d64) : d64_(d64) {}
explicit Double(DiyFp diy_fp) : d64_(DiyFpToUint64(diy_fp)) {}
// The value encoded by this Double must be greater or equal to +0.0.
// It must not be special (infinity, or NaN).
DiyFp AsDiyFp() const {
DOUBLE_CONVERSION_ASSERT(Sign() > 0);
DOUBLE_CONVERSION_ASSERT(!IsSpecial());
return DiyFp(Significand(), Exponent());
}
// The value encoded by this Double must be strictly greater than 0.
DiyFp AsNormalizedDiyFp() const {
DOUBLE_CONVERSION_ASSERT(value() > 0.0);
uint64_t f = Significand();
int e = Exponent();
// The current double could be a denormal.
while ((f & kHiddenBit) == 0) {
f <<= 1;
e--;
}
// Do the final shifts in one go.
f <<= DiyFp::kSignificandSize - kSignificandSize;
e -= DiyFp::kSignificandSize - kSignificandSize;
return DiyFp(f, e);
}
// Returns the double's bit as uint64.
uint64_t AsUint64() const { return d64_; }
// Returns the next greater double. Returns +infinity on input +infinity.
double NextDouble() const {
if (d64_ == kInfinity) return Double(kInfinity).value();
if (Sign() < 0 && Significand() == 0) {
// -0.0
return 0.0;
}
if (Sign() < 0) {
return Double(d64_ - 1).value();
} else {
return Double(d64_ + 1).value();
}
}
double PreviousDouble() const {
if (d64_ == (kInfinity | kSignMask)) return -Infinity();
if (Sign() < 0) {
return Double(d64_ + 1).value();
} else {
if (Significand() == 0) return -0.0;
return Double(d64_ - 1).value();
}
}
int Exponent() const {
if (IsDenormal()) return kDenormalExponent;
uint64_t d64 = AsUint64();
int biased_e =
static_cast<int>((d64 & kExponentMask) >> kPhysicalSignificandSize);
return biased_e - kExponentBias;
}
uint64_t Significand() const {
uint64_t d64 = AsUint64();
uint64_t significand = d64 & kSignificandMask;
if (!IsDenormal()) {
return significand + kHiddenBit;
} else {
return significand;
}
}
// Returns true if the double is a denormal.
bool IsDenormal() const {
uint64_t d64 = AsUint64();
return (d64 & kExponentMask) == 0;
}
// We consider denormals not to be special.
// Hence only Infinity and NaN are special.
bool IsSpecial() const {
uint64_t d64 = AsUint64();
return (d64 & kExponentMask) == kExponentMask;
}
bool IsNan() const {
uint64_t d64 = AsUint64();
return ((d64 & kExponentMask) == kExponentMask) &&
((d64 & kSignificandMask) != 0);
}
bool IsInfinite() const {
uint64_t d64 = AsUint64();
return ((d64 & kExponentMask) == kExponentMask) &&
((d64 & kSignificandMask) == 0);
}
int Sign() const {
uint64_t d64 = AsUint64();
return (d64 & kSignMask) == 0 ? 1 : -1;
}
// Precondition: the value encoded by this Double must be greater or equal
// than +0.0.
DiyFp UpperBoundary() const {
DOUBLE_CONVERSION_ASSERT(Sign() > 0);
return DiyFp(Significand() * 2 + 1, Exponent() - 1);
}
// Computes the two boundaries of this.
// The bigger boundary (m_plus) is normalized. The lower boundary has the same
// exponent as m_plus.
// Precondition: the value encoded by this Double must be greater than 0.
void NormalizedBoundaries(DiyFp* out_m_minus, DiyFp* out_m_plus) const {
DOUBLE_CONVERSION_ASSERT(value() > 0.0);
DiyFp v = this->AsDiyFp();
DiyFp m_plus = DiyFp::Normalize(DiyFp((v.f() << 1) + 1, v.e() - 1));
DiyFp m_minus;
if (LowerBoundaryIsCloser()) {
m_minus = DiyFp((v.f() << 2) - 1, v.e() - 2);
} else {
m_minus = DiyFp((v.f() << 1) - 1, v.e() - 1);
}
m_minus.set_f(m_minus.f() << (m_minus.e() - m_plus.e()));
m_minus.set_e(m_plus.e());
*out_m_plus = m_plus;
*out_m_minus = m_minus;
}
bool LowerBoundaryIsCloser() const {
// The boundary is closer if the significand is of the form f == 2^p-1 then
// the lower boundary is closer.
// Think of v = 1000e10 and v- = 9999e9.
// Then the boundary (== (v - v-)/2) is not just at a distance of 1e9 but
// at a distance of 1e8.
// The only exception is for the smallest normal: the largest denormal is
// at the same distance as its successor.
// Note: denormals have the same exponent as the smallest normals.
bool physical_significand_is_zero = ((AsUint64() & kSignificandMask) == 0);
return physical_significand_is_zero && (Exponent() != kDenormalExponent);
}
double value() const { return uint64_to_double(d64_); }
// Returns the significand size for a given order of magnitude.
// If v = f*2^e with 2^p-1 <= f <= 2^p then p+e is v's order of magnitude.
// This function returns the number of significant binary digits v will have
// once it's encoded into a double. In almost all cases this is equal to
// kSignificandSize. The only exceptions are denormals. They start with
// leading zeroes and their effective significand-size is hence smaller.
static int SignificandSizeForOrderOfMagnitude(int order) {
if (order >= (kDenormalExponent + kSignificandSize)) {
return kSignificandSize;
}
if (order <= kDenormalExponent) return 0;
return order - kDenormalExponent;
}
static double Infinity() { return Double(kInfinity).value(); }
static double NaN() { return Double(kNaN).value(); }
private:
static const int kDenormalExponent = -kExponentBias + 1;
static const uint64_t kInfinity =
DOUBLE_CONVERSION_UINT64_2PART_C(0x7FF00000, 00000000);
static const uint64_t kNaN =
DOUBLE_CONVERSION_UINT64_2PART_C(0x7FF80000, 00000000);
const uint64_t d64_;
static uint64_t DiyFpToUint64(DiyFp diy_fp) {
uint64_t significand = diy_fp.f();
int exponent = diy_fp.e();
while (significand > kHiddenBit + kSignificandMask) {
significand >>= 1;
exponent++;
}
if (exponent >= kMaxExponent) {
return kInfinity;
}
if (exponent < kDenormalExponent) {
return 0;
}
while (exponent > kDenormalExponent && (significand & kHiddenBit) == 0) {
significand <<= 1;
exponent--;
}
uint64_t biased_exponent;
if (exponent == kDenormalExponent && (significand & kHiddenBit) == 0) {
biased_exponent = 0;
} else {
biased_exponent = static_cast<uint64_t>(exponent + kExponentBias);
}
return (significand & kSignificandMask) |
(biased_exponent << kPhysicalSignificandSize);
}
DOUBLE_CONVERSION_DISALLOW_COPY_AND_ASSIGN(Double);
};
class Single {
public:
static const uint32_t kSignMask = 0x80000000;
static const uint32_t kExponentMask = 0x7F800000;
static const uint32_t kSignificandMask = 0x007FFFFF;
static const uint32_t kHiddenBit = 0x00800000;
static const int kPhysicalSignificandSize = 23; // Excludes the hidden bit.
static const int kSignificandSize = 24;
Single() : d32_(0) {}
explicit Single(float f) : d32_(float_to_uint32(f)) {}
explicit Single(uint32_t d32) : d32_(d32) {}
// The value encoded by this Single must be greater or equal to +0.0.
// It must not be special (infinity, or NaN).
DiyFp AsDiyFp() const {
DOUBLE_CONVERSION_ASSERT(Sign() > 0);
DOUBLE_CONVERSION_ASSERT(!IsSpecial());
return DiyFp(Significand(), Exponent());
}
// Returns the single's bit as uint64.
uint32_t AsUint32() const { return d32_; }
int Exponent() const {
if (IsDenormal()) return kDenormalExponent;
uint32_t d32 = AsUint32();
int biased_e =
static_cast<int>((d32 & kExponentMask) >> kPhysicalSignificandSize);
return biased_e - kExponentBias;
}
uint32_t Significand() const {
uint32_t d32 = AsUint32();
uint32_t significand = d32 & kSignificandMask;
if (!IsDenormal()) {
return significand + kHiddenBit;
} else {
return significand;
}
}
// Returns true if the single is a denormal.
bool IsDenormal() const {
uint32_t d32 = AsUint32();
return (d32 & kExponentMask) == 0;
}
// We consider denormals not to be special.
// Hence only Infinity and NaN are special.
bool IsSpecial() const {
uint32_t d32 = AsUint32();
return (d32 & kExponentMask) == kExponentMask;
}
bool IsNan() const {
uint32_t d32 = AsUint32();
return ((d32 & kExponentMask) == kExponentMask) &&
((d32 & kSignificandMask) != 0);
}
bool IsInfinite() const {
uint32_t d32 = AsUint32();
return ((d32 & kExponentMask) == kExponentMask) &&
((d32 & kSignificandMask) == 0);
}
int Sign() const {
uint32_t d32 = AsUint32();
return (d32 & kSignMask) == 0 ? 1 : -1;
}
// Computes the two boundaries of this.
// The bigger boundary (m_plus) is normalized. The lower boundary has the same
// exponent as m_plus.
// Precondition: the value encoded by this Single must be greater than 0.
void NormalizedBoundaries(DiyFp* out_m_minus, DiyFp* out_m_plus) const {
DOUBLE_CONVERSION_ASSERT(value() > 0.0);
DiyFp v = this->AsDiyFp();
DiyFp m_plus = DiyFp::Normalize(DiyFp((v.f() << 1) + 1, v.e() - 1));
DiyFp m_minus;
if (LowerBoundaryIsCloser()) {
m_minus = DiyFp((v.f() << 2) - 1, v.e() - 2);
} else {
m_minus = DiyFp((v.f() << 1) - 1, v.e() - 1);
}
m_minus.set_f(m_minus.f() << (m_minus.e() - m_plus.e()));
m_minus.set_e(m_plus.e());
*out_m_plus = m_plus;
*out_m_minus = m_minus;
}
// Precondition: the value encoded by this Single must be greater or equal
// than +0.0.
DiyFp UpperBoundary() const {
DOUBLE_CONVERSION_ASSERT(Sign() > 0);
return DiyFp(Significand() * 2 + 1, Exponent() - 1);
}
bool LowerBoundaryIsCloser() const {
// The boundary is closer if the significand is of the form f == 2^p-1 then
// the lower boundary is closer.
// Think of v = 1000e10 and v- = 9999e9.
// Then the boundary (== (v - v-)/2) is not just at a distance of 1e9 but
// at a distance of 1e8.
// The only exception is for the smallest normal: the largest denormal is
// at the same distance as its successor.
// Note: denormals have the same exponent as the smallest normals.
bool physical_significand_is_zero = ((AsUint32() & kSignificandMask) == 0);
return physical_significand_is_zero && (Exponent() != kDenormalExponent);
}
float value() const { return uint32_to_float(d32_); }
static float Infinity() { return Single(kInfinity).value(); }
static float NaN() { return Single(kNaN).value(); }
private:
static const int kExponentBias = 0x7F + kPhysicalSignificandSize;
static const int kDenormalExponent = -kExponentBias + 1;
static const int kMaxExponent = 0xFF - kExponentBias;
static const uint32_t kInfinity = 0x7F800000;
static const uint32_t kNaN = 0x7FC00000;
const uint32_t d32_;
DOUBLE_CONVERSION_DISALLOW_COPY_AND_ASSIGN(Single);
};
} // namespace double_conversion
#endif // DOUBLE_CONVERSION_DOUBLE_H_

View file

@ -1,308 +0,0 @@
#ifndef DOUBLE_CONVERSION_UTILS_H_
#define DOUBLE_CONVERSION_UTILS_H_
#include "libc/assert.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#ifndef DOUBLE_CONVERSION_ASSERT
#define DOUBLE_CONVERSION_ASSERT(condition) assert(condition);
#endif
#ifndef DOUBLE_CONVERSION_UNIMPLEMENTED
#define DOUBLE_CONVERSION_UNIMPLEMENTED() (abort())
#endif
#ifndef DOUBLE_CONVERSION_NO_RETURN
#ifdef _MSC_VER
#define DOUBLE_CONVERSION_NO_RETURN __declspec(noreturn)
#else
#define DOUBLE_CONVERSION_NO_RETURN __attribute__((noreturn))
#endif
#endif
#ifndef DOUBLE_CONVERSION_UNREACHABLE
#ifdef _MSC_VER
void DOUBLE_CONVERSION_NO_RETURN abort_noreturn();
inline void abort_noreturn() { abort(); }
#define DOUBLE_CONVERSION_UNREACHABLE() (abort_noreturn())
#else
#define DOUBLE_CONVERSION_UNREACHABLE() (abort())
#endif
#endif
#ifndef DOUBLE_CONVERSION_UNUSED
#ifdef __GNUC__
#define DOUBLE_CONVERSION_UNUSED __attribute__((unused))
#else
#define DOUBLE_CONVERSION_UNUSED
#endif
#endif
// Double operations detection based on target architecture.
// Linux uses a 80bit wide floating point stack on x86. This induces double
// rounding, which in turn leads to wrong results.
// An easy way to test if the floating-point operations are correct is to
// evaluate: 89255.0/1e22. If the floating-point stack is 64 bits wide then
// the result is equal to 89255e-22.
// The best way to test this, is to create a division-function and to compare
// the output of the division with the expected result. (Inlining must be
// disabled.)
// On Linux,x86 89255e-22 != Div_double(89255.0/1e22)
//
// For example:
/*
// -- in div.c
double Div_double(double x, double y) { return x / y; }
// -- in main.c
double Div_double(double x, double y); // Forward declaration.
int main(int argc, char** argv) {
return Div_double(89255.0, 1e22) == 89255e-22;
}
*/
// Run as follows ./main || echo "correct"
//
// If it prints "correct" then the architecture should be here, in the "correct"
// section.
#if defined(_M_X64) || defined(__x86_64__) || defined(__ARMEL__) || \
defined(__avr32__) || defined(_M_ARM) || defined(_M_ARM64) || \
defined(__hppa__) || defined(__ia64__) || defined(__mips__) || \
defined(__nios2__) || defined(__powerpc__) || defined(__ppc__) || \
defined(__ppc64__) || defined(_POWER) || defined(_ARCH_PPC) || \
defined(_ARCH_PPC64) || defined(__sparc__) || defined(__sparc) || \
defined(__s390__) || defined(__SH4__) || defined(__alpha__) || \
defined(_MIPS_ARCH_MIPS32R2) || defined(__ARMEB__) || \
defined(__AARCH64EL__) || defined(__aarch64__) || \
defined(__AARCH64EB__) || defined(__riscv) || defined(__e2k__) || \
defined(__or1k__) || defined(__arc__) || defined(__microblaze__) || \
defined(__XTENSA__) || defined(__EMSCRIPTEN__) || defined(__wasm32__)
#define DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS 1
#elif defined(__mc68000__) || defined(__pnacl__) || defined(__native_client__)
#undef DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS
#elif defined(_M_IX86) || defined(__i386__) || defined(__i386)
#if defined(_WIN32)
// Windows uses a 64bit wide floating point stack.
#define DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS 1
#else
#undef DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS
#endif // _WIN32
#else
#error Target architecture was not detected as supported by Double-Conversion.
#endif
typedef uint16_t uc16;
// The following macro works on both 32 and 64-bit platforms.
// Usage: instead of writing 0x1234567890123456
// write DOUBLE_CONVERSION_UINT64_2PART_C(0x12345678,90123456);
#define DOUBLE_CONVERSION_UINT64_2PART_C(a, b) \
(((static_cast<uint64_t>(a) << 32) + 0x##b##u))
// The expression DOUBLE_CONVERSION_ARRAY_SIZE(a) is a compile-time constant of
// type size_t which represents the number of elements of the given array. You
// should only use DOUBLE_CONVERSION_ARRAY_SIZE on statically allocated arrays.
#ifndef DOUBLE_CONVERSION_ARRAY_SIZE
#define DOUBLE_CONVERSION_ARRAY_SIZE(a) \
((sizeof(a) / sizeof(*(a))) / \
static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))
#endif
// A macro to disallow the evil copy constructor and operator= functions
// This should be used in the private: declarations for a class
#ifndef DOUBLE_CONVERSION_DISALLOW_COPY_AND_ASSIGN
#define DOUBLE_CONVERSION_DISALLOW_COPY_AND_ASSIGN(TypeName) \
TypeName(const TypeName&); \
void operator=(const TypeName&)
#endif
// A macro to disallow all the implicit constructors, namely the
// default constructor, copy constructor and operator= functions.
//
// This should be used in the private: declarations for a class
// that wants to prevent anyone from instantiating it. This is
// especially useful for classes containing only static methods.
#ifndef DOUBLE_CONVERSION_DISALLOW_IMPLICIT_CONSTRUCTORS
#define DOUBLE_CONVERSION_DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
TypeName(); \
DOUBLE_CONVERSION_DISALLOW_COPY_AND_ASSIGN(TypeName)
#endif
namespace double_conversion {
inline int StrLength(const char* string) {
size_t length = strlen(string);
DOUBLE_CONVERSION_ASSERT(length ==
static_cast<size_t>(static_cast<int>(length)));
return static_cast<int>(length);
}
// This is a simplified version of V8's Vector class.
template <typename T>
class Vector {
public:
Vector() : start_(NULL), length_(0) {}
Vector(T* data, int len) : start_(data), length_(len) {
DOUBLE_CONVERSION_ASSERT(len == 0 || (len > 0 && data != NULL));
}
// Returns a vector using the same backing storage as this one,
// spanning from and including 'from', to but not including 'to'.
Vector<T> SubVector(int from, int to) {
DOUBLE_CONVERSION_ASSERT(to <= length_);
DOUBLE_CONVERSION_ASSERT(from < to);
DOUBLE_CONVERSION_ASSERT(0 <= from);
return Vector<T>(start() + from, to - from);
}
// Returns the length of the vector.
int length() const { return length_; }
// Returns whether or not the vector is empty.
bool is_empty() const { return length_ == 0; }
// Returns the pointer to the start of the data in the vector.
T* start() const { return start_; }
// Access individual vector elements - checks bounds in debug mode.
T& operator[](int index) const {
DOUBLE_CONVERSION_ASSERT(0 <= index && index < length_);
return start_[index];
}
T& first() { return start_[0]; }
T& last() { return start_[length_ - 1]; }
void pop_back() {
DOUBLE_CONVERSION_ASSERT(!is_empty());
--length_;
}
private:
T* start_;
int length_;
};
// Helper class for building result strings in a character buffer. The
// purpose of the class is to use safe operations that checks the
// buffer bounds on all operations in debug mode.
class StringBuilder {
public:
StringBuilder(char* buffer, int buffer_size)
: buffer_(buffer, buffer_size), position_(0) {}
~StringBuilder() {
if (!is_finalized()) Finalize();
}
int size() const { return buffer_.length(); }
// Get the current position in the builder.
int position() const {
DOUBLE_CONVERSION_ASSERT(!is_finalized());
return position_;
}
// Reset the position.
void Reset() { position_ = 0; }
// Add a single character to the builder. It is not allowed to add
// 0-characters; use the Finalize() method to terminate the string
// instead.
void AddCharacter(char c) {
DOUBLE_CONVERSION_ASSERT(c != '\0');
DOUBLE_CONVERSION_ASSERT(!is_finalized() && position_ < buffer_.length());
buffer_[position_++] = c;
}
// Add an entire string to the builder. Uses strlen() internally to
// compute the length of the input string.
void AddString(const char* s) { AddSubstring(s, StrLength(s)); }
// Add the first 'n' characters of the given string 's' to the
// builder. The input string must have enough characters.
void AddSubstring(const char* s, int n) {
DOUBLE_CONVERSION_ASSERT(!is_finalized() &&
position_ + n < buffer_.length());
DOUBLE_CONVERSION_ASSERT(static_cast<size_t>(n) <= strlen(s));
__builtin_memmove(&buffer_[position_], s, n);
position_ += n;
}
// Add character padding to the builder. If count is non-positive,
// nothing is added to the builder.
void AddPadding(char c, int count) {
for (int i = 0; i < count; i++) {
AddCharacter(c);
}
}
// Finalize the string by 0-terminating it and returning the buffer.
char* Finalize() {
DOUBLE_CONVERSION_ASSERT(!is_finalized() && position_ < buffer_.length());
buffer_[position_] = '\0';
// Make sure nobody managed to add a 0-character to the
// buffer while building the string.
DOUBLE_CONVERSION_ASSERT(strlen(buffer_.start()) ==
static_cast<size_t>(position_));
position_ = -1;
DOUBLE_CONVERSION_ASSERT(is_finalized());
return buffer_.start();
}
private:
Vector<char> buffer_;
int position_;
bool is_finalized() const { return position_ < 0; }
DOUBLE_CONVERSION_DISALLOW_IMPLICIT_CONSTRUCTORS(StringBuilder);
};
// The type-based aliasing rule allows the compiler to assume that pointers of
// different types (for some definition of different) never alias each other.
// Thus the following code does not work:
//
// float f = foo();
// int fbits = *(int*)(&f);
//
// The compiler 'knows' that the int pointer can't refer to f since the types
// don't match, so the compiler may cache f in a register, leaving random data
// in fbits. Using C++ style casts makes no difference, however a pointer to
// char data is assumed to alias any other pointer. This is the 'memcpy
// exception'.
//
// Bit_cast uses the memcpy exception to move the bits from a variable of one
// type of a variable of another type. Of course the end result is likely to
// be implementation dependent. Most compilers (gcc-4.2 and MSVC 2005)
// will completely optimize BitCast away.
//
// There is an additional use for BitCast.
// Recent gccs will warn when they see casts that may result in breakage due to
// the type-based aliasing rule. If you have checked that there is no breakage
// you can use BitCast to cast one pointer type to another. This confuses gcc
// enough that it can no longer see that you have cast one pointer type to
// another thus avoiding the warning.
template <class Dest, class Source>
Dest BitCast(const Source& source) {
// Compile time assertion: sizeof(Dest) == sizeof(Source)
// A compile error here means your Dest and Source have different sizes.
#if __cplusplus >= 201103L
static_assert(sizeof(Dest) == sizeof(Source));
#else
DOUBLE_CONVERSION_UNUSED
typedef char VerifySizesAreEqual[sizeof(Dest) == sizeof(Source) ? 1 : -1];
#endif
Dest dest;
memmove(&dest, &source, sizeof(dest));
return dest;
}
template <class Dest, class Source>
Dest BitCast(Source* source) {
return BitCast<Dest>(reinterpret_cast<uintptr_t>(source));
}
} // namespace double_conversion
#endif // DOUBLE_CONVERSION_UTILS_H_

View file

@ -1,248 +0,0 @@
Change Log
==========
All notable changes to the project are documented in this file.
[1.16.1] - 2019-06-07
---------------------
### Changes
- Major updates to the `editline.3` man page
- Cleanup of examples `cli.c` and `fileman.c`
- Add example of hidden input prompt to `cli.c`
### Fixes
- Fix #20: `configure --disable-eof` does not bite
- Fix #23: Make Ctrl-L clear the screan instead of starting a new line
Like Ctrl-D, which exits, Ctrl-L only clears the screen when the line
is empty and the cursor is at the start of the line, otherwise Ctrl-L
will redraw/refresh the current line.
- Fix #24: Fix behavior when TTY is narrower than column width, by Will Dietz
- Fix #25: Avoid continuously duplicate commands in history
- Fix #31: Aborting i-search with Ctrl-C should not generate signal
[1.16.0][] - 2018-09-16
-----------------------
Event loop callback support.
### Changes
- `rl_unintialize()`, new function to free all memory, by Claus Fischer
- `rl_insert_text()`, new GNU Readline compat function
- `rl_refresh_line()`, new GNU Readline compat function
- `rl_callback_*()`, alternate interface to plain `readline()` for event
loops. Modeled after the GNU Readline API
- `rl_completion_entry_function`, and `rl_attempted_completion_function`
are two new GNU Readline compat user hooks for the completion framework
- `rl_completion_matches()` and `rl_filename_completion_function()`
are two new GNU Readline compat functions
- Add new example: `fileman.c` from GNU Readline to demonstrate the
level of compatibility of the revamped completion framework
- Add support for Ctrl-Right and Ctrl-Left, forward/backward word
- Add .deb package to official release target
### Fixes
- Fixed header guards, avoid using leading `__`
- Spell check fixes
- Remove duplicate code in history check
- Use `NULL` instead of `0`, and `-1` instead of `NULL`, where applicable
- Misc. minor Coverity Scan fixes
- Misc. minor fixes to `testit.c` example code
- Add `-Wextra` to std `CFLAGS`
- Check `fclose()` return value in in `write_history()` and `read_history()`
- Initialize global variables and reset to `NULL` on `free()`
- Fix off-by-one in forward kill word, avoid deleting too much
- Skip (or kill) leading whitespace when skipping (or killing) forwards
[1.15.3][] - 2017-09-07
-----------------------
Bug fix release.
### Changes
- Refactor all enable/disable configure options, same problem as in #7
### Fixes
- Fix #7: `--enable-termcap` configure option does not work. The script
enabled termcap by default rather than the other way around.
Also, check for terminfo as well, when `--enable-termcap` is selected.
[1.15.2][] - 2016-06-06
-----------------------
Bug fixes and minor feature creep in `pkg-config` support.
### Changes
- Prevent mangling of symbols when linking with C++. Patch courtesy of
Jakub Pawlowski
- Add `libeditline.pc` for `pkg-config`
### Fixes
- Do not assume a termcap library exists, check for `tgetent()` in
curses, ncurses, tinfo and termcap libraries
- Call `tty_flush()` when user calls `rl_forced_update_display()`
to prevent screen becoming garbled. Patch by Jakub Pawlowski
[1.15.1][] - 2015-11-16
-----------------------
Bug fixes only.
### Changes
- Update README with origin of this version of editline
### Fixes
- Fix build system, don't force automake v1.11, require at least v1.11
- Fix build problem with examples using `--enable-termcap`
[1.15.0][] - 2015-09-10
-----------------------
### Changes
- Add support for `--disable-eof` and `--disable-sigint` to disable
default Ctrl-D and Ctrl-C behavior
- Add support for `el_no_hist` to disable access to and auto-save of history
- GNU readline compat functions for prompt handling and redisplay
- Refactor: replace variables named 'new' with non-reserved word
- Add support for [Travis-CI][], continuous integration with GitHub
- Add support for [Coverity Scan][], the best static code analyzer,
integrated with [Travis-CI][] -- scan runs for each push to master
- Rename NEWS.md --> ChangeLog.md, with symlinks for <kbd>make install</kbd>
- Attempt to align with http://keepachangelog.com/ for this file
- Cleanup and improve Markdown syntax in [README.md][]
- Add API and example to [README.md][], inspired by [libuEv][]
- Removed generated files from version control. Use `./autogen.sh`
to generate the `configure` script when working from GIT. This
does not affect distributed tarballs
### Fixes
- Fix issue #2, regression in Ctrl-D (EOF) behavior. Regression
introduced in [1.14.1][]. Fixed by @TobyGoodwin
- Fix memory leak in completion handler. Found by [Coverity Scan][].
- Fix suspicious use of `sizeof(char **)`, same as `sizeof(char *)` but
non-portable. Found by [Coverity Scan][]
- Fix out-of-bounds access in user key binding routines
Found by [Coverity Scan][].
- Fix invisible example code in man page
[1.14.2][] - 2014-09-14
-----------------------
Bug fixes only.
### Fixes
- Fix `el_no_echo` bug causing secrets to leak when disabling no-echo
- Handle `EINTR` in syscalls better
[1.14.1][] - 2014-09-14
-----------------------
Minor fixes and additions.
### Changes
- Don't print status message on `stderr` in key binding funcions
- Export `el_del_char()`
- Check for and return pending signals when detected
- Allow custom key bindings ...
### Fixes
- Bug fixes ...
[1.14.0][] - 2010-08-10
-----------------------
Major cleanups and further merges with Debian editline package.
### Changes
- Merge in changes to `debian/` from `editline_1.12-6.debian.tar.gz`
- Migrate to use libtool
- Make `UNIQUE_HISTORY` configurable
- Make scrollback history (`HIST_SIZE`) configurable
- Configure options for toggling terminal bell and `SIGSTOP` (Ctrl-Z)
- Configure option for using termcap to read/control terminal size
- Rename Signal to `el_intr_pending`, from Festival speech-tools
- Merge support for capitalizing words (`M-c`) from Festival
speech-tools by Alan W Black <mailto:awb()cstr!ed!ac!uk>
- Fallback backspace handling, in case `tgetstr("le")` fails
### Fixes
- Cleanups and fixes thanks to the Sparse static code analysis tool
- Merge `el_no_echo` patch from Festival speech-tools
- Merge fixes from Heimdal project
- Completely refactor `rl_complete()` and `rl_list_possib()` with
fixes from the Heimdal project. Use `rl_set_complete_func()` and
`rl_set_list_possib_func()`. Default completion callbacks are now
available as a configure option `--enable-default-complete`
- Memory leak fixes
- Actually fix 8-bit handling by reverting old Debian patch
- Merge patch to improve compatibility with GNU readline, thanks to
Steve Tell from way back in 1997 and 1998
[1.13.0][] - 2010-03-09
-----------------------
Adaptations to Debian editline package.
### Changes
- Major version number bump, adapt to Jim Studt's v1.12
- Import `debian/` directory and adapt it to configure et al.
- Change library name to libeditline to distinguish it from BSD libedit
[0.3.0][] - 2009-02-08
----------------------
### Changes
- Support for ANSI arrow keys using <kbd>configure --enable-arrow-keys</kbd>
[0.2.3][] - 2008-12-02
----------------------
### Changes
- Patches from Debian package merged
- Support for custom command completion
[0.1.0][] - 2008-06-07
----------------------
### Changes
- First version, forked from Minix current 2008-06-06
[UNRELEASED]: https://github.com/troglobit/finit/compare/1.16.0...HEAD
[1.16.1]: https://github.com/troglobit/finit/compare/1.16.0...1.16.1
[1.16.0]: https://github.com/troglobit/finit/compare/1.15.3...1.16.0
[1.15.3]: https://github.com/troglobit/finit/compare/1.15.2...1.15.3
[1.15.2]: https://github.com/troglobit/finit/compare/1.15.1...1.15.2
[1.15.1]: https://github.com/troglobit/finit/compare/1.15.0...1.15.1
[1.15.0]: https://github.com/troglobit/finit/compare/1.14.2...1.15.0
[1.14.2]: https://github.com/troglobit/finit/compare/1.14.1...1.14.2
[1.14.1]: https://github.com/troglobit/finit/compare/1.14.0...1.14.1
[1.14.0]: https://github.com/troglobit/finit/compare/1.13.0...1.14.0
[1.13.0]: https://github.com/troglobit/finit/compare/0.3.0...1.13.0
[0.3.0]: https://github.com/troglobit/finit/compare/0.2.3...0.3.0
[0.2.3]: https://github.com/troglobit/finit/compare/0.1.0...0.2.3
[0.1.0]: https://github.com/troglobit/finit/compare/0.0.0...0.1.0
[libuEv]: http://github.com/troglobit/libuev
[Travis-CI]: https://travis-ci.org/troglobit/uftpd
[Coverity Scan]: https://scan.coverity.com/projects/2947
[README.md]: https://github.com/troglobit/editline/blob/master/README.md
<!--
-- Local Variables:
-- mode: markdown
-- End:
-->

View file

@ -1,18 +0,0 @@
Copyright 1992,1993 Simmule Turner and Rich Salz
All rights reserved.
This software is not subject to any license of the American Telephone
and Telegraph Company or of the Regents of the University of California.
Permission is granted to anyone to use this software for any purpose on
any computer system, and to alter it and redistribute it freely, subject
to the following restrictions:
1. The authors are not responsible for the consequences of use of this
software, no matter how awful, even if they arise from flaws in it.
2. The origin of this software must not be misrepresented, either by
explicit claim or by omission. Since few users ever read sources,
credits must appear in the documentation.
3. Altered versions must be plainly marked as such, and must not be
misrepresented as being the original software. Since few users
ever read sources, credits must appear in the documentation.
4. This notice may not be removed or altered.

View file

@ -1,362 +0,0 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/alg/alg.h"
#include "libc/calls/calls.h"
#include "libc/calls/struct/dirent.h"
#include "libc/fmt/fmt.h"
#include "libc/mem/mem.h"
#include "libc/str/str.h"
#include "third_party/editline/editline.h"
#include "third_party/editline/internal.h"
asm(".ident\t\"\\n\\n\
Cosmopolitan Linenoise (BSD-like license)\\n\
Copyright 2019 Justine Alexandra Roberts Tunney\\n\
Copyright 1992,1993 Simmule Turner and Rich Salz\\n\
All rights reserved.\\n\
\\n\
This software is not subject to any license of the American Telephone\\n\
and Telegraph Company or of the Regents of the University of California.\\n\
\\n\
Permission is granted to anyone to use this software for any purpose on\\n\
any computer system, and to alter it and redistribute it freely, subject\\n\
to the following restrictions:\\n\
1. The authors are not responsible for the consequences of use of this\\n\
software, no matter how awful, even if they arise from flaws in it.\\n\
2. The origin of this software must not be misrepresented, either by\\n\
explicit claim or by omission. Since few users ever read sources,\\n\
credits must appear in the documentation.\\n\
3. Altered versions must be plainly marked as such, and must not be\\n\
misrepresented as being the original software. Since few users\\n\
ever read sources, credits must appear in the documentation.\\n\
4. This notice may not be removed or altered.\"");
asm(".include \"libc/disclaimer.inc\"");
#define MAX_TOTAL_MATCHES (256 << sizeof(char *))
int rl_attempted_completion_over = 0;
rl_completion_func_t *rl_attempted_completion_function = NULL;
rl_compentry_func_t *rl_completion_entry_function = NULL;
/* Wrap strcmp() for qsort() -- weird construct to pass -Wcast-qual */
static int compare(const void *p1, const void *p2) {
char *const *v1 = (char *const *)p1;
char *const *v2 = (char *const *)p2;
return strcmp(*v1, *v2);
}
/* Fill in *avp with an array of names that match file, up to its length.
* Ignore . and .. . */
static int FindMatches(char *dir, char *file, char ***avp) {
char **av;
char **word;
char *p;
DIR *dp;
struct dirent *ep;
size_t ac;
size_t len;
size_t choices;
size_t total;
if ((dp = opendir(dir)) == NULL) return 0;
av = NULL;
ac = 0;
len = strlen(file);
choices = 0;
total = 0;
while ((ep = readdir(dp)) != NULL) {
p = ep->d_name;
if (p[0] == '.' && (p[1] == '\0' || (p[1] == '.' && p[2] == '\0')))
continue;
if (len && strncmp(p, file, len) != 0) continue;
choices++;
if ((total += strlen(p)) > MAX_TOTAL_MATCHES) {
/* This is a bit too much. */
while (ac > 0) free(av[--ac]);
continue;
}
if ((ac % MEM_INC) == 0) {
word = malloc(sizeof(char *) * (ac + MEM_INC));
if (!word) {
total = 0;
break;
}
if (ac) {
memcpy(word, av, ac * sizeof(char *));
free(av);
}
*avp = av = word;
}
if ((av[ac] = strdup(p)) == NULL) {
if (ac == 0) free(av);
total = 0;
break;
}
ac++;
}
/* Clean up and return. */
closedir(dp);
if (total > MAX_TOTAL_MATCHES) {
char many[sizeof(total) * 3];
p = many + sizeof(many);
*--p = '\0';
while (choices > 0) {
*--p = '0' + choices % 10;
choices /= 10;
}
while (p > many + sizeof(many) - 8) *--p = ' ';
if ((p = strdup(p)) != NULL) av[ac++] = p;
if ((p = strdup("choices")) != NULL) av[ac++] = p;
} else {
if (ac) qsort(av, ac, sizeof(char *), compare);
}
return ac;
}
/* Split a pathname into allocated directory and trailing filename parts. */
static int SplitPath(const char *path, char **dirpart, char **filepart) {
static char DOT[] = ".";
char *dpart;
char *fpart;
if ((fpart = strrchr(path, '/')) == NULL) {
if ((dpart = strdup(DOT)) == NULL) return -1;
if ((fpart = strdup(path)) == NULL) {
free(dpart);
return -1;
}
} else {
if ((dpart = strdup(path)) == NULL) return -1;
dpart[fpart - path + 1] = '\0';
if ((fpart = strdup(fpart + 1)) == NULL) {
free(dpart);
return -1;
}
}
*dirpart = dpart;
*filepart = fpart;
return 0;
}
static rl_complete_func_t *el_complete_func = NULL;
/* For compatibility with the Heimdal project. */
rl_complete_func_t *rl_set_complete_func(rl_complete_func_t *func) {
rl_complete_func_t *old = el_complete_func;
el_complete_func = func;
return old;
}
/* Attempt to complete the pathname, returning an allocated copy.
* Fill in *match if we completed it, or set it to 0 if ambiguous. */
char *el_filename_complete(char *pathname, int *match) {
char **av;
char *dir;
char *file;
char *path;
char *p;
size_t ac;
size_t end;
size_t i;
size_t j;
size_t len;
if (SplitPath((const char *)pathname, &dir, &file) < 0) return NULL;
if ((ac = FindMatches(dir, file, &av)) == 0) {
free(dir);
free(file);
return NULL;
}
p = NULL;
len = strlen(file);
if (ac == 1) {
/* Exactly one match -- finish it off. */
*match = 1;
j = strlen(av[0]) - len + 2;
p = malloc(sizeof(char) * (j + 1));
if (p) {
memcpy(p, av[0] + len, j);
len = strlen(dir) + strlen(av[0]) + 2;
path = malloc(sizeof(char) * len);
if (path) {
snprintf(path, len, "%s/%s", dir, av[0]);
rl_add_slash(path, p);
free(path);
}
}
} else {
*match = 0;
if (len) {
/* Find largest matching substring. */
for (i = len, end = strlen(av[0]); i < end; i++) {
for (j = 1; j < ac; j++) {
if (av[0][i] != av[j][i]) goto breakout;
}
}
breakout:
if (i > len) {
j = i - len + 1;
p = malloc(sizeof(char) * j);
if (p) {
memcpy(p, av[0] + len, j);
p[j - 1] = '\0';
}
}
}
}
/* Clean up and return. */
free(dir);
free(file);
for (i = 0; i < ac; i++) free(av[i]);
free(av);
return p;
}
char *rl_filename_completion_function(const char *text, int state) {
char *dir;
char *file;
static char **av;
static size_t i, ac;
if (!state) {
if (SplitPath(text, &dir, &file) < 0) return NULL;
ac = FindMatches(dir, file, &av);
free(dir);
free(file);
if (!ac) return NULL;
i = 0;
}
if (i < ac) return av[i++];
do {
free(av[--i]);
} while (i > 0);
return NULL;
}
/* Similar to el_find_word(), but used by GNU Readline API */
static char *rl_find_token(size_t *len) {
char *ptr;
int pos;
for (pos = rl_point; pos < rl_end; pos++) {
if (isspace(rl_line_buffer[pos])) {
if (pos > 0) pos--;
break;
}
}
ptr = &rl_line_buffer[pos];
while (pos >= 0 && !isspace(rl_line_buffer[pos])) {
if (pos == 0) break;
pos--;
}
if (ptr != &rl_line_buffer[pos]) {
*len = (size_t)(ptr - &rl_line_buffer[pos]);
return &rl_line_buffer[pos];
}
return NULL;
}
/*
* "uses an application-supplied generator function to generate the list
* of possible matches, and then returns the array of these matches. The
* caller should place the address of its generator function in
* rl_completion_entry_function"
*/
char **rl_completion_matches(const char *token,
rl_compentry_func_t *generator) {
int state = 0, num = 0;
char **array, *entry;
if (!generator) {
generator = rl_completion_entry_function;
if (!generator) generator = rl_filename_completion_function;
}
if (!generator) return NULL;
array = malloc(512 * sizeof(char *));
if (!array) return NULL;
while (num < 511 && (entry = generator(token, state))) {
state = 1;
array[num++] = entry;
}
array[num] = NULL;
if (!num) {
free(array);
return NULL;
}
return array;
}
static char *complete(char *token, int *match) {
size_t len = 0;
char *word, **words = NULL;
int start, end;
word = rl_find_token(&len);
if (!word) goto fallback;
start = word - rl_line_buffer;
end = start + len;
word = strndup(word, len);
if (!word) goto fallback;
rl_attempted_completion_over = 0;
words = rl_attempted_completion_function(word, start, end);
if (!rl_attempted_completion_over && !words)
words = rl_completion_matches(word, NULL);
if (words) {
int i = 0;
free(word);
word = NULL;
if (words[0]) word = strdup(words[0] + len);
while (words[i]) free(words[i++]);
free(words);
if (word) return word;
}
fallback:
return el_filename_complete(token, match);
}
/*
* First check for editline specific custom completion function, then
* for any GNU Readline compat, then fallback to filename completion.
*/
char *rl_complete(char *token, int *match) {
if (el_complete_func) return el_complete_func(token, match);
if (rl_attempted_completion_function) return complete(token, match);
return el_filename_complete(token, match);
}
static rl_list_possib_func_t *el_list_possib_func = NULL;
/* For compatibility with the Heimdal project. */
rl_list_possib_func_t *rl_set_list_possib_func(rl_list_possib_func_t *func) {
rl_list_possib_func_t *old = el_list_possib_func;
el_list_possib_func = func;
return old;
}
/* Default possible completions. */
int el_filename_list_possib(char *pathname, char ***av) {
char *dir;
char *file;
int ac;
if (SplitPath(pathname, &dir, &file) < 0) return 0;
ac = FindMatches(dir, file, av);
free(dir);
free(file);
return ac;
}
/* Return all possible completions. */
int rl_list_possib(char *token, char ***av) {
if (el_list_possib_func) return el_list_possib_func(token, av);
return el_filename_list_possib(token, av);
}

View file

@ -1,274 +0,0 @@
.Dd April 27, 2019
.Dt "THIRD_PARTY_EDITLINE" 30 "Cosmopolitan Field Manual"
.Os COSMOPOLITAN
.Sh NAME
.Nm "THIRD_PARTY_EDITLINE"
.Nd command-line editing library with history
.Sh SYNOPSIS
.Pp
.Sy #include "third_party/editline/editline.h"
.Pp
.Fn "char *readline" "const char *prompt"
.Fn "void add_history" "const char *line"
.Fn "int read_history" "const char *filename"
.Fn "int write_history" "const char *filename"
.Sh DESCRIPTION
.Nm
is a library that provides n line-editing interface with history. It
is intended to be functionally equivalent with the
.Nm readline
library provided by the Free Software Foundation, but much smaller. The
bulk of this manual page describes the basic user interface. More APIs,
both native and for
.Nm readline
compatibility ,
are also available. See the
.Cm editline.h
header file for details.
.Pp
The
.Fn readline
function displays the given
.Fa prompt
on stdout, waits for user input on stdin and then returns a line of text
with the trailing newline removed. The data is returned in a buffer
allocated with
.Xr malloc 3 ,
so the space should be released with
.Xr free 3
when the calling program is done with it.
.Pp
Each line returned is automatically saved in the internal history list,
unless it happens to be equal to the previous line. This is
configurable if you are building editline from source, i.e. if you would
rather like to call
.Fn add_history
manually.
.Pp
The
.Fn read_history
and
.Fn write_history
functions can be used to load and store the history of your application.
.Em Note:
these APIs do not do any tilde or environment variable expansion of the
given filename.
.Ss User Interface
A program that uses this library provides a simple emacs-like editing
interface to its users. A line may be edited before it is sent to the
calling program by typing either control characters or escape sequences.
A control character, shown as a caret followed by a letter, is typed by
holding down the control key while the letter is typed. For example,
.Cm ^A
is a control-A. An escape sequence is entered by typing the escape key
followed by one or more characters. The escape key is abbreviated as
.Cm ESC .
Note that unlike control keys, case matters in escape sequences;
.Cm ESC F
is not the same as
.Cm ESC f .
.Pp
An editing command may be typed anywhere on the line, not just at the
beginning. In addition, a return may also be typed anywhere on the
line, not just at the end.
.Pp
Most editing commands may be given a repeat count,
.Ar n ,
where
.Ar n
is a number. To enter a repeat count, type the escape key, the number,
and then the command to execute. For example,
.Cm ESC 4 ^f
moves forward four characters. If a command may be given a repeat count
then the text
.Cm [n]
is given at the end of its description.
.Pp
The following control characters are accepted:
.Pp
.Bl -tag -width "ESC DEL " -compact
.It ^A
Move to the beginning of the line
.It ^B
Move left (backwards) [n]
.It ^D
Delete character [n]
.It ^E
Move to end of line
.It ^F
Move right (forwards) [n]
.It ^G
Ring the bell
.It ^H
Delete character before cursor (backspace key) [n]
.It ^I
Complete filename (tab key); see below
.It ^J
Done with line (return key)
.It ^K
Kill to end of line (or column [n])
.It ^L
Redisplay line
.It ^M
Done with line (alternate return key)
.It ^N
Get next line from history [n]
.It ^P
Get previous line from history [n]
.It ^R
Search backward (forward if [n]) through history for text; prefixing the
string with a caret (^) forces it to match only at the beginning of a
history line
.It ^T
Transpose characters
.It ^V
Insert next character, even if it is an edit command
.It ^W
Wipe to the mark
.It ^X^X
Exchange current location and mark
.It ^Y
Yank back last killed text
.It ^[
Start an escape sequence (escape key)
.It ^]c
Move forward to next character
.Cm c
.It ^?
Delete character before cursor (delete key) [n]
.Ed
.Pp
The following escape sequences are provided:
.Pp
.Bl -tag -width "ESC DEL " -compact
.It ESC ^H
Delete previous word (backspace key) [n]
.It ESC DEL
Delete previous word (delete key) [n]
.It ESC SP
Set the mark (space key); see ^X^X and ^Y above
.It ESC\ .
Get the last (or [n]'th) word from previous line
.It ESC\ ?
Show possible completions; see below
.It ESC <
Move to start of history
.It ESC >
Move to end of history
.It ESC b
Move backward a word [n]
.It ESC d
Delete word under cursor [n]
.It ESC f
Move forward a word [n]
.It ESC l
Make word lowercase [n]
.It ESC m
Toggle if 8bit chars display normally or with an
.Ar M-
prefix
.It ESC u
Make word uppercase [n]
.It ESC y
Yank back last killed text
.It ESC v
Show library version
.It ESC w
Make area up to mark yankable
.It ESC nn
Set repeat count to the number nn
.It ESC C
Read from environment variable
.Ar $C ,
where
.Ar C
is an uppercase letter
.El
.Pp
The
.Nm
library has a small macro facility. If you type the escape key followed
by an uppercase letter,
.Ar C ,
then the contents of the environment variable
.Ar $C
are read in as if you had typed them at the keyboard. For example, if
the variable
.Ar $L
contains the following:
.Pp
.Dl ^A^Kecho '^V^[[H^V^[[2J'^M
.Pp
Then typing
.Cm ESC L
will move to the beginning of the line, kill the entire line, enter the
echo command needed to clear the terminal (if your terminal is like a
VT-100), and send the line back to the shell.
.Pp
The
.Nm
library also does filename completion. Suppose the root directory has
the following files in it:
.Pp
.Dl bin vmunix
.Dl core vmunix.old
.Pp
If you type
.Cm rm /v
and then the tab key,
.Nm
will then finish off as much of the name as possible by adding
.Ar munix .
Because the name is not unique, it will then beep. If you type the
escape key and a question mark, it will display the two choices. If you
then type a period and a tab, the library will finish off the filename
for you:
.Pp
.Bd -ragged -offset indent
rm /v[TAB]
.Em munix
\&.[TAB]
.Em old
.Ed
.Pp
The tab key is shown by [TAB] and the automatically-entered text
is shown in italics, or underline.
.Sh USAGE
To include
.Nm
in your program, call it as you do any other function and link your
program with
.Ar -leditline .
.Ss Example
The following brief example lets you enter a line and edit it, then displays it.
.Pp
.Bd -literal -offset indent
#include <stdio.h>
#include <stdlib.h>
#include <editline.h>
int main(void)
{
char *p;
while ((p = readline("CLI> "))) {
puts(p);
free(p);
}
return 0;
}
.El
.Sh AUTHORS
The original editline library was posted to comp.sources.unix newsgroup
by created by Simmule R. Turner and Rich Salz in 1992. It now exists in
several forks: Debian, Minix, Heimdal, Festival speech tools, Mozilla,
Google Gadgets for Linux, and many other places. The original manual
page was made by David W. Sanderson.
.Pp
This version was originally based on the Minix 2 sources, but has since
evolved to include patches from all relevant forks. It is currently
maintained by Joachim Nilsson at GitHub,
.Aq http://github.com/troglobit/editline
.Sh BUGS
Does not handle multiple lines well.

File diff suppressed because it is too large Load diff

View file

@ -1,91 +0,0 @@
#ifndef COSMOPOLITAN_THIRD_PARTY_EDITLINE_EDITLINE_H_
#define COSMOPOLITAN_THIRD_PARTY_EDITLINE_EDITLINE_H_
#include "libc/stdio/stdio.h"
#define CTL(x) ((x)&0x1F)
#define ISCTL(x) ((x) && (x) < ' ')
#define UNCTL(x) ((x) + 64)
#define META(x) ((x) | 0x80)
#define ISMETA(x) ((x)&0x80)
#define UNMETA(x) ((x)&0x7F)
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
typedef enum {
CSdone = 0, /* OK */
CSeof, /* Error, or EOF */
CSmove,
CSdispatch,
CSstay,
CSsignal
} el_status_t;
typedef int rl_list_possib_func_t(char *, char ***);
typedef el_status_t el_keymap_func_t(void);
typedef int rl_hook_func_t(void);
typedef int rl_getc_func_t(void);
typedef void rl_voidfunc_t(void);
typedef void rl_vintfunc_t(int);
typedef void rl_vcpfunc_t(char *);
compatfn typedef char *rl_complete_func_t(char *, int *);
compatfn typedef char *rl_compentry_func_t(const char *, int);
compatfn typedef char **rl_completion_func_t(const char *, int, int);
extern int rl_point;
extern int rl_mark;
extern int rl_end;
extern int rl_inhibit_complete;
extern char *rl_line_buffer;
extern const char *rl_readline_name;
extern FILE *rl_instream; /* The stdio stream from which input is read. Defaults
to stdin if NULL - Not supported yet! */
extern FILE *rl_outstream; /* The stdio stream to which output is flushed.
Defaults to stdout if NULL - Not supported yet! */
extern int el_no_echo; /* E.g under emacs, don't echo except prompt */
extern int el_no_hist; /* Disable auto-save of and access to history -- e.g. for
password prompts or wizards */
extern int el_hist_size; /* size of history scrollback buffer, default: 15 */
extern int rl_meta_chars; /* Display 8-bit chars "as-is" or as `M-x'? Toggle
with M-m. (Default:0 - "as-is") */
extern rl_completion_func_t *rl_attempted_completion_function;
char **rl_completion_matches(const char *, rl_compentry_func_t *);
char *el_find_word(void);
char *readline(const char *);
char *rl_complete(char *, int *);
char *rl_filename_completion_function(const char *, int);
const char *el_next_hist(void);
const char *el_prev_hist(void);
el_status_t el_bind_key(int, el_keymap_func_t);
el_status_t el_bind_key_in_metamap(int, el_keymap_func_t);
el_status_t el_del_char(void);
el_status_t el_ring_bell(void);
int read_history(const char *);
int rl_getc(void);
int rl_insert_text(const char *);
int rl_list_possib(char *, char ***);
int rl_refresh_line(int, int);
int write_history(const char *);
rl_complete_func_t *rl_set_complete_func(rl_complete_func_t *);
rl_getc_func_t *rl_set_getc_func(rl_getc_func_t *);
rl_list_possib_func_t *rl_set_list_possib_func(rl_list_possib_func_t *);
void add_history(const char *);
void el_print_columns(int, char **);
void rl_callback_handler_install(const char *, rl_vcpfunc_t *);
void rl_callback_handler_remove(void);
void rl_callback_read_char(void);
void rl_clear_message(void);
void rl_deprep_terminal(void);
void rl_forced_update_display(void);
void rl_initialize(void);
void rl_prep_terminal(int);
void rl_reset_terminal(const char *);
void rl_restore_prompt(void);
void rl_save_prompt(void);
void rl_set_prompt(const char *);
void rl_uninitialize(void);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_THIRD_PARTY_EDITLINE_EDITLINE_H_ */

View file

@ -1,57 +0,0 @@
#-*-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───────────────────────┘
PKGS += THIRD_PARTY_EDITLINE
THIRD_PARTY_EDITLINE_ARTIFACTS += THIRD_PARTY_EDITLINE_A
THIRD_PARTY_EDITLINE = $(THIRD_PARTY_EDITLINE_A_DEPS) $(THIRD_PARTY_EDITLINE_A)
THIRD_PARTY_EDITLINE_A = o/$(MODE)/third_party/editline/editline.a
THIRD_PARTY_EDITLINE_A_FILES := $(wildcard third_party/editline/*)
THIRD_PARTY_EDITLINE_A_HDRS = $(filter %.h,$(THIRD_PARTY_EDITLINE_A_FILES))
THIRD_PARTY_EDITLINE_A_SRCS = $(filter %.c,$(THIRD_PARTY_EDITLINE_A_FILES))
THIRD_PARTY_EDITLINE_A_OBJS = \
$(THIRD_PARTY_EDITLINE_A_SRCS:%=o/$(MODE)/%.zip.o) \
$(THIRD_PARTY_EDITLINE_A_SRCS:%.c=o/$(MODE)/%.o)
THIRD_PARTY_EDITLINE_A_CHECKS = \
$(THIRD_PARTY_EDITLINE_A).pkg
THIRD_PARTY_EDITLINE_A_DIRECTDEPS = \
LIBC_ALG \
LIBC_CALLS \
LIBC_CALLS_HEFTY \
LIBC_FMT \
LIBC_LOG \
LIBC_MEM \
LIBC_NEXGEN32E \
LIBC_STDIO \
LIBC_STR \
LIBC_STUBS \
LIBC_SYSV
THIRD_PARTY_EDITLINE_A_DEPS := \
$(call uniq,$(foreach x,$(THIRD_PARTY_EDITLINE_A_DIRECTDEPS),$($(x))))
$(THIRD_PARTY_EDITLINE_A): \
third_party/editline/ \
$(THIRD_PARTY_EDITLINE_A).pkg \
$(THIRD_PARTY_EDITLINE_A_OBJS)
$(THIRD_PARTY_EDITLINE_A).pkg: \
$(THIRD_PARTY_EDITLINE_A_OBJS) \
$(foreach x,$(THIRD_PARTY_EDITLINE_A_DIRECTDEPS),$($(x)_A).pkg)
THIRD_PARTY_EDITLINE_LIBS = $(foreach x,$(THIRD_PARTY_EDITLINE_ARTIFACTS),$($(x)))
THIRD_PARTY_EDITLINE_SRCS = $(foreach x,$(THIRD_PARTY_EDITLINE_ARTIFACTS),$($(x)_SRCS))
THIRD_PARTY_EDITLINE_HDRS = $(foreach x,$(THIRD_PARTY_EDITLINE_ARTIFACTS),$($(x)_HDRS))
THIRD_PARTY_EDITLINE_BINS = $(foreach x,$(THIRD_PARTY_EDITLINE_ARTIFACTS),$($(x)_BINS))
THIRD_PARTY_EDITLINE_CHECKS = $(foreach x,$(THIRD_PARTY_EDITLINE_ARTIFACTS),$($(x)_CHECKS))
THIRD_PARTY_EDITLINE_OBJS = $(foreach x,$(THIRD_PARTY_EDITLINE_ARTIFACTS),$($(x)_OBJS))
THIRD_PARTY_EDITLINE_TESTS = $(foreach x,$(THIRD_PARTY_EDITLINE_ARTIFACTS),$($(x)_TESTS))
$(THIRD_PARTY_EDITLINE_OBJS): third_party/editline/editline.mk
.PHONY: o/$(MODE)/third_party/editline
o/$(MODE)/third_party/editline: \
$(THIRD_PARTY_EDITLINE) \
$(THIRD_PARTY_EDITLINE_CHECKS)

View file

@ -1,21 +0,0 @@
#ifndef COSMOPOLITAN_THIRD_PARTY_EDITLINE_INTERNAL_H_
#define COSMOPOLITAN_THIRD_PARTY_EDITLINE_INTERNAL_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
#define MEM_INC 64
#define SCREEN_INC 256
extern int rl_eof;
extern int rl_erase;
extern int rl_intr;
extern int rl_kill;
extern int rl_quit;
extern int rl_susp;
void rl_ttyset(int);
void rl_add_slash(char *, char *);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_THIRD_PARTY_EDITLINE_INTERNAL_H_ */

View file

@ -1,112 +0,0 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/calls/calls.h"
#include "libc/calls/struct/stat.h"
#include "libc/calls/termios.h"
#include "libc/errno.h"
#include "libc/log/log.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/termios.h"
#include "third_party/editline/editline.h"
#include "third_party/editline/internal.h"
asm(".ident\t\"\\n\\n\
Cosmopolitan Linenoise (BSD-like license)\\n\
Copyright 2019 Justine Alexandra Roberts Tunney\\n\
Copyright 1992,1993 Simmule Turner and Rich Salz\\n\
All rights reserved.\\n\
\\n\
This software is not subject to any license of the American Telephone\\n\
and Telegraph Company or of the Regents of the University of California.\\n\
\\n\
Permission is granted to anyone to use this software for any purpose on\\n\
any computer system, and to alter it and redistribute it freely, subject\\n\
to the following restrictions:\\n\
1. The authors are not responsible for the consequences of use of this\\n\
software, no matter how awful, even if they arise from flaws in it.\\n\
2. The origin of this software must not be misrepresented, either by\\n\
explicit claim or by omission. Since few users ever read sources,\\n\
credits must appear in the documentation.\\n\
3. Altered versions must be plainly marked as such, and must not be\\n\
misrepresented as being the original software. Since few users\\n\
ever read sources, credits must appear in the documentation.\\n\
4. This notice may not be removed or altered.\"");
asm(".include \"libc/disclaimer.inc\"");
/* Wrapper for tcgetattr */
static int getattr(int fd, struct termios *arg) {
int result, retries = 3;
while (-1 == (result = tcgetattr(fd, arg)) && retries > 0) {
retries--;
if (EINTR == errno) continue;
break;
}
return result;
}
/* Wrapper for tcgetattr */
static int setattr(int fd, int opt, const struct termios *arg) {
int result, retries = 3;
while (-1 == (result = tcsetattr(fd, opt, arg)) && retries > 0) {
retries--;
if (EINTR == errno) continue;
break;
}
return result;
}
void rl_ttyset(int Reset) {
static struct termios old;
struct termios new;
if (!Reset) {
if (-1 == getattr(0, &old)) {
perror("Failed tcgetattr()");
}
rl_erase = old.c_cc[VERASE];
rl_kill = old.c_cc[VKILL];
rl_eof = old.c_cc[VEOF];
rl_intr = old.c_cc[VINTR];
rl_quit = old.c_cc[VQUIT];
#ifdef CONFIG_SIGSTOP
rl_susp = old.c_cc[VSUSP];
#endif
new = old;
new.c_lflag &= ~(ECHO | ICANON | ISIG);
new.c_iflag &= ~INPCK;
if (rl_meta_chars)
new.c_iflag |= ISTRIP;
else
new.c_iflag &= ~ISTRIP;
new.c_cc[VMIN] = 1;
new.c_cc[VTIME] = 0;
if (-1 == setattr(0, TCSADRAIN, &new)) {
perror("Failed tcsetattr(TCSADRAIN)");
}
} else {
if (-1 == setattr(0, TCSADRAIN, &old)) {
perror("Failed tcsetattr(TCSADRAIN)");
}
}
}
void rl_add_slash(char *path, char *p) {
struct stat Sb;
if (stat(path, &Sb) >= 0) strcat(p, S_ISDIR(Sb.st_mode) ? "/" : " ");
}

View file

@ -1,43 +0,0 @@
.ident "\n
Flex carries the copyright used for BSD software, slightly modified
because it originated at the Lawrence Berkeley (not Livermore!) Laboratory,
which operates under a contract with the Department of Energy:
Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 The Flex Project.
Copyright (c) 1990, 1997 The Regents of the University of California.
All rights reserved.
This code is derived from software contributed to Berkeley by
Vern Paxson.
The United States Government has rights in this work pursuant
to contract no. DE-AC03-76SF00098 between the United States
Department of Energy and the University of California.
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.
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 ``AS IS'' AND WITHOUT ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE.
This basically says \"do whatever you please with this software except
remove this notice or take advantage of the University's (or the flex
authors') name\".
Note that the \"flex.skl\" scanner skeleton carries no copyright notice.
You are free to do whatever you please with scanners generated using flex;
for them, you are not even bound by the above copyright."

File diff suppressed because it is too large Load diff

View file

@ -1,211 +0,0 @@
/* clang-format off */
/* $OpenBSD: FlexLexer.h,v 1.7 2015/11/19 19:43:40 tedu Exp $ */
// $Header: /cvs/src/usr.bin/lex/FlexLexer.h,v 1.7 2015/11/19 19:43:40 tedu Exp $
// -*-C++-*-
// FlexLexer.h -- define interfaces for lexical analyzer classes generated
// by flex
// Copyright (c) 1993 The Regents of the University of California.
// All rights reserved.
//
// This code is derived from software contributed to Berkeley by
// Kent Williams and Tom Epperly.
//
// 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.
// 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR
// IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE.
// This file defines FlexLexer, an abstract class which specifies the
// external interface provided to flex C++ lexer objects, and yyFlexLexer,
// which defines a particular lexer class.
//
// If you want to create multiple lexer classes, you use the -P flag
// to rename each yyFlexLexer to some other xxFlexLexer. You then
// include <FlexLexer.h> in your other sources once per lexer class:
//
// #undef yyFlexLexer
// #define yyFlexLexer xxFlexLexer
// #include <FlexLexer.h>
//
// #undef yyFlexLexer
// #define yyFlexLexer zzFlexLexer
// #include <FlexLexer.h>
// ...
#ifndef __FLEX_LEXER_H
// Never included before - need to define base class.
#define __FLEX_LEXER_H
#include <iostream>
# ifndef FLEX_STD
# define FLEX_STD std::
# endif
extern "C++" {
struct yy_buffer_state;
typedef int yy_state_type;
class FlexLexer {
public:
virtual ~FlexLexer() { }
const char* YYText() const { return yytext; }
int YYLeng() const { return yyleng; }
virtual void
yy_switch_to_buffer( struct yy_buffer_state* new_buffer ) = 0;
virtual struct yy_buffer_state*
yy_create_buffer( FLEX_STD istream* s, int size ) = 0;
virtual void yy_delete_buffer( struct yy_buffer_state* b ) = 0;
virtual void yyrestart( FLEX_STD istream* s ) = 0;
virtual int yylex() = 0;
// Call yylex with new input/output sources.
int yylex( FLEX_STD istream* new_in, FLEX_STD ostream* new_out = 0 )
{
switch_streams( new_in, new_out );
return yylex();
}
// Switch to new input/output streams. A nil stream pointer
// indicates "keep the current one".
virtual void switch_streams( FLEX_STD istream* new_in = 0,
FLEX_STD ostream* new_out = 0 ) = 0;
int lineno() const { return yylineno; }
int debug() const { return yy_flex_debug; }
void set_debug( int flag ) { yy_flex_debug = flag; }
protected:
char* yytext;
int yyleng;
int yylineno; // only maintained if you use %option yylineno
int yy_flex_debug; // only has effect with -d or "%option debug"
};
}
#endif // FLEXLEXER_H
#if defined(yyFlexLexer) || ! defined(yyFlexLexerOnce)
// Either this is the first time through (yyFlexLexerOnce not defined),
// or this is a repeated include to define a different flavor of
// yyFlexLexer, as discussed in the flex manual.
#define yyFlexLexerOnce
extern "C++" {
class yyFlexLexer : public FlexLexer {
public:
// arg_yyin and arg_yyout default to the cin and cout, but we
// only make that assignment when initializing in yylex().
yyFlexLexer( FLEX_STD istream* arg_yyin = 0, FLEX_STD ostream* arg_yyout = 0 );
virtual ~yyFlexLexer();
void yy_switch_to_buffer( struct yy_buffer_state* new_buffer );
struct yy_buffer_state* yy_create_buffer( FLEX_STD istream* s, int size );
void yy_delete_buffer( struct yy_buffer_state* b );
void yyrestart( FLEX_STD istream* s );
void yypush_buffer_state( struct yy_buffer_state* new_buffer );
void yypop_buffer_state();
virtual int yylex();
virtual void switch_streams( FLEX_STD istream* new_in, FLEX_STD ostream* new_out = 0 );
virtual int yywrap();
protected:
virtual int LexerInput( char* buf, int max_size );
virtual void LexerOutput( const char* buf, int size );
virtual void LexerError( const char* msg );
void yyunput( int c, char* buf_ptr );
int yyinput();
void yy_load_buffer_state();
void yy_init_buffer( struct yy_buffer_state* b, FLEX_STD istream* s );
void yy_flush_buffer( struct yy_buffer_state* b );
int yy_start_stack_ptr;
int yy_start_stack_depth;
int* yy_start_stack;
void yy_push_state( int new_state );
void yy_pop_state();
int yy_top_state();
yy_state_type yy_get_previous_state();
yy_state_type yy_try_NUL_trans( yy_state_type current_state );
int yy_get_next_buffer();
FLEX_STD istream* yyin; // input source for default LexerInput
FLEX_STD ostream* yyout; // output sink for default LexerOutput
// yy_hold_char holds the character lost when yytext is formed.
char yy_hold_char;
// Number of characters read into yy_ch_buf.
int yy_n_chars;
// Points to current character in buffer.
char* yy_c_buf_p;
int yy_init; // whether we need to initialize
int yy_start; // start state number
// Flag which is used to allow yywrap()'s to do buffer switches
// instead of setting up a fresh yyin. A bit of a hack ...
int yy_did_buffer_switch_on_eof;
size_t yy_buffer_stack_top; /**< index of top of stack. */
size_t yy_buffer_stack_max; /**< capacity of stack. */
struct yy_buffer_state ** yy_buffer_stack; /**< Stack as an array. */
void yyensure_buffer_stack(void);
// The following are not always needed, but may be depending
// on use of certain flex features (like REJECT or yymore()).
yy_state_type yy_last_accepting_state;
char* yy_last_accepting_cpos;
yy_state_type* yy_state_buf;
yy_state_type* yy_state_ptr;
char* yy_full_match;
int* yy_full_state;
int yy_full_lp;
int yy_lp;
int yy_looking_for_trail_begin;
int yy_more_flag;
int yy_more_len;
int yy_more_offset;
int yy_prev_more_offset;
};
}
#endif // yyFlexLexer || ! yyFlexLexerOnce

532
third_party/lex/NEWS vendored
View file

@ -1,532 +0,0 @@
This is the file NEWS for the flex package. It records user -visible
changes between releases of flex.
See the file COPYING for copying conditions.
* flex version 2.5.39
** no user visible changes in this release
* version 2.5.38 released 2014-02-14
** internationalization
*** add sr translation from the translation project
*** update da, es, ko, nl, pt_BR, ro, ru, sv, tr, vi, zh_CN translations from the translation project
*** rename zh_tw to its proper zh_TW name
* version 2.5.37 released 2012-08-03
** Import flex into git. See
git://flex.git.sourceforge.net/gitroot/flex/flex.
** Fix make install target to not fail when the flex++ program is
already installed
** New translations from the translation project: de, fi, pl, vi
* version 2.5.36 released 2012-07-20
** various portability fixes that quiet compiler warnings on 64-bit
hosts
** various manual fixes, including correcting the name of a %option and
updating some simple examples to use ANSI C syntax
** various bug fixes that prevent certain error conditions from
persisting when they should not persist
** improvements to the test suite so it behaves better when linking
compiled files
** new translations from the translation project: ca, da, es, fi, fr,
ga, ko, pt_br, ro, ru, sv, tr, zh_cn
** the flex distribution is now built with automake 1.10.1 and automake
2.61
* version 2.5.35 released 2008-02-26
** fixed bug that prevented flex from accepting certain comments in the
scanner file (resolves bugs #1849809 and #1849805)
** fix bug that prevented headers for all functions from being generated
(resolves bug #1628314)
** change yy_size_t to be size_t (resolves bug #1849812)
** new de, nl, pl, pt_br, vi translations from the translation project
* version 2.5.34 released 2007-12-12
** introduce yylex_init_extra; see the manual for details
** introduce %option extra-type="your_type *" (resolves bug #1744505)
** The flex program now parses multiple short concatenated options (resolves bug
#1619820). Thanks to Petr Machata of Red Hat on this issue.
** better checking after yyalloc/yyrealloc (resolves bug #1595967)
** flex now provides for a libfl_pic.a compiled with position
independent code. Particularly useful when including a flex scanner
in a shared library and with more recent versions of gcc. Thanks to the Debian project for the idea.
** SourceForge feature request #1658379: Expose YY_BUF_SIZE in the
header file.
** flex better escapes filenames with special characters in them
(resolves bug #1623600)
** a memory leak was plugged(resolves bug #1601111)
** pattern language expanded; see the manual for details on the below
highlights
*** pattern options added to specify patterns as case-insensitive or
case-sensitive
*** pattern options to specify whether the "." character should match
the newline character
*** pattern options added to allow ignoring of whitespace in patterns
*** POSIX character classes may be negated in patterns
*** patterns may now use set difference, union operators
** the manual now contains an appendix listing various common patterns
which may be useful when writing scanners
** some memory leaks were removed from the C++ scanner (but the C++
scanner is still experimental and may change radically without
notice)
** c++ scanners can now use yywrap
** added new unit test for c++ and yywrap
** portability fixes to some unit tests
** flex man page and flex manual in pdf now distributed in the flex
distribution
** new ca, vi, ga, nl translations from the translation project
** flex no longer comes with an rpm spec file
** flex development now happens with automake 1.9.6
* version 2.5.33 released 2006-2-20
** all flex resources are now to be found from the website at
http://flex.sourceforge.net/
** there was no release 2.5.32 published
** numerous bug and security fixes
** new nl, vi, sv, ro, po, ga, ca, fr, tr translations from the translation project
** upgrade to use gettext 0.12 (this now makes the "pdf" and "ps"
targets in the build system able to be run successfully)
* version 2.5.31 released 2003-4-1
** remove --enable-maintainer-mode configure option; none of the
Makefiles were using it and it can be unduely confusing
* version 2.5.30 released 2003-4-1
** yylineno is per-buffer in reentrant scanners
** added %top directive for placing code at the top of the generated
scanner; see manual for details
** flex now uses m4 to generate scanners; while this means that
scanners are more readable, it means that flex requires m4 to be
installed; see manual for details
* version 2.5.29 released 2003-3-5
** Automatic stack management for multiple input buffers in C and C++ scanners
** moved the flex documentation to a new doc/ subdirectory
** cleanups to the yy namespace
* version 2.5.28 released 2003-2-12
** flex is now hosted at sourceforge
** Fixed trailing slash bug in YY_INPUT macro def
** Flex now warns if always-interactive is specified with fast or full
* version 2.5.27 released 2003-1-21
** flex now works with recent bison versions
** new pt_br translation from the translation project
* version 2.5.26 released 2003-1-14
** Fixed table deserialization bug on big-endian archs. Patch sent from Bryce Nichols <bryce@bnichols.org>
** yyleng has proper declarations now; this caused flex to generate
unusable scanners for some programs
** the flex distribution now includes a spec file suitable for use
with rpm
** some more c++ fixes
** new es translation from the translation project
** slight tweeks to the flex_int*_t types
** flex now warns about pattern ranges that might be ambiguous when
generating a case-insensitive scanner
* version 2.5.25 released 2002-12-2
** flex now uses flex_int*_t types. For C99 systems, they are just the
int*_t types; for non-C99 systems, we just make some typedefs
** new pt_br translation from the translation project
* version 2.5.24 released 2002-11-25
* more portability fixes
** the manual continues to be updated and edited, but it's still got a
ways to go
** it is possible to have multiple c++ scanners in the same program again
** new turkish translation from the translation project
* version 2.5.23 released 2002-10-21
** more portability fixes
** the manual includes a title page and a table-of-contents when printed
** the test suite can be run with "make check" from the top-level
directory
** configure now accepts the --enable-maintainer-mode option
** gettext functionality is now only available externally
** the constant FLEX_BETA is defined if flex is a beta release
** the script create-test was not included in the distribution and it
should have been
* version 2.5.22 released 2002-10-10
** more portability fixes around how we get ahold of the integral
types; there is a constant FLEX_NEED_INTEGRAL_TYPE_DEFINITIONS
which you should define if you don't have the <inttypes.h> header
file (after you complain to your C vendor for not providing a
reasonable C environment)
** more test suite cleanups; in particular, the test suite should run
correctly when build from a different directory
** upgraded automake to 1.7 and consequently autoconf to 2.54; this
means, among other things, that there is some support for
formatting the manual in postscript and pdf in the distributed
Makefile.in (and therefore in the Makefile built by configure)
** the flex.1 manpage is generated by help2man; (this has been true
for quite a while but was not listed here)
** flex now includes three defined constants to indicate which version
of flex generated a scanner (YY_FLEX_{MAJOR,MINOR,SUBMINOR}_VERSION)
** flex tries its best to output only the relevant portions of the
skeleton when generating a scanner, thus avoiding as much
conditional compilation as possible
* version 2.5.21 released 2002-9-17
** one of the tests in the test suite broke the dist target
* version 2.5.20 released 2002-9-16
** A flex scanner has the ability to save the DFA tables to a file,
and load them at runtime when needed; see the manual for details
** Added %option bison-bridge (--bison-bridge)
** Removed %option reentrant-bison/--reentrant-bison/-Rb
** yylineno is present in all scanners; Modified nasty performance
penalty warning with yylineno in documentation
** test-table-opts is now run last in the test suite because it's so fat
** flex can, to some extent, diagnose where internal problems occur
** new translations from the translation project: fr, ca, de, ru, sv
**Flex generates C99 defs now; see YY_TRADITIONAL_FUNC_DEFS in the
manual if that's not a good thing for you
* version 2.5.19 released 2002-9-5
** prevent segfault on input lines which are longer than the allocated
space (problem report from Manoj Srivastava
<srivasta@golden-gryphon.com>)
** Changed option 'header' to 'header-file'
* version 2.5.18 released 2002-9-4
** portability fixes for integer constants and in the way the test
suite reports its results
** the test for bison was reporting bison missing when it was, in
fact, found
** if we don't find GNU indent, we're more careful when we're not
finding it
* version 2.5.17 released 2002-8-29
** more portability fixes
** updated config.sub and config.guess
** flex is indented by GNU indent (this was done earlier but not
explicitly documented)
* version 2.5.16 released 2002-8-28
** c++ scanners compile again
** there is now an indent target in the top-level Makefile; configure
checks for GNU indent which is required for proper operation of the
indent target
** some more portability fixes were made
** %options and invocation sections of manual merged
** a c++ test was added to the test suite
** we're trying to clean up more files in the test suite's make clean
targets
* version 2.5.15 released 2002-8-21
** reject-state buffer is now dynamically allocated and REJECT buffer
variables are reentrant-safe
** manual now discusses memory usage
** skeleton now processed by m4 before mkskel.sh; (this only matters
if you want to change the skeleton or if you're doing flex development)
** zh_cn translation added from translation project
** a bug that caused a segfault has now been fixed
** the test suite now respects the usual CFLAGS, etc. variables
** removed some warnings which some tests trigggered with the -s option
** the flex-generated header file now tries to be smarter about
conditionally including start conditions
** tables code omitted from generated scanner when not used
* version 2.5.14 released 2002-8-15
** the tests using the reentrant c scanner as c++ were reworked
slightly to be sure that the c++ was enforced
** de translation now included in the distribution
** various portability fixes regarding nls support, c++ include
headers, etc.
* version 2.5.13 released 2002-8-15
** the header file output with %option header is now much smaller
** Fixed type mismatch in printf in scanner skeleton
** yylex_init now reports errors
* version 2.5.12 released 2002-8-8
** updated gettext support to 0.11.5
** new fr translation from the translation project
** bison is no longer needed to build flex; If you are building flex
from a release (i.e., not from a cvs snapshot), then you don't need
to have a pre-built lex around either (unless you modify scan.l, of
course); (This has been true for some time, but was not mentioned
here.)
* version 2.5.11 released 2002-7-31
** Fixed bug where yyless did not consider yylineno
** the yylineno performance hit is now gone
** fixed some typos in the manual and we now include texinfo.tex in
the distribution
** traditional prototypes output for C scanners, controlled by a
preprocessor symbol; see documentation for details
* version 2.5.10 released 2002-7-24
** yy_globals renamed to yyscanner and yy_globals_t renamed to
yy_guts_t
** added dist-bzip2 option to Makefile.am so we now produce a bzip2'd
archive in addition to the standard gzip archive
* version 2.5.9
** new tests in test suite: test-mem-{nr,r}, test-posix,
test-posixly-correct, test-debug-{nr,r}
** made changes to work with gcc-3.2 development code
** ability to choose which memory functions are used in flex
** new yylex_destroy() function for the non-reentrant scanner
** new handling of POSIXLY_CORRECT environment variable
** the test suite now has its copyrights explicitly described
** new ca, de, fr, ru, sv, tr translations
* version 2.5.8
** a new --posix option generates scanners with posix-style abc{1,3}
compatible parsing, see manual for the screwy details
* version 2.5.7
** configure.in now includes a call to AC_PREREQ to enforce the
requirement for autoconf at least 2.50 (This only effects you if
you're doing flex development.)
** configure now uses autoconf's versioning information and configure
--help reports the bug-reporting address for flex
** test suite now only reports success versus failure; reporting
skipped is problematic under the current setup
** compilation with --disable-nls now works
** flex can now be built in a separate directory
* version 2.5.6
** gettext support added (from gettext 0.11)
*** translations for ca, da, de, es, fr, ko, ru, sv, tr included
** distribution now built under automake 1.6 and autoconf 2.53
** command-line option parsing happens differently now:
*** Added long option parsing
*** Options -n and -c, previously deprecated, now simply do nothing
*** Options are now parsed left to right
** added a number of new options
*** All positive %options are now accessible from the command line
*** Added option -D, to define a preprocessor symbol
*** Added option --header=FILE to specify a C .h file to generate
*** added option --yywrap to call yywrap on EOF
*** added option --yylineno to track line count in yylineno
*** --yyclass=NAME name of C++ class when generating c++ scanners
*** for long option names which are associated with existing short
options, see accompanying documentation
*** new %option nounistd or command-line --nounistd added to prevent
flex from generating #include <unistd.h> on systems that don't
have that include file
** Support for reentrant C scanners has been added
*** Updated the manual with the new reentrant API
*** Two new options %option reentrant (-R) and
%option reentrant-bison (-Rb)
*** All globals optionally placed into struct yyglobals_t
*** All access to globals replaced by macro invocations
*** All functions optionally take one additional
argument, yy_globals
*** New style for invoking reentrant scanner:
yylex_init(void** scanner );
yylex( scanner );
yylex_destroy( scanner );
*** Added get/set functions for members of struct yy_globals_t
e.g., yyget_text, yyget_leng, etc
*** Prefix substitution added for new functions
*** Macro shortcuts to the lengthy get/set functions
provided for use in actions, e.g., yytext, yyleng, etc
*** Arbitrary, user-defined data, "yyextra", may be added to scanner
** %option nomain no longer implies %option yywrap
But the inverse is still true
** Developer test suite added
*** TESTS/ directory has been added. Users can
'make test' in the TESTS directory to execute the test suite
** Support for bison variables yylval and yylloc added
** automake support for the build process
** manual is now in texinfo/info format
*** flex.1 removed from distribution
** flex no longer generates C-language scanners with C++-style
comments
** flex now generates scanners in c++ which are compatible with
recent c++ compilers
** flex input scanner now recognizes '\r' as an EOL character
See the file ONEWS for changes in earlier releases.
Local Variables:
mode: text
mode: outline-minor
end:

113
third_party/lex/NOTES vendored
View file

@ -1,113 +0,0 @@
This is flex, the fast lexical analyzer generator.
flex is a tool for generating scanners: programs which recognize
lexical patterns in text.
More information about flex as well as the latest official release of
flex can be found at:
http://flex.sourceforge.net/
Bug reports should be submitted using the SourceForge Bug Tracker for
flex at:
http://sourceforge.net/tracker/?group_id=97492&atid=618177
The flex codebase is kept in git at:
https://github.com/westes/flex
There are several mailing lists available as well:
flex-announce@lists.sourceforge.net - where posts will be made
announcing new releases of flex.
flex-help@lists.sourceforge.net - where you can post questions about
using flex
flex-devel@lists.sourceforge.net - where you can discuss development of
flex itself
Find information on subscribing to the mailing lists at:
http://sourceforge.net/mail/?group_id=97492
The flex distribution contains the following files which may be of interest:
README - This file.
NEWS - current version number and list of user-visible changes.
INSTALL - basic installation information.
ABOUT-NLS - description of internationalization support in flex.
COPYING - flex's copyright and license.
doc/ - user documentation.
examples/ - containing examples of some possible flex scanners and a
few other things. See the file examples/README for more details.
TODO - outstanding bug reports, desired features, etc.
tests/ - regression tests. See TESTS/README for details.
po/ - internationalization support files.
You need the following tools to build flex from the maintainer's
repository:
compiler suite - flex is built with gcc
bash, or a good Bourne-style shell
m4 - m4 -p needs to work; GNU m4 and a few others are suitable
GNU bison; to generate parse.c from parse.y
autoconf 2.69; for handling the build system
automake 1.12.2; for Makefile generation
gettext 0.18; fori18n support
help2man 1.36; to generate the flex man page
tar, gzip, etc.; for packaging of the source distribution
GNU texinfo 498; to build and test the flex manual
GNU indent 2.8; for indenting the flex source the way we want it done
Once you have all the necessary tools installed, life becomes
simple. To prepare the flex tree for building, run the script:
$ ./autogen.sh
in the top level of the flex source tree.
This script calls the various tools needed to get flex ready for the
GNU-style configure script to be able to work.
From this point on, building flex follows the usual configure, make,
make install routine.
This file is part of flex.
This code is derived from software contributed to Berkeley by
Vern Paxson.
The United States Government has rights in this work pursuant
to contract no. DE-AC03-76SF00098 between the United States
Department of Energy and the University of California.
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.
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 ``AS IS'' AND WITHOUT ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE.

1233
third_party/lex/ONEWS vendored

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

286
third_party/lex/buf.c vendored
View file

@ -1,286 +0,0 @@
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
vi: set et ft=c ts=8 sw=8 fenc=utf-8 :vi
*/
/* clang-format off */
/* $OpenBSD: buf.c,v 1.7 2015/11/20 18:54:49 tedu Exp $ */
/* flex - tool to generate fast lexical analyzers */
/* Copyright (c) 1990 The Regents of the University of California. */
/* All rights reserved. */
/* This code is derived from software contributed to Berkeley by */
/* Vern Paxson. */
/* The United States Government has rights in this work pursuant */
/* to contract no. DE-AC03-76SF00098 between the United States */
/* Department of Energy and the University of California. */
/* This file is part of flex. */
/* 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. */
/* 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR */
/* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED */
/* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR */
/* PURPOSE. */
#include "libc/str/str.h"
#include "libc/mem/mem.h"
#include "libc/fmt/fmt.h"
#include "libc/math.h"
#include "libc/fmt/conv.h"
#include "flexdef.h"
/* Take note: The buffer object is sometimes used as a String buffer (one
* continuous string), and sometimes used as a list of strings, usually line by
* line.
*
* The type is specified in buf_init by the elt_size. If the elt_size is
* sizeof(char), then the buffer should be treated as string buffer. If the
* elt_size is sizeof(char*), then the buffer should be treated as a list of
* strings.
*
* Certain functions are only appropriate for one type or the other.
*/
/* global buffers. */
struct Buf userdef_buf; /**< for user #definitions triggered by cmd-line. */
struct Buf defs_buf; /**< for #define's autogenerated. List of strings. */
struct Buf yydmap_buf; /**< string buffer to hold yydmap elements */
struct Buf m4defs_buf; /**< m4 definitions. List of strings. */
struct Buf top_buf; /**< contains %top code. String buffer. */
struct Buf *
buf_print_strings(struct Buf * buf, FILE * out)
{
int i;
if (!buf || !out)
return buf;
for (i = 0; i < buf->nelts; i++) {
const char *s = ((char **) buf->elts)[i];
if (s)
fprintf(out, "%s", s);
}
return buf;
}
/* Append a "%s" formatted string to a string buffer */
struct Buf *
buf_prints(struct Buf * buf, const char *fmt, const char *s)
{
char *t;
size_t tsz;
tsz = strlen(fmt) + strlen(s) + 1;
t = malloc(tsz);
if (!t)
flexfatal(_("Allocation of buffer to print string failed"));
snprintf(t, tsz, fmt, s);
buf = buf_strappend(buf, t);
free(t);
return buf;
}
/** Append a line directive to the string buffer.
* @param buf A string buffer.
* @param filename file name
* @param lineno line number
* @return buf
*/
struct Buf *
buf_linedir(struct Buf * buf, const char *filename, int lineno)
{
const char *src;
char *dst, *t;
size_t tsz;
tsz = strlen("#line \"\"\n") + /* constant parts */
2 * strlen(filename) + /* filename with possibly all backslashes escaped */
(int) (1 + log10(abs(lineno))) + /* line number */
1; /* NUL */
t = malloc(tsz);
if (!t)
flexfatal(_("Allocation of buffer for line directive failed"));
dst = t + snprintf(t, tsz, "#line %d \"", lineno);
for (src = filename; *src; *dst++ = *src++)
if (*src == '\\') /* escape backslashes */
*dst++ = '\\';
*dst++ = '"';
*dst++ = '\n';
*dst = '\0';
buf = buf_strappend(buf, t);
free(t);
return buf;
}
/** Append the contents of @a src to @a dest.
* @param @a dest the destination buffer
* @param @a dest the source buffer
* @return @a dest
*/
struct Buf *
buf_concat(struct Buf * dest, const struct Buf * src)
{
buf_append(dest, src->elts, src->nelts);
return dest;
}
/* Appends n characters in str to buf. */
struct Buf *
buf_strnappend(struct Buf *buf, const char *str, int n)
{
buf_append(buf, str, n + 1);
/* "undo" the '\0' character that buf_append() already copied. */
buf->nelts--;
return buf;
}
/* Appends characters in str to buf. */
struct Buf *
buf_strappend(struct Buf *buf, const char *str)
{
return buf_strnappend(buf, str, strlen(str));
}
/* appends "#define str def\n" */
struct Buf *
buf_strdefine(struct Buf *buf, const char *str, const char *def2)
{
buf_strappend(buf, "#define ");
buf_strappend(buf, " ");
buf_strappend(buf, str);
buf_strappend(buf, " ");
buf_strappend(buf, def2);
buf_strappend(buf, "\n");
return buf;
}
/** Pushes "m4_define( [[def]], [[val]])m4_dnl" to end of buffer.
* @param buf A buffer as a list of strings.
* @param def The m4 symbol to define.
* @param val The definition; may be NULL.
* @return buf
*/
struct Buf *
buf_m4_define(struct Buf * buf, const char *def2, const char *val)
{
const char *fmt = "m4_define( [[%s]], [[%s]])m4_dnl\n";
char *str;
size_t strsz;
val = val ? val : "";
strsz = strlen(fmt) + strlen(def2) + strlen(val) + 2;
str = malloc(strsz);
if (!str)
flexfatal(_("Allocation of buffer for m4 def failed"));
snprintf(str, strsz, fmt, def2, val);
buf_append(buf, &str, 1);
return buf;
}
/** Pushes "m4_undefine([[def]])m4_dnl" to end of buffer.
* @param buf A buffer as a list of strings.
* @param def The m4 symbol to undefine.
* @return buf
*/
struct Buf *
buf_m4_undefine(struct Buf * buf, const char *def2)
{
const char *fmt = "m4_undefine( [[%s]])m4_dnl\n";
char *str;
size_t strsz;
strsz = strlen(fmt) + strlen(def2) + 2;
str = malloc(strsz);
if (!str)
flexfatal(_("Allocation of buffer for m4 undef failed"));
snprintf(str, strsz, fmt, def2);
buf_append(buf, &str, 1);
return buf;
}
/* create buf with 0 elements, each of size elem_size. */
void
buf_init(struct Buf *buf, size_t elem_size)
{
buf->elts = NULL;
buf->nelts = 0;
buf->elt_size = elem_size;
buf->nmax = 0;
}
/* frees memory */
void
buf_destroy(struct Buf *buf)
{
free(buf->elts);
buf->elts = NULL;
}
/* appends ptr[] to buf, grow if necessary.
* n_elem is number of elements in ptr[], NOT bytes.
* returns buf.
* We grow by mod(512) boundaries.
*/
struct Buf *
buf_append(struct Buf *buf, const void *ptr, int n_elem)
{
int n_alloc = 0;
if (!ptr || n_elem == 0)
return buf;
/* May need to alloc more. */
if (n_elem + buf->nelts > buf->nmax) {
/* exact amount needed... */
n_alloc = (n_elem + buf->nelts) * buf->elt_size;
/* ...plus some extra */
if (((n_alloc * buf->elt_size) % 512) != 0
&& buf->elt_size < 512)
n_alloc +=
(512 -
((n_alloc * buf->elt_size) % 512)) /
buf->elt_size;
if (!buf->elts)
buf->elts =
allocate_array(n_alloc, buf->elt_size);
else
buf->elts =
reallocate_array(buf->elts, n_alloc,
buf->elt_size);
buf->nmax = n_alloc;
}
memcpy((char *) buf->elts + buf->nelts * buf->elt_size, ptr,
n_elem * buf->elt_size);
buf->nelts += n_elem;
return buf;
}

325
third_party/lex/ccl.c vendored
View file

@ -1,325 +0,0 @@
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
vi: set et ft=c ts=8 sw=8 fenc=utf-8 :vi
*/
/* clang-format off */
/* $OpenBSD: ccl.c,v 1.8 2015/11/19 22:55:13 tedu Exp $ */
/* ccl - routines for character classes */
/* Copyright (c) 1990 The Regents of the University of California. */
/* All rights reserved. */
/* This code is derived from software contributed to Berkeley by */
/* Vern Paxson. */
/* The United States Government has rights in this work pursuant */
/* to contract no. DE-AC03-76SF00098 between the United States */
/* Department of Energy and the University of California. */
/* This file is part of flex. */
/* 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. */
/* 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR */
/* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED */
/* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR */
/* PURPOSE. */
#include "libc/str/str.h"
#include "flexdef.h"
/* return true if the chr is in the ccl. Takes negation into account. */
static bool
ccl_contains(const int cclp, const int ch)
{
int ind, len, i;
len = ccllen[cclp];
ind = cclmap[cclp];
for (i = 0; i < len; ++i)
if (ccltbl[ind + i] == ch)
return !cclng[cclp];
return cclng[cclp];
}
/* ccladd - add a single character to a ccl */
void
ccladd(cclp, ch)
int cclp;
int ch;
{
int ind, len, newpos, i;
check_char(ch);
len = ccllen[cclp];
ind = cclmap[cclp];
/* check to see if the character is already in the ccl */
for (i = 0; i < len; ++i)
if (ccltbl[ind + i] == ch)
return;
/* mark newlines */
if (ch == nlch)
ccl_has_nl[cclp] = true;
newpos = ind + len;
if (newpos >= current_max_ccl_tbl_size) {
current_max_ccl_tbl_size += MAX_CCL_TBL_SIZE_INCREMENT;
++num_reallocs;
ccltbl = reallocate_Character_array(ccltbl,
current_max_ccl_tbl_size);
}
ccllen[cclp] = len + 1;
ccltbl[newpos] = ch;
}
/* dump_cclp - same thing as list_character_set, but for cclps. */
static void
dump_cclp(FILE * file, int cclp)
{
int i;
putc('[', file);
for (i = 0; i < csize; ++i) {
if (ccl_contains(cclp, i)) {
int start_char = i;
putc(' ', file);
fputs(readable_form(i), file);
while (++i < csize && ccl_contains(cclp, i));
if (i - 1 > start_char)
/* this was a run */
fprintf(file, "-%s",
readable_form(i - 1));
putc(' ', file);
}
}
putc(']', file);
}
/* ccl_set_diff - create a new ccl as the set difference of the two given ccls. */
int
ccl_set_diff(int a, int b)
{
int d, ch;
/* create new class */
d = cclinit();
/*
* In order to handle negation, we spin through all possible chars,
* addding each char in a that is not in b. (This could be O(n^2),
* but n is small and bounded.)
*/
for (ch = 0; ch < csize; ++ch)
if (ccl_contains(a, ch) && !ccl_contains(b, ch))
ccladd(d, ch);
/* debug */
if (0) {
fprintf(stderr, "ccl_set_diff (");
fprintf(stderr, "\n ");
dump_cclp(stderr, a);
fprintf(stderr, "\n ");
dump_cclp(stderr, b);
fprintf(stderr, "\n ");
dump_cclp(stderr, d);
fprintf(stderr, "\n)\n");
}
return d;
}
/* ccl_set_union - create a new ccl as the set union of the two given ccls. */
int
ccl_set_union(int a, int b)
{
int d, i;
/* create new class */
d = cclinit();
/* Add all of a */
for (i = 0; i < ccllen[a]; ++i)
ccladd(d, ccltbl[cclmap[a] + i]);
/* Add all of b */
for (i = 0; i < ccllen[b]; ++i)
ccladd(d, ccltbl[cclmap[b] + i]);
/* debug */
if (0) {
fprintf(stderr, "ccl_set_union (%d + %d = %d", a, b, d);
fprintf(stderr, "\n ");
dump_cclp(stderr, a);
fprintf(stderr, "\n ");
dump_cclp(stderr, b);
fprintf(stderr, "\n ");
dump_cclp(stderr, d);
fprintf(stderr, "\n)\n");
}
return d;
}
/* cclinit - return an empty ccl */
int
cclinit()
{
if (++lastccl >= current_maxccls) {
current_maxccls += MAX_CCLS_INCREMENT;
++num_reallocs;
cclmap =
reallocate_integer_array(cclmap, current_maxccls);
ccllen =
reallocate_integer_array(ccllen, current_maxccls);
cclng = reallocate_integer_array(cclng, current_maxccls);
ccl_has_nl =
reallocate_bool_array(ccl_has_nl,
current_maxccls);
}
if (lastccl == 1)
/* we're making the first ccl */
cclmap[lastccl] = 0;
else
/*
* The new pointer is just past the end of the last ccl.
* Since the cclmap points to the \first/ character of a ccl,
* adding the length of the ccl to the cclmap pointer will
* produce a cursor to the first free space.
*/
cclmap[lastccl] =
cclmap[lastccl - 1] + ccllen[lastccl - 1];
ccllen[lastccl] = 0;
cclng[lastccl] = 0; /* ccl's start out life un-negated */
ccl_has_nl[lastccl] = false;
return lastccl;
}
/* cclnegate - negate the given ccl */
void
cclnegate(cclp)
int cclp;
{
cclng[cclp] = 1;
ccl_has_nl[cclp] = !ccl_has_nl[cclp];
}
/* list_character_set - list the members of a set of characters in CCL form
*
* Writes to the given file a character-class representation of those
* characters present in the given CCL. A character is present if it
* has a non-zero value in the cset array.
*/
void
list_character_set(file, cset)
FILE *file;
int cset[];
{
int i;
putc('[', file);
for (i = 0; i < csize; ++i) {
if (cset[i]) {
int start_char = i;
putc(' ', file);
fputs(readable_form(i), file);
while (++i < csize && cset[i]);
if (i - 1 > start_char)
/* this was a run */
fprintf(file, "-%s",
readable_form(i - 1));
putc(' ', file);
}
}
putc(']', file);
}
/** Determines if the range [c1-c2] is unambiguous in a case-insensitive
* scanner. Specifically, if a lowercase or uppercase character, x, is in the
* range [c1-c2], then we require that UPPERCASE(x) and LOWERCASE(x) must also
* be in the range. If not, then this range is ambiguous, and the function
* returns false. For example, [@-_] spans [a-z] but not [A-Z]. Beware that
* [a-z] will be labeled ambiguous because it does not include [A-Z].
*
* @param c1 the lower end of the range
* @param c2 the upper end of the range
* @return true if [c1-c2] is not ambiguous for a caseless scanner.
*/
bool
range_covers_case(int c1, int c2)
{
int i, o;
for (i = c1; i <= c2; i++) {
if (has_case(i)) {
o = reverse_case(i);
if (o < c1 || c2 < o)
return false;
}
}
return true;
}
/** Reverse the case of a character, if possible.
* @return c if case-reversal does not apply.
*/
int
reverse_case(int c)
{
return isupper(c) ? tolower(c) : (islower(c) ? toupper(c) : c);
}
/** Return true if c is uppercase or lowercase. */
bool
has_case(int c)
{
return (isupper(c) || islower(c)) ? true : false;
}

View file

@ -1,207 +0,0 @@
/* $OpenBSD: config.h,v 1.5 2015/11/19 23:48:06 tedu Exp $ */
/* config.h. Generated from conf.in by configure. */
/* conf.in. Generated from configure.ac by autoheader. */
/* Define to 1 if you have the MacOS X function CFLocaleCopyCurrent in the
CoreFoundation framework. */
/* #undef HAVE_CFLOCALECOPYCURRENT */
/* Define to 1 if you have the MacOS X function CFPreferencesCopyAppValue in
the CoreFoundation framework. */
/* #undef HAVE_CFPREFERENCESCOPYAPPVALUE */
/* Define if the GNU dcgettext() function is already present or preinstalled.
*/
/* #undef HAVE_DCGETTEXT */
/* Define to 1 if you have the <dlfcn.h> header file. */
/* #define HAVE_DLFCN_H 1 */
/* Define to 1 if you have the `dup2' function. */
#define HAVE_DUP2 1
/* Define to 1 if you have the `fork' function. */
#define HAVE_FORK 1
/* Define if the GNU gettext() function is already present or preinstalled. */
/* #undef HAVE_GETTEXT */
/* Define if you have the iconv() function and it works. */
#define HAVE_ICONV 1
/* Define to 1 if you have the <inttypes.h> header file. */
#define HAVE_INTTYPES_H 1
/* Define to 1 if you have the `isascii' function. */
#define HAVE_ISASCII 1
/* Define to 1 if you have the <libintl.h> header file. */
/* #undef HAVE_LIBINTL_H */
/* Define to 1 if you have the `m' library (-lm). */
#define HAVE_LIBM 1
/* pthread library */
#define HAVE_LIBPTHREAD 1
/* Define to 1 if you have the <limits.h> header file. */
#define HAVE_LIMITS_H 1
/* Define to 1 if you have the <locale.h> header file. */
/* #define HAVE_LOCALE_H 1 */
/* Define to 1 if your system has a GNU libc compatible `malloc' function, and
to 0 otherwise. */
#define HAVE_MALLOC 1
/* Define to 1 if you have the <malloc.h> header file. */
#define HAVE_MALLOC_H 1
/* Define to 1 if you have the <memory.h> header file. */
#define HAVE_MEMORY_H 1
/* Define to 1 if you have the `memset' function. */
#define HAVE_MEMSET 1
/* Define to 1 if you have the <netinet/in.h> header file. */
/* #define HAVE_NETINET_IN_H 1 */
/* Define to 1 if you have the `pow' function. */
#define HAVE_POW 1
/* Define to 1 if you have the <pthread.h> header file. */
#define HAVE_PTHREAD_H 1
/* Define to 1 if your system has a GNU libc compatible `realloc' function,
and to 0 otherwise. */
#define HAVE_REALLOC 1
/* Define to 1 if you have the `regcomp' function. */
#define HAVE_REGCOMP 1
/* Define to 1 if you have the <regex.h> header file. */
#define HAVE_REGEX_H 1
/* Define to 1 if you have the `setlocale' function. */
/* #define HAVE_SETLOCALE 1 */
/* Define to 1 if stdbool.h conforms to C99. */
#define HAVE_STDBOOL_H 1
/* Define to 1 if you have the <stddef.h> header file. */
#define HAVE_STDDEF_H 1
/* Define to 1 if you have the <stdint.h> header file. */
#define HAVE_STDINT_H 1
/* Define to 1 if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H 1
/* Define to 1 if you have the `strchr' function. */
#define HAVE_STRCHR 1
/* Define to 1 if you have the <strings.h> header file. */
#define HAVE_STRINGS_H 1
/* Define to 1 if you have the <string.h> header file. */
#define HAVE_STRING_H 1
/* Define to 1 if you have the `strtol' function. */
#define HAVE_STRTOL 1
/* Define to 1 if you have the <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H 1
/* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1
/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */
#define HAVE_SYS_WAIT_H 1
/* Define to 1 if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1
/* Define to 1 if you have the `vfork' function. */
#define HAVE_VFORK 1
/* Define to 1 if you have the <vfork.h> header file. */
/* #undef HAVE_VFORK_H */
/* Define to 1 if `fork' works. */
#define HAVE_WORKING_FORK 1
/* Define to 1 if `vfork' works. */
#define HAVE_WORKING_VFORK 1
/* Define to 1 if the system has the type `_Bool'. */
#define HAVE__BOOL 1
/* Define to the sub-directory in which libtool stores uninstalled libraries.
*/
#define LT_OBJDIR ".libs/"
/* Define to the m4 executable name. */
#define M4 "o/$(MODE)/third_party/m4/m4.com.dbg"
/* Define to 1 if your C compiler doesn't accept -c and -o together. */
/* #undef NO_MINUS_C_MINUS_O */
/* Name of package */
#define PACKAGE "flex"
/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT "flex-help@lists.sourceforge.net"
/* Define to the full name of this package. */
#define PACKAGE_NAME "the fast lexical analyser generator"
/* Define to the full name and version of this package. */
#define PACKAGE_STRING "the fast lexical analyser generator 2.5.39"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "flex"
/* Define to the home page for this package. */
#define PACKAGE_URL ""
/* Define to the version of this package. */
#define PACKAGE_VERSION "2.5.39"
/* If using the C implementation of alloca, define if you know the
direction of stack growth for your system; otherwise it will be
automatically deduced at runtime.
STACK_DIRECTION > 0 => grows toward higher addresses
STACK_DIRECTION < 0 => grows toward lower addresses
STACK_DIRECTION = 0 => direction of growth unknown */
/* #undef STACK_DIRECTION */
/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1
/* Version number of package */
#define VERSION "2.5.39"
/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a
`char[]'. */
#define YYTEXT_POINTER 1
/* Define to empty if `const' does not conform to ANSI C. */
/* #undef const */
/* Define to rpl_malloc if the replacement function should be used. */
/* #undef malloc */
/* Define to `int' if <sys/types.h> does not define. */
/* #undef pid_t */
/* Define to rpl_realloc if the replacement function should be used. */
/* #undef realloc */
/* Define to `unsigned int' if <sys/types.h> does not define. */
/* #undef size_t */
/* Define as `fork' if `vfork' does not work. */
/* #undef vfork */
#define HAVE_ASSERT_H

1105
third_party/lex/dfa.c vendored

File diff suppressed because it is too large Load diff

230
third_party/lex/ecs.c vendored
View file

@ -1,230 +0,0 @@
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
vi: set et ft=c ts=8 sw=8 fenc=utf-8 :vi
*/
/* clang-format off */
/* $OpenBSD: ecs.c,v 1.9 2015/11/20 18:54:49 tedu Exp $ */
/* ecs - equivalence class routines */
/* Copyright (c) 1990 The Regents of the University of California. */
/* All rights reserved. */
/* This code is derived from software contributed to Berkeley by */
/* Vern Paxson. */
/* The United States Government has rights in this work pursuant */
/* to contract no. DE-AC03-76SF00098 between the United States */
/* Department of Energy and the University of California. */
/* This file is part of flex */
/* 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. */
/* 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR */
/* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED */
/* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR */
/* PURPOSE. */
#include "flexdef.h"
/* ccl2ecl - convert character classes to set of equivalence classes */
void
ccl2ecl(void)
{
int i, ich, newlen, cclp, ccls, cclmec;
for (i = 1; i <= lastccl; ++i) {
/*
* We loop through each character class, and for each
* character in the class, add the character's equivalence
* class to the new "character" class we are creating. Thus
* when we are all done, character classes will really
* consist of collections of equivalence classes
*/
newlen = 0;
cclp = cclmap[i];
for (ccls = 0; ccls < ccllen[i]; ++ccls) {
ich = ccltbl[cclp + ccls];
cclmec = ecgroup[ich];
if (cclmec > 0) {
ccltbl[cclp + newlen] = cclmec;
++newlen;
}
}
ccllen[i] = newlen;
}
}
/* cre8ecs - associate equivalence class numbers with class members
*
* fwd is the forward linked-list of equivalence class members. bck
* is the backward linked-list, and num is the number of class members.
*
* Returned is the number of classes.
*/
int
cre8ecs(int *fwd, int *bck, int num)
{
int i, j, numcl;
numcl = 0;
/*
* Create equivalence class numbers. From now on, ABS( bck(x) ) is
* the equivalence class number for object x. If bck(x) is positive,
* then x is the representative of its equivalence class.
*/
for (i = 1; i <= num; ++i)
if (bck[i] == NIL) {
bck[i] = ++numcl;
for (j = fwd[i]; j != NIL; j = fwd[j])
bck[j] = -numcl;
}
return numcl;
}
/* mkeccl - update equivalence classes based on character class xtions
*
* synopsis
* u_char ccls[];
* int lenccl, fwd[llsiz], bck[llsiz], llsiz, NUL_mapping;
* void mkeccl( u_char ccls[], int lenccl, int fwd[llsiz], int bck[llsiz],
* int llsiz, int NUL_mapping );
*
* ccls contains the elements of the character class, lenccl is the
* number of elements in the ccl, fwd is the forward link-list of equivalent
* characters, bck is the backward link-list, and llsiz size of the link-list.
*
* NUL_mapping is the value which NUL (0) should be mapped to.
*/
void
mkeccl(u_char *ccls, int lenccl, int *fwd, int *bck, int llsiz, int NUL_mapping)
{
int cclp, oldec, newec;
int cclm, i, j;
static unsigned char cclflags[CSIZE]; /* initialized to all '\0' */
/*
* Note that it doesn't matter whether or not the character class is
* negated. The same results will be obtained in either case.
*/
cclp = 0;
while (cclp < lenccl) {
cclm = ccls[cclp];
if (NUL_mapping && cclm == 0)
cclm = NUL_mapping;
oldec = bck[cclm];
newec = cclm;
j = cclp + 1;
for (i = fwd[cclm]; i != NIL && i <= llsiz; i = fwd[i]) {
/* look for the symbol in the character class */
for (; j < lenccl; ++j) {
int ccl_char;
if (NUL_mapping && ccls[j] == 0)
ccl_char = NUL_mapping;
else
ccl_char = ccls[j];
if (ccl_char > i)
break;
if (ccl_char == i && !cclflags[j]) {
/*
* We found an old companion of cclm
* in the ccl. Link it into the new
* equivalence class and flag it as
* having been processed.
*/
bck[i] = newec;
fwd[newec] = i;
newec = i;
/* Set flag so we don't reprocess. */
cclflags[j] = 1;
/* Get next equivalence class member. */
/* continue 2 */
goto next_pt;
}
}
/*
* Symbol isn't in character class. Put it in the
* old equivalence class.
*/
bck[i] = oldec;
if (oldec != NIL)
fwd[oldec] = i;
oldec = i;
next_pt: ;
}
if (bck[cclm] != NIL || oldec != bck[cclm]) {
bck[cclm] = NIL;
fwd[oldec] = NIL;
}
fwd[newec] = NIL;
/* Find next ccl member to process. */
for (++cclp; cclflags[cclp] && cclp < lenccl; ++cclp) {
/* Reset "doesn't need processing" flag. */
cclflags[cclp] = 0;
}
}
}
/* mkechar - create equivalence class for single character */
void
mkechar(int tch, int *fwd, int *bck)
{
/*
* If until now the character has been a proper subset of an
* equivalence class, break it away to create a new ec
*/
if (fwd[tch] != NIL)
bck[fwd[tch]] = bck[tch];
if (bck[tch] != NIL)
fwd[bck[tch]] = fwd[tch];
fwd[tch] = NIL;
bck[tch] = NIL;
}

View file

@ -1,452 +0,0 @@
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
vi: set et ft=c ts=8 sw=8 fenc=utf-8 :vi
*/
/* clang-format off */
/* $OpenBSD: filter.c,v 1.9 2017/08/30 02:54:07 lteo Exp $ */
/* filter - postprocessing of flex output through filters */
/* This file is part of flex. */
/* 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. */
/* 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR */
/* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED */
/* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR */
/* PURPOSE. */
#include "libc/mem/mem.h"
#include "libc/calls/calls.h"
#include "libc/calls/calls.h"
#include "libc/str/str.h"
#include "libc/fmt/fmt.h"
#include "libc/calls/calls.h"
#include "libc/runtime/runtime.h"
#include "libc/log/log.h"
#include "flexdef.h"
const char *check_4_gnu_m4 =
"m4_dnl ifdef(`__gnu__', ,"
"`errprint(Flex requires GNU M4. Set the PATH or set the M4 environment variable to its path name.)"
" m4exit(2)')\n";
/** global chain. */
struct filter *output_chain = NULL;
/* Allocate and initialize an external filter.
* @param chain the current chain or NULL for new chain
* @param cmd the command to execute.
* @param ... a NULL terminated list of (const char*) arguments to command,
* not including argv[0].
* @return newest filter in chain
*/
struct filter *
filter_create_ext(struct filter * chain, const char *cmd,
...)
{
struct filter *f;
int max_args;
const char *s;
va_list ap;
/* allocate and initialize new filter */
f = calloc(sizeof(struct filter), 1);
if (!f)
flexerror(_("calloc failed (f) in filter_create_ext"));
f->filter_func = NULL;
f->extra = NULL;
f->next = NULL;
f->argc = 0;
if (chain != NULL) {
/* append f to end of chain */
while (chain->next)
chain = chain->next;
chain->next = f;
}
/* allocate argv, and populate it with the argument list. */
max_args = 8;
f->argv = malloc(sizeof(char *) * (max_args + 1));
if (!f->argv)
flexerror(_("malloc failed (f->argv) in filter_create_ext"));
f->argv[f->argc++] = cmd;
va_start(ap, cmd);
while ((s = va_arg(ap, const char *)) != NULL) {
if (f->argc >= max_args) {
max_args += 8;
f->argv = realloc(f->argv,
sizeof(char *) * (max_args + 1));
}
f->argv[f->argc++] = s;
}
f->argv[f->argc] = NULL;
va_end(ap);
return f;
}
/* Allocate and initialize an internal filter.
* @param chain the current chain or NULL for new chain
* @param filter_func The function that will perform the filtering.
* filter_func should return 0 if successful, and -1
* if an error occurs -- or it can simply exit().
* @param extra optional user-defined data to pass to the filter.
* @return newest filter in chain
*/
struct filter *
filter_create_int(struct filter * chain,
int (*filter_func) (struct filter *),
void *extra)
{
struct filter *f;
/* allocate and initialize new filter */
f = calloc(sizeof(struct filter), 1);
if (!f)
flexerror(_("calloc failed in filter_create_int"));
f->next = NULL;
f->argc = 0;
f->argv = NULL;
f->filter_func = filter_func;
f->extra = extra;
if (chain != NULL) {
/* append f to end of chain */
while (chain->next)
chain = chain->next;
chain->next = f;
}
return f;
}
/** Fork and exec entire filter chain.
* @param chain The head of the chain.
* @return true on success.
*/
bool
filter_apply_chain(struct filter * chain)
{
int pid;
int pipes[2];
/*
* Tricky recursion, since we want to begin the chain at the END.
* Why? Because we need all the forked processes to be children of
* the main flex process.
*/
if (chain)
filter_apply_chain(chain->next);
else
return true;
/*
* Now we are the right-most unprocessed link in the chain.
*/
fflush(stdout);
fflush(stderr);
if (pipe(pipes) == -1)
flexerror(_("pipe failed"));
if ((pid = fork()) == -1)
flexerror(_("fork failed"));
if (pid == 0) {
/* child */
/*
* We need stdin (the FILE* stdin) to connect to this new
* pipe. There is no portable way to set stdin to a new file
* descriptor, as stdin is not an lvalue on some systems
* (BSD). So we dup the new pipe onto the stdin descriptor
* and use a no-op fseek to sync the stream. This is a Hail
* Mary situation. It seems to work.
*/
close(pipes[1]);
clearerr(stdin);
if (dup2(pipes[0], fileno(stdin)) == -1)
flexfatal(_("dup2(pipes[0],0)"));
close(pipes[0]);
fseek(stdin, 0, SEEK_CUR);
/* run as a filter, either internally or by exec */
if (chain->filter_func) {
if (chain->filter_func(chain) == -1)
flexfatal(_("filter_func failed"));
exit(0);
} else {
execvp(chain->argv[0],
(char **const) (chain->argv));
lerrsf_fatal(_("exec of %s failed"),
chain->argv[0]);
}
exit(1);
}
/* Parent */
close(pipes[0]);
if (dup2(pipes[1], fileno(stdout)) == -1)
flexfatal(_("dup2(pipes[1],1)"));
close(pipes[1]);
fseek(stdout, 0, SEEK_CUR);
return true;
}
/** Truncate the chain to max_len number of filters.
* @param chain the current chain.
* @param max_len the maximum length of the chain.
* @return the resulting length of the chain.
*/
int
filter_truncate(struct filter * chain, int max_len)
{
int len = 1;
if (!chain)
return 0;
while (chain->next && len < max_len) {
chain = chain->next;
++len;
}
chain->next = NULL;
return len;
}
/** Splits the chain in order to write to a header file.
* Similar in spirit to the 'tee' program.
* The header file name is in extra.
* @return 0 (zero) on success, and -1 on failure.
*/
int
filter_tee_header(struct filter * chain)
{
/*
* This function reads from stdin and writes to both the C file and
* the header file at the same time.
*/
const int readsz = 512;
char *buf;
int to_cfd = -1;
FILE *to_c = NULL, *to_h = NULL;
bool write_header;
write_header = (chain->extra != NULL);
/*
* Store a copy of the stdout pipe, which is already piped to C file
* through the running chain. Then create a new pipe to the H file as
* stdout, and fork the rest of the chain again.
*/
if ((to_cfd = dup(1)) == -1)
flexfatal(_("dup(1) failed"));
to_c = fdopen(to_cfd, "w");
if (write_header) {
if (freopen((char *) chain->extra, "w", stdout) == NULL)
flexfatal(_("freopen(headerfilename) failed"));
filter_apply_chain(chain->next);
to_h = stdout;
}
/*
* Now to_c is a pipe to the C branch, and to_h is a pipe to the H
* branch.
*/
if (write_header) {
/* fputs(check_4_gnu_m4, to_h); */
fputs("m4_changecom`'m4_dnl\n", to_h);
fputs("m4_changequote`'m4_dnl\n", to_h);
fputs("m4_changequote([[,]])[[]]m4_dnl\n", to_h);
fputs("m4_define([[M4_YY_NOOP]])[[]]m4_dnl\n", to_h);
fputs("m4_define( [[M4_YY_IN_HEADER]],[[]])m4_dnl\n",
to_h);
fprintf(to_h, "#ifndef %sHEADER_H\n", prefix);
fprintf(to_h, "#define %sHEADER_H 1\n", prefix);
fprintf(to_h, "#define %sIN_HEADER 1\n\n", prefix);
fprintf(to_h,
"m4_define( [[M4_YY_OUTFILE_NAME]],[[%s]])m4_dnl\n",
headerfilename ? headerfilename : "<stdout>");
}
/* fputs(check_4_gnu_m4, to_c); */
fputs("m4_changecom`'m4_dnl\n", to_c);
fputs("m4_changequote`'m4_dnl\n", to_c);
fputs("m4_changequote([[,]])[[]]m4_dnl\n", to_c);
fputs("m4_define([[M4_YY_NOOP]])[[]]m4_dnl\n", to_c);
fprintf(to_c, "m4_define( [[M4_YY_OUTFILE_NAME]],[[%s]])m4_dnl\n",
outfilename ? outfilename : "<stdout>");
buf = malloc(readsz);
if (!buf)
flexerror(_("malloc failed in filter_tee_header"));
while (fgets(buf, readsz, stdin)) {
fputs(buf, to_c);
if (write_header)
fputs(buf, to_h);
}
if (write_header) {
fprintf(to_h, "\n");
/*
* write a fake line number. It will get fixed by the linedir
* filter.
*/
fprintf(to_h, "#line 4000 \"M4_YY_OUTFILE_NAME\"\n");
fprintf(to_h, "#undef %sIN_HEADER\n", prefix);
fprintf(to_h, "#endif /* %sHEADER_H */\n", prefix);
fputs("m4_undefine( [[M4_YY_IN_HEADER]])m4_dnl\n", to_h);
fflush(to_h);
if (ferror(to_h))
lerrsf(_("error writing output file %s"),
(char *) chain->extra);
else if (fclose(to_h))
lerrsf(_("error closing output file %s"),
(char *) chain->extra);
}
fflush(to_c);
if (ferror(to_c))
lerrsf(_("error writing output file %s"),
outfilename ? outfilename : "<stdout>");
else if (fclose(to_c))
lerrsf(_("error closing output file %s"),
outfilename ? outfilename : "<stdout>");
while (wait(0) > 0);
exit(0);
return 0;
}
/** Adjust the line numbers in the #line directives of the generated scanner.
* After the m4 expansion, the line numbers are incorrect since the m4 macros
* can add or remove lines. This only adjusts line numbers for generated code,
* not user code. This also happens to be a good place to squeeze multiple
* blank lines into a single blank line.
*/
int
filter_fix_linedirs(struct filter * chain)
{
char *buf;
const int readsz = 512 + MAXLINE;
int lineno = 1;
bool in_gen = true; /* in generated code */
bool last_was_blank = false;
if (!chain)
return 0;
buf = malloc(readsz);
if (!buf)
flexerror(_("malloc failed in filter_fix_linedirs"));
while (fgets(buf, readsz, stdin)) {
regmatch_t m[10];
/* Check for #line directive. */
if (buf[0] == '#'
&& regexec(&regex_linedir, buf, 3, m, 0) == 0) {
int num;
char *fname;
/* extract the line number and filename */
num = regmatch_strtol(&m[1], buf, NULL, 0);
fname = regmatch_dup(&m[2], buf);
/* TODO(jart): Why isn't num being used? */
(void)num;
if (strcmp(fname,
outfilename ? outfilename : "<stdout>") == 0 ||
strcmp(fname, headerfilename ? headerfilename :
"<stdout>") == 0) {
char *s1, *s2;
char filename[MAXLINE];
s1 = fname;
s2 = filename;
while ((s2 - filename) < (MAXLINE - 1) && *s1) {
/* Escape the backslash */
if (*s1 == '\\')
*s2++ = '\\';
/* Escape the double quote */
if (*s1 == '\"')
*s2++ = '\\';
/* Copy the character as usual */
*s2++ = *s1++;
}
*s2 = '\0';
/* Adjust the line directives. */
in_gen = true;
snprintf(buf, readsz, "#line %d \"%s\"\n",
lineno + 1, filename);
} else {
/*
* it's a #line directive for code we didn't
* write
*/
in_gen = false;
}
free(fname);
last_was_blank = false;
}
/* squeeze blank lines from generated code */
else if (in_gen &&
regexec(&regex_blank_line, buf, 0, NULL, 0) == 0) {
if (last_was_blank)
continue;
else
last_was_blank = true;
} else {
/* it's a line of normal, non-empty code. */
last_was_blank = false;
}
fputs(buf, stdout);
lineno++;
}
fflush(stdout);
if (ferror(stdout))
lerrsf(_("error writing output file %s"),
outfilename ? outfilename : "<stdout>");
else if (fclose(stdout))
lerrsf(_("error closing output file %s"),
outfilename ? outfilename : "<stdout>");
return 0;
}

4438
third_party/lex/flex.1 vendored

File diff suppressed because it is too large Load diff

3451
third_party/lex/flex.skl vendored

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,67 +0,0 @@
/* clang-format off */
/* $OpenBSD: flexint.h,v 1.1 2015/11/19 19:43:40 tedu Exp $ */
/* flex integer type definitions */
#ifndef FLEXINT_H
#define FLEXINT_H
/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
* if you want the limit (max/min) macros for int types.
*/
#ifndef __STDC_LIMIT_MACROS
#define __STDC_LIMIT_MACROS 1
#endif
#include "libc/limits.h"
typedef int8_t flex_int8_t;
typedef uint8_t flex_uint8_t;
typedef int16_t flex_int16_t;
typedef uint16_t flex_uint16_t;
typedef int32_t flex_int32_t;
typedef uint32_t flex_uint32_t;
#else
typedef signed char flex_int8_t;
typedef short int flex_int16_t;
typedef int flex_int32_t;
typedef unsigned char flex_uint8_t;
typedef unsigned short int flex_uint16_t;
typedef unsigned int flex_uint32_t;
/* Limits of integral types. */
#ifndef INT8_MIN
#define INT8_MIN (-128)
#endif
#ifndef INT16_MIN
#define INT16_MIN (-32767-1)
#endif
#ifndef INT32_MIN
#define INT32_MIN (-2147483647-1)
#endif
#ifndef INT8_MAX
#define INT8_MAX (127)
#endif
#ifndef INT16_MAX
#define INT16_MAX (32767)
#endif
#ifndef INT32_MAX
#define INT32_MAX (2147483647)
#endif
#ifndef UINT8_MAX
#define UINT8_MAX (255U)
#endif
#ifndef UINT16_MAX
#define UINT16_MAX (65535U)
#endif
#ifndef UINT32_MAX
#define UINT32_MAX (4294967295U)
#endif
#endif /* ! C99 */
#endif /* ! FLEXINT_H */

2145
third_party/lex/gen.c vendored

File diff suppressed because it is too large Load diff

118
third_party/lex/lex.mk vendored
View file

@ -1,118 +0,0 @@
#-*-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:
# lex generates state machines for tokenizing languages.
PKGS += THIRD_PARTY_LEX
THIRD_PARTY_LEX = \
o/$(MODE)/third_party/lex/lex.com
THIRD_PARTY_LEX_BINS = \
$(THIRD_PARTY_LEX) \
$(THIRD_PARTY_LEX).dbg
THIRD_PARTY_LEX_OBJS = \
o/$(MODE)/third_party/lex/buf.o \
o/$(MODE)/third_party/lex/ccl.o \
o/$(MODE)/third_party/lex/dfa.o \
o/$(MODE)/third_party/lex/ecs.o \
o/$(MODE)/third_party/lex/filter.o \
o/$(MODE)/third_party/lex/gen.o \
o/$(MODE)/third_party/lex/main.o \
o/$(MODE)/third_party/lex/misc.o \
o/$(MODE)/third_party/lex/nfa.o \
o/$(MODE)/third_party/lex/options.o \
o/$(MODE)/third_party/lex/parse.o \
o/$(MODE)/third_party/lex/regex.o \
o/$(MODE)/third_party/lex/scan.o \
o/$(MODE)/third_party/lex/scanflags.o \
o/$(MODE)/third_party/lex/scanopt.o \
o/$(MODE)/third_party/lex/skel.o \
o/$(MODE)/third_party/lex/sym.o \
o/$(MODE)/third_party/lex/tables.o \
o/$(MODE)/third_party/lex/tables_shared.o \
o/$(MODE)/third_party/lex/tblcmp.o \
o/$(MODE)/third_party/lex/yylex.o \
o/$(MODE)/third_party/lex/buf.c.zip.o \
o/$(MODE)/third_party/lex/ccl.c.zip.o \
o/$(MODE)/third_party/lex/dfa.c.zip.o \
o/$(MODE)/third_party/lex/ecs.c.zip.o \
o/$(MODE)/third_party/lex/filter.c.zip.o \
o/$(MODE)/third_party/lex/gen.c.zip.o \
o/$(MODE)/third_party/lex/main.c.zip.o \
o/$(MODE)/third_party/lex/misc.c.zip.o \
o/$(MODE)/third_party/lex/nfa.c.zip.o \
o/$(MODE)/third_party/lex/options.c.zip.o \
o/$(MODE)/third_party/lex/parse.c.zip.o \
o/$(MODE)/third_party/lex/regex.c.zip.o \
o/$(MODE)/third_party/lex/scan.c.zip.o \
o/$(MODE)/third_party/lex/scanflags.c.zip.o \
o/$(MODE)/third_party/lex/scanopt.c.zip.o \
o/$(MODE)/third_party/lex/skel.c.zip.o \
o/$(MODE)/third_party/lex/sym.c.zip.o \
o/$(MODE)/third_party/lex/tables.c.zip.o \
o/$(MODE)/third_party/lex/tables_shared.c.zip.o \
o/$(MODE)/third_party/lex/tblcmp.c.zip.o \
o/$(MODE)/third_party/lex/yylex.c.zip.o
THIRD_PARTY_LEX_DIRECTDEPS = \
LIBC_ALG \
LIBC_CALLS \
LIBC_CALLS_HEFTY \
LIBC_FMT \
LIBC_LOG \
LIBC_MATH \
LIBC_MEM \
LIBC_NEXGEN32E \
LIBC_RUNTIME \
LIBC_STDIO \
LIBC_STR \
LIBC_STUBS \
LIBC_SYSV \
LIBC_SYSV_CALLS \
LIBC_UNICODE \
LIBC_X \
THIRD_PARTY_REGEX
THIRD_PARTY_LEX_DEPS := \
$(call uniq,$(foreach x,$(THIRD_PARTY_LEX_DIRECTDEPS),$($(x))))
$(THIRD_PARTY_LEX).pkg: \
$(THIRD_PARTY_LEX_OBJS) \
$(foreach x,$(THIRD_PARTY_LEX_DIRECTDEPS),$($(x)_A).pkg)
$(THIRD_PARTY_LEX_OBJS): \
DEFAULT_CPPFLAGS += \
-DHAVE_CONFIG_H \
-isystem third_party/lex
$(THIRD_PARTY_LEX_OBJS): \
OVERRIDE_CFLAGS += \
$(OLD_CODE) \
-O0
o/$(MODE)/third_party/lex/parse.o \
o/$(MODE)/third_party/lex/misc.o \
o/$(MODE)/third_party/lex/dfa.o: \
DEFAULT_CPPFLAGS += \
-DSTACK_FRAME_UNLIMITED
o/$(MODE)/third_party/lex/scan.o: \
DEFAULT_CFLAGS += \
-w
$(THIRD_PARTY_LEX).dbg: \
$(THIRD_PARTY_LEX_DEPS) \
$(THIRD_PARTY_LEX_OBJS) \
$(THIRD_PARTY_LEX).pkg \
$(CRT) \
$(APE)
@$(APELINK)
$(THIRD_PARTY_LEX_OBJS): \
$(BUILD_FILES) \
third_party/lex/lex.mk
.PHONY: o/$(MODE)/third_party/lex
o/$(MODE)/third_party/lex: $(THIRD_PARTY_LEX_BINS)

2208
third_party/lex/lex.ms vendored

File diff suppressed because it is too large Load diff

View file

@ -1,18 +0,0 @@
#if 0
/*─────────────────────────────────────────────────────────────────╗
To the extent possible under law, Justine Tunney has waived
all copyright and related or neighboring rights to this file,
as it is written in the following disclaimers:
http://unlicense.org/ │
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
int yylex();
int main(int argc, char *argv[]) {
for (;;) {
if (!yylex()) break;
}
return 0;
}

View file

@ -1,31 +0,0 @@
/* clang-format off */
/* $OpenBSD: libyywrap.c,v 1.9 2015/11/19 22:52:40 tedu Exp $ */
/* libyywrap - flex run-time support library "yywrap" function */
/* This file is part of flex. */
/* 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. */
/* 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR */
/* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED */
/* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR */
/* PURPOSE. */
int
yywrap(void)
{
return 1;
}

1826
third_party/lex/main.c vendored

File diff suppressed because it is too large Load diff

1017
third_party/lex/misc.c vendored

File diff suppressed because it is too large Load diff

View file

@ -1,38 +0,0 @@
#! /bin/sh
# $OpenBSD: mkskel.sh,v 1.3 2015/11/19 19:43:40 tedu Exp $
# This file is part of flex.
# 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.
# 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR
# IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE.
cat <<!
/* File created from flex.skl via mkskel.sh */
#include "flexdef.h"
const char *skel[] = {
!
sed 's/\\/&&/g' | sed 's/"/\\"/g' | sed 's/.*/ "&",/'
cat <<!
0
};
!

734
third_party/lex/nfa.c vendored
View file

@ -1,734 +0,0 @@
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
vi: set et ft=c ts=8 sw=8 fenc=utf-8 :vi
*/
/* clang-format off */
/* $OpenBSD: nfa.c,v 1.11 2015/11/19 22:52:40 tedu Exp $ */
/* nfa - NFA construction routines */
/* Copyright (c) 1990 The Regents of the University of California. */
/* All rights reserved. */
/* This code is derived from software contributed to Berkeley by */
/* Vern Paxson. */
/* The United States Government has rights in this work pursuant */
/* to contract no. DE-AC03-76SF00098 between the United States */
/* Department of Energy and the University of California. */
/* This file is part of flex. */
/* 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. */
/* 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR */
/* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED */
/* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR */
/* PURPOSE. */
#include "libc/fmt/fmt.h"
#include "flexdef.h"
/* declare functions that have forward references */
int dupmachine PROTO((int));
void mkxtion PROTO((int, int));
/* add_accept - add an accepting state to a machine
*
* accepting_number becomes mach's accepting number.
*/
void
add_accept(mach, accepting_number)
int mach, accepting_number;
{
/*
* Hang the accepting number off an epsilon state. if it is
* associated with a state that has a non-epsilon out-transition,
* then the state will accept BEFORE it makes that transition, i.e.,
* one character too soon.
*/
if (transchar[finalst[mach]] == SYM_EPSILON)
accptnum[finalst[mach]] = accepting_number;
else {
int astate = mkstate(SYM_EPSILON);
accptnum[astate] = accepting_number;
(void) link_machines(mach, astate);
}
}
/* copysingl - make a given number of copies of a singleton machine
*
* synopsis
*
* newsng = copysingl( singl, num );
*
* newsng - a new singleton composed of num copies of singl
* singl - a singleton machine
* num - the number of copies of singl to be present in newsng
*/
int
copysingl(singl, num)
int singl, num;
{
int copy, i;
copy = mkstate(SYM_EPSILON);
for (i = 1; i <= num; ++i)
copy = link_machines(copy, dupmachine(singl));
return copy;
}
/* dumpnfa - debugging routine to write out an nfa */
void
dumpnfa(state1)
int state1;
{
int sym, tsp1, tsp2, anum, ns;
fprintf(stderr,
_
("\n\n********** beginning dump of nfa with start state %d\n"),
state1);
/*
* We probably should loop starting at firstst[state1] and going to
* lastst[state1], but they're not maintained properly when we "or"
* all of the rules together. So we use our knowledge that the
* machine starts at state 1 and ends at lastnfa.
*/
/* for ( ns = firstst[state1]; ns <= lastst[state1]; ++ns ) */
for (ns = 1; ns <= lastnfa; ++ns) {
fprintf(stderr, _("state # %4d\t"), ns);
sym = transchar[ns];
tsp1 = trans1[ns];
tsp2 = trans2[ns];
anum = accptnum[ns];
fprintf(stderr, "%3d: %4d, %4d", sym, tsp1, tsp2);
if (anum != NIL)
fprintf(stderr, " [%d]", anum);
fprintf(stderr, "\n");
}
fprintf(stderr, _("********** end of dump\n"));
}
/* dupmachine - make a duplicate of a given machine
*
* synopsis
*
* copy = dupmachine( mach );
*
* copy - holds duplicate of mach
* mach - machine to be duplicated
*
* note that the copy of mach is NOT an exact duplicate; rather, all the
* transition states values are adjusted so that the copy is self-contained,
* as the original should have been.
*
* also note that the original MUST be contiguous, with its low and high
* states accessible by the arrays firstst and lastst
*/
int
dupmachine(mach)
int mach;
{
int i, init, state_offset;
int state = 0;
int last = lastst[mach];
for (i = firstst[mach]; i <= last; ++i) {
state = mkstate(transchar[i]);
if (trans1[i] != NO_TRANSITION) {
mkxtion(finalst[state], trans1[i] + state - i);
if (transchar[i] == SYM_EPSILON &&
trans2[i] != NO_TRANSITION)
mkxtion(finalst[state],
trans2[i] + state - i);
}
accptnum[state] = accptnum[i];
}
if (state == 0)
flexfatal(_("empty machine in dupmachine()"));
state_offset = state - i + 1;
init = mach + state_offset;
firstst[init] = firstst[mach] + state_offset;
finalst[init] = finalst[mach] + state_offset;
lastst[init] = lastst[mach] + state_offset;
return init;
}
/* finish_rule - finish up the processing for a rule
*
* An accepting number is added to the given machine. If variable_trail_rule
* is true then the rule has trailing context and both the head and trail
* are variable size. Otherwise if headcnt or trailcnt is non-zero then
* the machine recognizes a pattern with trailing context and headcnt is
* the number of characters in the matched part of the pattern, or zero
* if the matched part has variable length. trailcnt is the number of
* trailing context characters in the pattern, or zero if the trailing
* context has variable length.
*/
void
finish_rule(mach, variable_trail_rule, headcnt, trailcnt,
pcont_act)
int mach, variable_trail_rule, headcnt, trailcnt, pcont_act;
{
char action_text[MAXLINE];
add_accept(mach, num_rules);
/*
* We did this in new_rule(), but it often gets the wrong number
* because we do it before we start parsing the current rule.
*/
rule_linenum[num_rules] = linenum;
/*
* If this is a continued action, then the line-number has already
* been updated, giving us the wrong number.
*/
if (continued_action)
--rule_linenum[num_rules];
/*
* If the previous rule was continued action, then we inherit the
* previous newline flag, possibly overriding the current one.
*/
if (pcont_act && rule_has_nl[num_rules - 1])
rule_has_nl[num_rules] = true;
snprintf(action_text, sizeof(action_text), "case %d:\n", num_rules);
add_action(action_text);
if (rule_has_nl[num_rules]) {
snprintf(action_text, sizeof(action_text), "/* rule %d can match eol */\n",
num_rules);
add_action(action_text);
}
if (variable_trail_rule) {
rule_type[num_rules] = RULE_VARIABLE;
if (performance_report > 0)
fprintf(stderr,
_
("Variable trailing context rule at line %d\n"),
rule_linenum[num_rules]);
variable_trailing_context_rules = true;
} else {
rule_type[num_rules] = RULE_NORMAL;
if (headcnt > 0 || trailcnt > 0) {
/*
* Do trailing context magic to not match the
* trailing characters.
*/
char *scanner_cp = "YY_G(yy_c_buf_p) = yy_cp";
char *scanner_bp = "yy_bp";
add_action
("*yy_cp = YY_G(yy_hold_char); /* undo effects of setting up yytext */\n");
if (headcnt > 0) {
if (rule_has_nl[num_rules]) {
snprintf(action_text, sizeof(action_text),
"YY_LINENO_REWIND_TO(%s + %d);\n", scanner_bp, headcnt);
add_action(action_text);
}
snprintf(action_text, sizeof(action_text), "%s = %s + %d;\n",
scanner_cp, scanner_bp, headcnt);
add_action(action_text);
} else {
if (rule_has_nl[num_rules]) {
snprintf(action_text, sizeof(action_text),
"YY_LINENO_REWIND_TO(yy_cp - %d);\n", trailcnt);
add_action(action_text);
}
snprintf(action_text, sizeof(action_text), "%s -= %d;\n",
scanner_cp, trailcnt);
add_action(action_text);
}
add_action
("YY_DO_BEFORE_ACTION; /* set up yytext again */\n");
}
}
/*
* Okay, in the action code at this point yytext and yyleng have
* their proper final values for this rule, so here's the point to do
* any user action. But don't do it for continued actions, as
* that'll result in multiple YY_RULE_SETUP's.
*/
if (!continued_action)
add_action("YY_RULE_SETUP\n");
line_directive_out((FILE *) 0, 1);
}
/* link_machines - connect two machines together
*
* synopsis
*
* new = link_machines( first, last );
*
* new - a machine constructed by connecting first to last
* first - the machine whose successor is to be last
* last - the machine whose predecessor is to be first
*
* note: this routine concatenates the machine first with the machine
* last to produce a machine new which will pattern-match first first
* and then last, and will fail if either of the sub-patterns fails.
* FIRST is set to new by the operation. last is unmolested.
*/
int
link_machines(first, last)
int first, last;
{
if (first == NIL)
return last;
else if (last == NIL)
return first;
else {
mkxtion(finalst[first], last);
finalst[first] = finalst[last];
lastst[first] = MAX(lastst[first], lastst[last]);
firstst[first] = MIN(firstst[first], firstst[last]);
return first;
}
}
/* mark_beginning_as_normal - mark each "beginning" state in a machine
* as being a "normal" (i.e., not trailing context-
* associated) states
*
* The "beginning" states are the epsilon closure of the first state
*/
void
mark_beginning_as_normal(mach)
int mach;
{
switch (state_type[mach]) {
case STATE_NORMAL:
/* Oh, we've already visited here. */
return;
case STATE_TRAILING_CONTEXT:
state_type[mach] = STATE_NORMAL;
if (transchar[mach] == SYM_EPSILON) {
if (trans1[mach] != NO_TRANSITION)
mark_beginning_as_normal(trans1[mach]);
if (trans2[mach] != NO_TRANSITION)
mark_beginning_as_normal(trans2[mach]);
}
break;
default:
flexerror(_
("bad state type in mark_beginning_as_normal()"));
break;
}
}
/* mkbranch - make a machine that branches to two machines
*
* synopsis
*
* branch = mkbranch( first, second );
*
* branch - a machine which matches either first's pattern or second's
* first, second - machines whose patterns are to be or'ed (the | operator)
*
* Note that first and second are NEITHER destroyed by the operation. Also,
* the resulting machine CANNOT be used with any other "mk" operation except
* more mkbranch's. Compare with mkor()
*/
int
mkbranch(first, second)
int first, second;
{
int eps;
if (first == NO_TRANSITION)
return second;
else if (second == NO_TRANSITION)
return first;
eps = mkstate(SYM_EPSILON);
mkxtion(eps, first);
mkxtion(eps, second);
return eps;
}
/* mkclos - convert a machine into a closure
*
* synopsis
* new = mkclos( state );
*
* new - a new state which matches the closure of "state"
*/
int
mkclos(state)
int state;
{
return mkopt(mkposcl(state));
}
/* mkopt - make a machine optional
*
* synopsis
*
* new = mkopt( mach );
*
* new - a machine which optionally matches whatever mach matched
* mach - the machine to make optional
*
* notes:
* 1. mach must be the last machine created
* 2. mach is destroyed by the call
*/
int
mkopt(mach)
int mach;
{
int eps;
if (!SUPER_FREE_EPSILON(finalst[mach])) {
eps = mkstate(SYM_EPSILON);
mach = link_machines(mach, eps);
}
/*
* Can't skimp on the following if FREE_EPSILON(mach) is true because
* some state interior to "mach" might point back to the beginning
* for a closure.
*/
eps = mkstate(SYM_EPSILON);
mach = link_machines(eps, mach);
mkxtion(mach, finalst[mach]);
return mach;
}
/* mkor - make a machine that matches either one of two machines
*
* synopsis
*
* new = mkor( first, second );
*
* new - a machine which matches either first's pattern or second's
* first, second - machines whose patterns are to be or'ed (the | operator)
*
* note that first and second are both destroyed by the operation
* the code is rather convoluted because an attempt is made to minimize
* the number of epsilon states needed
*/
int
mkor(first, second)
int first, second;
{
int eps, orend;
if (first == NIL)
return second;
else if (second == NIL)
return first;
else {
/*
* See comment in mkopt() about why we can't use the first
* state of "first" or "second" if they satisfy
* "FREE_EPSILON".
*/
eps = mkstate(SYM_EPSILON);
first = link_machines(eps, first);
mkxtion(first, second);
if (SUPER_FREE_EPSILON(finalst[first]) &&
accptnum[finalst[first]] == NIL) {
orend = finalst[first];
mkxtion(finalst[second], orend);
} else if (SUPER_FREE_EPSILON(finalst[second]) &&
accptnum[finalst[second]] == NIL) {
orend = finalst[second];
mkxtion(finalst[first], orend);
} else {
eps = mkstate(SYM_EPSILON);
first = link_machines(first, eps);
orend = finalst[first];
mkxtion(finalst[second], orend);
}
}
finalst[first] = orend;
return first;
}
/* mkposcl - convert a machine into a positive closure
*
* synopsis
* new = mkposcl( state );
*
* new - a machine matching the positive closure of "state"
*/
int
mkposcl(state)
int state;
{
int eps;
if (SUPER_FREE_EPSILON(finalst[state])) {
mkxtion(finalst[state], state);
return state;
} else {
eps = mkstate(SYM_EPSILON);
mkxtion(eps, state);
return link_machines(state, eps);
}
}
/* mkrep - make a replicated machine
*
* synopsis
* new = mkrep( mach, lb, ub );
*
* new - a machine that matches whatever "mach" matched from "lb"
* number of times to "ub" number of times
*
* note
* if "ub" is INFINITE_REPEAT then "new" matches "lb" or more occurrences of "mach"
*/
int
mkrep(mach, lb, ub)
int mach, lb, ub;
{
int base_mach, tail, copy, i;
base_mach = copysingl(mach, lb - 1);
if (ub == INFINITE_REPEAT) {
copy = dupmachine(mach);
mach = link_machines(mach,
link_machines(base_mach,
mkclos(copy)));
} else {
tail = mkstate(SYM_EPSILON);
for (i = lb; i < ub; ++i) {
copy = dupmachine(mach);
tail = mkopt(link_machines(copy, tail));
}
mach =
link_machines(mach,
link_machines(base_mach, tail));
}
return mach;
}
/* mkstate - create a state with a transition on a given symbol
*
* synopsis
*
* state = mkstate( sym );
*
* state - a new state matching sym
* sym - the symbol the new state is to have an out-transition on
*
* note that this routine makes new states in ascending order through the
* state array (and increments LASTNFA accordingly). The routine DUPMACHINE
* relies on machines being made in ascending order and that they are
* CONTIGUOUS. Change it and you will have to rewrite DUPMACHINE (kludge
* that it admittedly is)
*/
int
mkstate(sym)
int sym;
{
if (++lastnfa >= current_mns) {
if ((current_mns += MNS_INCREMENT) >= maximum_mns)
lerrif(_
("input rules are too complicated (>= %d NFA states)"),
current_mns);
++num_reallocs;
firstst = reallocate_integer_array(firstst, current_mns);
lastst = reallocate_integer_array(lastst, current_mns);
finalst = reallocate_integer_array(finalst, current_mns);
transchar =
reallocate_integer_array(transchar, current_mns);
trans1 = reallocate_integer_array(trans1, current_mns);
trans2 = reallocate_integer_array(trans2, current_mns);
accptnum =
reallocate_integer_array(accptnum, current_mns);
assoc_rule =
reallocate_integer_array(assoc_rule, current_mns);
state_type =
reallocate_integer_array(state_type, current_mns);
}
firstst[lastnfa] = lastnfa;
finalst[lastnfa] = lastnfa;
lastst[lastnfa] = lastnfa;
transchar[lastnfa] = sym;
trans1[lastnfa] = NO_TRANSITION;
trans2[lastnfa] = NO_TRANSITION;
accptnum[lastnfa] = NIL;
assoc_rule[lastnfa] = num_rules;
state_type[lastnfa] = current_state_type;
/*
* Fix up equivalence classes base on this transition. Note that any
* character which has its own transition gets its own equivalence
* class. Thus only characters which are only in character classes
* have a chance at being in the same equivalence class. E.g. "a|b"
* puts 'a' and 'b' into two different equivalence classes. "[ab]"
* puts them in the same equivalence class (barring other differences
* elsewhere in the input).
*/
if (sym < 0) {
/*
* We don't have to update the equivalence classes since that
* was already done when the ccl was created for the first
* time.
*/
} else if (sym == SYM_EPSILON)
++numeps;
else {
check_char(sym);
if (useecs)
/* Map NUL's to csize. */
mkechar(sym ? sym : csize, nextecm, ecgroup);
}
return lastnfa;
}
/* mkxtion - make a transition from one state to another
*
* synopsis
*
* mkxtion( statefrom, stateto );
*
* statefrom - the state from which the transition is to be made
* stateto - the state to which the transition is to be made
*/
void
mkxtion(statefrom, stateto)
int statefrom, stateto;
{
if (trans1[statefrom] == NO_TRANSITION)
trans1[statefrom] = stateto;
else if ((transchar[statefrom] != SYM_EPSILON) ||
(trans2[statefrom] != NO_TRANSITION))
flexfatal(_("found too many transitions in mkxtion()"));
else { /* second out-transition for an epsilon state */
++eps2;
trans2[statefrom] = stateto;
}
}
/* new_rule - initialize for a new rule */
void
new_rule()
{
if (++num_rules >= current_max_rules) {
++num_reallocs;
current_max_rules += MAX_RULES_INCREMENT;
rule_type = reallocate_integer_array(rule_type,
current_max_rules);
rule_linenum = reallocate_integer_array(rule_linenum,
current_max_rules);
rule_useful = reallocate_integer_array(rule_useful,
current_max_rules);
rule_has_nl = reallocate_bool_array(rule_has_nl,
current_max_rules);
}
if (num_rules > MAX_RULE)
lerrif(_("too many rules (> %d)!"), MAX_RULE);
rule_linenum[num_rules] = linenum;
rule_useful[num_rules] = false;
rule_has_nl[num_rules] = false;
}

View file

@ -1,285 +0,0 @@
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
vi: set et ft=c ts=8 sw=8 fenc=utf-8 :vi
*/
/* clang-format off */
/* $OpenBSD: options.c,v 1.2 2015/11/19 22:16:43 tedu Exp $ */
/* flex - tool to generate fast lexical analyzers */
/* Copyright (c) 1990 The Regents of the University of California. */
/* All rights reserved. */
/* This code is derived from software contributed to Berkeley by */
/* Vern Paxson. */
/* The United States Government has rights in this work pursuant */
/* to contract no. DE-AC03-76SF00098 between the United States */
/* Department of Energy and the University of California. */
/* This file is part of flex. */
/* 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. */
/* 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR */
/* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED */
/* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR */
/* PURPOSE. */
#include "options.h"
/* Be sure to synchronize these options with those defined in "options.h",
* the giant switch() statement in "main.c", and the %option processing in
* "scan.l".
*/
/* The command-line options, passed to scanopt_init() */
optspec_t flexopts[] = {
{"-7", OPT_7BIT, 0}
,
{"--7bit", OPT_7BIT, 0}
, /* Generate 7-bit scanner. */
{"-8", OPT_8BIT, 0}
,
{"--8bit", OPT_8BIT, 0}
, /* Generate 8-bit scanner. */
{"--align", OPT_ALIGN, 0}
, /* Trade off larger tables for better memory alignment. */
{"--noalign", OPT_NO_ALIGN, 0}
,
{"--always-interactive", OPT_ALWAYS_INTERACTIVE, 0}
,
{"--array", OPT_ARRAY, 0}
,
{"-b", OPT_BACKUP, 0}
,
{"--backup", OPT_BACKUP, 0}
, /* Generate backing-up information to lex.backup. */
{"-B", OPT_BATCH, 0}
,
{"--batch", OPT_BATCH, 0}
, /* Generate batch scanner (opposite of -I). */
{"--bison-bridge", OPT_BISON_BRIDGE, 0}
, /* Scanner to be called by a bison pure parser. */
{"--bison-locations", OPT_BISON_BRIDGE_LOCATIONS, 0}
, /* Scanner to be called by a bison pure parser. */
{"-i", OPT_CASE_INSENSITIVE, 0}
,
{"--case-insensitive", OPT_CASE_INSENSITIVE, 0}
, /* Generate case-insensitive scanner. */
{"-C[aefFmr]", OPT_COMPRESSION,
"Specify degree of table compression (default is -Cem)"},
{"-+", OPT_CPLUSPLUS, 0}
,
{"--c++", OPT_CPLUSPLUS, 0}
, /* Generate C++ scanner class. */
{"-d", OPT_DEBUG, 0}
,
{"--debug", OPT_DEBUG, 0}
, /* Turn on debug mode in generated scanner. */
{"--nodebug", OPT_NO_DEBUG, 0}
,
{"-s", OPT_NO_DEFAULT, 0}
,
{"--nodefault", OPT_NO_DEFAULT, 0}
, /* Suppress default rule to ECHO unmatched text. */
{"--default", OPT_DEFAULT, 0}
,
{"-c", OPT_DONOTHING, 0}
, /* For POSIX lex compatibility. */
{"-n", OPT_DONOTHING, 0}
, /* For POSIX lex compatibility. */
{"--ecs", OPT_ECS, 0}
, /* Construct equivalence classes. */
{"--noecs", OPT_NO_ECS, 0}
,
{"-F", OPT_FAST, 0}
,
{"--fast", OPT_FAST, 0}
, /* Same as -CFr. */
{"-f", OPT_FULL, 0}
,
{"--full", OPT_FULL, 0}
, /* Same as -Cfr. */
{"--header-file[=FILE]", OPT_HEADER_FILE, 0}
,
{"-?", OPT_HELP, 0}
,
{"-h", OPT_HELP, 0}
,
{"--help", OPT_HELP, 0}
, /* Produce this help message. */
{"-I", OPT_INTERACTIVE, 0}
,
{"--interactive", OPT_INTERACTIVE, 0}
, /* Generate interactive scanner (opposite of -B). */
{"-l", OPT_LEX_COMPAT, 0}
,
{"--lex-compat", OPT_LEX_COMPAT, 0}
, /* Maximal compatibility with original lex. */
{"-X", OPT_POSIX_COMPAT, 0}
,
{"--posix-compat", OPT_POSIX_COMPAT, 0}
, /* Maximal compatibility with POSIX lex. */
{"--preproc=NUM", OPT_PREPROC_LEVEL, 0}
,
{"-L", OPT_NO_LINE, 0}
, /* Suppress #line directives in scanner. */
{"--noline", OPT_NO_LINE, 0}
, /* Suppress #line directives in scanner. */
{"--main", OPT_MAIN, 0}
, /* use built-in main() function. */
{"--nomain", OPT_NO_MAIN, 0}
,
{"--meta-ecs", OPT_META_ECS, 0}
, /* Construct meta-equivalence classes. */
{"--nometa-ecs", OPT_NO_META_ECS, 0}
,
{"--never-interactive", OPT_NEVER_INTERACTIVE, 0}
,
{"-o FILE", OPT_OUTFILE, 0}
,
{"--outfile=FILE", OPT_OUTFILE, 0}
, /* Write to FILE (default is lex.yy.c) */
{"-p", OPT_PERF_REPORT, 0}
,
{"--perf-report", OPT_PERF_REPORT, 0}
, /* Generate performance report to stderr. */
{"--pointer", OPT_POINTER, 0}
,
{"-P PREFIX", OPT_PREFIX, 0}
,
{"--prefix=PREFIX", OPT_PREFIX, 0}
, /* Use PREFIX (default is yy) */
{"-Dmacro", OPT_PREPROCDEFINE, 0}
, /* Define a preprocessor symbol. */
{"--read", OPT_READ, 0}
, /* Use read(2) instead of stdio. */
{"-R", OPT_REENTRANT, 0}
,
{"--reentrant", OPT_REENTRANT, 0}
, /* Generate a reentrant C scanner. */
{"--noreentrant", OPT_NO_REENTRANT, 0}
,
{"--reject", OPT_REJECT, 0}
,
{"--noreject", OPT_NO_REJECT, 0}
,
{"-S FILE", OPT_SKEL, 0}
,
{"--skel=FILE", OPT_SKEL, 0}
, /* Use skeleton from FILE */
{"--stack", OPT_STACK, 0}
,
{"--stdinit", OPT_STDINIT, 0}
,
{"--nostdinit", OPT_NO_STDINIT, 0}
,
{"-t", OPT_STDOUT, 0}
,
{"--stdout", OPT_STDOUT, 0}
, /* Write generated scanner to stdout. */
{"-T", OPT_TRACE, 0}
,
{"--trace", OPT_TRACE, 0}
, /* Flex should run in trace mode. */
{"--tables-file[=FILE]", OPT_TABLES_FILE, 0}
, /* Save tables to FILE */
{"--tables-verify", OPT_TABLES_VERIFY, 0}
, /* Tables integrity check */
{"--nounistd", OPT_NO_UNISTD_H, 0}
, /* Do not include unistd.h */
{"-v", OPT_VERBOSE, 0}
,
{"--verbose", OPT_VERBOSE, 0}
, /* Write summary of scanner statistics to stdout. */
{"-V", OPT_VERSION, 0}
,
{"--version", OPT_VERSION, 0}
, /* Report flex version. */
{"--warn", OPT_WARN, 0}
,
{"-w", OPT_NO_WARN, 0}
,
{"--nowarn", OPT_NO_WARN, 0}
, /* Suppress warning messages. */
{"--noansi-definitions", OPT_NO_ANSI_FUNC_DEFS, 0}
,
{"--noansi-prototypes", OPT_NO_ANSI_FUNC_PROTOS, 0}
,
{"--yyclass=NAME", OPT_YYCLASS, 0}
,
{"--yylineno", OPT_YYLINENO, 0}
,
{"--noyylineno", OPT_NO_YYLINENO, 0}
,
{"--yymore", OPT_YYMORE, 0}
,
{"--noyymore", OPT_NO_YYMORE, 0}
,
{"--noyywrap", OPT_NO_YYWRAP, 0}
,
{"--yywrap", OPT_YYWRAP, 0}
,
{"--nounput", OPT_NO_UNPUT, 0}
,
{"--noyy_push_state", OPT_NO_YY_PUSH_STATE, 0}
,
{"--noyy_pop_state", OPT_NO_YY_POP_STATE, 0}
,
{"--noyy_top_state", OPT_NO_YY_TOP_STATE, 0}
,
{"--noyy_scan_buffer", OPT_NO_YY_SCAN_BUFFER, 0}
,
{"--noyy_scan_bytes", OPT_NO_YY_SCAN_BYTES, 0}
,
{"--noyy_scan_string", OPT_NO_YY_SCAN_STRING, 0}
,
{"--noyyget_extra", OPT_NO_YYGET_EXTRA, 0}
,
{"--noyyset_extra", OPT_NO_YYSET_EXTRA, 0}
,
{"--noyyget_leng", OPT_NO_YYGET_LENG, 0}
,
{"--noyyget_text", OPT_NO_YYGET_TEXT, 0}
,
{"--noyyget_lineno", OPT_NO_YYGET_LINENO, 0}
,
{"--noyyset_lineno", OPT_NO_YYSET_LINENO, 0}
,
{"--noyyget_in", OPT_NO_YYGET_IN, 0}
,
{"--noyyset_in", OPT_NO_YYSET_IN, 0}
,
{"--noyyget_out", OPT_NO_YYGET_OUT, 0}
,
{"--noyyset_out", OPT_NO_YYSET_OUT, 0}
,
{"--noyyget_lval", OPT_NO_YYGET_LVAL, 0}
,
{"--noyyset_lval", OPT_NO_YYSET_LVAL, 0}
,
{"--noyyget_lloc", OPT_NO_YYGET_LLOC, 0}
,
{"--noyyset_lloc", OPT_NO_YYSET_LLOC, 0}
,
{0, 0, 0} /* required final NULL entry. */
};

View file

@ -1,135 +0,0 @@
/* clang-format off */
/* $OpenBSD: options.h,v 1.2 2015/11/19 22:16:43 tedu Exp $ */
/* flex - tool to generate fast lexical analyzers */
/* Copyright (c) 1990 The Regents of the University of California. */
/* All rights reserved. */
/* This code is derived from software contributed to Berkeley by */
/* Vern Paxson. */
/* The United States Government has rights in this work pursuant */
/* to contract no. DE-AC03-76SF00098 between the United States */
/* Department of Energy and the University of California. */
/* This file is part of flex. */
/* 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. */
/* 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR */
/* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED */
/* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR */
/* PURPOSE. */
#ifndef OPTIONS_H
#define OPTIONS_H
#include "scanopt.h"
extern optspec_t flexopts[];
enum flexopt_flag_t {
/* Use positive integers only, since they are return codes for scanopt.
* Order is not important. */
OPT_7BIT = 1,
OPT_8BIT,
OPT_ALIGN,
OPT_ALWAYS_INTERACTIVE,
OPT_ARRAY,
OPT_BACKUP,
OPT_BATCH,
OPT_BISON_BRIDGE,
OPT_BISON_BRIDGE_LOCATIONS,
OPT_CASE_INSENSITIVE,
OPT_COMPRESSION,
OPT_CPLUSPLUS,
OPT_DEBUG,
OPT_DEFAULT,
OPT_DONOTHING,
OPT_ECS,
OPT_FAST,
OPT_FULL,
OPT_HEADER_FILE,
OPT_HELP,
OPT_INTERACTIVE,
OPT_LEX_COMPAT,
OPT_POSIX_COMPAT,
OPT_MAIN,
OPT_META_ECS,
OPT_NEVER_INTERACTIVE,
OPT_NO_ALIGN,
OPT_NO_ANSI_FUNC_DEFS,
OPT_NO_ANSI_FUNC_PROTOS,
OPT_NO_DEBUG,
OPT_NO_DEFAULT,
OPT_NO_ECS,
OPT_NO_LINE,
OPT_NO_MAIN,
OPT_NO_META_ECS,
OPT_NO_REENTRANT,
OPT_NO_REJECT,
OPT_NO_STDINIT,
OPT_NO_UNPUT,
OPT_NO_WARN,
OPT_NO_YYGET_EXTRA,
OPT_NO_YYGET_IN,
OPT_NO_YYGET_LENG,
OPT_NO_YYGET_LINENO,
OPT_NO_YYGET_LLOC,
OPT_NO_YYGET_LVAL,
OPT_NO_YYGET_OUT,
OPT_NO_YYGET_TEXT,
OPT_NO_YYLINENO,
OPT_NO_YYMORE,
OPT_NO_YYSET_EXTRA,
OPT_NO_YYSET_IN,
OPT_NO_YYSET_LINENO,
OPT_NO_YYSET_LLOC,
OPT_NO_YYSET_LVAL,
OPT_NO_YYSET_OUT,
OPT_NO_YYWRAP,
OPT_NO_YY_POP_STATE,
OPT_NO_YY_PUSH_STATE,
OPT_NO_YY_SCAN_BUFFER,
OPT_NO_YY_SCAN_BYTES,
OPT_NO_YY_SCAN_STRING,
OPT_NO_YY_TOP_STATE,
OPT_OUTFILE,
OPT_PERF_REPORT,
OPT_POINTER,
OPT_PREFIX,
OPT_PREPROCDEFINE,
OPT_PREPROC_LEVEL,
OPT_READ,
OPT_REENTRANT,
OPT_REJECT,
OPT_SKEL,
OPT_STACK,
OPT_STDINIT,
OPT_STDOUT,
OPT_TABLES_FILE,
OPT_TABLES_VERIFY,
OPT_TRACE,
OPT_NO_UNISTD_H,
OPT_VERBOSE,
OPT_VERSION,
OPT_WARN,
OPT_YYCLASS,
OPT_YYLINENO,
OPT_YYMORE,
OPT_YYWRAP
};
#endif

1810
third_party/lex/parse.c vendored

File diff suppressed because it is too large Load diff

View file

@ -1,45 +0,0 @@
#define CHAR 257
#define NUMBER 258
#define SECTEND 259
#define SCDECL 260
#define XSCDECL 261
#define NAME 262
#define PREVCCL 263
#define EOF_OP 264
#define OPTION_OP 265
#define OPT_OUTFILE 266
#define OPT_PREFIX 267
#define OPT_YYCLASS 268
#define OPT_HEADER 269
#define OPT_EXTRA_TYPE 270
#define OPT_TABLES 271
#define CCE_ALNUM 272
#define CCE_ALPHA 273
#define CCE_BLANK 274
#define CCE_CNTRL 275
#define CCE_DIGIT 276
#define CCE_GRAPH 277
#define CCE_LOWER 278
#define CCE_PRINT 279
#define CCE_PUNCT 280
#define CCE_SPACE 281
#define CCE_UPPER 282
#define CCE_XDIGIT 283
#define CCE_NEG_ALNUM 284
#define CCE_NEG_ALPHA 285
#define CCE_NEG_BLANK 286
#define CCE_NEG_CNTRL 287
#define CCE_NEG_DIGIT 288
#define CCE_NEG_GRAPH 289
#define CCE_NEG_LOWER 290
#define CCE_NEG_PRINT 291
#define CCE_NEG_PUNCT 292
#define CCE_NEG_SPACE 293
#define CCE_NEG_UPPER 294
#define CCE_NEG_XDIGIT 295
#define CCL_OP_DIFF 296
#define CCL_OP_UNION 297
#define BEGIN_REPEAT_POSIX 298
#define END_REPEAT_POSIX 299
#define BEGIN_REPEAT_FLEX 300
#define END_REPEAT_FLEX 301

1089
third_party/lex/parse.y vendored

File diff suppressed because it is too large Load diff

View file

@ -1,181 +0,0 @@
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
vi: set et ft=c ts=8 sw=8 fenc=utf-8 :vi
*/
/* clang-format off */
/* $OpenBSD: regex.c,v 1.3 2015/11/19 23:20:34 tedu Exp $ */
/** regex - regular expression functions related to POSIX regex lib. */
/* This file is part of flex. */
/* 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. */
/* 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR */
/* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED */
/* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR */
/* PURPOSE. */
#include "libc/str/str.h"
#include "libc/mem/mem.h"
#include "libc/fmt/fmt.h"
#include "libc/fmt/conv.h"
#include "flexdef.h"
static const char* REGEXP_LINEDIR = "^#line ([[:digit:]]+) \"(.*)\"";
static const char* REGEXP_BLANK_LINE = "^[[:space:]]*$";
regex_t regex_linedir; /**< matches line directives */
regex_t regex_blank_line; /**< matches blank lines */
/** Initialize the regular expressions.
* @return true upon success.
*/
bool flex_init_regex(void)
{
flex_regcomp(&regex_linedir, REGEXP_LINEDIR, REG_EXTENDED);
flex_regcomp(&regex_blank_line, REGEXP_BLANK_LINE, REG_EXTENDED);
return true;
}
/** Compiles a regular expression or dies trying.
* @param preg Same as for regcomp().
* @param regex Same as for regcomp().
* @param cflags Same as for regcomp().
*/
void flex_regcomp(regex_t *preg, const char *regex, int cflags)
{
int err;
memset (preg, 0, sizeof (regex_t));
if ((err = regcomp (preg, regex, cflags)) != 0) {
const int errbuf_sz = 200;
char *errbuf, *rxerr;
errbuf = (char*)malloc(errbuf_sz *sizeof(char));
if (!errbuf)
flexfatal(_("Unable to allocate buffer to report regcomp"));
rxerr = (char*)malloc(errbuf_sz *sizeof(char));
if (!rxerr)
flexfatal(_("Unable to allocate buffer for regerror"));
regerror (err, preg, rxerr, errbuf_sz);
snprintf (errbuf, errbuf_sz, "regcomp for \"%s\" failed: %s", regex, rxerr);
flexfatal (errbuf);
free(errbuf);
free(rxerr);
}
}
/** Extract a copy of the match, or NULL if no match.
* @param m A match as returned by regexec().
* @param src The source string that was passed to regexec().
* @return The allocated string.
*/
char *regmatch_dup (regmatch_t * m, const char *src)
{
char *str;
int len;
if (m == NULL || m->rm_so < 0)
return NULL;
len = m->rm_eo - m->rm_so;
str = (char *) malloc ((len + 1) * sizeof (char));
if (!str)
flexfatal(_("Unable to allocate a copy of the match"));
strncpy (str, src + m->rm_so, len);
str[len] = 0;
return str;
}
/** Copy the match.
* @param m A match as returned by regexec().
* @param dest The destination buffer.
* @param src The source string that was passed to regexec().
* @return dest
*/
char *regmatch_cpy (regmatch_t * m, char *dest, const char *src)
{
if (m == NULL || m->rm_so < 0) {
if (dest)
dest[0] = '\0';
return dest;
}
snprintf (dest, regmatch_len(m), "%s", src + m->rm_so);
return dest;
}
/** Get the length in characters of the match.
* @param m A match as returned by regexec().
* @param src The source string that was passed to regexec().
* @return The length of the match.
*/
int regmatch_len (regmatch_t * m)
{
if (m == NULL || m->rm_so < 0) {
return 0;
}
return m->rm_eo - m->rm_so;
}
/** Convert a regmatch_t object to an integer using the strtol() function.
* @param m A match as returned by regexec().
* @param src The source string that was passed to regexec().
* @param endptr Same as the second argument to strtol().
* @param base Same as the third argument to strtol().
* @return The converted integer or error (Return value is the same as for strtol()).
*/
int regmatch_strtol (regmatch_t * m, const char *src, char **endptr,
int base2)
{
int n = 0;
#define bufsz 20
char buf[bufsz];
char *s;
if (m == NULL || m->rm_so < 0)
return 0;
if (regmatch_len (m) < bufsz)
s = regmatch_cpy (m, buf, src);
else
s = regmatch_dup (m, src);
n = strtol (s, endptr, base2);
if (s != buf)
free (s);
return n;
}
/** Check for empty or non-existent match.
* @param m A match as returned by regexec().
* @return false if match length is non-zero.
* Note that reg_empty returns true even if match did not occur at all.
*/
bool regmatch_empty (regmatch_t * m)
{
return (m == NULL || m->rm_so < 0 || m->rm_so == m->rm_eo);
}

4588
third_party/lex/scan.c vendored

File diff suppressed because it is too large Load diff

1010
third_party/lex/scan.l vendored

File diff suppressed because it is too large Load diff

View file

@ -1,75 +0,0 @@
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
vi: set et ft=c ts=8 sw=8 fenc=utf-8 :vi
*/
/* clang-format off */
/* $OpenBSD: scanflags.c,v 1.3 2015/11/19 23:20:34 tedu Exp $ */
/* scanflags - flags used by scanning. */
/* Copyright (c) 1990 The Regents of the University of California. */
/* All rights reserved. */
/* This code is derived from software contributed to Berkeley by */
/* Vern Paxson. */
/* The United States Government has rights in this work pursuant */
/* to contract no. DE-AC03-76SF00098 between the United States */
/* Department of Energy and the University of California. */
/* This file is part of flex. */
/* 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. */
/* 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR */
/* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED */
/* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR */
/* PURPOSE. */
#include "libc/mem/mem.h"
#include "libc/assert.h"
#include "third_party/lex/flexdef.h"
scanflags_t* _sf_stk = NULL;
size_t _sf_top_ix=0, _sf_max=0;
void
sf_push (void)
{
if (_sf_top_ix + 1 >= _sf_max)
_sf_stk = (scanflags_t*) realloc ( (void*) _sf_stk, sizeof(scanflags_t) * (_sf_max += 32));
// copy the top element
_sf_stk[_sf_top_ix + 1] = _sf_stk[_sf_top_ix];
++_sf_top_ix;
}
void
sf_pop (void)
{
assert(_sf_top_ix > 0);
--_sf_top_ix;
}
/* one-time initialization. Should be called before any sf_ functions. */
void
sf_init (void)
{
assert(_sf_stk == NULL);
_sf_stk = (scanflags_t*) malloc ( sizeof(scanflags_t) * (_sf_max = 32));
if (!_sf_stk)
lerrsf_fatal(_("Unable to allocate %ld of stack"),
(void *)sizeof(scanflags_t));
_sf_stk[_sf_top_ix] = 0;
}

View file

@ -1,881 +0,0 @@
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
vi: set et ft=c ts=8 sw=8 fenc=utf-8 :vi
*/
/* clang-format off */
/* $OpenBSD: scanopt.c,v 1.6 2017/05/31 07:20:26 tedu Exp $ */
/* flex - tool to generate fast lexical analyzers */
/* Copyright (c) 1990 The Regents of the University of California. */
/* All rights reserved. */
/* This code is derived from software contributed to Berkeley by */
/* Vern Paxson. */
/* The United States Government has rights in this work pursuant */
/* to contract no. DE-AC03-76SF00098 between the United States */
/* Department of Energy and the University of California. */
/* This file is part of flex. */
/* 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. */
/* 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR */
/* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED */
/* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR */
/* PURPOSE. */
#include "flexdef.h"
#include "libc/str/str.h"
#include "libc/fmt/conv.h"
#include "libc/mem/mem.h"
#include "libc/str/str.h"
#include "libc/str/str.h"
#include "libc/mem/mem.h"
#include "scanopt.h"
/* Internal structures */
#ifdef HAVE_STRCASECMP
#define STRCASECMP(a,b) strcasecmp(a,b)
#else
static int STRCASECMP PROTO ((const char *, const char *));
static int STRCASECMP (a, b)
const char *a;
const char *b;
{
while (tolower ((u_char)*a++) == tolower ((u_char)*b++)) ;
return b - a;
}
#endif
#define ARG_NONE 0x01
#define ARG_REQ 0x02
#define ARG_OPT 0x04
#define IS_LONG 0x08
struct _aux {
int flags; /* The above hex flags. */
int namelen; /* Length of the actual option word, e.g., "--file[=foo]" is 4 */
int printlen; /* Length of entire string, e.g., "--file[=foo]" is 12 */
};
struct _scanopt_t {
const optspec_t *options; /* List of options. */
struct _aux *aux; /* Auxiliary data about options. */
int optc; /* Number of options. */
int argc; /* Number of args. */
char **argv; /* Array of strings. */
int index; /* Used as: argv[index][subscript]. */
int subscript;
char no_err_msg; /* If true, do not print errors. */
char has_long;
char has_short;
};
/* Accessor functions. These WOULD be one-liners, but portability calls. */
static const char *NAME PROTO ((struct _scanopt_t *, int));
static int PRINTLEN PROTO ((struct _scanopt_t *, int));
static int RVAL PROTO ((struct _scanopt_t *, int));
static int FLAGS PROTO ((struct _scanopt_t *, int));
static const char *DESC PROTO ((struct _scanopt_t *, int));
static int scanopt_err PROTO ((struct _scanopt_t *, int, int, int));
static int matchlongopt PROTO ((char *, char **, int *, char **, int *));
static int find_opt
PROTO ((struct _scanopt_t *, int, char *, int, int *, int *opt_offset));
static const char *NAME (s, i)
struct _scanopt_t *s;
int i;
{
return s->options[i].opt_fmt +
((s->aux[i].flags & IS_LONG) ? 2 : 1);
}
static int PRINTLEN (s, i)
struct _scanopt_t *s;
int i;
{
return s->aux[i].printlen;
}
static int RVAL (s, i)
struct _scanopt_t *s;
int i;
{
return s->options[i].r_val;
}
static int FLAGS (s, i)
struct _scanopt_t *s;
int i;
{
return s->aux[i].flags;
}
static const char *DESC (s, i)
struct _scanopt_t *s;
int i;
{
return s->options[i].desc ? s->options[i].desc : "";
}
#ifndef NO_SCANOPT_USAGE
static int get_cols PROTO ((void));
static int get_cols ()
{
char *env;
int cols = 80; /* default */
#ifdef HAVE_NCURSES_H
initscr ();
endwin ();
if (COLS > 0)
return COLS;
#endif
if ((env = getenv ("COLUMNS")) != NULL)
cols = atoi (env);
return cols;
}
#endif
/* Macro to check for NULL before assigning a value. */
#define SAFE_ASSIGN(ptr,val) \
do{ \
if((ptr)!=NULL) \
*(ptr) = val; \
}while(0)
/* Macro to assure we reset subscript whenever we adjust s->index.*/
#define INC_INDEX(s,n) \
do{ \
(s)->index += (n); \
(s)->subscript= 0; \
}while(0)
scanopt_t *scanopt_init (options, argc, argv, flags)
const optspec_t *options;
int argc;
char **argv;
int flags;
{
int i;
struct _scanopt_t *s;
s = (struct _scanopt_t *) malloc (sizeof (struct _scanopt_t));
s->options = options;
s->optc = 0;
s->argc = argc;
s->argv = (char **) argv;
s->index = 1;
s->subscript = 0;
s->no_err_msg = (flags & SCANOPT_NO_ERR_MSG);
s->has_long = 0;
s->has_short = 0;
/* Determine option count. (Find entry with all zeros). */
s->optc = 0;
while (options[s->optc].opt_fmt
|| options[s->optc].r_val || options[s->optc].desc)
s->optc++;
/* Build auxiliary data */
s->aux = (struct _aux *) malloc (s->optc * sizeof (struct _aux));
for (i = 0; i < s->optc; i++) {
const u_char *p, *pname;
const struct optspec_t *opt;
struct _aux *aux;
opt = s->options + i;
aux = s->aux + i;
aux->flags = ARG_NONE;
if (opt->opt_fmt[0] == '-' && opt->opt_fmt[1] == '-') {
aux->flags |= IS_LONG;
pname = (const u_char *)(opt->opt_fmt + 2);
s->has_long = 1;
}
else {
pname = (const u_char *)(opt->opt_fmt + 1);
s->has_short = 1;
}
aux->printlen = strlen (opt->opt_fmt);
aux->namelen = 0;
for (p = pname + 1; *p; p++) {
/* detect required arg */
if (*p == '=' || isspace (*p)
|| !(aux->flags & IS_LONG)) {
if (aux->namelen == 0)
aux->namelen = p - pname;
aux->flags |= ARG_REQ;
aux->flags &= ~ARG_NONE;
}
/* detect optional arg. This overrides required arg. */
if (*p == '[') {
if (aux->namelen == 0)
aux->namelen = p - pname;
aux->flags &= ~(ARG_REQ | ARG_NONE);
aux->flags |= ARG_OPT;
break;
}
}
if (aux->namelen == 0)
aux->namelen = p - pname;
}
return (scanopt_t *) s;
}
#ifndef NO_SCANOPT_USAGE
/* these structs are for scanopt_usage(). */
struct usg_elem {
int idx;
struct usg_elem *next;
struct usg_elem *alias;
};
typedef struct usg_elem usg_elem;
/* Prints a usage message based on contents of optlist.
* Parameters:
* scanner - The scanner, already initialized with scanopt_init().
* fp - The file stream to write to.
* usage - Text to be prepended to option list.
* Return: Always returns 0 (zero).
* The output looks something like this:
[indent][option, alias1, alias2...][indent][description line1
description line2...]
*/
int scanopt_usage (scanner, fp, usage)
scanopt_t *scanner;
FILE *fp;
const char *usage;
{
struct _scanopt_t *s;
int i, columns, indent = 2;
usg_elem *byr_val = NULL; /* option indices sorted by r_val */
usg_elem *store; /* array of preallocated elements. */
int store_idx = 0;
usg_elem *ue;
int maxlen[2];
int desccol = 0;
int print_run = 0;
maxlen[0] = 0;
maxlen[1] = 0;
s = (struct _scanopt_t *) scanner;
if (usage) {
fprintf (fp, "%s\n", usage);
}
else {
/* Find the basename of argv[0] */
const char *p;
p = s->argv[0] + strlen (s->argv[0]);
while (p != s->argv[0] && *p != '/')
--p;
if (*p == '/')
p++;
fprintf (fp, _("Usage: %s [OPTIONS]...\n"), p);
}
fprintf (fp, "\n");
/* Sort by r_val and string. Yes, this is O(n*n), but n is small. */
store = (usg_elem *) malloc (s->optc * sizeof (usg_elem));
for (i = 0; i < s->optc; i++) {
/* grab the next preallocate node. */
ue = store + store_idx++;
ue->idx = i;
ue->next = ue->alias = NULL;
/* insert into list. */
if (!byr_val)
byr_val = ue;
else {
int found_alias = 0;
usg_elem **ue_curr, **ptr_if_no_alias = NULL;
ue_curr = &byr_val;
while (*ue_curr) {
if (RVAL (s, (*ue_curr)->idx) ==
RVAL (s, ue->idx)) {
/* push onto the alias list. */
ue_curr = &((*ue_curr)->alias);
found_alias = 1;
break;
}
if (!ptr_if_no_alias
&&
STRCASECMP (NAME (s, (*ue_curr)->idx),
NAME (s, ue->idx)) > 0) {
ptr_if_no_alias = ue_curr;
}
ue_curr = &((*ue_curr)->next);
}
if (!found_alias && ptr_if_no_alias)
ue_curr = ptr_if_no_alias;
ue->next = *ue_curr;
*ue_curr = ue;
}
}
#if 0
if (1) {
printf ("ORIGINAL:\n");
for (i = 0; i < s->optc; i++)
printf ("%2d: %s\n", i, NAME (s, i));
printf ("SORTED:\n");
ue = byr_val;
while (ue) {
usg_elem *ue2;
printf ("%2d: %s\n", ue->idx, NAME (s, ue->idx));
for (ue2 = ue->alias; ue2; ue2 = ue2->next)
printf (" +---> %2d: %s\n", ue2->idx,
NAME (s, ue2->idx));
ue = ue->next;
}
}
#endif
/* Now build each row of output. */
/* first pass calculate how much room we need. */
for (ue = byr_val; ue; ue = ue->next) {
usg_elem *ap;
int len = 0;
int nshort = 0, nlong = 0;
#define CALC_LEN(i) do {\
if(FLAGS(s,i) & IS_LONG) \
len += (nlong++||nshort) ? 2+PRINTLEN(s,i) : PRINTLEN(s,i);\
else\
len += (nshort++||nlong)? 2+PRINTLEN(s,i) : PRINTLEN(s,i);\
}while(0)
if (!(FLAGS (s, ue->idx) & IS_LONG))
CALC_LEN (ue->idx);
/* do short aliases first. */
for (ap = ue->alias; ap; ap = ap->next) {
if (FLAGS (s, ap->idx) & IS_LONG)
continue;
CALC_LEN (ap->idx);
}
if (FLAGS (s, ue->idx) & IS_LONG)
CALC_LEN (ue->idx);
/* repeat the above loop, this time for long aliases. */
for (ap = ue->alias; ap; ap = ap->next) {
if (!(FLAGS (s, ap->idx) & IS_LONG))
continue;
CALC_LEN (ap->idx);
}
if (len > maxlen[0])
maxlen[0] = len;
/* It's much easier to calculate length for description column! */
len = strlen (DESC (s, ue->idx));
if (len > maxlen[1])
maxlen[1] = len;
}
/* Determine how much room we have, and how much we will allocate to each col.
* Do not address pathological cases. Output will just be ugly. */
columns = get_cols () - 1;
if (maxlen[0] + maxlen[1] + indent * 2 > columns) {
/* col 0 gets whatever it wants. we'll wrap the desc col. */
maxlen[1] = columns - (maxlen[0] + indent * 2);
if (maxlen[1] < 14) /* 14 is arbitrary lower limit on desc width. */
maxlen[1] = INT_MAX;
}
desccol = maxlen[0] + indent * 2;
#define PRINT_SPACES(fp,n)\
do{\
int _n;\
_n=(n);\
while(_n-- > 0)\
fputc(' ',(fp));\
}while(0)
/* Second pass (same as above loop), this time we print. */
/* Sloppy hack: We iterate twice. The first time we print short and long options.
The second time we print those lines that have ONLY long options. */
while (print_run++ < 2) {
for (ue = byr_val; ue; ue = ue->next) {
usg_elem *ap;
int nwords = 0, nchars = 0, has_short = 0;
/* TODO: get has_short schtick to work */
has_short = !(FLAGS (s, ue->idx) & IS_LONG);
for (ap = ue->alias; ap; ap = ap->next) {
if (!(FLAGS (s, ap->idx) & IS_LONG)) {
has_short = 1;
break;
}
}
if ((print_run == 1 && !has_short) ||
(print_run == 2 && has_short))
continue;
PRINT_SPACES (fp, indent);
nchars += indent;
/* Print, adding a ", " between aliases. */
#define PRINT_IT(i) do{\
if(nwords++)\
nchars+=fprintf(fp,", ");\
nchars+=fprintf(fp,"%s",s->options[i].opt_fmt);\
}while(0)
if (!(FLAGS (s, ue->idx) & IS_LONG))
PRINT_IT (ue->idx);
/* print short aliases first. */
for (ap = ue->alias; ap; ap = ap->next) {
if (!(FLAGS (s, ap->idx) & IS_LONG))
PRINT_IT (ap->idx);
}
if (FLAGS (s, ue->idx) & IS_LONG)
PRINT_IT (ue->idx);
/* repeat the above loop, this time for long aliases. */
for (ap = ue->alias; ap; ap = ap->next) {
if (FLAGS (s, ap->idx) & IS_LONG)
PRINT_IT (ap->idx);
}
/* pad to desccol */
PRINT_SPACES (fp, desccol - nchars);
/* Print description, wrapped to maxlen[1] columns. */
if (1) {
const char *pstart;
pstart = DESC (s, ue->idx);
while (1) {
int n = 0;
const char *lastws = NULL, *p;
p = pstart;
while (*p && n < maxlen[1]
&& *p != '\n') {
if (isspace ((u_char)(*p))
|| *p == '-') lastws =
p;
n++;
p++;
}
if (!*p) { /* hit end of desc. done. */
fprintf (fp, "%s\n",
pstart);
break;
}
else if (*p == '\n') { /* print everything up to here then wrap. */
fprintf (fp, "%.*s\n", n,
pstart);
PRINT_SPACES (fp, desccol);
pstart = p + 1;
continue;
}
else { /* we hit the edge of the screen. wrap at space if possible. */
if (lastws) {
fprintf (fp,
"%.*s\n",
(int)(lastws - pstart),
pstart);
pstart =
lastws + 1;
}
else {
fprintf (fp,
"%.*s\n",
n,
pstart);
pstart = p + 1;
}
PRINT_SPACES (fp, desccol);
continue;
}
}
}
}
} /* end while */
free (store);
return 0;
}
#endif /* no scanopt_usage */
static int scanopt_err (s, opt_offset, is_short, err)
struct _scanopt_t *s;
int opt_offset;
int is_short;
int err;
{
const char *optname = "";
char optchar[2];
/* TODO(jart): wut */
/* const optspec_t *opt = NULL; */
/* if (opt_offset >= 0) */
/* opt = s->options + opt_offset; */
if (!s->no_err_msg) {
if (s->index > 0 && s->index < s->argc) {
if (is_short) {
optchar[0] =
s->argv[s->index][s->subscript];
optchar[1] = '\0';
optname = optchar;
}
else {
optname = s->argv[s->index];
}
}
fprintf (stderr, "%s: ", s->argv[0]);
switch (err) {
case SCANOPT_ERR_ARG_NOT_ALLOWED:
fprintf (stderr,
_
("option `%s' doesn't allow an argument\n"),
optname);
break;
case SCANOPT_ERR_ARG_NOT_FOUND:
fprintf (stderr,
_("option `%s' requires an argument\n"),
optname);
break;
case SCANOPT_ERR_OPT_AMBIGUOUS:
fprintf (stderr, _("option `%s' is ambiguous\n"),
optname);
break;
case SCANOPT_ERR_OPT_UNRECOGNIZED:
fprintf (stderr, _("Unrecognized option `%s'\n"),
optname);
break;
default:
fprintf (stderr, _("Unknown error=(%d)\n"), err);
break;
}
}
return err;
}
/* Internal. Match str against the regex ^--([^=]+)(=(.*))?
* return 1 if *looks* like a long option.
* 'str' is the only input argument, the rest of the arguments are output only.
* optname will point to str + 2
*
*/
static int matchlongopt (str, optname, optlen, arg, arglen)
char *str;
char **optname;
int *optlen;
char **arg;
int *arglen;
{
char *p;
*optname = *arg = (char *) 0;
*optlen = *arglen = 0;
/* Match regex /--./ */
p = str;
if (p[0] != '-' || p[1] != '-' || !p[2])
return 0;
p += 2;
*optname = (char *) p;
/* find the end of optname */
while (*p && *p != '=')
++p;
*optlen = p - *optname;
if (!*p)
/* an option with no '=...' part. */
return 1;
/* We saw an '=' char. The rest of p is the arg. */
p++;
*arg = p;
while (*p)
++p;
*arglen = p - *arg;
return 1;
}
/* Internal. Look up long or short option by name.
* Long options must match a non-ambiguous prefix, or exact match.
* Short options must be exact.
* Return boolean true if found and no error.
* Error stored in err_code or zero if no error. */
static int find_opt (s, lookup_long, optstart, len, err_code, opt_offset)
struct _scanopt_t *s;
int lookup_long;
char *optstart;
int len;
int *err_code;
int *opt_offset;
{
int nmatch = 0, lastr_val = 0, i;
*err_code = 0;
*opt_offset = -1;
if (!optstart)
return 0;
for (i = 0; i < s->optc; i++) {
char *optname;
optname =
(char *) (s->options[i].opt_fmt +
(lookup_long ? 2 : 1));
if (lookup_long && (s->aux[i].flags & IS_LONG)) {
if (len > s->aux[i].namelen)
continue;
if (strncmp (optname, optstart, len) == 0) {
nmatch++;
*opt_offset = i;
/* exact match overrides all. */
if (len == s->aux[i].namelen) {
nmatch = 1;
break;
}
/* ambiguity is ok between aliases. */
if (lastr_val
&& lastr_val ==
s->options[i].r_val) nmatch--;
lastr_val = s->options[i].r_val;
}
}
else if (!lookup_long && !(s->aux[i].flags & IS_LONG)) {
if (optname[0] == optstart[0]) {
nmatch++;
*opt_offset = i;
}
}
}
if (nmatch == 0) {
*err_code = SCANOPT_ERR_OPT_UNRECOGNIZED;
*opt_offset = -1;
}
else if (nmatch > 1) {
*err_code = SCANOPT_ERR_OPT_AMBIGUOUS;
*opt_offset = -1;
}
return *err_code ? 0 : 1;
}
int scanopt (svoid, arg, optindex)
scanopt_t *svoid;
char **arg;
int *optindex;
{
char *optname = NULL, *optarg = NULL, *pstart;
int namelen = 0, arglen = 0;
int errcode = 0, has_next;
const optspec_t *optp;
struct _scanopt_t *s;
struct _aux *auxp;
int is_short = 0;
int opt_offset = -1;
s = (struct _scanopt_t *) svoid;
/* Normalize return-parameters. */
SAFE_ASSIGN (arg, NULL);
SAFE_ASSIGN (optindex, s->index);
if (s->index >= s->argc)
return 0;
/* pstart always points to the start of our current scan. */
pstart = s->argv[s->index] + s->subscript;
if (!pstart)
return 0;
if (s->subscript == 0) {
/* test for exact match of "--" */
if (pstart[0] == '-' && pstart[1] == '-' && !pstart[2]) {
SAFE_ASSIGN (optindex, s->index + 1);
INC_INDEX (s, 1);
return 0;
}
/* Match an opt. */
if (matchlongopt
(pstart, &optname, &namelen, &optarg, &arglen)) {
/* it LOOKS like an opt, but is it one?! */
if (!find_opt
(s, 1, optname, namelen, &errcode,
&opt_offset)) {
scanopt_err (s, opt_offset, 0, errcode);
return errcode;
}
/* We handle this below. */
is_short = 0;
/* Check for short opt. */
}
else if (pstart[0] == '-' && pstart[1]) {
/* Pass through to below. */
is_short = 1;
s->subscript++;
pstart++;
}
else {
/* It's not an option. We're done. */
return 0;
}
}
/* We have to re-check the subscript status because it
* may have changed above. */
if (s->subscript != 0) {
/* we are somewhere in a run of short opts,
* e.g., at the 'z' in `tar -xzf` */
optname = pstart;
namelen = 1;
is_short = 1;
if (!find_opt
(s, 0, pstart, namelen, &errcode, &opt_offset)) {
return scanopt_err (s, opt_offset, 1, errcode);
}
optarg = pstart + 1;
if (!*optarg) {
optarg = NULL;
arglen = 0;
}
else
arglen = strlen (optarg);
}
/* At this point, we have a long or short option matched at opt_offset into
* the s->options array (and corresponding aux array).
* A trailing argument is in {optarg,arglen}, if any.
*/
/* Look ahead in argv[] to see if there is something
* that we can use as an argument (if needed). */
has_next = s->index + 1 < s->argc
&& strcmp ("--", s->argv[s->index + 1]) != 0;
optp = s->options + opt_offset;
auxp = s->aux + opt_offset;
/* case: no args allowed */
if (auxp->flags & ARG_NONE) {
if (optarg && !is_short) {
scanopt_err (s, opt_offset, is_short, errcode =
SCANOPT_ERR_ARG_NOT_ALLOWED);
INC_INDEX (s, 1);
return errcode;
}
else if (!optarg)
INC_INDEX (s, 1);
else
s->subscript++;
return optp->r_val;
}
/* case: required */
if (auxp->flags & ARG_REQ) {
if (!optarg && !has_next)
return scanopt_err (s, opt_offset, is_short,
SCANOPT_ERR_ARG_NOT_FOUND);
if (!optarg) {
/* Let the next argv element become the argument. */
SAFE_ASSIGN (arg, s->argv[s->index + 1]);
INC_INDEX (s, 2);
}
else {
SAFE_ASSIGN (arg, (char *) optarg);
INC_INDEX (s, 1);
}
return optp->r_val;
}
/* case: optional */
if (auxp->flags & ARG_OPT) {
SAFE_ASSIGN (arg, optarg);
INC_INDEX (s, 1);
return optp->r_val;
}
/* Should not reach here. */
return 0;
}
void scanopt_destroy (svoid)
scanopt_t *svoid;
{
struct _scanopt_t *s;
s = (struct _scanopt_t *) svoid;
if (s) {
free(s->aux);
free (s);
}
}

View file

@ -1,133 +0,0 @@
/* clang-format off */
/* $OpenBSD: scanopt.h,v 1.3 2017/05/31 07:20:26 tedu Exp $ */
/* flex - tool to generate fast lexical analyzers */
/* Copyright (c) 1990 The Regents of the University of California. */
/* All rights reserved. */
/* This code is derived from software contributed to Berkeley by */
/* Vern Paxson. */
/* The United States Government has rights in this work pursuant */
/* to contract no. DE-AC03-76SF00098 between the United States */
/* Department of Energy and the University of California. */
/* This file is part of flex. */
/* 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. */
/* 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR */
/* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED */
/* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR */
/* PURPOSE. */
#ifndef SCANOPT_H
#define SCANOPT_H
#include "flexdef.h"
#ifndef NO_SCANOPT_USAGE
/* Used by scanopt_usage for pretty-printing. */
#ifdef HAVE_NCURSES_H
#include <ncurses.h>
#endif
#endif
#ifdef __cplusplus
extern "C" {
#endif
#ifndef PROTO
#define PROTO(args) args
#endif
/* Error codes. */ enum scanopt_err_t {
SCANOPT_ERR_OPT_UNRECOGNIZED = -1, /* Unrecognized option. */
SCANOPT_ERR_OPT_AMBIGUOUS = -2, /* It matched more than one option name. */
SCANOPT_ERR_ARG_NOT_FOUND = -3, /* The required arg was not found. */
SCANOPT_ERR_ARG_NOT_ALLOWED = -4 /* Option does not take an argument. */
};
/* flags passed to scanopt_init */
enum scanopt_flag_t {
SCANOPT_NO_ERR_MSG = 0x01 /* Suppress printing to stderr. */
};
/* Specification for a single option. */
struct optspec_t {
const char *opt_fmt; /* e.g., "--foo=FILE", "-f FILE", "-n [NUM]" */
int r_val; /* Value to be returned by scanopt_ex(). */
const char *desc; /* Brief description of this option, or NULL. */
};
typedef struct optspec_t optspec_t;
/* Used internally by scanopt() to maintain state. */
/* Never modify these value directly. */
typedef void *scanopt_t;
/* Initializes scanner and checks option list for errors.
* Parameters:
* options - Array of options.
* argc - Same as passed to main().
* argv - Same as passed to main(). First element is skipped.
* flags - Control behavior.
* Return: A malloc'd pointer .
*/
scanopt_t *scanopt_init PROTO ((const optspec_t * options,
int argc, char **argv, int flags));
/* Frees memory used by scanner. */
void scanopt_destroy PROTO ((scanopt_t * scanner));
#ifndef NO_SCANOPT_USAGE
/* Prints a usage message based on contents of optlist.
* Parameters:
* scanner - The scanner, already initialized with scanopt_init().
* fp - The file stream to write to.
* usage - Text to be prepended to option list. May be NULL.
* Return: Always returns 0 (zero).
*/
int scanopt_usage
PROTO (
(scanopt_t * scanner, FILE * fp,
const char *usage));
#endif
/* Scans command-line options in argv[].
* Parameters:
* scanner - The scanner, already initialized with scanopt_init().
* optarg - Return argument, may be NULL.
* On success, it points to start of an argument.
* optindex - Return argument, may be NULL.
* On success or failure, it is the index of this option.
* If return is zero, then optindex is the NEXT valid option index.
*
* Return: > 0 on success. Return value is from optspec_t->rval.
* == 0 if at end of options.
* < 0 on error (return value is an error code).
*
*/
int scanopt
PROTO (
(scanopt_t * scanner, char **optarg,
int *optindex));
#ifdef __cplusplus
}
#endif
#endif

3740
third_party/lex/skel.c vendored

File diff suppressed because it is too large Load diff

280
third_party/lex/sym.c vendored
View file

@ -1,280 +0,0 @@
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
vi: set et ft=c ts=8 sw=8 fenc=utf-8 :vi
*/
/* clang-format off */
/* $OpenBSD: sym.c,v 1.9 2015/11/19 23:34:56 mmcc Exp $ */
/* sym - symbol table routines */
/* Copyright (c) 1990 The Regents of the University of California. */
/* All rights reserved. */
/* This code is derived from software contributed to Berkeley by */
/* Vern Paxson. */
/* The United States Government has rights in this work pursuant */
/* to contract no. DE-AC03-76SF00098 between the United States */
/* Department of Energy and the University of California. */
/* This file is part of flex. */
/* 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. */
/* 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR */
/* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED */
/* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR */
/* PURPOSE. */
#include "libc/str/str.h"
#include "libc/mem/mem.h"
#include "flexdef.h"
/* Variables for symbol tables:
* sctbl - start-condition symbol table
* ndtbl - name-definition symbol table
* ccltab - character class text symbol table
*/
struct hash_entry {
struct hash_entry *prev, *next;
char *name;
char *str_val;
int int_val;
};
typedef struct hash_entry **hash_table;
#define NAME_TABLE_HASH_SIZE 101
#define START_COND_HASH_SIZE 101
#define CCL_HASH_SIZE 101
static struct hash_entry *ndtbl[NAME_TABLE_HASH_SIZE];
static struct hash_entry *sctbl[START_COND_HASH_SIZE];
static struct hash_entry *ccltab[CCL_HASH_SIZE];
/* declare functions that have forward references */
static int addsym PROTO ((char[], char *, int, hash_table, int));
static struct hash_entry *findsym PROTO ((const char *sym,
hash_table table,
int table_size));
static int hashfunct PROTO ((const char *, int));
/* addsym - add symbol and definitions to symbol table
*
* -1 is returned if the symbol already exists, and the change not made.
*/
static int addsym (sym, str_def, int_def, table, table_size)
char sym[];
char *str_def;
int int_def;
hash_table table;
int table_size;
{
int hash_val = hashfunct (sym, table_size);
struct hash_entry *sym_entry = table[hash_val];
struct hash_entry *new_entry;
struct hash_entry *successor;
while (sym_entry) {
if (!strcmp (sym, sym_entry->name)) { /* entry already exists */
return -1;
}
sym_entry = sym_entry->next;
}
/* create new entry */
new_entry = (struct hash_entry *)
malloc (sizeof (struct hash_entry));
if (new_entry == NULL)
flexfatal (_("symbol table memory allocation failed"));
if ((successor = table[hash_val]) != 0) {
new_entry->next = successor;
successor->prev = new_entry;
}
else
new_entry->next = NULL;
new_entry->prev = NULL;
new_entry->name = sym;
new_entry->str_val = str_def;
new_entry->int_val = int_def;
table[hash_val] = new_entry;
return 0;
}
/* cclinstal - save the text of a character class */
void cclinstal (ccltxt, cclnum)
u_char ccltxt[];
int cclnum;
{
/* We don't bother checking the return status because we are not
* called unless the symbol is new.
*/
(void) addsym ((char *) copy_unsigned_string (ccltxt),
(char *) 0, cclnum, ccltab, CCL_HASH_SIZE);
}
/* ccllookup - lookup the number associated with character class text
*
* Returns 0 if there's no CCL associated with the text.
*/
int ccllookup (ccltxt)
u_char ccltxt[];
{
return findsym ((char *) ccltxt, ccltab, CCL_HASH_SIZE)->int_val;
}
/* findsym - find symbol in symbol table */
static struct hash_entry *findsym (sym, table, table_size)
const char *sym;
hash_table table;
int table_size;
{
static struct hash_entry empty_entry = {
(struct hash_entry *) 0, (struct hash_entry *) 0,
(char *) 0, (char *) 0, 0,
};
struct hash_entry *sym_entry =
table[hashfunct (sym, table_size)];
while (sym_entry) {
if (!strcmp (sym, sym_entry->name))
return sym_entry;
sym_entry = sym_entry->next;
}
return &empty_entry;
}
/* hashfunct - compute the hash value for "str" and hash size "hash_size" */
static int hashfunct (str, hash_size)
const char *str;
int hash_size;
{
int hashval;
int locstr;
hashval = 0;
locstr = 0;
while (str[locstr]) {
hashval = (hashval << 1) + (unsigned char) str[locstr++];
hashval %= hash_size;
}
return hashval;
}
/* ndinstal - install a name definition */
void ndinstal (name, definition)
const char *name;
u_char definition[];
{
if (addsym (copy_string (name),
(char *) copy_unsigned_string (definition), 0,
ndtbl, NAME_TABLE_HASH_SIZE))
synerr (_("name defined twice"));
}
/* ndlookup - lookup a name definition
*
* Returns a nil pointer if the name definition does not exist.
*/
u_char *ndlookup (nd)
const char *nd;
{
return (u_char *) findsym (nd, ndtbl, NAME_TABLE_HASH_SIZE)->str_val;
}
/* scextend - increase the maximum number of start conditions */
void scextend ()
{
current_max_scs += MAX_SCS_INCREMENT;
++num_reallocs;
scset = reallocate_integer_array (scset, current_max_scs);
scbol = reallocate_integer_array (scbol, current_max_scs);
scxclu = reallocate_integer_array (scxclu, current_max_scs);
sceof = reallocate_integer_array (sceof, current_max_scs);
scname = reallocate_char_ptr_array (scname, current_max_scs);
}
/* scinstal - make a start condition
*
* NOTE
* The start condition is "exclusive" if xcluflg is true.
*/
void scinstal (str, xcluflg)
const char *str;
int xcluflg;
{
if (++lastsc >= current_max_scs)
scextend ();
scname[lastsc] = copy_string (str);
if (addsym (scname[lastsc], (char *) 0, lastsc,
sctbl, START_COND_HASH_SIZE))
format_pinpoint_message (_
("start condition %s declared twice"),
str);
scset[lastsc] = mkstate (SYM_EPSILON);
scbol[lastsc] = mkstate (SYM_EPSILON);
scxclu[lastsc] = xcluflg;
sceof[lastsc] = false;
}
/* sclookup - lookup the number associated with a start condition
*
* Returns 0 if no such start condition.
*/
int sclookup (str)
const char *str;
{
return findsym (str, sctbl, START_COND_HASH_SIZE)->int_val;
}

View file

@ -1,466 +0,0 @@
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
vi: set et ft=c ts=8 sw=8 fenc=utf-8 :vi
*/
#include "libc/fmt/conv.h"
#include "libc/mem/mem.h"
#include "libc/sock/sock.h"
#include "libc/str/str.h"
/* clang-format off */
/* $OpenBSD: tables.c,v 1.4 2017/08/17 19:27:09 tedu Exp $ */
/* tables.c - tables serialization code
*
* Copyright (c) 1990 The Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Vern Paxson.
*
* The United States Government has rights in this work pursuant
* to contract no. DE-AC03-76SF00098 between the United States
* Department of Energy and the University of California.
*
* This file is part of flex.
*
* 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.
*
* 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE.
*/
#include "flexdef.h"
#include "tables.h"
/** Convert size_t to t_flag.
* @param n in {1,2,4}
* @return YYTD_DATA*.
*/
#define BYTES2TFLAG(n)\
(((n) == sizeof(flex_int8_t))\
? YYTD_DATA8\
:(((n)== sizeof(flex_int16_t))\
? YYTD_DATA16\
: YYTD_DATA32))
/** Clear YYTD_DATA* bit flags
* @return the flag with the YYTD_DATA* bits cleared
*/
#define TFLAGS_CLRDATA(flg) ((flg) & ~(YYTD_DATA8 | YYTD_DATA16 | YYTD_DATA32))
int yytbl_write32 (struct yytbl_writer *wr, flex_uint32_t v);
int yytbl_write16 (struct yytbl_writer *wr, flex_uint16_t v);
int yytbl_write8 (struct yytbl_writer *wr, flex_uint8_t v);
int yytbl_writen (struct yytbl_writer *wr, void *v, flex_int32_t len);
static flex_int32_t yytbl_data_geti (const struct yytbl_data *tbl, int i);
/** Initialize the table writer.
* @param wr an uninitialized writer
* @param the output file
* @return 0 on success
*/
int yytbl_writer_init (struct yytbl_writer *wr, FILE * out)
{
wr->out = out;
wr->total_written = 0;
return 0;
}
/** Initialize a table header.
* @param th The uninitialized structure
* @param version_str the version string
* @param name the name of this table set
*/
int yytbl_hdr_init (struct yytbl_hdr *th, const char *version_str,
const char *name)
{
memset (th, 0, sizeof (struct yytbl_hdr));
th->th_magic = YYTBL_MAGIC;
th->th_hsize = 14 + strlen (version_str) + 1 + strlen (name) + 1;
th->th_hsize += yypad64 (th->th_hsize);
th->th_ssize = 0; // Not known at this point.
th->th_flags = 0;
th->th_version = copy_string (version_str);
th->th_name = copy_string (name);
return 0;
}
/** Allocate and initialize a table data structure.
* @param tbl a pointer to an uninitialized table
* @param id the table identifier
* @return 0 on success
*/
int yytbl_data_init (struct yytbl_data *td, enum yytbl_id id)
{
memset (td, 0, sizeof (struct yytbl_data));
td->td_id = id;
td->td_flags = YYTD_DATA32;
return 0;
}
/** Clean up table and data array.
* @param td will be destroyed
* @return 0 on success
*/
int yytbl_data_destroy (struct yytbl_data *td)
{
free(td->td_data);
td->td_data = 0;
free (td);
return 0;
}
/** Write enough padding to bring the file pointer to a 64-bit boundary. */
static int yytbl_write_pad64 (struct yytbl_writer *wr)
{
int pad, bwritten = 0;
pad = yypad64 (wr->total_written);
while (pad-- > 0)
if (yytbl_write8 (wr, 0) < 0)
return -1;
else
bwritten++;
return bwritten;
}
/** write the header.
* @param out the output stream
* @param th table header to be written
* @return -1 on error, or bytes written on success.
*/
int yytbl_hdr_fwrite (struct yytbl_writer *wr, const struct yytbl_hdr *th)
{
int sz, rv;
int bwritten = 0;
if (yytbl_write32 (wr, th->th_magic) < 0
|| yytbl_write32 (wr, th->th_hsize) < 0)
flex_die (_("th_magic|th_hsize write32 failed"));
bwritten += 8;
if (fgetpos (wr->out, &(wr->th_ssize_pos)) != 0)
flex_die (_("fgetpos failed"));
if (yytbl_write32 (wr, th->th_ssize) < 0
|| yytbl_write16 (wr, th->th_flags) < 0)
flex_die (_("th_ssize|th_flags write failed"));
bwritten += 6;
sz = strlen (th->th_version) + 1;
if ((rv = yytbl_writen (wr, th->th_version, sz)) != sz)
flex_die (_("th_version writen failed"));
bwritten += rv;
sz = strlen (th->th_name) + 1;
if ((rv = yytbl_writen (wr, th->th_name, sz)) != sz)
flex_die (_("th_name writen failed"));
bwritten += rv;
/* add padding */
if ((rv = yytbl_write_pad64 (wr)) < 0)
flex_die (_("pad64 failed"));
bwritten += rv;
/* Sanity check */
if (bwritten != (int) th->th_hsize)
flex_die (_("pad64 failed"));
return bwritten;
}
/** Write this table.
* @param out the file writer
* @param td table data to be written
* @return -1 on error, or bytes written on success.
*/
int yytbl_data_fwrite (struct yytbl_writer *wr, struct yytbl_data *td)
{
int rv;
flex_int32_t bwritten = 0;
flex_int32_t i, total_len;
fpos_t pos;
if ((rv = yytbl_write16 (wr, td->td_id)) < 0)
return -1;
bwritten += rv;
if ((rv = yytbl_write16 (wr, td->td_flags)) < 0)
return -1;
bwritten += rv;
if ((rv = yytbl_write32 (wr, td->td_hilen)) < 0)
return -1;
bwritten += rv;
if ((rv = yytbl_write32 (wr, td->td_lolen)) < 0)
return -1;
bwritten += rv;
total_len = yytbl_calc_total_len (td);
for (i = 0; i < total_len; i++) {
switch (YYTDFLAGS2BYTES (td->td_flags)) {
case sizeof (flex_int8_t):
rv = yytbl_write8 (wr, yytbl_data_geti (td, i));
break;
case sizeof (flex_int16_t):
rv = yytbl_write16 (wr, yytbl_data_geti (td, i));
break;
case sizeof (flex_int32_t):
rv = yytbl_write32 (wr, yytbl_data_geti (td, i));
break;
default:
flex_die (_("invalid td_flags detected"));
}
if (rv < 0) {
flex_die (_("error while writing tables"));
return -1;
}
bwritten += rv;
}
/* Sanity check */
if (bwritten != (int) (12 + total_len * YYTDFLAGS2BYTES (td->td_flags))) {
flex_die (_("insanity detected"));
return -1;
}
/* add padding */
if ((rv = yytbl_write_pad64 (wr)) < 0) {
flex_die (_("pad64 failed"));
return -1;
}
bwritten += rv;
/* Now go back and update the th_hsize member */
if (fgetpos (wr->out, &pos) != 0
|| fsetpos (wr->out, &(wr->th_ssize_pos)) != 0
|| yytbl_write32 (wr, wr->total_written) < 0
|| fsetpos (wr->out, &pos)) {
flex_die (_("get|set|fwrite32 failed"));
return -1;
}
else
/* Don't count the int we just wrote. */
wr->total_written -= sizeof (flex_int32_t);
return bwritten;
}
/** Write n bytes.
* @param wr the table writer
* @param v data to be written
* @param len number of bytes
* @return -1 on error. number of bytes written on success.
*/
int yytbl_writen (struct yytbl_writer *wr, void *v, flex_int32_t len)
{
int rv;
rv = fwrite (v, 1, len, wr->out);
if (rv != len)
return -1;
wr->total_written += len;
return len;
}
/** Write four bytes in network byte order
* @param wr the table writer
* @param v a dword in host byte order
* @return -1 on error. number of bytes written on success.
*/
int yytbl_write32 (struct yytbl_writer *wr, flex_uint32_t v)
{
flex_uint32_t vnet;
size_t bytes, rv;
vnet = htonl (v);
bytes = sizeof (flex_uint32_t);
rv = fwrite (&vnet, bytes, 1, wr->out);
if (rv != 1)
return -1;
wr->total_written += bytes;
return bytes;
}
/** Write two bytes in network byte order.
* @param wr the table writer
* @param v a word in host byte order
* @return -1 on error. number of bytes written on success.
*/
int yytbl_write16 (struct yytbl_writer *wr, flex_uint16_t v)
{
flex_uint16_t vnet;
size_t bytes, rv;
vnet = htons (v);
bytes = sizeof (flex_uint16_t);
rv = fwrite (&vnet, bytes, 1, wr->out);
if (rv != 1)
return -1;
wr->total_written += bytes;
return bytes;
}
/** Write a byte.
* @param wr the table writer
* @param v the value to be written
* @return -1 on error. number of bytes written on success.
*/
int yytbl_write8 (struct yytbl_writer *wr, flex_uint8_t v)
{
size_t bytes, rv;
bytes = sizeof (flex_uint8_t);
rv = fwrite (&v, bytes, 1, wr->out);
if (rv != 1)
return -1;
wr->total_written += bytes;
return bytes;
}
/** Extract data element [i] from array data tables treated as a single flat array of integers.
* Be careful for 2-dimensional arrays or for YYTD_ID_TRANSITION, which is an array
* of structs.
* @param tbl data table
* @param i index into array.
* @return data[i]
*/
static flex_int32_t yytbl_data_geti (const struct yytbl_data *tbl, int i)
{
switch (YYTDFLAGS2BYTES (tbl->td_flags)) {
case sizeof (flex_int8_t):
return ((flex_int8_t *) (tbl->td_data))[i];
case sizeof (flex_int16_t):
return ((flex_int16_t *) (tbl->td_data))[i];
case sizeof (flex_int32_t):
return ((flex_int32_t *) (tbl->td_data))[i];
default:
flex_die (_("invalid td_flags detected"));
break;
}
return 0;
}
/** Set data element [i] in array data tables treated as a single flat array of integers.
* Be careful for 2-dimensional arrays or for YYTD_ID_TRANSITION, which is an array
* of structs.
* @param tbl data table
* @param i index into array.
* @param newval new value for data[i]
*/
static void yytbl_data_seti (const struct yytbl_data *tbl, int i,
flex_int32_t newval)
{
switch (YYTDFLAGS2BYTES (tbl->td_flags)) {
case sizeof (flex_int8_t):
((flex_int8_t *) (tbl->td_data))[i] = (flex_int8_t) newval;
break;
case sizeof (flex_int16_t):
((flex_int16_t *) (tbl->td_data))[i] = (flex_int16_t) newval;
break;
case sizeof (flex_int32_t):
((flex_int32_t *) (tbl->td_data))[i] = (flex_int32_t) newval;
break;
default:
flex_die (_("invalid td_flags detected"));
break;
}
}
/** Calculate the number of bytes needed to hold the largest
* absolute value in this data array.
* @param tbl the data table
* @return sizeof(n) where n in {flex_int8_t, flex_int16_t, flex_int32_t}
*/
static size_t min_int_size (struct yytbl_data *tbl)
{
flex_uint32_t i, total_len;
flex_int32_t max = 0;
total_len = yytbl_calc_total_len (tbl);
for (i = 0; i < total_len; i++) {
flex_int32_t n;
n = abs (yytbl_data_geti (tbl, i));
if (n > max)
max = n;
}
if (max <= INT8_MAX)
return sizeof (flex_int8_t);
else if (max <= INT16_MAX)
return sizeof (flex_int16_t);
else
return sizeof (flex_int32_t);
}
/** Transform data to smallest possible of (int32, int16, int8).
* For example, we may have generated an int32 array due to user options
* (e.g., %option align), but if the maximum value in that array
* is 80 (for example), then we can serialize it with only 1 byte per int.
* This is NOT the same as compressed DFA tables. We're just trying
* to save storage space here.
*
* @param tbl the table to be compressed
*/
void yytbl_data_compress (struct yytbl_data *tbl)
{
flex_int32_t i, newsz, total_len;
struct yytbl_data newtbl;
yytbl_data_init (&newtbl, tbl->td_id);
newtbl.td_hilen = tbl->td_hilen;
newtbl.td_lolen = tbl->td_lolen;
newtbl.td_flags = tbl->td_flags;
newsz = min_int_size (tbl);
if (newsz == (int) YYTDFLAGS2BYTES (tbl->td_flags))
/* No change in this table needed. */
return;
if (newsz > (int) YYTDFLAGS2BYTES (tbl->td_flags)) {
flex_die (_("detected negative compression"));
return;
}
total_len = yytbl_calc_total_len (tbl);
newtbl.td_data = calloc (total_len, newsz);
newtbl.td_flags =
TFLAGS_CLRDATA (newtbl.td_flags) | BYTES2TFLAG (newsz);
for (i = 0; i < total_len; i++) {
flex_int32_t g;
g = yytbl_data_geti (tbl, i);
yytbl_data_seti (&newtbl, i, g);
}
/* Now copy over the old table */
free (tbl->td_data);
*tbl = newtbl;
}

View file

@ -1,86 +0,0 @@
/* clang-format off */
/* $OpenBSD: tables.h,v 1.2 2015/11/19 22:16:43 tedu Exp $ */
/* tables.h - tables serialization code
*
* Copyright (c) 1990 The Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Vern Paxson.
*
* The United States Government has rights in this work pursuant
* to contract no. DE-AC03-76SF00098 between the United States
* Department of Energy and the University of California.
*
* This file is part of flex.
*
* 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.
*
* 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE.
*/
#ifndef TABLES_H
#define TABLES_H
#ifdef __cplusplus
/* *INDENT-OFF* */
extern "C" {
/* *INDENT-ON* */
#endif
/* Tables serialization API declarations. */
#include "tables_shared.h"
struct yytbl_writer {
FILE *out;
flex_uint32_t total_written;
/**< bytes written so far */
fpos_t th_ssize_pos;
/**< position of th_ssize */
};
/* These are used by main.c, gen.c, etc.
* tablesext - if true, create external tables
* tablesfilename - filename for external tables
* tablesname - name that goes in serialized data, e.g., "yytables"
* tableswr - writer for external tables
* tablesverify - true if tables-verify option specified
* gentables - true if we should spit out the normal C tables
*/
extern bool tablesext, tablesverify,gentables;
extern char *tablesfilename, *tablesname;
extern struct yytbl_writer tableswr;
int yytbl_writer_init (struct yytbl_writer *, FILE *);
int yytbl_hdr_init (struct yytbl_hdr *th, const char *version_str,
const char *name);
int yytbl_data_init (struct yytbl_data *tbl, enum yytbl_id id);
int yytbl_data_destroy (struct yytbl_data *td);
int yytbl_hdr_fwrite (struct yytbl_writer *wr,
const struct yytbl_hdr *th);
int yytbl_data_fwrite (struct yytbl_writer *wr, struct yytbl_data *td);
void yytbl_data_compress (struct yytbl_data *tbl);
struct yytbl_data *mkftbl (void);
#ifdef __cplusplus
/* *INDENT-OFF* */
}
/* *INDENT-ON* */
#endif
#endif

View file

@ -1,76 +0,0 @@
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
vi: set et ft=c ts=8 sw=8 fenc=utf-8 :vi
*/
/* clang-format off */
/* $OpenBSD: tables_shared.c,v 1.1 2015/11/19 19:43:40 tedu Exp $ */
#ifdef FLEX_SCANNER
/*
dnl tables_shared.c - tables serialization code
dnl
dnl Copyright (c) 1990 The Regents of the University of California.
dnl All rights reserved.
dnl
dnl This code is derived from software contributed to Berkeley by
dnl Vern Paxson.
dnl
dnl The United States Government has rights in this work pursuant
dnl to contract no. DE-AC03-76SF00098 between the United States
dnl Department of Energy and the University of California.
dnl
dnl This file is part of flex.
dnl
dnl Redistribution and use in source and binary forms, with or without
dnl modification, are permitted provided that the following conditions
dnl are met:
dnl
dnl 1. Redistributions of source code must retain the above copyright
dnl notice, this list of conditions and the following disclaimer.
dnl 2. Redistributions in binary form must reproduce the above copyright
dnl notice, this list of conditions and the following disclaimer in the
dnl documentation and/or other materials provided with the distribution.
dnl
dnl Neither the name of the University nor the names of its contributors
dnl may be used to endorse or promote products derived from this software
dnl without specific prior written permission.
dnl
dnl THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
dnl IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
dnl WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
dnl PURPOSE.
dnl
*/
/* This file is meant to be included in both the skeleton and the actual
* flex code (hence the name "_shared").
*/
#ifndef yyskel_static
#define yyskel_static static
#endif
#else
#include "flexdef.h"
#include "tables.h"
#ifndef yyskel_static
#define yyskel_static
#endif
#endif
/** Get the number of integers in this table. This is NOT the
* same thing as the number of elements.
* @param td the table
* @return the number of integers in the table
*/
yyskel_static flex_int32_t yytbl_calc_total_len (const struct yytbl_data *tbl)
{
flex_int32_t n;
/* total number of ints */
n = tbl->td_lolen;
if (tbl->td_hilen > 0)
n *= tbl->td_hilen;
if (tbl->td_id == YYTD_ID_TRANSITION)
n *= 2;
return n;
}

View file

@ -1,145 +0,0 @@
/* clang-format off */
/* $OpenBSD: tables_shared.h,v 1.2 2015/11/19 22:16:43 tedu Exp $ */
#ifdef FLEX_SCANNER
/*
dnl tables_shared.h - tables serialization header
dnl
dnl Copyright (c) 1990 The Regents of the University of California.
dnl All rights reserved.
dnl
dnl This code is derived from software contributed to Berkeley by
dnl Vern Paxson.
dnl
dnl The United States Government has rights in this work pursuant
dnl to contract no. DE-AC03-76SF00098 between the United States
dnl Department of Energy and the University of California.
dnl
dnl This file is part of flex.
dnl
dnl Redistribution and use in source and binary forms, with or without
dnl modification, are permitted provided that the following conditions
dnl are met:
dnl
dnl 1. Redistributions of source code must retain the above copyright
dnl notice, this list of conditions and the following disclaimer.
dnl 2. Redistributions in binary form must reproduce the above copyright
dnl notice, this list of conditions and the following disclaimer in the
dnl documentation and/or other materials provided with the distribution.
dnl
dnl Neither the name of the University nor the names of its contributors
dnl may be used to endorse or promote products derived from this software
dnl without specific prior written permission.
dnl
dnl THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
dnl IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
dnl WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
dnl PURPOSE.
dnl
dnl This file is meant to be included in both the skeleton and the actual
dnl flex code (hence the name "_shared").
*/
#ifndef yyskel_static
#define yyskel_static static
#endif
#else
#ifndef yyskel_static
#define yyskel_static
#endif
#endif
/* Structures and prototypes for serializing flex tables. The
* binary format is documented in the manual.
*
* Design considerations:
*
* - The format allows many tables per file.
* - The tables can be streamed.
* - All data is stored in network byte order.
* - We do not hinder future unicode support.
* - We can lookup tables by name.
*/
/** Magic number for serialized format. */
#ifndef YYTBL_MAGIC
#define YYTBL_MAGIC 0xF13C57B1
#endif
/** Calculate (0-7) = number bytes needed to pad n to next 64-bit boundary. */
#ifndef yypad64
#define yypad64(n) ((8-((n)%8))%8)
#endif
#ifndef YYTABLES_TYPES
#define YYTABLES_TYPES
/** Possible values for td_id field. Each one corresponds to a
* scanner table of the same name.
*/
enum yytbl_id {
YYTD_ID_ACCEPT = 0x01, /**< 1-dim ints */
YYTD_ID_BASE = 0x02, /**< 1-dim ints */
YYTD_ID_CHK = 0x03, /**< 1-dim ints */
YYTD_ID_DEF = 0x04, /**< 1-dim ints */
YYTD_ID_EC = 0x05, /**< 1-dim ints */
YYTD_ID_META = 0x06, /**< 1-dim ints */
YYTD_ID_NUL_TRANS = 0x07, /**< 1-dim ints, maybe indices */
YYTD_ID_NXT = 0x08, /**< may be 2 dimensional ints */
YYTD_ID_RULE_CAN_MATCH_EOL = 0x09, /**< 1-dim ints */
YYTD_ID_START_STATE_LIST = 0x0A, /**< 1-dim indices into trans tbl */
YYTD_ID_TRANSITION = 0x0B, /**< structs */
YYTD_ID_ACCLIST = 0x0C /**< 1-dim ints */
};
/** bit flags for t_flags field of struct yytbl_data */
enum yytbl_flags {
/* These first three are mutually exclusive */
YYTD_DATA8 = 0x01, /**< data is an array of type flex_int8_t */
YYTD_DATA16 = 0x02, /**< data is an array of type flex_int16_t */
YYTD_DATA32 = 0x04, /**< data is an array of type flex_int32_t */
/* These two are mutually exclusive. */
YYTD_PTRANS = 0x08, /**< data is a list of indexes of entries
into the expanded `yy_transition'
array. See notes in manual. */
YYTD_STRUCT = 0x10 /**< data consists of yy_trans_info structs */
};
/* The serialized tables header. */
struct yytbl_hdr {
flex_uint32_t th_magic; /**< Must be 0xF13C57B1 (comes from "Flex Table") */
flex_uint32_t th_hsize; /**< Size of this header in bytes. */
flex_uint32_t th_ssize; /**< Size of this dataset, in bytes, including header. */
flex_uint16_t th_flags; /**< Currently unused, must be 0 */
char *th_version; /**< Flex version string. NUL terminated. */
char *th_name; /**< The name of this table set. NUL terminated. */
};
/** A single serialized table */
struct yytbl_data {
flex_uint16_t td_id; /**< enum yytbl_id table identifier */
flex_uint16_t td_flags; /**< how to interpret this data */
flex_uint32_t td_hilen; /**< num elements in highest dimension array */
flex_uint32_t td_lolen; /**< num elements in lowest dimension array */
void *td_data; /**< table data */
};
#endif
/** Extract corresponding data size_t from td_flags */
#ifndef YYTDFLAGS2BYTES
#define YYTDFLAGS2BYTES(td_flags)\
(((td_flags) & YYTD_DATA8)\
? sizeof(flex_int8_t)\
:(((td_flags) & YYTD_DATA16)\
? sizeof(flex_int16_t)\
:sizeof(flex_int32_t)))
#endif
#ifdef FLEX_SCANNER
%not-for-header
#endif
yyskel_static flex_int32_t yytbl_calc_total_len (const struct yytbl_data *tbl);
#ifdef FLEX_SCANNER
%ok-for-header
#endif

View file

@ -1,885 +0,0 @@
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
vi: set et ft=c ts=8 sw=8 fenc=utf-8 :vi
*/
/* clang-format off */
/* $OpenBSD: tblcmp.c,v 1.10 2015/11/19 23:34:56 mmcc Exp $ */
/* tblcmp - table compression routines */
/* Copyright (c) 1990 The Regents of the University of California. */
/* All rights reserved. */
/* This code is derived from software contributed to Berkeley by */
/* Vern Paxson. */
/* The United States Government has rights in this work pursuant */
/* to contract no. DE-AC03-76SF00098 between the United States */
/* Department of Energy and the University of California. */
/* This file is part of flex. */
/* 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. */
/* 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR */
/* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED */
/* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR */
/* PURPOSE. */
#include "libc/str/str.h"
#include "third_party/lex/flexdef.h"
/* declarations for functions that have forward references */
void mkentry PROTO((int *, int, int, int, int));
void mkprot PROTO((int[], int, int));
void mktemplate PROTO((int[], int, int));
void mv2front PROTO((int));
int tbldiff PROTO((int[], int, int[]));
/* bldtbl - build table entries for dfa state
*
* synopsis
* int state[numecs], statenum, totaltrans, comstate, comfreq;
* bldtbl( state, statenum, totaltrans, comstate, comfreq );
*
* State is the statenum'th dfa state. It is indexed by equivalence class and
* gives the number of the state to enter for a given equivalence class.
* totaltrans is the total number of transitions out of the state. Comstate
* is that state which is the destination of the most transitions out of State.
* Comfreq is how many transitions there are out of State to Comstate.
*
* A note on terminology:
* "protos" are transition tables which have a high probability of
* either being redundant (a state processed later will have an identical
* transition table) or nearly redundant (a state processed later will have
* many of the same out-transitions). A "most recently used" queue of
* protos is kept around with the hope that most states will find a proto
* which is similar enough to be usable, and therefore compacting the
* output tables.
* "templates" are a special type of proto. If a transition table is
* homogeneous or nearly homogeneous (all transitions go to the same
* destination) then the odds are good that future states will also go
* to the same destination state on basically the same character set.
* These homogeneous states are so common when dealing with large rule
* sets that they merit special attention. If the transition table were
* simply made into a proto, then (typically) each subsequent, similar
* state will differ from the proto for two out-transitions. One of these
* out-transitions will be that character on which the proto does not go
* to the common destination, and one will be that character on which the
* state does not go to the common destination. Templates, on the other
* hand, go to the common state on EVERY transition character, and therefore
* cost only one difference.
*/
void
bldtbl(state, statenum, totaltrans, comstate, comfreq)
int state[], statenum, totaltrans, comstate, comfreq;
{
int extptr, extrct[2][CSIZE + 1];
int mindiff, minprot, i, d;
/*
* If extptr is 0 then the first array of extrct holds the result of
* the "best difference" to date, which is those transitions which
* occur in "state" but not in the proto which, to date, has the
* fewest differences between itself and "state". If extptr is 1
* then the second array of extrct hold the best difference. The two
* arrays are toggled between so that the best difference to date can
* be kept around and also a difference just created by checking
* against a candidate "best" proto.
*/
extptr = 0;
/*
* If the state has too few out-transitions, don't bother trying to
* compact its tables.
*/
if ((totaltrans * 100) < (numecs * PROTO_SIZE_PERCENTAGE))
mkentry(state, numecs, statenum, JAMSTATE, totaltrans);
else {
/*
* "checkcom" is true if we should only check "state" against
* protos which have the same "comstate" value.
*/
int checkcom =
comfreq * 100 > totaltrans * CHECK_COM_PERCENTAGE;
minprot = firstprot;
mindiff = totaltrans;
if (checkcom) {
/* Find first proto which has the same "comstate". */
for (i = firstprot; i != NIL; i = protnext[i])
if (protcomst[i] == comstate) {
minprot = i;
mindiff = tbldiff(state, minprot,
extrct[extptr]);
break;
}
} else {
/*
* Since we've decided that the most common
* destination out of "state" does not occur with a
* high enough frequency, we set the "comstate" to
* zero, assuring that if this state is entered into
* the proto list, it will not be considered a
* template.
*/
comstate = 0;
if (firstprot != NIL) {
minprot = firstprot;
mindiff = tbldiff(state, minprot,
extrct[extptr]);
}
}
/*
* We now have the first interesting proto in "minprot". If
* it matches within the tolerances set for the first proto,
* we don't want to bother scanning the rest of the proto
* list to see if we have any other reasonable matches.
*/
if (mindiff * 100 >
totaltrans * FIRST_MATCH_DIFF_PERCENTAGE) {
/*
* Not a good enough match. Scan the rest of the
* protos.
*/
for (i = minprot; i != NIL; i = protnext[i]) {
d = tbldiff(state, i, extrct[1 - extptr]);
if (d < mindiff) {
extptr = 1 - extptr;
mindiff = d;
minprot = i;
}
}
}
/*
* Check if the proto we've decided on as our best bet is
* close enough to the state we want to match to be usable.
*/
if (mindiff * 100 >
totaltrans * ACCEPTABLE_DIFF_PERCENTAGE) {
/*
* No good. If the state is homogeneous enough, we
* make a template out of it. Otherwise, we make a
* proto.
*/
if (comfreq * 100 >=
totaltrans * TEMPLATE_SAME_PERCENTAGE)
mktemplate(state, statenum,
comstate);
else {
mkprot(state, statenum, comstate);
mkentry(state, numecs, statenum,
JAMSTATE, totaltrans);
}
} else { /* use the proto */
mkentry(extrct[extptr], numecs, statenum,
prottbl[minprot], mindiff);
/*
* If this state was sufficiently different from the
* proto we built it from, make it, too, a proto.
*/
if (mindiff * 100 >=
totaltrans * NEW_PROTO_DIFF_PERCENTAGE)
mkprot(state, statenum, comstate);
/*
* Since mkprot added a new proto to the proto queue,
* it's possible that "minprot" is no longer on the
* proto queue (if it happened to have been the last
* entry, it would have been bumped off). If it's
* not there, then the new proto took its physical
* place (though logically the new proto is at the
* beginning of the queue), so in that case the
* following call will do nothing.
*/
mv2front(minprot);
}
}
}
/* cmptmps - compress template table entries
*
* Template tables are compressed by using the 'template equivalence
* classes', which are collections of transition character equivalence
* classes which always appear together in templates - really meta-equivalence
* classes.
*/
void
cmptmps()
{
int tmpstorage[CSIZE + 1];
int *tmp = tmpstorage, i, j;
int totaltrans, trans;
peakpairs = numtemps * numecs + tblend;
if (usemecs) {
/*
* Create equivalence classes based on data gathered on
* template transitions.
*/
nummecs = cre8ecs(tecfwd, tecbck, numecs);
} else
nummecs = numecs;
while (lastdfa + numtemps + 1 >= current_max_dfas)
increase_max_dfas();
/* Loop through each template. */
for (i = 1; i <= numtemps; ++i) {
/* Number of non-jam transitions out of this template. */
totaltrans = 0;
for (j = 1; j <= numecs; ++j) {
trans = tnxt[numecs * i + j];
if (usemecs) {
/*
* The absolute value of tecbck is the
* meta-equivalence class of a given
* equivalence class, as set up by cre8ecs().
*/
if (tecbck[j] > 0) {
tmp[tecbck[j]] = trans;
if (trans > 0)
++totaltrans;
}
} else {
tmp[j] = trans;
if (trans > 0)
++totaltrans;
}
}
/*
* It is assumed (in a rather subtle way) in the skeleton
* that if we're using meta-equivalence classes, the def[]
* entry for all templates is the jam template, i.e.,
* templates never default to other non-jam table entries
* (e.g., another template)
*/
/* Leave room for the jam-state after the last real state. */
mkentry(tmp, nummecs, lastdfa + i + 1, JAMSTATE,
totaltrans);
}
}
/* expand_nxt_chk - expand the next check arrays */
void
expand_nxt_chk()
{
int old_max = current_max_xpairs;
current_max_xpairs += MAX_XPAIRS_INCREMENT;
++num_reallocs;
nxt = reallocate_integer_array(nxt, current_max_xpairs);
chk = reallocate_integer_array(chk, current_max_xpairs);
memset((chk + old_max), 0, MAX_XPAIRS_INCREMENT * sizeof(int));
}
/* find_table_space - finds a space in the table for a state to be placed
*
* synopsis
* int *state, numtrans, block_start;
* int find_table_space();
*
* block_start = find_table_space( state, numtrans );
*
* State is the state to be added to the full speed transition table.
* Numtrans is the number of out-transitions for the state.
*
* find_table_space() returns the position of the start of the first block (in
* chk) able to accommodate the state
*
* In determining if a state will or will not fit, find_table_space() must take
* into account the fact that an end-of-buffer state will be added at [0],
* and an action number will be added in [-1].
*/
int
find_table_space(state, numtrans)
int *state, numtrans;
{
/*
* Firstfree is the position of the first possible occurrence of two
* consecutive unused records in the chk and nxt arrays.
*/
int i;
int *state_ptr, *chk_ptr;
int *ptr_to_last_entry_in_state;
/*
* If there are too many out-transitions, put the state at the end of
* nxt and chk.
*/
if (numtrans > MAX_XTIONS_FULL_INTERIOR_FIT) {
/*
* If table is empty, return the first available spot in
* chk/nxt, which should be 1.
*/
if (tblend < 2)
return 1;
/*
* Start searching for table space near the end of chk/nxt
* arrays.
*/
i = tblend - numecs;
} else
/*
* Start searching for table space from the beginning
* (skipping only the elements which will definitely not hold
* the new state).
*/
i = firstfree;
while (1) { /* loops until a space is found */
while (i + numecs >= current_max_xpairs)
expand_nxt_chk();
/*
* Loops until space for end-of-buffer and action number are
* found.
*/
while (1) {
/* Check for action number space. */
if (chk[i - 1] == 0) {
/* Check for end-of-buffer space. */
if (chk[i] == 0)
break;
else
/*
* Since i != 0, there is no use
* checking to see if (++i) - 1 == 0,
* because that's the same as i == 0,
* so we skip a space.
*/
i += 2;
} else
++i;
while (i + numecs >= current_max_xpairs)
expand_nxt_chk();
}
/*
* If we started search from the beginning, store the new
* firstfree for the next call of find_table_space().
*/
if (numtrans <= MAX_XTIONS_FULL_INTERIOR_FIT)
firstfree = i + 1;
/*
* Check to see if all elements in chk (and therefore nxt)
* that are needed for the new state have not yet been taken.
*/
state_ptr = &state[1];
ptr_to_last_entry_in_state = &chk[i + numecs + 1];
for (chk_ptr = &chk[i + 1];
chk_ptr != ptr_to_last_entry_in_state; ++chk_ptr)
if (*(state_ptr++) != 0 && *chk_ptr != 0)
break;
if (chk_ptr == ptr_to_last_entry_in_state)
return i;
else
++i;
}
}
/* inittbl - initialize transition tables
*
* Initializes "firstfree" to be one beyond the end of the table. Initializes
* all "chk" entries to be zero.
*/
void
inittbl()
{
int i;
memset(chk, 0, current_max_xpairs * sizeof(int));
tblend = 0;
firstfree = tblend + 1;
numtemps = 0;
if (usemecs) {
/*
* Set up doubly-linked meta-equivalence classes; these are
* sets of equivalence classes which all have identical
* transitions out of TEMPLATES.
*/
tecbck[1] = NIL;
for (i = 2; i <= numecs; ++i) {
tecbck[i] = i - 1;
tecfwd[i - 1] = i;
}
tecfwd[numecs] = NIL;
}
}
/* mkdeftbl - make the default, "jam" table entries */
void
mkdeftbl()
{
int i;
jamstate = lastdfa + 1;
++tblend; /* room for transition on end-of-buffer
* character */
while (tblend + numecs >= current_max_xpairs)
expand_nxt_chk();
/* Add in default end-of-buffer transition. */
nxt[tblend] = end_of_buffer_state;
chk[tblend] = jamstate;
for (i = 1; i <= numecs; ++i) {
nxt[tblend + i] = 0;
chk[tblend + i] = jamstate;
}
jambase = tblend;
base[jamstate] = jambase;
def[jamstate] = 0;
tblend += numecs;
++numtemps;
}
/* mkentry - create base/def and nxt/chk entries for transition array
*
* synopsis
* int state[numchars + 1], numchars, statenum, deflink, totaltrans;
* mkentry( state, numchars, statenum, deflink, totaltrans );
*
* "state" is a transition array "numchars" characters in size, "statenum"
* is the offset to be used into the base/def tables, and "deflink" is the
* entry to put in the "def" table entry. If "deflink" is equal to
* "JAMSTATE", then no attempt will be made to fit zero entries of "state"
* (i.e., jam entries) into the table. It is assumed that by linking to
* "JAMSTATE" they will be taken care of. In any case, entries in "state"
* marking transitions to "SAME_TRANS" are treated as though they will be
* taken care of by whereever "deflink" points. "totaltrans" is the total
* number of transitions out of the state. If it is below a certain threshold,
* the tables are searched for an interior spot that will accommodate the
* state array.
*/
void
mkentry(state, numchars, statenum, deflink, totaltrans)
int *state;
int numchars, statenum, deflink, totaltrans;
{
int minec, maxec, i, baseaddr;
int tblbase, tbllast;
if (totaltrans == 0) { /* there are no out-transitions */
if (deflink == JAMSTATE)
base[statenum] = JAMSTATE;
else
base[statenum] = 0;
def[statenum] = deflink;
return;
}
for (minec = 1; minec <= numchars; ++minec) {
if (state[minec] != SAME_TRANS)
if (state[minec] != 0 || deflink != JAMSTATE)
break;
}
if (totaltrans == 1) {
/*
* There's only one out-transition. Save it for later to
* fill in holes in the tables.
*/
stack1(statenum, minec, state[minec], deflink);
return;
}
for (maxec = numchars; maxec > 0; --maxec) {
if (state[maxec] != SAME_TRANS)
if (state[maxec] != 0 || deflink != JAMSTATE)
break;
}
/*
* Whether we try to fit the state table in the middle of the table
* entries we have already generated, or if we just take the state
* table at the end of the nxt/chk tables, we must make sure that we
* have a valid base address (i.e., non-negative). Note that
* negative base addresses dangerous at run-time (because indexing
* the nxt array with one and a low-valued character will access
* memory before the start of the array.
*/
/* Find the first transition of state that we need to worry about. */
if (totaltrans * 100 <= numchars * INTERIOR_FIT_PERCENTAGE) {
/* Attempt to squeeze it into the middle of the tables. */
baseaddr = firstfree;
while (baseaddr < minec) {
/*
* Using baseaddr would result in a negative base
* address below; find the next free slot.
*/
for (++baseaddr; chk[baseaddr] != 0; ++baseaddr);
}
while (baseaddr + maxec - minec + 1 >= current_max_xpairs)
expand_nxt_chk();
for (i = minec; i <= maxec; ++i)
if (state[i] != SAME_TRANS &&
(state[i] != 0 || deflink != JAMSTATE) &&
chk[baseaddr + i - minec] != 0) { /* baseaddr unsuitable -
* find another */
for (++baseaddr;
baseaddr < current_max_xpairs &&
chk[baseaddr] != 0; ++baseaddr);
while (baseaddr + maxec - minec + 1 >=
current_max_xpairs)
expand_nxt_chk();
/*
* Reset the loop counter so we'll start all
* over again next time it's incremented.
*/
i = minec - 1;
}
} else {
/*
* Ensure that the base address we eventually generate is
* non-negative.
*/
baseaddr = MAX(tblend + 1, minec);
}
tblbase = baseaddr - minec;
tbllast = tblbase + maxec;
while (tbllast + 1 >= current_max_xpairs)
expand_nxt_chk();
base[statenum] = tblbase;
def[statenum] = deflink;
for (i = minec; i <= maxec; ++i)
if (state[i] != SAME_TRANS)
if (state[i] != 0 || deflink != JAMSTATE) {
nxt[tblbase + i] = state[i];
chk[tblbase + i] = statenum;
}
if (baseaddr == firstfree)
/* Find next free slot in tables. */
for (++firstfree; chk[firstfree] != 0; ++firstfree);
tblend = MAX(tblend, tbllast);
}
/* mk1tbl - create table entries for a state (or state fragment) which
* has only one out-transition
*/
void
mk1tbl(state, sym, onenxt, onedef2)
int state, sym, onenxt, onedef2;
{
if (firstfree < sym)
firstfree = sym;
while (chk[firstfree] != 0)
if (++firstfree >= current_max_xpairs)
expand_nxt_chk();
base[state] = firstfree - sym;
def[state] = onedef2;
chk[firstfree] = state;
nxt[firstfree] = onenxt;
if (firstfree > tblend) {
tblend = firstfree++;
if (firstfree >= current_max_xpairs)
expand_nxt_chk();
}
}
/* mkprot - create new proto entry */
void
mkprot(state, statenum, comstate)
int state[], statenum, comstate;
{
int i, slot, tblbase;
if (++numprots >= MSP || numecs * numprots >= PROT_SAVE_SIZE) {
/*
* Gotta make room for the new proto by dropping last entry
* in the queue.
*/
slot = lastprot;
lastprot = protprev[lastprot];
protnext[lastprot] = NIL;
} else
slot = numprots;
protnext[slot] = firstprot;
if (firstprot != NIL)
protprev[firstprot] = slot;
firstprot = slot;
prottbl[slot] = statenum;
protcomst[slot] = comstate;
/* Copy state into save area so it can be compared with rapidly. */
tblbase = numecs * (slot - 1);
for (i = 1; i <= numecs; ++i)
protsave[tblbase + i] = state[i];
}
/* mktemplate - create a template entry based on a state, and connect the state
* to it
*/
void
mktemplate(state, statenum, comstate)
int state[], statenum, comstate;
{
int i, numdiff, tmpbase, tmp[CSIZE + 1];
u_char transset[CSIZE + 1];
int tsptr;
++numtemps;
tsptr = 0;
/*
* Calculate where we will temporarily store the transition table of
* the template in the tnxt[] array. The final transition table gets
* created by cmptmps().
*/
tmpbase = numtemps * numecs;
if (tmpbase + numecs >= current_max_template_xpairs) {
current_max_template_xpairs +=
MAX_TEMPLATE_XPAIRS_INCREMENT;
++num_reallocs;
tnxt = reallocate_integer_array(tnxt,
current_max_template_xpairs);
}
for (i = 1; i <= numecs; ++i)
if (state[i] == 0)
tnxt[tmpbase + i] = 0;
else {
transset[tsptr++] = i;
tnxt[tmpbase + i] = comstate;
}
if (usemecs)
mkeccl(transset, tsptr, tecfwd, tecbck, numecs, 0);
mkprot(tnxt + tmpbase, -numtemps, comstate);
/*
* We rely on the fact that mkprot adds things to the beginning of
* the proto queue.
*/
numdiff = tbldiff(state, firstprot, tmp);
mkentry(tmp, numecs, statenum, -numtemps, numdiff);
}
/* mv2front - move proto queue element to front of queue */
void
mv2front(qelm)
int qelm;
{
if (firstprot != qelm) {
if (qelm == lastprot)
lastprot = protprev[lastprot];
protnext[protprev[qelm]] = protnext[qelm];
if (protnext[qelm] != NIL)
protprev[protnext[qelm]] = protprev[qelm];
protprev[qelm] = NIL;
protnext[qelm] = firstprot;
protprev[firstprot] = qelm;
firstprot = qelm;
}
}
/* place_state - place a state into full speed transition table
*
* State is the statenum'th state. It is indexed by equivalence class and
* gives the number of the state to enter for a given equivalence class.
* Transnum is the number of out-transitions for the state.
*/
void
place_state(state, statenum, transnum)
int *state, statenum, transnum;
{
int i;
int *state_ptr;
int position = find_table_space(state, transnum);
/* "base" is the table of start positions. */
base[statenum] = position;
/*
* Put in action number marker; this non-zero number makes sure that
* find_table_space() knows that this position in chk/nxt is taken
* and should not be used for another accepting number in another
* state.
*/
chk[position - 1] = 1;
/*
* Put in end-of-buffer marker; this is for the same purposes as
* above.
*/
chk[position] = 1;
/* Place the state into chk and nxt. */
state_ptr = &state[1];
for (i = 1; i <= numecs; ++i, ++state_ptr)
if (*state_ptr != 0) {
chk[position + i] = i;
nxt[position + i] = *state_ptr;
}
if (position + numecs > tblend)
tblend = position + numecs;
}
/* stack1 - save states with only one out-transition to be processed later
*
* If there's room for another state on the "one-transition" stack, the
* state is pushed onto it, to be processed later by mk1tbl. If there's
* no room, we process the sucker right now.
*/
void
stack1(statenum, sym, nextstate, deflink)
int statenum, sym, nextstate, deflink;
{
if (onesp >= ONE_STACK_SIZE - 1)
mk1tbl(statenum, sym, nextstate, deflink);
else {
++onesp;
onestate[onesp] = statenum;
onesym[onesp] = sym;
onenext[onesp] = nextstate;
onedef[onesp] = deflink;
}
}
/* tbldiff - compute differences between two state tables
*
* "state" is the state array which is to be extracted from the pr'th
* proto. "pr" is both the number of the proto we are extracting from
* and an index into the save area where we can find the proto's complete
* state table. Each entry in "state" which differs from the corresponding
* entry of "pr" will appear in "ext".
*
* Entries which are the same in both "state" and "pr" will be marked
* as transitions to "SAME_TRANS" in "ext". The total number of differences
* between "state" and "pr" is returned as function value. Note that this
* number is "numecs" minus the number of "SAME_TRANS" entries in "ext".
*/
int
tbldiff(state, pr, ext)
int state[], pr, ext[];
{
int i, *sp = state, *ep = ext, *protp;
int numdiff = 0;
protp = &protsave[numecs * (pr - 1)];
for (i = numecs; i > 0; --i) {
if (*++protp == *++sp)
*++ep = SAME_TRANS;
else {
*++ep = *sp;
++numdiff;
}
}
return numdiff;
}

View file

@ -1,4 +0,0 @@
/* clang-format off */
/* $OpenBSD: version.h,v 1.5 2015/11/19 19:43:40 tedu Exp $ */
#define FLEX_VERSION VERSION

View file

@ -1,218 +0,0 @@
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:8;tab-width:8;coding:utf-8 -*-│
vi: set et ft=c ts=8 sw=8 fenc=utf-8 :vi
*/
/* clang-format off */
/* $OpenBSD: yylex.c,v 1.6 2015/11/19 19:43:40 tedu Exp $ */
/* yylex - scanner front-end for flex */
/* Copyright (c) 1990 The Regents of the University of California. */
/* All rights reserved. */
/* This code is derived from software contributed to Berkeley by */
/* Vern Paxson. */
/* The United States Government has rights in this work pursuant */
/* to contract no. DE-AC03-76SF00098 between the United States */
/* Department of Energy and the University of California. */
/* This file is part of flex. */
/* 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. */
/* 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR */
/* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED */
/* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR */
/* PURPOSE. */
#include "libc/str/str.h"
#include "third_party/lex/flexdef.h"
#include "libc/calls/calls.h"
#include "third_party/lex/parse.h"
/* yylex - scan for a regular expression token */
int yylex ()
{
int toktype;
static int beglin = false;
extern char *yytext;
if (eofseen)
toktype = EOF;
else
toktype = flexscan ();
if (toktype == EOF || toktype == 0) {
eofseen = 1;
if (sectnum == 1) {
synerr (_("premature EOF"));
sectnum = 2;
toktype = SECTEND;
}
else
toktype = 0;
}
if (trace) {
if (beglin) {
fprintf (stderr, "%d\t", num_rules + 1);
beglin = 0;
}
switch (toktype) {
case '<':
case '>':
case '^':
case '$':
case '"':
case '[':
case ']':
case '{':
case '}':
case '|':
case '(':
case ')':
case '-':
case '/':
case '\\':
case '?':
case '.':
case '*':
case '+':
case ',':
(void) putc (toktype, stderr);
break;
case '\n':
(void) putc ('\n', stderr);
if (sectnum == 2)
beglin = 1;
break;
case SCDECL:
fputs ("%s", stderr);
break;
case XSCDECL:
fputs ("%x", stderr);
break;
case SECTEND:
fputs ("%%\n", stderr);
/* We set beglin to be true so we'll start
* writing out numbers as we echo rules.
* flexscan() has already assigned sectnum.
*/
if (sectnum == 2)
beglin = 1;
break;
case NAME:
fprintf (stderr, "'%s'", nmstr);
break;
case CHAR:
switch (yylval) {
case '<':
case '>':
case '^':
case '$':
case '"':
case '[':
case ']':
case '{':
case '}':
case '|':
case '(':
case ')':
case '-':
case '/':
case '\\':
case '?':
case '.':
case '*':
case '+':
case ',':
fprintf (stderr, "\\%c", yylval);
break;
default:
if (!isascii (yylval) || !isprint (yylval))
fprintf (stderr,
"\\%.3o",
(unsigned int) yylval);
else
(void) putc (yylval, stderr);
break;
}
break;
case NUMBER:
fprintf (stderr, "%d", yylval);
break;
case PREVCCL:
fprintf (stderr, "[%d]", yylval);
break;
case EOF_OP:
fprintf (stderr, "<<EOF>>");
break;
case OPTION_OP:
fprintf (stderr, "%s ", yytext);
break;
case OPT_OUTFILE:
case OPT_PREFIX:
case CCE_ALNUM:
case CCE_ALPHA:
case CCE_BLANK:
case CCE_CNTRL:
case CCE_DIGIT:
case CCE_GRAPH:
case CCE_LOWER:
case CCE_PRINT:
case CCE_PUNCT:
case CCE_SPACE:
case CCE_UPPER:
case CCE_XDIGIT:
fprintf (stderr, "%s", yytext);
break;
case 0:
fprintf (stderr, _("End Marker\n"));
break;
default:
fprintf (stderr,
_
("*Something Weird* - tok: %d val: %d\n"),
toktype, yylval);
break;
}
}
return toktype;
}

View file

@ -1,25 +0,0 @@
Copyright (c) 2010-2014, Salvatore Sanfilippo <antirez at gmail dot com>
Copyright (c) 2010-2013, Pieter Noordhuis <pcnoordhuis at gmail dot com>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.

File diff suppressed because it is too large Load diff

View file

@ -1,31 +0,0 @@
#ifndef COSMOPOLITAN_THIRD_PARTY_LINENOISE_LINENOISE_H_
#define COSMOPOLITAN_THIRD_PARTY_LINENOISE_LINENOISE_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
typedef struct linenoiseCompletions {
size_t len;
char **cvec;
} linenoiseCompletions;
typedef void(linenoiseCompletionCallback)(const char *, linenoiseCompletions *);
typedef char *(linenoiseHintsCallback)(const char *, int *color, int *bold);
typedef void(linenoiseFreeHintsCallback)(void *);
void linenoiseSetCompletionCallback(linenoiseCompletionCallback *);
void linenoiseSetHintsCallback(linenoiseHintsCallback *);
void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *);
void linenoiseAddCompletion(linenoiseCompletions *, const char *);
char *linenoise(const char *prompt);
void linenoiseFree(void *ptr);
int linenoiseHistoryAdd(const char *line);
int linenoiseHistorySetMaxLen(int len);
int linenoiseHistorySave(const char *filename);
int linenoiseHistoryLoad(const char *filename);
void linenoiseClearScreen(void);
void linenoiseSetMultiLine(int ml);
void linenoisePrintKeyCodes(void);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_THIRD_PARTY_LINENOISE_LINENOISE_H_ */

View file

@ -1,57 +0,0 @@
#-*-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───────────────────────┘
PKGS += THIRD_PARTY_LINENOISE
THIRD_PARTY_LINENOISE_ARTIFACTS += THIRD_PARTY_LINENOISE_A
THIRD_PARTY_LINENOISE = $(THIRD_PARTY_LINENOISE_A_DEPS) $(THIRD_PARTY_LINENOISE_A)
THIRD_PARTY_LINENOISE_A = o/$(MODE)/third_party/linenoise/linenoise.a
THIRD_PARTY_LINENOISE_A_FILES := $(wildcard third_party/linenoise/*)
THIRD_PARTY_LINENOISE_A_HDRS = $(filter %.h,$(THIRD_PARTY_LINENOISE_A_FILES))
THIRD_PARTY_LINENOISE_A_SRCS = $(filter %.c,$(THIRD_PARTY_LINENOISE_A_FILES))
THIRD_PARTY_LINENOISE_A_OBJS = \
$(THIRD_PARTY_LINENOISE_A_SRCS:%=o/$(MODE)/%.zip.o) \
$(THIRD_PARTY_LINENOISE_A_SRCS:%.c=o/$(MODE)/%.o)
THIRD_PARTY_LINENOISE_A_CHECKS = \
$(THIRD_PARTY_LINENOISE_A).pkg
THIRD_PARTY_LINENOISE_A_DIRECTDEPS = \
LIBC_CALLS \
LIBC_FMT \
LIBC_MEM \
LIBC_NEXGEN32E \
LIBC_RUNTIME \
LIBC_STDIO \
LIBC_STR \
LIBC_STUBS \
LIBC_SYSV \
LIBC_SYSV_CALLS \
LIBC_UNICODE
THIRD_PARTY_LINENOISE_A_DEPS := \
$(call uniq,$(foreach x,$(THIRD_PARTY_LINENOISE_A_DIRECTDEPS),$($(x))))
$(THIRD_PARTY_LINENOISE_A): \
third_party/linenoise/ \
$(THIRD_PARTY_LINENOISE_A).pkg \
$(THIRD_PARTY_LINENOISE_A_OBJS)
$(THIRD_PARTY_LINENOISE_A).pkg: \
$(THIRD_PARTY_LINENOISE_A_OBJS) \
$(foreach x,$(THIRD_PARTY_LINENOISE_A_DIRECTDEPS),$($(x)_A).pkg)
THIRD_PARTY_LINENOISE_LIBS = $(foreach x,$(THIRD_PARTY_LINENOISE_ARTIFACTS),$($(x)))
THIRD_PARTY_LINENOISE_SRCS = $(foreach x,$(THIRD_PARTY_LINENOISE_ARTIFACTS),$($(x)_SRCS))
THIRD_PARTY_LINENOISE_HDRS = $(foreach x,$(THIRD_PARTY_LINENOISE_ARTIFACTS),$($(x)_HDRS))
THIRD_PARTY_LINENOISE_BINS = $(foreach x,$(THIRD_PARTY_LINENOISE_ARTIFACTS),$($(x)_BINS))
THIRD_PARTY_LINENOISE_CHECKS = $(foreach x,$(THIRD_PARTY_LINENOISE_ARTIFACTS),$($(x)_CHECKS))
THIRD_PARTY_LINENOISE_OBJS = $(foreach x,$(THIRD_PARTY_LINENOISE_ARTIFACTS),$($(x)_OBJS))
THIRD_PARTY_LINENOISE_TESTS = $(foreach x,$(THIRD_PARTY_LINENOISE_ARTIFACTS),$($(x)_TESTS))
$(THIRD_PARTY_LINENOISE_OBJS): third_party/linenoise/linenoise.mk
.PHONY: o/$(MODE)/third_party/linenoise
o/$(MODE)/third_party/linenoise: \
$(THIRD_PARTY_LINENOISE) \
$(THIRD_PARTY_LINENOISE_CHECKS)

View file

@ -1,8 +0,0 @@
.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
View file

@ -1,64 +0,0 @@
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
. |
+-------+ |
| <----------+
+-------+

View file

@ -1,380 +0,0 @@
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

View file

@ -1,38 +0,0 @@
# $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)))')')

View file

@ -1,43 +0,0 @@
# $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))')')

View file

@ -1,53 +0,0 @@
# $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

View file

@ -1,43 +0,0 @@
# $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))')')

View file

@ -1,43 +0,0 @@
# $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))')')

View file

@ -1,241 +0,0 @@
# $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..
#

View file

@ -1,640 +0,0 @@
# $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

File diff suppressed because it is too large Load diff

37
third_party/m4/expr.c vendored
View file

@ -1,37 +0,0 @@
/* $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;
}

View file

@ -1,183 +0,0 @@
/* 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 *, ...) wontreturn;
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
View file

@ -1,689 +0,0 @@
/* 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/fmt/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
View file

@ -1,333 +0,0 @@
/* 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
View file

@ -1,524 +0,0 @@
.\" @(#) $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 .

69
third_party/m4/m4.mk vendored
View file

@ -1,69 +0,0 @@
#-*-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): 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
View file

@ -1,967 +0,0 @@
.\" $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
View file

@ -1,642 +0,0 @@
/* 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.internal.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
View file

@ -1,239 +0,0 @@
/* 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
View file

@ -1,466 +0,0 @@
/* 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
View file

@ -1,325 +0,0 @@
/* 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);
}

View file

@ -1,75 +0,0 @@
/* 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

View file

@ -1,713 +0,0 @@
#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);
}

View file

@ -1,13 +0,0 @@
#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

View file

@ -1,81 +0,0 @@
%{
/* $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
;
%%

View file

@ -1,38 +0,0 @@
/* $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 */

Some files were not shown because too many files have changed in this diff Show more