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