PSTRUCT -- Persistent Structures 1) Usage | OBJECT p[PSTRUCT]; PSTRUCT objects are used to write structured data to permanent storage in a portable and unambigous format. By re-reading an exported PSTRUCT, exactly the same structures are re-created in memory. One PSTRUCT must be created per file to read or write. PSTRUCTs use fully buffered I/O to transfer data from and to external storage. 2) Methods 2.1 CLOSE | P.CLOSE() ! => 0|ERR_IO Close the PSTRUCT P. Return 0 upon success and PSTRUCT.ERR_IO in case of an error. 2.2 EOF | P.EOF() ! => -1|0 Check whether the end of a PSTRUCT P has been reached. The PSTRUCT must be read-only. Return -1, if a subsequent P.READ request would fail due to insufficient data to satisfy the request. Otherwise return 0. 2.3 OPEN | P.OPEN(file, buf, len, mode) ! Str,Bvec,Num,Num => 0|-1 Open the file 'file' in the mode 'mode'. 'Buf' is a buffer which is used to buffer data during I/O requests. 'Len' is the size of 'buf' in bytes. The exact format of 'file' depends on the operating system. 'Mode' determines the operations which may be performed on the file: Mode Description PSTRUCT.FREAD The PSTRUCT is read-only PSTRUCT.FWRITE The PSTRUCT is write-only 2.4 READ | P.READ(pa, pstat) ! Proc,Vec => data|errorcode Read one structure from the PSTRUCT and return it. In case of an error, return an error code instead. 'Pa' is a pointer to an allocation procedure which is used to allocate space for objects read from permanent storage. It must accept one single parameter which specifies the size in bytes of the vector to allocate. For example, the memory management class MEMORY could be used to supply a memory pool: | OBJECT Mem[memory]; In this case, the allocation procedure would look like this: | alloc(n) return Mem.alloc(n); Your allocation procedure may perform some error handling. However, in case of an error, it must return zero to the calling PSTRUCT. The above procedure does this correctly. P.READ appends a zero member to each table read. For example, reading the table | [ 2 3 5 7 ] will result in | [ 2,3,5,7,0 ] 'Pstat' is a pointer to a status variable. When the address of a variable is specified, this variable will be filled with the return code of the function. If 'pstat' is zero, it will be ignored. P.READ returns a pointer to the object read. 2.5 READFROM | P.READFROM(ios, pa, pstat) ! IOstream,Proc,Vec => data|errorcode P.READFROM performs the same operation as P.READ, but it operates on an already-open I/O-Stream rather than the internal I/O-Stream of a PSTRUCT. This way it allows to read stuctured data from system descriptors and/or mix I/O-Stream and PSTRUCT operations. 'Ios' is the I/O-Stream to read. 2.6 WRITE | P.WRITE(tmpl, data) ! Str,Vec => 0|errorcode P.WRITE writes the structured data object 'data' to permanent storage. 'Tmpl' is a template describing the structure to write. P.WRITE returns zero, if the write operation succeeded. Otherwise, it returns an apropriate error code. The template 'tmpl' is a string describing the layout of the 'data' structure. Each character of the string describes one member of the structure. Nested vectors are represented by an enclosing pair of square brackets. These characters are used to describe structures: Char. Format Describes B 0bn... a number in binary notation C 'c' a character N n... a number in decimal notation S "..." a string X 0xn... a number in hexa-decimal notation [] [...] an embedded vector * [...]* a repeatable embedded vector When a '*' operator is used after an embedded structure, P.WRITE will assume that a zero-terminated list of embedded structures is present in memory. It will write all members of this list to external storage. For example, given the table | tbl := [ [1,2,3], [4,5,6], [7,8,9], 0 ]; the message | P.WRITE("[[NNN]]", tbl); will only include the first group (consisting of [1,2,3]) in the structure which is written to permanent storage, but | P.WRITE("[[NNN]*]", tbl); will include all the groups of 'tbl'. 2.7 WRITETO | P.WRITETO(ios, tmpl, data) ! IOstream,Str,Vec => 0|errorcode P.WRITETO performs the same operation as P.WRITE, but it operates on an already-open I/O-Stream rather than the internal I/O-Stream of a PSTRUCT. This way it allows to write stuctured data to system descriptors and/or mix I/O-Stream and PSTRUCT operations. 'Ios' is the I/O-Stream to write to. 2.8 Error Codes Error Code Meaning PSTRUCT.ERR_IO An I/O error occurred (read error, insufficient . space on device, etc). PSTRUCT.ERR_EOF The end of file was reached during a READ or . READFROM operation. PSTRUCT.ERR_FMT An invalid template was passed to P.WRITE or . an input token could not be recognized by P.READ . or P.READFROM. PSTRUCT.ERR_MEM An allocation procedure returned failure. The . structure to read is too big to fit in the . supplied chunk of memory. 2.9 External Representation Data are written to files in the following format: Type Example Represented by B 0b10101 A string of binary digits prefixed with 0b. C 'x' A single character enclosed in apostrophes. (*) N -1250 A string of decimal digits prefixed with an . . optional leading minus sign. S "xyz" A string pf characters enclosed in double . . quotes. (*) [...] ['x'] An list of objects of any type enclosed by . . square brackets. X 0xF5 A string of hexa-decimal digits prefixed with 0x. (*) In character and string literals, unprintable characters (in the range 0...31 and 127...255) will be represented by a backslash followed by the code of the character in hexa-decimal notation. For example 'control-G' will be saved as '\07', In structures enclosed by [ and ], a space character must be included after [, before ], and between each two members of the structure. P.WRITE will attempt to write data in a 'pretty' form by indenting nested structures by one space character. For example, the table | [ [ 'l',"Load" ], [ 's', "Save" ], [ 'x', "Exit" ] ] would be written as | [ | [ 'l' "Load" ] | [ 's' "Save" ] | [ 'x' "Exit" ] | ] when using the template "[[CS]*]".