[Top][All Lists]
[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 *