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

  1. /*** analog 2.11 ***/
  2. /* Please read Readme.html, or http://www.statslab.cam.ac.uk/~sret1/analog/  */
  3.  
  4. /*** output.c; the main output function. ***/
  5. /* See output2.c for subsidiary functions */
  6.  
  7. #include "analhea2.h"
  8.  
  9. void output(struct genstruct *rsorthead, struct genstruct *isorthead,
  10.         struct genstruct *tsorthead, struct genstruct *Ssorthead,
  11.         int firstdom, struct genstruct *fsorthead,
  12.         struct genstruct *bsorthead, struct genstruct *Bsorthead,
  13.         int errorder[])
  14. {
  15.   extern char *outfile;
  16.   extern char dayname[7][11];
  17.   extern char monthname[12][12];
  18.   extern char *lngstr[NOLNGSTRS];
  19.   extern int monthlength[12];
  20.   extern char *hostname;
  21.   extern char *logourl;
  22.   extern char *hosturl;
  23.   extern char *commandname;
  24.   extern char *headerfile;
  25.   extern char *footerfile;
  26.   extern char reportorder[];
  27.   extern flag byq, refbyq, browbyq, html2;
  28.   extern flag mback, Dback, Wback, Hback;
  29.   extern int mrows, Hrows, Drows;
  30.   extern flag xq, dq, Dq, Wq, hq, Hq, mq, Sq, rq, oq, iq, tq, fq, bq, Bq, cq;
  31.   extern int eq;
  32.   extern int aq, debug;
  33.   extern struct include *linkhead, *reflinkhead;
  34.   extern struct alias *routaliashead, *ioutaliashead, *Soutaliashead;
  35.   extern struct alias *foutaliashead, *boutaliashead, *toutaliashead;
  36.   extern struct timestruct firsttime, lasttime;
  37.   extern time_t starttime, stoptime;
  38.   extern int weekbeginson;
  39.   extern struct monthly *firstm, *lastm;
  40.   extern struct weekly *firstW, *lastW;
  41.   extern struct daily *firstD, *lastD;
  42.   extern struct hourly *firstH, *lastH;
  43.   extern int dreq[], hreq[], dpag[], hpag[];
  44.   extern double dbytes[], hbytes[];
  45.   extern int munit, Wunit, hunit, Hunit, dunit, Dunit;
  46.   extern double total_bytes, total_ref_bytes, total_brow_bytes;
  47.   extern int total_succ_reqs, total_page_reqs, total_good_refs;
  48.   extern int total_good_brows, total_ref_pages, total_brow_pages;
  49.   extern int pagewidth;
  50.   extern int Ssortby, rsortby, isortby, tsortby, fsortby, bsortby, Bsortby;
  51.   extern char *Sminreqstr, *rminreqstr, *iminreqstr, *fminreqstr;
  52.   extern char *tminreqstr, *bminreqstr, *Bminreqstr;
  53.   extern char *Sminpagestr, *rminpagestr, *iminpagestr, *fminpagestr;
  54.   extern char *tminpagestr, *bminpagestr, *Bminpagestr;
  55.   extern char *Sminbytestr, *rminbytestr, *iminbytestr, *fminbytestr;
  56.   extern char *tminbytestr, *bminbytestr, *Bminbytestr;
  57.   extern char mgraph, dgraph, Dgraph, hgraph, Hgraph, Wgraph;
  58.   extern char mcols[], dcols[], Dcols[], hcols[], Wcols[], Hcols[];
  59.   extern char rcols[], icols[], tcols[], Scols[], fcols[], bcols[], Bcols[];
  60.   extern char *imagedir, *baseurl;
  61.   extern int imaxreqs, tmaxreqs, Smaxreqs, rmaxreqs, fmaxreqs, bmaxreqs;
  62.   extern int Bmaxreqs;
  63.   extern int imaxpages, tmaxpages, Smaxpages, rmaxpages, fmaxpages, bmaxpages;
  64.   extern int Bmaxpages;
  65.   extern double imaxbytes, tmaxbytes, Smaxbytes, rmaxbytes, fmaxbytes;
  66.   extern double bmaxbytes, Bmaxbytes;
  67.   extern char *presep;
  68.  
  69.   FILE *outf;       /* the output file */
  70.   int fieldwidth;   /* Width we require to print #reqs in */
  71.   int pfieldwidth, bfieldwidth;  /* #pages and #bytes ditto */
  72.   char bprefix[2];  /* kilo, Mega, etc. */
  73.   int graphwidth;   /* the width left for a graph after columns written */
  74.   struct monthly *mp;
  75.   struct daily *dp;
  76.   struct weekly *wp;
  77.   struct hourly *hp;
  78.   int maxreq, maxpages;       /* within a particular date report */
  79.   double maxbytes;
  80.   double bdivider;
  81.   int year, monthno, date, hr;
  82.   flag finished;
  83.   flag ispipe;
  84.   int i, j, firsti, lasti, tempint;
  85.   char *ro;
  86.   char templine[MAXLINELENGTH];
  87.   char tempstr[MAXSTRINGLENGTH];
  88.   FILE *tempf;
  89.  
  90.   bprefix[0] = '\0';
  91.   bprefix[1] = '\0';
  92.  
  93.   if (STREQ(outfile, "stdout") || STREQ(outfile, "-")) {
  94.     outf = stdout;
  95.     if (debug > 0)
  96.       fprintf(stderr, "F: Opening stdout as output file\n");
  97.   }
  98.  
  99.   else if ((outf = fopen(outfile, "a")) == NULL) {
  100.     fprintf(stderr, "%s: Error: failed to open output file %s for writing.\n",
  101.         commandname, outfile);
  102.     exit(ERR);  /* shouldn't get here because also tested at the beginning */
  103.   }             /* (unless it's vanished in the meantime or something) */
  104.  
  105.   else if (debug > 0)
  106.       fprintf(stderr, "F: Opening %s as output file\n", outfile);
  107.  
  108.   if (aq == CACHE)
  109.     fprintf(outf,
  110.         "CACHE type 2 produced by analog%s. Do not modify or delete!",
  111.         VERSION);
  112.   else {
  113.     if (aq == HTML) {
  114.       fprintf(outf, "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n");
  115.       fprintf(outf, "<html>\n<head>\n");
  116.       fprintf(outf, "<meta name=\"GENERATOR\" content=\"analog%s\">\n",
  117.           VERSION);
  118.       fprintf(outf, "<title>%s ", lngstr[webstatsfor_]);
  119.       htmlfprintf(outf, hostname);
  120.       fprintf(outf, "</title></head>\n");
  121.       fprintf(outf, "<body>\n<h1><a NAME=\"Top\">");
  122.       if (!STREQ(logourl, "none")) {
  123.     fprintf(outf, "<IMG src=\"");
  124.     htmlfprintf(outf, logourl);
  125.     fprintf(outf, "\" alt=\"\"> ");
  126.       }
  127.       if (hosturl[0] == '-') {
  128.     fprintf(outf, "%s</a> ", lngstr[webstatsfor_]);
  129.     htmlfprintf(outf, hostname);
  130.       }
  131.       else {
  132.     fprintf(outf, "%s</a> <a HREF=\"", lngstr[webstatsfor_]);
  133.     htmlfprintf(outf, hosturl);
  134.     fprintf(outf, "\">");
  135.     htmlfprintf(outf, hostname);
  136.     fprintf(outf, "</a>");
  137.       }
  138.       fprintf(outf, "</h1>\n\n");
  139.     }
  140.     else if (aq == ASCII) {
  141.       fprintf(outf, "%s %s\n", lngstr[webstatsfor_], hostname);
  142.       matchlength(outf, hostname, '=');
  143.       matchlength(outf, lngstr[webstatsfor_], '=');
  144.       fprintf(outf, "=\n");
  145.     }
  146.     
  147.     /* insert header file  -- before top line for HTML, ASCII; after for PRE */
  148.     
  149.     if (!STREQ(headerfile, "none")) {
  150.       tempf = fopenlog(headerfile, "header file", &ispipe);
  151.       if (tempf != NULL) {
  152.     if (aq == HTML)
  153.       fprintf(outf, "<hr>\n");
  154.     else if (aq == ASCII)
  155.       fprintf(outf, "\n");
  156.     
  157.     while(fgets(templine, MAXLINELENGTH, tempf) != NULL)
  158.       fprintf(outf, "%s", templine);
  159.     if (templine[(int)strlen(templine) - 1] != '\n')
  160.       fprintf(outf, "\n");
  161.     fcloselog(tempf, headerfile, "header file", ispipe);
  162.     
  163.     if (aq == ASCII) {
  164.       for (i = 0; i < pagewidth; i++)
  165.         fprintf(outf, "-");
  166.     }
  167.     
  168.     if (aq != PREFORMATTED)
  169.       fprintf(outf, "\n");
  170.  
  171.     html2 = OFF;
  172.       }
  173.     }
  174.  
  175.     if (aq == PREFORMATTED) {
  176.       if (xq) {
  177.     fprintf(outf, "x%sHN%s%s", presep, presep, hostname);
  178.     if (hosturl[0] != '-')
  179.       fprintf(outf, "\nx%sHU%s%s", presep, presep, hosturl);
  180.       }
  181.     }
  182.  
  183.   }   /* else (aq != CACHE) */
  184.  
  185.   /* Summary statistics */
  186.  
  187.   if (xq)
  188.     gensum(outf);
  189.   else if (aq == ASCII)
  190.     printf("\n");
  191.  
  192.   /* Now for the rest of the reports, in reportorder order */
  193.     
  194.   for (ro = reportorder; *ro != '\0'; ro++) {
  195.  
  196.     switch(*ro) {
  197.  
  198.     case 'm':    /* Monthly report */
  199.  
  200.       if (mq) {
  201.  
  202.     /* For forwards reports and (mrows > 0), must get the first month
  203.        correct (for backwards reports doesn't matter; can just count off
  204.        the correct number of months as we go (using j below). */
  205.  
  206.     /* NB This could be more efficient by not remembering months that
  207.        we're definitely not going to need (re-using those years in the
  208.        date hashing). Then we only ever need to move forward by at most
  209.        one year. We couldn't use firsttime for the earliest month recorded
  210.        though. */
  211.  
  212.     /* Another alternative would be to have TO times for each report
  213.        separately. (This would allow them for the general reports too).
  214.        It wouldn't, however, extend well to the weekly report. */
  215.  
  216.     if (!mback && mrows > 0) {  /* set year, monthno to 1st month wanted */
  217.       monthno = lasttime.year * 12 + lasttime.monthno - mrows + 1;
  218.       year = monthno / 12;
  219.       monthno %= 12;
  220.       if (year < firsttime.year ||
  221.           (year == firsttime.year && monthno <= firsttime.monthno)) {
  222.         mrows = 0;
  223.         monthno = 0;
  224.       }
  225.       else for (i = year - firsttime.year; i > 0; i--)
  226.         firstm = firstm -> next;    /* run firstm through enough years */
  227.     }
  228.     else
  229.       monthno = 0;
  230.  
  231.     if (aq != PREFORMATTED) {
  232.       maxreq = 0;
  233.       maxpages = 0;
  234.       maxbytes = 0.0;
  235.       finished = FALSE;
  236.       for (mp = mback?lastm:firstm; !finished; mp = mp -> next) {
  237.         for (i = (mp == firstm)?monthno:0; i < 12; i++) {
  238.           maxreq = MAX(maxreq, mp -> reqs[i]);
  239.           maxpages = MAX(maxpages, mp -> pages[i]);
  240.           maxbytes = MAX(maxbytes, mp -> bytes[i]);
  241.         }
  242.         if (mp == (mback?firstm:lastm))
  243.           finished = TRUE;
  244.       }
  245.       datehead(outf, maxreq, maxpages, maxbytes, mcols, &mgraph, "Monthly",
  246.            lngstr[monthrep_], lngstr[month_],
  247.            (int)htmlstrlen(monthname[0]) + 5, 'm', &munit, &fieldwidth,
  248.            &pfieldwidth, &bfieldwidth, &graphwidth, &bdivider);
  249.     }
  250.  
  251.     if (mback && mrows > 0)
  252.       j = mrows;
  253.     else
  254.       j = -1;
  255.     finished = FALSE;
  256.     if (mback || mrows <= 0)     /* else 'year' already calculated */
  257.       year = (mback?(&lasttime):(&firsttime)) -> year;
  258.     /* really (mback?lasttime:firsttime).year but some compilers choke */
  259.     for (mp = mback?lastm:firstm; !finished; mp = mp -> next) {
  260.       if (mp == firstm) {
  261.         if (!mback && mrows > 0)
  262.           firsti = monthno;
  263.         else
  264.           firsti = firsttime.monthno;
  265.         if (mback)
  266.           finished = TRUE;
  267.       }
  268.       else
  269.         firsti = 0;
  270.       if (mp == lastm) {
  271.         lasti = lasttime.monthno;
  272.         if (!mback)
  273.           finished = TRUE;
  274.       }
  275.       else
  276.         lasti = 11;
  277.       for (i = mback?lasti:firsti; (mback?(i >= firsti):(i <= lasti)) &&
  278.            j != 0; i += mback?(-1):1) {  /* thro months in chosen order */
  279.         if (aq == PREFORMATTED)
  280.           precols(outf, mcols, 'm', byq, ON);
  281.         else
  282.           fprintf(outf, "%s %d: ", monthname[i], year);
  283.         dateline(outf, mp -> reqs[i], mp -> pages[i], mp -> bytes[i],
  284.              mcols, mgraph, fieldwidth, pfieldwidth, bfieldwidth,
  285.              munit, bdivider);
  286.         if (aq == PREFORMATTED)
  287.           fprintf(outf, "%d%s%d\n", year, presep, i + 1);
  288.         j--;
  289.       }
  290.       year += mback?(-1):1;
  291.     }
  292.     
  293.     if (aq == ASCII)
  294.       asciiline(outf);
  295.     else if (aq == HTML)
  296.       fprintf(outf, "</tt></pre>");
  297.     
  298.       }
  299.  
  300.       break;
  301.       
  302.     case 'W':      /* Weekly report */
  303.  
  304.       if (Wq) {
  305.  
  306.     /* For the weekly report, we needn't worry about Wrows at this stage.
  307.        Becuase there is only one week per structure, we never allocate
  308.        more than are needed. */
  309.  
  310.     if (aq != PREFORMATTED) {
  311.       maxreq = 0;
  312.       maxpages = 0;
  313.       maxbytes = 0.0;
  314.       finished = FALSE;
  315.       for (wp = Wback?lastW:firstW; !finished; wp = wp -> next) {
  316.         maxreq = MAX(maxreq, wp -> reqs);
  317.         maxpages = MAX(maxpages, wp -> pages);
  318.         maxbytes = MAX(maxbytes, wp -> bytes);
  319.         if (wp == (Wback?firstW:lastW))
  320.           finished = TRUE;
  321.       }
  322.       datehead(outf, maxreq, maxpages, maxbytes, Wcols, &Wgraph, "Weekly",
  323.            lngstr[weekrep_], lngstr[weekbeg_],
  324.            (int)datefmtlen(lngstr[datefmt0_]), 'W', &Wunit,
  325.            &fieldwidth, &pfieldwidth, &bfieldwidth, &graphwidth,
  326.            &bdivider);
  327.     }
  328.  
  329.     finished = FALSE;
  330.     for (wp = Wback?lastW:firstW; !finished; wp = wp -> next) {
  331.       if (aq == PREFORMATTED)
  332.         precols(outf, Wcols, 'W', byq, ON);
  333.       else {
  334.         dateprintf(outf, lngstr[datefmt0_], wp -> start.date,
  335.                wp -> start.monthno, wp -> start.year, UNSET, UNSET);
  336.         fprintf(outf, ": ");
  337.       }
  338.       dateline(outf, wp -> reqs, wp -> pages, wp -> bytes, Wcols, Wgraph,
  339.            fieldwidth, pfieldwidth, bfieldwidth, Wunit, bdivider);
  340.       if (aq == PREFORMATTED)
  341.         fprintf(outf, "%d%s%d%s%d\n", wp -> start.year, presep,
  342.             wp -> start.monthno + 1, presep, wp -> start.date);
  343.       if (wp == (Wback?firstW:lastW))
  344.         finished = TRUE;
  345.       
  346.     }     /* end running through weeks */
  347.  
  348.     if (aq == ASCII)
  349.       asciiline(outf);
  350.     else if (aq == HTML)
  351.       fprintf(outf, "</tt></pre>");
  352.     
  353.       }   /* end if Wq */
  354.  
  355.       break;
  356.  
  357.     case 'd':      /* Daily summary */
  358.  
  359.       if (dq) {
  360.     
  361.     if (aq != PREFORMATTED) {
  362.       maxreq = 0;
  363.       maxpages = 0;
  364.       maxbytes = 0.0;
  365.       for (i = 0; i <= 6; i++) {
  366.         maxreq = MAX(maxreq, dreq[i]);
  367.         maxpages = MAX(maxpages, dpag[i]);
  368.         maxbytes = MAX(maxbytes, dbytes[i]);
  369.       }
  370.       datehead(outf, maxreq, maxpages, maxbytes, dcols, &dgraph, "Daily",
  371.            lngstr[daysum_], lngstr[day_], (int)htmlstrlen(dayname[0]),
  372.            'd', &dunit, &fieldwidth, &pfieldwidth, &bfieldwidth,
  373.            &graphwidth, &bdivider);
  374.     }
  375.  
  376.     for(i = 0; i <= 6; i++) {
  377.       j = (weekbeginson + i) % 7;
  378.       if (aq == PREFORMATTED)
  379.         precols(outf, dcols, 'd', byq, ON);
  380.       else
  381.         fprintf(outf, "%s: ", dayname[j]);
  382.       dateline(outf, dreq[j], dpag[j], dbytes[j], dcols, dgraph,
  383.            fieldwidth, pfieldwidth, bfieldwidth, dunit, bdivider);
  384.       if (aq == PREFORMATTED)
  385.         fprintf(outf, "%s\n", dayname[j]);
  386.     }
  387.     
  388.     if (aq == ASCII)
  389.       asciiline(outf);
  390.     else if (aq == HTML)
  391.       fprintf(outf, "</tt></pre>");
  392.     
  393.       }
  394.  
  395.       break;
  396.       
  397.     case 'D':       /* Full daily report */
  398.  
  399.       if (Dq) {
  400.  
  401.     /* For the daily report, we adopt a slightly different strategy to that
  402.        for the monthly report above. Rather than calculate the first day
  403.        explicitly, we move along the months until there are only the right
  404.        number of days left. */
  405.  
  406.     if (!Dback && Drows > 0) {
  407.       tempint = minsbetween(1, firsttime.monthno, firsttime.year, 0, 0,
  408.              lasttime.date, lasttime.monthno, lasttime.year, 0, 0) / 1440 + 1;
  409.       /* = days between start of first month, and last date, inc. */
  410.       monthno = firsttime.monthno;
  411.       year = firsttime.year;
  412.       if (tempint - firsttime.date < Drows) {
  413.         Drows = 0;
  414.         date = 1;
  415.       }
  416.       else {
  417.         while ((tempint -= monthlength[monthno] +
  418.             ISLEAPFEB(monthno, year)) > Drows) {
  419.           firstD = firstD -> next;
  420.           if (++monthno == 12) {
  421.         monthno = 0;
  422.         year++;
  423.           }
  424.         }      
  425.         date = tempint + monthlength[monthno] + ISLEAPFEB(monthno, year) -
  426.           Drows + 1;  /* when at right month, find initial date wanted */
  427.       }
  428.     }
  429.     else
  430.       date = 1;
  431.  
  432.     if (aq != PREFORMATTED) {
  433.       maxreq = 0;
  434.       maxpages = 0;
  435.       maxbytes = 0.0;
  436.       finished = FALSE;
  437.       for (dp = Dback?lastD:firstD; !finished; dp = dp -> next) {
  438.         for (i = (dp == firstD)?(date - 1):0; i < 31; i++) {
  439.           maxreq = MAX(maxreq, dp -> reqs[i]);
  440.           maxpages = MAX(maxpages, dp -> pages[i]);
  441.           maxbytes = MAX(maxbytes, dp -> bytes[i]);
  442.         }
  443.         if (dp == (Dback?firstD:lastD))
  444.           finished = TRUE;
  445.       }
  446.       datehead(outf, maxreq, maxpages, maxbytes, Dcols, &Dgraph,
  447.            "FullDaily", lngstr[dayrep_], lngstr[date_],
  448.            (int)datefmtlen(lngstr[datefmt0_]), 'D', &Dunit,
  449.            &fieldwidth, &pfieldwidth, &bfieldwidth, &graphwidth,
  450.            &bdivider);
  451.     }
  452.     
  453.     if (Dback && Drows > 0)
  454.       j = Drows;
  455.     else
  456.       j = -1;
  457.     finished = FALSE;
  458.     if (Dback || Drows <= 0) {  /* o/wise year and monthno already found */
  459.       year = (Dback?(&lasttime):(&firsttime)) -> year;
  460.       monthno = (Dback?(&lasttime):(&firsttime)) -> monthno;
  461.     }
  462.     for (dp = Dback?lastD:firstD; !finished; dp = dp -> next) {
  463.       if (dp == firstD) {
  464.         if (!Dback && Drows > 0)
  465.           firsti = date - 1;
  466.         else
  467.           firsti = firsttime.date - 1;
  468.         if (Dback)
  469.           finished = TRUE;
  470.       }
  471.       else
  472.         firsti = 0;
  473.       if (dp == lastD) {
  474.         lasti = lasttime.date - 1;
  475.         if (!Dback)
  476.           finished = TRUE;
  477.       }
  478.       else
  479.         lasti = monthlength[monthno] + ISLEAPFEB(monthno, year) - 1;
  480.       for (i = Dback?lasti:firsti; (Dback?(i >= firsti):(i <= lasti)) &&
  481.            j != 0; i += Dback?(-1):1) { /* thro days in chosen order */
  482.         if (aq == PREFORMATTED)
  483.           precols(outf, Dcols, 'D', byq, ON);
  484.         else {
  485.           dateprintf(outf, lngstr[datefmt0_], i + 1, monthno, year,
  486.              UNSET, UNSET);
  487.           fprintf(outf, ": ");
  488.         }
  489.         dateline(outf, dp -> reqs[i], dp -> pages[i], dp -> bytes[i],
  490.              Dcols, Dgraph, fieldwidth, pfieldwidth, bfieldwidth,
  491.              Dunit, bdivider);
  492.         if (aq == PREFORMATTED)
  493.           fprintf(outf, "%d%s%d%s%d\n", year, presep, monthno + 1, presep,
  494.               i + 1);
  495.         else if (((dayofdate(i + 1, monthno, year) + (!Dback)) % 7 ==
  496.             weekbeginson) && !(finished && i == (Dback?firsti:lasti)))
  497.           fprintf(outf, "\n");
  498.                          /* extra blank line after each week (not last) */
  499.         j--;
  500.       }
  501.  
  502.       if (Dback) {
  503.         if ((--monthno) == -1) {
  504.           monthno = 11;
  505.           --year;
  506.         }
  507.       }
  508.       else {
  509.         if ((++monthno) == 12) {
  510.           monthno = 0;
  511.           ++year;
  512.         }
  513.       }
  514.       
  515.     }     /* end running through dp's */
  516.  
  517.     if (aq == ASCII)
  518.       asciiline(outf);
  519.     else if (aq == HTML)
  520.       fprintf(outf, "</tt></pre>");
  521.     
  522.       }   /* end if Dq */
  523.  
  524.       break;
  525.  
  526.     case 'H':       /* Full hourly report */
  527.  
  528.       /* This is essentially like the daily report above */
  529.  
  530.       if (Hq) {
  531.  
  532.     if (!Hback && Hrows > 0) {
  533.       tempint = minsbetween(firsttime.date, firsttime.monthno,
  534.           firsttime.year, 0, 0, lasttime.date, lasttime.monthno,
  535.           lasttime.year, lasttime.hr, 0) / 60 + 1;
  536.       /* = hrs between start of first day, and last hr, inc. */
  537.       date = firsttime.date;
  538.       monthno = firsttime.monthno;
  539.       year = firsttime.year;
  540.       if (tempint - firsttime.hr < Hrows) {
  541.         Hrows = 0;
  542.         hr = 0;
  543.       }
  544.       else {
  545.         for ( ; tempint - Hrows > 23; tempint -= 24) {
  546.           firstH = firstH -> next;
  547.           if (++date > monthlength[monthno] + ISLEAPFEB(monthno, year)) {
  548.         date = 1;
  549.         if (++monthno == 12) {
  550.           monthno = 0;
  551.           year++;
  552.         }
  553.           }
  554.         }
  555.         hr = tempint - Hrows;
  556.       }
  557.     }
  558.     else
  559.       hr = 0;
  560.  
  561.     if (aq != PREFORMATTED) {
  562.       maxreq = 0;
  563.       maxpages = 0;
  564.       maxbytes = 0.0;
  565.       finished = FALSE;
  566.       for (hp = Hback?lastH:firstH; !finished; hp = hp -> next) {
  567.         for (i = ((hp == firstH)?hr:0); i < 24; i++) {
  568.           maxreq = MAX(maxreq, hp -> reqs[i]);
  569.           maxpages = MAX(maxpages, hp -> pages[i]);
  570.           maxbytes = MAX(maxbytes, hp -> bytes[i]);
  571.         }
  572.         if (hp == (Hback?firstH:lastH))
  573.           finished = TRUE;
  574.       }
  575.       sprintf(tempstr, "%s:%s", lngstr[date_], lngstr[hr_]);
  576.       if (aq != CACHE)
  577.         datehead(outf, maxreq, maxpages, maxbytes, Hcols, &Hgraph,
  578.              "FullHourly", lngstr[hourrep_], tempstr,
  579.              (int)datefmtlen(lngstr[datefmt0_]) + 3, 'H', &Hunit,
  580.              &fieldwidth, &pfieldwidth, &bfieldwidth, &graphwidth,
  581.              &bdivider);
  582.     }
  583.  
  584.     if (Hback && Hrows > 0)
  585.       j = Hrows;
  586.     else
  587.       j = -1;
  588.     finished = FALSE;
  589.     if (Hback || Hrows <= 0) {
  590.       year = (Hback?(&lasttime):(&firsttime)) -> year;
  591.       monthno = (Hback?(&lasttime):(&firsttime)) -> monthno;
  592.       date = (Hback?(&lasttime):(&firsttime)) -> date;
  593.     }
  594.     for (hp = Hback?lastH:firstH; !finished; hp = hp -> next) {
  595.       if (hp == firstH) {
  596.         if (!Hback && Hrows > 0)
  597.           firsti = hr;
  598.         else
  599.           firsti = firsttime.hr;
  600.         if (Hback)
  601.           finished = TRUE;
  602.       }
  603.       else
  604.         firsti = 0;
  605.       if (hp == lastH) {
  606.         lasti = lasttime.hr;
  607.         if (!Hback)
  608.           finished = TRUE;
  609.       }
  610.       else
  611.         lasti = 23;
  612.       for (i = Hback?lasti:firsti; (Hback?(i >= firsti):(i <= lasti)) &&
  613.            j != 0; i += Hback?(-1):1) {  /* through hrs in chosen order */
  614.         if (aq == CACHE) {
  615.           if (i == 0 || (hp == firstH && i == firsti))
  616.         fprintf(outf, "\n%d%02d%02d%02d", year, monthno + 1, date, i);
  617.           fprintf(outf, ":%d:%d:%.0f", hp -> reqs[i], hp -> pages[i],
  618.               hp -> bytes[i]);
  619.         }
  620.         else {
  621.           if (aq == PREFORMATTED)
  622.         precols(outf, Hcols, 'H', byq, ON);
  623.           else {
  624.         dateprintf(outf, lngstr[datefmt0_], date, monthno, year,
  625.                UNSET, UNSET);
  626.         fprintf(outf, ":%02d: ", i);
  627.           }
  628.           dateline(outf, hp -> reqs[i], hp -> pages[i], hp -> bytes[i],
  629.                Hcols, Hgraph, fieldwidth, pfieldwidth, bfieldwidth,
  630.                Hunit, bdivider);
  631.           if (aq == PREFORMATTED)
  632.         fprintf(outf, "%d%s%d%s%d%s%d\n", year, presep, monthno + 1,
  633.             presep, date, presep, i);
  634.           else if (i == (Hback?0:23) && !finished)
  635.         fprintf(outf, "\n");
  636.           /* extra blank line after each day (not last) */
  637.           j--;
  638.         }
  639.       }
  640.  
  641.       if (Hback) {
  642.         if ((--date) == 0) {
  643.           if ((--monthno) == -1) {
  644.         monthno = 11;
  645.         --year;
  646.           }
  647.           date = monthlength[monthno] + ISLEAPFEB(monthno, year);
  648.         }
  649.       }
  650.       else {
  651.         if ((++date) > monthlength[monthno] + ISLEAPFEB(monthno, year)) {
  652.           if ((++monthno) == 12) {
  653.         monthno = 0;
  654.         ++year;
  655.           }
  656.           date = 1;
  657.         }
  658.       }
  659.       
  660.     }     /* end running through hp's */
  661.  
  662.     if (aq == CACHE)
  663.       fprintf(outf, ":*\n");
  664.     else if (aq == ASCII)
  665.       asciiline(outf);
  666.     else if (aq == HTML)
  667.       fprintf(outf, "</tt></pre>");
  668.     
  669.       }   /* end if Hq */
  670.     
  671.       break;
  672.  
  673.     case 'h': /* Hourly summary */
  674.  
  675.       if (hq) {
  676.  
  677.     if (aq != PREFORMATTED) {
  678.       maxreq = 0;
  679.       maxpages = 0;
  680.       maxbytes = 0.0;
  681.       for (i = 0; i <= 23; i++) {
  682.         maxreq = MAX(maxreq, hreq[i]);
  683.         maxpages = MAX(maxpages, hpag[i]);
  684.         maxbytes = MAX(maxbytes, hbytes[i]);
  685.       }
  686.       datehead(outf, maxreq, maxpages, maxbytes, hcols, &hgraph, "Hourly",
  687.            lngstr[hoursum_], lngstr[hr_], 2, 'h', &hunit, &fieldwidth,
  688.            &pfieldwidth, &bfieldwidth, &graphwidth, &bdivider);
  689.     }
  690.  
  691.     for(i = 0; i <= 23; i++) {
  692.       if (aq == PREFORMATTED)
  693.         precols(outf, hcols, 'h', byq, ON);
  694.       else
  695.         fprintf(outf, "%2d: ", i);
  696.       dateline(outf, hreq[i], hpag[i], hbytes[i], hcols, hgraph,
  697.            fieldwidth, pfieldwidth, bfieldwidth, hunit, bdivider);
  698.       if (aq == PREFORMATTED)
  699.         fprintf(outf, "%d\n", i);
  700.     }
  701.     
  702.     if (aq == ASCII)
  703.       asciiline(outf);
  704.     else if (aq == HTML)
  705.       fprintf(outf, "</tt></pre>");
  706.     
  707.       }
  708.       
  709.       break;
  710.  
  711.     case 'o':    /* Domain report */
  712.  
  713.       if (oq)
  714.     domout(outf, firstdom);
  715.     
  716.       break;
  717.  
  718.     case 'S':    /* Host report */
  719.  
  720.       if (Sq) {
  721.      genout(outf, Ssorthead, total_succ_reqs, total_page_reqs, total_bytes,
  722.            Ssortby, Sminreqstr, Sminpagestr, Sminbytestr, Smaxreqs,
  723.            Smaxpages, Smaxbytes, Scols, "Host", lngstr[hostrep_],
  724.            lngstr[hostgs_], lngstr[hostgp_], lngstr[host_],
  725.            lngstr[hostgen_][0], 'S', Ssortby == ALPHABETICAL,
  726.            byq, ON, NULL, Soutaliashead, "");
  727.       }
  728.       break;
  729.  
  730.     case 'i':   /* Directory report */
  731.    
  732.       if (iq) {
  733.     genout(outf, isorthead, total_succ_reqs, total_page_reqs, total_bytes,
  734.            isortby, iminreqstr, iminpagestr, iminbytestr, imaxreqs,
  735.            imaxpages, imaxbytes, icols, "Directory", lngstr[dirrep_],
  736.            lngstr[dirgs_], lngstr[dirgp_], lngstr[dir_],
  737.            lngstr[dirgen_][0], 'i', FALSE, byq, ON, NULL,
  738.            ioutaliashead, "");
  739.       }
  740.       break;
  741.  
  742.     case 't':   /* File type report */
  743.    
  744.       if (tq) {
  745.     genout(outf, tsorthead, total_succ_reqs, total_page_reqs,
  746.            total_bytes, tsortby, tminreqstr, tminpagestr, tminbytestr,
  747.            tmaxreqs, tmaxpages, tmaxbytes, tcols, "FileType",
  748.            lngstr[typerep_], lngstr[extgs_], lngstr[extgp_], lngstr[ext_],
  749.            lngstr[extgen_][0], 't', FALSE, byq, ON, NULL,
  750.            toutaliashead, "");
  751.       }
  752.       break;
  753.  
  754.     case 'r':    /* Request report */
  755.       
  756.       if (rq) {
  757.     genout(outf, rsorthead, total_succ_reqs, total_page_reqs, total_bytes,
  758.            rsortby, rminreqstr, rminpagestr, rminbytestr, rmaxreqs,
  759.            rmaxpages, rmaxbytes, rcols, "Request", lngstr[reqrep_],
  760.            lngstr[filegs_], lngstr[filegp_], lngstr[file_],
  761.            lngstr[filegen_][0], 'r', FALSE, byq, ON,
  762.            (aq == HTML)?linkhead:NULL, routaliashead, baseurl);
  763.       }
  764.       break;
  765.  
  766.     case 'f':    /* Referrer report */
  767.  
  768.       if (fq) {
  769.     genout(outf, fsorthead, total_good_refs, total_ref_pages,
  770.            total_ref_bytes, fsortby, fminreqstr, fminpagestr, fminbytestr,
  771.            fmaxreqs, fmaxpages, fmaxbytes, fcols, "Referrer",
  772.            lngstr[refrep_], lngstr[refgs_], lngstr[refgp_], lngstr[url_],
  773.            lngstr[refgen_][0], 'f', FALSE, refbyq,
  774.            ON, (aq == HTML)?reflinkhead:NULL, foutaliashead, "");
  775.       }
  776.       break;
  777.  
  778.     case 'b':    /* Browser summary */
  779.  
  780.       if (bq) {
  781.     genout(outf, bsorthead, total_good_brows, total_brow_pages,
  782.            total_brow_bytes, bsortby, bminreqstr, bminpagestr,
  783.            bminbytestr, bmaxreqs, bmaxpages, bmaxbytes, bcols, "Browser",
  784.            lngstr[browsum_], lngstr[browgs_], lngstr[browgp_],
  785.            lngstr[browser_], lngstr[browgen_][0], 'b', FALSE,
  786.            browbyq, browbyq, NULL, boutaliashead, "");
  787.       }
  788.       break;
  789.       
  790.     case 'B':    /* Full browser report */
  791.  
  792.       if (Bq) {
  793.     genout(outf, Bsorthead, total_good_brows, total_brow_pages,
  794.            total_brow_bytes, Bsortby, Bminreqstr, Bminpagestr,
  795.            Bminbytestr, Bmaxreqs, Bmaxpages, Bmaxbytes, Bcols,
  796.            "FullBrowser", lngstr[browrep_], lngstr[browgs_],
  797.            lngstr[browgp_], lngstr[browser_], lngstr[browgen_][0], 'B',
  798.            FALSE, browbyq, browbyq, NULL, NULL, "");
  799.       }
  800.       break;
  801.  
  802.     case 'c':
  803.  
  804.       if (cq)
  805.     statusout(outf);
  806.       break;
  807.  
  808.     case 'e':
  809.  
  810.       if (eq)
  811.     errout(outf, errorder);
  812.       break;
  813.  
  814.     }    /* end switch */
  815.   }      /* end for ro */
  816.  
  817.   /*** Bit at the bottom of the page ***/
  818.  
  819.   if (aq != CACHE) {
  820.     if (aq != PREFORMATTED) {
  821.       if (!aq)
  822.       fprintf(outf, "\n\n<hr>\n<i>%s <a HREF=\"http://www.statslab.cam.ac.uk/~sret1/analog/\">analog%s</a>.\n", lngstr[credit_], VERSION);
  823.       else
  824.     fprintf(outf, "%s analog%s.\n", lngstr[credit_], VERSION);
  825.  
  826.       time(&stoptime);
  827.   
  828.       stoptime -= starttime;   /* so now measures elapsed time */
  829.  
  830.       if (stoptime == 0) {
  831.     if (aq == HTML)
  832.       fprintf(outf, "<br><b>%s%s</b> %s %s.</i>\n", lngstr[runtime_],
  833.           lngstr[colon_], lngstr[lessone_], lngstr[second_]);
  834.     else
  835.       fprintf(outf, "%s%s %s %s.\n", lngstr[runtime_], lngstr[colon_],
  836.           lngstr[lessone_], lngstr[second_]);
  837.       }
  838.  
  839.       else if (stoptime < 60) {
  840.     if (aq == HTML)
  841.       fprintf(outf, "<br><b>%s%s</b> %d %s.</i>\n",
  842.           lngstr[runtime_], lngstr[colon_], stoptime,
  843.           (stoptime == 1)?lngstr[second_]:lngstr[seconds_]);
  844.     else
  845.       fprintf(outf, "%s%s %d %s.\n", lngstr[runtime_], lngstr[colon_], 
  846.           stoptime, (stoptime == 1)?lngstr[second_]:lngstr[seconds_]);
  847.       }
  848.   
  849.       else {
  850.     if (aq == HTML)
  851.       fprintf(outf, "<br><b>%s%s</b> %d %s, %d %s.</i>\n",
  852.           lngstr[runtime_], lngstr[colon_], stoptime / 60,
  853.           (stoptime / 60 == 1)?lngstr[minute_]:lngstr[minutes_],
  854.           stoptime % 60,
  855.           (stoptime % 60 == 1)?lngstr[second_]:lngstr[seconds_]);
  856.     else
  857.       fprintf(outf, "%s%s %d %s, %d %s.\n",
  858.           lngstr[runtime_], lngstr[colon_], stoptime / 60,
  859.           (stoptime / 60 == 1)?lngstr[minute_]:lngstr[minutes_],
  860.           stoptime % 60,
  861.           (stoptime % 60 == 1)?lngstr[second_]:lngstr[seconds_]);
  862.       }
  863.   
  864.       if (!aq && (mq || Wq || dq || Dq || hq || oq || Sq || iq || rq)) {
  865.     gotos(outf, '\0');
  866.       }
  867.     }     /* end if aq != PREFORMATTED */
  868.  
  869.     /* Finally, insert footer file */
  870.  
  871.     if (!STREQ(footerfile, "none")) {
  872.       tempf = fopenlog(footerfile, "footer file", &ispipe);
  873.       if (tempf != NULL) {
  874.     if (aq == HTML)
  875.       fprintf(outf, "<hr>\n");
  876.     else if (aq == ASCII) {
  877.       for (i = 0; i < pagewidth; i++)
  878.         fprintf(outf, "-");
  879.       fprintf(outf, "\n\n");
  880.     }
  881.     fflush(stdout);
  882.  
  883.     while(fgets(templine, MAXLINELENGTH, tempf) != NULL)
  884.       fprintf(outf, "%s", templine);
  885.     if (templine[(int)strlen(templine) - 1] != '\n')
  886.       fprintf(outf, "\n");
  887.     fcloselog(tempf, footerfile, "footer file", ispipe);
  888.  
  889.     if (aq == HTML || aq == ASCII)
  890.       fprintf(outf, "\n");
  891.  
  892.     html2 = OFF;
  893.       }
  894.     }
  895.  
  896.     if (aq == HTML) {
  897.       if (html2) {
  898.     fprintf(outf,
  899.         "<P> <A HREF=\"http://www.webtechs.com/html-val-svc/\">\n");
  900.     fprintf(outf, "<IMG SRC=\"");
  901.     htmlfprintf(outf, imagedir);
  902.     fprintf(outf, "html2.gif\"\n");
  903.     fprintf(outf, "ALT=\"HTML 2.0 Conformant!\"></A>\n");
  904.       }
  905.       fprintf(outf, "\n</body>\n</html>\n");
  906.     }
  907.   }      /* end if aq != CACHE */
  908.  
  909.   fclose(outf);
  910.   if (debug > 0)
  911.     fprintf(stderr, "F: Closing %s\n", STREQ(outfile, "-")?"stdout":outfile);
  912.  
  913. }
  914.