This is hash.c in view mode; [Download] [Up]
/*** analog 1.9beta ***/
/* Please read Readme.html, or http://www.statslab.cam.ac.uk/~sret1/analog/ */
#include "analhea2.h"
/*** hash.c; the functions which do all the work in the hash tables. ***/
/*** The first few are all exactly the same, adding a certain number of
requests and a certain number of bytes to the hash entry for that item,
creating a new hash entry if none existed before. ***/
extern void *xmalloc(); /* in utils.c */
/* used in so many functions, I declare it here */
void hashadd(struct genstruct *objhead[], int hashsize, char *name, int reqs,
double bytes, flag last7q, int *totalobjs,
int *totalobjs7, int *totalnew7, flag al)
{
extern int magicno(); /* in utils.c */
int magicnumber;
flag finished;
struct genstruct *p, *lastp, *prevp;
/* First calculate name's "magic number" */
magicnumber = magicno(name, hashsize);
/* Now look through the magicnumber'th list for that URL */
finished = FALSE;
p = (objhead[magicnumber]);
lastp = p;
prevp = p;
while (p -> name != NULL && !finished) {
if (STREQ(p -> name, name)) { /* then done */
p -> reqs += reqs;
p -> bytes += bytes;
if (last7q && !(p -> last7)) {
(*totalobjs7)++;
p -> last7 = TRUE;
}
if (!last7q && !(p -> pre7)) {
p -> pre7 = TRUE;
(*totalnew7)--; /* Must have p -> last7, so have wrongly
counted it as new in last 7 */
}
/* keep the list in rough (not exact) order of number of
accesses for quicker searching; particularly useful if
the HASHSIZE is set too low. */
if (p -> reqs > lastp -> reqs) {
if (prevp == lastp) { /* iff p is 2nd in the list */
objhead[magicnumber] = p;
lastp -> next = p -> next;
p -> next = lastp;
}
else { /* p is 3rd or later in the list */
prevp -> next = p;
lastp -> next = p -> next;
p -> next = lastp;
}
}
finished = TRUE;
}
else { /* look at the next one */
prevp = lastp;
lastp = p;
p = p -> next;
}
}
if (!finished) { /* reached the end of the list without success; new one */
(*totalobjs)++;
p -> name = (char *)xmalloc((size_t)((int)strlen(name) + 1));
strcpy(p -> name, name);
p -> reqs = reqs;
p -> bytes = bytes;
p -> aliasdone = al;
if (last7q) {
(*totalobjs7)++;
(*totalnew7)++;
p -> last7 = TRUE;
p -> pre7 = FALSE;
}
else {
p -> last7 = FALSE;
p -> pre7 = TRUE;
}
p -> next = (struct genstruct *)xmalloc(sizeof(struct genstruct));
p -> next -> name = NULL;
}
}
/*** The domain hashadd function is different from the others, because we
already know all domains, so there need be no clashes in the hash table. ***/
void domhashadd(char *hostn, int reqs, double bytes)
{
extern int hosttodomcode(); /* in alias.c */
extern flag subdomadd(); /* in this file */
extern int magicno(); /* in utils.c */
extern struct domain *domainhead[], *subdomhead[], *wildsubdomhead,
*nwildsubdomhead;
extern int debug;
int domcode; /* domcode is as explained at the bit where we read the
domains in. It's the equivalent of magic number for
the other hashadd functions. */
int magicnumber; /* for subdomains */
flag finished;
struct domain *domp;
char *tempp;
char tempchar;
domcode = hosttodomcode(hostn);
if (domcode == DOMHASHSIZE - 2 && debug >= 2)
fprintf(stderr, "U: %s\n", hostn);
domainhead[domcode] -> reqs += reqs;
domainhead[domcode] -> bytes += bytes;
/* Next run through the list of wild subdomains. There are two cases;
numerical and ordinary subdomains */
if (!isdigit(hostn[(int)strlen(hostn) - 1])) { /* non-numerical */
for (domp = wildsubdomhead; domp -> id != NULL; domp = domp -> next) {
if(STREQ(domp -> id,
hostn + MAX((int)strlen(hostn) - (int)strlen(domp -> id), 0))) {
/* run back to just after the previous . (or the initial character) */
tempp = hostn + MAX((int)strlen(hostn) - (int)strlen(domp -> id), 0);
while (tempp != hostn && *(tempp - 1) != '.')
tempp--;
/* now add that one to the list of subdoms; it will get looked at
in the next stage */
subdomadd(tempp, "?");
}
}
/* now run through the subdomains this hostname could belong to and see
if any of them are required to be analysed */
tempp = strrchr(hostn, '.'); /* the final dot */
if (tempp != NULL) {
while (tempp != hostn) {
tempp--;
while (tempp != hostn && *(tempp - 1) != '.')
tempp--;
magicnumber = magicno(tempp, SUBDOMHASHSIZE);
finished = OFF;
for (domp = subdomhead[magicnumber]; domp -> name != NULL && !finished;
domp = domp -> next) {
if (STREQ(domp -> id, tempp)) {
domp -> reqs += reqs;
domp -> bytes += bytes;
finished = ON;
}
}
}
}
} /* end non-numerical subdomains; now do numerical ones */
else {
/* wild numerical subdomains */
for (domp = nwildsubdomhead; domp -> id != NULL; domp = domp -> next) {
if(strncmp(domp -> id, hostn, (size_t)(int)strlen(domp -> id)) == 0) {
/* run to the next . (or the end) */
tempp = hostn + (int)strlen(domp -> id);
while (*tempp != '.' && *tempp != '\0')
tempp++;
/* now add that one to the subdoms */
tempchar = *tempp;
*tempp = '\0'; /* temporarily trucate the string after the subdom */
subdomadd(hostn, "?");
*tempp = tempchar;
}
}
/* and now run through the ordinary subdoms for this numerical host */
tempp = hostn + (int)strlen(hostn);
while (tempp != hostn) {
while (tempp != hostn && *tempp != '.' && *tempp != '\0')
tempp--;
if (tempp != hostn) {
tempchar = *tempp;
*tempp = '\0'; /* temporarily trucate the string again */
magicnumber = magicno(hostn, SUBDOMHASHSIZE);
finished = OFF;
for (domp = subdomhead[magicnumber]; domp -> name != NULL && !finished;
domp = domp -> next) {
if (STREQ(domp -> id, hostn)) {
domp -> reqs += reqs;
domp -> bytes += bytes;
finished = ON;
}
}
*tempp = tempchar;
tempp--;
}
}
}
}
/*** Add a new subdomain to the list of subdomains ***/
flag subdomadd(char *id, char *name)
{
extern char *reversehostname(); /* in alias.c */
extern struct domain *subdomhead[SUBDOMHASHSIZE];
extern struct domain *wildsubdomhead, *nwildsubdomhead;
struct domain *domp, *domnextp;
int magicnumber;
flag numeric; /* whether it's a numerical subdomain */
if (id[0] == '?') /* we don't want it */
;
else if (id[0] == '*') { /* put at start wild list (order doesn't matter) */
domnextp = wildsubdomhead;
wildsubdomhead = (struct domain *)xmalloc(sizeof(struct domain));
wildsubdomhead -> next = domnextp;
wildsubdomhead -> id = xmalloc((size_t)((int)strlen(id)));
strcpy(wildsubdomhead -> id, id + 1);
}
else if (id[(int)strlen(id) - 1] == '*') {
domnextp = nwildsubdomhead;
nwildsubdomhead = (struct domain *)xmalloc(sizeof(struct domain));
nwildsubdomhead -> next = domnextp;
nwildsubdomhead -> id = xmalloc((size_t)((int)strlen(id)));
strncpy(nwildsubdomhead -> id, id, (size_t)((int)strlen(id) - 1));
*(nwildsubdomhead -> id + (int)strlen(id) - 1) = '\0';
}
else if (id[0] == '%') { /* token representing "all numerical domains" */
domnextp = nwildsubdomhead;
nwildsubdomhead = (struct domain *)xmalloc(sizeof(struct domain));
nwildsubdomhead -> next = domnextp;
nwildsubdomhead -> id = xmalloc(1);
nwildsubdomhead -> id[0] = '\0';
}
else {
magicnumber = magicno(id, SUBDOMHASHSIZE);
domp = subdomhead[magicnumber];
/* look through that list and slot it in alphabetically
(for quicker finding than random if it's repeated later) */
if (!isdigit(id[(int)strlen(id) - 1])) {
reversehostname(id);
numeric = FALSE;
}
else
numeric = TRUE;
/* if it goes at the beginning of the list, slot it in there */
if (domp -> name == NULL || strcmp(domp -> revid, id) > 0) {
domnextp = domp;
domp = (struct domain *)xmalloc(sizeof(struct domain));
subdomhead[magicnumber] = domp;
domp -> revid = xmalloc((size_t)((int)strlen(id) + 1));
strcpy(domp -> revid, id);
domp -> id = xmalloc((size_t)((int)strlen(id) + 1));
if (!numeric)
reversehostname(id);
strcpy(domp -> id, id);
domp -> name = xmalloc((size_t)((int)strlen(name) + 1));
strcpy(domp -> name, name);
domp -> reqs = 0;
domp -> bytes = 0;
domp -> next = domnextp;
return(TRUE);
}
else if (strcmp(domp -> revid, id) == 0) {
if (!numeric)
reversehostname(id);
return(FALSE);
}
else { /* run to right place in alphabet */
while (domp -> next -> name != NULL &&
strcmp(domp -> next -> revid, id) < 0)
domp = domp -> next;
if (domp -> next -> name != NULL &&
strcmp(domp -> next -> revid, id) == 0) {
if (!numeric)
reversehostname(id); /* so as to leave it unchanged on exit */
return(FALSE);
}
else {
domnextp = domp -> next;
domp -> next = (struct domain *)xmalloc(sizeof(struct domain));
domp = domp -> next;
domp -> revid = xmalloc((size_t)((int)strlen(id) + 1));
strcpy(domp -> revid, id);
domp -> id = xmalloc((size_t)((int)strlen(id) + 1));
if (!numeric)
reversehostname(id);
strcpy(domp -> id, id);
domp -> name = xmalloc((size_t)((int)strlen(name) + 1));
strcpy(domp -> name, name);
domp -> reqs = 0;
domp -> bytes = 0;
domp -> next = domnextp;
return(TRUE);
}
}
}
}
/*** Check if we want a certain referer, and add it ***/
void addref(char *fromurl, char *filename, double bytes, flag last7q,
flag filemaskq) /* last ON if extern one ON and not yet done */
{
extern flag refmaskq;
extern struct genstruct *refhead[];
extern struct include *wantrefhead, *wantfilehead;
flag wantthisone;
int tempint;
if (refmaskq)
wantthisone = (doaliasref(fromurl) != -1) &&
included(fromurl, wantrefhead);
if (wantthisone && filemaskq)
wantthisone = included(filename, wantfilehead);
if (wantthisone)
hashadd(refhead, REFHASHSIZE, fromurl, 1, bytes, last7q,
&tempint, &tempint, &tempint, OFF);
}
/*** Process a browser line, and add it to the lists ***/
/* (Little to do, so we don't use a browser alias function) */
void addbrowser(char *browser, double bytes, flag last7q)
{
extern flag bq, Bq;
extern struct genstruct *browhead[], *fullbrowhead[];
char *c;
int tempint;
/* cut (illegal) "via"s (e.g., via proxy gateway or via Harvest cache) */
if ((c = strstr(browser, " via ")) != NULL) {
while (*c != ' ' && c != browser)
c--;
*(c + 1) = '\0';
}
/* add to full browser report */
if (Bq)
hashadd(fullbrowhead, FULLBROWHASHSIZE, browser, 1, bytes,
last7q, &tempint, &tempint, &tempint, OFF);
if (bq) {
/* generate shortened name */
if ((c = strchr(browser, '/')) != NULL)
*c = '\0';
/* two special cases */
if (STREQ(browser, "Mozilla"))
strcpy(browser, "Netscape");
else if (strstr(browser, "Mosaic") != NULL ||
strstr(browser, "mosaic") != NULL)
strcpy(browser, "Mosaic");
/* and add to browser summary */
hashadd(browhead, BROWHASHSIZE, browser, 1, bytes,
last7q, &tempint, &tempint, &tempint, OFF);
}
}
/*** And one to add an error to the list of errors ***/
void adderr(char *errstr)
{
extern char *strtoupper(); /* in utils.c */
extern char errs[NO_ERRS][MAXERRLENGTH];
extern int errors[NO_ERRS];
extern int debug;
char e1[MAXLINELENGTH], e2[MAXSTRINGLENGTH];
int i;
flag done = OFF;
for (i = 0; !done; i++) {
strcpy(e1, errstr);
strcpy(e2, errs[i]);
if (strstr(strtoupper(e1), strtoupper(e2)) != NULL) {
done = ON;
errors[i]++;
if (debug >= 2 && i == NO_ERRS - 1) /* unknown error type */
fprintf(stderr, "E: %s\n", errstr);
}
}
}
/*** Next a function to do an approx count of the number of distinct hosts ***/
/* First some utilities for it */
flag approxhostfilled(char *space, int i)
{ /* whether there is already a 1 at entry i of the table */
int j, k;
j = i / 8;
k = i % 8;
return((*(space + j) >> k) & 1);
}
void approxhostfill(char *space, int i)
{ /* put a 1 at entry i; ASSUMES IT IS CURRENTLY EMPTY */
int j, k;
j = i / 8;
k = i % 8;
*(space + j) += (1 << k);
}
void approxhosthashadd(char *hostn, flag last7q)
{
extern char *approxhostspace, *approxhostspace7;
extern int approxhostsize;
extern int no_hosts, no_hosts7, no_new_hosts7;
extern flag q7;
int magicnumber1, magicnumber2, magicnumber3, magicnumber4;
flag seen1, seen2, seen3, seen4; /* whether we'd already seen that number */
flag seen17, seen27, seen37, seen47; /* ditto in last 7 days */
flag seen, seen7; /* whether we've seen all 4 numbers before */
register int i;
/* NB Note approxhostfill assumes empty; be careful about two equal magic
numbers for some host */
magicnumber1 = 0;
for (i = 0; hostn[i] != '\0'; i++) {
magicnumber1 = 101 * magicnumber1 + hostn[i];
if (magicnumber1 < 0)
magicnumber1 = -magicnumber1;
while (magicnumber1 >= 8 * approxhostsize)
magicnumber1 -= 8 * approxhostsize;
}
seen1 = approxhostfilled(approxhostspace, magicnumber1);
if (!seen1 && (!q7 || !last7q)) /* if q7 only pre-last7 go here;
if !q7 everything does */
approxhostfill(approxhostspace, magicnumber1);
if (q7) {
seen17 = approxhostfilled(approxhostspace7, magicnumber1);
if (!seen17 && last7q)
approxhostfill(approxhostspace7, magicnumber1);
}
magicnumber2 = 0;
for (i--; i >= 0; i--) {
magicnumber2 = 101 * magicnumber2 + hostn[i];
if (magicnumber2 < 0)
magicnumber2 = -magicnumber2;
while (magicnumber2 >= 8 * approxhostsize)
magicnumber2 -= 8 * approxhostsize;
}
seen2 = approxhostfilled(approxhostspace, magicnumber2);
if (!seen2 && (!q7 || !last7q))
approxhostfill(approxhostspace, magicnumber2);
if (q7) {
seen27 = approxhostfilled(approxhostspace7, magicnumber2);
if (!seen27 && last7q)
approxhostfill(approxhostspace7, magicnumber2);
}
magicnumber3 = 0;
for (i = 0; hostn[i] != '\0'; i++) {
magicnumber3 = 103 * magicnumber3 + hostn[i];
if (magicnumber3 < 0)
magicnumber3 = -magicnumber3;
while (magicnumber3 >= 8 * approxhostsize)
magicnumber3 -= 8 * approxhostsize;
}
seen3 = approxhostfilled(approxhostspace, magicnumber3);
if (!seen3 && (!q7 || !last7q))
approxhostfill(approxhostspace, magicnumber3);
if (q7) {
seen37 = approxhostfilled(approxhostspace7, magicnumber3);
if (!seen37 && last7q)
approxhostfill(approxhostspace7, magicnumber3);
}
magicnumber4 = 0;
for (i--; i >= 0; i--) {
magicnumber4 = 103 * magicnumber4 + hostn[i];
if (magicnumber4 < 0)
magicnumber4 = -magicnumber4;
while (magicnumber4 >= 8 * approxhostsize)
magicnumber4 -= 8 * approxhostsize;
}
seen4 = approxhostfilled(approxhostspace, magicnumber4);
if (!seen4 && (!q7 || !last7q))
approxhostfill(approxhostspace, magicnumber4);
if (q7) {
seen47 = approxhostfilled(approxhostspace7, magicnumber4);
if (!seen47 && last7q)
approxhostfill(approxhostspace7, magicnumber4);
seen7 = seen17 && seen27 && seen37 && seen47;
}
seen = seen1 && seen2 && seen3 && seen4;
if (!q7) {
if (!seen) /* new host */
++no_hosts;
}
else { /* q7 */
if (!seen && !seen7) {
++no_hosts;
if (last7q) {
++no_hosts7;
++no_new_hosts7;
}
}
else if (!seen && seen7 && !last7q) /* it wasn't really a new host 7 */
--no_new_hosts7;
else if (seen && !seen7 && last7q)
++no_hosts7;
} /* end else (= if q7) */
} /* end approxhosthashadd() */
/*** Next the functions to do with dates ***/
/* add to the number of requests for a particular month */
void addmonthlydata(int year, int monthno, int reqs, double bytes)
{
extern struct monthly *firstm, *lastm;
extern struct timestruct firsttime, lasttime;
extern flag mback;
struct monthly *mp;
int i;
mp = mback?lastm:firstm;
for (i = mback?(lasttime.year - year):(year - firsttime.year); i > 0; i--)
mp = mp -> next; /* run to the right year */
mp -> reqs[monthno] += reqs; /* and add to the right month in that year */
mp -> bytes[monthno] += bytes;
}
/* add to the number of requests for a particular day */
void adddailydata(int year, int monthno, int date, int reqs, double bytes)
{
extern struct daily *firstd, *lastd;
extern struct timestruct firsttime, lasttime;
extern flag Dback;
struct daily *dp;
int i;
dp = Dback?lastd:firstd;
for (i = Dback?((lasttime.year - year) * 12 + lasttime.monthno - monthno):
((year - firsttime.year) * 12 + monthno - firsttime.monthno);
i > 0; i--)
dp = dp -> next; /* run to the right month */
dp -> reqs[date - 1] += reqs; /* and add to the right date */
dp -> bytes[date - 1] += bytes;
}
/* add to the number of requests for a particular hour */
void addhourlydata(int year, int monthno, int date, int hr, int reqs,
double bytes)
{
extern struct hourly *firsth, *lasth;
extern struct timestruct firsttime, lasttime;
extern flag Hback;
struct hourly *hp;
int i;
hp = Hback?lasth:firsth;
for (i = Hback?minsbetween(date, monthno, year, 0, 0, lasttime.date,
lasttime.monthno, lasttime.year, 0, 0) / 1440:
minsbetween(firsttime.date, firsttime.monthno, firsttime.year, 0, 0,
date, monthno, year, 0, 0) / 1440;
i > 0; i--)
hp = hp -> next; /* run to the right day */
hp -> reqs[hr] += reqs; /* and add to the right hour */
hp -> bytes[hr] += bytes;
}
/* add to the number of requests for a particular week */
void addweeklydata(int year, int monthno, int date, int reqs, double bytes)
{
extern int minsbetween(); /* in utils.c */
extern struct weekly *firstw, *lastw;
extern flag Wback;
struct weekly *wp;
wp = Wback?lastw:firstw;
while(minsbetween(wp -> start.date, wp -> start.monthno, wp -> start.year,
0, 0, date, monthno, year, 0, 0) * (Wback?(-1):1)
>= (Wback?1:10080))
wp = wp -> next; /* run to right week (when 0 <= minsbetween < 10080) */
wp -> reqs += reqs; /* and add to its requests */
wp -> bytes += bytes;
}
/* and a function to co-ordinate all the date cataloguing */
void datehash(int year, int monthno, int date, int hr, int min,
long thistimecode, int reqs, double bytes)
{
extern long timecode(); /* in utils.c */
extern flag mq, dq, Dq, Wq, Hq;
extern flag mback, Dback, Wback, Hback;
extern struct timestruct firsttime, lasttime;
extern struct monthly *firstm, *lastm;
extern struct daily *firstd, *lastd;
extern struct weekly *firstw, *lastw;
extern struct hourly *firsth, *lasth;
extern int monthlength[];
extern int dailyreq[], hourlyreq[];
extern double dailybytes[], hourlybytes[];
int day;
struct monthly *tempmp;
struct daily *tempdp;
struct weekly *tempwp;
struct hourly *temphp;
int i, j;
if (mq) {
if (year <= firsttime.year) { /* then we might need a new lot of months */
for (i = firsttime.year - year; i > 0; i--) {
tempmp = firstm;
firstm = (struct monthly *)xmalloc(sizeof(struct monthly));
if (mback) {
tempmp -> next = firstm;
firstm -> next = NULL;
}
else
firstm -> next = tempmp;
for (j = 0; j < 12; j++) {
firstm -> reqs[j] = 0;
firstm -> bytes[j] = 0.0;
}
}
firstm -> reqs[monthno] += reqs; /* add to this month */
firstm -> bytes[monthno] += bytes; /* (whether or not newly created) */
}
else if (year >= lasttime.year) { /* similarly */
for (i = year - lasttime.year; i > 0; i--) {
tempmp = lastm;
lastm = (struct monthly *)xmalloc(sizeof(struct monthly));
if (mback)
lastm -> next = tempmp;
else {
tempmp -> next = lastm;
lastm -> next = NULL;
}
for (j = 0; j < 12; j++) {
lastm -> reqs[j] = 0;
lastm -> bytes[j] = 0.0;
}
}
lastm -> reqs[monthno] += reqs;
lastm -> bytes[monthno] += bytes;
}
else /* NB we will never get here if logfile in chron. order */
addmonthlydata(year, monthno, reqs, bytes);
} /* end if (mq) */
if (Dq) {
if (year * 12 + monthno <= firsttime.year * 12 + firsttime.monthno) {
/* then we might need a new lot of days */
for (i = (firsttime.year - year) * 12 +
firsttime.monthno - monthno; i > 0; i--) {
tempdp = firstd;
firstd = (struct daily *)xmalloc(sizeof(struct daily));
if (Dback) {
tempdp -> next = firstd;
firstd -> next = NULL;
}
else
firstd -> next = tempdp;
for (j = 0; j < 31; j++) {
firstd -> reqs[j] = 0;
firstd -> bytes[j] = 0.0;
}
}
firstd -> reqs[date - 1] += reqs;
firstd -> bytes[date - 1] += bytes;
}
else
if (year * 12 + monthno >= lasttime.year * 12 + lasttime.monthno) {
for (i = (year - lasttime.year) * 12 - lasttime.monthno + monthno;
i > 0; i--) {
tempdp = lastd;
lastd = (struct daily *)xmalloc(sizeof(struct daily));
if (Dback)
lastd -> next = tempdp;
else {
tempdp -> next = lastd;
lastd -> next = NULL;
}
for (j = 0; j < 31; j++) {
lastd -> reqs[j] = 0;
lastd -> bytes[j] = 0.0;
}
}
lastd -> reqs[date - 1] += reqs;
lastd -> bytes[date - 1] += bytes;
}
else
adddailydata(year, monthno, date, reqs, bytes);
} /* end if (mq) */
if (Hq) {
if (year * /* 12 * 31 */ 372 + monthno * 31 + date <=
firsttime.year * 372 + firsttime.monthno * 31 + firsttime.date) {
/* then we might need a new lot of hours */
for (i = minsbetween(date, monthno, year, 0, 0, firsttime.date,
firsttime.monthno, firsttime.year, 0, 0) / 1440;
i > 0; i--) {
temphp = firsth;
firsth = (struct hourly *)xmalloc(sizeof(struct hourly));
if (Hback) {
temphp -> next = firsth;
firsth -> next = NULL;
}
else
firsth -> next = temphp;
for (j = 0; j < 24; j++) {
firsth -> reqs[j] = 0;
firsth -> bytes[j] = 0.0;
}
}
firsth -> reqs[hr] += reqs;
firsth -> bytes[hr] += bytes;
}
else
if (year * 372 + monthno * 31 + date
>= lasttime.year * 372 + lasttime.monthno * 31 + lasttime.date) {
for (i = minsbetween(lasttime.date, lasttime.monthno, lasttime.year,
0, 0, date, monthno, year, 0, 0) / 1440;
i > 0; i--) {
temphp = lasth;
lasth = (struct hourly *)xmalloc(sizeof(struct hourly));
if (Hback)
lasth -> next = temphp;
else {
temphp -> next = lasth;
lasth -> next = NULL;
}
for (j = 0; j < 24; j++) {
lasth -> reqs[j] = 0;
lasth -> bytes[j] = 0.0;
}
}
lasth -> reqs[hr] += reqs;
lasth -> bytes[hr] += bytes;
}
else
addhourlydata(year, monthno, date, hr, reqs, bytes);
} /* end if (mq) */
if (Wq) {
if (thistimecode < firstw -> start.code) { /* new week needed */
while (thistimecode < firstw -> start.code) {
tempwp = firstw;
firstw = (struct weekly *)xmalloc(sizeof(struct weekly));
if (Wback) {
tempwp -> next = firstw;
firstw -> next = NULL;
}
else
firstw -> next = tempwp;
firstw -> reqs = 0;
firstw -> bytes = 0.0;
firstw -> start = tempwp -> start;
firstw -> start.date -= 7;
if (firstw -> start.date <= 0) {
firstw -> start.monthno--;
if (firstw -> start.monthno == -1) {
firstw -> start.monthno = 11;
firstw -> start.year--;
}
firstw -> start.date = monthlength[firstw -> start.monthno] +
firstw -> start.date +
ISLEAPFEB(firstw -> start.monthno, firstw -> start.year);
}
firstw -> start.code = timecode(firstw -> start.date,
firstw -> start.monthno,
firstw -> start.year, 0, 0);
}
firstw -> reqs += reqs;
firstw -> bytes += bytes;
}
else if (thistimecode >= lastw -> start.code) {
while (minsbetween(lastw -> start.date, lastw -> start.monthno,
lastw -> start.year, 0, 0, /* 10080m = 1w */
date, monthno, year, 0, 0) >= 10080) {
tempwp = lastw;
lastw = (struct weekly *)xmalloc(sizeof(struct weekly));
if (Wback)
lastw -> next = tempwp;
else {
tempwp -> next = lastw;
lastw -> next = NULL;
}
lastw -> reqs = 0;
lastw -> bytes = 0.0;
lastw -> start = tempwp -> start;
lastw -> start.date += 7;
if (lastw -> start.date > monthlength[lastw -> start.monthno] +
ISLEAPFEB(lastw -> start.monthno, lastw -> start.year)) {
lastw -> start.date -= monthlength[lastw -> start.monthno] +
ISLEAPFEB(lastw -> start.monthno, lastw -> start.year);
lastw -> start.monthno++;
if (lastw -> start.monthno == 12) {
lastw -> start.monthno = 0;
lastw -> start.year++;
}
}
lastw -> start.code = timecode(lastw -> start.date,
lastw -> start.monthno,
lastw -> start.year, 0, 0);
}
lastw -> reqs += reqs;
lastw -> bytes += bytes;
}
else /* again, only used if logfile not chronological */
addweeklydata(year, monthno, date, reqs, bytes);
} /* end if (Wq) */
if (dq) {
day = dayofdate(date, monthno, year);
dailyreq[day] += reqs;
dailybytes[day] += bytes;
}
hourlyreq[hr] += reqs; /* no need to bother checking hq */
hourlybytes[hr] += bytes;
if (thistimecode < firsttime.code) {
firsttime.date = date;
firsttime.monthno = monthno;
firsttime.year = year;
firsttime.hr = hr;
firsttime.min = min;
firsttime.code = thistimecode;
}
if (thistimecode > lasttime.code) {
lasttime.date = date;
lasttime.monthno = monthno;
lasttime.year = year;
lasttime.hr = hr;
lasttime.min = min;
lasttime.code = thistimecode;
}
}
/*** Now some routines to sort the various reports ready for printing ***/
/* First a simple bubblesort for the errors */
void errsort(int errorder[NO_ERRS])
{
extern int errors[NO_ERRS];
int i, j, tempint;
for (i = 0; i < NO_ERRS; i++)
errorder[i] = i;
for (i = NO_ERRS - 2; i >= 0; i--) {
for (j = 0; j <= i; j++) {
if (errors[errorder[j]] < errors[errorder[j + 1]]) {
tempint = errorder[j];
errorder[j] = errorder[j + 1];
errorder[j + 1] = tempint;
}
}
}
}
double bytefloor(double bytes, char str[])
{
double ans;
int last;
last = MAX((int)strlen(str) - 1, 0);
if (str[last] == '%') {
str[last] = '\0';
ans = bytes * atof(str) / 100.0;
str[last] = '%';
}
else if (str[last] == 'k' || str[last] == 'K') {
str[last] = '\0';
ans = atof(str) * 1024.0;
str[last] = 'k';
}
else if (str[last] == 'M' || str[last] == 'm') {
str[last] = '\0';
ans = atof(str) * 1048576.0;
str[last] = 'M';
}
else if (str[last] == 'G' || str[last] == 'g') {
str[last] = '\0';
ans = atof(str) * 1073741824.0;
str[last] = 'G';
}
else if (str[last] == 'T' || str[last] == 't') {
str[last] = '\0';
ans = atof(str) * 1099511627776.0;
str[last] = 'T';
}
else
ans = atof(str);
return(ans);
}
int reqfloor(int reqs, char str[])
{
int ans;
int last;
last = MAX((int)strlen(str) - 1, 0);
if (str[last] == '%') {
str[last] = '\0';
ans = (int)((double)reqs * atof(str) / 100.0);
str[last] = '%';
}
else
ans = atoi(str);
return(ans);
}
/* a function to sort the generic reports */
struct genstruct *gensort(struct genstruct *objhead[], int hashsize,
int sortby, char minreqstr[], char minbytestr[],
flag pagesonly, /* for URLs, list only pages? */
flag alphahost, /* an alphabetical hostsort? */
int *maxreqs, double *maxbytes, int *maxlength)
{
extern char *reversehostname(); /* in alias.c */
extern flag included(); /* in alias.c */
extern int hoststrcmp(); /* in utils.c */
extern struct include *ispagehead;
extern double total_bytes;
extern int total_succ_reqs;
flag wantit = ON; /* whether we want a particular item */
struct genstruct *sorthead; /* build up the sort in this list
(and return it at the end) */
struct genstruct *p, *p2, *nextp, *lastp;
int onlist; /* the list we are processing */
flag finished; /* whether we've finished with a particular entry */
double floorb = 0.0; /* floor for bytes (for byte sorting) */
int floorr = 0; /* floor for requests (for other sorting) */
int outnumber; /* the number of items to be displayed */
int i;
/* first calculate the floor */
if (sortby == BYBYTES)
floorb = bytefloor(total_bytes, minbytestr);
else
floorr = reqfloor(total_succ_reqs, minreqstr);
outnumber = 0;
sorthead = (struct genstruct *)xmalloc(sizeof(struct genstruct));
sorthead -> name = NULL; /* as marker */
onlist = 0; /* the list we are on */
p = objhead[0]; /* starting at list 0 */
for ( ; onlist < hashsize; p = nextp) {
/* run through all the objects */
if (p -> name == NULL) { /* then finished this list */
nextp = objhead[++onlist]; /* so look at the next list */
}
else {
if (pagesonly) /* only for URLs */ /* if not, wantit is always ON */
wantit = included(p -> name, ispagehead);
if ((sortby == BYBYTES && p -> bytes < floorb) ||
(sortby != BYBYTES && p -> reqs < floorr) ||
(!wantit)) { /* we don't want it */
nextp = p -> next;
}
else {
outnumber++;
*maxreqs = MAX(p -> reqs, *maxreqs);
*maxbytes = MAX(p -> bytes, *maxbytes);
if (alphahost) { /* some special things for alphabetical host sort */
*maxlength = MAX((int)strlen(p -> name), *maxlength);
if (!isdigit(p -> name[(int)strlen(p -> name) - 1]))
reversehostname(p -> name);
}
if ((sorthead -> name == NULL) ||
(sortby == RANDOMLY) ||
(sortby == BYBYTES && p -> bytes > sorthead -> bytes) ||
(sortby == BYREQUESTS && p -> reqs > sorthead -> reqs) ||
(sortby == ALPHABETICAL && !alphahost &&
strcmp(p -> name, sorthead -> name) < 0) ||
(sortby == ALPHABETICAL && alphahost &&
hoststrcmp(p -> name, sorthead -> name) < 0)) {
/* if it's before the first item currently on the list, slot it in */
nextp = p -> next; /* the next one we're going to look at */
p -> next = sorthead;
sorthead = p;
}
else { /* otherwise compare with the ones so far */
finished = OFF;
lastp = sorthead;
if (floorb < 0.0)
i = (int)ROUND(floorb);
else if (floorr < 0)
i = floorr;
else
i = 1;
for (p2 = sorthead -> next;
p2 -> name != NULL && (!finished) && (i++) != -1;
p2 = p2 -> next) {
if ((sortby == BYBYTES && p -> bytes > p2 -> bytes) ||
(sortby == BYREQUESTS && p -> reqs > p2 -> reqs) ||
(sortby == ALPHABETICAL && !alphahost &&
strcmp(p -> name, p2 -> name) < 0) ||
(sortby == ALPHABETICAL && alphahost &&
hoststrcmp(p -> name, p2 -> name) < 0)) {
/* if p comes before p2 in the chosen ordering, slot it in */
nextp = p -> next;
p -> next = p2;
lastp -> next = p;
finished = ON;
}
lastp = p2;
}
if (!finished) { /* we've reached the end of the list; */
/* slot it in at the end */
nextp = p -> next;
p -> next = p2;
p2 -> name = NULL;
lastp -> next = p;
}
}
}
}
p = nextp; /* so, on to the next one */
} /* end for running through all objects */
if (floorb < 0.0 && outnumber <= -(int)ROUND(floorb) ||
floorr < 0 && outnumber <= -floorr) {
/* -ve floor & there are at most that many objects */
strcpy(minreqstr, "0"); /* signal to output() that we are printing all */
strcpy(minbytestr, "0");
}
return(sorthead);
} /* end gensort */
/*** Again, the domain report is a bit different because the
structure is stored differently ***/
int domsort(void)
{
extern int onumber;
extern struct domain *domainhead[];
extern int domsortby;
extern char domminreqstr[];
extern char domminbytestr[];
extern double total_bytes;
extern int total_succ_reqs;
extern int dom_max_reqs;
extern double dom_max_bytes;
int i, j, k;
int firstdom; /* the numerical index of the first domain; we return this */
int domnextj;
struct domain *domp, *domlastp;
int floorr;
double floorb;
flag finished;
if (domsortby == BYBYTES)
floorb = bytefloor(total_bytes, domminbytestr);
else
floorr = reqfloor(total_succ_reqs, domminreqstr);
onumber = 0;
firstdom = DOMHASHSIZE - 2; /* start with unknown domains at front of list */
if ((domsortby == BYBYTES && (domainhead[firstdom] -> reqs == 0 ||
domainhead[firstdom] -> bytes < floorb)) ||
(domsortby != BYBYTES && domainhead[firstdom] -> reqs < floorr))
/* then we don't want it; set marker */
domainhead[firstdom] -> reqs = -1;
dom_max_reqs = domainhead[firstdom] -> reqs;
dom_max_bytes = domainhead[firstdom] -> bytes;
domainhead[firstdom] -> nexti = -1;
j = DOMHASHSIZE - 1; /* the domain we are on; start with numerical domains */
while (j >= 0) { /* run through all the domains */
domp = domainhead[j];
domnextj = domp -> nexti;
/* the one we're going to look at after this one */
if (!((domsortby == BYBYTES &&
(domp -> reqs == 0 || domp -> bytes < floorb)) ||
(domsortby != BYBYTES && domp -> reqs < floorr))) {
/* else we don't want it */
onumber++;
dom_max_reqs = MAX(domp -> reqs, dom_max_reqs);
dom_max_bytes = MAX(domp -> bytes, dom_max_bytes);
if ((domsortby == BYBYTES &&
domp -> bytes > domainhead[firstdom] -> bytes) ||
(domsortby == BYREQUESTS &&
domp -> reqs > domainhead[firstdom] -> reqs) ||
(domsortby == ALPHABETICAL &&
strcmp(domp -> id, domainhead[firstdom] -> id) < 0)) {
/* if it's before the first item currently on the list, slot it in */
domp -> nexti = firstdom;
firstdom = j;
}
else { /* otherwise compare with the ones so far */
finished = OFF;
domlastp = domainhead[firstdom];
if (floorb < 0.0)
k = (int)ROUND(floorb);
else if (floorr < 0)
k = floorr;
else
k = 1;
for (i = domainhead[firstdom] -> nexti;
i >= 0 && (!finished) && (k++) != -1;
i = domainhead[i] -> nexti) {
if ((domsortby == BYBYTES &&
domp -> bytes > domainhead[i] -> bytes) ||
(domsortby == BYREQUESTS &&
domp -> reqs > domainhead[i] -> reqs) ||
(domsortby == ALPHABETICAL &&
strcmp(domp -> id, domainhead[i] -> id) < 0)) {
/* if domp comes before domp2 in the chosen ordering, slot it in */
domp -> nexti = i;
domlastp -> nexti = j;
finished = ON;
}
domlastp = domainhead[i];
}
if (!finished) {
domp -> nexti = -1; /* meaning, last item on the list */
domlastp -> nexti = j;
}
}
}
j = domnextj; /* so, on to the next one */
} /* end while j >= 0 */
if (floorb < 0.0 && onumber <= -(int)ROUND(floorb) ||
floorr < 0 && onumber <= -floorr) {
strcpy(domminreqstr, "0");
strcpy(domminbytestr, "0");
}
return(firstdom);
} /* end domsort */
/*** Finally, sort subdomains into the domain report ***/
void subdomsort(void)
{
extern int hosttodomcode(); /* in alias.c */
extern int hoststrcmp(); /* in utils.c */
extern int subonumber;
extern struct domain *domainhead[], *subdomhead[];
extern int domsortby;
extern char subdomminbytestr[], subdomminreqstr[];
extern double total_bytes;
extern int total_succ_reqs;
struct domain *subdomp, *subdomnextp, *domp, *domnextp;
int floorr;
double floorb;
int onlist;
int domcode;
if (domsortby == BYBYTES)
floorb = bytefloor(total_bytes, subdomminbytestr);
else
floorr = reqfloor(total_succ_reqs, subdomminreqstr);
onlist = 0;
subonumber = 0;
subdomp = subdomhead[0]; /* starting at list 0 */
for ( ; onlist < SUBDOMHASHSIZE; subdomp = subdomnextp) {
/* run through all the subdoms */
if (subdomp -> name == NULL) { /* then finished this list */
subdomnextp = subdomhead[++onlist]; /* so look at the next list */
}
else if ((domsortby == BYBYTES && subdomp -> bytes >= floorb) ||
(domsortby != BYBYTES && subdomp -> reqs >= floorr)) {
subdomnextp = subdomp -> next;
subonumber++;
domcode = hosttodomcode(subdomp -> id);
if (domcode != DOMHASHSIZE - 2) {
domp = domainhead[domcode]; /* now run through that domain's
subdomains */
while (domp -> next -> name != NULL &&
hoststrcmp(domp -> next -> revid, subdomp -> revid) < 0)
domp = domp -> next; /* run to right place in alphabet */
domnextp = domp -> next; /* then slot it in */
domp -> next = subdomp;
subdomp -> next = domnextp;
}
}
else
subdomnextp = subdomp -> next;
}
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.