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
);
267 fputs("0\n};\n\n", fp
);
270 /* --- @quine__file@ --- *
272 * Arguments: @FILE *fp@ = output file handle
273 * @const char *name@ = name of input file
274 * @size_t fno@ = number of this file
278 * Use: Outputs a quine block containing the given file.
281 static void quine__file(FILE *fp
, const char *name
, size_t fno
)
285 fprintf(fp
, "static const char *qq__c_%lx[] = {\n", (unsigned long)fno
);
287 if ((ifp
= fopen(name
, "r")) == 0)
288 die("couldn't read `%s': %s", name
, strerror(errno
));
289 fprintf(fp
, "/* Filename: */ \"%s\",\n", name
);
291 /* --- Write file's mode to the output --- */
293 #ifndef QUINE_PORTABLE
296 if (stat(name
, &st
) == 0)
297 fprintf(fp
, "/* Mode: */ \"%%!0%03o\",\n", st
.st_mode
& 07777);
301 quine__doFile(fp
, ifp
);
304 /* --- Dummy quine library --- */
308 const char *qq_qqlib
[] = {
309 "/* --- No quine library available in xquine --- */%n",
317 * Arguments: @int argc@ = number of command line arguments
318 * @char *argv[]@ = pointer to the command line arguments
320 * Returns: Zero if successful, @EXIT_FAILURE@ if not.
322 * Use: Given a number of source files, outputs C code which prints
326 int main(int argc
, char *argv
[])
332 FILE *infp
= 0, *outfp
= 0;
341 /* --- Scan the command line arguments --- */
346 static struct option opts
[] = {
347 { "help", 0, 0, 'h' },
348 { "version", 0, 0, 'v' },
349 { "null", 0, 0, '0' },
350 { "file", OPTF_ARGREQ
, 0, 'f' },
351 { "nofiles", 0, 0, 'n' },
352 { "output", OPTF_ARGREQ
, 0, 'o' },
353 { "qqlib", OPTF_ARGREQ
, 0, 'l' },
354 #if !defined(QQ_XQUINE) && !defined(QQ_YQUINE)
355 { "quine", 0, 0, 'q' },
356 { "quine-dump", 0, 0, 'Q' },
361 #if !defined(QQ_XQUINE) && !defined(QQ_YQUINE)
362 # define OPTS "hv0nf:o:lqQ"
364 # define OPTS "hv0nf:o:l"
367 i
= mdwopt(argc
, argv
, OPTS
, opts
, 0, 0, 0);
377 quine__banner(stdout
);
394 #if !defined(QQ_XQUINE) && !defined(QQ_YQUINE)
397 die("couldn't build source distribution: %s", strerror(errno
));
411 quine__usage(stderr
);
415 /* --- Output a file as the qqlib library --- */
418 infp
= fopen(qqlibf
, "r");
420 die("couldn't open input file `%s': %s", inf
, strerror(errno
));
424 if (strcmp(outf
, "-") == 0)
427 outfp
= fopen(outf
, "w");
429 die("couldn't open output file `%s': %s", outf
, strerror(errno
));
431 fputs("/* quine library data */\n\n"
432 "const char *qq_qqlib[] = {\n", outfp
);
433 quine__doFile(outfp
, infp
);
439 /* --- Time to start work --- */
441 if (~f
& f_noFiles
&& (inf
|| optind
== argc
)) {
442 if (!inf
|| strcmp(inf
, "-") == 0)
445 infp
= fopen(inf
, "r");
447 die("couldn't open input file `%s': %s", inf
, strerror(errno
));
452 if (strcmp(outf
, "-") == 0)
455 outfp
= fopen(outf
, "w");
457 die("couldn't open output file `%s': %s", outf
, strerror(errno
));
459 /* --- Output a header --- */
462 fputs("/* --- file contents tables --- */\n\n", outfp
);
464 /* --- Scan the command line first --- */
466 while (~f
& f_noFiles
&& optind
< argc
)
467 quine__file(outfp
, argv
[optind
++], files
++);
469 /* --- Now read the input file --- */
482 while ((q
= quine__readLine(infp
, &p
, &sz
, del
)) != 0)
483 quine__file(outfp
, q
, files
++);
486 die("error reading input: %s", strerror(errno
));
489 /* --- And output the trailer --- */
491 qq_tail(outfp
, qq_qqlib
, files
,
492 strcmp(outf
, "-") == 0 ?
"<stdout>" : outf
);
496 if (outfp
!= stdout
&& fclose(outfp
))
497 die("error writing output: %s", strerror(errno
));
502 /*----- That's all, folks -------------------------------------------------*/