#include "global.h"
#include <errno.h>
#include <ctype.h>
#include <sys/types.h>
#include <signal.h>
#include "array.h"
#include "interpret.h"
#include "object.h"
#include "comm1.h"
#include "exec.h"
#include "call_out.h"
#include "sent.h"
#include "main.h"
#include "stralloc.h"
#include "dynamic_buffer.h"
#include "hash.h"
#include "simulate.h"
#include "socket_efuns.h"
#include "simul_efun.h"
#include "operators.h"
#include "save_objectII.h"
/*
* stralloc.c - string management.
*
* All strings are stored in an extensible hash table, with reference counts.
* free_string decreases the reference count; if it gets to zero, the string
* will be deallocated. add_string increases the ref count if it finds a
* matching string, or allocates it if it cant. There is no way to allocate
* a string of a particular size to fill later (hash wont work!), so you'll
* have to copy things freom a static (or malloced and later freed) buffer -
* that is, if you want to avoid space leaks...
*
* Current overhead (on a 32 bit system):
* next pointer: 4 bytes
* length: 4 bytes
* references: 4 bytes
* sum: 12 bytes + malloc overhead
*/
#ifdef DEBUG
/* #define ALERT "s" */
#endif
extern int d_flag;
#ifdef ALERT
void Alert(char *s)
{
fprintf(stderr,"Alert: '%s' done.\n",s);
}
void Alert2(char *s)
{
if(d_flag>6) Alert(s);
}
#endif
/*
* there is also generic hash table management code, but strings can be shared
* (that was the point of this code), will be unique in the table,
* require a reference count, and are malloced, copied and freed at
* will by the string manager. Besides, I wrote this code first :-).
* Look at htable.c for the other code. It uses the Hash() function
* defined here, and requires hashed objects to have a pointer to the
* next element in the chain (which you specify when you call the functions).
*/
static int search_len = 0;
static int num_str_searches = 0;
#ifdef DEBUG
int refchecked=0;
#endif
/*
* hash table - list of pointers to heads of string chains.
* Each string in chain has a pointer to the next string and a
* reference count (char *, int) stored just before the start of the string.
* HTABLE_SIZE is in config.h, and should be a prime, probably between
* 1000 and 5000.
*/
static char *base_table[HTABLE_SIZE];
/*
* generic hash function. This is probably overkill; I haven't checked the
* stats for different prime numbers, etc.
*/
INLINE static unsigned int StrHash(const char *s,int len)
{
return hashmem(s, len, 20) % HTABLE_SIZE;
}
/*
* Looks for a string in the table. If it finds it, returns a pointer to
* the start of the string part, and moves the entry for the string to
* the head of the pointer chain.
*/
static char *internal_findstring(const char *s,int len,int h)
{
char * curr, *prev;
#ifdef MALLOC_DEBUG
check_sfltable();
#endif
curr = base_table[h];
prev = 0;
num_str_searches++;
while (curr)
{
search_len++;
if (len==SIZE(curr) && !MEMCMP(curr, s,len)) /* found it */
{
if (prev) /* not at head of list */
{
NEXT(prev) = NEXT(curr);
NEXT(curr) = base_table[h];
base_table[h] = curr;
}
#if defined(DEBUG) && defined(STRALLOC_REFS)
if(REFS(curr)<1)
fatal("String with no references.\n");
#endif
return curr; /* pointer to string */
}
prev = curr;
curr = NEXT(curr);
}
return 0; /* not found */
}
char *findstring(const char *foo)
{
int l;
char *s;
l=strlen(foo);
s=internal_findstring(foo,l,StrHash(foo,l));
#ifdef WARN
if(foo==s)
warn(3,"findstring on already shared string.\n");
#endif
return s;
}
/* this one looks for strings that was already shared only */
static char *find_shared_string(const char *s,int h)
{
char * curr, *prev;
curr = base_table[h];
prev = 0;
num_str_searches++;
while(curr)
{
search_len++;
if (curr == s) /* found it */
{
if (prev) /* not at head of list */
{
NEXT(prev) = NEXT(curr);
NEXT(curr) = base_table[h];
base_table[h] = curr;
}
#if defined(DEBUG) && defined(STRALLOC_REFS)
if(REFS(curr)<1)
fatal("String with no references.\n");
#endif
return curr; /* pointer to string */
}
prev = curr;
curr = NEXT(curr);
}
return 0; /* not found */
}
char *debug_findstring(const char *foo)
{
return find_shared_string(foo,StrHash(foo,SIZE(foo)));
}
/* note that begin_shared_string expects the _exact_ size of the string,
* not the maximum size
*/
char *begin_shared_string(int len)
{
struct shared *t;
t=(struct shared *)xalloc(len + sizeof(struct shared));
t->size=len;
return t->str;
}
/*
* Make a space for a string. This is rather nasty, as we want to use
* alloc/free, but malloc overhead is generally severe. Later, we
* will have to compact strings...
*/
static char * alloc_new_string(const char *string,int len,int h)
{
char *s;
s=begin_shared_string(len);
MEMCPY(s, string,len);
s[len]=0;
#ifndef STRALLOC_GC
REFS(s) = 0;
#ifdef DEBUG
XREF(s)=0;
#endif
#endif
NEXT(s) = base_table[h];
base_table[h] = s;
return s;
}
char *end_shared_string(char *s)
{
int len,h;
char *s2;
len=SIZE(s);
h=StrHash(s,len);
if((s2=internal_findstring(s,len,h)))
{
free((char *)REFERENCE(s,));
s=s2;
}else{
s[len]=0;
#ifndef STRALLOC_GC
REFS(s) = 0;
#ifdef DEBUG
XREF(s)=0;
#endif
#endif
NEXT(s) = base_table[h];
base_table[h] = s;
}
#ifndef STRALLOC_GC
REFS(s)++;
#ifdef DEBUG
XREF(s)++;
#endif
#endif
return s;
}
char *make_shared_string(const char *str)
{
char * s;
int len=strlen(str);
int h=StrHash(str,len);
#ifdef ALERT
if(!strcmp(str,ALERT)) Alert("make_shared_string");
#endif
s = internal_findstring(str,len,h);
#ifdef WARN
if(s==str) warn(2,"make_shared_string on already shared string.\n");
#endif
if (!s) s = alloc_new_string(str,len,h);
#ifndef STRALLOC_GC
REFS(s)++;
#ifdef DEBUG
XREF(s)++;
#endif
#endif
return s;
}
char * make_shared_binary_string(const char *str,int len)
{
char * s;
int h=StrHash(str,len);
#ifdef ALERT
if(!strcmp(str,ALERT)) Alert("make_shared_binary_string");
#endif
s = internal_findstring(str,len,h);
#ifdef WARN
if(s==str) warn(2,"make_shared_binary_string on already shared string.\n");
#endif
if (!s) s = alloc_new_string(str,len,h);
#ifndef STRALLOC_GC
REFS(s)++;
#ifdef DEBUG
XREF(s)++;
#endif
#endif
return(s);
}
#ifdef DEBUG
int my_strlen2(const union storage_union u)
{
if(debug_findstring(strptr2(u))!=strptr2(u))
fatal("Non shared string to internal.\n");
return u.string->size;
}
int my_strlen(const struct svalue *s)
{
if(s->type!=T_STRING)
fatal("Bad type to internal strlen.\n");
return my_strlen2(s->u);
}
#endif
INLINE int my_string_is_equal(const struct svalue *a,const struct svalue *b)
{
#ifdef DEBUG
if(a->type!=T_STRING)
fatal("Bad type to internal strcmp.\n");
if(b->type!=T_STRING)
fatal("Bad type to internal strcmp.\n");
#endif
return a->u.string == b->u.string;
}
INLINE int my_strcmp(const struct svalue *a,const struct svalue *b)
{
int tmp;
#ifdef DEBUG
if(a->type!=T_STRING)
fatal("Bad type to internal strcmp.\n");
if(b->type!=T_STRING)
fatal("Bad type to internal strcmp.\n");
#endif
if(my_string_is_equal(a,b)) return 0;
if(my_strlen(a)>my_strlen(b))
{
tmp=MEMCMP(strptr(a),strptr(b),my_strlen(b));
if(tmp) return tmp;
return 1;
}else if(my_strlen(a)<my_strlen(b)){
tmp=MEMCMP(strptr(a),strptr(b),my_strlen(a));
if(tmp) return tmp;
return -1;
}else{
return MEMCMP(strptr(a),strptr(b),my_strlen(a));
}
}
#ifndef copy_shared_string
char * copy_shared_string(char *str)
{
#ifdef ALERT
if(!strcmp(str,ALERT)) Alert("copy_shared_string");
#endif
#ifdef DEBUG
if(debug_findstring(str)!=str)
fatal("Copy shared string on non shared string.\n");
#endif
#ifndef STRALLOC_GC
REFS(str)++;
#ifdef DEBUG
XREF(str)++;
#endif
#endif
return(str);
}
#endif
INLINE static void terminally_free_string(char **prev,char *s)
{
/* It will be at the head of the hash chain */
*prev = NEXT(s);
free((char *)REFERENCE(s,));
}
/*
* free_string - reduce the ref count on a string. Various sanity
* checks applied, the best of them being that a add_string allocated
* string will point to a word boundary + sizeof(char *)+sizeof(int),
* since malloc always allocates on a word boundary.
* On systems where a short is 1/2 a word, this gives an easy check
* to see whather we did in fact allocate it.
*/
#ifdef DEBUG
void free_string(char *str)
{
#if defined(DEBUG) || defined(STRALLOC_REFS)
char * s;
int h;
#endif
#ifdef ALERT
if(!strcmp(str,ALERT)) Alert("free_string");
#endif
#ifndef DEBUG
#ifndef STRALLOC_GC
if(--REFS(str)) return;
#endif
#ifdef STRALLOC_REFS
h=StrHash(str,SIZE(str));
s = find_shared_string(str,h); /* moves it to head of table if found */
#endif
#else
h=StrHash(str,SIZE(str));
s = find_shared_string(str,h); /* moves it to head of table if found */
if (!s)
{
fatal("Free string: not found in string table! (%s)", str);
return;
}
if (s != str)
{
fatal("Free string: string didnt hash to the same spot! (%s)", str);
return;
}
#ifndef STRALLOC_GC
XREF(s)--;
REFS(s)--;
if (REFS(s)<0)
{
fatal("Freeing string too many times. (%s)", str);
return;
}
/*
if(REFS(s) != XREF(s) && refchecked)
{
fprintf(stderr,"Freeing string with strange xrefs '%s'!\n",s);
}
*/
if (REFS(s) > 0) return;
#endif
#endif /* DEBUG */
#ifdef STRALLOC_REFS
terminally_free_string(base_table+h,s);
#endif
}
#else
#ifndef STRALLOC_GC
INLINE void really_free_string(char *str)
{
int h;
h=StrHash(str,SIZE(str));
terminally_free_string(base_table+h,find_shared_string(str,h));
}
#endif
#endif
/*
* you think this looks bad! and we didn't even tell them about the
* GNU malloc overhead! tee hee!
*/
char *add_string_status(int verbose)
{
char b[200];
init_buf();
if (verbose)
{
#ifndef STRALLOC_GC
int allocd_strings=0,allocd_bytes=0;
#endif
int num_distinct_strings=0,bytes_distinct_strings=0;
int overhead_bytes=0;
int e;
char *p;
for(e=0;e<HTABLE_SIZE;e++)
{
for(p=base_table[e];p;p=NEXT(p))
{
num_distinct_strings++;
bytes_distinct_strings+=((SIZE(p)+3)&~3);
#ifndef STRALLOC_GC
allocd_strings+=REFS(p);
allocd_bytes=REFS(p)*((SIZE(p)+3)&~3);
#endif
}
}
overhead_bytes=(sizeof(struct shared)-1)*num_distinct_strings;
my_strcat("\nShared string hash table:\n");
my_strcat("-------------------------\t Strings Bytes\n");
#ifndef STRALLOC_GC
sprintf(b,"Total asked for\t\t\t%8d %8d\n",
allocd_strings, allocd_bytes);
my_strcat(b);
#endif
sprintf(b,"Strings malloced\t\t%8d %8d + %d overhead\n",
num_distinct_strings, bytes_distinct_strings, overhead_bytes);
my_strcat(b);
sprintf(b,"Space actually required/total string bytes %d%%\n",
(bytes_distinct_strings + overhead_bytes)*100 / allocd_bytes);
my_strcat(b);
}
sprintf(b,"Searches: %d Average search length: %6.3f\n",
num_str_searches, (double)search_len / num_str_searches);
my_strcat(b);
return free_buf();
/* return(bytes_distinct_strings + overhead_bytes); */
}
/* only used in debug mode, or when stralloc uses garbage collect */
int ref_cycle=0;
#ifdef DEBUG
static void *string_to_find;
int check_ref_cycle=0;
#endif
#ifdef DEBUG
#define RETTYPE int
#define RETDECL RETTYPE ret=0
#define CCALL(X,Y) if X { ret=1; Y; }
#define RETURN return ret
#else
#define RETTYPE void
#define RETDECL
#define CCALL(X,Y) X
#define RETURN return
#endif
static RETTYPE check_svalues(struct svalue *s,int number);
static RETTYPE check_short_svalue(union storage_union *u,int type);
INLINE static RETTYPE check_string(char *c)
{
char *t;
RETDECL;
if(c)
{
t=debug_findstring(c);
if(!t) fatal("Shared string not shared.\n");
if(t!=c) fatal("Shared string not same as one in hashtable.\n");
#ifdef DEBUG
if(check_ref_cycle) RETURN;
if(string_to_find)
{
if(string_to_find==c)
{
fprintf(stderr,"Found '%s'\n",c);
ret=1;
}
}else
#endif
{
#ifdef STRALLOC_GC
if(SIZE(c)<0) SIZE(c)=-SIZE(c); /* mark */
#else
#ifdef DEBUG
XREF(c)++;
ret=0;
#endif
#endif
}
}
RETURN;
}
static RETTYPE check_array(struct vector *v)
{
RETDECL;
#ifdef DEBUG
if(v==string_to_find)
{
fprintf(stderr,"Array found...\n");
ret=1;
}
if(v->ref<1) fatal("Zero refs array.\n");
if(v->size>MAX_ARRAY_SIZE && !batch_mode)
fatal("Too large array.\n");
if(v->malloced_size<v->size)
fatal("Impossible array.\n");
if(check_ref_cycle)
{
if((v->flags & O_REF_CYCLE) != ref_cycle)
fatal("Error in ref cycle of program.\n");
if(!v->extra_ref) RETURN;
v->extra_ref=0;
}else
#endif
{
#ifdef DEBUG
if(!string_to_find)
v->extra_ref++;
#endif
if((v->flags & O_REF_CYCLE) == ref_cycle) RETURN;
v->flags&=~O_REF_CYCLE;
v->flags|=ref_cycle;
}
if(v->size>0 && v->item[0].type==T_ALIST_PART)
check_alist_for_destruct(v);
CCALL((check_svalues(v->item,v->size)), );
RETURN;
}
static RETTYPE check_program(struct program *p)
{
int e;
RETDECL;
if(!p) RETURN;
#ifdef DEBUG
if(p==string_to_find)
{
fprintf(stderr,"Program found...\n");
ret=1;
}
if(check_ref_cycle)
{
if((p->flags & O_REF_CYCLE) != ref_cycle)
fatal("Error in ref cycle of program.\n");
if(!p->extra_ref) RETURN;
p->extra_ref=0;
}else
#endif
{
#ifdef DEBUG
if(!string_to_find)
p->extra_ref++;
#endif
if((p->flags & O_REF_CYCLE) == ref_cycle) RETURN;
p->flags&=~O_REF_CYCLE;
p->flags|=ref_cycle;
}
CCALL((check_string(p->name)),fprintf(stderr,"Was the name of a program.\n"));
for(e=0;e<p->num_variables;e++)
{
CCALL((check_string(p->variable_names[e].name)),fprintf(stderr,"It's the name of a variable in %s.\n",p->name));
}
for(e=0;e<p->num_functions;e++)
{
CCALL((check_string(p->functions[e].name)),fprintf(stderr,"It's the name of a function in %s.\n",p->name));
}
for(e=0;e<p->num_strings;e++)
{
CCALL((check_string(p->strings[e])),fprintf(stderr,"It's a string in %s.\n",p->name));
}
if(p->inherit[0].prog!=p) fatal("p->inherited[0] != p.\n");
for(e=1;e<p->num_inherited;e++)
{
CCALL((check_program(p->inherit[e].prog)),fprintf(stderr,"Was inherited by '%s'.\n",p->name));
}
for(e=0;e<p->num_switch_mappings;e++)
{
CCALL((check_array(p->switch_mappings[e])),fprintf(stderr,"Was in a switch mapping of %s.\n",p->name));
}
CCALL((check_svalues(p->constants,p->num_constants)),fprintf(stderr,"Was in a program constant of %s.\n",p->name));
RETURN;
}
static RETTYPE check_object(struct object *ob)
{
int e;
RETDECL;
if(!ob) RETURN;
#ifdef DEBUG
if(ob==string_to_find)
{
fprintf(stderr,"Object found...\n");
ret=1;
}
if(check_ref_cycle)
{
if((ob->flags & O_REF_CYCLE) != ref_cycle)
fatal("Error in ref cycle of object.\n");
if(!ob->extra_ref) return 0;
ob->extra_ref=0;
}else
#endif
{
#ifdef DEBUG
if(!string_to_find)
ob->extra_ref++;
#endif
if((ob->flags & O_REF_CYCLE) == ref_cycle) RETURN;
ob->flags&=~O_REF_CYCLE;
ob->flags|=ref_cycle;
}
if(ob->flags & O_DESTRUCTED) RETURN;
for(e=0;e<ob->prog->num_variables;e++)
{
CCALL((check_short_svalue(ob->variables+e, ob->prog->variable_names[e].rttype)),fprintf(stderr,"Found in variable\n"));
}
CCALL((check_string(ob->obj_index)),fprintf(stderr,"It's the index of an object.\n"));
CCALL((check_string(ob->user)),fprintf(stderr,"Found in uid.\n"));
CCALL((check_string(ob->eff_user)),fprintf(stderr,"Found in euid.\n"));
if(ob->sentences)
{
for(e=0;e<ob->sentences->slots;e++)
{
if(!ob->sentences->sent[e].match) continue;
CCALL((check_string(ob->sentences->sent[e].match)),fprintf(stderr,"It's match in an add_action\n"));
CCALL((check_svalues(&(ob->sentences->sent[e].function),1)),fprintf(stderr,"It's the function name in an add_action\n"));
}
}
CCALL((check_program(ob->prog)),fprintf(stderr,"Found in program %s\n",ob->prog->name));
RETURN;
}
static RETTYPE check_svalues(struct svalue *s,int number)
{
int e;
RETDECL;
for(e=0;e<number;e++,s++)
{
switch(s->type)
{
case T_STRING:
CCALL((check_string(strptr(s))),fprintf(stderr,"In shared string svalue.\n"));
break;
case T_MAPPING:
case T_LIST:
case T_POINTER:
case T_ALIST_PART:
CCALL((check_array(s->u.vec)),
switch(s->type)
{
case T_MAPPING: fprintf(stderr,"In mapping.\n"); break;
case T_LIST: fprintf(stderr,"In list.\n"); break;
case T_POINTER: fprintf(stderr,"In array.\n"); break;
case T_ALIST_PART: fprintf(stderr,"In alist part.\n"); break;
}
);
break;
case T_LVALUE:
CCALL((check_svalues(&(s->u.lvalue->ind),1)),fprintf(stderr,"Found in lvalue index\n"));
case T_OBJECT:
case T_FUNCTION:
CCALL((check_object(s->u.ob)),fprintf(stderr,"Found in object %s\n",s->u.ob->prog->name));
if(s->u.ob->flags & O_DESTRUCTED)
{
short tmp;
tmp=s->type=T_OBJECT;
free_svalue(s);
s->subtype=tmp?NUMBER_DESTRUCTED_OBJECT:NUMBER_DESTRUCTED_FUNCTION;
}
}
}
RETURN;
}
static RETTYPE check_short_svalue(union storage_union *u,int type)
{
RETDECL;
if(u->number)
{
switch(type)
{
case T_ANY:
CCALL((check_svalues((struct svalue *)u,1)),);
case T_NOTHING:
break;
case T_STRING:
CCALL((check_string(strptr2(*u))),fprintf(stderr,"In shared string svalue.\n"));
break;
case T_MAPPING:
case T_LIST:
case T_POINTER:
case T_ALIST_PART:
CCALL((check_array(u->vec)),
switch(type)
{
case T_MAPPING: fprintf(stderr,"In mapping.\n"); break;
case T_LIST: fprintf(stderr,"In list.\n"); break;
case T_POINTER: fprintf(stderr,"In array.\n"); break;
case T_ALIST_PART: fprintf(stderr,"In alist part.\n"); break;
}
);
break;
case T_OBJECT:
case T_FUNCTION:
CCALL((check_object(u->ob)),fprintf(stderr,"Found in object %s\n",u->ob->prog->name));
if(u->ob->flags & O_DESTRUCTED)
{
free_short_svalue(u,type);
}
}
}
RETURN;
}
static RETTYPE check_str_ref_from_call_outs()
{
int e;
RETDECL;
for(e=0;e<num_pending_calls;e++)
{
CCALL((check_object(pending_calls[e]->command_giver)),fprintf(stderr,"Was command giver in call_out.\n"));
CCALL((check_array(pending_calls[e]->args)),fprintf(stderr,"Was in argument list for call_out.\n"));
}
RETURN;
}
extern struct svalue start_of_stack[EVALUATOR_STACK_SIZE];
extern struct lpc_socket lpc_socks[MAX_EFUN_SOCKS];
extern struct svalue *sp;
extern struct object *obj_list;
extern struct object *obj_list_destruct;
extern char **inc_list;
extern int inc_list_size;
extern struct svalue ret_value;
extern struct program *obj_table[OTABLE_SIZE];
extern struct keyword predefs[],reswords[];
extern int real_number_predefs,number_reswords;
extern char *last_file;
extern struct object *master_ob;
extern struct vector null_vector;
extern int batch_mode;
static void check_even_more_ref_counts2()
{
int e,q;
struct object *ob;
struct program *p;
#ifdef DEBUG
struct vector *v;
#endif
RETDECL;
check_str_ref_from_call_outs();
q=sp-start_of_stack+1;
for(e=0;e<num_lfuns;e++)
{
CCALL((check_string(lfuns[e])),fprintf(stderr,"Was an lfun\n"));
}
CCALL((check_svalues(start_of_stack,q)),fprintf(stderr,"Was found on stack\n"));
#ifdef YYOPT
for(e=0;e<real_number_predefs;e++)
{
CCALL((check_string(predefs[e].word)),fprintf(stderr,"Was efun name\n"));
}
for(e=0;e<number_reswords;e++)
{
CCALL((check_string(reswords[e].word)),fprintf(stderr,"Was a reserved word\n"));
}
#endif
for(e=0;e<OTABLE_SIZE;e++)
{
for(p=obj_table[e];p;p=p->next_hash)
{
CCALL((check_program(p)),fprintf(stderr,"Found in prog %s\n",p->name));
}
}
for(ob=obj_list; ob; ob = ob->next_all)
{
CCALL((check_object(ob)),fprintf(stderr,"Found in object %s\n",ob->prog->name));
}
for(ob=obj_list_destruct; ob; ob = ob->next_all)
{
CCALL((check_object(ob)),fprintf(stderr,"Found in destructed object %s\n",ob->prog->name));
}
CCALL((check_object(master_ob)),fprintf(stderr,"Found master object\n"));
for(e=0;e<inc_list_size;e++)
{
CCALL((check_string(inc_list[e])),fprintf(stderr,"Found in include path.\n"));
}
for(e=0;e<num_simul_efuns;e++)
{
CCALL((check_string(simul_efuns[e].name)),fprintf(stderr,"Is the name of a simul_efun.\n"));
CCALL((check_svalues(&(simul_efuns[e].fun),1)),fprintf(stderr,"Found in a simul efun svalue.\n"));
}
CCALL((check_svalues(&ret_value,1)),fprintf(stderr,"Was last returned value.\n"));
CCALL((check_svalues(&const_empty_string,1)),fprintf(stderr,"Was the empty string.\n"));
CCALL((check_string(hostname)),fprintf(stderr,"Was hostname.\n"));
CCALL((check_string(last_file)),fprintf(stderr,"Was filename of last database.\n"));
#ifdef ADD_CACHE_SIZE
for(e=0;e<ADD_CACHE_SIZE;e++)
{
CCALL((check_string(add_cache[e].a)),fprintf(stderr,"Was in add cache.\n"));
CCALL((check_string(add_cache[e].b)),fprintf(stderr,"Was in add cache.\n"));
CCALL((check_string(add_cache[e].sum)),fprintf(stderr,"Was in add cache.\n"));
}
#endif
for(e=0;e<MAX_EFUN_SOCKS;e++)
{
CCALL((check_svalues(&(lpc_socks[e].read_callback),1)),fprintf(stderr,"Was read callback svalue.\n"));
CCALL((check_svalues(&(lpc_socks[e].write_callback),1)),fprintf(stderr,"Was write callback svalue.\n"));
CCALL((check_svalues(&(lpc_socks[e].close_callback),1)),fprintf(stderr,"Was close callback svalue.\n"));
}
CCALL((check_array(&null_vector)),fprintf(stderr,"Was null vector.\n"));
#ifdef DEBUG
for(v=&null_vector;v;v=v->next)
{
CCALL((check_array(v)),fprintf(stderr,"Was in an array.\n"));
}
#endif
}
static void check_even_more_ref_counts()
{
if(ref_cycle)
{
ref_cycle=0;
}else{
ref_cycle=O_REF_CYCLE;
}
check_even_more_ref_counts2();
}
static last_gc;
void stralloc_gc(int force)
{
#if !defined(STRALLOC_REFS) || defined(DEBUG)
char *c;
int e;
#endif
extern int current_time;
#ifdef DEBUG
struct program *p;
struct object *ob;
struct vector *v;
#endif
if(d_flag<3 && !force && current_time-last_gc>STRALLOC_GC_TIME) return;
last_gc=current_time;
#ifdef ADD_CACHE_SIZE
clean_add_cache();
#endif
#ifdef DEBUG
for(e=0;e<OTABLE_SIZE;e++)
for(p=obj_table[e];p;p=p->next_hash)
p->extra_ref=-1;
for(ob=obj_list; ob; ob = ob->next_all)
ob->extra_ref=-1;
for(v=&null_vector; v; v = v->next)
v->extra_ref=-1;
check_ref_cycle=1;
check_even_more_ref_counts2();
check_ref_cycle=0;
string_to_find=0;
refchecked=1;
#endif
#ifdef STRALLOC_GC
for(e=0;e<HTABLE_SIZE;e++)
{
char **prev;
for(prev=base_table+e;(c=*prev);prev=&(NEXT(c)))
SIZE(c)=-SIZE(c);
}
#endif
#if defined(DEBUG) && !defined(STRALLOC_GC)
for(e=0;e<HTABLE_SIZE;e++)
{
char **prev;
for(prev=base_table+e;(c=*prev);prev=&(NEXT(c)))
XREF(c)=0;
}
#endif
#if !defined(STRALLOC_GC) && !defined(DEBUG)
if(force)
#endif
check_even_more_ref_counts();
#ifdef DEBUG
for(e=0;e<OTABLE_SIZE;e++)
{
for(p=obj_table[e];p;p=p->next_hash)
{
if(p->extra_ref!=p->ref)
{
fprintf(stderr,"Warning: program '%s' had %d refs, expected %d\n",p->name,p->ref,p->extra_ref);
string_to_find=p;
check_even_more_ref_counts();
if(d_flag>4) fatal("Error in object refs.\n");
}
}
}
for(ob=obj_list; ob; ob = ob->next_all)
{
if(ob->extra_ref!=ob->ref)
{
fprintf(stderr,"Warning: object %s#%d had %d refs, expected %d\n",ob->prog->name,ob->clone_number,ob->ref,ob->extra_ref);
string_to_find=ob;
check_even_more_ref_counts();
if(d_flag>4) fatal("Error in object refs.\n");
}
}
for(v=&null_vector; v; v = v->next)
{
if(v->extra_ref-1!=v->ref)
{
fprintf(stderr,"Warning: array had %d refs, expected %d\n",v->ref,v->extra_ref-1);
init_buf();
my_strcat("({");
debug_save_svalue_list(v);
my_strcat("})");
fprintf(stderr,"%s\n",return_buf());
string_to_find=v;
check_even_more_ref_counts();
if(d_flag>4) fatal("Error in array refs.\n");
}
}
#ifndef STRALLOC_GC
for(e=0;e<HTABLE_SIZE;e++)
{
for(c=base_table[e];c;c=NEXT(c))
{
if(XREF(c)!=REFS(c))
{
fprintf(stderr,"Warning: '%s' had %d refs, expected %d\n",c,REFS(c),XREF(c));
string_to_find=c;
check_even_more_ref_counts();
if(d_flag>4) fatal("Error in string refs.\n");
}
}
}
#endif
#endif
#ifndef STRALLOC_REFS
for(e=0;e<HTABLE_SIZE;e++)
{
char **prev;
for(prev=base_table+e;(c=*prev);prev=&(NEXT(c)))
{
#ifdef STRALLOC_HYBRID
if(!REFS(c))
#else
if(SIZE(c)<0)
#endif
{
terminally_free_string(prev,c);
}else{
prev=&(NEXT(c));
}
}
}
#endif
}
void not_backend_stralloc_gc()
{
/* we can't run gc here because pointers might be in local
* variables and such. *sigh*
*/
last_gc=0;
}
void dump_stralloc_strings()
{
int e;
char *p;
for(e=0;e<HTABLE_SIZE;e++)
for(p=base_table[e];p;p=NEXT(p))
printf("%d refs \"%s\"",REFS(p),p);
}