#define size 1000	/***/
/* interpret command time accounting */

int	lflg;
int	cflg;
int	jflg;
int	nflg;
int	aflg;
int	rflg;
int	tflg;
int	vflg;
int	uflg;
int	thres	1;
int	sflg;
int	bflg;
int	mflg;
extern int	fout;

struct	user {
	int	ncomm;
/***	int	fill;	***/
	float	fctime;
} user[256];
struct tab {
	char name[8];
	int count;
	float realt;
	float cput;
	float syst;
} *tab;
struct tab *enter();

struct ftab {
	char	fname[14];
	char	shf;
	char	uid;
	int	fdatet[2];
	int	frealt[2];
	int	fcput[2];
	int	fsyst[2];
};
float	treal;
float	tcpu;
float	tsys;
struct tab  *junkp 0;
char	*sname;
float	ncom;

main(argc, argv)
char **argv;
{
	register i, j, k;
	register struct tab *ip, *kp;
	extern tcmp(), ncmp(), bcmp();
	extern float sum();
	float ft;

	init();
	if (argc>1)
	if (argv[1][0]=='-') {
		argv++;
		argc--;
		for(i=1; argv[0][i]; i++)
		switch(argv[0][i]) {

		case 'b':
			bflg++;
			break;

		case 'l':
			lflg++;
			break;

		case 'c':
			cflg++;
			break;

		case 'j':
			jflg++;
			break;

		case 'n':
			nflg++;
			break;

		case 'a':
			aflg++;
			break;

		case 'r':
			rflg++;
			break;

		case 't':
			tflg++;
			break;

		case 's':
			sflg++;
			aflg++;
			break;

		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
			thres = argv[0][i]-'0';
			break;

		case 'v':
			vflg++;
			break;

		case 'u':
			uflg++;
			break;

		case 'm':
			mflg++;
			break;
		}
	}
	fout = dup(1);
	if (argc<2)
		acct("/usr/adm/sha");
	else while (--argc)
		acct(*++argv);
	if (uflg) {
		flush();
		return;
	}

/*
 * cleanup pass
 * put junk togr
 */

	if (vflg)
		strip();
	if(!aflg)
	for (ip = tab; ip < &tab[size]; ip++)
	if (ip->name[0]) {
		for(j=0; j<8; j++)
			if(ip->name[j] == '?')
				goto yes;
		if(ip->count != 1)
			continue;
	yes:
		if(junkp == 0)
			junkp = enter("***other");
		junkp->count =+ ip->count;
		junkp->realt =+ ip->realt;
		junkp->cput =+ ip->cput;
		junkp->syst =+ ip->syst;
		ip->name[0] = 0;
	}
	for (ip = kp = tab; ip < &tab[size]; ip++)
	if(ip->name[0]) {
		for(j=0; j<8; j++)
			kp->name[j] = ip->name[j];
		tcopy(ip, kp);
		kp++;
	}
	k = kp-tab;
	if (sflg) {
		signal(2, 1);
		i = creat("/usr/adm/shm", 0666);
		write(i, user, sizeof(user));
		close(i);
		if ((i = creat("/usr/adm/sht", 0666))<0) {
			printf("Can't save\n");
			exit();
		}
		write(i, tab, k*sizeof(*tab));
		close(i);
		if (sname) {
			if ((i = creat(sname, 0666))<0)
				printf("Can't truncate\n");
			close(i);
		}
		signal(2, 0);
	}
/*
 * sort and print
 */

	if (mflg) {
		printmoney();
		flush();
		exit();
	}
	qsort(tab, k, sizeof *tab, nflg? &ncmp: (bflg?&bcmp:&tcmp));
	printf("%8s", "");
	column(ncom, treal, tcpu, tsys);
	for (ip=tab; ip<kp; ip++)
	if (ip->name[0]) {
		ft = ip->count;
		printf("%-8.8s", ip->name);
		column(ft, ip->realt, ip->cput, ip->syst);
	}
	flush();
}

printmoney()
{
	register i;
	char buf[128];
	register char *cp;

	for (i=0; i<256; i++) {
		if (user[i].ncomm) {
			if (getpw(i, buf)!=0)
				printf("%-8d", i);
			else {
				cp = buf;
				while (*cp!=':' &&*cp!='\n' && *cp)
					cp++;
				*cp = 0;
				printf("%-8s", buf);
			}
			printf("%5l %7.2f\n",
				user[i].ncomm, user[i].fctime/60);
		}
	}
}

column(n, a, b, c)
double n, a, b, c;
{
	register i;

	printf("%6d", i = n);
	if(cflg) {
		if(n == ncom)
			printf("%7s", ""); else
			printf("%6.2f%%", 100.*n/ncom);
	}
	col(n, a, treal);
	if(lflg) {
		col(n, b, tcpu);
		col(n, c, tsys);
	} else
		col(n, b+c, tcpu+tsys);
	if(tflg)
		printf("%6.1f", a/(b+c));
	putchar('\n');
}

col(n, a, m)
double n, a, m;
{

	if(jflg)
		printf("%9.2f", a/(n*60.)); else
		printf("%9.2f", a/3600.);
	if(cflg) {
		if(a == m)
			printf("%7s", ""); else
			printf("%6.2f%%", 100.*a/m);
	}
}

