[net.sources] ve - An interactive viewer of programming errors

joseph@cadvaxoz.eecs.unsw.oz (Joseph Kam) (08/07/86)

          This is a very versatile little program which  allows  the  rapid
     positioning  to  the error lines specified in the error file one after
     the other,  and   if   possible,   prints   the   corresponding  error
     message  on  the  terminal's  status line.  The error file may contain
     errors output from cc(1), ld(1), lint(1), cyntax(1) and make(1).

          It should be able to run on both System V  and   BSD4.2  systems.
     The program uses terminfo(4) to print out error messages to the status
     line of a terminal. If you do not have  terminfo,  then  just  do  not
     define  TERMINFO in the Makefile. In this case, the error message will
     not be displayed on the status line of your terminal.  As the  program
     only  do  a  heuristic parsing of the form of error messages given out
     from cc, ld, lint, cyntax, and make from our UNSW Unix  System  (which
     is  a  mixture  or  a  mess  of  Version  7, System 5, and BSD4.2 with
     significant local hacks), it may not able to recognise error  messages
     in  a  different  format. But you can look into the individual  parser
     and do necessary changes or rewrite to make it work on your system.

          You are free to change the program, but if you have extended  its
     capabilities  like  able  to  recognise error messages from yacc, lex,
     awk, grep, etc., please send a copy back to  me.  For  sending  flame,
     please direct to /dev/null and hopefully I may get it (you never know)
     or just do a '/bin/rm *' if that will make you feel  happier.  Anyway,
     enjoy it.


Ming Chi Kam             ISD:  +61 2 697-4056
University of NSW,       STD:  (02) 697-4056
P.O. Box 1, Kensington,  ARPA: joseph%cadvax.oz@seismo.arpa
Sydney, NSW, 2033,       UUCP: seismo!munnari!cadvax.oz!joseph
AUSTRALIA.               ACSnet:  joseph@cadvax.oz

------- CUT HERE ----------- CUT HERE ----------- CUT HERE ----
# Shell Archive created by cadvax! at Thu Aug  7 12:00:29 1986

# To unpack the enclosed files, please use this file as input to the
# Bourne (sh) shell.  This can be most easily done by the command;
#     sh < thisfilename

# This archive contains;
#  ve.1             Makefile            cctag.c             cyntag.c            etag.c              ldtag.c             lintag.c


# ---------- file ve.1 ----------

filename="ve.1"

if [ -f $filename ]
then
  echo File \"$filename\" already exists\!  Skipping...
  filename=/dev/null		# throw it away
else
  echo extracting file ve.1...
fi

