AppBasic - Flushing buffer
Richard Ashbery (495) 163 posts |
I have an AppBasic program with a ‘window handler’ that opens a textfile, reads contents (1kb) into a memory buffer and then displays it in the TextArea gadget. It works but if the textfile is made shorter the next time program is run it leaves the existing contents in place. I’ve used SYS “OS_Byte”, 15, 0 to flush the buffer but it seems to be ignored. What’s the solution for flushing the memory buffer please? |
Fred Graute (114) 645 posts |
How are you transferring the data from the buffer to the TextArea gadget? Both the TextArea_SetText and TextArea_ReplaceText functions can be used. It’s also important that the text in the buffer is zero terminated. Calling SYS “OS_Byte”, 15, 0 doesn’t help as that flushes OS buffers which are nothing to do with the TextArea gadget. |
Richard Ashbery (495) 163 posts |
Hi Fred Thank you for rescuing me again. I’m sending the 2 handlers to the forum so you can see what I’m trying to do. REM Initial DEF PROCDealWith_InitialEvent REM Window DEF PROCDealWith_Window(event,object,component) SYS “OS_Byte”, 15, 0 was put in to clear the memory block of any rubbish. I must confess I’m not clear how this SWI works but it obviously doesn’t do the job I intended. You stated “that the text in the buffer must be zero terminated”. Could this be the problem? – please remind me what’s the best way? My simplistic use of adding +0 to bytes% isn’t what you mean. |
Steve Fryatt (216) 2105 posts |
That DIM statement is a bit curious… If you’re intending to set bytes% to the size of the required buffer, then to point buffer% to that block of memory, you’ll want something that looks like this. I’m not sure what the *10 was for; if the file is really 1K, then you need 1024 bytes + 1 byte for the terminator (of which see below).
Remember that in BASIC, DIM 1024 allocates you 1025 bytes because DIM always allocates one more byte than you ask for. This is often helpful, because if you then load 1024 bytes of data into the block, you’ve got a spare byte for terminating it. There seem to be some issues with the file loading, too. You need to check the file length and only load what there’s space for into the buffer; normally you’d do this by reading the file length with OS_Args (or EXT#), but as you’re using OS_GBPB 4 you can just tell that to only read the buffer length – 1 bytes. Because of the quirk of DIM, that length less 1 is actually the value of bytes% in this case. Note the test for handle% being non-zero. You should never try to use a zero file handle, as it means the file didn’t open for some reason. Worse, calling OS_Find 0 with a zero handle is a really bad thing to do, because it closes all the open files on the system – with bad consequences, given that the system will be using some of them.
Note that all this code is untested (I’ve just typed it direct into the forum form off the top of my head).
That’s because it has nothing to do with what you’re trying to do. OS_Byte 15 clears operating system IO buffers – you’ve just flushed the keyboard, serial port, printer, sound, speech and mouse buffers with that call. If you want to clear memory blocks allocated in your favourite programming language, you have to find a way to do it yourself. Generally, for zero terminated blocks, it just means placing a zero byte in the first byte of the block.
I’m not sure what you mean here. “Zero terminating” a buffer means placing a zero byte after the last byte of real data. How you do that will depend on how you know where the last byte of real data is; I’ve done it using the byte indirection operator (?) above, after working out where the zero byte needs to go. |
Fred Graute (114) 645 posts |
I see that Steve’s done a nicely annotated version already but here’s my take on it (completely untested):
|
Richard Ashbery (495) 163 posts |
Although not clear in my original posting this was added to handle much larger files (1Kb only for testing). REM help files excellent. Up to now buffer memory has been a mystery but it’s getting clearer – thanks :-)
It hadn’t occurred to me that SYS “OS_Find”, 0, handle% would close all files if specified file was unable to be opened. I’ve been lucky that it hasn’t caused problems. If handle% is zero wouldn’t it force an error? Your code works perfectly as does Fred’s example which actually simplifies things because it caters for an unlimited textfile size. Detailed and accurate information like this is quite hard to come by in RISC OS. Many thanks Steve and Fred for your extremely helpful replies. |
Rick Murray (539) 13840 posts |
Indeed. Some USB devices open file handles, and object if they’re suddenly closed.
No, zero is a magic value that means “all”. It’s the same in BASIC: |
Fred Graute (114) 645 posts |
It probably wouldn’t have come to that as the first call to OS_File would have raised an error if it couldn’t open the file, but in programming it’s always good to be defensive and to not make any assumptions.
No, SYS “OS_Find”, 0, 0 closing all open files is defined behaviour, hence Steve making sure that handle% isn’t 0.
It just barfs at anything that’s too big. To properly handle any file size you’d have to read in the file a piecemeal at a time and append it to the TextArea using TextArea_InsertText.
The information Steve and I gave is in the (PDF) PRMs as well as the StrongHelp manuals. It’s however not always easy to know where to look, and that a lot of the information is quite terse. |
Steve Fryatt (216) 2105 posts |
OS_File might, but Richard’s original and my reworking used OS_Find throughout. OS_Find (and OPENIN/UP in BASIC) don’t throw errors if they can’t find a file: they return a handle of zero. |
Fred Graute (114) 645 posts |
It will return an error in this case as bit 3 of R0 is set. Don’t you just love those magical bit values :-) |
Steve Fryatt (216) 2105 posts |
True; I’d missed that bit. The general point about being sure you’re not passing zero to CLOSE# / OS_Find 0 still stands, though!
:-) |
Steve Drain (222) 1620 posts |
Sorry to be a pedant, but DIM attempts to allocate
Disabling this was one of the first things I implemented in Basalt. It still leaves |
Steve Drain (222) 1620 posts |
Might I add a small caveat about TextArea text? The Toolbox specifies that supplied strings can be terminated by any control character (0-31), although it returns strings terminated by NUL (0). TextAreas are different, because there is a need to include LF (10) within the text to start new lines, so the NUL termination here is a special requirement. It is obscure, but this has caught people out in the past, who assumed that TB strings were always NUL (0) terminated. |
Steve Fryatt (216) 2105 posts |
In the context of explaining how to use DIM to a new developer, that’s irrelevant and only serves to confuse what’s already a lot of detail. It’s also undocumented, as the BBC BASIC Reference Manual states “the expression gives the number of bytes of storage required minus one”. If you need a round number of words, do the maths explicitly and then pass the rounded up value to DIM. Relying on implementation details is what stops code working on future versions of the OS. |
Steve Drain (222) 1620 posts |
I was not actually advocating using this feature, but it is documented after all, so worth getting right:
;-) |
Steffen Huber (91) 1953 posts |
The start address is word-aligned, but who says that BASIC will not use the bytes at the end for other things? So a DIM bytes% 8 allocates 9 bytes, starting at a word-aligned address, but nowhere is it stated that it is legal to use the bytes 10,11 and 12. |
Steve Drain (222) 1620 posts |
Who said it was? You are quite correct that you are allocated what you ask for. It is nevertheless true that BASIC does reserve memory in word-aligned blocks, which is all that I said. I think it is reasonable to infer that from this, also in the BASIC manual:
This knowledge can be useful, for instance when debugging someone’s code that has done For example, a routine that sometimes mistakenly assigns to Now our ‘new developer’ will be thoroughly confused. ;-) |
Steffen Huber (91) 1953 posts |
Hi Steve, I interpreted your comment
that way. I found this misunderstandable. Because after you “get” something, you “own” it. |
Steve Drain (222) 1620 posts |
OK – bad wording. I guess in my mind was an idiom: “you will get more than you asked [bargained] for”. That is, it could cause problems. On the other hand, I could just have been a clever-dick. ;-) I still think that being aware of the way BASIC reserves memory is useful. |