X-Git-Url: http://git.chise.org/gitweb/?p=chise%2Fxemacs-chise.git.1;a=blobdiff_plain;f=src%2Fbuffer.c;h=b7c18f9ef3222eb9e4d49f38009ef292a666d749;hp=19d63452213b3285189d563f2b3f3d91b74649a4;hb=716cfba952c1dc0d2cf5c968971f3780ba728a89;hpb=d74da9234cc42e8018b1500105c3892a5c46d5e3 diff --git a/src/buffer.c b/src/buffer.c index 19d6345..b7c18f9 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -74,8 +74,12 @@ Boston, MA 02111-1307, USA. */ #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" @@ -1410,7 +1414,7 @@ buffer. See `other-buffer' for more information. f->buffer_alist = lynk; va_run_hook_with_args (Qrecord_buffer_hook, 1, buffer); - + return Qnil; } @@ -1805,6 +1809,342 @@ represents all the memory concerned. #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) { @@ -1879,6 +2219,9 @@ syms_of_buffer (void) 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; @@ -2233,7 +2576,7 @@ reinit_complex_vars_of_buffer (void) static const struct lrecord_description buffer_slots_description_1[] = { - { XD_LISP_OBJECT, 0, BUFFER_SLOTS_COUNT }, + { XD_LISP_OBJECT_ARRAY, 0, BUFFER_SLOTS_COUNT }, { XD_END } }; @@ -2255,7 +2598,7 @@ complex_vars_of_buffer (void) 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. This is the same as (default-value 'modeline-format). @@ -2748,19 +3091,22 @@ handled: /* 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 @@ -2768,15 +3114,15 @@ init_initial_directory (void) { /* 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)); @@ -2814,7 +3160,7 @@ init_buffer (void) 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? */