/*** analog 1.9beta ***/ /* Please read Readme.html, or http://www.statslab.cam.ac.uk/~sret1/analog/ */ /*** output.c; the output functions, obviously. ***/ #include "analhea2.h" /*** The first function prints the "goto" line; links to all reports except possibly one (the one we're on). If called gotos('\0') won't omit one. If called gotos('z') will omit 'Top'. ***/ void gotos(FILE *outf, char c) { extern char reportorder[]; extern flag bq, Bq, cq, dq, Dq, eq, fq, hq, Hq, iq, mq, oq, rq, Sq, Wq, xq; char *i; if (xq) { fprintf(outf, "\n\n
(Go To"); if (c != 'z') fprintf(outf, ": Top"); for (i = reportorder; *i != '\0'; i++) { if (c != *i) { /* o/wise we don't want this one */ switch(*i) { case 'b': if (bq) fprintf(outf, ": Browser summary"); break; case 'B': if (Bq) fprintf(outf, ": Browser report"); break; case 'c': if (cq) fprintf(outf, ": Status code report"); break; case 'd': if (dq) fprintf(outf, ": Daily summary"); break; case 'D': if (Dq) fprintf(outf, ": Daily report"); break; case 'e': if (eq) fprintf(outf, ": Error report"); break; case 'f': if (fq) fprintf(outf, ": Referer report"); break; case 'H': if (Hq) fprintf(outf, ": Hourly report"); break; case 'h': if (hq) fprintf(outf, ": Hourly summary"); break; case 'i': if (iq) fprintf(outf, ": Directory report"); break; case 'm': if (mq) fprintf(outf, ": Monthly report"); break; case 'o': if (oq) fprintf(outf, ": Domain report"); break; case 'r': if (rq) fprintf(outf, ": Request report"); break; case 'S': if (Sq) fprintf(outf, ": Host report"); break; case 'W': if (Wq) fprintf(outf, ": Weekly report"); break; } /* end switch */ } /* end if this i wanted */ } /* end for i */ fprintf(outf, ")\n"); } /* end if xq */ } /* end function gotos() */ /*** Next, to print strings with HTML reserved characters translated ***/ void htmlputc(char c, FILE *outf) { if (c == '<') fprintf(outf, "<"); else if (c == '>') fprintf(outf, ">"); else if (c == '&') fprintf(outf, "&"); else if (c == '"') fprintf(outf, """); else putc(c, outf); } void htmlfprintf(FILE *outf, char string[MAXSTRINGLENGTH]) { char *c; for (c = string; *c != '\0'; c++) htmlputc(*c, outf); } /*** Now a little routine to find the correct divider for large numbers of bytes. Also sets bprefix[0] as a side effect. ***/ double finddivider(double bytes, char *bprefix) { extern flag rawbytes; double bdivider; if (rawbytes) bdivider = 1.0; else for (bdivider = 1; bytes / bdivider >= 999999.5; bdivider *= 1024) ; /* run bdivider to right multiplier */ if (bdivider == 1.0) *bprefix = '\0'; else if (bdivider == 1024.0) *bprefix = 'k'; else if (bdivider == 1048576.0) *bprefix = 'M'; else if (bdivider == 1073741824.0) *bprefix = 'G'; else if (bdivider == 1099511627776.0) *bprefix = 'T'; else /* 10^6 terabytes should be enough. Just about. */ *bprefix = '?'; return(bdivider); } /*** print a line across the page, assuming ASCII mode ***/ void asciiline(FILE *outf) { extern int pagewidth; int i; for (i = 0; i < pagewidth; i++) fprintf(outf, "-"); fprintf(outf, "\n\n"); } /*** a barchart bar, length n, within
***/
void barplot(FILE *outf, int n)
{
extern int aq;
extern flag graphical;
extern char imagedir[];
extern char markchar;
int i, k;
flag first = TRUE;
if (aq || !graphical) {
for ( ; n > 0; n--)
fprintf(outf, "%c", markchar);
}
else {
for (k = 32; k >= 1; k /= 2) {
while (n >= k) {
fprintf(outf, "
0; i--)
htmlputc(markchar, outf);
first = FALSE;
}
fprintf(outf, "\">");
n -= k;
}
}
}
}
/*** A nasty header bit. Return rough floor -- accurate if negative. ***/
int whatincluded(FILE *outf, int sortby, char *minreqstr, char *minbytestr,
char singular[20], char plural[21], flag subdoms)
{
extern double bytefloor(); /* in hash.c */
extern int reqfloor(); /* in hash.c */
extern void doublefprintf(); /* in utils.c */
extern double total_bytes;
extern int total_succ_reqs;
int genfloor;
int tempint;
char tempc;
if (sortby == BYBYTES) {
if (minbytestr[0] == '-') {
genfloor = (int)bytefloor(total_bytes, minbytestr);
if (genfloor == -1)
fprintf(outf, "Printing the first %s", singular);
else
fprintf(outf, "Printing the first %d %s", -genfloor, plural);
}
else {
fprintf(outf, "Printing all %s", plural);
genfloor = (int)(ceil(bytefloor(total_bytes, minbytestr)));
if (genfloor > 0) {
fprintf(outf, " with at least ");
tempint = MAX((int)strlen(minbytestr) - 1, 0);
if (minbytestr[tempint] == '%') {
minbytestr[tempint] = '\0';
doublefprintf(outf, atof(minbytestr));
fprintf(outf, "%% of the traffic");
}
else if (minbytestr[tempint] == 'k' || minbytestr[tempint] == 'M' ||
minbytestr[tempint] == 'G' || minbytestr[tempint] == 'T') {
tempc = minbytestr[tempint];
minbytestr[tempint] = '\0';
doublefprintf(outf, atof(minbytestr));
fprintf(outf, " %cbytes of traffic", tempc);
}
else {
doublefprintf(outf, atof(minbytestr));
fprintf(outf, " bytes of traffic");
}
}
}
if (subdoms)
fprintf(outf, ".\n");
else
fprintf(outf, ",%ssorted by amount of traffic.\n",
(genfloor > 0)?"\n ":" ");
}
else { /* sortby not BYBYTES */
genfloor = reqfloor(total_succ_reqs, minreqstr);
if (minreqstr[0] == '-') {
if (genfloor == -1)
fprintf(outf, "Printing the first %s", singular);
else
fprintf(outf, "Printing the first %d %s", -genfloor, plural);
}
else {
fprintf(outf, "Printing all %s", plural);
if (genfloor > 0) {
fprintf(outf, " with at least ");
tempint = MAX((int)strlen(minreqstr) - 1, 0);
if (minreqstr[tempint] == '%') {
minreqstr[tempint] = '\0';
doublefprintf(outf, atof(minreqstr));
fprintf(outf, "%% of the requests");
}
else
fprintf(outf, "%d request%s", atoi(minreqstr),
atoi(minreqstr) == 1?"":"s");
}
}
if (subdoms)
fprintf(outf, ".\n");
else if (sortby == BYREQUESTS)
fprintf(outf, ",%ssorted by number of requests.\n",
(genfloor > 0)?"\n ":" ");
else if (sortby == ALPHABETICAL)
fprintf(outf, ",%ssorted alphabetically.\n", (genfloor > 0)?"\n ":" ");
else
fprintf(outf, ", unsorted.\n");
}
return(genfloor);
}
/*** Generic output function for generic objects ***/
void genout(FILE *outf, struct genstruct *sorthead, int tot_reqs,
double tot_bytes, int sortby, char *minreqstr, char *minbytestr,
int max_reqs, double max_bytes, char *wantcols, char anchor[10],
char title[17], char singular[13], char plural[14],
char codeletter, flag alphahost, /* alphabetical host sort? */
flag byq, int kq, /* pagelinks? */ char baseurl[MAXSTRINGLENGTH]) {
extern char *reversehostname(); /* in alias.c */
extern flag included(); /* in alias.c */
extern int pagewidth;
extern int dirlevel;
extern int Smaxlength;
extern int aq;
extern flag rawbytes;
extern struct include *ispagehead;
struct genstruct *p;
int fieldwidth, bfieldwidth, graphwidth;
int genfloor;
double bdivider;
char bprefix[2];
char *cols;
double pc;
int pc1, pc2;
int i, j, tempint;
char *tempc;
bprefix[0] = '\0';
bprefix[1] = '\0';
if (!aq) {
fprintf(outf,
"\n\n
\n%s
\n\n", anchor, title);
gotos(outf, codeletter);
fprintf(outf, "");
}
else {
fprintf(outf, "%s\n", title);
for (tempc = title; *tempc != '\0'; tempc++)
fprintf(outf, "-");
fprintf(outf, "\n");
}
genfloor = whatincluded(outf, sortby, minreqstr, minbytestr, singular,
plural, FALSE);
if (codeletter == 'i') {
if (!aq)
fprintf(outf, "
");
fprintf(outf, "Printing directories to depth %d.\n", dirlevel);
}
if (aq)
fprintf(outf, "\n");
else
fprintf(outf, "
");
tempint = 10000;
for (fieldwidth = 5; max_reqs / tempint >= 10; fieldwidth++)
tempint *= 10;
if (byq) {
if (rawbytes) {
tempint = 100000;
for (bfieldwidth = 6; max_bytes / tempint >= 10; bfieldwidth++)
tempint *= 10;
}
else
bfieldwidth = 6;
bdivider = finddivider(max_bytes, bprefix);
}
for (cols = wantcols; *cols != '\0'; cols++) {
switch(*cols) {
case 'R':
for (i = 5; i < fieldwidth; i++)
fprintf(outf, " ");
fprintf(outf, "#reqs: ");
break;
case 'r':
fprintf(outf, " %%reqs: ");
break;
case 'B':
if (byq) {
for (i = 6; i < bfieldwidth; i++)
fprintf(outf, " ");
fprintf(outf, "%sbytes: ", bprefix[0] == '\0'?" ":bprefix);
}
break;
case 'b':
if (byq)
fprintf(outf, "%%bytes: ");
break;
}
}
fprintf(outf, "%s\n", singular);
for (cols = wantcols; *cols != '\0'; cols++) {
switch(*cols) {
case 'R':
for (i = 1; i <= fieldwidth; i++)
fprintf(outf, "-");
fprintf(outf, " ");
break;
case 'r':
fprintf(outf, "------ ");
break;
case 'B':
if (byq) {
for (i = 1; i <= bfieldwidth; i++)
fprintf(outf, "-");
fprintf(outf, " ");
}
break;
case 'b':
if (byq)
fprintf(outf, "------ ");
break;
}
}
for (tempc = singular; *tempc != '\0'; tempc++)
fprintf(outf, "-");
fprintf(outf, "\n");
if (genfloor < 0)
j = genfloor;
else j = 1;
if (alphahost) {
graphwidth = pagewidth;
for (cols = wantcols; *cols != '\0'; cols++) {
switch(*cols) {
case 'R':
graphwidth -= fieldwidth + 2;
break;
case 'B':
graphwidth -= bfieldwidth + 2;
break;
case 'r':
case 'b':
graphwidth -= 8;
break;
}
}
graphwidth = MIN(graphwidth, Smaxlength);
}
for(p = sorthead; p -> name != NULL && (j++) != 0;
p = p -> next) {
for (cols = wantcols; *cols != '\0'; cols++) {
switch(*cols) {
case 'R':
fprintf(outf, "%*d: ", fieldwidth, p -> reqs);
break;
case 'r':
pc = (p -> reqs + 0.0) / ((tot_reqs + 0.0) / 10000);
pc1 = ((int)(pc + 0.5)) / 100; /* whole no. of %reqs */
pc2 = ((int)(pc + 0.5)) % 100; /* remaining 100ths. */
if (pc1 == 100)
fprintf(outf, " 100%%: ");
else if (pc1 > 0 || pc2 > 0)
fprintf(outf, "%2d.%02d%%: ", pc1, pc2);
else
fprintf(outf, " : ");
break;
case 'B':
if (byq) {
if (p -> bytes / bdivider > 0.5)
fprintf(outf, "%*.0lf", bfieldwidth, p -> bytes / bdivider);
else for (i = 0; i < bfieldwidth; i++)
fprintf(outf, " ");
fprintf(outf, ": ");
}
break;
case 'b':
if (byq) {
pc = p -> bytes / (tot_bytes / 10000);
pc1 = ((int)(pc + 0.5)) / 100; /* whole no. of %bytes */
pc2 = ((int)(pc + 0.5)) % 100; /* remaining 100ths. */
if (pc1 == 100)
fprintf(outf, " 100%%: ");
else if (pc1 > 0 || pc2 > 0)
fprintf(outf, "%2d.%02d%%: ", pc1, pc2);
else
fprintf(outf, " : ");
}
break;
}
}
if (alphahost && !isdigit(p -> name[0])) { /* we've swapped the names */
reversehostname(p -> name);
/* Also in that case right align names */
for (i = graphwidth - (int)strlen(p -> name); i > 0; i--)
fprintf(outf, " ");
}
if ((kq == 2) ||
/* if we want to link to everything ... */
(kq == 1 && included(p -> name, ispagehead))) {
/* or it is a page, and we want to link to pages */
fprintf(outf, " name);
fprintf(outf, "\">");
htmlfprintf(outf, p -> name);
fprintf(outf, "");
}
else /* (the usual case for most reports) */
if (!aq)
htmlfprintf(outf, p -> name);
else
fprintf(outf, "%s", p -> name);
fprintf(outf, "\n");
}
if (aq)
asciiline(outf);
else
fprintf(outf, "");
}
/*** The domain report is similar to the generic ones. It differs in that
the domains are stored in a different structure, and that subdomains
must be printed. ***/
void domout(FILE *outf, int firstdom)
{
extern struct domain *ohead[];
extern int aq;
extern flag byq, rawbytes;
extern int osortby;
extern char ominbytestr[], ominreqstr[];
extern char Ominbytestr[], Ominreqstr[];
extern int omaxreqs;
extern double omaxbytes;
extern int Onumber;
extern char ocols[];
extern double total_bytes;
extern int total_succ_reqs;
int ofloor;
struct domain *p;
double bdivider;
char bprefix[2];
char *cols;
int fieldwidth, bfieldwidth;
double pc;
int pc1, pc2;
int i, j, k, tempint;
char *tempp;
bprefix[0] = '\0';
bprefix[1] = '\0';
if (!aq) {
fprintf(outf,
"\n\n
\nDomain Report
\n\n");
gotos(outf, 'o');
}
else {
fprintf(outf, "Domain Report\n");
fprintf(outf, "-------------\n");
}
if (!aq)
fprintf(outf, "");
ofloor = whatincluded(outf, osortby, ominreqstr, ominbytestr, "domain",
"domains", FALSE);
if (Onumber > 0) {
if (!aq)
fprintf(outf, "
");
whatincluded(outf, osortby, Ominreqstr, Ominbytestr, "requested subdomain",
"requested subdomains", TRUE);
}
if (aq)
fprintf(outf, "\n");
else
fprintf(outf, "
");
tempint = 10000;
for (fieldwidth = 5; omaxreqs / tempint >= 10; fieldwidth++)
tempint *= 10;
if (byq) {
if (rawbytes) {
tempint = 100000;
for (bfieldwidth = 6; omaxbytes / tempint >= 10; bfieldwidth++)
tempint *= 10;
}
else
bfieldwidth = 6;
bdivider = finddivider(omaxbytes, bprefix);
}
for (cols = ocols; *cols != '\0'; cols++) {
switch(*cols) {
case 'R':
for (i = 5; i < fieldwidth; i++)
fprintf(outf, " ");
if (Onumber > 0)
fprintf(outf, " #reqs : ");
else
fprintf(outf, "#reqs: ");
break;
case 'r':
if (Onumber > 0)
fprintf(outf, " %%reqs : ");
else
fprintf(outf, " %%reqs: ");
break;
case 'B':
if (byq) {
for (i = 6; i < bfieldwidth; i++)
fprintf(outf, " ");
if (Onumber > 0)
fprintf(outf, " %sbytes : ", bprefix[0] == '\0'?" ":bprefix);
else
fprintf(outf, "%sbytes: ", bprefix[0] == '\0'?" ":bprefix);
}
break;
case 'b':
if (byq) {
if (Onumber > 0)
fprintf(outf, " %%bytes : ");
else
fprintf(outf, "%%bytes: ");
}
break;
}
}
fprintf(outf, "domain\n");
for (cols = ocols; *cols != '\0'; cols++) {
switch(*cols) {
case 'R':
for (i = 1; i <= fieldwidth; i++)
fprintf(outf, "-");
if (Onumber > 0)
fprintf(outf, "--");
fprintf(outf, " ");
break;
case 'r':
if (Onumber > 0)
fprintf(outf, "--");
fprintf(outf, "------ ");
break;
case 'B':
if (byq) {
for (i = 1; i <= bfieldwidth; i++)
fprintf(outf, "-");
if (Onumber > 0)
fprintf(outf, "--");
fprintf(outf, " ");
}
break;
case 'b':
if (byq) {
if (Onumber > 0)
fprintf(outf, "--");
fprintf(outf, "------ ");
}
break;
}
}
fprintf(outf, "------\n");
if (ofloor < 0)
j = ofloor;
else j = 1;
for (i = firstdom; i >= 0 && (j++) != 0; i = ohead[i] -> nexti) {
if (!(i == DOMHASHSIZE - 2 && ohead[i] -> reqs == -1)) {
for (cols = ocols; *cols != '\0'; cols++) {
switch(*cols) {
case 'R':
if (Onumber > 0)
fprintf(outf, " %*d : ", fieldwidth, ohead[i] -> reqs);
else
fprintf(outf, "%*d: ", fieldwidth, ohead[i] -> reqs);
break;
case 'r':
pc = (ohead[i] -> reqs + 0.0) / ((total_succ_reqs + 0.0) / 10000);
pc1 = ((int)(pc + 0.5)) / 100; /* whole no. of %reqs */
pc2 = ((int)(pc + 0.5)) % 100; /* remaining 100ths. */
if (Onumber > 0)
fprintf(outf, " ");
if (pc1 == 100)
fprintf(outf, " 100%%");
else if (pc1 > 0 || pc2 > 0)
fprintf(outf, "%2d.%02d%%", pc1, pc2);
else
fprintf(outf, " ");
if (Onumber > 0)
fprintf(outf, " : ");
else
fprintf(outf, ": ");
break;
case 'B':
if (byq) {
if (ohead[i] -> bytes / bdivider > 0.5) {
if (Onumber > 0)
fprintf(outf, " %*.0lf ", bfieldwidth,
ohead[i] -> bytes / bdivider);
else
fprintf(outf, "%*.0lf", bfieldwidth,
ohead[i] -> bytes / bdivider);
}
else for (k = 0; k < bfieldwidth + 2 * (Onumber > 0); k++)
fprintf(outf, " ");
fprintf(outf, ": ");
}
break;
case 'b':
if (byq) {
pc = ohead[i] -> bytes / (total_bytes / 10000);
pc1 = ((int)(pc + 0.5)) / 100; /* whole no. of %bytes */
pc2 = ((int)(pc + 0.5)) % 100; /* remaining 100ths. */
if (Onumber > 0)
fprintf(outf, " ");
if (pc1 == 100)
fprintf(outf, " 100%%");
else if (pc1 > 0 || pc2 > 0)
fprintf(outf, "%2d.%02d%%", pc1, pc2);
else
fprintf(outf, " ");
if (Onumber > 0)
fprintf(outf, " : ");
else
fprintf(outf, ": ");
}
break;
}
}
if (ohead[i] -> id[0] == '*')
/* flagged domains, not real domain names */
fprintf(outf, "[%s]\n", ohead[i] -> name);
else if (ohead[i] -> name[0] == '?')
/* real domain, but don't print name */
fprintf(outf, ".%s\n", ohead[i] -> id);
else
fprintf(outf, ".%s (%s)\n", ohead[i] -> id, ohead[i] -> name);
/* Now print its subdomains too. */
for (p = ohead[i] -> next; p -> name != NULL;
p = p -> next) {
for (cols = ocols; *cols != '\0'; cols++) {
switch(*cols) {
case 'R':
fprintf(outf, "(%*d): ", fieldwidth, p -> reqs);
break;
case 'r':
pc = (p -> reqs + 0.0) /
((total_succ_reqs + 0.0) / 10000);
pc1 = ((int)(pc + 0.5)) / 100; /* whole no. of %reqs */
pc2 = ((int)(pc + 0.5)) % 100; /* remaining 100ths. */
if (pc1 == 100)
fprintf(outf, "( 100%%): ");
else if (pc1 > 0 || pc2 > 0)
fprintf(outf, "(%2d.%02d%%): ", pc1, pc2);
else
fprintf(outf, " : ");
break;
case 'B':
if (byq) {
if (p -> bytes / bdivider > 0.5)
fprintf(outf, "(%*.0lf)", bfieldwidth, p -> bytes / bdivider);
else for (k = 0; k < bfieldwidth + 2; k++)
fprintf(outf, " ");
fprintf(outf, ": ");
}
break;
case 'b':
if (byq) {
pc = p -> bytes / (total_bytes / 10000);
pc1 = ((int)(pc + 0.5)) / 100; /* whole no. of %bytes */
pc2 = ((int)(pc + 0.5)) % 100; /* remaining 100ths. */
if (pc1 == 100)
fprintf(outf, "( 100%%): ");
else if (pc1 > 0 || pc2 > 0)
fprintf(outf, "(%2d.%02d%%): ", pc1, pc2);
else
fprintf(outf, " : ");
}
break;
}
}
tempp = p -> id;
while ((tempp = strchr(tempp, '.')) != NULL) {
fprintf(outf, " ");
/* print two spaces for each dot in name */
tempp++;
}
if (i == DOMHASHSIZE - 1)
fprintf(outf, " "); /* + 2 more for numerical domains */
fprintf(outf, "%s", p -> id);
if (p -> name[0] != '?') /* print name */
fprintf(outf, " (%s)", p -> name);
fprintf(outf, "\n");
} /* end for domp */
}
} /* end for (i = running over domains) */
if (aq)
asciiline(outf);
else
fprintf(outf, "");
}
/*** The date reports aren't quite generic enough to combine completely,
but we can go a long way towards it. ***/
/*** First a function for printing out the headers of a report and finding
the fieldwidths etc.; then one for printing out each individual line. ***/
void datehead(FILE *outf, int maxreq, double maxbytes,
char *wantcols, char *graphtype, char anchor[11],
char title[15], char colhead[13], char codeletter,
int *unit, int *fieldwidth, int *bfieldwidth, int *graphwidth,
double *bdivider) /* NB: colhead: inc. leading spaces. */
/* The last 5 args are returned altered */
{
extern void int3printf(); /* in utils.c */
extern int aq;
extern flag byq, rawbytes, graphical;
extern int pagewidth;
extern char imagedir[];
extern char markchar;
char *cols;
char bprefix[2];
int i, j, tempint;
char *tempc;
bprefix[0] = '\0';
bprefix[1] = '\0';
if (*graphtype == 'b')
*graphtype = 'B';
if (!aq) {
fprintf(outf, "
\n%s
\n", anchor, title);
gotos(outf, codeletter);
}
else {
fprintf(outf, "%s\n", title);
for (tempc = title; *tempc != '\0'; tempc++)
fprintf(outf, "-");
fprintf(outf, "\n");
}
tempint = 10000;
for (*fieldwidth = 5; maxreq / tempint >= 10; (*fieldwidth)++)
tempint *= 10; /* so fieldwidth is log_10(maxreq), but >= 5 */
if (byq) {
if (rawbytes || (*graphtype == 'B' && *unit > 0)) {
tempint = 100000;
for (*bfieldwidth = 6; maxbytes / tempint >= 10; (*bfieldwidth)++)
tempint *= 10;
}
else
*bfieldwidth = 6;
*bdivider = finddivider(maxbytes, bprefix);
}
if (*unit <= 0) { /* (o/wise just use the given amount) */
/* Calculate the graphwidth */
*graphwidth = pagewidth - (int)strlen(colhead) - 2;
for (cols = wantcols; *cols != '\0'; cols++) {
switch(*cols) {
case 'R':
*graphwidth -= *fieldwidth + 2;
break;
case 'B':
*graphwidth -= *bfieldwidth + 2;
break;
case 'r':
case 'b':
*graphwidth -= 8;
break;
}
}
*graphwidth = MAX(*graphwidth, MINGRAPHWIDTH); /* must be >= MGW wide */
if (*graphtype == 'B')
*unit = (maxbytes - 1) / (*bdivider * *graphwidth);
else
*unit = (maxreq - 1) / *graphwidth;
/* except we want a 'nice' amount, so ... */
/* (Nice amount is 1, 1.5, 2, 2.5, 3, 4, 5, 6, 8 * 10^n */
j = 0;
while (*unit > 24) {
*unit /= 10;
j++;
}
if (*unit == 6)
*unit = 7;
else if (*unit == 8)
*unit = 9;
else if (*unit >= 20)
*unit = 24;
else if (*unit >= 15)
*unit = 19;
else if (*unit >= 10)
*unit = 14;
(*unit)++;
for (i = 0; i < j; i++) {
*unit *= 10;
}
} /* end if (*unit <= 0) */
else if (*graphtype == 'B') { /* o/wise unit doesn't make sense */
*bdivider = 1;
bprefix[0] = '\0';
}
if (!aq)
fprintf(outf, "\n");
if (!aq && graphical) {
fprintf(outf, "Each unit (
) represents ");
int3printf(outf, *unit);
if (*graphtype == 'B')
fprintf(outf, " %sbyte%s, or part thereof.", bprefix,
(*unit == 1)?"":"s");
else
fprintf(outf, " request%s.\n\n", (*unit == 1)?"":"s, or part thereof");
}
else {
fprintf(outf, "\nEach unit (%c) represents ", markchar);
int3printf(outf, *unit);
if (*graphtype == 'B')
fprintf(outf, " %sbyte%s, or part thereof.\n\n", bprefix,
(*unit == 1)?"":"s");
else
fprintf(outf, " request%s.\n\n",
(*unit == 1)?"":"s, or part thereof");
}
if (!aq)
fprintf(outf, "
\n", pagewidth);
fprintf(outf, "%s: ", colhead);
for (cols = wantcols; *cols != '\0'; cols++) {
switch(*cols) {
case 'R':
for (i = 5; i < *fieldwidth; i++)
fprintf(outf, " ");
fprintf(outf, "#reqs: ");
break;
case 'r':
fprintf(outf, " %%reqs: ");
break;
case 'B':
if (byq) {
for (i = 6; i < *bfieldwidth; i++)
fprintf(outf, " ");
fprintf(outf, "%sbytes: ", bprefix[0] == '\0'?" ":bprefix);
}
break;
case 'b':
if (byq)
fprintf(outf, "%%bytes: ");
break;
}
}
fprintf(outf, "\n");
for (tempc = colhead; *tempc != '\0'; tempc++)
fprintf(outf, "-");
fprintf(outf, " ");
for (cols = wantcols; *cols != '\0'; cols++) {
switch(*cols) {
case 'R':
for (i = 1; i <= *fieldwidth; i++)
fprintf(outf, "-");
fprintf(outf, " ");
break;
case 'r':
fprintf(outf, "------ ");
break;
case 'B':
if (byq) {
for (i = 1; i <= *bfieldwidth; i++)
fprintf(outf, "-");
fprintf(outf, " ");
}
break;
case 'b':
if (byq)
fprintf(outf, "------ ");
break;
}
}
fprintf(outf, "\n");
}
/* As promised, each separate line. We print name of date in output() though */
void dateline(FILE *outf, int reqs, double bytes, char *wantcols,
char graphtype, int fieldwidth, int bfieldwidth,
int unit, double bdivider) {
extern double total_bytes;
extern int total_succ_reqs;
extern flag byq;
char *cols;
double pc;
int pc1, pc2;
for (cols = wantcols; *cols != '\0'; cols++) {
switch(*cols) {
case 'R':
fprintf(outf, "%*d: ", fieldwidth, reqs);
break;
case 'r':
pc = (reqs + 0.0) / ((total_succ_reqs + 0.0) / 10000);
pc1 = ((int)(pc + 0.5)) / 100; /* whole no. of %reqs */
pc2 = ((int)(pc + 0.5)) % 100; /* remaining 100ths. */
if (pc1 == 100)
fprintf(outf, " 100%%: ");
else if (pc1 > 0 || pc2 > 0)
fprintf(outf, "%2d.%02d%%: ", pc1, pc2);
else
fprintf(outf, " : ");
break;
case 'B':
if (byq)
fprintf(outf, "%*.0lf: ", bfieldwidth, bytes / bdivider);
break;
case 'b':
if (byq) {
pc = bytes / (total_bytes / 10000);
pc1 = ((int)(pc + 0.5)) / 100; /* whole no. of %bytes */
pc2 = ((int)(pc + 0.5)) % 100; /* remaining 100ths. */
if (pc1 == 100)
fprintf(outf, " 100%%: ");
else if (pc1 > 0 || pc2 > 0)
fprintf(outf, "%2d.%02d%%: ", pc1, pc2);
else
fprintf(outf, " : ");
}
break;
}
}
if (graphtype == 'B')
barplot(outf, (int)(ceil(bytes / (unit * bdivider))));
else
barplot(outf, (reqs == 0)?0:((reqs - 1) / unit) + 1);
fprintf(outf, "\n");
}
/*** The status code report (very simple) ***/
void statusout(FILE *outf)
{
extern int status[], statusnos[];
extern char statusstrs[NO_STATUS][MAXSTATUSLENGTH];
extern int aq;
int fieldwidth;
int maxreqs = 0;
int i;
for (i = 0; i < NO_STATUS; i++)
maxreqs = MAX(maxreqs, status[i]);
if (!aq) {
fprintf(outf, "\n\n
\nStatus Code Report
\n\n");
gotos(outf, 'c');
fprintf(outf, "");
}
else
fprintf(outf, "Status Code Report\n------------------\n\n");
i = 10000;
for (fieldwidth = 5; maxreqs / i >= 10; fieldwidth++)
i *= 10;
for (i = 5; i < fieldwidth; i++)
fprintf(outf, " ");
fprintf(outf, "#occs: no. description\n");
for (i = 0; i < fieldwidth; i++)
fprintf(outf, "-");
fprintf(outf, " ---------------\n");
for (i = 0; i < NO_STATUS; i++) {
if (status[i] > 0) {
if (statusstrs[i][0] == '0')
fprintf(outf, "%*d: %s\n", fieldwidth, status[i], statusstrs[i]);
else
fprintf(outf, "%*d: %d %s\n", fieldwidth, status[i], statusnos[i],
statusstrs[i]);
}
}
if (aq)
asciiline(outf);
else
fprintf(outf, "");
}
/*** Finally in the individual report printing, the error report ***/
void errout(FILE *outf, int errorder[NO_ERRS])
{
extern int errors[NO_ERRS];
extern char errs[NO_ERRS][MAXERRLENGTH];
extern int eminreqs;
extern int aq;
int fieldwidth;
int i;
if (errors[errorder[0]] >= eminreqs) { /* o/wise no report */
if (!aq) {
fprintf(outf,
"\n\n
\nError Report
\n\n");
gotos(outf, 'e');
fprintf(outf, "");
}
else
fprintf(outf, "Error Report\n------------\n");
if (eminreqs == 0)
fprintf(outf, "Printing all possible errors, ");
else
fprintf(outf, "Printing all errors with at least %d occurence%s,\n",
eminreqs, (eminreqs == 1)?"":"s");
fprintf(outf, " sorted by number of occurrences.");
if (aq)
fprintf(outf, "\n\n");
else
fprintf(outf, "
");
i = 10000;
for (fieldwidth = 5; errors[errorder[0]] / i >= 10; fieldwidth++)
i *= 10;
for (i = 5; i < fieldwidth; i++)
fprintf(outf, " ");
fprintf(outf, "#occs: error type\n");
for (i = 0; i < fieldwidth; i++)
fprintf(outf, "-");
fprintf(outf, " ----------\n");
for (i = 0; errors[errorder[i]] >= eminreqs && i < NO_ERRS; i++)
fprintf(outf, "%*d: %s\n", fieldwidth, errors[errorder[i]],
(errs[errorder[i]][0] == '\0')?"[unknown]":errs[errorder[i]]);
if (aq)
asciiline(outf);
else
fprintf(outf, "");
}
}
/*** Now the main output function which calls all that stuff ***/
void output(struct genstruct *rsorthead, struct genstruct *isorthead,
struct genstruct *Ssorthead, int firstdom,
struct genstruct *fsorthead, struct genstruct *bsorthead,
struct genstruct *Bsorthead, int errorder[])
{
extern int dayofdate(); /* in utils.c */
extern int minsbetween(); /* in utils.c */
extern void int3printf(); /* in utils.c */
extern void double3printf(); /* in utils.c */
extern char outfile[];
extern char dayname[7][4];
extern char monthname[12][4];
extern int monthlength[];
extern char hostname[];
extern char logourl[];
extern char hosturl[];
extern char commandname[];
extern char headerfile[];
extern char footerfile[];
extern char reportorder[];
extern flag q7, byq, refbyq, browbyq, kq, warnq;
extern flag mback, Dback, Wback, Hback;
extern flag xq, dq, Dq, Wq, hq, Hq, mq, Sq, rq, oq, iq, fq, bq, Bq, cq, eq;
extern int sq, aq;
extern char starttimestr[];
extern struct timestruct firsttime, lasttime, oldtime, totime, starttimec;
extern time_t starttime, stoptime;
extern int weekbeginson;
extern struct monthly *firstm, *lastm;
extern struct weekly *firstW, *lastW;
extern struct daily *firstD, *lastD;
extern struct hourly *firstH, *lastH;
extern int dreq[], hreq[];
extern double dbytes[], hbytes[];
extern int munit, Wunit, hunit, Hunit, dunit, Dunit;
extern int corrupt_lines, other_lines;
extern int no_urls, no_hosts, no_urls7, no_hosts7, no_new_hosts7;
extern double total_bytes, total_bytes7;
extern double total_ref_bytes, total_brow_bytes;
extern int total_succ_reqs, total_fail_reqs, total_other_reqs;
extern int total_succ_reqs7, total_fail_reqs7, total_other_reqs7;
extern int total_good_refs, total_good_brows;
extern int pagewidth;
extern int Ssortby, rsortby, isortby, fsortby, bsortby, Bsortby;
extern char Sminreqstr[], rminreqstr[], iminreqstr[], fminreqstr[];
extern char bminreqstr[], Bminreqstr[];
extern char Sminbytestr[], rminbytestr[], iminbytestr[], fminbytestr[];
extern char bminbytestr[], Bminbytestr[];
extern char mgraph, dgraph, Dgraph, hgraph, Hgraph, Wgraph;
extern char mcols[], dcols[], Dcols[], hcols[], Wcols[], Hcols[];
extern char rcols[], icols[], Scols[], fcols[], bcols[], Bcols[];
extern char imagedir[], baseurl[];
extern int reqtype;
extern int imaxreqs, Smaxreqs, rmaxreqs, fmaxreqs, bmaxreqs, Bmaxreqs;
extern double imaxbytes, Smaxbytes, rmaxbytes, fmaxbytes, bmaxbytes;
extern double Bmaxbytes;
FILE *outf; /* the output file */
int totalmins; /* between first and last entries analysed */
int fieldwidth; /* Width we require to print #reqs in */
int bfieldwidth; /* #bytes ditto */
char bprefix[2]; /* kilo, Mega, etc. */
int graphwidth; /* the width left for a graph after columns written */
struct monthly *mp;
struct daily *dp;
struct weekly *wp;
struct hourly *hp;
int maxreq; /* within a particular date report */
double maxbytes;
double bdivider;
int year, monthno, date;
flag finished;
int i, j, firsti, lasti;
char *ro;
char templine[MAXLINELENGTH];
FILE *tempf;
bprefix[0] = '\0';
bprefix[1] = '\0';
if (STREQ(outfile, "stdout"))
outf = stdout;
else if ((outf = fopen(outfile, "w")) == NULL) {
fprintf(stderr, "%s: Error: failed to open output file %s for writing.\n",
commandname, outfile);
exit(ERR); /* shouldn't get here because also tested at the beginning */
} /* (unless it's vanished in the meantime or something) */
if (aq == CACHE)
fprintf(outf,
"CACHE type 1 produced by analog%s. Do not modify or delete!",
VERSION);
else {
if (!aq) {
fprintf(outf, "\nWeb Server Statistics for ");
htmlfprintf(outf, hostname);
fprintf(outf, " \n");
fprintf(outf, "\n");
if (!STREQ(logourl, "none")) {
fprintf(outf, "
");
}
if (hosturl[0] == '-') {
fprintf(outf, "Web Server Statistics for ");
htmlfprintf(outf, hostname);
}
else {
fprintf(outf, "Web Server Statistics for ");
htmlfprintf(outf, hostname);
fprintf(outf, "");
}
fprintf(outf, "
\n\n");
}
else {
fprintf(outf, "Web Server Statistics for %s\n", hostname);
fprintf(outf, "==========================");
for (i = (int)strlen(hostname); i > 0; i--)
fprintf(outf, "=");
fprintf(outf, "\n");
}
/* insert header file */
headerfile[MAXSTRINGLENGTH - 5] = '\0'; /* for safety */
if (!STREQ(headerfile, "none")) {
if ((tempf = fopen(headerfile, "r")) == NULL) {
if (warnq)
fprintf(stderr,
"%s: Warning: Failed to open headerfile %s: ignoring it.\n",
commandname, headerfile);
}
else { /* can open header file */
if (!aq)
fprintf(outf, "
");
else
fprintf(outf, "\n");
while(fgets(templine, MAXLINELENGTH, tempf) != NULL)
fprintf(outf, "%s", templine);
fclose(tempf);
if (templine[(int)strlen(templine) - 1] != '\n')
fprintf(outf, "\n");
if (aq) {
for (i = 0; i < pagewidth; i++)
fprintf(outf, "-");
}
fprintf(outf, "\n");
}
}
}
/* Summary statistics */
if (xq) {
if (!aq)
fprintf(outf, "
");
fprintf(outf,
"\nProgram started at %c%c%c-%c%c-%c%c%c-%c%c%c%c %c%c:%c%c local time.\n",
starttimestr[0], starttimestr[1], starttimestr[2],
(starttimestr[8]==' ')?'0':starttimestr[8], starttimestr[9],
starttimestr[4], starttimestr[5], starttimestr[6],
starttimestr[20], starttimestr[21], starttimestr[22],
starttimestr[23],
starttimestr[11], starttimestr[12],
starttimestr[14], starttimestr[15]);
if (firsttime.code > oldtime.code)
q7 = OFF;
if (total_succ_reqs > 0) {
totalmins = minsbetween(firsttime.date, firsttime.monthno, firsttime.year,
firsttime.hr, firsttime.min,
lasttime.date, lasttime.monthno, lasttime.year,
lasttime.hr, lasttime.min) + 1;
if (!aq)
fprintf(outf, "
");
fprintf(outf,
"Analysed requests from %s-%02d-%s-%d %02d:%02d to %s-%02d-%s-%d %02d:%02d\n (%.1f days).\n\n",
dayname[dayofdate(firsttime.date,
firsttime.monthno, firsttime.year)],
firsttime.date, monthname[firsttime.monthno], firsttime.year,
firsttime.hr, firsttime.min,
dayname[dayofdate(lasttime.date, lasttime.monthno,
lasttime.year)],
lasttime.date, monthname[lasttime.monthno], lasttime.year,
lasttime.hr, lasttime.min,
(double)totalmins / 1440.0);
}
if (!aq)
fprintf(outf, "Total completed requests: ");
else
fprintf(outf, "Total completed requests: ");
int3printf(outf, total_succ_reqs);
if (q7) {
fprintf(outf, " (");
int3printf(outf, total_succ_reqs7);
fprintf(outf, ")");
}
if (totalmins > 30) {
if (!aq)
fprintf(outf, "\n
Average completed requests per day: ");
else
fprintf(outf, "\nAverage completed requests per day: ");
if (total_succ_reqs < 2)
fprintf(outf, "0");
else
double3printf(outf, ((double)(total_succ_reqs - 1)) * 1440.0 / (totalmins + 0.0));
if (q7) {
fprintf(outf, " (");
int3printf(outf, total_succ_reqs7 / 7);
fprintf(outf, ")");
}
}
if (total_fail_reqs > 0) {
if (!aq)
fprintf(outf, "\n
Total failed requests: ");
else
fprintf(outf, "\nTotal failed requests: ");
int3printf(outf, total_fail_reqs);
if (q7) {
fprintf(outf, " (");
int3printf(outf, total_fail_reqs7);
fprintf(outf, ")");
}
}
if (total_other_reqs > 0) {
if (!aq)
fprintf(outf, "\n
Total redirected requests: ");
else
fprintf(outf, "\nTotal redirected requests: ");
int3printf(outf, total_other_reqs);
if (q7) {
fprintf(outf, " (");
int3printf(outf, total_other_reqs7);
fprintf(outf, ")");
}
}
if (rq) { /* These data are not collected o/wise (rq => this > 0) */
if (!aq)
fprintf(outf, "\n
Number of distinct files requested: ");
else
fprintf(outf, "\nNumber of distinct files requested: ");
int3printf(outf, no_urls);
if (q7) {
fprintf(outf, " (");
int3printf(outf, no_urls7);
fprintf(outf, ")");
}
}
if ((sq == ON || sq == APPROX) && no_hosts > 0) {
if (!aq)
fprintf(outf, "\n
%sumber of distinct hosts served: ",
(sq == ON)?"N":"Approximate n");
else
fprintf(outf, "\n%sumber of distinct hosts served: ",
(sq == ON)?"N":"Approximate n");
int3printf(outf, no_hosts);
if (q7) {
fprintf(outf, " (");
int3printf(outf, no_hosts7);
fprintf(outf, ")");
if (!aq)
fprintf(outf,
"\n
%sumber of new hosts served in last 7 days: ",
(sq == ON)?"N":"Approximate n");
else
fprintf(outf, "\n%sumber of new hosts served in last 7 days: ",
(sq == ON)?"N":"Approximate n");
int3printf(outf, no_new_hosts7);
}
}
if (corrupt_lines > 0) {
if (!aq)
fprintf(outf, "\n
Corrupt logfile lines: ");
else
fprintf(outf, "\nCorrupt logfile lines: ");
int3printf(outf, corrupt_lines);
}
if (other_lines > 0) {
if (!aq)
fprintf(outf, "\n
Unwanted logfile entries: ");
else
fprintf(outf, "\nUnwanted logfile entries: ");
int3printf(outf, other_lines);
}
if (byq) {
if (!aq)
fprintf(outf, "\n
Total data transferred: ");
else
fprintf(outf, "\nTotal data transferred: ");
bdivider = finddivider(total_bytes, bprefix);
double3printf(outf, ROUND(total_bytes / bdivider));
fprintf(outf, " %sbytes", bprefix);
if (q7) {
fprintf(outf, " (");
bdivider = finddivider(total_bytes7, bprefix);
double3printf(outf, ROUND(total_bytes7 / bdivider));
fprintf(outf, " %sbytes)", bprefix);
}
if (totalmins > 30) {
if (!aq)
fprintf(outf, "\n
Average data transferred per day: ");
else
fprintf(outf, "\nAverage data transferred per day: ");
bdivider = finddivider((total_bytes * 1440) / (totalmins + 0.0),
bprefix);
double3printf(outf,
ROUND((total_bytes * 1440) / (totalmins + 0.0) / bdivider));
fprintf(outf, " %sbytes", bprefix);
if (q7) {
fprintf(outf, " (");
bdivider = finddivider(total_bytes7 / 7.0, bprefix);
double3printf(outf, ROUND(total_bytes7 / 7.0 / bdivider));
fprintf(outf, " %sbytes)", bprefix);
}
}
}
if (q7) {
if (!aq)
fprintf(outf, "\n
");
else
fprintf(outf, "\n");
fprintf(outf, "(Figures in parentheses refer to the ");
if (starttimec.code > totime.code)
fprintf(outf, "7 days to %02d-%s-%4d).", totime.date,
monthname[totime.monthno], totime.year);
else
fprintf(outf, "last 7 days).");
}
if (!aq && (mq || Wq || dq || Dq || hq || oq || Sq || iq || rq))
gotos(outf, 'z');
if (aq) {
fprintf(outf, "\n");
asciiline(outf);
}
} /* end if xq */
else if (aq == ASCII)
printf("\n");
/* Now for the rest of the reports, in reportorder order */
for (ro = reportorder; *ro != '\0'; ro++) {
switch(*ro) {
case 'm': /* Monthly report */
if (mq) {
maxreq = 0;
maxbytes = 0.0;
finished = FALSE;
for (mp = mback?lastm:firstm; !finished; mp = mp -> next) {
for (i = 0; i < 12; i++) {
maxreq = MAX(maxreq, mp -> reqs[i]);
maxbytes = MAX(maxbytes, mp -> bytes[i]);
}
if (mp == (mback?firstm:lastm))
finished = TRUE;
}
datehead(outf, maxreq, maxbytes, mcols, &mgraph, "Monthly",
"Monthly Report", " month", 'm', &munit, &fieldwidth,
&bfieldwidth, &graphwidth, &bdivider);
finished = FALSE;
year = (mback?lasttime:firsttime).year;
for (mp = mback?lastm:firstm; !finished; mp = mp -> next) {
if (mp == firstm) {
firsti = firsttime.monthno;
if (mback)
finished = TRUE;
}
else
firsti = 0;
if (mp == lastm) {
lasti = lasttime.monthno;
if (!mback)
finished = TRUE;
}
else
lasti = 11;
for (i = mback?lasti:firsti; mback?(i >= firsti):(i <= lasti);
i += mback?(-1):1) { /* run through months in chosen order */
fprintf(outf, "%s %d: ", monthname[i], year);
dateline(outf, mp -> reqs[i], mp -> bytes[i], mcols, mgraph,
fieldwidth, bfieldwidth, munit, bdivider);
}
year += mback?(-1):1;
}
if (aq)
asciiline(outf);
else
fprintf(outf, "
");
}
break;
case 'W': /* Weekly report */
if (Wq) {
maxreq = 0;
maxbytes = 0.0;
finished = FALSE;
for (wp = Wback?lastW:firstW; !finished; wp = wp -> next) {
maxreq = MAX(maxreq, wp -> reqs);
maxbytes = MAX(maxbytes, wp -> bytes);
if (wp == (Wback?firstW:lastW))
finished = TRUE;
}
datehead(outf, maxreq, maxbytes, Wcols, &Wgraph, "Weekly",
"Weekly Report", "week beg.", 'W', &Wunit, &fieldwidth,
&bfieldwidth, &graphwidth, &bdivider);
finished = FALSE;
for (wp = Wback?lastW:firstW; !finished; wp = wp -> next) {
fprintf(outf, "%2d/%s/%02d: ", wp -> start.date,
monthname[wp -> start.monthno], wp -> start.year % 100);
dateline(outf, wp -> reqs, wp -> bytes, Wcols, Wgraph, fieldwidth,
bfieldwidth, Wunit, bdivider);
if (wp == (Wback?firstW:lastW))
finished = TRUE;
} /* end running through weeks */
if (aq)
asciiline(outf);
else
fprintf(outf, "");
} /* end if Wq */
break;
case 'd': /* Daily summary */
if (dq) {
maxreq = 0;
maxbytes = 0.0;
for (i = 0; i <= 6; i++) {
maxreq = MAX(maxreq, dreq[i]);
maxbytes = MAX(maxbytes, dbytes[i]);
}
datehead(outf, maxreq, maxbytes, dcols, &dgraph, "Daily",
"Daily Summary", "day", 'd', &dunit, &fieldwidth,
&bfieldwidth, &graphwidth, &bdivider);
for(i = 0; i <= 6; i++) {
j = (weekbeginson + i) % 7;
fprintf(outf, "%s: ", dayname[j]);
dateline(outf, dreq[j], dbytes[j], dcols, dgraph, fieldwidth,
bfieldwidth, dunit, bdivider);
}
if (aq)
asciiline(outf);
else
fprintf(outf, "");
}
break;
case 'D': /* Full daily report */
if (Dq) {
maxreq = 0;
maxbytes = 0.0;
finished = FALSE;
for (dp = Dback?lastD:firstD; !finished; dp = dp -> next) {
for (i = 0; i < 31; i++) {
maxreq = MAX(maxreq, dp -> reqs[i]);
maxbytes = MAX(maxbytes, dp -> bytes[i]);
}
if (dp == (Dback?firstD:lastD))
finished = TRUE;
}
datehead(outf, maxreq, maxbytes, Dcols, &Dgraph, "FullDaily",
"Daily Report", " date", 'D', &Dunit, &fieldwidth,
&bfieldwidth, &graphwidth, &bdivider);
finished = FALSE;
year = (Dback?lasttime:firsttime).year;
monthno = (Dback?lasttime:firsttime).monthno;
for (dp = Dback?lastD:firstD; !finished; dp = dp -> next) {
if (dp == firstD) {
firsti = firsttime.date - 1;
if (Dback)
finished = TRUE;
}
else
firsti = 0;
if (dp == lastD) {
lasti = lasttime.date - 1;
if (!Dback)
finished = TRUE;
}
else
lasti = monthlength[monthno] + ISLEAPFEB(monthno, year) - 1;
for (i = Dback?lasti:firsti; Dback?(i >= firsti):(i <= lasti);
i += Dback?(-1):1) { /* run through days in chosen order */
fprintf(outf, "%2d/%s/%02d: ", i + 1, monthname[monthno],
year % 100);
dateline(outf, dp -> reqs[i], dp -> bytes[i], Dcols, Dgraph,
fieldwidth, bfieldwidth, Dunit, bdivider);
if (((dayofdate(i + 1, monthno, year) + (!Dback)) % 7 ==
weekbeginson) && !(finished && i == (Dback?firsti:lasti)))
fprintf(outf, "\n");
/* extra blank line after each week (not last) */
}
if (Dback) {
if ((--monthno) == -1) {
monthno = 11;
--year;
}
}
else {
if ((++monthno) == 12) {
monthno = 0;
++year;
}
}
} /* end running through dp's */
if (aq)
asciiline(outf);
else
fprintf(outf, "");
} /* end if Dq */
break;
case 'H': /* Full hourly report */
if (Hq) {
maxreq = 0;
maxbytes = 0.0;
finished = FALSE;
for (hp = Hback?lastH:firstH; !finished; hp = hp -> next) {
for (i = 0; i < 24; i++) {
maxreq = MAX(maxreq, hp -> reqs[i]);
maxbytes = MAX(maxbytes, hp -> bytes[i]);
}
if (hp == (Hback?firstH:lastH))
finished = TRUE;
}
if (aq != CACHE)
datehead(outf, maxreq, maxbytes, Hcols, &Hgraph, "FullHourly",
"Hourly Report", " date:hr", 'H', &Hunit, &fieldwidth,
&bfieldwidth, &graphwidth, &bdivider);
finished = FALSE;
year = (Hback?lasttime:firsttime).year;
monthno = (Hback?lasttime:firsttime).monthno;
date = (Hback?lasttime:firsttime).date;
for (hp = Hback?lastH:firstH; !finished; hp = hp -> next) {
if (hp == firstH) {
firsti = firsttime.hr;
if (Hback)
finished = TRUE;
}
else
firsti = 0;
if (hp == lastH) {
lasti = lasttime.hr;
if (!Hback)
finished = TRUE;
}
else
lasti = 23;
for (i = Hback?lasti:firsti; Hback?(i >= firsti):(i <= lasti);
i += Hback?(-1):1) { /* run through hours in chosen order */
if (aq == CACHE) {
if (i == 0 || (hp == firstH && i == firsti))
fprintf(outf, "\n%d%02d%02d%02d", year, monthno + 1, date, i);
fprintf(outf, ":%d:%.0lf", hp -> reqs[i], hp -> bytes[i]);
}
else {
fprintf(outf, "%2d/%s/%02d:%02d: ", date, monthname[monthno],
year % 100, i);
dateline(outf, hp -> reqs[i], hp -> bytes[i], Hcols, Hgraph,
fieldwidth, bfieldwidth, Hunit, bdivider);
if (i == (Hback?0:23) && !finished)
fprintf(outf, "\n");
/* extra blank line after each day (not last) */
}
}
if (Hback) {
if ((--date) == 0) {
if ((--monthno) == -1) {
monthno = 11;
--year;
}
date = monthlength[monthno] + ISLEAPFEB(monthno, year);
}
}
else {
if ((++date) > monthlength[monthno] + ISLEAPFEB(monthno, year)) {
if ((++monthno) == 12) {
monthno = 0;
++year;
}
date = 1;
}
}
} /* end running through hp's */
if (aq == CACHE)
fprintf(outf, ":*\n");
else if (aq)
asciiline(outf);
else if (!aq)
fprintf(outf, "");
} /* end if Hq */
break;
case 'h': /* Hourly summary */
if (hq) {
maxreq = 0;
maxbytes = 0.0;
for (i = 0; i <= 23; i++) {
maxreq = MAX(maxreq, hreq[i]);
maxbytes = MAX(maxbytes, hbytes[i]);
}
datehead(outf, maxreq, maxbytes, hcols, &hgraph, "Hourly",
"Hourly Summary", "hr", 'h', &hunit, &fieldwidth,
&bfieldwidth, &graphwidth, &bdivider);
for(i = 0; i <= 23; i++) {
fprintf(outf, "%2d: ", i);
dateline(outf, hreq[i], hbytes[i], hcols, hgraph, fieldwidth,
bfieldwidth, hunit, bdivider);
}
if (aq)
asciiline(outf);
else
fprintf(outf, "");
}
break;
case 'o': /* Domain report */
if (oq)
domout(outf, firstdom);
break;
case 'S': /* Host report */
if (Sq)
genout(outf, Ssorthead, total_succ_reqs, total_bytes, Ssortby,
Sminreqstr, Sminbytestr, Smaxreqs, Smaxbytes, Scols, "Host",
"Host Report", "host", "hosts", 'S', Ssortby == ALPHABETICAL,
byq, OFF, "");
break;
case 'i': /* Directory report */
if (iq)
genout(outf, isorthead, total_succ_reqs, total_bytes, isortby,
iminreqstr, iminbytestr, imaxreqs, imaxbytes, icols,
"Directory", "Directory Report", "directory", "directories",
'i', FALSE, byq, OFF, "");
break;
case 'r': /* Request report */
if (rq) {
if (aq)
kq = 0; /* no links in ASCII output! */
else if (reqtype == PAGES && kq == 1)
kq = 2; /* If only printing pages, any linked = all linked */
genout(outf, rsorthead, total_succ_reqs, total_bytes, rsortby,
rminreqstr, rminbytestr, rmaxreqs, rmaxbytes, rcols, "Request",
"Request Report", (reqtype == PAGES)?"page":"file",
(reqtype == PAGES)?"pages":"files", 'r', FALSE, byq, kq,
baseurl);
}
break;
case 'f': /* Referer report */
if (fq)
genout(outf, fsorthead, total_good_refs, total_ref_bytes, fsortby,
fminreqstr, fminbytestr, fmaxreqs, fmaxbytes, fcols,
"Referer", "Referer Report", "refering URL", "refering URLs",
'f', FALSE, refbyq, !aq, "");
break;
case 'b': /* Browser summary */
if (bq)
genout(outf, bsorthead, total_good_brows, total_brow_bytes, bsortby,
bminreqstr, bminbytestr, bmaxreqs, bmaxbytes, bcols, "Browser",
"Browser Summary", "browser", "browsers", 'b', FALSE, browbyq,
OFF, "");
break;
case 'B': /* Full browser report */
if (Bq)
genout(outf, Bsorthead, total_good_brows, total_brow_bytes, Bsortby,
Bminreqstr, Bminbytestr, Bmaxreqs, Bmaxbytes, Bcols,
"FullBrowser", "Browser Report", "browser", "browsers", 'B',
FALSE, browbyq, OFF, "");
break;
case 'c':
if (cq)
statusout(outf);
break;
case 'e':
if (eq)
errout(outf, errorder);
break;
} /* end switch */
} /* end for ro */
/*** Bit at the bottom of the page ***/
if (aq != CACHE) {
if (!aq)
fprintf(outf, "\n\n \n");
fprintf(outf, "\n");
}
fprintf(outf, "\n\n\n");
}
}
fclose(outf);
}