aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorinmarket <andrewh@inmarket.com.au>2014-08-12 16:45:06 +1000
committerinmarket <andrewh@inmarket.com.au>2014-08-12 16:45:06 +1000
commit5460a923ab25d27e522fe175563633665c477e02 (patch)
treee43734965f66092d3d076a599b3b8a188b005bc0 /src
parent0e74c164c3eac14f6e99d1a5cc4e0563faeff5d0 (diff)
parent10902154aec652a3fcdf028b2c6ff16743464973 (diff)
downloaduGFX-5460a923ab25d27e522fe175563633665c477e02.tar.gz
uGFX-5460a923ab25d27e522fe175563633665c477e02.tar.bz2
uGFX-5460a923ab25d27e522fe175563633665c477e02.zip
Merge branch 'master' into newmouse
Diffstat (limited to 'src')
-rw-r--r--src/gdisp/gdisp.c6
-rw-r--r--src/gdisp/image_native.c2
-rw-r--r--src/gevent/gevent.c98
-rw-r--r--src/gevent/sys_defs.h21
-rw-r--r--src/gfile/gfile.c788
-rw-r--r--src/gfile/inc_chibiosfs.c33
-rw-r--r--src/gfile/inc_fatfs.c81
-rw-r--r--src/gfile/inc_memfs.c21
-rw-r--r--src/gfile/inc_nativefs.c116
-rw-r--r--src/gfile/inc_printg.c261
-rw-r--r--src/gfile/inc_romfs.c61
-rw-r--r--src/gfile/inc_scang.c257
-rw-r--r--src/gfile/inc_stdio.c45
-rw-r--r--src/gfile/inc_strings.c69
-rw-r--r--src/gfile/sys_defs.h136
-rw-r--r--src/gfile/sys_options.h14
-rw-r--r--src/gos/gfx_chibios.c (renamed from src/gos/chibios.c)27
-rw-r--r--src/gos/gfx_chibios.h (renamed from src/gos/chibios.h)0
-rw-r--r--src/gos/gfx_ecos.c (renamed from src/gos/ecos.c)7
-rw-r--r--src/gos/gfx_ecos.h (renamed from src/gos/ecos.h)0
-rw-r--r--src/gos/gfx_freertos.c (renamed from src/gos/freertos.c)8
-rw-r--r--src/gos/gfx_freertos.h (renamed from src/gos/freertos.h)12
-rw-r--r--src/gos/gfx_linux.c (renamed from src/gos/linux.c)1
-rw-r--r--src/gos/gfx_linux.h (renamed from src/gos/linux.h)0
-rw-r--r--src/gos/gfx_osx.c (renamed from src/gos/osx.c)1
-rw-r--r--src/gos/gfx_osx.h (renamed from src/gos/osx.h)0
-rw-r--r--src/gos/gfx_raw32.c (renamed from src/gos/raw32.c)6
-rw-r--r--src/gos/gfx_raw32.h (renamed from src/gos/raw32.h)22
-rw-r--r--src/gos/gfx_rawrtos.c83
-rw-r--r--src/gos/gfx_rawrtos.h77
-rw-r--r--src/gos/gfx_win32.c (renamed from src/gos/win32.c)2
-rw-r--r--src/gos/gfx_win32.h (renamed from src/gos/win32.h)0
-rw-r--r--src/gos/sys_defs.h16
-rw-r--r--src/gos/sys_make.mk15
-rw-r--r--src/gos/sys_options.h14
-rw-r--r--src/gos/sys_rules.h4
-rw-r--r--src/gwin/button.c3
-rw-r--r--src/gwin/button.h3
-rw-r--r--src/gwin/checkbox.c3
-rw-r--r--src/gwin/checkbox.h3
-rw-r--r--src/gwin/class_gwin.h4
-rw-r--r--src/gwin/frame.c6
-rw-r--r--src/gwin/gcontainer.c13
-rw-r--r--src/gwin/gcontainer.h1
-rw-r--r--src/gwin/gwidget.c57
-rw-r--r--src/gwin/gwidget.h45
-rw-r--r--src/gwin/list.c3
-rw-r--r--src/gwin/list.h3
-rw-r--r--src/gwin/radio.c3
-rw-r--r--src/gwin/radio.h3
-rw-r--r--src/gwin/slider.c3
-rw-r--r--src/gwin/slider.h3
-rw-r--r--src/gwin/sys_options.h9
53 files changed, 1653 insertions, 816 deletions
diff --git a/src/gdisp/gdisp.c b/src/gdisp/gdisp.c
index e9ede8ab..b8b4a847 100644
--- a/src/gdisp/gdisp.c
+++ b/src/gdisp/gdisp.c
@@ -21,7 +21,11 @@
#if 1
#undef INLINE
- #define INLINE inline
+ #if defined(__KEIL__) || defined(__C51__)
+ #define INLINE __inline
+ #else
+ #define INLINE inline
+ #endif
#else
#undef INLINE
#define INLINE
diff --git a/src/gdisp/image_native.c b/src/gdisp/image_native.c
index c458531e..81344642 100644
--- a/src/gdisp/image_native.c
+++ b/src/gdisp/image_native.c
@@ -90,7 +90,7 @@ gdispImageError gdispImageCache_NATIVE(gdispImage *img) {
return GDISP_IMAGE_ERR_OK;
}
-gdispImageError gdispImageGDraw_NATIVE(GDisplay *g, gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy) {
+gdispImageError gdispGImageDraw_NATIVE(GDisplay *g, gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy) {
coord_t mx, mcx;
size_t pos, len;
diff --git a/src/gevent/gevent.c b/src/gevent/gevent.c
index 779f63a0..f1dab064 100644
--- a/src/gevent/gevent.c
+++ b/src/gevent/gevent.c
@@ -22,26 +22,40 @@
#define GEVENT_ASSERT(x)
#endif
+/* Flags in the listener structure */
+#define GLISTENER_EVENTBUSY 0x0001 // The event buffer is busy
+#define GLISTENER_WAITING 0x0002 // The listener is waiting for a signal
+#define GLISTENER_WITHSOURCE 0x0004 // The listener is being looked at by a source for a possible event
+
/* This mutex protects access to our tables */
static gfxMutex geventMutex;
/* Our table of listener/source pairs */
static GSourceListener Assignments[GEVENT_MAX_SOURCE_LISTENERS];
+/* Send an exit event if possible. */
+/* We already have the geventMutex */
+static void doExitEvent(GListener *pl) {
+ // Don't do the exit if someone else currently has the event lock
+ if ((pl->flags & (GLISTENER_WAITING|GLISTENER_EVENTBUSY)) == GLISTENER_WAITING) {
+ pl->flags |= GLISTENER_EVENTBUSY; // Event buffer is in use
+ pl->event.type = GEVENT_EXIT; // Set up the EXIT event
+ pl->flags &= ~GLISTENER_WAITING; // Wake up the listener (with data)
+ gfxSemSignal(&pl->waitqueue);
+ }
+}
+
/* Loop through the assignment table deleting this listener/source pair. */
/* Null is treated as a wildcard. */
+/* We already have the geventMutex */
static void deleteAssignments(GListener *pl, GSourceHandle gsh) {
GSourceListener *psl;
for(psl = Assignments; psl < Assignments+GEVENT_MAX_SOURCE_LISTENERS; psl++) {
if ((!pl || psl->pListener == pl) && (!gsh || psl->pSource == gsh)) {
- if (gfxSemCounter(&psl->pListener->waitqueue) < 0) {
- gfxSemWait(&psl->pListener->eventlock, TIME_INFINITE); // Obtain the buffer lock
- psl->pListener->event.type = GEVENT_EXIT; // Set up the EXIT event
- gfxSemSignal(&psl->pListener->waitqueue); // Wake up the listener
- gfxSemSignal(&psl->pListener->eventlock); // Release the buffer lock
- }
+ doExitEvent(psl->pListener);
psl->pListener = 0;
+ psl->pSource = 0;
}
}
}
@@ -58,9 +72,9 @@ void _geventDeinit(void)
void geventListenerInit(GListener *pl) {
gfxSemInit(&pl->waitqueue, 0, MAX_SEMAPHORE_COUNT); // Next wait'er will block
- gfxSemInit(&pl->eventlock, 1, 1); // Only one thread at a time looking at the event buffer
pl->callback = 0; // No callback active
pl->event.type = GEVENT_NULL; // Always safety
+ pl->flags = 0;
}
bool_t geventAttachSource(GListener *pl, GSourceHandle gsh, unsigned flags) {
@@ -80,9 +94,7 @@ bool_t geventAttachSource(GListener *pl, GSourceHandle gsh, unsigned flags) {
if (pl == psl->pListener && gsh == psl->pSource) {
// Just update the flags
- gfxSemWait(&pl->eventlock, TIME_INFINITE); // Safety first - just in case a source is using it
psl->listenflags = flags;
- gfxSemSignal(&pl->eventlock); // Release this lock
gfxMutexExit(&geventMutex);
return TRUE;
}
@@ -106,33 +118,37 @@ void geventDetachSource(GListener *pl, GSourceHandle gsh) {
if (pl) {
gfxMutexEnter(&geventMutex);
deleteAssignments(pl, gsh);
- if (!gsh && gfxSemCounter(&pl->waitqueue) < 0) {
- gfxSemWait(&pl->eventlock, TIME_INFINITE); // Obtain the buffer lock
- pl->event.type = GEVENT_EXIT; // Set up the EXIT event
- gfxSemSignal(&pl->waitqueue); // Wake up the listener
- gfxSemSignal(&pl->eventlock); // Release the buffer lock
- }
+ if (!gsh)
+ doExitEvent(pl);
gfxMutexExit(&geventMutex);
}
}
GEvent *geventEventWait(GListener *pl, delaytime_t timeout) {
- if (pl->callback || gfxSemCounter(&pl->waitqueue) < 0)
+ gfxMutexEnter(&geventMutex);
+ // Don't allow waiting if we are on callbacks or if there is already a thread waiting
+ if (pl->callback || (pl->flags & GLISTENER_WAITING)) {
+ gfxMutexExit(&geventMutex);
return 0;
+ }
+ pl->flags &= ~GLISTENER_EVENTBUSY; // Event buffer is definitely not busy
+ pl->flags |= GLISTENER_WAITING; // We will now be waiting on the thread
+ gfxMutexExit(&geventMutex);
return gfxSemWait(&pl->waitqueue, timeout) ? &pl->event : 0;
}
+void geventEventComplete(GListener *pl) {
+ pl->flags &= ~GLISTENER_EVENTBUSY;
+}
+
void geventRegisterCallback(GListener *pl, GEventCallbackFn fn, void *param) {
if (pl) {
gfxMutexEnter(&geventMutex);
- gfxSemWait(&pl->eventlock, TIME_INFINITE); // Obtain the buffer lock
- pl->param = param; // Set the param
- pl->callback = fn; // Set the callback function
- if (gfxSemCounter(&pl->waitqueue) < 0) {
- pl->event.type = GEVENT_EXIT; // Set up the EXIT event
- gfxSemSignal(&pl->waitqueue); // Wake up the listener
- }
- gfxSemSignal(&pl->eventlock); // Release the buffer lock
+ doExitEvent(pl);
+ pl->param = param; // Set the param
+ pl->callback = fn; // Set the callback function
+ if (fn)
+ pl->flags &= ~GLISTENER_EVENTBUSY; // The event buffer is immediately available
gfxMutexExit(&geventMutex);
}
}
@@ -146,14 +162,13 @@ GSourceListener *geventGetSourceListener(GSourceHandle gsh, GSourceListener *las
gfxMutexEnter(&geventMutex);
- // Unlock the last listener event buffer
- if (lastlr)
- gfxSemSignal(&lastlr->pListener->eventlock);
+ // Unlock the last listener event buffer if it wasn't used.
+ if (lastlr && lastlr->pListener && (lastlr->pListener->flags & GLISTENER_WITHSOURCE))
+ lastlr->pListener->flags &= ~(GLISTENER_WITHSOURCE|GLISTENER_EVENTBUSY);
// Loop through the table looking for attachments to this source
for(psl = lastlr ? (lastlr+1) : Assignments; psl < Assignments+GEVENT_MAX_SOURCE_LISTENERS; psl++) {
if (gsh == psl->pSource) {
- gfxSemWait(&psl->pListener->eventlock, TIME_INFINITE); // Obtain a lock on the listener event buffer
gfxMutexExit(&geventMutex);
return psl;
}
@@ -163,21 +178,38 @@ GSourceListener *geventGetSourceListener(GSourceHandle gsh, GSourceListener *las
}
GEvent *geventGetEventBuffer(GSourceListener *psl) {
- // We already know we have the event lock
- return &psl->pListener->callback || gfxSemCounter(&psl->pListener->waitqueue) < 0 ? &psl->pListener->event : 0;
+ gfxMutexEnter(&geventMutex);
+ if ((psl->pListener->flags & GLISTENER_EVENTBUSY)) {
+ // Oops - event buffer is still in use
+ gfxMutexExit(&geventMutex);
+ return 0;
+ }
+
+ // Allocate the event buffer
+ psl->pListener->flags |= (GLISTENER_WITHSOURCE|GLISTENER_EVENTBUSY);
+ gfxMutexExit(&geventMutex);
+ return &psl->pListener->event;
}
void geventSendEvent(GSourceListener *psl) {
gfxMutexEnter(&geventMutex);
- if (psl->pListener->callback) { // This test needs to be taken inside the mutex
+ if (psl->pListener->callback) {
+
+ // Mark it back as free and as sent. This is early to be marking as free but it protects
+ // if the callback alters the listener in any way
+ psl->pListener->flags &= ~(GLISTENER_WITHSOURCE|GLISTENER_EVENTBUSY);
gfxMutexExit(&geventMutex);
- // We already know we have the event lock
+
+ // Do the callback
psl->pListener->callback(psl->pListener->param, &psl->pListener->event);
} else {
// Wake up the listener
- if (gfxSemCounter(&psl->pListener->waitqueue) <= 0)
+ if ((psl->pListener->flags & GLISTENER_WAITING)) {
+ psl->pListener->flags &= ~(GLISTENER_WITHSOURCE|GLISTENER_WAITING);
gfxSemSignal(&psl->pListener->waitqueue);
+ // The listener thread will free the event buffer when ready
+ }
gfxMutexExit(&geventMutex);
}
}
diff --git a/src/gevent/sys_defs.h b/src/gevent/sys_defs.h
index c50dc5ae..9f1f4dde 100644
--- a/src/gevent/sys_defs.h
+++ b/src/gevent/sys_defs.h
@@ -56,7 +56,7 @@ typedef void (*GEventCallbackFn)(void *param, GEvent *pe);
// The Listener Object
typedef struct GListener {
gfxSem waitqueue; // Private: Semaphore for the listener to wait on.
- gfxSem eventlock; // Private: Protect against more than one sources trying to use this event lock at the same time
+ uint16_t flags; // Private: Flags for operation
GEventCallbackFn callback; // Private: Call back Function
void *param; // Private: Parameter for the callback function.
GEvent event; // Public: The event object into which the event information is stored.
@@ -149,9 +149,11 @@ void geventDetachSource(GListener *pl, GSourceHandle gsh);
* timeout specifies the time to wait in system ticks.
* TIME_INFINITE means no timeout - wait forever for an event.
* TIME_IMMEDIATE means return immediately
- * @note The GEvent buffer is staticly allocated within the GListener so the event does not
- * need to be dynamicly freed however it will get overwritten by the next call to
- * this routine.
+ * @note The returned GEvent is released when this routine is called again
+ * or when optionally @p geventEventComplete() is called. Calling @p geventEventComplete()
+ * allows the GEvent object to be reused earlier which can reduce missed events. The GEvent
+ * object MUST NOT be used after this function is called (and is blocked waiting for the next
+ * event) or after geventEventComplete() is called.
*
* @param[in] pl The listener
* @param[in] timeout The timeout
@@ -160,6 +162,17 @@ void geventDetachSource(GListener *pl, GSourceHandle gsh);
*/
GEvent *geventEventWait(GListener *pl, delaytime_t timeout);
+/**
+ * @brief Release the GEvent buffer associated with a listener.
+ * @details The GEvent returned by @p geventEventWait() is released.
+ * @note The GEvent pointer returned by @p geventEventWait() is released when @p geventEventWait()
+ * is called again or when this function is called. The GEvent
+ * object MUST NOT be used after this function is called.
+ *
+ * @param[in] pl The listener
+ */
+void geventEventComplete(GListener *pl);
+
/* @brief Register a callback for an event on a listener from an assigned source.
* @details The type of the event should be checked (pevent->type) and then pevent should be typecast to the
* actual event type if it needs to be processed.
diff --git a/src/gfile/gfile.c b/src/gfile/gfile.c
index 6aadda09..caf7f22f 100644
--- a/src/gfile/gfile.c
+++ b/src/gfile/gfile.c
@@ -35,6 +35,11 @@ struct GFILE {
long int pos;
};
+struct gfileList {
+ const struct GFILEVMT * vmt;
+ bool_t dirs;
+};
+
typedef struct GFILEVMT {
const struct GFILEVMT * next;
uint8_t flags;
@@ -59,6 +64,11 @@ typedef struct GFILEVMT {
bool_t (*mount) (const char *drive);
bool_t (*unmount) (const char *drive);
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;
// The chain of FileSystems
@@ -70,6 +80,9 @@ GFILE *gfileStdIn;
GFILE *gfileStdOut;
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
* that they are searched to find a file.
@@ -119,6 +132,34 @@ GFILE *gfileStdErr;
#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
********************************************************/
@@ -251,39 +292,48 @@ bool_t gfileRename(const char *oldname, const char *newname) {
return FALSE;
}
-static uint16_t mode2flags(const char *mode) {
- uint16_t flags;
+static GFILE *findemptyfile(const char *mode) {
+ GFILE * f;
- 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) {
+ // First find an available GFILE slot.
+ for (f = gfileArr; f < &gfileArr[GFILE_MAX_GFILES]; f++) {
+ if (!(f->flags & GFILEFLG_OPEN)) {
+ // Get the flags
switch(mode[0]) {
- case '+': flags |= GFILEFLG_READ; break;
- case 'b': flags |= GFILEFLG_BINARY; break;
- case 'x': flags |= GFILEFLG_MUSTNOTEXIST; break;
+ case 'r':
+ 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;
}
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) {
- uint16_t flags;
GFILE * f;
const GFILEVMT *p;
- // Get the requested mode
- if (!(flags = mode2flags(mode)))
+ // Get an empty file and set the flags
+ if (!(f = findemptyfile(mode)))
return 0;
#if GFILE_ALLOW_DEVICESPECIFIC
if (fname[0] && fname[1] == '|') {
- // First find an available GFILE slot.
- for (f = gfileArr; f < &gfileArr[GFILE_MAX_GFILES]; f++) {
- if (!(f->flags & GFILEFLG_OPEN)) {
- // 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;
- }
+ for(p = FsChain; p; p = p->next) {
+ if (p->prefix == fname[0])
+ return testopen(p, f, fname+2) ? f : 0;
}
- // No available slot
+ // File not found
return 0;
}
#endif
- // First find an available GFILE slot.
- for (f = gfileArr; f < &gfileArr[GFILE_MAX_GFILES]; f++) {
- if (!(f->flags & GFILEFLG_OPEN)) {
-
- // 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;
- }
+ for(p = FsChain; p; p = p->next) {
+ if (testopen(p, f, fname))
+ return f;
}
- // No available slot
+ // File not found
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) {
if (!f || !(f->flags & GFILEFLG_OPEN))
return;
@@ -512,578 +484,34 @@ bool_t gfileSync(GFILE *f) {
return f->vmt->sync(f);
}
-/********************************************************
- * String VMT routines
- ********************************************************/
-#if GFILE_NEED_STRINGS && (GFILE_NEED_PRINTG || GFILE_NEED_SCANG)
- #include <string.h>
-
- // Special String VMT
- static int StringRead(GFILE *f, void *buf, int size) {
- (void) size;
-
- // 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
- };
-#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;
+#if GFILE_NEED_FILELISTS
+ gfileList *gfileOpenFileList(char fs, const char *path, bool_t dirs) {
+ const GFILEVMT *p;
+ gfileList * pfl;
- 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_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;
+ // Find the correct VMT
+ for(p = FsChain; p; p = p->next) {
+ if (p->prefix == fs) {
+ if (!p->flopen)
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;
- 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;
+ return 0;
}
- 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;
+ const char *gfileReadFileList(gfileList *pfl) {
+ return pfl->vmt->flread ? pfl->vmt->flread(pfl) : 0;
}
- #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;
+ void gfileCloseFileList(gfileList *pfl) {
+ if (pfl->vmt->flclose)
+ pfl->vmt->flclose(pfl);
}
#endif
diff --git a/src/gfile/inc_chibiosfs.c b/src/gfile/inc_chibiosfs.c
index 8d321b33..13ae6cac 100644
--- a/src/gfile/inc_chibiosfs.c
+++ b/src/gfile/inc_chibiosfs.c
@@ -27,22 +27,39 @@ static const GFILEVMT FsCHIBIOSVMT = {
0, 0, 0, 0,
0, ChibiOSBFSClose, ChibiOSBFSRead, ChibiOSBFSWrite,
ChibiOSBFSSetpos, ChibiOSBFSGetsize, ChibiOSBFSEof,
- 0, 0,
- 0
+ 0, 0, 0,
+ #if GFILE_NEED_FILELISTS
+ 0, 0, 0,
+ #endif
};
static void ChibiOSBFSClose(GFILE *f) {
- chFileStreamClose(((BaseFileStream *)f->fd));
+ chFileStreamClose(((BaseFileStream *)f->obj));
}
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) {
- 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) {
- chFileStreamSeek(((BaseFileStream *)f->fd), pos);
+ chFileStreamSeek(((BaseFileStream *)f->obj), pos);
return TRUE;
}
-static long int ChibiOSBFSGetsize(GFILE *f) { return chFileStreamGetSize(((BaseFileStream *)f->fd)); }
-static bool_t ChibiOSBFSEof(GFILE *f) { return f->pos >= 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->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;
+}
diff --git a/src/gfile/inc_fatfs.c b/src/gfile/inc_fatfs.c
index 8d7233e7..c8db0e64 100644
--- a/src/gfile/inc_fatfs.c
+++ b/src/gfile/inc_fatfs.c
@@ -30,6 +30,11 @@ static bool_t fatfsEOF(GFILE* f);
static bool_t fatfsMount(const char* drive);
static bool_t fatfsUnmount(const char* drive);
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 = {
GFILE_CHAINHEAD,
@@ -46,14 +51,29 @@ static const GFILEVMT FsFatFSVMT = {
fatfsSetPos,
fatfsGetSize,
fatfsEOF,
- fatfsMount,
- fatfsUnmount,
- fatfsSync
+ fatfsMount, fatfsUnmount, fatfsSync,
+ #if GFILE_NEED_FILELISTS
+ #if _FS_MINIMIZE <= 1
+ fatfsFlOpen, fatfsFlRead, fatfsFlClose
+ #else
+ 0, 0, 0
+ #endif
+ #endif
};
#undef GFILE_CHAINHEAD
#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
static bool_t fatfs_mounted = FALSE;
static FATFS fatfs_fs;
@@ -245,3 +265,58 @@ static bool_t fatfsSync(GFILE *f)
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
diff --git a/src/gfile/inc_memfs.c b/src/gfile/inc_memfs.c
index baeb0e97..6177b7d8 100644
--- a/src/gfile/inc_memfs.c
+++ b/src/gfile/inc_memfs.c
@@ -26,8 +26,10 @@ static const GFILEVMT FsMemVMT = {
0, 0, 0, 0,
0, 0, MEMRead, MEMWrite,
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) {
@@ -43,3 +45,18 @@ static bool_t MEMSetpos(GFILE *f, long int pos) {
(void) pos;
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;
+}
diff --git a/src/gfile/inc_nativefs.c b/src/gfile/inc_nativefs.c
index 6845cb71..8c28480b 100644
--- a/src/gfile/inc_nativefs.c
+++ b/src/gfile/inc_nativefs.c
@@ -33,6 +33,11 @@ static int NativeWrite(GFILE *f, const void *buf, int size);
static bool_t NativeSetpos(GFILE *f, long int pos);
static long int NativeGetsize(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 = {
GFILE_CHAINHEAD, // next
@@ -46,8 +51,10 @@ static const GFILEVMT FsNativeVMT = {
NativeDel, NativeExists, NativeFilesize, NativeRen,
NativeOpen, NativeClose, NativeRead, NativeWrite,
NativeSetpos, NativeGetsize, NativeEof,
- 0, 0,
- 0
+ 0, 0, 0,
+ #if GFILE_NEED_FILELISTS
+ NativeFlOpen, NativeFlRead, NativeFlClose
+ #endif
};
#undef GFILE_CHAINHEAD
#define GFILE_CHAINHEAD &FsNativeVMT
@@ -102,3 +109,108 @@ static long int NativeGetsize(GFILE *f) {
if (fstat(fileno((FILE *)f->obj), &st)) return -1;
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
diff --git a/src/gfile/inc_printg.c b/src/gfile/inc_printg.c
new file mode 100644
index 00000000..8d24b347
--- /dev/null
+++ b/src/gfile/inc_printg.c
@@ -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
diff --git a/src/gfile/inc_romfs.c b/src/gfile/inc_romfs.c
index 167430ce..97d26239 100644
--- a/src/gfile/inc_romfs.c
+++ b/src/gfile/inc_romfs.c
@@ -31,11 +31,15 @@ typedef struct ROMFS_DIRENTRY {
} ROMFS_DIRENTRY;
#define ROMFS_DIRENTRY_HEAD 0
-
#include "romfs_files.h"
-
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 long int ROMFilesize(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 long int ROMGetsize(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 = {
GFILE_CHAINHEAD, // next
@@ -52,8 +61,10 @@ static const GFILEVMT FsROMVMT = {
0, ROMExists, ROMFilesize, 0,
ROMOpen, ROMClose, ROMRead, 0,
ROMSetpos, ROMGetsize, ROMEof,
- 0, 0,
- 0
+ 0, 0, 0,
+ #if GFILE_NEED_FILELISTS
+ ROMFlOpen, ROMFlRead, ROMFlClose
+ #endif
};
#undef GFILE_CHAINHEAD
#define GFILE_CHAINHEAD &FsROMVMT
@@ -122,3 +133,45 @@ static bool_t ROMEof(GFILE *f)
{
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
diff --git a/src/gfile/inc_scang.c b/src/gfile/inc_scang.c
new file mode 100644
index 00000000..8dcc8d0f
--- /dev/null
+++ b/src/gfile/inc_scang.c
@@ -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
diff --git a/src/gfile/inc_stdio.c b/src/gfile/inc_stdio.c
new file mode 100644
index 00000000..8dc44dcb
--- /dev/null
+++ b/src/gfile/inc_stdio.c
@@ -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;
+}
diff --git a/src/gfile/inc_strings.c b/src/gfile/inc_strings.c
new file mode 100644
index 00000000..692d2dd3
--- /dev/null
+++ b/src/gfile/inc_strings.c
@@ -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;
+}
diff --git a/src/gfile/sys_defs.h b/src/gfile/sys_defs.h
index 0c5bac0c..81d72ac8 100644
--- a/src/gfile/sys_defs.h
+++ b/src/gfile/sys_defs.h
@@ -33,8 +33,10 @@
#ifndef GFILE_IMPLEMENTATION
typedef void GFILE;
+ typedef void gfileList;
#else
typedef struct GFILE GFILE;
+ typedef struct gfileList gfileList;
#endif
extern GFILE *gfileStdIn;
@@ -98,14 +100,33 @@ extern "C" {
/**
* @brief Open file
* @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.
*
* @param[in] fname The file name
- * @param[in] mode The mode
+ * @param[in] mode The mode.
*
* @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
*/
GFILE * gfileOpen(const char *fname, const char *mode);
@@ -239,15 +260,118 @@ extern "C" {
*/
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);
#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);
#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>
int vfnprintg(GFILE *f, int maxlen, const char *fmt, va_list arg);
@@ -265,7 +389,7 @@ extern "C" {
#endif
#endif
- #if GFILE_NEED_SCANG
+ #if GFILE_NEED_SCANG || defined(__DOXYGEN__)
#include <stdarg.h>
int vfscang(GFILE *f, const char *fmt, va_list arg);
diff --git a/src/gfile/sys_options.h b/src/gfile/sys_options.h
index ee52298c..ff1e5d4c 100644
--- a/src/gfile/sys_options.h
+++ b/src/gfile/sys_options.h
@@ -46,6 +46,7 @@
/**
* @brief Include printg, fprintg etc functions
* @details Defaults to FALSE
+ * @pre To get the string sprintg functions you also need to define @p GFILE_NEED_STRINGS
*/
#ifndef GFILE_NEED_PRINTG
#define GFILE_NEED_PRINTG FALSE
@@ -53,15 +54,14 @@
/**
* @brief Include scang, fscang etc functions
* @details Defaults to FALSE
+ * @pre To get the string sscang functions you also need to define @p GFILE_NEED_STRINGS
*/
#ifndef GFILE_NEED_SCANG
#define GFILE_NEED_SCANG FALSE
#endif
/**
- * @brief Include the string sprintg/sscang functions
+ * @brief Include the string based file functions
* @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
#define GFILE_NEED_STRINGS FALSE
@@ -146,6 +146,14 @@
#ifndef GFILE_NEED_MEMFS
#define GFILE_NEED_MEMFS FALSE
#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
/**
* @}
*
diff --git a/src/gos/chibios.c b/src/gos/gfx_chibios.c
index 468c012c..9d1a86da 100644
--- a/src/gos/chibios.c
+++ b/src/gos/gfx_chibios.c
@@ -33,18 +33,21 @@
void _gosInit(void)
{
- /* Don't initialise if the user already has */
-
- #if CH_KERNEL_MAJOR == 2
- if (!chThdSelf()) {
- halInit();
- chSysInit();
- }
- #elif CH_KERNEL_MAJOR == 3
- if (!chThdGetSelfX()) {
- halInit();
- chSysInit();
- }
+ #if !GFX_NO_OS_INIT
+ /* Don't Initialize if the user already has */
+ #if CH_KERNEL_MAJOR == 2
+ if (!chThdSelf()) {
+ halInit();
+ chSysInit();
+ }
+ #elif CH_KERNEL_MAJOR == 3
+ if (!chThdGetSelfX()) {
+ halInit();
+ chSysInit();
+ }
+ #endif
+ #else
+ #warning "GOS: Operating System initialization has been turned off. Make sure you call halInit() and chSysInit() before gfxInit() in your application!"
#endif
}
diff --git a/src/gos/chibios.h b/src/gos/gfx_chibios.h
index a07c72ab..a07c72ab 100644
--- a/src/gos/chibios.h
+++ b/src/gos/gfx_chibios.h
diff --git a/src/gos/ecos.c b/src/gos/gfx_ecos.c
index 5b94497a..16ce821b 100644
--- a/src/gos/ecos.c
+++ b/src/gos/gfx_ecos.c
@@ -11,8 +11,11 @@
void _gosInit(void)
{
- /* Don't initialise if the user already has */
- //cyg_scheduler_start();
+ #if !GFX_NO_OS_INIT
+ #error "GOS: Operating System initialization for eCos is not yet implemented in uGFX. Please set GFX_NO_OS_INIT to TRUE in your gfxconf.h"
+ #else
+ #warning "GOS: Operating System initialization has been turned off. Make sure you call cyg_scheduler_start() before gfxInit() in your application!"
+ #endif
}
void _gosDeinit(void)
diff --git a/src/gos/ecos.h b/src/gos/gfx_ecos.h
index be9037b6..be9037b6 100644
--- a/src/gos/ecos.h
+++ b/src/gos/gfx_ecos.h
diff --git a/src/gos/freertos.c b/src/gos/gfx_freertos.c
index f2c03eec..dbdfd22e 100644
--- a/src/gos/freertos.c
+++ b/src/gos/gfx_freertos.c
@@ -18,13 +18,17 @@
#error "GOS: configUSE_MUTEXES must be defined in FreeRTOSConfig.h"
#endif
-#if configUSE_COUNTING_SEMAPHORES != 1
+#if configUSE_COUNTING_SEMAPHORES != 1
#error "GOS: configUSE_COUNTING_SEMAPHORES must be defined in FreeRTOSConfig.h"
#endif
void _gosInit(void)
{
- // The user must call vTaskStartScheduler() himself before he calls gfxInit().
+ #if !GFX_NO_OS_INIT
+ #error "GOS: Operating System initialization for FreeRTOS is not yet implemented in uGFX. Please set GFX_NO_OS_INIT to TRUE in your gfxconf.h"
+ #else
+ #warning "GOS: Operating System initialization has been turned off. Make sure you call vTaskStartScheduler() before gfxInit() in your application!"
+ #endif
}
void _gosDeinit(void)
diff --git a/src/gos/freertos.h b/src/gos/gfx_freertos.h
index ccda4cbd..34ef548e 100644
--- a/src/gos/freertos.h
+++ b/src/gos/gfx_freertos.h
@@ -24,6 +24,18 @@
/* Type definitions */
/*===========================================================================*/
+/* Additional types are required when FreeRTOS 7.x is used */
+#if !defined(tskKERNEL_VERSION_MAJOR) && !tskKERNEL_VERSION_MAJOR == 8
+ typedef signed char int8_t
+ typedef unsigned char uint8_t
+ typedef signed int int16_t
+ typedef unsigned int uint16_t
+ typedef signed long int int32_t
+ typedef unsigned long int uint32_t
+ typedef signed long long int int64_t
+ typedef unsigned long long int uint64_t
+#endif
+
/**
* bool_t,
* int8_t, uint8_t,
diff --git a/src/gos/linux.c b/src/gos/gfx_linux.c
index d127fbe1..59b7f9c8 100644
--- a/src/gos/linux.c
+++ b/src/gos/gfx_linux.c
@@ -18,6 +18,7 @@ static gfxMutex SystemMutex;
void _gosInit(void)
{
+ /* No initialization of the operating system itself is needed */
gfxMutexInit(&SystemMutex);
}
diff --git a/src/gos/linux.h b/src/gos/gfx_linux.h
index 9ead9c0e..9ead9c0e 100644
--- a/src/gos/linux.h
+++ b/src/gos/gfx_linux.h
diff --git a/src/gos/osx.c b/src/gos/gfx_osx.c
index dccd49c9..50b06530 100644
--- a/src/gos/osx.c
+++ b/src/gos/gfx_osx.c
@@ -35,6 +35,7 @@ void get_ticks(mach_timespec_t *mts){
void _gosInit(void)
{
+ /* No initialization of the operating system itself is needed */
gfxMutexInit(&SystemMutex);
}
diff --git a/src/gos/osx.h b/src/gos/gfx_osx.h
index 635a8934..635a8934 100644
--- a/src/gos/osx.h
+++ b/src/gos/gfx_osx.h
diff --git a/src/gos/raw32.c b/src/gos/gfx_raw32.c
index c75342d4..22c753aa 100644
--- a/src/gos/raw32.c
+++ b/src/gos/gfx_raw32.c
@@ -24,6 +24,12 @@ static void _gosThreadsInit(void);
void _gosInit(void)
{
+ /* No initialization of the operating system itself is needed as there isn't one.
+ * On the other hand the C runtime should still already be initialized before
+ * getting here!
+ */
+ #warning "GOS: Raw32 - Make sure you initialize your hardware and the C runtime before calling gfxInit() in your application!"
+
// Set up the heap allocator
_gosHeapInit();
diff --git a/src/gos/raw32.h b/src/gos/gfx_raw32.h
index 6eb5f26e..5a6a2aa7 100644
--- a/src/gos/raw32.h
+++ b/src/gos/gfx_raw32.h
@@ -42,14 +42,20 @@
/*===========================================================================*/
typedef unsigned char bool_t;
-typedef char int8_t;
-typedef unsigned char uint8_t;
-typedef short int16_t;
-typedef unsigned short uint16_t;
-typedef int int32_t;
-typedef unsigned int uint32_t;
-
-typedef uint32_t size_t;
+
+#ifndef _STDINT_H
+ typedef char int8_t;
+ typedef unsigned char uint8_t;
+ typedef short int16_t;
+ typedef unsigned short uint16_t;
+ typedef int int32_t;
+ typedef unsigned int uint32_t;
+#endif
+
+#if !defined (__need_size_t) && !defined (_STDDEF_H_)
+ typedef uint32_t size_t;
+#endif
+
typedef uint32_t delaytime_t;
typedef uint32_t systemticks_t;
typedef short semcount_t;
diff --git a/src/gos/gfx_rawrtos.c b/src/gos/gfx_rawrtos.c
new file mode 100644
index 00000000..cd684208
--- /dev/null
+++ b/src/gos/gfx_rawrtos.c
@@ -0,0 +1,83 @@
+#include "gfx.h"
+
+#if GFX_USE_OS_RAWRTOS
+
+#include <string.h>
+#include "raw_api.h"
+#include "raw_config.h"
+
+#if CONFIG_RAW_MUTEX != 1
+ #error "GOS: CONFIG_RAW_MUTEX must be defined in raw_config.h"
+#endif
+
+#if CONFIG_RAW_SEMAPHORE != 1
+ #error "GOS: CONFIG_RAW_SEMAPHORE must be defined in raw_config.h"
+#endif
+
+
+void _gosInit(void)
+{
+ #if !GFX_NO_OS_INIT
+ #error "GOS: Operating System initialization for RawRTOS is not yet implemented in uGFX. Please set GFX_NO_OS_INIT to TRUE in your gfxconf.h"
+ #else
+ #warning "GOS: Operating System initialization has been turned off. Make sure you call raw_os_start() before gfxInit() in your application!"
+ #endif
+}
+
+void _gosDeinit(void)
+{
+}
+
+
+void gfxSleepMilliseconds(delaytime_t ms)
+{
+ systemticks_t ticks = ms*RAW_TICKS_PER_SECOND/1000;
+ if(!ticks)ticks = 1;
+ raw_sleep(ticks);
+}
+
+void gfxSleepMicroseconds(delaytime_t us)
+{
+ systemticks_t ticks = (us/1000)*RAW_TICKS_PER_SECOND/1000;
+ if(!ticks)ticks = 1;
+ raw_sleep(ticks);
+}
+
+bool_t gfxSemWait(gfxSem* psem, delaytime_t ms)
+{
+ systemticks_t ticks = ms*RAW_TICKS_PER_SECOND/1000;
+ if(!ticks)ticks=1;
+ if(raw_semaphore_get((psem), ticks)==RAW_SUCCESS)
+ return TRUE;
+ return FALSE;
+}
+
+bool_t gfxSemWaitI(gfxSem* psem)
+{
+ if(raw_semaphore_get((psem), TIME_IMMEDIATE)==RAW_SUCCESS)
+ return TRUE;
+ return FALSE;
+}
+
+gfxThreadHandle gfxThreadCreate(void *stackarea, size_t stacksz, threadpriority_t prio, DECLARE_THREAD_FUNCTION((*fn),p), void *param)
+{
+ RAW_U16 ret;
+ gfxThreadHandle taskobj;
+
+ taskobj = gfxAlloc(sizeof(RAW_TASK_OBJ));
+ ret = raw_task_create(taskobj, (RAW_U8 *)"uGFX_TASK", param,
+ prio, 0, stackarea,
+ stacksz/sizeof(PORT_STACK) , fn, 1);
+
+ if (ret != RAW_SUCCESS) {
+ for (;;);
+ }
+
+ return (taskobj);
+}
+
+
+#endif
+
+
+
diff --git a/src/gos/gfx_rawrtos.h b/src/gos/gfx_rawrtos.h
new file mode 100644
index 00000000..eeb5119d
--- /dev/null
+++ b/src/gos/gfx_rawrtos.h
@@ -0,0 +1,77 @@
+#ifndef _GOS_RAWRTOS_H
+#define _GOS_RAWRTOS_H
+
+#if GFX_USE_OS_RAWRTOS
+
+#include "raw_api.h"
+#include <stdint.h>
+
+#define TIME_IMMEDIATE (RAW_NO_WAIT)
+#define TIME_INFINITE (RAW_WAIT_FOREVER)
+typedef int8_t bool_t;
+typedef uint32_t delaytime_t;
+typedef RAW_TICK_TYPE systemticks_t;
+typedef int32_t semcount_t;
+typedef uint32_t threadreturn_t;
+typedef RAW_U8 threadpriority_t;
+typedef uint32_t size_t;
+
+#define MAX_SEMAPHORE_COUNT RAW_SEMAPHORE_COUNT
+#define LOW_PRIORITY (CONFIG_RAW_PRIO_MAX-2)
+#define NORMAL_PRIORITY (CONFIG_RAW_PRIO_MAX/2)
+#define HIGH_PRIORITY 1
+
+typedef RAW_SEMAPHORE gfxSem;
+typedef RAW_MUTEX gfxMutex;
+typedef RAW_TASK_OBJ* gfxThreadHandle;
+
+#define DECLARE_THREAD_FUNCTION(fnName, param) threadreturn_t fnName(void *param)
+#define DECLARE_THREAD_STACK(name, sz) PORT_STACK name[sz];
+
+#define gfxHalt(msg) for(;;)
+#define gfxExit() for(;;)
+#define gfxAlloc(sz) raw_malloc(sz)
+#define gfxRealloc(p,osz,nsz) raw_calloc(p, nsz)
+#define gfxFree(ptr) raw_free(ptr)
+#define gfxYield() raw_sleep(0)
+#define gfxSystemTicks() raw_system_time_get()
+#define gfxMillisecondsToTicks(ms) (ms*RAW_TICKS_PER_SECOND/1000)
+#define gfxSystemLock() {}
+#define gfxSystemUnlock() {}
+#define gfxMutexInit(pmutex) raw_mutex_create(pmutex, (RAW_U8 *)"", RAW_MUTEX_INHERIT_POLICY, 3)
+#define gfxMutexDestroy(pmutex) raw_mutex_delete(pmutex)
+#define gfxMutexEnter(pmutex) raw_mutex_get(pmutex, TIME_INFINITE)
+#define gfxMutexExit(pmutex) raw_mutex_put(pmutex)
+#define gfxSemInit(psem, val, limit) raw_semaphore_create(psem, "", val)
+#define gfxSemDestroy(psem) raw_semaphore_delete(psem)
+#define gfxSemSignal(psem) raw_semaphore_put((psem))
+#define gfxSemSignalI(psem) raw_semaphore_put_all((psem))
+#define gfxSemCounterI(psem) ((psem)->count)
+#define gfxThreadMe() {(unsigned int)raw_task_identify()}
+#define gfxThreadClose(thread) {}
+
+extern RAW_VOID *raw_malloc(RAW_U32 size);
+extern RAW_VOID raw_free(void *ptr);
+extern RAW_VOID *raw_calloc(RAW_U32 nmemb, RAW_U32 size);
+
+extern RAW_U16 raw_sleep(RAW_TICK_TYPE dly);
+extern RAW_TICK_TYPE raw_system_time_get(void);
+
+extern RAW_U16 raw_mutex_create(RAW_MUTEX *mutex_ptr, RAW_U8 *name_ptr, RAW_U8 policy, RAW_U8 ceiling_prio);
+extern RAW_U16 raw_mutex_delete(RAW_MUTEX *mutex_ptr);
+extern RAW_U16 raw_mutex_get(RAW_MUTEX *mutex_ptr, RAW_TICK_TYPE wait_option);
+extern RAW_U16 raw_mutex_put(RAW_MUTEX *mutex_ptr);
+extern RAW_U16 raw_semaphore_create(RAW_SEMAPHORE *semaphore_ptr, RAW_U8 *name_ptr, RAW_U32 initial_count);
+extern RAW_U16 raw_semaphore_delete(RAW_SEMAPHORE *semaphore_ptr);
+extern RAW_U16 raw_semaphore_get(RAW_SEMAPHORE *semaphore_ptr, RAW_TICK_TYPE wait_option);
+extern RAW_U16 raw_semaphore_put(RAW_SEMAPHORE *semaphore_ptr);
+
+void gfxSleepMilliseconds(delaytime_t ms);
+void gfxSleepMicroseconds(delaytime_t us);
+bool_t gfxSemWait(gfxSem* psem, delaytime_t ms);
+bool_t gfxSemWaitI(gfxSem* psem);
+gfxThreadHandle gfxThreadCreate(void *stackarea, size_t stacksz, threadpriority_t prio, DECLARE_THREAD_FUNCTION((*fn),p), void *param);
+
+#endif
+
+#endif
diff --git a/src/gos/win32.c b/src/gos/gfx_win32.c
index 3a3f2517..ffa7fac5 100644
--- a/src/gos/win32.c
+++ b/src/gos/gfx_win32.c
@@ -19,7 +19,7 @@ static HANDLE SystemMutex;
void _gosInit(void)
{
-
+ /* No initialization of the operating system itself is needed */
}
void _gosDeinit(void)
diff --git a/src/gos/win32.h b/src/gos/gfx_win32.h
index 4a198200..4a198200 100644
--- a/src/gos/win32.h
+++ b/src/gos/gfx_win32.h
diff --git a/src/gos/sys_defs.h b/src/gos/sys_defs.h
index 9da9dff0..d116826f 100644
--- a/src/gos/sys_defs.h
+++ b/src/gos/sys_defs.h
@@ -439,20 +439,22 @@
* All the above was just for the doxygen documentation. All the implementation of the above
* (without any of the documentation overheads) is in the files below.
*/
+#elif GFX_USE_OS_RAWRTOS
+ #include "src/gos/gfx_rawrtos.h"
#elif GFX_USE_OS_CHIBIOS
- #include "src/gos/chibios.h"
+ #include "src/gos/gfx_chibios.h"
#elif GFX_USE_OS_FREERTOS
- #include "src/gos/freertos.h"
+ #include "src/gos/gfx_freertos.h"
#elif GFX_USE_OS_WIN32
- #include "src/gos/win32.h"
+ #include "src/gos/gfx_win32.h"
#elif GFX_USE_OS_LINUX
- #include "src/gos/linux.h"
+ #include "src/gos/gfx_linux.h"
#elif GFX_USE_OS_OSX
- #include "src/gos/osx.h"
+ #include "src/gos/gfx_osx.h"
#elif GFX_USE_OS_RAW32
- #include "src/gos/raw32.h"
+ #include "src/gos/gfx_raw32.h"
#elif GFX_USE_OS_ECOS
- #include "src/gos/ecos.h"
+ #include "src/gos/gfx_ecos.h"
#else
#error "Your operating system is not supported yet"
#endif
diff --git a/src/gos/sys_make.mk b/src/gos/sys_make.mk
index 9e24f875..5efa7f80 100644
--- a/src/gos/sys_make.mk
+++ b/src/gos/sys_make.mk
@@ -1,8 +1,9 @@
-GFXSRC += $(GFXLIB)/src/gos/chibios.c \
- $(GFXLIB)/src/gos/freertos.c \
- $(GFXLIB)/src/gos/win32.c \
- $(GFXLIB)/src/gos/linux.c \
- $(GFXLIB)/src/gos/osx.c \
- $(GFXLIB)/src/gos/raw32.c \
- $(GFXLIB)/src/gos/ecos.c
+GFXSRC += $(GFXLIB)/src/gos/gfx_chibios.c \
+ $(GFXLIB)/src/gos/gfx_freertos.c \
+ $(GFXLIB)/src/gos/gfx_win32.c \
+ $(GFXLIB)/src/gos/gfx_linux.c \
+ $(GFXLIB)/src/gos/gfx_osx.c \
+ $(GFXLIB)/src/gos/gfx_raw32.c \
+ $(GFXLIB)/src/gos/gfx_ecos.c \
+ $(GFXLIB)/src/gos/gfx_rawrtos.c
diff --git a/src/gos/sys_options.h b/src/gos/sys_options.h
index 7937e082..ead1f3f7 100644
--- a/src/gos/sys_options.h
+++ b/src/gos/sys_options.h
@@ -76,6 +76,20 @@
* @{
*/
/**
+ * @brief Should uGFX avoid initializing the operating system
+ * @details Defaults to FALSE
+ * @note This is not relevant to all operating systems eg Win32 never initializes the
+ * operating system as uGFX runs as an application outside the boot process.
+ * @note Operating system initialization is not necessarily implemented for all
+ * operating systems yet even when it is relevant. These operating systems
+ * will display a compile warning reminding you to initialize the operating
+ * system in your application code. Note that on these operating systems the
+ * demo applications will not work without modification.
+ */
+ #ifndef GFX_NO_OS_INIT
+ #define GFX_NO_OS_INIT FALSE
+ #endif
+ /**
* @brief Should uGFX stuff be added to the FreeRTOS+Tracer
* @details Defaults to FALSE
*/
diff --git a/src/gos/sys_rules.h b/src/gos/sys_rules.h
index 0da01ff2..6d6c7845 100644
--- a/src/gos/sys_rules.h
+++ b/src/gos/sys_rules.h
@@ -16,7 +16,7 @@
#ifndef _GOS_RULES_H
#define _GOS_RULES_H
-#if !GFX_USE_OS_CHIBIOS && !GFX_USE_OS_WIN32 && !GFX_USE_OS_LINUX && !GFX_USE_OS_OSX && !GFX_USE_OS_RAW32 && !GFX_USE_OS_FREERTOS && !GFX_USE_OS_ECOS
+#if !GFX_USE_OS_CHIBIOS && !GFX_USE_OS_WIN32 && !GFX_USE_OS_LINUX && !GFX_USE_OS_OSX && !GFX_USE_OS_RAW32 && !GFX_USE_OS_FREERTOS && !GFX_USE_OS_ECOS && !GFX_USE_OS_RAWRTOS
#if GFX_DISPLAY_RULE_WARNINGS
#warning "GOS: No Operating System has been defined. ChibiOS (GFX_USE_OS_CHIBIOS) has been turned on for you."
#endif
@@ -24,7 +24,7 @@
#define GFX_USE_OS_CHIBIOS TRUE
#endif
-#if GFX_USE_OS_CHIBIOS + GFX_USE_OS_WIN32 + GFX_USE_OS_LINUX + GFX_USE_OS_OSX + GFX_USE_OS_RAW32 + GFX_USE_OS_FREERTOS + GFX_USE_OS_ECOS != 1 * TRUE
+#if GFX_USE_OS_CHIBIOS + GFX_USE_OS_WIN32 + GFX_USE_OS_LINUX + GFX_USE_OS_OSX + GFX_USE_OS_RAW32 + GFX_USE_OS_FREERTOS + GFX_USE_OS_ECOS + GFX_USE_OS_RAWRTOS != 1 * TRUE
#error "GOS: More than one operation system has been defined as TRUE."
#endif
diff --git a/src/gwin/button.c b/src/gwin/button.c
index d489ecb0..fc1cb976 100644
--- a/src/gwin/button.c
+++ b/src/gwin/button.c
@@ -39,6 +39,9 @@ static void SendButtonEvent(GWidgetObject *gw) {
continue;
pbe->type = GEVENT_GWIN_BUTTON;
pbe->button = (GHandle)gw;
+ #if GWIN_WIDGET_TAGS
+ pbe->tag = gw->tag;
+ #endif
geventSendEvent(psl);
}
diff --git a/src/gwin/button.h b/src/gwin/button.h
index 73d5f9f1..077b50f4 100644
--- a/src/gwin/button.h
+++ b/src/gwin/button.h
@@ -38,6 +38,9 @@
typedef struct GEventGWinButton {
GEventType type; // The type of this event (GEVENT_GWIN_BUTTON)
GHandle button; // The button that has been depressed (actually triggered on release)
+ #if GWIN_WIDGET_TAGS
+ WidgetTag tag; // The button tag
+ #endif
} GEventGWinButton;
/**
diff --git a/src/gwin/checkbox.c b/src/gwin/checkbox.c
index f162d8fc..7914ee82 100644
--- a/src/gwin/checkbox.c
+++ b/src/gwin/checkbox.c
@@ -33,6 +33,9 @@ static void SendCheckboxEvent(GWidgetObject *gw) {
pce->type = GEVENT_GWIN_CHECKBOX;
pce->checkbox = &gw->g;
pce->isChecked = (gw->g.flags & GCHECKBOX_FLG_CHECKED) ? TRUE : FALSE;
+ #if GWIN_WIDGET_TAGS
+ pce->tag = gw->tag;
+ #endif
geventSendEvent(psl);
}
diff --git a/src/gwin/checkbox.h b/src/gwin/checkbox.h
index 2b1fb801..ebd35a0b 100644
--- a/src/gwin/checkbox.h
+++ b/src/gwin/checkbox.h
@@ -38,6 +38,9 @@ typedef struct GEventGWinCheckbox {
GEventType type; // The type of this event (GEVENT_GWIN_CHECKBOX)
GHandle checkbox; // The checkbox that has been depressed (actually triggered on release)
bool_t isChecked; // Is the checkbox currently checked or unchecked?
+ #if GWIN_WIDGET_TAGS
+ WidgetTag tag; // The checkbox tag
+ #endif
} GEventGWinCheckbox;
/* A Checkbox window */
diff --git a/src/gwin/class_gwin.h b/src/gwin/class_gwin.h
index 995121b7..b32e4da2 100644
--- a/src/gwin/class_gwin.h
+++ b/src/gwin/class_gwin.h
@@ -23,6 +23,10 @@
#if GFX_USE_GWIN || defined(__DOXYGEN__)
+#if defined(__KEIL__) || defined(__C51__)
+ #pragma anon_unions
+#endif
+
/**
* @brief The predefined flags for a Window
* @{
diff --git a/src/gwin/frame.c b/src/gwin/frame.c
index c10aaea3..3f41c69f 100644
--- a/src/gwin/frame.c
+++ b/src/gwin/frame.c
@@ -38,8 +38,10 @@ static coord_t BorderSizeT(GHandle gh) { return (gh->flags & GWIN_FRAME_BORDER)
static void _frameDestroy(GHandle gh) {
/* Deregister the button callback */
- geventRegisterCallback(&gh2obj->gl, NULL, NULL);
- geventDetachSource(&gh2obj->gl, NULL);
+ if ((gh->flags & (GWIN_FRAME_CLOSE_BTN|GWIN_FRAME_MINMAX_BTN))) {
+ geventRegisterCallback(&gh2obj->gl, NULL, NULL);
+ geventDetachSource(&gh2obj->gl, NULL);
+ }
/* call the gcontainer standard destroy routine */
_gcontainerDestroy(gh);
diff --git a/src/gwin/gcontainer.c b/src/gwin/gcontainer.c
index 46e89032..2d711ffd 100644
--- a/src/gwin/gcontainer.c
+++ b/src/gwin/gcontainer.c
@@ -93,11 +93,14 @@ coord_t gwinGetInnerHeight(GHandle gh) {
static coord_t BorderSize(GHandle gh) { return (gh->flags & GWIN_CONTAINER_BORDER) ? 2 : 0; }
static void DrawSimpleContainer(GWidgetObject *gw, void *param) {
- (void) param;
- gdispGFillArea(gw->g.display, gw->g.x, gw->g.y, gw->g.width, gw->g.height, gw->pstyle->background);
- if ((gw->g.flags & GWIN_CONTAINER_BORDER))
- gdispGDrawBox(gw->g.display, gw->g.x, gw->g.y, gw->g.width, gw->g.height, (gw->g.flags & GWIN_FLG_SYSENABLED) ? gw->pstyle->enabled.edge : gw->pstyle->disabled.edge);
-}
+ (void)param;
+
+ if (!(gw->g.flags & GWIN_CONTAINER_TRANSPARENT))
+ gdispGFillArea(gw->g.display, gw->g.x, gw->g.y, gw->g.width, gw->g.height, gw->pstyle->background);
+
+ if ((gw->g.flags & GWIN_CONTAINER_BORDER))
+ gdispGDrawBox(gw->g.display, gw->g.x, gw->g.y, gw->g.width, gw->g.height, (gw->g.flags & GWIN_FLG_SYSENABLED) ? gw->pstyle->enabled.edge : gw->pstyle->disabled.edge);
+}
// The container VMT table
static const gcontainerVMT containerVMT = {
diff --git a/src/gwin/gcontainer.h b/src/gwin/gcontainer.h
index efba83f9..942cf8c0 100644
--- a/src/gwin/gcontainer.h
+++ b/src/gwin/gcontainer.h
@@ -105,6 +105,7 @@ extern "C" {
* @{
*/
#define GWIN_CONTAINER_BORDER 0x00000001
+ #define GWIN_CONTAINER_TRANSPARENT 0x00000002
/** @} */
/**
diff --git a/src/gwin/gwidget.c b/src/gwin/gwidget.c
index 8ccb47fc..c9fff50e 100644
--- a/src/gwin/gwidget.c
+++ b/src/gwin/gwidget.c
@@ -86,6 +86,7 @@ static void gwidgetEvent(void *param, GEvent *pe) {
#define pte ((GEventToggle *)pe)
#define pde ((GEventDial *)pe)
+ GHandle h;
GHandle gh;
#if GFX_USE_GINPUT && (GINPUT_NEED_TOGGLE || GINPUT_NEED_DIAL)
uint16_t role;
@@ -99,32 +100,38 @@ static void gwidgetEvent(void *param, GEvent *pe) {
case GEVENT_MOUSE:
case GEVENT_TOUCH:
// Cycle through all windows
- for(gh = gwinGetNextWindow(0); gh; gh = gwinGetNextWindow(gh)) {
-
- // check if the widget matches this display
- if (gh->display != pme->display)
- continue;
+ for(gh = 0, h = gwinGetNextWindow(0); h; h = gwinGetNextWindow(h)) {
- // check if it is a widget that is enabled and visible
- if ((gh->flags & (GWIN_FLG_WIDGET|GWIN_FLG_SYSENABLED|GWIN_FLG_SYSVISIBLE)) != (GWIN_FLG_WIDGET|GWIN_FLG_SYSENABLED|GWIN_FLG_SYSVISIBLE))
+ // The window must be on this display and visible to be relevant
+ if (h->display != pme->display || !(h->flags & GWIN_FLG_SYSVISIBLE))
continue;
- // Are we captured?
- if ((gw->g.flags & GWIN_FLG_MOUSECAPTURE)) {
+ // Is the mouse currently captured by this widget?
+ if ((h->flags & (GWIN_FLG_WIDGET|GWIN_FLG_MOUSECAPTURE)) == (GWIN_FLG_WIDGET|GWIN_FLG_MOUSECAPTURE)) {
+ gh = h;
if ((pme->last_buttons & ~pme->current_buttons & GINPUT_MOUSE_BTN_LEFT)) {
- gw->g.flags &= ~GWIN_FLG_MOUSECAPTURE;
+ gh->flags &= ~GWIN_FLG_MOUSECAPTURE;
if (wvmt->MouseUp)
- wvmt->MouseUp(gw, pme->x - gw->g.x, pme->y - gw->g.y);
+ wvmt->MouseUp(gw, pme->x - gh->x, pme->y - gh->y);
} else if (wvmt->MouseMove)
- wvmt->MouseMove(gw, pme->x - gw->g.x, pme->y - gw->g.y);
+ wvmt->MouseMove(gw, pme->x - gh->x, pme->y - gh->y);
+
+ // There is only ever one captured mouse. Prevent normal mouse processing if there is a captured mouse
+ gh = 0;
+ break;
+ }
+
+ // Save the highest z-order window that the mouse is over
+ if (pme->x >= h->x && pme->x < h->x + h->width && pme->y >= h->y && pme->y < h->y + h->height)
+ gh = h;
+ }
- // We are not captured - look for mouse downs over the widget
- } else if ((~pme->last_buttons & pme->current_buttons & GINPUT_MOUSE_BTN_LEFT)
- && pme->x >= gw->g.x && pme->x < gw->g.x + gw->g.width
- && pme->y >= gw->g.y && pme->y < gw->g.y + gw->g.height) {
- gw->g.flags |= GWIN_FLG_MOUSECAPTURE;
+ // Process any mouse down over the highest order window if it is an enabled widget
+ if (gh && (gh->flags & (GWIN_FLG_WIDGET|GWIN_FLG_SYSENABLED)) == (GWIN_FLG_WIDGET|GWIN_FLG_SYSENABLED)) {
+ if ((~pme->last_buttons & pme->current_buttons & GINPUT_MOUSE_BTN_LEFT)) {
+ gh->flags |= GWIN_FLG_MOUSECAPTURE;
if (wvmt->MouseDown)
- wvmt->MouseDown(gw, pme->x - gw->g.x, pme->y - gw->g.y);
+ wvmt->MouseDown(gw, pme->x - gh->x, pme->y - gh->y);
}
}
break;
@@ -242,6 +249,9 @@ GHandle _gwidgetCreate(GDisplay *g, GWidgetObject *pgw, const GWidgetInit *pInit
pgw->fnDraw = pInit->customDraw ? pInit->customDraw : vmt->DefaultDraw;
pgw->fnParam = pInit->customParam;
pgw->pstyle = pInit->customStyle ? pInit->customStyle : defaultStyle;
+ #if GWIN_WIDGET_TAGS
+ pgw->tag = pInit->tag;
+ #endif
return &pgw->g;
}
@@ -473,5 +483,16 @@ bool_t gwinAttachListener(GListener *pl) {
}
#endif
+#if GWIN_WIDGET_TAGS
+ void gwinSetTag(GHandle gh, WidgetTag tag) {
+ if ((gh->flags & GWIN_FLG_WIDGET))
+ gw->tag = tag;
+ }
+
+ WidgetTag gwinGetTag(GHandle gh) {
+ return ((gh->flags & GWIN_FLG_WIDGET)) ? gw->tag : 0;
+ }
+#endif
+
#endif /* GFX_USE_GWIN && GWIN_NEED_WIDGET */
/** @} */
diff --git a/src/gwin/gwidget.h b/src/gwin/gwidget.h
index 0a7bc72f..bd1ea4c8 100644
--- a/src/gwin/gwidget.h
+++ b/src/gwin/gwidget.h
@@ -73,6 +73,11 @@ extern const GWidgetStyle WhiteWidgetStyle;
typedef void (*CustomWidgetDrawFunction)(struct GWidgetObject *gw, void *param);
/**
+ * @brief Defines a the type of a tag on a widget
+ */
+typedef uint16_t WidgetTag;
+
+/**
* @brief The structure to initialise a widget.
*
* @note Some widgets may have extra parameters.
@@ -92,6 +97,9 @@ typedef struct GWidgetInit {
CustomWidgetDrawFunction customDraw; // @< A custom draw function - use NULL for the standard
void * customParam; // @< A parameter for the custom draw function (default = NULL)
const GWidgetStyle * customStyle; // @< A custom style to use - use NULL for the default style
+ #if GWIN_WIDGET_TAGS || defined(__DOXYGEN__)
+ WidgetTag tag; // @< The tag to associate with the widget
+ #endif
} GWidgetInit;
/** @} */
@@ -110,6 +118,9 @@ typedef struct GWidgetObject {
CustomWidgetDrawFunction fnDraw; // @< The current draw function
void * fnParam; // @< A parameter for the current draw function
const GWidgetStyle * pstyle; // @< The current widget style colors
+ #if GWIN_WIDGET_TAGS || defined(__DOXYGEN__)
+ WidgetTag tag; // @< The widget tag
+ #endif
} GWidgetObject;
/** @} */
@@ -187,6 +198,34 @@ void gwinSetText(GHandle gh, const char *text, bool_t useAlloc);
*/
const char *gwinGetText(GHandle gh);
+#if GWIN_WIDGET_TAGS || defined(__DOXYGEN__)
+ /**
+ * @brief Set the tag of a widget.
+ *
+ * @param[in] gh The widget handle
+ * @param[in] tag The tag to set.
+ *
+ * @note Non-widgets will ignore this call.
+ *
+ * @pre Requires GWIN_WIDGET_TAGS to be TRUE
+ *
+ * @api
+ */
+ void gwinSetTag(GHandle gh, WidgetTag tag);
+
+ /**
+ * @brief Get the tag of a widget.
+ * @return The widget tag value (or 0 if it is not a widget)
+ *
+ * @param[in] gh The widget handle
+ *
+ * @pre Requires GWIN_WIDGET_TAGS to be TRUE
+ *
+ * @api
+ */
+ WidgetTag gwinGetTag(GHandle gh);
+#endif
+
/**
* @brief Set the style of a widget.
*
@@ -235,7 +274,7 @@ void gwinSetCustomDraw(GHandle gh, CustomWidgetDrawFunction fn, void *param);
*/
bool_t gwinAttachListener(GListener *pl);
-#if GFX_USE_GINPUT && GINPUT_NEED_MOUSE
+#if (GFX_USE_GINPUT && GINPUT_NEED_MOUSE) || defined(__DOXYGEN__)
/**
* @brief Set the mouse to be used to control the widgets
* @return TRUE on success
@@ -249,7 +288,7 @@ bool_t gwinAttachListener(GListener *pl);
bool_t gwinAttachMouse(uint16_t instance);
#endif
-#if GFX_USE_GINPUT && GINPUT_NEED_TOGGLE
+#if (GFX_USE_GINPUT && GINPUT_NEED_TOGGLE) || defined(__DOXYGEN__)
/**
* @brief Attach a toggle to a widget
* @return TRUE on success
@@ -267,7 +306,7 @@ bool_t gwinAttachListener(GListener *pl);
bool_t gwinAttachToggle(GHandle gh, uint16_t role, uint16_t instance);
#endif
-#if GFX_USE_GINPUT && GINPUT_NEED_DIAL
+#if (GFX_USE_GINPUT && GINPUT_NEED_DIAL) || defined(__DOXYGEN__)
/**
* @brief Attach a toggle to a widget
* @return TRUE on success
diff --git a/src/gwin/list.c b/src/gwin/list.c
index c2a857e3..98ec2ed5 100644
--- a/src/gwin/list.c
+++ b/src/gwin/list.c
@@ -66,6 +66,9 @@ static void sendListEvent(GWidgetObject *gw, int item) {
ple->type = GEVENT_GWIN_LIST;
ple->list = (GHandle)gw;
ple->item = item;
+ #if GWIN_WIDGET_TAGS
+ ple->tag = gw->tag;
+ #endif
geventSendEvent(psl);
}
diff --git a/src/gwin/list.h b/src/gwin/list.h
index 9e31bf2a..1eae3c19 100644
--- a/src/gwin/list.h
+++ b/src/gwin/list.h
@@ -40,6 +40,9 @@ typedef struct GEventGWinList {
GEventType type; // The type of this event (GEVENT_GWIN_LIST)
GHandle list; // The list
int item; // The item that has been selected (or unselected in a multi-select listbox)
+ #if GWIN_WIDGET_TAGS
+ WidgetTag tag; // The list tag
+ #endif
} GEventGWinList;
// A list window
diff --git a/src/gwin/radio.c b/src/gwin/radio.c
index af7b877d..557061e4 100644
--- a/src/gwin/radio.c
+++ b/src/gwin/radio.c
@@ -38,6 +38,9 @@ static void SendRadioEvent(GWidgetObject *gw) {
pbe->type = GEVENT_GWIN_RADIO;
pbe->radio = (GHandle)gw;
pbe->group = ((GRadioObject *)gw)->group;
+ #if GWIN_WIDGET_TAGS
+ pbe->tag = gw->tag;
+ #endif
geventSendEvent(psl);
}
diff --git a/src/gwin/radio.h b/src/gwin/radio.h
index 196f8e27..eb7ee719 100644
--- a/src/gwin/radio.h
+++ b/src/gwin/radio.h
@@ -37,6 +37,9 @@ typedef struct GEventGWinRadio {
GEventType type; // The type of this event (GEVENT_GWIN_RADIO)
GHandle radio; // The radio button that has been depressed
uint16_t group; // The group for this radio button
+ #if GWIN_WIDGET_TAGS
+ WidgetTag tag; // The radio tag
+ #endif
} GEventGWinRadio;
/**
diff --git a/src/gwin/slider.c b/src/gwin/slider.c
index b488f823..7ce7b83f 100644
--- a/src/gwin/slider.c
+++ b/src/gwin/slider.c
@@ -38,6 +38,9 @@ static void SendSliderEvent(GWidgetObject *gw) {
pse->type = GEVENT_GWIN_SLIDER;
pse->slider = (GHandle)gw;
pse->position = ((GSliderObject *)gw)->pos;
+ #if GWIN_WIDGET_TAGS
+ pse->tag = gw->tag;
+ #endif
geventSendEvent(psl);
}
diff --git a/src/gwin/slider.h b/src/gwin/slider.h
index 41244186..32161d62 100644
--- a/src/gwin/slider.h
+++ b/src/gwin/slider.h
@@ -30,6 +30,9 @@ typedef struct GEventGWinSlider {
GEventType type; // The type of this event (GEVENT_GWIN_BUTTON)
GHandle slider; // The slider that is returning results
int position;
+ #if GWIN_WIDGET_TAGS
+ WidgetTag tag; // The slider tag
+ #endif
} GEventGWinSlider;
// There are currently no GEventGWinSlider listening flags - use 0
diff --git a/src/gwin/sys_options.h b/src/gwin/sys_options.h
index b1b58a68..d5240556 100644
--- a/src/gwin/sys_options.h
+++ b/src/gwin/sys_options.h
@@ -128,6 +128,15 @@
* @{
*/
/**
+ * @brief Add a tag to each widget
+ * @details Defaults to FALSE
+ * @note Adds a tag member to each widget. Any events created include this tag.
+ * The enables switch based application logic to detect the event source.
+ */
+ #ifndef GWIN_WIDGET_TAGS
+ #define GWIN_WIDGET_TAGS FALSE
+ #endif
+ /**
* @brief Use flat styling for controls rather than a 3D look
* @details Defaults to FALSE
* @note This may appear better on color-restricted displays