[Ecls-list] FILE* -> Lisp stream?
Mark Hoemmen
mark.hoemmen at gmail.com
Sun Jul 13 01:31:05 UTC 2008
Greetings!
Would there happen to be interest in adding a function to ECL that wraps
an open FILE* from C space in a Lisp stream? I've got a rough version
of such a function (which I've listed below), based on the existing
function ecl_make_stream_from_fd() in src/file.d. It doesn't yet
support Windows sockets (WSOCK, etc.).
My motivation for such a function is that I'd like to to pass an open
input stream from the C world into Lisp space for Lisp to read from it.
I could just use ecl_make_stream_from_fd() on the result of calling
fileno() on the open FILE*, but FILE* may do its own buffering. Thus,
if C has already read from the FILE*, the integer file descriptor's idea
of the current file position may be different from the FILE*'s idea.
Furthermore, fopen() may have already started buffering content from the
file into the FILE*, so the fd and the FILE* may not line up even if the
C world hasn't read from it.
An alternative to this approach would be to wrap the FILE* in a Gray
stream. I don't mind doing this, but since I'm only interested in
supporting ECL, and since ECL just uses a FILE* internally anyway, I
figured I should avoid the Gray stream machinery.
mfh
cl_object
ecl_make_stream_from_fileptr (FILE* f)
{
cl_object stream;
enum ecl_smmode smm;
int info = 0;
/* Query f's mode -- see function below */
smm = ecl_file_mode (f, &info);
if (info != 0)
return Cnil; /* or signal an error, etc. */
stream = cl_alloc_object (t_stream);
stream->stream.mode = (short)smm;
stream->stream.closed = 0;
stream->stream.file = f;
stream->stream.object0 = @'base-char';
/* ecl_make_stream_from_fd() said object1 isn't used */
stream->stream.object1 = Cnil;
stream->stream.int0 = stream->stream.int1 = 0;
stream->stream.char_stream_p = 1;
stream->stream.byte_size = 8;
stream->stream.signed_bytes = 0;
stream->stream.last_op = 0;
si_set_finalizer (stream, Ct);
return stream;
}
/**
* Query f's mode (input, output, or both) using the POSIX function
* fcntl(), and return the result. Set *info to zero if no errors,
* else set *info to nonzero.
*/
static enum ecl_smmode
ecl_file_mode (FILE* f, int* const info)
{
enum ecl_smmode smm;
int fd = fileno (f);
int flags = fcntl (fd, F_GETFL);
int modified_flags;
if (flags == -1)
{
*info = -1;
return smm_input; /* have to return something */
}
*info = 0;
flags = O_ACCMODE && flags;
if (flags == O_RDONLY)
return smm_input;
else if (flags == O_WRONLY)
return smm_output;
else if (flags == O_RDWR)
return smm_io;
else
{
*info = -2;
return smm_input; /* have to return something */
}
}
More information about the ecl-devel
mailing list