cat << 'END-OF-FILE' > $filename
.TH VE 1
.SH NAME
ve \- an interactive viewer of programming errors
.SH SYNOPSIS
.B ve file
.SH DESCRIPTION
.I Ve
accepts only one argument which is the name of the file containing 
errors output from cc, ld, lint, cyntax and make. With the automatic
invocation of the
screen editor - vi, 
.I ve
allows the rapid positioning to the error lines specified 
in the error file one after the other, and if possible,  
prints the corresponding error message on the terminal's status line. 
Three commands may be typed when in the vi editor to browse through the 
error lines. 
.P
.in +10
^A \(em go to next error line, 
.br
^Z \(em go back to the last error line, and
.br
^C \(em go to the current error line.
.in -10
.SH ARTHOR
Ming Chi, Kam (joseph@cadvax.unsw.oz)
.SH BUGS
As users may change the contents of the file, so
.I ve
does not rely on the line number specified in the error file to
position the cursor to the line which may cause the error. Instead,
.I ve
uses a pattern matching method to try to match the  original line pattern 
before invoking vi, with the same file, after being possibly changed. 
As a result, there may be a chance, possibly very slight, that the file
contains more than one line with the same pattern and incidently, 
.I ve
positions to the wrong one. So users are advised to compare the line number
in the error message with the line number of error line positioned by
.I ve
in cases where the users have some doubts as a result of their big
difference or no error can be spotted. In both cases, the command n or N 
may be typed to see if any other match can be found.
END-OF-FILE

if [ "$filename" != "/dev/null" ]
then
  size=`wc -c < $filename`

  if [ $size != 1600 ]
  then
    echo $filename changed - should be 1600 bytes, not $size bytes
  fi

  chmod 600 $filename
fi

# ---------- file Makefile ----------

filename="Makefile"

if [ -f $filename ]
then
  echo File \"$filename\" already exists\!  Skipping...
  filename=/dev/null		# throw it away
else
  echo extracting file Makefile...
fi

cat << 'END-OF-FILE' > $filename
# Define GETLOGIN if you do not have getlogin(3C) call
# Define TMPFILE  if you do not have tmpfile(3C) call
# Define BSD      if you use index(3C) call instead of strchr(3C)
# Define TERMINFO only if your system supports terminfo(4).
CFLAGS= -O 
LINKFLAGS= -n

CC= cc

CFILES= cctag.c cyntag.c etag.c ldtag.c lintag.c
OBJECTS= cctag.o cyntag.o etag.o ldtag.o lintag.o

# Use -lterminfo if you do not have -lcurses
LIBS= -lcurses

ve:	$(OBJECTS)
	$(CC) $(LINKFLAGS) -o ve $(OBJECTS) $(LIBS)

.c.o:
	$(CC) $(CFLAGS) -c $*.c
END-OF-FILE

if [ "$filename" != "/dev/null" ]
then
  size=`wc -c < $filename`

  if [ $size != 462 ]
  then
    echo $filename changed - should be 462 bytes, not $size bytes
  fi

  chmod 600 $filename
fi

# ---------- file cctag.c ----------

filename="cctag.c"

if [ -f $filename ]
then
  echo File \"$filename\" already exists\!  Skipping...
  filename=/dev/null		# throw it away
else
  echo extracting file cctag.c...
fi

cat << 'END-OF-FILE' > $filename

#include <stdio.h>

int	makecctag(infp, outfp)
FILE	*infp ;
FILE	*outfp ;
{
	int	find = 0 ;
	char	lbuf[512] ;

	while (fgets(lbuf, 512, infp) != NULL)
	{
	         if (*lbuf == '"' )
		 {
			fputs(lbuf, outfp) ;
			find = 1 ;
		 }
	}
	return(find) ;
}
END-OF-FILE

if [ "$filename" != "/dev/null" ]
then
  size=`wc -c < $filename`

  if [ $size != 253 ]
  then
    echo $filename changed - should be 253 bytes, not $size bytes
  fi

  chmod 600 $filename
fi

# ---------- file cyntag.c ----------

filename="cyntag.c"

if [ -f $filename ]
then
  echo File \"$filename\" already exists\!  Skipping...
  filename=/dev/null		# throw it away
else
  echo extracting file cyntag.c...
fi

cat << 'END-OF-FILE' > $filename

#include <stdio.h>

static  int	line ;
static	FILE	*outfp ;
static	FILE	*infp ;
static	char	mesg[254] ;
static	char	filename[100] ;

int	makecyntag(infilep, outfilep)
FILE	*infilep ;
FILE	*outfilep ;
{
	int	find = 0 ;
	char	lbuf[512] ;

	infp = infilep ;
	outfp = outfilep ;
	while (fgets(lbuf, 512, infp) != NULL)
	{
		switch ( CynMatch1(lbuf) )
		{
		   case  1 : 
			find = 1 ;
			break ;
		   case -1 : 
		 	return(0) ;
		   case  0 : 
			switch (CynMatch2(lbuf) )
			{
			   case  1 : 
				find = 1 ;
				break ;
			   case -1 : 
				return(0) ;
			   case  0 : 
				switch (CynMatch3(lbuf) )
				{
				   case  1 : 
					find = 1 ;
					break ;
				   case -1 : 
					return(0) ;
				   case  0 : 
					switch (CynMatch4(lbuf) )
					{
					   case  1 : 
						find = 1 ;
						break ;
					   case -1 : 
						return(0) ;
					}
			        }
		        }
	         }
	} 
	return(find) ;
}


int	CynMatch1(lbuf)
/*
 *	Match ordinary error line with the format
 *	file: line: error
 */
char	*lbuf ;
{
	if ( sscanf(lbuf, "%[^: \t]: %d: %[^\n]", filename, &line, mesg) > 2)  
	{
		fprintf(outfp, "\"%s\", line %d: %s\n", filename, line, mesg ) ;
		return(1) ;
	}
	return(0) ;
}


int	CynMatch2(lbuf)
/*
 *	match line with the format 
 *	variable "multiply declared":
 */
char	*lbuf ;
{
	char	c ;
	char	varname[100] ;
	char	linebuf[512] ;

	if (
		sscanf(lbuf, "%s multiply declared%c", varname, &c) > 1
		&&
		c == ':'
	   )
	{
	    if (
		(getc(infp) == '\t')
		&&
		fgets(linebuf, 512, infp) != NULL
	       )
	    {
		if (
		    sscanf(linebuf, "%[^:]: %d %[^\n]", filename, &line, mesg)  > 2 
		    &&
		    strncmp(mesg, "implicitly as", 13) == 0
		   )
		{
			if (
			    getc(infp) != '\t' 
			    || 
			    fgets(linebuf, 512, infp) == NULL)
			    return(-1) ;
		}
		else 
		{
			if (fscanf(infp, " %[^:]: %d %[^\n]\n", filename, &line, mesg)  <  3)  
			   return(-1) ;
		}
		fprintf(
			outfp,
			"\"%s\", line %d: %s %s : %s", 
			filename, 
			line, 
			varname,
			mesg, 
			linebuf 
		       ) ;
		return(1) ;
	    }
	    else return(-1) ;
	}
	else return(0) ;
}

int	CynMatch3(lbuf)
/*
 *	match line with the format 
 *	variable "multiply defined":
 */
char	*lbuf ;
{
	char	word[512] ;
	char	linebuf[512] ;
	char	c ;

	if (
		sscanf(lbuf, "%*s multiply defined%c",  &c) > 0
		&&
		c == ':'
	   )
	{
	    
		while ((c = getc(infp)) == '\t')
		{
			if (
			    fgets(linebuf, 512, infp) != NULL
			    &&
			    sscanf(linebuf, "%[^:]: %d", filename, &line) > 1
			   )
			{	
				fprintf(
					outfp,
					"\"%s\", line %d: %s", 
					filename, 
					line, 
					lbuf 
				       ) ;
		        }
			else return(-1) ;
		}
		ungetc(c, infp) ;
		return(1) ;
	}
	else return(0) ;

}

int	CynMatch4(lbuf)
/*
 *	match line with the format 
 *	"function" function: library 
 *      or
 *      "function" function: file: line
 */
char	*lbuf ;
{
	char	word[512] ;
	char	linebuf[512] ;
	char	c ;

	if (
		sscanf(lbuf, "function %*[^:]: %[^\n]",  word) > 0
	   )
	{
		lbuf[strlen(lbuf) - 1] = '\0' ;
		while ((c = getc(infp)) == '\t')
		{
			if (
			    fgets(linebuf, 512, infp) != NULL
			    &&
			    sscanf(linebuf, "%[^:]: %d, %[^\n]", filename, &line, mesg) > 2
			   )
			{	
				fprintf(
					outfp,
					"\"%s\", line %d: %s %s\n", 
					filename, 
				        line,
					lbuf,
				        mesg 
				       ) ;
		        }
			else return(-1) ;
		}
		ungetc(c, infp) ;
		return(1) ;
	}
	else return(0) ;
}



END-OF-FILE

if [ "$filename" != "/dev/null" ]
then
  size=`wc -c < $filename`

  if [ $size != 3424 ]
  then
    echo $filename changed - should be 3424 bytes, not $size bytes
  fi

  chmod 600 $filename
fi

# ---------- file etag.c ----------

filename="etag.c"

if [ -f $filename ]
then
  echo File \"$filename\" already exists\!  Skipping...
  filename=/dev/null		# throw it away
else
  echo extracting file etag.c...
fi

cat << 'END-OF-FILE' > $filename
/*	
 *	This is a program to make the debugging of C programs much
 *	easier and faster. It makes use of the capability of vi
 *	and terminfo. 
 *	Currently it can work with errors output from cc, lint, 
 *	ld, yacc, cyntax and make. 
 *	
 *	Written by M.C. KAM
 */
#define		SINGLE
#define 	MAXEXSIZE	62
#define		BELL		"\007\007\007\007\007\007\007\007\007"

#include	<stdio.h>

#ifdef	BSD
#define	strchr	index
#define	strrchr	rindex
#endif

extern		char	*strrchr() ;
extern		int	strcmp() ;
extern		char	*getcmdpath() ;
extern		char	*getenv() ;
extern		FILE	*tmpfile() ;

extern		int	makelintag() ;
extern		int	makeldtag() ;
extern		int	makecctag() ;
extern		int	makecyntag() ;
static		void    creattag() ;


typedef	struct
{
	int	(*translator)() ;
	int	checktype ;

}	ERRDRIVER ;

ERRDRIVER	driverlist[] = 
{
		makecyntag,  1,
		makecctag,  0,
		makeldtag,  0,
		makelintag, 0,
		NULL
} ;


static		FILE		*srcefp ;
static		FILE		*errfp;
static		FILE		*tmpfp ;
static		FILE		*terrfp ;
static		char		tempfile[64] ;
static		char		cursrcefile[128] ;
static		char		curlinebuf[512] ;
static		char		lbuf[512];
static		int		curlineno ;
static		int		patmatch ;
static		FILE		*fp;
static		int		tabsize = 0 ;
static		int		line  = 0 ;
static		char		tagfile[50] ;

main(argc, argv, envp)
int	argc;
char	**argv;
char	**envp;
{
	int			i ;
	char			**newenvp ;
	int			eline;
	int			initflag = 0 ;
	char			filename[100];
	char			errmsg[132] ;
	char			tagmsg[512] ;
	char			envstr[300] ;
	char			srhpat[50] ;
	char			*homep ;
	extern	char		*getlogin() ;
	extern	char		*ttyname() ;
	extern  char		*strrchr() ;
	long			addr ;
	

	

	if (isatty(0) == 0)
	{
		fputs(BELL, stderr) ;	
		sleep(1) ;
		fputs(BELL, stderr) ;	
		sleep(1) ;
		fputs(BELL, stderr) ;	
		exit(1) ;
	}
	else homep = strrchr(ttyname(0), '/') + 1 ;
	line = 0 ;
	strcpy(tagfile, "/tmp/tags.") ;
	strcat(tagfile, homep) ;
	strcat(tagfile, getlogin());
	switch (*argv[1])
	{
	case '+' : 
		(void) getheader(&line, &patmatch, &tabsize) ;
		 if ((++line )  > tabsize)  
		 {
			fputs(BELL, stdout) ;
			fseek(fp, 3 * sizeof(int) + tabsize * sizeof(long), 0) ;
			fread((char *) &addr, sizeof (long), 1, fp) ; 
			fseek(fp, addr + 55 * sizeof(char), 0) ;
			fprintf(fp, "/$/%62.s\n", "") ;
			fclose(fp) ;
			tprintf("ve : no more error line found");
			exit(0) ;
		 }
		 break;
	case '=' : 
		(void) getheader(&line, &patmatch, &tabsize) ;
		 break;
	case '-' : initflag = -1 ;
		(void) getheader(&line, &patmatch, &tabsize) ;
		if (line > 1)
			line-- ;
		else 
		{
			fputs(BELL, stdout) ;
			tprintf("ve : no more previous error line");
			exit(0) ;
		}
		break;
	default: 
		 if (argc < 2)
		 {
			fprintf(stderr, "usage : %s file\n", argv[0]) ;
			exit(1) ;
		 }
		 else 
		 {
			 if ((errfp = fopen(argv[1], "r")) == NULL)
			 {
				fprintf(stderr, "%s : can not open error file : %s\n", argv[0], argv[1]) ;
				exit(2) ;
			 }
		 }
		 if (getc(errfp) != EOF)
		   rewind(errfp) ;
		 else 
		 {
			fputs(BELL, stdout) ;
			tprintf("ve : no recognisable syntax error ");
			exit(1) ;
		 }
		 patmatch = (argc <= 2) ;
		 openfile() ;
		 CallTranslator() ;
		 initflag = 1 ;
		 line++ ;
		 fputs(BELL, stderr) ;
		 break;
	}
	fseek(fp, (line - 1) * sizeof( long), 1) ;
	fread((char *) &addr, sizeof (long), 1, fp) ; 
	fseek(fp, addr, 0) ;
	fgets(lbuf, 512, fp) ;
	rewind(fp) ;
	fwrite((char *) &line, sizeof (int), 1, fp) ; 
	fseek(fp, 3 * sizeof(int) + tabsize * sizeof(long), 0) ;
	fread((char *) &addr, sizeof (long), 1, fp) ; 
	fseek(fp, addr, 0) ;
	if (*lbuf == '"')
	{
		if (sscanf(lbuf, "\"%[^\"]\", line %d: %[^\^\n]%[^\n]", 
			   filename, &eline, errmsg, tagmsg) > 3 
		    && 
		    (
			patmatch == 1
			&&
			initflag != 1
		    )
		   )
		{
		     char	*ch ;

			tprintf("%s, %d: %s", filename, eline, errmsg) ;
			ch = (initflag == -1 ? "?" : "/") ;
			fprintf(fp, "err\t%50.50s\t%s%s%-*.1s\n", filename, ch,  tagmsg, MAXEXSIZE + 2  - strlen(tagmsg), ch);
		}
		else    
		{
			tprintf("%s, %d: %s", filename, eline, errmsg) ;
			fprintf(fp, "err\t%50.50s\t%5d%60.s\n", filename, eline, "");
		}
	}
	else  if (*lbuf == '\'') 
	{
	     char	*ch ;

		ch = (initflag == -1 ? "?" : "/") ;
		sscanf(lbuf, "'%[^']', %s : %[^\n]", filename, srhpat, tagmsg)  ;
		tprintf("%s, %s", filename, tagmsg ) ;
		fprintf(fp, "err\t%50.50s\t%s%.*s%-*.1s\n", 
			filename, ch,  MAXEXSIZE + 1, srhpat, 
			MAXEXSIZE + 2  - strlen(srhpat), ch);
	}
	fclose(fp) ;
	if (initflag == 1 ) 
	{
		for (i = 0 ; envp[i] != NULL && strncmp(envp[i], "EXINIT", 6) ; i++) ;
		if (envp[i] != NULL)
		{
			sprintf(
				envstr, 
				"EXINIT=%s | set tags=%s\\ tags | set nu | map ? :!%s +\r:ta err\r | map ? :!%s +\r | map ? :ta err\r | map ? :!%s =\r:ta err\r | map ? :!%s -\r:ta err\r | set nomagic", 
				envp[i]+7, 
				tagfile,
				argv[0],
				argv[0],
				argv[0],
				argv[0]
			       );
			envp[i] = envstr ;
			fflush(stdout) ;
			execle(getcmdpath("vi"), "vi", "-t", "err", 0, envp) ;
			perror("ve") ;
			exit(2) ;
		}
		else
		{
			int	j ;
			newenvp = (char **) malloc ((i + 2) * sizeof (char **)) ;

			for (j = 0 ; j < i ; j++)
				newenvp[j] = envp[j] ;
			sprintf(
				envstr, 
				"EXINIT=set tags=%s\\ tags | set nomagic | map ? :!%s +\r:ta err\r | map ? :!%s =\r:ta err\r |  map ? :!%s -\r:ta err\r | set nu",
				 tagfile,
				 argv[0],
				 argv[0],
				 argv[0]
				);
			newenvp[i+1] = NULL ;
			newenvp[i] = envstr ;

			fflush(stdout) ;
			execle(getcmdpath("vi"), "vi", "-t", "err", 0, newenvp) ;
			perror("ve") ;
			exit(2) ;
		}
	}
}


CallTranslator()
{
	register	ERRDRIVER	*errdp ;

	for (
	      errdp = driverlist ; 
	      errdp->translator != NULL ;
	      errdp++
	    ) 
	{
	      if ((* errdp->translator)( errfp, terrfp) == 1 && errdp->checktype == 0)
	          break ;  
	      else
	          rewind(errfp) ;
	}
	fclose(errfp) ;
	rewind(terrfp) ;
	preprocess() ;
	
}
	
preprocess()
{


	*cursrcefile = '\0' ;
	tabsize = 0 ;
	while (fgets(lbuf, 512, terrfp) != NULL)
	{
	         switch (*lbuf )
		 {
		    case '\'' :
			fputs(lbuf, tmpfp) ;
			 tabsize++ ;
			break ;
		    case '"' :  lbuf[strlen(lbuf) - 1]  = '\0' ;
				extract(lbuf) ;
				 tabsize++ ;
				break ;
		 }
	}
	if (tabsize != 0)
		creattag(tmpfp) ;
	else
	{
		fputs(BELL, stdout) ;
	    	tprintf("ve : no recognisable syntax error ");
	    	exit(1) ;
		
	}

}


extract(linebuf)
char	*linebuf ;
{
	char	filename[64] ;
	int	eline ;
	
	if (sscanf(linebuf, "\"%[^\"]\", line %d:", filename, &eline) <= 1)
		return ;
	if (! strcmp(cursrcefile, filename))
	{
		if (curlineno > eline)
		{

			rewind(srcefp) ;
			curlineno = 0 ;
		}
		processsrce(linebuf, eline) ;
	}
	else
	{
		if (srcefp != NULL)
		    fclose(srcefp) ;
		if ((srcefp = fopen(filename, "r")) == NULL)
			   fprintf(tmpfp, "%s\n", linebuf) ;
		else
		{
			curlineno = 0 ;
			strcpy(cursrcefile, filename) ;
			processsrce(linebuf, eline) ;
		}
	}
}
			
			






processsrce(linebuf, eline)
int	eline ;
char	linebuf[];
{
	if (curlineno < eline)
	{
		do 
		{
		    if (fgets(curlinebuf, 512, srcefp) == NULL)
			break ;
		    else curlineno ++ ;
		}
		while (curlineno < eline) ;
		if (curlineno < eline)
		{
			fprintf(tmpfp, "%s\n", linebuf) ;
			return ;
		}
		else
		{
		  int	LineLen ;
		  register char	*cp ;

		  cp = curlinebuf ;
		  /*
		   *  put extra '\' to quote the magic char
		   */
		   while (*cp != '\0')
		   {
			if (*cp == '\\' || *cp == '/')
			{
				mvstr(cp) ;
				*cp++ = '\\' ;
			}
			cp++ ;
		   }
		  if ((LineLen = strlen(curlinebuf)) <= MAXEXSIZE)
			curlinebuf[LineLen - 1] = '$' ;
		  else
			curlinebuf[MAXEXSIZE] = '\0' ;
		}
	}
	fprintf(tmpfp, "%s^%s\n", linebuf, curlinebuf) ;
}

mvstr(tcp)
char	tcp[] ;
{
	register	int	slen ;
	
	for (slen = strlen(tcp) + 1 ; slen > 0 ; slen--) 
	{
		tcp[slen ] = tcp[slen - 1] ;
	}
}
	


#ifdef  TERMINFO
#include	<curses.h>
#include 	<term.h>
#endif

tprintf(format, p1, p2, p3, p4)
char	*format ;
{
	char    buf[512] ;

#ifdef TERMINFO
	setupterm(0, 1, 0) ;
	if (has_status_line == 0)
	{
	/*
         *	put it out to the status line	
	 */

		
		putp(to_status_line) ;
		fprintf(stdout, format, p1, p2, p3, p4) ;
		putp(from_status_line) ;
	}
	else
#endif
	{
		fprintf(stdout, format, p1, p2, p3, p4) ;
		fputc('\n', stdout) ;
	}

#ifdef TERMINFO
	resetterm() ;
#endif

}


openfile()
{
	
		if ((tmpfp = tmpfile()) == NULL || (terrfp = tmpfile()) == NULL)
		{
			fprintf(stderr, "ve : can not open temporary file for writing\n") ;
			exit(2) ;
		}
}




static	void
creattag(tempfp)
FILE	*tempfp ;
{
	long	address  ;
	long	startadd  ;
	register 	int	c ;
	extern  long  ftell() ;
	
	

	rewind(tempfp) ;
	if ((fp = fopen(tagfile, "w+")) == NULL)
	{
		perror("ve") ;
		exit(1) ;
	}
/*
	setbuf(fp, NULL) ;
/**/
	startadd = 3 * sizeof (int) + (tabsize + 1) * sizeof( long) ;
	fwrite((char *) &line, sizeof(int), 1, fp) ;
	fwrite((char *) &patmatch, sizeof(int), 1, fp) ;
	fwrite((char *) &tabsize, sizeof(int), 1, fp) ;
	fwrite((char *) &startadd, sizeof(long), 1, fp) ;
	while ((c = getc(tempfp)) != EOF)
	{
		if (c == '\n')
		{
			address = ftell(tempfp) + startadd ;
			fwrite((char *) &address, sizeof(long), 1, fp) ;
		}
	}
	rewind(tempfp) ;
	while (( c = getc(tempfp)) != EOF)
		putc(c, fp) ;
	fseek(fp, 3 * sizeof(int), 0) ;
}



			
			
	
	
	
	
	
getheader(errno, type, size)
int	*errno ;
int	*type ;
int	*size ;
{
	if ((fp = fopen(tagfile, "r+")) == NULL)
	{
		perror("ve") ;
		exit(1) ;
	}
	else
	{
/*
		setbuf(fp, NULL) ;
/**/
		fread((char *)errno, sizeof(int), 1, fp) ;
		fread((char *)type, sizeof(int), 1, fp) ;
		fread((char *)size, sizeof(int), 1, fp) ;
	}
}

#ifdef	GETLOGIN

#include	<pwd.h>

char *
getlogin()
{
	extern	struct	passwd	*getpwuid();
	struct	passwd		*pwd;

	if ((pwd = getpwuid(getuid())) == (struct passwd *) NULL)
		return NULL;
	else
		return(pwd->pw_name);
}
#endif	GETLOGIN

#ifdef	TMPFILE
FILE    *
tmpfile()
{
      char     filename[15] ;   
      FILE     *fp;

      strcpy(filename, "/tmp/tagXXXXXX") ;
      if ((fp = fopen(mktemp(filename), "w+")) != NULL)
      {
		unlink(filename);
		return(fp);
      }
      return(NULL);
}
#endif	TMPFILE

/*
 *
 *	getcmdpath.c returns the full path name of the argument cmd
 *	by looking through the environment variable PATH. 
 *	
 *
 */
char  *
getcmdpath(cmd)
char *cmd;
{
    extern char *getenv();
    extern char	*strchr();
    char *path, *cp;
    static  char buf[200];
    char patbuf[512];

    if (cmd == NULL || *cmd == '/')
	return(cmd) ;
	strcpy(patbuf, getenv("PATH"));
	path = patbuf;
	cp = path;

	while(1) {
	    if (path == NULL || *path == '\0') 
		return(NULL) ;
	    if (*path == ':')
		strcpy(buf, cmd);
	    else
	    {
	        cp = strchr(path, ':');
	        if (cp != NULL)
	    	    *cp = '\0';
	        sprintf(buf, "%s/%s", path, cmd);
	    }
	    path = ++cp;

	    if (access(buf, 1) == 0) {
		return(buf) ;
	    }
	}
}
END-OF-FILE

if [ "$filename" != "/dev/null" ]
then
  size=`wc -c < $filename`

  if [ $size != 10732 ]
  then
    echo $filename changed - should be 10732 bytes, not $size bytes
  fi

  chmod 600 $filename
fi

# ---------- file ldtag.c ----------

filename="ldtag.c"

if [ -f $filename ]
then
  echo File \"$filename\" already exists\!  Skipping...
  filename=/dev/null		# throw it away
else
  echo extracting file ldtag.c...
fi

cat << 'END-OF-FILE' > $filename
#include <stdio.h>

int	makeldtag(infp, outfp)
FILE	*infp ;
FILE	*outfp ;
{
	int	find = 0 ;
	char	lbuf[512] ;
	char	varname[100] ;
	char	filename[100] ;
	char	filename2[100] ;

	while (fgets(lbuf, 512, infp) != NULL)
	{
	         if (
			*lbuf == '_'  
			&& 
			sscanf(lbuf+1, "%s %s",  varname, filename) > 1
		    )  
		{
			filename[strlen(filename) - 1 ] = 'c' ;
			fprintf(outfp, "'%s', %s : undefined symbol %s\n", filename, varname, varname ) ;
			find = 1 ;
		}
	        else if ( sscanf(
				 lbuf, 
				 "ld : Symbol _%s in %s is multiply defined. First defined in %s",
				 varname,
				 filename,
				 filename2
			        ) > 2
			 )
		{
			filename[strlen(filename) - 1 ] = 'c' ;
			filename2[strlen(filename2) - 1 ] = 'c' ;
			fprintf(
				outfp, 
				"'%s', %s : multiply defined symbol %s. First defined in %s\n",
				filename,
				varname,
				varname,
				filename2
			       ) ;
			find = 1 ;
		}
				
	}
	return(find) ;
}
END-OF-FILE

if [ "$filename" != "/dev/null" ]
then
  size=`wc -c < $filename`

  if [ $size != 944 ]
  then
    echo $filename changed - should be 944 bytes, not $size bytes
  fi

  chmod 600 $filename
fi

# ---------- file lintag.c ----------

filename="lintag.c"

if [ -f $filename ]
then
  echo File \"$filename\" already exists\!  Skipping...
  filename=/dev/null		# throw it away
else
  echo extracting file lintag.c...
fi

cat << 'END-OF-FILE' > $filename
#include 	<stdio.h>

char		lbuf[512] ;
char		rbuf[512] ;
char		mbuf[512] ;
char		*varname[100] ;
char		filename[100] ;
int		linenum1 ;
int		linenum2 ;
int		linenum3 ;
int		lineref = 0 ;
int		j ;
FILE		*infp ;
extern  char		*strchr() ;
extern  char		*strrchr() ;


char	*getline(linebuf)
char	*linebuf ;
{
	if (fgets(linebuf, 512, infp) != NULL)
	{
	  lineref++ ;
/*
	  fprintf(stderr, "line %d : %s\n", lineref, linebuf) ;
*/
	  linebuf[strlen(linebuf) - 1] = '\0' ;
	  return(linebuf) ;
	}
	else return(NULL) ;
}

int makelintag(infilep, outfp)
FILE	*infilep ;
FILE	*outfp ;
{

	int	lintfilepresent = 0 ;

	while (fgets(lbuf, 512, infilep) != NULL)
	{
	         if  (*lbuf == '=' )
		 {
			if ( ! strncmp(lbuf + 1, "=============", 13))
			{
				lintfilepresent = 1 ;
				rewind(infilep) ;
				break ;
			}
		 }
	}
	if (lintfilepresent == 0)
	{
		/*
		fprintf(stderr, "Lint file not present\n") ;
		/**/
		return(0) ;
	}
	else infp = infilep ;
	/*
	fprintf(stderr, "Lint file present\n") ;
	/**/
	while (getline(lbuf) != NULL)
	{
		if (*lbuf == '\0')
		   continue ;
		if (*lbuf == '=')
		{
		       if  (getline(lbuf) == NULL)
			  goto end ;
			while (*lbuf != ' ')
			{
				strcpy(rbuf, lbuf) ;
				if (getline(lbuf) == NULL)
			  		goto end ;
		
				if (match3(lbuf, mbuf, varname,  filename, &linenum1)) 
				{
				    do
				    {
					strcat(mbuf, " - ");
					strcat(mbuf, varname) ;
					fprintf(outfp, "\"%s\", line %d: %s: %s\n", filename, linenum1, rbuf, mbuf) ;
					if (getline(lbuf) == NULL)
					    goto end ;
				    }
				    while (match3(lbuf, mbuf, varname, filename, &linenum1) ) ;
				
				}
				else if (match4( lbuf, mbuf, filename, &linenum1))
				{
				    do
				    {
					fprintf(outfp, "\"%s\", line %d: %s: %s\n", filename, linenum1, rbuf, mbuf) ;
					if (getline(lbuf) == NULL)
					   goto end ;
				    }
				    while (match4( lbuf, mbuf, filename, &linenum1)) ;
				}
		    }
		   goto end ;
		}

	 loop1: strcpy(rbuf, lbuf) ;
	        if (getline(lbuf) == NULL)
		  goto end ;
		switch (*lbuf)
		{
			case '=' :  sscanf(rbuf, "%s", filename) ;
				    /*
				    fprintf(stderr, "File %s found\n", filename) ;
				    /**/
				    break ;
			case '\0' : continue ;
			default   : 
				    goto loop1 ;
		}
		if (getline(lbuf) == NULL)
		  goto end ;
                if (! match1(lbuf,& linenum1, mbuf)) 
		{
        loop2 :	   strcpy(rbuf, lbuf) ;
	           if (getline(lbuf) == NULL)
			goto end ;
		        if (*lbuf == '\0')
			     continue ;
			if ((j = match5(lbuf, &linenum1, &linenum2, &linenum3)) > 1)
			{
			    do
			    {
		   	        fprintf(outfp, "\"%s\", line %d: %s %s\n", filename, linenum1, rbuf, mbuf) ; 
		   		fprintf(outfp, "\"%s\", line %d: %s %s\n", filename, linenum2, rbuf, mbuf) ; 
			      if (j > 2) 
		   		fprintf(outfp, "\"%s\", line %d: %s %s\n", filename, linenum3, rbuf, mbuf) ; 
				if (getline(lbuf) == NULL)
				  goto end ;
			    }
			    while ((j = match5(lbuf, &linenum1, &linenum2, &linenum3)) > 1 ) ;
		        }
			else if (match2(lbuf, &linenum1, mbuf) )
			{
			    do
			    {
		   		fprintf(outfp, "\"%s\", line %d: %s %s\n", filename, linenum1, rbuf, mbuf) ; 
				if (getline(lbuf) == NULL)
				    goto end ;
			    }
			    while (match2(lbuf, &linenum1, mbuf) ) ;
			}
		        goto loop2 ;
		
		}
		else
		do
		{
			
		   fprintf(outfp, "\"%s\", line %d: %s\n", filename, linenum1, mbuf) ; 
		   if (getline(lbuf) == NULL)
			goto end ;
		}
		while (match1( lbuf, &linenum1, mbuf) ) ;
		goto loop2 ;
	}
end :   return(1) ;
}
		   
		   
		
int	match1(linebuf, linenum, msg)
/*
 *	match line with the format
 *		(line)  message
 */
char	*linebuf ;
int	*linenum ;
char	*msg ;
{
	return(sscanf(linebuf, "(%d) %[^$]", linenum, msg) > 1) ;
}
		
				   
int	match2(linebuf, linenum, msg)
/*
 *	match line with the format
 *		4 spaces (line)  message
 */
char	*linebuf ;
int	*linenum ;
char	*msg ;
{
	int 	i ;

	for (i = 0 ; linebuf[i] != '\0' && linebuf[i]  == ' ' ; i++);

	if (i != 4)
	   return(0) ;
	else
	{
	   *msg = '\0' ;
	   return(sscanf(linebuf, " (%d) %[^$]", linenum, msg) > 0) ;
	}
}
		
				   
		
			
int   match3(linebuf, msg, vname, fname, linenum)
/*
 *	match line with the format
 *		message	 file1(line1) :: file2(line2)
 */
char	*linebuf ;
char	*msg ;
char	*fname ;
char	*vname ;
int	*linenum ;
{
	int 	i ;

	for (i = 0 ; linebuf[i] != '\0' && linebuf[i]  == ' ' ; i++);

	if (i != 4)
	   return(0) ;
	if (sscanf(linebuf, " %[^\t]\t%s :: %[^\(](%d)", msg, vname, fname, linenum) > 3) 
	{
	
		if (fname[strlen(fname) - 2] != '.')
		{
			char	filenamebuf[100]  ;
			int	line ;

			sscanf(vname, "%[^\(](%d)", filenamebuf, &line) ;
			sprintf(vname, "%s(%d)", fname, *linenum) ;
			strcpy(fname, filenamebuf) ;
			*linenum = line ;
		}
		return(1) ;
	}
	else
		return(0) ;
			
			
}


int   match4(linebuf, msg, fname, linenum)
/*
 *	match line with the format: 
 *		message 	file(line)
 */
char	*linebuf ;
char	*msg ;
char	*fname ;
int	*linenum ;
{
	int 	i ;

	for (i = 0 ; linebuf[i] != '\0' && linebuf[i]  == ' ' ; i++);

	if (i != 4)
	   return(0) ;
	
	if (sscanf(linebuf, " %s %[^\(](%d)", msg, fname, linenum) > 2)
	{
		i = strlen(fname) - 1  ;
		if (fname[i] == '?')
			fname[i] = '\0' ; 
		return(1) ;
	}
	else return(0) ;
}


int	match5(linebuf, lnum1, lnum2, lnum3)
/*
 *	match line which contains only numbers 
 */
char	*linebuf ;
int	*lnum1 ;
int	*lnum2 ;
int	*lnum3 ;
{
	int 	i ;

	for (i = 0 ; linebuf[i] != '\0' && linebuf[i]  == ' ' ; i++);

	if (i != 4)
	   return(0) ;
	
	return( sscanf(linebuf, " (%d)\t(%d)\t(%d)", lnum1, lnum2, lnum3)) ;
}
END-OF-FILE

if [ "$filename" != "/dev/null" ]
then
  size=`wc -c < $filename`

  if [ $size != 5575 ]
  then
    echo $filename changed - should be 5575 bytes, not $size bytes
  fi

  chmod 600 $filename
fi

echo done

exit 0