/* cache2.c */
#include "config.h"
#include "object.h"
#include "globals.h"
#include "construct.h"
#include "dbhandle.h"
#include "interp.h"
#include "file.h"
#include "compile.h"
#include "clearq.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;
};
extern struct obj_link *hash_list[CACHE_HASH];
extern struct obj_link *cache_head;
extern struct obj_link *cache_tail;
extern 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. */
extern int access_load_file;
struct object *db_ref_to_obj(signed long refno);
void pass_data(FILE *infile);
void writeinstr(FILE *outfile, struct var *v);
char *readstring(FILE *infile);
void readinstr(FILE *infile, struct var *v);
void writedata(FILE *outfile, struct object *obj);
void readdata(FILE *infile, struct object *obj);
void freedata(struct object *obj);
void write_filesystem(FILE *outfile, struct file_entry *parent_dir,
char *parent_dir_name);
signed long db_obj_to_ref(struct object *obj);
void writeverb(FILE *outfile, struct verb *curr_verb);
int manual_move(char *oldname, char *newname) {
FILE *oldf,*newf;
int c;
oldf=fopen(oldname,"r");
if (!oldf) return 1;
newf=fopen(newname,"w");
if (!newf) {
fclose(oldf);
return 1;
}
c=fgetc(oldf);
while (c!=(-1)) {
fputc(c,newf);
c=fgetc(oldf);
}
fclose(oldf);
fclose(newf);
remove(oldname);
return 0;
}
int save_db(char *filename) {
long count,index,place,loop;
struct obj_blk *curr_block;
struct cmdq *curr_cmd;
struct alarmq *curr_alarm;
struct object *curr_obj;
struct file_entry *curr_file;
FILE *outfile,*infile,*file3,*cachefile;
char *buf1,*buf2;
struct proto *curr_proto;
struct fns *curr_fns;
struct var_tab *curr_var;
struct array_size *curr_array;
cachefile=fopen(cache_path,"r");
outfile=fopen(tmpdb_path,"w");
if (!outfile) {
if (cachefile) fclose(cachefile);
log_sysmsg(" cache: save_db() couldn't write to temporary database");
return 1;
}
if (access_load_file==1)
infile=fopen(load_name,"r");
else
if (access_load_file==0)
infile=fopen(save_name,"r");
else
infile=NULL;
if (access_load_file!=(-1) && !infile) {
log_sysmsg(" cache: save_db() couldn't read from database");
fclose(outfile);
return 1;
}
count=0;
index=0;
curr_block=obj_list;
curr_file=root_dir;
fprintf(outfile,"%s%ld\n%d\n%ld\n",DB_IDENSTR,(long) db_top,
(int) root_dir->flags,(long) root_dir->owner);
write_filesystem(outfile,root_dir,"");
fprintf(outfile,".END\n");
while (count<db_top) {
curr_obj=&(curr_block->block[index]);
fprintf(outfile,"%ld\n",(long) curr_obj->flags);
fprintf(outfile,"%ld\n",(long) db_obj_to_ref(curr_obj->next_child));
fprintf(outfile,"%ld\n",(long) db_obj_to_ref(curr_obj->location));
fprintf(outfile,"%ld\n",(long) db_obj_to_ref(curr_obj->contents));
fprintf(outfile,"%ld\n",(long) db_obj_to_ref(curr_obj->next_object));
if (curr_obj->obj_state==IN_DB) {
place=ftell(outfile);
fseek(infile,curr_obj->file_offset,SEEK_SET);
readdata(infile,curr_obj);
writedata(outfile,curr_obj);
freedata(curr_obj);
curr_obj->file_offset=place;
} else
if (curr_obj->obj_state==IN_CACHE) {
if (!cachefile) {
log_sysmsg(" cache: save_db() couldn't read from cache");
return 1;
}
place=ftell(outfile);
fseek(cachefile,curr_obj->file_offset,SEEK_SET);
readdata(cachefile,curr_obj);
writedata(outfile,curr_obj);
freedata(curr_obj);
curr_obj->file_offset=place;
curr_obj->obj_state=IN_DB;
} else {
place=ftell(outfile);
writedata(outfile,curr_obj);
curr_obj->file_offset=place;
curr_obj->obj_state=FROM_DB;
}
writeverb(outfile,curr_obj->verb_list);
fprintf(outfile,".END\n");
count++;
index++;
if (index==OBJ_ALLOC_BLKSIZ) {
index=0;
curr_block=curr_block->next;
}
}
if (cachefile) fclose(cachefile);
remove(cache_path);
cache_top=0;
curr_proto=ref_to_obj(0)->parent;
while (curr_proto) {
fprintf(outfile,"%s\n%ld\n%ld\n",curr_proto->pathname,
(long) curr_proto->proto_obj->refno,
(long) curr_proto->funcs->num_globals);
curr_var=curr_proto->funcs->gst;
while (curr_var) {
fprintf(outfile,"*%s\n%d\n",curr_var->name,(int) curr_var->base);
curr_array=curr_var->array;
while (curr_array) {
fprintf(outfile,"%d\n",(int) curr_array->size);
curr_array=curr_array->next;
}
fprintf(outfile,"\n");
curr_var=curr_var->next;
}
curr_fns=curr_proto->funcs->func_list;
while (curr_fns) {
fprintf(outfile,"%d\n%ld\n%ld\n%ld\n%ld\n%s",
(int) curr_fns->is_static,
(long) curr_fns->num_args,
(long) curr_fns->num_locals,
(long) curr_fns->num_instr,
(long) strlen(curr_fns->funcname),
curr_fns->funcname);
loop=0;
while (loop<curr_fns->num_instr) {
writeinstr(outfile,&(curr_fns->code[loop]));
loop++;
}
curr_fns=curr_fns->next;
}
fprintf(outfile,".END\n");
curr_proto=curr_proto->next_proto;
}
fprintf(outfile,".END\n");
curr_cmd=cmd_head;
while (curr_cmd) {
fprintf(outfile,"%ld\n%ld\n%s",(long) curr_cmd->obj->refno,
(long) strlen(curr_cmd->cmd),
curr_cmd->cmd);
curr_cmd=curr_cmd->next;
}
fprintf(outfile,".END\n");
curr_alarm=alarm_list;
while (curr_alarm) {
fprintf(outfile,"%ld\n%ld\n%ld\n%s",(long) curr_alarm->obj->refno,
(long) curr_alarm->delay,
(long) strlen(curr_alarm->funcname),
curr_alarm->funcname);
curr_alarm=curr_alarm->next;
}
fprintf(outfile,".END\n");
fprintf(outfile,"db.END\n");
fclose(outfile);
if (infile) fclose(infile);
if (filename)
if (strcmp(save_name,filename)) {
FREE(save_name);
save_name=copy_string(filename);
}
remove(save_name);
if (rename(tmpdb_path,save_name))
if (manual_move(tmpdb_path,save_name)) {
log_sysmsg(" cache: save_db() couldn't move temporary database to "
"save database");
return 1;
}
access_load_file=0;
return 0;
}
int init_db() {
FILE *infile;
char *buf;
char *string,*string2;
signed long flags,uid,count,num_blocks,loop1,loop2,index;
struct obj_blk *curr_block,*object_block;
unsigned int num_globals;
struct verb *verbptr;
unsigned char is_xverb;
struct proto *curr_proto;
struct object *curr_obj;
struct fns *curr_fns;
char c;
struct array_size *new_array,*curr_array;
struct var_tab *new_var,*curr_var;
access_load_file=1;
infile=fopen(load_name,"r");
if (!infile) {
log_sysmsg(" cache: init_db() couldn't read from database");
return 1;
}
buf=MALLOC(MAX_STR_LEN);
fgets(buf,MAX_STR_LEN,infile);
if (strcmp(buf,DB_IDENSTR)) {
FREE(buf);
buf=MALLOC(strlen(load_name)+28);
sprintf(buf," system: %s not a CI database",load_name);
log_sysmsg(buf);
FREE(buf);
fclose(infile);
return 1;
}
fgets(buf,MAX_STR_LEN,infile);
db_top=atol(buf);
if (db_top<=0) {
FREE(buf);
buf=MALLOC(strlen(load_name)+43);
sprintf(buf," system: %s corrupt (while reading db_top)",load_name);
log_sysmsg(buf);
FREE(buf);
fclose(infile);
return 1;
}
num_blocks=db_top/OBJ_ALLOC_BLKSIZ+1;
objects_allocd=num_blocks*OBJ_ALLOC_BLKSIZ;
obj_list=NULL;
free_obj_list=NULL;
loop1=0;
while (loop1<num_blocks) {
object_block=MALLOC(sizeof(struct obj_blk));
object_block->block=MALLOC(sizeof(struct object)*OBJ_ALLOC_BLKSIZ);
object_block->next=obj_list;
obj_list=object_block;
loop1++;
}
count=0;
fgets(buf,MAX_STR_LEN,infile);
root_dir->flags=atoi(buf);
fgets(buf,MAX_STR_LEN,infile);
root_dir->owner=atol(buf);
fgets(buf,MAX_STR_LEN,infile);
while (strcmp(buf,".END\n")) {
if (feof(infile)) {
FREE(buf);
buf=MALLOC(strlen(load_name)+47);
sprintf(buf," system: %s corrupt (while reading filesystem)",load_name);
log_sysmsg(buf);
FREE(buf);
fclose(infile);
return 1;
}
string=copy_string(buf);
string[strlen(string)-1]='\0';
fgets(buf,MAX_STR_LEN,infile);
flags=atoi(buf);
fgets(buf,MAX_STR_LEN,infile);
uid=atol(buf);
db_add_entry(string,uid,flags);
FREE(string);
fgets(buf,MAX_STR_LEN,infile);
}
count=0;
curr_block=obj_list;
index=0;
while (count<db_top) {
if (feof(infile)) {
FREE(buf);
buf=MALLOC(strlen(load_name)+48+ITOA_BUFSIZ);
sprintf(buf," system: %s corrupt (while reading object #%ld)",load_name,
(long) count);
log_sysmsg(buf);
FREE(buf);
fclose(infile);
return 1;
}
curr_block->block[index].refno=count;
curr_block->block[index].devnum=-1;
fgets(buf,MAX_STR_LEN,infile);
flags=atoi(buf);
flags&=~(IN_EDITOR | RESIDENT);
curr_block->block[index].flags=flags;
fgets(buf,MAX_STR_LEN,infile);
curr_block->block[index].next_child=db_ref_to_obj(atol(buf));
fgets(buf,MAX_STR_LEN,infile);
curr_block->block[index].location=db_ref_to_obj(atol(buf));
fgets(buf,MAX_STR_LEN,infile);
curr_block->block[index].contents=db_ref_to_obj(atol(buf));
fgets(buf,MAX_STR_LEN,infile);
curr_block->block[index].next_object=db_ref_to_obj(atol(buf));
curr_block->block[index].file_offset=ftell(infile);
if (flags & GARBAGE)
curr_block->block[index].obj_state=DIRTY;
else
curr_block->block[index].obj_state=IN_DB;
curr_block->block[index].globals=NULL;
curr_block->block[index].refd_by=NULL;
curr_block->block[index].verb_list=NULL;
if (flags & GARBAGE) {
curr_block->block[index].next_object=free_obj_list;
free_obj_list=&(curr_block->block[index]);
}
pass_data(infile);
fgets(buf,MAX_STR_LEN,infile);
while (strcmp(buf,".END\n") && !(feof(infile))) {
is_xverb=atoi(buf);
string=readstring(infile);
string2=readstring(infile);
verbptr=MALLOC(sizeof(struct verb));
verbptr->verb_name=string;
verbptr->is_xverb=is_xverb;
verbptr->function=string2;
verbptr->next=curr_block->block[index].verb_list;
curr_block->block[index].verb_list=verbptr;
fgets(buf,MAX_STR_LEN,infile);
}
count++;
index++;
if (index==OBJ_ALLOC_BLKSIZ) {
index=0;
curr_block=curr_block->next;
}
}
fgets(buf,MAX_STR_LEN,infile);
while (strcmp(buf,".END\n")) {
if (feof(infile)) {
FREE(buf);
buf=MALLOC(strlen(load_name)+47);
sprintf(buf," system: %s corrupt (while reading prototypes)",load_name);
log_sysmsg(buf);
FREE(buf);
fclose(infile);
return 1;
}
curr_proto=MALLOC(sizeof(struct proto));
buf[strlen(buf)-1]='\0';
curr_proto->pathname=copy_string(buf);
fgets(buf,MAX_STR_LEN,infile);
curr_proto->proto_obj=db_ref_to_obj(atol(buf));
curr_obj=curr_proto->proto_obj;
while (curr_obj) {
curr_obj->parent=curr_proto;
curr_obj=curr_obj->next_child;
}
curr_obj=db_ref_to_obj(0);
if (curr_obj->parent!=curr_proto) {
curr_proto->next_proto=curr_obj->parent->next_proto;
curr_obj->parent->next_proto=curr_proto;
} else
curr_proto->next_proto=NULL;
curr_proto->funcs=MALLOC(sizeof(struct code));
fgets(buf,MAX_STR_LEN,infile);
num_globals=atoi(buf);
curr_proto->funcs->num_globals=num_globals;
curr_proto->funcs->func_list=NULL;
curr_proto->funcs->gst=NULL;
c=fgetc(infile);
curr_var=NULL;
while (c=='*' && !feof(infile)) {
new_var=MALLOC(sizeof(struct var_tab));
fgets(buf,MAX_STR_LEN,infile);
buf[strlen(buf)-1]='\0';
new_var->name=copy_string(buf);
fgets(buf,MAX_STR_LEN,infile);
new_var->base=atoi(buf);
fgets(buf,MAX_STR_LEN,infile);
new_var->array=NULL;
new_var->next=NULL;
curr_array=NULL;
while (strcmp(buf,"\n") && !feof(infile)) {
new_array=MALLOC(sizeof(struct array_size));
new_array->size=atoi(buf);
if (curr_array)
curr_array->next=new_array;
else
new_var->array=new_array;
new_array->next=NULL;
curr_array=new_array;
fgets(buf,MAX_STR_LEN,infile);
}
if (curr_var)
curr_var->next=new_var;
else
curr_proto->funcs->gst=new_var;
curr_var=new_var;
c=fgetc(infile);
}
ungetc(c,infile);
fgets(buf,MAX_STR_LEN,infile);
while (strcmp(buf,".END\n")) {
if (feof(infile)) {
FREE(buf);
buf=MALLOC(strlen(load_name)+46);
sprintf(buf," system: %s corrupt (while reading functions)",load_name);
log_sysmsg(buf);
FREE(buf);
fclose(infile);
return 1;
}
curr_fns=MALLOC(sizeof(struct fns));
curr_fns->is_static=atoi(buf);
fgets(buf,MAX_STR_LEN,infile);
curr_fns->num_args=atoi(buf);
fgets(buf,MAX_STR_LEN,infile);
curr_fns->num_locals=atoi(buf);
fgets(buf,MAX_STR_LEN,infile);
curr_fns->num_instr=atol(buf);
curr_fns->funcname=readstring(infile);
curr_fns->next=curr_proto->funcs->func_list;
curr_proto->funcs->func_list=curr_fns;
if (curr_fns->num_instr)
curr_fns->code=MALLOC(sizeof(struct var)*(curr_fns->num_instr));
else
curr_fns->code=NULL;
loop1=0;
while (loop1<curr_fns->num_instr) {
readinstr(infile,&(curr_fns->code[loop1]));
loop1++;
}
fgets(buf,MAX_STR_LEN,infile);
}
fgets(buf,MAX_STR_LEN,infile);
}
fgets(buf,MAX_STR_LEN,infile);
while (strcmp(buf,".END\n")) {
if (feof(infile)) {
FREE(buf);
buf=MALLOC(strlen(load_name)+45);
sprintf(buf," system: %s corrupt (while reading commands)",load_name);
log_sysmsg(buf);
FREE(buf);
fclose(infile);
return 1;
}
curr_obj=db_ref_to_obj(atol(buf));
string=readstring(infile);
queue_command(curr_obj,string);
FREE(string);
fgets(buf,MAX_STR_LEN,infile);
}
fgets(buf,MAX_STR_LEN,infile);
while (strcmp(buf,".END\n")) {
if (feof(infile)) {
FREE(buf);
buf=MALLOC(strlen(load_name)+43);
sprintf(buf," system: %s corrupt (while reading alarms)",load_name);
log_sysmsg(buf);
FREE(buf);
fclose(infile);
return 1;
}
curr_obj=db_ref_to_obj(atol(buf));
fgets(buf,MAX_STR_LEN,infile);
count=atol(buf);
string=readstring(infile);
db_queue_for_alarm(curr_obj,count,string);
FREE(string);
fgets(buf,MAX_STR_LEN,infile);
}
fgets(buf,MAX_STR_LEN,infile);
if (feof(infile) || strcmp(buf,"db.END\n")) {
FREE(buf);
buf=MALLOC(strlen(load_name)+45);
sprintf(buf," system: %s corrupt (no db.END magic cookie)",load_name);
log_sysmsg(buf);
FREE(buf);
fclose(infile);
return 1;
}
FREE(buf);
fclose(infile);
return 0;
}
int create_db() {
struct code *the_code;
unsigned int result;
struct object *obj;
struct proto *proto_obj;
long loop;
struct fns *init_func;
struct var_stack *rts;
struct var tmp;
access_load_file=-1;
db_add_entry("/boot.c",0,0);
result=parse_code("/boot",NULL,&the_code);
if (result==((unsigned int) -1)) return 1;
if (result) {
compile_error(NULL,"/boot",result);
return 1;
}
obj=newobj();
proto_obj=MALLOC(sizeof(struct proto));
proto_obj->pathname=copy_string("/boot");
proto_obj->funcs=the_code;
proto_obj->proto_obj=obj;
proto_obj->next_proto=NULL;
obj->refno=0;
obj->devnum=-1;
obj->flags=PROTOTYPE | PRIV;
obj->parent=proto_obj;
obj->next_child=NULL;
obj->location=NULL;
obj->contents=NULL;
obj->next_object=NULL;
if (the_code->num_globals) {
obj->globals=MALLOC(sizeof(struct var)*(the_code->num_globals));
loop=0;
while (loop<the_code->num_globals) {
obj->globals[loop].type=INTEGER;
obj->globals[loop].value.integer=0;
loop++;
}
} else
obj->globals=NULL;
obj->refd_by=NULL;
obj->verb_list=NULL;
add_loaded(obj);
obj->obj_state=DIRTY;
#ifdef CYCLE_HARD_MAX
hard_cycles=0;
#endif /* CYCLE_HARD_MAX */
#ifdef CYCLE_SOFT_MAX
soft_cycles=0;
#endif /* CYCLE_SOFT_MAX */
init_func=find_fns("init",obj);
if (init_func) {
rts=NULL;
tmp.type=NUM_ARGS;
tmp.value.num=0;
push(&tmp,&rts);
interp(NULL,obj,NULL,&rts,init_func);
free_stack(&rts);
}
handle_destruct();
return 0;
}