+ *q++ = 0;
+
+ send_to_emacs (s, copy);
+
+ free (copy);
+}
+
+
+/* The inverse of quote_argument. Removes quoting in string STR by
+ modifying the string in place. Returns STR. */
+
+char *
+unquote_argument (str)
+ char *str;
+{
+ char *p, *q;
+
+ if (! str)
+ return str;
+
+ p = str;
+ q = str;
+ while (*p)
+ {
+ if (*p == '&')
+ {
+ p++;
+ if (*p == '&')
+ *p = '&';
+ else if (*p == '_')
+ *p = ' ';
+ else if (*p == 'n')
+ *p = '\n';
+ else if (*p == '-')
+ *p = '-';
+ }
+ *q++ = *p++;
+ }
+ *q = 0;
+ return str;
+}
+
+\f
+int
+file_name_absolute_p (filename)
+ const unsigned char *filename;
+{
+ /* Sanity check, it shouldn't happen. */
+ if (! filename) return FALSE;
+
+ /* /xxx is always an absolute path. */
+ if (filename[0] == '/') return TRUE;
+
+ /* Empty filenames (which shouldn't happen) are relative. */
+ if (filename[0] == '\0') return FALSE;
+
+#ifdef WINDOWSNT
+ /* X:\xxx is always absolute. */
+ if (isalpha (filename[0])
+ && filename[1] == ':' && (filename[2] == '\\' || filename[2] == '/'))
+ return TRUE;
+
+ /* 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;
+}
+
+#ifdef WINDOWSNT
+/* Wrapper to make WSACleanup a cdecl, as required by atexit. */
+void
+__cdecl close_winsock ()
+{
+ WSACleanup ();
+}
+
+/* Initialize the WinSock2 library. */
+void
+initialize_sockets ()
+{
+ WSADATA wsaData;
+
+ if (WSAStartup (MAKEWORD (2, 0), &wsaData))
+ {
+ message (TRUE, "%s: error initializing WinSock2", progname);
+ exit (EXIT_FAILURE);
+ }
+
+ atexit (close_winsock);
+}
+#endif /* WINDOWSNT */
+
+\f
+/*
+ * Read the information needed to set up a TCP comm channel with
+ * the Emacs server: host, port, pid and authentication string.
+ */
+int
+get_server_config (server, authentication)
+ struct sockaddr_in *server;
+ char *authentication;
+{
+ char dotted[32];
+ char *port;
+ char *pid;
+ FILE *config = NULL;
+
+ if (file_name_absolute_p (server_file))
+ config = fopen (server_file, "rb");
+ else
+ {
+ char *home = getenv ("HOME");
+
+ if (home)
+ {
+ char *path = alloca (32 + strlen (home) + strlen (server_file));
+ sprintf (path, "%s/.emacs.d/server/%s", home, server_file);
+ config = fopen (path, "rb");
+ }
+#ifdef WINDOWSNT
+ if (!config && (home = getenv ("APPDATA")))
+ {
+ char *path = alloca (32 + strlen (home) + strlen (server_file));
+ sprintf (path, "%s/.emacs.d/server/%s", home, server_file);
+ config = fopen (path, "rb");
+ }
+#endif
+ }
+
+ if (! config)
+ return FALSE;
+
+ if (fgets (dotted, sizeof dotted, config)
+ && (port = strchr (dotted, ':'))
+ && (pid = strchr (port, ' ')))
+ {
+ *port++ = '\0';
+ *pid++ = '\0';
+ }
+ else
+ {
+ message (TRUE, "%s: invalid configuration info", progname);
+ exit (EXIT_FAILURE);
+ }
+
+ server->sin_family = AF_INET;
+ server->sin_addr.s_addr = inet_addr (dotted);
+ server->sin_port = htons (atoi (port));
+
+ if (! fread (authentication, AUTH_KEY_LENGTH, 1, config))
+ {
+ message (TRUE, "%s: cannot read authentication info", progname);
+ exit (EXIT_FAILURE);
+ }