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