Nuke arch-tags.
[emacs.git] / lisp / progmodes / executable.el
blobc200d99eb83f354175275201a9dad94234309a97
1 ;;; executable.el --- base functionality for executable interpreter scripts -*- byte-compile-dynamic: t -*-
3 ;; Copyright (C) 1994, 1995, 1996, 2000, 2001, 2002, 2003, 2004, 2005,
4 ;; 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
6 ;; Author: Daniel Pfeiffer <occitan@esperanto.org>
7 ;; Keywords: languages, unix
9 ;; This file is part of GNU Emacs.
11 ;; GNU Emacs is free software: you can redistribute it and/or modify
12 ;; it under the terms of the GNU General Public License as published by
13 ;; the Free Software Foundation, either version 3 of the License, or
14 ;; (at your option) any later version.
16 ;; GNU Emacs is distributed in the hope that it will be useful,
17 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 ;; GNU General Public License for more details.
21 ;; You should have received a copy of the GNU General Public License
22 ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
24 ;;; Commentary:
26 ;; executable.el is used by certain major modes to insert a suitable
27 ;; #! line at the beginning of the file, if the file does not already
28 ;; have one.
30 ;; Unless it has a magic number, a Unix file with executable mode is passed to
31 ;; a new instance of the running shell (or to a Bourne shell if a csh is
32 ;; running and the file starts with `:'). Only a shell can start such a file,
33 ;; exec() cannot, which is why it is important to have a magic number in every
34 ;; executable script. Such a magic number is made up by the characters `#!'
35 ;; the filename of an interpreter (in COFF, ELF or somesuch format) and one
36 ;; optional argument.
38 ;; This library is for certain major modes like sh-, awk-, perl-, tcl- or
39 ;; makefile-mode to insert or update a suitable #! line at the beginning of
40 ;; the file, if the file does not already have one and the file is not a
41 ;; default file of that interpreter (like .profile or makefile). It also
42 ;; makes the file executable if it wasn't, as soon as it's saved.
44 ;; It also allows debugging scripts, with an adaptation of compile, as far
45 ;; as interpreters give out meaningful error messages.
47 ;; Modes that use this should nconc `executable-map' to the end of their own
48 ;; keymap and `executable-font-lock-keywords' to the end of their own font
49 ;; lock keywords. Their mode-setting commands should call
50 ;; `executable-set-magic'.
52 ;;; Code:
54 (defgroup executable nil
55 "Base functionality for executable interpreter scripts."
56 :group 'processes)
58 ;; This used to default to `other', but that doesn't seem to have any
59 ;; significance. fx 2000-02-11.
60 (defcustom executable-insert t ; 'other
61 "*Non-nil means offer to add a magic number to a file.
62 This takes effect when you switch to certain major modes,
63 including Shell-script mode (`sh-mode').
64 When you type \\[executable-set-magic], it always offers to add or
65 update the magic number."
66 ;;; :type '(choice (const :tag "off" nil)
67 ;;; (const :tag "on" t)
68 ;;; symbol)
69 :type 'boolean
70 :group 'executable)
73 (defcustom executable-query 'function
74 "*If non-nil, ask user before changing an existing magic number.
75 When this is `function', only ask when called non-interactively."
76 :type '(choice (const :tag "Don't Ask" nil)
77 (const :tag "Ask when non-interactive" function)
78 (other :tag "Ask" t))
79 :group 'executable)
82 (defcustom executable-magicless-file-regexp "/[Mm]akefile$\\|/\\.\\(z?profile\\|bash_profile\\|z?login\\|bash_login\\|z?logout\\|bash_logout\\|.+shrc\\|esrc\\|rcrc\\|[kz]shenv\\)$"
83 "*On files with this kind of name no magic is inserted or changed."
84 :type 'regexp
85 :group 'executable)
88 (defcustom executable-prefix "#! "
89 "*Interpreter magic number prefix inserted when there was no magic number."
90 :type 'string
91 :group 'executable)
94 (defcustom executable-chmod 73
95 "*After saving, if the file is not executable, set this mode.
96 This mode passed to `set-file-modes' is taken absolutely when negative, or
97 relative to the files existing modes. Do nothing if this is nil.
98 Typical values are 73 (+x) or -493 (rwxr-xr-x)."
99 :type '(choice integer
100 (const nil))
101 :group 'executable)
104 (defvar executable-command nil)
106 (defcustom executable-self-display "tail"
107 "*Command you use with argument `+2' to make text files self-display.
108 Note that the like of `more' doesn't work too well under Emacs \\[shell]."
109 :type 'string
110 :group 'executable)
113 (defvar executable-font-lock-keywords
114 '(("\\`#!.*/\\([^ \t\n]+\\)" 1 font-lock-keyword-face t))
115 "*Rules for highlighting executable scripts' magic number.
116 This can be included in `font-lock-keywords' by modes that call `executable'.")
119 (defvar executable-error-regexp-alist
120 '(;; /bin/xyz: syntax error at line 14: `(' unexpected
121 ;; /bin/xyz[5]: syntax error at line 8 : ``' unmatched
122 ("^\\(.*[^[/]\\)\\(\\[[0-9]+\\]\\)?: .* error .* line \\([0-9]+\\)" 1 3)
123 ;; /bin/xyz[27]: ehco: not found
124 ("^\\(.*[^/]\\)\\[\\([0-9]+\\)\\]: .*: " 1 2)
125 ;; /bin/xyz: syntax error near unexpected token `)'
126 ;; /bin/xyz: /bin/xyz: line 2: `)'
127 ("^\\(.*[^/]\\): [^0-9\n]+\n\\1: \\1: line \\([0-9]+\\):" 1 2)
128 ;; /usr/bin/awk: syntax error at line 5 of file /bin/xyz
129 (" error .* line \\([0-9]+\\) of file \\(.+\\)$" 2 1)
130 ;; /usr/bin/awk: calling undefined function toto
131 ;; input record number 3, file awktestdata
132 ;; source line 4 of file /bin/xyz
133 ("^[^ ].+\n\\( .+\n\\)* line \\([0-9]+\\) of file \\(.+\\)$" 3 2)
134 ;; makefile:1: *** target pattern contains no `%'. Stop.
135 ("^\\(.+\\):\\([0-9]+\\): " 1 2))
136 "Alist of regexps used to match script errors.
137 See `compilation-error-regexp-alist'.")
139 ;; The C function openp slightly modified would do the trick fine
140 (defvaralias 'executable-binary-suffixes 'exec-suffixes)
142 ;;;###autoload
143 (defun executable-command-find-posix-p (&optional program)
144 "Check if PROGRAM handles arguments Posix-style.
145 If PROGRAM is non-nil, use that instead of \"find\"."
146 ;; Pick file to search from location we know
147 (let* ((dir (file-truename data-directory))
148 (file (car (directory-files dir nil "^[^.]"))))
149 (with-temp-buffer
150 (call-process (or program "find")
152 (current-buffer)
155 "-name"
156 file
157 "-maxdepth"
158 "1")
159 (goto-char (point-min))
160 (if (search-forward file nil t)
161 t))))
163 (defun executable-chmod ()
164 "This gets called after saving a file to assure that it be executable.
165 You can set the absolute or relative mode in variable `executable-chmod' for
166 non-executable files."
167 (and executable-chmod
168 buffer-file-name
169 (or (file-executable-p buffer-file-name)
170 (set-file-modes buffer-file-name
171 (if (< executable-chmod 0)
172 (- executable-chmod)
173 (logior executable-chmod
174 (file-modes buffer-file-name)))))))
177 ;;;###autoload
178 (defun executable-interpret (command)
179 "Run script with user-specified args, and collect output in a buffer.
180 While script runs asynchronously, you can use the \\[next-error]
181 command to find the next error. The buffer is also in `comint-mode' and
182 `compilation-shell-minor-mode', so that you can answer any prompts."
183 (interactive (list (read-string "Run script: "
184 (or executable-command
185 buffer-file-name))))
186 (require 'compile)
187 (save-some-buffers (not compilation-ask-about-save))
188 (set (make-local-variable 'executable-command) command)
189 (let ((compilation-error-regexp-alist executable-error-regexp-alist))
190 (compilation-start command t (lambda (x) "*interpretation*"))))
194 ;;;###autoload
195 (defun executable-set-magic (interpreter &optional argument
196 no-query-flag insert-flag)
197 "Set this buffer's interpreter to INTERPRETER with optional ARGUMENT.
198 The variables `executable-magicless-file-regexp', `executable-prefix',
199 `executable-insert', `executable-query' and `executable-chmod' control
200 when and how magic numbers are inserted or replaced and scripts made
201 executable."
202 (interactive
203 (let* ((name (read-string "Name or file name of interpreter: "))
204 (arg (read-string (format "Argument for %s: " name))))
205 (list name arg (eq executable-query 'function) t)))
207 (setq interpreter (if (file-name-absolute-p interpreter)
208 interpreter
209 (or (executable-find interpreter)
210 (error "Interpreter %s not recognized"
211 interpreter))))
213 (setq argument (concat (if (string-match "\\`/:" interpreter)
214 (replace-match "" nil nil interpreter)
215 interpreter)
216 (and argument (string< "" argument) " ")
217 argument))
219 (or buffer-read-only
220 (if buffer-file-name
221 (string-match executable-magicless-file-regexp
222 buffer-file-name))
223 (not (or insert-flag executable-insert))
224 (> (point-min) 1)
225 (save-excursion
226 (goto-char (point-min))
227 (add-hook 'after-save-hook 'executable-chmod nil t)
228 (if (looking-at "#![ \t]*\\(.*\\)$")
229 (and (goto-char (match-beginning 1))
230 ;; If the line ends in a space,
231 ;; don't offer to change it.
232 (not (= (char-after (1- (match-end 1))) ?\s))
233 (not (string= argument
234 (buffer-substring (point) (match-end 1))))
235 (if (or (not executable-query) no-query-flag
236 (save-window-excursion
237 ;; Make buffer visible before question.
238 (switch-to-buffer (current-buffer))
239 (y-or-n-p (concat "Replace magic number by `"
240 executable-prefix argument "'? "))))
241 (progn
242 (replace-match argument t t nil 1)
243 (message "Magic number changed to `%s'"
244 (concat executable-prefix argument)))))
245 (insert executable-prefix argument ?\n)
246 (message "Magic number changed to `%s'"
247 (concat executable-prefix argument)))))
248 interpreter)
252 ;;;###autoload
253 (defun executable-self-display ()
254 "Turn a text file into a self-displaying Un*x command.
255 The magic number of such a command displays all lines but itself."
256 (interactive)
257 (if (eq this-command 'executable-self-display)
258 (setq this-command 'executable-set-magic))
259 (executable-set-magic executable-self-display "+2"))
261 ;;;###autoload
262 (defun executable-make-buffer-file-executable-if-script-p ()
263 "Make file executable according to umask if not already executable.
264 If file already has any execute bits set at all, do not change existing
265 file modes."
266 (and (>= (buffer-size) 2)
267 (save-restriction
268 (widen)
269 (string= "#!" (buffer-substring (point-min) (+ 2 (point-min)))))
270 (let* ((current-mode (file-modes (buffer-file-name)))
271 (add-mode (logand ?\111 (default-file-modes))))
272 (or (/= (logand ?\111 current-mode) 0)
273 (zerop add-mode)
274 (set-file-modes (buffer-file-name)
275 (logior current-mode add-mode))))))
277 (provide 'executable)
279 ;;; executable.el ends here