Commit b4132433 authored by Kenichi Handa's avatar Kenichi Handa
Browse files

(set_auto_coding_unwind): New function.

(Finsert_file_contents): If the current buffer is empty, decide
the coding system after the file is inserted in the buffer.  If
not, insert the head and tail of a file in a temporary buffer and
call set-auto-coding-function.
(e_write): If there are carryover bytes in encoding because of
incomplete multibyte form, write them out as is.
parent 03c6b7f6
......@@ -3246,6 +3246,26 @@ Lisp_Object Qfind_buffer_file_type;
#define READ_BUF_SIZE (64 << 10)
#endif
/* This function is called when a function bound to
Vset_auto_coding_function causes some error. At that time, a text
of a file has already been inserted in the current buffer, but,
markers has not yet been adjusted. Thus we must adjust markers
here. We are sure that the buffer was empty before the text of the
file was inserted. */
static Lisp_Object
set_auto_coding_unwind (multibyte)
Lisp_Object multibyte;
{
int inserted = Z_BYTE - BEG_BYTE;
if (!NILP (multibyte))
inserted = multibyte_chars_in_text (GPT_ADDR - inserted, inserted);
adjust_after_insert (PT, PT_BYTE, Z, Z_BYTE, inserted);
return Qnil;
}
DEFUN ("insert-file-contents", Finsert_file_contents, Sinsert_file_contents,
1, 5, 0,
"Insert contents of file FILENAME after point.\n\
......@@ -3290,6 +3310,7 @@ actually used.")
unsigned char buffer[1 << 14];
int replace_handled = 0;
int set_coding_system = 0;
int coding_system_decided = 0;
if (current_buffer->base_buffer && ! NILP (visit))
error ("Cannot do file visiting in an indirect buffer");
......@@ -3392,161 +3413,107 @@ actually used.")
}
}
/* Decide the coding-system of the file. */
{
Lisp_Object val;
val = Qnil;
if (!NILP (Vcoding_system_for_read))
val = Vcoding_system_for_read;
else if (! NILP (replace))
/* In REPLACE mode, we can use the same coding system
that was used to visit the file. */
val = current_buffer->buffer_file_coding_system;
else if (! not_regular)
{
/* Don't try looking inside a file for a coding system specification
if it is not seekable. */
if (! NILP (Vset_auto_coding_function))
{
/* Find a coding system specified in the heading two lines
or in the tailing several lines of the file. We assume
that the 1K-byte and 3K-byte for heading and tailing
respectively are sufficient fot this purpose. */
int nread;
int beginning_of_end, end_of_beginning;
if (st.st_size <= (1024 * 4))
{
nread = read (fd, read_buf, 1024 * 4);
end_of_beginning = nread;
beginning_of_end = 0;
}
else
{
nread = read (fd, read_buf, 1024);
end_of_beginning = nread;
beginning_of_end = nread;
if (nread >= 0)
{
if (lseek (fd, st.st_size - (1024 * 3), 0) < 0)
report_file_error ("Setting file position",
Fcons (orig_filename, Qnil));
nread += read (fd, read_buf + nread, 1024 * 3);
}
}
if (BEG < Z)
{
/* Decide the coding system to use for reading the file now
because we can't use an optimized method for handling
`coding:' tag if the current buffer is not empty. */
Lisp_Object val;
val = Qnil;
if (nread < 0)
error ("IO error reading %s: %s",
XSTRING (orig_filename)->data, strerror (errno));
else if (nread > 0)
{
int i;
int possible_spec = 0;
unsigned char *p, *p1;
Lisp_Object tem;
unsigned char *copy = (unsigned char *) alloca (nread + 1);
/* Make a copy of the contents of read_buf in COPY,
and convert it to lower case so we can compare
more efficiently. */
bcopy (read_buf, copy, nread);
for (i = 0; i < nread; i++)
copy[i] = DOWNCASE (copy[i]);
/* Ensure various comparisons fail at end of data. */
copy[nread] = 0;
/* Now test quickly whether the file contains a -*- line. */
p = copy;
while (*p != '\n' && p - copy < end_of_beginning)
p++;
if (copy[0] == '#' && copy[1] == '!')
while (*p != '\n' && p - copy < end_of_beginning)
p++;
p1 = copy;
while (p - p1 >= 3)
{
if (p1[0] == '-' && p1[1] == '*' && p1[2] == '-')
{
while (p - p1 >= 7)
{
if (! bcmp ("coding:", p1, 7))
{
possible_spec = 1;
goto win;
}
p1++;
}
break;
}
p1++;
}
if (!NILP (Vcoding_system_for_read))
val = Vcoding_system_for_read;
else if (! NILP (replace))
/* In REPLACE mode, we can use the same coding system
that was used to visit the file. */
val = current_buffer->buffer_file_coding_system;
else
{
/* Don't try looking inside a file for a coding system
specification if it is not seekable. */
if (! not_regular && ! NILP (Vset_auto_coding_function))
{
/* Find a coding system specified in the heading two
lines or in the tailing several lines of the file.
We assume that the 1K-byte and 3K-byte for heading
and tailing respectively are sufficient fot this
purpose. */
int how_many, nread;
if (st.st_size <= (1024 * 4))
nread = read (fd, read_buf, 1024 * 4);
else
{
nread = read (fd, read_buf, 1024);
if (nread >= 0)
{
if (lseek (fd, st.st_size - (1024 * 3), 0) < 0)
report_file_error ("Setting file position",
Fcons (orig_filename, Qnil));
nread += read (fd, read_buf + nread, 1024 * 3);
}
}
/* Test quickly whether the file
contains a local variables list. */
p = &copy[nread - 1];
p1 = &copy[beginning_of_end];
while (p > p1)
{
if (p[0] == '\n' && p[1] == '\f')
break;
p--;
}
p1 = &copy[nread];
while (p1 - p >= 16)
{
if (! bcmp ("local variables:", p, 16))
{
possible_spec = 1;
break;
}
p++;
}
win:
if (nread < 0)
error ("IO error reading %s: %s",
XSTRING (orig_filename)->data, strerror (errno));
else if (nread > 0)
{
int count = specpdl_ptr - specpdl;
struct buffer *prev = current_buffer;
record_unwind_protect (Fset_buffer, Fcurrent_buffer ());
temp_output_buffer_setup (" *code-converting-work*");
set_buffer_internal (XBUFFER (Vstandard_output));
current_buffer->enable_multibyte_characters = Qnil;
insert_1_both (read_buf, nread, nread, 0, 0, 0);
TEMP_SET_PT_BOTH (BEG, BEG_BYTE);
val = call1 (Vset_auto_coding_function, make_number (nread));
set_buffer_internal (prev);
/* Discard the unwind protect for recovering the
current buffer. */
specpdl_ptr--;
/* Rewind the file for the actual read done later. */
if (lseek (fd, 0, 0) < 0)
report_file_error ("Setting file position",
Fcons (orig_filename, Qnil));
}
}
if (possible_spec)
{
/* Always make this a unibyte string
because we have not yet decoded it. */
tem = make_unibyte_string (read_buf, nread);
val = call1 (Vset_auto_coding_function, tem);
}
if (NILP (val))
{
/* If we have not yet decided a coding system, check
file-coding-system-alist. */
Lisp_Object args[6], coding_systems;
args[0] = Qinsert_file_contents, args[1] = orig_filename;
args[2] = visit, args[3] = beg, args[4] = end, args[5] = replace;
coding_systems = Ffind_operation_coding_system (6, args);
if (CONSP (coding_systems))
val = XCONS (coding_systems)->car;
}
}
/* Rewind the file for the actual read done later. */
if (lseek (fd, 0, 0) < 0)
report_file_error ("Setting file position",
Fcons (orig_filename, Qnil));
}
}
if (NILP (val))
{
Lisp_Object args[6], coding_systems;
setup_coding_system (Fcheck_coding_system (val), &coding);
args[0] = Qinsert_file_contents, args[1] = orig_filename;
args[2] = visit, args[3] = beg, args[4] = end, args[5] = replace;
coding_systems = Ffind_operation_coding_system (6, args);
if (CONSP (coding_systems))
val = XCONS (coding_systems)->car;
}
}
if (NILP (Vcoding_system_for_read)
&& NILP (current_buffer->enable_multibyte_characters))
{
/* We must suppress all text conversion except for end-of-line
conversion. */
int eol_type;
if (NILP (Vcoding_system_for_read)
&& NILP (current_buffer->enable_multibyte_characters))
{
/* We must suppress all text conversion except for end-of-line
conversion. */
struct coding_system coding_temp;
eol_type = coding.eol_type;
setup_coding_system (Qraw_text, &coding);
coding.eol_type = eol_type;
}
setup_coding_system (Fcheck_coding_system (val), &coding_temp);
setup_coding_system (Qraw_text, &coding);
coding.eol_type = coding_temp.eol_type;
}
else
setup_coding_system (Fcheck_coding_system (val), &coding);
coding_system_decided = 1;
}
/* Ensure we always set Vlast_coding_system_used. */
set_coding_system = 1;
}
/* Ensure we always set Vlast_coding_system_used. */
set_coding_system = 1;
/* If requested, replace the accessible part of the buffer
with the file contents. Avoid replacing text at the
......@@ -3563,6 +3530,7 @@ actually used.")
But if we discover the need for conversion, we give up on this method
and let the following if-statement handle the replace job. */
if (!NILP (replace)
&& BEGV < ZV
&& ! CODING_REQUIRE_DECODING (&coding)
&& (coding.eol_type == CODING_EOL_UNDECIDED
|| coding.eol_type == CODING_EOL_LF))
......@@ -3741,7 +3709,7 @@ actually used.")
is needed, in a simple way that needs a lot of memory.
The preceding if-statement handles the case of no conversion
in a more optimized way. */
if (!NILP (replace) && ! replace_handled)
if (!NILP (replace) && ! replace_handled && BEGV < ZV)
{
int same_at_start = BEGV_BYTE;
int same_at_end = ZV_BYTE;
......@@ -3993,6 +3961,69 @@ actually used.")
if (inserted > 0)
{
if (! coding_system_decided)
{
/* The coding system is not yet decided. Decide it by an
optimized method for handling `coding:' tag. */
Lisp_Object val;
val = Qnil;
if (!NILP (Vcoding_system_for_read))
val = Vcoding_system_for_read;
else
{
if (! NILP (Vset_auto_coding_function))
{
/* Since we are sure that the current buffer was
empty before the insertion, we can toggle
enable-multibyte-characters directly here without
taking care of marker adjustment and byte
combining problem. */
Lisp_Object prev_multibyte;
int count = specpdl_ptr - specpdl;
prev_multibyte = current_buffer->enable_multibyte_characters;
current_buffer->enable_multibyte_characters = Qnil;
record_unwind_protect (set_auto_coding_unwind,
prev_multibyte);
val = call1 (Vset_auto_coding_function,
make_number (inserted));
/* Discard the unwind protect for recovering the
error of Vset_auto_coding_function. */
specpdl_ptr--;
current_buffer->enable_multibyte_characters = prev_multibyte;
TEMP_SET_PT_BOTH (BEG, BEG_BYTE);
}
if (NILP (val))
{
/* If the coding system is not yet decided, check
file-coding-system-alist. */
Lisp_Object args[6], coding_systems;
args[0] = Qinsert_file_contents, args[1] = orig_filename;
args[2] = visit, args[3] = beg, args[4] = end, args[5] = Qnil;
coding_systems = Ffind_operation_coding_system (6, args);
if (CONSP (coding_systems))
val = XCONS (coding_systems)->car;
}
}
setup_coding_system (Fcheck_coding_system (val), &coding);
if (NILP (Vcoding_system_for_read)
&& NILP (current_buffer->enable_multibyte_characters))
{
/* We must suppress all text conversion except for
end-of-line conversion. */
int eol_type;
eol_type = coding.eol_type;
setup_coding_system (Qraw_text, &coding);
coding.eol_type = eol_type;
}
}
if (CODING_MAY_REQUIRE_DECODING (&coding))
{
/* Here, we don't have to consider byte combining (see the
......@@ -4763,13 +4794,22 @@ e_write (desc, addr, nbytes, coding)
now it is handled within encode_coding. */
while (1)
{
encode_coding (coding, addr, buf, nbytes, WRITE_BUF_SIZE);
int result;
result = encode_coding (coding, addr, buf, nbytes, WRITE_BUF_SIZE);
nbytes -= coding->consumed, addr += coding->consumed;
if (coding->produced > 0)
{
coding->produced -= write (desc, buf, coding->produced);
if (coding->produced) return -1;
}
if (result == CODING_FINISH_INSUFFICIENT_SRC)
{
/* The source text ends by an incomplete multibyte form.
There's no way other than write it out as is. */
nbytes -= write (desc, addr, nbytes);
if (nbytes) return -1;
}
if (nbytes <= 0)
break;
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment