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