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