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

1.19    ! deraadt     1: /*     $OpenBSD: grep.c,v 1.18 2005/10/13 05:24:52 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.18      kjell      42: static BUFFER  *compile_mode(char *, char *, char *);
                     43: static int      getbufcwd(char *, size_t);
1.1       art        44:
                     45: void grep_init(void);
                     46:
1.8       vincent    47: static char compile_last_command[NFILEN] = "make ";
                     48:
1.1       art        49: /*
                     50:  * Hints for next-error
                     51:  *
                     52:  * XXX - need some kind of callback to find out when those get killed.
                     53:  */
1.13      db         54: MGWIN  *compile_win;
                     55: BUFFER *compile_buffer;
1.1       art        56:
                     57: static PF compile_pf[] = {
1.13      db         58:        compile_goto_error
1.1       art        59: };
                     60:
                     61: static struct KEYMAPE (1 + IMAPEXT) compilemap = {
                     62:        1,
                     63:        1 + IMAPEXT,
                     64:        rescan,
                     65:        {
1.13      db         66:                { CCHR('M'), CCHR('M'), compile_pf, NULL }
1.1       art        67:        }
                     68: };
                     69:
                     70: void
                     71: grep_init(void)
                     72: {
                     73:        funmap_add(compile_goto_error, "compile-goto-error");
                     74:        funmap_add(next_error, "next-error");
                     75:        funmap_add(grep, "grep");
                     76:        funmap_add(compile, "compile");
                     77:        funmap_add(gid, "gid");
                     78:        maps_add((KEYMAP *)&compilemap, "compile");
                     79: }
                     80:
                     81: static int
                     82: grep(int f, int n)
                     83: {
1.13      db         84:        char     command[NFILEN + 20];
                     85:        char     prompt[NFILEN], *bufp;
                     86:        BUFFER  *bp;
                     87:        MGWIN   *wp;
1.18      kjell      88:        char     path[NFILEN];
                     89:
                     90:        /* get buffer cwd */
                     91:        if (getbufcwd(path, sizeof(path)) == FALSE) {
                     92:                ewprintf("Failed. "
                     93:                    "Can't get working directory of current buffer.");
                     94:                return (FALSE);
                     95:        }
1.1       art        96:
1.13      db         97:        (void)strlcpy(prompt, "grep -n ", sizeof(prompt));
1.16      kjell      98:        if ((bufp = eread("Run grep: ", prompt, NFILEN,
                     99:            EFDEF | EFNEW | EFCR)) == NULL)
1.13      db        100:                return (ABORT);
1.16      kjell     101:        else if (bufp[0] == '\0')
                    102:                return (FALSE);
1.13      db        103:        (void)snprintf(command, sizeof(command), "%s /dev/null", bufp);
1.1       art       104:
1.18      kjell     105:        if ((bp = compile_mode("*grep*", command, path)) == NULL)
1.13      db        106:                return (FALSE);
1.1       art       107:        if ((wp = popbuf(bp)) == NULL)
1.13      db        108:                return (FALSE);
1.1       art       109:        curbp = bp;
                    110:        compile_win = curwp = wp;
1.13      db        111:        return (TRUE);
1.1       art       112: }
                    113:
                    114: static int
                    115: compile(int f, int n)
                    116: {
1.13      db        117:        char     command[NFILEN + 20];
                    118:        char     prompt[NFILEN], *bufp;
                    119:        BUFFER  *bp;
                    120:        MGWIN   *wp;
1.18      kjell     121:        char     path[NFILEN];
                    122:
                    123:        /* get buffer cwd */
                    124:        if (getbufcwd(path, sizeof(path)) == FALSE) {
                    125:                ewprintf("Failed. "
                    126:                    "Can't get working directory of current buffer.");
                    127:                return (FALSE);
                    128:        }
1.1       art       129:
1.13      db        130:        (void)strlcpy(prompt, compile_last_command, sizeof(prompt));
1.16      kjell     131:        if ((bufp = eread("Compile command: ", prompt, NFILEN,
                    132:            EFDEF | EFNEW | EFCR)) == NULL)
1.14      jason     133:                return (ABORT);
1.16      kjell     134:        else if (bufp[0] == '\0')
                    135:                return (FALSE);
1.14      jason     136:        if (savebuffers(f, n) == ABORT)
1.13      db        137:                return (ABORT);
                    138:        (void)strlcpy(compile_last_command, bufp, sizeof(compile_last_command));
1.1       art       139:
1.13      db        140:        (void)snprintf(command, sizeof(command), "%s 2>&1", bufp);
1.1       art       141:
1.18      kjell     142:        if ((bp = compile_mode("*compile*", command, path)) == NULL)
1.13      db        143:                return (FALSE);
1.1       art       144:        if ((wp = popbuf(bp)) == NULL)
1.13      db        145:                return (FALSE);
1.1       art       146:        curbp = bp;
                    147:        compile_win = curwp = wp;
1.13      db        148:        return (TRUE);
1.1       art       149: }
                    150:
                    151: /* id-utils foo. */
                    152: static int
                    153: gid(int f, int n)
                    154: {
1.13      db        155:        char     command[NFILEN + 20];
                    156:        char     prompt[NFILEN], c, *bufp;
                    157:        BUFFER  *bp;
                    158:        MGWIN   *wp;
                    159:        int      i, j;
1.18      kjell     160:        char     path[NFILEN];
                    161:
                    162:        /* get buffer cwd */
                    163:        if (getbufcwd(path, sizeof(path)) == FALSE) {
                    164:                ewprintf("Failed. "
                    165:                    "Can't get working directory of current buffer.");
                    166:                return (FALSE);
                    167:        }
1.1       art       168:
1.11      vincent   169:        /* catch ([^\s(){}]+)[\s(){}]* */
                    170:
                    171:        i = curwp->w_doto;
1.15      cloder    172:        /* Skip backwards over delimiters we are currently on */
                    173:        while (i > 0) {
                    174:                c = lgetc(curwp->w_dotp, i);
                    175:                if (isalnum(c) || c == '_')
                    176:                        break;
                    177:
1.11      vincent   178:                i--;
1.15      cloder    179:        }
                    180:
1.11      vincent   181:        /* Skip the symbol itself */
                    182:        for (; i > 0; i--) {
                    183:                c = lgetc(curwp->w_dotp, i - 1);
1.15      cloder    184:                if (!isalnum(c) && c != '_')
1.11      vincent   185:                        break;
                    186:        }
                    187:        /* Fill the symbol in prompt[] */
                    188:        for (j = 0; j < sizeof(prompt) - 1 && i < llength(curwp->w_dotp);
                    189:            j++, i++) {
                    190:                c = lgetc(curwp->w_dotp, i);
1.15      cloder    191:                if (!isalnum(c) && c != '_')
1.11      vincent   192:                        break;
                    193:                prompt[j] = c;
                    194:        }
                    195:        prompt[j] = '\0';
                    196:
1.12      vincent   197:        if ((bufp = eread("Run gid (with args): ", prompt, NFILEN,
1.16      kjell     198:            (j ? EFDEF : 0) | EFNEW | EFCR)) == NULL)
1.13      db        199:                return (ABORT);
1.16      kjell     200:        else if (bufp[0] == '\0')
                    201:                return (FALSE);
1.13      db        202:        (void)snprintf(command, sizeof(command), "gid %s", prompt);
1.1       art       203:
1.18      kjell     204:        if ((bp = compile_mode("*gid*", command, path)) == NULL)
1.13      db        205:                return (FALSE);
1.1       art       206:        if ((wp = popbuf(bp)) == NULL)
1.13      db        207:                return (FALSE);
1.1       art       208:        curbp = bp;
                    209:        compile_win = curwp = wp;
1.13      db        210:        return (TRUE);
1.1       art       211: }
                    212:
                    213: BUFFER *
