(executable-binary-suffixes): New variable.
[bpt/emacs.git] / lisp / progmodes / executable.el
1 ;;; executable.el --- base functionality for executable interpreter scripts
2
3 ;; Copyright (C) 1994, 1995, 1996 by Free Software Foundation, Inc.
4
5 ;; Author: Daniel.Pfeiffer@Informatik.START.dbp.de
6 ;; fax (+49 69) 7588-2389
7 ;; Keywords: languages, unix
8
9 ;; This file is part of GNU Emacs.
10
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 2, or (at your option)
14 ;; any later version.
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
22 ;; along with GNU Emacs; see the file COPYING. If not, write to the
23 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
24 ;; Boston, MA 02111-1307, USA.
25
26 ;;; Commentary:
27
28 ;; executable.el is used by certain major modes to insert a suitable
29 ;; #! line at the beginning of the file, if the file does not already
30 ;; have one.
31
32 ;; Unless it has a magic number, a Unix file with executable mode is passed to
33 ;; a new instance of the running shell (or to a Bourne shell if a csh is
34 ;; running and the file starts with `:'). Only a shell can start such a file,
35 ;; exec() cannot, which is why it is important to have a magic number in every
36 ;; executable script. Such a magic number is made up by the characters `#!'
37 ;; the filename of an interpreter (in COFF, ELF or somesuch format) and one
38 ;; optional argument.
39
40 ;; This library is for certain major modes like sh-, awk-, perl-, tcl- or
41 ;; makefile-mode to insert or update a suitable #! line at the beginning of
42 ;; the file, if the file does not already have one and the file is not a
43 ;; default file of that interpreter (like .profile or makefile). It also
44 ;; makes the file executable if it wasn't, as soon as it's saved.
45
46 ;; It also allows debugging scripts, with an adaptation of compile, as far
47 ;; as interpreters give out meaningful error messages.
48
49 ;; Modes that use this should nconc `executable-map' to the end of their own
50 ;; keymap and `executable-font-lock-keywords' to the end of their own font
51 ;; lock keywords. Their mode-setting commands should call
52 ;; `executable-set-magic'.
53
54 ;;; Code:
55
56 (defgroup executable nil
57 "Base functionality for executable interpreter scripts"
58 :group 'processes)
59
60 (defcustom executable-insert '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 :group 'executable)
70
71
72 (defcustom executable-query 'function
73 "*If non-nil, ask user before changing an existing magic number.
74 When this is `function', only ask when called non-interactively."
75 :type '(choice (const :tag "Don't Ask" nil)
76 (const :tag "Ask" t)
77 (const :tag "Ask when non-interactive" function))
78 :group 'executable)
79
80
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)
85
86
87 (defcustom executable-prefix "#! "
88 "*Interpreter magic number prefix inserted when there was no magic number."
89 :type 'string
90 :group 'executable)
91
92
93 (defcustom executable-chmod 73
94 "*After saving, if the file is not executable, set this mode.
95 This mode passed to `set-file-modes' is taken absolutely when negative, or
96 relative to the files existing modes. Do nothing if this is nil.
97 Typical values are 73 (+x) or -493 (rwxr-xr-x)."
98 :type '(choice integer
99 (const nil))
100 :group 'executable)
101
102
103 (defvar executable-command nil)
104
105 (defcustom executable-self-display "tail"
106 "*Command you use with argument `+2' to make text files self-display.
107 Note that the like of `more' doesn't work too well under Emacs \\[shell]."
108 :type 'string
109 :group 'executable)
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.
115 This 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.
136 See `compilation-error-regexp-alist'.")
137
138 ;; The C function openp slightly modified would do the trick fine
139 (defvar executable-binary-suffixes
140 (if (memq system-type '(ms-dos windows-nt))
141 '(".exe" ".com" ".bat" ".cmd" ".btm" "")
142 '("")))
143 (defun executable-find (command)
144 "Search for COMMAND in exec-path and return the absolute file name.
145 Return nil if COMMAND is not found anywhere in `exec-path'."
146 (let ((list exec-path)
147 file)
148 (while list
149 (setq list
150 (if (and (setq file (expand-file-name command (car list)))
151 (let ((suffixes executable-binary-suffixes)
152 candidate)
153 (while suffixes
154 (setq candidate (concat file (car suffixes)))
155 (if (and (file-executable-p candidate)
156 (not (file-directory-p candidate)))
157 (setq suffixes nil)
158 (setq suffixes (cdr suffixes))
159 (setq candidate nil)))
160 (setq file candidate)))
161 nil
162 (setq file nil)
163 (cdr list))))
164 file))
165
166 (defun executable-chmod ()
167 "This gets called after saving a file to assure that it be executable.
168 You can set the absolute or relative mode in variable `executable-chmod' for
169 non-executable files."
170 (and executable-chmod
171 buffer-file-name
172 (or (file-executable-p buffer-file-name)
173 (set-file-modes buffer-file-name
174 (if (< executable-chmod 0)
175 (- executable-chmod)
176 (logior executable-chmod
177 (file-modes buffer-file-name)))))))
178
179
180 (defun executable-interpret (command)
181 "Run script with user-specified args, and collect output in a buffer.
182 While script runs asynchronously, you can use the \\[next-error] command
183 to find the next error."
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))
189 (make-local-variable 'executable-command)
190 (compile-internal (setq executable-command command)
191 "No more errors." "Interpretation"
192 ;; Give it a simpler regexp to match.
193 nil executable-error-regexp-alist))
194
195
196
197 ;;;###autoload
198 (defun executable-set-magic (interpreter &optional argument
199 no-query-flag insert-flag)
200 "Set this buffer's interpreter to INTERPRETER with optional ARGUMENT.
201 The variables `executable-magicless-file-regexp', `executable-prefix',
202 `executable-insert', `executable-query' and `executable-chmod' control
203 when and how magic numbers are inserted or replaced and scripts made
204 executable."
205 (interactive
206 (let* ((name (read-string "Name or file name of interpreter: "))
207 (arg (read-string (format "Argument for %s: " name))))
208 (list name arg (eq executable-query 'function) t)))
209 (setq interpreter (if (file-name-absolute-p interpreter)
210 interpreter
211 (or (executable-find interpreter)
212 (error "Interpreter %s not recognized" interpreter)))
213 argument (concat interpreter
214 (and argument (string< "" argument) " ")
215 argument))
216 (or buffer-read-only
217 (if buffer-file-name
218 (string-match executable-magicless-file-regexp
219 buffer-file-name))
220 (not (or insert-flag executable-insert))
221 (> (point-min) 1)
222 (save-excursion
223 (let ((point (point-marker))
224 (buffer-modified-p (buffer-modified-p)))
225 (goto-char (point-min))
226 (make-local-hook 'after-save-hook)
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))) ?\ ))
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 ;;; (or insert-flag
249 ;;; (eq executable-insert t)
250 ;;; (set-buffer-modified-p buffer-modified-p))
251 )))
252 interpreter)
253
254
255
256 ;;;###autoload
257 (defun executable-self-display ()
258 "Turn a text file into a self-displaying Un*x command.
259 The magic number of such a command displays all lines but itself."
260 (interactive)
261 (if (eq this-command 'executable-self-display)
262 (setq this-command 'executable-set-magic))
263 (executable-set-magic executable-self-display "+2"))
264
265
266
267 (provide 'executable)
268
269 ;; executable.el ends here