1*11451Sralph /* pac.c 4.1 83/03/09 */ 2*11451Sralph /* 3*11451Sralph * Do Printer accounting summary. 4*11451Sralph * Currently, usage is 5*11451Sralph * pac [-Pprinter] [-pprice] [-s] [-r] [-c] [user ...] 6*11451Sralph * to print the usage information for the named people. 7*11451Sralph */ 8*11451Sralph 9*11451Sralph #include <stdio.h> 10*11451Sralph #include "lp.local.h" 11*11451Sralph 12*11451Sralph char *printer; /* printer name */ 13*11451Sralph char *acctfile; /* accounting file (input data) */ 14*11451Sralph char *sumfile; /* summary file */ 15*11451Sralph float price = 0.02; /* cost per page (or what ever) */ 16*11451Sralph int allflag = 1; /* Get stats on everybody */ 17*11451Sralph int sort; /* Sort by cost */ 18*11451Sralph int summarize; /* Compress accounting file */ 19*11451Sralph int reverse; /* Reverse sort order */ 20*11451Sralph int hcount; /* Count of hash entries */ 21*11451Sralph int errs; 22*11451Sralph 23*11451Sralph /* 24*11451Sralph * Grossness follows: 25*11451Sralph * Names to be accumulated are hashed into the following 26*11451Sralph * table. 27*11451Sralph */ 28*11451Sralph 29*11451Sralph #define HSHSIZE 97 /* Number of hash buckets */ 30*11451Sralph 31*11451Sralph struct hent { 32*11451Sralph struct hent *h_link; /* Forward hash link */ 33*11451Sralph char *h_name; /* Name of this user */ 34*11451Sralph float h_feetpages; /* Feet or pages of paper */ 35*11451Sralph int h_count; /* Number of runs */ 36*11451Sralph }; 37*11451Sralph 38*11451Sralph struct hent *hashtab[HSHSIZE]; /* Hash table proper */ 39*11451Sralph struct hent *enter(); 40*11451Sralph struct hent *lookup(); 41*11451Sralph 42*11451Sralph #define NIL ((struct hent *) 0) /* The big zero */ 43*11451Sralph 44*11451Sralph double atof(); 45*11451Sralph char *getenv(); 46*11451Sralph char *pgetstr(); 47*11451Sralph 48*11451Sralph main(argc, argv) 49*11451Sralph char **argv; 50*11451Sralph { 51*11451Sralph register FILE *acct; 52*11451Sralph register char *cp; 53*11451Sralph 54*11451Sralph while (--argc) { 55*11451Sralph cp = *++argv; 56*11451Sralph if (*cp++ == '-') { 57*11451Sralph switch(*cp++) { 58*11451Sralph case 'P': 59*11451Sralph /* 60*11451Sralph * Printer name. 61*11451Sralph */ 62*11451Sralph printer = cp; 63*11451Sralph continue; 64*11451Sralph 65*11451Sralph case 'p': 66*11451Sralph /* 67*11451Sralph * get the price. 68*11451Sralph */ 69*11451Sralph price = atof(cp); 70*11451Sralph continue; 71*11451Sralph 72*11451Sralph case 's': 73*11451Sralph /* 74*11451Sralph * Summarize and compress accounting file. 75*11451Sralph */ 76*11451Sralph summarize++; 77*11451Sralph continue; 78*11451Sralph 79*11451Sralph case 'c': 80*11451Sralph /* 81*11451Sralph * Sort by cost. 82*11451Sralph */ 83*11451Sralph sort++; 84*11451Sralph continue; 85*11451Sralph 86*11451Sralph case 'r': 87*11451Sralph /* 88*11451Sralph * Reverse sorting order. 89*11451Sralph */ 90*11451Sralph reverse++; 91*11451Sralph continue; 92*11451Sralph 93*11451Sralph default: 94*11451Sralph fprintf(stderr, "usage: pac [-Pprinter] [-pprice] [-s] [-c] [-r] [user ...]\n"); 95*11451Sralph exit(1); 96*11451Sralph } 97*11451Sralph } 98*11451Sralph (void) enter(--cp); 99*11451Sralph allflag = 0; 100*11451Sralph } 101*11451Sralph if (printer == NULL && (printer = getenv("PRINTER")) == NULL) 102*11451Sralph printer = DEFLP; 103*11451Sralph if (!chkprinter(printer)) { 104*11451Sralph printf("pac: unknown printer %s\n", printer); 105*11451Sralph exit(2); 106*11451Sralph } 107*11451Sralph 108*11451Sralph if ((acct = fopen(acctfile, "r")) == NULL) { 109*11451Sralph perror(acctfile); 110*11451Sralph exit(1); 111*11451Sralph } 112*11451Sralph account(acct); 113*11451Sralph fclose(acct); 114*11451Sralph if ((acct = fopen(sumfile, "r")) != NULL) { 115*11451Sralph account(acct); 116*11451Sralph fclose(acct); 117*11451Sralph } 118*11451Sralph if (summarize) 119*11451Sralph rewrite(); 120*11451Sralph else 121*11451Sralph dumpit(); 122*11451Sralph exit(errs); 123*11451Sralph } 124*11451Sralph 125*11451Sralph /* 126*11451Sralph * Read the entire accounting file, accumulating statistics 127*11451Sralph * for the users that we have in the hash table. If allflag 128*11451Sralph * is set, then just gather the facts on everyone. 129*11451Sralph * Note that we must accomodate both the active and summary file 130*11451Sralph * formats here. 131*11451Sralph */ 132*11451Sralph 133*11451Sralph account(acct) 134*11451Sralph register FILE *acct; 135*11451Sralph { 136*11451Sralph char linebuf[BUFSIZ]; 137*11451Sralph double t; 138*11451Sralph register char *cp, *cp2; 139*11451Sralph register struct hent *hp; 140*11451Sralph register int ic; 141*11451Sralph 142*11451Sralph while (fgets(linebuf, BUFSIZ, acct) != NULL) { 143*11451Sralph cp = linebuf; 144*11451Sralph while (any(*cp, " t\t")) 145*11451Sralph cp++; 146*11451Sralph t = atof(cp); 147*11451Sralph while (any(*cp, ".0123456789")) 148*11451Sralph cp++; 149*11451Sralph while (any(*cp, " \t")) 150*11451Sralph cp++; 151*11451Sralph for (cp2 = cp; !any(*cp2, " \t\n"); cp2++) 152*11451Sralph ; 153*11451Sralph ic = atoi(cp2); 154*11451Sralph *cp2 = '\0'; 155*11451Sralph hp = lookup(cp); 156*11451Sralph if (hp == NIL) { 157*11451Sralph if (!allflag) 158*11451Sralph continue; 159*11451Sralph hp = enter(cp); 160*11451Sralph } 161*11451Sralph hp->h_feetpages += t; 162*11451Sralph if (ic) 163*11451Sralph hp->h_count += ic; 164*11451Sralph else 165*11451Sralph hp->h_count++; 166*11451Sralph } 167*11451Sralph } 168*11451Sralph 169*11451Sralph /* 170*11451Sralph * Sort the hashed entries by name or footage 171*11451Sralph * and print it all out. 172*11451Sralph */ 173*11451Sralph 174*11451Sralph dumpit() 175*11451Sralph { 176*11451Sralph struct hent **base; 177*11451Sralph register struct hent *hp, **ap; 178*11451Sralph register int hno, c, runs; 179*11451Sralph float feet; 180*11451Sralph int qucmp(); 181*11451Sralph 182*11451Sralph hp = hashtab[0]; 183*11451Sralph hno = 1; 184*11451Sralph base = (struct hent **) calloc(sizeof hp, hcount); 185*11451Sralph for (ap = base, c = hcount; c--; ap++) { 186*11451Sralph while (hp == NIL) 187*11451Sralph hp = hashtab[hno++]; 188*11451Sralph *ap = hp; 189*11451Sralph hp = hp->h_link; 190*11451Sralph } 191*11451Sralph qsort(base, hcount, sizeof hp, qucmp); 192*11451Sralph printf(" Login pages/feet runs price\n"); 193*11451Sralph feet = 0.0; 194*11451Sralph runs = 0; 195*11451Sralph for (ap = base, c = hcount; c--; ap++) { 196*11451Sralph hp = *ap; 197*11451Sralph runs += hp->h_count; 198*11451Sralph feet += hp->h_feetpages; 199*11451Sralph printf("%-24s %7.2f %4d $%6.2f\n", hp->h_name, 200*11451Sralph hp->h_feetpages, hp->h_count, hp->h_feetpages * price); 201*11451Sralph } 202*11451Sralph if (allflag) { 203*11451Sralph printf("\n"); 204*11451Sralph printf("%-24s %7.2f %4d $%6.2f\n", "total", feet, 205*11451Sralph runs, feet * price); 206*11451Sralph } 207*11451Sralph } 208*11451Sralph 209*11451Sralph /* 210*11451Sralph * Rewrite the summary file with the summary information we have accumulated. 211*11451Sralph */ 212*11451Sralph 213*11451Sralph rewrite() 214*11451Sralph { 215*11451Sralph register struct hent *hp; 216*11451Sralph register int i; 217*11451Sralph register FILE *acctf; 218*11451Sralph 219*11451Sralph if ((acctf = fopen(sumfile, "w")) == NULL) { 220*11451Sralph perror(sumfile); 221*11451Sralph errs++; 222*11451Sralph return; 223*11451Sralph } 224*11451Sralph for (i = 0; i < HSHSIZE; i++) { 225*11451Sralph hp = hashtab[i]; 226*11451Sralph while (hp != NULL) { 227*11451Sralph fprintf(acctf, "%7.2f\t%s\t%d\n", hp->h_feetpages, 228*11451Sralph hp->h_name, hp->h_count); 229*11451Sralph hp = hp->h_link; 230*11451Sralph } 231*11451Sralph } 232*11451Sralph fflush(acctf); 233*11451Sralph if (ferror(acctf)) { 234*11451Sralph perror(sumfile); 235*11451Sralph errs++; 236*11451Sralph } 237*11451Sralph fclose(acctf); 238*11451Sralph if ((acctf = fopen(acctfile, "w")) == NULL) 239*11451Sralph perror(acctfile); 240*11451Sralph else 241*11451Sralph fclose(acctf); 242*11451Sralph } 243*11451Sralph 244*11451Sralph /* 245*11451Sralph * Hashing routines. 246*11451Sralph */ 247*11451Sralph 248*11451Sralph /* 249*11451Sralph * Enter the name into the hash table and return the pointer allocated. 250*11451Sralph */ 251*11451Sralph 252*11451Sralph struct hent * 253*11451Sralph enter(name) 254*11451Sralph char name[]; 255*11451Sralph { 256*11451Sralph register struct hent *hp; 257*11451Sralph register int h; 258*11451Sralph 259*11451Sralph if ((hp = lookup(name)) != NIL) 260*11451Sralph return(hp); 261*11451Sralph h = hash(name); 262*11451Sralph hcount++; 263*11451Sralph hp = (struct hent *) calloc(sizeof *hp, 1); 264*11451Sralph hp->h_name = (char *) calloc(sizeof(char), strlen(name)+1); 265*11451Sralph strcpy(hp->h_name, name); 266*11451Sralph hp->h_feetpages = 0.0; 267*11451Sralph hp->h_count = 0; 268*11451Sralph hp->h_link = hashtab[h]; 269*11451Sralph hashtab[h] = hp; 270*11451Sralph return(hp); 271*11451Sralph } 272*11451Sralph 273*11451Sralph /* 274*11451Sralph * Lookup a name in the hash table and return a pointer 275*11451Sralph * to it. 276*11451Sralph */ 277*11451Sralph 278*11451Sralph struct hent * 279*11451Sralph lookup(name) 280*11451Sralph char name[]; 281*11451Sralph { 282*11451Sralph register int h; 283*11451Sralph register struct hent *hp; 284*11451Sralph 285*11451Sralph h = hash(name); 286*11451Sralph for (hp = hashtab[h]; hp != NIL; hp = hp->h_link) 287*11451Sralph if (strcmp(hp->h_name, name) == 0) 288*11451Sralph return(hp); 289*11451Sralph return(NIL); 290*11451Sralph } 291*11451Sralph 292*11451Sralph /* 293*11451Sralph * Hash the passed name and return the index in 294*11451Sralph * the hash table to begin the search. 295*11451Sralph */ 296*11451Sralph 297*11451Sralph hash(name) 298*11451Sralph char name[]; 299*11451Sralph { 300*11451Sralph register int h; 301*11451Sralph register char *cp; 302*11451Sralph 303*11451Sralph for (cp = name, h = 0; *cp; h = (h << 2) + *cp++) 304*11451Sralph ; 305*11451Sralph return((h & 0x7fffffff) % HSHSIZE); 306*11451Sralph } 307*11451Sralph 308*11451Sralph /* 309*11451Sralph * Other stuff 310*11451Sralph */ 311*11451Sralph 312*11451Sralph any(ch, str) 313*11451Sralph char str[]; 314*11451Sralph { 315*11451Sralph register int c = ch; 316*11451Sralph register char *cp = str; 317*11451Sralph 318*11451Sralph while (*cp) 319*11451Sralph if (*cp++ == c) 320*11451Sralph return(1); 321*11451Sralph return(0); 322*11451Sralph } 323*11451Sralph 324*11451Sralph /* 325*11451Sralph * The qsort comparison routine. 326*11451Sralph * The comparison is ascii collating order 327*11451Sralph * or by feet of typesetter film, according to sort. 328*11451Sralph */ 329*11451Sralph 330*11451Sralph qucmp(left, right) 331*11451Sralph struct hent **left, **right; 332*11451Sralph { 333*11451Sralph register struct hent *h1, *h2; 334*11451Sralph register int r; 335*11451Sralph 336*11451Sralph h1 = *left; 337*11451Sralph h2 = *right; 338*11451Sralph if (sort) 339*11451Sralph r = h1->h_feetpages < h2->h_feetpages ? -1 : h1->h_feetpages > h2->h_feetpages; 340*11451Sralph else 341*11451Sralph r = strcmp(h1->h_name, h2->h_name); 342*11451Sralph return(reverse ? -r : r); 343*11451Sralph } 344*11451Sralph 345*11451Sralph /* 346*11451Sralph * Perform lookup for printer name or abbreviation -- 347*11451Sralph */ 348*11451Sralph chkprinter(s) 349*11451Sralph register char *s; 350*11451Sralph { 351*11451Sralph static char buf[BUFSIZ/2]; 352*11451Sralph char b[BUFSIZ]; 353*11451Sralph int stat; 354*11451Sralph char *bp = buf; 355*11451Sralph 356*11451Sralph if ((stat = pgetent(b, s)) < 0) { 357*11451Sralph printf("pac: can't open printer description file\n"); 358*11451Sralph exit(3); 359*11451Sralph } else if (stat == 0) 360*11451Sralph return(0); 361*11451Sralph if ((acctfile = pgetstr("af", &bp)) == NULL) { 362*11451Sralph printf("accounting not enabled for printer %s\n", printer); 363*11451Sralph exit(2); 364*11451Sralph } 365*11451Sralph sumfile = (char *) calloc(sizeof(char), strlen(acctfile)+5); 366*11451Sralph if (sumfile == NULL) { 367*11451Sralph perror("pac"); 368*11451Sralph exit(1); 369*11451Sralph } 370*11451Sralph strcpy(sumfile, acctfile); 371*11451Sralph strcat(sumfile, "_sum"); 372*11451Sralph return(1); 373*11451Sralph } 374