1995-08-09 08:06:35 -07:00
|
|
|
/***********************************************************************/
|
|
|
|
/* */
|
2011-07-27 07:17:02 -07:00
|
|
|
/* OCaml */
|
1995-08-09 08:06:35 -07:00
|
|
|
/* */
|
|
|
|
/* Xavier Leroy, projet Cristal, INRIA Rocquencourt */
|
|
|
|
/* */
|
1996-04-30 07:53:58 -07:00
|
|
|
/* Copyright 1996 Institut National de Recherche en Informatique et */
|
1999-11-17 10:59:06 -08:00
|
|
|
/* en Automatique. All rights reserved. This file is distributed */
|
2001-12-07 05:41:02 -08:00
|
|
|
/* under the terms of the GNU Library General Public License, with */
|
|
|
|
/* the special exception on linking described in file ../LICENSE. */
|
1995-08-09 08:06:35 -07:00
|
|
|
/* */
|
|
|
|
/***********************************************************************/
|
|
|
|
|
1995-05-04 03:15:53 -07:00
|
|
|
/* Buffered input/output. */
|
|
|
|
|
|
|
|
#include <errno.h>
|
|
|
|
#include <fcntl.h>
|
1998-10-07 12:01:42 -07:00
|
|
|
#include <limits.h>
|
1995-05-04 03:15:53 -07:00
|
|
|
#include <string.h>
|
2002-03-02 01:16:39 -08:00
|
|
|
#include <sys/types.h>
|
2014-12-27 06:41:49 -08:00
|
|
|
#include "caml/config.h"
|
1996-02-21 02:49:46 -08:00
|
|
|
#ifdef HAS_UNISTD
|
1995-05-04 03:15:53 -07:00
|
|
|
#include <unistd.h>
|
1996-02-21 02:49:46 -08:00
|
|
|
#endif
|
2013-12-03 06:43:02 -08:00
|
|
|
#ifdef __CYGWIN__
|
|
|
|
#include </usr/include/io.h>
|
|
|
|
#endif
|
2014-12-27 06:41:49 -08:00
|
|
|
#include "caml/alloc.h"
|
|
|
|
#include "caml/custom.h"
|
|
|
|
#include "caml/fail.h"
|
|
|
|
#include "caml/io.h"
|
|
|
|
#include "caml/memory.h"
|
|
|
|
#include "caml/misc.h"
|
|
|
|
#include "caml/mlvalues.h"
|
|
|
|
#include "caml/signals.h"
|
|
|
|
#include "caml/sys.h"
|
1995-05-04 03:15:53 -07:00
|
|
|
|
1996-04-18 09:29:57 -07:00
|
|
|
#ifndef SEEK_SET
|
|
|
|
#define SEEK_SET 0
|
|
|
|
#define SEEK_CUR 1
|
|
|
|
#define SEEK_END 2
|
|
|
|
#endif
|
|
|
|
|
1997-08-29 08:37:22 -07:00
|
|
|
/* Hooks for locking channels */
|
1995-05-04 03:15:53 -07:00
|
|
|
|
2003-12-29 14:15:02 -08:00
|
|
|
CAMLexport void (*caml_channel_mutex_free) (struct channel *) = NULL;
|
|
|
|
CAMLexport void (*caml_channel_mutex_lock) (struct channel *) = NULL;
|
|
|
|
CAMLexport void (*caml_channel_mutex_unlock) (struct channel *) = NULL;
|
|
|
|
CAMLexport void (*caml_channel_mutex_unlock_exn) (void) = NULL;
|
1997-08-29 08:37:22 -07:00
|
|
|
|
2001-10-09 08:14:01 -07:00
|
|
|
/* List of opened channels */
|
2003-12-29 14:15:02 -08:00
|
|
|
CAMLexport struct channel * caml_all_opened_channels = NULL;
|
2001-10-09 08:14:01 -07:00
|
|
|
|
1997-08-29 08:37:22 -07:00
|
|
|
/* Basic functions over type struct channel *.
|
|
|
|
These functions can be called directly from C.
|
|
|
|
No locking is performed. */
|
1997-05-13 07:05:44 -07:00
|
|
|
|
1998-02-26 04:51:39 -08:00
|
|
|
/* Functions shared between input and output */
|
2000-01-07 08:05:19 -08:00
|
|
|
|
2003-12-29 14:15:02 -08:00
|
|
|
CAMLexport struct channel * caml_open_descriptor_in(int fd)
|
1995-05-04 03:15:53 -07:00
|
|
|
{
|
|
|
|
struct channel * channel;
|
|
|
|
|
2003-12-31 06:20:40 -08:00
|
|
|
channel = (struct channel *) caml_stat_alloc(sizeof(struct channel));
|
1995-05-04 03:15:53 -07:00
|
|
|
channel->fd = fd;
|
2010-04-01 00:36:49 -07:00
|
|
|
caml_enter_blocking_section();
|
|
|
|
channel->offset = lseek(fd, 0, SEEK_CUR);
|
|
|
|
caml_leave_blocking_section();
|
1997-08-29 08:37:22 -07:00
|
|
|
channel->curr = channel->max = channel->buff;
|
|
|
|
channel->end = channel->buff + IO_BUFFER_SIZE;
|
|
|
|
channel->mutex = NULL;
|
2001-10-09 08:14:01 -07:00
|
|
|
channel->revealed = 0;
|
|
|
|
channel->old_revealed = 0;
|
|
|
|
channel->refcount = 0;
|
2006-09-20 10:37:08 -07:00
|
|
|
channel->flags = 0;
|
2003-12-29 14:15:02 -08:00
|
|
|
channel->next = caml_all_opened_channels;
|
2005-09-24 09:14:41 -07:00
|
|
|
channel->prev = NULL;
|
|
|
|
if (caml_all_opened_channels != NULL)
|
|
|
|
caml_all_opened_channels->prev = channel;
|
2003-12-29 14:15:02 -08:00
|
|
|
caml_all_opened_channels = channel;
|
1995-05-04 03:15:53 -07:00
|
|
|
return channel;
|
|
|
|
}
|
|
|
|
|
2003-12-29 14:15:02 -08:00
|
|
|
CAMLexport struct channel * caml_open_descriptor_out(int fd)
|
2001-10-09 08:14:01 -07:00
|
|
|
{
|
|
|
|
struct channel * channel;
|
|
|
|
|
2003-12-29 14:15:02 -08:00
|
|
|
channel = caml_open_descriptor_in(fd);
|
2001-10-09 08:14:01 -07:00
|
|
|
channel->max = NULL;
|
|
|
|
return channel;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void unlink_channel(struct channel *channel)
|
|
|
|
{
|
2005-09-24 09:14:41 -07:00
|
|
|
if (channel->prev == NULL) {
|
|
|
|
Assert (channel == caml_all_opened_channels);
|
|
|
|
caml_all_opened_channels = caml_all_opened_channels->next;
|
|
|
|
if (caml_all_opened_channels != NULL)
|
|
|
|
caml_all_opened_channels->prev = NULL;
|
|
|
|
} else {
|
|
|
|
channel->prev->next = channel->next;
|
|
|
|
if (channel->next != NULL) channel->next->prev = channel->prev;
|
|
|
|
}
|
2001-10-09 08:14:01 -07:00
|
|
|
}
|
|
|
|
|
2003-12-29 14:15:02 -08:00
|
|
|
CAMLexport void caml_close_channel(struct channel *channel)
|
1996-04-18 09:29:57 -07:00
|
|
|
{
|
|
|
|
close(channel->fd);
|
2001-10-09 08:14:01 -07:00
|
|
|
if (channel->refcount > 0) return;
|
2003-12-29 14:15:02 -08:00
|
|
|
if (caml_channel_mutex_free != NULL) (*caml_channel_mutex_free)(channel);
|
2001-10-09 08:14:01 -07:00
|
|
|
unlink_channel(channel);
|
2003-12-31 06:20:40 -08:00
|
|
|
caml_stat_free(channel);
|
2000-01-07 08:05:19 -08:00
|
|
|
}
|
1996-04-18 09:29:57 -07:00
|
|
|
|
2003-12-29 14:15:02 -08:00
|
|
|
CAMLexport file_offset caml_channel_size(struct channel *channel)
|
1995-05-04 03:15:53 -07:00
|
|
|
{
|
2010-04-01 00:36:49 -07:00
|
|
|
file_offset offset;
|
2002-03-02 01:16:39 -08:00
|
|
|
file_offset end;
|
2010-04-01 00:36:49 -07:00
|
|
|
int fd;
|
1995-05-04 03:15:53 -07:00
|
|
|
|
2012-02-10 08:15:24 -08:00
|
|
|
/* We extract data from [channel] before dropping the OCaml lock, in case
|
2010-04-01 00:36:49 -07:00
|
|
|
someone else touches the block. */
|
|
|
|
fd = channel->fd;
|
|
|
|
offset = channel->offset;
|
|
|
|
caml_enter_blocking_section();
|
|
|
|
end = lseek(fd, 0, SEEK_END);
|
|
|
|
if (end == -1 || lseek(fd, offset, SEEK_SET) != offset) {
|
|
|
|
caml_leave_blocking_section();
|
2003-12-15 08:29:53 -08:00
|
|
|
caml_sys_error(NO_ARG);
|
1997-08-29 08:37:22 -07:00
|
|
|
}
|
2010-04-01 00:36:49 -07:00
|
|
|
caml_leave_blocking_section();
|
1997-08-29 08:37:22 -07:00
|
|
|
return end;
|
1995-05-04 03:15:53 -07:00
|
|
|
}
|
|
|
|
|
2003-12-29 14:15:02 -08:00
|
|
|
CAMLexport int caml_channel_binary_mode(struct channel *channel)
|
1998-02-26 04:51:39 -08:00
|
|
|
{
|
2005-10-25 12:15:36 -07:00
|
|
|
#if defined(_WIN32) || defined(__CYGWIN__)
|
1998-05-12 04:23:15 -07:00
|
|
|
int oldmode = setmode(channel->fd, O_BINARY);
|
|
|
|
if (oldmode == O_TEXT) setmode(channel->fd, O_TEXT);
|
1998-02-26 04:51:39 -08:00
|
|
|
return oldmode == O_BINARY;
|
|
|
|
#else
|
|
|
|
return 1;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
1995-05-04 03:15:53 -07:00
|
|
|
/* Output */
|
|
|
|
|
1996-04-29 06:18:36 -07:00
|
|
|
#ifndef EINTR
|
|
|
|
#define EINTR (-1)
|
|
|
|
#endif
|
|
|
|
#ifndef EAGAIN
|
|
|
|
#define EAGAIN (-1)
|
|
|
|
#endif
|
|
|
|
#ifndef EWOULDBLOCK
|
|
|
|
#define EWOULDBLOCK (-1)
|
|
|
|
#endif
|
|
|
|
|
1997-09-02 05:55:01 -07:00
|
|
|
static int do_write(int fd, char *p, int n)
|
1995-05-04 03:15:53 -07:00
|
|
|
{
|
|
|
|
int retcode;
|
1996-04-18 09:29:57 -07:00
|
|
|
|
1996-04-29 06:18:36 -07:00
|
|
|
again:
|
2004-01-01 08:42:43 -08:00
|
|
|
caml_enter_blocking_section();
|
1996-04-18 09:29:57 -07:00
|
|
|
retcode = write(fd, p, n);
|
2004-01-01 08:42:43 -08:00
|
|
|
caml_leave_blocking_section();
|
1996-04-29 06:18:36 -07:00
|
|
|
if (retcode == -1) {
|
|
|
|
if (errno == EINTR) goto again;
|
1998-11-20 07:36:27 -08:00
|
|
|
if ((errno == EAGAIN || errno == EWOULDBLOCK) && n > 1) {
|
1996-04-29 09:56:34 -07:00
|
|
|
/* We couldn't do a partial write here, probably because
|
1997-05-19 08:42:21 -07:00
|
|
|
n <= PIPE_BUF and POSIX says that writes of less than
|
|
|
|
PIPE_BUF characters must be atomic.
|
1998-11-20 07:36:27 -08:00
|
|
|
We first try again with a partial write of 1 character.
|
|
|
|
If that fails too, we'll raise Sys_blocked_io below. */
|
1998-10-01 05:31:34 -07:00
|
|
|
n = 1; goto again;
|
1996-04-29 06:18:36 -07:00
|
|
|
}
|
|
|
|
}
|
2007-02-25 04:38:36 -08:00
|
|
|
if (retcode == -1) caml_sys_io_error(NO_ARG);
|
1996-04-18 09:29:57 -07:00
|
|
|
return retcode;
|
|
|
|
}
|
1995-05-04 03:15:53 -07:00
|
|
|
|
1996-04-18 09:29:57 -07:00
|
|
|
/* Attempt to flush the buffer. This will make room in the buffer for
|
|
|
|
at least one character. Returns true if the buffer is empty at the
|
2002-03-26 06:28:25 -08:00
|
|
|
end of the flush, or false if some data remains in the buffer.
|
|
|
|
*/
|
1996-04-18 09:29:57 -07:00
|
|
|
|
2003-12-29 14:15:02 -08:00
|
|
|
CAMLexport int caml_flush_partial(struct channel *channel)
|
1995-05-04 03:15:53 -07:00
|
|
|
{
|
1996-04-18 09:29:57 -07:00
|
|
|
int towrite, written;
|
1997-08-29 08:37:22 -07:00
|
|
|
|
1996-04-18 09:29:57 -07:00
|
|
|
towrite = channel->curr - channel->buff;
|
|
|
|
if (towrite > 0) {
|
|
|
|
written = do_write(channel->fd, channel->buff, towrite);
|
|
|
|
channel->offset += written;
|
|
|
|
if (written < towrite)
|
2000-10-12 11:05:42 -07:00
|
|
|
memmove(channel->buff, channel->buff + written, towrite - written);
|
1996-04-18 09:29:57 -07:00
|
|
|
channel->curr -= written;
|
1995-05-04 03:15:53 -07:00
|
|
|
}
|
1997-08-29 08:37:22 -07:00
|
|
|
return (channel->curr == channel->buff);
|
1996-04-18 09:29:57 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Flush completely the buffer. */
|
|
|
|
|
2003-12-29 14:15:02 -08:00
|
|
|
CAMLexport void caml_flush(struct channel *channel)
|
1996-04-18 09:29:57 -07:00
|
|
|
{
|
2003-12-29 14:15:02 -08:00
|
|
|
while (! caml_flush_partial(channel)) /*nothing*/;
|
1995-05-04 03:15:53 -07:00
|
|
|
}
|
|
|
|
|
1997-08-29 08:37:22 -07:00
|
|
|
/* Output data */
|
1995-05-04 03:15:53 -07:00
|
|
|
|
2014-08-27 02:58:33 -07:00
|
|
|
CAMLexport void caml_putword(struct channel *channel, uint32_t w)
|
1995-05-04 03:15:53 -07:00
|
|
|
{
|
2003-12-29 14:15:02 -08:00
|
|
|
if (! caml_channel_binary_mode(channel))
|
2004-01-01 08:42:43 -08:00
|
|
|
caml_failwith("output_binary_int: not a binary channel");
|
1995-05-04 03:15:53 -07:00
|
|
|
putch(channel, w >> 24);
|
|
|
|
putch(channel, w >> 16);
|
|
|
|
putch(channel, w >> 8);
|
|
|
|
putch(channel, w);
|
|
|
|
}
|
|
|
|
|
2005-09-22 07:21:50 -07:00
|
|
|
CAMLexport int caml_putblock(struct channel *channel, char *p, intnat len)
|
1995-05-04 03:15:53 -07:00
|
|
|
{
|
1996-04-18 09:29:57 -07:00
|
|
|
int n, free, towrite, written;
|
1995-05-04 03:15:53 -07:00
|
|
|
|
1996-02-13 08:26:14 -08:00
|
|
|
n = len >= INT_MAX ? INT_MAX : (int) len;
|
1996-04-18 09:29:57 -07:00
|
|
|
free = channel->end - channel->curr;
|
2002-05-27 07:31:09 -07:00
|
|
|
if (n < free) {
|
1996-04-18 09:29:57 -07:00
|
|
|
/* Write request small enough to fit in buffer: transfer to buffer. */
|
2000-10-12 11:05:42 -07:00
|
|
|
memmove(channel->curr, p, n);
|
1995-05-04 03:15:53 -07:00
|
|
|
channel->curr += n;
|
1996-04-18 09:29:57 -07:00
|
|
|
return n;
|
1995-05-04 03:15:53 -07:00
|
|
|
} else {
|
2002-05-27 07:31:09 -07:00
|
|
|
/* Write request overflows buffer (or just fills it up): transfer whatever
|
|
|
|
fits to buffer and write the buffer */
|
2000-10-12 11:05:42 -07:00
|
|
|
memmove(channel->curr, p, free);
|
1996-04-18 09:29:57 -07:00
|
|
|
towrite = channel->end - channel->buff;
|
|
|
|
written = do_write(channel->fd, channel->buff, towrite);
|
|
|
|
if (written < towrite)
|
2000-10-12 11:05:42 -07:00
|
|
|
memmove(channel->buff, channel->buff + written, towrite - written);
|
1996-04-18 09:29:57 -07:00
|
|
|
channel->offset += written;
|
|
|
|
channel->curr = channel->end - written;
|
|
|
|
return free;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-04-16 16:28:22 -07:00
|
|
|
CAMLexport void caml_really_putblock(struct channel *channel,
|
2005-09-22 07:21:50 -07:00
|
|
|
char *p, intnat len)
|
1996-04-18 09:29:57 -07:00
|
|
|
{
|
|
|
|
int written;
|
|
|
|
while (len > 0) {
|
2003-12-29 14:15:02 -08:00
|
|
|
written = caml_putblock(channel, p, len);
|
1996-04-18 09:29:57 -07:00
|
|
|
p += written;
|
|
|
|
len -= written;
|
1995-05-04 03:15:53 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-12-29 14:15:02 -08:00
|
|
|
CAMLexport void caml_seek_out(struct channel *channel, file_offset dest)
|
1995-05-04 03:15:53 -07:00
|
|
|
{
|
2003-12-29 14:15:02 -08:00
|
|
|
caml_flush(channel);
|
2010-04-01 00:36:49 -07:00
|
|
|
caml_enter_blocking_section();
|
|
|
|
if (lseek(channel->fd, dest, SEEK_SET) != dest) {
|
|
|
|
caml_leave_blocking_section();
|
|
|
|
caml_sys_error(NO_ARG);
|
|
|
|
}
|
|
|
|
caml_leave_blocking_section();
|
1996-04-18 09:29:57 -07:00
|
|
|
channel->offset = dest;
|
1995-05-04 03:15:53 -07:00
|
|
|
}
|
|
|
|
|
2003-12-29 14:15:02 -08:00
|
|
|
CAMLexport file_offset caml_pos_out(struct channel *channel)
|
1995-05-04 03:15:53 -07:00
|
|
|
{
|
2003-01-06 02:59:07 -08:00
|
|
|
return channel->offset + (file_offset)(channel->curr - channel->buff);
|
1995-05-04 03:15:53 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Input */
|
|
|
|
|
2003-12-29 14:15:02 -08:00
|
|
|
/* caml_do_read is exported for Cash */
|
|
|
|
CAMLexport int caml_do_read(int fd, char *p, unsigned int n)
|
1995-05-04 03:15:53 -07:00
|
|
|
{
|
|
|
|
int retcode;
|
|
|
|
|
2005-07-31 05:31:03 -07:00
|
|
|
do {
|
|
|
|
caml_enter_blocking_section();
|
|
|
|
retcode = read(fd, p, n);
|
2012-06-25 05:00:44 -07:00
|
|
|
#if defined(_WIN32)
|
|
|
|
if (retcode == -1 && errno == ENOMEM && n > 16384){
|
|
|
|
retcode = read(fd, p, 16384);
|
|
|
|
}
|
|
|
|
#endif
|
2012-07-26 12:21:54 -07:00
|
|
|
caml_leave_blocking_section();
|
2005-07-31 05:31:03 -07:00
|
|
|
} while (retcode == -1 && errno == EINTR);
|
2007-02-25 04:38:36 -08:00
|
|
|
if (retcode == -1) caml_sys_io_error(NO_ARG);
|
1995-05-04 03:15:53 -07:00
|
|
|
return retcode;
|
|
|
|
}
|
|
|
|
|
2003-12-29 14:15:02 -08:00
|
|
|
CAMLexport unsigned char caml_refill(struct channel *channel)
|
1995-05-04 03:15:53 -07:00
|
|
|
{
|
|
|
|
int n;
|
|
|
|
|
2003-12-29 14:15:02 -08:00
|
|
|
n = caml_do_read(channel->fd, channel->buff, channel->end - channel->buff);
|
2004-01-01 08:42:43 -08:00
|
|
|
if (n == 0) caml_raise_end_of_file();
|
1995-05-04 03:15:53 -07:00
|
|
|
channel->offset += n;
|
|
|
|
channel->max = channel->buff + n;
|
|
|
|
channel->curr = channel->buff + 1;
|
|
|
|
return (unsigned char)(channel->buff[0]);
|
|
|
|
}
|
|
|
|
|
2014-08-27 02:58:33 -07:00
|
|
|
CAMLexport uint32_t caml_getword(struct channel *channel)
|
1995-05-04 03:15:53 -07:00
|
|
|
{
|
|
|
|
int i;
|
2014-08-27 02:58:33 -07:00
|
|
|
uint32_t res;
|
1995-05-04 03:15:53 -07:00
|
|
|
|
2003-12-29 14:15:02 -08:00
|
|
|
if (! caml_channel_binary_mode(channel))
|
2004-01-01 08:42:43 -08:00
|
|
|
caml_failwith("input_binary_int: not a binary channel");
|
1995-05-04 03:15:53 -07:00
|
|
|
res = 0;
|
|
|
|
for(i = 0; i < 4; i++) {
|
|
|
|
res = (res << 8) + getch(channel);
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2005-09-22 07:21:50 -07:00
|
|
|
CAMLexport int caml_getblock(struct channel *channel, char *p, intnat len)
|
1995-05-04 03:15:53 -07:00
|
|
|
{
|
1996-04-18 09:29:57 -07:00
|
|
|
int n, avail, nread;
|
1995-05-04 03:15:53 -07:00
|
|
|
|
1996-02-13 08:26:14 -08:00
|
|
|
n = len >= INT_MAX ? INT_MAX : (int) len;
|
1996-04-18 09:29:57 -07:00
|
|
|
avail = channel->max - channel->curr;
|
|
|
|
if (n <= avail) {
|
2000-10-12 11:05:42 -07:00
|
|
|
memmove(p, channel->curr, n);
|
1995-05-04 03:15:53 -07:00
|
|
|
channel->curr += n;
|
|
|
|
return n;
|
1996-04-18 09:29:57 -07:00
|
|
|
} else if (avail > 0) {
|
2000-10-12 11:05:42 -07:00
|
|
|
memmove(p, channel->curr, avail);
|
1996-04-18 09:29:57 -07:00
|
|
|
channel->curr += avail;
|
|
|
|
return avail;
|
2000-02-07 06:07:31 -08:00
|
|
|
} else {
|
2003-12-29 14:15:02 -08:00
|
|
|
nread = caml_do_read(channel->fd, channel->buff,
|
|
|
|
channel->end - channel->buff);
|
1996-04-18 09:29:57 -07:00
|
|
|
channel->offset += nread;
|
|
|
|
channel->max = channel->buff + nread;
|
|
|
|
if (n > nread) n = nread;
|
2000-10-12 11:05:42 -07:00
|
|
|
memmove(p, channel->buff, n);
|
1995-05-04 03:15:53 -07:00
|
|
|
channel->curr = channel->buff + n;
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-09-22 07:21:50 -07:00
|
|
|
CAMLexport int caml_really_getblock(struct channel *chan, char *p, intnat n)
|
1995-05-04 03:15:53 -07:00
|
|
|
{
|
1996-02-13 08:26:14 -08:00
|
|
|
int r;
|
1995-05-04 03:15:53 -07:00
|
|
|
while (n > 0) {
|
2003-12-29 14:15:02 -08:00
|
|
|
r = caml_getblock(chan, p, n);
|
1997-08-29 08:37:22 -07:00
|
|
|
if (r == 0) break;
|
1995-05-04 03:15:53 -07:00
|
|
|
p += r;
|
|
|
|
n -= r;
|
|
|
|
}
|
1997-08-29 08:37:22 -07:00
|
|
|
return (n == 0);
|
1995-05-04 03:15:53 -07:00
|
|
|
}
|
|
|
|
|
2003-12-29 14:15:02 -08:00
|
|
|
CAMLexport void caml_seek_in(struct channel *channel, file_offset dest)
|
1995-05-04 03:15:53 -07:00
|
|
|
{
|
|
|
|
if (dest >= channel->offset - (channel->max - channel->buff) &&
|
|
|
|
dest <= channel->offset) {
|
|
|
|
channel->curr = channel->max - (channel->offset - dest);
|
|
|
|
} else {
|
2010-04-01 00:36:49 -07:00
|
|
|
caml_enter_blocking_section();
|
|
|
|
if (lseek(channel->fd, dest, SEEK_SET) != dest) {
|
|
|
|
caml_leave_blocking_section();
|
|
|
|
caml_sys_error(NO_ARG);
|
|
|
|
}
|
|
|
|
caml_leave_blocking_section();
|
1995-05-04 03:15:53 -07:00
|
|
|
channel->offset = dest;
|
|
|
|
channel->curr = channel->max = channel->buff;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-12-29 14:15:02 -08:00
|
|
|
CAMLexport file_offset caml_pos_in(struct channel *channel)
|
1995-05-04 03:15:53 -07:00
|
|
|
{
|
2003-01-06 02:59:07 -08:00
|
|
|
return channel->offset - (file_offset)(channel->max - channel->curr);
|
1995-05-04 03:15:53 -07:00
|
|
|
}
|
|
|
|
|
2005-09-22 07:21:50 -07:00
|
|
|
CAMLexport intnat caml_input_scan_line(struct channel *channel)
|
1995-05-04 03:15:53 -07:00
|
|
|
{
|
|
|
|
char * p;
|
|
|
|
int n;
|
|
|
|
|
|
|
|
p = channel->curr;
|
|
|
|
do {
|
|
|
|
if (p >= channel->max) {
|
|
|
|
/* No more characters available in the buffer */
|
|
|
|
if (channel->curr > channel->buff) {
|
|
|
|
/* Try to make some room in the buffer by shifting the unread
|
|
|
|
portion at the beginning */
|
2000-10-12 11:05:42 -07:00
|
|
|
memmove(channel->buff, channel->curr, channel->max - channel->curr);
|
1995-05-04 03:15:53 -07:00
|
|
|
n = channel->curr - channel->buff;
|
|
|
|
channel->curr -= n;
|
|
|
|
channel->max -= n;
|
|
|
|
p -= n;
|
|
|
|
}
|
|
|
|
if (channel->max >= channel->end) {
|
|
|
|
/* Buffer is full, no room to read more characters from the input.
|
|
|
|
Return the number of characters in the buffer, with negative
|
|
|
|
sign to indicate that no newline was encountered. */
|
1997-08-29 08:37:22 -07:00
|
|
|
return -(channel->max - channel->curr);
|
1995-05-04 03:15:53 -07:00
|
|
|
}
|
|
|
|
/* Fill the buffer as much as possible */
|
2003-12-29 14:15:02 -08:00
|
|
|
n = caml_do_read(channel->fd, channel->max, channel->end - channel->max);
|
1995-05-04 03:15:53 -07:00
|
|
|
if (n == 0) {
|
|
|
|
/* End-of-file encountered. Return the number of characters in the
|
2000-01-07 08:05:19 -08:00
|
|
|
buffer, with negative sign since we haven't encountered
|
1995-05-04 03:15:53 -07:00
|
|
|
a newline. */
|
1997-08-29 08:37:22 -07:00
|
|
|
return -(channel->max - channel->curr);
|
1995-05-04 03:15:53 -07:00
|
|
|
}
|
|
|
|
channel->offset += n;
|
|
|
|
channel->max += n;
|
|
|
|
}
|
|
|
|
} while (*p++ != '\n');
|
|
|
|
/* Found a newline. Return the length of the line, newline included. */
|
1997-08-29 08:37:22 -07:00
|
|
|
return (p - channel->curr);
|
|
|
|
}
|
|
|
|
|
2012-02-10 08:15:24 -08:00
|
|
|
/* OCaml entry points for the I/O functions. Wrap struct channel *
|
2000-02-07 06:07:31 -08:00
|
|
|
objects into a heap-allocated object. Perform locking
|
1997-08-29 08:37:22 -07:00
|
|
|
and unlocking around the I/O operations. */
|
2015-02-06 13:58:00 -08:00
|
|
|
|
2003-12-29 14:15:02 -08:00
|
|
|
/* FIXME CAMLexport, but not in io.h exported for Cash ? */
|
|
|
|
CAMLexport void caml_finalize_channel(value vchan)
|
1997-08-29 08:37:22 -07:00
|
|
|
{
|
|
|
|
struct channel * chan = Channel(vchan);
|
2001-10-09 08:14:01 -07:00
|
|
|
if (--chan->refcount > 0) return;
|
2015-02-06 13:58:00 -08:00
|
|
|
/* If the buffer is empty, remove the channel from the list of all
|
|
|
|
open channels and free it. Otherwise, keep it around so the Ocaml
|
|
|
|
[at_exit] function gets a chance to flush it.
|
|
|
|
We would want to simply flush the channel now, but flushing can
|
|
|
|
raise exceptions, which is forbidden in a finalization function.
|
|
|
|
*/
|
|
|
|
if (chan->curr == chan->buff){
|
2015-04-21 08:20:10 -07:00
|
|
|
if (caml_channel_mutex_free != NULL) (*caml_channel_mutex_free)(chan);
|
2015-02-06 13:58:00 -08:00
|
|
|
unlink_channel(chan);
|
|
|
|
caml_stat_free(chan);
|
|
|
|
}
|
1997-08-29 08:37:22 -07:00
|
|
|
}
|
|
|
|
|
2000-05-16 02:11:51 -07:00
|
|
|
static int compare_channel(value vchan1, value vchan2)
|
|
|
|
{
|
|
|
|
struct channel * chan1 = Channel(vchan1);
|
|
|
|
struct channel * chan2 = Channel(vchan2);
|
|
|
|
return (chan1 == chan2) ? 0 : (chan1 < chan2) ? -1 : 1;
|
|
|
|
}
|
|
|
|
|
2011-07-23 03:07:25 -07:00
|
|
|
static intnat hash_channel(value vchan)
|
|
|
|
{
|
|
|
|
return (intnat) (Channel(vchan));
|
|
|
|
}
|
|
|
|
|
2000-02-10 06:04:59 -08:00
|
|
|
static struct custom_operations channel_operations = {
|
|
|
|
"_chan",
|
2003-12-29 14:15:02 -08:00
|
|
|
caml_finalize_channel,
|
2000-05-16 02:11:51 -07:00
|
|
|
compare_channel,
|
2011-07-23 03:07:25 -07:00
|
|
|
hash_channel,
|
2000-02-10 06:04:59 -08:00
|
|
|
custom_serialize_default,
|
2011-07-23 03:07:25 -07:00
|
|
|
custom_deserialize_default,
|
|
|
|
custom_compare_ext_default
|
2000-02-10 06:04:59 -08:00
|
|
|
};
|
|
|
|
|
2003-12-29 14:15:02 -08:00
|
|
|
CAMLexport value caml_alloc_channel(struct channel *chan)
|
1997-08-29 08:37:22 -07:00
|
|
|
{
|
2003-07-29 04:48:34 -07:00
|
|
|
value res;
|
|
|
|
chan->refcount++; /* prevent finalization during next alloc */
|
2004-01-01 08:42:43 -08:00
|
|
|
res = caml_alloc_custom(&channel_operations, sizeof(struct channel *),
|
|
|
|
1, 1000);
|
2000-02-10 06:04:59 -08:00
|
|
|
Channel(res) = chan;
|
1997-08-29 08:37:22 -07:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2003-12-29 14:15:02 -08:00
|
|
|
CAMLprim value caml_ml_open_descriptor_in(value fd)
|
2001-10-09 08:14:01 -07:00
|
|
|
{
|
2003-12-29 14:15:02 -08:00
|
|
|
return caml_alloc_channel(caml_open_descriptor_in(Int_val(fd)));
|
2001-10-09 08:14:01 -07:00
|
|
|
}
|
|
|
|
|
2003-12-29 14:15:02 -08:00
|
|
|
CAMLprim value caml_ml_open_descriptor_out(value fd)
|
1997-08-29 08:37:22 -07:00
|
|
|
{
|
2003-12-29 14:15:02 -08:00
|
|
|
return caml_alloc_channel(caml_open_descriptor_out(Int_val(fd)));
|
2001-10-09 08:14:01 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#define Pair_tag 0
|
|
|
|
|
2003-12-29 14:15:02 -08:00
|
|
|
CAMLprim value caml_ml_out_channels_list (value unit)
|
2001-10-09 08:14:01 -07:00
|
|
|
{
|
|
|
|
CAMLparam0 ();
|
|
|
|
CAMLlocal3 (res, tail, chan);
|
|
|
|
struct channel * channel;
|
|
|
|
|
|
|
|
res = Val_emptylist;
|
2003-12-29 14:15:02 -08:00
|
|
|
for (channel = caml_all_opened_channels;
|
2001-10-09 08:14:01 -07:00
|
|
|
channel != NULL;
|
2006-04-16 16:28:22 -07:00
|
|
|
channel = channel->next)
|
2001-10-09 08:14:01 -07:00
|
|
|
/* Testing channel->fd >= 0 looks unnecessary, as
|
2003-12-29 14:15:02 -08:00
|
|
|
caml_ml_close_channel changes max when setting fd to -1. */
|
2001-10-09 08:14:01 -07:00
|
|
|
if (channel->max == NULL) {
|
2003-12-29 14:15:02 -08:00
|
|
|
chan = caml_alloc_channel (channel);
|
2001-10-09 08:14:01 -07:00
|
|
|
tail = res;
|
2003-12-29 14:15:02 -08:00
|
|
|
res = caml_alloc_small (2, Pair_tag);
|
2001-10-09 08:14:01 -07:00
|
|
|
Field (res, 0) = chan;
|
|
|
|
Field (res, 1) = tail;
|
|
|
|
}
|
|
|
|
CAMLreturn (res);
|
1997-08-29 08:37:22 -07:00
|
|
|
}
|
|
|
|
|
2003-12-29 14:15:02 -08:00
|
|
|
CAMLprim value caml_channel_descriptor(value vchannel)
|
1997-08-29 08:37:22 -07:00
|
|
|
{
|
1998-10-29 07:54:39 -08:00
|
|
|
int fd = Channel(vchannel)->fd;
|
2003-12-15 08:29:53 -08:00
|
|
|
if (fd == -1) { errno = EBADF; caml_sys_error(NO_ARG); }
|
1998-10-29 07:54:39 -08:00
|
|
|
return Val_int(fd);
|
1995-05-04 03:15:53 -07:00
|
|
|
}
|
1997-08-29 08:37:22 -07:00
|
|
|
|
2003-12-29 14:15:02 -08:00
|
|
|
CAMLprim value caml_ml_close_channel(value vchannel)
|
1997-08-29 08:37:22 -07:00
|
|
|
{
|
2002-10-29 05:55:33 -08:00
|
|
|
int result;
|
2010-04-23 00:58:59 -07:00
|
|
|
int do_syscall;
|
|
|
|
int fd;
|
2002-10-29 05:55:33 -08:00
|
|
|
|
1997-08-29 08:37:22 -07:00
|
|
|
/* For output channels, must have flushed before */
|
|
|
|
struct channel * channel = Channel(vchannel);
|
2002-10-31 02:37:53 -08:00
|
|
|
if (channel->fd != -1){
|
2010-04-23 00:58:59 -07:00
|
|
|
fd = channel->fd;
|
2002-10-31 02:37:53 -08:00
|
|
|
channel->fd = -1;
|
2010-04-23 00:58:59 -07:00
|
|
|
do_syscall = 1;
|
2002-10-31 02:37:53 -08:00
|
|
|
}else{
|
2010-04-23 00:58:59 -07:00
|
|
|
do_syscall = 0;
|
2002-10-31 02:37:53 -08:00
|
|
|
result = 0;
|
|
|
|
}
|
2001-02-06 07:21:50 -08:00
|
|
|
/* Ensure that every read or write on the channel will cause an
|
2003-12-29 14:15:02 -08:00
|
|
|
immediate caml_flush_partial or caml_refill, thus raising a Sys_error
|
2001-02-06 07:21:50 -08:00
|
|
|
exception */
|
|
|
|
channel->curr = channel->max = channel->end;
|
2010-04-23 00:58:59 -07:00
|
|
|
|
|
|
|
if (do_syscall) {
|
|
|
|
caml_enter_blocking_section();
|
|
|
|
result = close(fd);
|
|
|
|
caml_leave_blocking_section();
|
|
|
|
}
|
|
|
|
|
2003-12-15 08:29:53 -08:00
|
|
|
if (result == -1) caml_sys_error (NO_ARG);
|
1997-08-29 08:37:22 -07:00
|
|
|
return Val_unit;
|
|
|
|
}
|
|
|
|
|
2002-03-02 01:16:39 -08:00
|
|
|
/* EOVERFLOW is the Unix98 error indicating that a file position or file
|
|
|
|
size is not representable.
|
|
|
|
ERANGE is the ANSI C error indicating that some argument to some
|
|
|
|
function is out of range. This is less precise than EOVERFLOW,
|
|
|
|
but guaranteed to be defined on all ANSI C environments. */
|
|
|
|
#ifndef EOVERFLOW
|
|
|
|
#define EOVERFLOW ERANGE
|
|
|
|
#endif
|
|
|
|
|
2003-12-29 14:15:02 -08:00
|
|
|
CAMLprim value caml_ml_channel_size(value vchannel)
|
1997-08-29 08:37:22 -07:00
|
|
|
{
|
2003-12-29 14:15:02 -08:00
|
|
|
file_offset size = caml_channel_size(Channel(vchannel));
|
2003-12-15 08:29:53 -08:00
|
|
|
if (size > Max_long) { errno = EOVERFLOW; caml_sys_error(NO_ARG); }
|
2002-03-02 01:16:39 -08:00
|
|
|
return Val_long(size);
|
|
|
|
}
|
|
|
|
|
2003-12-29 14:15:02 -08:00
|
|
|
CAMLprim value caml_ml_channel_size_64(value vchannel)
|
2002-03-02 01:16:39 -08:00
|
|
|
{
|
2003-12-29 14:15:02 -08:00
|
|
|
return Val_file_offset(caml_channel_size(Channel(vchannel)));
|
1997-08-29 08:37:22 -07:00
|
|
|
}
|
|
|
|
|
2003-12-29 14:15:02 -08:00
|
|
|
CAMLprim value caml_ml_set_binary_mode(value vchannel, value mode)
|
1998-07-02 02:51:50 -07:00
|
|
|
{
|
2005-10-25 12:15:36 -07:00
|
|
|
#if defined(_WIN32) || defined(__CYGWIN__)
|
1998-07-02 02:51:50 -07:00
|
|
|
struct channel * channel = Channel(vchannel);
|
|
|
|
if (setmode(channel->fd, Bool_val(mode) ? O_BINARY : O_TEXT) == -1)
|
2003-12-15 08:29:53 -08:00
|
|
|
caml_sys_error(NO_ARG);
|
1998-07-02 02:51:50 -07:00
|
|
|
#endif
|
|
|
|
return Val_unit;
|
|
|
|
}
|
|
|
|
|
2003-01-03 07:04:08 -08:00
|
|
|
/*
|
|
|
|
If the channel is closed, DO NOT raise a "bad file descriptor"
|
|
|
|
exception, but do nothing (the buffer is already empty).
|
|
|
|
This is because some libraries will flush at exit, even on
|
|
|
|
file descriptors that may be closed.
|
|
|
|
*/
|
|
|
|
|
2003-12-29 14:15:02 -08:00
|
|
|
CAMLprim value caml_ml_flush_partial(value vchannel)
|
1997-08-29 08:37:22 -07:00
|
|
|
{
|
2006-04-16 16:28:22 -07:00
|
|
|
CAMLparam1 (vchannel);
|
1998-06-11 05:53:08 -07:00
|
|
|
struct channel * channel = Channel(vchannel);
|
|
|
|
int res;
|
2001-10-09 08:14:01 -07:00
|
|
|
|
2006-07-17 12:30:18 -07:00
|
|
|
if (channel->fd == -1) CAMLreturn(Val_true);
|
1998-06-11 05:53:08 -07:00
|
|
|
Lock(channel);
|
2003-12-29 14:15:02 -08:00
|
|
|
res = caml_flush_partial(channel);
|
1998-06-11 05:53:08 -07:00
|
|
|
Unlock(channel);
|
2006-04-16 16:28:22 -07:00
|
|
|
CAMLreturn (Val_bool(res));
|
1997-08-29 08:37:22 -07:00
|
|
|
}
|
|
|
|
|
2003-12-29 14:15:02 -08:00
|
|
|
CAMLprim value caml_ml_flush(value vchannel)
|
1997-08-29 08:37:22 -07:00
|
|
|
{
|
2006-04-16 16:28:22 -07:00
|
|
|
CAMLparam1 (vchannel);
|
1998-06-11 05:53:08 -07:00
|
|
|
struct channel * channel = Channel(vchannel);
|
2001-10-09 08:14:01 -07:00
|
|
|
|
2006-07-17 12:30:18 -07:00
|
|
|
if (channel->fd == -1) CAMLreturn(Val_unit);
|
1998-06-11 05:53:08 -07:00
|
|
|
Lock(channel);
|
2003-12-29 14:15:02 -08:00
|
|
|
caml_flush(channel);
|
1998-06-11 05:53:08 -07:00
|
|
|
Unlock(channel);
|
2006-04-16 16:28:22 -07:00
|
|
|
CAMLreturn (Val_unit);
|
1997-08-29 08:37:22 -07:00
|
|
|
}
|
|
|
|
|
2003-12-29 14:15:02 -08:00
|
|
|
CAMLprim value caml_ml_output_char(value vchannel, value ch)
|
1997-08-29 08:37:22 -07:00
|
|
|
{
|
2006-04-16 16:28:22 -07:00
|
|
|
CAMLparam2 (vchannel, ch);
|
1997-08-29 08:37:22 -07:00
|
|
|
struct channel * channel = Channel(vchannel);
|
2006-04-16 16:28:22 -07:00
|
|
|
|
1997-08-29 08:37:22 -07:00
|
|
|
Lock(channel);
|
|
|
|
putch(channel, Long_val(ch));
|
|
|
|
Unlock(channel);
|
2006-04-16 16:28:22 -07:00
|
|
|
CAMLreturn (Val_unit);
|
1997-08-29 08:37:22 -07:00
|
|
|
}
|
|
|
|
|
2003-12-29 14:15:02 -08:00
|
|
|
CAMLprim value caml_ml_output_int(value vchannel, value w)
|
1997-08-29 08:37:22 -07:00
|
|
|
{
|
2006-04-16 16:28:22 -07:00
|
|
|
CAMLparam2 (vchannel, w);
|
1997-08-29 08:37:22 -07:00
|
|
|
struct channel * channel = Channel(vchannel);
|
2006-04-16 16:28:22 -07:00
|
|
|
|
1997-08-29 08:37:22 -07:00
|
|
|
Lock(channel);
|
2003-12-29 14:15:02 -08:00
|
|
|
caml_putword(channel, Long_val(w));
|
1997-08-29 08:37:22 -07:00
|
|
|
Unlock(channel);
|
2006-04-16 16:28:22 -07:00
|
|
|
CAMLreturn (Val_unit);
|
1997-08-29 08:37:22 -07:00
|
|
|
}
|
|
|
|
|
2003-12-29 14:15:02 -08:00
|
|
|
CAMLprim value caml_ml_output_partial(value vchannel, value buff, value start,
|
|
|
|
value length)
|
1997-08-29 08:37:22 -07:00
|
|
|
{
|
1999-11-29 11:03:05 -08:00
|
|
|
CAMLparam4 (vchannel, buff, start, length);
|
1997-08-29 08:37:22 -07:00
|
|
|
struct channel * channel = Channel(vchannel);
|
|
|
|
int res;
|
1999-11-29 11:03:05 -08:00
|
|
|
|
|
|
|
Lock(channel);
|
2003-12-29 14:15:02 -08:00
|
|
|
res = caml_putblock(channel, &Byte(buff, Long_val(start)), Long_val(length));
|
1999-11-29 11:03:05 -08:00
|
|
|
Unlock(channel);
|
|
|
|
CAMLreturn (Val_int(res));
|
1997-08-29 08:37:22 -07:00
|
|
|
}
|
|
|
|
|
2003-12-29 14:15:02 -08:00
|
|
|
CAMLprim value caml_ml_output(value vchannel, value buff, value start,
|
|
|
|
value length)
|
1997-08-29 08:37:22 -07:00
|
|
|
{
|
1999-11-29 11:03:05 -08:00
|
|
|
CAMLparam4 (vchannel, buff, start, length);
|
1997-08-29 08:37:22 -07:00
|
|
|
struct channel * channel = Channel(vchannel);
|
2005-09-22 07:21:50 -07:00
|
|
|
intnat pos = Long_val(start);
|
|
|
|
intnat len = Long_val(length);
|
1997-08-29 08:37:22 -07:00
|
|
|
|
1999-11-29 11:03:05 -08:00
|
|
|
Lock(channel);
|
2000-01-07 08:05:19 -08:00
|
|
|
while (len > 0) {
|
2003-12-29 14:15:02 -08:00
|
|
|
int written = caml_putblock(channel, &Byte(buff, pos), len);
|
2000-01-07 08:05:19 -08:00
|
|
|
pos += written;
|
|
|
|
len -= written;
|
|
|
|
}
|
1999-11-29 11:03:05 -08:00
|
|
|
Unlock(channel);
|
|
|
|
CAMLreturn (Val_unit);
|
1997-08-29 08:37:22 -07:00
|
|
|
}
|
|
|
|
|
2003-12-29 14:15:02 -08:00
|
|
|
CAMLprim value caml_ml_seek_out(value vchannel, value pos)
|
1997-08-29 08:37:22 -07:00
|
|
|
{
|
2006-04-16 16:28:22 -07:00
|
|
|
CAMLparam2 (vchannel, pos);
|
1997-08-29 08:37:22 -07:00
|
|
|
struct channel * channel = Channel(vchannel);
|
2006-04-16 16:28:22 -07:00
|
|
|
|
1997-08-29 08:37:22 -07:00
|
|
|
Lock(channel);
|
2003-12-29 14:15:02 -08:00
|
|
|
caml_seek_out(channel, Long_val(pos));
|
1997-08-29 08:37:22 -07:00
|
|
|
Unlock(channel);
|
2006-04-16 16:28:22 -07:00
|
|
|
CAMLreturn (Val_unit);
|
1997-08-29 08:37:22 -07:00
|
|
|
}
|
|
|
|
|
2003-12-29 14:15:02 -08:00
|
|
|
CAMLprim value caml_ml_seek_out_64(value vchannel, value pos)
|
2002-03-02 01:16:39 -08:00
|
|
|
{
|
2006-04-16 16:28:22 -07:00
|
|
|
CAMLparam2 (vchannel, pos);
|
2002-03-02 01:16:39 -08:00
|
|
|
struct channel * channel = Channel(vchannel);
|
2006-04-16 16:28:22 -07:00
|
|
|
|
2002-03-02 01:16:39 -08:00
|
|
|
Lock(channel);
|
2003-12-29 14:15:02 -08:00
|
|
|
caml_seek_out(channel, File_offset_val(pos));
|
2002-03-02 01:16:39 -08:00
|
|
|
Unlock(channel);
|
2006-04-16 16:28:22 -07:00
|
|
|
CAMLreturn (Val_unit);
|
2002-03-02 01:16:39 -08:00
|
|
|
}
|
|
|
|
|
2003-12-29 14:15:02 -08:00
|
|
|
CAMLprim value caml_ml_pos_out(value vchannel)
|
1997-08-29 08:37:22 -07:00
|
|
|
{
|
2003-12-29 14:15:02 -08:00
|
|
|
file_offset pos = caml_pos_out(Channel(vchannel));
|
2003-12-15 08:29:53 -08:00
|
|
|
if (pos > Max_long) { errno = EOVERFLOW; caml_sys_error(NO_ARG); }
|
2002-03-02 01:16:39 -08:00
|
|
|
return Val_long(pos);
|
|
|
|
}
|
|
|
|
|
2003-12-29 14:15:02 -08:00
|
|
|
CAMLprim value caml_ml_pos_out_64(value vchannel)
|
2002-03-02 01:16:39 -08:00
|
|
|
{
|
2003-12-29 14:15:02 -08:00
|
|
|
return Val_file_offset(caml_pos_out(Channel(vchannel)));
|
1997-08-29 08:37:22 -07:00
|
|
|
}
|
|
|
|
|
2003-12-29 14:15:02 -08:00
|
|
|
CAMLprim value caml_ml_input_char(value vchannel)
|
1997-08-29 08:37:22 -07:00
|
|
|
{
|
2006-04-16 16:28:22 -07:00
|
|
|
CAMLparam1 (vchannel);
|
1997-08-29 08:37:22 -07:00
|
|
|
struct channel * channel = Channel(vchannel);
|
|
|
|
unsigned char c;
|
|
|
|
|
|
|
|
Lock(channel);
|
|
|
|
c = getch(channel);
|
|
|
|
Unlock(channel);
|
2006-04-16 16:28:22 -07:00
|
|
|
CAMLreturn (Val_long(c));
|
1997-08-29 08:37:22 -07:00
|
|
|
}
|
|
|
|
|
2003-12-29 14:15:02 -08:00
|
|
|
CAMLprim value caml_ml_input_int(value vchannel)
|
1997-08-29 08:37:22 -07:00
|
|
|
{
|
2006-04-16 16:28:22 -07:00
|
|
|
CAMLparam1 (vchannel);
|
1997-08-29 08:37:22 -07:00
|
|
|
struct channel * channel = Channel(vchannel);
|
2005-09-22 07:21:50 -07:00
|
|
|
intnat i;
|
1997-08-29 08:37:22 -07:00
|
|
|
|
|
|
|
Lock(channel);
|
2003-12-29 14:15:02 -08:00
|
|
|
i = caml_getword(channel);
|
1997-08-29 08:37:22 -07:00
|
|
|
Unlock(channel);
|
|
|
|
#ifdef ARCH_SIXTYFOUR
|
|
|
|
i = (i << 32) >> 32; /* Force sign extension */
|
|
|
|
#endif
|
2006-04-16 16:28:22 -07:00
|
|
|
CAMLreturn (Val_long(i));
|
1997-08-29 08:37:22 -07:00
|
|
|
}
|
|
|
|
|
2003-12-29 14:15:02 -08:00
|
|
|
CAMLprim value caml_ml_input(value vchannel, value buff, value vstart,
|
|
|
|
value vlength)
|
1997-08-29 08:37:22 -07:00
|
|
|
{
|
2000-02-07 06:07:31 -08:00
|
|
|
CAMLparam4 (vchannel, buff, vstart, vlength);
|
1997-08-29 08:37:22 -07:00
|
|
|
struct channel * channel = Channel(vchannel);
|
2005-09-22 07:21:50 -07:00
|
|
|
intnat start, len;
|
2000-02-07 06:07:31 -08:00
|
|
|
int n, avail, nread;
|
1997-08-29 08:37:22 -07:00
|
|
|
|
1999-11-29 11:03:05 -08:00
|
|
|
Lock(channel);
|
2003-12-29 14:15:02 -08:00
|
|
|
/* We cannot call caml_getblock here because buff may move during
|
|
|
|
caml_do_read */
|
2000-02-07 06:07:31 -08:00
|
|
|
start = Long_val(vstart);
|
|
|
|
len = Long_val(vlength);
|
|
|
|
n = len >= INT_MAX ? INT_MAX : (int) len;
|
|
|
|
avail = channel->max - channel->curr;
|
|
|
|
if (n <= avail) {
|
2000-10-12 11:05:42 -07:00
|
|
|
memmove(&Byte(buff, start), channel->curr, n);
|
2000-02-07 06:07:31 -08:00
|
|
|
channel->curr += n;
|
|
|
|
} else if (avail > 0) {
|
2000-10-12 11:05:42 -07:00
|
|
|
memmove(&Byte(buff, start), channel->curr, avail);
|
2000-02-07 06:07:31 -08:00
|
|
|
channel->curr += avail;
|
|
|
|
n = avail;
|
|
|
|
} else {
|
2003-12-29 14:15:02 -08:00
|
|
|
nread = caml_do_read(channel->fd, channel->buff,
|
|
|
|
channel->end - channel->buff);
|
2000-02-07 06:07:31 -08:00
|
|
|
channel->offset += nread;
|
|
|
|
channel->max = channel->buff + nread;
|
|
|
|
if (n > nread) n = nread;
|
2000-10-12 11:05:42 -07:00
|
|
|
memmove(&Byte(buff, start), channel->buff, n);
|
2000-02-07 06:07:31 -08:00
|
|
|
channel->curr = channel->buff + n;
|
|
|
|
}
|
1999-11-29 11:03:05 -08:00
|
|
|
Unlock(channel);
|
2000-02-07 06:07:31 -08:00
|
|
|
CAMLreturn (Val_long(n));
|
1997-08-29 08:37:22 -07:00
|
|
|
}
|
|
|
|
|
2003-12-29 14:15:02 -08:00
|
|
|
CAMLprim value caml_ml_seek_in(value vchannel, value pos)
|
1997-08-29 08:37:22 -07:00
|
|
|
{
|
2006-04-16 16:28:22 -07:00
|
|
|
CAMLparam2 (vchannel, pos);
|
1997-08-29 08:37:22 -07:00
|
|
|
struct channel * channel = Channel(vchannel);
|
2006-04-16 16:28:22 -07:00
|
|
|
|
1997-08-29 08:37:22 -07:00
|
|
|
Lock(channel);
|
2003-12-29 14:15:02 -08:00
|
|
|
caml_seek_in(channel, Long_val(pos));
|
1997-08-29 08:37:22 -07:00
|
|
|
Unlock(channel);
|
2006-04-16 16:28:22 -07:00
|
|
|
CAMLreturn (Val_unit);
|
1997-08-29 08:37:22 -07:00
|
|
|
}
|
|
|
|
|
2003-12-29 14:15:02 -08:00
|
|
|
CAMLprim value caml_ml_seek_in_64(value vchannel, value pos)
|
2002-03-02 01:16:39 -08:00
|
|
|
{
|
2006-04-16 16:28:22 -07:00
|
|
|
CAMLparam2 (vchannel, pos);
|
2002-03-02 01:16:39 -08:00
|
|
|
struct channel * channel = Channel(vchannel);
|
2006-04-16 16:28:22 -07:00
|
|
|
|
2002-03-02 01:16:39 -08:00
|
|
|
Lock(channel);
|
2003-12-29 14:15:02 -08:00
|
|
|
caml_seek_in(channel, File_offset_val(pos));
|
2002-03-02 01:16:39 -08:00
|
|
|
Unlock(channel);
|
2006-04-16 16:28:22 -07:00
|
|
|
CAMLreturn (Val_unit);
|
2002-03-02 01:16:39 -08:00
|
|
|
}
|
|
|
|
|
2003-12-29 14:15:02 -08:00
|
|
|
CAMLprim value caml_ml_pos_in(value vchannel)
|
1997-08-29 08:37:22 -07:00
|
|
|
{
|
2003-12-29 14:15:02 -08:00
|
|
|
file_offset pos = caml_pos_in(Channel(vchannel));
|
2003-12-15 08:29:53 -08:00
|
|
|
if (pos > Max_long) { errno = EOVERFLOW; caml_sys_error(NO_ARG); }
|
2002-03-02 01:16:39 -08:00
|
|
|
return Val_long(pos);
|
|
|
|
}
|
|
|
|
|
2003-12-29 14:15:02 -08:00
|
|
|
CAMLprim value caml_ml_pos_in_64(value vchannel)
|
2002-03-02 01:16:39 -08:00
|
|
|
{
|
2003-12-29 14:15:02 -08:00
|
|
|
return Val_file_offset(caml_pos_in(Channel(vchannel)));
|
1997-08-29 08:37:22 -07:00
|
|
|
}
|
|
|
|
|
2003-12-29 14:15:02 -08:00
|
|
|
CAMLprim value caml_ml_input_scan_line(value vchannel)
|
1997-08-29 08:37:22 -07:00
|
|
|
{
|
2006-04-16 16:28:22 -07:00
|
|
|
CAMLparam1 (vchannel);
|
1997-08-29 08:37:22 -07:00
|
|
|
struct channel * channel = Channel(vchannel);
|
2005-09-22 07:21:50 -07:00
|
|
|
intnat res;
|
1997-08-29 08:37:22 -07:00
|
|
|
|
|
|
|
Lock(channel);
|
2003-12-29 14:15:02 -08:00
|
|
|
res = caml_input_scan_line(channel);
|
1997-08-29 08:37:22 -07:00
|
|
|
Unlock(channel);
|
2006-04-16 16:28:22 -07:00
|
|
|
CAMLreturn (Val_long(res));
|
1997-08-29 08:37:22 -07:00
|
|
|
}
|