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