The scandir() function scans the directory dir, calling select() on each directory entry as "int(*filter)(const struct dirent *)" How can I pass pattern value as parameter to fnmatch(const char *pattern, const char *string, int flags) function used in filter ?
Here my sample code
int my_selectgrf(const struct dirent *namelist)
{
int r = 0;
char my_pattern[] = "*.grf";
r = fnmatch(my_pattern, namelist->d_name, FNM_PERIOD);
return (r==0)?1:0;
}
scandir("/pub/data/grf", &namelist, my_selectgrf, alphasort);
my goal is to be able to use my_pattern as input parameter.
The short answer: You can't. This is an atrociously bad API, and it's outright shameful that something like this was added to POSIX as recently as 2008 (based on a bad design in glibc). This kind of API without a way to parameterize it or pass it a context should have been abolished 20+ years ago.
With that said, there are some workarounds:
Approach 1: Use a global variable, and if your code needs to be thread-safe, ensure that only one thread can be using scandir
with the given scan function at a time, by locking. This of course serializes usage, which is probably not acceptable if you actually want to be calling the function from multiple threads.
Approach 2: Use thread-local storage, either the GCC __thread
keyword (or the C11 _Thread_local
keyword, which GCC sadly still does not accept) or POSIX pthread_setspecific
and family. This is fairly clean, but unfortunately it may not be correct; if the implementation of scandir
internally used multiple threads, the parameter could fail to be available in some calls back to the scan function. At present, I don't believe there are multi-threaded implementations of scandir
.
Now, the better solution:
Ditch scandir
and write your own function to do the same thing, with the proper API. It's only a few lines anyway.