view src/minibuf.c @ 2720:6fa9919a9a0b

[xemacs-hg @ 2005-04-08 23:10:01 by crestani] ChangeLog addition: 2005-04-01  Marcus Crestani  <crestani@xemacs.org>         The new allocator.         New configure flag: `MC_ALLOC':         * configure.ac (XE_COMPLEX_ARG_ENABLE): Add `--enable-mc-alloc' as         a new configure flag.         * configure.in (AC_INIT_PARSE_ARGS): Add `--mc-alloc' as a new         configure flag.         * configure.usage: Add description for `mc-alloc'.         DUMP_IN_EXEC:         * Makefile.in.in: Condition the installation of a separate dump         file on !DUMP_ON_EXEC.         * configure.ac (XE_COMPLEX_ARG_ENABLE): Add         `--enable-dump-in-exec' as a new configure flag.         * configure.ac: DUMP_IN_EXEC is define as default for PDUMP but         not default for MC_ALLOC.         * configure.in (AC_INIT_PARSE_ARGS): Add `--dump-in-exec' as a         new configure flag.         * configure.in: DUMP_IN_EXEC is define as default for PDUMP but         not default for MC_ALLOC.         * configure.usage: Add description for `dump-in-exec'. lib-src/ChangeLog addition: 2005-04-01  Marcus Crestani  <crestani@xemacs.org>         The new allocator.         DUMP_IN_EXEC:                  * Makefile.in.in: Only compile insert-data-in-exec if         DUMP_IN_EXEC is defined. lisp/ChangeLog addition: 2005-04-01  Marcus Crestani  <crestani@xemacs.org>         The new allocator.         MEMORY_USAGE_STATS         * diagnose.el: Add new lisp function to pretty print statistics         about the new allocator.         * diagnose.el (show-mc-alloc-memory-usage): New. modules/ChangeLog addition: 2005-04-01  Marcus Crestani  <crestani@xemacs.org>         The new allocator.         Remove Lcrecords:                  * postgresql/postgresql.c (allocate_pgconn): Allocate with new         allocator.         * postgresql/postgresql.c (allocate_pgresult): Allocate PGresult         with new allocator.           * postgresql/postgresql.h (struct Lisp_PGconn): Add         lrecord_header.         * postgresql/postgresql.h (struct Lisp_PGresult): Add         lrecord_header.         * ldap/eldap.c (allocate_ldap): Allocate with new allocator.         * ldap/eldap.h (struct Lisp_LDAP): Add lrecord_header. nt/ChangeLog addition: 2005-04-01  Marcus Crestani  <crestani@xemacs.org>         The new allocator.         New configure flag: `MC_ALLOC':         * config.inc.samp: Add new flag `MC_ALLOC'.         * xemacs.mak: Add flag and configuration output for `MC_ALLOC'.         New files:         * xemacs.dsp: Add source files mc-alloc.c and mc-alloc.h.         * xemacs.mak: Add new object file mc-alloc.obj to dependencies. src/ChangeLog addition: 2005-04-01  Marcus Crestani  <crestani@xemacs.org>         The new allocator.         New configure flag: `MC_ALLOC':         * config.h.in: Add new flag `MC_ALLOC'.         New files:         * Makefile.in.in: Add new object file mc-alloc.o.         * depend: Add new files to dependencies.         * mc-alloc.c: New.         * mc-alloc.h: New.         Running the new allocator from XEmacs:         * alloc.c (deadbeef_memory): Moved to mc-alloc.c.         * emacs.c (main_1): Initialize the new allocator and add         syms_of_mc_alloc.         * symsinit.h: Add syms_of_mc_alloc.         New lrecord allocation and free functions:         * alloc.c (alloc_lrecord): New. Allocates an lrecord, includes         type checking and initializing of the lrecord_header.         * alloc.c (noseeum_alloc_lrecord): Same as above, but increments         the NOSEEUM cons counter.         * alloc.c (free_lrecord): New. Calls the finalizer and frees the         lrecord.         * lrecord.h: Add lrecord allocation prototypes and comments.         Remove old lrecord FROB block allocation:                  * alloc.c (allocate_lisp_storage): Former function to expand         heap. Not needed anymore, remove.         * alloc.c: Completely remove `Fixed-size type macros'         * alloc.c (release_breathing_space): Remove.         * alloc.c (memory_full): Remove release_breathing_space.         * alloc.c (refill_memory_reserve): Remove.         * alloc.c (TYPE_ALLOC_SIZE): Remove.         * alloc.c (DECLARE_FIXED_TYPE_ALLOC): Remove.         * alloc.c (ALLOCATE_FIXED_TYPE_FROM_BLOCK): Remove.         * alloc.c (ALLOCATE_FIXED_TYPE_1): Remove.         * alloc.c (ALLOCATE_FIXED_TYPE): Remove.         * alloc.c (NOSEEUM_ALLOCATE_FIXED_TYPE): Remove.         * alloc.c (struct Lisp_Free): Remove.         * alloc.c (LRECORD_FREE_P): Remove.         * alloc.c (MARK_LRECORD_AS_FREE): Remove.         * alloc.c (MARK_LRECORD_AS_NOT_FREE): Remove.         * alloc.c (PUT_FIXED_TYPE_ON_FREE_LIST): Remove.         * alloc.c (FREE_FIXED_TYPE): Remove.         * alloc.c (FREE_FIXED_TYPE_WHEN_NOT_IN_GC): Remove.         Allocate old lrecords with new allocator:                  * alloc.c: DECLARE_FIXED_TYPE_ALLOC removed for all lrecords         defined in alloc.c.         * alloc.c (Fcons): Allocate with new allocator.         * alloc.c (noseeum_cons): Allocate with new allocator.         * alloc.c (make_float): Allocate with new allocator.         * alloc.c (make_bignum): Allocate with new allocator.         * alloc.c (make_bignum_bg): Allocate with new allocator.         * alloc.c (make_ratio): Allocate with new allocator.         * alloc.c (make_ratio_bg): Allocate with new allocator.         * alloc.c (make_ratio_rt): Allocate with new allocator.         * alloc.c (make_bigfloat): Allocate with new allocator.         * alloc.c (make_bigfloat_bf): Allocate with new allocator.         * alloc.c (make_compiled_function): Allocate with new allocator.         * alloc.c (Fmake_symbol): Allocate with new allocator.         * alloc.c (allocate_extent): Allocate with new allocator.         * alloc.c (allocate_event): Allocate with new allocator.         * alloc.c (make_key_data): Allocate with new allocator.         * alloc.c (make_button_data): Allocate with new allocator.         * alloc.c (make_motion_data): Allocate with new allocator.         * alloc.c (make_process_data): Allocate with new allocator.         * alloc.c (make_timeout_data): Allocate with new allocator.         * alloc.c (make_magic_data): Allocate with new allocator.         * alloc.c (make_magic_eval_data): Allocate with new allocator.         * alloc.c (make_eval_data): Allocate with new allocator.         * alloc.c (make_misc_user_data): Allocate with new allocator.         * alloc.c (Fmake_marker): Allocate with new allocator.         * alloc.c (noseeum_make_marker): Allocate with new allocator.         * alloc.c (make_uninit_string): Allocate with new allocator.         * alloc.c (resize_string): Allocate with new allocator.         * alloc.c (make_string_nocopy): Allocate with new allocator.         Garbage Collection:         * alloc.c (GC_CHECK_NOT_FREE): Remove obsolete assertions.         * alloc.c (SWEEP_FIXED_TYPE_BLOCK): Remove.         * alloc.c (SWEEP_FIXED_TYPE_BLOCK_1): Remove.         * alloc.c (sweep_conses): Remove.         * alloc.c (free_cons): Use new allocator to free.         * alloc.c (sweep_compiled_functions): Remove.         * alloc.c (sweep_floats): Remove.         * alloc.c (sweep_bignums): Remove.         * alloc.c (sweep_ratios): Remove.         * alloc.c (sweep_bigfloats): Remove.         * alloc.c (sweep_symbols): Remove.         * alloc.c (sweep_extents): Remove.         * alloc.c (sweep_events): Remove.         * alloc.c (sweep_key_data): Remove.         * alloc.c (free_key_data): Use new allocator to free.         * alloc.c (sweep_button_data): Remove.         * alloc.c (free_button_data): Use new allocator to free.         * alloc.c (sweep_motion_data): Remove.         * alloc.c (free_motion_data): Use new allocator to free.         * alloc.c (sweep_process_data): Remove.         * alloc.c (free_process_data): Use new allocator to free.         * alloc.c (sweep_timeout_data): Remove.         * alloc.c (free_timeout_data): Use new allocator to free.         * alloc.c (sweep_magic_data): Remove.         * alloc.c (free_magic_data): Use new allocator to free.         * alloc.c (sweep_magic_eval_data): Remove.         * alloc.c (free_magic_eval_data): Use new allocator to free.         * alloc.c (sweep_eval_data): Remove.         * alloc.c (free_eval_data): Use new allocator to free.         * alloc.c (sweep_misc_user_data): Remove.         * alloc.c (free_misc_user_data): Use new allocator to free.         * alloc.c (sweep_markers): Remove.         * alloc.c (free_marker): Use new allocator to free.         * alloc.c (garbage_collect_1): Remove release_breathing_space.         * alloc.c (gc_sweep): Remove all the old lcrecord and lrecord         related stuff. Sweeping now works like this: compact string         chars, finalize, sweep.         * alloc.c (common_init_alloc_early): Remove old lrecord         initializations, remove breathing_space.         * emacs.c (Fdump_emacs): Remove release_breathing_space.         * lisp.h: Remove prototype for release_breathing_space.         * lisp.h: Adjust the special cons mark makros.         Lrecord Finalizer:         * alloc.c: Add finalizer to lrecord definition.         * alloc.c (finalize_string): Add finalizer for string.         * bytecode.c: Add finalizer to lrecord definition.         * bytecode.c (finalize_compiled_function): Add finalizer for         compiled function.         * marker.c: Add finalizer to lrecord definition.         * marker.c (finalize_marker): Add finalizer for marker.         These changes build the interface to mc-alloc:         * lrecord.h (MC_ALLOC_CALL_FINALIZER): Tell mc-alloc how to         finalize lrecords.         * lrecord.h (MC_ALLOC_CALL_FINALIZER_FOR_DISKSAVE): Tell         mc-alloc how to finalize for disksave.         Unify lrecords and lcrecords:         * lisp.h (struct Lisp_String): Adjust string union hack to         new lrecord header.         * lrecord.h: Adjust comments.         * lrecord.h (struct lrecord_header): The new lrecord header         includes type, lisp-readonly, free, and uid.         * lrecord.h (set_lheader_implementation): Adjust to new         lrecord_header.         * lrecord.h (struct lrecord_implementation): The field basic_p         for indication of an old lrecord is not needed anymore, remove.         * lrecord.h (MAKE_LRECORD_IMPLEMENTATION): Remove basic_p.         * lrecord.h (MAKE_EXTERNAL_LRECORD_IMPLEMENTATION): Remove         basic_p.         * lrecord.h (copy_sized_lrecord): Remove distinction between         old lrecords and lcrecords.         * lrecord.h (copy_lrecord): Remove distinction between old         lrecords and lcrecords.         * lrecord.h (zero_sized_lrecord): Remove distinction between         old lrecords and lcrecords.         * lrecord.h (zero_lrecord): Remove distinction between old         lrecords and lcrecords.         Remove lcrecords and lcrecord lists:         * alloc.c (basic_alloc_lcrecord): Not needed anymore, remove.         * alloc.c (very_old_free_lcrecord): Not needed anymore, remove.         * alloc.c (copy_lisp_object): No more distinction between         lrecords and lcrecords.         * alloc.c (all_lcrecords): Not needed anymore, remove.         * alloc.c (make_vector_internal): Allocate as lrecord.         * alloc.c (make_bit_vector_internal): Allocate as lrecord.         * alloc.c: Completely remove `lcrecord lists'.         * alloc.c (free_description): Remove.         * alloc.c (lcrecord_list_description): Remove.         * alloc.c (mark_lcrecord_list): Remove.         * alloc.c (make_lcrecord_list): Remove.         * alloc.c (alloc_managed_lcrecord): Remove.         * alloc.c (free_managed_lcrecord): Remove.         * alloc.c (alloc_automanaged_lcrecord): Remove.         * alloc.c (free_lcrecord): Remove.         * alloc.c (lcrecord_stats): Remove.         * alloc.c (tick_lcrecord_stats): Remove.         * alloc.c (disksave_object_finalization_1): Add call to         mc_finalize_for_disksave. Remove the lcrecord way to visit all         objects.         * alloc.c (kkcc_marking): Remove XD_FLAG_FREE_LISP_OBJECT         * alloc.c (sweep_lcrecords_1): Remove.         * alloc.c (common_init_alloc_early): Remove everything related         to lcrecords, remove old lrecord initializations,         * alloc.c (init_lcrecord_lists): Not needed anymore, remove.         * alloc.c (reinit_alloc_early): Remove everything related to         lcrecords.         * alloc.c (init_alloc_once_early): Remove everything related to         lcrecords.         * buffer.c (allocate_buffer): Allocate as lrecord.         * buffer.c (nuke_all_buffer_slots): Use lrecord functions.         * buffer.c (common_init_complex_vars_of_buffer): Allocate as         lrecord.         * buffer.h (struct buffer): Add lrecord_header.         * casetab.c (allocate_case_table): Allocate as lrecord.         * casetab.h (struct Lisp_Case_Table): Add lrecord_header.         * charset.h (struct Lisp_Charset): Add lrecord_header.         * chartab.c (fill_char_table): Use lrecord functions.         * chartab.c (Fmake_char_table): Allocate as lrecord.         * chartab.c (make_char_table_entry): Allocate as lrecord.         * chartab.c (copy_char_table_entry): Allocate as lrecord.         * chartab.c (Fcopy_char_table): Allocate as lrecord.         * chartab.c (put_char_table): Use lrecord functions.         * chartab.h (struct Lisp_Char_Table_Entry): Add lrecord_header.         * chartab.h (struct Lisp_Char_Table): Add lrecord_header.         * console-impl.h (struct console): Add lrecord_header.         * console-msw-impl.h (struct Lisp_Devmode): Add lrecord_header.         * console-msw-impl.h (struct mswindows_dialog_id): Add         lrecord_header.         * console.c (allocate_console): Allocate as lrecord.         * console.c (nuke_all_console_slots): Use lrecord functions.         * console.c (common_init_complex_vars_of_console): Allocate as         lrecord.         * data.c (make_weak_list): Allocate as lrecord.         * data.c (make_weak_box): Allocate as lrecord.         * data.c (make_ephemeron): Allocate as lrecord.         * database.c (struct Lisp_Database): Add lrecord_header.         * database.c (allocate_database): Allocate as lrecord.         * device-impl.h (struct device): Add lrecord_header.         * device-msw.c (allocate_devmode): Allocate as lrecord.         * device.c (nuke_all_device_slots): Use lrecord functions.         * device.c (allocate_device): Allocate as lrecord.         * dialog-msw.c (handle_question_dialog_box): Allocate as lrecord.         * elhash.c (struct Lisp_Hash_Table): Add lrecord_header.         * elhash.c (make_general_lisp_hash_table): Allocate as lrecord.         * elhash.c (Fcopy_hash_table): Allocate as lrecord.         * event-stream.c: Lcrecord lists Vcommand_builder_free_list and         Vtimeout_free_list are no longer needed. Remove.         * event-stream.c (allocate_command_builder): Allocate as lrecord.         * event-stream.c (free_command_builder): Use lrecord functions.         * event-stream.c (event_stream_generate_wakeup): Allocate as         lrecord.         * event-stream.c (event_stream_resignal_wakeup): Use lrecord         functions.         * event-stream.c (event_stream_disable_wakeup): Use lrecord         functions.         * event-stream.c (reinit_vars_of_event_stream): Lcrecord lists         remove.         * events.h (struct Lisp_Timeout): Add lrecord_header.         * events.h (struct command_builder): Add lrecord_header.         * extents-impl.h (struct extent_auxiliary): Add lrecord_header.         * extents-impl.h (struct extent_info): Add lrecord_header.         * extents.c (allocate_extent_auxiliary): Allocate as lrecord.         * extents.c (allocate_extent_info): Allocate as lrecord.         * extents.c (copy_extent): Allocate as lrecord.         * faces.c (allocate_face): Allocate as lrecord.         * faces.h (struct Lisp_Face): Add lrecord_header.         * file-coding.c (allocate_coding_system): Allocate as lrecord.         * file-coding.c (Fcopy_coding_system): Allocate as lrecord.         * file-coding.h (struct Lisp_Coding_System): Add lrecord_header.         * fns.c (Ffillarray): Allocate as lrecord.         * frame-impl.h (struct frame): Add lrecord_header.         * frame.c (nuke_all_frame_slots): Use lrecord functions.         * frame.c (allocate_frame_core): Allocate as lrecord.         * glyphs.c (allocate_image_instance): Allocate as lrecord.         * glyphs.c (Fcolorize_image_instance): Allocate as lrecord.         * glyphs.c (allocate_glyph): Allocate as lrecord.         * glyphs.h (struct Lisp_Image_Instance): Add lrecord_header.         * glyphs.h (struct Lisp_Glyph): Add lrecord_header.         * gui.c (allocate_gui_item): Allocate as lrecord.         * gui.h (struct Lisp_Gui_Item): Add lrecord_header.         * keymap.c (struct Lisp_Keymap): Add lrecord_header.         * keymap.c (make_keymap): Allocate as lrecord.         * lisp.h (struct Lisp_Vector): Add lrecord_header.         * lisp.h (struct Lisp_Bit_Vector): Add lrecord_header.         * lisp.h (struct weak_box): Add lrecord_header.         * lisp.h (struct ephemeron): Add lrecord_header.         * lisp.h (struct weak_list): Add lrecord_header.         * lrecord.h (struct lcrecord_header): Not used, remove.         * lrecord.h (struct free_lcrecord_header): Not used, remove.         * lrecord.h (struct lcrecord_list): Not needed anymore, remove.         * lrecord.h (lcrecord_list): Not needed anymore, remove.         * lrecord.h: (enum data_description_entry_flags): Remove         XD_FLAG_FREE_LISP_OBJECT.         * lstream.c: Lrecord list Vlstream_free_list remove.         * lstream.c (Lstream_new): Allocate as lrecord.         * lstream.c (Lstream_delete): Use lrecod functions.         * lstream.c (reinit_vars_of_lstream): Vlstream_free_list         initialization remove.           * lstream.h (struct lstream): Add lrecord_header.         * emacs.c (main_1): Remove lstream initialization.         * mule-charset.c (make_charset): Allocate as lrecord.         * objects-impl.h (struct Lisp_Color_Instance): Add         lrecord_header.         * objects-impl.h (struct Lisp_Font_Instance): Add lrecord_header.         * objects.c (Fmake_color_instance): Allocate as lrecord.         * objects.c (Fmake_font_instance): Allocate as lrecord.         * objects.c (reinit_vars_of_objects): Allocate as lrecord.         * opaque.c: Lcreord list Vopaque_ptr_list remove.         * opaque.c (make_opaque): Allocate as lrecord.         * opaque.c (make_opaque_ptr): Allocate as lrecord.         * opaque.c (free_opaque_ptr): Use lrecord functions.         * opaque.c (reinit_opaque_early):         * opaque.c (init_opaque_once_early): Vopaque_ptr_list         initialization remove.         * opaque.h (Lisp_Opaque): Add lrecord_header.         * opaque.h (Lisp_Opaque_Ptr): Add lrecord_header.         * emacs.c (main_1): Remove opaque variable initialization.         * print.c (default_object_printer): Use new lrecord_header.         * print.c (print_internal): Use new lrecord_header.         * print.c (debug_p4): Use new lrecord_header.         * process.c (make_process_internal): Allocate as lrecord.         * procimpl.h (struct Lisp_Process): Add lrecord_header.         * rangetab.c (Fmake_range_table): Allocate as lrecord.         * rangetab.c (Fcopy_range_table): Allocate as lrecord.         * rangetab.h (struct Lisp_Range_Table): Add lrecord_header.         * scrollbar.c (create_scrollbar_instance): Allocate as lrecord.         * scrollbar.h (struct scrollbar_instance): Add lrecord_header.         * specifier.c (make_specifier_internal): Allocate as lrecord.         * specifier.h (struct Lisp_Specifier): Add lrecord_header.         * symbols.c:         * symbols.c (Fmake_variable_buffer_local): Allocate as lrecord.         * symbols.c (Fdontusethis_set_symbol_value_handler): Allocate         as lrecord.         * symbols.c (Fdefvaralias): Allocate as lrecord.         * symeval.h (struct symbol_value_magic): Add lrecord_header.         * toolbar.c (update_toolbar_button): Allocate as lrecord.         * toolbar.h (struct toolbar_button): Add lrecord_header.         * tooltalk.c (struct Lisp_Tooltalk_Message): Add lrecord_header.         * tooltalk.c (make_tooltalk_message): Allocate as lrecord.         * tooltalk.c (struct Lisp_Tooltalk_Pattern): Add lrecord_header.         * tooltalk.c (make_tooltalk_pattern): Allocate as lrecord.         * ui-gtk.c (allocate_ffi_data): Allocate as lrecord.         * ui-gtk.c (allocate_emacs_gtk_object_data): Allocate as lrecord.         * ui-gtk.c (allocate_emacs_gtk_boxed_data): Allocate as lrecord.         * ui-gtk.h (structs): Add lrecord_header.         * window-impl.h (struct window): Add lrecord_header.         * window-impl.h (struct window_mirror): Add lrecord_header.         * window.c (allocate_window): Allocate as lrecord.         * window.c (new_window_mirror): Allocate as lrecord.         * window.c (make_dummy_parent): Allocate as lrecord.         MEMORY_USAGE_STATS         * alloc.c (fixed_type_block_overhead): Not used anymore, remove.         * buffer.c (compute_buffer_usage): Get storage size from new         allocator.         * marker.c (compute_buffer_marker_usage): Get storage size from         new allocator.         * mule-charset.c (compute_charset_usage): Get storage size from         new allocator.         * scrollbar-gtk.c (gtk_compute_scrollbar_instance_usage): Get         storage size from new allocator.         * scrollbar-msw.c (mswindows_compute_scrollbar_instance_usage):         Get storage size from new allocator.         * scrollbar-x.c (x_compute_scrollbar_instance_usage): Get         storage size from new allocator.         * scrollbar.c (compute_scrollbar_instance_usage): Get storage         size from new allocator.         * unicode.c (compute_from_unicode_table_size_1): Get storage         size from new allocator.         * unicode.c (compute_to_unicode_table_size_1): Get storage size         from new allocator.         * window.c (compute_window_mirror_usage): Get storage size from         new allocator.         * window.c (compute_window_usage): Get storage size from new         allocator.         MC_ALLOC_TYPE_STATS:         * alloc.c (alloc_lrecord): Bump lrecord count.         * alloc.c (noseeum_alloc_lrecord): Bump lrecord count.         * alloc.c (struct lrecord_stats): Storage for counts.         * alloc.c (init_lrecord_stats): Zero statistics.         * alloc.c (inc_lrecord_stats): Increase the statistic.         * alloc.c (dec_lrecord_stats): Decrease the statistic.         * alloc.c (gc_plist_hack): Used to print the information.         * alloc.c (Fgarbage_collect): Return the collected information.         * mc-alloc.c (remove_cell): Decrease lrecord count.         * mc-alloc.h: Set flag MC_ALLOC_TYPE_STATS.         * emacs.c (main_1): Init lrecord statistics.         * lrecord.h: Add prototypes for *_lrecord_stats.         Strings:         * alloc.c (Fmake_string): Initialize ascii_begin to zero.         * alloc.c (gc_count_num_short_string_in_use): Remove.         * alloc.c (gc_count_string_total_size): Remove.         * alloc.c (gc_count_short_string_total_size): Remove.         * alloc.c (debug_string_purity): Remove.         * alloc.c (debug_string_purity_print): Remove.         * alloc.c (sweep_strings): Remove.                  Remove static C-readonly Lisp objects:         * alloc.c (c_readonly): Not needed anymore, remove.         * alloc.c (GC_CHECK_LHEADER_INVARIANTS): Remove some obsolete         lheader invariants assertions.         * buffer.c (DEFVAR_BUFFER_LOCAL_1): Allocate dynamically.         * console.c (DEFVAR_CONSOLE_LOCAL_1): Allocate dynamically.         * gpmevent.c: Indirection via MC_ALLOC_Freceive_gpm_event.         * gpmevent.c (Fgpm_enable): Allocate dynamically.         * gpmevent.c (syms_of_gpmevent): Allocate dynamically.         * lisp.h (C_READONLY): Not needed anymore, remove.         * lisp.h (DEFUN): Allocate dynamically.         * lrecord.h (C_READONLY_RECORD_HEADER_P): Not needed anymore,         remove.         * lrecord.h (SET_C_READONLY_RECORD_HEADER): Not needed anymore,         remove.         * symbols.c (guts_of_unbound_marker):         * symeval.h (defsubr): Allocate dynamically.         * symeval.h (DEFSUBR_MACRO): Allocate dynamically.         * symeval.h (DEFVAR_ SYMVAL_FWD): Allocate dynamically.         * tests.c (TESTS_DEFSUBR): Allocate dynamically.         Definition of mcpro:         * lisp.h: Add mcpro prototypes.         * alloc.c (common_init_alloc_early): Add initialization for         mcpros.         * alloc.c (mcpro_description_1): New.         * alloc.c (mcpro_description): New.         * alloc.c (mcpros_description_1): New.         * alloc.c (mcpros_description): New.         * alloc.c (mcpro_one_name_description_1): New.         * alloc.c (mcpro_one_name_description): New.         * alloc.c (mcpro_names_description_1): New.         * alloc.c (mcpro_names_description): New.         * alloc.c (mcpros): New.         * alloc.c (mcpro_names): New.         * alloc.c (mcpro_1): New.         * alloc.c (mc_pro): New.         * alloc.c (garbage_collect_1): Add mcpros to root set.         Usage of mcpro:         * alloc.c (make_string_nocopy): Add string to root set.         * symbols.c (init_symbols_once_early): Add Qunbound to root set.         Changes to the Portable Dumper:                  * alloc.c (FREE_OR_REALLOC_BEGIN): Since dumped objects can be         freed with the new allocator, remove assertion for !DUMPEDP.         * dumper.c: Adjust comments, increase PDUMP_HASHSIZE.         * dumper.c (pdump_make_hash): Shift address only 2 bytes, to         avoid collisions.         * dumper.c (pdump_objects_unmark): No more mark bits within         the object, remove.         * dumper.c (mc_addr_elt): New. Element data structure for mc         hash table.         * dumper.c (pdump_mc_hash): New hash table: `lookup table'.         * dumper.c (pdump_get_mc_addr): New. Lookup for hash table.         * dumper.c (pdump_get_indirect_mc_addr): New. Lookup for         convertibles.         * dumper.c (pdump_put_mc_addr): New. Putter for hash table.         * dumper.c (pdump_dump_mc_data): New. Writes the table for         relocation at load time to the dump file.         * dumper.c (pdump_scan_lisp_objects_by_alignment): New.         Visits all dumped Lisp objects.         * dumper.c (pdump_scan_non_lisp_objects_by_alignment): New.         Visits all other dumped objects.         * dumper.c (pdump_reloc_one_mc): New. Updates all pointers         of an object by using the hash table pdump_mc_hash.         * dumper.c (pdump_reloc_one): Replaced by pdump_reloc_one_mc.         * dumper.c (pdump): Change the structure of the dump file, add         the mc post dump relocation table to dump file.         * dumper.c (pdump_load_finish): Hand all dumped objects to the         new allocator and use the mc post dump relocation table for         relocating the dumped objects at dump file load time, free not         longer used data structures.         * dumper.c (pdump_load): Free the dump file.         * dumper.h: Remove pdump_objects_unmark.         * lrecord.h (DUMPEDP): Dumped objects can be freed, remove.              DUMP_IN_EXEC:         * Makefile.in.in: Linking for and with dump in executable only if         DUMP_IN_EXEC is defined.         * config.h.in: Add new flag `DUMP_IN_EXEC'         * emacs.c: Condition dump-data.h on DUMP_IN_EXEC.         * emacs.c (main_1): Flag `-si' only works if dump image is         written into executable.         Miscellanious         * lrecord.h (enum lrecord_type): Added numbers to all types,         very handy for debugging.         * xemacs.def.in.in: Add mc-alloc functions to make them visible         to the modules.
author crestani
date Fri, 08 Apr 2005 23:11:35 +0000
parents ecf1ebac70d8
children 44c9d1005ce2
line wrap: on
line source

