We are planning to upgrade GitLab to the latest version this Friday morning. Expect some downtime!

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

Camil Staps's avatar
Camil Staps committed
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

Camil Staps's avatar
Camil Staps committed
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
//* File mode: read text
FReadText	:== 0

//* File mode: write text
FWriteText	:== 1

//* File mode: append text
FAppendText	:== 2

//* File mode: read data
FReadData	:== 3

//* File mode: write data
FWriteData	:== 4

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

//	Seek modes synonyms

Camil Staps's avatar
Camil Staps committed
34 35
//* Seek mode: the new position is the seek offset
FSeekSet	:== 0
36

Camil Staps's avatar
Camil Staps committed
37 38
//* Seek mode: the new position is the current position plus the seek offset
FSeekCur	:== 1
39

Camil Staps's avatar
Camil Staps committed
40 41
//* Seek mode: the new position is the size of the file plus the seek offset
FSeekEnd	:== 2
42

Camil Staps's avatar
Camil Staps committed
43 44 45 46 47 48 49 50 51 52 53
/**
 * 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
Camil Staps's avatar
Camil Staps committed
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)
Camil Staps's avatar
Camil Staps committed
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)
Camil Staps's avatar
Camil Staps committed
74 75

	//* Open the 'Console' for reading and writing.
76
	stdio  :: !*f -> (!*File,!*f)
Camil Staps's avatar
Camil Staps committed
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91

	/**
	 * 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`}}
	 */
92 93 94 95 96
	sfopen :: !{#Char} !Int !*f -> (!Bool,!File,!*f)

instance FileSystem Files
instance FileSystem World

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

instance FileEnv World

Camil Staps's avatar
Camil Staps committed
108 109 110 111 112 113 114
/**
 * 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
 */
115
freopen		:: !*File !Int -> (!Bool,!*File)							:== code { .d 0 3 f i ; jsr reopenF ; .o 0 3 b f }
116 117 118

//	Reading from a File:

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

Camil Staps's avatar
Camil Staps committed
126 127 128 129 130 131 132
/**
 * 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
 */
133
freadi		:: !*File -> (!Bool,!Int,!*File)							:== code { .d 0 2 f ; jsr readFI ; .o 0 4 b i f }
134

Camil Staps's avatar
Camil Staps committed
135 136 137 138 139 140 141
/**
 * 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
 */
142
freadr		:: !*File -> (!Bool,!Real,!*File)							:== code { .d 0 2 f ; jsr readFR ; .o 0 5 b r f }
143

Camil Staps's avatar
Camil Staps committed
144 145 146 147 148 149 150 151 152
/**
 * 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
 */
153
freads		:: ! *File !Int -> (!*{#Char},!*File)						:== code { .d 0 3 f i ; jsr readFS ; .o 1 2 f }
154

Camil Staps's avatar
Camil Staps committed
155 156 157 158 159 160 161 162 163 164 165 166
/**
 * 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
*/
167
freadsubstring :: !Int !Int !*{#Char} !*File -> (!Int,!*{#Char},!*File)	:== code { .d 1 4 i i f ; jsr readFString ; .o 1 3 i f }
168

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

//	Writing to a File:

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

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

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

Camil Staps's avatar
Camil Staps committed
195
//* Writes a String to a text or data file.
196
fwrites		:: !{#Char} !*File -> *File									:== code { .d 1 2 f ; jsr writeFS ; .o 0 2 f }
197

Camil Staps's avatar
Camil Staps committed
198 199 200 201
/**
 * Writes the characters at positions `arg1`..`arg1+arg2-1` of string `arg3` to
 * a text or data file.
 */
202
fwritesubstring :: !Int !Int !{#Char} !*File -> *File					:== code { .d 1 4 i i f ; jsr writeFString ; .o 0 2 f }
203

Camil Staps's avatar
Camil Staps committed
204 205 206 207 208 209 210 211 212
/**
 * 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
 */
213 214
class (<<<) infixl a :: !*File !a -> *File

215 216 217 218
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 }
219 220 221

//	Testing:

Camil Staps's avatar
Camil Staps committed
222 223 224
/**
 * @result Whether end-of-file has been reached
 */
225
fend		:: !*File -> (!Bool,!*File)									:== code { .d 0 2 f ; jsr endF ; .o 0 3 b f }
226

Camil Staps's avatar
Camil Staps committed
227 228 229
/**
 * @result Whether an error has occurred during previous file I/O operations
 */
230
ferror		:: !*File -> (!Bool,!*File)									:== code { .d 0 2 f ; jsr errorF ; .o 0 3 b f }
231

Camil Staps's avatar
Camil Staps committed
232 233 234 235
/**
 * @result The current position of the file pointer as an Integer. This
 *   position can be used later on for the fseek function.
 */
236
fposition	:: !*File -> (!Int,!*File)									:== code { .d 0 2 f ; jsr positionF ; .o 0 3 i f }
237

Camil Staps's avatar
Camil Staps committed
238 239 240 241 242 243 244
/**
 * 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
 */
245
fseek		:: !*File !Int !Int -> (!Bool,!*File)						:== code { .d 0 4 f i i ; jsr seekF ; .o 0 3 b f }
246 247 248

//	Predefined files.

Camil Staps's avatar
Camil Staps committed
249
//* Open the 'Errors' file for writing only. May be opened more than once.
250
stderr		:: *File													:== code { .d 0 0 ; jsr	stderrF ; .o 0 2 f }
251 252 253

//	Opening and reading Shared Files:

254 255 256 257 258 259
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 }
260

261 262
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 }
263 264 265 266 267 268
/*	The functions sfend and sfposition work like fend and fposition, but don't return a
	new file on which other operations can continue. They can be used for files opened
	with sfopen or after fshare, and in guards for files opened with fopen or freopen. */

//	Convert a *File into:

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

Camil Staps's avatar
Camil Staps committed
272
//* Flush all I/O operations on a file.
273
fflush :: !*File -> (!Bool,!*File)										:== code { .d 0 2 f ; jsr flushF ; .o 0 3 bf }