225 lines
5.8 KiB
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: */
|