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