Merge branch 'emacs-26' of git.savannah.gnu.org:/srv/git/emacs into emacs-26
[emacs.git] / lisp / progmodes / executable.el
blob9b556df89b4458eb646baba36071881e1264c2d8
1 ;;; executable.el --- base functionality for executable interpreter scripts -*- byte-compile-dynamic: t -*-
3 ;; Copyright (C) 1994-1996, 2000-2018 Free Software Foundation, Inc.
5 ;; Author: Daniel Pfeiffer <occitan@esperanto.org>
6 ;; Keywords: languages, unix
8 ;; This file is part of GNU Emacs.
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 3 of the License, or
13 ;; (at your option) any later version.
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.
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
23 ;;; Commentary:
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.
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.
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.
43 ;; It also allows debugging scripts, with an adaptation of compile, as far
44 ;; as interpreters give out meaningful error messages.
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'.
51 ;;; Code:
53 (defgroup executable nil
54 "Base functionality for executable interpreter scripts."
55 :group 'processes)
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
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 :type 'boolean
69 :group 'executable)
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 when non-interactive" function)
77 (other :tag "Ask" t))
78 :group 'executable)
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)
86 (defcustom executable-prefix "#!"
87 "Interpreter magic number prefix inserted when there was no magic number.
88 Use of `executable-prefix-env' is preferable to this option."
89 :version "26.1" ; deprecated
90 :type 'string
91 :group 'executable)
93 (defcustom executable-prefix-env nil
94 "If non-nil, use \"/usr/bin/env\" in interpreter magic number.
95 If this variable is non-nil, the interpreter magic number inserted
96 by `executable-set-magic' will be \"#!/usr/bin/env INTERPRETER\",
97 otherwise it will be \"#!/path/to/INTERPRETER\"."
98 :version "26.1"
99 :type 'boolean
100 :group 'executable)
102 (defcustom executable-chmod 73
103 "After saving, if the file is not executable, set this mode.
104 This mode passed to `set-file-modes' is taken absolutely when negative, or
105 relative to the files existing modes. Do nothing if this is nil.
106 Typical values are 73 (+x) or -493 (rwxr-xr-x)."
107 :type '(choice integer
108 (const nil))
109 :group 'executable)
112 (defvar executable-command nil)
114 (defcustom executable-self-display "tail"
115 "Command you use with argument `-n+2' to make text files self-display.
116 Note that the like of `more' doesn't work too well under Emacs \\[shell]."
117 :type 'string
118 :group 'executable)
120 (make-obsolete-variable 'executable-self-display nil "25.1" 'set)
123 (defvar executable-font-lock-keywords
124 '(("\\`#!.*/\\([^ \t\n]+\\)" 1 font-lock-keyword-face t))
125 "Rules for highlighting executable scripts' magic number.
126 This can be included in `font-lock-keywords' by modes that call `executable'.")
129 (defvar executable-error-regexp-alist
130 '(;; /bin/xyz: syntax error at line 14: `(' unexpected
131 ;; /bin/xyz[5]: syntax error at line 8 : ``' unmatched
132 ("^\\(.*[^[/]\\)\\(\\[[0-9]+\\]\\)?: .* error .* line \\([0-9]+\\)" 1 3)
133 ;; /bin/xyz[27]: ehco: not found
134 ("^\\(.*[^/]\\)\\[\\([0-9]+\\)\\]: .*: " 1 2)
135 ;; /bin/xyz: syntax error near unexpected token `)'
136 ;; /bin/xyz: /bin/xyz: line 2: `)'
137 ("^\\(.*[^/]\\): [^0-9\n]+\n\\1: \\1: line \\([0-9]+\\):" 1 2)
138 ;; /usr/bin/awk: syntax error at line 5 of file /bin/xyz
139 (" error .* line \\([0-9]+\\) of file \\(.+\\)$" 2 1)
140 ;; /usr/bin/awk: calling undefined function toto
141 ;; input record number 3, file awktestdata
142 ;; source line 4 of file /bin/xyz
143 ("^[^ ].+\n\\( .+\n\\)* line \\([0-9]+\\) of file \\(.+\\)$" 3 2)
144 ;; makefile:1: *** target pattern contains no `%'. Stop.
145 ("^\\(.+\\):\\([0-9]+\\): " 1 2))
146 "Alist of regexps used to match script errors.
147 See `compilation-error-regexp-alist'.")
149 ;; The C function openp slightly modified would do the trick fine
150 (defvaralias 'executable-binary-suffixes 'exec-suffixes)
152 ;;;###autoload
153 (defun executable-command-find-posix-p (&optional program)
154 "Check if PROGRAM handles arguments Posix-style.
155 If PROGRAM is non-nil, use that instead of \"find\"."
156 ;; Pick file to search from location we know
157 (let* ((dir (file-truename data-directory))
158 (file (car (directory-files dir nil "^[^.]"))))
159 (with-temp-buffer
160 (call-process (or program "find")
162 (current-buffer)
165 "-name"
166 file
167 "-maxdepth"
168 "1")
169 (goto-char (point-min))
170 (if (search-forward file nil t)
171 t))))
173 (defun executable-chmod ()
174 "This gets called after saving a file to assure that it be executable.
175 You can set the absolute or relative mode in variable `executable-chmod' for
176 non-executable files."
177 (and executable-chmod
178 buffer-file-name
179 (or (file-executable-p buffer-file-name)
180 (set-file-modes buffer-file-name
181 (if (< executable-chmod 0)
182 (- executable-chmod)
183 (logior executable-chmod
184 (file-modes buffer-file-name)))))))
187 (defvar compilation-error-regexp-alist) ; from compile.el
189 ;;;###autoload
190 (defun executable-interpret (command)
191 "Run script with user-specified args, and collect output in a buffer.
192 While script runs asynchronously, you can use the \\[next-error]
193 command to find the next error. The buffer is also in `comint-mode' and
194 `compilation-shell-minor-mode', so that you can answer any prompts."
195 (interactive (list (read-string "Run script: "
196 (or executable-command
197 buffer-file-name))))
198 (require 'compile)
199 (save-some-buffers (not compilation-ask-about-save))
200 (set (make-local-variable 'executable-command) command)
201 (let ((compilation-error-regexp-alist executable-error-regexp-alist))
202 (compilation-start command t (lambda (_x) "*interpretation*"))))
206 ;;;###autoload
207 (defun executable-set-magic (interpreter &optional argument
208 no-query-flag insert-flag)
209 "Set this buffer's interpreter to INTERPRETER with optional ARGUMENT.
210 The variables `executable-magicless-file-regexp', `executable-prefix-env',
211 `executable-insert', `executable-query' and `executable-chmod' control
212 when and how magic numbers are inserted or replaced and scripts made
213 executable."
214 (interactive
215 (let* ((name (read-string "Name or file name of interpreter: "))
216 (arg (read-string (format "Argument for %s: " name))))
217 (list name arg (eq executable-query 'function) t)))
219 (setq interpreter (if (file-name-absolute-p interpreter)
220 interpreter
221 (or (executable-find interpreter)
222 (error "Interpreter %s not recognized"
223 interpreter))))
225 (setq argument (concat (if (string-match "\\`/:" interpreter)
226 (replace-match "" nil nil interpreter)
227 interpreter)
228 (and argument (string< "" argument) " ")
229 argument))
231 ;; For backward compatibility, allow `executable-prefix-env' to be
232 ;; overridden by custom `executable-prefix'.
233 (if (string-match "#!\\([ \t]*/usr/bin/env[ \t]*\\)?$" executable-prefix)
234 (if executable-prefix-env
235 (setq argument (concat "/usr/bin/env "
236 (file-name-nondirectory argument))))
237 (setq argument (concat (substring executable-prefix 2) argument)))
239 (or buffer-read-only
240 (if buffer-file-name
241 (string-match executable-magicless-file-regexp
242 buffer-file-name))
243 (not (or insert-flag executable-insert))
244 (> (point-min) 1)
245 (save-excursion
246 (goto-char (point-min))
247 (add-hook 'after-save-hook 'executable-chmod nil t)
248 (if (looking-at "#![ \t]*\\(.*\\)$")
249 (and (goto-char (match-beginning 1))
250 ;; If the line ends in a space,
251 ;; don't offer to change it.
252 (not (= (char-after (1- (match-end 1))) ?\s))
253 (not (string= argument
254 (buffer-substring (point) (match-end 1))))
255 (if (or (not executable-query) no-query-flag
256 (save-window-excursion
257 ;; Make buffer visible before question.
258 (switch-to-buffer (current-buffer))
259 (y-or-n-p (format-message
260 "Replace magic number by `#!%s'? "
261 argument))))
262 (progn
263 (replace-match argument t t nil 1)
264 (message "Magic number changed to `#!%s'" argument))))
265 (insert "#!" argument ?\n)
266 (message "Magic number changed to `#!%s'" argument))))
267 interpreter)
271 (defun executable-self-display ()
272 "Turn a text file into a self-displaying Un*x command.
273 The magic number of such a command displays all lines but itself."
274 (declare (obsolete nil "25.1"))
275 (interactive)
276 (if (eq this-command 'executable-self-display)
277 (setq this-command 'executable-set-magic))
278 (executable-set-magic executable-self-display "-n+2"))
280 ;;;###autoload
281 (defun executable-make-buffer-file-executable-if-script-p ()
282 "Make file executable according to umask if not already executable.
283 If file already has any execute bits set at all, do not change existing
284 file modes."
285 (and (>= (buffer-size) 2)
286 (save-restriction
287 (widen)
288 (string= "#!" (buffer-substring (point-min) (+ 2 (point-min)))))
289 ;; Eg file-modes can return nil (bug#9879). It should not,
290 ;; in this context, but we should handle it all the same.
291 (with-demoted-errors "Unable to make file executable: %s"
292 (let* ((current-mode (file-modes (buffer-file-name)))
293 (add-mode (logand ?\111 (default-file-modes))))
294 (or (/= (logand ?\111 current-mode) 0)
295 (zerop add-mode)
296 (set-file-modes (buffer-file-name)
297 (logior current-mode add-mode)))))))
299 (provide 'executable)
301 ;;; executable.el ends here