summaryrefslogtreecommitdiff
path: root/src/fileio.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/fileio.c')
-rw-r--r--src/fileio.c205
1 files changed, 146 insertions, 59 deletions
diff --git a/src/fileio.c b/src/fileio.c
index ef2b0cfbb2e..d921916a4de 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -21,6 +21,7 @@ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA. */
#include <config.h>
+#include <limits.h>
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
@@ -78,6 +79,8 @@ extern int errno;
#include "coding.h"
#include "window.h"
#include "blockinput.h"
+#include "frame.h"
+#include "dispextern.h"
#ifdef WINDOWSNT
#define NOMINMAX 1
@@ -2463,8 +2466,8 @@ uid and gid of FILE to NEWNAME. */)
if (NILP (handler))
handler = Ffind_file_name_handler (newname, Qcopy_file);
if (!NILP (handler))
- RETURN_UNGCPRO (call5 (handler, Qcopy_file, file, newname,
- ok_if_already_exists, keep_time));
+ RETURN_UNGCPRO (call6 (handler, Qcopy_file, file, newname,
+ ok_if_already_exists, keep_time, preserve_uid_gid));
encoded_file = ENCODE_FILE (file);
encoded_newname = ENCODE_FILE (newname);
@@ -3433,7 +3436,9 @@ Return nil, if file does not exist or is not accessible. */)
return make_number (st.st_mode & 07777);
}
-DEFUN ("set-file-modes", Fset_file_modes, Sset_file_modes, 2, 2, 0,
+DEFUN ("set-file-modes", Fset_file_modes, Sset_file_modes, 2, 2,
+ "(let ((file (read-file-name \"File: \"))) \
+ (list file (read-file-modes nil file)))",
doc: /* Set mode bits of file named FILENAME to MODE (an integer).
Only the 12 low bits of MODE are used. */)
(filename, mode)
@@ -3690,27 +3695,25 @@ DEFUN ("insert-file-contents", Finsert_file_contents, Sinsert_file_contents,
1, 5, 0,
doc: /* Insert contents of file FILENAME after point.
Returns list of absolute file name and number of characters inserted.
-If second argument VISIT is non-nil, the buffer's visited filename
-and last save file modtime are set, and it is marked unmodified.
-If visiting and the file does not exist, visiting is completed
-before the error is signaled.
-The optional third and fourth arguments BEG and END
-specify what portion of the file to insert.
-These arguments count bytes in the file, not characters in the buffer.
-If VISIT is non-nil, BEG and END must be nil.
-
-If optional fifth argument REPLACE is non-nil,
-it means replace the current buffer contents (in the accessible portion)
-with the file contents. This is better than simply deleting and inserting
-the whole thing because (1) it preserves some marker positions
-and (2) it puts less data in the undo list.
-When REPLACE is non-nil, the value is the number of characters actually read,
-which is often less than the number of characters to be read.
-
-This does code conversion according to the value of
-`coding-system-for-read' or `file-coding-system-alist',
-and sets the variable `last-coding-system-used' to the coding system
-actually used. */)
+If second argument VISIT is non-nil, the buffer's visited filename and
+last save file modtime are set, and it is marked unmodified. If
+visiting and the file does not exist, visiting is completed before the
+error is signaled.
+
+The optional third and fourth arguments BEG and END specify what portion
+of the file to insert. These arguments count bytes in the file, not
+characters in the buffer. If VISIT is non-nil, BEG and END must be nil.
+
+If optional fifth argument REPLACE is non-nil, replace the current
+buffer contents (in the accessible portion) with the file contents.
+This is better than simply deleting and inserting the whole thing
+because (1) it preserves some marker positions and (2) it puts less data
+in the undo list. When REPLACE is non-nil, the second return value is
+the number of characters that replace previous buffer contents.
+
+This function does code conversion according to the value of
+`coding-system-for-read' or `file-coding-system-alist', and sets the
+variable `last-coding-system-used' to the coding system actually used. */)
(filename, visit, beg, end, replace)
Lisp_Object filename, visit, beg, end, replace;
{
@@ -3720,8 +3723,8 @@ actually used. */)
register int how_much;
register int unprocessed;
int count = SPECPDL_INDEX ();
- struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
- Lisp_Object handler, val, insval, orig_filename;
+ struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
+ Lisp_Object handler, val, insval, orig_filename, old_undo;
Lisp_Object p;
int total = 0;
int not_regular = 0;
@@ -3744,8 +3747,9 @@ actually used. */)
val = Qnil;
p = Qnil;
orig_filename = Qnil;
+ old_undo = Qnil;
- GCPRO4 (filename, val, p, orig_filename);
+ GCPRO5 (filename, val, p, orig_filename, old_undo);
CHECK_STRING (filename);
filename = Fexpand_file_name (filename, Qnil);
@@ -3860,7 +3864,7 @@ actually used. */)
overflow. The calculations below double the file size
twice, so check that it can be multiplied by 4 safely. */
if (XINT (end) != st.st_size
- || ((int) st.st_size * 4) / 4 != st.st_size)
+ || st.st_size > INT_MAX / 4)
error ("Maximum buffer size exceeded");
/* The file size returned from stat may be zero, but data
@@ -4704,24 +4708,119 @@ actually used. */)
/* Decode file format */
if (inserted > 0)
{
- int empty_undo_list_p = 0;
+ /* Don't run point motion or modification hooks when decoding. */
+ int count = SPECPDL_INDEX ();
+ specbind (Qinhibit_point_motion_hooks, Qt);
+ specbind (Qinhibit_modification_hooks, Qt);
+
+ /* Save old undo list and don't record undo for decoding. */
+ old_undo = current_buffer->undo_list;
+ current_buffer->undo_list = Qt;
- /* If we're anyway going to discard undo information, don't
- record it in the first place. The buffer's undo list at this
- point is either nil or t when visiting a file. */
- if (!NILP (visit))
+ if (NILP (replace))
{
- empty_undo_list_p = NILP (current_buffer->undo_list);
- current_buffer->undo_list = Qt;
+ insval = call3 (Qformat_decode,
+ Qnil, make_number (inserted), visit);
+ CHECK_NUMBER (insval);
+ inserted = XFASTINT (insval);
+ }
+ else
+ {
+ /* If REPLACE is non-nil and we succeeded in not replacing the
+ beginning or end of the buffer text with the file's contents,
+ call format-decode with `point' positioned at the beginning of
+ the buffer and `inserted' equalling the number of characters
+ in the buffer. Otherwise, format-decode might fail to
+ correctly analyze the beginning or end of the buffer. Hence
+ we temporarily save `point' and `inserted' here and restore
+ `point' iff format-decode did not insert or delete any text.
+ Otherwise we leave `point' at point-min. */
+ int opoint = PT;
+ int opoint_byte = PT_BYTE;
+ int oinserted = ZV - BEGV;
+ int ochars_modiff = CHARS_MODIFF;
+
+ TEMP_SET_PT_BOTH (BEGV, BEGV_BYTE);
+ insval = call3 (Qformat_decode,
+ Qnil, make_number (oinserted), visit);
+ CHECK_NUMBER (insval);
+ if (ochars_modiff == CHARS_MODIFF)
+ /* format_decode didn't modify buffer's characters => move
+ point back to position before inserted text and leave
+ value of inserted alone. */
+ SET_PT_BOTH (opoint, opoint_byte);
+ else
+ /* format_decode modified buffer's characters => consider
+ entire buffer changed and leave point at point-min. */
+ inserted = XFASTINT (insval);
}
- insval = call3 (Qformat_decode,
- Qnil, make_number (inserted), visit);
- CHECK_NUMBER (insval);
- inserted = XFASTINT (insval);
+ /* For consistency with format-decode call these now iff inserted > 0
+ (martin 2007-06-28) */
+ p = Vafter_insert_file_functions;
+ while (CONSP (p))
+ {
+ if (NILP (replace))
+ {
+ insval = call1 (XCAR (p), make_number (inserted));
+ if (!NILP (insval))
+ {
+ CHECK_NUMBER (insval);
+ inserted = XFASTINT (insval);
+ }
+ }
+ else
+ {
+ /* For the rationale of this see the comment on format-decode above. */
+ int opoint = PT;
+ int opoint_byte = PT_BYTE;
+ int oinserted = ZV - BEGV;
+ int ochars_modiff = CHARS_MODIFF;
+
+ TEMP_SET_PT_BOTH (BEGV, BEGV_BYTE);
+ insval = call1 (XCAR (p), make_number (oinserted));
+ if (!NILP (insval))
+ {
+ CHECK_NUMBER (insval);
+ if (ochars_modiff == CHARS_MODIFF)
+ /* after_insert_file_functions didn't modify
+ buffer's characters => move point back to
+ position before inserted text and leave value of
+ inserted alone. */
+ SET_PT_BOTH (opoint, opoint_byte);
+ else
+ /* after_insert_file_functions did modify buffer's
+ characters => consider entire buffer changed and
+ leave point at point-min. */
+ inserted = XFASTINT (insval);
+ }
+ }
+
+ QUIT;
+ p = XCDR (p);
+ }
+
+ if (NILP (visit))
+ {
+ Lisp_Object lbeg, lend;
+ XSETINT (lbeg, PT);
+ XSETINT (lend, PT + inserted);
+ if (CONSP (old_undo))
+ {
+ Lisp_Object tem = XCAR (old_undo);
+ if (CONSP (tem) && INTEGERP (XCAR (tem)) &&
+ INTEGERP (XCDR (tem)) && EQ (XCAR (tem), lbeg))
+ /* In the non-visiting case record only the final insertion. */
+ current_buffer->undo_list =
+ Fcons (Fcons (lbeg, lend), Fcdr (old_undo));
+ }
+ }
+ else
+ /* If undo_list was Qt before, keep it that way.
+ Otherwise start with an empty undo_list. */
+ current_buffer->undo_list = EQ (old_undo, Qt) ? Qt : Qnil;
- if (!NILP (visit))
- current_buffer->undo_list = empty_undo_list_p ? Qnil : Qt;
+ unbind_to (count, Qnil);
}
/* Call after-change hooks for the inserted text, aside from the case
@@ -4734,19 +4833,6 @@ actually used. */)
update_compositions (PT, PT, CHECK_BORDER);
}
- p = Vafter_insert_file_functions;
- while (CONSP (p))
- {
- insval = call1 (XCAR (p), make_number (inserted));
- if (!NILP (insval))
- {
- CHECK_NUMBER (insval);
- inserted = XFASTINT (insval);
- }
- QUIT;
- p = XCDR (p);
- }
-
if (!NILP (visit)
&& current_buffer->modtime == -1)
{
@@ -5746,7 +5832,7 @@ auto_save_error (error)
char *msgbuf;
USE_SAFE_ALLOCA;
- ring_bell ();
+ ring_bell (XFRAME (selected_frame));
args[0] = build_string ("Auto-saving %s: %s");
args[1] = current_buffer->name;
@@ -6309,7 +6395,7 @@ and `read-file-name-function'. */)
/* If dir starts with user's homedir, change that to ~. */
homedir = (char *) egetenv ("HOME");
#ifdef DOS_NT
- /* homedir can be NULL in temacs, since Vprocess_environment is not
+ /* homedir can be NULL in temacs, since Vglobal_environment is not
yet set up. We shouldn't crash in that case. */
if (homedir != 0)
{
@@ -6431,7 +6517,7 @@ and `read-file-name-function'. */)
if (! replace_in_history)
add_to_history = 1;
- val = empty_string;
+ val = empty_unibyte_string;
}
unbind_to (count, Qnil);
@@ -6684,8 +6770,9 @@ or local variable spec of the tailing lines with `coding:' tag. */);
DEFVAR_LISP ("after-insert-file-functions", &Vafter_insert_file_functions,
doc: /* A list of functions to be called at the end of `insert-file-contents'.
-Each is passed one argument, the number of characters inserted.
-It should return the new character count, and leave point the same.
+Each is passed one argument, the number of characters inserted,
+with point at the start of the inserted text. Each function
+should leave point the same, and return the new character count.
If `insert-file-contents' is intercepted by a handler from
`file-name-handler-alist', that handler is responsible for calling the
functions in `after-insert-file-functions' if appropriate. */);