Fix texinfo grammar.
[m4/ericb.git] / src / freeze.c
blob383d008b508ac7bdc23658ff87baa5f733cae0ec
1 /* GNU m4 -- A simple macro processor
3 Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994, 2006, 2007, 2008
4 Free Software Foundation, Inc.
6 This file is part of GNU M4.
8 GNU M4 is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
13 GNU M4 is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
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 file = fopen (name, O_BINARY ? "wb" : "w");
60 if (!file)
62 m4_error (0, errno, NULL, _("cannot open %s"), name);
63 return;
66 /* Write a recognizable header. */
68 xfprintf (file, "# This is a frozen state file generated by %s\n",
69 PACKAGE_STRING);
70 xfprintf (file, "V1\n");
72 /* Dump quote delimiters. */
74 if (strcmp (curr_quote.str1, DEF_LQUOTE)
75 || strcmp (curr_quote.str2, DEF_RQUOTE))
76 xfprintf (file, "Q%d,%d\n%s%s\n", (int) curr_quote.len1,
77 (int) curr_quote.len2, curr_quote.str1, curr_quote.str2);
79 /* Dump comment delimiters. */
81 if (strcmp (curr_comm.str1, DEF_BCOMM) || strcmp (curr_comm.str2, DEF_ECOMM))
82 xfprintf (file, "C%d,%d\n%s%s\n", (int) curr_comm.len1,
83 (int) curr_comm.len2, curr_comm.str1, curr_comm.str2);
85 /* Dump all symbols. */
87 for (h = 0; h < hash_table_size; h++)
90 /* Process all entries in one bucket, from the last to the first.
91 This order ensures that, at reload time, pushdef's will be
92 executed with the oldest definitions first. */
94 symtab[h] = reverse_symbol_list (symtab[h]);
95 for (sym = symtab[h]; sym; sym = SYMBOL_NEXT (sym))
97 switch (SYMBOL_TYPE (sym))
99 case TOKEN_TEXT:
100 xfprintf (file, "T%d,%d\n",
101 (int) strlen (SYMBOL_NAME (sym)),
102 (int) strlen (SYMBOL_TEXT (sym)));
103 fputs (SYMBOL_NAME (sym), file);
104 fputs (SYMBOL_TEXT (sym), file);
105 fputc ('\n', file);
106 break;
108 case TOKEN_FUNC:
109 bp = find_builtin_by_addr (SYMBOL_FUNC (sym));
110 if (bp == NULL)
112 assert (!"produce_frozen_state");
113 abort ();
115 xfprintf (file, "F%d,%d\n",
116 (int) strlen (SYMBOL_NAME (sym)),
117 (int) strlen (bp->name));
118 fputs (SYMBOL_NAME (sym), file);
119 fputs (bp->name, file);
120 fputc ('\n', file);
121 break;
123 case TOKEN_VOID:
124 /* Ignore placeholder tokens that exist due to traceon. */
125 break;
127 default:
128 assert (!"produce_frozen_state");
129 abort ();
130 break;
134 /* Reverse the bucket once more, putting it back as it was. */
136 symtab[h] = reverse_symbol_list (symtab[h]);
139 /* Let diversions be issued from output.c module, its cleaner to have this
140 piece of code there. */
142 freeze_diversions (file);
144 /* All done. */
146 fputs ("# End of frozen state file\n", file);
147 if (close_stream (file) != 0)
148 m4_error (EXIT_FAILURE, errno, NULL, _("unable to create frozen state"));
151 /*----------------------------------------------------------------------.
152 | Issue a message saying that some character is an EXPECTED character. |
153 `----------------------------------------------------------------------*/
155 static void
156 issue_expect_message (int expected)
158 if (expected == '\n')
159 m4_error (EXIT_FAILURE, 0, NULL, _("expecting line feed in frozen file"));
160 else
161 m4_error (EXIT_FAILURE, 0, NULL,
162 _("expecting character `%c' in frozen file"), expected);
165 /*-------------------------------------------------.
166 | Reload a frozen state from the given file NAME. |
167 `-------------------------------------------------*/
169 /* We are seeking speed, here. */
171 void
172 reload_frozen_state (const char *name)
174 FILE *file;
175 int character;
176 int operation;
177 char *string[2];
178 int allocated[2];
179 int number[2];
180 const builtin *bp;
182 #define GET_CHARACTER \
183 (character = getc (file))
185 #define GET_NUMBER(Number) \
186 do \
188 (Number) = 0; \
189 while (isdigit (character)) \
191 (Number) = 10 * (Number) + character - '0'; \
192 GET_CHARACTER; \
195 while (0)
197 #define VALIDATE(Expected) \
198 do \
200 if (character != (Expected)) \
201 issue_expect_message ((Expected)); \
203 while (0)
205 /* Skip comments (`#' at beginning of line) and blank lines, setting
206 character to the next directive or to EOF. */
208 #define GET_DIRECTIVE \
209 do \
211 GET_CHARACTER; \
212 if (character == '#') \
214 while (character != EOF && character != '\n') \
215 GET_CHARACTER; \
216 VALIDATE ('\n'); \
219 while (character == '\n')
221 file = m4_path_search (name, NULL);
222 if (file == NULL)
223 m4_error (EXIT_FAILURE, errno, NULL, _("cannot open %s"), name);
225 allocated[0] = 100;
226 string[0] = xcharalloc ((size_t) allocated[0]);
227 allocated[1] = 100;
228 string[1] = xcharalloc ((size_t) allocated[1]);
230 /* Validate format version. Only `1' is acceptable for now. */
231 GET_DIRECTIVE;
232 VALIDATE ('V');
233 GET_CHARACTER;
234 GET_NUMBER (number[0]);
235 if (number[0] > 1)
236 m4_error (EXIT_MISMATCH, 0, NULL,
237 _("frozen file version %d greater than max supported of 1"),
238 number[0]);
239 else if (number[0] < 1)
240 m4_error (EXIT_FAILURE, 0, NULL,
241 _("ill-formed frozen file, version directive expected"));
242 VALIDATE ('\n');
244 GET_DIRECTIVE;
245 while (character != EOF)
247 switch (character)
249 default:
250 m4_error (EXIT_FAILURE, 0, NULL, _("ill-formed frozen file"));
252 case 'C':
253 case 'D':
254 case 'F':
255 case 'T':
256 case 'Q':
257 operation = character;
258 GET_CHARACTER;
260 /* Get string lengths. Accept a negative diversion number. */
262 if (operation == 'D' && character == '-')
264 GET_CHARACTER;
265 GET_NUMBER (number[0]);
266 number[0] = -number[0];
268 else
269 GET_NUMBER (number[0]);
270 VALIDATE (',');
271 GET_CHARACTER;
272 GET_NUMBER (number[1]);
273 VALIDATE ('\n');
275 if (operation != 'D')
278 /* Get first string contents. */
280 if (number[0] + 1 > allocated[0])
282 free (string[0]);
283 allocated[0] = number[0] + 1;
284 string[0] = xcharalloc ((size_t) allocated[0]);
287 if (number[0] > 0)
288 if (!fread (string[0], (size_t) number[0], 1, file))
289 m4_error (EXIT_FAILURE, 0, NULL,
290 _("premature end of frozen file"));
292 string[0][number[0]] = '\0';
295 /* Get second string contents. */
297 if (number[1] + 1 > allocated[1])
299 free (string[1]);
300 allocated[1] = number[1] + 1;
301 string[1] = xcharalloc ((size_t) allocated[1]);
304 if (number[1] > 0)
305 if (!fread (string[1], (size_t) number[1], 1, file))
306 m4_error (EXIT_FAILURE, 0, NULL,
307 _("premature end of frozen file"));
309 string[1][number[1]] = '\0';
310 GET_CHARACTER;
311 VALIDATE ('\n');
313 /* Act according to operation letter. */
315 switch (operation)
317 case 'C':
319 /* Change comment strings. */
321 set_comment (string[0], string[1]);
322 break;
324 case 'D':
326 /* Select a diversion and add a string to it. */
328 make_diversion (number[0]);
329 if (number[1] > 0)
330 output_text (string[1], number[1]);
331 break;
333 case 'F':
335 /* Enter a macro having a builtin function as a definition. */
337 bp = find_builtin_by_name (string[1]);
338 define_builtin (string[0], bp, SYMBOL_PUSHDEF);
339 break;
341 case 'T':
343 /* Enter a macro having an expansion text as a definition. */
345 define_user_macro (string[0], number[0], string[1],
346 SYMBOL_PUSHDEF);
347 break;
349 case 'Q':
351 /* Change quote strings. */
353 set_quotes (string[0], string[1]);
354 break;
356 default:
358 /* Cannot happen. */
360 break;
362 break;
365 GET_DIRECTIVE;
368 free (string[0]);
369 free (string[1]);
370 errno = 0;
371 if (ferror (file) || fclose (file) != 0)
372 m4_error (EXIT_FAILURE, errno, NULL, _("unable to read frozen state"));
374 #undef GET_CHARACTER
375 #undef GET_DIRECTIVE
376 #undef GET_NUMBER
377 #undef VALIDATE