/* Minibuffer input and completion.
   Copyright (C) 1985, 1986, 1992-1995 Free Software Foundation, Inc.
   Copyright (C) 1995 Sun Microsystems, Inc.
   Copyright (C) 2002 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.  */

/* Synched up with: Mule 2.0, FSF 19.28.  Mule-ized except as noted.
   Substantially different from FSF. */

/* #### dmoore - All sorts of things in here can call lisp, like message.
   Track all this stuff. */

#include <config.h>
#include "lisp.h"

#include "buffer.h"
#include "commands.h"
#include "console-stream.h"
#include "events.h"
#include "frame-impl.h"
#include "insdel.h"
#include "redisplay.h"
#include "window-impl.h"

/* Depth in minibuffer invocations.  */
int minibuf_level;

Lisp_Object Qcompletion_ignore_case;

/* Nonzero means completion ignores case.  */
int completion_ignore_case;

/* List of regexps that should restrict possible completions.  */
Lisp_Object Vcompletion_regexp_list;

/* The echo area buffer. */
Lisp_Object Vecho_area_buffer;

/* Prompt to display in front of the minibuffer contents */
Lisp_Object Vminibuf_prompt;

/* Added on 97/3/14 by Jareth Hein (jhod@po.iijnet.or.jp) for input system support */
/* String to be displayed in front of prompt of the minibuffer contents */
Lisp_Object Vminibuf_preprompt;

