/*** analog 4.13 http://www.analog.cx/ ***/ /*** This program is copyright (c) Stephen R. E. Turner 1995 - 2000 except as *** stated otherwise. Distribution, usage and modification of this program is *** subject to the conditions of the Licence which you should have received *** with it. This program comes with no warranty, expressed or implied. ***/ /*** hash.c; the functions which do all the work in the hash tables. ***/ #include "anlghea3.h" Hashtable *rehash(Hashtable *old, unsigned long size, Memman *treespace) { /* Construct a new hash table out of an old one, using same buckets */ unsigned long i, magic; Hashindex *p, *nextp; Hashtable *ans; char *c; if (treespace != NULL && size * sizeof(Hashindex *) < BLOCKSIZE) { ans = (Hashtable *)submalloc(treespace, sizeof(Hashtable)); ans->head = (Hashindex **)submalloc(treespace, size * sizeof(Hashindex *)); } else { ans = (Hashtable *)xmalloc(sizeof(Hashtable)); ans->head = (Hashindex **)xmalloc(size * sizeof(Hashindex *)); } ans->size = size; ans->n = 0; for (i = 0; i < size; i++) ans->head[i] = NULL; if (old != NULL) { if (treespace != NULL) /* i.e. is tree */ ans->head[0] = old->head[0]; for (i = (unsigned long)(treespace != NULL); i < old->size; i++) { /* run through items in old table */ for (p = old->head[i]; p != NULL; p = nextp) { nextp = p->next; /* rehash p into new table */ if (treespace != NULL) { c = strchr(p->name, '\0'); MAGICNOTREE(magic, p->name, c, size); } else MAGICNO(magic, p->name, size); p->next = ans->head[magic]; ans->head[magic] = p; ans->n++; } } if (treespace == NULL || old->size * sizeof(Hashindex *) >= BLOCKSIZE) { /* free old table, if originally xmalloc'ed */ free((void *)(old->head)); free((void *)old); } } return(ans); } Hashindex *hashfind(Memman *mp, Hashtable **table, Include *wanthead, choice ispage, Include *ispagehead, Alias *aliashead, char *dirsuffix, unsigned int dirsufflength, logical usercase_insensitive, unsigned char convfloor, choice type, logical aliased) { /* NB The calling function will normally consult (lp->own) if aliased, (Hashentry *)(lp->other) if !aliased */ /* NB2 ispage != UNSET means aliasing and in/excluding already done too */ extern Hashentry *unwanted_entry, *blank_entry; extern Memman *amemman, *xmemman; unsigned long magic; /* register'ing this made it slower on my machine */ Hashindex *lp, *lastlp; char *name, *c; choice rc; if (TOO_FULL((*table)->n, (*table)->size)) *table = rehash(*table, NEW_SIZE((*table)->size), NULL); name = (char *)(mp->curr_pos); MAGICNO(magic, name, (*table)->size); lp = (*table)->head[magic]; lastlp = NULL; while (TRUE) { if (lp == NULL) { /* need a new index entry */ lp = (Hashindex *)submalloc(xmemman, sizeof(Hashindex)); if (lastlp == NULL) (*table)->head[magic] = lp; else lastlp->next = lp; lp->name = name; lp->own = NULL; lp->other = NULL; lp->next = NULL; ((*table)->n)++; if (aliased) { if (ispage == UNSET) { ispage = (choice)pageq(name, ispagehead, type); if (included(name, (logical)ispage, wanthead)) lp->own = newhashentry((logical)ispage); else lp->own = unwanted_entry; } else lp->own = newhashentry((logical)ispage); } else { if ((rc = do_alias(lp->name, amemman, aliashead, dirsuffix, dirsufflength, usercase_insensitive, convfloor, type)) == TRUE) lp->other = (void *)hashfind(amemman, table, wanthead, UNSET, ispagehead, NULL, dirsuffix, dirsufflength, usercase_insensitive, convfloor, type, TRUE)->own; else if (rc == ERR) { if (included("", FALSE, wanthead)) { lp->own = blank_entry; lp->other = (void *)blank_entry; } else { lp->own = unwanted_entry; lp->other = (void *)unwanted_entry; } } else { ispage = (choice)pageq(name, ispagehead, type); if (included(name, (logical)ispage, wanthead)) { lp->own = newhashentry((logical)ispage); lp->other = (void *)(lp->own); } else { lp->own = unwanted_entry; lp->other = (void *)unwanted_entry; } } } /* end !aliased */ return(lp); } /* end need new entry */ else if (STREQ(lp->name, name)) { /* found it */ mp->next_pos = mp->curr_pos; /* overwrites old name in mp */ if (aliased) { if (lp->own == NULL) { /* haven't calculated lp->own yet */ if (ispage == UNSET) { if (type == ITEM_FILE) { if ((c = strchr(name, '?')) != NULL) { *c = '\0'; ispage = (choice)included(name, FALSE, ispagehead); *c = '?'; } else ispage = (choice)included(name, FALSE, ispagehead); } else ispage = FALSE; if (included(name, (logical)ispage, wanthead)) lp->own = newhashentry((logical)ispage); else lp->own = unwanted_entry; } else lp->own = newhashentry((logical)ispage); } } else { /* !aliased */ if (lp->other == NULL) { if ((rc = do_alias(lp->name, amemman, aliashead, dirsuffix, dirsufflength, usercase_insensitive, convfloor, type)) == FALSE) lp->other = (void *)(lp->own); /* own must have been set because alias hasn't */ else if (rc == TRUE) lp->other = (void *)hashfind(amemman, table, wanthead, UNSET, ispagehead, NULL, dirsuffix, dirsufflength, usercase_insensitive, convfloor, type, TRUE)->own; else /* rc == ERR */ if (included("", FALSE, wanthead)) lp->other = (void *)blank_entry; else lp->other = (void *)unwanted_entry; } } /* end !aliased */ return(lp); } /* end found it */ else { lastlp = lp; TO_NEXT(lp); } } } Hashentry *newhashentry(logical ispage) { extern Memman *xmemman; Hashentry *ans; int i; ans = (Hashentry *)submalloc(xmemman, sizeof(Hashentry)); for (i = 0; i < DATA_NUMBER; i++) ans->data[i] = 0; ans->bytes = 0.0; ans->last7 = FALSE; ans->ispage = ispage; return(ans); } void hashscore(Hashentry *ep, choice outcome, logical last7, logical ispage, timecode_t timecode, double bytes) { if (outcome == SUCCESS) { ep->data[REQUESTS]++; ep->bytes += bytes; ep->data[PAGES] += ispage; ep->data[SUCCDATE] = MAX(timecode, ep->data[SUCCDATE]); if (last7) ep->last7 = TRUE; } else if (outcome == FAILURE) { ep->data[FAIL]++; ep->data[FAILDATE] = MAX(timecode, ep->data[FAILDATE]); } else { ep->data[REDIR]++; ep->data[REDIRDATE] = MAX(timecode, ep->data[REDIRDATE]); } } void unhash(Hashtable *hash, Hashindex **gooditems, Hashindex **baditems) { Hashindex *p, *nextp; unsigned long j; *gooditems = NULL; *baditems = NULL; for (j = 0; j < hash->size; j++) { /* run through all items */ for (p = hash->head[j]; p != NULL; p = nextp) { nextp = p->next; p->next = *gooditems; /* compiling backwards is easier */ *gooditems = p; } } } void unhashall(Hashtable **hash, Hashindex ***gooditems, Hashindex ***baditems) { unsigned int i; *gooditems = (Hashindex **)xmalloc(ITEM_NUMBER * sizeof(Hashindex *)); *baditems = (Hashindex **)xmalloc(ITEM_NUMBER * sizeof(Hashindex *)); for (i = 0; i < ITEM_NUMBER; i++) { unhash(hash[i], &((*gooditems)[i]), &((*baditems)[i])); } }