The functions in the previous sections are intended to be a possibility for direct access to the low level I/O functions in the C library. Thus, the calling conventions are strictly as in the original.
The functionality described in this section is implemented completely in the GAP language and is intended to provide a good interface for programming in GAP. The fundamental object for I/O on the C library level is the file descriptor, which is just a non-negative integer representing an open file of the process. The basic idea is to wrap up file descriptors in GAP objects that do the buffering.
Note that considerable care has been taken to ensure that one can do I/O multiplexing with buffered I/O. That is, one always has the possibility to make sure before a read or write operation, that this read or write operation will not block. This is crucial when one wants to serve more than one I/O channel from the same (single-threaded) GAP process. This design principle sometimes made it necessary to have more than one function for a certain operation. Those functions usually differ in a subtle way with respect to their blocking behaviour.
File objectsThe wrapped file objects are in the following category:
> IsFile( o ) | ( Category ) |
The category of File objects.
To create objects in this category, one uses the following function:
> IO_WrapFD( fd, rbufsize, wbufsize ) | ( function ) |
The argument fd must be a file descriptor (i.e. an integer) or -1 (see below).
rbufsize can either be false for unbuffered reading or an integer buffer size or a string. If it is an integer, a read buffer of that size is used. If it is a string, then fd must be -1 and a File object that reads from that string is created.
wbufsize can either be false for unbuffered writing or an integer buffer size or a string. If it is an integer, a write buffer of that size is used. If it is a string, then fd must be -1 and a File object that appends to that string is created.
The result of this function is a new File object.
A convenient way to do this for reading or writing of files on disk is the following function:
> IO_File( filename[, mode] ) | ( function ) |
> IO_File( filename[, bufsize] ) | ( function ) |
> IO_File( filename, mode, bufsize ) | ( function ) |
The argument filename must be a string specifying the path name of the file to work on. mode must also be a string with possible values "r", "w", or "a", meaning read access, write access (with creating and truncating), and append access respectively. If mode is omitted, it defaults to "r". bufsize, if given, must be a positive integer or false, otherwise it defaults to IO.DefaultBufSize. Internally, the IO_open (3.2-31) function is used and the result file descriptor is wrapped using IO_WrapFD (4.1-2) with bufsize as the buffer size.
The result is either fail in case of an error or a File object in case of success.
Once a File object is created, one can use the following functions on it:
> IO_ReadUntilEOF( f ) | ( function ) |
This function reads all data from the file f until the end of file. The data is returned as a GAP string. If the file is already at end of file, an empty string is returned. If an error occurs, then fail is returned.
> IO_ReadBlock( f, len ) | ( function ) |
This function gets two arguments, the first argument f must be a File object and the second argument len must be a positive integer. The function tries to read len bytes and returns a string of that length. If and only if the end of file is reached earlier, fewer bytes are returned. If an error occurs, fail is returned. Note that this function blocks until either len bytes are read, or the end of file is reached, or an error occurs.
> IO_ReadLine( f ) | ( function ) |
This function gets exactly one argument, which must be a File object f. It reads one line of data, where the definition of line is operating system dependent. The line end character(s) are included in the result. The function returns a string with the line in case of success and fail in case of an error. In the latter case, one can query the error with LastSystemError (Reference: LastSystemError).
Note that the reading is done via the buffer of f, such that this function will be quite fast also for large amounts of data.
If the end of file is hit without a line end, the rest of the file is returned. If the file is already at end of file before the call, then a string of length 0 is returned. Note that this is not an error but the standard end of file convention!
> IO_ReadLines( f[, max] ) | ( function ) |
This function gets one or two arguments, the first of which must always be a File object f. It reads lines of data (where the definition of line is operating system dependent) either until end of file (without a second argument) or up to max lines (with a second argument max. A list of strings with the result is returned, if everything went well and fail oterwise. In the latter case, one can query the error with LastSystemError (Reference: LastSystemError).
Note that the reading is done via the buffer of f, such that this function will be quite fast also for large amounts of data.
If the file is already at the end of file, the function returns a list of length 0. Note that this is not an error but the standard end of file convention!
> IO_HasData( f ) | ( function ) |
This function takes one argument f which must be a File object. It returns true or false according to whether there is data to read available in the file f. A return value of true guarantees that the next call to IO_Read (4.2-6) on that file will succeed without blocking and return at least one byte or an empty string to indicate the end of file.
> IO_Read( f, len ) | ( function ) |
The function gets two arguments, the first of which must be a File object f. The second argument must be a positive integer. The function reads data up to len bytes. A string with the result is returned, if everything went well and fail otherwise. In the latter case, one can query the error with LastSystemError (Reference: LastSystemError).
Note that the reading is done via the buffer of f, such that this function will be quite fast also for large amounts of data.
If the file is already at the end of the file, the function returns a string of length 0. Note that this is not an error!
If a previous call to IO_HasData (4.2-5) or to IO_Select (4.3-3) indicated that there is data available to read, then it is guaranteed that the function IO_Read does not block and returns at least one byte if the file is not yet at end of file and an empty string otherwise.
> IO_Write( f[, things, ...] ) | ( function ) |
This function can get an arbitrary number of arguments, the first of which must be a File object f. All the other arguments are just written to f if they are strings. Otherwise, the String function is called on them and the result is written out to f.
Note that the writing is done buffered. That is, the data is first written to the buffer and only really written out after the buffer is full or after the user explicitly calls IO_Flush (4.2-10) on f.
The result is either the number of bytes written in case of success or fail in case of an error. In the latter case the error can be queried with LastSystemError (Reference: LastSystemError).
Note that this function blocks until all data is at least written into the buffer and might block until data can be sent again if the buffer is full.
> IO_WriteLine( f, line ) | ( function ) |
Behaves like IO_Write (4.2-7) but works on a single string line and sends an (operating system dependent) end of line string afterwards. Also IO_Flush (4.2-10) is called automatically after the operation, such that one can be sure, that the data is actually written out after the function has completed.
> IO_WriteLines( f, list ) | ( function ) |
Behaves like IO_Write (4.2-7) but works on a list of strings list and sends an (operating system dependent) end of line string after each string in the list. Also IO_Flush (4.2-10) is called automatically after the operation, such that one can be sure, that the data is actually written out after the function has completed.
> IO_Flush( f ) | ( function ) |
This function gets one argument f, which must be a File object. It writes out all the data that is in the writing buffer. This is not necessary before the call to the function IO_Close (4.2-16), since that function calls IO_Flush automatically. However, it is necessary to call IO_Flush after calls to IO_Write (4.2-7) to be sure that the data is really sent out. The function returns true if everything goes well and fail if an error occurs.
Remember that the functions IO_WriteLine (4.2-8) and IO_WriteLines (4.2-9) implicitly call IO_Flush after they are done.
Note that this function might block until all data is actually written to the file descriptor.
> IO_WriteFlush( f[, things] ) | ( function ) |
This function behaves like IO_Write (4.2-7) followed by a call to IO_Flush (4.2-10). It returns either the number of bytes written or fail if an error occurs.
> IO_ReadyForWrite( f ) | ( function ) |
This function takes one argument f which must be a File object. It returns true or false according to whether the file f is ready to write. A return value of true guarantees that the next call to IO_WriteNonBlocking (4.2-13) on that file will succeed without blocking and accept at least one byte.
> IO_WriteNonBlocking( f, st, pos, len ) | ( function ) |
This function takes four arguments. The first one f must be a File object, the second st a string, and the arguments pos and len must be integers, such that positions pos+1 until pos+len are bound in st. The function tries to write up to len bytes from st from position pos+1 to the file f. If a previous call to IO_ReadyForWrite (4.2-12) or to IO_Select (4.3-3) indicates that f is writable, then it is guaranteed that the following call to IO_WriteNonBlocking will not block and accept at least one byte of data. Note that it is not guaranteed that all len bytes are written. The function returns the number of bytes written or fail if an error occurs.
> IO_ReadyForFlush( f ) | ( function ) |
This function takes one argument f which must be a File object. It returns true or false according to whether the file f is ready to flush. A return value of true guarantees that the next call to IO_FlushNonBlocking (4.2-15) on that file will succeed without blocking and flush out at least one byte. Note that this does not guarantee, that this call succeeds to flush out the whole content of the buffer!
> IO_FlushNonBlocking( f ) | ( function ) |
This function takes one argument f which must be a File object. It tries to write all data in the writing buffer to the file descriptor. If this succeeds, the function returns true and false otherwise. If an error occurs, fail is returned. If a previous call to IO_ReadyForFlush (4.2-14) or IO_Select (4.3-3) indicated that f is flushable, then it is guaranteed that the following call to IO_FlushNonBlocking does not block. However, it is not guaranteed that true is returned from that call.
> IO_Close( f ) | ( function ) |
This function closes the File object f after writing all data in the write buffer out and closing the file descriptor. All buffers are freed. In case of an error, the function returns fail and otherwise true.
> IO_GetFD( f ) | ( function ) |
This function returns the real file descriptor that is behind the File object f.
> IO_GetWBuf( f ) | ( function ) |
This function gets one argument f which must be a File object and returns the writing buffer of that File object. This is necessary for File objects, that are not associated to a real file descriptor but just collect everything that was written in their writing buffer. Remember to use this function before closing the File object.
> IO_Select( r, w, f, e, t1, t2 ) | ( function ) |
This function is the corresponding function to IO_select (3.2-43) for buffered file access. It behaves similarly to that function. The differences are the following: There are four lists of files r, w, f, and e. They all can contain either integers (standing for file descriptors) or File objects. The list r is for checking, whether files or file descriptors are ready to read, the list w is for checking whether they are ready to write, the list f is for checking whether they are ready to flush, and the list e is for checking whether they have exceptions.
For File objects it is always first checked, whether there is either data available in a reading buffer or space in a writing buffer. If so, they are immediately reported to be ready. For the remaining files and for all specified file descriptors, the function IO_select (3.2-43) is called to get an overview about readiness. The timeout values t1 and t2 are set to zero for immediate returning if one of the requested buffers were ready.
IO_Select returns the number of files or file descriptors that are ready to serve or fail if an error occurs.
The following function is a convenience function for directory access:
> IO_ListDir( pathname ) | ( function ) |
This function gets a string containing a path name as single argument and returns a list of strings that are the names of the files in that directory, or fail, if an error occurred.
The following function is used to create strings describing a pair of an IP address and a port number in a binary way. These strings can be used in connection with the C library functions connect, bind, recvfrom, and sendto for the arguments needing such address pairs.
> IO_MakeIPAddressPort( ipstring, portnr ) | ( function ) |
This function gets a string ipstring containing an IP address in dot notation, i.e. four numbers in the range from 0 to 255 separated by dots ".", and an integer portnr, which is a port number. The result is a string of the correct length to be used for the low level C library functions, wherever IP address port number pairs are needed.
> IO_Environment( ) | ( function ) |
Takes no arguments, uses IO_environ (3.3-2) to get the environment and returns a record in which the component names are the names of the environment variables and the values are the values. This can then be changed and the changed record can be given to IO_MakeEnvList (4.3-7) to produce again a list which can be used for IO_execve (3.2-13) as third argument.
> IO_MakeEnvList( r ) | ( function ) |
Takes a record as returned by IO_Environment (4.3-6) and turns it into a list of strings as needed by IO_execve (3.2-13) as third argument.
> IO_CloseAllFDs( exceptions ) | ( function ) |
Closes all file descriptors except those listed in exceptions, which must be a list of integers.
> IO_Popen( path, argv, mode ) | ( function ) |
Starts a child process with either stdout or stdin being a pipe. The argument mode must be either the string "r" or the string "w".
In the first case, the standard output of the child process will be the writing end of a pipe. A File object for reading connected to the reading end of the pipe is returned. The standard input and standard error of the child process will be the same than the calling GAP process.
In the second case, the standard input of the child process will be the reading end of a pipe. A File object for writing connected to the writing end of the pipe is returned. The standard output and standard error of the child process will be the same than the calling GAP process.
In case of an error, fail is returned.
The process will usually die, when the pipe is closed, but can also do so without that. It lies in the responsability of the caller to IO_WaitPid (3.2-52) for it, if our SIGCHLD handler has been activated (see IO_InstallSIGCHLDHandler (3.3-3)).
In either case the File object will have the attribute "ProcessID" set to the process ID of the child process.
> IO_Popen2( path, argv ) | ( function ) |
A new child process is started. The standard input and standard output of it are pipes. The writing end of the input pipe and the reading end of the output pipe are returned as File objects bound to two components "stdin" and "stdout" (resp.) of the returned record. This means, you have to write to "stdin" and read from "stdout" in the calling GAP process. The standard error of the child process will be the same as the one of the calling GAP process.
Returns fail if an error occurred.
The process will usually die, when one of the pipes is closed. It lies in the responsability of the caller to IO_WaitPid (3.2-52) for it, if our SIGCHLD handler has been activated (see IO_InstallSIGCHLDHandler (3.3-3)).
Both File objects will have the attribute "ProcessID" set to the process ID of the child process, which will also be bound to the "pid" component of the returned record.
> IO_Popen3( path, argv ) | ( function ) |
A new child process is started. The standard input, standard output, and standard error of it are pipes. The writing end of the input pipe, the reading end of the output pipe and the reading end of the error pie are returned as File objects bound to two components "stdin", "stdout", and "stderr" (resp.) of the returned record. This means, you have to write to "stdin" and read from "stdout" and "stderr" in the calling GAP process.
Returns fail if an error occurred.
The process will usually die, when one of the pipes is closed. It lies in the responsability of the caller to IO_WaitPid (3.2-52) for it, if our SIGCHLD handler has been activated (see IO_InstallSIGCHLDHandler (3.3-3)).
All three File objects will have the attribute "ProcessID" set to the process ID of the child process, which will also be bound to the "pid" component of the returned record.
> IO_SendStringBackground( f, st ) | ( function ) |
This functions uses IO_Write (4.2-7) to write the whole string st to the File object f. However, this is done by forking off a child process identical to the calling GAP process that does the sending. The calling GAP process returns immediately, even before anything has been sent away with the result true. The forked off sender process terminates itself immediately, after it has sent all data away.
The reason for having this function available is the following: If one uses IO_Popen2 (4.4-3) or IO_Popen3 (4.4-4) to start up a child process with standard input and standard output being a pipe, then one usually has the problem, that the child process starts reading some data, but then wants to write data, before it received all data coming. If the calling GAP process would first try to write all data and only start to read the output of the child process after sending away all data, a deadlock situation would occur. This is avoided with the forking and backgrounding approach.
Remember to close the writing end of the standard input pipe in the calling GAP process directly after IO_SendStringBackground has returned, because otherwise the child process might not notice that all data has arrived, because the pipe persists! See the file popen2.g in the example directory for an example.
Note that with most modern operating systems the forking off of an identical child process does in fact not mean a duplication of the total main memory used by both processes, because the operating system kernel will use "copy on write". However, if a garbage collection happens to become necessary during the sending of the data in the forked off sending process, this might trigger doubled memory usage.
> IO_PipeThrough( cmd, args, input ) | ( function ) |
Returns: a string or fail
Starts the process with the executable stored at the file name cmd (must be a string) with arguments in the argument list args (a list of strings). The standard input and output of the started process are connected via pipes to the calling process. The content of the string input is written to the standard input of the called process and its standard output is read and returned as a string.
All the necessary I/O multiplexing and non-blocking I/O to avoid deadlocks is done in this function.
> IO_PipeThroughWithError( cmd, args, input ) | ( function ) |
Returns: a string or fail
Starts the process with the executable stored at the file name cmd (must be a string) with arguments in the argument list args (a list of strings). The standard input, output and error of the started process are connected via pipes to the calling process. The content of the string input is written to the standard input of the called process and its standard output and error are read and returned as a record with components out and err, which are strings.
All the necessary I/O multiplexing and non-blocking I/O to avoid deadlocks is done in this function.
generated by GAPDoc2HTML