[BACK]Return to region.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / mg

Annotation of src/usr.bin/mg/region.c, Revision 1.43

1.43    ! op          1: /*     $OpenBSD: region.c,v 1.42 2023/03/27 17:54:20 op 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.35      bcallah    12: #include <sys/queue.h>
                     13: #include <sys/socket.h>
1.30      lum        14: #include <sys/types.h>
1.36      lum        15: #include <sys/wait.h>
1.35      bcallah    16: #include <errno.h>
1.30      lum        17: #include <fcntl.h>
1.43    ! op         18: #include <paths.h>
1.30      lum        19: #include <poll.h>
1.35      bcallah    20: #include <signal.h>
                     21: #include <stdio.h>
                     22: #include <stdlib.h>
1.30      lum        23: #include <string.h>
                     24: #include <unistd.h>
                     25:
1.3       millert    26: #include "def.h"
                     27:
1.30      lum        28: #define TIMEOUT 10000
                     29:
                     30: static char leftover[BUFSIZ];
                     31:
1.19      deraadt    32: static int     getregion(struct region *);
1.32      florian    33: static int     iomux(int, char * const, int, struct buffer *);
1.30      lum        34: static int     preadin(int, struct buffer *);
                     35: static void    pwriteout(int, char **, int *);
1.19      deraadt    36: static int     setsize(struct region *, RSIZE);
1.33      lum        37: static int     shellcmdoutput(char * const[], char * const, int);
1.1       deraadt    38:
                     39: /*
1.3       millert    40:  * Kill the region.  Ask "getregion" to figure out the bounds of the region.
1.26      kjell      41:  * Move "." to the start, and kill the characters. Mark is cleared afterwards.
1.1       deraadt    42:  */
1.3       millert    43: int
1.12      cloder     44: killregion(int f, int n)
1.1       deraadt    45: {
1.3       millert    46:        int     s;
1.19      deraadt    47:        struct region   region;
1.1       deraadt    48:
1.2       millert    49:        if ((s = getregion(&region)) != TRUE)
1.1       deraadt    50:                return (s);
1.3       millert    51:        /* This is a kill-type command, so do magic kill buffer stuff. */
                     52:        if ((lastflag & CFKILL) == 0)
                     53:                kdelete();
                     54:        thisflag |= CFKILL;
1.1       deraadt    55:        curwp->w_dotp = region.r_linep;
                     56:        curwp->w_doto = region.r_offset;
1.28      kjell      57:        curwp->w_dotline = region.r_lineno;
1.29      kjell      58:        s = ldelete(region.r_size, KFORW | KREG);
1.26      kjell      59:        clearmark(FFARG, 0);
                     60:
1.23      kjell      61:        return (s);
1.1       deraadt    62: }
                     63:
                     64: /*
1.26      kjell      65:  * Copy all of the characters in the region to the kill buffer,
                     66:  * clearing the mark afterwards.
                     67:  * This is a bit like a kill region followed by a yank.
1.1       deraadt    68:  */
1.3       millert    69: int
1.12      cloder     70: copyregion(int f, int n)
1.1       deraadt    71: {
1.19      deraadt    72:        struct line     *linep;
                     73:        struct region    region;
1.3       millert    74:        int      loffs;
                     75:        int      s;
1.1       deraadt    76:
1.2       millert    77:        if ((s = getregion(&region)) != TRUE)
1.15      db         78:                return (s);
1.3       millert    79:
                     80:        /* kill type command */
                     81:        if ((lastflag & CFKILL) == 0)
1.1       deraadt    82:                kdelete();
                     83:        thisflag |= CFKILL;
1.3       millert    84:
                     85:        /* current line */
                     86:        linep = region.r_linep;
                     87:
                     88:        /* current offset */
                     89:        loffs = region.r_offset;
                     90:
1.1       deraadt    91:        while (region.r_size--) {
1.2       millert    92:                if (loffs == llength(linep)) {  /* End of line.          */
1.39      lum        93:                        if ((s = kinsert(*curbp->b_nlchr, KFORW)) != TRUE)
1.1       deraadt    94:                                return (s);
                     95:                        linep = lforw(linep);
                     96:                        loffs = 0;
1.3       millert    97:                } else {                        /* Middle of line.       */
1.2       millert    98:                        if ((s = kinsert(lgetc(linep, loffs), KFORW)) != TRUE)
1.15      db         99:                                return (s);
1.1       deraadt   100:                        ++loffs;
                    101:                }
                    102:        }
1.26      kjell     103:        clearmark(FFARG, 0);
                    104:
1.15      db        105:        return (TRUE);
1.1       deraadt   106: }
                    107:
                    108: /*
1.6       mickey    109:  * Lower case region.  Zap all of the upper case characters in the region to
                    110:  * lower case. Use the region code to set the limits. Scan the buffer, doing
                    111:  * the changes. Call "lchange" to ensure that redisplay is done in all
1.3       millert   112:  * buffers.
1.1       deraadt   113:  */
1.3       millert   114: int
1.12      cloder    115: lowerregion(int f, int n)
1.1       deraadt   116: {
1.19      deraadt   117:        struct line     *linep;
                    118:        struct region    region;
1.3       millert   119:        int      loffs, c, s;
1.1       deraadt   120:
1.27      kjell     121:        if ((s = checkdirty(curbp)) != TRUE)
                    122:                return (s);
1.10      vincent   123:        if (curbp->b_flag & BFREADONLY) {
1.34      lum       124:                dobeep();
1.10      vincent   125:                ewprintf("Buffer is read-only");
                    126:                return (FALSE);
                    127:        }
                    128:
1.2       millert   129:        if ((s = getregion(&region)) != TRUE)
1.15      db        130:                return (s);
1.9       vincent   131:
                    132:        undo_add_change(region.r_linep, region.r_offset, region.r_size);
1.11      deraadt   133:
1.22      kjell     134:        lchange(WFFULL);
1.1       deraadt   135:        linep = region.r_linep;
                    136:        loffs = region.r_offset;
                    137:        while (region.r_size--) {
                    138:                if (loffs == llength(linep)) {
                    139:                        linep = lforw(linep);
                    140:                        loffs = 0;
                    141:                } else {
                    142:                        c = lgetc(linep, loffs);
                    143:                        if (ISUPPER(c) != FALSE)
                    144:                                lputc(linep, loffs, TOLOWER(c));
                    145:                        ++loffs;
                    146:                }
                    147:        }
1.15      db        148:        return (TRUE);
1.1       deraadt   149: }
                    150:
                    151: /*
1.6       mickey    152:  * Upper case region.  Zap all of the lower case characters in the region to
1.3       millert   153:  * upper case.  Use the region code to set the limits.  Scan the buffer,
1.6       mickey    154:  * doing the changes.  Call "lchange" to ensure that redisplay is done in all
1.3       millert   155:  * buffers.
1.1       deraadt   156:  */
1.3       millert   157: int
1.12      cloder    158: upperregion(int f, int n)
1.1       deraadt   159: {
1.19      deraadt   160:        struct line      *linep;
                    161:        struct region     region;
1.3       millert   162:        int       loffs, c, s;
1.1       deraadt   163:
1.27      kjell     164:        if ((s = checkdirty(curbp)) != TRUE)
                    165:                return (s);
1.10      vincent   166:        if (curbp->b_flag & BFREADONLY) {
1.34      lum       167:                dobeep();
1.10      vincent   168:                ewprintf("Buffer is read-only");
                    169:                return (FALSE);
                    170:        }
1.2       millert   171:        if ((s = getregion(&region)) != TRUE)
1.15      db        172:                return (s);
1.11      deraadt   173:
1.9       vincent   174:        undo_add_change(region.r_linep, region.r_offset, region.r_size);
1.11      deraadt   175:
1.22      kjell     176:        lchange(WFFULL);
1.1       deraadt   177:        linep = region.r_linep;
                    178:        loffs = region.r_offset;
                    179:        while (region.r_size--) {
                    180:                if (loffs == llength(linep)) {
                    181:                        linep = lforw(linep);
                    182:                        loffs = 0;
                    183:                } else {
                    184:                        c = lgetc(linep, loffs);
                    185:                        if (ISLOWER(c) != FALSE)
                    186:                                lputc(linep, loffs, TOUPPER(c));
                    187:                        ++loffs;
                    188:                }
                    189:        }
1.15      db        190:        return (TRUE);
1.1       deraadt   191: }
                    192:
                    193: /*
1.6       mickey    194:  * This routine figures out the bound of the region in the current window,
                    195:  * and stores the results into the fields of the REGION structure. Dot and
                    196:  * mark are usually close together, but I don't know the order, so I scan
                    197:  * outward from dot, in both directions, looking for mark. The size is kept
                    198:  * in a long. At the end, after the size is figured out, it is assigned to
                    199:  * the size field of the region structure. If this assignment loses any bits,
                    200:  * then we print an error. This is "type independent" overflow checking. All
                    201:  * of the callers of this routine should be ready to get an ABORT status,
1.15      db        202:  * because I might add a "if regions is big, ask before clobbering" flag.
1.1       deraadt   203:  */
1.3       millert   204: static int
1.19      deraadt   205: getregion(struct region *rp)
1.2       millert   206: {
1.19      deraadt   207:        struct line     *flp, *blp;
1.3       millert   208:        long     fsize, bsize;
1.1       deraadt   209:
                    210:        if (curwp->w_markp == NULL) {
1.34      lum       211:                dobeep();
1.1       deraadt   212:                ewprintf("No mark set in this window");
                    213:                return (FALSE);
                    214:        }
1.3       millert   215:
                    216:        /* "r_size" always ok */
                    217:        if (curwp->w_dotp == curwp->w_markp) {
1.1       deraadt   218:                rp->r_linep = curwp->w_dotp;
1.28      kjell     219:                rp->r_lineno = curwp->w_dotline;
1.1       deraadt   220:                if (curwp->w_doto < curwp->w_marko) {
                    221:                        rp->r_offset = curwp->w_doto;
1.3       millert   222:                        rp->r_size = (RSIZE)(curwp->w_marko - curwp->w_doto);
1.1       deraadt   223:                } else {
                    224:                        rp->r_offset = curwp->w_marko;
1.3       millert   225:                        rp->r_size = (RSIZE)(curwp->w_doto - curwp->w_marko);
1.1       deraadt   226:                }
1.15      db        227:                return (TRUE);
1.1       deraadt   228:        }
1.3       millert   229:        /* get region size */
                    230:        flp = blp = curwp->w_dotp;
1.1       deraadt   231:        bsize = curwp->w_doto;
1.2       millert   232:        fsize = llength(flp) - curwp->w_doto + 1;
1.24      kjell     233:        while (lforw(flp) != curbp->b_headp || lback(blp) != curbp->b_headp) {
                    234:                if (lforw(flp) != curbp->b_headp) {
1.1       deraadt   235:                        flp = lforw(flp);
                    236:                        if (flp == curwp->w_markp) {
                    237:                                rp->r_linep = curwp->w_dotp;
                    238:                                rp->r_offset = curwp->w_doto;
1.28      kjell     239:                                rp->r_lineno = curwp->w_dotline;
1.1       deraadt   240:                                return (setsize(rp,
1.3       millert   241:                                    (RSIZE)(fsize + curwp->w_marko)));
1.1       deraadt   242:                        }
1.2       millert   243:                        fsize += llength(flp) + 1;
1.1       deraadt   244:                }
1.24      kjell     245:                if (lback(blp) != curbp->b_headp) {
1.1       deraadt   246:                        blp = lback(blp);
1.2       millert   247:                        bsize += llength(blp) + 1;
1.1       deraadt   248:                        if (blp == curwp->w_markp) {
                    249:                                rp->r_linep = blp;
                    250:                                rp->r_offset = curwp->w_marko;
1.28      kjell     251:                                rp->r_lineno = curwp->w_markline;
1.1       deraadt   252:                                return (setsize(rp,
1.3       millert   253:                                    (RSIZE)(bsize - curwp->w_marko)));
1.1       deraadt   254:                        }
                    255:                }
                    256:        }
1.34      lum       257:        dobeep();
1.3       millert   258:        ewprintf("Bug: lost mark");
1.15      db        259:        return (FALSE);
1.1       deraadt   260: }
                    261:
                    262: /*
                    263:  * Set size, and check for overflow.
                    264:  */
1.3       millert   265: static int
1.19      deraadt   266: setsize(struct region *rp, RSIZE size)
1.2       millert   267: {
1.1       deraadt   268:        rp->r_size = size;
                    269:        if (rp->r_size != size) {
1.34      lum       270:                dobeep();
1.1       deraadt   271:                ewprintf("Region is too large");
1.15      db        272:                return (FALSE);
1.1       deraadt   273:        }
1.15      db        274:        return (TRUE);
1.1       deraadt   275: }
                    276:
                    277: #define PREFIXLENGTH 40
1.3       millert   278: static char    prefix_string[PREFIXLENGTH] = {'>', '\0'};
1.1       deraadt   279:
                    280: /*
1.6       mickey    281:  * Prefix the region with whatever is in prefix_string.  Leaves dot at the
                    282:  * beginning of the line after the end of the region.  If an argument is
1.3       millert   283:  * given, prompts for the line prefix string.
1.1       deraadt   284:  */
1.3       millert   285: int
1.12      cloder    286: prefixregion(int f, int n)
1.1       deraadt   287: {
1.19      deraadt   288:        struct line     *first, *last;
                    289:        struct region    region;
1.3       millert   290:        char    *prefix = prefix_string;
                    291:        int      nline;
                    292:        int      s;
1.1       deraadt   293:
1.27      kjell     294:        if ((s = checkdirty(curbp)) != TRUE)
                    295:                return (s);
1.10      vincent   296:        if (curbp->b_flag & BFREADONLY) {
1.34      lum       297:                dobeep();
1.10      vincent   298:                ewprintf("Buffer is read-only");
                    299:                return (FALSE);
                    300:        }
1.1       deraadt   301:        if ((f == TRUE) && ((s = setprefix(FFRAND, 1)) != TRUE))
1.15      db        302:                return (s);
1.1       deraadt   303:
                    304:        /* get # of lines to affect */
                    305:        if ((s = getregion(&region)) != TRUE)
                    306:                return (s);
                    307:        first = region.r_linep;
                    308:        last = (first == curwp->w_dotp) ? curwp->w_markp : curwp->w_dotp;
                    309:        for (nline = 1; first != last; nline++)
                    310:                first = lforw(first);
                    311:
1.2       millert   312:        /* move to beginning of region */
1.1       deraadt   313:        curwp->w_dotp = region.r_linep;
                    314:        curwp->w_doto = region.r_offset;
1.28      kjell     315:        curwp->w_dotline = region.r_lineno;
1.1       deraadt   316:
                    317:        /* for each line, go to beginning and insert the prefix string */
                    318:        while (nline--) {
1.5       art       319:                (void)gotobol(FFRAND, 1);
1.1       deraadt   320:                for (prefix = prefix_string; *prefix; prefix++)
1.5       art       321:                        (void)linsert(1, *prefix);
                    322:                (void)forwline(FFRAND, 1);
1.1       deraadt   323:        }
1.5       art       324:        (void)gotobol(FFRAND, 1);
1.15      db        325:        return (TRUE);
1.1       deraadt   326: }
                    327:
                    328: /*
1.25      kjell     329:  * Set line prefix string. Used by prefixregion.
1.1       deraadt   330:  */
1.3       millert   331: int
1.12      cloder    332: setprefix(int f, int n)
1.1       deraadt   333: {
1.14      vincent   334:        char    buf[PREFIXLENGTH], *rep;
1.15      db        335:        int     retval;
1.1       deraadt   336:
                    337:        if (prefix_string[0] == '\0')
1.18      kjell     338:                rep = eread("Prefix string: ", buf, sizeof(buf),
                    339:                    EFNEW | EFCR);
1.1       deraadt   340:        else
1.18      kjell     341:                rep = eread("Prefix string (default %s): ", buf, sizeof(buf),
                    342:                    EFNUL | EFNEW | EFCR, prefix_string);
                    343:        if (rep == NULL)
                    344:                return (ABORT);
                    345:        if (rep[0] != '\0') {
1.15      db        346:                (void)strlcpy(prefix_string, rep, sizeof(prefix_string));
1.14      vincent   347:                retval = TRUE;
1.18      kjell     348:        } else if (rep[0] == '\0' && prefix_string[0] != '\0') {
1.14      vincent   349:                /* CR -- use old one */
                    350:                retval = TRUE;
                    351:        } else
                    352:                retval = FALSE;
1.15      db        353:        return (retval);
1.1       deraadt   354: }
1.9       vincent   355:
                    356: int
