GFILE: restructure files, add File Listing, add C String files
Fix compile error for ChibiOS BaseStreamFile based GFILES'.
This commit is contained in:
parent
6ff7d90500
commit
10902154ae
@ -22,6 +22,8 @@ FEATURE: Added support for the RawOS real time operating system
|
|||||||
FEATURE: Operating System initialisation is now optional
|
FEATURE: Operating System initialisation is now optional
|
||||||
FEATURE: Added optional transparency to container
|
FEATURE: Added optional transparency to container
|
||||||
FEATURE: Prevent mouse events going to obscured widgets
|
FEATURE: Prevent mouse events going to obscured widgets
|
||||||
|
FEATURE: Add GFILE support for file lists
|
||||||
|
FEATURE: Add GFILE support for C strings as files
|
||||||
|
|
||||||
|
|
||||||
*** Release 2.1 ***
|
*** Release 2.1 ***
|
||||||
|
@ -224,10 +224,8 @@
|
|||||||
//#define GFILE_NEED_PRINTG FALSE
|
//#define GFILE_NEED_PRINTG FALSE
|
||||||
//#define GFILE_NEED_SCANG FALSE
|
//#define GFILE_NEED_SCANG FALSE
|
||||||
//#define GFILE_NEED_STRINGS FALSE
|
//#define GFILE_NEED_STRINGS FALSE
|
||||||
|
//#define GFILE_NEED_FILELISTS FALSE
|
||||||
//#define GFILE_NEED_STDIO FALSE
|
//#define GFILE_NEED_STDIO FALSE
|
||||||
// #define GFILE_ALLOW_FLOATS FALSE
|
|
||||||
// #define GFILE_ALLOW_DEVICESPECIFIC FALSE
|
|
||||||
// #define GFILE_MAX_GFILES 3
|
|
||||||
//#define GFILE_NEED_NOAUTOMOUNT FALSE
|
//#define GFILE_NEED_NOAUTOMOUNT FALSE
|
||||||
//#define GFILE_NEED_NOAUTOSYNC FALSE
|
//#define GFILE_NEED_NOAUTOSYNC FALSE
|
||||||
|
|
||||||
@ -238,6 +236,9 @@
|
|||||||
//#define GFILE_NEED_NATIVEFS FALSE
|
//#define GFILE_NEED_NATIVEFS FALSE
|
||||||
//#define GFILE_NEED_CHBIOSFS FALSE
|
//#define GFILE_NEED_CHBIOSFS FALSE
|
||||||
|
|
||||||
|
//#define GFILE_ALLOW_FLOATS FALSE
|
||||||
|
//#define GFILE_ALLOW_DEVICESPECIFIC FALSE
|
||||||
|
//#define GFILE_MAX_GFILES 3
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// GADC //
|
// GADC //
|
||||||
|
@ -35,6 +35,11 @@ struct GFILE {
|
|||||||
long int pos;
|
long int pos;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct gfileList {
|
||||||
|
const struct GFILEVMT * vmt;
|
||||||
|
bool_t dirs;
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct GFILEVMT {
|
typedef struct GFILEVMT {
|
||||||
const struct GFILEVMT * next;
|
const struct GFILEVMT * next;
|
||||||
uint8_t flags;
|
uint8_t flags;
|
||||||
@ -59,6 +64,11 @@ typedef struct GFILEVMT {
|
|||||||
bool_t (*mount) (const char *drive);
|
bool_t (*mount) (const char *drive);
|
||||||
bool_t (*unmount) (const char *drive);
|
bool_t (*unmount) (const char *drive);
|
||||||
bool_t (*sync) (GFILE *f);
|
bool_t (*sync) (GFILE *f);
|
||||||
|
#if GFILE_NEED_FILELISTS
|
||||||
|
gfileList * (*flopen) (const char *path, bool_t dirs);
|
||||||
|
const char *(*flread) (gfileList *pfl);
|
||||||
|
void (*flclose) (gfileList *pfl);
|
||||||
|
#endif
|
||||||
} GFILEVMT;
|
} GFILEVMT;
|
||||||
|
|
||||||
// The chain of FileSystems
|
// The chain of FileSystems
|
||||||
@ -70,6 +80,9 @@ GFILE *gfileStdIn;
|
|||||||
GFILE *gfileStdOut;
|
GFILE *gfileStdOut;
|
||||||
GFILE *gfileStdErr;
|
GFILE *gfileStdErr;
|
||||||
|
|
||||||
|
// Forward definition used by some special open calls
|
||||||
|
static GFILE *findemptyfile(const char *mode);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The order of the file-systems below determines the order
|
* The order of the file-systems below determines the order
|
||||||
* that they are searched to find a file.
|
* that they are searched to find a file.
|
||||||
@ -118,6 +131,34 @@ GFILE *gfileStdErr;
|
|||||||
#include "src/gfile/inc_romfs.c"
|
#include "src/gfile/inc_romfs.c"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/********************************************************
|
||||||
|
* The virtual string file VMT
|
||||||
|
********************************************************/
|
||||||
|
#if GFILE_NEED_STRINGS
|
||||||
|
#include "src/gfile/inc_strings.c"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/********************************************************
|
||||||
|
* Printg Routines
|
||||||
|
********************************************************/
|
||||||
|
#if GFILE_NEED_PRINTG
|
||||||
|
#include "src/gfile/inc_printg.c"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/********************************************************
|
||||||
|
* Scang Routines
|
||||||
|
********************************************************/
|
||||||
|
#if GFILE_NEED_SCANG
|
||||||
|
#include "src/gfile/inc_scang.c"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/********************************************************
|
||||||
|
* Stdio Emulation Routines
|
||||||
|
********************************************************/
|
||||||
|
#if GFILE_NEED_STDIO
|
||||||
|
#include "src/gfile/inc_stdio.c"
|
||||||
|
#endif
|
||||||
|
|
||||||
/********************************************************
|
/********************************************************
|
||||||
* IO routines
|
* IO routines
|
||||||
********************************************************/
|
********************************************************/
|
||||||
@ -251,39 +292,48 @@ bool_t gfileRename(const char *oldname, const char *newname) {
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint16_t mode2flags(const char *mode) {
|
static GFILE *findemptyfile(const char *mode) {
|
||||||
uint16_t flags;
|
GFILE * f;
|
||||||
|
|
||||||
switch(mode[0]) {
|
// First find an available GFILE slot.
|
||||||
case 'r':
|
for (f = gfileArr; f < &gfileArr[GFILE_MAX_GFILES]; f++) {
|
||||||
flags = GFILEFLG_READ|GFILEFLG_MUSTEXIST;
|
if (!(f->flags & GFILEFLG_OPEN)) {
|
||||||
while (*++mode) {
|
// Get the flags
|
||||||
switch(mode[0]) {
|
switch(mode[0]) {
|
||||||
case '+': flags |= GFILEFLG_WRITE; break;
|
case 'r':
|
||||||
case 'b': flags |= GFILEFLG_BINARY; break;
|
f->flags = GFILEFLG_READ|GFILEFLG_MUSTEXIST;
|
||||||
|
while (*++mode) {
|
||||||
|
switch(mode[0]) {
|
||||||
|
case '+': f->flags |= GFILEFLG_WRITE; break;
|
||||||
|
case 'b': f->flags |= GFILEFLG_BINARY; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'w':
|
||||||
|
f->flags = GFILEFLG_WRITE|GFILEFLG_TRUNC;
|
||||||
|
while (*++mode) {
|
||||||
|
switch(mode[0]) {
|
||||||
|
case '+': f->flags |= GFILEFLG_READ; break;
|
||||||
|
case 'b': f->flags |= GFILEFLG_BINARY; break;
|
||||||
|
case 'x': f->flags |= GFILEFLG_MUSTNOTEXIST; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'a':
|
||||||
|
f->flags = GFILEFLG_WRITE|GFILEFLG_APPEND;
|
||||||
|
while (*++mode) {
|
||||||
|
switch(mode[0]) {
|
||||||
|
case '+': f->flags |= GFILEFLG_READ; break;
|
||||||
|
case 'b': f->flags |= GFILEFLG_BINARY; break;
|
||||||
|
case 'x': f->flags |= GFILEFLG_MUSTNOTEXIST; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
return f;
|
||||||
}
|
}
|
||||||
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;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -307,112 +357,34 @@ static bool_t testopen(const GFILEVMT *p, GFILE *f, const char *fname) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
GFILE *gfileOpen(const char *fname, const char *mode) {
|
GFILE *gfileOpen(const char *fname, const char *mode) {
|
||||||
uint16_t flags;
|
|
||||||
GFILE * f;
|
GFILE * f;
|
||||||
const GFILEVMT *p;
|
const GFILEVMT *p;
|
||||||
|
|
||||||
// Get the requested mode
|
// Get an empty file and set the flags
|
||||||
if (!(flags = mode2flags(mode)))
|
if (!(f = findemptyfile(mode)))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
#if GFILE_ALLOW_DEVICESPECIFIC
|
#if GFILE_ALLOW_DEVICESPECIFIC
|
||||||
if (fname[0] && fname[1] == '|') {
|
if (fname[0] && fname[1] == '|') {
|
||||||
// First find an available GFILE slot.
|
for(p = FsChain; p; p = p->next) {
|
||||||
for (f = gfileArr; f < &gfileArr[GFILE_MAX_GFILES]; f++) {
|
if (p->prefix == fname[0])
|
||||||
if (!(f->flags & GFILEFLG_OPEN)) {
|
return testopen(p, f, fname+2) ? f : 0;
|
||||||
// Try to open the file
|
|
||||||
f->flags = flags;
|
|
||||||
for(p = FsChain; p; p = p->next) {
|
|
||||||
if (p->prefix == fname[0])
|
|
||||||
return testopen(p, f, fname+2) ? f : 0;
|
|
||||||
}
|
|
||||||
// File not found
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// No available slot
|
// File not found
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// First find an available GFILE slot.
|
for(p = FsChain; p; p = p->next) {
|
||||||
for (f = gfileArr; f < &gfileArr[GFILE_MAX_GFILES]; f++) {
|
if (testopen(p, f, fname))
|
||||||
if (!(f->flags & GFILEFLG_OPEN)) {
|
return f;
|
||||||
|
|
||||||
// Try to open the file
|
|
||||||
f->flags = flags;
|
|
||||||
for(p = FsChain; p; p = p->next) {
|
|
||||||
if (testopen(p, f, fname))
|
|
||||||
return f;
|
|
||||||
}
|
|
||||||
// File not found
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// No available slot
|
// File not found
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if GFILE_NEED_CHIBIOSFS && GFX_USE_OS_CHIBIOS
|
|
||||||
GFILE * gfileOpenBaseFileStream(void *BaseFileStreamPtr, const char *mode) {
|
|
||||||
GFILE * f;
|
|
||||||
|
|
||||||
// First find an available GFILE slot.
|
|
||||||
for (f = gfileArr; f < &gfileArr[GFILE_MAX_GFILES]; f++) {
|
|
||||||
if (!(f->flags & GFILEFLG_OPEN)) {
|
|
||||||
// Get the flags
|
|
||||||
if (!(f->flags = mode2flags(mode)))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
// If we want write but the fs doesn't allow it then return
|
|
||||||
if ((f->flags & GFILEFLG_WRITE) && !(FsCHIBIOSVMT.flags & GFSFLG_WRITEABLE))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
// File is open - fill in all the details
|
|
||||||
f->vmt = &FsCHIBIOSVMT;
|
|
||||||
f->obj = BaseFileStreamPtr;
|
|
||||||
f->pos = 0;
|
|
||||||
f->flags |= GFILEFLG_OPEN|GFILEFLG_CANSEEK;
|
|
||||||
return f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// No available slot
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if GFILE_NEED_MEMFS
|
|
||||||
GFILE * gfileOpenMemory(void *memptr, const char *mode) {
|
|
||||||
GFILE * f;
|
|
||||||
|
|
||||||
// First find an available GFILE slot.
|
|
||||||
for (f = gfileArr; f < &gfileArr[GFILE_MAX_GFILES]; f++) {
|
|
||||||
if (!(f->flags & GFILEFLG_OPEN)) {
|
|
||||||
// Get the flags
|
|
||||||
if (!(f->flags = mode2flags(mode)))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
// If we want write but the fs doesn't allow it then return
|
|
||||||
if ((f->flags & GFILEFLG_WRITE) && !(FsMemVMT.flags & GFSFLG_WRITEABLE))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
// File is open - fill in all the details
|
|
||||||
f->vmt = &FsMemVMT;
|
|
||||||
f->obj = memptr;
|
|
||||||
f->pos = 0;
|
|
||||||
f->flags |= GFILEFLG_OPEN|GFILEFLG_CANSEEK;
|
|
||||||
return f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// No available slot
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void gfileClose(GFILE *f) {
|
void gfileClose(GFILE *f) {
|
||||||
if (!f || !(f->flags & GFILEFLG_OPEN))
|
if (!f || !(f->flags & GFILEFLG_OPEN))
|
||||||
return;
|
return;
|
||||||
@ -512,579 +484,35 @@ bool_t gfileSync(GFILE *f) {
|
|||||||
return f->vmt->sync(f);
|
return f->vmt->sync(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
/********************************************************
|
#if GFILE_NEED_FILELISTS
|
||||||
* String VMT routines
|
gfileList *gfileOpenFileList(char fs, const char *path, bool_t dirs) {
|
||||||
********************************************************/
|
const GFILEVMT *p;
|
||||||
#if GFILE_NEED_STRINGS && (GFILE_NEED_PRINTG || GFILE_NEED_SCANG)
|
gfileList * pfl;
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
// Special String VMT
|
// Find the correct VMT
|
||||||
static int StringRead(GFILE *f, void *buf, int size) {
|
for(p = FsChain; p; p = p->next) {
|
||||||
(void) size;
|
if (p->prefix == fs) {
|
||||||
|
if (!p->flopen)
|
||||||
// size must be 1 for a complete read
|
|
||||||
if (!((char *)f->obj)[f->pos])
|
|
||||||
return 0;
|
|
||||||
((char *)buf)[0] = ((char *)f->obj)[f->pos];
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
static int StringWrite(GFILE *f, const void *buf, int size) {
|
|
||||||
(void) size;
|
|
||||||
|
|
||||||
// size must be 1 for a complete write
|
|
||||||
((char *)f->obj)[f->pos] = ((char *)buf)[0];
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
static const GFILEVMT StringVMT = {
|
|
||||||
0, // next
|
|
||||||
0, // flags
|
|
||||||
'_', // prefix
|
|
||||||
0, 0, 0, 0,
|
|
||||||
0, 0, StringRead, StringWrite,
|
|
||||||
0, 0, 0,
|
|
||||||
0, 0, 0
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/********************************************************
|
|
||||||
* printg routines
|
|
||||||
********************************************************/
|
|
||||||
#if GFILE_NEED_PRINTG
|
|
||||||
#include <stdarg.h>
|
|
||||||
|
|
||||||
#define MAX_FILLER 11
|
|
||||||
#define FLOAT_PRECISION 100000
|
|
||||||
|
|
||||||
int fnprintg(GFILE *f, int maxlen, const char *fmt, ...) {
|
|
||||||
int res;
|
|
||||||
va_list ap;
|
|
||||||
|
|
||||||
va_start(ap, fmt);
|
|
||||||
res = vfnprintg(f, maxlen, fmt, ap);
|
|
||||||
va_end(ap);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
static char *ltoa_wd(char *p, long num, unsigned radix, long divisor) {
|
|
||||||
int i;
|
|
||||||
char * q;
|
|
||||||
|
|
||||||
if (!divisor) divisor = num;
|
|
||||||
|
|
||||||
q = p + MAX_FILLER;
|
|
||||||
do {
|
|
||||||
i = (int)(num % radix);
|
|
||||||
i += '0';
|
|
||||||
if (i > '9')
|
|
||||||
i += 'A' - '0' - 10;
|
|
||||||
*--q = i;
|
|
||||||
num /= radix;
|
|
||||||
} while ((divisor /= radix) != 0);
|
|
||||||
|
|
||||||
i = (int)(p + MAX_FILLER - q);
|
|
||||||
do {
|
|
||||||
*p++ = *q++;
|
|
||||||
} while (--i);
|
|
||||||
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
int vfnprintg(GFILE *f, int maxlen, const char *fmt, va_list arg) {
|
|
||||||
int ret;
|
|
||||||
char *p, *s, c, filler;
|
|
||||||
int i, precision, width;
|
|
||||||
bool_t is_long, left_align;
|
|
||||||
long l;
|
|
||||||
#if GFILE_ALLOW_FLOATS
|
|
||||||
float f;
|
|
||||||
char tmpbuf[2*MAX_FILLER + 1];
|
|
||||||
#else
|
|
||||||
char tmpbuf[MAX_FILLER + 1];
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ret = 0;
|
|
||||||
if (maxlen < 0)
|
|
||||||
return 0;
|
|
||||||
if (!maxlen)
|
|
||||||
maxlen = -1;
|
|
||||||
|
|
||||||
while (*fmt) {
|
|
||||||
if (*fmt != '%') {
|
|
||||||
gfileWrite(f, fmt, 1);
|
|
||||||
ret++; if (!--maxlen) return ret;
|
|
||||||
fmt++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
fmt++;
|
|
||||||
|
|
||||||
p = s = tmpbuf;
|
|
||||||
left_align = FALSE;
|
|
||||||
filler = ' ';
|
|
||||||
width = 0;
|
|
||||||
precision = 0;
|
|
||||||
|
|
||||||
if (*fmt == '-') {
|
|
||||||
fmt++;
|
|
||||||
left_align = TRUE;
|
|
||||||
}
|
|
||||||
if (*fmt == '.') {
|
|
||||||
fmt++;
|
|
||||||
filler = '0';
|
|
||||||
}
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
c = *fmt++;
|
|
||||||
if (c >= '0' && c <= '9') {
|
|
||||||
c -= '0';
|
|
||||||
width = width * 10 + c;
|
|
||||||
} else if (c == '*')
|
|
||||||
width = va_arg(arg, int);
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (c == '.') {
|
|
||||||
while (1) {
|
|
||||||
c = *fmt++;
|
|
||||||
if (c >= '0' && c <= '9') {
|
|
||||||
c -= '0';
|
|
||||||
precision = precision * 10 + c;
|
|
||||||
} else if (c == '*')
|
|
||||||
precision = va_arg(arg, int);
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* Long modifier.*/
|
|
||||||
if (c == 'l' || c == 'L') {
|
|
||||||
is_long = TRUE;
|
|
||||||
if (*fmt)
|
|
||||||
c = *fmt++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
is_long = (c >= 'A') && (c <= 'Z');
|
|
||||||
|
|
||||||
/* Command decoding.*/
|
|
||||||
switch (c) {
|
|
||||||
case 0:
|
|
||||||
return ret;
|
|
||||||
case 'c':
|
|
||||||
filler = ' ';
|
|
||||||
*p++ = va_arg(arg, int);
|
|
||||||
break;
|
|
||||||
case 's':
|
|
||||||
filler = ' ';
|
|
||||||
if ((s = va_arg(arg, char *)) == 0)
|
|
||||||
s = "(null)";
|
|
||||||
if (precision == 0)
|
|
||||||
precision = 32767;
|
|
||||||
for (p = s; *p && (--precision >= 0); p++);
|
|
||||||
break;
|
|
||||||
case 'D':
|
|
||||||
case 'd':
|
|
||||||
if (is_long)
|
|
||||||
l = va_arg(arg, long);
|
|
||||||
else
|
|
||||||
l = va_arg(arg, int);
|
|
||||||
if (l < 0) {
|
|
||||||
*p++ = '-';
|
|
||||||
l = -l;
|
|
||||||
}
|
|
||||||
p = ltoa_wd(p, l, 10, 0);
|
|
||||||
break;
|
|
||||||
#if GFILE_ALLOW_FLOATS
|
|
||||||
case 'f':
|
|
||||||
f = (float) va_arg(arg, double);
|
|
||||||
if (f < 0) {
|
|
||||||
*p++ = '-';
|
|
||||||
f = -f;
|
|
||||||
}
|
|
||||||
l = f;
|
|
||||||
p = ltoa_wd(p, l, 10, 0);
|
|
||||||
*p++ = '.';
|
|
||||||
l = (f - l) * FLOAT_PRECISION;
|
|
||||||
p = ltoa_wd(p, l, 10, FLOAT_PRECISION / 10);
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
case 'X':
|
|
||||||
case 'x':
|
|
||||||
c = 16;
|
|
||||||
goto unsigned_common;
|
|
||||||
case 'U':
|
|
||||||
case 'u':
|
|
||||||
c = 10;
|
|
||||||
goto unsigned_common;
|
|
||||||
case 'O':
|
|
||||||
case 'o':
|
|
||||||
c = 8;
|
|
||||||
unsigned_common:
|
|
||||||
if (is_long)
|
|
||||||
l = va_arg(arg, long);
|
|
||||||
else
|
|
||||||
l = va_arg(arg, int);
|
|
||||||
p = ltoa_wd(p, l, c, 0);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
*p++ = c;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
i = (int)(p - s);
|
|
||||||
if ((width -= i) < 0)
|
|
||||||
width = 0;
|
|
||||||
if (left_align == FALSE)
|
|
||||||
width = -width;
|
|
||||||
if (width < 0) {
|
|
||||||
if (*s == '-' && filler == '0') {
|
|
||||||
gfileWrite(f, s++, 1);
|
|
||||||
ret++; if (!--maxlen) return ret;
|
|
||||||
i--;
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
gfileWrite(f, &filler, 1);
|
|
||||||
ret++; if (!--maxlen) return ret;
|
|
||||||
} while (++width != 0);
|
|
||||||
}
|
|
||||||
while (--i >= 0) {
|
|
||||||
gfileWrite(f, s++, 1);
|
|
||||||
ret++; if (!--maxlen) return ret;
|
|
||||||
}
|
|
||||||
while (width) {
|
|
||||||
gfileWrite(f, &filler, 1);
|
|
||||||
ret++; if (!--maxlen) return ret;
|
|
||||||
width--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if GFILE_NEED_STRINGS
|
|
||||||
int snprintg(char *buf, int maxlen, const char *fmt, ...) {
|
|
||||||
int res;
|
|
||||||
GFILE f;
|
|
||||||
va_list ap;
|
|
||||||
|
|
||||||
if (maxlen <= 1) {
|
|
||||||
if (maxlen == 1) {
|
|
||||||
*buf = 0;
|
|
||||||
return 0;
|
return 0;
|
||||||
|
pfl = p->flopen(path, dirs);
|
||||||
|
if (pfl) {
|
||||||
|
pfl->vmt = p;
|
||||||
|
pfl->dirs = dirs;
|
||||||
}
|
}
|
||||||
maxlen += 1;
|
return pfl;
|
||||||
}
|
|
||||||
f.flags = GFILEFLG_OPEN|GFILEFLG_WRITE;
|
|
||||||
f.vmt = &StringVMT;
|
|
||||||
f.pos = 0;
|
|
||||||
f.obj = buf;
|
|
||||||
va_start(ap, fmt);
|
|
||||||
res = vfnprintg(&f, maxlen-1, fmt, ap);
|
|
||||||
va_end(ap);
|
|
||||||
buf[res] = 0;
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
int vsnprintg(char *buf, int maxlen, const char *fmt, va_list arg) {
|
|
||||||
int res;
|
|
||||||
GFILE f;
|
|
||||||
|
|
||||||
if (maxlen <= 1) {
|
|
||||||
if (maxlen == 1) {
|
|
||||||
*buf = 0;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
maxlen += 1;
|
|
||||||
}
|
|
||||||
f.flags = GFILEFLG_OPEN|GFILEFLG_WRITE;
|
|
||||||
f.vmt = &StringVMT;
|
|
||||||
f.pos = 0;
|
|
||||||
f.obj = buf;
|
|
||||||
res = vfnprintg(&f, maxlen-1, fmt, arg);
|
|
||||||
buf[res] = 0;
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/********************************************************
|
|
||||||
* scang routines
|
|
||||||
********************************************************/
|
|
||||||
#if GFILE_NEED_SCANG
|
|
||||||
int fscang(GFILE *f, const char *fmt, ...) {
|
|
||||||
int res;
|
|
||||||
va_list ap;
|
|
||||||
|
|
||||||
va_start(ap, fmt);
|
|
||||||
res = vfscang(f, fmt, ap);
|
|
||||||
va_end(ap);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
int vfscang(GFILE *f, const char *fmt, va_list arg) {
|
|
||||||
int res, width, size, base;
|
|
||||||
unsigned long num;
|
|
||||||
char c;
|
|
||||||
bool_t assign, negate;
|
|
||||||
char *p;
|
|
||||||
|
|
||||||
for(res = 0; *fmt; fmt++) {
|
|
||||||
switch(*fmt) {
|
|
||||||
case ' ': case '\t': case '\r': case '\n': case '\v': case '\f':
|
|
||||||
break;
|
|
||||||
|
|
||||||
case '%':
|
|
||||||
fmt++;
|
|
||||||
assign = TRUE;
|
|
||||||
negate = FALSE;
|
|
||||||
width = 0;
|
|
||||||
size = 1;
|
|
||||||
num = 0;
|
|
||||||
|
|
||||||
if (*fmt == '*') {
|
|
||||||
fmt++;
|
|
||||||
assign = FALSE;
|
|
||||||
}
|
|
||||||
while(*fmt >= '0' && *fmt <= '9')
|
|
||||||
width = width * 10 + (*fmt++ - '0');
|
|
||||||
if (*fmt == 'h') {
|
|
||||||
fmt++;
|
|
||||||
size = 0;
|
|
||||||
} else if (*fmt == 'l') {
|
|
||||||
fmt++;
|
|
||||||
size = 2;
|
|
||||||
} else if (*fmt == 'L') {
|
|
||||||
fmt++;
|
|
||||||
size = 3;
|
|
||||||
}
|
|
||||||
switch(*fmt) {
|
|
||||||
case 0:
|
|
||||||
return res;
|
|
||||||
case '%':
|
|
||||||
goto matchchar;
|
|
||||||
case 'c':
|
|
||||||
if (!width) {
|
|
||||||
while(1) {
|
|
||||||
if (!gfileRead(f, &c, 1)) return res;
|
|
||||||
switch(c) {
|
|
||||||
case ' ': case '\t': case '\r':
|
|
||||||
case '\n': case '\v': case '\f': continue;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
width = 1;
|
|
||||||
} else {
|
|
||||||
if (!gfileRead(f, &c, 1)) return res;
|
|
||||||
}
|
|
||||||
if (assign) {
|
|
||||||
p = va_arg(arg, char *);
|
|
||||||
res++;
|
|
||||||
*p++ = c;
|
|
||||||
}
|
|
||||||
while(--width) {
|
|
||||||
if (!gfileRead(f, &c, 1)) return res;
|
|
||||||
if (assign) *p++ = c;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 's':
|
|
||||||
while(1) {
|
|
||||||
if (!gfileRead(f, &c, 1)) return res;
|
|
||||||
switch(c) {
|
|
||||||
case ' ': case '\t': case '\r':
|
|
||||||
case '\n': case '\v': case '\f': continue;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (assign) {
|
|
||||||
p = va_arg(arg, char *);
|
|
||||||
res++;
|
|
||||||
*p++ = c;
|
|
||||||
}
|
|
||||||
if (width) {
|
|
||||||
while(--width) {
|
|
||||||
if (!gfileRead(f, &c, 1)) {
|
|
||||||
if (assign) *((char *)p) = 0;
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
if (assign) *p++ = c;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
while(1) {
|
|
||||||
if (!gfileRead(f, &c, 1)) {
|
|
||||||
if (assign) *((char *)p) = 0;
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
switch(c) {
|
|
||||||
case ' ': case '\t': case '\r':
|
|
||||||
case '\n': case '\v': case '\f': break;
|
|
||||||
default:
|
|
||||||
if (assign) *p++ = c;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
//ungetch(c);
|
|
||||||
}
|
|
||||||
if (assign) *p = 0;
|
|
||||||
break;
|
|
||||||
case 'd': base = 10; goto getnum;
|
|
||||||
case 'i': base = -1; goto getnum;
|
|
||||||
case 'o': base = 8; goto getnum;
|
|
||||||
case 'u': base = 10; goto getnum;
|
|
||||||
case 'x': base = 16; goto getnum;
|
|
||||||
case 'b': base = 2;
|
|
||||||
getnum:
|
|
||||||
while(1) {
|
|
||||||
if (!gfileRead(f, &c, 1)) return res;
|
|
||||||
switch(c) {
|
|
||||||
case ' ': case '\t': case '\r':
|
|
||||||
case '\n': case '\v': case '\f': continue;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (c == '-' && *fmt != 'u') {
|
|
||||||
negate = TRUE;
|
|
||||||
if ((width && !--width) || !gfileRead(f, &c, 1)) return res;
|
|
||||||
}
|
|
||||||
if (base == -1) {
|
|
||||||
if (c == '0') {
|
|
||||||
if ((width && !--width) || !gfileRead(f, &c, 1)) goto assignnum;
|
|
||||||
switch(c) {
|
|
||||||
case 'x': case 'X':
|
|
||||||
base = 16;
|
|
||||||
if ((width && !--width) || !gfileRead(f, &c, 1)) return res;
|
|
||||||
break;
|
|
||||||
case 'b': case 'B':
|
|
||||||
base = 2;
|
|
||||||
if ((width && !--width) || !gfileRead(f, &c, 1)) return res;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
base = 8;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
base = 10;
|
|
||||||
}
|
|
||||||
while(1) {
|
|
||||||
if (c >= '0' && c <= '9' && c - '0' < base)
|
|
||||||
num = num * base + (c - '0');
|
|
||||||
else if (c >= 'A' && c <= 'F' && base == 16)
|
|
||||||
num = num * base + (c - ('A'-10));
|
|
||||||
else if (c >= 'a' && c <= 'f' && base == 16)
|
|
||||||
num = num * base + (c - ('a'-10));
|
|
||||||
else {
|
|
||||||
// ungetch(c)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if ((width && !--width) || !gfileRead(f, &c, 1))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
assignnum:
|
|
||||||
if (negate)
|
|
||||||
num = -num;
|
|
||||||
|
|
||||||
if (assign) {
|
|
||||||
switch(size) {
|
|
||||||
case 0: // short
|
|
||||||
p = (char *)va_arg(arg, short *);
|
|
||||||
res++;
|
|
||||||
*((short *)p) = (short)num;
|
|
||||||
case 1: // int
|
|
||||||
p = (char *)va_arg(arg, int *);
|
|
||||||
res++;
|
|
||||||
*((int *)p) = (int)num;
|
|
||||||
case 2: case 3: // long
|
|
||||||
p = (char *)va_arg(arg, long *);
|
|
||||||
res++;
|
|
||||||
*((long *)p) = (long)num;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
#if GFILE_ALLOW_FLOATS
|
|
||||||
case 'e': case 'f': case 'g':
|
|
||||||
// TODO
|
|
||||||
#endif
|
|
||||||
default:
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
matchchar:
|
|
||||||
while(1) {
|
|
||||||
if (!gfileRead(f, &c, 1)) return res;
|
|
||||||
switch(c) {
|
|
||||||
case ' ': case '\t': case '\r':
|
|
||||||
case '\n': case '\v': case '\f': continue;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (c != *fmt) return res;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if GFILE_NEED_STRINGS
|
|
||||||
int sscang(const char *buf, const char *fmt, ...) {
|
|
||||||
int res;
|
|
||||||
GFILE f;
|
|
||||||
va_list ap;
|
|
||||||
|
|
||||||
f.flags = GFILEFLG_OPEN|GFILEFLG_READ;
|
|
||||||
f.vmt = &StringVMT;
|
|
||||||
f.pos = 0;
|
|
||||||
f.obj = (void *)buf;
|
|
||||||
va_start(ap, fmt);
|
|
||||||
res = vfscang(&f, fmt, ap);
|
|
||||||
va_end(ap);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
int vsscang(const char *buf, const char *fmt, va_list arg) {
|
|
||||||
int res;
|
|
||||||
GFILE f;
|
|
||||||
|
|
||||||
f.flags = GFILEFLG_OPEN|GFILEFLG_READ;
|
|
||||||
f.vmt = &StringVMT;
|
|
||||||
f.pos = 0;
|
|
||||||
f.obj = (void *)buf;
|
|
||||||
res = vfscang(&f, fmt, arg);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/********************************************************
|
|
||||||
* stdio emulation routines
|
|
||||||
********************************************************/
|
|
||||||
#if GFILE_NEED_STDIO
|
|
||||||
size_t gstdioRead(void * ptr, size_t size, size_t count, FILE *f) {
|
|
||||||
return gfileRead(f, ptr, size*count)/size;
|
|
||||||
}
|
|
||||||
size_t gstdioWrite(const void * ptr, size_t size, size_t count, FILE *f) {
|
|
||||||
return gfileWrite(f, ptr, size*count)/size;
|
|
||||||
}
|
|
||||||
int gstdioSeek(FILE *f, size_t offset, int origin) {
|
|
||||||
switch(origin) {
|
|
||||||
case SEEK_SET:
|
|
||||||
break;
|
|
||||||
case SEEK_CUR:
|
|
||||||
offset += f->pos;
|
|
||||||
break;
|
|
||||||
case SEEK_END:
|
|
||||||
offset += gfileGetSize(f);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return gfileSetPos(f, offset) ? 0 : -1;
|
|
||||||
}
|
|
||||||
int gstdioGetpos(FILE *f, long int *pos) {
|
|
||||||
if (!(f->flags & GFILEFLG_OPEN))
|
|
||||||
return -1;
|
|
||||||
*pos = f->pos;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *gfileReadFileList(gfileList *pfl) {
|
||||||
|
return pfl->vmt->flread ? pfl->vmt->flread(pfl) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void gfileCloseFileList(gfileList *pfl) {
|
||||||
|
if (pfl->vmt->flclose)
|
||||||
|
pfl->vmt->flclose(pfl);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* GFX_USE_GFILE */
|
#endif /* GFX_USE_GFILE */
|
||||||
|
@ -27,22 +27,39 @@ static const GFILEVMT FsCHIBIOSVMT = {
|
|||||||
0, 0, 0, 0,
|
0, 0, 0, 0,
|
||||||
0, ChibiOSBFSClose, ChibiOSBFSRead, ChibiOSBFSWrite,
|
0, ChibiOSBFSClose, ChibiOSBFSRead, ChibiOSBFSWrite,
|
||||||
ChibiOSBFSSetpos, ChibiOSBFSGetsize, ChibiOSBFSEof,
|
ChibiOSBFSSetpos, ChibiOSBFSGetsize, ChibiOSBFSEof,
|
||||||
0, 0,
|
0, 0, 0,
|
||||||
0
|
#if GFILE_NEED_FILELISTS
|
||||||
|
0, 0, 0,
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
static void ChibiOSBFSClose(GFILE *f) {
|
static void ChibiOSBFSClose(GFILE *f) {
|
||||||
chFileStreamClose(((BaseFileStream *)f->fd));
|
chFileStreamClose(((BaseFileStream *)f->obj));
|
||||||
}
|
}
|
||||||
static int ChibiOSBFSRead(GFILE *f, void *buf, int size) {
|
static int ChibiOSBFSRead(GFILE *f, void *buf, int size) {
|
||||||
return chSequentialStreamRead(((BaseFileStream *)f->fd), (uint8_t *)buf, size);
|
return chSequentialStreamRead(((BaseFileStream *)f->obj), (uint8_t *)buf, size);
|
||||||
}
|
}
|
||||||
static int ChibiOSBFSWrite(GFILE *f, const void *buf, int size) {
|
static int ChibiOSBFSWrite(GFILE *f, const void *buf, int size) {
|
||||||
return chSequentialStreamWrite(((BaseFileStream *)f->fd), (uint8_t *)buf, size);
|
return chSequentialStreamWrite(((BaseFileStream *)f->obj), (uint8_t *)buf, size);
|
||||||
}
|
}
|
||||||
static bool_t ChibiOSBFSSetpos(GFILE *f, long int pos) {
|
static bool_t ChibiOSBFSSetpos(GFILE *f, long int pos) {
|
||||||
chFileStreamSeek(((BaseFileStream *)f->fd), pos);
|
chFileStreamSeek(((BaseFileStream *)f->obj), pos);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
static long int ChibiOSBFSGetsize(GFILE *f) { return chFileStreamGetSize(((BaseFileStream *)f->fd)); }
|
static long int ChibiOSBFSGetsize(GFILE *f) { return chFileStreamGetSize(((BaseFileStream *)f->obj)); }
|
||||||
static bool_t ChibiOSBFSEof(GFILE *f) { return f->pos >= chFileStreamGetSize(((BaseFileStream *)f->fd)); }
|
static bool_t ChibiOSBFSEof(GFILE *f) { return f->pos >= chFileStreamGetSize(((BaseFileStream *)f->obj)); }
|
||||||
|
|
||||||
|
GFILE * gfileOpenBaseFileStream(void *BaseFileStreamPtr, const char *mode) {
|
||||||
|
GFILE * f;
|
||||||
|
|
||||||
|
// Get an empty file and set the flags
|
||||||
|
if (!(f = findemptyfile(mode)))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// File is open - fill in all the details
|
||||||
|
f->vmt = &FsCHIBIOSVMT;
|
||||||
|
f->obj = BaseFileStreamPtr;
|
||||||
|
f->pos = 0;
|
||||||
|
f->flags |= GFILEFLG_OPEN|GFILEFLG_CANSEEK;
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
@ -30,6 +30,11 @@ static bool_t fatfsEOF(GFILE* f);
|
|||||||
static bool_t fatfsMount(const char* drive);
|
static bool_t fatfsMount(const char* drive);
|
||||||
static bool_t fatfsUnmount(const char* drive);
|
static bool_t fatfsUnmount(const char* drive);
|
||||||
static bool_t fatfsSync(GFILE* f);
|
static bool_t fatfsSync(GFILE* f);
|
||||||
|
#if _FS_MINIMIZE <= 1 && GFILE_NEED_FILELISTS
|
||||||
|
static gfileList *fatfsFlOpen(const char *path, bool_t dirs);
|
||||||
|
static const char *fatfsFlRead(gfileList *pfl);
|
||||||
|
static void fatfsFlClose(gfileList *pfl);
|
||||||
|
#endif
|
||||||
|
|
||||||
static const GFILEVMT FsFatFSVMT = {
|
static const GFILEVMT FsFatFSVMT = {
|
||||||
GFILE_CHAINHEAD,
|
GFILE_CHAINHEAD,
|
||||||
@ -46,14 +51,29 @@ static const GFILEVMT FsFatFSVMT = {
|
|||||||
fatfsSetPos,
|
fatfsSetPos,
|
||||||
fatfsGetSize,
|
fatfsGetSize,
|
||||||
fatfsEOF,
|
fatfsEOF,
|
||||||
fatfsMount,
|
fatfsMount, fatfsUnmount, fatfsSync,
|
||||||
fatfsUnmount,
|
#if GFILE_NEED_FILELISTS
|
||||||
fatfsSync
|
#if _FS_MINIMIZE <= 1
|
||||||
|
fatfsFlOpen, fatfsFlRead, fatfsFlClose
|
||||||
|
#else
|
||||||
|
0, 0, 0
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
#undef GFILE_CHAINHEAD
|
#undef GFILE_CHAINHEAD
|
||||||
#define GFILE_CHAINHEAD &FsFatFSVMT
|
#define GFILE_CHAINHEAD &FsFatFSVMT
|
||||||
|
|
||||||
|
// Our directory list structure
|
||||||
|
typedef struct fatfsList {
|
||||||
|
gfileList fl; // This must be the first element.
|
||||||
|
DIR dir;
|
||||||
|
FILINFO fno;
|
||||||
|
#if _USE_LFN
|
||||||
|
char lfn[_MAX_LFN + 1]; /* Buffer to store the LFN */
|
||||||
|
#endif
|
||||||
|
} fatfsList;
|
||||||
|
|
||||||
// optimize these later on. Use an array to have multiple FatFS
|
// optimize these later on. Use an array to have multiple FatFS
|
||||||
static bool_t fatfs_mounted = FALSE;
|
static bool_t fatfs_mounted = FALSE;
|
||||||
static FATFS fatfs_fs;
|
static FATFS fatfs_fs;
|
||||||
@ -245,3 +265,58 @@ static bool_t fatfsSync(GFILE *f)
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if _FS_MINIMIZE <= 1 && GFILE_NEED_FILELISTS
|
||||||
|
static gfileList *fatfsFlOpen(const char *path, bool_t dirs) {
|
||||||
|
fatfsList *p;
|
||||||
|
(void) dirs;
|
||||||
|
|
||||||
|
if (!(p = gfxAlloc(sizeof(fatfsList))))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (f_opendir(&p->dir, path) != FR_OK) {
|
||||||
|
gfxFree(p);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return &p->fl;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *fatfsFlRead(gfileList *pfl) {
|
||||||
|
#define ffl ((fatfsList *)pfl)
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
#if _USE_LFN
|
||||||
|
ffl->fno.lfname = ffl->lfn;
|
||||||
|
ffl->fno.lfsize = sizeof(ffl->lfn);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Read the next entry
|
||||||
|
if (f_readdir(&ffl->dir, &ffl->fno) != FR_OK || !ffl->fno.fname[0])
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Ignore dot entries */
|
||||||
|
if (ffl->fno.fname[0] == '.') continue;
|
||||||
|
|
||||||
|
/* Is it a directory */
|
||||||
|
if (ffl->fl.dirs) {
|
||||||
|
if ((ffl->fno.fattrib & AM_DIR))
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
if (!(ffl->fno.fattrib & AM_DIR))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if _USE_LFN
|
||||||
|
return ffl->fno.lfname[0] ? ffl->fno.lfname : ffl->fno.fname;
|
||||||
|
#else
|
||||||
|
return ffl->fno.fname;
|
||||||
|
#endif
|
||||||
|
#undef ffl
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fatfsFlClose(gfileList *pfl) {
|
||||||
|
f_closedir(&((fatfsList *)pfl)->dir);
|
||||||
|
gfxFree(pfl);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
@ -26,8 +26,10 @@ static const GFILEVMT FsMemVMT = {
|
|||||||
0, 0, 0, 0,
|
0, 0, 0, 0,
|
||||||
0, 0, MEMRead, MEMWrite,
|
0, 0, MEMRead, MEMWrite,
|
||||||
MEMSetpos, 0, 0,
|
MEMSetpos, 0, 0,
|
||||||
0, 0,
|
0, 0, 0,
|
||||||
0
|
#if GFILE_NEED_FILELISTS
|
||||||
|
0, 0, 0,
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
static int MEMRead(GFILE *f, void *buf, int size) {
|
static int MEMRead(GFILE *f, void *buf, int size) {
|
||||||
@ -43,3 +45,18 @@ static bool_t MEMSetpos(GFILE *f, long int pos) {
|
|||||||
(void) pos;
|
(void) pos;
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GFILE * gfileOpenMemory(void *memptr, const char *mode) {
|
||||||
|
GFILE *f;
|
||||||
|
|
||||||
|
// Get an empty file and set the flags
|
||||||
|
if (!(f = findemptyfile(mode)))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// File is open - fill in all the details
|
||||||
|
f->vmt = &FsMemVMT;
|
||||||
|
f->obj = memptr;
|
||||||
|
f->pos = 0;
|
||||||
|
f->flags |= GFILEFLG_OPEN|GFILEFLG_CANSEEK;
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
@ -33,6 +33,11 @@ static int NativeWrite(GFILE *f, const void *buf, int size);
|
|||||||
static bool_t NativeSetpos(GFILE *f, long int pos);
|
static bool_t NativeSetpos(GFILE *f, long int pos);
|
||||||
static long int NativeGetsize(GFILE *f);
|
static long int NativeGetsize(GFILE *f);
|
||||||
static bool_t NativeEof(GFILE *f);
|
static bool_t NativeEof(GFILE *f);
|
||||||
|
#if GFILE_NEED_FILELISTS
|
||||||
|
static gfileList *NativeFlOpen(const char *path, bool_t dirs);
|
||||||
|
static const char *NativeFlRead(gfileList *pfl);
|
||||||
|
static void NativeFlClose(gfileList *pfl);
|
||||||
|
#endif
|
||||||
|
|
||||||
static const GFILEVMT FsNativeVMT = {
|
static const GFILEVMT FsNativeVMT = {
|
||||||
GFILE_CHAINHEAD, // next
|
GFILE_CHAINHEAD, // next
|
||||||
@ -46,8 +51,10 @@ static const GFILEVMT FsNativeVMT = {
|
|||||||
NativeDel, NativeExists, NativeFilesize, NativeRen,
|
NativeDel, NativeExists, NativeFilesize, NativeRen,
|
||||||
NativeOpen, NativeClose, NativeRead, NativeWrite,
|
NativeOpen, NativeClose, NativeRead, NativeWrite,
|
||||||
NativeSetpos, NativeGetsize, NativeEof,
|
NativeSetpos, NativeGetsize, NativeEof,
|
||||||
0, 0,
|
0, 0, 0,
|
||||||
0
|
#if GFILE_NEED_FILELISTS
|
||||||
|
NativeFlOpen, NativeFlRead, NativeFlClose
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
#undef GFILE_CHAINHEAD
|
#undef GFILE_CHAINHEAD
|
||||||
#define GFILE_CHAINHEAD &FsNativeVMT
|
#define GFILE_CHAINHEAD &FsNativeVMT
|
||||||
@ -102,3 +109,108 @@ static long int NativeGetsize(GFILE *f) {
|
|||||||
if (fstat(fileno((FILE *)f->obj), &st)) return -1;
|
if (fstat(fileno((FILE *)f->obj), &st)) return -1;
|
||||||
return st.st_size;
|
return st.st_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if GFILE_NEED_FILELISTS
|
||||||
|
#if defined(WIN32) || GFX_USE_OS_WIN32
|
||||||
|
typedef struct NativeFileList {
|
||||||
|
gfileList fl;
|
||||||
|
HANDLE d;
|
||||||
|
WIN32_FIND_DATA f;
|
||||||
|
bool_t first;
|
||||||
|
} NativeFileList;
|
||||||
|
|
||||||
|
static gfileList *NativeFlOpen(const char *path, bool_t dirs) {
|
||||||
|
NativeFileList *p;
|
||||||
|
(void) dirs;
|
||||||
|
|
||||||
|
if (!(p = gfxAlloc(sizeof(NativeFileList))))
|
||||||
|
return 0;
|
||||||
|
if ((p->d = FindFirstFile(path, &p->f)) == INVALID_HANDLE_VALUE) {
|
||||||
|
gfxFree(p);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
p->first = TRUE;
|
||||||
|
return &p->fl;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *NativeFlRead(gfileList *pfl) {
|
||||||
|
#define nfl ((NativeFileList *)pfl)
|
||||||
|
while(1) {
|
||||||
|
if (!nfl->first && !FindNextFile(nfl->d, &nfl->f))
|
||||||
|
return 0;
|
||||||
|
nfl->first = FALSE;
|
||||||
|
if (nfl->f.cFileName[0] == '.')
|
||||||
|
continue;
|
||||||
|
if (nfl->fl.dirs) {
|
||||||
|
if ((nfl->f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
if (!(nfl->f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nfl->f.cFileName;
|
||||||
|
#undef nfl
|
||||||
|
}
|
||||||
|
|
||||||
|
static void NativeFlClose(gfileList *pfl) {
|
||||||
|
CloseHandle(((NativeFileList *)pfl)->d);
|
||||||
|
gfxFree(pfl);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
#include <dirent.h>
|
||||||
|
|
||||||
|
typedef struct NativeFileList {
|
||||||
|
gfileList fl;
|
||||||
|
DIR * d;
|
||||||
|
struct dirent * f;
|
||||||
|
} NativeFileList;
|
||||||
|
|
||||||
|
static gfileList *NativeFlOpen(const char *path, bool_t dirs) {
|
||||||
|
NativeFileList *p;
|
||||||
|
(void) dirs;
|
||||||
|
|
||||||
|
if (!(p = gfxAlloc(sizeof(NativeFileList))))
|
||||||
|
return 0;
|
||||||
|
if (!(p->d = opendir(path))) {
|
||||||
|
gfxFree(p);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return &p->fl;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *NativeFlRead(gfileList *pfl) {
|
||||||
|
#define nfl ((NativeFileList *)pfl)
|
||||||
|
while(1) {
|
||||||
|
if (!(nfl->f = readdir(nfl->d)))
|
||||||
|
return 0;
|
||||||
|
if (nfl->f->d_name[0] == '.')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
#ifdef _DIRENT_HAVE_D_TYPE
|
||||||
|
if (nfl->fl.dirs) {
|
||||||
|
if (nfl->f->d_type == DT_DIR)
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
if (nfl->f->d_type == DT_REG)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
// Oops - no type field. We could use stat() here but that would mean
|
||||||
|
// concatting the supplied path to the found filename.
|
||||||
|
// That all just seems too hard. Instead we just don't
|
||||||
|
// distinguish between files and directories.
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
return nfl->f->d_name;
|
||||||
|
#undef nfl
|
||||||
|
}
|
||||||
|
|
||||||
|
static void NativeFlClose(gfileList *pfl) {
|
||||||
|
closedir(((NativeFileList *)pfl)->d);
|
||||||
|
gfxFree(pfl);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
261
src/gfile/inc_printg.c
Normal file
261
src/gfile/inc_printg.c
Normal file
@ -0,0 +1,261 @@
|
|||||||
|
/*
|
||||||
|
* This file is subject to the terms of the GFX License. If a copy of
|
||||||
|
* the license was not distributed with this file, you can obtain one at:
|
||||||
|
*
|
||||||
|
* http://ugfx.org/license.html
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This file is included by src/gfile/gfile.c
|
||||||
|
*/
|
||||||
|
|
||||||
|
/********************************************************
|
||||||
|
* Printg Routines
|
||||||
|
********************************************************/
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
#define MAX_FILLER 11
|
||||||
|
#define FLOAT_PRECISION 100000
|
||||||
|
|
||||||
|
int fnprintg(GFILE *f, int maxlen, const char *fmt, ...) {
|
||||||
|
int res;
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
res = vfnprintg(f, maxlen, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *ltoa_wd(char *p, long num, unsigned radix, long divisor) {
|
||||||
|
int i;
|
||||||
|
char * q;
|
||||||
|
|
||||||
|
if (!divisor) divisor = num;
|
||||||
|
|
||||||
|
q = p + MAX_FILLER;
|
||||||
|
do {
|
||||||
|
i = (int)(num % radix);
|
||||||
|
i += '0';
|
||||||
|
if (i > '9')
|
||||||
|
i += 'A' - '0' - 10;
|
||||||
|
*--q = i;
|
||||||
|
num /= radix;
|
||||||
|
} while ((divisor /= radix) != 0);
|
||||||
|
|
||||||
|
i = (int)(p + MAX_FILLER - q);
|
||||||
|
do {
|
||||||
|
*p++ = *q++;
|
||||||
|
} while (--i);
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
int vfnprintg(GFILE *f, int maxlen, const char *fmt, va_list arg) {
|
||||||
|
int ret;
|
||||||
|
char *p, *s, c, filler;
|
||||||
|
int i, precision, width;
|
||||||
|
bool_t is_long, left_align;
|
||||||
|
long l;
|
||||||
|
#if GFILE_ALLOW_FLOATS
|
||||||
|
float f;
|
||||||
|
char tmpbuf[2*MAX_FILLER + 1];
|
||||||
|
#else
|
||||||
|
char tmpbuf[MAX_FILLER + 1];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
if (maxlen < 0)
|
||||||
|
return 0;
|
||||||
|
if (!maxlen)
|
||||||
|
maxlen = -1;
|
||||||
|
|
||||||
|
while (*fmt) {
|
||||||
|
if (*fmt != '%') {
|
||||||
|
gfileWrite(f, fmt, 1);
|
||||||
|
ret++; if (!--maxlen) return ret;
|
||||||
|
fmt++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
fmt++;
|
||||||
|
|
||||||
|
p = s = tmpbuf;
|
||||||
|
left_align = FALSE;
|
||||||
|
filler = ' ';
|
||||||
|
width = 0;
|
||||||
|
precision = 0;
|
||||||
|
|
||||||
|
if (*fmt == '-') {
|
||||||
|
fmt++;
|
||||||
|
left_align = TRUE;
|
||||||
|
}
|
||||||
|
if (*fmt == '.') {
|
||||||
|
fmt++;
|
||||||
|
filler = '0';
|
||||||
|
}
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
c = *fmt++;
|
||||||
|
if (c >= '0' && c <= '9') {
|
||||||
|
c -= '0';
|
||||||
|
width = width * 10 + c;
|
||||||
|
} else if (c == '*')
|
||||||
|
width = va_arg(arg, int);
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (c == '.') {
|
||||||
|
while (1) {
|
||||||
|
c = *fmt++;
|
||||||
|
if (c >= '0' && c <= '9') {
|
||||||
|
c -= '0';
|
||||||
|
precision = precision * 10 + c;
|
||||||
|
} else if (c == '*')
|
||||||
|
precision = va_arg(arg, int);
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Long modifier.*/
|
||||||
|
if (c == 'l' || c == 'L') {
|
||||||
|
is_long = TRUE;
|
||||||
|
if (*fmt)
|
||||||
|
c = *fmt++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
is_long = (c >= 'A') && (c <= 'Z');
|
||||||
|
|
||||||
|
/* Command decoding.*/
|
||||||
|
switch (c) {
|
||||||
|
case 0:
|
||||||
|
return ret;
|
||||||
|
case 'c':
|
||||||
|
filler = ' ';
|
||||||
|
*p++ = va_arg(arg, int);
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
filler = ' ';
|
||||||
|
if ((s = va_arg(arg, char *)) == 0)
|
||||||
|
s = "(null)";
|
||||||
|
if (precision == 0)
|
||||||
|
precision = 32767;
|
||||||
|
for (p = s; *p && (--precision >= 0); p++);
|
||||||
|
break;
|
||||||
|
case 'D':
|
||||||
|
case 'd':
|
||||||
|
if (is_long)
|
||||||
|
l = va_arg(arg, long);
|
||||||
|
else
|
||||||
|
l = va_arg(arg, int);
|
||||||
|
if (l < 0) {
|
||||||
|
*p++ = '-';
|
||||||
|
l = -l;
|
||||||
|
}
|
||||||
|
p = ltoa_wd(p, l, 10, 0);
|
||||||
|
break;
|
||||||
|
#if GFILE_ALLOW_FLOATS
|
||||||
|
case 'f':
|
||||||
|
f = (float) va_arg(arg, double);
|
||||||
|
if (f < 0) {
|
||||||
|
*p++ = '-';
|
||||||
|
f = -f;
|
||||||
|
}
|
||||||
|
l = f;
|
||||||
|
p = ltoa_wd(p, l, 10, 0);
|
||||||
|
*p++ = '.';
|
||||||
|
l = (f - l) * FLOAT_PRECISION;
|
||||||
|
p = ltoa_wd(p, l, 10, FLOAT_PRECISION / 10);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
case 'X':
|
||||||
|
case 'x':
|
||||||
|
c = 16;
|
||||||
|
goto unsigned_common;
|
||||||
|
case 'U':
|
||||||
|
case 'u':
|
||||||
|
c = 10;
|
||||||
|
goto unsigned_common;
|
||||||
|
case 'O':
|
||||||
|
case 'o':
|
||||||
|
c = 8;
|
||||||
|
unsigned_common:
|
||||||
|
if (is_long)
|
||||||
|
l = va_arg(arg, long);
|
||||||
|
else
|
||||||
|
l = va_arg(arg, int);
|
||||||
|
p = ltoa_wd(p, l, c, 0);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
*p++ = c;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
i = (int)(p - s);
|
||||||
|
if ((width -= i) < 0)
|
||||||
|
width = 0;
|
||||||
|
if (left_align == FALSE)
|
||||||
|
width = -width;
|
||||||
|
if (width < 0) {
|
||||||
|
if (*s == '-' && filler == '0') {
|
||||||
|
gfileWrite(f, s++, 1);
|
||||||
|
ret++; if (!--maxlen) return ret;
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
do {
|
||||||
|
gfileWrite(f, &filler, 1);
|
||||||
|
ret++; if (!--maxlen) return ret;
|
||||||
|
} while (++width != 0);
|
||||||
|
}
|
||||||
|
while (--i >= 0) {
|
||||||
|
gfileWrite(f, s++, 1);
|
||||||
|
ret++; if (!--maxlen) return ret;
|
||||||
|
}
|
||||||
|
while (width) {
|
||||||
|
gfileWrite(f, &filler, 1);
|
||||||
|
ret++; if (!--maxlen) return ret;
|
||||||
|
width--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if GFILE_NEED_STRINGS
|
||||||
|
int snprintg(char *buf, int maxlen, const char *fmt, ...) {
|
||||||
|
int res;
|
||||||
|
GFILE f;
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
if (maxlen <= 1) {
|
||||||
|
if (maxlen == 1) {
|
||||||
|
*buf = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
maxlen += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
f.flags = GFILEFLG_WRITE|GFILEFLG_TRUNC;
|
||||||
|
gfileOpenStringFromStaticGFILE(&f, buf);
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
res = vfnprintg(&f, maxlen-1, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
int vsnprintg(char *buf, int maxlen, const char *fmt, va_list arg) {
|
||||||
|
GFILE f;
|
||||||
|
|
||||||
|
if (maxlen <= 1) {
|
||||||
|
if (maxlen == 1) {
|
||||||
|
*buf = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
maxlen += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
f.flags = GFILEFLG_WRITE|GFILEFLG_TRUNC;
|
||||||
|
gfileOpenStringFromStaticGFILE(&f, buf);
|
||||||
|
|
||||||
|
return vfnprintg(&f, maxlen-1, fmt, arg);
|
||||||
|
}
|
||||||
|
#endif
|
@ -31,11 +31,15 @@ typedef struct ROMFS_DIRENTRY {
|
|||||||
} ROMFS_DIRENTRY;
|
} ROMFS_DIRENTRY;
|
||||||
|
|
||||||
#define ROMFS_DIRENTRY_HEAD 0
|
#define ROMFS_DIRENTRY_HEAD 0
|
||||||
|
|
||||||
#include "romfs_files.h"
|
#include "romfs_files.h"
|
||||||
|
|
||||||
static const ROMFS_DIRENTRY const *FsROMHead = ROMFS_DIRENTRY_HEAD;
|
static const ROMFS_DIRENTRY const *FsROMHead = ROMFS_DIRENTRY_HEAD;
|
||||||
|
|
||||||
|
typedef struct ROMFileList {
|
||||||
|
gfileList fl;
|
||||||
|
const ROMFS_DIRENTRY *pdir;
|
||||||
|
} ROMFileList;
|
||||||
|
|
||||||
|
|
||||||
static bool_t ROMExists(const char *fname);
|
static bool_t ROMExists(const char *fname);
|
||||||
static long int ROMFilesize(const char *fname);
|
static long int ROMFilesize(const char *fname);
|
||||||
static bool_t ROMOpen(GFILE *f, const char *fname);
|
static bool_t ROMOpen(GFILE *f, const char *fname);
|
||||||
@ -44,6 +48,11 @@ static int ROMRead(GFILE *f, void *buf, int size);
|
|||||||
static bool_t ROMSetpos(GFILE *f, long int pos);
|
static bool_t ROMSetpos(GFILE *f, long int pos);
|
||||||
static long int ROMGetsize(GFILE *f);
|
static long int ROMGetsize(GFILE *f);
|
||||||
static bool_t ROMEof(GFILE *f);
|
static bool_t ROMEof(GFILE *f);
|
||||||
|
#if GFILE_NEED_FILELISTS
|
||||||
|
static gfileList *ROMFlOpen(const char *path, bool_t dirs);
|
||||||
|
static const char *ROMFlRead(gfileList *pfl);
|
||||||
|
static void ROMFlClose(gfileList *pfl);
|
||||||
|
#endif
|
||||||
|
|
||||||
static const GFILEVMT FsROMVMT = {
|
static const GFILEVMT FsROMVMT = {
|
||||||
GFILE_CHAINHEAD, // next
|
GFILE_CHAINHEAD, // next
|
||||||
@ -52,8 +61,10 @@ static const GFILEVMT FsROMVMT = {
|
|||||||
0, ROMExists, ROMFilesize, 0,
|
0, ROMExists, ROMFilesize, 0,
|
||||||
ROMOpen, ROMClose, ROMRead, 0,
|
ROMOpen, ROMClose, ROMRead, 0,
|
||||||
ROMSetpos, ROMGetsize, ROMEof,
|
ROMSetpos, ROMGetsize, ROMEof,
|
||||||
0, 0,
|
0, 0, 0,
|
||||||
0
|
#if GFILE_NEED_FILELISTS
|
||||||
|
ROMFlOpen, ROMFlRead, ROMFlClose
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
#undef GFILE_CHAINHEAD
|
#undef GFILE_CHAINHEAD
|
||||||
#define GFILE_CHAINHEAD &FsROMVMT
|
#define GFILE_CHAINHEAD &FsROMVMT
|
||||||
@ -122,3 +133,45 @@ static bool_t ROMEof(GFILE *f)
|
|||||||
{
|
{
|
||||||
return f->pos >= ((const ROMFS_DIRENTRY *)f->obj)->size;
|
return f->pos >= ((const ROMFS_DIRENTRY *)f->obj)->size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if GFILE_NEED_FILELISTS
|
||||||
|
static gfileList *ROMFlOpen(const char *path, bool_t dirs) {
|
||||||
|
ROMFileList * p;
|
||||||
|
(void) path;
|
||||||
|
|
||||||
|
// We don't support directories or path searching
|
||||||
|
if (dirs)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Allocate the list buffer
|
||||||
|
if (!(p = gfxAlloc(sizeof(ROMFileList))))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Initialize it and return it.
|
||||||
|
p->pdir = 0;
|
||||||
|
return &p->fl;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *ROMFlRead(gfileList *pfl) {
|
||||||
|
#define rfl ((ROMFileList *)pfl)
|
||||||
|
|
||||||
|
// Is it the first entry
|
||||||
|
if (!rfl->pdir) {
|
||||||
|
rfl->pdir = FsROMHead;
|
||||||
|
return FsROMHead->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is it not the last entry
|
||||||
|
if (rfl->pdir->next) {
|
||||||
|
rfl->pdir = rfl->pdir->next;
|
||||||
|
return rfl->pdir->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
#undef rfl
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ROMFlClose(gfileList *pfl) {
|
||||||
|
gfxFree(pfl);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
257
src/gfile/inc_scang.c
Normal file
257
src/gfile/inc_scang.c
Normal file
@ -0,0 +1,257 @@
|
|||||||
|
/*
|
||||||
|
* This file is subject to the terms of the GFX License. If a copy of
|
||||||
|
* the license was not distributed with this file, you can obtain one at:
|
||||||
|
*
|
||||||
|
* http://ugfx.org/license.html
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This file is included by src/gfile/gfile.c
|
||||||
|
*/
|
||||||
|
|
||||||
|
/********************************************************
|
||||||
|
* Scang Routines
|
||||||
|
********************************************************/
|
||||||
|
|
||||||
|
int fscang(GFILE *f, const char *fmt, ...) {
|
||||||
|
int res;
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
res = vfscang(f, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
int vfscang(GFILE *f, const char *fmt, va_list arg) {
|
||||||
|
int res, width, size, base;
|
||||||
|
unsigned long num;
|
||||||
|
char c;
|
||||||
|
bool_t assign, negate;
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
for(res = 0; *fmt; fmt++) {
|
||||||
|
switch(*fmt) {
|
||||||
|
case ' ': case '\t': case '\r': case '\n': case '\v': case '\f':
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '%':
|
||||||
|
fmt++;
|
||||||
|
assign = TRUE;
|
||||||
|
negate = FALSE;
|
||||||
|
width = 0;
|
||||||
|
size = 1;
|
||||||
|
num = 0;
|
||||||
|
|
||||||
|
if (*fmt == '*') {
|
||||||
|
fmt++;
|
||||||
|
assign = FALSE;
|
||||||
|
}
|
||||||
|
while(*fmt >= '0' && *fmt <= '9')
|
||||||
|
width = width * 10 + (*fmt++ - '0');
|
||||||
|
if (*fmt == 'h') {
|
||||||
|
fmt++;
|
||||||
|
size = 0;
|
||||||
|
} else if (*fmt == 'l') {
|
||||||
|
fmt++;
|
||||||
|
size = 2;
|
||||||
|
} else if (*fmt == 'L') {
|
||||||
|
fmt++;
|
||||||
|
size = 3;
|
||||||
|
}
|
||||||
|
switch(*fmt) {
|
||||||
|
case 0:
|
||||||
|
return res;
|
||||||
|
case '%':
|
||||||
|
goto matchchar;
|
||||||
|
case 'c':
|
||||||
|
if (!width) {
|
||||||
|
while(1) {
|
||||||
|
if (!gfileRead(f, &c, 1)) return res;
|
||||||
|
switch(c) {
|
||||||
|
case ' ': case '\t': case '\r':
|
||||||
|
case '\n': case '\v': case '\f': continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
width = 1;
|
||||||
|
} else {
|
||||||
|
if (!gfileRead(f, &c, 1)) return res;
|
||||||
|
}
|
||||||
|
if (assign) {
|
||||||
|
p = va_arg(arg, char *);
|
||||||
|
res++;
|
||||||
|
*p++ = c;
|
||||||
|
}
|
||||||
|
while(--width) {
|
||||||
|
if (!gfileRead(f, &c, 1)) return res;
|
||||||
|
if (assign) *p++ = c;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
while(1) {
|
||||||
|
if (!gfileRead(f, &c, 1)) return res;
|
||||||
|
switch(c) {
|
||||||
|
case ' ': case '\t': case '\r':
|
||||||
|
case '\n': case '\v': case '\f': continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (assign) {
|
||||||
|
p = va_arg(arg, char *);
|
||||||
|
res++;
|
||||||
|
*p++ = c;
|
||||||
|
}
|
||||||
|
if (width) {
|
||||||
|
while(--width) {
|
||||||
|
if (!gfileRead(f, &c, 1)) {
|
||||||
|
if (assign) *((char *)p) = 0;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
if (assign) *p++ = c;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
while(1) {
|
||||||
|
if (!gfileRead(f, &c, 1)) {
|
||||||
|
if (assign) *((char *)p) = 0;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
switch(c) {
|
||||||
|
case ' ': case '\t': case '\r':
|
||||||
|
case '\n': case '\v': case '\f': break;
|
||||||
|
default:
|
||||||
|
if (assign) *p++ = c;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
//ungetch(c);
|
||||||
|
}
|
||||||
|
if (assign) *p = 0;
|
||||||
|
break;
|
||||||
|
case 'd': base = 10; goto getnum;
|
||||||
|
case 'i': base = -1; goto getnum;
|
||||||
|
case 'o': base = 8; goto getnum;
|
||||||
|
case 'u': base = 10; goto getnum;
|
||||||
|
case 'x': base = 16; goto getnum;
|
||||||
|
case 'b': base = 2;
|
||||||
|
getnum:
|
||||||
|
while(1) {
|
||||||
|
if (!gfileRead(f, &c, 1)) return res;
|
||||||
|
switch(c) {
|
||||||
|
case ' ': case '\t': case '\r':
|
||||||
|
case '\n': case '\v': case '\f': continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (c == '-' && *fmt != 'u') {
|
||||||
|
negate = TRUE;
|
||||||
|
if ((width && !--width) || !gfileRead(f, &c, 1)) return res;
|
||||||
|
}
|
||||||
|
if (base == -1) {
|
||||||
|
if (c == '0') {
|
||||||
|
if ((width && !--width) || !gfileRead(f, &c, 1)) goto assignnum;
|
||||||
|
switch(c) {
|
||||||
|
case 'x': case 'X':
|
||||||
|
base = 16;
|
||||||
|
if ((width && !--width) || !gfileRead(f, &c, 1)) return res;
|
||||||
|
break;
|
||||||
|
case 'b': case 'B':
|
||||||
|
base = 2;
|
||||||
|
if ((width && !--width) || !gfileRead(f, &c, 1)) return res;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
base = 8;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
base = 10;
|
||||||
|
}
|
||||||
|
while(1) {
|
||||||
|
if (c >= '0' && c <= '9' && c - '0' < base)
|
||||||
|
num = num * base + (c - '0');
|
||||||
|
else if (c >= 'A' && c <= 'F' && base == 16)
|
||||||
|
num = num * base + (c - ('A'-10));
|
||||||
|
else if (c >= 'a' && c <= 'f' && base == 16)
|
||||||
|
num = num * base + (c - ('a'-10));
|
||||||
|
else {
|
||||||
|
// ungetch(c)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ((width && !--width) || !gfileRead(f, &c, 1))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
assignnum:
|
||||||
|
if (negate)
|
||||||
|
num = -num;
|
||||||
|
|
||||||
|
if (assign) {
|
||||||
|
switch(size) {
|
||||||
|
case 0: // short
|
||||||
|
p = (char *)va_arg(arg, short *);
|
||||||
|
res++;
|
||||||
|
*((short *)p) = (short)num;
|
||||||
|
case 1: // int
|
||||||
|
p = (char *)va_arg(arg, int *);
|
||||||
|
res++;
|
||||||
|
*((int *)p) = (int)num;
|
||||||
|
case 2: case 3: // long
|
||||||
|
p = (char *)va_arg(arg, long *);
|
||||||
|
res++;
|
||||||
|
*((long *)p) = (long)num;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
#if GFILE_ALLOW_FLOATS
|
||||||
|
case 'e': case 'f': case 'g':
|
||||||
|
// TODO
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
matchchar:
|
||||||
|
while(1) {
|
||||||
|
if (!gfileRead(f, &c, 1)) return res;
|
||||||
|
switch(c) {
|
||||||
|
case ' ': case '\t': case '\r':
|
||||||
|
case '\n': case '\v': case '\f': continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (c != *fmt) return res;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if GFILE_NEED_STRINGS
|
||||||
|
int sscang(const char *buf, const char *fmt, ...) {
|
||||||
|
int res;
|
||||||
|
GFILE f;
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
f.flags = GFILEFLG_READ;
|
||||||
|
gfileOpenStringFromStaticGFILE(&f, (char *)buf);
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
res = vfscang(&f, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
int vsscang(const char *buf, const char *fmt, va_list arg) {
|
||||||
|
GFILE f;
|
||||||
|
|
||||||
|
f.flags = GFILEFLG_READ;
|
||||||
|
gfileOpenStringFromStaticGFILE(&f, (char *)buf);
|
||||||
|
|
||||||
|
return vfscang(&f, fmt, arg);
|
||||||
|
}
|
||||||
|
#endif
|
45
src/gfile/inc_stdio.c
Normal file
45
src/gfile/inc_stdio.c
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* This file is subject to the terms of the GFX License. If a copy of
|
||||||
|
* the license was not distributed with this file, you can obtain one at:
|
||||||
|
*
|
||||||
|
* http://ugfx.org/license.html
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This file is included by src/gfile/gfile.c
|
||||||
|
*/
|
||||||
|
|
||||||
|
/********************************************************
|
||||||
|
* Stdio Emulation Routines
|
||||||
|
********************************************************/
|
||||||
|
|
||||||
|
size_t gstdioRead(void * ptr, size_t size, size_t count, FILE *f) {
|
||||||
|
return gfileRead(f, ptr, size*count)/size;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t gstdioWrite(const void * ptr, size_t size, size_t count, FILE *f) {
|
||||||
|
return gfileWrite(f, ptr, size*count)/size;
|
||||||
|
}
|
||||||
|
|
||||||
|
int gstdioSeek(FILE *f, size_t offset, int origin) {
|
||||||
|
switch(origin) {
|
||||||
|
case SEEK_SET:
|
||||||
|
break;
|
||||||
|
case SEEK_CUR:
|
||||||
|
offset += f->pos;
|
||||||
|
break;
|
||||||
|
case SEEK_END:
|
||||||
|
offset += gfileGetSize(f);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return gfileSetPos(f, offset) ? 0 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int gstdioGetpos(FILE *f, long int *pos) {
|
||||||
|
if (!(f->flags & GFILEFLG_OPEN))
|
||||||
|
return -1;
|
||||||
|
*pos = f->pos;
|
||||||
|
return 0;
|
||||||
|
}
|
69
src/gfile/inc_strings.c
Normal file
69
src/gfile/inc_strings.c
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* This file is subject to the terms of the GFX License. If a copy of
|
||||||
|
* the license was not distributed with this file, you can obtain one at:
|
||||||
|
*
|
||||||
|
* http://ugfx.org/license.html
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This file is included by src/gfile/gfile.c
|
||||||
|
*/
|
||||||
|
|
||||||
|
/********************************************************
|
||||||
|
* The virtual string file VMT
|
||||||
|
********************************************************/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
// Special String VMT
|
||||||
|
static int StringRead(GFILE *f, void *buf, int size) {
|
||||||
|
int res;
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
p = ((char *)f->obj) + f->pos;
|
||||||
|
for(res = 0; res < size && *p; res++, p++, buf = ((char *)buf)+1)
|
||||||
|
((char *)buf)[0] = *p;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
static int StringWrite(GFILE *f, const void *buf, int size) {
|
||||||
|
if ((f->flags & GFILEFLG_APPEND)) {
|
||||||
|
while(((char *)f->obj)[f->pos])
|
||||||
|
f->pos++;
|
||||||
|
}
|
||||||
|
memcpy(((char *)f->obj)+f->pos, buf, size);
|
||||||
|
((char *)f->obj)[f->pos+size] = 0;
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
static const GFILEVMT StringVMT = {
|
||||||
|
0, // next
|
||||||
|
0, // flags
|
||||||
|
'_', // prefix
|
||||||
|
0, 0, 0, 0,
|
||||||
|
0, 0, StringRead, StringWrite,
|
||||||
|
0, 0, 0,
|
||||||
|
0, 0, 0,
|
||||||
|
#if GFILE_NEED_FILELISTS
|
||||||
|
0, 0, 0,
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
static void gfileOpenStringFromStaticGFILE(GFILE *f, char *str) {
|
||||||
|
if ((f->flags & GFILEFLG_TRUNC))
|
||||||
|
str[0] = 0;
|
||||||
|
f->vmt = &StringVMT;
|
||||||
|
f->obj = str;
|
||||||
|
f->pos = 0;
|
||||||
|
f->flags |= GFILEFLG_OPEN|GFILEFLG_CANSEEK;
|
||||||
|
}
|
||||||
|
|
||||||
|
GFILE *gfileOpenString(char *str, const char *mode) {
|
||||||
|
GFILE *f;
|
||||||
|
|
||||||
|
// Get an empty file and set the flags
|
||||||
|
if (!(f = findemptyfile(mode)))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// File is open - fill in all the details
|
||||||
|
gfileOpenStringFromStaticGFILE(f, str);
|
||||||
|
return f;
|
||||||
|
}
|
@ -33,8 +33,10 @@
|
|||||||
|
|
||||||
#ifndef GFILE_IMPLEMENTATION
|
#ifndef GFILE_IMPLEMENTATION
|
||||||
typedef void GFILE;
|
typedef void GFILE;
|
||||||
|
typedef void gfileList;
|
||||||
#else
|
#else
|
||||||
typedef struct GFILE GFILE;
|
typedef struct GFILE GFILE;
|
||||||
|
typedef struct gfileList gfileList;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern GFILE *gfileStdIn;
|
extern GFILE *gfileStdIn;
|
||||||
@ -98,14 +100,33 @@ extern "C" {
|
|||||||
/**
|
/**
|
||||||
* @brief Open file
|
* @brief Open file
|
||||||
* @details A file must be opened before it can be accessed
|
* @details A file must be opened before it can be accessed
|
||||||
* @details ToDo (document possible modes)
|
|
||||||
* @details The resulting GFILE will be used for all functions that access the file.
|
* @details The resulting GFILE will be used for all functions that access the file.
|
||||||
*
|
*
|
||||||
* @param[in] fname The file name
|
* @param[in] fname The file name
|
||||||
* @param[in] mode The mode
|
* @param[in] mode The mode.
|
||||||
*
|
*
|
||||||
* @return Valid GFILE on success, 0 otherwise
|
* @return Valid GFILE on success, 0 otherwise
|
||||||
*
|
*
|
||||||
|
* @note The modes follow the c library fopen() standard.
|
||||||
|
* The valid modes are:<br/>
|
||||||
|
* <ul><li>r - Open for read, the file must exist</li>
|
||||||
|
* <li>w - Open for write, the file is truncated if it exists</li>
|
||||||
|
* <li>wx - Open for write, the file must not exist</li>
|
||||||
|
* <li>a - Open for append, the file is truncated if it exists</li>
|
||||||
|
* <li>ax - Open for append, the file must not exists</li>
|
||||||
|
* </ul><br/>
|
||||||
|
* THe following flags can also be added to the above modes:<br/>
|
||||||
|
* <ul><li>+ - Open for both read and write</li>
|
||||||
|
* <li>b - Open as a binary file rather than a text file</li>
|
||||||
|
* <ul>
|
||||||
|
* @note Not all file-systems support all modes. For example, write
|
||||||
|
* is not available with the ROM file-system. Similarly few platforms
|
||||||
|
* distinguish between binary and text files.
|
||||||
|
* @note Even though binary vs text is relevant only for a small number of platforms
|
||||||
|
* the "b" flag should always be specified for binary files such as images.
|
||||||
|
* This ensures portability to other platforms. The extra flag will be ignored
|
||||||
|
* on platforms where it is not relevant.
|
||||||
|
*
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
GFILE * gfileOpen(const char *fname, const char *mode);
|
GFILE * gfileOpen(const char *fname, const char *mode);
|
||||||
@ -239,15 +260,118 @@ extern "C" {
|
|||||||
*/
|
*/
|
||||||
bool_t gfileSync(GFILE *f);
|
bool_t gfileSync(GFILE *f);
|
||||||
|
|
||||||
#if GFILE_NEED_CHIBIOSFS && GFX_USE_OS_CHIBIOS
|
#if GFILE_NEED_FILELISTS || defined(__DOXYGEN__)
|
||||||
|
/**
|
||||||
|
* @brief Open a file list
|
||||||
|
*
|
||||||
|
* @param[in] fs The file system (F for FatFS)
|
||||||
|
* @param[in] path Path information to pass to the file system
|
||||||
|
* @param[in] dirs Pass TRUE to get directories only, FALSE to get files only
|
||||||
|
*
|
||||||
|
* @return A pointer to a file list on success, NULL otherwise
|
||||||
|
*
|
||||||
|
* @note The path parameter is handled in a file-system specific way. It could be
|
||||||
|
* treated as a directory name, it may be treated as a file pattern, or it
|
||||||
|
* may be ignored. Passing NULL will always return the full list of files
|
||||||
|
* in at least the top level directory.
|
||||||
|
* @note For file systems that do not support directories, passing TRUE for dirs
|
||||||
|
* will return an error.
|
||||||
|
* @note You must call @p gfileCloseFileList() when you have finished with the
|
||||||
|
* file list in order to free resources.
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
gfileList *gfileOpenFileList(char fs, const char *path, bool_t dirs);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the next file in a file list.
|
||||||
|
*
|
||||||
|
* @param[in] pfl Pointer to a file list returned by @p gfileOpenFileList()
|
||||||
|
*
|
||||||
|
* @return A pointer to a file (or directory) name. Returns NULL if there are no more.
|
||||||
|
*
|
||||||
|
* @note The file name may contain the full directory path or may not depending
|
||||||
|
* on how the file system treats directories.
|
||||||
|
* @note The returned buffer may be destroyed by the next call to any of
|
||||||
|
* @p gfileOpenFileList(), @p gfileReadFileList() or @p gfileCloseFileList().
|
||||||
|
* Do not use this pointer after one of those calls.
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
const char *gfileReadFileList(gfileList *pfl);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Close a file list.
|
||||||
|
*
|
||||||
|
* @param[in] pfl Pointer to a file list returned by @p gfileOpenFileList()
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
void gfileCloseFileList(gfileList *pfl);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (GFILE_NEED_CHIBIOSFS && GFX_USE_OS_CHIBIOS) || defined(__DOXYGEN__)
|
||||||
|
/**
|
||||||
|
* @brief Open file from a ChibiOS BaseFileStream
|
||||||
|
*
|
||||||
|
* @param[in] BaseFileStreamPtr The BaseFileStream to open as a GFILE
|
||||||
|
* @param[in] mode The mode.
|
||||||
|
*
|
||||||
|
* @return Valid GFILE on success, 0 otherwise
|
||||||
|
*
|
||||||
|
* @note The modes are the same modes as in @p gfileOpen(). The
|
||||||
|
* open mode is NOT compared against the BaseFileStream capabilities.
|
||||||
|
* @note Supported operations are: read, write, getpos, setpos, eof and getsize
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
GFILE * gfileOpenBaseFileStream(void *BaseFileStreamPtr, const char *mode);
|
GFILE * gfileOpenBaseFileStream(void *BaseFileStreamPtr, const char *mode);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if GFILE_NEED_MEMFS
|
#if GFILE_NEED_MEMFS || defined(__DOXYGEN__)
|
||||||
|
/**
|
||||||
|
* @brief Open file from a memory pointer
|
||||||
|
*
|
||||||
|
* @param[in] memptr The pointer to the memory
|
||||||
|
* @param[in] mode The mode.
|
||||||
|
*
|
||||||
|
* @return Valid GFILE on success, 0 otherwise
|
||||||
|
*
|
||||||
|
* @note The modes are the same modes as in @p gfileOpen(). Note there is
|
||||||
|
* no concept of file-size. Be careful not to overwrite other memory or
|
||||||
|
* to read from inaccessible sections of memory.
|
||||||
|
* @note Supported operations are: read, write, getpos, setpos
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
GFILE * gfileOpenMemory(void *memptr, const char *mode);
|
GFILE * gfileOpenMemory(void *memptr, const char *mode);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if GFILE_NEED_PRINTG
|
#if GFILE_NEED_STRINGS || defined(__DOXYGEN__)
|
||||||
|
/**
|
||||||
|
* @brief Open file from a null terminated C string
|
||||||
|
*
|
||||||
|
* @param[in] memptr The pointer to the string or string buffer
|
||||||
|
* @param[in] mode The mode.
|
||||||
|
*
|
||||||
|
* @return Valid GFILE on success, 0 otherwise
|
||||||
|
*
|
||||||
|
* @note The modes are the same modes as in @p gfileOpen(). Note there is
|
||||||
|
* no concept of file-size. Be careful not to overwrite other memory or
|
||||||
|
* to read from inaccessible sections of memory.
|
||||||
|
* @note Reading will return EOF when the NULL character is reached.
|
||||||
|
* @note Writing will always place a NULL in the next character effectively terminating the
|
||||||
|
* string at the character just written.
|
||||||
|
* @note Supported operations are: read, write, append, getpos, setpos
|
||||||
|
* @note Be careful with setpos and getpos. They do not check for the end of the string.
|
||||||
|
* @note Reading and Writing will read/write a maximum of one character at a time.
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
GFILE * gfileOpenString(char *str, const char *mode);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if GFILE_NEED_PRINTG || defined(__DOXYGEN__)
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
int vfnprintg(GFILE *f, int maxlen, const char *fmt, va_list arg);
|
int vfnprintg(GFILE *f, int maxlen, const char *fmt, va_list arg);
|
||||||
@ -265,7 +389,7 @@ extern "C" {
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if GFILE_NEED_SCANG
|
#if GFILE_NEED_SCANG || defined(__DOXYGEN__)
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
int vfscang(GFILE *f, const char *fmt, va_list arg);
|
int vfscang(GFILE *f, const char *fmt, va_list arg);
|
||||||
|
@ -46,6 +46,7 @@
|
|||||||
/**
|
/**
|
||||||
* @brief Include printg, fprintg etc functions
|
* @brief Include printg, fprintg etc functions
|
||||||
* @details Defaults to FALSE
|
* @details Defaults to FALSE
|
||||||
|
* @pre To get the string sprintg functions you also need to define @p GFILE_NEED_STRINGS
|
||||||
*/
|
*/
|
||||||
#ifndef GFILE_NEED_PRINTG
|
#ifndef GFILE_NEED_PRINTG
|
||||||
#define GFILE_NEED_PRINTG FALSE
|
#define GFILE_NEED_PRINTG FALSE
|
||||||
@ -53,15 +54,14 @@
|
|||||||
/**
|
/**
|
||||||
* @brief Include scang, fscang etc functions
|
* @brief Include scang, fscang etc functions
|
||||||
* @details Defaults to FALSE
|
* @details Defaults to FALSE
|
||||||
|
* @pre To get the string sscang functions you also need to define @p GFILE_NEED_STRINGS
|
||||||
*/
|
*/
|
||||||
#ifndef GFILE_NEED_SCANG
|
#ifndef GFILE_NEED_SCANG
|
||||||
#define GFILE_NEED_SCANG FALSE
|
#define GFILE_NEED_SCANG FALSE
|
||||||
#endif
|
#endif
|
||||||
/**
|
/**
|
||||||
* @brief Include the string sprintg/sscang functions
|
* @brief Include the string based file functions
|
||||||
* @details Defaults to FALSE
|
* @details Defaults to FALSE
|
||||||
* @pre To get sprintg functions you also need to define @p GFILE_NEED_PRINTG
|
|
||||||
* @pre To get sscang functions you also need to define @p GFILE_NEED_SCANG
|
|
||||||
*/
|
*/
|
||||||
#ifndef GFILE_NEED_STRINGS
|
#ifndef GFILE_NEED_STRINGS
|
||||||
#define GFILE_NEED_STRINGS FALSE
|
#define GFILE_NEED_STRINGS FALSE
|
||||||
@ -146,6 +146,14 @@
|
|||||||
#ifndef GFILE_NEED_MEMFS
|
#ifndef GFILE_NEED_MEMFS
|
||||||
#define GFILE_NEED_MEMFS FALSE
|
#define GFILE_NEED_MEMFS FALSE
|
||||||
#endif
|
#endif
|
||||||
|
/**
|
||||||
|
* @brief Include support for file list functions
|
||||||
|
* @details Defaults to FALSE
|
||||||
|
* @note Adds support for @p gfileOpenFileList(), @p gfileReadFileList() and @p gfileCloseFileList().
|
||||||
|
*/
|
||||||
|
#ifndef GFILE_NEED_FILELISTS
|
||||||
|
#define GFILE_NEED_FILELISTS FALSE
|
||||||
|
#endif
|
||||||
/**
|
/**
|
||||||
* @}
|
* @}
|
||||||
*
|
*
|
||||||
|
Loading…
Reference in New Issue
Block a user