It is the 2086th of March 2020 (aka the 15th of November 2025)
You are 18.97.14.85,
pleased to meet you!
mailto:blog-at-heyrick-dot-eu
Scanning a directory
Rob recently asked:
Why read through counting i_s, then again counting p_s? Read through once, incrementing the relevant counter depending on the filename you find. Ditto the storing of the names. You'd only need to run through twice.
The primary reason is that I am using the OS_GBPB wildcards to do the matching for me, and because certain points of the RISC OS API are just dumb.
Here is how GBPB 10 works:
OS_GPBP, 10
Read entries and info from given directory.
Entry: R0 = 10
R1 = Directory name
R2 = Buffer
R3 = Number of objects to read
R4 = Where to start (0 = first time)
R5 = Length of buffer
R6 = Wildcarded name to match (0 = "*")
Exit: R3 = Number of objects read
R4 = Where to continue, or -1 for done
C clear if R3 = 0, else set.
Call as follows:
repeat
{
call OS_GBPB 10
if (r3 != 0)
{
do something with the buffer
}
} until (R4 = -1)
Buffer layout:
+0 Load address OR filetype/top byte of date
+4 Exec address OR lower word of date
+8 Length
+12 Attributes (read/write and locked)
+16 Object type (1=file; 2=dir; 3=image)
+20 Null terminated name
Let's see this in practice.
next% = 0
DIM buffer% 32
REPEAT
SYS "XOS_GBPB",10,"$",buffer%,1,next%,32,0 TO ,,,count%,next%
IF (count% <> 0) THEN
SYS "XOS_GenerateError", buffer%+20 TO name$
PRINT name$
ENDIF
UNTIL next% = -1
This is because the next file is "AcornSSLipv6" which is too large for the 12 byte filename buffer.
Okay, no problems. Just use the X-form of the SWI and trap the error. Well, in that case, this happens:
*ReadDir
!Boot
!cds
!Rejoin
!StartWiFi
!StartWiFi
!StartWiFi
!StartWiFi
!StartWiFi
!StartWiFi
!StartWiFi
!StartWiFi
[and so on forever]
Okay, no problems, we'll just make the buffer larger and... oh... wait... but how do you do that?
In a word, you can't. I have already put it to the OS developers if there is an upper boundary to the size of a filename/path, and they categorically refused to answer. Their logic was that there was enough of a nightmare in "the old days" with people assuming that filenames were 10 characters long (which would have been a dumb thing to do as DOSFS's "FILENAME/EXT" is twelve), so they aren't going to divulge if there's a limit and what it is.
The API offers no way to determine what the length of a filename is, other than to just keep making the name larger and keep trying until it works. Yes, I am well aware that I could just allocate a kilobyte and that would suffice for all but pathological cases, but that's not the point.
In practical terms, the maximum total filename (including path) is 211 characters. This is because the Filer works by passing around various messages like DataOpen, and the Wimp data block is 256 bytes in length. The header takes 44 bytes, which leaves 212, minus one for the terminator.
In other words, this file cannot be double-clicked upon:
Older versions of RISC OS used to crash. Newer versions just do nothing. Either way, it's a zombie file as far as the Desktop world is concerned.
While reporting "Buffer overflow" is logical as the buffer is indeed too small to hold the filename, not only is there no way to determine the size of buffer necessary to hold the largest filename in that directory, there's also no way to skip the file. R4 is not updated, and won't be until the file details are provided, hence the loop.
In Tea, I have made the buffer 52 bytes, which is giving 32 bytes for the filename. That's around 2½ times what is necessary.
As I am specifically looking for "i_*" and "p_*" files, I'm looking for files that Tea will have created itself. You can probably "crash" the program by renaming one to have a long tail, but that's on you, you aren't supposed to be messing around in the cache.
By using GBPB to filter the files, not only do I not have to look at the filenames myself, but I also filter out everything else, so "channel_data_backup_from_25_october_2025" won't make anything blow up as it just won't be seen as it doesn't start with an 'i' or a 'p' followed by an underscore.
Anyway, it's not the nicest method, but it's one that'll have to do for now; though I have noted that the call to read the filenames also returns the file datestamp, so maybe a future optimisation could be to filter out files that are old enough to be deleted? An alternative optimisation is to manage a linked list and simply scan through twice (for i_ and for p_) and add entries to the list for processing?
This all being said, under heavy use it's maybe a hundred files or so which gets processed pretty quickly. We aren't using floppies any more! ☺
With that in mind, there's going to be more important stuff to do.
With reference to the linked document regarding structures, something that didn't leap out at me (maybe I just missed it?) is the ability to give an address to a structure, and from that point on access the structure that will access its elements at the address given.
For an example of this in use, something like this:
DEFTYPE fileinfo
LET load%
LET exec%
LET length%
LET attr$
LET type%
LET name$
ENDTYPE
...
REPEAT
SYS "OS_GBPB", 10, dir$, buf%, 1, next%, 20+256, 6 TO....
IF (count% <> 0) THEN
fileinfo = buf%
PRINT fileinfo{name$}
ENDIF
UNTIL next% = -1
It will also need to be necessary and possible to assign multiple types of different structure the same address - think of Wimp blocks.
I'm not sure how I feel about the runtime numeric format selection switches (for 5-byte BASIC FP, 8-byte legacy FPA, or 8-byte VFP) as well as integers being 32 or 64 bit. What concerns me is how much time is liable to be taken in deciding which code path to take for every single numerical access.
It has been said that it would be nice to be able to do:
DIM magenta%() = 255, 0, 255
GCOL magenta%()
To my mind, the main problem is the GCOL statement, that says "Can't use array reference here".
As for the array assignment, it is possible in two steps (and something else from the past that ABC is yet to support):
Note well the use of 1,1 and not 2,2 because BASIC counts from zero so using 2,2 would actually give you a 3×3 array.
Several enhanced string operations have been proposed, including these.
lower$ = -string$ converts to lowercase
upper$ = +string$ converts to uppercase
swap$ = SWAP string$ swaps case
Please define upper and lower case. It is really easy to convert "oi! you! no!" to upper case by knocking out the sixth bit (EOR 32).
Due to how the character table is laid out, you can even convert "déjà vu" using the same method; but there are certain characters that don't follow the same pattern - such as ŵ and ŷ (W and Y with circumflex) as used in Welsh; or Germany's ß character.
It also won't work for various ligatures such as œ (that has an upper case version) or the fi and fl ligatures that do not.
Conspicuously absent is any mention of any form of Unicode.
I also notice that there's still no plan to have BASIC support automatic conversion from null terminated strings. If you wonder why I am calling XOS_GenerateError passing a string pointer; especially given as it's a completely nonsense call, I'm asking the OS to generate an error, but giving the 'X' flag which means don't generate an error. So effectively this call does nothing. Indeed, the OS itself traps this weirdness and simply returns.
So why did I do it? Well, it's to leverage the fact that there exists code to translate null terminated strings into BASIC strings, and BASIC uses this if you make a SYS call and have a value returned in a string.
So effectively I'm instructing the computer to waste some time calling this pointless OS call simply in order to convert a reference to an actual string, because name$=$(buffer%+20) will give an empty string as a null terminated string isn't a valid BASIC string.
Maybe it needs some syntax like name$=$[buffer%+20] to instruct the system that it should convert from a null terminated string. Wrapping in square brackets instead of normal ones indicates that it's a null terminated string.
ReadCurrentTimeZone failure
One document I had said that the timezone offset was returned in R2. Another made no mention of R2 at all. As it turns out, and I might have realised if I had been slightly more awake, RISC OS is an API still heavily based around assembler, so it would not have just decided to return something new in R2 as that breaks the original API (in which R2 didn't change). In order to get this, one must provide a magic word ("ZONE") in R2.
I discovered this by looking at the source. And a bit of rummaging showed that this was introduced in version 0.47 of the module (28th May 2012). While this may seem ancient, I can't help but think that there are older versions of RISC OS in use, so my name matching will work in the rare cases where ReadCurrentTimeZone doesn't support doing anything with R2.
Misery
I got up to feed kitty at seven (the old six) and it was cold, miserable, and dark.
I'm about to go feed her now whilst the kettle is boiling for my pasta and it's cold, miserable, and rapidly getting dark.
This end of the year sucks. My camera can take such lovely vibrant pictures, but there was just nothing lovely about today's cold bleakness. It's like the day you know the nice weather is over and it's going to be five months of ick.
The end is coming, can I hibernate?
Storm casualty
While walking around I discovered a casualty of the recent storm, Storm Benjamin. It's the tree stump that I hung my hammock upon. I guess there will be no more hammock until I sort out someplace else.
No more hammock-holder.
Pasta
This was... about a week ago. I turned this:
Pasta pieces.
Into this:
Yummy!
And now I'm going to go do it again. So, bye!
Your comments:
Please note that while I check this page every so often, I am not able to control what users write; therefore I disclaim all liability for unpleasant and/or infringing and/or defamatory material. Undesired content will be removed as soon as it is noticed. By leaving a comment, you agree not to post material that is illegal or in bad taste, and you should be aware that the time and your IP address are both recorded, should it be necessary to find out who you are. Oh, and don't bother trying to inline HTML. I'm not that stupid! ☺ As of February 2025, commenting is no longer available to UK residents, following the implementation of the vague and overly broad Online Safety Act. You must tick the box below to verify that you are not a UK resident, and you expressly agree if you are in fact a UK resident that you will indemnify me (Richard Murray), as well as the person maintaining my site (Rob O'Donnell), the hosting providers, and so on. It's a shitty law, complain to your MP. It's not that I don't want to hear from my British friends, it's because your country makes stupid laws.
You can now follow comment additions with the comment RSS feed. This is distinct from the b.log RSS feed, so you can subscribe to one or both as you wish.
Rob, 27th October 2025, 18:56
Ah, gotcha. Not knowing RISC OS APIs I didn't know it could do the filter for you. I was assuming you ran through all files and checked LEFT$ or similar...
jgh, 28th October 2025, 03:38
Richard Russell put a lot of thought, coding, and testing into implementing structures in BBC BASIC in the Windows and SDL versions. I've posted several times on the RISC OS forums that they should go trying to invent a untested whell and just use the existing almost-20-year-old syntax that already exists, with the added - "bonus" is the wrong word, lack of killing multi-platform programs - of code working on multiple platforms without huge piles of IF thisplaform THEN dothis ELSE IF something THE somethingelse ELSE someotherthing ELSE blowup.
eg, when I've added stuff to PDP11 BASIC, Richard's extensions are my starting point. For instance ^variable to find the address of a variable, PROC(address) to indirectly call a procedure.
jgh, 28th October 2025, 03:49
<i>If you wonder why I am calling XOS_GenerateError passing a string pointer;</i>
I use OS_WriteN,address TO s$. It writes zero bytes to the output stream from 'address', increments 'address' by zero, and returns it to the string 's$'. Of course, with Russell extensions you'd use $$address.
jgh, 28th October 2025, 03:57
There's a very sketchy list of extended syntax here: mdfs.net/Software/BBCBasic/RISCOS/BasPlus.htm
I keep meaning to properly update it.
C Ferris, 30th October 2025, 11:18
Rick - Piers on the Rool site has discovered a ARM company Norcroft C++ prog and got it working on multi CPUs.
JAD, 31st October 2025, 21:26
Have you tried the 1st 2 example progs on Fat32fs? It doesn't allow you to call it more than 10 times without enlarging the buffer. From the source code:
/* Problems here: We should return "Buffer too small here" (R3 = 0) but badly written s/w will simply call me again until R4 == -1 so we give the caller a chance to increase the buffer size by using a counter. */
Rick, 1st November 2025, 10:20
No, I didn't try it with Fat33FS. It will fail the moment the filename is too long to fit. I would imagine that your eleventh file has a longer name; and yes, it'll either abort or loop. That's part of the demonstration of why this API is dumb.
Why not return the error? I'm not sure making a broken API more broken is a good solution. 😉
This web page is licenced for your personal, private, non-commercial use only. No automated processing by advertising systems is permitted.
RIPA notice: No consent is given for interception of page transmission.