X-Git-Url: http://git.hcoop.net/bpt/emacs.git/blobdiff_plain/47854a55680b5809811caf72f66ecbe8289c2855..448d408588e2da398e3f17177b05314e8c7c9a94:/lib-src/emacsclient.c diff --git a/lib-src/emacsclient.c b/lib-src/emacsclient.c index acc322d638..ac41359702 100644 --- a/lib-src/emacsclient.c +++ b/lib-src/emacsclient.c @@ -1,13 +1,13 @@ /* Client process that communicates with GNU Emacs acting as server. Copyright (C) 1986, 1987, 1994, 1999, 2000, 2001, 2002, 2003, 2004, - 2005, 2006, 2007 Free Software Foundation, Inc. + 2005, 2006, 2007, 2008 Free Software Foundation, Inc. This file is part of GNU Emacs. -GNU Emacs is free software; you can redistribute it and/or modify +GNU Emacs is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 3, or (at your option) -any later version. +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. GNU Emacs is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -15,13 +15,9 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with GNU Emacs; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -Boston, MA 02110-1301, USA. */ +along with GNU Emacs. If not, see . */ -#define NO_SHORTNAMES - #ifdef HAVE_CONFIG_H #include #endif @@ -51,6 +47,8 @@ Boston, MA 02110-1301, USA. */ # include # endif +# include + # define INVALID_SOCKET -1 # define HSOCKET int # define CLOSE_SOCKET close @@ -68,15 +66,11 @@ Boston, MA 02110-1301, USA. */ #include #endif -#ifdef VMS -# include "vms-pwd.h" -#else /* not VMS */ #ifdef WINDOWSNT # include #else /* not WINDOWSNT */ # include #endif /* not WINDOWSNT */ -#endif /* not VMS */ #include #include @@ -117,6 +111,10 @@ char *w32_getenv (); #ifndef NO_RETURN #define NO_RETURN #endif + +/* Additional space when allocating buffers for filenames, etc. */ +#define EXTRA_SPACE 100 + /* Name used to invoke this program. */ char *progname; @@ -133,9 +131,6 @@ int eval = 0; /* Nonzero means don't open a new frame. Inverse of --create-frame. */ int current_frame = 1; -/* Nonzero means open a new graphical frame. */ -int window_system = 0; - /* The display on which Emacs should work. --display. */ char *display = NULL; @@ -164,13 +159,16 @@ struct option longopts[] = { "help", no_argument, NULL, 'H' }, { "version", no_argument, NULL, 'V' }, { "tty", no_argument, NULL, 't' }, + { "nw", no_argument, NULL, 't' }, { "create-frame", no_argument, NULL, 'c' }, { "alternate-editor", required_argument, NULL, 'a' }, #ifndef NO_SOCKETS_IN_FILE_SYSTEM { "socket-name", required_argument, NULL, 's' }, #endif { "server-file", required_argument, NULL, 'f' }, +#ifndef WINDOWSNT { "display", required_argument, NULL, 'd' }, +#endif { 0, 0, 0, 0 } }; @@ -227,7 +225,7 @@ xstrdup (const char *s) /* Return the current working directory. Returns NULL on errors. - Any other returned value must be freed with free. This is used + Any other returned value must be freed with free. This is used only when get_current_dir_name is not defined on the system. */ char* get_current_dir_name () @@ -321,8 +319,8 @@ w32_get_resource (predefined, key, type) { result = (char *) xmalloc (cbData); - if ((RegQueryValueEx (hrootkey, key, NULL, type, result, &cbData) != ERROR_SUCCESS) || - (*result == 0)) + if ((RegQueryValueEx (hrootkey, key, NULL, type, result, &cbData) != ERROR_SUCCESS) + || (*result == 0)) { free (result); result = NULL; @@ -354,8 +352,13 @@ w32_getenv (envvar) if (! (value = w32_get_resource (HKEY_CURRENT_USER, envvar, &dwType)) && ! (value = w32_get_resource (HKEY_LOCAL_MACHINE, envvar, &dwType))) - /* Not found in the registry. */ - return NULL; + { + /* "w32console" is what Emacs on Windows uses for tty-type under -nw. */ + if (strcmp (envvar, "TERM") == 0) + return xstrdup ("w32console"); + /* Found neither in the environment nor in the registry. */ + return NULL; + } if (dwType == REG_SZ) /* Registry; no need to expand. */ @@ -436,6 +439,13 @@ w32_execvp (path, argv) #undef execvp #define execvp w32_execvp +/* Emulation of ttyname for Windows. */ +char * +ttyname (int fd) +{ + return "CONOUT$"; +} + #endif /* WINDOWSNT */ /* Display a normal or error message. @@ -477,13 +487,10 @@ decode_options (argc, argv) char **argv; { alternate_editor = egetenv ("ALTERNATE_EDITOR"); - display = egetenv ("DISPLAY"); - if (display && strlen (display) == 0) - display = NULL; while (1) { - int opt = getopt_long (argc, argv, + int opt = getopt_long_only (argc, argv, #ifndef NO_SOCKETS_IN_FILE_SYSTEM "VHnea:s:f:d:tc", #else @@ -515,6 +522,10 @@ decode_options (argc, argv) server_file = optarg; break; + /* We used to disallow this argument in w32, but it seems better + to allow it, for the occasional case where the user is + connecting with a w32 client to a server compiled with X11 + support. */ case 'd': display = optarg; break; @@ -552,26 +563,27 @@ decode_options (argc, argv) } } - if (!tty && display) - window_system = 1; -#if !defined (WINDOWSNT) && !defined (HAVE_CARBON) - else + /* If the -c option is used (without -t) and no --display argument + is provided, try $DISPLAY. + Without the -c option, we used to set `display' to $DISPLAY by + default, but this changed the default behavior and is sometimes + inconvenient. So we force users to use "--display $DISPLAY" if + they want Emacs to connect to their current display. */ + if (!current_frame && !tty && !display) + display = egetenv ("DISPLAY"); + + /* A null-string display is invalid. */ + if (display && strlen (display) == 0) + display = NULL; + + /* If no display is available, new frames are tty frames. */ + if (!current_frame && !display) tty = 1; -#endif /* --no-wait implies --current-frame on ttys when there are file - arguments or expressions given. */ + arguments or expressions given. */ if (nowait && tty && argc - optind > 0) current_frame = 1; - - if (current_frame) - { - tty = 0; - window_system = 0; - } - - if (tty) - window_system = 0; } @@ -590,7 +602,7 @@ Every FILE can be either just a FILENAME or [+LINE[:COLUMN]] FILENAME.\n\ The following OPTIONS are accepted:\n\ -V, --version Just print version info and return\n\ -H, --help Print this usage information message\n\ --t, --tty Open a new Emacs frame on the current terminal\n\ +-nw, -t, --tty Open a new Emacs frame on the current terminal\n\ -c, --create-frame Create a new frame instead of trying to\n\ use the current Emacs frame\n\ -e, --eval Evaluate the FILE arguments as ELisp expressions\n\ @@ -829,38 +841,6 @@ file_name_absolute_p (filename) /* Both \xxx and \\xxx\yyy are absolute. */ if (filename[0] == '\\') return TRUE; - - /* - FIXME: There's a corner case not dealt with, "x:y", where: - - 1) x is a valid drive designation (usually a letter in the A-Z range) - and y is a path, relative to the current directory on drive x. This - is absolute, *after* fixing the y part to include the current - directory in x. - - 2) x is a relative file name, and y is an NTFS stream name. This is a - correct relative path, but it is very unusual. - - The trouble is that first case items are also valid examples of the - second case, i.e., "c:test" can be understood as drive:path or as - file:stream. - - The "right" fix would involve checking whether - - the current drive/partition is NTFS, - - x is a valid (and accesible) drive designator, - - x:y already exists as a file:stream in the current directory, - - y already exists on the current directory of drive x, - - the auspices are favorable, - and then taking an "informed decision" based on the above. - - Whatever the result, Emacs currently does a very bad job of dealing - with NTFS file:streams: it cannot visit them, and the only way to - create one is by setting `buffer-file-name' to point to it (either - manually or with emacsclient). So perhaps resorting to 1) and ignoring - 2) for now is the right thing to do. - - Anyway, something to decide After the Release. - */ #endif return FALSE; @@ -882,7 +862,7 @@ initialize_sockets () if (WSAStartup (MAKEWORD (2, 0), &wsaData)) { - message (TRUE, "%s: error initializing WinSock2", progname); + message (TRUE, "%s: error initializing WinSock2\n", progname); exit (EXIT_FAILURE); } @@ -913,14 +893,16 @@ get_server_config (server, authentication) if (home) { - char *path = alloca (32 + strlen (home) + strlen (server_file)); + char *path = alloca (strlen (home) + strlen (server_file) + + EXTRA_SPACE); sprintf (path, "%s/.emacs.d/server/%s", home, server_file); config = fopen (path, "rb"); } #ifdef WINDOWSNT if (!config && (home = egetenv ("APPDATA"))) { - char *path = alloca (32 + strlen (home) + strlen (server_file)); + char *path = alloca (strlen (home) + strlen (server_file) + + EXTRA_SPACE); sprintf (path, "%s/.emacs.d/server/%s", home, server_file); config = fopen (path, "rb"); } @@ -939,7 +921,7 @@ get_server_config (server, authentication) } else { - message (TRUE, "%s: invalid configuration info", progname); + message (TRUE, "%s: invalid configuration info\n", progname); exit (EXIT_FAILURE); } @@ -949,7 +931,7 @@ get_server_config (server, authentication) if (! fread (authentication, AUTH_KEY_LENGTH, 1, config)) { - message (TRUE, "%s: cannot read authentication info", progname); + message (TRUE, "%s: cannot read authentication info\n", progname); exit (EXIT_FAILURE); } @@ -1002,7 +984,7 @@ set_tcp_socket () send_to_emacs (s, "-auth "); send_to_emacs (s, auth_string); - send_to_emacs (s, "\n"); + send_to_emacs (s, " "); return s; } @@ -1015,6 +997,57 @@ strprefix (char *prefix, char *string) return !strncmp (prefix, string, strlen (prefix)); } +/* Get tty name and type. If successful, return the type in TTY_TYPE + and the name in TTY_NAME, and return 1. Otherwise, fail if NOABORT + is zero, or return 0 if NOABORT is non-zero. */ + +int +find_tty (char **tty_type, char **tty_name, int noabort) +{ + char *type = egetenv ("TERM"); + char *name = ttyname (fileno (stdout)); + + if (!name) + { + if (noabort) + return 0; + else + { + message (TRUE, "%s: could not get terminal name\n", progname); + fail (); + } + } + + if (!type) + { + if (noabort) + return 0; + else + { + message (TRUE, "%s: please set the TERM variable to your terminal type\n", + progname); + fail (); + } + } + + if (strcmp (type, "eterm") == 0) + { + if (noabort) + return 0; + else + { + /* This causes nasty, MULTI_KBOARD-related input lockouts. */ + message (TRUE, "%s: opening a frame in an Emacs term buffer" + " is not supported\n", progname); + fail (); + } + } + + *tty_name = name; + *tty_type = type; + return 1; +} + #if !defined (NO_SOCKETS_IN_FILE_SYSTEM) @@ -1092,7 +1125,7 @@ handle_sigtstp (int signalnum) if (emacs_socket) send_to_emacs (emacs_socket, "-suspend \n"); - /* Unblock this signal and call the default handler by temprarily + /* Unblock this signal and call the default handler by temporarily changing the handler and resignalling. */ sigprocmask (SIG_BLOCK, NULL, &set); sigdelset (&set, signalnum); @@ -1103,6 +1136,8 @@ handle_sigtstp (int signalnum) errno = old_errno; } + + /* Set up signal handlers before opening a frame on the current tty. */ void @@ -1148,6 +1183,7 @@ set_local_socket () int default_sock = !socket_name; int saved_errno = 0; char *server_name = "server"; + char *tmpdir; if (socket_name && !index (socket_name, '/') && !index (socket_name, '\\')) { /* socket_name is a file name component. */ @@ -1158,16 +1194,20 @@ set_local_socket () if (default_sock) { - socket_name = alloca (100 + strlen (server_name)); - sprintf (socket_name, "/tmp/emacs%d/%s", - (int) geteuid (), server_name); + tmpdir = egetenv ("TMPDIR"); + if (!tmpdir) + tmpdir = "/tmp"; + socket_name = alloca (strlen (tmpdir) + strlen (server_name) + + EXTRA_SPACE); + sprintf (socket_name, "%s/emacs%d/%s", + tmpdir, (int) geteuid (), server_name); } if (strlen (socket_name) < sizeof (server.sun_path)) strcpy (server.sun_path, socket_name); else { - message (TRUE, "%s: socket-name %s too long", + message (TRUE, "%s: socket-name %s too long\n", progname, socket_name); fail (); } @@ -1194,15 +1234,16 @@ set_local_socket () if (pw && (pw->pw_uid != geteuid ())) { /* We're running under su, apparently. */ - socket_name = alloca (100 + strlen (server_name)); - sprintf (socket_name, "/tmp/emacs%d/%s", - (int) pw->pw_uid, server_name); + socket_name = alloca (strlen (tmpdir) + strlen (server_name) + + EXTRA_SPACE); + sprintf (socket_name, "%s/emacs%d/%s", + tmpdir, (int) pw->pw_uid, server_name); if (strlen (socket_name) < sizeof (server.sun_path)) strcpy (server.sun_path, socket_name); else { - message (TRUE, "%s: socket-name %s too long", + message (TRUE, "%s: socket-name %s too long\n", progname, socket_name); exit (EXIT_FAILURE); } @@ -1266,7 +1307,7 @@ set_socket () s = set_local_socket (); if ((s != INVALID_SOCKET) || alternate_editor) return s; - message (TRUE, "%s: error accessing socket \"%s\"", + message (TRUE, "%s: error accessing socket \"%s\"\n", progname, socket_name); exit (EXIT_FAILURE); } @@ -1282,7 +1323,7 @@ set_socket () if ((s != INVALID_SOCKET) || alternate_editor) return s; - message (TRUE, "%s: error accessing server file \"%s\"", + message (TRUE, "%s: error accessing server file \"%s\"\n", progname, server_file); exit (EXIT_FAILURE); } @@ -1382,7 +1423,7 @@ main (argc, argv) /* Process options. */ decode_options (argc, argv); - if ((argc - optind < 1) && !eval && !tty && !window_system) + if ((argc - optind < 1) && !eval && current_frame) { message (TRUE, "%s: file name or argument required\n" "Try `%s --help' for more information\n", @@ -1407,7 +1448,7 @@ main (argc, argv) w32_give_focus (); #endif - /* Send over our environment. */ + /* Send over our environment and current directory. */ if (!current_frame) { extern char **environ; @@ -1420,11 +1461,6 @@ main (argc, argv) quote_argument (emacs_socket, environ[i]); send_to_emacs (emacs_socket, " "); } - } - - /* Send over our current directory. */ - if (!current_frame) - { send_to_emacs (emacs_socket, "-dir "); quote_argument (emacs_socket, cwd); send_to_emacs (emacs_socket, "/"); @@ -1445,46 +1481,27 @@ main (argc, argv) send_to_emacs (emacs_socket, " "); } - if (tty) + /* If using the current frame, send tty information to Emacs anyway. + In daemon mode, Emacs may need to occupy this tty if no other + frame is available. */ + if (tty || (current_frame && !eval)) { - char *type = egetenv ("TERM"); - char *tty_name = NULL; -#ifndef WINDOWSNT - tty_name = ttyname (fileno (stdin)); -#endif - - if (! tty_name) - { - message (TRUE, "%s: could not get terminal name\n", progname); - fail (); - } - - if (! type) - { - message (TRUE, "%s: please set the TERM variable to your terminal type\n", - progname); - fail (); - } + char *tty_type, *tty_name; - if (! strcmp (type, "eterm")) - { - /* This causes nasty, MULTI_KBOARD-related input lockouts. */ - message (TRUE, "%s: opening a frame in an Emacs term buffer" - " is not supported\n", progname); - fail (); - } + if (find_tty (&tty_type, &tty_name, !tty)) + { #if !defined (NO_SOCKETS_IN_FILE_SYSTEM) - init_signals (); + init_signals (); #endif - - send_to_emacs (emacs_socket, "-tty "); - quote_argument (emacs_socket, tty_name); - send_to_emacs (emacs_socket, " "); - quote_argument (emacs_socket, type); - send_to_emacs (emacs_socket, " "); + send_to_emacs (emacs_socket, "-tty "); + quote_argument (emacs_socket, tty_name); + send_to_emacs (emacs_socket, " "); + quote_argument (emacs_socket, tty_type); + send_to_emacs (emacs_socket, " "); + } } - if (window_system) + if (!current_frame && !tty) send_to_emacs (emacs_socket, "-window-system "); if ((argc - optind > 0)) @@ -1516,8 +1533,30 @@ main (argc, argv) else relative = 1; } - else if (! file_name_absolute_p (argv[i])) - relative = 1; + else if (! file_name_absolute_p (argv[i])) +#ifndef WINDOWSNT + relative = 1; +#else + /* Call GetFullPathName so filenames of the form X:Y, where X is + a valid drive designator, are interpreted as drive:path, not + file:stream, and treated as absolute. + The user can still pass a file:stream if desired (for example, + .\X:Y), but it is not very useful, as Emacs currently does a + very bad job of dealing with NTFS streams. */ + { + char *filename = (char *) xmalloc (MAX_PATH); + DWORD size; + + size = GetFullPathName (argv[i], MAX_PATH, filename, NULL); + if (size > 0 && size < MAX_PATH) + argv[i] = filename; + else + { + relative = 1; + free (filename); + } + } +#endif send_to_emacs (emacs_socket, "-file "); if (relative) @@ -1529,20 +1568,15 @@ main (argc, argv) send_to_emacs (emacs_socket, " "); } } - else + else if (eval) { - if (!tty && !window_system) - { - while ((str = fgets (string, BUFSIZ, stdin))) - { - if (eval) - send_to_emacs (emacs_socket, "-eval "); - else - send_to_emacs (emacs_socket, "-file "); - quote_argument (emacs_socket, str); - } - send_to_emacs (emacs_socket, " "); - } + /* Read expressions interactively. */ + while ((str = fgets (string, BUFSIZ, stdin))) + { + send_to_emacs (emacs_socket, "-eval "); + quote_argument (emacs_socket, str); + } + send_to_emacs (emacs_socket, " "); } send_to_emacs (emacs_socket, "\n"); @@ -1575,7 +1609,6 @@ main (argc, argv) { /* -window-system-unsupported: Emacs was compiled without X support. Try again on the terminal. */ - window_system = 0; nowait = 0; tty = 1; goto retry;