1.18      kjell     214: compile_mode(char *name, char *command, char *path)
1.1       art       215: {
1.13      db        216:        BUFFER  *bp;
                    217:        FILE    *pipe;
                    218:        char    *buf;
                    219:        size_t   len;
                    220:        int      ret;
1.19    ! deraadt   221:        char    *wdir, cwd[NFILEN];
1.18      kjell     222:        char     timestr[NTIME];
                    223:        time_t   t;
1.1       art       224:
                    225:        bp = bfind(name, TRUE);
                    226:        if (bclear(bp) != TRUE)
1.13      db        227:                return (NULL);
1.1       art       228:
1.18      kjell     229:        addlinef(bp, "cd %s", path);
                    230:        addline(bp, command);
1.1       art       231:        addline(bp, "");
                    232:
1.18      kjell     233:        if ((wdir = getcwd(cwd, sizeof(cwd))) == NULL)
                    234:                panic("Can't get current directory!");
                    235:        if (chdir(path) == -1) {
                    236:                ewprintf("Can't change dir to %s", path);
                    237:                return (NULL);
1.19    ! deraadt   238:        }
1.1       art       239:        if ((pipe = popen(command, "r")) == NULL) {
                    240:                ewprintf("Problem opening pipe");
1.13      db        241:                return (NULL);
1.1       art       242:        }
                    243:        /*
                    244:         * We know that our commands are nice and the last line will end with
                    245:         * a \n, so we don't need to try to deal with the last line problem
                    246:         * in fgetln.
                    247:         */
                    248:        while ((buf = fgetln(pipe, &len)) != NULL) {
                    249:                buf[len - 1] = '\0';
                    250:                addline(bp, buf);
                    251:        }
                    252:        ret = pclose(pipe);
1.18      kjell     253:        t = time(NULL);
                    254:        strftime(timestr, sizeof(timestr), "%a %b %e %T %Y", localtime(&t));
1.1       art       255:        addline(bp, "");
1.18      kjell     256:        if (ret != 0)
                    257:                addlinef(bp, "Command exited abnormally with code %d"
                    258:                    " at %s", ret, timestr);
                    259:        else
                    260:                addlinef(bp, "Command finished at %s", timestr);
                    261:
1.1       art       262:        bp->b_dotp = lforw(bp->b_linep);        /* go to first line */
                    263:        bp->b_modes[0] = name_mode("fundamental");
                    264:        bp->b_modes[1] = name_mode("compile");
                    265:        bp->b_nmodes = 1;
                    266:
                    267:        compile_buffer = bp;
                    268:
1.18      kjell     269:        if (chdir(cwd) == -1) {
                    270:                ewprintf("Can't change dir back to %s", cwd);
                    271:                return (NULL);
1.19    ! deraadt   272:        }
1.13      db        273:        return (bp);
1.1       art       274: }
                    275:
                    276: static int
                    277: compile_goto_error(int f, int n)
                    278: {
1.13      db        279:        BUFFER  *bp;
                    280:        MGWIN   *wp;
                    281:        char    *fname, *line, *lp, *ln, *lp1;
                    282:        int      lineno, len;
                    283:        char    *adjf;
1.1       art       284:
                    285:        compile_win = curwp;
                    286:        compile_buffer = curbp;
                    287:
                    288: retry:
                    289:        len = llength(curwp->w_dotp);
                    290:
                    291:        if ((line = malloc(len + 1)) == NULL)
1.13      db        292:                return (FALSE);
1.1       art       293:
1.6       vincent   294:        (void)memcpy(line, curwp->w_dotp->l_text, len);
1.1       art       295:        line[len] = '\0';
                    296:
                    297:        lp = line;
                    298:        if ((fname = strsep(&lp, ":")) == NULL)
                    299:                goto fail;
                    300:        if ((ln = strsep(&lp, ":")) == NULL)
                    301:                goto fail;
                    302:        lineno = strtol(ln, &lp1, 10);
                    303:        if (lp != lp1 + 1)
                    304:                goto fail;
1.10      vincent   305:
                    306:        adjf = adjustname(fname);
1.1       art       307:        free(line);
                    308:
1.7       vincent   309:        if (adjf == NULL)
                    310:                return (FALSE);
1.10      vincent   311:
1.1       art       312:        if ((bp = findbuffer(adjf)) == NULL)
1.13      db        313:                return (FALSE);
1.1       art       314:        if ((wp = popbuf(bp)) == NULL)
1.13      db        315:                return (FALSE);
1.1       art       316:        curbp = bp;
                    317:        curwp = wp;
                    318:        if (bp->b_fname[0] == 0)
                    319:                readin(adjf);
                    320:        gotoline(FFARG, lineno);
1.13      db        321:        return (TRUE);
1.1       art       322: fail:
1.3       deraadt   323:        free(line);
1.1       art       324:        if (curwp->w_dotp != lback(curbp->b_linep)) {
                    325:                curwp->w_dotp = lforw(curwp->w_dotp);
                    326:                curwp->w_flag |= WFMOVE;
                    327:                goto retry;
                    328:        }
                    329:        ewprintf("No more hits");
1.13      db        330:        return (FALSE);
1.1       art       331: }
                    332:
