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