Mercurial > hg > xemacs-beta
view src/emodules.c @ 4952:19a72041c5ed
Mule-izing, various fixes related to char * arguments
-------------------- ChangeLog entries follow: --------------------
modules/ChangeLog addition:
2010-01-26 Ben Wing <ben@xemacs.org>
* postgresql/postgresql.c:
* postgresql/postgresql.c (CHECK_LIVE_CONNECTION):
* postgresql/postgresql.c (print_pgresult):
* postgresql/postgresql.c (Fpq_conn_defaults):
* postgresql/postgresql.c (Fpq_connectdb):
* postgresql/postgresql.c (Fpq_connect_start):
* postgresql/postgresql.c (Fpq_result_status):
* postgresql/postgresql.c (Fpq_res_status):
Mule-ize large parts of it.
2010-01-26 Ben Wing <ben@xemacs.org>
* ldap/eldap.c (print_ldap):
* ldap/eldap.c (allocate_ldap):
Use write_ascstring().
src/ChangeLog addition:
2010-01-26 Ben Wing <ben@xemacs.org>
* alloc.c:
* alloc.c (build_ascstring):
* alloc.c (build_msg_cistring):
* alloc.c (staticpro_1):
* alloc.c (staticpro_name):
* alloc.c (staticpro_nodump_1):
* alloc.c (staticpro_nodump_name):
* alloc.c (unstaticpro_nodump_1):
* alloc.c (mcpro_1):
* alloc.c (mcpro_name):
* alloc.c (object_memory_usage_stats):
* alloc.c (common_init_alloc_early):
* alloc.c (init_alloc_once_early):
* buffer.c (print_buffer):
* buffer.c (vars_of_buffer):
* buffer.c (common_init_complex_vars_of_buffer):
* buffer.c (init_initial_directory):
* bytecode.c (invalid_byte_code):
* bytecode.c (print_compiled_function):
* bytecode.c (mark_compiled_function):
* chartab.c (print_table_entry):
* chartab.c (print_char_table):
* config.h.in:
* console-gtk.c:
* console-gtk.c (gtk_device_to_console_connection):
* console-gtk.c (gtk_semi_canonicalize_console_connection):
* console-gtk.c (gtk_canonicalize_console_connection):
* console-gtk.c (gtk_semi_canonicalize_device_connection):
* console-gtk.c (gtk_canonicalize_device_connection):
* console-stream.c (stream_init_frame_1):
* console-stream.c (vars_of_console_stream):
* console-stream.c (init_console_stream):
* console-x.c (x_semi_canonicalize_console_connection):
* console-x.c (x_semi_canonicalize_device_connection):
* console-x.c (x_canonicalize_device_connection):
* console-x.h:
* data.c (eq_with_ebola_notice):
* data.c (Fsubr_interactive):
* data.c (Fnumber_to_string):
* data.c (digit_to_number):
* device-gtk.c (gtk_init_device):
* device-msw.c (print_devmode):
* device-x.c (x_event_name):
* dialog-msw.c (handle_directory_dialog_box):
* dialog-msw.c (handle_file_dialog_box):
* dialog-msw.c (vars_of_dialog_mswindows):
* doc.c (weird_doc):
* doc.c (Fsnarf_documentation):
* doc.c (vars_of_doc):
* dumper.c (pdump):
* dynarr.c:
* dynarr.c (Dynarr_realloc):
* editfns.c (Fuser_real_login_name):
* editfns.c (get_home_directory):
* elhash.c (print_hash_table_data):
* elhash.c (print_hash_table):
* emacs.c (main_1):
* emacs.c (vars_of_emacs):
* emodules.c:
* emodules.c (_emodules_list):
* emodules.c (Fload_module):
* emodules.c (Funload_module):
* emodules.c (Flist_modules):
* emodules.c (find_make_module):
* emodules.c (attempt_module_delete):
* emodules.c (emodules_load):
* emodules.c (emodules_doc_subr):
* emodules.c (emodules_doc_sym):
* emodules.c (syms_of_module):
* emodules.c (vars_of_module):
* emodules.h:
* eval.c (print_subr):
* eval.c (signal_call_debugger):
* eval.c (build_error_data):
* eval.c (signal_error):
* eval.c (maybe_signal_error):
* eval.c (signal_continuable_error):
* eval.c (maybe_signal_continuable_error):
* eval.c (signal_error_2):
* eval.c (maybe_signal_error_2):
* eval.c (signal_continuable_error_2):
* eval.c (maybe_signal_continuable_error_2):
* eval.c (signal_ferror):
* eval.c (maybe_signal_ferror):
* eval.c (signal_continuable_ferror):
* eval.c (maybe_signal_continuable_ferror):
* eval.c (signal_ferror_with_frob):
* eval.c (maybe_signal_ferror_with_frob):
* eval.c (signal_continuable_ferror_with_frob):
* eval.c (maybe_signal_continuable_ferror_with_frob):
* eval.c (syntax_error):
* eval.c (syntax_error_2):
* eval.c (maybe_syntax_error):
* eval.c (sferror):
* eval.c (sferror_2):
* eval.c (maybe_sferror):
* eval.c (invalid_argument):
* eval.c (invalid_argument_2):
* eval.c (maybe_invalid_argument):
* eval.c (invalid_constant):
* eval.c (invalid_constant_2):
* eval.c (maybe_invalid_constant):
* eval.c (invalid_operation):
* eval.c (invalid_operation_2):
* eval.c (maybe_invalid_operation):
* eval.c (invalid_change):
* eval.c (invalid_change_2):
* eval.c (maybe_invalid_change):
* eval.c (invalid_state):
* eval.c (invalid_state_2):
* eval.c (maybe_invalid_state):
* eval.c (wtaerror):
* eval.c (stack_overflow):
* eval.c (out_of_memory):
* eval.c (print_multiple_value):
* eval.c (issue_call_trapping_problems_warning):
* eval.c (backtrace_specials):
* eval.c (backtrace_unevalled_args):
* eval.c (Fbacktrace):
* eval.c (warn_when_safe):
* event-Xt.c (modwarn):
* event-Xt.c (modbarf):
* event-Xt.c (check_modifier):
* event-Xt.c (store_modifier):
* event-Xt.c (emacs_Xt_format_magic_event):
* event-Xt.c (describe_event):
* event-gtk.c (dragndrop_data_received):
* event-gtk.c (store_modifier):
* event-gtk.c (gtk_reset_modifier_mapping):
* event-msw.c (dde_eval_string):
* event-msw.c (Fdde_alloc_advise_item):
* event-msw.c (mswindows_dde_callback):
* event-msw.c (FROB):
* event-msw.c (emacs_mswindows_format_magic_event):
* event-stream.c (external_debugging_print_event):
* event-stream.c (execute_help_form):
* event-stream.c (vars_of_event_stream):
* events.c (print_event_1):
* events.c (print_event):
* events.c (event_equal):
* extents.c (print_extent_1):
* extents.c (print_extent):
* extents.c (vars_of_extents):
* faces.c (print_face):
* faces.c (complex_vars_of_faces):
* file-coding.c:
* file-coding.c (print_coding_system):
* file-coding.c (print_coding_system_in_print_method):
* file-coding.c (default_query_method):
* file-coding.c (find_coding_system):
* file-coding.c (make_coding_system_1):
* file-coding.c (chain_print):
* file-coding.c (undecided_print):
* file-coding.c (gzip_print):
* file-coding.c (vars_of_file_coding):
* file-coding.c (complex_vars_of_file_coding):
* fileio.c:
* fileio.c (report_file_type_error):
* fileio.c (report_error_with_errno):
* fileio.c (report_file_error):
* fileio.c (barf_or_query_if_file_exists):
* fileio.c (vars_of_fileio):
* floatfns.c (matherr):
* fns.c (print_bit_vector):
* fns.c (Fmapconcat):
* fns.c (add_suffix_to_symbol):
* fns.c (add_prefix_to_symbol):
* frame-gtk.c:
* frame-gtk.c (Fgtk_window_id):
* frame-x.c (def):
* frame-x.c (x_cde_transfer_callback):
* frame.c:
* frame.c (Fmake_frame):
* gc.c (show_gc_cursor_and_message):
* gc.c (vars_of_gc):
* glyphs-eimage.c (png_instantiate):
* glyphs-eimage.c (tiff_instantiate):
* glyphs-gtk.c (gtk_print_image_instance):
* glyphs-msw.c (mswindows_print_image_instance):
* glyphs-x.c (x_print_image_instance):
* glyphs-x.c (update_widget_face):
* glyphs.c (make_string_from_file):
* glyphs.c (print_image_instance):
* glyphs.c (signal_image_error):
* glyphs.c (signal_image_error_2):
* glyphs.c (signal_double_image_error):
* glyphs.c (signal_double_image_error_2):
* glyphs.c (xbm_mask_file_munging):
* glyphs.c (pixmap_to_lisp_data):
* glyphs.h:
* gui.c (gui_item_display_flush_left):
* hpplay.c (player_error_internal):
* hpplay.c (myHandler):
* intl-win32.c:
* intl-win32.c (langcode_to_lang):
* intl-win32.c (sublangcode_to_lang):
* intl-win32.c (Fmswindows_get_locale_info):
* intl-win32.c (lcid_to_locale_mule_or_no):
* intl-win32.c (mswindows_multibyte_to_unicode_print):
* intl-win32.c (complex_vars_of_intl_win32):
* keymap.c:
* keymap.c (print_keymap):
* keymap.c (ensure_meta_prefix_char_keymapp):
* keymap.c (Fkey_description):
* keymap.c (Ftext_char_description):
* lisp.h:
* lisp.h (struct):
* lisp.h (DECLARE_INLINE_HEADER):
* lread.c (Fload_internal):
* lread.c (locate_file):
* lread.c (read_escape):
* lread.c (read_raw_string):
* lread.c (read1):
* lread.c (read_list):
* lread.c (read_compiled_function):
* lread.c (init_lread):
* lrecord.h:
* marker.c (print_marker):
* marker.c (marker_equal):
* menubar-msw.c (displayable_menu_item):
* menubar-x.c (command_builder_operate_menu_accelerator):
* menubar.c (vars_of_menubar):
* minibuf.c (reinit_complex_vars_of_minibuf):
* minibuf.c (complex_vars_of_minibuf):
* mule-charset.c (Fmake_charset):
* mule-charset.c (complex_vars_of_mule_charset):
* mule-coding.c (iso2022_print):
* mule-coding.c (fixed_width_query):
* number.c (bignum_print):
* number.c (ratio_print):
* number.c (bigfloat_print):
* number.c (bigfloat_finalize):
* objects-msw.c:
* objects-msw.c (mswindows_color_to_string):
* objects-msw.c (mswindows_color_list):
* objects-tty.c:
* objects-tty.c (tty_font_list):
* objects-tty.c (tty_find_charset_font):
* objects-xlike-inc.c (xft_find_charset_font):
* objects-xlike-inc.c (endif):
* print.c:
* print.c (write_istring):
* print.c (write_ascstring):
* print.c (Fterpri):
* print.c (Fprint):
* print.c (print_error_message):
* print.c (print_vector_internal):
* print.c (print_cons):
* print.c (print_string):
* print.c (printing_unreadable_object):
* print.c (print_internal):
* print.c (print_float):
* print.c (print_symbol):
* process-nt.c (mswindows_report_winsock_error):
* process-nt.c (nt_canonicalize_host_name):
* process-unix.c (unix_canonicalize_host_name):
* process.c (print_process):
* process.c (report_process_error):
* process.c (report_network_error):
* process.c (make_process_internal):
* process.c (Fstart_process_internal):
* process.c (status_message):
* process.c (putenv_internal):
* process.c (vars_of_process):
* process.h:
* profile.c (vars_of_profile):
* rangetab.c (print_range_table):
* realpath.c (vars_of_realpath):
* redisplay.c (vars_of_redisplay):
* search.c (wordify):
* search.c (Freplace_match):
* sheap.c (sheap_adjust_h):
* sound.c (report_sound_error):
* sound.c (Fplay_sound_file):
* specifier.c (print_specifier):
* symbols.c (Fsubr_name):
* symbols.c (do_symval_forwarding):
* symbols.c (set_default_buffer_slot_variable):
* symbols.c (set_default_console_slot_variable):
* symbols.c (store_symval_forwarding):
* symbols.c (default_value):
* symbols.c (defsymbol_massage_name_1):
* symbols.c (defsymbol_massage_name_nodump):
* symbols.c (defsymbol_massage_name):
* symbols.c (defsymbol_massage_multiword_predicate_nodump):
* symbols.c (defsymbol_massage_multiword_predicate):
* symbols.c (defsymbol_nodump):
* symbols.c (defsymbol):
* symbols.c (defkeyword):
* symbols.c (defkeyword_massage_name):
* symbols.c (check_module_subr):
* symbols.c (deferror_1):
* symbols.c (deferror):
* symbols.c (deferror_massage_name):
* symbols.c (deferror_massage_name_and_message):
* symbols.c (defvar_magic):
* symeval.h:
* symeval.h (DEFVAR_SYMVAL_FWD):
* sysdep.c:
* sysdep.c (init_system_name):
* sysdll.c:
* sysdll.c (MAYBE_PREPEND_UNDERSCORE):
* sysdll.c (dll_function):
* sysdll.c (dll_variable):
* sysdll.c (dll_error):
* sysdll.c (dll_open):
* sysdll.c (dll_close):
* sysdll.c (image_for_address):
* sysdll.c (my_find_image):
* sysdll.c (search_linked_libs):
* sysdll.h:
* sysfile.h:
* sysfile.h (DEFAULT_DIRECTORY_FALLBACK):
* syswindows.h:
* tests.c (DFC_CHECK_LENGTH):
* tests.c (DFC_CHECK_CONTENT):
* tests.c (Ftest_hash_tables):
* text.c (vars_of_text):
* text.h:
* tooltalk.c (tt_opnum_string):
* tooltalk.c (tt_message_arg_ival_string):
* tooltalk.c (Ftooltalk_default_procid):
* tooltalk.c (Ftooltalk_default_session):
* tooltalk.c (init_tooltalk):
* tooltalk.c (vars_of_tooltalk):
* ui-gtk.c (Fdll_load):
* ui-gtk.c (type_to_marshaller_type):
* ui-gtk.c (Fgtk_import_function_internal):
* ui-gtk.c (emacs_gtk_object_printer):
* ui-gtk.c (emacs_gtk_boxed_printer):
* unicode.c (unicode_to_ichar):
* unicode.c (unicode_print):
* unicode.c (unicode_query):
* unicode.c (vars_of_unicode):
* unicode.c (complex_vars_of_unicode):
* win32.c:
* win32.c (mswindows_report_process_error):
* window.c (print_window):
* xemacs.def.in.in:
BASIC IDEA: Further fixing up uses of char * and CIbyte *
to reflect their actual semantics; Mule-izing some code;
redoing of the not-yet-working code to handle message translation.
Clean up code to handle message-translation (not yet working).
Create separate versions of build_msg_string() for working with
Ibyte *, CIbyte *, and Ascbyte * arguments. Assert that Ascbyte *
arguments are pure-ASCII. Make build_msg_string() be the same
as build_msg_ascstring(). Create same three versions of GETTEXT()
and DEFER_GETTEXT(). Also create build_defer_string() and
variants for the equivalent of DEFER_GETTEXT() when building a
string. Remove old CGETTEXT(). Clean up code where GETTEXT(),
DEFER_GETTEXT(), build_msg_string(), etc. was being called and
introduce some new calls to build_msg_string(), etc. Remove
GETTEXT() from calls to weird_doc() -- we assume that the
message snarfer knows about weird_doc(). Remove uses of
DEFER_GETTEXT() from error messages in sysdep.c and instead use
special comments /* @@@begin-snarf@@@ */ and /* @@@end-snarf@@@ */
that the message snarfer presumably knows about.
Create build_ascstring() and use it in many instances in place
of build_string(). The purpose of having Ascbyte * variants is
to make the code more self-documenting in terms of what sort of
semantics is expected for char * strings. In fact in the process
of looking for uses of build_string(), much improperly Mule-ized
was discovered.
Mule-ize a lot of code as described in previous paragraph,
e.g. in sysdep.c.
Make the error functions take Ascbyte * strings and fix up a
couple of places where non-pure-ASCII strings were being passed in
(file-coding.c, mule-coding.c, unicode.c). (It's debatable whether
we really need to make the error functions work this way. It
helps catch places where code is written in a way that message
translation won't work, but we may well never implement message
translation.)
Make staticpro() and friends take Ascbyte * strings instead of
raw char * strings. Create a const_Ascbyte_ptr dynarr type
to describe what's held by staticpro_names[] and friends,
create pdump descriptions for const_Ascbyte_ptr dynarrs, and
use them in place of specially-crafted staticpro descriptions.
Mule-ize certain other functions (e.g. x_event_name) by correcting
raw use of char * to Ascbyte *, Rawbyte * or another such type,
and raw use of char[] buffers to another type (usually Ascbyte[]).
Change many uses of write_c_string() to write_msg_string(),
write_ascstring(), etc.
Mule-ize emodules.c, emodules.h, sysdll.h.
Fix some un-Mule-ized code in intl-win32.c.
A comment in event-Xt.c and the limitations of the message
snarfer (make-msgfile or whatever) is presumably incorrect --
it should be smart enough to handle function calls spread over
more than one line. Clean up code in event-Xt.c that was
written awkwardly for this reason.
In config.h.in, instead of NEED_ERROR_CHECK_TYPES_INLINES,
create a more general XEMACS_DEFS_NEEDS_INLINE_DECLS to
indicate when inlined functions need to be declared in
xemacs.defs.in.in, and make use of it in xemacs.defs.in.in.
We need to do this because postgresql.c now calls qxestrdup(),
which is an inline function.
Make nconc2() and other such functions MODULE_API and put
them in xemacs.defs.in.in since postgresql.c now uses them.
Clean up indentation in lread.c and a few other places.
In text.h, document ASSERT_ASCTEXT_ASCII() and
ASSERT_ASCTEXT_ASCII_LEN(), group together the stand-in
encodings and add some more for DLL symbols, function and
variable names, etc.
author | Ben Wing <ben@xemacs.org> |
---|---|
date | Tue, 26 Jan 2010 23:22:30 -0600 |
parents | 726060ee587c |
children | 304aebb79cd3 |
line wrap: on
line source
/* emodules.c - Support routines for dynamic module loading (C) Copyright 1998, 1999 J. Kean Johnston. All rights reserved. (C) Copyright 2010 Ben Wing. This file is part of XEmacs. XEmacs 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. XEmacs 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 XEmacs; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* This file has been Mule-ized, Ben Wing, 1-26-10. */ #include "emodules.h" #include "sysdll.h" #ifdef HAVE_LTDL #include <ltdl.h> #endif /* Load path */ static Lisp_Object Vmodule_load_path; /* Module lFile extensions */ static Lisp_Object Vmodule_extensions; #ifdef HAVE_SHLIB /* CE-Emacs version number */ Lisp_Object Vmodule_version; /* Do we do our work quietly? */ int load_modules_quietly; /* Set this while unloading a module. This should NOT be made set by users, as it allows the unbinding of symbol-value-forward variables. */ int unloading_module; Lisp_Object Qdll_error; Lisp_Object Qmodule, Qunload_module, module_tag; typedef struct _emodules_list { int used; /* Is this slot used? */ Ibyte *soname; /* Name of the shared object loaded (full path) */ Ibyte *modname; /* The name of the module */ Ibyte *modver; /* The module version string */ Ibyte *modtitle; /* How the module announces itself */ void (*unload) (void);/* Module cleanup function to run before unloading */ dll_handle dlhandle; /* Dynamic lib handle */ } emodules_list; static int emodules_depth; static dll_handle dlhandle; static emodules_list *modules; static int modnum; static int find_make_module (Lisp_Object mod, const Ibyte *name, const Ibyte *ver, int make_or_find); static Lisp_Object module_load_unwind (Lisp_Object); static void attempt_module_delete (int mod); DEFUN ("load-module", Fload_module, 1, 3, "FLoad dynamic module: ", /* Load in a C Emacs Extension module named FILE. The optional NAME and VERSION are used to identify specific modules. DO NOT USE THIS FUNCTION in your programs. Use `require' instead. This function is similar in intent to `load' except that it loads in pre-compiled C or C++ code, using dynamic shared objects. If NAME is specified, then the module is only loaded if its internal name matches the NAME specified. If VERSION is specified, then the module is only loaded if it matches that VERSION. This function will check to make sure that the same module is not loaded twice. Modules are searched for in the same way as Lisp files, except that the valid file extensions are `.so', `.dll', `.ell', or `.dylib'. All symbols in the shared module must be completely resolved in order for this function to be successful. Any modules which the specified FILE depends on will be automatically loaded. You can determine which modules have been loaded as dynamic shared objects by examining the return value of the function `list-modules'. It is possible, although unwise, to unload modules using `unload-feature'. The preferred mechanism for unloading or reloading modules is to quit XEmacs, and then reload those new or changed modules that are required. Messages informing you of the progress of the load are displayed unless the variable `load-modules-quietly' is non-NIL. */ (file, name, version)) { const Ibyte *mod, *mname, *mver; int speccount = specpdl_depth(); CHECK_STRING (file); mod = XSTRING_DATA (file); if (NILP (name)) mname = (const Ibyte *) ""; else mname = XSTRING_DATA (name); if (NILP (version)) mver = (const Ibyte *) ""; else mver = XSTRING_DATA (version); dlhandle = 0; record_unwind_protect (module_load_unwind, make_int(modnum)); emodules_load (mod, mname, mver); unbind_to (speccount); return Qt; } DEFUN ("unload-module", Funload_module, 1, 3, 0, /* Unload a module previously loaded with load-module. DO NOT USE THIS FUNCTION in your programs. Use `unload-feature' instead. As with load-module, this function requires at least the module FILE, and optionally the module NAME and VERSION to unload. It may not be possible for the module to be unloaded from memory, as there may be Lisp objects referring to variables inside the module code. However, once you have requested a module to be unloaded, it will be unloaded from memory as soon as the last reference to symbols within the module is destroyed. */ (file, name, version)) { int x; const Ibyte *mname, *mver; Lisp_Object foundname = Qnil; struct gcpro gcpro1; CHECK_STRING(file); GCPRO1 (foundname); if (locate_file (Vmodule_load_path, file, Vmodule_extensions, &foundname, 0) < 0) return Qt; UNGCPRO; if (NILP (name)) mname = (const Ibyte *) ""; else mname = XSTRING_DATA (name); if (NILP (version)) mver = (const Ibyte *) ""; else mver = XSTRING_DATA (version); x = find_make_module (foundname, mname, mver, 1); if (x != -1) { if (modules[x].unload != NULL) modules[x].unload (); attempt_module_delete (x); } return Qt; } DEFUN ("list-modules", Flist_modules, 0, 0, "", /* Produce a list of loaded dynamic modules. This function will return a list of all the loaded dynamic modules. Each element in the list is a list in the form (SONAME NAME VER DESC), where SONAME is the name of the shared object that was loaded, NAME is the internal module name, VER is the version of the module, and DESC is how the module describes itself. This function returns a list, so you will need to assign the return value to a variable and then examine the variable with `describe-variable'. For example: (setq mylist (list-modules)) (describe-variable 'mylist) NOTE: It is possible for the same module to be loaded more than once, at different versions. However, you should never see the same module, with the same name and version, loaded more than once. If you do, this is a bug, and you are encouraged to report it. */ ()) { Lisp_Object mlist = Qnil; int i; for (i = 0; i < modnum; i++) { if (modules[i].used == 1) mlist = Fcons (list4 (build_intstring (modules[i].soname), build_intstring (modules[i].modname), build_intstring (modules[i].modver), build_intstring (modules[i].modtitle)), mlist); } return mlist; } static int find_make_module (Lisp_Object mod, const Ibyte *name, const Ibyte *ver, int mof) { int i, fs = -1; Ibyte *modstr = XSTRING_DATA (mod); for (i = 0; i < modnum; i++) { if (fs == -1 && modules[i].used == 0) fs = i; if (qxestrcmp (modules[i].soname, modstr) == 0) { if (name && name[0] && qxestrcmp (modules[i].modname, name)) continue; if (ver && ver[0] && qxestrcmp (modules[i].modver, ver)) continue; return i; /* Found a match */ } } if (mof) return fs; if (fs != -1) return fs; /* First free slot */ /* * We only get here if we haven't found a free slot and the module was * not previously loaded. */ if (modules == NULL) modules = xnew (emodules_list); modnum++; XREALLOC_ARRAY (modules, emodules_list, modnum); fs = modnum - 1; memset (&modules[fs], 0, sizeof (emodules_list)); return fs; } static void attempt_module_delete (int mod) { if (dll_close (modules[mod].dlhandle) == 0) { xfree (modules[mod].soname, Ibyte *); xfree (modules[mod].modname, Ibyte *); xfree (modules[mod].modver, Ibyte *); xfree (modules[mod].modtitle, Ibyte *); modules[mod].dlhandle = 0; modules[mod].used = 0; } else if (modules[mod].used > 1) modules[mod].used = 1; /* We couldn't delete it - it stays */ } static Lisp_Object module_load_unwind (Lisp_Object upto) { int x,l=0; /* * First close off the current handle if it is open. */ if (dlhandle != 0) dll_close (dlhandle); dlhandle = 0; if (CONSP (upto)) { if (INTP (XCAR (upto))) l = XINT (XCAR (upto)); free_cons (upto); } else l = XINT (upto); /* * Here we need to go through and dlclose() (IN REVERSE ORDER!) any * modules that were loaded as part of this load chain. We only mark * the slots as closed if the dlclose() succeeds. */ for (x = modnum-1; x >= l; x--) { if (modules[x].used > 1) attempt_module_delete (x); } emodules_depth = 0; return Qnil; } /* * Do the actual grunt-work of loading in a module. We first try and * dlopen() the module. If that fails, we have an error and we bail * out immediately. If the dlopen() succeeds, we need to check for the * existence of certain special symbols. * * All modules will have complete access to the variables and functions * defined within XEmacs itself. It is up to the module to declare any * variables or functions it uses, however. Modules will also have access * to other functions and variables in other loaded modules, unless they * are defined as STATIC. * * We need to be very careful with how we load modules. If we encounter an * error along the way, we need to back out completely to the point at * which the user started. Since we can be called recursively, we need to * take care with marking modules as loaded. When we first start loading * modules, we set the counter to zero. As we enter the function each time, * we increment the counter, and before we leave we decrement it. When * we get back down to 0, we know we are at the end of the chain and we * can mark all the modules in the list as loaded. * * When we signal an error, we need to be sure to unwind all modules loaded * thus far (but only for this module chain). It is assumed that if any * modules in a chain fail, then they all do. This is logical, considering * that the only time we recurse is when we have dependent modules. So in * the error handler we take great care to close off the module chain before * we call "error" and let the Fmodule_load unwind_protect() function handle * the cleaning up. */ void emodules_load (const Ibyte *module, const Ibyte *modname, const Ibyte *modver) { Lisp_Object old_load_list; Lisp_Object filename; Lisp_Object foundname, lisp_modname; int x, mpx; const Extbyte **f; const long *ellcc_rev; Ibyte *mver, *mname, *mtitle, *symname; void (*modload)(void) = 0; void (*modsyms)(void) = 0; void (*modvars)(void) = 0; void (*moddocs)(void) = 0; void (*modunld)(void) = 0; emodules_list *mp; struct gcpro gcpro1, gcpro2, gcpro3, gcpro4; filename = Qnil; foundname = Qnil; emodules_depth++; dlhandle = 0; if (module == NULL || module[0] == '\0') invalid_argument ("Empty module name", Qunbound); GCPRO4 (filename, foundname, old_load_list, lisp_modname); filename = build_intstring (module); if (locate_file (Vmodule_load_path, filename, Vmodule_extensions, &foundname, 0) < 0) signal_error (Qdll_error, "Cannot open dynamic module", filename); lisp_modname = call1 (Qfile_name_sans_extension, Ffile_name_nondirectory (foundname)); dlhandle = dll_open (foundname); if (dlhandle == NULL) { signal_error (Qdll_error, "Opening dynamic module", dll_error ()); } ellcc_rev = (const long *) dll_variable (dlhandle, "emodule_compiler"); if (ellcc_rev == NULL || *ellcc_rev <= 0L) signal_error (Qdll_error, "Invalid dynamic module: Missing symbol `emodule_compiler'", Qunbound); if (*ellcc_rev > EMODULES_REVISION) signal_ferror (Qdll_error, "Invalid dynamic module: Unsupported version `%ld(%ld)'", *ellcc_rev, EMODULES_REVISION); f = (const Extbyte **) dll_variable (dlhandle, "emodule_name"); if (f == NULL || *f == NULL) signal_error (Qdll_error, "Invalid dynamic module: Missing symbol `emodule_name'", Qunbound); mname = NEW_EXTERNAL_TO_C_STRING (f, Qemodule_string_encoding); /* #### Not obvious we have to force an alloca copy here, but the old code did so */ IBYTE_STRING_TO_ALLOCA (mname, mname); if (mname[0] == '\0') signal_error (Qdll_error, "Invalid dynamic module: Empty value for `emodule_name'", Qunbound); f = (const Extbyte **) dll_variable (dlhandle, "emodule_version"); if (f == NULL || *f == NULL) signal_error (Qdll_error, "Missing symbol `emodule_version': Invalid dynamic module", Qunbound); mver = NEW_EXTERNAL_TO_C_STRING (f, Qemodule_string_encoding); /* #### Not obvious we have to force an alloca copy here, but the old code did so */ IBYTE_STRING_TO_ALLOCA (mver, mver); f = (const Extbyte **) dll_variable (dlhandle, "emodule_title"); if (f == NULL || *f == NULL) signal_error (Qdll_error, "Invalid dynamic module: Missing symbol `emodule_title'", Qunbound); mtitle = NEW_EXTERNAL_TO_C_STRING (f, Qemodule_string_encoding); /* #### Not obvious we have to force an alloca copy here, but the old code did so */ IBYTE_STRING_TO_ALLOCA (mtitle, mtitle); symname = alloca_ibytes (qxestrlen (mname) + 15); qxestrcpy_ascii (symname, "modules_of_"); qxestrcat (symname, mname); modload = (void (*)(void)) dll_function (dlhandle, symname); /* * modload is optional. If the module doesn't require other modules it can * be left out. */ qxestrcpy_ascii (symname, "syms_of_"); qxestrcat (symname, mname); modsyms = (void (*)(void)) dll_function (dlhandle, symname); if (modsyms == NULL) { missing_symbol: signal_error (Qdll_error, "Invalid dynamic module: Missing symbol", build_intstring (symname)); } qxestrcpy_ascii (symname, "vars_of_"); qxestrcat (symname, mname); modvars = (void (*)(void)) dll_function (dlhandle, symname); if (modvars == NULL) goto missing_symbol; qxestrcpy_ascii (symname, "docs_of_"); qxestrcat (symname, mname); moddocs = (void (*)(void)) dll_function (dlhandle, symname); if (moddocs == NULL) goto missing_symbol; /* Now look for the optional unload function. */ qxestrcpy_ascii (symname, "unload_"); qxestrcat (symname, mname); modunld = (void (*)(void)) dll_function (dlhandle, symname); if (modname && modname[0] && qxestrcmp (modname, mname)) signal_error (Qdll_error, "Module name mismatch", Qunbound); if (modver && modver[0] && qxestrcmp (modver, mver)) signal_error (Qdll_error, "Module version mismatch", Qunbound); /* * Attempt to make a new slot for this module. If this really is the * first time we are loading this module, the used member will be 0. * If that is non-zero, we know that we have a previously loaded module * of the same name and version, and we don't need to go any further. */ mpx = find_make_module (foundname, mname, mver, 0); mp = &modules[mpx]; if (mp->used > 0) { emodules_depth--; dll_close (dlhandle); dlhandle = 0; /* Zero this out before module_load_unwind runs */ return; } if (!load_modules_quietly) message ("Loading %s v%s (%s)", mname, mver, mtitle); /* * We have passed the basic initialization, and can now add this * module to the list of modules. */ mp->used = emodules_depth + 1; mp->soname = qxestrdup (XSTRING_DATA (foundname)); mp->modname = qxestrdup (mname); mp->modver = qxestrdup (mver); mp->modtitle = qxestrdup (mtitle); mp->dlhandle = dlhandle; mp->unload = modunld; dlhandle = 0; old_load_list = Vcurrent_load_list; Vcurrent_load_list = Qnil; LOADHIST_ATTACH (lisp_modname); LOADHIST_ATTACH (module_tag); /* * Now we need to call the module init function and perform the various * startup tasks. */ if (modload != 0) (*modload) (); /* * Now we can get the module to initialize its symbols, and then its * variables, and lastly the documentation strings. */ (*modsyms) (); (*modvars) (); (*moddocs) (); if (!load_modules_quietly) message ("Loaded module %s v%s (%s)", mname, mver, mtitle); Vload_history = Fcons (Fnreverse (Vcurrent_load_list), Vload_history); Vcurrent_load_list = old_load_list; UNGCPRO; emodules_depth--; if (emodules_depth == 0) { /* * We have reached the end of the load chain. We now go through the * list of loaded modules and mark all the valid modules as just * that. */ for (x = 0; x < modnum; x++) if (modules[x].used > 1) modules[x].used = 1; } } void emodules_doc_subr (const Ibyte *symname, const Ibyte *doc) { Bytecount len = qxestrlen (symname); Lisp_Object sym = oblookup (Vobarray, symname, len); Lisp_Subr *subr; /* Skip autoload cookies */ if (SYMBOLP (sym) && SUBRP (XSYMBOL (sym)->function)) { subr = XSUBR (XSYMBOL (sym)->function); subr->doc = xstrdup (doc); } /* * #### FIXME: I wish there was some way to avoid the xstrdup(). Is it * possible to just set a pointer to the string, or somehow create a * symbol whose value we can point to the constant string? Can someone * look into this? */ } void emodules_doc_sym (const Ibyte *symname, const Ibyte *doc) { Bytecount len = qxestrlen (symname); Lisp_Object sym = oblookup (Vobarray, symname, len); Lisp_Object docstr; struct gcpro gcpro1; if (SYMBOLP (sym)) { docstr = build_intstring (doc); GCPRO1 (docstr); Fput (sym, Qvariable_documentation, docstr); UNGCPRO; } } void syms_of_module (void) { DEFERROR_STANDARD (Qdll_error, Qerror); DEFSYMBOL (Qmodule); DEFSYMBOL (Qunload_module); DEFSUBR (Fload_module); DEFSUBR (Flist_modules); DEFSUBR (Funload_module); module_tag = Fcons (Qmodule, Qnil); staticpro (&module_tag); Fput (Qunload_module, Qdisabled, Qt); } void reinit_vars_of_module (void) { emodules_depth = 0; modules = NULL; modnum = 0; } #endif /* HAVE_SHLIB */ void vars_of_module (void) { #ifdef HAVE_SHLIB Fprovide (intern ("modules")); #ifdef HAVE_LTDL lt_dlinit (); lt_dlmalloc = (lt_ptr (*) (size_t)) xmalloc; lt_dlrealloc = (lt_ptr (*) (lt_ptr, size_t)) xrealloc; lt_dlfree = (void (*) (lt_ptr)) xfree_1; #endif DEFVAR_LISP ("module-version", &Vmodule_version /* Emacs dynamic loading mechanism version, as a string. This string is in the form XX.YY.ppp, where XX is the major version number, YY is the minor version number, and ppp is the patch level. This variable can be used to distinguish between different versions of the dynamic loading technology used in Emacs, if required. It is not a given that this value will be the same as the Emacs version number. */ ); Vmodule_version = build_string (EMODULES_VERSION); DEFVAR_BOOL ("load-modules-quietly", &load_modules_quietly /* *Set to t if module loading is to be silent. Normally, when loading dynamic modules, Emacs will inform you of its progress, and will display the module name and version if the module is loaded correctly. Setting this variable to `t' will suppress these messages. This would normally only be done if `load-module' was being called by a Lisp function. */); load_modules_quietly = 0; DEFVAR_BOOL ("unloading-module", &unloading_module /* Used internally by `unload-feature'. Do not set this variable. Danger, danger, Will Robinson! */); unloading_module = 0; #endif /* HAVE_SHLIB */ DEFVAR_LISP ("module-load-path", &Vmodule_load_path /* *List of directories to search for dynamic modules to load. Each element is a string (directory name) or nil (try default directory). Note that elements of this list *may not* begin with "~", so you must call `expand-file-name' on them before adding them to this list. Initialized based on EMACSMODULEPATH environment variable, if any, otherwise to default specified the file `paths.h' when XEmacs was built. If there were no paths specified in `paths.h', then XEmacs chooses a default value for this variable by looking around in the file-system near the directory in which the XEmacs executable resides. Due to the nature of dynamic modules, the path names should almost always refer to architecture-dependent directories. It is unwise to attempt to store dynamic modules in a heterogenous environment. Some environments are similar enough to each other that XEmacs will be unable to determine the correctness of a dynamic module, which can have unpredictable results when a dynamic module is loaded. */); Vmodule_load_path = Qnil; DEFVAR_LISP ("module-extensions", &Vmodule_extensions /* *List of filename extensions to use when searching for dynamic modules. */); Vmodule_extensions = list5 (build_ascstring (".ell"), build_ascstring (".so"), build_ascstring (".dll"), build_ascstring (".dylib"), build_ascstring ("")); }