Page 1 of 1
Make CheckFilename behave differently on different OSs
Posted: Thu May 22, 2025 12:14 am
by Quin
This could maybe be put behind a flag to not break (rare) old code, but IMO the way CheckFilename works is fundamentally flawed.
If I understand how it works correctly, if I pass it a path like "/home/quin" on Linux, it'll return #False because / isn't allowed in filenames on Windows...
This is also written in the docs:
Even if the syntax-check of this function doesn't complain, there are different 'forbidden' filenames on different OS. For example on Windows filenames containing "COM1" till "COM9", "LPT1" till "LPT9" or "aux" are not allowed. For more information see here.
I think it would be better if this function returned different results for all the different OSs, e.g. / shouldn't make it return false on Linux.

Re: Make CheckFilename behave differently on different OSs
Posted: Thu May 22, 2025 1:30 am
by AZJIO
It is necessary to clarify what a "Filename" is. I think "Filename" and "Path" are different things.
Re: Make CheckFilename behave differently on different OSs
Posted: Thu May 22, 2025 1:34 am
by Quin
Filenames often come at the end of paths

Sure, there's GetFilePart(), but if this function is only meant for filenames *without* any parent directories, that needs to be clearly stated IMO.
Re: Make CheckFilename behave differently on different OSs
Posted: Thu May 22, 2025 1:38 am
by BarryG
The manual says CheckFilename() is "the filename to check without a path", so don't include the path.

