source: abuse/trunk/src/cache.cpp @ 41

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