|
SimpleOpt
|
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 // Platform dependent implementations 00153 00154 // if we aren't on Windows and we have ICU available, then enable ICU 00155 // by default. Define this to 0 to intentially disable it. 00156 #ifndef SG_HAVE_ICU 00157 # if !defined(_WIN32) && defined(USTRING_H) 00158 # define SG_HAVE_ICU 1 00159 # else 00160 # define SG_HAVE_ICU 0 00161 # endif 00162 #endif 00163 00164 // don't include this in documentation as it isn't relevant 00165 #ifndef DOXYGEN 00166 00167 // on Windows we want to use MBCS aware string functions and mimic the 00168 // Unix glob functionality. On Unix we just use glob. 00169 #ifdef _WIN32 00170 # include <mbstring.h> 00171 # define sg_strchr ::_mbschr 00172 # define sg_strrchr ::_mbsrchr 00173 # define sg_strlen ::_mbslen 00174 # if __STDC_WANT_SECURE_LIB__ 00175 # define sg_strcpy_s(a,n,b) ::_mbscpy_s(a,n,b) 00176 # else 00177 # define sg_strcpy_s(a,n,b) ::_mbscpy(a,b) 00178 # endif 00179 # define sg_strcmp ::_mbscmp 00180 # define sg_strcasecmp ::_mbsicmp 00181 # define SOCHAR_T unsigned char 00182 #else 00183 # include <sys/types.h> 00184 # include <sys/stat.h> 00185 # include <glob.h> 00186 # include <limits.h> 00187 # define MAX_PATH PATH_MAX 00188 # define sg_strchr ::strchr 00189 # define sg_strrchr ::strrchr 00190 # define sg_strlen ::strlen 00191 # define sg_strcpy_s(a,n,b) ::strcpy(a,b) 00192 # define sg_strcmp ::strcmp 00193 # define sg_strcasecmp ::strcasecmp 00194 # define SOCHAR_T char 00195 #endif 00196 00197 #include <stdlib.h> 00198 #include <string.h> 00199 #include <wchar.h> 00200 00201 // use assertions to test the input data 00202 #ifdef _DEBUG 00203 # ifdef _MSC_VER 00204 # include <crtdbg.h> 00205 # define SG_ASSERT(b) _ASSERTE(b) 00206 # else 00207 # include <assert.h> 00208 # define SG_ASSERT(b) assert(b) 00209 # endif 00210 #else 00211 # define SG_ASSERT(b) 00212 #endif 00213 00215 class SimpleGlobUtil 00216 { 00217 public: 00218 static const char * strchr(const char *s, char c) { 00219 return (char *) sg_strchr((const SOCHAR_T *)s, c); 00220 } 00221 static const wchar_t * strchr(const wchar_t *s, wchar_t c) { 00222 return ::wcschr(s, c); 00223 } 00224 #if SG_HAVE_ICU 00225 static const UChar * strchr(const UChar *s, UChar c) { 00226 return ::u_strchr(s, c); 00227 } 00228 #endif 00229 00230 static const char * strrchr(const char *s, char c) { 00231 return (char *) sg_strrchr((const SOCHAR_T *)s, c); 00232 } 00233 static const wchar_t * strrchr(const wchar_t *s, wchar_t c) { 00234 return ::wcsrchr(s, c); 00235 } 00236 #if SG_HAVE_ICU 00237 static const UChar * strrchr(const UChar *s, UChar c) { 00238 return ::u_strrchr(s, c); 00239 } 00240 #endif 00241 00242 // Note: char strlen returns number of bytes, not characters 00243 static size_t strlen(const char *s) { return ::strlen(s); } 00244 static size_t strlen(const wchar_t *s) { return ::wcslen(s); } 00245 #if SG_HAVE_ICU 00246 static size_t strlen(const UChar *s) { return ::u_strlen(s); } 00247 #endif 00248 00249 static void strcpy_s(char *dst, size_t n, const char *src) { 00250 (void) n; 00251 sg_strcpy_s((SOCHAR_T *)dst, n, (const SOCHAR_T *)src); 00252 } 00253 static void strcpy_s(wchar_t *dst, size_t n, const wchar_t *src) { 00254 # if __STDC_WANT_SECURE_LIB__ 00255 ::wcscpy_s(dst, n, src); 00256 #else 00257 (void) n; 00258 ::wcscpy(dst, src); 00259 #endif 00260 } 00261 #if SG_HAVE_ICU 00262 static void strcpy_s(UChar *dst, size_t n, const UChar *src) { 00263 ::u_strncpy(dst, src, n); 00264 } 00265 #endif 00266 00267 static int strcmp(const char *s1, const char *s2) { 00268 return sg_strcmp((const SOCHAR_T *)s1, (const SOCHAR_T *)s2); 00269 } 00270 static int strcmp(const wchar_t *s1, const wchar_t *s2) { 00271 return ::wcscmp(s1, s2); 00272 } 00273 #if SG_HAVE_ICU 00274 static int strcmp(const UChar *s1, const UChar *s2) { 00275 return ::u_strcmp(s1, s2); 00276 } 00277 #endif 00278 00279 static int strcasecmp(const char *s1, const char *s2) { 00280 return sg_strcasecmp((const SOCHAR_T *)s1, (const SOCHAR_T *)s2); 00281 } 00282 #if _WIN32 00283 static int strcasecmp(const wchar_t *s1, const wchar_t *s2) { 00284 return ::_wcsicmp(s1, s2); 00285 } 00286 #endif // _WIN32 00287 #if SG_HAVE_ICU 00288 static int strcasecmp(const UChar *s1, const UChar *s2) { 00289 return u_strcasecmp(s1, s2, 0); 00290 } 00291 #endif 00292 }; 00293 00294 enum SG_FileType { 00295 SG_FILETYPE_INVALID, 00296 SG_FILETYPE_FILE, 00297 SG_FILETYPE_DIR 00298 }; 00299 00300 #ifdef _WIN32 00301 00302 #ifndef INVALID_FILE_ATTRIBUTES 00303 # define INVALID_FILE_ATTRIBUTES ((DWORD)-1) 00304 #endif 00305 00306 #define SG_PATH_CHAR '\\' 00307 00309 template<class SOCHAR> 00310 struct SimpleGlobBase 00311 { 00312 SimpleGlobBase() : m_hFind(INVALID_HANDLE_VALUE) { } 00313 00314 int FindFirstFileS(const char * a_pszFileSpec, unsigned int) { 00315 m_hFind = FindFirstFileA(a_pszFileSpec, &m_oFindDataA); 00316 if (m_hFind != INVALID_HANDLE_VALUE) { 00317 return SG_SUCCESS; 00318 } 00319 DWORD dwErr = GetLastError(); 00320 if (dwErr == ERROR_FILE_NOT_FOUND) { 00321 return SG_ERR_NOMATCH; 00322 } 00323 return SG_ERR_FAILURE; 00324 } 00325 int FindFirstFileS(const wchar_t * a_pszFileSpec, unsigned int) { 00326 m_hFind = FindFirstFileW(a_pszFileSpec, &m_oFindDataW); 00327 if (m_hFind != INVALID_HANDLE_VALUE) { 00328 return SG_SUCCESS; 00329 } 00330 DWORD dwErr = GetLastError(); 00331 if (dwErr == ERROR_FILE_NOT_FOUND) { 00332 return SG_ERR_NOMATCH; 00333 } 00334 return SG_ERR_FAILURE; 00335 } 00336 00337 bool FindNextFileS(char) { 00338 return FindNextFileA(m_hFind, &m_oFindDataA) != FALSE; 00339 } 00340 bool FindNextFileS(wchar_t) { 00341 return FindNextFileW(m_hFind, &m_oFindDataW) != FALSE; 00342 } 00343 00344 void FindDone() { 00345 FindClose(m_hFind); 00346 } 00347 00348 const char * GetFileNameS(char) const { 00349 return m_oFindDataA.cFileName; 00350 } 00351 const wchar_t * GetFileNameS(wchar_t) const { 00352 return m_oFindDataW.cFileName; 00353 } 00354 00355 bool IsDirS(char) const { 00356 return GetFileTypeS(m_oFindDataA.dwFileAttributes) == SG_FILETYPE_DIR; 00357 } 00358 bool IsDirS(wchar_t) const { 00359 return GetFileTypeS(m_oFindDataW.dwFileAttributes) == SG_FILETYPE_DIR; 00360 } 00361 00362 SG_FileType GetFileTypeS(const char * a_pszPath) { 00363 return GetFileTypeS(GetFileAttributesA(a_pszPath)); 00364 } 00365 SG_FileType GetFileTypeS(const wchar_t * a_pszPath) { 00366 return GetFileTypeS(GetFileAttributesW(a_pszPath)); 00367 } 00368 SG_FileType GetFileTypeS(DWORD a_dwAttribs) const { 00369 if (a_dwAttribs == INVALID_FILE_ATTRIBUTES) { 00370 return SG_FILETYPE_INVALID; 00371 } 00372 if (a_dwAttribs & FILE_ATTRIBUTE_DIRECTORY) { 00373 return SG_FILETYPE_DIR; 00374 } 00375 return SG_FILETYPE_FILE; 00376 } 00377 00378 private: 00379 HANDLE m_hFind; 00380 WIN32_FIND_DATAA m_oFindDataA; 00381 WIN32_FIND_DATAW m_oFindDataW; 00382 }; 00383 00384 #else // !_WIN32 00385 00386 #define SG_PATH_CHAR '/' 00387 00389 template<class SOCHAR> 00390 struct SimpleGlobBase 00391 { 00392 SimpleGlobBase() { 00393 memset(&m_glob, 0, sizeof(m_glob)); 00394 m_uiCurr = (size_t)-1; 00395 } 00396 00397 ~SimpleGlobBase() { 00398 globfree(&m_glob); 00399 } 00400 00401 void FilePrep() { 00402 m_bIsDir = false; 00403 size_t len = strlen(m_glob.gl_pathv[m_uiCurr]); 00404 if (m_glob.gl_pathv[m_uiCurr][len-1] == '/') { 00405 m_bIsDir = true; 00406 m_glob.gl_pathv[m_uiCurr][len-1] = 0; 00407 } 00408 } 00409 00410 int FindFirstFileS(const char * a_pszFileSpec, unsigned int a_uiFlags) { 00411 int nFlags = GLOB_MARK | GLOB_NOSORT; 00412 if (a_uiFlags & SG_GLOB_ERR) nFlags |= GLOB_ERR; 00413 if (a_uiFlags & SG_GLOB_TILDE) nFlags |= GLOB_TILDE; 00414 int rc = glob(a_pszFileSpec, nFlags, NULL, &m_glob); 00415 if (rc == GLOB_NOSPACE) return SG_ERR_MEMORY; 00416 if (rc == GLOB_ABORTED) return SG_ERR_FAILURE; 00417 if (rc == GLOB_NOMATCH) return SG_ERR_NOMATCH; 00418 m_uiCurr = 0; 00419 FilePrep(); 00420 return SG_SUCCESS; 00421 } 00422 00423 #if SG_HAVE_ICU 00424 int FindFirstFileS(const UChar * a_pszFileSpec, unsigned int a_uiFlags) { 00425 char buf[PATH_MAX] = { 0 }; 00426 UErrorCode status = U_ZERO_ERROR; 00427 u_strToUTF8(buf, sizeof(buf), NULL, a_pszFileSpec, -1, &status); 00428 if (U_FAILURE(status)) return SG_ERR_FAILURE; 00429 return FindFirstFileS(buf, a_uiFlags); 00430 } 00431 #endif 00432 00433 bool FindNextFileS(char) { 00434 SG_ASSERT(m_uiCurr != (size_t)-1); 00435 if (++m_uiCurr >= m_glob.gl_pathc) { 00436 return false; 00437 } 00438 FilePrep(); 00439 return true; 00440 } 00441 00442 #if SG_HAVE_ICU 00443 bool FindNextFileS(UChar) { 00444 return FindNextFileS((char)0); 00445 } 00446 #endif 00447 00448 void FindDone() { 00449 globfree(&m_glob); 00450 memset(&m_glob, 0, sizeof(m_glob)); 00451 m_uiCurr = (size_t)-1; 00452 } 00453 00454 const char * GetFileNameS(char) const { 00455 SG_ASSERT(m_uiCurr != (size_t)-1); 00456 return m_glob.gl_pathv[m_uiCurr]; 00457 } 00458 00459 #if SG_HAVE_ICU 00460 const UChar * GetFileNameS(UChar) const { 00461 const char * pszFile = GetFileNameS((char)0); 00462 if (!pszFile) return NULL; 00463 UErrorCode status = U_ZERO_ERROR; 00464 memset(m_szBuf, 0, sizeof(m_szBuf)); 00465 u_strFromUTF8(m_szBuf, PATH_MAX, NULL, pszFile, -1, &status); 00466 if (U_FAILURE(status)) return NULL; 00467 return m_szBuf; 00468 } 00469 #endif 00470 00471 bool IsDirS(char) const { 00472 SG_ASSERT(m_uiCurr != (size_t)-1); 00473 return m_bIsDir; 00474 } 00475 00476 #if SG_HAVE_ICU 00477 bool IsDirS(UChar) const { 00478 return IsDirS((char)0); 00479 } 00480 #endif 00481 00482 SG_FileType GetFileTypeS(const char * a_pszPath) const { 00483 struct stat sb; 00484 if (0 != stat(a_pszPath, &sb)) { 00485 return SG_FILETYPE_INVALID; 00486 } 00487 if (S_ISDIR(sb.st_mode)) { 00488 return SG_FILETYPE_DIR; 00489 } 00490 if (S_ISREG(sb.st_mode)) { 00491 return SG_FILETYPE_FILE; 00492 } 00493 return SG_FILETYPE_INVALID; 00494 } 00495 00496 #if SG_HAVE_ICU 00497 SG_FileType GetFileTypeS(const UChar * a_pszPath) const { 00498 char buf[PATH_MAX] = { 0 }; 00499 UErrorCode status = U_ZERO_ERROR; 00500 u_strToUTF8(buf, sizeof(buf), NULL, a_pszPath, -1, &status); 00501 if (U_FAILURE(status)) return SG_FILETYPE_INVALID; 00502 return GetFileTypeS(buf); 00503 } 00504 #endif 00505 00506 private: 00507 glob_t m_glob; 00508 size_t m_uiCurr; 00509 bool m_bIsDir; 00510 #if SG_HAVE_ICU 00511 mutable UChar m_szBuf[PATH_MAX]; 00512 #endif 00513 }; 00514 00515 #endif // _WIN32 00516 00517 #endif // DOXYGEN 00518 00519 // --------------------------------------------------------------------------- 00520 // MAIN TEMPLATE CLASS 00521 // --------------------------------------------------------------------------- 00522 00524 template<class SOCHAR> 00525 class CSimpleGlobTempl : private SimpleGlobBase<SOCHAR> 00526 { 00527 public: 00536 CSimpleGlobTempl(unsigned int a_uiFlags = 0, int a_nReservedSlots = 0); 00537 00539 ~CSimpleGlobTempl(); 00540 00553 int Init(unsigned int a_uiFlags = 0, int a_nReservedSlots = 0); 00554 00568 int Add(const SOCHAR *a_pszFileSpec); 00569 00584 int Add(int a_nCount, const SOCHAR * const * a_rgpszFileSpec); 00585 00588 inline int FileCount() const { return m_nArgsLen; } 00589 00591 inline SOCHAR ** Files() { 00592 SetArgvArrayType(POINTERS); 00593 return m_rgpArgs; 00594 } 00595 00597 inline SOCHAR * File(int n) { 00598 SG_ASSERT(n >= 0 && n < m_nArgsLen); 00599 return Files()[n]; 00600 } 00601 00602 private: 00603 CSimpleGlobTempl(const CSimpleGlobTempl &); // disabled 00604 CSimpleGlobTempl & operator=(const CSimpleGlobTempl &); // disabled 00605 00611 enum ARG_ARRAY_TYPE { OFFSETS, POINTERS }; 00612 00614 void SetArgvArrayType(ARG_ARRAY_TYPE a_nNewType); 00615 00617 int AppendName(const SOCHAR *a_pszFileName, bool a_bIsDir); 00618 00620 bool GrowArgvArray(int a_nNewLen); 00621 00623 bool GrowStringBuffer(size_t a_uiMinSize); 00624 00626 static int fileSortCompare(const void *a1, const void *a2); 00627 00628 private: 00629 unsigned int m_uiFlags; 00630 ARG_ARRAY_TYPE m_nArgArrayType; 00631 SOCHAR ** m_rgpArgs; 00632 int m_nReservedSlots; 00633 int m_nArgsSize; 00634 int m_nArgsLen; 00635 SOCHAR * m_pBuffer; 00636 size_t m_uiBufferSize; 00637 size_t m_uiBufferLen; 00638 SOCHAR m_szPathPrefix[MAX_PATH]; 00639 }; 00640 00641 // --------------------------------------------------------------------------- 00642 // IMPLEMENTATION 00643 // --------------------------------------------------------------------------- 00644 00645 template<class SOCHAR> 00646 CSimpleGlobTempl<SOCHAR>::CSimpleGlobTempl( 00647 unsigned int a_uiFlags, 00648 int a_nReservedSlots 00649 ) 00650 { 00651 m_rgpArgs = NULL; 00652 m_nArgsSize = 0; 00653 m_pBuffer = NULL; 00654 m_uiBufferSize = 0; 00655 00656 Init(a_uiFlags, a_nReservedSlots); 00657 } 00658 00659 template<class SOCHAR> 00660 CSimpleGlobTempl<SOCHAR>::~CSimpleGlobTempl() 00661 { 00662 if (m_rgpArgs) free(m_rgpArgs); 00663 if (m_pBuffer) free(m_pBuffer); 00664 } 00665 00666 template<class SOCHAR> 00667 int 00668 CSimpleGlobTempl<SOCHAR>::Init( 00669 unsigned int a_uiFlags, 00670 int a_nReservedSlots 00671 ) 00672 { 00673 m_nArgArrayType = POINTERS; 00674 m_uiFlags = a_uiFlags; 00675 m_nArgsLen = a_nReservedSlots; 00676 m_nReservedSlots = a_nReservedSlots; 00677 m_uiBufferLen = 0; 00678 00679 if (m_nReservedSlots > 0) { 00680 if (!GrowArgvArray(m_nReservedSlots)) { 00681 return SG_ERR_MEMORY; 00682 } 00683 for (int n = 0; n < m_nReservedSlots; ++n) { 00684 m_rgpArgs[n] = NULL; 00685 } 00686 } 00687 00688 return SG_SUCCESS; 00689 } 00690 00691 template<class SOCHAR> 00692 int 00693 CSimpleGlobTempl<SOCHAR>::Add( 00694 const SOCHAR *a_pszFileSpec 00695 ) 00696 { 00697 #ifdef _WIN32 00698 // Windows FindFirst/FindNext recognizes forward slash as the same as 00699 // backward slash and follows the directories. We need to do the same 00700 // when calculating the prefix and when we have no wildcards. 00701 SOCHAR szFileSpec[MAX_PATH]; 00702 SimpleGlobUtil::strcpy_s(szFileSpec, MAX_PATH, a_pszFileSpec); 00703 const SOCHAR * pszPath = SimpleGlobUtil::strchr(szFileSpec, '/'); 00704 while (pszPath) { 00705 szFileSpec[pszPath - szFileSpec] = SG_PATH_CHAR; 00706 pszPath = SimpleGlobUtil::strchr(pszPath + 1, '/'); 00707 } 00708 a_pszFileSpec = szFileSpec; 00709 #endif 00710 00711 // if this doesn't contain wildcards then we can just add it directly 00712 m_szPathPrefix[0] = 0; 00713 if (!SimpleGlobUtil::strchr(a_pszFileSpec, '*') && 00714 !SimpleGlobUtil::strchr(a_pszFileSpec, '?')) 00715 { 00716 SG_FileType nType = GetFileTypeS(a_pszFileSpec); 00717 if (nType == SG_FILETYPE_INVALID) { 00718 if (m_uiFlags & SG_GLOB_NOCHECK) { 00719 return AppendName(a_pszFileSpec, false); 00720 } 00721 return SG_ERR_NOMATCH; 00722 } 00723 return AppendName(a_pszFileSpec, nType == SG_FILETYPE_DIR); 00724 } 00725 00726 #ifdef _WIN32 00727 // Windows doesn't return the directory with the filename, so we need to 00728 // extract the path from the search string ourselves and prefix it to the 00729 // filename we get back. 00730 const SOCHAR * pszFilename = 00731 SimpleGlobUtil::strrchr(a_pszFileSpec, SG_PATH_CHAR); 00732 if (pszFilename) { 00733 SimpleGlobUtil::strcpy_s(m_szPathPrefix, MAX_PATH, a_pszFileSpec); 00734 m_szPathPrefix[pszFilename - a_pszFileSpec + 1] = 0; 00735 } 00736 #endif 00737 00738 // search for the first match on the file 00739 int rc = FindFirstFileS(a_pszFileSpec, m_uiFlags); 00740 if (rc != SG_SUCCESS) { 00741 if (rc == SG_ERR_NOMATCH && (m_uiFlags & SG_GLOB_NOCHECK)) { 00742 int ok = AppendName(a_pszFileSpec, false); 00743 if (ok != SG_SUCCESS) rc = ok; 00744 } 00745 return rc; 00746 } 00747 00748 // add it and find all subsequent matches 00749 int nError, nStartLen = m_nArgsLen; 00750 bool bSuccess; 00751 do { 00752 nError = AppendName(GetFileNameS((SOCHAR)0), IsDirS((SOCHAR)0)); 00753 bSuccess = FindNextFileS((SOCHAR)0); 00754 } 00755 while (nError == SG_SUCCESS && bSuccess); 00756 SimpleGlobBase<SOCHAR>::FindDone(); 00757 00758 // sort these files if required 00759 if (m_nArgsLen > nStartLen && !(m_uiFlags & SG_GLOB_NOSORT)) { 00760 if (m_uiFlags & SG_GLOB_FULLSORT) { 00761 nStartLen = m_nReservedSlots; 00762 } 00763 SetArgvArrayType(POINTERS); 00764 qsort( 00765 m_rgpArgs + nStartLen, 00766 m_nArgsLen - nStartLen, 00767 sizeof(m_rgpArgs[0]), fileSortCompare); 00768 } 00769 00770 return nError; 00771 } 00772 00773 template<class SOCHAR> 00774 int 00775 CSimpleGlobTempl<SOCHAR>::Add( 00776 int a_nCount, 00777 const SOCHAR * const * a_rgpszFileSpec 00778 ) 00779 { 00780 int nResult; 00781 for (int n = 0; n < a_nCount; ++n) { 00782 nResult = Add(a_rgpszFileSpec[n]); 00783 if (nResult != SG_SUCCESS) { 00784 return nResult; 00785 } 00786 } 00787 return SG_SUCCESS; 00788 } 00789 00790 template<class SOCHAR> 00791 int 00792 CSimpleGlobTempl<SOCHAR>::AppendName( 00793 const SOCHAR * a_pszFileName, 00794 bool a_bIsDir 00795 ) 00796 { 00797 // we need the argv array as offsets in case we resize it 00798 SetArgvArrayType(OFFSETS); 00799 00800 // check for special cases which cause us to ignore this entry 00801 if ((m_uiFlags & SG_GLOB_ONLYDIR) && !a_bIsDir) { 00802 return SG_SUCCESS; 00803 } 00804 if ((m_uiFlags & SG_GLOB_ONLYFILE) && a_bIsDir) { 00805 return SG_SUCCESS; 00806 } 00807 if ((m_uiFlags & SG_GLOB_NODOT) && a_bIsDir) { 00808 if (a_pszFileName[0] == '.') { 00809 if (a_pszFileName[1] == '\0') { 00810 return SG_SUCCESS; 00811 } 00812 if (a_pszFileName[1] == '.' && a_pszFileName[2] == '\0') { 00813 return SG_SUCCESS; 00814 } 00815 } 00816 } 00817 00818 // ensure that we have enough room in the argv array 00819 if (!GrowArgvArray(m_nArgsLen + 1)) { 00820 return SG_ERR_MEMORY; 00821 } 00822 00823 // ensure that we have enough room in the string buffer (+1 for null) 00824 size_t uiPrefixLen = SimpleGlobUtil::strlen(m_szPathPrefix); 00825 size_t uiLen = uiPrefixLen + SimpleGlobUtil::strlen(a_pszFileName) + 1; 00826 if (a_bIsDir && (m_uiFlags & SG_GLOB_MARK) == SG_GLOB_MARK) { 00827 ++uiLen; // need space for the backslash 00828 } 00829 if (!GrowStringBuffer(m_uiBufferLen + uiLen)) { 00830 return SG_ERR_MEMORY; 00831 } 00832 00833 // add this entry. m_uiBufferLen is offset from beginning of buffer. 00834 m_rgpArgs[m_nArgsLen++] = (SOCHAR*)m_uiBufferLen; 00835 SimpleGlobUtil::strcpy_s(m_pBuffer + m_uiBufferLen, 00836 m_uiBufferSize - m_uiBufferLen, m_szPathPrefix); 00837 SimpleGlobUtil::strcpy_s(m_pBuffer + m_uiBufferLen + uiPrefixLen, 00838 m_uiBufferSize - m_uiBufferLen - uiPrefixLen, a_pszFileName); 00839 m_uiBufferLen += uiLen; 00840 00841 // add the directory slash if desired 00842 if (a_bIsDir && (m_uiFlags & SG_GLOB_MARK) == SG_GLOB_MARK) { 00843 const static SOCHAR szDirSlash[] = { SG_PATH_CHAR, 0 }; 00844 SimpleGlobUtil::strcpy_s(m_pBuffer + m_uiBufferLen - 2, 00845 m_uiBufferSize - (m_uiBufferLen - 2), szDirSlash); 00846 } 00847 00848 return SG_SUCCESS; 00849 } 00850 00851 template<class SOCHAR> 00852 void 00853 CSimpleGlobTempl<SOCHAR>::SetArgvArrayType( 00854 ARG_ARRAY_TYPE a_nNewType 00855 ) 00856 { 00857 if (m_nArgArrayType == a_nNewType) return; 00858 if (a_nNewType == POINTERS) { 00859 SG_ASSERT(m_nArgArrayType == OFFSETS); 00860 for (int n = 0; n < m_nArgsLen; ++n) { 00861 m_rgpArgs[n] = (m_rgpArgs[n] == (SOCHAR*)-1) ? 00862 NULL : m_pBuffer + (size_t) m_rgpArgs[n]; 00863 } 00864 } 00865 else { 00866 SG_ASSERT(a_nNewType == OFFSETS); 00867 SG_ASSERT(m_nArgArrayType == POINTERS); 00868 for (int n = 0; n < m_nArgsLen; ++n) { 00869 m_rgpArgs[n] = (m_rgpArgs[n] == NULL) ? 00870 (SOCHAR*) -1 : (SOCHAR*) (m_rgpArgs[n] - m_pBuffer); 00871 } 00872 } 00873 m_nArgArrayType = a_nNewType; 00874 } 00875 00876 template<class SOCHAR> 00877 bool 00878 CSimpleGlobTempl<SOCHAR>::GrowArgvArray( 00879 int a_nNewLen 00880 ) 00881 { 00882 if (a_nNewLen >= m_nArgsSize) { 00883 static const int SG_ARGV_INITIAL_SIZE = 32; 00884 int nNewSize = (m_nArgsSize > 0) ? 00885 m_nArgsSize * 2 : SG_ARGV_INITIAL_SIZE; 00886 while (a_nNewLen >= nNewSize) { 00887 nNewSize *= 2; 00888 } 00889 void * pNewBuffer = realloc(m_rgpArgs, nNewSize * sizeof(SOCHAR*)); 00890 if (!pNewBuffer) return false; 00891 m_nArgsSize = nNewSize; 00892 m_rgpArgs = (SOCHAR**) pNewBuffer; 00893 } 00894 return true; 00895 } 00896 00897 template<class SOCHAR> 00898 bool 00899 CSimpleGlobTempl<SOCHAR>::GrowStringBuffer( 00900 size_t a_uiMinSize 00901 ) 00902 { 00903 if (a_uiMinSize >= m_uiBufferSize) { 00904 static const int SG_BUFFER_INITIAL_SIZE = 1024; 00905 size_t uiNewSize = (m_uiBufferSize > 0) ? 00906 m_uiBufferSize * 2 : SG_BUFFER_INITIAL_SIZE; 00907 while (a_uiMinSize >= uiNewSize) { 00908 uiNewSize *= 2; 00909 } 00910 void * pNewBuffer = realloc(m_pBuffer, uiNewSize * sizeof(SOCHAR)); 00911 if (!pNewBuffer) return false; 00912 m_uiBufferSize = uiNewSize; 00913 m_pBuffer = (SOCHAR*) pNewBuffer; 00914 } 00915 return true; 00916 } 00917 00918 template<class SOCHAR> 00919 int 00920 CSimpleGlobTempl<SOCHAR>::fileSortCompare( 00921 const void *a1, 00922 const void *a2 00923 ) 00924 { 00925 const SOCHAR * s1 = *(const SOCHAR **)a1; 00926 const SOCHAR * s2 = *(const SOCHAR **)a2; 00927 if (s1 && s2) { 00928 return SimpleGlobUtil::strcasecmp(s1, s2); 00929 } 00930 // NULL sorts first 00931 return s1 == s2 ? 0 : (s1 ? 1 : -1); 00932 } 00933 00934 // --------------------------------------------------------------------------- 00935 // TYPE DEFINITIONS 00936 // --------------------------------------------------------------------------- 00937 00939 typedef CSimpleGlobTempl<char> CSimpleGlobA; 00940 00942 typedef CSimpleGlobTempl<wchar_t> CSimpleGlobW; 00943 00944 #if SG_HAVE_ICU 00945 00946 typedef CSimpleGlobTempl<UChar> CSimpleGlobU; 00947 #endif 00948 00949 #ifdef _UNICODE 00950 00951 # if SG_HAVE_ICU 00952 # define CSimpleGlob CSimpleGlobU 00953 # else 00954 # define CSimpleGlob CSimpleGlobW 00955 # endif 00956 #else 00957 00958 # define CSimpleGlob CSimpleGlobA 00959 #endif 00960 00961 #endif // INCLUDED_SimpleGlob
1.7.3