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