Home | Gaming | Programming | Play Online | Contact | Keyword Query
Games++ Games & Game Programming

C For Dummies®, Volume One & Two Bundle

C For Dummies®, Volume One & Two Bundle

The C Answer Book 2nd Edition.

The C Answer Book 2nd Edition.

Absolute Beginner's Guide to C (2nd Edition)

Absolute Beginner's Guide to C (2nd Edition)

Self Replicating Code

A recent posting of a generator for self-extracting compressed program reminded me of the self-replicating program I posted a year or two back (after one of the inevitable rounds of discussion about same). Since I'd played around a bit more with it, I decided to dust it off and fix it up a bit.

There are actually three separate versions of programs here. The interesting part is that it is a fairly general shell for building self-replicating programs. Obviously, the job can be done much more easily if the only goal is to write a program that can re-create it's source.

Instructions for use: snip and copy to a file, compile it, create a new directory and cd to it, then run the program.

e.g.
cc -o replicate replicate.c
mkdir self
cd self
../replicate

This will create a makefile and several source files. The file "selfcopy.c" in the new directory should be the same as what I'm posting. "make test" will build and test all three versions.

The three programs are:

  1. self just reproduces its source on stdout
  2. selfshar reproduces on stdout a shar file that contains the sources for re-creating a new version of itself (requires "shar")
  3. replicate creates the source tree for building itself and the other two programs (in the current directory); also creates a file selfcopy.c, which should be identical to replicate.c

Sorry for the lack of comments.

Here is replicate.c:

char	*selfish[] = {
"#include \n",
"\n",
"void\tdup(p, out)\n",
"\tchar\t*p[];\n",
"\tFILE\t*out;\n",
"{\n",
"\tchar\t*c;\n",
"\n",
"\twhile (c = *p++)\n",
"\t\tfputs(c, out);\n",
"}\n",
"\n",
"void\tmakehead(aname, out)\n",
"\tchar\t*aname;\n",
"\tFILE\t*out;\n",
"{\n",
"\tfprintf(out, \"char\\t*%s[] = {\\n\", aname);\n",
"}\n",
"\n",
"void\tmakeline(c, out)\n",
"\tchar\t*c;\n",
"\tFILE\t*out;\n",
"{\n",
"\tchar\tch;\n",
"\n",
"\tputc('\"', out);\n",
"\twhile (ch = *c++) {\n",
"\t\tif ((ch == '\"') || (ch == '\\\\') || (ch == '\\n') ||\n",
"\t\t\t(ch == '\\t'))\n",
"\t\t\tputc('\\\\', out);\n",
"\t\tif (ch == '\\n')\n",
"\t\t\tputc('n', out);\n",
"\t\telse if (ch == '\\t')\n",
"\t\t\tputc('t', out);\n",
"\t\telse\n",
"\t\t\tputc(ch, out);\n",
"\t}\n",
"\tfputs(\"\\\",\\n\", out);\n",
"}\n",
"\n",
"void\tmaketail(out)\n",
"\tFILE\t*out;\n",
"{\n",
"\tfputs(\"0};\\n\\n\", out);\n",
"}\n",
"\n",
"void\tclone(aname, p, out)\n",
"\tchar\t*aname;\n",
"\tchar\t*p[];\n",
"\tFILE\t*out;\n",
"{\n",
"\tmakehead(aname, out);\n",
"\twhile (*p)\n",
"\t\tmakeline(*p++, out);\n",
"\tmaketail(out);\n",
"}\n",
"\n",
"void\tclonehead(aname, out)\n",
"\tchar\t*aname;\n",
"\tFILE\t*out;\n",
"{\n",
"\tfprintf(out, \"\\nstruct self {\\n\");\n",
"\tfprintf(out, \"\\tchar\\t**txt;\\n\");\n",
"\tfprintf(out, \"\\tchar\\t*name;\\n\");\n",
"\tfprintf(out, \"\\tchar\\t*file;\\n\");\n",
"\tfprintf(out, \"} %s[] = {\\n\", aname);\n",
"}\n",
"\n",
"void\tcloneline(aname, afile, out)\n",
"\tchar\t*aname;\n",
"\tchar\t*afile;\n",
"\tFILE\t*out;\n",
"{\n",
"\tfprintf(out, \"\\t%s, \\\"%s\\\", \\\"%s\\\",\\n\", aname, aname, afil",
"e);\n",
"}\n",
"\n",
"void\tclonetail(aname, afile, out)\n",
"\tchar\t*aname;\n",
"\tchar\t*afile;\n",
"\tFILE\t*out;\n",
"{\n",
"\tfprintf(out, \"\\t0, \\\"%s\\\", \\\"%s\\\"\\n\", aname, afile);\n",
"\tfprintf(out, \"};\\n\\n\");\n",
"}\n",
0};

