Mercurial > hg > xemacs-beta
diff src/buffer.c @ 398:74fd4e045ea6 r21-2-29
Import from CVS: tag r21-2-29
author | cvs |
---|---|
date | Mon, 13 Aug 2007 11:13:30 +0200 |
parents | aabb7f5b1c81 |
children | a86b2b5e0111 |
line wrap: on
line diff
--- a/src/buffer.c Mon Aug 13 11:12:06 2007 +0200 +++ b/src/buffer.c Mon Aug 13 11:13:30 2007 +0200 @@ -74,8 +74,12 @@ #include "elhash.h" #include "extents.h" #include "faces.h" +#ifdef FILE_CODING +#include "file-coding.h" +#endif #include "frame.h" #include "insdel.h" +#include "lstream.h" #include "process.h" /* for kill_buffer_processes */ #ifdef REGION_CACHE_NEEDS_WORK #include "region-cache.h" @@ -96,6 +100,7 @@ Setting the default value also goes through the alist of buffers and stores into each buffer that does not say it has a local value. */ Lisp_Object Vbuffer_defaults; +static void *buffer_defaults_saved_slots; /* This structure marks which slots in a buffer have corresponding default values in Vbuffer_defaults. @@ -133,6 +138,7 @@ /* This structure holds the names of symbols whose values may be buffer-local. It is indexed and accessed in the same way as the above. */ static Lisp_Object Vbuffer_local_symbols; +static void *buffer_local_symbols_saved_slots; /* Alist of all buffer names vs the buffers. */ /* This used to be a variable, but is no longer, @@ -189,7 +195,7 @@ Lisp_Object Qdefault_directory; Lisp_Object Qkill_buffer_hook; -Lisp_Object Qbuffer_file_name, Qbuffer_undo_list; +Lisp_Object Qrecord_buffer_hook; Lisp_Object Qrename_auto_save_file; @@ -220,7 +226,7 @@ } static Lisp_Object -mark_buffer (Lisp_Object obj, void (*markobj) (Lisp_Object)) +mark_buffer (Lisp_Object obj) { struct buffer *buf = XBUFFER (obj); @@ -229,13 +235,13 @@ undo_threshold, undo_high_threshold); -#define MARKED_SLOT(x) ((void) (markobj (buf->x))); +#define MARKED_SLOT(x) mark_object (buf->x) #include "bufslots.h" #undef MARKED_SLOT - markobj (buf->extent_info); + mark_object (buf->extent_info); if (buf->text) - markobj (buf->text->line_number_cache); + mark_object (buf->text->line_number_cache); /* Don't mark normally through the children slot. (Actually, in this case, it doesn't matter.) */ @@ -276,7 +282,7 @@ because all buffers have `kill-buffer' applied to them before they disappear, and the children removal happens then. */ DEFINE_LRECORD_IMPLEMENTATION ("buffer", buffer, - mark_buffer, print_buffer, 0, 0, 0, + mark_buffer, print_buffer, 0, 0, 0, 0, struct buffer); DEFUN ("bufferp", Fbufferp, 1, 1, 0, /* @@ -541,7 +547,7 @@ static struct buffer * allocate_buffer (void) { - struct buffer *b = alloc_lcrecord_type (struct buffer, lrecord_buffer); + struct buffer *b = alloc_lcrecord_type (struct buffer, &lrecord_buffer); copy_lcrecord (b, XBUFFER (Vbuffer_defaults)); @@ -1180,7 +1186,7 @@ killp = call1 (Qyes_or_no_p, (emacs_doprnt_string_c - ((CONST Bufbyte *) GETTEXT ("Buffer %s modified; kill anyway? "), + ((const Bufbyte *) GETTEXT ("Buffer %s modified; kill anyway? "), Qnil, -1, XSTRING_DATA (b->name)))); UNGCPRO; if (NILP (killp)) @@ -1406,6 +1412,9 @@ XCDR (prev) = XCDR (XCDR (prev)); XCDR (lynk) = f->buffer_alist; f->buffer_alist = lynk; + + va_run_hook_with_args (Qrecord_buffer_hook, 1, buffer); + return Qnil; } @@ -1619,6 +1628,8 @@ If BUFFER is nil or omitted, bury the current buffer. Also, if BUFFER is nil or omitted, remove the current buffer from the selected window if it is displayed there. +Because of this, you may need to specify (current-buffer) as +BUFFER when calling from minibuffer. If BEFORE is non-nil, it specifies a buffer before which BUFFER will be placed, instead of being placed at the end. */ @@ -1798,6 +1809,342 @@ #endif /* MEMORY_USAGE_STATS */ + +/************************************************************************/ +/* Implement TO_EXTERNAL_FORMAT, TO_INTERNAL_FORMAT */ +/************************************************************************/ + +/* This implementation should probably be elsewhere, but it can't be + in file-coding.c since that file is only available if FILE_CODING + is defined. */ +#ifdef FILE_CODING +static int +coding_system_is_binary (Lisp_Object coding_system) +{ + Lisp_Coding_System *cs = XCODING_SYSTEM (coding_system); + return + (CODING_SYSTEM_TYPE (cs) == CODESYS_NO_CONVERSION && + CODING_SYSTEM_EOL_TYPE (cs) == EOL_LF && + EQ (CODING_SYSTEM_POST_READ_CONVERSION (cs), Qnil) && + EQ (CODING_SYSTEM_PRE_WRITE_CONVERSION (cs), Qnil)); +} +#else +#define coding_system_is_binary(coding_system) 1 +#endif + +static Extbyte_dynarr *conversion_out_dynarr; +static Bufbyte_dynarr *conversion_in_dynarr; + +static int dfc_convert_to_external_format_in_use; +static int dfc_convert_to_internal_format_in_use; + +static Lisp_Object +dfc_convert_to_external_format_reset_in_use (Lisp_Object value) +{ + dfc_convert_to_external_format_in_use = XINT (value); + return Qnil; +} + +static Lisp_Object +dfc_convert_to_internal_format_reset_in_use (Lisp_Object value) +{ + dfc_convert_to_internal_format_in_use = XINT (value); + return Qnil; +} + +void +dfc_convert_to_external_format (dfc_conversion_type source_type, + dfc_conversion_data *source, +#ifdef FILE_CODING + Lisp_Object coding_system, +#endif + dfc_conversion_type sink_type, + dfc_conversion_data *sink) +{ + int count = specpdl_depth (); + + type_checking_assert + (((source_type == DFC_TYPE_DATA) || + (source_type == DFC_TYPE_LISP_LSTREAM && LSTREAMP (source->lisp_object)) || + (source_type == DFC_TYPE_LISP_STRING && STRINGP (source->lisp_object))) + && + ((sink_type == DFC_TYPE_DATA) || + (sink_type == DFC_TYPE_LISP_LSTREAM && LSTREAMP (source->lisp_object)))); + + if (dfc_convert_to_external_format_in_use != 0) + error ("Can't call a conversion function from a conversion function"); + else + dfc_convert_to_external_format_in_use = 1; + + record_unwind_protect (dfc_convert_to_external_format_reset_in_use, + Qzero); + +#ifdef FILE_CODING + coding_system = Fget_coding_system (coding_system); +#endif + + Dynarr_reset (conversion_out_dynarr); + + /* Here we optimize in the case where the coding system does no + conversion. However, we don't want to optimize in case the source + or sink is an lstream, since writing to an lstream can cause a + garbage collection, and this could be problematic if the source + is a lisp string. */ + if (source_type != DFC_TYPE_LISP_LSTREAM && + sink_type != DFC_TYPE_LISP_LSTREAM && + coding_system_is_binary (coding_system)) + { + const Bufbyte *ptr; + Bytecount len; + + if (source_type == DFC_TYPE_LISP_STRING) + { + ptr = XSTRING_DATA (source->lisp_object); + len = XSTRING_LENGTH (source->lisp_object); + } + else + { + ptr = (Bufbyte *) source->data.ptr; + len = source->data.len; + } + +#ifdef MULE + { + const Bufbyte *end; + for (end = ptr + len; ptr < end;) + { + Bufbyte c = + (BYTE_ASCII_P (*ptr)) ? *ptr : + (*ptr == LEADING_BYTE_CONTROL_1) ? (*(ptr+1) - 0x20) : + (*ptr == LEADING_BYTE_LATIN_ISO8859_1) ? (*(ptr+1)) : + '~'; + + Dynarr_add (conversion_out_dynarr, (Extbyte) c); + INC_CHARPTR (ptr); + } + bufpos_checking_assert (ptr == end); + } +#else + Dynarr_add_many (conversion_out_dynarr, ptr, len); +#endif + + } + else + { + Lisp_Object streams_to_delete[3]; + int delete_count = 0; + Lisp_Object instream, outstream; + Lstream *reader, *writer; + struct gcpro gcpro1, gcpro2; + + if (source_type == DFC_TYPE_LISP_LSTREAM) + instream = source->lisp_object; + else if (source_type == DFC_TYPE_DATA) + streams_to_delete[delete_count++] = instream = + make_fixed_buffer_input_stream (source->data.ptr, source->data.len); + else + { + type_checking_assert (source_type == DFC_TYPE_LISP_STRING); + streams_to_delete[delete_count++] = instream = + make_lisp_string_input_stream (source->lisp_object, 0, -1); + } + + if (sink_type == DFC_TYPE_LISP_LSTREAM) + outstream = sink->lisp_object; + else + { + type_checking_assert (sink_type == DFC_TYPE_DATA); + streams_to_delete[delete_count++] = outstream = + make_dynarr_output_stream + ((unsigned_char_dynarr *) conversion_out_dynarr); + } + +#ifdef FILE_CODING + streams_to_delete[delete_count++] = outstream = + make_encoding_output_stream (XLSTREAM (outstream), coding_system); +#endif + + reader = XLSTREAM (instream); + writer = XLSTREAM (outstream); + /* decoding_stream will gc-protect outstream */ + GCPRO2 (instream, outstream); + + while (1) + { + ssize_t size_in_bytes; + char tempbuf[1024]; /* some random amount */ + + size_in_bytes = Lstream_read (reader, tempbuf, sizeof (tempbuf)); + + if (size_in_bytes == 0) + break; + else if (size_in_bytes < 0) + error ("Error converting to external format"); + + size_in_bytes = Lstream_write (writer, tempbuf, size_in_bytes); + + if (size_in_bytes <= 0) + error ("Error converting to external format"); + } + + /* Closing writer will close any stream at the other end of writer. */ + Lstream_close (writer); + Lstream_close (reader); + UNGCPRO; + + /* The idea is that this function will create no garbage. */ + while (delete_count) + Lstream_delete (XLSTREAM (streams_to_delete [--delete_count])); + } + + unbind_to (count, Qnil); + + if (sink_type != DFC_TYPE_LISP_LSTREAM) + { + sink->data.len = Dynarr_length (conversion_out_dynarr); + Dynarr_add (conversion_out_dynarr, 0); + sink->data.ptr = Dynarr_atp (conversion_out_dynarr, 0); + } +} + +void +dfc_convert_to_internal_format (dfc_conversion_type source_type, + dfc_conversion_data *source, +#ifdef FILE_CODING + Lisp_Object coding_system, +#endif + dfc_conversion_type sink_type, + dfc_conversion_data *sink) +{ + int count = specpdl_depth (); + + type_checking_assert + ((source_type == DFC_TYPE_DATA || + source_type == DFC_TYPE_LISP_LSTREAM) + && + (sink_type == DFC_TYPE_DATA || + sink_type == DFC_TYPE_LISP_LSTREAM)); + + if (dfc_convert_to_internal_format_in_use != 0) + error ("Can't call a conversion function from a conversion function"); + else + dfc_convert_to_internal_format_in_use = 1; + + record_unwind_protect (dfc_convert_to_internal_format_reset_in_use, + Qzero); + +#ifdef FILE_CODING + coding_system = Fget_coding_system (coding_system); +#endif + + Dynarr_reset (conversion_in_dynarr); + + if (source_type != DFC_TYPE_LISP_LSTREAM && + sink_type != DFC_TYPE_LISP_LSTREAM && + coding_system_is_binary (coding_system)) + { +#ifdef MULE + const Bufbyte *ptr = (const Bufbyte *) source->data.ptr; + Bytecount len = source->data.len; + const Bufbyte *end = ptr + len; + + for (; ptr < end; ptr++) + { + Extbyte c = *ptr; + + if (BYTE_ASCII_P (c)) + Dynarr_add (conversion_in_dynarr, c); + else if (BYTE_C1_P (c)) + { + Dynarr_add (conversion_in_dynarr, LEADING_BYTE_CONTROL_1); + Dynarr_add (conversion_in_dynarr, c + 0x20); + } + else + { + Dynarr_add (conversion_in_dynarr, LEADING_BYTE_LATIN_ISO8859_1); + Dynarr_add (conversion_in_dynarr, c); + } + } +#else + Dynarr_add_many (conversion_in_dynarr, source->data.ptr, source->data.len); +#endif + } + else + { + Lisp_Object streams_to_delete[3]; + int delete_count = 0; + Lisp_Object instream, outstream; + Lstream *reader, *writer; + struct gcpro gcpro1, gcpro2; + + if (source_type == DFC_TYPE_LISP_LSTREAM) + instream = source->lisp_object; + else + { + type_checking_assert (source_type == DFC_TYPE_DATA); + streams_to_delete[delete_count++] = instream = + make_fixed_buffer_input_stream (source->data.ptr, source->data.len); + } + + if (sink_type == DFC_TYPE_LISP_LSTREAM) + outstream = sink->lisp_object; + else + { + type_checking_assert (sink_type == DFC_TYPE_DATA); + streams_to_delete[delete_count++] = outstream = + make_dynarr_output_stream + ((unsigned_char_dynarr *) conversion_in_dynarr); + } + +#ifdef FILE_CODING + streams_to_delete[delete_count++] = outstream = + make_decoding_output_stream (XLSTREAM (outstream), coding_system); +#endif + + reader = XLSTREAM (instream); + writer = XLSTREAM (outstream); + /* outstream will gc-protect its sink stream, if necessary */ + GCPRO2 (instream, outstream); + + while (1) + { + ssize_t size_in_bytes; + char tempbuf[1024]; /* some random amount */ + + size_in_bytes = Lstream_read (reader, tempbuf, sizeof (tempbuf)); + + if (size_in_bytes == 0) + break; + else if (size_in_bytes < 0) + error ("Error converting to internal format"); + + size_in_bytes = Lstream_write (writer, tempbuf, size_in_bytes); + + if (size_in_bytes <= 0) + error ("Error converting to internal format"); + } + + /* Closing writer will close any stream at the other end of writer. */ + Lstream_close (writer); + Lstream_close (reader); + UNGCPRO; + + /* The idea is that this function will create no garbage. */ + while (delete_count) + Lstream_delete (XLSTREAM (streams_to_delete [--delete_count])); + } + + unbind_to (count, Qnil); + + if (sink_type != DFC_TYPE_LISP_LSTREAM) + { + sink->data.len = Dynarr_length (conversion_in_dynarr); + Dynarr_add (conversion_in_dynarr, 0); /* remember to zero-terminate! */ + sink->data.ptr = Dynarr_atp (conversion_in_dynarr, 0); + } +} + + void syms_of_buffer (void) { @@ -1806,6 +2153,7 @@ defsymbol (&Qmode_class, "mode-class"); defsymbol (&Qrename_auto_save_file, "rename-auto-save-file"); defsymbol (&Qkill_buffer_hook, "kill-buffer-hook"); + defsymbol (&Qrecord_buffer_hook, "record-buffer-hook"); defsymbol (&Qpermanent_local, "permanent-local"); defsymbol (&Qfirst_change_hook, "first-change-hook"); @@ -1816,8 +2164,6 @@ defsymbol (&Qbefore_change_function, "before-change-function"); defsymbol (&Qafter_change_function, "after-change-function"); - defsymbol (&Qbuffer_file_name, "buffer-file-name"); - defsymbol (&Qbuffer_undo_list, "buffer-undo-list"); defsymbol (&Qdefault_directory, "default-directory"); defsymbol (&Qget_file_buffer, "get-file-buffer"); @@ -1870,20 +2216,29 @@ "Attempt to modify a protected field", Qerror); } +void +reinit_vars_of_buffer (void) +{ + conversion_in_dynarr = Dynarr_new (Bufbyte); + conversion_out_dynarr = Dynarr_new (Extbyte); + + staticpro_nodump (&Vbuffer_alist); + Vbuffer_alist = Qnil; + current_buffer = 0; +} + /* initialize the buffer routines */ void vars_of_buffer (void) { /* This function can GC */ + reinit_vars_of_buffer (); + staticpro (&QSFundamental); staticpro (&QSscratch); - staticpro (&Vbuffer_alist); - - QSFundamental = Fpurecopy (build_string ("Fundamental")); - QSscratch = Fpurecopy (build_string (DEFER_GETTEXT ("*scratch*"))); - - Vbuffer_alist = Qnil; - current_buffer = 0; + + QSFundamental = build_string ("Fundamental"); + QSscratch = build_string (DEFER_GETTEXT ("*scratch*")); DEFVAR_LISP ("change-major-mode-hook", &Vchange_major_mode_hook /* List of hooks to be run before killing local variables in a buffer. @@ -2023,10 +2378,26 @@ from SunPro C's fix-and-continue feature (a way neato feature that makes debugging unbelievably more bearable) */ #define DEFVAR_BUFFER_LOCAL_1(lname, field_name, forward_type, magicfun) do { \ - static CONST_IF_NOT_DEBUG struct symbol_value_forward I_hate_C \ - = { { { symbol_value_forward_lheader_initializer, \ - (struct lcrecord_header *) &(buffer_local_flags.field_name), 69 }, \ - forward_type }, magicfun }; \ + static CONST_IF_NOT_DEBUG struct symbol_value_forward I_hate_C = \ + { /* struct symbol_value_forward */ \ + { /* struct symbol_value_magic */ \ + { /* struct lcrecord_header */ \ + { /* struct lrecord_header */ \ + 1, /* type - index into lrecord_implementations_table */ \ + 0, /* mark bit */ \ + 0, /* c_readonly bit */ \ + 0 /* lisp_readonly bit */ \ + }, \ + 0, /* next */ \ + 0, /* uid */ \ + 0 /* free */ \ + }, \ + &(buffer_local_flags.field_name), \ + forward_type \ + }, \ + magicfun \ + }; \ + \ { \ int offset = ((char *)symbol_value_forward_forward (&I_hate_C) - \ (char *)&buffer_local_flags); \ @@ -2063,21 +2434,21 @@ b->indirect_children = Qnil; b->own_text.line_number_cache = Qnil; -#define MARKED_SLOT(x) b->x = (zap); +#define MARKED_SLOT(x) b->x = zap #include "bufslots.h" #undef MARKED_SLOT } -void -complex_vars_of_buffer (void) +static void +common_init_complex_vars_of_buffer (void) { /* Make sure all markable slots in buffer_defaults are initialized reasonably, so mark_buffer won't choke. */ - struct buffer *defs = alloc_lcrecord_type (struct buffer, lrecord_buffer); - struct buffer *syms = alloc_lcrecord_type (struct buffer, lrecord_buffer); - - staticpro (&Vbuffer_defaults); - staticpro (&Vbuffer_local_symbols); + struct buffer *defs = alloc_lcrecord_type (struct buffer, &lrecord_buffer); + struct buffer *syms = alloc_lcrecord_type (struct buffer, &lrecord_buffer); + + staticpro_nodump (&Vbuffer_defaults); + staticpro_nodump (&Vbuffer_local_symbols); XSETBUFFER (Vbuffer_defaults, defs); XSETBUFFER (Vbuffer_local_symbols, syms); @@ -2193,10 +2564,56 @@ buffer_local_flags.buffer_file_coding_system = make_int (1<<14); #endif - /* #### Warning: 1<<28 is the largest number currently allowable + /* #### Warning: 1<<31 is the largest number currently allowable due to the XINT() handling of this value. With some rearrangement you can get 3 more bits. */ } +} + +#define BUFFER_SLOTS_SIZE (offsetof (struct buffer, BUFFER_SLOTS_LAST_NAME) - offsetof (struct buffer, BUFFER_SLOTS_FIRST_NAME) + sizeof (Lisp_Object)) +#define BUFFER_SLOTS_COUNT (BUFFER_SLOTS_SIZE / sizeof (Lisp_Object)) + +void +reinit_complex_vars_of_buffer (void) +{ + struct buffer *defs, *syms; + + common_init_complex_vars_of_buffer (); + + defs = XBUFFER (Vbuffer_defaults); + syms = XBUFFER (Vbuffer_local_symbols); + memcpy (&defs->BUFFER_SLOTS_FIRST_NAME, + buffer_defaults_saved_slots, + BUFFER_SLOTS_SIZE); + memcpy (&syms->BUFFER_SLOTS_FIRST_NAME, + buffer_local_symbols_saved_slots, + BUFFER_SLOTS_SIZE); +} + + +static const struct lrecord_description buffer_slots_description_1[] = { + { XD_LISP_OBJECT_ARRAY, 0, BUFFER_SLOTS_COUNT }, + { XD_END } +}; + +static const struct struct_description buffer_slots_description = { + BUFFER_SLOTS_SIZE, + buffer_slots_description_1 +}; + +void +complex_vars_of_buffer (void) +{ + struct buffer *defs, *syms; + + common_init_complex_vars_of_buffer (); + + defs = XBUFFER (Vbuffer_defaults); + syms = XBUFFER (Vbuffer_local_symbols); + buffer_defaults_saved_slots = &defs->BUFFER_SLOTS_FIRST_NAME; + buffer_local_symbols_saved_slots = &syms->BUFFER_SLOTS_FIRST_NAME; + dumpstruct (&buffer_defaults_saved_slots, &buffer_slots_description); + dumpstruct (&buffer_local_symbols_saved_slots, &buffer_slots_description); DEFVAR_BUFFER_DEFAULTS ("default-modeline-format", modeline_format /* Default value of `modeline-format' for buffers that don't override it. @@ -2690,19 +3107,22 @@ /* Is PWD another name for `.' ? */ static int -directory_is_current_directory (char *pwd) +directory_is_current_directory (Extbyte *pwd) { Bufbyte *pwd_internal; + Bytecount pwd_internal_len; struct stat dotstat, pwdstat; - GET_C_CHARPTR_INT_FILENAME_DATA_ALLOCA (pwd, pwd_internal); + TO_INTERNAL_FORMAT (DATA, (pwd, strlen ((char *)pwd) + 1), + ALLOCA, (pwd_internal, pwd_internal_len), + Qfile_name); return (IS_DIRECTORY_SEP (*pwd_internal) && stat ((char *) pwd_internal, &pwdstat) == 0 && stat (".", &dotstat) == 0 && dotstat.st_ino == pwdstat.st_ino && dotstat.st_dev == pwdstat.st_dev - && (int) strlen ((char *) pwd_internal) < MAXPATHLEN); + && pwd_internal_len < MAXPATHLEN); } void @@ -2710,15 +3130,15 @@ { /* This function can GC */ - char *pwd; + Extbyte *pwd; initial_directory[0] = 0; /* If PWD is accurate, use it instead of calling getcwd. This is faster when PWD is right, and may avoid a fatal error. */ - if ((pwd = getenv ("PWD")) != NULL + if ((pwd = (Extbyte *) getenv ("PWD")) != NULL && directory_is_current_directory (pwd)) - strcpy (initial_directory, pwd); + strcpy (initial_directory, (char *) pwd); else if (getcwd (initial_directory, MAXPATHLEN) == NULL) fatal ("`getcwd' failed: %s\n", strerror (errno)); @@ -2756,7 +3176,7 @@ Fset_buffer (Fget_buffer_create (QSscratch)); current_buffer->directory = - build_ext_string (initial_directory, FORMAT_FILENAME); + build_ext_string (initial_directory, Qfile_name); #if 0 /* FSFmacs */ /* #### is this correct? */