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

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