⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 newlib_hooks.c

📁 umon bootloader source code, support mips cpu.
💻 C
📖 第 1 页 / 共 2 页
字号:
/* newlib_hooks.c:
 * This is a basic set of hooks that allow some of the stuff
 * in newlib to interface to a MicroMonitor based application.
 *
 * It hooks newlib to:
 * 	- uMon's console io (mon_putchar() & mon_getchar())
 * 	- uMon's file system (TFS)
 *	- uMon's environment (mon_getenv() & mon_setenv())
 *	- uMon's memory allocator (mon_malloc(), mon_free(), mon_realloc())
 *
 * The code assumes that fds 0, 1 & 2 are in/out/err and open() will
 * not be called for these.  All fds above that are for TFS files.
 * This version simply maps the incoming flags to as close of a fit
 * to a corresponding TFS operation as possible.
 *
 * WARNING: not heavily tested.
 *
 * NOTE: this "may" be thread safe if tfdlock() and newlib_tfdunlock()
 * are defined; however, I haven't looked at it very close.
 *
 * Author: Ed Sutter, with quite a bit of help from an article written
 * by Bill Gatliff http://billgatliff.com/articles/newlib/newlib.
 */
#include <stdio.h>
#include <reent.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include "monlib.h"

#define REENT struct _reent
#define MAXFILESIZE 0x4000

/* NEWLIB_TRACE:
 * When set, the shell variable "NEWLIB_TRACE" controls verbosity
 * within this module.
 */
#ifndef NEWLIB_TRACE
#define NEWLIB_TRACE 0
#endif

#define MAXTFDS	15

/* Define these for thread safety...
 */
#ifndef newlib_tfdlock
#define newlib_tfdlock()
#endif

#ifndef newlib_tfdunlock
#define newlib_tfdunlock()
#endif

/* TFS file descriptor info:
 */
struct tfdinfo {
	int	inuse;
	int	tfd;
	char *buf;
	char name[TFSNAMESIZE+1];
	char info[TFSNAMESIZE+1];
} tfdtable[MAXTFDS];


static void
newlib_not_supported(REENT *rptr,char *hook)
{
	mon_printf("NEWLIB HOOK '%s', NOT YET SUPPORTED\n",hook);
	rptr->_errno = ENOTSUP;
}

/*******************************************************************
 *******************************************************************
 *
 * Hooks to TFS:
 * (read & write also hook to console IO)
 */

/* open():
 * Attempts to remap the incoming flags to TFS equivalent.
 * Its not a perfect mapping, but gets pretty close.
 * A comma-delimited path is supported to allow the user
 * to specify TFS-stuff (flag string, info string, and a buffer).
 * For example:
 *	abc,e,script,0x400000
 *	This is a file called "abc" that will have the TFS 'e' flag
 *	and the TFS info field of "script".  The storage buffer is
 *  supplied by the user at 0x400000.
 */
