Search for files by multiple extensions

New to FreeBASIC? Post your questions here.
gerry
Posts: 70
Joined: Oct 04, 2021 7:29

Search for files by multiple extensions

Post by gerry »

Hi!

I haven't found any examples of searching for files by multiple extensions anywhere..
Are there any options?

Code: Select all

Dim As String Filename
Filename = Dir("*.txt")
Do While Len(Filename)
    Print Filename
    Filename = Dir()
Loop
Sleep
St_W
Posts: 1619
Joined: Feb 11, 2009 14:24
Location: Austria
Contact:

Re: Search for files by multiple extensions

Post by St_W »

I fear the only options you have are either listing the directory contents multiple times, for each file type individually, or listing all files and doing the extension filtering manually yourself.

As far as I know the underlying methods used (e.g. on Windows FindFirstFileEx) don't support what you're looking for (haven't looked in fbc's source to verify that, however).
jj2007
Posts: 2326
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: Search for files by multiple extensions

Post by jj2007 »

Difficult in FreeBasic, but pretty "basic" in other languages:

Code: Select all

  GetFiles examples\win32\COM\*.bas|*.bi
  SortFiles date		; most recent on top, please
  For_ ct=0 To Files$(?)-1	; print the results
	PrintLine Str$(GfSize(ct)), Tb$, GfDate$(ct), Spc2$, GfTime$(ct), Tb$, Files$(ct)
  Next

Code: Select all

4982    05.06.2021  13:52:20    examples\win32\COM\MoviePlayer\movctrl\CMovie.bas
3923    05.06.2021  13:52:20    examples\win32\COM\MoviePlayer\movctrl\movctrl.bas
579     05.06.2021  13:52:20    examples\win32\COM\MoviePlayer\movctrl\CMovie.bi
743     05.06.2021  13:52:20    examples\win32\COM\MoviePlayer\movctrl\movctrl.bi
6277    05.06.2021  13:52:20    examples\win32\COM\MoviePlayer\test.bas
4590    05.06.2021  13:52:20    examples\win32\COM\WebBrowser\webctrl\CClientSite.bas
8360    05.06.2021  13:52:20    examples\win32\COM\WebBrowser\webctrl\CBrowser.bas
6297    05.06.2021  13:52:20    examples\win32\COM\WebBrowser\webctrl\CInPlaceSite.bas
4923    05.06.2021  13:52:20    examples\win32\COM\WebBrowser\webctrl\CInPlaceFrame.bas
4562    05.06.2021  13:52:20    examples\win32\COM\WebBrowser\webctrl\webctrl.bas
355     05.06.2021  13:52:20    examples\win32\COM\WebBrowser\webctrl\Common.bi
754     05.06.2021  13:52:20    examples\win32\COM\WebBrowser\webctrl\CInPlaceSite.bi
495     05.06.2021  13:52:20    examples\win32\COM\WebBrowser\webctrl\CInPlaceFrame.bi
676     05.06.2021  13:52:20    examples\win32\COM\WebBrowser\webctrl\CClientSite.bi
897     05.06.2021  13:52:20    examples\win32\COM\WebBrowser\webctrl\CBrowser.bi
1068    05.06.2021  13:52:20    examples\win32\COM\WebBrowser\webctrl\webctrl.bi
7154    05.06.2021  13:52:20    examples\win32\COM\WebBrowser\test.bas
11400   05.06.2021  13:52:20    examples\win32\COM\D3DX\Meshes\meshes.bas
6626    05.06.2021  13:52:20    examples\win32\COM\DropTarget\CDropTarget.bas
2915    05.06.2021  13:52:20    examples\win32\COM\DropTarget\test.bas
1681    05.06.2021  13:52:20    examples\win32\COM\DropTarget\CDropTarget.bi
2918    19.08.2018  10:43:59    examples\win32\COM\DropTarget\tmp\TmpFile.bas
St_W
Posts: 1619
Joined: Feb 11, 2009 14:24
Location: Austria
Contact:

Re: Search for files by multiple extensions

Post by St_W »

