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

Annotation of src/usr.bin/mg/grep.c, Revision 1.26

1.26    ! kjell       1: /*     $OpenBSD: grep.c,v 1.25 2005/12/13 02:08:06 kjell Exp $ */
1.1       art         2: /*
1.18      kjell       3:  * Copyright (c) 2001 Artur Grabowski <art@openbsd.org>.
                      4:  * Copyright (c) 2005 Kjell Wooding <kjell@openbsd.org>.
                      5:  * All rights reserved.
1.1       art         6:  *
                      7:  * Redistribution and use in source and binary forms, with or without
                      8:  * modification, are permitted provided that the following conditions
                      9:  * are met:
                     10:  * 1. Redistributions of source code must retain the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer.
                     12:  * 2. Redistributions in binary form must reproduce the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer in the
                     14:  *    documentation and/or other materials provided with the distribution.
                     15:  *
                     16:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     17:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
                     18:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
                     19:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
                     20:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
                     21:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
                     22:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
                     23:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
                     24:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
                     25:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     26:  */
                     27:
                     28: #include "def.h"
                     29: #include "kbd.h"
                     30: #include "funmap.h"
                     31:
1.18      kjell      32: #include <sys/types.h>
1.11      vincent    33: #include <ctype.h>
1.18      kjell      34: #include <libgen.h>
                     35: #include <time.h>
1.11      vincent    36:
1.13      db         37: static int      compile_goto_error(int, int);
1.17      kjell      38: int             next_error(int, int);
1.13      db         39: static int      grep(int, int);
                     40: static int      compile(int, int);
                     41: static int      gid(int, int);
1.24      deraadt    42: static struct buffer   *compile_mode(const char *, const char *, const char *);
1.18      kjell      43: static int      getbufcwd(char *, size_t);
1.25      kjell      44: static int      xlint(int, int);
1.1       art        45:
                     46: void grep_init(void);
                     47:
1.8       vincent    48: static char compile_last_command[NFILEN] = "make ";
                     49:
1.1       art        50: /*
                     51:  * Hints for next-error
                     52:  *
                     53:  * XXX - need some kind of callback to find out when those get killed.
                     54:  */
1.24      deraadt    55: struct mgwin   *compile_win;
                     56: struct buffer  *compile_buffer;
1.1       art        57:
                     58: static PF compile_pf[] = {
1.13      db         59:        compile_goto_error
1.1       art        60: };
                     61:
                     62: static struct KEYMAPE (1 + IMAPEXT) compilemap = {
                     63:        1,
                     64:        1 + IMAPEXT,
                     65:        rescan,
                     66:        {
1.13      db         67:                { CCHR('M'), CCHR('M'), compile_pf, NULL }
1.1       art        68:        }
                     69: };
                     70:
                     71: void
                     72: grep_init(void)
                     73: {
                     74:        funmap_add(compile_goto_error, "compile-goto-error");
                     75:        funmap_add(next_error, "next-error");
                     76:        funmap_add(grep, "grep");
1.25      kjell      77:        funmap_add(xlint, "lint");
1.1       art        78:        funmap_add(compile, "compile");
                     79:        funmap_add(gid, "gid");
                     80:        maps_add((KEYMAP *)&compilemap, "compile");
                     81: }
                     82:
1.20      kjell      83: /* ARGSUSED */
1.1       art        84: static int
                     85: grep(int f, int n)
                     86: {
1.25      kjell      87:        char     command[NFILEN + 21];
                     88:        char     cprompt[NFILEN], *bufp;
1.24      deraadt    89:        struct buffer   *bp;
                     90:        struct mgwin    *wp;
1.18      kjell      91:        char     path[NFILEN];
                     92:
                     93:        /* get buffer cwd */
                     94:        if (getbufcwd(path, sizeof(path)) == FALSE) {
                     95:                ewprintf("Failed. "
                     96:                    "Can't get working directory of current buffer.");
                     97:                return (FALSE);
                     98:        }
1.1       art        99:
1.25      kjell     100:        (void)strlcpy(cprompt, "grep -n ", sizeof(cprompt));
                    101:        if ((bufp = eread("Run grep: ", cprompt, NFILEN,
1.16      kjell     102:            EFDEF | EFNEW | EFCR)) == NULL)
1.13      db        103:                return (ABORT);
1.16      kjell     104:        else if (bufp[0] == '\0')
                    105:                return (FALSE);
1.13      db        106:        (void)snprintf(command, sizeof(command), "%s /dev/null", bufp);
1.1       art       107:
1.18      kjell     108:        if ((bp = compile_mode("*grep*", command, path)) == NULL)
1.13      db        109:                return (FALSE);
1.1       art       110:        if ((wp = popbuf(bp)) == NULL)
1.13      db        111:                return (FALSE);
1.1       art       112:        curbp = bp;
                    113:        compile_win = curwp = wp;
1.13      db        114:        return (TRUE);
1.1       art       115: }
                    116:
1.20      kjell     117: /* ARGSUSED */
1.1       art       118: static int
1.25      kjell     119: xlint(int f, int n)
                    120: {
                    121:        char     command[NFILEN + 16];
                    122:        char     cprompt[NFILEN], *bufp;
                    123:        struct buffer   *bp;
                    124:        struct mgwin    *wp;
                    125:        char     path[NFILEN];
                    126:
                    127:        /* get buffer cwd */
                    128:        if (getbufcwd(path, sizeof(path)) == FALSE) {
                    129:                ewprintf("Failed. "
                    130:                    "Can't get working directory of current buffer.");
                    131:                return (FALSE);
                    132:        }
                    133:
                    134:        (void)strlcpy(cprompt, "make lint ", sizeof(cprompt));
                    135:        if ((bufp = eread("Run lint: ", cprompt, NFILEN,
                    136:            EFDEF | EFNEW | EFCR)) == NULL)
                    137:                return (ABORT);
                    138:        else if (bufp[0] == '\0')
                    139:                return (FALSE);
                    140:        (void)snprintf(command, sizeof(command), "%s 2>&1", bufp);
                    141:
                    142:        if ((bp = compile_mode("*lint*", command, path)) == NULL)
                    143:                return (FALSE);
                    144:        if ((wp = popbuf(bp)) == NULL)
                    145:                return (FALSE);
                    146:        curbp = bp;
                    147:        compile_win = curwp = wp;
                    148:        return (TRUE);
                    149: }
                    150:
                    151: /* ARGSUSED */
                    152: static int
1.1       art       153: compile(int f, int n)
                    154: {
1.13      db        155:        char     command[NFILEN + 20];
1.25      kjell     156:        char     cprompt[NFILEN], *bufp;
1.24      deraadt   157:        struct buffer   *bp;
                    158:        struct mgwin    *wp;
1.18      kjell     159:        char     path[NFILEN];
                    160:
                    161:        /* get buffer cwd */
                    162:        if (getbufcwd(path, sizeof(path)) == FALSE) {
                    163:                ewprintf("Failed. "
                    164:                    "Can't get working directory of current buffer.");
                    165:                return (FALSE);
                    166:        }
1.1       art       167:
1.25      kjell     168:        (void)strlcpy(cprompt, compile_last_command, sizeof(cprompt));
                    169:        if ((bufp = eread("Compile command: ", cprompt, NFILEN,
1.16      kjell     170:            EFDEF | EFNEW | EFCR)) == NULL)
1.14      jason     171:                return (ABORT);
1.16      kjell     172:        else if (bufp[0] == '\0')
                    173:                return (FALSE);
1.14      jason     174:        if (savebuffers(f, n) == ABORT)
1.13      db        175:                return (ABORT);
                    176:        (void)strlcpy(compile_last_command, bufp, sizeof(compile_last_command));
1.1       art       177:
1.13      db        178:        (void)snprintf(command, sizeof(command), "%s 2>&1", bufp);
1.1       art       179:
1.18      kjell     180:        if ((bp = compile_mode("*compile*", command, path)) == NULL)
1.13      db        181:                return (FALSE);
1.1       art       182:        if ((wp = popbuf(bp)) == NULL)
1.13      db        183:                return (FALSE);
1.1       art       184:        curbp = bp;
                    185:        compile_win = curwp = wp;
1.13      db        186:        return (TRUE);
1.1       art       187: }
                    188:
                    189: /* id-utils foo. */