/* Hook to run just after entry to minibuffer. */
Lisp_Object Qminibuffer_setup_hook, Vminibuffer_setup_hook;

Lisp_Object Qappend_message, Qcurrent_message_label,
            Qclear_message, Qdisplay_message;


DEFUN ("minibuffer-depth", Fminibuffer_depth, 0, 0, 0, /*
Return current depth of activations of minibuffer, a nonnegative integer.
*/
       ())
{
  return make_int (minibuf_level);
}

/* The default buffer to use as the window-buffer of minibuffer windows */
/*  Note there is special code in kill-buffer to make this unkillable */
Lisp_Object Vminibuffer_zero;


/* Actual minibuffer invocation. */

static Lisp_Object
read_minibuffer_internal_unwind (Lisp_Object unwind_data)
{
  Lisp_Object frame;
  XWINDOW (minibuf_window)->last_modified[CURRENT_DISP] = Qzero;
  XWINDOW (minibuf_window)->last_modified[DESIRED_DISP] = Qzero;
  XWINDOW (minibuf_window)->last_modified[CMOTION_DISP] = Qzero;
  XWINDOW (minibuf_window)->last_facechange[CURRENT_DISP] = Qzero;
  XWINDOW (minibuf_window)->last_facechange[DESIRED_DISP] = Qzero;
  XWINDOW (minibuf_window)->last_facechange[CMOTION_DISP] = Qzero;
  Vminibuf_prompt = Felt (unwind_data, Qzero);
  minibuf_level = XINT (Felt (unwind_data, make_int (1)));
  while (CONSP (unwind_data))
    {
      Lisp_Object victim = unwind_data;
      unwind_data = XCDR (unwind_data);
      free_cons (victim);
    }

  /* If cursor is on the minibuffer line,
     show the user we have exited by putting it in column 0.  */
  frame = Fselected_frame (Qnil);
  if (!noninteractive
      && !NILP (frame)
      && !NILP (XFRAME (frame)->minibuffer_window))
    {
      struct window *w = XWINDOW (XFRAME (frame)->minibuffer_window);
      redisplay_move_cursor (w, 0, 0);
    }

  return Qnil;
}