Nice, but if you'd tell us how it's implemented it would be more helpful ;-)

As the issue is basically "inherited" from the underlying API I searched for possible other solutions, but they typically also suggest to filter yourself: https://stackoverflow.com/a/8781629
coderJeff
Site Admin
Posts: 4313
Joined: Nov 04, 2005 14:23
Location: Ontario, Canada
Contact:

Re: Search for files by multiple extensions

Post by coderJeff »

gerry wrote: Feb 20, 2022 8:45 Are there any options?
Assuming windows only (you have other posts about autoit):

Code: Select all

#include "windows.bi"
#include "win/shlwapi.bi"

Dim As String Filename
Filename = Dir("*.*")
Do While Len(Filename)
	if PathMatchSpec( filename, "*.txt" ) _
		or PathMatchSpec( filename, "*.bas" ) then 
	    Print Filename
	end if
    Filename = Dir()
Loop
Or if really want a single function - though it may depend on your version of windows (and IE?). This shows declarations for the "PathMatchSpecEx" winapi function:

Code: Select all

#include "windows.bi"
#include "win/shlwapi.bi"

#define PMSF_NORMAL            &h00000000ul
#define PMSF_MULTIPLE          &h00000001ul
#define PMSF_DONT_STRIP_SPACES &h00010000ul

declare function PathMatchSpecExA(byval pszFile as LPCSTR, byval pszSpec as LPCSTR, byval dwFlags as DWORD) as HRESULT
declare function PathMatchSpecExW(byval pszFile as LPCWSTR, byval pszSpec as LPCWSTR, byval dwFlags as DWORD) as HRESULT

#ifdef UNICODE
	declare function PathMatchSpecEx alias "PathMatchSpecExW"(byval pszFile as LPCWSTR, byval pszSpec as LPCWSTR, byval dwFlags as DWORD) as HRESULT
#else
	declare function PathMatchSpecEx alias "PathMatchSpecExA"(byval pszFile as LPCSTR, byval pszSpec as LPCSTR, byval dwFlags as DWORD) as HRESULT
#endif

Dim As String Filename
Filename = Dir("*.*")
Do While Len(Filename)
	if PathMatchSpecEx( filename, "*.txt;*.bas", PMSF_MULTIPLE ) = S_OK then 
	    Print Filename
	end if
    Filename = Dir()
Loop
fb's included windows headers are a little out of date ... so not every winapi function is available by default.

If the intent is to use this cross-platform, say on linux, then obviously need to implement a pattern matching function.
badidea
Posts: 2586
Joined: May 24, 2007 22:10
Location: The Netherlands

Re: Search for files by multiple extensions

Post by badidea »

Do it manually / filter in freebasic:

Code: Select all

function getFileExt(fullfileName as string) as string
	dim as integer sepPos = instrrev(fullfileName, any ".")
	return mid(fullfileName, sepPos + 1)
end function

function isListed(fileName as string, extList() as string) as boolean
	dim as string fileExt = getFileExt(fileName)
	for i as integer = 0 to ubound(extList)
		if fileExt = extList(i) then return true
	next
	return false
end function

dim as string extMatchList(...) = {"txt", "bas"}

dim as string fileName
fileName = dir("*")
do while len(fileName)
	if isListed(fileName, extMatchList()) then
		print "MATCH:  " & fileName
	else
		print "REJECT: " & fileName
	end if
	fileName = dir()
loop
sleep
output here:

Code: Select all

REJECT: test1234save.bin
MATCH:  wikimedia_intallation.txt
REJECT: rubik.pdf
REJECT: test
REJECT: FB-manual-1.07.1.chm
MATCH:  github-recovery-codes.txt
MATCH:  test.bas
REJECT: Coronabewijs met QR-code.pdf
MATCH:  FreneticPanicBakery.txt
Munair
Posts: 1286
Joined: Oct 19, 2017 15:00
Location: Netherlands
Contact:

Re: Search for files by multiple extensions

Post by Munair »

badidea wrote: Feb 20, 2022 14:12 Do it manually / filter in freebasic:
It's a workaround, but probably the cleanest and best multi-platform solution.
gerry
Posts: 70
Joined: Oct 04, 2021 7:29

