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