/* 97/4/13 jhod: Added for input methods */
DEFUN ("set-minibuffer-preprompt", Fset_minibuffer_preprompt, 1, 1, 0, /*
Set the minibuffer preprompt string to PREPROMPT. This is used by language
input methods to relay state information to the user.
*/
       (preprompt))
{
  if (NILP (preprompt))
    {
      Vminibuf_preprompt = Qnil;
    }
  else
    {
      CHECK_STRING (preprompt);

      Vminibuf_preprompt = LISP_GETTEXT (preprompt);
    }
  return Qnil;
}

DEFUN_NORETURN ("read-minibuffer-internal", Fread_minibuffer_internal,
		1, 1, 0, /*
Lowest-level interface to minibuffers.  Don't call this.
*/
       (prompt))
{
  /* This function can GC */

  /* We used to record the specpdl_depth here, but since call_command_loop
     never returns, we can never call unbind_to_1.  Since we exit via a throw,
     we let whoever catches unbind for us. */

  CHECK_STRING (prompt);

  single_console_state ();

  record_unwind_protect (read_minibuffer_internal_unwind,
                         noseeum_cons
			 (Vminibuf_prompt,
			  noseeum_cons (make_int (minibuf_level), Qnil)));
  Vminibuf_prompt = LISP_GETTEXT (prompt);

  /* NOTE: Here (or somewhere around here), in FSFmacs 19.30,
     choose_minibuf_frame() is called.  This is the only
     place in FSFmacs that it's called any more -- there's
     also a call in xterm.c, but commented out, and 19.28
     had the calls in different places.

     choose_minibuf_frame() does the following:

  if (!EQ (minibuf_window, selected_frame()->minibuffer_window))
    {
      Fset_window_buffer (selected_frame()->minibuffer_window,
			  XWINDOW (minibuf_window)->buffer);
      minibuf_window = selected_frame()->minibuffer_window;
    }

  #### Note that we don't do the set-window-buffer.  This call is
  similar, but not identical, to a set-window-buffer call made
  in `read-from-minibuffer' in minibuf.el.  I hope it's close
  enough, because minibuf_window isn't really exported to Lisp.

  The comment above choose_minibuf_frame() reads:

  Put minibuf on currently selected frame's minibuffer.
  We do this whenever the user starts a new minibuffer
  or when a minibuffer exits.  */

  minibuf_window = FRAME_MINIBUF_WINDOW (selected_frame ());

  run_hook (Qminibuffer_setup_hook);

  minibuf_level++;
  clear_echo_area (selected_frame (), Qnil, 0);

  call_command_loop (Qt);

  RETURN_NOT_REACHED (Qnil);
}



