home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / languages / elisp / functions / shadow-load.el < prev    next >
Encoding:
Text File  |  1991-07-24  |  11.2 KB  |  289 lines

  1. ; Path: dg-rtp!rock!mcnc!stanford.edu!agate!usenet.ins.cwru.edu!magnus.acs.ohio-state.edu!cis.ohio-state.edu!ifi.uio.no!hallvard
  2. ; From: hallvard@ifi.uio.no (Hallvard B Furuseth)
  3. ; Newsgroups: gnu.emacs.sources
  4. ; Subject: shadow-load.el
  5. ; Date: 11 Jul 91 23:11:05 GMT
  6. ; Here is a library I have forgotten to post for some time.
  7. ; If your private ~/elisp/foo.el loads the standard library foo.el and then
  8. ; redefines some parts of it, you can now put
  9. ;    (load "foo" nil 'shadow)
  10. ; in ~/elisp/foo.el to load the standard library.  It does the same as
  11. ; normal load, but skips the first ~/elisp/foo.el in load-path.
  12. ; This can be convenient if the "standard" load-path is undetermined when
  13. ; you write your mod to foo.el, or if "foo" loads other libraries which are
  14. ; also modified in ~/elisp.  Otherwise ~/elisp/foo.el could simply say
  15. ;   (let ((load-path '("/usr/lib/gnu/emacs/lisp")))
  16. ;      (load "foo" nil t))
  17. ; Problems: It will not always work in autoloads.  Read the top of the file
  18. ; to see.
  19. ; Hallvard Furuseth
  20. ; hallvard@ifi.uio.no
  21.  
  22. ;; shadow-load.el version 1.5 for GNU Emacs.
  23. ;; Created by Hallvard B Furuseth (hallvard@ifi.uio.no).
  24. ;; Last modified Tue 18/04-1991.
  25. ;; This code is in the public domain.
  26.  
  27. ;; LCD Archive Entry:
  28. ;; shadow-load|Hallvard B Furuseth|hallvard@ifi.uio.no
  29. ;; |Load "file" from first dir in load-path from which "file" is not loading
  30. ;; |91-04-18|1.5|~/functions/shadow-load.el.Z
  31.  
  32. ;; In file "foo.el", put
  33. ;;
  34. ;;   (load "foo" nil 'shadow)
  35. ;;
  36. ;; to load "foo" from the first dir in load-path from which "foo" not
  37. ;; currently loading.
  38. ;; It first searches load-path once for library "foo", the first occurrence
  39. ;; which is not already shadowed is assumed to be the current file.
  40. ;;
  41. ;; To let others (who do not have ~you/elisp in load-path) load your foo, the
  42. ;; form below is currently necessary. It will probably be abolished if
  43. ;; shadowing is implemeted in C:
  44. ;;
  45. ;;   (require 'shadow-load "~you/elisp/shadow-load")
  46. ;;   (load "foo" nil "~you/elisp/foo")
  47. ;;
  48. ;; This informs load that the your "foo" resides in ~you/elisp/.
  49. ;; But in many cases you could probably just as well say
  50. ;;    (load "/local/lib/gnu/emacs/lisp/foo").
  51. ;;
  52. ;; Extended require:
  53. ;;   Arg 3 is NOERROR as 2nd arg to load,
  54. ;;   Arg 4 is SHADOW ('shadow or filename of self, as with load).
  55. ;; So you may prefer to use require instead of load:
  56. ;;
  57. ;;   (require 'shadow-load "~you/elisp/shadow-load")
  58. ;;   (require 'foo nil nil "~you/elisp/foo")
  59. ;;
  60. ;; Modified eval-current-buffer and eval-region so shadowing can be
  61. ;; used inside them.
  62. ;;
  63. ;; Also includes an extension to my where-is-file (locate a file in a pathlist)
  64. ;; which obeys the variable load-ignore-directories.
  65.  
  66. ;; Bugs and caveats:
  67. ;;
  68. ;;   If you don't tell Load which file is currently loading, it can guess
  69. ;;   wrong.
  70. ;;
  71. ;;   When you give 3rd or 4th arg to Require, defuns in the loaded file are
  72. ;;   not undone if the feature was not provided.
  73. ;;
  74. ;;   File-id has several problems.  See comments in the code.
  75. ;;   It is used to (try to) detect directories with several names, but
  76. ;;   if you don't like it, replace it with (fset 'file-id 'identity).
  77. ;;
  78. ;;   These problems can be fixed by writing this in C.
  79. ;;   The code should be smaller in C, too.  Load, f.ex, would simply bind
  80. ;;   current-load-info to (cons full-filename load-ignore-directories) during
  81. ;;   readevalloop().  When shadowing, it would bind load-ignore-directories
  82. ;;   to (cons (file-id (car current-load-info)) (cdr current-load-info))
  83. ;;   during openp() and when computing the current-load-info above.
  84.  
  85. (provide 'shadow-load)
  86.  
  87.  
  88. (defvar current-load-info nil
  89.   "Info about the currently loading file.  Set by function load.
  90. Value: (full_filename . load-ignore-directories for (load ... 'shadow)).")
  91.  
  92. (defvar load-ignore-directories nil
  93.   "If (list (file-id DIR)) is in this list, where-is-file will not return
  94. files in DIR.  However, files in subdirs of DIR may still be returned.
  95. Used in (load ... 'shadow).
  96. Don't modify this variable unless you know exactly what you are doing.")
  97.  
  98.  
  99. (or (fboundp 'shadow-old-load)
  100.     (fset 'shadow-old-load (symbol-function 'load)))
  101.  
  102. (defun load (shadow-lib &optional shadow-noerr shadow-self shadow-nosuff)
  103.   "Execute a file of Lisp code named FILE.
  104. First tries FILE with .elc appended, then tries with .el,
  105.  then tries FILE unmodified.  Searches directories in  load-path.
  106. If optional second arg NOERROR is non-nil,
  107.  report no error if FILE doesn't exist.
  108. Print messages at start and end of loading unless
  109.  optional third arg NOMESSAGE is non-nil.
  110. If optional fourth arg NOSUFFIX is non-nil, don't try adding
  111.  suffixes .elc or .el to the specified name FILE.
  112. Return t if file exists.
  113.  
  114. Extension:
  115. If NOMESSAGE is 'shadow, load FILE from the first dir in load-path from which
  116.  FILE is not currently loading.  If FILE is an absolute pathname, just fail if
  117.  it's already loading.  The calling file must have the same basename as FILE.
  118. Until this is written in C, NOMESSAGE may also be the full pathname of the file
  119.  which calls load.  If not, load assumes this is the first (not shadowed) FILE
  120.  in load-path."
  121.   (if (not (or (eq shadow-self 'shadow) (stringp shadow-self)))
  122.       (let ((current-load-info (list shadow-lib)))
  123.     (shadow-old-load shadow-lib shadow-noerr shadow-self shadow-nosuff))
  124.     (or current-load-info load-in-progress
  125.     (error "Attempt to shadow-load while no load in progress"))
  126.     (let ((current-load-info
  127.        (let* ((load-ignore-directories load-ignore-directories)
  128.           (case-fold-search (eq system-type 'vax-vms))
  129.           self key tmp)
  130.          ;; Get or guess current library name and load-ignore-directories
  131.          (setq self (cond
  132.              ((not (stringp shadow-self)) shadow-lib)
  133.              ((not (file-name-absolute-p shadow-self))
  134.               (error "load: non-absolute shadow %s" shadow-self))
  135.              ((setq shadow-self (expand-file-name shadow-self))))
  136.            self (substring self 0 (string-match "\\.elc?\\'" self))
  137.            key (file-name-nondirectory self))
  138.          (and current-load-info
  139.           (string-match
  140.            (concat "\\`" (regexp-quote key) "\\(\\.elc?\\)?\\'")
  141.            (file-name-nondirectory (car current-load-info)))
  142.           (progn (setq load-ignore-directories (cdr current-load-info))
  143.              (or (stringp shadow-self)
  144.                  (setq shadow-self (car current-load-info)))))
  145.          ;; load-ignore-directories is set. Find currently loading file
  146.          (or (stringp shadow-self)
  147.          (setq shadow-self (if (file-name-absolute-p self) key self)))
  148.          (setq self
  149.            (cond ((file-name-absolute-p shadow-self)
  150.               (expand-file-name shadow-self))
  151.              ((where-is-file load-path shadow-self ".elc:.el:"))
  152.              ((error "load: unknown shadow file %s" shadow-self))))
  153.          ;; Find shadowed library
  154.          (setq load-ignore-directories
  155.            (cons (list (file-id (file-name-directory self)))
  156.              load-ignore-directories))
  157.          (or (setq shadow-lib
  158.                (where-is-file load-path (setq tmp shadow-lib)
  159.                       (if (not shadow-nosuff) ".elc:.el:")))
  160.          shadow-noerr
  161.          (error "Cannot open shadow-load file: %s" tmp))
  162.          (cons shadow-lib load-ignore-directories))))
  163.       (and shadow-lib
  164.        (shadow-old-load shadow-lib shadow-noerr t t)))))
  165.  
  166.  
  167.  
  168. (or (fboundp 'shadow-old-eval-current-buffer)
  169.     (fset 'shadow-old-eval-current-buffer (symbol-function 'eval-current-buffer)))
  170. (defun eval-current-buffer (&optional shadow-printflag)
  171.   (interactive)
  172.   (let ((current-load-info (if buffer-file-name
  173.                    (list buffer-file-name))))
  174.     (shadow-old-eval-current-buffer shadow-printflag)))
  175.  
  176. (or (fboundp 'shadow-old-eval-region)
  177.     (fset 'shadow-old-eval-region (symbol-function 'eval-region)))
  178. (defun eval-region (shadow-beginning shadow-end &optional shadow-printflag)
  179.   (interactive "r")
  180.   (let ((current-load-info (if buffer-file-name
  181.                    (list buffer-file-name))))
  182.     (shadow-old-eval-region shadow-beginning shadow-end shadow-printflag)))
  183.  
  184.  
  185.  
  186. (or (fboundp 'shadow-old-require)
  187.     (fset 'shadow-old-require (symbol-function 'require)))
  188.  
  189. (defun require (rq-feature &optional rq-file rq-noerror rq-shadow)
  190.   "If FEATURE is not present in Emacs (ie (featurep FEATURE) is false),
  191.  load FILENAME.  FILENAME is optional and defaults to FEATURE.
  192. Extension:
  193. If NOERROR is non-nil, report no error if no FILENAME is found.
  194. If SHADOW is 'shadow (or, for now, a string), it is used as 3rd arg to load."
  195.   (cond ((featurep rq-feature) rq-feature)
  196.     ((not (or rq-noerror rq-shadow))
  197.      (shadow-old-require rq-feature rq-file))
  198.     ((not (condition-case error
  199.           (load (or rq-file (symbol-name rq-feature))
  200.             rq-noerror (or rq-shadow t))
  201.         (error
  202.          (setq features (delq rq-feature features))
  203.          (signal (car error) (cdr error)))))
  204.      nil)
  205.     ((featurep rq-feature) rq-feature)
  206.     ((error "Required feature %s was not provided" rq-feature))))
  207.  
  208.  
  209. ;; This is a lisp version of openp() in src/lread.c,
  210. ;; ***extended to obey the load-ignore-directories variable***.
  211. ;;  Instead of using the exec_only argument of openp(), it returns the
  212. ;;  name of a *readable* file.  Should include an optional prefix arg
  213. ;;  ACCESS as well, but that can't be done correctly in Elisp.
  214. (defun where-is-file (path file &optional suffixes)
  215.   "Search through PATH (list) for a readable FILENAME, expanded by one of the
  216. optional SUFFIXES (string of suffixes separated by \":\"s).  Interactively,
  217. SUFFIXES (default \".elc:.el:\") is prompted when there is a prefix arg.
  218. Does not return files in load-ignore-directories, see doc for that variable."
  219.   (interactive
  220.    (list (let ((path (read-minibuffer "Search path: " "load-path")))
  221.        (if (and (consp path) (or (stringp (car path)) (null (car path))))
  222.            path
  223.          (eval path)))
  224.      (read-string "Locate file: ")
  225.      (if current-prefix-arg
  226.          (read-string "Suffixes: " ".elc:.el:")
  227.        ".elc:.el:")))
  228.   (if (not (equal file ""))
  229.       (let ((filelist nil) pos temp templist ignore)
  230.     ;; Make list of possible file names
  231.     (setq filelist
  232.           (if suffixes
  233.           (progn
  234.             (while (setq pos (string-match ":[^:]*\\'" suffixes))
  235.               (setq filelist (cons (concat file (substring suffixes
  236.                                    (1+ pos)))
  237.                        filelist))
  238.               (setq suffixes (substring suffixes 0 pos)))
  239.             (cons (concat file suffixes) filelist))
  240.         (list file)))
  241.     ;; Search PATH for a readable file in filelist
  242.     (catch 'bar
  243.       (if (file-name-absolute-p file) (setq path '(nil)))
  244.       (while path
  245.         (setq ignore (cons '(nil) load-ignore-directories))
  246.         (setq templist filelist)
  247.         (while
  248.         (progn
  249.           (setq temp (expand-file-name (car templist) (car path)))
  250.           (cond ((and ignore
  251.                   (prog1
  252.                   (assoc (file-id (file-name-directory temp))
  253.                      ignore)
  254.                 (setq ignore nil)))
  255.              nil)
  256.             ((file-readable-p temp)
  257.              (if (interactive-p)
  258.                  (message "%s" temp))
  259.              (throw 'bar temp))
  260.             ((setq templist (cdr templist))))))
  261.         (setq path (cdr path)))
  262.       (if (interactive-p)
  263.           (message "(File %s not found)" file))
  264.       nil))))
  265.  
  266.  
  267. (defun file-id (file)
  268.   "Attempt to return an i.d. for FILE which is unique (by EQUAL)."
  269.   ;; Problems:
  270.   ;;    Does not dereference if FILE is a symlink (because expand-file-name
  271.   ;;      handles "foo/.." incorrectly if foo is a symlink).
  272.   ;;    I have no idea of how this works on non-UNIX systems.
  273.   ;;    Can't get FILE's device, so two files with the same
  274.   ;;      inode and owner will be considered equal.
  275.   ;;  If you don't trust it, replace it with (fset 'file-id 'identity).
  276.   (if (setq file (file-attributes file))
  277.       ;; Should be (inode . device), but I suppose this is safe enough
  278.       ;; for the use of this package.
  279.       (cons (nth 10 file) (nth 2 file))))
  280.