diff options
Diffstat (limited to 'm4/module.c')
-rw-r--r-- | m4/module.c | 344 |
1 files changed, 0 insertions, 344 deletions
diff --git a/m4/module.c b/m4/module.c deleted file mode 100644 index c00b8aa1..00000000 --- a/m4/module.c +++ /dev/null @@ -1,344 +0,0 @@ -/* GNU m4 -- A simple macro processor - Copyright (C) 1989-1994, 1998-1999, 2002-2008, 2010, 2013-2014, 2017 - Free Software Foundation, Inc. - - This file is part of GNU M4. - - GNU M4 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 3 of the License, or - (at your option) any later version. - - GNU M4 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, see <http://www.gnu.org/licenses/>. -*/ - -#include <config.h> - -#include <dlfcn.h> - -#include "m4private.h" -#include "xvasprintf.h" - -/* Define this to see runtime debug info. Implied by DEBUG. */ -/*#define DEBUG_MODULES */ - -/* - * This file implements dynamic modules in GNU M4. A module is a - * compiled shared object, that can be loaded into GNU M4 at run - * time. Information about creating modules is in ../modules/README. - * - * This implementation uses libltdl, which is in turn can open modules - * using either dlopen(3) (exists on GNU/Linux, OSF, Solaris, SunOS and - * others), shl_load(3) (exists on HPUX), LoadLibrary(3) (exists on - * Windows, cygwin, OS/2), load_add_on(3) (exists on BeOS), NSAddImage - * (exists on MacOS) and can also fall back to dld_link(3) from GNU - * libdld or lt_dlpreload from libtool if shared libraries are not - * available on the host machine. - * - * An M4 module will usually define an external symbol named after the - * basename of the loadable module: - * - * void - * mymod_LTX_m4_init_module (m4 *context, m4_module *module, - * m4_obstack *obs) - * - * The function is only called the first time the module is included - * and generally uses either `m4_install_builtins' or - * `m4_install_macros' (or both!) to register whatever builtins and - * macros are provided by the module. - * - * To load a module, call m4_module_load(), which searches for the - * module in directories from M4PATH. The search path is initialized - * from the environment variable M4PATH, followed by the configuration - * time default where the modules shipped with M4 itself are installed. - * `m4_module_load' returns NULL on failure, or else an opaque module - * handle for the newly mapped vm segment containing the module code. - * If the module is not already loaded, m4_module_load() the builtins - * and macros registered by `mymod_LTX_m4_init_module' are installed - * into the symbol table using `install_builtin_table' and `install_ - * macro_table' respectively. - **/ - -#define MODULE_SELF_NAME "!myself!" - -#if DLSYM_USCORE -static void * -uscore_sym (void *handle, const char *symbol) -{ - char *symname = xasprintf ("_%s", symbol); - void *address = dlsym (handle, symname); - free (symname); - return address; -} - -#define dlsym uscore_sym -#endif - -static const char * module_dlerror (void); - -static void install_builtin_table (m4*, m4_module *); -static void install_macro_table (m4*, m4_module *); - -static int compare_builtin_CB (const void *a, const void *b); - -const char * -m4_get_module_name (const m4_module *module) -{ - assert (module); - return module->name; -} - -void * -m4_module_import (m4 *context, const char *module_name, - const char *symbol_name, m4_obstack *obs) -{ - m4_module * module = m4__module_find (context, module_name); - void * symbol_address = NULL; - - /* Try to load the module if it is not yet available (errors are - diagnosed by m4_module_load). */ - /* FIXME - should this use m4__module_open instead, to avoid - polluting the symbol table when importing a function? */ - if (!module) - module = m4_module_load (context, module_name, obs); - - if (module) - { - symbol_address = dlsym (module->handle, symbol_name); - - if (!symbol_address) - m4_error (context, 0, 0, NULL, - _("cannot load symbol `%s' from module `%s'"), - symbol_name, module_name); - } - - return symbol_address; -} - -void -m4_install_builtins (m4 *context, m4_module *module, const m4_builtin *bp) -{ - assert (context); - assert (module); - assert (bp); - - const m4_builtin *tmp; - m4__builtin *builtin; - for (tmp = bp; tmp->name; tmp++) - module->builtins_len++; - module->builtins = (m4__builtin *) xnmalloc (module->builtins_len, - sizeof *module->builtins); - for (builtin = module->builtins; bp->name != NULL; bp++, builtin++) - { - /* Sanity check that builtins meet the required interface. */ - assert (bp->min_args <= bp->max_args); - assert (bp->min_args > 0 || - (bp->flags & (M4_BUILTIN_BLIND|M4_BUILTIN_SIDE_EFFECT)) == 0); - assert (bp->max_args || - (bp->flags & M4_BUILTIN_FLATTEN_ARGS) == 0); - assert ((bp->flags & ~M4_BUILTIN_FLAGS_MASK) == 0); - memcpy (&builtin->builtin, bp, sizeof *bp); - builtin->builtin.name = xstrdup (bp->name); - builtin->module = module; - } - qsort (module->builtins, module->builtins_len, - sizeof *module->builtins, compare_builtin_CB); -} - -static void -install_builtin_table (m4 *context, m4_module *module) -{ - size_t i; - - assert (context); - assert (module); - for (i = 0; i < module->builtins_len; i++) - { - m4_symbol_value *value = m4_symbol_value_create (); - const char *name = module->builtins[i].builtin.name; - - m4__set_symbol_value_builtin (value, &module->builtins[i]); - if (m4_get_prefix_builtins_opt (context)) - name = xasprintf ("m4_%s", name); - - m4_symbol_pushdef (M4SYMTAB, name, strlen (name), value); - - if (m4_get_prefix_builtins_opt (context)) - DELETE (name); - } - if (i) - m4_debug_message (context, M4_DEBUG_TRACE_MODULE, - _("module %s: builtins loaded"), - m4_get_module_name (module)); -} - -void -m4_install_macros (m4 *context, m4_module *module, const m4_macro *mp) -{ - assert (context); - assert (module); - assert (mp); - - module->macros = (m4_macro *) mp; -} - -static void -install_macro_table (m4 *context, m4_module *module) -{ - const m4_macro *mp; - - assert (context); - assert (module); - - mp = module->macros; - - if (mp) - { - for (; mp->name != NULL; mp++) - { - m4_symbol_value *value = m4_symbol_value_create (); - size_t len = strlen (mp->value); - - /* Sanity check that builtins meet the required interface. */ - assert (mp->min_args <= mp->max_args); - - m4_set_symbol_value_text (value, xmemdup0 (mp->value, len), len, 0); - VALUE_MODULE (value) = module; - VALUE_MIN_ARGS (value) = mp->min_args; - VALUE_MAX_ARGS (value) = mp->max_args; - - m4_symbol_pushdef (M4SYMTAB, mp->name, strlen (mp->name), value); - } - - m4_debug_message (context, M4_DEBUG_TRACE_MODULE, - _("module %s: macros loaded"), - m4_get_module_name (module)); - } -} - -m4_module * -m4_module_load (m4 *context, const char *name, m4_obstack *obs) -{ - m4_module *module = m4__module_find (context, name); - - if (!module) - { - module = m4__module_open (context, name, obs); - - if (module) - { - install_builtin_table (context, module); - install_macro_table (context, module); - } - } - - return module; -} - - -/* Return successive loaded modules. */ -m4_module * -m4_module_next (m4 *context, m4_module *module) -{ - return module ? module->next : context->modules; -} - -/* Return the first loaded module that passes the registered interface test - and is called NAME. */ -m4_module * -m4__module_find (m4 *context, const char *name) -{ - m4_module **pmodule = (m4_module **) m4_hash_lookup (context->namemap, name); - return pmodule ? *pmodule : NULL; -} - - -/* Compare two builtins A and B for sorting, as in qsort. */ -static int -compare_builtin_CB (const void *a, const void *b) -{ - const m4__builtin *builtin_a = (const m4__builtin *) a; - const m4__builtin *builtin_b = (const m4__builtin *) b; - int result = strcmp (builtin_a->builtin.name, builtin_b->builtin.name); - /* A builtin module should never provide two builtins with the same - name. */ - assert (result || a == b); - return result; -} - -/* Load a module. NAME can be a absolute file name or, if relative, - it is searched for in the module path. The module is unloaded in - case of error. */ -m4_module * -m4__module_open (m4 *context, const char *name, m4_obstack *obs) -{ - static const char * suffixes[] = { "", LT_MODULE_EXT, NULL }; - m4_module * module = NULL; - - assert (context); - - char *filepath = m4_path_search (context, name, suffixes); - void *handle = NULL; - - if (filepath) - { - handle = dlopen (filepath, RTLD_NOW|RTLD_GLOBAL); - free (filepath); - } - - if (handle) - { - m4_debug_message (context, M4_DEBUG_TRACE_MODULE, - _("module %s: opening file %s"), - name ? name : MODULE_SELF_NAME, - quotearg_style (locale_quoting_style, name)); - - module = (m4_module *) xzalloc (sizeof *module); - module->name = xstrdup (name); - module->handle = handle; - module->next = context->modules; - - context->modules = module; - m4_hash_insert (context->namemap, xstrdup (name), module); - - /* Find and run any initializing function in the opened module, - the first time the module is opened. */ - char *entry_point = xasprintf ("include_%s", name); - m4_module_init_func *init_func = - (m4_module_init_func *) dlsym (handle, entry_point); - free (entry_point); - - if (init_func) - { - init_func (context, module, obs); - - m4_debug_message (context, M4_DEBUG_TRACE_MODULE, - _("module %s: init hook called"), name); - } - else - { - m4_error (context, EXIT_FAILURE, 0, NULL, - _("module `%s' has no entry point"), name); - } - - m4_debug_message (context, M4_DEBUG_TRACE_MODULE, - _("module %s: opened"), name); - } - else - { - const char *err = dlerror (); - if (!err) err = _("unknown error"); - - /* Couldn't open the module; diagnose and exit. */ - m4_error (context, EXIT_FAILURE, 0, NULL, - _("cannot open module `%s': %s"), name, err); - } - - return module; -} |