1.20      kjell     190: /* ARGSUSED */
1.1       art       191: static int
                    192: gid(int f, int n)
                    193: {
1.13      db        194:        char     command[NFILEN + 20];
1.25      kjell     195:        char     cprompt[NFILEN], c, *bufp;
1.24      deraadt   196:        struct buffer   *bp;
                    197:        struct mgwin    *wp;
1.13      db        198:        int      i, j;
1.18      kjell     199:        char     path[NFILEN];
                    200:
                    201:        /* get buffer cwd */
                    202:        if (getbufcwd(path, sizeof(path)) == FALSE) {
                    203:                ewprintf("Failed. "
                    204:                    "Can't get working directory of current buffer.");
                    205:                return (FALSE);
                    206:        }
1.1       art       207:
1.11      vincent   208:        /* catch ([^\s(){}]+)[\s(){}]* */
                    209:
                    210:        i = curwp->w_doto;
1.15      cloder    211:        /* Skip backwards over delimiters we are currently on */
                    212:        while (i > 0) {
                    213:                c = lgetc(curwp->w_dotp, i);
                    214:                if (isalnum(c) || c == '_')
                    215:                        break;
                    216:
1.11      vincent   217:                i--;
1.15      cloder    218:        }
                    219:
1.11      vincent   220:        /* Skip the symbol itself */
                    221:        for (; i > 0; i--) {
                    222:                c = lgetc(curwp->w_dotp, i - 1);
1.15      cloder    223:                if (!isalnum(c) && c != '_')
1.11      vincent   224:                        break;
                    225:        }
1.25      kjell     226:        /* Fill the symbol in cprompt[] */
                    227:        for (j = 0; j < sizeof(cprompt) - 1 && i < llength(curwp->w_dotp);
1.11      vincent   228:            j++, i++) {
                    229:                c = lgetc(curwp->w_dotp, i);
1.15      cloder    230:                if (!isalnum(c) && c != '_')
1.11      vincent   231:                        break;
1.25      kjell     232:                cprompt[j] = c;
1.11      vincent   233:        }
1.25      kjell     234:        cprompt[j] = '\0';
1.11      vincent   235:
1.25      kjell     236:        if ((bufp = eread("Run gid (with args): ", cprompt, NFILEN,
1.16      kjell     237:            (j ? EFDEF : 0) | EFNEW | EFCR)) == NULL)
1.13      db        238:                return (ABORT);
1.16      kjell     239:        else if (bufp[0] == '\0')
                    240:                return (FALSE);
1.25      kjell     241:        (void)snprintf(command, sizeof(command), "gid %s", cprompt);
1.1       art       242:
1.18      kjell     243:        if ((bp = compile_mode("*gid*", command, path)) == NULL)
1.13      db        244:                return (FALSE);
1.1       art       245:        if ((wp = popbuf(bp)) == NULL)
1.13      db        246:                return (FALSE);
1.1       art       247:        curbp = bp;
                    248:        compile_win = curwp = wp;
1.13      db        249:        return (TRUE);
1.1       art       250: }
                    251:
