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