home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 8 / FreshFishVol8-CD1.bin / gnu / src / baseline / jove-4.14.6.lha / jove-4.14.6 / proc.c < prev    next >
C/C++ Source or Header  |  1992-01-10  |  19KB  |  869 lines

  1. /***************************************************************************
  2.  * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
  3.  * is provided to you without charge, and with no warranty.  You may give  *
  4.  * away copies of JOVE, including sources, provided that this notice is    *
  5.  * included in all the files.                                              *
  6.  ***************************************************************************/
  7.  
  8. #include "jove.h"
  9. #include "ctype.h"
  10. #include "fp.h"
  11. #include "re.h"
  12. #include "termcap.h"
  13. #include "disp.h"
  14. #include "rec.h"
  15.  
  16. #include <signal.h>
  17. #ifdef    STDARGS
  18. # include <stdarg.h>
  19. #else
  20. # include <varargs.h>
  21. #endif
  22.  
  23. #ifdef    MSDOS
  24. # include <io.h>
  25. # include <process.h>
  26. # include <sys/stat.h>
  27. #endif
  28.  
  29. private void
  30.     DoShell proto((char *, char *)),
  31.     com_finish proto((int, char *));
  32.  
  33. long    SigMask = 0;
  34.  
  35. /* This disgusting RE search string parses output from the GREP
  36.    family, from the pdp11 compiler, pcc, and lint.  Jay (HACK)
  37.    Fenlasen changed this to work for the lint errors. */
  38. char    ErrFmtStr[256] = "^\\{\",\\}\\([^:\"( \t]*\\)\\{\"\\, line ,:,(\\} *\\([0-9][0-9]*\\)[:)]\
  39. \\|::  *\\([^(]*\\)(\\([0-9]*\\))$\
  40. \\|( \\([^(]*\\)(\\([0-9]*\\)) ),";
  41.  
  42. struct error {
  43.     Buffer        *er_buf;    /* Buffer error is in */
  44.     Line        *er_mess,    /* Actual error message */
  45.             *er_text;    /* Actual error */
  46.     int        er_char;    /* char pos of error */
  47.     struct error    *er_prev,    /* List of errors */
  48.             *er_next;
  49. };
  50.  
  51. private struct error    *cur_error = NULL,
  52.         *errorlist = NULL;
  53. Buffer        *perr_buf = NULL;    /* Buffer with error messages */
  54.  
  55. bool    WtOnMk = ON;        /* Write the modified files when we make */
  56.  
  57. /* Eliminate any error records that contain dangling references to Lines.
  58.  * We only eliminate error structs when either referent is recycled.
  59.  * If it deleted, we keep it (dormant) in case it will be pasted back
  60.  * into the same buffer.
  61.  */
  62.  
  63. void
  64. ChkErrorLines()
  65. {
  66.     register struct error    *e;
  67.     struct error    *prev = NULL;
  68.  
  69.     for (e = errorlist; e != NULL; ) {
  70.         struct error    *next = e->er_next;
  71.  
  72.         if (e->er_mess->l_dline == NULL_DADDR
  73.         || e->er_text->l_dline == NULL_DADDR)
  74.         {
  75.             /* dangling reference: delete */
  76.             if (prev == NULL)
  77.                 errorlist = next;
  78.             else
  79.                 prev->er_next = next;
  80.             if (next != NULL)
  81.                 next->er_prev = prev;
  82.             if (cur_error == e)
  83.                 cur_error = next;
  84.             free((UnivPtr)e);
  85.         } else {
  86.             prev = e;
  87.         }
  88.         e = next;
  89.     }
  90. }
  91.  
  92. /* Add an error to the end of the list of errors.  This is used for
  93.    parse-{C,LINT}-errors and for the spell-buffer command */
  94.  
  95. private struct error *
  96. AddError(laste, errline, buf, line, charpos)
  97. struct error    *laste;
  98. Line    *errline,
  99.     *line;
  100. Buffer    *buf;
  101. int    charpos;
  102. {
  103.     struct error    *new = (struct error *) emalloc(sizeof *new);
  104.  
  105.     new->er_prev = laste;
  106.     if (laste)
  107.         laste->er_next = new;
  108.     else {
  109.         if (errorlist)        /* Free up old errors */
  110.             ErrFree();
  111.         cur_error = errorlist = new;
  112.     }
  113.     laste = new;
  114.     new->er_next = NULL;
  115.     new->er_buf = buf;
  116.     new->er_text = line;
  117.     new->er_char = charpos;
  118.     new->er_mess = errline;
  119.  
  120.     return new;
  121. }
  122.  
  123. void
  124. get_FL_info(fname, lineno)
  125. char    *fname,
  126.     *lineno;
  127. {
  128.     putmatch(1, fname, (size_t)FILESIZE);
  129.     putmatch(2, lineno, (size_t)FILESIZE);
  130.  
  131.     /* error had lineno followed fname, so switch the two */
  132.     if (!jisdigit(lineno[0])) {
  133.         char    tmp[FILESIZE];
  134.  
  135.         strcpy(tmp, lineno);
  136.         strcpy(lineno, fname);
  137.         strcpy(fname, tmp);
  138.     }
  139. }
  140.  
  141. /* Free up all the errors */
  142.  
  143. void
  144. ErrFree()
  145. {
  146.     register struct error    *ep;
  147.  
  148.     for (ep = errorlist; ep != NULL; ep = ep->er_next)
  149.         free((UnivPtr) ep);
  150.     errorlist = cur_error = NULL;
  151. }
  152.  
  153. /* Parse errors of the form specified in ErrFmtStr in the current
  154.    buffer.  Do a show error of the first error.  This is neat because this
  155.    will work for any kind of output that prints a file name and a line
  156.    number on the same line. */
  157.  
  158. void
  159. ErrParse()
  160. {
  161.     struct RE_block    re_blk;
  162.     Bufpos    *bp;
  163.     char    fname[FILESIZE],
  164.         lineno[FILESIZE];
  165.     int    lnum,
  166.         last_lnum = -1;
  167.     struct error    *ep = NULL;
  168.     Buffer    *buf,
  169.         *lastb = NULL;
  170.     Line    *err_line;
  171.  
  172.     ErrFree();        /* This is important! */
  173.     ToFirst();
  174.     perr_buf = curbuf;
  175.     REcompile(ErrFmtStr, YES, &re_blk);
  176.     /* Find a line with a number on it. */
  177.     while ((bp = docompiled(FORWARD, &re_blk)) != NULL) {
  178.         SetDot(bp);
  179.         get_FL_info(fname, lineno);
  180.         buf = do_find((Window *)NULL, fname, YES);
  181.         if (buf != lastb) {
  182.             lastb = buf;
  183.             last_lnum = -1;        /* signals new file */
  184.             err_line = buf->b_first;
  185.         }
  186.         (void) chr_to_int(lineno, 10, NO, &lnum);
  187.         if (lnum == last_lnum)    /* one error per line is nicer */
  188.             continue;
  189.         if (last_lnum == -1)
  190.             last_lnum = 1;    /* that's where we really are */
  191.         err_line = next_line(err_line, lnum - last_lnum);
  192.         ep = AddError(ep, curline, buf, err_line, 0);
  193.         last_lnum = lnum;
  194.     }
  195.     if (cur_error != NULL)
  196.         ShowErr();
  197. }
  198.  
  199. private void
  200. NeedErrors()
  201. {
  202.     if (cur_error == NULL)
  203.         complain("No errors!");
  204. }
  205.  
  206. private bool
  207. ErrorHasReferents()
  208. {
  209.     return inlist(cur_error->er_buf->b_first, cur_error->er_text)
  210.         && inlist(perr_buf->b_first, cur_error->er_mess);
  211. }
  212.  
  213. /* Go the the next error, if there is one.  Put the error buffer in
  214.    one window and the buffer with the error in another window.
  215.    It checks to make sure that the error actually exists. */
  216.  
  217. private void
  218. ToError(forward)
  219. bool    forward;
  220. {
  221.     register struct error    *e = cur_error;
  222.     int    num = arg_value();
  223.  
  224.     NeedErrors();
  225.     if ((forward? e->er_next : e->er_prev) == NULL)
  226.         complain("You're at the %s error.", forward ? "last" : "first");
  227.     while (--num >= 0 || !ErrorHasReferents()) {
  228.         e = forward ? e->er_next : e->er_prev;
  229.         if (e == NULL)
  230.             break;
  231.         cur_error = e;
  232.     }
  233.     ShowErr();
  234. }
  235.  
  236. void
  237. NextError()
  238. {
  239.     ToError(TRUE);
  240. }
  241.  
  242. void
  243. PrevError()
  244. {
  245.     ToError(FALSE);
  246. }
  247.  
  248. int    EWSize = 20;    /* percentage of screen the error window
  249.                should be */
  250.  
  251. private void
  252. set_wsize(wsize)
  253. int    wsize;
  254. {
  255.     wsize = (LI * wsize) / 100;
  256.     if (wsize >= 1 && !one_windp())
  257.         WindSize(curwind, wsize - (curwind->w_height - 1));
  258. }
  259.  
  260. /* Show the current error, i.e. put the line containing the error message
  261.    in one window, and the buffer containing the actual error in another
  262.    window. */
  263.  
  264. void
  265. ShowErr()
  266. {
  267.     Window    *err_wind,
  268.         *buf_wind;
  269.  
  270.     NeedErrors();
  271.     if (!ErrorHasReferents()) {
  272.         rbell();
  273.         return;
  274.     }
  275.     err_wind = windbp(perr_buf);
  276.     buf_wind = windbp(cur_error->er_buf);
  277.  
  278.     if (err_wind && !buf_wind) {
  279.         SetWind(err_wind);
  280.         pop_wind(cur_error->er_buf->b_name, NO, -1);
  281.         buf_wind = curwind;
  282.     } else if (!err_wind && buf_wind) {
  283.         SetWind(buf_wind);
  284.         pop_wind(perr_buf->b_name, NO, -1);
  285.         err_wind = curwind;
  286.     } else if (!err_wind && !buf_wind) {
  287.         pop_wind(perr_buf->b_name, NO, -1);
  288.         err_wind = curwind;
  289.         pop_wind(cur_error->er_buf->b_name, NO, -1);
  290.         buf_wind = curwind;
  291.     }
  292.  
  293.     /* Put the current error message at the top of its Window */
  294.     SetWind(err_wind);
  295.     SetLine(cur_error->er_mess);
  296.     SetTop(curwind, (curwind->w_line = cur_error->er_mess));
  297.     set_wsize(EWSize);
  298.  
  299.     /* now go to the the line with the error in the other window */
  300.     SetWind(buf_wind);
  301.     DotTo(cur_error->er_text, cur_error->er_char);
  302. }
  303.  
  304. char    ShcomBuf[LBSIZE];
  305.  
  306. /* Make a buffer name given the command `command', i.e. "fgrep -n foo *.c"
  307.    will return the buffer name "fgrep".  */
  308.  
  309. char *
  310. MakeName(command)
  311. char    *command;
  312. {
  313.     static char    bnm[50];
  314.     register char    *cp = bnm,
  315.             c;
  316.  
  317.     do ; while ((c = *command++) != '\0' && (c == ' ' || c == '\t'));
  318.     do {
  319.         *cp++ = c;
  320.     } while ((c = *command++) != '\0' && (c != ' ' && c != '\t'));
  321.     *cp = '\0';
  322.     strcpy(bnm, basename(bnm));
  323.  
  324.     return bnm;
  325. }
  326.  
  327. /* Run make, first writing all the modified buffers (if the WtOnMk flag is
  328.    on), parse the errors, and go the first error. */
  329.  
  330. private char    make_cmd[LBSIZE] = "make";
  331.  
  332. void
  333. MakeErrors()
  334. {
  335.     Window    *old = curwind;
  336.     int    status;
  337.     bool    compilation;
  338.  
  339.     if (WtOnMk)
  340.         put_bufs(FALSE);
  341.     /* When we're not doing make or cc (i.e., the last command
  342.        was probably a grep or something) and the user just types
  343.        C-X C-E, he probably (possibly, hopefully, usually (in my
  344.        case)) doesn't want to do the grep again but rather wants
  345.        to do a make again; so we ring the bell and insert the
  346.        default command and let the person decide. */
  347.  
  348.     compilation = (sindex("make", make_cmd) || sindex("cc", make_cmd));
  349.     if (is_an_arg() || !compilation) {
  350.         if (!compilation) {
  351.             rbell();
  352.             Inputp = mak