source: abuse/tags/pd/macabuse/src/cache.c @ 49

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