* m4/gnulib-cache.m4: Augment with 'gnulib-tool --import stdint'.
[m4/ericb.git] / src / freeze.c
blob7b8a7bc30c175b31b921e774fbf3acb902a26d63
1 /* GNU m4 -- A simple macro processor
3 Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994, 2006
4 Free Software Foundation, Inc.
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.
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.
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
22 /* This module handles frozen files. */
24 #include "m4.h"
26 /*-------------------------------------------------------------------.
27 | Destructively reverse a symbol list and return the reversed list. |
28 `-------------------------------------------------------------------*/
30 static symbol *
31 reverse_symbol_list (symbol *sym)
33 symbol *result;
34 symbol *next;
36 result = NULL;
37 while (sym)
39 next = SYMBOL_NEXT (sym);
40 SYMBOL_NEXT (sym) = result;
41 result = sym;
42 sym = next;
44 return result;
47 /*------------------------------------------------.
48 | Produce a frozen state to the given file NAME. |
49 `------------------------------------------------*/
51 void
52 produce_frozen_state (const char *name)
54 FILE *file;
55 int h;
56 symbol *sym;
57 const builtin *bp;
59 if (file = fopen (name, O_BINARY ? "wb" : "w"), !file)
61 M4ERROR ((warning_status, errno, name));
62 return;
65 /* Write a recognizable header. */
67 fprintf (file, "# This is a frozen state file generated by %s\n",
68 PACKAGE_STRING);
69 fprintf (file, "V1\n");
71 /* Dump quote delimiters. */
73 if (strcmp (lquote.string, DEF_LQUOTE) || strcmp (rquote.string, DEF_RQUOTE))
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);
81 /* Dump comment delimiters. */
83 if (strcmp (bcomm.string, DEF_BCOMM) || strcmp (ecomm.string, DEF_ECOMM))
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);
91 /* Dump all symbols. */
93 for (h = 0; h < hash_table_size; h++)
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. */
100 symtab[h] = reverse_symbol_list (symtab[h]);
101 for (sym = symtab[h]; sym; sym = SYMBOL_NEXT (sym))
103 switch (SYMBOL_TYPE (sym))
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;
114 case TOKEN_FUNC:
115 bp = find_builtin_by_addr (SYMBOL_FUNC (sym));
116 if (bp == NULL)
118 M4ERROR ((warning_status, 0, "\
119 INTERNAL ERROR: builtin not found in builtin table!"));
120 abort ();
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;
130 default:
131 M4ERROR ((warning_status, 0, "\
132 INTERNAL ERROR: bad token data type in freeze_one_symbol ()"));
133 abort ();
134 break;
138 /* Reverse the bucket once more, putting it back as it was. */
140 symtab[h] = reverse_symbol_list (symtab[h]);
143 /* Let diversions be issued from output.c module, its cleaner to have this
144 piece of code there. */
146 freeze_diversions (file);
148 /* All done. */
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"));
155 /*----------------------------------------------------------------------.
156 | Issue a message saying that some character is an EXPECTED character. |
157 `----------------------------------------------------------------------*/
159 static void
160 issue_expect_message (int expected)
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));
169 /*-------------------------------------------------.
170 | Reload a frozen state from the given file NAME. |
171 `-------------------------------------------------*/
173 /* We are seeking speed, here. */
175 void
176 reload_frozen_state (const char *name)
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;
186 #define GET_CHARACTER \
187 (character = getc (file))
189 #define GET_NUMBER(Number) \
190 do \
192 (Number) = 0; \
193 while (isdigit (character)) \
195 (Number) = 10 * (Number) + character - '0'; \
196 GET_CHARACTER; \
199 while (0)
201 #define VALIDATE(Expected) \
202 do \
204 if (character != (Expected)) \
205 issue_expect_message ((Expected)); \
207 while (0)
209 /* Skip comments (`#' at beginning of line) and blank lines, setting
210 character to the next directive or to EOF. */
212 #define GET_DIRECTIVE \
213 do \
215 GET_CHARACTER; \
216 if (character == '#') \
218 while (character != EOF && character != '\n') \
219 GET_CHARACTER; \
220 VALIDATE ('\n'); \
223 while (character == '\n')
225 file = m4_path_search (name, NULL);
226 if (file == NULL)
227 M4ERROR ((EXIT_FAILURE, errno, "cannot open %s", name));
229 allocated[0] = 100;
230 string[0] = xcharalloc ((size_t) allocated[0]);
231 allocated[1] = 100;
232 string[1] = xcharalloc ((size_t) allocated[1]);
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');
248 GET_DIRECTIVE;
249 while (character != EOF)
251 switch (character)
253 default:
254 M4ERROR ((EXIT_FAILURE, 0, "ill-formed frozen file"));
256 case 'C':
257 case 'D':
258 case 'F':
259 case 'T':
260 case 'Q':
261 operation = character;
262 GET_CHARACTER;
264 /* Get string lengths. Accept a negative diversion number. */
266 if (operation == 'D' && character == '-')
268 GET_CHARACTER;
269 GET_NUMBER (number[0]);
270 number[0] = -number[0];
272 else
273 GET_NUMBER (number[0]);
274 VALIDATE (',');
275 GET_CHARACTER;
276 GET_NUMBER (number[1]);
277 VALIDATE ('\n');
279 if (operation != 'D')
282 /* Get first string contents. */
284 if (number[0] + 1 > allocated[0])
286 free (string[0]);
287 allocated[0] = number[0] + 1;
288 string[0] = xcharalloc ((size_t) allocated[0]);
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"));
295 string[0][number[0]] = '\0';
298 /* Get second string contents. */
300 if (number[1] + 1 > allocated[1])
302 free (string[1]);
303 allocated[1] = number[1] + 1;
304 string[1] = xcharalloc ((size_t) allocated[1]);
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"));
311 string[1][number[1]] = '\0';
312 GET_CHARACTER;
313 VALIDATE ('\n');
315 /* Act according to operation letter. */
317 switch (operation)
319 case 'C':
321 /* Change comment strings. */
323 set_comment (string[0], string[1]);
324 break;
326 case 'D':
328 /* Select a diversion and add a string to it. */
330 make_diversion (number[0]);
331 if (number[1] > 0)
332 shipout_text (NULL, string[1], number[1]);
333 break;
335 case 'F':
337 /* Enter a macro having a builtin function as a definition. */
339 bp = find_builtin_by_name (string[1]);
340 define_builtin (string[0], bp, SYMBOL_PUSHDEF);
341 break;
343 case 'T':
345 /* Enter a macro having an expansion text as a definition. */
347 define_user_macro (string[0], string[1], SYMBOL_PUSHDEF);
348 break;
350 case 'Q':
352 /* Change quote strings. */
354 set_quotes (string[0], string[1]);
355 break;
357 default:
359 /* Cannot happen. */
361 break;
363 break;
366 GET_DIRECTIVE;
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"));
375 #undef GET_CHARACTER
376 #undef GET_DIRECTIVE
377 #undef GET_NUMBER
378 #undef VALIDATE