Annotation of src/usr.bin/mg/grep.c, Revision 1.34
1.34 ! kjell 1: /* $OpenBSD: grep.c,v 1.33 2006/11/19 16:51:19 deraadt 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.34 ! kjell 37: int globalwd = FALSE;
1.13 db 38: static int compile_goto_error(int, int);
1.17 kjell 39: int next_error(int, int);
1.13 db 40: static int grep(int, int);
41: static int compile(int, int);
42: static int gid(int, int);
1.28 kjell 43: static struct buffer *compile_mode(const char *, const char *);
1.25 kjell 44: static int xlint(int, int);
1.1 art 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.24 deraadt 54: struct mgwin *compile_win;
55: struct 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");
1.25 kjell 76: funmap_add(xlint, "lint");
1.1 art 77: funmap_add(compile, "compile");
78: funmap_add(gid, "gid");
79: maps_add((KEYMAP *)&compilemap, "compile");
80: }
81:
1.20 kjell 82: /* ARGSUSED */
1.1 art 83: static int
84: grep(int f, int n)
85: {
1.25 kjell 86: char cprompt[NFILEN], *bufp;
1.24 deraadt 87: struct buffer *bp;
88: struct mgwin *wp;
1.1 art 89:
1.25 kjell 90: (void)strlcpy(cprompt, "grep -n ", sizeof(cprompt));
91: if ((bufp = eread("Run grep: ", cprompt, NFILEN,
1.16 kjell 92: EFDEF | EFNEW | EFCR)) == NULL)
1.13 db 93: return (ABORT);
1.16 kjell 94: else if (bufp[0] == '\0')
95: return (FALSE);
1.29 kjell 96: if (strlcat(cprompt, " /dev/null", sizeof(cprompt)) >= sizeof(cprompt))
97: return (FALSE);
1.1 art 98:
1.29 kjell 99: if ((bp = compile_mode("*grep*", cprompt)) == NULL)
1.13 db 100: return (FALSE);
1.1 art 101: if ((wp = popbuf(bp)) == NULL)
1.13 db 102: return (FALSE);
1.1 art 103: curbp = bp;
104: compile_win = curwp = wp;
1.13 db 105: return (TRUE);
1.1 art 106: }
107:
1.20 kjell 108: /* ARGSUSED */
1.1 art 109: static int
1.25 kjell 110: xlint(int f, int n)
111: {
112: char cprompt[NFILEN], *bufp;
113: struct buffer *bp;
114: struct mgwin *wp;
115:
116: (void)strlcpy(cprompt, "make lint ", sizeof(cprompt));
117: if ((bufp = eread("Run lint: ", cprompt, NFILEN,
118: EFDEF | EFNEW | EFCR)) == NULL)
119: return (ABORT);
120: else if (bufp[0] == '\0')
121: return (FALSE);
122:
1.29 kjell 123: if ((bp = compile_mode("*lint*", cprompt)) == NULL)
1.25 kjell 124: return (FALSE);
125: if ((wp = popbuf(bp)) == NULL)
126: return (FALSE);
127: curbp = bp;
128: compile_win = curwp = wp;
129: return (TRUE);
130: }
131:
132: /* ARGSUSED */
133: static int
1.1 art 134: compile(int f, int n)
135: {
1.25 kjell 136: char cprompt[NFILEN], *bufp;
1.24 deraadt 137: struct buffer *bp;
138: struct mgwin *wp;
1.1 art 139:
1.25 kjell 140: (void)strlcpy(cprompt, compile_last_command, sizeof(cprompt));
141: if ((bufp = eread("Compile command: ", cprompt, NFILEN,
1.16 kjell 142: EFDEF | EFNEW | EFCR)) == NULL)
1.14 jason 143: return (ABORT);
1.16 kjell 144: else if (bufp[0] == '\0')
145: return (FALSE);
1.14 jason 146: if (savebuffers(f, n) == ABORT)
1.13 db 147: return (ABORT);
148: (void)strlcpy(compile_last_command, bufp, sizeof(compile_last_command));
1.1 art 149:
1.29 kjell 150: if ((bp = compile_mode("*compile*", cprompt)) == NULL)
1.13 db 151: return (FALSE);
1.1 art 152: if ((wp = popbuf(bp)) == NULL)
1.13 db 153: return (FALSE);
1.1 art 154: curbp = bp;
155: compile_win = curwp = wp;
1.27 kjell 156: gotoline(FFARG, 0);
1.13 db 157: return (TRUE);
1.1 art 158: }
159:
160: /* id-utils foo. */
1.20 kjell 161: /* ARGSUSED */
1.1 art 162: static int
163: gid(int f, int n)
164: {
1.29 kjell 165: char command[NFILEN];
1.25 kjell 166: char cprompt[NFILEN], c, *bufp;
1.24 deraadt 167: struct buffer *bp;
168: struct mgwin *wp;
1.29 kjell 169: int i, j, len;
1.1 art 170:
1.11 vincent 171: /* catch ([^\s(){}]+)[\s(){}]* */
172:
173: i = curwp->w_doto;
1.15 cloder 174: /* Skip backwards over delimiters we are currently on */
175: while (i > 0) {
176: c = lgetc(curwp->w_dotp, i);
177: if (isalnum(c) || c == '_')
178: break;
179:
1.11 vincent 180: i--;
1.15 cloder 181: }
182:
1.11 vincent 183: /* Skip the symbol itself */
184: for (; i > 0; i--) {
185: c = lgetc(curwp->w_dotp, i - 1);
1.15 cloder 186: if (!isalnum(c) && c != '_')
1.11 vincent 187: break;
188: }
1.25 kjell 189: /* Fill the symbol in cprompt[] */
190: for (j = 0; j < sizeof(cprompt) - 1 && i < llength(curwp->w_dotp);
1.11 vincent 191: j++, i++) {
192: c = lgetc(curwp->w_dotp, i);
1.15 cloder 193: if (!isalnum(c) && c != '_')
1.11 vincent 194: break;
1.25 kjell 195: cprompt[j] = c;
1.11 vincent 196: }
1.25 kjell 197: cprompt[j] = '\0';
1.11 vincent 198:
1.25 kjell 199: if ((bufp = eread("Run gid (with args): ", cprompt, NFILEN,
1.16 kjell 200: (j ? EFDEF : 0) | EFNEW | EFCR)) == NULL)
1.13 db 201: return (ABORT);
1.16 kjell 202: else if (bufp[0] == '\0')
203: return (FALSE);
1.29 kjell 204: len = snprintf(command, sizeof(command), "gid %s", cprompt);
205: if (len < 0 || len >= sizeof(command))
206: return (FALSE);
1.1 art 207:
1.28 kjell 208: if ((bp = compile_mode("*gid*", command)) == NULL)
1.13 db 209: return (FALSE);
1.1 art 210: if ((wp = popbuf(bp)) == NULL)
1.13 db 211: return (FALSE);
1.1 art 212: curbp = bp;
213: compile_win = curwp = wp;
1.13 db 214: return (TRUE);
1.1 art 215: }
216:
1.24 deraadt 217: struct buffer *
1.28 kjell 218: compile_mode(const char *name, const char *command)
1.1 art 219: {
1.24 deraadt 220: struct buffer *bp;
1.26 kjell 221: FILE *fpipe;
1.13 db 222: char *buf;
223: size_t len;
1.29 kjell 224: int ret, n;
225: char cwd[NFILEN], qcmd[NFILEN];
1.18 kjell 226: char timestr[NTIME];
227: time_t t;
1.1 art 228:
1.29 kjell 229: n = snprintf(qcmd, sizeof(qcmd), "%s 2>&1", command);
230: if (n < 0 || n >= sizeof(qcmd))
231: return (NULL);
232:
1.1 art 233: bp = bfind(name, TRUE);
234: if (bclear(bp) != TRUE)
1.13 db 235: return (NULL);
1.1 art 236:
1.28 kjell 237: if (getbufcwd(bp->b_cwd, sizeof(bp->b_cwd)) != TRUE)
238: return (NULL);
239: addlinef(bp, "cd %s", bp->b_cwd);
1.29 kjell 240: addline(bp, qcmd);
1.1 art 241: addline(bp, "");
242:
1.23 deraadt 243: if (getcwd(cwd, sizeof(cwd)) == NULL)
1.18 kjell 244: panic("Can't get current directory!");
1.28 kjell 245: if (chdir(bp->b_cwd) == -1) {
246: ewprintf("Can't change dir to %s", bp->b_cwd);
1.18 kjell 247: return (NULL);
1.19 deraadt 248: }
1.29 kjell 249: if ((fpipe = popen(qcmd, "r")) == NULL) {
1.1 art 250: ewprintf("Problem opening pipe");
1.13 db 251: return (NULL);
1.1 art 252: }
253: /*
254: * We know that our commands are nice and the last line will end with
255: * a \n, so we don't need to try to deal with the last line problem
256: * in fgetln.
257: */
1.26 kjell 258: while ((buf = fgetln(fpipe, &len)) != NULL) {
1.1 art 259: buf[len - 1] = '\0';
260: addline(bp, buf);
261: }
1.26 kjell 262: ret = pclose(fpipe);
1.18 kjell 263: t = time(NULL);
264: strftime(timestr, sizeof(timestr), "%a %b %e %T %Y", localtime(&t));
1.1 art 265: addline(bp, "");
1.18 kjell 266: if (ret != 0)
267: addlinef(bp, "Command exited abnormally with code %d"
268: " at %s", ret, timestr);
269: else
270: addlinef(bp, "Command finished at %s", timestr);
271:
1.32 kjell 272: bp->b_dotp = bfirstlp(bp);
1.1 art 273: bp->b_modes[0] = name_mode("fundamental");
274: bp->b_modes[1] = name_mode("compile");
275: bp->b_nmodes = 1;
276:
277: compile_buffer = bp;
278:
1.18 kjell 279: if (chdir(cwd) == -1) {
280: ewprintf("Can't change dir back to %s", cwd);
281: return (NULL);
1.19 deraadt 282: }
1.13 db 283: return (bp);
1.1 art 284: }
285:
1.20 kjell 286: /* ARGSUSED */
1.1 art 287: static int
288: compile_goto_error(int f, int n)
289: {
1.24 deraadt 290: struct buffer *bp;
291: struct mgwin *wp;
1.21 kjell 292: char *fname, *line, *lp, *ln;
1.29 kjell 293: int lineno;
1.28 kjell 294: char *adjf, path[NFILEN];
1.21 kjell 295: const char *errstr;
1.24 deraadt 296: struct line *last;
1.1 art 297:
298: compile_win = curwp;
299: compile_buffer = curbp;
1.32 kjell 300: last = blastlp(compile_buffer);
1.22 deraadt 301:
1.21 kjell 302: retry:
303: /* last line is compilation result */
304: if (curwp->w_dotp == last)
305: return (FALSE);
1.33 deraadt 306:
1.29 kjell 307: if ((line = linetostr(curwp->w_dotp)) == NULL)
1.13 db 308: return (FALSE);
1.1 art 309: lp = line;
1.21 kjell 310: if ((fname = strsep(&lp, ":")) == NULL || *fname == '\0')
1.1 art 311: goto fail;
1.21 kjell 312: if ((ln = strsep(&lp, ":")) == NULL || *ln == '\0')
1.1 art 313: goto fail;
1.24 deraadt 314: lineno = (int)strtonum(ln, INT_MIN, INT_MAX, &errstr);
1.21 kjell 315: if (errstr)
1.1 art 316: goto fail;
1.33 deraadt 317:
1.28 kjell 318: if (fname && fname[0] != '/') {
1.34 ! kjell 319: if (getbufcwd(path, sizeof(path)) == FALSE)
! 320: goto fail;
1.28 kjell 321: if (strlcat(path, fname, sizeof(path)) >= sizeof(path))
322: goto fail;
323: adjf = path;
324: } else {
1.30 jason 325: adjf = adjustname(fname, TRUE);
1.28 kjell 326: }
1.1 art 327: free(line);
328:
1.7 vincent 329: if (adjf == NULL)
330: return (FALSE);
1.10 vincent 331:
1.1 art 332: if ((bp = findbuffer(adjf)) == NULL)
1.13 db 333: return (FALSE);
1.1 art 334: if ((wp = popbuf(bp)) == NULL)
1.13 db 335: return (FALSE);
1.1 art 336: curbp = bp;
337: curwp = wp;
1.27 kjell 338: if (bp->b_fname[0] == '\0')
1.1 art 339: readin(adjf);
340: gotoline(FFARG, lineno);
1.13 db 341: return (TRUE);
1.1 art 342: fail:
1.3 deraadt 343: free(line);
1.32 kjell 344: if (curwp->w_dotp != blastlp(curbp)) {
1.1 art 345: curwp->w_dotp = lforw(curwp->w_dotp);
346: curwp->w_flag |= WFMOVE;
347: goto retry;
348: }
349: ewprintf("No more hits");
1.13 db 350: return (FALSE);
1.1 art 351: }
352:
1.20 kjell 353: /* ARGSUSED */
1.17 kjell 354: int
1.1 art 355: next_error(int f, int n)
356: {
357: if (compile_win == NULL || compile_buffer == NULL) {
358: ewprintf("No compilation active");
1.13 db 359: return (FALSE);
1.1 art 360: }
361: curwp = compile_win;
362: curbp = compile_buffer;
1.32 kjell 363: if (curwp->w_dotp == blastlp(curbp)) {
1.1 art 364: ewprintf("No more hits");
1.13 db 365: return (FALSE);
1.1 art 366: }
367: curwp->w_dotp = lforw(curwp->w_dotp);
368: curwp->w_flag |= WFMOVE;
369:
1.13 db 370: return (compile_goto_error(f, n));
1.34 ! kjell 371: }
! 372:
! 373: /*
! 374: * Since we don't have variables (we probably should) these are command
! 375: * processors for changing the values of mode flags.
! 376: */
! 377: /* ARGSUSED */
! 378: int
! 379: globalwdtoggle(int f, int n)
! 380: {
! 381: if (f & FFARG)
! 382: globalwd = n > 0;
! 383: else
! 384: globalwd = !globalwd;
! 385:
! 386: sgarbf = TRUE;
! 387:
! 388: return (TRUE);
1.1 art 389: }