2.9BSD/usr/contrib/jove/jove_proc.c

Compare this file to the similar file:
Show the results in this format:

/*
   Jonathan Payne at Lincoln-Sudbury Regional High School 5-25-83
  
   jove_proc.c

   This file contains procedures to handle the shell to buffer commands
   and buffer to shell commands.  It isn't especially neat, but I think
   it is understandable. */

#include <whoami.h>
#include "jove.h"

#include <signal.h>

char	*cerrfmt = "\\([^:]*\\):\\([0-9][0-9]*\\):";
	/* C error scanf format string for errors of the form
	 * filename:linenum: error message
	 */

char	*lerrfmt = "\"\\([^:]*\\)\", line \\([0-9][0-9]*\\):";
	/* Lint error for errors of the form
	 * "filename", line linenum: error message.
	 */

struct error {
	BUFFER		*er_buf;	/* Buffer error is in */
	LINE		*er_mess;	/* Actual error message */
	LINE		*er_text;	/* Actual error */
	int		er_char;	/* char pos of error */
	struct error	*er_next;	/* List of error */
};

struct error	*thiserror = 0,
		*errorlist = 0;
BUFFER		*thisbuf = 0;	/* Buffer that error parsing took place */

int	MakeAll = 0,		/* Not make -k */
	WtOnMk = 1;		/* Write the modified files when we make */

/* Add an error to the end of the list of errors.  This is used for
 * parse-C/LINT-errors and for the spell-buffer command
 */

struct error *
AddError(newerror, errline, buf, line, charpos)
struct error	*newerror;
LINE	*errline,
	*line;
BUFFER	*buf;
{
	if (newerror) {
		newerror->er_next = (struct error *)
				emalloc(sizeof (struct error));
		newerror = newerror->er_next;
	} else
		thiserror = newerror = errorlist = (struct error *)
				emalloc(sizeof (struct error));
	newerror->er_buf = buf;
	newerror->er_text = line;
	newerror->er_char = charpos;
	newerror->er_next = 0;
	newerror->er_mess = errline;
	return newerror;
}

/* Returns the num'th line in buffer `b' */

LINE *
LineAt(num, b)
register int	num;
BUFFER	 *b;
{
	register LINE	*lp = b->b_zero;

	while (--num > 0 && lp)
		lp = lp->l_next;
	return lp;
}

CParse()
{
	ErrParse(cerrfmt);
}

LintParse()
{
	ErrParse(lerrfmt);
}

/* Parse for C/LINT errors in the current buffer.  Set up for the next-error
   command. */

ErrParse(fmtstr)
char	*fmtstr;
{
	BUFLOC	*bp;
	char	fname[100],
		lineno[10];
	struct error	*ep = 0;
	BUFFER	*buf;
	
	Bof();
	if (errorlist)
		ErrFree();
	thisbuf = curbuf;
	/* Find a line with a number on it */
	while (bp = dosearch(fmtstr, 1, 1)) {
		SetDot(bp);
		putmatch(1, fname, sizeof fname);
		putmatch(2, lineno, sizeof lineno);
		buf = do_find((WINDOW *) 0, fname);
		ep = AddError(ep, curline, buf, LineAt(atoi(lineno), buf), 0);
	}
}

/* Send the buffer to the spell program (for some reason, writing the 
   file and running spell on that file caused spell to just sit there!)
   and then go find each occurrence of the mispelled words that the user
   says to go find.  Check out SpParse() */

SpellCom()
{
	WINDOW	*errwind,
		*savewind;
	char	command[100];

	savewind = curwind;
	exp_p = 1;
	if (IsModified(curbuf))
		SaveFile();

	ignore(UnixToBuf("Spell", 1, !exp_p, "/bin/csh", "csh", "-cf",
			sprintf(command, "/bin/spell %s", curbuf->b_fname), 0));
	NotModified();
	Bof();		/* Beginning of (error messages) file */
	errwind = curwind;
	if (linebuf[0]) {
		SpParse(errwind, savewind);
		if (thiserror)
			NextError();
		message("Go get 'em");
	} else {
		message("No errors");
		SetWind(savewind);
	}
}

/* There is one word per line in the current buffer.  Read that word
   and ask the user whether he wants us to search for it (if it is a
   big buffer he may not want to if he thinks it is spelled correctly). */

SpParse(err, buf)
WINDOW	*err,
	*buf;
{
	BUFLOC	*bp;
	char	string[100],
		ans;
	struct error	*newerr = 0;

	if (errorlist)
		ErrFree();
	thisbuf = err->w_bufp;
	SetWind(err);
	for (;;) {
		if (linebuf[0] == 0)
			goto nextword;
		s_mess("Is \"%s\" misspelled (Y or N)? ", linebuf);
		ignore(sprintf(string, "\\b%s\\b", linebuf));
		SetWind(buf);		/* Paper buffer */
		Bof();
		do
			ans = getch();
		while ((ans = Upper(ans)) != 'Y' && ans != 'N');

		if (ans == 'Y') {	/* Not correct */
			while (bp = dosearch(string, 1, 1)) {
				SetDot(bp);
				newerr = AddError(newerr, 
				    thisbuf->b_dot, buf->w_bufp,
				    curline, curchar);
			}
		}
			
nextword:
		SetWind(err);	/* Back to error window to move to
				   the next word */
		if (eobp())
			break;
		if (ans == 'N') {	/* Delete the word ... */
			Bol();
			DoTimes(KillEOL, 1);	/* by deleting the line */
		} else {
			if (lastp(curline))
				break;
			else
				SetLine(curline->l_next);
		}
	}
}

/* Free up all the errors */

ErrFree()
{
	register struct error	*ep;

	for (ep = errorlist; ep; ep = ep->er_next)
		free((char *) ep);
	errorlist = thiserror = 0;
}

/* Go the the next error, if there is one.  Put the error buffer in
   one window and the buffer with the error in another window.
   It checks to make sure that the error actually exists. */

NextError()
{
	register int	i = exp;

	while (--i >= 0)
		DoNextErr();
}

DoNextErr()
{
	/* Make sure we haven't deleted the line with the actual error
	   by accident. */

	while (errorlist && thiserror) {
		if (inlist(thiserror->er_buf->b_zero, thiserror->er_text))
			break;
		thiserror = thiserror->er_next;
	}
	if (errorlist == 0 || thiserror == 0)
		complain("No errors");

	pop_wind(thisbuf->b_name, 0);
	SetLine(thiserror->er_mess);
	SetTop(curwind, (curwind->w_line = thiserror->er_mess));
	pop_wind(thiserror->er_buf->b_name, 0);
	DotTo(thiserror->er_text, thiserror->er_char);
	thiserror = thiserror->er_next;
}

/* Run make, first writing all the modified buffers (if the WtOnMk flag is
 * non-zero), parse the errors, and go the first error.
 */

MakeErrors()
{
	WINDOW	*old = curwind;
	int	status;

	if (WtOnMk)
		WtModBuf();
	if (MakeAll)
		status = UnixToBuf("make", 1, 1, "/bin/make", "Make", "-k", 0);
	else
		status = UnixToBuf("make", 1, 1, "/bin/make", "Make", 0);
	com_finish(status, "make");
	if (errorlist)
		ErrFree();

	if (status)
#ifndef VMUNIX
		ErrParse(cerrfmt);
#else
		ErrParse(lerrfmt);
#endif VMUNIX

	if (thiserror)
		NextError();
	else
		SetWind(old);
}

/* Make a buffer name given the command `command', i.e. "fgrep -n foo *.c"
   will return the buffer name "fgrep".  */

char *
MakeName(command)
char	*command;
{
	static char	bufname[50];
	char	*cp = bufname, c;

	while ((c = *command++) && (c == ' ' || c == '\t'))
		;
	do
		*cp++ = c;
	while ((c = *command++) && (c != ' ' && c != '\t'));
	*cp = 0;
	cp = rindex(bufname, '/');
	if (cp)
		strcpy(bufname, cp + 1);
	return bufname;
}

ShToBuf()
{
	char	bufname[100];

	strcpy(bufname, ask((char *) 0, "Buffer: "));
	DoShell(bufname, ask((char *) 0, "Command: "));
}

ShellCom()
{
	char	command[100];

	strcpy(command, ask((char *) 0, FuncName()));
	DoShell(MakeName(command), command);
}

/* Run the shell command into `bufname'.  Empty the buffer except when we
   give a numeric argument, in which case it inserts the output at the
   current position in the buffer.  */

DoShell(bufname, command)
char	*bufname,
	*command;
{
	WINDOW	*savewp = curwind;
	int	status;

	exp = 1;
	status = UnixToBuf(bufname, 1, !exp_p, "/bin/csh", "csh", "-fc",
			command, 0);
	com_finish(status, command);
	SetWind(savewp);
}

