/* File IO for GNU Emacs.
- Copyright (C) 1985,86,87,88,93,94,95,96 Free Software Foundation, Inc.
+ Copyright (C) 1985,86,87,88,93,94,95,96,1997 Free Software Foundation, Inc.
This file is part of GNU Emacs.
#include <fcntl.h>
#endif
+#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
extern int minibuf_level;
+extern int minibuffer_auto_raise;
+
/* These variables describe handlers that have "already" had a chance
to handle the current operation.
/* Get rid of any slash at the end of newdir, unless newdir is
just // (an incomplete UNC name). */
length = strlen (newdir);
- if (IS_DIRECTORY_SEP (newdir[length - 1])
+ if (length > 0 && IS_DIRECTORY_SEP (newdir[length - 1])
#ifdef WINDOWSNT
&& !(length == 2 && IS_DIRECTORY_SEP (newdir[0]))
#endif
{
while (o != target && (--o) && !IS_DIRECTORY_SEP (*o))
;
- if (o == target && IS_ANY_SEP (*o))
+ /* Keep initial / only if this is the whole name. */
+ if (o == target && IS_ANY_SEP (*o) && p[3] == 0)
++o;
p += 3;
}
|| IS_DIRECTORY_SEP (p[0])
#endif /* not (APOLLO || WINDOWSNT) */
)
- && p != nm && IS_DIRECTORY_SEP (p[-1]))
+ && p != xnm && IS_DIRECTORY_SEP (p[-1]))
xnm = p;
#ifdef DOS_NT
else if (IS_DRIVE (p[0]) && p[1] == ':'
}
DEFUN ("file-directory-p", Ffile_directory_p, Sfile_directory_p, 1, 1, 0,
- "Return t if file FILENAME is the name of a directory as a file.\n\
-A directory name spec may be given instead; then the value is t\n\
-if the directory so specified exists and really is a directory.")
+ "Return t if FILENAME names an existing directory.")
(filename)
Lisp_Object filename;
{
When REPLACE is non-nil, the value is the number of characters actually read,\n\
which is often less than the number of characters to be read.\n\
This does code conversion according to the value of\n\
- `coding-system-for-read' or `coding-system-alist', and sets the variable\n\
- `last-coding-system-used' to the coding system actually used.")
+ `coding-system-for-read' or `file-coding-system-alist',\n\
+ and sets the variable `last-coding-system-used' to the coding system\n\
+ actually used.")
(filename, visit, beg, end, replace)
Lisp_Object filename, visit, beg, end, replace;
{
/* Decide the coding-system of the file. */
{
- Lisp_Object val = Vcoding_system_for_read;
- if (NILP (current_buffer->enable_multibyte_characters))
- val = Qnil;
- else if (NILP (val))
+ Lisp_Object val;
+
+ if (!NILP (Vcoding_system_for_read))
+ val = Vcoding_system_for_read;
+ else if (NILP (current_buffer->enable_multibyte_characters))
+ val = Qemacs_mule;
+ else
{
Lisp_Object args[6], coding_systems;
args[0] = Qinsert_file_contents, args[1] = filename, args[2] = visit,
args[3] = beg, args[4] = end, args[5] = replace;
- coding_systems = Ffind_coding_system (6, args);
+ coding_systems = Ffind_operation_coding_system (6, args);
val = CONSP (coding_systems) ? XCONS (coding_systems)->car : Qnil;
}
setup_coding_system (Fcheck_coding_system (val), &coding);
}
+#ifdef DOS_NT
+ /* Use the conversion type to determine buffer-file-type
+ (find-buffer-file-type is now used to help determine the
+ conversion). */
+ if (coding.type == coding_type_no_conversion)
+ current_buffer->buffer_file_type = Qt;
+ else
+ current_buffer->buffer_file_type = Qnil;
+#endif
+
fd = -1;
#ifndef APOLLO
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)
- && (! CODING_REQUIRE_CONVERSION (&coding)
- || (coding.type == coding_type_automatic
- && ! CODING_REQUIRE_TEXT_CONVERSION (&coding))
- || (coding.eol_type == CODING_EOL_AUTOMATIC
- && ! CODING_REQUIRE_EOL_CONVERSION (&coding))))
+ && CODING_MAY_REQUIRE_NO_CONVERSION (&coding))
{
int same_at_start = BEGV;
int same_at_end = ZV;
else if (nread == 0)
break;
- if (coding.type == coding_type_automatic)
+ if (coding.type == coding_type_undecided)
detect_coding (&coding, buffer, nread);
- if (CODING_REQUIRE_TEXT_CONVERSION (&coding))
+ if (coding.type != coding_type_undecided
+ && coding.type != coding_type_no_conversion
+ && coding.type != coding_type_emacs_mule)
/* We found that the file should be decoded somehow.
Let's give up here. */
{
break;
}
- if (coding.eol_type == CODING_EOL_AUTOMATIC)
+ if (coding.eol_type == CODING_EOL_UNDECIDED)
detect_eol (&coding, buffer, nread);
- if (CODING_REQUIRE_EOL_CONVERSION (&coding))
+ if (coding.eol_type != CODING_EOL_UNDECIDED
+ && coding.eol_type != CODING_EOL_LF)
/* We found that the format of eol should be decoded.
Let's give up here. */
{
we cannot use this method; giveup and try the other. */
if (same_at_end > same_at_start
&& FETCH_BYTE (same_at_end - 1) >= 0200
- && ! NILP (current_buffer->enable_multibyte_characters))
+ && ! NILP (current_buffer->enable_multibyte_characters)
+ && ! CODING_REQUIRE_NO_CONVERSION (&coding))
giveup_match_end = 1;
break;
}
{
/* We win! We can handle REPLACE the optimized way. */
+ /* Extends the end of non-matching text area to multibyte
+ character boundary. */
+ if (! NILP (current_buffer->enable_multibyte_characters))
+ while (same_at_end < ZV && ! CHAR_HEAD_P (POS_ADDR (same_at_end)))
+ same_at_end++;
+
/* Don't try to reuse the same piece of text twice. */
overlap = same_at_start - BEGV - (same_at_end + st.st_size - ZV);
if (overlap > 0)
int bufpos;
/* Make sure that the gap is large enough. */
int bufsize = 2 * st.st_size;
- unsigned char *conversion_buffer = (unsigned char *) malloc (bufsize);
+ unsigned char *conversion_buffer = (unsigned char *) xmalloc (bufsize);
/* First read the whole file, performing code conversion into
CONVERSION_BUFFER. */
how_much += this;
- if (CODING_REQUIRE_CONVERSION (&coding))
+ if (! CODING_REQUIRE_NO_CONVERSION (&coding))
{
int require, produced, consumed;
if (inserted + require + 2 * (total - how_much) > bufsize)
{
bufsize = inserted + require + 2 * (total - how_much);
- conversion_buffer = (unsigned char *) realloc (conversion_buffer, bufsize);
+ conversion_buffer = (unsigned char *) xrealloc (conversion_buffer, bufsize);
}
/* Convert this batch with results in CONVERSION_BUFFER. */
total = READ_BUF_SIZE;
if (NILP (visit) && total > 0)
- prepare_to_modify_buffer (PT, PT);
+ prepare_to_modify_buffer (PT, PT, NULL);
move_gap (PT);
if (GAP_SIZE < total)
{
/* try is reserved in some compilers (Microsoft C) */
int trytry = min (total - how_much, READ_BUF_SIZE - unprocessed);
- char *destination = (CODING_REQUIRE_CONVERSION (&coding)
- ? read_buf + unprocessed
- : (char *) (POS_ADDR (PT + inserted - 1) + 1));
+ char *destination = (CODING_REQUIRE_NO_CONVERSION (&coding)
+ ? (char *) (POS_ADDR (PT + inserted - 1) + 1)
+ : read_buf + unprocessed);
int this;
/* Allow quitting out of the actual I/O. */
if (! not_regular)
how_much += this;
- if (CODING_REQUIRE_CONVERSION (&coding))
+ if (! CODING_REQUIRE_NO_CONVERSION (&coding))
{
int require, produced, consumed;
}
\f
static Lisp_Object build_annotations ();
+extern Lisp_Object Ffile_locked_p ();
/* If build_annotations switched buffers, switch back to BUF.
Kill the temporary buffer that was selected in the meantime.
The optional sixth arg LOCKNAME, if non-nil, specifies the name to\n\
use for locking and unlocking, overriding FILENAME and VISIT.\n\
Kludgy feature: if START is a string, then that string is written\n\
-to the file, instead of any buffer contents, and END is ignored.\n\
-This does code conversion according to the value of\n\
- `coding-system-for-write' or `coding-system-alist', and sets the variable\n\
- `last-coding-system-used' to the coding system actually used.")
+to the file, instead of any buffer contents, and END is ignored.")
(start, end, filename, append, visit, lockname)
Lisp_Object start, end, filename, append, visit, lockname;
{
struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
struct buffer *given_buffer;
#ifdef DOS_NT
- int buffer_file_type
- = NILP (current_buffer->buffer_file_type) ? O_TEXT : O_BINARY;
+ int buffer_file_type = O_BINARY;
#endif /* DOS_NT */
struct coding_system coding;
if (!NILP (start) && !STRINGP (start))
validate_region (&start, &end);
- GCPRO3 (filename, visit, lockname);
+ GCPRO4 (start, filename, visit, lockname);
+
+ /* Decide the coding-system to be encoded to. */
+ {
+ Lisp_Object val;
+
+ if (auto_saving)
+ val = Qnil;
+ else if (!NILP (Vcoding_system_for_write))
+ val = Vcoding_system_for_write;
+ else if (NILP (current_buffer->enable_multibyte_characters))
+ val = (NILP (Flocal_variable_p (Qbuffer_file_coding_system, Qnil))
+ ? Qnil
+ : Fsymbol_value (Qbuffer_file_coding_system));
+ else
+ {
+ Lisp_Object args[7], coding_systems;
+
+ args[0] = Qwrite_region, args[1] = start, args[2] = end,
+ args[3] = filename, args[4] = append, args[5] = visit,
+ args[6] = lockname;
+ coding_systems = Ffind_operation_coding_system (7, args);
+ val = (CONSP (coding_systems) && !NILP (XCONS (coding_systems)->cdr)
+ ? XCONS (coding_systems)->cdr
+ : current_buffer->buffer_file_coding_system);
+ }
+ setup_coding_system (Fcheck_coding_system (val), &coding);
+ if (!STRINGP (start) && !NILP (current_buffer->selective_display))
+ coding.selective = 1;
+ }
+
filename = Fexpand_file_name (filename, Qnil);
if (STRINGP (visit))
visit_file = Fexpand_file_name (visit, Qnil);
return val;
}
- /* Decide the coding-system to be encoded to. */
- {
- Lisp_Object val;
-
- if (auto_saving || NILP (current_buffer->enable_multibyte_characters))
- val = Qnil;
- else if (!NILP (Vcoding_system_for_write))
- val = Vcoding_system_for_write;
- else if (!NILP (Flocal_variable_if_set_p (Qbuffer_file_coding_system,
- Qnil)))
- val = Fsymbol_value (Qbuffer_file_coding_system);
- else
- {
- Lisp_Object args[7], coding_systems;
-
- args[0] = Qwrite_region, args[1] = start, args[2] = end,
- args[3] = filename, args[4] = append, args[5] = visit,
- args[6] = lockname;
- coding_systems = Ffind_coding_system (7, args);
- val = (CONSP (coding_systems)
- ? XCONS (coding_systems)->cdr
- : Fsymbol_value (Qbuffer_file_coding_system));
- }
- setup_coding_system (Fcheck_coding_system (val), &coding);
- if (!STRINGP (start) && !NILP (current_buffer->selective_display))
- coding.selective = 1;
-#ifdef DOS_NT
- if (!NILP (current_buffer->buffer_file_type))
- coding.eol_type = CODING_EOL_LF;
-#endif /* DOS_NT */
- }
-
/* Special kludge to simplify auto-saving. */
if (NILP (start))
{
annotations = build_annotations (start, end, coding.pre_write_conversion);
if (current_buffer != given_buffer)
{
- start = BEGV;
- end = ZV;
+ XSETFASTINT (start, BEGV);
+ XSETFASTINT (end, ZV);
}
#ifdef CLASH_DETECTION
/* If we've locked this file for some other buffer,
query before proceeding. */
if (!visiting && EQ (Ffile_locked_p (lockname), Qt))
- call2 (intern ("ask-user-about-lock"), fn, Vuser_login_name);
+ call2 (intern ("ask-user-about-lock"), filename, Vuser_login_name);
lock_file (lockname);
}
*/
if (GPT > BEG && GPT_ADDR[-1] != '\n')
move_gap (find_next_newline (GPT, 1));
+#else
+ /* Whether VMS or not, we must move the gap to the next of newline
+ when we must put designation sequences at beginning of line. */
+ if (INTEGERP (start)
+ && coding.type == coding_type_iso2022
+ && coding.flags & CODING_FLAG_ISO_DESIGNATE_AT_BOL
+ && GPT > BEG && GPT_ADDR[-1] != '\n')
+ move_gap (find_next_newline (GPT, 1));
#endif
failure = 0;
else
{
/* If file was empty, still need to write the annotations */
+ coding.last_block = 1;
failure = 0 > a_write (desc, "", 0, XINT (start), &annotations, &coding);
save_errno = errno;
}
- if (coding.require_flushing)
+ if (coding.require_flushing && !coding.last_block)
{
/* We have to flush out a data. */
coding.last_block = 1;
been dealt with by this function. */
if (current_buffer != given_buffer)
{
- start = BEGV;
- end = ZV;
+ XSETFASTINT (start, BEGV);
+ XSETFASTINT (end, ZV);
annotations = Qnil;
}
Flength (res); /* Check basic validity of return value */
original_buffer);
if (current_buffer != given_buffer)
{
- start = BEGV;
- end = ZV;
+ XSETFASTINT (start, BEGV);
+ XSETFASTINT (end, ZV);
annotations = Qnil;
}
Flength (res);
struct buffer *given_buffer = current_buffer;
Vwrite_region_annotations_so_far = annotations;
res = call2 (pre_write_conversion, start, end);
- if (current_buffer != given_buffer)
- {
- start = BEGV;
- end = ZV;
- annotations = Qnil;
- }
Flength (res);
- annotations = merge (annotations, res, Qcar_less_than_car);
+ annotations = (current_buffer != given_buffer
+ ? res
+ : merge (annotations, res, Qcar_less_than_car));
}
UNGCPRO;
produced = encode_coding (coding, addr, buf, len, WRITE_BUF_SIZE,
&consumed);
len -= consumed, addr += consumed;
- if (produced == 0 && len > 0)
- {
- /* There was a carry over because of invalid codes in the source.
- We just write out them as is. */
- bcopy (addr, buf, len);
- produced = len;
- len = 0;
- }
if (produced > 0)
{
produced -= write (desc, buf, produced);
}
static Lisp_Object
-do_auto_save_unwind (desc) /* used as unwind-protect function */
- Lisp_Object desc;
+do_auto_save_unwind (stream) /* used as unwind-protect function */
+ Lisp_Object stream;
{
auto_saving = 0;
- if (XINT (desc) >= 0)
- close (XINT (desc));
+ if (!NILP (stream))
+ fclose ((FILE *) (XFASTINT (XCONS (stream)->car) << 16
+ | XFASTINT (XCONS (stream)->cdr)));
+ return Qnil;
+}
+
+static Lisp_Object
+do_auto_save_unwind_1 (value) /* used as unwind-protect function */
+ Lisp_Object value;
+{
+ minibuffer_auto_raise = XINT (value);
return Qnil;
}
int omessage_length = echo_area_glyphs_length;
int do_handled_files;
Lisp_Object oquit;
- int listdesc;
+ FILE *stream;
+ Lisp_Object lispstream;
int count = specpdl_ptr - specpdl;
int *ptr;
+ int orig_minibuffer_auto_raise = minibuffer_auto_raise;
/* Ordinarily don't quit within this function,
but don't make it impossible to quit (in case we get hung in I/O). */
{
Lisp_Object listfile;
listfile = Fexpand_file_name (Vauto_save_list_file_name, Qnil);
-#ifdef DOS_NT
- listdesc = open (XSTRING (listfile)->data,
- O_WRONLY | O_TRUNC | O_CREAT | O_TEXT,
- S_IREAD | S_IWRITE);
-#else /* not DOS_NT */
- listdesc = creat (XSTRING (listfile)->data, 0666);
-#endif /* not DOS_NT */
+ stream = fopen (XSTRING (listfile)->data, "w");
+
+ /* Arrange to close that file whether or not we get an error.
+ Also reset auto_saving to 0. */
+ lispstream = Fcons (Qnil, Qnil);
+ XSETFASTINT (XCONS (lispstream)->car, (EMACS_UINT)stream >> 16);
+ XSETFASTINT (XCONS (lispstream)->cdr, (EMACS_UINT)stream & 0xffff);
}
else
- listdesc = -1;
-
- /* Arrange to close that file whether or not we get an error.
- Also reset auto_saving to 0. */
- record_unwind_protect (do_auto_save_unwind, make_number (listdesc));
+ {
+ stream = NULL;
+ lispstream = Qnil;
+ }
+ record_unwind_protect (do_auto_save_unwind, lispstream);
+ record_unwind_protect (do_auto_save_unwind_1,
+ make_number (minibuffer_auto_raise));
+ minibuffer_auto_raise = 0;
auto_saving = 1;
/* First, save all files which don't have handlers. If Emacs is
in the special file that lists them. For each of these buffers,
Record visited name (if any) and auto save name. */
if (STRINGP (b->auto_save_file_name)
- && listdesc >= 0 && do_handled_files == 0)
+ && stream != NULL && do_handled_files == 0)
{
if (!NILP (b->filename))
{
- write (listdesc, XSTRING (b->filename)->data,
- XSTRING (b->filename)->size);
+ fwrite (XSTRING (b->filename)->data, 1,
+ XSTRING (b->filename)->size, stream);
}
- write (listdesc, "\n", 1);
- write (listdesc, XSTRING (b->auto_save_file_name)->data,
- XSTRING (b->auto_save_file_name)->size);
- write (listdesc, "\n", 1);
+ putc ('\n', stream);
+ fwrite (XSTRING (b->auto_save_file_name)->data, 1,
+ XSTRING (b->auto_save_file_name)->size, stream);
+ putc ('\n', stream);
}
if (!NILP (current_only)
&& NILP (no_message))
{
/* It has shrunk too much; turn off auto-saving here. */
+ minibuffer_auto_raise = orig_minibuffer_auto_raise;
message ("Buffer %s has shrunk a lot; auto save turned off there",
XSTRING (b->name)->data);
+ minibuffer_auto_raise = 0;
/* Turn off auto-saving until there's a real save,
and prevent any more warnings. */
XSETINT (b->save_length, -1);
{
if (omessage)
{
- sit_for (1, 0, 0, 0);
+ sit_for (1, 0, 0, 0, 0);
message2 (omessage, omessage_length);
}
else
else if (STRINGP (initial))
{
insdef = initial;
- insdef1 = Fcons (double_dollars (insdef), 0);
+ insdef1 = Fcons (double_dollars (insdef), make_number (0));
}
else
insdef = Qnil, insdef1 = Qnil;
GCPRO2 (insdef, default_filename);
val = Fcompleting_read (prompt, intern ("read-file-name-internal"),
dir, mustmatch, insdef1,
- Qfile_name_history);
+ Qfile_name_history, default_filename);
+ /* If Fcompleting_read returned the default string itself
+ (rather than a new string with the same contents),
+ it has to mean that the user typed RET with the minibuffer empty.
+ In that case, we really want to return ""
+ so that commands such as set-visited-file-name can distinguish. */
+ if (EQ (val, default_filename))
+ val = build_string ("");
#ifdef VMS
unbind_to (count, Qnil);
val = Fcompleting_read (prompt, intern ("read-file-name-internal"),
dir, mustmatch,
insert_default_directory ? insdef : Qnil,
- Qfile_name_history);
+ Qfile_name_history, Qnil);
#ifdef VMS
unbind_to (count, Qnil);
This variable affects the built-in functions only on Windows,\n\
on other platforms, it is initialized so that Lisp code can find out\n\
what the normal separator is.");
- Vdirectory_sep_char = '/';
+ XSETFASTINT (Vdirectory_sep_char, '/');
DEFVAR_LISP ("file-name-handler-alist", &Vfile_name_handler_alist,
"*Alist of elements (REGEXP . HANDLER) for file names handled specially.\n\