diff lib-src/gnuclient.c @ 151:59463afc5666 r20-3b2

Import from CVS: tag r20-3b2
author cvs
date Mon, 13 Aug 2007 09:37:19 +0200
parents 538048ae2ab8
children 25f70ba0133c
line wrap: on
line diff
--- a/lib-src/gnuclient.c	Mon Aug 13 09:36:20 2007 +0200
+++ b/lib-src/gnuclient.c	Mon Aug 13 09:37:19 2007 +0200
@@ -124,6 +124,9 @@
   signal (SIGHUP, pass_signal_to_emacs);
   signal (SIGQUIT, pass_signal_to_emacs);
   signal (SIGINT, pass_signal_to_emacs);
+#ifdef SIGWINCH
+  signal (SIGWINCH, pass_signal_to_emacs);
+#endif
 
   /* We want emacs to realize that we are resuming */
   signal (SIGCONT, tell_emacs_to_resume);
@@ -190,234 +193,395 @@
 
 } /* filename_expand */
 
+/* Encase the string in quotes, escape all the backslashes and quotes
+   in string.  */
+char *
+clean_string (CONST char *s)
+{
+  int i = 0;
+  char *p, *res;
+
+  for (p = s; *p; p++, i++)
+    {
+      if (*p == '\\' || *p == '\"')
+	++i;
+      else if (*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)
+
+
 int
 main (int argc, char *argv[])
 {
-  int starting_line = 1;			/* line to start editing at */
-  char command[MAXPATHLEN+50];			/* emacs command buffer */
-  char fullpath[MAXPATHLEN+1];			/* full pathname to file */
-  int qflg = 0;					/* quick edit, don't wait for 
-						 * user to finish */
-  int view = 0;					/* view only. */
-  int errflg = 0;				/* option error */
-  int c;					/* char from getopt */
-  int s;					/* socket / msqid to server */
-  int connect_type;           			/* CONN_UNIX, CONN_INTERNET, or
-						 * CONN_IPC */
+  int starting_line = 1;	/* line to start editing at */
+  char command[MAXPATHLEN+50];	/* emacs command buffer */
+  char fullpath[MAXPATHLEN+1];	/* full pathname to file */
+  char *eval_form = NULL;	/* form to evaluate with `-eval' */
+  char *eval_function = NULL;	/* function to evaluate with `-f' */
+  char *load_library = NULL;	/* library to load */
+  int quick = 0;	       	/* quick edit, don't wait for user to
+				   finish */
+  int batch = 0;		/* batch mode */
+  int view = 0;			/* view only. */
+  int nofiles = 0;
+  int errflg = 0;		/* option error */
+  int c;			/* char from getopt */
+  int s;			/* socket / msqid to server */
+  int connect_type;		/* CONN_UNIX, CONN_INTERNET, or
+				 * CONN_IPC */
   int suppress_windows_system = 0;
   char *display;
 #ifdef INTERNET_DOMAIN_SOCKETS
-  char *hostarg = NULL;				/* remote hostname */
-  char thishost[HOSTNAMSZ];			/* this hostname */
-  char remotepath[MAXPATHLEN+1];		/* remote pathname */
-  int rflg = 0;					/* pathname given on cmdline */
-  u_short portarg = 0;				/* port to server */
-  char *ptr;					/* return from getenv */
+  char *hostarg = NULL;		/* remote hostname */
+  char *remotearg;
+  char thishost[HOSTNAMSZ];	/* this hostname */
+  char remotepath[MAXPATHLEN+1]; /* remote pathname */
+  char *path;
+  int rflg = 0;			/* pathname given on cmdline */
+  char *portarg;
+  u_short port = 0;		/* port to server */
 #endif /* INTERNET_DOMAIN_SOCKETS */
 #ifdef SYSV_IPC
-  struct msgbuf *msgp;				/* message */
+  struct msgbuf *msgp;		/* message */
 #endif /* SYSV_IPC */
   char *tty;
-  char buffer[GSERV_BUFSZ+1];		/* buffer to read pid */
+  char buffer[GSERV_BUFSZ + 1];	/* buffer to read pid */
+  char result[GSERV_BUFSZ + 1];
+  int i;
 
 #ifdef INTERNET_DOMAIN_SOCKETS
   memset (remotepath, 0, sizeof (remotepath));
 #endif /* INTERNET_DOMAIN_SOCKETS */
 
-  progname = argv[0];
+  progname = strrchr (argv[0], '/');
+  if (progname)
+    ++progname;
+  else
+    progname = argv[0];
 
   display = getenv ("DISPLAY");
   if (!display)
     suppress_windows_system = 1;
 
-  while ((c = getopt (argc, argv,
-
-#ifdef INTERNET_DOMAIN_SOCKETS
-		      "n:h:p:r:qv"
-#else /* !INTERNET_DOMAIN_SOCKETS */
-		      "n:qv"
-#endif /* !INTERNET_DOMAIN_SOCKETS */
-
-		      )) != EOF)
-    switch (c)
-      {
-      case 'n':
-	if (*optarg == 'w')
-	  suppress_windows_system++;
-	else
-	  errflg++;
-	break;
-      case 'q':					/* quick mode specified */
-	qflg++;
+  for (i = 1; argv[i] && !errflg; i++)
+    {
+      if (*argv[i] != '-')
 	break;
-      case 'v':
-	view++;
-	break;
-
+      if (!strcmp (argv[i], "-batch"))
+	batch = 1;
+      else if (!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"))
+	{
+	  suppress_windows_system = 0;
+	  if (!argv[++i])
+	    {
+	      fprintf (stderr, "%s: `-display' must be followed by an argument\n",
+		       progname);
+	      exit (1);
+	    }
+	  display = argv[i];
+	}
+      else if (!strcmp (argv[i], "-nw"))
+	suppress_windows_system = 1;
+      else
+	{
+	  /* Iterate over one-letter options. */
+	  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':				/* server host name specified */
-	hostarg = optarg;
-	break;
-      case 'r':				/* remote path from server specifed */
-	strcpy (remotepath,optarg);
-	rflg++;
-	break;
-      case 'p':				/* port number specified */
-	portarg = atoi (optarg);
-	break;
+		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 /* INTERNET_DOMAIN_SOCKETS */
-
-      case '?':
-	errflg++;
-      } /* switch */
+		default:
+		  errflg = 1;
+		}
+	    } /* for */
+	} /* else */
+    } /* for */
 
   if (errflg)
     {
       fprintf (stderr,
 #ifdef INTERNET_DOMAIN_SOCKETS
-	       "usage: %s [-q] [-h hostname] [-p port] [-r pathname] "
+	       "usage: %s [-nw] [-q] [-v] [-l library] [-f function] [-eval expr]\n"
+	       "       [-h host] [-p port] [-r file-name] [[+line] file] ...\n",
+#else /* !INTERNET_DOMAIN_SOCKETS */
+	       "usage: %s [-nw] [-q] [-v] [-l library] [-f function] [-eval expr] "
 	       "[[+line] path] ...\n",
-#else /* !INTERNET_DOMAIN_SOCKETS */
-	       "usage: %s [-nw] [-q] [[+line] path] ...\n",
 #endif /* !INTERNET_DOMAIN_SOCKETS */
 	       progname);
       exit (1);
-    } /* if */
-
-  if (suppress_windows_system)
+    }
+  if (batch && argv[i])
     {
-      tty = ttyname (0);
-      if (!tty)
-	{
-	  fprintf (stderr, "%s: Not connected to a tty", progname);
-	  exit (1);
-	}
-    }
-  /* This next stuff added in an attempt to make handling of the tty
-     do the right thing when dealing with signals.  The idea is to
-     pass all the appropriate signals to the emacs process. */
-
-  connect_type = make_connection (NULL, (u_short) 0, &s);
-
-  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 procces id\n",
+      fprintf (stderr, "%s: Cannot specify `-batch' with file names\n",
 	       progname);
       exit (1);
     }
