1 /* $OpenBSD: grep.c,v 1.49 2021/03/01 10:51:14 lum Exp $ */ 2 3 /* This file is in the public domain */ 4 5 #include <sys/queue.h> 6 #include <sys/types.h> 7 #include <sys/wait.h> 8 9 #include <ctype.h> 10 #include <limits.h> 11 #include <signal.h> 12 #include <stdio.h> 13 #include <stdlib.h> 14 #include <string.h> 15 #include <time.h> 16 #include <unistd.h> 17 18 #include "def.h" 19 #include "kbd.h" 20 #include "funmap.h" 21 22 int globalwd = FALSE; 23 static int compile_goto_error(int, int); 24 int next_error(int, int); 25 static int grep(int, int); 26 static int gid(int, int); 27 static struct buffer *compile_mode(const char *, const char *); 28 void grep_init(void); 29 30 static char compile_last_command[NFILEN] = "make "; 31 32 /* 33 * Hints for next-error 34 * 35 * XXX - need some kind of callback to find out when those get killed. 36 */ 37 struct mgwin *compile_win; 38 struct buffer *compile_buffer; 39 40 static PF compile_pf[] = { 41 compile_goto_error 42 }; 43 44 static struct KEYMAPE (1) compilemap = { 45 1, 46 1, 47 rescan, 48 { 49 { CCHR('M'), CCHR('M'), compile_pf, NULL } 50 } 51 }; 52 53 void 54 grep_init(void) 55 { 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); 61 maps_add((KEYMAP *)&compilemap, "compile"); 62 } 63 64 /* ARGSUSED */ 65 static int 66 grep(int f, int n) 67 { 68 char cprompt[NFILEN], *bufp; 69 struct buffer *bp; 70 struct mgwin *wp; 71 72 (void)strlcpy(cprompt, "grep -n ", sizeof(cprompt)); 73 if ((bufp = eread("Run grep: ", cprompt, NFILEN, 74 EFDEF | EFNEW | EFCR)) == NULL) 75 return (ABORT); 76 else if (bufp[0] == '\0') 77 return (FALSE); 78 if (strlcat(cprompt, " /dev/null", sizeof(cprompt)) >= sizeof(cprompt)) 79 return (FALSE); 80 81 if ((bp = compile_mode("*grep*", cprompt)) == NULL) 82 return (FALSE); 83 if ((wp = popbuf(bp, WNONE)) == NULL) 84 return (FALSE); 85 curbp = bp; 86 compile_win = curwp = wp; 87 return (TRUE); 88 } 89 90 /* ARGSUSED */ 91 int 92 compile(int f, int n) 93 { 94 char cprompt[NFILEN], *bufp; 95 struct buffer *bp; 96 struct mgwin *wp; 97 98 (void)strlcpy(cprompt, compile_last_command, sizeof(cprompt)); 99 if ((bufp = eread("Compile command: ", cprompt, NFILEN, 100 EFDEF | EFNEW | EFCR)) == NULL) 101 return (ABORT); 102 else if (bufp[0] == '\0') 103 return (FALSE); 104 if (savebuffers(f, n) == ABORT) 105 return (ABORT); 106 (void)strlcpy(compile_last_command, bufp, sizeof(compile_last_command)); 107 108 if ((bp = compile_mode("*compile*", cprompt)) == NULL) 109 return (FALSE); 110 if ((wp = popbuf(bp, WNONE)) == NULL) 111 return (FALSE); 112 curbp = bp; 113 compile_win = curwp = wp; 114 gotoline(FFARG, 0); 115 return (TRUE); 116 } 117 118 /* id-utils foo. */ 119 /* ARGSUSED */ 120 static int 121 gid(int f, int n) 122 { 123 char command[NFILEN]; 124 char cprompt[NFILEN], *bufp; 125 int c; 126 struct buffer *bp; 127 struct mgwin *wp; 128 int i, j, len; 129 130 /* catch ([^\s(){}]+)[\s(){}]* */ 131 132 i = curwp->w_doto; 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 139 i--; 140 } 141 142 /* Skip the symbol itself */ 143 for (; i > 0; i--) { 144 c = lgetc(curwp->w_dotp, i - 1); 145 if (!isalnum(c) && c != '_') 146 break; 147 } 148 /* Fill the symbol in cprompt[] */ 149 for (j = 0; j < sizeof(cprompt) - 1 && i < llength(curwp->w_dotp); 150 j++, i++) { 151 c = lgetc(curwp->w_dotp, i); 152 if (!isalnum(c) && c != '_') 153 break; 154 cprompt[j] = c; 155 } 156 cprompt[j] = '\0'; 157 158 if ((bufp = eread("Run gid (with args): ", cprompt, NFILEN, 159 (j ? EFDEF : 0) | EFNEW | EFCR)) == NULL) 160 return (ABORT); 161 else if (bufp[0] == '\0') 162 return (FALSE); 163 len = snprintf(command, sizeof(command), "gid %s", cprompt); 164 if (len < 0 || len >= sizeof(command)) 165 return (FALSE); 166 167 if ((bp = compile_mode("*gid*", command)) == NULL) 168 return (FALSE); 169 if ((wp = popbuf(bp, WNONE)) == NULL) 170 return (FALSE); 171 curbp = bp; 172 compile_win = curwp = wp; 173 return (TRUE); 174 } 175 176 struct buffer * 177 compile_mode(const char *name, const char *command) 178 { 179 struct buffer *bp; 180 FILE *fpipe; 181 char *buf; 182 size_t sz; 183 ssize_t len; 184 int ret, n, status; 185 char cwd[NFILEN], qcmd[NFILEN]; 186 char timestr[NTIME]; 187 time_t t; 188 189 buf = NULL; 190 sz = 0; 191 192 n = snprintf(qcmd, sizeof(qcmd), "%s 2>&1", command); 193 if (n < 0 || n >= sizeof(qcmd)) 194 return (NULL); 195 196 bp = bfind(name, TRUE); 197 if (bclear(bp) != TRUE) 198 return (NULL); 199 200 if (getbufcwd(bp->b_cwd, sizeof(bp->b_cwd)) != TRUE) 201 return (NULL); 202 addlinef(bp, "cd %s", bp->b_cwd); 203 addline(bp, qcmd); 204 addline(bp, ""); 205 206 if (getcwd(cwd, sizeof(cwd)) == NULL) 207 panic("Can't get current directory!"); 208 if (chdir(bp->b_cwd) == -1) { 209 dobeep(); 210 ewprintf("Can't change dir to %s", bp->b_cwd); 211 return (NULL); 212 } 213 if ((fpipe = popen(qcmd, "r")) == NULL) { 214 dobeep(); 215 ewprintf("Problem opening pipe"); 216 return (NULL); 217 } 218 while ((len = getline(&buf, &sz, fpipe)) != -1) { 219 if (buf[len - 1] == *bp->b_nlchr) 220 buf[len - 1] = '\0'; 221 addline(bp, buf); 222 } 223 free(buf); 224 if (ferror(fpipe)) 225 ewprintf("Problem reading pipe"); 226 ret = pclose(fpipe); 227 t = time(NULL); 228 strftime(timestr, sizeof(timestr), "%a %b %e %T %Y", localtime(&t)); 229 addline(bp, ""); 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); 240 241 bp->b_dotp = bfirstlp(bp); 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 248 if (chdir(cwd) == -1) { 249 dobeep(); 250 ewprintf("Can't change dir back to %s", cwd); 251 return (NULL); 252 } 253 return (bp); 254 } 255 256 /* ARGSUSED */ 257 static int 258 compile_goto_error(int f, int n) 259 { 260 struct buffer *bp; 261 struct mgwin *wp; 262 char *fname, *line, *lp, *ln; 263 int lineno; 264 char *adjf, path[NFILEN]; 265 const char *errstr; 266 struct line *last; 267 268 compile_win = curwp; 269 compile_buffer = curbp; 270 last = blastlp(compile_buffer); 271 272 retry: 273 /* last line is compilation result */ 274 if (curwp->w_dotp == last) 275 return (FALSE); 276 277 if ((line = linetostr(curwp->w_dotp)) == NULL) 278 return (FALSE); 279 lp = line; 280 if ((fname = strsep(&lp, ":")) == NULL || *fname == '\0') 281 goto fail; 282 if ((ln = strsep(&lp, ":")) == NULL || *ln == '\0') 283 goto fail; 284 lineno = (int)strtonum(ln, INT_MIN, INT_MAX, &errstr); 285 if (errstr) 286 goto fail; 287 288 if (fname && fname[0] != '/') { 289 if (getbufcwd(path, sizeof(path)) == FALSE) 290 goto fail; 291 if (strlcat(path, fname, sizeof(path)) >= sizeof(path)) 292 goto fail; 293 adjf = path; 294 } else { 295 adjf = adjustname(fname, TRUE); 296 } 297 free(line); 298 299 if (adjf == NULL) 300 return (FALSE); 301 302 if ((bp = findbuffer(adjf)) == NULL) 303 return (FALSE); 304 if ((wp = popbuf(bp, WNONE)) == NULL) 305 return (FALSE); 306 curbp = bp; 307 curwp = wp; 308 if (bp->b_fname[0] == '\0') 309 readin(adjf); 310 gotoline(FFARG, lineno); 311 return (TRUE); 312 fail: 313 free(line); 314 if (curwp->w_dotp != blastlp(curbp)) { 315 curwp->w_dotp = lforw(curwp->w_dotp); 316 curwp->w_rflag |= WFMOVE; 317 goto retry; 318 } 319 dobeep(); 320 ewprintf("No more hits"); 321 return (FALSE); 322 } 323 324 /* ARGSUSED */ 325 int 326 next_error(int f, int n) 327 { 328 if (compile_win == NULL || compile_buffer == NULL) { 329 dobeep(); 330 ewprintf("No compilation active"); 331 return (FALSE); 332 } 333 curwp = compile_win; 334 curbp = compile_buffer; 335 if (curwp->w_dotp == blastlp(curbp)) { 336 dobeep(); 337 ewprintf("No more hits"); 338 return (FALSE); 339 } 340 curwp->w_dotp = lforw(curwp->w_dotp); 341 curwp->w_rflag |= WFMOVE; 342 343 return (compile_goto_error(f, n)); 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); 362 } 363