/*
 * |-----------------------------------------------------------|
 * | Copyright (c) 1991, 1990 MIPS Computer Systems, Inc.      |
 * | All Rights Reserved                                       |
 * |-----------------------------------------------------------|
 * |          Restricted Rights Legend                         |
 * | Use, duplication, or disclosure by the Government is      |
 * | subject to restrictions as set forth in                   |
 * | subparagraph (c)(1)(ii) of the Rights in Technical        |
 * | Data and Computer Software Clause of DFARS 252.227-7013.  |
 * |         MIPS Computer Systems, Inc.                       |
 * |         950 DeGuigne Avenue                               |
 * |         Sunnyvale, California 94088-3650, USA             |
 * |-----------------------------------------------------------|
 */
#ident	"$Header: cxr.c,v 1.10.2.1 92/06/24 13:27:16 marker Exp $"

/*	Copyright (c) 1984 AT&T	*/
/*	  All Rights Reserved  	*/

/*	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T	*/
/*	The copyright notice above does not evidence any   	*/
/*	actual or intended publication of such source code.	*/

/*	3.0 SID #	1.2	*/
#include <stdio.h>
#include <ctype.h>
#include <signal.h>
#include <sys/euc.h>						/* MNLS */
#include <getwidth.h>						/* MNLS */
#include <locale.h>						/* MNLS */
#include "owner.h"

#ifdef FLEXNAMES
#define MAXWORD (BUFSIZ / 2)
#define MAXRFW MAXWORD
#define MAXRFL MAXWORD
#else
#define MAXWORD	100	/* maximum length of word */
#define MAXRFW	20
#define MAXRFL	50
#endif
#define MAX	BUFSIZ	/* maximum length of line */
#define MAXARG	60	/* maximum number of arguments */
#define MAXDEFS	20	/* maximum number of defines or undefines */
#define MAXINC	10	/* maximum number of include directories */
#define BASIZ	50	/* funny */
#define LPROUT	70	/* output */
#define TTYOUT	30	/* numbers */
#define YES	1
#define NO	0
#define LETTER	'a'
#define DIGIT	'0'
#define XCPP	"xcpp"
#define XREF	"xpass"
#define SRT	"/bin/sort"

extern char
	*calloc(),
	*strcat(),
	*strcpy(),
	*mktemp(),
	*getenv();

char	*xref,	/* path to the cross-referencer */
	*xcpp,	/* path to cxref pre-processor */
	*cfile,	/* current file name */
	*tmp1,	/* contains preprocessor result */
	*tmp2,	/* contains xcpp and xpass cross-reference */
	*tmp3,	/* contains transformed tmp2 */
	*tmp4;	/* contains sorted output */

char	*clfunc = "   --   ";	/* clears function name for ext. variables */

char	*myalloc();

char	xflnm[MAXWORD],	/* saves current filename */
	funcname[MAXWORD],	/* saves current function name */
	sv1[MAXRFL],	/* save areas used for output printing */
	sv2[MAXRFL],
	sv3[MAXRFL],
	sv4[MAXRFL],
	buf[BUFSIZ];

char	*arv[MAXARG],
	*predefs[MAXDEFS],
	*preunds[MAXDEFS],
	*incdirs[MAXINC];

char    argdirs[MAXINC][300];

int	cflg = NO,	/* prints all given files as one cxref listing */
	silent = NO,	/* print filename before cxref? */
	tmpmade = NO,	/* indicates if temp file has been made */
	inafunc = NO,	/* in a function? */
	fprnt = YES,	/* first printed line? */
	addlino = NO,	/* add line number to line?? */
	hflag = YES,	/* print header? */
	ddbgflg = NO,	/* debugging? */
	idbgflg = NO,
	bdbgflg = NO,
	tdbgflg = NO,
	edbgflg = NO,
	xdbgflg = NO,
	LSIZE = LPROUT,	/* default size */
	lsize = 0,	/* scanline: keeps track of line length */
	sblk = 0,	/* saves first block number of each new function */
	fsp = 0,	/* format determined by prntflnm */
	defs = 0,	/* number of defines */
	undefs = 0,	/* number of undefines */
	incs = 0;	/* number of '-I' directories */
	nerrs = 0;	/* errors encountered along the way */
	wflg = 0;
	lflg = 0;	/* does not print local variables, prints only
			   global and file scope statistics. */
	static int Lflg = 0;           /* -L n prints n columns of numbers    */
	static int Wflg = 0;          /* -Wn,n,n,n changes widths of columns */


