(main): Fix having macros in a printf statement.
[bpt/emacs.git] / lib-src / emacsclient.c
index b63a4d2..fc85ba6 100644 (file)
@@ -1,5 +1,5 @@
 /* Client process that communicates with GNU Emacs acting as server.
 /* Client process that communicates with GNU Emacs acting as server.
-   Copyright (C) 1986, 1987, 1994, 1999, 2000, 2001
+   Copyright (C) 1986, 1987, 1994, 1999, 2000, 2001, 2003
    Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
    Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
@@ -21,10 +21,14 @@ Boston, MA 02111-1307, USA.  */
 
 
 #define NO_SHORTNAMES
 
 
 #define NO_SHORTNAMES
-#include <../src/config.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
 #undef signal
 
 #undef signal
 
-#include <ctype.h> 
+#include <ctype.h>
 #include <stdio.h>
 #include <getopt.h>
 #ifdef HAVE_UNISTD_H
 #include <stdio.h>
 #include <getopt.h>
 #ifdef HAVE_UNISTD_H
@@ -53,20 +57,29 @@ char *progname;
 /* Nonzero means don't wait for a response from Emacs.  --no-wait.  */
 int nowait = 0;
 
 /* Nonzero means don't wait for a response from Emacs.  --no-wait.  */
 int nowait = 0;
 
+/* Nonzero means args are expressions to be evaluated.  --eval.  */
+int eval = 0;
+
+/* The display on which Emacs should work.  --display.  */
+char *display = NULL;
+
+/* If non-NULL, the name of an editor to fallback to if the server
+   is not running.  --alternate-editor.   */
+const char * alternate_editor = NULL;
+
 void print_help_and_exit ();
 
 struct option longopts[] =
 {
   { "no-wait", no_argument,       NULL, 'n' },
 void print_help_and_exit ();
 
 struct option longopts[] =
 {
   { "no-wait", no_argument,       NULL, 'n' },
+  { "eval",    no_argument,       NULL, 'e' },
   { "help",    no_argument,       NULL, 'H' },
   { "version", no_argument,       NULL, 'V' },
   { "help",    no_argument,       NULL, 'H' },
   { "version", no_argument,       NULL, 'V' },
-  { "alternate-editor",required_argument, NULL, 'a' },
-  { 0 }
+  { "alternate-editor", required_argument, NULL, 'a' },
+  { "display", required_argument, NULL, 'd' },
+  { 0, 0, 0, 0 }
 };
 
 };
 
-
-const char * alternate_editor = NULL;
-
 /* Decode the options from argv and argc.
    The global variable `optind' will say how many arguments we used up.  */
 
 /* Decode the options from argv and argc.
    The global variable `optind' will say how many arguments we used up.  */
 
@@ -78,36 +91,49 @@ decode_options (argc, argv)
   while (1)
     {
       int opt = getopt_long (argc, argv,
   while (1)
     {
       int opt = getopt_long (argc, argv,
-                            "VHna:", longopts, 0);
+                            "VHnea:d:", longopts, 0);
 
       if (opt == EOF)
        break;
 
       alternate_editor = getenv ("ALTERNATE_EDITOR");
 
       if (opt == EOF)
        break;
 
       alternate_editor = getenv ("ALTERNATE_EDITOR");
-      
+
       switch (opt)
        {
        case 0:
          /* If getopt returns 0, then it has already processed a
             long-named option.  We should do nothing.  */
          break;
       switch (opt)
        {
        case 0:
          /* If getopt returns 0, then it has already processed a
             long-named option.  We should do nothing.  */
          break;
-         
+
        case 'a':
          alternate_editor = optarg;
          break;
        case 'a':
          alternate_editor = optarg;
          break;
-         
+
+       case 'd':
+         display = optarg;
+         break;
+
        case 'n':
          nowait = 1;
          break;
 
        case 'n':
          nowait = 1;
          break;
 
+       case 'e':
+         eval = 1;
+         break;
+
        case 'V':
        case 'V':
-         fprintf (stderr, "emacsclient %s\n", VERSION);
-         exit (1);
+         printf ("emacsclient %s\n", VERSION);
+         exit (0);
          break;
 
        case 'H':
          break;
 
        case 'H':
-       default:
          print_help_and_exit ();
          print_help_and_exit ();
+         break;
+
+       default:
+         fprintf (stderr, "Try `%s --help' for more information\n", progname);
+         exit (1);
+         break;
        }
     }
 }
        }
     }
 }
