Portable Self-Replicating C Contest

Karl Heuer karl at haddock.ima.isc.com
Sat Apr 8 07:08:09 AEST 1989


I've received several contest entries by mail.  Our gateway has been flakey,
so if you haven't gotten a response, try again.  I reply to each entry.

My reply has almost become a form letter, since I keep seeing the same
mistakes.  So I guess it's time for a followup.  Here are the rules from my
original article:

>0.  The output of the program must be its own source code.
>1.  It may not be safely assumed that the source code resides in an openable
>    file at runtime.
>2.  The program must be written in Strictly Conforming ANSI C.
>3.  The program must return a proper exit status, indicating whether or not
>    its output-calls succeeded.
>4.  The source must use only the ISO 646 character set, using trigraphs as
>    needed.
>5.  No source line may exceed 72 characters.
>6.  There will be two winners: the first correct program to arrive at my site,
>    and the shortest (measured in source characters, including newlines).  The
>    contest ends on 23-Apr-1989.  No prizes will be awarded.

Note rule 3.  Output calls can fail (e.g. disk full); the program must detect
this condition and return the value EXIT_FAILURE to the execution environment.
This constant is defined in <stdlib.h>, which must therefore be included.

Note rule 4 especially.  The nine characters   # ^ ~ { | } [ \ ]  are not
allowed to appear in the source; you must use the trigraph equivalents   ??=
??' ??- ??< ??! ??> ??( ??/ ??)   instead.  Only one entrant has observed this
rule so far!

I should also point out that assumptions such as '"'==34 are an artifact of
the ASCII character set, which a strictly conforming program may not rely on.

I use the enclosed shell script as a preliminary test.  If you don't have
<stdlib.h>, or if your compiler doesn't understand trigraphs, you might find
it useful.

Karl W. Z. Heuer (ima!haddock!karl or karl at haddock.isc.com), The Walking Lint
________
#!/bin/sh
# Accepts a program by file name, or on standard input.
PATH=/bin:/usr/bin:/usr/ucb; export PATH
E=2; T=/tmp/$$self.d; trap 'rm -rf $T; trap 0; exit $E' 0 1 2 3 15
mkdir $T; cat $1 >$T/self.src; cd $T
if [ `tr -cd '#^~[\\]{|}' <self.src | wc -c` != 0 ]; then
    echo 'bad character set'; E=1
fi
awk '{if (length>72) {print "too wide"; exit 1}}' <self.src || E=1
if grep printf <self.src >/dev/null; then
    if egrep '\.\.\.|stdio' <self.src >/dev/null; then :; else
	echo 'printf not declared'; E=1
    fi
fi
sed -e "s/??=/#/g" -e "s/??'/^/g" -e "s/??!/|/g" -e "s/??-/~/g" \
	 -e "s/??</{/g" -e "s/??>/}/g" -e "s/??(/[/g" -e "s/??)/]/g" \
	 -e 's;??/;\\;g' <self.src >self.c
cat <<\! >stdlib.h
#define EXIT_SUCCESS 0
#define EXIT_FAILURE 1
!
${CC-/bin/cc} -I. self.c -o self && ./self | cmp - self.src || E=1
if [ "$E" = "2" ]; then echo 'looks good'; E=0; fi



More information about the Comp.std.c mailing list