/*
** Standard widths for name, file, function and lines; number of
** columns per line (for lines) - these can change via the -W option.
*/
#define COL     5
static int col = COL;
static int linecol = 0;	/* keep track of the appearance of line number printed */

#define W_NAME  15
static int w_name = W_NAME;

#define W_FILE  13
static int w_file = W_FILE;

#define W_FUNC  15
static int w_func = W_FUNC;

#define W_LINE  4
static int w_line = W_LINE;


int	nword,	/* prntlino: new word? */
	nflnm,	/* new filename? */
	nfnc,	/* new function name? */
	nlino;	/* new line number? */
int	sawone = 0;   /* did we process any files? */

/* compiler environment variable */
char *systype = 0;
char *comp_target_root = 0;
char include_base[300];
char include_default[300];

/* MNLS */
eucwidth_t	wp;
int     difset1;        /* difference in each code set  */              /*MNLS*/
int     difset2;        /*  between cswidth and         */              /*MNLS*/
int     difset3;        /*  scrwidth                    */              /*MNLS*/


main(argc,argv)
	int argc;
	char *argv[];
{
	char *tmpnames;
        static char w_opt[] = "-w option cancelled by use of -L or -W\n";
	register int len;

	(void)setlocale(LC_ALL, "");	/*MNLS */
	getwidth(&wp);					/* MNLS */
	difset1 = wp._eucw1 - wp._scrw1;		/* MNLS */
	difset2 = wp._eucw2 - wp._scrw2;		/* MNLS */
	difset3 = wp._eucw3 - wp._scrw3;		/* MNLS */
	xref = myalloc(sizeof(OWNERBIN) + sizeof(XREF) - 1, 1);
	strcat(strcpy(xref, OWNERBIN), XREF);
	xcpp = myalloc(sizeof(OWNERBIN) + sizeof(XCPP) - 1, 1);
	strcat(strcpy(xcpp, OWNERBIN), XCPP);

	comp_target_root = getenv("COMP_TARGET_ROOT");

	mktmpfl();	/* make temp files */
	while (--argc > 0) {
		++argv;
		sblk = 0;
		/* special case for -systype xxx */
		if (strcmp(*argv,"-systype") == 0)
		{
		    if ( --argc > 0 )
		    {
			if (systype != 0)
			{
			    fprintf(stderr,
			    "cxref: only one -systype option allowed\n");
			    dexit(1);
			}
			systype = *++argv;
		    }
		    else
		    {
			fprintf(stderr,
			"cxref: missing argument for -systype\n");
			dexit(1);
		    }
		}
		if (**argv == '-') {
			switch (*++*argv) {
				/* prints cross reference for all files combined */
				case 'c':
					cflg = YES;
					continue;
				case 'd':
					ddbgflg = YES;
					continue;
				case 'h':
					hflag = NO;
				case 'i':
					idbgflg = YES;
					continue;
				case 'b':
					bdbgflg = YES;
					continue;
				case 'T':
					tdbgflg = YES;
					continue;
				case 'e':
					edbgflg = YES;
					continue;
				case 'x':
					xdbgflg = YES;
					continue;
				case 'D':
					if (strlen(*argv) < 2)
					{
					    fprintf(stderr,
					    "cxref: bad -D argument (%s)\n",
					    --*argv);
					    dexit(1);
					}
					if (defs < MAXDEFS) {
						predefs[defs++] = --*argv;
					}
					else {
						fprintf(stderr, "Too many defines\n");
						dexit(1);
					};
					continue;
				case 'U':
					if (strlen(*argv) < 2)
					{
					    fprintf(stderr,
					    "cxref: bad -U argument (%s)\n",
					    --*argv);
					    dexit(1);
					}
					if (undefs < MAXDEFS) {
						preunds[undefs++] = --*argv;
					}
					else {
						fprintf(stderr, "Too many undefines\n");
						dexit(1);
					};
					continue;
				case 'I' :
					if (strlen(*argv) < 2)
					{
					    fprintf(stderr,
					    "cxref: bad -I argument (%s)\n",
					    --*argv);
					    dexit(1);
					}
					if (incs < MAXINC) {
/* later we'll add in COMP_TARGET_ROOT and systype, so get just the name
 * skipping by the "-I"
 */
						incdirs[incs++] = ++*argv;
					}
					else {
						fprintf(stderr, "Too many '-I' options\n");
						dexit(1);
					};
					continue ;
				/* length option when printing on terminal */
				case 't':
				case 'w':
					if (argv[1] == '\0')
					{
					    fprintf(stderr,
					    "cxref:  missing argument for -w\n");
					    dexit(1);
					}
					wflg = 1;
					if (Lflg) {
						(void) fprintf(stderr, w_opt);
						break;
					}
					LSIZE = getnumb(++*argv) - BASIZ;
					if (LSIZE <= 0)
					    LSIZE = TTYOUT;
					continue;
				case 's':
					silent = YES;
					continue;
				/* output file */
				case 'o':
					if (--argc <= 0)
					{
					    fprintf(stderr,
					    "cxref:  missing argument for -o\n");
					    dexit(1);
					}
					if (freopen(*++argv, "w", stdout) == NULL) {
						perror(*argv);
						dexit(1);
					};
					continue;
#ifdef DEBUG
/* get the xcpp or xref from non-std places */
				case 'j':
				    xref = *++argv;
				    argc--;
				    continue;
				case 'k':
				    xcpp = *++argv;
				    argc--;
				    continue;
#endif
				case 'l':
				    lflg = 1;
				    continue;
				case 'L':
				    if (argv[1] == '\0')
					{
					    fprintf(stderr,
					    "cxref:  missing argument for -L\n");
					    dexit(1);
					}
				    if (wflg)
					(void) fprintf(stderr, w_opt);
				    Lflg = 1;
				    col = getnumb(++*argv);
		                    if (col <= 0) {
                    			(void) fprintf(stderr,"bad number to -L option\n");
                    			exit(1);
                		    }
				    continue;
				case 'W':
				   /*
            			    Change default widths; comma separated 
  				    list where all 4 must be specified:
            			    w_name, w_file, w_func, w_line
            		    	   */
				   if (wflg)
					(void) fprintf(stderr, w_opt);
				   Wflg = 1;
				   len = strlen(++*argv);
				   tmpnames = (char *) malloc(len+1);
				   (void) strcpy(tmpnames, *argv);
				   w_name = atoi(strtok(tmpnames, ","));
				   w_file = atoi(strtok(NULL, ","));
				   w_func = atoi(strtok(NULL, ","));
				   w_line = atoi(strtok(NULL, ","));
				   if (! w_name || ! w_file || ! w_func || !w_line) {
				       (void) fprintf(stderr,"bad number to -W option\n");
					exit(1);
				   }
				   continue;
				default:
					fprintf(stderr, "cxref: invalid option '%c' - ignored\n", **argv);
			};
		}
		else if (strcmp(*argv + strlen(*argv) - 2, ".c") != 0)
		{
			fprintf(stderr,"cxref: %s is not a C file, ignored\n",*argv);
			continue;		/* not a .c file, skip */
		}
		else {
			if (*argv == 0)
			{
			    fprintf(stderr,
			    "cxref: no C input files specified\n");
			    dexit(1);
			}
			cfile = *argv;
			if (silent == NO)
				printf("%s:\n\n", cfile);
		}

		sawone = 1;
		doxref();	/* find variables in the input files */
		if (cflg == NO) {
			sortfile();	/* sorts temp file */
			prtsort();	/* print sorted temp file when -c option is not used */
			tunlink();	/* forget everything */
			mktmpfl();	/* and start over */
		};
	};
	if ( sawone == 0)
	{
	    fprintf(stderr,"cxref: no C input files specified\n");
	    dexit(1);
	}
	if (cflg == YES) {
		sortfile();	/* sorts temp file */
		prtsort();	/* print sorted temp file when -c option is used */
	};
	tunlink();	/* unlink temp files */
	exit (0);
}

	/*
	 * This routine calls the program "xpass" which parses
	 * the input files, breaking the file down into
	 * a list with the variables, their definitions and references,
	 * the beginning and ending function block numbers,
	 * and the names of the functions---The output is stored on a
	 * temporary file and then read.  The file is then scanned
	 * by tmpscan(), which handles the processing of the variables
	 */

