Annotation of src/usr.bin/mg/region.c, Revision 1.31
1.31 ! florian 1: /* $OpenBSD: region.c,v 1.30 2012/04/11 17:51:10 lum Exp $ */
1.17 kjell 2:
3: /* This file is in the public domain. */
1.4 niklas 4:
1.1 deraadt 5: /*
6: * Region based commands.
1.6 mickey 7: * The routines in this file deal with the region, that magic space between
1.3 millert 8: * "." and mark. Some functions are commands. Some functions are just for
1.1 deraadt 9: * internal use.
10: */
1.3 millert 11:
1.30 lum 12: #include <sys/types.h>
13: #include <sys/socket.h>
14:
15: #include <fcntl.h>
16: #include <poll.h>
17: #include <string.h>
18: #include <unistd.h>
19:
1.3 millert 20: #include "def.h"
21:
1.30 lum 22: #define TIMEOUT 10000
23:
24: static char leftover[BUFSIZ];
25:
1.19 deraadt 26: static int getregion(struct region *);
1.30 lum 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 *);
1.19 deraadt 31: static int setsize(struct region *, RSIZE);
1.1 deraadt 32:
33: /*
1.3 millert 34: * Kill the region. Ask "getregion" to figure out the bounds of the region.
1.26 kjell 35: * Move "." to the start, and kill the characters. Mark is cleared afterwards.
1.1 deraadt 36: */
1.2 millert 37: /* ARGSUSED */
1.3 millert 38: int
1.12 cloder 39: killregion(int f, int n)
1.1 deraadt 40: {
1.3 millert 41: int s;
1.19 deraadt 42: struct region region;
1.1 deraadt 43:
1.2 millert 44: if ((s = getregion(®ion)) != TRUE)
1.1 deraadt 45: return (s);
1.3 millert 46: /* This is a kill-type command, so do magic kill buffer stuff. */
47: if ((lastflag & CFKILL) == 0)
48: kdelete();
49: thisflag |= CFKILL;
1.1 deraadt 50: curwp->w_dotp = region.r_linep;
51: curwp->w_doto = region.r_offset;
1.28 kjell 52: curwp->w_dotline = region.r_lineno;
1.29 kjell 53: s = ldelete(region.r_size, KFORW | KREG);
1.26 kjell 54: clearmark(FFARG, 0);
55:
1.23 kjell 56: return (s);
1.1 deraadt 57: }
58:
59: /*
1.26 kjell 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.
1.1 deraadt 63: */
1.2 millert 64: /* ARGSUSED */
1.3 millert 65: int
1.12 cloder 66: copyregion(int f, int n)
1.1 deraadt 67: {
1.19 deraadt 68: struct line *linep;
69: struct region region;
1.3 millert 70: int loffs;
71: int s;
1.1 deraadt 72:
1.2 millert 73: if ((s = getregion(®ion)) != TRUE)
1.15 db 74: return (s);
1.3 millert 75:
76: /* kill type command */
77: if ((lastflag & CFKILL) == 0)
1.1 deraadt 78: kdelete();
79: thisflag |= CFKILL;
1.3 millert 80:
81: /* current line */
82: linep = region.r_linep;
83:
84: /* current offset */
85: loffs = region.r_offset;
86:
1.1 deraadt 87: while (region.r_size--) {
1.2 millert 88: if (loffs == llength(linep)) { /* End of line. */
89: if ((s = kinsert('\n', KFORW)) != TRUE)
1.1 deraadt 90: return (s);
91: linep = lforw(linep);
92: loffs = 0;
1.3 millert 93: } else { /* Middle of line. */
1.2 millert 94: if ((s = kinsert(lgetc(linep, loffs), KFORW)) != TRUE)
1.15 db 95: return (s);
1.1 deraadt 96: ++loffs;
97: }
98: }
1.26 kjell 99: clearmark(FFARG, 0);
100:
1.15 db 101: return (TRUE);
1.1 deraadt 102: }
103:
104: /*
1.6 mickey 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
1.3 millert 108: * buffers.
1.1 deraadt 109: */
1.2 millert 110: /* ARGSUSED */
1.3 millert 111: int
1.12 cloder 112: lowerregion(int f, int n)
1.1 deraadt 113: {
1.19 deraadt 114: struct line *linep;
115: struct region region;
1.3 millert 116: int loffs, c, s;
1.1 deraadt 117:
1.27 kjell 118: if ((s = checkdirty(curbp)) != TRUE)
119: return (s);
1.10 vincent 120: if (curbp->b_flag & BFREADONLY) {
121: ewprintf("Buffer is read-only");
122: return (FALSE);
123: }
124:
1.2 millert 125: if ((s = getregion(®ion)) != TRUE)
1.15 db 126: return (s);
1.9 vincent 127:
128: undo_add_change(region.r_linep, region.r_offset, region.r_size);
1.11 deraadt 129:
1.22 kjell 130: lchange(WFFULL);
1.1 deraadt 131: linep = region.r_linep;
132: loffs = region.r_offset;
133: while (region.r_size--) {
134: if (loffs == llength(linep)) {
135: linep = lforw(linep);
136: loffs = 0;
137: } else {
138: c = lgetc(linep, loffs);
139: if (ISUPPER(c) != FALSE)
140: lputc(linep, loffs, TOLOWER(c));
141: ++loffs;
142: }
143: }
1.15 db 144: return (TRUE);
1.1 deraadt 145: }
146:
147: /*
1.6 mickey 148: * Upper case region. Zap all of the lower case characters in the region to
1.3 millert 149: * upper case. Use the region code to set the limits. Scan the buffer,
1.6 mickey 150: * doing the changes. Call "lchange" to ensure that redisplay is done in all
1.3 millert 151: * buffers.
1.1 deraadt 152: */
1.2 millert 153: /* ARGSUSED */
1.3 millert 154: int
1.12 cloder 155: upperregion(int f, int n)
1.1 deraadt 156: {
1.19 deraadt 157: struct line *linep;
158: struct region region;
1.3 millert 159: int loffs, c, s;
1.1 deraadt 160:
1.27 kjell 161: if ((s = checkdirty(curbp)) != TRUE)
162: return (s);
1.10 vincent 163: if (curbp->b_flag & BFREADONLY) {
164: ewprintf("Buffer is read-only");
165: return (FALSE);
166: }
1.2 millert 167: if ((s = getregion(®ion)) != TRUE)
1.15 db 168: return (s);
1.11 deraadt 169:
1.9 vincent 170: undo_add_change(region.r_linep, region.r_offset, region.r_size);
1.11 deraadt 171:
1.22 kjell 172: lchange(WFFULL);
1.1 deraadt 173: linep = region.r_linep;
174: loffs = region.r_offset;
175: while (region.r_size--) {
176: if (loffs == llength(linep)) {
177: linep = lforw(linep);
178: loffs = 0;
179: } else {
180: c = lgetc(linep, loffs);
181: if (ISLOWER(c) != FALSE)
182: lputc(linep, loffs, TOUPPER(c));
183: ++loffs;
184: }
185: }
1.15 db 186: return (TRUE);
1.1 deraadt 187: }
188:
189: /*
1.6 mickey 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,
1.15 db 198: * because I might add a "if regions is big, ask before clobbering" flag.
1.1 deraadt 199: */
1.3 millert 200: static int
1.19 deraadt 201: getregion(struct region *rp)
1.2 millert 202: {
1.19 deraadt 203: struct line *flp, *blp;
1.3 millert 204: long fsize, bsize;
1.1 deraadt 205:
206: if (curwp->w_markp == NULL) {
207: ewprintf("No mark set in this window");
208: return (FALSE);
209: }
1.3 millert 210:
211: /* "r_size" always ok */
212: if (curwp->w_dotp == curwp->w_markp) {
1.1 deraadt 213: rp->r_linep = curwp->w_dotp;
1.28 kjell 214: rp->r_lineno = curwp->w_dotline;
1.1 deraadt 215: if (curwp->w_doto < curwp->w_marko) {
216: rp->r_offset = curwp->w_doto;
1.3 millert 217: rp->r_size = (RSIZE)(curwp->w_marko - curwp->w_doto);
1.1 deraadt 218: } else {
219: rp->r_offset = curwp->w_marko;
1.3 millert 220: rp->r_size = (RSIZE)(curwp->w_doto - curwp->w_marko);
1.1 deraadt 221: }
1.15 db 222: return (TRUE);
1.1 deraadt 223: }
1.3 millert 224: /* get region size */
225: flp = blp = curwp->w_dotp;
1.1 deraadt 226: bsize = curwp->w_doto;
1.2 millert 227: fsize = llength(flp) - curwp->w_doto + 1;
1.24 kjell 228: while (lforw(flp) != curbp->b_headp || lback(blp) != curbp->b_headp) {
229: if (lforw(flp) != curbp->b_headp) {
1.1 deraadt 230: flp = lforw(flp);
231: if (flp == curwp->w_markp) {
232: rp->r_linep = curwp->w_dotp;
233: rp->r_offset = curwp->w_doto;
1.28 kjell 234: rp->r_lineno = curwp->w_dotline;
1.1 deraadt 235: return (setsize(rp,
1.3 millert 236: (RSIZE)(fsize + curwp->w_marko)));
1.1 deraadt 237: }
1.2 millert 238: fsize += llength(flp) + 1;
1.1 deraadt 239: }
1.24 kjell 240: if (lback(blp) != curbp->b_headp) {
1.1 deraadt 241: blp = lback(blp);
1.2 millert 242: bsize += llength(blp) + 1;
1.1 deraadt 243: if (blp == curwp->w_markp) {
244: rp->r_linep = blp;
245: rp->r_offset = curwp->w_marko;
1.28 kjell 246: rp->r_lineno = curwp->w_markline;
1.1 deraadt 247: return (setsize(rp,
1.3 millert 248: (RSIZE)(bsize - curwp->w_marko)));
1.1 deraadt 249: }
250: }
251: }
1.3 millert 252: ewprintf("Bug: lost mark");
1.15 db 253: return (FALSE);
1.1 deraadt 254: }
255:
256: /*
257: * Set size, and check for overflow.
258: */
1.3 millert 259: static int
1.19 deraadt 260: setsize(struct region *rp, RSIZE size)
1.2 millert 261: {
1.1 deraadt 262: rp->r_size = size;
263: if (rp->r_size != size) {
264: ewprintf("Region is too large");
1.15 db 265: return (FALSE);
1.1 deraadt 266: }
1.15 db 267: return (TRUE);
1.1 deraadt 268: }
269:
270: #define PREFIXLENGTH 40
1.3 millert 271: static char prefix_string[PREFIXLENGTH] = {'>', '\0'};
1.1 deraadt 272:
273: /*
1.6 mickey 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
1.3 millert 276: * given, prompts for the line prefix string.
1.1 deraadt 277: */
1.2 millert 278: /* ARGSUSED */
1.3 millert 279: int
1.12 cloder 280: prefixregion(int f, int n)
1.1 deraadt 281: {
1.19 deraadt 282: struct line *first, *last;
283: struct region region;
1.3 millert 284: char *prefix = prefix_string;
285: int nline;
286: int s;
1.1 deraadt 287:
1.27 kjell 288: if ((s = checkdirty(curbp)) != TRUE)
289: return (s);
1.10 vincent 290: if (curbp->b_flag & BFREADONLY) {
291: ewprintf("Buffer is read-only");
292: return (FALSE);
293: }
1.1 deraadt 294: if ((f == TRUE) && ((s = setprefix(FFRAND, 1)) != TRUE))
1.15 db 295: return (s);
1.1 deraadt 296:
297: /* get # of lines to affect */
298: if ((s = getregion(®ion)) != TRUE)
299: return (s);
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);
304:
1.2 millert 305: /* move to beginning of region */
1.1 deraadt 306: curwp->w_dotp = region.r_linep;
307: curwp->w_doto = region.r_offset;
1.28 kjell 308: curwp->w_dotline = region.r_lineno;
1.1 deraadt 309:
310: /* for each line, go to beginning and insert the prefix string */
311: while (nline--) {
1.5 art 312: (void)gotobol(FFRAND, 1);
1.1 deraadt 313: for (prefix = prefix_string; *prefix; prefix++)
1.5 art 314: (void)linsert(1, *prefix);
315: (void)forwline(FFRAND, 1);
1.1 deraadt 316: }
1.5 art 317: (void)gotobol(FFRAND, 1);
1.15 db 318: return (TRUE);
1.1 deraadt 319: }
320:
321: /*
1.25 kjell 322: * Set line prefix string. Used by prefixregion.
1.1 deraadt 323: */
1.2 millert 324: /* ARGSUSED */
1.3 millert 325: int
1.12 cloder 326: setprefix(int f, int n)
1.1 deraadt 327: {
1.14 vincent 328: char buf[PREFIXLENGTH], *rep;
1.15 db 329: int retval;
1.1 deraadt 330:
331: if (prefix_string[0] == '\0')
1.18 kjell 332: rep = eread("Prefix string: ", buf, sizeof(buf),
333: EFNEW | EFCR);
1.1 deraadt 334: else
1.18 kjell 335: rep = eread("Prefix string (default %s): ", buf, sizeof(buf),
336: EFNUL | EFNEW | EFCR, prefix_string);
337: if (rep == NULL)
338: return (ABORT);
339: if (rep[0] != '\0') {
1.15 db 340: (void)strlcpy(prefix_string, rep, sizeof(prefix_string));
1.14 vincent 341: retval = TRUE;
1.18 kjell 342: } else if (rep[0] == '\0' && prefix_string[0] != '\0') {
1.14 vincent 343: /* CR -- use old one */
344: retval = TRUE;
345: } else
346: retval = FALSE;
1.15 db 347: return (retval);
1.1 deraadt 348: }
1.9 vincent 349:
350: int
1.19 deraadt 351: region_get_data(struct region *reg, char *buf, int len)
1.9 vincent 352: {
1.15 db 353: int i, off;
1.19 deraadt 354: struct line *lp;
1.11 deraadt 355:
1.9 vincent 356: off = reg->r_offset;
357: lp = reg->r_linep;
1.13 vincent 358: for (i = 0; i < len; i++) {
1.9 vincent 359: if (off == llength(lp)) {
360: lp = lforw(lp);
1.24 kjell 361: if (lp == curbp->b_headp)
1.9 vincent 362: break;
363: off = 0;
364: buf[i] = '\n';
365: } else {
366: buf[i] = lgetc(lp, off);
367: off++;
368: }
369: }
1.13 vincent 370: buf[i] = '\0';
1.15 db 371: return (i);
1.9 vincent 372: }
373:
1.20 kjell 374: void
1.9 vincent 375: region_put_data(const char *buf, int len)
376: {
377: int i;
378:
1.21 kjell 379: for (i = 0; buf[i] != '\0' && i < len; i++) {
1.9 vincent 380: if (buf[i] == '\n')
381: lnewline();
382: else
383: linsert(1, buf[i]);
384: }
1.30 lum 385: }
386:
387: /*
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.
391: */
392: int
393: markbuffer(int f, int n)
394: {
395: if (gotoeob(f,n) == FALSE)
396: return (FALSE);
397: if (gotobob(f,n) == FALSE)
398: return (FALSE);
399: return (TRUE);
400: }
401:
402: /*
403: * Pipe text from current region to external command.
404: */
405: /*ARGSUSED */
406: int
407: piperegion(int f, int n)
408: {
409: char *cmd, cmdbuf[NFILEN];
410:
411: /* C-u M-| is not supported yet */
412: if (n > 1)
413: return (ABORT);
414:
415: if (curwp->w_markp == NULL) {
416: ewprintf("The mark is not set now, so there is no region");
417: return (FALSE);
418: }
419: if ((cmd = eread("Shell command on region: ", cmdbuf, sizeof(cmdbuf),
420: EFNEW | EFCR)) == NULL || (cmd[0] == '\0'))
421: return (ABORT);
422:
423: return (pipeio(cmdbuf));
424: }
425:
426: /*
427: * Create a socketpair, fork and execl cmd passed. STDIN, STDOUT
428: * and STDERR of child process are redirected to socket.
429: */
430: int
431: pipeio(const char* const cmd)
432: {
433: int s[2];
434: char *shellp;
435:
436: if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, s) == -1) {
437: ewprintf("socketpair error");
438: return (FALSE);
439: }
440: switch(fork()) {
441: case -1:
442: ewprintf("Can't fork");
443: return (FALSE);
444: case 0:
445: /* Child process */
446: close(s[0]);
447: if (dup2(s[1], STDIN_FILENO) == -1)
448: _exit(1);
449: if (dup2(s[1], STDOUT_FILENO) == -1)
450: _exit(1);
451: if (dup2(s[1], STDERR_FILENO) == -1)
452: _exit(1);
453: if ((shellp = getenv("SHELL")) == NULL)
454: _exit(1);
455: execl(shellp, "sh", "-c", cmd, (char *)NULL);
456: _exit(1);
457: default:
458: /* Parent process */
459: close(s[1]);
460: return iomux(s[0]);
461: }
462: return (FALSE);
463: }
464:
465: /*
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.
469: */
470: int
471: iomux(int fd)
472: {
473: struct region region;
474: struct buffer *bp;
475: struct pollfd pfd[1];
476: int nfds;
477: char *text, *textcopy;
478:
1.31 ! florian 479: if (getregion(®ion) != TRUE) {
! 480: close(fd);
1.30 lum 481: return (FALSE);
1.31 ! florian 482: }
! 483:
! 484: if ((text = malloc(region.r_size + 1)) == NULL) {
! 485: close(fd);
1.30 lum 486: return (ABORT);
1.31 ! florian 487: }
! 488:
1.30 lum 489: region_get_data(®ion, text, region.r_size);
490: textcopy = text;
491: fcntl(fd, F_SETFL, O_NONBLOCK);
492:
493: /* There is nothing to write if r_size is zero
494: * but the cmd's output should be read so shutdown
495: * the socket for writing only.
496: */
497: if (region.r_size == 0)
498: shutdown(fd, SHUT_WR);
499:
500: bp = bfind("*Shell Command Output*", TRUE);
501: bp->b_flag |= BFREADONLY;
1.31 ! florian 502: if (bclear(bp) != TRUE) {
! 503: close(fd);
! 504: free(text);
1.30 lum 505: return (FALSE);
1.31 ! florian 506: }
1.30 lum 507:
508: pfd[0].fd = fd;
509: pfd[0].events = POLLIN | POLLOUT;
510: while ((nfds = poll(pfd, 1, TIMEOUT)) != -1 ||
511: (pfd[0].revents & (POLLERR | POLLHUP | POLLNVAL))) {
512: if (pfd[0].revents & POLLOUT && region.r_size > 0)
513: pwriteout(fd, &textcopy, ®ion.r_size);
514: else if (pfd[0].revents & POLLIN)
515: if (preadin(fd, bp) == FALSE)
516: break;
517: }
518: close(fd);
519: free(text);
520: /* In case if last line doesn't have a '\n' add the leftover
521: * characters to buffer.
522: */
523: if (leftover[0] != '\0') {
524: addline(bp, leftover);
525: leftover[0] = '\0';
526: }
527: if (nfds == 0) {
528: ewprintf("poll timed out");
529: return (FALSE);
530: } else if (nfds == -1) {
531: ewprintf("poll error");
532: return (FALSE);
533: }
534: return (popbuftop(bp, WNONE));
535: }
536:
537: /*
538: * Write some text from region to fd. Once done shutdown the
539: * write end.
540: */
541: void
542: pwriteout(int fd, char **text, int *len)
543: {
544: int w;
545:
546: if (((w = send(fd, *text, *len, MSG_NOSIGNAL)) == -1)) {
547: switch(errno) {
548: case EPIPE:
549: *len = -1;
550: break;
551: case EAGAIN:
552: return;
553: }
554: } else
555: *len -= w;
556:
557: *text += w;
558: if (*len <= 0)
559: shutdown(fd, SHUT_WR);
560: }
561:
562: /*
563: * Read some data from socket fd, break on '\n' and add
564: * to buffer. If couldn't break on newline hold leftover
565: * characters and append in next iteration.
566: */
567: int
568: preadin(int fd, struct buffer *bp)
569: {
570: int len;
571: static int nooutput;
572: char buf[BUFSIZ], *p, *q;
573:
574: if ((len = read(fd, buf, BUFSIZ - 1)) == 0) {
575: if (nooutput == 0)
576: addline(bp, "(Shell command succeeded with no output)");
577: nooutput = 0;
578: return (FALSE);
579: }
580: nooutput = 1;
581: buf[len] = '\0';
582: p = q = buf;
583: if (leftover[0] != '\0' && ((q = strchr(p, '\n')) != NULL)) {
584: *q++ = '\0';
585: if (strlcat(leftover, p, sizeof(leftover)) >=
586: sizeof(leftover)) {
587: ewprintf("line too long");
588: return (FALSE);
589: }
590: addline(bp, leftover);
591: leftover[0] = '\0';
592: p = q;
593: }
594: while ((q = strchr(p, '\n')) != NULL) {
595: *q++ = '\0';
596: addline(bp, p);
597: p = q;
598: }
599: if (strlcpy(leftover, p, sizeof(leftover)) >= sizeof(leftover)) {
600: ewprintf("line too long");
601: return (FALSE);
602: }
603: return (TRUE);
1.9 vincent 604: }