mud/fluffos-2.23-ds03/object.c
2020-09-06 05:43:07 -07:00

2196 lines
57 KiB
C

#include "std.h"
#include "lpc_incl.h"
#include "file_incl.h"
#include "otable.h"
#include "backend.h"
#include "comm.h"
#include "socket_efuns.h"
#include "call_out.h"
#include "port.h"
#include "file.h"
#include "hash.h"
#include "master.h"
#include "add_action.h"
#define too_deep_save_error() \
error("Mappings and/or arrays nested too deep (%d) for save_object\n",\
MAX_SAVE_SVALUE_DEPTH);
object_t *previous_ob;
int tot_alloc_object, tot_alloc_object_size;
char *save_mapping (mapping_t *m);
INLINE_STATIC int restore_array (char **str, svalue_t *);
INLINE_STATIC int restore_class (char **str, svalue_t *);
#ifdef F_SET_HIDE
int num_hidden = 0;
INLINE int
valid_hide (object_t * obj)
{
svalue_t *ret;
if (!obj) {
return 0;
}
push_object(obj);
ret = apply_master_ob(APPLY_VALID_HIDE, 1);
return (!IS_ZERO(ret));
}
#endif
int save_svalue_depth = 0, max_depth;
int *sizes = 0;
INLINE int svalue_save_size (svalue_t * v)
{
switch(v->type) {
case T_STRING:
{
register const char *cp = v->u.string;
char c;
int size = 0;
while ((c = *cp++)) {
if (c == '\\' || c == '"') size++;
size++;
}
return 3 + size;
}
case T_ARRAY:
{
svalue_t *sv = v->u.arr->item;
int i = v->u.arr->size, size = 0;
if (++save_svalue_depth > MAX_SAVE_SVALUE_DEPTH) {
save_svalue_depth = 0;
too_deep_save_error();
}
while (i--) size += svalue_save_size(sv++);
save_svalue_depth--;
return size + 5;
}
case T_CLASS:
{
svalue_t *sv = v->u.arr->item;
int i = v->u.arr->size, size = 0;
if (++save_svalue_depth > MAX_SAVE_SVALUE_DEPTH) {
save_svalue_depth = 0;
too_deep_save_error();
}
while (i--) size += svalue_save_size(sv++);
save_svalue_depth--;
return size + 5;
}
case T_MAPPING:
{
mapping_node_t **a = v->u.map->table, *elt;
int j = v->u.map->table_size, size = 0;
if (++save_svalue_depth > MAX_SAVE_SVALUE_DEPTH) {
save_svalue_depth = 0;
too_deep_save_error();
}
do {
for (elt = a[j]; elt; elt = elt->next) {
size += svalue_save_size(elt->values) +
svalue_save_size(elt->values+1);
}
} while (j--);
save_svalue_depth--;
return size + 5;
}
case T_NUMBER:
{
long res = v->u.number, len;
#if SIZEOF_LONG == 4
len = res < 0 ? (res = (-res) & 0x7fffffff,3) : 2;
#else
len = res < 0 ? (res = (-res) & 0x7fffffffffffffff,3) : 2;
#endif
while (res>9) {
res /= 10;
len++;
}
return len;
}
case T_REAL:
{
char buf[256];
sprintf(buf, "%f", v->u.real);
return (strlen(buf)+1);
}
default:
{
return 1;
}
}
}
INLINE void save_svalue (svalue_t * v, char ** buf)
{
switch(v->type) {
case T_STRING:
{
register char *cp = *buf;
const char *str = v->u.string;
char c;
*cp++ = '"';
while ((c = *str++)) {
if (c == '"' || c == '\\') {
*cp++ = '\\';
*cp++ = c;
}
else *cp++ = (c == '\n') ? '\r' : c;
}
*cp++ = '"';
*(*buf = cp) = '\0';
return;
}
case T_ARRAY:
{
int i = v->u.arr->size;
svalue_t *sv = v->u.arr->item;
*(*buf)++ = '(';
*(*buf)++ = '{';
while (i--) {
save_svalue(sv++, buf);
*(*buf)++ = ',';
}
*(*buf)++ = '}';
*(*buf)++ = ')';
*(*buf) = '\0';
return;
}
case T_CLASS:
{
int i = v->u.arr->size;
svalue_t *sv = v->u.arr->item;
*(*buf)++ = '(';
*(*buf)++ = '/'; /* Why yes, this *is* a kludge! */
while (i--) {
save_svalue(sv++, buf);
*(*buf)++ = ',';
}
*(*buf)++ = '/';
*(*buf)++ = ')';
*(*buf) = '\0';
return;
}
case T_NUMBER:
{
long res = v->u.number, fact;
int len = 1, neg = 0;
register char *cp;
if (res < 0) {
len++;
neg = 1;
#if SIZEOF_LONG == 4
res = (-res) & 0x7fffffff;
#else
res = (-res) & 0x7fffffffffffffff;
#endif
}
fact = res;
while (fact > 9) {
fact /= 10;
len++;
}
*(cp = (*buf += len)) = '\0';
do {
*--cp = res % 10 + '0';
res /= 10;
} while (res);
if (neg) *(cp-1) = '-';
return;
}
case T_REAL:
{
sprintf(*buf, "%f", v->u.real);
(*buf) += strlen(*buf);
return;
}
case T_MAPPING:
{
int j = v->u.map->table_size;
mapping_node_t **a = v->u.map->table, *elt;
*(*buf)++ = '(';
*(*buf)++ = '[';
do {
for (elt = a[j]; elt; elt = elt->next) {
save_svalue(elt->values, buf);
*(*buf)++ = ':';
save_svalue(elt->values + 1, buf);
*(*buf)++ = ',';
}
} while (j--);
*(*buf)++ = ']';
*(*buf)++ = ')';
*(*buf) = '\0';
return;
}
}
}
INLINE_STATIC int
restore_internal_size (const char ** str, int is_mapping, int depth)
{
register const char *cp = *str;
int size = 0;
char c, delim, toggle = 0;
delim = is_mapping ? ':' : ',';
while ((c = *cp++)) {
switch(c) {
case '"':
{
while ((c = *cp++) != '"')
if ((c == '\0') || (c == '\\' && !*cp++)) {
return 0;
}
if (*cp++ != delim) return 0;
size++;
break;
}
case '(':
{
if (*cp == '{') {
*str = ++cp;
if (!restore_internal_size(str, 0, save_svalue_depth++)) {
return 0;
}
}
else if (*cp == '[') {
*str = ++cp;
if (!restore_internal_size(str, 1, save_svalue_depth++)) { return 0;}
}
else if (*cp == '/') {
*str = ++cp;
if (!restore_internal_size(str, 0, save_svalue_depth++))
return 0;
} else { return 0;}
if (*(cp = *str) != delim) { return 0;}
cp++;
size++;
break;
}
case ']':
{
if (*cp++ == ')' && is_mapping) {
*str = cp;
if (!sizes) {
max_depth = 128;
while (max_depth <= depth) max_depth <<= 1;
sizes = CALLOCATE(max_depth, int, TAG_TEMPORARY,
"restore_internal_size");
}
else if (depth >= max_depth) {
while ((max_depth <<= 1) <= depth);
sizes = RESIZE(sizes, max_depth, int, TAG_TEMPORARY,
"restore_internal_size");
}
sizes[depth] = size;
return 1;
}
else { return 0; }
}
case '/':
case '}':
{
if (*cp++ == ')' && !is_mapping) {
*str = cp;
if (!sizes) {
max_depth = 128;
while (max_depth <= depth) max_depth <<= 1;
sizes = CALLOCATE(max_depth, int, TAG_TEMPORARY,
"restore_internal_size");
}
else if (depth >= max_depth) {
while ((max_depth <<= 1) <= depth);
sizes = RESIZE(sizes, max_depth, int, TAG_TEMPORARY,
"restore_internal_size");
}
sizes[depth] = size;
return 1;
}
else { return 0;}
}
case ':':
case ',':
{
if (c != delim) return 0;
size++;
break;
}
default:
{
if (!(cp = strchr(cp, delim))) return 0;
cp++;
size++;
}
}
if (is_mapping) delim = (toggle ^= 1) ? ',' : ':';
}
return 0;
}
INLINE_STATIC int
restore_size (const char ** str, int is_mapping)
{
register const char *cp = *str;
int size = 0;
char c, delim, toggle = 0;
delim = is_mapping ? ':' : ',';
while ((c = *cp++)) {
switch(c) {
case '"':
{
while ((c = *cp++) != '"')
if ((c == '\0') || (c == '\\' && !*cp++)) return 0;
if (*cp++ != delim) { return -1; }
size++;
break;
}
case '(':
{
if (*cp == '{') {
*str = ++cp;
if (!restore_internal_size(str, 0, save_svalue_depth++)) return -1;
}
else if (*cp == '[') {
*str = ++cp;
if (!restore_internal_size(str, 1, save_svalue_depth++)) return -1;
}
else if (*cp == '/') {
*str = ++cp;
if (!restore_internal_size(str, 0, save_svalue_depth++)) return -1;
} else { return -1; }
if (*(cp = *str) != delim) { return -1;}
cp++;
size++;
break;
}
case ']':
{
save_svalue_depth = 0;
if (*cp++ == ')' && is_mapping) {
*str = cp;
return size;
}
else { return -1;}
}
case '/':
case '}':
{
save_svalue_depth = 0;
if (*cp++ == ')' && !is_mapping) {
*str = cp;
return size;
}
else { return -1;}
}
case ':':
case ',':
{
if (c != delim) return -1;
size++;
break;
}
default:
{
if (!(cp = strchr(cp, delim))) { return -1;}
cp++;
size++;
}
}
if (is_mapping) delim = (toggle ^= 1) ? ',' : ':';
}
return -1;
}
INLINE_STATIC int
restore_interior_string (char ** val, svalue_t * sv)
{
register char *cp = *val;
char *start = cp, *newstr;
char c;
int len;
while ((c = *cp++) != '"') {
switch (c) {
case '\r':
{
*(cp-1) = '\n';
break;
}
case '\\':
{
char *news = cp - 1;
if ((*news++ = *cp++)) {
while ((c = *cp++) != '"') {
if (c == '\\') {
if (!(*news++ = *cp++)) return ROB_STRING_ERROR;
}
else {
if (c == '\r')
*news++ = '\n';
else *news++ = c;
}
}
if (c == '\0') return ROB_STRING_ERROR;
*news = '\0';
*val = cp;
newstr = new_string(len = (news - start),
"restore_string");
strcpy(newstr, start);
sv->u.string = newstr;
sv->type = T_STRING;
sv->subtype = STRING_MALLOC;
return 0;
}
else return ROB_STRING_ERROR;
}
case '\0':
{
return ROB_STRING_ERROR;
}
}
}
*val = cp;
*--cp = '\0';
len = cp - start;
newstr = new_string(len, "restore_string");
strcpy(newstr, start);
sv->u.string = newstr;
sv->type = T_STRING;
sv->subtype = STRING_MALLOC;
return 0;
}
static int parse_numeric (char ** cpp, unsigned char c, svalue_t * dest)
{
char *cp = *cpp;
long res, neg;
if (c == '-') {
neg = 1;
res = 0;
c = *cp++;
if (!isdigit(c))
return 0;
} else
neg = 0;
res = c - '0';
while ((c = *cp++) && isdigit(c)) {
res *= 10;
res += c - '0';
}
if (c == '.') {
float f1 = 0.0, f2 = 10.0;
c = *cp++;
if (!c) {
cp--;
c = '0';
}
if (!isdigit(c)) return 0;
do {
f1 += (c - '0')/f2;
f2 *= 10;
} while ((c = *cp++) && isdigit(c));
f1 += res;
if (c == 'e') {
int expo = 0;
if ((c = *cp++) == '+') {
while ((c = *cp++) && isdigit(c)) {
expo *= 10;
expo += (c - '0');
}
f1 *= pow(10.0, expo);
} else if (c == '-') {
while ((c = *cp++) && isdigit(c)) {
expo *= 10;
expo += (c - '0');
}
f1 *= pow(10.0, -expo);
} else
return 0;
}
dest->type = T_REAL;
dest->u.real = (neg ? -f1 : f1);
*cpp = cp;
return 1;
} else if (c == 'e') {
int expo = 0;
float f1;
if ((c = *cp++) == '+') {
while ((c = *cp++) && isdigit(c)) {
expo *= 10;
expo += (c - '0');
}
f1 = res * pow(10.0, expo);
} else if (c == '-') {
while ((c = *cp++) && isdigit(c)) {
expo *= 10;
expo += (c - '0');
}
f1 = res * pow(10.0, -expo);
} else
return 0;
dest->type = T_REAL;
dest->u.real = (neg ? -f1 : f1);
*cpp = cp;
return 1;
} else {
dest->type = T_NUMBER;
dest->u.number = (neg ? -res : res);
dest->subtype = 0;
*cpp = cp;
return 1;
}
}
INLINE_STATIC void add_map_stats (mapping_t * m, int count)
{
total_mapping_nodes += count;
total_mapping_size += count * sizeof(mapping_node_t);
#ifdef PACKAGE_MUDLIB_STATS
add_array_size(&m->stats, count << 1);
#endif
m->count = count;
}
static int
restore_mapping (char **str, svalue_t * sv)
{
int size, i, mask, count = 0;
unsigned long oi;
char c;
mapping_t *m;
svalue_t key, value;
mapping_node_t **a, *elt, *elt2;
char *cp = *str;
int err;
if (save_svalue_depth) size = sizes[save_svalue_depth-1];
else if ((size = restore_size((const char **)str, 1)) < 0) return 0;
if (!size) {
*str += 2;
sv->u.map = allocate_mapping(0);
sv->type = T_MAPPING;
return 0;
}
m = allocate_mapping(size >> 1); /* have to clean up after this or */
a = m->table; /* we'll leak */
mask = m->table_size;
while (1) {
switch (c = *cp++) {
case '"':
{
*str = cp;
if ((err = restore_hash_string(str, &key)))
goto key_error;
cp = *str;
cp++;
break;
}
case '(':
{
save_svalue_depth++;
if (*cp == '[') {
*str = ++cp;
if ((err = restore_mapping(str, &key)))
goto key_error;
}
else if (*cp == '{') {
*str = ++cp;
if ((err = restore_array(str, &key)))
goto key_error;
}
else if (*cp == '/') {
*str = ++cp;
if ((err = restore_class(str, &key)))
goto key_error;
}
else goto generic_key_error;
cp = *str;
cp++;
break;
}
case ':':
{
key.u.number = 0;
key.type = T_NUMBER;
key.subtype = 0;
break;
}
case ']':
*str = ++cp;
add_map_stats(m, count);
sv->type = T_MAPPING;
sv->u.map = m;
return 0;
case '-':
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
if (!parse_numeric(&cp, c, &key))
goto key_numeral_error;
break;
default:
goto generic_key_error;
}
/* At this point, key is a valid, referenced svalue and we're
responsible for it */
switch (c = *cp++) {
case '"':
{
*str = cp;
if ((err = restore_interior_string(str, &value)))
goto value_error;
cp = *str;
cp++;
break;
}
case '(':
{
save_svalue_depth++;
if (*cp == '[') {
*str = ++cp;
if ((err = restore_mapping(str, &value)))
goto value_error;
}
else if (*cp == '{') {
*str = ++cp;
if ((err = restore_array(str, &value)))
goto value_error;
} else if (*cp == '/') {
*str = ++cp;
if ((err = restore_class(str, &value)))
goto value_error;
}
else goto generic_value_error;
cp = *str;
cp++;
break;
}
case '-':
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
if (!parse_numeric(&cp, c, &value))
goto value_numeral_error;
break;
case ',':
{
value.u.number = 0;
value.type = T_NUMBER;
value.subtype = 0;
break;
}
default:
goto generic_value_error;
}
/* both key and value are valid, referenced svalues */
oi = MAP_SVAL_HASH(key);
i = oi & mask;
if ((elt2 = elt = a[i])) {
do {
/* This should never happen, but don't bail on it */
if (msameval(&key, elt->values)) {
free_svalue(&key, "restore_mapping: duplicate key");
free_svalue(elt->values+1, "restore_mapping: replaced value");
*(elt->values+1) = value;
break;
}
} while ((elt = elt->next));
if (elt)
continue;
} else if (!(--m->unfilled)) {
if (growMap(m)) {
a = m->table;
if (oi & ++mask) elt2 = a[i |= mask];
mask <<= 1;
mask--;
} else {
add_map_stats(m, count);
free_mapping(m);
free_svalue(&key, "restore_mapping: out of memory");
free_svalue(&value, "restore_mapping: out of memory");
error("Out of memory\n");
}
}
if (++count > MAX_MAPPING_SIZE) {
add_map_stats(m, count -1);
free_mapping(m);
free_svalue(&key, "restore_mapping: mapping too large");
free_svalue(&value, "restore_mapping: mapping too large");
mapping_too_large();
}
elt = new_map_node();
*elt->values = key;
*(elt->values + 1) = value;
(a[i] = elt)->next = elt2;
}
/* something went wrong */
value_numeral_error:
free_svalue(&key, "restore_mapping: numeral value error");
key_numeral_error:
add_map_stats(m, count);
free_mapping(m);
return ROB_NUMERAL_ERROR;
generic_value_error:
free_svalue(&key, "restore_mapping: generic value error");
generic_key_error:
add_map_stats(m, count);
free_mapping(m);
return ROB_MAPPING_ERROR;
value_error:
free_svalue(&key, "restore_mapping: value error");
key_error:
add_map_stats(m, count);
free_mapping(m);
return err;
}
INLINE_STATIC int
restore_class (char ** str, svalue_t * ret)
{
int size;
char c;
array_t *v;
svalue_t *sv;
char *cp = *str;
int err;
if (save_svalue_depth) size = sizes[save_svalue_depth-1];
else if ((size = restore_size((const char **)str,0)) < 0) return ROB_CLASS_ERROR;
v = allocate_class_by_size(size); /* after this point we have to clean up
or we'll leak */
sv = v->item;
while (size--) {
switch (c = *cp++) {
case '"':
*str = cp;
if ((err = restore_interior_string(str, sv)))
goto generic_error;
cp = *str;
cp++;
sv++;
break;
case ',':
sv++;
break;
case '(':
{
save_svalue_depth++;
if (*cp == '[') {
*str = ++cp;
if ((err = restore_mapping(str, sv)))
goto error;
}
else if (*cp == '{') {
*str = ++cp;
if ((err = restore_array(str, sv)))
goto error;
}
else if (*cp == '/') {
*str = ++cp;
if ((err = restore_class(str, sv)))
goto error;
}
else goto generic_error;
sv++;
cp = *str;
cp++;
break;
}
case '-':
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
if (parse_numeric(&cp, c, sv))
sv++;
else
goto numeral_error;
break;
default:
goto generic_error;
}
}
cp += 2;
*str = cp;
ret->u.arr = v;
ret->type = T_CLASS;
return 0;
/* something went wrong */
numeral_error:
err = ROB_NUMERAL_ERROR;
goto error;
generic_error:
err = ROB_CLASS_ERROR;
error:
free_class(v);
return err;
}
INLINE_STATIC int
restore_array (char ** str, svalue_t * ret)
{
int size;
char c;
array_t *v;
svalue_t *sv;
char *cp = *str;
int err;
if (save_svalue_depth) size = sizes[save_svalue_depth-1];
else if ((size = restore_size((const char **)str,0)) < 0) return ROB_ARRAY_ERROR;
v = allocate_array(size); /* after this point we have to clean up
or we'll leak */
sv = v->item;
while (size--) {
switch (c = *cp++) {
case '"':
*str = cp;
if ((err = restore_interior_string(str, sv)))
goto generic_error;
cp = *str;
cp++;
sv++;
break;
case ',':
sv++;
break;
case '(':
{
save_svalue_depth++;
if (*cp == '[') {
*str = ++cp;
if ((err = restore_mapping(str, sv)))
goto error;
}
else if (*cp == '{') {
*str = ++cp;
if ((err = restore_array(str, sv)))
goto error;
}
else if (*cp == '/') {
*str = ++cp;
if ((err = restore_class(str, sv)))
goto error;
}
else goto generic_error;
sv++;
cp = *str;
cp++;
break;
}
case '-':
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
if (parse_numeric(&cp, c, sv))
sv++;
else
goto numeral_error;
break;
default:
goto generic_error;
}
}
cp += 2;
*str = cp;
ret->u.arr = v;
ret->type = T_ARRAY;
return 0;
/* something went wrong */
numeral_error:
err = ROB_NUMERAL_ERROR;
goto error;
generic_error:
err = ROB_ARRAY_ERROR;
error:
free_array(v);
return err;
}
INLINE_STATIC int
restore_string (char * val, svalue_t * sv)
{
register char *cp = val;
char *start = cp, *newstr;
char c;
int len;
while ((c = *cp++) != '"') {
switch (c) {
case '\r':
{
*(cp-1) = '\n';
break;
}
case '\\':
{
char *news = cp - 1;
if ((*news++ = *cp++)) {
while ((c = *cp++) != '"' && c) {
if (c == '\\') {
if (!(*news++ = *cp++))
return ROB_STRING_ERROR;
} else {
if (c == '\r')
*news++ = '\n';
else
*news++ = c;
}
}
if ((c == '\0') || (*cp != '\0'))
return ROB_STRING_ERROR;
*news = '\0';
newstr = new_string(news - start, "restore_string");
strcpy(newstr, start);
sv->u.string = newstr;
sv->type = T_STRING;
sv->subtype = STRING_MALLOC;
return 0;
}
}
case '\0':
{
return ROB_STRING_ERROR;
}
}
}
if (*cp--) return ROB_STRING_ERROR;
*cp = '\0';
len = cp - start;
newstr = new_string(len, "restore_string");
strcpy(newstr, start);
sv->u.string = newstr;
sv->type = T_STRING;
sv->subtype = STRING_MALLOC;
return 0;
}
/* for this case, the variable in question has been set to zero already,
and we don't have to worry about preserving it */
INLINE int
restore_svalue (char * cp, svalue_t * v)
{
int ret;
char c;
switch (c = *cp++) {
case '"':
return restore_string(cp, v);
case '(':
if (*cp == '{') {
cp++;
ret = restore_array(&cp, v);
} else if (*cp == '[') {
cp++;
ret = restore_mapping(&cp, v);
} else if (*cp++ == '/') {
ret = restore_class(&cp, v);
}
else ret = ROB_GENERAL_ERROR;
if (save_svalue_depth) {
save_svalue_depth = max_depth = 0;
if (sizes)
FREE((char *) sizes);
sizes = (int *) 0;
}
return ret;
case '-':
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
if (!parse_numeric(&cp, c, v))
return ROB_NUMERAL_ERROR;
break;
default:
v->type = T_NUMBER;
v->u.number = 0;
}
return 0;
}
/* for this case, we're being careful and want to leave the value alone on
an error */
INLINE_STATIC int
safe_restore_svalue (char * cp, svalue_t * v)
{
int ret;
svalue_t val;
char c;
val.type = T_NUMBER;
switch (c = *cp++) {
case '"':
if ((ret = restore_string(cp, &val))) return ret;
break;
case '(':
{
if (*cp == '{') {
cp++;
ret = restore_array(&cp, &val);
} else if (*cp == '[') {
cp++;
ret = restore_mapping(&cp, &val);
} else if (*cp++ == '/') {
ret = restore_class(&cp, &val);
}
else return ROB_GENERAL_ERROR;
if (save_svalue_depth) {
save_svalue_depth = max_depth = 0;
if (sizes)
FREE((char *) sizes);
sizes = (int *) 0;
}
if (ret)
return ret;
break;
}
case '-':
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
if (!parse_numeric(&cp, c, &val))
return ROB_NUMERAL_ERROR;
break;
default:
val.type = T_NUMBER;
val.u.number = 0;
}
free_svalue(v, "safe_restore_svalue");
*v = val;
return 0;
}
static int fgv_recurse (program_t * prog, int * idx,
char * name, unsigned short * type,
int check_nosave) {
int i;
for (i = 0; i < prog->num_inherited; i++) {
if (fgv_recurse(prog->inherit[i].prog, idx, name, type, check_nosave)) {
*type = DECL_MODIFY(prog->inherit[i].type_mod, *type);
return 1;
}
}
for (i = 0; i < prog->num_variables_defined; i++) {
if (prog->variable_table[i] == name &&
(!check_nosave || !(prog->variable_types[i] & DECL_NOSAVE))) {
*idx += i;
*type = prog->variable_types[i];
return 1;
}
}
*idx += prog->num_variables_defined;
return 0;
}
int find_global_variable (program_t * prog, const char * const name,
unsigned short * type, int check_nosave) {
int idx = 0;
char *str = findstring(name);
if (str && fgv_recurse(prog, &idx, str, type, check_nosave))
return idx;
return -1;
}
void
restore_object_from_line (object_t * ob, char * line, int noclear)
{
char *space;
svalue_t *v;
char var[100];
int idx;
svalue_t *sv = ob->variables;
int rc;
unsigned short t;
if (line[0] == '#') { /* ignore 'comments' in savefiles */
return ;
}
space = strchr(line, ' ');
if (!space || ((space - line) >= sizeof(var))) {
error("restore_object(): Illegal file format - 1 (%s).\n", line);
}
(void)strncpy(var, line, space - line);
var[space - line] = '\0';
idx = find_global_variable(current_object->prog, var, &t, 1);
if (idx == -1) {
push_number(0);
rc = restore_svalue(space+1, sp);
} else {
v = &sv[idx];
if (noclear) {
rc = safe_restore_svalue(space+1, v);
} else {
rc = restore_svalue(space+1, v);
}
}
if (rc & ROB_ERROR) {
if (rc & ROB_GENERAL_ERROR) {
error("restore_object(): Illegal general format while restoring %s.\n", var);
} else if (rc & ROB_NUMERAL_ERROR) {
error("restore_object(): Illegal numeric format while restoring %s.\n", var);
} else if (rc & ROB_ARRAY_ERROR) {
error("restore_object(): Illegal array format while restoring %s.\n", var);
} else if (rc & ROB_MAPPING_ERROR) {
error("restore_object(): Illegal mapping format while restoring %s.\n", var);
} else if (rc & ROB_STRING_ERROR) {
error("restore_object(): Illegal string format while restoring %s.\n", var);
} else if (rc & ROB_CLASS_ERROR) {
error("restore_object(): Illegal class format while restoring %s.\n", var);
}
}
if(idx == -1){
copy_and_push_string(var);
apply("restore_lost_variable", ob, 2, ORIGIN_DRIVER);
}
}
#ifdef HAVE_ZLIB
int
restore_object_from_gzip (object_t * ob,
gzFile gzf,
int noclear, int *count)
{
static char *buff = NULL;
static long buffsize = 0;
const char* tmp = "";
int idx;
int t;
t = 65536 << *count; //should be big enough most of the time
if (buff && buffsize < t) {
FREE(buff);
buff = NULL;
}
if(!buff){
buff = (char *)DXALLOC(t, TAG_TEMPORARY, "restore_object: 6");
buffsize = t;
}
t = buffsize;
while (!gzeof(gzf) && tmp != Z_NULL) {
idx = 0;
buff[t - 2] = 0;
// gzgets appaears to pay attension to zero termination even on short
// strings
buff[0] = 0;
tmp = gzgets(gzf, buff, t);
if (buff[t - 2] != 0 && buff[t - 2] != '\n' && !gzeof(gzf)) {
return -1; //retry with bigger buffer
}
if (buff[0]) {
char *tmp2 = strchr(buff, '\n');
if (tmp2) {
*tmp2 = '\0';
if (tmp2 > buff && tmp2[-1] == '\r') {
*(--tmp2) = '\0';
}
}
restore_object_from_line(ob, buff, noclear);
}
}
return 0;
}
#endif
void
restore_object_from_buff (object_t * ob, char * theBuff,
int noclear)
{
char *buff, *nextBuff, *tmp;
nextBuff = theBuff;
while ((buff = nextBuff) && *buff) {
if ((tmp = strchr(buff, '\n'))) {
*tmp = '\0';
if (tmp > buff && tmp[-1] == '\r')
*(--tmp) = '\0';
nextBuff = tmp + 1;
} else {
nextBuff = 0;
}
restore_object_from_line(ob, buff, noclear);
}
}
/*
* Save an object to a file.
* The routine checks with the function "valid_write()" in /obj/master.c
* to assertain that the write is legal.
* If 'save_zeros' is set, 0 valued variables will be saved
*/
#ifdef HAVE_ZLIB
static int save_object_recurse (program_t * prog, svalue_t **
svp, int type, int save_zeros,
FILE * f, gzFile gzf)
#else
static int save_object_recurse (program_t * prog, svalue_t **
svp, int type, int save_zeros,
FILE * f)
#endif
{
int i;
int textsize = 1;
int tmp;
int theSize;
int oldSize;
char *new_str, *p;
for (i = 0; i < prog->num_inherited; i++) {
#ifdef HAVE_ZLIB
if (!(tmp = save_object_recurse(prog->inherit[i].prog, svp,
prog->inherit[i].type_mod | type,
save_zeros, f, gzf)))
#else
if (!(tmp = save_object_recurse(prog->inherit[i].prog, svp,
prog->inherit[i].type_mod | type,
save_zeros, f)))
#endif
return 0;
textsize += tmp;
}
if (type & DECL_NOSAVE) {
(*svp) += prog->num_variables_defined;
return 1;
}
oldSize = -1;
new_str = NULL;
for (i = 0; i < prog->num_variables_defined; i++) {
if (prog->variable_types[i] & DECL_NOSAVE) {
(*svp)++;
continue;
}
save_svalue_depth = 0;
theSize = svalue_save_size(*svp);
// Try not to malloc/free too much.
if (theSize > oldSize) {
if (new_str) {
FREE(new_str);
}
new_str = (char *)DXALLOC(theSize, TAG_TEMPORARY, "save_object: 2");
oldSize = theSize;
}
*new_str = '\0';
p = new_str;
save_svalue((*svp)++, &p);
DEBUG_CHECK(p - new_str != theSize - 1, "Length miscalculated in save_object!");
/* FIXME: shouldn't use fprintf() */
if (save_zeros || new_str[0] != '0' || new_str[1] != 0) { /* Armidale */
textsize += theSize;
textsize += strlen(prog->variable_table[i]);
textsize += 2;
#ifdef HAVE_ZLIB
if (gzf) {
gzputs(gzf, prog->variable_table[i]);
gzputs(gzf, " ");
gzputs(gzf, new_str);
gzputs(gzf, "\n");
} else
#endif
{
if (fprintf(f, "%s %s\n", prog->variable_table[i], new_str) < 0) {
debug_perror("save_object: fprintf", 0);
FREE(new_str);
return 0;
}
}
}
}
if (new_str) {
FREE(new_str);
}
return textsize;
}
/*
* Save an object to a file.
* The routine checks with the function "valid_write()" in /obj/master.c
* to assertain that the write is legal.
* If 'save_zeros' is set, 0 valued variables will be saved
*/
static int save_object_recurse_str (program_t * prog, svalue_t **svp, int type, int save_zeros, char *buf, int bufsize){
int i;
int textsize = 1;
int tmp;
int theSize;
int oldSize;
char *new_str, *p;
for (i = 0; i < prog->num_inherited; i++) {
if (!(tmp = save_object_recurse_str(prog->inherit[i].prog, svp,
prog->inherit[i].type_mod | type,
save_zeros, buf+textsize-1, bufsize)))
return 0;
textsize += tmp - 1;
}
if (type & DECL_NOSAVE) {
(*svp) += prog->num_variables_defined;
return 1;
}
oldSize = -1;
new_str = NULL;
for (i = 0; i < prog->num_variables_defined; i++) {
if (prog->variable_types[i] & DECL_NOSAVE) {
(*svp)++;
continue;
}
save_svalue_depth = 0;
theSize = svalue_save_size(*svp);
if(textsize+theSize + 2 + strlen(prog->variable_table[i])> bufsize)
return 0;
// Try not to malloc/free too much.
if (theSize > oldSize) {
if (new_str) {
FREE(new_str);
}
new_str = (char *)DXALLOC(theSize, TAG_TEMPORARY, "save_object: 2");
oldSize = theSize;
}
*new_str = '\0';
p = new_str;
save_svalue((*svp)++, &p);
DEBUG_CHECK(p - new_str != theSize - 1, "Length miscalculated in save_object!");
if (save_zeros || new_str[0] != '0' || new_str[1] != 0) { /* Armidale */
if (sprintf(buf+textsize-1, "%s %s\n", prog->variable_table[i], new_str) < 0) {
debug_perror("save_object: fprintf", 0);
FREE(new_str);
return 0;
}
textsize += theSize;
textsize += strlen(prog->variable_table[i]);
textsize ++;
}
}
if (new_str) {
FREE(new_str);
}
return textsize;
}
int sel = -1;
#ifdef HAVE_ZLIB
int gz_sel = -1;
#endif
int
save_object (object_t * ob, const char * file, int save_zeros)
{
char *name, *p;
static char save_name[256], tmp_name[256];
int len;
FILE *f;
int success;
svalue_t *v;
#ifdef HAVE_ZLIB
gzFile gzf;
int save_compressed;
if (save_zeros & 2) {
save_compressed = 1;
save_zeros &= ~2;
} else {
save_compressed = 0;
}
#endif
if (ob->flags & O_DESTRUCTED)
return 0;
len = strlen(file);
if (file[len-2] == '.' && file[len - 1] == 'c')
len -= 2;
if (sel == -1) sel = strlen(SAVE_EXTENSION);
if (strcmp(file + len - sel, SAVE_EXTENSION) == 0)
len -= sel;
#ifdef HAVE_ZLIB
if (gz_sel == -1) {
gz_sel = strlen(SAVE_GZ_EXTENSION);
}
if (save_compressed) {
name = new_string(len + gz_sel, "save_object");
strcpy(name, file);
strcpy(name + len, SAVE_GZ_EXTENSION);
} else
#endif
{
name = new_string(len + sel, "save_object");
strcpy(name, file);
strcpy(name + len, SAVE_EXTENSION);
}
push_malloced_string(name); /* errors */
file = check_valid_path(name, ob, "save_object", 1);
free_string_svalue(sp--);
if (!file)
error("Denied write permission in save_object().\n");
strcpy(save_name, ob->obname);
if ((p = strrchr(save_name, '#')) != 0)
*p = '\0';
p = save_name + strlen(save_name) - 1;
if (*p != 'c' && *(p - 1) != '.')
strcat(p, ".c");
/*
* Write the save-files to different directories, just in case
* they are on different file systems.
*/
sprintf(tmp_name, "%.250s.tmp", file);
#ifdef HAVE_ZLIB
gzf = NULL;
f = NULL;
if (save_compressed) {
gzf = gzopen(tmp_name, "w");
if (!gzf) {
error("Could not open /%s for a save.\n", tmp_name);
}
if (!gzprintf(gzf, "#/%s\n", ob->prog->filename)) {
error("Could not open /%s for a save.\n", tmp_name);
}
} else
#endif
{
if (!(f = fopen(tmp_name, "w")) || fprintf(f, "#/%s\n", save_name) < 0) {
error("Could not open /%s for a save.\n", tmp_name);
}
}
v = ob->variables;
#ifdef HAVE_ZLIB
success = save_object_recurse(ob->prog, &v, 0, save_zeros, f, gzf);
if (gzf && gzclose(gzf)) {
debug_perror("save_object", file);
success = 0;
}
#else
success = save_object_recurse(ob->prog, &v, 0, save_zeros, f);
#endif
if (f && fclose(f) < 0) {
debug_perror("save_object", file);
success = 0;
}
if (!success) {
debug_message("Failed to completely save file. Disk could be full.\n");
unlink(tmp_name);
} else {
#ifdef WIN32
/* Need to erase it to write over it. */
unlink(file);
#endif
if (rename(tmp_name, file) < 0) {
debug_perror("save_object", file);
debug_message("Failed to rename /%s to /%s\n", tmp_name, file);
debug_message("Failed to save object!\n");
unlink(tmp_name);
}
#ifdef HAVE_ZLIB
else if (save_compressed) {
char buf[1024];
// When compressed, unlink the uncompressed name too.
strcpy(buf, file);
len = strlen(buf) - gz_sel;
strcpy(buf + len, SAVE_EXTENSION);
unlink(buf);
}
#endif
}
return success;
}
int
save_object_str (object_t *ob, int save_zeros, char *saved, int size)
{
char *p;
int success;
svalue_t *v;
char *now = saved;
int left;
if (ob->flags & O_DESTRUCTED)
return 0;
strcpy(now, "#/");
now+=2;
strcpy(now, ob->obname);
if ((p = strrchr(now, '#')) != 0)
*p = '\0';
p = now + strlen(now) - 1;
if (*p != 'c' && *(p - 1) != '.')
strcat(p, ".c");
now = now + strlen(now);
*now++ = '\n';
left = size - (now - saved);
*now = 0;
/*
* Write the save-files to different directories, just in case
* they are on different file systems.
*/
v = ob->variables;
success = save_object_recurse_str(ob->prog, &v, 0, save_zeros, now, left);
if (!success) {
debug_message("Failed to completely save file. string size too small?.\n");
}
return success;
}
/*
* return a string representing an svalue in the form that save_object()
* would write it.
*/
char *
save_variable (svalue_t * var)
{
int theSize;
char *new_str, *p;
save_svalue_depth = 0;
theSize = svalue_save_size(var);
new_str = new_string(theSize - 1, "save_variable");
*new_str = '\0';
p = new_str;
save_svalue(var, &p);
DEBUG_CHECK(p - new_str != theSize - 1, "Length miscalculated in save_variable");
return new_str;
}
static void cns_just_count (int * idx, program_t * prog) {
int i;
for (i = 0; i < prog->num_inherited; i++)
cns_just_count(idx, prog->inherit[i].prog);
*idx += prog->num_variables_defined;
}
static void cns_recurse (object_t * ob, int * idx, program_t * prog) {
int i;
for (i = 0; i < prog->num_inherited; i++) {
if (prog->inherit[i].type_mod & DECL_NOSAVE)
cns_just_count(idx, prog->inherit[i].prog);
else
cns_recurse(ob, idx, prog->inherit[i].prog);
}
for (i = 0; i < prog->num_variables_defined; i++) {
if (!(prog->variable_types[i] & DECL_NOSAVE)) {
free_svalue(&ob->variables[*idx + i], "cns_recurse");
ob->variables[*idx + i] = const0u;
}
}
*idx += prog->num_variables_defined;
}
void clear_non_statics (object_t * ob) {
int idx = 0;
cns_recurse(ob, &idx, ob->prog);
}
int restore_object (object_t * ob, const char * file, int noclear)
{
char *name;
int len;
object_t *save = current_object;
struct stat st;
#ifdef HAVE_ZLIB
int pos;
gzFile gzf;
static int count = 0;
#else
FILE *f;
// Try and keep one buffer for droping all the restores into
static char *theBuff = NULL;
static int buff_len = 0;
int tmp_len;
#endif
if (ob->flags & O_DESTRUCTED)
return 0;
len = strlen(file);
if (file[len-2] == '.' && file[len - 1] == 'c')
len -= 2;
if (sel == -1) sel = strlen(SAVE_EXTENSION);
if (strcmp(file + len - sel, SAVE_EXTENSION) == 0)
len -= sel;
#ifdef HAVE_ZLIB
else {
if (gz_sel == -1) gz_sel = strlen(SAVE_GZ_EXTENSION);
if (strcmp(file + len - gz_sel, SAVE_GZ_EXTENSION) == 0)
len -= gz_sel;
}
name = new_string(len + gz_sel, "restore_object");
strncpy(name, file, len);
strcpy(name + len, SAVE_GZ_EXTENSION);
pos = 0;
while (name[pos] == '/') {
pos++;
}
// See if the gz file exists.
if (stat(name + pos, &st) == -1)
{
FREE_MSTR(name);
#else
{
#endif
name = new_string(len + sel, "restore_object");
strncpy(name, file, len);
strcpy(name + len, SAVE_EXTENSION);
}
push_malloced_string(name); /* errors */
file = check_valid_path(name, ob, "restore_object", 0);
free_string_svalue(sp--);
if (!file) error("Denied read permission in restore_object().\n");
#ifdef HAVE_ZLIB
gzf = gzopen(file, "r");
if (!gzf) {
if (gzf) {
(void)gzclose(gzf);
}
return 0;
}
/* This next bit added by Armidale@Cyberworld 1/1/93
* If 'noclear' flag is not set, all non-static variables will be
* initialized to 0 when restored.
*/
if (!noclear) {
clear_non_statics(ob);
}
error_context_t econ;
save_context(&econ);
if (SETJMP(econ.context)){
restore_context(&econ);
pop_context(&econ);
gzclose(gzf);
return 0;
}
while((restore_object_from_gzip(ob, gzf, noclear, &count))){
count++;
gzseek(gzf, 0, SEEK_SET);
if (!noclear) {
clear_non_statics(ob);
}
}
gzclose(gzf);
pop_context(&econ);
#else
f = fopen(file, "r");
if (!f || fstat(fileno(f), &st) == -1) {
if (f)
(void)fclose(f);
return 0;
}
if (!(tmp_len = st.st_size)) {
(void)fclose(f);
return 0;
}
if (tmp_len > buff_len) {
if (theBuff) {
FREE(theBuff);
}
theBuff = DXALLOC(tmp_len + 1, TAG_TEMPORARY, "restore_object: 4");
buff_len = tmp_len;
}
#ifdef WIN32
tmp_len = read(_fileno(f), theBuff, tmp_len);
#else
fread(theBuff, 1, tmp_len, f);
#endif
fclose(f);
theBuff[tmp_len] = '\0';
current_object = ob;
/* This next bit added by Armidale@Cyberworld 1/1/93
* If 'noclear' flag is not set, all non-static variables will be
* initialized to 0 when restored.
*/
if (!noclear)
clear_non_statics(ob);
restore_object_from_buff(ob, theBuff, noclear);
#endif
current_object = save;
debug(d_flag, ("Object /%s restored from /%s.\n", ob->obname, file));
return 1;
}
void restore_variable (svalue_t * var, char * str)
{
int rc;
rc = restore_svalue(str, var);
if (rc & ROB_ERROR) {
*var = const0; /* clean up */
if (rc & ROB_GENERAL_ERROR)
error("restore_object(): Illegal general format.\n");
else if (rc & ROB_NUMERAL_ERROR)
error("restore_object(): Illegal numeric format.\n");
else if (rc & ROB_ARRAY_ERROR)
error("restore_object(): Illegal array format.\n");
else if (rc & ROB_MAPPING_ERROR)
error("restore_object(): Illegal mapping format.\n");
else if (rc & ROB_STRING_ERROR)
error("restore_object(): Illegal string format.\n");
}
}
void tell_npc (object_t * ob, const char * str)
{
copy_and_push_string(str);
apply(APPLY_CATCH_TELL, ob, 1, ORIGIN_DRIVER);
}
/*
* tell_object: send a message to an object.
* If it is an interactive object, it will go to his
* screen. Otherwise, it will go to a local function
* catch_tell() in that object. This enables communications
* between users and NPC's, and between other NPC's.
* If INTERACTIVE_CATCH_TELL is defined then the message always
* goes to catch_tell unless the target of tell_object is interactive
* and is the current_object in which case it is written via add_message().
*/
void tell_object (object_t * ob, const char * str, int len)
{
if (!ob || (ob->flags & O_DESTRUCTED)) {
add_message(0, str, len);
return;
}
/* if this is on, EVERYTHING goes through catch_tell() */
#ifndef INTERACTIVE_CATCH_TELL
if (ob->interactive)
add_message(ob, str, len);
else
#endif
tell_npc(ob, str);
}
void dealloc_object (object_t * ob, const char * from)
{
#ifdef DEBUG
object_t *tmp, *prev_all = 0;
#endif
debug(d_flag, ("free_object: /%s.\n", ob->obname));
if (!(ob->flags & O_DESTRUCTED)) {
if(ob->next_all != ob)
/* This is fatal, and should never happen. */
fatal("FATAL: Object 0x%x /%s ref count 0, but not destructed (from %s).\n",
ob, ob->obname, from);
else {
destruct_object(ob);
return;
}
}
DEBUG_CHECK(ob->interactive, "Tried to free an interactive object.\n");
/*
* If the program is freed, then we can also free the variable
* declarations.
*/
if (ob->prog) {
tot_alloc_object_size -=
(ob->prog->num_variables_total - 1) * sizeof(svalue_t) +
sizeof(object_t);
free_prog(&ob->prog);
ob->prog = 0;
}
if (ob->replaced_program) {
FREE_MSTR(ob->replaced_program);
ob->replaced_program = 0;
}
#ifdef PRIVS
if (ob->privs)
free_string(ob->privs);
#endif
if (ob->obname) {
debug(d_flag, ("Free object /%s\n", ob->obname));
DEBUG_CHECK1(lookup_object_hash(ob->obname) == ob,
"Freeing object /%s but name still in name table", ob->obname);
FREE((char *)ob->obname);
SETOBNAME(ob, 0);
}
#ifdef DEBUG
prev_all = ob->prev_all;
if (prev_all){
prev_all->next_all = ob->next_all;
if(ob->next_all)
ob->next_all->prev_all = prev_all;
} else {
obj_list_dangling = ob->next_all;
if(obj_list_dangling)
obj_list_dangling->prev_all = 0;
}
ob->next_all = 0;
ob->prev_all = 0;
tot_dangling_object--;
#endif
tot_alloc_object--;
FREE((char *) ob);
}
void free_object (object_t ** ob, const char * const from)
{
//note that we get a pointer to a pointer unlike MudOS where it's a pointer to the object
//this is so we can clear the variable holding the reference as that shouldn't be used anymore
//after freeing it! don't set to NULL as that might still hide such bugs, and I suspect it may
//be related to some of the corrupted memory crashes (which dw stopped doing, oh well, I'm sure it
//will be back.) Better to find and fix than to hide!
if(*ob)
(*ob)->ref--;
if ((*ob)->ref > 0) {
*ob = (object_t *)9;
return;
}
dealloc_object(*ob, from);
*ob = (object_t *)1;
}
/*
* Allocate an empty object, and set all variables to 0. Note that a
* 'object_t' already has space for one variable. So, if no variables
* are needed, we waste one svalue worth of memory (or we'd write too
* much memory in copying the NULL_object over.
*/
object_t *get_empty_object (int num_var)
{
//static object_t NULL_object;
object_t *ob;
int size = sizeof(object_t) +
(num_var - !!num_var) * sizeof(svalue_t);
int i;
tot_alloc_object++;
tot_alloc_object_size += size;
ob = (object_t *) DXALLOC(size, TAG_OBJECT, "get_empty_object");
/*
* marion Don't initialize via memset, this is incorrect. E.g. the bull
* machines have a (char *)0 which is not zero. We have structure
* assignment, so use it.
*/
//*ob = NULL_object; gives a warning on const pointers
//memcpy(ob, &NULL_object, sizeof NULL_object);
//screw the "bull machines" we're in the 21st century now
memset(ob, 0, sizeof(object_t));
ob->ref = 1;
for (i = 0; i < num_var; i++)
ob->variables[i] = const0u;
return ob;
}
void reset_object (object_t * ob)
{
/* Be sure to update time first ! */
ob->next_reset = current_time + TIME_TO_RESET / 2 +
random_number(TIME_TO_RESET / 2);
save_command_giver(0);
if (!apply(APPLY_RESET, ob, 0, ORIGIN_DRIVER)) {
/* no reset() in the object */
ob->flags &= ~O_WILL_RESET; /* don't call it next time */
}
restore_command_giver();
ob->flags |= O_RESET_STATE;
}
void call_create (object_t * ob, int num_arg)
{
/* Be sure to update time first ! */
ob->next_reset = current_time + TIME_TO_RESET / 2 +
random_number(TIME_TO_RESET / 2);
call___INIT(ob);
if (ob->flags & O_DESTRUCTED) {
pop_n_elems(num_arg);
return; /* sigh */
}
apply(APPLY_CREATE, ob, num_arg, ORIGIN_DRIVER);
ob->flags |= O_RESET_STATE;
}
#ifdef F_SET_HIDE
INLINE int object_visible (object_t * ob)
{
if (ob->flags & O_HIDDEN) {
if (current_object->flags & O_HIDDEN)
return 1;
return valid_hide(current_object);
} else
return 1;
}
#endif
void reload_object (object_t * obj)
{
int i;
if (!obj->prog)
return;
for (i = 0; i < obj->prog->num_variables_total; i++) {
free_svalue(&obj->variables[i], "reload_object");
obj->variables[i] = const0u;
}
#if defined(PACKAGE_SOCKETS) || defined(PACKAGE_EXTERNAL)
if (obj->flags & O_EFUN_SOCKET) {
close_referencing_sockets(obj);
}
#endif
/*
* If this is the first object being shadowed by another object, then
* destruct the whole list of shadows.
*/
#ifndef NO_SHADOWS
if (obj->shadowed && !obj->shadowing) {
object_t *ob2;
object_t *otmp;
for (ob2 = obj->shadowed; ob2;) {
otmp = ob2;
ob2 = ob2->shadowed;
otmp->shadowed = 0;
otmp->shadowing = 0;
destruct_object(otmp);
}
}
/*
* The chain of shadows is a double linked list. Take care to update it
* correctly.
*/
if (obj->shadowing)
obj->shadowing->shadowed = obj->shadowed;
if (obj->shadowed)
obj->shadowed->shadowing = obj->shadowing;
obj->shadowing = 0;
obj->shadowed = 0;
#endif
remove_living_name(obj);
set_heart_beat(obj, 0);
remove_all_call_out(obj);
#ifndef NO_LIGHT
add_light(obj, -(obj->total_light));
#endif
#ifdef PACKAGE_UIDS
#ifdef AUTO_SETEUID
obj->euid = obj->uid;
#else
obj->euid = NULL;
#endif
#endif
call_create(obj, 0);
}
void get_objects (object_t *** list, int * size, get_objectsfn_t callback, void * data)
{
object_t *ob;
#ifdef F_SET_HIDE
int display_hidden = 0;
if (num_hidden > 0) {
if (current_object->flags & O_HIDDEN) {
display_hidden = 1;
} else {
display_hidden = valid_hide(current_object);
}
}
*list = (object_t **)new_string(((tot_alloc_object - (display_hidden ? 0 : num_hidden)) * sizeof(object_t *)) - 1, "get_objects");
#else
*list = (object_t **)new_string((tot_alloc_object * sizeof(object_t *)) - 1, "get_objects");
#endif
if (!*list)
fatal("Out of memory!\n");
push_malloced_string((char *)*list);
for (*size = 0, ob = obj_list; ob; ob = ob->next_all) {
#ifdef F_SET_HIDE
if (!display_hidden && (ob->flags & O_HIDDEN))
continue;
#endif
if (!callback || callback(ob, data))
(*list)[(*size)++] = ob;
}
}
static object_t *command_giver_stack[CFG_MAX_CALL_DEPTH];
object_t **cgsp = command_giver_stack;
#ifdef DEBUGMALLOC_EXTENSIONS
void mark_command_giver_stack (void)
{
object_t **ob;
for (ob = &command_giver_stack[0]; ob < cgsp; ob++) {
if (*ob)
(*ob)->extra_ref++;
}
if (command_giver)
command_giver->extra_ref++;
}
#endif
/* set a new command giver, saving the old one */
void save_command_giver (object_t * ob)
{
DEBUG_CHECK(cgsp == &command_giver_stack[CFG_MAX_CALL_DEPTH], "command_giver stack overflow");
*(++cgsp) = command_giver;
command_giver = ob;
if (command_giver)
add_ref(command_giver, "save_command_giver");
}
/* restore the saved command giver */
void restore_command_giver (void)
{
if (command_giver)
free_object(&command_giver, "command_giver_error_handler");
DEBUG_CHECK(cgsp == command_giver_stack, "command_giver stack underflow");
command_giver = *(cgsp--);
}
/* set a new command giver */
void set_command_giver (object_t * ob)
{
if (command_giver)
free_object(&command_giver, "set_command_giver");
command_giver = ob;
if (command_giver != 0)
add_ref(command_giver, "set_command_giver");
}