--- /dev/null
+Makefile.in
+aclocal.m4
+build
+configure
+qqlout.c
+qqout.c
--- /dev/null
+COPYING
+INSTALL
+install-sh
+mdwopt.c
+mdwopt.h
+missing
+mkinstalldirs
+missing
--- /dev/null
+## Process with `automake' to generate `Makefile.in'
+## -*-makefile-*-
+##
+## $Id: Makefile.am,v 1.1 1999/04/28 19:58:07 mdw Exp $
+##
+## Makefile for Quine
+##
+## (c) 1999 Mark Wooding
+##
+
+##----- Licensing notice ----------------------------------------------------
+##
+## This file is part of Quine.
+##
+## Quine is free software; you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+##
+## Quine is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with Quine; if not, write to the Free Software Foundation,
+## Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+##----- Revision history ----------------------------------------------------
+##
+## $Log: Makefile.am,v $
+## Revision 1.1 1999/04/28 19:58:07 mdw
+## Initial revision
+##
+
+AUTOMAKE_OPTIONS = foreign
+
+## --- What needs installing ---
+
+bin_PROGRAMS = quine
+noinst_PROGRAMS = ansicquine
+include_HEADERS = quine.h
+
+## --- How to build the program ---
+
+quine_SOURCES = quine.c qqout.c mdwopt.c quine.h mdwopt.h
+ansicquine_SOURCES = ansicquine.c
+EXTRA_DIST = qqlib.c qqout.c qqlout.c rexxquine.exec bournequine
+CLEANFILES = xquine yquine
+MAINTAINERCLEANFILES = qqout.c qqlout.c $(srcdir)/qqout.c $(srcdir)/qqlout.c
+
+## --- I need recursive makeness ---
+##
+## In this way, I can rebuild `xquine' and `yquine' only when they really
+## get needed.
+
+@SET_MAKE@
+
+## --- Some hacking for the bootstrapping process ---
+##
+## The outputtable library gets built from `qqlib.c'. I therefore have to
+## build a `quine' which can do this. This is `xquine'. Then, I can
+## build a `yquine' which is capable of writing full `qqout.c' files, with
+## which I can build the final glorious `quine'.
+
+xquine: xquine.o qqlib.o mdwopt.o
+ $(LINK) xquine.o qqlib.o mdwopt.o
+xquine.o: quine.c
+ $(COMPILE) -c -DQQ_XQUINE $(srcdir)/quine.c -o xquine.o
+
+yquine: yquine.o qqlib.o qqlout.o mdwopt.o
+ $(LINK) yquine.o qqlib.o qqlout.o mdwopt.o
+yquine.o: quine.c
+ $(COMPILE) -c -DQQ_YQUINE $(srcdir)/quine.c -o yquine.o
+
+## --- The `qqlout.c' file ---
+##
+## The contents of `qqlib.c' are included in every `qqout.c' file we write.
+## But I've got to get it from somewhere so that I can write it to the first
+## `qqout.c' file. The solution is, as described above, to use a cut-down
+## `quine' program which can just about build `qqlout.c' which contains only
+## the library.
+
+qqlout.c: qqlib.c
+ if [ -z "$(qq_xquine)" ]; then \
+ $(MAKE) qq_xquine=true xquine; \
+ else :; fi
+ ./xquine --qqlib $(srcdir)/qqlib.c -o qqlout.c
+
+## --- The `qqout.c' file ---
+##
+## This contains the complete source code for the program.
+
+qqout.c: quine.c qqlout.c qqlib.c mdwopt.c quine.h mdwopt.h
+ if [ -z "$(qq_yquine)" ]; then \
+ $(MAKE) qq_yquine=true yquine; \
+ else :; fi
+ touch qqout.c
+ -ln qqout.c qqlout.c $(srcdir)
+ $(MAKE) distdir
+ rm qqout.c
+ find $(distdir) \( -type f -o -type l \) ! -name qqout.c -print | \
+ ./yquine -o $(distdir)/qqout.c
+ ln $(distdir)/qqout.c qqout.c
+ rm -rf $(distdir)
+
+##----- That's all, folks ---------------------------------------------------
--- /dev/null
+Quine
+~~~~~
+
+The `Jargon File' (well, my GNU Info edition) defines a `quine' as:
+
+:quine: /kwi:n/ n. [from the name of the logician Willard
+ van Orman Quine, via Douglas Hofstadter] A program that generates a
+ copy of its own source text as its complete output. Devising the
+ shortest possible quine in some given programming language is a
+ common hackish amusement. Here is one classic quine:
+
+ ((lambda (x)
+ (list x (list (quote quote) x)))
+ (quote
+ (lambda (x)
+ (list x (list (quote quote) x)))))
+
+ This one works in LISP or Scheme. It's relatively easy to write
+ quines in other languages such as Postscript which readily handle
+ programs as data; much harder (and thus more challenging!) in
+ languages like C which do not. Here is a classic C quine for ASCII
+ machines:
+
+ char*f="char*f=%c%s%c;main()
+ {printf(f,34,f,34,10);}%c";
+ main(){printf(f,34,f,34,10);}
+
+ For excruciatingly exact quinishness, remove the interior line
+ breaks. Some infamous *note Obfuscated C Contest:: entries have been
+ quines that reproduced in exotic ways.
+
+Small quines, like the one above (or the author's strictly conformant
+ANSI C version) have been around for ages. However, I'm not aware of
+any programs which provide quine support for arbitrary pieces of
+software. The `quine' program is intended to remedy this omission.
+
+Building the package is easy. Run the `configure' script, and then say
+`make'. This then gowes through the rather convoluted build process
+automatically, and produces a binary `quine'.
+
+As an example of `quine's ability to enquine programs, it is (of course)
+a quine itself. To demonstrate this, run the command
+
+ ./quine --quine
+
+It should (very quickly) create a `quine' source distribution in the
+current directory.
+
+Conferring quineishness upon other programs isn't hard. You require the
+`quine.h' file from the source distribution (`make install' will install
+it in some standard place for you), and the `quine' binary.
+
+The `quine' program works by writing a file describing the contents of
+your source files, and the code necessary to recreate them. It reads
+the names of your sources from standard input and writes (by default) to
+`qqout.c'; thus an incantation like
+
+ find . -type f -print | quine
+
+should be sufficient to build the `qqout.c' file. Then all you need to
+do to your code to output the source code is call `qq_create' to build a
+distribution directory, or `qq_dump(STREAM)' to dump the source code to
+the output stream STREAM. Easy, no?
+
+The author's own preference for creating source distributions is to
+create a distribution directory (with `make distdir') and use `find'
+within that to build the `qqout.c' file. See the `Makefile.am' to see
+how this was achieved for `quine' itself. (Note that `quine' has to use
+itself to build its `qqout.c' file, which makes the whole procedure a
+little more interesting.)
+
+I'll admit it: this isn't what you'd call a `useful' program.
--- /dev/null
+#include <stdio.h>
+int main(void){char n='\n';char b='\\';char q='"';char*p="#include <stdio.h>%cint main(void){char n='%cn';char b='%c%c';char q='%c';char*p=%c%s%c;printf(p,n,b,b,b,q,q,p,q,n);return 0;}%c";printf(p,n,b,b,b,q,q,p,q,n);return 0;}
--- /dev/null
+#! /bin/sh
+q="'" qq='echo \#! /bin/sh;echo q=\"$q\" qq=${q}$qq$q;echo eval \$qq'
+eval $qq
--- /dev/null
+dnl -*-fundamental-*-
+dnl
+dnl $Id: configure.in,v 1.1 1999/04/28 19:58:07 mdw Exp $
+dnl
+dnl Configure script for Quine
+dnl
+dnl (c) 1999 Mark Wooding
+dnl
+
+dnl----- Licensing notice ---------------------------------------------------
+dnl
+dnl This file is part of Quine.
+dnl
+dnl Quine is free software; you can redistribute it and/or modify it
+dnl under the terms of the GNU General Public License as published by
+dnl the Free Software Foundation; either version 2 of the License, or
+dnl (at your option) any later version.
+dnl
+dnl Quine is distributed in the hope that it will be useful, but
+dnl WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+dnl GNU General Public License for more details.
+dnl
+dnl You should have received a copy of the GNU General Public License
+dnl along with Quine; if not, write to the Free Software Foundation,
+dnl Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+dnl----- Revision history ---------------------------------------------------
+dnl
+dnl $Log: configure.in,v $
+dnl Revision 1.1 1999/04/28 19:58:07 mdw
+dnl Initial revision
+dnl
+
+AC_INIT(quine.c)
+AM_INIT_AUTOMAKE(quine, 1.1.0)
+AC_ARG_PROGRAM
+AC_PROG_CC
+AC_PROG_MAKE_SET
+mdw_GCC_FLAGS
+AC_OUTPUT(Makefile)
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id: qqlib.c,v 1.1 1999/04/28 19:58:07 mdw Exp $
+ *
+ * Useful library of tools for quines
+ *
+ * (c) 1999 Mark Wooding
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Quine
+ *
+ * Quine is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Quine is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Quine; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * However, when this source text is embedded in a file by the Quine
+ * program, you may do anything you like with the resulting text;
+ * distribution and modification are not limited by the General Public
+ * License.
+ */
+
+/*----- Revision history --------------------------------------------------*
+ *
+ * $Log: qqlib.c,v $
+ * Revision 1.1 1999/04/28 19:58:07 mdw
+ * Initial revision
+ *
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+/* --- ANSI headers --- */
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* --- POSIX headers --- */
+
+#ifndef QUINE_PORTABLE
+# include <sys/types.h>
+# include <sys/fcntl.h>
+# include <sys/stat.h>
+# include <unistd.h>
+#endif
+
+/* --- Local headers --- */
+
+#include "quine.h"
+
+/*----- Macro hacking -----------------------------------------------------*/
+
+#ifdef QUINE_PORTABLE
+# define PORT(x) x
+# define NPORT(x)
+#else
+# define PORT(x)
+# define NPORT(x) x
+#endif
+
+/*----- Main code ---------------------------------------------------------*/
+
+/* --- @qq_xlate@ --- *
+ *
+ * Arguments: @FILE *fp@ = output file handle
+ * @const char *p@ = pointer to encoded text
+ *
+ * Returns: ---
+ *
+ * Use: Writes the decoded string to the given file handle.
+ */
+
+void qq_xlate(FILE *fp, const char *p)
+{
+ while (*p) {
+ if (*p == '%') {
+ p++;
+ switch (*p) {
+ case 'q': fputc('\"', fp); break;
+ case 'b': fputc('\\', fp); break;
+ case 't': fputc('\t', fp); break;
+ case 'n': fputc('\n', fp); break;
+ case 'a': fputc('\a', fp); break;
+ case 'r': fputc('\r', fp); break;
+ case '0': fputc('\0', fp); break;
+ case '%': fputc('%', fp); break;
+ case 'x': {
+ unsigned char ch = 0;
+ p++;
+ while (*p != '%') {
+ unsigned int x = *p++;
+ x -= '0';
+ if (x >= 10) x -= 'a' - '0' - 10;
+ if (x >= 16) x -= 'A' - 'a';
+ ch = (ch << 4) + x;
+ }
+ fputc(ch, fp);
+ } break;
+ default:
+ p--;
+ break;
+ }
+ } else
+ fputc(*p, fp);
+ p++;
+ }
+}
+
+/* --- @qq_file@ --- *
+ *
+ * Arguments: @FILE *fp@ = output file handle
+ * @const char **p@ = pointer to the output array
+ *
+ * Returns: ---
+ *
+ * Use: Writes the contents of a file to the output.
+ */
+
+void qq_file(FILE *fp, const char **p)
+{
+ while (*p)
+ qq_xlate(fp, *p++);
+}
+
+/* --- @qq_head@ --- *
+ *
+ * Arguments: @FILE *fp@ = output file handle
+ *
+ * Returns: ---
+ *
+ * Use: Writes the head of a `qqout.c' file.
+ */
+
+void qq_head(FILE *fp)
+{
+ fputs("/* quine output file */\n\n", fp);
+}
+
+/* --- @qq_body@ --- *
+ *
+ * Arguments: @FILE *fp@ = output file handle
+ * @const char ***p@ = pointer to main table
+ *
+ * Returns: ---
+ *
+ * Use: Writes the body table of a `qqout.c' file.
+ */
+
+void qq_body(FILE *fp, const char ***p)
+{
+ size_t fno = 0;
+ const char **q;
+
+ fputs("/* --- file contents tables --- */\n\n", fp);
+ while (*p) {
+ q = *p;
+ fprintf(fp, "static const char *qq__c_%lx[] = {\n", (unsigned long)fno);
+ fprintf(fp, "/* Filename: */ \"%s\",\n", *q++);
+ if (strncmp(*q, "%!", 2) == 0)
+ fprintf(fp, "/* Mode: */ \"%s\",\n", *q++);
+ while (*q)
+ fprintf(fp, "\"%s\",\n", *q++);
+ fputs("0\n};\n\n", fp);
+ p++;
+ fno++;
+ }
+}
+
+/* --- @qq_tail@ --- *
+ *
+ * Arguments: @FILE *fp@ = output file handle
+ * @const char **qql@ = pointer to qqlib file array
+ * @size_t fno@ = number of files written
+ * @const char *fn@ = name of `qqout.c' file
+ *
+ * Returns: ---
+ *
+ * Use: Writes the head of a `qqout.c' file.
+ */
+
+void qq_tail(FILE *fp, const char **qql, size_t fno, const char *fn)
+{
+ const char **p;
+ size_t i;
+
+ /* --- Write out the qqlib array --- */
+
+ fputs("/* --- qqlib code --- */\n\n"
+ "const char *qq_qqlib[] = {\n", fp);
+ for (p = qql; *p; p++)
+ fprintf(fp, "\"%s\",\n", *p);
+ fputs("0\n};\n\n", fp);
+
+ /* --- Build the main array --- */
+
+ fputs("/* --- table of files to output --- */\n\n"
+ "const char **qq_table[] = {\n", fp);
+ for (i = 0; i < fno; i++)
+ fprintf(fp, " qq__c_%lx,\n", (unsigned long)i);
+ fputs(" 0\n};\n\n", fp);
+
+ /* --- Now output the qqlib code --- */
+
+ fputs("#define QQ_OUT\n\n", fp);
+ qq_file(fp, qql);
+
+ /* --- Finally write the code to write everything out --- */
+
+ fprintf(fp,
+ "/* --- quine output routines --- */\n\n"
+ "void qq_dump(FILE *fp) {\n"
+ " qq__dump(fp, qq_table, qq_qqlib, \"%s\", %lu);\n"
+ "}\n"
+ "int qq_create(void) {\n"
+ " return (qq__create(qq_table, qq_qqlib, \"%s\", %lu));\n"
+ "}\n\n",
+ fn, (unsigned long)fno, fn, (unsigned long)fno);
+}
+
+/* --- @qq_mkfile@ --- *
+ *
+ * Arguments: @const char *fn@ = pointer to a filename
+ * @int mode@ = file mode to use (only in Unix-specific version)
+ *
+ * Returns: A handle for the created file.
+ *
+ * Use: Creates a file, and leading directories and stuff.
+ */
+
+#ifdef QUINE_PORTABLE
+FILE *qq_mkfile(const char *fn)
+{
+ return (fopen(fn, "w"));
+}
+#else
+FILE *qq_mkfile(const char *fn, int mode)
+{
+ char buf[FILENAME_MAX];
+ char *p;
+ int fd;
+
+ strcpy(buf, fn);
+ p = strchr(buf, '/');
+ for (;;) {
+ if (!p)
+ break;
+ *p = 0;
+ mkdir(buf, 0777);
+ *p = '/';
+ p = strchr(p + 1, '/');
+ }
+
+ fd = open(fn, O_WRONLY|O_CREAT|O_TRUNC, mode);
+ return (fd >=0 ? fdopen(fd, "w") : 0);
+}
+#endif
+
+#ifdef QQ_OUT
+
+/* --- @qq__dump@ --- *
+ *
+ * Arguments: @FILE *fp@ = file to dump on
+ * @const char ***p@ = pointer to main table
+ * @const char **qql@ = pointer to qqlib code
+ * @const char *fn@ = name of `qqout.c' file
+ * @size_t fno@ = number of files to be output
+ *
+ * Returns: ---
+ *
+ * Use: Outputs the entire source code to a given file.
+ */
+
+static void qq__dump(FILE *fp, const char ***p, const char **qql,
+ const char *fn, size_t fno)
+{
+ const char ***q = p;
+
+ while (*q) {
+ fprintf(fp, "******** %s\n\n", **q);
+ qq_file(fp, *q + 1);
+ q++;
+ }
+ fprintf(fp, "******** %s\n\n", fn);
+ qq_head(fp);
+ qq_body(fp, p);
+ qq_tail(fp, qql, fno, fn);
+}
+
+/* --- @qq__create@ --- *
+ *
+ * Arguments: @const char ***p@ = pointer to main table
+ * @const char **qql@ = pointer to qqlib code
+ * @const char *fn@ = name of `qqout.c' file
+ * @size_t fno@ = number of files to be output
+ *
+ * Returns: Zero if all went well, else nonzero.
+ *
+ * Use: Rebuilds the original source distribution.
+ */
+
+static int qq__create(const char ***p, const char **qql,
+ const char *fn, size_t fno)
+{
+ FILE *fp;
+ const char ***q = p;
+
+ while (*q) {
+ const char **qq = *q + 1;
+
+#ifdef QUINE_PORTABLE
+ if (strncmp(*qq, "%!", 2) == 0)
+ qq++;
+ fp = qq_mkfile(*qq);
+#else
+ if (strncmp(*qq, "%!", 2) == 0) {
+ fp = qq_mkfile(**q, (int)strtol(*qq + 2, 0, 8));
+ qq++;
+ } else
+ fp = qq_mkfile(**q, 0666);
+#endif
+
+ if (!fp)
+ return (-1);
+ qq_file(fp, qq);
+ if (fclose(fp))
+ return (-1);
+ q++;
+ }
+ fp = qq_mkfile(fn, 0666);
+ if (!fp)
+ return (-1);
+ qq_head(fp);
+ qq_body(fp, p);
+ qq_tail(fp, qql, fno, fn);
+ if (fclose(fp))
+ return (-1);
+ return (0);
+}
+
+#endif
+
+/*----- That's all, folks -------------------------------------------------*/
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id: quine.c,v 1.1 1999/04/28 19:58:07 mdw Exp $
+ *
+ * Output a program's source code as a quine file
+ *
+ * (c) 1999 Mark Wooding
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Quine
+ *
+ * Quine is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Quine is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Quine; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------*
+ *
+ * $Log: quine.c,v $
+ * Revision 1.1 1999/04/28 19:58:07 mdw
+ * Initial revision
+ *
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+/* --- ANSI headers --- */
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* --- POSIX headers --- */
+
+#ifndef QUINE_PORTABLE
+#include <sys/types.h>
+#include <sys/stat.h>
+#endif
+
+/* --- Local headers --- */
+
+#include "mdwopt.h"
+#include "quine.h"
+
+/*----- Main code ---------------------------------------------------------*/
+
+/* --- @die@ --- *
+ *
+ * Arguments: @const char *f@ = a @printf@-style format string
+ * @...@ = other arguments
+ *
+ * Returns: Never.
+ *
+ * Use: Reports an error and hari-kiris. Like @moan@ above, only
+ * more permanent.
+ */
+
+void die(const char *f, ...)
+{
+ va_list ap;
+ va_start(ap, f);
+ fprintf(stderr, "%s: ", optprog);
+ vfprintf(stderr, f, ap);
+ va_end(ap);
+ putc('\n', stderr);
+ exit(EXIT_FAILURE);
+}
+
+/* --- @quine__banner@ --- *
+ *
+ * Arguments: @FILE *fp@ = file to write on
+ *
+ * Returns: ---
+ *
+ * Use: Writes a banner to the given file.
+ */
+
+static void quine__banner(FILE *fp)
+{
+ fprintf(fp, "%s quine generator v. 1.1\n", optprog);
+}
+
+/* --- @quine__usage@ --- *
+ *
+ * Arguments: @FILE *fp@ = file to write on
+ *
+ * Returns: ---
+ *
+ * Use: Writes a usage note to the given file.
+ */
+
+static void quine__usage(FILE *fp)
+{
+ fprintf(fp, "Usage: %s [-hv0n] [-f FILE] [FILE...]\n", optprog);
+}
+
+/* --- @quine__help@ --- *
+ *
+ * Arguments: @FILE *fp@ = file to write on
+ *
+ * Returns: ---
+ *
+ * Use: Writes a help message to the given file.
+ */
+
+static void quine__help(FILE *fp)
+{
+ quine__banner(fp);
+ putc('\n', fp);
+ quine__usage(fp);
+ putc('\n', fp);
+ fputs(
+"Given a list of source files, constructs a C source file which will write\n"
+"the sources, and itself, when requested. In this way, it is easy to\n"
+"create programs which contain their own source distributions, thus\n"
+"fulfilling the requirements of the GNU General Public License with a\n"
+"single binary program.\n"
+"\n"
+"The following options are provided:\n"
+"\n"
+"-h, --help\t\tdisplay this help message\n"
+"-v, --version\t\tshow the program's version number\n"
+"-0, --null\t\tread null terminated filenames\n"
+"-l, --qqlib\t\tused while bootstrapping `quine'\n"
+"-f, --file=FILE\t\tread filenames from FILE\n"
+"-o, --output=FILE\twrite output quine data to FILE\n"
+"-q, --quine\t\tbuild `quine's source distribution\n"
+"-Q, --quine-dump\twrite `quine's source code to standard output\n",
+fp);
+}
+
+/* --- @quine__readLine@ --- *
+ *
+ * Arguments: @FILE *fp@ = pointer to input file
+ * @char **p@ = address of pointer to set up
+ * @size_t *sz@ = address of array length
+ * @const char *delim@ = array of delimiters
+ *
+ * Returns: Pointer to allocated line if all OK, otherwise zero.
+ *
+ * Use: Reads a line of input from the file.
+ */
+
+static char *quine__readLine(FILE *fp, char **p, size_t *sz,
+ const char *delim)
+{
+ size_t len = 0;
+ char *q;
+ const char *d;
+ int ch;
+
+ /* --- If I couldn't make my initial buffer, there's no hope --- */
+
+ if (!*p) {
+ *sz = 64;
+ *p = malloc(*sz);
+ if (!*p)
+ die("out of memory");
+ }
+
+ /* --- Skip over initial delimiters --- */
+
+skip_delims:
+ ch = getc(fp);
+ if (ch == EOF)
+ return (0);
+ d = delim;
+ do {
+ if (ch == (unsigned char)*d)
+ goto skip_delims;
+ } while (*d++);
+
+ /* --- Read characters into the buffer --- */
+
+ for (;;) {
+
+ /* --- If not enough buffer space, double the buffer --- *
+ *
+ * The plus-one is for the null byte on the end.
+ */
+
+ if (len + 1 >= *sz) {
+ *sz <<= 1;
+ q = realloc(p, *sz);
+ if (!q)
+ die("out of memory");
+ *p = q;
+ }
+ (*p)[len++] = ch;
+
+ /* --- Read and check the next byte --- */
+
+ ch = getc(fp);
+ if (ch == EOF)
+ goto done;
+ d = delim;
+ do {
+ if (ch == (unsigned char)*d)
+ goto done;
+ } while (*d++);
+ }
+
+ /* --- Terminate the string and return --- */
+
+done:
+ (*p)[len++] = 0;
+ return (*p);
+}
+
+/* --- @quine__doFile@ --- *
+ *
+ * Arguments: @FILE *fp@ = output file handle
+ * @FILE *ifp@ = input file
+ *
+ * Returns: ---
+ *
+ * Use: Outputs the contents of a quine block containing the given
+ * file.
+ */
+
+static void quine__doFile(FILE *fp, FILE *ifp)
+{
+ char *p;
+ char buff[80];
+ int ch;
+
+ for (;;) {
+ p = buff;
+ ch = getc(ifp);
+ if (ch == EOF)
+ break;
+ for (;;) {
+ *p++ = ch;
+ if (ch == '\n' || p >= buff + sizeof(buff))
+ break;
+ ch = getc(ifp);
+ }
+ fputc('\"', fp);
+ for (p = buff; p < buff + sizeof(buff); p++) {
+ switch (*p) {
+ case '\"': fputs("%q", fp); break;
+ case '\\': fputs("%b", fp); break;
+ case '\t': fputs("%t", fp); break;
+ case '\n': fputs("%n", fp); break;
+ case '\a': fputs("%a", fp); break;
+ case '\r': fputs("%r", fp); break;
+ case '\0': fputs("%0", fp); break;
+ case '%': fputs("%%", fp); break;
+ default:
+ if (isprint((unsigned char)*p))
+ fputc(*p, fp);
+ else
+ fprintf(fp, "%%x%02x%%", (unsigned char)*p);
+ break;
+ }
+ if (*p == '\n')
+ break;
+ }
+ fputs("\",\n", fp);
+ }
+ fclose(ifp);
+
+ fputs("0\n};\n\n", fp);
+}
+
+/* --- @quine__file@ --- *
+ *
+ * Arguments: @FILE *fp@ = output file handle
+ * @const char *name@ = name of input file
+ * @size_t fno@ = number of this file
+ *
+ * Returns: ---
+ *
+ * Use: Outputs a quine block containing the given file.
+ */
+
+static void quine__file(FILE *fp, const char *name, size_t fno)
+{
+ FILE *ifp;
+
+ fprintf(fp, "static const char *qq__c_%lx[] = {\n", (unsigned long)fno);
+
+ if ((ifp = fopen(name, "r")) == 0)
+ die("couldn't read `%s': %s", name, strerror(errno));
+ fprintf(fp, "/* Filename: */ \"%s\",\n", name);
+
+ /* --- Write file's mode to the output --- */
+
+#ifndef QUINE_PORTABLE
+ {
+ struct stat st;
+ if (stat(name, &st) == 0)
+ fprintf(fp, "/* Mode: */ \"%%!0%03o\",\n", st.st_mode & 07777);
+ }
+#endif
+
+ quine__doFile(fp, ifp);
+}
+
+/* --- Dummy quine library --- */
+
+#ifdef QQ_XQUINE
+
+const char *qq_qqlib[] = {
+ "/* --- No quine library available in xquine --- */%n",
+ 0
+};
+
+#endif
+
+/* --- @main@ --- *
+ *
+ * Arguments: @int argc@ = number of command line arguments
+ * @char *argv[]@ = pointer to the command line arguments
+ *
+ * Returns: Zero if successful, @EXIT_FAILURE@ if not.
+ *
+ * Use: Given a number of source files, outputs C code which prints
+ * them (and itself).
+ */
+
+int main(int argc, char *argv[])
+{
+ char *inf = 0;
+ char *outf = 0;
+ char *qqlibf = 0;
+ unsigned int f = 0;
+ FILE *infp = 0, *outfp = 0;
+ size_t files = 0;
+
+ enum {
+ f_duff = 1,
+ f_null = 2,
+ f_noFiles = 4
+ };
+
+ /* --- Scan the command line arguments --- */
+
+ for (;;) {
+ int i;
+
+ static struct option opts[] = {
+ { "help", 0, 0, 'h' },
+ { "version", 0, 0, 'v' },
+ { "null", 0, 0, '0' },
+ { "file", gFlag_argReq, 0, 'f' },
+ { "nofiles", 0, 0, 'n' },
+ { "output", gFlag_argReq, 0, 'o' },
+ { "qqlib", gFlag_argReq, 0, 'l' },
+#if !defined(QQ_XQUINE) && !defined(QQ_YQUINE)
+ { "quine", 0, 0, 'q' },
+ { "quine-dump", 0, 0, 'Q' },
+#endif
+ { 0, 0, 0, 0 }
+ };
+
+#if !defined(QQ_XQUINE) && !defined(QQ_YQUINE)
+# define OPTS "hv0nf:o:lqQ"
+#else
+# define OPTS "hv0nf:o:l"
+#endif
+
+ i = mdwopt(argc, argv, OPTS, opts, 0, 0, 0);
+
+ if (i < 0)
+ break;
+
+ switch (i) {
+ case 'h':
+ quine__help(stdout);
+ exit(0);
+ case 'v':
+ quine__banner(stdout);
+ exit(0);
+ case '0':
+ f |= f_null;
+ break;
+ case 'f':
+ inf = optarg;
+ break;
+ case 'o':
+ outf = optarg;
+ break;
+ case 'l':
+ qqlibf = optarg;
+ break;
+ case 'n':
+ f |= f_noFiles;
+ break;
+#if !defined(QQ_XQUINE) && !defined(QQ_YQUINE)
+ case 'q':
+ if (qq_create())
+ die("couldn't build source distribution: %s", strerror(errno));
+ exit(0);
+ case 'Q':
+ qq_dump(stdout);
+ exit(0);
+ break;
+#endif
+ default:
+ f |= f_duff;
+ break;
+ }
+ }
+
+ if (f & f_duff) {
+ quine__usage(stderr);
+ exit(EXIT_FAILURE);
+ }
+
+ /* --- Output a file as the qqlib library --- */
+
+ if (qqlibf) {
+ infp = fopen(qqlibf, "r");
+ if (!infp)
+ die("couldn't open input file `%s': %s", inf, strerror(errno));
+
+ if (!outf)
+ outf = "qqlout.c";
+ if (strcmp(outf, "-") == 0)
+ outfp = stdout;
+ else
+ outfp = fopen(outf, "w");
+ if (!outfp)
+ die("couldn't open output file `%s': %s", outf, strerror(errno));
+
+ fputs("/* quine library data */\n\n"
+ "const char *qq_qqlib[] = {\n", outfp);
+ quine__doFile(outfp, infp);
+ fclose(infp);
+ fclose(outfp);
+ exit(0);
+ }
+
+ /* --- Time to start work --- */
+
+ if (~f & f_noFiles && (inf || optind == argc)) {
+ if (!inf || strcmp(inf, "-") == 0)
+ infp = stdin;
+ else
+ infp = fopen(inf, "r");
+ if (!infp)
+ die("couldn't open input file `%s': %s", inf, strerror(errno));
+ }
+
+ if (!outf)
+ outf = "qqout.c";
+ if (strcmp(outf, "-") == 0)
+ outfp = stdout;
+ else
+ outfp = fopen(outf, "w");
+ if (!outfp)
+ die("couldn't open output file `%s': %s", outf, strerror(errno));
+
+ /* --- Output a header --- */
+
+ qq_head(outfp);
+ fputs("/* --- file contents tables --- */\n\n", outfp);
+
+ /* --- Scan the command line first --- */
+
+ while (~f & f_noFiles && optind < argc)
+ quine__file(outfp, argv[optind++], files++);
+
+ /* --- Now read the input file --- */
+
+ if (infp) {
+ char *p = 0;
+ char *q;
+ const char *del;
+ size_t sz = 0;
+
+ if (f & f_null)
+ del = "";
+ else
+ del = " \n\t";
+
+ while ((q = quine__readLine(infp, &p, &sz, del)) != 0)
+ quine__file(outfp, q, files++);
+
+ if (fclose(infp))
+ die("error reading input: %s", strerror(errno));
+ }
+
+ /* --- And output the trailer --- */
+
+ qq_tail(outfp, qq_qqlib, files,
+ strcmp(outf, "-") == 0 ? "<stdout>" : outf);
+
+ /* --- Done --- */
+
+ if (outfp != stdout && fclose(outfp))
+ die("error writing output: %s", strerror(errno));
+
+ return (0);
+}
+
+/*----- That's all, folks -------------------------------------------------*/
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id: quine.h,v 1.1 1999/04/28 19:58:07 mdw Exp $
+ *
+ * Definitions for building quines
+ *
+ * (c) 1999 Mark Wooding
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Quine
+ *
+ * Quine is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Quine is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Quine; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------*
+ *
+ * $Log: quine.h,v $
+ * Revision 1.1 1999/04/28 19:58:07 mdw
+ * Initial revision
+ *
+ */
+
+#ifndef QUINE_H
+#define QUINE_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/*----- Required headers --------------------------------------------------*/
+
+#include <stdio.h>
+
+/*----- External tables ---------------------------------------------------*/
+
+extern const char **qq_table[];
+extern const char *qq_qqlib[];
+
+/*----- Functions provided ------------------------------------------------*/
+
+/* --- @qq_xlate@ --- *
+ *
+ * Arguments: @FILE *fp@ = output file handle
+ * @const char *p@ = pointer to encoded text
+ *
+ * Returns: ---
+ *
+ * Use: Writes the decoded string to the given file handle.
+ */
+
+extern void qq_xlate(FILE */*fp*/, const char */*p*/);
+
+/* --- @qq_file@ --- *
+ *
+ * Arguments: @FILE *fp@ = output file handle
+ * @const char **p@ = pointer to the output array
+ *
+ * Returns: ---
+ *
+ * Use: Writes the contents of a file to the output.
+ */
+
+extern void qq_file(FILE */*fp*/, const char **/*p*/);
+
+/* --- @qq_head@ --- *
+ *
+ * Arguments: @FILE *fp@ = output file handle
+ *
+ * Returns: ---
+ *
+ * Use: Writes the head of a `qqout.c' file.
+ */
+
+extern void qq_head(FILE */*fp*/);
+
+/* --- @qq_body@ --- *
+ *
+ * Arguments: @FILE *fp@ = output file handle
+ * @const char ***p@ = pointer to main table
+ *
+ * Returns: ---
+ *
+ * Use: Writes the body table of a `qqout.c' file.
+ */
+
+extern void qq_body(FILE */*fp*/, const char ***/*p*/);
+
+/* --- @qq_tail@ --- *
+ *
+ * Arguments: @FILE *fp@ = output file handle
+ * @const char **qql@ = pointer to qqlib file array
+ * @size_t fno@ = number of files written
+ * @const char *fn@ = name of `qqout.c' file
+ *
+ * Returns: ---
+ *
+ * Use: Writes the head of a `qqout.c' file.
+ */
+
+extern void qq_tail(FILE */*fp*/, const char **/*qql*/,
+ size_t /*fno*/, const char */*fn*/);
+
+/* --- @qq_mkfile@ --- *
+ *
+ * Arguments: @const char *fn@ = pointer to a filename
+ * @int mode@ = mode to create file with
+ *
+ * Returns: A handle for the created file.
+ *
+ * Use: Creates a file, and leading directories and stuff.
+ */
+
+#ifdef QUINE_PORTABLE
+extern FILE *qq_mkfile(const char */*fn*/);
+#else
+extern FILE *qq_mkfile(const char */*fn*/, int /*mode*/);
+#endif
+
+/* --- @qq_dump@ --- *
+ *
+ * Arguments: @FILE *fp@ = stream to dump on
+ *
+ * Returns: ---
+ *
+ * Use: Writes the program's source code to the given file.
+ */
+
+extern void qq_dump(FILE */*fp*/);
+
+/* --- @qq_create@ --- *
+ *
+ * Arguments: ---
+ *
+ * Returns: ---
+ *
+ * Use: Writes a source distribution to the current directory.
+ */
+
+extern int qq_create(void);
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
--- /dev/null
+/* */
+q=''''
+p='say"/* */";say"q="q||q||q||q;say"p="q||p||q;say"interpret p"'
+interpret p