;;; file-fns.el --- functions for querying about or acting on files

;; Copyright (C) 1991-1999 Noah S. Friedman

;; Author: Noah Friedman <friedman@splode.com>
;; Maintainer: friedman@splode.com

;; $Id: file-fns.el,v 1.5 1999/10/30 07:52:59 friedman Exp $

;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2, or (at your option)
;; any later version.
;;
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with this program; if not, you can either send email to this
;; program's maintainer or write to: The Free Software Foundation,
;; Inc.; 59 Temple Place, Suite 330; Boston, MA 02111-1307, USA.

;;; Commentary:
;;; Code:

;;;###autoload
(defun file-in-pathlist-p (file path)
  "Return path of FILE if FILE is found anywhere in PATH.
FILE is a string.  PATH is a list of strings."
  (let ((found nil)
        (f nil))
    (while (and (not found) path)
      (setq f (concat (file-name-as-directory (car path)) file))
      (and (file-exists-p f)
           (setq found f))
      (setq path (cdr path)))
    found))

;;;###autoload
(defun file-plain-p (file)
  "Returns `t' if FILE is a plain file.
That means it is not a directory, symlink, character-special device, named
pipe, socket, etc."
  (and (stringp file)
       (let ((mode (nth 8 (file-attributes file))))
         (and mode
              (= ?- (aref mode 0))))))

;;;###autoload
(defun file-name-completions-in-path (name-regexp path-list
                                                  &optional predicate filter)
  "Return an obarray containing file name completions.
All file names matching NAME-REGEXP, located in directories listed in
PATH-LIST, which satisfy optional arg PREDICATE, are put into the obarray
after being filtered through optional FILTER for potential edits.

If NAME-REGEXP is nil, then all files are candidates.

PREDICATE and FILTER should be functions which take one argument, a string
representing a file name."
  (let ((completions (make-vector 3 0))
        (files nil))
    (while path-list
      (setq files (directory-files (car path-list) nil name-regexp t))
      (while files
        (cond ((or (null predicate)
                   (funcall predicate (car files)))
               (intern (if filter
                           (funcall filter (car files))
                         (car files))
                       completions)))
        (setq files (cdr files)))
      (setq path-list (cdr path-list)))
    completions))

;;;###autoload
(defun insert-tail-of-file-contents (file bytes)
  "Insert the last N bytes of FILE.
If the file is smaller than N, just insert the entire file."
  (interactive "fFile name: \nnLast N bytes of file to insert: ")
  (setq file (expand-file-name file))
  (let* ((attr (file-attributes file))
         (size (nth 7 attr)))
    (and (= size -1)
         (signal 'overflow-error (list file size attr)))
    (if (> bytes size)
        (insert-file-contents file)
      (insert-file-contents file nil (- size bytes)))))

;;;###autoload
(defun make-autosave-for-buffer-before-kill-p ()
  (cond ((and (buffer-modified-p)
              (yes-or-no-p "This buffer is modified; make autosave? "))
         (make-local-variable 'kill-buffer-hook)
         (add-hook 'kill-buffer-hook
                   (function
                    (lambda ()
                      ;; Do an auto save, then set the auto save file name
                      ;; to nil to prevent kill-buffer from deleting it.
                      ;; For some reason setting delete-auto-save-files nil
                      ;; seems not to work.
                      (if (< (emacs-version-major) 19)
                          (do-auto-save)
                        ;; In emacs 19, just autosave the current buffer.
                        (do-auto-save nil t))
                      (setq buffer-auto-save-file-name nil)))))
        ;; The kill-buffer-query-functions have the semantics that if any
        ;; return nil, then do not kill the buffer.  If they all return t,
        ;; then do kill.
        (t t)))

;;;###autoload
(defun make-buffer-file-executable-if-script-p ()
  "Make file executable according to umask if not already executable.
If file already has any execute bits set at all, do not change existing
file modes."
  (and (save-excursion
         (save-restriction
           (widen)
           (goto-char (point-min))
           (save-match-data
             (looking-at "^#!"))))
       (let* ((current-mode (file-modes (buffer-file-name)))
              (add-mode (logand ?\111 (default-file-modes))))
         (or (null current-mode)
             (/= (logand ?\111 current-mode) 0)
             (zerop add-mode)
             (set-file-modes (buffer-file-name)
                             (logior current-mode add-mode))))))

(provide 'file-fns)

;;; file-fns.el ends here.