1.19      deraadt   357: region_get_data(struct region *reg, char *buf, int len)
1.9       vincent   358: {
1.15      db        359:        int      i, off;
1.19      deraadt   360:        struct line     *lp;
1.11      deraadt   361:
1.9       vincent   362:        off = reg->r_offset;
                    363:        lp = reg->r_linep;
1.13      vincent   364:        for (i = 0; i < len; i++) {
1.9       vincent   365:                if (off == llength(lp)) {
                    366:                        lp = lforw(lp);
1.24      kjell     367:                        if (lp == curbp->b_headp)
1.9       vincent   368:                                break;
                    369:                        off = 0;
1.39      lum       370:                        buf[i] = *curbp->b_nlchr;
1.9       vincent   371:                } else {
                    372:                        buf[i] = lgetc(lp, off);
                    373:                        off++;
                    374:                }
                    375:        }
1.13      vincent   376:        buf[i] = '\0';
1.15      db        377:        return (i);
1.9       vincent   378: }
                    379:
1.20      kjell     380: void
1.9       vincent   381: region_put_data(const char *buf, int len)
                    382: {
                    383:        int i;
                    384:
1.21      kjell     385:        for (i = 0; buf[i] != '\0' && i < len; i++) {
1.39      lum       386:                if (buf[i] == *curbp->b_nlchr)
1.9       vincent   387:                        lnewline();
                    388:                else
                    389:                        linsert(1, buf[i]);
                    390:        }
1.30      lum       391: }
                    392:
                    393: /*
                    394:  * Mark whole buffer by first traversing to end-of-buffer
                    395:  * and then to beginning-of-buffer. Mark, dot are implicitly
                    396:  * set to eob, bob respectively during traversal.
                    397:  */
                    398: int
                    399: markbuffer(int f, int n)
                    400: {
                    401:        if (gotoeob(f,n) == FALSE)
                    402:                return (FALSE);
1.38      lum       403:        (void) clearmark(f, n);
1.30      lum       404:        if (gotobob(f,n) == FALSE)
                    405:                return (FALSE);
                    406:        return (TRUE);
                    407: }
                    408:
                    409: /*
                    410:  * Pipe text from current region to external command.
                    411:  */
                    412: int
                    413: piperegion(int f, int n)
                    414: {
1.32      florian   415:        struct region region;
1.33      lum       416:        int len;
                    417:        char *cmd, cmdbuf[NFILEN], *text;
1.32      florian   418:        char *argv[] = {"sh", "-c", (char *) NULL, (char *) NULL};
1.30      lum       419:
                    420:        /* C-u M-| is not supported yet */
                    421:        if (n > 1)
                    422:                return (ABORT);
                    423:
                    424:        if (curwp->w_markp == NULL) {
1.34      lum       425:                dobeep();
1.30      lum       426:                ewprintf("The mark is not set now, so there is no region");
                    427:                return (FALSE);
                    428:        }
1.32      florian   429:
1.30      lum       430:        if ((cmd = eread("Shell command on region: ", cmdbuf, sizeof(cmdbuf),
                    431:            EFNEW | EFCR)) == NULL || (cmd[0] == '\0'))
                    432:                return (ABORT);
                    433:
1.32      florian   434:        argv[2] = cmd;
                    435:
                    436:        if (getregion(&region) != TRUE)
                    437:                return (FALSE);
                    438:
                    439:        len = region.r_size;
                    440:
                    441:        if ((text = malloc(len + 1)) == NULL) {
1.34      lum       442:                dobeep();
1.32      florian   443:                ewprintf("Cannot allocate memory.");
                    444:                return (FALSE);
                    445:        }
                    446:
1.33      lum       447:        region_get_data(&region, text, len);
                    448:
                    449:        return shellcmdoutput(argv, text, len);
                    450: }
                    451:
                    452: /*
                    453:  * Get command from mini-buffer and execute externally.
                    454:  */
                    455: int
                    456: shellcommand(int f, int n)
                    457: {
                    458:        char *cmd, cmdbuf[NFILEN];
                    459:        char *argv[] = {"sh", "-c", (char *) NULL, (char *) NULL};
                    460:
                    461:        if (n > 1)
                    462:                return (ABORT);
                    463:
                    464:        if ((cmd = eread("Shell command: ", cmdbuf, sizeof(cmdbuf),
                    465:            EFNEW | EFCR)) == NULL || (cmd[0] == '\0'))
                    466:                return (ABORT);
                    467:
                    468:        argv[2] = cmd;
                    469:
                    470:        return shellcmdoutput(argv, NULL, 0);
                    471: }
                    472:
                    473: int
                    474: shellcmdoutput(char* const argv[], char* const text, int len)
                    475: {
                    476:        struct buffer *bp;
                    477:        char    *shellp;
                    478:        int      ret;
                    479:
1.32      florian   480:        bp = bfind("*Shell Command Output*", TRUE);
                    481:        bp->b_flag |= BFREADONLY;
                    482:        if (bclear(bp) != TRUE) {
                    483:                free(text);
                    484:                return (FALSE);
                    485:        }
                    486:
1.43    ! op        487:        if ((shellp = getenv("SHELL")) == NULL)
        !           488:                shellp = _PATH_BSHELL;
1.32      florian   489:
                    490:        ret = pipeio(shellp, argv, text, len, bp);
                    491:
                    492:        if (ret == TRUE) {
                    493:                eerase();
                    494:                if (lforw(bp->b_headp) == bp->b_headp)
                    495:                        addline(bp, "(Shell command succeeded with no output)");
                    496:        }
                    497:
                    498:        free(text);
                    499:        return (ret);
1.30      lum       500: }
                    501:
                    502: /*
1.32      florian   503:  * Create a socketpair, fork and execv path with argv.
                    504:  * STDIN, STDOUT and STDERR of child process are redirected to socket.
                    505:  * Parent writes len chars from text to socket.
1.30      lum       506:  */
                    507: int
