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