/* Completion hair */

/* Compare exactly LEN chars of strings at S1 and S2,
   ignoring case if appropriate.
   Return -1 if strings match,
   else number of chars that match at the beginning.  */

/* Note that this function works in Charcounts, unlike most functions.
   This is necessary for many reasons, one of which is that two
   strings may match even if they have different numbers of bytes,
   if IGNORE_CASE is true. */

Charcount
scmp_1 (const Ibyte *s1, const Ibyte *s2, Charcount len,
	int ignore_case)
{
  Charcount l = len;

  if (ignore_case)
    {
      while (l)
        {
          Ichar c1 = DOWNCASE (0, itext_ichar (s1));
          Ichar c2 = DOWNCASE (0, itext_ichar (s2));

          if (c1 == c2)
            {
              l--;
              INC_IBYTEPTR (s1);
              INC_IBYTEPTR (s2);
            }
          else
            break;
        }
    }
  else
    {
      while (l && itext_ichar (s1) == itext_ichar (s2))
	{
	  l--;
	  INC_IBYTEPTR (s1);
	  INC_IBYTEPTR (s2);
	}
    }

  if (l == 0)
    return -1;
  else return len - l;
}


int
regexp_ignore_completion_p (const Ibyte *nonreloc,
			    Lisp_Object reloc, Bytecount offset,
			    Bytecount length)
{
  /* Ignore this element if it fails to match all the regexps.  */
  if (!NILP (Vcompletion_regexp_list))
    {
      EXTERNAL_LIST_LOOP_2 (re, Vcompletion_regexp_list)
	{
	  CHECK_STRING (re);
	  if (fast_string_match (re, nonreloc, reloc, offset,
				 length, 0, ERROR_ME, 0) < 0)
	    return 1;
	}
    }
  return 0;
}


