xref: /csrg-svn/usr.sbin/lpr/pac/pac.c (revision 22435)
1*22435Sdist /*
2*22435Sdist  * Copyright (c) 1983 Regents of the University of California.
3*22435Sdist  * All rights reserved.  The Berkeley software License Agreement
4*22435Sdist  * specifies the terms and conditions for redistribution.
5*22435Sdist  */
6*22435Sdist 
713954Ssam #ifndef lint
8*22435Sdist char copyright[] =
9*22435Sdist "@(#) Copyright (c) 1983 Regents of the University of California.\n\
10*22435Sdist  All rights reserved.\n";
11*22435Sdist #endif not lint
1213954Ssam 
13*22435Sdist #ifndef lint
14*22435Sdist static char sccsid[] = "@(#)pac.c	5.1 (Berkeley) 06/06/85";
15*22435Sdist #endif not lint
16*22435Sdist 
1711451Sralph /*
1811451Sralph  * Do Printer accounting summary.
1911451Sralph  * Currently, usage is
2011451Sralph  *	pac [-Pprinter] [-pprice] [-s] [-r] [-c] [user ...]
2111451Sralph  * to print the usage information for the named people.
2211451Sralph  */
2311451Sralph 
2411451Sralph #include <stdio.h>
2511451Sralph #include "lp.local.h"
2611451Sralph 
2711451Sralph char	*printer;			/* printer name */
2811451Sralph char	*acctfile;			/* accounting file (input data) */
2911451Sralph char	*sumfile;			/* summary file */
3011451Sralph float	price = 0.02;			/* cost per page (or what ever) */
3111451Sralph int	allflag = 1;			/* Get stats on everybody */
3211451Sralph int	sort;				/* Sort by cost */
3311451Sralph int	summarize;			/* Compress accounting file */
3411451Sralph int	reverse;			/* Reverse sort order */
3511451Sralph int	hcount;				/* Count of hash entries */
3611451Sralph int	errs;
3711451Sralph 
3811451Sralph /*
3911451Sralph  * Grossness follows:
4011451Sralph  *  Names to be accumulated are hashed into the following
4111451Sralph  *  table.
4211451Sralph  */
4311451Sralph 
4411451Sralph #define	HSHSIZE	97			/* Number of hash buckets */
4511451Sralph 
4611451Sralph struct hent {
4711451Sralph 	struct	hent *h_link;		/* Forward hash link */
4811451Sralph 	char	*h_name;		/* Name of this user */
4911451Sralph 	float	h_feetpages;		/* Feet or pages of paper */
5011451Sralph 	int	h_count;		/* Number of runs */
5111451Sralph };
5211451Sralph 
5311451Sralph struct	hent	*hashtab[HSHSIZE];	/* Hash table proper */
5411451Sralph struct	hent	*enter();
5511451Sralph struct	hent	*lookup();
5611451Sralph 
5711451Sralph #define	NIL	((struct hent *) 0)	/* The big zero */
5811451Sralph 
5911451Sralph double	atof();
6011451Sralph char	*getenv();
6111451Sralph char	*pgetstr();
6211451Sralph 
6311451Sralph main(argc, argv)
6411451Sralph 	char **argv;
6511451Sralph {
6611451Sralph 	register FILE *acct;
6711451Sralph 	register char *cp;
6811451Sralph 
6911451Sralph 	while (--argc) {
7011451Sralph 		cp = *++argv;
7111451Sralph 		if (*cp++ == '-') {
7211451Sralph 			switch(*cp++) {
7311451Sralph 			case 'P':
7411451Sralph 				/*
7511451Sralph 				 * Printer name.
7611451Sralph 				 */
7711451Sralph 				printer = cp;
7811451Sralph 				continue;
7911451Sralph 
8011451Sralph 			case 'p':
8111451Sralph 				/*
8211451Sralph 				 * get the price.
8311451Sralph 				 */
8411451Sralph 				price = atof(cp);
8511451Sralph 				continue;
8611451Sralph 
8711451Sralph 			case 's':
8811451Sralph 				/*
8911451Sralph 				 * Summarize and compress accounting file.
9011451Sralph 				 */
9111451Sralph 				summarize++;
9211451Sralph 				continue;
9311451Sralph 
9411451Sralph 			case 'c':
9511451Sralph 				/*
9611451Sralph 				 * Sort by cost.
9711451Sralph 				 */
9811451Sralph 				sort++;
9911451Sralph 				continue;
10011451Sralph 
10111451Sralph 			case 'r':
10211451Sralph 				/*
10311451Sralph 				 * Reverse sorting order.
10411451Sralph 				 */
10511451Sralph 				reverse++;
10611451Sralph 				continue;
10711451Sralph 
10811451Sralph 			default:
10911451Sralph fprintf(stderr, "usage: pac [-Pprinter] [-pprice] [-s] [-c] [-r] [user ...]\n");
11011451Sralph 				exit(1);
11111451Sralph 			}
11211451Sralph 		}
11311451Sralph 		(void) enter(--cp);
11411451Sralph 		allflag = 0;
11511451Sralph 	}
11611451Sralph 	if (printer == NULL && (printer = getenv("PRINTER")) == NULL)
11711451Sralph 		printer = DEFLP;
11811451Sralph 	if (!chkprinter(printer)) {
11911451Sralph 		printf("pac: unknown printer %s\n", printer);
12011451Sralph 		exit(2);
12111451Sralph 	}
12211451Sralph 
12311451Sralph 	if ((acct = fopen(acctfile, "r")) == NULL) {
12411451Sralph 		perror(acctfile);
12511451Sralph 		exit(1);
12611451Sralph 	}
12711451Sralph 	account(acct);
12811451Sralph 	fclose(acct);
12911451Sralph 	if ((acct = fopen(sumfile, "r")) != NULL) {
13011451Sralph 		account(acct);
13111451Sralph 		fclose(acct);
13211451Sralph 	}
13311451Sralph 	if (summarize)
13411451Sralph 		rewrite();
13511451Sralph 	else
13611451Sralph 		dumpit();
13711451Sralph 	exit(errs);
13811451Sralph }
13911451Sralph 
14011451Sralph /*
14111451Sralph  * Read the entire accounting file, accumulating statistics
14211451Sralph  * for the users that we have in the hash table.  If allflag
14311451Sralph  * is set, then just gather the facts on everyone.
14411451Sralph  * Note that we must accomodate both the active and summary file
14511451Sralph  * formats here.
14611451Sralph  */
14711451Sralph 
14811451Sralph account(acct)
14911451Sralph 	register FILE *acct;
15011451Sralph {
15111451Sralph 	char linebuf[BUFSIZ];
15211451Sralph 	double t;
15311451Sralph 	register char *cp, *cp2;
15411451Sralph 	register struct hent *hp;
15511451Sralph 	register int ic;
15611451Sralph 
15711451Sralph 	while (fgets(linebuf, BUFSIZ, acct) != NULL) {
15811451Sralph 		cp = linebuf;
15911451Sralph 		while (any(*cp, " t\t"))
16011451Sralph 			cp++;
16111451Sralph 		t = atof(cp);
16211451Sralph 		while (any(*cp, ".0123456789"))
16311451Sralph 			cp++;
16411451Sralph 		while (any(*cp, " \t"))
16511451Sralph 			cp++;
16611451Sralph 		for (cp2 = cp; !any(*cp2, " \t\n"); cp2++)
16711451Sralph 			;
16811451Sralph 		ic = atoi(cp2);
16911451Sralph 		*cp2 = '\0';
17011451Sralph 		hp = lookup(cp);
17111451Sralph 		if (hp == NIL) {
17211451Sralph 			if (!allflag)
17311451Sralph 				continue;
17411451Sralph 			hp = enter(cp);
17511451Sralph 		}
17611451Sralph 		hp->h_feetpages += t;
17711451Sralph 		if (ic)
17811451Sralph 			hp->h_count += ic;
17911451Sralph 		else
18011451Sralph 			hp->h_count++;
18111451Sralph 	}
18211451Sralph }
18311451Sralph 
18411451Sralph /*
18511451Sralph  * Sort the hashed entries by name or footage
18611451Sralph  * and print it all out.
18711451Sralph  */
18811451Sralph 
18911451Sralph dumpit()
19011451Sralph {
19111451Sralph 	struct hent **base;
19211451Sralph 	register struct hent *hp, **ap;
19311451Sralph 	register int hno, c, runs;
19411451Sralph 	float feet;
19511451Sralph 	int qucmp();
19611451Sralph 
19711451Sralph 	hp = hashtab[0];
19811451Sralph 	hno = 1;
19911451Sralph 	base = (struct hent **) calloc(sizeof hp, hcount);
20011451Sralph 	for (ap = base, c = hcount; c--; ap++) {
20111451Sralph 		while (hp == NIL)
20211451Sralph 			hp = hashtab[hno++];
20311451Sralph 		*ap = hp;
20411451Sralph 		hp = hp->h_link;
20511451Sralph 	}
20611451Sralph 	qsort(base, hcount, sizeof hp, qucmp);
20711451Sralph 	printf("  Login               pages/feet   runs    price\n");
20811451Sralph 	feet = 0.0;
20911451Sralph 	runs = 0;
21011451Sralph 	for (ap = base, c = hcount; c--; ap++) {
21111451Sralph 		hp = *ap;
21211451Sralph 		runs += hp->h_count;
21311451Sralph 		feet += hp->h_feetpages;
21411451Sralph 		printf("%-24s %7.2f %4d   $%6.2f\n", hp->h_name,
21511451Sralph 		    hp->h_feetpages, hp->h_count, hp->h_feetpages * price);
21611451Sralph 	}
21711451Sralph 	if (allflag) {
21811451Sralph 		printf("\n");
21911451Sralph 		printf("%-24s %7.2f %4d   $%6.2f\n", "total", feet,
22011451Sralph 		    runs, feet * price);
22111451Sralph 	}
22211451Sralph }
22311451Sralph 
22411451Sralph /*
22511451Sralph  * Rewrite the summary file with the summary information we have accumulated.
22611451Sralph  */
22711451Sralph 
22811451Sralph rewrite()
22911451Sralph {
23011451Sralph 	register struct hent *hp;
23111451Sralph 	register int i;
23211451Sralph 	register FILE *acctf;
23311451Sralph 
23411451Sralph 	if ((acctf = fopen(sumfile, "w")) == NULL) {
23511451Sralph 		perror(sumfile);
23611451Sralph 		errs++;
23711451Sralph 		return;
23811451Sralph 	}
23911451Sralph 	for (i = 0; i < HSHSIZE; i++) {
24011451Sralph 		hp = hashtab[i];
24111451Sralph 		while (hp != NULL) {
24211451Sralph 			fprintf(acctf, "%7.2f\t%s\t%d\n", hp->h_feetpages,
24311451Sralph 			    hp->h_name, hp->h_count);
24411451Sralph 			hp = hp->h_link;
24511451Sralph 		}
24611451Sralph 	}
24711451Sralph 	fflush(acctf);
24811451Sralph 	if (ferror(acctf)) {
24911451Sralph 		perror(sumfile);
25011451Sralph 		errs++;
25111451Sralph 	}
25211451Sralph 	fclose(acctf);
25311451Sralph 	if ((acctf = fopen(acctfile, "w")) == NULL)
25411451Sralph 		perror(acctfile);
25511451Sralph 	else
25611451Sralph 		fclose(acctf);
25711451Sralph }
25811451Sralph 
25911451Sralph /*
26011451Sralph  * Hashing routines.
26111451Sralph  */
26211451Sralph 
26311451Sralph /*
26411451Sralph  * Enter the name into the hash table and return the pointer allocated.
26511451Sralph  */
26611451Sralph 
26711451Sralph struct hent *
26811451Sralph enter(name)
26911451Sralph 	char name[];
27011451Sralph {
27111451Sralph 	register struct hent *hp;
27211451Sralph 	register int h;
27311451Sralph 
27411451Sralph 	if ((hp = lookup(name)) != NIL)
27511451Sralph 		return(hp);
27611451Sralph 	h = hash(name);
27711451Sralph 	hcount++;
27811451Sralph 	hp = (struct hent *) calloc(sizeof *hp, 1);
27911451Sralph 	hp->h_name = (char *) calloc(sizeof(char), strlen(name)+1);
28011451Sralph 	strcpy(hp->h_name, name);
28111451Sralph 	hp->h_feetpages = 0.0;
28211451Sralph 	hp->h_count = 0;
28311451Sralph 	hp->h_link = hashtab[h];
28411451Sralph 	hashtab[h] = hp;
28511451Sralph 	return(hp);
28611451Sralph }
28711451Sralph 
28811451Sralph /*
28911451Sralph  * Lookup a name in the hash table and return a pointer
29011451Sralph  * to it.
29111451Sralph  */
29211451Sralph 
29311451Sralph struct hent *
29411451Sralph lookup(name)
29511451Sralph 	char name[];
29611451Sralph {
29711451Sralph 	register int h;
29811451Sralph 	register struct hent *hp;
29911451Sralph 
30011451Sralph 	h = hash(name);
30111451Sralph 	for (hp = hashtab[h]; hp != NIL; hp = hp->h_link)
30211451Sralph 		if (strcmp(hp->h_name, name) == 0)
30311451Sralph 			return(hp);
30411451Sralph 	return(NIL);
30511451Sralph }
30611451Sralph 
30711451Sralph /*
30811451Sralph  * Hash the passed name and return the index in
30911451Sralph  * the hash table to begin the search.
31011451Sralph  */
31111451Sralph 
31211451Sralph hash(name)
31311451Sralph 	char name[];
31411451Sralph {
31511451Sralph 	register int h;
31611451Sralph 	register char *cp;
31711451Sralph 
31811451Sralph 	for (cp = name, h = 0; *cp; h = (h << 2) + *cp++)
31911451Sralph 		;
32011451Sralph 	return((h & 0x7fffffff) % HSHSIZE);
32111451Sralph }
32211451Sralph 
32311451Sralph /*
32411451Sralph  * Other stuff
32511451Sralph  */
32611451Sralph 
32711451Sralph any(ch, str)
32811451Sralph 	char str[];
32911451Sralph {
33011451Sralph 	register int c = ch;
33111451Sralph 	register char *cp = str;
33211451Sralph 
33311451Sralph 	while (*cp)
33411451Sralph 		if (*cp++ == c)
33511451Sralph 			return(1);
33611451Sralph 	return(0);
33711451Sralph }
33811451Sralph 
33911451Sralph /*
34011451Sralph  * The qsort comparison routine.
34111451Sralph  * The comparison is ascii collating order
34211451Sralph  * or by feet of typesetter film, according to sort.
34311451Sralph  */
34411451Sralph 
34511451Sralph qucmp(left, right)
34611451Sralph 	struct hent **left, **right;
34711451Sralph {
34811451Sralph 	register struct hent *h1, *h2;
34911451Sralph 	register int r;
35011451Sralph 
35111451Sralph 	h1 = *left;
35211451Sralph 	h2 = *right;
35311451Sralph 	if (sort)
35411451Sralph 		r = h1->h_feetpages < h2->h_feetpages ? -1 : h1->h_feetpages > h2->h_feetpages;
35511451Sralph 	else
35611451Sralph 		r = strcmp(h1->h_name, h2->h_name);
35711451Sralph 	return(reverse ? -r : r);
35811451Sralph }
35911451Sralph 
36011451Sralph /*
36111451Sralph  * Perform lookup for printer name or abbreviation --
36211451Sralph  */
36311451Sralph chkprinter(s)
36411451Sralph 	register char *s;
36511451Sralph {
36611451Sralph 	static char buf[BUFSIZ/2];
36711451Sralph 	char b[BUFSIZ];
36811451Sralph 	int stat;
36911451Sralph 	char *bp = buf;
37011451Sralph 
37111451Sralph 	if ((stat = pgetent(b, s)) < 0) {
37211451Sralph 		printf("pac: can't open printer description file\n");
37311451Sralph 		exit(3);
37411451Sralph 	} else if (stat == 0)
37511451Sralph 		return(0);
37611451Sralph 	if ((acctfile = pgetstr("af", &bp)) == NULL) {
37711451Sralph 		printf("accounting not enabled for printer %s\n", printer);
37811451Sralph 		exit(2);
37911451Sralph 	}
38011451Sralph 	sumfile = (char *) calloc(sizeof(char), strlen(acctfile)+5);
38111451Sralph 	if (sumfile == NULL) {
38211451Sralph 		perror("pac");
38311451Sralph 		exit(1);
38411451Sralph 	}
38511451Sralph 	strcpy(sumfile, acctfile);
38611451Sralph 	strcat(sumfile, "_sum");
38711451Sralph 	return(1);
38811451Sralph }
389