Portable Self-Replicating C Contest

Karl Heuer karl at haddock.ima.isc.com
Fri Apr 28 13:03:53 AEST 1989


# Compilation Copyright (c) 1989 by Karl Heuer.  I don't care what you do with
# this article, but the right to resubmit these programs to the IOCCC remains
# with the original authors.

#!/bin/sh
: run this file through sh to unbundle
:    README scjones diomidis
cat <<\--------cut-------- >README
Well, the contest is over, and here are the results.  For those of you who
missed the beginning of this, the challenge was to write a self-reproducing
program which is strictly pANS-conforming (to the letter!), had a proper exit
status, was no more than 72 characters wide, and used only the characters in
ISO 646 (using trigraphs as needed).  (I should also have had a rule against
using any obsolescent feature, but I didn't think of that in time.)  To the
best of my knowledge, the two enclosed programs were the only entries that
satisfied all of the rules.  If someone still manages to spot a flaw in either
of these, I'll be impressed.

The Early Bird Winner was Larry Jones <scjones at sdrc.UU.NET>.  His entry
demonstrated that I should have said "columns" instead of "characters" in the
width requirement (he used tabs), but that's not important.  (If I'd insisted
on rephrasing the rule, a simple `tr \\11 \\40' would have fixed his entry.)
Note that he didn't resort to printf trickery to construct trigraphs for
output; he just used the straightforward notation like `???/?/'.  I like that.

The winner for shortest program was Diomidis Spinellis <ecrcvax!diomidis>, at
499 characters.  Interestingly enough, there was still some slack here; it
would still be strictly conforming to drop the `int' declaration from main()
and to use 0 rather than EXIT_SUCCESS, for example.  This entry deserves a
special award for the clever use of the `#' operator to do most of the work;
that possibility hadn't occurred to me.  (It should also be pointed out that
this program cannot be directly tested with gcc 1.32, because of a bug in the
gnu preprocessor that was discovered when he submitted an earlier attempt.)

A few other entries were only slightly flawed, and probably could have been
fixed if the deadline hadn't expired first.  I apologize for the sometimes
long turnaround time on reporting such flaws; besides my having other business
to take care of, we had severe problems with our mail gateway.  (I considered
extending the duration of the contest as a sporting gesture, but I'm getting
rather tired of this.  If you want to improve on these, you can do it without
my help.)

When I first thought about this puzzle, I was thinking in terms of the simple
program (shown here folded)
	char*f="char*f=%c%s%c;main(){printf(f,34,f,34,10);}%c";\
	main(){printf(f,34,f,34,10);}
and wondered how much effort it would be to make it portable.  After fixing
the hardcoded ASCII values, entrigraphing, adding required headers, and
checking the exit status, the program had grown to:
	??=include<stdlib.h>
	??=include<stdio.h>
	char*f="?%c=include<stdlib.h>%c?%c=include<stdio.h>%cchar*f=%c%s%c,\
	t='?',n='?%c/n',q='%c';main()?%c<exit(printf(f,t,n,t,n,q,f,q,t,q,t,\
	t,n)<0?EXIT_FAILURE:0);?%c>%c",t='?',n='??/n',q='"';main()??<exit(p\
	rintf(f,t,n,t,n,q,f,q,t,q,t,t,n)<0?EXIT_FAILURE:0);??>
