rosella/mods/mod_io.c

225 lines
5.8 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 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));
interp_return_values(state,
cons((fd >= 0) ? fixnum_value(fd) : FALSE_VALUE,
cons(fixnum_value(saved_errno),
NIL)));
}
//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));
interp_return_values(state,
cons((newfd >= 0) ? fixnum_value(newfd) : FALSE_VALUE,
cons(fixnum_value(saved_errno),
NIL)));
}
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));
interp_return_values(state,
cons((newfd >= 0) ? fixnum_value(newfd) : FALSE_VALUE,
cons(fixnum_value(saved_errno),
NIL)));
}
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));
interp_return_values(state,
cons((result >= 0) ? fixnum_value(result) : FALSE_VALUE,
cons(fixnum_value(saved_errno),
NIL)));
}
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));
interp_return_values(state,
cons((result >= 0) ? fixnum_value(result) : FALSE_VALUE,
cons(fixnum_value(saved_errno),
NIL)));
}
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))
{
interp_return_values(state, cons(FALSE_VALUE, cons(fixnum_value(saved_errno), NIL)));
}
else
{
release_assert((result >= 0) && (result <= FIXNUM_MAX));
interp_return_values(state,
cons(fixnum_value(result),
cons(fixnum_value(saved_errno),
NIL)));
}
}
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;
interp_return_values(state,
cons(boolean_value(!result),
cons(fixnum_value(saved_errno),
NIL)));
}
/* vim:set sw=2 expandtab: */