/* Callers should GCPRO, since this may call eval */
static int
ignore_completion_p (Lisp_Object completion_string,
                     Lisp_Object pred, Lisp_Object completion)
{
  if (regexp_ignore_completion_p (0, completion_string, 0, -1))
    return 1;

  /* Ignore this element if there is a predicate
     and the predicate doesn't like it. */
  if (!NILP (pred))
  {
    Lisp_Object tem;
    if (EQ (pred, Qcommandp))
      tem = Fcommandp (completion);
    else
      tem = call1 (pred, completion);
    if (NILP (tem))
      return 1;
  }
  return 0;
}


/* #### Maybe we should allow COLLECTION to be a hash table.
   It is wrong for the use of obarrays to be better-rewarded than the
   use of hash tables.  By better-rewarded I mean that you can pass an
   obarray to all of the completion functions, whereas you can't do
   anything like that with a hash table.

   To do so, there should probably be a
   map_obarray_or_alist_or_hash_table function which would be used by
   both Ftry_completion and Fall_completions.  [[ But would the
   additional funcalls slow things down? ]] Seriously doubtful. --ben */

DEFUN ("try-completion", Ftry_completion, 2, 3, 0, /*
Return common substring of all completions of STRING in COLLECTION.
COLLECTION must be an alist, an obarray, or a function.
Each string in COLLECTION is tested to see if it begins with STRING.
All that match are compared together; the longest initial sequence
common to all matches is returned as a string.  If there is no match
at all, nil is returned.  For an exact match, t is returned.

If COLLECTION is an alist, the cars of the elements of the alist
\(which must be strings) form the set of possible completions.

If COLLECTION is an obarray, the names of all symbols in the obarray
are the possible completions.

If COLLECTION is a function, it is called with three arguments: the
values STRING, PREDICATE and nil.  Whatever it returns becomes the
value of `try-completion'.

If optional third argument PREDICATE is non-nil, it is used to test
each possible match.  The match is a candidate only if PREDICATE
returns non-nil.  The argument given to PREDICATE is the alist element
or the symbol from the obarray.
*/
       (string, collection, predicate))
{
  /* This function can GC */
  Lisp_Object bestmatch, tail;
  Charcount bestmatchsize = 0;
  int list;
  int indice = 0;
  int matchcount = 0;
  int obsize;
  Lisp_Object bucket;
  Charcount slength, blength;

  CHECK_STRING (string);

  if (CONSP (collection))
    {
      Lisp_Object tem = XCAR (collection);
      if (SYMBOLP (tem))	/* lambda, autoload, etc.  Emacs-lisp sucks */
	return call3 (collection, string, predicate, Qnil);
      else
	list = 1;
    }
  else if (VECTORP (collection))
    list = 0;
  else if (NILP (collection))
    list = 1;
  else
    return call3 (collection, string, predicate, Qnil);

  bestmatch = Qnil;
  blength = 0;
  slength = string_char_length (string);

  /* If COLLECTION is not a list, set TAIL just for gc pro.  */
  tail = collection;
  if (!list)
    {
      obsize = XVECTOR_LENGTH (collection);
      bucket = XVECTOR_DATA (collection)[indice];
    }
  else /* warning suppression */
    {
      obsize = 0;
      bucket = Qnil;
    }

  while (1)
    {
      /* Get the next element of the alist or obarray. */
      /* Exit the loop if the elements are all used up. */
      /* elt gets the alist element or symbol.
	 eltstring gets the name to check as a completion. */
      Lisp_Object elt;
      Lisp_Object eltstring;

      if (list)
	{
	  if (NILP (tail))
	    break;
	  elt = Fcar (tail);
	  eltstring = Fcar (elt);
	  tail = Fcdr (tail);
	}
      else
	{
	  if (!ZEROP (bucket))
	    {
              Lisp_Symbol *next;
	      if (!SYMBOLP (bucket))
		{
		  invalid_argument ("Bad obarray passed to try-completions",
				    bucket);
		}
	      next = symbol_next (XSYMBOL (bucket));
	      elt = bucket;
	      eltstring = Fsymbol_name (elt);
              if (next)
		bucket = wrap_symbol (next);
	      else
		bucket = Qzero;
	    }
	  else if (++indice >= obsize)
	    break;
	  else
	    {
	      bucket = XVECTOR_DATA (collection)[indice];
	      continue;
	    }
	}

      /* Is this element a possible completion? */

      if (STRINGP (eltstring))
	{
	  Charcount eltlength = string_char_length (eltstring);
	  if (slength <= eltlength
	      && (0 > scmp (XSTRING_DATA (eltstring),
                            XSTRING_DATA (string),
                            slength)))
	    {
              {
                struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
                int loser;
                GCPRO4 (tail, string, eltstring, bestmatch);
                loser = ignore_completion_p (eltstring, predicate, elt);
                UNGCPRO;
                if (loser)      /* reject this one */
                  continue;
              }

	      /* Update computation of how much all possible
		 completions match */

	      matchcount++;
	      if (NILP (bestmatch))
		{
		  bestmatch = eltstring;
                  blength = eltlength;
		  bestmatchsize = eltlength;
		}
	      else
		{
		  Charcount compare = min (bestmatchsize, eltlength);
		  Charcount matchsize =
		    scmp (XSTRING_DATA (bestmatch),
			  XSTRING_DATA (eltstring),
			  compare);
		  if (matchsize < 0)
		    matchsize = compare;
		  if (completion_ignore_case)
		    {
		      /* If this is an exact match except for case,
			 use it as the best match rather than one that is not
			 an exact match.  This way, we get the case pattern
			 of the actual match.  */
		      if ((matchsize == eltlength
			   && matchsize < blength)
			  ||
			  /* If there is more than one exact match ignoring
			     case, and one of them is exact including case,
			     prefer that one.  */
			  /* If there is no exact match ignoring case,
			     prefer a match that does not change the case
			     of the input.  */
			  ((matchsize == eltlength)
			   ==
			   (matchsize == blength)
			   && 0 > scmp_1 (XSTRING_DATA (eltstring),
					  XSTRING_DATA (string),
					  slength, 0)
			   && 0 <= scmp_1 (XSTRING_DATA (bestmatch),
					   XSTRING_DATA (string),
					   slength, 0)))
                      {
			bestmatch = eltstring;
                        blength = eltlength;
                      }
		    }
		  bestmatchsize = matchsize;
		}
	    }
	}
    }

  if (NILP (bestmatch))
    return Qnil;		/* No completions found */
  /* If we are ignoring case, and there is no exact match,
     and no additional text was supplied,
     don't change the case of what the user typed.  */
  if (completion_ignore_case
      && bestmatchsize == slength
      && blength > bestmatchsize)
    return string;

  /* Return t if the supplied string is an exact match (counting case);
     it does not require any change to be made.  */
  if (matchcount == 1
      && bestmatchsize == slength
      && 0 > scmp_1 (XSTRING_DATA (bestmatch),
		     XSTRING_DATA (string),
		     bestmatchsize, 0))
    return Qt;

  /* Else extract the part in which all completions agree */
  return Fsubstring (bestmatch, Qzero, make_int (bestmatchsize));
}


