1 #ifndef lint 2 static char sccsid[] = "@(#)pac.c 4.2 (Berkeley) 07/17/83"; 3 #endif 4 5 /* 6 * Do Printer accounting summary. 7 * Currently, usage is 8 * pac [-Pprinter] [-pprice] [-s] [-r] [-c] [user ...] 9 * to print the usage information for the named people. 10 */ 11 12 #include <stdio.h> 13 #include "lp.local.h" 14 15 char *printer; /* printer name */ 16 char *acctfile; /* accounting file (input data) */ 17 char *sumfile; /* summary file */ 18 float price = 0.02; /* cost per page (or what ever) */ 19 int allflag = 1; /* Get stats on everybody */ 20 int sort; /* Sort by cost */ 21 int summarize; /* Compress accounting file */ 22 int reverse; /* Reverse sort order */ 23 int hcount; /* Count of hash entries */ 24 int errs; 25 26 /* 27 * Grossness follows: 28 * Names to be accumulated are hashed into the following 29 * table. 30 */ 31 32 #define HSHSIZE 97 /* Number of hash buckets */ 33 34 struct hent { 35 struct hent *h_link; /* Forward hash link */ 36 char *h_name; /* Name of this user */ 37 float h_feetpages; /* Feet or pages of paper */ 38 int h_count; /* Number of runs */ 39 }; 40 41 struct hent *hashtab[HSHSIZE]; /* Hash table proper */ 42 struct hent *enter(); 43 struct hent *lookup(); 44 45 #define NIL ((struct hent *) 0) /* The big zero */ 46 47 double atof(); 48 char *getenv(); 49 char *pgetstr(); 50 51 main(argc, argv) 52 char **argv; 53 { 54 register FILE *acct; 55 register char *cp; 56 57 while (--argc) { 58 cp = *++argv; 59 if (*cp++ == '-') { 60 switch(*cp++) { 61 case 'P': 62 /* 63 * Printer name. 64 */ 65 printer = cp; 66 continue; 67 68 case 'p': 69 /* 70 * get the price. 71 */ 72 price = atof(cp); 73 continue; 74 75 case 's': 76 /* 77 * Summarize and compress accounting file. 78 */ 79 summarize++; 80 continue; 81 82 case 'c': 83 /* 84 * Sort by cost. 85 */ 86 sort++; 87 continue; 88 89 case 'r': 90 /* 91 * Reverse sorting order. 92 */ 93 reverse++; 94 continue; 95 96 default: 97 fprintf(stderr, "usage: pac [-Pprinter] [-pprice] [-s] [-c] [-r] [user ...]\n"); 98 exit(1); 99 } 100 } 101 (void) enter(--cp); 102 allflag = 0; 103 } 104 if (printer == NULL && (printer = getenv("PRINTER")) == NULL) 105 printer = DEFLP; 106 if (!chkprinter(printer)) { 107 printf("pac: unknown printer %s\n", printer); 108 exit(2); 109 } 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 double t; 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) { 160 if (!allflag) 161 continue; 162 hp = enter(cp); 163 } 164 hp->h_feetpages += t; 165 if (ic) 166 hp->h_count += ic; 167 else 168 hp->h_count++; 169 } 170 } 171 172 /* 173 * Sort the hashed entries by name or footage 174 * and print it all out. 175 */ 176 177 dumpit() 178 { 179 struct hent **base; 180 register struct hent *hp, **ap; 181 register int hno, c, runs; 182 float feet; 183 int qucmp(); 184 185 hp = hashtab[0]; 186 hno = 1; 187 base = (struct hent **) calloc(sizeof hp, hcount); 188 for (ap = base, c = hcount; c--; ap++) { 189 while (hp == NIL) 190 hp = hashtab[hno++]; 191 *ap = hp; 192 hp = hp->h_link; 193 } 194 qsort(base, hcount, sizeof hp, qucmp); 195 printf(" Login pages/feet 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("%-24s %7.2f %4d $%6.2f\n", hp->h_name, 203 hp->h_feetpages, hp->h_count, hp->h_feetpages * price); 204 } 205 if (allflag) { 206 printf("\n"); 207 printf("%-24s %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 name into the hash table and return the pointer allocated. 253 */ 254 255 struct hent * 256 enter(name) 257 char name[]; 258 { 259 register struct hent *hp; 260 register int h; 261 262 if ((hp = lookup(name)) != NIL) 263 return(hp); 264 h = hash(name); 265 hcount++; 266 hp = (struct hent *) calloc(sizeof *hp, 1); 267 hp->h_name = (char *) calloc(sizeof(char), strlen(name)+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 return((h & 0x7fffffff) % HSHSIZE); 309 } 310 311 /* 312 * Other stuff 313 */ 314 315 any(ch, str) 316 char str[]; 317 { 318 register int c = ch; 319 register char *cp = str; 320 321 while (*cp) 322 if (*cp++ == c) 323 return(1); 324 return(0); 325 } 326 327 /* 328 * The qsort comparison routine. 329 * The comparison is ascii collating order 330 * or by feet of typesetter film, according to sort. 331 */ 332 333 qucmp(left, right) 334 struct hent **left, **right; 335 { 336 register struct hent *h1, *h2; 337 register int r; 338 339 h1 = *left; 340 h2 = *right; 341 if (sort) 342 r = h1->h_feetpages < h2->h_feetpages ? -1 : h1->h_feetpages > h2->h_feetpages; 343 else 344 r = strcmp(h1->h_name, h2->h_name); 345 return(reverse ? -r : r); 346 } 347 348 /* 349 * Perform lookup for printer name or abbreviation -- 350 */ 351 chkprinter(s) 352 register char *s; 353 { 354 static char buf[BUFSIZ/2]; 355 char b[BUFSIZ]; 356 int stat; 357 char *bp = buf; 358 359 if ((stat = pgetent(b, s)) < 0) { 360 printf("pac: can't open printer description file\n"); 361 exit(3); 362 } else if (stat == 0) 363 return(0); 364 if ((acctfile = pgetstr("af", &bp)) == NULL) { 365 printf("accounting not enabled for printer %s\n", printer); 366 exit(2); 367 } 368 sumfile = (char *) calloc(sizeof(char), strlen(acctfile)+5); 369 if (sumfile == NULL) { 370 perror("pac"); 371 exit(1); 372 } 373 strcpy(sumfile, acctfile); 374 strcat(sumfile, "_sum"); 375 return(1); 376 } 377