83 #ifndef INCLUDED_SimpleGlob
84 #define INCLUDED_SimpleGlob
130 SG_GLOB_ERR = 1 << 0,
131 SG_GLOB_MARK = 1 << 1,
132 SG_GLOB_NOSORT = 1 << 2,
133 SG_GLOB_NOCHECK = 1 << 3,
134 SG_GLOB_TILDE = 1 << 4,
135 SG_GLOB_ONLYDIR = 1 << 5,
136 SG_GLOB_ONLYFILE = 1 << 6,
137 SG_GLOB_NODOT = 1 << 7,
138 SG_GLOB_FULLSORT = 1 << 8
155 #if !defined(__WIN32__) && defined(USTRING_H)
156 #define SG_HAVE_ICU 1
158 #define SG_HAVE_ICU 0
168 #include <mbstring.h>
169 #define sg_strchr ::_mbschr
170 #define sg_strrchr ::_mbsrchr
171 #define sg_strlen ::_mbslen
172 #if __STDC_WANT_SECURE_LIB__
173 #define sg_strcpy_s(a, n, b) ::_mbscpy_s(a, n, b)
175 #define sg_strcpy_s(a, n, b) ::_mbscpy(a, b)
177 #define sg_strcmp ::_mbscmp
178 #define sg_strcasecmp ::_mbsicmp
179 #define SOCHAR_T unsigned char
181 #include <sys/types.h>
182 #include <sys/stat.h>
185 #define MAX_PATH PATH_MAX
186 #define sg_strchr ::strchr
187 #define sg_strrchr ::strrchr
188 #define sg_strlen ::strlen
189 #define sg_strcpy_s(a, n, b) ::strcpy(a, b)
190 #define sg_strcmp ::strcmp
191 #define sg_strcasecmp ::strcasecmp
192 #define SOCHAR_T char
203 #define SG_ASSERT(b) _ASSERTE(b)
206 #define SG_ASSERT(b) assert(b)
213 class SimpleGlobUtil {
215 static const char* strchr(
const char* s,
char c)
217 return (
char*)sg_strchr((
const SOCHAR_T*)s, c);
219 static const wchar_t* strchr(
const wchar_t* s,
wchar_t c)
221 return ::wcschr(s, c);
224 static const UChar* strchr(
const UChar* s, UChar c)
226 return ::u_strchr(s, c);
230 static const char* strrchr(
const char* s,
char c)
232 return (
char*)sg_strrchr((
const SOCHAR_T*)s, c);
234 static const wchar_t* strrchr(
const wchar_t* s,
wchar_t c)
236 return ::wcsrchr(s, c);
239 static const UChar* strrchr(
const UChar* s, UChar c)
241 return ::u_strrchr(s, c);
246 static size_t strlen(
const char* s) { return ::strlen(s); }
247 static size_t strlen(
const wchar_t* s) { return ::wcslen(s); }
249 static size_t strlen(
const UChar* s)
251 return ::u_strlen(s);
255 static void strcpy_s(
char* dst,
size_t n,
const char* src)
258 sg_strcpy_s((SOCHAR_T*)dst, n, (
const SOCHAR_T*)src);
260 static void strcpy_s(
wchar_t* dst,
size_t n,
const wchar_t* src)
262 #if __STDC_WANT_SECURE_LIB__
263 ::wcscpy_s(dst, n, src);
270 static void strcpy_s(UChar* dst,
size_t n,
const UChar* src)
272 ::u_strncpy(dst, src, n);
276 static int strcmp(
const char* s1,
const char* s2)
278 return sg_strcmp((
const SOCHAR_T*)s1, (
const SOCHAR_T*)s2);
280 static int strcmp(
const wchar_t* s1,
const wchar_t* s2)
282 return ::wcscmp(s1, s2);
285 static int strcmp(
const UChar* s1,
const UChar* s2)
287 return ::u_strcmp(s1, s2);
291 static int strcasecmp(
const char* s1,
const char* s2)
293 return sg_strcasecmp((
const SOCHAR_T*)s1, (
const SOCHAR_T*)s2);
296 static int strcasecmp(
const wchar_t* s1,
const wchar_t* s2)
298 return ::_wcsicmp(s1, s2);
302 static int strcasecmp(
const UChar* s1,
const UChar* s2)
304 return u_strcasecmp(s1, s2, 0);
317 #ifndef INVALID_FILE_ATTRIBUTES
318 #define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
321 #define SG_PATH_CHAR '\\'
324 template <
class SOCHAR>
325 struct SimpleGlobBase {
327 : m_hFind(INVALID_HANDLE_VALUE)
331 int FindFirstFileS(
const char* a_pszFileSpec,
unsigned int)
333 m_hFind = FindFirstFileA(a_pszFileSpec, &m_oFindDataA);
334 if (m_hFind != INVALID_HANDLE_VALUE) {
337 DWORD dwErr = GetLastError();
338 if (dwErr == ERROR_FILE_NOT_FOUND) {
339 return SG_ERR_NOMATCH;
341 return SG_ERR_FAILURE;
343 int FindFirstFileS(
const wchar_t* a_pszFileSpec,
unsigned int)
345 m_hFind = FindFirstFileW(a_pszFileSpec, &m_oFindDataW);
346 if (m_hFind != INVALID_HANDLE_VALUE) {
349 DWORD dwErr = GetLastError();
350 if (dwErr == ERROR_FILE_NOT_FOUND) {
351 return SG_ERR_NOMATCH;
353 return SG_ERR_FAILURE;
356 bool FindNextFileS(
char)
358 return FindNextFileA(m_hFind, &m_oFindDataA) != FALSE;
360 bool FindNextFileS(
wchar_t)
362 return FindNextFileW(m_hFind, &m_oFindDataW) != FALSE;
370 const char* GetFileNameS(
char)
const
372 return m_oFindDataA.cFileName;
374 const wchar_t* GetFileNameS(
wchar_t)
const
376 return m_oFindDataW.cFileName;
379 bool IsDirS(
char)
const
381 return this->GetFileTypeS(m_oFindDataA.dwFileAttributes) == SG_FILETYPE_DIR;
383 bool IsDirS(
wchar_t)
const
385 return this->GetFileTypeS(m_oFindDataW.dwFileAttributes) == SG_FILETYPE_DIR;
388 SG_FileType GetFileTypeS(
const char* a_pszPath)
390 return this->GetFileTypeS(GetFileAttributesA(a_pszPath));
392 SG_FileType GetFileTypeS(
const wchar_t* a_pszPath)
394 return this->GetFileTypeS(GetFileAttributesW(a_pszPath));
396 SG_FileType GetFileTypeS(DWORD a_dwAttribs)
const
398 if (a_dwAttribs == INVALID_FILE_ATTRIBUTES) {
399 return SG_FILETYPE_INVALID;
401 if (a_dwAttribs & FILE_ATTRIBUTE_DIRECTORY) {
402 return SG_FILETYPE_DIR;
404 return SG_FILETYPE_FILE;
409 WIN32_FIND_DATAA m_oFindDataA;
410 WIN32_FIND_DATAW m_oFindDataW;
415 #define SG_PATH_CHAR '/'
418 template <
class SOCHAR>
419 struct SimpleGlobBase {
422 memset(&m_glob, 0,
sizeof(m_glob));
423 m_uiCurr = (size_t)-1;
434 size_t len = strlen(m_glob.gl_pathv[m_uiCurr]);
435 if (m_glob.gl_pathv[m_uiCurr][len - 1] ==
'/') {
437 m_glob.gl_pathv[m_uiCurr][len - 1] = 0;
441 int FindFirstFileS(
const char* a_pszFileSpec,
unsigned int a_uiFlags)
443 int nFlags = GLOB_MARK | GLOB_NOSORT;
444 if (a_uiFlags & SG_GLOB_ERR)
446 if (a_uiFlags & SG_GLOB_TILDE)
447 nFlags |= GLOB_TILDE;
448 int rc = glob(a_pszFileSpec, nFlags, NULL, &m_glob);
449 if (rc == GLOB_NOSPACE)
450 return SG_ERR_MEMORY;
451 if (rc == GLOB_ABORTED)
452 return SG_ERR_FAILURE;
453 if (rc == GLOB_NOMATCH)
454 return SG_ERR_NOMATCH;
461 int FindFirstFileS(
const UChar* a_pszFileSpec,
unsigned int a_uiFlags)
463 char buf[PATH_MAX] = { 0 };
464 UErrorCode status = U_ZERO_ERROR;
465 u_strToUTF8(buf,
sizeof(buf), NULL, a_pszFileSpec, -1, &status);
466 if (U_FAILURE(status))
467 return SG_ERR_FAILURE;
468 return this->FindFirstFileS(buf, a_uiFlags);
472 bool FindNextFileS(
char)
474 SG_ASSERT(m_uiCurr != (
size_t)-1);
475 if (++m_uiCurr >= m_glob.gl_pathc) {
483 bool FindNextFileS(UChar)
485 return this->FindNextFileS((
char)0);
492 memset(&m_glob, 0,
sizeof(m_glob));
493 m_uiCurr = (size_t)-1;
496 const char* GetFileNameS(
char)
const
498 SG_ASSERT(m_uiCurr != (
size_t)-1);
499 return m_glob.gl_pathv[m_uiCurr];
503 const UChar* GetFileNameS(UChar)
const
505 const char* pszFile = this->GetFileNameS((
char)0);
508 UErrorCode status = U_ZERO_ERROR;
509 memset(m_szBuf, 0,
sizeof(m_szBuf));
510 u_strFromUTF8(m_szBuf, PATH_MAX, NULL, pszFile, -1, &status);
511 if (U_FAILURE(status))
517 bool IsDirS(
char)
const
519 SG_ASSERT(m_uiCurr != (
size_t)-1);
524 bool IsDirS(UChar)
const
526 return this->IsDirS((
char)0);
530 SG_FileType GetFileTypeS(
const char* a_pszPath)
const
533 if (0 != stat(a_pszPath, &sb)) {
534 return SG_FILETYPE_INVALID;
536 if (S_ISDIR(sb.st_mode)) {
537 return SG_FILETYPE_DIR;
539 if (S_ISREG(sb.st_mode)) {
540 return SG_FILETYPE_FILE;
542 return SG_FILETYPE_INVALID;
546 SG_FileType GetFileTypeS(
const UChar* a_pszPath)
const
548 char buf[PATH_MAX] = { 0 };
549 UErrorCode status = U_ZERO_ERROR;
550 u_strToUTF8(buf,
sizeof(buf), NULL, a_pszPath, -1, &status);
551 if (U_FAILURE(status))
552 return SG_FILETYPE_INVALID;
553 return this->GetFileTypeS(buf);
562 mutable UChar m_szBuf[PATH_MAX];
575 template <
class SOCHAR>
576 class CSimpleGlobTempl :
private SimpleGlobBase<SOCHAR> {
586 CSimpleGlobTempl(
unsigned int a_uiFlags = 0,
int a_nReservedSlots = 0);
603 int Init(
unsigned int a_uiFlags = 0,
int a_nReservedSlots = 0);
618 int Add(
const SOCHAR* a_pszFileSpec);
634 int Add(
int a_nCount,
const SOCHAR*
const* a_rgpszFileSpec);
638 inline int FileCount()
const {
return m_nArgsLen; }
641 inline SOCHAR** Files()
643 SetArgvArrayType(POINTERS);
648 inline SOCHAR* File(
int n)
650 SG_ASSERT(n >= 0 && n < m_nArgsLen);
655 CSimpleGlobTempl(
const CSimpleGlobTempl&);
656 CSimpleGlobTempl& operator=(
const CSimpleGlobTempl&);
663 enum ARG_ARRAY_TYPE { OFFSETS,
667 void SetArgvArrayType(ARG_ARRAY_TYPE a_nNewType);
670 int AppendName(
const SOCHAR* a_pszFileName,
bool a_bIsDir);
673 bool GrowArgvArray(
int a_nNewLen);
676 bool GrowStringBuffer(
size_t a_uiMinSize);
679 static int fileSortCompare(
const void* a1,
const void* a2);
682 unsigned int m_uiFlags;
683 ARG_ARRAY_TYPE m_nArgArrayType;
685 int m_nReservedSlots;
689 size_t m_uiBufferSize;
690 size_t m_uiBufferLen;
691 SOCHAR m_szPathPrefix[MAX_PATH];
698 template <
class SOCHAR>
699 CSimpleGlobTempl<SOCHAR>::CSimpleGlobTempl(
700 unsigned int a_uiFlags,
701 int a_nReservedSlots)
708 Init(a_uiFlags, a_nReservedSlots);
711 template <
class SOCHAR>
712 CSimpleGlobTempl<SOCHAR>::~CSimpleGlobTempl()
720 template <
class SOCHAR>
721 int CSimpleGlobTempl<SOCHAR>::Init(
722 unsigned int a_uiFlags,
723 int a_nReservedSlots)
725 m_nArgArrayType = POINTERS;
726 m_uiFlags = a_uiFlags;
727 m_nArgsLen = a_nReservedSlots;
728 m_nReservedSlots = a_nReservedSlots;
731 if (m_nReservedSlots > 0) {
732 if (!GrowArgvArray(m_nReservedSlots)) {
733 return SG_ERR_MEMORY;
735 for (
int n = 0; n < m_nReservedSlots; ++n) {
743 template <
class SOCHAR>
744 int CSimpleGlobTempl<SOCHAR>::Add(
745 const SOCHAR* a_pszFileSpec)
751 SOCHAR szFileSpec[MAX_PATH];
752 SimpleGlobUtil::strcpy_s(szFileSpec, MAX_PATH, a_pszFileSpec);
753 const SOCHAR* pszPath = SimpleGlobUtil::strchr(szFileSpec,
'/');
755 szFileSpec[pszPath - szFileSpec] = SG_PATH_CHAR;
756 pszPath = SimpleGlobUtil::strchr(pszPath + 1,
'/');
758 a_pszFileSpec = szFileSpec;
762 m_szPathPrefix[0] = 0;
763 if (!SimpleGlobUtil::strchr(a_pszFileSpec,
'*') && !SimpleGlobUtil::strchr(a_pszFileSpec,
'?')) {
764 SG_FileType nType = this->GetFileTypeS(a_pszFileSpec);
765 if (nType == SG_FILETYPE_INVALID) {
766 if (m_uiFlags & SG_GLOB_NOCHECK) {
767 return AppendName(a_pszFileSpec,
false);
769 return SG_ERR_NOMATCH;
771 return AppendName(a_pszFileSpec, nType == SG_FILETYPE_DIR);
778 const SOCHAR* pszFilename = SimpleGlobUtil::strrchr(a_pszFileSpec, SG_PATH_CHAR);
780 SimpleGlobUtil::strcpy_s(m_szPathPrefix, MAX_PATH, a_pszFileSpec);
781 m_szPathPrefix[pszFilename - a_pszFileSpec + 1] = 0;
786 int rc = this->FindFirstFileS(a_pszFileSpec, m_uiFlags);
787 if (rc != SG_SUCCESS) {
788 if (rc == SG_ERR_NOMATCH && (m_uiFlags & SG_GLOB_NOCHECK)) {
789 int ok = AppendName(a_pszFileSpec,
false);
790 if (ok != SG_SUCCESS)
797 int nError, nStartLen = m_nArgsLen;
800 nError = AppendName(this->GetFileNameS((SOCHAR)0), this->IsDirS((SOCHAR)0));
801 bSuccess = this->FindNextFileS((SOCHAR)0);
802 }
while (nError == SG_SUCCESS && bSuccess);
803 SimpleGlobBase<SOCHAR>::FindDone();
806 if (m_nArgsLen > nStartLen && !(m_uiFlags & SG_GLOB_NOSORT)) {
807 if (m_uiFlags & SG_GLOB_FULLSORT) {
808 nStartLen = m_nReservedSlots;
810 SetArgvArrayType(POINTERS);
812 m_rgpArgs + nStartLen,
813 m_nArgsLen - nStartLen,
814 sizeof(m_rgpArgs[0]), fileSortCompare);
820 template <
class SOCHAR>
821 int CSimpleGlobTempl<SOCHAR>::Add(
823 const SOCHAR*
const* a_rgpszFileSpec)
826 for (
int n = 0; n < a_nCount; ++n) {
827 nResult = Add(a_rgpszFileSpec[n]);
828 if (nResult != SG_SUCCESS) {
835 template <
class SOCHAR>
836 int CSimpleGlobTempl<SOCHAR>::AppendName(
837 const SOCHAR* a_pszFileName,
841 SetArgvArrayType(OFFSETS);
844 if ((m_uiFlags & SG_GLOB_ONLYDIR) && !a_bIsDir) {
847 if ((m_uiFlags & SG_GLOB_ONLYFILE) && a_bIsDir) {
850 if ((m_uiFlags & SG_GLOB_NODOT) && a_bIsDir) {
851 if (a_pszFileName[0] ==
'.') {
852 if (a_pszFileName[1] ==
'\0') {
855 if (a_pszFileName[1] ==
'.' && a_pszFileName[2] ==
'\0') {
862 if (!GrowArgvArray(m_nArgsLen + 1)) {
863 return SG_ERR_MEMORY;
867 size_t uiPrefixLen = SimpleGlobUtil::strlen(m_szPathPrefix);
868 size_t uiLen = uiPrefixLen + SimpleGlobUtil::strlen(a_pszFileName) + 1;
869 if (a_bIsDir && (m_uiFlags & SG_GLOB_MARK) == SG_GLOB_MARK) {
872 if (!GrowStringBuffer(m_uiBufferLen + uiLen)) {
873 return SG_ERR_MEMORY;
877 m_rgpArgs[m_nArgsLen++] = (SOCHAR*)m_uiBufferLen;
878 SimpleGlobUtil::strcpy_s(m_pBuffer + m_uiBufferLen,
879 m_uiBufferSize - m_uiBufferLen, m_szPathPrefix);
880 SimpleGlobUtil::strcpy_s(m_pBuffer + m_uiBufferLen + uiPrefixLen,
881 m_uiBufferSize - m_uiBufferLen - uiPrefixLen, a_pszFileName);
882 m_uiBufferLen += uiLen;
885 if (a_bIsDir && (m_uiFlags & SG_GLOB_MARK) == SG_GLOB_MARK) {
886 const static SOCHAR szDirSlash[] = { SG_PATH_CHAR, 0 };
887 SimpleGlobUtil::strcpy_s(m_pBuffer + m_uiBufferLen - 2,
888 m_uiBufferSize - (m_uiBufferLen - 2), szDirSlash);
894 template <
class SOCHAR>
895 void CSimpleGlobTempl<SOCHAR>::SetArgvArrayType(
896 ARG_ARRAY_TYPE a_nNewType)
898 if (m_nArgArrayType == a_nNewType)
900 if (a_nNewType == POINTERS) {
901 SG_ASSERT(m_nArgArrayType == OFFSETS);
902 for (
int n = 0; n < m_nArgsLen; ++n) {
903 m_rgpArgs[n] = (m_rgpArgs[n] == (SOCHAR*)-1) ? NULL : m_pBuffer + (size_t)m_rgpArgs[n];
906 SG_ASSERT(a_nNewType == OFFSETS);
907 SG_ASSERT(m_nArgArrayType == POINTERS);
908 for (
int n = 0; n < m_nArgsLen; ++n) {
909 m_rgpArgs[n] = (m_rgpArgs[n] == NULL) ? (SOCHAR*)-1 : (SOCHAR*)(m_rgpArgs[n] - m_pBuffer);
912 m_nArgArrayType = a_nNewType;
915 template <
class SOCHAR>
916 bool CSimpleGlobTempl<SOCHAR>::GrowArgvArray(
919 if (a_nNewLen >= m_nArgsSize) {
920 static const int SG_ARGV_INITIAL_SIZE = 32;
921 int nNewSize = (m_nArgsSize > 0) ? m_nArgsSize * 2 : SG_ARGV_INITIAL_SIZE;
922 while (a_nNewLen >= nNewSize) {
925 void* pNewBuffer = realloc(m_rgpArgs, nNewSize *
sizeof(SOCHAR*));
928 m_nArgsSize = nNewSize;
929 m_rgpArgs = (SOCHAR**)pNewBuffer;
934 template <
class SOCHAR>
935 bool CSimpleGlobTempl<SOCHAR>::GrowStringBuffer(
938 if (a_uiMinSize >= m_uiBufferSize) {
939 static const int SG_BUFFER_INITIAL_SIZE = 1024;
940 size_t uiNewSize = (m_uiBufferSize > 0) ? m_uiBufferSize * 2 : SG_BUFFER_INITIAL_SIZE;
941 while (a_uiMinSize >= uiNewSize) {
944 void* pNewBuffer = realloc(m_pBuffer, uiNewSize *
sizeof(SOCHAR));
947 m_uiBufferSize = uiNewSize;
948 m_pBuffer = (SOCHAR*)pNewBuffer;
953 template <
class SOCHAR>
954 int CSimpleGlobTempl<SOCHAR>::fileSortCompare(
958 const SOCHAR* s1 = *(
const SOCHAR**)a1;
959 const SOCHAR* s2 = *(
const SOCHAR**)a2;
961 return SimpleGlobUtil::strcasecmp(s1, s2);
964 return s1 == s2 ? 0 : (s1 ? 1 : -1);
972 typedef CSimpleGlobTempl<char> CSimpleGlobA;
975 typedef CSimpleGlobTempl<wchar_t> CSimpleGlobW;
979 typedef CSimpleGlobTempl<UChar> CSimpleGlobU;
985 #define CSimpleGlob CSimpleGlobU
987 #define CSimpleGlob CSimpleGlobW
991 #define CSimpleGlob CSimpleGlobA