nuttx-apps/interpreters/bas/fs.c

2196 lines
42 KiB
C
Raw Normal View History

/****************************************************************************
* apps/examples/interpreters/bas/value.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
****************************************************************************/
2014-10-27 22:37:19 +01:00
#include <nuttx/config.h>
#include "config.h"
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#ifdef HAVE_GETTEXT
# include <libintl.h>
# define _(String) gettext(String)
#else
# define _(String) String
#endif
#include <math.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <time.h>
#ifdef HAVE_TERMCAP_H
# include <termcap.h>
#endif
#ifdef HAVE_CURSES_H
# include <curses.h>
#endif
#include <unistd.h>
#include "fs.h"
#ifdef USE_DMALLOC
# include "dmalloc.h"
#endif
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define LINEWIDTH 80
#define COLWIDTH 14
/****************************************************************************
* Private Data
****************************************************************************/
static struct FileStream **file;
static int capacity;
static int used;
#ifdef CONFIG_SERIAL_TERMIOS
static struct termios origMode;
#endif
static struct termios rawMode;
static const int open_mode[4] = { 0, O_RDONLY, O_WRONLY, O_RDWR };
2014-10-27 22:37:19 +01:00
#ifdef CONFIG_INTERPRETER_BAS_HAVE_SIGINT
static struct sigaction old_sigint;
#endif
#ifdef CONFIG_INTERPRETER_BAS_HAVE_SIGQUIT
static struct sigaction old_sigquit;
#endif
#ifdef CONFIG_SERIAL_TERMIOS
static int termchannel;
#endif
const char *FS_errmsg;
static char FS_errmsgbuf[80];
volatile int FS_intr;
#ifdef HAVE_TGETENT
static char *term;
static char entrybuf[2048];
static char *cap;
static char *cl;
static char *cm;
static char *ce;
static char *cr;
static char *md;
static char *me;
static char *AF;
static char *AB;
static int Co;
static int NC;
#endif
/****************************************************************************
* 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;
}
if (ch == rawMode.c_cc[VERASE])
{
if (f->inCapacity)
{
if (f->inBuf[f->inCapacity - 1] >= '\0' &&
f->inBuf[f->inCapacity - 1] < ' ')
{
FS_putChars(chn, "\b\b \b\b");
}
else
{
FS_putChars(chn, "\b \b");
}
--f->inCapacity;
}
}
else if ((f->inCapacity + 1) < sizeof(f->inBuf))
{
if (ch != '\n')
{
if (ch >= '\0' && ch < ' ')
{
FS_putChar(chn, '^');
FS_putChar(chn, ch ? (ch + 'a' - 1) : '@');
}
else
{
FS_putChar(chn, ch);
}
}
else if (onl)
{
FS_putChar(chn, '\n');
}
f->inBuf[f->inCapacity++] = ch;
}
}
while (ch != '\n');
return 0;
}
#if defined(HAVE_TGETENT) || defined(CONFIG_SERIAL_TERMIOS)
static int outc(int ch)
{
struct FileStream *f;
if (opened(termchannel, 0) == -1)
{
return -1;
}
f = file[termchannel];
if (f->outSize + 1 >= f->outCapacity && FS_flush(termchannel) == -1)
{
return -1;
}
f->outBuf[f->outSize++] = ch;
FS_errmsg = (const char *)0;
return ch;
}
#endif
#ifdef HAVE_TGETENT
static int mytputs(const char *str, int affcnt, int (*out) (int))
{
# ifdef TPUTS_RETURNS_VOID
tputs(str, affcnt, out);
return 0;
# else
return tputs(str, affcnt, out);
# endif
}
#ifdef CONFIG_SERIAL_TERMIOS
static int initTerminal(int chn)
{
static int init = 0;
if (!init)
{
termchannel = chn;
if ((term = getenv("TERM")) == (char *)0)
{
FS_errmsg = _("environment variable TERM is not set");
return -1;
}
switch (tgetent(entrybuf, term))
{
case -1:
{
FS_errmsg = _("reading terminal description failed");
return -1;
}
case 0:
{
sprintf(FS_errmsgbuf, _("unknown terminal type %s"), term);
FS_errmsg = FS_errmsgbuf;
return -1;
}
case 1:
{
cl = tgetstr("cl", &cap);
cm = tgetstr("cm", &cap);
ce = tgetstr("ce", &cap);
cr = tgetstr("cr", &cap);
md = tgetstr("md", &cap);
me = tgetstr("me", &cap);
AF = tgetstr("AF", &cap);
AB = tgetstr("AB", &cap);
Co = tgetnum("Co");
if ((NC = tgetnum("NC")) == -1)
{
NC = 0;
}
return 0;
}
}
init = 1;
}
return 0;
}
#endif /* CONFIG_SERIAL_TERMIOS */
static int cls(int chn)
{
if (cl == (char *)0)
{
sprintf(FS_errmsgbuf,
_("terminal type %s can not clear the screen"), term);
FS_errmsg = FS_errmsgbuf;
return -1;
}
if (mytputs(cl, 0, outc) == -1)
{
return -1;
}
return 0;
}
static int locate(int chn, int line, int column)
{
termchannel = chn;
if (cm == (char *)0)
{
sprintf(FS_errmsgbuf,
_("terminal type %s can not position the cursor"), term);
FS_errmsg = FS_errmsgbuf;
return -1;
}
if (mytputs(tgoto(cm, column - 1, line - 1), 0, outc) == -1)
{
return -1;
}
return 0;
}
static int colour(int chn, int foreground, int background)
{
if (AF && AB && Co >= 8)
{
static int map[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
if (foreground != -1)
{
if (md && me && !(NC & 32))
{
if (foreground > 7 && file[chn]->outforeground <= 7)
{
if (mytputs(md, 0, outc) == -1)
{
return -1;
}
/* all attributes are gone now, need to set background
* again */
if (background == -1)
{
background = file[chn]->outbackground;
}
}
else if (foreground <= 7 && file[chn]->outforeground > 7)
{
if (mytputs(me, 0, outc) == -1)
{
return -1;
}
}
}
if (mytputs(tgoto(AF, 0, map[foreground & 7]), 0, outc) == -1)
{
return -1;
}
}
if (background != -1)
{
if (mytputs(tgoto(AB, 0, map[background & 7]), 0, outc) == -1)
{
return -1;
}
}
}
return 0;
}
static int resetcolour(int chn)
{
if (me)
{
mytputs(me, 0, outc);
}
if (ce)
{
mytputs(ce, 0, outc);
}
return 0;
}
#ifdef CONFIG_SERIAL_TERMIOS
static void carriage_return(int chn)
{
if (cr)
{
mytputs(cr, 0, outc);
}
else
{
outc('\r');
}
outc('\n');
}
#endif /* CONFIG_SERIAL_TERMIOS */
#else /* HAVE_TGETENT */
#ifdef CONFIG_SERIAL_TERMIOS
static int initTerminal(int chn)
{
termchannel = chn;
return 0;
}
#endif /* CONFIG_SERIAL_TERMIOS */
static int cls(int chn)
{
FS_errmsg = _("This installation does not support terminal handling");
return -1;
}
static int locate(int chn, int line, int column)
{
FS_errmsg = _("This installation does not support terminal handling");
return -1;
}
static int colour(int chn, int foreground, int background)
{
FS_errmsg = _("This installation does not support terminal handling");
return -1;
}
static int resetcolour(int chn)
{
return 0;
}
#ifdef CONFIG_SERIAL_TERMIOS
static void carriage_return(int chn)
{
outc('\r');
outc('\n');
}
#endif /* CONFIG_SERIAL_TERMIOS */
#endif /* HAVE_TGETENT */
2014-10-27 22:37:19 +01:00
#ifdef CONFIG_INTERPRETER_BAS_HAVE_SIGINT
static void sigintr(int sig)
{
FS_intr = 1;
FS_allowIntr(0);
}
2014-10-27 22:37:19 +01:00
#endif
/****************************************************************************
* 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
if ((file[chn]->tty = (infd == 0 ? isatty(infd) && isatty(outfd) : 0)))
{
if (tcgetattr(infd, &origMode) == -1)
{
FS_errmsg = strerror(errno);
free(file[chn]);
file[chn] = (struct FileStream *)0;
return -1;
}
rawMode = origMode;
rawMode.c_lflag &= ~(ICANON | ECHO); /* IEXTEN would disable IUCLC,
* breaking UC only terminals */
rawMode.c_cc[VMIN] = 1;
rawMode.c_cc[VTIME] = 0;
rawMode.c_oflag &= ~ONLCR;
if (tcsetattr(infd, TCSADRAIN, &rawMode) == -1)
{
FS_errmsg = strerror(errno);
free(file[chn]);
file[chn] = (struct FileStream *)0;
return -1;
}
initTerminal(chn);
}
#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);
}
#ifdef CONFIG_SERIAL_TERMIOS
if (file[dev]->tty)
{
tcsetattr(file[dev]->infd, TCSADRAIN, &origMode);
}
#endif
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)
{
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;
}
void FS_shellmode(int dev)
{
2014-10-27 22:37:19 +01:00
#if defined(CONFIG_INTERPRETER_BAS_HAVE_SIGINT) || defined(CONFIG_INTERPRETER_BAS_HAVE_SIGQUIT)
struct sigaction interrupt;
2014-10-27 22:37:19 +01:00
#endif
#ifdef CONFIG_SERIAL_TERMIOS
if (file[dev]->tty)
{
tcsetattr(file[dev]->infd, TCSADRAIN, &origMode);
}
#endif
2014-10-27 22:37:19 +01:00
#if defined(CONFIG_INTERPRETER_BAS_HAVE_SIGINT) || defined(CONFIG_INTERPRETER_BAS_HAVE_SIGQUIT)
interrupt.sa_flags = 0;
sigemptyset(&interrupt.sa_mask);
interrupt.sa_handler = SIG_IGN;
# ifdef CONFIG_INTERPRETER_BAS_HAVE_SIGINT
sigaction(SIGINT, &interrupt, &old_sigint);
# endif
# ifdef CONFIG_INTERPRETER_BAS_HAVE_SIGQUIT
sigaction(SIGQUIT, &interrupt, &old_sigquit);
# endif
2014-10-27 22:37:19 +01:00
#endif
}
void FS_fsmode(int chn)
{
#ifdef CONFIG_SERIAL_TERMIOS
if (file[chn]->tty)
{
tcsetattr(file[chn]->infd, TCSADRAIN, &rawMode);
}
#endif
2014-10-27 22:37:19 +01:00
#ifdef CONFIG_INTERPRETER_BAS_HAVE_SIGINT
sigaction(SIGINT, &old_sigint, (struct sigaction *)0);
2014-10-27 22:37:19 +01:00
#endif
#ifdef CONFIG_INTERPRETER_BAS_HAVE_SIGQUIT
sigaction(SIGQUIT, &old_sigquit, (struct sigaction *)0);
2014-10-27 22:37:19 +01:00
#endif
}
void FS_xonxoff(int chn, int on)
{
#ifdef CONFIG_SERIAL_TERMIOS
if (file[chn]->tty)
{
if (on)
{
rawMode.c_iflag |= (IXON | IXOFF);
}
else
{
rawMode.c_iflag &= ~(IXON | IXOFF);
}
tcsetattr(file[chn]->infd, TCSADRAIN, &rawMode);
}
#endif
}
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)
{
#ifdef CONFIG_SERIAL_TERMIOS
if (FS_istty(dev))
{
carriage_return(dev);
}
else
#endif
{
f->outBuf[f->outSize++] = '\n';
}
f->outPos = 0;
}
#ifdef CONFIG_SERIAL_TERMIOS
if (FS_istty(dev) && ch == '\n')
{
carriage_return(dev);
}
else
#endif
{
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 USE_SELECT
fd_set just_infd;
struct timeval timeout;
#elif defined(CONFIG_SERIAL_TERMIOS)
struct termios timedread;
#endif
if (opened(dev, 1) == -1)
{
return -1;
}
f = file[dev];
if (f->inSize < f->inCapacity)
{
return f->inBuf[f->inSize++];
}
#ifdef 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
#ifdef CONFIG_SERIAL_TERMIOS
timedread = rawMode;
timedread.c_cc[VMIN] = 0;
timedread.c_cc[VTIME] = (ms ? ms : 100) / 100;
if (tcsetattr(f->infd, TCSADRAIN, &timedread) == -1)
{
FS_errmsg = strerror(errno);
return -1;
}
#endif
FS_errmsg = (const char *)0;
len = read(f->infd, &c, 1);
#ifdef CONFIG_SERIAL_TERMIOS
tcsetattr(f->infd, TCSADRAIN, &rawMode);
#endif
if (len == -1)
{
FS_errmsg = strerror(errno);
return -1;
}
return (len == 1 ? c : -1);
#endif
}
void FS_sleep(double s)
{
#ifdef HAVE_NANOSLEEP
struct timespec p;
p.tv_sec = floor(s);
p.tv_nsec = 1000000000 * (s - floor(s));
nanosleep(&p, (struct timespec *)0);
#else
sleep((int)s);
#endif
}
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)
{
struct stat buf;
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);
if (fstat(fd, &buf) == -1)
{
FS_errmsg = strerror(errno);
return -1;
}
return buf.st_size / 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;
}
if (s->length >= 2 && s->character[s->length - 2] == '\r')
{
s->character[s->length - 2] = '\n';
--s->length;
}
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;
}
void FS_allowIntr(int on)
{
2014-10-27 22:37:19 +01:00
#ifdef CONFIG_INTERPRETER_BAS_HAVE_SIGINT
struct sigaction breakact;
breakact.sa_handler = on ? sigintr : SIG_IGN;
sigemptyset(&breakact.sa_mask);
sigaddset(&breakact.sa_mask, SIGINT);
breakact.sa_flags = 0;
sigaction(SIGINT, &breakact, (struct sigaction *)0);
2014-10-27 22:37:19 +01:00
#endif
}