DEFUN ("all-completions", Fall_completions, 2, 3, 0, /*
Search for partial matches to STRING in COLLECTION.
COLLECTION must be an alist, an obarray, or a function.
Each string in COLLECTION is tested to see if it begins with STRING.
The value is a list of all the strings from COLLECTION that match.

If COLLECTION is an alist, the cars of the elements of the alist
\(which must be strings) form the set of possible completions.

If COLLECTION is an obarray, the names of all symbols in the obarray
are the possible completions.

If COLLECTION is a function, it is called with three arguments: the
values STRING, PREDICATE and t.  Whatever it returns becomes the
value of `all-completions'.

If optional third argument PREDICATE is non-nil, it is used to test
each possible match.  The match is a candidate only if PREDICATE
returns non-nil.  The argument given to PREDICATE is the alist element
or the symbol from the obarray.
*/
       (string, collection, predicate))
{
  /* This function can GC */
  Lisp_Object tail;
  Lisp_Object allmatches;
  int list;
  int indice = 0;
  int obsize;
  Lisp_Object bucket;
  Charcount slength;

  CHECK_STRING (string);

  if (CONSP (collection))
    {
      Lisp_Object tem = XCAR (collection);
      if (SYMBOLP (tem))	/* lambda, autoload, etc.  Emacs-lisp sucks */
	return call3 (collection, string, predicate, Qt);
      else
	list = 1;
    }
  else if (VECTORP (collection))
    list = 0;
  else if (NILP (collection))
    list = 1;
  else
    return call3 (collection, string, predicate, Qt);

  allmatches = Qnil;
  slength = string_char_length (string);

  /* If COLLECTION is not a list, set TAIL just for gc pro.  */
  tail = collection;
  if (!list)
    {
      obsize = XVECTOR_LENGTH (collection);
      bucket = XVECTOR_DATA (collection)[indice];
    }
  else /* warning suppression */
    {
      obsize = 0;
      bucket = Qnil;
    }

  while (1)
    {
      /* Get the next element of the alist or obarray. */
      /* Exit the loop if the elements are all used up. */
      /* elt gets the alist element or symbol.
	 eltstring gets the name to check as a completion. */
      Lisp_Object elt;
      Lisp_Object eltstring;

      if (list)
	{
	  if (NILP (tail))
	    break;
	  elt = Fcar (tail);
	  eltstring = Fcar (elt);
	  tail = Fcdr (tail);
	}
      else
	{
	  if (!ZEROP (bucket))
	    {
              Lisp_Symbol *next = symbol_next (XSYMBOL (bucket));
	      elt = bucket;
	      eltstring = Fsymbol_name (elt);
              if (next)
		bucket = wrap_symbol (next);
	      else
		bucket = Qzero;
            }
	  else if (++indice >= obsize)
	    break;
	  else
	    {
	      bucket = XVECTOR_DATA (collection)[indice];
	      continue;
	    }
	}

      /* Is this element a possible completion? */

      if (STRINGP (eltstring)
          && (slength <= string_char_length (eltstring))
          /* Reject alternatives that start with space
	     unless the input starts with space.  */
	  && ((string_char_length (string) > 0 &&
	       string_ichar (string, 0) == ' ')
	      || string_ichar (eltstring, 0) != ' ')
	  && (0 > scmp (XSTRING_DATA (eltstring),
                        XSTRING_DATA (string),
                        slength)))
	{
	  /* Yes.  Now check whether predicate likes it. */
          struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
          int loser;
          GCPRO4 (tail, eltstring, allmatches, string);
          loser = ignore_completion_p (eltstring, predicate, elt);
          UNGCPRO;
          if (!loser)
            /* Ok => put it on the list. */
            allmatches = Fcons (eltstring, allmatches);
        }
    }

  return Fnreverse (allmatches);
}

/* Useless FSFmacs functions */
/* More than useless.  I've nuked minibuf_prompt_width so they won't
   function at all in XEmacs at the moment.  They are used to
   implement some braindamage in FSF which we aren't including. --cet */

#if 0
DEFUN ("minibuffer-prompt", Fminibuffer_prompt, 0, 0, 0, /*
Return the prompt string of the currently-active minibuffer.
If no minibuffer is active, return nil.
*/
	 ())
{
  return Fcopy_sequence (Vminibuf_prompt);
}

DEFUN ("minibuffer-prompt-width", Fminibuffer_prompt_width, 0, 0, 0, /*
Return the display width of the minibuffer prompt.
*/
	 ())
{
  return make_int (minibuf_prompt_width);
}
#endif /* 0 */


/************************************************************************/
/*                              echo area                               */
/************************************************************************/

extern int stdout_needs_newline;

static Lisp_Object
clear_echo_area_internal (struct frame *f, Lisp_Object label, int from_print,
			  int no_restore)
{
  /* This function can call lisp */
  if (!NILP (Ffboundp (Qclear_message)))
    {
      Lisp_Object frame = wrap_frame (f);

      return call4 (Qclear_message, label, frame, from_print ? Qt : Qnil,
		    no_restore ? Qt : Qnil);
    }
  else
    {
      stderr_out ("\n");
      return Qnil;
    }
}

Lisp_Object
clear_echo_area (struct frame *f, Lisp_Object label, int no_restore)
{
  /* This function can call lisp */
  return clear_echo_area_internal (f, label, 0, no_restore);
}

Lisp_Object
clear_echo_area_from_print (struct frame *f, Lisp_Object label, int no_restore)
{
  /* This function can call lisp */
  return clear_echo_area_internal (f, label, 1, no_restore);
}

void
echo_area_append (struct frame *f, const Ibyte *nonreloc, Lisp_Object reloc,
		  Bytecount offset, Bytecount length,
		  Lisp_Object label)
{
  /* This function can call lisp */
  Lisp_Object obj;
  struct gcpro gcpro1;
  Lisp_Object frame;

  /* There is an inlining bug in egcs-20000131 c++ that can be worked
     around as follows:  */
#if defined (__GNUC__) && defined (__cplusplus)
  alloca (4);
#endif

  /* some callers pass in a null string as a way of clearing the echo area.
     check for length == 0 now; if this case, neither nonreloc nor reloc
     may be valid.  */
  if (length == 0)
    return;

  fixup_internal_substring (nonreloc, reloc, offset, &length);

  /* also check it here, in case the string was really blank. */
  if (length == 0)
    return;

  if (!NILP (Ffboundp (Qappend_message)))
    {
      if (STRINGP (reloc) && offset == 0 && length == XSTRING_LENGTH (reloc))
	obj = reloc;
      else
	{
	  if (STRINGP (reloc))
	    nonreloc = XSTRING_DATA (reloc);
	  obj = make_string (nonreloc + offset, length);
	}

      frame = wrap_frame (f);
      GCPRO1 (obj);
      call4 (Qappend_message, label, obj, frame,
	     EQ (label, Qprint) ? Qt : Qnil);
      UNGCPRO;
    }
  else
    {
      if (STRINGP (reloc))
	nonreloc = XSTRING_DATA (reloc);
      write_string_1 (Qexternal_debugging_output, nonreloc + offset, length);
    }
}

