helpfor studient
Dependents: STM32_F103-C8T6basecanblink_led
Fork of mbed-dev by
Diff: platform/mbed_retarget.cpp
- Revision:
- 185:08ed48f1de7f
- Parent:
- 183:a56a73fd2a6f
--- a/platform/mbed_retarget.cpp Tue Mar 20 17:01:51 2018 +0000 +++ b/platform/mbed_retarget.cpp Thu Apr 19 17:12:19 2018 +0100 @@ -26,15 +26,18 @@ #include "platform/mbed_error.h" #include "platform/mbed_stats.h" #include "platform/mbed_critical.h" +#include "platform/mbed_poll.h" #include "platform/PlatformMutex.h" +#include "drivers/UARTSerial.h" #include "us_ticker_api.h" #include "lp_ticker_api.h" #include <stdlib.h> #include <string.h> #include <limits.h> -#if DEVICE_STDIO_MESSAGES +#ifndef SSIZE_MAX +#define SSIZE_MAX INT_MAX +#endif #include <stdio.h> -#endif #include <errno.h> #include "platform/mbed_retarget.h" @@ -67,7 +70,7 @@ # define PREFIX(x) x #endif -#define FILE_HANDLE_RESERVED 0xFFFFFFFF +#define FILE_HANDLE_RESERVED ((FileHandle*)0xFFFFFFFF) using namespace mbed; @@ -89,12 +92,15 @@ /* newlib has the filehandle field in the FILE struct as a short, so * we can't just return a Filehandle* from _open and instead have to * put it in a filehandles array and return the index into that array - * (or rather index+3, as filehandles 0-2 are stdin/out/err). */ -static FileHandle *filehandles[OPEN_MAX]; +static FileHandle *filehandles[OPEN_MAX] = { FILE_HANDLE_RESERVED, FILE_HANDLE_RESERVED, FILE_HANDLE_RESERVED }; +static char stdio_in_prev[OPEN_MAX]; +static char stdio_out_prev[OPEN_MAX]; static SingletonPtr<PlatformMutex> filehandle_mutex; namespace mbed { +void mbed_set_unbuffered_stream(std::FILE *_file); + void remove_filehandle(FileHandle *file) { filehandle_mutex->lock(); /* Remove all open filehandles for this */ @@ -110,20 +116,138 @@ #if DEVICE_SERIAL extern int stdio_uart_inited; extern serial_t stdio_uart; -#if MBED_CONF_PLATFORM_STDIO_CONVERT_NEWLINES -static char stdio_in_prev; -static char stdio_out_prev; -#endif #endif -static void init_serial() { -#if DEVICE_SERIAL +/* Private FileHandle to implement backwards-compatible functionality of + * direct HAL serial access for default stdin/stdout/stderr. + * This is not a particularly well-behaved FileHandle for a stream, which + * is why it's not public. People should be using UARTSerial. + */ +class DirectSerial : public FileHandle { +public: + DirectSerial(PinName tx, PinName rx, int baud); + virtual ssize_t write(const void *buffer, size_t size); + virtual ssize_t read(void *buffer, size_t size); + virtual off_t seek(off_t offset, int whence = SEEK_SET) { + return -ESPIPE; + } + virtual off_t size() { + return -EINVAL; + } + virtual int isatty() { + return true; + } + virtual int close() { + return 0; + } + virtual short poll(short events) const; +}; + +DirectSerial::DirectSerial(PinName tx, PinName rx, int baud) { if (stdio_uart_inited) return; - serial_init(&stdio_uart, STDIO_UART_TX, STDIO_UART_RX); -#if MBED_CONF_PLATFORM_STDIO_BAUD_RATE - serial_baud(&stdio_uart, MBED_CONF_PLATFORM_STDIO_BAUD_RATE); + serial_init(&stdio_uart, tx, rx); + serial_baud(&stdio_uart, baud); +} + +ssize_t DirectSerial::write(const void *buffer, size_t size) { + const unsigned char *buf = static_cast<const unsigned char *>(buffer); + for (size_t i = 0; i < size; i++) { + serial_putc(&stdio_uart, buf[i]); + } + return size; +} + +ssize_t DirectSerial::read(void *buffer, size_t size) { + unsigned char *buf = static_cast<unsigned char *>(buffer); + if (size == 0) { + return 0; + } + buf[0] = serial_getc(&stdio_uart); + return 1; +} + +short DirectSerial::poll(short events) const { + short revents = 0; + if ((events & POLLIN) && serial_readable(&stdio_uart)) { + revents |= POLLIN; + } + if ((events & POLLOUT) && serial_writable(&stdio_uart)) { + revents |= POLLOUT; + } + return revents; +} + +class Sink : public FileHandle { +public: + virtual ssize_t write(const void *buffer, size_t size); + virtual ssize_t read(void *buffer, size_t size); + virtual off_t seek(off_t offset, int whence = SEEK_SET) { return ESPIPE; } + virtual off_t size() { return -EINVAL; } + virtual int isatty() { return true; } + virtual int close() { return 0; } +}; + +ssize_t Sink::write(const void *buffer, size_t size) { + // Just swallow the data - this is historical non-DEVICE_SERIAL behaviour + return size; +} + +ssize_t Sink::read(void *buffer, size_t size) { + // Produce 1 zero byte - historical behaviour returned 1 without touching + // the buffer + unsigned char *buf = static_cast<unsigned char *>(buffer); + buf[0] = 0; + return 1; +} + + +MBED_WEAK FileHandle* mbed::mbed_target_override_console(int fd) +{ + return NULL; +} + +MBED_WEAK FileHandle* mbed::mbed_override_console(int fd) +{ + return NULL; +} + +static FileHandle* default_console() +{ +#if DEVICE_SERIAL +# if MBED_CONF_PLATFORM_STDIO_BUFFERED_SERIAL + static UARTSerial console(STDIO_UART_TX, STDIO_UART_RX, MBED_CONF_PLATFORM_STDIO_BAUD_RATE); +# else + static DirectSerial console(STDIO_UART_TX, STDIO_UART_RX, MBED_CONF_PLATFORM_STDIO_BAUD_RATE); +# endif +#else // DEVICE_SERIAL + static Sink console; #endif -#endif + return &console; +} + +/* Locate the default console for stdout, stdin, stderr */ +static FileHandle* get_console(int fd) { + FileHandle *fh = mbed_override_console(fd); + if (fh) { + return fh; + } + fh = mbed_target_override_console(fd); + if (fh) { + return fh; + } + return default_console(); +} + +/* Deal with the fact C library may not _open descriptors 0, 1, 2 - auto bind */ +static FileHandle* get_fhc(int fd) { + if (fd >= OPEN_MAX) { + return NULL; + } + FileHandle *fh = filehandles[fd]; + if (fh == FILE_HANDLE_RESERVED && fd < 3) { + filehandles[fd] = fh = get_console(fd); + } + return fh; } /** @@ -140,41 +264,123 @@ return -1; } -static inline int openmode_to_posix(int openmode) { - int posix = openmode; +static inline int openflags_to_posix(int openflags) { + int posix = openflags; #ifdef __ARMCC_VERSION - if (openmode & OPEN_PLUS) { + if (openflags & OPEN_PLUS) { posix = O_RDWR; - } else if(openmode & OPEN_W) { + } else if(openflags & OPEN_W) { posix = O_WRONLY; - } else if(openmode & OPEN_A) { + } else if(openflags & OPEN_A) { posix = O_WRONLY|O_APPEND; } else { posix = O_RDONLY; } /* a, w, a+, w+ all create if file does not already exist */ - if (openmode & (OPEN_A|OPEN_W)) { + if (openflags & (OPEN_A|OPEN_W)) { posix |= O_CREAT; } /* w and w+ truncate */ - if (openmode & OPEN_W) { + if (openflags & OPEN_W) { posix |= O_TRUNC; } #elif defined(__ICCARM__) - switch (openmode & _LLIO_RDWRMASK) { + switch (openflags & _LLIO_RDWRMASK) { case _LLIO_RDONLY: posix = O_RDONLY; break; case _LLIO_WRONLY: posix = O_WRONLY; break; case _LLIO_RDWR : posix = O_RDWR ; break; } - if (openmode & _LLIO_CREAT ) posix |= O_CREAT; - if (openmode & _LLIO_APPEND) posix |= O_APPEND; - if (openmode & _LLIO_TRUNC ) posix |= O_TRUNC; + if (openflags & _LLIO_CREAT ) posix |= O_CREAT; + if (openflags & _LLIO_APPEND) posix |= O_APPEND; + if (openflags & _LLIO_TRUNC ) posix |= O_TRUNC; #elif defined(TOOLCHAIN_GCC) posix &= ~O_BINARY; #endif return posix; } +static int reserve_filehandle() { + // find the first empty slot in filehandles, after the slots reserved for stdin/stdout/stderr + filehandle_mutex->lock(); + int fh_i; + for (fh_i = 3; fh_i < OPEN_MAX; fh_i++) { + /* Take a next free filehandle slot available. */ + if (filehandles[fh_i] == NULL) break; + } + if (fh_i >= OPEN_MAX) { + /* Too many file handles have been opened */ + errno = EMFILE; + filehandle_mutex->unlock(); + return -1; + } + filehandles[fh_i] = FILE_HANDLE_RESERVED; + filehandle_mutex->unlock(); + + return fh_i; +} + +int mbed::bind_to_fd(FileHandle *fh) { + int fh_i = reserve_filehandle(); + if (fh_i < 0) { + return fh_i; + } + + filehandles[fh_i] = fh; + stdio_in_prev[fh_i] = 0; + stdio_out_prev[fh_i] = 0; + + return fh_i; +} + +static int unbind_from_fd(int fd, FileHandle *fh) { + if (filehandles[fd] == fh) { + filehandles[fd] = NULL; + return 0; + } else { + errno = EBADF; + return -1; + } +} + +#ifndef __IAR_SYSTEMS_ICC__ +/* IAR provides fdopen itself */ +extern "C" std::FILE* fdopen(int fildes, const char *mode) +{ + // This is to avoid scanf and the bloat it brings. + char buf[1 + sizeof fildes]; /* @(integer) */ + MBED_STATIC_ASSERT(sizeof buf == 5, "Integers should be 4 bytes."); + buf[0] = '@'; + memcpy(buf + 1, &fildes, sizeof fildes); + + std::FILE *stream = std::fopen(buf, mode); + /* newlib-nano doesn't appear to ever call _isatty itself, so + * happily fully buffers an interactive stream. Deal with that here. + */ + if (stream && isatty(fildes)) { + mbed_set_unbuffered_stream(stream); + } + return stream; +} +#endif + +namespace mbed { +std::FILE *fdopen(FileHandle *fh, const char *mode) +{ + // First reserve the integer file descriptor + int fd = bind_to_fd(fh); + if (!fd) { + return NULL; + } + // Then bind that to the C stream. If successful, C library + // takes ownership and responsibility to close. + std::FILE *stream = ::fdopen(fd, mode); + if (!stream) { + unbind_from_fd(fd, fh); + } + return stream; +} +} + /* @brief standard c library fopen() retargeting function. * * This function is invoked by the standard c library retargeting to handle fopen() @@ -186,8 +392,8 @@ * EMFILE the maximum number of open files was exceeded. * * */ -extern "C" FILEHANDLE PREFIX(_open)(const char* name, int openmode) { - #if defined(__MICROLIB) && (__ARMCC_VERSION>5030000) +extern "C" FILEHANDLE PREFIX(_open)(const char *name, int openflags) { +#if defined(__MICROLIB) && (__ARMCC_VERSION>5030000) #if !defined(MBED_CONF_RTOS_PRESENT) // valid only for mbed 2 // for ulib, this is invoked after RAM init, prior c++ @@ -205,82 +411,77 @@ // Before version 5.03, we were using a patched version of microlib with proper names // This is the workaround that the microlib author suggested us static int n = 0; - if (!std::strcmp(name, ":tt")) return n++; - #else + if (std::strcmp(name, ":tt") == 0 && n < 3) { + return n++; + } +#else /* Use the posix convention that stdin,out,err are filehandles 0,1,2. */ if (std::strcmp(name, __stdin_name) == 0) { - init_serial(); - return 0; + get_fhc(STDIN_FILENO); + return STDIN_FILENO; } else if (std::strcmp(name, __stdout_name) == 0) { - init_serial(); - return 1; + get_fhc(STDOUT_FILENO); + return STDOUT_FILENO; } else if (std::strcmp(name, __stderr_name) == 0) { - init_serial(); - return 2; + get_fhc(STDERR_FILENO); + return STDERR_FILENO; } - #endif +#endif +#ifndef __IAR_SYSTEMS_ICC__ + /* FILENAME: "@(integer)" gives an already-allocated descriptor */ + if (name[0] == '@') { + int fd; + memcpy(&fd, name + 1, sizeof fd); + return fd; + } +#endif + return open(name, openflags_to_posix(openflags)); +} - // find the first empty slot in filehandles - filehandle_mutex->lock(); - unsigned int fh_i; - for (fh_i = 0; fh_i < sizeof(filehandles)/sizeof(*filehandles); fh_i++) { - /* Take a next free filehandle slot available. */ - if (filehandles[fh_i] == NULL) break; +extern "C" int open(const char *name, int oflag, ...) { + int fh_i = reserve_filehandle(); + if (fh_i < 0) { + return fh_i; } - if (fh_i >= sizeof(filehandles)/sizeof(*filehandles)) { - /* Too many file handles have been opened */ - errno = EMFILE; - filehandle_mutex->unlock(); - return -1; - } - filehandles[fh_i] = (FileHandle*)FILE_HANDLE_RESERVED; - filehandle_mutex->unlock(); FileHandle *res = NULL; - - /* FILENAME: ":(pointer)" describes a FileHandle* */ - if (name[0] == ':') { - void *p; - memcpy(&p, name + 1, sizeof(p)); - res = (FileHandle*)p; + FilePath path(name); - /* FILENAME: "/file_system/file_name" */ - } else { - FilePath path(name); + if (!path.exists()) { + /* The first part of the filename (between first 2 '/') is not a + * registered mount point in the namespace. + */ + return handle_open_errors(-ENODEV, fh_i); + } - if (!path.exists()) { - /* The first part of the filename (between first 2 '/') is not a - * registered mount point in the namespace. - */ + if (path.isFile()) { + res = path.file(); + } else { + FileSystemHandle *fs = path.fileSystem(); + if (fs == NULL) { return handle_open_errors(-ENODEV, fh_i); } - - if (path.isFile()) { - res = path.file(); - } else { - FileSystemHandle *fs = path.fileSystem(); - if (fs == NULL) { - return handle_open_errors(-ENODEV, fh_i); - } - int posix_mode = openmode_to_posix(openmode); - int err = fs->open(&res, path.fileName(), posix_mode); - if (err) { - return handle_open_errors(err, fh_i); - } + int err = fs->open(&res, path.fileName(), oflag); + if (err) { + return handle_open_errors(err, fh_i); } } filehandles[fh_i] = res; + stdio_in_prev[fh_i] = 0; + stdio_out_prev[fh_i] = 0; - return fh_i + 3; // +3 as filehandles 0-2 are stdin/out/err + return fh_i; } extern "C" int PREFIX(_close)(FILEHANDLE fh) { - if (fh < 3) return 0; + return close(fh); +} - FileHandle* fhc = filehandles[fh-3]; - filehandles[fh-3] = NULL; +extern "C" int close(int fh) { + FileHandle* fhc = get_fhc(fh); + filehandles[fh] = NULL; if (fhc == NULL) { errno = EBADF; return -1; @@ -295,12 +496,21 @@ } } +static bool convert_crlf(int fd) { +#if MBED_CONF_PLATFORM_STDIO_CONVERT_TTY_NEWLINES + return isatty(fd); +#elif MBED_CONF_PLATFORM_STDIO_CONVERT_NEWLINES + return fd < 3 && isatty(fd); +#else + return false; +#endif +} + #if defined(__ICCARM__) extern "C" size_t __write (int fh, const unsigned char *buffer, size_t length) { #else extern "C" int PREFIX(_write)(FILEHANDLE fh, const unsigned char *buffer, unsigned int length, int mode) { #endif - int n; // n is the number of bytes written #if defined(MBED_TRAP_ERRORS_ENABLED) && MBED_TRAP_ERRORS_ENABLED && defined(MBED_CONF_RTOS_PRESENT) if (core_util_is_isr_active() || !core_util_are_interrupts_enabled()) { @@ -308,52 +518,99 @@ } #endif - if (fh < 3) { -#if DEVICE_SERIAL - if (!stdio_uart_inited) init_serial(); -#if MBED_CONF_PLATFORM_STDIO_CONVERT_NEWLINES - for (unsigned int i = 0; i < length; i++) { - if (buffer[i] == '\n' && stdio_out_prev != '\r') { - serial_putc(&stdio_uart, '\r'); + if (length > SSIZE_MAX) { + errno = EINVAL; + return -1; + } + + ssize_t slength = length; + ssize_t written = 0; + + if (convert_crlf(fh)) { + // local prev is previous in buffer during seek + // stdio_out_prev[fh] is last thing actually written + char prev = stdio_out_prev[fh]; + // Seek for '\n' without preceding '\r'; if found flush + // preceding and insert '\r'. Continue until end of input. + for (ssize_t cur = 0; cur < slength; cur++) { + if (buffer[cur] == '\n' && prev != '\r') { + ssize_t r; + // flush stuff preceding the \n + if (cur > written) { + r = write(fh, buffer + written, cur - written); + if (r < 0) { + return -1; + } + written += r; + if (written < cur) { + // For some reason, didn't write all - give up now + goto finish; + } + stdio_out_prev[fh] = prev; + } + // insert a \r now, leaving the \n still to be written + r = write(fh, "\r", 1); + if (r < 0) { + return -1; + } + if (r < 1) { + goto finish; + } + stdio_out_prev[fh] = '\r'; } - serial_putc(&stdio_uart, buffer[i]); - stdio_out_prev = buffer[i]; + prev = buffer[cur]; } -#else - for (unsigned int i = 0; i < length; i++) { - serial_putc(&stdio_uart, buffer[i]); - } -#endif -#endif - n = length; - } else { - FileHandle* fhc = filehandles[fh-3]; - if (fhc == NULL) { - errno = EBADF; + } + + // Flush remaining from conversion, or the whole thing if no conversion + if (written < slength) { + ssize_t r = write(fh, buffer + written, slength - written); + if (r < 0) { return -1; } - - n = fhc->write(buffer, length); - if (n < 0) { - errno = -n; + written += r; + if (written > 0) { + stdio_out_prev[fh] = buffer[written - 1]; } } + +finish: #ifdef __ARMCC_VERSION - return length-n; + if (written >= 0) { + return slength - written; + } else { + return written; + } #else - return n; + return written; #endif } +extern "C" ssize_t write(int fh, const void *buf, size_t length) { + + FileHandle* fhc = get_fhc(fh); + if (fhc == NULL) { + errno = EBADF; + return -1; + } + + ssize_t ret = fhc->write(buf, length); + if (ret < 0) { + errno = -ret; + return -1; + } else { + return ret; + } +} + #if defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) extern "C" void PREFIX(_exit)(int return_code) { while(1) {} } extern "C" void _ttywrch(int ch) { -#if DEVICE_SERIAL - serial_putc(&stdio_uart, ch); -#endif + char c = ch; + write(STDOUT_FILENO, &c, 1); } #endif @@ -362,7 +619,6 @@ #else extern "C" int PREFIX(_read)(FILEHANDLE fh, unsigned char *buffer, unsigned int length, int mode) { #endif - int n; // n is the number of bytes read #if defined(MBED_TRAP_ERRORS_ENABLED) && MBED_TRAP_ERRORS_ENABLED && defined(MBED_CONF_RTOS_PRESENT) if (core_util_is_isr_active() || !core_util_are_interrupts_enabled()) { @@ -370,51 +626,71 @@ } #endif - if (fh < 3) { - // only read a character at a time from stdin -#if DEVICE_SERIAL - if (!stdio_uart_inited) init_serial(); -#if MBED_CONF_PLATFORM_STDIO_CONVERT_NEWLINES + if (length > SSIZE_MAX) { + errno = EINVAL; + return -1; + } + + ssize_t bytes_read = 0; + + if (convert_crlf(fh)) { while (true) { - char c = serial_getc(&stdio_uart); - if ((c == '\r' && stdio_in_prev != '\n') || - (c == '\n' && stdio_in_prev != '\r')) { - stdio_in_prev = c; + char c; + ssize_t r = read(fh, &c, 1); + if (r < 0) { + return -1; + } + if (r == 0) { + return bytes_read; + } + if ((c == '\r' && stdio_in_prev[fh] != '\n') || + (c == '\n' && stdio_in_prev[fh] != '\r')) { + stdio_in_prev[fh] = c; *buffer = '\n'; break; - } else if ((c == '\r' && stdio_in_prev == '\n') || - (c == '\n' && stdio_in_prev == '\r')) { - stdio_in_prev = c; - // onto next character + } else if ((c == '\r' && stdio_in_prev[fh] == '\n') || + (c == '\n' && stdio_in_prev[fh] == '\r')) { + stdio_in_prev[fh] = c; continue; } else { - stdio_in_prev = c; + stdio_in_prev[fh] = c; *buffer = c; break; } } -#else - *buffer = serial_getc(&stdio_uart); -#endif -#endif - n = 1; + bytes_read = 1; + } else { + bytes_read = read(fh, buffer, length); + } + +#ifdef __ARMCC_VERSION + if (bytes_read < 0) { + return -1; + } else if (bytes_read == 0) { + return 0x80000000 | length; // weird EOF indication } else { - FileHandle* fhc = filehandles[fh-3]; - if (fhc == NULL) { - errno = EBADF; - return -1; - } + return (ssize_t)length - bytes_read; + } +#else + return bytes_read; +#endif +} + +extern "C" ssize_t read(int fh, void *buf, size_t length) { - n = fhc->read(buffer, length); - if (n < 0) { - errno = -n; - } + FileHandle* fhc = get_fhc(fh); + if (fhc == NULL) { + errno = EBADF; + return -1; } -#ifdef __ARMCC_VERSION - return length-n; -#else - return n; -#endif + + ssize_t ret = fhc->read(buf, length); + if (ret < 0) { + errno = -ret; + return -1; + } else { + return ret; + } } @@ -424,10 +700,11 @@ extern "C" int _isatty(FILEHANDLE fh) #endif { - /* stdin, stdout and stderr should be tty */ - if (fh < 3) return 1; + return isatty(fh); +} - FileHandle* fhc = filehandles[fh-3]; +extern "C" int isatty(int fh) { + FileHandle* fhc = get_fhc(fh); if (fhc == NULL) { errno = EBADF; return 0; @@ -455,12 +732,17 @@ int whence = SEEK_SET; #endif - if (fh < 3) { - errno = ESPIPE; + off_t off = lseek(fh, offset, whence); + // Assuming INT_MAX = LONG_MAX, so we don't care about prototype difference + if (off > INT_MAX) { + errno = EOVERFLOW; return -1; } + return off; +} - FileHandle* fhc = filehandles[fh-3]; +extern "C" off_t lseek(int fh, off_t offset, int whence) { + FileHandle* fhc = get_fhc(fh); if (fhc == NULL) { errno = EBADF; return -1; @@ -471,19 +753,17 @@ errno = -off; return -1; } - // Assuming INT_MAX = LONG_MAX, so we don't care about prototype difference - if (off > INT_MAX) { - errno = EOVERFLOW; - return -1; - } return off; } #ifdef __ARMCC_VERSION extern "C" int PREFIX(_ensure)(FILEHANDLE fh) { - if (fh < 3) return 0; + return fsync(fh); +} +#endif - FileHandle* fhc = filehandles[fh-3]; +extern "C" int fsync(int fh) { + FileHandle* fhc = get_fhc(fh); if (fhc == NULL) { errno = EBADF; return -1; @@ -498,13 +778,9 @@ } } +#ifdef __ARMCC_VERSION extern "C" long PREFIX(_flen)(FILEHANDLE fh) { - if (fh < 3) { - errno = EINVAL; - return -1; - } - - FileHandle* fhc = filehandles[fh-3]; + FileHandle* fhc = get_fhc(fh); if (fhc == NULL) { errno = EBADF; return -1; @@ -546,12 +822,12 @@ #if !defined(__ARMCC_VERSION) && !defined(__ICCARM__) extern "C" int _fstat(int fh, struct stat *st) { - if (fh < 3) { - st->st_mode = S_IFCHR; - return 0; - } + return fstat(fh, st); +} +#endif - FileHandle* fhc = filehandles[fh-3]; +extern "C" int fstat(int fh, struct stat *st) { + FileHandle* fhc = get_fhc(fh); if (fhc == NULL) { errno = EBADF; return -1; @@ -561,7 +837,27 @@ st->st_size = fhc->size(); return 0; } -#endif + +extern "C" int poll(struct pollfd fds[], nfds_t nfds, int timeout) +{ + if (nfds > OPEN_MAX) { + errno = EINVAL; + return -1; + } + + struct mbed::pollfh fhs[OPEN_MAX]; + for (nfds_t n = 0; n < nfds; n++) { + // Underlying FileHandle poll returns POLLNVAL if given NULL, so + // we don't need to take special action. + fhs[n].fh = get_fhc(fds[n].fd); + fhs[n].events = fds[n].events; + } + int ret = poll(fhs, nfds, timeout); + for (nfds_t n = 0; n < nfds; n++) { + fds[n].revents = fhs[n].revents; + } + return ret; +} namespace std { extern "C" int remove(const char *path) { @@ -711,6 +1007,23 @@ } } +extern "C" int statvfs(const char *path, struct statvfs *buf) { + FilePath fp(path); + FileSystemHandle *fs = fp.fileSystem(); + if (fs == NULL) { + errno = ENODEV; + return -1; + } + + int err = fs->statvfs(fp.fileName(), buf); + if (err < 0) { + errno = -err; + return -1; + } else { + return 0; + } +} + #if defined(TOOLCHAIN_GCC) /* prevents the exception handling name demangling code getting pulled in */ #include "mbed_error.h" @@ -881,28 +1194,6 @@ #endif } -/* Applications are expected to use fdopen() - * not this function directly. This code had to live here because FILE and FileHandle - * processes are all linked together here. - */ -std::FILE *mbed_fdopen(FileHandle *fh, const char *mode) -{ - // This is to avoid scanf(buf, ":%.4s", fh) and the bloat it brings. - char buf[1 + sizeof(fh)]; /* :(pointer) */ - MBED_STATIC_ASSERT(sizeof(buf) == 5, "Pointers should be 4 bytes."); - buf[0] = ':'; - memcpy(buf + 1, &fh, sizeof(fh)); - - std::FILE *stream = std::fopen(buf, mode); - /* newlib-nano doesn't appear to ever call _isatty itself, so - * happily fully buffers an interactive stream. Deal with that here. - */ - if (stream && fh->isatty()) { - mbed_set_unbuffered_stream(stream); - } - return stream; -} - int mbed_getc(std::FILE *_file){ #if defined(__IAR_SYSTEMS_ICC__ ) && (__VER__ < 8000000) /*This is only valid for unbuffered streams*/