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