diff options
Diffstat (limited to 'apps/interpreters/bas/fs.c')
-rw-r--r-- | apps/interpreters/bas/fs.c | 1823 |
1 files changed, 1823 insertions, 0 deletions
diff --git a/apps/interpreters/bas/fs.c b/apps/interpreters/bas/fs.c new file mode 100644 index 000000000..cea05db56 --- /dev/null +++ b/apps/interpreters/bas/fs.c @@ -0,0 +1,1823 @@ +/**************************************************************************** + * apps/interpreters/bas/fs.c + * BASIC file system interface. + * + * Copyright (c) 1999-2014 Michael Haardt + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Adapted to NuttX and re-released under a 3-clause BSD license: + * + * Copyright (C) 2014 Gregory Nutt. All rights reserved. + * Authors: Alan Carvalho de Assis <Alan Carvalho de Assis> + * Gregory Nutt <gnutt@nuttx.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/time.h> +#include <sys/types.h> + +#include <assert.h> +#include <errno.h> +#include <fcntl.h> +#include <math.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> +#include <time.h> +#include <unistd.h> + +#include "fs.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define LINEWIDTH 80 +#define COLWIDTH 14 + +#define _(String) String + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static struct FileStream **file; +static int capacity; +static int used; +static const int open_mode[4] = { 0, O_RDONLY, O_WRONLY, O_RDWR }; + +const char *FS_errmsg; +static char FS_errmsgbuf[80]; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static int size(int dev) +{ + if (dev >= capacity) + { + int i; + struct FileStream **n; + + n = (struct FileStream **) + realloc(file, (dev + 1) * sizeof(struct FileStream *)); + if (n == (struct FileStream **)0) + { + FS_errmsg = strerror(errno); + return -1; + } + + file = n; + for (i = capacity; i <= dev; ++i) + { + file[i] = (struct FileStream *)0; + } + + capacity = dev + 1; + } + + return 0; +} + +static int opened(int dev, int mode) +{ + int fd = -1; + + if (dev < 0 || dev >= capacity || file[dev] == (struct FileStream *)0) + { + snprintf(FS_errmsgbuf, sizeof(FS_errmsgbuf), _("channel #%d not open"), + dev); + FS_errmsg = FS_errmsgbuf; + return -1; + } + + if (mode == -1) + { + return 0; + } + + switch (mode) + { + case 0: + { + fd = file[dev]->outfd; + if (fd == -1) + { + snprintf(FS_errmsgbuf, sizeof(FS_errmsgbuf), + _("channel #%d not opened for writing"), dev); + } + break; + } + + case 1: + { + fd = file[dev]->infd; + if (fd == -1) + { + snprintf(FS_errmsgbuf, sizeof(FS_errmsgbuf), + _("channel #%d not opened for reading"), dev); + } + break; + } + + case 2: + { + fd = file[dev]->randomfd; + if (fd == -1) + { + snprintf(FS_errmsgbuf, sizeof(FS_errmsgbuf), + _("channel #%d not opened for random access"), dev); + } + break; + } + + case 3: + { + fd = file[dev]->binaryfd; + if (fd == -1) + { + snprintf(FS_errmsgbuf, sizeof(FS_errmsgbuf), + _("channel #%d not opened for binary access"), dev); + } + break; + } + + case 4: + { + fd = + (file[dev]->randomfd != + -1 ? file[dev]->randomfd : file[dev]->binaryfd); + if (fd == -1) + { + snprintf(FS_errmsgbuf, sizeof(FS_errmsgbuf), + _("channel #%d not opened for random or binary access"), + dev); + } + break; + } + + default: + assert(0); + } + + if (fd == -1) + { + FS_errmsg = FS_errmsgbuf; + return -1; + } + else + { + return 0; + } +} + +static int refill(int dev) +{ + struct FileStream *f; + ssize_t len; + + f = file[dev]; + f->inSize = 0; + len = read(f->infd, f->inBuf, sizeof(f->inBuf)); + if (len <= 0) + { + f->inCapacity = 0; + FS_errmsg = (len == -1 ? strerror(errno) : (const char *)0); + return -1; + } + else + { + f->inCapacity = len; + return 0; + } +} + +static int edit(int chn, int onl) +{ + struct FileStream *f = file[chn]; + char *buf = f->inBuf; + char ch; + int r; + + for (buf = f->inBuf; buf < (f->inBuf + f->inCapacity); ++buf) + { + if (*buf >= '\0' && *buf < ' ') + { + FS_putChar(chn, '^'); + FS_putChar(chn, *buf ? (*buf + 'a' - 1) : '@'); + } + else + { + FS_putChar(chn, *buf); + } + } + do + { + FS_flush(chn); + if ((r = read(f->infd, &ch, 1)) == -1) + { + f->inCapacity = 0; + FS_errmsg = strerror(errno); + return -1; + } + else if (r == 0 || (f->inCapacity == 0 && ch == 4)) + { + FS_errmsg = (char *)0; + return -1; + } + +#ifdef CONFIG_INTERPREPTER_BAS_VT100 + /* REVISIT: Use VT100 commands to erase */ +#warning Missing Logic +#else + if ((f->inCapacity + 1) < sizeof(f->inBuf)) + { + /* Ignore carriage returns that may accompany a CRLF sequence. + * REVISIT: Some environments may have other line termination rules + */ + + if (ch != '\r') + { + /* Is this a new line character */ + + if (ch != '\n') + { + /* No.. escape control characters other than newline and + * carriage return + */ + + if (ch >= '\0' && ch < ' ') + { + FS_putChar(chn, '^'); + FS_putChar(chn, ch ? (ch + 'a' - 1) : '@'); + } + + /* Output normal, printable characters */ + + else + { + FS_putChar(chn, ch); + } + } + + /* Echo the newline (or not) */ + + else if (onl) + { + FS_putChar(chn, '\n'); + } + + f->inBuf[f->inCapacity++] = ch; + } + } +#endif + } + while (ch != '\n'); + + return 0; +} + +static int cls(int chn) +{ +#ifdef CONFIG_INTERPREPTER_BAS_VT100 + /* REVISIT: Use VT100 commands to clear the screen */ +#warning Missing Logic +#endif + FS_errmsg = _("Clear screen operation not implemented"); + return -1; +} + +static int locate(int chn, int line, int column) +{ +#ifdef CONFIG_INTERPREPTER_BAS_VT100 + /* REVISIT: Use VT100 commands to set the cursor position */ +#warning Missing Logic +#endif + FS_errmsg = _("Set cursor position operation not implement"); + return -1; +} + +static int colour(int chn, int foreground, int background) +{ +#ifdef CONFIG_INTERPREPTER_BAS_VT100 + /* REVISIT: Use VT100 commands to color */ +#warning Missing Logic +#endif + FS_errmsg = _("Set color operation no implemented"); + return -1; +} + +static int resetcolour(int chn) +{ +#ifdef CONFIG_INTERPREPTER_BAS_VT100 + /* REVISIT: Use VT100 commands to reset color */ +#warning Missing Logic +#endif + return 0; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int FS_opendev(int chn, int infd, int outfd) +{ + if (size(chn) == -1) + { + return -1; + } + + if (file[chn] != (struct FileStream *)0) + { + FS_errmsg = _("channel already open"); + return -1; + } + + file[chn] = malloc(sizeof(struct FileStream)); + file[chn]->dev = 1; +#ifdef CONFIG_SERIAL_TERMIOS + file[chn]->tty = (infd == 0 ? isatty(infd) && isatty(outfd) : 0); +#else + file[chn]->tty = 1; +#endif + file[chn]->recLength = 1; + file[chn]->infd = infd; + file[chn]->inSize = 0; + file[chn]->inCapacity = 0; + file[chn]->outfd = outfd; + file[chn]->outPos = 0; + file[chn]->outLineWidth = LINEWIDTH; + file[chn]->outColWidth = COLWIDTH; + file[chn]->outCapacity = sizeof(file[chn]->outBuf); + file[chn]->outSize = 0; + file[chn]->outforeground = -1; + file[chn]->outbackground = -1; + file[chn]->randomfd = -1; + file[chn]->binaryfd = -1; + FS_errmsg = (const char *)0; + ++used; + return 0; +} + +int FS_openin(const char *name) +{ + int chn, fd; + + if ((fd = open(name, O_RDONLY)) == -1) + { + FS_errmsg = strerror(errno); + return -1; + } + + for (chn = 0; chn < capacity; ++chn) + { + if (file[chn] == (struct FileStream *)0) + { + break; + } + } + + if (size(chn) == -1) + { + return -1; + } + + file[chn] = malloc(sizeof(struct FileStream)); + file[chn]->recLength = 1; + file[chn]->dev = 0; + file[chn]->tty = 0; + file[chn]->infd = fd; + file[chn]->inSize = 0; + file[chn]->inCapacity = 0; + file[chn]->outfd = -1; + file[chn]->randomfd = -1; + file[chn]->binaryfd = -1; + FS_errmsg = (const char *)0; + ++used; + return chn; +} + +int FS_openinChn(int chn, const char *name, int mode) +{ + int fd; + mode_t fl; + + if (size(chn) == -1) + { + return -1; + } + + if (file[chn] != (struct FileStream *)0) + { + FS_errmsg = _("channel already open"); + return -1; + } + + fl = open_mode[mode]; + + /* Serial devices on Linux should be opened non-blocking, otherwise the + * open() may block already. Named pipes can not be opened non-blocking in + * write-only mode, so first try non-blocking, then blocking. */ + + if ((fd = open(name, fl | O_NONBLOCK)) == -1) + { + if (errno != ENXIO || (fd = open(name, fl)) == -1) + { + FS_errmsg = strerror(errno); + return -1; + } + } + else if (fcntl(fd, F_SETFL, (long)fl) == -1) + { + FS_errmsg = strerror(errno); + close(fd); + return -1; + } + + file[chn] = malloc(sizeof(struct FileStream)); + file[chn]->recLength = 1; + file[chn]->dev = 0; + file[chn]->tty = 0; + file[chn]->infd = fd; + file[chn]->inSize = 0; + file[chn]->inCapacity = 0; + file[chn]->outfd = -1; + file[chn]->randomfd = -1; + file[chn]->binaryfd = -1; + FS_errmsg = (const char *)0; + ++used; + return chn; +} + +int FS_openout(const char *name) +{ + int chn, fd; + + if ((fd = open(name, O_WRONLY | O_TRUNC | O_CREAT, 0666)) == -1) + { + FS_errmsg = strerror(errno); + return -1; + } + + for (chn = 0; chn < capacity; ++chn) + { + if (file[chn] == (struct FileStream *)0) + { + break; + } + } + + if (size(chn) == -1) + { + return -1; + } + + file[chn] = malloc(sizeof(struct FileStream)); + file[chn]->recLength = 1; + file[chn]->dev = 0; + file[chn]->tty = 0; + file[chn]->infd = -1; + file[chn]->outfd = fd; + file[chn]->outPos = 0; + file[chn]->outLineWidth = LINEWIDTH; + file[chn]->outColWidth = COLWIDTH; + file[chn]->outSize = 0; + file[chn]->outCapacity = sizeof(file[chn]->outBuf); + file[chn]->randomfd = -1; + file[chn]->binaryfd = -1; + FS_errmsg = (const char *)0; + ++used; + return chn; +} + +int FS_openoutChn(int chn, const char *name, int mode, int append) +{ + int fd; + mode_t fl; + + if (size(chn) == -1) + { + return -1; + } + + if (file[chn] != (struct FileStream *)0) + { + FS_errmsg = _("channel already open"); + return -1; + } + + fl = open_mode[mode] | (append ? O_APPEND : 0); + + /* Serial devices on Linux should be opened non-blocking, otherwise the */ + /* open() may block already. Named pipes can not be opened non-blocking */ + /* in write-only mode, so first try non-blocking, then blocking. */ + + fd = open(name, fl | O_CREAT | (append ? 0 : O_TRUNC) | O_NONBLOCK, 0666); + if (fd == -1) + { + if (errno != ENXIO || + (fd = open(name, fl | O_CREAT | (append ? 0 : O_TRUNC), 0666)) == -1) + { + FS_errmsg = strerror(errno); + return -1; + } + } + else if (fcntl(fd, F_SETFL, (long)fl) == -1) + { + FS_errmsg = strerror(errno); + close(fd); + return -1; + } + + file[chn] = malloc(sizeof(struct FileStream)); + file[chn]->recLength = 1; + file[chn]->dev = 0; + file[chn]->tty = 0; + file[chn]->infd = -1; + file[chn]->outfd = fd; + file[chn]->outPos = 0; + file[chn]->outLineWidth = LINEWIDTH; + file[chn]->outColWidth = COLWIDTH; + file[chn]->outSize = 0; + file[chn]->outCapacity = sizeof(file[chn]->outBuf); + file[chn]->randomfd = -1; + file[chn]->binaryfd = -1; + FS_errmsg = (const char *)0; + ++used; + return chn; +} + +int FS_openrandomChn(int chn, const char *name, int mode, int recLength) +{ + int fd; + + assert(chn >= 0); + assert(name != (const char *)0); + assert(recLength > 0); + if (size(chn) == -1) + { + return -1; + } + + if (file[chn] != (struct FileStream *)0) + { + FS_errmsg = _("channel already open"); + return -1; + } + + if ((fd = open(name, open_mode[mode] | O_CREAT, 0666)) == -1) + { + FS_errmsg = strerror(errno); + return -1; + } + + file[chn] = malloc(sizeof(struct FileStream)); + file[chn]->recLength = recLength; + file[chn]->dev = 0; + file[chn]->tty = 0; + file[chn]->infd = -1; + file[chn]->outfd = -1; + file[chn]->randomfd = fd; + file[chn]->recBuf = malloc(recLength); + memset(file[chn]->recBuf, 0, recLength); + StringField_new(&file[chn]->field); + file[chn]->binaryfd = -1; + FS_errmsg = (const char *)0; + ++used; + return chn; +} + +int FS_openbinaryChn(int chn, const char *name, int mode) +{ + int fd; + + assert(chn >= 0); + assert(name != (const char *)0); + if (size(chn) == -1) + { + return -1; + } + + if (file[chn] != (struct FileStream *)0) + { + FS_errmsg = _("channel already open"); + return -1; + } + + if ((fd = open(name, open_mode[mode] | O_CREAT, 0666)) == -1) + { + FS_errmsg = strerror(errno); + return -1; + } + file[chn] = malloc(sizeof(struct FileStream)); + file[chn]->recLength = 1; + file[chn]->dev = 0; + file[chn]->tty = 0; + file[chn]->infd = -1; + file[chn]->outfd = -1; + file[chn]->randomfd = -1; + file[chn]->binaryfd = fd; + FS_errmsg = (const char *)0; + ++used; + return chn; +} + +int FS_freechn(void) +{ + int i; + + for (i = 0; i < capacity && file[i]; ++i); + if (size(i) == -1) + { + return -1; + } + + return i; +} + +int FS_flush(int dev) +{ + ssize_t written; + size_t offset; + + if (file[dev] == (struct FileStream *)0) + { + FS_errmsg = _("channel not open"); + return -1; + } + + offset = 0; + while (offset < file[dev]->outSize) + { + written = + write(file[dev]->outfd, file[dev]->outBuf + offset, + file[dev]->outSize - offset); + if (written == -1) + { + FS_errmsg = strerror(errno); + return -1; + } + else + { + offset += written; + } + } + + file[dev]->outSize = 0; + FS_errmsg = (const char *)0; + return 0; +} + +int FS_close(int dev) +{ + if (file[dev] == (struct FileStream *)0) + { + FS_errmsg = _("channel not open"); + return -1; + } + + if (file[dev]->outfd >= 0) + { + if (file[dev]->tty && + (file[dev]->outforeground != -1 || file[dev]->outbackground != -1)) + { + resetcolour(dev); + } + + FS_flush(dev); + close(file[dev]->outfd); + } + + if (file[dev]->randomfd >= 0) + { + StringField_destroy(&file[dev]->field); + free(file[dev]->recBuf); + close(file[dev]->randomfd); + } + + if (file[dev]->binaryfd >= 0) + { + close(file[dev]->binaryfd); + } + + if (file[dev]->infd >= 0) + { + close(file[dev]->infd); + } + + free(file[dev]); + file[dev] = (struct FileStream *)0; + FS_errmsg = (const char *)0; + if (--used == 0) + { + free(file); + capacity = 0; + } + + return 0; +} + +#ifdef CONFIG_SERIAL_TERMIOS +int FS_istty(int chn) +{ + return (file[chn] && file[chn]->tty); +} +#endif + +int FS_lock(int chn, off_t offset, off_t length, int mode, int w) +{ + int fd; + struct flock recordLock; + + if (file[chn] == (struct FileStream *)0) + { + FS_errmsg = _("channel not open"); + return -1; + } + + if ((fd = file[chn]->infd) == -1) + { + if ((fd = file[chn]->outfd) == -1) + { + if ((fd = file[chn]->randomfd) == -1) + { + if ((fd = file[chn]->binaryfd) == -1) + assert(0); + } + } + } + + recordLock.l_whence = SEEK_SET; + recordLock.l_start = offset; + recordLock.l_len = length; + switch (mode) + { + case FS_LOCK_SHARED: + recordLock.l_type = F_RDLCK; + break; + + case FS_LOCK_EXCLUSIVE: + recordLock.l_type = F_WRLCK; + break; + + case FS_LOCK_NONE: + recordLock.l_type = F_UNLCK; + break; + + default: + assert(0); + } + + if (fcntl(fd, w ? F_SETLKW : F_SETLK, &recordLock) == -1) + { + FS_errmsg = strerror(errno); + return -1; + } + + return 0; +} + +int FS_truncate(int chn) +{ +#ifdef CONFIG_INTERPRETER_BAS_HAVE_FTRUNCATE + int fd; + off_t o; + + if (file[chn] == (struct FileStream *)0) + { + FS_errmsg = _("channel not open"); + return -1; + } + + if ((fd = file[chn]->infd) == -1) + { + if ((fd = file[chn]->outfd) == -1) + { + if ((fd = file[chn]->randomfd) == -1) + { + if ((fd = file[chn]->binaryfd) == -1) + { + assert(0); + } + } + } + } + + if ((o = lseek(fd, 0, SEEK_CUR)) == (off_t) - 1 || ftruncate(fd, o + 1) == -1) + { + FS_errmsg = strerror(errno); + return -1; + } + + return 0; +#else + FS_errmsg = strerror(ENOSYS); + return -1; +#endif +} + +void FS_shellmode(int dev) +{ +} + +void FS_fsmode(int chn) +{ +} + +void FS_xonxoff(int chn, int on) +{ + /* Not implemented */ +} + +int FS_put(int chn) +{ + ssize_t offset, written; + + if (opened(chn, 2) == -1) + { + return -1; + } + + offset = 0; + while (offset < file[chn]->recLength) + { + written = + write(file[chn]->randomfd, file[chn]->recBuf + offset, + file[chn]->recLength - offset); + if (written == -1) + { + FS_errmsg = strerror(errno); + return -1; + } + else + { + offset += written; + } + } + + FS_errmsg = (const char *)0; + return 0; +} + +int FS_putChar(int dev, char ch) +{ + struct FileStream *f; + + if (opened(dev, 0) == -1) + { + return -1; + } + + f = file[dev]; + if (ch == '\n') + { + f->outPos = 0; + } + + if (ch == '\b' && f->outPos) + { + --f->outPos; + } + + if (f->outSize + 2 >= f->outCapacity && FS_flush(dev) == -1) + { + return -1; + } + + if (f->outLineWidth && f->outPos == f->outLineWidth) + { + f->outBuf[f->outSize++] = '\n'; + f->outPos = 0; + } + + f->outBuf[f->outSize++] = ch; + + if (ch != '\n' && ch != '\b') + { + ++f->outPos; + } + + FS_errmsg = (const char *)0; + return 0; +} + +int FS_putChars(int dev, const char *chars) +{ + while (*chars) + { + if (FS_putChar(dev, *chars++) == -1) + { + return -1; + } + } + + return 0; +} + +int FS_putString(int dev, const struct String *s) +{ + size_t len = s->length; + const char *c = s->character; + + while (len) + { + if (FS_putChar(dev, *c++) == -1) + { + return -1; + } + else + { + --len; + } + } + + return 0; +} + +int FS_putItem(int dev, const struct String *s) +{ + struct FileStream *f; + + if (opened(dev, 0) == -1) + { + return -1; + } + + f = file[dev]; + if (f->outPos && f->outPos + s->length > f->outLineWidth) + { + FS_nextline(dev); + } + + return FS_putString(dev, s); +} + +int FS_putbinaryString(int chn, const struct String *s) +{ + if (opened(chn, 3) == -1) + { + return -1; + } + + if (s->length && + write(file[chn]->binaryfd, s->character, s->length) != s->length) + { + FS_errmsg = strerror(errno); + return -1; + } + + return 0; +} + +int FS_putbinaryInteger(int chn, long int x) +{ + char s[sizeof(long int)]; + int i; + + if (opened(chn, 3) == -1) + { + return -1; + } + + for (i = 0; i < sizeof(x); ++i, x >>= 8) + { + s[i] = (x & 0xff); + } + + if (write(file[chn]->binaryfd, s, sizeof(s)) != sizeof(s)) + { + FS_errmsg = strerror(errno); + return -1; + } + + return 0; +} + +int FS_putbinaryReal(int chn, double x) +{ + if (opened(chn, 3) == -1) + { + return -1; + } + + if (write(file[chn]->binaryfd, &x, sizeof(x)) != sizeof(x)) + { + FS_errmsg = strerror(errno); + return -1; + } + + return 0; +} + +int FS_getbinaryString(int chn, struct String *s) +{ + ssize_t len; + + if (opened(chn, 3) == -1) + { + return -1; + } + + if (s->length && + (len = read(file[chn]->binaryfd, s->character, s->length)) != s->length) + { + if (len == -1) + { + FS_errmsg = strerror(errno); + } + else + { + FS_errmsg = _("End of file"); + } + + return -1; + } + + return 0; +} + +int FS_getbinaryInteger(int chn, long int *x) +{ + char s[sizeof(long int)]; + int i; + ssize_t len; + + if (opened(chn, 3) == -1) + { + return -1; + } + + if ((len = read(file[chn]->binaryfd, s, sizeof(s))) != sizeof(s)) + { + if (len == -1) + { + FS_errmsg = strerror(errno); + } + else + { + FS_errmsg = _("End of file"); + } + + return -1; + } + + *x = (s[sizeof(x) - 1] < 0) ? -1 : 0; + for (i = sizeof(s) - 1; i >= 0; --i) + { + *x = (*x << 8) | (s[i] & 0xff); + } + + return 0; +} + +int FS_getbinaryReal(int chn, double *x) +{ + ssize_t len; + + if (opened(chn, 3) == -1) + { + return -1; + } + + if ((len = read(file[chn]->binaryfd, x, sizeof(*x))) != sizeof(*x)) + { + if (len == -1) + { + FS_errmsg = strerror(errno); + } + else + { + FS_errmsg = _("End of file"); + } + + return -1; + } + + return 0; +} + +int FS_nextcol(int dev) +{ + struct FileStream *f; + + if (opened(dev, 0) == -1) + { + return -1; + } + + f = file[dev]; + if (f->outPos % f->outColWidth + && f->outLineWidth + && ((f->outPos / f->outColWidth + 2) * f->outColWidth) > f->outLineWidth) + { + return FS_putChar(dev, '\n'); + } + + if (!(f->outPos % f->outColWidth) && FS_putChar(dev, ' ') == -1) + { + return -1; + } + + while (f->outPos % f->outColWidth) + { + if (FS_putChar(dev, ' ') == -1) + { + return -1; + } + } + + return 0; +} + +int FS_nextline(int dev) +{ + struct FileStream *f; + + if (opened(dev, 0) == -1) + { + return -1; + } + + f = file[dev]; + if (f->outPos && FS_putChar(dev, '\n') == -1) + { + return -1; + } + + return 0; +} + +int FS_tab(int dev, int position) +{ + struct FileStream *f = file[dev]; + + if (f->outLineWidth && position >= f->outLineWidth) + { + position = f->outLineWidth - 1; + } + + while (f->outPos < (position - 1)) + { + if (FS_putChar(dev, ' ') == -1) + { + return -1; + } + } + + return 0; +} + +int FS_width(int dev, int width) +{ + if (opened(dev, 0) == -1) + { + return -1; + } + + if (width < 0) + { + FS_errmsg = _("negative width"); + return -1; + } + + file[dev]->outLineWidth = width; + return 0; +} + +int FS_zone(int dev, int zone) +{ + if (opened(dev, 0) == -1) + { + return -1; + } + + if (zone <= 0) + { + FS_errmsg = _("non-positive zone width"); + return -1; + } + + file[dev]->outColWidth = zone; + return 0; +} + +int FS_cls(int chn) +{ + struct FileStream *f; + + if (opened(chn, 0) == -1) + { + return -1; + } + + f = file[chn]; + if (!f->tty) + { + FS_errmsg = _("not a terminal"); + return -1; + } + + if (cls(chn) == -1) + { + return -1; + } + + if (FS_flush(chn) == -1) + { + return -1; + } + + f->outPos = 0; + return 0; +} + +int FS_locate(int chn, int line, int column) +{ + struct FileStream *f; + + if (opened(chn, 0) == -1) + { + return -1; + } + + f = file[chn]; + if (!f->tty) + { + FS_errmsg = _("not a terminal"); + return -1; + } + + if (locate(chn, line, column) == -1) + { + return -1; + } + + if (FS_flush(chn) == -1) + { + return -1; + } + + f->outPos = column - 1; + return 0; +} + +int FS_colour(int chn, int foreground, int background) +{ + struct FileStream *f; + + if (opened(chn, 0) == -1) + { + return -1; + } + + f = file[chn]; + if (!f->tty) + { + FS_errmsg = _("not a terminal"); + return -1; + } + + if (colour(chn, foreground, background) == -1) + { + return -1; + } + + f->outforeground = foreground; + f->outbackground = background; + return 0; +} + +int FS_getChar(int dev) +{ + struct FileStream *f; + + if (opened(dev, 1) == -1) + { + return -1; + } + + f = file[dev]; + if (f->inSize == f->inCapacity && refill(dev) == -1) + { + return -1; + } + + FS_errmsg = (const char *)0; + if (f->inSize + 1 == f->inCapacity) + { + char ch = f->inBuf[f->inSize]; + + f->inSize = f->inCapacity = 0; + return ch; + } + else + { + return f->inBuf[f->inSize++]; + } +} + +int FS_get(int chn) +{ + ssize_t offset, rd; + + if (opened(chn, 2) == -1) + { + return -1; + } + + offset = 0; + while (offset < file[chn]->recLength) + { + rd = + read(file[chn]->randomfd, file[chn]->recBuf + offset, + file[chn]->recLength - offset); + if (rd == -1) + { + FS_errmsg = strerror(errno); + return -1; + } + else + { + offset += rd; + } + } + + FS_errmsg = (const char *)0; + return 0; +} + +int FS_inkeyChar(int dev, int ms) +{ + struct FileStream *f; + char c; + ssize_t len; +#ifdef CONFIG_INTERPRETER_BAS_USE_SELECT + fd_set just_infd; + struct timeval timeout; +#endif + + if (opened(dev, 1) == -1) + { + return -1; + } + + f = file[dev]; + if (f->inSize < f->inCapacity) + { + return f->inBuf[f->inSize++]; + } + +#ifdef CONFIG_INTERPRETER_BAS_USE_SELECT + FD_ZERO(&just_infd); + FD_SET(f->infd, &just_infd); + timeout.tv_sec = ms / 1000; + timeout.tv_usec = (ms % 1000) * 1000; + switch (select(f->infd + 1, &just_infd, (fd_set *) 0, (fd_set *) 0, &timeout)) + { + case 1: + { + FS_errmsg = (const char *)0; + len = read(f->infd, &c, 1); + return (len == 1 ? c : -1); + } + + case 0: + { + FS_errmsg = (const char *)0; + return -1; + } + + case -1: + { + FS_errmsg = strerror(errno); + return -1; + } + + default: + assert(0); + } + + return 0; + +#else + FS_errmsg = (const char *)0; + len = read(f->infd, &c, 1); + + if (len == -1) + { + FS_errmsg = strerror(errno); + return -1; + } + + return (len == 1 ? c : -1); +#endif +} + +void FS_sleep(double s) +{ + struct timespec p; + + p.tv_sec = floor(s); + p.tv_nsec = 1000000000 * (s - floor(s)); + + nanosleep(&p, (struct timespec *)0); +} + +int FS_eof(int chn) +{ + struct FileStream *f; + + if (opened(chn, 1) == -1) + { + return -1; + } + + f = file[chn]; + if (f->inSize == f->inCapacity && refill(chn) == -1) + { + return 1; + } + + return 0; +} + +long int FS_loc(int chn) +{ + int fd; + off_t cur, offset = 0; + + if (opened(chn, -1) == -1) + { + return -1; + } + + if (file[chn]->infd != -1) + { + fd = file[chn]->infd; + offset = -file[chn]->inCapacity + file[chn]->inSize; + } + else if (file[chn]->outfd != -1) + { + fd = file[chn]->outfd; + offset = file[chn]->outSize; + } + else if (file[chn]->randomfd != -1) + { + fd = file[chn]->randomfd; + } + else + { + fd = file[chn]->binaryfd; + } + + assert(fd != -1); + if ((cur = lseek(fd, 0, SEEK_CUR)) == -1) + { + FS_errmsg = strerror(errno); + return -1; + } + + return (cur + offset) / file[chn]->recLength; +} + +long int FS_lof(int chn) +{ + off_t curpos; + off_t endpos; + int fd; + + if (opened(chn, -1) == -1) + { + return -1; + } + + if (file[chn]->infd != -1) + { + fd = file[chn]->infd; + } + else if (file[chn]->outfd != -1) + { + fd = file[chn]->outfd; + } + else if (file[chn]->randomfd != -1) + { + fd = file[chn]->randomfd; + } + else + { + fd = file[chn]->binaryfd; + } + + assert(fd != -1); + + /* Get the size of the file */ + /* Save the current file position */ + + curpos = lseek(fd, 0, SEEK_CUR); + if (curpos == (off_t)-1) + { + FS_errmsg = strerror(errno); + return -1; + } + + /* Get the position at the end of the file */ + + endpos = lseek(fd, 0, SEEK_END); + if (endpos == (off_t)-1) + { + FS_errmsg = strerror(errno); + return -1; + } + + /* Restore the file position */ + + curpos = lseek(fd, curpos, SEEK_SET); + if (curpos == (off_t)-1) + { + FS_errmsg = strerror(errno); + return -1; + } + + return (long int)(endpos / file[chn]->recLength); +} + +long int FS_recLength(int chn) +{ + if (opened(chn, 2) == -1) + { + return -1; + } + + return file[chn]->recLength; +} + +void FS_field(int chn, struct String *s, long int position, long int length) +{ + assert(file[chn]); + String_joinField(s, &file[chn]->field, file[chn]->recBuf + position, length); +} + +int FS_seek(int chn, long int record) +{ + if (opened(chn, 2) != -1) + { + if (lseek + (file[chn]->randomfd, (off_t) record * file[chn]->recLength, + SEEK_SET) != -1) + { + return 0; + } + + FS_errmsg = strerror(errno); + } + else if (opened(chn, 4) != -1) + { + if (lseek(file[chn]->binaryfd, (off_t) record, SEEK_SET) != -1) + { + return 0; + } + + FS_errmsg = strerror(errno); + } + + return -1; +} + +int FS_appendToString(int chn, struct String *s, int onl) +{ + size_t new; + char *n; + struct FileStream *f = file[chn]; + int c; + + if (f->tty && f->inSize == f->inCapacity) + { + if (edit(chn, onl) == -1) + { + return (FS_errmsg ? -1 : 0); + } + } + + do + { + n = f->inBuf + f->inSize; + while (1) + { + if (n == f->inBuf + f->inCapacity) + { + break; + } + + c = *n++; + if (c == '\n') + { + break; + } + } + + new = n - (f->inBuf + f->inSize); + if (new) + { + size_t offset = s->length; + + if (String_size(s, offset + new) == -1) + { + FS_errmsg = strerror(errno); + return -1; + } + + memcpy(s->character + offset, f->inBuf + f->inSize, new); + f->inSize += new; + if (*(n - 1) == '\n') + { + if (f->inSize == f->inCapacity) + { + f->inSize = f->inCapacity = 0; + } + + return 0; + } + } + + if ((c = FS_getChar(chn)) >= 0) + { + String_appendChar(s, c); + } + + if (c == '\n') + { + if (s->length >= 2 && s->character[s->length - 2] == '\r') + { + s->character[s->length - 2] = '\n'; + --s->length; + } + + return 0; + } + } + while (c != -1); + + return (FS_errmsg ? -1 : 0); +} + +void FS_closefiles(void) +{ + int i; + + for (i = 0; i < capacity; ++i) + { + if (file[i] && !file[i]->dev) + { + FS_close(i); + } + } +} + +int FS_charpos(int chn) +{ + if (file[chn] == (struct FileStream *)0) + { + FS_errmsg = _("channel not open"); + return -1; + } + + return (file[chn]->outPos); +} + +int FS_copy(const char *from, const char *to) +{ + int infd, outfd; + char buf[4096]; + ssize_t inlen, outlen = -1; + + if ((infd = open(from, O_RDONLY)) == -1) + { + FS_errmsg = strerror(errno); + return -1; + } + + if ((outfd = open(to, O_WRONLY | O_CREAT | O_TRUNC, 0666)) == -1) + { + FS_errmsg = strerror(errno); + return -1; + } + + while ((inlen = read(infd, &buf, sizeof(buf))) > 0) + { + ssize_t off = 0; + + while (inlen && (outlen = write(outfd, &buf + off, inlen)) > 0) + { + off += outlen; + inlen -= outlen; + } + + if (outlen == -1) + { + FS_errmsg = strerror(errno); + close(infd); + close(outfd); + return -1; + } + } + + if (inlen == -1) + { + FS_errmsg = strerror(errno); + close(infd); + close(outfd); + return -1; + } + + if (close(infd) == -1) + { + FS_errmsg = strerror(errno); + close(outfd); + return -1; + } + + if (close(outfd) == -1) + { + FS_errmsg = strerror(errno); + return -1; + } + + return 0; +} + +int FS_portInput(int address) +{ + FS_errmsg = _("Direct port access not available"); + return -1; +} + +int FS_memInput(int address) +{ + FS_errmsg = _("Direct memory access not available"); + return -1; +} + +int FS_portOutput(int address, int value) +{ + FS_errmsg = _("Direct port access not available"); + return -1; +} + +int FS_memOutput(int address, int value) +{ + FS_errmsg = _("Direct memory access not available"); + return -1; +} |