Commit | Line | Data |
---|---|---|
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 | ||
12 | int errs; | |
13 | char vpacct[] = "/usr/adm/vpacct"; | |
14 | char 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 | ||
26 | struct 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 | ||
33 | struct hent *hashtab[HSHSIZE]; /* Hash table proper */ | |
34 | struct hent *enter(); | |
35 | struct hent *lookup(); | |
36 | ||
37 | #define NIL ((struct hent *) 0) /* The big zero */ | |
38 | ||
39 | int allflag; /* Get stats on everybody */ | |
40 | int sort; /* Sort by cost */ | |
41 | int summarize; /* Compress accounting file */ | |
42 | int reverse; /* Reverse sort order */ | |
43 | ||
44 | int hcount; /* Count of hash entries */ | |
45 | ||
46 | main(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 | ||
115 | account(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 | ||
155 | dumpit() | |
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 | ||
195 | rewrite() | |
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 | ||
235 | struct hent * | |
236 | enter(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 | ||
260 | struct hent * | |
261 | lookup(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 | ||
279 | hash(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 | ||
298 | any(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 | ||
314 | ignore(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 | ||
324 | qucmp(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 | } |