home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / pc / ABUSESRC.ZIP / AbuseSrc / macabuse / src / cache.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-05-20  |  28.2 KB  |  1,247 lines

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