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
22 /* This module handles frozen files. */
26 /*-------------------------------------------------------------------.
27 | Destructively reverse a symbol list and return the reversed list. |
28 `-------------------------------------------------------------------*/
31 reverse_symbol_list (symbol
*sym
)
39 next
= SYMBOL_NEXT (sym
);
40 SYMBOL_NEXT (sym
) = result
;
47 /*------------------------------------------------.
48 | Produce a frozen state to the given file NAME. |
49 `------------------------------------------------*/
52 produce_frozen_state (const char *name
)
59 if (file
= fopen (name
, O_BINARY
? "wb" : "w"), !file
)
61 M4ERROR ((warning_status
, errno
, name
));
65 /* Write a recognizable header. */
67 fprintf (file
, "# This is a frozen state file generated by %s\n",
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
);
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
);
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
))
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
);
115 bp
= find_builtin_by_addr (SYMBOL_FUNC (sym
));
118 M4ERROR ((warning_status
, 0, "\
119 INTERNAL ERROR: builtin not found in builtin table!"));
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
);
131 M4ERROR ((warning_status
, 0, "\
132 INTERNAL ERROR: bad token data type in freeze_one_symbol ()"));
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
);
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 `----------------------------------------------------------------------*/
160 issue_expect_message (int expected
)
162 if (expected
== '\n')
163 M4ERROR ((EXIT_FAILURE
, 0, "expecting line feed in frozen file"));
165 M4ERROR ((EXIT_FAILURE
, 0, "expecting character `%c' in frozen file",
169 /*-------------------------------------------------.
170 | Reload a frozen state from the given file NAME. |
171 `-------------------------------------------------*/
173 /* We are seeking speed, here. */
176 reload_frozen_state (const char *name
)
186 #define GET_CHARACTER \
187 (character = getc (file))
189 #define GET_NUMBER(Number) \
193 while (isdigit (character)) \
195 (Number) = 10 * (Number) + character - '0'; \
201 #define VALIDATE(Expected) \
204 if (character != (Expected)) \
205 issue_expect_message ((Expected)); \
209 /* Skip comments (`#' at beginning of line) and blank lines, setting
210 character to the next directive or to EOF. */
212 #define GET_DIRECTIVE \
216 if (character == '#') \
218 while (character != EOF && character != '\n') \
223 while (character == '\n')
225 file
= path_search (name
, NULL
);
227 M4ERROR ((EXIT_FAILURE
, errno
, "cannot open %s", name
));
230 string
[0] = xmalloc ((size_t) allocated
[0]);
232 string
[1] = xmalloc ((size_t) allocated
[1]);
234 /* Validate format version. Only `1' is acceptable for now. */
238 GET_NUMBER (number
[0]);
240 M4ERROR ((EXIT_MISMATCH
, 0,
241 "frozen file version %d greater than max supported of 1",
243 else if (number
[0] < 1)
244 M4ERROR ((EXIT_FAILURE
, 0,
245 "ill-formed frozen file, version directive expected"));
249 while (character
!= EOF
)
254 M4ERROR ((EXIT_FAILURE
, 0, "ill-formed frozen file"));
261 operation
= character
;
264 /* Get string lengths. Accept a negative diversion number. */
266 if (operation
== 'D' && character
== '-')
269 GET_NUMBER (number
[0]);
270 number
[0] = -number
[0];
273 GET_NUMBER (number
[0]);
276 GET_NUMBER (number
[1]);
279 if (operation
!= 'D')
282 /* Get first string contents. */
284 if (number
[0] + 1 > allocated
[0])
287 allocated
[0] = number
[0] + 1;
288 string
[0] = xmalloc ((size_t) allocated
[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])
303 allocated
[1] = number
[1] + 1;
304 string
[1] = xmalloc ((size_t) allocated
[1]);
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';
315 /* Act according to operation letter. */
321 /* Change comment strings. */
323 set_comment (string
[0], string
[1]);
328 /* Select a diversion and add a string to it. */
330 make_diversion (number
[0]);
332 shipout_text (NULL
, string
[1], number
[1]);
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
);
345 /* Enter a macro having an expansion text as a definition. */
347 define_user_macro (string
[0], string
[1], SYMBOL_PUSHDEF
);
352 /* Change quote strings. */
354 set_quotes (string
[0], string
[1]);
372 if (ferror (file
) || fclose (file
) != 0)
373 M4ERROR ((EXIT_FAILURE
, errno
, "unable to read frozen state"));