00001
00085 #ifndef INCLUDED_SimpleGlob
00086 #define INCLUDED_SimpleGlob
00087
00131 enum SG_Flags {
00132 SG_GLOB_ERR = 1 << 0,
00133 SG_GLOB_MARK = 1 << 1,
00134 SG_GLOB_NOSORT = 1 << 2,
00135 SG_GLOB_NOCHECK = 1 << 3,
00136 SG_GLOB_TILDE = 1 << 4,
00137 SG_GLOB_ONLYDIR = 1 << 5,
00138 SG_GLOB_ONLYFILE = 1 << 6,
00139 SG_GLOB_NODOT = 1 << 7,
00140 SG_GLOB_FULLSORT = 1 << 8
00141 };
00142
00144 enum SG_Error {
00145 SG_SUCCESS = 0,
00146 SG_ERR_NOMATCH = 1,
00147 SG_ERR_MEMORY = -1,
00148 SG_ERR_FAILURE = -2
00149 };
00150
00151
00152
00153
00154
00155 #ifndef DOXYGEN
00156
00157
00158
00159 #ifdef _WIN32
00160 # include <mbstring.h>
00161 # define sg_strchr ::_mbschr
00162 # define sg_strrchr ::_mbsrchr
00163 # define sg_strlen ::_mbslen
00164 # if __STDC_WANT_SECURE_LIB__
00165 # define sg_strcpy_s(a,n,b) ::_mbscpy_s(a,n,b)
00166 # else
00167 # define sg_strcpy_s(a,n,b) ::_mbscpy(a,b)
00168 # endif
00169 # define sg_strcmp ::_mbscmp
00170 # define sg_strcasecmp ::_mbsicmp
00171 # define SOCHAR_T unsigned char
00172 #else
00173 # include <sys/types.h>
00174 # include <sys/stat.h>
00175 # include <glob.h>
00176 # include <limits.h>
00177 # define MAX_PATH PATH_MAX
00178 # define sg_strchr ::strchr
00179 # define sg_strrchr ::strrchr
00180 # define sg_strlen ::strlen
00181 # define sg_strcpy_s(a,n,b) ::strcpy(a,b)
00182 # define sg_strcmp ::strcmp
00183 # define sg_strcasecmp ::strcasecmp
00184 # define SOCHAR_T char
00185 #endif
00186
00187 #include <stdlib.h>
00188 #include <string.h>
00189 #include <wchar.h>
00190
00191
00192 #ifdef _DEBUG
00193 # ifdef _MSC_VER
00194 # include <crtdbg.h>
00195 # define SG_ASSERT(b) _ASSERTE(b)
00196 # else
00197 # include <assert.h>
00198 # define SG_ASSERT(b) assert(b)
00199 # endif
00200 #else
00201 # define SG_ASSERT(b)
00202 #endif
00203
00205 class SimpleGlobUtil
00206 {
00207 public:
00208 static const char * strchr(const char *s, char c) {
00209 return (char *) sg_strchr((const SOCHAR_T *)s, c);
00210 }
00211 static const wchar_t * strchr(const wchar_t *s, wchar_t c) {
00212 return ::wcschr(s, c);
00213 }
00214
00215 static const char * strrchr(const char *s, char c) {
00216 return (char *) sg_strrchr((const SOCHAR_T *)s, c);
00217 }
00218 static const wchar_t * strrchr(const wchar_t *s, wchar_t c) {
00219 return ::wcsrchr(s, c);
00220 }
00221
00222
00223 static size_t strlen(const char *s) { return ::strlen(s); }
00224 static size_t strlen(const wchar_t *s) { return ::wcslen(s); }
00225
00226 static void strcpy_s(char *dst, size_t n, const char *src) {
00227 (void) n;
00228 sg_strcpy_s((SOCHAR_T *)dst, n, (const SOCHAR_T *)src);
00229 }
00230 static void strcpy_s(wchar_t *dst, size_t n, const wchar_t *src) {
00231 # if __STDC_WANT_SECURE_LIB__
00232 ::wcscpy_s(dst, n, src);
00233 #else
00234 (void) n;
00235 ::wcscpy(dst, src);
00236 #endif
00237 }
00238
00239 static int strcmp(const char *s1, const char *s2) {
00240 return sg_strcmp((const SOCHAR_T *)s1, (const SOCHAR_T *)s2);
00241 }
00242 static int strcmp(const wchar_t *s1, const wchar_t *s2) {
00243 return ::wcscmp(s1, s2);
00244 }
00245
00246 static int strcasecmp(const char *s1, const char *s2) {
00247 return sg_strcasecmp((const SOCHAR_T *)s1, (const SOCHAR_T *)s2);
00248 }
00249 #if _WIN32
00250 static int strcasecmp(const wchar_t *s1, const wchar_t *s2) {
00251 return ::_wcsicmp(s1, s2);
00252 }
00253 #endif // _WIN32
00254 };
00255
00256 enum SG_FileType {
00257 SG_FILETYPE_INVALID,
00258 SG_FILETYPE_FILE,
00259 SG_FILETYPE_DIR
00260 };
00261
00262 #ifdef _WIN32
00263
00264 #ifndef INVALID_FILE_ATTRIBUTES
00265 # define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
00266 #endif
00267
00268 #define SG_PATH_CHAR '\\'
00269
00271 template<class SOCHAR>
00272 struct SimpleGlobBase
00273 {
00274 SimpleGlobBase() : m_hFind(INVALID_HANDLE_VALUE) { }
00275
00276 int FindFirstFileS(const char * a_pszFileSpec, unsigned int) {
00277 m_hFind = FindFirstFileA(a_pszFileSpec, &m_oFindDataA);
00278 if (m_hFind != INVALID_HANDLE_VALUE) {
00279 return SG_SUCCESS;
00280 }
00281 DWORD dwErr = GetLastError();
00282 if (dwErr == ERROR_FILE_NOT_FOUND) {
00283 return SG_ERR_NOMATCH;
00284 }
00285 return SG_ERR_FAILURE;
00286 }
00287 int FindFirstFileS(const wchar_t * a_pszFileSpec, unsigned int) {
00288 m_hFind = FindFirstFileW(a_pszFileSpec, &m_oFindDataW);
00289 if (m_hFind != INVALID_HANDLE_VALUE) {
00290 return SG_SUCCESS;
00291 }
00292 DWORD dwErr = GetLastError();
00293 if (dwErr == ERROR_FILE_NOT_FOUND) {
00294 return SG_ERR_NOMATCH;
00295 }
00296 return SG_ERR_FAILURE;
00297 }
00298
00299 bool FindNextFileS(char) {
00300 return FindNextFileA(m_hFind, &m_oFindDataA) != FALSE;
00301 }
00302 bool FindNextFileS(wchar_t) {
00303 return FindNextFileW(m_hFind, &m_oFindDataW) != FALSE;
00304 }
00305
00306 void FindDone() {
00307 FindClose(m_hFind);
00308 }
00309
00310 const char * GetFileNameS(char) const {
00311 return m_oFindDataA.cFileName;
00312 }
00313 const wchar_t * GetFileNameS(wchar_t) const {
00314 return m_oFindDataW.cFileName;
00315 }
00316
00317 bool IsDirS(char) const {
00318 return GetFileTypeS(m_oFindDataA.dwFileAttributes) == SG_FILETYPE_DIR;
00319 }
00320 bool IsDirS(wchar_t) const {
00321 return GetFileTypeS(m_oFindDataW.dwFileAttributes) == SG_FILETYPE_DIR;
00322 }
00323
00324 SG_FileType GetFileTypeS(const char * a_pszPath) {
00325 return GetFileTypeS(GetFileAttributesA(a_pszPath));
00326 }
00327 SG_FileType GetFileTypeS(const wchar_t * a_pszPath) {
00328 return GetFileTypeS(GetFileAttributesW(a_pszPath));
00329 }
00330 SG_FileType GetFileTypeS(DWORD a_dwAttribs) const {
00331 if (a_dwAttribs == INVALID_FILE_ATTRIBUTES) {
00332 return SG_FILETYPE_INVALID;
00333 }
00334 if (a_dwAttribs & FILE_ATTRIBUTE_DIRECTORY) {
00335 return SG_FILETYPE_DIR;
00336 }
00337 return SG_FILETYPE_FILE;
00338 }
00339
00340 private:
00341 HANDLE m_hFind;
00342 WIN32_FIND_DATAA m_oFindDataA;
00343 WIN32_FIND_DATAW m_oFindDataW;
00344 };
00345
00346 #else // !_WIN32
00347
00348 #define SG_PATH_CHAR '/'
00349
00351 template<class SOCHAR>
00352 struct SimpleGlobBase
00353 {
00354 SimpleGlobBase() {
00355 memset(&m_glob, 0, sizeof(m_glob));
00356 m_uiCurr = (size_t)-1;
00357 }
00358
00359 ~SimpleGlobBase() {
00360 globfree(&m_glob);
00361 }
00362
00363 void FilePrep() {
00364 m_bIsDir = false;
00365 size_t len = strlen(m_glob.gl_pathv[m_uiCurr]);
00366 if (m_glob.gl_pathv[m_uiCurr][len-1] == '/') {
00367 m_bIsDir = true;
00368 m_glob.gl_pathv[m_uiCurr][len-1] = 0;
00369 }
00370 }
00371
00372 int FindFirstFileS(const char * a_pszFileSpec, unsigned int a_uiFlags) {
00373 int nFlags = GLOB_MARK | GLOB_NOSORT;
00374 if (a_uiFlags & SG_GLOB_ERR) nFlags |= GLOB_ERR;
00375 if (a_uiFlags & SG_GLOB_TILDE) nFlags |= GLOB_TILDE;
00376 int rc = glob(a_pszFileSpec, nFlags, NULL, &m_glob);
00377 if (rc == GLOB_NOSPACE) return SG_ERR_MEMORY;
00378 if (rc == GLOB_ABORTED) return SG_ERR_FAILURE;
00379 if (rc == GLOB_NOMATCH) return SG_ERR_NOMATCH;
00380 m_uiCurr = 0;
00381 FilePrep();
00382 return SG_SUCCESS;
00383 }
00384
00385 bool FindNextFileS(char) {
00386 SG_ASSERT(m_uiCurr != (size_t)-1);
00387 if (++m_uiCurr >= m_glob.gl_pathc) {
00388 return false;
00389 }
00390 FilePrep();
00391 return true;
00392 }
00393
00394 void FindDone() {
00395 globfree(&m_glob);
00396 memset(&m_glob, 0, sizeof(m_glob));
00397 m_uiCurr = (size_t)-1;
00398 }
00399
00400 const char * GetFileNameS(char) const {
00401 SG_ASSERT(m_uiCurr != (size_t)-1);
00402 return m_glob.gl_pathv[m_uiCurr];
00403 }
00404
00405 bool IsDirS(char) const {
00406 SG_ASSERT(m_uiCurr != (size_t)-1);
00407 return m_bIsDir;
00408 }
00409
00410 SG_FileType GetFileTypeS(const char * a_pszPath) const {
00411 struct stat sb;
00412 if (0 != stat(a_pszPath, &sb)) {
00413 return SG_FILETYPE_INVALID;
00414 }
00415 if (S_ISDIR(sb.st_mode)) {
00416 return SG_FILETYPE_DIR;
00417 }
00418 if (S_ISREG(sb.st_mode)) {
00419 return SG_FILETYPE_FILE;
00420 }
00421 return SG_FILETYPE_INVALID;
00422 }
00423
00424 private:
00425 glob_t m_glob;
00426 size_t m_uiCurr;
00427 bool m_bIsDir;
00428 };
00429
00430 #endif // _WIN32
00431
00432 #endif // DOXYGEN
00433
00434
00435
00436
00437
00439 template<class SOCHAR>
00440 class CSimpleGlobTempl : private SimpleGlobBase<SOCHAR>
00441 {
00442 public:
00451 CSimpleGlobTempl(unsigned int a_uiFlags = 0, int a_nReservedSlots = 0);
00452
00454 ~CSimpleGlobTempl();
00455
00468 int Init(unsigned int a_uiFlags = 0, int a_nReservedSlots = 0);
00469
00483 int Add(const SOCHAR *a_pszFileSpec);
00484
00499 int Add(int a_nCount, const SOCHAR * const * a_rgpszFileSpec);
00500
00503 inline int FileCount() const { return m_nArgsLen; }
00504
00506 inline SOCHAR ** Files() {
00507 SetArgvArrayType(POINTERS);
00508 return m_rgpArgs;
00509 }
00510
00512 inline SOCHAR * File(int n) {
00513 SG_ASSERT(n >= 0 && n < m_nArgsLen);
00514 return Files()[n];
00515 }
00516
00517 private:
00523 enum ARG_ARRAY_TYPE { OFFSETS, POINTERS };
00524
00526 void SetArgvArrayType(ARG_ARRAY_TYPE a_nNewType);
00527
00529 int AppendName(const SOCHAR *a_pszFileName, bool a_bIsDir);
00530
00532 bool GrowArgvArray(int a_nNewLen);
00533
00535 bool GrowStringBuffer(size_t a_uiMinSize);
00536
00538 static int fileSortCompare(const void *a1, const void *a2);
00539
00540 private:
00541 unsigned int m_uiFlags;
00542 ARG_ARRAY_TYPE m_nArgArrayType;
00543 SOCHAR ** m_rgpArgs;
00544 int m_nReservedSlots;
00545 int m_nArgsSize;
00546 int m_nArgsLen;
00547 SOCHAR * m_pBuffer;
00548 size_t m_uiBufferSize;
00549 size_t m_uiBufferLen;
00550 SOCHAR m_szPathPrefix[MAX_PATH];
00551 };
00552
00553
00554
00555
00556
00557 template<class SOCHAR>
00558 CSimpleGlobTempl<SOCHAR>::CSimpleGlobTempl(
00559 unsigned int a_uiFlags,
00560 int a_nReservedSlots
00561 )
00562 {
00563 m_rgpArgs = NULL;
00564 m_nArgsSize = 0;
00565 m_pBuffer = NULL;
00566 m_uiBufferSize = 0;
00567
00568 Init(a_uiFlags, a_nReservedSlots);
00569 }
00570
00571 template<class SOCHAR>
00572 CSimpleGlobTempl<SOCHAR>::~CSimpleGlobTempl()
00573 {
00574 if (m_rgpArgs) free(m_rgpArgs);
00575 if (m_pBuffer) free(m_pBuffer);
00576 }
00577
00578 template<class SOCHAR>
00579 int
00580 CSimpleGlobTempl<SOCHAR>::Init(
00581 unsigned int a_uiFlags,
00582 int a_nReservedSlots
00583 )
00584 {
00585 m_nArgArrayType = POINTERS;
00586 m_uiFlags = a_uiFlags;
00587 m_nArgsLen = a_nReservedSlots;
00588 m_nReservedSlots = a_nReservedSlots;
00589 m_uiBufferLen = 0;
00590
00591 if (m_nReservedSlots > 0) {
00592 if (!GrowArgvArray(m_nReservedSlots)) {
00593 return SG_ERR_MEMORY;
00594 }
00595 for (int n = 0; n < m_nReservedSlots; ++n) {
00596 m_rgpArgs[n] = NULL;
00597 }
00598 }
00599
00600 return SG_SUCCESS;
00601 }
00602
00603 template<class SOCHAR>
00604 int
00605 CSimpleGlobTempl<SOCHAR>::Add(
00606 const SOCHAR *a_pszFileSpec
00607 )
00608 {
00609 #ifdef _WIN32
00610
00611
00612
00613 SOCHAR szFileSpec[MAX_PATH];
00614 SimpleGlobUtil::strcpy_s(szFileSpec, MAX_PATH, a_pszFileSpec);
00615 const SOCHAR * pszPath = SimpleGlobUtil::strchr(szFileSpec, '/');
00616 while (pszPath) {
00617 szFileSpec[pszPath - szFileSpec] = SG_PATH_CHAR;
00618 pszPath = SimpleGlobUtil::strchr(pszPath + 1, '/');
00619 }
00620 a_pszFileSpec = szFileSpec;
00621 #endif
00622
00623
00624 m_szPathPrefix[0] = 0;
00625 if (!SimpleGlobUtil::strchr(a_pszFileSpec, '*') &&
00626 !SimpleGlobUtil::strchr(a_pszFileSpec, '?'))
00627 {
00628 SG_FileType nType = GetFileTypeS(a_pszFileSpec);
00629 if (nType == SG_FILETYPE_INVALID) {
00630 if (m_uiFlags & SG_GLOB_NOCHECK) {
00631 return AppendName(a_pszFileSpec, false);
00632 }
00633 return SG_ERR_NOMATCH;
00634 }
00635 return AppendName(a_pszFileSpec, nType == SG_FILETYPE_DIR);
00636 }
00637
00638 #ifdef _WIN32
00639
00640
00641
00642 const SOCHAR * pszFilename =
00643 SimpleGlobUtil::strrchr(a_pszFileSpec, SG_PATH_CHAR);
00644 if (pszFilename) {
00645 SimpleGlobUtil::strcpy_s(m_szPathPrefix, MAX_PATH, a_pszFileSpec);
00646 m_szPathPrefix[pszFilename - a_pszFileSpec + 1] = 0;
00647 }
00648 #endif
00649
00650
00651 int rc = FindFirstFileS(a_pszFileSpec, m_uiFlags);
00652 if (rc != SG_SUCCESS) {
00653 if (rc == SG_ERR_NOMATCH && (m_uiFlags & SG_GLOB_NOCHECK)) {
00654 int ok = AppendName(a_pszFileSpec, false);
00655 if (ok != SG_SUCCESS) rc = ok;
00656 }
00657 return rc;
00658 }
00659
00660
00661 int nError, nStartLen = m_nArgsLen;
00662 bool bSuccess;
00663 do {
00664 nError = AppendName(GetFileNameS((SOCHAR)0), IsDirS((SOCHAR)0));
00665 bSuccess = FindNextFileS((SOCHAR)0);
00666 }
00667 while (nError == SG_SUCCESS && bSuccess);
00668 SimpleGlobBase<SOCHAR>::FindDone();
00669
00670
00671 if (m_nArgsLen > nStartLen && !(m_uiFlags & SG_GLOB_NOSORT)) {
00672 if (m_uiFlags & SG_GLOB_FULLSORT) {
00673 nStartLen = m_nReservedSlots;
00674 }
00675 SetArgvArrayType(POINTERS);
00676 qsort(
00677 m_rgpArgs + nStartLen,
00678 m_nArgsLen - nStartLen,
00679 sizeof(m_rgpArgs[0]), fileSortCompare);
00680 }
00681
00682 return nError;
00683 }
00684
00685 template<class SOCHAR>
00686 int
00687 CSimpleGlobTempl<SOCHAR>::Add(
00688 int a_nCount,
00689 const SOCHAR * const * a_rgpszFileSpec
00690 )
00691 {
00692 int nResult;
00693 for (int n = 0; n < a_nCount; ++n) {
00694 nResult = Add(a_rgpszFileSpec[n]);
00695 if (nResult != SG_SUCCESS) {
00696 return nResult;
00697 }
00698 }
00699 return SG_SUCCESS;
00700 }
00701
00702 template<class SOCHAR>
00703 int
00704 CSimpleGlobTempl<SOCHAR>::AppendName(
00705 const SOCHAR * a_pszFileName,
00706 bool a_bIsDir
00707 )
00708 {
00709
00710 SetArgvArrayType(OFFSETS);
00711
00712
00713 if ((m_uiFlags & SG_GLOB_ONLYDIR) && !a_bIsDir) {
00714 return SG_SUCCESS;
00715 }
00716 if ((m_uiFlags & SG_GLOB_ONLYFILE) && a_bIsDir) {
00717 return SG_SUCCESS;
00718 }
00719 if ((m_uiFlags & SG_GLOB_NODOT) && a_bIsDir) {
00720 if (a_pszFileName[0] == '.') {
00721 if (a_pszFileName[1] == '\0') {
00722 return SG_SUCCESS;
00723 }
00724 if (a_pszFileName[1] == '.' && a_pszFileName[2] == '\0') {
00725 return SG_SUCCESS;
00726 }
00727 }
00728 }
00729
00730
00731 if (!GrowArgvArray(m_nArgsLen + 1)) {
00732 return SG_ERR_MEMORY;
00733 }
00734
00735
00736 size_t uiPrefixLen = SimpleGlobUtil::strlen(m_szPathPrefix);
00737 size_t uiLen = uiPrefixLen + SimpleGlobUtil::strlen(a_pszFileName) + 1;
00738 if (a_bIsDir && (m_uiFlags & SG_GLOB_MARK) == SG_GLOB_MARK) {
00739 ++uiLen;
00740 }
00741 if (!GrowStringBuffer(m_uiBufferLen + uiLen)) {
00742 return SG_ERR_MEMORY;
00743 }
00744
00745
00746 m_rgpArgs[m_nArgsLen++] = (SOCHAR*)m_uiBufferLen;
00747 SimpleGlobUtil::strcpy_s(m_pBuffer + m_uiBufferLen,
00748 m_uiBufferSize - m_uiBufferLen, m_szPathPrefix);
00749 SimpleGlobUtil::strcpy_s(m_pBuffer + m_uiBufferLen + uiPrefixLen,
00750 m_uiBufferSize - m_uiBufferLen - uiPrefixLen, a_pszFileName);
00751 m_uiBufferLen += uiLen;
00752
00753
00754 if (a_bIsDir && (m_uiFlags & SG_GLOB_MARK) == SG_GLOB_MARK) {
00755 const static SOCHAR szDirSlash[] = { SG_PATH_CHAR, 0 };
00756 SimpleGlobUtil::strcpy_s(m_pBuffer + m_uiBufferLen - 2,
00757 m_uiBufferSize - (m_uiBufferLen - 2), szDirSlash);
00758 }
00759
00760 return SG_SUCCESS;
00761 }
00762
00763 template<class SOCHAR>
00764 void
00765 CSimpleGlobTempl<SOCHAR>::SetArgvArrayType(
00766 ARG_ARRAY_TYPE a_nNewType
00767 )
00768 {
00769 if (m_nArgArrayType == a_nNewType) return;
00770 if (a_nNewType == POINTERS) {
00771 SG_ASSERT(m_nArgArrayType == OFFSETS);
00772 for (int n = 0; n < m_nArgsLen; ++n) {
00773 m_rgpArgs[n] = (m_rgpArgs[n] == (SOCHAR*)-1) ?
00774 NULL : m_pBuffer + (size_t) m_rgpArgs[n];
00775 }
00776 }
00777 else {
00778 SG_ASSERT(a_nNewType == OFFSETS);
00779 SG_ASSERT(m_nArgArrayType == POINTERS);
00780 for (int n = 0; n < m_nArgsLen; ++n) {
00781 m_rgpArgs[n] = (m_rgpArgs[n] == NULL) ?
00782 (SOCHAR*) -1 : (SOCHAR*) (m_rgpArgs[n] - m_pBuffer);
00783 }
00784 }
00785 m_nArgArrayType = a_nNewType;
00786 }
00787
00788 template<class SOCHAR>
00789 bool
00790 CSimpleGlobTempl<SOCHAR>::GrowArgvArray(
00791 int a_nNewLen
00792 )
00793 {
00794 if (a_nNewLen >= m_nArgsSize) {
00795 static const int SG_ARGV_INITIAL_SIZE = 32;
00796 int nNewSize = (m_nArgsSize > 0) ?
00797 m_nArgsSize * 2 : SG_ARGV_INITIAL_SIZE;
00798 while (a_nNewLen >= nNewSize) {
00799 nNewSize *= 2;
00800 }
00801 void * pNewBuffer = realloc(m_rgpArgs, nNewSize * sizeof(SOCHAR*));
00802 if (!pNewBuffer) return false;
00803 m_nArgsSize = nNewSize;
00804 m_rgpArgs = (SOCHAR**) pNewBuffer;
00805 }
00806 return true;
00807 }
00808
00809 template<class SOCHAR>
00810 bool
00811 CSimpleGlobTempl<SOCHAR>::GrowStringBuffer(
00812 size_t a_uiMinSize
00813 )
00814 {
00815 if (a_uiMinSize >= m_uiBufferSize) {
00816 static const int SG_BUFFER_INITIAL_SIZE = 1024;
00817 size_t uiNewSize = (m_uiBufferSize > 0) ?
00818 m_uiBufferSize * 2 : SG_BUFFER_INITIAL_SIZE;
00819 while (a_uiMinSize >= uiNewSize) {
00820 uiNewSize *= 2;
00821 }
00822 void * pNewBuffer = realloc(m_pBuffer, uiNewSize * sizeof(SOCHAR));
00823 if (!pNewBuffer) return false;
00824 m_uiBufferSize = uiNewSize;
00825 m_pBuffer = (SOCHAR*) pNewBuffer;
00826 }
00827 return true;
00828 }
00829
00830 template<class SOCHAR>
00831 int
00832 CSimpleGlobTempl<SOCHAR>::fileSortCompare(
00833 const void *a1,
00834 const void *a2
00835 )
00836 {
00837 const SOCHAR * s1 = *(const SOCHAR **)a1;
00838 const SOCHAR * s2 = *(const SOCHAR **)a2;
00839 if (s1 && s2) {
00840 return SimpleGlobUtil::strcasecmp(s1, s2);
00841 }
00842
00843 return s1 == s2 ? 0 : (s1 ? 1 : -1);
00844 }
00845
00846
00847
00848
00849
00851 typedef CSimpleGlobTempl<char> CSimpleGlobA;
00852
00854 typedef CSimpleGlobTempl<wchar_t> CSimpleGlobW;
00855
00856 #if defined(_UNICODE)
00857
00858 # define CSimpleGlob CSimpleGlobW
00859 #else
00860
00861 # define CSimpleGlob CSimpleGlobA
00862 #endif
00863
00864 #endif // INCLUDED_SimpleGlob