#include #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); static void bi_posix_chdir(interp_state_t *state); static void bi_posix_getcwd(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_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)); register_builtin(BI_IO_POSIX_CHDIR, make_builtin_fn(bi_posix_chdir)); register_builtin(BI_IO_POSIX_GETCWD, make_builtin_fn(bi_posix_getcwd)); } 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)->nbytes)); 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; ssize_t result; int saved_errno; release_assert(is_byte_string(str)); if (!is_nil(CDDR(state->argv.value))) { count = get_fixnum(CAR(CDDR(state->argv.value))); release_assert(is_nil(CDR(CDDR(state->argv.value)))); } else { count = get_byte_string(str)->nbytes; } release_assert((0 <= count) && (count <= get_byte_string(str)->nbytes)); 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))); } static void bi_posix_chdir(interp_state_t *state) { char *pathname; int saved_errno; int result; pathname = value_to_string(CAR(state->argv.value)); release_assert(is_nil(CDR(state->argv.value))); errno = 0; result = chdir(pathname); saved_errno = errno; free(pathname); interp_return_values(state, cons(boolean_value(!result), cons(fixnum_value(saved_errno), NIL))); } static void bi_posix_getcwd(interp_state_t *state) { static char buffer[PATH_MAX]; value_t result_value = FALSE_VALUE; char *result; int saved_errno; release_assert(is_nil(state->argv.value)); errno = 0; result = getcwd(buffer, sizeof buffer); saved_errno = errno; if (result != NULL) { result_value = string_to_value(buffer); } interp_return_values(state, cons(result_value, cons(fixnum_value(saved_errno), NIL))); } /* vim:set sw=2 expandtab: */