diff options
Diffstat (limited to 'src/fileio.c')
-rw-r--r-- | src/fileio.c | 167 |
1 files changed, 116 insertions, 51 deletions
diff --git a/src/fileio.c b/src/fileio.c index 6af3386b82a..983bd72d282 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -3695,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; { @@ -3725,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; @@ -3749,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); @@ -4681,24 +4680,103 @@ 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; + + TEMP_SET_PT_BOTH (BEGV, BEGV_BYTE); + insval = call3 (Qformat_decode, + Qnil, make_number (oinserted), visit); + CHECK_NUMBER (insval); + if (XINT (insval) == oinserted) + SET_PT_BOTH (opoint, opoint_byte); + 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; + + TEMP_SET_PT_BOTH (BEGV, BEGV_BYTE); + insval = call1 (XCAR (p), make_number (oinserted)); + if (!NILP (insval)) + { + CHECK_NUMBER (insval); + if (XINT (insval) == oinserted) + SET_PT_BOTH (opoint, opoint_byte); + 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 @@ -4711,19 +4789,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) { @@ -5144,7 +5209,7 @@ This does code conversion according to the value of * if we do writes that don't end with a carriage return. Furthermore * it cannot handle writes of more then 16K. The modified * version of "sys_write" in SYSDEP.C (see comment there) copes with - * this EXCEPT for the last record (iff it doesn't end with a carriage + * this EXCEPT for the last record (if it doesn't end with a carriage * return). This implies that if your buffer doesn't end with a carriage * return, you get one free... tough. However it also means that if * we make two calls to sys_write (a la the following code) you can |