Re: Search for files by multiple extensions

Post by gerry »

coderJeff wrote: Feb 20, 2022 13:21
gerry wrote: Feb 20, 2022 8:45 Are there any options?
Assuming windows only (you have other posts about autoit):

Code: Select all

#include "windows.bi"
#include "win/shlwapi.bi"

Dim As String Filename
Filename = Dir("*.*")
Do While Len(Filename)
	if PathMatchSpec( filename, "*.txt" ) _
		or PathMatchSpec( filename, "*.bas" ) then 
	    Print Filename
	end if
    Filename = Dir()
Loop
Or if really want a single function - though it may depend on your version of windows (and IE?). This shows declarations for the "PathMatchSpecEx" winapi function:

Code: Select all

#include "windows.bi"
#include "win/shlwapi.bi"

#define PMSF_NORMAL            &h00000000ul
#define PMSF_MULTIPLE          &h00000001ul
#define PMSF_DONT_STRIP_SPACES &h00010000ul

declare function PathMatchSpecExA(byval pszFile as LPCSTR, byval pszSpec as LPCSTR, byval dwFlags as DWORD) as HRESULT
declare function PathMatchSpecExW(byval pszFile as LPCWSTR, byval pszSpec as LPCWSTR, byval dwFlags as DWORD) as HRESULT

#ifdef UNICODE
	declare function PathMatchSpecEx alias "PathMatchSpecExW"(byval pszFile as LPCWSTR, byval pszSpec as LPCWSTR, byval dwFlags as DWORD) as HRESULT
#else
	declare function PathMatchSpecEx alias "PathMatchSpecExA"(byval pszFile as LPCSTR, byval pszSpec as LPCSTR, byval dwFlags as DWORD) as HRESULT
#endif

Dim As String Filename
Filename = Dir("*.*")
Do While Len(Filename)
	if PathMatchSpecEx( filename, "*.txt;*.bas", PMSF_MULTIPLE ) = S_OK then 
	    Print Filename
	end if
    Filename = Dir()
Loop
fb's included windows headers are a little out of date ... so not every winapi function is available by default.

If the intent is to use this cross-platform, say on linux, then obviously need to implement a pattern matching function.
Thank you for your help! :)
gerry
Posts: 70
Joined: Oct 04, 2021 7:29

Re: Search for files by multiple extensions

Post by gerry »

badidea wrote: Feb 20, 2022 14:12 Do it manually / filter in freebasic:

Code: Select all

function getFileExt(fullfileName as string) as string
	dim as integer sepPos = instrrev(fullfileName, any ".")
	return mid(fullfileName, sepPos + 1)
end function

function isListed(fileName as string, extList() as string) as boolean
	dim as string fileExt = getFileExt(fileName)
	for i as integer = 0 to ubound(extList)
		if fileExt = extList(i) then return true
	next
	return false
end function

dim as string extMatchList(...) = {"txt", "bas"}

dim as string fileName
fileName = dir("*")
do while len(fileName)
	if isListed(fileName, extMatchList()) then
		print "MATCH:  " & fileName
	else
		print "REJECT: " & fileName
	end if
	fileName = dir()
loop
sleep
output here:

Code: Select all

REJECT: test1234save.bin
MATCH:  wikimedia_intallation.txt
REJECT: rubik.pdf
REJECT: test
REJECT: FB-manual-1.07.1.chm
MATCH:  github-recovery-codes.txt
MATCH:  test.bas
REJECT: Coronabewijs met QR-code.pdf
MATCH:  FreneticPanicBakery.txt
Thank you, you helped out :)
paul doe
Moderator
Posts: 1730
Joined: Jul 25, 2017 17:22
Location: Argentina

Re: Search for files by multiple extensions

Post by paul doe »