-  /* Don't do disconnect_from_server becasue we have already read
-     data, and disconnect doesn't do anything else. */
-#ifdef SYSV_IPC
-  if (connect_type == (int) CONN_IPC)
-    disconnect_from_ipc_server (s, msgp, FALSE);
+  *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)
+	{
+	  sprintf (command, " (load-library %s)", clean_string (load_library));
+	  send_string (s, command);
+	}
+      if (eval_form)
+	{
+	  sprintf (command, " %s", eval_form);
+	  send_string (s, command);
+	}
+      if (eval_function)
+	{
+	  sprintf (command, " (%s)", eval_function);
+	  send_string (s, command);
+	}
+      send_string (s, "))");
+      send_string (s, EOT_STR);
+      if (read_line (s, result) == 0)
+	{
+	  fprintf (stderr, "%s: Could not read\n", progname);
+	  exit (1);
+	}
+    } /* eval_function || eval_form || load_library */
+  else if (batch)
+    {
+      fprintf (stderr, "%s: `-batch' requires an evaluation\n",
+	       progname);
+      exit (1);
+    }
+
+  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 procces id\n",
+		   progname);
+	  exit (1);
+	}
+      /* Don't do disconnect_from_server becasue we have already read
+	 data, and disconnect doesn't do anything else. */
+#ifndef INTERNET_DOMAIN_SOCKETS
+      if (connect_type == (int) CONN_IPC)
+	disconnect_from_ipc_server (s, msgp, FALSE);
 #endif /* !SYSV_IPC */
 