doxref()
{

	register int i, n;
	FILE *fp, *tfp;
	char line[MAXRFL], s1[MAXRFW], s2[MAXRFW];
	char argsystype[30];
	char *p;

	strcpy(include_base,"-I");
	if ( comp_target_root != 0)
	{
	    strcat(include_base, "/");
	    strcat(include_base,comp_target_root);
	}
	if ( systype != 0)
	{
	    strcat(include_base, "/");
	    strcat(include_base,systype);
	}

	arv[0] = "xcpp";
	arv[1] = "-F";
	arv[2] = tmp2;
	arv[3] = cfile;
	arv[4] = tmp1;
	arv[5] = "-Dmips";
	arv[6] = "-DLANGUAGE_C";
	arv[7] = "-Dunix";
	arv[8] = "-Dhost_mips";
	arv[9] = "-DMIPSEB";
	for (n = 10, i = 0; i < defs; i++) {
		arv[n++] = predefs[i];
	};
	if (systype != 0)
	{
	    /* generate -DSYSTYPE_xxx */
	    p = systype;
	    while (*p)
		*p++ = toupper(*p);
	    strcpy(argsystype,"-DSYSTYPE_");
	    strcat(argsystype,systype);
	    arv[n++] = argsystype;
	}
	else
	{
	    arv[n++] = "-DSYSTYPE_SYSV";
	}
	for (i = 0; i < undefs; i++) {
		arv[n++] = preunds[i];
	};
	if ( (comp_target_root != 0) || (systype != 0) )
	{
	    strcpy(include_default,include_base);
	    strcat(include_default,"/usr/include");
	    arv[n++] = include_default;
	}
	for (i = 0; i < incs; i++) {
		strcpy(&argdirs[i][0],include_base);
		strcat(&argdirs[i][0],incdirs[i]);
		arv[n++] = &argdirs[i][0];
	};
	arv[n] = 0 ;
	if ( callsys(xcpp, arv) > 0) {
		fprintf(stderr, "xcpp failed on %s!\n", cfile);
		dexit(1);
	};

	i = 0;
	arv[i++] = "xpass";
	if (ddbgflg)
		arv[i++] = "-d";
	if (idbgflg)
		arv[i++] = "-I";
	if (bdbgflg)
		arv[i++] = "-b";
	if (tdbgflg)
		arv[i++] = "-t";
	if (edbgflg)
		arv[i++] = "-e";
	if (xdbgflg)
		arv[i++] = "-x";
	arv[i++] = "-f";
	arv[i++] = cfile;
	arv[i++] = "-i";
	arv[i++] = tmp1;
	arv[i++] = "-o";
	arv[i++] = tmp2;
	arv[i++] = 0;
	if ( callsys(xref, arv) > 0) {
		fprintf(stderr, "xpass failed on %s!\n", cfile);
		dexit(1);
	};

	/* open temp file produced by "xpass" for reading */
	if ((fp = fopen(tmp2, "r")) == NULL) {
		perror(tmp2);
		dexit(1);
	}
	else {
		setbuf(fp, buf);
		/*
		 * open a new temp file for writing
		 * the output from tmpscan()
		 */
		if ((tfp = fopen(tmp3, "a")) == NULL) {
			perror(tmp3);
			dexit(1);
		}
		else {

			/*
			 * read a line from tempfile 2,
			 * break it down and scan the
			 * line in tmpscan()
			 */

			while (fgets(line, MAX, fp) != NULL) {
				if (line[0] == '"') {
					/* removes quotes */
					for (i=0; line[i + 1] != '"'; i++) {
						xflnm[i] = line[i + 1];
					};
					xflnm[i] = '\0';
					continue;
				};
				sscanf(line, "%s%s", s1, s2);
				tmpscan(s1, s2, tfp);
			};
			if (tfp && (feof(tfp) || ferror(tfp)))
			{
				perror("cxref.tmpscan");
				dexit(1);
			}
			fclose(tfp);
		};
		if (fp && ferror(fp))
		{
			perror("cxref.tmpscan");
			dexit(1);
		}
		fclose(fp);
	};
}

	/*
	 * general purpose routine which does a fork
	 * and executes what was passed to it--
	 */