1.24      deraadt   252: struct buffer *
1.21      kjell     253: compile_mode(const char *name, const char *command, const char *path)
1.1       art       254: {
1.24      deraadt   255:        struct buffer   *bp;
1.26    ! kjell     256:        FILE    *fpipe;
1.13      db        257:        char    *buf;
                    258:        size_t   len;
                    259:        int      ret;
1.23      deraadt   260:        char     cwd[NFILEN];
1.18      kjell     261:        char     timestr[NTIME];
                    262:        time_t   t;
1.1       art       263:
                    264:        bp = bfind(name, TRUE);
                    265:        if (bclear(bp) != TRUE)
1.13      db        266:                return (NULL);
1.1       art       267:
1.18      kjell     268:        addlinef(bp, "cd %s", path);
                    269:        addline(bp, command);
1.1       art       270:        addline(bp, "");
                    271:
1.23      deraadt   272:        if (getcwd(cwd, sizeof(cwd)) == NULL)
1.18      kjell     273:                panic("Can't get current directory!");
                    274:        if (chdir(path) == -1) {
                    275:                ewprintf("Can't change dir to %s", path);
                    276:                return (NULL);
1.19      deraadt   277:        }
1.26    ! kjell     278:        if ((fpipe = popen(command, "r")) == NULL) {
1.1       art       279:                ewprintf("Problem opening pipe");
1.13      db        280:                return (NULL);
1.1       art       281:        }
                    282:        /*
                    283:         * We know that our commands are nice and the last line will end with
                    284:         * a \n, so we don't need to try to deal with the last line problem
                    285:         * in fgetln.
                    286:         */
1.26    ! kjell     287:        while ((buf = fgetln(fpipe, &len)) != NULL) {
1.1       art       288:                buf[len - 1] = '\0';
                    289:                addline(bp, buf);
                    290:        }
1.26    ! kjell     291:        ret = pclose(fpipe);
1.18      kjell     292:        t = time(NULL);
                    293:        strftime(timestr, sizeof(timestr), "%a %b %e %T %Y", localtime(&t));
1.1       art       294:        addline(bp, "");
1.18      kjell     295:        if (ret != 0)
                    296:                addlinef(bp, "Command exited abnormally with code %d"
                    297:                    " at %s", ret, timestr);
                    298:        else
                    299:                addlinef(bp, "Command finished at %s", timestr);
                    300:
1.1       art       301:        bp->b_dotp = lforw(bp->b_linep);        /* go to first line */
                    302:        bp->b_modes[0] = name_mode("fundamental");
                    303:        bp->b_modes[1] = name_mode("compile");
                    304:        bp->b_nmodes = 1;
                    305:
                    306:        compile_buffer = bp;
                    307:
1.18      kjell     308:        if (chdir(cwd) == -1) {
                    309:                ewprintf("Can't change dir back to %s", cwd);
                    310:                return (NULL);
1.19      deraadt   311:        }
1.13      db        312:        return (bp);
1.1       art       313: }
                    314:
