/* mp4h -- A macro processor for HTML documents Copyright 2000-2002, Denis Barbier All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is a work based on GNU m4 version 1.4n. Below is the original copyright. */ /* GNU m4 -- A simple macro processor Copyright (C) 1989, 90, 91, 92, 93, 94 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef MP4H_H #define MP4H_H #ifdef HAVE_CONFIG_H # include #endif #include # define voidstar void * #include #include #include "obstack.h" /* An ANSI string.h and pre-ANSI memory.h might conflict. */ #if defined (HAVE_STRING_H) || defined (STDC_HEADERS) # include # if !defined (STDC_HEADERS) && defined (HAVE_MEMORY_H) # include # endif /* This is for obstack code -- should live in obstack.h. */ # ifndef bcopy # define bcopy(S, D, N) memcpy ((D), (S), (N)) # endif #else # include # ifndef memcpy # define memcpy(D, S, N) bcopy((S), (D), (N)) # endif # ifndef strchr # define strchr(S, C) index ((S), (C)) # endif # ifndef strrchr # define strrchr(S, C) rindex ((S), (C)) # endif # ifndef bcopy void bcopy (); # endif #endif #ifdef STDC_HEADERS # include #else /* not STDC_HEADERS */ voidstar malloc (); voidstar realloc (); char *getenv (); double atof (); long strtol (); #endif /* STDC_HEADERS */ /* Some systems do not define EXIT_*, even with STDC_HEADERS. */ #ifndef EXIT_SUCCESS # define EXIT_SUCCESS 0 #endif #ifndef EXIT_FAILURE # define EXIT_FAILURE 1 #endif #include #ifndef errno extern int errno; #endif #ifdef HAVE_UNISTD_H # include #endif /* If FALSE is defined, we presume TRUE is defined too. In this case, merely typedef boolean as being int. Or else, define these all. */ #ifndef FALSE # define FALSE 0 # define TRUE 1 #endif typedef int boolean; char *mktemp (); #ifndef __P # ifdef PROTOTYPES # define __P(Args) Args # else # define __P(Args) () # endif #endif #if HAVE_LOCALE_H # include #else # define setlocale(Category, Locale) #endif #ifdef ENABLE_NLS #include #define _(Text) gettext ((Text)) #else #define _(Text) (Text) #endif /* Last character of a string. */ #define LAST_CHAR(Text) *(Text + strlen (Text) - 1) /* Various declarations. */ struct _string { char *string; /* characters of the string */ size_t length; /* length of the string */ }; typedef struct _string STRING; /* Those must come first. */ typedef void builtin_func (); /* Various different token types. */ enum _token_type { TOKEN_EOF, /* end of file */ TOKEN_NONE, /* discardable token */ TOKEN_STRING, /* a string */ TOKEN_QUOTED, /* a quoted string */ TOKEN_QUOTE, /* begin delimiter of a quoted string to expand */ TOKEN_BGROUP, /* begin group */ TOKEN_EGROUP, /* end group */ TOKEN_SPACE, /* whitespace */ TOKEN_WORD, /* an identifier */ TOKEN_ENTITY, /* an entity */ TOKEN_SIMPLE, /* a single character */ TOKEN_MACDEF /* a macros definition (see "defn") */ }; typedef enum _token_type token_type; /* The data for a token, a macro argument, and a macro definition. */ enum _token_data_type { TOKEN_VOID, TOKEN_TEXT, TOKEN_FUNC }; typedef enum _token_data_type token_data_type; struct _token_data { token_data_type type; union { struct { char *text; } u_t; struct { builtin_func *func; boolean traced; } u_f; } u; }; typedef struct _token_data token_data; /* Memory allocation. */ voidstar xmalloc __P ((size_t)); voidstar xcalloc __P ((size_t, size_t)); voidstar xrealloc __P ((voidstar , size_t)); void xfree __P ((voidstar)); char *xstrdup __P ((const char *)); #define obstack_chunk_alloc xmalloc #define obstack_chunk_free xfree /* Other library routines. */ void error __P ((int, int, const char *, ...)); /* File: mp4h.c --- global definitions. */ /* Option flags. */ extern int interactive; /* -e */ extern int sync_output; /* -s */ extern int debug_level; /* -d */ extern int hash_table_size; /* -H */ extern int max_debug_argument_length; /* -l */ extern int suppress_warnings; /* -Q */ extern int warning_status; /* -E */ extern int nesting_limit; /* -L */ extern int frozen_dump; /* -F */ /* Error handling. */ #define MP4HERROR(Arglist) (error Arglist) /* File: debug.c --- debugging and tracing function. */ extern FILE *debug; /* The value of debug_level is a bitmask of the following. */ /* a: show arglist in trace output */ #define DEBUG_TRACE_ARGS 1 /* e: show expansion in trace output */ #define DEBUG_TRACE_EXPANSION 2 /* t: trace all macros -- overrides trace{on,off} */ #define DEBUG_TRACE_ALL 8 /* l: add line numbers to trace output */ #define DEBUG_TRACE_LINE 16 /* f: add file name to trace output */ #define DEBUG_TRACE_FILE 32 /* p: trace path search of include files */ #define DEBUG_TRACE_PATH 64 /* c: show macro call before args collection */ #define DEBUG_TRACE_CALL 128 /* i: trace changes of input files */ #define DEBUG_TRACE_INPUT 256 /* x: add call id to trace output */ #define DEBUG_TRACE_CALLID 512 /* m: trace module loading */ #define DEBUG_TRACE_MODULES 1024 /* V: very verbose -- print everything */ #define DEBUG_TRACE_VERBOSE 1023 /* default flags -- equiv: ae */ #define DEBUG_TRACE_DEFAULT 3 #define DEBUG_PRINT1(Fmt, Arg1) \ do \ { \ if (debug != NULL) \ fprintf (debug, Fmt, Arg1); \ } \ while (0) #define DEBUG_PRINT3(Fmt, Arg1, Arg2, Arg3) \ do \ { \ if (debug != NULL) \ fprintf (debug, Fmt, Arg1, Arg2, Arg3); \ } \ while (0) #define DEBUG_MESSAGE(Fmt) \ do \ { \ if (debug != NULL) \ { \ debug_message_prefix (); \ fprintf (debug, Fmt); \ putc ('\n', debug); \ } \ } \ while (0) #define DEBUG_MESSAGE1(Fmt, Arg1) \ do \ { \ if (debug != NULL) \ { \ debug_message_prefix (); \ fprintf (debug, Fmt, Arg1); \ putc ('\n', debug); \ } \ } \ while (0) #define DEBUG_MESSAGE2(Fmt, Arg1, Arg2) \ do \ { \ if (debug != NULL) \ { \ debug_message_prefix (); \ fprintf (debug, Fmt, Arg1, Arg2); \ putc ('\n', debug); \ } \ } \ while (0) void debug_init __P ((void)); void debug_deallocate __P ((void)); int debug_decode __P ((const char *)); void debug_flush_files __P ((void)); boolean debug_set_output __P ((const char *)); void debug_message_prefix __P ((void)); void trace_prepre __P ((const char *, int)); void trace_pre __P ((const char *, int, int, token_data **)); void trace_post __P ((const char *, int, int, token_data **, const char *)); /* File: input.c --- lexical definitions. */ #define TOKEN_DATA_TYPE(Td) ((Td)->type) #define TOKEN_DATA_TEXT(Td) ((Td)->u.u_t.text) #define TOKEN_DATA_FUNC(Td) ((Td)->u.u_f.func) #define TOKEN_DATA_FUNC_TRACED(Td) ((Td)->u.u_f.traced) /* The status of processing. */ #define READ_NORMAL (1 << 0) /* normal expansion of macros */ #define READ_ATTRIBUTE (1 << 1) /* when reading macro arguments */ #define READ_ATTR_QUOT (1 << 2) /* like READ_ATTRIBUTE, but quotes are preserved */ #define READ_ATTR_VERB (1 << 3) /* inside macros with attributes=verbatim */ #define READ_ATTR_ASIS (1 << 4) /* attributes are read without any modification, main difference with READ_ATTR_VERB is that quotes and backslashes are not removed and are part of this attribute */ #define READ_BODY (1 << 5) /* when reading body function */ /* Flags which determine how expansion is done */ #define EXP_NO_HTMLTAG (1 << 0) /* do not parse unknown tags */ #define EXP_DFT_SIMPLE (1 << 1) /* HTML tags are simple */ #define EXP_STAR_COMPLEX (1 << 2) /* HTML tags whose last char is an asterisk are by default simple tags, they become complex when this flag is set. */ #define EXP_UNM_BREAK (1 << 3) /* An unmatched end tag closes all previous unmatched begin tags. */ #define EXP_STD_BSLASH (1 << 4) /* By default, only 'n', 'r', 't', '"' and '\\' are escaped. When this flag is set, backslashes are interpreted as in printf. */ #define EXP_REMOVE_TRAILING_SLASH \ (1 << 5) /* Remove trailing slash in simple tag attributes */ #define EXP_LEAVE_TRAILING_STAR \ (1 << 6) /* Do not remove trailing slash in simple tag attributes */ #define EXP_LEAVE_LEADING_STAR \ (1 << 7) /* Do not remove trailing slash in simple tag attributes */ #define EXP_NOSPACE_BSLASH \ (1 << 8) /* Do not add space before trailing slash in simple tag attributes */ #define EXP_NOWARN_NEST (1 << 10) /* Suppress warning about bad nested tags */ #define EXP_NOWARN_SLASH (1 << 11) /* Suppress warning about missing trailing slash */ extern int exp_flags; typedef int read_type; void input_init __P ((void)); void input_deallocate __P ((void)); void syntax_init __P ((void)); int peek_input __P ((void)); token_type next_token __P ((token_data *, read_type, boolean)); void skip_line __P ((void)); void skip_buffer __P ((void)); void input_close __P ((void)); /* push back input */ void push_file __P ((FILE *, const char *)); void push_macro __P ((builtin_func *, boolean)); void push_single __P ((int)); struct obstack *push_string_init __P ((void)); const char *push_string_finish __P ((read_type)); void push_wrapup __P ((const char *)); boolean pop_wrapup __P ((void)); void unget_string __P ((char *)); /* read a file verbatim */ void read_file_verbatim __P ((struct obstack *)); /* current input file, and line */ extern char *current_file; extern int current_line; extern char **array_current_file; extern int *array_current_line; #define CURRENT_FILE_LINE \ (expansion_level == 0 ? current_file : \ array_current_file[expansion_level]), \ (expansion_level == 0 ? current_line : \ array_current_line[expansion_level]) /* Begin and end quote */ extern STRING lquote, rquote; /* Eof-of-line comment */ extern STRING eolcomm; /* Special characters used for grouping */ #define CHAR_LQUOTE '\1' #define CHAR_RQUOTE '\2' #define CHAR_BGROUP '\3' #define CHAR_EGROUP '\4' /* Some characters are replaced during input/output phases */ #define CHAR_QUOTE '\5' #define CHAR_SLASH '\6' /* Default eof-of-line comment */ #define DEF_EOLCOMM ";;;" /* Default quotes */ #define DEF_LQUOTE "<@[" #define DEF_RQUOTE "]@>" /* Syntax table definitions. */ /* Please read the comment at the top of input.c for details */ extern unsigned short syntax_table[256]; /* These are simple values, not bit masks. There is no overlap. */ #define SYNTAX_OTHER (0x0000) #define SYNTAX_IGNORE (0x0001) #define SYNTAX_SPACE (0x0002) #define SYNTAX_GROUP (0x0009) /* These are values to be assigned to syntax table entries, but they are used as bit masks with IS_ALNUM.*/ #define SYNTAX_ALPHA (0x0010) #define SYNTAX_NUM (0x0020) #define SYNTAX_ALNUM (SYNTAX_ALPHA|SYNTAX_NUM) /* These bits define the syntax code of a character */ #define SYNTAX_VALUE (0x00FF) #define SYNTAX_MASKS (0xFF00) #define IS_OTHER(ch) ((syntax_table[(int)(ch)]&SYNTAX_VALUE) == SYNTAX_OTHER) #define IS_IGNORE(ch) ((syntax_table[(int)(ch)]) == SYNTAX_IGNORE) #define IS_SPACE(ch) ((syntax_table[(int)(ch)]&SYNTAX_VALUE) == SYNTAX_SPACE) #define IS_ALPHA(ch) ((syntax_table[(int)(ch)]&SYNTAX_VALUE) == SYNTAX_ALPHA) #define IS_NUM(ch) ((syntax_table[(int)(ch)]&SYNTAX_VALUE) == SYNTAX_NUM) #define IS_ALNUM(ch) ((((syntax_table[(int)(ch)]) & SYNTAX_ALNUM) != 0) \ || ch == ':' || ch == '-') #define IS_BGROUP(ch) (ch == CHAR_BGROUP) #define IS_EGROUP(ch) (ch == CHAR_EGROUP) #define IS_LQUOTE(ch) (ch == CHAR_LQUOTE) #define IS_RQUOTE(ch) (ch == CHAR_RQUOTE) #define IS_GROUP(ch) ((syntax_table[(int)(ch)]&SYNTAX_VALUE) == SYNTAX_GROUP) #define IS_SLASH(ch) (ch == CHAR_SLASH || ch == '/') #define IS_TAG(ch) (ch == '<') #define IS_CLOSE(ch) (ch == '>') #define IS_ENTITY(ch) (ch == '&') void set_syntax __P ((int, const char *)); void set_syntax_internal __P ((int, int)); void unset_syntax_attribute __P ((int, int)); /* File: output.c --- output functions. */ extern int current_diversion; extern int output_current_line; void output_init __P ((void)); void output_deallocate __P ((void)); void shipout_text __P ((struct obstack *, char *)); void make_diversion __P ((int)); void insert_diversion __P ((int)); void insert_file __P ((FILE *)); void freeze_diversions __P ((FILE *)); void remove_special_chars __P ((char *, boolean)); /* File symtab.c --- symbol table definitions. */ /* Default case sensitiveness */ #define CASELESS_DEFAULT 3 /* Operation modes for lookup_symbol (). */ enum _symbol_lookup { SYMBOL_LOOKUP, SYMBOL_INSERT, SYMBOL_DELETE }; /* Symbol table entry. */ struct _symbol { struct _symbol *next; boolean traced; boolean container; boolean expand_args; char *name; char *hook_begin; char *hook_end; token_data data; }; #define SYMBOL_NEXT(S) ((S)->next) #define SYMBOL_TRACED(S) ((S)->traced) #define SYMBOL_CONTAINER(S) ((S)->container) #define SYMBOL_EXPAND_ARGS(S) ((S)->expand_args) #define SYMBOL_NAME(S) ((S)->name) #define SYMBOL_HOOK_BEGIN(S) ((S)->hook_begin) #define SYMBOL_HOOK_END(S) ((S)->hook_end) #define SYMBOL_TYPE(S) (TOKEN_DATA_TYPE (&(S)->data)) #define SYMBOL_TEXT(S) (TOKEN_DATA_TEXT (&(S)->data)) #define SYMBOL_FUNC(S) (TOKEN_DATA_FUNC (&(S)->data)) typedef enum _symbol_lookup symbol_lookup; typedef struct _symbol symbol; typedef void hack_symbol (); #define HASHMAX 509 /* default, overridden by -Hsize */ extern symbol **sym_tab; extern symbol **var_tab; extern symbol **file_tab; extern symbol **symtab; void symtab_init __P ((void)); void symtab_deallocate __P ((void)); void caseless_init __P ((int)); symbol *lookup_symbol __P ((const char *, symbol_lookup)); symbol *lookup_entity __P ((const char *, symbol_lookup)); symbol *lookup_variable __P ((const char *, symbol_lookup)); symbol *lookup_file __P ((const char *, symbol_lookup)); void hack_all_symbols __P ((hack_symbol *, const char *)); /* File: macro.c --- macro expansion. */ void expand_input __P ((void)); void call_macro __P ((symbol *, struct obstack *, int, token_data **, read_type)); boolean get_attribute (struct obstack *obs, token_data *argp); extern int expansion_level; /* File: builtin.c --- builtins. */ enum _encoding_type { ENCODING_8BIT, /* 1-byte char */ ENCODING_UTF8 /* UTF-8 */ }; typedef enum _encoding_type encoding_type; struct _builtin { const char *name; boolean container; boolean expand_args; builtin_func *func; }; typedef struct _builtin builtin; extern boolean visible_quotes; /* Used to disable risky functions. */ extern int safety_level; /* Document encoding */ extern encoding_type document_encoding; void locale_init __P ((int, char *)); void pcre_init __P ((void)); void pcre_deallocate __P ((void)); void initialize_builtin __P ((symbol *)); void builtin_init __P ((void)); void builtin_deallocate __P ((void)); void clear_tag_attr __P ((void)); void define_builtin __P ((const char *, const builtin *, boolean)); void break_init __P ((void)); void break_deallocate __P ((void)); void define_user_macro __P ((const char *, char *, symbol_lookup, boolean, boolean, boolean)); void undivert_all __P ((void)); void expand_user_macro __P ((struct obstack *, symbol *, int, token_data **, read_type)); const builtin *find_builtin_by_addr __P ((builtin_func *)); const builtin *find_builtin_by_name __P ((const char *)); void install_builtin_table __P ((builtin *)); /* File: devel.c --- global functions for writing builtins and modules. */ boolean bad_argc __P ((token_data *, int, int, int)); boolean numeric_arg __P ((token_data *, const char *, boolean, int *)); void shipout_int __P ((struct obstack *, int)); void shipout_long __P ((struct obstack *, long)); void shipout_string __P ((struct obstack *, const char *, int)); void dump_args __P ((struct obstack *, int, token_data **, const char *)); const char * predefined_attribute __P ((const char *, int *, token_data **, boolean)); /* File: path.c --- path search for include files. */ void include_init __P ((void)); void include_env_init __P ((void)); void include_deallocate __P ((void)); void add_include_directory __P ((const char *)); FILE *path_search __P ((const char *, char **)); /* These are for other search paths */ struct search_path { struct search_path *next; /* next directory to search */ const char *dir; /* directory */ int len; }; typedef struct search_path search_path; struct search_path_info { search_path *list; /* the list of path directories */ search_path *list_end; /* the end of same */ search_path *sys; /* system path directories */ search_path *sys_end; /* the end of same */ int max_length; /* length of longest directory name */ }; /* File: eval.c --- expression evaluation. */ boolean evaluate __P ((struct obstack *obs, const char *, const int radix, int min)); #ifdef WITH_GMP boolean mp_evaluate __P ((struct obstack *obs, const char *, const int radix, int min)); #endif /* WITH_GMP */ /* File: format.c --- printf like formatting. */ void format __P ((struct obstack *, int, token_data **)); /* File: freeze.c --- frozen state files. */ void produce_frozen_state __P ((const char *)); void reload_frozen_state __P ((const char *)); /* File: module.c --- dynamic modules */ #if defined(WITH_MODULES) || defined(MP4H_MODULE) typedef void module_init_t __P ((struct obstack *)); typedef void module_finish_t __P ((void)); typedef voidstar module_func __P ((const char *)); void module_init __P ((void)); void library_load __P ((const char *, struct obstack *)); void module_load __P ((const char *, struct obstack *)); void module_unload_all __P ((void)); #endif /* Debugging the memory allocator. */ #ifdef WITH_DMALLOC # define DMALLOC_FUNC_CHECK # include #endif /* Other debug stuff. */ #ifdef DEBUG # define DEBUG_INPUT # define DEBUG_MACRO # define DEBUG_SYM # define DEBUG_INCL #endif /* Stuff for compiling builtins and loadable modules. */ #ifdef MP4H_MODULE #define MP4H_BUILTIN_ARGS struct obstack *obs, int argc, token_data **argv, \ read_type expansion #define MP4H_BUILTIN_PROTO struct obstack *, int, token_data **, read_type #define MP4H_BUILTIN_RECUR obs, argc, argv, expansion #define DECLARE(name) \ static void name __P ((MP4H_BUILTIN_PROTO)) #define ARG(i) (i