/*
 * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de.
 * Distributed under the terms of the MIT License.
 */
#ifndef _ENTRY_FILTER_H
#define _ENTRY_FILTER_H
 
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
 
#include <new>
 
#if defined(__BEOS__) && !defined(__HAIKU__)
	// BeOS doesn't have <fnmatch.h>, but libroot.so features fnmatch() anyway
	extern "C" int fnmatch(const char *pattern, const char *string, int flags);
#else
#	include <fnmatch.h>
#endif
 
namespace BPrivate {
 
 
class BasicEntryFilter {
public:
	BasicEntryFilter()
		: fPattern(NULL),
		  fIsFileName(false)
	{
	}
 
	~BasicEntryFilter()
	{
		free(fPattern);
	}
 
	bool SetTo(const char* pattern, bool isFileName)
	{
		free(fPattern);
 
		fPattern = strdup(pattern);
		if (fPattern == NULL)
			return false;
 
		fIsFileName = isFileName;
 
		return true;
	}
 
	bool Filter(const char* path, const char* name) const
	{
		if (fPattern != NULL) {
			if (fnmatch(fPattern, (fIsFileName ? name : path), 0) == 0)
				return true;
		}
 
		return false;
	}
 
	void SetNextFilter(BasicEntryFilter* next)
	{
		fNextFilter = next;
	}
 
	BasicEntryFilter* NextFilter() const
	{
		 return fNextFilter;
	}
 
private:
	char*				fPattern;
	bool				fIsFileName;
	BasicEntryFilter*	fNextFilter;
};
 
 
class EntryFilter {
public:
	EntryFilter()
		: fIncludeFilters(NULL),
		  fExcludeFilters(NULL)
	{
	}
 
	~EntryFilter()
	{
		while (BasicEntryFilter* filter = fIncludeFilters) {
			fIncludeFilters = filter->NextFilter();
			delete filter;
		}
 
		while (BasicEntryFilter* filter = fExcludeFilters) {
			fExcludeFilters = filter->NextFilter();
			delete filter;
		}
	}
 
	void AddIncludeFilter(BasicEntryFilter* filter)
	{
		_AddFilter(fIncludeFilters, filter);
	}
 
	bool AddIncludeFilter(const char* pattern, bool isFilePattern)
	{
		return _AddFilter(fIncludeFilters, pattern, isFilePattern);
	}
 
	void AddExcludeFilter(BasicEntryFilter* filter)
	{
		_AddFilter(fExcludeFilters, filter);
	}
 
	bool AddExcludeFilter(const char* pattern, bool isFilePattern)
	{
		return _AddFilter(fExcludeFilters, pattern, isFilePattern);
	}
 
	bool Filter(const char* path) const
	{
		if (fExcludeFilters == NULL && fIncludeFilters)
			return true;
 
		// get leaf name
		const char* name = strrchr(path, '/');
		name = (name != NULL ? name + 1 : path);
 
		// exclude filters
		if (_Filter(fExcludeFilters, path, name))
			return false;
 
		// include filters -- if none are given, everything matches
		return fIncludeFilters == NULL || _Filter(fIncludeFilters, path, name);
	}
 
private:
	static void _AddFilter(BasicEntryFilter*& filterList,
		BasicEntryFilter* filter)
	{
		filter->SetNextFilter(filterList);
		filterList = filter;
	}
 
	static bool _AddFilter(BasicEntryFilter*& filterList, const char* pattern,
		bool isFilePattern)
	{
		BasicEntryFilter* filter = new(std::nothrow) BasicEntryFilter;
		if (filter == NULL)
			return false;
 
		if (!filter->SetTo(pattern, isFilePattern)) {
			delete filter;
			return false;
		}
 
		_AddFilter(filterList, filter);
 
		return true;
	}
 
	static bool _Filter(const BasicEntryFilter* const& filterList,
		const char* path, const char* name)
	{
		const BasicEntryFilter* filter = filterList;
		while (filter) {
			if (filter->Filter(path, name))
				return true;
			filter = filter->NextFilter();
		}
 
		return false;
	}
 
private:
	BasicEntryFilter*	fIncludeFilters;
	BasicEntryFilter*	fExcludeFilters;
};
 
}	// namespace BPrivate
 
 
#endif	// _ENTRY_FILTER_H

V730 Not all members of a class are initialized inside the constructor. Consider inspecting: fNextFilter.