/**********************************************************************
This file is part of Crack dot Com's free source code release of
Golgotha.
for
information about compiling & licensing issues visit this URL
If that doesn't help, contact Jonathan Clark at
golgotha_source@usa.net (Subject should have "GOLG" in it)
***********************************************************************/
//{{{ File & File Manager Classes
//
//$Id: file.cc,v 1.48 1998/07/15 21:16:39 jc Exp $
#include "file/file.hh"
#include "memory/malloc.hh"
#include "error/error.hh"
#include "time/profile.hh"
#include "error/error.hh"
#include "file/file_man.hh"
#include "string/string.hh"
#include
#include
#include
#include
static i4_profile_class pf_tell("File tell");
static i4_profile_class pf_open("File Open");
static i4_profile_class pf_sopen("System file Open");
static i4_profile_class pf_close("File Close");
static i4_profile_class pf_read("File Read");
static i4_profile_class pf_con_buf("::buffered file");
i4_bool i4_file_class::async_write(const void *buffer, w32 size,
async_callback call,
void *context)
{
(*call)(write(buffer, size), context);
return i4_T;
}
i4_bool i4_file_class::async_read (void *buffer, w32 size,
async_callback call,
void *context)
{
(*call)(read(buffer, size), context);
return i4_T;
}
class file_string : public i4_str
{
public:
file_string(w16 size) : i4_str(size) {}
char *buffer() { return (char *)ptr; }
void set_len(w16 _len) { len = _len; }
};
i4_str* i4_file_class::read_str(w32 len)
{
file_string *str = new file_string((w16)len);
len = read(str->buffer(),len);
str->set_len((w16)len);
return str;
}
i4_str* i4_file_class::read_counted_str()
{
w16 len = read_16();
return read_str(len);
}
class file_write_string : public i4_const_str
{
public:
char *buffer() { return (char *)ptr; }
};
w32 i4_file_class::write_str(const i4_const_str &str)
{
file_write_string *s = (file_write_string *)&str;
return write(s->buffer(), s->length());
}
w32 i4_file_class::write_counted_str(const i4_const_str &str)
{
w32 count;
count = write_16((w16)str.length());
if (str.length())
return (count + write_str(str));
else
return count;
}
static inline int fmt_char(char c)
{
if ((c>='a' && c<='z') || (c>='A' && c<='Z'))
return 1;
return 0;
}
// same as fprintf, but with the addition %S is a i4_const_str *
int i4_file_class::printf(char *fmt, ...)
{
w32 start=tell();
va_list ap;
va_start(ap, fmt);
while (*fmt)
{
if (*fmt=='%')
{
char *fmt_end=fmt;
while (!fmt_char(*fmt_end) && *fmt_end) fmt_end++;
char f[10], out[500];
memcpy(f, fmt, fmt_end-fmt+1);
f[fmt_end-fmt+1]=0;
out[0]=0;
switch (*fmt_end)
{
case 's' :
{
char *str=va_arg(ap,char *);
write(str,strlen(str));
} break;
case 'S' :
{
i4_const_str *s=va_arg(ap,i4_const_str *);
write_str(*s);
} break;
case 'd' :
case 'i' :
case 'x' :
case 'X' :
case 'c' :
case 'o' :
{
::sprintf(out,f,va_arg(ap,int));
write(out,strlen(out));
} break;
case 'f' :
case 'g' :
::sprintf(out,f,va_arg(ap,double));
write(out,strlen(out));
break;
default :
::sprintf(out,f,va_arg(ap,void *));
write(out,strlen(out));
break;
}
fmt=fmt_end;
if (*fmt)
fmt++;
}
else
{
write_8(*fmt);
fmt++;
}
}
va_end(ap);
return tell()-start;
}
int i4_file_class::write_format(char *format, ...)
{
char *f=format;
va_list ap;
va_start(ap, format);
int start=tell();
while (*f)
{
switch (*f)
{
case '1' : write_8(*(va_arg(ap, w8 *))); break;
case '2' : write_16(*(va_arg(ap, w16 *))); break;
case '4' : write_32(*(va_arg(ap, w32 *))); break;
case 'f' : write_float(*(va_arg(ap, float *))); break;
case 'S' : write_counted_str( *(va_arg(ap, i4_const_str *))); break;
}
f++;
}
va_end(ap);
return tell()-start;
}
// format is same as write_format, returns number of fields written
int i4_file_class::read_format(char *format, ...)
{
char *f=format;
va_list ap;
va_start(ap, format);
int start=tell();
while (*f)
{
switch (*f)
{
case '1' : *(va_arg(ap, w8 *))=read_8(); break;
case '2' : *(va_arg(ap, w16 *))=read_16(); break;
case '4' : *(va_arg(ap, w32 *))=read_32(); break;
case 'f' : *(va_arg(ap, float*))=read_float(); break;
case 'S' : *(va_arg(ap, i4_str **))=read_counted_str(); break;
}
f++;
}
va_end(ap);
return tell()-start;
}
// returns NULL if unable to open file
i4_file_class *i4_open(const i4_const_str &name, w32 flags)
{
for (i4_file_manager_class *m=i4_file_manager_class::first; m; m=m->next)
{
i4_file_class *fp=m->open(name,flags);
if (fp)
return fp;
}
return 0;
}
// return i4_F on failure
i4_bool i4_unlink(const i4_const_str &name)
{
for (i4_file_manager_class *m=i4_file_manager_class::first; m; m=m->next)
if (m->unlink(name))
return i4_T;
return i4_F;
}
// returns i4_F if file does not exsist
i4_bool i4_get_status(const i4_const_str &filename,
i4_file_status_struct &return_stat)
{
for (i4_file_manager_class *m=i4_file_manager_class::first; m; m=m->next)
if (m->get_status(filename, return_stat))
return i4_T;
return i4_F;
}
// return i4_F on failure
i4_bool i4_mkdir(const i4_const_str &name)
{
for (i4_file_manager_class *m=i4_file_manager_class::first; m; m=m->next)
if (m->mkdir(name))
return i4_T;
return i4_F;
}
// returns i4_F if path is bad (tfiles and tdirs will be 0 as well)
// you are responsible for deleting both the array of strings and each string in the array
// file_status is a pointer to an array of file_status's that will be created, you
// must free these as well. file_status may be 0 (default), in which case no array is created
i4_bool i4_get_directory(const i4_const_str &path,
i4_directory_struct &dir_struct,
i4_bool get_status,
i4_status_class *status)
{
for (i4_file_manager_class *m=i4_file_manager_class::first; m; m=m->next)
if (m->get_directory(path, dir_struct, get_status, status))
return i4_T;
return i4_F;
}
// returns i4_F if path cannot be split
i4_bool i4_split_path(const i4_const_str &name, i4_filename_struct &fname_struct)
{
for (i4_file_manager_class *m=i4_file_manager_class::first; m; m=m->next)
if (m->split_path(name, fname_struct))
return i4_T;
return i4_F;
}
// return 0 if full path cannot be determined
i4_str *i4_full_path(const i4_const_str &relative_name)
{
for (i4_file_manager_class *m=i4_file_manager_class::first; m; m=m->next)
{
i4_str *s=m->full_path(relative_name);
if (s)
return s;
}
return 0;
}
i4_file_manager_class *i4_file_manager_class::first=0;
void i4_add_file_manager(i4_file_manager_class *fman, i4_bool add_front)
{
if (add_front)
{
fman->next=i4_file_manager_class::first;
i4_file_manager_class::first=fman;
}
else
{
i4_file_manager_class *last=0, *p=i4_file_manager_class::first;
while (p)
{
last=p;
p=p->next;
}
if (!last)
i4_add_file_manager(fman, i4_T);
else
{
last->next=fman;
fman->next=0;
}
}
}
void i4_remove_file_manger(i4_file_manager_class *fman)
{
i4_file_manager_class *last=0, *p=i4_file_manager_class::first;
while (p && p!=fman)
{
last=p;
p=p->next;
}
if (p!=fman)
i4_error("unable to find file manager");
else if (last)
last->next=fman->next;
else
i4_file_manager_class::first=fman->next;
}
i4_bool i4_file_manager_class::split_path(const i4_const_str &name, i4_filename_struct &fn)
{
char buf[512];
i4_os_string(name, buf, 512);
char *p=buf, *last_slash=0, *last_dot=0, *q;
while (*p)
{
if (*p=='/' || *p=='\\')
last_slash=p;
else if (*p=='.')
last_dot=p;
p++;
}
if (last_dot)
{
q=fn.extension;
for (p=last_dot+1; *p; )
*(q++)=*(p++);
*q=0;
}
else last_dot=p;
if (last_slash)
{
q=fn.path;
for (p=buf; p!=last_slash; )
*(q++)=*(p++);
*q=0;
last_slash++;
}
else last_slash=buf;
q=fn.filename;
for (p=last_slash; p!=last_dot;)
*(q++)=*(p++);
*q=0;
return i4_T;
}
i4_directory_struct::~i4_directory_struct()
{
int i;
for (i=0; i