diff options
| -rw-r--r-- | include/gfile/gfile.h | 189 | ||||
| -rw-r--r-- | include/gfile/options.h | 149 | ||||
| -rw-r--r-- | src/gfile/gfile.c | 679 | ||||
| -rw-r--r-- | src/gfile/gfile.mk | 1 | ||||
| -rw-r--r-- | src/gfile/inc_fatfs.c | 15 | ||||
| -rw-r--r-- | src/gfile/inc_nativefs.c | 98 | ||||
| -rw-r--r-- | src/gfile/inc_ramfs.c | 15 | ||||
| -rw-r--r-- | src/gfile/inc_romfs.c | 87 | 
8 files changed, 1233 insertions, 0 deletions
| diff --git a/include/gfile/gfile.h b/include/gfile/gfile.h new file mode 100644 index 00000000..bc476956 --- /dev/null +++ b/include/gfile/gfile.h @@ -0,0 +1,189 @@ +/* + * 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 + */ + +/** + * @file    include/gfile/gfile.h + * @brief   GFILE - File IO Routines header file. + * + * @addtogroup GFILE + * + * @brief	Module which contains Operating system independent FILEIO + * + * @{ + */ + +#ifndef _GFILE_H +#define _GFILE_H + +#include "gfx.h" + +#if GFX_USE_GMISC || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Type definitions                                                          */ +/*===========================================================================*/ + +/** + * @brief	A file pointer + */ + +typedef struct GFILE { +	const struct GFILEVMT *	vmt; +	uint16_t				flags; +		#define	GFILEFLG_OPEN			0x0001		// File is open +		#define	GFILEFLG_READ			0x0002		// Read the file +		#define	GFILEFLG_WRITE			0x0004		// Write the file +		#define	GFILEFLG_APPEND			0x0008		// Append on each write +		#define GFILEFLG_BINARY			0x0010		// Treat as a binary file +		#define	GFILEFLG_DELONCLOSE		0x0020		// Delete on close +		#define	GFILEFLG_CANSEEK		0x0040		// Seek operations are valid +		#define GFILEFLG_FAILONBLOCK	0x0080		// Fail on a blocking call +		#define GFILEFLG_MUSTEXIST		0x0100		// On open file must exist +		#define GFILEFLG_MUSTNOTEXIST	0x0200		// On open file must not exist +		#define GFILEFLG_TRUNC			0x0400		// On open truncate the file +	void *					obj; +	long int				pos; +} GFILE; + +typedef struct GFILEVMT { +	const struct GFILEVMT *	next; +	uint8_t					flags; +		#define GFSFLG_WRITEABLE		0x0001 +		#define GFSFLG_CASESENSITIVE	0x0002 +		#define GFSFLG_SEEKABLE			0x0004 +		#define GFSFLG_FAST				0x0010 +		#define GFSFLG_SMALL			0x0020 +		#define GFSFLG_TEXTMODES		0x0040 +	char					prefix; +	bool_t		del(const char *fname); +	bool_t		exists(const char *fname); +	long int	filesize(const char *fname); +	bool_t		ren(const char *oldname, const char *newname); +	bool_t		open(GFILE *f, const char *fname); +	void		close(GFILE *f); +	int			read(GFILE *f, char *buf, int size); +	int			write(GFILE *f, const char *buf, int size); +	bool_t		setpos(GFILE *f, long int pos); +	long int	getsize(GFILE *f); +	bool_t		eof(GFILE *f); +} GFILEVMT; + +typedef void	GFILE; + +extern GFILE *gfileStdIn; +extern GFILE *gfileStdErr; +extern GFILE *gfileStdOut; + +/*===========================================================================*/ +/* External declarations.                                                    */ +/*===========================================================================*/ + +//TODO +//FILE * tmpfile ( void );		// Auto-deleting +//char * tmpnam ( char * str ); +//L_tmpnam - Minimum length for temporary file name +//FILENAME_MAX - Maximum length of file names (constant ) +// FOPEN_MAX - Potential limit of simultaneous open streams (constant ) +// TMP_MAX - Number of temporary files (constant ) +//FILE * freopen ( const char * filename, const char * mode, FILE * stream ); +//setbuf +//setvbuf +//fflush +//fscanf +//scanf +//sscanf +//vscanf +//vsscanf +//fgetc +//fgets +//fputc +//fputs +//getc +//getchar +//puts +//ungetc +//void perror (const char * str); + +#ifdef __cplusplus +extern "C" { +#endif + +	bool_t		gfileExists(const char *fname); +	bool_t		gfileDelete(const char *fname); +	long int	gfileGetFilesize(const char *fname); +	bool_t		gfileRename(const char *oldname, const char *newname); +	GFILE *		gfileOpen(const char *fname, const char *mode); +	void		gfileClose(GFILE *f); +	size_t		gfileRead(GFILE *f, char *buf, size_t len); +	size_t		gfileWrite(GFILE *f, const char *buf, size_t len); +	long int	gfileGetPos(GFILE *f); +	bool_t		gfileSetPos(GFILE *f, long int pos); +	long int	gfileGetSize(GFILE *f); +	bool_t		gfileEOF(GFILE *f); + +	#if GFILE_NEED_PRINTG +		int vfnprintg(GFILE *f, int maxlen, const char *fmt, va_list arg); +		int fnprintg(GFILE *f, int maxlen, const char *fmt, ...); +		#define vfprintg(f,m,a)			vfnprintg(f,0,m,a) +		#define fprintg(f,m,...)		fnprintg(f,0,m,...) +		#define vprintg(m,a)			vfnprintg(gfileStdOut,0,m,a) +		#define printg(m,...)			fnprintg(gfileStdOut,0,m,...) + +		#if GFILE_NEED_STRINGS +			int vsnprintg(char *buf, int maxlen, const char *fmt, va_list arg); +			int snprintg(char *buf, int maxlen, const char *fmt, ...); +			#define vsprintg(s,m,a)			vsnprintg(s,0,m,a) +			#define sprintg(s,m,...)		snprintg(s,0,m,...) +		#endif +	#endif + + +	#if GFILE_NEED_STDIO && !defined(GFILE_IMPLEMENTATION) +		#define FILE					GFILE +		#define fopen(n,m)				gfileOpen(n,m) +		#define fclose(f)				gfileClose(f) +		size_t gstdioRead(void * ptr, size_t size, size_t count, FILE *f); +		size_t gstdioWrite(const void * ptr, size_t size, size_t count, FILE *f); +		#define fread(p,sz,cnt,f)		gstdioRead(p,sz,cnt,f) +		#define fwrite(p,sz,cnt,f)		gstdioWrite(p,sz,cnt,f) +		int gstdioSeek(FILE *f, size_t offset, int origin); +		#define fseek(f,ofs,org)		gstdioSeek(f,ofs,org) +			#define SEEK_SET	0 +			#define SEEK_CUR	1 +			#define SEEK_END	2 +		#define remove(n)				(!gfileDelete(n)) +		#define rename(o,n)				(!gfileRename(o,n)) +		#define fflush(f)				(0) +		#define ftell(f)				gfileGetPos(f) +		#define fpos_t					long int +		int gstdioGetpos(FILE *f, long int *pos); +		#define fgetpos(f,pos)			gstdioGetpos(f,pos) +		#define fsetpos(f, pos)			(!gfileSetPos(f, *pos)) +		#define rewind(f)				gfileSetPos(f, 0); +		#define clearerr(f)				(0) +		#define feof(f)					gfileEOF(f) +		//#define ferror(f)				(0) + +		#define vfprintf(f,m,a)			vfnprintg(f,0,m,a) +		#define fprintf(f,m,...)		fnprintg(f,0,m,...) +		#define vprintf(m,a)			vfnprintg(gfileStdOut,0,m,a) +		#define printf(m,...)			fnprintg(gfileStdOut,0,m,...) +		#define vsnprintf(s,n,m,a)		vsnprintg(s,n,m,a) +		#define snprintf(s,n,m,...)		snprintg(s,n,m,...) +		#define vsprintf(s,m,a)			vsnprintg(s,0,m,a) +		#define sprintf(s,m,...)		snprintg(s,0,m,...) +	#endif + +#ifdef __cplusplus +} +#endif + +#endif /* GFX_USE_MISC */ + +#endif /* _GMISC_H */ +/** @} */ + diff --git a/include/gfile/options.h b/include/gfile/options.h new file mode 100644 index 00000000..a64937f1 --- /dev/null +++ b/include/gfile/options.h @@ -0,0 +1,149 @@ +/* + * 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 + */ + +/** + * @file    include/gfile/options.h + * @brief   GFILE - File IO options header file. + * + * @addtogroup GFILE + * @{ + */ + +#ifndef _GFILE_OPTIONS_H +#define _GFILE_OPTIONS_H + +/** + * @name    GFILE Functionality to be included + * @{ + */ +	/** +	 * @brief   Include printg, fprintg etc functions +	 * @details	Defaults to FALSE +	 */ +	#ifndef GFILE_NEED_PRINTG +		#define GFILE_NEED_PRINTG		FALSE +	#endif +	/** +	 * @brief   Include scang, fscang etc functions +	 * @details	Defaults to FALSE +	 */ +	#ifndef GFILE_NEED_SCANG +		#define GFILE_NEED_SCANG		FALSE +	#endif +	/** +	 * @brief   Include the string sprintg/sscang 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 +	#endif +	/** +	 * @brief   Include scang, fscang, sscang etc functions +	 * @details	Defaults to FALSE +	 */ +	#ifndef GFILE_NEED_SCANG +		#define GFILE_NEED_SCANG		FALSE +	#endif +	/** +	 * @brief   Map many stdio functions to their GFILE equivalent +	 * @details	Defaults to FALSE +	 * @note	This replaces the functions in stdio.h with equivalents +	 * 			- Do not include stdio.h as it has different conflicting definitions. +	 */ +	#ifndef GFILE_NEED_STDIO +		#define GFILE_NEED_STDIO		FALSE +	#endif +	/** +	 * @brief   Include the ROM file system +	 * @details	Defaults to FALSE +	 * @note	If GFILE_ALLOW_DEVICESPECIFIC is on then you can ensure that you are +	 * 			opening a file on the ROM file system by prefixing +	 * 			its name with "S|" (the letter 'S', followed by a vertical bar). +	 * @note	This requires a file called romfs_files.h to be included in the +	 * 			users project. This file includes all the files converted to .h files +	 * 			using the file2c utility using the "-r" flag. +	 */ +	#ifndef GFILE_NEED_ROMFS +		#define GFILE_NEED_ROMFS		FALSE +	#endif +	/** +	 * @brief   Include the RAM file system +	 * @details	Defaults to FALSE +	 * @note	If GFILE_ALLOW_DEVICESPECIFIC is on then you can ensure that you are +	 * 			opening a file on the RAM file system by prefixing +	 * 			its name with "R|" (the letter 'R', followed by a vertical bar). +	 * @note	You must also define GFILE_RAMFS_SIZE with the size of the file system +	 * 			to be allocated in RAM. +	 */ +	#ifndef GFILE_NEED_RAMFS +		#define GFILE_NEED_RAMFS		FALSE +	#endif +	/** +	 * @brief   Include the FAT file system driver +	 * @details	Defaults to FALSE +	 * @note	If GFILE_ALLOW_DEVICESPECIFIC is on then you can ensure that you are +	 * 			opening a file on the FAT file system by prefixing +	 * 			its name with "F|" (the letter 'F', followed by a vertical bar). +	 * @note	You must separately include the FATFS library and code. +	 */ +	#ifndef GFILE_NEED_FATFS +		#define GFILE_NEED_FATFS		FALSE +	#endif +	/** +	 * @brief   Include the operating system's native file system +	 * @details	Defaults to FALSE +	 * @note	If GFILE_ALLOW_DEVICESPECIFIC is on then you can ensure that you are +	 * 			opening a file on the native file system by prefixing +	 * 			its name with "N|" (the letter 'N', followed by a vertical bar). +	 * @note	If defined then the gfileStdOut and gfileStdErr handles +	 * 			use the operating system equivalent stdio and stderr. +	 * 			If it is not defined the gfileStdOut and gfileStdErr io is discarded. +	 */ +	#ifndef GFILE_NEED_NATIVEFS +		#define GFILE_NEED_NATIVEFS		FALSE +	#endif +/** + * @} + * + * @name    GFILE Optional Parameters + * @{ + */ +	/** +	 * @brief  Add floating point support to printg/scang etc. +	 */ +	#ifndef GFILE_ALLOW_FLOATS +		#define GFILE_ALLOW_FLOATS +	#endif +	/** +	 * @brief   Can the device be specified as part of the file name. +	 * @note	If this is on then a device letter and a vertical bar can be +	 * 			prefixed on a file name to specify that it must be on a +	 * 			specific device. +	 */ +	#ifndef GFILE_ALLOW_DEVICESPECIFIC +		#define GFILE_ALLOW_DEVICESPECIFIC		FALSE +	#endif +	/** +	 * @brief   The maximum number of open files +	 * @note	This count excludes gfileStdIn, gfileStdOut and gfileStdErr +	 * 			(if open by default). +	 */ +	#ifndef GFILE_MAX_GFILES +		#define GFILE_MAX_GFILES		3 +	#endif +	/** +	 * @brief   The size in bytes of the RAM file system +	 */ +	#ifndef GFILE_RAMFS_SIZE +		#define GFILE_RAMFS_SIZE		0 +	#endif +/** @} */ + +#endif /* _GFILE_OPTIONS_H */ +/** @} */ diff --git a/src/gfile/gfile.c b/src/gfile/gfile.c new file mode 100644 index 00000000..59dade1f --- /dev/null +++ b/src/gfile/gfile.c @@ -0,0 +1,679 @@ +/* + * 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 + */ + +/** + * @file    src/gfile/gfile.c + * @brief   GFILE code. + * + */ + +#define GFILE_IMPLEMENTATION +#include "gfx.h" + +#if GFX_USE_GFILE + +// The chain of FileSystems +#define GFILE_CHAINHEAD		0 + +// The table of GFILE's +static GFILE gfileArr[GFILE_MAX_GFILES]; +GFILE *gfileStdIn; +GFILE *gfileStdOut; +GFILE *gfileStdErr; + +/** + * The order of the file-systems below determines the order + * that they are searched to find a file. + * The last defined is the first searched. + */ + +/******************************************************** + * The RAM file-system VMT + ********************************************************/ +#if GFILE_NEED_RAMFS +	#include "../src/gfile/inc_ramfs.c" +#endif + +/******************************************************** + * The FAT file-system VMT + ********************************************************/ +#ifndef GFILE_NEED_FATFS +	#include "../src/gfile/inc_fatfs.c" +#endif + +/******************************************************** + * The native file-system + ********************************************************/ +#if GFILE_NEED_NATIVEFS +	#include "../src/gfile/inc_nativefs.c" +#endif + +/******************************************************** + * The ROM file-system VMT + ********************************************************/ +#if GFILE_NEED_ROMFS +	#include "../src/gfile/inc_romfs.c" +#endif + +/******************************************************** + * IO routines + ********************************************************/ + +/** + * The chain of file systems. + */ +static const GFILEVMT const * FsChain = GFILE_CHAINHEAD; + +void _gfileInit(void) +{ +	#if GFILE_NEED_NATIVEFS +		NativeStdIn.flags = GFILEFLG_OPEN|GFILEFLG_READ; +		NativeStdIn.vmt = &FsNativeVMT; +		NativeStdIn.obj = (void *)stdin; +		NativeStdIn.pos = 0; +		gfileStdIn = &NativeStdIn; +		NativeStdOut.flags = GFILEFLG_OPEN|GFILEFLG_WRITE|GFILEFLG_APPEND; +		NativeStdOut.vmt = &FsNativeVMT; +		NativeStdOut.obj = (void *)stdout; +		NativeStdOut.pos = 0; +		gfileStdOut = &NativeStdOut; +		NativeStdErr.flags = GFILEFLG_OPEN|GFILEFLG_WRITE|GFILEFLG_APPEND; +		NativeStdErr.vmt = &FsNativeVMT; +		NativeStdErr.obj = (void *)stderr; +		NativeStdErr.pos = 0; +		gfileStdErr = &NativeStdErr; +	#endif +} + +void _gfileDeinit(void) +{ +	/* ToDo */ +} + +bool_t gfileExists(const char *fname) { +	const GFILEVMT *p; + +	#if GFILE_ALLOW_DEVICESPECIFIC +		if (fname[0] && fname[1] == '|') { +			for(p = FsChain; p; p = p->next) { +				if (p->prefix == fname[0]) +					return p->exists && p->exists(fname+2); +			} +			return FALSE; +		} +	#endif + +	for(p = FsChain; p; p = p->next) { +		if (p->exists && p->exists(fname)) +			return TRUE; +	} +	return FALSE; +} + +bool_t gfileDelete(const char *fname) { +	const GFILEVMT *p; + +	#if GFILE_ALLOW_DEVICESPECIFIC +		if (fname[0] && fname[1] == '|') { +			for(p = FsChain; p; p = p->next) { +				if (p->prefix == fname[0]) +					return p->del && p->del(fname+2); +			} +			return FALSE; +		} +	#endif + +	for(p = FsChain; p; p = p->next) { +		if (p->del && p->del(fname)) +			return TRUE; +	} +	return FALSE; +} + +long int gfileGetFilesize(const char *fname) { +	const GFILEVMT *p; +	long int res; + +	#if GFILE_ALLOW_DEVICESPECIFIC +		if (fname[0] && fname[1] == '|') { +			for(p = FsChain; p; p = p->next) { +				if (p->prefix == fname[0]) +					return p->filesize ? p->filesize(fname+2) : -1; +			} +			return -1; +		} +	#endif + +	for(p = FsChain; p; p = p->next) { +		if (p->filesize && (res = p->filesize(fname)) != -1) +			return res; +	} +	return -1; +} + +bool_t gfileRename(const char *oldname, const char *newname) { +	const GFILEVMT *p; + +	#if GFILE_ALLOW_DEVICESPECIFIC +		if ((oldname[0] && oldname[1] == '|') || (newname[0] && newname[1] == '|')) { +			char ch; + +			if (oldname[0] && oldname[1] == '|') { +				ch = oldname[0]; +				oldname += 2; +				if (newname[0] && newname[1] == '|') { +					if (newname[0] != ch) +						// Both oldname and newname are fs specific but different ones. +						return FALSE; +					newname += 2; +				} +			} else { +				ch = newname[0]; +				newname += 2; +			} +			for(p = FsChain; p; p = p->next) { +				if (p->prefix == ch) +					return p->ren && p->ren(oldname, newname); +			} +			return FALSE; +		} +	#endif + +	for(p = FsChain; p; p = p->next) { +		if (p->ren && p->ren(oldname,newname)) +			return TRUE; +	} +	return FALSE; +} + +static uint16_t mode2flags(const char *mode) { +	uint16_t	flags; + +	switch(mode[0]) { +	case 'r': +		flags = GFILEFLG_READ|GFILEFLG_MUSTEXIST; +		while (*++mode) { +			switch(mode[0]) { +			case '+':	flags |= GFILEFLG_WRITE;		break; +			case 'b':	flags |= GFILEFLG_BINARY;		break; +			} +		} +		return flags; +	case 'w': +		flags = GFILEFLG_WRITE|GFILEFLG_TRUNC; +		while (*++mode) { +			switch(mode[0]) { +			case '+':	flags |= GFILEFLG_READ;			break; +			case 'b':	flags |= GFILEFLG_BINARY;		break; +			case 'x':	flags |= GFILEFLG_MUSTNOTEXIST;	break; +			} +		} +		return flags; +	case 'a': +		flags = GFILEFLG_WRITE|GFILEFLG_APPEND; +		while (*++mode) { +			switch(mode[0]) { +			case '+':	flags |= GFILEFLG_READ;			break; +			case 'b':	flags |= GFILEFLG_BINARY;		break; +			case 'x':	flags |= GFILEFLG_MUSTNOTEXIST;	break; +			} +		} +		return flags; +	} +	return 0; +} + +static bool_t testopen(const GFILEVMT *p, GFILE *f, const char *fname) { +	// If we want write but the fs doesn't allow it then return +	if ((f->flags & GFILEFLG_WRITE) && !(p->flags & GFSFLG_WRITEABLE)) +		return FALSE; + +	// Try to open +	if (!p->open || !p->open(f, fname)) +		return FALSE; + +	// File is open - fill in all the details +	f->vmt = p; +	f->err = 0; +	f->pos = 0; +	f->flags |= GFILEFLG_OPEN; +	if (p->flags & GFSFLG_SEEKABLE) +		f->flags |= GFILEFLG_CANSEEK; +	return TRUE; +} + +GFILE *gfileOpen(const char *fname, const char *mode) { +	uint16_t		flags; +	GFILE *			f; +	const GFILEVMT *p; + +	// Get the requested mode +	if (!(flags = mode2flags(mode))) +		return FALSE; + +	#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); +					} +					// File not found +					break; +				} +			} + +			// No available slot +			return FALSE; +		} +	#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 TRUE; +			} +			// File not found +			break; +		} +	} + +	// No available slot +	return FALSE; +} + +void gfileClose(GFILE *f) { +	if (!(f->flags & GFILEFLG_OPEN)) +		return; +	if (f->vmt->close) +		f->vmt->close(f); +	f->flags = 0; +} + +size_t gfileRead(GFILE *f, char *buf, size_t len) { +	size_t	res; + +	if ((f->flags & (GFILEFLG_OPEN|GFILEFLG_READ)) != (GFILEFLG_OPEN|GFILEFLG_READ)) +		return 0; +	if (!f->vmt->read) +		return 0; +	if ((res = f->vmt->read(f, buf, len)) <= 0) +		return 0; +	f->pos += res; +	return res; +} + +size_t gfileWrite(GFILE *f, const char *buf, size_t len) { +	size_t	res; + +	if ((f->flags & (GFILEFLG_OPEN|GFILEFLG_WRITE)) != (GFILEFLG_OPEN|GFILEFLG_WRITE)) +		return 0; +	if (!f->vmt->write) +		return 0; +	if ((res = f->vmt->write(f, buf, len)) <= 0) +		return 0; +	f->pos += res; +	return res; +} + +long int gfileGetPos(GFILE *f) { +	if (!(f->flags & GFILEFLG_OPEN)) +		return 0; +	return f->pos; +} + +bool_t gfileSetPos(GFILE *f, long int pos) { +	if (!(f->flags & GFILEFLG_OPEN)) +		return FALSE; +	if (!f->vmt->setpos || !f->vmt->setpos(f, pos)) +		return FALSE; +	f->pos = pos; +} + +long int gfileGetSize(GFILE *f) { +	if (!(f->flags & GFILEFLG_OPEN)) +		return 0; +	if (!f->vmt->getsize) +		return 0; +	return f->vmt->getsize(f); +} + +bool_t gfileEOF(GFILE *f) { +	if (!(f->flags & GFILEFLG_OPEN)) +		return TRUE; +	if (!f->vmt->eof) +		return TRUE; +	return f->vmt->eof(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, char *buf, int size) { +		memcpy(buf, (char *)f->obj+f->pos, size); +		return size; +	} +	static int StringWrite(GFILE *f, const char *buf, int size) { +		memcpy((char *)f->obj+f->pos, buf, size); +		return size; +	} +	static const GFILEVMT StringVMT = { +		0,								// next +		0,								// flags +		'_',							// prefix +		0, 0, 0, 0, +		0, 0, StringRead, StringWrite, +		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'; +				else if (c == '*') +					c = va_arg(ap, int); +				else +					break; +				width = width * 10 + c; +			} +			if (c == '.') { +				while (1) { +					c = *fmt++; +					if (c >= '0' && c <= '9') +						c -= '0'; +					else if (c == '*') +						c = va_arg(ap, int); +					else +						break; +					precision = precision * 10 + c; +				} +			} +			/* 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(ap, int); +				break; +			case 's': +				filler = ' '; +				if ((s = va_arg(ap, 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(ap, long); +				else +					l = va_arg(ap, 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(ap, 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(ap, long); +				else +					l = va_arg(ap, 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; +			} +			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; +			} +			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 +	#error "GFILE-SCANG: Not implemented yet" +#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; +	} +#endif + +#endif /* GFX_USE_GFILE */ diff --git a/src/gfile/gfile.mk b/src/gfile/gfile.mk new file mode 100644 index 00000000..381bd6f6 --- /dev/null +++ b/src/gfile/gfile.mk @@ -0,0 +1 @@ +GFXSRC +=   $(GFXLIB)/src/gfile/gfile.c diff --git a/src/gfile/inc_fatfs.c b/src/gfile/inc_fatfs.c new file mode 100644 index 00000000..d49cfe7a --- /dev/null +++ b/src/gfile/inc_fatfs.c @@ -0,0 +1,15 @@ +/* + * 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 FAT file-system VMT + ********************************************************/ +#error "GFILE: FATFS Not implemented yet" diff --git a/src/gfile/inc_nativefs.c b/src/gfile/inc_nativefs.c new file mode 100644 index 00000000..df5e7861 --- /dev/null +++ b/src/gfile/inc_nativefs.c @@ -0,0 +1,98 @@ +/* + * 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 native file-system + ********************************************************/ + +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> + +static GFILE NativeStdIn; +static GFILE NativeStdOut; +static GFILE NativeStdErr; + +static bool_t NativeDel(const char *fname); +static bool_t NativeExists(const char *fname); +static long int	NativeFilesize(const char *fname); +static bool_t NativeRen(const char *oldname, const char *newname); +static bool_t NativeOpen(GFILE *f, const char *fname); +static void NativeClose(GFILE *f); +static int NativeRead(GFILE *f, char *buf, int size); +static int NativeWrite(GFILE *f, const char *buf, int size); +static bool_t NativeSetpos(GFILE *f, long int pos); +static long int NativeGetsize(GFILE *f); +static bool_t NativeEof(GFILE *f); + +static const GFILEVMT FsNativeVMT = { +	GFILE_CHAINHEAD,									// next +	#if defined(WIN32) || GFX_USE_OS_WIN32 +		GFSFLG_TEXTMODES| +	#else +		GFSFLG_CASESENSITIVE| +	#endif +	GFSFLG_WRITEABLE|GFSFLG_SEEKABLE|GFSFLG_FAST,		// flags +	'N',												// prefix +	NativeDel, NativeExists, NativeFilesize, NativeRen, +	NativeOpen, NativeClose, NativeRead, NativeWrite, +	NativeSetpos, NativeGetsize, NativeEof, +}; +#undef GFILE_CHAINHEAD +#define GFILE_CHAINHEAD		&FsNativeVMT + +static char *flags2mode(char *buf, uint16_t flags) { +	if (flags & GFILEFLG_MUSTEXIST) +		*buf = 'r'; +	else if (flags & GFILEFLG_APPEND) +		*buf = 'a'; +	else +		*buf = 'w'; +	buf++; +	if ((flags & (GFILEFLG_READ|GFILEFLG_WRITE)) == (GFILEFLG_READ|GFILEFLG_WRITE)) +		*buf++ = '+'; +	if (flags & GFILEFLG_BINARY) +		*buf++ = 'b'; +	if (flags & GFILEFLG_MUSTNOTEXIST) +		*buf++ = 'x'; +	*buf++ = 0; +} + +static bool_t NativeDel(const char *fname) { return remove(fname) ? FALSE : TRUE; } +static bool_t NativeExists(const char *fname) { return access(fname, 0) ? FALSE : TRUE; } +static long int	NativeFilesize(const char *fname) { +	struct stat st; +	if (stat(fname, &st)) return -1; +	return st.st_size; +} +static bool_t NativeRen(const char *oldname, const char *newname) { return rename(oldname, newname) ? FALSE : TRUE }; +static bool_t NativeOpen(GFILE *f, const char *fname) { +	FILE *fd; +	char mode[5]; + +	if (!(fd = fopen(fname, mode))) +		return FALSE; +	f->obj = (void *)fd; +	return TRUE; +} +static void NativeClose(GFILE *f) { fclose((FILE *)f->obj); } +static int NativeRead(GFILE *f, char *buf, int size) { return fread(buf, 1, size, (FILE *)f->obj); } +static int NativeWrite(GFILE *f, const char *buf, int size) { return fwrite(buf, 1, size, (FILE *)f->obj); } +static bool_t NativeSetpos(GFILE *f, long int pos) { +	return fseek((FILE *)f->obj, pos, SEEK_SET) ?  FALSE : TRUE; +} +static long int NativeGetsize(GFILE *f) { +	struct stat st; +	if (fstat(fileno((FILE *)f->obj), &st)) return -1; +	return st.st_size; +} +static bool_t NativeEof(GFILE *f) { return feof((FILE *)f->obj) ? TRUE : FALSE; } diff --git a/src/gfile/inc_ramfs.c b/src/gfile/inc_ramfs.c new file mode 100644 index 00000000..b0f0d052 --- /dev/null +++ b/src/gfile/inc_ramfs.c @@ -0,0 +1,15 @@ +/* + * 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 RAM file-system VMT + ********************************************************/ +#error "GFILE: RAMFS Not implemented yet" diff --git a/src/gfile/inc_romfs.c b/src/gfile/inc_romfs.c new file mode 100644 index 00000000..5a780554 --- /dev/null +++ b/src/gfile/inc_romfs.c @@ -0,0 +1,87 @@ +/* + * 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 ROM file-system VMT + ********************************************************/ + +#include <string.h> + +typedef struct ROMFS_DIRENTRY { +	const struct ROMFS_DIRENTRY *	next; +	const char *					name; +	long int						size; +	const char *					file; +} ROMFS_DIRENTRY; + +#define ROMFS_DIRENTRY_HEAD		0 + +#include "romfs_files.h" + +static const ROMFS_DIRENTRY const *FsROMHead = ROMFS_DIRENTRY_HEAD; + +static bool_t ROMExists(const char *fname); +static long int	ROMFilesize(const char *fname); +static bool_t ROMOpen(GFILE *f, const char *fname); +static void ROMClose(GFILE *f); +static int ROMRead(GFILE *f, char *buf, int size); +static bool_t ROMSetpos(GFILE *f, long int pos); +static long int ROMGetsize(GFILE *f); +static bool_t ROMEof(GFILE *f); + +static const GFILEVMT FsROMVMT = { +	GFILE_CHAINHEAD,									// next +	GFSFLG_CASESENSITIVE|GFSFLG_SEEKABLE|GFSFLG_FAST,	// flags +	'S',												// prefix +	0, ROMExists, ROMFilesize, 0, +	ROMOpen, ROMClose, ROMRead, 0, +	ROMSetpos, ROMGetsize, ROMEof, +}; +#undef GFILE_CHAINHEAD +#define GFILE_CHAINHEAD		&FsROMVMT + +static ROMFS_DIRENTRY *ROMFindFile(const char *fname) { +	const ROMFS_DIRENTRY *p; + +	for(p = FsROMHead; p; p = p->next) { +		if (!strcmp(p->name, fname)) +			break; +	} +	return p; +} +static bool_t ROMExists(const char *fname) { return ROMFindFile(fname) != 0; } +static long int	ROMFilesize(const char *fname) { +	const ROMFS_DIRENTRY *p; + +	if (!(p = ROMFindFile(fname))) return -1; +	return p->size; +} +static bool_t ROMOpen(GFILE *f, const char *fname) { +	const ROMFS_DIRENTRY *p; + +	if (!(p = ROMFindFile(fname))) return FALSE; +	f->obj = (void *)p; +	return TRUE; +} +static void ROMClose(GFILE *f) { (void)f; } +static int ROMRead(GFILE *f, char *buf, int size) { +	const ROMFS_DIRENTRY *p; + +	p = (const ROMFS_DIRENTRY *)f->obj; +	if (p->size - f->pos < size) +		size = p->size - f->pos; +	if (size <= 0)	return 0; +	memcpy(buf, p->file+f->pos, size); +	return size; +} +static bool_t ROMSetpos(GFILE *f, long int pos) { return pos <= ((const ROMFS_DIRENTRY *)f->obj)->size; } +static long int ROMGetsize(GFILE *f) { return ((const ROMFS_DIRENTRY *)f->obj)->size; } +static bool_t ROMEof(GFILE *f) { return f->pos >= ((const ROMFS_DIRENTRY *)f->obj)->size; } | 
