chiark / gitweb /
Debianization.
[quine] / qqlib.c
CommitLineData
267c6003 1/* -*-c-*-
2 *
7f6303ef 3 * $Id$
267c6003 4 *
5 * Useful library of tools for quines
6 *
7 * (c) 1999 Mark Wooding
8 */
9
10/*----- Licensing notice --------------------------------------------------*
11 *
12 * This file is part of Quine
13 *
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.
18 *
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.
23 *
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.
27 *
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
31 * License.
32 */
33
267c6003 34/*----- Header files ------------------------------------------------------*/
35
36/* --- ANSI headers --- */
37
267c6003 38#include <errno.h>
39#include <stdio.h>
40#include <stdlib.h>
41#include <string.h>
42
43/* --- POSIX headers --- */
44
45#ifndef QUINE_PORTABLE
46# include <sys/types.h>
47# include <sys/fcntl.h>
48# include <sys/stat.h>
49# include <unistd.h>
50#endif
51
52/* --- Local headers --- */
53
54#include "quine.h"
55
56/*----- Macro hacking -----------------------------------------------------*/
57
58#ifdef QUINE_PORTABLE
59# define PORT(x) x
60# define NPORT(x)
61#else
62# define PORT(x)
63# define NPORT(x) x
64#endif
65
66/*----- Main code ---------------------------------------------------------*/
67
68/* --- @qq_xlate@ --- *
69 *
70 * Arguments: @FILE *fp@ = output file handle
71 * @const char *p@ = pointer to encoded text
72 *
73 * Returns: ---
74 *
75 * Use: Writes the decoded string to the given file handle.
76 */
77
78void qq_xlate(FILE *fp, const char *p)
79{
80 while (*p) {
81 if (*p == '%') {
82 p++;
83 switch (*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;
92 case 'x': {
93 unsigned char ch = 0;
94 p++;
95 while (*p != '%') {
96 unsigned int x = *p++;
97 x -= '0';
98 if (x >= 10) x -= 'a' - '0' - 10;
99 if (x >= 16) x -= 'A' - 'a';
100 ch = (ch << 4) + x;
101 }
102 fputc(ch, fp);
103 } break;
104 default:
105 p--;
106 break;
107 }
108 } else
109 fputc(*p, fp);
110 p++;
111 }
112}
113
114/* --- @qq_file@ --- *
115 *
116 * Arguments: @FILE *fp@ = output file handle
117 * @const char **p@ = pointer to the output array
118 *
119 * Returns: ---
120 *
121 * Use: Writes the contents of a file to the output.
122 */
123
124void qq_file(FILE *fp, const char **p)
125{
126 while (*p)
127 qq_xlate(fp, *p++);
128}
129
130/* --- @qq_head@ --- *
131 *
132 * Arguments: @FILE *fp@ = output file handle
133 *
134 * Returns: ---
135 *
136 * Use: Writes the head of a `qqout.c' file.
137 */
138
139void qq_head(FILE *fp)
140{
141 fputs("/* quine output file */\n\n", fp);
142}
143
144/* --- @qq_body@ --- *
145 *
146 * Arguments: @FILE *fp@ = output file handle
147 * @const char ***p@ = pointer to main table
148 *
149 * Returns: ---
150 *
151 * Use: Writes the body table of a `qqout.c' file.
152 */
153
154void qq_body(FILE *fp, const char ***p)
155{
156 size_t fno = 0;
157 const char **q;
158
159 fputs("/* --- file contents tables --- */\n\n", fp);
160 while (*p) {
161 q = *p;
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++);
166 while (*q)
167 fprintf(fp, "\"%s\",\n", *q++);
168 fputs("0\n};\n\n", fp);
169 p++;
170 fno++;
171 }
172}
173
174/* --- @qq_tail@ --- *
175 *
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
180 *
181 * Returns: ---
182 *
183 * Use: Writes the head of a `qqout.c' file.
184 */
185
186void qq_tail(FILE *fp, const char **qql, size_t fno, const char *fn)
187{
188 const char **p;
189 size_t i;
190
191 /* --- Write out the qqlib array --- */
192
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);
198
199 /* --- Build the main array --- */
200
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);
206
207 /* --- Now output the qqlib code --- */
208
209 fputs("#define QQ_OUT\n\n", fp);
210 qq_file(fp, qql);
211
212 /* --- Finally write the code to write everything out --- */
213
214 fprintf(fp,
215 "/* --- quine output routines --- */\n\n"
216 "void qq_dump(FILE *fp) {\n"
217 " qq__dump(fp, qq_table, qq_qqlib, \"%s\", %lu);\n"
218 "}\n"
219 "int qq_create(void) {\n"
220 " return (qq__create(qq_table, qq_qqlib, \"%s\", %lu));\n"
221 "}\n\n",
222 fn, (unsigned long)fno, fn, (unsigned long)fno);
223}
224
225/* --- @qq_mkfile@ --- *
226 *
227 * Arguments: @const char *fn@ = pointer to a filename
228 * @int mode@ = file mode to use (only in Unix-specific version)
229 *
230 * Returns: A handle for the created file.
231 *
232 * Use: Creates a file, and leading directories and stuff.
233 */
234
235#ifdef QUINE_PORTABLE
236FILE *qq_mkfile(const char *fn)
237{
238 return (fopen(fn, "w"));
239}
240#else
241FILE *qq_mkfile(const char *fn, int mode)
242{
243 char buf[FILENAME_MAX];
244 char *p;
245 int fd;
246
247 strcpy(buf, fn);
248 p = strchr(buf, '/');
249 for (;;) {
250 if (!p)
251 break;
252 *p = 0;
253 mkdir(buf, 0777);
254 *p = '/';
255 p = strchr(p + 1, '/');
256 }
257
258 fd = open(fn, O_WRONLY|O_CREAT|O_TRUNC, mode);
259 return (fd >=0 ? fdopen(fd, "w") : 0);
260}
261#endif
262
263#ifdef QQ_OUT
264
265/* --- @qq__dump@ --- *
266 *
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
272 *
273 * Returns: ---
274 *
275 * Use: Outputs the entire source code to a given file.
276 */
277
278static void qq__dump(FILE *fp, const char ***p, const char **qql,
279 const char *fn, size_t fno)
280{
281 const char ***q = p;
282
283 while (*q) {
284 fprintf(fp, "******** %s\n\n", **q);
285 qq_file(fp, *q + 1);
286 q++;
287 }
288 fprintf(fp, "******** %s\n\n", fn);
289 qq_head(fp);
290 qq_body(fp, p);
291 qq_tail(fp, qql, fno, fn);
292}
293
294/* --- @qq__create@ --- *
295 *
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
300 *
301 * Returns: Zero if all went well, else nonzero.
302 *
303 * Use: Rebuilds the original source distribution.
304 */
305
306static int qq__create(const char ***p, const char **qql,
307 const char *fn, size_t fno)
308{
309 FILE *fp;
310 const char ***q = p;
311
312 while (*q) {
313 const char **qq = *q + 1;
314
315#ifdef QUINE_PORTABLE
316 if (strncmp(*qq, "%!", 2) == 0)
317 qq++;
318 fp = qq_mkfile(*qq);
319#else
320 if (strncmp(*qq, "%!", 2) == 0) {
321 fp = qq_mkfile(**q, (int)strtol(*qq + 2, 0, 8));
322 qq++;
323 } else
324 fp = qq_mkfile(**q, 0666);
325#endif
326
327 if (!fp)
328 return (-1);
329 qq_file(fp, qq);
330 if (fclose(fp))
331 return (-1);
332 q++;
333 }
334 fp = qq_mkfile(fn, 0666);
335 if (!fp)
336 return (-1);
337 qq_head(fp);
338 qq_body(fp, p);
339 qq_tail(fp, qql, fno, fn);
340 if (fclose(fp))
341 return (-1);
342 return (0);
343}
344
345#endif
346
347/*----- That's all, folks -------------------------------------------------*/