Browse code

Deprecate file-read-chunks by incorporating it inside asma.

Andrew Alderwick authored on 01/12/2021 22:01:26
Showing 2 changed files
... ...
@@ -230,7 +230,59 @@
230 230
 	POP2 POP2 POP2 POP2 POP2
231 231
 	JMP2r
232 232
 
233
-~projects/library/file-read-chunks.tal
233
+@file-read-chunks ( func* udata* buf* size* filename* -- func* udata'* buf* size* filename* )
234
+
235
+	#0000 DUP2                 ( F* U* B* SZ* FN* OL* OH* / )
236
+	&resume
237
+	ROT2 STH2                  ( F* U* B* SZ* OL* OH*     / FN* )
238
+	ROT2                       ( F* U* B* OL* OH* SZ*     / FN* )
239
+
240
+	&loop
241
+	STH2kr .File/name DEO2     ( F* U* B* OL* OH* SZ*     / FN* )
242
+	STH2k ,ffwd/length STR2    ( F* U* B* OL* OH*         / FN* SZ* )
243
+	STH2                       ( F* U* B* OL*             / FN* SZ* OH* )
244
+	STH2k ,ffwd/offset STR2    ( F* U* B*                 / FN* SZ* OH* OL* )
245
+	DUP2 ,ffwd/addr STR2
246
+	,ffwd JSR
247
+	SWP2                       ( F* B* U*                 / FN* SZ* OH* OL* )
248
+	ROT2k NIP2                 ( F* B* U* B* F*           / FN* SZ* OH* OL* )
249
+	OVR2 .File/read DEO2       ( F* B* U* B* F*           / FN* SZ* OH* OL* )
250
+	.File/success DEI2 SWP2    ( F* B* U* B* length* F*   / FN* SZ* OH* OL* )
251
+	JSR2                       ( F* B* U'* done-up-to*    / FN* SZ* OH* OL* )
252
+	ROT2 SWP2                  ( F* U'* B* done-up-to*    / FN* SZ* OH* OL* )
253
+	SUB2k NIP2                 ( F* U'* B* -done-length*  / FN* SZ* OH* OL* )
254
+	ORAk ,&not-end JCN         ( F* U'* B* -done-length*  / FN* SZ* OH* OL* )
255
+
256
+	POP2 POP2r POP2r           ( F* U'* B*                / FN* SZ* )
257
+	STH2r STH2r                ( F* U'* B* SZ* FN*        / )
258
+	JMP2r
259
+
260
+	&not-end
261
+	STH2r SWP2                 ( F* U'* B* OL* -done-length* / FN* SZ* OH* )
262
+	LTH2k JMP INC2r            ( F* U'* B* OL* -done-length* / FN* SZ* OH'* )
263
+	SUB2                       ( F* U'* B* OL'*              / FN* SZ* OH'* )
264
+	STH2r STH2r                ( F* U'* B* OL'* OH'* SZ*     / FN* )
265
+	,&loop JMP
266
+
267
+@ffwd
268
+	LIT2 &length $2
269
+	LIT2 &offset $2
270
+
271
+	&coarse ( length* offset* )
272
+	GTH2k ,&fine JCN
273
+	OVR2 .File/length DEO2
274
+	,&addr LDR2 .File/read DEO2
275
+	OVR2 SUB2
276
+	,&coarse JMP
277
+
278
+	&fine ( length* offset* )
279
+	.File/length DEO2 ( length* )
280
+	,&addr LDR2 .File/read DEO2
281
+	.File/length DEO2 ( )
282
+	JMP2r
283
+
284
+	&addr $2
285
+
234 286
 
235 287
 (
236 288
 	Assemble a chunk of source code, which begins with whitespace or the start
237 289
deleted file mode 100644
... ...
@@ -1,209 +0,0 @@
1
-(
2
-
3
-# Summary
4
-
5
-*** CAUTION: this library is deprecated! ***
6
-
7
-Chunked file reads are now possible in the File device directly: just use
8
-File/read or File/write multiple times. This library exists for compatibility to
9
-keep asma going until it gets a more substantial rewrite.
10
-
11
-***
12
-
13
-Reads a file in chunks - perfect for when you have a small buffer or when you
14
-don't know the file size. Copes with files up to 4,294,967,295 bytes long.
15
-
16
-# Code
17
-
18
-)
19
-@file-read-chunks ( func* udata* buf* size* filename* -- func* udata'* buf* size* filename* )
20
-
21
-	#0000 DUP2                 ( F* U* B* SZ* FN* OL* OH* / )
22
-	&resume
23
-	ROT2 STH2                  ( F* U* B* SZ* OL* OH*     / FN* )
24
-	ROT2                       ( F* U* B* OL* OH* SZ*     / FN* )
25
-
26
-	&loop
27
-	STH2kr .File/name DEO2     ( F* U* B* OL* OH* SZ*     / FN* )
28
-	STH2k ,ffwd/length STR2    ( F* U* B* OL* OH*         / FN* SZ* )
29
-	STH2                       ( F* U* B* OL*             / FN* SZ* OH* )
30
-	STH2k ,ffwd/offset STR2    ( F* U* B*                 / FN* SZ* OH* OL* )
31
-	DUP2 ,ffwd/addr STR2
32
-	,ffwd JSR
33
-	SWP2                       ( F* B* U*                 / FN* SZ* OH* OL* )
34
-	ROT2k NIP2                 ( F* B* U* B* F*           / FN* SZ* OH* OL* )
35
-	OVR2 .File/read DEO2       ( F* B* U* B* F*           / FN* SZ* OH* OL* )
36
-	.File/success DEI2 SWP2    ( F* B* U* B* length* F*   / FN* SZ* OH* OL* )
37
-	JSR2                       ( F* B* U'* done-up-to*    / FN* SZ* OH* OL* )
38
-	ROT2 SWP2                  ( F* U'* B* done-up-to*    / FN* SZ* OH* OL* )
39
-	SUB2k NIP2                 ( F* U'* B* -done-length*  / FN* SZ* OH* OL* )
40
-	ORAk ,&not-end JCN         ( F* U'* B* -done-length*  / FN* SZ* OH* OL* )
41
-
42
-	POP2 POP2r POP2r           ( F* U'* B*                / FN* SZ* )
43
-	STH2r STH2r                ( F* U'* B* SZ* FN*        / )
44
-	JMP2r
45
-
46
-	&not-end
47
-	STH2r SWP2                 ( F* U'* B* OL* -done-length* / FN* SZ* OH* )
48
-	LTH2k JMP INC2r            ( F* U'* B* OL* -done-length* / FN* SZ* OH'* )
49
-	SUB2                       ( F* U'* B* OL'*              / FN* SZ* OH'* )
50
-	STH2r STH2r                ( F* U'* B* OL'* OH'* SZ*     / FN* )
51
-	,&loop JMP
52
-
53
-@ffwd
54
-	LIT2 &length $2
55
-	LIT2 &offset $2
56
-
57
-	&coarse ( length* offset* )
58
-	GTH2k ,&fine JCN
59
-	OVR2 .File/length DEO2
60
-	,&addr LDR2 .File/read DEO2
61
-	OVR2 SUB2
62
-	,&coarse JMP
63
-
64
-	&fine ( length* offset* )
65
-	.File/length DEO2 ( length* )
66
-	,&addr LDR2 .File/read DEO2
67
-	.File/length DEO2 ( )
68
-	JMP2r
69
-
70
-	&addr $2
71
-
72
-(
73
-
74
-# Arguments
75
-
76
-* func*     - address of callback routine
77
-* udata*    - userdata to pass to callback routine
78
-* buf*      - address of first byte of buffer of file's contents
79
-* size*     - size in bytes of buffer
80
-* filename* - address of filename string (zero-terminated)
81
-
82
-All of the arguments are shorts (suffixed by asterisks *).
83
-
84
-# Callback routine
85
-
86
-If you make use of userdata, the signature of the callback routine is:
87
-)
88
-	( udata* buf* length* -- udata'* done-up-to* )
89
-(
90
-
91
-* udata* and buf* are as above.
92
-* length* is the length of the chunk being worked on, which could be less than
93
-  size* when near the end of the file, and func* is called with zero length* to
94
-  signify end of file.
95
-* udata'* is the (potentially) modified userdata, to be passed on to the next
96
-  callback routine call and returned by file-read-chunks after the last chunk.
97
-* done-up-to* is the pointer to the first unprocessed byte in the buffer, or
98
-  buf* + length* if the whole chunk was processed.
99
-
100
-If you don't make use of any userdata, feel free to pretend the signature is:
101
-)
102
-	( buf* length* -- done-up-to* )
103
-(
104
-
105
-# Userdata
106
-
107
-The udata* parameter is not processed by file-read-chunks, except to keep the
108
-one returned from one callback to the next. The meaning of its contents is up
109
-to you - it could simply be a short integer or a pointer to a region of memory.
110
-
111
-# Operation
112
-
113
-file-read-chunks reads a file into the buffer you provide and calls func* with
114
-JSR2 with each chunk of data, finishing with an empty chunk at end of file.
115
-
116
-file-read-chunks loops until done-up-to* equals buf*, equivalent to when no
117
-data is processed by func*. This could be because processing cannot continue
118
-without a larger buffer, an error is detected in the data and further
119
-processing is pointless, or because the end-of-file empty chunk leaves the
120
-callback routine with no other choice.
121
-
122
-# Return values
123
-
124
-Since file-read-chunks's input parameters remain available throughout its
125
-operation, they are not automatically discarded in case they are useful to the
126
-caller.
127
-
128
-# Discussion about done-up-to*
129
-
130
-file-read-chunks is extra flexible because it doesn't just give you one chance
131
-to process each part of the file. Consider a func* routine that splits the
132
-chunk's contents into words separated by whitespace. If the buffer ends with a
133
-letter, you can't assume that letter is the end of that word - it's more likely
134
-to be the in the middle of a word that continues on. If func* returns the
135
-address of the first letter of the word so far, it will be called again with
136
-that first letter as the first character of the next chunk's buffer. There's no
137
-need to remember the earlier part of the word because you get presented with
138
-the whole lot again to give parsing another try.
139
-
140
-That said, func* must make at least _some_ progress through the chunk: if it
141
-returns the address at the beginning of the buffer, buf*, file-read-chunks will
142
-terminate and return to its caller. With our word example, a buffer of ten
143
-bytes will be unable to make progress with words that are ten or more letters
144
-long. Depending on your application, either make the buffer big enough so that
145
-progress should always be possible, or find a way to discern this error
146
-condition from everything working fine.
147
-
148
-# Discussion about recursion
149
-
150
-Since all of file-read-chunks's data is on the working and return stacks, it
151
-can be called recursively by code running in the callback routine. For example,
152
-a code assembler can process the phrase "include library.tal" by calling
153
-file-read-chunks again with library.tal as the filename. There are a couple of
154
-caveats:
155
-
156
-* the filename string must not reside inside file-read-chunk's working buffer,
157
-  otherwise it gets overwritten by the file's contents and subsequent chunks
158
-  will fail to be read properly; and
159
-
160
-* if the buffer is shared with the parent file-read-chunk, the callback routine
161
-  should stop further processing and return with done-up-to* straight away,
162
-  since the buffer contents have already been replaced by the child
163
-  file-read-chunk.
164
-
165
-# Resuming / starting operation from an arbitrary offset
166
-
167
-You can call file-read-chunks/resume instead of the main routine if you'd like
168
-to provide your own offset shorts rather than beginning at the start of the
169
-file. The effective signature for file-read-chunks/resume is:
170
-)
171
-	( func* udata* buf* size* filename* offset-ls* offset-hs* -- func* udata'* buf* size* filename* )
172
-(
173
-
174
-# Example callback routines
175
-
176
-This minimal routine is a no-op that "processes" the entire buffer each time
177
-and returns a valid done-up-to*:
178
-
179
-	@quick-but-useless
180
-		ADD2 JMP2r
181
-
182
-This extremely inefficient callback routine simply prints a single character
183
-from the buffer and asks for the next one. It operates with a buffer that is
184
-just one byte long, but for extra inefficiency you can assign a much larger
185
-buffer and it will ignore everything after the first byte each time. If the
186
-buffer is zero length it returns done-up-to* == buf* so that file-read-chunks
187
-returns properly.
188
-
189
-	@one-at-a-time
190
-		#0000 NEQ2 JMP JMP2r
191
-		LDAk .Console/write DEO
192
-		INC2 JMP2r
193
-
194
-This more efficient example writes the entire chunk to the console before
195
-requesting the next one by returning. How short can you make a routine that
196
-does the same?
197
-
198
-	@chunk-at-a-time
199
-		&loop
200
-		ORAk ,&not-eof JCN
201
-		POP2 JMP2r
202
-
203
-		&not-eof
204
-		STH2
205
-		LDAk .Console/write DEO
206
-		INC2 STH2r #0001 SUB2
207
-		,&loop JMP
208
-
209
-)