(********************************************************************) (* *) (* null_file.s7i Base implementation type for all files *) (* Copyright (C) 1989 - 2013, 2021, 2022 Thomas Mertes *) (* *) (* This file is part of the Seed7 Runtime Library. *) (* *) (* The Seed7 Runtime Library is free software; you can *) (* redistribute it and/or modify it under the terms of the GNU *) (* Lesser General Public License as published by the Free Software *) (* Foundation; either version 2.1 of the License, or (at your *) (* option) any later version. *) (* *) (* The Seed7 Runtime Library is distributed in the hope that it *) (* will be useful, but WITHOUT ANY WARRANTY; without even the *) (* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR *) (* PURPOSE. See the GNU Lesser General Public License for more *) (* details. *) (* *) (* You should have received a copy of the GNU Lesser General *) (* Public License along with this program; if not, write to the *) (* Free Software Foundation, Inc., 51 Franklin Street, *) (* Fifth Floor, Boston, MA 02110-1301, USA. *) (* *) (********************************************************************) include "file.s7i"; (** * Base implementation type for the [[file]] interface. * A ''null_file'' discards all data written to it. Reads from a * ''null_file'' always yield [[char#EOF|EOF]] immediately. A ''null_file'' * is not seekable. The functions [[#length(in_null_file)|length]], * [[#seek(in_null_file,in_integer)|seek]] and [[#tell(in_null_file)|tell]] * raise FILE_ERROR. The functions [[#getc(inout_null_file)|getc]], * [[#getwd(inout_null_file)|getwd]] and [[#getln(inout_null_file)|getln]] * are written such that a derived type can use them. Derived * types of ''null_file'' need to override the functions * [[#write(in_null_file,in_string)|write]], [[#gets(in_null_file,in_integer)|gets]], * [[#eof(in_null_file)|eof]] and [[#hasNext(in_null_file)|hasNext]]. * A derived type, which represents a seekable file, needs to * override the functions [[#length(in_null_file)|length]], * [[#seek(in_null_file,in_integer)|seek]] and [[#tell(in_null_file)|tell]]. *) const type: null_file is new struct var char: bufferChar is '\n'; end struct; type_implements_interface(null_file, file); const func boolean: (in null_file: aFile1) = (in null_file: aFile2) is action "ENU_EQ"; const func boolean: (in null_file: aFile1) <> (in null_file: aFile2) is action "ENU_NE"; (** * Standard null file. * Anything written to STD_NULL is ignored. Reading from STD_NULL does not * deliver data. * eof(STD_NULL) returns TRUE * getc(STD_NULL) returns EOF * gets(STD_NULL, 1) returns "" * The file STD_NULL is used to initialize [[file]] variables * and as result of [[external_file#open(in_string,in_string)|open]], * if a ''file'' cannot be opened. *) var null_file: STD_NULL is null_file.value; (** * Default value of ''file'' (STD_NULL). *) const file: (attr file) . value is STD_NULL; (** * Write a [[string]] to a ''null_file''. * The parameter ''stri'' is just ignored. Derived types of * ''null_file'' need to override this function. *) const proc: write (in null_file: outFile, in string: stri) is noop; (** * Write end-of-line to ''outFile''. * This function writes the end-of-line marker '\n'. Derived types * can use this function. If a derived type does not use '\n' * as end-of-line marker it needs to override this function. *) const proc: writeln (inout null_file: outFile) is func begin write(outFile, "\n"); end func; (** * Write a [[string]] followed by end-of-line to ''outFile''. * This function is based on write and writeln. Derived types * can use this function. This function must be overridden, if * it is necessary to write ''stri'' and '\n' together. *) const proc: writeln (inout null_file: outFile, in string: stri) is func begin write(outFile, stri); writeln(outFile); end func; (** * Read a string with a maximum length from a ''null_file''. * Derived types of ''null_file'' need to override this function. * @return the empty string (""). * @exception RANGE_ERROR The parameter ''maxLength'' is negative. *) const func string: gets (in null_file: inFile, in integer: maxLength) is func result var string: striRead is ""; begin if maxLength < 0 then raise RANGE_ERROR; end if; end func; (** * Read a character from a ''null_file''. * This function is based on the gets function. Therefore it is * useable for derived types of ''null_file''. For the ''null_file'' * itself it always returns [[char#EOF|EOF]]. * @return the character read, or [[char#EOF|EOF]] at the end of the file. *) const func char: getc (inout null_file: inFile) is func result var char: charRead is ' '; local var string: buffer is ""; begin buffer := gets(inFile, 1); if buffer = "" then charRead := EOF; else charRead := buffer[1]; end if; end func; (** * Read a [[string]] from ''inFile'' until the ''terminator'' character is found. * If a ''terminator'' is found the string before the ''terminator'' is * returned and the ''terminator'' character is assigned to inFile.bufferChar. * The file position is advanced after the ''terminator'' character. * If no ''terminator'' is found the rest of ''inFile'' is returned and * [[char#EOF|EOF]] is assigned to the inFile.bufferChar. When the function * is left inFile.bufferChar contains either ''terminator'' or [[char#EOF|EOF]]. * This function is based on the gets function. * Therefore it is useable for derived types of ''null_file''. * For the ''null_file'' itself it always returns "" and assigns * [[char#EOF|EOF]] to inFile.bufferChar. * @param inFile File from which the string is read. * @param terminator Character which terminates the string. * @return the string read without the ''terminator'' or the rest of the * file if no ''terminator'' is found. *) const func string: getTerminatedString (inout null_file: inFile, in char: terminator) is func result var string: stri is ""; local var string: buffer is ""; begin buffer := gets(inFile, 1); while buffer <> "" and buffer[1] <> terminator do stri &:= buffer; buffer := gets(inFile, 1); end while; if buffer = "" then inFile.bufferChar := EOF; else inFile.bufferChar := terminator; end if; end func; (** * Read a word from a ''null_file''. * Before reading the word it skips spaces and tabs. The function * accepts words ending with ' ', '\t', '\n' or [[char#EOF|EOF]]. The * word ending characters are not copied into the string. When the * function is left inFile.bufferChar contains ' ', '\t', '\n' or * [[char#EOF|EOF]]. This function is based on the gets function. * Therefore it is useable for derived types of ''null_file''. * For the ''null_file'' itself it always returns "" and assigns * [[char#EOF|EOF]] to inFile.bufferChar. * @return the word read. *) const func string: getwd (inout null_file: inFile) is func result var string: word is ""; local var string: buffer is ""; begin repeat buffer := gets(inFile, 1); until buffer <> " " and buffer <> "\t"; while buffer <> " " and buffer <> "\t" and buffer <> "\n" and buffer <> "" do word &:= buffer; buffer := gets(inFile, 1); end while; if buffer = "" then inFile.bufferChar := EOF; else inFile.bufferChar := buffer[1]; end if; end func; (** * Read a line from a ''null_file''. * The function accepts lines ending with '\n' or [[char#EOF|EOF]]. * The line ending characters are not copied into the string. When * the function is left inFile.bufferChar contains '\n' or * [[char#EOF|EOF]]. This function is based on the gets function. * Therefore it is useable for derived types of ''null_file''. * For the ''null_file'' itself it always returns "" and assigns * [[char#EOF|EOF]] to inFile.bufferChar. * @return the line read. *) const func string: getln (inout null_file: inFile) is func result var string: line is ""; local var string: buffer is ""; begin buffer := gets(inFile, 1); while buffer <> "\n" and buffer <> "" do line &:= buffer; buffer := gets(inFile, 1); end while; if buffer = "" then inFile.bufferChar := EOF; else inFile.bufferChar := '\n'; end if; end func; (** * Determine the end-of-file indicator. * Derived types of ''null_file'' need to override this function. * @return TRUE, since a ''null_file'' is always at end-of-file. *) const boolean: eof (in null_file: inFile) is TRUE; (** * Determine if at least one character can be read successfully. * Derived types of ''null_file'' need to override this function. * @return FALSE, since the next ''getc'' will always return * [[char#EOF|EOF]]. *) const boolean: hasNext (in null_file: inFile) is FALSE; const func boolean: eoln (in null_file: inFile) is return inFile.bufferChar = '\n'; (** * Obtain the length of a file. * A ''null_file'' is not seekable, therefore FILE_ERROR is raised. * Derived types of ''null_file'' need to override this function. * @return nothing, because FILE_ERROR is always raised. * @exception FILE_ERROR Is always raised, because a ''null_file'' is * not seekable. *) const func integer: length (in null_file: aFile) is func result var integer: length is 0; begin raise FILE_ERROR; end func; (** * Determine if the file ''aFile'' is seekable. * If a file is seekable the functions ''seek'' and ''tell'' * can be used to set and and obtain the current file position. * @return FALSE, since a ''null_file'' is not seekable. *) const boolean: seekable (in null_file: aFile) is FALSE; (** * Set the current file position. * A ''null_file'' is not seekable, therefore FILE_ERROR is raised. * If a derived type is seekable it needs to override this function. * @exception FILE_ERROR Is always raised, because a ''null_file'' is * not seekable. *) const proc: seek (in null_file: aFile, in integer: position) is func begin raise FILE_ERROR; end func; (** * Obtain the current file position. * A ''null_file'' is not seekable, therefore FILE_ERROR is raised. * If a derived type is seekable it needs to override this function. * @return nothing, because FILE_ERROR is always raised. * @exception FILE_ERROR Is always raised, because a ''null_file'' is * not seekable. *) const func integer: tell (in null_file: aFile) is func result var integer: position is 0; begin raise FILE_ERROR; end func; const proc: moveLeft (in null_file: outFile, in string: stri) is func begin raise FILE_ERROR; end func; const proc: erase (in null_file: outFile, in string: stri) is func begin raise FILE_ERROR; end func; (** * Close a ''null_file''. * Closing a ''null_file'' has no effect. *) const proc: close (in null_file: aFile) is noop; (** * Forces that all buffered data is sent to its destination. * Flushing a ''null_file'' has no effect. *) const proc: flush (in null_file: aFile) is noop;