]> code.delx.au - gnu-emacs/blobdiff - lisp/files.el
Update copyright year to 2015
[gnu-emacs] / lisp / files.el
index be1b6c29d10133e84d4ab859d6bb34a5caac255f..22362ca13ca77d2eb66c60060250adb4ccfea2d3 100644 (file)
@@ -1,6 +1,6 @@
 ;;; files.el --- file input and output commands for Emacs  -*- lexical-binding:t -*-
 
-;; Copyright (C) 1985-1987, 1992-2014 Free Software Foundation, Inc.
+;; Copyright (C) 1985-1987, 1992-2015 Free Software Foundation, Inc.
 
 ;; Maintainer: emacs-devel@gnu.org
 ;; Package: emacs
@@ -729,6 +729,67 @@ The path separator is colon in GNU and GNU-like systems."
                     (lambda (f) (and (file-directory-p f) 'dir-ok)))
        (error "No such directory found via CDPATH environment variable"))))
 
+(defun file-tree-walk (dir action &rest args)
+  "Walk DIR executing ACTION on each file, with ARGS as additional arguments.
+For each file, the function calls ACTION as follows:
+
+   \(ACTION DIRECTORY BASENAME ARGS\)
+
+Where DIRECTORY is the leading directory of the file,
+      BASENAME is the basename of the file,
+      and ARGS are as specified in the call to this function, or nil if omitted.
+
+The ACTION is applied to each subdirectory before descending into
+it, and if nil is returned at that point, the descent will be
+prevented.  Directory entries are sorted with string-lessp."
+  (cond ((file-directory-p dir)
+        (setq dir (file-name-as-directory dir))
+        (let ((lst (directory-files dir nil nil t))
+              fullname file)
+          (while lst
+            (setq file (car lst))
+            (setq lst (cdr lst))
+            (cond ((member file '("." "..")))
+                  (t
+                   (and (apply action dir file args)
+                        (setq fullname (concat dir file))
+                        (file-directory-p fullname)
+                        (apply 'file-tree-walk fullname action args)))))))
+       (t
+        (apply action
+               (file-name-directory dir)
+               (file-name-nondirectory dir)
+               args))))
+
+(defsubst directory-name-p (name)
+  "Return non-nil if NAME ends with a slash character."
+  (and (> (length name) 0)
+       (char-equal (aref name (1- (length name))) ?/)))
+
+(defun directory-files-recursively (dir match &optional include-directories)
+  "Return all files under DIR that have file names matching MATCH (a regexp).
+This function works recursively.  Files are returned in \"depth first\"
+and alphabetical order.
+If INCLUDE-DIRECTORIES, also include directories that have matching names."
+  (let ((result nil)
+       (files nil))
+    (dolist (file (sort (file-name-all-completions "" dir)
+                       'string<))
+      (unless (member file '("./" "../"))
+       (if (directory-name-p file)
+           (let* ((leaf (substring file 0 (1- (length file))))
+                  (path (expand-file-name leaf dir)))
+             ;; Don't follow symlinks to other directories.
+             (unless (file-symlink-p path)
+               (setq result (nconc result (directory-files-recursively
+                                           path match include-directories))))
+             (when (and include-directories
+                        (string-match match leaf))
+               (setq result (nconc result (list path)))))
+         (when (string-match match file)
+           (push (expand-file-name file dir) files)))))
+    (nconc result (nreverse files))))
+
 (defun load-file (file)
   "Load the Lisp file named FILE."
   ;; This is a case where .elc makes a lot of sense.
@@ -6670,7 +6731,7 @@ only these files will be asked to be saved."
       (`add (concat "/:" (apply operation arguments)))
       (`insert-file-contents
        (let ((visit (nth 1 arguments)))
-         (prog1
+         (unwind-protect
              (apply operation arguments)
            (when (and visit buffer-file-name)
              (setq buffer-file-name (concat "/:" buffer-file-name))))))