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