-  emacs_pid = (pid_t)atol(buffer);
-  initialize_signals();
+      emacs_pid = (pid_t)atol(buffer);
+      initialize_signals();
 
-#if defined(INTERNET_DOMAIN_SOCKETS) && !defined(GNUATTACH)
-  connect_type = make_connection (hostarg, portarg, &s);
+#if defined(INTERNET_DOMAIN_SOCKETS)
+      connect_type = make_connection (hostarg, port, &s);
 #else
-  connect_type = make_connection (NULL, (u_short) 0, &s);
+      connect_type = make_connection (NULL, (u_short) 0, &s);
 #endif
 
 #ifdef INTERNET_DOMAIN_SOCKETS
-  if (connect_type == (int) CONN_INTERNET)
-    {
-      gethostname (thishost, HOSTNAMSZ);
-      if (!rflg)
-	{				/* attempt to generate a path 
+      if (connect_type == (int) CONN_INTERNET)
+	{
+	  char *ptr;
+	  gethostname (thishost, HOSTNAMSZ);
+	  if (!rflg)
+	    {				/* attempt to generate a path 
 					 * to this machine */
-	  if ((ptr = getenv ("GNU_NODE")) != NULL)
-	    /* user specified a path */
-	    strcpy (remotepath, ptr);
-	}
+	      if ((ptr = getenv ("GNU_NODE")) != NULL)
+		/* user specified a path */
+		strcpy (remotepath, ptr);
+	    }
 #if 0  /* This is really bogus... re-enable it if you must have it! */
 #if defined (hp9000s300) || defined (hp9000s800)
-      else if (strcmp (thishost,hostarg))
-	{	/* try /net/thishost */
-	  strcpy (remotepath, "/net/");		/* (this fails using internet 
-						   addresses) */
-	  strcat (remotepath, thishost);
-	}
+	  else if (strcmp (thishost,hostarg))
+	    {	/* try /net/thishost */
+	      strcpy (remotepath, "/net/");		/* (this fails using internet 
+							   addresses) */
+	      strcat (remotepath, thishost);
+	    }
 #endif
 #endif
-    }
-  else
-    {					/* same machines, no need for path */
-      remotepath[0] = '\0';		/* default is the empty path */
-    }
+	}
+      else
+	{			/* same machines, no need for path */
+	  remotepath[0] = '\0';	/* default is the empty path */
+	}
 #endif /* INTERNET_DOMAIN_SOCKETS */
 
 #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);
