Hi Mark, Sorry for taking so long to respond.
[email protected] writes: > Mark H Weaver <[email protected]> writes: > >> [email protected] writes: >>> Reading and writing to a socket seems to lend itself well to custom >>> binary ports, >> >> Why do you say that? For most purposes, Guile's native file ports are >> superior, and they seem the natural choice for sockets. >> > > I over-generalized. In my application, I'm using the X protocol, which > is a binary one. I've been so involved with that I forgot that much of > the time you want to read/write character data from a socket. Guile's native file ports (which also work on sockets) can be used for binary data as well as character data. There's no need to create a custom binary port for this purpose. Indeed, the custom ports have several major disadvantages compared to the native file ports. >> 'get-bytevector-some' from (rnrs io ports) might do what you need. If >> there's at least one byte available it will not block, but in practice >> it reads much more than that (for buffered ports). Guile 2.0.9 has a >> nice fast implementation. Prior to 2.0.9, it was less so. >> >> In more detail: as of 2.0.9, 'get-bytevector-some' will simply copy the >> input buffer managed by Guile into a bytevector and return it. If >> Guile's input buffer is empty, it will try to refill the buffer using >> the port type's 'fill_input' method. For file ports this is >> fports.c:fport_fill_input, and for custom binary ports it's >> r6rs-ports.c:cbip_fill_input. > > In order to know if the port has at least one byte ready, you need to be > able to call 'char-ready?', don't you? And as you mentioned, that > doesn't work on custom binary ports. I'm still exploring this part of > Guile so I might not have the details right. > >> >> So again I ask, why use custom binary ports for sockets? >> > > Thanks for the detailed explanation; I think I'll move away from > them. Were they added just to meet the r6rs spec? Are there any good > uses for custom binary ports that you're aware of? Yes, custom ports are needed if the data that's being read is not coming from a file, pipe, device, socket, string, or bytevector (the cases covered by Guile's existing native port types; maybe I'm forgetting some). Similarly for writing. For example, suppose you wanted a make an input port that reads keypresses from a GUI interface. In this case, the keypresses are received via events during the main event loop. There is no underlying POSIX file descriptor to read from, nor is there a single Scheme string or bytevector. You could use pipes I suppose, but that assumes POSIX. Another way is to make a custom port. In the case of guile-xcb, I see two places where custom ports are used in auth.scm. Here's the first case: --8<---------------cut here---------------start------------->8--- (define auth-file (open-file (getenv "XAUTHORITY") "rb")) (define port (make-custom-binary-input-port "xcb-auth-input" (lambda (bv start count) (do ((n 0 (1+ n)) (ch (read-char auth-file) (read-char auth-file))) ((or (>= n count) (eof-object? ch)) n) (bytevector-u8-set! bv (+ start n) (char->integer ch)))) #f #f (lambda () (close-port port)))) --8<---------------cut here---------------end--------------->8--- First of all, that '(close-port port)' is wrong. Here you are trying to tell Guile how to close 'port', and this just recurses. I guess it should be (close-port auth-file)'. However, I don't see why this custom port is needed at all. You've already opened 'auth-file' in binary mode, so you should be able to use it directly, i.e. replace the above code with: (define port (open-file (getenv "XAUTHORITY") "rb")) The other case is here (also in auth.scm): --8<---------------cut here---------------start------------->8--- (define (read! bv start count) (let* ((in-bv (make-bytevector count)) (bytes-read (recv! sock in-bv))) (bytevector-copy! in-bv 0 bv start bytes-read) bytes-read)) (define port (make-custom-binary-input-port "xcb-input" read! #f #f #f)) --8<---------------cut here---------------end--------------->8--- Again, I don't see why this custom port should be needed. You should be able to use 'sock' directly. Anyway, thanks for working on this! :) Regards, Mark