acct(f)
char *f;
{
	register ff;
	register struct tab *ip;
	float x;
	struct ftab fbuf;
	register char *cp;
	register int c;
	extern double ltod();

	if (sflg && sname) {
		printf("Only 1 file with -s\n");
		exit();
	}
	if (sflg)
		sname = f;
	if ((ff=open(f, 0))<0) {
		printf("Can't open %s\n", f);
		return;
	}
	while (read(ff, &fbuf, sizeof(fbuf))==sizeof(fbuf)) {
		for (cp = fbuf.name; cp < &fbuf.name[8]; cp++) {
			c = *cp & 0377;
			if (c && (c < ' ' || c >= 0200))
				*cp = '?';
		}
		if (uflg) {
			printdate(fbuf.fdatet);
			printf(" %3d %.8s\n", fbuf.uid, fbuf.name);
			continue;
		}
		if (fbuf.shf==0) {
			c = fbuf.uid&0377;
			user[c].ncomm++;
			user[c].fctime =+ (ltod(fbuf.fcput)+ltod(fbuf.fsyst))/60;
		}
		ncom =+ 1.0;
		ip = enter(&fbuf);
		ip->count++;
		x = ltod(fbuf.frealt);
		x =* 60.;
		ip->realt =+ x;
		treal =+ x;
		x = ltod(fbuf.fcput);
		ip->cput =+ x;
		tcpu =+ x;
		x = ltod(fbuf.fsyst);
		ip->syst =+ x;
		tsys =+ x;
	}
	close(ff);
}

ncmp(p1, p2)
struct tab *p1, *p2;
{

	if(p1->count == p2->count)
		return(tcmp(p1, p2));
	if(rflg)
		return(p1->count - p2->count);
	return(p2->count - p1->count);
}

bcmp(p1, p2)
struct tab *p1, *p2;
{
	float f1, f2;
	extern float sum();

	f1 = sum(p1)/p1->count;
	f2 = sum(p2)/p2->count;
	if(f1 < f2) {
		if(rflg)
			return(-1);
		return(1);
	}
	if(f1 > f2) {
		if(rflg)
			return(1);
		return(-1);
	}
	return(0);
}
tcmp(p1, p2)
struct tab *p1, *p2;
{
	extern float sum();
	float f1, f2;

	f1 = sum(p1);
	f2 = sum(p2);
	if(f1 < f2) {
		if(rflg)
			return(-1);
		return(1);
	}
	if(f1 > f2) {
		if(rflg)
			return(1);
		return(-1);
	}
	return(0);
}

float sum(p)
struct tab *p;
{

	if(p->name[0] == 0)
		return(0.0);
	return(
		p->cput+
		p->syst);
}

init()
{
	struct tab tbuf;
	register i, j, f;
	register struct tab *ip;

	/*** tab must be obtained dynamically to avoid Interdata 	***/
	/*** assembler bug!						***/
	tab = sbrk(size * sizeof *tab);
	if ((f=open("/usr/adm/sht", 0))<0)
		goto gshm;
	while (read(f, &tbuf, sizeof(tbuf)) == sizeof(tbuf)) {
		ip = enter(&tbuf);
		tcopy(&tbuf, ip);
		ncom =+ tbuf.count;
		treal =+ tbuf.realt;
		tcpu =+ tbuf.cput;
		tsys =+ tbuf.syst;
	}
	close(f);
 gshm:
	if ((f=open("/usr/adm/shm", 0)) < 0)
		return;
	read(f, user, sizeof(user));
	close(f);
}

struct ftab *enter(fbuf)
struct ftab *fbuf;
{
	register i, j;
	struct ftab *ip;

	i = 0;
	for (j=0; j<8; j++) {
		i = i*7 + fbuf->fname[j];
	}
	if(i < 0)
		i = -i;
	for (i=%size; (ip = &tab[i])->name[0]; i = (i+1)%size) {
		for (j=0; j<8; j++)
			if (ip->name[j]!=fbuf->fname[j])
				goto no;
		goto yes;
	no:;
	}
	for (j=0; j<8; j++)
		ip->name[j] = fbuf->fname[j];
yes:
	return(ip);
}

tcopy(from, to)
int *from, *to;
{
	register i;

	for (i=2; i<6; i++)
		to[i] = from[i];
}

strip()
{
	register k, c;
	register struct tab *ip, *jp;

	jp = enter("**junk**");
	for (ip = tab; ip < &tab[size]; ip++) {
		if (ip->name[0] && ip->count<=thres) {
			printf("%.8s--", ip->name);
			flush();
			if ((c=getchar())=='y') {
				ip->name[0] = '\0';
				jp->count =+ ip->count;
				jp->realt =+ ip->realt;
				jp->cput =+ ip->cput;
				jp->syst =+ ip->syst;
			}
			while (c && c!='\n')
				c = getchar();
		}
	}
}

printdate(tvec)
int tvec[2];
{
	register int *lt;
	int *localtime();

	lt = localtime(tvec);
	printf("%3d ", lt[7]);
	pair(lt[2]); pair(lt[1]); pair(lt[0]); 
	printf(" %d", lt[6]);
}

pair(n)
{
	printf("%c%c", n/10+'0', n%10+'0');
}

/*** temporary ltod() -- long integer->float conversion ***/
double ltod(d)
int d[2];
{
	float x;

	return(x = d[1]);
}
/*** temporary getpw() - get password file entry ***/
getpw()
{
	return(-1);
}
