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