3 * $Id: qqlib.c,v 1.2 2000/08/01 17:41:39 mdw Exp $
5 * Useful library of tools for quines
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.
28 * However, when this source text is embedded in a file by the Quine
29 * program, you may do anything you like with the resulting text;
30 * distribution and modification are not limited by the General Public
34 /*----- Revision history --------------------------------------------------*
37 * Revision 1.2 2000/08/01 17:41:39 mdw
38 * Remove unnecessary <ctype.h> header.
40 * Revision 1.1.1.1 1999/04/28 19:58:07 mdw
45 /*----- Header files ------------------------------------------------------*/
47 /* --- ANSI headers --- */
54 /* --- POSIX headers --- */
56 #ifndef QUINE_PORTABLE
57 # include <sys/types.h>
58 # include <sys/fcntl.h>
59 # include <sys/stat.h>
63 /* --- Local headers --- */
67 /*----- Macro hacking -----------------------------------------------------*/
77 /*----- Main code ---------------------------------------------------------*/
79 /* --- @qq_xlate@ --- *
81 * Arguments: @FILE *fp@ = output file handle
82 * @const char *p@ = pointer to encoded text
86 * Use: Writes the decoded string to the given file handle.
89 void qq_xlate(FILE *fp, const char *p)
95 case 'q': fputc('\"', fp); break;
96 case 'b': fputc('\\', fp); break;
97 case 't': fputc('\t', fp); break;
98 case 'n': fputc('\n', fp); break;
99 case 'a': fputc('\a', fp); break;
100 case 'r': fputc('\r', fp); break;
101 case '0': fputc('\0', fp); break;
102 case '%': fputc('%', fp); break;
104 unsigned char ch = 0;
107 unsigned int x = *p++;
109 if (x >= 10) x -= 'a' - '0' - 10;
110 if (x >= 16) x -= 'A' - 'a';
125 /* --- @qq_file@ --- *
127 * Arguments: @FILE *fp@ = output file handle
128 * @const char **p@ = pointer to the output array
132 * Use: Writes the contents of a file to the output.
135 void qq_file(FILE *fp, const char **p)
141 /* --- @qq_head@ --- *
143 * Arguments: @FILE *fp@ = output file handle
147 * Use: Writes the head of a `qqout.c' file.
150 void qq_head(FILE *fp)
152 fputs("/* quine output file */\n\n", fp);
155 /* --- @qq_body@ --- *
157 * Arguments: @FILE *fp@ = output file handle
158 * @const char ***p@ = pointer to main table
162 * Use: Writes the body table of a `qqout.c' file.
165 void qq_body(FILE *fp, const char ***p)
170 fputs("/* --- file contents tables --- */\n\n", fp);
173 fprintf(fp, "static const char *qq__c_%lx[] = {\n", (unsigned long)fno);
174 fprintf(fp, "/* Filename: */ \"%s\",\n", *q++);
175 if (strncmp(*q, "%!", 2) == 0)
176 fprintf(fp, "/* Mode: */ \"%s\",\n", *q++);
178 fprintf(fp, "\"%s\",\n", *q++);
179 fputs("0\n};\n\n", fp);
185 /* --- @qq_tail@ --- *
187 * Arguments: @FILE *fp@ = output file handle
188 * @const char **qql@ = pointer to qqlib file array
189 * @size_t fno@ = number of files written
190 * @const char *fn@ = name of `qqout.c' file
194 * Use: Writes the head of a `qqout.c' file.
197 void qq_tail(FILE *fp, const char **qql, size_t fno, const char *fn)
202 /* --- Write out the qqlib array --- */
204 fputs("/* --- qqlib code --- */\n\n"
205 "const char *qq_qqlib[] = {\n", fp);
206 for (p = qql; *p; p++)
207 fprintf(fp, "\"%s\",\n", *p);
208 fputs("0\n};\n\n", fp);
210 /* --- Build the main array --- */
212 fputs("/* --- table of files to output --- */\n\n"
213 "const char **qq_table[] = {\n", fp);
214 for (i = 0; i < fno; i++)
215 fprintf(fp, " qq__c_%lx,\n", (unsigned long)i);
216 fputs(" 0\n};\n\n", fp);
218 /* --- Now output the qqlib code --- */
220 fputs("#define QQ_OUT\n\n", fp);
223 /* --- Finally write the code to write everything out --- */
226 "/* --- quine output routines --- */\n\n"
227 "void qq_dump(FILE *fp) {\n"
228 " qq__dump(fp, qq_table, qq_qqlib, \"%s\", %lu);\n"
230 "int qq_create(void) {\n"
231 " return (qq__create(qq_table, qq_qqlib, \"%s\", %lu));\n"
233 fn, (unsigned long)fno, fn, (unsigned long)fno);
236 /* --- @qq_mkfile@ --- *
238 * Arguments: @const char *fn@ = pointer to a filename
239 * @int mode@ = file mode to use (only in Unix-specific version)
241 * Returns: A handle for the created file.
243 * Use: Creates a file, and leading directories and stuff.
246 #ifdef QUINE_PORTABLE
247 FILE *qq_mkfile(const char *fn)
249 return (fopen(fn, "w"));
252 FILE *qq_mkfile(const char *fn, int mode)
254 char buf[FILENAME_MAX];
259 p = strchr(buf, '/');
266 p = strchr(p + 1, '/');
269 fd = open(fn, O_WRONLY|O_CREAT|O_TRUNC, mode);
270 return (fd >=0 ? fdopen(fd, "w") : 0);
276 /* --- @qq__dump@ --- *
278 * Arguments: @FILE *fp@ = file to dump on
279 * @const char ***p@ = pointer to main table
280 * @const char **qql@ = pointer to qqlib code
281 * @const char *fn@ = name of `qqout.c' file
282 * @size_t fno@ = number of files to be output
286 * Use: Outputs the entire source code to a given file.
289 static void qq__dump(FILE *fp, const char ***p, const char **qql,
290 const char *fn, size_t fno)
295 fprintf(fp, "******** %s\n\n", **q);
299 fprintf(fp, "******** %s\n\n", fn);
302 qq_tail(fp, qql, fno, fn);
305 /* --- @qq__create@ --- *
307 * Arguments: @const char ***p@ = pointer to main table
308 * @const char **qql@ = pointer to qqlib code
309 * @const char *fn@ = name of `qqout.c' file
310 * @size_t fno@ = number of files to be output
312 * Returns: Zero if all went well, else nonzero.
314 * Use: Rebuilds the original source distribution.
317 static int qq__create(const char ***p, const char **qql,
318 const char *fn, size_t fno)
324 const char **qq = *q + 1;
326 #ifdef QUINE_PORTABLE
327 if (strncmp(*qq, "%!", 2) == 0)
331 if (strncmp(*qq, "%!", 2) == 0) {
332 fp = qq_mkfile(**q, (int)strtol(*qq + 2, 0, 8));
335 fp = qq_mkfile(**q, 0666);
345 fp = qq_mkfile(fn, 0666);
350 qq_tail(fp, qql, fno, fn);
358 /*----- That's all, folks -------------------------------------------------*/