callsys(f, v)
	char f[], *v[];
{
	register int pid, w;
	int status;

	if ((pid = fork()) == 0) {
		/* only the child gets here */
		execvp(f, v);
		perror(f);
		dexit(1);
	}
	else
		if (pid == -1) {
			/* fork failed - tell user */
			perror("cxref");
			dexit(1);
		};
	/*
	 * loop while calling "wait" to wait for the child.
	 * "wait" returns the pid of the child when it returns or
	 * -1 if the child can not be found.
	 */
	while (((w = wait(&status)) != pid) && (w != -1));
	if (w == -1) {
		/* child was lost - inform user */
		perror(f);
		dexit(1);
	}
	else {
		/* check system return status */
		if (((w = status & 0x7f) != 0) && (w != SIGALRM)) {
			/* don't complain if the user interrupted us */
			if (w != SIGINT) {
				fprintf(stderr, "Fatal error in %s", f);
				perror(" ");
			};
			/* remove temporary files */
			dexit(1);
		};
	};
	/* return child status only */
	return((status >> 8) & 0xff);
}

	/*
	 * general purpose routine which returns
	 * the numerical value found in a string
	 */

getnumb(ap)
	register char *ap;
{

	register int n, c;

	n = 0;
	while ((c = *ap++) >= '0' && c <= '9')
		n = n * 10 + c - '0';
	return(n);
}

