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