📄 newlib_hooks.c
字号:
/* 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 + -