/* Client process that communicates with GNU Emacs acting as server.
- Copyright (C) 1986, 1987, 1994, 1999, 2000, 2001, 2003
+ Copyright (C) 1986, 1987, 1994, 1999, 2000, 2001, 2003, 2004
Free Software Foundation, Inc.
This file is part of GNU Emacs.
# include <pwd.h>
#endif /* not VMS */
+#include <signal.h>
+#include <errno.h>
+
+\f
char *getenv (), *getwd ();
char *getcwd ();
/* Name used to invoke this program. */
char *progname;
+/* The first argument to main. */
+int main_argc;
+
+/* The second argument to main. */
+char **main_argv;
+
/* Nonzero means don't wait for a response from Emacs. --no-wait. */
int nowait = 0;
/* The display on which Emacs should work. --display. */
char *display = NULL;
+/* Nonzero means open a new Emacs frame on the current terminal. */
+int frame = 0;
+
/* If non-NULL, the name of an editor to fallback to if the server
is not running. --alternate-editor. */
const char * alternate_editor = NULL;
+/* If non-NULL, the filename of the UNIX socket. */
+char *socket_name = NULL;
+
void print_help_and_exit ();
struct option longopts[] =
{ "eval", no_argument, NULL, 'e' },
{ "help", no_argument, NULL, 'H' },
{ "version", no_argument, NULL, 'V' },
+ { "tty", no_argument, NULL, 't' },
{ "alternate-editor", required_argument, NULL, 'a' },
+ { "socket-name", required_argument, NULL, 's' },
{ "display", required_argument, NULL, 'd' },
{ 0, 0, 0, 0 }
};
while (1)
{
int opt = getopt_long (argc, argv,
- "VHnea:d:", longopts, 0);
+ "VHnea:s:d:t", longopts, 0);
if (opt == EOF)
break;
alternate_editor = optarg;
break;
+ case 's':
+ socket_name = optarg;
+ break;
+
case 'd':
display = optarg;
break;
exit (0);
break;
+ case 't':
+ frame = 1;
+ break;
+
case 'H':
print_help_and_exit ();
break;
break;
}
}
+
+ if (frame) {
+ nowait = 0;
+ display = 0;
+ }
+
}
void
The following OPTIONS are accepted:\n\
-V, --version Just print a 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\
-n, --no-wait Don't wait for the server to return\n\
-e, --eval Evaluate the FILE arguments as ELisp expressions\n\
-d, --display=DISPLAY Visit the file in the given display\n\
+-s, --socket-name=FILENAME\n\
+ Set the filename of the UNIX socket for communication\n\
-a, --alternate-editor=EDITOR\n\
Editor to fallback to if the server is not running\n\
\n\
exit (0);
}
-/* Return a copy of NAME, inserting a &
- before each &, each space, each newline, and any initial -.
- Change spaces to underscores, too, so that the
+/* In NAME, insert a & before each &, each space, each newline, and
+ any initial -. Change spaces to underscores, too, so that the
return value never contains a space. */
-char *
-quote_file_name (name)
+void
+quote_file_name (name, stream)
char *name;
+ FILE *stream;
{
char *copy = (char *) malloc (strlen (name) * 2 + 1);
char *p, *q;
}
*q++ = 0;
- return copy;
+ fprintf (stream, copy);
+
+ free (copy);
}
/* Like malloc but get fatal error if memory is exhausted. */
defined-- exit with an errorcode.
*/
void
-fail (argc, argv)
- int argc;
- char **argv;
+fail (void)
{
if (alternate_editor)
{
int i = optind - 1;
- execvp (alternate_editor, argv + i);
+ execvp (alternate_editor, main_argv + i);
return;
}
else
}
}
+int emacs_pid;
+
+#ifdef nec_ews_svr4
+extern char *_sobuf ;
+#else
+#if defined (USG) || defined (DGUX)
+unsigned char _sobuf[BUFSIZ+8];
+#else
+char _sobuf[BUFSIZ];
+#endif
+#endif
+
+/* A signal handler that passes the signal to the Emacs process.
+ Useful for SIGWINCH. */
+
+SIGTYPE
+pass_signal_to_emacs (int signalnum)
+{
+ int old_errno = errno;
+
+ if (emacs_pid)
+ kill (emacs_pid, signalnum);
+
+ signal (signalnum, pass_signal_to_emacs);
+ errno = old_errno;
+}
+
+/* Set up signal handlers before opening a frame on the current tty. */
+
+void
+init_signals (void)
+{
+ /* Set up signal handlers. */
+ signal (SIGWINCH, pass_signal_to_emacs);
+
+ /* Don't pass SIGINT and SIGQUIT to Emacs, because it has no way of
+ deciding which terminal the signal came from. C-g is now a
+ normal input event on secondary terminals. */
+#if 0
+ signal (SIGINT, pass_signal_to_emacs);
+ signal (SIGQUIT, pass_signal_to_emacs);
+#endif
+}
\f
#if !defined (HAVE_SOCKETS) || defined (NO_SOCKETS_IN_FILE_SYSTEM)
argv[0]);
fprintf (stderr, "on systems with Berkeley sockets.\n");
- fail (argc, argv);
+ fail ();
}
#else /* HAVE_SOCKETS */
return 0;
}
+/* Returns 1 if PREFIX is a prefix of STRING. */
+static int
+strprefix (char *prefix, char *string)
+{
+ int i;
+ if (! prefix)
+ return 1;
+
+ if (!string)
+ return 0;
+
+ for (i = 0; prefix[i]; i++)
+ if (!string[i] || string[i] != prefix[i])
+ return 0;
+ return 1;
+}
+
int
main (argc, argv)
int argc;
char *cwd, *str;
char string[BUFSIZ];
+ main_argc = argc;
+ main_argv = argv;
progname = argv[0];
/* Process options. */
decode_options (argc, argv);
- if (argc - optind < 1)
+ if ((argc - optind < 1) && !eval && !frame)
{
fprintf (stderr, "%s: file name or argument required\n", progname);
fprintf (stderr, "Try `%s --help' for more information\n", progname);
{
fprintf (stderr, "%s: ", argv[0]);
perror ("socket");
- fail (argc, argv);
+ fail ();
}
server.sun_family = AF_UNIX;
{
int sock_status = 0;
+ int default_sock = !socket_name;
+ int saved_errno = 0;
+
+ if (default_sock)
+ {
+ socket_name = alloca (system_name_length + 100);
+ sprintf (socket_name, "/tmp/emacs%d-%s/server",
+ (int) geteuid (), system_name);
+ }
- sprintf (server.sun_path, "/tmp/esrv%d-%s", (int) geteuid (), system_name);
+ if (strlen (socket_name) < sizeof (server.sun_path))
+ strcpy (server.sun_path, socket_name);
+ else
+ {
+ fprintf (stderr, "%s: socket-name %s too long",
+ argv[0], socket_name);
+ fail ();
+ }
/* See if the socket exists, and if it's owned by us. */
sock_status = socket_status (server.sun_path);
- if (sock_status)
+ saved_errno = errno;
+ if (sock_status && default_sock)
{
/* Failing that, see if LOGNAME or USER exist and differ from
our euid. If so, look for a socket based on the UID
if (pw && (pw->pw_uid != geteuid ()))
{
/* We're running under su, apparently. */
- sprintf (server.sun_path, "/tmp/esrv%d-%s",
+ sprintf (socket_name, "/tmp/emacs%d-%s/server",
(int) pw->pw_uid, system_name);
+
+ if (strlen (socket_name) < sizeof (server.sun_path))
+ strcpy (server.sun_path, socket_name);
+ else
+ {
+ fprintf (stderr, "%s: socket-name %s too long",
+ argv[0], socket_name);
+ exit (1);
+ }
+
sock_status = socket_status (server.sun_path);
+ saved_errno = errno;
}
}
}
if (0 != geteuid ())
{
fprintf (stderr, "%s: Invalid socket owner\n", argv[0]);
- fail (argc, argv);
+ fail ();
}
break;
case 2:
/* `stat' failed */
- if (errno == ENOENT)
+ if (saved_errno == ENOENT)
fprintf (stderr,
- "%s: can't find socket; have you started the server?\n\
+ "%s: Can't find socket; have you started the server?\n\
To start the server in Emacs, type \"M-x server-start\".\n",
argv[0]);
else
- fprintf (stderr, "%s: can't stat %s: %s\n",
- argv[0], server.sun_path, strerror (errno));
- fail (argc, argv);
+ fprintf (stderr, "%s: Can't stat %s: %s\n",
+ argv[0], server.sun_path, strerror (saved_errno));
+ fail ();
break;
}
}
{
fprintf (stderr, "%s: ", argv[0]);
perror ("connect");
- fail (argc, argv);
+ fail ();
}
/* We use the stream OUT to send our command to the server. */
{
fprintf (stderr, "%s: ", argv[0]);
perror ("fdopen");
- fail (argc, argv);
+ fail ();
}
/* We use the stream IN to read the response.
{
fprintf (stderr, "%s: ", argv[0]);
perror ("fdopen");
- fail (argc, argv);
+ fail ();
}
#ifdef HAVE_GETCWD
if (cwd == 0)
{
/* getwd puts message in STRING if it fails. */
- fprintf (stderr, "%s: %s (%s)\n", argv[0],
+
#ifdef HAVE_GETCWD
- "Cannot get current working directory",
+ fprintf (stderr, "%s: %s (%s)\n", argv[0],
+ "Cannot get current working directory", strerror (errno));
#else
- string,
+ fprintf (stderr, "%s: %s (%s)\n", argv[0], string, strerror (errno));
#endif
- strerror (errno));
- fail (argc, argv);
+ fail ();
}
if (nowait)
fprintf (out, "-eval ");
if (display)
- fprintf (out, "-display %s ", quote_file_name (display));
+ {
+ fprintf (out, "-display ");
+ quote_file_name (display, out);
+ fprintf (out, " ");
+ }
- for (i = optind; i < argc; i++)
+ if (frame)
{
- if (eval)
- ; /* Don't prepend any cwd or anything like that. */
- else if (*argv[i] == '+')
+ char *tty_name = ttyname (fileno (stdin));
+ if (! tty_name)
+ fail ();
+
+ init_signals ();
+
+ fprintf (out, "-tty ");
+ quote_file_name (tty_name, out);
+ fprintf (out, " ");
+ quote_file_name (getenv("TERM"), out);
+ fprintf (out, " ");
+ }
+
+ if ((argc - optind > 0))
+ {
+ for (i = optind; i < argc; i++)
{
- char *p = argv[i] + 1;
- while (isdigit ((unsigned char) *p) || *p == ':') p++;
- if (*p != 0)
- fprintf (out, "%s/", quote_file_name (cwd));
+ if (eval)
+ ; /* Don't prepend any cwd or anything like that. */
+ else if (*argv[i] == '+')
+ {
+ char *p = argv[i] + 1;
+ while (isdigit ((unsigned char) *p) || *p == ':') p++;
+ if (*p != 0)
+ {
+ quote_file_name (cwd, out);
+ fprintf (out, "/");
+ }
+ }
+ else if (*argv[i] != '/')
+ {
+ quote_file_name (cwd, out);
+ fprintf (out, "/");
+ }
+
+ quote_file_name (argv[i], out);
+ fprintf (out, " ");
}
- else if (*argv[i] != '/')
- fprintf (out, "%s/", quote_file_name (cwd));
-
- fprintf (out, "%s ", quote_file_name (argv[i]));
}
+ else
+ {
+ if (!frame)
+ {
+ while ((str = fgets (string, BUFSIZ, stdin)))
+ {
+ quote_file_name (str, out);
+ }
+ fprintf (out, " ");
+ }
+ }
+
fprintf (out, "\n");
fflush (out);
/* Maybe wait for an answer. */
if (nowait)
- return 0;
+ {
+ return 0;
+ }
- if (!eval)
+ if (!eval && !frame)
{
printf ("Waiting for Emacs...");
needlf = 2;
/* Now, wait for an answer and print any messages. */
while ((str = fgets (string, BUFSIZ, in)))
{
- if (needlf == 2)
- printf ("\n");
- printf ("%s", str);
- needlf = str[0] == '\0' ? needlf : str[strlen (str) - 1] != '\n';
+ if (frame)
+ {
+ if (strprefix ("emacs-pid ", str))
+ {
+ emacs_pid = strtol (string + strlen ("emacs-pid"), NULL, 10);
+ }
+ }
+ else
+ {
+ if (needlf == 2)
+ printf ("\n");
+ printf ("%s", str);
+ needlf = str[0] == '\0' ? needlf : str[strlen (str) - 1] != '\n';
+ }
}
if (needlf)
}
#endif /* ! HAVE_STRERROR */
+
+/* arch-tag: f39bb9c4-73eb-477e-896d-50832e2ca9a7
+ (do not change this comment) */