#include #include #include #include #include #include #include #include #include #include #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: */