BSD 4 development
[unix-history] / usr / src / cmd / vpr / vpac.c
CommitLineData
3398ef49
BJ
1#
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
12int 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"
18char *acctfile;
19char *sumfile;
20
21#define VAPRICE 0.02 /* Dollars per page */
22#define VPPRICE 0.08 /* Dollars per foot of paper */
23float 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
33struct 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
40struct hent *hashtab[HSHSIZE]; /* Hash table proper */
41struct hent *enter();
42struct hent *lookup();
43
44#define NIL ((struct hent *) 0) /* The big zero */
45
46int allflag; /* Get stats on everybody */
47int sort; /* Sort by cost */
48int summarize; /* Compress accounting file */
49int reverse; /* Reverse sort order */
50int wide; /* wide paper (Versatec) accounting. */
51
52int hcount; /* Count of hash entries */
53
54main(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
136account(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
176dumpit()
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
216rewrite()
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
256struct hent *
257enter(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
281struct hent *
282lookup(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
300hash(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
319any(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
335ignore(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
345qucmp(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}