MKDIR problem

Discussions about the BBC BASIC language, with particular reference to BB4W and BBCSDL
MrHiggins
Posts: 19
Joined: Wed 28 Jul 2021, 13:29

MKDIR problem

Post by MrHiggins »

Hi,

I have been experimenting and made this simple program that will create a Testing folder under @tmp$. It then goes on to create 10 dir{I%} folders under the testing folder. The PROC that handles directory creation has an ON ERROR LOCAL catching for file exists errors and then ignoring them. I run this program on BB4W the first time it creates the folders and the second time it skips creation of the folders as they are already created, which is expected. If I then delete those created folders and then run the program in BB4SDL, on the first run it can create the folders but the second time it seems to hang on

Code: Select all

OSCLI "MKDIR " + path$
Can anyone point out what is wrong with this code?

Code: Select all

      base$ = @tmp$ + "testing\"

      PROC_createdir(base$)

      FOR I% = 0 TO 10
        PROC_createdir(base$ + "dir" + STR$(I%))
      NEXT I%

      END

      DEF PROC_createdir(path$)
      ON ERROR LOCAL : IF ERR = 196 THEN PRINT "existing " + FN_quote(path$) : ENDPROC
      OSCLI "MKDIR " + path$
      PRINT "Created " + FN_quote(path$)
      ENDPROC


      DEF FN_quote(str$) =CHR$(&22) + str$ + CHR$(&22)
Hated Moron

Re: MKDIR problem

Post by Hated Moron »

MrHiggins wrote: Thu 11 Aug 2022, 15:57 Can anyone point out what is wrong with this code?
There are a couple of things wrong with it.

Code: Select all

      base$ = @tmp$ + "testing\"
The backslash character should be a forward slash (/). Although this won't matter when running in Windows, it will fail on every other platform.

Code: Select all

      ON ERROR LOCAL : IF ERR = 196 THEN PRINT "existing " + FN_quote(path$) : ENDPROC
      OSCLI "MKDIR " + path$
What happens if ERR is not 196? The answer is that it will 'fall through' to the next line of code, and attempt the *MKDIR again (and again and again...). And that's precisely what is happening in your case, because in BBCSDL a failed *MKDIR results in the error 'Bad command' (254) not 'File exists' (196).

The reason for this difference is that in BBCSDL the underlying API call does not report the reason for the failure, it may be that the directory already exists but it could equally be that the 'parent' directory doesn't exist, or that you do not have the necessary privileges to create a sub-directory there. So rather than report a potentially misleading 'File exists' error it instead reports the catch-all 'Bad command'.

If your code had been written 'defensively' you would have been alerted to what happened. For example you could have written:

Code: Select all

      ON ERROR LOCAL IF ERR = 196 THEN PRINT "existing " + FN_quote(path$) : ENDPROC ELSE RESTORE LOCAL : ERROR ERR, REPORT$
MrHiggins
Posts: 19
Joined: Wed 28 Jul 2021, 13:29

Re: MKDIR problem

Post by MrHiggins »

Fantastic, thanks Richard!

Would it maybe worth adding a note for *MKDIR about the SDL behaviour giving "BAD COMMAND"?
Hated Moron

Re: MKDIR problem

Post by Hated Moron »

MrHiggins wrote: Thu 11 Aug 2022, 17:31 Would it maybe worth adding a note for *MKDIR about the SDL behaviour giving "BAD COMMAND"?
Done. Generally, users should be aware that behaviour in the event of an error may differ in detail between platforms.

One cannot even be certain that an error will occur at all. For example in iOS (uniquely of the platforms currently supported) this code, which should raise a 'Number too big' error, doesn't:

Code: Select all

      v%% = 2^63
MrHiggins
Posts: 19
Joined: Wed 28 Jul 2021, 13:29

Re: MKDIR problem

Post by MrHiggins »

Providing this info in case other people find the information useful.

The platform agnostic solution to this I have gone for is before executing the MKDIR I will look to see if there is a directory there already and if there is skip it.

Code: Select all

      DEF PROC_createdir(path$)
      LOCAL F%
      F% = OPENIN(path$+"/NUL")
      IF F% THEN
        CLOSE #F%
        PRINT "Exists " + FN_quote(path$)
      ELSE
        OSCLI "MKDIR " + FN_quote(path$)
        PRINT "Created " + FN_quote(path$)
      ENDIF
      ENDPROC
Hated Moron

Re: MKDIR problem

Post by Hated Moron »

