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