char	*replicate[] = {
"void\tcloneself(last, out)\n",
"\tstruct self\t*last;\n",
"\tFILE\t*out;\n",
"{\n",
"\tstruct self\t*p;\n",
"\n",
"\tclonehead(last->name, out);\n",
"\tfor (p = self; p->txt; p++)\n",
"\t\tcloneline(p->name, p->file, out);\n",
"\tclonetail(last->name, last->file, out);\n",
"}\n",
"\n",
"void\tdupself(out)\n",
"{\n",
"\tstruct self\t*p;\n",
"\n",
"\tfor (p = self; p->txt; p++)\n",
"\t\tclone(p->name, p->txt, out);\n",
"\tcloneself(p, out);\n",
"\tdup(self[0].txt, out);\n",
"\tdup(self[1].txt, out);\n",
"}\n",
"\n",
"void\tdupfile(p)\n",
"\tstruct self\t*p;\n",
"{\n",
"\tFILE\t*out;\n",
"\n",
"\tif (!(out = fopen(p->file, \"w\"))) {\n",
"\t\tfprintf(stderr, \"dupfile: create \");\n",
"\t\tperror(p->file);\n",
"\t\texit(1);\n",
"\t}\n",
"\tif (p->txt)\n",
"\t\tdup(p->txt, out);\n",
"\telse\n",
"\t\tdupself(out);\n",
"\tfclose(out);\n",
"}\n",
"\n",
"void\tdupfiles()\n",
"{\n",
"\tstruct self\t*p;\n",
"\n",
"\tfor (p = self; p->txt; p++)\n",
"\t\tdupfile(p);\n",
"\tdupfile(p);\n",
"}\n",
"\n",
"int\tmain(argc, argv)\n",
"\tint\targc;\n",
"\tchar\t*argv[];\n",
"{\n",
"\tdupfiles();\n",
"\treturn 0;\n",
"}\n",
0};

char	*replicant[] = {
"\n",
"int\tmain()\n",
"{\n",
"\tclone(\"self\", self, stdout);\n",
"\tclone(\"replicant\", replicant, stdout);\n",
"\tdup(self, stdout);\n",
"\tdup(replicant, stdout);\n",
"}\n",
0};

char	*shar[] = {
"#include \n",
"\n",
"int\tmain()\n",
"{\n",
"\tchar\t**p;\n",
"\tchar\t*s;\n",
"\n",
"\tp = shar;\n",
"\twhile (s = *p++)\n",
"\t\tfputs(s, stdout);\n",
"\treturn 0;\n",
"}\n",
0};

