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
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 <http://www.gnu.org/licenses/>. */
#ifdef HAVE_CONFIG_H
#else /* !WINDOWSNT */
-# include <sys/types.h>
+# include "syswait.h"
# ifdef HAVE_INET_SOCKETS
# include <netinet/in.h>
# endif
+# include <arpa/inet.h>
+
# define INVALID_SOCKET -1
# define HSOCKET int
# define CLOSE_SOCKET close
# define INITIALIZE()
+# ifndef WCONTINUED
+# define WCONTINUED 8
+# endif
+
#endif /* !WINDOWSNT */
#undef signal
#include <unistd.h>
#endif
-#ifdef VMS
-# include "vms-pwd.h"
-#else /* not VMS */
#ifdef WINDOWSNT
# include <io.h>
#else /* not WINDOWSNT */
# include <pwd.h>
#endif /* not WINDOWSNT */
-#endif /* not VMS */
#include <sys/stat.h>
#include <signal.h>
#ifndef NO_RETURN
#define NO_RETURN
#endif
+
+/* Additional space when allocating buffers for filenames, etc. */
+#define EXTRA_SPACE 100
+
\f
/* Name used to invoke this program. */
char *progname;
/* 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;
{ "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
{
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;
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. */
#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.
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
to allow it, for the occasional case where the user is
connecting with a w32 client to a server compiled with X11
support. */
-#if 1 /* !defined WINDOWS */
case 'd':
display = optarg;
break;
-#endif
case 'n':
nowait = 1;
}
}
- /* We used to set `display' to $DISPLAY by default, but this changed the
- default behavior and is sometimes inconvenient. So instead of forcing
- users to say "--display ''" when they want to use Emacs's existing tty
- or display connection, we force them to use "--display $DISPLAY" if
- they want Emacs to connect to their current display.
- -c still implicitly passes --display $DISPLAY unless -t was specified
- so as to try and mimick the behavior of `emacs' which either uses
- the current tty or the current $DISPLAY. */
+ /* 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 (!tty && display)
- window_system = 1;
-#if !defined (WINDOWSNT) && !defined (HAVE_CARBON)
- else if (!current_frame)
+ /* 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)
+#ifdef WINDOWSNT
+ if (alternate_editor && alternate_editor[0] == '\0')
{
- tty = 0;
- window_system = 0;
+ message (TRUE, "--alternate-editor argument or ALTERNATE_EDITOR variable cannot be\n\
+an empty string");
+ exit (EXIT_FAILURE);
}
-
- if (tty)
- window_system = 0;
+#endif /* WINDOWSNT */
}
\f
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\
"-f, --server-file=FILENAME\n\
Set filename of the TCP authentication file\n\
-a, --alternate-editor=EDITOR\n\
- Editor to fallback to if the server is not running\n\
-\n\
+ Editor to fallback to if the server is not running\n"
+#ifdef WINDOWSNT
+" If EDITOR is the empty string, start Emacs in daemon\n\
+ mode and try connecting again\n"
+#endif /* WINDOWSNT */
+"\n\
Report bugs to bug-gnu-emacs@gnu.org.\n", progname);
exit (EXIT_SUCCESS);
}
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");
}
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)
errno = old_errno;
}
+
+
/* Set up signal handlers before opening a frame on the current tty. */
void
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. */
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))
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);
#endif /* ! NO_SOCKETS_IN_FILE_SYSTEM */
HSOCKET
-set_socket ()
+set_socket (int no_exit_if_error)
{
HSOCKET s;
if (socket_name)
{
s = set_local_socket ();
- if ((s != INVALID_SOCKET) || alternate_editor)
+ if ((s != INVALID_SOCKET) || no_exit_if_error)
return s;
message (TRUE, "%s: error accessing socket \"%s\"\n",
progname, socket_name);
if (server_file)
{
s = set_tcp_socket ();
- if ((s != INVALID_SOCKET) || alternate_editor)
+ if ((s != INVALID_SOCKET) || no_exit_if_error)
return s;
message (TRUE, "%s: error accessing server file \"%s\"\n",
/* Implicit server file. */
server_file = "server";
s = set_tcp_socket ();
- if ((s != INVALID_SOCKET) || alternate_editor)
+ if ((s != INVALID_SOCKET) || no_exit_if_error)
return s;
/* No implicit or explicit socket, and no alternate editor. */
}
#endif
+/* Start the emacs daemon and try to connect to it. */
+
+void
+start_daemon_and_retry_set_socket (void)
+{
+#ifndef WINDOWSNT
+ pid_t dpid;
+ int status;
+ pid_t p;
+
+ dpid = fork ();
+
+ if (dpid > 0)
+ {
+ p = waitpid (dpid, &status, WUNTRACED | WCONTINUED);
+
+ /* Try connecting again, the daemon should have started by
+ now. */
+ message (TRUE, "daemon should have started, trying to connect again\n", dpid);
+ if ((emacs_socket = set_socket (1)) == INVALID_SOCKET)
+ message (TRUE, "Cannot connect even after starting the daemon\n");
+ }
+ else if (dpid < 0)
+ {
+ fprintf (stderr, "Cannot fork!\n");
+ exit (1);
+ }
+ else
+ {
+ char *d_argv[] = {"emacs", "--daemon", 0 };
+ if (socket_name != NULL)
+ {
+ /* Pass --daemon=socket_name as argument. */
+ char *deq = "--daemon=";
+ char *daemon_arg = alloca (strlen (deq)
+ + strlen (socket_name) + 1);
+ strcpy (daemon_arg, deq);
+ strcat (daemon_arg, socket_name);
+ d_argv[1] = daemon_arg;
+ }
+ execvp ("emacs", d_argv);
+ message (TRUE, "%s: error starting emacs daemon\n", progname);
+ }
+#endif /* WINDOWSNT */
+}
+
int
main (argc, argv)
int argc;
int i, rl, needlf = 0;
char *cwd, *str;
char string[BUFSIZ+1];
+ int null_socket_name, null_server_file, start_daemon_if_needed;
main_argv = argv;
progname = argv[0];
/* 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",
exit (EXIT_FAILURE);
}
- if ((emacs_socket = set_socket ()) == INVALID_SOCKET)
- fail ();
+ /* If alternate_editor is the empty string, start the emacs daemon
+ in case of failure to connect. */
+ start_daemon_if_needed = (alternate_editor
+ && (alternate_editor[0] == '\0'));
+ if (start_daemon_if_needed)
+ {
+ /* set_socket changes the values for socket_name and
+ server_file, we need to reset them, if they were NULL before
+ for the second call to set_socket. */
+ null_socket_name = (socket_name == NULL);
+ null_server_file = (server_file == NULL);
+ }
+ if ((emacs_socket = set_socket (alternate_editor
+ || start_daemon_if_needed)) == INVALID_SOCKET)
+ if (start_daemon_if_needed)
+ {
+ /* Reset socket_name and server_file if they were NULL
+ before the set_socket call. */
+ if (null_socket_name)
+ socket_name = NULL;
+ if (null_server_file)
+ server_file = NULL;
+
+ start_daemon_and_retry_set_socket ();
+ }
+ else
+ fail ();
cwd = get_current_dir_name ();
if (cwd == 0)
w32_give_focus ();
#endif
- /* Send over our environment. */
+ /* Send over our environment and current directory. */
if (!current_frame)
{
extern char **environ;
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, "/");
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
+ char *tty_type, *tty_name;
- 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 ();
- }
-
- 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))
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 wih NTFS streams. */
+ very bad job of dealing with NTFS streams. */
{
char *filename = (char *) xmalloc (MAX_PATH);
DWORD size;
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");
{
/* -window-system-unsupported: Emacs was compiled without X
support. Try again on the terminal. */
- window_system = 0;
nowait = 0;
tty = 1;
goto retry;