Merge pull request #1396 from xexyl/fanf-98
This commit is contained in:
26 files changed
+623
-295
No files matched your search
@@ -0,0 +1,28 @@
|
||||
#include <ctype.h>
|
||||
#include <curses.h>
|
||||
#define T isspace(*(t=Z(p)))&&
|
||||
#define V return
|
||||
#define _ while
|
||||
int d,i,j,m,n,p,q,x,y;char*c,b[BUF],*f,*g=b,*h,k[]="hjklbJKw0$tbixWRq",*t;
|
||||
char*Z(a){if(a<0)V b;V b+a+(b+a<g?0:h-g);}P(a)char*a;{V
|
||||
a-b-(a<h?0:h-g);}S(){p=0;}bf(){n=p=P(c);}Q(){q=1;}C(){clear();Y();}
|
||||
G(){t=Z(p);_(t<g)*--h= *--g;_(h<t)*g++= *h++;p=P(h);}B(){_(!T b<t)--p;_(T
|
||||
b<t)--p;}M(a){_(b<(t=Z(--a))&&*t-'\n');V
|
||||
b<t?++a:0;}N(a){_((t=Z(a++))<c&&*t-'\n');V
|
||||
t<c?a:P(c);}A(a,j){i=0;_((t=Z(a))<c&&*t-'\n'&&i<j){i+= *t-'\t'?1:8-(i&7);++a;}V
|
||||
a;}L(){0<p&&--p;}R(){p<P(c)&&++p;}U(){p=A(M(M(p)-1),x);}
|
||||
D(){p=A(N(p),x);}H(){p=M(p);}E(){p=N(p);L();}
|
||||
J(){m=p=M(n-1);_(0<y--)D();n=P(c);}K(){j=d;_(0<--j)m=M(m-1),U();}
|
||||
I(){G();_((j=getch())-'\x1b'){if(j-'\b')g-h&&(*g++=j-'\r'?j:'\n');else
|
||||
b<g&&--g;p=P(h);Y();}}X(){G();p=h<c?P(++h):p;}
|
||||
F(){j=p;p=0;G();write(i=creat(f,MODE),h,(int)(c-h));close(i);p=j;}W(){_(!T
|
||||
t<c)++p;_(T
|
||||
t<c)++p;}int(*z[])()={L,D,U,R,B,J,K,W,H,E,S,bf,I,X,F,C,Q,G};
|
||||
Y(){m=p<m?M(p):m;if(n<=p){m=N(p);i=m-P(c)?d:d-2;_(0<i--)m=M(m-1);}
|
||||
move(0,0);i=j=0;n=m;_(1){p-n||(y=i,x=j);t=Z(n);if(d<=i||c<=t)break;
|
||||
if(*t-'\r')addch(*t),j+= *t-'\t'?1:8-(j&7);if(*t=='\n'||COLS<=j)
|
||||
++i,j=0;++n;}clrtobot();++i<d&&mvaddstr(i,0,"<< EOF >>");move(y,x);
|
||||
refresh();}main(u,v)char**v;{h=c=b+BUF;if(u<2)V
|
||||
2;initscr();d=LINES;raw();noecho();idlok(stdscr,1);if(0<(i=open(f= *++v,0))){
|
||||
g+=read(i,b,BUF);g=g<b?b:g;close(i);}S();_(!q){Y();i=0;j=getch();
|
||||
_(k[i]&&j-k[i])++i;(*z[i])();}endwin();V 0;}
|
||||
@@ -1,3 +1,4 @@
|
||||
kivinen
|
||||
kivinen.alt
|
||||
kivinen.orig
|
||||
prog.orig
|
||||
@@ -58,7 +58,7 @@ ARCH=
|
||||
|
||||
# Defines that are needed to compile
|
||||
#
|
||||
CDEFINE= -DZ=15000
|
||||
CDEFINE= -DZ=20000
|
||||
|
||||
# Include files that are needed to compile
|
||||
#
|
||||
@@ -113,8 +113,8 @@ OBJ= ${PROG}.o
|
||||
DATA=
|
||||
TARGET= ${PROG}
|
||||
#
|
||||
ALT_OBJ=
|
||||
ALT_TARGET=
|
||||
ALT_OBJ= ${PROG}.alt.o
|
||||
ALT_TARGET= ${PROG}.alt
|
||||
|
||||
|
||||
#################
|
||||
|
||||
+38
-8
@@ -3,14 +3,14 @@
|
||||
If your machine support the X Window System, Version 11:
|
||||
|
||||
```sh
|
||||
make all
|
||||
make alt
|
||||
```
|
||||
|
||||
NOTE: this entry requires `X11/Xlib.h` header file and the X11 library to
|
||||
compile. macOS users running Mountain Lion and later will need to download and
|
||||
install [XQuartz](https://www.xquartz.org) in order to compile and run this
|
||||
entry.
|
||||
We recommend the alt version first as the original goes too fast on modern
|
||||
systems. See [original code](#original-code) for the original should you wish to
|
||||
see what we mean.
|
||||
|
||||
You can reconfigure the value to `usleep(3)`; see [try](#try) section below.
|
||||
|
||||
### Bugs and (Mis)features:
|
||||
|
||||
@@ -26,15 +26,45 @@ For more detailed information see [1992 kivinen in bugs.md](/bugs.md#1992-kivine
|
||||
### Try:
|
||||
|
||||
```sh
|
||||
./kivinen
|
||||
./kivinen.alt
|
||||
|
||||
./kivinen a
|
||||
./kivinen.alt a
|
||||
|
||||
./kivinen a b
|
||||
./kivinen.alt a b
|
||||
```
|
||||
|
||||
See also the author's remarks for other variations.
|
||||
|
||||
Also try changing the speed this game moves. For instance if you wish to change
|
||||
the `usleep(3)` value to `30000` from `20000`, try:
|
||||
|
||||
```sh
|
||||
make clobber CDEFINE="-DZ=30000" alt # make it slower
|
||||
|
||||
make clobber CDEFINE="-DZ=10000" alt # make it faster
|
||||
```
|
||||
|
||||
Then use the same syntax as above and described by the author.
|
||||
|
||||
|
||||
## Original code:
|
||||
|
||||
As noted above, the alt version is recommended because the code goes too fast in
|
||||
modern systems. If you wish to see the original you may do so with the original
|
||||
code.
|
||||
|
||||
|
||||
### Original build:
|
||||
|
||||
```sh
|
||||
make all
|
||||
```
|
||||
|
||||
|
||||
### Original use:
|
||||
|
||||
Use `kivinen` as you would `kivinen.alt`.
|
||||
|
||||
|
||||
## Judges' remarks:
|
||||
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
#include <X11/Xlib.h>
|
||||
#define exit(a) (exit(a),0)
|
||||
# define X( x,v,y) XMoveWindow(d,s[x],(v)*z,(y)*z)
|
||||
# define _ ButtonPressMask|ButtonReleaseMask
|
||||
# define I( x,y) XSelectInput(d,s[x],y)
|
||||
# define N( v) (XMapWindow(d,s[v]),v)
|
||||
# define V VisibilityChangeMask
|
||||
# define A XCreateSimpleWindow
|
||||
# define D DefaultScreen(d)
|
||||
# define E r.xbutton.button
|
||||
# define R BlackPixel(d,D)
|
||||
# define S r.xvisibility
|
||||
|
||||
int main(a)int a;{Window s[53];int w,u,i,c,y,l=0
|
||||
,q,e=32,t,k,j=~0,z=(a+1)/2,x=a&1,v=z&1;XEvent r;Display*
|
||||
d=XOpenDisplay("");s[0]=A(d,DefaultRootWindow(d),200,200,(x&
|
||||
v?330:120)*z,215*z,2,R,R);I(N(c=0),_);for(;c<(x?32:52);c++){s[
|
||||
c+1]=A(d,s[0],x ?c*20*z:(c-1)%10 *12*z,x?-20*z:(
|
||||
c-1)/10*12*z,x ?z*(c^31?10: 2):z*10*(c?1:2
|
||||
), x& v?z*10: (c &&!x?10:1+ x) *z,k =q=1, R,
|
||||
WhitePixel(d ,D));I (N(c+1), V);}X( N(1),y=(x&v)
|
||||
*115+50,x*70+ 60 ); X(N(c-- )+ 1,x?-10:(i=y)
|
||||
,u=!x*130-20); while(c &&e< 160){if(x){if(
|
||||
v){l=!(e &32)*9; for(w=30; w--;){ if(s[w+2]){ k=w%
|
||||
10;l=e&32?k>l?k:l:k<l?k:l;X(w+2,10+k *20+q,(w/10)*20+e);}}l*=20;
|
||||
e&31?e++:e&32?(q++,(q+l>300?e++:0)):(q--,q+l<10?e++:0); } u>140?
|
||||
exit(c):u>-20?X(32,i,u-=(v?5:-1 )):(!v?(u =5,srandom(time(0)),i=
|
||||
random()%88+6):0); } else{k>0?i+=(i>105?k= -k:k):(i+=(i<1?k= -k:
|
||||
k)); j>0?u +=(u>140?exit(++c):j):(u+=(u <1?j= -j:j
|
||||
)); X( 52,i,u);}XSync(d,0); while(
|
||||
XCheckMaskEvent(d ,_|V,&r))if(!(r. type==ButtonPress
|
||||
?(E&1||!x||!v?t=E*4-8 :u<0?i=y+4,u=122:1):r
|
||||
.type==ButtonRelease&&E?t=0,1:r.type^VisibilityNotify|S.state^1)
|
||||
)for(x&v?(u= -15),w++:(w=0);++w <52-x*20;)if
|
||||
(s[w] ==S.window)x&&v|| w ^1?
|
||||
XUnmapWindow (d,s[w]) ,s[w]=0,c--:
|
||||
0,l=1; if(!x&&l)j= -j,l=0; if(l&x&&!v
|
||||
)u=~19,c--,l=0;t=(!x||!v) &&(y<5&&t<0||y>95&&t>0)?0:t
|
||||
;s[1]?X(1,y+=x&v?t:t/(x+1),130):exit(++c);usleep(Z);};return c;}
|
||||
@@ -1,5 +1,5 @@
|
||||
#include <X11/Xlib.h>
|
||||
#define ext(a) (exit(a),0)
|
||||
#define exit(a) (exit(a),0)
|
||||
# define X( x,v,y) XMoveWindow(d,s[x],(v)*z,(y)*z)
|
||||
# define _ ButtonPressMask|ButtonReleaseMask
|
||||
# define I( x,y) XSelectInput(d,s[x],y)
|
||||
@@ -24,9 +24,9 @@
|
||||
v){l=!(e &32)*9; for(w=30; w--;){ if(s[w+2]){ k=w%
|
||||
10;l=e&32?k>l?k:l:k<l?k:l;X(w+2,10+k *20+q,(w/10)*20+e);}}l*=20;
|
||||
e&31?e++:e&32?(q++,(q+l>300?e++:0)):(q--,q+l<10?e++:0); } u>140?
|
||||
ext(c):u>-20?X(32,i,u-=(v?5:-1 )) :(!v?(u =5,srandom(time(0)),i=
|
||||
exit(c):u>-20?X(32,i,u-=(v?5:-1 )):(!v?(u =5,srandom(time(0)),i=
|
||||
random()%88+6):0); } else{k>0?i+=(i>105?k= -k:k):(i+=(i<1?k= -k:
|
||||
k)); j>0?u +=(u>140?ext(++c):j):(u+=(u <1?j= -j:j
|
||||
k)); j>0?u +=(u>140?exit(++c):j):(u+=(u <1?j= -j:j
|
||||
)); X( 52,i,u);}XSync(d,0); while(
|
||||
XCheckMaskEvent(d ,_|V,&r))if(!(r. type==ButtonPress
|
||||
?(E&1||!x||!v?t=E*4-8 :u<0?i=y+4,u=122:1):r
|
||||
@@ -36,4 +36,4 @@
|
||||
XUnmapWindow (d,s[w]) ,s[w]=0,c--:
|
||||
0,l=1; if(!x&&l)j= -j,l=0; if(l&x&&!v
|
||||
)u=~19,c--,l=0;t=(!x||!v) &&(y<5&&t<0||y>95&&t>0)?0
|
||||
:t;s[1]?X(1,y+=x&v?t:t/(x+1),130):ext(++c);usleep(Z);};return(c);}
|
||||
:t;s[1]?X(1,y+=x&v?t:t/(x+1),130):exit(++c);};return(c);}
|
||||
@@ -1,5 +1,7 @@
|
||||
fanf
|
||||
fanftmp1.c
|
||||
fanftmp1
|
||||
fanftmp2.c
|
||||
fanftmp2
|
||||
fanf.orig
|
||||
prog.orig
|
||||
+4
-2
@@ -130,8 +130,10 @@ all: data ${TARGET}
|
||||
sandwich supernova deep_magic magic charon pluto
|
||||
|
||||
${PROG}: ${PROG}.c
|
||||
@echo "This next step may take some time to complete:"
|
||||
${CC} ${CFLAGS} ${PROG}.c ${LDFLAGS} -o $@
|
||||
@echo "This may take some time to complete:"
|
||||
${CC} ${PROG}.c -E > ${PROG}tmp1.c
|
||||
${CC} ${PROG}tmp1.c -E > ${PROG}tmp2.c
|
||||
${CC} ${CFLAGS} ${PROG}tmp2.c ${LDFLAGS} -o $@
|
||||
|
||||
# alternative executable
|
||||
#
|
||||
|
||||
+46
-51
@@ -4,7 +4,7 @@
|
||||
make all
|
||||
```
|
||||
|
||||
NOTE: This may take a while. Some systems may have problems building\
|
||||
NOTE: this may take a while. Some systems may have problems building
|
||||
this entry because of the system resources it requires.
|
||||
|
||||
|
||||
@@ -15,36 +15,26 @@ this entry because of the system resources it requires.
|
||||
```
|
||||
|
||||
|
||||
### To use:
|
||||
### Try:
|
||||
|
||||
Enter an expression on standard input. Here are some
|
||||
sample expressions that you can use:
|
||||
Enter an expression on standard input. To try some we have selected:
|
||||
|
||||
```
|
||||
((\a(\b(\c(d)))) e)
|
||||
|
||||
|
||||
(\f\g\x
|
||||
(
|
||||
(g x) (f x)
|
||||
) K K z
|
||||
)
|
||||
|
||||
|
||||
(\f(\f\g\x( (f((\a(g(b))) e)) (g x) ) K K z))
|
||||
|
||||
|
||||
(Y\f\n
|
||||
((= n 0)
|
||||
1
|
||||
(* n (f (- n 1)))
|
||||
)
|
||||
)
|
||||
```sh
|
||||
./try.sh
|
||||
```
|
||||
|
||||
|
||||
## Judges' remarks:
|
||||
|
||||
|
||||
### Historical aside:
|
||||
|
||||
At a time the code in [fanf.c](fanf.c) was that of [fanf.orig.c](fanf.orig.c)
|
||||
but to get this to compile in modern systems it had to be translated to what you
|
||||
now see. The intermediate steps can still be performed but they might be
|
||||
different from the past. This should be kept in mind as you read the below
|
||||
remarks.
|
||||
|
||||
This program translates lambda expressions into combinator
|
||||
expressions. But you do not need to know Lambda Calculus to be
|
||||
impressed by this program!
|
||||
@@ -56,20 +46,21 @@ Notice how large the code grows from the [fanf.c](fanf.c) into the final
|
||||
`fanftmp2.c` C program. Take a look at that final C program again,
|
||||
can you begin to understand what it is doing?
|
||||
|
||||
Look at the first stage of the C pre-processing:
|
||||
Look at the first stage of the C pre-processing which was done like:
|
||||
|
||||
```sh
|
||||
cc fanf.c -E > fanftmp1.c
|
||||
```
|
||||
|
||||
Skip to the bottom of `fanftmp1.c` (after all of the `#include` header
|
||||
stuff ... look for a line of the form: `# 2 "fanf.c"` near the bottom)
|
||||
Skip to the bottom of `fanftmp1.c` (after all of the C pre-processor header
|
||||
stuff ... look for a line of the form: `# 38 "fanf.c"` near the bottom)
|
||||
and look at the resulting code. This code, when C pre-processed
|
||||
will expand into over 342 times the original code (ignoring `#include`
|
||||
headers) to produce `fanftmp2.c`. That program in turn, when compiled
|
||||
translates a single lambda expression on standard input into
|
||||
combinator expressions on standard output.
|
||||
|
||||
|
||||
### Extra credit question:
|
||||
|
||||
What do you have to do to make this program work with an old non-ANSI C
|
||||
@@ -88,7 +79,7 @@ for translating lambda expressions into combinator expressions.
|
||||
The syntax of lambda expressions recognised by the program is as
|
||||
follows: The basic atoms are variables which are single characters other
|
||||
than backslash or parentheses, e.g. `a` or `b` or `@`. Variables are
|
||||
combined by function application which is written e.g. `(f a)` which is
|
||||
combined by function application which is written as e.g. `(f a)` which is
|
||||
the function `f` applied to the argument `a`. Application groups to the
|
||||
left, so `(f a b c)` is equivalent to `(((f a) b) c)`. Functions are
|
||||
created from lambda terms which are written in the form `\a(expr)` which
|
||||
@@ -131,30 +122,34 @@ The algorithm for translating lambda expressions into combinator
|
||||
expressions works as follows. There are three forms of lambda expression
|
||||
to consider: variables, applications, and abstractions.
|
||||
|
||||
trans `v` -> `v` (variable)
|
||||
trans `a b` -> (trans `a`) (trans `b`) (application)
|
||||
trans `\ab` -> abs a (trans `b`) (abstraction)
|
||||
```
|
||||
trans v -> v (variable)
|
||||
trans a b -> (trans a) (trans b ) (application)
|
||||
trans \ab -> abs a (trans b) (abstraction)
|
||||
```
|
||||
|
||||
There are a further three cases to consider for the body of lambda
|
||||
expressions, where we need to do the magic that transforms away the
|
||||
variables.
|
||||
|
||||
abs a `f x` -> `S` (abs a `f`) (abs a `x`)
|
||||
abs a `b` -> `K b` (b != a)
|
||||
abs a `a` -> `I`
|
||||
```
|
||||
abs a f x -> S (abs a f) (abs a x)
|
||||
abs a b -> K b (b != a)
|
||||
abs a a -> I
|
||||
```
|
||||
|
||||
E.g. suppose we had combinator expressions for `+` and `3` and we wanted
|
||||
to see what the combinator expression for doubling 3 looked like:
|
||||
|
||||
```
|
||||
trans `\x(+ x x) 3`
|
||||
-> (trans `\x(+ x x)`) (trans `3`)
|
||||
-> (abs x (trans `+ x x`)) `3`
|
||||
-> (abs x `+ x x`) `3`
|
||||
-> `S` (abs x `+ x`) (abs x `x`) `3`
|
||||
-> `S` (`S` (abs x `+`) (abs x `x`)) `I` `3`
|
||||
-> `S` (`S` (`K +`) `I`) `I` `3`
|
||||
-> `S (S (K +) I) I 3`
|
||||
trans \x(+ x x) 3
|
||||
-> (trans \x(+ x x)) (trans 3)
|
||||
-> (abs x (trans + x x)) 3
|
||||
-> (abs x + x x) 3
|
||||
-> S (abs x + x) (abs x x) 3
|
||||
-> S (S (abs x +) (abs x x)) I 3
|
||||
-> S (S (K +) I) I 3
|
||||
-> S (S (K +) I) I 3
|
||||
```
|
||||
|
||||
We can then check that this evaluates to the expected result:
|
||||
@@ -176,7 +171,7 @@ same as `S (K a) (K b)`, because
|
||||
-> a b
|
||||
```
|
||||
|
||||
and
|
||||
and
|
||||
|
||||
```
|
||||
S (K a) (K b) x
|
||||
@@ -220,7 +215,7 @@ It is fairly well known that the lambda calculus (and hence SK
|
||||
combinators) can compute anything, but mere computation is no use if you
|
||||
cannot communicate with the world. This is why `OFL` includes a few
|
||||
concessions to reality: a combinator `E` for representing characters and
|
||||
testing them for equality, two IO combinators, `G` and `P`, for reading
|
||||
testing them for equality, two I/O combinators, `G` and `P`, for reading
|
||||
and writing characters respectively, and a combinator `J` for
|
||||
representing `false`. I also implemented the `Y` combinator directly
|
||||
rather than in terms of the primitive combinators, since it only
|
||||
@@ -239,7 +234,7 @@ the expression evaluates to `J`.
|
||||
|
||||
`K` and `J` are used to represent `true` and `false` respectively; they
|
||||
correspond exactly to the standard lambda calculus representations of
|
||||
true and false, viz. `\t\f(t)` and `\t\f(f)` respectively. In this way a
|
||||
`true` and `false`, viz. `\t\f(t)` and `\t\f(f)` respectively. In this way a
|
||||
conditional expression can just be written `cond then else`, which is
|
||||
even more terse than C `cond ? then : else`. An expression that
|
||||
compares a character with `a`, say, can be written in the rather
|
||||
@@ -247,7 +242,7 @@ obfuscated form `E('a') char then else`.
|
||||
|
||||
The `P` combinator, like the `E` combinator, starts off by evaluating
|
||||
its first argument and checking that it is some form of `E`. It then
|
||||
writes that character on stdout, and finally it calls its second
|
||||
writes that character on `stdout`, and finally it calls its second
|
||||
argument as a function with the argument `I`, i.e.
|
||||
|
||||
```
|
||||
@@ -256,7 +251,7 @@ P x f -> f I
|
||||
|
||||
with a side-effect.
|
||||
|
||||
The `G` combinator just reads a character from stdin then calls its
|
||||
The `G` combinator just reads a character from `stdin` then calls its
|
||||
argument as a function with the appropriate `E` combinator as an
|
||||
argument, i.e.
|
||||
|
||||
@@ -268,12 +263,12 @@ with a side-effect.
|
||||
|
||||
One of the problems with non-strict languages is that it is hard to
|
||||
predict in advance in which order side-effects will occur. In my program
|
||||
I used a monadic IO structure like that used by the programming language
|
||||
I used a monadic I/O structure like that used by the programming language
|
||||
Haskell; this allows one to write programs that manipulate external
|
||||
state in a manner remarkably similar to imperative programming languages
|
||||
like C. An examination of my program should provide an illustration of
|
||||
how well this technique works in practice. (In particular, I used the
|
||||
CPS form of the IO monad from page 6 of "Imperative Functional
|
||||
CPS form of the I/O monad from page 6 of "Imperative Functional
|
||||
Programming".)
|
||||
|
||||
The `Y` combinator is used for implementing recursive functions. It has
|
||||
@@ -342,8 +337,8 @@ of the program that is then interpreted.
|
||||
The first pass of the compiler is implemented via the C preprocessor. It
|
||||
implements one optimisation, namely function in-lining. Unfortunately,
|
||||
this optimisation always increases object code size and execution time.
|
||||
The opposite optimisation, common sub-expression elimination, (which
|
||||
would offer improvements in code size and execution time) has not been
|
||||
The opposite optimisation, common sub-expression elimination (which
|
||||
would offer improvements in code size and execution time), has not been
|
||||
implemented. The output of this pass is a C program that may be compiled
|
||||
by a normal C compiler.
|
||||
|
||||
|
||||
Executable
+41
@@ -0,0 +1,41 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
make all || exit 1
|
||||
|
||||
echo "$ echo '((\a(\b(\c(d)))) e' | ./fanf" 1>&2
|
||||
echo '((\a(\b(\c(d)))) e)' | ./fanf
|
||||
echo 1>&2
|
||||
|
||||
echo "$ echo '
|
||||
(\f\g\x
|
||||
(
|
||||
(g x) (f x)
|
||||
) K K z
|
||||
)'|./fanf" 1>&2
|
||||
echo '
|
||||
(\f\g\x
|
||||
(
|
||||
(g x) (f x)
|
||||
) K K z
|
||||
)'|./fanf
|
||||
echo 1>&2
|
||||
|
||||
|
||||
echo "$ echo '(\f(\f\g\x( (f((\a(g(b))) e)) (g x) ) K K z))' | ./fanf" 1>&2
|
||||
echo '(\f(\f\g\x( (f((\a(g(b))) e)) (g x) ) K K z))' | ./fanf
|
||||
echo 1>&2
|
||||
|
||||
echo "$ echo '
|
||||
(Y\f\n
|
||||
((= n 0)
|
||||
1
|
||||
(* n (f (- n 1)))
|
||||
)
|
||||
)' | ./fanf" 1>&2
|
||||
|
||||
echo '(Y\f\n
|
||||
((= n 0)
|
||||
1
|
||||
(* n (f (- n 1)))
|
||||
)
|
||||
)' | ./fanf
|
||||
@@ -56,7 +56,7 @@ This is a beautiful program. How can a program with no conditional (except for
|
||||
the fixes for modern systems) behavior at all have output which
|
||||
depends on anything?
|
||||
|
||||
For hints on deciphering this, see below past the Author's Comments;
|
||||
For hints on deciphering this, see below past the Author's remarks;
|
||||
they're a nice summary, but they leave the mystery intact.
|
||||
|
||||
BTW: the author notes an incredible lipogram story called
|
||||
@@ -71,9 +71,9 @@ In literary circles, there is a poetic form called a "lipogram",
|
||||
which is a poem in which a specific letter has been distinctly
|
||||
avoided. This principle can be applied in other ways. For
|
||||
instance, in this paragraph, the vowel which immediately follows
|
||||
't' in the alphabet is nowhere to be seen. There is even an
|
||||
`t` in the alphabet is nowhere to be seen. There is even an
|
||||
entire novel (E. V. Wright's "Gadsby") in which no word contains
|
||||
the letter 'e'.
|
||||
the letter `e`.
|
||||
|
||||
The IOCCC has been no stranger to this concept. Several winning entries from
|
||||
years past have accomplished interesting feats while completely avoiding the use
|
||||
@@ -85,12 +85,12 @@ In continuing with this fine tradition, this program suggests to the ANSI
|
||||
committee some new practical simplifications for the C language. For instance,
|
||||
it appears that CONDITIONAL BRANCHING isn't really necessary. So, we can do
|
||||
away with `while`, `do...while`, `for`, `if`/`else`, `switch`, `?:`, or anything
|
||||
else that might cause any kind of nondeterministic jump in the code. There's
|
||||
else that might cause any kind of non-deterministic jump in the code. There's
|
||||
too much uncertainty in the world anyway.
|
||||
|
||||
Function parameters and return types just confuse people anyway, so
|
||||
get rid of them. Same with local variables. In fact, all you really
|
||||
need are assignment statements, and maybe one `printf()` and one `goto`.
|
||||
need are assignment statements, and maybe one `printf(3)` and one `goto`.
|
||||
|
||||
This style of programming is also ideal for systems with limited
|
||||
memory capacity, since the function call stack never goes beyond
|
||||
@@ -103,7 +103,7 @@ line, such as
|
||||
./schnitzi 5
|
||||
```
|
||||
|
||||
The output will itself be a lipographic program, one which inputs
|
||||
The output will itself be a lipographic program, one which expects input of
|
||||
(in this case) five numbers and prints them out sorted. It sorts
|
||||
them, however, using only `if/else` statements, without arrays or
|
||||
looping. To see the resulting program run, redirect the output from
|
||||
|
||||
+48
-96
@@ -5,8 +5,9 @@ make all
|
||||
```
|
||||
|
||||
There is an alternate version of this entry that will work with macOS. See the
|
||||
[Alternate code](#alternate-code) section below for details on how it works and
|
||||
how to use it.
|
||||
[Alternate code](#alternate-code) section below. We recommend you look at it
|
||||
even if you don't have a Mac, unless you want to figure it out yourself, as it
|
||||
includes some interesting details about the entry.
|
||||
|
||||
|
||||
## To use:
|
||||
@@ -15,9 +16,6 @@ how to use it.
|
||||
./schweikh1
|
||||
```
|
||||
|
||||
NOTE: a limitation with the entry was that it required `gcc` but this limitation
|
||||
has been removed to make it more portable, requiring only `cc`.
|
||||
|
||||
|
||||
## Alternate code:
|
||||
|
||||
@@ -25,83 +23,25 @@ As noted above this entry will not work as it stands for macOS and there are
|
||||
some important notes as well as a description of how the fixed version works
|
||||
(the details of which are relevant to the original entry that no longer works as
|
||||
well as the fixed version but are described in the context of the macOS
|
||||
adjustments).
|
||||
adjustments). For details of what had to change, see [macos.md](macos.md).
|
||||
Unless you wish to figure it out yourself, we recommend that you read this even
|
||||
if you don't have a Mac as it has some interesting details about the entry.
|
||||
|
||||
#### macOS changes:
|
||||
|
||||
As an aside: if you have a Mac with the Apple chip, some of the header files
|
||||
will report an unsupported architecture and unsupported compiler (error,
|
||||
warning). This will not make the program abort, however, but even with an Intel
|
||||
CPU though, the original entry will not work in macOS as it stands because
|
||||
`/usr/include` is hard-coded in the code and macOS does not have it.
|
||||
### Alternate build:
|
||||
|
||||
Nevertheless, although some of it would not work in other systems where
|
||||
`/usr/include` exists, the `#define`s would still be found okay, at least until
|
||||
a file was not found (this limitation was removed in both versions, see
|
||||
[thanks-for-fixes.md](/thanks-for-fixes.md) for details).
|
||||
|
||||
However, as noted, macOS does **not** have `/usr/include` so this would not ever
|
||||
work for macOS without some changes, described next. For macOS you will need the
|
||||
command line tools installed which can be done like:
|
||||
|
||||
```sh
|
||||
sudo xcode-select --install
|
||||
```
|
||||
|
||||
An important point is that the original version hard-coded `gcc` but just like
|
||||
the entry, the alternate version has also removed this limitation despite `gcc`
|
||||
existing (though it's `clang`) in macOS.
|
||||
|
||||
Now as far as how this works if you look at the code of
|
||||
[schweikh1.c](schweikh1.c), on line 55 you'll see a funny command (this goes for
|
||||
the alternate version as well but a bit different).
|
||||
|
||||
Now the key is two magic numbers, one (two of this exist) on a different line shortly below the
|
||||
string and the other a couple lines further below.
|
||||
|
||||
In the original the numbers are, respectively, 44 and 46, but with the gcc
|
||||
limitation removed the numbers now are 43 and 45. But how does this work? Well
|
||||
the command is:
|
||||
|
||||
```
|
||||
"0gcc -ansi -E -dM -undef %s /usr/include/%s>r\0 ("
|
||||
```
|
||||
|
||||
which has been changed to be:
|
||||
|
||||
```
|
||||
"0cc -ansi -E -dM -undef %s /usr/include/%s>r\0 ("
|
||||
```
|
||||
|
||||
Shortly below that you will see, as noted above, the numbers:
|
||||
|
||||
```c
|
||||
if ((H = fopen (__FILE__+43, 43+__FILE__)))
|
||||
while ((fgets (L, (int)sizeof L, H)) != 0) {
|
||||
I[strcspn (I, 45+__FILE__)] = O = 0;
|
||||
```
|
||||
|
||||
The first number in the above C means the length starting from 0 up through the
|
||||
`>`. The second number is the same starting point but up through the `\0` which
|
||||
is why it's `+2`. But what happens if only the first number is updated (from the
|
||||
original)? Most of the output will be just `#define` by itself; in the cases
|
||||
where there was text after that it was macros that certainly were not defined.
|
||||
There might have been other errors as well.
|
||||
|
||||
Changing this for macOS allows for opening the right files; the problem with the
|
||||
macOS is `/usr/include` does not exist: instead it's
|
||||
`/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include` which is why
|
||||
the different command line and the different numbers. The change of the numbers
|
||||
can be found in the alternate code and the explanation is the same.
|
||||
|
||||
To use this version use:
|
||||
|
||||
```sh
|
||||
make alt
|
||||
```
|
||||
|
||||
|
||||
### Alternate build:
|
||||
|
||||
Use `schweikh1.alt` as you would `schweikh1` above.
|
||||
|
||||
### Alternate try:
|
||||
|
||||
Bonus exercise: modify the code to provide a different compiler.
|
||||
|
||||
|
||||
@@ -123,6 +63,7 @@ Do not read them if you want to figure this out yourself. "Amendment
|
||||
One" refers to "NA1", the add-on to C89 which added some fairly
|
||||
crufty internationalization support.
|
||||
|
||||
|
||||
#### Historical note:
|
||||
|
||||
Some non-gcc compilers that were not fully ANSI standard did not
|
||||
@@ -130,7 +71,8 @@ compile this entry correctly. Using cc by default was not helpful
|
||||
most of the time on this entry, because the program had a hardcoded
|
||||
gcc invocation anyway. Anyone who uses egcs and has no plain gcc
|
||||
will need to frob the source anyway and can be expected to do the
|
||||
right thing with `${CC}`. So one should have used gcc.
|
||||
right thing with `${CC}`. This limitation was removed in 2023 but in the past
|
||||
one should have used gcc.
|
||||
|
||||
|
||||
## Author's remarks:
|
||||
@@ -162,16 +104,17 @@ Bug your vendor for an upgrade.
|
||||
The format of the info file is straightforward and described in the file
|
||||
itself. Just load it in your favorite editor.
|
||||
|
||||
|
||||
### Requirements
|
||||
|
||||
`gcc` (the GNU C compiler) must be available at runtime. It is assumed that your
|
||||
C implementation keeps headers as files in the /usr/include directory. The info
|
||||
file must be readable and reside in the current working directory. The current
|
||||
working directory must be writable in order to create a temporary file (which is
|
||||
removed upon program termination). In case you don't have gcc at runtime, not
|
||||
all is lost if your compiler or preprocessor can produce a list of defined
|
||||
macros in the format output by `gcc -dM`, i.e. lines of the form `#define MACRO
|
||||
value`.
|
||||
C implementation keeps headers as files in the `/usr/include` directory. The
|
||||
[info](info) file must be readable and reside in the current working directory.
|
||||
The current working directory must be writable in order to create a temporary
|
||||
file (which is removed upon program termination). In case you don't have gcc at
|
||||
runtime, not all is lost if your compiler or preprocessor can produce a list of
|
||||
defined macros in the format output by `gcc -dM`, i.e. lines of the form
|
||||
`#define MACRO value`.
|
||||
|
||||
Edit the source at line 55 in this case.
|
||||
|
||||
@@ -180,7 +123,7 @@ Edit the source at line 55 in this case.
|
||||
ISO C has a very strict idea of visibility of identifiers. All possible
|
||||
macros are explicitly enumerated. In a compliant implementation no other
|
||||
macros can be defined, because you could write strictly conforming
|
||||
programs that may fail to compile due to syntax errors: suppose
|
||||
programs that may fail to compile due to syntax errors: supposing that
|
||||
`<stdio.h>` defines `PIPE_BUF`, then the conforming
|
||||
|
||||
```c
|
||||
@@ -200,6 +143,7 @@ int main (void)
|
||||
is expected to compile and meet the assertion. If it does not, your
|
||||
compiler compiles some other language than ISO C.
|
||||
|
||||
|
||||
### Why I think my program is obfuscated
|
||||
|
||||
Not only is the program's purpose a thorough standard conformance
|
||||
@@ -232,7 +176,7 @@ C compilers.
|
||||
```
|
||||
|
||||
To be honest, I don't know if the rules for pp-tokens and token
|
||||
pasting don't forbid what I do (and tcc is correct in rejecting it).
|
||||
pasting don't forbid what I do (and thus tcc is correct in rejecting it).
|
||||
In this case, all other compilers I tried are buggy, or the Standard
|
||||
itself :-)
|
||||
|
||||
@@ -263,21 +207,21 @@ foo\0bar 9 tcc 4.1.2, Sunsoft cc turn "\0" into "\\0", ugh!
|
||||
|
||||
3. The `%:` and `%:%:` digraphs test for conformance to Amendment One.
|
||||
|
||||
Ask your local guru if C allows the same case label in the same switch
|
||||
statement to appear more than once. Ask him/her to think real hard.
|
||||
The answer will be "no". The true guru will cite a constraint in
|
||||
ISO 6.6.4.2. Then make fun of the guru's answer by waving `case __LINE__:`
|
||||
under his/her nose. Easy money from a bet! Make sure your guru has
|
||||
no chance to use Standardese weasel words as an escape: can I have
|
||||
Ask your local guru if C allows the same case label in the same switch
|
||||
statement to appear more than once. Ask him/her to think real hard.
|
||||
The answer will be "no". The true guru will cite a constraint in
|
||||
ISO 6.6.4.2. Then make fun of the guru's answer by waving `case __LINE__:`
|
||||
under his/her nose. Easy money from a bet! Make sure your guru has
|
||||
no chance to use Standardese weasel words as an escape: can I have
|
||||
|
||||
```c
|
||||
case <some_token>:
|
||||
case <some_token>:
|
||||
```
|
||||
|
||||
in the same switch? (Note that you need the [invisible] newline. You
|
||||
can generously allow the additional constraint that no `#undef`s or
|
||||
`#define`s are allowed between the two cases.)
|
||||
in the same switch? (Note that you need the [invisible] newline. You
|
||||
can generously allow the additional constraint that no `#undef`s or
|
||||
`#define`s are allowed between the two cases.)
|
||||
|
||||
Lots of integer constants and string literals come into the source
|
||||
via `__LINE__` and `__FILE__` which are redefined at various places.
|
||||
@@ -289,7 +233,7 @@ This makes the source and header input depend on ASCII.
|
||||
A few old obfuscations, like one character identifiers, not too
|
||||
many macros, a `goto O`, "needless" assignments to satisfy lint
|
||||
with its "function value ignored" warnings. My lint has nothing
|
||||
to complain.
|
||||
to complain about.
|
||||
|
||||
There's more whitespace in the Standard than just space, tab and newline. In
|
||||
particular, there are vertical tab and form-feed that can be used in certain
|
||||
@@ -303,13 +247,14 @@ printer when you make a hard copy of the source...
|
||||
|
||||
While I'm at it, the rules state that only space, tab and newline
|
||||
are ignored for the count (plus '`{`', '`}`', '`;`' followed by
|
||||
whitespace). The mkentry.c program, however, uses `isspace()` which
|
||||
returns nonzero for vtab and form-feed and other characters as well.
|
||||
I could have used a lot more ^K and ^L probably undetected by your
|
||||
whitespace). The [mkentry.c](../mkentry.c) program, however, uses `isspace(3)` which
|
||||
returns nonzero for `\v` and `\f` and other characters as well.
|
||||
I could have used a lot more `^K` and `^L` probably undetected by your
|
||||
counter but decided to err on the side of safety. I use a perl
|
||||
script to compute the character count according to the rules.
|
||||
The advantages of an independent clean room approach...
|
||||
|
||||
|
||||
```perl
|
||||
#!/usr/bin/perl -w
|
||||
$/ = "\0";
|
||||
@@ -320,10 +265,17 @@ print length ($_),"\n";
|
||||
|
||||
```
|
||||
|
||||
To use, try:
|
||||
|
||||
```sh
|
||||
perl ./charcount.pl schweikh1.c
|
||||
```
|
||||
|
||||
|
||||
I have tried, as suggested in the guidelines, to let the code look
|
||||
like ordinary C code. Apart from a few long lines I think I left
|
||||
the indentation like I would in RL. You should however not try to
|
||||
use indent on the source. The code is extremely fragile because of the
|
||||
use `indent` on the source. The code is extremely fragile because of the
|
||||
myriads of `__LINE__` macros -- indenting is a sure way to break
|
||||
the program. Don't even think of maintaining that beast; I've
|
||||
had my share of core dumps during development :-) A test suite
|
||||
|
||||
Executable
+8
@@ -0,0 +1,8 @@
|
||||
#!/usr/bin/perl -w
|
||||
$/ = "\0";
|
||||
$_ = <>;
|
||||
s/[;{}][ \t\n]/\n/g;
|
||||
s/[ \t\n]+//g;
|
||||
print length ($_),"\n";
|
||||
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
This document describes how this was fixed to work with macOS as well as some of
|
||||
the magic in the entry. Even if you don't have a Mac it might be worth your time
|
||||
reading especially as some of it details some important fixes and changes in the
|
||||
original entry as well.
|
||||
|
||||
# macOS changes
|
||||
|
||||
As an aside: if you have a Mac with the Apple chip, some of the header files
|
||||
will report an unsupported architecture and unsupported compiler (error,
|
||||
warning). This will not make the program abort, however, but even with an Intel
|
||||
CPU though, the original entry will not work in macOS as it stands because
|
||||
`/usr/include` is hard-coded in the code and macOS does not have it.
|
||||
|
||||
Nevertheless, although some of it would not work in other systems where
|
||||
`/usr/include` exists, the `#define`s would still be found okay, at least until
|
||||
a file was not found (this limitation was removed in both versions in 2023). see
|
||||
|
||||
However, as noted, macOS does **not** have `/usr/include` so this would never
|
||||
work for macOS without some changes, described next. For macOS you will need the
|
||||
command line tools installed which can be done like:
|
||||
|
||||
```sh
|
||||
sudo xcode-select --install
|
||||
```
|
||||
|
||||
An important point is that the original version hard-coded `gcc` but just like
|
||||
the entry, the alternate version has also removed this limitation despite `gcc`
|
||||
existing (though it's `clang`) in macOS.
|
||||
|
||||
Now as far as how this works if you look at the code of
|
||||
[schweikh1.c](schweikh1.c), on line 55 you'll see a funny command (this goes for
|
||||
the alternate version as well but a bit different).
|
||||
|
||||
Now the key is two magic numbers, one (two times) on a different line shortly below the
|
||||
string and the other a couple lines further below.
|
||||
|
||||
In the original the numbers are, respectively, `44` and `46`, but with the gcc
|
||||
limitation removed the numbers now are `43` and `45`. But how does this work? Well
|
||||
the command is:
|
||||
|
||||
```
|
||||
"0gcc -ansi -E -dM -undef %s /usr/include/%s>r\0 ("
|
||||
```
|
||||
|
||||
which has been changed to be:
|
||||
|
||||
```
|
||||
"0cc -ansi -E -dM -undef %s /usr/include/%s>r\0 ("
|
||||
```
|
||||
|
||||
Shortly below that you will see, as noted above, the numbers:
|
||||
|
||||
```c
|
||||
if ((H = fopen (__FILE__+43, 43+__FILE__)))
|
||||
while ((fgets (L, (int)sizeof L, H)) != 0) {
|
||||
I[strcspn (I, 45+__FILE__)] = O = 0;
|
||||
```
|
||||
|
||||
The first number in the above C means the length starting from 0 up through the
|
||||
`>`. The second number is the same starting point but up through the `\0` which
|
||||
is why it's `+2`. But what happens if only the first number is updated (from the
|
||||
original)? Most of the output will be just `#define` by itself; in the cases
|
||||
where there was text after that it was macros that certainly were not defined.
|
||||
There might have been other errors as well.
|
||||
|
||||
Changing this for macOS allows for opening the right files; the problem with
|
||||
macOS is `/usr/include` does not exist: instead it's
|
||||
`/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include` which is why
|
||||
the different command line and the different numbers. The change of the numbers
|
||||
can be found in the alternate code and the explanation is the same.
|
||||
@@ -89,6 +89,7 @@ to trigger this error.
|
||||
With the proper text beyond the `\012`, it was even possible to have all kinds
|
||||
of fun adding inline assembly via `#line` directives. :-)
|
||||
|
||||
|
||||
#### For extra fun and credit:
|
||||
|
||||
If your compiler had this bug, you could transform the line in the C program to
|
||||
@@ -136,6 +137,7 @@ and now it works with both clang and gcc.
|
||||
|
||||
## Author's remarks:
|
||||
|
||||
|
||||
### What this program does
|
||||
|
||||
My entry is a `yarng`, which stands for, you guessed it, yet another
|
||||
@@ -147,7 +149,7 @@ non-deterministic factors. Here's how it works:
|
||||
1. an alarm is scheduled to be delivered in a second
|
||||
2. an infinite loop is entered that just increments a counter
|
||||
3. on delivery of the alarm signal, the counter's LSB is printed.
|
||||
4. while some other counter is not zero, go to 1)
|
||||
4. while some other counter is not zero, go to step (1)
|
||||
5. exit
|
||||
|
||||
The `yarng` therefore produces output at a rate of 1 baud. The number of
|
||||
@@ -175,7 +177,7 @@ impossible, like in the `int main` declaration I have `int` split across two
|
||||
lines. All indent programs I use insert space at the beginning of the
|
||||
continuation line and thereby introduce a syntax error.
|
||||
|
||||
- `main` (ab)used as a signal handler. Shocking. Yeah, this leads to undefined
|
||||
- `main()` (ab)used as a signal handler. Shocking. Yeah, this leads to undefined
|
||||
behaviour. I have yet to see a system where it does not work. If it doesn't work
|
||||
for you, I'd appreciate if you mail me about it. Uh-oh, Schweikh did it,
|
||||
uttered "Works for me". Don't quote me on that!
|
||||
@@ -190,7 +192,7 @@ lame and I came up with `??=line 10 ONE(O(1,1,2,6,0,6))`.
|
||||
|
||||
- `__LINE__` is used as the signal number argument to `signal()`. If indenting or
|
||||
other editing changes the number of lines the program is likely to be killed
|
||||
after one second... Thanks to POSIX for specifying SIGALRM as 14. You're SOL if
|
||||
after one second... Thanks to POSIX for specifying `SIGALRM` as `14`. You're SOL if
|
||||
your system does not conform. Get a real OS.
|
||||
|
||||
- All strings (or characters) needed are crammed into `__FILE__` using octal
|
||||
@@ -205,14 +207,15 @@ and as a plain identifier in `main`'s parameters. The rule is that whenever
|
||||
`ONE` is followed by `(` it must be the macro.
|
||||
|
||||
- A quote from Kernighan and Plauger, _The Elements of Programming Style_, 2nd
|
||||
Ed., page 21: "A useful way to decide if some piece of code is clear or not is
|
||||
Ed., page 21: `"A useful way to decide if some piece of code is clear or not is
|
||||
the 'telephone test.' If someone could understand your code when read aloud
|
||||
over the telephone, it's clear enough. If not then it needs rewriting." Now try
|
||||
over the telephone, it's clear enough. If not then it needs rewriting."` Now try
|
||||
the telephone test for 'one = zero = atoi (ONE[zero-1])'.
|
||||
|
||||
- Don't you love the aesthetics of symmetry: `write (1, 1+__FILE__+1, 1)`
|
||||
(telephone test this as well; is it 1, One, ONE, one? Maybe won?).
|
||||
|
||||
|
||||
### Where does the randomness come from?
|
||||
|
||||
Each bit obviously depends on the number of times the loop body is
|
||||
@@ -221,7 +224,7 @@ this number?
|
||||
|
||||
- The accuracy of the clock driving the CPU.
|
||||
- The accuracy of the clock driving the timer responsible for alarm signals.
|
||||
- On multitasking OS's: The total time the process is scheduled to run between
|
||||
- On multitasking OSes: The total time the process is scheduled to run between
|
||||
successive invocations of the signal handler.
|
||||
|
||||
How about the randomness of the `yarng`? To measure these properties I
|
||||
@@ -230,7 +233,7 @@ expect from a generator with uniform distribution (all sequences
|
||||
equally likely to occur).
|
||||
|
||||
It is interesting to note that `yarng`'s maximum deviations are less
|
||||
than or equal to `rand()`'s. Randomness however tends to degrade under
|
||||
than or equal to `rand(3)`'s. Randomness however tends to degrade under
|
||||
high load averages on my system (Linux). This could be avoided by
|
||||
allowing the process one second of execution time instead of wall
|
||||
clock time (using the `SIGVTALRM` sent by the virtual timer
|
||||
|
||||
@@ -58,7 +58,7 @@ ARCH=
|
||||
# Defines that are needed to compile
|
||||
#
|
||||
CDEFINE= -DM0=sizeof -DM1=long -DM2=void \
|
||||
-DM3=realloc -DM4=calloc -DM5=free
|
||||
-DM3=realloc -DM4=calloc -DM5=free -DSZ=32767
|
||||
|
||||
# Include files that are needed to compile
|
||||
#
|
||||
|
||||
+60
-46
@@ -4,10 +4,29 @@
|
||||
make all
|
||||
```
|
||||
|
||||
The author stated:
|
||||
|
||||
```
|
||||
In the remote event that the input has more than `8192` files with
|
||||
the same size (on systems where `sizeof (char *) == 4`, or `4096` when
|
||||
`sizeof (char *) == 8`), increase the manifest constant 32767 on line
|
||||
31.
|
||||
```
|
||||
|
||||
so we changed the constant to be `SZ` defined in the Makefile. To change the
|
||||
value you can do something like:
|
||||
|
||||
```sh
|
||||
make clobber CDEFINE="-DM0=sizeof -DM1=long -DM2=void \
|
||||
-DM3=realloc -DM4=calloc -DM5=free -DSZ=55555" all
|
||||
```
|
||||
|
||||
or whatever you wish to redefine it to.
|
||||
|
||||
|
||||
## To use:
|
||||
|
||||
If "dir" is the directory (or a directory tree) where you keep
|
||||
If `dir` is the directory (or a directory tree) where you keep
|
||||
all your favorite pictures off the Internet or from
|
||||
`alt.binaries.pictures.*`, do
|
||||
|
||||
@@ -15,7 +34,7 @@ all your favorite pictures off the Internet or from
|
||||
find dir -type f -print | ./samefile
|
||||
```
|
||||
|
||||
Maybe you will not need to buy another 10 Gb disk to store them. :-)
|
||||
Maybe you will not need to buy another 10 GB disk to store them. :-)
|
||||
|
||||
|
||||
### Try:
|
||||
@@ -23,20 +42,14 @@ Maybe you will not need to buy another 10 Gb disk to store them. :-)
|
||||
If you're in this winning entry's directory:
|
||||
|
||||
```sh
|
||||
find . -type f -print | ./samefile
|
||||
./try.sh
|
||||
```
|
||||
|
||||
Notice that the tool finds a duplicate file, that of the man page.
|
||||
Notice that the tool finds some files that are duplicates.
|
||||
|
||||
|
||||
## Judges' remarks:
|
||||
|
||||
Try this:
|
||||
|
||||
```sh
|
||||
./try.sh
|
||||
```
|
||||
|
||||
This program is not as smart as to detect identity of JPEG files with the same
|
||||
picture but with different compression levels. On the other hand compression can
|
||||
make a thing look/sound/feel different so these probably aren't duplicates
|
||||
@@ -56,7 +69,7 @@ Thank God the IEEE does not standardize a coding style...
|
||||
### What this program does
|
||||
|
||||
This is best explained in the man page. The troff source for this
|
||||
man page can be found in the file samefile.1. To render try:
|
||||
man page can be found in the file [samefile.1](samefile.1). To render try:
|
||||
|
||||
```sh
|
||||
`man ./samefile.1
|
||||
@@ -65,23 +78,24 @@ man page can be found in the file samefile.1. To render try:
|
||||
Otherwise:
|
||||
|
||||
|
||||
**SAMEFILE(1) User Manuals SAMEFILE(1)**
|
||||
### SAMEFILE(1) User Manuals SAMEFILE(1)
|
||||
|
||||
|
||||
**NAME**
|
||||
#### NAME
|
||||
|
||||
**samefile** - find identical files
|
||||
`samefile` - find identical files
|
||||
|
||||
|
||||
**SYNOPSIS**
|
||||
#### SYNOPSIS
|
||||
|
||||
./samefile
|
||||
|
||||
```sh
|
||||
./samefile
|
||||
```
|
||||
|
||||
**DESCRIPTION**
|
||||
#### DESCRIPTION
|
||||
|
||||
`samefile` reads a list of file names (one file name per
|
||||
line) from `stdin`. For each file name pair with identical
|
||||
line) from `stdin`. For each file name pair with identical
|
||||
contents, a line consisting of six tab separated fields is
|
||||
output: The size in bytes, two file names, the character
|
||||
`=` if the two files are on the same device, `X` otherwise,
|
||||
@@ -104,10 +118,10 @@ binary tree.
|
||||
In the second stage all files having the same size are
|
||||
compared against each other. The rules of mathematical
|
||||
logic are applied to reduce work and output noise: if
|
||||
files A, B, and C have the same size and samefile finds
|
||||
that A = B and A = C then it will not compare B against C
|
||||
(and will not output a line for B and C) but only for A =
|
||||
B and A = C. The algorithm will detect equality across
|
||||
files `A`, `B`, and `C` have the same size and samefile finds
|
||||
that `A = B` and `A = C` then it will not compare `B` against `C`
|
||||
(and will not output a line for `B` and `C`) but only for `A =
|
||||
B` and `A = C`. The algorithm will detect equality across
|
||||
arbitrarily long chains. Note however, that because only
|
||||
the first filename per inode gets into the first stage,
|
||||
the output for a group of identical files with different
|
||||
@@ -116,13 +130,13 @@ identical files of size 100 in an inode group consisting
|
||||
of the three inodes with numbers 10, 20 and 30:
|
||||
|
||||
```sh
|
||||
$ ls -i # output edited for readability:
|
||||
10 file1 20 file4 30 file6
|
||||
10 file2 20 file5
|
||||
10 file3
|
||||
$ ls | ./samefile
|
||||
100 file1 file4 = 3 2
|
||||
100 file1 file6 = 3 1
|
||||
$ ls -i # output edited for readability:
|
||||
10 file1 20 file4 30 file6
|
||||
10 file2 20 file5
|
||||
10 file3
|
||||
$ ls | ./samefile
|
||||
100 file1 file4 = 3 2
|
||||
100 file1 file6 = 3 1
|
||||
```
|
||||
|
||||
The sum of the sizes in the first column is the amount of
|
||||
@@ -135,24 +149,24 @@ Note that it is not enough to just remove `file4` and `file6`
|
||||
exists.)
|
||||
|
||||
|
||||
**LIMITATIONS**
|
||||
#### LIMITATIONS
|
||||
|
||||
`samefile` was written with no limits in mind. The number of
|
||||
input lines is unlimited. The size of the actual files is
|
||||
only limited by available virtual memory needed to compare
|
||||
one pair of files. The only hard limit is the constraint
|
||||
that there should not be more than about 8192 files having
|
||||
that there should not be more than about `8192` files having
|
||||
the same size. Experience has shown that there are rarely
|
||||
more than a couple dozen files of the same size.
|
||||
|
||||
**EXAMPLES**
|
||||
#### EXAMPLES
|
||||
|
||||
For everybody:
|
||||
|
||||
What are the duplicates under my home directory?
|
||||
|
||||
```sh
|
||||
$ find $HOME | ./samefile
|
||||
find $HOME | ./samefile
|
||||
```
|
||||
|
||||
For the sysadmin folks:
|
||||
@@ -160,23 +174,23 @@ For the sysadmin folks:
|
||||
Report all duplicate files under /usr larger than 16k:
|
||||
|
||||
```sh
|
||||
$ find /usr -size +16384c -a -type f | ./samefile
|
||||
find /usr -size +16384c -a -type f | ./samefile
|
||||
```
|
||||
|
||||
For the ftp and WWW admins:
|
||||
How much space is wasted below our site's /pub directory?
|
||||
|
||||
```sh
|
||||
$ find /pub -type f | samefile | awk '{sum += $1} END {print sum}'
|
||||
find /pub -type f | samefile | awk '{sum += $1} END {print sum}'
|
||||
```
|
||||
|
||||
|
||||
**EXIT STATUS**
|
||||
#### EXIT STATUS
|
||||
|
||||
If `samefile` runs out of memory the exit status is 1, zero
|
||||
otherwise.
|
||||
|
||||
**SEE ALSO**
|
||||
#### SEE ALSO
|
||||
|
||||
`find(1)`, `ln(1)`, `rm(1)`
|
||||
|
||||
@@ -194,19 +208,19 @@ otherwise.
|
||||
of files across arbitrarily long chains? In my private unobfuscated
|
||||
source there are 17 lines describing just that. A classical case for
|
||||
the well known `/* You're not supposed to understand this */` comment.
|
||||
- Would Dijkstra consider this goto harmful?
|
||||
- The only string literal is split in more than a dozen substrings
|
||||
- Would Dijkstra consider this `goto` harmful?
|
||||
- The only string literal is split in more than a dozen substrings.
|
||||
- For the task at hand the code is pretty terse. Some dynamic memory
|
||||
is even freed as soon as it's no longer needed. I have tried to
|
||||
make the preprocessor directives as short as possible. This means
|
||||
no spaces after #include and no spaces after some of the macro
|
||||
no spaces after `#include` and no spaces after some of the macro
|
||||
names.
|
||||
|
||||
Are you an algorithms guru? If so you should know why the output
|
||||
appears sorted without any use of `qsort()` or `system("sort")`.
|
||||
appears sorted without any use of `qsort(3)` or `system("sort")`.
|
||||
|
||||
Rewrite (hah!) the program to use memory mapping of files instead
|
||||
of `read()`. Does this affect performance noticeably?
|
||||
of `read(2)`. Does this affect performance noticeably?
|
||||
|
||||
It's easy to write a script that takes `samefile`'s output and
|
||||
hard links (or symlinks) identical files. Writing such a script is
|
||||
@@ -214,11 +228,11 @@ left as an exercise for the deobfuscator.
|
||||
|
||||
When you run `samefile` on some directory tree, try to estimate
|
||||
how much you think it will find. Is the actual result anywhere
|
||||
near your estimate? How many copies of the GPL COPYING file
|
||||
near your estimate? How many copies of the GPL `COPYING` file
|
||||
are there on your filesystems? :-)
|
||||
|
||||
In the remote event that the input has more than 8192 files with
|
||||
the same size (on systems where `sizeof (char *) == 4`, or 4096 when
|
||||
In the remote event that the input has more than `8192` files with
|
||||
the same size (on systems where `sizeof (char *) == 4`, or `4096` when
|
||||
`sizeof (char *) == 8`), increase the manifest constant 32767 on line
|
||||
31.
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
/* HE WHO SAYS */
|
||||
|
||||
Z I A<:32767/ M0(I )]; Z g stat S,T; Z size_t y B f{
|
||||
Z I A<: SZ/ M0(I )]; Z g stat S,T; Z size_t y B f{
|
||||
I n ; g f * x ; dev_t d ; ino_t i; } f B t{ M1 s,c; f
|
||||
*l; g t*L,*R; } t; D(a,t)D(E ,f)Z t*J(t*p,I n){ H! p){ p=
|
||||
a(); p _ s =S O; p _ c=1; p _ L=p _ R=0;
|
||||
|
||||
@@ -12,3 +12,6 @@ echo "$ ln -f file3 file4"
|
||||
ln -f file3 file4
|
||||
echo "$ find . -type f -name 'file?' | ./samefile"
|
||||
find . -type f -name 'file?' | ./samefile
|
||||
|
||||
echo "find . -type f -print | ./samefile" 1>&2
|
||||
find . -type f -print | ./samefile
|
||||
+34
-19
@@ -8,26 +8,31 @@ make all
|
||||
## To use:
|
||||
|
||||
```sh
|
||||
./tomtorfs tomtorfs.c 32 04C11DB7 1 FFFFFFFF FFFFFFFF
|
||||
./tomtorfs filename bitwidth polynom reflected init xor
|
||||
```
|
||||
|
||||
where:
|
||||
|
||||
```
|
||||
filename : file to calculate the CRC of
|
||||
bitwidth : width of the CRC in bits (decimal)
|
||||
polynom : polynomial used for the CRC (hexadecimal)
|
||||
reflected : 0 if the CRC is not reflected, 1 if it is
|
||||
init : initial value for the CRC (hexadecimal)
|
||||
xor : value to xor the final CRC with (hexadecimal)
|
||||
```
|
||||
|
||||
### Try:
|
||||
|
||||
```sh
|
||||
echo "abscond conferrable" > file.A
|
||||
echo "adorn condolence" > file.B
|
||||
echo "adorn condolence too" > file.C
|
||||
./tomtorfs file.A 32 04C11DB7 1 FFFFFFFF FFFFFFFF
|
||||
./tomtorfs file.B 32 04C11DB7 1 FFFFFFFF FFFFFFFF
|
||||
./tomtorfs file.C 32 04C11DB7 1 FFFFFFFF FFFFFFFF
|
||||
./try.sh
|
||||
```
|
||||
|
||||
|
||||
## Judges' remarks:
|
||||
|
||||
If you don't believe the program is correct, try and compare the output
|
||||
of the program with the value of CRC computed by PKZIP or any other
|
||||
of the program with the value of CRCs computed by PKZIP or any other
|
||||
archiver that uses the CRC-32 algorithm.
|
||||
|
||||
|
||||
@@ -47,12 +52,14 @@ xor : value to xor the final CRC with (hexadecimal)
|
||||
|
||||
### Examples
|
||||
|
||||
|
||||
#### CRC-16:
|
||||
|
||||
```sh
|
||||
./tomtorfs filename 16 1021 0 FFFF 0000
|
||||
```
|
||||
|
||||
|
||||
#### CRC-32:
|
||||
|
||||
|
||||
@@ -60,6 +67,7 @@ xor : value to xor the final CRC with (hexadecimal)
|
||||
./tomtorfs filename 32 04C11DB7 1 FFFFFFFF FFFFFFFF
|
||||
```
|
||||
|
||||
|
||||
#### XMODEM:
|
||||
|
||||
```sh
|
||||
@@ -67,12 +75,14 @@ xor : value to xor the final CRC with (hexadecimal)
|
||||
|
||||
```
|
||||
|
||||
|
||||
#### ARC:
|
||||
|
||||
```sh
|
||||
./tomtorfs filename 16 8005 1 0000 0000
|
||||
```
|
||||
|
||||
|
||||
### Portability notes
|
||||
|
||||
The program assumes `CHAR_BIT==8`. Results are undefined if `bitwidth >
|
||||
@@ -82,11 +92,13 @@ valid exit value to indicate failure (replace them with `EOF` resp.
|
||||
|
||||
No special build options required.
|
||||
|
||||
|
||||
### Special notes
|
||||
|
||||
Count the number of non-whitespace characters in the source
|
||||
file to find out what dark force drove me to write this ;-).
|
||||
|
||||
|
||||
### Spoiler
|
||||
|
||||
First of all, if you run a C beautifier on the program (thereby of course losing
|
||||
@@ -99,26 +111,29 @@ following meanings:
|
||||
```
|
||||
a = argc
|
||||
A = argv
|
||||
|
||||
b = array of unsigned long variables
|
||||
b[0] = bit-width of the CRC (argv[2])
|
||||
b[1] = CRC polynomial (argv[3])
|
||||
b[2] = nonzero if CRC is reflected (argv[4])
|
||||
b[3] = initial value of CRC (argv[5])
|
||||
b[4] = value final CRC is XORed with (argv[6])
|
||||
b[5] = CRC value
|
||||
b[6] = byte from file
|
||||
b[7] = counter
|
||||
b[0] = bit-width of the CRC (argv[2])
|
||||
b[1] = CRC polynomial (argv[3])
|
||||
b[2] = nonzero if CRC is reflected (argv[4])
|
||||
b[3] = initial value of CRC (argv[5])
|
||||
b[4] = value final CRC is XORed with (argv[6])
|
||||
b[5] = CRC value
|
||||
b[6] = byte from file
|
||||
b[7] = counter
|
||||
|
||||
B = FILE * through which the file argv[1] is opened
|
||||
|
||||
C = typedef for unsigned long
|
||||
```
|
||||
|
||||
The first for loop simply reads the command-line arguments
|
||||
in the `b[]` array. The third parameter to `strtoul()` causes
|
||||
The first `for` loop simply reads the command-line arguments
|
||||
in the `b[]` array. The third parameter to `strtoul(3)` causes
|
||||
all arguments to be in base-16 (hex) except the first one,
|
||||
which will be in base-10 (decimal).
|
||||
|
||||
The rest of the program "simply" calculates the CRC in `b[5]`
|
||||
and then prints it to stdout. The bit reflection loops may
|
||||
and then prints it to `stdout`. The bit reflection loops may
|
||||
appear a bit tricky at first, but if you have a good look
|
||||
at them they should become obvious also.
|
||||
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#define exit(a) return EXIT_FAILURE
|
||||
|
||||
int main(int a,char **A){FILE*B;typedef unsigned long C;C b
|
||||
[8]; if(!(a==7&&(B= fopen(1[A],"rb")))) return 1;for(7[b]=0
|
||||
[8]; if(!(a==7&&(B= fopen(1[A],"rb")))) exit(1); for(7[b]=0
|
||||
;7[b]<5;7[b]++)b[7[ b]]=strtoul(A[2+7[b ]],0,16-!7[b]*6);5[
|
||||
b]=3[b] ; while ((6[b]= getc(B)
|
||||
)!=(C)- 1){if(2 [b])for (7[b]=0
|
||||
) !=EOF ){if(2 [b])for (7[b]=0
|
||||
;7[b]<4 ;7[b]++ )if(((6 [b]>>7[
|
||||
b])^(6[ b]>>(7-7[b])))&1)6[ b] ^=(1
|
||||
<<7[b]) ^(1<<(7-7[b]));5[b] ^= 6[b]
|
||||
|
||||
Executable
+23
@@ -0,0 +1,23 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# script to demonstrate 1998/tomtorfs
|
||||
#
|
||||
|
||||
rm -f file.A file.B file.C
|
||||
|
||||
echo "$ echo abscond conferrable > file.A" 1>&2
|
||||
echo "abscond conferrable" > file.A
|
||||
echo "$ ./tomtorfs file.A 32 04C11DB7 1 FFFFFFFF FFFFFFFF" 1>&2
|
||||
./tomtorfs file.A 32 04C11DB7 1 FFFFFFFF FFFFFFFF
|
||||
|
||||
echo "$ echo adorn condolence > file.B" 1>&2
|
||||
echo "adorn condolence" > file.B
|
||||
echo "$ ./tomtorfs file.B 32 04C11DB7 1 FFFFFFFF FFFFFFFF" 1>&2
|
||||
./tomtorfs file.B 32 04C11DB7 1 FFFFFFFF FFFFFFFF
|
||||
|
||||
echo "$ echo adorn condolence too > file.C" 1>&2
|
||||
echo "adorn condolence too" > file.C
|
||||
echo "$ ./tomtorfs file.C 32 04C11DB7 1 FFFFFFFF FFFFFFFF" 1>&2
|
||||
./tomtorfs file.C 32 04C11DB7 1 FFFFFFFF FFFFFFFF
|
||||
|
||||
rm -f file.A file.B file.C
|
||||
@@ -0,0 +1,62 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <conio.h>
|
||||
#include <signal.h>
|
||||
#define n(o,p,e)=y=(z=a(e)%16 p x%16 p o,a(e)p x p o),h(
|
||||
#define s 6[o]
|
||||
#define p z=l[d(9)]|l[d(9)+1]<<8,1<(9[o]+=2)||++8[o]
|
||||
#define Q a(7)
|
||||
#define w 254>(9[o]-=2)||--8[o],l[d(9)]=z,l[1+d(9)]=z>>8
|
||||
#define O )):((
|
||||
#define b (y&1?~s:s)>>"\6\0\2\7"[y/2]&1?0:(
|
||||
#define S )?(z-=
|
||||
#define a(f)*((7&f)-6?&o[f&7]:&l[d(5)])
|
||||
#define C S 5 S 3
|
||||
#define D(E)x/8!=16+E&198+E*8!=x?
|
||||
#define B(C)fclose((C))
|
||||
#define q (c+=2,0[c-2]|1[c-2]<<8)
|
||||
#define m x=64&x?*c++:a(x),
|
||||
#define A(F)=fopen((F),"rb+")
|
||||
unsigned char o[10],l[78114],*c=l,*k=l
|
||||
#define d(e)o[e]+256*o[e-1]
|
||||
#define h(l)s=l>>8&1|128&y|!(y&255)*64|16&z|2,y^=y>>4,y^=y<<2,y^=~y>>1,s|=y&4
|
||||
+64506; FILE *u, *v, *e, *V; int x,y,z,Z; main(r,U)char**U;{
|
||||
|
||||
{ { { } } } { { { } } } { { { } } } { { { } } }
|
||||
{ { { } } } { { { } } } { { { } } } { { { } } }
|
||||
{ { { } } } { { { } } } { { { } } } { { { } } }
|
||||
{ { { } } } { { { } } } { { { } } } { { { } } }
|
||||
{ { { } } } { { { } } } { { { } } } { { { } } }
|
||||
{ { { } } } { { { } } } { { { } } } { { { } } }
|
||||
{ { ; } } { { { } } } { { ; } } { { { } } }
|
||||
{ { { } } } { { { } } } { { { } } } { { { } } }
|
||||
{ { { } } } { { { } } } { { { } } } { { { } } }
|
||||
{ { { } } } { { { } } } { { { } } } { { { } } }
|
||||
{ { { } } } { { { } } } { { { } } } { { { } } }
|
||||
{ { { } } } { { { } } } { { { } } } { { { } } }
|
||||
{ { { } } } { { { } } } { { { } } } { { { } } }
|
||||
|
||||
|
||||
signal(SIGINT, SIG_IGN); for(v A((u A((e A((r-2?0:(V A(1[U])),"C")
|
||||
),fread(l,78114,1,e),B(e),"B")),"A")); 118-(x
|
||||
=*c++); (y=x/8%8,z=(x&199)-4 S 1 S 1 S 186 S 2 S 2 S 3 S 0,r=(y>5)*2+y,z=(x&
|
||||
207)-1 S 2 S 6 S 2 S 182 S 4)?D(0)D(1)D(2)D(3)D(4)D(5)D(6)D(7)(z=x-2 C C C C
|
||||
C C C C+129 S 6 S 4 S 6 S 8 S 8 S 6 S 2 S 2 S 12)?x/64-1?((0 O a(y)=a(x) O 9
|
||||
[o]=a(5),8[o]=a(4) O 237==*c++?((int (*)())(2-*c++?fwrite:fread))(l+*k+1[k]*
|
||||
256,128,1,(fseek(y=5[k]-1?u:v,((3[k]|4[k]<<8)<<7|2[k])<<7,Q=0),y)):0 O y=a(5
|
||||
),z=a(4),a(5)=a(3),a(4)=a(2),a(3)=y,a(2)=z O c=l+d(5) O y=l[x=d(9)],z=l[++x]
|
||||
,x[l]=a(4),l[--x]=a(5),a(5)=y,a(4)=z O 2-*c?Z||Z=kbhit()?getch():0,1&*c++?Q=Z,Z=0:(
|
||||
Q=!!Z):(c++,Q=r=V?fgetc(V):-1,s=s&~1|r<0) O++c,putchar(7[o]) O z=c+2-l,w,
|
||||
c=l+q O p,c=l+z O c=l+q O s^=1 O Q=q[l] O s|=1 O q[l]=Q O Q=~Q O a(5)=l[x=q]
|
||||
,a(4)=l[++x] O s|=s&16|9<Q%16?Q+=6,16:0,z=s|=1&s|Q>159?Q+=96,1:0,y=Q,h(s<<8)
|
||||
O l[x=q]=a(5),l[++x]=a(4) O x=Q%2,Q=Q/2+s%2*128,s=s&~1|x O Q=l[d(3)]O x=Q /
|
||||
128,Q=Q*2+s%2,s=s&~1|x O l[d(3)]=Q O s=s&~1|1&Q,Q=Q/2|Q<<7 O Q=l[d(1)]O s=~1
|
||||
&s|Q>>7,Q=Q*2|Q>>7 O l[d(1)]=Q O m y n(0,-,7)y) O m z=0,y=Q|=x,h(y) O m z=0,
|
||||
y=Q^=x,h(y) O m z=Q*2|2*x,y=Q&=x,h(y) O m Q n(s%2,-,7)y) O m Q n(0,-,7)y) O
|
||||
m Q n(s%2,+,7)y) O m Q n(0,+,7)y) O z=r-8?d(r+1):s|Q<<8,w O p,r-8?o[r+1]=z,r
|
||||
[o]=z>>8:(s=~40&z|2,Q=z>>8) O r[o]--||--o[r-1]O a(5)=z=a(5)+r[o],a(4)=z=a(4)
|
||||
+o[r-1]+z/256,s=~1&s|z>>8 O ++o[r+1]||r[o]++O o[r+1]=*c++,r[o]=*c++O z=c-l,w
|
||||
,c=y*8+l O x=q,b z=c-l,w,c=l+x) O x=q,b c=l+x) O b p,c=l+z) O a(y)=*c++O r=y
|
||||
,x=0,a(r)n(1,-,y)s<<8) O r=y,x=0,a(r)n(1,+,y)s<<8))));
|
||||
system("stty cooked echo"); B((B((V?B(V):0,u)),v)); }
|
||||
@@ -1026,8 +1026,8 @@ not exist in the archive. Do you have it? Please provide it!
|
||||
### Source code: [1993/cmills/cmills.c](1993/cmills/cmills.c)
|
||||
### Information: [1993/cmills/README.md](1993/cmills/README.md)
|
||||
|
||||
We are unsure if this is a problem with multiple platforms but in macOS at least
|
||||
the program appears to just shows a black screen.
|
||||
In multiple platforms, both macOS and also linux (in particular a RHEL 9.3
|
||||
system), this entry just shows a blank screen.
|
||||
|
||||
Can you fix it? We welcome your help.
|
||||
|
||||
@@ -1041,7 +1041,8 @@ Can you fix it? We welcome your help.
|
||||
This entry relied on a bug in gcc that was fixed with gcc version 2.3.3. This
|
||||
cannot be fixed for modern systems as the bug is long gone.
|
||||
|
||||
An alternate version, however, does exist. See the README.md file for details.
|
||||
An alternate version that will work for modern systems, however, does exist. See
|
||||
the README.md file for details.
|
||||
|
||||
|
||||
### STATUS: INABIAF - please **DO NOT** fix
|
||||
|
||||
@@ -361,7 +361,7 @@ usually away with `stty echo`. Sometimes you can also get away with `stty sane`.
|
||||
will too but it won't reset the terminal).
|
||||
|
||||
|
||||
<a name="#X11macos"></a>
|
||||
<a name="X11macos"></a>
|
||||
## Q: How do I get X11 entries to work with macOS?
|
||||
|
||||
As an example we will use [1993/jonth](1993/jonth/README.md) which works well
|
||||
|
||||
+83
-45
@@ -1391,15 +1391,16 @@ should have been removed.
|
||||
## [1992/adrian](1992/adrian/adrian.c) ([README.md](1992/adrian/README.md]))
|
||||
|
||||
Cody fixed the code so that it will try opening the file the code was compiled
|
||||
from (`__FILE__`), not `adgrep.c`, as
|
||||
the latter does not exist: `adgrep` is simply a link to `adrian` as `adgrep` is
|
||||
what the program was submitted as but the winner is `adrian.c`.
|
||||
from (`__FILE__`), not `adgrep.c`, as the latter does not exist: `adgrep` is
|
||||
simply a link to `adrian` as `adgrep` is what the program was submitted as but
|
||||
the winner is `adrian.c`.
|
||||
|
||||
Not fixing this would cause the program to crash if no arg was specified as the
|
||||
file did not exist. In doing this, at first the change to check for a NULL file
|
||||
was added. Then it was noticed that the problem is that `adgrep.c` was an
|
||||
incorrect reference that was never fixed in any of the files, not the code or
|
||||
the documentation. A fun fact is that one can do:
|
||||
Not fixing the above problem would have also cause the program to crash if no
|
||||
arg was specified as the file doesn't exist. In making the above fix, at first
|
||||
the change to check for a `NULL` file was added. Then it was noticed that the
|
||||
problem is that `adgrep.c` was an incorrect reference that never existed and it
|
||||
was never fixed in any of the files, not the code or the documentation, and thus
|
||||
was entirely incorrect code. A fun fact is that one can do:
|
||||
|
||||
```c
|
||||
W= fopen(wc>= 2 ? V[1] : __FILE__,"rt");if(!W)exit(1);
|
||||
@@ -1423,24 +1424,24 @@ Cody also restored a slightly more obscure line of code that had been changed:
|
||||
+ putc(i["}|uutsrq`_^bji`[Zkediml[PO]a_M__]ISOYIRGTNR"]+i-9,stderr);
|
||||
```
|
||||
|
||||
though it's questionable how much more (if at all) obscure that is.
|
||||
though it's questionable how much more (if at all) obscure that is :-)
|
||||
|
||||
Cody also changed the location that it used `gets()` to be `fgets()` instead to
|
||||
make it safer and to prevent annoying warnings during compiling, linking or
|
||||
runtime (interspersed with the program's output). This was complicated because
|
||||
of how the other source files are generated, as noted above; simply changing the
|
||||
code could cause invalid output in the program which made other files fail to
|
||||
compile (for this example specifically, see below).
|
||||
of how the other source files are generated (as above); simply changing the code
|
||||
could cause invalid output in the program which made other files fail to compile
|
||||
(for this example specifically, see below).
|
||||
|
||||
One might think that simply changing the `gets()` to `fgets()` (with `stdin`)
|
||||
would work but it did not because `fgets()` stores the newline and `gets()` does
|
||||
not. That is well known but this code was relying on not having this newline
|
||||
(see also above).
|
||||
not. That is well known but this code was relying on not having this newline in
|
||||
a different way (see also above).
|
||||
|
||||
With `fgets()` the code `if(A(Y)) puts(Y);` ended up printing an extra line
|
||||
which made the generation of some files (like `adhead.c`) fail to compile. Why?
|
||||
There was a blank line after a `\` at the end of the first line of a macro
|
||||
definition! Thus the code now first trims off the last character of the buffer
|
||||
There was a blank line after a `\` at the end of the first line of a _macro
|
||||
definition_! Thus the code now first trims off the last character of the buffer
|
||||
read to get the same correct functionality but in a safe and non obnoxious way.
|
||||
|
||||
Later Cody improved the change to `fgets()` to make it slightly more like the
|
||||
@@ -1467,9 +1468,10 @@ the additional tools.
|
||||
|
||||
Cody fixed this to compile with modern systems. Note that in 1996 a bug fix was
|
||||
applied to the code, provided as the alt code as that version is not obfuscated.
|
||||
Thus Cody's fixed applies to the original entry. The problems were that
|
||||
`malloc.h` is not the correct header file now and a non-void (implicit int)
|
||||
function returning without a value. The function was changed to return void.
|
||||
Thus Cody's fix applies to the original entry. The problems were that `malloc.h`
|
||||
is not the correct header file now (at least in some systems?) and a non-void
|
||||
(implicit int) function returning without a value. That function was changed to
|
||||
return void.
|
||||
|
||||
|
||||
## [1992/ant](1992/ant/ant.c) ([README.md](1992/ant/README.md]))
|
||||
@@ -1495,7 +1497,8 @@ necessary to include `time.h` so Cody did this as well.
|
||||
|
||||
Cody added a check for the right number of args, exiting 1 if not enough (2)
|
||||
used. This was not originally done but at a time it was changed to be considered
|
||||
a bug so it was fixed at that point as it only took a few seconds.
|
||||
a bug so it was fixed at that point as it only took a few seconds and had to be
|
||||
verified that it was consistent with the [bugs.md](/bugs.md) file.
|
||||
|
||||
He also added the [try.sh](1991/buzzard.1/try.sh) script to try out some
|
||||
commands that we suggested and some additional ones that provide for some fun.
|
||||
@@ -1522,14 +1525,15 @@ loop).
|
||||
|
||||
Cody also added the [mkdict.sh](1992/gson/mkdict.sh) script that the author
|
||||
included in their remarks. See the README.md for its purpose. It was NOT fixed
|
||||
for ShellCheck because the author deliberately obfuscated it.
|
||||
for ShellCheck because the author deliberately obfuscated it so **PLEASE DO NOT
|
||||
FIX THIS**.
|
||||
|
||||
|
||||
## [1992/imc](1992/imc/imc.c) ([README.md](1992/imc/README.md]))
|
||||
|
||||
The original code, [imc.orig.c](1992/imc/imc.orig.c), assumed that `exit(3)`
|
||||
returned a value but this will cause problems where `exit(3)` returns void. The
|
||||
source code was modified to avoid this problem but like Cody did with otherfixes
|
||||
source code was modified to avoid this problem but like Cody did with other fixes
|
||||
he made this more like the original by redefining `exit` to use the comma
|
||||
operator so that it could be used in binary expressions.
|
||||
|
||||
@@ -1537,16 +1541,17 @@ operator so that it could be used in binary expressions.
|
||||
## [1992/kivinen](1992/kivinen/kivinen.c) ([README.md](1992/kivinen/README.md]))
|
||||
|
||||
It was observed that on modern systems this goes much too quick. Yusuke created
|
||||
a patch that calls `usleep()` but Cody thought the value was too slow so he made
|
||||
it a macro in the Makefile `Z`, defaulting at 15000. You can reconfigure it
|
||||
like:
|
||||
a patch that calls `usleep(3)` but Cody thought the value was too slow so he
|
||||
made it a macro in the Makefile `Z`, defaulting at 15000. This was made an [alt
|
||||
version](1992/kivinen/kivinen.alt.c) and it is recommended one use the alt
|
||||
version first. See the README.md file to see how to reconfigure it.
|
||||
|
||||
```sh
|
||||
make clobber Z=1000 all
|
||||
```
|
||||
|
||||
This was not made an alternate version because it moves so fast that it's nigh
|
||||
impossible to use otherwise.
|
||||
Cody also made the fixed version (the code relied on `exit(3)` returning to use
|
||||
in binary expressions) (and alt code from it) more like the original by renaming
|
||||
the `ext` macro to be `exit` which uses the comma operator. He made it so the
|
||||
line lengths match the original code, at least as best as possible (if not
|
||||
perfectly), including start and end columns, often (if not all) with the same
|
||||
start and end character.
|
||||
|
||||
Yusuke also noted that there is a bug in the program where right after starting
|
||||
it moves towards the right but if you click the mouse it goes back.
|
||||
@@ -2045,9 +2050,13 @@ exiting the program.
|
||||
|
||||
## [1998/fanf](1998/fanf/fanf.c) ([README.md](1998/fanf/README.md))
|
||||
|
||||
Cody fixed this for Linux. The problem was the intermediate steps to get to the
|
||||
final code that is compiled. The entry itself is what was essentially what used
|
||||
to be compiled. Now it works with both Linux and macOS (and BSD?).
|
||||
Cody fixed this to compile. The problem was the intermediate steps to get to the
|
||||
final code that is compiled. The code is now what it essentially becomes when
|
||||
processed completely. The intermediate steps can now be performed to see how it
|
||||
expands but it can still compile and be used.
|
||||
|
||||
Cody also added the [try.sh](1998/fanf/try.sh) script to show the output of some
|
||||
of the expressions that we selected.
|
||||
|
||||
|
||||
## [1998/schnitzi](1998/schnitzi/schnitzi.c) ([README.md](1998/schnitzi/README.md]))
|
||||
@@ -2055,8 +2064,9 @@ to be compiled. Now it works with both Linux and macOS (and BSD?).
|
||||
Cody fixed invalid data types which prevented this entry from working, causing a
|
||||
segfault. This showed itself in two parts which required two fixes, one for
|
||||
linux and further changes for macOS. He also fixed a segfault (after printing
|
||||
garbage) when the arg specified evaluated to 0. It was decided that these
|
||||
segfault fixes should be made because the program is so beautiful.
|
||||
garbage) when the arg specified evaluated to 0. It was decided by us, the
|
||||
judges, that these segfault fixes should be made because the program is so
|
||||
beautiful.
|
||||
|
||||
Later on Cody improved the fixes by checking that the arg is a number `>0 &&
|
||||
<27` as that was noted by the author as a requirement and again since it's such
|
||||
@@ -2081,16 +2091,16 @@ alternate version that works with macOS. Cody also made it ever so slightly more
|
||||
portable by removing the hard-coding of `gcc`, instead hard-coding it `cc`. Doing
|
||||
this not only lets it work with systems without `gcc` (though in macOS it does
|
||||
exist but is actually `clang`) as `cc` always should.
|
||||
|
||||
Getting this entry to work was quite complicated but is also very interesting.
|
||||
To see how the macOS fixes works, see the README.md but do note that this
|
||||
includes spoilers for both versions! The fixes to get it to work at all are
|
||||
described next.
|
||||
|
||||
To see how the macOS fixes works, see the [macos.md](1998/schweikh1/macos.md)
|
||||
file but do note that this includes spoilers for both versions! The fixes to get
|
||||
it to work at all are described next.
|
||||
|
||||
So what was wrong with the original?
|
||||
|
||||
The call to `freopen()` was incorrect with the second arg (the mode) being
|
||||
`5+__FILE__`; it is now `"r"`. (Observe that the mode to the `fopen()`
|
||||
The call to `freopen(3)` was incorrect with the second arg (the mode) being
|
||||
`5+__FILE__`; it is now `"r"`. (Observe that the mode to the `fopen(3)`
|
||||
call is: `43+__FILE__`. This might seem incorrect and indeed it can be changed
|
||||
to `"r"` as well but this was not actually necessary so once this was noticed it
|
||||
was changed back to the original.)
|
||||
@@ -2127,9 +2137,9 @@ as the author stated: as long as the options `-E -dM` of the compiler prints out
|
||||
the macros in the form of `gcc -dM` i.e. the lines are in the form `#define
|
||||
MACRO value` it will work, assuming that compiler can run, of course.
|
||||
|
||||
As for the version for macOS, the even more complicated details are described in
|
||||
the [Alternate code](1998/schweikh1/README#alternate-code) section of the
|
||||
README.md file as these changes pertain to the described version therein.
|
||||
Cody also added the perl script that the author provided that they used to
|
||||
compute the character count in the code according to the contest rules of 1998
|
||||
in the file [charcount.pl](1998/schweikh1/charcount.pl).
|
||||
|
||||
|
||||
## [1998/schweikh2](1998/schweikh2/schweikh2.c) ([README.md](1998/schweikh2/README.md]))
|
||||
@@ -2158,10 +2168,38 @@ command.
|
||||
Cody also made the Makefile rule `all` symlink the entry to `samefile` as that
|
||||
is the name of the program.
|
||||
|
||||
The author stated that:
|
||||
|
||||
```
|
||||
In the remote event that the input has more than `8192` files with
|
||||
the same size (on systems where `sizeof (char *) == 4`, or `4096` when
|
||||
`sizeof (char *) == 8`), increase the manifest constant 32767 on line
|
||||
31.
|
||||
```
|
||||
|
||||
so Cody changed the constant to a macro in the Makefile called `SZ` so one can
|
||||
more easily do this (though it indeed seems highly unlikely). See the README.md
|
||||
for more details.
|
||||
|
||||
There actually is a web page for the tool and this was added to the author
|
||||
information for the entry. It has not been added to any JSON file.
|
||||
|
||||
|
||||
## [1998/tomtorfs](1998/tomtorfs/tomtorfs.c) ([README.md](1998/tomtorfs/README.md]))
|
||||
|
||||
Cody fixed the assumption that `EOF` is `-1` (the author noted that it assumes
|
||||
it is `-1` and it's indeed a valid concern as the standard only guarantees that
|
||||
it's a value `< 0`) and that `1` is a valid code to return failure (it seems
|
||||
unlikely that it wouldn't be but since the author suggested it it was changed to
|
||||
`EXIT_FAILURE`). To make it so the lines end at the same columns as the original
|
||||
the `EXIT_FAILURE` change was done by redefining `exit(3)` to be `exit(a) return
|
||||
EXIT_FAILURE` and `1` was passed to it (`return` was used because the original
|
||||
program had `return 1`).
|
||||
|
||||
Cody also added the [try.sh](1998/tomtorfs/try.sh) script to try out a few
|
||||
commands that we recommended.
|
||||
|
||||
|
||||
## [2000/anderson](2000/anderson/anderson.c) ([README.md](2000/anderson/README.md]))
|
||||
|
||||
Cody changed this entry to use `fgets()` instead of `gets()` to make it safer
|
||||
|
||||
Reference in new issue
Block a user