From c5ab2adbf0c14a6d0d4e2245a616d01de4b88214 Mon Sep 17 00:00:00 2001 From: inmarket Date: Fri, 24 Jan 2014 19:33:28 +1000 Subject: [PATCH] More code for GFile --- include/gfile/gfile.h | 34 ++++++-------- src/gfile/gfile.c | 95 ++++++++++++++++++++++++++++++++++++++-- src/gfile/inc_nativefs.c | 23 ++++++++-- src/gfile/inc_romfs.c | 14 +----- 4 files changed, 128 insertions(+), 38 deletions(-) diff --git a/include/gfile/gfile.h b/include/gfile/gfile.h index 675342fb..5b49a6b3 100644 --- a/include/gfile/gfile.h +++ b/include/gfile/gfile.h @@ -34,13 +34,17 @@ typedef struct GFILE { const struct GFILEVMT * vmt; uint16_t flags; - #define GFILEFLG_OPEN 0x0001 - #define GFILEFLG_READ 0x0002 - #define GFILEFLG_WRITE 0x0004 - #define GFILEFLG_APPEND 0x0008 - #define GFILEFLG_CANSEEK 0x0010 - #define GFILEFLG_DELONCLOSE 0x0020 - #define GFILEFLG_FAILONBLOCK 0x0040 + #define GFILEFLG_OPEN 0x0001 // File is open + #define GFILEFLG_READ 0x0002 // Read the file + #define GFILEFLG_WRITE 0x0004 // Write the file + #define GFILEFLG_APPEND 0x0008 // Append on each write + #define GFILEFLG_BINARY 0x0010 // Treat as a binary file + #define GFILEFLG_DELONCLOSE 0x0020 // Delete on close + #define GFILEFLG_CANSEEK 0x0040 // Seek operations are valid + #define GFILEFLG_FAILONBLOCK 0x0080 // Fail on a blocking call + #define GFILEFLG_MUSTEXIST 0x0100 // On open file must exist + #define GFILEFLG_MUSTNOTEXIST 0x0200 // On open file must not exist + #define GFILEFLG_TRUNC 0x0400 // On open truncate the file short err; void * obj; long int pos; @@ -48,18 +52,18 @@ typedef struct GFILE { typedef struct GFILEVMT { const struct GFILEVMT * next; - char prefix; - uint16_t flags; + uint8_t flags; #define GFSFLG_WRITEABLE 0x0001 #define GFSFLG_CASESENSITIVE 0x0002 #define GFSFLG_SEEKABLE 0x0004 #define GFSFLG_FAST 0x0010 #define GFSFLG_SMALL 0x0020 + char prefix; bool_t del(const char *fname); bool_t exists(const char *fname); long int filesize(const char *fname); bool_t ren(const char *oldname, const char *newname); - bool_t open(GFILE *f, const char *fname, const char *mode); + bool_t open(GFILE *f, const char *fname); void close(GFILE *f); int read(GFILE *f, char *buf, int size); int write(GFILE *f, char *buf, int size); @@ -104,16 +108,6 @@ extern GFILE *gfileStdOut; //ungetc //void perror (const char * str); -//"r" read: Open file for input operations. The file must exist. -//"w" write: Create an empty file for output operations. If a file with the same name already exists, its contents are discarded and the file is treated as a new empty file. -//"a" append: Open file for output at the end of a file. Output operations always write data at the end of the file, expanding it. Repositioning operations (fseek, fsetpos, rewind) are ignored. The file is created if it does not exist. -//"r+" read/update: Open a file for update (both for input and output). The file must exist. -//"w+" write/update: Create an empty file and open it for update (both for input and output). If a file with the same name already exists its contents are discarded and the file is treated as a new empty file. -//"a+" append/update: Open a file for update (both for input and output) with all output operations writing data at the end of the file. Repositioning operations (fseek, fsetpos, rewind) affects the next input operations, but output operations move the position back to the end of file. The file is created if it does not exist. -//"...b" A binary stream -//"...x" Added to "w" - fail if file exists - - #ifdef __cplusplus extern "C" { #endif diff --git a/src/gfile/gfile.c b/src/gfile/gfile.c index bf76e8bc..83e487a1 100644 --- a/src/gfile/gfile.c +++ b/src/gfile/gfile.c @@ -147,7 +147,7 @@ long int gfileGetFilesize(const char *fname) { bool_t gfileRename(const char *oldname, const char *newname) { const GFILEVMT *p; - if ((oldname[0] && oldname[1] == '|') || (newname[0] && newname[1])) { + if ((oldname[0] && oldname[1] == '|') || (newname[0] && newname[1] == '|')) { char ch; if (oldname[0] && oldname[1] == '|') { @@ -155,6 +155,7 @@ bool_t gfileRename(const char *oldname, const char *newname) { oldname += 2; if (newname[0] && newname[1] == '|') { if (newname[0] != ch) + // Both oldname and newname are fs specific but different ones. return FALSE; newname += 2; } @@ -175,12 +176,100 @@ bool_t gfileRename(const char *oldname, const char *newname) { return FALSE; } -GFILE *gfileOpen(const char *fname, const char *mode) { +static uint16_t mode2flags(const char *mode) { + uint16_t flags; + switch(mode[0]) { + case 'r': + flags = GFILEFLG_READ|GFILEFLG_MUSTEXIST; + while (*++mode) { + switch(mode[0]) { + case '+': flags |= GFILEFLG_WRITE; break; + case 'b': flags |= GFILEFLG_BINARY; break; + } + } + return flags; + case 'w': + flags = GFILEFLG_WRITE|GFILEFLG_TRUNC; + while (*++mode) { + switch(mode[0]) { + case '+': flags |= GFILEFLG_READ; break; + case 'b': flags |= GFILEFLG_BINARY; break; + case 'x': flags |= GFILEFLG_MUSTNOTEXIST; break; + } + } + return flags; + case 'a': + flags = GFILEFLG_WRITE|GFILEFLG_APPEND; + while (*++mode) { + switch(mode[0]) { + case '+': flags |= GFILEFLG_READ; break; + case 'b': flags |= GFILEFLG_BINARY; break; + case 'x': flags |= GFILEFLG_MUSTNOTEXIST; break; + } + } + return flags; + } + return 0; +} + +static bool_t testopen(const GFILEVMT *p, GFILE *f, const char *fname) { + // If we want write but the fs doesn't allow it then return + if ((f->flags & GFILEFLG_WRITE) && !(p->flags & GFSFLG_WRITEABLE)) + return FALSE; + + // Try to open + if (!p->open || !p->open(f, fname)) + return FALSE; + + // File is open - fill in all the details + f->vmt = p; + f->err = 0; + f->pos = 0; + f->flags |= GFILEFLG_OPEN; + if (p->flags & GFSFLG_SEEKABLE) + f->flags |= GFILEFLG_CANSEEK; + return TRUE; +} + +GFILE *gfileOpen(const char *fname, const char *mode) { + GFILE *f; + const GFILEVMT *p; + + // First find an available GFILE slot. + for (f = gfileArr; f < &gfileArr[GFILE_MAX_GFILES]; f++) { + if (!(f->flags & GFILEFLG_OPEN)) { + + // Get the requested mode + if (!(f->flags = mode2flags(mode))) + return FALSE; + + // Try to open the file + if (fname[0] && fname[1] == '|') { + for(p = FsChain; p; p = p->next) { + if (p->prefix == fname[0]) + return testopen(p, f, fname+2); + } + } else { + for(p = FsChain; p; p = p->next) { + if (testopen(p, f, fname)) + return TRUE; + } + } + + // File not found + return FALSE; + } + } + + // No available slot + return FALSE; } void gfileClose(GFILE *f) { - + // Make sure it is one of the system GFILE's + if (f < gfileArr || f >= &gfileArr[GFILE_MAX_GFILES]) + return; } size_t gfileRead(GFILE *f, char *buf, size_t len) { diff --git a/src/gfile/inc_nativefs.c b/src/gfile/inc_nativefs.c index 7828ff84..ccf1d40a 100644 --- a/src/gfile/inc_nativefs.c +++ b/src/gfile/inc_nativefs.c @@ -36,11 +36,11 @@ static bool_t NativeEof(GFILE *f); static const GFILEVMT FsNativeVMT = { GFILE_CHAINHEAD, // next - 'N', // prefix #if !defined(WIN32) && !GFX_USE_OS_WIN32 GFSFLG_CASESENSITIVE| #endif GFSFLG_WRITEABLE|GFSFLG_SEEKABLE|GFSFLG_FAST, // flags + 'N', // prefix NativeDel, NativeExists, NativeFilesize, NativeRen, NativeOpen, NativeClose, NativeRead, NativeWrite, NativeSetpos, NativeGetsize, NativeEof, @@ -48,6 +48,23 @@ static const GFILEVMT FsNativeVMT = { #undef GFILE_CHAINHEAD #define GFILE_CHAINHEAD &FsNativeVMT +static char *flags2mode(char *buf, uint16_t flags) { + if (flags & GFILEFLG_MUSTEXIST) + *buf = 'r'; + else if (flags & GFILEFLG_APPEND) + *buf = 'a'; + else + *buf = 'w'; + buf++; + if ((flags & (GFILEFLG_READ|GFILEFLG_WRITE)) == (GFILEFLG_READ|GFILEFLG_WRITE)) + *buf++ = '+'; + if (flags & GFILEFLG_BINARY) + *buf++ = 'b'; + if (flags & GFILEFLG_MUSTNOTEXIST) + *buf++ = 'x'; + *buf++ = 0; +} + static bool_t NativeDel(const char *fname) { return remove(fname) ? FALSE : TRUE; } static bool_t NativeExists(const char *fname) { return access(fname, 0) ? FALSE : TRUE; } static long int NativeFilesize(const char *fname) { @@ -56,12 +73,12 @@ static long int NativeFilesize(const char *fname) { return st.st_size; } static bool_t NativeRen(const char *oldname, const char *newname) { return rename(oldname, newname) ? FALSE : TRUE }; -static bool_t NativeOpen(GFILE *f, const char *fname, const char *mode) { +static bool_t NativeOpen(GFILE *f, const char *fname) { FILE *fd; + char mode[5]; if (!(fd = fopen(fname, mode))) return FALSE; - f->vmt = &FsNativeVMT; f->obj = (void *)fd; return TRUE; } diff --git a/src/gfile/inc_romfs.c b/src/gfile/inc_romfs.c index 321dc9b1..170b9a6c 100644 --- a/src/gfile/inc_romfs.c +++ b/src/gfile/inc_romfs.c @@ -39,8 +39,8 @@ static bool_t ROMEof(GFILE *f); static const GFILEVMT FsROMVMT = { GFILE_CHAINHEAD, // next - 'S', // prefix GFSFLG_CASESENSITIVE|GFSFLG_SEEKABLE|GFSFLG_FAST, // flags + 'S', // prefix 0, ROMExists, ROMFilesize, 0, ROMOpen, ROMClose, ROMRead, 0, ROMSetpos, ROMGetsize, ROMEof, @@ -64,20 +64,10 @@ static long int ROMFilesize(const char *fname) { if (!(p = ROMFindFile(fname))) return -1; return p->size; } -static bool_t ROMOpen(GFILE *f, const char *fname, const char *mode) { +static bool_t ROMOpen(GFILE *f, const char *fname) { const ROMFS_DIRENTRY *p; - // Check mode - if (mode[0] != 'r') return FALSE; - while(*++mode) { - switch(*mode) { - case '+': case 'w': case 'a': - return FALSE; - } - } - if (!(p = ROMFindFile(fname))) return FALSE; - f->vmt = &FsROMVMT; f->obj = (void *)p; return TRUE; }