StdFile.dcl 9.31 KB
Newer Older
1 2
system module StdFile

3 4 5 6
/**
 * Functions to manipulate the file system with the File type.
 */

7
// ****************************************************************************************
8 9
//	Concurrent Clean Standard Library Module Version 3.0
//	Copyright 2019 University of Nijmegen
10 11 12 13
// ****************************************************************************************

//	File modes synonyms

14
//* File mode: read text
15 16
FReadText	:== 0

17
//* File mode: write text
18 19
FWriteText	:== 1

20
//* File mode: append text
21 22
FAppendText	:== 2

23
//* File mode: read data
24 25
FReadData	:== 3

26
//* File mode: write data
27 28
FWriteData	:== 4

29
//* File mode: append data
30
FAppendData	:== 5
31 32 33

//	Seek modes synonyms

34
//* Seek mode: the new position is the seek offset
35 36
FSeekSet	:== 0

37
//* Seek mode: the new position is the current position plus the seek offset
38 39
FSeekCur	:== 1

40
//* Seek mode: the new position is the size of the file plus the seek offset
41 42 43 44 45 46 47 48 49 50 51 52 53
FSeekEnd	:== 2

/**
 * The filesystem environment, independent from *World. This type can only be
 * used through the FileSystem and FileEnv classes.
 */
:: *Files

/**
 * Access to the filesystem.
 *
 * @var The unique type that is used to ensure purity.
 */
54
class FileSystem f where
55 56 57 58 59 60 61 62 63
	/**
	 * Opens a file for the first time in a certain mode.
	 * @param The filename
	 * @param The mode (read / write / append; text / data)
	 * @param The {{`FileSystem`}} (usually {{`World`}})
	 * @result A boolean indicating success
	 * @result The {{`File`}}
	 * @result The new {{`FileSystem`}}
	 */
