122435Sdist /* 222435Sdist * Copyright (c) 1983 Regents of the University of California. 3*34203Sbostic * All rights reserved. 4*34203Sbostic * 5*34203Sbostic * Redistribution and use in source and binary forms are permitted 6*34203Sbostic * provided that this notice is preserved and that due credit is given 7*34203Sbostic * to the University of California at Berkeley. The name of the University 8*34203Sbostic * may not be used to endorse or promote products derived from this 9*34203Sbostic * software without specific prior written permission. This software 10*34203Sbostic * is provided ``as is'' without express or implied warranty. 1122435Sdist */ 1222435Sdist 1313954Ssam #ifndef lint 1422435Sdist char copyright[] = 1522435Sdist "@(#) Copyright (c) 1983 Regents of the University of California.\n\ 1622435Sdist All rights reserved.\n"; 17*34203Sbostic #endif /* not lint */ 1813954Ssam 1922435Sdist #ifndef lint 20*34203Sbostic static char sccsid[] = "@(#)pac.c 5.3 (Berkeley) 05/05/88"; 21*34203Sbostic #endif /* not lint */ 2222435Sdist 2311451Sralph /* 2411451Sralph * Do Printer accounting summary. 2511451Sralph * Currently, usage is 2625337Sbloom * pac [-Pprinter] [-pprice] [-s] [-r] [-c] [-m] [user ...] 2711451Sralph * to print the usage information for the named people. 2811451Sralph */ 2911451Sralph 3011451Sralph #include <stdio.h> 3111451Sralph #include "lp.local.h" 3211451Sralph 3311451Sralph char *printer; /* printer name */ 3411451Sralph char *acctfile; /* accounting file (input data) */ 3511451Sralph char *sumfile; /* summary file */ 3611451Sralph float price = 0.02; /* cost per page (or what ever) */ 3711451Sralph int allflag = 1; /* Get stats on everybody */ 3811451Sralph int sort; /* Sort by cost */ 3911451Sralph int summarize; /* Compress accounting file */ 4011451Sralph int reverse; /* Reverse sort order */ 4111451Sralph int hcount; /* Count of hash entries */ 4211451Sralph int errs; 4325337Sbloom int mflag = 0; /* disregard machine names */ 4425337Sbloom int pflag = 0; /* 1 if -p on cmd line */ 4525337Sbloom int price100; /* per-page cost in 100th of a cent */ 4625337Sbloom char *index(); 4725337Sbloom int pgetnum(); 4811451Sralph 4911451Sralph /* 5011451Sralph * Grossness follows: 5111451Sralph * Names to be accumulated are hashed into the following 5211451Sralph * table. 5311451Sralph */ 5411451Sralph 5511451Sralph #define HSHSIZE 97 /* Number of hash buckets */ 5611451Sralph 5711451Sralph struct hent { 5811451Sralph struct hent *h_link; /* Forward hash link */ 5911451Sralph char *h_name; /* Name of this user */ 6011451Sralph float h_feetpages; /* Feet or pages of paper */ 6111451Sralph int h_count; /* Number of runs */ 6211451Sralph }; 6311451Sralph 6411451Sralph struct hent *hashtab[HSHSIZE]; /* Hash table proper */ 6511451Sralph struct hent *enter(); 6611451Sralph struct hent *lookup(); 6711451Sralph 6811451Sralph #define NIL ((struct hent *) 0) /* The big zero */ 6911451Sralph 7011451Sralph double atof(); 7111451Sralph char *getenv(); 7211451Sralph char *pgetstr(); 7311451Sralph 7411451Sralph main(argc, argv) 7511451Sralph char **argv; 7611451Sralph { 7711451Sralph register FILE *acct; 7811451Sralph register char *cp; 7911451Sralph 8011451Sralph while (--argc) { 8111451Sralph cp = *++argv; 8211451Sralph if (*cp++ == '-') { 8311451Sralph switch(*cp++) { 8411451Sralph case 'P': 8511451Sralph /* 8611451Sralph * Printer name. 8711451Sralph */ 8811451Sralph printer = cp; 8911451Sralph continue; 9011451Sralph 9111451Sralph case 'p': 9211451Sralph /* 9311451Sralph * get the price. 9411451Sralph */ 9511451Sralph price = atof(cp); 9625337Sbloom pflag = 1; 9711451Sralph continue; 9811451Sralph 9911451Sralph case 's': 10011451Sralph /* 10111451Sralph * Summarize and compress accounting file. 10211451Sralph */ 10311451Sralph summarize++; 10411451Sralph continue; 10511451Sralph 10611451Sralph case 'c': 10711451Sralph /* 10811451Sralph * Sort by cost. 10911451Sralph */ 11011451Sralph sort++; 11111451Sralph continue; 11211451Sralph 11325337Sbloom case 'm': 11425337Sbloom /* 11525337Sbloom * disregard machine names for each user 11625337Sbloom */ 11725337Sbloom mflag = 1; 11825337Sbloom continue; 11925337Sbloom 12011451Sralph case 'r': 12111451Sralph /* 12211451Sralph * Reverse sorting order. 12311451Sralph */ 12411451Sralph reverse++; 12511451Sralph continue; 12611451Sralph 12711451Sralph default: 12825337Sbloom fprintf(stderr, 12925337Sbloom "usage: pac [-Pprinter] [-pprice] [-s] [-c] [-r] [-m] [user ...]\n"); 13011451Sralph exit(1); 13111451Sralph } 13211451Sralph } 13311451Sralph (void) enter(--cp); 13411451Sralph allflag = 0; 13511451Sralph } 13611451Sralph if (printer == NULL && (printer = getenv("PRINTER")) == NULL) 13711451Sralph printer = DEFLP; 13811451Sralph if (!chkprinter(printer)) { 13911451Sralph printf("pac: unknown printer %s\n", printer); 14011451Sralph exit(2); 14111451Sralph } 14211451Sralph 14311451Sralph if ((acct = fopen(acctfile, "r")) == NULL) { 14411451Sralph perror(acctfile); 14511451Sralph exit(1); 14611451Sralph } 14711451Sralph account(acct); 14811451Sralph fclose(acct); 14911451Sralph if ((acct = fopen(sumfile, "r")) != NULL) { 15011451Sralph account(acct); 15111451Sralph fclose(acct); 15211451Sralph } 15311451Sralph if (summarize) 15411451Sralph rewrite(); 15511451Sralph else 15611451Sralph dumpit(); 15711451Sralph exit(errs); 15811451Sralph } 15911451Sralph 16011451Sralph /* 16111451Sralph * Read the entire accounting file, accumulating statistics 16211451Sralph * for the users that we have in the hash table. If allflag 16311451Sralph * is set, then just gather the facts on everyone. 16411451Sralph * Note that we must accomodate both the active and summary file 16511451Sralph * formats here. 16625337Sbloom * Host names are ignored if the -m flag is present. 16711451Sralph */ 16811451Sralph 16911451Sralph account(acct) 17011451Sralph register FILE *acct; 17111451Sralph { 17211451Sralph char linebuf[BUFSIZ]; 17311451Sralph double t; 17411451Sralph register char *cp, *cp2; 17511451Sralph register struct hent *hp; 17611451Sralph register int ic; 17711451Sralph 17811451Sralph while (fgets(linebuf, BUFSIZ, acct) != NULL) { 17911451Sralph cp = linebuf; 18011451Sralph while (any(*cp, " t\t")) 18111451Sralph cp++; 18211451Sralph t = atof(cp); 18311451Sralph while (any(*cp, ".0123456789")) 18411451Sralph cp++; 18511451Sralph while (any(*cp, " \t")) 18611451Sralph cp++; 18711451Sralph for (cp2 = cp; !any(*cp2, " \t\n"); cp2++) 18811451Sralph ; 18911451Sralph ic = atoi(cp2); 19011451Sralph *cp2 = '\0'; 19125337Sbloom if (mflag && index(cp, ':')) 19225337Sbloom cp = index(cp, ':') + 1; 19311451Sralph hp = lookup(cp); 19411451Sralph if (hp == NIL) { 19511451Sralph if (!allflag) 19611451Sralph continue; 19711451Sralph hp = enter(cp); 19811451Sralph } 19911451Sralph hp->h_feetpages += t; 20011451Sralph if (ic) 20111451Sralph hp->h_count += ic; 20211451Sralph else 20311451Sralph hp->h_count++; 20411451Sralph } 20511451Sralph } 20611451Sralph 20711451Sralph /* 20811451Sralph * Sort the hashed entries by name or footage 20911451Sralph * and print it all out. 21011451Sralph */ 21111451Sralph 21211451Sralph dumpit() 21311451Sralph { 21411451Sralph struct hent **base; 21511451Sralph register struct hent *hp, **ap; 21611451Sralph register int hno, c, runs; 21711451Sralph float feet; 21811451Sralph int qucmp(); 21911451Sralph 22011451Sralph hp = hashtab[0]; 22111451Sralph hno = 1; 22211451Sralph base = (struct hent **) calloc(sizeof hp, hcount); 22311451Sralph for (ap = base, c = hcount; c--; ap++) { 22411451Sralph while (hp == NIL) 22511451Sralph hp = hashtab[hno++]; 22611451Sralph *ap = hp; 22711451Sralph hp = hp->h_link; 22811451Sralph } 22911451Sralph qsort(base, hcount, sizeof hp, qucmp); 23011451Sralph printf(" Login pages/feet runs price\n"); 23111451Sralph feet = 0.0; 23211451Sralph runs = 0; 23311451Sralph for (ap = base, c = hcount; c--; ap++) { 23411451Sralph hp = *ap; 23511451Sralph runs += hp->h_count; 23611451Sralph feet += hp->h_feetpages; 23711451Sralph printf("%-24s %7.2f %4d $%6.2f\n", hp->h_name, 23811451Sralph hp->h_feetpages, hp->h_count, hp->h_feetpages * price); 23911451Sralph } 24011451Sralph if (allflag) { 24111451Sralph printf("\n"); 24211451Sralph printf("%-24s %7.2f %4d $%6.2f\n", "total", feet, 24311451Sralph runs, feet * price); 24411451Sralph } 24511451Sralph } 24611451Sralph 24711451Sralph /* 24811451Sralph * Rewrite the summary file with the summary information we have accumulated. 24911451Sralph */ 25011451Sralph 25111451Sralph rewrite() 25211451Sralph { 25311451Sralph register struct hent *hp; 25411451Sralph register int i; 25511451Sralph register FILE *acctf; 25611451Sralph 25711451Sralph if ((acctf = fopen(sumfile, "w")) == NULL) { 25811451Sralph perror(sumfile); 25911451Sralph errs++; 26011451Sralph return; 26111451Sralph } 26211451Sralph for (i = 0; i < HSHSIZE; i++) { 26311451Sralph hp = hashtab[i]; 26411451Sralph while (hp != NULL) { 26511451Sralph fprintf(acctf, "%7.2f\t%s\t%d\n", hp->h_feetpages, 26611451Sralph hp->h_name, hp->h_count); 26711451Sralph hp = hp->h_link; 26811451Sralph } 26911451Sralph } 27011451Sralph fflush(acctf); 27111451Sralph if (ferror(acctf)) { 27211451Sralph perror(sumfile); 27311451Sralph errs++; 27411451Sralph } 27511451Sralph fclose(acctf); 27611451Sralph if ((acctf = fopen(acctfile, "w")) == NULL) 27711451Sralph perror(acctfile); 27811451Sralph else 27911451Sralph fclose(acctf); 28011451Sralph } 28111451Sralph 28211451Sralph /* 28311451Sralph * Hashing routines. 28411451Sralph */ 28511451Sralph 28611451Sralph /* 28711451Sralph * Enter the name into the hash table and return the pointer allocated. 28811451Sralph */ 28911451Sralph 29011451Sralph struct hent * 29111451Sralph enter(name) 29211451Sralph char name[]; 29311451Sralph { 29411451Sralph register struct hent *hp; 29511451Sralph register int h; 29611451Sralph 29711451Sralph if ((hp = lookup(name)) != NIL) 29811451Sralph return(hp); 29911451Sralph h = hash(name); 30011451Sralph hcount++; 30111451Sralph hp = (struct hent *) calloc(sizeof *hp, 1); 30211451Sralph hp->h_name = (char *) calloc(sizeof(char), strlen(name)+1); 30311451Sralph strcpy(hp->h_name, name); 30411451Sralph hp->h_feetpages = 0.0; 30511451Sralph hp->h_count = 0; 30611451Sralph hp->h_link = hashtab[h]; 30711451Sralph hashtab[h] = hp; 30811451Sralph return(hp); 30911451Sralph } 31011451Sralph 31111451Sralph /* 31211451Sralph * Lookup a name in the hash table and return a pointer 31311451Sralph * to it. 31411451Sralph */ 31511451Sralph 31611451Sralph struct hent * 31711451Sralph lookup(name) 31811451Sralph char name[]; 31911451Sralph { 32011451Sralph register int h; 32111451Sralph register struct hent *hp; 32211451Sralph 32311451Sralph h = hash(name); 32411451Sralph for (hp = hashtab[h]; hp != NIL; hp = hp->h_link) 32511451Sralph if (strcmp(hp->h_name, name) == 0) 32611451Sralph return(hp); 32711451Sralph return(NIL); 32811451Sralph } 32911451Sralph 33011451Sralph /* 33111451Sralph * Hash the passed name and return the index in 33211451Sralph * the hash table to begin the search. 33311451Sralph */ 33411451Sralph 33511451Sralph hash(name) 33611451Sralph char name[]; 33711451Sralph { 33811451Sralph register int h; 33911451Sralph register char *cp; 34011451Sralph 34111451Sralph for (cp = name, h = 0; *cp; h = (h << 2) + *cp++) 34211451Sralph ; 34311451Sralph return((h & 0x7fffffff) % HSHSIZE); 34411451Sralph } 34511451Sralph 34611451Sralph /* 34711451Sralph * Other stuff 34811451Sralph */ 34911451Sralph 35011451Sralph any(ch, str) 35111451Sralph char str[]; 35211451Sralph { 35311451Sralph register int c = ch; 35411451Sralph register char *cp = str; 35511451Sralph 35611451Sralph while (*cp) 35711451Sralph if (*cp++ == c) 35811451Sralph return(1); 35911451Sralph return(0); 36011451Sralph } 36111451Sralph 36211451Sralph /* 36311451Sralph * The qsort comparison routine. 36411451Sralph * The comparison is ascii collating order 36511451Sralph * or by feet of typesetter film, according to sort. 36611451Sralph */ 36711451Sralph 36811451Sralph qucmp(left, right) 36911451Sralph struct hent **left, **right; 37011451Sralph { 37111451Sralph register struct hent *h1, *h2; 37211451Sralph register int r; 37311451Sralph 37411451Sralph h1 = *left; 37511451Sralph h2 = *right; 37611451Sralph if (sort) 37725337Sbloom r = h1->h_feetpages < h2->h_feetpages ? -1 : h1->h_feetpages > 37825337Sbloom h2->h_feetpages; 37911451Sralph else 38011451Sralph r = strcmp(h1->h_name, h2->h_name); 38111451Sralph return(reverse ? -r : r); 38211451Sralph } 38311451Sralph 38411451Sralph /* 38511451Sralph * Perform lookup for printer name or abbreviation -- 38611451Sralph */ 38711451Sralph chkprinter(s) 38811451Sralph register char *s; 38911451Sralph { 39011451Sralph static char buf[BUFSIZ/2]; 39111451Sralph char b[BUFSIZ]; 39211451Sralph int stat; 39311451Sralph char *bp = buf; 39411451Sralph 39511451Sralph if ((stat = pgetent(b, s)) < 0) { 39611451Sralph printf("pac: can't open printer description file\n"); 39711451Sralph exit(3); 39811451Sralph } else if (stat == 0) 39911451Sralph return(0); 40011451Sralph if ((acctfile = pgetstr("af", &bp)) == NULL) { 40111451Sralph printf("accounting not enabled for printer %s\n", printer); 40211451Sralph exit(2); 40311451Sralph } 40425337Sbloom if (!pflag && (price100 = pgetnum("pc")) > 0) 40525337Sbloom price = price100/10000.0; 40611451Sralph sumfile = (char *) calloc(sizeof(char), strlen(acctfile)+5); 40711451Sralph if (sumfile == NULL) { 40811451Sralph perror("pac"); 40911451Sralph exit(1); 41011451Sralph } 41111451Sralph strcpy(sumfile, acctfile); 41211451Sralph strcat(sumfile, "_sum"); 41311451Sralph return(1); 41411451Sralph } 415