/*
 *	Polytechnic UNIX accounting Package - Program: build.c
 *
 *	Author:	John Buck
 *	Polytechnic Institute NY, September 1981
 *
 *	Program Description:
 *	build - make a file for the ibm side of accounting to read
 *
 *	Usage: build [file] > outfile
 *
 *	file defaults to /accting/today, which is created by /accting/mktoday
 *	Modified by John Buck: 5/9/84 -- New IBM accting card format
 */

/*
 *	Author: John Buck, PINY Sep, 1981
 */



#

#define	SUB(x)	((unsigned)((x) >> 3))
#define	BIT(x)	(1 << ((x) & 07))


#include	"hsubs.h"
#include	"actrecs.h"

struct	acctrec	acctrec;
int af;

char	done[8192];

struct	{
	int uuid;
	int ggid;
} user[4049];

char	bufr[10240];


char	ibuf[504];

long	connect, scpu, ucpu, disk;
long	tc();
double	dolcost;
long	idolcost;

main(c,v)
char **v;
{
	int fi , u , g , oldg;

	char err;
	register r , i;
	register struct	ibment *ip;
	int rr;
	if(c == 1) *v = TFILE;
	else	v++;

	if((fi = open(IBMFILE,0)) == -1)exit(10);
	if((af = open(*v,0)) == -1)exit(11);
	prheadr();
	i = -1;
	oldg = -1;
	while((rr = read(fi,ibuf,504))%IREAD == 0 && rr)
		for(ip = ibuf; ip < &ibuf[rr]; ip++){
			u = num(ip->uid);
			g = num(ip->gid);

			if(g >= MAXACGIDS)continue;
			if(ip->send == 'X')continue;
			user[++i].uuid = u;
			user[i].ggid = g;
			if(user[i].ggid == -1){
				if(user[i].uuid == -1)continue;
				for(r = 0; r < MAXACGIDS; r++)done[r] = 0;
				for(r = 0; r < i; r++)
					if((user[r].uuid == -1 ||
					    user[r].uuid == user[i].uuid) &&
					   user[r].ggid != -1)
						done[SUB(user[r].ggid)] |=
							BIT(user[r].ggid);
				connect = scpu = ucpu = disk = 0L;
#ifdef DEBUG
				for(r = 0; r < 32767; r++)
					if(done[SUB(r)] & BIT(r))
						printf("U:%-5d ", r);
				printf("\n");
#endif
				fixuids(u);
			}
			else	if(user[i].uuid == -1){
					if(user[i].ggid == -1)continue;
					for(r = 0; r < 8192; r++)done[r] = 0;
					for(r = 0; r < i; r++)
						if((user[r].ggid == -1 ||
						    user[r].ggid == user[i].ggid) &&
						   user[r].uuid != -1)
						done[SUB(user[r].uuid)] |=
							BIT(user[r].uuid);
					connect = scpu = ucpu = disk = 0L;
					fixgrps(g);
				}
				else	{
					getarec(user[i].ggid,user[i].uuid);
					connect = acctrec.a_connect;
					scpu = acctrec.a_syscpu;
					ucpu = acctrec.a_usrcpu;
					disk = acctrec.a_diskblks;
				}
			if(connect < 0L){
				connect = 2147483647L;
			}
			if(ucpu < 0L){
				scpu += ucpu + 2147483647L;
				ucpu = 2147483647L;
			}
			if(scpu < 0L)
				scpu = 2147483647L;
			dolcost = ((double)(connect)/3600.0)*CONRATE;
			dolcost += (((double)(ucpu) + (double)(scpu))/(216000.0))*
				TICRATE;
			dolcost += ((double)(disk)/1000.0)*DISKRATE;
			idolcost = (long)(dolcost*100.0);
			printf("%8.8s %8.8s %10D %10D %10D %10D %10D\n",
				ip->name, ip->acct, connect, ucpu,
				scpu, disk, idolcost);
		}

	close(fi);
	close(af);
	exit(0);
}



getarec(g,u)
register g,u;
{
	lseek(af, (long)(akey(u))*AREAD, 0);
lp:
	if(read(af, &acctrec, AREAD) != AREAD) return;
	if((acctrec.a_uid == u && acctrec.a_gid == g) ||
	   (acctrec.a_uid == 0 && acctrec.a_gid == 0))return;
	goto lp;
}

num(s)
register char *s;
{
	register i;
	i = 0;
	if(*s < '0' || *s > '9')return(-1);
	while(*s >= '0' && *s <= '9')i = i * 10 + *s++ - '0';
	return(i);
}



prheadr(){
	register char *s;
	register int *l, i;
	int *localtime();
	int tv[2];
	char *hd = "00.000";

	s = hd + 1;
	time(tv);
	l = localtime(tv);
	l[7]++;
	if(l[7] == 1){
		l[7] = 365;
		l[5]--;
		if(l[5]%4 == 0)l[7] = 366;
				/* This routine will not work on years > 2099 */
	}
	else	l[7]--;
	i = l[5];
	while(i){
		*s-- = i%10 + '0';
		i =/ 10;
	}
	s = hd+5;
	i = l[7];
	while(i){
		*s-- = i%10 + '0';
		i =/ 10;
	}
	printf("%s\n",hd);
}



fixgrps(g)
register short g;
{
	register struct acctrec *pa, *pl;
	int r;

	lseek(af, 0L, 0);
	while((r = read(af, bufr, 10240)) > 0){
		pl = &bufr[r];
		for(pa = bufr; pa < pl; pa++)
			if(pa->a_gid == g && (done[SUB(pa->a_uid)] &
				BIT(pa->a_uid)) == 0){
					connect += pa->a_connect;
					scpu += pa->a_syscpu;
					ucpu += pa->a_usrcpu;
					disk += pa->a_diskblks;
			}
	}
}

fixuids(u)
register short u;
{
	register struct acctrec *pa, *pl;
	int r;
	char err;

	err = 0;
	lseek(af, (long)(akey(u))*AREAD, 0);
	while((r = read(af, bufr, 100)) > 0){
		pl = &bufr[r];
		for(pa = bufr; pa < pl; pa++){
#ifdef DEBUG1
			printf("U=%d ", pa->a_uid);
#endif
			if(pa->a_uid == u && (done[SUB(pa->a_gid)] &
				BIT(pa->a_gid)) == 0){
					connect += pa->a_connect;
					scpu += pa->a_syscpu;
					ucpu += pa->a_usrcpu;
					disk += pa->a_diskblks;
			}
			if(pa->a_uid == 0 && pa->a_gid == 0)
				return;
		}
	}
}

