bug-ed
[Top][All Lists]
Advanced

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

Patch for ex-style filter


From: Andrew L. Moore
Subject: Patch for ex-style filter
Date: Fri, 10 Nov 2006 00:47:59 -0800 (PST)

The previous patch for ex-style filter omitted read_stream_r ().
Hopefully the follow is more complete..
-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)
--- io.c.orig   2006-11-10 00:46:18.000000000 -0800
+++ io.c        2006-11-07 00:23:32.000000000 -0800
@@ -57,6 +57,24 @@
 }
 
 
+/* PUT_BUFFER_LINE: Add a line of text to the editor buffer. */
+#define PUT_BUFFER_LINE(tb, lp, up, current_addr, cleanup)                    \
+  do                                                                          \
+    {                                                                         \
+      SPL1 ();                                                                \
+      if (put_buffer_line ((tb)) == NULL)                                     \
+        {                                                                     \
+          SPL0 ();                                                            \
+          if ((cleanup)) clear_input_stack ();                                \
+          return ERR;                                                         \
+        }                                                                     \
+      (lp) = (lp)->q_forw;                                                    \
+      PUSH_UNDO ((lp), (up), (current_addr));                                 \
+      SPL0 ();                                                                \
+    }                                                                         \
+  while (0)
+
+
 int nl_added = 0;               /* if set, newline appended to input file */
 int buffer_empty = 1;           /* If set, buffer is `logically' empty. */
 int buffer_empty_prev = 1;
@@ -120,6 +138,105 @@
 }
 
 
+typedef char * input_t;
+
+#define INPUT_T_SIZE sizeof (input_t)
+
+static char *is_p = NULL;       /* (char *) input stack */
+static size_t is_size = 0;      /* input stack size */
+static size_t is_i = 0;         /* input stack index */
+
+
+/* read_stream_r: Read a stream into memory and then into editor
+   buffer after the given address; return bytes read. */
+int
+read_stream_r (fp, after, size)
+  FILE *fp;
+  size_t after;
+  off_t *size;
+{
+  line_t *lp;
+  undo_t *up = NULL;
+  input_t *is = (input_t *) is_p; /* input stack */
+  char *is_t = NULL;              /* input stack data */
+  char *tb;
+  size_t i = 0;
+  size_t is_t_size = 0;
+  size_t len = 0;
+  int nl_inserted = 0;
+  int nl_prev = nl_added;
+  int binary_prev = binary_data;
+  int stream_appended = after == addr_last;
+
+  /* Read stream into memory to avoid reentrant calls to buffer_file I/O. */
+  for (*size = 0, is = (input_t *) is_p, is_i = 0;
+       tb = get_stream_line (fp, &len);
+       ++is_i, *size += len)
+    {
+      if (is_i >= is_size / INPUT_T_SIZE)
+        {
+          REALLOC_THROW (is_p, is_size, ((off_t) is_i + 1) * INPUT_T_SIZE, 
ERR);
+          is = (input_t *) is_p;
+        }
+      is_t = NULL;
+      is_t_size = 0;
+      REALLOC_THROW (is_t, is_t_size, (off_t) len + 1, ERR);
+      memcpy (is_t, tb, len + 1);
+      *(is + is_i) = (input_t) is_t;
+    }
+  if (ferror (fp))
+    {
+      clearerr (fp);
+      clear_input_stack ();
+      return ERR;
+    }
+  else if (!feof (fp) && tb == NULL)
+    return ERR;
+
+  lp = get_addressed_line_node (after);
+  current_addr = after;
+  binary_data = nl_added = 0;
+  
+  /* Write memory to buffer_file. */
+  for (i = 0; i < is_i; ++i)
+    PUT_BUFFER_LINE (*(is + i), lp, up, current_addr, 1);
+  clear_input_stack ();
+
+  /* read_stream_r called only from filter_lines, so handle
+     buffer_empty in delete_lines. */
+  /*
+  buffer_empty_prev = buffer_empty;
+  buffer_empty = buffer_empty ? *size == nl_added : 0;
+  */
+
+  nl_inserted = stream_appended ? (nl_prev && binary_prev) : nl_added;
+  nl_added = stream_appended ? nl_added : nl_prev;
+
+  /* If binary, adjust size since appended newlines are not written. */
+  if ((binary_data |= binary_prev) && nl_added && stream_appended)
+    --*size;
+
+  if (nl_inserted && *size > 0)
+    puts (_("Newline inserted\n"));
+  else if (nl_added && !binary_data && (*size || buffer_empty))
+    puts (_("Newline appended\n"));
+
+  return 0;
+}
+
+
+/* clear_input_stack: Release memory allocated temporarily for reading input. 
*/
+void
+clear_input_stack ()
+{
+  input_t *is = (input_t *) is_p;
+  size_t i = 0;
+
+  while (i < is_i)
+    free ((char *) *(is + i++));
+}
+
+
 /* get_extended_line: Get an extended line from stdin;
    return pointer to static buffer. */
 char *




reply via email to

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