The underlying I/O routines of the operating system act on collections of bytes, which are 8-bit quantities that can be thought of as integers in the range 0..255. The Magma I/O routines provide three different interpretations of these collections of bytes: as strings (textual data), as byte sequences, and as representations of Magma objects. The first two of these are unstructured --- any amount of data is a valid instance --- while the third viewpoint requires that the byte values conform to a certain protocol. This protocol is described in a separate document (Magma Object Transfer Protocol), available from the Magma website.
To make error handling easier, most of the I/O operations that read or write data also have checked variants that will not raise an error due to I/O failure but instead return whether the operation was successful.
The I/O operations described below that return strings need some way of indicating when a read request fails due to no more data being available. This is achieved by returning a special "end of file" (shortened to "EOF") string that is not equal to any normal string.
Creates the special EOF string.
Given a string S, return whether S is the special EOF string.
Returns whether all data is known to have been read from I (and thus that further reads will return the special EOF string). Note that if this function returns false then it may still be the case that the next read returns EOF; typically AtEof only returns true when a previous read has already returned EOF.
> eof := Eof(); > eof; EOF > IsEof(eof); trueNote that the special EOF string is different from the string "EOF", which is a normal string.
> E := "EOF"; > E; EOF > IsEof(E); false
Max: RngIntElt Default: 0
Waits for data to become available for reading from I and then returns it as a string. If the parameter Max is set to a positive value then at most that many bytes will be read. Note that fewer than Max bytes may be returned, depending on the amount of currently available data.If no data can be read from I then the special EOF string is returned.
Max: RngIntElt Default: 0
Performs the same Read action as above. If an error would arise then instead false is returned; otherwise true is returned along with the result of the read.
Attempts to read exactly n bytes of data from I and then returns it as a string; will wait if necessary until either n bytes have become available or the input has terminated. Note that the returned string may contain fewer than n bytes if the input has terminated.If the input terminates and no bytes have been read then the special EOF string is returned.
Performs the same Read action as above. If an error would arise then instead false is returned; otherwise true is returned along with the result of the read.
Writes the characters of the string s to I.
Performs the same Write action as above. Returns whether the write completed without error.
The I/O operations in this section are retained for compatibility with older versions of Magma. They reflect the semantics of the C standard I/O library at the time. Their use is somewhat discouraged, although there is currently no good alternative for getting a line of input at a time (as provided by Gets).
Writes the string s to the channel I. This is equivalent to Write(I, s).
Writes the string s to the channel I, followed by a newline character. This is equivalent to Write(I, s cat "\n").
Reads a single character from I and returns it as a string. This is equivalent to Read(I, 1). If no data is available from I then the special EOF string is returned instead.
Reads a line of input from I and returns it as a string. The line is considered to end when either a newline character is received or all data in I has been received. If a newline character is received then it is omitted from the returned string. If no data at all is available from I then the special EOF string is returned instead.This routine is only currently available for files and pipes.
Pushes the given character (a string of length one) c into the start of the input buffer of I. The next read operation on I should return this character as the first byte.This routine is only currently available for files and pipes.
Use of this intrinsic may interact unpredictably and poorly with asynchronous I/O, and especially so when reading objects. Its use is strongly discouraged and it will probably be removed in a future release.
> function LineCount(F) > FP := Open(F, "r"); > count := 0; > while true do > line := Gets(FP); > if IsEof(line) then > break; > end if; > count +:= 1; > end while; > return count; > end function; > LineCount("/etc/passwd"); 59
A byte sequence is a sequence of integers in the range 0..255. Note that byte sequences have the ring of integers as their universe; they will never be null.
Max: RngIntElt Default: 0
Waits for data to become available for reading from I and then returns it as a byte sequence. If the parameter Max is set to a positive value then at most that many bytes will be read. Note that fewer than Max bytes may be returned, depending on the amount of currently available data.If no data can be read from I then an empty byte sequence is returned.
Max: RngIntElt Default: 0
Performs the same ReadBytes action as above. If an error would arise then instead false is returned; otherwise true is returned along with the result of the read.
Attempts to read exactly n bytes of data from I and then returns it as a byte sequence; will wait if necessary until either n bytes have become available or the input has terminated. Note that the returned sequence may contain fewer than n bytes if the input has terminated.If the input terminates and no bytes have been read then an empty byte sequence is returned.
Performs the same ReadBytes action as above. If an error would arise then instead false is returned; otherwise true is returned along with the result of the read.
Writes the bytes of the byte sequence S to I.
Performs the same WriteBytes action as above. Returns whether the write completed without error.
Some Magma objects can be used in I/O calls. The details of which objects can be handled, as well as specifications of the format, are provided in a separate document (Magma Object Transfer Protocol), available from the Magma website.
As of V25.1 the allowable object types include integers, rationals, reals, complexes, booleans, strings, finite field elements, polynomials (univariate and multivariate), sequences, sets, indexed sets, multisets, tuples, lists, records, matrices, vectors, lattices, permutations, number field elements, and all the associated parent structures. Support for more types of objects will continue to be added in patch releases.
Reads a Magma object from I in Magma Object Format and returns it. An error will be raised if input terminates before a complete object can be read.
Performs the same ReadObject action as above. If an error would arise then instead false is returned; otherwise true is returned along with the result of the read.
Writes the Magma object x to I, using the Magma Object Format.
Performs the same WriteObject action as above. Returns whether the write completed without error.
As described in the Magma Object Transfer Protocol document (available from the Magma website), each program that can read or write Magma objects does so according to the Protocol. This Protocol will continue to evolve as more objects are implemented and as more features are added.
In order to manage the different versions of the Protocol, each is associated with a unique version number (or simply version), and this version forms part of the data for each object. Programs that understand one version of the Protocol are also expected to understand all previous versions. Thus programs can detect if a received object uses a later version of the Protocol and raise an error, or cooperate to ensure that communication takes place using only a mutually-understood version of the Protocol.
In the following, a version number is represented as a string of the form "M.m", where M and m are integers between 0 and 65 535 (inclusive). When two programs wish to exchange Magma objects, the first step should be for each to notify the other of the version of the Protocol that it understands. Each program can then send objects using the lower of the two versions, ensuring that the object data is correctly interpreted by the other program.
Returns the maximum (latest) version number of the Protocol that is understood by this copy of Magma.
Returns the version number of the Protocol that will be used by Magma for newly-created I/O objects. This will usually be the same as the maximum version, but the user can explicitly lower it by using SetMOTPVersion.
Sets the version of the Protocol to use with newly-created channels. This may not be set to a value higher than the maximum version (as returned by GetMOTPMaxVersion). Usually it is not desirable to change this value as version negotiation takes care of communication issues, but it can be useful when testing or when saving objects that are to be read later by programs that only understand an earlier version of the Protocol.
Sets the version of the Protocol to use from now on with the given channel. Usually it is not desirable to change this value as version negotiation takes care of communication issues, but it can be useful when testing or when saving objects that are to be read later by programs that only understand an earlier version of the Protocol.
Sends a version Protocol message to the other end of the channel that contains the desired version number to use for communication. i.e., a version number that this program will be able to understand. This will be either the value returned by GetMOTPVersion when the channel was created, or the value used in a call to SetMOTPVersion on the channel.It is allowed, but unusual, to send versions in this way after the initial exchange of versions occurs. The other end of the channel is expected to update its internal value to use for communication when it receives such a message. For more details see the Magma Object Transfer Protocol document.
Expects a version Protocol message containing a version number understood by the other end of the communication channel. This version will be stored internally and Protocol messages sent to the other end of the channel will use a version no higher than this value. An error will arise if a different Protocol message was received when a version was expected.
Performs both a NotifyVersion and ExpectVersion on the channel. This is the preferred method to use; after a communication channel has been set up then the first thing both sides should do is to call ExchangeVersions (or its asynchronous version, see later) on the channel. Thereafter objects can be safely sent and received.Note: It is often the case that one is using the same version of Magma on each machine, and thus that each process understands the same version of the Protocol. It may thus be tempting to omit the use of ExchangeVersions under such circumstances, and this is reasonable for interactive sessions. However, it is strongly encouraged to use ExchangeVersions in longer-lived code; doing so will save many headaches down the line when one finds oneself trying to get different versions of Magma to interact.
> // First Magma process > server := Socket(: LocalHost := "localhost", LocalPort := 4000); > S1 := WaitForConnection(server);The first Magma process is now waiting for a connection to be made. We create a client socket in another Magma process on the same machine and establish the connection with the first process. Since we intend to exchange objects over this connection, we also do the version exchange immediately.
> // Second Magma process > S2 := Socket("localhost", 4000); > ExchangeVersions(S2);Now the second Magma process is waiting for the version exchange to be complete. The first process has received the connection and completes the version exchange.
> // First Magma process > ExchangeVersions(S1);Both processes are now ready to communicate using ReadObject and WriteObject. We demonstrate some simple exchanges.
> // First Magma process > WriteObject(S1, [ IsPrime(x) : x in [1..10] ]);
> // Second Magma process > ReadObject(S2); [ false, true, true, false, true, false, true, false, false, false ] > WriteObject(S2, IdentityMatrix(Rationals(), 2));
> // First Magma process > ReadObject(S1); [1 0] [0 1] > Parent($1); Full Matrix Algebra of degree 2 over Rational FieldIt is possible to use eval and Magma-level printing in order to send objects of types that not yet handled by the Protocol.
> // First Magma process > E := EllipticCurve("37a1"); > E; Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field > WriteObject(S1, E); >> WriteObject(S1, E); ^ Runtime error in 'WriteObject': Unable to serialize specified object > WriteObject(S1, Sprint(E, "Magma"));
> // Second Magma process > E := eval ReadObject(S2); > E; Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field
Some I/O types have positioning information associated with them, and this information can be retrieved and modified to allow access to specific parts of the data. Essentially, we regard the object as equivalent to a large array of bytes and the position as being the index within that array that the next I/O call will start from.
I/O types that support this view are called seekable, after the C library function for manipulating the position. Currently only file objects are seekable. Note: The position starts at 0, not 1, reflecting the C conventions of the underlying operating system calls.
Given a seekable channel I, returns the current position as an integer.
Adjusts the position of the seekable channel I to be at the given offset relative to the origin. The origin must be one of: 0 to mean relative to the beginning; 1 to mean relative to the current position; or 2 to indicate relative to the end of the channel. If the origin is not specified then it is taken to be 0.
Moves the position of the seekable channel I to the beginning. This is equivalent to Seek(I, 0).
This routine ensures that all pending output on the given channel has been committed. It is useful to ensure that previously-committed asynchronous writes have completed, and also to ensure that any buffered data has actually been written.