s/irrespective/regardless/

On Tue, Mar 27, 2012 at 12:57 PM, Sunil Nimmagadda <
[email protected]> wrote:

> This version implements some off-list review comments...
>
> 1. Discard explicit checking whether command exists and it's
> permissions since shell already does and reports error.
>
> 2. Remove unnecessary bzero call.
>
> 3. Document minor deviation from emacs behaviour in README.
>
> Index: README
> ===================================================================
> RCS file: /cvs/src/usr.bin/mg/README,v
> retrieving revision 1.8
> diff -u -p -r1.8 README
> --- README      1 Aug 2011 12:15:23 -0000       1.8
> +++ README      20 Mar 2012 17:54:12 -0000
> @@ -61,7 +61,9 @@ recognized as special cases.
>  On systems with 16 bit integers, the kill buffer cannot exceed 32767
>  bytes.
>
> -
> +Unlike GNU Emacs, Mg's minibuffer isn't multi-line aware and hence
> +some commands like "shell-command-on-region" always pop up a buffer to
> +display output irrespective of output's size.
>
>  New implementation oddities:
>
> Index: def.h
> ===================================================================
> RCS file: /cvs/src/usr.bin/mg/def.h,v
> retrieving revision 1.118
> diff -u -p -r1.118 def.h
> --- def.h       10 Dec 2011 14:09:48 -0000      1.118
> +++ def.h       16 Mar 2012 04:59:14 -0000
> @@ -567,6 +567,8 @@ int          prefixregion(int, int);
>  int             setprefix(int, int);
>  int             region_get_data(struct region *, char *, int);
>  void            region_put_data(const char *, int);
> +int             markbuffer(int, int);
> +int             piperegion(int, int);
>
>  /* search.c X */
>  int             forwsearch(int, int);
> Index: funmap.c
> ===================================================================
> RCS file: /cvs/src/usr.bin/mg/funmap.c,v
> retrieving revision 1.36
> diff -u -p -r1.36 funmap.c
> --- funmap.c    14 Mar 2012 13:56:35 -0000      1.36
> +++ funmap.c    16 Mar 2012 04:59:14 -0000
> @@ -113,6 +113,7 @@ static struct funmap functnames[] = {
>        {localbind, "local-set-key",},
>        {localunbind, "local-unset-key",},
>        {makebkfile, "make-backup-files",},
> +       {markbuffer, "mark-whole-buffer",},
>        {do_meta, "meta-key-mode",},    /* better name, anyone? */
>        {negative_argument, "negative-argument",},
>        {newline, "newline",},
> @@ -166,6 +167,7 @@ static struct funmap functnames[] = {
>        {setfillcol, "set-fill-column",},
>        {setmark, "set-mark-command",},
>        {setprefix, "set-prefix-string",},
> +       {piperegion, "shell-command-on-region",},
>        {shrinkwind, "shrink-window",},
>  #ifdef NOTAB
>        {space_to_tabstop, "space-to-tabstop",},
> Index: keymap.c
> ===================================================================
> RCS file: /cvs/src/usr.bin/mg/keymap.c,v
> retrieving revision 1.47
> diff -u -p -r1.47 keymap.c
> --- keymap.c    14 Mar 2012 13:56:35 -0000      1.47
> +++ keymap.c    16 Mar 2012 04:59:14 -0000
> @@ -135,7 +135,7 @@ static PF cXcar[] = {
>  #endif /* !NO_MACRO */
>        setfillcol,             /* f */
>        gotoline,               /* g */
> -       rescan,                 /* h */
> +       markbuffer,             /* h */
>        fileinsert,             /* i */
>        rescan,                 /* j */
>        killbuffer_cmd,         /* k */
> @@ -257,7 +257,7 @@ static PF metal[] = {
>        rescan,                 /* y */
>        rescan,                 /* z */
>        gotobop,                /* { */
> -       rescan,                 /* | */
> +       piperegion,             /* | */
>        gotoeop                 /* } */
>  };
>
> Index: mg.1
> ===================================================================
> RCS file: /cvs/src/usr.bin/mg/mg.1,v
> retrieving revision 1.58
> diff -u -p -r1.58 mg.1
> --- mg.1        9 Feb 2012 09:00:14 -0000       1.58
> +++ mg.1        16 Mar 2012 04:59:14 -0000
> @@ -196,6 +196,8 @@ call-last-kbd-macro
>  set-fill-column
>  .It C-x g
>  goto-line
> +.It C-x h
> +mark-whole-buffer
>  .It C-x i
>  insert-file
>  .It C-x k
> @@ -260,6 +262,8 @@ copy-region-as-kill
>  execute-extended-command
>  .It M-{
>  backward-paragraph
> +.It M-|
> +shell-command-on-region
>  .It M-}
>  forward-paragraph
>  .It M-~
> @@ -572,6 +576,9 @@ Bind a key mapping in the local (topmost
>  Unbind a key mapping in the local (topmost) mode.
>  .It make-backup-files
>  Toggle generation of backup files.
> +.It mark-whole-buffer
> +Marks whole buffer as a region by putting dot at the beginning and mark
> +at the end of buffer.
>  .It meta-key-mode
>  When disabled, the meta key can be used to insert extended-ascii (8-bit)
>  characters.
> @@ -734,6 +741,8 @@ Used by auto-fill-mode.
>  Sets the mark in the current window to the current dot location.
>  .It set-prefix-string
>  Sets the prefix string to be used by the 'prefix-region' command.
> +.It shell-command-on-region
> +Provide the text in region to the shell command as input.
>  .It shrink-window
>  Shrink current window by one line.
>  The window immediately below is expanded to pick up the slack.
> Index: region.c
> ===================================================================
> RCS file: /cvs/src/usr.bin/mg/region.c,v
> retrieving revision 1.29
> diff -u -p -r1.29 region.c
> --- region.c    5 Jun 2009 18:02:06 -0000       1.29
> +++ region.c    21 Mar 2012 17:45:24 -0000
> @@ -9,9 +9,25 @@
>   * internal use.
>  */
>
> +#include <sys/types.h>
> +#include <sys/socket.h>
> +
> +#include <poll.h>
> +#include <string.h>
> +#include <unistd.h>
> +
>  #include "def.h"
>
> +#define TIMEOUT 10000
> +
> +static char leftover[BUFSIZ];
> +
> +static  char    *get_line(struct line *, int *);
>  static int     getregion(struct region *);
> +static  int    iomux(int);
> +static  int    pipeio(const char *);
> +static  int     preadin(int,struct buffer *);
> +static  void    pwriteout(int,struct region *);
>  static int     setsize(struct region *, RSIZE);
>
>  /*
> @@ -366,4 +382,228 @@ region_put_data(const char *buf, int len
>                 else
>                        linsert(1, buf[i]);
>        }
> +}
> +
> +/*
> + * Mark whole buffer by first traversing to end-of-buffer
> + * and then to beginning-of-buffer. Mark, dot are implicitly
> + * set to eob, bob respectively during traversal.
> + */
> +int
> +markbuffer(int f, int n)
> +{
> +       if (gotoeob(f,n) == FALSE)
> +               return (FALSE);
> +       if (gotobob(f,n) == FALSE)
> +               return (FALSE);
> +       return (TRUE);
> +}
> +
> +/*
> + * Pipe text from current region to external command.
> + */
> +/*ARGSUSED */
> +int
> +piperegion(int f, int n)
> +{
> +       char *cmd, cmdbuf[NFILEN];
> +
> +       /* C-u M-| is not supported yet */
> +       if (n > 1)
> +               return (ABORT);
> +
> +       if (curwp->w_markp == NULL) {
> +               ewprintf("The mark is not set now, so there is no region");
> +               return (FALSE);
> +       }
> +       if ((cmd = eread("Shell command on region: ", cmdbuf,
> sizeof(cmdbuf),
> +           EFNEW | EFCR)) == NULL)
> +               return (FALSE);
> +       else if (cmd[0] == '\0')
> +               return (ABORT);
> +       return (pipeio(cmdbuf));
> +}
> +
> +/*
> + * Create a socketpair, fork and execl cmd passed. STDIN, STDOUT
> + * and STDERR of child process are redirected to socket.
> + */
> +int
> +pipeio(const char* const cmd)
> +{
> +       int s[2];
> +       char *shellp;
> +
> +       if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, s) == -1) {
> +               ewprintf("socketpair error");
> +               return (FALSE);
> +       }
> +       switch(fork()) {
> +       case -1:
> +               ewprintf("Can't fork");
> +               return (FALSE);
> +       case 0:
> +               /* Child process */
> +               close(s[0]);
> +               if (dup2(s[1], STDIN_FILENO) == -1)
> +                       _exit(1);
> +               if (dup2(s[1], STDOUT_FILENO) == -1)
> +                       _exit(1);
> +               if (dup2(s[1], STDERR_FILENO) == -1)
> +                       _exit(1);
> +               if ((shellp = getenv("SHELL")) == NULL)
> +                       _exit(1);
> +               execl(shellp, "sh", "-c", cmd, (char *)NULL);
> +               _exit(1);
> +       default:
> +               /* Parent process */
> +               close(s[1]);
> +               return iomux(s[0]);
> +       }
> +       return (FALSE);
> +}
> +
> +/*
> + * Multiplex read, write on socket fd passed. First get the region,
> + * find/create *Shell Command Output* buffer and clear it's contents.
> + * Poll on the fd for both read and write readiness.
> + */
> +int
> +iomux(int fd)
> +{
> +       struct region region;
> +       struct buffer *bp;
> +       struct pollfd pfd[1];
> +       int nfds;
> +
> +       if (getregion(&region) != TRUE)
> +               return (FALSE);
> +
> +       /* There is nothing to write if r_size is zero
> +        * but the cmd's output should be read so shutdown
> +        * the socket for writing only.
> +        */
> +       if (region.r_size == 0)
> +               shutdown(fd, SHUT_WR);
> +
> +       bp = bfind("*Shell Command Output*", TRUE);
> +       bp->b_flag |= BFREADONLY;
> +       if (bclear(bp) != TRUE)
> +               return (FALSE);
> +
> +       pfd[0].fd = fd;
> +       pfd[0].events = POLLIN | POLLOUT;
> +       while ((nfds = poll(pfd, 1, TIMEOUT)) != -1 ||
> +           (pfd[0].revents & (POLLERR | POLLHUP | POLLNVAL))) {
> +               if (pfd[0].revents & POLLOUT && region.r_size > 0) {
> +                       pwriteout(fd, &region);
> +                       region.r_linep = lforw(region.r_linep);
> +               } else if (pfd[0].revents & POLLIN)
> +                       if (preadin(fd, bp) == FALSE)
> +                               break;
> +       }
> +       close(fd);
> +       /* In case if last line doesn't have a '\n' add the leftover
> +        * characters to buffer.
> +        */
> +       if (leftover[0] != '\0')
> +               addline(bp, leftover);
> +       if (nfds == 0) {
> +               ewprintf("poll timed out");
> +               return (FALSE);
> +       } else if (nfds == -1) {
> +               ewprintf("poll error");
> +               return (FALSE);
> +       }
> +       return (popbuftop(bp, WNONE));
> +}
> +
> +/*
> + * Write each line from region to fd. Once done shutdown the
> + * write end.
> + */
> +void
> +pwriteout(int fd, struct region *region)
> +{
> +       struct line *linep;
> +       int len, loffs;
> +       char *l;
> +
> +       linep = region->r_linep;
> +       loffs = region->r_offset;
> +       /* Reset the offset, needed only for first line of region. */
> +       region->r_offset = 0;
> +       if ((l = get_line(linep, &len)) == NULL)
> +               return;
> +       /* Take care of region's offset on first and last line */
> +       len -= loffs;
> +       len = (len  < region->r_size) ? len : region->r_size;
> +       if ((send(fd, l + loffs, len, MSG_NOSIGNAL) == -1)
> +           && (errno == EPIPE))
> +               region->r_size = -1;
> +       else
> +               region->r_size -= len;
> +       if (region->r_size <= 0)
> +               shutdown(fd, SHUT_WR);
> +       free(l);
> +}
> +
> +/*
> + * Since struct line doesn't have a terminating '\n',
> + * make a copy and append '\n'.
> + */
> +char *
> +get_line(struct line *ln, int *lenp)
> +{
> +       int      len;
> +       char    *line;
> +
> +       len = llength(ln);
> +       if (len == INT_MAX)
> +               return (NULL);
> +
> +       if ((line = malloc(len + 1)) == NULL)
> +               return (NULL);
> +
> +       (void)memmove(line, ltext(ln), len);
> +       line[len] = '\n';
> +       *lenp = len + 1;
> +       return (line);
> +}
> +
> +/*
> + * Read some data from socket fd, break on '\n' and add
> + * to buffer. If couldn't break on newline hold leftover
> + * characters and append in next iteration.
> + */
> +int
> +preadin(int fd, struct buffer *bp)
> +{
> +       int len;
> +       char buf[BUFSIZ], *p, *q;
> +
> +       if ((len = read(fd, buf, BUFSIZ - 1)) == 0)
> +               return (FALSE);
> +       buf[len] = '\0';
> +       p = q = buf;
> +       if (leftover[0] != '\0' && ((q = strchr(p, '\n')) != NULL)) {
> +               *q++ = '\0';
> +               if (strlcat(leftover, p, sizeof(leftover)) >=
> sizeof(leftover)) {
> +                       ewprintf("line too long");
> +                       return (FALSE);
> +               }
> +               addline(bp, leftover);
> +               leftover[0] = '\0';
> +               p = q;
> +       }
> +       while ((q = strchr(p, '\n')) != NULL) {
> +               *q++ = '\0';
> +               addline(bp, p);
> +               p = q;
> +       }
> +       if (strlcpy(leftover, p, sizeof(leftover)) >= sizeof(leftover)) {
> +               ewprintf("line too long");
> +               return (FALSE);
> +       }
> +       return (TRUE);
>  }

Reply via email to