|
|
1.1 ! root 1: /************************************************************************* ! 2: * This program is copyright (C) 1985, 1986 by Jonathan Payne. It is * ! 3: * provided to you without charge for use only on a licensed Unix * ! 4: * system. You may copy JOVE provided that this notice is included with * ! 5: * the copy. You may not sell copies of this program or versions * ! 6: * modified for use on microcomputer systems, unless the copies are * ! 7: * included with a Unix system distribution and the source is provided. * ! 8: *************************************************************************/ ! 9: ! 10: #include "jove.h" ! 11: #include "io.h" ! 12: #include "termcap.h" ! 13: ! 14: #include <signal.h> ! 15: ! 16: private char ! 17: *errfmt = "^\\{\",\\}\\([^:\"( \t]*\\)\\{\"\\, line ,:,(\\} *\\([0-9][0-9]*\\)[:)]"; ! 18: ! 19: struct error { ! 20: Buffer *er_buf; /* Buffer error is in */ ! 21: Line *er_mess, /* Actual error message */ ! 22: *er_text; /* Actual error */ ! 23: int er_char; /* char pos of error */ ! 24: struct error *er_prev, /* List of errors */ ! 25: *er_next; ! 26: }; ! 27: ! 28: struct error *cur_error = 0, ! 29: *errorlist = 0; ! 30: Buffer *perr_buf = 0; /* Buffer with error messages */ ! 31: ! 32: int WtOnMk = 1; /* Write the modified files when we make */ ! 33: ! 34: /* Add an error to the end of the list of errors. This is used for ! 35: parse-{C,LINT}-errors and for the spell-buffer command */ ! 36: ! 37: private struct error * ! 38: AddError(laste, errline, buf, line, charpos) ! 39: struct error *laste; ! 40: Line *errline, ! 41: *line; ! 42: Buffer *buf; ! 43: { ! 44: struct error *new = (struct error *) emalloc(sizeof *new); ! 45: ! 46: new->er_prev = laste; ! 47: if (laste) ! 48: laste->er_next = new; ! 49: else { ! 50: if (errorlist) /* Free up old errors */ ! 51: ErrFree(); ! 52: cur_error = errorlist = new; ! 53: } ! 54: laste = new; ! 55: new->er_next = 0; ! 56: new->er_buf = buf; ! 57: new->er_text = line; ! 58: new->er_char = charpos; ! 59: new->er_mess = errline; ! 60: ! 61: return new; ! 62: } ! 63: ! 64: ParseAll() ! 65: { ! 66: ErrParse(errfmt); ! 67: } ! 68: ! 69: XParse() ! 70: { ! 71: char *sstr; ! 72: ! 73: sstr = ask(errfmt, ProcFmt); ! 74: ErrParse(sstr); ! 75: } ! 76: ! 77: /* Parse for {C,LINT} errors (or anything that matches fmtstr) in the ! 78: current buffer. Set up for the next-error command. This is neat ! 79: because this will work for any kind of output that prints a file ! 80: name and a line number on the same line. */ ! 81: ! 82: ErrParse(fmtstr) ! 83: char *fmtstr; ! 84: { ! 85: Bufpos *bp; ! 86: char fname[FILESIZE], ! 87: lineno[10], ! 88: REbuf[128], ! 89: *REalts[10]; ! 90: int lnum, ! 91: last_lnum = -1; ! 92: struct error *ep = 0; ! 93: Buffer *buf, ! 94: *lastb = 0; ! 95: Line *err_line; ! 96: ! 97: ErrFree(); /* This is important! */ ! 98: ToFirst(); ! 99: perr_buf = curbuf; ! 100: REcompile(fmtstr, 1, REbuf, REalts); ! 101: /* Find a line with a number on it. */ ! 102: while (bp = docompiled(FORWARD, REbuf, REalts)) { ! 103: SetDot(bp); ! 104: putmatch(1, fname, sizeof fname); ! 105: putmatch(2, lineno, sizeof lineno); ! 106: buf = do_find((Window *) 0, fname, 1); ! 107: if (buf != lastb) { ! 108: lastb = buf; ! 109: last_lnum = -1; /* signals new file */ ! 110: err_line = buf->b_first; ! 111: } ! 112: lnum = chr_to_int(lineno, 10, 0); ! 113: if (lnum == last_lnum) /* one error per line is nicer */ ! 114: continue; ! 115: if (last_lnum == -1) ! 116: last_lnum = 1; /* that's where we really are */ ! 117: err_line = next_line(err_line, lnum - last_lnum); ! 118: ep = AddError(ep, curline, buf, err_line, 0); ! 119: last_lnum = lnum; ! 120: } ! 121: if (cur_error != 0) ! 122: ShowErr(); ! 123: exp = 1; ! 124: } ! 125: ! 126: /* Free up all the errors */ ! 127: ! 128: ErrFree() ! 129: { ! 130: register struct error *ep; ! 131: ! 132: for (ep = errorlist; ep != 0; ep = ep->er_next) ! 133: free((char *) ep); ! 134: errorlist = cur_error = 0; ! 135: } ! 136: ! 137: /* Internal next error sets cur_error to the next error, taking the ! 138: argument count, supplied by the user, into consideration. */ ! 139: ! 140: private char errbounds[] = "You're at the %s error.", ! 141: noerrs[] = "No errors!"; ! 142: ! 143: private ! 144: toerror(forward) ! 145: { ! 146: register int i; ! 147: register struct error *e = cur_error; ! 148: ! 149: if (e == 0) ! 150: complain(noerrs); ! 151: if ((forward && (e->er_next == 0)) || ! 152: (!forward && (e->er_prev == 0))) ! 153: complain(errbounds, forward ? "last" : "first"); ! 154: ! 155: for (i = 0; i < exp; i++) { ! 156: if ((e = forward ? e->er_next : e->er_prev) == 0) ! 157: break; ! 158: cur_error = e; ! 159: } ! 160: } ! 161: ! 162: NextError() ! 163: { ! 164: ToError(1); ! 165: } ! 166: ! 167: PrevError() ! 168: { ! 169: ToError(0); ! 170: } ! 171: ! 172: private ! 173: okay_error() ! 174: { ! 175: return ((inlist(perr_buf->b_first, cur_error->er_mess)) && ! 176: (inlist(cur_error->er_buf->b_first, cur_error->er_text))); ! 177: } ! 178: ! 179: /* Go the the next error, if there is one. Put the error buffer in ! 180: one window and the buffer with the error in another window. ! 181: It checks to make sure that the error actually exists. */ ! 182: ! 183: ToError(forward) ! 184: { ! 185: do { ! 186: toerror(forward); ! 187: exp = 1; ! 188: } while (!okay_error()); ! 189: ShowErr(); ! 190: } ! 191: ! 192: int EWSize = 20; /* percentage of screen the error window ! 193: should be */ ! 194: ! 195: /* Show the current error, i.e. put the line containing the error message ! 196: in one window, and the buffer containing the actual error in another ! 197: window. */ ! 198: ! 199: ShowErr() ! 200: { ! 201: Window *err_wind, ! 202: *buf_wind; ! 203: int w_size; /* size of window */ ! 204: ! 205: if (cur_error == 0) ! 206: complain(noerrs); ! 207: if (!okay_error()) { ! 208: rbell(); ! 209: return; ! 210: } ! 211: err_wind = windbp(perr_buf); ! 212: buf_wind = windbp(cur_error->er_buf); ! 213: ! 214: if (err_wind && !buf_wind) { ! 215: SetWind(err_wind); ! 216: pop_wind(cur_error->er_buf->b_name, 0, -1); ! 217: buf_wind = curwind; ! 218: } else if (!err_wind && buf_wind) { ! 219: SetWind(buf_wind); ! 220: pop_wind(perr_buf->b_name, 0, -1); ! 221: err_wind = curwind; ! 222: } else if (!err_wind && !buf_wind) { ! 223: pop_wind(perr_buf->b_name, 0, -1); ! 224: err_wind = curwind; ! 225: pop_wind(cur_error->er_buf->b_name, 0, -1); ! 226: buf_wind = curwind; ! 227: } ! 228: ! 229: /* Put the current error message at the top of its Window */ ! 230: SetWind(err_wind); ! 231: SetLine(cur_error->er_mess); ! 232: SetTop(curwind, (curwind->w_line = cur_error->er_mess)); ! 233: w_size = (ILI * EWSize) / 100; ! 234: if (w_size >= 1) ! 235: WindSize(curwind, w_size - (curwind->w_height - 1)); ! 236: ! 237: /* now go to the the line with the error in the other window */ ! 238: SetWind(buf_wind); ! 239: DotTo(cur_error->er_text, cur_error->er_char); ! 240: } ! 241: ! 242: char ShcomBuf[128] = {0}; ! 243: ! 244: /* Make a buffer name given the command `command', i.e. "fgrep -n foo *.c" ! 245: will return the buffer name "fgrep". */ ! 246: ! 247: char * ! 248: MakeName(command) ! 249: char *command; ! 250: { ! 251: static char bufname[50]; ! 252: register char *cp = bufname, ! 253: c; ! 254: ! 255: while ((c = *command++) && (c == ' ' || c == '\t')) ! 256: ; ! 257: do ! 258: *cp++ = c; ! 259: while ((c = *command++) && (c != ' ' && c != '\t')); ! 260: *cp = 0; ! 261: strcpy(bufname, basename(bufname)); ! 262: ! 263: return bufname; ! 264: } ! 265: ! 266: /* Run make, first writing all the modified buffers (if the WtOnMk flag is ! 267: non-zero), parse the errors, and go the first error. */ ! 268: ! 269: char make_cmd[128] = "make"; ! 270: ! 271: MakeErrors() ! 272: { ! 273: Window *old = curwind; ! 274: int status, ! 275: compilation; ! 276: ! 277: if (WtOnMk) ! 278: put_bufs(0); ! 279: /* When we're not doing make or cc (i.e., the last command ! 280: was probably a grep or something) and the user just types ! 281: C-X C-E, he probably (possibly, hopefully, usually (in my ! 282: case)) doesn't want to do the grep again but rather wants ! 283: to do a make again; so we ring the bell and insert the ! 284: default command and let the person decide. */ ! 285: ! 286: compilation = (sindex("make", make_cmd) || sindex("cc", make_cmd)); ! 287: if (exp_p || !compilation) { ! 288: if (!compilation) { ! 289: rbell(); ! 290: Inputp = make_cmd; /* insert the default for the ! 291: user */ ! 292: } ! 293: null_ncpy(make_cmd, ask(make_cmd, "Compilation command: "), ! 294: sizeof (make_cmd) - 1); ! 295: } ! 296: status = UnixToBuf(MakeName(make_cmd), YES, EWSize, YES, Shell, basename(Shell), ShFlags, make_cmd, 0); ! 297: com_finish(status, make_cmd); ! 298: ! 299: ErrParse(errfmt); ! 300: ! 301: if (!cur_error) ! 302: SetWind(old); ! 303: } ! 304: ! 305: #ifdef SPELL ! 306: ! 307: SpelBuffer() ! 308: { ! 309: char *Spell = "Spell", ! 310: com[100]; ! 311: Window *savewp = curwind; ! 312: ! 313: put_bufs(0); ! 314: sprintf(com, "spell %s", curbuf->b_fname); ! 315: (void) UnixToBuf(Spell, YES, EWSize, YES, Shell, basename(Shell), ShFlags, com, 0); ! 316: message("[Delete the irrelevant words and then type C-X C-C]"); ! 317: Recur(); ! 318: SetWind(savewp); ! 319: SpelParse(Spell); ! 320: } ! 321: ! 322: SpelWords() ! 323: { ! 324: char *buftospel; ! 325: Buffer *wordsb = curbuf; ! 326: ! 327: if ((buftospel = ask_buf((Buffer *) 0)) == 0) ! 328: return; ! 329: SetBuf(do_select(curwind, buftospel)); ! 330: SpelParse(wordsb->b_name); ! 331: } ! 332: ! 333: SpelParse(bname) ! 334: char *bname; ! 335: { ! 336: Buffer *buftospel, ! 337: *wordsb; ! 338: char wordspel[100]; ! 339: Bufpos *bp; ! 340: struct error *ep = 0; ! 341: ! 342: ErrFree(); /* This is important! */ ! 343: ! 344: buftospel = curbuf; ! 345: wordsb = buf_exists(bname); ! 346: perr_buf = wordsb; /* This is important (buffer containing ! 347: error messages) */ ! 348: SetBuf(wordsb); ! 349: ToFirst(); ! 350: f_mess("Finding misspelled words ... "); ! 351: while (!lastp(curline)) { ! 352: sprintf(wordspel, "\\<%s\\>", linebuf); ! 353: SetBuf(buftospel); ! 354: ToFirst(); ! 355: while (bp = dosearch(wordspel, 1, 1)) { ! 356: SetDot(bp); ! 357: ep = AddError(ep, wordsb->b_dot, buftospel, ! 358: curline, curchar); ! 359: } ! 360: SetBuf(wordsb); ! 361: line_move(FORWARD, NO); ! 362: } ! 363: add_mess("Done."); ! 364: SetBuf(buftospel); ! 365: ShowErr(); ! 366: } ! 367: ! 368: #endif SPELL ! 369: ! 370: ShToBuf() ! 371: { ! 372: char bufname[100]; ! 373: ! 374: strcpy(bufname, ask((char *) 0, "Buffer: ")); ! 375: DoShell(bufname, ask(ShcomBuf, "Command: ")); ! 376: } ! 377: ! 378: ShellCom() ! 379: { ! 380: null_ncpy(ShcomBuf, ask(ShcomBuf, ProcFmt), (sizeof ShcomBuf) - 1); ! 381: DoShell(MakeName(ShcomBuf), ShcomBuf); ! 382: } ! 383: ! 384: /* Run the shell command into `bufname'. Empty the buffer except when we ! 385: give a numeric argument, in which case it inserts the output at the ! 386: current position in the buffer. */ ! 387: ! 388: private ! 389: DoShell(bufname, command) ! 390: char *bufname, ! 391: *command; ! 392: { ! 393: Window *savewp = curwind; ! 394: int status; ! 395: ! 396: exp = 1; ! 397: status = UnixToBuf(bufname, YES, 0, !exp_p, Shell, basename(Shell), ! 398: ShFlags, command, 0); ! 399: com_finish(status, command); ! 400: SetWind(savewp); ! 401: } ! 402: ! 403: private ! 404: com_finish(status, com) ! 405: char *com; ! 406: { ! 407: s_mess("\"%s\" completed %ssuccessfully.", com, status ? "un" : NullStr); ! 408: } ! 409: ! 410: dowait(pid, status) ! 411: int pid, ! 412: *status; ! 413: { ! 414: #ifndef IPROCS ! 415: ! 416: int rpid; ! 417: ! 418: while ((rpid = wait(status)) != pid) ! 419: ; ! 420: #else ! 421: ! 422: #ifdef BSD4_2 ! 423: # include <sys/wait.h> ! 424: #else ! 425: # include <wait.h> ! 426: #endif ! 427: ! 428: union wait w; ! 429: int rpid; ! 430: ! 431: for (;;) { ! 432: #ifndef VMUNIX ! 433: rpid = wait2(&w.w_status, 0); ! 434: #else ! 435: rpid = wait3(&w, 0, (struct rusage *) 0); ! 436: #endif ! 437: if (rpid == pid) { ! 438: if (status) ! 439: *status = w.w_status; ! 440: break; ! 441: } else ! 442: kill_off(rpid, w); ! 443: } ! 444: #endif IPROCS ! 445: } ! 446: ! 447: /* Run the command to bufname, erase the buffer if clobber is non-zero, ! 448: and redisplay if disp is non-zero. Leaves current buffer in `bufname' ! 449: and leaves any windows it creates lying around. It's up to the caller ! 450: to fix everything up after we're done. (Usually there's nothing to ! 451: fix up.) */ ! 452: ! 453: /* VARARGS3 */ ! 454: ! 455: UnixToBuf(bufname, disp, wsize, clobber, cmd, args) ! 456: char *bufname, ! 457: *cmd; ! 458: { ! 459: int p[2], ! 460: pid; ! 461: extern int ninbuf; ! 462: Buffer *bp; ! 463: ! 464: if (clobber && (bp = buf_exists(bufname)) != 0 && ! 465: bp->b_type != B_PROCESS && bp->b_type != B_IPROCESS) ! 466: complain("Command would over-write buffer %s.", bufname); ! 467: if (disp) { ! 468: message("Starting up..."); ! 469: pop_wind(bufname, clobber, clobber ? B_PROCESS : B_FILE); ! 470: wsize = (LI * wsize) / 100; ! 471: if (wsize >= 1 && !one_windp()) ! 472: WindSize(curwind, wsize - (curwind->w_height - 1)); ! 473: redisplay(); ! 474: } ! 475: exp = 1; ! 476: dopipe(p); ! 477: pid = fork(); ! 478: if (pid == -1) { ! 479: pclose(p); ! 480: complain("[Fork failed]"); ! 481: } ! 482: if (pid == 0) { ! 483: (void) close(0); ! 484: (void) open("/dev/null", 0); ! 485: (void) close(1); ! 486: (void) close(2); ! 487: (void) dup(p[1]); ! 488: (void) dup(p[1]); ! 489: pclose(p); ! 490: execv(cmd, (char **) &args); ! 491: (void) write(1, "Execl failed.\n", 14); ! 492: _exit(1); ! 493: } else { ! 494: int status; ! 495: int (*oldint)() = signal(SIGINT, SIG_IGN); ! 496: char *mess; ! 497: File *fp; ! 498: ! 499: #ifdef IPROCS ! 500: sighold(SIGCHLD); ! 501: #endif ! 502: ! 503: (void) close(p[1]); ! 504: fp = fd_open(cmd, F_READ, p[0], iobuff, LBSIZE); ! 505: while (inIOread = 1, f_gets(fp, genbuf, LBSIZE) != EOF) { ! 506: inIOread = 0; ! 507: ins_str(genbuf, YES); ! 508: LineInsert(); ! 509: if (disp != 0 && fp->f_cnt <= 0) { ! 510: #ifdef LOAD_AV ! 511: { ! 512: double theavg; ! 513: ! 514: get_la(&theavg); ! 515: if (theavg < 2.0) ! 516: mess = "Screaming along..."; ! 517: else if (theavg < 5.0) ! 518: mess = "Chugging along..."; ! 519: else ! 520: mess = "Crawling along..."; ! 521: } ! 522: #else ! 523: mess = "Chugging along..."; ! 524: #endif LOAD_AV ! 525: message(mess); ! 526: redisplay(); ! 527: } ! 528: } ! 529: if (disp) ! 530: DrawMesg(NO); ! 531: close_file(fp); ! 532: (void) signal(SIGINT, oldint); ! 533: dowait(pid, &status); ! 534: #ifdef IPROCS ! 535: sigrelse(SIGCHLD); ! 536: #endif ! 537: return status; ! 538: } ! 539: return 0; ! 540: } ! 541: ! 542: #ifdef BSD4_2 ! 543: ! 544: private int SigMask = 0; ! 545: ! 546: sighold(sig) ! 547: { ! 548: (void) sigblock(SigMask |= (1 << (sig - 1))); ! 549: } ! 550: ! 551: sigrelse(sig) ! 552: { ! 553: (void) sigsetmask(SigMask &= ~(1 << (sig - 1))); ! 554: } ! 555: ! 556: #endif ! 557: ! 558: FilterRegion() ! 559: { ! 560: char *cmd = ask((char *) 0, ": %f (through command) ", ProcFmt); ! 561: ! 562: RegToUnix(curbuf, cmd); ! 563: } ! 564: ! 565: /* Send the current region to CMD and insert the output from the ! 566: command into OUT_BUF. */ ! 567: ! 568: RegToUnix(outbuf, cmd) ! 569: Buffer *outbuf; ! 570: char *cmd; ! 571: { ! 572: Mark *m = CurMark(); ! 573: char *tname = mktemp("/tmp/jfilterXXXXXX"), ! 574: combuf[130]; ! 575: Window *save_wind = curwind; ! 576: int status; ! 577: File *fp; ! 578: ! 579: CATCH ! 580: fp = open_file(tname, iobuff, F_WRITE, COMPLAIN, QUIET); ! 581: putreg(fp, m->m_line, m->m_char, curline, curchar, YES); ! 582: DelReg(); ! 583: sprintf(combuf, "%s < %s", cmd, tname); ! 584: status = UnixToBuf(outbuf->b_name, NO, 0, outbuf->b_type == B_SCRATCH, ! 585: Shell, basename(Shell), ShFlags, combuf, 0); ! 586: ONERROR ! 587: ; /* Do nothing ... but fall through and delete the tmp ! 588: file. */ ! 589: ENDCATCH ! 590: f_close(fp); ! 591: (void) unlink(tname); ! 592: SetWind(save_wind); ! 593: com_finish(status, combuf); ! 594: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.