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