com_finish(status, com)
char	*com;
{
	s_mess("\"%s\" completed %ssuccessfully", com, status ? "un" : "");
}

dopipe(p)
int	p[];
{
	if (pipe(p) == -1)
		complain("Cannot pipe");
}

PipeClose(p)
int	p[];
{
	ignore(close(p[0]));
	ignore(close(p[1]));
}

/* Run the command to bufname, erase the buffer if clobber is non-zero,
 * and redisplay if disp is non-zero.
 */

/* VARARGS3 */

UnixToBuf(bufname, disp, clobber, func, args)
char	*bufname,
	*func;
{
	int	p[2],
		pid;
	char	buff[LBSIZE];
	extern int	ninbuf;

	message("Starting up...");
	pop_wind(bufname, clobber);
	if (disp)
		redisplay();		
	if (clobber)
		curbuf->b_type = SCRATCHBUF;
	exp = 1;

	dopipe(p);
	pid = fork();
	if (pid == -1) {
		PipeClose(p);
		complain("Cannot fork");
	}
	if (pid == 0) {
#ifdef SIGTSTP
		ignorf(sigset(SIGINT, SIG_DFL));
#else
		ignorf(signal(SIGINT, SIG_DFL));
#endif
		ignore(close(0));
		ignore(open("/dev/null", 0));
		ignore(close(1));
		ignore(close(2));
		ignore(dup(p[1]));
		ignore(dup(p[1]));
		PipeClose(p);
		execv(func, (char **) &args);
		ignore(write(1, "Execl failed", 12));
		_exit(1);
	} else {
#ifdef SIGTSTP
		int	(*oldquit)() = sigset(SIGINT, SIG_IGN);
#else
		int	(*oldquit)() = signal(SIGINT, SIG_IGN);
#endif
		int	status;
		char	*mess;

		ignore(close(p[1]));
		io = p[0];
		while (getfline(buff) != EOF) {
			ins_str(buff);
			LineInsert();
			if (ninbuf <= 0) {
#ifdef VMUNIX			/* No easy way to find out */
				mess = "Chugging along...";
#else
#if	defined(MENLO_JCL) && !defined(NONFP)
				{
					short	avg[3];
					double	theavg;

					ignore(gldav(avg));
					theavg = (double) avg[0] / 256;
					if (theavg < 1.0)
						mess = "Screaming along...";
					else if (theavg < 3.0)
						mess = "Chugging along...";
					else
						mess = "Crawling along...";
				}
#else
				mess = "Chugging along...";
#endif MENLO_JCL
#endif VMUNIX
				message(mess);
				redisplay();
			}
		}
		UpdateMesg();
		IOclose();
#ifdef SIGTSTP
		ignorf(sigset(SIGINT, oldquit));
#else
		ignorf(signal(SIGINT, oldquit));
#endif
		while (wait(&status) != pid)
			;
		return status;
	}
	return 0;
}

/* Send a region to shell.  Now we can beautify C and sort programs */

RegToShell()
{
	char	com[100];
	MARK	*m = CurMark();

	strcpy(com, ask((char *) 0, FuncName()));
	if (!exp_p) {
		exp_p = 1;	/* So it doesn't delete the region */
		exp = 0;
	}
	if (inorder(m->m_line, m->m_char, curline, curchar))
		RegToUnix(curbuf->b_name, 1, m->m_line, m->m_char,
					curline, curchar, com);
	else
		RegToUnix(curbuf->b_name, 1, curline, curchar, m->m_line,
					m->m_char, com);
	message("Done");
}

/* Writes the region to a tmp file and then run the command with input
   from that file */

RegToUnix(bufname, replace, line1, char1, line2, char2, func)
char	*bufname;
LINE	*line1,
	*line2;
char	*func;
{
	char	*fname = mktemp(TMPFILE);
	char	com[100];

	if ((io = creat(fname, 0644)) == -1)
		complain(IOerr("create", fname));
	putreg(line1, char1, line2, char2);
	IOclose();
	if (replace)
		DelReg();
	ignore(sprintf(com, "%s < %s", func, fname));
	ignore(UnixToBuf(bufname, 0, 0, "/bin/csh", "csh", "-c", com, 0));
	ignore(unlink(fname));
}