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