3 * Output a program's source code as a quine file
5 * (c) 1999 Mark Wooding
8 /*----- Licensing notice --------------------------------------------------*
10 * This file is part of Quine
12 * Quine is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * Quine is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with Quine; if not, write to the Free Software Foundation,
24 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27 /*----- Header files ------------------------------------------------------*/
29 /* --- ANSI headers --- */
38 /* --- POSIX headers --- */
40 #ifndef QUINE_PORTABLE
41 #include <sys/types.h>
45 /* --- Local headers --- */
50 /*----- Main code ---------------------------------------------------------*/
54 * Arguments: @const char *f@ = a @printf@-style format string
55 * @...@ = other arguments
59 * Use: Reports an error and hari-kiris. Like @moan@ above, only
63 void die(const char *f, ...)
67 fprintf(stderr, "%s: ", optprog);
68 vfprintf(stderr, f, ap);
74 /* --- @quine__banner@ --- *
76 * Arguments: @FILE *fp@ = file to write on
80 * Use: Writes a banner to the given file.
83 static void quine__banner(FILE *fp)
85 fprintf(fp, "%s quine generator v. 1.1\n", optprog);
88 /* --- @quine__usage@ --- *
90 * Arguments: @FILE *fp@ = file to write on
94 * Use: Writes a usage note to the given file.
97 static void quine__usage(FILE *fp)
99 fprintf(fp, "Usage: %s [-hv0n] [-f FILE] [FILE...]\n", optprog);
102 /* --- @quine__help@ --- *
104 * Arguments: @FILE *fp@ = file to write on
108 * Use: Writes a help message to the given file.
111 static void quine__help(FILE *fp)
118 "Given a list of source files, constructs a C source file which will write\n"
119 "the sources, and itself, when requested. In this way, it is easy to\n"
120 "create programs which contain their own source distributions, thus\n"
121 "fulfilling the requirements of the GNU General Public License with a\n"
122 "single binary program.\n"
124 "The following options are provided:\n"
126 "-h, --help\t\tdisplay this help message\n"
127 "-v, --version\t\tshow the program's version number\n"
128 "-0, --null\t\tread null terminated filenames\n"
129 "-l, --qqlib\t\tused while bootstrapping `quine'\n"
130 "-f, --file=FILE\t\tread filenames from FILE\n"
131 "-o, --output=FILE\twrite output quine data to FILE\n"
132 "-q, --quine\t\tbuild `quine's source distribution\n"
133 "-Q, --quine-dump\twrite `quine's source code to standard output\n",
137 /* --- @quine__readLine@ --- *
139 * Arguments: @FILE *fp@ = pointer to input file
140 * @char **p@ = address of pointer to set up
141 * @size_t *sz@ = address of array length
142 * @const char *delim@ = array of delimiters
144 * Returns: Pointer to allocated line if all OK, otherwise zero.
146 * Use: Reads a line of input from the file.
149 static char *quine__readLine(FILE *fp, char **p, size_t *sz,
157 /* --- If I couldn't make my initial buffer, there's no hope --- */
163 die("out of memory");
166 /* --- Skip over initial delimiters --- */
174 if (ch == (unsigned char)*d)
178 /* --- Read characters into the buffer --- */
182 /* --- If not enough buffer space, double the buffer --- *
184 * The plus-one is for the null byte on the end.
187 if (len + 1 >= *sz) {
191 die("out of memory");
196 /* --- Read and check the next byte --- */
203 if (ch == (unsigned char)*d)
208 /* --- Terminate the string and return --- */
215 /* --- @quine__doFile@ --- *
217 * Arguments: @FILE *fp@ = output file handle
218 * @FILE *ifp@ = input file
222 * Use: Outputs the contents of a quine block containing the given
226 static void quine__doFile(FILE *fp, FILE *ifp)
239 if (ch == '\n' || p >= buff + sizeof(buff))
244 for (p = buff; p < buff + sizeof(buff); p++) {
246 case '\"': fputs("%q", fp); break;
247 case '\\': fputs("%b", fp); break;
248 case '\t': fputs("%t", fp); break;
249 case '\n': fputs("%n", fp); break;
250 case '\a': fputs("%a", fp); break;
251 case '\r': fputs("%r", fp); break;
252 case '\0': fputs("%0", fp); break;
253 case '%': fputs("%%", fp); break;
255 if (isprint((unsigned char)*p))
258 fprintf(fp, "%%x%02x%%", (unsigned char)*p);
268 fputs("0\n};\n\n", fp);
271 /* --- @quine__file@ --- *
273 * Arguments: @FILE *fp@ = output file handle
274 * @const char *name@ = name of input file
275 * @size_t fno@ = number of this file
279 * Use: Outputs a quine block containing the given file.
282 static void quine__file(FILE *fp, const char *name, size_t fno)
286 fprintf(fp, "static const char *qq__c_%lx[] = {\n", (unsigned long)fno);
288 if ((ifp = fopen(name, "r")) == 0)
289 die("couldn't read `%s': %s", name, strerror(errno));
290 fprintf(fp, "/* Filename: */ \"%s\",\n", name);
292 /* --- Write file's mode to the output --- */
294 #ifndef QUINE_PORTABLE
297 if (stat(name, &st) == 0)
298 fprintf(fp, "/* Mode: */ \"%%!0%03o\",\n", st.st_mode & 07777);
302 quine__doFile(fp, ifp);
305 /* --- Dummy quine library --- */
309 const char *qq_qqlib[] = {
310 "/* --- No quine library available in xquine --- */%n",
318 * Arguments: @int argc@ = number of command line arguments
319 * @char *argv[]@ = pointer to the command line arguments
321 * Returns: Zero if successful, @EXIT_FAILURE@ if not.
323 * Use: Given a number of source files, outputs C code which prints
327 int main(int argc, char *argv[])
333 FILE *infp = 0, *outfp = 0;
342 /* --- Scan the command line arguments --- */
347 static struct option opts[] = {
348 { "help", 0, 0, 'h' },
349 { "version", 0, 0, 'v' },
350 { "null", 0, 0, '0' },
351 { "file", OPTF_ARGREQ, 0, 'f' },
352 { "nofiles", 0, 0, 'n' },
353 { "output", OPTF_ARGREQ, 0, 'o' },
354 { "qqlib", OPTF_ARGREQ, 0, 'l' },
355 #if !defined(QQ_XQUINE) && !defined(QQ_YQUINE)
356 { "quine", 0, 0, 'q' },
357 { "quine-dump", 0, 0, 'Q' },
362 #if !defined(QQ_XQUINE) && !defined(QQ_YQUINE)
363 # define OPTS "hv0nf:o:lqQ"
365 # define OPTS "hv0nf:o:l"
368 i = mdwopt(argc, argv, OPTS, opts, 0, 0, 0);
378 quine__banner(stdout);
395 #if !defined(QQ_XQUINE) && !defined(QQ_YQUINE)
398 die("couldn't build source distribution: %s", strerror(errno));
412 quine__usage(stderr);
416 /* --- Output a file as the qqlib library --- */
419 infp = fopen(qqlibf, "r");
421 die("couldn't open input file `%s': %s", inf, strerror(errno));
425 if (strcmp(outf, "-") == 0)
428 outfp = fopen(outf, "w");
430 die("couldn't open output file `%s': %s", outf, strerror(errno));
432 fputs("/* quine library data */\n\n"
433 "const char *qq_qqlib[] = {\n", outfp);
434 quine__doFile(outfp, infp);
440 /* --- Time to start work --- */
442 if (~f & f_noFiles && (inf || optind == argc)) {
443 if (!inf || strcmp(inf, "-") == 0)
446 infp = fopen(inf, "r");
448 die("couldn't open input file `%s': %s", inf, strerror(errno));
453 if (strcmp(outf, "-") == 0)
456 outfp = fopen(outf, "w");
458 die("couldn't open output file `%s': %s", outf, strerror(errno));
460 /* --- Output a header --- */
463 fputs("/* --- file contents tables --- */\n\n", outfp);
465 /* --- Scan the command line first --- */
467 while (~f & f_noFiles && optind < argc)
468 quine__file(outfp, argv[optind++], files++);
470 /* --- Now read the input file --- */
483 while ((q = quine__readLine(infp, &p, &sz, del)) != 0)
484 quine__file(outfp, q, files++);
487 die("error reading input: %s", strerror(errno));
490 /* --- And output the trailer --- */
492 qq_tail(outfp, qq_qqlib, files,
493 strcmp(outf, "-") == 0 ? "<stdout>" : outf);
497 if (outfp != stdout && fclose(outfp))
498 die("error writing output: %s", strerror(errno));
503 /*----- That's all, folks -------------------------------------------------*/