/* cache1.c */
#include "config.h"
#include "object.h"
#include "globals.h"
#include "construct.h"
#include "dbhandle.h"
#include "interp.h"
#include "file.h"
struct obj_link {
struct object *obj;
struct obj_link *prev_link;
struct obj_link *next_link;
struct obj_link *prev_queue;
struct obj_link *next_queue;
};
struct obj_link *hash_list[CACHE_HASH];
struct obj_link *cache_head;
struct obj_link *cache_tail;
signed long loaded_obj_count;
/* if access_load_file is 0, then all loads from the db will be from
the save_name file. if it is non-zero, loads will be from the
load_name file. */
int access_load_file;
signed long db_obj_to_ref(struct object *obj) {
if (!obj) return -1;
return obj->refno;
}
struct obj_link *find_cache(struct object *obj) {
struct obj_link *curr_link;
curr_link=hash_list[obj->refno%CACHE_HASH];
while (curr_link) {
if (curr_link->obj==obj)
return curr_link;
curr_link=curr_link->next_link;
}
return NULL;
}
void write_filesystem(FILE *outfile, struct file_entry *parent_dir,
char *parent_dir_name) {
struct file_entry *curr_entry;
char *buf;
curr_entry=parent_dir->contents;
while (curr_entry) {
fprintf(outfile,"%s/%s\n%ld\n%ld\n",parent_dir_name,
curr_entry->filename,
(long) curr_entry->flags,
(long) curr_entry->owner);
if (curr_entry->contents) {
buf=MALLOC(strlen(parent_dir_name)+strlen(curr_entry->filename)+2);
sprintf(buf,"%s/%s",parent_dir_name,curr_entry->filename);
write_filesystem(outfile,curr_entry,buf);
FREE(buf);
}
curr_entry=curr_entry->next_file;
}
}
void freedata(struct object *obj) {
long loop;
struct ref_list *curr,*next;
loop=0;
if (obj->globals) {
while (loop<obj->parent->funcs->num_globals) {
if (obj->globals[loop].type==STRING)
FREE(obj->globals[loop].value.string);
loop++;
}
FREE(obj->globals);
obj->globals=NULL;
}
curr=obj->refd_by;
while (curr) {
next=curr->next;
FREE(curr);
curr=next;
}
obj->refd_by=NULL;
obj->flags&=~(RESIDENT);
}
struct object *db_ref_to_obj(signed long refno) {
struct obj_blk *curr;
signed long count,index;
if (refno<0) return NULL;
count=refno/OBJ_ALLOC_BLKSIZ;
index=refno%OBJ_ALLOC_BLKSIZ;
curr=obj_list;
while (count--)
curr=curr->next;
return &(curr->block[index]);
}
void init_globals(char *loadpath, char *savepath, char *panicpath) {
signed long loop;
cache_top=0;
loop=0;
while (loop<CACHE_HASH) {
hash_list[loop]=NULL;
loop++;
}
db_top=0;
edit_list=NULL;
cache_head=NULL;
cache_tail=NULL;
loaded_obj_count=0;
root_dir=MALLOC(sizeof(struct file_entry));
root_dir->filename=copy_string("");
root_dir->flags=READ_OK | DIRECTORY;
root_dir->owner=0;
root_dir->contents=NULL;
root_dir->parent=NULL;
root_dir->prev_file=NULL;
root_dir->next_file=NULL;
num_locals=0;
locals=NULL;
c_err_msg=NULL;
cmd_head=NULL;
cmd_tail=NULL;
dest_list=NULL;
alarm_list=NULL;
now_time=time2int(time(NULL));
obj_list=NULL;
if (loadpath)
load_name=copy_string(loadpath);
else
load_name=copy_string(DEFAULT_LOAD);
if (savepath)
save_name=copy_string(savepath);
else
save_name=copy_string(DEFAULT_SAVE);
if (panicpath)
panic_name=copy_string(panicpath);
else
panic_name=copy_string(DEFAULT_PANIC);
free_obj_list=NULL;
objects_allocd=0;
db_top=0;
}
void pass_data(FILE *infile) {
char c;
char buf[ITOA_BUFSIZ+1];
int done;
long count;
done=0;
while (!done) {
c=fgetc(infile);
switch (c) {
case 'I':
case 'O':
fgets(buf,ITOA_BUFSIZ+1,infile);
break;
case 'S':
fgets(buf,ITOA_BUFSIZ+1,infile);
count=atol(buf);
while (count--) fgetc(infile);
break;
case '.':
done=1;
break;
case EOF:
return;
break;
}
}
fgets(buf,ITOA_BUFSIZ+1,infile);
c=fgetc(infile);
while (c!='.' && c!=EOF) c=fgetc(infile);
fgets(buf,ITOA_BUFSIZ+1,infile);
}
void writeinstr(FILE *outfile,struct var *v) {
if (v->type==FUNC_CALL)
fprintf(outfile,"%d\n",(int) FUNC_NAME);
else
fprintf(outfile,"%d\n",(int) v->type);
switch (v->type) {
case INTEGER:
fprintf(outfile,"%ld\n",(long) v->value.integer);
break;
case STRING:
case FUNC_NAME:
fprintf(outfile,"%ld\n%s",(long) strlen(v->value.string),
v->value.string);
break;
case OBJECT:
fprintf(outfile,"%ld\n",(long) v->value.objptr->refno);
break;
case ASM_INSTR:
fprintf(outfile,"%d\n",(int) v->value.instruction);
break;
case GLOBAL_L_VALUE:
case LOCAL_L_VALUE:
fprintf(outfile,"%d\n%d\n",(int) v->value.l_value.ref,
(int) v->value.l_value.size);
break;
case FUNC_CALL:
fprintf(outfile,"%ld\n%s",(long) strlen(v->value.func_call->funcname),
v->value.func_call->funcname);
break;
case NUM_ARGS:
case ARRAY_SIZE:
case JUMP:
case BRANCH:
case NEW_LINE:
fprintf(outfile,"%ld\n",(long) v->value.num);
break;
default:
break;
}
}
char *readstring(FILE *infile) {
static char buf[ITOA_BUFSIZ+1];
static char *string;
static long len,loop;
fgets(buf,ITOA_BUFSIZ+1,infile);
len=atol(buf);
loop=0;
string=MALLOC(len+1);
while (loop<len) {
string[loop]=fgetc(infile);
loop++;
}
string[loop]='\0';
return string;
}
void readinstr(FILE *infile,struct var *v) {
static char type;
static char buf[ITOA_BUFSIZ+1];
fgets(buf,ITOA_BUFSIZ+1,infile);
type=atoi(buf);
v->type=type;
switch (type) {
case INTEGER:
fgets(buf,ITOA_BUFSIZ+1,infile);
v->value.integer=atol(buf);
break;
case STRING:
case FUNC_NAME:
v->value.string=readstring(infile);
break;
case OBJECT:
fgets(buf,ITOA_BUFSIZ+1,infile);
v->value.objptr=db_ref_to_obj(atol(buf));
break;
case ASM_INSTR:
fgets(buf,ITOA_BUFSIZ+1,infile);
v->value.instruction=atoi(buf);
break;
case GLOBAL_L_VALUE:
case LOCAL_L_VALUE:
fgets(buf,ITOA_BUFSIZ+1,infile);
v->value.l_value.ref=atoi(buf);
fgets(buf,ITOA_BUFSIZ+1,infile);
v->value.l_value.size=atoi(buf);
break;
case NUM_ARGS:
case ARRAY_SIZE:
case JUMP:
case BRANCH:
case NEW_LINE:
fgets(buf,ITOA_BUFSIZ+1,infile);
v->value.num=atol(buf);
break;
default:
break;
}
}
void writedata(FILE *outfile,struct object *obj) {
long loop;
struct ref_list *curr;
loop=0;
if (obj->flags & GARBAGE) {
fprintf(outfile,".END\n.END\n");
return;
}
while (loop<obj->parent->funcs->num_globals) {
switch (obj->globals[loop].type) {
case INTEGER:
fprintf(outfile,"I%ld\n",(long) obj->globals[loop].value.integer);
break;
case OBJECT:
fprintf(outfile,"O%ld\n",(long) obj->globals[loop].value.objptr->
refno);
break;
case STRING:
fprintf(outfile,"S%ld\n%s",(long) strlen(obj->globals[loop].value.
string),obj->globals[loop].value.string);
break;
default:
fprintf(outfile,"?");
break;
}
loop++;
}
fprintf(outfile,".END\n");
curr=obj->refd_by;
while (curr) {
fprintf(outfile,"%ld\n%ld\n",(long) curr->ref_obj->refno,
(long) curr->ref_num);
curr=curr->next;
}
fprintf(outfile,".END\n");
}
void readdata(FILE *infile, struct object *obj) {
long loop;
char c;
char buf[ITOA_BUFSIZ+1];
struct ref_list *curr;
loop=0;
if (obj->parent->funcs->num_globals)
obj->globals=MALLOC(sizeof(struct var)*(obj->parent->funcs->num_globals));
else
obj->globals=NULL;
while (loop<obj->parent->funcs->num_globals) {
c=fgetc(infile);
switch (c) {
case 'I':
obj->globals[loop].type=INTEGER;
fgets(buf,ITOA_BUFSIZ+1,infile);
obj->globals[loop].value.integer=atol(buf);
break;
case 'O':
obj->globals[loop].type=OBJECT;
fgets(buf,ITOA_BUFSIZ+1,infile);
obj->globals[loop].value.objptr=db_ref_to_obj(atol(buf));
break;
case 'S':
obj->globals[loop].type=STRING;
obj->globals[loop].value.string=readstring(infile);
break;
default:
obj->globals[loop].type=INTEGER;
obj->globals[loop].value.integer=0;
break;
}
loop++;
}
fgets(buf,ITOA_BUFSIZ+1,infile);
if (feof(infile) || strcmp(buf,".END\n")) {
log_sysmsg(" cache: readdata() encountered corrupt data");
return;
}
fgets(buf,ITOA_BUFSIZ+1,infile);
while (!feof(infile) && strcmp(buf,".END\n")) {
curr=MALLOC(sizeof(struct ref_list));
curr->ref_obj=db_ref_to_obj(atol(buf));
fgets(buf,ITOA_BUFSIZ+1,infile);
curr->ref_num=atoi(buf);
curr->next=obj->refd_by;
obj->refd_by=curr;
fgets(buf,ITOA_BUFSIZ+1,infile);
}
}
void unload_object(struct object *obj) {
struct obj_link *this_link;
char *buf;
this_link=find_cache(obj);
if (this_link) {
loaded_obj_count--;
if (this_link->prev_link)
this_link->prev_link->next_link=this_link->next_link;
else
hash_list[obj->refno%CACHE_HASH]=this_link->next_link;
if (this_link->next_link)
this_link->next_link->prev_link=this_link->prev_link;
if (this_link->prev_queue)
this_link->prev_queue->next_queue=this_link->next_queue;
else
cache_head=this_link->next_queue;
if (this_link->next_queue)
this_link->next_queue->prev_queue=this_link->prev_queue;
else
cache_tail=this_link->prev_queue;
FREE(this_link);
}
if (obj->obj_state==FROM_DB || obj->obj_state==FROM_CACHE ||
obj->obj_state==DIRTY)
freedata(obj);
obj->obj_state=DIRTY;
obj->flags&=~(RESIDENT);
}
void add_loaded(struct object *obj) {
signed long hash_value;
struct obj_link *new_link;
if (!obj) return;
if (new_link=find_cache(obj)) {
if (new_link->prev_queue)
new_link->prev_queue->next_queue=new_link->next_queue;
if (new_link->next_queue)
new_link->next_queue->prev_queue=new_link->prev_queue;
if (new_link==cache_tail)
cache_tail=new_link->prev_queue;
if (new_link==cache_head)
cache_head=new_link->next_queue;
} else {
hash_value=obj->refno%CACHE_HASH;
new_link=MALLOC(sizeof(struct obj_link));
new_link->obj=obj;
new_link->prev_link=NULL;
new_link->next_link=hash_list[hash_value];
if (hash_list[hash_value])
hash_list[hash_value]->prev_link=new_link;
hash_list[hash_value]=new_link;
loaded_obj_count++;
}
obj->flags|=RESIDENT;
if (cache_head)
cache_head->prev_queue=new_link;
new_link->next_queue=cache_head;
new_link->prev_queue=NULL;
cache_head=new_link;
if (!cache_tail)
cache_tail=new_link;
}
void unload_data() {
struct obj_link *curr_link;
FILE *outfile;
signed long place;
while (loaded_obj_count>CACHE_SIZE) {
curr_link=cache_tail;
curr_link->prev_queue->next_queue=NULL;
cache_tail=curr_link->prev_queue;
if (curr_link->prev_link)
curr_link->prev_link->next_link=curr_link->next_link;
else
hash_list[curr_link->obj->refno%CACHE_HASH]=curr_link->next_link;
if (curr_link->next_link)
curr_link->next_link->prev_link=curr_link->prev_link;
if (curr_link->obj->flags & GARBAGE) {
curr_link->obj->obj_state=DIRTY;
} else
if (curr_link->obj->obj_state==DIRTY) {
outfile=fopen(cache_path,"a");
if (!outfile) {
log_sysmsg(" cache: unload_data() unable to write to cache");
return;
}
place=ftell(outfile);
writedata(outfile,curr_link->obj);
cache_top=ftell(outfile);
fclose(outfile);
curr_link->obj->obj_state=IN_CACHE;
curr_link->obj->file_offset=place;
} else
if (curr_link->obj->obj_state==FROM_DB)
curr_link->obj->obj_state=IN_DB;
else
if (curr_link->obj->obj_state==FROM_CACHE)
curr_link->obj->obj_state=IN_CACHE;
freedata(curr_link->obj);
FREE(curr_link);
loaded_obj_count--;
}
}
void load_data(struct object *obj) {
FILE *infile;
if (obj->flags & RESIDENT) {
add_loaded(obj);
return;
}
if (obj->flags & GARBAGE) return;
if (obj->obj_state==IN_CACHE) {
infile=fopen(cache_path,"r");
if (!infile) {
log_sysmsg(" cache: load_data() unable to read from cache");
return;
}
fseek(infile,obj->file_offset,SEEK_SET);
readdata(infile,obj);
fclose(infile);
obj->obj_state=FROM_CACHE;
} else
if (obj->obj_state==IN_DB) {
infile=fopen((access_load_file ? load_name : save_name),"r");
if (!infile) {
log_sysmsg(" cache: load_data() unable to read from database");
return;
}
fseek(infile,obj->file_offset,SEEK_SET);
readdata(infile,obj);
fclose(infile);
obj->obj_state=FROM_DB;
}
add_loaded(obj);
}
void writeverb(FILE *outfile, struct verb *curr_verb) {
if (!curr_verb) return;
writeverb(outfile,curr_verb->next);
fprintf(outfile,"%d\n%ld\n%s%ld\n%s",(int) curr_verb->is_xverb,
(long) strlen(curr_verb->verb_name),
curr_verb->verb_name,
(long) strlen(curr_verb->function),
curr_verb->function);
}