and I still needed a way to break up that 255-character third line.  At this
point I gave up on the single-printf approach, though I'd be interested to
hear if anybody can salvage it.
--------cut--------
cat <<\--------cut-------- >scjones
static const char *foo??(??) = ??<
"??=include <stdio.h>??/n",
"??=include <stdlib.h>??/n",
"??/n",
"void out(q, f)??/n",
"	const char *q;??/n",
"	int f;??/n",
"	??<??/n",
"	for (;; q++) ??<??/n",
"		switch (*q) ??<??/n",
"		case 0:??/n",
"			if (f) fputs(??/"??/??/??/",??/??/n??/??/??/"??/", stdout);??/n",
"			return;??/n",
"		case '??=':??/n",
"			fputs(??/"???/??/?=??/", stdout);??/n",
"			break;??/n",
"		case '??<':??/n",
"			fputs(??/"???/??/?<??/", stdout);??/n",
"			break;??/n",
"		case '??>':??/n",
"			fputs(??/"???/??/?>??/", stdout);??/n",
"			break;??/n",
"		case '??(':??/n",
"			fputs(??/"???/??/?(??/", stdout);??/n",
"			break;??/n",
"		case '??)':??/n",
"			fputs(??/"???/??/?)??/", stdout);??/n",
"			break;??/n",
"		case '??/??/??/??/':??/n",
"			if (f) fputs(??/"???/??/?/??/", stdout);??/n",
"			fputs(??/"???/??/?/??/", stdout);??/n",
"			break;??/n",
"		case '??/??/n':??/n",
"			if (f) fputs(??/"???/??/?/n??/", stdout);??/n",
"			else putchar(*q);??/n",
"			break;??/n",
"		case '??/"':??/n",
"			if (f) fputs(??/"???/??/?/??/??/??/"??/", stdout);??/n",
"			else putchar(*q);??/n",
"			break;??/n",
"		default:??/n",
"			putchar(*q);??/n",
"			??>??/n",
"		??>??/n",
"	??>??/n",
"??/n",
"main()??/n",
"	??<??/n",
"	const char **p;??/n",
"??/n",
"	out(??/"static const char *foo??(??) = ??<??/??/n??/", 0);??/n",
"	out(??/"??/??/??/"??/", 0);??/n",
"	for (p = foo; **p; p++) out(*p, 1);??/n",
"	out(??/"??/??/??/"??>;??/??/n??/", 0);??/n",
"	for (p = foo; **p; p++) out(*p, 0);??/n",
"	exit(ferror(stdout) ? EXIT_FAILURE : EXIT_SUCCESS);??/n",
"	??>??/n",
""??>;
??=include <stdio.h>
??=include <stdlib.h>

void out(q, f)
	const char *q;
	int f;
	??<
	for (;; q++) ??<
		switch (*q) ??<
		case 0:
			if (f) fputs("??/",??/n??/"", stdout);
			return;
		case '??=':
			fputs("???/?=", stdout);
			break;
		case '??<':
			fputs("???/?<", stdout);
			break;
		case '??>':
			fputs("???/?>", stdout);
			break;
		case '??(':
			fputs("???/?(", stdout);
			break;
		case '??)':
			fputs("???/?)", stdout);
			break;
		case '??/??/':
			if (f) fputs("???/?/", stdout);
			fputs("???/?/", stdout);
			break;
		case '??/n':
			if (f) fputs("???/?/n", stdout);
			else putchar(*q);
			break;
		case '"':
			if (f) fputs("???/?/??/"", stdout);
			else putchar(*q);
			break;
		default:
			putchar(*q);
			??>
		??>
	??>

main()
	??<
	const char **p;

	out("static const char *foo??(??) = ??<??/n", 0);
	out("??/"", 0);
	for (p = foo; **p; p++) out(*p, 1);
	out("??/"??>;??/n", 0);
	for (p = foo; **p; p++) out(*p, 0);
	exit(ferror(stdout) ? EXIT_FAILURE : EXIT_SUCCESS);
	??>
--------cut--------
cat <<\--------cut-------- >diomidis
??=include<stdlib.h>
??=include<stdio.h>
??=include<string.h>
??=define P(x)char*w=??=x;x
P(p(char
q)
??<if(putchar(q)==EOF)exit(EXIT_FAILURE);??>
o(char*s)
??<char*q;char*t="??<??>??=??/??/??(??)";for(;*s;s++)if(q=strchr(t,*s))
??<o("??");p("<>=/()"??(q-t??));??>else
if(!strchr("'Pc<",s??(1??))&&*s==' ')p('??/n');else
p(*s);??>
int
main()
??<o("??=include<stdlib.h>??/n??=include<stdio.h>??/n??=include<str"
"ing.h>??/n??=define P(x)char*w=??=x;x??/nP(");
o(w);o(")??/n");exit(EXIT_SUCCESS);??>)
--------cut--------
exit 0



More information about the Comp.std.c mailing list