122435Sdist /* 222435Sdist * Copyright (c) 1983 Regents of the University of California. 334203Sbostic * All rights reserved. 434203Sbostic * 542803Sbostic * %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*55478Sbostic static char sccsid[] = "@(#)pac.c 5.6 (Berkeley) 07/21/92"; 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 25*55478Sbostic #include <sys/param.h> 26*55478Sbostic 27*55478Sbostic #include <dirent.h> 28*55478Sbostic #include <stdlib.h> 2911451Sralph #include <stdio.h> 30*55478Sbostic #include <string.h> 31*55478Sbostic #include "lp.h" 3211451Sralph #include "lp.local.h" 3311451Sralph 3411451Sralph char *printer; /* printer name */ 3511451Sralph char *acctfile; /* accounting file (input data) */ 3611451Sralph char *sumfile; /* summary file */ 3711451Sralph float price = 0.02; /* cost per page (or what ever) */ 3811451Sralph int allflag = 1; /* Get stats on everybody */ 3911451Sralph int sort; /* Sort by cost */ 4011451Sralph int summarize; /* Compress accounting file */ 4111451Sralph int reverse; /* Reverse sort order */ 4211451Sralph int hcount; /* Count of hash entries */ 4311451Sralph int errs; 4425337Sbloom int mflag = 0; /* disregard machine names */ 4525337Sbloom int pflag = 0; /* 1 if -p on cmd line */ 4625337Sbloom int price100; /* per-page cost in 100th of a cent */ 4711451Sralph 4811451Sralph /* 4911451Sralph * Grossness follows: 5011451Sralph * Names to be accumulated are hashed into the following 5111451Sralph * table. 5211451Sralph */ 5311451Sralph 5411451Sralph #define HSHSIZE 97 /* Number of hash buckets */ 5511451Sralph 5611451Sralph struct hent { 5711451Sralph struct hent *h_link; /* Forward hash link */ 5811451Sralph char *h_name; /* Name of this user */ 5911451Sralph float h_feetpages; /* Feet or pages of paper */ 6011451Sralph int h_count; /* Number of runs */ 6111451Sralph }; 6211451Sralph 6311451Sralph struct hent *hashtab[HSHSIZE]; /* Hash table proper */ 6411451Sralph 65*55478Sbostic int account __P((FILE *)); 66*55478Sbostic int any __P((int, char [])); 67*55478Sbostic int chkprinter __P((char *)); 68*55478Sbostic void dumpit __P((void)); 69*55478Sbostic int hash __P((char [])); 70*55478Sbostic struct hent *enter __P((char [])); 71*55478Sbostic struct hent *lookup __P((char [])); 72*55478Sbostic int qucmp __P((const void *, const void *)); 73*55478Sbostic void rewrite __P((void)); 7411451Sralph 75*55478Sbostic int 7611451Sralph main(argc, argv) 77*55478Sbostic int argc; 7811451Sralph char **argv; 7911451Sralph { 8011451Sralph register FILE *acct; 8111451Sralph register char *cp; 8211451Sralph 8311451Sralph while (--argc) { 8411451Sralph cp = *++argv; 8511451Sralph if (*cp++ == '-') { 8611451Sralph switch(*cp++) { 8711451Sralph case 'P': 8811451Sralph /* 8911451Sralph * Printer name. 9011451Sralph */ 9111451Sralph printer = cp; 9211451Sralph continue; 9311451Sralph 9411451Sralph case 'p': 9511451Sralph /* 9611451Sralph * get the price. 9711451Sralph */ 9811451Sralph price = atof(cp); 9925337Sbloom pflag = 1; 10011451Sralph continue; 10111451Sralph 10211451Sralph case 's': 10311451Sralph /* 10411451Sralph * Summarize and compress accounting file. 10511451Sralph */ 10611451Sralph summarize++; 10711451Sralph continue; 10811451Sralph 10911451Sralph case 'c': 11011451Sralph /* 11111451Sralph * Sort by cost. 11211451Sralph */ 11311451Sralph sort++; 11411451Sralph continue; 11511451Sralph 11625337Sbloom case 'm': 11725337Sbloom /* 11825337Sbloom * disregard machine names for each user 11925337Sbloom */ 12025337Sbloom mflag = 1; 12125337Sbloom continue; 12225337Sbloom 12311451Sralph case 'r': 12411451Sralph /* 12511451Sralph * Reverse sorting order. 12611451Sralph */ 12711451Sralph reverse++; 12811451Sralph continue; 12911451Sralph 13011451Sralph default: 13125337Sbloom fprintf(stderr, 13225337Sbloom "usage: pac [-Pprinter] [-pprice] [-s] [-c] [-r] [-m] [user ...]\n"); 13311451Sralph exit(1); 13411451Sralph } 13511451Sralph } 13611451Sralph (void) enter(--cp); 13711451Sralph allflag = 0; 13811451Sralph } 13911451Sralph if (printer == NULL && (printer = getenv("PRINTER")) == NULL) 14011451Sralph printer = DEFLP; 14111451Sralph if (!chkprinter(printer)) { 14211451Sralph printf("pac: unknown printer %s\n", printer); 14311451Sralph exit(2); 14411451Sralph } 14511451Sralph 14611451Sralph if ((acct = fopen(acctfile, "r")) == NULL) { 14711451Sralph perror(acctfile); 14811451Sralph exit(1); 14911451Sralph } 15011451Sralph account(acct); 15111451Sralph fclose(acct); 15211451Sralph if ((acct = fopen(sumfile, "r")) != NULL) { 15311451Sralph account(acct); 15411451Sralph fclose(acct); 15511451Sralph } 15611451Sralph if (summarize) 15711451Sralph rewrite(); 15811451Sralph else 15911451Sralph dumpit(); 16011451Sralph exit(errs); 16111451Sralph } 16211451Sralph 16311451Sralph /* 16411451Sralph * Read the entire accounting file, accumulating statistics 16511451Sralph * for the users that we have in the hash table. If allflag 16611451Sralph * is set, then just gather the facts on everyone. 16711451Sralph * Note that we must accomodate both the active and summary file 16811451Sralph * formats here. 16925337Sbloom * Host names are ignored if the -m flag is present. 17011451Sralph */ 171*55478Sbostic int 17211451Sralph account(acct) 17311451Sralph register FILE *acct; 17411451Sralph { 17511451Sralph char linebuf[BUFSIZ]; 17611451Sralph double t; 17711451Sralph register char *cp, *cp2; 17811451Sralph register struct hent *hp; 17911451Sralph register int ic; 18011451Sralph 18111451Sralph while (fgets(linebuf, BUFSIZ, acct) != NULL) { 18211451Sralph cp = linebuf; 18311451Sralph while (any(*cp, " t\t")) 18411451Sralph cp++; 18511451Sralph t = atof(cp); 18611451Sralph while (any(*cp, ".0123456789")) 18711451Sralph cp++; 18811451Sralph while (any(*cp, " \t")) 18911451Sralph cp++; 19011451Sralph for (cp2 = cp; !any(*cp2, " \t\n"); cp2++) 19111451Sralph ; 19211451Sralph ic = atoi(cp2); 19311451Sralph *cp2 = '\0'; 19425337Sbloom if (mflag && index(cp, ':')) 19525337Sbloom cp = index(cp, ':') + 1; 19611451Sralph hp = lookup(cp); 197*55478Sbostic if (hp == NULL) { 19811451Sralph if (!allflag) 19911451Sralph continue; 20011451Sralph hp = enter(cp); 20111451Sralph } 20211451Sralph hp->h_feetpages += t; 20311451Sralph if (ic) 20411451Sralph hp->h_count += ic; 20511451Sralph else 20611451Sralph hp->h_count++; 20711451Sralph } 20811451Sralph } 20911451Sralph 21011451Sralph /* 21111451Sralph * Sort the hashed entries by name or footage 21211451Sralph * and print it all out. 21311451Sralph */ 214*55478Sbostic void 21511451Sralph dumpit() 21611451Sralph { 21711451Sralph struct hent **base; 21811451Sralph register struct hent *hp, **ap; 21911451Sralph register int hno, c, runs; 22011451Sralph float feet; 22111451Sralph 22211451Sralph hp = hashtab[0]; 22311451Sralph hno = 1; 22411451Sralph base = (struct hent **) calloc(sizeof hp, hcount); 22511451Sralph for (ap = base, c = hcount; c--; ap++) { 226*55478Sbostic while (hp == NULL) 22711451Sralph hp = hashtab[hno++]; 22811451Sralph *ap = hp; 22911451Sralph hp = hp->h_link; 23011451Sralph } 23111451Sralph qsort(base, hcount, sizeof hp, qucmp); 23211451Sralph printf(" Login pages/feet runs price\n"); 23311451Sralph feet = 0.0; 23411451Sralph runs = 0; 23511451Sralph for (ap = base, c = hcount; c--; ap++) { 23611451Sralph hp = *ap; 23711451Sralph runs += hp->h_count; 23811451Sralph feet += hp->h_feetpages; 23911451Sralph printf("%-24s %7.2f %4d $%6.2f\n", hp->h_name, 24011451Sralph hp->h_feetpages, hp->h_count, hp->h_feetpages * price); 24111451Sralph } 24211451Sralph if (allflag) { 24311451Sralph printf("\n"); 24411451Sralph printf("%-24s %7.2f %4d $%6.2f\n", "total", feet, 24511451Sralph runs, feet * price); 24611451Sralph } 24711451Sralph } 24811451Sralph 24911451Sralph /* 25011451Sralph * Rewrite the summary file with the summary information we have accumulated. 25111451Sralph */ 252*55478Sbostic void 25311451Sralph rewrite() 25411451Sralph { 25511451Sralph register struct hent *hp; 25611451Sralph register int i; 25711451Sralph register FILE *acctf; 25811451Sralph 25911451Sralph if ((acctf = fopen(sumfile, "w")) == NULL) { 26011451Sralph perror(sumfile); 26111451Sralph errs++; 26211451Sralph return; 26311451Sralph } 26411451Sralph for (i = 0; i < HSHSIZE; i++) { 26511451Sralph hp = hashtab[i]; 26611451Sralph while (hp != NULL) { 26711451Sralph fprintf(acctf, "%7.2f\t%s\t%d\n", hp->h_feetpages, 26811451Sralph hp->h_name, hp->h_count); 26911451Sralph hp = hp->h_link; 27011451Sralph } 27111451Sralph } 27211451Sralph fflush(acctf); 27311451Sralph if (ferror(acctf)) { 27411451Sralph perror(sumfile); 27511451Sralph errs++; 27611451Sralph } 27711451Sralph fclose(acctf); 27811451Sralph if ((acctf = fopen(acctfile, "w")) == NULL) 27911451Sralph perror(acctfile); 28011451Sralph else 28111451Sralph fclose(acctf); 28211451Sralph } 28311451Sralph 28411451Sralph /* 28511451Sralph * Hashing routines. 28611451Sralph */ 28711451Sralph 28811451Sralph /* 28911451Sralph * Enter the name into the hash table and return the pointer allocated. 29011451Sralph */ 29111451Sralph 29211451Sralph struct hent * 29311451Sralph enter(name) 29411451Sralph char name[]; 29511451Sralph { 29611451Sralph register struct hent *hp; 29711451Sralph register int h; 29811451Sralph 299*55478Sbostic if ((hp = lookup(name)) != NULL) 30011451Sralph return(hp); 30111451Sralph h = hash(name); 30211451Sralph hcount++; 30311451Sralph hp = (struct hent *) calloc(sizeof *hp, 1); 30411451Sralph hp->h_name = (char *) calloc(sizeof(char), strlen(name)+1); 30511451Sralph strcpy(hp->h_name, name); 30611451Sralph hp->h_feetpages = 0.0; 30711451Sralph hp->h_count = 0; 30811451Sralph hp->h_link = hashtab[h]; 30911451Sralph hashtab[h] = hp; 31011451Sralph return(hp); 31111451Sralph } 31211451Sralph 31311451Sralph /* 31411451Sralph * Lookup a name in the hash table and return a pointer 31511451Sralph * to it. 31611451Sralph */ 31711451Sralph 31811451Sralph struct hent * 31911451Sralph lookup(name) 32011451Sralph char name[]; 32111451Sralph { 32211451Sralph register int h; 32311451Sralph register struct hent *hp; 32411451Sralph 32511451Sralph h = hash(name); 326*55478Sbostic for (hp = hashtab[h]; hp != NULL; hp = hp->h_link) 32711451Sralph if (strcmp(hp->h_name, name) == 0) 32811451Sralph return(hp); 329*55478Sbostic return(NULL); 33011451Sralph } 33111451Sralph 33211451Sralph /* 33311451Sralph * Hash the passed name and return the index in 33411451Sralph * the hash table to begin the search. 33511451Sralph */ 336*55478Sbostic int 33711451Sralph hash(name) 33811451Sralph char name[]; 33911451Sralph { 34011451Sralph register int h; 34111451Sralph register char *cp; 34211451Sralph 34311451Sralph for (cp = name, h = 0; *cp; h = (h << 2) + *cp++) 34411451Sralph ; 34511451Sralph return((h & 0x7fffffff) % HSHSIZE); 34611451Sralph } 34711451Sralph 34811451Sralph /* 34911451Sralph * Other stuff 35011451Sralph */ 351*55478Sbostic int 35211451Sralph any(ch, str) 353*55478Sbostic int ch; 35411451Sralph char str[]; 35511451Sralph { 35611451Sralph register int c = ch; 35711451Sralph register char *cp = str; 35811451Sralph 35911451Sralph while (*cp) 36011451Sralph if (*cp++ == c) 36111451Sralph return(1); 36211451Sralph return(0); 36311451Sralph } 36411451Sralph 36511451Sralph /* 36611451Sralph * The qsort comparison routine. 36711451Sralph * The comparison is ascii collating order 36811451Sralph * or by feet of typesetter film, according to sort. 36911451Sralph */ 370*55478Sbostic int 371*55478Sbostic qucmp(a, b) 372*55478Sbostic const void *a, *b; 37311451Sralph { 37411451Sralph register struct hent *h1, *h2; 37511451Sralph register int r; 37611451Sralph 377*55478Sbostic h1 = *(struct hent **)a; 378*55478Sbostic h2 = *(struct hent **)b; 37911451Sralph if (sort) 380*55478Sbostic r = h1->h_feetpages < h2->h_feetpages ? 381*55478Sbostic -1 : h1->h_feetpages > h2->h_feetpages; 38211451Sralph else 38311451Sralph r = strcmp(h1->h_name, h2->h_name); 38411451Sralph return(reverse ? -r : r); 38511451Sralph } 38611451Sralph 38711451Sralph /* 38811451Sralph * Perform lookup for printer name or abbreviation -- 38911451Sralph */ 390*55478Sbostic int 39111451Sralph chkprinter(s) 39211451Sralph register char *s; 39311451Sralph { 39411451Sralph static char buf[BUFSIZ/2]; 39511451Sralph char b[BUFSIZ]; 39611451Sralph int stat; 39711451Sralph char *bp = buf; 39811451Sralph 39911451Sralph if ((stat = pgetent(b, s)) < 0) { 40011451Sralph printf("pac: can't open printer description file\n"); 40111451Sralph exit(3); 40211451Sralph } else if (stat == 0) 40311451Sralph return(0); 40411451Sralph if ((acctfile = pgetstr("af", &bp)) == NULL) { 40511451Sralph printf("accounting not enabled for printer %s\n", printer); 40611451Sralph exit(2); 40711451Sralph } 40825337Sbloom if (!pflag && (price100 = pgetnum("pc")) > 0) 40925337Sbloom price = price100/10000.0; 41011451Sralph sumfile = (char *) calloc(sizeof(char), strlen(acctfile)+5); 41111451Sralph if (sumfile == NULL) { 41211451Sralph perror("pac"); 41311451Sralph exit(1); 41411451Sralph } 41511451Sralph strcpy(sumfile, acctfile); 41611451Sralph strcat(sumfile, "_sum"); 41711451Sralph return(1); 41811451Sralph } 419