jj2007 wrote: Feb 20, 2022 11:16 Difficult in FreeBasic, but pretty "basic" in other languages:
...
Yeah but unfortunately, this is a forum about a specific language called 'FreeBasic'. Don't you like it? There's the door over there. I already issued you a warning for this kind of demeanor. There won't be a second one.
paul doe
Moderator
Posts: 1730
Joined: Jul 25, 2017 17:22
Location: Argentina

Re: Search for files by multiple extensions

Post by paul doe »

coderJeff wrote: Feb 20, 2022 13:21 ...
If the intent is to use this cross-platform, say on linux, then obviously need to implement a pattern matching function.
Regarding this, someone asked a while back on the Discord server about this, so I quickly ported one (original was in C):

Code: Select all

function match( subject as zstring ptr, pattern as zstring ptr ) as boolean
  #define cst( v ) cast( ubyte ptr, v )
  #define CH_QUOTE 63 '' ASCII for ?
  #define CH_MULT  42 '' ASCII for *
  
  return( _
    iif( cst( pattern )[ 0 ] = 0 andAlso cst( subject )[ 0 ] = 0, true, _
    iif( cst( pattern )[ 0 ] = CH_QUOTE orElse _
      cst( pattern )[ 0 ] = cst( subject )[ 0 ], match( subject + 1, pattern + 1 ), _
    iif( cst( pattern )[ 0 ] = CH_MULT, match( subject, pattern + 1 ) orElse _
      match( subject + 1, pattern ), false ) ) ) )
end function
@gerry: the above function will return true if some string matches the specified pattern. '?' means 'any character', and '*' means 'any number of characters'. Like this:

Code: Select all

? match( "freebasicrocks", "f*basic??cks" ) '' true
? match( "freebasicsucks", "f*basic??cks" ) '' true
? match( "freeasicracks", "f*basic??cks" )  '' false
Munair
Posts: 1286
Joined: Oct 19, 2017 15:00
Location: Netherlands
Contact:

Re: Search for files by multiple extensions

Post by Munair »

paul doe wrote: Feb 20, 2022 16:50
jj2007 wrote: Feb 20, 2022 11:16 Difficult in FreeBasic, but pretty "basic" in other languages:
...
Yeah but unfortunately, this is a forum about a specific language called 'FreeBasic'. Don't you like it? There's the door over there. I already issued you a warning for this kind of demeanor. There won't be a second one.
I think Paul Doe is going over the top here as a moderator. And this isn't the first time. Do moderators actually communicate guidelines with each other or does every moderator make his own decisions as he sees fit?
coderJeff
Site Admin
Posts: 4313
Joined: Nov 04, 2005 14:23
Location: Ontario, Canada
Contact:

Re: Search for files by multiple extensions

Post by coderJeff »

Of course we communicate with each other. This is not a surprise at all. It's been going on a long time.
jj2007
Posts: 2326
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: Search for files by multiple extensions

Post by jj2007 »

St_W wrote: Feb 20, 2022 12:22Nice, but if you'd tell us how it's implemented it would be more helpful ;-)
GetFiles uses FindFirstFileW, and checks for each file extension if it's contained in the *.bas|*.bi whatever string. It's pretty straightforward, actually. Besides, you could specify a callback function where the user can decide, based on the elements of the WIN32_FIND_DATA structure (date, size, etc), whether to include or exclude the file in the string array.
paul doe wrote: Feb 20, 2022 16:50 There's the door over there
Cool down, young man. I am poking you a little bit, trying to give you the inspiration needed to make the language deserve the "B" in its name. My own dialect is only a hobby, I am probably the only user, and it is definitely not intended to be competition. Honestly, it makes me really sad to see that perhaps the last free BASIC dialect has so many problems with build errors and exaggerated "type safety" that results in absurd warnings when you try to compile a simple Windows program.
Last edited by jj2007 on Feb 20, 2022 18:49, edited 1 time in total.
Munair
Posts: 1286
Joined: Oct 19, 2017 15:00
Location: Netherlands
Contact:

Re: Search for files by multiple extensions

Post by Munair »

jj2007 wrote: Feb 20, 2022 18:47 [and exaggerated "type safety" that results in absurd warnings
Recompile the Lazarus IDE and count the warnings. :D
Post Reply