3 * Useful library of tools for quines
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.
26 * However, when this source text is embedded in a file by the Quine
27 * program, you may do anything you like with the resulting text;
28 * distribution and modification are not limited by the General Public
32 /*----- Header files ------------------------------------------------------*/
34 /* --- ANSI headers --- */
41 /* --- POSIX headers --- */
43 #ifndef QUINE_PORTABLE
44 # include <sys/types.h>
45 # include <sys/fcntl.h>
46 # include <sys/stat.h>
50 /* --- Local headers --- */
54 /*----- Macro hacking -----------------------------------------------------*/
64 /*----- Main code ---------------------------------------------------------*/
66 /* --- @qq_xlate@ --- *
68 * Arguments: @FILE *fp@ = output file handle
69 * @const char *p@ = pointer to encoded text
73 * Use: Writes the decoded string to the given file handle.
76 void qq_xlate(FILE *fp
, const char *p
)
82 case 'q': fputc('\"', fp
); break;
83 case 'b': fputc('\\', fp
); break;
84 case 't': fputc('\t', fp
); break;
85 case 'n': fputc('\n', fp
); break;
86 case 'a': fputc('\a', fp
); break;
87 case 'r': fputc('\r', fp
); break;
88 case '0': fputc('\0', fp
); break;
89 case '%': fputc('%', fp
); break;
94 unsigned int x
= *p
++;
96 if (x
>= 10) x
-= 'a' - '0' - 10;
97 if (x
>= 16) x
-= 'A' - 'a';
112 /* --- @qq_file@ --- *
114 * Arguments: @FILE *fp@ = output file handle
115 * @const char **p@ = pointer to the output array
119 * Use: Writes the contents of a file to the output.
122 void qq_file(FILE *fp
, const char **p
)
128 /* --- @qq_head@ --- *
130 * Arguments: @FILE *fp@ = output file handle
134 * Use: Writes the head of a `qqout.c' file.
137 void qq_head(FILE *fp
)
139 fputs("/* quine output file */\n\n", fp
);
142 /* --- @qq_body@ --- *
144 * Arguments: @FILE *fp@ = output file handle
145 * @const char ***p@ = pointer to main table
149 * Use: Writes the body table of a `qqout.c' file.
152 void qq_body(FILE *fp
, const char ***p
)
157 fputs("/* --- file contents tables --- */\n\n", fp
);
160 fprintf(fp
, "static const char *qq__c_%lx[] = {\n", (unsigned long)fno
);
161 fprintf(fp
, "/* Filename: */ \"%s\",\n", *q
++);
162 if (strncmp(*q
, "%!", 2) == 0)
163 fprintf(fp
, "/* Mode: */ \"%s\",\n", *q
++);
165 fprintf(fp
, "\"%s\",\n", *q
++);
166 fputs("0\n};\n\n", fp
);
172 /* --- @qq_tail@ --- *
174 * Arguments: @FILE *fp@ = output file handle
175 * @const char **qql@ = pointer to qqlib file array
176 * @size_t fno@ = number of files written
177 * @const char *fn@ = name of `qqout.c' file
181 * Use: Writes the head of a `qqout.c' file.
184 void qq_tail(FILE *fp
, const char **qql
, size_t fno
, const char *fn
)
189 /* --- Write out the qqlib array --- */
191 fputs("/* --- qqlib code --- */\n\n"
192 "const char *qq_qqlib[] = {\n", fp
);
193 for (p
= qql
; *p
; p
++)
194 fprintf(fp
, "\"%s\",\n", *p
);
195 fputs("0\n};\n\n", fp
);
197 /* --- Build the main array --- */
199 fputs("/* --- table of files to output --- */\n\n"
200 "const char **qq_table[] = {\n", fp
);
201 for (i
= 0; i
< fno
; i
++)
202 fprintf(fp
, " qq__c_%lx,\n", (unsigned long)i
);
203 fputs(" 0\n};\n\n", fp
);
205 /* --- Now output the qqlib code --- */
207 fputs("#define QQ_OUT\n\n", fp
);
210 /* --- Finally write the code to write everything out --- */
213 "/* --- quine output routines --- */\n\n"
214 "void qq_dump(FILE *fp) {\n"
215 " qq__dump(fp, qq_table, qq_qqlib, \"%s\", %lu);\n"
217 "int qq_create(void) {\n"
218 " return (qq__create(qq_table, qq_qqlib, \"%s\", %lu));\n"
220 fn
, (unsigned long)fno
, fn
, (unsigned long)fno
);
223 /* --- @qq_mkfile@ --- *
225 * Arguments: @const char *fn@ = pointer to a filename
226 * @int mode@ = file mode to use (only in Unix-specific version)
228 * Returns: A handle for the created file.
230 * Use: Creates a file, and leading directories and stuff.
233 #ifdef QUINE_PORTABLE
234 FILE *qq_mkfile(const char *fn
)
236 return (fopen(fn
, "w"));
239 FILE *qq_mkfile(const char *fn
, int mode
)
241 char buf
[FILENAME_MAX
];
246 p
= strchr(buf
, '/');
253 p
= strchr(p
+ 1, '/');
256 fd
= open(fn
, O_WRONLY
|O_CREAT
|O_TRUNC
, mode
);
257 return (fd
>=0 ?
fdopen(fd
, "w") : 0);
263 /* --- @qq__dump@ --- *
265 * Arguments: @FILE *fp@ = file to dump on
266 * @const char ***p@ = pointer to main table
267 * @const char **qql@ = pointer to qqlib code
268 * @const char *fn@ = name of `qqout.c' file
269 * @size_t fno@ = number of files to be output
273 * Use: Outputs the entire source code to a given file.
276 static void qq__dump(FILE *fp
, const char ***p
, const char **qql
,
277 const char *fn
, size_t fno
)
282 fprintf(fp
, "******** %s\n\n", **q
);
286 fprintf(fp
, "******** %s\n\n", fn
);
289 qq_tail(fp
, qql
, fno
, fn
);
292 /* --- @qq__create@ --- *
294 * Arguments: @const char ***p@ = pointer to main table
295 * @const char **qql@ = pointer to qqlib code
296 * @const char *fn@ = name of `qqout.c' file
297 * @size_t fno@ = number of files to be output
299 * Returns: Zero if all went well, else nonzero.
301 * Use: Rebuilds the original source distribution.
304 static int qq__create(const char ***p
, const char **qql
,
305 const char *fn
, size_t fno
)
311 const char **qq
= *q
+ 1;
313 #ifdef QUINE_PORTABLE
314 if (strncmp(*qq
, "%!", 2) == 0)
318 if (strncmp(*qq
, "%!", 2) == 0) {
319 fp
= qq_mkfile(**q
, (int)strtol(*qq
+ 2, 0, 8));
322 fp
= qq_mkfile(**q
, 0666);
332 fp
= qq_mkfile(fn
, 0666);
337 qq_tail(fp
, qql
, fno
, fn
);
345 /*----- That's all, folks -------------------------------------------------*/