-    } /* if */
+      if ((msgp = (struct msgbuf *) 
+	   malloc (sizeof *msgp + GSERV_BUFSZ)) == NULL)
+	{
+	  fprintf (stderr, "%s: not enough memory for message buffer\n", progname);
+	  exit (1);
+	} /* if */
 
-  msgp->mtext[0] = '\0';			/* ready for later strcats */
+      msgp->mtext[0] = '\0';			/* ready for later strcats */
 #endif /* SYSV_IPC */
 
-  if (suppress_windows_system)
-    {
-      ptr = getenv ("TERM");
-      if (!ptr)
+      if (suppress_windows_system)
 	{
-	  fprintf (stderr, "%s: unknown terminal type\n", progname);
-	  exit (1);
+	  char *term = getenv ("TERM");
+	  if (!term)
+	    {
+	      fprintf (stderr, "%s: unknown terminal type\n", progname);
+	      exit (1);
+	    }
+	  sprintf (command, "(gnuserv-edit-files '(tty %s %s %d) '(",
+		   clean_string (tty), clean_string (term), getpid ());
 	}
-      sprintf (command,
-	       "(gnuserv-edit-files '(tty \"%s\" \"%s\" %d) '(",
-	       tty, ptr, getpid ());
-    }
-  else /* !suppress_windows_system */
-    {
-      sprintf (command, "(gnuserv-edit-files '(x \"%s\") '(",
-	       display);
-    } /* !suppress_windows_system */
-  send_string (s, command);
+      else /* !suppress_windows_system */
+	{
+	  sprintf (command, "(gnuserv-edit-files '(x %s) '(",
+		   clean_string (display));
+	} /* !suppress_windows_system */
+      send_string (s, command);
 
-  if (!suppress_windows_system && (optind == argc))
-    qflg = 1;
+      if (!argv[i])
+	nofiles = 1;
 
-  for (; optind < argc; optind++)
-    {
-      if (optind < argc - 1 && *argv[optind] == '+')
-	starting_line = atoi (argv[optind++]);
-      else
-	starting_line = 1;
-      /* If the last argument is +something, treat it as a file. */
-      if (optind == argc)
+      for (; argv[i]; i++)
 	{
-	  starting_line = 1;
-	  --optind;
-	}
-      filename_expand (fullpath, argv[optind]);
-      sprintf (command, "(%d . \"%s%s\")", starting_line,
+	  if (i < argc - 1 && *argv[i] == '+')
+	    starting_line = atoi (argv[i++]);
+	  else
+	    starting_line = 1;
+	  /* If the last argument is +something, treat it as a file. */
+	  if (i == argc)
+	    {
+	      starting_line = 1;
+	      --i;
+	    }
+	  filename_expand (fullpath, argv[i]);
 #ifdef INTERNET_DOMAIN_SOCKETS
-	       remotepath,
-#else /* !INTERNET_DOMAIN_SOCKETS */
-	       "",
+	  path = malloc (strlen (remotepath) + strlen (fullpath) + 1);
+	  sprintf (path, "%s%s", remotepath, fullpath);
+#else
+	  path = malloc (strlen (fullpath));
+	  strcpy (path, fullpath);
 #endif
-	       fullpath);
+	  sprintf (command, "(%d . %s)", starting_line, clean_string (path));
+	  send_string (s, command);
+	  free (path);
+	} /* for */
+
+      sprintf (command, ")%s%s",
+	       (quick || (nofiles && !suppress_windows_system)) ? " 'quick" : "",
+	       view ? " 'view" : "");
       send_string (s, command);
-    } /* for */
-
-  sprintf (command, ") %s)", qflg ? "'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);
+      if (connect_type == (int) CONN_IPC)
+	disconnect_from_ipc_server (s, msgp, FALSE);
 #else /* !SYSV_IPC */
-  if (connect_type != (int) CONN_IPC)
-    disconnect_from_server (s, FALSE);
+      if (connect_type != (int) CONN_IPC)
+	disconnect_from_server (s, FALSE);
 #endif /* !SYSV_IPC */
+    } /* not batch */
+
+  if (batch && !quick)
+      printf ("%s\n", result);
 
   return 0;