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