aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorReuben Thomas2016-12-01 15:21:57 +0000
committerReuben Thomas2017-08-30 21:59:38 +0100
commit98f01a13a3bf2a4db2dcc82a342ee017326de732 (patch)
tree70aac99762c0ee95026ec72fc307304b6700d372
parentdc313922d826b9f53cf1426ff36c8cc3f71d64c6 (diff)
downloademacs-98f01a13a3bf2a4db2dcc82a342ee017326de732.tar.gz
emacs-98f01a13a3bf2a4db2dcc82a342ee017326de732.zip
Add support for arguments in emacsclient's ALTERNATE_EDITOR (Bug #25082)
* lib-src/emacsclient.c (fail): Parse ALTERNATE_EDITOR, or corresponding command-line argument, into quote- or space-separated tokens. If a token starts with a quote, then it naturally is expected to end with a quote; escaping is not supported. This is enough to cope with the typical case of requiring the initial path to be quoted, common on Windows where it may contain spaces. * etc/NEWS: Document. * doc/emacs/misc.texi: Likewise. * doc/man/emacsclient.1: Tweak to remove the implication that only an editor can be specified (the manual already mentions a “command”). Fix a small error where “EDITOR” is referred to rather than “ALTERNATE_EDITOR”. * test/lib-src/emacsclient-tests.el: Add tests.
-rw-r--r--doc/emacs/misc.texi4
-rw-r--r--doc/man/emacsclient.16
-rw-r--r--etc/NEWS7
-rw-r--r--lib-src/emacsclient.c84
-rw-r--r--test/lib-src/emacsclient-tests.el50
5 files changed, 129 insertions, 22 deletions
diff --git a/doc/emacs/misc.texi b/doc/emacs/misc.texi
index 73a6bae767a..7602fbb7454 100644
--- a/doc/emacs/misc.texi
+++ b/doc/emacs/misc.texi
@@ -1821,8 +1821,10 @@ listed below:
1821@table @samp 1821@table @samp
1822@item -a @var{command} 1822@item -a @var{command}
1823@itemx --alternate-editor=@var{command} 1823@itemx --alternate-editor=@var{command}
1824Specify a command to run if @code{emacsclient} fails to contact Emacs. 1824Specify a shell command to run if @code{emacsclient} fails to contact Emacs.
1825This is useful when running @code{emacsclient} in a script. 1825This is useful when running @code{emacsclient} in a script.
1826The command may include arguments, which may be quoted "like this".
1827Currently, escaping of quotes is not supported.
1826 1828
1827As a special exception, if @var{command} is the empty string, then 1829As a special exception, if @var{command} is the empty string, then
1828@code{emacsclient} starts Emacs in daemon mode (as @command{emacs 1830@code{emacsclient} starts Emacs in daemon mode (as @command{emacs
diff --git a/doc/man/emacsclient.1 b/doc/man/emacsclient.1
index 010eeba19c1..daaacab7f3e 100644
--- a/doc/man/emacsclient.1
+++ b/doc/man/emacsclient.1
@@ -62,10 +62,10 @@ A missing
62is treated as column 1. 62is treated as column 1.
63This option applies only to the next file specified. 63This option applies only to the next file specified.
64.TP 64.TP
65.B \-a, \-\-alternate-editor=EDITOR 65.B \-a, \-\-alternate-editor=COMMAND
66if the Emacs server is not running, run the specified editor instead. 66if the Emacs server is not running, run the specified shell command instead.
67This can also be specified via the ALTERNATE_EDITOR environment variable. 67This can also be specified via the ALTERNATE_EDITOR environment variable.
68If the value of EDITOR is the empty string, run "emacs \-\-daemon" to 68If the value of ALTERNATE_EDITOR is the empty string, run "emacs \-\-daemon" to
69start Emacs in daemon mode, and try to connect to it. 69start Emacs in daemon mode, and try to connect to it.
70.TP 70.TP
71.B -c, \-\-create-frame 71.B -c, \-\-create-frame
diff --git a/etc/NEWS b/etc/NEWS
index ef4d8cda397..0889303f82e 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -485,6 +485,13 @@ Linum mode and all similar packages are henceforth becoming obsolete.
485Users and developers are encouraged to switch to this new feature 485Users and developers are encouraged to switch to this new feature
486instead. 486instead.
487 487
488+++
489** emacsclient now accepts command-line options in ALTERNATE_EDITOR
490and --alternate-editor. For example, ALTERNATE_EDITOR="emacs -Q -nw".
491Arguments may be quoted "like this", so that for example an absolute
492path containing a space may be specified; quote escaping is not
493supported.
494
488 495
489* Editing Changes in Emacs 26.1 496* Editing Changes in Emacs 26.1
490 497
diff --git a/lib-src/emacsclient.c b/lib-src/emacsclient.c
index f1d4e8976da..5e181ccacb1 100644
--- a/lib-src/emacsclient.c
+++ b/lib-src/emacsclient.c
@@ -110,6 +110,9 @@ char *w32_getenv (const char *);
110/* Name used to invoke this program. */ 110/* Name used to invoke this program. */
111const char *progname; 111const char *progname;
112 112
113/* The first argument to main. */
114int main_argc;
115
113/* The second argument to main. */ 116/* The second argument to main. */
114char **main_argv; 117char **main_argv;
115 118
@@ -201,6 +204,35 @@ xmalloc (size_t size)
201 return result; 204 return result;
202} 205}
203 206
207/* Like realloc but get fatal error if memory is exhausted. */
208
209static void *
210xrealloc (void *ptr, size_t size)
211{
212 void *result = realloc (ptr, size);
213 if (result == NULL)
214 {
215 perror ("realloc");
216 exit (EXIT_FAILURE);
217 }
218 return result;
219}
220
221/* Like strdup but get a fatal error if memory is exhausted. */
222char *xstrdup (const char *);
223
224char *
225xstrdup (const char *s)
226{
227 char *result = strdup (s);
228 if (result == NULL)
229 {
230 perror ("strdup");
231 exit (EXIT_FAILURE);
232 }
233 return result;
234}
235
204/* From sysdep.c */ 236/* From sysdep.c */
205#if !defined (HAVE_GET_CURRENT_DIR_NAME) || defined (BROKEN_GET_CURRENT_DIR_NAME) 237#if !defined (HAVE_GET_CURRENT_DIR_NAME) || defined (BROKEN_GET_CURRENT_DIR_NAME)
206 238
@@ -264,21 +296,6 @@ get_current_dir_name (void)
264 296
265#ifdef WINDOWSNT 297#ifdef WINDOWSNT
266 298
267/* Like strdup but get a fatal error if memory is exhausted. */
268char *xstrdup (const char *);
269
270char *
271xstrdup (const char *s)
272{
273 char *result = strdup (s);
274 if (result == NULL)
275 {
276 perror ("strdup");
277 exit (EXIT_FAILURE);
278 }
279 return result;
280}
281
282#define REG_ROOT "SOFTWARE\\GNU\\Emacs" 299#define REG_ROOT "SOFTWARE\\GNU\\Emacs"
283 300
284char *w32_get_resource (HKEY, const char *, LPDWORD); 301char *w32_get_resource (HKEY, const char *, LPDWORD);
@@ -673,7 +690,7 @@ Report bugs with M-x report-emacs-bug.\n");
673} 690}
674 691
675/* Try to run a different command, or --if no alternate editor is 692/* Try to run a different command, or --if no alternate editor is
676 defined-- exit with an errorcode. 693 defined-- exit with an error code.
677 Uses argv, but gets it from the global variable main_argv. */ 694 Uses argv, but gets it from the global variable main_argv. */
678 695
679static _Noreturn void 696static _Noreturn void
@@ -681,9 +698,38 @@ fail (void)
681{ 698{
682 if (alternate_editor) 699 if (alternate_editor)
683 { 700 {
684 int i = optind - 1; 701 size_t extra_args_size = (main_argc - optind + 1) * sizeof (char *);
702 size_t new_argv_size = extra_args_size;
703 char **new_argv = NULL;
704 char *s = xstrdup (alternate_editor);
705 unsigned toks = 0;
706
707 /* Unpack alternate_editor's space-separated tokens into new_argv. */
708 for (char *tok = s; tok != NULL && *tok != '\0';)
709 {
710 /* Allocate new token. */
711 ++toks;
712 new_argv = xrealloc (new_argv, new_argv_size + toks * sizeof (char *));
713
714 /* Skip leading delimiters, and set separator, skipping any
715 opening quote. */
716 size_t skip = strspn (tok, " \"");
717 tok += skip;
718 char sep = (skip > 0 && tok[-1] == '"') ? '"' : ' ';
719
720 /* Record start of token. */
721 new_argv[toks - 1] = tok;
722
723 /* Find end of token and overwrite it with NUL. */
724 tok = strchr (tok, sep);
725 if (tok != NULL)
726 *tok++ = '\0';
727 }
728
729 /* Append main_argv arguments to new_argv. */
730 memcpy (&new_argv[toks], main_argv + optind, extra_args_size);
685 731
686 execvp (alternate_editor, main_argv + i); 732 execvp (*new_argv, new_argv);
687 message (true, "%s: error executing alternate editor \"%s\"\n", 733 message (true, "%s: error executing alternate editor \"%s\"\n",
688 progname, alternate_editor); 734 progname, alternate_editor);
689 } 735 }
@@ -696,6 +742,7 @@ fail (void)
696int 742int
697main (int argc, char **argv) 743main (int argc, char **argv)
698{ 744{
745 main_argc = argc;
699 main_argv = argv; 746 main_argv = argv;
700 progname = argv[0]; 747 progname = argv[0];
701 message (true, "%s: Sorry, the Emacs server is supported only\n" 748 message (true, "%s: Sorry, the Emacs server is supported only\n"
@@ -1629,6 +1676,7 @@ main (int argc, char **argv)
1629 int start_daemon_if_needed; 1676 int start_daemon_if_needed;
1630 int exit_status = EXIT_SUCCESS; 1677 int exit_status = EXIT_SUCCESS;
1631 1678
1679 main_argc = argc;
1632 main_argv = argv; 1680 main_argv = argv;
1633 progname = argv[0]; 1681 progname = argv[0];
1634 1682
diff --git a/test/lib-src/emacsclient-tests.el b/test/lib-src/emacsclient-tests.el
new file mode 100644
index 00000000000..ea757f69144
--- /dev/null
+++ b/test/lib-src/emacsclient-tests.el
@@ -0,0 +1,50 @@
1;;; emacsclient-tests.el --- Test emacsclient
2
3;; Copyright (C) 2016 Free Software Foundation, Inc.
4
5;; This program is free software; you can redistribute it and/or modify
6;; it under the terms of the GNU General Public License as published by
7;; the Free Software Foundation, either version 3 of the License, or
8;; (at your option) any later version.
9
10;; This program is distributed in the hope that it will be useful,
11;; but WITHOUT ANY WARRANTY; without even the implied warranty of
12;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13;; GNU General Public License for more details.
14
15;; You should have received a copy of the GNU General Public License
16;; along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18;;; Commentary:
19
20;;
21
22;;; Code:
23
24(require 'ert)
25
26(defconst emacsclient-test-emacs
27 (expand-file-name "emacsclient" (concat
28 (file-name-directory
29 (directory-file-name
30 (file-name-directory invocation-directory)))
31 "lib-src"))
32 "Path to emacsclient binary in build tree.")
33
34(ert-deftest emacsclient-test-alternate-editor-allows-arguments ()
35 (let (process-environment process-environment)
36 (setenv "ALTERNATE_EDITOR" (concat
37 (expand-file-name invocation-name invocation-directory)
38 " --batch"))
39 (should (= 0 (call-process emacsclient-test-emacs nil nil nil "foo")))))
40
41(ert-deftest emacsclient-test-alternate-editor-allows-quotes ()
42 (let (process-environment process-environment)
43 (setenv "ALTERNATE_EDITOR" (concat
44 "\""
45 (expand-file-name invocation-name invocation-directory)
46 "\"" " --batch"))
47 (should (= 0 (call-process emacsclient-test-emacs nil nil nil "foo")))))
48
49(provide 'emacsclient-tests)
50;;; emacsclient-tests.el ends here