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.