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