1.17      kjell     333: int
1.1       art       334: next_error(int f, int n)
                    335: {
                    336:        if (compile_win == NULL || compile_buffer == NULL) {
                    337:                ewprintf("No compilation active");
1.13      db        338:                return (FALSE);
1.1       art       339:        }
                    340:        curwp = compile_win;
                    341:        curbp = compile_buffer;
                    342:        if (curwp->w_dotp == lback(curbp->b_linep)) {
                    343:                ewprintf("No more hits");
1.13      db        344:                return (FALSE);
1.1       art       345:        }
                    346:        curwp->w_dotp = lforw(curwp->w_dotp);
                    347:        curwp->w_flag |= WFMOVE;
                    348:
1.13      db        349:        return (compile_goto_error(f, n));
1.18      kjell     350: }
                    351:
                    352: /*
                    353:  * Return the working directory for the current buffer, terminated
                    354:  * with a '/'. First, try to extract it from the current buffer's
                    355:  * filename. If that fails, use global cwd.
                    356:  */
                    357: static int
                    358: getbufcwd(char *path, size_t plen)
                    359: {
                    360:        char *dname, cwd[NFILEN];
                    361:        if (plen == 0)
                    362:                goto error;
                    363:
                    364:        if (curbp->b_fname && curbp->b_fname[0] != '\0' &&
                    365:            (dname = dirname(curbp->b_fname)) != NULL) {
                    366:                if (strlcpy(path, dname, plen) >= plen)
                    367:                        goto error;
                    368:                if (strlcat(path, "/", plen) >= plen)
                    369:                        goto error;
                    370:        } else {
                    371:                if ((dname = getcwd(cwd, sizeof(cwd))) == NULL)
                    372:                        goto error;
                    373:                if (strlcpy(path, dname, plen) >= plen)
                    374:                        goto error;
                    375:        }
                    376:        return (TRUE);
                    377: error:
                    378:        path = NULL;
                    379:        return (FALSE);
1.1       art       380: }