tmpscan(s, ns, tfp)
	register char s[];
	char ns[];
	FILE *tfp;
{

	/* this routine parses the output of "xpass"*/

	/*
	 * D--variable defined; R--variable referenced;
	 * F--function name; B--block(function ) begins;
	 * E--block(function) ends
	 */

	register int lino = 0;
	char star;

	/*
	 * look for definitions and references of external variables;
	 * look for function names and beginning block numbers
	 */

	if (inafunc == NO) {
		switch (*s++) {
			case 'D':
				star = '*';
				goto ahead1;
			case 'R':
				star = ' ';
ahead1:				lino = getnumb(ns);
				fprintf(tfp, "%s\t%s\t%s\t%5d\t%c\n", s, xflnm, clfunc, lino, star);
				break;
			case 'F':
				strcpy(funcname, s);
				star = '$';
				fprintf(tfp, "%s\t%c\n", s, star);
				break;
			case 'B':
				inafunc = YES;
				sblk = getnumb(s);
				break;
			default:
				fprintf(stderr, "SWITCH ERROR IN TMPSCAN: inafunc = no\n");
				dexit(1);
		};
	}
	else {
		/*
		 * in a function:  handles local variables
		 * and looks for the end of the function
		 */

		switch (*s++) {
			case 'R':
				star = ' ';
				goto ahead2;
				/* No Break Needed */
			case 'D':
				star = '*';
ahead2:				lino = getnumb(ns);
				if (!lflg)
				fprintf(tfp, "%s\t%s\t%s\t%5d\t%c\n", s, xflnm, funcname, lino, star);
				break;
			case 'B':
				break;
			case 'E':
				lino = getnumb(s);
				/*
				 * lino is used to hold the ending block
				 * number at this point
				 *
				 * if the ending block number is the
				 * same as the beginning block number
				 * of the function, indicate that the
				 * next variable found will be external.
				 */

				if (sblk == lino) {
					inafunc = NO;
				}
				break;
			case 'F':
				star = '$';
				fprintf(tfp, "%s\t%c\n", s, star);
				break;
			default:
				fprintf(stderr, "SWITCH ERROR IN TMPSCAN: inafunc = yes\n");
				dexit(1);
		};
	};
}

