PageRenderTime 45ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/old-archive/functions/shadow-load.el

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