+(defun find-library-suffixes ()
+ (let ((suffixes nil))
+ (dolist (suffix (get-load-suffixes) (nreverse suffixes))
+ (unless (string-match "elc" suffix) (push suffix suffixes)))))
+
+(defun find-library-name (library)
+ "Return the absolute file name of the Lisp source of LIBRARY."
+ ;; If the library is byte-compiled, try to find a source library by
+ ;; the same name.
+ (if (string-match "\\.el\\(c\\(\\..*\\)?\\)\\'" library)
+ (setq library (replace-match "" t t library)))
+ (or (locate-file library
+ (or find-function-source-path load-path)
+ (append (find-library-suffixes) load-file-rep-suffixes))
+ (error "Can't find library %s" library)))
+
+(defvar find-function-C-source-directory
+ (let ((dir (expand-file-name "src" source-directory)))
+ (when (and (file-directory-p dir) (file-readable-p dir))
+ dir))
+ "Directory where the C source files of Emacs can be found.
+If nil, do not try to find the source code of functions and variables
+defined in C.")
+
+(defun find-function-C-source (fun-or-var file type)
+ "Find the source location where FUN-OR-VAR is defined in FILE.
+TYPE should be nil to find a function, or `defvar' to find a variable."
+ (unless find-function-C-source-directory
+ (setq find-function-C-source-directory
+ (read-directory-name "Emacs C source dir: " nil nil t)))
+ (setq file (expand-file-name file find-function-C-source-directory))
+ (unless (file-readable-p file)
+ (error "The C source file %s is not available"
+ (file-name-nondirectory file)))
+ (unless type
+ (setq fun-or-var (indirect-function fun-or-var)))
+ (with-current-buffer (find-file-noselect file)
+ (goto-char (point-min))
+ (unless (re-search-forward
+ (if type
+ (concat "DEFVAR[A-Z_]*[ \t\n]*([ \t\n]*\""
+ (regexp-quote (symbol-name fun-or-var))
+ "\"")
+ (concat "DEFUN[ \t\n]*([ \t\n]*\""
+ (regexp-quote (subr-name fun-or-var))
+ "\""))
+ nil t)
+ (error "Can't find source for %s" fun-or-var))
+ (cons (current-buffer) (match-beginning 0))))
+