mktmpfl()
{

	/* make temporary files */

	tmp1 = tempnam(NULL, "xr1");
	tmp2 = tempnam(NULL, "xr2");	/* holds output of "xpass" */
	tmp3 = tempnam(NULL, "xr3");	/* holds output of tmpscan() routine */
	tmp4 = tempnam(NULL, "xr4");	/* holds output of tempfile 3 */
	tmpmade = YES;	/* indicates temporary files have been made */
	setsig();
}

tunlink()
{

	/* unlink temporary files */

	if (tmpmade == YES) {	/* if tempfiles exist */
		unlink(tmp1);
		unlink(tmp2);
		unlink(tmp3);
		unlink(tmp4);
	};
}

dexit(n)
	int n;
{
	/* remove temporary files and exit with error status */

	tunlink();
	exit(n);
}

setsig()
{

	/* set up check on signals */

	int sigout();

	if (isatty(1)) {
		if (signal(SIGHUP, SIG_IGN) == SIG_DFL)
			signal(SIGHUP, sigout);
		if (signal(SIGINT, SIG_IGN) == SIG_DFL)
			signal(SIGINT, sigout);
	}
	else {
		signal(SIGHUP, SIG_IGN);
		signal(SIGINT, SIG_IGN);
	};

	signal(SIGQUIT, sigout);
	signal(SIGTERM, sigout);
}

sigout()
{

	/* signal caught; unlink tmp files */

	tunlink();
	signal(SIGHUP, SIG_IGN);
	signal(SIGINT, SIG_IGN);
	signal(SIGTERM, SIG_IGN);
	dexit(1);
}

sortfile()
{
	/* sorts temp file 3 --- stores on 4 */

	register int status;

	arv[0] = "sort";
	arv[1] = "-o";
	arv[2] = tmp4;
	arv[3] = tmp3;
	arv[4] = 0;
	/* execute sort */
	if ((status = callsys(SRT, arv)) > 0) {
		fprintf(stderr, "Sort failed with status %d\n", status);
		dexit(1);
	};
}

prtsort()
{

	/* prints sorted files and formats output for cxref listing */

	FILE *fp;
	char line[MAX];

	/* open tempfile of sorted data */
	if ((fp = fopen(tmp4, "r")) == NULL) {
		fprintf(stderr, "CAN'T OPEN %s\n", tmp4);
		dexit(1);
	}
	else {
		if (hflag) {
			if (lflg)
			fprintf(stdout, "	SYMBOL	     FILE		     LINE\n");
			else
			fprintf(stdout, "	SYMBOL	     FILE		     FUNCTION	LINE\n");
			
		};
		while (fgets(line, MAX, fp) != NULL) {
			scanline(line);	/* routine to format output */
		};
		fprnt = YES;	/* reinitialize for next file */
		if (fp && ferror(fp))
		{
			perror("cxref.prtsort");
			dexit(1);
		}
		fclose(fp);
		putc('\n', stdout);
	};
}

