home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / gnu / lucid / lemacs-19.6 / lisp / dired / dired-link.el < prev    next >
Encoding:
Text File  |  1992-06-29  |  5.7 KB  |  139 lines

  1. ;;!emacs
  2. ;;
  3. ;; FILE:         dired-link.el
  4. ;; SUMMARY:      Properly resolves UNIX (and Apollo variant) links under dired.
  5. ;;               Works for both classic dired (V18) and tree dired (V19).
  6. ;;
  7. ;; AUTHOR:       Bob Weiner
  8. ;;
  9. ;; ORIG-DATE:    09-May-89
  10. ;; LAST-MOD:     15-Apr-92
  11. ;;
  12. ;; Copyright (C) 1989, 1991, Brown University, Providence, RI
  13. ;; Available for use and distribution under the same terms as GNU Emacs.
  14. ;;
  15. ;; This file is not part of GNU Emacs.
  16. ;;
  17. ;; DESCRIPTION:  
  18. ;;
  19. ;;   This library is used in conjunction with the GNU Emacs dired facility.
  20. ;;   To install it, simply load this file or create a
  21. ;;   dired hook which loads this file.  Then use {M-x dired <directory> RTN}
  22. ;;   or {C-x C-f <directory> RTN} as one normally would.
  23. ;;
  24. ;;   The changes below to 'dired-noselect' assume UNIX shell file
  25. ;;   abbreviation and UNIX file name conventions.
  26. ;;
  27. ;;   This modified version of the 'dired-noselect' function automatically
  28. ;;   resolves all recursive links properly and edits the final directory that
  29. ;;   a link points to, called the link referent.  It handles Apollo-isms such
  30. ;;   as /usr/local -> $(SERVER_LOCAL)/usr/local, /usr/bin ->
  31. ;;   ../$(SYSTYPE)/usr/bin and /tmp -> `node_data/tmp.  It also handles
  32. ;;   relative links properly as in /usr/local/emacs -> gnu/emacs which must
  33. ;;   be resolved relative to the '/usr/local' directory.
  34. ;;
  35. ;; DESCRIP-END.
  36.  
  37. (require 'dired)
  38.  
  39. ;; ************************************************************************
  40. ;; Internal functions
  41. ;; ************************************************************************
  42.  
  43. ;; Normally, if one performs a dired multiple times on a directory which is a
  44. ;; link, a new buffer will be created each time.  This is due to the fact
  45. ;; that 'dired-find-buffer' is called in 'dired-noselect' before the link is
  46. ;; resolved.  The following code solves this problem by checking for a
  47. ;; previously existing buffer that is performing dired on the directory that
  48. ;; the link resolves to.  This is also done recursively.  If one is found,
  49. ;; the dired buffer that shows the link is killed and the previously existing
  50. ;; one is used and re-read in.
  51.  
  52. (defun dired-link-noselect-classic (dirname)
  53.   "Like M-x dired but returns the dired buffer as value, does not select it."
  54.   (or dirname (setq dirname default-directory))
  55.   (setq dirname (dired-link-referent (directory-file-name dirname)))
  56.   (if (equal dirname "")
  57.       nil
  58.     (if (= (aref dirname 0) ?~) (setq dirname (expand-file-name dirname)))
  59.     (if (file-directory-p dirname)
  60.     (setq dirname (file-name-as-directory dirname)))
  61.     (let ((buffer (dired-find-buffer dirname)))
  62.       (set-buffer buffer)
  63.       (dired-readin dirname buffer)
  64.       (dired-move-to-filename)
  65.       (dired-mode dirname)
  66.       buffer)))
  67.  
  68. (defun dired-link-noselect-tree (dirname &optional switches)
  69.   "Like `dired' but returns the dired buffer as value, does not select it."
  70.   (or dirname (setq dirname default-directory))
  71.   (setq dirname (expand-file-name
  72.          (dired-link-referent (directory-file-name dirname))))
  73.   (if (file-directory-p dirname)
  74.       (setq dirname (file-name-as-directory dirname)))
  75.   (dired-internal-noselect dirname switches))
  76.  
  77. ;; Overload as appropriate for Classic (V18) or Tree Dired
  78. (fset 'dired-noselect (if (fboundp 'dired-internal-noselect)
  79.               'dired-link-noselect-tree
  80.             'dired-link-noselect-classic))
  81.  
  82. ;;
  83. ;; Resolves all UNIX links.
  84. ;; Works with Apollo's variant and other strange links.  Will fail on
  85. ;; Apollos if the '../' notation is used to move just above the '/'
  86. ;; directory level.  This is fairly uncommon and so the problem has not been
  87. ;; fixed.
  88. ;;;
  89. (defun dired-link-referent (linkname)
  90.   "Returns expanded file or directory referent of LINKNAME.
  91. LINKNAME should not end with a directory delimiter.
  92. If LINKNAME is not a string, returns nil.
  93. If LINKNAME is not a link, it is simply expanded and returned."
  94.   (if (not (stringp linkname))
  95.       nil
  96.     (let ((referent))
  97.       (while (setq referent (file-symlink-p linkname))
  98.     (setq linkname (dired-link-expand
  99.             referent (file-name-directory linkname)))))
  100.     (dired-link-expand linkname (file-name-directory linkname))))
  101.  
  102. (defun dired-link-expand (referent dirname)
  103.   "Expands REFERENT relative to DIRNAME and returns."
  104.   (let ((var-link)
  105.     (dir dirname))
  106.     (while (string-match "\\$(\\([^\)]*\\))" referent)
  107.       (setq var-link (getenv (substring referent (match-beginning 1)
  108.                     (match-end 1)))
  109.         referent (concat (substring referent 0 (match-beginning 0))
  110.                  var-link
  111.                  (substring referent (match-end 0)))))
  112.     ;; If referent is not an absolute path
  113.     (let ((nd-abbrev (string-match "`node_data" referent)))
  114.       (if (and nd-abbrev (= nd-abbrev 0))
  115.       (setq referent (concat
  116.                ;; Prepend node name given in dirname, if any
  117.                (and (string-match "^//[^/]+" dirname)
  118.                 (substring dirname 0 (match-end 0)))
  119.                "/sys/" (substring referent 1)))))
  120.     (while (string-match "\\.\\." referent)
  121.       ;; Match to "//.." or "/.." at the start of link referent
  122.       (while (string-match "^\\(//\\.\\.\\|/\\.\\.\\)\\(/\\|$\\)" referent)
  123.     (setq referent (substring referent (match-end 1))))
  124.       ;; Match to "../" or ".." at the start of link referent
  125.       (while (string-match "^\\.\\.\\(/\\|$\\)" referent)
  126.     (setq dir (file-name-directory (directory-file-name dir))
  127.           referent (concat dir (substring referent (match-end 0)))))
  128.       ;; Match to rest of "../" in link referent
  129.       (while (string-match "[^/]+/\\.\\./" referent)
  130.     (setq referent (concat (substring referent 0 (match-beginning 0))
  131.                    (substring referent (match-end 0))))))
  132.     (and (/= (aref referent 0) ?~)
  133.      (/= (aref referent 0) ?/)
  134.      (setq referent (concat dirname referent))))
  135.   referent)
  136.  
  137. (provide 'dir-links)            ; the old name of this package
  138. (provide 'dired-link)
  139.