[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.34

1.34    ! lum         1: /*     $OpenBSD: region.c,v 1.33 2013/05/22 19:23:45 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.32      florian    27: static int     iomux(int, char * const, int, struct buffer *);
1.30      lum        28: static int     preadin(int, struct buffer *);
                     29: static void    pwriteout(int, char **, int *);
1.19      deraadt    30: static int     setsize(struct region *, RSIZE);
1.33      lum        31: static int     shellcmdoutput(char * const[], char * const, int);
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(&region)) != 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(&region)) != 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) {
1.34    ! lum       121:                dobeep();
1.10      vincent   122:                ewprintf("Buffer is read-only");
                    123:                return (FALSE);
                    124:        }
                    125:
1.2       millert   126:        if ((s = getregion(&region)) != TRUE)
1.15      db        127:                return (s);
1.9       vincent   128:
                    129:        undo_add_change(region.r_linep, region.r_offset, region.r_size);
1.11      deraadt   130:
1.22      kjell     131:        lchange(WFFULL);
1.1       deraadt   132:        linep = region.r_linep;
                    133:        loffs = region.r_offset;
                    134:        while (region.r_size--) {
                    135:                if (loffs == llength(linep)) {
                    136:                        linep = lforw(linep);
                    137:                        loffs = 0;
                    138:                } else {
                    139:                        c = lgetc(linep, loffs);
                    140:                        if (ISUPPER(c) != FALSE)
                    141:                                lputc(linep, loffs, TOLOWER(c));
                    142:                        ++loffs;
                    143:                }
                    144:        }
1.15      db        145:        return (TRUE);
1.1       deraadt   146: }
                    147:
                    148: /*
1.6       mickey    149:  * Upper case region.  Zap all of the lower case characters in the region to
1.3       millert   150:  * upper case.  Use the region code to set the limits.  Scan the buffer,
1.6       mickey    151:  * doing the changes.  Call "lchange" to ensure that redisplay is done in all
1.3       millert   152:  * buffers.
1.1       deraadt   153:  */
1.2       millert   154: /* ARGSUSED */
1.3       millert   155: int
1.12      cloder    156: upperregion(int f, int n)
1.1       deraadt   157: {
1.19      deraadt   158:        struct line      *linep;
                    159:        struct region     region;
1.3       millert   160:        int       loffs, c, s;
1.1       deraadt   161:
1.27      kjell     162:        if ((s = checkdirty(curbp)) != TRUE)
                    163:                return (s);
1.10      vincent   164:        if (curbp->b_flag & BFREADONLY) {
1.34    ! lum       165:                dobeep();
1.10      vincent   166:                ewprintf("Buffer is read-only");
                    167:                return (FALSE);
                    168:        }
1.2       millert   169:        if ((s = getregion(&region)) != TRUE)
1.15      db        170:                return (s);
1.11      deraadt   171:
1.9       vincent   172:        undo_add_change(region.r_linep, region.r_offset, region.r_size);
1.11      deraadt   173:
1.22      kjell     174:        lchange(WFFULL);
1.1       deraadt   175:        linep = region.r_linep;
                    176:        loffs = region.r_offset;
                    177:        while (region.r_size--) {
                    178:                if (loffs == llength(linep)) {
                    179:                        linep = lforw(linep);
                    180:                        loffs = 0;
                    181:                } else {
                    182:                        c = lgetc(linep, loffs);
                    183:                        if (ISLOWER(c) != FALSE)
                    184:                                lputc(linep, loffs, TOUPPER(c));
                    185:                        ++loffs;
                    186:                }
                    187:        }
1.15      db        188:        return (TRUE);
1.1       deraadt   189: }
                    190:
                    191: /*
1.6       mickey    192:  * This routine figures out the bound of the region in the current window,
                    193:  * and stores the results into the fields of the REGION structure. Dot and
                    194:  * mark are usually close together, but I don't know the order, so I scan
                    195:  * outward from dot, in both directions, looking for mark. The size is kept
                    196:  * in a long. At the end, after the size is figured out, it is assigned to
                    197:  * the size field of the region structure. If this assignment loses any bits,
                    198:  * then we print an error. This is "type independent" overflow checking. All
                    199:  * of the callers of this routine should be ready to get an ABORT status,
1.15      db        200:  * because I might add a "if regions is big, ask before clobbering" flag.
1.1       deraadt   201:  */
1.3       millert   202: static int
1.19      deraadt   203: getregion(struct region *rp)
1.2       millert   204: {
1.19      deraadt   205:        struct line     *flp, *blp;
1.3       millert   206:        long     fsize, bsize;
1.1       deraadt   207:
                    208:        if (curwp->w_markp == NULL) {
1.34    ! lum       209:                dobeep();
1.1       deraadt   210:                ewprintf("No mark set in this window");
                    211:                return (FALSE);
                    212:        }
1.3       millert   213:
                    214:        /* "r_size" always ok */
                    215:        if (curwp->w_dotp == curwp->w_markp) {
1.1       deraadt   216:                rp->r_linep = curwp->w_dotp;
1.28      kjell     217:                rp->r_lineno = curwp->w_dotline;
1.1       deraadt   218:                if (curwp->w_doto < curwp->w_marko) {
                    219:                        rp->r_offset = curwp->w_doto;
1.3       millert   220:                        rp->r_size = (RSIZE)(curwp->w_marko - curwp->w_doto);
1.1       deraadt   221:                } else {
                    222:                        rp->r_offset = curwp->w_marko;
1.3       millert   223:                        rp->r_size = (RSIZE)(curwp->w_doto - curwp->w_marko);
1.1       deraadt   224:                }
1.15      db        225:                return (TRUE);
1.1       deraadt   226:        }
1.3       millert   227:        /* get region size */
                    228:        flp = blp = curwp->w_dotp;
1.1       deraadt   229:        bsize = curwp->w_doto;
1.2       millert   230:        fsize = llength(flp) - curwp->w_doto + 1;
1.24      kjell     231:        while (lforw(flp) != curbp->b_headp || lback(blp) != curbp->b_headp) {
                    232:                if (lforw(flp) != curbp->b_headp) {
1.1       deraadt   233:                        flp = lforw(flp);
                    234:                        if (flp == curwp->w_markp) {
                    235:                                rp->r_linep = curwp->w_dotp;
                    236:                                rp->r_offset = curwp->w_doto;
1.28      kjell     237:                                rp->r_lineno = curwp->w_dotline;
1.1       deraadt   238:                                return (setsize(rp,
1.3       millert   239:                                    (RSIZE)(fsize + curwp->w_marko)));
1.1       deraadt   240:                        }
1.2       millert   241:                        fsize += llength(flp) + 1;
1.1       deraadt   242:                }
1.24      kjell     243:                if (lback(blp) != curbp->b_headp) {
1.1       deraadt   244:                        blp = lback(blp);
1.2       millert   245:                        bsize += llength(blp) + 1;
1.1       deraadt   246:                        if (blp == curwp->w_markp) {
                    247:                                rp->r_linep = blp;
                    248:                                rp->r_offset = curwp->w_marko;
1.28      kjell     249:                                rp->r_lineno = curwp->w_markline;
1.1       deraadt   250:                                return (setsize(rp,
1.3       millert   251:                                    (RSIZE)(bsize - curwp->w_marko)));
1.1       deraadt   252:                        }
                    253:                }
                    254:        }
1.34    ! lum       255:        dobeep();
1.3       millert   256:        ewprintf("Bug: lost mark");
1.15      db        257:        return (FALSE);
1.1       deraadt   258: }
                    259:
                    260: /*
                    261:  * Set size, and check for overflow.
                    262:  */
1.3       millert   263: static int
1.19      deraadt   264: setsize(struct region *rp, RSIZE size)
1.2       millert   265: {
1.1       deraadt   266:        rp->r_size = size;
                    267:        if (rp->r_size != size) {
1.34    ! lum       268:                dobeep();
1.1       deraadt   269:                ewprintf("Region is too large");
1.15      db        270:                return (FALSE);
1.1       deraadt   271:        }
1.15      db        272:        return (TRUE);
1.1       deraadt   273: }
                    274:
                    275: #define PREFIXLENGTH 40
1.3       millert   276: static char    prefix_string[PREFIXLENGTH] = {'>', '\0'};
1.1       deraadt   277:
                    278: /*
1.6       mickey    279:  * Prefix the region with whatever is in prefix_string.  Leaves dot at the
                    280:  * beginning of the line after the end of the region.  If an argument is
1.3       millert   281:  * given, prompts for the line prefix string.
1.1       deraadt   282:  */
1.2       millert   283: /* ARGSUSED */
1.3       millert   284: int
1.12      cloder    285: prefixregion(int f, int n)
1.1       deraadt   286: {
1.19      deraadt   287:        struct line     *first, *last;
                    288:        struct region    region;
1.3       millert   289:        char    *prefix = prefix_string;
                    290:        int      nline;
                    291:        int      s;
1.1       deraadt   292:
1.27      kjell     293:        if ((s = checkdirty(curbp)) != TRUE)
                    294:                return (s);
1.10      vincent   295:        if (curbp->b_flag & BFREADONLY) {
1.34    ! lum       296:                dobeep();
1.10      vincent   297:                ewprintf("Buffer is read-only");
                    298:                return (FALSE);
                    299:        }
1.1       deraadt   300:        if ((f == TRUE) && ((s = setprefix(FFRAND, 1)) != TRUE))
1.15      db        301:                return (s);
1.1       deraadt   302:
                    303:        /* get # of lines to affect */
                    304:        if ((s = getregion(&region)) != TRUE)
                    305:                return (s);
                    306:        first = region.r_linep;
                    307:        last = (first == curwp->w_dotp) ? curwp->w_markp : curwp->w_dotp;
                    308:        for (nline = 1; first != last; nline++)
                    309:                first = lforw(first);
                    310:
1.2       millert   311:        /* move to beginning of region */
1.1       deraadt   312:        curwp->w_dotp = region.r_linep;
                    313:        curwp->w_doto = region.r_offset;
1.28      kjell     314:        curwp->w_dotline = region.r_lineno;
1.1       deraadt   315:
                    316:        /* for each line, go to beginning and insert the prefix string */
                    317:        while (nline--) {
1.5       art       318:                (void)gotobol(FFRAND, 1);
1.1       deraadt   319:                for (prefix = prefix_string; *prefix; prefix++)
1.5       art       320:                        (void)linsert(1, *prefix);
                    321:                (void)forwline(FFRAND, 1);
1.1       deraadt   322:        }
1.5       art       323:        (void)gotobol(FFRAND, 1);
1.15      db        324:        return (TRUE);
1.1       deraadt   325: }
                    326:
                    327: /*
1.25      kjell     328:  * Set line prefix string. Used by prefixregion.
1.1       deraadt   329:  */
1.2       millert   330: /* ARGSUSED */
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;
                    370:                        buf[i] = '\n';
                    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.9       vincent   386:                if (buf[i] == '\n')
                    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);
                    403:        if (gotobob(f,n) == FALSE)
                    404:                return (FALSE);
                    405:        return (TRUE);
                    406: }
                    407:
                    408: /*
                    409:  * Pipe text from current region to external command.
                    410:  */
                    411: /*ARGSUSED */
                    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: /*ARGSUSED */
                    456: int
                    457: shellcommand(int f, int n)
                    458: {
                    459:
                    460:        char *cmd, cmdbuf[NFILEN];
                    461:        char *argv[] = {"sh", "-c", (char *) NULL, (char *) NULL};
                    462:
                    463:        if (n > 1)
                    464:                return (ABORT);
                    465:
                    466:        if ((cmd = eread("Shell command: ", cmdbuf, sizeof(cmdbuf),
                    467:            EFNEW | EFCR)) == NULL || (cmd[0] == '\0'))
                    468:                return (ABORT);
                    469:
                    470:        argv[2] = cmd;
                    471:
                    472:        return shellcmdoutput(argv, NULL, 0);
                    473: }
                    474:
                    475:
                    476: int
                    477: shellcmdoutput(char* const argv[], char* const text, int len)
                    478: {
                    479:
                    480:        struct buffer *bp;
                    481:        char    *shellp;
                    482:        int      ret;
                    483:
1.32      florian   484:        bp = bfind("*Shell Command Output*", TRUE);
                    485:        bp->b_flag |= BFREADONLY;
                    486:        if (bclear(bp) != TRUE) {
                    487:                free(text);
                    488:                return (FALSE);
                    489:        }
                    490:
                    491:        shellp = getenv("SHELL");
                    492:
                    493:        ret = pipeio(shellp, argv, text, len, bp);
                    494:
                    495:        if (ret == TRUE) {
                    496:                eerase();
                    497:                if (lforw(bp->b_headp) == bp->b_headp)
                    498:                        addline(bp, "(Shell command succeeded with no output)");
                    499:        }
                    500:
                    501:        free(text);
                    502:        return (ret);
1.30      lum       503: }
                    504:
                    505: /*
1.32      florian   506:  * Create a socketpair, fork and execv path with argv.
                    507:  * STDIN, STDOUT and STDERR of child process are redirected to socket.
                    508:  * Parent writes len chars from text to socket.
1.30      lum       509:  */
                    510: int
