(fortran-font-lock-keywords-1): Warp
[bpt/emacs.git] / lisp / progmodes / executable.el
CommitLineData
58a4ff04 1;;; executable.el --- base functionality for executable interpreter scripts
b578f267
EN
2
3;; Copyright (C) 1994, 1995, 1996 by Free Software Foundation, Inc.
58a4ff04 4
0acdb863
RS
5;; Author: Daniel.Pfeiffer@Informatik.START.dbp.de
6;; fax (+49 69) 7588-2389
58a4ff04
KH
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
b578f267
EN
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.
58a4ff04
KH
25
26;;; Commentary:
314001b5
RS
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
252ed276
RS
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'.
4a789a51 53
58a4ff04
KH
54;;; Code:
55
bbf5eb28
RS
56(defgroup executable nil
57 "Base functionality for executable interpreter scripts"
58 :group 'processes)
59
60(defcustom executable-insert '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
RS
65update the magic number."
66 :type '(choice (const :tag "off" nil)
67 (const :tag "on" t)
68 symbol)
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.
bbf5eb28
RS
107Note that the like of `more' doesn't work too well under Emacs \\[shell]."
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
80e1568a
RS
139(defvar executable-binary-suffixes
140 (if (memq system-type '(ms-dos windows-nt))
141 '(".exe" ".com" ".bat" ".cmd" ".btm" "")
142 '("")))
291c92b7 143(defun executable-find (command)
6ddc496f 144 "Search for COMMAND in exec-path and return the absolute file name.
77a039e2 145Return nil if COMMAND is not found anywhere in `exec-path'."
58a4ff04 146 (let ((list exec-path)
291c92b7 147 file)
58a4ff04 148 (while list
80e1568a
RS
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))))
291c92b7 164 file))
58a4ff04 165
58a4ff04
KH
166(defun executable-chmod ()
167 "This gets called after saving a file to assure that it be executable.
168You can set the absolute or relative mode in variable `executable-chmod' for
169non-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.
182While script runs asynchronously, you can use the \\[next-error] command
183to 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
291c92b7
KH
198(defun executable-set-magic (interpreter &optional argument
199 no-query-flag insert-flag)
58a4ff04
KH
200 "Set this buffer's interpreter to INTERPRETER with optional ARGUMENT.
201The variables `executable-magicless-file-regexp', `executable-prefix',
202`executable-insert', `executable-query' and `executable-chmod' control
203when and how magic numbers are inserted or replaced and scripts made
204executable."
291c92b7
KH
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)))
58a4ff04
KH
209 (setq interpreter (if (file-name-absolute-p interpreter)
210 interpreter
291c92b7
KH
211 (or (executable-find interpreter)
212 (error "Interpreter %s not recognized" interpreter)))
58a4ff04
KH
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))
291c92b7 220 (not (or insert-flag executable-insert))
58a4ff04 221 (> (point-min) 1)
291c92b7
KH
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))
77f76e3e
RS
230 ;; If the line ends in a space,
231 ;; don't offer to change it.
232 (not (= (char-after (1- (match-end 1))) ?\ ))
291c92b7
KH
233 (not (string= argument
234 (buffer-substring (point) (match-end 1))))
77f76e3e
RS
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'"
3fbe4759 244 (concat executable-prefix argument)))))
291c92b7
KH
245 (insert executable-prefix argument ?\n)
246 (message "Magic number changed to `%s'"
247 (concat executable-prefix argument)))
77f76e3e
RS
248;;; (or insert-flag
249;;; (eq executable-insert t)
250;;; (set-buffer-modified-p buffer-modified-p))
251 )))
58a4ff04
KH
252 interpreter)
253
254
255
256;;;###autoload
257(defun executable-self-display ()
258 "Turn a text file into a self-displaying Un*x command.
259The 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