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