123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347 |
- /* Part of Scheme 48 1.9. See file COPYING for notices and license.
- *
- * Authors: Richard Kelsey, Jonathan Rees, Mike Sperber, Marcus Crestani
- */
- /* NB: sysdep.h must come first in order for LFS to be enabled
- properly */
- #include "sysdep.h"
- #include <unistd.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <sys/time.h>
- #include <errno.h> /* for errno, (POSIX?/ANSI) */
- #include <string.h> /* FD_ZERO sometimes needs this */
- #include <locale.h> /* ISO C99 */
- #ifdef HAVE_POLL_H
- #include <poll.h>
- #endif
- #include "c-mods.h"
- #include "scheme48vm.h"
- #include "event.h"
- #include "fd-io.h"
- #include "unix.h"
- /* Non-blocking I/O on file descriptors.
- There appear to be two ways to get non-blocking input and output. One
- is to open files with the O_NONBLOCK flag (and to use fcntl() to do the
- same to stdin and stdout), the other is to call select() on each file
- descriptor before doing the I/O operation. O_NONBLOCK has the problem
- of being a property of the file descriptor, and its use with stdin and
- stdout can lead to horrible results.
- We use a mixture of both. For input files we call select() before doing
- a read(), because read() will return immediately if there are any bytes
- available at all, and using O_NONBLOCK on stdin is a very bad idea.
- Output files are opened using O_NONBLOCK and stdout is left alone.
- */
- int
- ps_open_fd(char *filename, psbool is_input, long *status)
- {
- #define FILE_NAME_SIZE 1024
- #define PERMISSION 0666 /* read and write for everyone */
- char filename_temp[FILE_NAME_SIZE];
- char *expanded;
- extern char *s48_expand_file_name(char *, char *, int);
- int flags;
- mode_t mode;
- expanded = s48_expand_file_name(filename, filename_temp, FILE_NAME_SIZE);
- if (expanded == NULL)
- return -1;
- if (is_input) {
- flags = O_RDONLY;
- mode = 0; }
- else {
- flags = O_WRONLY | O_CREAT | O_TRUNC | O_NONBLOCK;
- mode = PERMISSION; }
- /* keep trying if interrupted */
- while(1) {
- int fd = open(expanded, flags, mode);
- if (fd != -1) {
- *status = NO_ERRORS;
- return fd; }
- else if (errno != EINTR) {
- *status = errno;
- return -1; }
- }
- }
- int
- ps_close_fd(long fd_as_long)
- {
- int fd = (int)fd_as_long;
- /* keep retrying if interrupted */
- while(1) {
- int status = close(fd);
- if (status != -1) {
- s48_remove_fd(fd);
- return NO_ERRORS; }
- else if (errno != EINTR)
- return errno;
- }
- }
- psbool ps_check_fd(long fd_as_long, psbool is_read, long *status)
- {
- int fd = (int)fd_as_long;
- int ready;
- #if defined HAVE_GLIB
- struct pollfd pollfds[1];
- pollfds[0].fd = fd;
- pollfds[0].events = is_read? POLLIN : POLLOUT;
- *status = NO_ERRORS;
- while(1) {
- ready = poll(pollfds, 1, 0);
- #elif defined HAVE_POLL
- struct pollfd pollfds[1];
- pollfds[0].fd = fd;
- pollfds[0].events = is_read? POLLIN : POLLOUT;
- *status = NO_ERRORS;
- while(1) {
- ready = poll(pollfds, 1, 0);
- #elif defined HAVE_SELECT
- struct timeval timeout;
- fd_set fds;
- FD_ZERO(&fds);
- FD_SET(fd, &fds);
- timerclear(&timeout);
- *status = NO_ERRORS;
- while(1) {
- ready = select(fd + 1,
- is_read ? &fds : NULL,
- is_read ? NULL : &fds,
- &fds,
- &timeout);
- #endif /* HAVE_SELECT */
- if (ready == 0)
- return PSFALSE;
- /* Mike has witnessed it return 2 on Mac OS X. */
- else if (ready >= 1)
- return PSTRUE;
- else if (errno != EINTR) {
- *status = errno;
- return PSFALSE; } }
- }
- long
- ps_read_fd(long fd_as_long, char *buffer, long max, psbool waitp,
- psbool *eofp, psbool *pending, long *status)
- {
- int got, ready;
- void *buf = (void *)buffer;
- int fd = (int)fd_as_long;
- #if defined HAVE_GLIB
- struct pollfd pollfds[1];
- pollfds[0].fd = fd;
- pollfds[0].events = POLLIN;
- /* for the normal return */
- *eofp = PSFALSE;
- *pending = PSFALSE;
- *status = NO_ERRORS;
- while(1) {
- ready = poll(pollfds, 1, 0);
- #elif defined HAVE_POLL
- struct pollfd pollfds[1];
- pollfds[0].fd = fd;
- pollfds[0].events = POLLIN;
- /* for the normal return */
- *eofp = PSFALSE;
- *pending = PSFALSE;
- *status = NO_ERRORS;
- while(1) {
- ready = poll(pollfds, 1, 0);
- #elif HAVE_SELECT
- struct timeval timeout;
- fd_set readfds;
- FD_ZERO(&readfds);
- FD_SET(fd, &readfds);
- timerclear(&timeout);
- /* for the normal return */
- *eofp = PSFALSE;
- *pending = PSFALSE;
- *status = NO_ERRORS;
- while(1) {
- ready = select(fd + 1, &readfds, NULL, &readfds, &timeout);
- #endif /* HAVE_SELECT */
- if (ready == 0) {
- if (!waitp)
- return 0;
- else if (s48_add_pending_fd(fd, PSTRUE)) {
- *pending = PSTRUE;
- return 0; }
- else {
- *status = ENOMEM; /* as close as POSIX gets */
- return 0; }}
- else if (ready == -1) {
- if (errno != EINTR) {
- *status = errno;
- return 0; } }
- else { /* characters waiting */
- got = read(fd, buf, max);
- if (got > 0) { /* all is well */
- return got; }
- else if (got == 0) { /* end of file */
- *eofp = PSTRUE;
- return 0; }
- else if (errno == EINTR) { /* HCC */
- return 0; }
- else if (errno == EAGAIN) { /* HCC */
- if (!waitp)
- return 0;
- else if (s48_add_pending_fd(fd, PSTRUE)) {
- *pending = PSTRUE;
- return 0; }
- else {
- *status = ENOMEM; /* as close as POSIX gets */
- return 0; } }
- else {
- *status = errno;
- return 0; } } }
- }
- long
- ps_write_fd(long fd_as_long, char *buffer, long max, psbool *pending, long *status)
- {
- int sent;
- int fd = (int)fd_as_long;
- void *buf = (void *)buffer;
- *pending = PSFALSE;
- *status = NO_ERRORS;
- sent = write(fd, buf, max);
- if (sent > 0)
- {}
- else if (errno == EINTR || errno == EAGAIN) { /* HCC */
- if (s48_add_pending_fd(fd, PSFALSE))
- *pending = PSTRUE;
- else
- *status = ENOMEM; /* as close as POSIX gets */
- sent = 0; }
- else {
- *status = errno;
- sent = 0; }
- return sent;
- }
- long
- ps_io_buffer_size(void)
- {
- return 4096;
- }
- psbool
- ps_io_crlf_p(void)
- {
- return PSFALSE;
- }
- char *
- ps_console_encoding(long fd_as_long)
- {
- static char *encoding_STDIN = NULL;
- static char *encoding_STDOUT = NULL;
- static char *encoding_STDERR = NULL;
- static char setlocale_called = PSFALSE;
- char *codeset;
- char** encoding_p;
- if (fd_as_long == STDIN_FD())
- encoding_p = &encoding_STDIN;
- else if (fd_as_long == STDOUT_FD())
- encoding_p = &encoding_STDOUT;
- else if (fd_as_long == STDERR_FD())
- encoding_p = &encoding_STDERR;
-
- /* Mike has no clue what the rationale for needing this is. */
- if (!setlocale_called)
- {
- setlocale(LC_CTYPE, "");
- setlocale_called = PSTRUE;
- }
- if (*encoding_p == NULL)
- {
- codeset = nl_langinfo(CODESET); /* this ain't reentrant */
- *encoding_p = malloc(strlen(codeset) + 1);
- if (*encoding_p == NULL)
- return NULL;
- strcpy(*encoding_p, codeset);
- }
- return *encoding_p;
- }
- long
- ps_abort_fd_op(long fd_as_long)
- {
- int fd = (int)fd_as_long;
- if (!s48_remove_fd(fd))
- fprintf(stderr, "Error: ps_abort_fd_op, no pending operation on fd %d\n",
- fd);
- return 0; /* because we do not actually do any I/O in parallel the
- status is always zero: no characters transfered. */
- }
- /*
- * This checks that fd's destined for output channels are marked
- * as nonblocking. Stdout and stderr are a special case because
- * we do not want to screw up the shell, if we were invoked from
- * one.
- */
- s48_ref_t
- s48_add_channel_2(s48_call_t call, s48_ref_t mode, s48_ref_t id, long fd)
- {
- if (s48_eq_p_2(call, mode, s48_channel_status_output_2(call))
- && fd != 1
- && fd != 2) {
- int flags;
- RETRY_OR_RAISE_NEG(flags, fcntl(fd, F_GETFL));
- if ((flags & O_NONBLOCK) == 0)
- fprintf(stderr,
- "Warning: output channel file descriptor %d is not non-blocking\n",
- (int) fd); }
- return s48_make_local_ref(call, s48_really_add_channel(s48_deref(mode), s48_deref(id), fd));
- }
- s48_ref_t
- s48_set_channel_os_index_2(s48_call_t call, s48_ref_t channel, long fd)
- {
- /* back to the VM */
- return s48_make_local_ref(call, s48_set_channel_os_index(s48_deref(channel), fd));
- }
|