@@ -115,19 +141,26 @@ decode_options (argc, argv)
 void
 print_help_and_exit ()
 {
 void
 print_help_and_exit ()
 {
-  fprintf (stderr,
-          "Usage: %s [-a ALTERNATE-EDITOR] [-n] [--no-wait] [+LINE[:COLUMN]] FILENAME\n",
-          progname);
-  fprintf (stderr,
-          "Or %s --version\n",
-          progname);
-  fprintf (stderr,
-          "Report bugs to bug-gnu-emacs@gnu.org.\n");
-  exit (1);
+  printf (
+         "Usage: %s [OPTIONS] FILE...\n\
+Tell the Emacs server to visit the specified files.\n\
+Every FILE can be either just a FILENAME or [+LINE[:COLUMN]] FILENAME.\n\
+\n\
+The following OPTIONS are accepted:\n\
+-V, --version           Just print a version info and return\n\
+-H, --help              Print this usage information message\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\
+-a, --alternate-editor=EDITOR\n\
+                        Editor to fallback to if the server is not running\n\
+\n\
+Report bugs to bug-gnu-emacs@gnu.org.\n", progname);
+  exit (0);
 }
 
 /* Return a copy of NAME, inserting a &
 }
 
 /* Return a copy of NAME, inserting a &
-   before each &, each space, and any initial -.
+   before each &, each space, each newline, and any initial -.
    Change spaces to underscores, too, so that the
    return value never contains a space.  */
 
    Change spaces to underscores, too, so that the
    return value never contains a space.  */
 
@@ -148,6 +181,12 @@ quote_file_name (name)
          *q++ = '_';
          p++;
        }
          *q++ = '_';
          p++;
        }
+      else if (*p == '\n')
+       {
+         *q++ = '&';
+         *q++ = 'n';
+         p++;
+       }
       else
        {
          if (*p == '&' || (*p == '-' && p == name))
       else
        {
          if (*p == '&' || (*p == '-' && p == name))
@@ -157,7 +196,6 @@ quote_file_name (name)
     }
   *q++ = 0;
 
     }
   *q++ = 0;
 
-  
   return copy;
 }
 
   return copy;
 }
 
@@ -187,7 +225,7 @@ fail (argc, argv)
 {
   if (alternate_editor)
     {
 {
   if (alternate_editor)
     {
-      int i = optind -;
+      int i = optind - 1;
       execvp (alternate_editor, argv + i);
       return;
     }
       execvp (alternate_editor, argv + i);
       return;
     }
@@ -198,9 +236,8 @@ fail (argc, argv)
 }
 
 
 }
 
 
-       
 \f
 \f
-#if !defined (HAVE_SOCKETS) && !defined (HAVE_SYSVIPC)
+#if !defined (HAVE_SOCKETS) || defined (NO_SOCKETS_IN_FILE_SYSTEM)
 
 int
 main (argc, argv)
 
 int
 main (argc, argv)
@@ -209,15 +246,12 @@ main (argc, argv)
 {
   fprintf (stderr, "%s: Sorry, the Emacs server is supported only\n",
           argv[0]);
 {
   fprintf (stderr, "%s: Sorry, the Emacs server is supported only\n",
           argv[0]);
-  fprintf (stderr, "on systems with Berkeley sockets or System V IPC.\n");
+  fprintf (stderr, "on systems with Berkeley sockets.\n");
 
   fail (argc, argv);
 }
 
 
   fail (argc, argv);
 }
 
-#else /* HAVE_SOCKETS or HAVE_SYSVIPC */
-
-#if defined (HAVE_SOCKETS) && ! defined (NO_SOCKETS_IN_FILE_SYSTEM)
-/* BSD code is very different from SYSV IPC code */
+#else /* HAVE_SOCKETS */
 
 #include <sys/types.h>
 #include <sys/socket.h>
 
 #include <sys/types.h>
 #include <sys/socket.h>
