diff options
Diffstat (limited to 'src/fileio.c')
-rw-r--r-- | src/fileio.c | 205 |
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. */); |