/*** 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" /* A few variables global to this file */ int total_succ_reqs, total_fail_reqs, total_other_reqs; int total_succ_reqs7, total_fail_reqs7, total_other_reqs7; /*** 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;

  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 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 host_max_length;
  extern int aq;
  extern flag rawbytes;
  extern double total_bytes;
  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, host_max_length);
  }

  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) / ((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 (i = 0; i < bfieldwidth; i++)
	    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;
      }
    }
    
    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, 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 *domainhead[]; extern int aq; extern flag byq, rawbytes; extern int domsortby; extern char domminbytestr[], domminreqstr[]; extern char subdomminbytestr[], subdomminreqstr[]; extern int dom_max_reqs; extern double dom_max_bytes; extern int subonumber; extern char domcols[]; extern double total_bytes; int domfloor; struct domain *domp; 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
\n

Domain Report

\n\n"); gotos(outf, 'o'); } else { fprintf(outf, "Domain Report\n"); fprintf(outf, "-------------\n"); } if (!aq) fprintf(outf, "

"); domfloor = whatincluded(outf, domsortby, domminreqstr, domminbytestr, "domain", "domains", FALSE); if (subonumber > 0) { if (!aq) fprintf(outf, "
"); whatincluded(outf, domsortby, subdomminreqstr, subdomminbytestr, "requested subdomain", "requested subdomains", TRUE); } if (aq) fprintf(outf, "\n"); else fprintf(outf, "

");
  
  tempint = 10000;
  for (fieldwidth = 5; dom_max_reqs / tempint >= 10; fieldwidth++)
    tempint *= 10;
  
  if (byq) {
    if (rawbytes) {
      tempint = 100000;
      for (bfieldwidth = 6; dom_max_bytes / tempint >= 10; bfieldwidth++)
	tempint *= 10;
    }
    else
      bfieldwidth = 6;

    bdivider = finddivider(dom_max_bytes, bprefix);
  }
  
  for (cols = domcols; *cols != '\0'; cols++) {
    switch(*cols) {
    case 'R':
      for (i = 5; i < fieldwidth; i++)
	fprintf(outf, " ");
      if (subonumber > 0)
	fprintf(outf, " #reqs : ");
      else
	fprintf(outf, "#reqs: ");
      break;
    case 'r':
      if (subonumber > 0)
	fprintf(outf, "  %%reqs : ");
      else
	fprintf(outf, " %%reqs: ");
      break;
    case 'B':
      if (byq) {
	for (i = 6; i < bfieldwidth; i++)
	  fprintf(outf, " ");
	if (subonumber > 0)
	  fprintf(outf, " %sbytes : ", bprefix[0] == '\0'?" ":bprefix);
	else
	  fprintf(outf, "%sbytes: ", bprefix[0] == '\0'?" ":bprefix);
      }
      break;
    case 'b':
      if (byq) {
	if (subonumber > 0)
	  fprintf(outf, " %%bytes : ");
	else
	  fprintf(outf, "%%bytes: ");
      }
      break;
    }
  }
  fprintf(outf, "domain\n");

  for (cols = domcols; *cols != '\0'; cols++) {
    switch(*cols) {
    case 'R':
      for (i = 1; i <= fieldwidth; i++)
	fprintf(outf, "-");
      if (subonumber > 0)
	fprintf(outf, "--");
      fprintf(outf, "  ");
      break;
    case 'r':
      if (subonumber > 0)
	fprintf(outf, "--");
      fprintf(outf, "------  ");
      break;
    case 'B':
      if (byq) {
	for (i = 1; i <= bfieldwidth; i++)
	  fprintf(outf, "-");
	if (subonumber > 0)
	  fprintf(outf, "--");
	fprintf(outf, "  ");
      }
      break;
    case 'b':
      if (byq) {
	if (subonumber > 0)
	  fprintf(outf, "--");
	fprintf(outf, "------  ");
      }
	    break;
    }
 } 
  fprintf(outf, "------\n");

  if (domfloor < 0)
    j = domfloor;
  else j = 1;

  for (i = firstdom; i >= 0 && (j++) != 0; i = domainhead[i] -> nexti) {

    if (!(i == DOMHASHSIZE - 2 && domainhead[i] -> reqs == -1)) {

      for (cols = domcols; *cols != '\0'; cols++) {
	switch(*cols) {
	case 'R':
	  if (subonumber > 0)
	    fprintf(outf, " %*d : ", fieldwidth,
		    domainhead[i] -> reqs);
	  else
	    fprintf(outf, "%*d: ", fieldwidth, domainhead[i] -> reqs);
	  break;
	case 'r':
	  pc = (domainhead[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 (subonumber > 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 (subonumber > 0)
	    fprintf(outf, " : ");
	  else
	    fprintf(outf, ": ");
	  break;
	case 'B':
	  if (byq) {
	    if (domainhead[i] -> bytes / bdivider > 0.5) {
	      if (subonumber > 0)
		fprintf(outf, " %*.0lf ", bfieldwidth,
			domainhead[i] -> bytes / bdivider);
	      else
		fprintf(outf, "%*.0lf", bfieldwidth,
			domainhead[i] -> bytes / bdivider);
	    }
	    else for (k = 0; k < bfieldwidth + 2 * (subonumber > 0); k++)
		fprintf(outf, " ");
	    fprintf(outf, ": ");
	  }
	  break;
	case 'b':
	  if (byq) {
	    pc = domainhead[i] -> bytes / (total_bytes / 10000);
	    pc1 = ((int)(pc + 0.5)) / 100;    /* whole no. of %bytes */
	    pc2 = ((int)(pc + 0.5)) % 100;    /* remaining 100ths. */
	    if (subonumber > 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 (subonumber > 0)
	      fprintf(outf, " : ");
	    else
	      fprintf(outf, ": ");
	  }
	  break;
	}
      }
      
      if (domainhead[i] -> id[0] == '*')
	/* flagged domains, not real domain names */
	fprintf(outf, "[%s]\n", domainhead[i] -> name);
      else if (domainhead[i] -> name[0] == '?')
	/* real domain, but don't print name */
	fprintf(outf, ".%s\n", domainhead[i] -> id);
      else
	fprintf(outf, ".%s (%s)\n", domainhead[i] -> id,
		domainhead[i] -> name);
      
      /* Now print its subdomains too. */
      
      for (domp = domainhead[i] -> next; domp -> name != NULL;
	   domp = domp -> next) {
	
	for (cols = domcols; *cols != '\0'; cols++) {
	  switch(*cols) {
	  case 'R':
	    fprintf(outf, "(%*d): ", fieldwidth, domp -> reqs);
	    break;
	  case 'r':
	    pc = (domp -> 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 (domp -> bytes / bdivider > 0.5)
		fprintf(outf, "(%*.0lf)", bfieldwidth,
			domp -> bytes / bdivider);
	      else for (k = 0; k < bfieldwidth + 2; k++)
		fprintf(outf, " ");
	      fprintf(outf, ": ");
	    }
	    break;
	  case 'b':
	    if (byq) {
	      pc = domp -> 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 = domp -> 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", domp -> id);
	
	if (domp -> name[0] != '?')    /* print name */
	  fprintf(outf, " (%s)", domp -> 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; 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

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.", (*unit == 1)?"":"s, or part thereof"); fprintf(outf, "\n\n

\n", pagewidth);
  }
  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");
  }
	
  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, int bdivider) {
  extern double total_bytes;
  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
\n

Status 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 errminreqs; extern int aq; int fieldwidth; int i; if (errors[errorder[0]] >= errminreqs) { /* o/wise no report */ if (!aq) { fprintf(outf, "\n\n
\n

Error Report

\n\n"); gotos(outf, 'e'); fprintf(outf, "

"); } else fprintf(outf, "Error Report\n------------\n"); if (errminreqs == 0) fprintf(outf, "Printing all possible errors, "); else fprintf(outf, "Printing all errors with at least %d occurence%s,\n", errminreqs, (errminreqs == 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]] >= errminreqs && 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 *urlsorthead, struct genstruct *dirsorthead, struct genstruct *hostsorthead, int firstdom, struct genstruct *refsorthead, struct genstruct *browsorthead, struct genstruct *fullbrowsorthead, 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 dailyreq[], hourlyreq[]; extern double dailybytes[], hourlybytes[]; extern int monthlyunit, weeklyunit, hourlyunit, fullhourlyunit, dailyunit; extern int fulldailyunit; extern int cachereqs, cachereqs7, corrupt_lines, other_lines; extern int no_urls, no_hosts, no_urls7, no_hosts7, no_new_hosts7; extern double total_bytes, total_bytes7; extern int pagewidth; extern int hostsortby, reqsortby, dirsortby; extern int refsortby, browsortby, fullbrowsortby; extern char hostminreqstr[], urlminreqstr[], dirminreqstr[], refminreqstr[]; extern char browminreqstr[], fullbrowminreqstr[]; extern char hostminbytestr[], urlminbytestr[], dirminbytestr[]; extern char refminbytestr[], browminbytestr[], fullbrowminbytestr[]; extern char monthgraph, daygraph, fulldaygraph, hourgraph, fullhourgraph; extern char weekgraph; extern char monthcols[], daycols[], fulldaycols[], hourcols[], weekcols[]; extern char fullhourcols[], reqcols[], dircols[], hostcols[], refcols[]; extern char browcols[], fullbrowcols[]; extern char imagedir[], baseurl[]; extern int reqtype; extern int status[], status7[], statusnos[]; extern int dir_max_reqs, host_max_reqs, url_max_reqs, ref_max_reqs, brow_max_reqs, fullbrow_max_reqs; extern double dir_max_bytes, host_max_bytes, url_max_bytes; 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 tempstr[MAXSTRINGLENGTH]; FILE *tempf; bprefix[0] = '\0'; bprefix[1] = '\0'; total_succ_reqs = cachereqs; total_fail_reqs = 0; total_other_reqs = 0; total_succ_reqs7 = cachereqs7; total_fail_reqs7 = 0; total_other_reqs7 = 0; for (i = 0; i < NO_STATUS; i++) { if (statusnos[i] <= 299 || statusnos[i] == 304) { total_succ_reqs += status[i]; total_succ_reqs7 += status7[i]; } else if (statusnos[i] <= 399) { total_other_reqs += status[i]; total_other_reqs7 += status7[i]; } else { total_fail_reqs += status[i]; total_fail_reqs7 += status7[i]; } } 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(tempstr, MAXLINELENGTH, tempf) != NULL) fprintf(outf, "%s", tempstr); fclose(tempf); if (tempstr[(int)strlen(tempstr) - 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, monthcols, &monthgraph, "Monthly", "Monthly Report", " month", 'm', &monthlyunit, &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], monthcols, monthgraph, fieldwidth, bfieldwidth, monthlyunit, 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, weekcols, &weekgraph, "Weekly", "Weekly Report", "week beg.", 'W', &weeklyunit, &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, weekcols, weekgraph, fieldwidth, bfieldwidth, weeklyunit, 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, dailyreq[i]); maxbytes = MAX(maxbytes, dailybytes[i]); } datehead(outf, maxreq, maxbytes, daycols, &daygraph, "Daily", "Daily Summary", "day", 'd', &dailyunit, &fieldwidth, &bfieldwidth, &graphwidth, &bdivider); for(i = 0; i <= 6; i++) { j = (weekbeginson + i) % 7; fprintf(outf, "%s: ", dayname[j]); dateline(outf, dailyreq[j], dailybytes[j], daycols, daygraph, fieldwidth, bfieldwidth, dailyunit, 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, fulldaycols, &fulldaygraph, "FullDaily", "Daily Report", " date", 'D', &fulldailyunit, &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], fulldaycols, fulldaygraph, fieldwidth, bfieldwidth, fulldailyunit, 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, fullhourcols, &fullhourgraph, "FullHourly", "Hourly Report", " date:hr", 'H', &fullhourlyunit, &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], fullhourcols, fullhourgraph, fieldwidth, bfieldwidth, fullhourlyunit, 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, hourlyreq[i]); maxbytes = MAX(maxbytes, hourlybytes[i]); } datehead(outf, maxreq, maxbytes, hourcols, &hourgraph, "Hourly", "Hourly Summary", "hr", 'h', &hourlyunit, &fieldwidth, &bfieldwidth, &graphwidth, &bdivider); for(i = 0; i <= 23; i++) { fprintf(outf, "%2d: ", i); dateline(outf, hourlyreq[i], hourlybytes[i], hourcols, hourgraph, fieldwidth, bfieldwidth, hourlyunit, 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, hostsorthead, hostsortby, hostminreqstr, hostminbytestr, host_max_reqs, host_max_bytes, hostcols, "Host", "Host Report", "host", "hosts", 'S', hostsortby == ALPHABETICAL, byq, OFF, ""); break; case 'i': /* Directory report */ if (iq) genout(outf, dirsorthead, dirsortby, dirminreqstr, dirminbytestr, dir_max_reqs, dir_max_bytes, dircols, "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 = 2; /* If only printing pages, any linked = all linked */ genout(outf, urlsorthead, reqsortby, urlminreqstr, urlminbytestr, url_max_reqs, url_max_bytes, reqcols, "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, refsorthead, refsortby, refminreqstr, refminbytestr, ref_max_reqs, 0, refcols, "Referer", "Referer Report", "refering URL", "refering URLs", 'f', FALSE, refbyq, !aq, ""); break; case 'b': /* Browser summary */ if (bq) genout(outf, browsorthead, browsortby, browminreqstr, browminbytestr, brow_max_reqs, 0, browcols, "Browser", "Browser Summary", "browser", "browsers", 'b', FALSE, browbyq, OFF, ""); break; case 'B': /* Full browser report */ if (Bq) genout(outf, fullbrowsorthead, fullbrowsortby, fullbrowminreqstr, fullbrowminbytestr, fullbrow_max_reqs, 0, fullbrowcols, "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
\nThis analysis was produced by analog%s.\n", VERSION); else fprintf(outf, "This analysis was produced by analog%s.\n", VERSION); time(&stoptime); stoptime -= starttime; /* so now measures elapsed time */ if (stoptime == 0) { if (!aq) fprintf(outf, "
Running time: Less than 1 second.
\n"); else fprintf(outf, "Running time: Less than 1 second.\n"); } else if (stoptime < 60) { if (!aq) fprintf(outf, "
Running time: %ld second%s.\n", stoptime, (stoptime == 1)?"":"s"); else fprintf(outf, "Running time: %ld second%s.\n", stoptime, (stoptime == 1)?"":"s"); } else { if (!aq) fprintf(outf, "
Running time: %ld minute%s, %ld second%s.\n", stoptime / 60, (stoptime / 60 == 1)?"":"s", stoptime % 60, (stoptime % 60 == 1)?"":"s"); else fprintf(outf, "Running time: %ld minute%s, %ld second%s.\n", stoptime / 60, (stoptime / 60 == 1)?"":"s", stoptime % 60, (stoptime % 60 == 1)?"":"s"); } if (!aq && (mq || Wq || dq || Dq || hq || oq || Sq || iq || rq)) { gotos(outf, '\0'); } /* Finally, insert footer file */ footerfile[MAXSTRINGLENGTH - 5] = '\0'; /* for safety */ if (!STREQ(footerfile, "none")) { if ((tempf = fopen(footerfile, "r")) == NULL) { if (warnq) fprintf(stderr, "%s: Warning: Failed to open footer file %s: ignoring it.\n", commandname, footerfile); } else { /* can open footer file */ if (!aq) fprintf(outf, "
"); else { for (i = 0; i < pagewidth; i++) fprintf(outf, "-"); } fprintf(outf, "\n\n"); fflush(stdout); while(fgets(tempstr, MAXLINELENGTH, tempf) != NULL) fprintf(outf, "%s", tempstr); fclose(tempf); if (tempstr[(int)strlen(tempstr) - 1] != '\n') fprintf(outf, "\n"); fprintf(outf, "\n"); } } if (!aq) { if (STREQ(headerfile, "none") && STREQ(footerfile, "none")) { fprintf(outf, "

\n"); fprintf(outf, "\n"); } fprintf(outf, "\n\n\n"); } } fclose(outf); }