1 /* $OpenBSD: region.c,v 1.30 2012/04/11 17:51:10 lum Exp $ */
3 /* This file is in the public domain. */
6 * Region based commands.
7 * The routines in this file deal with the region, that magic space between
8 * "." and mark. Some functions are commands. Some functions are just for
12 #include <sys/types.h>
13 #include <sys/socket.h>
24 static char leftover[BUFSIZ];
26 static int getregion(struct region *);
27 static int iomux(int);
28 static int pipeio(const char *);
29 static int preadin(int, struct buffer *);
30 static void pwriteout(int, char **, int *);
31 static int setsize(struct region *, RSIZE);
34 * Kill the region. Ask "getregion" to figure out the bounds of the region.
35 * Move "." to the start, and kill the characters. Mark is cleared afterwards.
39 killregion(int f, int n)
44 if ((s = getregion(®ion)) != TRUE)
46 /* This is a kill-type command, so do magic kill buffer stuff. */
47 if ((lastflag & CFKILL) == 0)
50 curwp->w_dotp = region.r_linep;
51 curwp->w_doto = region.r_offset;
52 curwp->w_dotline = region.r_lineno;
53 s = ldelete(region.r_size, KFORW | KREG);
60 * Copy all of the characters in the region to the kill buffer,
61 * clearing the mark afterwards.
62 * This is a bit like a kill region followed by a yank.
66 copyregion(int f, int n)
73 if ((s = getregion(®ion)) != TRUE)
76 /* kill type command */
77 if ((lastflag & CFKILL) == 0)
82 linep = region.r_linep;
85 loffs = region.r_offset;
87 while (region.r_size--) {
88 if (loffs == llength(linep)) { /* End of line. */
89 if ((s = kinsert('\n', KFORW)) != TRUE)
93 } else { /* Middle of line. */
94 if ((s = kinsert(lgetc(linep, loffs), KFORW)) != TRUE)
105 * Lower case region. Zap all of the upper case characters in the region to
106 * lower case. Use the region code to set the limits. Scan the buffer, doing
107 * the changes. Call "lchange" to ensure that redisplay is done in all
112 lowerregion(int f, int n)
115 struct region region;
118 if ((s = checkdirty(curbp)) != TRUE)
120 if (curbp->b_flag & BFREADONLY) {
121 ewprintf("Buffer is read-only");
125 if ((s = getregion(®ion)) != TRUE)
128 undo_add_change(region.r_linep, region.r_offset, region.r_size);
131 linep = region.r_linep;
132 loffs = region.r_offset;
133 while (region.r_size--) {
134 if (loffs == llength(linep)) {
135 linep = lforw(linep);
138 c = lgetc(linep, loffs);
139 if (ISUPPER(c) != FALSE)
140 lputc(linep, loffs, TOLOWER(c));
148 * Upper case region. Zap all of the lower case characters in the region to
149 * upper case. Use the region code to set the limits. Scan the buffer,
150 * doing the changes. Call "lchange" to ensure that redisplay is done in all
155 upperregion(int f, int n)
158 struct region region;
161 if ((s = checkdirty(curbp)) != TRUE)
163 if (curbp->b_flag & BFREADONLY) {
164 ewprintf("Buffer is read-only");
167 if ((s = getregion(®ion)) != TRUE)
170 undo_add_change(region.r_linep, region.r_offset, region.r_size);
173 linep = region.r_linep;
174 loffs = region.r_offset;
175 while (region.r_size--) {
176 if (loffs == llength(linep)) {
177 linep = lforw(linep);
180 c = lgetc(linep, loffs);
181 if (ISLOWER(c) != FALSE)
182 lputc(linep, loffs, TOUPPER(c));
190 * This routine figures out the bound of the region in the current window,
191 * and stores the results into the fields of the REGION structure. Dot and
192 * mark are usually close together, but I don't know the order, so I scan
193 * outward from dot, in both directions, looking for mark. The size is kept
194 * in a long. At the end, after the size is figured out, it is assigned to
195 * the size field of the region structure. If this assignment loses any bits,
196 * then we print an error. This is "type independent" overflow checking. All
197 * of the callers of this routine should be ready to get an ABORT status,
198 * because I might add a "if regions is big, ask before clobbering" flag.
201 getregion(struct region *rp)
203 struct line *flp, *blp;
206 if (curwp->w_markp == NULL) {
207 ewprintf("No mark set in this window");
211 /* "r_size" always ok */
212 if (curwp->w_dotp == curwp->w_markp) {
213 rp->r_linep = curwp->w_dotp;
214 rp->r_lineno = curwp->w_dotline;
215 if (curwp->w_doto < curwp->w_marko) {
216 rp->r_offset = curwp->w_doto;
217 rp->r_size = (RSIZE)(curwp->w_marko - curwp->w_doto);
219 rp->r_offset = curwp->w_marko;
220 rp->r_size = (RSIZE)(curwp->w_doto - curwp->w_marko);
224 /* get region size */
225 flp = blp = curwp->w_dotp;
226 bsize = curwp->w_doto;
227 fsize = llength(flp) - curwp->w_doto + 1;
228 while (lforw(flp) != curbp->b_headp || lback(blp) != curbp->b_headp) {
229 if (lforw(flp) != curbp->b_headp) {
231 if (flp == curwp->w_markp) {
232 rp->r_linep = curwp->w_dotp;
233 rp->r_offset = curwp->w_doto;
234 rp->r_lineno = curwp->w_dotline;
236 (RSIZE)(fsize + curwp->w_marko)));
238 fsize += llength(flp) + 1;
240 if (lback(blp) != curbp->b_headp) {
242 bsize += llength(blp) + 1;
243 if (blp == curwp->w_markp) {
245 rp->r_offset = curwp->w_marko;
246 rp->r_lineno = curwp->w_markline;
248 (RSIZE)(bsize - curwp->w_marko)));
252 ewprintf("Bug: lost mark");
257 * Set size, and check for overflow.
260 setsize(struct region *rp, RSIZE size)
263 if (rp->r_size != size) {
264 ewprintf("Region is too large");
270 #define PREFIXLENGTH 40
271 static char prefix_string[PREFIXLENGTH] = {'>', '\0'};
274 * Prefix the region with whatever is in prefix_string. Leaves dot at the
275 * beginning of the line after the end of the region. If an argument is
276 * given, prompts for the line prefix string.
280 prefixregion(int f, int n)
282 struct line *first, *last;
283 struct region region;
284 char *prefix = prefix_string;
288 if ((s = checkdirty(curbp)) != TRUE)
290 if (curbp->b_flag & BFREADONLY) {
291 ewprintf("Buffer is read-only");
294 if ((f == TRUE) && ((s = setprefix(FFRAND, 1)) != TRUE))
297 /* get # of lines to affect */
298 if ((s = getregion(®ion)) != TRUE)
300 first = region.r_linep;
301 last = (first == curwp->w_dotp) ? curwp->w_markp : curwp->w_dotp;
302 for (nline = 1; first != last; nline++)
303 first = lforw(first);
305 /* move to beginning of region */
306 curwp->w_dotp = region.r_linep;
307 curwp->w_doto = region.r_offset;
308 curwp->w_dotline = region.r_lineno;
310 /* for each line, go to beginning and insert the prefix string */
312 (void)gotobol(FFRAND, 1);
313 for (prefix = prefix_string; *prefix; prefix++)
314 (void)linsert(1, *prefix);
315 (void)forwline(FFRAND, 1);
317 (void)gotobol(FFRAND, 1);
322 * Set line prefix string. Used by prefixregion.
326 setprefix(int f, int n)
328 char buf[PREFIXLENGTH], *rep;
331 if (prefix_string[0] == '\0')
332 rep = eread("Prefix string: ", buf, sizeof(buf),
335 rep = eread("Prefix string (default %s): ", buf, sizeof(buf),
336 EFNUL | EFNEW | EFCR, prefix_string);
339 if (rep[0] != '\0') {
340 (void)strlcpy(prefix_string, rep, sizeof(prefix_string));
342 } else if (rep[0] == '\0' && prefix_string[0] != '\0') {
343 /* CR -- use old one */
351 region_get_data(struct region *reg, char *buf, int len)
358 for (i = 0; i < len; i++) {
359 if (off == llength(lp)) {
361 if (lp == curbp->b_headp)
366 buf[i] = lgetc(lp, off);
375 region_put_data(const char *buf, int len)
379 for (i = 0; buf[i] != '\0' && i < len; i++) {
388 * Mark whole buffer by first traversing to end-of-buffer
389 * and then to beginning-of-buffer. Mark, dot are implicitly
390 * set to eob, bob respectively during traversal.
393 markbuffer(int f, int n)
395 if (gotoeob(f,n) == FALSE)
397 if (gotobob(f,n) == FALSE)
403 * Pipe text from current region to external command.
407 piperegion(int f, int n)
409 char *cmd, cmdbuf[NFILEN];
411 /* C-u M-| is not supported yet */
415 if (curwp->w_markp == NULL) {
416 ewprintf("The mark is not set now, so there is no region");
419 if ((cmd = eread("Shell command on region: ", cmdbuf, sizeof(cmdbuf),
420 EFNEW | EFCR)) == NULL || (cmd[0] == '\0'))
423 return (pipeio(cmdbuf));
427 * Create a socketpair, fork and execl cmd passed. STDIN, STDOUT
428 * and STDERR of child process are redirected to socket.
431 pipeio(const char* const cmd)
436 if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, s) == -1) {
437 ewprintf("socketpair error");
442 ewprintf("Can't fork");
447 if (dup2(s[1], STDIN_FILENO) == -1)
449 if (dup2(s[1], STDOUT_FILENO) == -1)
451 if (dup2(s[1], STDERR_FILENO) == -1)
453 if ((shellp = getenv("SHELL")) == NULL)
455 execl(shellp, "sh", "-c", cmd, (char *)NULL);
466 * Multiplex read, write on socket fd passed. First get the region,
467 * find/create *Shell Command Output* buffer and clear it's contents.
468 * Poll on the fd for both read and write readiness.
473 struct region region;
475 struct pollfd pfd[1];
477 char *text, *textcopy;
479 if (getregion(®ion) != TRUE)
482 if ((text = malloc(region.r_size + 1)) == NULL)
485 region_get_data(®ion, text, region.r_size);
487 fcntl(fd, F_SETFL, O_NONBLOCK);
489 /* There is nothing to write if r_size is zero
490 * but the cmd's output should be read so shutdown
491 * the socket for writing only.
493 if (region.r_size == 0)
494 shutdown(fd, SHUT_WR);
496 bp = bfind("*Shell Command Output*", TRUE);
497 bp->b_flag |= BFREADONLY;
498 if (bclear(bp) != TRUE)
502 pfd[0].events = POLLIN | POLLOUT;
503 while ((nfds = poll(pfd, 1, TIMEOUT)) != -1 ||
504 (pfd[0].revents & (POLLERR | POLLHUP | POLLNVAL))) {
505 if (pfd[0].revents & POLLOUT && region.r_size > 0)
506 pwriteout(fd, &textcopy, ®ion.r_size);
507 else if (pfd[0].revents & POLLIN)
508 if (preadin(fd, bp) == FALSE)
513 /* In case if last line doesn't have a '\n' add the leftover
514 * characters to buffer.
516 if (leftover[0] != '\0') {
517 addline(bp, leftover);
521 ewprintf("poll timed out");
523 } else if (nfds == -1) {
524 ewprintf("poll error");
527 return (popbuftop(bp, WNONE));
531 * Write some text from region to fd. Once done shutdown the
535 pwriteout(int fd, char **text, int *len)
539 if (((w = send(fd, *text, *len, MSG_NOSIGNAL)) == -1)) {
552 shutdown(fd, SHUT_WR);
556 * Read some data from socket fd, break on '\n' and add
557 * to buffer. If couldn't break on newline hold leftover
558 * characters and append in next iteration.
561 preadin(int fd, struct buffer *bp)
565 char buf[BUFSIZ], *p, *q;
567 if ((len = read(fd, buf, BUFSIZ - 1)) == 0) {
569 addline(bp, "(Shell command succeeded with no output)");
576 if (leftover[0] != '\0' && ((q = strchr(p, '\n')) != NULL)) {
578 if (strlcat(leftover, p, sizeof(leftover)) >=
580 ewprintf("line too long");
583 addline(bp, leftover);
587 while ((q = strchr(p, '\n')) != NULL) {
592 if (strlcpy(leftover, p, sizeof(leftover)) >= sizeof(leftover)) {
593 ewprintf("line too long");