1.32      florian   508: pipeio(const char* const path, char* const argv[], char* const text, int len,
                    509:     struct buffer *outbp)
1.30      lum       510: {
1.36      lum       511:        int s[2], ret;
1.32      florian   512:        char *err;
1.36      lum       513:        pid_t pid;
1.30      lum       514:
                    515:        if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, s) == -1) {
1.34      lum       516:                dobeep();
1.30      lum       517:                ewprintf("socketpair error");
                    518:                return (FALSE);
                    519:        }
1.32      florian   520:
1.36      lum       521:        switch((pid = fork())) {
1.30      lum       522:        case -1:
1.34      lum       523:                dobeep();
1.30      lum       524:                ewprintf("Can't fork");
                    525:                return (FALSE);
                    526:        case 0:
                    527:                /* Child process */
                    528:                close(s[0]);
                    529:                if (dup2(s[1], STDIN_FILENO) == -1)
                    530:                        _exit(1);
                    531:                if (dup2(s[1], STDOUT_FILENO) == -1)
                    532:                        _exit(1);
                    533:                if (dup2(s[1], STDERR_FILENO) == -1)
                    534:                        _exit(1);
1.32      florian   535:
                    536:                execv(path, argv);
                    537:                err = strerror(errno);
                    538:                write(s[1], err, strlen(err));
1.30      lum       539:                _exit(1);
                    540:        default:
                    541:                /* Parent process */
                    542:                close(s[1]);
1.36      lum       543:                ret = iomux(s[0], text, len, outbp);
                    544:                waitpid(pid, NULL, 0); /* Collect child to prevent zombies */
                    545:
                    546:                return (ret);
1.30      lum       547:        }
                    548:        return (FALSE);
                    549: }
                    550:
                    551: /*
1.32      florian   552:  * Multiplex read, write on socket fd passed. Put output in outbp
1.30      lum       553:  * Poll on the fd for both read and write readiness.
                    554:  */
                    555: int
