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