1
/* mp4h -- A macro processor for HTML documents
2
Copyright 2000-2003, Denis Barbier
5
This program is free software; you can redistribute it and/or modify
6
it under the terms of the GNU General Public License as published by
7
the Free Software Foundation; either version 2, or (at your option)
10
This program is a work based on GNU m4 version 1.4n. Below is the
13
/* GNU m4 -- A simple macro processor
14
Copyright (C) 1989, 90, 91, 92, 93, 94 Free Software Foundation, Inc.
16
This program is free software; you can redistribute it and/or modify
17
it under the terms of the GNU General Public License as published by
18
the Free Software Foundation; either version 2, or (at your option)
21
This program is distributed in the hope that it will be useful,
22
but WITHOUT ANY WARRANTY; without even the implied warranty of
23
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24
GNU General Public License for more details.
26
You should have received a copy of the GNU General Public License
27
along with this program; if not, write to the Free Software
28
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
31
/* This module handles frozen files. */
37
/*-------------------------------------------------------------------.
38
| Destructively reverse a symbol list and return the reversed list. |
39
`-------------------------------------------------------------------*/
42
reverse_symbol_list (symbol *sym)
50
next = SYMBOL_NEXT (sym);
51
SYMBOL_NEXT (sym) = result;
58
/*------------------------------------------------.
59
| Produce a frozen state to the given file NAME. |
60
`------------------------------------------------*/
63
produce_frozen_state (const char *name)
71
if (file = fopen (name, "w"), !file)
73
MP4HERROR ((warning_status, errno, name));
77
/* Write a recognizable header. */
79
fprintf (file, "# This is a frozen state file generated by %s %s\n",
81
fprintf (file, "V1\n");
83
/* Dump comment delimiters. */
84
if (strcmp (eolcomm.string, DEF_EOLCOMM))
86
fprintf (file, "C%d\n", (int) eolcomm.length);
87
fputs (eolcomm.string, file);
92
/* Dump all symbols. */
94
for (h = 0; h < hash_table_size; h++)
97
/* Process all entries in one bucket, from the last to the first.
98
This order ensures that, at reload time, pushdef's will be
99
executed with the oldest definitions first. */
101
symtab[h] = reverse_symbol_list (symtab[h]);
102
for (sym = symtab[h]; sym; sym = SYMBOL_NEXT (sym))
104
switch (SYMBOL_TYPE (sym))
107
if (*SYMBOL_NAME (sym) == '<')
109
fprintf (file, "A%d,%d\n",
110
(int) strlen (SYMBOL_NAME (sym)) - 1,
111
(int) strlen (SYMBOL_TEXT (sym)));
112
fputs (SYMBOL_NAME (sym) + 1, file);
116
fprintf (file, "T%d,%d\n",
117
(int) strlen (SYMBOL_NAME (sym)),
118
(int) strlen (SYMBOL_TEXT (sym)));
119
fputs (SYMBOL_NAME (sym), file);
121
fputs (SYMBOL_TEXT (sym), file);
123
if (*SYMBOL_NAME (sym) != '<')
125
fputc (SYMBOL_CONTAINER (sym) ? '1' : '0', file);
126
fputc (SYMBOL_EXPAND_ARGS (sym) ? '1' : '0', file);
128
number[0] = (SYMBOL_HOOK_BEGIN (sym) ?
129
strlen (SYMBOL_HOOK_BEGIN (sym)) : 0);
130
number[1] = (SYMBOL_HOOK_END (sym) ?
131
strlen (SYMBOL_HOOK_END (sym)) : 0);
132
fprintf (file, "%d,%d\n", number[0], number[1]);
133
if (SYMBOL_HOOK_BEGIN (sym))
134
fputs (SYMBOL_HOOK_BEGIN (sym), file);
135
if (SYMBOL_HOOK_END (sym))
136
fputs (SYMBOL_HOOK_END (sym), file);
142
bp = find_builtin_by_addr (SYMBOL_FUNC (sym));
145
MP4HERROR ((warning_status, 0, "\
146
INTERNAL ERROR: Built-in not found in builtin table!"));
149
fprintf (file, "F%d,%d\n",
150
(int) strlen (SYMBOL_NAME (sym)),
151
(int) strlen (bp->name));
152
fputs (SYMBOL_NAME (sym), file);
153
fputs (bp->name, file);
158
MP4HERROR ((warning_status, 0, "\
159
INTERNAL ERROR: Bad token data type in freeze_one_symbol ()"));
165
/* Reverse the bucket once more, putting it back as it was. */
167
symtab[h] = reverse_symbol_list (symtab[h]);
172
fputs ("# End of frozen state file\n", file);
176
/*----------------------------------------------------------------------.
177
| Issue a message saying that some character is an EXPECTED character. |
178
`----------------------------------------------------------------------*/
181
issue_expect_message (int expected)
183
if (expected == '\n')
184
MP4HERROR ((EXIT_FAILURE, 0, _("%d: Expecting line feed in frozen file"),
187
MP4HERROR ((EXIT_FAILURE, 0, _("%d: Expecting character `%c' in frozen file"),
191
/*-------------------------------------------------.
192
| Reload a frozen state from the given file NAME. |
193
`-------------------------------------------------*/
195
/* We are seeking speed, here. */
197
#define GET_CHARACTER \
198
(character = getc (file))
200
#define GET_NUMBER(Number) \
204
while (isdigit (character)) \
206
(Number) = 10 * (Number) + character - '0'; \
212
#define VALIDATE(Expected) \
215
if (character != (Expected)) \
216
issue_expect_message ((Expected)); \
221
reload_frozen_state (const char *name)
231
boolean container, expand_args;
233
file = path_search (name, (char **)NULL);
235
MP4HERROR ((EXIT_FAILURE, errno, _("Cannot open %s"), name));
239
string[0] = xmalloc ((size_t) allocated[0]);
241
string[1] = xmalloc ((size_t) allocated[1]);
243
while (GET_CHARACTER, character != EOF)
248
MP4HERROR ((EXIT_FAILURE, 0, _("Ill-formated frozen file")));
252
/* Skip empty lines. */
259
/* Comments are introduced by `#' at beginning of line, and are
262
while (character != EOF && character != '\n')
270
/* Change comment strings. */
273
GET_NUMBER (number[0]);
277
if (number[0] + 1 > allocated[0])
280
allocated[0] = number[0] + 1;
281
string[0] = xmalloc ((size_t) allocated[0]);
285
if (!fread (string[0], (size_t) number[0], 1, file))
286
MP4HERROR ((EXIT_FAILURE, 0, _("Premature end of frozen file")));
288
string[0][number[0]] = '\0';
293
eolcomm.string = string[0];
294
eolcomm.length = strlen (eolcomm.string);
300
operation = character;
303
/* Get string lengths. Accept a negative diversion number. */
306
GET_NUMBER (number[0]);
309
GET_NUMBER (number[1]);
313
/* Get first string contents. */
315
if (number[0] + 1 > allocated[0])
318
allocated[0] = number[0] + 1;
319
string[0] = xmalloc ((size_t) allocated[0]);
323
if (!fread (string[0], (size_t) number[0], 1, file))
324
MP4HERROR ((EXIT_FAILURE, 0, _("Premature end of frozen file")));
326
string[0][number[0]] = '\0';
328
/* Get second string contents. */
330
if (number[1] + 1 > allocated[1])
333
allocated[1] = number[1] + 1;
334
string[1] = xmalloc ((size_t) allocated[1]);
338
if (!fread (string[1], (size_t) number[1], 1, file))
339
MP4HERROR ((EXIT_FAILURE, 0, _("Premature end of frozen file")));
341
string[1][number[1]] = '\0';
347
/* Act according to operation letter. */
353
/* Define a variable. */
355
var = lookup_variable (string[0], SYMBOL_INSERT);
356
SYMBOL_TYPE (var) = TOKEN_TEXT;
357
SYMBOL_TEXT (var) = xstrdup (string[0]);
362
/* Enter a macro having a builtin function as a definition. */
364
bp = find_builtin_by_name (string[1]);
366
define_builtin (string[0], bp, 0);
368
MP4HERROR ((warning_status, 0, _("\
369
`%s' from frozen file not found in builtin table!"),
376
container = (character == '1');
378
expand_args = (character == '1');
383
/* Enter a macro having an expansion text as a definition. */
385
define_user_macro (string[0], string[1], SYMBOL_INSERT,
386
container, expand_args, FALSE);
388
sym = lookup_symbol (string[0], SYMBOL_LOOKUP);
393
GET_NUMBER (number[0]);
396
GET_NUMBER (number[1]);
402
if (number[0] + 1 > allocated[0])
405
allocated[0] = number[0] + 1;
406
string[0] = xmalloc ((size_t) allocated[0]);
408
if (!fread (string[0], (size_t) number[0], 1, file))
409
MP4HERROR ((EXIT_FAILURE, 0, _("Premature end of frozen file")));
411
string[0][number[0]] = '\0';
413
SYMBOL_HOOK_BEGIN (sym) = xstrdup (string[0]);
419
if (number[1] + 1 > allocated[1])
422
allocated[1] = number[1] + 1;
423
string[1] = xmalloc ((size_t) allocated[1]);
425
if (!fread (string[1], (size_t) number[1], 1, file))
426
MP4HERROR ((EXIT_FAILURE, 0, _("Premature end of frozen file")));
428
string[1][number[1]] = '\0';
430
SYMBOL_HOOK_END (sym) = xstrdup (string[1]);
449
/* Validate format version. Only `1' is acceptable for now. */