| Tables, Rules and Hypothetical Reasoning Hypothetical Reasoning |
categories I/O, Modules and System Interface Communication ports |
Printing |
In XL CLAIRE, the entire port interface has been rewritten such port is now the root class for an extensible hierarchy of communication interface (In CLAIRE 3, ports are based on a C++ import). We define two sorts of port :
Definition : A device is a communication port that is connected to a physical port like a file or a socket that can be handled through a chain of filter |
Definition : A filter is a communication port that may modify, buffer or look at a data read or written from a device. |
Given this sorts, we define the descriptor device as a wrapper for UNIX descriptor which handles read, write (read_port and write_port interface) and close (close_port interface) operations in a unified way for each derived class (disk_file, socket, pipe). At startup, 3 global variables named stdin, stdout and stderr are created to hold the standard input, output, and error devices respectively (UNIX descriptors 0,1,2 on most system).
Languages often provide these standard ports in a buffered way, that is system calls read(2) or write(2) are made by chunks. So XL CLAIRE comes with two kind of filter, the buffer (as created by buffer!) that perform read (or write) once for each read (or written) chunk of a given size and the line_buffer (as created by line_buffer!) that perform write calls once for each written line. Depending on how the program was launched, the standard output may be a terminal or something else (e.g. pipe). In the later case we'll always provide stdout as a buffer but when it is found that the output is a terminal device, which is often shared by multiple processes, we'll provide stdout as a line_buffer. On the other hand the standard error port is always provided unbuffered, such that in case of crash we avoid data miss that could be hold by a buffer.
To avoid problems of synchronization between reading and writing, it is sometimes useful to ensure that the buffer of a given port is empty. This is done by the command flush(p:port). flush(p) will perform all printing instructions for the port p that are waiting in the associated buffer (flush_port interface).
A (buffered) file is opened with fopen(s:string,m:string) where s is the file path and m the opening mode ("r": read, "w": write, "a": append). For instance :
| inefficient_show_size(filepath:string) : void -> let f := fopen(filepath, "r"), content := fread(f) in printf("File ~A has ~S bytes\n", filepath, length(content)) |
| let b := blob!("toto") in assert(fread(b) = "toto") let b := blob!() in (fwrite("toto",b), assert(fread(b) = "toto")) |
| categories | Communication ports | normal dispatch | operation | [XL] Core method |
translate the char* pointer self with an offset of n bytes
| categories | Communication ports | ephemeral | [XL] Core class |
blob is a port interface for strings, data are stored in a chunk of memory allocated outside claire memory.
| categories | Communication ports | normal dispatch | [XL] Core method |
allocate an empty blob
| categories | Communication ports | normal dispatch | [XL] Core method |
allocate a blob that can receive at least n bytes (i.e. writing more than n bytes may cause further allocation)
| categories | Communication ports | normal dispatch | [XL] Core method |
allocate a blob that is a copy of the given blob
| categories | Communication ports | normal dispatch | [XL] Core method |
allocate a blob with the string self has the initial data
| categories | Communication ports | normal dispatch | [XL] Core method |
allocate a blob that is filled with all data that can be read on p
| categories | Communication ports | normal dispatch | [XL] Core method |
perform a back-quote expansion of the system command s. subexpressions enclosed by '`' are substituted by the output generated by the corresponding command ex: bexpand("`ls`") returns the result of an ls command
| categories | Communication ports | ephemeral | [XL] Core class |
a buffer filter performs a single read/write call on its target for each data raw of a given size (buffer_length). It comes as replacement of the C FILE* buffering capability.
| categories | Communication ports | normal dispatch | [XL] Core method |
buffer! creates a buffer filter on the port self with an internal buffer bufsize bytes long.
| categories | Communication ports | ephemeral | [XL] Core class |
byte_counter is a pure filter that count the number of bytes transfered in both directions
| categories | Communication ports | abstract | [XL] Core class |
read_port and write_port operate on a given buffer of a given size. these buffers are char* imported from C, this way we have an interface similar to read(2) and write(2)
| categories | Communication ports | normal dispatch | [XL] Core method |
creates a UNIX domain connected socket on the UNIX domain server at file addr
| categories | Communication ports | normal dispatch | [XL] Core method |
creates a connected socket at the address "addr:p", addr may be a numeric IP or a server name and p is the TCP port on which the connection should be made. For instance we could implement a simple HTTP GET :
| httpget(addr:string, f:string) : string -> let c := client!(addr, 80) in (printf(c, "GET /~A HTTP/1.0\r\n\r\n", f), let response := fread(c) in (fclose(c), response)) |
| categories | Communication ports | fast dispatch | [XL] Core interface |
| close_port(self:my_port) : void -> ... |
| categories | Communication ports | normal dispatch | [XL] Core method |
tell that the filter should close its target when it is itself closed (cascading close)
| categories | Communication ports | normal dispatch | [XL] Kernel method |
decode64(pr,pw) reads pr until EOF. read data is assumed to be encoded in base 64, the decoded data is written on pw.
| categories | Communication ports | ephemeral | [XL] Core class |
UNIX file descriptor wrapping. we do not use C stream capabilities (FILE*) but the descriptor itself, which make the API relying on system calls read(2) and write(2), stream interface is provided by filters (buffer)
| categories | Communication ports | ephemeral | [XL] Core class |
physical port like a descriptor or a blob that may be handled through a chain of filter
| categories | Communication ports | ephemeral | [XL] Core class |
disk_file is the interface for file located on the hard drive
| categories | Communication ports | normal dispatch | [XL] Kernel method |
encode64(pr,pw,line_length) reads pr until EOF. read data are encoded in base 64 and then written on the port pw. line_length specify the length at which carriage return are inserted.
| categories | Communication ports | normal dispatch | [XL] Core method |
check whether the end-of-file condition has been reached
| categories | Communication ports | fast dispatch | [XL] Core interface |
interface to check the end-of-file condition on a given port :
| eof_port?(self:my_port) : boolean -> ... |
| categories | Communication ports | ephemeral | [XL] Core class |
port that may analyze and/or transform and/or collect read and/or written data like a buffer, a line counter or even a MIME decoder or any kind embedded protocols.
| categories | Communication ports | normal dispatch | [XL] Core method |
filter! should be used by filter constructors, it ensures the good shape of the inner relations (i.e. between the filter and its device)
| categories | Communication ports | normal dispatch | Core method |
flush pending buffers in the filter chain such pending data are actually written on the device
| categories | Communication ports | normal dispatch | Core method |
for compatibility with <ycs> mainly used for stdin
| categories | Communication ports | fast dispatch | [XL] Core interface |
interface to flush pending buffered data
| flush_port(self:my_port) : void -> ... |
| categories | Communication ports | normal dispatch | [XL] Core method |
open a file on disk. the returned port is buffered. This is a lib C like fopen API (see man for details). note: unlike in C lib there is no support for the 'b' mode (binary) i.e. always open in binary mode. For instance here is a simple file copy method :
| file_copy(src:string, cpy:string) : void -> let fsrc := fopen(src, "r"), fcpy := fopen(cpy,"w") in (freadwrite(fsrc, fcpy), fclose(fsrc), fclose(fcpy)) |
| categories | Communication ports | normal dispatch | [XL] Kernel method |
read all data on self until eof
| categories | Communication ports | normal dispatch | [XL] Kernel method |
read inside an existing string, this overwrites the string content and may modify the string length if an eof condition is reached on self. the amount of queried bytes is the length of the input string
| categories | Communication ports | normal dispatch | [XL] Kernel method |
read a string of n bytes on self the length of the returned string may be lower than n if an eof condition is reached on self
| categories | Communication ports | normal dispatch | [XL] Kernel method |
freadline(p) read a single line on the port p. The end-on-line marker is either CRLF, CR or LF and is not part of the returned line.
| categories | Communication ports | normal dispatch | [XL] Kernel method |
Equivalent to freadline(p, sep, true)[1]
| categories | Communication ports | normal dispatch | [XL] Kernel method |
Equivalent to freadline(p, seps, true) For instance :
| parse_line_of_floats(p:port) : list[float] -> let l := list[float] in (while not(eof?(p)) let (data, sep) := freadline(p, {',', ';', '\n'}) in (if (length(data) > 0) l add float!(data), case sep ({""} break())), l) |
| categories | Communication ports | normal dispatch | [XL] Kernel method |
Equivalent to freadline(p, list(sep), sensitive?) but without support for escaping.
| categories | Communication ports | normal dispatch | [XL] Kernel method |
read a raw data from p until a separator in seps matches. If sensitive? is false the separator matching is made insensitively. esc is an escape char that is used while reading the raw data so that the char that follows cannot be part of a match. The return value is a tuple made of :
| categories | Communication ports | normal dispatch | [XL] Kernel method |
Equivalent to freadline(p, list(sep), sensitive?, esc)[1]
| categories | Communication ports | normal dispatch | [XL] Kernel method |
read all data from src until eof and write it on trgt without performing any allocation. returns the amount of byte transfered.
| categories | Communication ports | normal dispatch | [XL] Kernel method |
read up-to len bytes from src and write them on trgt without performing any allocation. returns the amount of bytes actually transferred (may be lower than len if an eof condition is reached on src)
| categories | Communication ports | normal dispatch | [XL] Core method |
skip n bytes from self (dummy read) without performing any allocation and return the amount of bytes actually skipped (may be lower than len if an eof condition is reached)
| categories | Communication ports | normal dispatch | [XL] Kernel method |
writes a raw string on the port p
| categories | Communication ports | normal dispatch | [XL] Kernel method |
returns the current reading index
| categories | Communication ports | normal dispatch | [XL] Core method |
read a single char on self reading an EOF char does not mean that the end-of-file is reached, one should use eof? @ port to check the eof condition
| categories | Communication ports | normal dispatch | [XL] Core method |
returns the name of the host running CLAIRE
| categories | Communication ports | normal dispatch | [XL] Kernel method |
return the total amount of bytes contained in the blob, string! @ blob will return a string with that length
| categories | Communication ports | ephemeral | [XL] Core class |
line_buffer is a write filter that collects written data until a new line character. each line is flushed with a single write on the target port. It is mainly used for terminal output such to prevent line overlap when multiple process share the same terminal output or when a trace file is shared by multiple process.
| categories | Communication ports | normal dispatch | [XL] Core method |
line_buffer! creates a new line_buffer filter on the port self.
| categories | Communication ports | ephemeral | [XL] Core class |
line_counter is a pure filter that count the number of lines transfered in both directions
| categories | Communication ports | normal dispatch | [XL] Core method |
since socket are bi-channel communication ports a simple close (i.e. the two channel at once) may cause the client to miss information already sent on the socket but still unsent from the underlying system point of view. This is the purpose of the linger that will ensure that what is sent is actually received: first, the write channel is closed then we wait for the read channel to be closed by the remote part. For sanity this operation has a timeout of 3 seconds
| categories | Communication ports | ephemeral | [XL] Core class |
the interface for listening sockets. such socket are used with accept to handle new connections.
| categories | Communication ports | normal dispatch | [XL] Kernel method |
| categories | Communication ports | normal dispatch | [XL] Kernel method |
get the char at position n in self (n is a 1 based index).
| categories | Communication ports | normal dispatch | [XL] Kernel method |
| categories | Communication ports | normal dispatch | [XL] Kernel method |
sets the nthchar in self with c (n is a 1 based index).
| categories | Communication ports | ephemeral | [XL] Core class |
interface for UNIX pipes
| categories | Communication ports | normal dispatch | [XL] Core method |
create a pair of unidirectional pipe connected to each other. The first one is intended for read and the second one for write. note: some system may return bi-directional pipes...
| categories | Communication ports | normal dispatch | [XL] Core method |
popen creates a new process with a redirected input ("r") or output (w). popen may be a two way communication device, this is system dependent
| categories | Communication ports | [XL] Core constant |
compatibility with <ycs>, one should use blob! instead.
| categories | Communication ports | normal dispatch | Core method |
writes a single byte on p
| categories | Communication ports | normal dispatch | [XL] Core method |
read!(self) put the descriptor self in the selection set used for the select? operation
| categories | Communication ports | fast dispatch | [XL] Core interface |
interface to read a chunk of data :
| read_port(self:my_port, buf:data*, len:integer) : integer -> ... |
| categories | Communication ports | normal dispatch | [XL] Core method |
readable?(self) returns true when self has been selected (see select?) and that a read operation is guaranteed to succeed.
| categories | Communication ports | normal dispatch | [XL] Core method |
reopen a file for read, the current offset of the reopened file is moved at the same place if a buffer is present on the filter chain then it contents and index are restored
| categories | Communication ports | normal dispatch | [XL] Core method |
select?() waits for selected descriptors for a write or read condition to occur. This method blocks until a condition occur and will always return true as soon as a condition is satisfied. selected descriptors are the one for which read! or write! has been called first. In order to test whether a condition was satisfied on a selected descriptor one should use readable? or writeable?.
| categories | Communication ports | normal dispatch | [XL] Core method |
select?(ms) is the non-blocking version of select?. It returns true whenever a read or write condition is satisfied on a selected descriptor before a timeout of ms milliseconds could occur. If the timeout is reached before a condition could occur then select?(ms) returns false.
When true is returned a read (resp. write) operation is guaranteed to succeed on a descriptor for which readable? (resp. writable?) returns true. If the descriptor is a listener socket and readable? returns true then accept is guaranteed to succeed.
| get_one_char(c:socket) : string -> (read!(c), if (select?(10) & readable?(c)) fread(c, 1) // always succeed else "") |
| categories | Communication ports | normal dispatch | [XL] Core method |
creates a UNIX domain listener socket. addr is the absolutepath (i.e. must start with '/') to a file that will be used by the subsystem as listener descriptor.
| categories | Communication ports | normal dispatch | [XL] Core method |
creates a INET domain listener socket listening on the port p. For instance here is a basic HTTP server :
| http_server(n:integer) : void -> let s := server!(n) in (while true let c := accept(s) in serve_client(c)) serve_client(c:socket) : void -> (printf(c, "Hello world\n"), fclose(c)) (http_server(80)) |
| categories | Communication ports | normal dispatch | [XL] Core method |
creates a INET domain listener socket listening on the port p with an internal queue of qlen connections.
| categories | Communication ports | normal dispatch | [XL] Kernel method |
sets the current reading index
| categories | Communication ports | normal dispatch | [XL] Core method |
sets the amount of bytes contained in the blob, when 0 is given a new chunk is reallocated for the internal data
| categories | Communication ports | ephemeral | [XL] Core class |
the interface for UNIX stream oriented sockets, sockets are two way communication ports connected to a remote client.
| categories | Communication ports | normal dispatch | [XL] Core method |
return a pair of inter-connected socket
| categories | Communication ports | [XL] Core global variable |
the standard error output port
| categories | Communication ports | [XL] Core global variable |
the standard input port
| categories | Communication ports | [XL] Core global variable |
the standard output port
| categories | Communication ports | normal dispatch | [XL] Kernel method |
string! converts a blob in a string
| categories | Communication ports | normal dispatch | [XL] Kernel method |
make a new string of length len from a char*
| categories | Communication ports | normal dispatch | [XL] Kernel method |
returns a substring of the internal data considered, i and j are 1 base indexed
| categories | Communication ports | normal dispatch | [XL] Core method |
unget a string such the next char that can be read is c
| categories | Communication ports | normal dispatch | [XL] Core method |
unget a string such the next data that can be read is s
| categories | Communication ports | fast dispatch | [XL] Core interface |
interface to unget a chunk of data :
| unget_port(self:my_port, buf:data*, len:integer) : void -> ... |
| categories | Communication ports | normal dispatch | [XL] Kernel method |
unlink the UNIX domain socket file associated with the given listener socket
| categories | Communication ports | normal dispatch | Kernel method |
use_as_output(p) changes the value of the current output (the port where all print instructions will be sent AKA cout()) to p. It returns the previous port that was used as output which can thus be saved and possibly restored later.
| categories | Communication ports | normal dispatch | [XL] Core method |
writable?(self) returns true when self has been selected (see select?) and that a write operation is guaranteed to succeed.
| categories | Communication ports | normal dispatch | [XL] Core method |
write!(self) put the descriptor self in the selection set used for the select? operation
| categories | Communication ports | fast dispatch | [XL] Core interface |
interface to write a chunk of data
| write_port(self:my_port, buf:data*, len:integer) : integer -> ... |