123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265 |
- /*
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- /*
- compatibility with posix APIs using AP_Filesystem
- This implements the FILE* API from posix sufficiently well for Lua
- scripting to function. It has no buffering so is inefficient for
- single character operations. We deliberately use this implementation
- in HAL_SITL and HAL_Linux where it is not needed in order to have a
- uniform implementation across all platforms
- */
- #include "AP_Filesystem.h"
- #if HAVE_FILESYSTEM_SUPPORT
- #include "posix_compat.h"
- #include <stdarg.h>
- #include <AP_Math/AP_Math.h>
- struct apfs_file {
- int fd;
- bool error;
- bool eof;
- int16_t unget;
- char *tmpfile_name;
- };
- #define CHECK_STREAM(stream, ret) while (stream == NULL || stream->fd < 0) { errno = EBADF; return ret; }
- #define modecmp(str, pat) (strcmp(str, pat) == 0 ? 1: 0)
- /*
- map a fopen() file mode to a open() mode
- */
- static int posix_fopen_modes_to_open(const char *mode)
- {
- int flag = 0;
- if (modecmp(mode,"r") || modecmp(mode,"rb")) {
- flag = O_RDONLY;
- return flag;
- }
- if (modecmp(mode,"r+") || modecmp(mode, "r+b" ) || modecmp(mode, "rb+" )) {
- flag = O_RDWR | O_TRUNC;
- return flag;
- }
- if (modecmp(mode,"w") || modecmp(mode,"wb")) {
- flag = O_WRONLY | O_CREAT | O_TRUNC;
- return flag;
- }
- if (modecmp(mode,"w+") || modecmp(mode, "w+b" ) || modecmp(mode, "wb+" )) {
- flag = O_RDWR | O_CREAT | O_TRUNC;
- return flag;
- }
- if (modecmp(mode,"a") || modecmp(mode,"ab")) {
- flag = O_WRONLY | O_CREAT | O_APPEND;
- return flag;
- }
- if (modecmp(mode,"a+") || modecmp(mode, "a+b" ) || modecmp(mode, "ab+" )) {
- flag = O_RDWR | O_CREAT | O_APPEND;
- return -1;
- }
- return -1;
- }
- APFS_FILE *apfs_fopen(const char *pathname, const char *mode)
- {
- APFS_FILE *f = new APFS_FILE;
- if (!f) {
- return nullptr;
- }
- f->fd = AP::FS().open(pathname, posix_fopen_modes_to_open(mode));
- f->unget = -1;
- return f;
- }
- int apfs_fprintf(APFS_FILE *stream, const char *fmt, ...)
- {
- CHECK_STREAM(stream, -1);
- va_list va;
- char* buf = NULL;
- int16_t len;
- va_start(va, fmt);
- len = vasprintf(&buf, fmt, va);
- va_end(va);
- if (len > 0) {
- len = AP::FS().write(stream->fd, buf, len);
- free(buf);
- }
- return len;
- }
- int apfs_fflush(APFS_FILE *stream)
- {
- CHECK_STREAM(stream, EOF);
- return 0;
- }
- size_t apfs_fread(void *ptr, size_t size, size_t nmemb, APFS_FILE *stream)
- {
- CHECK_STREAM(stream, 0);
- ssize_t ret = AP::FS().read(stream->fd, ptr, size*nmemb);
- if (ret <= 0) {
- stream->eof = true;
- return 0;
- }
- return ret / size;
- }
- size_t apfs_fwrite(const void *ptr, size_t size, size_t nmemb, APFS_FILE *stream)
- {
- CHECK_STREAM(stream, 0);
- ssize_t ret = AP::FS().write(stream->fd, ptr, size*nmemb);
- if (ret <= 0) {
- stream->error = true;
- return 0;
- }
- return ret / size;
- }
- int apfs_fputs(const char *s, APFS_FILE *stream)
- {
- CHECK_STREAM(stream, EOF);
- ssize_t ret = AP::FS().write(stream->fd, s, strlen(s));
- if (ret < 0) {
- stream->error = true;
- return EOF;
- }
- return ret;
- }
- char *apfs_fgets(char *s, int size, APFS_FILE *stream)
- {
- CHECK_STREAM(stream, NULL);
- ssize_t ret = AP::FS().read(stream->fd, s, size-1);
- if (ret < 0) {
- stream->error = true;
- return NULL;
- }
- s[ret] = 0;
- return s;
- }
- void apfs_clearerr(APFS_FILE *stream)
- {
- stream->error = false;
- }
- int apfs_fseek(APFS_FILE *stream, long offset, int whence)
- {
- CHECK_STREAM(stream, EOF);
- stream->eof = false;
- return AP::FS().lseek(stream->fd, offset, whence);
- }
- int apfs_ferror(APFS_FILE *stream)
- {
- CHECK_STREAM(stream, EOF);
- return stream->error;
- }
- int apfs_fclose(APFS_FILE *stream)
- {
- CHECK_STREAM(stream, EOF);
- int ret = AP::FS().close(stream->fd);
- stream->fd = -1;
- if (stream->tmpfile_name) {
- AP::FS().unlink(stream->tmpfile_name);
- free(stream->tmpfile_name);
- stream->tmpfile_name = NULL;
- }
- delete stream;
- return ret;
- }
- APFS_FILE *apfs_tmpfile(void)
- {
- char *fname = NULL;
- if (asprintf(&fname, "tmp.%03u", unsigned(get_random16()) % 1000) <= 0) {
- return NULL;
- }
- APFS_FILE *ret = apfs_fopen(fname, "w");
- if (!ret) {
- free(fname);
- return NULL;
- }
- ret->tmpfile_name = fname;
- return ret;
- }
- int apfs_getc(APFS_FILE *stream)
- {
- CHECK_STREAM(stream, EOF);
- uint8_t c;
- if (stream->unget != -1) {
- c = stream->unget;
- stream->unget = -1;
- return c;
- }
- ssize_t ret = AP::FS().read(stream->fd, &c, 1);
- if (ret <= 0) {
- stream->eof = true;
- return EOF;
- }
- return c;
- }
- int apfs_ungetc(int c, APFS_FILE *stream)
- {
- CHECK_STREAM(stream, EOF);
- stream->unget = c;
- stream->eof = false;
- return c;
- }
- int apfs_feof(APFS_FILE *stream)
- {
- return stream->eof;
- }
- APFS_FILE *apfs_freopen(const char *pathname, const char *mode, APFS_FILE *stream)
- {
- CHECK_STREAM(stream, NULL);
- int ret = AP::FS().close(stream->fd);
- if (ret < 0) {
- return NULL;
- }
- if (stream->tmpfile_name) {
- AP::FS().unlink(stream->tmpfile_name);
- free(stream->tmpfile_name);
- stream->tmpfile_name = NULL;
- }
- stream->fd = AP::FS().open(pathname, posix_fopen_modes_to_open(mode));
- stream->error = false;
- stream->eof = false;
- stream->unget = -1;
- return stream;
- }
- long apfs_ftell(APFS_FILE *stream)
- {
- CHECK_STREAM(stream, EOF);
- return AP::FS().lseek(stream->fd, 0, SEEK_CUR);
- }
- int apfs_remove(const char *pathname)
- {
- return AP::FS().unlink(pathname);
- }
- #endif // HAVE_FILESYSTEM_SUPPORT
|