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