MrHiggins wrote: Fri 12 Aug 2022, 09:55 The platform agnostic solution to this I have gone for is before executing the MKDIR I will look to see if there is a directory there already and if there is skip it.
Have you actually tested that on any platform other than Windows? I thought the NUL pseudo-file was a Windows-specific feature and didn't work on any other platform, but I'm happy to be proved wrong.

It's perhaps also worth reminding everybody that this is a case when trying something and seeing if an error occurs is the correct way to do it, because any other approach is prone to failure in a multi-tasking operating system. Although the chances are probably small, it's possible for this sequence of events to occur:
  1. The BBC BASIC program tests to see if the directory exists, it doesn't.
  2. Another program creates the directory (either through running on another core or because of a task-switch).
  3. The BBC BASIC program tries to create the directory, and fails with an error.
The only safe way is to test whether the directory exists and if not create it as an atomic operation (one which cannot be interrupted by another task), which can only be achieved by trapping the error and attempting it anyway.

I know it's unreasonable to expect BBC BASIC programmers to test their code on every supported platform, but I would urge checking it on at least two dissimilar platforms (e.g. Windows and 64-bit Linux or Windows and MacOS). Even if you don't have a suitable alternative platform, you can usually test your code by running it in a browser, which will check most things except 64-bit compatibility.

For the record, these are the platforms on which I test every release of BBCSDL: Windows 10 32-bit (desktop), Windows 10 64-bit (desktop), Windows 10 64-bit (laptop with touchscreen), MacOS (x86 CPU), MacOS (M1 CPU), Ubuntu 18.04 32-bit, Ubuntu 18.04 64-bit, Raspberry Pi 4 32-bit, Raspberry Pi 4 64-bit, Android phone (x86), Android phone (ARM), Android tablet (ARM), iPod Touch, iPhone 5, iPad mini and in Chrome, Edge & Firefox!

When I am no longer able to do that (sadly probably quite soon) anybody contemplating taking over the role is going to need access to at least as many systems for testing. :shock:
MrHiggins
Posts: 19
Joined: Wed 28 Jul 2021, 13:29

Re: MKDIR problem

Post by MrHiggins »

Have you actually tested that on any platform other than Windows? I thought the NUL pseudo-file was a Windows-specific feature and didn't work on any other platform
It seems to be working the same in BB4W and BB4SDL. Here is my full program listing so you can try it also.

Code: Select all

      base$ = @tmp$ + "testing/"

      PROC_createdir(base$)

      FOR I% = 0 TO 10
        PROC_createdir(base$ + "dir" + STR$(I%))
      NEXT I%

      END

      DEF PROC_createdir(path$)
      LOCAL F%
      F% = OPENIN(path$+"/NUL")
      IF F% THEN
        CLOSE #F%
        PRINT "Exists " + FN_quote(path$)
      ELSE
        OSCLI "MKDIR " + FN_quote(path$)
        PRINT "Created " + FN_quote(path$)
      ENDIF
      ENDPROC


      DEF FN_quote(str$) = CHR$(&22) + str$ + CHR$(&22)
For deleting directories with BB4SDL, what would be the best way of doing it be? DELETE looks like it only works with files? I could use the DOS command RD but then it is not platform agnostic.

EDIT
I just found it on the * commands and it is *RMDIR (*RD) :roll:
Hated Moron

Re: MKDIR problem

Post by Hated Moron »

MrHiggins wrote: Fri 12 Aug 2022, 10:58 Here is my full program listing so you can try it also.
Nope it doesn't work (you could have tried it yourself, just three clicks needed!). This confirms what I thought, the NUL pseudo-file is Windows-specific:

mkdir.png
You do not have the required permissions to view the files attached to this post.
MrHiggins
Posts: 19
Joined: Wed 28 Jul 2021, 13:29

Re: MKDIR problem

Post by MrHiggins »

Nope it doesn't work (you could have tried it yourself, just three clicks needed!)
I did run it. It works on my windows desktop SDL but I guess it might not for other platforms then, fair enough. When you said windows my brain translated that as BB4W.
Hated Moron

Re: MKDIR problem

Post by Hated Moron »

MrHiggins wrote: Fri 12 Aug 2022, 12:10 When you said windows my brain translated that as BB4W.
No, I was talking about the platform, i.e. the underlying filing system. Basically there's Windows and there's everything else (because they all use something based on Unix), although there are complications such as MacOS supporting case-insensitive filenames like Windows does.

It's so easy just to click on the cogs button (Compile dialogue) then on 'Deploy as a web application' then on 'Test' - the three clicks I was referring to - as a quick check of cross-platform compatibility. As I mentioned, the main thing that doesn't test is 64-bit-ness.