64
	fopen :: !{#Char} !Int !*f -> (!Bool,!*File,!*f)
65 66 67 68 69 70 71 72

	/**
	 * Closes a file.
	 * @param The {{`File`}}
	 * @param The {{`FileSystem`}}
	 * @result A boolean indicating success
	 * @result The new {{`FileSystem`}}
	 */
73
	fclose :: !*File !*f -> (!Bool,!*f)
74 75 76 77

	/**
	 * Open the 'Console' for reading and writing.
	 */
78
	stdio  :: !*f -> (!*File,!*f)
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93

	/**
	 * With `sfopen` a file can be opened for reading more than once. On a file
	 * opened by `sfopen` only the operations beginning with `sf` can be used.
	 * The `sf...` operations work just like the corresponding `f...`
	 * operations. They can't be used for files opened with {{`fopen`} or
	 * {{`freopen`}}.
	 *
	 * @param The filename
	 * @param The mode (read; text / data)
	 * @param The {{`FileSystem`}} (usually {{`World`}})
	 * @result A boolean indicating success
	 * @result The new {{`File`}}
	 * @result The new {{`FileSystem`}}
	 */
94 95 96 97 98
	sfopen :: !{#Char} !Int !*f -> (!Bool,!File,!*f)

instance FileSystem Files
instance FileSystem World

99 100 101 102 103
/**
 * An environment in which files can be dealt with.
 *
 * @var The unique type that is used to ensure purity.
 */
104 105 106 107 108 109
class FileEnv env where
	accFiles :: !.(*Files -> (.x,*Files)) !*env -> (!.x,!*env)
	appFiles :: !.(*Files -> *Files) !*env -> *env

instance FileEnv World

110 111 112 113 114 115 116
/**
 * Re-opens an open file in a possibly different mode.
 * @param The file
 * @param The new mode
 * @result A boolean indicating successful closing before reopening
 * @result The new file
 */
117
freopen		:: !*File !Int -> (!Bool,!*File)							:== code { .d 0 3 f i ; jsr reopenF ; .o 0 3 b f }
118 119 120

//	Reading from a File:

121 122 123 124 125
/**
 * Reads a character from a text file or a byte from a datafile.
 * @result A boolean indicating success
 * @result The read character
 */
126
freadc		:: !*File -> (!Bool,!Char,!*File)							:== code { .d 0 2 f ; jsr readFC ; .o 0 4 b c f }
127

128 129 130 131 132 133 134
/**
 * Reads an Integer from a textfile by skipping spaces, tabs and newlines and
 * then reading digits, which may be preceeded by a plus or minus sign.
 * From a datafile `freadi` will just read four bytes (a Clean Int).
 * @result A boolean indicating success
 * @result The read integer
 */
135
freadi		:: !*File -> (!Bool,!Int,!*File)							:== code { .d 0 2 f ; jsr readFI ; .o 0 4 b i f }
136

137 138 139 140 141 142 143
/**
 * Reads a Real from a textfile by skipping spaces, tabs and newlines and then
 * reading a character representation of a Real number.
 * From a datafile `freadr` will just read eight bytes (a Clean Real).
 * @result A boolean indicating success
 * @result The read real
 */
144
freadr		:: !*File -> (!Bool,!Real,!*File)							:== code { .d 0 2 f ; jsr readFR ; .o 0 5 b r f }
145

146 147 148 149 150 151 152 153 154
/**
 * Reads n characters from a text or data file, which are returned as a String.
 * If the file doesn't contain n characters the file will be read to the end
 * of the file. An empty String is returned if no characters can be read.
 * @param The file
 * @param The amount of characters to read
 * @result The read string
 * @result The file
 */
155
freads		:: ! *File !Int -> (!*{#Char},!*File)						:== code { .d 0 3 f i ; jsr readFS ; .o 1 2 f }
156

157 158 159 160 161 162 163 164 165 166 167 168
/**
 * Reads `n` characters from a text or data file, which are returned in the
 * string `arg3` at positions `arg1`..`arg1+arg2-1`. If the file doesn't
 * contain `arg2` characters the file will be read to the end of the file, and
 * the part of the string `arg3` that could not be read will not be changed.
 *
 * @param The start of the substring to modify
 * @param The length of the substring
 * @param The string to modify
 * @result The number of characters read
 * @result The modified string
*/
169
freadsubstring :: !Int !Int !*{#Char} !*File -> (!Int,!*{#Char},!*File)	:== code { .d 1 4 i i f ; jsr readFString ; .o 1 3 i f }
170

171 172 173 174
/**
 * Reads a line from a textfile, including a newline character, except for the
 * last line. `freadline` cannot be used on data files.
 */
175
freadline	:: !*File -> (!*{#Char},!*File)								:== code { .d 0 2 f ; jsr readLineF ; .o 1 2 f }
176 177 178

//	Writing to a File:

179 180 181 182
/**
 * Writes a character to a textfile.
 * To a datafile fwritec writes one byte (a Clean Char).
 */
183
fwritec		:: !Char !*File -> *File									:== code { .d 0 3 c f ; jsr writeFC ; .o 0 2 f }
184

185 186 187 188
/**
 * Writes an Integer (its textual representation) to a text file. To a datafile
 * fwritei writes four bytes (a Clean Int).
 */
189
fwritei		:: !Int !*File -> *File										:== code { .d 0 3 i f ; jsr writeFI ; .o 0 2 f }
190

191 192 193 194
/**
 * Writes a Real (its textual representation) to a text file. To a datafile
 * fwriter writes eight bytes (a Clean Real).
 */
195
fwriter		:: !Real !*File -> *File									:== code { .d 0 4 r f ; jsr writeFR ; .o 0 2 f }
196

197 198 199
/**
 * Writes a String to a text or data file.
 */
200
fwrites		:: !{#Char} !*File -> *File									:== code { .d 1 2 f ; jsr writeFS ; .o 0 2 f }
201

202 203 204 205
/**
 * Writes the characters at positions `arg1`..`arg1+arg2-1` of string `arg3` to
 * a text or data file.
 */
206
fwritesubstring :: !Int !Int !{#Char} !*File -> *File					:== code { .d 1 4 i i f ; jsr writeFString ; .o 0 2 f }
207

208 209 210 211 212 213 214 215 216
/**
 * Overloaded write to file. This allows you to chain write operations, like:
 * `# f = f <<< "X is: " <<< x <<< "; y is: " <<< y <<< "\n"`
 *
 * @var The type that can be written to a file
 * @param The File
 * @param The thing to write
 * @result The new File
 */
217 218
class (<<<) infixl a :: !*File !a -> *File

219 220 221 222
instance <<< Int 		:: !*File !Int -> *File							:== code { push_b 2 ; update_b 2 3 ; update_b 1 2 ; updatepop_b 0 1 ; .d 0 3 i f ; jsr writeFI ; .o 0 2 f }
instance <<< Char		:: !*File !Char -> *File						:== code { push_b 2 ; update_b 2 3 ; update_b 1 2 ; updatepop_b 0 1 ; .d 0 3 c f ; jsr writeFC ; .o 0 2 f }
instance <<< {#Char}	:: !*File !{#Char} -> *File						:== code { .d 1 2 f ; jsr writeFS ; .o 0 2 f }
instance <<< Real		:: !*File !Real -> *File						:== code { push_b 3 ; push_b 3 ; update_b 3 5 ; update_b 2 4 ; update_b 1 3 ; updatepop_b 0 2 ; .d 0 4 r f ; jsr writeFR ; .o 0 2 f }
223 224 225

//	Testing:

226 227 228
/**
 * @result Whether end-of-file has been reached
 */
229
fend		:: !*File -> (!Bool,!*File)									:== code { .d 0 2 f ; jsr endF ; .o 0 3 b f }
230

231 232 233
/**
 * @result Whether an error has occurred during previous file I/O operations
 */
234
ferror		:: !*File -> (!Bool,!*File)									:== code { .d 0 2 f ; jsr errorF ; .o 0 3 b f }
235

236 237 238 239
/**
 * @result The current position of the file pointer as an Integer. This
 *   position can be used later on for the fseek function.
 */
240
fposition	:: !*File -> (!Int,!*File)									:== code { .d 0 2 f ; jsr positionF ; .o 0 3 i f }
241

242 243 244 245 246 247 248
/**
 * Move to a different position in the file
 *
 * @param The offset
 * @param A seek mode ({{`FSeekSet`}}, {{`FSeekCur`}} or {{`FSeekEnd`}})
 * @result True iff the seek was successful
 */
249
fseek		:: !*File !Int !Int -> (!Bool,!*File)						:== code { .d 0 4 f i i ; jsr seekF ; .o 0 3 b f }
250 251 252

//	Predefined files.

253 254 255
/**
 * Open the 'Errors' file for writing only. May be opened more than once.
 */
256
stderr		:: *File													:== code { .d 0 0 ; jsr	stderrF ; .o 0 2 f }
257 258 259

//	Opening and reading Shared Files:

260 261 262 263 264 265
sfreadc		:: !File -> (!Bool,!Char,!File)								:== code { .d 0 2 f ; jsr readSFC ; .o 0 4 b c f }
sfreadi		:: !File -> (!Bool,!Int,!File)								:== code { .d 0 2 f ; jsr readSFI ; .o 0 4 b i f }
sfreadr		:: !File -> (!Bool,!Real,!File)								:== code { .d 0 2 f ; jsr readSFR ; .o 0 5 b r f }
sfreads		:: !File !Int -> (!*{#Char},!File)							:== code { .d 0 3 f i ; jsr readSFS ; .o 1 2 f }
sfreadline	:: !File -> (!*{#Char},!File)								:== code { .d 0 2 f ; jsr readLineSF ; .o 1 2 f }
sfseek		:: !File !Int !Int -> (!Bool,!File)							:== code { .d 0 4 f i i ; jsr seekSF ; .o 0 3 b f }
266

267 268
sfend		:: !File -> Bool											:== code { .d 0 2 f ; jsr endSF ; .o 0 1 b }
sfposition	:: !File -> Int												:== code { .d 0 2 f ; jsr positionSF ; .o 0 1 i }
269 270 271

//	Convert a *File into:

272 273 274
/**
 * Change a file so that from now it can only be used with `sf...` operations.
 */
275
fshare		:: !*File -> File											:== code { .d 0 2 f ; jsr shareF ; .o 0 2 f }
John van Groningen's avatar
John van Groningen committed
276

277
fflush :: !*File -> (!Bool,!*File)										:== code { .d 0 2 f ; jsr flushF ; .o 0 3 bf }