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