Merge pull request #1396 from xexyl/fanf-98

This commit is contained in:
Landon Curt Noll authored and GitHub committed 2023-11-12 09:26:10 -07:00
commit b1e339cdbe
26 files changed
+623 -295

No files matched your search

+28
View File
@@ -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
View File
@@ -1,3 +1,4 @@
kivinen
kivinen.alt
kivinen.orig
prog.orig
+3 -3
View File
@@ -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
View File
@@ -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:
+39
View File
@@ -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;}
+4 -4
View File
@@ -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);}
+2
View File
@@ -1,5 +1,7 @@
fanf
fanftmp1.c
fanftmp1
fanftmp2.c
fanftmp2
fanf.orig
prog.orig
+4 -2
View File
@@ -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
View File
@@ -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.
+41
View File
@@ -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
+6 -6
View File
@@ -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
View File
@@ -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
+8
View File
@@ -0,0 +1,8 @@
#!/usr/bin/perl -w
$/ = "\0";
$_ = <>;
s/[;{}][ \t\n]/\n/g;
s/[ \t\n]+//g;
print length ($_),"\n";
+70
View File
@@ -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.
+10 -7
View File
@@ -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
+1 -1
View File
@@ -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
View File
@@ -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.
+1 -1
View File
@@ -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;
+3
View File
@@ -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
View File
@@ -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.
+3 -2
View File
@@ -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]
+23
View File
@@ -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
+62
View File
@@ -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)); }
+4 -3
View File
@@ -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
+1 -1
View File
@@ -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
View File
@@ -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