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: }

Defined functions

AddError defined in line 37; used 2 times
DoShell defined in line 388; used 2 times
ErrFree defined in line 128; used 4 times
ErrParse defined in line 82; used 3 times
FilterRegion defined in line 558; used 2 times
MakeErrors defined in line 271; used 2 times
MakeName defined in line 247; used 4 times
NextError defined in line 162; used 2 times
ParseAll defined in line 64; used 3 times
PrevError defined in line 167; used 2 times
RegToUnix defined in line 568; used 1 times
ShToBuf defined in line 370; used 2 times
ShellCom defined in line 378; used 2 times
ShowErr defined in line 199; used 5 times
SpelBuffer defined in line 307; used 2 times
SpelParse defined in line 333; used 2 times
SpelWords defined in line 322; used 2 times
ToError defined in line 183; used 2 times
UnixToBuf defined in line 455; used 5 times
XParse defined in line 69; used 2 times
com_finish defined in line 403; used 3 times
dowait defined in line 410; used 3 times
okay_error defined in line 172; used 2 times
toerror defined in line 143; used 1 times

Defined variables

EWSize defined in line 192; used 7 times
ShcomBuf defined in line 242; used 6 times
SigMask defined in line 544; used 2 times
WtOnMk defined in line 32; used 3 times
cur_error defined in line 28; used 17 times
errbounds defined in line 140; used 1 times
errfmt defined in line 17; used 3 times
make_cmd defined in line 269; used 9 times
perr_buf defined in line 30; used 6 times

Defined struct's

error defined in line 19; used 20 times
Last modified: 1986-03-28
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2105
Valid CSS Valid XHTML 1.0 Strict