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