#include "gnuserv.h"
char gnuserv_version[] = "gnuclient version " GNUSERV_VERSION;
#include "getopt.h"
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sysfile.h>
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <signal.h>
#if !defined(SYSV_IPC) && !defined(UNIX_DOMAIN_SOCKETS) && \
!defined(INTERNET_DOMAIN_SOCKETS)
int
main (int argc, char *argv[])
{
fprintf (stderr, "Sorry, the Emacs server is only "
"supported on systems that have\n");
fprintf (stderr, "Unix Domain sockets, Internet Domain "
"sockets or System V IPC.\n");
exit (1);
}
#else
static char cwd[MAXPATHLEN+2];
static char *cp = NULL;
static pid_t emacs_pid;
#ifdef SYSV_IPC
struct msgbuf *msgp;
#endif
void initialize_signals (void);
static void
tell_emacs_to_resume (int sig)
{
char buffer[GSERV_BUFSZ+1];
int s;
int connect_type;
#ifdef SIGCONT
signal(SIGCONT, tell_emacs_to_resume);
#endif
connect_type = make_connection (NULL, (u_short) 0, &s);
sprintf(buffer,"(gnuserv-eval '(resume-pid-console %d))", (int)getpid());
send_string(s, buffer);
#ifdef SYSV_IPC
if (connect_type == (int) CONN_IPC)
disconnect_from_ipc_server (s, msgp, FALSE);
#else
if (connect_type != (int) CONN_IPC)
disconnect_from_server (s, FALSE);
#endif
}
static void
pass_signal_to_emacs (int sig)
{
if (kill (emacs_pid, sig) == -1)
{
fprintf (stderr, "gnuattach: Could not pass signal to emacs process\n");
exit (1);
}
initialize_signals ();
}
void
initialize_signals (void)
{
signal (SIGQUIT, pass_signal_to_emacs);
signal (SIGINT, pass_signal_to_emacs);
#ifdef SIGWINCH
signal (SIGWINCH, pass_signal_to_emacs);
#endif
#ifdef SIGCONT
signal (SIGCONT, tell_emacs_to_resume);
#endif
}
static char *
get_current_working_directory (void)
{
if (cp == NULL)
{
#ifdef BSD
if (getwd (cwd) == 0)
#else
if (getcwd (cwd,MAXPATHLEN) == NULL)
#endif
{
perror (progname);
fprintf (stderr, "%s: unable to get current working directory\n",
progname);
exit (1);
}
for (cp = cwd; *cp && *cp != '/'; ++cp)
;
}
return cp;
}
static void
filename_expand (char *fullpath, char *filename)
{
int len;
fullpath[0] = '\0';
if (filename[0] && filename[0] == '/')
{
strcat (fullpath, filename);
}
#ifdef CYGWIN
else if (filename[0] && filename[0] == '\\' &&
filename[1] && filename[1] == '\\')
{
strcat (fullpath, filename);
}
else if (filename[0] &&
filename[1] && filename[1] == ':' &&
filename[2] && filename[2] == '\\')
{
strcat (fullpath, "//");
strncat (fullpath, filename, 1);
strcat (fullpath, &filename[2]);
}
#endif
else
{
strcat (fullpath, get_current_working_directory ());
len = strlen (fullpath);
if (len > 0 && fullpath[len-1] == '/')
;
else
strcat (fullpath, "/");
strcat (fullpath,filename);
}
}
static char *
clean_string (const char *s)
{
int i = 0;
char *p, *res;
{
const char *const_p;
for (const_p = s; *const_p; const_p++, i++)
{
if (*const_p == '\\' || *const_p == '\"')
++i;
else if (*const_p == '\004')
i += 3;
}
}
p = res = (char *) malloc (i + 2 + 1);
*p++ = '\"';
for (; *s; p++, s++)
{
switch (*s)
{
case '\\':
*p++ = '\\';
*p = '\\';
break;
case '\"':
*p++ = '\\';
*p = '\"';
break;
case '\004':
*p++ = '\\';
*p++ = 'C';
*p++ = '-';
*p = 'd';
break;
default:
*p = *s;
}
}
*p++ = '\"';
*p = '\0';
return res;
}
#define GET_ARGUMENT(var, desc) do { \
if (*(p + 1)) (var) = p + 1; \
else \
{ \
if (!argv[++i]) \
{ \
fprintf (stderr, "%s: `%s' must be followed by an argument\n", \
progname, desc); \
exit (1); \
} \
(var) = argv[i]; \
} \
over = 1; \
} while (0)
static char *
my_strdup (const char *s)
{
char *new_s = (char *) malloc (strlen (s) + 1);
if (new_s)
strcpy (new_s, s);
return new_s;
}
int
main (int argc, char *argv[])
{
int starting_line = 1;
char command[MAXPATHLEN+50];
char fullpath[MAXPATHLEN+1];
char *eval_form = NULL;
char *eval_function = NULL;
char *load_library = NULL;
int quick = 0;
int batch = 0;
int view = 0;
int nofiles = 0;
int errflg = 0;
int s;
int connect_type;
int suppress_windows_system = 0;
char *display = NULL;
char *path;
#ifdef INTERNET_DOMAIN_SOCKETS
char *hostarg = NULL;
char *remotearg;
char thishost[HOSTNAMSZ];
char remotepath[MAXPATHLEN+1];
int rflg = 0;
char *portarg;
u_short port = 0;
#endif
char *tty = NULL;
char buffer[GSERV_BUFSZ + 1];
char result[GSERV_BUFSZ + 1];
int i;
#ifdef INTERNET_DOMAIN_SOCKETS
memset (remotepath, 0, sizeof (remotepath));
#endif
progname = strrchr (argv[0], '/');
if (progname)
++progname;
else
progname = argv[0];
#ifdef USE_TMPDIR
tmpdir = getenv ("TMPDIR");
#endif
if (!tmpdir)
tmpdir = "/tmp";
display = getenv ("DISPLAY");
if (display)
display = my_strdup (display);
#ifndef HAVE_MS_WINDOWS
else
suppress_windows_system = 1;
#endif
for (i = 1; argv[i] && !errflg; i++)
{
if (*argv[i] != '-')
break;
else if (*argv[i] == '-'
&& (*(argv[i] + 1) == '\0'
|| (*(argv[i] + 1) == '-' && *(argv[i] + 2) == '\0')))
{
++i;
break;
}
if (!strcmp (argv[i], "-batch") || !strcmp (argv[i], "--batch"))
batch = 1;
else if (!strcmp (argv[i], "-eval") || !strcmp (argv[i], "--eval"))
{
if (!argv[++i])
{
fprintf (stderr, "%s: `-eval' must be followed by an argument\n",
progname);
exit (1);
}
eval_form = argv[i];
}
else if (!strcmp (argv[i], "-display") || !strcmp (argv[i], "--display"))
{
suppress_windows_system = 0;
if (!argv[++i])
{
fprintf (stderr,
"%s: `-display' must be followed by an argument\n",
progname);
exit (1);
}
if (display)
free (display);
display = argv[i];
}
else if (!strcmp (argv[i], "-nw"))
suppress_windows_system = 1;
else
{
char *p;
int over = 0;
for (p = argv[i] + 1; *p && !over; p++)
{
switch (*p)
{
case 'q':
quick = 1;
break;
case 'v':
view = 1;
break;
case 'f':
GET_ARGUMENT (eval_function, "-f");
break;
case 'l':
GET_ARGUMENT (load_library, "-l");
break;
#ifdef INTERNET_DOMAIN_SOCKETS
case 'h':
GET_ARGUMENT (hostarg, "-h");
break;
case 'p':
GET_ARGUMENT (portarg, "-p");
port = atoi (portarg);
break;
case 'r':
GET_ARGUMENT (remotearg, "-r");
strcpy (remotepath, remotearg);
rflg = 1;
break;
#endif
default:
errflg = 1;
}
}
}
}
if (errflg)
{
fprintf (stderr,
#ifdef INTERNET_DOMAIN_SOCKETS
"Usage: %s [-nw] [-display display] [-q] [-v] [-l library]\n"
" [-batch] [-f function] [-eval form]\n"
" [-h host] [-p port] [-r remote-path] [[+line] file] ...\n",
#else
"Usage: %s [-nw] [-q] [-v] [-l library] [-f function] [-eval form] "
"[[+line] path] ...\n",
#endif
progname);
exit (1);
}
if (batch && argv[i])
{
fprintf (stderr, "%s: Cannot specify `-batch' with file names\n",
progname);
exit (1);
}
#ifdef INTERNET_DOMAIN_SOCKETS
if (suppress_windows_system && hostarg)
{
fprintf (stderr, "%s: Remote editing is available only on X\n",
progname);
exit (1);
}
#endif
*result = '\0';
if (eval_function || eval_form || load_library)
{
#if defined(INTERNET_DOMAIN_SOCKETS)
connect_type = make_connection (hostarg, port, &s);
#else
connect_type = make_connection (NULL, (u_short) 0, &s);
#endif
sprintf (command, "(gnuserv-eval%s '(progn ", quick ? "-quickly" : "");
send_string (s, command);
if (load_library)
{
send_string (s , "(load-library ");
send_string (s, clean_string(load_library));
send_string (s, ") ");
}
if (eval_form)
{
send_string (s, eval_form);
}
if (eval_function)
{
send_string (s, "(");
send_string (s, eval_function);
send_string (s, ")");
}
send_string (s, "))");
#ifdef SYSV_IPC
if (connect_type == (int) CONN_IPC)
disconnect_from_ipc_server (s, msgp, batch && !quick);
#else
if (connect_type != (int) CONN_IPC)
disconnect_from_server (s, batch && !quick);
#endif
}
else if (batch)
{
int nb;
#if defined(INTERNET_DOMAIN_SOCKETS)
connect_type = make_connection (hostarg, port, &s);
#else
connect_type = make_connection (NULL, (u_short) 0, &s);
#endif
sprintf (command, "(gnuserv-eval%s '(progn ", quick ? "-quickly" : "");
send_string (s, command);
while ((nb = read(fileno(stdin), buffer, GSERV_BUFSZ-1)) > 0)
{
buffer[nb] = '\0';
send_string(s, buffer);
}
send_string(s,"))");
#ifdef SYSV_IPC
if (connect_type == (int) CONN_IPC)
disconnect_from_ipc_server (s, msgp, batch && !quick);
#else
if (connect_type != (int) CONN_IPC)
disconnect_from_server (s, batch && !quick);
#endif
}
if (!batch)
{
if (suppress_windows_system)
{
tty = ttyname (0);
if (!tty)
{
fprintf (stderr, "%s: Not connected to a tty", progname);
exit (1);
}
#if defined(INTERNET_DOMAIN_SOCKETS)
connect_type = make_connection (hostarg, port, &s);
#else
connect_type = make_connection (NULL, (u_short) 0, &s);
#endif
send_string (s, "(gnuserv-eval '(emacs-pid))");
send_string (s, EOT_STR);
if (read_line (s, buffer) == 0)
{
fprintf (stderr, "%s: Could not establish Emacs process id\n",
progname);
exit (1);
}
#ifdef SYSV_IPC
if (connect_type == (int) CONN_IPC)
disconnect_from_ipc_server (s, msgp, FALSE);
#endif
emacs_pid = (pid_t)atol(buffer);
initialize_signals();
}
#if defined(INTERNET_DOMAIN_SOCKETS)
connect_type = make_connection (hostarg, port, &s);
#else
connect_type = make_connection (NULL, (u_short) 0, &s);
#endif
#ifdef INTERNET_DOMAIN_SOCKETS
if (connect_type == (int) CONN_INTERNET)
{
char *ptr;
gethostname (thishost, HOSTNAMSZ);
if (!rflg)
{
if ((ptr = getenv ("GNU_NODE")) != NULL)
strcpy (remotepath, ptr);
}
#if 0
#if defined (hp9000s300) || defined (hp9000s800)
else if (strcmp (thishost,hostarg))
{
strcpy (remotepath, "/net/");
strcat (remotepath, thishost);
}
#endif
#endif
}
else
{
remotepath[0] = '\0';
}
#endif
#ifdef SYSV_IPC
if ((msgp = (struct msgbuf *)
malloc (sizeof *msgp + GSERV_BUFSZ)) == NULL)
{
fprintf (stderr, "%s: not enough memory for message buffer\n", progname);
exit (1);
}
msgp->mtext[0] = '\0';
#endif
if (suppress_windows_system)
{
char *term = getenv ("TERM");
if (!term)
{
fprintf (stderr, "%s: unknown terminal type\n", progname);
exit (1);
}
sprintf (command, "(gnuserv-edit-files '(tty %s) '(",
clean_string (term));
}
else
{
if (display)
sprintf (command, "(gnuserv-edit-files '(x %s) '(",
clean_string (display));
#ifdef HAVE_MS_WINDOWS
else
sprintf (command, "(gnuserv-edit-files '(mswindows nil) '(");
#endif
}
send_string (s, command);
if (!argv[i])
nofiles = 1;
for (; argv[i]; i++)
{
if (i < argc - 1 && *argv[i] == '+')
starting_line = atoi (argv[i++]);
else
starting_line = 1;
if (i == argc)
{
starting_line = 1;
--i;
}
filename_expand (fullpath, argv[i]);
#ifdef INTERNET_DOMAIN_SOCKETS
path = (char *) malloc (strlen (remotepath) + strlen (fullpath) + 1);
sprintf (path, "%s%s", remotepath, fullpath);
#else
path = my_strdup (fullpath);
#endif
sprintf (command, "(%d . %s)", starting_line, clean_string (path));
send_string (s, command);
free (path);
}
sprintf (command, ")%s%s",
(quick || (nofiles && !suppress_windows_system)) ? " 'quick" : "",
view ? " 'view" : "");
send_string (s, command);
send_string (s, ")");
#ifdef SYSV_IPC
if (connect_type == (int) CONN_IPC)
disconnect_from_ipc_server (s, msgp, FALSE);
#else
if (connect_type != (int) CONN_IPC)
disconnect_from_server (s, FALSE);
#endif
}
return 0;
}
#endif