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