Switch to recommended form of GPLv3 permissions notice.
[bpt/emacs.git] / lisp / progmodes / executable.el
CommitLineData
778e1d17 1;;; executable.el --- base functionality for executable interpreter scripts -*- byte-compile-dynamic: t -*-
b578f267 2
4e643dd2 3;; Copyright (C) 1994, 1995, 1996, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
034babe1 4;; Free Software Foundation, Inc.
58a4ff04 5
3e910376 6;; Author: Daniel Pfeiffer <occitan@esperanto.org>
58a4ff04
KH
7;; Keywords: languages, unix
8
9;; This file is part of GNU Emacs.
10
b1fc2b50 11;; GNU Emacs is free software: you can redistribute it and/or modify
58a4ff04 12;; it under the terms of the GNU General Public License as published by
b1fc2b50
GM
13;; the Free Software Foundation, either version 3 of the License, or
14;; (at your option) any later version.
58a4ff04
KH
15
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.
20
21;; You should have received a copy of the GNU General Public License
b1fc2b50 22;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
58a4ff04
KH
23
24;;; Commentary:
314001b5
RS
25
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.
29
252ed276
RS
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.
37
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.
43
44;; It also allows debugging scripts, with an adaptation of compile, as far
45;; as interpreters give out meaningful error messages.
46
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'.
4a789a51 51
58a4ff04
KH
52;;; Code:
53
bbf5eb28 54(defgroup executable nil
67da3b40 55 "Base functionality for executable interpreter scripts."
bbf5eb28
RS
56 :group 'processes)
57
778e1d17
DL
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
8d4e82b5
RS
61 "*Non-nil means offer to add a magic number to a file.
62This takes effect when you switch to certain major modes,
63including Shell-script mode (`sh-mode').
64When you type \\[executable-set-magic], it always offers to add or
bbf5eb28 65update the magic number."
778e1d17
DL
66;;; :type '(choice (const :tag "off" nil)
67;;; (const :tag "on" t)
68;;; symbol)
69 :type 'boolean
bbf5eb28 70 :group 'executable)
58a4ff04 71
58a4ff04 72
bbf5eb28
RS
73(defcustom executable-query 'function
74 "*If non-nil, ask user before changing an existing magic number.
75When this is `function', only ask when called non-interactively."
76 :type '(choice (const :tag "Don't Ask" nil)
0c3ba9b2
AS
77 (const :tag "Ask when non-interactive" function)
78 (other :tag "Ask" t))
bbf5eb28 79 :group 'executable)
58a4ff04 80
58a4ff04 81
bbf5eb28
RS
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)
58a4ff04 86
58a4ff04 87
bbf5eb28
RS
88(defcustom executable-prefix "#! "
89 "*Interpreter magic number prefix inserted when there was no magic number."
90 :type 'string
91 :group 'executable)
58a4ff04
KH
92
93
bbf5eb28 94(defcustom executable-chmod 73
58a4ff04
KH
95 "*After saving, if the file is not executable, set this mode.
96This mode passed to `set-file-modes' is taken absolutely when negative, or
97relative to the files existing modes. Do nothing if this is nil.
bbf5eb28 98Typical values are 73 (+x) or -493 (rwxr-xr-x)."
9cbf5df2
RS
99 :type '(choice integer
100 (const nil))
bbf5eb28 101 :group 'executable)
58a4ff04
KH
102
103
104(defvar executable-command nil)
105
bbf5eb28 106(defcustom executable-self-display "tail"
58a4ff04 107 "*Command you use with argument `+2' to make text files self-display.
778e1d17 108Note that the like of `more' doesn't work too well under Emacs \\[shell]."
bbf5eb28
RS
109 :type 'string
110 :group 'executable)
58a4ff04
KH
111
112
113(defvar executable-font-lock-keywords
114 '(("\\`#!.*/\\([^ \t\n]+\\)" 1 font-lock-keyword-face t))
115 "*Rules for highlighting executable scripts' magic number.
116This can be included in `font-lock-keywords' by modes that call `executable'.")
117
118
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.
137See `compilation-error-regexp-alist'.")
138
291c92b7 139;; The C function openp slightly modified would do the trick fine
2d08a2d4 140(defvaralias 'executable-binary-suffixes 'exec-suffixes)
778e1d17 141
14768716
RS
142;;;###autoload
143(defun executable-command-find-posix-p (&optional program)
144 "Check if PROGRAM handles arguments Posix-style.
679be517 145If PROGRAM is non-nil, use that instead of \"find\"."
14768716 146 ;; Pick file to search from location we know
c6190ba0
MR
147 (let* ((dir (file-truename data-directory))
148 (file (car (directory-files dir nil "^[^.]"))))
14768716
RS
149 (with-temp-buffer
150 (call-process (or program "find")
151 nil
152 (current-buffer)
153 nil
154 dir
155 "-name"
156 file
157 "-maxdepth"
158 "1")
159 (goto-char (point-min))
160 (if (search-forward file nil t)
161 t))))
162
58a4ff04
KH
163(defun executable-chmod ()
164 "This gets called after saving a file to assure that it be executable.
165You can set the absolute or relative mode in variable `executable-chmod' for
166non-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)))))))
175
176
78f617dd 177;;;###autoload
58a4ff04
KH
178(defun executable-interpret (command)
179 "Run script with user-specified args, and collect output in a buffer.
78f617dd
DP
180While script runs asynchronously, you can use the \\[next-error]
181command 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."
58a4ff04
KH
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))
78f617dd
DP
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*"))))
58a4ff04
KH
191
192
193
194;;;###autoload
291c92b7
KH
195(defun executable-set-magic (interpreter &optional argument
196 no-query-flag insert-flag)
58a4ff04
KH
197 "Set this buffer's interpreter to INTERPRETER with optional ARGUMENT.
198The variables `executable-magicless-file-regexp', `executable-prefix',
199`executable-insert', `executable-query' and `executable-chmod' control
200when and how magic numbers are inserted or replaced and scripts made
201executable."
291c92b7
KH
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)))
6c233cc0 206
58a4ff04
KH
207 (setq interpreter (if (file-name-absolute-p interpreter)
208 interpreter
291c92b7 209 (or (executable-find interpreter)
6c233cc0
GM
210 (error "Interpreter %s not recognized"
211 interpreter))))
212
213 (setq argument (concat (if (string-match "\\`/:" interpreter)
214 (replace-match "" nil nil interpreter)
215 interpreter)
58a4ff04
KH
216 (and argument (string< "" argument) " ")
217 argument))
6c233cc0 218
58a4ff04
KH
219 (or buffer-read-only
220 (if buffer-file-name
221 (string-match executable-magicless-file-regexp
222 buffer-file-name))
291c92b7 223 (not (or insert-flag executable-insert))
58a4ff04 224 (> (point-min) 1)
291c92b7 225 (save-excursion
1d88c1b3
SM
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.
67da3b40 232 (not (= (char-after (1- (match-end 1))) ?\s))
1d88c1b3
SM
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)))))
6c233cc0 248 interpreter)
58a4ff04
KH
249
250
251
252;;;###autoload
253(defun executable-self-display ()
254 "Turn a text file into a self-displaying Un*x command.
255The 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"))
260
778e1d17 261;;;###autoload
cc7e1d18 262(defun executable-make-buffer-file-executable-if-script-p ()
778e1d17
DL
263 "Make file executable according to umask if not already executable.
264If file already has any execute bits set at all, do not change existing
265file modes."
fd5f61d3
GM
266 (and (>= (buffer-size) 2)
267 (save-restriction
cc7e1d18 268 (widen)
1d88c1b3 269 (string= "#!" (buffer-substring (point-min) (+ 2 (point-min)))))
778e1d17
DL
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))))))
58a4ff04
KH
276
277(provide 'executable)
278
ba47dcb2 279;; arch-tag: 58458d1c-d9db-45ec-942b-8bbb1d5e319d
e8af40ee 280;;; executable.el ends here