diff options
| author | Richard M. Stallman | 1994-02-17 08:38:34 +0000 |
|---|---|---|
| committer | Richard M. Stallman | 1994-02-17 08:38:34 +0000 |
| commit | 3d0387c0f3be8e915aef9c5733be5bcec5f8924c (patch) | |
| tree | 30ddff283197c636a14f929990d9d9a86c2c10ec /src | |
| parent | f9456b0a5b508c8b031f9cc996e904d01bcdf697 (diff) | |
| download | emacs-3d0387c0f3be8e915aef9c5733be5bcec5f8924c.tar.gz emacs-3d0387c0f3be8e915aef9c5733be5bcec5f8924c.zip | |
(Finsert_file_contents): New arg REPLACE.
New feature to replace buffer contents with file contents.
Diffstat (limited to 'src')
| -rw-r--r-- | src/fileio.c | 102 |
1 files changed, 97 insertions, 5 deletions
diff --git a/src/fileio.c b/src/fileio.c index ee623182acd..ab2e6396cdb 100644 --- a/src/fileio.c +++ b/src/fileio.c | |||
| @@ -2485,7 +2485,7 @@ Lisp_Object Qfind_buffer_file_type; | |||
| 2485 | #endif | 2485 | #endif |
| 2486 | 2486 | ||
| 2487 | DEFUN ("insert-file-contents", Finsert_file_contents, Sinsert_file_contents, | 2487 | DEFUN ("insert-file-contents", Finsert_file_contents, Sinsert_file_contents, |
| 2488 | 1, 4, 0, | 2488 | 1, 5, 0, |
| 2489 | "Insert contents of file FILENAME after point.\n\ | 2489 | "Insert contents of file FILENAME after point.\n\ |
| 2490 | Returns list of absolute file name and length of data inserted.\n\ | 2490 | Returns list of absolute file name and length of data inserted.\n\ |
| 2491 | If second argument VISIT is non-nil, the buffer's visited filename\n\ | 2491 | If second argument VISIT is non-nil, the buffer's visited filename\n\ |
| @@ -2494,9 +2494,14 @@ If visiting and the file does not exist, visiting is completed\n\ | |||
| 2494 | before the error is signaled.\n\n\ | 2494 | before the error is signaled.\n\n\ |
| 2495 | The optional third and fourth arguments BEG and END\n\ | 2495 | The optional third and fourth arguments BEG and END\n\ |
| 2496 | specify what portion of the file to insert.\n\ | 2496 | specify what portion of the file to insert.\n\ |
| 2497 | If VISIT is non-nil, BEG and END must be nil.") | 2497 | If VISIT is non-nil, BEG and END must be nil.\n\ |
| 2498 | (filename, visit, beg, end) | 2498 | If optional fifth argument REPLACE is non-nil,\n\ |
| 2499 | Lisp_Object filename, visit, beg, end; | 2499 | it means replace the current buffer contents (in the accessible portion)\n\ |
| 2500 | with the file contents. This is better than simply deleting and inserting\n\ | ||
| 2501 | the whole thing because (1) it preserves some marker positions\n\ | ||
| 2502 | and (2) it puts less data in the undo list.") | ||
| 2503 | (filename, visit, beg, end, replace) | ||
| 2504 | Lisp_Object filename, visit, beg, end, replace; | ||
| 2500 | { | 2505 | { |
| 2501 | struct stat st; | 2506 | struct stat st; |
| 2502 | register int fd; | 2507 | register int fd; |
| @@ -2523,7 +2528,8 @@ If VISIT is non-nil, BEG and END must be nil.") | |||
| 2523 | handler = Ffind_file_name_handler (filename); | 2528 | handler = Ffind_file_name_handler (filename); |
| 2524 | if (!NILP (handler)) | 2529 | if (!NILP (handler)) |
| 2525 | { | 2530 | { |
| 2526 | val = call5 (handler, Qinsert_file_contents, filename, visit, beg, end); | 2531 | val = call6 (handler, Qinsert_file_contents, filename, |
| 2532 | visit, beg, end, replace); | ||
| 2527 | goto handled; | 2533 | goto handled; |
| 2528 | } | 2534 | } |
| 2529 | 2535 | ||
| @@ -2579,6 +2585,92 @@ If VISIT is non-nil, BEG and END must be nil.") | |||
| 2579 | error ("maximum buffer size exceeded"); | 2585 | error ("maximum buffer size exceeded"); |
| 2580 | } | 2586 | } |
| 2581 | 2587 | ||
| 2588 | /* If requested, replace the accessible part of the buffer | ||
| 2589 | with the file contents. Avoid replacing text at the | ||
| 2590 | beginning or end of the buffer that matches the file contents; | ||
| 2591 | that preserves markers pointing to the unchanged parts. */ | ||
| 2592 | if (!NILP (replace)) | ||
| 2593 | { | ||
| 2594 | char buffer[1 << 14]; | ||
| 2595 | int same_at_start = BEGV; | ||
| 2596 | int same_at_end = ZV; | ||
| 2597 | immediate_quit = 1; | ||
| 2598 | QUIT; | ||
| 2599 | /* Count how many chars at the start of the file | ||
| 2600 | match the text at the beginning of the buffer. */ | ||
| 2601 | while (1) | ||
| 2602 | { | ||
| 2603 | int nread, bufpos; | ||
| 2604 | |||
| 2605 | nread = read (fd, buffer, sizeof buffer); | ||
| 2606 | if (nread < 0) | ||
| 2607 | error ("IO error reading %s: %s", | ||
| 2608 | XSTRING (filename)->data, strerror (errno)); | ||
| 2609 | else if (nread == 0) | ||
| 2610 | break; | ||
| 2611 | bufpos = 0; | ||
| 2612 | while (bufpos < nread && same_at_start < ZV | ||
| 2613 | && FETCH_CHAR (same_at_start) == buffer[bufpos]) | ||
| 2614 | same_at_start++, bufpos++; | ||
| 2615 | /* If we found a discrepancy, stop the scan. | ||
| 2616 | Otherwise loop around and scan the next bufferfull. */ | ||
| 2617 | if (bufpos != nread) | ||
| 2618 | break; | ||
| 2619 | } | ||
| 2620 | immediate_quit = 0; | ||
| 2621 | /* If the file matches the buffer completely, | ||
| 2622 | there's no need to replace anything. */ | ||
| 2623 | if (same_at_start == ZV) | ||
| 2624 | { | ||
| 2625 | close (fd); | ||
| 2626 | goto handled; | ||
| 2627 | } | ||
| 2628 | immediate_quit = 1; | ||
| 2629 | QUIT; | ||
| 2630 | /* Count how many chars at the end of the file | ||
| 2631 | match the text at the end of the buffer. */ | ||
| 2632 | while (1) | ||
| 2633 | { | ||
| 2634 | int total_read, nread, bufpos, curpos, trial; | ||
| 2635 | |||
| 2636 | /* At what file position are we now scanning? */ | ||
| 2637 | curpos = st.st_size - (ZV - same_at_end); | ||
| 2638 | /* How much can we scan in the next step? */ | ||
| 2639 | trial = min (curpos, sizeof buffer); | ||
| 2640 | if (lseek (fd, curpos - trial, 0) < 0) | ||
| 2641 | report_file_error ("Setting file position", | ||
| 2642 | Fcons (filename, Qnil)); | ||
| 2643 | |||
| 2644 | total_read = 0; | ||
| 2645 | while (total_read < trial) | ||
| 2646 | { | ||
| 2647 | nread = read (fd, buffer + total_read, trial - total_read); | ||
| 2648 | if (nread <= 0) | ||
| 2649 | error ("IO error reading %s: %s", | ||
| 2650 | XSTRING (filename)->data, strerror (errno)); | ||
| 2651 | total_read += nread; | ||
| 2652 | } | ||
| 2653 | /* Scan this bufferfull from the end, comparing with | ||
| 2654 | the Emacs buffer. */ | ||
| 2655 | bufpos = total_read; | ||
| 2656 | /* Compare with same_at_start to avoid counting some buffer text | ||
| 2657 | as matching both at the file's beginning and at the end. */ | ||
| 2658 | while (bufpos > 0 && same_at_end > same_at_start | ||
| 2659 | && FETCH_CHAR (same_at_end - 1) == buffer[bufpos - 1]) | ||
| 2660 | same_at_end--, bufpos--; | ||
| 2661 | /* If we found a discrepancy, stop the scan. | ||
| 2662 | Otherwise loop around and scan the preceding bufferfull. */ | ||
| 2663 | if (bufpos != 0) | ||
| 2664 | break; | ||
| 2665 | } | ||
| 2666 | immediate_quit = 0; | ||
| 2667 | /* Arrange to read only the nonmatching middle part of the file. */ | ||
| 2668 | XFASTINT (beg) = same_at_start - BEGV; | ||
| 2669 | XFASTINT (end) = st.st_size - (ZV - same_at_end); | ||
| 2670 | /* Delete the nonmatching middle part of the buffer. */ | ||
| 2671 | Fdelete_region (make_number (same_at_start), make_number (same_at_end)); | ||
| 2672 | } | ||
| 2673 | |||
| 2582 | total = XINT (end) - XINT (beg); | 2674 | total = XINT (end) - XINT (beg); |
| 2583 | 2675 | ||
| 2584 | { | 2676 | { |