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

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