source: abuse/trunk/src/imlib/specs.cpp

Last change on this file was 555, checked in by Sam Hocevar, 12 years ago

ps3: make everything compile on the PS3. Of course, nothing links yet
because so much support is missing.

File size: 19.0 KB
Line 
1/*
2 *  Abuse - dark 2D side-scrolling platform game
3 *  Copyright (c) 1995 Crack dot Com
4 *  Copyright (c) 2005-2011 Sam Hocevar <sam@hocevar.net>
5 *
6 *  This software was released into the Public Domain. As with most public
7 *  domain software, no warranty is made or implied by Crack dot Com, by
8 *  Jonathan Clark, or by Sam Hocevar.
9 */
10
11#if defined HAVE_CONFIG_H
12#   include "config.h"
13#endif
14
15#include <stdio.h>
16#include <stdlib.h>
17#include <stdint.h>
18#include <ctype.h>
19#include <fcntl.h>
20#include <math.h>
21#include <unistd.h>
22#include <sys/types.h>
23#include <sys/stat.h>
24
25#include "common.h"
26
27#include "image.h"
28#include "palette.h"
29#include "specs.h"
30#include "dprint.h"
31
32char const *spec_types[] =
33{
34    "Invalid type", // 0
35    "Color table",  // 1
36    "Palette",      // 2
37    "Invalid Type", // 3
38    "Image",        // 4
39    "Fore Tile",
40    "Back Tile",
41    "Character",
42    "8 Morph",
43    "16 Morph",
44    "Grue objs",
45    "Extern WAV",
46    "DMX MUS",
47    "Patched morph",
48    "Normal file",
49    "Compress1 file",
50    "Vector Image",
51    "Light list",
52    "Grue fgmap",
53    "Grue bgmap",
54    "Data array",
55    "Character2",
56    "Particle",
57    "Extern lcache"
58};
59
60
61int total_files_open=0;
62char spec_main_file[100];
63
64static char *spec_prefix=NULL;
65static char *save_spec_prefix=NULL;
66
67static jFILE spec_main_jfile((FILE*)0);
68static int spec_main_fd = -1;
69static long spec_main_offset = -1;
70static spec_directory spec_main_sd;
71
72void set_filename_prefix(char const *prefix)
73{
74    if( spec_prefix )
75    {
76        free( spec_prefix );
77    }
78
79    if( prefix )
80    {
81        spec_prefix = strcpy( (char *)malloc( strlen( prefix ) + 2 ), prefix );
82        int len = strlen( prefix );
83        if( prefix[len - 1] != '\\' && prefix[len - 1] != '/')
84        {
85            spec_prefix[len] = '/';
86            spec_prefix[len + 1] = 0;
87        }
88    }
89    else
90    {
91        spec_prefix = NULL;
92    }
93}
94
95char *get_filename_prefix()
96{
97    return spec_prefix;
98}
99
100
101void set_save_filename_prefix(char const *save_prefix)
102{
103    if( save_spec_prefix )
104    {
105        free( save_spec_prefix );
106    }
107
108    if( save_prefix )
109    {
110        int len = strlen( save_prefix );
111        save_spec_prefix = (char *)malloc( len + 1 );
112        strcpy( save_spec_prefix, save_prefix );
113/* AK - Commented this out as it may cause problems
114        if( save_prefix[len - 1] != '\\' && save_prefix[len - 1] != '/' )
115        {
116            save_spec_prefix[len] = '/';
117            save_spec_prefix[len + 1] = '\0';
118        } */
119    }
120    else
121    {
122        save_spec_prefix = NULL;
123    }
124}
125
126char *get_save_filename_prefix()
127{
128  return save_spec_prefix;
129}
130
131int search_order=SPEC_SEARCH_OUTSIDE_INSIDE;
132
133static void (*no_space_handle_fun)()=NULL;
134
135void set_no_space_handler(void (*handle_fun)())
136{
137  no_space_handle_fun=handle_fun;
138}
139
140
141bFILE::bFILE()
142{
143  rbuf_size=8192;
144  rbuf=(unsigned char *)malloc(rbuf_size);
145  rbuf_start=rbuf_end=0;
146
147  wbuf_size=8192;
148  wbuf=(unsigned char *)malloc(wbuf_size);
149  wbuf_end=0;
150}
151
152bFILE::~bFILE()
153{
154  if (rbuf) free(rbuf);
155  flush_writes();
156  if (wbuf) free(wbuf);
157}
158
159int bFILE::flush_writes()
160{
161  if (wbuf_end!=0)
162  {
163    unsigned long ret=unbuffered_write(wbuf,wbuf_end);
164    if (ret!=wbuf_end && no_space_handle_fun)
165      no_space_handle_fun();
166
167    wbuf_end=0;
168    return ret;
169  }
170  return 0;
171}
172
173int bFILE::read(void *buf, size_t count)       // returns number of bytes read, calls unbuffer_read
174{
175  if (!allow_read_buffering())
176    return unbuffered_read(buf,count);
177
178  int total_read=0,error=0;
179  if (!count) return 0;
180  while (count && !error)
181  {
182    if (rbuf_start<rbuf_end)
183    {
184      unsigned int avail_size=rbuf_end-rbuf_start;
185      int copy_size=avail_size>count ? count : avail_size;
186      memcpy(buf,rbuf+rbuf_start,copy_size);
187      buf=(void *)(((unsigned char *)buf)+copy_size);
188      rbuf_start+=copy_size;
189      if (rbuf_start>=rbuf_end)
190      {
191                if (rbuf_end!=rbuf_size)  // buffer wasn't full before so there is no way we can complete read
192                  error=1;
193                rbuf_start=rbuf_end=0;
194      }
195      total_read+=copy_size;
196      count-=copy_size;
197    } else
198    {
199      rbuf_end=unbuffered_read(rbuf,rbuf_size);
200      if (rbuf_end==0) error=1;
201      rbuf_start=0;
202    }
203  }
204  return total_read;
205}
206
207
208int bFILE::write(void const *buf, size_t count)      // returns number of bytes written
209{
210  if (allow_write_buffering())
211  {
212    int total_written=0;
213    while (count)
214    {
215      int copy_size=wbuf_end+count<=wbuf_size ? count :  wbuf_size-wbuf_end;
216      memcpy(wbuf+wbuf_end,buf,copy_size);
217      wbuf_end+=copy_size;
218      count-=copy_size;
219      buf=(void *)(((char *)buf)+copy_size);
220      if (wbuf_end==wbuf_size)
221        if ((unsigned int)flush_writes()!=wbuf_size)
222      return total_written;
223
224      total_written+=copy_size;
225    }
226    return total_written;
227  } else
228  {
229    unsigned long ret=unbuffered_write(buf,count);
230    if (ret!=count && no_space_handle_fun)
231      no_space_handle_fun();
232  }
233  return 0;
234}
235
236int bFILE::seek(long offset, int whence) // whence=SEEK_SET, SEEK_CUR, SEEK_END, ret=0=success
237{
238//    rbuf_start=rbuf_end=0;
239//    unbuffered_seek(offset,SEEK_SET);
240
241  long realpos=unbuffered_tell();
242  long curpos=realpos-rbuf_end+rbuf_start;
243  if (whence==SEEK_CUR) offset+=curpos;
244  else if (whence==SEEK_END) offset=file_size()-offset;
245
246  if (offset<realpos-(long)rbuf_end || offset>=realpos)
247  {
248    rbuf_start=rbuf_end=0;
249    unbuffered_seek(offset,SEEK_SET);
250  } else
251    rbuf_start=rbuf_end-(realpos-offset);
252  return 1;
253}
254
255int bFILE::tell()
256{
257  return unbuffered_tell()-rbuf_end+rbuf_start+
258         wbuf_end;    // if this a write file, add on how much we've written
259}
260
261int bFILE::allow_read_buffering() { return 1; }
262int bFILE::allow_write_buffering() { return 1; }
263
264void set_spec_main_file(char const *filename, int Search_order)
265{
266  dprintf("Specs : main file set to %s\n",filename);
267  strcpy(spec_main_file,filename);
268  search_order=Search_order;
269
270#if (defined(__APPLE__) && !defined(__MACH__))
271  spec_main_jfile.open_external(filename,"rb",O_BINARY|O_RDONLY);
272#else
273  spec_main_jfile.open_external(filename,"rb",O_RDONLY);
274#endif
275  spec_main_fd = spec_main_jfile.get_fd();
276  if (spec_main_fd==-1)
277    return;
278  spec_main_sd.startup(&spec_main_jfile);
279}
280
281jFILE::jFILE(FILE *file_pointer)                       // assumes fp is at begining of file
282{
283  access=0;
284  fd=-1;
285  file_length=0;
286  start_offset=0;
287  flags=JFILE_CLONED;
288}
289
290void jFILE::open_external(char const *filename, char const *mode, int flags)
291{
292  int skip_size=0;
293  char tmp_name[200];
294  if (spec_prefix && filename[0] != '/')
295    sprintf(tmp_name,"%s%s",spec_prefix,filename);
296  else strcpy(tmp_name,filename);
297
298//  int old_mask=umask(S_IRWXU | S_IRWXG | S_IRWXO);
299  if (flags&O_WRONLY)
300  {
301    if ((flags&O_APPEND)==0)
302    {
303      skip_size=1;
304      //int errval = unlink(tmp_name);
305    }
306
307    flags-=O_WRONLY;
308    flags|=O_CREAT|O_RDWR;
309
310    fd=open(tmp_name,flags,S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
311  } else
312    fd=open(tmp_name,flags);
313
314//  umask(old_mask);
315  if (fd>=0 && !skip_size)
316  {
317    file_length=lseek(fd,0,SEEK_END);
318    if ((flags&O_APPEND)==0)
319      lseek(fd,0,SEEK_SET);
320    else
321        current_offset = file_length;
322    start_offset=0;
323  } else
324  {
325    file_length=0;
326    start_offset=0;
327  }
328}
329
330
331class null_file : public bFILE     // this file type will use virtual opens inside of a spe
332{
333  public :
334  virtual int open_failure() { return 1; }
335  virtual int unbuffered_read(void *buf, size_t count)   { return 0; }
336  virtual int unbuffered_write(void const *buf, size_t count)  { return 0; }
337  virtual int unbuffered_seek(long offset, int whence)   { return 0; }
338
339  virtual int unbuffered_tell() { return 0; }
340  virtual int file_size() { return 0; }
341  virtual ~null_file() { ; }
342} ;
343
344
345static bFILE *(*open_file_fun)(char const *,char const *)=NULL;
346int (*verify_file_fun)(char const *,char const *)=NULL;
347
348void set_file_opener(bFILE *(*open_fun)(char const *, char const *))
349{
350  open_file_fun=open_fun;
351}
352
353bFILE *open_file(char const *filename, char const *mode)
354{
355  if (!verify_file_fun || verify_file_fun(filename,mode))
356  {
357    if (open_file_fun)
358      return open_file_fun(filename,mode);
359    else return new jFILE(filename,mode);
360  } else return new null_file;
361}
362
363void jFILE::open_internal(char const *filename, char const *mode, int flags)
364{
365  int wr=0;
366  for (char const *s=mode; *s; s++)
367    if (toupper(*s)=='A' || toupper(*s)=='W')
368      wr=1;
369
370  if (wr)
371    fd=-1;                 // only allow extern file openings for writing
372  else
373  {
374       fd = spec_main_fd;
375    if (fd>=0)                    // if we were able to open the main file, see if it's in there
376    {
377      start_offset=0;
378      spec_entry *se=spec_main_sd.find(filename);
379      if (se)
380      {
381    start_offset=se->offset;
382    current_offset = 0;
383    file_length=se->size;
384    rbuf_start=rbuf_end=0;
385      } else
386      {
387    close(fd);
388    fd=-1;
389      }
390    }
391  }
392}
393
394jFILE::jFILE(char const *filename, char const *access_string)      // same as fopen parameters
395{
396 flags=access=0;
397 char const *s=access_string;
398  for (; *s; s++)
399    if (toupper(*s)=='R') access=O_RDONLY;
400
401  for (s=access_string; *s; s++)
402    if (toupper(*s)=='W')
403    {
404      if (access)
405        access=O_RDWR;
406      else access=O_WRONLY;
407    }
408
409  for (s=access_string; *s; s++)
410    if (toupper(*s)=='A')
411      access|=O_APPEND|O_WRONLY;
412
413  file_length=start_offset=-1;
414  current_offset = 0;
415
416  fd=-1;
417  if (search_order==SPEC_SEARCH_OUTSIDE_INSIDE)
418    open_external(filename,access_string,access);
419
420  if (fd<0)
421    open_internal(filename,access_string,access);
422
423  if (fd<0 && search_order==SPEC_SEARCH_INSIDE_OUTSIDE)
424    open_external(filename,access_string,access);
425
426  total_files_open++;
427}
428
429jFILE::~jFILE()
430{
431  flush_writes();
432  if (fd>=0 && !(flags&JFILE_CLONED))
433  {
434    total_files_open--;
435    if (fd != spec_main_fd)
436        close(fd);
437  }
438}
439
440int jFILE::unbuffered_tell()
441{
442//    int ret = ::lseek(fd,0,SEEK_CUR) - start_offset;
443//    if (ret != current_offset)
444//        fprintf(stderr,"Bad tell %d\n",current_offset);
445    return current_offset;
446}
447
448int jFILE::unbuffered_read(void *buf, size_t count)
449{
450    unsigned long len;
451
452    if (fd == spec_main_fd)
453    {
454        if (current_offset+start_offset != spec_main_offset)
455            spec_main_offset = lseek(fd, start_offset+current_offset, SEEK_SET);
456
457        len = ::read(fd,(char*)buf,count);
458        spec_main_offset += len;
459    }
460    else
461    {
462      len = ::read(fd,(char*)buf,count);
463    }
464    current_offset += len;
465    return len;
466}
467
468int jFILE::unbuffered_write(void const *buf, size_t count)
469{
470  long ret = ::write(fd,(char*)buf,count);
471    current_offset += ret;
472    return ret;
473}
474
475int jFILE::unbuffered_seek(long offset, int whence) // whence=SEEK_SET, SEEK_CUR, SEEK_END, ret=0=success
476{
477  long ret;
478
479  switch (whence)
480  {
481    case SEEK_SET :
482    { ret = lseek(fd,start_offset+offset,SEEK_SET); } break;
483    case SEEK_END :
484    { ret = lseek(fd,start_offset+file_length-offset,SEEK_SET); } break;
485    case SEEK_CUR :
486    { ret = lseek(fd,offset,SEEK_CUR); } break;
487    default:
488        ret = -1;
489        break;
490  }
491  if (ret>=0)
492  {
493    current_offset = ret - start_offset;
494    if (spec_main_fd == fd)
495      spec_main_offset = ret;
496    return ret;
497  }
498  else
499    return -1;  // if a bad whence, then failure
500}
501
502
503uint8_t bFILE::read_uint8()
504{ uint8_t x;
505  read(&x,1);
506  return x;
507}
508
509uint16_t bFILE::read_uint16()
510{
511  uint16_t x;
512  read(&x,2);
513  return lstl(x);
514}
515
516
517uint32_t bFILE::read_uint32()
518{
519  uint32_t x;
520  read(&x,4);
521  return lltl(x);
522}
523
524void bFILE::write_uint8(uint8_t x)
525{
526  write(&x,1);
527}
528
529void bFILE::write_uint16(uint16_t x)
530{
531  x=lstl(x);
532  write(&x,2);
533}
534
535
536void bFILE::write_uint32(uint32_t x)
537{
538  x=lltl(x);
539  write(&x,4);
540}
541
542void bFILE::write_double(double x)
543{
544  double a;
545  write_uint32((long)(modf(x,&a)*(double)(1<<31)));
546  write_uint32((long)a);
547}
548
549double bFILE::read_double()
550{
551  long a,b;
552  a=read_uint32();
553  b=read_uint32();
554  return (double)b+a/(double)(1<<31);
555}
556
557spec_directory::~spec_directory()
558{
559
560  if (total)
561  {
562    free(data);
563    free(entries);
564  }
565}
566
567void spec_directory::FullyLoad(bFILE *fp)
568{
569    for (int i = 0; i < total; i++)
570    {
571        spec_entry *se = entries[i];
572        free(se->data);
573        se->data = malloc(se->size);
574        fp->seek(se->offset, SEEK_SET);
575        fp->read(se->data, se->size);
576    }
577}
578
579spec_entry::spec_entry(uint8_t spec_type, char const *object_name,
580                       char const *link_filename,
581                       unsigned long data_size, unsigned long data_offset)
582{
583    type = spec_type;
584    name = strdup(object_name);
585    data = NULL;
586    size = data_size;
587    offset = data_offset;
588}
589
590spec_entry::~spec_entry()
591{
592    free(name);
593    free(data);
594}
595
596void spec_entry::Print()
597{
598    printf("%15s%25s%8ld%8ld\n", spec_types[type], name, size, offset);
599}
600
601void spec_directory::calc_offsets()
602{
603    size_t o = SPEC_SIG_SIZE + 2;
604
605    // calculate the size of directory info
606    for (int i = 0; i < total; i++)
607        o += 1 + 1 + strlen(entries[i]->name) + 1 + 1 + 8;
608
609    // calculate offset for each entry
610    for (int i = 0; i < total; i++)
611    {
612        entries[i]->offset = o;
613        o += entries[i]->size;
614    }
615}
616
617spec_entry *spec_directory::find(char const *name, int type)
618{
619  int i;
620  spec_entry **e;
621  for (i=0,e=entries; i<total; i++,e++)
622    if (!strcmp((*e)->name,name) && (*e)->type==type)
623      return (*e);
624  return NULL;
625}
626
627spec_entry *spec_directory::find(char const *name)
628{
629  int i;
630  spec_entry **e;
631  for (i=0,e=entries; i<total; i++,e++)
632    if (!strcmp((*e)->name,name))
633      return (*e);
634  return NULL;
635}
636
637long spec_directory::find_number(char const *name)
638{
639  int i;
640  spec_entry **e;
641  for (i=0,e=entries; i<total; i++,e++)
642    if (!strcmp((*e)->name,name))
643      return i;
644  return -1;
645}
646
647spec_entry *spec_directory::find(int type)
648{
649  int i;
650  spec_entry **e;
651  for (i=0,e=entries; i<total; i++,e++)
652    if ((*e)->type==type)
653      return (*e);
654  return NULL;
655}
656
657long spec_directory::type_total(int type)
658{
659  int i,x=0;
660  spec_entry **e;
661  for (i=0,e=entries; i<total; i++,e++)
662    if ((*e)->type==type) x++;
663  return x;
664}
665
666long spec_directory::find_number(int type)
667{
668  int i;
669  spec_entry **e;
670  for (i=0,e=entries; i<total; i++,e++)
671    if ((*e)->type==type)
672      return i;
673  return -1;
674}
675
676void spec_directory::print()
677{
678  spec_entry **se;
679  int i;
680  printf("[   Entry type   ][   Entry name   ][  Size  ][ Offset ]\n");
681  for (i=0,se=entries; i<total; i++,se++)
682    (*se)->Print();
683}
684
685
686void spec_directory::startup(bFILE *fp)
687{
688  char buf[256];
689  memset(buf,0,256);
690  fp->read(buf,8);
691  buf[9]=0;
692  size=0;
693  if (!strcmp(buf,SPEC_SIGNATURE))
694  {
695    total=fp->read_uint16();
696    entries=(spec_entry **)malloc(sizeof(spec_entry *)*total);
697    long start=fp->tell();
698
699    int i;
700    for (i=0; i<total; i++)
701    {
702      fp->read(buf,2);
703      long entry_size=sizeof(spec_entry)+(unsigned char)buf[1];
704      entry_size=(entry_size+3)&(~3);
705      fp->read(buf,(unsigned char)buf[1]);
706      fp->read(buf,9);
707
708      size+=entry_size;
709    }
710    data=malloc(size);
711    char *dp=(char *)data;
712    fp->seek(start,SEEK_SET);
713    for (i=0; i<total; i++)
714    {
715      spec_entry *se=(spec_entry *)dp;
716      entries[i]=se;
717
718      unsigned char len,flags,type;
719      fp->read(&type,1);
720      fp->read(&len,1);
721      se->type=type;
722      se->data = NULL;
723      se->name=dp+sizeof(spec_entry);
724      fp->read(se->name,len);
725      fp->read(&flags,1);
726
727      se->size=fp->read_uint32();
728      se->offset=fp->read_uint32();
729      dp+=((sizeof(spec_entry)+len)+3)&(~3);
730    }
731  }
732  else
733  {
734    total=0;
735    data=NULL;
736    entries=NULL;
737  }
738}
739
740
741spec_directory::spec_directory(bFILE *fp)
742{ startup(fp); }
743
744spec_directory::spec_directory(FILE *fp)
745{
746  jFILE jfp(fp);
747  startup(&jfp);
748}
749
750spec_directory::spec_directory()
751{
752  size=0;
753  total=0;
754  data=NULL;
755  entries=NULL;
756}
757
758/*
759spec_directory::spec_directory(char *filename)
760{
761  jFILE *fp;
762  if (filename)
763  {
764    fp=new jFILE(filename,"rb");
765    if (!fp->open_failure())
766      startup(fp);
767    else
768    {
769      total=0;
770      entries=NULL;
771    }
772    delete fp;
773  } else printf("NULL filename to spec_directory::spec_directory\n");
774}*/
775
776int write_string(bFILE *fp, char const *st)
777{
778  unsigned char length=strlen(st)+1;
779  if (fp->write(&length,1)!=1) return 0;
780  if (fp->write(st,length)!=length) return 0;
781  return 1;
782}
783
784long spec_directory::data_start_offset()
785{
786    /* FIXME: no need for a for loop here! */
787    long i;
788    for(i = 0; i < total; i++)
789        return entries[i]->offset;
790
791    // If no entries, then no data, but return where it would start anyway
792    return SPEC_SIG_SIZE + 2;
793}
794
795long spec_directory::data_end_offset()
796{
797    /* FIXME: no need for a for loop here! */
798  spec_entry **e;
799  long i;
800  for (i=total-1,e=entries; i>=0; i--,e++)
801    return (*e)->offset+(*e)->size;
802
803  return SPEC_SIG_SIZE+2;
804}
805
806int spec_directory::write(bFILE *fp)
807{
808
809  char sig[SPEC_SIG_SIZE];
810  unsigned char flags=0;
811  unsigned long offset,data_size;
812  spec_entry **e;
813  strcpy(sig,SPEC_SIGNATURE);
814
815  if (fp->write(sig,sizeof(sig))!=sizeof(sig))    return 0;
816  fp->write_uint16(total);
817
818
819  int i;
820  for (i=0,e=entries; i<total; i++,e++)
821  {
822    if (fp->write(&(*e)->type,1)!=1)                 return 0;
823    if (!write_string(fp,(*e)->name))                return 0;
824    flags=0;
825    if (fp->write(&flags,1)!=1)                     return 0;
826
827    data_size=lltl((*e)->size);
828    if (fp->write((char *)&data_size,4)!=4)              return 0;
829    offset=lltl((*e)->offset);
830    if (fp->write((char *)&offset,4)!=4)                  return 0;
831
832  }
833  return 1;
834}
835
836jFILE *spec_directory::write(char const *filename)
837{
838  jFILE *fp;
839  fp=new jFILE(filename,"wb");
840  if (fp->open_failure()) { delete fp; return NULL; }
841  if (!write(fp))
842  {
843    delete fp;
844    return NULL;
845  } else return fp;
846
847}
848
849uint16_t read_uint16(FILE *fp)
850{
851  uint16_t x;
852  fread(&x,1,2,fp);
853  return lstl(x);
854}
855
856uint32_t read_uint32(FILE *fp)
857{
858  uint32_t x;
859  fread(&x,1,4,fp);
860  return lltl(x);
861}
862void write_uint16(FILE *fp, uint16_t x)
863{
864  x=lstl(x);
865  fwrite(&x,1,2,fp);
866}
867
868void write_uint32(FILE *fp, uint32_t x)
869{
870  x=lltl(x);
871  fwrite(&x,1,4,fp);
872}
873
874uint8_t read_uint8(FILE *fp) { return fgetc(fp)&0xff; }
875void write_uint8(FILE *fp, uint8_t x) { fputc((unsigned char)x,fp); }
876
877void spec_directory::remove(spec_entry *e)
878{
879  int i;
880  for (i=0; i<total && entries[i]!=e; i++);            // find the entry in the array first
881
882  if (entries[i]==e)                                 // make sre it was found
883  {
884    delete e;
885    total--;
886    for (; i<total; i++)                               // compact the pointer array
887      entries[i]=entries[i+1];
888    entries=(spec_entry **)realloc(entries,sizeof(spec_entry *)*total);
889  }
890  else
891    printf("Spec_directory::remove bad entry pointer\n");
892}
893
894
895
896void spec_directory::add_by_hand(spec_entry *e)
897{
898  total++;
899  entries=(spec_entry **)realloc(entries,sizeof(spec_entry *)*total);
900  entries[total-1]=e;
901}
902
903void spec_directory::delete_entries()   // if the directory was created by hand instead of by file
904{
905  int i;
906  for (i=0; i<total; i++)
907    delete entries[i];
908
909  if (total)
910    free(entries);
911}
912
913void note_open_fd(int fd, char const *str)
914{
915    total_files_open++;
916}
917
918void note_close_fd(int fd)
919{
920    total_files_open--;
921}
922
923void list_open_fds()
924{
925    printf("Total open file descriptors: %d\n", total_files_open);
926}
927
Note: See TracBrowser for help on using the repository browser.