ftp.nice.ch/pub/next/unix/network/www/analog.NIHS.bs.gnutar.gz#/analog/init.c

This is init.c in view mode; [Download] [Up]

/*** analog 1.9beta ***/
/* Please read Readme.html, or http://www.statslab.cam.ac.uk/~sret1/analog/  */

/*** init.c; initialisation routines and declaration of global variables ***/

#include "analhea2.h"

/*** First declare all global variables. We choose to declare them in this
     file rather than analog.c because more are needed here. ***/

char dayname[7][4] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
char monthname[12][4] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
			   "Aug", "Sep", "Oct", "Nov", "Dec"};
/* Note: month numbers run from 0 (Jan) to 11 (Dec) internally to this
   program (though not where month numbers are needed in user input and
   output) */
int dateoffset[12] = {0, 31, 59, 90, 120, 151, 181,
			212, 243, 273, 304, 334};
int monthlength[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

char errs[NO_ERRS][MAXERRLENGTH] = {"Send timed out", "File does not exist",
"No file matching URL", "User does not exist", "Send aborted",
"Timed out waiting", "File permissions deny server access",
"Client denied by server configuration", "Malformed header from script",
"Killing CGI process", "Could not get local address", "Will not follow link",
"Could not get port number", "Script does not exist", "Script not found",
"Unable to include", "Could not fork new process",
"Unable to fork new process", "Invalid CGI ref",
"Caught SIGTERM, shutting down", "Caught SIGSEGV, dumping core",
"Caught SIGHUP, restarting", "SIGHUP received.  Attempting to restart",
"Successful restart", "Resuming normal operations", "Starting",
"Child error: pass failed", "Socket error: accept failed", ""};
      /* last must be "" */    
int errors[NO_ERRS];   /* how many occurrences of each */
int statusnos[NO_STATUS] = {200, 201, 202, 203, 204, 299, 301, 302, 303, 304,
399, 400, 401, 402, 403, 404, 499, 500, 501, 502, 503, 599};
/* all status codes */
char statusstrs[NO_STATUS][MAXSTATUSLENGTH] = {"OK", "Created",
"Accepted for future processing", "Partial information",
"OK, but nothing to send", "[Miscellaneous successes]", "Document moved",
"Document found elsewhere", "Moved; use another request method",
"Not modified since last retrieval", "[Miscellaneous redirections]",
"Bad request", "Authorisation required", "Payment required", "Forbidden",
"Document not found", "[Miscellaneous client/user errors]",
"Internal server error", "Request type not supported",
"Server overloaded", "Gateway timed out", "[Miscellaneous server errors]"};
int status[NO_STATUS];   /* how many of each have been seen */
int status7[NO_STATUS];  /* ditto in last 7 days */

char outfile[MAXSTRINGLENGTH];

struct timestruct firsttime, lasttime, starttimec, oldtime, fromtime, totime;
/* first and last log entries, now, a week before now, and
   lower and upper bounds on time interval we want to consider */

struct monthly *firstm, *lastm;
    /* pointers to the first and last years of monthly data */
struct daily *firstd, *lastd;   /* ... months of daily data */
struct hourly *firsth, *lasth;  /* ... days of hourly data */
struct weekly *firstw, *lastw;  /* ... and to the first and last week */

int no_urls;                  /* the number of distinct files found so far */
int no_urls7;                 /* the number used in the last 7 days */
struct genstruct *urlhead[URLHASHSIZE];  /* hash table of all files found */
struct genstruct *dirhead[DIRHASHSIZE];  /* and one for all directories */
struct domain *subdomhead[SUBDOMHASHSIZE];  /* one for subdomains */
struct domain *wildsubdomhead;     /* and one for wild subdomains */
struct domain *nwildsubdomhead;    /* and one for wild numerical subdomains */
int no_hosts;                 /* the number of hosts so far */
int no_hosts7;                /* the number of all hosts in the last 7 days */
int no_new_hosts7;            /* the number of new hosts in the last 7 days */
struct genstruct *hosthead[HOSTHASHSIZE];  /* and a record of all hosts */
char *approxhostspace;       /* start of the space for approx host counting */
char *approxhostspace7;      /* and a bit more for last 7 days accounting */
int approxhostsize;          /* the size of those spaces, in bytes */
struct domain *domainhead[DOMHASHSIZE];
struct genstruct *refhead[REFHASHSIZE];
struct genstruct *browhead[BROWHASHSIZE];
struct genstruct *fullbrowhead[FULLBROWHASHSIZE];

struct alias *filealiashead, *hostaliashead, *refaliashead, *subdomshead;
    /* subdomshead is not really an alias, but it's the right shape */
struct include *wantfilehead, *wanthosthead, *wantrefhead;
struct include *ispagehead, *noexpandhead, *refexpandhead;

int dailyreq[7];            /* requests for each day */
int hourlyreq[24];          /* ... and hour */
double dailybytes[7];       /* ... and bytes ditto */
double hourlybytes[24];

int url_max_reqs;        /* the max reqs for any file */
int dir_max_reqs;        /* for any directory */
int host_max_reqs;       /* for any host */
int dom_max_reqs;        /* for any domain */
int ref_max_reqs;        /* for any referer */
int brow_max_reqs;       /* for any browser */
int fullbrow_max_reqs;   /* for any browser (full name) */

double url_max_bytes;    /* the same for max bytes */
double dir_max_bytes;
double host_max_bytes;
double dom_max_bytes;
double ref_max_bytes;
double brow_max_bytes;
double fullbrow_max_bytes;

int host_max_length;     /* and the same for length of name */

int dirsufflength;  /* the length of DIRSUFFIX */
int onumber, subonumber;  /* the number of (sub)domains in the domain report */
time_t starttime, stoptime;
char starttimestr[26];     /* the start and stop time of the program */
double total_bytes;
double total_bytes7;
int corrupt_lines;         /* the number of corrupt lines in the logfile */
                             /* (Overlong lines, URLs with quotes in...) */
int other_lines;           /* Lines masked out */
int cachereqs, cachereqs7; /* The number of requests from cache */
flag byq, refbyq, browbyq; /* whether we want to count bytes; always on until
			      we find a line with no bytes information. */
flag rawbytes;   /* whether bytes are quoted raw or in k notation */
flag graphical;  /* whether to draw pretty graphs or just use ASCII art */
flag filemaskq, hostmaskq, refmaskq;
/* whether there is any masking of hosts, files or refs */

int weekbeginson;  /* which is the first day of the week? */
char sepchar;      /* character as separator in, e.g., 23 000 000 */

char commandname[MAXSTRINGLENGTH];  /* the name of the program, as called */

char baseurl[MAXSTRINGLENGTH];     /* base URL for all URLs found */
char reqcols[5], dircols[5], hostcols[5], domcols[5], refcols[5], browcols[5];
char fullbrowcols[5], monthcols[5], daycols[5], fulldaycols[5], weekcols[5];
char hourcols[5], fullhourcols[5];      /* Columns appearing in each report */

struct loglist *logfilehead, *uncompresshead;
/* uncompress is not really a loglist, but it's the right shape */
struct stringlist *cachefilehead, *refloghead, *browloghead, *errloghead;
char domainsfile[MAXSTRINGLENGTH];
char logourl[MAXSTRINGLENGTH];
char imagedir[MAXSTRINGLENGTH];
char headerfile[MAXSTRINGLENGTH], footerfile[MAXSTRINGLENGTH];
char reportorder[18];  /* the order in which reports occur (room for more) */
flag xq, mq, oq, iq, rq, q7, dq, hq, Hq, Sq, Dq, Wq, fq, bq, Bq, cq, eq;
int sq, aq;  /* a: output type     x->s: whether we want each type of report */
flag warnq;             /* whether we want warnings */
int monthlyunit, weeklyunit, dailyunit, fulldailyunit, hourlyunit;
int fullhourlyunit;  /* the size of the mark in the graphical displays */
char domminreqstr[MAXSTRINGLENGTH], subdomminreqstr[MAXSTRINGLENGTH];
char hostminreqstr[MAXSTRINGLENGTH], dirminreqstr[MAXSTRINGLENGTH];
char urlminreqstr[MAXSTRINGLENGTH], refminreqstr[MAXSTRINGLENGTH];
char browminreqstr[MAXSTRINGLENGTH], fullbrowminreqstr[MAXSTRINGLENGTH];
char domminbytestr[MAXSTRINGLENGTH], subdomminbytestr[MAXSTRINGLENGTH];
char hostminbytestr[MAXSTRINGLENGTH], dirminbytestr[MAXSTRINGLENGTH];
char urlminbytestr[MAXSTRINGLENGTH], refminbytestr[MAXSTRINGLENGTH];
char browminbytestr[MAXSTRINGLENGTH], fullbrowminbytestr[MAXSTRINGLENGTH];
int errminreqs;
char monthgraph, daygraph, fulldaygraph, hourgraph, fullhourgraph, weekgraph;
flag mback, Dback, Wback, Hback;
int domsortby, dirsortby, hostsortby, reqsortby, refsortby, browsortby;
int fullbrowsortby;
int dirlevel, reqtype, pagewidth;
char markchar;
char hostname[MAXSTRINGLENGTH], hosturl[MAXSTRINGLENGTH];
int kq;        /* default PAGELINKS */
int debug;

flag vblesonly;  /* commandline only. If ON, just print variables and exit */
flag formq;      /* commandline only. If ON, just make a form interface */

extern void *xmalloc();   /* in utils.c */
extern void *xcalloc();   /* in utils.c */

/* We also declare the following pointers as global here. They are not used
   outside this file, but we want to keep track of all of them between
   various functions within this file. */

struct alias *filealiasp, *hostaliasp, *refaliasp, *subdomp, *subdomtempp;
struct include *wantfilep, *wanthostp, *wantrefp, *ispagep, *noexpandp;
struct include *refexpandp;
struct loglist *logfilep, *uncompressp;
struct stringlist *cachefilep, *reflogp, *browlogp, *errlogp;

/*** Next, the function that parses the domains file ***/

void domainscan(void)
{
  extern flag subdomadd();        /* in hash.c */
  extern int sscanf_domains();    /* in sscanf.c */

  FILE *df;
  struct domain *domp, *domlastp;
  /* Recycle global struct alias *subdomp; */
  char tempstr[MAXSTRINGLENGTH], tempstr2[MAXSTRINGLENGTH];
  char inputline[MAXLINELENGTH];
  int rc;    /* return code */
  int domcode;   /* the code of a particular domain;
		    see the long comment just below */

  df = fopen(domainsfile, "r");
  if (df == NULL) {
    if (warnq) {
      fprintf(stderr, "%s: Warning: Failed to open domains file \"%s\":\n",
	      commandname, domainsfile);
      fprintf(stderr,"  will not construct domain report.\n");
    }
    oq = OFF;
    return;
  }

  /* We put the domains in the following order. aa = 0, ab = 2, ...,
     ba = 52, ... Domains with more than two letters go in the spaces;
     co = 134, com = 135, cp = 136. We assume that there are no two long
     domain names with the same two initial letters. Finally zz = 1350,
     zzspam = 1351, Unknown = 1352, Numerical = 1353. Each domain contains
     a 'nexti' element to show which is the next domain that occurs in the
     domains file. */

  else {   /* there is a domains file */
    domp = domainhead[DOMHASHSIZE - 2];
    domp -> id = xmalloc(5);      /* enough for "*UNK\0" */
    strcpy(domp -> id, "*UNK");
    domp -> name = xmalloc(8);
    strcpy(domp -> name, "unknown");
    domp -> reqs = 0;
    domp -> bytes = 0;
    domp -> next = (struct domain *)xmalloc(sizeof(struct domain));
    domp -> next -> name = NULL;
    domp = domainhead[DOMHASHSIZE - 1];
    domp -> id = xmalloc(5);
    strcpy(domp -> id, "*NUM");
    domp -> name = xmalloc(31);
    strcpy(domp -> name, "unresolved numerical addresses");
    domp -> reqs = 0;
    domp -> bytes = 0;
    domp -> next = (struct domain *)xmalloc(sizeof(struct domain));
    domp -> next -> name = NULL;
    domlastp = domp;
    domp = domp -> next;

    while (fgets(inputline, MAXLINELENGTH, df) != NULL) {
      rc = sscanf_domains(inputline, tempstr, tempstr2);
      if (rc == 2) {
	if ((!isdigit(tempstr[0])) && strchr(tempstr, '.') == NULL) {
                                                    /* new domain */
	  domcode = (tempstr[0] - 'a') * 52 + (tempstr[1] - 'a') * 2 +
	    (tempstr[2] != '\0');
	  if ((domcode < 0 || domcode > DOMHASHSIZE - 3) && warnq) {
	    fprintf(stderr, "%s: Warning: Ignoring corrupt line in domains file looking like\n", commandname);
	    fprintf(stderr,"  %s", inputline);
	  }
	  domp = domainhead[domcode];
	  domp -> id = xmalloc((size_t)((int)strlen(tempstr) + 1));
	  strcpy(domp -> id, tempstr);
	  domp -> name = xmalloc((size_t)((int)strlen(tempstr2) + 1));
	  strcpy(domp -> name, tempstr2);
	  domp -> reqs = 0;
	  domp -> bytes = 0;
	  domp -> next = (struct domain *)xmalloc(sizeof(struct domain));
	  domp -> next -> name = NULL;
	  domlastp -> nexti = domcode;
                            /* domlastp is the last domain we looked at */
	  domlastp = domp;
	  domp = domp -> next;
	}
	else if (warnq) {   /* old specification subdomain */
	  fprintf(stderr,
          "%s: Warning: Subdomains should now be specified in configuration\n",
		  commandname);
	  fprintf(stderr, "  file, not domains file. Ignoring line\n  %s",
		  inputline);
	}
      }
      else if (rc == 1 && warnq) {
	fprintf(stderr, "%s: Warning: Ignoring corrupt line in domains file looking like\n", commandname);
	fprintf(stderr, "  %s", inputline);
      }
    }

    domlastp -> nexti = -1;   /* marker; last domain has no subsequent one */
    
    fclose(df);

    /* Now do the subdomains which we read in at configuration time */

    for (subdomp = subdomshead; subdomp -> from[0] != '\0';
	 subdomp = subdomp -> next)
      if (subdomp -> from[0] != '?')
	subdomadd(subdomp -> from, subdomp -> to);

  }     /* end else can read domains file */
}


/*** Now boring functions for initialisation of variables etc. ***/

void defaults(void)
{
  strncpy(domainsfile, DOMAINSFILE, MAXSTRINGLENGTH - 1);
  domainsfile[MAXSTRINGLENGTH - 1] = '\0';
  strncpy(headerfile, HEADERFILE, MAXSTRINGLENGTH - 1);
  headerfile[MAXSTRINGLENGTH - 1] = '\0';
  strncpy(footerfile, FOOTERFILE, MAXSTRINGLENGTH - 1);
  footerfile[MAXSTRINGLENGTH - 1] = '\0';
  strncpy(outfile, OUTFILE, MAXSTRINGLENGTH - 1);
  outfile[MAXSTRINGLENGTH - 1] = '\0';
  strncpy(baseurl, BASEURL, MAXSTRINGLENGTH - 1);
  baseurl[MAXSTRINGLENGTH - 1] = '\0';
  strncpy(imagedir, IMAGEDIR, MAXSTRINGLENGTH - 1);
  imagedir[MAXSTRINGLENGTH - 1] = '\0';
  strncpy(reportorder, REPORTORDER, 15);
  reportorder[15] = '\0';
  strncpy(domcols, DOMCOLS, 4);
  domcols[4] = '\0';
  strncpy(hostcols, HOSTCOLS, 4);
  hostcols[4] = '\0';
  strncpy(dircols, DIRCOLS, 4);
  dircols[4] = '\0';
  strncpy(reqcols, REQCOLS, 4);
  reqcols[4] = '\0';
  strncpy(refcols, REFCOLS, 4);
  refcols[4] = '\0';
  strncpy(browcols, BROWCOLS, 4);
  browcols[4] = '\0';
  strncpy(fullbrowcols, FULLBROWCOLS, 4);
  fullbrowcols[4] = '\0';
  strncpy(monthcols, MONTHCOLS, 4);
  monthcols[4] = '\0';
  strncpy(daycols, DAYCOLS, 4);
  daycols[4] = '\0';
  strncpy(fulldaycols, FULLDAYCOLS, 4);
  fulldaycols[4] = '\0';
  strncpy(weekcols, WEEKCOLS, 4);
  weekcols[4] = '\0';
  strncpy(hourcols, HOURCOLS, 4);
  hourcols[4] = '\0';
  strncpy(fullhourcols, FULLHOURCOLS, 4);
  fullhourcols[4] = '\0';
  strcpy(logourl, LOGOURL);
  mq = MONTHLY;
  Wq = WEEKLY;
  dq = DAILY;
  Dq = FULLDAILY;
  hq = HOURLY;
  Hq = FULLHOURLY;
  oq = DOMAINREP;
  iq = DIRECTORY;
  rq = REQUEST;
  sq = COUNTHOSTS;
  Sq = FULLHOSTS;
  fq = REFERER;
  bq = BROWSER;
  Bq = FULLBROWSER;
  cq = STATUS;
  eq = ERROR;
  xq = GENERAL;
  q7 = LASTSEVEN;
  aq = OUTPUT;
  warnq = WARNINGS;
  graphical = GRAPHICAL;
  monthlyunit = 0;
  weeklyunit = 0;
  hourlyunit = 0;
  fullhourlyunit = 0;
  dailyunit = 0;
  fulldailyunit = 0;
  monthgraph = MONTHGRAPH;
  daygraph = DAYGRAPH;
  fulldaygraph = FULLDAYGRAPH;
  hourgraph = HOURGRAPH;
  fullhourgraph = FULLHOURGRAPH;
  weekgraph = WEEKGRAPH;
  Hback = FULLHOURLYBACK;
  Dback = FULLDAILYBACK;
  Wback = WEEKLYBACK;
  mback = MONTHLYBACK;
  domsortby = DOMSORTBY;
  dirsortby = DIRSORTBY;
  reqsortby = REQSORTBY;
  hostsortby = HOSTSORTBY;
  refsortby = REFSORTBY;
  browsortby = BROWSORTBY;
  fullbrowsortby = FULLBROWSORTBY;
  strncpy(domminreqstr, MIN_DOM_REQS, MAXSTRINGLENGTH - 1);
  domminreqstr[MAXSTRINGLENGTH - 1] = '\0';
  strncpy(domminbytestr, MIN_DOM_BYTES, MAXSTRINGLENGTH - 1);
  domminbytestr[MAXSTRINGLENGTH - 1] = '\0';
  strncpy(subdomminreqstr, MIN_SUBDOM_REQS, MAXSTRINGLENGTH - 1);
  subdomminreqstr[MAXSTRINGLENGTH - 1] = '\0';
  strncpy(subdomminbytestr, MIN_SUBDOM_BYTES, MAXSTRINGLENGTH - 1);
  subdomminbytestr[MAXSTRINGLENGTH - 1] = '\0';
  strncpy(dirminreqstr, MIN_DIR_REQS, MAXSTRINGLENGTH - 1);
  dirminreqstr[MAXSTRINGLENGTH - 1] = '\0';
  strncpy(dirminbytestr, MIN_DIR_BYTES, MAXSTRINGLENGTH - 1);
  dirminbytestr[MAXSTRINGLENGTH - 1] = '\0';
  strncpy(hostminreqstr, MIN_HOST_REQS, MAXSTRINGLENGTH - 1);
  hostminreqstr[MAXSTRINGLENGTH - 1] = '\0';
  strncpy(hostminbytestr, MIN_HOST_BYTES, MAXSTRINGLENGTH - 1);
  hostminbytestr[MAXSTRINGLENGTH - 1] = '\0';
  strncpy(urlminreqstr, MIN_URL_REQS, MAXSTRINGLENGTH - 1);
  urlminreqstr[MAXSTRINGLENGTH - 1] = '\0';
  strncpy(urlminbytestr, MIN_URL_BYTES, MAXSTRINGLENGTH - 1);
  urlminbytestr[MAXSTRINGLENGTH - 1] = '\0';
  strncpy(refminreqstr, MIN_REF_REQS, MAXSTRINGLENGTH - 1);
  refminreqstr[MAXSTRINGLENGTH - 1] = '\0';
  strncpy(refminbytestr, MIN_REF_BYTES, MAXSTRINGLENGTH - 1);
  refminbytestr[MAXSTRINGLENGTH - 1] = '\0';
  strncpy(browminreqstr, MIN_BROW_REQS, MAXSTRINGLENGTH - 1);
  browminreqstr[MAXSTRINGLENGTH - 1] = '\0';
  strncpy(browminbytestr, MIN_BROW_BYTES, MAXSTRINGLENGTH - 1);
  browminbytestr[MAXSTRINGLENGTH - 1] = '\0';
  strncpy(fullbrowminreqstr, MIN_FULLBROW_REQS, MAXSTRINGLENGTH - 1);
  fullbrowminreqstr[MAXSTRINGLENGTH - 1] = '\0';
  strncpy(fullbrowminbytestr, MIN_FULLBROW_BYTES, MAXSTRINGLENGTH - 1);
  fullbrowminbytestr[MAXSTRINGLENGTH - 1] = '\0';
  errminreqs = MIN_ERR_OCCS;
  dirlevel = DIRLEVEL;
  reqtype = REQTYPE;
  pagewidth = PAGEWIDTH;
  markchar = MARKCHAR;
  rawbytes = RAWBYTES;
  strncpy(hostname, HOSTNAME, MAXSTRINGLENGTH - 1);
  hostname[MAXSTRINGLENGTH - 1] = '\0';
  strncpy(hosturl, HOSTURL, MAXSTRINGLENGTH - 1);
  hosturl[MAXSTRINGLENGTH - 1] = '\0';
  kq = PAGELINKS;
  weekbeginson = WEEKBEGINSON;
  sepchar = SEPCHAR;
  vblesonly = OFF;
  formq = OFF;
  fromtime.code = -INFINITY;
  totime.code = INFINITY;
  approxhostsize = APPROXHOSTSIZE;
  debug = DEBUG;
  filemaskq = OFF;
  hostmaskq = OFF;
  refmaskq = OFF;
}

void init_structs(void)
{
  extern void addlogfile(), configstrlist();     /* later in this file */
  char tempstr[MAXSTRINGLENGTH];

  logfilehead = (struct loglist *)xmalloc(sizeof(struct loglist));
  logfilep = logfilehead;
  if (STREQ(LOGFILE, "none"))
    logfilehead -> name[0] = '\0';
  else {
    strcpy(tempstr, LOGFILE);
    addlogfile(&logfilep, tempstr, "");
  }
  cachefilehead = (struct stringlist *)xmalloc(sizeof(struct stringlist));
  cachefilep = cachefilehead;
  if (STREQ(CACHEFILE, "none"))
    cachefilehead -> name[0] = '\0';
  else {
    strcpy(tempstr, CACHEFILE);
    configstrlist(tempstr, &cachefilep, (char *)NULL, (char *)NULL, 2);
  }
  refloghead = (struct stringlist *)xmalloc(sizeof(struct stringlist));
  reflogp = refloghead;
  if (STREQ(REFERER_LOG, "none"))
    refloghead -> name[0] = '\0';
  else{
    strcpy(tempstr, REFERER_LOG);
    configstrlist(tempstr, &reflogp, (char *)NULL, (char *)NULL, 2);
  }
  browloghead = (struct stringlist *)xmalloc(sizeof(struct stringlist));
  browlogp = browloghead;
  if (STREQ(BROWSER_LOG, "none"))
    browloghead -> name[0] = '\0';
  else {
    strcpy(tempstr, BROWSER_LOG);
    configstrlist(tempstr, &browlogp, (char *)NULL, (char *)NULL, 2);
  }
  errloghead = (struct stringlist *)xmalloc(sizeof(struct stringlist));
  errlogp = errloghead;
  if (STREQ(ERROR_LOG, "none"))
    errloghead -> name[0] = '\0';
  else {
    strcpy(tempstr, ERROR_LOG);
    configstrlist(tempstr, &errlogp, (char *)NULL, (char *)NULL, 2);
  }
  uncompresshead = (struct loglist *)xmalloc(sizeof(struct loglist));
  uncompresshead -> name[0] = '\0';
  uncompressp = uncompresshead;
  filealiashead = (struct alias *)xmalloc(sizeof(struct alias));
  filealiashead -> from[0] = '\0';
  filealiasp = filealiashead;
  hostaliashead = (struct alias *)xmalloc(sizeof(struct alias));
  hostaliashead -> from[0] = '\0';
  hostaliasp = hostaliashead;
  refaliashead = (struct alias *)xmalloc(sizeof(struct alias));
  refaliashead -> from[0] = '\0';
  refaliasp = refaliashead;
  wantfilehead = (struct include *)xmalloc(sizeof(struct include));
  wantfilehead -> in = UNSET;
  wantfilep = wantfilehead;
  wanthosthead = (struct include *)xmalloc(sizeof(struct include));
  wanthosthead -> in = UNSET;
  wanthostp = wanthosthead;
  subdomshead = (struct alias *)xmalloc(sizeof(struct alias));
  subdomshead -> from[0] = '\0';
  subdomp = subdomshead;
  wantrefhead = (struct include *)xmalloc(sizeof(struct include));
  wantrefhead -> in = UNSET;
  wantrefp = wantrefhead;
  noexpandhead = (struct include *)xmalloc(sizeof(struct include));
  noexpandhead -> in = UNSET;
  noexpandp = noexpandhead;
  refexpandhead = (struct include *)xmalloc(sizeof(struct include));
  refexpandhead -> in = UNSET;
  refexpandp = refexpandhead;
  ispagehead = (struct include *)xmalloc(sizeof(struct include));
  ispagep = ispagehead;
  strcpy(ispagep -> name, "*.html");
  ispagep -> in = TRUE;
  ispagep -> next = (struct include *)xmalloc(sizeof(struct include));
  ispagep = ispagep -> next;
  strcpy(ispagep -> name, "*/");
  ispagep -> in = TRUE;
  ispagep -> next = (struct include *)xmalloc(sizeof(struct include));
  ispagep = ispagep -> next;
  strcpy(ispagep -> name, "*.htm");
  ispagep -> in = TRUE;
  ispagep -> next = (struct include *)xmalloc(sizeof(struct include));
  ispagep = ispagep -> next;
  strcpy(ispagep -> name, "*.shtml");
  ispagep -> in = TRUE;
  ispagep -> next = (struct include *)xmalloc(sizeof(struct include));
  ispagep = ispagep -> next;
  strcpy(ispagep -> name, "*.shtm");
  ispagep -> in = TRUE;
  ispagep -> next = (struct include *)xmalloc(sizeof(struct include));
  ispagep = ispagep -> next;
  strcpy(ispagep -> name, "*.html3");
  ispagep -> in = TRUE;
  ispagep -> next = (struct include *)xmalloc(sizeof(struct include));
  ispagep = ispagep -> next;
  strcpy(ispagep -> name, "*.ht3");
  ispagep -> in = TRUE;
  ispagep -> next = (struct include *)xmalloc(sizeof(struct include));
  ispagep -> next -> in = UNSET;
}

void othervars(void)    /* vars initialised after command args and config */
{
  extern long timecode();     /* in utils.c */

  char oldmonth[4];           /* the time 7 days ago */
  long oldtimeno;
  char oldtimestr[26];
  int i;

  no_urls = 0;
  no_urls7 = 0;
  no_hosts = 0;
  no_hosts7 = 0;
  no_new_hosts7 = 0;
  url_max_reqs = 0;
  dir_max_reqs = 0;
  host_max_reqs = 0;
  url_max_bytes = 0;
  dir_max_bytes = 0;
  host_max_bytes = 0;         /* dom_max_reqs and _bytes are set later */
  host_max_length = 0;
  for (i = 0; i < NO_STATUS; i++) {
    status[i] = 0;
    status7[i] = 0;
  }
  total_bytes = 0.0;
  total_bytes7 = 0.0;
  corrupt_lines = 0;
  other_lines = 0;
  cachereqs = 0;
  cachereqs7 = 0;
  byq = ON;
  refbyq = ON;
  browbyq = ON;

  /* initialise the date structures */
  if (mq) {
    firstm = (struct monthly *)xmalloc(sizeof(struct monthly));
    for (i = 0; i < 12; i++) {
      firstm -> reqs[i] = 0;
      firstm -> bytes[i] = 0.0;
    }
    firstm -> next = NULL;
    lastm = firstm;
  }
  if (Dq) {
    firstd = (struct daily *)xmalloc(sizeof(struct daily));
    for (i = 0; i < 31; i++) {
      firstd -> reqs[i] = 0;
      firstd -> bytes[i] = 0.0;
    }
    firstd -> next = NULL;
    lastd = firstd;
  }
  if (Hq) {
    firsth = (struct hourly *)xmalloc(sizeof(struct hourly));
    for (i = 0; i < 24; i++) {
      firsth -> reqs[i] = 0;
      firsth -> bytes[i] = 0.0;
    }
    firsth -> next = NULL;
    lasth = firsth;
  }
  if (Wq) {
    firstw = (struct weekly *)xmalloc(sizeof(struct weekly));
    firstw -> reqs = 0;
    firstw -> bytes = 0;
    firstw -> next = NULL;
    lastw = firstw;
  }
  if (dq) {
    for (i = 0; i < 7; i++) {
      dailyreq[i] = 0;
      dailybytes[i] = 0.0;
    }
  }
  if (hq) {
    for (i = 0; i < 24; i++) {
      hourlyreq[i] = 0;
      hourlybytes[i] = 0.0;
    }
  }

  if (q7) {   /* calculate the time 7 days ago */
    if (starttimec.code <= totime.code) {
      oldtimeno = starttime - 604800;        /* seconds in a week */
      strcpy(oldtimestr, (char *)(ctime((time_t *)(&oldtimeno))));
      oldtime.year = (oldtimestr[23] - '0') + (oldtimestr[22] - '0') * 10
	+ (oldtimestr[21] - '0') * 100 + (oldtimestr[20] - '0') * 1000;
      oldtime.min = (oldtimestr[15] - '0') + (oldtimestr[14] - '0') * 10;
      oldtime.hr = (oldtimestr[12] - '0') + (oldtimestr[11] - '0') * 10;
      oldtime.date = (oldtimestr[9] - '0');
      if (oldtimestr[8] != ' ')
	oldtime.date += (oldtimestr[8] - '0') * 10;
      oldtimestr[7] = '\0';
      strcpy(oldmonth, oldtimestr + 4);
      oldtime.monthno = strtomonth(oldmonth);
    }
    else {    /* totime is earlier than today; take 7 days before that */
      oldtime.hr = 23;
      oldtime.min = 59;
      oldtime.year = totime.year;
      oldtime.monthno = totime.monthno;
      oldtime.date = totime.date - 7;
      if (oldtime.date < 1) {
	oldtime.monthno--;
	if (oldtime.monthno < 0) {
	  oldtime.year--;
	  oldtime.monthno += 12;
	}
	oldtime.date += monthlength[oldtime.monthno] +
	  ISLEAPFEB(oldtime.monthno, oldtime.year);
      }
    }
    oldtime.code = timecode(oldtime.date, oldtime.monthno, oldtime.year,
			    oldtime.hr, oldtime.min);
    if (oldtime.code < fromtime.code)
      q7 = OFF;  /* FROM--TO is all in last 7 days */
  }
  
  dirsufflength = (int)strlen(DIRSUFFIX);
    
  if (rq || iq) {   /* we do a (silent) req. report if iq as well */
    for (i = 0; i < URLHASHSIZE; i++) {
      urlhead[i] = (struct genstruct *)xmalloc(sizeof(struct genstruct));
      urlhead[i] -> name = NULL;
    }
  }
  if (iq) {
    for (i = 0; i < DIRHASHSIZE; i++) {
      dirhead[i] = (struct genstruct *)xmalloc(sizeof(struct genstruct));
      dirhead[i] -> name = NULL;
    }
  }
  if (sq == ON) {
    for (i = 0; i < HOSTHASHSIZE; i++) {
      hosthead[i] = (struct genstruct *)xmalloc(sizeof(struct genstruct));
      hosthead[i] -> name = NULL;
    }
  }
  else if (sq == APPROX) {
    approxhostspace = (char *) xcalloc(approxhostsize, 1);
    if (q7)
      approxhostspace7 = (char *) xcalloc(approxhostsize, 1);
  }
  if (fq) {
    for (i = 0; i < REFHASHSIZE; i++) {
      refhead[i] = (struct genstruct *)xmalloc(sizeof(struct genstruct));
      refhead[i] -> name = NULL;
    }
  }
  if (bq) {
    for (i = 0; i < BROWHASHSIZE; i++) {
      browhead[i] = (struct genstruct *)xmalloc(sizeof(struct genstruct));
      browhead[i] -> name = NULL;
    }
  }
  if (Bq) {
    for (i = 0; i < FULLBROWHASHSIZE; i++) {
      fullbrowhead[i] =
	(struct genstruct *)xmalloc(sizeof(struct genstruct));
      fullbrowhead[i] -> name = NULL;
    }
  }
  if (eq) {
    for (i = 0; i < NO_ERRS; i++)
      errors[i] = 0;
  }
  if (oq) {
    for (i = 0; i < DOMHASHSIZE; i++) {
      domainhead[i] = (struct domain *)xmalloc(sizeof(struct domain));
      domainhead[i] -> name = NULL;
    }
    for (i = 0; i < SUBDOMHASHSIZE; i++) {
      subdomhead[i] = (struct domain *)xmalloc(sizeof(struct domain));
      subdomhead[i] -> name = NULL;
    }
    wildsubdomhead = (struct domain *)xmalloc(sizeof(struct domain));
    wildsubdomhead -> id = NULL;
    nwildsubdomhead = (struct domain *)xmalloc(sizeof(struct domain));
    nwildsubdomhead -> id = NULL;
    domainscan();      /* read in all the domains */
  }   /* end if (oq) */

}

/*** Now for the functions that parse the configuration commands. ***/

/* First some warning messages */

void configwarning(char *comname, char *inputline)
{  /* a generic warning for the next command */
  if (warnq) {
    fprintf(stderr, "%s: Warning: Not enough arguments to %s command: ignoring line\n", commandname, comname);
    fprintf(stderr, "  %s", inputline);
    if (inputline[strlen(inputline)-1] != '\n')
      fprintf(stderr, "\n", inputline);
  }
}

void configwarning2(char *inputline)
{
  if (warnq) {
    fprintf(stderr, "%s: Warning: Discarding illegal configuration command\n",
	    commandname);
    fprintf(stderr, "  %s", inputline);
    if (inputline[strlen(inputline)-1] != '\n')
      fprintf(stderr, "\n", inputline);
  }
}

void configwarning3(char *comname, char *inputline)
{
  if (warnq) {
    fprintf(stderr, "%s: Warning: Too many arguments to %s command: ignoring end of line\n", commandname, comname);
    fprintf(stderr, "  %s", inputline);
    if (inputline[strlen(inputline)-1] != '\n')
      fprintf(stderr, "\n", inputline);
  }
}

/* Next some sub-functions to do things that come up in lots of commands */

void addlogfile(struct loglist **p, char name[MAXSTRINGLENGTH],
		char prefix[MAXSTRINGLENGTH])
{
  char *tempstr;

  tempstr = strtok(name, ",");
  strncpy((*p) -> name, tempstr, MAXSTRINGLENGTH - 1);
  (*p) -> name[MAXSTRINGLENGTH - 1] = '\0';
  strncpy((*p) -> prefix, prefix, MAXSTRINGLENGTH - 1);
  (*p) -> prefix[MAXSTRINGLENGTH - 1] = '\0';
  (*p) -> next = (struct loglist *)xmalloc(sizeof(struct loglist));
  *p = (*p) -> next;
  (*p) -> name[0] = '\0';
  while ((tempstr = strtok((char *)NULL, ",")) != NULL) {
    strncpy((*p) -> name, tempstr, MAXSTRINGLENGTH - 1);
    (*p) -> name[MAXSTRINGLENGTH - 1] = '\0';
    strncpy((*p) -> prefix, prefix, MAXSTRINGLENGTH - 1);
    (*p) -> prefix[MAXSTRINGLENGTH - 1] = '\0';
    (*p) -> next = (struct loglist *)xmalloc(sizeof(struct loglist));
    *p = (*p) -> next;
    (*p) -> name[0] = '\0';
  }
}

void include(char *name, struct include **p, int in, char *comname,
	     char *inputline, int rc, flag *maskq)
{                          /* put something(s) in an include list */
  char *tempstr;

  if (rc < 2)
    configwarning(comname, inputline);
  else {
    if (rc > 2)
      configwarning3(comname, inputline);
    *maskq = ON;
    tempstr = strtok(name, ",");
    strncpy((*p) -> name, tempstr, MAXSTRINGLENGTH - 1);
    (*p) -> name[MAXSTRINGLENGTH - 1] = '\0';
    (*p) -> in = in;
    (*p) -> next = (struct include *)xmalloc(sizeof(struct include));
    *p = (*p) -> next;
    (*p) -> in = UNSET;
    while ((tempstr = strtok((char *)NULL, ",")) != NULL) {
      strncpy((*p) -> name, tempstr, MAXSTRINGLENGTH - 1);
      (*p) -> name[MAXSTRINGLENGTH - 1] = '\0';
      (*p) -> in = in;
      (*p) -> next = (struct include *)xmalloc(sizeof(struct include));
      *p = (*p) -> next;
      (*p) -> in = UNSET;
    }
  }
}

void configalias(char *from, char *to, struct alias **p, char *comname,
		 char *inputline, int rc)
{
  if (rc < 3)
    configwarning(comname, inputline);
  else if (from[0] == '\0' || to[0] == '\0')
    configwarning2(inputline);
  else {
    if (rc > 3)
      configwarning3(comname, inputline);
    strcpy((*p) -> from, from);
    strcpy((*p) -> to, to);
    (*p) -> next = (struct alias *)xmalloc(sizeof(struct alias));
    *p = (*p) -> next;
    (*p) -> from[0] = '\0';
  }
}

void fromtodate(char *tstr, struct timestruct *t, flag from,
		char *comname, char *inputline, int rc)
{  /* NB should we put more syntax checking in this function? */
  extern long timecode();      /* in utils.c */
  extern char *strtoupper();   /* in utils.c */

  if (rc < 2)
    configwarning(comname, inputline);
  else if (STREQ(strtoupper(tstr), "OFF")) {
    if (from)
      t -> code = -INFINITY;
    else
      t -> code = INFINITY;
  }
  else if ((int)strlen(tstr) < 6)
    configwarning2(inputline);
  else {
    if (rc > 2)
      configwarning3(comname, inputline);
    if (*tstr == '-') {
      t -> year = starttimec.year;
      t -> year -= 10 * (*(++tstr) - '0');
      t -> year -= (*(++tstr) - '0');
    }
    else {
      t -> year = 10 * (*tstr - '0');
      t -> year += (*(++tstr) - '0');
      if (t -> year > 70)   /* (say) */
	t -> year += 1900;
      else
	t -> year += 2000;
    }
    tstr++;
    if (*tstr == '-') {
      t -> monthno = starttimec.monthno;
      t -> monthno -= 10 * (*(++tstr) - '0');
      t -> monthno -= (*(++tstr) - '0');
      while (t -> monthno < 0) {
	t -> monthno += 12;
	t -> year--;
      }
    }
    else if (*tstr == '+') {
      t -> monthno = starttimec.monthno;
      t -> monthno += 10 * (*(++tstr) - '0');
      t -> monthno += (*(++tstr) - '0');
      while (t -> monthno > 11) {
	t -> monthno -= 12;
	t -> year++;
      }
    }
    else {
      t -> monthno = 10 * (*tstr - '0');
      t -> monthno += (*(++tstr) - '0');
      t -> monthno--;  /* prog. months are 1 out from standard */
    }
    tstr++;
    if (*tstr == '-') {
      t -> date = starttimec.date;
      t -> date -= atoi(++tstr);
      while (t -> date <= 0) {
	t -> monthno--;
	if (t -> monthno < 0) {
	  t -> monthno += 12;
	  t -> year--;
	}
	t -> date += monthlength[t -> monthno] +
	  ISLEAPFEB(t -> monthno, t -> year);
      }
    }
    else if (*tstr == '+') {
      t -> date = starttimec.date;
      t -> date += atoi(++tstr);
      while (t -> date > monthlength[t -> monthno] +
	     ISLEAPFEB(t -> monthno, t -> year)) {
	t -> date -= monthlength[t -> monthno] +
	  ISLEAPFEB(t -> monthno, t -> year);
	t -> monthno++;
	if (t -> monthno > 11) {
	  t -> monthno -= 12;
	  t -> year++;
	}
      }
    }
    else {
      t -> date = 10 * (*tstr - '0');
      t -> date += (*(++tstr) - '0');
    }
    if (from) {
      t -> hr = 0;
      t -> min = 0;
    }
    else {
      t -> hr = 23;
      t -> min = 59;
    }
    t -> code = timecode(t -> date, t -> monthno, t -> year, t -> hr,
			 t -> min);
  }
}

void configstr(char *name, char *target, char *comname, char *inputline,
	       int rc)  /* NB: name must have size at least MSL */
{
  if (rc < 2)
    configwarning(comname, inputline);
  else {
    if (rc > 2)
      configwarning3(comname, inputline);
    strncpy(target, name, MAXSTRINGLENGTH - 1);
  }
}

void configstrlist(char *name, struct stringlist **p, char *comname,
		   char *inputline, int rc)
{   /* one or more of a list of strings */ /* NB in configstr() applies */
  char *tempstr;

  if (rc < 2)
    configwarning(comname, inputline);
  else {
    if (rc > 2)
      configwarning3(comname, inputline);
    tempstr = strtok(name, ",");
    strncpy((*p) -> name, tempstr, MAXSTRINGLENGTH - 1);
    (*p) -> name[MAXSTRINGLENGTH - 1] = '\0';
    (*p) -> next = (struct stringlist *)xmalloc(sizeof(struct stringlist));
    *p = (*p) -> next;
    (*p) -> name[0] = '\0';
    while ((tempstr = strtok((char *)NULL, ",")) != NULL) {
      strncpy((*p) -> name, tempstr, MAXSTRINGLENGTH - 1);
      (*p) -> name[MAXSTRINGLENGTH - 1] = '\0';
      (*p) -> next = (struct stringlist *)xmalloc(sizeof(struct stringlist));
      *p = (*p) -> next;
      (*p) -> name[0] = '\0';
    }
  }
}


void configcols(char *cols, char *target, char *comname, char *inputline,
		int rc)
{                           /* as configstr, but extra length check */
  if (rc < 2)
    configwarning(comname, inputline);
  else {
    if (rc > 2 || (int)strlen(cols) > 4)
      configwarning3(comname, inputline);
    strncpy(target, cols, 4);
  }
}

void configchar(char *str, char *target, char *comname, char *inputline,
		int rc)
{                           /* read in a single character */
  if (rc < 2)
    configwarning(comname, inputline);
  else {
    if (rc > 2 || str[1] != '\0')
      configwarning3(comname, inputline);
    *target = str[0];
  }
}

void configint(char *number, int *target, char *comname, char *inputline,
	       int rc)
{
  if (rc < 2)
    configwarning(comname, inputline);
  else {
    if (rc > 2)
      configwarning3(comname, inputline);
    *target = atoi(number);
  }
}

void configsortby(char *method, int *target, char *comname, char *inputline,
		  int rc)
{
  extern char *strtoupper();   /* in utils.c */

  if (rc < 2)
    configwarning(comname, inputline);
  else {
    strtoupper(method);
    if (STREQ(method, "REQUESTS"))
      *target = BYREQUESTS;
    else if (STREQ(method, "BYTES"))
      *target = BYBYTES;
    else if (STREQ(method, "ALPHABETICAL"))
      *target = ALPHABETICAL;
    else if (STREQ(method, "RANDOM"))
      *target = RANDOMLY;
    else
      configwarning2(inputline);
  }
}

void onoff(char *method, flag *target, char *comname, char *inputline, int rc)
{
  extern char *strtoupper();   /* in utils.c */

  if (rc < 2)
    configwarning(comname, inputline);
  else {
    strtoupper(method);
    if (STREQ(method, "ON"))
      *target = ON;
    else if (STREQ(method, "OFF"))
      *target = OFF;
    else
      configwarning2(inputline);
  }
}

void configline(char inputline[MAXLINELENGTH])  /* process one configline */
{
  enum {BADCOMMAND_, FILEALIAS_, HOSTALIAS_, REFALIAS_, FILEINCLUDE_, 
	  FILEEXCLUDE_, HOSTINCLUDE_, HOSTEXCLUDE_, REFINCLUDE_, REFEXCLUDE_,
	  FROM_, TO_, SUBDOMAIN_, WEEKBEGINSON_, APPROXHOSTSIZE_, ISPAGE_,
	  ISNOTPAGE_, SEPCHAR_, REPORTORDER_, WITHARGS_, WITHOUTARGS_,
	  REFWITHARGS_, REFWITHOUTARGS_, NOTSUBDOMAIN_, BASEURL_, DOMCOLS_,
	  HOSTCOLS_, DIRCOLS_, REQCOLS_, REFCOLS_, BROWCOLS_, FULLBROWCOLS_,
	  MONTHCOLS_, DAYCOLS_, FULLDAYCOLS_, WEEKCOLS_, HOURCOLS_,
	  FULLHOURCOLS_, MONTHGRAPH_, DAYGRAPH_, FULLDAYGRAPH_, HOURGRAPH_,
	  FULLHOURGRAPH_, WEEKGRAPH_, GRAPHICAL_, LOGFILE_, CACHEFILE_,
	  REFLOG_, BROWLOG_, ERRLOG_, DOMAINSFILE_, HOSTNAME_, HOSTURL_,
	  HOSTMINREQS_, DOMMINREQS_, SUBDOMMINREQS_, DIRMINREQS_, REQMINREQS_,
	  REFMINREQS_, BROWMINREQS_, FULLBROWMINREQS_, HOSTMINBYTES_,
	  DOMMINBYTES_, SUBDOMMINBYTES_, DIRMINBYTES_, REQMINBYTES_,
	  REFMINBYTES_, BROWMINBYTES_, FULLBROWMINBYTES_, ERRMINOCCS_,
	  REQSORTBY_, DOMSORTBY_, DIRSORTBY_, HOSTSORTBY_, REFSORTBY_,
	  BROWSORTBY_, FULLBROWSORTBY_, MARKCHAR_, PAGEWIDTH_, ALLBACK_,
	  MONTHLYBACK_, FULLHOURLYBACK_, FULLDAILYBACK_, WEEKLYBACK_,
	  MONTHLY_, DAILY_, FULLDAILY_, WEEKLY_, HOURLY_, FULLHOURLY_, DOMAIN_,
	  DIRECTORY_, REQUEST_, FULLHOSTS_, REFERER_, BROWSER_, FULLBROWSER_,
	  STATUS_, ERROR_, DIRLEVEL_, REQTYPE_, PAGELINKS_, COUNTHOSTS_,
	  LASTSEVEN_, WARNINGS_, IMAGEDIR_,
	  MONTHLYUNIT_, HOURLYUNIT_, FULLHOURLYUNIT_, DAILYUNIT_, LOGOURL_,
	  HEADERFILE_, FOOTERFILE_, FULLDAILYUNIT_, WEEKLYUNIT_, ALL_,
	  GENERAL_, OUTPUT_, DEBUG_, RAWBYTES_, UNCOMPRESS_, OUTFILE_}
  commandtype;   /* final '_'s to avoid clashes with #defines */

  extern int sscanf_config();  /* in sscanf.c */
  extern char *strtolower();   /* in utils.c */
  extern char *strtoupper();   /* in utils.c */

  char string1[MAXSTRINGLENGTH], string2[MAXSTRINGLENGTH],
       string3[MAXSTRINGLENGTH];
  int rc;
  flag tempflag;

  rc = sscanf_config(inputline, string1, string2, string3);
  if (rc > 0) {
    commandtype = BADCOMMAND_;   /* pessimism :) */
    strtoupper(string1);
    if (STREQ(string1, "FILEALIAS"))
      commandtype = FILEALIAS_;
    else if (STREQ(string1, "HOSTALIAS"))
      commandtype = HOSTALIAS_;
    else if (STREQ(string1, "REFALIAS"))
      commandtype = REFALIAS_;
    else if (STREQ(string1, "FILEINCLUDE"))
      commandtype = FILEINCLUDE_;
    else if (STREQ(string1, "FILEEXCLUDE"))
      commandtype = FILEEXCLUDE_;
    else if (STREQ(string1, "HOSTINCLUDE"))
      commandtype = HOSTINCLUDE_;
    else if (STREQ(string1, "HOSTEXCLUDE"))
      commandtype = HOSTEXCLUDE_;
    else if (STREQ(string1, "REFINCLUDE"))
      commandtype = REFINCLUDE_;
    else if (STREQ(string1, "REFEXCLUDE"))
      commandtype = REFEXCLUDE_;
    else if (STREQ(string1, "FROM"))
      commandtype = FROM_;
    else if (STREQ(string1, "TO"))
      commandtype = TO_;
    else if (STREQ(string1, "SUBDOMAIN"))
      commandtype = SUBDOMAIN_;
    else if (STREQ(string1, "WEEKBEGINSON"))
      commandtype = WEEKBEGINSON_;
    else if (STREQ(string1, "APPROXHOSTSIZE"))
      commandtype = APPROXHOSTSIZE_;
    else if (STREQ(string1, "ISPAGE"))
      commandtype = ISPAGE_;
    else if (STREQ(string1, "ISNOTPAGE"))
      commandtype = ISNOTPAGE_;
    else if (STREQ(string1, "SEPCHAR"))
      commandtype = SEPCHAR_;
    else if (STREQ(string1, "REPORTORDER"))
      commandtype = REPORTORDER_;
    else if (STREQ(string1, "WITHARGS"))
      commandtype = WITHARGS_;
    else if (STREQ(string1, "WITHOUTARGS"))
      commandtype = WITHOUTARGS_;
    else if (STREQ(string1, "REFWITHARGS"))
      commandtype = REFWITHARGS_;
    else if (STREQ(string1, "REFWITHOUTARGS"))
      commandtype = REFWITHOUTARGS_;
    else if (STREQ(string1, "NOTSUBDOMAIN"))
      commandtype = NOTSUBDOMAIN_;
    else if (STREQ(string1, "BASEURL"))
      commandtype = BASEURL_;
    else if (STREQ(string1, "DOMCOLS"))
      commandtype = DOMCOLS_;
    else if (STREQ(string1, "HOSTCOLS"))
      commandtype = HOSTCOLS_;
    else if (STREQ(string1, "DIRCOLS"))
      commandtype = DIRCOLS_;
    else if (STREQ(string1, "REQCOLS"))
      commandtype = REQCOLS_;
    else if (STREQ(string1, "REFCOLS"))
      commandtype = REFCOLS_;
    else if (STREQ(string1, "BROWCOLS"))
      commandtype = BROWCOLS_;
    else if (STREQ(string1, "FULLBROWCOLS"))
      commandtype = FULLBROWCOLS_;
    else if (STREQ(string1, "MONTHCOLS"))
      commandtype = MONTHCOLS_;
    else if (STREQ(string1, "DAYCOLS"))
      commandtype = DAYCOLS_;
    else if (STREQ(string1, "FULLDAYCOLS"))
      commandtype = FULLDAYCOLS_;
    else if (STREQ(string1, "WEEKCOLS"))
      commandtype = WEEKCOLS_;
    else if (STREQ(string1, "HOURCOLS"))
      commandtype = HOURCOLS_;
    else if (STREQ(string1, "FULLHOURCOLS"))
      commandtype = FULLHOURCOLS_;
    else if (STREQ(string1, "MONTHGRAPH"))
      commandtype = MONTHGRAPH_;
    else if (STREQ(string1, "DAYGRAPH"))
      commandtype = DAYGRAPH_;
    else if (STREQ(string1, "FULLDAYGRAPH"))
      commandtype = FULLDAYGRAPH_;
    else if (STREQ(string1, "HOURGRAPH"))
      commandtype = HOURGRAPH_;
    else if (STREQ(string1, "FULLHOURGRAPH"))
      commandtype = FULLHOURGRAPH_;
    else if (STREQ(string1, "WEEKGRAPH"))
      commandtype = WEEKGRAPH_;
    else if (STREQ(string1, "GRAPHICAL"))
      commandtype = GRAPHICAL_;
    else if (STREQ(string1, "LOGFILE"))
      commandtype = LOGFILE_;
    else if (STREQ(string1, "CACHEFILE"))
      commandtype = CACHEFILE_;
    else if (STREQ(string1, "REFLOG"))
      commandtype = REFLOG_;
    else if (STREQ(string1, "BROWLOG"))
      commandtype = BROWLOG_;
    else if (STREQ(string1, "ERRLOG"))
      commandtype = ERRLOG_;
    else if (STREQ(string1, "DOMAINSFILE"))
      commandtype = DOMAINSFILE_;
    else if (STREQ(string1, "HOSTNAME"))
      commandtype = HOSTNAME_;
    else if (STREQ(string1, "HOSTURL"))
      commandtype = HOSTURL_;
    else if (STREQ(string1, "HOSTMINREQS"))
      commandtype = HOSTMINREQS_;
    else if (STREQ(string1, "DOMMINREQS"))
      commandtype = DOMMINREQS_;
    else if (STREQ(string1, "SUBDOMMINREQS"))
      commandtype = SUBDOMMINREQS_;
    else if (STREQ(string1, "DIRMINREQS"))
      commandtype = DIRMINREQS_;
    else if (STREQ(string1, "REQMINREQS"))
      commandtype = REQMINREQS_;
    else if (STREQ(string1, "REFMINREQS"))
      commandtype = REFMINREQS_;
    else if (STREQ(string1, "BROWMINREQS"))
      commandtype = BROWMINREQS_;
    else if (STREQ(string1, "FULLBROWMINREQS"))
      commandtype = FULLBROWMINREQS_;
    else if (STREQ(string1, "HOSTMINBYTES"))
      commandtype = HOSTMINBYTES_;
    else if (STREQ(string1, "DOMMINBYTES"))
    commandtype = DOMMINBYTES_;
    else if (STREQ(string1, "SUBDOMMINBYTES"))
      commandtype = SUBDOMMINBYTES_;
    else if (STREQ(string1, "DIRMINBYTES"))
      commandtype = DIRMINBYTES_;
    else if (STREQ(string1, "REQMINBYTES"))
      commandtype = REQMINBYTES_;
    else if (STREQ(string1, "REFMINBYTES"))
      commandtype = REFMINBYTES_;
    else if (STREQ(string1, "BROWMINBYTES"))
      commandtype = BROWMINBYTES_;
    else if (STREQ(string1, "FULLBROWMINBYTES"))
      commandtype = FULLBROWMINBYTES_;
    else if (STREQ(string1, "ERRMINOCCS"))
      commandtype = ERRMINOCCS_;
    else if (STREQ(string1, "REQSORTBY"))
      commandtype = REQSORTBY_;
    else if (STREQ(string1, "DOMSORTBY"))
      commandtype = DOMSORTBY_;
    else if (STREQ(string1, "DIRSORTBY"))
      commandtype = DIRSORTBY_;
    else if (STREQ(string1, "HOSTSORTBY"))
      commandtype = HOSTSORTBY_;
    else if (STREQ(string1, "MARKCHAR"))
      commandtype = MARKCHAR_;
    else if (STREQ(string1, "PAGEWIDTH"))
      commandtype = PAGEWIDTH_;
    else if (STREQ(string1, "ALLBACK"))
      commandtype = ALLBACK_;
    else if (STREQ(string1, "MONTHLYBACK"))
      commandtype = MONTHLYBACK_;
    else if (STREQ(string1, "FULLHOURLYBACK"))
      commandtype = FULLHOURLYBACK_;
    else if (STREQ(string1, "FULLDAILYBACK"))
      commandtype = FULLDAILYBACK_;
    else if (STREQ(string1, "WEEKLYBACK"))
      commandtype = WEEKLYBACK_;
    else if (STREQ(string1, "MONTHLY"))
      commandtype = MONTHLY_;
    else if (STREQ(string1, "DAILY"))
      commandtype = DAILY_;
    else if (STREQ(string1, "FULLDAILY"))
      commandtype = FULLDAILY_;
    else if (STREQ(string1, "WEEKLY"))
      commandtype = WEEKLY_;
    else if (STREQ(string1, "HOURLY"))
      commandtype = HOURLY_;
    else if (STREQ(string1, "FULLHOURLY"))
      commandtype = FULLHOURLY_;
    else if (STREQ(string1, "DOMAIN"))
      commandtype = DOMAIN_;
    else if (STREQ(string1, "DIRECTORY"))
      commandtype = DIRECTORY_;
    else if (STREQ(string1, "REQUEST"))
      commandtype = REQUEST_;
    else if (STREQ(string1, "FULLHOSTS"))
      commandtype = FULLHOSTS_;
    else if (STREQ(string1, "REFERER"))
      commandtype = REFERER_;
    else if (STREQ(string1, "BROWSER"))
      commandtype = BROWSER_;
    else if (STREQ(string1, "FULLBROWSER"))
      commandtype = FULLBROWSER_;
    else if (STREQ(string1, "STATUS"))
      commandtype = STATUS_;
    else if (STREQ(string1, "ERROR"))
      commandtype = ERROR_;
    else if (STREQ(string1, "DIRLEVEL"))
      commandtype = DIRLEVEL_;
    else if (STREQ(string1, "REQTYPE"))
      commandtype = REQTYPE_;
    else if (STREQ(string1, "PAGELINKS"))
      commandtype = PAGELINKS_;
    else if (STREQ(string1, "COUNTHOSTS"))
      commandtype = COUNTHOSTS_;
    else if (STREQ(string1, "LASTSEVEN"))
      commandtype = LASTSEVEN_;
    else if (STREQ(string1, "WARNINGS"))
      commandtype = WARNINGS_;
    else if (STREQ(string1, "IMAGEDIR"))
      commandtype = IMAGEDIR_;
    else if (STREQ(string1, "MONTHLYUNIT"))
      commandtype = MONTHLYUNIT_;
    else if (STREQ(string1, "HOURLYUNIT"))
      commandtype = HOURLYUNIT_;
    else if (STREQ(string1, "FULLHOURLYUNIT"))
      commandtype = FULLHOURLYUNIT_;
    else if (STREQ(string1, "DAILYUNIT"))
      commandtype = DAILYUNIT_;
    else if (STREQ(string1, "FULLDAILYUNIT"))
      commandtype = FULLDAILYUNIT_;
    else if (STREQ(string1, "WEEKLYUNIT"))
      commandtype = WEEKLYUNIT_;
    else if (STREQ(string1, "LOGOURL"))
      commandtype = LOGOURL_;
    else if (STREQ(string1, "HEADERFILE"))
      commandtype = HEADERFILE_;
    else if (STREQ(string1, "FOOTERFILE"))
      commandtype = FOOTERFILE_;
    else if (STREQ(string1, "ALL"))
      commandtype = ALL_;
    else if (STREQ(string1, "GENERAL"))
      commandtype = GENERAL_;
    else if (STREQ(string1, "OUTPUT"))
      commandtype = OUTPUT_;
    else if (STREQ(string1, "DEBUG"))
      commandtype = DEBUG_;
    else if (STREQ(string1, "RAWBYTES"))
      commandtype = RAWBYTES_;
    else if (STREQ(string1, "UNCOMPRESS"))
      commandtype = UNCOMPRESS_;
    else if (STREQ(string1, "OUTFILE"))
      commandtype = OUTFILE_;
    
    switch(commandtype) {
    case (BADCOMMAND_):
      configwarning2(inputline);
      break;
    case (FILEALIAS_):
      configalias(string2, string3, &filealiasp, string1, inputline, rc);
      break;
    case (HOSTALIAS_):
      configalias(strtolower(string2), strtolower(string3), &hostaliasp,
		  string1, inputline, rc);
      break;
    case (REFALIAS_):
      configalias(string2, string3, &refaliasp, string1, inputline, rc);
      break;
    case (FILEINCLUDE_):
      include(string2, &wantfilep, TRUE, string1, inputline, rc, &filemaskq);
      break;
    case (FILEEXCLUDE_):
      include(string2, &wantfilep, FALSE, string1, inputline, rc, &filemaskq);
      break;
    case (HOSTINCLUDE_):
      include(string2,& wanthostp, TRUE, string1, inputline, rc, &hostmaskq);
      break;
    case (HOSTEXCLUDE_):
      include(string2, &wanthostp, FALSE, string1, inputline, rc, &hostmaskq);
      break;
    case (REFINCLUDE_):
      include(string2, &wantrefp, TRUE, string1, inputline, rc, &refmaskq);
      break;
    case (REFEXCLUDE_):
      include(string2, &wantrefp, FALSE, string1, inputline, rc, &refmaskq);
      break;
    case (FROM_):
      fromtodate(string2, &fromtime, TRUE, string1, inputline, rc);
    break;
    case (TO_):
      fromtodate(string2, &totime, FALSE, string1, inputline, rc);
      break;
    case (SUBDOMAIN_):
      if (string2[0] == '\0')
	configwarning2(inputline);
      else if (rc < 2)
	configwarning(string1, inputline);
      else {
	if (rc > 3 ||
	    (rc == 3 && (string2[0] == '*' || 
			 string2[(int)strlen(string2) - 1] == '*' ||
			 string2[0] == '%')))
	  configwarning3(string1, inputline);
	strcpy(subdomp -> from, string2);
	if (rc == 2 || string2[0] == '*' ||
	    string2[(int)strlen(string2) - 1] == '*' || string2[0] == '%')
	  strcpy(subdomp -> to, "?");
	else
	  strcpy(subdomp -> to, string3);
	subdomp -> next =
	  (struct alias *)xmalloc(sizeof(struct alias));
	subdomp = subdomp -> next;
	subdomp -> from[0] = '\0';
      }
      break;
    case (WEEKBEGINSON_):
      if (rc < 2)
	configwarning(string1, inputline);
      else {
	strtoupper(string2);
	if (STREQ(string2, "SUNDAY"))
	  weekbeginson = SUNDAY;
	else if (STREQ(string2, "MONDAY"))
	  weekbeginson = MONDAY;
	else if (STREQ(string2, "TUESDAY"))
	  weekbeginson = TUESDAY;
	else if (STREQ(string2, "WEDNESDAY"))
	  weekbeginson = WEDNESDAY;
	else if (STREQ(string2, "THURSDAY"))
	  weekbeginson = THURSDAY;
	else if (STREQ(string2, "FRIDAY"))
	  weekbeginson = FRIDAY;
	else if (STREQ(string2, "SATURDAY"))
	  weekbeginson = SATURDAY;
	else
	  configwarning2(inputline);
      }
      break;
    case (APPROXHOSTSIZE_):
      if (rc < 2)
	configwarning(string1, inputline);
      else {
	if (rc > 2)
	  configwarning3(string1, inputline);
	approxhostsize = atoi(string2);
	if (approxhostsize <= 0)
	  configwarning2(inputline);
      }
      break;
    case (ISPAGE_):
      include(string2, &ispagep, TRUE, string1, inputline, rc, &tempflag);
      break;
    case (ISNOTPAGE_):
      include(string2, &ispagep, FALSE, string1, inputline, rc, &tempflag);
      break;
    case (SEPCHAR_):
      if (rc < 2)
	configwarning(string1, inputline);
      else {
	if (rc > 2 || (string2[0] != '\0' && string2[1] != '\0'))
	  configwarning3(string1, inputline);
	sepchar = string2[0];
      }
    break;
    case (REPORTORDER_):
      if (rc < 2)
	configwarning(string1, inputline);
      else {
	if (rc > 2 || (int)strlen(string2) > 15)
	  configwarning3(string1, inputline);
	strncpy(reportorder, string2, 15);
    }
      break;
    case (WITHARGS_):
      include(string2, &noexpandp, FALSE, string1, inputline, rc, &tempflag);
      break;
    case (WITHOUTARGS_):
      include(string2, &noexpandp, TRUE, string1, inputline, rc, &tempflag);
      break;
    case (REFWITHARGS_):
      include(string2, &refexpandp, TRUE, string1, inputline, rc, &tempflag);
    break;
    case (REFWITHOUTARGS_):
      include(string2, &refexpandp, FALSE, string1, inputline, rc, &tempflag);
      break;
    case (NOTSUBDOMAIN_):
      if (rc < 2)
	configwarning(string1, inputline);
      else {
	if (rc > 2)
	  configwarning3(string1, inputline);
	for (subdomtempp = subdomshead; subdomtempp -> from[0] != '\0' &&
	     !STREQ(subdomtempp -> from, string2);
	     subdomtempp = subdomtempp -> next)
	  ;     /* run to the subdomain we want to remove */
	if (subdomtempp -> from[0] != '\0')
	  subdomtempp -> from[0] = '?';   /* mark that we don't want it */
      }
      break;
    case (BASEURL_):
      configstr(string2, baseurl, string1, inputline, rc);
      break;
    case (DOMCOLS_):
      configcols(string2, domcols, string1, inputline, rc);
      break;
    case (HOSTCOLS_):
      configcols(string2, hostcols, string1, inputline, rc);
      break;
    case (DIRCOLS_):
      configcols(string2, dircols, string1, inputline, rc);
      break;
    case (REQCOLS_):
      configcols(string2, reqcols, string1, inputline, rc);
      break;
    case (REFCOLS_):
      configcols(string2, refcols, string1, inputline, rc);
      break;
    case (BROWCOLS_):
      configcols(string2, browcols, string1, inputline, rc);
      break;
    case (FULLBROWCOLS_):
      configcols(string2, fullbrowcols, string1, inputline, rc);
      break;
    case (MONTHCOLS_):
      configcols(string2, monthcols, string1, inputline, rc);
      break;
    case (DAYCOLS_):
      configcols(string2, daycols, string1, inputline, rc);
      break;
    case (FULLDAYCOLS_):
      configcols(string2, fulldaycols, string1, inputline, rc);
      break;
    case (WEEKCOLS_):
      configcols(string2, weekcols, string1, inputline, rc);
      break;
    case (HOURCOLS_):
      configcols(string2, hourcols, string1, inputline, rc);
      break;
    case (FULLHOURCOLS_):
      configcols(string2, fullhourcols, string1, inputline, rc);
      break;
    case (MONTHGRAPH_):
      configchar(string2, &monthgraph, string1, inputline, rc);
      break;
    case (DAYGRAPH_):
      configchar(string2, &daygraph, string1, inputline, rc);
      break;
    case (FULLDAYGRAPH_):
      configchar(string2, &fulldaygraph, string1, inputline, rc);
      break;
    case (HOURGRAPH_):
      configchar(string2, &hourgraph, string1, inputline, rc);
      break;
    case (FULLHOURGRAPH_):
      configchar(string2, &fullhourgraph, string1, inputline, rc);
      break;
    case (WEEKGRAPH_):
      configchar(string2, &weekgraph, string1, inputline, rc);
      break;
    case (GRAPHICAL_):
      onoff(string2, &graphical, string1, inputline, rc);
      break;
    case (LOGFILE_):
      if (rc < 2)
	configwarning(string1, inputline);
      else if (STREQ(string2, "none")) {
	logfilep = logfilehead;
	logfilehead -> name[0] = '\0';
      }
      else if (rc == 2)
	addlogfile(&logfilep, string2, "");
      else {
	addlogfile(&logfilep, string2, string3);
	if (rc > 3)
	  configwarning3(string1, inputline);
      }
      break;
    case (CACHEFILE_):
      if (STREQ(string2, "none")) {
	cachefilep = cachefilehead;
	cachefilehead -> name[0] = '\0';
      }
      else
	configstrlist(string2, &cachefilep, string1, inputline, rc);
      break;
    case (REFLOG_):
      if (STREQ(string2, "none")) {
	reflogp = refloghead;
	refloghead -> name[0] = '\0';
      }
      else
	configstrlist(string2, &reflogp, string1, inputline, rc);
      break;
    case (BROWLOG_):
      if (STREQ(string2, "none")) {
	browlogp = browloghead;
	browloghead -> name[0] = '\0';
      }
      else
	configstrlist(string2, &browlogp, string1, inputline, rc);
      break;
    case (ERRLOG_):
    if (STREQ(string2, "none")) {
      errlogp = errloghead;
      errloghead -> name[0] = '\0';
    }
    else
      configstrlist(string2, &errlogp, string1, inputline, rc);
      break;
    case (DOMAINSFILE_):
      configstr(string2, domainsfile, string1, inputline, rc);
      break;
    case (HOSTNAME_):
      configstr(string2, hostname, string1, inputline, rc);
      break;
    case (HOSTURL_):
      configstr(string2, hosturl, string1, inputline, rc);
      break;
    case (HOSTMINREQS_):
      configstr(string2, hostminreqstr, string1, inputline, rc);
      break;
    case (DOMMINREQS_):
      configstr(string2, domminreqstr, string1, inputline, rc);
      break;
    case (SUBDOMMINREQS_):
      configstr(string2, subdomminreqstr, string1, inputline, rc);
      break;
    case (DIRMINREQS_):
      configstr(string2, dirminreqstr, string1, inputline, rc);
      break;
    case (REQMINREQS_):
      configstr(string2, urlminreqstr, string1, inputline, rc);
      break;
    case (REFMINREQS_):
      configstr(string2, refminreqstr, string1, inputline, rc);
      break;
    case (BROWMINREQS_):
      configstr(string2, browminreqstr, string1, inputline, rc);
      break;
    case (FULLBROWMINREQS_):
      configstr(string2, fullbrowminreqstr, string1, inputline, rc);
      break;
    case (HOSTMINBYTES_):
      configstr(string2, hostminbytestr, string1, inputline, rc);
    break;
    case (DOMMINBYTES_):
      configstr(string2, domminbytestr, string1, inputline, rc);
      break;
    case (SUBDOMMINBYTES_):
      configstr(string2, subdomminbytestr, string1, inputline, rc);
      break;
    case (DIRMINBYTES_):
      configstr(string2, dirminbytestr, string1, inputline, rc);
      break;
    case (REQMINBYTES_):
      configstr(string2, urlminbytestr, string1, inputline, rc);
      break;
    case (REFMINBYTES_):
      configstr(string2, refminbytestr, string1, inputline, rc);
      break;
    case (BROWMINBYTES_):
      configstr(string2, browminbytestr, string1, inputline, rc);
      break;
    case (FULLBROWMINBYTES_):
      configstr(string2, fullbrowminbytestr, string1, inputline, rc);
      break;
    case (ERRMINOCCS_):
      configint(string2, &errminreqs, string1, inputline, rc);
      break;
    case (REQSORTBY_):
      configsortby(string2, &reqsortby, string1, inputline, rc);
      break;
    case (DOMSORTBY_):
      configsortby(string2, &domsortby, string1, inputline, rc);
      break;
    case (DIRSORTBY_):
      configsortby(string2, &dirsortby, string1, inputline, rc);
      break;
    case (HOSTSORTBY_):
      configsortby(string2, &hostsortby, string1, inputline, rc);
      break;
    case (REFSORTBY_):
      configsortby(string2, &refsortby, string1, inputline, rc);
      break;
    case (BROWSORTBY_):
      configsortby(string2, &browsortby, string1, inputline, rc);
      break;
    case (FULLBROWSORTBY_):
      configsortby(string2, &fullbrowsortby, string1, inputline, rc);
      break;
    case (MARKCHAR_):
      if (rc < 2)
	configwarning(string1, inputline);
      else {
	if (rc > 2 || string2[1] != '\0')
	  configwarning3(string1, inputline);
	markchar = string2[0];
      }
      break;
    case (PAGEWIDTH_):
      if (rc < 2)
	configwarning(string1, inputline);
      else {
	if (rc > 2)
	  configwarning3(string1, inputline);
	pagewidth = atoi(string2);
	if (pagewidth < MINPAGEWIDTH || pagewidth > MAXPAGEWIDTH) {
	  fprintf(stderr, "%s: Page width should be between %d and %d\n",
		  commandname, MINPAGEWIDTH, MAXPAGEWIDTH);
	  configwarning2(inputline);
	  pagewidth = PAGEWIDTH;
	}
      }
      break;
    case (ALLBACK_):  /* onoff() extended */
      if (rc < 2)
	configwarning(string1, inputline);
      else {
	strtoupper(string2);
	if (STREQ(string2, "ON")) {
	  mback = ON;
	  Hback = ON;
	  Wback = ON;
	  Dback = ON;
	}
	else if (STREQ(string2, "OFF")) {
	  mback = OFF;
	  Hback = OFF;
	  Wback = OFF;
	  Dback = OFF;
	}
	else
	  configwarning2(inputline);
      }
      break;
    case (MONTHLYBACK_):
      onoff(string2, &mback, string1, inputline, rc);
      break;
    case (FULLHOURLYBACK_):
      onoff(string2, &Hback, string1, inputline, rc);
      break;
    case (FULLDAILYBACK_):
      onoff(string2, &Dback, string1, inputline, rc);
      break;
    case (WEEKLYBACK_):
      onoff(string2, &Wback, string1, inputline, rc);
      break;
    case (MONTHLY_):
      onoff(string2, &mq, string1, inputline, rc);
      break;
    case (DAILY_):
      onoff(string2, &dq, string1, inputline, rc);
      break;
    case (FULLDAILY_):
      onoff(string2, &Dq, string1, inputline, rc);
      break;
    case (HOURLY_):
      onoff(string2, &hq, string1, inputline, rc);
      break;
    case (FULLHOURLY_):
      onoff(string2, &Hq, string1, inputline, rc);
      break;
    case (WEEKLY_):
      onoff(string2, &Wq, string1, inputline, rc);
      break;
    case (DOMAIN_):
      onoff(string2, &oq, string1, inputline, rc);
      break;
    case (FULLHOSTS_):
      onoff(string2, &Sq, string1, inputline, rc);
      break;
    case (DIRECTORY_):
      onoff(string2, &iq, string1, inputline, rc);
      break;
    case (REQUEST_):
      onoff(string2, &rq, string1, inputline, rc);
      break;
    case (REFERER_):
      onoff(string2, &fq, string1, inputline, rc);
      break;
    case (BROWSER_):
      onoff(string2, &bq, string1, inputline, rc);
      break;
    case (FULLBROWSER_):
      onoff(string2, &Bq, string1, inputline, rc);
      break;
    case (STATUS_):
      onoff(string2, &cq, string1, inputline, rc);
      break;
    case (ERROR_):
      onoff(string2, &eq, string1, inputline, rc);
      break;
    case (ALL_):
      if (rc < 2)
	configwarning(string1, inputline);
      else {
	strtoupper(string2);
	if (STREQ(string2, "ON")) {
	  mq = ON;
	  Wq = ON;
	  dq = ON;
	  Dq = ON;
	  hq = ON;
	  oq = ON;
	  Sq = ON;
	  iq = ON;
	  rq = ON;
	  fq = ON;
	  bq = ON;
	  Bq = ON;
	  cq = ON;
	  eq = ON;
	}
	else if (STREQ(string2, "OFF"))  {
	  mq = OFF;
	  Wq = OFF;
	  dq = OFF;
	  Dq = OFF;
	  hq = OFF;
	  oq = OFF;
	  Sq = OFF;
	  iq = OFF;
	  rq = OFF;
	  fq = OFF;
	  bq = OFF;
	  Bq = OFF;
	  cq = OFF;
	  eq = OFF;
	}
	else
	  configwarning2(inputline);
      }
      break;
    case (GENERAL_):
      onoff(string2, &xq, string1, inputline, rc);
      break;
    case (DIRLEVEL_):
      configint(string2, &dirlevel, string1, inputline, rc);
      break;
    case (REQTYPE_):
      if (rc < 2)
	configwarning(string1, inputline);
      else {
	strtoupper(string2);
	if (STREQ(string2, "PAGES"))
	  reqtype = PAGES;
	else if (STREQ(string2, "ALL"))
	  reqtype = ALL;
	else
	  configwarning2(inputline);
      }
      break;
    case (PAGELINKS_):
      if (rc < 2)
	configwarning(string1, inputline);
      else {
	strtoupper(string2);
	if (STREQ(string2, "ON"))
	  kq = ON;
	else if (STREQ(string2, "OFF"))
	  kq = OFF;
	else if (STREQ(string2, "ALL"))
	  kq = ALL;
	else
	  configwarning2(inputline);
      }
      break;
    case (COUNTHOSTS_):
      if (rc < 2)
	configwarning(string1, inputline);
      else {
	strtoupper(string2);
	if (STREQ(string2, "ON"))
	  sq = ON;
	else if (STREQ(string2, "OFF"))
	  sq = OFF;
	else if (STREQ(string2, "APPROX"))
	  sq = APPROX;
	else
	  configwarning2(inputline);
      }
      break;
    case (LASTSEVEN_):
      onoff(string2, &q7, string1, inputline, rc);
      break;
    case (WARNINGS_):
      onoff(string2, &warnq, string1, inputline, rc);
      break;
    case (IMAGEDIR_):
      configstr(string2, imagedir, string1, inputline, rc);
      break;
    case (MONTHLYUNIT_):
      configint(string2, &monthlyunit, string1, inputline, rc);	  
      break;
    case (HOURLYUNIT_):
      configint(string2, &hourlyunit, string1, inputline, rc);	  
      break;
    case (FULLHOURLYUNIT_):
      configint(string2, &fullhourlyunit, string1, inputline, rc);	  
      break;
    case (DAILYUNIT_):
      configint(string2, &dailyunit, string1, inputline, rc);	  
      break;
    case (FULLDAILYUNIT_):
      configint(string2, &fulldailyunit, string1, inputline, rc);	  
      break;
    case (WEEKLYUNIT_):
      configint(string2, &weeklyunit, string1, inputline, rc);	  
      break;
    case (LOGOURL_):
      configstr(string2, logourl, string1, inputline, rc);
      break;
    case (HEADERFILE_):
      configstr(string2, headerfile, string1, inputline, rc);
      break;
    case (FOOTERFILE_):
      configstr(string2, footerfile, string1, inputline, rc);
      break;
    case (OUTPUT_):
      if (rc < 2)
	configwarning(string1, inputline);
      else {
	strtoupper(string2);
	if (STREQ(string2, "ASCII"))
	  aq = ASCII;
	else if (STREQ(string2, "HTML"))
	  aq = HTML;
	else if (STREQ(string2, "CACHE"))
	  aq = CACHE;
	else
	  configwarning2(inputline);
      }
      break;
    case (DEBUG_):
      configint(string2, &debug, string1, inputline, rc);	  
      break;
    case (RAWBYTES_):
      onoff(string2, &rawbytes, string1, inputline, rc);
      break;
    case (UNCOMPRESS_):
      if (rc < 3)
	configwarning(string1, inputline);
      else {
	addlogfile(&uncompressp, string2, string3);
	if (rc > 3)
	  configwarning3(string1, inputline);
      }
      break;
    case (OUTFILE_):
      configstr(string2, outfile, string1, inputline, rc);
      break;
    }
  }
}

flag config(char *filename)
{

  FILE *cf;
  char inputline[MAXLINELENGTH];

  if (STREQ(filename, "none"))
    return(0);
  else if (STREQ(filename, "stdin") || STREQ(filename, "-"))
    cf = stdin;
  else
    cf = fopen(filename, "r");

  if (cf == NULL) {
    if (warnq)
      fprintf(stderr, "%s: Warning: Failed to open configuration file \"%s\": ignoring it\n", commandname, filename);
    return(1);
  }

  else {  /* we can read the config. file */
    while (fgets(inputline, MAXLINELENGTH, cf) != NULL)
      configline(inputline);
    return(0);
  }
}

/*** Now the functions to parse the commandline arguments ***/

/* As in the config commands, first some subfunctions */

void clflag(flag *f, char *arg)   /* simple on/off switches */
{
  if (arg[0] == '-')
    *f = OFF;
  else
    *f = ON;
  if (arg[2] != '\0' && warnq)
    fprintf(stderr, "%s: Warning: ignoring extra text after %c%c option\n",
	    commandname, arg[0], arg[1]);
}

void cldaterep(flag *f, char *graph, char *arg)
{
  if (arg[0] == '-') {
    *f = OFF;
    if (arg[2] != '\0' && warnq)
      fprintf(stderr, "%s: Warning: ignoring extra text after -%c option\n",
	      commandname, arg[1]);
  }
  else {
    *f = ON;
    if (arg[2] != '\0') {
      if (arg[2] != 'b' && arg[2] != 'r' && arg[2] != 'B' && arg[2] != 'R') {
	fprintf(stderr, "%s: Warning: unknown graph method %c at %s\n",
		commandname, arg[2], arg);
      }
      else {
	*graph = arg[2];
	if (arg[3] != '\0')
	  fprintf(stderr,
		  "%s: Warning: ignoring extra text after +%c%c option\n",
		  commandname, arg[1], arg[2]);
      }
    }
  }
}

void clgenrep(flag *f, int *sortby, char *minreqstr, char *minbytestr,
	      char *arg)    /* generic reports */
{
  if (arg[0] == '-') {
    *f = OFF;
    if (arg[2] != '\0' && warnq)
      fprintf(stderr, "%s: Warning: ignoring extra text after -%c option\n",
	      commandname, arg[1]);
  }
  else {
    *f = ON;
    switch (arg[2]) {
    case '\0':
      break;
    case 'a':
    case 'A':
      *sortby = ALPHABETICAL;
      if (arg[3] != '\0')
	strcpy(minreqstr, arg + 3);
      break;
    case 'b':
    case 'B':
      *sortby = BYBYTES;
      if (arg[3] != '\0')
	strcpy(minbytestr, arg + 3);
      break;
    case 'r':
    case 'R':
      *sortby = BYREQUESTS;
      if (arg[3] != '\0')
	strcpy(minreqstr, arg + 3);
      break;
    case 'x':
    case 'X':
      *sortby = RANDOMLY;
      if (arg[3] != '\0')
	strcpy(minreqstr, arg + 3);
      break;
    default:
      if (warnq)
	fprintf(stderr, "%s: Warning: unknown sort method %c at %s\n",
		commandname, arg[2], arg);
    }
  }
}

flag clfile(char *filename, char *arg)   /* read in a filename */
{
  if (arg[0] == '-') {
    strcpy(filename, "none");
    if (arg[2] != '\0' && warnq)
      fprintf(stderr, "%s: Warning: ignoring extra text after -%c option\n",
	      commandname, arg[1]);
  }
  else if (arg[2] == '\0') {
    if (warnq) {
      fprintf(stderr, "%s: Warning: no filename supplied after +%c option\n",
	      commandname, arg[1]);
      fprintf(stderr, "  (or space left before filename)\n");
    }
    return(ERR);
  }
  else
    strncpy(filename, arg + 2, MAXSTRINGLENGTH - 1);
  return(OK);
}

/* Now the main commandline command */

void commandline(int argc, char **argv)
{
  int i;

  flag Gfound = FALSE;
  char tempstr1[MAXSTRINGLENGTH], tempstr2[MAXSTRINGLENGTH];

  /* First see whether to include the default config. file, by scanning
     backwards through the arguments looking for the (last) occurrence of
     +G or -G. We then run the config. file, then look at the other args. */

  for (i = argc - 1; i >= 1 && !Gfound; i--) {
    if (argv[i][1] == 'G') {
      if (argv[i][2] != '\0' && (argv[i][0] == '+' || argv[i][0] == '-')) {
	if (warnq) {
	  fprintf(stderr,
		  "%s: Warning: ignoring extra text after %cG option\n",
		  commandname, argv[i][0]);
	}
      }
      if (argv[i][0] == '+') {
	Gfound = TRUE;
	config(DEFAULTCONFIGFILE);
      }
      else if (argv[i][0] == '-') {
	Gfound = TRUE;
      }
    }
  }
  if (!Gfound) {
    logfilep = logfilehead;
    cachefilep = cachefilehead;
    reflogp = refloghead;
    browlogp = browloghead;
    errlogp = errloghead;
    config(DEFAULTCONFIGFILE);
  }

  logfilep = logfilehead;  /* reset logfile pointers for over-write */
  cachefilep = cachefilehead;
  reflogp = refloghead;
  browlogp = browloghead;
  errlogp = errloghead;

  /* Now read the other arguments */

  for (i = 1; i < argc; i++) {

    if (argv[i][0] != '+' && argv[i][0] != '-') {
      if (STREQ(argv[i], "none")) {
	logfilep = logfilehead;
	logfilehead -> name[0] = '\0';
      }
      else
	addlogfile(&logfilep, argv[i], "");
    }
    else switch (argv[i][1]) {
    case '\0':    /* read stdin */
      addlogfile(&logfilep, "stdin", "");
      break;
    case '7':     /* stats for last 7 days */
      clflag(&q7, argv[i]);
      break;
    case 'a':     /* ASCII output */
      clflag(&aq, argv[i]);  /* This works because ON = ASCII, OFF = HTML */
      break;      
    case 'A':     /* all reports */
      if (argv[i][0] == '-')
	configline("ALL OFF");
      else
	configline("ALL ON");
      if (argv[i][2] != '\0' && warnq)
	fprintf(stderr, "%s: Warning: ignoring extra text after %cA option\n",
		commandname, argv[i][0]);
      break;
    case 'b':     /* browser summary */
      clgenrep(&bq, &browsortby, browminreqstr, browminbytestr, argv[i]);
      break;
    case 'B':     /* browser report */
      clgenrep(&Bq, &fullbrowsortby, fullbrowminreqstr, fullbrowminbytestr,
	       argv[i]);
      break;
    case 'c':     /* status code report */
      clflag(&cq, argv[i]);
      break;
    case 'C':     /* configuration command */
      if (argv[i][2] == '\0') {
	if (warnq) {
	  fprintf(stderr, "%s: Warning: no command supplied after +C option\n",
		  commandname);
	  fprintf(stderr, "  (or space left before command)\n");
	}
      }
      else
	configline(argv[i] + 2);
      break;
    case 'd':     /* daily summary */
      cldaterep(&dq, &daygraph, argv[i]);
      break;
    case 'D':     /* full daily report */
      cldaterep(&Dq, &fulldaygraph, argv[i]);
      break;
    case 'e':     /* error report */
      clflag(&eq, argv[i]);
      break;
    case 'f':     /* form */
      if (STREQ(argv[i] + 2, "orm"))
	formq = ON;
      else        /* referer report */
	clgenrep(&fq, &refsortby, refminreqstr, refminbytestr, argv[i]);
      break;
    case 'g':     /* configuration file */
      if (argv[i][0] == '+') {
	if (argv[i][2] == '\0') {
	  if (warnq) {
	    fprintf(stderr,
		    "%s: Warning: no filename supplied after +g option\n",
		    commandname);
	    fprintf(stderr, "  (or space left before filename)\n");
	  }
	}
	else
	  config(argv[i] + 2);
      }
      break;
    case 'F':     /* FROM */
      if (argv[i][0] == '-') {
	configline("FROM OFF");
	if (argv[i][2] != '\0' && warnq)
	  fprintf(stderr, "%s: Warning: ignoring extra text after -F option\n",
		  commandname);
      }
      else if (argv[i][2] == '\0' && warnq) {
	fprintf(stderr, "%s: Warning: no date supplied after +F option\n",
		commandname);
	fprintf(stderr, "  (or space left before date)\n");
      }
      else {
	strcpy(tempstr2, "FROM ");
	strcat(tempstr2, argv[i] + 2);
	configline(tempstr2);
      }
      break;
    case 'G':     /* default configuration file: done already */
      break;
    case 'h':     /* help */
      if (STREQ(argv[i] + 2, "elp")) {
	fprintf(stderr, "For help see Readme.html, or\n");
	fprintf(stderr, "  http://www.statslab.cam.ac.uk/~sret1/analog/analog/Readme.html\n");
	exit(OK);
      }
      else        /* hourly summary */
	cldaterep(&hq, &hourgraph, argv[i]);
      break;
    case 'H':     /* hourly report */
      cldaterep(&Hq, &fullhourgraph, argv[i]);
      break;
    case 'i':     /* directory report */
      clgenrep(&iq, &dirsortby, dirminreqstr, dirminbytestr, argv[i]);
      break;
    case 'k':     /* link to pages in req. report? */
      if (argv[i][0] == '-') {
	kq = OFF;
	if (argv[i][2] != '\0' && warnq)
	  fprintf(stderr, "%s: Warning: ignoring extra text after -k option\n",
		  commandname);
      }
      else {
	kq = ON;
	if (argv[i][2] == 'k')
	  kq = ALL;
      }
      break;
    case 'l':     /* 'level' of dir report */
      dirlevel = atoi(argv[i] + 2);
      break;
    case 'm':     /* monthly report */
      cldaterep(&mq, &monthgraph, argv[i]);
      break;
    case 'n':     /* our host or organisation name */
      if (argv[i][2] == '\0') {
	if (warnq) {
	  fprintf(stderr, "%s: Warning: no text supplied after %cn option\n",
		  commandname, argv[i][0]);
	  fprintf(stderr, "  (or space left before text)\n");
	}
      }
      else
	strncpy(hostname, argv[i] + 2, MAXSTRINGLENGTH - 1);
      break;
    case 'o':                 /* domain report */
      clgenrep(&oq, &domsortby, domminreqstr, domminbytestr, argv[i]);      
      break;
    case 'O':     /* outfile */
      clfile(outfile, argv[i]);
      break;
    case 'p':    /* logo? */
      clfile(logourl, argv[i]);
      break;
    case 'q':    /* warnings? */
      clflag(&warnq, argv[i]);
      break;
    case 'r':    /* request report */
    case 'R':
      if (argv[i][0] == '+') {
	if (argv[i][1] == 'r')
	  reqtype = PAGES;
	else
	  reqtype = ALL;
      }
      clgenrep(&rq, &reqsortby, urlminreqstr, urlminbytestr, argv[i]);
      break;
    case 's':      /* count hosts? */
      if (argv[i][0] == '-')
	sq = OFF;
      else if (argv[i][2] == 's')
	sq = APPROX;
      else
	sq = ON;
      if (argv[i][2] == 's') {
	if (argv[i][3] != '\0' && warnq)
	  fprintf(stderr,
		  "%s: Warning: ignoring extra text after %css option\n",
		  commandname, argv[i][0]);
      }
      else {  /* argv[i][2] != 's' */
	if (argv[i][2] != '\0' && warnq)
	  fprintf(stderr,
		  "%s: Warning: ignoring extra text after %cs option\n",
		  commandname, argv[i][0]);
      }
      break;
    case 'S':      /* full hostname report */
      clgenrep(&Sq, &hostsortby, hostminreqstr, hostminbytestr, argv[i]);
      break;
    case 'T':     /* TO */
      if (argv[i][0] == '-') {
	configline("TO OFF");
	if (argv[i][2] != '\0' && warnq)
	  fprintf(stderr, "%s: Warning: ignoring extra text after -T option\n",
		  commandname);
      }
      else if (argv[i][2] == '\0' && warnq) {
	fprintf(stderr, "%s: Warning: no date supplied after +T option\n",
		commandname);
	fprintf(stderr, "  (or space left before date)\n");
      }
      else {
	strcpy(tempstr2, "TO ");
	strcat(tempstr2, argv[i] + 2);
	configline(tempstr2);
      }
      break;
    case 'u':     /* host URL */
      if (argv[i][2] == '\0') {
	if (warnq) {
	  fprintf(stderr, "%s: Warning: no URL supplied after %cu option\n",
		  commandname, argv[i][0]);
	  fprintf(stderr, "  (or space left before URL)\n");
	}
      }
      else
	strncpy(hosturl, argv[i] + 2, MAXSTRINGLENGTH - 1);
      break;
    case 'U':      /* cache file */
      if(clfile(tempstr1, argv[i]) == OK) {
	strcpy(tempstr2, "CACHEFILE ");
	strncat(tempstr2, tempstr1, MAXSTRINGLENGTH - 11);
	configline(tempstr2);
      }
      break;
    case 'v':          /* print variables and exit */
      if (argv[i][2] != '\0' && warnq)
	fprintf(stderr, "%s: Warning: ignoring extra text after %cv option\n",
		commandname, argv[i][0]);
      vblesonly = ON;
      break;
    case 'V':          /* debugging info */
      if (argv[i][0] == '-') {
	debug = OFF;
	if (argv[i][2] != '\0' && warnq)
	  fprintf(stderr, "%s: Warning: ignoring extra text after -V option\n",
		  commandname);
      }
      else {
	if (argv[i][2] == '\0')
	  debug = 1;
	else
	  debug = atoi(argv[i] + 2);
      }
      break;
    case 'w':          /* pagewidth */
      pagewidth = atoi(argv[i] + 2);
      if (pagewidth < MINPAGEWIDTH || pagewidth > MAXPAGEWIDTH) {
	if (warnq) {
	  fprintf(stderr,"%s: Warning: at option %s, page width should be between %d and %d\n", commandname, argv[i], MINPAGEWIDTH, MAXPAGEWIDTH);
	  fprintf(stderr, "  Resetting to default value of %d\n", PAGEWIDTH);
	}
	pagewidth = PAGEWIDTH;
      }
      break;
    case 'W':           /* weekly report */
      cldaterep(&Wq, &weekgraph, argv[i]);
      break;
    case 'x':           /* general summary and gotos */
      clflag(&xq, argv[i]);
      break;
    default:
      fprintf(stderr,
      "%s: Error: Unknown option %s: see README.html for correct usage\n",
	      commandname, argv[i]);
      fprintf(stderr,
      "  or go to http://www.statslab.cam.ac.uk/~sret1/analog/\n");
      exit(ERR);
    }
  }

  /* Finally, the mandatory config file */
  logfilep = logfilehead;  /* reset logfile pointers for over-write */
  cachefilep = cachefilehead;
  reflogp = refloghead;
  browlogp = browloghead;
  errlogp = errloghead;

  if (config(MANDATORYCONFIGFILE)) {
    fprintf(stderr,
    "%s: Error: Cannot ignore mandatory configuration file: exiting\n",
	    commandname);
    exit(ERR);
  }

}

/*** The actual initialise() function ***/

void initialise(int argc, char **argv)
{
  extern void formgen();      /* in formgen.c */
  extern int strtomonth();    /* in utils.c */
  extern long timecode();     /* in utils.c */

  char startmonth[4];
  FILE *outf;

  time(&starttime);
  strcpy(starttimestr, ctime(&starttime));
  starttimec.year = (starttimestr[23] - '0') + (starttimestr[22] - '0') * 10
    + (starttimestr[21] - '0') * 100 + (starttimestr[20] - '0') * 1000;
  starttimec.date = (starttimestr[9] - '0');
  if (starttimestr[8] != ' ')
    starttimec.date += (starttimestr[8] - '0') * 10;
  strncpy(startmonth, starttimestr + 4, 3);
  starttimec.monthno = strtomonth(startmonth);
  starttimec.code = timecode(starttimec.date, starttimec.monthno,
			     starttimec.year, 23, 59);
  /* end of today will be good enough for our purposes */

  defaults();   /* enter the defaults for all the variables
		   (before possibly changing them). */

  init_structs();   /* initialise all the structures (and pointers to them) */

  strncpy(commandname, argv[0], MAXSTRINGLENGTH - 1);

  commandline(argc, argv);  /* parse commandline. This also parses all the
			       configuration files. */

  /* correct any variables for which wrong value given */

  if (fromtime.code > totime.code) {
    fprintf(stderr, "%s: Error: FROM and TO exclude all dates.\n",
	    commandname);
    exit(ERR);
  }

  if (dirlevel == 0)
    dirlevel = 1;

  if (Sq)
    sq = ON;      /* +S implies +s */

  if (STREQ(baseurl, "none"))
    baseurl[0] = '\0';

  if (!STREQ(outfile, "stdout")) {
    if ((outf = fopen(outfile, "w")) == NULL) {
      fprintf(stderr,
	      "%s: Error: failed to open output file %s for writing.\n",
	      commandname, outfile);
      exit(ERR);   /* test now so we don't do the processing THEN find out */
    }
    else
      fclose(outf);  /* no need to hold it open */
  }

  if (aq == CACHE) {
    configline("ALL OFF");
    xq = OFF;
    Hq = ON;
    Hback = OFF;
  }

  /* if we just want a form, generate that and exit */

  if (formq) {
    formgen();
    exit(OK);
  }

  if (!vblesonly)
    othervars();

}   /* end initialise() */


/*** Finally, boring functions just to print variables and exit ***/

void pvfilelist(struct stringlist *head, char filetype[MAXSTRINGLENGTH])
{
  FILE *filep;
  struct stringlist *p;

  printf("%s to analyse:\n", filetype);
  if (head -> name[0] == '\0')
    printf("  none\n");
  for (p = head; p -> name[0] != '\0'; p = p -> next) {  /* for each file */
    printf("  %s", p -> name);
    if ((filep = fopen(p -> name, "r")) == NULL && !STREQ(p -> name, "stdin"))
      printf(":   Warning: cannot open that file");
    else
      fclose(filep);  /* NB So condl 3 lines back must be in that order */
      printf("\n");
  }
}

void pvcols(char *cols)
{
  char *c;

  printf("  Columns:");
  if (*cols == '\0')
    printf("  none");
  else for (c = dircols; *c != '\0'; c++) {
    switch(*c) {
    case 'b':
      printf("  %%bytes");
      break;
    case 'B':
      printf("  #bytes");
      break;
    case 'r':
      printf("  %%requests");
      break;
    case 'R':
      printf("  #requests");
      break;
    }
  }
  printf("\n");
}

void pvtime(char name[15], flag q, char graph, int unit, char cols[])
{
  extern void int3printf();     /* in utils.c */

  int i;

  printf("%s", name);
  for (i = 19 - (int)strlen(name); i--; i > 0)
    printf(" ");
  printf("%s\n", q?"ON":"OFF");
  if (q) {
    printf("  Drawing bar chart by %s\n",
	   (graph == 'b' || graph == 'B')?"bytes":"requests");
    if (unit != 0) {
      printf("  Each character in the graph will represent");
      int3printf(stdout, unit);
      printf("%s\n", (graph == 'b' || graph == 'B')?"bytes":"requests");
    }
    pvcols(cols);
  }
}

void pvgen(char name[17], flag q, int sortby, char *minreqstr,
	   char *minbytestr, char cols[], char singular[20], char plural[21])
{
  extern int whatincluded();        /* in output.c */

  int i;

  printf("%s", name);
  for (i = 19 - (int)strlen(name); i--; i > 0)
    printf(" ");
  printf("%s\n", q?"ON":"OFF");
  if (q) {
    printf("  ");
    whatincluded(stdout, sortby, minreqstr, minbytestr, singular, plural, OFF);
    pvcols(cols);
  }
}

void pvinout(char name[9], struct include *head)
{
  struct include *p;

  printf("\nIncluding (+) and excluding (-) the following %s:\n", name);
  printf("  All %s, then\n", (head -> in == TRUE)?"excluded":"included");
  for (p = head; p -> in != UNSET; p = p -> next)
    printf("  %c %s\n", (p -> in)?'+':'-', p -> name);
}

void pvalias(char name[8], struct alias *head)
{
  struct alias *p;

  if (head -> from[0] != '\0') {
    printf("%s aliases:\n", name);
    for (p = head; p -> from[0] != '\0'; p = p -> next)
      printf("  %s -> %s", p -> from, p -> to);
    printf("\n");
  }
}

void printvbles(void)
{
  extern void int3printf();     /* in utils.c */
  extern int whatincluded();    /* in output.c */

  FILE *filep;
  char *c;

  printf("This is analog version %s\n", VERSION);
  printf("For more information on analog see Readme.html or\n");
  printf("http://www.statslab.cam.ac.uk/~sret1/analog/\n\n");

  printf("Logfiles to analyse:\n");  /* as printfilelist(), but for logfiles */
  if (logfilehead -> name[0] == '\0')
    printf("  none\n");
  for (logfilep = logfilehead; logfilep -> name[0] != '\0';
       logfilep = logfilep -> next) {
    printf("  %s", logfilep -> name);
    if ((filep = fopen(logfilep -> name, "r")) == NULL &&
	!STREQ(logfilep -> name, "stdin"))
      printf(":   Warning: cannot open that file");
    else
      fclose(filep);  /* NB So condl 3 lines back must be in that order */
    printf("\n");
  }

  pvfilelist(cachefilehead, "Cache files");

  if (aq != CACHE) {
    pvfilelist(refloghead, "Referer logs");
    pvfilelist(browloghead, "Browser logs");
    pvfilelist(errloghead, "Error logs");
  }

  if (uncompresshead -> name[0] != '\0') {
    printf("Files uncompressed by the following methods:\n");
    for (uncompressp = uncompresshead; uncompressp -> name[0] != '\0';
	 uncompressp = uncompressp -> next)
      printf("  %s by %s\n", uncompressp -> name, uncompressp -> prefix);
  }

  if (aq == CACHE)
    printf("\nOutputting cache file only.\n");
  else {
    printf("The domains file is %s\n", domainsfile);
    if ((filep = fopen(domainsfile, "r")) == NULL)
      printf("  Warning: cannot open that file: cannot construct domain report\n");
    else
      fclose(filep);

    printf("The output file is %s\n", outfile);
    /* Don't check for being able to write as it will destroy the file */

    printf("\nReport order:\n");
    printf("General summary    %s\n", xq?"ON":"OFF");
    for (c = reportorder; *c != '\0'; c++) {
      switch(*c) {
      case 'b':
	pvgen("Browser summary", bq, browsortby, browminreqstr, browminbytestr,
	      browcols, "browser", "browsers");
	break;
      case 'B':
	pvgen("Browser report", Bq, fullbrowsortby, fullbrowminreqstr,
	      fullbrowminbytestr, fullbrowcols, "browser", "browsers");
	break;
      case 'c':
	printf("Status code report %s\n", cq?"ON":"OFF");
	break;
      case 'd':
	pvtime("Daily summary", dq, daygraph, dailyunit, daycols);
	break;
      case 'D':
	pvtime("Daily report", Dq, fulldaygraph, fulldailyunit, fulldaycols);
	break;
      case 'e':
	printf("Error report       %s\n", eq?"ON":"OFF");
	if (errminreqs == 0)
	  printf("  Printing all possible errors, ");
	else
	  printf("  Printing all errors with at least %d occurence%s,\n",
		 errminreqs, (errminreqs == 1)?"":"s");
	printf("  sorted by number of occurrences.");
	break;
      case 'f':
	pvgen("Referer report", fq, refsortby, refminreqstr, refminbytestr,
	      refcols, "referer", "referers");
	break;
      case 'h':
	pvtime("Hourly summary", hq, hourgraph, hourlyunit, hourcols);
	break;
      case 'H':
	pvtime("Hourly report", Hq, fullhourgraph, fullhourlyunit,
	       fullhourcols);
	break;
      case 'i':
	pvgen("Directory report", iq, dirsortby, dirminreqstr, dirminbytestr,
	      dircols, "directory", "directories");
	printf("  Printing directories to depth %d.\n", dirlevel);
	break;
      case 'm':
	pvtime("Monthly report", mq, monthgraph, monthlyunit, monthcols);
	break;
      case 'o':
	pvgen("Domain report", oq, domsortby, domminreqstr, domminbytestr,
	      domcols, "domain", "domains");
	printf("  ");
	whatincluded(stdout, domsortby, domminreqstr, domminbytestr,
		     "requested subdomain", "requested subdomains", ON);
	break;
      case 'r':
	pvgen("Request report", rq, reqsortby, urlminreqstr, urlminbytestr,
	      reqcols, (reqtype == PAGES)?"page":"file",
	      (reqtype == PAGES)?"pages":"files");
	if (kq == OFF)
	  printf("  Linking disabled.\n");
	else {
	  printf("  Linking to %s enabled", (kq==ALL)?"all files":"pages");
	  if (baseurl[0] != '\0')
	    printf(" (prepended by %s)", baseurl);
	  printf(".\n");
	}
	break;
      case 'S':
	pvgen("Host report", Sq, hostsortby, hostminreqstr, hostminbytestr,
	      hostcols, "host", "hosts");
	break;
      case 'W':
	pvtime("Weekly report", Wq, weekgraph, weeklyunit, weekcols);
	break;
      }  /* end switch c */
    }    /* end for c */
    

    if (sq == APPROX) {
      printf("\nApproximate hostname count ON\n");
      printf("  Space used for hostname count: ");
      int3printf(stdout, approxhostsize);
      printf(" bytes\n");
    }
    else
      printf("\nHostname count     %s\n", (sq == ON)?"ON":"OFF");

    printf("Statistics for last 7 days %s\n", q7?"ON":"OFF");

    if (oq) {
      printf("\nRequested subdomains:\n");
      if (subdomshead -> from[0] == '\0')
	printf("  None\n");
      else for (subdomp = subdomshead; subdomp -> from[0] != '\0';
		subdomp = subdomp -> next) {
	if (subdomp -> from[0] == '?')  /* don't want it */
	  ;
	else if (subdomp -> from[0] == '%')
	  printf("  Numerical subdomains\n");
	else {
	  printf("  %s", subdomp -> from);
	  if (subdomp -> to[0] != '?')
	    printf(" (%s)", subdomp -> to);
	  printf("\n");
	}
      }
    }
    
    if (mq || dq || hq || Hq || Dq || Wq) {
      printf("\nThe character used in the graphs will be '%c'\n", markchar);
      printf("The page width is %d\n", pagewidth);
    }

    if (sepchar != '\0')
      printf("The character used as a separator in big numbers will be '%c'\n",
	     sepchar);

    if (Wq || Dq || dq) {
      printf("Weeks are taken to begin on ");
      switch(weekbeginson) {
      case (SUNDAY):
	printf("Sunday.\n");
	break;
      case (MONDAY):
	printf("Monday.\n");
	break;
      case (TUESDAY):
	printf("Tuesday.\n");
	break;
      case (WEDNESDAY):
	printf("Wednesday.\n");
	break;
      case (THURSDAY):
      printf("Thursday.\n");
	break;
      case (FRIDAY):
	printf("Friday.\n");
	break;
      case (SATURDAY):
	printf("Saturday.\n");
      break;
      }
    }

    printf("\nThe output will be in %s.\n",aq?"plain text":"HTML");
    printf("The following will be included in the output:\n");

    if (!aq)
      printf("Logo               %s\n", STREQ(logourl, "none")?logourl:"OFF");
    printf("Header file        %s\n",
	   STREQ(headerfile, "none")?"OFF":headerfile);
    if (!STREQ(headerfile, "none")) {
      if ((filep = fopen(headerfile, "r")) == NULL)
	printf("  Warning: cannot open that file: will ignore it\n");
      else
	fclose(filep);
    }
    printf("Footer file        %s\n",
	   STREQ(footerfile, "none")?"OFF":footerfile);
    if (!STREQ(footerfile, "none")) {
      if ((filep = fopen(footerfile, "r")) == NULL)
	printf("  Warning: cannot open that file: will ignore it\n");
      else
	fclose(filep);
    }
    printf("Organisation name  \"%s\"\n", hostname);
    if (!aq)
      printf("Name linked to URL %s\n\n", (hosturl[0]=='-')?"OFF":hosturl);

  pvinout("as pages", ispagehead);
  pvalias("File", filealiashead);
  pvalias("Host", hostaliashead);
  pvalias("Referer", refaliashead);

  }   /* end if aq != CACHE */

  if (filemaskq)
    pvinout("files", wantfilehead);
  if (hostmaskq)
    pvinout("hosts", wanthosthead);
  if (refmaskq && aq != CACHE)
    pvinout("referers", wantrefhead);

  if (fromtime.code > -INFINITY || totime.code < INFINITY) {
    printf("\nExamining only times");
    if (fromtime.code > -INFINITY)
      printf(" from %02d/%s/%d", fromtime.date,
	     monthname[fromtime.monthno], fromtime.year);
    if (totime.code < INFINITY)
      printf(" to %02d/%s/%d", totime.date,
	     monthname[totime.monthno], totime.year);
    printf("\n");
  }

  printf("\nDebug level is %d\n\n", debug);

  exit(OK);

}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.