home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / usr.sbin / lpr / pac / pac.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-19  |  9.3 KB  |  436 lines

  1. /*
  2.  * Copyright (c) 1983 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. #ifndef lint
  35. char copyright[] =
  36. "@(#) Copyright (c) 1983 Regents of the University of California.\n\
  37.  All rights reserved.\n";
  38. #endif /* not lint */
  39.  
  40. #ifndef lint
  41. static char sccsid[] = "@(#)pac.c    5.5 (Berkeley) 6/1/90";
  42. #endif /* not lint */
  43.  
  44. /*
  45.  * Do Printer accounting summary.
  46.  * Currently, usage is
  47.  *    pac [-Pprinter] [-pprice] [-s] [-r] [-c] [-m] [user ...]
  48.  * to print the usage information for the named people.
  49.  */
  50.  
  51. #include <stdio.h>
  52. #include "lp.local.h"
  53.  
  54. char    *printer;            /* printer name */
  55. char    *acctfile;            /* accounting file (input data) */
  56. char    *sumfile;            /* summary file */
  57. float    price = 0.02;            /* cost per page (or what ever) */
  58. int    allflag = 1;            /* Get stats on everybody */
  59. int    sort;                /* Sort by cost */
  60. int    summarize;            /* Compress accounting file */
  61. int    reverse;            /* Reverse sort order */
  62. int    hcount;                /* Count of hash entries */
  63. int    errs;
  64. int    mflag = 0;            /* disregard machine names */
  65. int    pflag = 0;            /* 1 if -p on cmd line */
  66. int    price100;            /* per-page cost in 100th of a cent */
  67. char    *index();
  68. int    pgetnum();
  69.  
  70. /*
  71.  * Grossness follows:
  72.  *  Names to be accumulated are hashed into the following
  73.  *  table.
  74.  */
  75.  
  76. #define    HSHSIZE    97            /* Number of hash buckets */
  77.  
  78. struct hent {
  79.     struct    hent *h_link;        /* Forward hash link */
  80.     char    *h_name;        /* Name of this user */
  81.     float    h_feetpages;        /* Feet or pages of paper */
  82.     int    h_count;        /* Number of runs */
  83. };
  84.  
  85. struct    hent    *hashtab[HSHSIZE];    /* Hash table proper */
  86. struct    hent    *enter();
  87. struct    hent    *lookup();
  88.  
  89. #define    NIL    ((struct hent *) 0)    /* The big zero */
  90.  
  91. double    atof();
  92. char    *getenv();
  93. char    *pgetstr();
  94.  
  95. main(argc, argv)
  96.     char **argv;
  97. {
  98.     register FILE *acct;
  99.     register char *cp;
  100.  
  101.     while (--argc) {
  102.         cp = *++argv;
  103.         if (*cp++ == '-') {
  104.             switch(*cp++) {
  105.             case 'P':
  106.                 /*
  107.                  * Printer name.
  108.                  */
  109.                 printer = cp;
  110.                 continue;
  111.  
  112.             case 'p':
  113.                 /*
  114.                  * get the price.
  115.                  */
  116.                 price = atof(cp);
  117.                 pflag = 1;
  118.                 continue;
  119.  
  120.             case 's':
  121.                 /*
  122.                  * Summarize and compress accounting file.
  123.                  */
  124.                 summarize++;
  125.                 continue;
  126.  
  127.             case 'c':
  128.                 /*
  129.                  * Sort by cost.
  130.                  */
  131.                 sort++;
  132.                 continue;
  133.  
  134.             case 'm':
  135.                 /*
  136.                  * disregard machine names for each user
  137.                  */
  138.                 mflag = 1;
  139.                 continue;
  140.  
  141.             case 'r':
  142.                 /*
  143.                  * Reverse sorting order.
  144.                  */
  145.                 reverse++;
  146.                 continue;
  147.  
  148.             default:
  149. fprintf(stderr,
  150.     "usage: pac [-Pprinter] [-pprice] [-s] [-c] [-r] [-m] [user ...]\n");
  151.                 exit(1);
  152.             }
  153.         }
  154.         (void) enter(--cp);
  155.         allflag = 0;
  156.     }
  157.     if (printer == NULL && (printer = getenv("PRINTER")) == NULL)
  158.         printer = DEFLP;
  159.     if (!chkprinter(printer)) {
  160.         printf("pac: unknown printer %s\n", printer);
  161.         exit(2);
  162.     }
  163.  
  164.     if ((acct = fopen(acctfile, "r")) == NULL) {
  165.         perror(acctfile);
  166.         exit(1);
  167.     }
  168.     account(acct);
  169.     fclose(acct);
  170.     if ((acct = fopen(sumfile, "r")) != NULL) {
  171.         account(acct);
  172.         fclose(acct);
  173.     }
  174.     if (summarize)
  175.         rewrite();
  176.     else
  177.         dumpit();
  178.     exit(errs);
  179. }
  180.  
  181. /*
  182.  * Read the entire accounting file, accumulating statistics
  183.  * for the users that we have in the hash table.  If allflag
  184.  * is set, then just gather the facts on everyone.
  185.  * Note that we must accomodate both the active and summary file
  186.  * formats here.
  187.  * Host names are ignored if the -m flag is present.
  188.  */
  189.  
  190. account(acct)
  191.     register FILE *acct;
  192. {
  193.     char linebuf[BUFSIZ];
  194.     double t;
  195.     register char *cp, *cp2;
  196.     register struct hent *hp;
  197.     register int ic;
  198.  
  199.     while (fgets(linebuf, BUFSIZ, acct) != NULL) {
  200.         cp = linebuf;
  201.         while (any(*cp, " t\t"))
  202.             cp++;
  203.         t = atof(cp);
  204.         while (any(*cp, ".0123456789"))
  205.             cp++;
  206.         while (any(*cp, " \t"))
  207.             cp++;
  208.         for (cp2 = cp; !any(*cp2, " \t\n"); cp2++)
  209.             ;
  210.         ic = atoi(cp2);
  211.         *cp2 = '\0';
  212.         if (mflag && index(cp, ':'))
  213.             cp = index(cp, ':') + 1;
  214.         hp = lookup(cp);
  215.         if (hp == NIL) {
  216.             if (!allflag)
  217.                 continue;
  218.             hp = enter(cp);
  219.         }
  220.         hp->h_feetpages += t;
  221.         if (ic)
  222.             hp->h_count += ic;
  223.         else
  224.             hp->h_count++;
  225.     }
  226. }
  227.  
  228. /*
  229.  * Sort the hashed entries by name or footage
  230.  * and print it all out.
  231.  */
  232.  
  233. dumpit()
  234. {
  235.     struct hent **base;
  236.     register struct hent *hp, **ap;
  237.     register int hno, c, runs;
  238.     float feet;
  239.     int qucmp();
  240.  
  241.     hp = hashtab[0];
  242.     hno = 1;
  243.     base = (struct hent **) calloc(sizeof hp, hcount);
  244.     for (ap = base, c = hcount; c--; ap++) {
  245.         while (hp == NIL)
  246.             hp = hashtab[hno++];
  247.         *ap = hp;
  248.         hp = hp->h_link;
  249.     }
  250.     qsort(base, hcount, sizeof hp, qucmp);
  251.     printf("  Login               pages/feet   runs    price\n");
  252.     feet = 0.0;
  253.     runs = 0;
  254.     for (ap = base, c = hcount; c--; ap++) {
  255.         hp = *ap;
  256.         runs += hp->h_count;
  257.         feet += hp->h_feetpages;
  258.         printf("%-24s %7.2f %4d   $%6.2f\n", hp->h_name,
  259.             hp->h_feetpages, hp->h_count, hp->h_feetpages * price);
  260.     }
  261.     if (allflag) {
  262.         printf("\n");
  263.         printf("%-24s %7.2f %4d   $%6.2f\n", "total", feet, 
  264.             runs, feet * price);
  265.     }
  266. }
  267.  
  268. /*
  269.  * Rewrite the summary file with the summary information we have accumulated.
  270.  */
  271.  
  272. rewrite()
  273. {
  274.     register struct hent *hp;
  275.     register int i;
  276.     register FILE *acctf;
  277.  
  278.     if ((acctf = fopen(sumfile, "w")) == NULL) {
  279.         perror(sumfile);
  280.         errs++;
  281.         return;
  282.     }
  283.     for (i = 0; i < HSHSIZE; i++) {
  284.         hp = hashtab[i];
  285.         while (hp != NULL) {
  286.             fprintf(acctf, "%7.2f\t%s\t%d\n", hp->h_feetpages,
  287.                 hp->h_name, hp->h_count);
  288.             hp = hp->h_link;
  289.         }
  290.     }
  291.     fflush(acctf);
  292.     if (ferror(acctf)) {
  293.         perror(sumfile);
  294.         errs++;
  295.     }
  296.     fclose(acctf);
  297.     if ((acctf = fopen(acctfile, "w")) == NULL)
  298.         perror(acctfile);
  299.     else
  300.         fclose(acctf);
  301. }
  302.  
  303. /*
  304.  * Hashing routines.
  305.  */
  306.  
  307. /*
  308.  * Enter the name into the hash table and return the pointer allocated.
  309.  */
  310.  
  311. struct hent *
  312. enter(name)
  313.     char name[];
  314. {
  315.     register struct hent *hp;
  316.     register int h;
  317.  
  318.     if ((hp = lookup(name)) != NIL)
  319.         return(hp);
  320.     h = hash(name);
  321.     hcount++;
  322.     hp = (struct hent *) calloc(sizeof *hp, 1);
  323.     hp->h_name = (char *) calloc(sizeof(char), strlen(name)+1);
  324.     strcpy(hp->h_name, name);
  325.     hp->h_feetpages = 0.0;
  326.     hp->h_count = 0;
  327.     hp->h_link = hashtab[h];
  328.     hashtab[h] = hp;
  329.     return(hp);
  330. }
  331.  
  332. /*
  333.  * Lookup a name in the hash table and return a pointer
  334.  * to it.
  335.  */
  336.  
  337. struct hent *
  338. lookup(name)
  339.     char name[];
  340. {
  341.     register int h;
  342.     register struct hent *hp;
  343.  
  344.     h = hash(name);
  345.     for (hp = hashtab[h]; hp != NIL; hp = hp->h_link)
  346.         if (strcmp(hp->h_name, name) == 0)
  347.             return(hp);
  348.     return(NIL);
  349. }
  350.  
  351. /*
  352.  * Hash the passed name and return the index in
  353.  * the hash table to begin the search.
  354.  */
  355.  
  356. hash(name)
  357.     char name[];
  358. {
  359.     register int h;
  360.     register char *cp;
  361.  
  362.     for (cp = name, h = 0; *cp; h = (h << 2) + *cp++)
  363.         ;
  364.     return((h & 0x7fffffff) % HSHSIZE);
  365. }
  366.  
  367. /*
  368.  * Other stuff
  369.  */
  370.  
  371. any(ch, str)
  372.     char str[];
  373. {
  374.     register int c = ch;
  375.     register char *cp = str;
  376.  
  377.     while (*cp)
  378.         if (*cp++ == c)
  379.             return(1);
  380.     return(0);
  381. }
  382.  
  383. /*
  384.  * The qsort comparison routine.
  385.  * The comparison is ascii collating order
  386.  * or by feet of typesetter film, according to sort.
  387.  */
  388.  
  389. qucmp(left, right)
  390.     struct hent **left, **right;
  391. {
  392.     register struct hent *h1, *h2;
  393.     register int r;
  394.  
  395.     h1 = *left;
  396.     h2 = *right;
  397.     if (sort)
  398.         r = h1->h_feetpages < h2->h_feetpages ? -1 : h1->h_feetpages > 
  399. h2->h_feetpages;
  400.     else
  401.         r = strcmp(h1->h_name, h2->h_name);
  402.     return(reverse ? -r : r);
  403. }
  404.  
  405. /*
  406.  * Perform lookup for printer name or abbreviation --
  407.  */
  408. chkprinter(s)
  409.     register char *s;
  410. {
  411.     static char buf[BUFSIZ/2];
  412.     char b[BUFSIZ];
  413.     int stat;
  414.     char *bp = buf;
  415.  
  416.     if ((stat = pgetent(b, s)) < 0) {
  417.         printf("pac: can't open printer description file\n");
  418.         exit(3);
  419.     } else if (stat == 0)
  420.         return(0);
  421.     if ((acctfile = pgetstr("af", &bp)) == NULL) {
  422.         printf("accounting not enabled for printer %s\n", printer);
  423.         exit(2);
  424.     }
  425.     if (!pflag && (price100 = pgetnum("pc")) > 0)
  426.         price = price100/10000.0;
  427.     sumfile = (char *) calloc(sizeof(char), strlen(acctfile)+5);
  428.     if (sumfile == NULL) {
  429.         perror("pac");
  430.         exit(1);
  431.     }
  432.     strcpy(sumfile, acctfile);
  433.     strcat(sumfile, "_sum");
  434.     return(1);
  435. }
  436.