int
_open_r(REENT *rptr, const char *path, int flags, int mode)
{
	static int beenhere = 0;
	long flagmode;
	int	tfdidx, tfd;
	struct tfdinfo *tip;
	char *buf, *fstr, *istr, *bstr, pathcopy[TFSNAMESIZE*3+1];

#if NEWLIB_TRACE
	if (mon_getenv("NEWLIB_TRACE"))
		mon_printf("_open_r(%s,0x%x,0x%x)\n",path,flags,mode);
#endif

	if (!beenhere) {
		newlib_tfdlock();
		for(tfdidx=0;tfdidx<MAXTFDS;tfdidx++)
			tfdtable[tfdidx].inuse = 0;		

		tfdtable[0].inuse = 1;		/* fake entry for stdin */
		tfdtable[1].inuse = 1;		/* fake entry for stdout */
		tfdtable[2].inuse = 1;		/* fake entry for stderr */
		newlib_tfdunlock();
		beenhere = 1;
	}

	istr = fstr = bstr = buf = (char *)0;

	/* Copy the incoming path to a local array so that we can safely
	 * modify the string...
 	 */
	if (strlen(path) > TFSNAMESIZE*3) {
		rptr->_errno = ENAMETOOLONG;
		return(-1);
	}
	strcpy(pathcopy,path);

	/* The incoming string may have commas that are used to delimit the
	 * name from the TFS flag string, TFS info string and buffer.
	 * Check for the commas and test for maximum string length...
	 */
	fstr = strchr(pathcopy,',');
	if (fstr)  {
		*fstr++ = 0;
		istr = strchr(fstr,',');
		if (istr) {
			*istr++ = 0;
			bstr = strchr(istr,',');
			if (bstr)
				*bstr++ = 0;
		}
	}
	if (strlen(pathcopy) > TFSNAMESIZE) {
		rptr->_errno = ENAMETOOLONG;
		return(-1);
	}
	if (istr) {
		if (strlen(istr) > TFSNAMESIZE) {
			rptr->_errno = ENAMETOOLONG;
			return(-1);
		}
	}

	/* If O_EXCL and O_CREAT are set, then fail if the file exists...
	 */
	if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) {
		if (mon_tfsstat((char *)pathcopy)) {
			rptr->_errno = EEXIST;
			return(-1);
		}
	}

	/* Only a few flag combinations are supported...
	 * O_RDONLY						 Simple read-only
	 * O_WRONLY | O_APPEND			 Each write starts at end of file
	 * O_WRONLY | O_TRUNC			 If file exists, truncate it
	 * O_WRONLY | O_CREAT			 Create if it doesn't exist
	 * O_WRONLY | O_CREAT | O_EXCL	 Fail if file exists
	 */
	switch(flags) {
		case O_RDONLY:
			flagmode = TFS_RDONLY;
			break;
		case O_WRONLY|O_APPEND:
			flagmode = TFS_APPEND;
			break;
		case O_WRONLY|O_TRUNC:
		case O_WRONLY|O_CREAT|O_TRUNC:
			mon_tfsunlink((char *)pathcopy);
			flagmode = TFS_CREATE|TFS_APPEND;
			break;
		case O_WRONLY|O_CREAT:
		case O_WRONLY|O_CREAT|O_APPEND:
			flagmode = TFS_CREATE|TFS_APPEND;
			break;
		case O_RDWR:
		case O_WRONLY|O_CREAT|O_EXCL:
			flagmode = TFS_CREATE|TFS_APPEND;
			break;
		default:
			mon_printf("_open_r(): flag 0x%x not supported\n",flags);
			rptr->_errno = ENOTSUP;
			return(-1);
	}

	/* Find an open slot in our tfd table:
	 */
	newlib_tfdlock();
	for(tfdidx=0;tfdidx<MAXTFDS;tfdidx++) {
		if (tfdtable[tfdidx].inuse == 0)
			break;
	}
	if (tfdidx == MAXTFDS) {
		newlib_tfdunlock();
		rptr->_errno = EMFILE;
		return(-1);
	}
	tip = &tfdtable[tfdidx];
	tip->inuse = 1;
	newlib_tfdunlock();

	/* If file is opened for something other than O_RDONLY, then
	 * we need to allocate a buffer for the file..
	 * WARNING: It is the user's responsibility to make sure that
	 * the file size does not exceed this buffer.  Note that the
	 * buffer may be specified as part of the comma-delimited path.
	 */
	if (flagmode == TFS_RDONLY) {
		buf = (char *)0;
	}
	else {
		if (bstr)
			buf = (char *)strtol(bstr,0,0);
		else
			buf = mon_malloc(MAXFILESIZE);
		if (!buf) {
			newlib_tfdlock();
			tip->inuse = 0;	
			newlib_tfdunlock();
			rptr->_errno = ENOMEM;
			return(-1);
		}
	}

	/* Deal with tfs flags and tfs info fields if necessary:
	 */
	if (fstr) {
		long bflag;

		bflag = mon_tfsctrl(TFS_FATOB,(long)fstr,0);
		if (bflag == -1) {
			rptr->_errno = EINVAL;
			return(-1);
		}
		flagmode |= bflag;
	}

	if (istr) 
		strcpy(tip->info,istr);
	else 
		tip->info[0] = 0;

	tfd = mon_tfsopen((char *)pathcopy,flagmode,buf);
	if (tfd >= 0) {
		tip->tfd = tfd;	
		tip->buf = buf;	
		strcpy(tip->name,pathcopy);
		return(tfdidx);
	}
	else {
		mon_printf("%s: %s\n",pathcopy,
			(char *)mon_tfsctrl(TFS_ERRMSG,tfd,0));
	}

	if (buf)
		mon_free(buf);

	newlib_tfdlock();
	tip->inuse = 0;	
	newlib_tfdunlock();
	rptr->_errno = EINVAL;
	return(-1);
}

int
_close_r(REENT *rptr, int fd)
{
	char *info;
	struct tfdinfo *tip;

#if NEWLIB_TRACE
	if (mon_getenv("NEWLIB_TRACE"))
		mon_printf("_close_r(%d)\n",fd);
#endif

	if ((fd < 3) || (fd >= MAXTFDS)) {
		rptr->_errno = EBADF;
		return(-1);
	}

	tip = &tfdtable[fd];

	if (tip->info[0])
		info = tip->info;
	else
		info = (char *)0;

	mon_tfsclose(tip->tfd,info);

	if (tip->buf)
		mon_free(tip->buf);

	newlib_tfdlock();
	tip->inuse = 0;	
	newlib_tfdunlock();
	rptr->_errno = 0;
	return(0);
}

_ssize_t
_write_r(REENT *rptr, int fd, const void *ptr, size_t len)
{
	int	i, ret;

#if NEWLIB_TRACE
	if (mon_getenv("NEWLIB_TRACE"))
		mon_printf("_write_r(%d,%d)\n",fd,len);
#endif

	if ((fd == 1) || (fd == 2)) {
		for(i=0;i<len;i++) {
			if (*(char *)ptr == '\n')
				mon_putchar('\r');
			mon_putchar(*(char *)ptr++);
		}
		return(len);
	}
	if ((fd <= 0) || (fd >= MAXTFDS)) {
		rptr->_errno = EBADF;
		return(-1);
	}

	ret = mon_tfswrite(tfdtable[fd].tfd,(char *)ptr,len);
	if (ret < 0)
		return(-1);
	else
		return(ret);
}

_ssize_t
_read_r(REENT *rptr, int fd, void *ptr, size_t len)
{
	int	i, ret;
	char c, *array;

#if NEWLIB_TRACE
	if (mon_getenv("NEWLIB_TRACE"))
		mon_printf("_read_r(%d,%d)\n",fd,len);
#endif

	array = (char *)ptr;

	if (fd == 0) {				/* stdin? */
		for(i=0;i<len;i++) {
			c = (char)mon_getchar();
			if (c == '\b') {
				if (i > 0) {
					mon_printf("\b \b");
					i--;
				}
				i--;
			}
			else if ((c == '\r') || (c == '\n')) {
				array[i] = '\n';
				mon_printf("\r\n");
				break;
			}
			else {
				array[i] = c;
				mon_putchar(c);
			}
		}
		ret = i+1;
	}
	else {
		if ((fd < 3) || (fd >= MAXTFDS)) {
			rptr->_errno = EBADF;
			return(-1);
		}

		ret = mon_tfsread(tfdtable[fd].tfd,ptr,len);
		if (ret == TFSERR_EOF)
			ret = 0;
	}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -