]> code.delx.au - gnu-emacs/blob - lisp/progmodes/executable.el
* faces.el (secondary-selection): Change background to yellow.
[gnu-emacs] / 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 <occitan@esperanto.org>
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
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.
24
25 ;;; Commentary:
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
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'.
52
53 ;;; Code:
54
55 (defgroup executable nil
56 "Base functionality for executable interpreter scripts"
57 :group 'processes)
58
59 (defcustom executable-insert 'other
60 "*Non-nil means offer to add a magic number to a file.
61 This takes effect when you switch to certain major modes,
62 including Shell-script mode (`sh-mode').
63 When you type \\[executable-set-magic], it always offers to add or
64 update the magic number."
65 :type '(choice (const :tag "off" nil)
66 (const :tag "on" t)
67 symbol)
68 :group 'executable)
69
70
71 (defcustom executable-query 'function
72 "*If non-nil, ask user before changing an existing magic number.
73 When this is `function', only ask when called non-interactively."
74 :type '(choice (const :tag "Don't Ask" nil)
75 (const :tag "Ask when non-interactive" function)
76 (other :tag "Ask" t))
77 :group 'executable)
78
79
80 (defcustom executable-magicless-file-regexp "/[Mm]akefile$\\|/\\.\\(z?profile\\|bash_profile\\|z?login\\|bash_login\\|z?logout\\|bash_logout\\|.+shrc\\|esrc\\|rcrc\\|[kz]shenv\\)$"
81 "*On files with this kind of name no magic is inserted or changed."
82 :type 'regexp
83 :group 'executable)
84
85
86 (defcustom executable-prefix "#! "
87 "*Interpreter magic number prefix inserted when there was no magic number."
88 :type 'string
89 :group 'executable)
90
91
92 (defcustom executable-chmod 73
93 "*After saving, if the file is not executable, set this mode.
94 This mode passed to `set-file-modes' is taken absolutely when negative, or
95 relative to the files existing modes. Do nothing if this is nil.
96 Typical values are 73 (+x) or -493 (rwxr-xr-x)."
97 :type '(choice integer
98 (const nil))
99 :group 'executable)
100
101
102 (defvar executable-command nil)
103
104 (defcustom executable-self-display "tail"
105 "*Command you use with argument `+2' to make text files self-display.
106 Note that the like of `more' doesn't work too well under Emacs \\[shell]."
107 :type 'string
108 :group 'executable)
109
110
111 (defvar executable-font-lock-keywords
112 '(("\\`#!.*/\\([^ \t\n]+\\)" 1 font-lock-keyword-face t))
113 "*Rules for highlighting executable scripts' magic number.
114 This can be included in `font-lock-keywords' by modes that call `executable'.")
115
116
117 (defvar executable-error-regexp-alist
118 '(;; /bin/xyz: syntax error at line 14: `(' unexpected
119 ;; /bin/xyz[5]: syntax error at line 8 : ``' unmatched
120 ("^\\(.*[^[/]\\)\\(\\[[0-9]+\\]\\)?: .* error .* line \\([0-9]+\\)" 1 3)
121 ;; /bin/xyz[27]: ehco: not found
122 ("^\\(.*[^/]\\)\\[\\([0-9]+\\)\\]: .*: " 1 2)
123 ;; /bin/xyz: syntax error near unexpected token `)'
124 ;; /bin/xyz: /bin/xyz: line 2: `)'
125 ("^\\(.*[^/]\\): [^0-9\n]+\n\\1: \\1: line \\([0-9]+\\):" 1 2)
126 ;; /usr/bin/awk: syntax error at line 5 of file /bin/xyz
127 (" error .* line \\([0-9]+\\) of file \\(.+\\)$" 2 1)
128 ;; /usr/bin/awk: calling undefined function toto
129 ;; input record number 3, file awktestdata
130 ;; source line 4 of file /bin/xyz
131 ("^[^ ].+\n\\( .+\n\\)* line \\([0-9]+\\) of file \\(.+\\)$" 3 2)
132 ;; makefile:1: *** target pattern contains no `%'. Stop.
133 ("^\\(.+\\):\\([0-9]+\\): " 1 2))
134 "Alist of regexps used to match script errors.
135 See `compilation-error-regexp-alist'.")
136
137 ;; The C function openp slightly modified would do the trick fine
138 (defvar executable-binary-suffixes
139 (if (memq system-type '(ms-dos windows-nt))
140 '(".exe" ".com" ".bat" ".cmd" ".btm" "")
141 '("")))
142 (defun executable-find (command)
143 "Search for COMMAND in exec-path and return the absolute file name.
144 Return nil if COMMAND is not found anywhere in `exec-path'."
145 (let ((list exec-path)
146 file)
147 (while list
148 (setq list
149 (if (and (setq file (expand-file-name command (car list)))
150 (let ((suffixes executable-binary-suffixes)
151 candidate)
152 (while suffixes
153 (setq candidate (concat file (car suffixes)))
154 (if (and (file-executable-p candidate)
155 (not (file-directory-p candidate)))
156 (setq suffixes nil)
157 (setq suffixes (cdr suffixes))
158 (setq candidate nil)))
159 (setq file candidate)))
160 nil
161 (setq file nil)
162 (cdr list))))
163 file))
164
165 (defun executable-chmod ()
166 "This gets called after saving a file to assure that it be executable.
167 You can set the absolute or relative mode in variable `executable-chmod' for
168 non-executable files."
169 (and executable-chmod
170 buffer-file-name
171 (or (file-executable-p buffer-file-name)
172 (set-file-modes buffer-file-name
173 (if (< executable-chmod 0)
174 (- executable-chmod)
175 (logior executable-chmod
176 (file-modes buffer-file-name)))))))
177
178
179 (defun executable-interpret (command)
180 "Run script with user-specified args, and collect output in a buffer.
181 While script runs asynchronously, you can use the \\[next-error] command
182 to find the next error."
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))
188 (make-local-variable 'executable-command)
189 (compile-internal (setq executable-command command)
190 "No more errors." "Interpretation"
191 ;; Give it a simpler regexp to match.
192 nil executable-error-regexp-alist))
193
194
195
196 ;;;###autoload
197 (defun executable-set-magic (interpreter &optional argument
198 no-query-flag insert-flag)
199 "Set this buffer's interpreter to INTERPRETER with optional ARGUMENT.
200 The variables `executable-magicless-file-regexp', `executable-prefix',
201 `executable-insert', `executable-query' and `executable-chmod' control
202 when and how magic numbers are inserted or replaced and scripts made
203 executable."
204 (interactive
205 (let* ((name (read-string "Name or file name of interpreter: "))
206 (arg (read-string (format "Argument for %s: " name))))
207 (list name arg (eq executable-query 'function) t)))
208 (setq interpreter (if (file-name-absolute-p interpreter)
209 interpreter
210 (or (executable-find interpreter)
211 (error "Interpreter %s not recognized" interpreter)))
212 argument (concat interpreter
213 (and argument (string< "" argument) " ")
214 argument))
215 (or buffer-read-only
216 (if buffer-file-name
217 (string-match executable-magicless-file-regexp
218 buffer-file-name))
219 (not (or insert-flag executable-insert))
220 (> (point-min) 1)
221 (save-excursion
222 (let ((point (point-marker))
223 (buffer-modified-p (buffer-modified-p)))
224 (goto-char (point-min))
225 (make-local-hook 'after-save-hook)
226 (add-hook 'after-save-hook 'executable-chmod nil t)
227 (if (looking-at "#![ \t]*\\(.*\\)$")
228 (and (goto-char (match-beginning 1))
229 ;; If the line ends in a space,
230 ;; don't offer to change it.
231 (not (= (char-after (1- (match-end 1))) ?\ ))
232 (not (string= argument
233 (buffer-substring (point) (match-end 1))))
234 (if (or (not executable-query) no-query-flag
235 (save-window-excursion
236 ;; Make buffer visible before question.
237 (switch-to-buffer (current-buffer))
238 (y-or-n-p (concat "Replace magic number by `"
239 executable-prefix argument "'? "))))
240 (progn
241 (replace-match argument t t nil 1)
242 (message "Magic number changed to `%s'"
243 (concat executable-prefix argument)))))
244 (insert executable-prefix argument ?\n)
245 (message "Magic number changed to `%s'"
246 (concat executable-prefix argument)))
247 ;;; (or insert-flag
248 ;;; (eq executable-insert t)
249 ;;; (set-buffer-modified-p buffer-modified-p))
250 )))
251 interpreter)
252
253
254
255 ;;;###autoload
256 (defun executable-self-display ()
257 "Turn a text file into a self-displaying Un*x command.
258 The magic number of such a command displays all lines but itself."
259 (interactive)
260 (if (eq this-command 'executable-self-display)
261 (setq this-command 'executable-set-magic))
262 (executable-set-magic executable-self-display "+2"))
263
264
265
266 (provide 'executable)
267
268 ;; executable.el ends here