home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 35 Internet / 35-Internet.zip / analg211.zip / analog.c < prev    next >
C/C++ Source or Header  |  1997-03-14  |  32KB  |  1,052 lines

  1. /*** analog 2.1 ***/
  2. /* Please read Readme.html, or http://www.statslab.cam.ac.uk/~sret1/analog/  */
  3.  
  4. /*** analog.c; the main function ***/
  5.  
  6. #include "analhea2.h"
  7.  
  8. int main(int argc, char **argv)
  9. {
  10.   extern char *commandname;    /* all global vars declared in init.c */
  11.   extern struct loglist *logfilehead;
  12.   extern struct stringlist *cachefilehead, *refloghead, *browloghead;
  13.   extern struct stringlist *errloghead;
  14. #ifndef NODNS
  15.   extern char *dnsfile;
  16.   extern flag dnsq;
  17.   extern struct dnscache **dnshead;
  18.   extern size_t dnshashsize;
  19.   struct dnscache *dnsp, *dnsnextp;
  20. #endif
  21.   extern flag byq, browbyq, refbyq;
  22.   extern flag filemaskq, hostmaskq, q7, warnq, anywarns;
  23.   extern flag mq, hq, Hq, dq, Dq, Wq, sq, Sq, oq, iq, tq, rq, fq, Bq, bq, cq;
  24.   extern flag eq;
  25.   extern int osortby, rsortby, isortby, tsortby, Ssortby, fsortby;
  26.   extern int bsortby, Bsortby;
  27.   extern char bcols[], Bcols[], fcols[];
  28.   extern char mgraph, dgraph, Dgraph, hgraph, Hgraph, Wgraph;
  29.   extern char *rminreqstr, *iminreqstr, *tminreqstr, *Sminreqstr;
  30.   extern char *fminreqstr, *bminreqstr, *Bminreqstr;
  31.   extern char *rminpagestr, *iminpagestr, *tminpagestr, *Sminpagestr;
  32.   extern char *fminpagestr, *bminpagestr, *Bminpagestr;
  33.   extern char *rminbytestr, *iminbytestr, *tminbytestr, *Sminbytestr;
  34.   extern char *fminbytestr, *bminbytestr, *Bminbytestr;
  35.   extern int rmaxreqs, imaxreqs, tmaxreqs, Smaxreqs, fmaxreqs;
  36.   extern int bmaxreqs, Bmaxreqs, eminreqs;
  37.   extern int rmaxpages, imaxpages, tmaxpages, Smaxpages, fmaxpages;
  38.   extern int bmaxpages, Bmaxpages;
  39.   extern double rmaxbytes, imaxbytes, tmaxbytes, Smaxbytes, fmaxbytes;
  40.   extern double bmaxbytes, Bmaxbytes;
  41.   extern size_t rhashsize, ihashsize, thashsize, Shashsize, fhashsize;
  42.   extern size_t bhashsize, Bhashsize;
  43.   extern int Smaxlength;
  44.   extern struct timestruct firsttime, lasttime, fromtime, totime, oldtime;
  45.   extern int no_hosts, no_hosts7, no_new_hosts7;
  46.   extern int no_urls, no_urls7;
  47.   extern int cachereqs, cachereqs7, cachepages, cachepages7;
  48.   extern int corrupt_lines, other_lines;
  49.   extern double total_bytes, total_bytes7, total_ref_bytes, total_brow_bytes;
  50.   extern int total_succ_reqs, total_fail_reqs, total_other_reqs;
  51.   extern int total_succ_reqs7, total_fail_reqs7, total_other_reqs7;
  52.   extern int total_page_reqs, total_page_reqs7;
  53.   extern int total_good_refs, total_bad_refs, total_masked_refs;
  54.   extern int total_good_brows, total_bad_brows, total_masked_brows;
  55.   extern int total_ref_pages, total_brow_pages;
  56.   extern struct weekly *firstW;
  57.   extern struct genstruct **Shead, **rhead, **ihead, **thead, **fhead;
  58.   extern struct genstruct **bhead, **Bhead, **Shead2, **rhead2, **fhead2;
  59.   extern int errors[];
  60.   extern int onumber;
  61.   extern struct include *wanthosthead, *wantreqhead;
  62.   extern int debug, progressfreq;
  63.   extern int status[], status7[], statusnos[];
  64.  
  65.   FILE *lf;
  66.   flag ispipe;           /* whether the currently open logfile is a pipe */
  67.   struct loglist *logfilep;
  68.   struct stringlist *otherlogp;
  69.   char inputline[MAXLINELENGTH];  /* a particular input line */
  70.   int linetype;          /* COMMON, NCSAOLD, WEBSTAR or CORRUPT */
  71.   char hostn[MAXSTRINGLENGTH];
  72.   int date, year, hr, min, monthno;
  73.   long thistimecode;
  74.   char fromurl[MAXSTRINGLENGTH];
  75.   char browser[MAXSTRINGLENGTH];
  76.   char errstr[MAXLINELENGTH];
  77.   char filename[MAXSTRINGLENGTH];
  78.   int code;
  79.   size_t preflength;     /* length of filename prefix for this logfile */
  80.   flag firstreq = TRUE;
  81.   flag datemaskq;
  82.   flag fwarn1 = OFF, fwarn2 = OFF, fwarn3 = OFF;
  83.   flag bwarn1 = OFF, bwarn2 = OFF, bwarn3 = OFF, bwarn4 = OFF;
  84.   /* have certain warnings been given? */
  85.   double bytes;    /* long is not big enough; double has more sig. figs,
  86.               and copes with overflow automatically. */
  87.   char bytestr[16];
  88.  
  89.   struct genstruct *rsorthead, *isorthead, *tsorthead, *Ssorthead;
  90.   struct genstruct *fsorthead, *bsorthead, *Bsorthead;
  91.   int firstdom, errorder[NO_ERRS];     /* heads for sorting */
  92.  
  93.   struct genstruct *hostp, *hostnextp, *urlp, *urlnextp;
  94.   int onlist;
  95.  
  96.   flag wantthisone = TRUE;  /* whether we want to analyse a particular entry */
  97.   flag issuccess;           /* whether an entry has a success status code */
  98.   flag ispage = OFF;        /* whether it represents a page */
  99.   flag last7q = OFF;        /* are we now in the last 7 days? */
  100.   int rc;
  101.   register int linesread;
  102.   int nextreport;
  103.   char *tempstr, *tempc;
  104.   int i, tempint, tempint2;
  105.   flag tempf;
  106.   char tempchar, tempchar2;
  107.   struct genstruct *tempgs;
  108.  
  109.   /*** Initialisation ***/
  110.  
  111. #ifdef MAC_EVENTS
  112.   MacInit();
  113. #endif
  114. #ifdef WIN32
  115.   Win32Init();
  116. #endif
  117.   initialise(argc, argv);
  118.   linesread = 0;
  119.   nextreport = progressfreq;
  120.   datemaskq = (fromtime.code > -INFINITY || totime.code < INFINITY);
  121.  
  122.   /*** Now start scanning ***/
  123.  
  124.   for (logfilep = logfilehead; logfilep -> name[0] != '\0';
  125.        logfilep = logfilep -> next) {  /* for each logfile */
  126.  
  127.     lf = fopenlog(logfilep -> name, "logfile", &ispipe);
  128.     if (lf != NULL) {
  129.  
  130.       preflength = strlen(logfilep -> prefix);
  131.  
  132.       while(fgets(inputline, MAXLINELENGTH, lf) != NULL) {
  133.  
  134.     strcpy(filename, logfilep -> prefix);
  135.     /* needed each line coz can get accidentally overwritten by /../ */
  136.  
  137.     linetype = CORRUPT;   /* paranoia :) */
  138.  
  139.     if ((rc = sscanf_common(inputline, hostn, &date, &monthno, &year, &hr,
  140.                 &min, filename + preflength, fromurl, browser,
  141.                 &code, bytestr, preflength)) >= 9) {
  142.       linetype = COMMON;
  143.       bytes = atof(bytestr);
  144.     }
  145. #ifdef WEBSTAR
  146.     else if ((rc = sscanf_webstar(inputline, hostn, &date, &monthno, &year,
  147.                       &hr, &min, filename + preflength,
  148.                       fromurl, browser, &code, bytestr,
  149.                       preflength)) >= 9) {
  150.       linetype = WEBSTARLINE;
  151.       bytes = atof(bytestr);
  152.     }
  153. #endif
  154. #ifdef NETPRESENZ
  155.     else if ((rc = sscanf_netpresenz(lf, inputline, hostn, &date, &monthno,
  156.                      &year, &hr, &min,
  157.                      filename + preflength, fromurl,
  158.                      browser, &code, bytestr,
  159.                      preflength)) >= 9) {
  160.       linetype = NETPRESENZLINE;
  161.       bytes = 0;
  162.       if (byq) {
  163.         fprintf(stderr, "%s: Warning: Netpresenz logs contain no bytes information:\n", commandname);
  164.         fprintf(stderr, "  will not report on bytes transferred.\n");
  165.         byq = OFF;
  166.         if (osortby == BYBYTES)
  167.           osortby = BYREQUESTS;
  168.         if (rsortby == BYBYTES)
  169.           rsortby = BYREQUESTS;
  170.         if (isortby == BYBYTES)
  171.           isortby = BYREQUESTS;
  172.         if (tsortby == BYBYTES)
  173.           tsortby = BYREQUESTS;
  174.         if (Ssortby == BYBYTES)
  175.           Ssortby = BYREQUESTS;
  176.         if (mgraph == 'b' || mgraph == 'B')
  177.           mgraph = 'r';
  178.         if (dgraph == 'b' || dgraph == 'B')
  179.           dgraph = 'r';
  180.         if (Dgraph == 'b' || Dgraph == 'B')
  181.           Dgraph = 'r';
  182.         if (hgraph == 'b' || hgraph == 'B')
  183.           hgraph = 'r';
  184.         if (Hgraph == 'b' || Hgraph == 'B')
  185.           Hgraph = 'r';
  186.         if (Wgraph == 'b' || Wgraph == 'B')
  187.           Wgraph = 'r';
  188.       }
  189.     }
  190. #endif
  191.     else if ((rc = sscanf_ncsaold(inputline, hostn, &monthno, &date, &hr,
  192.                       &min, &year, filename + preflength,
  193.                       preflength)) == 7) {
  194.       linetype = NCSAOLD;
  195.       code = 200;
  196.       bytes = 0;
  197.       if (byq) {
  198.         fprintf(stderr, "%s: Warning: old style NCSA logs contain no bytes information:\n", commandname);
  199.         fprintf(stderr, "  will not report on bytes transferred.");
  200.         byq = OFF;
  201.         if (osortby == BYBYTES)
  202.           osortby = BYREQUESTS;
  203.         if (rsortby == BYBYTES)
  204.           rsortby = BYREQUESTS;
  205.         if (isortby == BYBYTES)
  206.           isortby = BYREQUESTS;
  207.         if (tsortby == BYBYTES)
  208.           tsortby = BYREQUESTS;
  209.         if (Ssortby == BYBYTES)
  210.           Ssortby = BYREQUESTS;
  211.         if (mgraph == 'b' || mgraph == 'B')
  212.           mgraph = 'r';
  213.         if (dgraph == 'b' || dgraph == 'B')
  214.           dgraph = 'r';
  215.         if (Dgraph == 'b' || Dgraph == 'B')
  216.           Dgraph = 'r';
  217.         if (hgraph == 'b' || hgraph == 'B')
  218.           hgraph = 'r';
  219.         if (Hgraph == 'b' || Hgraph == 'B')
  220.           Hgraph = 'r';
  221.         if (Wgraph == 'b' || Wgraph == 'B')
  222.           Wgraph = 'r';
  223.       }
  224.     }
  225.       
  226.     if (linetype != CORRUPT) {
  227.     
  228.       thistimecode = timecode(date, monthno, year, hr, min);
  229.       wantthisone = thistimecode >= fromtime.code &&
  230.         thistimecode <= totime.code;
  231.       if (wantthisone && hostmaskq) {  /* must hostmask before req. hash */
  232.         doaliashost(hostn);
  233.         wantthisone = included(hostn, UNSET, wanthosthead);
  234.       }
  235.       if (wantthisone) {
  236.         issuccess = (code <= 299 || code == 304);
  237.         /* Are we in the last 7 days? Check this every time in case */
  238.         /* logfile is not in chronological order */
  239.         if (q7)   /* if !q7, last7q stays off (for efficiency) */
  240.           last7q = (thistimecode > oldtime.code);
  241.     
  242.         /* Request report. We always construct a (poss. silent) request
  243.            report in order to generate ispage etc. */
  244.         tempgs = hashadd(rhead2, rhashsize, filename, issuccess,
  245.                  issuccess?bytes:0, UNSET,
  246.                  last7q, &tempint, &tempint, &tempint,
  247.                  OFF, filemaskq, UNSET,
  248.                  (struct genstruct *)NULL, -1, 'r');
  249.         wantthisone = tempgs -> wanted;
  250.         ispage = tempgs -> ispage;
  251.       }
  252.       if (wantthisone) {
  253.         /* Hostname report/count. This time, we don't do one if the
  254.            domain report or hostmaskq is on and this is off, because
  255.            this takes up a lot of memory. */
  256.         if (sq == ON) {
  257.           if (hostmaskq)  /* then aliasing already done */
  258.         hashadd(Shead2, Shashsize, hostn, issuccess, issuccess?bytes:0,
  259.             issuccess && ispage, last7q, &tempint, &tempint,
  260.             &tempint, ON, OFF, OFF, (struct genstruct *)NULL,
  261.             -1, 'S');  /* and we know it's wanted */
  262.           else
  263.         wantthisone = hashadd(Shead2, Shashsize, hostn, issuccess,
  264.                       issuccess?bytes:0, issuccess && ispage,
  265.                       last7q, &tempint, &tempint, &tempint,
  266.                       OFF, OFF, OFF, (struct genstruct *)NULL,
  267.                       -1, 'S') -> wanted;
  268.         }
  269.         else if (issuccess) {
  270.           if (!hostmaskq && (oq || sq == APPROX)) {
  271.         doaliashost(hostn);
  272.         wantthisone = included(hostn, UNSET, wanthosthead);
  273.           }
  274.           if /* still */ (wantthisone) {
  275.         if (oq)
  276.           domhashadd(hostn, 1, ispage, bytes);
  277.         if (sq == APPROX)
  278.           approxhosthashadd(hostn, last7q);
  279.           }
  280.         }
  281.       }
  282.  
  283.       if (!wantthisone)
  284.         ++other_lines;
  285.       else {
  286.         /* add to the right status code total */
  287.         tempf = OFF;
  288.         for (i = 0; !tempf && i < NO_STATUS; i++) {
  289.           if (code <= statusnos[i]) {
  290.         status[i]++;
  291.         if (last7q)
  292.           status7[i]++;
  293.         tempf = ON;
  294.           }
  295.         }
  296.  
  297.         if (issuccess) {
  298.           if (ispage) {
  299.         total_page_reqs++;
  300.         total_page_reqs7 += last7q;
  301.           }
  302.           total_bytes += bytes;  /* NB only count bytes for successes */
  303.           if (last7q)
  304.         total_bytes7 += bytes;
  305.  
  306.           if (firstreq) {
  307.         firstreq = FALSE;
  308.         firsttime.date = date;
  309.         firsttime.monthno = monthno;
  310.         firsttime.year = year;
  311.         firsttime.hr = hr;
  312.         firsttime.min = min;
  313.         firsttime.code = thistimecode;
  314.         if (Wq)
  315.           firstW -> start = startofweek(firsttime);
  316.         lasttime.date = date;
  317.         lasttime.monthno = monthno;
  318.         lasttime.year = year;
  319.         lasttime.hr = hr;
  320.         lasttime.min = min;
  321.         lasttime.code = thistimecode;
  322.           }
  323.       
  324.           /* date cataloguing */
  325.  
  326.           datehash(year, monthno, date, hr, min, thistimecode, 1, ispage,
  327.                bytes);
  328.  
  329.         }    /* end if issuccess */
  330.     
  331.         if (rc == 11) {  /* then do referrer and browser now (all codes) */
  332.           if (fq && fromurl[0] != '\0')
  333.         addref(fromurl, filename, ispage, bytes, last7q, OFF);
  334.           if ((Bq || bq) && browser[0] != '\0')
  335.         addbrowser(browser, ispage, bytes, last7q);
  336.         }
  337.  
  338.       }  /* end if want this one */
  339.       
  340.     }   /* end if linetype != CORRUPT */
  341.  
  342.     else {   /* line is corrupt */
  343.       ++corrupt_lines;
  344.       if (debug != 0)
  345.         fprintf(stderr, "C: %s", inputline);
  346.       if (strchr(inputline, '\n') == NULL) {
  347.         /* line corrupt by being too long; */
  348.         fscanf(lf, "%*[^\n]");              /* read to end of line */
  349.         if (debug != 0)
  350.           fprintf(stderr, "\n");
  351.       }
  352.     }
  353.   
  354.     if ((++linesread) == nextreport) {
  355.       fprintf(stderr, "%s: %d lines read\n", commandname, linesread);
  356.       nextreport += progressfreq;
  357.     }
  358.  
  359. #ifdef MAC_EVENTS
  360.     if ((linesread % MAC_IDLE_FREQ) == 0)
  361.       MacIdle();
  362. #endif
  363.  
  364.       }   /* end of reading this logfile */
  365.  
  366.       fcloselog(lf, logfilep -> name, "logfile", ispipe);
  367.  
  368.     }
  369.   }    /*** End of main loop (for all logfiles) ***/
  370.  
  371.   /*** Now for the other logfiles. First cache files. ***/
  372.   /* NB Some of this is shared with main loop and could probably be combined */
  373.  
  374.   min = 30;   /* reckon all cache entries at half past the hour */
  375.   for (otherlogp = cachefilehead; otherlogp -> name[0] != '\0';
  376.        otherlogp = otherlogp -> next) {  /* for each referrer log */
  377.     
  378.     lf = fopenlog(otherlogp -> name, "cache file", &ispipe);
  379.     if (lf != NULL) {
  380.  
  381.       if (fgets(inputline, MAXLINELENGTH, lf) == NULL ||
  382.       sscanf(inputline, "CACHE type %c produced by analo%c", &tempchar,
  383.          &tempchar2) != 2 ||
  384.       tempchar2 != 'g' || (tempchar != '1' && tempchar != '2')) {
  385.     if (warnq) {
  386.       fprintf(stderr, "%s: Warning: %s appears not to be a cache file: ignoring it\n", commandname, otherlogp -> name);
  387.       anywarns = ON;
  388.     }
  389.       }
  390.       else {
  391.     if (tempchar == '1') {
  392.       tempint2 = 0;  /* number of page requests then always zero */
  393.       if (warnq) {
  394.         fprintf(stderr, "%s: Warning: old style cache file %s contains no page information:\n",
  395.             commandname, otherlogp -> name);
  396.         fprintf(stderr, "  page counts will be too low\n");
  397.         anywarns = ON;
  398.       }
  399.     }
  400.     while (fgets(inputline, MAXLINELENGTH, lf) != NULL) {
  401.       if ((tempstr = strtok(inputline, ":")) != NULL) {
  402.         tempc = tempstr;
  403.         if (strlen(tempstr) != 10) {
  404.           if (warnq) {
  405.         fprintf(stderr, "%s: Warning: ignoring corrupt line in cache file %s starting %s\n", commandname, otherlogp -> name, tempc);
  406.         anywarns = ON;
  407.           }
  408.         }
  409.         else {
  410.           year = 1000 * (*tempstr - '0');
  411.           year += 100 * (*(++tempstr) - '0');
  412.           year += 10 * (*(++tempstr) - '0');
  413.           year += (*(++tempstr) - '0');
  414.           monthno = 10 * (*(++tempstr) - '0');
  415.           monthno += *(++tempstr) - '0' - 1;
  416.           date = 10 * (*(++tempstr) - '0');
  417.           date += *(++tempstr) - '0';
  418.           hr = 10 * (*(++tempstr) - '0');
  419.           hr += *(++tempstr) - '0';
  420.           tempf = OFF;
  421.           for ( ; hr < 24 && !tempf; hr++) {
  422.         if ((tempstr = strtok((char *)NULL, ":")) == NULL) {
  423.           if (warnq) {
  424.             fprintf(stderr, "%s: Warning: missing data in cache file %s at line starting %s\n", commandname, otherlogp -> name, tempc);
  425.             anywarns = ON;
  426.           }
  427.           tempf = ON;
  428.         }
  429.         else if (tempstr[0] == '*')
  430.           tempf = ON;
  431.         else {
  432.           tempint = atoi(tempstr);
  433.           if (tempchar == '2') {
  434.             if ((tempstr = strtok((char *)NULL, ":")) == NULL) {
  435.               if (warnq) {
  436.             fprintf(stderr, "%s: Warning: missing data in cache file %s at line starting %s\n", commandname, otherlogp -> name, tempc);
  437.             anywarns = ON;
  438.               }
  439.               tempf = ON;
  440.             }
  441.             else
  442.               tempint2 = atoi(tempstr);
  443.           }
  444.           if ((tempstr = strtok((char *)NULL, ":")) == NULL) {
  445.             if (warnq) {
  446.               fprintf(stderr, "%s: Warning: missing data in cache file %s at line starting %s\n", commandname, otherlogp -> name, tempc);
  447.               anywarns = ON;
  448.             }
  449.             tempf = ON;
  450.           }
  451.           else {
  452.             bytes = atof(tempstr);
  453.             thistimecode = timecode(date, monthno, year, hr, min);
  454.             if (thistimecode >= fromtime.code &&
  455.             thistimecode <= totime.code) {
  456.               if (firstreq) {
  457.             firstreq = FALSE;
  458.             firsttime.date = date;
  459.             firsttime.monthno = monthno;
  460.             firsttime.year = year;
  461.             firsttime.hr = hr;
  462.             firsttime.min = min;
  463.             firsttime.code = thistimecode;
  464.             if (Wq)
  465.               firstW -> start = startofweek(firsttime);
  466.             lasttime.date = date;
  467.             lasttime.monthno = monthno;
  468.             lasttime.year = year;
  469.             lasttime.hr = hr;
  470.             lasttime.min = min;
  471.             lasttime.code = thistimecode;
  472.               }
  473.               if (q7)
  474.             last7q = (thistimecode > oldtime.code);
  475.               total_bytes += bytes;
  476.               cachereqs += tempint;
  477.               cachepages += tempint2;
  478.               if (last7q) {
  479.             total_bytes7 += bytes;
  480.             cachereqs7 += tempint;
  481.             cachepages7 += tempint2;
  482.               }
  483.               datehash(year, monthno, date, hr, min, thistimecode,
  484.                    tempint, tempint2, bytes);
  485.             }
  486.           }
  487.         }
  488.           }
  489.         }
  490.       }
  491.     }
  492.       }
  493.       fcloselog(lf, otherlogp -> name, "cache file", ispipe);
  494.     }
  495.   }
  496.  
  497.   /*** Now the referrer logs ***/
  498.  
  499.   if (fq) {
  500.  
  501.     for (otherlogp = refloghead; otherlogp -> name[0] != '\0';
  502.      otherlogp = otherlogp -> next) {  /* for each referrer log */
  503.  
  504.       lf = fopenlog(otherlogp -> name, "referrer log", &ispipe);
  505.       if (lf != NULL) {
  506.  
  507.     while(fgets(inputline, MAXLINELENGTH, lf) != NULL) {
  508.       if (sscanf_referrer(inputline, &date, &monthno, &year, &hr, &min,
  509.                  fromurl, filename) == 7) {
  510.         wantthisone = ON;
  511.         last7q = OFF;
  512.         if (datemaskq) {
  513.           if (date != 0) {
  514.         thistimecode = timecode(date, monthno, year, hr, min);
  515.         wantthisone = thistimecode > fromtime.code &&
  516.           thistimecode < totime.code;
  517.         if (q7)
  518.           last7q = (thistimecode > oldtime.code);
  519.           }
  520.           else if (!fwarn1 && warnq) {
  521.         fprintf(stderr, "%s: Warning: Referrer log contains lines with no date information;\n", commandname);
  522.         fprintf(stderr, "  cannot apply FROM and TO commands to them.\n");
  523.         fwarn1 = ON;
  524.         anywarns = ON;
  525.           }
  526.         }
  527.         if (!fwarn2 && hostmaskq && wantthisone && warnq) {
  528.           fprintf(stderr, "%s: Warning: Referrer logs contain no host information;\n", commandname);
  529.           fprintf(stderr, "  cannot apply HOSTINCLUDE and HOSTEXCLUDE commands to it.\n");
  530.           fwarn2 = ON;
  531.           anywarns = ON;
  532.         }
  533.         if (!fwarn3) {
  534.           fwarn3 = ON;
  535.           for (tempc = fcols; *tempc != '\0' && *tempc != 'B' &&
  536.            *tempc != 'b'; tempc++)
  537.         ;
  538.           if (*tempc != '\0' || fsortby == BYBYTES) {
  539.         if (warnq) {
  540.           fprintf(stderr, "%s: Warning: Referrer logs contain no bytes information;\n", commandname);
  541.           fprintf(stderr, "  cannot report on referrer bytes.\n");
  542.           anywarns = ON;
  543.         }
  544.         if (fsortby == BYBYTES)
  545.           fsortby = BYREQUESTS;
  546.         refbyq = OFF;
  547.           }
  548.         }
  549.         if (wantthisone)
  550.           addref(fromurl, filename, UNSET, 0.0, last7q, filemaskq);
  551.         else
  552.           ++total_masked_refs;
  553.       }
  554.       else
  555.         ++total_bad_refs;
  556.  
  557.     if ((++linesread) == nextreport) {
  558.       fprintf(stderr, "%s: %d lines read\n", commandname, linesread);
  559.       nextreport += progressfreq;
  560.     }
  561.  
  562. #ifdef MAC_EVENTS
  563.     if ((linesread % MAC_IDLE_FREQ) == 0)
  564.       MacIdle();
  565. #endif
  566.  
  567.     }
  568.     
  569.     fcloselog(lf, otherlogp -> name, "referrer log", ispipe);
  570.       }
  571.     }
  572.   }
  573.  
  574.   /* Next the browser logs */
  575.  
  576.   if (bq || Bq) {
  577.  
  578.     for (otherlogp = browloghead; otherlogp -> name[0] != '\0';
  579.      otherlogp = otherlogp -> next) { 
  580.  
  581.       lf = fopenlog(otherlogp -> name, "browser log", &ispipe);
  582.       if (lf != NULL) {
  583.  
  584.     while(fgets(inputline, MAXLINELENGTH, lf) != NULL) {
  585.     
  586.       /* read in the date, if supplied */
  587.       if (*(tempstr = inputline) == '[') {
  588.         wantthisone = FALSE;  /* unless date is valid */
  589.         if (sscanf_date(++tempstr, &date, &monthno, &year, &hr, &min) ==
  590.         5) {
  591.           tempstr += 20;
  592.           if (*tempstr == ']') {
  593.         if (*(++tempstr) == ' ') {
  594.           tempstr++;
  595.           wantthisone = TRUE;
  596.         }
  597.           }
  598.         }
  599.       }
  600.       else {
  601.         wantthisone = TRUE;
  602.         date = 0;   /* as marker */
  603.       }
  604.  
  605.       if (wantthisone) {
  606.         last7q = OFF;
  607.         if (datemaskq) {
  608.           if (date != 0) {
  609.         thistimecode = timecode(date, monthno, year, hr, min);
  610.         wantthisone = thistimecode > fromtime.code &&
  611.           thistimecode < totime.code;
  612.         if (q7)
  613.           last7q = (thistimecode > oldtime.code);
  614.           }
  615.           else if (!bwarn1 && warnq) {
  616.         fprintf(stderr, "%s: Warning: Browser log contains lines with no date information;\n", commandname);
  617.         fprintf(stderr, "  cannot apply FROM and TO commands to them.\n");
  618.         bwarn1 = ON;
  619.         anywarns = ON;
  620.           }
  621.         }
  622.         if (warnq) {  /* some boring warnings */
  623.           if (!bwarn2 && hostmaskq && wantthisone) {
  624.         fprintf(stderr, "%s: Warning: Browser logs contain no host information;\n", commandname);
  625.         fprintf(stderr, "  cannot apply HOSTINCLUDE and HOSTEXCLUDE commands to them.\n");
  626.         bwarn2 = ON;
  627.         anywarns = ON;
  628.           }
  629.           if (!bwarn3 && filemaskq && wantthisone) {
  630.         fprintf(stderr, "%s: Warning: Browser logs contain no file information;\n", commandname);
  631.         fprintf(stderr, "  cannot apply FILEINCLUDE and FILEEXCLUDE commands to them.\n");
  632.         bwarn3 = ON;
  633.         anywarns = ON;
  634.           }
  635.         }
  636.         if (!bwarn4) {
  637.           bwarn4 = ON;
  638.           tempf = OFF;
  639.           if (bq && (bsortby == BYBYTES || bsortby == BYPAGES))
  640.         tempf = ON;
  641.           else if (Bq && (bsortby == BYBYTES || bsortby == BYPAGES))
  642.         tempf = ON;
  643.           else if (bq) {
  644.         for (tempc = bcols; *tempc != '\0' && *tempc != 'p' &&
  645.              *tempc != 'P' && *tempc != 'B' && *tempc != 'b';
  646.              tempc++)
  647.           ;
  648.         if (*tempc != '\0')
  649.           tempf = ON;
  650.           }
  651.           if (!tempf && Bq) {
  652.         for (tempc = Bcols; *tempc != '\0' && *tempc != 'p' &&
  653.              *tempc != 'P' && *tempc != 'B' && *tempc != 'b';
  654.              tempc++)
  655.           ;
  656.         if (*tempc != '\0')
  657.           tempf = ON;
  658.           }
  659.           if (tempf) {
  660.         if (warnq) {
  661.           fprintf(stderr, "%s: Warning: Browser logs contain no file information;\n", commandname);
  662.           fprintf(stderr, "  cannot report on browser page counts or bytes.\n");
  663.           anywarns = ON;
  664.         }
  665.         browbyq = OFF;
  666.         if (bsortby == BYBYTES || bsortby == BYPAGES)
  667.           bsortby = BYREQUESTS;
  668.         if (Bsortby == BYBYTES || Bsortby == BYPAGES)
  669.           Bsortby = BYREQUESTS;
  670.           }
  671.         }
  672.         if (wantthisone) {
  673.           if ((tempc = strchr(tempstr, '\n')) != NULL)
  674.         *tempc = '\0';
  675.           strcpy(browser, tempstr);
  676.           addbrowser(browser, OFF, 0.0, last7q);
  677.         }
  678.         else   /* masked out */
  679.           ++total_masked_brows;
  680.  
  681.       }
  682.       else    /* had bad date */
  683.         ++total_bad_brows;
  684.  
  685.       if ((++linesread) == nextreport) {
  686.         fprintf(stderr, "%s: %d lines read\n", commandname, linesread);
  687.         nextreport += progressfreq;
  688.       }
  689.  
  690. #ifdef MAC_EVENTS
  691.       if ((linesread % MAC_IDLE_FREQ) == 0)
  692.         MacIdle();
  693. #endif
  694.  
  695.     }
  696.  
  697.     fcloselog(lf, otherlogp -> name, "browser log", ispipe);
  698.  
  699.       }
  700.     }
  701.   }
  702.  
  703.   /* Finally the error logs */
  704.  
  705.   if (eq) {
  706.  
  707.     for (otherlogp = errloghead; otherlogp -> name[0] != '\0';
  708.      otherlogp = otherlogp -> next) {  /* for each logfile */
  709.  
  710.       lf = fopenlog(otherlogp -> name, "error log", &ispipe);
  711.       if (lf != NULL) {
  712.  
  713.     while(fgets(inputline, MAXLINELENGTH, lf) != NULL) {
  714.     
  715.       tempstr = inputline;
  716.  
  717.       wantthisone = FALSE;
  718.       if (*tempstr == '[') {   /* others are non-httpd errors */
  719.         if (sscanf_olddate(++tempstr, &date, &monthno, &year, &hr, &min)
  720.         == 5) {
  721.           tempstr += 24;
  722.           if (*tempstr == ']') {
  723.         if (*(++tempstr) == ' ') {
  724.           tempstr++;
  725.           wantthisone = TRUE;
  726.         }
  727.           }
  728.         }
  729.       }
  730.  
  731.       if (wantthisone) {
  732.         if (datemaskq) {
  733.           thistimecode = timecode(date, monthno, year, hr, min);
  734.           wantthisone = (thistimecode > fromtime.code) &&
  735.         (thistimecode < totime.code);
  736.         }
  737.         if (wantthisone) {
  738.           strcpy(errstr, tempstr);
  739.           adderr(errstr);
  740.         }
  741.       }
  742.  
  743.       if ((++linesread) == nextreport) {
  744.         fprintf(stderr, "%s: %d lines read\n", commandname, linesread);
  745.         nextreport += progressfreq;
  746.       }
  747.  
  748. #ifdef MAC_EVENTS
  749.       if ((linesread % MAC_IDLE_FREQ) == 0)
  750.         MacIdle();
  751. #endif
  752.  
  753.     }
  754.  
  755.     fcloselog(lf, otherlogp -> name, "error log", ispipe);
  756.       }
  757.  
  758.     }
  759.   }
  760.  
  761.   /* Now writing out the DNS cache */
  762.  
  763. #ifndef NODNS
  764.   if (dnsq) {
  765.     if (STREQ(dnsfile, "-") || STREQ(dnsfile, "stdin")) {
  766.       lf = stdout;
  767.       if (debug > 0)
  768.     fprintf(stderr, "F: Opening stdout as DNS cache output file\n");
  769.     }
  770.     else if ((lf = fopen(dnsfile, "w")) == NULL) {
  771.       if (warnq) {
  772.     fprintf(stderr,
  773.         "%s: Warning: failed to open DNS cache file %s for writing.\n",
  774.         commandname, dnsfile);
  775.     anywarns = ON;
  776.       }
  777.     }
  778.     else if (debug > 0)
  779.       fprintf(stderr, "F: Opening %s as DNS cache output file\n", dnsfile);
  780.     if (lf != NULL) {
  781.       onlist = 0;
  782.       for (dnsp = dnshead[0]; onlist < dnshashsize; dnsp = dnsnextp) {
  783.                                     /* run through hosts, as below */
  784.     if (dnsp -> number == NULL) {
  785.       dnsnextp = dnshead[++onlist];
  786.     }
  787.     else {
  788.       if (isnumeric(dnsp -> number))
  789.         fprintf(lf, "%d %s %s\n", dnsp -> altimecode, dnsp -> number,
  790.                 (dnsp -> alias == NULL)?"*":(dnsp -> alias));
  791.       dnsnextp = dnsp -> next;
  792.     }
  793.       }
  794.       fclose(lf);
  795.       if (debug > 0)
  796.     fprintf(stderr, "F: Closing %s\n",
  797.         (STREQ(dnsfile, "-") || STREQ(dnsfile, "stdin"))?"stdout":
  798.         dnsfile);
  799.     }
  800.   }
  801. #endif
  802.  
  803.   /* now start final accounting */
  804.  
  805.   for (i = 0; i < NO_STATUS; i++) {
  806.     if (statusnos[i] <= 299 || statusnos[i] == 304) {
  807.       total_succ_reqs += status[i];
  808.       total_succ_reqs7 += status7[i];
  809.     }
  810.     else if (statusnos[i] <= 399) {
  811.       total_other_reqs += status[i];
  812.       total_other_reqs7 += status7[i];
  813.     }
  814.     else {
  815.       total_fail_reqs += status[i];
  816.       total_fail_reqs7 += status7[i];
  817.     }
  818.   }
  819.  
  820.   tempint = total_succ_reqs;
  821.   total_succ_reqs += cachereqs;
  822.   total_succ_reqs7 += cachereqs7;
  823.   total_page_reqs += cachepages;
  824.   total_page_reqs7 += cachepages7;
  825.  
  826.   if (tempint == 0) {      /* no logfile successes */
  827.     if (cachereqs == 0) {  /* no cached successes either */
  828.       mq = OFF;
  829.       dq = OFF;
  830.       Dq = OFF;
  831.       Wq = OFF;
  832.       hq = OFF;
  833.       Hq = OFF;
  834.       q7 = OFF;
  835.     }
  836.     oq = OFF;
  837.     iq = OFF;
  838.     tq = OFF;
  839.     rq = OFF;
  840.     Sq = OFF;
  841.     cq = OFF;
  842.   }
  843.  
  844.   else {   /* there are things to report from the main logfile */
  845.  
  846.     if (total_succ_reqs7 == 0)
  847.       q7 = OFF;   /* just total_bytes no good in case (!byq) */
  848.  
  849.     /* Next do aliasing of hosts */
  850.  
  851.     if (sq == ON)
  852.       allaliases(Shead2, Shead, Shashsize, &no_hosts, &no_hosts7,
  853.          &no_new_hosts7, 'S');
  854.  
  855.     /* Now the domain report. This is now easy because all the hostnames
  856.        are already aliased etc. */
  857.  
  858.     if (oq && sq == ON) {
  859.       onlist = 0;                          /* the list of files we are on */
  860.       hostp = Shead[0];                    /* starting at list 0 */
  861.       for ( ; onlist < Shashsize; hostp = hostnextp) {
  862.                                            /* run through hosts */
  863.     if (hostp -> name == NULL) {       /* then finished this list */
  864.       hostnextp = Shead[++onlist];     /* so start the next list */
  865.     }
  866.     else {
  867.       strcpy(hostn, hostp -> name);
  868.       domhashadd(hostn, hostp -> reqs, hostp -> pages, hostp -> bytes);
  869.       hostnextp = hostp -> next;
  870.     }
  871.       }
  872.     }
  873.  
  874.     /* Now for aliasing filenames. */
  875.  
  876.     if (rq || iq || tq)
  877.       allaliases(rhead2, rhead, rhashsize, &no_urls, &no_urls7, &tempint,
  878.          'r');
  879.  
  880.     /* Now the filetype report */
  881.  
  882.     if (tq) {
  883.       onlist = 0;
  884.       urlp = rhead[0];
  885.       for ( ; onlist < rhashsize; urlp = urlnextp) {
  886.                                          /* run through files */
  887.     if (urlp -> name == NULL) {      /* then finished this list */
  888.       urlnextp = rhead[++onlist];    /* so start the next list */
  889.     }
  890.     else {
  891.       hashadd(thead, thashsize, urltoext(urlp -> name), urlp -> reqs,
  892.           urlp -> bytes, urlp -> pages, urlp -> last7, &tempint,
  893.           &tempint, &tempint, ON, OFF, OFF, (struct genstruct *)NULL,
  894.           -1, 't');
  895.       urlnextp = urlp -> next;
  896.     }
  897.       }
  898.     }      
  899.  
  900.     /* Now the directory report. */
  901.  
  902.     if (iq) {
  903.       onlist = 0;                        /* the list of files we are on */
  904.       urlp = rhead[0];                   /* starting at list 0 */
  905.       for ( ; onlist < rhashsize; urlp = urlnextp) {
  906.                                          /* run through files */
  907.     if (urlp -> name == NULL) {      /* then finished this list */
  908.       urlnextp = rhead[++onlist];  /* so start the next list */
  909.     }
  910.     else {
  911.       strcpy(filename, urlp -> name);
  912.       urltodir(filename);
  913.       hashadd(ihead, ihashsize, filename, urlp -> reqs, urlp -> bytes,
  914.           urlp -> pages, urlp -> last7, &tempint, &tempint, &tempint,
  915.           ON, OFF, OFF, (struct genstruct *)NULL, -1, 'i');
  916.       urlnextp = urlp -> next;
  917.     }
  918.       }
  919.     }
  920.       
  921.     /*** now for the checking and sorting ***/
  922.     
  923.     if (rq) {
  924.       rsorthead = gensort(rhead, rhashsize, total_succ_reqs,
  925.               total_page_reqs, total_bytes, rsortby, rminreqstr,
  926.               rminpagestr, rminbytestr, wantreqhead,
  927.               OFF, &rmaxreqs, &rmaxpages, &rmaxbytes, &tempint);
  928.       if (rsorthead -> name == NULL)
  929.     rq = OFF;
  930.     }
  931.  
  932.     if (iq) {
  933.       isorthead = gensort(ihead, ihashsize, total_succ_reqs,
  934.               total_page_reqs, total_bytes, isortby, iminreqstr,
  935.               iminpagestr, iminbytestr, (struct include *)NULL,
  936.               OFF, &imaxreqs, &imaxpages, &imaxbytes, &tempint);
  937.       if (isorthead -> name == NULL)
  938.     iq = OFF;
  939.     }
  940.  
  941.     if (tq) {
  942.       tsorthead = gensort(thead, thashsize, total_succ_reqs,
  943.               total_page_reqs, total_bytes, tsortby, tminreqstr,
  944.               tminpagestr, tminbytestr,(struct include *) NULL,
  945.               OFF, &tmaxreqs, &tmaxpages, &tmaxbytes, &tempint);
  946.     if (tsorthead -> name == NULL)
  947.       tq = OFF;
  948.     }
  949.  
  950.     if (Sq) {
  951.       Ssorthead = gensort(Shead, Shashsize, total_succ_reqs,
  952.               total_page_reqs, total_bytes, Ssortby, Sminreqstr,
  953.               Sminpagestr, Sminbytestr, (struct include *)NULL,
  954.               Ssortby == ALPHABETICAL, &Smaxreqs, &Smaxpages,
  955.               &Smaxbytes, &Smaxlength);
  956.       if (Ssorthead -> name == NULL)
  957.     Sq = OFF;
  958.     }
  959.  
  960.     if (oq) {
  961.       firstdom = domsort();
  962.       if (onumber == 0)
  963.     oq = OFF;
  964.       else
  965.     subdomsort();
  966.     }
  967.  
  968.   }    /* end else (there are things to report from the main logfile) */
  969.  
  970.   if (fq) {
  971.     /* aliasing referrers */
  972.     allaliases(fhead2, fhead, fhashsize, &tempint, &tempint, &tempint, 'f');
  973.     fsorthead = gensort(fhead, fhashsize, total_good_refs, total_ref_pages,
  974.             total_ref_bytes, fsortby, fminreqstr, fminpagestr,
  975.             fminbytestr, (struct include *)NULL, OFF, &fmaxreqs,
  976.             &fmaxpages, &fmaxbytes, &tempint);
  977.     if (fsorthead -> name == NULL)
  978.       fq = OFF;
  979.   }
  980.  
  981.   if (bq) {
  982.     bsorthead = gensort(bhead, bhashsize, total_good_brows,
  983.             total_brow_pages, total_brow_bytes, bsortby,
  984.             bminreqstr, bminpagestr, bminbytestr,
  985.             (struct include *)NULL, OFF, &bmaxreqs, &bmaxpages,
  986.             &bmaxbytes, &tempint);
  987.     if (bsorthead -> name == NULL)
  988.       bq = OFF;
  989.   } 
  990.  
  991.   if (Bq) {
  992.     Bsorthead = gensort(Bhead, Bhashsize, total_good_brows,
  993.             total_brow_pages, total_brow_bytes, Bsortby,
  994.             Bminreqstr, Bminpagestr, Bminbytestr,
  995.             (struct include *)NULL, OFF, &Bmaxreqs, &Bmaxpages,
  996.             &Bmaxbytes, &tempint);
  997.     if (Bsorthead -> name == NULL)
  998.       Bq = OFF;
  999.   }
  1000.  
  1001.   if (eq) {
  1002.     errsort(errorder);
  1003.     if (errors[errorder[0]] < eminreqs)
  1004.       eq = OFF;
  1005.   }
  1006.  
  1007.   /*** Finally, do all the output ***/
  1008.  
  1009.   if (debug > 0) {
  1010.     fprintf(stderr, "S: successful requests: %d (%d)\n", total_succ_reqs,
  1011.         total_succ_reqs7);
  1012.     fprintf(stderr, "S: requests from cache: %d (%d)\n", cachereqs,
  1013.         cachereqs7);
  1014.     fprintf(stderr, "S: page requests from cache: %d (%d)\n", cachepages,
  1015.         cachepages7);
  1016.     fprintf(stderr, "S: failed requests: %d (%d)\n", total_fail_reqs,
  1017.         total_fail_reqs7);
  1018.     fprintf(stderr, "S: redirected requests: %d (%d)\n", total_other_reqs,
  1019.         total_other_reqs7);
  1020.     fprintf(stderr, "S: successful page requests: %d (%d)\n", total_page_reqs,
  1021.         total_page_reqs7);
  1022.     fprintf(stderr, "S: total bytes: %.0f (%.0f)\n", total_bytes,
  1023.         total_bytes7);
  1024.     fprintf(stderr, "S: corrupt lines: %d\n", corrupt_lines);
  1025.     fprintf(stderr, "S: unwanted lines: %d\n", other_lines);
  1026.     fprintf(stderr, "S: good referrer lines: %d\n", total_good_refs);
  1027.     fprintf(stderr, "S: bad referrer lines: %d\n", total_bad_refs);
  1028.     fprintf(stderr, "S: unwanted referrer lines: %d\n", total_masked_refs);
  1029.     fprintf(stderr, "S: referrer lines for pages: %d\n", total_ref_pages);
  1030.     fprintf(stderr, "S: total referrer bytes: %.0f\n", total_ref_bytes);
  1031.     fprintf(stderr, "S: good browser lines: %d\n", total_good_brows);
  1032.     fprintf(stderr, "S: bad browser lines: %d\n", total_bad_brows);
  1033.     fprintf(stderr, "S: unwanted browser lines: %d\n", total_masked_brows);
  1034.     fprintf(stderr, "S: browser lines for pages: %d\n", total_brow_pages); 
  1035.     fprintf(stderr, "S: total browser bytes: %.0f\n", total_brow_bytes);
  1036.     anywarns = ON;
  1037.  }
  1038.  
  1039.   output(rsorthead, isorthead, tsorthead, Ssorthead, firstdom, fsorthead,
  1040.      bsorthead, Bsorthead, errorder);
  1041.  
  1042. #ifdef MAC_EVENTS
  1043.   MacFini();
  1044. #endif
  1045. #ifdef WIN32
  1046.   Win32Cleanup();
  1047. #endif
  1048.  
  1049.   return(OK);
  1050.    
  1051. }
  1052.