4.4BSD/usr/src/contrib/nvi/nvi/ex/ex_errlist.c

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

/*-
 * Copyright (c) 1992, 1993
 *	The Regents of the University of California.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed by the University of
 *	California, Berkeley and its contributors.
 * 4. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#ifndef lint
static char sccsid[] = "@(#)ex_errlist.c	8.1 (Berkeley) 6/9/93";
#endif /* not lint */

#ifndef NO_ERRLIST 
#include <sys/param.h>

#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "vi.h"
#include "excmd.h"
#include "pathnames.h"

static FILE *errlistfp;		/* Error list descriptor. */

static char	*parse_err __P((char *, char **, u_long *));
static int	 run __P((SCR *, EXF *, EXCMDARG *, char *));

int
ex_cc(sp, ep, cmdp)
	SCR *sp;
	EXF *ep;
	EXCMDARG *cmdp;
{
	return (run(sp, ep, cmdp, O_STR(sp, O_CC)));
}

int
ex_make(sp, ep, cmdp)
	SCR *sp;
	EXF *ep;
	EXCMDARG *cmdp;
{
	return (run(sp, ep, cmdp, O_STR(sp, O_MAKE)));
}

static int
run(sp, ep, cmdp, cname)
	SCR *sp;
	EXF *ep;
	EXCMDARG *cmdp;
	char *cname;
{
	struct termios t;
	EXCMDARG cmd;
	int fd;
	char cb[MAXPATHLEN], tf[MAXPATHLEN];

	MODIFY_CHECK(sp, ep, 0);

	/* Close any previously open error list file. */
	if (errlistfp != NULL)
		(void)fclose(errlistfp);

	(void)strcpy(tf, _PATH_ERRLIST);
	if ((fd = mkstemp(tf)) == -1) {
		msgq(sp, M_ERR, "%s: %s", tf, strerror(errno));
		return (1);
	}
	if ((errlistfp = fdopen(fd, "r")) == NULL) {
		(void)close(fd);
		msgq(sp, M_ERR, "%s: %s", tf, strerror(errno));
		return (1);
	}

	/* Build and run the command. */
	(void)snprintf(cb,
	    sizeof(cb), "%s %s 2> %s", cname, cmdp->string, tf);
	(void)fprintf(sp->stdfp, "%s", cb);

	/* Save ex/vi terminal settings, and restore the original ones. */
	(void)tcgetattr(STDIN_FILENO, &t);
	(void)tcsetattr(STDIN_FILENO, TCSADRAIN, &sp->gp->original_termios);

	/* Start with a new line. */
	(void)write(STDOUT_FILENO, "\n", 1);

	/*
	 * System will exit with an error status if the file doesn't compile,
	 * so we have to ignore errors.
	 */
	(void)esystem(sp, _PATH_BSHELL, cb);

	/* Repaint the screen. */
	F_SET(sp, S_REFRESH);

	/* Restore ex/vi terminal settings. */
	(void)tcsetattr(STDIN_FILENO, TCSAFLUSH, &t);

	/* We have a handle on the file, delete its name. */
 	(void)unlink(tf);

	/* Run the errlist command. */
	SETCMDARG(cmd, C_ERRLIST, 0, OOBLNO, 0, 0, NULL);
	return (ex_errlist(sp, ep, &cmd));
}

int
ex_errlist(sp, ep, cmdp)
	SCR *sp;
	EXF *ep;
	EXCMDARG *cmdp;
{
	EXF *tep;
	u_long line;
	size_t len;
	char mbuf[20], *fname, *p;

	switch (cmdp->argc) {
	case 0:
		if (errlistfp == NULL) {
			msgq(sp, M_ERR, "No error list file.");
			return (1);
		}
		break;
	case 1:
		if (errlistfp != NULL)
			(void)fclose(errlistfp);
		if ((errlistfp = fopen((char *)cmdp->argv[0], "r")) == NULL) {
			msgq(sp, M_ERR,
			    "%s: %s", cmdp->argv[0], strerror(errno));
			return (1);
		}
		break;
	default:
		abort();
	}

	/* Find the next error message in the file. */
	while (!ex_getline(sp, errlistfp, &len)) {
		/* See if it's an error message. */
		if ((p = parse_err(sp->ibp, &fname, &line)) == NULL)
			continue;

		if (strcmp(fname, ep->name)) {
			MODIFY_CHECK(sp, ep, 0);
			if ((tep = file_get(sp, ep, fname, 1)) == NULL)
				return (1);
			sp->enext = tep;
			F_SET(sp, S_FSWITCH);
		} else
			tep = ep;

		/* Go to the right line. */
		sp->lno = line;
		sp->cno = 0;
		F_CLR(ep, F_NOSETPOS);

		/* Display the error message. */
		(void)snprintf(mbuf, sizeof(mbuf), "line %lu: ", line);
		msgq(sp, M_ERR,
		    "%s%.*s", mbuf, sp->cols - strlen(mbuf) - 1, p);
		return (0);
	}
	msgq(sp, M_ERR, "No more errors in the file.");
	(void)fclose(errlistfp);
	errlistfp = NULL;
	return (0);
}

/*
 * parse_err --
 *	Try and parse a compiler error message.
 *
 *	This code handles gcc output, but fairly badly.  Gcc has a penchant
 *	for multi-line output which we don't handle at all.
 */
static char *
parse_err(line, fnamep, lnop)
	char *line, **fnamep;
	recno_t *lnop;
{
	static char *fname;
	register char *p, *t;
	int len;

	/*
	 * Grab the file name.  Ignore any associated path, the chances of
	 * two files with the same name being edited in the same session
	 * in different directories is much less than the chance of having
	 * two different paths for the same file.
	 */
	if ((p = strchr(line, ':')) == NULL)
		return (NULL);
	*p = '\0';
	if ((t = strrchr(line, '/')) == NULL)
		t = line;
	else
		++t;
	len = (p - t) + 1;
	if ((fname = realloc(fname, len)) == NULL)
		return (NULL);
	memmove(fname, t, len);
	fname[len] = '\0';
	*fnamep = fname;

	/* Grab the line number. */
	if (!*++p || !isdigit(*p))
		return (NULL);
	*lnop = strtoul(p, NULL, 10);

	/* Skip the line number. */
	if ((p = strchr(p, ':')) == NULL)
		return (NULL);

	/* Skip leading spaces. */
	for (; *p && isspace(*p); ++p);
	if (*p == '\0')
		return (NULL);

	return (p);
}
#endif /* NO_ERRLIST */