1.32      florian   556: iomux(int fd, char* const text, int len, struct buffer *outbp)
1.30      lum       557: {
                    558:        struct pollfd pfd[1];
                    559:        int nfds;
1.32      florian   560:        char *textcopy;
1.31      florian   561:
1.30      lum       562:        textcopy = text;
                    563:        fcntl(fd, F_SETFL, O_NONBLOCK);
1.32      florian   564:        pfd[0].fd = fd;
                    565:
                    566:        /* There is nothing to write if len is zero
1.41      op        567:         * but the cmd's output should be read so shutdown
1.32      florian   568:         * the socket for writing only and don't wait for POLLOUT
1.30      lum       569:         */
1.32      florian   570:        if (len == 0) {
1.30      lum       571:                shutdown(fd, SHUT_WR);
1.32      florian   572:                pfd[0].events = POLLIN;
                    573:        } else
                    574:                pfd[0].events = POLLIN | POLLOUT;
1.30      lum       575:
                    576:        while ((nfds = poll(pfd, 1, TIMEOUT)) != -1 ||
                    577:            (pfd[0].revents & (POLLERR | POLLHUP | POLLNVAL))) {
1.32      florian   578:                if (pfd[0].revents & POLLOUT && len > 0)
                    579:                        pwriteout(fd, &textcopy, &len);
1.30      lum       580:                else if (pfd[0].revents & POLLIN)
1.32      florian   581:                        if (preadin(fd, outbp) == FALSE)
1.30      lum       582:                                break;
1.32      florian   583:                if (len == 0 && pfd[0].events & POLLOUT)
                    584:                        pfd[0].events = POLLIN;
1.30      lum       585:        }
                    586:        close(fd);
1.32      florian   587:
1.41      op        588:        /* In case if last line doesn't have a '\n' add the leftover
1.30      lum       589:         * characters to buffer.
                    590:         */
                    591:        if (leftover[0] != '\0') {
1.32      florian   592:                addline(outbp, leftover);
1.30      lum       593:                leftover[0] = '\0';
                    594:        }
                    595:        if (nfds == 0) {
1.34      lum       596:                dobeep();
1.30      lum       597:                ewprintf("poll timed out");
                    598:                return (FALSE);
                    599:        } else if (nfds == -1) {
1.34      lum       600:                dobeep();
1.30      lum       601:                ewprintf("poll error");
                    602:                return (FALSE);
                    603:        }
1.32      florian   604:        return (popbuftop(outbp, WNONE));
1.30      lum       605: }
                    606:
                    607: /*
1.41      op        608:  * Write some text from region to fd. Once done shutdown the
1.30      lum       609:  * write end.
                    610:  */
                    611: void
                    612: pwriteout(int fd, char **text, int *len)
                    613: {
                    614:        int w;
                    615:
                    616:        if (((w = send(fd, *text, *len, MSG_NOSIGNAL)) == -1)) {
                    617:                switch(errno) {
                    618:                case EPIPE:
                    619:                        *len = -1;
                    620:                        break;
                    621:                case EAGAIN:
                    622:                        return;
                    623:                }
                    624:        } else
                    625:                *len -= w;
                    626:
                    627:        *text += w;
                    628:        if (*len <= 0)
1.41      op        629:                shutdown(fd, SHUT_WR);
1.30      lum       630: }
                    631:
                    632: /*
                    633:  * Read some data from socket fd, break on '\n' and add
                    634:  * to buffer. If couldn't break on newline hold leftover
                    635:  * characters and append in next iteration.
                    636:  */
                    637: int
                    638: preadin(int fd, struct buffer *bp)
                    639: {
                    640:        int len;
                    641:        char buf[BUFSIZ], *p, *q;
                    642:
1.37      lum       643:        if ((len = read(fd, buf, BUFSIZ - 1)) <= 0)
1.30      lum       644:                return (FALSE);
1.32      florian   645:
1.30      lum       646:        buf[len] = '\0';
                    647:        p = q = buf;
1.39      lum       648:        if (leftover[0] != '\0' && ((q = strchr(p, *bp->b_nlchr)) != NULL)) {
1.30      lum       649:                *q++ = '\0';
                    650:                if (strlcat(leftover, p, sizeof(leftover)) >=
                    651:                    sizeof(leftover)) {
1.34      lum       652:                        dobeep();
1.30      lum       653:                        ewprintf("line too long");
                    654:                        return (FALSE);
                    655:                }
                    656:                addline(bp, leftover);
                    657:                leftover[0] = '\0';
                    658:                p = q;
                    659:        }
1.39      lum       660:        while ((q = strchr(p, *bp->b_nlchr)) != NULL) {
1.30      lum       661:                *q++ = '\0';
                    662:                addline(bp, p);
                    663:                p = q;
                    664:        }
                    665:        if (strlcpy(leftover, p, sizeof(leftover)) >= sizeof(leftover)) {
1.34      lum       666:                dobeep();
1.30      lum       667:                ewprintf("line too long");
                    668:                return (FALSE);
                    669:        }
                    670:        return (TRUE);
1.9       vincent   671: }