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

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