1.20      kjell     315: /* ARGSUSED */
1.1       art       316: static int
                    317: compile_goto_error(int f, int n)
                    318: {
1.24      deraadt   319:        struct buffer   *bp;
                    320:        struct mgwin    *wp;
1.21      kjell     321:        char    *fname, *line, *lp, *ln;
1.13      db        322:        int      lineno, len;
                    323:        char    *adjf;
1.21      kjell     324:        const char *errstr;
1.24      deraadt   325:        struct line     *last;
1.1       art       326:
                    327:        compile_win = curwp;
                    328:        compile_buffer = curbp;
1.21      kjell     329:        last = lback(compile_buffer->b_linep);
1.22      deraadt   330:
1.21      kjell     331:  retry:
                    332:        /* last line is compilation result */
                    333:        if (curwp->w_dotp == last)
                    334:                return (FALSE);
1.1       art       335:
                    336:        len = llength(curwp->w_dotp);
                    337:
                    338:        if ((line = malloc(len + 1)) == NULL)
1.13      db        339:                return (FALSE);
1.1       art       340:
1.6       vincent   341:        (void)memcpy(line, curwp->w_dotp->l_text, len);
1.1       art       342:        line[len] = '\0';
                    343:
                    344:        lp = line;
1.21      kjell     345:        if ((fname = strsep(&lp, ":")) == NULL || *fname == '\0')
1.1       art       346:                goto fail;
1.21      kjell     347:        if ((ln = strsep(&lp, ":")) == NULL || *ln == '\0')
1.1       art       348:                goto fail;
1.24      deraadt   349:        lineno = (int)strtonum(ln, INT_MIN, INT_MAX, &errstr);
1.21      kjell     350:        if (errstr)
1.1       art       351:                goto fail;
1.10      vincent   352:
                    353:        adjf = adjustname(fname);
1.1       art       354:        free(line);
                    355:
1.7       vincent   356:        if (adjf == NULL)
                    357:                return (FALSE);
1.10      vincent   358:
1.1       art       359:        if ((bp = findbuffer(adjf)) == NULL)
1.13      db        360:                return (FALSE);
1.1       art       361:        if ((wp = popbuf(bp)) == NULL)
1.13      db        362:                return (FALSE);
1.1       art       363:        curbp = bp;
                    364:        curwp = wp;
                    365:        if (bp->b_fname[0] == 0)
                    366:                readin(adjf);
                    367:        gotoline(FFARG, lineno);
1.13      db        368:        return (TRUE);
1.1       art       369: fail:
1.3       deraadt   370:        free(line);
1.1       art       371:        if (curwp->w_dotp != lback(curbp->b_linep)) {
                    372:                curwp->w_dotp = lforw(curwp->w_dotp);
                    373:                curwp->w_flag |= WFMOVE;
                    374:                goto retry;
                    375:        }
                    376:        ewprintf("No more hits");
1.13      db        377:        return (FALSE);
1.1       art       378: }
                    379:
1.20      kjell     380: /* ARGSUSED */
1.17      kjell     381: int
1.1       art       382: next_error(int f, int n)
                    383: {
                    384:        if (compile_win == NULL || compile_buffer == NULL) {
                    385:                ewprintf("No compilation active");
1.13      db        386:                return (FALSE);
1.1       art       387:        }
                    388:        curwp = compile_win;
                    389:        curbp = compile_buffer;
                    390:        if (curwp->w_dotp == lback(curbp->b_linep)) {
                    391:                ewprintf("No more hits");
1.13      db        392:                return (FALSE);
1.1       art       393:        }
                    394:        curwp->w_dotp = lforw(curwp->w_dotp);
                    395:        curwp->w_flag |= WFMOVE;
                    396:
1.13      db        397:        return (compile_goto_error(f, n));
1.18      kjell     398: }
                    399:
                    400: /*
                    401:  * Return the working directory for the current buffer, terminated
                    402:  * with a '/'. First, try to extract it from the current buffer's
                    403:  * filename. If that fails, use global cwd.
                    404:  */
                    405: static int
                    406: getbufcwd(char *path, size_t plen)
                    407: {
                    408:        char *dname, cwd[NFILEN];
                    409:        if (plen == 0)
                    410:                goto error;
                    411:
                    412:        if (curbp->b_fname && curbp->b_fname[0] != '\0' &&
                    413:            (dname = dirname(curbp->b_fname)) != NULL) {
                    414:                if (strlcpy(path, dname, plen) >= plen)
                    415:                        goto error;
                    416:                if (strlcat(path, "/", plen) >= plen)
                    417:                        goto error;
                    418:        } else {
                    419:                if ((dname = getcwd(cwd, sizeof(cwd))) == NULL)
                    420:                        goto error;
                    421:                if (strlcpy(path, dname, plen) >= plen)
                    422:                        goto error;
                    423:        }
                    424:        return (TRUE);
                    425: error:
                    426:        path = NULL;
                    427:        return (FALSE);
1.1       art       428: }