bug-ed
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: ed proposal - multiple files on command line


From: Andrew L. Moore
Subject: Re: ed proposal - multiple files on command line
Date: Fri, 10 Nov 2006 00:27:09 -0800 (PST)

The follow patch that adds ex-style `!' to ed.  It needs to be
applied manually.
-AM

--- exec.c.orig 2006-11-10 00:11:15.000000000 -0800
+++ exec.c      2006-11-10 00:10:53.000000000 -0800
@@ -638,6 +638,33 @@
       GET_COMMAND_SUFFIX ();
       printf ("%lu\n", addr_cnt ? second_addr : addr_last);
       break;
+    case '!':
+       if (addr_cnt > 0
+           && (status = check_addr_range (current_addr, current_addr)) < 0)
+         return status;
+      --cb_p;
+      GET_FILE_NAME (fn, len);
+      if (addr_cnt == 0)
+        {
+          system (++fn);
+          puts ("!");
+        }
+      else
+        {
+#if !HAVE_FORK
+          err_msg = _("Address not allowed");
+          return ERR;
+#else
+          if (!global_state)
+            clear_undo_stack ();
+          addr = addr_last;
+          if ((status = filter_lines (first_addr, second_addr, ++fn)) < 0
+              ||  (status = delete_lines (first_addr, second_addr)) < 0)
+            return status;
+          current_addr = second_addr + addr_last - addr;
+#endif /* HAVE_FORK */
+        }
+      return 0;
     case '\n':
       if ((status = check_addr_range
            (first_addr = 1,
--- cmds.c.orig 2006-11-10 00:09:13.000000000 -0800
+++ cmds.c      2006-11-07 00:17:38.000000000 -0800
@@ -20,6 +20,17 @@
 
 #include "ed.h"
 
+#if HAVE_SYS_WAIT_H
+# include <sys/wait.h>
+#endif
+
+#ifndef WIFEXITED
+# define WIFEXITED(status) (((status) & 0xff) == 0)
+#endif
+
+#ifndef WEXITSTATUS
+# define WEXITSTATUS(status) ((unsigned)(status) >> 8)
+#endif
 
 /* append_lines: Insert text from stdin to after given address; stop
    when either a single period is read or EOF; return status. */
@@ -182,6 +193,145 @@
 }
 
 
+#if HAVE_FORK
+# define WAITPID(pid)                                                         \
+  do                                                                          \
+    {                                                                         \
+      waitpid(pid, &status, 0);                                               \
+      if (!status && WIFEXITED(status) && WEXITSTATUS(status) == 127)         \
+        {                                                                     \
+          err_msg = _("Process error waiting for child exit");                \
+          status = ERR;                                                       \
+      }                                                                       \
+    }                                                                         \
+  while (0)
+
+
+/* filter_lines: Filter a range of lines through a shell command;
+   return status. */
+int
+filter_lines (from, to, sc)
+     size_t from;
+     size_t to;
+     const char *sc;
+{
+  FILE *ipp, *opp;
+  pid_t shell_pid, write_pid;
+  off_t size = 0;
+  int ip[2], op[2];
+  int status = 0;
+
+  /* Flush any buffered I/O. */
+  fflush (NULL);
+
+  /* Create two pipes: one for writing to the shell command and
+     another for reading from it.  */
+  if (pipe (ip) < 0 || pipe (op) < 0)
+    {
+      fprintf (stderr, "%s\n", strerror (errno));
+      err_msg = _("Pipe create error");
+      return ERR;
+    }
+
+  /* Disable SIGINT in the parent while shell command executes. */
+  reliable_signal (SIGINT, SIG_IGN);
+
+  /* Create first child process for shell command. */
+  switch (shell_pid = fork ())
+    {
+    case -1:
+      fprintf (stderr, "%s\n", strerror (errno));
+      err_msg = _("Fork error");
+      close (ip[0]), close (ip[1]);
+      close (op[0]), close (op[1]);
+      reliable_signal (SIGINT, signal_int);
+      return ERR;
+    case 0:
+      /* Reset signals for shell. */
+      signal (SIGINT, SIG_DFL);
+      signal (SIGQUIT, SIG_DFL);
+
+      /* Redirect read/write pipes to command's standard I/O.  Close
+         write end of pipe ip, ip[1], so that EOF is seen.  Execute
+         shell command. */
+      if (dup2 (ip[0], 0) < 0 || dup2 (op[1], 1) < 0 || dup2 (op[1], 2) < 0
+          || close (ip[0]) < 0 || close (ip[1]) < 0
+          || close (op[0]) < 0 || close (op[1]) < 0
+          || execl ("/bin/sh", "sh", "-c", sc, (char *) NULL))
+        {
+          fprintf (stderr, "%s\n", strerror (errno));
+          _exit (127);
+        }
+
+      /* NOTREACHED */
+    }
+
+  /* Close write end of pipe op, op[1], so that EOF is seen. */
+  close (op[1]);
+
+  /* Create second child process for writing to shell command. */
+  switch (write_pid = fork ())
+    {
+    case -1:
+      fprintf (stderr, "%s\n", strerror (errno));
+      err_msg = _("Fork error");
+      close (ip[1]);
+      close (op[0]);
+      status = ERR;
+      goto err;
+    case 0:
+
+      /* Close unused pipe ends. */
+      close (ip[0]);
+      close (op[0]);
+
+      /* Open shell command input for writing.  Write to shell
+         process. */
+      if (!(ipp = fdopen (ip[1], "w"))
+          || ((status = write_stream (ipp, from, to, &size)) >= 0
+              && (status = fclose (ipp)) < 0))
+        {
+          fprintf (stderr, "%s\n", strerror (errno));
+          status = ERR;
+        }
+
+      /* Avoid exit (3). */
+      _exit (status < 0 ? 127 << 8: 0);
+    }
+
+  /* Close unused pipe ends. */
+  close (ip[0]), close (ip[1]);
+
+  /* NB: To initiate reading shell command output in a child process,
+     vfork would be necessary for in-core buffer access. */
+  
+  /* Open shell command output for reading. */
+  if (!(opp = fdopen (op[0], "r")))
+    {
+      fprintf (stderr, "%s\n", strerror (errno));
+      err_msg = _("Pipe open error");
+      status = ERR;
+    }
+
+  /* Read shell command output via reentrant version of read_stream. */
+  else if ((status = read_stream_r (opp, to, &size)) >= 0
+           && (status = fclose (opp)) < 0)
+    {
+      fprintf (stderr, "%s\n", strerror (errno));
+      err_msg = _("Pipe close error");
+      status = ERR;
+    }
+  printf (!scripted ? "%lld\n" : "", size);
+
+  WAITPID (write_pid);
+
+ err:
+  WAITPID (shell_pid);
+  reliable_signal (SIGINT, signal_int);
+  return status;
+}
+#endif /* HAVE_FORK */
+
 /* join_lines: Replace a range of lines with the joined text of those lines. */
 int
 join_lines (from, to)




reply via email to

[Prev in Thread] Current Thread [Next in Thread]