Commit | Line | Data |
---|---|---|
d0aeaf5a DF |
1 | /* |
2 | * Copyright (c) 1983 Regents of the University of California. | |
9d85c861 KB |
3 | * All rights reserved. |
4 | * | |
5 | * Redistribution and use in source and binary forms are permitted | |
a399f6c8 KB |
6 | * provided that the above copyright notice and this paragraph are |
7 | * duplicated in all such forms and that any documentation, | |
8 | * advertising materials, and other materials related to such | |
9 | * distribution and use acknowledge that the software was developed | |
10 | * by the University of California, Berkeley. The name of the | |
11 | * University may not be used to endorse or promote products derived | |
12 | * from this software without specific prior written permission. | |
13 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR | |
14 | * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED | |
15 | * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. | |
d0aeaf5a DF |
16 | */ |
17 | ||
18 | #ifndef lint | |
19 | char copyright[] = | |
20 | "@(#) Copyright (c) 1983 Regents of the University of California.\n\ | |
21 | All rights reserved.\n"; | |
9d85c861 | 22 | #endif /* not lint */ |
d0aeaf5a | 23 | |
5f84f8f0 | 24 | #ifndef lint |
a399f6c8 | 25 | static char sccsid[] = "@(#)pac.c 5.4 (Berkeley) %G%"; |
9d85c861 | 26 | #endif /* not lint */ |
5f84f8f0 | 27 | |
28e04fa9 RC |
28 | /* |
29 | * Do Printer accounting summary. | |
30 | * Currently, usage is | |
3576ded8 | 31 | * pac [-Pprinter] [-pprice] [-s] [-r] [-c] [-m] [user ...] |
28e04fa9 RC |
32 | * to print the usage information for the named people. |
33 | */ | |
34 | ||
35 | #include <stdio.h> | |
36 | #include "lp.local.h" | |
37 | ||
38 | char *printer; /* printer name */ | |
39 | char *acctfile; /* accounting file (input data) */ | |
40 | char *sumfile; /* summary file */ | |
41 | float price = 0.02; /* cost per page (or what ever) */ | |
42 | int allflag = 1; /* Get stats on everybody */ | |
43 | int sort; /* Sort by cost */ | |
44 | int summarize; /* Compress accounting file */ | |
45 | int reverse; /* Reverse sort order */ | |
46 | int hcount; /* Count of hash entries */ | |
47 | int errs; | |
3576ded8 JB |
48 | int mflag = 0; /* disregard machine names */ |
49 | int pflag = 0; /* 1 if -p on cmd line */ | |
50 | int price100; /* per-page cost in 100th of a cent */ | |
51 | char *index(); | |
52 | int pgetnum(); | |
28e04fa9 RC |
53 | |
54 | /* | |
55 | * Grossness follows: | |
56 | * Names to be accumulated are hashed into the following | |
57 | * table. | |
58 | */ | |
59 | ||
60 | #define HSHSIZE 97 /* Number of hash buckets */ | |
61 | ||
62 | struct hent { | |
63 | struct hent *h_link; /* Forward hash link */ | |
64 | char *h_name; /* Name of this user */ | |
65 | float h_feetpages; /* Feet or pages of paper */ | |
66 | int h_count; /* Number of runs */ | |
67 | }; | |
68 | ||
69 | struct hent *hashtab[HSHSIZE]; /* Hash table proper */ | |
70 | struct hent *enter(); | |
71 | struct hent *lookup(); | |
72 | ||
73 | #define NIL ((struct hent *) 0) /* The big zero */ | |
74 | ||
75 | double atof(); | |
76 | char *getenv(); | |
77 | char *pgetstr(); | |
78 | ||
79 | main(argc, argv) | |
80 | char **argv; | |
81 | { | |
82 | register FILE *acct; | |
83 | register char *cp; | |
84 | ||
85 | while (--argc) { | |
86 | cp = *++argv; | |
87 | if (*cp++ == '-') { | |
88 | switch(*cp++) { | |
89 | case 'P': | |
90 | /* | |
91 | * Printer name. | |
92 | */ | |
93 | printer = cp; | |
94 | continue; | |
95 | ||
96 | case 'p': | |
97 | /* | |
98 | * get the price. | |
99 | */ | |
100 | price = atof(cp); | |
3576ded8 | 101 | pflag = 1; |
28e04fa9 RC |
102 | continue; |
103 | ||
104 | case 's': | |
105 | /* | |
106 | * Summarize and compress accounting file. | |
107 | */ | |
108 | summarize++; | |
109 | continue; | |
110 | ||
111 | case 'c': | |
112 | /* | |
113 | * Sort by cost. | |
114 | */ | |
115 | sort++; | |
116 | continue; | |
117 | ||
3576ded8 JB |
118 | case 'm': |
119 | /* | |
120 | * disregard machine names for each user | |
121 | */ | |
122 | mflag = 1; | |
123 | continue; | |
124 | ||
28e04fa9 RC |
125 | case 'r': |
126 | /* | |
127 | * Reverse sorting order. | |
128 | */ | |
129 | reverse++; | |
130 | continue; | |
131 | ||
132 | default: | |
3576ded8 JB |
133 | fprintf(stderr, |
134 | "usage: pac [-Pprinter] [-pprice] [-s] [-c] [-r] [-m] [user ...]\n"); | |
28e04fa9 RC |
135 | exit(1); |
136 | } | |
137 | } | |
138 | (void) enter(--cp); | |
139 | allflag = 0; | |
140 | } | |
141 | if (printer == NULL && (printer = getenv("PRINTER")) == NULL) | |
142 | printer = DEFLP; | |
143 | if (!chkprinter(printer)) { | |
144 | printf("pac: unknown printer %s\n", printer); | |
145 | exit(2); | |
146 | } | |
147 | ||
148 | if ((acct = fopen(acctfile, "r")) == NULL) { | |
149 | perror(acctfile); | |
150 | exit(1); | |
151 | } | |
152 | account(acct); | |
153 | fclose(acct); | |
154 | if ((acct = fopen(sumfile, "r")) != NULL) { | |
155 | account(acct); | |
156 | fclose(acct); | |
157 | } | |
158 | if (summarize) | |
159 | rewrite(); | |
160 | else | |
161 | dumpit(); | |
162 | exit(errs); | |
163 | } | |
164 | ||
165 | /* | |
166 | * Read the entire accounting file, accumulating statistics | |
167 | * for the users that we have in the hash table. If allflag | |
168 | * is set, then just gather the facts on everyone. | |
169 | * Note that we must accomodate both the active and summary file | |
170 | * formats here. | |
3576ded8 | 171 | * Host names are ignored if the -m flag is present. |
28e04fa9 RC |
172 | */ |
173 | ||
174 | account(acct) | |
175 | register FILE *acct; | |
176 | { | |
177 | char linebuf[BUFSIZ]; | |
178 | double t; | |
179 | register char *cp, *cp2; | |
180 | register struct hent *hp; | |
181 | register int ic; | |
182 | ||
183 | while (fgets(linebuf, BUFSIZ, acct) != NULL) { | |
184 | cp = linebuf; | |
185 | while (any(*cp, " t\t")) | |
186 | cp++; | |
187 | t = atof(cp); | |
188 | while (any(*cp, ".0123456789")) | |
189 | cp++; | |
190 | while (any(*cp, " \t")) | |
191 | cp++; | |
192 | for (cp2 = cp; !any(*cp2, " \t\n"); cp2++) | |
193 | ; | |
194 | ic = atoi(cp2); | |
195 | *cp2 = '\0'; | |
3576ded8 JB |
196 | if (mflag && index(cp, ':')) |
197 | cp = index(cp, ':') + 1; | |
28e04fa9 RC |
198 | hp = lookup(cp); |
199 | if (hp == NIL) { | |
200 | if (!allflag) | |
201 | continue; | |
202 | hp = enter(cp); | |
203 | } | |
204 | hp->h_feetpages += t; | |
205 | if (ic) | |
206 | hp->h_count += ic; | |
207 | else | |
208 | hp->h_count++; | |
209 | } | |
210 | } | |
211 | ||
212 | /* | |
213 | * Sort the hashed entries by name or footage | |
214 | * and print it all out. | |
215 | */ | |
216 | ||
217 | dumpit() | |
218 | { | |
219 | struct hent **base; | |
220 | register struct hent *hp, **ap; | |
221 | register int hno, c, runs; | |
222 | float feet; | |
223 | int qucmp(); | |
224 | ||
225 | hp = hashtab[0]; | |
226 | hno = 1; | |
227 | base = (struct hent **) calloc(sizeof hp, hcount); | |
228 | for (ap = base, c = hcount; c--; ap++) { | |
229 | while (hp == NIL) | |
230 | hp = hashtab[hno++]; | |
231 | *ap = hp; | |
232 | hp = hp->h_link; | |
233 | } | |
234 | qsort(base, hcount, sizeof hp, qucmp); | |
235 | printf(" Login pages/feet runs price\n"); | |
236 | feet = 0.0; | |
237 | runs = 0; | |
238 | for (ap = base, c = hcount; c--; ap++) { | |
239 | hp = *ap; | |
240 | runs += hp->h_count; | |
241 | feet += hp->h_feetpages; | |
242 | printf("%-24s %7.2f %4d $%6.2f\n", hp->h_name, | |
243 | hp->h_feetpages, hp->h_count, hp->h_feetpages * price); | |
244 | } | |
245 | if (allflag) { | |
246 | printf("\n"); | |
247 | printf("%-24s %7.2f %4d $%6.2f\n", "total", feet, | |
248 | runs, feet * price); | |
249 | } | |
250 | } | |
251 | ||
252 | /* | |
253 | * Rewrite the summary file with the summary information we have accumulated. | |
254 | */ | |
255 | ||
256 | rewrite() | |
257 | { | |
258 | register struct hent *hp; | |
259 | register int i; | |
260 | register FILE *acctf; | |
261 | ||
262 | if ((acctf = fopen(sumfile, "w")) == NULL) { | |
263 | perror(sumfile); | |
264 | errs++; | |
265 | return; | |
266 | } | |
267 | for (i = 0; i < HSHSIZE; i++) { | |
268 | hp = hashtab[i]; | |
269 | while (hp != NULL) { | |
270 | fprintf(acctf, "%7.2f\t%s\t%d\n", hp->h_feetpages, | |
271 | hp->h_name, hp->h_count); | |
272 | hp = hp->h_link; | |
273 | } | |
274 | } | |
275 | fflush(acctf); | |
276 | if (ferror(acctf)) { | |
277 | perror(sumfile); | |
278 | errs++; | |
279 | } | |
280 | fclose(acctf); | |
281 | if ((acctf = fopen(acctfile, "w")) == NULL) | |
282 | perror(acctfile); | |
283 | else | |
284 | fclose(acctf); | |
285 | } | |
286 | ||
287 | /* | |
288 | * Hashing routines. | |
289 | */ | |
290 | ||
291 | /* | |
292 | * Enter the name into the hash table and return the pointer allocated. | |
293 | */ | |
294 | ||
295 | struct hent * | |
296 | enter(name) | |
297 | char name[]; | |
298 | { | |
299 | register struct hent *hp; | |
300 | register int h; | |
301 | ||
302 | if ((hp = lookup(name)) != NIL) | |
303 | return(hp); | |
304 | h = hash(name); | |
305 | hcount++; | |
306 | hp = (struct hent *) calloc(sizeof *hp, 1); | |
307 | hp->h_name = (char *) calloc(sizeof(char), strlen(name)+1); | |
308 | strcpy(hp->h_name, name); | |
309 | hp->h_feetpages = 0.0; | |
310 | hp->h_count = 0; | |
311 | hp->h_link = hashtab[h]; | |
312 | hashtab[h] = hp; | |
313 | return(hp); | |
314 | } | |
315 | ||
316 | /* | |
317 | * Lookup a name in the hash table and return a pointer | |
318 | * to it. | |
319 | */ | |
320 | ||
321 | struct hent * | |
322 | lookup(name) | |
323 | char name[]; | |
324 | { | |
325 | register int h; | |
326 | register struct hent *hp; | |
327 | ||
328 | h = hash(name); | |
329 | for (hp = hashtab[h]; hp != NIL; hp = hp->h_link) | |
330 | if (strcmp(hp->h_name, name) == 0) | |
331 | return(hp); | |
332 | return(NIL); | |
333 | } | |
334 | ||
335 | /* | |
336 | * Hash the passed name and return the index in | |
337 | * the hash table to begin the search. | |
338 | */ | |
339 | ||
340 | hash(name) | |
341 | char name[]; | |
342 | { | |
343 | register int h; | |
344 | register char *cp; | |
345 | ||
346 | for (cp = name, h = 0; *cp; h = (h << 2) + *cp++) | |
347 | ; | |
348 | return((h & 0x7fffffff) % HSHSIZE); | |
349 | } | |
350 | ||
351 | /* | |
352 | * Other stuff | |
353 | */ | |
354 | ||
355 | any(ch, str) | |
356 | char str[]; | |
357 | { | |
358 | register int c = ch; | |
359 | register char *cp = str; | |
360 | ||
361 | while (*cp) | |
362 | if (*cp++ == c) | |
363 | return(1); | |
364 | return(0); | |
365 | } | |
366 | ||
367 | /* | |
368 | * The qsort comparison routine. | |
369 | * The comparison is ascii collating order | |
370 | * or by feet of typesetter film, according to sort. | |
371 | */ | |
372 | ||
373 | qucmp(left, right) | |
374 | struct hent **left, **right; | |
375 | { | |
376 | register struct hent *h1, *h2; | |
377 | register int r; | |
378 | ||
379 | h1 = *left; | |
380 | h2 = *right; | |
381 | if (sort) | |
3576ded8 JB |
382 | r = h1->h_feetpages < h2->h_feetpages ? -1 : h1->h_feetpages > |
383 | h2->h_feetpages; | |
28e04fa9 RC |
384 | else |
385 | r = strcmp(h1->h_name, h2->h_name); | |
386 | return(reverse ? -r : r); | |
387 | } | |
388 | ||
389 | /* | |
390 | * Perform lookup for printer name or abbreviation -- | |
391 | */ | |
392 | chkprinter(s) | |
393 | register char *s; | |
394 | { | |
395 | static char buf[BUFSIZ/2]; | |
396 | char b[BUFSIZ]; | |
397 | int stat; | |
398 | char *bp = buf; | |
399 | ||
400 | if ((stat = pgetent(b, s)) < 0) { | |
401 | printf("pac: can't open printer description file\n"); | |
402 | exit(3); | |
403 | } else if (stat == 0) | |
404 | return(0); | |
405 | if ((acctfile = pgetstr("af", &bp)) == NULL) { | |
406 | printf("accounting not enabled for printer %s\n", printer); | |
407 | exit(2); | |
408 | } | |
3576ded8 JB |
409 | if (!pflag && (price100 = pgetnum("pc")) > 0) |
410 | price = price100/10000.0; | |
28e04fa9 RC |
411 | sumfile = (char *) calloc(sizeof(char), strlen(acctfile)+5); |
412 | if (sumfile == NULL) { | |
413 | perror("pac"); | |
414 | exit(1); | |
415 | } | |
416 | strcpy(sumfile, acctfile); | |
417 | strcat(sumfile, "_sum"); | |
418 | return(1); | |
419 | } |