@@ -255,12 +289,9 @@ main (argc, argv)
 {
   char *system_name;
   int system_name_length;
 {
   char *system_name;
   int system_name_length;
-  int s, i;
+  int s, i, needlf = 0;
   FILE *out, *in;
   struct sockaddr_un server;
   FILE *out, *in;
   struct sockaddr_un server;
-#ifdef SERVER_HOME_DIR
-  char *homedir;
-#endif
   char *cwd, *str;
   char string[BUFSIZ];
 
   char *cwd, *str;
   char string[BUFSIZ];
 
@@ -270,9 +301,13 @@ main (argc, argv)
   decode_options (argc, argv);
 
   if (argc - optind < 1)
   decode_options (argc, argv);
 
   if (argc - optind < 1)
-    print_help_and_exit ();
+    {
+      fprintf (stderr, "%s: file name or argument required\n", progname);
+      fprintf (stderr, "Try `%s --help' for more information\n", progname);
+      exit (1);
+    }
 
 
-  /* 
+  /*
    * Open up an AF_UNIX socket in this person's home directory
    */
 
    * Open up an AF_UNIX socket in this person's home directory
    */
 
@@ -282,10 +317,11 @@ main (argc, argv)
       perror ("socket");
       fail (argc, argv);
     }
       perror ("socket");
       fail (argc, argv);
     }
-  
+
   server.sun_family = AF_UNIX;
 
   {
   server.sun_family = AF_UNIX;
 
   {
+    char *dot;
     system_name_length = 32;
 
     while (1)
     system_name_length = 32;
 
     while (1)
@@ -301,13 +337,17 @@ main (argc, argv)
        free (system_name);
        system_name_length *= 2;
       }
        free (system_name);
        system_name_length *= 2;
       }
+
+    /* We always use the non-dotted host name, for simplicity.  */
+    dot = index (system_name, '.');
+    if (dot)
+      *dot = '\0';
   }
 
   }
 
-#ifndef SERVER_HOME_DIR
   {
     int sock_status = 0;
 
   {
     int sock_status = 0;
 
-    sprintf (server.sun_path, "/tmp/esrv%d-%s", (int) geteuid (), system_name);
+    sprintf (server.sun_path, "/tmp/emacs%d-%s/server", (int) geteuid (), system_name);
 
     /* See if the socket exists, and if it's owned by us. */
     sock_status = socket_status (server.sun_path);
 
     /* See if the socket exists, and if it's owned by us. */
     sock_status = socket_status (server.sun_path);
@@ -317,11 +357,11 @@ main (argc, argv)
           our euid.  If so, look for a socket based on the UID
           associated with the name.  This is reminiscent of the logic
           that init_editfns uses to set the global Vuser_full_name.  */
           our euid.  If so, look for a socket based on the UID
           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");
        if (!user_name)
          user_name = (char *) getenv ("USER");
        char *user_name = (char *) getenv ("LOGNAME");
        if (!user_name)
          user_name = (char *) getenv ("USER");
-       
+
        if (user_name)
          {
            struct passwd *pw = getpwnam (user_name);
        if (user_name)
          {
            struct passwd *pw = getpwnam (user_name);
@@ -334,7 +374,7 @@ main (argc, argv)
              }
          }
       }
              }
          }
       }
+
      switch (sock_status)
        {
        case 1:
      switch (sock_status)
        {
        case 1:
@@ -346,12 +386,13 @@ main (argc, argv)
             fail (argc, argv);
           }
         break;
             fail (argc, argv);
           }
         break;
-        
+
        case 2:
         /* `stat' failed */
         if (errno == ENOENT)
           fprintf (stderr,
        case 2:
         /* `stat' failed */
         if (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]);
         else
           fprintf (stderr, "%s: can't stat %s: %s\n",
@@ -360,16 +401,6 @@ main (argc, argv)
         break;
        }
   }
         break;
        }
   }
-#else
-  if ((homedir = getenv ("HOME")) == NULL)
-    {
-      fprintf (stderr, "%s: No home directory\n", argv[0]);
-      fail (argc, argv);
-    }
-  strcpy (server.sun_path, homedir);
-  strcat (server.sun_path, "/.emacs-server-");
-  strcat (server.sun_path, system_name);
-#endif
 
   if (connect (s, (struct sockaddr *) &server, strlen (server.sun_path) + 2)
       < 0)
 
   if (connect (s, (struct sockaddr *) &server, strlen (server.sun_path) + 2)
       < 0)
@@ -399,33 +430,41 @@ main (argc, argv)
       fail (argc, argv);
     }
 
       fail (argc, argv);
     }
 
