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)
209 # define SG_ASSERT(b)
216 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) {
220 return ::wcschr(s, c);
223 static const UChar * strchr(
const UChar *s, UChar c) {
224 return ::u_strchr(s, c);
228 static const char * strrchr(
const char *s,
char c) {
229 return (
char *) sg_strrchr((
const SOCHAR_T *)s, c);
231 static const wchar_t * strrchr(
const wchar_t *s,
wchar_t c) {
232 return ::wcsrchr(s, c);
235 static const UChar * strrchr(
const UChar *s, UChar c) {
236 return ::u_strrchr(s, c);
241 static size_t strlen(
const char *s) { return ::strlen(s); }
242 static size_t strlen(
const wchar_t *s) { return ::wcslen(s); }
244 static size_t strlen(
const UChar *s) { return ::u_strlen(s); }
247 static void strcpy_s(
char *dst,
size_t n,
const char *src) {
249 sg_strcpy_s((SOCHAR_T *)dst, n, (
const SOCHAR_T *)src);
251 static void strcpy_s(
wchar_t *dst,
size_t n,
const wchar_t *src) {
252 # if __STDC_WANT_SECURE_LIB__
253 ::wcscpy_s(dst, n, src);
260 static void strcpy_s(UChar *dst,
size_t n,
const UChar *src) {
261 ::u_strncpy(dst, src, n);
265 static int strcmp(
const char *s1,
const char *s2) {
266 return sg_strcmp((
const SOCHAR_T *)s1, (
const SOCHAR_T *)s2);
268 static int strcmp(
const wchar_t *s1,
const wchar_t *s2) {
269 return ::wcscmp(s1, s2);
272 static int strcmp(
const UChar *s1,
const UChar *s2) {
273 return ::u_strcmp(s1, s2);
277 static int strcasecmp(
const char *s1,
const char *s2) {
278 return sg_strcasecmp((
const SOCHAR_T *)s1, (
const SOCHAR_T *)s2);
281 static int strcasecmp(
const wchar_t *s1,
const wchar_t *s2) {
282 return ::_wcsicmp(s1, s2);
286 static int strcasecmp(
const UChar *s1,
const UChar *s2) {
287 return u_strcasecmp(s1, s2, 0);
300 #ifndef INVALID_FILE_ATTRIBUTES
301 # define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
304 #define SG_PATH_CHAR '\\'
307 template<
class SOCHAR>
308 struct SimpleGlobBase
310 SimpleGlobBase() : m_hFind(INVALID_HANDLE_VALUE) { }
312 int FindFirstFileS(
const char * a_pszFileSpec,
unsigned int) {
313 m_hFind = FindFirstFileA(a_pszFileSpec, &m_oFindDataA);
314 if (m_hFind != INVALID_HANDLE_VALUE) {
317 DWORD dwErr = GetLastError();
318 if (dwErr == ERROR_FILE_NOT_FOUND) {
319 return SG_ERR_NOMATCH;
321 return SG_ERR_FAILURE;
323 int FindFirstFileS(
const wchar_t * a_pszFileSpec,
unsigned int) {
324 m_hFind = FindFirstFileW(a_pszFileSpec, &m_oFindDataW);
325 if (m_hFind != INVALID_HANDLE_VALUE) {
328 DWORD dwErr = GetLastError();
329 if (dwErr == ERROR_FILE_NOT_FOUND) {
330 return SG_ERR_NOMATCH;
332 return SG_ERR_FAILURE;
335 bool FindNextFileS(
char) {
336 return FindNextFileA(m_hFind, &m_oFindDataA) != FALSE;
338 bool FindNextFileS(
wchar_t) {
339 return FindNextFileW(m_hFind, &m_oFindDataW) != FALSE;
346 const char * GetFileNameS(
char)
const {
347 return m_oFindDataA.cFileName;
349 const wchar_t * GetFileNameS(
wchar_t)
const {
350 return m_oFindDataW.cFileName;
353 bool IsDirS(
char)
const {
354 return this->GetFileTypeS(m_oFindDataA.dwFileAttributes) == SG_FILETYPE_DIR;
356 bool IsDirS(
wchar_t)
const {
357 return this->GetFileTypeS(m_oFindDataW.dwFileAttributes) == SG_FILETYPE_DIR;
360 SG_FileType GetFileTypeS(
const char * a_pszPath) {
361 return this->GetFileTypeS(GetFileAttributesA(a_pszPath));
363 SG_FileType GetFileTypeS(
const wchar_t * a_pszPath) {
364 return this->GetFileTypeS(GetFileAttributesW(a_pszPath));
366 SG_FileType GetFileTypeS(DWORD a_dwAttribs)
const {
367 if (a_dwAttribs == INVALID_FILE_ATTRIBUTES) {
368 return SG_FILETYPE_INVALID;
370 if (a_dwAttribs & FILE_ATTRIBUTE_DIRECTORY) {
371 return SG_FILETYPE_DIR;
373 return SG_FILETYPE_FILE;
378 WIN32_FIND_DATAA m_oFindDataA;
379 WIN32_FIND_DATAW m_oFindDataW;
384 #define SG_PATH_CHAR '/'
387 template<
class SOCHAR>
388 struct SimpleGlobBase
391 memset(&m_glob, 0,
sizeof(m_glob));
392 m_uiCurr = (size_t)-1;
401 size_t len = strlen(m_glob.gl_pathv[m_uiCurr]);
402 if (m_glob.gl_pathv[m_uiCurr][len-1] ==
'/') {
404 m_glob.gl_pathv[m_uiCurr][len-1] = 0;
408 int FindFirstFileS(
const char * a_pszFileSpec,
unsigned int a_uiFlags) {
409 int nFlags = GLOB_MARK | GLOB_NOSORT;
410 if (a_uiFlags & SG_GLOB_ERR) nFlags |= GLOB_ERR;
411 if (a_uiFlags & SG_GLOB_TILDE) nFlags |= GLOB_TILDE;
412 int rc = glob(a_pszFileSpec, nFlags, NULL, &m_glob);
413 if (rc == GLOB_NOSPACE)
return SG_ERR_MEMORY;
414 if (rc == GLOB_ABORTED)
return SG_ERR_FAILURE;
415 if (rc == GLOB_NOMATCH)
return SG_ERR_NOMATCH;
422 int FindFirstFileS(
const UChar * a_pszFileSpec,
unsigned int a_uiFlags) {
423 char buf[PATH_MAX] = { 0 };
424 UErrorCode status = U_ZERO_ERROR;
425 u_strToUTF8(buf,
sizeof(buf), NULL, a_pszFileSpec, -1, &status);
426 if (U_FAILURE(status))
return SG_ERR_FAILURE;
427 return this->FindFirstFileS(buf, a_uiFlags);
431 bool FindNextFileS(
char) {
432 SG_ASSERT(m_uiCurr != (
size_t)-1);
433 if (++m_uiCurr >= m_glob.gl_pathc) {
441 bool FindNextFileS(UChar) {
442 return this->FindNextFileS((
char)0);
448 memset(&m_glob, 0,
sizeof(m_glob));
449 m_uiCurr = (size_t)-1;
452 const char * GetFileNameS(
char)
const {
453 SG_ASSERT(m_uiCurr != (
size_t)-1);
454 return m_glob.gl_pathv[m_uiCurr];
458 const UChar * GetFileNameS(UChar)
const {
459 const char * pszFile = this->GetFileNameS((
char)0);
460 if (!pszFile)
return NULL;
461 UErrorCode status = U_ZERO_ERROR;
462 memset(m_szBuf, 0,
sizeof(m_szBuf));
463 u_strFromUTF8(m_szBuf, PATH_MAX, NULL, pszFile, -1, &status);
464 if (U_FAILURE(status))
return NULL;
469 bool IsDirS(
char)
const {
470 SG_ASSERT(m_uiCurr != (
size_t)-1);
475 bool IsDirS(UChar)
const {
476 return this->IsDirS((
char)0);
480 SG_FileType GetFileTypeS(
const char * a_pszPath)
const {
482 if (0 != stat(a_pszPath, &sb)) {
483 return SG_FILETYPE_INVALID;
485 if (S_ISDIR(sb.st_mode)) {
486 return SG_FILETYPE_DIR;
488 if (S_ISREG(sb.st_mode)) {
489 return SG_FILETYPE_FILE;
491 return SG_FILETYPE_INVALID;
495 SG_FileType GetFileTypeS(
const UChar * a_pszPath)
const {
496 char buf[PATH_MAX] = { 0 };
497 UErrorCode status = U_ZERO_ERROR;
498 u_strToUTF8(buf,
sizeof(buf), NULL, a_pszPath, -1, &status);
499 if (U_FAILURE(status))
return SG_FILETYPE_INVALID;
500 return this->GetFileTypeS(buf);
509 mutable UChar m_szBuf[PATH_MAX];
522 template<
class SOCHAR>
551 int Init(
unsigned int a_uiFlags = 0,
int a_nReservedSlots = 0);
566 int Add(
const SOCHAR *a_pszFileSpec);
582 int Add(
int a_nCount,
const SOCHAR *
const * a_rgpszFileSpec);
590 SetArgvArrayType(POINTERS);
596 SG_ASSERT(n >= 0 && n < m_nArgsLen);
609 enum ARG_ARRAY_TYPE { OFFSETS, POINTERS };
612 void SetArgvArrayType(ARG_ARRAY_TYPE a_nNewType);
615 int AppendName(
const SOCHAR *a_pszFileName,
bool a_bIsDir);
618 bool GrowArgvArray(
int a_nNewLen);
621 bool GrowStringBuffer(
size_t a_uiMinSize);
624 static int fileSortCompare(
const void *a1,
const void *a2);
627 unsigned int m_uiFlags;
628 ARG_ARRAY_TYPE m_nArgArrayType;
630 int m_nReservedSlots;
634 size_t m_uiBufferSize;
635 size_t m_uiBufferLen;
636 SOCHAR m_szPathPrefix[MAX_PATH];
643 template<
class SOCHAR>
645 unsigned int a_uiFlags,
654 Init(a_uiFlags, a_nReservedSlots);
657 template<
class SOCHAR>
660 if (m_rgpArgs) free(m_rgpArgs);
661 if (m_pBuffer) free(m_pBuffer);
664 template<
class SOCHAR>
667 unsigned int a_uiFlags,
671 m_nArgArrayType = POINTERS;
672 m_uiFlags = a_uiFlags;
673 m_nArgsLen = a_nReservedSlots;
674 m_nReservedSlots = a_nReservedSlots;
677 if (m_nReservedSlots > 0) {
678 if (!GrowArgvArray(m_nReservedSlots)) {
679 return SG_ERR_MEMORY;
681 for (
int n = 0; n < m_nReservedSlots; ++n) {
689 template<
class SOCHAR>
692 const SOCHAR *a_pszFileSpec
699 SOCHAR szFileSpec[MAX_PATH];
700 SimpleGlobUtil::strcpy_s(szFileSpec, MAX_PATH, a_pszFileSpec);
701 const SOCHAR * pszPath = SimpleGlobUtil::strchr(szFileSpec,
'/');
703 szFileSpec[pszPath - szFileSpec] = SG_PATH_CHAR;
704 pszPath = SimpleGlobUtil::strchr(pszPath + 1,
'/');
706 a_pszFileSpec = szFileSpec;
710 m_szPathPrefix[0] = 0;
711 if (!SimpleGlobUtil::strchr(a_pszFileSpec,
'*') &&
712 !SimpleGlobUtil::strchr(a_pszFileSpec,
'?'))
714 SG_FileType nType = this->GetFileTypeS(a_pszFileSpec);
715 if (nType == SG_FILETYPE_INVALID) {
716 if (m_uiFlags & SG_GLOB_NOCHECK) {
717 return AppendName(a_pszFileSpec,
false);
719 return SG_ERR_NOMATCH;
721 return AppendName(a_pszFileSpec, nType == SG_FILETYPE_DIR);
728 const SOCHAR * pszFilename =
729 SimpleGlobUtil::strrchr(a_pszFileSpec, SG_PATH_CHAR);
731 SimpleGlobUtil::strcpy_s(m_szPathPrefix, MAX_PATH, a_pszFileSpec);
732 m_szPathPrefix[pszFilename - a_pszFileSpec + 1] = 0;
737 int rc = this->FindFirstFileS(a_pszFileSpec, m_uiFlags);
738 if (rc != SG_SUCCESS) {
739 if (rc == SG_ERR_NOMATCH && (m_uiFlags & SG_GLOB_NOCHECK)) {
740 int ok = AppendName(a_pszFileSpec,
false);
741 if (ok != SG_SUCCESS) rc = ok;
747 int nError, nStartLen = m_nArgsLen;
750 nError = AppendName(this->GetFileNameS((SOCHAR)0), this->IsDirS((SOCHAR)0));
751 bSuccess = this->FindNextFileS((SOCHAR)0);
753 while (nError == SG_SUCCESS && bSuccess);
754 SimpleGlobBase<SOCHAR>::FindDone();
757 if (m_nArgsLen > nStartLen && !(m_uiFlags & SG_GLOB_NOSORT)) {
758 if (m_uiFlags & SG_GLOB_FULLSORT) {
759 nStartLen = m_nReservedSlots;
761 SetArgvArrayType(POINTERS);
763 m_rgpArgs + nStartLen,
764 m_nArgsLen - nStartLen,
765 sizeof(m_rgpArgs[0]), fileSortCompare);
771 template<
class SOCHAR>
775 const SOCHAR *
const * a_rgpszFileSpec
779 for (
int n = 0; n < a_nCount; ++n) {
780 nResult = Add(a_rgpszFileSpec[n]);
781 if (nResult != SG_SUCCESS) {
788 template<
class SOCHAR>
791 const SOCHAR * a_pszFileName,
796 SetArgvArrayType(OFFSETS);
799 if ((m_uiFlags & SG_GLOB_ONLYDIR) && !a_bIsDir) {
802 if ((m_uiFlags & SG_GLOB_ONLYFILE) && a_bIsDir) {
805 if ((m_uiFlags & SG_GLOB_NODOT) && a_bIsDir) {
806 if (a_pszFileName[0] ==
'.') {
807 if (a_pszFileName[1] ==
'\0') {
810 if (a_pszFileName[1] ==
'.' && a_pszFileName[2] ==
'\0') {
817 if (!GrowArgvArray(m_nArgsLen + 1)) {
818 return SG_ERR_MEMORY;
822 size_t uiPrefixLen = SimpleGlobUtil::strlen(m_szPathPrefix);
823 size_t uiLen = uiPrefixLen + SimpleGlobUtil::strlen(a_pszFileName) + 1;
824 if (a_bIsDir && (m_uiFlags & SG_GLOB_MARK) == SG_GLOB_MARK) {
827 if (!GrowStringBuffer(m_uiBufferLen + uiLen)) {
828 return SG_ERR_MEMORY;
832 m_rgpArgs[m_nArgsLen++] = (SOCHAR*)m_uiBufferLen;
833 SimpleGlobUtil::strcpy_s(m_pBuffer + m_uiBufferLen,
834 m_uiBufferSize - m_uiBufferLen, m_szPathPrefix);
835 SimpleGlobUtil::strcpy_s(m_pBuffer + m_uiBufferLen + uiPrefixLen,
836 m_uiBufferSize - m_uiBufferLen - uiPrefixLen, a_pszFileName);
837 m_uiBufferLen += uiLen;
840 if (a_bIsDir && (m_uiFlags & SG_GLOB_MARK) == SG_GLOB_MARK) {
841 const static SOCHAR szDirSlash[] = { SG_PATH_CHAR, 0 };
842 SimpleGlobUtil::strcpy_s(m_pBuffer + m_uiBufferLen - 2,
843 m_uiBufferSize - (m_uiBufferLen - 2), szDirSlash);
849 template<
class SOCHAR>
852 ARG_ARRAY_TYPE a_nNewType
855 if (m_nArgArrayType == a_nNewType)
return;
856 if (a_nNewType == POINTERS) {
857 SG_ASSERT(m_nArgArrayType == OFFSETS);
858 for (
int n = 0; n < m_nArgsLen; ++n) {
859 m_rgpArgs[n] = (m_rgpArgs[n] == (SOCHAR*)-1) ?
860 NULL : m_pBuffer + (size_t) m_rgpArgs[n];
864 SG_ASSERT(a_nNewType == OFFSETS);
865 SG_ASSERT(m_nArgArrayType == POINTERS);
866 for (
int n = 0; n < m_nArgsLen; ++n) {
867 m_rgpArgs[n] = (m_rgpArgs[n] == NULL) ?
868 (SOCHAR*) -1 : (SOCHAR*) (m_rgpArgs[n] - m_pBuffer);
871 m_nArgArrayType = a_nNewType;
874 template<
class SOCHAR>
880 if (a_nNewLen >= m_nArgsSize) {
881 static const int SG_ARGV_INITIAL_SIZE = 32;
882 int nNewSize = (m_nArgsSize > 0) ?
883 m_nArgsSize * 2 : SG_ARGV_INITIAL_SIZE;
884 while (a_nNewLen >= nNewSize) {
887 void * pNewBuffer = realloc(m_rgpArgs, nNewSize *
sizeof(SOCHAR*));
888 if (!pNewBuffer)
return false;
889 m_nArgsSize = nNewSize;
890 m_rgpArgs = (SOCHAR**) pNewBuffer;
895 template<
class SOCHAR>
901 if (a_uiMinSize >= m_uiBufferSize) {
902 static const int SG_BUFFER_INITIAL_SIZE = 1024;
903 size_t uiNewSize = (m_uiBufferSize > 0) ?
904 m_uiBufferSize * 2 : SG_BUFFER_INITIAL_SIZE;
905 while (a_uiMinSize >= uiNewSize) {
908 void * pNewBuffer = realloc(m_pBuffer, uiNewSize *
sizeof(SOCHAR));
909 if (!pNewBuffer)
return false;
910 m_uiBufferSize = uiNewSize;
911 m_pBuffer = (SOCHAR*) pNewBuffer;
916 template<
class SOCHAR>
923 const SOCHAR * s1 = *(
const SOCHAR **)a1;
924 const SOCHAR * s2 = *(
const SOCHAR **)a2;
926 return SimpleGlobUtil::strcasecmp(s1, s2);
929 return s1 == s2 ? 0 : (s1 ? 1 : -1);
950 # define CSimpleGlob CSimpleGlobU
952 # define CSimpleGlob CSimpleGlobW
956 # define CSimpleGlob CSimpleGlobA
959 #endif // INCLUDED_SimpleGlob