mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 03:27:39 +00:00
Delete unused third party projects
This commit is contained in:
parent
113eeabd85
commit
04caf6f9ad
105 changed files with 0 additions and 66614 deletions
5
Makefile
5
Makefile
|
@ -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
|
||||
|
|
125
third_party/bzip2/.clang-format
vendored
125
third_party/bzip2/.clang-format
vendored
|
@ -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
|
||||
...
|
33
third_party/bzip2/bzip2.mk
vendored
33
third_party/bzip2/bzip2.mk
vendored
|
@ -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)
|
569
third_party/bzip2/µbunzip2.c
vendored
569
third_party/bzip2/µbunzip2.c
vendored
|
@ -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;
|
||||
}
|
||||
}
|
26
third_party/double-conversion/LICENSE
vendored
26
third_party/double-conversion/LICENSE
vendored
|
@ -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.
|
1
third_party/double-conversion/README.cosmo
vendored
1
third_party/double-conversion/README.cosmo
vendored
|
@ -1 +0,0 @@
|
|||
google/double-conversion@1dce44c4313a6f356fcfa4b3e8887f037ac0bf23
|
621
third_party/double-conversion/bignum-dtoa.cc
vendored
621
third_party/double-conversion/bignum-dtoa.cc
vendored
|
@ -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
|
84
third_party/double-conversion/bignum-dtoa.h
vendored
84
third_party/double-conversion/bignum-dtoa.h
vendored
|
@ -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_
|
775
third_party/double-conversion/bignum.cc
vendored
775
third_party/double-conversion/bignum.cc
vendored
|
@ -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
|
153
third_party/double-conversion/bignum.h
vendored
153
third_party/double-conversion/bignum.h
vendored
|
@ -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_
|
140
third_party/double-conversion/diy-fp.h
vendored
140
third_party/double-conversion/diy-fp.h
vendored
|
@ -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_
|
|
@ -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)
|
395
third_party/double-conversion/ieee.h
vendored
395
third_party/double-conversion/ieee.h
vendored
|
@ -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_
|
308
third_party/double-conversion/utils.h
vendored
308
third_party/double-conversion/utils.h
vendored
|
@ -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_
|
248
third_party/editline/ChangeLog.md
vendored
248
third_party/editline/ChangeLog.md
vendored
|
@ -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:
|
||||
-->
|
18
third_party/editline/LICENSE
vendored
18
third_party/editline/LICENSE
vendored
|
@ -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.
|
362
third_party/editline/complete.c
vendored
362
third_party/editline/complete.c
vendored
|
@ -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);
|
||||
}
|
274
third_party/editline/editline.3
vendored
274
third_party/editline/editline.3
vendored
|
@ -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.
|
1557
third_party/editline/editline.c
vendored
1557
third_party/editline/editline.c
vendored
File diff suppressed because it is too large
Load diff
91
third_party/editline/editline.h
vendored
91
third_party/editline/editline.h
vendored
|
@ -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_ */
|
57
third_party/editline/editline.mk
vendored
57
third_party/editline/editline.mk
vendored
|
@ -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)
|
21
third_party/editline/internal.h
vendored
21
third_party/editline/internal.h
vendored
|
@ -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_ */
|
112
third_party/editline/sysunix.c
vendored
112
third_party/editline/sysunix.c
vendored
|
@ -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) ? "/" : " ");
|
||||
}
|
43
third_party/lex/COPYING
vendored
43
third_party/lex/COPYING
vendored
|
@ -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."
|
8226
third_party/lex/ChangeLog
vendored
8226
third_party/lex/ChangeLog
vendored
File diff suppressed because it is too large
Load diff
211
third_party/lex/FlexLexer.h
vendored
211
third_party/lex/FlexLexer.h
vendored
|
@ -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
532
third_party/lex/NEWS
vendored
|
@ -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
113
third_party/lex/NOTES
vendored
|
@ -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
1233
third_party/lex/ONEWS
vendored
File diff suppressed because it is too large
Load diff
2759
third_party/lex/README.txt
vendored
2759
third_party/lex/README.txt
vendored
File diff suppressed because it is too large
Load diff
286
third_party/lex/buf.c
vendored
286
third_party/lex/buf.c
vendored
|
@ -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
325
third_party/lex/ccl.c
vendored
|
@ -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;
|
||||
}
|
207
third_party/lex/config.h
vendored
207
third_party/lex/config.h
vendored
|
@ -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
1105
third_party/lex/dfa.c
vendored
File diff suppressed because it is too large
Load diff
230
third_party/lex/ecs.c
vendored
230
third_party/lex/ecs.c
vendored
|
@ -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;
|
||||
}
|
452
third_party/lex/filter.c
vendored
452
third_party/lex/filter.c
vendored
|
@ -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(®ex_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(®ex_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
4438
third_party/lex/flex.1
vendored
File diff suppressed because it is too large
Load diff
3451
third_party/lex/flex.skl
vendored
3451
third_party/lex/flex.skl
vendored
File diff suppressed because it is too large
Load diff
1105
third_party/lex/flexdef.h
vendored
1105
third_party/lex/flexdef.h
vendored
File diff suppressed because it is too large
Load diff
67
third_party/lex/flexint.h
vendored
67
third_party/lex/flexint.h
vendored
|
@ -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
2145
third_party/lex/gen.c
vendored
File diff suppressed because it is too large
Load diff
118
third_party/lex/lex.mk
vendored
118
third_party/lex/lex.mk
vendored
|
@ -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
2208
third_party/lex/lex.ms
vendored
File diff suppressed because it is too large
Load diff
18
third_party/lex/libmain.c
vendored
18
third_party/lex/libmain.c
vendored
|
@ -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;
|
||||
}
|
31
third_party/lex/libyywrap.c
vendored
31
third_party/lex/libyywrap.c
vendored
|
@ -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
1826
third_party/lex/main.c
vendored
File diff suppressed because it is too large
Load diff
1017
third_party/lex/misc.c
vendored
1017
third_party/lex/misc.c
vendored
File diff suppressed because it is too large
Load diff
38
third_party/lex/mkskel.sh
vendored
38
third_party/lex/mkskel.sh
vendored
|
@ -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
734
third_party/lex/nfa.c
vendored
|
@ -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;
|
||||
}
|
285
third_party/lex/options.c
vendored
285
third_party/lex/options.c
vendored
|
@ -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. */
|
||||
};
|
135
third_party/lex/options.h
vendored
135
third_party/lex/options.h
vendored
|
@ -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
1810
third_party/lex/parse.c
vendored
File diff suppressed because it is too large
Load diff
45
third_party/lex/parse.h
vendored
45
third_party/lex/parse.h
vendored
|
@ -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
1089
third_party/lex/parse.y
vendored
File diff suppressed because it is too large
Load diff
181
third_party/lex/regex.c
vendored
181
third_party/lex/regex.c
vendored
|
@ -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(®ex_linedir, REGEXP_LINEDIR, REG_EXTENDED);
|
||||
flex_regcomp(®ex_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
4588
third_party/lex/scan.c
vendored
File diff suppressed because it is too large
Load diff
1010
third_party/lex/scan.l
vendored
1010
third_party/lex/scan.l
vendored
File diff suppressed because it is too large
Load diff
75
third_party/lex/scanflags.c
vendored
75
third_party/lex/scanflags.c
vendored
|
@ -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;
|
||||
}
|
881
third_party/lex/scanopt.c
vendored
881
third_party/lex/scanopt.c
vendored
|
@ -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);
|
||||
}
|
||||
}
|
133
third_party/lex/scanopt.h
vendored
133
third_party/lex/scanopt.h
vendored
|
@ -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
3740
third_party/lex/skel.c
vendored
File diff suppressed because it is too large
Load diff
280
third_party/lex/sym.c
vendored
280
third_party/lex/sym.c
vendored
|
@ -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;
|
||||
}
|
466
third_party/lex/tables.c
vendored
466
third_party/lex/tables.c
vendored
|
@ -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;
|
||||
}
|
86
third_party/lex/tables.h
vendored
86
third_party/lex/tables.h
vendored
|
@ -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
|
76
third_party/lex/tables_shared.c
vendored
76
third_party/lex/tables_shared.c
vendored
|
@ -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;
|
||||
}
|
145
third_party/lex/tables_shared.h
vendored
145
third_party/lex/tables_shared.h
vendored
|
@ -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
|
885
third_party/lex/tblcmp.c
vendored
885
third_party/lex/tblcmp.c
vendored
|
@ -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;
|
||||
}
|
4
third_party/lex/version.h
vendored
4
third_party/lex/version.h
vendored
|
@ -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
|
218
third_party/lex/yylex.c
vendored
218
third_party/lex/yylex.c
vendored
|
@ -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;
|
||||
}
|
25
third_party/linenoise/LICENSE
vendored
25
third_party/linenoise/LICENSE
vendored
|
@ -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.
|
1187
third_party/linenoise/linenoise.c
vendored
1187
third_party/linenoise/linenoise.c
vendored
File diff suppressed because it is too large
Load diff
31
third_party/linenoise/linenoise.h
vendored
31
third_party/linenoise/linenoise.h
vendored
|
@ -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_ */
|
57
third_party/linenoise/linenoise.mk
vendored
57
third_party/linenoise/linenoise.mk
vendored
|
@ -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)
|
8
third_party/m4/COPYING
vendored
8
third_party/m4/COPYING
vendored
|
@ -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
64
third_party/m4/NOTES
vendored
|
@ -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
|
||||
. |
|
||||
+-------+ |
|
||||
| <----------+
|
||||
+-------+
|
380
third_party/m4/README.txt
vendored
380
third_party/m4/README.txt
vendored
|
@ -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
|
38
third_party/m4/TEST/ack.m4
vendored
38
third_party/m4/TEST/ack.m4
vendored
|
@ -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)))')')
|
43
third_party/m4/TEST/hanoi.m4
vendored
43
third_party/m4/TEST/hanoi.m4
vendored
|
@ -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))')')
|
53
third_party/m4/TEST/hash.m4
vendored
53
third_party/m4/TEST/hash.m4
vendored
|
@ -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
|
43
third_party/m4/TEST/sqroot.m4
vendored
43
third_party/m4/TEST/sqroot.m4
vendored
|
@ -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))')')
|
43
third_party/m4/TEST/string.m4
vendored
43
third_party/m4/TEST/string.m4
vendored
|
@ -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))')')
|
241
third_party/m4/TEST/test.m4
vendored
241
third_party/m4/TEST/test.m4
vendored
|
@ -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..
|
||||
#
|
640
third_party/m4/TEST/test.m4.golden
vendored
640
third_party/m4/TEST/test.m4.golden
vendored
|
@ -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
1031
third_party/m4/eval.c
vendored
File diff suppressed because it is too large
Load diff
37
third_party/m4/expr.c
vendored
37
third_party/m4/expr.c
vendored
|
@ -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;
|
||||
}
|
183
third_party/m4/extern.h
vendored
183
third_party/m4/extern.h
vendored
|
@ -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
689
third_party/m4/gnum4.c
vendored
|
@ -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
333
third_party/m4/look.c
vendored
|
@ -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(¯os, 10, ¯o_info);
|
||||
}
|
||||
|
||||
/*
|
||||
* find name in the hash table
|
||||
*/
|
||||
ndptr
|
||||
lookup(const char *name)
|
||||
{
|
||||
return ohash_find(¯os, ohash_qlookup(¯os, name));
|
||||
}
|
||||
|
||||
struct macro_definition *
|
||||
lookup_macro_definition(const char *name)
|
||||
{
|
||||
ndptr p;
|
||||
|
||||
p = ohash_find(¯os, ohash_qlookup(¯os, name));
|
||||
if (p)
|
||||
return p->d;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
setup_definition(struct macro_definition *d, const char *defn, const char *name)
|
||||
{
|
||||
ndptr p;
|
||||
|
||||
if (strncmp(defn, BUILTIN_MARKER, sizeof(BUILTIN_MARKER)-1) == 0 &&
|
||||
(p = macro_getbuiltin(defn+sizeof(BUILTIN_MARKER)-1)) != NULL) {
|
||||
d->type = macro_builtin_type(p);
|
||||
d->defn = xstrdup(defn+sizeof(BUILTIN_MARKER)-1);
|
||||
} else {
|
||||
if (!*defn)
|
||||
d->defn = null;
|
||||
else
|
||||
d->defn = xstrdup(defn);
|
||||
d->type = MACRTYPE;
|
||||
}
|
||||
if (STREQ(name, defn))
|
||||
d->type |= RECDEF;
|
||||
}
|
||||
|
||||
static ndptr
|
||||
create_entry(const char *name)
|
||||
{
|
||||
const char *end = NULL;
|
||||
unsigned int i;
|
||||
ndptr n;
|
||||
|
||||
i = ohash_qlookupi(¯os, name, &end);
|
||||
n = ohash_find(¯os, i);
|
||||
if (n == NULL) {
|
||||
n = ohash_create_entry(¯o_info, name, &end);
|
||||
ohash_insert(¯os, i, n);
|
||||
n->trace_flags = FLAG_NO_TRACE;
|
||||
n->builtin_type = MACRTYPE;
|
||||
n->d = NULL;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
void
|
||||
macro_define(const char *name, const char *defn)
|
||||
{
|
||||
ndptr n = create_entry(name);
|
||||
if (n->d != NULL) {
|
||||
if (n->d->defn != null)
|
||||
free_definition(n->d->defn);
|
||||
} else {
|
||||
n->d = xalloc(sizeof(struct macro_definition), NULL);
|
||||
n->d->next = NULL;
|
||||
}
|
||||
setup_definition(n->d, defn, name);
|
||||
}
|
||||
|
||||
void
|
||||
macro_pushdef(const char *name, const char *defn)
|
||||
{
|
||||
ndptr n;
|
||||
struct macro_definition *d;
|
||||
|
||||
n = create_entry(name);
|
||||
d = xalloc(sizeof(struct macro_definition), NULL);
|
||||
d->next = n->d;
|
||||
n->d = d;
|
||||
setup_definition(n->d, defn, name);
|
||||
}
|
||||
|
||||
void
|
||||
macro_undefine(const char *name)
|
||||
{
|
||||
ndptr n = lookup(name);
|
||||
if (n != NULL) {
|
||||
struct macro_definition *r, *r2;
|
||||
|
||||
for (r = n->d; r != NULL; r = r2) {
|
||||
r2 = r->next;
|
||||
if (r->defn != null)
|
||||
free(r->defn);
|
||||
free(r);
|
||||
}
|
||||
n->d = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
macro_popdef(const char *name)
|
||||
{
|
||||
ndptr n = lookup(name);
|
||||
|
||||
if (n != NULL) {
|
||||
struct macro_definition *r = n->d;
|
||||
if (r != NULL) {
|
||||
n->d = r->next;
|
||||
if (r->defn != null)
|
||||
free(r->defn);
|
||||
free(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
macro_for_all(void (*f)(const char *, struct macro_definition *))
|
||||
{
|
||||
ndptr n;
|
||||
unsigned int i;
|
||||
|
||||
for (n = ohash_first(¯os, &i); n != NULL;
|
||||
n = ohash_next(¯os, &i))
|
||||
if (n->d != NULL)
|
||||
f(n->name, n->d);
|
||||
}
|
||||
|
||||
void
|
||||
setup_builtin(const char *name, unsigned int type)
|
||||
{
|
||||
ndptr n;
|
||||
char *name2;
|
||||
|
||||
if (prefix_builtins) {
|
||||
name2 = xalloc(strlen(name)+3+1, NULL);
|
||||
memcpy(name2, "m4_", 3);
|
||||
memcpy(name2 + 3, name, strlen(name)+1);
|
||||
} else
|
||||
name2 = xstrdup(name);
|
||||
|
||||
n = create_entry(name2);
|
||||
n->builtin_type = type;
|
||||
n->d = xalloc(sizeof(struct macro_definition), NULL);
|
||||
n->d->defn = name2;
|
||||
n->d->type = type;
|
||||
n->d->next = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
mark_traced(const char *name, int on)
|
||||
{
|
||||
ndptr p;
|
||||
unsigned int i;
|
||||
|
||||
if (name == NULL) {
|
||||
if (on)
|
||||
trace_flags |= TRACE_ALL;
|
||||
else
|
||||
trace_flags &= ~TRACE_ALL;
|
||||
for (p = ohash_first(¯os, &i); p != NULL;
|
||||
p = ohash_next(¯os, &i))
|
||||
p->trace_flags = FLAG_NO_TRACE;
|
||||
} else {
|
||||
p = create_entry(name);
|
||||
p->trace_flags = on;
|
||||
}
|
||||
}
|
||||
|
||||
ndptr
|
||||
macro_getbuiltin(const char *name)
|
||||
{
|
||||
ndptr p;
|
||||
|
||||
p = lookup(name);
|
||||
if (p == NULL || p->builtin_type == MACRTYPE)
|
||||
return NULL;
|
||||
else
|
||||
return p;
|
||||
}
|
||||
|
||||
/* XXX things are slightly more complicated than they seem.
|
||||
* a macro may actually be "live" (in the middle of an expansion
|
||||
* on the stack.
|
||||
* So we actually may need to place it in an array for later...
|
||||
*/
|
||||
|
||||
static int kept_capacity = 0;
|
||||
static int kept_size = 0;
|
||||
static char **kept = NULL;
|
||||
|
||||
static void
|
||||
keep(char *ptr)
|
||||
{
|
||||
if (kept_capacity <= kept_size) {
|
||||
if (kept_capacity)
|
||||
kept_capacity *= 2;
|
||||
else
|
||||
kept_capacity = 50;
|
||||
kept = xreallocarray(kept, kept_capacity,
|
||||
sizeof(char *), "Out of memory while saving %d strings\n",
|
||||
kept_capacity);
|
||||
}
|
||||
kept[kept_size++] = ptr;
|
||||
}
|
||||
|
||||
static int
|
||||
string_in_use(const char *ptr)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i <= sp; i++) {
|
||||
if (sstack[i] == STORAGE_MACRO && mstack[i].sstr == ptr)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
free_definition(char *ptr)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* first try to free old strings */
|
||||
for (i = 0; i < kept_size; i++) {
|
||||
if (!string_in_use(kept[i])) {
|
||||
kept_size--;
|
||||
free(kept[i]);
|
||||
if (i != kept_size)
|
||||
kept[i] = kept[kept_size];
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
/* then deal with us */
|
||||
if (string_in_use(ptr))
|
||||
keep(ptr);
|
||||
else
|
||||
free(ptr);
|
||||
}
|
||||
|
524
third_party/m4/m4.1
vendored
524
third_party/m4/m4.1
vendored
|
@ -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
69
third_party/m4/m4.mk
vendored
|
@ -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
967
third_party/m4/m4.ms
vendored
|
@ -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
642
third_party/m4/main.c
vendored
|
@ -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(¯os, ohash_qlookupi(¯os, name, (const char **)&tp));
|
||||
if (p == NULL)
|
||||
return NULL;
|
||||
if (macro_getdef(p) == NULL)
|
||||
return NULL;
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
* initkwds - initialise m4 keywords as fast as possible.
|
||||
* This very similar to install, but without certain overheads,
|
||||
* such as calling lookup. Malloc is not used for storing the
|
||||
* keyword strings, since we simply use the static pointers
|
||||
* within keywrds block.
|
||||
*/
|
||||
static void
|
||||
initkwds(void)
|
||||
{
|
||||
unsigned int type;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAXKEYS; i++) {
|
||||
type = keywrds[i].ktyp & TYPEMASK;
|
||||
if ((keywrds[i].ktyp & NOARGS) == 0)
|
||||
type |= NEEDARGS;
|
||||
setup_builtin(keywrds[i].knam, type);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
record(struct position *t, int lev)
|
||||
{
|
||||
if (lev < MAXRECORD) {
|
||||
t[lev].name = CURRENT_NAME;
|
||||
t[lev].line = CURRENT_LINE;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dump_stack(struct position *t, int lev)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < lev; i++) {
|
||||
if (i == MAXRECORD) {
|
||||
fprintf(stderr, " ...\n");
|
||||
break;
|
||||
}
|
||||
fprintf(stderr, " %s at line %lu\n",
|
||||
t[i].name, t[i].line);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
enlarge_stack(void)
|
||||
{
|
||||
STACKMAX += STACKMAX/2;
|
||||
mstack = xreallocarray(mstack, STACKMAX, sizeof(stae),
|
||||
"Evaluation stack overflow (%lu)",
|
||||
(unsigned long)STACKMAX);
|
||||
sstack = xrealloc(sstack, STACKMAX,
|
||||
"Evaluation stack overflow (%lu)",
|
||||
(unsigned long)STACKMAX);
|
||||
}
|
239
third_party/m4/mdef.h
vendored
239
third_party/m4/mdef.h
vendored
|
@ -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
466
third_party/m4/misc.c
vendored
|
@ -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
325
third_party/m4/ohash.c
vendored
|
@ -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);
|
||||
}
|
75
third_party/m4/ohash.h
vendored
75
third_party/m4/ohash.h
vendored
|
@ -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
|
713
third_party/m4/parser.c
vendored
713
third_party/m4/parser.c
vendored
|
@ -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);
|
||||
}
|
13
third_party/m4/parser.h
vendored
13
third_party/m4/parser.h
vendored
|
@ -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
|
81
third_party/m4/parser.y
vendored
81
third_party/m4/parser.y
vendored
|
@ -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
|
||||
;
|
||||
%%
|
||||
|
38
third_party/m4/pathnames.h
vendored
38
third_party/m4/pathnames.h
vendored
|
@ -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
Loading…
Reference in a new issue