-#ifdef BSD_SYSTEM
-  cwd = getwd (string);
-#else
+#ifdef HAVE_GETCWD
   cwd = getcwd (string, sizeof string);
   cwd = getcwd (string, sizeof string);
+#else
+  cwd = getwd (string);
 #endif
   if (cwd == 0)
     {
       /* getwd puts message in STRING if it fails.  */
 #endif
   if (cwd == 0)
     {
       /* getwd puts message in STRING if it fails.  */
+
+#ifdef HAVE_GETCWD
       fprintf (stderr, "%s: %s (%s)\n", argv[0],
       fprintf (stderr, "%s: %s (%s)\n", argv[0],
-#ifdef BSD_SYSTEM
-              string,
+              "Cannot get current working directory", strerror (errno));
 #else
 #else
-              "Cannot get current working directory",
+      fprintf (stderr, "%s: %s (%s)\n", argv[0], string, strerror (errno));
 #endif
 #endif
-              strerror (errno));
       fail (argc, argv);
     }
 
   if (nowait)
     fprintf (out, "-nowait ");
 
       fail (argc, argv);
     }
 
   if (nowait)
     fprintf (out, "-nowait ");
 
+  if (eval)
+    fprintf (out, "-eval ");
+
+  if (display)
+    fprintf (out, "-display %s ", quote_file_name (display));
+
   for (i = optind; i < argc; i++)
     {
   for (i = optind; i < argc; i++)
     {
-      if (*argv[i] == '+')
+      if (eval)
+       ; /* Don't prepend any cwd or anything like that.  */
+      else if (*argv[i] == '+')
        {
          char *p = argv[i] + 1;
        {
          char *p = argv[i] + 1;
-         while (isdigit (*p) || *p == ':') p++;
+         while (isdigit ((unsigned char) *p) || *p == ':') p++;
          if (*p != 0)
            fprintf (out, "%s/", quote_file_name (cwd));
        }
          if (*p != 0)
            fprintf (out, "%s/", quote_file_name (cwd));
        }
@@ -441,197 +480,30 @@ main (argc, argv)
   if (nowait)
     return 0;
 
   if (nowait)
     return 0;
 
-  printf ("Waiting for Emacs...");
-  fflush (stdout);
-
-  /* Now, wait for an answer and print any messages.  On some systems,
-     the first line we read will actually be the output we just sent.
-     We can't predict whether that will happen, so if it does, we
-     detect it by recognizing `Client: ' at the beginning.  */
-  
-  while (str = fgets (string, BUFSIZ, in))
-    printf ("%s", str);
-
-  return 0;
-}
-
-#else /* This is the SYSV IPC section */
-
-#include <sys/types.h>
-#include <sys/ipc.h>
-#include <sys/msg.h>
-#include <sys/utsname.h>
-#include <stdio.h>
-#include <errno.h>
-extern int errno;
-
-char *getwd (), *getcwd (), *getenv ();
-struct utsname system_name;
-
-main (argc, argv)
-     int argc;
-     char **argv;
-{
-  int s;
-  key_t key;
-  /* Size of text allocated in MSGP.  */
-  int size_allocated = BUFSIZ;
-  /* Amount of text used in MSGP.  */
-  int used;
-  struct msgbuf *msgp
-    = (struct msgbuf *) malloc (sizeof (struct msgbuf) + size_allocated);
-  struct msqid_ds * msg_st;
-  char *homedir, buf[BUFSIZ];
-  char gwdirb[BUFSIZ];
-  char *cwd;
-  char *temp;
-
-  progname = argv[0];
-
-  /* Process options.  */
-  decode_options (argc, argv);
-
-  if (argc - optind < 1)
-    print_help_and_exit ();
-
-  /*
-   * Create a message queue using ~/.emacs-server as the path for ftok
-   */
-  if ((homedir = getenv ("HOME")) == NULL)
+  if (!eval)
     {
     {
-      fprintf (stderr, "%s: No home directory\n", argv[0]);
-      exit (1);
-    }
-  strcpy (buf, homedir);
-#ifndef HAVE_LONG_FILE_NAMES
-  /* If file names are short, we can't fit the host name.  */
-  strcat (buf, "/.emacs-server");
-#else
-  strcat (buf, "/.emacs-server-");
-  uname (&system_name);
-  strcat (buf, system_name.nodename);
-#endif
-  creat (buf, 0600);
-  key = ftok (buf, 1); /* unlikely to be anyone else using it */
-  s = msgget (key, 0600 | IPC_CREAT);
-  if (s == -1)
-    {
-      fprintf (stderr, "%s: ", argv[0]);
-      perror ("msgget");
-      exit (1);
-    }
-
-  /* Determine working dir, so we can prefix it to all the arguments.  */
-#ifdef BSD_SYSTEM
-  temp = getwd (gwdirb);
-#else
-  temp = getcwd (gwdirb, sizeof gwdirb);
-#endif
-
-  cwd = gwdirb;
-  if (temp != 0)
-    {
-      /* On some systems, cwd can look like `@machine/...';
-        ignore everything before the first slash in such a case.  */
-      while (*cwd && *cwd != '/')
-       cwd++;
-      strcat (cwd, "/");
-    }
-  else
-    {
-#ifdef BSD_SYSTEM
-      fprintf (stderr, "%s: %s\n", argv[0], cwd);
-#else
-      fprintf (stderr, "%s: Cannot get current working directory: %s\n",
-              argv[0], strerror (errno));
-#endif
-      fail (argc, argv);
+      printf ("Waiting for Emacs...");
+      needlf = 2;
     }
     }
+  fflush (stdout);
 
 
-  msgp->mtext[0] = 0;
-  used = 0;
-
-  if (nowait)
-    {
-      strcat (msgp->mtext, "-nowait ");
-      used += 8;
-    }
-
-  argc -= optind;
-  argv += optind;
-
-  while (argc)
-    {
-      int need_cwd = 0;
-      char *modified_arg = argv[0];
-
-      if (*modified_arg == '+')
-       {
-         char *p = modified_arg + 1;
-         while (isdigit (*p) || *p == ':')
-           p++;
-         if (*p != 0)
-           need_cwd = 1;
-       }
-      else if (*modified_arg != '/')
-       need_cwd = 1;
-
-      modified_arg = quote_file_name (modified_arg);
-
-      if (need_cwd)
-       /* Overestimate in case we have to quote something in CWD.  */
-       used += 2 * strlen (cwd);
-      used += strlen (modified_arg) + 1;
-      while (used + 2 > size_allocated)
-       {
-         size_allocated *= 2;
-         msgp = (struct msgbuf *) realloc (msgp,
-                                           (sizeof (struct msgbuf)
-                                            + size_allocated));
-       }
-
-      if (need_cwd)
-       strcat (msgp->mtext, quote_file_name (cwd));
-
-      strcat (msgp->mtext, modified_arg);
-      strcat (msgp->mtext, " ");
-      argv++; argc--;
-    }
-  strcat (msgp->mtext, "\n");
-#ifdef HPUX /* HPUX has a bug.  */
-  if (strlen (msgp->mtext) >= 512)
-    {
-      fprintf (stderr, "%s: args too long for msgsnd\n", progname);
-      fail (argc, argv);
-    }
-#endif
-  msgp->mtype = 1;
-  if (msgsnd (s, msgp, strlen (msgp->mtext)+1, 0) < 0)
+  /* Now, wait for an answer and print any messages.  */
+  while ((str = fgets (string, BUFSIZ, in)))
     {
     {
-      fprintf (stderr, "%s: ", progname);
-      perror ("msgsnd");
-      fail (argc, argv);
+      if (needlf == 2)
+       printf ("\n");
+      printf ("%s", str);
+      needlf = str[0] == '\0' ? needlf : str[strlen (str) - 1] != '\n';
     }
 
     }
 
-  /* Maybe wait for an answer.   */
-  if (nowait)
-    return 0;
-
-  printf ("Waiting for Emacs...");
+  if (needlf)
+    printf ("\n");
   fflush (stdout);
 
   fflush (stdout);
 
-  msgrcv (s, msgp, BUFSIZ, getpid (), 0);      /* wait for anything back */
-  strcpy (buf, msgp->mtext);
-
-  printf ("\n");
-  if (*buf)
-    printf ("%s\n", buf);
-  exit (0);
+  return 0;
 }
 
 }
 
-#endif /* HAVE_SYSVIPC */
-
-#endif /* HAVE_SOCKETS or HAVE_SYSVIPC */
+#endif /* HAVE_SOCKETS */
 \f
 #ifndef HAVE_STRERROR
 char *
 \f
 #ifndef HAVE_STRERROR
 char *