/*
 * $Copyright:	$
 * Copyright (c) 1984, 1985, 1986, 1987, 1988, 1989, 1990 
 * Sequent Computer Systems, Inc.   All rights reserved.
 *  
 * This software is furnished under a license and may be used
 * only in accordance with the terms of that license and with the
 * inclusion of the above copyright notice.   This software may not
 * be provided or otherwise made available to, or used by, any
 * other person.  No title to or ownership of the software is
 * hereby transferred.
 *
 */

/*	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.	*/

#ident	"$Header: sagb.c 1.3 89/10/10 $"

/*
 * sagb.c
 *	source for sag (system activity graph)
 */

/* $Log:	sagb.c,v $
 */

#include "saghdr.h"

combine(p, pn)
struct	p	*p;
int	pn;

{
int	a, b, c;
int	i;
int	qi = 0;
float	vala, valb;
struct	array	*ara, *arb, *arc;
struct	array	*popar();
char	*strcpy();

ara = p->c[pn].dptr;
arb = p->c[pn+1].dptr;
arc = popar();
if(DEBUG){fprintf(stderr, "combine p->c[%d].name:%s  &  p->c[%d].name:%s\n",
		pn, p->c[pn].name, pn+1, p->c[pn+1].name);
	fprintf(stderr, "  alias ara->hname:%s    arb->hname:%s\n",
		ara->hname, arb->hname);
	}

for(a=b=c=0; a<NPTS && b<NPTS && c<NPTS;   )
	{
	if((ara->ent[a].hr == 0) || (arb->ent[b].hr == 0))
		{		/*   End of file   */
		arc->ent[c].hr = 0;
		break;
		}

	if((ara->ent[0].hr < 0) || (arb->ent[0].hr < 0))
		{		/*   One or both is a constant   */
		if((ara->ent[a].val <= -1000) || (arb->ent[b].val <= -1000))
			arc->ent[c].val = -1000;
		else
			switch (p->c[pn].op)
			{
			case '+':
				arc->ent[c].val = ara->ent[a].val + arb->ent[b].val;
				break;
			case '-':
				arc->ent[c].val = ara->ent[a].val - arb->ent[b].val;
				break;
			case '*':
				arc->ent[c].val = ara->ent[a].val * arb->ent[b].val;
				break;
			case '/':
				if(arb->ent[b].val != 0)
					arc->ent[c].val = ara->ent[a].val / arb->ent[b].val;
				else
					arc->ent[c].val = 0;
				break;
			default:
				break;
			}
		if(ara->ent[0].hr >= 0)
			{		/*   a is variable   */
			strcpy(arc->ent[c].tm, ara->ent[a].tm);
			strcpy(arc->ent[c].qfld, ara->ent[a].qfld);
			arc->ent[c].hr = ara->ent[a].hr;
			a++;
			}
		else if(arb->ent[0].hr >= 0)
			{		/*   b is variable   */
			strcpy(arc->ent[c].tm, arb->ent[b].tm);
			strcpy(arc->ent[c].qfld, arb->ent[b].qfld);
			arc->ent[c].hr = arb->ent[b].hr;
			b++;
			}
		else
			{		/*   Both are constant   */
			strcpy(arc->ent[c].tm, ara->ent[a].tm);
			strcpy(arc->ent[c].qfld, ara->ent[a].qfld);
			arc->ent[c].hr = ara->ent[a].hr;
			a++;
			b++;
			}
		c++;
		continue;
		}

	if(ara->ent[a].hr < arb->ent[b].hr)
		{		/*   b missing   */
		arc->ent[c].hr = ara->ent[a].hr;
		strcpy(arc->ent[c].tm, ara->ent[a].tm);
		strcpy(arc->ent[c].qfld, ara->ent[a].qfld);
		vala = ara->ent[a].val;
		valb = 0.;
		a++;
		}
	else if(ara->ent[a].hr > arb->ent[b].hr)
		{		/*   a missing   */
		arc->ent[c].hr = arb->ent[b].hr;
		strcpy(arc->ent[c].tm, arb->ent[b].tm);
		strcpy(arc->ent[c].qfld, arb->ent[b].qfld);
		valb = arb->ent[b].val;
		vala = 0.;
		b++;
		}
	else
		{		/*   a & b hrs equal   */
		arc->ent[c].hr = ara->ent[a].hr;
		strcpy(arc->ent[c].tm, ara->ent[a].tm);
		vala = ara->ent[a].val;
		valb = arb->ent[b].val;
/*
**	Test which index can be incremented without
**	incurring a change in ..hr
*/
		if((ara->ent[a+1].hr == ara->ent[a].hr)
		 && (arb->ent[b+1].hr != arb->ent[b].hr))
			{		/*  a free, b constrained  */
			strcpy(arc->ent[c].qfld, ara->ent[a].qfld);
			qi = 0;
			a++;
			}
		else if((ara->ent[a+1].hr != ara->ent[a].hr)
		  && (arb->ent[b+1].hr == arb->ent[b].hr))
			{		/*   a constrained, b free  */
			strcpy(arc->ent[c].qfld, arb->ent[b].qfld);
			qi = 1;
			b++;
			}
		else
			{		/*   Both free or both constrained   */
			if(qi == 1)
				strcpy(arc->ent[c].qfld, arb->ent[b].qfld);
			else
				strcpy(arc->ent[c].qfld, ara->ent[a].qfld);
			a++;
			b++;
			}
		}
	if((vala <= -1000) || (valb <= -1000))
		arc->ent[c].val = -1000;
	else
		switch (p->c[pn].op)
		{
		case '+':
			arc->ent[c].val = vala + valb;
			break;
		case '-':
			arc->ent[c].val = vala - valb;
			break;
		case '*':
			arc->ent[c].val = vala * valb;
			break;
		case '/':
			if(valb != 0)
				arc->ent[c].val = vala / valb;
			else
				arc->ent[c].val = 0;
			break;
		default:
			break;
		}
	c++;
	}

sprintf(arc->hname, "%s %c %s", ara->hname, p->c[pn].op, arb->hname);
if(DEBUG){printar(ara);
	printar(arb);
	printar(arc);
	}
pushar(ara);
pushar(arb);
p->c[pn].op = p->c[pn+1].op;
p->c[pn].dptr = arc;
for(i=pn+1; i<4; i++)
	{
	strcpy(p->c[i].name, p->c[i+1].name);
	p->c[i].op = p->c[i+1].op;
	p->c[i].dptr = p->c[i+1].dptr;
	}
}


