5 * Output a program's source code as a quine file
7 * (c) 1999 Mark Wooding
10 /*----- Licensing notice --------------------------------------------------*
12 * This file is part of Quine
14 * Quine is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
19 * Quine is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with Quine; if not, write to the Free Software Foundation,
26 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
29 /*----- Header files ------------------------------------------------------*/
31 /* --- ANSI headers --- */
40 /* --- POSIX headers --- */
42 #ifndef QUINE_PORTABLE
43 #include <sys/types.h>
47 /* --- Local headers --- */
52 /*----- Main code ---------------------------------------------------------*/
56 * Arguments: @const char *f@ = a @printf@-style format string
57 * @...@ = other arguments
61 * Use: Reports an error and hari-kiris. Like @moan@ above, only
65 void die(const char *f, ...)
69 fprintf(stderr, "%s: ", optprog);
70 vfprintf(stderr, f, ap);
76 /* --- @quine__banner@ --- *
78 * Arguments: @FILE *fp@ = file to write on
82 * Use: Writes a banner to the given file.
85 static void quine__banner(FILE *fp)
87 fprintf(fp, "%s quine generator v. 1.1\n", optprog);
90 /* --- @quine__usage@ --- *
92 * Arguments: @FILE *fp@ = file to write on
96 * Use: Writes a usage note to the given file.
99 static void quine__usage(FILE *fp)
101 fprintf(fp, "Usage: %s [-hv0n] [-f FILE] [FILE...]\n", optprog);
104 /* --- @quine__help@ --- *
106 * Arguments: @FILE *fp@ = file to write on
110 * Use: Writes a help message to the given file.
113 static void quine__help(FILE *fp)
120 "Given a list of source files, constructs a C source file which will write\n"
121 "the sources, and itself, when requested. In this way, it is easy to\n"
122 "create programs which contain their own source distributions, thus\n"
123 "fulfilling the requirements of the GNU General Public License with a\n"
124 "single binary program.\n"
126 "The following options are provided:\n"
128 "-h, --help\t\tdisplay this help message\n"
129 "-v, --version\t\tshow the program's version number\n"
130 "-0, --null\t\tread null terminated filenames\n"
131 "-l, --qqlib\t\tused while bootstrapping `quine'\n"
132 "-f, --file=FILE\t\tread filenames from FILE\n"
133 "-o, --output=FILE\twrite output quine data to FILE\n"
134 "-q, --quine\t\tbuild `quine's source distribution\n"
135 "-Q, --quine-dump\twrite `quine's source code to standard output\n",
139 /* --- @quine__readLine@ --- *
141 * Arguments: @FILE *fp@ = pointer to input file
142 * @char **p@ = address of pointer to set up
143 * @size_t *sz@ = address of array length
144 * @const char *delim@ = array of delimiters
146 * Returns: Pointer to allocated line if all OK, otherwise zero.
148 * Use: Reads a line of input from the file.
151 static char *quine__readLine(FILE *fp, char **p, size_t *sz,
159 /* --- If I couldn't make my initial buffer, there's no hope --- */
165 die("out of memory");
168 /* --- Skip over initial delimiters --- */
176 if (ch == (unsigned char)*d)
180 /* --- Read characters into the buffer --- */
184 /* --- If not enough buffer space, double the buffer --- *
186 * The plus-one is for the null byte on the end.
189 if (len + 1 >= *sz) {
193 die("out of memory");
198 /* --- Read and check the next byte --- */
205 if (ch == (unsigned char)*d)
210 /* --- Terminate the string and return --- */
217 /* --- @quine__doFile@ --- *
219 * Arguments: @FILE *fp@ = output file handle
220 * @FILE *ifp@ = input file
224 * Use: Outputs the contents of a quine block containing the given
228 static void quine__doFile(FILE *fp, FILE *ifp)
241 if (ch == '\n' || p >= buff + sizeof(buff))
246 for (p = buff; p < buff + sizeof(buff); p++) {
248 case '\"': fputs("%q", fp); break;
249 case '\\': fputs("%b", fp); break;
250 case '\t': fputs("%t", fp); break;
251 case '\n': fputs("%n", fp); break;
252 case '\a': fputs("%a", fp); break;
253 case '\r': fputs("%r", fp); break;
254 case '\0': fputs("%0", fp); break;
255 case '%': fputs("%%", fp); break;
257 if (isprint((unsigned char)*p))
260 fprintf(fp, "%%x%02x%%", (unsigned char)*p);
270 fputs("0\n};\n\n", fp);
273 /* --- @quine__file@ --- *
275 * Arguments: @FILE *fp@ = output file handle
276 * @const char *name@ = name of input file
277 * @size_t fno@ = number of this file
281 * Use: Outputs a quine block containing the given file.
284 static void quine__file(FILE *fp, const char *name, size_t fno)
288 fprintf(fp, "static const char *qq__c_%lx[] = {\n", (unsigned long)fno);
290 if ((ifp = fopen(name, "r")) == 0)
291 die("couldn't read `%s': %s", name, strerror(errno));
292 fprintf(fp, "/* Filename: */ \"%s\",\n", name);
294 /* --- Write file's mode to the output --- */
296 #ifndef QUINE_PORTABLE
299 if (stat(name, &st) == 0)
300 fprintf(fp, "/* Mode: */ \"%%!0%03o\",\n", st.st_mode & 07777);
304 quine__doFile(fp, ifp);
307 /* --- Dummy quine library --- */
311 const char *qq_qqlib[] = {
312 "/* --- No quine library available in xquine --- */%n",
320 * Arguments: @int argc@ = number of command line arguments
321 * @char *argv[]@ = pointer to the command line arguments
323 * Returns: Zero if successful, @EXIT_FAILURE@ if not.
325 * Use: Given a number of source files, outputs C code which prints
329 int main(int argc, char *argv[])
335 FILE *infp = 0, *outfp = 0;
344 /* --- Scan the command line arguments --- */
349 static struct option opts[] = {
350 { "help", 0, 0, 'h' },
351 { "version", 0, 0, 'v' },
352 { "null", 0, 0, '0' },
353 { "file", OPTF_ARGREQ, 0, 'f' },
354 { "nofiles", 0, 0, 'n' },
355 { "output", OPTF_ARGREQ, 0, 'o' },
356 { "qqlib", OPTF_ARGREQ, 0, 'l' },
357 #if !defined(QQ_XQUINE) && !defined(QQ_YQUINE)
358 { "quine", 0, 0, 'q' },
359 { "quine-dump", 0, 0, 'Q' },
364 #if !defined(QQ_XQUINE) && !defined(QQ_YQUINE)
365 # define OPTS "hv0nf:o:lqQ"
367 # define OPTS "hv0nf:o:l"
370 i = mdwopt(argc, argv, OPTS, opts, 0, 0, 0);
380 quine__banner(stdout);
397 #if !defined(QQ_XQUINE) && !defined(QQ_YQUINE)
400 die("couldn't build source distribution: %s", strerror(errno));
414 quine__usage(stderr);
418 /* --- Output a file as the qqlib library --- */
421 infp = fopen(qqlibf, "r");
423 die("couldn't open input file `%s': %s", inf, strerror(errno));
427 if (strcmp(outf, "-") == 0)
430 outfp = fopen(outf, "w");
432 die("couldn't open output file `%s': %s", outf, strerror(errno));
434 fputs("/* quine library data */\n\n"
435 "const char *qq_qqlib[] = {\n", outfp);
436 quine__doFile(outfp, infp);
442 /* --- Time to start work --- */
444 if (~f & f_noFiles && (inf || optind == argc)) {
445 if (!inf || strcmp(inf, "-") == 0)
448 infp = fopen(inf, "r");
450 die("couldn't open input file `%s': %s", inf, strerror(errno));
455 if (strcmp(outf, "-") == 0)
458 outfp = fopen(outf, "w");
460 die("couldn't open output file `%s': %s", outf, strerror(errno));
462 /* --- Output a header --- */
465 fputs("/* --- file contents tables --- */\n\n", outfp);
467 /* --- Scan the command line first --- */
469 while (~f & f_noFiles && optind < argc)
470 quine__file(outfp, argv[optind++], files++);
472 /* --- Now read the input file --- */
485 while ((q = quine__readLine(infp, &p, &sz, del)) != 0)
486 quine__file(outfp, q, files++);
489 die("error reading input: %s", strerror(errno));
492 /* --- And output the trailer --- */
494 qq_tail(outfp, qq_qqlib, files,
495 strcmp(outf, "-") == 0 ? "<stdout>" : outf);
499 if (outfp != stdout && fclose(outfp))
500 die("error writing output: %s", strerror(errno));
505 /*----- That's all, folks -------------------------------------------------*/