2013-09-13 2 views
3

Функция scandir() сканирует каталог dir, вызывая select() для каждой записи каталога как «int (* filter) (const struct dirent *)» Как пропустить шаблон значение как параметр для fnmatch (const char * pattern, const char * string, int flags) функция, используемая в фильтре?Как я могу параметризовать функцию select в scandir

Вот мой пример кода

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_pattern в качестве входного параметра.

+0

Что происходит, когда вы делаете то, что вы показываете в своем коде? Вы получаете ошибки компиляции? Ошибки времени выполнения? Он работает не так, как ожидалось (в этом случае, каковы фактические и ожидаемые результаты?) –

+1

'my_pattern' или' pattern'? – 0x90

+0

my_pattern, извините, я исправил код – famedoro

ответ

5

Короткий ответ: вы не можете. Это ужасно плохой API, и совершенно позорно, что что-то вроде этого было добавлено в POSIX еще в 2008 году (на основе плохого дизайна в glibc). Этот тип API без возможности параметризовать его или передать ему контекст должен был быть отменен 20 лет назад.

С учетом сказанного, есть некоторые обходные пути:

Подход 1: Используйте глобальную переменную, и если ваш код должен быть поточно-безопасной, убедитесь, что только один поток может быть с помощью scandir с заданной функцией сканирования в то время, путем блокировки. Это, конечно, сериализует использование, что, вероятно, неприемлемо, если вы действительно хотите вызвать функцию из нескольких потоков.

подход 2: Использование потоков локальное хранилище, либо GCC __thread ключевое слово (или C11 _Thread_local ключевого слова, которые, к сожалению, до сих пор GCC не принимает) или POSIX pthread_setspecific и семьи. Это довольно чисто, но, к сожалению, это может быть неверно; если в реализации scandir внутренне используется несколько потоков, параметр может оказаться недоступным в некоторых вызовах функции сканирования. В настоящее время я не считаю, что существуют многопоточные реализации scandir.

Теперь, лучшее решение:

Ditch scandir и написать свою собственную функцию, чтобы сделать то же самое, с соответствующим API. В любом случае, это всего лишь несколько строк.

+0

Это именно то, что я писал ... +1 для вас. Я добавил бы также, что могут возникать проблемы с реентерацией, когда задействованы сигналы Unix, в частности, API API статического стиля. Очень жаль! –

+0

@R .. Спасибо за ваше предложение, где я могу найти исходный код для скандинава? – famedoro

+0

Источник glibc для скандира находится здесь: [http://code.metager.de/source/xref/gnu/glibc/dirent/scandirat.c]. Обратите внимание, что для переносимого кода (т. Е. Целей без glibc) вы должны заменить вызов readdir() с помощью readdir_r() (и принять все осторожные меры readdir_r()). –