/************************************************/


getdata(name, array)
char	*name;
struct	array	*array;
/*
**	Extracts data from sarc[] array and puts into 
**	array entries.  Hunts for name string among column
**	headers in sarc, and copies following data items
**	from corresponding field up to next "Average" line.
**	Special treatment when name string contains an integer
**	or "time".
*/

{
extern	char	fld[NFLD][FLDCH];
extern	FILE	*sard;
extern	long	sardoff;
int	fnum;
char	nm[18], ql[8];
int	nparts;
int	i, j;
int	timeflg;
int	hr, min, sec;
int	nmloc;
double	atof();
float	hour;
char	*strcpy();
char	*strtok();
char	*tok;

if(DEBUG)	fprintf(stderr, "getdata-> name:%s\n", name);
if(sscanf(name,"%f", &array->ent[0].val) == 1)	/*  name contains a constant  */
	{					/*  no sar data is required  */
	strcpy(array->ent[0].tm, "***");
	strcpy(array->hname, name);
	array->ent[0].hr = -1;
	array->ent[0].qfld[0] = '\0';
	array->ent[1].hr = 0;
	return(0);
	}

if(strmatch("time", name) >= 0)		/*  Pick up time values from  */
	{				/*  1st sar group - %usr  */
	if(DEBUG) fprintf(stderr, "name matches time\n");
	strcpy(nm, "%usr");
	strcpy(ql, "");
	nparts = 1;
	timeflg = 1;
	}
else
	{
	nparts = 0;
	timeflg = 0;
	if((tok = strtok(name, "[]")) != NULL)
		{
		nparts = 1;
		strcpy(nm, tok);
		}
	if((tok = strtok(0, "[]")) != NULL)
		{
		nparts++;
		strcpy(ql, tok);
		}
	else
		strcpy(ql, "");
	}
/*	fprintf(stderr, "nparts:%d  nm:%s  ql:%s\n",  nparts, nm, ql);
*/

fseek(sard, sardoff, 0);		/*  seek to line 2 of sard  */
while((fnum = getfld()) != EOF)
	{
	for(i=0; i<fnum; i++)
		if(strmatch(nm, fld[i]) >= 0)
			{
			if(timeflg == 1)
				{
				nmloc = 0;
				strcpy(array->hname, "time");
				}
			else
				{
				nmloc = i ;
				if(nparts < 2)
					strcpy(array->hname, fld[i]);
				else
					sprintf(array->hname, "%s[%s]",
						fld[i], ql);
				}
			goto readin;
			}
	}
fprintf(stderr, "\"%s\" data not found\n", nm);
return(-1);

readin:
	for(i=0; i<NPTS;   )
		{
		if(((fnum = getfld()) == EOF)
		  || (strmatch(":", fld[0]) < 0))
			{
			array->ent[i].hr = 0;
			return(0);
			}
		if(DEBUG>1) {
			for (j=0; j<fnum; j++)
				fprintf(stderr, "  %s", fld[j]);
			fputc('\n', stderr);
			}
		sscanf(fld[0], "%d:%d:%d", &hr, &min, &sec);
		hour = (float)hr + (float)min/60 + (float)sec/3600;
		if(timeflg == 1)
			{
			strcpy(array->ent[i].tm, fld[0]);
			array->ent[i].hr = hour;
			array->ent[i].val = hour;
			strcpy(array->ent[i].qfld, "");
			i++;
			continue;
			}
		if(strmatch("unix", fld[1]) >= 0)
			{
			strcpy(array->ent[i].tm, fld[0]);
			array->ent[i].hr = hour;
			array->ent[i].val = -1000.;
			strcpy(array->ent[i].qfld, "");
			i++;
			continue;
			}
		if((nparts > 1) && (strmatch(ql, fld[1]) < 0))
			continue;

		strcpy(array->ent[i].tm, fld[0]);
		array->ent[i].hr = hour;
		array->ent[i].val = atof(fld[nmloc]);
		strcpy(array->ent[i].qfld, fld[1]);

		if(DEBUG>1)
			fprintf(stderr, "    .val:%.3f\n", array->ent[i].val);
		i++;
		}
return(0);
}