scanline(line)
	char *line;
{

	/* formats what is to be printed on the output */

	register char *sptr1;
	register int och, nch;
	char s1[MAXRFL], s2[MAXRFL], s3[MAXRFL], s4[MAXRFL], s5[MAXRFL];
	register int i;	
	
	/*
	 * break down line into variable name, filename,
	 * function name, and line number
	 */
	sscanf(line, "%s%s%s%s%s", s1, s2, s3, s4, s5);
	if (strcmp(s2, "$") == 0) {
		/* function name */
		if (strcmp(sv1, s1) != 0) {
			strcpy(sv1, s1);
			printf("\n%s()", s1);	/* append '()' to name */
			*sv2 = *sv3 = *sv4 = '\0';
			fprnt = NO;
		};
		return;
	};
	if (strcmp(s5, "*") == 0) {
		/* variable defined at this line number */
		*s5 = '\0';
		sptr1 = s4;
		och = '*';
		/* prepend a star '*' */
		for ( nch = *sptr1; *sptr1 = och; nch = *++sptr1)
			och = nch;
	}
	if (fprnt == YES) {
		/* if first line--copy the line to a save area */
		prntwrd( strcpy(sv1, s1) );
		prntflnm( strcpy(sv2, s2) );
		if (!lflg)
			prntfnc( strcpy(sv3, s3) );
		linecol++;	
		if (!Lflg || (linecol <= col) )
			prntlino( strcpy(sv4, s4) );
		
		fprnt = NO;
		return;
	}
	else {
		/*
		 * this part checks to see what variables have changed
		 */
		if (strcmp(sv1, s1) != 0) {
			nword = nflnm = nfnc = nlino = YES;
		}
		else {
			nword = NO;
			if (strcmp(sv2, s2) != 0) {
				nflnm = nfnc = nlino = YES;
				linecol = 0;
			}
			else {
				nflnm = NO;
				if (strcmp(sv3, s3) != 0) {
					nfnc = nlino = YES;
					linecol = 0;
				}
				else {
					nfnc = NO;
					nlino = (strcmp(sv4, s4) != 0) ? YES : NO;
					if (nlino == YES) {
						/*
						 * everything is the same
						 * except line number
						 * add new line number
						 */
						linecol++;
						if (!Lflg || (linecol <= col) )
						{
							addlino = YES;
							prntlino( strcpy(sv4, s4) );
						}
					};
					/*
					 * Want to return if we get to
					 * this point. Case 1: nlino
					 * is NO, then entire line is
					 * same as previous one.
					 * Case 2: only line number is
					 * different, add new line number
					 */
					return;
				};
			};
		};
	};

	/*
	 * either the word, filename or function name
	 * are different; this part of the routine handles  
	 * what has changed...
	 */

	addlino = NO;
	lsize = 0;
	if (nword == YES) {
		/* word different--print line */
		prntwrd( strcpy(sv1, s1) );
		prntflnm( strcpy(sv2, s2) );
		if (!lflg)
		prntfnc( strcpy(sv3, s3) );
		linecol++;
		if (!Lflg || (linecol <= col))
			prntlino( strcpy(sv4, s4) );
		return;
	}
	else {
		if (Wflg) {
			fputs("\n", stdout);
			for (i = 0; i< (w_name+1); i++)
		        	fputs(" ", stdout);
		} else
			fputs("\n\t\t", stdout);
		if (nflnm == YES) {
			/*
			 * different filename---new name,
			 * function name and line number are
			 * printed and saved
			 */
			prntflnm( strcpy(sv2, s2) );
			if (!lflg)
				prntfnc( strcpy(sv3, s3) );
			prntlino( strcpy(sv4, s4) );
			return;
		}
		else {
			/* prints filename as formatted by prntflnm()*/
			if (Wflg) 
				printf("%-*s ",w_file, s2);
			else
			{
				
				switch (fsp) {
				case 1:
					printf("%s\t\t\t", s2);
					break;
				case 2:
					printf("%s\t\t", s2);
					break;
				case 3:
					printf("%s\t", s2);
					break;
				case 4:
					printf("%s  ", s2);
				};
			};
			if (nfnc == YES) {
				/*
				 * different function name---new name
				 * is printed with line number;
				 * name and line are saved
				 */
				if (!lflg)
					prntfnc( strcpy(sv3, s3) );
				prntlino( strcpy(sv4, s4) );
			};
		};
	};
}

