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. */
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 file
= fopen (name
, O_BINARY
? "wb" : "w");
62 m4_error (0, errno
, NULL
, _("cannot open %s"), name
);
66 /* Write a recognizable header. */
68 xfprintf (file
, "# This is a frozen state file generated by %s\n",
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
))
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
);
109 bp
= find_builtin_by_addr (SYMBOL_FUNC (sym
));
112 assert (!"produce_frozen_state");
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
);
124 /* Ignore placeholder tokens that exist due to traceon. */
128 assert (!"produce_frozen_state");
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
);
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 `----------------------------------------------------------------------*/
156 issue_expect_message (int expected
)
158 if (expected
== '\n')
159 m4_error (EXIT_FAILURE
, 0, NULL
, _("expecting line feed in frozen file"));
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. */
172 reload_frozen_state (const char *name
)
182 #define GET_CHARACTER \
183 (character = getc (file))
185 #define GET_NUMBER(Number) \
189 while (isdigit (character)) \
191 (Number) = 10 * (Number) + character - '0'; \
197 #define VALIDATE(Expected) \
200 if (character != (Expected)) \
201 issue_expect_message ((Expected)); \
205 /* Skip comments (`#' at beginning of line) and blank lines, setting
206 character to the next directive or to EOF. */
208 #define GET_DIRECTIVE \
212 if (character == '#') \
214 while (character != EOF && character != '\n') \
219 while (character == '\n')
221 file
= m4_path_search (name
, NULL
);
223 m4_error (EXIT_FAILURE
, errno
, NULL
, _("cannot open %s"), name
);
226 string
[0] = xcharalloc ((size_t) allocated
[0]);
228 string
[1] = xcharalloc ((size_t) allocated
[1]);
230 /* Validate format version. Only `1' is acceptable for now. */
234 GET_NUMBER (number
[0]);
236 m4_error (EXIT_MISMATCH
, 0, NULL
,
237 _("frozen file version %d greater than max supported of 1"),
239 else if (number
[0] < 1)
240 m4_error (EXIT_FAILURE
, 0, NULL
,
241 _("ill-formed frozen file, version directive expected"));
245 while (character
!= EOF
)
250 m4_error (EXIT_FAILURE
, 0, NULL
, _("ill-formed frozen file"));
257 operation
= character
;
260 /* Get string lengths. Accept a negative diversion number. */
262 if (operation
== 'D' && character
== '-')
265 GET_NUMBER (number
[0]);
266 number
[0] = -number
[0];
269 GET_NUMBER (number
[0]);
272 GET_NUMBER (number
[1]);
275 if (operation
!= 'D')
278 /* Get first string contents. */
280 if (number
[0] + 1 > allocated
[0])
283 allocated
[0] = number
[0] + 1;
284 string
[0] = xcharalloc ((size_t) allocated
[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])
300 allocated
[1] = number
[1] + 1;
301 string
[1] = xcharalloc ((size_t) allocated
[1]);
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';
313 /* Act according to operation letter. */
319 /* Change comment strings. */
321 set_comment (string
[0], string
[1]);
326 /* Select a diversion and add a string to it. */
328 make_diversion (number
[0]);
330 output_text (string
[1], number
[1]);
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
);
343 /* Enter a macro having an expansion text as a definition. */
345 define_user_macro (string
[0], number
[0], string
[1],
351 /* Change quote strings. */
353 set_quotes (string
[0], string
[1]);
371 if (ferror (file
) || fclose (file
) != 0)
372 m4_error (EXIT_FAILURE
, errno
, NULL
, _("unable to read frozen state"));