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

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