221 lines
5.9 KiB
C
221 lines
5.9 KiB
C
#include <assert.h>
|
|
#include <inttypes.h>
|
|
#include <stdbool.h>
|
|
#include <stdlib.h>
|
|
#include <math.h>
|
|
#include <errno.h>
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
|
|
#include "gc.h"
|
|
#include "builtin.h"
|
|
#include "interp.h"
|
|
|
|
#include "mod_io.h"
|
|
|
|
static void bi_posix_open(interp_state_t *state);
|
|
//static void bi_posix_openat(interp_state_t *state);
|
|
static void bi_posix_dup(interp_state_t *state);
|
|
static void bi_posix_dup2(interp_state_t *state);
|
|
static void bi_posix_read(interp_state_t *state);
|
|
static void bi_posix_write(interp_state_t *state);
|
|
static void bi_posix_lseek(interp_state_t *state);
|
|
static void bi_posix_close(interp_state_t *state);
|
|
|
|
void mod_io_init(void)
|
|
{
|
|
register_builtin(BI_IO_POSIX_OPEN, make_builtin_fn(bi_posix_open));
|
|
//register_builtin(BI_IO_POSIX_OPENAT, make_builtin_fn(bi_posix_openat));
|
|
register_builtin(BI_IO_POSIX_OPENAT, UNDEFINED);
|
|
|
|
register_builtin(BI_IO_POSIX_DUP, make_builtin_fn(bi_posix_dup));
|
|
register_builtin(BI_IO_POSIX_DUP2, make_builtin_fn(bi_posix_dup2));
|
|
|
|
register_builtin(BI_IO_POSIX_READ, make_builtin_fn(bi_posix_read));
|
|
register_builtin(BI_IO_POSIX_WRITE, make_builtin_fn(bi_posix_write));
|
|
register_builtin(BI_IO_POSIX_LSEEK, make_builtin_fn(bi_posix_lseek));
|
|
|
|
register_builtin(BI_IO_POSIX_CLOSE, make_builtin_fn(bi_posix_close));
|
|
}
|
|
|
|
static void simple_return(interp_state_t *state, value_t rval)
|
|
{
|
|
state->lambda.value = state->k.value;
|
|
state->argv.value = rval;
|
|
state->k.value = FALSE_VALUE;
|
|
state->ctx.value = FALSE_VALUE;
|
|
}
|
|
|
|
static void simple_return2(interp_state_t *state, value_t v1, value_t v2)
|
|
{
|
|
simple_return(state, cons(v1, cons(v2, NIL)));
|
|
}
|
|
|
|
static void bi_posix_open(interp_state_t *state)
|
|
{
|
|
char *pathname;
|
|
int flags;
|
|
mode_t mode;
|
|
int fd;
|
|
int saved_errno;
|
|
|
|
release_assert(is_nil(CDDR(state->argv.value)) || is_nil(CDR(_CDDR(state->argv.value))));
|
|
|
|
pathname = value_to_string(CAR(state->argv.value));
|
|
flags = get_fixnum(CAR(_CDR(state->argv.value)));
|
|
|
|
if (!is_nil(_CDDR(state->argv.value)))
|
|
{
|
|
mode = get_fixnum(CAR(_CDDR(state->argv.value)));
|
|
}
|
|
else
|
|
{
|
|
release_assert((flags & O_CREAT) == 0);
|
|
mode = 0;
|
|
}
|
|
|
|
errno = 0;
|
|
fd = open(pathname, flags, mode);
|
|
saved_errno = errno;
|
|
free(pathname);
|
|
|
|
release_assert(is_valid_fixnum(fd));
|
|
release_assert(is_valid_fixnum(saved_errno));
|
|
|
|
simple_return2(state, (fd >= 0) ? fixnum_value(fd) : FALSE_VALUE,
|
|
fixnum_value(saved_errno));
|
|
}
|
|
|
|
//static void bi_posix_openat(interp_state_t *state) {}
|
|
|
|
static void bi_posix_dup(interp_state_t *state)
|
|
{
|
|
int oldfd = get_fixnum(CAR(state->argv.value));
|
|
int newfd;
|
|
int saved_errno;
|
|
|
|
release_assert(is_nil(_CDR(state->argv.value)));
|
|
|
|
errno = 0;
|
|
newfd = dup(oldfd);
|
|
saved_errno = errno;
|
|
|
|
release_assert(is_valid_fixnum(newfd));
|
|
release_assert(is_valid_fixnum(saved_errno));
|
|
|
|
simple_return2(state, (newfd >= 0) ? fixnum_value(newfd) : FALSE_VALUE,
|
|
fixnum_value(saved_errno));
|
|
}
|
|
|
|
static void bi_posix_dup2(interp_state_t *state)
|
|
{
|
|
int oldfd = get_fixnum(CAR(state->argv.value));
|
|
int newfd = get_fixnum(CAR(_CDR(state->argv.value)));
|
|
int saved_errno;
|
|
|
|
release_assert(is_nil(_CDDR(state->argv.value)));
|
|
|
|
errno = 0;
|
|
newfd = dup2(oldfd, newfd);
|
|
saved_errno = errno;
|
|
|
|
release_assert(is_valid_fixnum(newfd));
|
|
release_assert(is_valid_fixnum(saved_errno));
|
|
|
|
simple_return2(state, (newfd >= 0) ? fixnum_value(newfd) : FALSE_VALUE,
|
|
fixnum_value(saved_errno));
|
|
}
|
|
|
|
static void bi_posix_read(interp_state_t *state)
|
|
{
|
|
int fd = get_fixnum(CAR(state->argv.value));
|
|
value_t str = CAR(_CDR(state->argv.value));
|
|
fixnum_t count = get_fixnum(CAR(_CDDR(state->argv.value)));
|
|
ssize_t result;
|
|
int saved_errno;
|
|
|
|
release_assert(is_byte_string(str));
|
|
release_assert(is_nil(_CDR(_CDDR(state->argv.value))));
|
|
release_assert((0 <= count) && (count <= _get_byte_string(str)->size));
|
|
|
|
errno = 0;
|
|
result = read(fd, _get_byte_string(str)->bytes, count);
|
|
saved_errno = errno;
|
|
|
|
release_assert(is_valid_fixnum(result));
|
|
release_assert(is_valid_fixnum(saved_errno));
|
|
|
|
simple_return2(state, (result >= 0) ? fixnum_value(result) : FALSE_VALUE,
|
|
fixnum_value(saved_errno));
|
|
}
|
|
|
|
static void bi_posix_write(interp_state_t *state)
|
|
{
|
|
int fd = get_fixnum(CAR(state->argv.value));
|
|
value_t str = CAR(_CDR(state->argv.value));
|
|
fixnum_t count = get_fixnum(CAR(_CDDR(state->argv.value)));
|
|
ssize_t result;
|
|
int saved_errno;
|
|
|
|
release_assert(is_byte_string(str));
|
|
release_assert(is_nil(_CDR(_CDDR(state->argv.value))));
|
|
release_assert((0 <= count) && (count <= _get_byte_string(str)->size));
|
|
|
|
errno = 0;
|
|
result = write(fd, _get_byte_string(str)->bytes, count);
|
|
saved_errno = errno;
|
|
|
|
release_assert(is_valid_fixnum(result));
|
|
release_assert(is_valid_fixnum(saved_errno));
|
|
|
|
simple_return2(state, (result >= 0) ? fixnum_value(result) : FALSE_VALUE,
|
|
fixnum_value(saved_errno));
|
|
}
|
|
|
|
static void bi_posix_lseek(interp_state_t *state)
|
|
{
|
|
int fd = get_fixnum(CAR(state->argv.value));
|
|
fixnum_t off = get_fixnum(CAR(_CDR(state->argv.value)));
|
|
fixnum_t whence = get_fixnum(CAR(_CDDR(state->argv.value)));
|
|
off_t result;
|
|
int saved_errno;
|
|
|
|
release_assert(is_nil(_CDR(_CDDR(state->argv.value))));
|
|
|
|
errno = 0;
|
|
result = lseek(fd, off, whence);
|
|
saved_errno = errno;
|
|
|
|
release_assert(is_valid_fixnum(saved_errno));
|
|
|
|
if (result == (off_t)(-1))
|
|
{
|
|
simple_return2(state, FALSE_VALUE, fixnum_value(saved_errno));
|
|
}
|
|
else
|
|
{
|
|
release_assert((result >= 0) && (result <= FIXNUM_MAX));
|
|
simple_return2(state, fixnum_value(result), fixnum_value(saved_errno));
|
|
}
|
|
}
|
|
|
|
static void bi_posix_close(interp_state_t *state)
|
|
{
|
|
int fd = get_fixnum(CAR(state->argv.value));
|
|
ssize_t result;
|
|
int saved_errno;
|
|
|
|
release_assert(is_nil(_CDR(state->argv.value)));
|
|
|
|
errno = 0;
|
|
result = close(fd);
|
|
saved_errno = errno;
|
|
|
|
simple_return2(state, boolean_value(!result), fixnum_value(saved_errno));
|
|
}
|
|
|
|
/* vim:set sw=2 expandtab: */
|