char	*make[] = {
"all:\tself selfshar replicate\n",
"\n",
"test:\tall\n",
"\trm -rf cmp\n",
"\tmkdir cmp\n",
"\t./self > cmp/self.c\n",
"\tcmp self.c cmp/self.c\n",
"\trm -f cmp/*\n",
"\t./selfshar > cmp/shar\n",
"\tcd cmp; unshar shar; make selfshar; ./selfshar > shar\n",
"\tcmp cmp/shar cmp/self.shar\n",
"\trm -f cmp/*\n",
"\tcd cmp; ../replicate\n",
"\tcmp replicate.c cmp/selfcopy.c\n",
"\tcd cmp; make replicate.c\n",
"\tcmp replicate.c cmp/replicate.c\n",
"\trm -rf cmp\n",
"\n",
"self:\tself.c\n",
"\tcc -o self self.c\n",
"\n",
"self.c:\tmakeself replicant.self\n",
"\t./makeself self selfish.c replicant replicant.self - selfi",
"sh.c replicant.self > self.c\n",
"\n",
"selfshar:\tselfshar.c\n",
"\tcc -o selfshar selfshar.c\n",
"\n",
"selfshar.c:\tmakeself self.shar\n",
"\t./makeself shar self.shar - selfshar.self > selfshar.c\n",
"\n",
"self.shar:\tselfish.c clone.c makeself.c selfshar.self Makef",
"ile\n",
"\tshar selfish.c clone.c makeself.c selfshar.self Makefile >",
" self.shar\n",
"\n",
"replicate:\treplicate.c\n",
"\tcc -o replicate replicate.c\n",
"\n",
"replicate.c:\tmakeself replicate.self replicant.self selfsha",
"r.self Makefile\n",
"\t./makeself selfish selfish.c replicate replicate.self repl",
"icant replicant.self shar selfshar.self make Makefile build",
" makeself.c cloner clone.c -self selfcopy.c selfish.c repli",
"cate.self > replicate.c\n",
"\n",
"makeself:\tmakeself.o selfish.o clone.o\n",
"\tcc -o makeself makeself.o selfish.o clone.o\n",
"\n",
"clean:\n",
"\trm -f replicate.c self.c selfshar.c replicate self selfsha",
"r self.shar copy.c\n",
"\n",
"realclean:\tclean\n",
"\trm -f *.o makeself\n",
"\trm -rf cmp\n",
0};

char	*build[] = {
"#include \n",
"\n",
"int\tmain(argc, argv)\n",
"\tint\targc;\n",
"\tchar\t*argv[];\n",
"{\n",
"\tint\tindex;\n",
"\tint\tclonal;\n",
"\n",
"\tclonal = 0;\n",
"\tfor (index = 1; index < argc; index += 2) {\n",
"\t\tif (*argv[index] == '-') {\n",
"\t\t\tclonal = index;\n",
"\t\t\tbreak;\n",
"\t\t}\n",
"\t\tmakeself(argv[index], argv[index+1], stdout);\n",
"\t}\n",
"\tif (clonal) {\n",
"\t\tif (argv[clonal][1]) {\n",
"\t\t\tclonehead(argv[clonal]+1, stdout);\n",
"\t\t\tfor (index = 1; index < clonal; index += 2)\n",
"\t\t\t\tcloneline(argv[index], argv[index+1], stdout);\n",
"\t\t\tclonetail(argv[clonal]+1, argv[clonal+1], stdout);\n",
"\t\t\tclonal += 1;\n",
"\t\t}\n",
"\t\tfor (index = clonal + 1; index < argc; index += 1)\n",
"\t\t\tcopyfile(argv[index], stdout);\n",
"\t}\n",
"\treturn 0;\n",
"}\n",
0};

char	*cloner[] = {
"#include \n",
"\n",
"#define\tMAXLINE\t60\n",
"\n",
"void\tmakeself(aname, fname, out)\n",
"\tchar\t*aname;\n",
"\tchar\t*fname;\n",
"\tFILE\t*out;\n",
"{\n",
"\tFILE\t*in;\n",
"\tchar\tp[MAXLINE];\n",
"\n",
"\tif (!(in = fopen(fname, \"r\"))) {\n",
"\t\tfprintf(stderr, \"makeself: create \");\n",
"\t\tperror(fname);\n",
"\t\texit(1);\n",
"\t}\n",
"\tmakehead(aname, out);\n",
"\twhile (fgets(p, MAXLINE, in))\n",
"\t\tmakeline(p, out);\n",
"\tmaketail(out);\n",
"\tfclose(in);\n",
"}\n",
"\n",
"void\tcopyfile(fname, out)\n",
"\tchar\t*fname;\n",
"\tFILE\t*out;\n",
"{\n",
"\tFILE\t*in;\n",
"\tchar\ts[MAXLINE];\n",
"\n",
"\tif (!(in = fopen(fname, \"r\"))) {\n",
"\t\tfprintf(stderr, \"copyfile: open \");\n",
"\t\tperror(fname);\n",
"\t\texit(1);\n",
"\t}\n",
"\twhile (fgets(s, MAXLINE, in))\n",
"\t\tfputs(s, out);\n",
"\tfclose(in);\n",
"}\n",
0};


