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