comparison lisp/files.el @ 50339:b8ecb0403fa1

(file-relative-name): If FILENAME and DIRECTORY are on different drives (on DOS/Windows) or use different handlers, do like `expand-file-name' on FILENAME and return an absolute name. From Lars Hansen <larsh@math.ku.dk>.
author Kai Großjohann <kgrossjo@eu.uu.net>
date Sat, 29 Mar 2003 15:31:07 +0000
parents 994336ed195e
children 8e666b72c381
comparison
equal deleted inserted replaced
50338:155b4b78aa3b 50339:b8ecb0403fa1
2779 2779
2780 (defun file-nlinks (filename) 2780 (defun file-nlinks (filename)
2781 "Return number of names file FILENAME has." 2781 "Return number of names file FILENAME has."
2782 (car (cdr (file-attributes filename)))) 2782 (car (cdr (file-attributes filename))))
2783 2783
2784 ;; (defun file-relative-name (filename &optional directory)
2785 ;; "Convert FILENAME to be relative to DIRECTORY (default: `default-directory').
2786 ;; This function returns a relative file name which is equivalent to FILENAME
2787 ;; when used with that default directory as the default.
2788 ;; If this is impossible (which can happen on MSDOS and Windows
2789 ;; when the file name and directory use different drive names)
2790 ;; then it returns FILENAME."
2791 ;; (save-match-data
2792 ;; (let ((fname (expand-file-name filename)))
2793 ;; (setq directory (file-name-as-directory
2794 ;; (expand-file-name (or directory default-directory))))
2795 ;; ;; On Microsoft OSes, if FILENAME and DIRECTORY have different
2796 ;; ;; drive names, they can't be relative, so return the absolute name.
2797 ;; (if (and (or (eq system-type 'ms-dos)
2798 ;; (eq system-type 'cygwin)
2799 ;; (eq system-type 'windows-nt))
2800 ;; (not (string-equal (substring fname 0 2)
2801 ;; (substring directory 0 2))))
2802 ;; filename
2803 ;; (let ((ancestor ".")
2804 ;; (fname-dir (file-name-as-directory fname)))
2805 ;; (while (and (not (string-match (concat "^" (regexp-quote directory)) fname-dir))
2806 ;; (not (string-match (concat "^" (regexp-quote directory)) fname)))
2807 ;; (setq directory (file-name-directory (substring directory 0 -1))
2808 ;; ancestor (if (equal ancestor ".")
2809 ;; ".."
2810 ;; (concat "../" ancestor))))
2811 ;; ;; Now ancestor is empty, or .., or ../.., etc.
2812 ;; (if (string-match (concat "^" (regexp-quote directory)) fname)
2813 ;; ;; We matched within FNAME's directory part.
2814 ;; ;; Add the rest of FNAME onto ANCESTOR.
2815 ;; (let ((rest (substring fname (match-end 0))))
2816 ;; (if (and (equal ancestor ".")
2817 ;; (not (equal rest "")))
2818 ;; ;; But don't bother with ANCESTOR if it would give us `./'.
2819 ;; rest
2820 ;; (concat (file-name-as-directory ancestor) rest)))
2821 ;; ;; We matched FNAME's directory equivalent.
2822 ;; ancestor))))))
2823
2784 (defun file-relative-name (filename &optional directory) 2824 (defun file-relative-name (filename &optional directory)
2785 "Convert FILENAME to be relative to DIRECTORY (default: `default-directory'). 2825 "Convert FILENAME to be relative to DIRECTORY (default: `default-directory').
2786 This function returns a relative file name which is equivalent to FILENAME 2826 This function returns a relative file name which is equivalent to FILENAME
2787 when used with that default directory as the default. 2827 when used with that default directory as the default.
2788 If this is impossible (which can happen on MSDOS and Windows 2828 If FILENAME and DIRECTORY lie on different machines or on different drives
2789 when the file name and directory use different drive names) 2829 \(DOS/Windows), it returns FILENAME in expanded form."
2790 then it returns FILENAME."
2791 (save-match-data 2830 (save-match-data
2792 (let ((fname (expand-file-name filename))) 2831 (setq directory
2793 (setq directory (file-name-as-directory 2832 (file-name-as-directory (expand-file-name (or directory
2794 (expand-file-name (or directory default-directory)))) 2833 default-directory))))
2795 ;; On Microsoft OSes, if FILENAME and DIRECTORY have different 2834 (setq filename (expand-file-name filename))
2796 ;; drive names, they can't be relative, so return the absolute name. 2835 (let ((hf (find-file-name-handler filename 'file-local-copy))
2797 (if (and (or (eq system-type 'ms-dos) 2836 (hd (find-file-name-handler directory 'file-local-copy)))
2798 (eq system-type 'cygwin) 2837 (when (and hf (not (get hf 'file-remote-p))) (setq hf nil))
2799 (eq system-type 'windows-nt)) 2838 (when (and hd (not (get hd 'file-remote-p))) (setq hd nil))
2800 (not (string-equal (substring fname 0 2) 2839 (if (and
2801 (substring directory 0 2)))) 2840 ;; Conditions for separate trees
2841 (or
2842 ;; Test for different drives on DOS/Windows
2843 (and
2844 (memq system-type '(ms-dos cygwin windows-nt))
2845 (not (string-equal (substring filename 0 2)
2846 (substring directory 0 2))))
2847 ;; Test for different remote file handlers
2848 (not (eq hf hd))
2849 ;; Test for different remote file system identification
2850 (and
2851 hf
2852 (let ((re (car (rassq hf file-name-handler-alist))))
2853 (not
2854 (equal
2855 (and
2856 (string-match re filename)
2857 (substring filename 0 (match-end 0)))
2858 (and
2859 (string-match re directory)
2860 (substring directory 0 (match-end 0)))))))))
2802 filename 2861 filename
2803 (let ((ancestor ".") 2862 (unless (eq (aref filename 0) ?/)
2804 (fname-dir (file-name-as-directory fname))) 2863 (setq filename (concat "/" filename)))
2805 (while (and (not (string-match (concat "^" (regexp-quote directory)) fname-dir)) 2864 (unless (eq (aref directory 0) ?/)
2806 (not (string-match (concat "^" (regexp-quote directory)) fname))) 2865 (setq directory (concat "/" directory)))
2807 (setq directory (file-name-directory (substring directory 0 -1)) 2866 (let ((ancestor ".")
2867 (filename-dir (file-name-as-directory filename)))
2868 (while
2869 (and
2870 (not (string-match (concat "^" (regexp-quote directory))
2871 filename-dir))
2872 (not (string-match (concat "^" (regexp-quote directory))
2873 filename)))
2874 (setq directory (file-name-directory (substring directory 0 -1))
2808 ancestor (if (equal ancestor ".") 2875 ancestor (if (equal ancestor ".")
2809 ".." 2876 ".."
2810 (concat "../" ancestor)))) 2877 (concat "../" ancestor))))
2811 ;; Now ancestor is empty, or .., or ../.., etc. 2878 ;; Now ancestor is empty, or .., or ../.., etc.
2812 (if (string-match (concat "^" (regexp-quote directory)) fname) 2879 (if (string-match (concat "^" (regexp-quote directory)) filename)
2813 ;; We matched within FNAME's directory part. 2880 ;; We matched within FILENAME's directory part.
2814 ;; Add the rest of FNAME onto ANCESTOR. 2881 ;; Add the rest of FILENAME onto ANCESTOR.
2815 (let ((rest (substring fname (match-end 0)))) 2882 (let ((rest (substring filename (match-end 0))))
2816 (if (and (equal ancestor ".") 2883 (if (and (equal ancestor ".") (not (equal rest "")))
2817 (not (equal rest "")))
2818 ;; But don't bother with ANCESTOR if it would give us `./'. 2884 ;; But don't bother with ANCESTOR if it would give us `./'.
2819 rest 2885 rest
2820 (concat (file-name-as-directory ancestor) rest))) 2886 (concat (file-name-as-directory ancestor) rest)))
2821 ;; We matched FNAME's directory equivalent. 2887 ;; We matched FILENAME's directory equivalent.
2822 ancestor)))))) 2888 ancestor))))))
2823 2889
2824 (defun save-buffer (&optional args) 2890 (defun save-buffer (&optional args)
2825 "Save current buffer in visited file if modified. Versions described below. 2891 "Save current buffer in visited file if modified. Versions described below.
2826 By default, makes the previous version into a backup file 2892 By default, makes the previous version into a backup file
2827 if previously requested or if this is the first save. 2893 if previously requested or if this is the first save.