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