struct self {
	char	**txt;
	char	*name;
	char	*file;
} self[] = {
	selfish, "selfish", "selfish.c",
	replicate, "replicate", "replicate.self",
	replicant, "replicant", "replicant.self",
	shar, "shar", "selfshar.self",
	make, "make", "Makefile",
	build, "build", "makeself.c",
	cloner, "cloner", "clone.c",
	0, "self", "selfcopy.c"
};

#include 

void	dup(p, out)
	char	*p[];
	FILE	*out;
{
	char	*c;

	while (c = *p++)
		fputs(c, out);
}

void	makehead(aname, out)
	char	*aname;
	FILE	*out;
{
	fprintf(out, "char\t*%s[] = {\n", aname);
}

void	makeline(c, out)
	char	*c;
	FILE	*out;
{
	char	ch;

	putc('"', out);
	while (ch = *c++) {
		if ((ch == '"') || (ch == '\\') || (ch == '\n') ||
			(ch == '\t'))
			putc('\\', out);
		if (ch == '\n')
			putc('n', out);
		else if (ch == '\t')
			putc('t', out);
		else
			putc(ch, out);
	}
	fputs("\",\n", out);
}

void	maketail(out)
	FILE	*out;
{
	fputs("0};\n\n", out);
}

void	clone(aname, p, out)
	char	*aname;
	char	*p[];
	FILE	*out;
{
	makehead(aname, out);
	while (*p)
		makeline(*p++, out);
	maketail(out);
}

void	clonehead(aname, out)
	char	*aname;
	FILE	*out;
{
	fprintf(out, "\nstruct self {\n");
	fprintf(out, "\tchar\t**txt;\n");
	fprintf(out, "\tchar\t*name;\n");
	fprintf(out, "\tchar\t*file;\n");
	fprintf(out, "} %s[] = {\n", aname);
}

void	cloneline(aname, afile, out)
	char	*aname;
	char	*afile;
	FILE	*out;
{
	fprintf(out, "\t%s, \"%s\", \"%s\",\n", aname, aname, afile);
}

void	clonetail(aname, afile, out)
	char	*aname;
	char	*afile;
	FILE	*out;
{
	fprintf(out, "\t0, \"%s\", \"%s\"\n", aname, afile);
	fprintf(out, "};\n\n");
}
void	cloneself(last, out)
	struct self	*last;
	FILE	*out;
{
	struct self	*p;

	clonehead(last->name, out);
	for (p = self; p->txt; p++)
		cloneline(p->name, p->file, out);
	clonetail(last->name, last->file, out);
}

void	dupself(out)
{
	struct self	*p;

	for (p = self; p->txt; p++)
		clone(p->name, p->txt, out);
	cloneself(p, out);
	dup(self[0].txt, out);
	dup(self[1].txt, out);
}

void	dupfile(p)
	struct self	*p;
{
	FILE	*out;

	if (!(out = fopen(p->file, "w"))) {
		fprintf(stderr, "dupfile: create ");
		perror(p->file);
		exit(1);
	}
	if (p->txt)
		dup(p->txt, out);
	else
		dupself(out);
	fclose(out);
}

void	dupfiles()
{
	struct self	*p;

	for (p = self; p->txt; p++)
		dupfile(p);
	dupfile(p);
}

int	main(argc, argv)
	int	argc;
	char	*argv[];
{
	dupfiles();
	return 0;
}