source: abuse/branches/pd/abuse/src/cache.c @ 636

Last change on this file since 636 was 49, checked in by Sam Hocevar, 15 years ago
  • Imported original public domain release, for future reference.
  • Property svn:keywords set to Id
File size: 28.3 KB
Line 
1#include "cache.hpp"
2#include "lisp.hpp"
3#include "video.hpp"
4#include "dprint.hpp"
5#include "exitproc.hpp"
6#include "lcache.hpp"
7#include "status.hpp"
8#include "game.hpp"
9#include "lisp_gc.hpp"
10#include "level.hpp"
11#include "status.hpp"
12#include "crc.hpp"
13#include "specache.hpp"
14
15#ifndef __POWERPC__
16#include <sys/stat.h>
17#endif
18
19#include <fcntl.h>
20char lfname[100]="";          // name of compiled lisp code cache file
21
22#define touch(x) { (x)->last_access=last_access++; \
23                   if ((x)->last_access<0) { normalize(); (x)->last_access=1; } }
24
25extern char *symbol_str(char *name);
26
27crc_manager crc_man;
28
29int past_startup=0;
30
31int crc_man_write_crc_file(char *filename)
32{
33  return crc_man.write_crc_file(filename);
34}
35
36int crc_manager::write_crc_file(char *filename)  // return 0 on failure
37{
38  char msg[100];
39  sprintf(msg,symbol_str("calc_crc"));  // this may take some time, show the user a status indicator
40  if (stat_man) stat_man->push(msg,NULL);
41
42  int i,total=0;
43  for (i=0;i<total_files;i++)
44  {
45    int failed=0;
46    get_crc(i,failed);
47
48    if (failed)
49    {
50      jFILE *fp=new jFILE(get_filename(i),"rb");
51      if (!fp->open_failure())
52      {
53        set_crc(i,crc_file(fp));
54        total++;
55      }
56      delete fp;
57    } else total++;
58    if (stat_man)
59      stat_man->update(i*100/total_files);
60  }
61  if (stat_man) stat_man->pop();
62  jFILE *fp=new jFILE("#net_crc","wb");
63  if (fp->open_failure())
64  {
65    delete fp;
66    return 0;
67  }
68
69  fp->write_short(total);
70  total=0;
71  for (i=0;i<total_files;i++)
72  {
73    ulong crc;
74    int failed=0;
75    crc=get_crc(i,failed);
76    if (!failed)
77    {
78      fp->write_long(crc);
79      uchar len=strlen(get_filename(i))+1;
80      fp->write_byte(len);
81      fp->write(get_filename(i),len);
82      total++;
83    }
84  }
85  delete fp;
86  return 1; 
87}
88
89int crc_manager::load_crc_file(char *filename)
90{
91  bFILE *fp=open_file(filename,"rb");
92  if (fp->open_failure())
93  {
94    delete fp;
95    return 0;
96  } else
97  {
98    short total=fp->read_short();
99    int i;
100    for (i=0;i<total;i++)
101    {
102      char name[256];
103      ulong crc=fp->read_long();
104      uchar len=fp->read_byte();
105      fp->read(name,len);
106      set_crc(get_filenumber(name),crc);
107    }
108    delete fp;
109  }
110  return 1; 
111}
112
113void crc_manager::clean_up()
114{
115  for (int i=0;i<total_files;i++)
116    delete files[i];
117  if (total_files)
118    jfree(files);
119  total_files=0;
120  files=NULL;
121}
122
123crced_file::~crced_file()
124{
125  jfree(filename);
126}
127
128crced_file::crced_file(char *name)
129{
130  filename=strcpy((char *)jmalloc(strlen(name)+1,"crc_file"),name);
131  crc_calculated=0;
132}
133
134crc_manager::crc_manager()
135{
136  total_files=0;
137  files=NULL;
138}
139
140int crc_manager::get_filenumber(char *filename)
141{
142  for (int i=0;i<total_files;i++)
143    if (!strcmp(filename,files[i]->filename)) return i;
144  total_files++;
145  files=(crced_file **)jrealloc(files,total_files*sizeof(crced_file *),"crc_file_list");
146  files[total_files-1]=new crced_file(filename);
147  return total_files-1;
148}
149
150char *crc_manager::get_filename(long filenumber)
151{
152  CHECK(filenumber>=0 && filenumber<total_files);
153  return files[filenumber]->filename;
154}
155
156ulong crc_manager::get_crc(long filenumber, int &failed)
157{   
158  CHECK(filenumber>=0 && filenumber<total_files);
159  if (files[filenumber]->crc_calculated)
160  {
161    failed=0;
162    return files[filenumber]->crc;
163  }
164  failed=1;
165  return 0;
166}
167
168void crc_manager::set_crc(long filenumber, ulong crc)
169{
170  CHECK(filenumber>=0 && filenumber<total_files);
171  files[filenumber]->crc_calculated=1;
172  files[filenumber]->crc=crc;
173}
174
175void cache_list::unmalloc(cache_item *i)
176{
177  switch (i->type)
178  {
179    case SPEC_CHARACTER2 :
180    case SPEC_CHARACTER : delete ((figure *)i->data);   break;
181    case SPEC_FORETILE : delete ((foretile *)i->data);  break;
182    case SPEC_BACKTILE : delete ((backtile *)i->data);  break;
183    case SPEC_IMAGE    : delete ((image *)i->data);     break;
184    case SPEC_EXTERN_SFX : delete ((sound_effect *)i->data); break;
185    case SPEC_PARTICLE : delete ((part_frame *)i->data); break;
186    case SPEC_EXTERNAL_LCACHE : if (i->data) jfree(i->data); break;
187    case SPEC_PALETTE : delete ((char_tint *)i->data); break;
188    default :
189      printf("Trying to unmalloc unknown type\n");
190  }
191  i->data=NULL;
192  i->last_access=-1;
193}
194
195
196
197void cache_list::prof_init()
198{
199  if (prof_data)
200    jfree(prof_data);
201 
202  prof_data=(int *)jmalloc(sizeof(int)*total,"cache profile");
203  memset(prof_data,0,sizeof(int)*total);
204}
205
206static int c_sorter(const void *a, const void *b)
207{
208  return cash.compare(*(int *)a,*(int *)b);
209}
210
211int cache_list::compare(int a, int b)
212{
213  if (prof_data[a]<prof_data[b])
214    return 1;
215  else if (prof_data[a]>prof_data[b])
216    return -1;
217  else return 0;
218}
219
220
221int cache_list::prof_size()
222{
223  int size=0;     // count up the size for a spec enrty
224  size+=2;        // total filenames
225  int i;
226  for (i=0;i<crc_man.total_filenames();i++)
227      size+=strlen(crc_man.get_filename(i))+2;    // filename + 0 + size of string
228
229  size+=4;       // number of entries saved
230
231  for (i=0;i<total;i++)
232    if (list[i].last_access>0)       // don't save unaccessed counts
233      size+=2+4+1;                   // filenumber & offset & type
234
235  return size;
236}
237
238
239void cache_list::prof_write(bFILE *fp)
240{
241  if (prof_data)
242  {
243    int *ordered_ids=(int *)jmalloc(sizeof(int)*total,"profile order");
244    int i;
245    for (i=0;i<total;i++) ordered_ids[i]=i;
246    qsort(ordered_ids,total,sizeof(int),c_sorter);
247
248    if (fp)
249    {
250      fp->write_short(crc_man.total_filenames());
251      for (i=0;i<crc_man.total_filenames();i++)
252      {
253        int l=strlen(crc_man.get_filename(i))+1;
254        fp->write_byte(l);
255        fp->write(crc_man.get_filename(i),l);
256      }
257
258      int tsaved=0;
259      for (i=0;i<total;i++)
260        if (list[i].last_access>0) tsaved++;
261      fp->write_long(tsaved);
262
263      for (i=0;i<total;i++)
264      {
265        int id=ordered_ids[i];
266        if (list[id].last_access>0)       // don't save unaccessed counts     
267        {
268          fp->write_byte(list[id].type);    // save type, if type changed on reload
269                                            // don't cache in-> its a different refrence
270          fp->write_short(list[id].file_number);
271          fp->write_long(list[id].offset);
272        }
273      }     
274    }
275
276    jfree(ordered_ids);
277
278  } else dprintf("Cache profiling was not initialized\n");
279}
280
281void cache_list::prof_uninit()
282{
283  if (prof_data)
284  {
285    jfree(prof_data);
286    prof_data=NULL;
287  }
288}
289
290int *sorted_id_list;
291
292
293static int s_offset_compare(const void *a, const void *b)
294{
295  return cash.offset_compare(*(int *)a,*(int *)b);
296}
297
298int cache_list::offset_compare(int a, int b)
299{
300  if (list[a].offset<list[b].offset)
301    return -1;
302  else if (list[a].offset>list[b].offset)
303    return 1;
304  else if (list[a].file_number<list[b].file_number)
305    return -1;
306  else if (list[a].file_number>list[b].file_number)
307    return 1;
308  else return 0;
309}
310
311
312int cache_list::search(int *sarray, ushort filenum, long offset)
313{
314  int x1=0,x2=total-1;
315  int split;
316  do
317  {
318    split=(x1+x2)/2;
319    cache_item *e=list+sarray[split];
320
321    int comp;
322    if (e->offset<offset)      // search to the right   
323      x1=split+1;
324    else if (e->offset>offset)
325      x2=split-1;
326    else if (e->file_number<filenum)
327      x1=split+1;
328    else if (e->file_number>filenum)
329      x2=split-1;
330    else return sarray[split];
331  } while (x1<=x2);
332  return -1;
333}
334
335static int load_chars()  // returns 0 if cache filled
336{
337  int i;
338  for (i=0;i<total_objects;i++)
339  {
340    if (figures[i]->get_cflag(CFLAG_NEED_CACHE_IN))
341    {
342      figures[i]->set_cflag(CFLAG_CACHED_IN,0);
343      figures[i]->cache_in();
344      figures[i]->set_cflag(CFLAG_NEED_CACHE_IN,0);
345    }
346  }
347  return 1;
348 
349}
350
351void cache_list::note_need(int id)
352{
353  if (list[id].last_access<0)
354    list[id].last_access=-2;
355  else
356    list[id].last_access=2;
357}
358
359void cache_list::preload_cache_object(int type)
360{
361  if (type<0xffff)
362  {
363    if (!figures[type]->get_cflag(CFLAG_NEED_CACHE_IN))  // see if it's already marked
364    {       
365      figures[type]->set_cflag(CFLAG_NEED_CACHE_IN,1);
366      void *cache_fun=figures[type]->get_fun(OFUN_GET_CACHE_LIST);
367
368      if (cache_fun)
369      {
370        int sp=current_space;
371        current_space=PERM_SPACE;
372
373        void *call_with=NULL;
374        push_onto_list(new_lisp_number(type),call_with);
375
376        void *cache_list=eval_function((lisp_symbol *)cache_fun,call_with);
377        p_ref r1(cache_list);
378
379        if (cache_list && lcar(cache_list))
380        {
381          void *obj_list=lcar(cache_list);
382          while (obj_list)
383          {
384            int t=lnumber_value(CAR(obj_list));
385            if (t<0 || t>=total_objects)
386              lbreak("Get cache list returned a bad object number %d\n",t);
387            else
388              preload_cache_object(t);
389            obj_list=CDR(obj_list);
390          }
391        }
392        if (cache_list && lcdr(cache_list))
393        {
394          void *id_list=lcar(lcdr(cache_list));
395          while (id_list)
396          {
397            int id=lnumber_value(CAR(id_list));
398            if (id<0 || id>=total)
399              lbreak("Get cache list returned a bad id number %d\n",id);
400            else if (list[id].last_access<0)
401              list[id].last_access=-2;
402            else list[id].last_access=2;
403
404            id_list=CDR(id_list);
405          }
406        }
407        current_space=sp;
408
409      }
410    }
411  }
412}
413
414void cache_list::preload_cache(level *lev)
415{
416  game_object *f;
417  int i;
418  for (i=0;i<total_objects;i++)                       // mark all types as not needing loading
419    figures[i]->set_cflag(CFLAG_NEED_CACHE_IN,0);
420
421  for (f=lev->first_object();f;f=f->next)               // go through each object and get requested items to cache in
422    preload_cache_object(f->otype);
423
424
425  int j;
426  ushort *fg_line;
427  for (j=0;j<lev->foreground_height();j++)
428  {
429    fg_line=lev->get_fgline(j);
430    for (i=0;i<lev->foreground_width();i++,fg_line++)
431    {
432      int id=foretiles[fgvalue(*fg_line)];
433      if (id>=0 && id<nforetiles)
434      {
435        if (list[id].last_access<0)
436          list[id].last_access=-2;
437        else list[id].last_access=2;     
438      }
439    }     
440  }
441
442  ushort *bg_line;
443  for (j=0;j<lev->background_height();j++)
444  {
445    bg_line=lev->get_bgline(j);
446    for (i=0;i<lev->background_width();i++,bg_line++)
447    {   
448      int id=backtiles[bgvalue(*bg_line)];
449      if (id>=0 && id<nbacktiles)
450      {
451        if (list[id].last_access<0)
452          list[id].last_access=-2;
453        else list[id].last_access=2;     
454      }
455    }     
456  }
457
458  load_chars();
459}
460
461void cache_list::load_cache_prof_info(char *filename, level *lev)
462{
463  int j;
464  for (j=0;j<this->total;j++)
465    if (list[j].last_access>=0)      // reset all loaded cache items to 0, all non-load to -1
466      list[j].last_access=0;
467
468  preload_cache(lev);                // preliminary guesses at stuff to load
469
470  int load_fail=1;
471  bFILE *fp=open_file(filename,"rb");
472  if (!fp->open_failure())
473  {
474    spec_directory sd(fp);
475    spec_entry *se=sd.find("cache profile info");   // see if the cache profile info is in the file
476    if (se)
477    {
478      fp->seek(se->offset,0);
479
480      char name[255];
481      int tnames=0;
482      int *fnum_remap;    // remaps old filenumbers into current ones
483     
484      tnames=fp->read_short();
485      if (tnames)                     /// make sure there isn't bad info in the file
486      {
487        fnum_remap=(int *)jmalloc(sizeof(int)*tnames,"pfname remap");
488
489        int i;
490        for (i=0;i<tnames;i++)
491        {
492          fp->read(name,fp->read_byte());
493          fnum_remap[i]=-1;                    // initialize the map to no-map
494
495          int j;
496          for (j=0;j<crc_man.total_filenames();j++)
497            if (!strcmp(crc_man.get_filename(j),name))
498              fnum_remap[i]=j;
499        }
500       
501        long tsaved=fp->read_long();
502
503
504        int *priority=(int *)jmalloc(tsaved*sizeof(int),"priorities");
505        memset(priority,0xff,tsaved*sizeof(int));   // initialize to -1
506        int tmatches=0;
507
508        sorted_id_list=(int *)jmalloc(sizeof(int)*total,"sorted ids");
509        for (j=0;j<total;j++) sorted_id_list[j]=j;
510        qsort(sorted_id_list,total,sizeof(int),s_offset_compare);
511
512        for (i=0;i<tsaved;i++)
513        {
514          uchar type=fp->read_byte();
515          short file_num=fp->read_short();
516          if (file_num>=tnames)  // bad data?
517            file_num=-1;
518          else file_num=fnum_remap[file_num];
519
520          ulong offset=fp->read_long();
521
522          // search for a match
523          j=search(sorted_id_list,file_num,offset);     
524          if (j!=-1)
525          {           
526            if (list[j].last_access<0)  // if not loaded
527              list[j].last_access=-2;      // mark as needing loading
528            else list[j].last_access=2;   // mark as loaded and needing to stay that way
529            priority[i]=j;
530            tmatches++;
531          }
532        }
533
534        jfree(sorted_id_list);            // was used for searching, no longer needed
535
536        for (j=0;j<total;j++)
537          if (list[j].last_access==0)
538            unmalloc(list+j);             // free any cache entries that are not accessed at all in the level
539
540
541        ful=0;
542        int tcached=0;
543        for (j=0;j<total;j++)    // now load all of the objects until full
544        {
545//        stat_man->update(j*70/total+25);
546          if (list[j].file_number>=0 && list[j].last_access==-2)
547          {
548            list[j].last_access=-1;
549            if (!ful)
550            {
551              switch (list[j].type)
552              {
553                case SPEC_BACKTILE : backt(j); break;
554                case SPEC_FORETILE : foret(j); break;
555                case SPEC_CHARACTER :
556                case SPEC_CHARACTER2 : fig(j); break;
557                case SPEC_IMAGE : img(j); break;
558                case SPEC_PARTICLE : part(j); break;
559                case SPEC_EXTERN_SFX : sfx(j); break;
560                case SPEC_EXTERNAL_LCACHE : lblock(j); break;
561                case SPEC_PALETTE : ctint(j); break;
562              }
563              tcached++;
564            }
565          }
566        }
567        load_fail=0;
568//      if (full())
569//        dprintf("Cache filled while loading\n");
570
571        if (tsaved>tmatches)
572          tmatches=tsaved+1;
573
574        last_access=tmatches+1;
575        for (i=0;i<tsaved;i++)      // reorder the last access of each cache to reflect prioirties
576        {
577          if (priority[i]!=-1)
578          {
579            if (list[priority[i]].last_access!=-1)            // make sure this wasn't the last item
580              list[priority[i]].last_access=tmatches--;
581          }
582        }
583
584        jfree(priority);
585        jfree(fnum_remap);
586
587
588      }
589    }   
590  }
591
592  if (load_fail) // no cache file, go solely on above gueses
593  {
594    int j;
595    for (j=0;j<total;j++)    // now load all of the objects until full, don't free old stuff
596    {
597//      stat_man->update(j*70/total+25);
598
599      if (list[j].file_number>=0 && list[j].last_access==-2)
600      {
601        list[j].last_access=-1;
602        if (!ful)
603        {
604          switch (list[j].type)
605          {
606            case SPEC_BACKTILE : backt(j); break;
607            case SPEC_FORETILE : foret(j); break;
608            case SPEC_CHARACTER :
609            case SPEC_CHARACTER2 : fig(j); break;
610            case SPEC_IMAGE : img(j); break;
611            case SPEC_PARTICLE : part(j); break;
612            case SPEC_EXTERN_SFX : sfx(j); break;
613            case SPEC_EXTERNAL_LCACHE : lblock(j); break;
614            case SPEC_PALETTE : ctint(j); break;
615          }
616        }
617      }
618    }
619    if (full())
620      dprintf("Cache filled while loading\n");
621  }
622  delete fp;
623}
624
625
626void cache_list::prof_poll_start()
627{
628  poll_start_access=last_access; 
629}
630
631void cache_list::prof_poll_end()
632{
633  if (prof_data)
634  {
635    int i=0;
636    for (;i<total;i++)
637    {
638      if (list[i].last_access>=poll_start_access)
639        prof_data[i]++;
640    }
641  }
642}
643
644void cache_list::unreg(int id)
645{
646  if (list[id].file_number)
647  {
648    unmalloc(&list[id]);
649    list[id].file_number=-1;
650  }
651  else
652    printf("Error : trying to unregister free object\n");
653}
654
655void cache_cleanup2()
656{ unlink(lfname);
657}
658
659void cache_cleanup(int ret, void *arg)
660{ unlink(lfname);
661}
662
663FILE *open_FILE(char *filename, char *mode);
664extern char *macify_name(char *s);
665
666void cache_list::create_lcache()
667{
668#ifdef __WATCOMC__
669  char *prefix="c:\\";
670#else
671  char *prefix="/tmp/";     // for UNIX store lisp cache in tmp dir
672  int flags=O_CREAT | O_RDWR;
673#endif
674 
675  int cfail=1,num=0;
676  do
677  {
678    sprintf(lfname,"%slcache%02d.tmp",prefix,num);
679
680#if defined( __WATCOMC__ ) || defined( __POWERPC__ )
681    unlink(lfname);
682#ifdef __POWERPC__
683                macify_name(lfname);
684#endif
685    FILE *fp=fopen(lfname,"wb");
686    if (fp)
687    {
688        fclose(fp);
689        cfail=0;
690                }
691#else
692    int fd=open(lfname,flags,S_IRWXU | S_IRWXG | S_IRWXO);     // can we get exclusive rights to this file?
693    if (fd<0) close(fd); else cfail=0;
694#endif
695
696    if (cfail)
697      num++;
698
699  } while (cfail && num<15);
700  if (cfail)
701  {
702    fprintf(stderr,"Error : Unable to open cache file for compiled code.\n"
703            "        Please delete all files named lcacheXX.tmp\n"
704            "        and make sure you have write permission to\n"
705            "        directory (%s)\n",prefix);
706    exit(0);
707  } else
708  {
709    exit_proc(cache_cleanup,cache_cleanup2);    // make sure this file gets deleted on exit..
710  }
711  lcache_number=-1;
712}
713
714cache_list::cache_list()
715{
716  // start out with a decent sized cache buffer because it's going to get allocated anyway.
717  total=0;
718  list=NULL;
719  last_registered=-1;   
720  cache_file=fp=NULL;
721  last_access=1;
722  used=ful=0;
723  last_dir=NULL;
724  last_file=-1;
725  prof_data=NULL;
726  cache_read_file=NULL;
727  create_lcache();
728}
729
730cache_list::~cache_list()
731{
732}
733
734void cache_list::empty()
735{
736  for (int i=0;i<total;i++)
737  {
738    if (list[i].file_number>=0 && list[i].last_access!=-1)
739      unmalloc(&list[i]);
740  }
741  jfree(list);
742  if (fp) delete fp;
743  if (last_dir) delete last_dir;
744  if (cache_file)
745  {
746    delete cache_file;
747    cache_file=NULL;   
748  }
749  unlink(lfname);
750
751  if (prof_data)
752  {
753    delete prof_data;
754    prof_data=NULL;
755  }
756
757  total=0;                    // reinitalize
758  list=NULL;
759  last_registered=-1;   
760  cache_file=fp=NULL;
761  if (cache_read_file)
762  {
763    delete cache_read_file;
764    cache_read_file=NULL;
765  }
766
767  last_access=1;
768  used=ful=0;
769  last_dir=NULL;
770  last_file=-1;
771  prof_data=NULL;
772}
773
774void cache_list::locate(cache_item *i, int local_only)
775{
776//  dprintf("cache in %s, type %d, offset %d\n",crc_man.get_filename(i->file_number),i->type,i->offset);
777  if (i->file_number!=last_file)
778  {
779    if (fp) delete fp;
780    if (last_dir) delete last_dir;
781    if (local_only)
782      fp=new jFILE(crc_man.get_filename(i->file_number),"rb");
783    else
784      fp=open_file(crc_man.get_filename(i->file_number),"rb");
785
786
787    if (fp->open_failure())
788    {
789      printf("Ooch. Could not open file %s\n",crc_man.get_filename(i->file_number));
790      delete fp;
791      exit(0);
792    }
793
794    last_offset=-1;
795    last_dir=new spec_directory(fp);
796    last_file=i->file_number;
797  }
798  if (i->offset!=last_offset)
799  {
800    fp->seek(i->offset,SEEK_SET);
801    last_offset=i->offset;
802  }
803  used=1;
804}
805
806long cache_list::alloc_id()
807{
808  int id;
809  if (prof_data)
810  {
811    the_game->show_help("new id allocated, cache profiling turned off\n");
812    prof_uninit();
813  }
814
815  // see if we previously allocated an id, if so check the next spot in the array
816  // otherwise we will have to scan the whole list for a free id and possible
817  // grow the list.
818  if (last_registered+1<total && list[last_registered+1].file_number<0)
819    id=last_registered+1;
820  else
821  {
822    int i;
823    cache_item *ci=list;
824    for (i=0,id=-1;i<total && id<0;i++,ci++)        // scan list for a free id
825    {
826      if (ci->file_number<0)
827        id=i;
828    }
829
830    if (id<0)                                 // if no free id's then make list bigger
831    {
832      int add_size=20;
833      list=(cache_item *)jrealloc(list,(sizeof(cache_item)*(total+add_size)),"Cache list");
834      for (i=0;i<add_size;i++)
835      {
836        list[total+i].file_number=-1;         // mark new entries as new
837        list[total+i].last_access=-1;
838        list[total+i].data=NULL;
839      }
840      id=total;
841      if (prof_data)                          // new id's have been added old prof_data size won't work
842      { jfree(prof_data); prof_data=NULL; }
843      total+=add_size;
844    }
845  }
846  last_registered=id;
847  return id;
848}
849
850
851
852long cache_list::reg_lisp_block(Cell *block)
853{
854  long s;
855  if (lcache_number==-1)
856    lcache_number=crc_man.get_filenumber(lfname);
857
858  if (can_cache_lisp())
859  {
860    if (!cache_file)
861    {
862      if (cache_read_file)
863      {
864                                delete cache_read_file;
865                                cache_read_file=NULL;
866                       
867                                cache_file=new jFILE(lfname,"ab");     
868      } else cache_file=new jFILE(lfname,"wb");  // first time we opened
869
870    }
871    if (cache_file->open_failure())
872    {
873      delete cache_file;
874      lprint(block);
875      fprintf(stderr,"Unable to open lisp cache file name %s\n",lfname);
876      exit(0);
877    }
878  }
879  int id=alloc_id(),i,fn=crc_man.get_filenumber(lfname);
880  cache_item *ci=list+id;
881  CHECK(id<total && list[id].file_number<0);
882
883  ci->file_number=fn;
884  ci->last_access=-1;
885  ci->type=SPEC_EXTERNAL_LCACHE;
886  if (!can_cache_lisp())
887  {
888    ci->data=(void *)block;                // we can't cache it out so it must be in memory
889    return id;
890  }
891  ci->data=NULL;                  // assume that it is in tmp memory, need to cache in on access
892  ci->offset=cache_file->tell();
893
894  s=block_size(block);
895  cache_file->write_long(s);
896  write_level(cache_file,block);
897  return id;   
898}
899
900long cache_list::reg_object(char *filename, void *object, int type, int rm_dups)
901{
902  char *name;
903  if (item_type(object)==L_CONS_CELL)      // see if we got a object with a filename included
904  {
905    filename=lstring_value(lcar(object));
906    name=lstring_value(lcdr(object));
907  }
908  else name=lstring_value(object);        // otherwise should be a string
909  return reg(filename,name,type,rm_dups);
910}
911
912extern int total_files_open;
913
914long cache_list::reg(char *filename, char *name, int type, int rm_dups)
915{
916  int id=alloc_id(),i,fn=crc_man.get_filenumber(filename);
917  cache_item *ci=list+id;
918  CHECK(id<total && list[id].file_number<0);
919
920  if (type==SPEC_EXTERN_SFX)    // if a extern sound effect then just make sure it's there
921  {
922    bFILE *check=open_file(filename,"rb");
923    if (check->open_failure())
924    {
925      delete check;
926      printf("Unable to open file '%s' for reading\n",filename);
927      exit(0);
928    }
929    char buf[4];
930    check->read(buf,4);
931    delete check;
932    if (memcmp(buf,"RIFF",4))
933    {
934      printf("File %s is not a WAV file\n",filename);
935      exit(0);
936    }
937    ci->file_number=fn;
938    ci->last_access=-1;
939    ci->data=NULL;
940    ci->offset=0;
941    ci->type=type; 
942    return id; 
943  }
944
945  spec_directory *sd=sd_cache.get_spec_directory(filename);
946 
947  if (!sd)
948  {
949    printf("Unable to open filename %s for requested item %s\n",filename,name);
950    exit(0);
951  }
952
953  spec_entry *se;
954  if (type!=-1)
955  {
956    se=sd->find(name,type);
957    if (!se) se=sd->find(name);
958  }
959  else se=sd->find(name);
960 
961 
962  if (!se)
963  {   
964    printf("No such item %s in file %s\n",name,filename);
965    exit(0);
966  }
967  else if (type>=0 && (type!=se->type && ((type!=SPEC_CHARACTER2 && type!=SPEC_CHARACTER)  ||
968                                          (se->type!=SPEC_CHARACTER && se->type!=SPEC_CHARACTER2))))
969  {
970    printf("Item %s of file %s should be type %s\n",name,filename,spec_types[type]);
971    exit(0);
972  }
973
974     
975
976  if (rm_dups)
977  {
978    for (i=0;i<total;i++)
979      if (list[i].file_number==fn && list[i].offset==se->offset)
980        return i;
981  }
982
983  ci->file_number=fn;
984  ci->last_access=-1;
985  ci->data=NULL;
986  ci->offset=se->offset;
987  ci->type=se->type; 
988  return id; 
989}
990
991
992void cache_list::normalize()
993{
994  int j;
995  cache_item *ci=list;
996  last_access=-1;
997  for (j=0;j<total;j++,ci++)
998  {
999    if (ci->last_access>=0)
1000      ci->last_access=ci->last_access>>16;        // shift everything over by 16
1001    if (ci->last_access>last_access)            //  and find new largest timestamp
1002      last_access=ci->last_access;
1003  }
1004  last_access++;
1005}
1006
1007backtile *cache_list::backt(int id)
1008{
1009  cache_item *me=list+id;
1010  CONDITION(id<total && id>=0 && me->file_number>=0,"Bad id");
1011
1012  if (me->last_access>=0) 
1013  {
1014    touch(me);
1015    return (backtile *)me->data;
1016  }
1017  else
1018  {
1019    touch(me);
1020    locate(me);
1021    int sp=alloc_space; alloc_space=ALLOC_SPACE_CACHE;
1022    me->data=(void *)new backtile(fp);
1023    alloc_space=sp;
1024    last_offset=fp->tell();
1025    return (backtile *)me->data;
1026  } 
1027}
1028
1029
1030foretile *cache_list::foret(int id)
1031{
1032  cache_item *me=list+id;
1033  CONDITION(id<total && id>=0 && me->file_number>=0,"Bad id");
1034
1035  if (me->last_access>=0) 
1036  {
1037    touch(me);
1038    return (foretile *)me->data;
1039  }
1040  else
1041  {
1042    touch(me);
1043    locate(me);
1044    int sp=alloc_space; alloc_space=ALLOC_SPACE_CACHE;
1045    me->data=(void *)new foretile(fp);
1046    alloc_space=sp;
1047    last_offset=fp->tell();
1048    return (foretile *)me->data;
1049  } 
1050}
1051
1052figure *cache_list::fig(int id)
1053{
1054  cache_item *me=list+id;
1055//  CONDITION(id<total && id>=0 && me->file_number>=0,"Bad id");
1056  if (me->last_access>=0) 
1057  {
1058    touch(me);
1059    return (figure *)me->data;
1060  }
1061  else
1062  {
1063    touch(me);
1064    locate(me);
1065    int sp=alloc_space; alloc_space=ALLOC_SPACE_CACHE;
1066    me->data=(void *)new figure(fp,me->type);
1067    alloc_space=sp;
1068    last_offset=fp->tell();
1069    return (figure *)me->data;
1070  } 
1071}
1072
1073image *cache_list::img(int id)
1074{
1075  cache_item *me=list+id;
1076  CONDITION(id<total && id>=0 && me->file_number>=0,"Bad id");
1077  if (me->last_access>=0) 
1078  {
1079    touch(me);
1080    return (image *)me->data;
1081  }
1082  else
1083  {
1084    touch(me);                                           // hold me, feel me, be me!
1085    locate(me);
1086    int sp=alloc_space; alloc_space=ALLOC_SPACE_CACHE;
1087    image *im=new image(fp);
1088    alloc_space=sp;
1089    me->data=(void *)im;
1090    last_offset=fp->tell();
1091
1092    return (image *)me->data;
1093  } 
1094}
1095
1096sound_effect *cache_list::sfx(int id)
1097{
1098  cache_item *me=list+id;
1099  CONDITION(id<total && id>=0 && me->file_number>=0,"Bad id");
1100  if (me->last_access>=0) 
1101  {
1102    touch(me);                                           // hold me, feel me, be me!
1103    return (sound_effect *)me->data;
1104  }
1105  else
1106  {
1107    touch(me);                                           // hold me, feel me, be me!
1108    char *fn=crc_man.get_filename(me->file_number);
1109    int sp=alloc_space; alloc_space=ALLOC_SPACE_CACHE;
1110    me->data=(void *)new sound_effect(fn);
1111    alloc_space=sp;
1112    return (sound_effect *)me->data;
1113  } 
1114}
1115
1116
1117part_frame *cache_list::part(int id)
1118{
1119  cache_item *me=list+id;
1120  CONDITION(id<total && id>=0 && me->file_number>=0,"Bad id");
1121  if (me->last_access>=0) 
1122  {
1123    touch(me);                                           // hold me, feel me, be me!
1124    return (part_frame *)me->data;
1125  }
1126  else
1127  {
1128    touch(me);
1129    locate(me);
1130    int sp=alloc_space; alloc_space=ALLOC_SPACE_CACHE;
1131    me->data=(void *)new part_frame(fp);
1132    alloc_space=sp;
1133    last_offset=fp->tell();
1134    return (part_frame *)me->data;
1135  } 
1136}
1137
1138
1139Cell *cache_list::lblock(int id)
1140{
1141  cache_item *me=list+id;
1142  CONDITION(id<total && id>=0 && me->file_number>=0,"Bad id");
1143  if (!can_cache_lisp()) return (Cell *)me->data;
1144  if (me->last_access>=0) 
1145  {
1146    touch(me);
1147    return (Cell *)me->data;
1148  }
1149  else
1150  {
1151    if (cache_file)
1152    {
1153      delete cache_file;
1154      cache_file=NULL;
1155    }
1156    touch(me);
1157
1158    if (!cache_read_file)
1159    {
1160      cache_read_file=new jFILE(crc_man.get_filename(me->file_number),"rb");
1161     
1162      int cache_size=80*1024;                   // 80K
1163      cache_read_file->set_read_buffer_size(cache_size);
1164      uchar mini_buf;
1165      cache_read_file->read(&mini_buf,1);       // prime the buffer
1166    }
1167
1168    cache_read_file->seek(me->offset,0);
1169
1170    int sp=alloc_space; alloc_space=ALLOC_SPACE_CACHE;
1171
1172    long size=cache_read_file->read_long();
1173    void *space;
1174
1175    if (size)
1176      space=jmalloc(size,"cached lisp block");
1177    else space=NULL;
1178
1179    int cs=current_space;
1180    use_user_space(space,size);   
1181    load_block(cache_read_file);
1182    current_space=cs;
1183   
1184    alloc_space=sp;
1185    if (size)
1186      me->data=(Cell *)space;
1187    else me->data=NULL;
1188    return (Cell *)me->data;
1189  } 
1190}
1191
1192cache_list cash;
1193
1194void free_up_memory()
1195{
1196  cash.free_oldest();
1197}
1198
1199void cache_list::free_oldest()
1200{
1201  long i,old_time=last_access;
1202  cache_item *ci=list,*oldest=NULL;
1203  ful=1;
1204
1205  for (i=0;i<total;i++,ci++)
1206  {
1207    if (ci->data && ci->last_access<old_time)
1208    {
1209      oldest=ci;
1210      old_time=ci->last_access;
1211    }
1212  }
1213  if (oldest)
1214  {
1215    dprintf("mem_maker : freeing %s\n",spec_types[oldest->type]);
1216    unmalloc(oldest);   
1217  }
1218  else
1219  {
1220    close_graphics();
1221    printf("Out of memory, please remove any TSR's device drivers you can\n");
1222    mem_report("out_of_mem");
1223    exit(0);
1224  }         
1225}
1226
1227
1228void cache_list::show_accessed()
1229{
1230  int old=last_access,new_old_accessed;
1231  cache_item *ci,*new_old;
1232 
1233  do
1234  {
1235    new_old_accessed=-1;
1236    new_old=NULL;
1237    ci=list;
1238    for (int i=0;i<total;i++,ci++) 
1239    {
1240      if (ci->last_access<old && ci->last_access>0 && ci->last_access>new_old_accessed)   
1241      {
1242        new_old_accessed=ci->last_access;
1243        new_old=ci;   
1244      }
1245    }
1246    if (new_old)
1247    {
1248      ci=new_old;
1249      old=ci->last_access;
1250      printf("type=(%20s) file=(%20s) access=(%6d)\n",spec_types[ci->type],
1251             crc_man.get_filename(ci->file_number),
1252             ci->last_access);
1253    }
1254  } while (new_old);
1255}
1256
1257
1258int cache_list::loaded(int id)
1259{
1260  cache_item *me=list+id;
1261  CONDITION(id<total && id>=0 && me->file_number>=0,"Bad id");
1262  if (me->last_access>=0) 
1263    return 1;
1264  else return 0;
1265}
1266
1267
1268
1269char_tint *cache_list::ctint(int id)
1270{
1271  cache_item *me=list+id;
1272  CONDITION(id<total && id>=0 && me->file_number>=0,"Bad id" && me->type==SPEC_PALETTE);
1273  if (me->last_access>=0) 
1274  {
1275    touch(me);
1276    return (char_tint *)me->data;
1277  }
1278  else
1279  {
1280    touch(me);
1281    locate(me);
1282    int sp=alloc_space; alloc_space=ALLOC_SPACE_CACHE;
1283    me->data=(void *)new char_tint(fp);
1284    alloc_space=sp;
1285    last_offset=fp->tell();
1286    return (char_tint *)me->data;
1287  }   
1288}
1289
1290
1291
1292
Note: See TracBrowser for help on using the repository browser.