How can I parameterize the select function in scandir

The scandir () function scans the dir directory, calling select () for each directory entry as "int (* filter) (const struct dirent *)" How to pass the template value as a parameter to fnmatch (const char * pattern, const char * string, int flags) function used in the filter?

Here is 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 use my_pattern as an input parameter.

+4
source share
1 answer

Short answer: you cannot. This is a terribly bad API, and it is shameful that something like this was added to POSIX back in 2008 (based on poor design in glibc). This type of API without the ability to parameterize it or pass context to it should have been canceled 20 years ago.

With that said, there are some workarounds:

Approach 1: use a global variable, and if your code should be thread safe, make sure that only one thread can use scandir with the given scan function at a time, blocking. This, of course, serializes the use, which is probably not acceptable if you really want to call a function from multiple threads.

Approach 2: use local thread storage, either the GCC __thread keyword (or the C11 _Thread_local , which GCC unfortunately still does not accept), or the POSIX pthread_setspecific and its family. This is pretty clean, but unfortunately this may not be true; if the scandir implementation internally uses multiple threads, the parameter may not be available in some calls to the scan function. Currently, I do not believe that there are multithreaded scandir implementations.

Now the best solution:

Ditch scandir and write your own function to do the same with the appropriate API. These are just a few lines.

+5
source

Source: https://habr.com/ru/post/1502005/


All Articles