|
|
1.1 root 1: #
2:
3: #include <stdio.h>
4:
5: /*
6: * Do Versatec accounting summary.
7: * Currently, usage is
8: * vpac user ...
9: * to print the usage information for the named people.
10: */
11:
12: int errs;
13: char vpacct[] = "/usr/adm/vpacct";
14: char sumfile[] = "/usr/adm/vp_sum";
15:
16: #define PRICE 0.08 /* Dollars per foot of paper */
17:
18: /*
19: * Grossness follows:
20: * Names to be accumulated are hashed into the following
21: * table.
22: */
23:
24: #define HSHSIZE 97 /* Number of hash buckets */
25:
26: struct hent {
27: struct hent *h_link; /* Forward hash link */
28: char h_name[9]; /* Name of this user */
29: float h_feet; /* Feet of typesetter film */
30: int h_count; /* Number of runs */
31: };
32:
33: struct hent *hashtab[HSHSIZE]; /* Hash table proper */
34: struct hent *enter();
35: struct hent *lookup();
36:
37: #define NIL ((struct hent *) 0) /* The big zero */
38:
39: int allflag; /* Get stats on everybody */
40: int sort; /* Sort by cost */
41: int summarize; /* Compress accounting file */
42: int reverse; /* Reverse sort order */
43:
44: int hcount; /* Count of hash entries */
45:
46: main(argc, argv)
47: char **argv;
48: {
49: register FILE *acct;
50: register char *cp;
51: register int gotcha = 0;
52:
53: if ((acct = fopen(vpacct, "r")) == NULL) {
54: perror(vpacct);
55: exit(1);
56: }
57: if (argc >= 2)
58: while (--argc) {
59: cp = *++argv;
60: if (*cp++ == '-') {
61: while (*cp) switch(*cp++) {
62: case 's':
63: /*
64: * Summarize and compress
65: * accounting file.
66: */
67: summarize++;
68: break;
69:
70: case 't':
71: /*
72: * Sort by feet of typesetter film.
73: */
74: sort++;
75: break;
76:
77: case 'r':
78: /*
79: * Reverse sorting order.
80: */
81: reverse++;
82: break;
83:
84: default:
85: fprintf(stderr, "%s?\n", *argv);
86: exit(1);
87: }
88: continue;
89: }
90: ignore(enter(--cp));
91: gotcha++;
92: }
93: allflag = gotcha == 0;
94: account(acct);
95: fclose(acct);
96: if ((acct = fopen(sumfile, "r")) != NULL) {
97: account(acct);
98: fclose(acct);
99: }
100: if (summarize)
101: rewrite();
102: else
103: dumpit();
104: exit(errs);
105: }
106:
107: /*
108: * Read the entire accounting file, accumulating statistics
109: * for the users that we have in the hash table. If allflag
110: * is set, then just gather the facts on everyone.
111: * Note that we must accomodate both the active and summary file
112: * formats here.
113: */
114:
115: account(acct)
116: register FILE *acct;
117: {
118: char linebuf[BUFSIZ];
119: float t, atof();
120: register char *cp, *cp2;
121: register struct hent *hp;
122: register int ic;
123:
124: while (fgets(linebuf, BUFSIZ, acct) != NULL) {
125: cp = linebuf;
126: while (any(*cp, " t\t"))
127: cp++;
128: t = atof(cp);
129: while (any(*cp, ".0123456789"))
130: cp++;
131: while (any(*cp, " \t"))
132: cp++;
133: for (cp2 = cp; !any(*cp2, " \t\n"); cp2++)
134: ;
135: ic = atoi(cp2);
136: *cp2 = '\0';
137: hp = lookup(cp);
138: if (hp == NIL && !allflag)
139: continue;
140: if (hp == NIL)
141: hp = enter(cp);
142: hp->h_feet += t;
143: if (ic)
144: hp->h_count += ic;
145: else
146: hp->h_count++;
147: }
148: }
149:
150: /*
151: * Sort the hashed entries by name or footage
152: * and print it all out.
153: */
154:
155: dumpit()
156: {
157: struct hent **base;
158: register struct hent *hp, **ap;
159: register int hno, c, runs;
160: float feet;
161: int qucmp();
162:
163: hp = hashtab[0];
164: hno = 1;
165: base = (struct hent **) calloc(sizeof hp, hcount+4);
166: for (ap = base, c = hcount; c--; ap++) {
167: while (hp == NIL)
168: hp = hashtab[hno++];
169: *ap = hp;
170: hp = hp->h_link;
171: }
172: qsort(base, hcount, sizeof hp, qucmp);
173: printf(" Login feet runs price\n");
174: feet = 0.0;
175: runs = 0;
176: for (ap = base, c = hcount; c--; ap++) {
177: hp = *ap;
178: runs += hp->h_count;
179: feet += hp->h_feet;
180: printf("%-8s %7.2f %4d $%6.2f\n", hp->h_name, hp->h_feet,
181: hp->h_count, hp->h_feet * PRICE);
182: }
183: if (allflag) {
184: printf("\n");
185: printf("%-8s %7.2f %4d $%6.2f\n", "total", feet,
186: runs, feet * PRICE);
187: }
188: }
189:
190: /*
191: * Rewrite the Versatec printer summary file with the summary
192: * information we have accumulated.
193: */
194:
195: rewrite()
196: {
197: register struct hent *hp;
198: register int i;
199: register FILE *acctf;
200:
201: if ((acctf = fopen(sumfile, "w")) == NULL) {
202: perror(sumfile);
203: errs++;
204: return;
205: }
206: for (i = 0; i < HSHSIZE; i++) {
207: hp = hashtab[i];
208: while (hp != NULL) {
209: fprintf(acctf, "%7.2f\t%s\t%d\n", hp->h_feet,
210: hp->h_name, hp->h_count);
211: hp = hp->h_link;
212: }
213: }
214: fflush(acctf);
215: if (ferror(acctf)) {
216: perror(sumfile);
217: errs++;
218: }
219: fclose(acctf);
220: if ((acctf = fopen(vpacct, "w")) == NULL)
221: perror(vpacct);
222: else
223: fclose(acctf);
224: }
225:
226: /*
227: * Hashing routines.
228: */
229:
230: /*
231: * Enter the passed name into the hash table
232: * and returns the pointer allocated.
233: */
234:
235: struct hent *
236: enter(name)
237: char name[];
238: {
239: register struct hent *hp;
240: register int h;
241:
242: if ((hp = lookup(name)) != NIL)
243: return(hp);
244: h = hash(name);
245: hcount++;
246: hp = (struct hent *) calloc(sizeof *hp, 1);
247: strcpy(hp->h_name, name);
248: hp->h_feet = 0.0;
249: hp->h_count = 0;
250: hp->h_link = hashtab[h];
251: hashtab[h] = hp;
252: return(hp);
253: }
254:
255: /*
256: * Lookup a name in the hash table and return a pointer
257: * to it.
258: */
259:
260: struct hent *
261: lookup(name)
262: char name[];
263: {
264: register int h;
265: register struct hent *hp;
266:
267: h = hash(name);
268: for (hp = hashtab[h]; hp != NIL; hp = hp->h_link)
269: if (strcmp(hp->h_name, name) == 0)
270: return(hp);
271: return(NIL);
272: }
273:
274: /*
275: * Hash the passed name and return the index in
276: * the hash table to begin the search.
277: */
278:
279: hash(name)
280: char name[];
281: {
282: register int h;
283: register char *cp;
284:
285: for (cp = name, h = 0; *cp; h = (h << 2) + *cp++)
286: ;
287: if (h < 0)
288: h = -h;
289: if (h < 0)
290: h = 0;
291: return(h % HSHSIZE);
292: }
293:
294: /*
295: * Other stuff
296: */
297:
298: any(ch, str)
299: char str[];
300: {
301: register int c = ch;
302: register char *cp = str;
303:
304: while (*cp)
305: if (*cp++ == c)
306: return(1);
307: return(0);
308: }
309:
310: /*
311: * Throw away a hash pointer.
312: */
313:
314: ignore(p)
315: struct hent *p;
316: {;}
317:
318: /*
319: * The qsort comparison routine.
320: * The comparison is ascii collating order
321: * or by feet of typesetter film, according to sort.
322: */
323:
324: qucmp(left, right)
325: struct hent **left, **right;
326: {
327: register struct hent *h1, *h2;
328: register int r;
329:
330: h1 = *left;
331: h2 = *right;
332: if (sort)
333: r = h1->h_feet < h2->h_feet ? -1 : h1->h_feet > h2->h_feet;
334: else
335: r = strcmp(h1->h_name, h2->h_name);
336: return(reverse ? -r : r);
337: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.