1.32      florian   511: pipeio(const char* const path, char* const argv[], char* const text, int len,
                    512:     struct buffer *outbp)
1.30      lum       513: {
                    514:        int s[2];
1.32      florian   515:        char *err;
1.30      lum       516:
                    517:        if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, s) == -1) {
1.34    ! lum       518:                dobeep();
1.30      lum       519:                ewprintf("socketpair error");
                    520:                return (FALSE);
                    521:        }
1.32      florian   522:
1.30      lum       523:        switch(fork()) {
                    524:        case -1:
1.34    ! lum       525:                dobeep();
1.30      lum       526:                ewprintf("Can't fork");
                    527:                return (FALSE);
                    528:        case 0:
                    529:                /* Child process */
                    530:                close(s[0]);
                    531:                if (dup2(s[1], STDIN_FILENO) == -1)
                    532:                        _exit(1);
                    533:                if (dup2(s[1], STDOUT_FILENO) == -1)
                    534:                        _exit(1);
                    535:                if (dup2(s[1], STDERR_FILENO) == -1)
                    536:                        _exit(1);
1.32      florian   537:                if (path == NULL)
1.30      lum       538:                        _exit(1);
1.32      florian   539:
                    540:                execv(path, argv);
                    541:                err = strerror(errno);
                    542:                write(s[1], err, strlen(err));
1.30      lum       543:                _exit(1);
                    544:        default:
                    545:                /* Parent process */
                    546:                close(s[1]);
1.32      florian   547:                return (iomux(s[0], text, len, outbp));
1.30      lum       548:        }
                    549:        return (FALSE);
                    550: }
                    551:
                    552: /*
1.32      florian   553:  * Multiplex read, write on socket fd passed. Put output in outbp
1.30      lum       554:  * Poll on the fd for both read and write readiness.
                    555:  */
                    556: int
