|
|
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
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.
16: */
17:
18: #ifndef lint
19: char copyright[] =
20: "@(#) Copyright (c) 1983 Regents of the University of California.\n\
21: All rights reserved.\n";
22: #endif /* not lint */
23:
24: #ifndef lint
25: static char sccsid[] = "@(#)pac.c 5.4 (Berkeley) 6/30/88";
26: #endif /* not lint */
27:
28: /*
29: * Do Printer accounting summary.
30: * Currently, usage is
31: * pac [-Pprinter] [-pprice] [-s] [-r] [-c] [-m] [user ...]
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;
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();
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);
101: pflag = 1;
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:
118: case 'm':
119: /*
120: * disregard machine names for each user
121: */
122: mflag = 1;
123: continue;
124:
125: case 'r':
126: /*
127: * Reverse sorting order.
128: */
129: reverse++;
130: continue;
131:
132: default:
133: fprintf(stderr,
134: "usage: pac [-Pprinter] [-pprice] [-s] [-c] [-r] [-m] [user ...]\n");
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.
171: * Host names are ignored if the -m flag is present.
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';
196: if (mflag && index(cp, ':'))
197: cp = index(cp, ':') + 1;
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)
382: r = h1->h_feetpages < h2->h_feetpages ? -1 : h1->h_feetpages >
383: h2->h_feetpages;
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: }
409: if (!pflag && (price100 = pgetnum("pc")) > 0)
410: price = price100/10000.0;
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.