Re: Make CheckFilename behave differently on different OSs
Posted: Thu May 22, 2025 1:51 am
by Quin
Derp.
That's the problem with reading at 900 words a minute.
Sometimes you miss things.
So, to amend the feature request: on Windows, can it detect those special filenames, such as COM1, COM2 etc?
Re: Make CheckFilename behave differently on different OSs
Posted: Thu May 22, 2025 2:29 am
by BarryG
Those special filenames are reserved in Windows, so they're not available and CheckFilename() will rightfully return 0. Try creating a file in Windows (not from PureBasic) with one of those names and you'll see that the OS rejects it (
https://learn.microsoft.com/en-us/windo ... ing-a-file).
Technically, the CheckFilename() command
could be updated to internally remove the path before checking, like this:
Code: Select all
Debug CheckFilename(GetFilePart(path_and_file$))
So your request isn't so bad if it's done this way.

Re: Make CheckFilename behave differently on different OSs
Posted: Thu May 22, 2025 3:03 am
by AZJIO
BarryG wrote: Thu May 22, 2025 2:29 am
So your request isn't so bad if it's done this way.
Don't forget that when you add 90 protections against stupid user actions, you make the function 90 times slower. Many will build in the necessary protections on their own and only those that are necessary.
Re: Make CheckFilename behave differently on different OSs
Posted: Thu May 22, 2025 3:49 am
by BarryG
Fair call.
Re: Make CheckFilename behave differently on different OSs
Posted: Thu May 22, 2025 3:55 am
by AZJIO
Code: Select all
EnableExplicit
Procedure CheckPath(*c.Character)
Protected i, slash, flag = #True
If *c = 0 Or *c\c = 0
ProcedureReturn #False
EndIf
While *c\c
i + 1
Select i
Case 1
If Not ((*c\c >= 'a' And *c\c <= 'z') Or (*c\c >= 'A' And *c\c <= 'Z'))
flag = #False
Break
Else
*c + SizeOf(Character)
Continue
EndIf
Case 2
If *c\c <> ':'
flag = #False
Break
Else
*c + SizeOf(Character)
Continue
EndIf
Case 3
If *c\c <> '\'
flag = #False
Break
Else
slash = 1
*c + SizeOf(Character)
Continue
EndIf
EndSelect
Select *c\c
Case '\'
If slash
flag = #False
Break
EndIf
slash = 1
Case '<', '>', '?', '|', '*', '"', ':'
flag = #False
Break
Default
slash = 0
EndSelect
*c + SizeOf(Character)
Wend
ProcedureReturn flag
EndProcedure
Define path$
path$ = "C:\PB\PureBasic\PureBasic_x64\Compilers"
Debug CheckPath(@path$)
path$ = "C:\PB\PureBasic\\PureBasic_x64\Compilers"
Debug CheckPath(@path$)
path$ = "C:\PB\PureBasic:PureBasic_x64\Compilers"
Debug CheckPath(@path$)
path$ = "C:\Users\<user>\AppData"
Debug CheckPath(@path$)
path$ = "%temp%"
Debug CheckPath(@path$)
version 2
Code: Select all
EnableExplicit
Procedure CheckPath(*c.Character)
Protected i, slash, flag = #True
If *c = 0 Or *c\c = 0
ProcedureReturn #False
EndIf
While *c\c
i + 1
If i = 1
If Not ((*c\c >= 'a' And *c\c <= 'z') Or (*c\c >= 'A' And *c\c <= 'Z'))
flag = #False
Break
Else
*c + SizeOf(Character)
If *c\c <> ':'
flag = #False
Break
Else
*c + SizeOf(Character)
If *c\c <> '\'
flag = #False
Break
Else
slash = 1
*c + SizeOf(Character)
Continue
EndIf
EndIf
EndIf
EndIf
Select *c\c
Case '\'
If slash
flag = #False
Break
EndIf
slash = 1
Case '<', '>', '?', '|', '*', '"', ':'
flag = #False
Break
Default
slash = 0
EndSelect
*c + SizeOf(Character)
Wend
ProcedureReturn flag
EndProcedure
Define path$
path$ = "C:\PB\PureBasic\PureBasic_x64\Compilers"
Debug CheckPath(@path$)
path$ = "C:\PB\PureBasic\PureBasic_x64\Compilers\"
Debug CheckPath(@path$)
path$ = "C:\"
Debug CheckPath(@path$)
; Error
path$ = "C:"
Debug CheckPath(@path$)
path$ = "C:\\"
Debug CheckPath(@path$)
path$ = "C:\PB\PureBasic\\PureBasic_x64\Compilers"
Debug CheckPath(@path$)
path$ = "C:\PB\PureBasic:PureBasic_x64\Compilers"
Debug CheckPath(@path$)
path$ = "C:\Users\<user>\AppData"
Debug CheckPath(@path$)
path$ = "%temp%"
Debug CheckPath(@path$)
Regular expression
Code: Select all
EnableExplicit
Procedure CheckPath(path$)
Protected id_re, flag = #True
id_re = CreateRegularExpression(#PB_Any, "\A[a-z]:(\\[^\\/:*?" + Chr(34) + "<>|]+)*?\\?\z", #PB_RegularExpression_NoCase)
If id_re
If Not MatchRegularExpression(id_re, path$)
flag = #False
EndIf
FreeRegularExpression(id_re)
EndIf
ProcedureReturn flag
EndProcedure
Define path$
path$ = "C:\PB\PureBasic\PureBasic_x64\Compilers"
Debug CheckPath(path$)
path$ = "C:\PB\PureBasic\PureBasic_x64\Compilers\"
Debug CheckPath(path$)
path$ = "C:\"
Debug CheckPath(path$)
; Error
path$ = "C:\\"
Debug CheckPath(path$)
path$ = "C:\PB\PureBasic\\PureBasic_x64\Compilers"
Debug CheckPath(path$)
path$ = "C:\PB\PureBasic:PureBasic_x64\Compilers"
Debug CheckPath(path$)
path$ = "C:\Users\<user>\AppData"
Debug CheckPath(path$)
path$ = "%temp%"
Debug CheckPath(path$)
Re: Make CheckFilename behave differently on different OSs
Posted: Thu May 22, 2025 8:59 am
by NicTheQuick
On Linux that command would be quite simple. Only the null character and `/` are not allowed in filenames. But all the other Unicode characters are allowed. On Windows it is more complicated.
To be precise, it's not just the operating system, but also the file system. If you use NTFS or FAT32 under Linux, the characters there are also limited. This means that, technically speaking, you would actually have to pass an entire path to `CheckFilename()` and the function would then have to check internally which file system the file is on and react accordingly.