* server.el (server-process-filter): Use expand-file-name rather than
[bpt/emacs.git] / lib-src / emacsclient.c
index cac8bce..3197b2a 100644 (file)
@@ -1,6 +1,6 @@
 /* Client process that communicates with GNU Emacs acting as server.
    Copyright (C) 1986, 1987, 1994, 1999, 2000, 2001, 2002, 2003, 2004,
-                 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+                 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -41,17 +41,23 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #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
@@ -129,9 +135,6 @@ int eval = 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;
-
 /* The display on which Emacs should work.  --display.  */
 char *display = NULL;
 
@@ -527,11 +530,9 @@ decode_options (argc, argv)
             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;
@@ -566,38 +567,44 @@ decode_options (argc, argv)
        }
     }
 
-  /* 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");
+    {
+      display = egetenv ("DISPLAY");
+#ifdef NS_IMPL_COCOA
+      /* Under Cocoa, we don't really use displays the same way as in X,
+         so provide a dummy. */
+      if (!display || strlen (display) == 0)
+        display = "ns";
+#endif
+    }
 
+  /* A null-string display is invalid.  */
   if (display && strlen (display) == 0)
     display = NULL;
 
-  if (!tty && display)
-    window_system = 1;
-  else if (!current_frame)
+  /* If no display is available, new frames are tty frames.  */
+  if (!current_frame && !display)
     tty = 1;
 
   /* --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
@@ -629,8 +636,12 @@ The following OPTIONS are accepted:\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);
 }
@@ -1011,6 +1022,57 @@ strprefix (char *prefix, char *string)
   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)
 
@@ -1099,6 +1161,8 @@ handle_sigtstp (int signalnum)
 
   errno = old_errno;
 }
+
+
 /* Set up signal handlers before opening a frame on the current tty.  */
 
 void
@@ -1255,7 +1319,7 @@ To start the server in Emacs, type \"M-x server-start\".\n",
 #endif /* ! NO_SOCKETS_IN_FILE_SYSTEM */
 
 HSOCKET
-set_socket ()
+set_socket (int no_exit_if_error)
 {
   HSOCKET s;
 
@@ -1266,7 +1330,7 @@ set_socket ()
   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);
@@ -1281,7 +1345,7 @@ set_socket ()
   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",
@@ -1299,7 +1363,7 @@ set_socket ()
   /* 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.  */
@@ -1369,6 +1433,60 @@ w32_give_focus ()
 }
 #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;
+
+  dpid = fork ();
+
+  if (dpid > 0)
+    {
+      pid_t w;
+      w = waitpid (dpid, &status, WUNTRACED | WCONTINUED);
+
+      if ((w == -1) || !WIFEXITED (status) || WEXITSTATUS(status))
+       {
+         message (TRUE, "Error: Could not start the Emacs daemon\n");
+         exit (EXIT_FAILURE);
+       }
+
+      /* Try connecting, the daemon should have started by now.  */
+      message (TRUE, "Emacs daemon should have started, trying to connect again\n");
+      if ((emacs_socket = set_socket (1)) == INVALID_SOCKET)
+       {
+         message (TRUE, "Error: Cannot connect even after starting the Emacs daemon\n");
+         exit (EXIT_FAILURE);
+       }
+    }
+  else if (dpid < 0)
+    {
+      fprintf (stderr, "Error: 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;
@@ -1377,6 +1495,7 @@ main (argc, argv)
   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];
@@ -1384,7 +1503,7 @@ main (argc, argv)
   /* 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",
@@ -1392,9 +1511,34 @@ main (argc, argv)
       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)
@@ -1409,7 +1553,7 @@ main (argc, argv)
   w32_give_focus ();
 #endif
 
-  /* Send over our environment. */
+  /* Send over our environment and current directory. */
   if (!current_frame)
     {
       extern char **environ;
@@ -1423,15 +1567,10 @@ main (argc, argv)
           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, " ");
-    }
+  send_to_emacs (emacs_socket, "-dir ");
+  quote_argument (emacs_socket, cwd);
+  send_to_emacs (emacs_socket, "/");
+  send_to_emacs (emacs_socket, " ");
 
  retry:
   if (nowait)
@@ -1452,50 +1591,28 @@ main (argc, argv)
      frame is available.  */
   if (tty || (current_frame && !eval))
     {
-      char *type = egetenv ("TERM");
-      char *tty_name = NULL;
+      char *tty_type, *tty_name;
 
-      tty_name = ttyname (fileno (stdout));
-
-      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))
     {
       for (i = optind; i < argc; i++)
        {
-          int relative = 0;
 
          if (eval)
             {
@@ -1517,58 +1634,22 @@ main (argc, argv)
                   send_to_emacs (emacs_socket, " ");
                   continue;
                 }
-              else
-                relative = 1;
             }
-         else if (! file_name_absolute_p (argv[i]))
-#ifndef WINDOWSNT
-           relative = 1;
-#else
-           /* Call GetFullPathName so filenames of the form X:Y, where X is
-              a valid drive designator, are interpreted as drive:path, not
-              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 with NTFS streams. */
-           {
-             char *filename = (char *) xmalloc (MAX_PATH);
-             DWORD size;
-
-             size = GetFullPathName (argv[i], MAX_PATH, filename, NULL);
-             if (size > 0 && size < MAX_PATH)
-               argv[i] = filename;
-             else
-               {
-                 relative = 1;
-                 free (filename);
-               }
-           }
-#endif
 
           send_to_emacs (emacs_socket, "-file ");
-          if (relative)
-            {
-              quote_argument (emacs_socket, cwd);
-              send_to_emacs (emacs_socket, "/");
-            }
           quote_argument (emacs_socket, argv[i]);
           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");
@@ -1601,7 +1682,6 @@ main (argc, argv)
         {
           /* -window-system-unsupported: Emacs was compiled without X
               support.  Try again on the terminal. */
-          window_system = 0;
           nowait = 0;
           tty = 1;
           goto retry;