/* 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);
}