/* vattr.c -- Manages the user-defined attributes. */ #include "autoconf.h" #include "copyright.h" #ifndef lint static char *RCSid = "$Id: vattr.c,v 1.7 1995/03/21 00:01:38 ambar Exp $"; USE(RCSid); #endif /* Gather page fault stats */ #undef GATHER_STATS #include "copyright.h" #include "externs.h" #include "mudconf.h" #include "vattr.h" #include "alloc.h" #ifndef NULL #define NULL 0 #endif static VATTR **vhash; static VATTR *vfreelist; static int vhash_index; static int vstats_count; static int vstats_freecnt; static int vstats_lookups; #ifdef GATHER_STATS static int page_faults = 0; #endif #define vattr_hash(n) hashval((n), VHASH_MASK) static void FDECL(fixcase, (char *)); static char FDECL(*store_string, (char *)); /* Allocate space for strings in lumps this big. */ #define STRINGBLOCK 1000 /* Current block we're putting stuff in */ static char *stringblock = (char *) 0; /* High water mark. */ static int stringblock_hwm = 0; void NDECL(vattr_init) { VATTR **vpp; int i; vhash = (VATTR **) XMALLOC(VHASH_SIZE * sizeof(VATTR *), "vattr_init"); vfreelist = NULL; for (i = 0, vpp = vhash; i < VHASH_SIZE; i++) *vpp++ = NULL; vstats_count = 0; vstats_lookups = 0; } VATTR * vattr_find(name) char *name; { register VATTR *vp, *vprev; int hash; #if defined(GATHER_STATS) && defined(HAVE_GETRUSAGE) struct rusage foo; int old_majflt; getrusage(RUSAGE_SELF, &foo); old_majflt = foo.ru_majflt; #endif fixcase(name); if (!ok_attr_name(name)) return (NULL); hash = vattr_hash(name); vstats_lookups++; vprev = NULL; for (vp = vhash[hash]; vp != NULL; vprev = vp, vp = vp->next) { if (!strcmp(name, vp->name)) break; } if (vp && vprev) { /* Rechain */ vprev->next = vp->next; vp->next = vhash[hash]; vhash[hash] = vp; } #if defined(GATHER_STATS) && defined(HAVE_GETRUSAGE) getrusage(RUSAGE_SELF, &foo); page_faults += foo.ru_majflt - old_majflt; #endif /* vp is NULL or the right thing. It's right, either way. */ return (vp); } VATTR * vattr_alloc(name, flags) char *name; int flags; { int number; if (((number = mudstate.attr_next++) & 0x7f) == 0) number = mudstate.attr_next++; anum_extend(number); return (vattr_define(name, number, flags)); } VATTR * vattr_define(name, number, flags) char *name; int number, flags; { VATTR *vp; int hash; /* Be ruthless. */ if (strlen(name) > VNAME_SIZE) name[VNAME_SIZE - 1] = '\0'; fixcase(name); if (!ok_attr_name(name)) return (NULL); if ((vp = vattr_find(name)) != NULL) return (vp); /* returning NULL barfs on 32-char names */ if (vfreelist == NULL) { vfreelist = vp = (VATTR *) XMALLOC(VALLOC_SIZE * sizeof(VATTR), "vattr_define"); for (hash = 0; hash < (VALLOC_SIZE - 1); hash++, vp++) vp->next = vp + 1; vp->next = NULL; vstats_freecnt = VALLOC_SIZE; } vp = vfreelist; vfreelist = vp->next; vstats_freecnt--; vstats_count++; vp->name = store_string(name); vp->flags = flags; vp->number = number; hash = vattr_hash(name); vp->next = vhash[hash]; vhash[hash] = vp; anum_extend(vp->number); anum_set(vp->number, (ATTR *) vp); return (vp); } void vattr_delete(name) char *name; { VATTR *vp, *vpo; int number, hash; fixcase(name); if (!ok_attr_name(name)) return; number = 0; hash = vattr_hash(name); for (vp = vhash[hash], vpo = NULL; vp != NULL;) { if (!strcmp(name, vp->name)) { number = vp->number; if (vpo == NULL) vhash[hash] = vp->next; else vpo->next = vp->next; vp->next = vfreelist; vfreelist = vp; vstats_count--; vstats_freecnt++; break; } vpo = vp; vp = vp->next; } if (number) anum_set(number, NULL); return; } VATTR * vattr_rename(name, newname) char *name, *newname; { VATTR *vp, *vpo; int hash; fixcase(name); if (!ok_attr_name(name)) return (NULL); /* Be ruthless. */ if (strlen(newname) > VNAME_SIZE) newname[VNAME_SIZE - 1] = '\0'; fixcase(newname); if (!ok_attr_name(newname)) return (NULL); hash = vattr_hash(name); for (vp = vhash[hash], vpo = NULL; vp != NULL;) { if (!strcmp(name, vp->name)) { if (vpo == NULL) vhash[hash] = vp->next; else vpo->next = vp->next; break; } vpo = vp; vp = vp->next; } vp->name = store_string(newname); hash = vattr_hash(newname); vp->next = vhash[hash]; vhash[hash] = vp; return (vp); } VATTR * NDECL(vattr_first) { for (vhash_index = 0; vhash_index < VHASH_SIZE; vhash_index++) { if (vhash[vhash_index]) return vhash[vhash_index]; } return NULL; } VATTR * vattr_next(vp) VATTR *vp; { if (vp == NULL) return (vattr_first()); if (vp->next == NULL) { while (++vhash_index < VHASH_SIZE) { if (vhash[vhash_index]) return vhash[vhash_index]; } return (NULL); } return (vp->next); } #ifndef STANDALONE void list_vhashstats(player) dbref player; { char *buff; buff = alloc_lbuf("vattr_hashstats"); #ifdef GATHER_STATS sprintf(buff, "Vattr stats (size %d): %d alloc, %d free, %d name lookups, %d page faults in lookups.\n", VHASH_SIZE, vstats_count, vstats_freecnt, vstats_lookups, page_faults); #else sprintf(buff, "Vattr stats (size %d): %d alloc, %d free, %d name lookups\n", VHASH_SIZE, vstats_count, vstats_freecnt, vstats_lookups); #endif notify(player, buff); free_lbuf(buff); } #endif static void fixcase(name) char *name; { char *cp = name; while (*cp) { if (islower(*cp)) *cp = toupper(*cp); cp++; } return; } /* Some goop for efficiently storing strings we expect to keep forever. There is no freeing mechanism. */ static char * store_string(str) char *str; { int len; char *ret; len = strlen(str); /* If we have no block, or there's not enough room left in the current one, get a new one. */ if (!stringblock || (STRINGBLOCK - stringblock_hwm) < (len + 1)) { stringblock = (char *) XMALLOC(STRINGBLOCK, "store_string"); if (!stringblock) return ((char *) 0); stringblock_hwm = 0; } ret = stringblock + stringblock_hwm; strcpy(ret, str); stringblock_hwm += (len + 1); return (ret); }