#include "m4.h"
static symbol *
reverse_symbol_list (symbol *sym)
{
symbol *result;
symbol *next;
result = NULL;
while (sym)
{
next = SYMBOL_NEXT (sym);
SYMBOL_NEXT (sym) = result;
result = sym;
sym = next;
}
return result;
}
void
produce_frozen_state (const char *name)
{
FILE *file;
int h;
symbol *sym;
const builtin *bp;
if (file = fopen (name, "w"), !file)
{
M4ERROR ((warning_status, errno, name));
return;
}
fprintf (file, "# This is a frozen state file generated by GNU %s %s\n",
PRODUCT, VERSION);
fprintf (file, "V1\n");
if (strcmp (lquote.string, DEF_LQUOTE) || strcmp (rquote.string, DEF_RQUOTE))
{
fprintf (file, "Q%d,%d\n", (int) lquote.length, (int) rquote.length);
fputs (lquote.string, file);
fputs (rquote.string, file);
fputc ('\n', file);
}
if (strcmp (bcomm.string, DEF_BCOMM) || strcmp (ecomm.string, DEF_ECOMM))
{
fprintf (file, "C%d,%d\n", (int) bcomm.length, (int) ecomm.length);
fputs (bcomm.string, file);
fputs (ecomm.string, file);
fputc ('\n', file);
}
for (h = 0; h < hash_table_size; h++)
{
symtab[h] = reverse_symbol_list (symtab[h]);
for (sym = symtab[h]; sym; sym = SYMBOL_NEXT (sym))
{
switch (SYMBOL_TYPE (sym))
{
case TOKEN_TEXT:
fprintf (file, "T%d,%d\n",
(int) strlen (SYMBOL_NAME (sym)),
(int) strlen (SYMBOL_TEXT (sym)));
fputs (SYMBOL_NAME (sym), file);
fputs (SYMBOL_TEXT (sym), file);
fputc ('\n', file);
break;
case TOKEN_FUNC:
bp = find_builtin_by_addr (SYMBOL_FUNC (sym));
if (bp == NULL)
{
M4ERROR ((warning_status, 0, "\
INTERNAL ERROR: Built-in not found in builtin table!"));
abort ();
}
fprintf (file, "F%d,%d\n",
(int) strlen (SYMBOL_NAME (sym)),
(int) strlen (bp->name));
fputs (SYMBOL_NAME (sym), file);
fputs (bp->name, file);
fputc ('\n', file);
break;
default:
M4ERROR ((warning_status, 0, "\
INTERNAL ERROR: Bad token data type in freeze_one_symbol ()"));
abort ();
break;
}
}
symtab[h] = reverse_symbol_list (symtab[h]);
}
freeze_diversions (file);
fputs ("# End of frozen state file\n", file);
fclose (file);
}
static void
issue_expect_message (int expected)
{
if (expected == '\n')
M4ERROR ((EXIT_FAILURE, 0, "Expecting line feed in frozen file"));
else
M4ERROR ((EXIT_FAILURE, 0, "Expecting character `%c' in frozen file",
expected));
}
void
reload_frozen_state (const char *name)
{
FILE *file;
int character;
int operation;
char *string[2];
int allocated[2];
int number[2];
const builtin *bp;
#define GET_CHARACTER \
(character = getc (file))
#define GET_NUMBER(Number) \
do \
{ \
(Number) = 0; \
while (isdigit (character)) \
{ \
(Number) = 10 * (Number) + character - '0'; \
GET_CHARACTER; \
} \
} \
while (0)
#define VALIDATE(Expected) \
do \
{ \
if (character != (Expected)) \
issue_expect_message ((Expected)); \
} \
while (0)
file = path_search (name);
if (file == NULL)
M4ERROR ((EXIT_FAILURE, errno, "Cannot open %s", name));
allocated[0] = 100;
string[0] = xmalloc ((size_t) allocated[0]);
allocated[1] = 100;
string[1] = xmalloc ((size_t) allocated[1]);
while (GET_CHARACTER, character != EOF)
switch (character)
{
default:
M4ERROR ((EXIT_FAILURE, 0, "Ill-formated frozen file"));
case '\n':
break;
case '#':
while (character != EOF && character != '\n')
GET_CHARACTER;
VALIDATE ('\n');
break;
case 'C':
case 'D':
case 'F':
case 'T':
case 'Q':
operation = character;
GET_CHARACTER;
if (operation == 'D' && character == '-')
{
GET_CHARACTER;
GET_NUMBER (number[0]);
number[0] = -number[0];
}
else
GET_NUMBER (number[0]);
VALIDATE (',');
GET_CHARACTER;
GET_NUMBER (number[1]);
VALIDATE ('\n');
if (operation != 'D')
{
if (number[0] + 1 > allocated[0])
{
free (string[0]);
allocated[0] = number[0] + 1;
string[0] = xmalloc ((size_t) allocated[0]);
}
if (number[0] > 0)
if (!fread (string[0], (size_t) number[0], 1, file))
M4ERROR ((EXIT_FAILURE, 0, "Premature end of frozen file"));
string[0][number[0]] = '\0';
}
if (number[1] + 1 > allocated[1])
{
free (string[1]);
allocated[1] = number[1] + 1;
string[1] = xmalloc ((size_t) allocated[1]);
}
if (number[1] > 0)
if (!fread (string[1], (size_t) number[1], 1, file))
M4ERROR ((EXIT_FAILURE, 0, "Premature end of frozen file"));
string[1][number[1]] = '\0';
GET_CHARACTER;
VALIDATE ('\n');
switch (operation)
{
case 'C':
set_comment (string[0], string[1]);
break;
case 'D':
make_diversion (number[0]);
if (number[1] > 0)
shipout_text (NULL, string[1], number[1]);
break;
case 'F':
bp = find_builtin_by_name (string[1]);
if (bp)
define_builtin (string[0], bp, SYMBOL_PUSHDEF, 0);
else
M4ERROR ((warning_status, 0, "\
`%s' from frozen file not found in builtin table!",
string[0]));
break;
case 'T':
define_user_macro (string[0], string[1], SYMBOL_PUSHDEF);
break;
case 'Q':
set_quotes (string[0], string[1]);
break;
default:
break;
}
break;
case 'V':
GET_CHARACTER;
VALIDATE ('1');
GET_CHARACTER;
VALIDATE ('\n');
break;
}
free (string[0]);
free (string[1]);
fclose (file);
#undef GET_CHARACTER
#undef GET_NUMBER
#undef VALIDATE
}