[Ecls-list] FILE* -> Lisp stream?

Mark Hoemmen mark.hoemmen at gmail.com
Sun Jul 13 01:31:05 UTC 2008


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.


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;
       *info = -2;
       return smm_input; /* have to return something */

More information about the ecl-devel mailing list