Add deobfuscated versions of 199[1-3]/ant
Anthony/@SirWumpus kindly provided these files. The source code and their Makefiles are in a deobfuscated/ subdirectory (for each of the three entries) but running make alt from the entry directory works. It uses the deobfuscated version's Makefile but copies the compiled binary to the entry's directory to keep things clean (deobfuscated code separate from the entry) to simplify using the deobfuscated versions. Entries that had a test suite Makefile have a new one for the deobfuscated code and a try.alt.sh script was added to 1992/ant and 1993/ant but the entry_text is a bit different than the usual to indicate that it's the deobfuscated version. It might be that the way this is done should be reorganised some but that can be decided on later. The entries from 2004 and 2005 have not yet been added because some decisions have to be made as those are the ones with a configure script. The manifest was updated and the .entry.json and index.html files were updated. It is not clear yet if the inventory_order is right but that will be looked at in the next day or two. Thank you Anthony!
This commit is contained in:
1 parent
95efa5ada6
commit
a4fb0a8c8c
39 files changed
+3174
-48
No files matched your search
+49
-1
@@ -49,6 +49,46 @@
|
||||
"display_via_github" : true,
|
||||
"entry_text" : "script to try entry"
|
||||
},
|
||||
{
|
||||
"file_path" : "deobfuscated/ant-c89.c",
|
||||
"inventory_order" : 120,
|
||||
"OK_to_edit" : true,
|
||||
"display_as" : "c",
|
||||
"display_via_github" : true,
|
||||
"entry_text" : "author provided deobfuscated code converted from K&R"
|
||||
},
|
||||
{
|
||||
"file_path" : "deobfuscated/ant.c",
|
||||
"inventory_order" : 120,
|
||||
"OK_to_edit" : true,
|
||||
"display_as" : "c",
|
||||
"display_via_github" : true,
|
||||
"entry_text" : "author provided deobfuscated code"
|
||||
},
|
||||
{
|
||||
"file_path" : "try.alt.sh",
|
||||
"inventory_order" : 130,
|
||||
"OK_to_edit" : true,
|
||||
"display_as" : "shellscript",
|
||||
"display_via_github" : true,
|
||||
"entry_text" : "script to try deobfuscated code"
|
||||
},
|
||||
{
|
||||
"file_path" : "deobfuscated/Makefile",
|
||||
"inventory_order" : 140,
|
||||
"OK_to_edit" : true,
|
||||
"display_as" : "makefile",
|
||||
"display_via_github" : true,
|
||||
"entry_text" : "author provided Makefile for deobfuscated code"
|
||||
},
|
||||
{
|
||||
"file_path" : "deobfuscated/test.mk",
|
||||
"inventory_order" : 140,
|
||||
"OK_to_edit" : true,
|
||||
"display_as" : "makefile",
|
||||
"display_via_github" : true,
|
||||
"entry_text" : "author provided test suite Makefile for deobfuscated code"
|
||||
},
|
||||
{
|
||||
"file_path" : "ant.test.mk",
|
||||
"inventory_order" : 150,
|
||||
@@ -60,11 +100,19 @@
|
||||
{
|
||||
"file_path" : "ants.txt",
|
||||
"inventory_order" : 150,
|
||||
"OK_to_edit" : true,
|
||||
"OK_to_edit" : false,
|
||||
"display_as" : "text",
|
||||
"display_via_github" : false,
|
||||
"entry_text" : "lyrics of the Ants Go Marching song"
|
||||
},
|
||||
{
|
||||
"file_path" : "ant.alt.test.mk",
|
||||
"inventory_order" : 160,
|
||||
"OK_to_edit" : true,
|
||||
"display_as" : "makefile",
|
||||
"display_via_github" : true,
|
||||
"entry_text" : "test suite Makefile for deobfuscated code"
|
||||
},
|
||||
{
|
||||
"file_path" : "1993_ant.tar.bz2",
|
||||
"inventory_order" : 1415926535,
|
||||
|
||||
@@ -2,8 +2,10 @@
|
||||
# sort with: ../../bin/sgi.sh
|
||||
*.dSYM
|
||||
ag
|
||||
ag.alt
|
||||
ag.txt
|
||||
ant
|
||||
ant.alt
|
||||
ant.orig
|
||||
indent
|
||||
indent.c
|
||||
|
||||
+26
-5
@@ -116,8 +116,8 @@ OBJ= ${PROG}.o
|
||||
DATA=
|
||||
TARGET= ${PROG}
|
||||
#
|
||||
ALT_OBJ=
|
||||
ALT_TARGET=
|
||||
ALT_OBJ= deobfuscated/${PROG}.o
|
||||
ALT_TARGET= deobfuscated/${PROG}
|
||||
|
||||
|
||||
#################
|
||||
@@ -145,9 +145,30 @@ ag.txt: ${PROG}.txt
|
||||
|
||||
# alternative executable
|
||||
#
|
||||
alt: data ${ALT_TARGET}
|
||||
alt: data ${PROG}.alt
|
||||
@${TRUE}
|
||||
|
||||
# We keep the alternate code, the deobfuscated code, and its Makefile, in the
|
||||
# deobfuscated directory but copy the compiled binaries to the entry directory,
|
||||
# to keep both directories clean, separating the two. The reason we copy the
|
||||
# binary to the entry directory is so one does not have to do:
|
||||
#
|
||||
# ./deobfuscated/ant
|
||||
#
|
||||
# but instead just:
|
||||
#
|
||||
# ./ant.alt
|
||||
#
|
||||
# while still using the Makefile provided with the deobfuscated code.
|
||||
#
|
||||
${PROG}.alt: deobfuscated/ant.c
|
||||
${MAKE} -C deobfuscated ant
|
||||
${CP} -v -f deobfuscated/ant ant.alt
|
||||
|
||||
ag.alt: ${PROG}.alt
|
||||
${RM} -f $@
|
||||
${CP} -f $< $@
|
||||
|
||||
# data files
|
||||
#
|
||||
data: ${DATA}
|
||||
@@ -155,7 +176,7 @@ data: ${DATA}
|
||||
|
||||
# both all and alt
|
||||
#
|
||||
everything: all alt
|
||||
everything: all alt ag ag.alt
|
||||
@${TRUE}
|
||||
|
||||
|
||||
@@ -215,7 +236,7 @@ clean:
|
||||
clobber: clean
|
||||
${RM} -f ${TARGET} ${ALT_TARGET}
|
||||
${RM} -rf *.dSYM
|
||||
${RM} -f ag ag.txt
|
||||
${RM} -f ag ag.txt ant.alt ag.alt deobfuscated/ant deobfuscated/ant-c89 deobfuscated/ag deobfuscated/ag-c89
|
||||
@-if [ -e sandwich ]; then \
|
||||
${RM} -f sandwich; \
|
||||
echo 'ate sandwich'; \
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
make all
|
||||
```
|
||||
|
||||
The author provided a deobfuscated version. See [Alternate
|
||||
code](#alternate-code) below.
|
||||
|
||||
|
||||
### Bugs and (Mis)features:
|
||||
|
||||
@@ -31,6 +34,35 @@ For more detailed information see [1993/ant in bugs.html](../../bugs.html#1993_a
|
||||
```
|
||||
|
||||
|
||||
## Alternate code:
|
||||
|
||||
The [ant.c in deobfuscated/](%%REPO_URL%%/1993/ant/deobfuscated/ant.c) is a
|
||||
deobfuscated version provided by the author. You can look at this code if you
|
||||
want some clues in how it works.
|
||||
|
||||
|
||||
## Alternate build:
|
||||
|
||||
If you wish to build this deobfuscated version, you can do so like:
|
||||
|
||||
|
||||
``` <!---sh-->
|
||||
make alt
|
||||
```
|
||||
|
||||
|
||||
## Alternate use:
|
||||
|
||||
Use `ant.alt` like you would `ant` above.
|
||||
|
||||
|
||||
## Alternate try:
|
||||
|
||||
``` <!---sh-->
|
||||
./try.alt.sh
|
||||
```
|
||||
|
||||
|
||||
## Judges' remarks:
|
||||
|
||||
See the author's POSIX P1003.2-like documentation file [ant.txt](ant.txt) for
|
||||
|
||||
@@ -0,0 +1,240 @@
|
||||
#
|
||||
# Test Driver for Anthony's Grep
|
||||
#
|
||||
# Public Domain 1992, 1993 by Anthony Howe. No warrant.alty.
|
||||
#
|
||||
|
||||
SHELL=/bin/sh
|
||||
PRG=./ant.alt
|
||||
|
||||
all: ant.alt char word anchor literal wild closure option branch sub class
|
||||
|
||||
#
|
||||
# Built the entry
|
||||
#
|
||||
ant.alt: Makefile
|
||||
make -f Makefile ant.alt
|
||||
|
||||
#
|
||||
# Test simple text patterns without the use of meta characters.
|
||||
#
|
||||
|
||||
empty:
|
||||
$(PRG) '' ant.alt.test.mk
|
||||
|
||||
char:
|
||||
$(PRG) 'q' ant.alt.test.mk
|
||||
|
||||
word:
|
||||
$(PRG) 'simple' ant.alt.test.mk
|
||||
|
||||
#
|
||||
# Test meta characters.
|
||||
#
|
||||
|
||||
anchor: anchor1 anchor2 anchor3 anchor4 anchor5
|
||||
|
||||
anchor1:
|
||||
$(PRG) '^anchor1' ant.alt.test.mk
|
||||
|
||||
anchor2:
|
||||
$(PRG) 'Grep$$' ant.alt.test.mk
|
||||
|
||||
#
|
||||
# Find all empty lines.
|
||||
#
|
||||
anchor3:
|
||||
$(PRG) '^$$' ant.alt.test.mk
|
||||
|
||||
#
|
||||
# This is valid but will never match.
|
||||
#
|
||||
anchor4:
|
||||
-$(PRG) 'x^a' ant.alt.test.mk
|
||||
|
||||
#
|
||||
# This is valid but will never match.
|
||||
#
|
||||
anchor5:
|
||||
-$(PRG) 'mk$$x' ant.alt.test.mk
|
||||
|
||||
literal: literal1 literal2
|
||||
|
||||
#
|
||||
# Every line with a dollar-sign.
|
||||
#
|
||||
literal1:
|
||||
$(PRG) '\$$' ant.alt.test.mk
|
||||
|
||||
#
|
||||
# Every line with a backslash.
|
||||
#
|
||||
literal2:
|
||||
$(PRG) '\\' ant.alt.test.mk
|
||||
|
||||
#
|
||||
# wild #1#
|
||||
# wild #a#
|
||||
# wild #%#
|
||||
#
|
||||
wild:
|
||||
$(PRG) '#.#' ant.alt.test.mk
|
||||
|
||||
#
|
||||
# closure !!
|
||||
# closure !x!
|
||||
# closure !xxxxxx!
|
||||
#
|
||||
closure:
|
||||
$(PRG) 'closure !x*!' ant.alt.test.mk
|
||||
|
||||
#
|
||||
# option ++
|
||||
# option +a+
|
||||
# option +b+
|
||||
# option +c+
|
||||
# option +abc+
|
||||
#
|
||||
option: option1 option2
|
||||
|
||||
option1:
|
||||
$(PRG) '+b?+' ant.alt.test.mk
|
||||
|
||||
option2:
|
||||
$(PRG) '+.?+' ant.alt.test.mk
|
||||
|
||||
branch: branch1 branch2 branch3 branch4 branch5 branch6
|
||||
|
||||
branch1:
|
||||
$(PRG) 'q|simple' ant.alt.test.mk
|
||||
|
||||
#
|
||||
# This pattern should be the same as '(^all)|(Public)|(Grep$)'.
|
||||
#
|
||||
branch2:
|
||||
$(PRG) '^all|Public|Grep$$' ant.alt.test.mk
|
||||
|
||||
#
|
||||
# This pattern should generate the same results as branch2.
|
||||
#
|
||||
branch3:
|
||||
$(PRG) 'Grep$$|^all|Public' ant.alt.test.mk
|
||||
|
||||
#
|
||||
# Null expression between start of pattern and vertical-line.
|
||||
#
|
||||
branch4:
|
||||
$(PRG) '|Grep' ant.alt.test.mk
|
||||
|
||||
#
|
||||
# Null expression between vertical-line and end of pattern.
|
||||
#
|
||||
branch5:
|
||||
$(PRG) 'Grep|' ant.alt.test.mk
|
||||
|
||||
#
|
||||
# Null expression between vertical-line and vertical-line.
|
||||
#
|
||||
branch6:
|
||||
$(PRG) 'all||Grep' ant.alt.test.mk
|
||||
|
||||
#
|
||||
# sub aabcbcbcxx
|
||||
# sub aagxx
|
||||
# sub aaggxx
|
||||
# sub aadddxx
|
||||
# sub aaxx
|
||||
#
|
||||
sub: sub0 sub1 sub2 sub3 sub4 sub5 lparen1 lparen2 rparen1 rparen2
|
||||
|
||||
#
|
||||
# Null sub-expressions.
|
||||
#
|
||||
sub0:
|
||||
$(PRG) 's()u()b()' ant.alt.test.mk
|
||||
|
||||
sub1:
|
||||
$(PRG) '#(1|%)#' ant.alt.test.mk
|
||||
|
||||
sub2:
|
||||
$(PRG) 'aa((bc)*|g)xx' ant.alt.test.mk
|
||||
|
||||
#
|
||||
# Null expression between the left-parenthesis and the vertical-line.
|
||||
#
|
||||
sub3:
|
||||
$(PRG) '#(|1)#' ant.alt.test.mk
|
||||
|
||||
#
|
||||
# Null expression between the vertical-line and the right-parenthesis.
|
||||
#
|
||||
sub4:
|
||||
$(PRG) '#(1|)#' ant.alt.test.mk
|
||||
|
||||
#
|
||||
# Null expression between the vertical-line and the right-parenthesis.
|
||||
#
|
||||
sub5:
|
||||
$(PRG) '#(%||1)#' ant.alt.test.mk
|
||||
|
||||
#
|
||||
# Missing left-parenthesis generates an error.
|
||||
#
|
||||
lparen1:
|
||||
-$(PRG) 'left ( only' ant.alt.test.mk
|
||||
|
||||
lparen2:
|
||||
$(PRG) 'left \( only' ant.alt.test.mk
|
||||
|
||||
#
|
||||
# Right-parenthesis without preceding left parenthesis should be a literal.
|
||||
#
|
||||
rparen1:
|
||||
-$(PRG) 'right ) only' ant.alt.test.mk
|
||||
|
||||
rparen2:
|
||||
$(PRG) 'right \) only' ant.alt.test.mk
|
||||
|
||||
#
|
||||
# 12345678
|
||||
# -----------------
|
||||
# =0= 1 45
|
||||
# =1= 2 45 78
|
||||
# =2= 2 45
|
||||
# =3= 2 45 78
|
||||
# =4= 2 45
|
||||
# =5= 2 45
|
||||
# =6= 2 45
|
||||
# =7= 2 45
|
||||
# =8= 2 45
|
||||
# =9= 1 45
|
||||
# =]= 23 6
|
||||
# =-= 2 4 678
|
||||
# = = 2 4 6
|
||||
#
|
||||
class: class1 class2 class3 class4 class5 class6 class7 class8
|
||||
|
||||
class1:
|
||||
$(PRG) '=[09]=' ant.alt.test.mk
|
||||
|
||||
class2:
|
||||
$(PRG) '=[^09]=' ant.alt.test.mk
|
||||
|
||||
class3:
|
||||
$(PRG) '=[]]=' ant.alt.test.mk
|
||||
|
||||
class4:
|
||||
$(PRG) '=[^]]=' ant.alt.test.mk
|
||||
|
||||
class5:
|
||||
$(PRG) '=[0-9]=' ant.alt.test.mk
|
||||
|
||||
class6:
|
||||
$(PRG) '=[^0-9]=' ant.alt.test.mk
|
||||
|
||||
class7:
|
||||
-$(PRG) '=[3-1]=' ant.alt.test.mk
|
||||
|
||||
class8:
|
||||
$(PRG) '=[-13]=' ant.alt.test.mk
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
CFLAGS= -Os -Wno-deprecated-non-prototype
|
||||
|
||||
all: build
|
||||
|
||||
build: ant ant-c89
|
||||
|
||||
clean:
|
||||
-rm -f ant ant-c89 *.out
|
||||
|
||||
# Original K&R version.
|
||||
ant$E: ant.c
|
||||
${CC} ${CFLAGS} ant.c -o $@
|
||||
|
||||
ant-c89$E: ant-c89.c
|
||||
${CC} ${CFLAGS} ant-c89.c -o $@
|
||||
|
||||
test: ant$E
|
||||
${MAKE} -f test.mk PRG=./ant >ant.out 2>&1
|
||||
|
||||
test-c89: ant-c89$E
|
||||
${MAKE} -f test.mk PRG=./ant-c89 >ant-c89.out 2>&1
|
||||
|
||||
# Make sure the old and revised versions behave the same.
|
||||
test-compare: build test test-c89
|
||||
sed -e 's/-c89//' ant-c89.out | diff -u ant.out -
|
||||
rm *.out
|
||||
|
||||
@@ -0,0 +1,425 @@
|
||||
/*
|
||||
* ag.c
|
||||
*
|
||||
* Anthony's Grep
|
||||
*
|
||||
* Public Domain 1992, 2021 by Anthony Howe. All rights released.
|
||||
*
|
||||
* Synopsis: ag <pattern> [files...]
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifndef ARRAY
|
||||
#define ARRAY 512
|
||||
#endif
|
||||
|
||||
#define EXIT_MATCH 0
|
||||
#define EXIT_NOMATCH 1
|
||||
#define EXIT_USAGE 2
|
||||
#define EXIT_ERROR 3
|
||||
|
||||
/*
|
||||
* Non-deterministic Finite-state Automaton
|
||||
*
|
||||
* An NFA is a directed graph whose nodes are called states. Each
|
||||
* state is either a labeled state denoting a literal value, or a
|
||||
* NIL state that has no label. Each state has at most two edges
|
||||
* leaving it. There is only one start state and one final state,
|
||||
* which may be the same state.
|
||||
*
|
||||
* Various state-structures can be represented by an array. These
|
||||
* structures have only one start point being the left most index,
|
||||
* and one end point being the right most index.
|
||||
*
|
||||
* a ...[a]...
|
||||
*
|
||||
* ab ...[a][b]...
|
||||
*
|
||||
* ^a [bol][a]...
|
||||
*
|
||||
* a$ ...[a][eol]
|
||||
*
|
||||
* a.b ...[a][wild][b]...
|
||||
* _
|
||||
* v \
|
||||
* a* ...[\][a][\]...
|
||||
* \____^
|
||||
*
|
||||
* a? ...[\][a]...
|
||||
* \___^
|
||||
* _______________
|
||||
* / v
|
||||
* a|b ...[\][a][/][stop][pass][b]...
|
||||
* \_____________^
|
||||
*
|
||||
* [a0-9] ...[class][a][0][1][2][3][4][5][6][7][8][9][stop]...
|
||||
*
|
||||
* [^a0-9] ...[nclass][a][0][1][2][3][4][5][6][7][8][9][stop]...
|
||||
*
|
||||
* _____________ _______________
|
||||
* / v/ v
|
||||
* a|b|c ...[\][a][/][stop][\][b][/][stop][pass][c]...
|
||||
* \_____________^\_____________^
|
||||
*
|
||||
* _ _______________
|
||||
* v \ / v
|
||||
* a*(b|c) ...[\][a][\][\][b][/][stop][pass][c]...
|
||||
* \____^ \_____________^
|
||||
*/
|
||||
|
||||
#define BOL ('\n')
|
||||
#define EOL ('\n')
|
||||
#define STOP ('\n')
|
||||
#define WILD (0)
|
||||
#define CLASS (-1)
|
||||
#define NCLASS (-2)
|
||||
#define PASS (-3)
|
||||
#define JUMP(n) (-4-(n))
|
||||
#define CHAR(c) (c)
|
||||
#define ISJUMP(x) ((x) <= PASS)
|
||||
#define ISCHAR(x) (0 <= (x))
|
||||
|
||||
/*
|
||||
* Special member that is contained in all sets. It is the location
|
||||
* of the WILD element that the pattern array is initialised with in
|
||||
* main(). Due to the way from() performs the pattern search, this
|
||||
* member is always the first member of a set and so can be used to
|
||||
* delimit sets.
|
||||
*/
|
||||
#define MEMBER 2
|
||||
|
||||
static int chr;
|
||||
static int final;
|
||||
static int nesting;
|
||||
static int array[ARRAY], next;
|
||||
|
||||
/*
|
||||
* The number of states will always be related to the number of
|
||||
* unique sets in set[], which is less-than-equal-to next_set.
|
||||
* There is no need to bounds check dfa[][] since next_set
|
||||
* is bounds checked in from() and would cause an error well in
|
||||
* advance of overflowing the total number of possible states.
|
||||
*/
|
||||
static int dfa[ARRAY][ARRAY];
|
||||
static int set[ARRAY], new_set, next_set;
|
||||
|
||||
void expr(char **);
|
||||
|
||||
/*
|
||||
* Allocate an element from the pool of free elements. The
|
||||
* global variable 'next' points to the next free element in
|
||||
* the pool. Return the allocated element's index.
|
||||
*/
|
||||
int
|
||||
new(int c)
|
||||
{
|
||||
if (ARRAY <= next) {
|
||||
fprintf(stderr, "ag: Pattern too long.\n");
|
||||
exit(EXIT_ERROR);
|
||||
}
|
||||
array[next] = c;
|
||||
return (next++);
|
||||
}
|
||||
|
||||
/*
|
||||
* literal
|
||||
* .
|
||||
* class
|
||||
* character
|
||||
* \ character
|
||||
*
|
||||
* class
|
||||
* [ ] ]
|
||||
* [ range ]
|
||||
* [ ] range ]
|
||||
* [ ^ range ]
|
||||
* [ ^ ] range ]
|
||||
*
|
||||
* range
|
||||
* -
|
||||
* character
|
||||
* range character
|
||||
* character_low - character_hi
|
||||
* range character_low - character_hi
|
||||
*/
|
||||
void
|
||||
literal(char **p)
|
||||
{
|
||||
int i, j;
|
||||
if (**p == '.') {
|
||||
new(WILD);
|
||||
} else if (**p == '[') {
|
||||
++*p;
|
||||
i = new(CLASS);
|
||||
if (**p == '^') {
|
||||
++*p;
|
||||
array[i] = NCLASS;
|
||||
}
|
||||
if (**p == ']') {
|
||||
++*p;
|
||||
new(CHAR(']'));
|
||||
}
|
||||
while ((i = **p) != ']') {
|
||||
if ((*p)[1] == '-' && i < (j = (*p)[2])) {
|
||||
while (i <= j)
|
||||
new(CHAR(i++));
|
||||
*p += 3;
|
||||
} else {
|
||||
new(CHAR(i));
|
||||
++*p;
|
||||
}
|
||||
}
|
||||
new(STOP);
|
||||
} else {
|
||||
if (**p == '\\')
|
||||
++*p;
|
||||
new(CHAR(**p));
|
||||
}
|
||||
++*p;
|
||||
}
|
||||
|
||||
/*
|
||||
* factor
|
||||
* ^
|
||||
* $
|
||||
* literal
|
||||
* ( expr )
|
||||
* factor *
|
||||
*/
|
||||
void
|
||||
factor(char **p)
|
||||
{
|
||||
int i = new(PASS);
|
||||
if (**p == '^') {
|
||||
++*p;
|
||||
new(BOL);
|
||||
} else if (**p == '$') {
|
||||
++*p;
|
||||
new(EOL);
|
||||
} else if (**p == '(') {
|
||||
++*p;
|
||||
++nesting;
|
||||
expr(p);
|
||||
if (**p != ')') {
|
||||
fprintf(stderr, "ag: Missing ')'.\n");
|
||||
exit(EXIT_ERROR);
|
||||
}
|
||||
--nesting;
|
||||
++*p;
|
||||
} else {
|
||||
literal(p);
|
||||
}
|
||||
if (**p == '*') {
|
||||
++*p;
|
||||
array[i] = JUMP(next);
|
||||
new(JUMP(i+1));
|
||||
} else if (**p == '?') {
|
||||
++*p;
|
||||
array[i] = JUMP(next);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* term
|
||||
* factor
|
||||
* term factor
|
||||
*/
|
||||
void
|
||||
term(char **p)
|
||||
{
|
||||
while (**p != '|' && (0 == nesting || **p != ')') && **p != '\0')
|
||||
factor(p);
|
||||
}
|
||||
|
||||
/*
|
||||
* expr
|
||||
* term
|
||||
* expr | term
|
||||
*/
|
||||
void
|
||||
expr(char **p)
|
||||
{
|
||||
int i, j;
|
||||
i = new(PASS);
|
||||
term(p);
|
||||
while (**p == '|') {
|
||||
++*p;
|
||||
j = new(PASS);
|
||||
new(STOP);
|
||||
array[i] = JUMP(next);
|
||||
i = new(PASS);
|
||||
term(p);
|
||||
array[j] = JUMP(next);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If element pointed to by 'p' is CLASS, return true if 'c' is in
|
||||
* the class. If the element is NCLASS, return true if 'c' is not
|
||||
* in the class. Pass back the end of the character class in 'p'.
|
||||
*/
|
||||
int
|
||||
inclass(int *p)
|
||||
{
|
||||
int i = 0, j = 0;
|
||||
if (array[*p] == CLASS || (j = array[*p] == NCLASS)) {
|
||||
while (array[++*p] != STOP)
|
||||
if (array[*p] == CHAR(chr))
|
||||
i = 1;
|
||||
}
|
||||
return (i ^ j);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return true if the end point (final state) can be reached
|
||||
* from element 'p' without crossing any labeled elements.
|
||||
*/
|
||||
int
|
||||
isfinal(int p)
|
||||
{
|
||||
return (
|
||||
final || p == next || (
|
||||
ISJUMP(array[p]) && (
|
||||
(array[p] != PASS && isfinal(JUMP(array[p])))
|
||||
|| isfinal(p+1)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find all labeled elements reachable from element 'p' and add to
|
||||
* the global set 'new_set' those that are labeled with global 'chr'.
|
||||
* 'final' is true if the final state can be reached.
|
||||
*/
|
||||
void
|
||||
from(int p)
|
||||
{
|
||||
int i = new_set;
|
||||
if (next <= p)
|
||||
return;
|
||||
if (ISJUMP(array[p])) {
|
||||
if (array[p] != PASS)
|
||||
from(JUMP(array[p]));
|
||||
from(p+1);
|
||||
} else if (WILD == array[p] || array[p] == CHAR(chr) || inclass(&p)) {
|
||||
/* If element 'p' already a member of set 't' then return. */
|
||||
while (i < next_set)
|
||||
if (set[i++] == p)
|
||||
return;
|
||||
/* Can we reach the final state from here? */
|
||||
final = isfinal(p+1);
|
||||
|
||||
if (ARRAY <= next_set) {
|
||||
fprintf(stderr, "ag: Out of space.\n");
|
||||
exit(EXIT_ERROR);
|
||||
}
|
||||
/* Add element 'p' to set 't'. */
|
||||
set[next_set++] = p;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Return true if the given string matches. The search string must
|
||||
* be of the form "\ntext\n\0" in order to handle line anchoring.
|
||||
*/
|
||||
int
|
||||
match(char *p)
|
||||
{
|
||||
int state, i, j, k;
|
||||
final = state = 0;
|
||||
while (*p != '\0' && 0 <= state) {
|
||||
if (0 < (i = dfa[state][*p])) {
|
||||
/* Transition on known DFA state. */
|
||||
state = i;
|
||||
} else {
|
||||
/* Perform lazy DFA evaluation from NFA.
|
||||
*
|
||||
* Compute new_set, which represents a transition
|
||||
* from the current state's set on character *p.
|
||||
* dfa[state]['\0'] contains the set[] index for
|
||||
* the current state.
|
||||
*/
|
||||
chr = *p;
|
||||
i = dfa[state]['\0'];
|
||||
j = new_set = next_set;
|
||||
do
|
||||
from(set[i++]+1);
|
||||
while (set[i] != MEMBER);
|
||||
|
||||
/* Determine if this is a known set or not. */
|
||||
i = k = 0;
|
||||
while (i < new_set) {
|
||||
if (set[i] == MEMBER) {
|
||||
j = new_set;
|
||||
++k;
|
||||
}
|
||||
if (set[i++] == set[j]) {
|
||||
if (next_set <= ++j) {
|
||||
j = new_set;
|
||||
if (set[i] == MEMBER) {
|
||||
/* Known set found. */
|
||||
next_set = new_set;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
j = new_set;
|
||||
}
|
||||
}
|
||||
if (new_set < next_set)
|
||||
/* New set found. */
|
||||
dfa[++k]['\0'] = new_set;
|
||||
state = dfa[state][*p] = final ? -1 : k;
|
||||
}
|
||||
++p;
|
||||
}
|
||||
return (state < 0);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int error;
|
||||
FILE *file;
|
||||
char *name, line[BUFSIZ+1];
|
||||
|
||||
if (--argc < 1) {
|
||||
fprintf(stderr, "usage: ag <pattern> [files...]\n");
|
||||
return (EXIT_USAGE);
|
||||
}
|
||||
|
||||
/* Initialise array[] = [pass][3][wild][1]... */
|
||||
new(PASS);
|
||||
new(JUMP(next+2));
|
||||
new(WILD);
|
||||
new(JUMP(next-1));
|
||||
|
||||
expr(&(*++argv));
|
||||
|
||||
*line = BOL;
|
||||
next_set = 1;
|
||||
error = EXIT_NOMATCH;
|
||||
do {
|
||||
name = "-";
|
||||
file = stdin;
|
||||
if (1 < argc && **++argv != '-') {
|
||||
if (NULL == (file = fopen(name = *argv, "r"))) {
|
||||
fprintf(stderr,
|
||||
"ag: Failed to open '%s'.\n", name);
|
||||
error = EXIT_ERROR;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
while (fgets(line+1, BUFSIZ, file) != NULL) {
|
||||
if (match(line)) {
|
||||
printf("%s:%s", name, line+1);
|
||||
error = EXIT_MATCH;
|
||||
}
|
||||
}
|
||||
fclose(file);
|
||||
} while (1 < --argc);
|
||||
return (error);
|
||||
}
|
||||
@@ -0,0 +1,449 @@
|
||||
/*
|
||||
* ag.c
|
||||
*
|
||||
* Anthony's Grep
|
||||
*
|
||||
* Public Domain 1992, 1993 by Anthony Howe. All rights released.
|
||||
*
|
||||
* Synopsis: ag <pattern> [files...]
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifndef ARRAY
|
||||
#define ARRAY 512
|
||||
#endif
|
||||
|
||||
#define EXIT_MATCH 0
|
||||
#define EXIT_NOMATCH 1
|
||||
#define EXIT_USAGE 2
|
||||
#define EXIT_ERROR 3
|
||||
|
||||
/*
|
||||
* Non-deterministic Finite-state Automaton
|
||||
*
|
||||
* An NFA is a directed graph whose nodes are called states. Each
|
||||
* state is either a labeled state denoting a literal value, or a
|
||||
* NIL state that has no label. Each state has at most two edges
|
||||
* leaving it. There is only one start state and one final state,
|
||||
* which may be the same state.
|
||||
*
|
||||
* Various state-structures can be represented by an array. These
|
||||
* structures have only one start point being the left most index,
|
||||
* and one end point being the right most index.
|
||||
*
|
||||
* a ...[a]...
|
||||
*
|
||||
* ab ...[a][b]...
|
||||
*
|
||||
* ^a [bol][a]...
|
||||
*
|
||||
* a$ ...[a][eol]
|
||||
*
|
||||
* a.b ...[a][wild][b]...
|
||||
* _
|
||||
* v \
|
||||
* a* ...[\][a][\]...
|
||||
* \____^
|
||||
*
|
||||
* a? ...[\][a]...
|
||||
* \___^
|
||||
* _______________
|
||||
* / v
|
||||
* a|b ...[\][a][/][stop][pass][b]...
|
||||
* \_____________^
|
||||
*
|
||||
* [a0-9] ...[class][a][0][1][2][3][4][5][6][7][8][9][stop]...
|
||||
*
|
||||
* [^a0-9] ...[nclass][a][0][1][2][3][4][5][6][7][8][9][stop]...
|
||||
*
|
||||
* _____________ _______________
|
||||
* / v/ v
|
||||
* a|b|c ...[\][a][/][stop][\][b][/][stop][pass][c]...
|
||||
* \_____________^\_____________^
|
||||
*
|
||||
* _ _______________
|
||||
* v \ / v
|
||||
* a*(b|c) ...[\][a][\][\][b][/][stop][pass][c]...
|
||||
* \____^ \_____________^
|
||||
*/
|
||||
|
||||
#define BOL ('\n')
|
||||
#define EOL ('\n')
|
||||
#define STOP ('\n')
|
||||
#define WILD (0)
|
||||
#define CLASS (-1)
|
||||
#define NCLASS (-2)
|
||||
#define PASS (-3)
|
||||
#define JUMP(n) (-4-(n))
|
||||
#define CHAR(c) (c)
|
||||
#define ISJUMP(x) ((x) <= PASS)
|
||||
#define ISCHAR(x) (0 <= (x))
|
||||
|
||||
/*
|
||||
* Special member that is contained in all sets. It is the location
|
||||
* of the WILD element that the pattern array is initialised with in
|
||||
* main(). Due to the way from() performs the pattern search, this
|
||||
* member is always the first member of a set and so can be used to
|
||||
* delimit sets.
|
||||
*/
|
||||
#define MEMBER 2
|
||||
|
||||
typedef int I;
|
||||
typedef char C;
|
||||
typedef void V;
|
||||
|
||||
I chr;
|
||||
I final;
|
||||
I nesting;
|
||||
I array[ARRAY], next;
|
||||
|
||||
/*
|
||||
* The number of states will always be related to the number of
|
||||
* unique sets in set[], which is less-than-equal-to next_set.
|
||||
* There is no need to bounds check dfa[][] since next_set
|
||||
* is bounds checked in from() and would cause an error well in
|
||||
* advance of overflowing the total number of possible states.
|
||||
*/
|
||||
I dfa[ARRAY][ARRAY];
|
||||
I set[ARRAY], new_set, next_set;
|
||||
|
||||
I new();
|
||||
I match();
|
||||
I inclass();
|
||||
I isfinal();
|
||||
V expr();
|
||||
V term();
|
||||
V factor();
|
||||
V literal();
|
||||
V from();
|
||||
|
||||
I
|
||||
main(argc, argv)
|
||||
I argc;
|
||||
C **argv;
|
||||
{
|
||||
I error;
|
||||
FILE *file;
|
||||
C *name, line[BUFSIZ+1];
|
||||
|
||||
if (--argc < 1) {
|
||||
fprintf(stderr, "usage: ag <pattern> [files...]\n");
|
||||
return (EXIT_USAGE);
|
||||
}
|
||||
|
||||
/* Initialise array[] = [pass][3][wild][1]... */
|
||||
new(PASS);
|
||||
new(JUMP(next+2));
|
||||
new(WILD);
|
||||
new(JUMP(next-1));
|
||||
|
||||
expr(&(*++argv));
|
||||
|
||||
*line = BOL;
|
||||
next_set = 1;
|
||||
error = EXIT_NOMATCH;
|
||||
do {
|
||||
name = "-";
|
||||
file = stdin;
|
||||
if (1 < argc && **++argv != '-') {
|
||||
if (NULL == (file = fopen(name = *argv, "r"))) {
|
||||
fprintf(stderr,
|
||||
"ag: Failed to open '%s'.\n", name);
|
||||
error = EXIT_ERROR;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
while (fgets(line+1, BUFSIZ, file) != NULL) {
|
||||
if (match(line)) {
|
||||
printf("%s:%s", name, line+1);
|
||||
error = EXIT_MATCH;
|
||||
}
|
||||
}
|
||||
fclose(file);
|
||||
} while (1 < --argc);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* expr
|
||||
* term
|
||||
* expr | term
|
||||
*/
|
||||
V
|
||||
expr(p)
|
||||
C **p;
|
||||
{
|
||||
I i, j;
|
||||
i = new(PASS);
|
||||
term(p);
|
||||
while (**p == '|') {
|
||||
++*p;
|
||||
j = new(PASS);
|
||||
new(STOP);
|
||||
array[i] = JUMP(next);
|
||||
i = new(PASS);
|
||||
term(p);
|
||||
array[j] = JUMP(next);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* term
|
||||
* factor
|
||||
* term factor
|
||||
*/
|
||||
V
|
||||
term(p)
|
||||
C **p;
|
||||
{
|
||||
while (**p != '|' && (0 == nesting || **p != ')') && **p != '\0')
|
||||
factor(p);
|
||||
}
|
||||
|
||||
/*
|
||||
* factor
|
||||
* ^
|
||||
* $
|
||||
* literal
|
||||
* ( expr )
|
||||
* factor *
|
||||
*/
|
||||
V
|
||||
factor(p)
|
||||
C **p;
|
||||
{
|
||||
I i = new(PASS);
|
||||
if (**p == '^') {
|
||||
++*p;
|
||||
new(BOL);
|
||||
} else if (**p == '$') {
|
||||
++*p;
|
||||
new(EOL);
|
||||
} else if (**p == '(') {
|
||||
++*p;
|
||||
++nesting;
|
||||
expr(p);
|
||||
if (**p != ')') {
|
||||
fprintf(stderr, "ag: Missing ')'.\n");
|
||||
exit(EXIT_ERROR);
|
||||
}
|
||||
--nesting;
|
||||
++*p;
|
||||
} else {
|
||||
literal(p);
|
||||
}
|
||||
if (**p == '*') {
|
||||
++*p;
|
||||
array[i] = JUMP(next);
|
||||
new(JUMP(i+1));
|
||||
} else if (**p == '?') {
|
||||
++*p;
|
||||
array[i] = JUMP(next);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* literal
|
||||
* .
|
||||
* class
|
||||
* character
|
||||
* \ character
|
||||
*
|
||||
* class
|
||||
* [ ] ]
|
||||
* [ range ]
|
||||
* [ ] range ]
|
||||
* [ ^ range ]
|
||||
* [ ^ ] range ]
|
||||
*
|
||||
* range
|
||||
* -
|
||||
* character
|
||||
* range character
|
||||
* character_low - character_hi
|
||||
* range character_low - character_hi
|
||||
*/
|
||||
V
|
||||
literal(p)
|
||||
C **p;
|
||||
{
|
||||
I i, j;
|
||||
if (**p == '.') {
|
||||
new(WILD);
|
||||
} else if (**p == '[') {
|
||||
++*p;
|
||||
i = new(CLASS);
|
||||
if (**p == '^') {
|
||||
++*p;
|
||||
array[i] = NCLASS;
|
||||
}
|
||||
if (**p == ']') {
|
||||
++*p;
|
||||
new(CHAR(']'));
|
||||
}
|
||||
while ((i = **p) != ']') {
|
||||
if ((*p)[1] == '-' && i < (j = (*p)[2])) {
|
||||
while (i <= j)
|
||||
new(CHAR(i++));
|
||||
*p += 3;
|
||||
} else {
|
||||
new(CHAR(i));
|
||||
++*p;
|
||||
}
|
||||
}
|
||||
new(STOP);
|
||||
} else {
|
||||
if (**p == '\\')
|
||||
++*p;
|
||||
new(CHAR(**p));
|
||||
}
|
||||
++*p;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate an element from the pool of free elements. The
|
||||
* global variable 'next' points to the next free element in
|
||||
* the pool. Return the allocated element's index.
|
||||
*/
|
||||
I
|
||||
new(c)
|
||||
I c;
|
||||
{
|
||||
if (ARRAY <= next) {
|
||||
fprintf(stderr, "ag: Pattern too long.\n");
|
||||
exit(EXIT_ERROR);
|
||||
}
|
||||
array[next] = c;
|
||||
return (next++);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find all labeled elements reachable from element 'p' and add to
|
||||
* the global set 'new_set' those that are labeled with global 'chr'.
|
||||
* 'final' is true if the final state can be reached.
|
||||
*/
|
||||
V
|
||||
from(p)
|
||||
I p;
|
||||
{
|
||||
I i = new_set;
|
||||
if (next <= p)
|
||||
return;
|
||||
if (ISJUMP(array[p])) {
|
||||
if (array[p] != PASS)
|
||||
from(JUMP(array[p]));
|
||||
from(p+1);
|
||||
} else if (WILD == array[p] || array[p] == CHAR(chr) || inclass(&p)) {
|
||||
/* If element 'p' already a member of set 't' then return. */
|
||||
while (i < next_set)
|
||||
if (set[i++] == p)
|
||||
return;
|
||||
/* Can we reach the final state from here? */
|
||||
final = isfinal(p+1);
|
||||
|
||||
if (ARRAY <= next_set) {
|
||||
fprintf(stderr, "ag: Out of space.\n");
|
||||
exit(EXIT_ERROR);
|
||||
}
|
||||
/* Add element 'p' to set 't'. */
|
||||
set[next_set++] = p;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If element pointed to by 'p' is CLASS, return true if 'c' is in
|
||||
* the class. If the element is NCLASS, return true if 'c' is not
|
||||
* in the class. Pass back the end of the character class in 'p'.
|
||||
*/
|
||||
I
|
||||
inclass(p)
|
||||
I *p;
|
||||
{
|
||||
I i = 0, j = 0;
|
||||
if (array[*p] == CLASS || (j = array[*p] == NCLASS)) {
|
||||
while (array[++*p] != STOP)
|
||||
if (array[*p] == CHAR(chr))
|
||||
i = 1;
|
||||
}
|
||||
return (i ^ j);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return true if the end point (final state) can be reached
|
||||
* from element 'p' without crossing any labeled elements.
|
||||
*/
|
||||
I
|
||||
isfinal(p)
|
||||
I p;
|
||||
{
|
||||
return (
|
||||
final || p == next || (
|
||||
ISJUMP(array[p]) && (
|
||||
(array[p] != PASS && isfinal(JUMP(array[p])))
|
||||
|| isfinal(p+1)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return true if the given string matches. The search string must
|
||||
* be of the form "\ntext\n\0" in order to handle line anchoring.
|
||||
*/
|
||||
I
|
||||
match(p)
|
||||
C *p;
|
||||
{
|
||||
I state, i, j, k;
|
||||
final = state = 0;
|
||||
while (*p != '\0' && 0 <= state) {
|
||||
if (0 < (i = dfa[state][*p])) {
|
||||
/* Transition on known DFA state. */
|
||||
state = i;
|
||||
} else {
|
||||
/* Perform lazy DFA evaluation from NFA.
|
||||
*
|
||||
* Compute new_set, which represents a transition
|
||||
* from the current state's set on character *p.
|
||||
* dfa[state]['\0'] contains the set[] index for
|
||||
* the current state.
|
||||
*/
|
||||
chr = *p;
|
||||
i = dfa[state]['\0'];
|
||||
j = new_set = next_set;
|
||||
do
|
||||
from(set[i++]+1);
|
||||
while (set[i] != MEMBER);
|
||||
|
||||
/* Determine if this is a known set or not. */
|
||||
i = k = 0;
|
||||
while (i < new_set) {
|
||||
if (set[i] == MEMBER) {
|
||||
j = new_set;
|
||||
++k;
|
||||
}
|
||||
if (set[i++] == set[j]) {
|
||||
if (next_set <= ++j) {
|
||||
j = new_set;
|
||||
if (set[i] == MEMBER) {
|
||||
/* Known set found. */
|
||||
next_set = new_set;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
j = new_set;
|
||||
}
|
||||
}
|
||||
if (new_set < next_set)
|
||||
/* New set found. */
|
||||
dfa[++k]['\0'] = new_set;
|
||||
state = dfa[state][*p] = final ? -1 : k;
|
||||
}
|
||||
++p;
|
||||
}
|
||||
return (state < 0);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,233 @@
|
||||
#
|
||||
# Test Driver for Anthony's Grep
|
||||
#
|
||||
# Public Domain 1992, 1993 by Anthony Howe. No warranty.
|
||||
#
|
||||
|
||||
SHELL = /bin/sh
|
||||
|
||||
all: char word anchor literal wild closure option branch sub class
|
||||
|
||||
#
|
||||
# Test simple text patterns without the use of meta characters.
|
||||
#
|
||||
|
||||
empty:
|
||||
$(PRG) '' test.mk
|
||||
|
||||
char:
|
||||
$(PRG) 'q' test.mk
|
||||
|
||||
word:
|
||||
$(PRG) 'simple' test.mk
|
||||
|
||||
#
|
||||
# Test meta characters.
|
||||
#
|
||||
|
||||
anchor: anchor1 anchor2 anchor3 anchor4 anchor5
|
||||
|
||||
anchor1:
|
||||
$(PRG) '^anchor1' test.mk
|
||||
|
||||
anchor2:
|
||||
$(PRG) 'Grep$$' test.mk
|
||||
|
||||
#
|
||||
# Find all empty lines.
|
||||
#
|
||||
anchor3:
|
||||
$(PRG) '^$$' test.mk
|
||||
|
||||
#
|
||||
# This is valid but will never match.
|
||||
#
|
||||
anchor4:
|
||||
-$(PRG) 'x^a' test.mk
|
||||
|
||||
#
|
||||
# This is valid but will never match.
|
||||
#
|
||||
anchor5:
|
||||
-$(PRG) 'mk$$x' test.mk
|
||||
|
||||
literal: literal1 literal2
|
||||
|
||||
#
|
||||
# Every line with a dollar-sign.
|
||||
#
|
||||
literal1:
|
||||
$(PRG) '\$$' test.mk
|
||||
|
||||
#
|
||||
# Every line with a backslash.
|
||||
#
|
||||
literal2:
|
||||
$(PRG) '\\' test.mk
|
||||
|
||||
#
|
||||
# wild #1#
|
||||
# wild #a#
|
||||
# wild #%#
|
||||
#
|
||||
wild:
|
||||
$(PRG) '#.#' test.mk
|
||||
|
||||
#
|
||||
# closure !!
|
||||
# closure !x!
|
||||
# closure !xxxxxx!
|
||||
#
|
||||
closure:
|
||||
$(PRG) 'closure !x*!' test.mk
|
||||
|
||||
#
|
||||
# option ++
|
||||
# option +a+
|
||||
# option +b+
|
||||
# option +c+
|
||||
# option +abc+
|
||||
#
|
||||
option: option1 option2
|
||||
|
||||
option1:
|
||||
$(PRG) '+b?+' test.mk
|
||||
|
||||
option2:
|
||||
$(PRG) '+.?+' test.mk
|
||||
|
||||
branch: branch1 branch2 branch3 branch4 branch5 branch6
|
||||
|
||||
branch1:
|
||||
$(PRG) 'q|simple' test.mk
|
||||
|
||||
#
|
||||
# This pattern should be the same as '(^all)|(Public)|(Grep$)'.
|
||||
#
|
||||
branch2:
|
||||
$(PRG) '^all|Public|Grep$$' test.mk
|
||||
|
||||
#
|
||||
# This pattern should generate the same results as branch2.
|
||||
#
|
||||
branch3:
|
||||
$(PRG) 'Grep$|^all|Public' test.mk
|
||||
|
||||
#
|
||||
# Null expression between start of pattern and vertical-line.
|
||||
#
|
||||
branch4:
|
||||
$(PRG) '|Grep' test.mk
|
||||
|
||||
#
|
||||
# Null expression between vertical-line and end of pattern.
|
||||
#
|
||||
branch5:
|
||||
$(PRG) 'Grep|' test.mk
|
||||
|
||||
#
|
||||
# Null expression between vertical-line and vertical-line.
|
||||
#
|
||||
branch6:
|
||||
$(PRG) 'all||Grep' test.mk
|
||||
|
||||
#
|
||||
# sub aabcbcbcxx
|
||||
# sub aagxx
|
||||
# sub aaggxx
|
||||
# sub aadddxx
|
||||
# sub aaxx
|
||||
#
|
||||
sub: sub0 sub1 sub2 sub3 sub4 sub5 lparen1 lparen2 rparen1 rparen2
|
||||
|
||||
#
|
||||
# Null sub-expressions.
|
||||
#
|
||||
sub0:
|
||||
$(PRG) 's()u()b()' test.mk
|
||||
|
||||
sub1:
|
||||
$(PRG) '#(1|%)#' test.mk
|
||||
|
||||
sub2:
|
||||
$(PRG) 'aa((bc)*|g)xx' test.mk
|
||||
|
||||
#
|
||||
# Null expression between the left-parenthesis and the vertical-line.
|
||||
#
|
||||
sub3:
|
||||
$(PRG) '#(|1)#' test.mk
|
||||
|
||||
#
|
||||
# Null expression between the vertical-line and the right-parenthesis.
|
||||
#
|
||||
sub4:
|
||||
$(PRG) '#(1|)#' test.mk
|
||||
|
||||
#
|
||||
# Null expression between the vertical-line and the right-parenthesis.
|
||||
#
|
||||
sub5:
|
||||
$(PRG) '#(%||1)#' test.mk
|
||||
|
||||
#
|
||||
# Missing left-parenthesis generates an error.
|
||||
#
|
||||
lparen1:
|
||||
-$(PRG) 'left ( only' test.mk
|
||||
|
||||
lparen2:
|
||||
$(PRG) 'left \( only' test.mk
|
||||
|
||||
#
|
||||
# Right-parenthesis without preceding left parenthesis should be a literal.
|
||||
#
|
||||
rparen1:
|
||||
-$(PRG) 'right ) only' test.mk
|
||||
|
||||
rparen2:
|
||||
$(PRG) 'right \) only' test.mk
|
||||
|
||||
#
|
||||
# 12345678
|
||||
# -----------------
|
||||
# =0= 1 45
|
||||
# =1= 2 45 78
|
||||
# =2= 2 45
|
||||
# =3= 2 45 78
|
||||
# =4= 2 45
|
||||
# =5= 2 45
|
||||
# =6= 2 45
|
||||
# =7= 2 45
|
||||
# =8= 2 45
|
||||
# =9= 1 45
|
||||
# =]= 23 6
|
||||
# =-= 2 4 678
|
||||
# = = 2 4 6
|
||||
#
|
||||
class: class1 class2 class3 class4 class5 class6 class7 class8
|
||||
|
||||
class1:
|
||||
$(PRG) '=[09]=' test.mk
|
||||
|
||||
class2:
|
||||
$(PRG) '=[^09]=' test.mk
|
||||
|
||||
class3:
|
||||
$(PRG) '=[]]=' test.mk
|
||||
|
||||
class4:
|
||||
$(PRG) '=[^]]=' test.mk
|
||||
|
||||
class5:
|
||||
$(PRG) '=[0-9]=' test.mk
|
||||
|
||||
class6:
|
||||
$(PRG) '=[^0-9]=' test.mk
|
||||
|
||||
class7:
|
||||
-$(PRG) '=[3-1]=' test.mk
|
||||
|
||||
class8:
|
||||
$(PRG) '=[-13]=' test.mk
|
||||
|
||||
@@ -403,6 +403,8 @@ Location: <a href="../../location.html#CA">CA</a> - <em>Canada</em></li>
|
||||
<!-- BEFORE: 1st line of markdown file: 1993/ant/README.md -->
|
||||
<h2 id="to-build">To build:</h2>
|
||||
<pre><code> make all</code></pre>
|
||||
<p>The author provided a deobfuscated version. See <a href="#alternate-code">Alternate
|
||||
code</a> below.</p>
|
||||
<h3 id="bugs-and-misfeatures">Bugs and (Mis)features:</h3>
|
||||
<p>The current status of this entry is:</p>
|
||||
<pre><code> STATUS: INABIAF - please DO NOT fix
|
||||
@@ -412,6 +414,17 @@ Location: <a href="../../location.html#CA">CA</a> - <em>Canada</em></li>
|
||||
<pre><code> ./ant 'ERE' [file ...]</code></pre>
|
||||
<h2 id="try">Try:</h2>
|
||||
<pre><code> ./try.sh</code></pre>
|
||||
<h2 id="alternate-code">Alternate code:</h2>
|
||||
<p>The <a href="https://github.com/ioccc-src/temp-test-ioccc/blob/master/1993/ant/deobfuscated/ant.c">ant.c in deobfuscated/</a> is a
|
||||
deobfuscated version provided by the author. You can look at this code if you
|
||||
want some clues in how it works.</p>
|
||||
<h2 id="alternate-build">Alternate build:</h2>
|
||||
<p>If you wish to build this deobfuscated version, you can do so like:</p>
|
||||
<pre><code> make alt</code></pre>
|
||||
<h2 id="alternate-use">Alternate use:</h2>
|
||||
<p>Use <code>ant.alt</code> like you would <code>ant</code> above.</p>
|
||||
<h2 id="alternate-try">Alternate try:</h2>
|
||||
<pre><code> ./try.alt.sh</code></pre>
|
||||
<h2 id="judges-remarks">Judges’ remarks:</h2>
|
||||
<p>See the author’s POSIX P1003.2-like documentation file <a href="ant.txt">ant.txt</a> for
|
||||
more information.</p>
|
||||
@@ -459,8 +472,14 @@ more information.</p>
|
||||
<li><a href="https://github.com/ioccc-src/temp-test-ioccc/blob/master/1993/ant/ant.orig.c">ant.orig.c</a> - original source code</li>
|
||||
<li><a href="ant.txt">ant.txt</a> - ag man page</li>
|
||||
<li><a href="https://github.com/ioccc-src/temp-test-ioccc/blob/master/1993/ant/try.sh">try.sh</a> - script to try entry</li>
|
||||
<li><a href="https://github.com/ioccc-src/temp-test-ioccc/blob/master/1993/ant/deobfuscated/ant-c89.c">deobfuscated/ant-c89.c</a> - author provided deobfuscated code converted from K&R</li>
|
||||
<li><a href="https://github.com/ioccc-src/temp-test-ioccc/blob/master/1993/ant/deobfuscated/ant.c">deobfuscated/ant.c</a> - author provided deobfuscated code</li>
|
||||
<li><a href="https://github.com/ioccc-src/temp-test-ioccc/blob/master/1993/ant/try.alt.sh">try.alt.sh</a> - script to try deobfuscated code</li>
|
||||
<li><a href="https://github.com/ioccc-src/temp-test-ioccc/blob/master/1993/ant/deobfuscated/Makefile">deobfuscated/Makefile</a> - author provided Makefile for deobfuscated code</li>
|
||||
<li><a href="https://github.com/ioccc-src/temp-test-ioccc/blob/master/1993/ant/deobfuscated/test.mk">deobfuscated/test.mk</a> - author provided test suite Makefile for deobfuscated code</li>
|
||||
<li><a href="ants.txt">ants.txt</a> - lyrics of the Ants Go Marching song</li>
|
||||
<li><a href="https://github.com/ioccc-src/temp-test-ioccc/blob/master/1993/ant/ant.test.mk">ant.test.mk</a> - test suite Makefile</li>
|
||||
<li><a href="https://github.com/ioccc-src/temp-test-ioccc/blob/master/1993/ant/ant.alt.test.mk">ant.alt.test.mk</a> - test suite Makefile for deobfuscated code</li>
|
||||
</ul>
|
||||
<h2 id="secondary-files">Secondary files</h2>
|
||||
<ul>
|
||||
|
||||
Executable
+41
@@ -0,0 +1,41 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# try.sh - demonstrate IOCCC entry 1993/ant alt code
|
||||
#
|
||||
|
||||
# make sure CC is set so that when we do make CC="$CC" it isn't empty. Doing it
|
||||
# this way allows us to have the user specify a different compiler in an easy
|
||||
# way.
|
||||
if [[ -z "$CC" ]]; then
|
||||
CC="cc"
|
||||
fi
|
||||
|
||||
make CC="$CC" alt >/dev/null || exit 1
|
||||
|
||||
# clear screen after compilation so that only the entry is shown
|
||||
clear
|
||||
|
||||
read -r -n 1 -p "Press any key to run: ./ant.alt ant.alt README.md: "
|
||||
echo 1>&2
|
||||
./ant.alt ant.alt README.md
|
||||
echo 1>&2
|
||||
|
||||
read -r -n 1 -p "Press any key to run: ./ant.alt '\[' ant.txt: "
|
||||
echo 1>&2
|
||||
./ant.alt '\[' ant.txt
|
||||
echo 1>&2
|
||||
|
||||
echo "Note: the next one should show: ag: Pattern too long." 1>&2
|
||||
read -r -n 1 -p "Press any key to run: ./ant.alt '[' ant.txt: "
|
||||
echo 1>&2
|
||||
./ant.alt '[' ant.txt
|
||||
echo 1>&2
|
||||
|
||||
read -r -n 1 -p "Press any key to run: ./ant.alt ant ants.txt | cut -d: -f2 (space = next page, q = quit): "
|
||||
echo 1>&2
|
||||
./ant.alt ant ants.txt | cut -d: -f2 | less -rEXF
|
||||
echo 1>&2
|
||||
|
||||
read -r -n 1 -p "Press any key to run the test suite (make -f ant.alt.test.mk): "
|
||||
echo 1>&2
|
||||
make -f ant.alt.test.mk
|
||||
+2
-2
@@ -36,6 +36,6 @@ echo 1>&2
|
||||
./ant ant ants.txt | cut -d: -f2 | less -rEXF
|
||||
echo 1>&2
|
||||
|
||||
read -r -n 1 -p "Press any key to run the test suite (make -f ant.test.mk) (space = next page, q = quit): "
|
||||
read -r -n 1 -p "Press any key to run the test suite (make -f ant.test.mk): "
|
||||
echo 1>&2
|
||||
make -f ant.test.mk | less -rEXF
|
||||
make -f ant.test.mk
|
||||
Reference in new issue
Block a user