|
|
1.1 root 1: #ifndef lint
2: static char sccsid[] = "@(#)pac.c 4.2 (Berkeley) 7/17/83";
3: #endif
4:
5: /*
6: * Do Printer accounting summary.
7: * Currently, usage is
8: * pac [-Pprinter] [-pprice] [-s] [-r] [-c] [user ...]
9: * to print the usage information for the named people.
10: */
11:
12: #include <stdio.h>
13: #include "lp.local.h"
14:
15: char *printer; /* printer name */
16: char *acctfile; /* accounting file (input data) */
17: char *sumfile; /* summary file */
18: float price = 0.02; /* cost per page (or what ever) */
19: int allflag = 1; /* Get stats on everybody */
20: int sort; /* Sort by cost */
21: int summarize; /* Compress accounting file */
22: int reverse; /* Reverse sort order */
23: int hcount; /* Count of hash entries */
24: int errs;
25:
26: /*
27: * Grossness follows:
28: * Names to be accumulated are hashed into the following
29: * table.
30: */
31:
32: #define HSHSIZE 97 /* Number of hash buckets */
33:
34: struct hent {
35: struct hent *h_link; /* Forward hash link */
36: char *h_name; /* Name of this user */
37: float h_feetpages; /* Feet or pages of paper */
38: int h_count; /* Number of runs */
39: };
40:
41: struct hent *hashtab[HSHSIZE]; /* Hash table proper */
42: struct hent *enter();
43: struct hent *lookup();
44:
45: #define NIL ((struct hent *) 0) /* The big zero */
46:
47: double atof();
48: char *getenv();
49: char *pgetstr();
50:
51: main(argc, argv)
52: char **argv;
53: {
54: register FILE *acct;
55: register char *cp;
56:
57: while (--argc) {
58: cp = *++argv;
59: if (*cp++ == '-') {
60: switch(*cp++) {
61: case 'P':
62: /*
63: * Printer name.
64: */
65: printer = cp;
66: continue;
67:
68: case 'p':
69: /*
70: * get the price.
71: */
72: price = atof(cp);
73: continue;
74:
75: case 's':
76: /*
77: * Summarize and compress accounting file.
78: */
79: summarize++;
80: continue;
81:
82: case 'c':
83: /*
84: * Sort by cost.
85: */
86: sort++;
87: continue;
88:
89: case 'r':
90: /*
91: * Reverse sorting order.
92: */
93: reverse++;
94: continue;
95:
96: default:
97: fprintf(stderr, "usage: pac [-Pprinter] [-pprice] [-s] [-c] [-r] [user ...]\n");
98: exit(1);
99: }
100: }
101: (void) enter(--cp);
102: allflag = 0;
103: }
104: if (printer == NULL && (printer = getenv("PRINTER")) == NULL)
105: printer = DEFLP;
106: if (!chkprinter(printer)) {
107: printf("pac: unknown printer %s\n", printer);
108: exit(2);
109: }
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: double t;
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) {
160: if (!allflag)
161: continue;
162: hp = enter(cp);
163: }
164: hp->h_feetpages += t;
165: if (ic)
166: hp->h_count += ic;
167: else
168: hp->h_count++;
169: }
170: }
171:
172: /*
173: * Sort the hashed entries by name or footage
174: * and print it all out.
175: */
176:
177: dumpit()
178: {
179: struct hent **base;
180: register struct hent *hp, **ap;
181: register int hno, c, runs;
182: float feet;
183: int qucmp();
184:
185: hp = hashtab[0];
186: hno = 1;
187: base = (struct hent **) calloc(sizeof hp, hcount);
188: for (ap = base, c = hcount; c--; ap++) {
189: while (hp == NIL)
190: hp = hashtab[hno++];
191: *ap = hp;
192: hp = hp->h_link;
193: }
194: qsort(base, hcount, sizeof hp, qucmp);
195: printf(" Login pages/feet 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("%-24s %7.2f %4d $%6.2f\n", hp->h_name,
203: hp->h_feetpages, hp->h_count, hp->h_feetpages * price);
204: }
205: if (allflag) {
206: printf("\n");
207: printf("%-24s %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 name into the hash table and return the pointer allocated.
253: */
254:
255: struct hent *
256: enter(name)
257: char name[];
258: {
259: register struct hent *hp;
260: register int h;
261:
262: if ((hp = lookup(name)) != NIL)
263: return(hp);
264: h = hash(name);
265: hcount++;
266: hp = (struct hent *) calloc(sizeof *hp, 1);
267: hp->h_name = (char *) calloc(sizeof(char), strlen(name)+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: return((h & 0x7fffffff) % HSHSIZE);
309: }
310:
311: /*
312: * Other stuff
313: */
314:
315: any(ch, str)
316: char str[];
317: {
318: register int c = ch;
319: register char *cp = str;
320:
321: while (*cp)
322: if (*cp++ == c)
323: return(1);
324: return(0);
325: }
326:
327: /*
328: * The qsort comparison routine.
329: * The comparison is ascii collating order
330: * or by feet of typesetter film, according to sort.
331: */
332:
333: qucmp(left, right)
334: struct hent **left, **right;
335: {
336: register struct hent *h1, *h2;
337: register int r;
338:
339: h1 = *left;
340: h2 = *right;
341: if (sort)
342: r = h1->h_feetpages < h2->h_feetpages ? -1 : h1->h_feetpages > h2->h_feetpages;
343: else
344: r = strcmp(h1->h_name, h2->h_name);
345: return(reverse ? -r : r);
346: }
347:
348: /*
349: * Perform lookup for printer name or abbreviation --
350: */
351: chkprinter(s)
352: register char *s;
353: {
354: static char buf[BUFSIZ/2];
355: char b[BUFSIZ];
356: int stat;
357: char *bp = buf;
358:
359: if ((stat = pgetent(b, s)) < 0) {
360: printf("pac: can't open printer description file\n");
361: exit(3);
362: } else if (stat == 0)
363: return(0);
364: if ((acctfile = pgetstr("af", &bp)) == NULL) {
365: printf("accounting not enabled for printer %s\n", printer);
366: exit(2);
367: }
368: sumfile = (char *) calloc(sizeof(char), strlen(acctfile)+5);
369: if (sumfile == NULL) {
370: perror("pac");
371: exit(1);
372: }
373: strcpy(sumfile, acctfile);
374: strcat(sumfile, "_sum");
375: return(1);
376: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.