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