Commit | Line | Data |
---|---|---|
32aa4077 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 | ||
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 | } |