summaryrefslogtreecommitdiff
path: root/m4/module.c
diff options
context:
space:
mode:
Diffstat (limited to 'm4/module.c')
-rw-r--r--m4/module.c344
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;
-}