1 static char sccsid[] = "@(#)vpac.c 1.2 (Berkeley) 08/08/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 } 359