X-Git-Url: https://pd.if.org/git/?p=pd_readline;a=blobdiff_plain;f=mg%2Fregion.c;fp=mg%2Fregion.c;h=0000000000000000000000000000000000000000;hp=baca932ca1fe01717a9a765df52ef6ec9d1c771e;hb=4bb27266f935c9aafad6870ffc8847fc65c8120f;hpb=3f771e17236364ded86e96ee64f99344337991f8 diff --git a/mg/region.c b/mg/region.c deleted file mode 100644 index baca932..0000000 --- a/mg/region.c +++ /dev/null @@ -1,597 +0,0 @@ -/* $OpenBSD: region.c,v 1.30 2012/04/11 17:51:10 lum Exp $ */ - -/* This file is in the public domain. */ - -/* - * Region based commands. - * The routines in this file deal with the region, that magic space between - * "." and mark. Some functions are commands. Some functions are just for - * internal use. - */ - -#include -#include - -#include -#include -#include -#include - -#include "def.h" - -#define TIMEOUT 10000 - -static char leftover[BUFSIZ]; - -static int getregion(struct region *); -static int iomux(int); -static int pipeio(const char *); -static int preadin(int, struct buffer *); -static void pwriteout(int, char **, int *); -static int setsize(struct region *, RSIZE); - -/* - * Kill the region. Ask "getregion" to figure out the bounds of the region. - * Move "." to the start, and kill the characters. Mark is cleared afterwards. - */ -/* ARGSUSED */ -int -killregion(int f, int n) -{ - int s; - struct region region; - - if ((s = getregion(®ion)) != TRUE) - return (s); - /* This is a kill-type command, so do magic kill buffer stuff. */ - if ((lastflag & CFKILL) == 0) - kdelete(); - thisflag |= CFKILL; - curwp->w_dotp = region.r_linep; - curwp->w_doto = region.r_offset; - curwp->w_dotline = region.r_lineno; - s = ldelete(region.r_size, KFORW | KREG); - clearmark(FFARG, 0); - - return (s); -} - -/* - * Copy all of the characters in the region to the kill buffer, - * clearing the mark afterwards. - * This is a bit like a kill region followed by a yank. - */ -/* ARGSUSED */ -int -copyregion(int f, int n) -{ - struct line *linep; - struct region region; - int loffs; - int s; - - if ((s = getregion(®ion)) != TRUE) - return (s); - - /* kill type command */ - if ((lastflag & CFKILL) == 0) - kdelete(); - thisflag |= CFKILL; - - /* current line */ - linep = region.r_linep; - - /* current offset */ - loffs = region.r_offset; - - while (region.r_size--) { - if (loffs == llength(linep)) { /* End of line. */ - if ((s = kinsert('\n', KFORW)) != TRUE) - return (s); - linep = lforw(linep); - loffs = 0; - } else { /* Middle of line. */ - if ((s = kinsert(lgetc(linep, loffs), KFORW)) != TRUE) - return (s); - ++loffs; - } - } - clearmark(FFARG, 0); - - return (TRUE); -} - -/* - * Lower case region. Zap all of the upper case characters in the region to - * lower case. Use the region code to set the limits. Scan the buffer, doing - * the changes. Call "lchange" to ensure that redisplay is done in all - * buffers. - */ -/* ARGSUSED */ -int -lowerregion(int f, int n) -{ - struct line *linep; - struct region region; - int loffs, c, s; - - if ((s = checkdirty(curbp)) != TRUE) - return (s); - if (curbp->b_flag & BFREADONLY) { - ewprintf("Buffer is read-only"); - return (FALSE); - } - - if ((s = getregion(®ion)) != TRUE) - return (s); - - undo_add_change(region.r_linep, region.r_offset, region.r_size); - - lchange(WFFULL); - linep = region.r_linep; - loffs = region.r_offset; - while (region.r_size--) { - if (loffs == llength(linep)) { - linep = lforw(linep); - loffs = 0; - } else { - c = lgetc(linep, loffs); - if (ISUPPER(c) != FALSE) - lputc(linep, loffs, TOLOWER(c)); - ++loffs; - } - } - return (TRUE); -} - -/* - * Upper case region. Zap all of the lower case characters in the region to - * upper case. Use the region code to set the limits. Scan the buffer, - * doing the changes. Call "lchange" to ensure that redisplay is done in all - * buffers. - */ -/* ARGSUSED */ -int -upperregion(int f, int n) -{ - struct line *linep; - struct region region; - int loffs, c, s; - - if ((s = checkdirty(curbp)) != TRUE) - return (s); - if (curbp->b_flag & BFREADONLY) { - ewprintf("Buffer is read-only"); - return (FALSE); - } - if ((s = getregion(®ion)) != TRUE) - return (s); - - undo_add_change(region.r_linep, region.r_offset, region.r_size); - - lchange(WFFULL); - linep = region.r_linep; - loffs = region.r_offset; - while (region.r_size--) { - if (loffs == llength(linep)) { - linep = lforw(linep); - loffs = 0; - } else { - c = lgetc(linep, loffs); - if (ISLOWER(c) != FALSE) - lputc(linep, loffs, TOUPPER(c)); - ++loffs; - } - } - return (TRUE); -} - -/* - * This routine figures out the bound of the region in the current window, - * and stores the results into the fields of the REGION structure. Dot and - * mark are usually close together, but I don't know the order, so I scan - * outward from dot, in both directions, looking for mark. The size is kept - * in a long. At the end, after the size is figured out, it is assigned to - * the size field of the region structure. If this assignment loses any bits, - * then we print an error. This is "type independent" overflow checking. All - * of the callers of this routine should be ready to get an ABORT status, - * because I might add a "if regions is big, ask before clobbering" flag. - */ -static int -getregion(struct region *rp) -{ - struct line *flp, *blp; - long fsize, bsize; - - if (curwp->w_markp == NULL) { - ewprintf("No mark set in this window"); - return (FALSE); - } - - /* "r_size" always ok */ - if (curwp->w_dotp == curwp->w_markp) { - rp->r_linep = curwp->w_dotp; - rp->r_lineno = curwp->w_dotline; - if (curwp->w_doto < curwp->w_marko) { - rp->r_offset = curwp->w_doto; - rp->r_size = (RSIZE)(curwp->w_marko - curwp->w_doto); - } else { - rp->r_offset = curwp->w_marko; - rp->r_size = (RSIZE)(curwp->w_doto - curwp->w_marko); - } - return (TRUE); - } - /* get region size */ - flp = blp = curwp->w_dotp; - bsize = curwp->w_doto; - fsize = llength(flp) - curwp->w_doto + 1; - while (lforw(flp) != curbp->b_headp || lback(blp) != curbp->b_headp) { - if (lforw(flp) != curbp->b_headp) { - flp = lforw(flp); - if (flp == curwp->w_markp) { - rp->r_linep = curwp->w_dotp; - rp->r_offset = curwp->w_doto; - rp->r_lineno = curwp->w_dotline; - return (setsize(rp, - (RSIZE)(fsize + curwp->w_marko))); - } - fsize += llength(flp) + 1; - } - if (lback(blp) != curbp->b_headp) { - blp = lback(blp); - bsize += llength(blp) + 1; - if (blp == curwp->w_markp) { - rp->r_linep = blp; - rp->r_offset = curwp->w_marko; - rp->r_lineno = curwp->w_markline; - return (setsize(rp, - (RSIZE)(bsize - curwp->w_marko))); - } - } - } - ewprintf("Bug: lost mark"); - return (FALSE); -} - -/* - * Set size, and check for overflow. - */ -static int -setsize(struct region *rp, RSIZE size) -{ - rp->r_size = size; - if (rp->r_size != size) { - ewprintf("Region is too large"); - return (FALSE); - } - return (TRUE); -} - -#define PREFIXLENGTH 40 -static char prefix_string[PREFIXLENGTH] = {'>', '\0'}; - -/* - * Prefix the region with whatever is in prefix_string. Leaves dot at the - * beginning of the line after the end of the region. If an argument is - * given, prompts for the line prefix string. - */ -/* ARGSUSED */ -int -prefixregion(int f, int n) -{ - struct line *first, *last; - struct region region; - char *prefix = prefix_string; - int nline; - int s; - - if ((s = checkdirty(curbp)) != TRUE) - return (s); - if (curbp->b_flag & BFREADONLY) { - ewprintf("Buffer is read-only"); - return (FALSE); - } - if ((f == TRUE) && ((s = setprefix(FFRAND, 1)) != TRUE)) - return (s); - - /* get # of lines to affect */ - if ((s = getregion(®ion)) != TRUE) - return (s); - first = region.r_linep; - last = (first == curwp->w_dotp) ? curwp->w_markp : curwp->w_dotp; - for (nline = 1; first != last; nline++) - first = lforw(first); - - /* move to beginning of region */ - curwp->w_dotp = region.r_linep; - curwp->w_doto = region.r_offset; - curwp->w_dotline = region.r_lineno; - - /* for each line, go to beginning and insert the prefix string */ - while (nline--) { - (void)gotobol(FFRAND, 1); - for (prefix = prefix_string; *prefix; prefix++) - (void)linsert(1, *prefix); - (void)forwline(FFRAND, 1); - } - (void)gotobol(FFRAND, 1); - return (TRUE); -} - -/* - * Set line prefix string. Used by prefixregion. - */ -/* ARGSUSED */ -int -setprefix(int f, int n) -{ - char buf[PREFIXLENGTH], *rep; - int retval; - - if (prefix_string[0] == '\0') - rep = eread("Prefix string: ", buf, sizeof(buf), - EFNEW | EFCR); - else - rep = eread("Prefix string (default %s): ", buf, sizeof(buf), - EFNUL | EFNEW | EFCR, prefix_string); - if (rep == NULL) - return (ABORT); - if (rep[0] != '\0') { - (void)strlcpy(prefix_string, rep, sizeof(prefix_string)); - retval = TRUE; - } else if (rep[0] == '\0' && prefix_string[0] != '\0') { - /* CR -- use old one */ - retval = TRUE; - } else - retval = FALSE; - return (retval); -} - -int -region_get_data(struct region *reg, char *buf, int len) -{ - int i, off; - struct line *lp; - - off = reg->r_offset; - lp = reg->r_linep; - for (i = 0; i < len; i++) { - if (off == llength(lp)) { - lp = lforw(lp); - if (lp == curbp->b_headp) - break; - off = 0; - buf[i] = '\n'; - } else { - buf[i] = lgetc(lp, off); - off++; - } - } - buf[i] = '\0'; - return (i); -} - -void -region_put_data(const char *buf, int len) -{ - int i; - - for (i = 0; buf[i] != '\0' && i < len; i++) { - if (buf[i] == '\n') - lnewline(); - 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 || (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; - char *text, *textcopy; - - if (getregion(®ion) != TRUE) - return (FALSE); - - if ((text = malloc(region.r_size + 1)) == NULL) - return (ABORT); - - region_get_data(®ion, text, region.r_size); - textcopy = text; - fcntl(fd, F_SETFL, O_NONBLOCK); - - /* 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, &textcopy, ®ion.r_size); - else if (pfd[0].revents & POLLIN) - if (preadin(fd, bp) == FALSE) - break; - } - close(fd); - free(text); - /* In case if last line doesn't have a '\n' add the leftover - * characters to buffer. - */ - if (leftover[0] != '\0') { - addline(bp, leftover); - leftover[0] = '\0'; - } - if (nfds == 0) { - ewprintf("poll timed out"); - return (FALSE); - } else if (nfds == -1) { - ewprintf("poll error"); - return (FALSE); - } - return (popbuftop(bp, WNONE)); -} - -/* - * Write some text from region to fd. Once done shutdown the - * write end. - */ -void -pwriteout(int fd, char **text, int *len) -{ - int w; - - if (((w = send(fd, *text, *len, MSG_NOSIGNAL)) == -1)) { - switch(errno) { - case EPIPE: - *len = -1; - break; - case EAGAIN: - return; - } - } else - *len -= w; - - *text += w; - if (*len <= 0) - shutdown(fd, SHUT_WR); -} - -/* - * 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; - static int nooutput; - char buf[BUFSIZ], *p, *q; - - if ((len = read(fd, buf, BUFSIZ - 1)) == 0) { - if (nooutput == 0) - addline(bp, "(Shell command succeeded with no output)"); - nooutput = 0; - return (FALSE); - } - nooutput = 1; - 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); -}