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 /*----- Header files ------------------------------------------------------*/
36 /* --- ANSI headers --- */
43 /* --- POSIX headers --- */
45 #ifndef QUINE_PORTABLE
46 # include <sys/types.h>
47 # include <sys/fcntl.h>
48 # include <sys/stat.h>
52 /* --- Local headers --- */
56 /*----- Macro hacking -----------------------------------------------------*/
66 /*----- Main code ---------------------------------------------------------*/
68 /* --- @qq_xlate@ --- *
70 * Arguments: @FILE *fp@ = output file handle
71 * @const char *p@ = pointer to encoded text
75 * Use: Writes the decoded string to the given file handle.
78 void qq_xlate(FILE *fp
, const char *p
)
84 case 'q': fputc('\"', fp
); break;
85 case 'b': fputc('\\', fp
); break;
86 case 't': fputc('\t', fp
); break;
87 case 'n': fputc('\n', fp
); break;
88 case 'a': fputc('\a', fp
); break;
89 case 'r': fputc('\r', fp
); break;
90 case '0': fputc('\0', fp
); break;
91 case '%': fputc('%', fp
); break;
96 unsigned int x
= *p
++;
98 if (x
>= 10) x
-= 'a' - '0' - 10;
99 if (x
>= 16) x
-= 'A' - 'a';
114 /* --- @qq_file@ --- *
116 * Arguments: @FILE *fp@ = output file handle
117 * @const char **p@ = pointer to the output array
121 * Use: Writes the contents of a file to the output.
124 void qq_file(FILE *fp
, const char **p
)
130 /* --- @qq_head@ --- *
132 * Arguments: @FILE *fp@ = output file handle
136 * Use: Writes the head of a `qqout.c' file.
139 void qq_head(FILE *fp
)
141 fputs("/* quine output file */\n\n", fp
);
144 /* --- @qq_body@ --- *
146 * Arguments: @FILE *fp@ = output file handle
147 * @const char ***p@ = pointer to main table
151 * Use: Writes the body table of a `qqout.c' file.
154 void qq_body(FILE *fp
, const char ***p
)
159 fputs("/* --- file contents tables --- */\n\n", fp
);
162 fprintf(fp
, "static const char *qq__c_%lx[] = {\n", (unsigned long)fno
);
163 fprintf(fp
, "/* Filename: */ \"%s\",\n", *q
++);
164 if (strncmp(*q
, "%!", 2) == 0)
165 fprintf(fp
, "/* Mode: */ \"%s\",\n", *q
++);
167 fprintf(fp
, "\"%s\",\n", *q
++);
168 fputs("0\n};\n\n", fp
);
174 /* --- @qq_tail@ --- *
176 * Arguments: @FILE *fp@ = output file handle
177 * @const char **qql@ = pointer to qqlib file array
178 * @size_t fno@ = number of files written
179 * @const char *fn@ = name of `qqout.c' file
183 * Use: Writes the head of a `qqout.c' file.
186 void qq_tail(FILE *fp
, const char **qql
, size_t fno
, const char *fn
)
191 /* --- Write out the qqlib array --- */
193 fputs("/* --- qqlib code --- */\n\n"
194 "const char *qq_qqlib[] = {\n", fp
);
195 for (p
= qql
; *p
; p
++)
196 fprintf(fp
, "\"%s\",\n", *p
);
197 fputs("0\n};\n\n", fp
);
199 /* --- Build the main array --- */
201 fputs("/* --- table of files to output --- */\n\n"
202 "const char **qq_table[] = {\n", fp
);
203 for (i
= 0; i
< fno
; i
++)
204 fprintf(fp
, " qq__c_%lx,\n", (unsigned long)i
);
205 fputs(" 0\n};\n\n", fp
);
207 /* --- Now output the qqlib code --- */
209 fputs("#define QQ_OUT\n\n", fp
);
212 /* --- Finally write the code to write everything out --- */
215 "/* --- quine output routines --- */\n\n"
216 "void qq_dump(FILE *fp) {\n"
217 " qq__dump(fp, qq_table, qq_qqlib, \"%s\", %lu);\n"
219 "int qq_create(void) {\n"
220 " return (qq__create(qq_table, qq_qqlib, \"%s\", %lu));\n"
222 fn
, (unsigned long)fno
, fn
, (unsigned long)fno
);
225 /* --- @qq_mkfile@ --- *
227 * Arguments: @const char *fn@ = pointer to a filename
228 * @int mode@ = file mode to use (only in Unix-specific version)
230 * Returns: A handle for the created file.
232 * Use: Creates a file, and leading directories and stuff.
235 #ifdef QUINE_PORTABLE
236 FILE *qq_mkfile(const char *fn
)
238 return (fopen(fn
, "w"));
241 FILE *qq_mkfile(const char *fn
, int mode
)
243 char buf
[FILENAME_MAX
];
248 p
= strchr(buf
, '/');
255 p
= strchr(p
+ 1, '/');
258 fd
= open(fn
, O_WRONLY
|O_CREAT
|O_TRUNC
, mode
);
259 return (fd
>=0 ?
fdopen(fd
, "w") : 0);
265 /* --- @qq__dump@ --- *
267 * Arguments: @FILE *fp@ = file to dump on
268 * @const char ***p@ = pointer to main table
269 * @const char **qql@ = pointer to qqlib code
270 * @const char *fn@ = name of `qqout.c' file
271 * @size_t fno@ = number of files to be output
275 * Use: Outputs the entire source code to a given file.
278 static void qq__dump(FILE *fp
, const char ***p
, const char **qql
,
279 const char *fn
, size_t fno
)
284 fprintf(fp
, "******** %s\n\n", **q
);
288 fprintf(fp
, "******** %s\n\n", fn
);
291 qq_tail(fp
, qql
, fno
, fn
);
294 /* --- @qq__create@ --- *
296 * Arguments: @const char ***p@ = pointer to main table
297 * @const char **qql@ = pointer to qqlib code
298 * @const char *fn@ = name of `qqout.c' file
299 * @size_t fno@ = number of files to be output
301 * Returns: Zero if all went well, else nonzero.
303 * Use: Rebuilds the original source distribution.
306 static int qq__create(const char ***p
, const char **qql
,
307 const char *fn
, size_t fno
)
313 const char **qq
= *q
+ 1;
315 #ifdef QUINE_PORTABLE
316 if (strncmp(*qq
, "%!", 2) == 0)
320 if (strncmp(*qq
, "%!", 2) == 0) {
321 fp
= qq_mkfile(**q
, (int)strtol(*qq
+ 2, 0, 8));
324 fp
= qq_mkfile(**q
, 0666);
334 fp
= qq_mkfile(fn
, 0666);
339 qq_tail(fp
, qql
, fno
, fn
);
347 /*----- That's all, folks -------------------------------------------------*/