diff options
| author | Richard M. Stallman | 1993-10-09 21:30:48 +0000 |
|---|---|---|
| committer | Richard M. Stallman | 1993-10-09 21:30:48 +0000 |
| commit | d6a3cc1563d5c25456f430a3087b4fa6fd3505dd (patch) | |
| tree | 8e8a40607def489b88b542e23b6934cb24ae888a /src | |
| parent | 149df30fea0649d3909979b7215e9c20f93d6ac6 (diff) | |
| download | emacs-d6a3cc1563d5c25456f430a3087b4fa6fd3505dd.tar.gz emacs-d6a3cc1563d5c25456f430a3087b4fa6fd3505dd.zip | |
(Vafter_insert_file_functions): New variable.
(Vwrite_region_annotate_functions): New variable.
(Qcar_less_than_car): New variable.
(Fcar_less_than_car): New function.
(syms_of_fileio): Make Lisp variables and function available.
staticpro Qcar_less_than_car.
(a_write, build_annotations): New functions.
(Fwrite_region): Call them.
(Finsert_file_contents): Run the Vafter_insert_file_functions.
Diffstat (limited to 'src')
| -rw-r--r-- | src/fileio.c | 178 |
1 files changed, 164 insertions, 14 deletions
diff --git a/src/fileio.c b/src/fileio.c index 347585fc4d2..c2fca1b375b 100644 --- a/src/fileio.c +++ b/src/fileio.c | |||
| @@ -100,6 +100,12 @@ int auto_save_mode_bits; | |||
| 100 | whose I/O is done with a special handler. */ | 100 | whose I/O is done with a special handler. */ |
| 101 | Lisp_Object Vfile_name_handler_alist; | 101 | Lisp_Object Vfile_name_handler_alist; |
| 102 | 102 | ||
| 103 | /* Functions to be called to process text properties in inserted file. */ | ||
| 104 | Lisp_Object Vafter_insert_file_functions; | ||
| 105 | |||
| 106 | /* Functions to be called to create text property annotations for file. */ | ||
| 107 | Lisp_Object Vwrite_region_annotate_functions; | ||
| 108 | |||
| 103 | /* Nonzero means, when reading a filename in the minibuffer, | 109 | /* Nonzero means, when reading a filename in the minibuffer, |
| 104 | start out by inserting the default directory into the minibuffer. */ | 110 | start out by inserting the default directory into the minibuffer. */ |
| 105 | int insert_default_directory; | 111 | int insert_default_directory; |
| @@ -112,6 +118,8 @@ Lisp_Object Qfile_error, Qfile_already_exists; | |||
| 112 | 118 | ||
| 113 | Lisp_Object Qfile_name_history; | 119 | Lisp_Object Qfile_name_history; |
| 114 | 120 | ||
| 121 | Lisp_Object Qcar_less_than_car; | ||
| 122 | |||
| 115 | report_file_error (string, data) | 123 | report_file_error (string, data) |
| 116 | char *string; | 124 | char *string; |
| 117 | Lisp_Object data; | 125 | Lisp_Object data; |
| @@ -2353,13 +2361,15 @@ If VISIT is non-nil, BEG and END must be nil.") | |||
| 2353 | register int inserted = 0; | 2361 | register int inserted = 0; |
| 2354 | register int how_much; | 2362 | register int how_much; |
| 2355 | int count = specpdl_ptr - specpdl; | 2363 | int count = specpdl_ptr - specpdl; |
| 2356 | struct gcpro gcpro1; | 2364 | struct gcpro gcpro1, gcpro2; |
| 2357 | Lisp_Object handler, val; | 2365 | Lisp_Object handler, val, insval; |
| 2366 | Lisp_Object p; | ||
| 2358 | int total; | 2367 | int total; |
| 2359 | 2368 | ||
| 2360 | val = Qnil; | 2369 | val = Qnil; |
| 2370 | p = Qnil; | ||
| 2361 | 2371 | ||
| 2362 | GCPRO1 (filename); | 2372 | GCPRO2 (filename, p); |
| 2363 | if (!NILP (current_buffer->read_only)) | 2373 | if (!NILP (current_buffer->read_only)) |
| 2364 | Fbarf_if_buffer_read_only(); | 2374 | Fbarf_if_buffer_read_only(); |
| 2365 | 2375 | ||
| @@ -2523,6 +2533,22 @@ If VISIT is non-nil, BEG and END must be nil.") | |||
| 2523 | 2533 | ||
| 2524 | signal_after_change (point, 0, inserted); | 2534 | signal_after_change (point, 0, inserted); |
| 2525 | 2535 | ||
| 2536 | if (inserted > 0) | ||
| 2537 | { | ||
| 2538 | p = Vafter_insert_file_functions; | ||
| 2539 | while (!NILP (p)) | ||
| 2540 | { | ||
| 2541 | insval = call1 (Fcar (p), make_number (inserted)); | ||
| 2542 | if (!NILP (insval)) | ||
| 2543 | { | ||
| 2544 | CHECK_NUMBER (insval, 0); | ||
| 2545 | inserted = XFASTINT (insval); | ||
| 2546 | } | ||
| 2547 | QUIT; | ||
| 2548 | p = Fcdr (p); | ||
| 2549 | } | ||
| 2550 | } | ||
| 2551 | |||
| 2526 | if (!NILP (val)) | 2552 | if (!NILP (val)) |
| 2527 | RETURN_UNGCPRO (val); | 2553 | RETURN_UNGCPRO (val); |
| 2528 | RETURN_UNGCPRO (Fcons (filename, | 2554 | RETURN_UNGCPRO (Fcons (filename, |
| @@ -2530,6 +2556,8 @@ If VISIT is non-nil, BEG and END must be nil.") | |||
| 2530 | Qnil))); | 2556 | Qnil))); |
| 2531 | } | 2557 | } |
| 2532 | 2558 | ||
| 2559 | static Lisp_Object build_annotations (); | ||
| 2560 | |||
| 2533 | DEFUN ("write-region", Fwrite_region, Swrite_region, 3, 5, | 2561 | DEFUN ("write-region", Fwrite_region, Swrite_region, 3, 5, |
| 2534 | "r\nFWrite region to file: ", | 2562 | "r\nFWrite region to file: ", |
| 2535 | "Write current region into specified file.\n\ | 2563 | "Write current region into specified file.\n\ |
| @@ -2555,13 +2583,15 @@ to the file, instead of any buffer contents, and END is ignored.") | |||
| 2555 | int save_errno; | 2583 | int save_errno; |
| 2556 | unsigned char *fn; | 2584 | unsigned char *fn; |
| 2557 | struct stat st; | 2585 | struct stat st; |
| 2558 | int tem; | 2586 | int tem, tem2; |
| 2559 | int count = specpdl_ptr - specpdl; | 2587 | int count = specpdl_ptr - specpdl; |
| 2560 | #ifdef VMS | 2588 | #ifdef VMS |
| 2561 | unsigned char *fname = 0; /* If non-0, original filename (must rename) */ | 2589 | unsigned char *fname = 0; /* If non-0, original filename (must rename) */ |
| 2562 | #endif /* VMS */ | 2590 | #endif /* VMS */ |
| 2563 | Lisp_Object handler; | 2591 | Lisp_Object handler; |
| 2564 | Lisp_Object visit_file; | 2592 | Lisp_Object visit_file; |
| 2593 | Lisp_Object annotations; | ||
| 2594 | int visiting, quietly; | ||
| 2565 | struct gcpro gcpro1, gcpro2, gcpro3, gcpro4; | 2595 | struct gcpro gcpro1, gcpro2, gcpro3, gcpro4; |
| 2566 | 2596 | ||
| 2567 | /* Special kludge to simplify auto-saving */ | 2597 | /* Special kludge to simplify auto-saving */ |
| @@ -2579,7 +2609,12 @@ to the file, instead of any buffer contents, and END is ignored.") | |||
| 2579 | else | 2609 | else |
| 2580 | visit_file = filename; | 2610 | visit_file = filename; |
| 2581 | 2611 | ||
| 2582 | GCPRO4 (start, filename, visit, visit_file); | 2612 | visiting = (EQ (visit, Qt) || XTYPE (visit) == Lisp_String); |
| 2613 | quietly = !NILP (visit); | ||
| 2614 | |||
| 2615 | annotations = Qnil; | ||
| 2616 | |||
| 2617 | GCPRO4 (start, filename, annotations, visit_file); | ||
| 2583 | 2618 | ||
| 2584 | /* If the file name has special constructs in it, | 2619 | /* If the file name has special constructs in it, |
| 2585 | call the corresponding file handler. */ | 2620 | call the corresponding file handler. */ |
| @@ -2594,7 +2629,7 @@ to the file, instead of any buffer contents, and END is ignored.") | |||
| 2594 | /* Do this before reporting IO error | 2629 | /* Do this before reporting IO error |
| 2595 | to avoid a "file has changed on disk" warning on | 2630 | to avoid a "file has changed on disk" warning on |
| 2596 | next attempt to save. */ | 2631 | next attempt to save. */ |
| 2597 | if (EQ (visit, Qt) || XTYPE (visit) == Lisp_String) | 2632 | if (visiting) |
| 2598 | { | 2633 | { |
| 2599 | current_buffer->modtime = 0; | 2634 | current_buffer->modtime = 0; |
| 2600 | current_buffer->save_modified = MODIFF; | 2635 | current_buffer->save_modified = MODIFF; |
| @@ -2605,6 +2640,8 @@ to the file, instead of any buffer contents, and END is ignored.") | |||
| 2605 | return val; | 2640 | return val; |
| 2606 | } | 2641 | } |
| 2607 | 2642 | ||
| 2643 | annotations = build_annotations (start, end); | ||
| 2644 | |||
| 2608 | #ifdef CLASH_DETECTION | 2645 | #ifdef CLASH_DETECTION |
| 2609 | if (!auto_saving) | 2646 | if (!auto_saving) |
| 2610 | lock_file (visit_file); | 2647 | lock_file (visit_file); |
| @@ -2713,18 +2750,20 @@ to the file, instead of any buffer contents, and END is ignored.") | |||
| 2713 | 2750 | ||
| 2714 | if (XTYPE (start) == Lisp_String) | 2751 | if (XTYPE (start) == Lisp_String) |
| 2715 | { | 2752 | { |
| 2716 | failure = 0 > e_write (desc, XSTRING (start)->data, | 2753 | failure = 0 > a_write (desc, XSTRING (start)->data, |
| 2717 | XSTRING (start)->size); | 2754 | XSTRING (start)->size, 0, &annotations); |
| 2718 | save_errno = errno; | 2755 | save_errno = errno; |
| 2719 | } | 2756 | } |
| 2720 | else if (XINT (start) != XINT (end)) | 2757 | else if (XINT (start) != XINT (end)) |
| 2721 | { | 2758 | { |
| 2759 | tem2 = 1; | ||
| 2722 | if (XINT (start) < GPT) | 2760 | if (XINT (start) < GPT) |
| 2723 | { | 2761 | { |
| 2724 | register int end1 = XINT (end); | 2762 | register int end1 = XINT (end); |
| 2725 | tem = XINT (start); | 2763 | tem = XINT (start); |
| 2726 | failure = 0 > e_write (desc, &FETCH_CHAR (tem), | 2764 | failure = 0 > a_write (desc, &FETCH_CHAR (tem), |
| 2727 | min (GPT, end1) - tem); | 2765 | min (GPT, end1) - tem, 1, &annotations); |
| 2766 | tem2 += min (GPT, end1) - tem; | ||
| 2728 | save_errno = errno; | 2767 | save_errno = errno; |
| 2729 | } | 2768 | } |
| 2730 | 2769 | ||
| @@ -2732,7 +2771,15 @@ to the file, instead of any buffer contents, and END is ignored.") | |||
| 2732 | { | 2771 | { |
| 2733 | tem = XINT (start); | 2772 | tem = XINT (start); |
| 2734 | tem = max (tem, GPT); | 2773 | tem = max (tem, GPT); |
| 2735 | failure = 0 > e_write (desc, &FETCH_CHAR (tem), XINT (end) - tem); | 2774 | failure = 0 > a_write (desc, &FETCH_CHAR (tem), XINT (end) - tem, |
| 2775 | tem2, &annotations); | ||
| 2776 | tem2 += XINT (end) - tem; | ||
| 2777 | save_errno = errno; | ||
| 2778 | } | ||
| 2779 | if (tem2 == 1) | ||
| 2780 | { | ||
| 2781 | /* If file was empty, still need to write the annotations */ | ||
| 2782 | failure = 0 > a_write (desc, "", 0, 1, &annotations); | ||
| 2736 | save_errno = errno; | 2783 | save_errno = errno; |
| 2737 | } | 2784 | } |
| 2738 | } | 2785 | } |
| @@ -2795,19 +2842,19 @@ to the file, instead of any buffer contents, and END is ignored.") | |||
| 2795 | /* Do this before reporting IO error | 2842 | /* Do this before reporting IO error |
| 2796 | to avoid a "file has changed on disk" warning on | 2843 | to avoid a "file has changed on disk" warning on |
| 2797 | next attempt to save. */ | 2844 | next attempt to save. */ |
| 2798 | if (EQ (visit, Qt) || XTYPE (visit) == Lisp_String) | 2845 | if (visiting) |
| 2799 | current_buffer->modtime = st.st_mtime; | 2846 | current_buffer->modtime = st.st_mtime; |
| 2800 | 2847 | ||
| 2801 | if (failure) | 2848 | if (failure) |
| 2802 | error ("IO error writing %s: %s", fn, err_str (save_errno)); | 2849 | error ("IO error writing %s: %s", fn, err_str (save_errno)); |
| 2803 | 2850 | ||
| 2804 | if (EQ (visit, Qt) || XTYPE (visit) == Lisp_String) | 2851 | if (visiting) |
| 2805 | { | 2852 | { |
| 2806 | current_buffer->save_modified = MODIFF; | 2853 | current_buffer->save_modified = MODIFF; |
| 2807 | XFASTINT (current_buffer->save_length) = Z - BEG; | 2854 | XFASTINT (current_buffer->save_length) = Z - BEG; |
| 2808 | current_buffer->filename = visit_file; | 2855 | current_buffer->filename = visit_file; |
| 2809 | } | 2856 | } |
| 2810 | else if (!NILP (visit)) | 2857 | else if (quietly) |
| 2811 | return Qnil; | 2858 | return Qnil; |
| 2812 | 2859 | ||
| 2813 | if (!auto_saving) | 2860 | if (!auto_saving) |
| @@ -2816,6 +2863,87 @@ to the file, instead of any buffer contents, and END is ignored.") | |||
| 2816 | return Qnil; | 2863 | return Qnil; |
| 2817 | } | 2864 | } |
| 2818 | 2865 | ||
| 2866 | Lisp_Object merge (); | ||
| 2867 | |||
| 2868 | DEFUN ("car-less-than-car", Fcar_less_than_car, Scar_less_than_car, 2, 2, 0, | ||
| 2869 | "Return t if (car A) is numerically less than (car B)." | ||
| 2870 | (a, b) | ||
| 2871 | Lisp_Object a, b; | ||
| 2872 | { | ||
| 2873 | return Flss (Fcar (a), Fcar (b)); | ||
| 2874 | } | ||
| 2875 | |||
| 2876 | /* Build the complete list of annotations appropriate for writing out | ||
| 2877 | the text between START and END, by calling all the functions in | ||
| 2878 | write-region-annotate-functions and merging the lists they return. */ | ||
| 2879 | |||
| 2880 | static Lisp_Object | ||
| 2881 | build_annotations (start, end) | ||
| 2882 | Lisp_Object start, end; | ||
| 2883 | { | ||
| 2884 | Lisp_Object annotations; | ||
| 2885 | Lisp_Object p, res; | ||
| 2886 | struct gcpro gcpro1, gcpro2; | ||
| 2887 | |||
| 2888 | annotations = Qnil; | ||
| 2889 | p = Vwrite_region_annotate_functions; | ||
| 2890 | GCPRO2 (annotations, p); | ||
| 2891 | while (!NILP (p)) | ||
| 2892 | { | ||
| 2893 | res = call2 (Fcar (p), start, end); | ||
| 2894 | Flength (res); /* Check basic validity of return value */ | ||
| 2895 | annotations = merge (annotations, res, Qcar_less_than_car); | ||
| 2896 | p = Fcdr (p); | ||
| 2897 | } | ||
| 2898 | UNGCPRO; | ||
| 2899 | return annotations; | ||
| 2900 | } | ||
| 2901 | |||
| 2902 | /* Write to descriptor DESC the LEN characters starting at ADDR, | ||
| 2903 | assuming they start at position POS in the buffer. | ||
| 2904 | Intersperse with them the annotations from *ANNOT | ||
| 2905 | (those which fall within the range of positions POS to POS + LEN), | ||
| 2906 | each at its appropriate position. | ||
| 2907 | |||
| 2908 | Modify *ANNOT by discarding elements as we output them. | ||
| 2909 | The return value is negative in case of system call failure. */ | ||
| 2910 | |||
| 2911 | int | ||
| 2912 | a_write (desc, addr, len, pos, annot) | ||
| 2913 | int desc; | ||
| 2914 | register char *addr; | ||
| 2915 | register int len; | ||
| 2916 | int pos; | ||
| 2917 | Lisp_Object *annot; | ||
| 2918 | { | ||
| 2919 | Lisp_Object tem; | ||
| 2920 | int nextpos; | ||
| 2921 | int lastpos = pos + len; | ||
| 2922 | |||
| 2923 | while (1) | ||
| 2924 | { | ||
| 2925 | tem = Fcar_safe (Fcar (*annot)); | ||
| 2926 | if (INTEGERP (tem) && XINT (tem) >= pos && XFASTINT (tem) <= lastpos) | ||
| 2927 | nextpos = XFASTINT (tem); | ||
| 2928 | else | ||
| 2929 | return e_write (desc, addr, lastpos - pos); | ||
| 2930 | if (nextpos > pos) | ||
| 2931 | { | ||
| 2932 | if (0 > e_write (desc, addr, nextpos - pos)) | ||
| 2933 | return -1; | ||
| 2934 | addr += nextpos - pos; | ||
| 2935 | pos = nextpos; | ||
| 2936 | } | ||
| 2937 | tem = Fcdr (Fcar (*annot)); | ||
| 2938 | if (STRINGP (tem)) | ||
| 2939 | { | ||
| 2940 | if (0 > e_write (desc, XSTRING (tem)->data, XSTRING (tem)->size)) | ||
| 2941 | return -1; | ||
| 2942 | } | ||
| 2943 | *annot = Fcdr (*annot); | ||
| 2944 | } | ||
| 2945 | } | ||
| 2946 | |||
| 2819 | int | 2947 | int |
| 2820 | e_write (desc, addr, len) | 2948 | e_write (desc, addr, len) |
| 2821 | int desc; | 2949 | int desc; |
| @@ -3411,6 +3539,9 @@ syms_of_fileio () | |||
| 3411 | Qfile_already_exists = intern("file-already-exists"); | 3539 | Qfile_already_exists = intern("file-already-exists"); |
| 3412 | staticpro (&Qfile_already_exists); | 3540 | staticpro (&Qfile_already_exists); |
| 3413 | 3541 | ||
| 3542 | Qcar_less_than_car = intern ("car-less-than-car"); | ||
| 3543 | staticpro (&Qcar_less_than_car); | ||
| 3544 | |||
| 3414 | Fput (Qfile_error, Qerror_conditions, | 3545 | Fput (Qfile_error, Qerror_conditions, |
| 3415 | Fcons (Qfile_error, Fcons (Qerror, Qnil))); | 3546 | Fcons (Qfile_error, Fcons (Qerror, Qnil))); |
| 3416 | Fput (Qfile_error, Qerror_message, | 3547 | Fput (Qfile_error, Qerror_message, |
| @@ -3446,6 +3577,24 @@ The function `find-file-name-handler' checks this list for a handler\n\ | |||
| 3446 | for its argument."); | 3577 | for its argument."); |
| 3447 | Vfile_name_handler_alist = Qnil; | 3578 | Vfile_name_handler_alist = Qnil; |
| 3448 | 3579 | ||
| 3580 | DEFVAR_LISP ("after-insert-file-functions", &Vafter_insert_file_functions, | ||
| 3581 | "A list of functions to be called at the end of `insert-file-contents'. | ||
| 3582 | Each is passed one argument, the number of bytes inserted. It should return | ||
| 3583 | the new byte count, and leave point the same. If `insert-file-contents' is | ||
| 3584 | intercepted by a handler from `file-name-handler-alist', that handler is | ||
| 3585 | responsible for calling the after-insert-file-functions if appropriate."); | ||
| 3586 | Vafter_insert_file_functions = Qnil; | ||
| 3587 | |||
| 3588 | DEFVAR_LISP ("write-region-annotate-functions", &Vwrite_region_annotate_functions, | ||
| 3589 | "A list of functions to be called at the start of `write-region'. | ||
| 3590 | Each is passed two arguments, START and END as for `write-region'. It should | ||
| 3591 | return a list of pairs (POSITION . STRING) of strings to be effectively | ||
| 3592 | inserted at the specified positions of the file being written (1 means to | ||
| 3593 | insert before the first byte written). The POSITIONs must be sorted into | ||
| 3594 | increasing order. If there are several functions in the list, the several | ||
| 3595 | lists are merged destructively."); | ||
| 3596 | Vwrite_region_annotate_functions = Qnil; | ||
| 3597 | |||
| 3449 | defsubr (&Sfind_file_name_handler); | 3598 | defsubr (&Sfind_file_name_handler); |
| 3450 | defsubr (&Sfile_name_directory); | 3599 | defsubr (&Sfile_name_directory); |
| 3451 | defsubr (&Sfile_name_nondirectory); | 3600 | defsubr (&Sfile_name_nondirectory); |
| @@ -3485,6 +3634,7 @@ for its argument."); | |||
| 3485 | defsubr (&Sfile_newer_than_file_p); | 3634 | defsubr (&Sfile_newer_than_file_p); |
| 3486 | defsubr (&Sinsert_file_contents); | 3635 | defsubr (&Sinsert_file_contents); |
| 3487 | defsubr (&Swrite_region); | 3636 | defsubr (&Swrite_region); |
| 3637 | defsubr (&Scar_less_than_car); | ||
| 3488 | defsubr (&Sverify_visited_file_modtime); | 3638 | defsubr (&Sverify_visited_file_modtime); |
| 3489 | defsubr (&Sclear_visited_file_modtime); | 3639 | defsubr (&Sclear_visited_file_modtime); |
| 3490 | defsubr (&Svisited_file_modtime); | 3640 | defsubr (&Svisited_file_modtime); |