/* 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
it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
+the Free Software Foundation; either version 3, or (at your option)
any later version.
GNU Emacs is distributed in the hope that it will be useful,
# include <malloc.h>
# include <stdlib.h>
# include <windows.h>
+# include <commctrl.h>
# define NO_SOCKETS_IN_FILE_SYSTEM
#include <signal.h>
#include <errno.h>
-/* From lisp.h */
-#ifndef DIRECTORY_SEP
-#define DIRECTORY_SEP '/'
-#endif
-#ifndef IS_DIRECTORY_SEP
-#define IS_DIRECTORY_SEP(_c_) ((_c_) == DIRECTORY_SEP)
-#endif
-#ifndef IS_DEVICE_SEP
-#ifndef DEVICE_SEP
-#define IS_DEVICE_SEP(_c_) 0
-#else
-#define IS_DEVICE_SEP(_c_) ((_c_) == DEVICE_SEP)
-#endif
-#endif
-#ifndef IS_ANY_SEP
-#define IS_ANY_SEP(_c_) (IS_DIRECTORY_SEP (_c_))
-#endif
-
-
\f
char *getenv (), *getwd ();
char *(getcwd) ();
+#ifdef WINDOWSNT
+char *w32_getenv ();
+#define egetenv(VAR) w32_getenv(VAR)
+#else
+#define egetenv(VAR) getenv(VAR)
+#endif
+
#ifndef VERSION
#define VERSION "unspecified"
#endif
/* 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 args are expressions to be evaluated. --eval. */
int eval = 0;
-/* Nonzero means don't open a new frame. --current-frame. */
-int current_frame = 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;
{ "help", no_argument, NULL, 'H' },
{ "version", no_argument, NULL, 'V' },
{ "tty", no_argument, NULL, 't' },
- { "current-frame", no_argument, NULL, 'c' },
+ { "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 }
};
/* From sysdep.c */
#if !defined (HAVE_GET_CURRENT_DIR_NAME) || defined (BROKEN_GET_CURRENT_DIR_NAME)
+/* From lisp.h */
+#ifndef DIRECTORY_SEP
+#define DIRECTORY_SEP '/'
+#endif
+#ifndef IS_DIRECTORY_SEP
+#define IS_DIRECTORY_SEP(_c_) ((_c_) == DIRECTORY_SEP)
+#endif
+#ifndef IS_DEVICE_SEP
+#ifndef DEVICE_SEP
+#define IS_DEVICE_SEP(_c_) 0
+#else
+#define IS_DEVICE_SEP(_c_) ((_c_) == DEVICE_SEP)
+#endif
+#endif
+#ifndef IS_ANY_SEP
+#define IS_ANY_SEP(_c_) (IS_DIRECTORY_SEP (_c_))
+#endif
+
+
/* Return the current working directory. Returns NULL on errors.
Any other returned value must be freed with free. This is used
only when get_current_dir_name is not defined on the system. */
/* If PWD is accurate, use it instead of calling getwd. PWD is
sometimes a nicer name, and using it may avoid a fatal error if a
parent directory is searchable but not readable. */
- if ((pwd = getenv ("PWD")) != 0
+ if ((pwd = egetenv ("PWD")) != 0
&& (IS_DIRECTORY_SEP (*pwd) || (*pwd && IS_DEVICE_SEP (pwd[1])))
&& stat (pwd, &pwdstat) == 0
&& stat (".", &dotstat) == 0
}
#endif
-/* Message functions. */
-
#ifdef WINDOWSNT
+
+#define REG_ROOT "SOFTWARE\\GNU\\Emacs"
+
+/* Retrieve an environment variable from the Emacs subkeys of the registry.
+ Return NULL if the variable was not found, or it was empty.
+ This code is based on w32_get_resource (w32.c). */
+char *
+w32_get_resource (predefined, key, type)
+ HKEY predefined;
+ char *key;
+ LPDWORD type;
+{
+ HKEY hrootkey = NULL;
+ char *result = NULL;
+ DWORD cbData;
+
+ if (RegOpenKeyEx (predefined, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
+ {
+ if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS)
+ {
+ result = (char *) xmalloc (cbData);
+
+ if ((RegQueryValueEx (hrootkey, key, NULL, type, result, &cbData) != ERROR_SUCCESS) ||
+ (*result == 0))
+ {
+ free (result);
+ result = NULL;
+ }
+ }
+
+ RegCloseKey (hrootkey);
+ }
+
+ return result;
+}
+
+/*
+ getenv wrapper for Windows
+
+ This is needed to duplicate Emacs's behavior, which is to look for enviroment
+ variables in the registry if they don't appear in the environment.
+*/
+char *
+w32_getenv (envvar)
+ char *envvar;
+{
+ char *value;
+ DWORD dwType;
+
+ if (value = getenv (envvar))
+ /* Found in the environment. */
+ return value;
+
+ 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;
+
+ if (dwType == REG_SZ)
+ /* Registry; no need to expand. */
+ return value;
+
+ if (dwType == REG_EXPAND_SZ)
+ {
+ DWORD size;
+
+ if (size = ExpandEnvironmentStrings (value, NULL, 0))
+ {
+ char *buffer = (char *) xmalloc (size);
+ if (ExpandEnvironmentStrings (value, buffer, size))
+ {
+ /* Found and expanded. */
+ free (value);
+ return buffer;
+ }
+
+ /* Error expanding. */
+ free (buffer);
+ }
+ }
+
+ /* Not the right type, or not correctly expanded. */
+ free (value);
+ return NULL;
+}
+
int
w32_window_app ()
{
char szTitle[MAX_PATH];
if (window_app < 0)
- /* Checking for STDOUT does not work; it's a valid handle also in
- nonconsole apps. Testing for the console title seems to work. */
- window_app = (GetConsoleTitleA (szTitle, MAX_PATH) == 0);
+ {
+ /* Checking for STDOUT does not work; it's a valid handle also in
+ nonconsole apps. Testing for the console title seems to work. */
+ window_app = (GetConsoleTitleA (szTitle, MAX_PATH) == 0);
+ if (window_app)
+ InitCommonControls();
+ }
return window_app;
}
/*
- execvp wrapper for Windows. Quotes arguments with embedded spaces.
+ execvp wrapper for Windows. Quotes arguments with embedded spaces.
This is necessary due to the broken implementation of exec* routines in
the Microsoft libraries: they concatenate the arguments together without
#endif /* WINDOWSNT */
+/* Display a normal or error message.
+ On Windows, use a message box if compiled as a Windows app. */
void
message (int is_error, char *message, ...)
{
int argc;
char **argv;
{
- alternate_editor = getenv ("ALTERNATE_EDITOR");
- display = getenv ("DISPLAY");
+ alternate_editor = egetenv ("ALTERNATE_EDITOR");
+#ifndef WINDOWSNT
+ display = egetenv ("DISPLAY");
if (display && strlen (display) == 0)
display = NULL;
+#endif
while (1)
{
server_file = optarg;
break;
+#ifndef WINDOWSNT
case 'd':
display = optarg;
break;
+#endif
case 'n':
nowait = 1;
case 't':
tty = 1;
+ current_frame = 0;
break;
case 'c':
- current_frame = 1;
+ current_frame = 0;
break;
case 'H':
-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\
--c, --current-frame Do not create a new frame;\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\
--n, --no-wait Don't wait for the server to return\n\
--d, --display=DISPLAY Visit the file in the given display\n"
+-n, --no-wait Don't wait for the server to return\n"
+#ifndef WINDOWSNT
+"-d, --display=DISPLAY Visit the file in the given display\n"
+#endif
#ifndef NO_SOCKETS_IN_FILE_SYSTEM
"-s, --socket-name=FILENAME\n\
Set filename of the UNIX socket for communication\n"
/*
Try to run a different command, or --if no alternate editor is
defined-- exit with an errorcode.
+ Uses argv, but gets it from the global variable main_argv.
*/
void
fail (void)
int argc;
char **argv;
{
- main_argc = argc;
main_argv = argv;
progname = argv[0];
message (TRUE, "%s: Sorry, the Emacs server is supported only\n"
# include <sys/types.h>
# include <sys/socket.h>
# include <sys/un.h>
-# include <sys/stat.h>
-# include <errno.h>
#endif
#define AUTH_KEY_LENGTH 64
/* Socket used to communicate with the Emacs server process. */
HSOCKET emacs_socket = 0;
+/* On Windows, the socket library was historically separate from the standard
+ C library, so errors are handled differently. */
+void
+sock_err_message (function_name)
+ char *function_name;
+{
+#ifdef WINDOWSNT
+ char* msg = NULL;
+
+ FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM
+ | FORMAT_MESSAGE_ALLOCATE_BUFFER
+ | FORMAT_MESSAGE_ARGUMENT_ARRAY,
+ NULL, WSAGetLastError (), 0, (LPTSTR)&msg, 0, NULL);
+
+ message (TRUE, "%s: %s: %s\n", progname, function_name, msg);
+
+ LocalFree (msg);
+#else
+ message (TRUE, "%s: %s: %s\n", progname, function_name, strerror (errno));
+#endif
+}
+
+
/* Let's send the data to Emacs when either
- the data ends in "\n", or
- the buffer is full (but this shouldn't happen)
if (WSAStartup (MAKEWORD (2, 0), &wsaData))
{
- message (TRUE, "%s: error initializing WinSock2", progname);
+ message (TRUE, "%s: error initializing WinSock2\n", progname);
exit (EXIT_FAILURE);
}
config = fopen (server_file, "rb");
else
{
- char *home = getenv ("HOME");
+ char *home = egetenv ("HOME");
if (home)
{
config = fopen (path, "rb");
}
#ifdef WINDOWSNT
- if (!config && (home = getenv ("APPDATA")))
+ if (!config && (home = egetenv ("APPDATA")))
{
char *path = alloca (32 + strlen (home) + strlen (server_file));
sprintf (path, "%s/.emacs.d/server/%s", home, server_file);
}
else
{
- message (TRUE, "%s: invalid configuration info", progname);
+ message (TRUE, "%s: invalid configuration info\n", progname);
exit (EXIT_FAILURE);
}
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);
}
*/
if ((s = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
{
- message (TRUE, "%s: socket: %s\n", progname, strerror (errno));
+ sock_err_message ("socket");
return INVALID_SOCKET;
}
*/
if (connect (s, (struct sockaddr *) &server, sizeof server) < 0)
{
- message (TRUE, "%s: connect: %s\n", progname, strerror (errno));
+ sock_err_message ("connect");
return INVALID_SOCKET;
}
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;
+ return !strncmp (prefix, string, strlen (prefix));
}
int sock_status = 0;
int default_sock = !socket_name;
int saved_errno = 0;
-
char *server_name = "server";
if (socket_name && !index (socket_name, '/') && !index (socket_name, '\\'))
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 ();
}
associated with the name. This is reminiscent of the logic
that init_editfns uses to set the global Vuser_full_name. */
- char *user_name = (char *) getenv ("LOGNAME");
+ char *user_name = (char *) egetenv ("LOGNAME");
if (!user_name)
- user_name = (char *) getenv ("USER");
+ user_name = (char *) egetenv ("USER");
if (user_name)
{
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);
}
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);
}
/* Explicit --server-file arg or EMACS_SERVER_FILE variable. */
if (!server_file)
- server_file = getenv ("EMACS_SERVER_FILE");
+ server_file = egetenv ("EMACS_SERVER_FILE");
if (server_file)
{
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);
}
char *cwd, *str;
char string[BUFSIZ+1];
- main_argc = argc;
main_argv = argv;
progname = argv[0];
w32_give_focus ();
#endif
- /* First of all, send our version number for verification. */
- send_to_emacs (emacs_socket, "-version ");
- send_to_emacs (emacs_socket, VERSION);
- send_to_emacs (emacs_socket, " ");
-
/* Send over our environment. */
if (!current_frame)
{
if (tty)
{
- char *type = getenv ("TERM");
+ char *type = egetenv ("TERM");
char *tty_name = NULL;
#ifndef WINDOWSNT
tty_name = ttyname (fileno (stdin));
while (p > string && *p == '\n')
*p-- = 0;
- if (strprefix ("-good-version ", string))
- {
- /* -good-version: The versions match. */
- }
- else if (strprefix ("-emacs-pid ", string))
+ if (strprefix ("-emacs-pid ", string))
{
/* -emacs-pid PID: The process id of the Emacs process. */
emacs_pid = strtol (string + strlen ("-emacs-pid"), NULL, 10);
fprintf (stderr, "*ERROR*: %s", str);
needlf = str[0] == '\0' ? needlf : str[strlen (str) - 1] != '\n';
}
-#ifndef WINDOWSNT
+#ifdef SIGSTOP
else if (strprefix ("-suspend ", string))
{
/* -suspend: Suspend this terminal, i.e., stop the process. */