source: trunk/essentials/sys-devel/m4/src/freeze.c

Last change on this file was 3090, checked in by bird, 18 years ago

m4 1.4.8

File size: 10.1 KB
Line 
1/* GNU m4 -- A simple macro processor
2
3 Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994, 2006
4 Free Software Foundation, Inc.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA
20*/
21
22/* This module handles frozen files. */
23
24#include "m4.h"
25
26/*-------------------------------------------------------------------.
27| Destructively reverse a symbol list and return the reversed list. |
28`-------------------------------------------------------------------*/
29
30static symbol *
31reverse_symbol_list (symbol *sym)
32{
33 symbol *result;
34 symbol *next;
35
36 result = NULL;
37 while (sym)
38 {
39 next = SYMBOL_NEXT (sym);
40 SYMBOL_NEXT (sym) = result;
41 result = sym;
42 sym = next;
43 }
44 return result;
45}
46
47/*------------------------------------------------.
48| Produce a frozen state to the given file NAME. |
49`------------------------------------------------*/
50
51void
52produce_frozen_state (const char *name)
53{
54 FILE *file;
55 int h;
56 symbol *sym;
57 const builtin *bp;
58
59 if (file = fopen (name, O_BINARY ? "wb" : "w"), !file)
60 {
61 M4ERROR ((warning_status, errno, name));
62 return;
63 }
64
65 /* Write a recognizable header. */
66
67 fprintf (file, "# This is a frozen state file generated by %s\n",
68 PACKAGE_STRING);
69 fprintf (file, "V1\n");
70
71 /* Dump quote delimiters. */
72
73 if (strcmp (lquote.string, DEF_LQUOTE) || strcmp (rquote.string, DEF_RQUOTE))
74 {
75 fprintf (file, "Q%d,%d\n", (int) lquote.length, (int) rquote.length);
76 fputs (lquote.string, file);
77 fputs (rquote.string, file);
78 fputc ('\n', file);
79 }
80
81 /* Dump comment delimiters. */
82
83 if (strcmp (bcomm.string, DEF_BCOMM) || strcmp (ecomm.string, DEF_ECOMM))
84 {
85 fprintf (file, "C%d,%d\n", (int) bcomm.length, (int) ecomm.length);
86 fputs (bcomm.string, file);
87 fputs (ecomm.string, file);
88 fputc ('\n', file);
89 }
90
91 /* Dump all symbols. */
92
93 for (h = 0; h < hash_table_size; h++)
94 {
95
96 /* Process all entries in one bucket, from the last to the first.
97 This order ensures that, at reload time, pushdef's will be
98 executed with the oldest definitions first. */
99
100 symtab[h] = reverse_symbol_list (symtab[h]);
101 for (sym = symtab[h]; sym; sym = SYMBOL_NEXT (sym))
102 {
103 switch (SYMBOL_TYPE (sym))
104 {
105 case TOKEN_TEXT:
106 fprintf (file, "T%d,%d\n",
107 (int) strlen (SYMBOL_NAME (sym)),
108 (int) strlen (SYMBOL_TEXT (sym)));
109 fputs (SYMBOL_NAME (sym), file);
110 fputs (SYMBOL_TEXT (sym), file);
111 fputc ('\n', file);
112 break;
113
114 case TOKEN_FUNC:
115 bp = find_builtin_by_addr (SYMBOL_FUNC (sym));
116 if (bp == NULL)
117 {
118 M4ERROR ((warning_status, 0, "\
119INTERNAL ERROR: builtin not found in builtin table!"));
120 abort ();
121 }
122 fprintf (file, "F%d,%d\n",
123 (int) strlen (SYMBOL_NAME (sym)),
124 (int) strlen (bp->name));
125 fputs (SYMBOL_NAME (sym), file);
126 fputs (bp->name, file);
127 fputc ('\n', file);
128 break;
129
130 default:
131 M4ERROR ((warning_status, 0, "\
132INTERNAL ERROR: bad token data type in freeze_one_symbol ()"));
133 abort ();
134 break;
135 }
136 }
137
138 /* Reverse the bucket once more, putting it back as it was. */
139
140 symtab[h] = reverse_symbol_list (symtab[h]);
141 }
142
143 /* Let diversions be issued from output.c module, its cleaner to have this
144 piece of code there. */
145
146 freeze_diversions (file);
147
148 /* All done. */
149
150 fputs ("# End of frozen state file\n", file);
151 if (close_stream (file) != 0)
152 M4ERROR ((EXIT_FAILURE, errno, "unable to create frozen state"));
153}
154
155/*----------------------------------------------------------------------.
156| Issue a message saying that some character is an EXPECTED character. |
157`----------------------------------------------------------------------*/
158
159static void
160issue_expect_message (int expected)
161{
162 if (expected == '\n')
163 M4ERROR ((EXIT_FAILURE, 0, "expecting line feed in frozen file"));
164 else
165 M4ERROR ((EXIT_FAILURE, 0, "expecting character `%c' in frozen file",
166 expected));
167}
168
169/*-------------------------------------------------.
170| Reload a frozen state from the given file NAME. |
171`-------------------------------------------------*/
172
173/* We are seeking speed, here. */
174
175void
176reload_frozen_state (const char *name)
177{
178 FILE *file;
179 int character;
180 int operation;
181 char *string[2];
182 int allocated[2];
183 int number[2];
184 const builtin *bp;
185
186#define GET_CHARACTER \
187 (character = getc (file))
188
189#define GET_NUMBER(Number) \
190 do \
191 { \
192 (Number) = 0; \
193 while (isdigit (character)) \
194 { \
195 (Number) = 10 * (Number) + character - '0'; \
196 GET_CHARACTER; \
197 } \
198 } \
199 while (0)
200
201#define VALIDATE(Expected) \
202 do \
203 { \
204 if (character != (Expected)) \
205 issue_expect_message ((Expected)); \
206 } \
207 while (0)
208
209 /* Skip comments (`#' at beginning of line) and blank lines, setting
210 character to the next directive or to EOF. */
211
212#define GET_DIRECTIVE \
213 do \
214 { \
215 GET_CHARACTER; \
216 if (character == '#') \
217 { \
218 while (character != EOF && character != '\n') \
219 GET_CHARACTER; \
220 VALIDATE ('\n'); \
221 } \
222 } \
223 while (character == '\n')
224
225 file = m4_path_search (name, NULL);
226 if (file == NULL)
227 M4ERROR ((EXIT_FAILURE, errno, "cannot open %s", name));
228
229 allocated[0] = 100;
230 string[0] = xcharalloc ((size_t) allocated[0]);
231 allocated[1] = 100;
232 string[1] = xcharalloc ((size_t) allocated[1]);
233
234 /* Validate format version. Only `1' is acceptable for now. */
235 GET_DIRECTIVE;
236 VALIDATE ('V');
237 GET_CHARACTER;
238 GET_NUMBER (number[0]);
239 if (number[0] > 1)
240 M4ERROR ((EXIT_MISMATCH, 0,
241 "frozen file version %d greater than max supported of 1",
242 number[0]));
243 else if (number[0] < 1)
244 M4ERROR ((EXIT_FAILURE, 0,
245 "ill-formed frozen file, version directive expected"));
246 VALIDATE ('\n');
247
248 GET_DIRECTIVE;
249 while (character != EOF)
250 {
251 switch (character)
252 {
253 default:
254 M4ERROR ((EXIT_FAILURE, 0, "ill-formed frozen file"));
255
256 case 'C':
257 case 'D':
258 case 'F':
259 case 'T':
260 case 'Q':
261 operation = character;
262 GET_CHARACTER;
263
264 /* Get string lengths. Accept a negative diversion number. */
265
266 if (operation == 'D' && character == '-')
267 {
268 GET_CHARACTER;
269 GET_NUMBER (number[0]);
270 number[0] = -number[0];
271 }
272 else
273 GET_NUMBER (number[0]);
274 VALIDATE (',');
275 GET_CHARACTER;
276 GET_NUMBER (number[1]);
277 VALIDATE ('\n');
278
279 if (operation != 'D')
280 {
281
282 /* Get first string contents. */
283
284 if (number[0] + 1 > allocated[0])
285 {
286 free (string[0]);
287 allocated[0] = number[0] + 1;
288 string[0] = xcharalloc ((size_t) allocated[0]);
289 }
290
291 if (number[0] > 0)
292 if (!fread (string[0], (size_t) number[0], 1, file))
293 M4ERROR ((EXIT_FAILURE, 0, "premature end of frozen file"));
294
295 string[0][number[0]] = '\0';
296 }
297
298 /* Get second string contents. */
299
300 if (number[1] + 1 > allocated[1])
301 {
302 free (string[1]);
303 allocated[1] = number[1] + 1;
304 string[1] = xcharalloc ((size_t) allocated[1]);
305 }
306
307 if (number[1] > 0)
308 if (!fread (string[1], (size_t) number[1], 1, file))
309 M4ERROR ((EXIT_FAILURE, 0, "premature end of frozen file"));
310
311 string[1][number[1]] = '\0';
312 GET_CHARACTER;
313 VALIDATE ('\n');
314
315 /* Act according to operation letter. */
316
317 switch (operation)
318 {
319 case 'C':
320
321 /* Change comment strings. */
322
323 set_comment (string[0], string[1]);
324 break;
325
326 case 'D':
327
328 /* Select a diversion and add a string to it. */
329
330 make_diversion (number[0]);
331 if (number[1] > 0)
332 shipout_text (NULL, string[1], number[1]);
333 break;
334
335 case 'F':
336
337 /* Enter a macro having a builtin function as a definition. */
338
339 bp = find_builtin_by_name (string[1]);
340 define_builtin (string[0], bp, SYMBOL_PUSHDEF);
341 break;
342
343 case 'T':
344
345 /* Enter a macro having an expansion text as a definition. */
346
347 define_user_macro (string[0], string[1], SYMBOL_PUSHDEF);
348 break;
349
350 case 'Q':
351
352 /* Change quote strings. */
353
354 set_quotes (string[0], string[1]);
355 break;
356
357 default:
358
359 /* Cannot happen. */
360
361 break;
362 }
363 break;
364
365 }
366 GET_DIRECTIVE;
367 }
368
369 free (string[0]);
370 free (string[1]);
371 errno = 0;
372 if (ferror (file) || fclose (file) != 0)
373 M4ERROR ((EXIT_FAILURE, errno, "unable to read frozen state"));
374
375#undef GET_CHARACTER
376#undef GET_DIRECTIVE
377#undef GET_NUMBER
378#undef VALIDATE
379}
Note: See TracBrowser for help on using the repository browser.