xref: /csrg-svn/usr.sbin/lpr/pac/pac.c (revision 11451)
1*11451Sralph /*	pac.c	4.1	83/03/09	*/
2*11451Sralph /*
3*11451Sralph  * Do Printer accounting summary.
4*11451Sralph  * Currently, usage is
5*11451Sralph  *	pac [-Pprinter] [-pprice] [-s] [-r] [-c] [user ...]
6*11451Sralph  * to print the usage information for the named people.
7*11451Sralph  */
8*11451Sralph 
9*11451Sralph #include <stdio.h>
10*11451Sralph #include "lp.local.h"
11*11451Sralph 
12*11451Sralph char	*printer;			/* printer name */
13*11451Sralph char	*acctfile;			/* accounting file (input data) */
14*11451Sralph char	*sumfile;			/* summary file */
15*11451Sralph float	price = 0.02;			/* cost per page (or what ever) */
16*11451Sralph int	allflag = 1;			/* Get stats on everybody */
17*11451Sralph int	sort;				/* Sort by cost */
18*11451Sralph int	summarize;			/* Compress accounting file */
19*11451Sralph int	reverse;			/* Reverse sort order */
20*11451Sralph int	hcount;				/* Count of hash entries */
21*11451Sralph int	errs;
22*11451Sralph 
23*11451Sralph /*
24*11451Sralph  * Grossness follows:
25*11451Sralph  *  Names to be accumulated are hashed into the following
26*11451Sralph  *  table.
27*11451Sralph  */
28*11451Sralph 
29*11451Sralph #define	HSHSIZE	97			/* Number of hash buckets */
30*11451Sralph 
31*11451Sralph struct hent {
32*11451Sralph 	struct	hent *h_link;		/* Forward hash link */
33*11451Sralph 	char	*h_name;		/* Name of this user */
34*11451Sralph 	float	h_feetpages;		/* Feet or pages of paper */
35*11451Sralph 	int	h_count;		/* Number of runs */
36*11451Sralph };
37*11451Sralph 
38*11451Sralph struct	hent	*hashtab[HSHSIZE];	/* Hash table proper */
39*11451Sralph struct	hent	*enter();
40*11451Sralph struct	hent	*lookup();
41*11451Sralph 
42*11451Sralph #define	NIL	((struct hent *) 0)	/* The big zero */
43*11451Sralph 
44*11451Sralph double	atof();
45*11451Sralph char	*getenv();
46*11451Sralph char	*pgetstr();
47*11451Sralph 
48*11451Sralph main(argc, argv)
49*11451Sralph 	char **argv;
50*11451Sralph {
51*11451Sralph 	register FILE *acct;
52*11451Sralph 	register char *cp;
53*11451Sralph 
54*11451Sralph 	while (--argc) {
55*11451Sralph 		cp = *++argv;
56*11451Sralph 		if (*cp++ == '-') {
57*11451Sralph 			switch(*cp++) {
58*11451Sralph 			case 'P':
59*11451Sralph 				/*
60*11451Sralph 				 * Printer name.
61*11451Sralph 				 */
62*11451Sralph 				printer = cp;
63*11451Sralph 				continue;
64*11451Sralph 
65*11451Sralph 			case 'p':
66*11451Sralph 				/*
67*11451Sralph 				 * get the price.
68*11451Sralph 				 */
69*11451Sralph 				price = atof(cp);
70*11451Sralph 				continue;
71*11451Sralph 
72*11451Sralph 			case 's':
73*11451Sralph 				/*
74*11451Sralph 				 * Summarize and compress accounting file.
75*11451Sralph 				 */
76*11451Sralph 				summarize++;
77*11451Sralph 				continue;
78*11451Sralph 
79*11451Sralph 			case 'c':
80*11451Sralph 				/*
81*11451Sralph 				 * Sort by cost.
82*11451Sralph 				 */
83*11451Sralph 				sort++;
84*11451Sralph 				continue;
85*11451Sralph 
86*11451Sralph 			case 'r':
87*11451Sralph 				/*
88*11451Sralph 				 * Reverse sorting order.
89*11451Sralph 				 */
90*11451Sralph 				reverse++;
91*11451Sralph 				continue;
92*11451Sralph 
93*11451Sralph 			default:
94*11451Sralph fprintf(stderr, "usage: pac [-Pprinter] [-pprice] [-s] [-c] [-r] [user ...]\n");
95*11451Sralph 				exit(1);
96*11451Sralph 			}
97*11451Sralph 		}
98*11451Sralph 		(void) enter(--cp);
99*11451Sralph 		allflag = 0;
100*11451Sralph 	}
101*11451Sralph 	if (printer == NULL && (printer = getenv("PRINTER")) == NULL)
102*11451Sralph 		printer = DEFLP;
103*11451Sralph 	if (!chkprinter(printer)) {
104*11451Sralph 		printf("pac: unknown printer %s\n", printer);
105*11451Sralph 		exit(2);
106*11451Sralph 	}
107*11451Sralph 
108*11451Sralph 	if ((acct = fopen(acctfile, "r")) == NULL) {
109*11451Sralph 		perror(acctfile);
110*11451Sralph 		exit(1);
111*11451Sralph 	}
112*11451Sralph 	account(acct);
113*11451Sralph 	fclose(acct);
114*11451Sralph 	if ((acct = fopen(sumfile, "r")) != NULL) {
115*11451Sralph 		account(acct);
116*11451Sralph 		fclose(acct);
117*11451Sralph 	}
118*11451Sralph 	if (summarize)
119*11451Sralph 		rewrite();
120*11451Sralph 	else
121*11451Sralph 		dumpit();
122*11451Sralph 	exit(errs);
123*11451Sralph }
124*11451Sralph 
125*11451Sralph /*
126*11451Sralph  * Read the entire accounting file, accumulating statistics
127*11451Sralph  * for the users that we have in the hash table.  If allflag
128*11451Sralph  * is set, then just gather the facts on everyone.
129*11451Sralph  * Note that we must accomodate both the active and summary file
130*11451Sralph  * formats here.
131*11451Sralph  */
132*11451Sralph 
133*11451Sralph account(acct)
134*11451Sralph 	register FILE *acct;
135*11451Sralph {
136*11451Sralph 	char linebuf[BUFSIZ];
137*11451Sralph 	double t;
138*11451Sralph 	register char *cp, *cp2;
139*11451Sralph 	register struct hent *hp;
140*11451Sralph 	register int ic;
141*11451Sralph 
142*11451Sralph 	while (fgets(linebuf, BUFSIZ, acct) != NULL) {
143*11451Sralph 		cp = linebuf;
144*11451Sralph 		while (any(*cp, " t\t"))
145*11451Sralph 			cp++;
146*11451Sralph 		t = atof(cp);
147*11451Sralph 		while (any(*cp, ".0123456789"))
148*11451Sralph 			cp++;
149*11451Sralph 		while (any(*cp, " \t"))
150*11451Sralph 			cp++;
151*11451Sralph 		for (cp2 = cp; !any(*cp2, " \t\n"); cp2++)
152*11451Sralph 			;
153*11451Sralph 		ic = atoi(cp2);
154*11451Sralph 		*cp2 = '\0';
155*11451Sralph 		hp = lookup(cp);
156*11451Sralph 		if (hp == NIL) {
157*11451Sralph 			if (!allflag)
158*11451Sralph 				continue;
159*11451Sralph 			hp = enter(cp);
160*11451Sralph 		}
161*11451Sralph 		hp->h_feetpages += t;
162*11451Sralph 		if (ic)
163*11451Sralph 			hp->h_count += ic;
164*11451Sralph 		else
165*11451Sralph 			hp->h_count++;
166*11451Sralph 	}
167*11451Sralph }
168*11451Sralph 
169*11451Sralph /*
170*11451Sralph  * Sort the hashed entries by name or footage
171*11451Sralph  * and print it all out.
172*11451Sralph  */
173*11451Sralph 
174*11451Sralph dumpit()
175*11451Sralph {
176*11451Sralph 	struct hent **base;
177*11451Sralph 	register struct hent *hp, **ap;
178*11451Sralph 	register int hno, c, runs;
179*11451Sralph 	float feet;
180*11451Sralph 	int qucmp();
181*11451Sralph 
182*11451Sralph 	hp = hashtab[0];
183*11451Sralph 	hno = 1;
184*11451Sralph 	base = (struct hent **) calloc(sizeof hp, hcount);
185*11451Sralph 	for (ap = base, c = hcount; c--; ap++) {
186*11451Sralph 		while (hp == NIL)
187*11451Sralph 			hp = hashtab[hno++];
188*11451Sralph 		*ap = hp;
189*11451Sralph 		hp = hp->h_link;
190*11451Sralph 	}
191*11451Sralph 	qsort(base, hcount, sizeof hp, qucmp);
192*11451Sralph 	printf("  Login               pages/feet   runs    price\n");
193*11451Sralph 	feet = 0.0;
194*11451Sralph 	runs = 0;
195*11451Sralph 	for (ap = base, c = hcount; c--; ap++) {
196*11451Sralph 		hp = *ap;
197*11451Sralph 		runs += hp->h_count;
198*11451Sralph 		feet += hp->h_feetpages;
199*11451Sralph 		printf("%-24s %7.2f %4d   $%6.2f\n", hp->h_name,
200*11451Sralph 		    hp->h_feetpages, hp->h_count, hp->h_feetpages * price);
201*11451Sralph 	}
202*11451Sralph 	if (allflag) {
203*11451Sralph 		printf("\n");
204*11451Sralph 		printf("%-24s %7.2f %4d   $%6.2f\n", "total", feet,
205*11451Sralph 		    runs, feet * price);
206*11451Sralph 	}
207*11451Sralph }
208*11451Sralph 
209*11451Sralph /*
210*11451Sralph  * Rewrite the summary file with the summary information we have accumulated.
211*11451Sralph  */
212*11451Sralph 
213*11451Sralph rewrite()
214*11451Sralph {
215*11451Sralph 	register struct hent *hp;
216*11451Sralph 	register int i;
217*11451Sralph 	register FILE *acctf;
218*11451Sralph 
219*11451Sralph 	if ((acctf = fopen(sumfile, "w")) == NULL) {
220*11451Sralph 		perror(sumfile);
221*11451Sralph 		errs++;
222*11451Sralph 		return;
223*11451Sralph 	}
224*11451Sralph 	for (i = 0; i < HSHSIZE; i++) {
225*11451Sralph 		hp = hashtab[i];
226*11451Sralph 		while (hp != NULL) {
227*11451Sralph 			fprintf(acctf, "%7.2f\t%s\t%d\n", hp->h_feetpages,
228*11451Sralph 			    hp->h_name, hp->h_count);
229*11451Sralph 			hp = hp->h_link;
230*11451Sralph 		}
231*11451Sralph 	}
232*11451Sralph 	fflush(acctf);
233*11451Sralph 	if (ferror(acctf)) {
234*11451Sralph 		perror(sumfile);
235*11451Sralph 		errs++;
236*11451Sralph 	}
237*11451Sralph 	fclose(acctf);
238*11451Sralph 	if ((acctf = fopen(acctfile, "w")) == NULL)
239*11451Sralph 		perror(acctfile);
240*11451Sralph 	else
241*11451Sralph 		fclose(acctf);
242*11451Sralph }
243*11451Sralph 
244*11451Sralph /*
245*11451Sralph  * Hashing routines.
246*11451Sralph  */
247*11451Sralph 
248*11451Sralph /*
249*11451Sralph  * Enter the name into the hash table and return the pointer allocated.
250*11451Sralph  */
251*11451Sralph 
252*11451Sralph struct hent *
253*11451Sralph enter(name)
254*11451Sralph 	char name[];
255*11451Sralph {
256*11451Sralph 	register struct hent *hp;
257*11451Sralph 	register int h;
258*11451Sralph 
259*11451Sralph 	if ((hp = lookup(name)) != NIL)
260*11451Sralph 		return(hp);
261*11451Sralph 	h = hash(name);
262*11451Sralph 	hcount++;
263*11451Sralph 	hp = (struct hent *) calloc(sizeof *hp, 1);
264*11451Sralph 	hp->h_name = (char *) calloc(sizeof(char), strlen(name)+1);
265*11451Sralph 	strcpy(hp->h_name, name);
266*11451Sralph 	hp->h_feetpages = 0.0;
267*11451Sralph 	hp->h_count = 0;
268*11451Sralph 	hp->h_link = hashtab[h];
269*11451Sralph 	hashtab[h] = hp;
270*11451Sralph 	return(hp);
271*11451Sralph }
272*11451Sralph 
273*11451Sralph /*
274*11451Sralph  * Lookup a name in the hash table and return a pointer
275*11451Sralph  * to it.
276*11451Sralph  */
277*11451Sralph 
278*11451Sralph struct hent *
279*11451Sralph lookup(name)
280*11451Sralph 	char name[];
281*11451Sralph {
282*11451Sralph 	register int h;
283*11451Sralph 	register struct hent *hp;
284*11451Sralph 
285*11451Sralph 	h = hash(name);
286*11451Sralph 	for (hp = hashtab[h]; hp != NIL; hp = hp->h_link)
287*11451Sralph 		if (strcmp(hp->h_name, name) == 0)
288*11451Sralph 			return(hp);
289*11451Sralph 	return(NIL);
290*11451Sralph }
291*11451Sralph 
292*11451Sralph /*
293*11451Sralph  * Hash the passed name and return the index in
294*11451Sralph  * the hash table to begin the search.
295*11451Sralph  */
296*11451Sralph 
297*11451Sralph hash(name)
298*11451Sralph 	char name[];
299*11451Sralph {
300*11451Sralph 	register int h;
301*11451Sralph 	register char *cp;
302*11451Sralph 
303*11451Sralph 	for (cp = name, h = 0; *cp; h = (h << 2) + *cp++)
304*11451Sralph 		;
305*11451Sralph 	return((h & 0x7fffffff) % HSHSIZE);
306*11451Sralph }
307*11451Sralph 
308*11451Sralph /*
309*11451Sralph  * Other stuff
310*11451Sralph  */
311*11451Sralph 
312*11451Sralph any(ch, str)
313*11451Sralph 	char str[];
314*11451Sralph {
315*11451Sralph 	register int c = ch;
316*11451Sralph 	register char *cp = str;
317*11451Sralph 
318*11451Sralph 	while (*cp)
319*11451Sralph 		if (*cp++ == c)
320*11451Sralph 			return(1);
321*11451Sralph 	return(0);
322*11451Sralph }
323*11451Sralph 
324*11451Sralph /*
325*11451Sralph  * The qsort comparison routine.
326*11451Sralph  * The comparison is ascii collating order
327*11451Sralph  * or by feet of typesetter film, according to sort.
328*11451Sralph  */
329*11451Sralph 
330*11451Sralph qucmp(left, right)
331*11451Sralph 	struct hent **left, **right;
332*11451Sralph {
333*11451Sralph 	register struct hent *h1, *h2;
334*11451Sralph 	register int r;
335*11451Sralph 
336*11451Sralph 	h1 = *left;
337*11451Sralph 	h2 = *right;
338*11451Sralph 	if (sort)
339*11451Sralph 		r = h1->h_feetpages < h2->h_feetpages ? -1 : h1->h_feetpages > h2->h_feetpages;
340*11451Sralph 	else
341*11451Sralph 		r = strcmp(h1->h_name, h2->h_name);
342*11451Sralph 	return(reverse ? -r : r);
343*11451Sralph }
344*11451Sralph 
345*11451Sralph /*
346*11451Sralph  * Perform lookup for printer name or abbreviation --
347*11451Sralph  */
348*11451Sralph chkprinter(s)
349*11451Sralph 	register char *s;
350*11451Sralph {
351*11451Sralph 	static char buf[BUFSIZ/2];
352*11451Sralph 	char b[BUFSIZ];
353*11451Sralph 	int stat;
354*11451Sralph 	char *bp = buf;
355*11451Sralph 
356*11451Sralph 	if ((stat = pgetent(b, s)) < 0) {
357*11451Sralph 		printf("pac: can't open printer description file\n");
358*11451Sralph 		exit(3);
359*11451Sralph 	} else if (stat == 0)
360*11451Sralph 		return(0);
361*11451Sralph 	if ((acctfile = pgetstr("af", &bp)) == NULL) {
362*11451Sralph 		printf("accounting not enabled for printer %s\n", printer);
363*11451Sralph 		exit(2);
364*11451Sralph 	}
365*11451Sralph 	sumfile = (char *) calloc(sizeof(char), strlen(acctfile)+5);
366*11451Sralph 	if (sumfile == NULL) {
367*11451Sralph 		perror("pac");
368*11451Sralph 		exit(1);
369*11451Sralph 	}
370*11451Sralph 	strcpy(sumfile, acctfile);
371*11451Sralph 	strcat(sumfile, "_sum");
372*11451Sralph 	return(1);
373*11451Sralph }
374