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

Last change on this file since 56 was 56, checked in by Sam Hocevar, 14 years ago
  • Add licensing terms to most C / C++ files (Ref #5).
File size: 28.7 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
38crc_manager crc_man;
39
40int past_startup=0;
41
42int crc_man_write_crc_file(char const *filename)
43{
44  return crc_man.write_crc_file(filename);
45}
46
47int crc_manager::write_crc_file(char const *filename)  // return 0 on failure
48{
49  char msg[100];
50  sprintf(msg,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 crc_manager::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 crc_manager::clean_up()
125{
126  for (int i=0;i<total_files;i++)
127    delete files[i];
128  if (total_files)
129    jfree(files);
130  total_files=0;
131  files=NULL;
132}
133
134crced_file::~crced_file()
135{
136  jfree(filename);
137}
138
139crced_file::crced_file(char const *name)
140{
141  filename=strcpy((char *)jmalloc(strlen(name)+1,"crc_file"),name);
142  crc_calculated=0;
143}
144
145crc_manager::crc_manager()
146{
147  total_files=0;
148  files=NULL;
149}
150
151int crc_manager::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=(crced_file **)jrealloc(files,total_files*sizeof(crced_file *),"crc_file_list");
157  files[total_files-1]=new crced_file(filename);
158  return total_files-1;
159}
160
161char *crc_manager::get_filename(int32_t filenumber)
162{
163  CHECK(filenumber>=0 && filenumber<total_files);
164  return files[filenumber]->filename;
165}
166
167uint32_t crc_manager::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 crc_manager::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 cache_list::unmalloc(cache_item *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) jfree(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 cache_list::prof_init()
209{
210  if (prof_data)
211    jfree(prof_data);
212 
213  prof_data=(int *)jmalloc(sizeof(int)*total,"cache profile");
214  memset(prof_data,0,sizeof(int)*total);
215}
216
217static int c_sorter(const void *a, const void *b)
218{
219  return cash.compare(*(int *)a,*(int *)b);
220}
221
222int cache_list::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 cache_list::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_man.total_filenames();i++)
238      size+=strlen(crc_man.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 cache_list::prof_write(bFILE *fp)
251{
252  if (prof_data)
253  {
254    int *ordered_ids=(int *)jmalloc(sizeof(int)*total,"profile order");
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_man.total_filenames());
262      for (i=0;i<crc_man.total_filenames();i++)
263      {
264        int l=strlen(crc_man.get_filename(i))+1;
265        fp->write_uint8(l);
266        fp->write(crc_man.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    jfree(ordered_ids);
288
289  } else dprintf("Cache profiling was not initialized\n");
290}
291
292void cache_list::prof_uninit()
293{
294  if (prof_data)
295  {
296    jfree(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 cash.offset_compare(*(int *)a,*(int *)b);
307}
308
309int cache_list::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 cache_list::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    cache_item *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 cache_list::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 cache_list::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 *cache_list=eval_function((lisp_symbol *)cache_fun,call_with);
387        p_ref r1(cache_list);
388
389        if (cache_list && lcar(cache_list))
390        {
391          void *obj_list=lcar(cache_list);
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 (cache_list && lcdr(cache_list))
403        {
404          void *id_list=lcar(lcdr(cache_list));
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 cache_list::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 cache_list::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 *)jmalloc(sizeof(int)*tnames,"pfname remap");
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_man.total_filenames();j++)
507            if (!strcmp(crc_man.get_filename(j),name))
508              fnum_remap[i]=j;
509        }
510       
511        uint32_t tsaved=fp->read_uint32();
512
513
514        int *priority=(int *)jmalloc(tsaved*sizeof(int),"priorities");
515        memset(priority,0xff,tsaved*sizeof(int));   // initialize to -1
516        int tmatches=0;
517
518        sorted_id_list=(int *)jmalloc(sizeof(int)*total,"sorted ids");
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        jfree(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        jfree(priority);
595        jfree(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 cache_list::prof_poll_start()
637{
638  poll_start_access=last_access; 
639}
640
641void cache_list::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 cache_list::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
665void cache_cleanup2()
666{ unlink(lfname);
667}
668
669void cache_cleanup(int ret, void *arg)
670{ unlink(lfname);
671}
672
673extern char *macify_name(char *s);
674
675void cache_list::create_lcache()
676{
677#ifdef WIN32
678        char *prefix="c:\\";
679#else
680        char const *prefix = "/tmp/";     // for UNIX store lisp cache in tmp dir
681        int flags = O_CREAT | O_RDWR;
682#endif
683
684        int cfail = 1, num = 0;
685        do
686        {
687                sprintf(lfname,"%slcache%02d.tmp",prefix,num);
688
689#if defined( __APPLE__ )
690                unlink(lfname);
691#if (defined(__APPLE__) && !defined(__MACH__))
692                macify_name(lfname);
693#endif
694                FILE *fp=fopen(lfname,"wb");
695                if (fp)
696                {
697                        fclose(fp);
698                        cfail=0;
699                }
700#else
701                int fd=open(lfname,flags,S_IRWXU | S_IRWXG | S_IRWXO);     // can we get exclusive rights to this file?
702                if (fd<0) close(fd); else cfail=0;
703#endif
704
705                if (cfail)
706                        num++;
707
708        } while (cfail && num<15);
709
710        if (cfail)
711        {
712                fprintf(stderr,"Error : Unable to open cache file for compiled code.\n"
713                        "        Please delete all files named lcacheXX.tmp\n"
714                        "        and make sure you have write permission to\n"
715                        "        directory (%s)\n",prefix);
716                exit(0);
717        }
718        else
719        {
720                exit_proc(cache_cleanup,cache_cleanup2);    // make sure this file gets deleted on exit..
721        }
722        lcache_number=-1;
723}
724
725cache_list::cache_list()
726{
727  // start out with a decent sized cache buffer because it's going to get allocated anyway.
728  total=0;
729  list=NULL;
730  last_registered=-1;   
731  cache_file=fp=NULL;
732  last_access=1;
733  used=ful=0;
734  last_dir=NULL;
735  last_file=-1;
736  prof_data=NULL;
737  cache_read_file=NULL;
738  create_lcache();
739}
740
741cache_list::~cache_list()
742{
743}
744
745void cache_list::empty()
746{
747  for (int i=0;i<total;i++)
748  {
749    if (list[i].file_number>=0 && list[i].last_access!=-1)
750      unmalloc(&list[i]);
751  }
752  jfree(list);
753  if (fp) delete fp;
754  if (last_dir) delete last_dir;
755  if (cache_file)
756  {
757    delete cache_file;
758    cache_file=NULL;   
759  }
760  unlink(lfname);
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_file=fp=NULL;
772  if (cache_read_file)
773  {
774    delete cache_read_file;
775    cache_read_file=NULL;
776  }
777
778  last_access=1;
779  used=ful=0;
780  last_dir=NULL;
781  last_file=-1;
782  prof_data=NULL;
783}
784
785void cache_list::locate(cache_item *i, int local_only)
786{
787//  dprintf("cache in %s, type %d, offset %d\n",crc_man.get_filename(i->file_number),i->type,i->offset);
788  if (i->file_number!=last_file)
789  {
790    if (fp) delete fp;
791    if (last_dir) delete last_dir;
792    if (local_only)
793      fp=new jFILE(crc_man.get_filename(i->file_number),"rb");
794    else
795      fp=open_file(crc_man.get_filename(i->file_number),"rb");
796
797
798    if (fp->open_failure())
799    {
800      printf("Ooch. Could not open file %s\n",crc_man.get_filename(i->file_number));
801      delete fp;
802      exit(0);
803    }
804
805    last_offset=-1;
806    last_dir=new spec_directory(fp);
807    last_file=i->file_number;
808  }
809  if (i->offset!=last_offset)
810  {
811    fp->seek(i->offset,SEEK_SET);
812    last_offset=i->offset;
813  }
814  used=1;
815}
816
817int32_t cache_list::alloc_id()
818{
819  int id;
820  if (prof_data)
821  {
822    the_game->show_help("new id allocated, cache profiling turned off\n");
823    prof_uninit();
824  }
825
826  // see if we previously allocated an id, if so check the next spot in the array
827  // otherwise we will have to scan the whole list for a free id and possible
828  // grow the list.
829  if (last_registered+1<total && list[last_registered+1].file_number<0)
830    id=last_registered+1;
831  else
832  {
833    int i;
834    cache_item *ci=list;
835    for (i=0,id=-1;i<total && id<0;i++,ci++)        // scan list for a free id
836    {
837      if (ci->file_number<0)
838        id=i;
839    }
840
841    if (id<0)                                 // if no free id's then make list bigger
842    {
843      int add_size=20;
844      list=(cache_item *)jrealloc(list,(sizeof(cache_item)*(total+add_size)),"Cache list");
845      for (i=0;i<add_size;i++)
846      {
847        list[total+i].file_number=-1;         // mark new entries as new
848        list[total+i].last_access=-1;
849        list[total+i].data=NULL;
850      }
851      id=total;
852      if (prof_data)                          // new id's have been added old prof_data size won't work
853      { jfree(prof_data); prof_data=NULL; }
854      total+=add_size;
855    }
856  }
857  last_registered=id;
858  return id;
859}
860
861
862
863int32_t cache_list::reg_lisp_block(Cell *block)
864{
865  uint32_t s;
866  if (lcache_number==-1)
867    lcache_number=crc_man.get_filenumber(lfname);
868
869  if (can_cache_lisp())
870  {
871    if (!cache_file)
872    {
873      if (cache_read_file)
874      {
875        delete cache_read_file;
876        cache_read_file=NULL;
877
878        cache_file=new jFILE(lfname,"ab");     
879      } else cache_file=new jFILE(lfname,"wb");  // first time we opened
880    }
881    if (cache_file->open_failure())
882    {
883      delete cache_file;
884      lprint(block);
885      fprintf(stderr,"Unable to open lisp cache file name %s\n",lfname);
886      exit(0);
887    }
888  }
889  int id=alloc_id(),fn=crc_man.get_filenumber(lfname);
890  cache_item *ci=list+id;
891  CHECK(id<total && list[id].file_number<0);
892
893  ci->file_number=fn;
894  ci->last_access=-1;
895  ci->type=SPEC_EXTERNAL_LCACHE;
896  if (!can_cache_lisp())
897  {
898    ci->data=(void *)block;                // we can't cache it out so it must be in memory
899    return id;
900  }
901  ci->data=NULL;                  // assume that it is in tmp memory, need to cache in on access
902  ci->offset=cache_file->tell();
903
904  s=block_size(block);
905  cache_file->write_uint32(s);
906  write_level(cache_file,block);
907  return id;   
908}
909
910int32_t cache_list::reg_object(char const *filename, void *object, int type, int rm_dups)
911{
912  char *name;
913  if (item_type(object)==L_CONS_CELL)      // see if we got a object with a filename included
914  {
915    filename=lstring_value(lcar(object));
916    name=lstring_value(lcdr(object));
917  }
918  else name=lstring_value(object);        // otherwise should be a string
919  return reg(filename,name,type,rm_dups);
920}
921
922extern int total_files_open;
923
924int32_t cache_list::reg(char const *filename, char const *name, int type, int rm_dups)
925{
926        int id=alloc_id(),i,fn=crc_man.get_filenumber(filename);
927        cache_item *ci=list+id;
928        CHECK(id<total && list[id].file_number<0);
929
930        if( type == SPEC_EXTERN_SFX ) // If a extern sound effect then just make sure it's there
931        {
932                bFILE *check=open_file(filename,"rb");
933                if (check->open_failure())
934                {
935                        delete check;
936                        if( sound_avail )
937                        {
938                                printf("Unable to open file '%s' for reading\n",filename);
939                                exit(0);
940                        }
941                        else
942                        {
943                                // Sound is disabled, we don't really care if the sound file
944                                // is there or not, just pretend it's all ok.
945                                return id;
946                        }
947                }
948                char buf[4];
949                check->read(buf,4);
950                delete check;
951                if (memcmp(buf,"RIFF",4))
952                {
953                        printf("File %s is not a WAV file\n",filename);
954                        exit(0);
955                }
956                ci->file_number=fn;
957                ci->last_access=-1;
958                ci->data=NULL;
959                ci->offset=0;
960                ci->type=type;
961                return id;
962        }
963
964        spec_directory *sd=sd_cache.get_spec_directory(filename);
965
966        if (!sd)
967        {
968                printf("Unable to open filename %s for requested item %s\n",filename,name);
969                exit(0);
970        }
971
972        spec_entry *se;
973        if (type!=-1)
974        {
975                se=sd->find(name,type);
976                if (!se) se=sd->find(name);
977        }
978        else se=sd->find(name);
979
980
981        if (!se)
982        {
983                printf("No such item %s in file %s\n",name,filename);
984                exit(0);
985        }
986        else if (type>=0 && (type!=se->type && ((type!=SPEC_CHARACTER2 && type!=SPEC_CHARACTER)  ||
987                                                (se->type!=SPEC_CHARACTER && se->type!=SPEC_CHARACTER2))))
988        {
989                printf("Item %s of file %s should be type %s\n",name,filename,spec_types[type]);
990                exit(0);
991        }
992
993        if (rm_dups)
994        {
995                for (i=0;i<total;i++)
996                        if (list[i].file_number == fn && (unsigned)list[i].offset == se->offset)
997                                return i;
998        }
999
1000        ci->file_number=fn;
1001        ci->last_access=-1;
1002        ci->data=NULL;
1003        ci->offset=se->offset;
1004        ci->type=se->type; 
1005        return id; 
1006}
1007
1008
1009void cache_list::normalize()
1010{
1011  int j;
1012  cache_item *ci=list;
1013  last_access=-1;
1014  for (j=0;j<total;j++,ci++)
1015  {
1016    if (ci->last_access>=0)
1017      ci->last_access=ci->last_access>>16;        // shift everything over by 16
1018    if (ci->last_access>last_access)            //  and find new largest timestamp
1019      last_access=ci->last_access;
1020  }
1021  last_access++;
1022}
1023
1024backtile *cache_list::backt(int id)
1025{
1026  cache_item *me=list+id;
1027  CONDITION(id<total && id>=0 && me->file_number>=0,"Bad id");
1028
1029  if (me->last_access>=0) 
1030  {
1031    touch(me);
1032    return (backtile *)me->data;
1033  }
1034  else
1035  {
1036    touch(me);
1037    locate(me);
1038    int sp=alloc_space; alloc_space=ALLOC_SPACE_CACHE;
1039    me->data=(void *)new backtile(fp);
1040    alloc_space=sp;
1041    last_offset=fp->tell();
1042    return (backtile *)me->data;
1043  } 
1044}
1045
1046
1047foretile *cache_list::foret(int id)
1048{
1049  cache_item *me=list+id;
1050  CONDITION(id<total && id>=0 && me->file_number>=0,"Bad id");
1051
1052  if (me->last_access>=0) 
1053  {
1054    touch(me);
1055    return (foretile *)me->data;
1056  }
1057  else
1058  {
1059    touch(me);
1060    locate(me);
1061    int sp=alloc_space; alloc_space=ALLOC_SPACE_CACHE;
1062    me->data=(void *)new foretile(fp);
1063    alloc_space=sp;
1064    last_offset=fp->tell();
1065    return (foretile *)me->data;
1066  } 
1067}
1068
1069figure *cache_list::fig(int id)
1070{
1071  cache_item *me=list+id;
1072//  CONDITION(id<total && id>=0 && me->file_number>=0,"Bad id");
1073  if (me->last_access>=0) 
1074  {
1075    touch(me);
1076    return (figure *)me->data;
1077  }
1078  else
1079  {
1080    touch(me);
1081    locate(me);
1082    int sp=alloc_space; alloc_space=ALLOC_SPACE_CACHE;
1083    me->data=(void *)new figure(fp,me->type);
1084    alloc_space=sp;
1085    last_offset=fp->tell();
1086    return (figure *)me->data;
1087  } 
1088}
1089
1090image *cache_list::img(int id)
1091{
1092  cache_item *me=list+id;
1093  CONDITION(id<total && id>=0 && me->file_number>=0,"Bad id");
1094  if (me->last_access>=0) 
1095  {
1096    touch(me);
1097    return (image *)me->data;
1098  }
1099  else
1100  {
1101    touch(me);                                           // hold me, feel me, be me!
1102    locate(me);
1103    int sp=alloc_space; alloc_space=ALLOC_SPACE_CACHE;
1104    image *im=new image(fp);
1105    alloc_space=sp;
1106    me->data=(void *)im;
1107    last_offset=fp->tell();
1108
1109    return (image *)me->data;
1110  } 
1111}
1112
1113sound_effect *cache_list::sfx(int id)
1114{
1115  cache_item *me=list+id;
1116  CONDITION(id<total && id>=0 && me->file_number>=0,"Bad id");
1117  if (me->last_access>=0) 
1118  {
1119    touch(me);                                           // hold me, feel me, be me!
1120    return (sound_effect *)me->data;
1121  }
1122  else
1123  {
1124    touch(me);                                           // hold me, feel me, be me!
1125    char *fn=crc_man.get_filename(me->file_number);
1126    int sp=alloc_space; alloc_space=ALLOC_SPACE_CACHE;
1127    me->data=(void *)new sound_effect(fn);
1128    alloc_space=sp;
1129    return (sound_effect *)me->data;
1130  } 
1131}
1132
1133
1134part_frame *cache_list::part(int id)
1135{
1136  cache_item *me=list+id;
1137  CONDITION(id<total && id>=0 && me->file_number>=0,"Bad id");
1138  if (me->last_access>=0) 
1139  {
1140    touch(me);                                           // hold me, feel me, be me!
1141    return (part_frame *)me->data;
1142  }
1143  else
1144  {
1145    touch(me);
1146    locate(me);
1147    int sp=alloc_space; alloc_space=ALLOC_SPACE_CACHE;
1148    me->data=(void *)new part_frame(fp);
1149    alloc_space=sp;
1150    last_offset=fp->tell();
1151    return (part_frame *)me->data;
1152  } 
1153}
1154
1155
1156Cell *cache_list::lblock(int id)
1157{
1158  cache_item *me=list+id;
1159  CONDITION(id<total && id>=0 && me->file_number>=0,"Bad id");
1160  if (!can_cache_lisp()) return (Cell *)me->data;
1161  if (me->last_access>=0) 
1162  {
1163    touch(me);
1164    return (Cell *)me->data;
1165  }
1166  else
1167  {
1168    if (cache_file)
1169    {
1170      delete cache_file;
1171      cache_file=NULL;
1172    }
1173    touch(me);
1174
1175    if (!cache_read_file)
1176    {
1177      cache_read_file=new jFILE(crc_man.get_filename(me->file_number),"rb");
1178     
1179      int cache_size=80*1024;                   // 80K
1180      cache_read_file->set_read_buffer_size(cache_size);
1181      uint8_t mini_buf;
1182      cache_read_file->read(&mini_buf,1);       // prime the buffer
1183    }
1184
1185    cache_read_file->seek(me->offset,0);
1186
1187    int sp=alloc_space; alloc_space=ALLOC_SPACE_CACHE;
1188
1189    uint32_t size=cache_read_file->read_uint32();
1190    void *space;
1191
1192    if (size)
1193      space=jmalloc(size,"cached lisp block");
1194    else space=NULL;
1195
1196    int cs=current_space;
1197    use_user_space(space,size);   
1198    load_block(cache_read_file);
1199    current_space=cs;
1200   
1201    alloc_space=sp;
1202    if (size)
1203      me->data=(Cell *)space;
1204    else me->data=NULL;
1205    return (Cell *)me->data;
1206  } 
1207}
1208
1209cache_list cash;
1210
1211void free_up_memory()
1212{
1213  cash.free_oldest();
1214}
1215
1216void cache_list::free_oldest()
1217{
1218  uint32_t i,old_time=last_access;
1219  cache_item *ci=list,*oldest=NULL;
1220  ful=1;
1221
1222  for (i=0;i<total;i++,ci++)
1223  {
1224    if (ci->data && ci->last_access<old_time)
1225    {
1226      oldest=ci;
1227      old_time=ci->last_access;
1228    }
1229  }
1230  if (oldest)
1231  {
1232    dprintf("mem_maker : freeing %s\n",spec_types[oldest->type]);
1233    unmalloc(oldest);   
1234  }
1235  else
1236  {
1237    close_graphics();
1238    printf("Out of memory, please remove any TSR's device drivers you can\n");
1239    mem_report("out_of_mem");
1240    exit(0);
1241  }         
1242}
1243
1244
1245void cache_list::show_accessed()
1246{
1247  int old=last_access,new_old_accessed;
1248  cache_item *ci,*new_old;
1249 
1250  do
1251  {
1252    new_old_accessed=-1;
1253    new_old=NULL;
1254    ci=list;
1255    for (int i=0;i<total;i++,ci++) 
1256    {
1257      if (ci->last_access<old && ci->last_access>0 && ci->last_access>new_old_accessed)   
1258      {
1259        new_old_accessed=ci->last_access;
1260        new_old=ci;   
1261      }
1262    }
1263    if (new_old)
1264    {
1265      ci=new_old;
1266      old=ci->last_access;
1267      printf("type=(%20s) file=(%20s) access=(%6ld)\n",spec_types[ci->type],
1268             crc_man.get_filename(ci->file_number),
1269             (long int)ci->last_access);
1270    }
1271  } while (new_old);
1272}
1273
1274
1275int cache_list::loaded(int id)
1276{
1277  cache_item *me=list+id;
1278  CONDITION(id<total && id>=0 && me->file_number>=0,"Bad id");
1279  if (me->last_access>=0) 
1280    return 1;
1281  else return 0;
1282}
1283
1284
1285
1286char_tint *cache_list::ctint(int id)
1287{
1288  cache_item *me=list+id;
1289  CONDITION(id<total && id>=0 && me->file_number>=0,"Bad id" && me->type==SPEC_PALETTE);
1290  if (me->last_access>=0) 
1291  {
1292    touch(me);
1293    return (char_tint *)me->data;
1294  }
1295  else
1296  {
1297    touch(me);
1298    locate(me);
1299    int sp=alloc_space; alloc_space=ALLOC_SPACE_CACHE;
1300    me->data=(void *)new char_tint(fp);
1301    alloc_space=sp;
1302    last_offset=fp->tell();
1303    return (char_tint *)me->data;
1304  }   
1305}
1306
1307
1308
1309
Note: See TracBrowser for help on using the repository browser.