1 /* GNU m4 -- A simple macro processor
2 Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994, 2004, 2005, 2006,
3 2007, 2008 Free Software Foundation, Inc.
5 This file is part of GNU M4.
7 GNU M4 is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 GNU M4 is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 /* This module handles frozen files. */
27 #include "binary-io.h"
28 #include "close-stream.h"
33 static void produce_mem_dump (FILE *, const char *, size_t);
34 static void produce_resyntax_dump (m4
*, FILE *);
35 static void produce_syntax_dump (FILE *, m4_syntax_table
*, char);
36 static void produce_module_dump (FILE *, m4_module
*);
37 static void produce_symbol_dump (m4
*, FILE *, m4_symbol_table
*);
38 static void *dump_symbol_CB (m4_symbol_table
*, const char *,
39 size_t, m4_symbol
*, void *);
40 static void issue_expect_message (m4
*, int);
41 static int decode_char (m4
*, FILE *, bool *);
44 /* Dump an ASCII-encoded representation of LEN bytes at MEM to FILE.
45 MEM may contain embedded NUL characters. */
47 produce_mem_dump (FILE *file
, const char *mem
, size_t len
)
49 char *quoted
= quotearg_style_mem (escape_quoting_style
, mem
, len
);
50 /* Any errors will be detected by ferror later. */
51 fwrite (quoted
, strlen (quoted
), 1, file
);
55 /* Produce the 'R14\nPOSIX_EXTENDED\n' frozen file dump of the current
56 default regular expression syntax. Note that it would be a little
57 faster to use the encoded syntax in this format as used by re_compile(),
58 but the representation of RE_SYNTAX_POSIX_EXTENDED may change in
59 future (or alternative) implementations of re_compile, so we use an
60 unencoded representation here. */
63 produce_resyntax_dump (m4
*context
, FILE *file
)
65 int code
= m4_get_regexp_syntax_opt (context
);
67 /* Don't dump default syntax code (`0' for GNU_EMACS). */
70 const char *resyntax
= m4_regexp_syntax_decode (code
);
73 m4_error (context
, EXIT_FAILURE
, 0, NULL
,
74 _("invalid regexp syntax code `%d'"), code
);
76 /* No need to use produce_mem_dump, since we know all resyntax
77 names are already ASCII-encoded. */
78 xfprintf (file
, "R%zu\n%s\n", strlen (resyntax
), resyntax
);
83 produce_syntax_dump (FILE *file
, m4_syntax_table
*syntax
, char ch
)
85 char buf
[UCHAR_MAX
+ 1];
86 int code
= m4_syntax_code (ch
);
90 for (i
= 0; i
< UCHAR_MAX
+ 1; ++i
)
91 if (m4_has_syntax (syntax
, i
, code
) && code
!= syntax
->orig
[i
])
94 /* If code falls in M4_SYNTAX_MASKS, then we must treat it
95 specially, since it will not be found in syntax->orig. */
97 && ((code
== M4_SYNTAX_RQUOTE
&& *buf
== *DEF_RQUOTE
)
98 || (code
== M4_SYNTAX_ECOMM
&& *buf
== *DEF_ECOMM
)))
101 if (count
|| (code
& M4_SYNTAX_MASKS
))
103 xfprintf (file
, "S%c%d\n", ch
, count
);
104 produce_mem_dump (file
, buf
, count
);
109 /* Store the debug mode in textual format. */
111 produce_debugmode_state (FILE *file
, int flags
)
113 /* This code tracks the number of bits in M4_DEBUG_TRACE_VERBOSE. */
116 verify ((1 << (sizeof str
- 1)) - 1 == M4_DEBUG_TRACE_VERBOSE
);
117 if (flags
& M4_DEBUG_TRACE_ARGS
)
119 if (flags
& M4_DEBUG_TRACE_EXPANSION
)
121 if (flags
& M4_DEBUG_TRACE_QUOTE
)
123 if (flags
& M4_DEBUG_TRACE_ALL
)
125 if (flags
& M4_DEBUG_TRACE_LINE
)
127 if (flags
& M4_DEBUG_TRACE_FILE
)
129 if (flags
& M4_DEBUG_TRACE_PATH
)
131 if (flags
& M4_DEBUG_TRACE_CALL
)
133 if (flags
& M4_DEBUG_TRACE_INPUT
)
135 if (flags
& M4_DEBUG_TRACE_CALLID
)
137 if (flags
& M4_DEBUG_TRACE_MODULE
)
139 if (flags
& M4_DEBUG_TRACE_STACK
)
141 if (flags
& M4_DEBUG_TRACE_DEREF
)
145 xfprintf (file
, "d%d\n%s\n", offset
, str
);
148 /* The modules must be dumped in the order in which they will be
149 reloaded from the frozen file. libltdl stores handles in a push
150 down stack, so we need to dump them in the reverse order to that. */
152 produce_module_dump (FILE *file
, m4_module
*module
)
154 const char *name
= m4_get_module_name (module
);
155 size_t len
= strlen (name
);
157 module
= m4__module_next (module
);
159 produce_module_dump (file
, module
);
161 xfprintf (file
, "M%zu\n", len
);
162 produce_mem_dump (file
, name
, len
);
166 /* Process all entries in one bucket, from the last to the first.
167 This order ensures that, at reload time, pushdef's will be
168 executed with the oldest definitions first. */
170 produce_symbol_dump (m4
*context
, FILE *file
, m4_symbol_table
*symtab
)
172 if (m4_symtab_apply (symtab
, true, dump_symbol_CB
, file
))
176 /* Given a stack of symbol values starting with VALUE, destructively
177 reverse the stack and return the pointer to what was previously the
178 last value in the stack. VALUE may be NULL. The symbol table that
179 owns the value stack should not be modified or consulted until this
180 is called again to undo the effect. */
181 static m4_symbol_value
*
182 reverse_symbol_value_stack (m4_symbol_value
*value
)
184 m4_symbol_value
*result
= NULL
;
185 m4_symbol_value
*next
;
188 next
= VALUE_NEXT (value
);
189 VALUE_NEXT (value
) = result
;
196 /* Dump the stack of values for SYMBOL, with name SYMBOL_NAME and
197 length LEN, located in SYMTAB. USERDATA is interpreted as the
200 dump_symbol_CB (m4_symbol_table
*symtab
, const char *symbol_name
, size_t len
,
201 m4_symbol
*symbol
, void *userdata
)
203 FILE *file
= (FILE *) userdata
;
204 m4_symbol_value
*value
;
205 m4_symbol_value
*last
;
207 last
= value
= reverse_symbol_value_stack (m4_get_symbol_value (symbol
));
210 m4_module
*module
= VALUE_MODULE (value
);
211 const char *module_name
= module
? m4_get_module_name (module
) : NULL
;
212 size_t module_len
= module_name
? strlen (module_name
) : 0;
214 if (m4_is_symbol_value_text (value
))
216 const char *text
= m4_get_symbol_value_text (value
);
217 size_t text_len
= m4_get_symbol_value_len (value
);
218 xfprintf (file
, "T%zu,%zu", len
, text_len
);
220 xfprintf (file
, ",%zu", module_len
);
223 produce_mem_dump (file
, symbol_name
, len
);
225 produce_mem_dump (file
, text
, text_len
);
229 produce_mem_dump (file
, module_name
, module_len
);
233 else if (m4_is_symbol_value_func (value
))
235 const m4_builtin
*bp
= m4_get_symbol_value_builtin (value
);
238 assert (!"INTERNAL ERROR: builtin not found in builtin table!");
239 bp_len
= strlen (bp
->name
);
241 xfprintf (file
, "F%zu,%zu", len
, bp_len
);
243 xfprintf (file
, ",%zu", module_len
);
246 produce_mem_dump (file
, symbol_name
, len
);
248 produce_mem_dump (file
, bp
->name
, bp_len
);
252 produce_mem_dump (file
, module_name
, module_len
);
256 else if (m4_is_symbol_value_placeholder (value
))
257 ; /* Nothing to do for a builtin we couldn't reload earlier. */
259 assert (!"dump_symbol_CB");
260 value
= VALUE_NEXT (value
);
262 reverse_symbol_value_stack (last
);
263 if (m4_get_symbol_traced (symbol
))
264 xfprintf (file
, "t%zu\n%s\n", len
, symbol_name
);
268 /* Produce a frozen state to the given file NAME. */
270 produce_frozen_state (m4
*context
, const char *name
)
272 FILE *file
= fopen (name
, O_BINARY
? "wb" : "w");
274 const m4_string_pair
*pair
;
278 m4_error (context
, 0, errno
, NULL
, _("cannot open `%s'"), name
);
282 /* Write a recognizable header. */
284 xfprintf (file
, "# This is a frozen state file generated by GNU %s %s\n",
286 fputs ("V2\n", file
);
288 /* Dump quote delimiters. */
289 pair
= m4_get_syntax_quotes (M4SYNTAX
);
290 if (strcmp (pair
->str1
, DEF_LQUOTE
) || strcmp (pair
->str2
, DEF_RQUOTE
))
292 xfprintf (file
, "Q%zu,%zu\n", pair
->len1
, pair
->len2
);
293 produce_mem_dump (file
, pair
->str1
, pair
->len1
);
295 produce_mem_dump (file
, pair
->str2
, pair
->len2
);
299 /* Dump comment delimiters. */
300 pair
= m4_get_syntax_comments (M4SYNTAX
);
301 if (strcmp (pair
->str1
, DEF_BCOMM
) || strcmp (pair
->str2
, DEF_ECOMM
))
303 xfprintf (file
, "C%zu,%zu\n", pair
->len1
, pair
->len2
);
304 produce_mem_dump (file
, pair
->str1
, pair
->len1
);
306 produce_mem_dump (file
, pair
->str2
, pair
->len2
);
310 /* Dump regular expression syntax. */
311 produce_resyntax_dump (context
, file
);
313 /* Dump syntax table. */
314 str
= "I@WLBOD${}SA(),RE";
316 produce_syntax_dump (file
, M4SYNTAX
, *str
++);
318 /* Dump debugmode state. */
319 produce_debugmode_state (file
, m4_get_debug_level_opt (context
));
321 /* Dump all loaded modules. */
322 produce_module_dump (file
, m4__module_next (NULL
));
324 /* Dump all symbols. */
325 produce_symbol_dump (context
, file
, M4SYMTAB
);
327 /* Let diversions be issued from output.c module, its cleaner to have this
328 piece of code there. */
329 m4_freeze_diversions (context
, file
);
333 fputs ("# End of frozen state file\n", file
);
334 if (close_stream (file
) != 0)
335 m4_error (context
, EXIT_FAILURE
, errno
, NULL
,
336 _("unable to create frozen state"));
339 /* Issue a message saying that some character is an EXPECTED character. */
341 issue_expect_message (m4
*context
, int expected
)
343 if (expected
== '\n')
344 m4_error (context
, EXIT_FAILURE
, 0, NULL
,
345 _("expecting line feed in frozen file"));
347 m4_error (context
, EXIT_FAILURE
, 0, NULL
,
348 _("expecting character `%c' in frozen file"), expected
);
352 /* Reload frozen state. */
354 /* Read the next character from the IN stream. Various escape
355 sequences are converted, and returned. EOF is returned if the end
356 of file is reached whilst reading the character, or on an
357 unrecognized escape sequence. */
360 decode_char (m4
*context
, FILE *in
, bool *advance_line
)
368 m4_set_current_line (context
, m4_get_current_line (context
) + 1);
369 *advance_line
= false;
377 case 'a': return '\a';
378 case 'b': return '\b';
379 case 'f': return '\f';
380 case 'n': return '\n';
381 case 'r': return '\r';
382 case 't': return '\t';
383 case 'v': return '\v';
384 case '\\': return '\\';
388 m4_set_current_line (context
, m4_get_current_line (context
) + 1);
393 if (next
>= '0' && next
<= '9')
394 ch
= (next
- '0') * 16;
395 else if (next
>= 'a' && next
<= 'f')
396 ch
= (next
- 'a' + 10) * 16;
397 else if (next
>= 'A' && next
<= 'F')
398 ch
= (next
- 'A' + 10) * 16;
402 if (next
>= '0' && next
<= '9')
404 else if (next
>= 'a' && next
<= 'f')
405 ch
+= next
- 'a' + 10;
406 else if (next
>= 'A' && next
<= 'F')
407 ch
+= next
- 'A' + 10;
411 case '0': case '1': case '2': case '3':
415 case '4': case '5': case '6': case '7':
416 if (ch
>= '0' && ch
<= '7')
418 value
= value
* 8 + ch
- '0';
426 if (ch
>= '0' && ch
<= '7')
427 value
= value
* 8 + ch
- '0';
438 *advance_line
= true;
443 /* Reload state from the given file NAME. We are seeking speed,
447 reload_frozen_state (m4
*context
, const char *name
)
457 bool advance_line
= true;
459 #define GET_CHARACTER \
464 m4_set_current_line (context, \
465 m4_get_current_line (context) + 1); \
466 advance_line = false; \
468 character = getc (file); \
469 if (character == '\n') \
470 advance_line = true; \
474 #define GET_NUMBER(Number, AllowNeg) \
477 unsigned int n = 0; \
478 while (isdigit (character) && n <= INT_MAX / 10) \
480 n = 10 * n + character - '0'; \
483 if (((AllowNeg) ? INT_MIN: INT_MAX) < n \
484 || isdigit (character)) \
485 m4_error (context, EXIT_FAILURE, 0, NULL, \
486 _("integer overflow in frozen file")); \
491 #define GET_STRING(File, Buf, BufSize, StrLen, UseChar) \
494 size_t len = (StrLen); \
499 ungetc (character, File); \
502 assert (character == '\n'); \
503 advance_line = false; \
506 CHECK_ALLOCATION ((Buf), (BufSize), len); \
511 ? decode_char (context, File, &advance_line) \
514 m4_error (context, EXIT_FAILURE, 0, NULL, \
515 _("premature end of frozen file")); \
520 while (version > 1 && character == '\\') \
529 #define VALIDATE(Expected) \
532 if (character != (Expected)) \
533 issue_expect_message (context, (Expected)); \
537 #define CHECK_ALLOCATION(Where, Allocated, Needed) \
540 if ((Needed) + 1 > (Allocated)) \
543 (Allocated) = (Needed) + 1; \
544 (Where) = xcharalloc (Allocated); \
549 /* Skip comments (`#' at beginning of line) and blank lines, setting
550 character to the next directive or to EOF. */
552 #define GET_DIRECTIVE \
556 if (character == '#') \
558 while (character != EOF && character != '\n') \
563 while (character == '\n')
565 file
= m4_path_search (context
, name
, (char **)NULL
);
567 m4_error (context
, EXIT_FAILURE
, errno
, NULL
, _("cannot open `%s'"), name
);
568 m4_set_current_file (context
, name
);
571 string
[0] = xcharalloc (allocated
[0]);
573 string
[1] = xcharalloc (allocated
[1]);
575 string
[2] = xcharalloc (allocated
[2]);
577 /* Validate format version. Accept both `1' (m4 1.3 and 1.4.x) and
582 GET_NUMBER (version
, false);
588 m4__module_open (context
, "m4", NULL
);
589 if (m4_get_posixly_correct_opt (context
))
590 m4__module_open (context
, "traditional", NULL
);
592 m4__module_open (context
, "gnu", NULL
);
593 /* Disable { and } categories, since ${11} was not supported in
595 m4_set_syntax (M4SYNTAX
, 'O', '+', "{}", 2);
599 m4_error (context
, EXIT_MISMATCH
, 0, NULL
,
600 _("frozen file version %d greater than max supported of 2"),
603 m4_error (context
, EXIT_FAILURE
, 0, NULL
,
604 _("ill-formed frozen file, version directive expected"));
609 while (character
!= EOF
)
614 m4_error (context
, EXIT_FAILURE
, 0, NULL
,
615 _("ill-formed frozen file, unknown directive %c"),
619 /* Set debugmode flags. */
622 /* 'd' operator is not supported in format version 1. */
623 m4_error (context
, EXIT_FAILURE
, 0, NULL
, _("\
624 ill-formed frozen file, version 2 directive `%c' encountered"), 'd');
628 GET_NUMBER (number
[0], false);
630 GET_STRING (file
, string
[0], allocated
[0], number
[0], false);
633 if (m4_debug_decode (context
, string
[0]) < 0)
634 m4_error (context
, EXIT_FAILURE
, 0, NULL
,
635 _("unknown debug mode `%s'"),
636 quotearg_style_mem (locale_quoting_style
, string
[0],
643 /* Get string lengths. */
645 GET_NUMBER (number
[0], false);
648 GET_NUMBER (number
[1], false);
650 if (character
== ',')
654 /* 'F' operator accepts an optional third argument for
655 format versions 2 or later. */
657 GET_NUMBER (number
[2], false);
660 /* 3 argument 'F' operations are invalid for format
662 m4_error (context
, EXIT_FAILURE
, 0, NULL
, _("\
663 ill-formed frozen file, version 2 directive `%c' encountered"), 'F');
673 /* Get string contents. */
675 GET_STRING (file
, string
[0], allocated
[0], number
[0], false);
681 GET_STRING (file
, string
[1], allocated
[1], number
[1], true);
682 if (version
> 1 && number
[2])
687 GET_STRING (file
, string
[2], allocated
[2], number
[2], true);
690 /* Enter a macro having a builtin function as a definition. */
692 m4_module
*module
= NULL
;
693 m4_symbol_value
*token
;
696 module
= m4__module_find (string
[2]);
697 token
= m4_builtin_find_by_name (module
, string
[1]);
701 token
= (m4_symbol_value
*) xzalloc (sizeof *token
);
702 m4_set_symbol_value_placeholder (token
, xstrdup (string
[1]));
703 VALUE_MODULE (token
) = module
;
704 VALUE_MIN_ARGS (token
) = 0;
705 VALUE_MAX_ARGS (token
) = -1;
707 m4_symbol_pushdef (M4SYMTAB
, string
[0], number
[0], token
);
713 /* Load a module, but *without* perturbing the symbol table.
714 Note that any expansion from loading the module which would
715 have been seen when loading it originally is discarded
716 when loading it from a frozen file. */
720 /* 'M' operator is not supported in format version 1. */
721 m4_error (context
, EXIT_FAILURE
, 0, NULL
, _("\
722 ill-formed frozen file, version 2 directive `%c' encountered"), 'M');
726 GET_NUMBER (number
[0], false);
728 GET_STRING (file
, string
[0], allocated
[0], number
[0], false);
731 m4__module_open (context
, string
[0], NULL
);
739 /* 'R' operator is not supported in format version 1. */
740 m4_error (context
, EXIT_FAILURE
, 0, NULL
, _("\
741 ill-formed frozen file, version 2 directive `%c' encountered"), 'R');
745 GET_NUMBER (number
[0], false);
747 GET_STRING (file
, string
[0], allocated
[0], number
[0], false);
750 m4_set_regexp_syntax_opt (context
,
751 m4_regexp_syntax_encode (string
[0]));
752 if (m4_get_regexp_syntax_opt (context
) < 0)
754 m4_error (context
, EXIT_FAILURE
, 0, NULL
,
755 _("unknown regexp syntax code `%s'"),
756 quotearg_style_mem (locale_quoting_style
, string
[0],
766 /* 'S' operator is not supported in format version 1. */
767 m4_error (context
, EXIT_FAILURE
, 0, NULL
, _("\
768 ill-formed frozen file, version 2 directive `%c' encountered"), 'S');
774 GET_NUMBER (number
[0], false);
776 GET_STRING (file
, string
[0], allocated
[0], number
[0], false);
778 /* Syntax under M4_SYNTAX_MASKS is handled specially; all
779 other characters are additive. */
780 if ((m4_set_syntax (M4SYNTAX
, syntax
,
781 (m4_syntax_code (syntax
) & M4_SYNTAX_MASKS
782 ? '=' : '+'), string
[0], number
[0]) < 0)
785 m4_error (context
, 0, 0, NULL
,
786 _("undefined syntax code %c"), syntax
);
791 /* Trace a macro name. */
794 /* 't' operator is not supported in format version 1. */
795 m4_error (context
, EXIT_FAILURE
, 0, NULL
, _("\
796 ill-formed frozen file, version 2 directive `%c' encountered"), 't');
800 GET_NUMBER (number
[0], false);
802 GET_STRING (file
, string
[0], allocated
[0], number
[0], false);
805 m4_set_symbol_name_traced (M4SYMTAB
, string
[0], number
[0], true);
812 operation
= character
;
815 /* Get string lengths. */
817 if (operation
== 'D' && character
== '-')
819 /* Accept a negative diversion number. */
821 GET_NUMBER (number
[0], true);
822 number
[0] = -number
[0];
825 GET_NUMBER (number
[0], false);
828 GET_NUMBER (number
[1], false);
831 /* Get string contents. */
832 if (operation
!= 'D')
834 GET_STRING (file
, string
[0], allocated
[0], number
[0], false);
843 GET_STRING (file
, string
[1], allocated
[1], number
[1], true);
846 /* Act according to operation letter. */
852 /* Change comment strings. */
854 m4_set_comment (M4SYNTAX
, string
[0], number
[0], string
[1],
860 /* Select a diversion and add a string to it. */
862 m4_make_diversion (context
, number
[0]);
864 m4_output_text (context
, string
[1], number
[1]);
869 /* Change quote strings. */
871 m4_set_quotes (M4SYNTAX
, string
[0], number
[0], string
[1],
886 /* Get string lengths. */
888 GET_NUMBER (number
[0], false);
891 GET_NUMBER (number
[1], false);
893 if (character
== ',')
897 /* 'T' operator accepts an optional third argument for
898 format versions 2 or later. */
900 GET_NUMBER (number
[2], false);
904 /* 3 argument 'T' operations are invalid for format
906 m4_error (context
, EXIT_FAILURE
, 0, NULL
, _("\
907 ill-formed frozen file, version 2 directive `%c' encountered"), 'T');
915 /* Get string contents. */
916 GET_STRING (file
, string
[0], allocated
[0], number
[0], false);
922 GET_STRING (file
, string
[1], allocated
[1], number
[1], true);
923 if (version
> 1 && number
[2])
928 GET_STRING (file
, string
[2], allocated
[2], number
[2], true);
931 /* Enter a macro having an expansion text as a definition. */
933 m4_symbol_value
*token
;
934 m4_module
*module
= NULL
;
936 token
= (m4_symbol_value
*) xzalloc (sizeof *token
);
938 module
= m4__module_find (string
[2]);
940 m4_set_symbol_value_text (token
, xmemdup0 (string
[1], number
[1]),
942 VALUE_MODULE (token
) = module
;
943 VALUE_MAX_ARGS (token
) = -1;
945 m4_symbol_pushdef (M4SYMTAB
, string
[0], number
[0], token
);
956 if (close_stream (file
) != 0)
957 m4_error (context
, EXIT_FAILURE
, errno
, NULL
,
958 _("unable to read frozen state"));
959 m4_set_current_file (context
, NULL
);
960 m4_set_current_line (context
, 0);
966 #undef CHECK_ALLOCATION