/* $Header: /cvsroot/fbmuck/fbmuck/src/property.c,v 1.26 2004/10/07 09:19:03 revar Exp $ */ #include "copyright.h" #include "config.h" #include "params.h" #include "db.h" #include "tune.h" #include "mpi.h" #include "props.h" #include "externs.h" #include "interface.h" #include <string.h> #include <math.h> #define alloc_compressed(x) alloc_string(compress(x)) /* property.c A whole new lachesis mod. Adds property manipulation routines to TinyMUCK. */ /* Completely rewritten by darkfox and Foxen, for propdirs and other things */ void set_property_nofetch(dbref player, const char *pname, PData * dat) { PropPtr p; char buf[BUFFER_LEN]; char *n, *w; /* Make sure that we are passed a valid property name */ if (!pname) return; while (*pname == PROPDIR_DELIMITER) pname++; if ((!(FLAGS(player) & LISTENER)) && (string_prefix(pname, "_listen") || string_prefix(pname, "~listen") || string_prefix(pname, "~olisten"))) { FLAGS(player) |= LISTENER; } w = strcpyn(buf, sizeof(buf), pname); /* truncate propnames with a ':' in them at the ':' */ n = index(buf, PROP_DELIMITER); if (n) *n = '\0'; if (!*buf) return; p = propdir_new_elem(&(DBFETCH(player)->properties), w); /* free up any old values */ clear_propnode(p); SetPFlagsRaw(p, dat->flags); if (PropFlags(p) & PROP_ISUNLOADED) { SetPDataUnion(p, dat->data); return; } switch (PropType(p)) { case PROP_STRTYP: if (!dat->data.str || !*(dat->data.str)) { SetPType(p, PROP_DIRTYP); SetPDataStr(p, NULL); if (!PropDir(p)) { remove_property_nofetch(player, pname); } } else { SetPDataStr(p, alloc_compressed(dat->data.str)); #ifdef COMPRESS SetPFlagsRaw(p, (dat->flags | PROP_COMPRESSED)); #endif } break; case PROP_INTTYP: SetPDataVal(p, dat->data.val); if (!dat->data.val) { SetPType(p, PROP_DIRTYP); if (!PropDir(p)) { remove_property_nofetch(player, pname); } } break; case PROP_FLTTYP: SetPDataFVal(p, dat->data.fval); if (dat->data.fval == 0.0) { SetPType(p, PROP_DIRTYP); if (!PropDir(p)) { remove_property_nofetch(player, pname); } } break; case PROP_REFTYP: SetPDataRef(p, dat->data.ref); if (dat->data.ref == NOTHING) { SetPType(p, PROP_DIRTYP); SetPDataRef(p, 0); if (!PropDir(p)) { remove_property_nofetch(player, pname); } } break; case PROP_LOKTYP: SetPDataLok(p, dat->data.lok); break; case PROP_DIRTYP: SetPDataVal(p, 0); if (!PropDir(p)) { remove_property_nofetch(player, pname); } break; } } void set_property(dbref player, const char *name, PData * dat) { #ifdef DISKBASE fetchprops(player, propdir_name(name)); set_property_nofetch(player, name, dat); dirtyprops(player); #else set_property_nofetch(player, name, dat); #endif DBDIRTY(player); } void set_lock_property(dbref player, const char *pname, const char *lok) { PData mydat; mydat.flags = PROP_LOKTYP; if (!lok || !*lok) { mydat.data.lok = TRUE_BOOLEXP; } else { mydat.data.lok = parse_boolexp(-1, (dbref) 1, lok, 1); } set_property(player, pname, &mydat); } /* adds a new property to an object */ void add_prop_nofetch(dbref player, const char *pname, const char *strval, int value) { PData mydat; if (strval && *strval) { mydat.flags = PROP_STRTYP; mydat.data.str = (char *) strval; } else if (value) { mydat.flags = PROP_INTTYP; mydat.data.val = value; } else { mydat.flags = PROP_DIRTYP; mydat.data.str = NULL; } set_property_nofetch(player, pname, &mydat); } /* adds a new property to an object */ void add_property(dbref player, const char *pname, const char *strval, int value) { #ifdef DISKBASE fetchprops(player, propdir_name(pname)); add_prop_nofetch(player, pname, strval, value); dirtyprops(player); #else add_prop_nofetch(player, pname, strval, value); #endif DBDIRTY(player); } void remove_proplist_item(dbref player, PropPtr p, int allp) { const char *ptr; if (!p) return; ptr = PropName(p); if (Prop_System(ptr)) return; if (!allp) { if (*ptr == PROP_HIDDEN) return; if (*ptr == PROP_SEEONLY) return; if (ptr[0] == '_' && ptr[1] == '\0') return; if (PropFlags(p) & PROP_SYSPERMS) return; } remove_property(player, ptr); } /* removes property list --- if it's not there then ignore */ void remove_property_list(dbref player, int all) { PropPtr l; PropPtr p; PropPtr n; #ifdef DISKBASE fetchprops(player, NULL); #endif if ((l = DBFETCH(player)->properties) != NULL) { p = first_node(l); while (p) { n = next_node(l, PropName(p)); remove_proplist_item(player, p, all); l = DBFETCH(player)->properties; p = n; } } #ifdef DISKBASE dirtyprops(player); #endif DBDIRTY(player); } /* removes property --- if it's not there then ignore */ void remove_property_nofetch(dbref player, const char *pname) { PropPtr l; char buf[BUFFER_LEN]; char *w; w = strcpyn(buf, sizeof(buf), pname); l = DBFETCH(player)->properties; l = propdir_delete_elem(l, w); DBFETCH(player)->properties = l; DBDIRTY(player); } void remove_property(dbref player, const char *pname) { #ifdef DISKBASE fetchprops(player, propdir_name(pname)); #endif remove_property_nofetch(player, pname); #ifdef DISKBASE dirtyprops(player); #endif } PropPtr get_property(dbref player, const char *pname) { PropPtr p; char buf[BUFFER_LEN]; char *w; #ifdef DISKBASE fetchprops(player, propdir_name(pname)); #endif w = strcpy(buf, pname); p = propdir_get_elem(DBFETCH(player)->properties, w); return (p); } /* checks if object has property, returning 1 if it or any of it's contents has the property stated */ int has_property(int descr, dbref player, dbref what, const char *pname, const char *strval, int value) { dbref things; if (has_property_strict(descr, player, what, pname, strval, value)) return 1; for (things = DBFETCH(what)->contents; things != NOTHING; things = DBFETCH(things)->next) { if (has_property(descr, player, things, pname, strval, value)) return 1; } if (tp_lock_envcheck) { things = getparent(what); while (things != NOTHING) { if (has_property_strict(descr, player, things, pname, strval, value)) return 1; things = getparent(things); } } return 0; } static int has_prop_recursion_limit = 2; /* checks if object has property, returns 1 if it has the property */ int has_property_strict(int descr, dbref player, dbref what, const char *pname, const char *strval, int value) { PropPtr p; const char *str; char *ptr; char buf[BUFFER_LEN]; p = get_property(what, pname); if (p) { #ifdef DISKBASE propfetch(what, p); #endif if (PropType(p) == PROP_STRTYP) { str = uncompress(DoNull(PropDataStr(p))); if (has_prop_recursion_limit-->0) { ptr = do_parse_mesg(descr, player, what, str, "(Lock)", buf, (MPI_ISPRIVATE | MPI_ISLOCK | ((PropFlags(p) & PROP_BLESSED)? MPI_ISBLESSED : 0))); } else { strcpyn(buf, sizeof(buf), str); ptr = buf; } has_prop_recursion_limit++; return (equalstr((char *) strval, ptr)); } else if (PropType(p) == PROP_LOKTYP) { return 0; } else if (PropType(p) == PROP_INTTYP) { return (value == PropDataVal(p)); } else { return (value == (int) PropDataFVal(p)); } } return 0; } /* return string value of property */ const char * get_property_class(dbref player, const char *pname) { PropPtr p; p = get_property(player, pname); if (p) { #ifdef DISKBASE propfetch(player, p); #endif if (PropType(p) != PROP_STRTYP) return (char *) NULL; return (PropDataStr(p)); } else { return (char *) NULL; } } /* return value of property */ int get_property_value(dbref player, const char *pname) { PropPtr p; p = get_property(player, pname); if (p) { #ifdef DISKBASE propfetch(player, p); #endif if (PropType(p) != PROP_INTTYP) return 0; return (PropDataVal(p)); } else { return 0; } } /* return float value of a property */ double get_property_fvalue(dbref player, const char *pname) { PropPtr p; p = get_property(player, pname); if (p) { #ifdef DISKBASE propfetch(player, p); #endif if (PropType(p) != PROP_FLTTYP) return 0.0; return (PropDataFVal(p)); } else { return 0.0; } } /* return boolexp lock of property */ dbref get_property_dbref(dbref player, const char *pname) { PropPtr p; p = get_property(player, pname); if (!p) return NOTHING; #ifdef DISKBASE propfetch(player, p); #endif if (PropType(p) != PROP_REFTYP) return NOTHING; return PropDataRef(p); } /* return boolexp lock of property */ struct boolexp * get_property_lock(dbref player, const char *pname) { PropPtr p; p = get_property(player, pname); if (!p) return TRUE_BOOLEXP; #ifdef DISKBASE propfetch(player, p); if (PropFlags(p) & PROP_ISUNLOADED) return TRUE_BOOLEXP; #endif if (PropType(p) != PROP_LOKTYP) return TRUE_BOOLEXP; return PropDataLok(p); } /* return flags of property */ int get_property_flags(dbref player, const char *pname) { PropPtr p; p = get_property(player, pname); if (p) { return (PropFlags(p)); } else { return 0; } } /* return flags of property */ void clear_property_flags(dbref player, const char *pname, int flags) { PropPtr p; flags &= ~PROP_TYPMASK; p = get_property(player, pname); if (p) { SetPFlags(p, (PropFlags(p) & ~flags)); #ifdef DISKBASE dirtyprops(player); #endif } } /* return flags of property */ void set_property_flags(dbref player, const char *pname, int flags) { PropPtr p; flags &= ~PROP_TYPMASK; p = get_property(player, pname); if (p) { SetPFlags(p, (PropFlags(p) | flags)); #ifdef DISKBASE dirtyprops(player); #endif } } /* return type of property */ int get_property_type(dbref player, const char *pname) { PropPtr p; p = get_property(player, pname); if (p) { return (PropType(p)); } else { return 0; } } PropPtr copy_prop(dbref old) { PropPtr p, n = NULL; #ifdef DISKBASE fetchprops(old, NULL); #endif p = DBFETCH(old)->properties; copy_proplist(old, &n, p); return (n); } /* Return a pointer to the first property in a propdir and duplicates the property name into 'name'. Returns NULL if the property list is empty or does not exist. */ PropPtr first_prop_nofetch(dbref player, const char *dir, PropPtr * list, char *name) { char buf[BUFFER_LEN]; PropPtr p; if (dir) { while (*dir && *dir == PROPDIR_DELIMITER) { dir++; } } if (!dir || !*dir) { *list = DBFETCH(player)->properties; p = first_node(*list); if (p) { strcpy(name, PropName(p)); } else { *name = '\0'; } return (p); } strcpy(buf, dir); *list = p = propdir_get_elem(DBFETCH(player)->properties, buf); if (!p) { *name = '\0'; return NULL; } *list = PropDir(p); p = first_node(*list); if (p) { strcpy(name, PropName(p)); } else { *name = '\0'; } return (p); } /* first_prop() returns a pointer to the first property. * player dbref of object that the properties are on. * dir pointer to string name of the propdir * list pointer to a proplist pointer. Returns the root node. * name printer to a string. Returns the name of the first node. */ PropPtr first_prop(dbref player, const char *dir, PropPtr * list, char *name) { #ifdef DISKBASE fetchprops(player, (char *) dir); #endif return (first_prop_nofetch(player, dir, list, name)); } /* next_prop() returns a pointer to the next property node. * list Pointer to the root node of the list. * prop Pointer to the previous prop. * name Pointer to a string. Returns the name of the next property. */ PropPtr next_prop(PropPtr list, PropPtr prop, char *name) { PropPtr p = prop; if (!p || !(p = next_node(list, PropName(p)))) return ((PropPtr) 0); strcpy(name, PropName(p)); return (p); } /* next_prop_name() returns a ptr to the string name of the next property. * player object the properties are on. * outbuf pointer to buffer to return the next prop's name in. * name pointer to the name of the previous property. * * Returns null if propdir doesn't exist, or if no more properties in list. * Call with name set to "" to get the first property of the root propdir. */ char * next_prop_name(dbref player, char *outbuf, int outbuflen, char *name) { char *ptr; char buf[BUFFER_LEN]; PropPtr p, l; #ifdef DISKBASE fetchprops(player, propdir_name(name)); #endif strcpy(buf, name); if (!*name || name[strlen(name) - 1] == PROPDIR_DELIMITER) { l = DBFETCH(player)->properties; p = propdir_first_elem(l, buf); if (!p) { *outbuf = '\0'; return NULL; } strcpyn(outbuf, outbuflen, name); strcatn(outbuf, outbuflen, PropName(p)); } else { l = DBFETCH(player)->properties; p = propdir_next_elem(l, buf); if (!p) { *outbuf = '\0'; return NULL; } strcpy(outbuf, name); ptr = rindex(outbuf, PROPDIR_DELIMITER); if (!ptr) ptr = outbuf; *(ptr++) = PROPDIR_DELIMITER; strcpy(ptr, PropName(p)); } return outbuf; } long size_properties(dbref player, int load) { #ifdef DISKBASE if (load) { fetchprops(player, NULL); fetch_propvals(player, "/"); } #endif return size_proplist(DBFETCH(player)->properties); } /* return true if a property contains a propdir */ int is_propdir_nofetch(dbref player, const char *pname) { PropPtr p; char w[BUFFER_LEN]; strcpy(w, pname); p = propdir_get_elem(DBFETCH(player)->properties, w); if (!p) return 0; return (PropDir(p) != (PropPtr) NULL); } int is_propdir(dbref player, const char *pname) { #ifdef DISKBASE fetchprops(player, propdir_name(pname)); #endif return (is_propdir_nofetch(player, pname)); } PropPtr envprop(dbref * where, const char *propname, int typ) { PropPtr temp; while (*where != NOTHING) { temp = get_property(*where, propname); #ifdef DISKBASE if (temp) propfetch(*where, temp); #endif if (temp && (!typ || PropType(temp) == typ)) return temp; *where = getparent(*where); } return NULL; } const char * envpropstr(dbref * where, const char *propname) { PropPtr temp; temp = envprop(where, propname, PROP_STRTYP); if (!temp) return NULL; if (PropType(temp) == PROP_STRTYP) return (PropDataStr(temp)); return NULL; } char * displayprop(dbref player, dbref obj, const char *name, char *buf, size_t bufsiz) { char mybuf[BUFFER_LEN]; int pdflag; char blesschar = '-'; PropPtr p = get_property(obj, name); if (!p) { snprintf(buf, bufsiz, "%s: No such property.", name); return buf; } #ifdef DISKBASE propfetch(obj, p); #endif if (PropFlags(p) & PROP_BLESSED) blesschar = 'B'; pdflag = (PropDir(p) != NULL); snprintf(mybuf, bufsiz, "%.*s%c", (BUFFER_LEN / 4), name, (pdflag) ? PROPDIR_DELIMITER : '\0'); switch (PropType(p)) { case PROP_STRTYP: snprintf(buf, bufsiz, "%c str %s:%.*s", blesschar, mybuf, (BUFFER_LEN / 2), PropDataStr(p)); break; case PROP_REFTYP: snprintf(buf, bufsiz, "%c ref %s:%s", blesschar, mybuf, unparse_object(player, PropDataRef(p))); break; case PROP_INTTYP: snprintf(buf, bufsiz, "%c int %s:%d", blesschar, mybuf, PropDataVal(p)); break; case PROP_FLTTYP: snprintf(buf, bufsiz, "%c flt %s:%.17g", blesschar, mybuf, PropDataFVal(p)); break; case PROP_LOKTYP: if (PropFlags(p) & PROP_ISUNLOADED) { snprintf(buf, bufsiz, "%c lok %s:*UNLOCKED*", blesschar, mybuf); } else { snprintf(buf, bufsiz, "%c lok %s:%.*s", blesschar, mybuf, (BUFFER_LEN / 2), unparse_boolexp(player, PropDataLok(p), 1)); } break; case PROP_DIRTYP: snprintf(buf, bufsiz, "%c dir %s:(no value)", blesschar, mybuf); break; } return buf; } #define DOWNCASE(x) (tolower(x)) extern short db_conversion_flag; extern short db_decompression_flag; int db_get_single_prop(FILE * f, dbref obj, long pos, PropPtr pnode, const char *pdir) { char getprop_buf[BUFFER_LEN * 3]; char *name, *flags, *value, *p; int flg; long tpos=0L; struct boolexp *lok; short do_diskbase_propvals; PData mydat; #ifdef DISKBASE do_diskbase_propvals = tp_diskbase_propvals; #else do_diskbase_propvals = 0; #endif if (pos) { fseek(f, pos, 0); } else if (do_diskbase_propvals) { tpos = ftell(f); } name = fgets(getprop_buf, sizeof(getprop_buf), f); if (!name) { wall_wizards("## WARNING! A corrupt property was found while trying to read it from disk."); wall_wizards("## This property has been skipped and will not be loaded. See the sanity"); wall_wizards("## logfile for technical details."); log_sanity("Failed to read property from disk: Failed disk read. obj = #%d, pos = %ld, pdir = %s", obj, pos, pdir); return -1; } if (*name == '*') { if (!strcmp(name, "*End*\n")) { return 0; } if (name[1] == '\n') { return 2; } } flags = index(name, PROP_DELIMITER); if (!flags) { wall_wizards("## WARNING! A corrupt property was found while trying to read it from disk."); wall_wizards("## This property has been skipped and will not be loaded. See the sanity"); wall_wizards("## logfile for technical details."); log_sanity("Failed to read property from disk: Corrupt property, flag delimiter not found. obj = #%d, pos = %ld, pdir = %s, data = %s", obj, pos, pdir, name); return -1; } *flags++ = '\0'; value = index(flags, PROP_DELIMITER); if (!value) { wall_wizards("## WARNING! A corrupt property was found while trying to read it from disk."); wall_wizards("## This property has been skipped and will not be loaded. See the sanity"); wall_wizards("## logfile for technical details."); log_sanity("Failed to read property from disk: Corrupt property, value delimiter not found. obj = #%d, pos = %ld, pdir = %s, data = %s:%s", obj, pos, pdir, name, flags); return -1; } *value++ = '\0'; p = index(value, '\n'); if (p) { *p = '\0'; } if (!number(flags)) { wall_wizards("## WARNING! A corrupt property was found while trying to read it from disk."); wall_wizards("## This property has been skipped and will not be loaded. See the sanity"); wall_wizards("## logfile for technical details."); log_sanity("Failed to read property from disk: Corrupt property flags. obj = #%d, pos = %ld, pdir = %s, data = %s:%s:%s", obj, pos, pdir, name, flags, value); return -1; } flg = atoi(flags); switch (flg & PROP_TYPMASK) { case PROP_STRTYP: if (!do_diskbase_propvals || pos) { flg &= ~PROP_ISUNLOADED; #ifdef COMPRESS if (!(flg & PROP_COMPRESSED)) { value = (char *) old_uncompress(value); } #endif if (pnode) { SetPDataStr(pnode, alloc_compressed(value)); #ifdef COMPRESS flg |= PROP_COMPRESSED; #endif SetPFlagsRaw(pnode, flg); } else { mydat.flags = flg; mydat.data.str = value; set_property_nofetch(obj, name, &mydat); } } else { flg |= PROP_ISUNLOADED; mydat.flags = flg; mydat.data.val = tpos; set_property_nofetch(obj, name, &mydat); } break; case PROP_LOKTYP: if (!do_diskbase_propvals || pos) { lok = parse_boolexp(-1, (dbref) 1, value, 32767); flg &= ~PROP_ISUNLOADED; if (pnode) { SetPDataLok(pnode, lok); SetPFlagsRaw(pnode, flg); } else { mydat.flags = flg; mydat.data.lok = lok; set_property_nofetch(obj, name, &mydat); } } else { flg |= PROP_ISUNLOADED; mydat.flags = flg; mydat.data.val = tpos; set_property_nofetch(obj, name, &mydat); } break; case PROP_INTTYP: if (!number(value)) { wall_wizards("## WARNING! A corrupt property was found while trying to read it from disk."); wall_wizards("## This property has been skipped and will not be loaded. See the sanity"); wall_wizards("## logfile for technical details."); log_sanity("Failed to read property from disk: Corrupt integer value. obj = #%d, pos = %ld, pdir = %s, data = %s:%s:%s", obj, pos, pdir, name, flags, value); return -1; } mydat.flags = flg; mydat.data.val = atoi(value); set_property_nofetch(obj, name, &mydat); break; case PROP_FLTTYP: mydat.flags = flg; if (!number(value) && !ifloat(value)) { char *tpnt = value; int dtemp = 0; if ((*tpnt == '+') || (*tpnt == '-')) { if (*tpnt == '+') { dtemp = 0; } else { dtemp = 1; } tpnt++; } tpnt[0] = toupper(tpnt[0]); tpnt[1] = toupper(tpnt[1]); tpnt[2] = toupper(tpnt[2]); if (!strncmp(tpnt, "INF", 3)) { if (!dtemp) { mydat.data.fval = INF; } else { mydat.data.fval = NINF; } } else { if (!strncmp(tpnt, "NAN", 3)) { /* FIXME: This should be NaN. */ mydat.data.fval = INF; } } } else { sscanf(value, "%lg", &mydat.data.fval); } set_property_nofetch(obj, name, &mydat); break; case PROP_REFTYP: if (!number(value)) { wall_wizards("## WARNING! A corrupt property was found while trying to read it from disk."); wall_wizards("## This property has been skipped and will not be loaded. See the sanity"); wall_wizards("## logfile for technical details."); log_sanity("Failed to read property from disk: Corrupt dbref value. obj = #%d, pos = %ld, pdir = %s, data = %s:%s:%s", obj, pos, pdir, name, flags, value); return -1; } mydat.flags = flg; mydat.data.ref = atoi(value); set_property_nofetch(obj, name, &mydat); break; case PROP_DIRTYP: break; } return 1; } void db_getprops(FILE * f, dbref obj, const char *pdir) { while (db_get_single_prop(f, obj, 0L, (PropPtr) NULL, pdir)) ; } void db_putprop(FILE * f, const char *dir, PropPtr p) { char buf[BUFFER_LEN * 2]; const char *ptr2; char tbuf[50]; int outflags = (PropFlagsRaw(p) & ~(PROP_TOUCHED | PROP_ISUNLOADED | PROP_DIRUNLOADED)); if (PropType(p) == PROP_DIRTYP) return; ptr2 = ""; switch (PropType(p)) { case PROP_INTTYP: if (!PropDataVal(p)) return; ptr2 = intostr(PropDataVal(p)); break; case PROP_FLTTYP: if (!PropDataFVal(p)) return; snprintf(tbuf, sizeof(tbuf), "%.17g", PropDataFVal(p)); ptr2 = tbuf; break; case PROP_REFTYP: if (PropDataRef(p) == NOTHING) return; ptr2 = intostr(PropDataRef(p)); break; case PROP_STRTYP: if (!*PropDataStr(p)) return; if (db_decompression_flag) { ptr2 = uncompress(PropDataStr(p)); } else { ptr2 = PropDataStr(p); } break; case PROP_LOKTYP: if (PropFlags(p) & PROP_ISUNLOADED) return; if (PropDataLok(p) == TRUE_BOOLEXP) return; ptr2 = unparse_boolexp((dbref) 1, PropDataLok(p), 0); break; } snprintf(buf, sizeof(buf), "%s%s%c%d%c%s\n", dir+1, PropName(p), PROP_DELIMITER, outflags, PROP_DELIMITER, ptr2); if (fputs(buf, f) == EOF) { log_sanity("Failed to write out property db_putprop(dir = %s)", dir); abort(); } } int db_dump_props_rec(dbref obj, FILE * f, const char *dir, PropPtr p) { char buf[BUFFER_LEN]; #ifdef DISKBASE long tpos=0L; int flg; short wastouched = 0; #endif int count = 0; int pdcount; if (!p) return 0; count += db_dump_props_rec(obj, f, dir, AVL_LF(p)); #ifdef DISKBASE wastouched = (PropFlags(p) & PROP_TOUCHED); if (tp_diskbase_propvals) { tpos = ftell(f); } if (wastouched) { count++; } if (propfetch(obj, p)) { fseek(f, 0L, 2); } #endif db_putprop(f, dir, p); #ifdef DISKBASE if (tp_diskbase_propvals && !wastouched) { if (PropType(p) == PROP_STRTYP || PropType(p) == PROP_LOKTYP) { flg = PropFlagsRaw(p) | PROP_ISUNLOADED; clear_propnode(p); SetPFlagsRaw(p, flg); SetPDataVal(p, tpos); } } #endif if (PropDir(p)) { const char *iptr; char *optr; for (iptr = dir, optr = buf; *iptr;) *optr++ = *iptr++; for (iptr = PropName(p); *iptr;) *optr++ = *iptr++; *optr++ = PROPDIR_DELIMITER; *optr++ = '\0'; pdcount = db_dump_props_rec(obj, f, buf, PropDir(p)); count += pdcount; } count += db_dump_props_rec(obj, f, dir, AVL_RT(p)); return count; } void db_dump_props(FILE * f, dbref obj) { db_dump_props_rec(obj, f, "/", DBFETCH(obj)->properties); } void untouchprop_rec(PropPtr p) { if (!p) return; SetPFlags(p, (PropFlags(p) & ~PROP_TOUCHED)); untouchprop_rec(AVL_LF(p)); untouchprop_rec(AVL_RT(p)); untouchprop_rec(PropDir(p)); } static dbref untouch_lastdone = 0; void untouchprops_incremental(int limit) { PropPtr p; while (untouch_lastdone < db_top) { /* clear the touch flags */ p = DBFETCH(untouch_lastdone)->properties; if (p) { if (!limit--) return; untouchprop_rec(p); } untouch_lastdone++; } untouch_lastdone = 0; } void reflist_add(dbref obj, const char* propname, dbref toadd) { PropPtr ptr; const char *temp; const char *list; int count = 0; int charcount = 0; char buf[BUFFER_LEN]; char outbuf[BUFFER_LEN]; ptr = get_property(obj, propname); if (ptr) { const char *pat = NULL; #ifdef DISKBASE propfetch(obj, ptr); #endif switch (PropType(ptr)) { case PROP_STRTYP: *outbuf = '\0'; list = temp = uncompress(PropDataStr(ptr)); snprintf(buf, sizeof(buf), "%d", toadd); while (*temp) { if (*temp == '#') { pat = buf; count++; charcount = temp - list; } else if (pat) { if (!*pat) { if (!*temp || *temp == ' ') { break; } pat = NULL; } else if (*pat != *temp) { pat = NULL; } else { pat++; } } temp++; } if (pat && !*pat) { if (charcount > 0) { strcpyn(outbuf, charcount, list); } strcatn(outbuf, sizeof(outbuf), temp); } else { strcpyn(outbuf, sizeof(outbuf), list); } snprintf(buf, sizeof(buf), " #%d", toadd); if (strlen(outbuf) + strlen(buf) < BUFFER_LEN) { strcatn(outbuf, sizeof(outbuf), buf); for (temp = outbuf; isspace(*temp); temp++); add_property(obj, propname, temp, 0); } break; case PROP_REFTYP: if (PropDataRef(ptr) != toadd) { snprintf(outbuf, sizeof(outbuf), "#%d #%d", PropDataRef(ptr), toadd); add_property(obj, propname, outbuf, 0); } break; default: snprintf(outbuf, sizeof(outbuf), "#%d", toadd); add_property(obj, propname, outbuf, 0); break; } } else { snprintf(outbuf, sizeof(outbuf), "#%d", toadd); add_property(obj, propname, outbuf, 0); } } void reflist_del(dbref obj, const char* propname, dbref todel) { PropPtr ptr; const char *temp; const char *list; int count = 0; int charcount = 0; char buf[BUFFER_LEN]; char outbuf[BUFFER_LEN]; ptr = get_property(obj, propname); if (ptr) { const char *pat = NULL; #ifdef DISKBASE propfetch(obj, ptr); #endif switch (PropType(ptr)) { case PROP_STRTYP: *outbuf = '\0'; list = temp = uncompress(PropDataStr(ptr)); snprintf(buf, sizeof(buf), "%d", todel); while (*temp) { if (*temp == '#') { pat = buf; count++; charcount = temp - list; } else if (pat) { if (!*pat) { if (!*temp || *temp == ' ') { break; } pat = NULL; } else if (*pat != *temp) { pat = NULL; } else { pat++; } } temp++; } if (pat && !*pat) { if (charcount > 0) { strcpyn(outbuf, charcount, list); } strcatn(outbuf, sizeof(outbuf), temp); for (temp = outbuf; isspace(*temp); temp++); add_property(obj, propname, temp, 0); } break; case PROP_REFTYP: if (PropDataRef(ptr) == todel) { add_property(obj, propname, "", 0); } break; default: break; } } } int reflist_find(dbref obj, const char* propname, dbref tofind) { PropPtr ptr; const char *temp; int pos = 0; int count = 0; char buf[BUFFER_LEN]; ptr = get_property(obj, propname); if (ptr) { const char *pat = NULL; #ifdef DISKBASE propfetch(obj, ptr); #endif switch (PropType(ptr)) { case PROP_STRTYP: temp = uncompress(PropDataStr(ptr)); snprintf(buf, sizeof(buf), "%d", tofind); while (*temp) { if (*temp == '#') { pat = buf; count++; } else if (pat) { if (!*pat) { if (!*temp || *temp == ' ') { break; } pat = NULL; } else if (*pat != *temp) { pat = NULL; } else { pat++; } } temp++; } if (pat && !*pat) { pos = count; } break; case PROP_REFTYP: if (PropDataRef(ptr) == tofind) pos = 1; break; default: break; } } return pos; }