/************************************************/


getfld()
/*
**	Scans characters pointed to by cp;
**	puts non-blank strings into fld[NFLD][FLDCH]
**	up to first newline or EOF.
**	Returns number of fld's filled (or EOF),
**	with cp updated to next readable char.
*/
{
extern	char	fld[NFLD][FLDCH];
extern	FILE	*sard;
int	fnum=0, i=0;
int	c;

while((c = getc(sard)) != EOF)
	switch((char)c){
	case ' ':
		fld[fnum][i] = '\0';
		i = 0;
		if(++fnum >= 9)		return(fnum);
		break;
	case '\n':
		fld[fnum][i] = '\0';
		return(++fnum);
		break;
	default:
		fld[fnum][i++] = c;
		break;
	}

fld[fnum][i] = '\0';
if((i == 0) && (fnum == 0))		return(EOF);
else		return(++fnum);
}


/************************************************/


static	struct	array	stack[10];
static	struct	array	*sp[] = {
	&stack[0],
	&stack[1],
	&stack[2],
	&stack[3],
	&stack[4],
	&stack[5],
	&stack[6],
	&stack[7],
	&stack[8],
	&stack[9]};
static	int	spn = 10;



struct	array	*popar()
{
if(spn > 0)
	return(sp[--spn]);
else
	{
	fprintf(stderr, "Stack empty\n");
	exit();
	}
}


pushar(par)
struct	array	*par;

{
if(spn < 10)
	{
	sp[spn++] = par;
	return(1);
	}
else
	{
	fprintf(stderr, "Stack full\n");
	return(0);
	}
}


/************************************************/


stribl(s)
char	*s;
/*
**	Strips leading and trailing blanks from string
**	by moving string pointer to first non-blank character,
**	and replacing trailing blanks with '\0'.
**	Returns number of remaining characters.
*/

{
char	*a, *b;

a = b = s;
while (*b == ' ') 	b++;
while ((*a++ = *b++) != '\0');
a--;
while (a-- > s)
	if (*a != ' ')	break;
	else	*a = '\0';
return (int)(a-s+1);
}


/************************************************/


int strmatch (pat, targ)
char *pat, *targ;

/*
**	strmatch looks for an occurrence of string pat
**	inside string targ.  It returns the number of
**	the first starting character position (zero is valid),
**	or -1 for no match.
*/

{
int i, c, ifirst;

for (ifirst=0;   ; ifirst++)
	{
	i=0;
	do
		{
		if(pat[i] == '\0')
			return(ifirst);
		if (targ[ifirst + i] == '\0')
			return(-1);
		c=i++;
		}
	while (pat[c] == targ[ifirst + c]);
	}
}


/************************************************/


float	yrange(ff)
float	ff;
{
static float	ylimit[] = {1.0, 1.5, 2.5, 5.0, 10.0};
float	div = 1;
int	i = 0;
if (ff <= 0.)	return(0);
while (ff/div > 10.)	div *= 10.;
while (ff/div < 1.)	div /= 10.;
while ((ff/div) > ylimit[i])	i++;
return (ylimit[i] * div);
}
