/* This file is in the public domain. */ #include #include #include #include "db.h" #include "defs.h" #include "prims.h" #include "params.h" #include "config.h" #include "random.h" #include "externs.h" #include "property.h" #include "unused-arg.h" #define MAXHEIGHT 16 #define SLRATIO 2 struct propname { unsigned int height : 8; unsigned int refcnt : 23; unsigned int serial : 31; struct propname *ptrs[1]; /* actually [.height] */ } ; #define PROPNAME_NAME(pn) ((char *)&(pn)->ptrs[(pn)->height]) struct lockprop { STR value; } ; #define LOCKPROP_NAME(p) ((char *)(p+1)) #define LOCKPROP_CNAME(p) ((const char *)(p+1)) union pleval { STR s; dbref d; struct inst *i; } ; struct propref { unsigned int height : 8; unsigned int refcnt : 23; unsigned int deleted : 1; struct propname *name; PROPATTR attr; dbref ondbref; union pleval value; struct propref *ptrs[1]; /* actually [.height] */ } ; struct plist { struct propref *ptrs[MAXHEIGHT+1]; } ; static struct propname *pnroot[MAXHEIGHT+1]; static unsigned int nextpnserial = 0; static struct propname pn_noref; #define PN_NOREF (&pn_noref) static struct propref pr_noref; #define PR_NOREF (&pr_noref) #define PERM_BASE 060 #define PERM_MASK 077 #define PERM_SHIFT 6 #define PERM_TERM 040 #define PERM_END 052 static void pninit(void) { int i; for (i=0;i<=MAXHEIGHT;i++) pnroot[i] = 0; nextpnserial = 1; } #define PNINIT() do { if (nextpnserial == 0) pninit(); } while (0) static void propname_norefchk(struct propname *p) { int i; for (i=p->height-1;i>=0;i--) if (p->ptrs[i] != PN_NOREF) return; free(p); } static struct propname *insert_propname(const char *name, struct propname ***linkptrs) { int h; struct propname *pn; h = 1; while ((h < MAXHEIGHT) && !rnd(SLRATIO)) h ++; pn = malloc(sizeof(struct propname)+((h-1)*sizeof(struct propname *))+strlen(name)+1); pn->height = h; pn->refcnt = 0; pn->serial = nextpnserial ++; strcpy(PROPNAME_NAME(pn),name); for (h--;h>=0;h--) { pn->ptrs[h] = *linkptrs[h]; *linkptrs[h] = pn; } return(pn); } static struct propname *lookup_propname(const char *name, int createp) { int h; struct propname *t; struct propname *t2; struct propname **linkptrs[MAXHEIGHT+1]; PNINIT(); h = MAXHEIGHT; while (h >= 0) { t = pnroot[h]; if (t) { if (t->refcnt == 0) { pnroot[h] = t->ptrs[h]; t->ptrs[h] = PN_NOREF; propname_norefchk(t); continue; } if (string_compare(PROPNAME_NAME(t),name) <= 0) break; } linkptrs[h] = &pnroot[h]; h --; } if (h < 0) { if (! createp) return(0); return(insert_propname(name,&linkptrs[0])); } while (h >= 0) { while (1) { t2 = t->ptrs[h]; if (t2 == 0) break; if (t2->refcnt == 0) { t->ptrs[h] = t2->ptrs[h]; t2->ptrs[h] = PN_NOREF; propname_norefchk(t2); continue; } if (string_compare(PROPNAME_NAME(t2),name) > 0) break; t = t2; } linkptrs[h] = &t->ptrs[h]; h --; } if (! string_compare(PROPNAME_NAME(t),name)) return(t); if (! createp) return(0); return(insert_propname(name,&linkptrs[0])); } static void clear_value(struct propref *pr) { switch (pr->attr & PATTR_TYPE) { case PTYPE_NIL: break; case PTYPE_STRING: free_str(pr->value.s); break; case PTYPE_DBREF: remove_backprop(pr->ondbref,pr->value.d); break; case PTYPE_ANYVAL: CLEAR(pr->value.i); free(pr->value.i); break; default: panic("clear_value: bad type"); break; } pr->attr = (pr->attr & ~PATTR_TYPE) | PTYPE_NIL; } static struct plist *new_plist(void) { struct plist *p; int i; p = malloc(sizeof(struct plist)); for (i=0;i<=MAXHEIGHT;i++) p->ptrs[i] = 0; return(p); } static struct propref *plist_insert(struct propname *pn, struct propref ***linkptrs, dbref ondbref) { int h; struct propref *pr; pn->refcnt ++; h = 1; while ((h < MAXHEIGHT) && !rnd(SLRATIO)) h ++; pr = malloc(sizeof(struct propref)+((h-1)*sizeof(struct propref *))); pr->height = h; pr->refcnt = 1; pr->deleted = 0; pr->name = pn; pr->attr = PTYPE_NIL | PATTR_MBO; pr->ondbref = ondbref; for (h--;h>=0;h--) { pr->ptrs[h] = *linkptrs[h]; *linkptrs[h] = pr; } return(pr); } static void propref_refc0chk(struct propref *pr) { if (pr->refcnt != 0) return; if (pr->name->refcnt == 0) panic("propref_refc0chk: name refcnt==0"); pr->name->refcnt --; clear_value(pr); free(pr); } static void propref_norefchk(struct propref *pr) { int i; for (i=pr->height-1;i>=0;i--) if (pr->ptrs[i] != PR_NOREF) return; pr->refcnt --; propref_refc0chk(pr); } static void attr_sanity(struct propref *pr) { if (PATTR_MBZ & pr->attr) panic("property attribute MBZ bit set"); if (PATTR_MBO & ~pr->attr) panic("property attribute MBO bit not set"); } static void propref_copy_type_and_value(struct propref *new, struct propref *old) { clear_value(new); new->attr = (new->attr & ~PATTR_TYPE) | (old->attr & PATTR_TYPE); attr_sanity(new); switch (old->attr & PATTR_TYPE) { case PTYPE_STRING: new->value.s = copy_str(old->value.s); break; case PTYPE_DBREF: new->value.d = old->value.d; add_backprop(new->ondbref,new->value.d); break; case PTYPE_ANYVAL: new->value.i = malloc(sizeof(struct inst)); copyinst(old->value.i,new->value.i); break; default: panic("propref_copy_type_and_value: bad type"); break; } } static void fputs_pperm(FILE *f, PROPATTR perm) { while (perm) { putc(PERM_BASE+(perm&PERM_MASK),f); perm >>= PERM_SHIFT; } putc(PERM_TERM,f); } static int fgets_pperm(FILE *f, PROPATTR *permp) { int c; PROPATTR p; int s; p = 0; s = 0; while (1) { c = getc(f); if (c == PERM_END) return(1); if (c == PERM_TERM) { *permp = (p | PATTR_MBO) & ~PATTR_MBZ; return(0); } if ((c < PERM_BASE) || (c > PERM_BASE+PERM_MASK)) return(-1); p |= ((PROPATTR)(c-PERM_BASE)) << s; s += PERM_SHIFT; } } static struct propref *plist_sort(struct propref *list) { struct propref *l1; struct propref *l2; struct propref *e; struct propref **lp; l1 = 0; l2 = 0; while (list) { e = list; list = e->ptrs[0]; e->ptrs[0] = l1; l1 = e; e = list; if (! e) break; list = e->ptrs[0]; e->ptrs[0] = l2; l2 = e; } if (! l2) return(l1); l1 = plist_sort(l1); l2 = plist_sort(l2); lp = &list; while (l1 || l2) { if (!l2 || (l1 && (l1->name->serial < l2->name->serial))) { e = l1; l1 = e->ptrs[0]; } else { e = l2; l2 = e->ptrs[0]; } *lp = e; lp = &e->ptrs[0]; } return(list); } static void plist_rethread(struct plist *pl) { int i; struct propref *e; struct propref **pvec[MAXHEIGHT+1]; for (i=MAXHEIGHT;i>0;i--) pvec[i] = &pl->ptrs[i]; for (e=pl->ptrs[0];e;e=e->ptrs[0]) { for (i=e->height-1;i>0;i--) { *pvec[i] = e; pvec[i] = &e->ptrs[i]; } } for (i=MAXHEIGHT;i>0;i--) *pvec[i] = 0; } static int has_prop_value(dbref obj, const char *name, PROPATTR bit, const char *val) { struct propref *pr; int rv; char *v; pr = lookup_property(obj,name,0); if (pr == 0) return(0); rv = 0; if ( ((pr->attr & PATTR_TYPE) == PTYPE_STRING) && (pr->attr & bit) ) { v = propref_get_string(pr); if (!strcmp(v,val)) rv = 1; free(v); } propref_done(pr); return(rv); } static int list_has_prop_value(dbref head, const char *name, PROPATTR bit, const char *val) { while (head != NOTHING) { if (has_prop_value(head,name,bit,val)) return(1); head = DBFETCH(head)->next; } return(0); } void prop_done(void) { lookup_propname("",0); } const char *lockprop_name(const struct lockprop *lp) { return(LOCKPROP_CNAME(lp)); } char *lockprop_value(const struct lockprop *lp) { return(fetch_str(lp->value)); } int lockprop_check(dbref onthing, dbref passer, struct lockprop *lp) { PROPATTR maskbit; char *cmp; maskbit = PPERM_PICKWHO( TrueGod(onthing), TrueWizard(onthing), TrueRoyalty(onthing), OWNER(onthing)==OWNER(passer) ) & PPERM_BIT_R & PPERM_HOW_L; cmp = fetch_str(lp->value); if (has_prop_value(passer,LOCKPROP_CNAME(lp),maskbit,cmp)) { free(cmp); return(1); } switch (Typeof(passer)) { case TYPE_PLAYER: if (list_has_prop_value(DBFETCH(passer)->contents,LOCKPROP_CNAME(lp),maskbit,cmp)) { free(cmp); return(1); } } free(cmp); return(0); } struct lockprop *copy_lockprop(const struct lockprop *lp) { struct lockprop *new; int nlen; nlen = strlen(LOCKPROP_CNAME(lp)); new = malloc(sizeof(struct lockprop)+nlen+1); bcopy(LOCKPROP_CNAME(lp),LOCKPROP_NAME(new),nlen+1); new->value = copy_str(lp->value); return(new); } struct lockprop *make_lockprop(const char *name, int nlen, const char *value, int vlen) { struct lockprop *lp; static char *vtmp; static int vtlen = -1; if (nlen < 0) nlen = strlen(name); if (vlen < 0) vlen = strlen(value); lp = malloc(sizeof(struct lockprop)+nlen+1); bcopy(name,LOCKPROP_NAME(lp),nlen); LOCKPROP_NAME(lp)[nlen] = '\0'; if (vlen > vtlen) { free(vtmp); vtlen = vlen + 32; vtmp = malloc(vtlen+1); } bcopy(value,vtmp,vlen); vtmp[vlen] = '\0'; lp->value = store_str(vtmp); return(lp); } void free_lockprop(struct lockprop *lp) { free_str(lp->value); free(lp); } void put_lockprop(FILE *f, const struct lockprop *lp) { char *v0; char *v; fprintf(f,"%s:",LOCKPROP_CNAME(lp)); v0 = fetch_str(lp->value); if (v0) { for (v=v0;*v;v++) { switch (*v) { case ']': putc('\1',f); break; default: putc(*v,f); break; } } free(v0); } } int get_lockprop(FILE *f, struct lockprop **lpp) { int c; char *buf; int have; int len; char *name; int namelen; struct lockprop *lp; buf = malloc(1); have = 0; len = 0; name = 0; while (1) { c = getc(f); if (c == EOF) { free(buf); return(1); } if ((c == ':') && !name) { buf[len] = '\0'; name = buf; namelen = len; buf = malloc(1); have = 0; len = 0; continue; } if (c == ']') { buf[len] = '\0'; ungetc(']',f); if (! name) return(1); lp = malloc(sizeof(struct lockprop)+namelen+1); lp->value = store_str(buf); bcopy(name,LOCKPROP_NAME(lp),namelen+1); *lpp = lp; free(name); free(buf); return(0); } if (c == '\1') c = ']'; if (len >= have) buf = realloc(buf,(have=len+16)+1); buf[len++] = c; } } int lockprop_memused(const struct lockprop *lp) { return(sizeof(*lp)+strlen(LOCKPROP_CNAME(lp))+1+str_memusage(lp->value)); } static struct propref *lookup_property_(struct plist **listp, struct propname *name, unsigned int flags, PROPATTR perm, dbref ondbref) { int h; struct plist *list; struct propref *t; struct propref *t2; struct propref **pvec; struct propref **linkptrs[MAXHEIGHT+1]; if (flags & ~LP__ALL) panic("lookup_property_: bad flags"); list = *listp; if (list == 0) { if (! (flags & LP_CREATE)) return(0); *listp = list = new_plist(); } pvec = &list->ptrs[0]; h = MAXHEIGHT; while (h >= 0) { t = pvec[h]; if (t) { if (t->deleted) { pvec[h] = t->ptrs[h]; t->ptrs[h] = PR_NOREF; propref_norefchk(t); continue; } if (t->name->serial <= name->serial) break; } linkptrs[h] = &pvec[h]; h --; } if (h < 0) { if (! (flags & LP_CREATE)) return(0); t = plist_insert(name,&linkptrs[0],ondbref); t->attr = (t->attr & ~PATTR_PERM) | (perm & PATTR_PERM); attr_sanity(t); } else { t = pvec[h]; while (h >= 0) { while (1) { t2 = t->ptrs[h]; if (t2 == 0) break; if (t2->deleted) { t->ptrs[h] = t2->ptrs[h]; t2->ptrs[h] = PR_NOREF; propref_norefchk(t2); continue; } if (t->ptrs[h]->name->serial > name->serial) break; t = t2; } linkptrs[h] = &t->ptrs[h]; h --; } if (t->name != name) { if (! (flags & LP_CREATE)) return(0); t = plist_insert(name,&linkptrs[0],ondbref); t->attr = (t->attr & ~PATTR_PERM) | (perm & PATTR_PERM); attr_sanity(t); } } t->refcnt ++; return(t); } struct propref *lookup_property(dbref dbr, const char *name, unsigned int flags, ...) { struct propname *pn; va_list ap; PROPATTR perm; if (flags & ~LP__ALL) abort(); if (flags & LP_CREATE) { va_start(ap,flags); perm = va_arg(ap,PROPATTR); va_end(ap); pn = lookup_propname(name,1); return(lookup_property_(&DBFETCH(dbr)->properties,pn,LP_CREATE,perm,dbr)); } else { pn = lookup_propname(name,0); if (pn == 0) return(0); return(lookup_property_(&DBFETCH(dbr)->properties,pn,0,0,0)); } } PROPATTR propref_get_attr(struct propref *pr) { return(pr->attr); } char *propref_get_name(struct propref *pr) { return(PROPNAME_NAME(pr->name)); } char *propref_get_string(struct propref *pr) { if ((pr->attr & PATTR_TYPE) != PTYPE_STRING) panic("propref_get_string: bad type"); return(fetch_str(pr->value.s)); } dbref propref_get_dbref(struct propref *pr) { if ((pr->attr & PATTR_TYPE) != PTYPE_DBREF) panic("propref_get_dbref: bad type"); return(pr->value.d); } struct inst propref_get_anyval(struct propref *pr) { struct inst i; if ((pr->attr & PATTR_TYPE) != PTYPE_ANYVAL) panic("propref_get_anyval: bad type"); copyinst(pr->value.i,&i); return(i); } int dbref_is_player(dbref d) { return(Typeof(d)==TYPE_PLAYER); } int dbref_is_room(dbref d) { return(Typeof(d)==TYPE_ROOM); } int dbref_is_program(dbref d) { return(Typeof(d)==TYPE_PROGRAM); } dbref propref_get_as_dbref(struct propref *pr, int (*check)(dbref)) { dbref rv; rv = NOTHING; switch (pr->attr & PATTR_TYPE) { case PTYPE_DBREF: rv = pr->value.d; break; case PTYPE_STRING: { char *v; v = fetch_str(pr->value.s); rv = (dbref) atoi(v); free(v); } break; } if (check && ((rv < 0) || (rv >= db_top) || !(*check)(rv))) { rv = NOTHING; propref_remove(pr); } else { propref_done(pr); } return(rv); } void propref_set_perms(struct propref *pr, PROPATTR perms) { pr->attr = (pr->attr & ~PATTR_PERM) | (perms & PATTR_PERM); attr_sanity(pr); } void propref_set_type_and_value(struct propref *pr, PROPATTR type, ...) { va_list ap; va_start(ap,type); clear_value(pr); type &= PATTR_TYPE; pr->attr = (pr->attr & ~PATTR_TYPE) | type; attr_sanity(pr); switch (type) { case PTYPE_STRING: pr->value.s = store_str(va_arg(ap,char *)); break; case PTYPE_DBREF: pr->value.d = va_arg(ap,dbref); add_backprop(pr->ondbref,pr->value.d); break; case PTYPE_ANYVAL: pr->value.i = malloc(sizeof(struct inst)); copyinst(va_arg(ap,struct inst *),pr->value.i); break; default: panic("propref_set_type_and_value: bad type"); break; } va_end(ap); } void propref_remove(struct propref *pr) { pr->deleted = 1; propref_done(pr); } void propref_done(struct propref *pr) { if (pr->refcnt == 0) panic("propref_done: refcnt==0"); pr->refcnt --; propref_refc0chk(pr); } void propref_remove_nil_or_done(struct propref *pr) { if ((pr->attr & PATTR_TYPE) == PTYPE_NIL) { propref_remove(pr); } else { propref_done(pr); } } void copy_plist_to(struct plist *pl, dbref todbref) { struct propref *pr; struct propref *npr; if (pl == 0) return; for (pr=pl->ptrs[0];pr;pr=pr->ptrs[0]) { if (pr->deleted) continue; npr = lookup_property(todbref,PROPNAME_NAME(pr->name),LP_CREATE,pr->attr); propref_copy_type_and_value(npr,pr); propref_done(npr); } } void free_plist(struct plist *pl) { struct propref *p; if (pl == 0) return; for (p=pl->ptrs[0];p;p=p->ptrs[0]) p->deleted = 1; lookup_property_(&pl,0,0,0,0); free(pl); } struct propref *create_property_compat(dbref dbr, const char *name) { PROPATTR perms; switch (name[0]) { case '.': perms = PPERM_COMPAT_PRIVATE; break; case '_': case '%': perms = PPERM_COMPAT_RDONLY; break; case '@': perms = PPERM_COMPAT_WIZ; break; case '~': perms = PPERM_COMPAT_WWUR; break; case '*': perms = PPERM_COMPAT_MUF; break; default: perms = PPERM_COMPAT_DEFAULT; break; } return(lookup_property(dbr,name,LP_CREATE,perms)); } int walk_plist(struct plist *pl, unsigned int flags, int (*fn)(struct propref *, void *), void *cookie) { int frv; int trv; struct propref *pr; if (pl == 0) return(0); trv = 0; if (flags != 0) panic("walk_plist: bad flags"); for (pr=pl->ptrs[0];pr;pr=pr->ptrs[0]) { if (pr->deleted) continue; /* could duplicate deletion code, but... */ frv = (*fn)(pr,cookie); if (frv < 0) return(frv); trv += frv; } return(trv); } void plist_filter(struct plist **plp, int (*fn)(struct propref *, void *), void *cookie) { struct propref **linkptrs[MAXHEIGHT]; struct propref *p; struct propref *p2; int i; if (*plp == 0) return; for (i=0;iptrs[i]; for (p=(*plp)->ptrs[0];p;p=p2) { p2 = p->ptrs[0]; if (!p->deleted && (*fn)(p,cookie)) { for (i=p->height-1;i>=0;i--) { *linkptrs[i] = p; linkptrs[i] = &p->ptrs[i]; } } else { p->refcnt --; propref_refc0chk(p); } } for (i=0;iptrs[0] == 0) { free(*plp); *plp = 0; } } void putplist(FILE *f, struct plist *pl) { struct propref *pr; fprintf(f,"*p1*\n"); if (pl) { for (pr=pl->ptrs[0];pr;pr=pr->ptrs[0]) { if (pr->deleted) continue; switch (pr->attr & PATTR_TYPE) { case PTYPE_STRING: fputs_pperm(f,pr->attr&PATTR_PERM); fprintf(f,"S%s:",PROPNAME_NAME(pr->name)); fputs_str(pr->value.s,f); fprintf(f,"\n"); break; case PTYPE_DBREF: fputs_pperm(f,pr->attr&PATTR_PERM); fprintf(f,"D%s:%ld\n",PROPNAME_NAME(pr->name),(long int)pr->value.d); break; } } } fprintf(f,"%c\n",PERM_END); } int getplist(FILE *f, dbref dbr) { int c; char *buf; int have; int len; char *name; PROPATTR attr; while (1) { c = getc(f); if (c == EOF) return(1); if (c == '\n') break; } buf = malloc(1); have = 0; len = 0; name = 0; while (1) { c = fgets_pperm(f,&attr); if (c < 0) return(1); if (c > 0) break; c = getc(f); switch (c) { case 'S': attr |= PTYPE_STRING; break; case 'D': attr |= PTYPE_DBREF; break; default: return(1); break; } while (1) { c = getc(f); if (c == EOF) return(1); if ((c == ':') && !name) { buf[len] = '\0'; name = buf; buf = malloc(1); have = 0; len = 0; continue; } if (c == '\n') { if (name) { struct propref *pr; buf[len] = '\0'; pr = lookup_property(dbr,name,LP_CREATE,attr); if ((pr->attr & PATTR_TYPE) != PTYPE_NIL) panic("getplist: non-nil prop"); switch (attr & PATTR_TYPE) { case PTYPE_STRING: propref_set_type_and_value(pr,PTYPE_STRING,buf); break; case PTYPE_DBREF: propref_set_type_and_value(pr,PTYPE_DBREF,(dbref)atoi(buf)); break; default: panic("getplist: impossible type"); break; } propref_done(pr); free(name); name = 0; len = 0; break; } else { free(buf); return(0); } } if (len >= have) buf = realloc(buf,(have=len+16)+1); buf[len++] = c; } } free(buf); while (1) { c = getc(f); if (c == EOF) return(1); if (c == '\n') break; } return(0); } int compat_getplist(FILE *f, dbref dbr) { int c; char *buf; int have; int len; char *name; while (1) { c = getc(f); if (c == EOF) return(1); if (c == '\n') break; } buf = malloc(1); have = 0; len = 0; name = 0; while (1) { c = getc(f); if (c == EOF) return(1); if ((c == ':') && !name) { buf[len] = '\0'; name = buf; buf = malloc(1); have = 0; len = 0; continue; } if (c == '\n') { if (name) { struct propref *pr; buf[len] = '\0'; pr = create_property_compat(dbr,name); if ((pr->attr & PATTR_TYPE) != PTYPE_NIL) panic("compat_getplist: non-nil prop"); propref_set_type_and_value(pr,PTYPE_STRING,buf); free(name); name = 0; len = 0; continue; } else { free(buf); return(0); } } if (len >= have) buf = realloc(buf,(have=len+16)+1); buf[len++] = c; } } int get_plist_strings(FILE *f, void (*fn)(const char *)) { int c; char *buf; int have; int len; int name; PROPATTR attr; while (1) { c = getc(f); if (c == EOF) return(1); if (c == '\n') break; } buf = malloc(1); have = 0; len = 0; name = 0; while (1) { c = fgets_pperm(f,&attr); if (c < 0) return(1); if (c > 0) break; c = getc(f); switch (c) { case 'S': attr |= PTYPE_STRING; break; case 'D': attr |= PTYPE_DBREF; break; default: return(1); break; } while (1) { c = getc(f); if (c == EOF) return(1); if ((c == ':') && !name) { name = 1; len = 0; continue; } if (c == '\n') { if (name) { buf[len] = '\0'; (*fn)(buf); name = 0; len = 0; break; } else { free(buf); return(0); } } if (len >= have) buf = realloc(buf,(have=len+16)+1); buf[len++] = c; } } free(buf); return(0); } int genderof(dbref thing) { struct propref *pr; char *sex; int rv; pr = lookup_property(thing,"_sex",0); sex = 0; if (pr && ((propref_get_attr(pr) & PATTR_TYPE) == PTYPE_STRING)) { sex = propref_get_string(pr); } rv = GENDER_UNASSIGNED; if (sex) { if (!string_compare(sex,"male")) rv = GENDER_MALE; else if (!string_compare(sex,"female")) rv = GENDER_FEMALE; else if (!string_compare(sex,"neuter")) rv = GENDER_NEUTER; free(sex); } if (pr) propref_done(pr); return(rv); } int plist_memused(const struct plist *pl) { int m; struct propref *pr; if (pl == 0) return(0); m = sizeof(struct plist); for (pr=pl->ptrs[0];pr;pr=pr->ptrs[0]) { if (pr->deleted) continue; m += sizeof(*pr) + ((pr->height - 1) * sizeof(struct propref *)) + strlen(PROPNAME_NAME(pr->name)) + 1; switch (pr->attr & PATTR_TYPE) { case PTYPE_STRING: m += str_memusage(pr->value.s); break; case PTYPE_ANYVAL: m += inst_memused(pr->value.i); break; } } return(m); } /* Renumber all properties, so as to sort all property lists. */ extern void prop_renumber_all(void); /* debugging help */ void dump_pns(void); void dump_pns(void) { static struct propname *curptrs[MAXHEIGHT+1]; struct propname *t; int i; for (i=MAXHEIGHT;i>=0;i--) { curptrs[i] = pnroot[i]; fprintf(stderr," x"); } fprintf(stderr," (root)\n"); while ((t=curptrs[0])) { for (i=t->height-1;i>=0;i--) { if (curptrs[i] != t) { fprintf(stderr,"*** curptrs[%d] = %p, should be %p\n",i,(void *)curptrs[i],(void *)t); } curptrs[i] = t->ptrs[i]; } for (i=MAXHEIGHT;i>=(int)t->height;i--) fprintf(stderr," "); for (;i>=0;i--) fprintf(stderr," x"); fprintf(stderr," (ser=%d ref=%d) %s\n",(int)t->serial,(int)t->refcnt,PROPNAME_NAME(t)); } for (i=MAXHEIGHT;i>=0;i--) { if (curptrs[i]) { fprintf(stderr,"*** curptrs[%d] = %p, should be %p\n",i,(void *)curptrs[i],(void *)0); } } } void dump_props(int); void dump_props(int dbr) { static struct propref *curptrs[MAXHEIGHT+1]; struct propref *t; struct plist *lst; int i; if ((dbr < 0) || (dbr >= db_top)) { fprintf(stderr,"#%d: not a valid dbref\n",dbr); return; } if (Typeof(dbr) == TYPE_GARBAGE) { fprintf(stderr,"note: #%d is garbage\n",dbr); } lst = DBFETCH(dbr)->properties; if (lst == 0) { fprintf(stderr,"#%d: no property list\n",dbr); return; } for (i=MAXHEIGHT;i>=0;i--) { curptrs[i] = lst->ptrs[i]; fprintf(stderr," x"); } fprintf(stderr," (root)\n"); t = curptrs[0]; while (t) { for (i=t->height-1;i>=0;i--) { if (curptrs[i] != t) { fprintf(stderr,"*** curptrs[%d] = %p, should be %p\n",i,(void *)curptrs[i],(void *)t); } curptrs[i] = t->ptrs[i]; } for (i=MAXHEIGHT;i>=(int)t->height;i--) fprintf(stderr," "); for (;i>=0;i--) fprintf(stderr," x"); { char *val; val = fetch_str(t->value.s); fprintf(stderr," (nameser=%d name=%s) %s\n",(int)t->name->serial,PROPNAME_NAME(t->name),val); free(val); } } for (i=MAXHEIGHT;i>=0;i--) { if (curptrs[i]) { fprintf(stderr,"*** curptrs[%d] = %p, should be %p\n",i,(void *)curptrs[i],(void *)0); } } } void prop_renumber_all(void) { struct propname *n; dbref d; struct plist *pl; for (n=pnroot[0];n;n=n->ptrs[0]) n->serial = nextpnserial ++; for (d=0;dproperties; if (! pl) continue; pl->ptrs[0] = plist_sort(pl->ptrs[0]); plist_rethread(pl); } } static int fry_if_matches(struct propref *pr, void *tvp) { if ((pr->attr & PATTR_TYPE) != PTYPE_DBREF) return(0); if (pr->value.d != *(dbref *)tvp) return(0); pr->value.d = NOTHING; return(0); } void fry_dbref_props(struct plist *pl, dbref target) { walk_plist(pl,0,fry_if_matches,&target); }