/* db.c */ #include "copyright.h" #include <stdio.h> #include <ctype.h> #include <string.h> #include <sys/file.h> #include <sys/types.h> #define __DB_C #include "mudconf.h" #include "config.h" #include "externs.h" #include "db.h" #ifdef __GNUC__ #define INLINE inline #else #define INLINE #endif /* __GNUC__ */ DB *dbp; struct object *db = NULL; #ifdef TEST_MALLOC int malloc_count = 0; #endif /* TEST_MALLOC */ /* #define GNU_MALLOC_TEST 1 */ #ifdef GNU_MALLOC_TEST extern unsigned int malloc_sbrk_used; /* amount of data space used now */ #endif /* Check routine forward declaration. */ extern int ck_fwdlist(int key, dbref player, dbref thing, int anum, char *atext); /* * If you would like to add some attributes of your own please write to me * for available attribute #'s. This way some degree of compatibility can be * maintained between different variation of TinyMUSH Try: * larry@pleiades.ecs.umass.edu larry@belch.berkeley.edu * larry@sigh.berkeley.edu larry@roberts.wpi.edu or shiva on the MUDS */ /* list of attributes */ ATTR attr[] = { {"Aahear", A_AAHEAR, AF_ODARK, NULL}, {"Aclone", A_ACLONE, AF_ODARK, NULL}, {"Aconnect", A_ACONNECT, AF_ODARK, NULL}, {"Adesc", A_ADESC, AF_ODARK, NULL}, {"Adisconnect", A_ADISCONNECT, AF_ODARK, NULL}, {"Adrop", A_ADROP, AF_ODARK, NULL}, {"Aefail", A_AEFAIL, AF_ODARK|AF_NOPROG, NULL}, {"Aenter", A_AENTER, AF_ODARK, NULL}, {"Afail", A_AFAIL, AF_ODARK|AF_NOPROG, NULL}, {"Ahear", A_AHEAR, AF_ODARK, NULL}, {"Akill", A_AKILL, AF_ODARK, NULL}, {"Aleave", A_ALEAVE, AF_ODARK, NULL}, {"Alfail", A_ALFAIL, AF_ODARK|AF_NOPROG, NULL}, {"Alias", A_ALIAS, AF_NOPROG|AF_NOCMD|AF_GOD, NULL}, {"Allowance", A_ALLOWANCE, AF_MDARK|AF_NOPROG|AF_WIZARD, NULL}, {"Amhear", A_AMHEAR, AF_ODARK, NULL}, {"Amove", A_AMOVE, AF_ODARK, NULL}, {"Apay", A_APAY, AF_ODARK, NULL}, {"Asucc", A_ASUCC, AF_ODARK, NULL}, {"Atport", A_ATPORT, AF_ODARK|AF_NOPROG, NULL}, {"Aufail", A_AUFAIL, AF_ODARK|AF_NOPROG, NULL}, {"Ause", A_AUSE, AF_ODARK, NULL}, {"Away", A_AWAY, AF_ODARK|AF_NOPROG, NULL}, {"Charges", A_CHARGES, AF_ODARK|AF_NOPROG, NULL}, {"Comment", A_COMMENT, AF_MDARK|AF_WIZARD, NULL}, {"Cost", A_COST, AF_ODARK, NULL}, {"Desc", A_DESC, AF_NOPROG, NULL}, {"DefaultLock", A_LOCK, AF_ODARK|AF_NOPROG|AF_NOCMD|AF_IS_LOCK, NULL}, {"Drop", A_DROP, AF_ODARK|AF_NOPROG, NULL}, {"DropLock", A_LDROP, AF_ODARK|AF_NOPROG|AF_NOCMD|AF_IS_LOCK, NULL}, {"Ealias", A_EALIAS, AF_ODARK|AF_NOPROG, NULL}, {"Efail", A_EFAIL, AF_ODARK|AF_NOPROG, NULL}, {"Enter", A_ENTER, AF_ODARK, NULL}, {"EnterLock", A_LENTER, AF_ODARK|AF_NOPROG|AF_NOCMD|AF_IS_LOCK, NULL}, {"Fail", A_FAIL, AF_ODARK|AF_NOPROG, NULL}, {"Filter", A_FILTER, AF_ODARK|AF_NOPROG, NULL}, {"Forwardlist", A_FORWARDLIST, AF_ODARK|AF_NOPROG, ck_fwdlist}, {"GiveLock", A_LGIVE, AF_ODARK|AF_NOPROG|AF_NOCMD|AF_IS_LOCK, NULL}, {"Idesc", A_IDESC, AF_ODARK|AF_NOPROG, NULL}, {"Idle", A_IDLE, AF_ODARK|AF_NOPROG, NULL}, {"Infilter", A_INFILTER, AF_ODARK|AF_NOPROG, NULL}, {"Inprefix", A_INPREFIX, AF_ODARK|AF_NOPROG, NULL}, {"Kill", A_KILL, AF_ODARK, NULL}, {"Lalias", A_LALIAS, AF_ODARK|AF_NOPROG, NULL}, {"Last", A_LAST, AF_WIZARD|AF_NOCMD|AF_NOPROG, NULL}, {"Lastsite", A_LASTSITE, AF_ODARK|AF_NOPROG|AF_NOCMD|AF_GOD, NULL}, {"Leave", A_LEAVE, AF_ODARK, NULL}, {"LeaveLock", A_LLEAVE, AF_ODARK|AF_NOPROG|AF_NOCMD|AF_IS_LOCK, NULL}, {"Lfail", A_LFAIL, AF_ODARK|AF_NOPROG, NULL}, {"LinkLock", A_LLINK, AF_ODARK|AF_NOPROG|AF_NOCMD|AF_IS_LOCK, NULL}, {"Listen", A_LISTEN, AF_ODARK, NULL}, {"Logindata", A_LOGINDATA, AF_DARK|AF_NOPROG|AF_NOCMD|AF_INTERNAL, NULL}, {"Move", A_MOVE, AF_ODARK, NULL}, #ifdef ATR_NAME {"Name", A_NAME, AF_DARK|AF_NOPROG|AF_NOCMD|AF_INTERNAL, NULL}, #endif {"Odesc", A_ODESC, AF_ODARK|AF_NOPROG, NULL}, {"Odrop", A_ODROP, AF_ODARK|AF_NOPROG, NULL}, {"Oefail", A_OEFAIL, AF_ODARK|AF_NOPROG, NULL}, {"Oenter", A_OENTER, AF_ODARK, NULL}, {"Ofail", A_OFAIL, AF_ODARK|AF_NOPROG, NULL}, {"Okill", A_OKILL, AF_ODARK, NULL}, {"Oleave", A_OLEAVE, AF_ODARK, NULL}, {"Olfail", A_OLFAIL, AF_ODARK|AF_NOPROG, NULL}, {"Omove", A_OMOVE, AF_ODARK, NULL}, {"Opay", A_OPAY, AF_ODARK, NULL}, {"Osucc", A_OSUCC, AF_ODARK|AF_NOPROG, NULL}, {"Otport", A_OTPORT, AF_ODARK|AF_NOPROG, NULL}, {"Oufail", A_OUFAIL, AF_ODARK|AF_NOPROG, NULL}, {"Ouse", A_OUSE, AF_ODARK, NULL}, {"Oxenter", A_OXENTER, AF_ODARK, NULL}, {"Oxleave", A_OXLEAVE, AF_ODARK, NULL}, {"Oxtport", A_OXTPORT, AF_ODARK|AF_NOPROG, NULL}, {"PageLock", A_LPAGE, AF_ODARK|AF_NOPROG|AF_NOCMD|AF_IS_LOCK, NULL}, {"Pay", A_PAY, AF_ODARK, NULL}, {"Prefix", A_PREFIX, AF_ODARK|AF_NOPROG, NULL}, {"Queue", A_QUEUE, AF_ODARK|AF_NOPROG|AF_WIZARD|AF_NOCMD, NULL}, {"Quota", A_QUOTA, AF_DARK|AF_NOPROG|AF_WIZARD|AF_NOCMD, NULL}, {"ReceiveLock", A_LRECEIVE, AF_ODARK|AF_NOPROG|AF_NOCMD|AF_IS_LOCK, NULL}, {"Reject", A_REJECT, AF_ODARK|AF_NOPROG, NULL}, {"Rquota", A_RQUOTA, AF_DARK|AF_NOPROG|AF_WIZARD|AF_NOCMD, NULL}, {"Runout", A_RUNOUT, AF_ODARK, NULL}, {"Semaphore", A_SEMAPHORE, AF_ODARK|AF_NOPROG|AF_WIZARD|AF_NOCMD, NULL}, {"Sex", A_SEX, AF_NOPROG, NULL}, {"Startup", A_STARTUP, AF_ODARK, NULL}, {"Succ", A_SUCC, AF_ODARK|AF_NOPROG, NULL}, {"TeloutLock", A_LTELOUT, AF_ODARK|AF_NOPROG|AF_NOCMD|AF_IS_LOCK, NULL}, {"Timeout", A_TIMEOUT, AF_MDARK|AF_NOPROG|AF_WIZARD, NULL}, {"Tport", A_TPORT, AF_ODARK|AF_NOPROG, NULL}, {"TportLock", A_LTPORT, AF_ODARK|AF_NOPROG|AF_NOCMD|AF_IS_LOCK, NULL}, {"Ufail", A_UFAIL, AF_ODARK|AF_NOPROG, NULL}, {"Use", A_USE, AF_ODARK, NULL}, {"UseLock", A_LUSE, AF_ODARK|AF_NOPROG|AF_NOCMD|AF_IS_LOCK, NULL}, {"VA", A_VA, AF_ODARK, NULL}, {"VB", A_VA+1, AF_ODARK, NULL}, {"VC", A_VA+2, AF_ODARK, NULL}, {"VD", A_VA+3, AF_ODARK, NULL}, {"VE", A_VA+4, AF_ODARK, NULL}, {"VF", A_VA+5, AF_ODARK, NULL}, {"VG", A_VA+6, AF_ODARK, NULL}, {"VH", A_VA+7, AF_ODARK, NULL}, {"VI", A_VA+8, AF_ODARK, NULL}, {"VJ", A_VA+9, AF_ODARK, NULL}, {"VK", A_VA+10, AF_ODARK, NULL}, {"VL", A_VA+11, AF_ODARK, NULL}, {"VM", A_VA+12, AF_ODARK, NULL}, {"VN", A_VA+13, AF_ODARK, NULL}, {"VO", A_VA+14, AF_ODARK, NULL}, {"VP", A_VA+15, AF_ODARK, NULL}, {"VQ", A_VA+16, AF_ODARK, NULL}, {"VR", A_VA+17, AF_ODARK, NULL}, {"VS", A_VA+18, AF_ODARK, NULL}, {"VT", A_VA+19, AF_ODARK, NULL}, {"VU", A_VA+20, AF_ODARK, NULL}, {"VV", A_VA+21, AF_ODARK, NULL}, {"VW", A_VA+22, AF_ODARK, NULL}, {"VX", A_VA+23, AF_ODARK, NULL}, {"VY", A_VA+24, AF_ODARK, NULL}, {"VZ", A_VA+25, AF_ODARK, NULL}, {"Xyxxy", A_PASS, AF_DARK|AF_NOPROG|AF_NOCMD|AF_INTERNAL, NULL}, {NULL, 0, 0, NULL}}; #define DB_GET(x) return (db[thing].x) #define DB_SET(x,new) db[thing].x = (new) INLINE void s_Location(dbref thing, dbref new) { DB_SET(location, new); } INLINE void s_Zone(dbref thing, dbref new) { } INLINE void s_Contents(dbref thing, dbref new) { DB_SET(contents, new); } INLINE void s_Exits(dbref thing, dbref new) { DB_SET(exits, new); } INLINE void s_Next(dbref thing, dbref new) { DB_SET(next, new); } INLINE void s_Link(dbref thing, dbref new) { DB_SET(link, new); } INLINE void s_Owner(dbref thing, dbref new) { DB_SET(owner, new); } INLINE void s_Parent(dbref thing, dbref new) { DB_SET(parent, new); } INLINE void s_Pennies(dbref thing, int p) { DB_SET(penn, p); } INLINE void s_Flags(dbref thing, FLAG f) { DB_SET(flags, f); } INLINE dbref Location(dbref thing) { DB_GET(location); } INLINE dbref Zone(dbref thing) { return NOTHING; } INLINE dbref Contents(dbref thing) { DB_GET(contents); } INLINE dbref Exits(dbref thing) { DB_GET(exits); } INLINE dbref Next(dbref thing) { DB_GET(next); } INLINE dbref Link(dbref thing) { DB_GET(link); } INLINE dbref Owner(dbref thing) { DB_GET(owner); } INLINE dbref Parent(dbref thing) { DB_GET(parent); } INLINE int Pennies(dbref thing) { DB_GET(penn); } INLINE FLAG Flags(dbref thing) { DB_GET(flags); } /* --------------------------------------------------------------------------- * check_forwardlist: Check a list of dbref numbers to forward to for AUDIBLE */ int ck_fwdlist(int key, dbref player, dbref thing, int anum, char *atext) { #ifndef STANDALONE dbref target; char *tp, *bp, *dp; if (atext && *atext) { tp = bp = alloc_lbuf("ck_fwdlist"); strcpy(tp, atext); do { dp = parse_to(&bp, ' ', 0); if ((*dp++ == '#') && isdigit(*dp)) { target = atoi(dp); if (!Good_obj(target) || (!controls(player, target) && !((Flags(target) & LINK_OK) && (could_doit(player, target, A_LLINK))))) { notify(player, tprintf("Cannot forward to #%d: Permission denied.", target)); free_lbuf(tp); return 0; } } } while (bp); free_lbuf(tp); } #endif return 1; } /* --------------------------------------------------------------------------- * Name, s_Name: Get or set an object's name. */ INLINE char *Name(dbref thing) { dbref aowner; int aflags; #ifndef ATR_NAME return (db[thing].name); #else static char temp[LBUF_SIZE]; return (atr_get_str(temp, thing, A_NAME, &aowner, &aflags)); #endif /* ATR_NAME */ } INLINE void s_Name(dbref thing, const char *s) { #ifndef ATR_NAME set_string(&db[thing].name, s); #else atr_add_raw(thing, A_NAME, (char *)s); #endif /* ATR_NAME */ } void s_Pass(dbref thing, const char *s) { atr_add_raw(thing, A_PASS, (char *)s); } #ifndef STANDALONE /* --------------------------------------------------------------------------- * do_attrib: Manage user-named attributes. */ extern NAMETAB attraccess_nametab[]; void do_attribute (dbref player, dbref cause, int key, char *aname, char *value) { int success, negate, f; char *buff, *sp, *p, *q; VATTR *va; ATTR *va2; /* Look up the user-named attribute we want to play with */ buff = alloc_sbuf("do_attribute"); for (p=buff,q=aname; *q&&((p-buff)<(SBUF_SIZE-1)); p++,q++) *p=ToLower(*q); *p = '\0'; va = (VATTR *)hashfind(buff, &mudstate.vattr_name_htab); if (!va) { notify(player, "No such user-named attribute."); free_sbuf(buff); return; } switch (key) { case ATTRIB_ACCESS: /* Modify access to user-named attribute */ for (sp=value; *sp; sp++) *sp=ToLower(*sp); sp = strtok(value, " "); success = 0; while (sp != NULL) { /* Check for negation */ negate = 0; if (*sp == '!') { negate = 1; sp++; } /* Set or clear the appropriate bit */ f = search_nametab(player, attraccess_nametab, sp); if (f != -1) { success = 1; if (negate) va->flags &= ~f; else va->flags |= f; } else { notify(player, tprintf("Unknown permission: %s.", sp)); } /* Get the next token */ sp = strtok(NULL, " "); } if (success && !Quiet(player)) notify(player, "Attribute access changed."); break; case ATTRIB_RENAME: /* Make sure the new name doesn't already exist */ va2 = atr_str(value); if (va2) { notify(player, "An attribute with that name already exists."); return; } /* Get rid of the old entry in the name table */ for (p=buff,q=va->name; *q&&((p-buff)<(SBUF_SIZE-1)); p++,q++) *p=ToLower(*q); *p = '\0'; hashdelete(buff, &mudstate.vattr_name_htab); /* Add the new entry to the name table */ for (p=buff,q=value; *q&&((p-buff)<(SBUF_SIZE-1)); p++,q++) *p=ToLower(*q); *p = '\0'; hashadd(buff, (int *)va, &mudstate.vattr_name_htab); /* Replace the name in the entry itself */ XFREE (va->name, "do_attribute.rename"); va->name = strsave(value); if (strlen(va->name) >= SBUF_SIZE) va->name[SBUF_SIZE-1] = '\0'; notify(player, "Attribute renamed."); break; case ATTRIB_DELETE: /* Remove the attribute */ hashdelete (buff, &mudstate.vattr_name_htab); nhashdelete (va->number, &mudstate.vattr_num_htab); free_vattr (va->number); XFREE (va->name, "do_attribute.delete"); va->name = NULL; va->flags = AF_DELETED; notify(player, "Attribute deleted."); break; } free_sbuf(buff); return; } /* --------------------------------------------------------------------------- * do_fixdb: Directly edit database fields */ void do_fixdb (dbref player, dbref cause, int key, char *arg1, char *arg2) { dbref thing, res; init_match(player, arg1, NOTYPE); match_everything(); thing = noisy_match_result(); if (thing == NOTHING) return; res = NOTHING; switch (key) { case FIXDB_OWNER: case FIXDB_LOC: case FIXDB_CON: case FIXDB_EXITS: case FIXDB_NEXT: init_match(player, arg2, NOTYPE); match_everything(); res = noisy_match_result(); break; case FIXDB_PENNIES: res = atoi(arg2); break; } switch (key) { case FIXDB_OWNER: s_Owner(thing, res); if (!Quiet(player)) notify(player, tprintf("Owner set to #%d", res)); break; case FIXDB_LOC: s_Location(thing, res); if (!Quiet(player)) notify(player, tprintf("Location set to #%d", res)); break; case FIXDB_CON: s_Contents(thing, res); if (!Quiet(player)) notify(player, tprintf("Contents set to #%d", res)); break; case FIXDB_EXITS: s_Exits(thing, res); if (!Quiet(player)) notify(player, tprintf("Exits set to #%d", res)); break; case FIXDB_NEXT: s_Next(thing, res); if (!Quiet(player)) notify(player, tprintf("Next set to #%d", res)); break; case FIXDB_PENNIES: s_Pennies(thing, res); if (!Quiet(player)) notify(player, tprintf("Pennies set to %d", res)); break; case FIXDB_NAME: if (Typeof(thing) == TYPE_PLAYER) { if (!ok_player_name(arg2)) { notify(player, "That's not a good name for a player."); return; } if (lookup_player(NOTHING, arg2, 0) != NOTHING) { notify(player, "That name is already in use."); return; } STARTLOG(LOG_SECURITY,"SEC","CNAME") log_name(thing), log_text((char *)" renamed to "); log_text(arg2); ENDLOG if (Suspect(player)) { raw_broadcast(WIZARD, "[Suspect] %s renamed to %s", Name(thing), arg2); } delete_player_name(thing, Name(thing)); s_Name(thing, arg2); add_player_name(thing, arg2); } else { if (!ok_name(arg2)) { notify(player, "Warning: That is not a reasonable name."); } s_Name(thing, arg2); } if (!Quiet(player)) notify(player, tprintf("Name set to %s", arg2)); break; } } /* --------------------------------------------------------------------------- * init_attrtab: Initialize the attribute hash tables. */ void init_attrtab() { ATTR *a; char *buff, *p, *q; nhashinit(&mudstate.attr_num_htab, 47); hashinit(&mudstate.attr_name_htab, 47); nhashinit(&mudstate.vattr_num_htab, 1009); hashinit(&mudstate.vattr_name_htab, 1009); buff = alloc_sbuf("init_attrtab"); for (a=attr; a->number; a++) { nhashadd(a->number, (int *)a, &mudstate.attr_num_htab); for (p=buff,q=(char *)a->name; *q; p++,q++) *p=ToLower(*q); *p = '\0'; hashadd(buff, (int *)a, &mudstate.attr_name_htab); } free_sbuf(buff); } /* --------------------------------------------------------------------------- * atr_str: Look up an attribute by name. */ ATTR *atr_str(char *s) { char *buff, *p, *q; ATTR *a; VATTR *va; static ATTR tattr; /* Convert the buffer name to lowercase */ buff = alloc_sbuf("atr_str"); for (p=buff,q=s; *q&&((p-buff)<(SBUF_SIZE-1)); p++,q++) *p=ToLower(*q); *p = '\0'; /* Look for a predefined attribute */ a = (ATTR *)hashfind(buff, &mudstate.attr_name_htab); if (a != NULL) { free_sbuf(buff); return a; } /* Nope, look for a user attribute */ va = (VATTR *)hashfind(buff, &mudstate.vattr_name_htab); free_sbuf(buff); /* If we got one, load tattr and return a pointer to it. */ if (va != NULL) { tattr.name = va->name; tattr.number = va->number; tattr.flags = va->flags; tattr.check = NULL; return &tattr; } /* All failed, return NULL */ return NULL; } /* --------------------------------------------------------------------------- * atr_num: Look up an attribute by number. */ ATTR *atr_num(int anum) { ATTR *a; VATTR *va; static ATTR tattr; /* Look for a predefined attribute */ a = (ATTR *)nhashfind(anum, &mudstate.attr_num_htab); if (a != NULL) return a; /* Nope, look for a user-defined attribute */ va = (VATTR *)nhashfind(anum, &mudstate.vattr_num_htab); if (va != NULL) { tattr.name = va->name; tattr.number = va->number; tattr.flags = va->flags; tattr.check = NULL; return &tattr; } /* All failed, return NULL */ return NULL; } #else /* STANDALONE */ /* We don't have the hash tables, do it by hand */ /* --------------------------------------------------------------------------- * atr_str: Look up an attribute by name. */ ATTR *atr_str(char *s) { ATTR *ap; VATTR *va; static ATTR tattr; /* Check for an exact match on a predefined attribute */ for (ap=attr; ap->name; ap++) { if (!string_compare(ap->name, s)) return ap; } /* Check for an exact match on a user-named attribute */ for (va=mudstate.user_attrs; va; va=va->next) { if (string_compare(va->name, s)) continue; /* Got it */ tattr.name = va->name; tattr.number = va->number; tattr.flags = AF_ODARK; tattr.check = NULL; return &tattr; } /* No exact match, try for a prefix match on predefined attribs. * Check for both longer versions and shorter versions. */ for (ap=attr; ap->name; ap++) { if (string_prefix(s, ap->name)) return ap; if (string_prefix(ap->name, s)) return ap; } return NULL; } /* --------------------------------------------------------------------------- * atr_num: Look up an attribute by number. */ ATTR *atr_num(int anum) { ATTR *ap; VATTR *va; static ATTR tattr; for (ap=attr; ap->name; ap++) if (ap->number == anum) return ap; for (va=mudstate.user_attrs; va; va=va->next) if (va->number == anum) { tattr.name = va->name; tattr.number = va->number; tattr.flags = AF_ODARK; tattr.check = NULL; return &tattr; } return NULL; } #endif /* STANDALONE */ /* --------------------------------------------------------------------------- * mkattr: Lookup attribute by name, creating if needed. */ int mkattr (char *buff) { ATTR *ap; VATTR *va; if (!(ap = atr_str(buff))) { /* Unknown attr, create a new one */ va = alloc_vattr(buff, mudconf.vattr_flags); if (!va || !(va->number)) return -1; return va->number; } if (!(ap->number)) return -1; return ap->number; } /* --------------------------------------------------------------------------- * al_decode: Fetch an attribute number from an alist. */ static int al_decode (char **app) { int atrnum = 0, anum, atrshft = 0; char *ap; ap = *app; for (;;) { anum = ((*ap) & 0x7f); if (atrshft > 0) atrnum += (anum << atrshft); else atrnum = anum; if (!(*ap++ & 0x80)) { *app = ap; return atrnum; } atrshft += 7; } return 0; } /* --------------------------------------------------------------------------- * al_code: Store an attribute number in an alist. */ static void al_code (char **app, int atrnum) { char *ap; ap = *app; for (;;) { *ap = atrnum & 0x7f; atrnum = atrnum >> 7; if (!atrnum) { *app = ++ap; return; } *ap++ |= 0x80; } } /* --------------------------------------------------------------------------- * Commer: check if an object has any $-commands in its attributes. */ int Commer(dbref thing) { char *s, *as, c; int attr, aflags; dbref aowner; ATTR *ap; atr_push(); for (attr=atr_head(thing,&as); attr; attr=atr_next(&as)) { ap = atr_num(attr); if (!ap || (ap->flags & AF_NOPROG)) continue; s = atr_get(thing, attr, &aowner, &aflags); c = *s; free_lbuf(s); if ((c == '$') && !(aflags & AF_NOPROG)) { atr_pop(); return 1; } } atr_pop(); return 0; } #ifdef ATR_NAME char *set_string(char **ptr, char *new) { /* if pointer not null unalloc it */ if (*ptr) XFREE(*ptr, "set_string"); if (!new) return (*ptr = NULL); /* Check with GAC about this */ /* if (!new || !*new) return(*ptr=NULL); */ *ptr = (char *) XMALLOC(strlen(new) + 1, "set_string"); strcpy(*ptr, new); return (*ptr); } #endif /* ATR_NAME */ /* routines to handle object attribute lists */ /* --------------------------------------------------------------------------- * al_size, al_fetch, al_store, al_add, al_delete: Manipulate attribute lists */ /* al_extend: Get more space for attributes, if needed */ void al_extend (char **buffer, int *bufsiz, int len, int copy) { char *tbuff; if (len > *bufsiz) { *bufsiz = len + ATR_BUF_CHUNK; tbuff = XMALLOC(*bufsiz, "al_extend"); if (*buffer) { if (copy) bcopy(*buffer, tbuff, len); XFREE(*buffer, "al_extend"); } *buffer = tbuff; } } /* al_size: Return length of attribute list in chars */ int al_size (char *astr) { if (!astr) return 0; return (strlen(astr) + 1); } /* al_store: Write modified attribute list */ void al_store (void) { if (mudstate.mod_al_id != NOTHING) { if (mudstate.mod_alist && *mudstate.mod_alist) { atr_add_raw(mudstate.mod_al_id, A_LIST, mudstate.mod_alist); } else { atr_clr(mudstate.mod_al_id, A_LIST); } } mudstate.mod_al_id = NOTHING; } /* al_fetch: Load attribute list */ char *al_fetch (dbref thing) { char *astr; int len; /* We only need fetch if we change things */ if (mudstate.mod_al_id == thing) return mudstate.mod_alist; /* Save old list, then fetch and set up the attribute list */ al_store(); astr = atr_get_raw(thing, A_LIST); if (astr) { len = al_size(astr); al_extend(&mudstate.mod_alist, &mudstate.mod_size, len, 0); bcopy(astr, mudstate.mod_alist, len); } else { al_extend(&mudstate.mod_alist, &mudstate.mod_size, 1, 0); *mudstate.mod_alist = '\0'; } mudstate.mod_al_id = thing; return mudstate.mod_alist; } /* al_add: Add an attribute to an attribute list */ void al_add (dbref thing, int attrnum) { char *abuf, *cp; int anum; /* If trying to modify List attrib, return. Otherwise, get the * attribute list. */ if (attrnum == A_LIST) return; abuf = al_fetch(thing); /* See if attr is in the list. If so, exit (need not do anything) */ cp = abuf; while (*cp) { anum = al_decode(&cp); if (anum == attrnum) return; } /* Nope, extend it */ al_extend(&mudstate.mod_alist, &mudstate.mod_size, (cp-abuf+ATR_BUF_INCR), 1); if (mudstate.mod_alist != abuf) { /* extend returned different buffer, re-find the end */ abuf = mudstate.mod_alist; for (cp=abuf; *cp; anum=al_decode(&cp)) ; } /* Add the new attribute on to the end */ al_code(&cp, attrnum); *cp = '\0'; return; } /* al_delete: Remove an attribute from an attribute list */ void al_delete (dbref thing, int attrnum) { int anum; char *abuf, *cp, *dp; /* If trying to modify List attrib, return. Otherwise, get the * attribute list. */ if (attrnum == A_LIST) return; abuf = al_fetch(thing); if (!abuf) return; cp = abuf; while (*cp) { dp = cp; anum = al_decode(&cp); if (anum == attrnum) { while (*cp) { anum = al_decode(&cp); al_code(&dp, anum); } *dp = '\0'; return; } } return; } INLINE static void makekey (dbref thing, dbref atr, char *buff) { char *bp; int i; bp = buff; for (i=0; thing && i<6; i++) { *bp++ = (thing & 0x3f) + '0'; thing = thing >> 6; } *bp++ = '-'; for (i=0; atr && i<6; i++) { *bp++ = (atr & 0x3f) + '0'; atr = atr >> 6; } *bp = '\0'; } /* --------------------------------------------------------------------------- * atr_clr: clear an attribute in the list. */ void atr_clr(dbref thing, int atr) { DBT key; char okey[KEY_SIZE]; makekey(thing, atr, okey); key.data = okey; key.size = strlen(okey) + 1; DELETE(key); al_delete(thing, atr); } /* --------------------------------------------------------------------------- * al_destroy: wipe out an object's attribute list. */ void al_destroy (dbref thing) { if (mudstate.mod_al_id == thing) al_store(); /* remove from cache */ atr_clr(thing, A_LIST); } /* --------------------------------------------------------------------------- * atr_encode: Encode an attribute string. */ static char *atr_encode (char *iattr, dbref thing, dbref owner, int flags) { /* Compress the sttribute string */ iattr = (char *) compress(iattr); /* If using the default owner and flags (almost all attributes will), * just store the string. */ if (((owner == Owner(thing)) || (owner == NOTHING)) && !flags) return iattr; /* Encode owner and flags into the attribute text */ if (owner == NOTHING) owner = Owner(thing); return tprintf("%c%d:%d:%s", ATR_INFO_CHAR, owner, flags, iattr); } /* --------------------------------------------------------------------------- * atr_decode: Decode an attribute string. */ static void atr_decode (char *iattr, char *oattr, dbref thing, dbref *owner, int *flags) { char *cp; int neg; /* See if the first char of the attribute is the special character */ if (*iattr == ATR_INFO_CHAR) { /* It is, crack the attr apart */ cp = &iattr[1]; /* Get the attribute owner */ *owner = 0; neg = 0; if (*cp == '-') { neg = 1; cp++; } while (isdigit(*cp)) { *owner = (*owner * 10) + (*cp++ - '0'); } if (neg) *owner = 0 - *owner; /* If delimiter is not ':', just return attribute */ if (*cp++ != ':') { *owner = Owner(thing); *flags = 0; if (oattr) uncompress_str(oattr, iattr); return; } /* Get the attribute flags */ *flags = 0; while (isdigit(*cp)) { *flags = (*flags * 10) + (*cp++ - '0'); } /* If delimiter is not ':', just return attribute */ if (*cp++ != ':') { *owner = Owner(thing); *flags = 0; if (oattr) uncompress_str(oattr, iattr); } /* Get the attribute text */ if (oattr) uncompress_str(oattr, cp); if (*owner == NOTHING) *owner = Owner(thing); } else { /* Not the special character, return normal info */ *owner = Owner(thing); *flags = 0; if (oattr) uncompress_str(oattr, iattr); } } /* --------------------------------------------------------------------------- * atr_add_raw, atr_add: add attribute of type atr to list */ void atr_add_raw(dbref thing, int atr, char *buff) { DBT key, con; char okey[KEY_SIZE]; if (!buff || !*buff) { atr_clr(thing, atr); return; } makekey(thing, atr, okey); key.data = okey; key.size = strlen(okey) + 1; con.data = buff; con.size = strlen(buff) + 1; STORE(key, con); al_add(thing, atr); if (atr == A_STARTUP) /* Set STARTUP flag */ s_Flags(thing, Flags(thing) | STARTUP); } void atr_add(dbref thing, int atr, char *buff, dbref owner, int flags) { char *tbuff; if (!buff || !*buff) { atr_clr(thing, atr); if (atr == A_STARTUP) /* Reset STARTUP flag */ s_Flags(thing, Flags(thing) & ~STARTUP); } else { tbuff = atr_encode(buff, thing, owner, flags); atr_add_raw(thing, atr, tbuff); } } void atr_set_owner (dbref thing, int atr, dbref owner) { dbref aowner; int aflags; char *buff; buff = atr_get(thing, atr, &aowner, &aflags); atr_add(thing, atr, buff, owner, aflags); free_lbuf(buff); } void atr_set_flags (dbref thing, int atr, dbref flags) { dbref aowner; int aflags; char *buff; buff = atr_get(thing, atr, &aowner, &aflags); atr_add(thing, atr, buff, aowner, flags); free_lbuf(buff); } /* --------------------------------------------------------------------------- * atr_get_raw, atr_get_str, atr_get: Get an attribute from the database. */ char *atr_get_raw(dbref thing, int atr) { DBT key, con; char okey[KEY_SIZE]; makekey(thing, atr, okey); key.data = okey; key.size = strlen(okey) + 1; if (!FETCH(key, con)) { return con.data; } else { return NULL; } } char *atr_get_str(char *s, dbref thing, int atr, dbref *owner, int *flags) { char *buff; buff = atr_get_raw(thing, atr); if (!buff) { *owner = Owner(thing); *flags = 0; *s = '\0'; } else { atr_decode(buff, s, thing, owner, flags); } return s; } char *atr_get(dbref thing, int atr, dbref *owner, int *flags) { char *buff; buff = alloc_lbuf("atr_get"); return atr_get_str(buff, thing, atr, owner, flags); } int atr_get_info (dbref thing, int atr, dbref *owner, int *flags) { char *buff; buff = atr_get_raw(thing, atr); if (!buff) { *owner = Owner(thing); *flags = 0; return 0; } atr_decode(buff, NULL, thing, owner, flags); return 1; } #ifndef STANDALONE char *atr_pget_str(char *s, dbref thing, int atr, dbref *owner, int *flags) { char *buff; dbref parent; int lev; buff = atr_get_raw(thing, atr); if (!buff) { for (lev=0, parent=Parent(thing); (Good_obj(parent) && (lev < mudconf.parent_nest_lim) && !buff); parent=Parent(parent), lev++) { buff = atr_get_raw(parent, atr); } } if (!buff) { *owner = Owner(thing); *flags = 0; *s = '\0'; } else { atr_decode(buff, s, thing, owner, flags); } return s; } char *atr_pget(dbref thing, int atr, dbref *owner, int *flags) { char *buff; buff = alloc_lbuf("atr_get"); return atr_pget_str(buff, thing, atr, owner, flags); } int atr_pget_info (dbref thing, int atr, dbref *owner, int *flags) { char *buff; dbref parent; int lev; buff = atr_get_raw(thing, atr); if (!buff) { for (lev=0, parent=Parent(thing); (Good_obj(parent) && (lev < mudconf.parent_nest_lim) && !buff); parent=Parent(parent), lev++) { buff = atr_get_raw(parent, atr); } } if (!buff) { *owner = Owner(thing); *flags = 0; return 0; } atr_decode(buff, NULL, thing, owner, flags); return 1; } #endif STANDALONE /* --------------------------------------------------------------------------- * atr_free: Return all attributes of an object. */ void atr_free(dbref thing) { int attr; char *as; for (attr=atr_head(thing,&as); attr; attr=atr_next(&as)) { atr_clr(thing, attr); } al_destroy(thing); /* Just to be on the safe side */ } /* garbage collect an attribute list */ void atr_collect(dbref thing) { /* Nada. gdbm takes care of us. I hope ;-) */ } /* --------------------------------------------------------------------------- * atr_cpy: Copy all attributes from one object to another. */ void atr_cpy(dbref dest, dbref source) { int attr, aflags; dbref owner, aowner; char *as, *buf; owner = Owner(dest); for (attr=atr_head(source,&as); attr; attr=atr_next(&as)) { buf = atr_get(source, attr, &aowner, &aflags); if (!(aflags & AF_LOCK)) aowner = owner; /* chg owner */ atr_add(dest, attr, buf, aowner, aflags); free_lbuf(buf); } } /* --------------------------------------------------------------------------- * atr_chown: Change the ownership of the attributes of an object to the * current owner if they are not locked. */ void atr_chown(dbref obj) { int attr, aflags; dbref owner, aowner; char *as, *buf; owner = Owner(obj); for (attr=atr_head(obj,&as); attr; attr=atr_next(&as)) { buf = atr_get(obj, attr, &aowner, &aflags); if ((aowner != owner) && !(aflags & AF_LOCK)) atr_add(obj, attr, buf, owner, aflags); free_lbuf(buf); } } /* --------------------------------------------------------------------------- * atr_next: Return next attribute in attribute list. */ int atr_next(char **attrp) { if (!*attrp || !**attrp) { return 0; } else { return al_decode(attrp); } } /* --------------------------------------------------------------------------- * atr_push, atr_pop: Push and pop attr lists. */ void atr_push(void) { ALIST *new_alist; new_alist = (ALIST *)alloc_sbuf("atr_push"); new_alist->data = mudstate.iter_alist.data; new_alist->len = mudstate.iter_alist.len; new_alist->next = mudstate.iter_alist.next; mudstate.iter_alist.data = NULL; mudstate.iter_alist.len = 0; mudstate.iter_alist.next = new_alist; return; } void atr_pop(void) { ALIST *old_alist; char *cp; old_alist = mudstate.iter_alist.next; if (mudstate.iter_alist.data) { free(mudstate.iter_alist.data); } if (old_alist) { mudstate.iter_alist.data = old_alist->data; mudstate.iter_alist.len = old_alist->len; mudstate.iter_alist.next = old_alist->next; cp = (char *)old_alist; free_sbuf(cp); } else { mudstate.iter_alist.data = NULL; mudstate.iter_alist.len = 0; mudstate.iter_alist.next = NULL; } return; } /* --------------------------------------------------------------------------- * atr_head: Returns the head of the attr list for object 'thing' */ int atr_head(dbref thing, char **attrp) { char *astr; int alen; /* Get attribute list. Save a read if it is in the modify atr list */ if (thing == mudstate.mod_al_id) { astr = mudstate.mod_alist; } else { astr = atr_get_raw(thing, A_LIST); } alen = al_size(astr); /* If no list, return nothing */ if (!alen) return 0; /* Set up the list and return the first entry */ al_extend(&mudstate.iter_alist.data, &mudstate.iter_alist.len, alen, 0); bcopy(astr, mudstate.iter_alist.data, alen); *attrp = mudstate.iter_alist.data; return atr_next(attrp); } /* --------------------------------------------------------------------------- * define_vattr: Define a new user-named attribute. */ VATTR *define_vattr (char *aname, int anum, int aflags) { VATTR *va; char *p, *q, *buf; #ifdef STANDALONE char *s1, *n1; #endif if (!ok_attr_name(aname)) return NULL; buf = alloc_sbuf("define_vattr"); for (p=buf,q=aname; *q&&(((p-buf))<(SBUF_SIZE-1)); p++,q++) *p=ToLower(*q); *p = '\0'; /* If already in the hash table, disregard */ #ifndef STANDALONE if (hashfind(buf, &mudstate.vattr_name_htab)) { free_sbuf(buf); return NULL; } #else for (va=mudstate.user_attrs; va; va=va->next) { for (s1=buf,n1=va->name; *s1&&*n1; s1++,n1++) { if (ToLower(*s1) != ToLower(*n1)) break; } if (*s1 || *n1) continue; free_sbuf(buf); return NULL; } #endif /* Set up a vattr structure and link it in */ va = (VATTR *)XMALLOC(sizeof(VATTR), "define_vattr"); va->name = strsave(aname); va->number = anum; va->flags = aflags; va->refcount = 0; if (strlen(va->name) >= SBUF_SIZE) va->name[SBUF_SIZE-1] = '\0'; va->next = mudstate.user_attrs; mudstate.user_attrs = va; #ifndef STANDALONE hashadd(buf, (int *)va, &mudstate.vattr_name_htab); nhashadd(anum, (int *)va, &mudstate.vattr_num_htab); #endif free_sbuf(buf); return va; } /* --------------------------------------------------------------------------- * alloc_vattr: Allocate a new user-defined attribute. */ VATTR *alloc_vattr (char *aname, int aflags) { VATTR *va; int anum; /* Make sure the attribute name is valid, reject it if not. */ if (!ok_attr_name(aname)) return NULL; /* Get attr numbers until we get one such that the low-order 7 bits are * not zero. If we ever had such an attribute it would truncate the * attribute list at that point (because strlen would see it as the * end-of-string marker (7 zero bits + a zero 'more data' bit) */ do { if (mudstate.user_attr_free == NULL) { anum = mudstate.attr_next++; } else { va = mudstate.user_attr_free; mudstate.user_attr_free = va->next; anum = va->number; XFREE(va, "alloc_vattr"); } } while (!(anum & 0x7f)); va = define_vattr(aname, anum, aflags); if (!va) free_vattr(anum); return va; } /* --------------------------------------------------------------------------- * free_vattr: Add an attribute number to the attr freelist. */ void free_vattr (int anum) { VATTR *va; if (anum == (mudstate.attr_next - 1)) { mudstate.attr_next--; } else { va = (VATTR *)XMALLOC(sizeof(VATTR), "free_vattr"); va->name = NULL; va->number = anum; va->next = mudstate.user_attr_free; mudstate.user_attr_free = va; va->refcount = 0; } } /* --------------------------------------------------------------------------- * db_grow: Extend the struct database. */ #define SIZE_HACK 1 /* So mistaken refs to #-1 won't die. */ void db_grow(dbref newtop) { int newsize, marksize, delta, i; MARKBUF *newmarkbuf; OBJ *newdb; char *cp; #ifndef STANDALONE delta = mudconf.init_size; #else delta = 1000; #endif /* Determine what to do based on requested size, current top and * size. Make sure we grow in reasonable-sized chunks to prevent * frequent reallocations of the db array. */ if (newtop <= mudstate.db_top) { return; } else if (newtop <= mudstate.db_size) { for (i=mudstate.db_top; i<newtop; i++) s_Flags(i, TYPE_THING|GOING); mudstate.db_top = newtop; return; } else if (newtop <= mudstate.db_size + delta) { newsize = mudstate.db_size + delta; } else { newsize = newtop; } if (newsize < mudstate.min_size) newsize = mudstate.min_size + delta;; /* Allocate space for the new db array */ newdb = (OBJ *)XMALLOC((newsize + SIZE_HACK) * sizeof(OBJ), "db_grow"); if (!newdb) { LOG_SIMPLE(LOG_ALWAYS, "ALC", "DB", tprintf("Could not allocate space for %d item struct database.", newsize)); abort(); } if (db) { /* An old struct database exists. Copy it to the new buffer */ db -= SIZE_HACK; memcpy(newdb, db, (mudstate.db_top + SIZE_HACK) * sizeof(OBJ)); cp = (char *)db; XFREE(cp, "db_grow"); } else { /* Creating a brand new struct database. Fill in the * 'reserved' area in case it gets referenced. */ db = newdb; for (i=0; i<SIZE_HACK; i++) { s_Owner(i, GOD); s_Flags(i, (TYPE_THING | GOING)); s_Location(i, NOTHING); s_Contents(i, NOTHING); s_Exits(i, NOTHING); s_Link(i, NOTHING); s_Next(i, NOTHING); s_Pennies(i, NOTHING); s_Zone(i, NOTHING); s_Parent(i, NOTHING); s_Pennies(i, 0); } } db = newdb + SIZE_HACK; newdb = NULL; for (i=mudstate.db_top; i<newtop; i++) s_Flags(i, TYPE_THING|GOING); mudstate.db_top = newtop; mudstate.db_size = newsize; /* Grow the db mark buffer */ marksize = (newsize+7)>>3; newmarkbuf = (MARKBUF *)XMALLOC(marksize, "db_grow"); memset(newmarkbuf, '\0', marksize); if (mudstate.markbits) { marksize = (mudstate.db_top+7)>>3; memcpy(newmarkbuf, mudstate.markbits, marksize); cp = (char *)mudstate.markbits; XFREE(cp, "db_grow"); } mudstate.markbits = newmarkbuf; } void db_free(void) { char *cp; if (db != NULL) { db -= SIZE_HACK; cp = (char *)db; XFREE(cp, "db_grow"); db = NULL; } mudstate.db_top = 0; mudstate.db_size = 0; mudstate.freelist = NOTHING; } #ifndef STANDALONE void db_make_minimal(void) { dbref obj; db_free(); db_grow(1); s_Name(0, "Limbo"); s_Flags(0, TYPE_ROOM); s_Location(0, NOTHING); s_Exits(0, NOTHING); s_Link(0, NOTHING); s_Parent(0, NOTHING); s_Zone(0, NOTHING); s_Pennies(0, 1); /* should be #1 */ load_player_names(); obj = create_player((char *)"Wizard", (char *)"potrzebie", NOTHING, 0); s_Flags(obj, Flags(obj) | WIZARD); s_Pennies(obj, 1000); /* Manually link to Limbo, just in case */ s_Location(obj, 0); s_Next(obj, NOTHING); s_Contents(0, obj); s_Link(obj, 0); } #endif dbref parse_dbref(const char *s) { const char *p; long x; x = atol(s); if (x > 0) { return x; } else if (x == 0) { /* check for 0 */ for (p = s; *p; p++) { if (*p == '0') return 0; if (!isspace(*p)) break; } } /* else x < 0 or s != 0 */ return NOTHING; } void putref(FILE * f, dbref ref) { fprintf(f, "%d\n", ref); } void putstring(FILE * f, const char *s) { if (s) { fputs(s, f); } putc('\n', f); } const char *getstring_noalloc(FILE * f) { static char buf[LBUF_SIZE]; char *p; int c, lastc; p = buf; c = '\0'; for (;;) { lastc = c; c = fgetc(f); /* If EOF or null, return */ if (!c || (c == EOF)) { *p = '\0'; return buf; } /* If a newline, return if prior char is not a cr. Otherwise * keep on truckin' */ if ((c == '\n') && (lastc != '\r')) { *p = '\0'; return buf; } safe_chr(c, buf, &p); } } dbref getref(FILE * f) { return(atol(getstring_noalloc(f))); } void free_boolexp(struct boolexp * b) { if (b != TRUE_BOOLEXP) { switch (b->type) { case BOOLEXP_AND: case BOOLEXP_OR: free_boolexp(b->sub1); free_boolexp(b->sub2); free_bool(b); break; case BOOLEXP_NOT: case BOOLEXP_CARRY: case BOOLEXP_IS: case BOOLEXP_OWNER: case BOOLEXP_INDIR: free_boolexp(b->sub1); free_bool(b); break; case BOOLEXP_CONST: free_bool(b); break; case BOOLEXP_ATR: free((char *)b->sub1); free_bool(b); break; } } } struct boolexp *dup_bool(struct boolexp * b) { struct boolexp *r; if (b == TRUE_BOOLEXP) return (TRUE_BOOLEXP); r = alloc_bool("dup_bool"); switch (r->type = b->type) { case BOOLEXP_AND: case BOOLEXP_OR: r->sub2 = dup_bool(b->sub2); case BOOLEXP_NOT: case BOOLEXP_CARRY: case BOOLEXP_IS: case BOOLEXP_OWNER: case BOOLEXP_INDIR: r->sub1 = dup_bool(b->sub1); case BOOLEXP_CONST: r->thing = b->thing; break; case BOOLEXP_ATR: r->thing = b->thing; r->sub1 = (struct boolexp *)strsave((char *)b->sub1); break; default: fprintf(stderr, "bad bool type!!\n"); return (TRUE_BOOLEXP); } return (r); } void clone_object(dbref a, dbref b) { memcpy(&db[a], &db[b], sizeof(struct object)); } int init_gdbm_db(char *gdbmfile) { HASHINFO info; info.bsize = 4096; /* Setting this to your blocksize is pretty good. */ #ifndef STANDALONE info.cachesize = mudconf.gdbm_cache_size * 1024; #else info.cachesize = 1024 * 1024 * 4; /* 4 megabytes */ #endif info.ffactor = 64; info.hash = NULL; /* use default hash function. */ info.lorder = 0; /* use system byteorder. */ info.nelem = 40000; #ifdef STANDALONE fprintf(stderr, "Opening %s\n", gdbmfile); #endif dbp = hash_open(gdbmfile, O_CREAT | O_RDWR, 0600, &info); #ifdef STANDALONE fprintf(stderr, "Done opening %s.\n", gdbmfile); #endif if (!dbp) return (-1); #ifdef STANDALONE fprintf(stderr, "Done initializing.\n"); #else STARTLOG(LOG_ALWAYS,"INI","LOAD") log_text((char *)"Using gdbm file: "); log_text(gdbmfile); ENDLOG #endif db_free(); return (0); }