1.32      florian   557: iomux(int fd, char* const text, int len, struct buffer *outbp)
1.30      lum       558: {
                    559:        struct pollfd pfd[1];
                    560:        int nfds;
1.32      florian   561:        char *textcopy;
1.31      florian   562:
1.30      lum       563:        textcopy = text;
                    564:        fcntl(fd, F_SETFL, O_NONBLOCK);
1.32      florian   565:        pfd[0].fd = fd;
                    566:
                    567:        /* There is nothing to write if len is zero
1.30      lum       568:         * but the cmd's output should be read so shutdown
1.32      florian   569:         * the socket for writing only and don't wait for POLLOUT
1.30      lum       570:         */
1.32      florian   571:        if (len == 0) {
1.30      lum       572:                shutdown(fd, SHUT_WR);
1.32      florian   573:                pfd[0].events = POLLIN;
                    574:        } else
                    575:                pfd[0].events = POLLIN | POLLOUT;
1.30      lum       576:
                    577:        while ((nfds = poll(pfd, 1, TIMEOUT)) != -1 ||
                    578:            (pfd[0].revents & (POLLERR | POLLHUP | POLLNVAL))) {
1.32      florian   579:                if (pfd[0].revents & POLLOUT && len > 0)
                    580:                        pwriteout(fd, &textcopy, &len);
1.30      lum       581:                else if (pfd[0].revents & POLLIN)
1.32      florian   582:                        if (preadin(fd, outbp) == FALSE)
1.30      lum       583:                                break;
1.32      florian   584:                if (len == 0 && pfd[0].events & POLLOUT)
                    585:                        pfd[0].events = POLLIN;
1.30      lum       586:        }
                    587:        close(fd);
1.32      florian   588:
1.30      lum       589:        /* In case if last line doesn't have a '\n' add the leftover
                    590:         * characters to buffer.
                    591:         */
                    592:        if (leftover[0] != '\0') {
1.32      florian   593:                addline(outbp, leftover);
1.30      lum       594:                leftover[0] = '\0';
                    595:        }
                    596:        if (nfds == 0) {
1.34    ! lum       597:                dobeep();
1.30      lum       598:                ewprintf("poll timed out");
                    599:                return (FALSE);
                    600:        } else if (nfds == -1) {
1.34    ! lum       601:                dobeep();
1.30      lum       602:                ewprintf("poll error");
                    603:                return (FALSE);
                    604:        }
1.32      florian   605:        return (popbuftop(outbp, WNONE));
1.30      lum       606: }
                    607:
                    608: /*
                    609:  * Write some text from region to fd. Once done shutdown the
                    610:  * write end.
                    611:  */
                    612: void
                    613: pwriteout(int fd, char **text, int *len)
                    614: {
                    615:        int w;
                    616:
                    617:        if (((w = send(fd, *text, *len, MSG_NOSIGNAL)) == -1)) {
                    618:                switch(errno) {
                    619:                case EPIPE:
                    620:                        *len = -1;
                    621:                        break;
                    622:                case EAGAIN:
                    623:                        return;
                    624:                }
                    625:        } else
                    626:                *len -= w;
                    627:
                    628:        *text += w;
                    629:        if (*len <= 0)
                    630:                shutdown(fd, SHUT_WR);
                    631: }
                    632:
                    633: /*
                    634:  * Read some data from socket fd, break on '\n' and add
                    635:  * to buffer. If couldn't break on newline hold leftover
                    636:  * characters and append in next iteration.
                    637:  */
                    638: int
                    639: preadin(int fd, struct buffer *bp)
                    640: {
                    641:        int len;
                    642:        char buf[BUFSIZ], *p, *q;
                    643:
1.32      florian   644:        if ((len = read(fd, buf, BUFSIZ - 1)) == 0)
1.30      lum       645:                return (FALSE);
1.32      florian   646:
1.30      lum       647:        buf[len] = '\0';
                    648:        p = q = buf;
                    649:        if (leftover[0] != '\0' && ((q = strchr(p, '\n')) != NULL)) {
                    650:                *q++ = '\0';
                    651:                if (strlcat(leftover, p, sizeof(leftover)) >=
                    652:                    sizeof(leftover)) {
1.34    ! lum       653:                        dobeep();
1.30      lum       654:                        ewprintf("line too long");
                    655:                        return (FALSE);
                    656:                }
                    657:                addline(bp, leftover);
                    658:                leftover[0] = '\0';
                    659:                p = q;
                    660:        }
                    661:        while ((q = strchr(p, '\n')) != NULL) {
                    662:                *q++ = '\0';
                    663:                addline(bp, p);
                    664:                p = q;
                    665:        }
                    666:        if (strlcpy(leftover, p, sizeof(leftover)) >= sizeof(leftover)) {
1.34    ! lum       667:                dobeep();
1.30      lum       668:                ewprintf("line too long");
                    669:                return (FALSE);
                    670:        }
                    671:        return (TRUE);
1.9       vincent   672: }