prntwrd(w)
	char *w;
{

	/* formats word(variable)*/
	register int wsize;	/*16 char max. word length */
	if (Wflg) {
		if (w)
			printf("\n%-*s", w_name+1, w);
		else 
			printf("\n%-*s", w_name+1, " ");
		return;
	}
	
	if ((wsize = strlen(w)) < 8) {
		printf("\n%s\t\t", w);
	}
	else
		if ((wsize >= 8) && (wsize < 16)) {
			printf("\n%s\t", w);
		}
		else {
			printf("\n%s  ", w);
		};
}

prntflnm(fn)
	char *fn;
{

	/* formats filename */
	register int fsize;	/*24 char max. fliename length */

	if (Wflg) {
		printf("%-*s", w_file+1, fn);
		return;
	};
	/* for MNLS */
	fsize = strlen(fn);
	fsize -= setcount(fn);
	if (fsize < 8) {
		printf("%s\t\t\t", fn);
		fsp = 1;
	}
	else {
		if ((fsize >= 8) && (fsize < 16)) {
			printf("%s\t\t", fn);
			fsp = 2;
		}
		else
			if ((fsize >= 16) && (fsize < 24)) {
				printf("%s\t", fn);
				fsp = 3;
			}
			else {
				printf("%s  ", fn);
				fsp = 4;
			};
	};
}

prntfnc(fnc)
	char *fnc;
{

	if (Wflg) {
		printf("%-*s", w_func+1, fnc);
		return;
	};
	/* formats function name */
	if (strlen(fnc) < 8) {
		printf("%s\t  ", fnc);
	}
	else {
		printf("%s  ", fnc);
	};
}

char *
myalloc(num, size)
	unsigned num, size;
{
	register char *ptr;

	if ((ptr = calloc(num, size)) == NULL) {
		perror("cxref");
		dexit(1);
	};
	return(ptr);
}

prntlino(ns)
	register char *ns;
{

	/* formats line numbers */

	register int lino, i;
	char star;

	i = lino = 0;

	if (*ns == '*') {
		star = '*';
		ns++;	/* get past star */
	}
	else {
		star = ' ';
	};
	lino = getnumb(ns);
	if (lino < 10)	/* keeps track of line width */
		lsize += (i = 3);
	else if ((lino >=10) && (lino < 100))
			lsize += (i = 4);
	else if ((lino >= 100) && (lino < 1000))
				lsize += (i = 5);
	else if ((lino >= 1000) && (lino < 10000))
					lsize += (i = 6);
	else /* lino > 10000 */
						lsize += (i = 7);
	if (addlino == YES) {
		if (Wflg) {
			printf(" %c", star);
			(void) printf("%-*d ", w_line,  lino);
		}
		else {
			if (lsize <= LSIZE) {
			/* line length not exceeded--print line number */
				fprintf(stdout, " %c%d", star, lino);
			}
			else {
				/* line to long---format lines overflow */
				fprintf(stdout, "\n\t\t\t\t\t\t   %c%d", star, lino);
				lsize = i;
			};
		};
		addlino = NO;
	}
	else {
		if (Wflg) {
			printf(" %c", star);
			(void) printf("%-*d ", w_line,  lino);
		}
		else {
			fprintf(stdout, " %c%d", star, lino);
		};

	};
}
/* MNLS: */
/*
 * This function counts the number of shift codes and the difference
 * between EUC width and display width.
 * And returns with that value.
 */
setcount(s)                                                             
register char *s;                                                     
{                                                                    
        register int cnt=0;                                         
	
	while (*s) {
		if (NOTASCII(*s)) {
			cnt += ISSET2(*s) ? difset2 + 1  :
				ISSET3(*s) ? difset3 + 1 : difset1;
			if (ISSET2(*s)) 
				s += wp._eucw2 + 1;
			else if (ISSET3(*s))
				s += wp._eucw3 + 1;
			else
				s += wp._eucw1;
		} else
			s++;
	
	}
	return(cnt);
}
	

