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