void
echo_area_message (struct frame *f, const Ibyte *nonreloc,
		   Lisp_Object reloc, Bytecount offset, Bytecount length,
		   Lisp_Object label)
{
  /* This function can call lisp */
  clear_echo_area (f, label, 1);
  echo_area_append (f, nonreloc, reloc, offset, length, label);
}

int
echo_area_active (struct frame *UNUSED (f))
{
  /* By definition, the echo area is active if the echo-area buffer
     is not empty.  No need to call Lisp code. (Anyway, this function
     is called from redisplay.) */
  struct buffer *echo_buffer = XBUFFER (Vecho_area_buffer);
  return BUF_BEGV (echo_buffer) != BUF_ZV (echo_buffer);
}

Lisp_Object
echo_area_status (struct frame *f)
{
  /* This function can call lisp */
  if (!NILP (Ffboundp (Qcurrent_message_label)))
    {
      Lisp_Object frame = wrap_frame (f);

      return call1 (Qcurrent_message_label, frame);
    }
  else
    return stdout_needs_newline ? Qmessage : Qnil;
}

Lisp_Object
echo_area_contents (struct frame *UNUSED (f))
{
  /* See above.  By definition, the contents of the echo-area buffer
     are the contents of the echo area. */
  return Fbuffer_substring (Qnil, Qnil, Vecho_area_buffer);
}

/* Dump an informative message to the echo area.  This function takes a
   string in internal format. */
void
message_internal (const Ibyte *nonreloc, Lisp_Object reloc,
		  Bytecount offset, Bytecount length)
{
  /* This function can call lisp  */
  if (NILP (Vexecuting_macro))
    echo_area_message (selected_frame (), nonreloc, reloc, offset, length,
		       Qmessage);
}

void
message_append_internal (const Ibyte *nonreloc, Lisp_Object reloc,
			 Bytecount offset, Bytecount length)
{
  /* This function can call lisp  */
  if (NILP (Vexecuting_macro))
    echo_area_append (selected_frame (), nonreloc, reloc, offset, length,
		      Qmessage);
}

/* The next three functions are interfaces to message_internal() that
   take strings in external format.  message() does I18N3 translating
   on the format string; message_no_translate() does not. */

static void
message_1 (const CIbyte *fmt, va_list args)
{
  /* This function can call lisp */
  if (fmt)
    {
      struct gcpro gcpro1;
      /* message_internal() might GC, e.g. if there are after-change-hooks
	 on the echo area buffer */
      Lisp_Object obj = emacs_vsprintf_string (fmt, args);
      GCPRO1 (obj);
      message_internal (0, obj, 0, -1);
      UNGCPRO;
    }
  else
    message_internal (0, Qnil, 0, 0);
}

static void
message_append_1 (const CIbyte *fmt, va_list args)
{
  /* This function can call lisp */
  if (fmt)
    {
      struct gcpro gcpro1;
      /* message_internal() might GC, e.g. if there are after-change-hooks
	 on the echo area buffer */
      Lisp_Object obj = emacs_vsprintf_string (fmt, args);
      GCPRO1 (obj);
      message_append_internal (0, obj, 0, -1);
      UNGCPRO;
    }
  else
    message_append_internal (0, Qnil, 0, 0);
}

void
clear_message (void)
{
  /* This function can call lisp */
  message_internal (0, Qnil, 0, 0);
}

void
message (const char *fmt, ...)
{
  /* This function can call lisp */
  /* I think it's OK to pass the data of Lisp strings as arguments to
     this function.  No GC'ing will occur until the data has already
     been copied. */
  va_list args;

  va_start (args, fmt);
  if (fmt)
    fmt = GETTEXT (fmt);
  message_1 (fmt, args);
  va_end (args);
}

void
message_append (const char *fmt, ...)
{
  /* This function can call lisp */
  va_list args;

  va_start (args, fmt);
  if (fmt)
    fmt = GETTEXT (fmt);
  message_append_1 (fmt, args);
  va_end (args);
}

void
message_no_translate (const char *fmt, ...)
{
  /* This function can call lisp */
  /* I think it's OK to pass the data of Lisp strings as arguments to
     this function.  No GC'ing will occur until the data has already
     been copied. */
  va_list args;

  va_start (args, fmt);
  message_1 (fmt, args);
  va_end (args);
}


/************************************************************************/
/*                            initialization                            */
/************************************************************************/

void
syms_of_minibuf (void)
{
  DEFSYMBOL (Qminibuffer_setup_hook);

  DEFSYMBOL (Qcompletion_ignore_case);

  DEFSUBR (Fminibuffer_depth);
#if 0
  DEFSUBR (Fminibuffer_prompt);
  DEFSUBR (Fminibuffer_prompt_width);
#endif
  DEFSUBR (Fset_minibuffer_preprompt);
  DEFSUBR (Fread_minibuffer_internal);

  DEFSUBR (Ftry_completion);
  DEFSUBR (Fall_completions);

  DEFSYMBOL (Qappend_message);
  DEFSYMBOL (Qclear_message);
  DEFSYMBOL (Qdisplay_message);
  DEFSYMBOL (Qcurrent_message_label);
}

void
reinit_vars_of_minibuf (void)
{
  minibuf_level = 0;
}

void
vars_of_minibuf (void)
{
  staticpro (&Vminibuf_prompt);
  Vminibuf_prompt = Qnil;

  /* Added by Jareth Hein (jhod@po.iijnet.or.jp) for input system support */
  staticpro (&Vminibuf_preprompt);
  Vminibuf_preprompt = Qnil;

  DEFVAR_LISP ("minibuffer-setup-hook", &Vminibuffer_setup_hook /*
Normal hook run just after entry to minibuffer.
*/ );
  Vminibuffer_setup_hook = Qnil;

  DEFVAR_BOOL ("completion-ignore-case", &completion_ignore_case /*
Non-nil means don't consider case significant in completion.
*/ );
  completion_ignore_case = 0;

  DEFVAR_LISP ("completion-regexp-list", &Vcompletion_regexp_list /*
List of regexps that should restrict possible completions.
Each completion has to match all regexps in this list.
*/ );
  Vcompletion_regexp_list = Qnil;
}

void
reinit_complex_vars_of_minibuf (void)
{
  /* This function can GC */
#ifdef I18N3
  /* #### This needs to be fixed up so that the gettext() gets called
     at runtime instead of at load time. */
#endif
  Vminibuffer_zero
    = Fget_buffer_create
      (build_string (DEFER_GETTEXT (" *Minibuf-0*")));
  Vecho_area_buffer
    = Fget_buffer_create
      (build_string (DEFER_GETTEXT (" *Echo Area*")));
}

void
complex_vars_of_minibuf (void)
{
  reinit_complex_vars_of_minibuf ();
}