install correct aliases file
[unix-history] / usr / src / usr.sbin / lpr / pac / pac.c
CommitLineData
d0aeaf5a
DF
1/*
2 * Copyright (c) 1983 Regents of the University of California.
9d85c861
KB
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms are permitted
a399f6c8
KB
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.
d0aeaf5a
DF
16 */
17
18#ifndef lint
19char copyright[] =
20"@(#) Copyright (c) 1983 Regents of the University of California.\n\
21 All rights reserved.\n";
9d85c861 22#endif /* not lint */
d0aeaf5a 23
5f84f8f0 24#ifndef lint
a399f6c8 25static char sccsid[] = "@(#)pac.c 5.4 (Berkeley) %G%";
9d85c861 26#endif /* not lint */
5f84f8f0 27
28e04fa9
RC
28/*
29 * Do Printer accounting summary.
30 * Currently, usage is
3576ded8 31 * pac [-Pprinter] [-pprice] [-s] [-r] [-c] [-m] [user ...]
28e04fa9
RC
32 * to print the usage information for the named people.
33 */
34
35#include <stdio.h>
36#include "lp.local.h"
37
38char *printer; /* printer name */
39char *acctfile; /* accounting file (input data) */
40char *sumfile; /* summary file */
41float price = 0.02; /* cost per page (or what ever) */
42int allflag = 1; /* Get stats on everybody */
43int sort; /* Sort by cost */
44int summarize; /* Compress accounting file */
45int reverse; /* Reverse sort order */
46int hcount; /* Count of hash entries */
47int errs;
3576ded8
JB
48int mflag = 0; /* disregard machine names */
49int pflag = 0; /* 1 if -p on cmd line */
50int price100; /* per-page cost in 100th of a cent */
51char *index();
52int pgetnum();
28e04fa9
RC
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
62struct 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
69struct hent *hashtab[HSHSIZE]; /* Hash table proper */
70struct hent *enter();
71struct hent *lookup();
72
73#define NIL ((struct hent *) 0) /* The big zero */
74
75double atof();
76char *getenv();
77char *pgetstr();
78
79main(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);
3576ded8 101 pflag = 1;
28e04fa9
RC
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
3576ded8
JB
118 case 'm':
119 /*
120 * disregard machine names for each user
121 */
122 mflag = 1;
123 continue;
124
28e04fa9
RC
125 case 'r':
126 /*
127 * Reverse sorting order.
128 */
129 reverse++;
130 continue;
131
132 default:
3576ded8
JB
133fprintf(stderr,
134 "usage: pac [-Pprinter] [-pprice] [-s] [-c] [-r] [-m] [user ...]\n");
28e04fa9
RC
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.
3576ded8 171 * Host names are ignored if the -m flag is present.
28e04fa9
RC
172 */
173
174account(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';
3576ded8
JB
196 if (mflag && index(cp, ':'))
197 cp = index(cp, ':') + 1;
28e04fa9
RC
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
217dumpit()
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
256rewrite()
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
295struct hent *
296enter(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
321struct hent *
322lookup(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
340hash(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
355any(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
373qucmp(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)
3576ded8
JB
382 r = h1->h_feetpages < h2->h_feetpages ? -1 : h1->h_feetpages >
383h2->h_feetpages;
28e04fa9
RC
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 */
392chkprinter(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 }
3576ded8
JB
409 if (!pflag && (price100 = pgetnum("pc")) > 0)
410 price = price100/10000.0;
28e04fa9
RC
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}