Points&Forces (core)
Software tools facilitating the task of surveying architecture
SimpleGlob.h
Go to the documentation of this file.
1 
83 #ifndef INCLUDED_SimpleGlob
84 #define INCLUDED_SimpleGlob
85 
129 enum SG_Flags {
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,
137  SG_GLOB_NODOT = 1 << 7,
138  SG_GLOB_FULLSORT = 1 << 8
139 };
140 
142 enum SG_Error {
146  SG_ERR_FAILURE = -2
147 };
148 
149 // ---------------------------------------------------------------------------
150 // Platform dependent implementations
151 
152 // if we aren't on Windows and we have ICU available, then enable ICU
153 // by default. Define this to 0 to intentially disable it.
154 #ifndef SG_HAVE_ICU
155 # if !defined(_WIN32) && defined(USTRING_H)
156 # define SG_HAVE_ICU 1
157 # else
158 # define SG_HAVE_ICU 0
159 # endif
160 #endif
161 
162 // don't include this in documentation as it isn't relevant
163 #ifndef DOXYGEN
164 
165 // on Windows we want to use MBCS aware string functions and mimic the
166 // Unix glob functionality. On Unix we just use glob.
167 #ifdef _WIN32
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)
174 # else
175 # define sg_strcpy_s(a,n,b) ::_mbscpy(a,b)
176 # endif
177 # define sg_strcmp ::_mbscmp
178 # define sg_strcasecmp ::_mbsicmp
179 # define SOCHAR_T unsigned char
180 #else
181 # include <sys/types.h>
182 # include <sys/stat.h>
183 # include <glob.h>
184 # include <limits.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
193 #endif
194 
195 #include <stdlib.h>
196 #include <string.h>
197 #include <wchar.h>
198 
199 // use assertions to test the input data
200 #ifdef _DEBUG
201 # ifdef _MSC_VER
202 # include <crtdbg.h>
203 # define SG_ASSERT(b) _ASSERTE(b)
204 # else
205 # include <assert.h>
206 # define SG_ASSERT(b) assert(b)
207 # endif
208 #else
209 # define SG_ASSERT(b)
210 #endif
211 
214 {
215 public:
216  static const char * strchr(const char *s, char c) {
217  return (char *) sg_strchr((const SOCHAR_T *)s, c);
218  }
219  static const wchar_t * strchr(const wchar_t *s, wchar_t c) {
220  return ::wcschr(s, c);
221  }
222 #if SG_HAVE_ICU
223  static const UChar * strchr(const UChar *s, UChar c) {
224  return ::u_strchr(s, c);
225  }
226 #endif
227 
228  static const char * strrchr(const char *s, char c) {
229  return (char *) sg_strrchr((const SOCHAR_T *)s, c);
230  }
231  static const wchar_t * strrchr(const wchar_t *s, wchar_t c) {
232  return ::wcsrchr(s, c);
233  }
234 #if SG_HAVE_ICU
235  static const UChar * strrchr(const UChar *s, UChar c) {
236  return ::u_strrchr(s, c);
237  }
238 #endif
239 
240  // Note: char strlen returns number of bytes, not characters
241  static size_t strlen(const char *s) { return ::strlen(s); }
242  static size_t strlen(const wchar_t *s) { return ::wcslen(s); }
243 #if SG_HAVE_ICU
244  static size_t strlen(const UChar *s) { return ::u_strlen(s); }
245 #endif
246 
247  static void strcpy_s(char *dst, size_t n, const char *src) {
248  (void) n;
249  sg_strcpy_s((SOCHAR_T *)dst, n, (const SOCHAR_T *)src);
250  }
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);
254 #else
255  (void) n;
256  ::wcscpy(dst, src);
257 #endif
258  }
259 #if SG_HAVE_ICU
260  static void strcpy_s(UChar *dst, size_t n, const UChar *src) {
261  ::u_strncpy(dst, src, n);
262  }
263 #endif
264 
265  static int strcmp(const char *s1, const char *s2) {
266  return sg_strcmp((const SOCHAR_T *)s1, (const SOCHAR_T *)s2);
267  }
268  static int strcmp(const wchar_t *s1, const wchar_t *s2) {
269  return ::wcscmp(s1, s2);
270  }
271 #if SG_HAVE_ICU
272  static int strcmp(const UChar *s1, const UChar *s2) {
273  return ::u_strcmp(s1, s2);
274  }
275 #endif
276 
277  static int strcasecmp(const char *s1, const char *s2) {
278  return sg_strcasecmp((const SOCHAR_T *)s1, (const SOCHAR_T *)s2);
279  }
280 #if _WIN32
281  static int strcasecmp(const wchar_t *s1, const wchar_t *s2) {
282  return ::_wcsicmp(s1, s2);
283  }
284 #endif // _WIN32
285 #if SG_HAVE_ICU
286  static int strcasecmp(const UChar *s1, const UChar *s2) {
287  return u_strcasecmp(s1, s2, 0);
288  }
289 #endif
290 };
291 
296 };
297 
298 #ifdef _WIN32
299 
300 #ifndef INVALID_FILE_ATTRIBUTES
301 # define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
302 #endif
303 
304 #define SG_PATH_CHAR '\\'
305 
307 template<class SOCHAR>
308 struct SimpleGlobBase
309 {
310  SimpleGlobBase() : m_hFind(INVALID_HANDLE_VALUE) { }
311 
312  int FindFirstFileS(const char * a_pszFileSpec, unsigned int) {
313  m_hFind = FindFirstFileA(a_pszFileSpec, &m_oFindDataA);
314  if (m_hFind != INVALID_HANDLE_VALUE) {
315  return SG_SUCCESS;
316  }
317  DWORD dwErr = GetLastError();
318  if (dwErr == ERROR_FILE_NOT_FOUND) {
319  return SG_ERR_NOMATCH;
320  }
321  return SG_ERR_FAILURE;
322  }
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) {
326  return SG_SUCCESS;
327  }
328  DWORD dwErr = GetLastError();
329  if (dwErr == ERROR_FILE_NOT_FOUND) {
330  return SG_ERR_NOMATCH;
331  }
332  return SG_ERR_FAILURE;
333  }
334 
335  bool FindNextFileS(char) {
336  return FindNextFileA(m_hFind, &m_oFindDataA) != FALSE;
337  }
338  bool FindNextFileS(wchar_t) {
339  return FindNextFileW(m_hFind, &m_oFindDataW) != FALSE;
340  }
341 
342  void FindDone() {
343  FindClose(m_hFind);
344  }
345 
346  const char * GetFileNameS(char) const {
347  return m_oFindDataA.cFileName;
348  }
349  const wchar_t * GetFileNameS(wchar_t) const {
350  return m_oFindDataW.cFileName;
351  }
352 
353  bool IsDirS(char) const {
354  return this->GetFileTypeS(m_oFindDataA.dwFileAttributes) == SG_FILETYPE_DIR;
355  }
356  bool IsDirS(wchar_t) const {
357  return this->GetFileTypeS(m_oFindDataW.dwFileAttributes) == SG_FILETYPE_DIR;
358  }
359 
360  SG_FileType GetFileTypeS(const char * a_pszPath) {
361  return this->GetFileTypeS(GetFileAttributesA(a_pszPath));
362  }
363  SG_FileType GetFileTypeS(const wchar_t * a_pszPath) {
364  return this->GetFileTypeS(GetFileAttributesW(a_pszPath));
365  }
366  SG_FileType GetFileTypeS(DWORD a_dwAttribs) const {
367  if (a_dwAttribs == INVALID_FILE_ATTRIBUTES) {
368  return SG_FILETYPE_INVALID;
369  }
370  if (a_dwAttribs & FILE_ATTRIBUTE_DIRECTORY) {
371  return SG_FILETYPE_DIR;
372  }
373  return SG_FILETYPE_FILE;
374  }
375 
376 private:
377  HANDLE m_hFind;
378  WIN32_FIND_DATAA m_oFindDataA;
379  WIN32_FIND_DATAW m_oFindDataW;
380 };
381 
382 #else // !_WIN32
383 
384 #define SG_PATH_CHAR '/'
385 
387 template<class SOCHAR>
389 {
391  memset(&m_glob, 0, sizeof(m_glob));
392  m_uiCurr = (size_t)-1;
393  }
394 
396  globfree(&m_glob);
397  }
398 
399  void FilePrep() {
400  m_bIsDir = false;
401  size_t len = strlen(m_glob.gl_pathv[m_uiCurr]);
402  if (m_glob.gl_pathv[m_uiCurr][len-1] == '/') {
403  m_bIsDir = true;
404  m_glob.gl_pathv[m_uiCurr][len-1] = 0;
405  }
406  }
407 
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;
416  m_uiCurr = 0;
417  FilePrep();
418  return SG_SUCCESS;
419  }
420 
421 #if SG_HAVE_ICU
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);
428  }
429 #endif
430 
431  bool FindNextFileS(char) {
432  SG_ASSERT(m_uiCurr != (size_t)-1);
433  if (++m_uiCurr >= m_glob.gl_pathc) {
434  return false;
435  }
436  FilePrep();
437  return true;
438  }
439 
440 #if SG_HAVE_ICU
441  bool FindNextFileS(UChar) {
442  return this->FindNextFileS((char)0);
443  }
444 #endif
445 
446  void FindDone() {
447  globfree(&m_glob);
448  memset(&m_glob, 0, sizeof(m_glob));
449  m_uiCurr = (size_t)-1;
450  }
451 
452  const char * GetFileNameS(char) const {
453  SG_ASSERT(m_uiCurr != (size_t)-1);
454  return m_glob.gl_pathv[m_uiCurr];
455  }
456 
457 #if SG_HAVE_ICU
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;
465  return m_szBuf;
466  }
467 #endif
468 
469  bool IsDirS(char) const {
470  SG_ASSERT(m_uiCurr != (size_t)-1);
471  return m_bIsDir;
472  }
473 
474 #if SG_HAVE_ICU
475  bool IsDirS(UChar) const {
476  return this->IsDirS((char)0);
477  }
478 #endif
479 
480  SG_FileType GetFileTypeS(const char * a_pszPath) const {
481  struct stat sb;
482  if (0 != stat(a_pszPath, &sb)) {
483  return SG_FILETYPE_INVALID;
484  }
485  if (S_ISDIR(sb.st_mode)) {
486  return SG_FILETYPE_DIR;
487  }
488  if (S_ISREG(sb.st_mode)) {
489  return SG_FILETYPE_FILE;
490  }
491  return SG_FILETYPE_INVALID;
492  }
493 
494 #if SG_HAVE_ICU
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);
501  }
502 #endif
503 
504 private:
505  glob_t m_glob;
506  size_t m_uiCurr;
507  bool m_bIsDir;
508 #if SG_HAVE_ICU
509  mutable UChar m_szBuf[PATH_MAX];
510 #endif
511 };
512 
513 #endif // _WIN32
514 
515 #endif // DOXYGEN
516 
517 // ---------------------------------------------------------------------------
518 // MAIN TEMPLATE CLASS
519 // ---------------------------------------------------------------------------
520 
522 template<class SOCHAR>
523 class CSimpleGlobTempl : private SimpleGlobBase<SOCHAR>
524 {
525 public:
534  CSimpleGlobTempl(unsigned int a_uiFlags = 0, int a_nReservedSlots = 0);
535 
538 
551  int Init(unsigned int a_uiFlags = 0, int a_nReservedSlots = 0);
552 
566  int Add(const SOCHAR *a_pszFileSpec);
567 
582  int Add(int a_nCount, const SOCHAR * const * a_rgpszFileSpec);
583 
586  inline int FileCount() const { return m_nArgsLen; }
587 
589  inline SOCHAR ** Files() {
590  SetArgvArrayType(POINTERS);
591  return m_rgpArgs;
592  }
593 
595  inline SOCHAR * File(int n) {
596  SG_ASSERT(n >= 0 && n < m_nArgsLen);
597  return Files()[n];
598  }
599 
600 private:
601  CSimpleGlobTempl(const CSimpleGlobTempl &); // disabled
602  CSimpleGlobTempl & operator=(const CSimpleGlobTempl &); // disabled
603 
609  enum ARG_ARRAY_TYPE { OFFSETS, POINTERS };
610 
612  void SetArgvArrayType(ARG_ARRAY_TYPE a_nNewType);
613 
615  int AppendName(const SOCHAR *a_pszFileName, bool a_bIsDir);
616 
618  bool GrowArgvArray(int a_nNewLen);
619 
621  bool GrowStringBuffer(size_t a_uiMinSize);
622 
624  static int fileSortCompare(const void *a1, const void *a2);
625 
626 private:
627  unsigned int m_uiFlags;
628  ARG_ARRAY_TYPE m_nArgArrayType;
629  SOCHAR ** m_rgpArgs;
630  int m_nReservedSlots;
631  int m_nArgsSize;
632  int m_nArgsLen;
633  SOCHAR * m_pBuffer;
634  size_t m_uiBufferSize;
635  size_t m_uiBufferLen;
636  SOCHAR m_szPathPrefix[MAX_PATH];
637 };
638 
639 // ---------------------------------------------------------------------------
640 // IMPLEMENTATION
641 // ---------------------------------------------------------------------------
642 
643 template<class SOCHAR>
645  unsigned int a_uiFlags,
646  int a_nReservedSlots
647  )
648 {
649  m_rgpArgs = NULL;
650  m_nArgsSize = 0;
651  m_pBuffer = NULL;
652  m_uiBufferSize = 0;
653 
654  Init(a_uiFlags, a_nReservedSlots);
655 }
656 
657 template<class SOCHAR>
659 {
660  if (m_rgpArgs) free(m_rgpArgs);
661  if (m_pBuffer) free(m_pBuffer);
662 }
663 
664 template<class SOCHAR>
665 int
667  unsigned int a_uiFlags,
668  int a_nReservedSlots
669  )
670 {
671  m_nArgArrayType = POINTERS;
672  m_uiFlags = a_uiFlags;
673  m_nArgsLen = a_nReservedSlots;
674  m_nReservedSlots = a_nReservedSlots;
675  m_uiBufferLen = 0;
676 
677  if (m_nReservedSlots > 0) {
678  if (!GrowArgvArray(m_nReservedSlots)) {
679  return SG_ERR_MEMORY;
680  }
681  for (int n = 0; n < m_nReservedSlots; ++n) {
682  m_rgpArgs[n] = NULL;
683  }
684  }
685 
686  return SG_SUCCESS;
687 }
688 
689 template<class SOCHAR>
690 int
692  const SOCHAR *a_pszFileSpec
693  )
694 {
695 #ifdef _WIN32
696  // Windows FindFirst/FindNext recognizes forward slash as the same as
697  // backward slash and follows the directories. We need to do the same
698  // when calculating the prefix and when we have no wildcards.
699  SOCHAR szFileSpec[MAX_PATH];
700  SimpleGlobUtil::strcpy_s(szFileSpec, MAX_PATH, a_pszFileSpec);
701  const SOCHAR * pszPath = SimpleGlobUtil::strchr(szFileSpec, '/');
702  while (pszPath) {
703  szFileSpec[pszPath - szFileSpec] = SG_PATH_CHAR;
704  pszPath = SimpleGlobUtil::strchr(pszPath + 1, '/');
705  }
706  a_pszFileSpec = szFileSpec;
707 #endif
708 
709  // if this doesn't contain wildcards then we can just add it directly
710  m_szPathPrefix[0] = 0;
711  if (!SimpleGlobUtil::strchr(a_pszFileSpec, '*') &&
712  !SimpleGlobUtil::strchr(a_pszFileSpec, '?'))
713  {
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);
718  }
719  return SG_ERR_NOMATCH;
720  }
721  return AppendName(a_pszFileSpec, nType == SG_FILETYPE_DIR);
722  }
723 
724 #ifdef _WIN32
725  // Windows doesn't return the directory with the filename, so we need to
726  // extract the path from the search string ourselves and prefix it to the
727  // filename we get back.
728  const SOCHAR * pszFilename =
729  SimpleGlobUtil::strrchr(a_pszFileSpec, SG_PATH_CHAR);
730  if (pszFilename) {
731  SimpleGlobUtil::strcpy_s(m_szPathPrefix, MAX_PATH, a_pszFileSpec);
732  m_szPathPrefix[pszFilename - a_pszFileSpec + 1] = 0;
733  }
734 #endif
735 
736  // search for the first match on the file
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;
742  }
743  return rc;
744  }
745 
746  // add it and find all subsequent matches
747  int nError, nStartLen = m_nArgsLen;
748  bool bSuccess;
749  do {
750  nError = AppendName(this->GetFileNameS((SOCHAR)0), this->IsDirS((SOCHAR)0));
751  bSuccess = this->FindNextFileS((SOCHAR)0);
752  }
753  while (nError == SG_SUCCESS && bSuccess);
755 
756  // sort these files if required
757  if (m_nArgsLen > nStartLen && !(m_uiFlags & SG_GLOB_NOSORT)) {
758  if (m_uiFlags & SG_GLOB_FULLSORT) {
759  nStartLen = m_nReservedSlots;
760  }
761  SetArgvArrayType(POINTERS);
762  qsort(
763  m_rgpArgs + nStartLen,
764  m_nArgsLen - nStartLen,
765  sizeof(m_rgpArgs[0]), fileSortCompare);
766  }
767 
768  return nError;
769 }
770 
771 template<class SOCHAR>
772 int
774  int a_nCount,
775  const SOCHAR * const * a_rgpszFileSpec
776  )
777 {
778  int nResult;
779  for (int n = 0; n < a_nCount; ++n) {
780  nResult = Add(a_rgpszFileSpec[n]);
781  if (nResult != SG_SUCCESS) {
782  return nResult;
783  }
784  }
785  return SG_SUCCESS;
786 }
787 
788 template<class SOCHAR>
789 int
791  const SOCHAR * a_pszFileName,
792  bool a_bIsDir
793  )
794 {
795  // we need the argv array as offsets in case we resize it
796  SetArgvArrayType(OFFSETS);
797 
798  // check for special cases which cause us to ignore this entry
799  if ((m_uiFlags & SG_GLOB_ONLYDIR) && !a_bIsDir) {
800  return SG_SUCCESS;
801  }
802  if ((m_uiFlags & SG_GLOB_ONLYFILE) && a_bIsDir) {
803  return SG_SUCCESS;
804  }
805  if ((m_uiFlags & SG_GLOB_NODOT) && a_bIsDir) {
806  if (a_pszFileName[0] == '.') {
807  if (a_pszFileName[1] == '\0') {
808  return SG_SUCCESS;
809  }
810  if (a_pszFileName[1] == '.' && a_pszFileName[2] == '\0') {
811  return SG_SUCCESS;
812  }
813  }
814  }
815 
816  // ensure that we have enough room in the argv array
817  if (!GrowArgvArray(m_nArgsLen + 1)) {
818  return SG_ERR_MEMORY;
819  }
820 
821  // ensure that we have enough room in the string buffer (+1 for null)
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) {
825  ++uiLen; // need space for the backslash
826  }
827  if (!GrowStringBuffer(m_uiBufferLen + uiLen)) {
828  return SG_ERR_MEMORY;
829  }
830 
831  // add this entry. m_uiBufferLen is offset from beginning of buffer.
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;
838 
839  // add the directory slash if desired
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);
844  }
845 
846  return SG_SUCCESS;
847 }
848 
849 template<class SOCHAR>
850 void
852  ARG_ARRAY_TYPE a_nNewType
853  )
854 {
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];
861  }
862  }
863  else {
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);
869  }
870  }
871  m_nArgArrayType = a_nNewType;
872 }
873 
874 template<class SOCHAR>
875 bool
877  int a_nNewLen
878  )
879 {
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) {
885  nNewSize *= 2;
886  }
887  void * pNewBuffer = realloc(m_rgpArgs, nNewSize * sizeof(SOCHAR*));
888  if (!pNewBuffer) return false;
889  m_nArgsSize = nNewSize;
890  m_rgpArgs = (SOCHAR**) pNewBuffer;
891  }
892  return true;
893 }
894 
895 template<class SOCHAR>
896 bool
898  size_t a_uiMinSize
899  )
900 {
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) {
906  uiNewSize *= 2;
907  }
908  void * pNewBuffer = realloc(m_pBuffer, uiNewSize * sizeof(SOCHAR));
909  if (!pNewBuffer) return false;
910  m_uiBufferSize = uiNewSize;
911  m_pBuffer = (SOCHAR*) pNewBuffer;
912  }
913  return true;
914 }
915 
916 template<class SOCHAR>
917 int
919  const void *a1,
920  const void *a2
921  )
922 {
923  const SOCHAR * s1 = *(const SOCHAR **)a1;
924  const SOCHAR * s2 = *(const SOCHAR **)a2;
925  if (s1 && s2) {
926  return SimpleGlobUtil::strcasecmp(s1, s2);
927  }
928  // NULL sorts first
929  return s1 == s2 ? 0 : (s1 ? 1 : -1);
930 }
931 
932 // ---------------------------------------------------------------------------
933 // TYPE DEFINITIONS
934 // ---------------------------------------------------------------------------
935 
938 
941 
942 #if SG_HAVE_ICU
944 typedef CSimpleGlobTempl<UChar> CSimpleGlobU;
945 #endif
946 
947 #ifdef _UNICODE
949 # if SG_HAVE_ICU
950 # define CSimpleGlob CSimpleGlobU
951 # else
952 # define CSimpleGlob CSimpleGlobW
953 # endif
954 #else
956 # define CSimpleGlob CSimpleGlobA
957 #endif
958 
959 #endif // INCLUDED_SimpleGlob
SG_Flags
The operation of SimpleGlob is fine-tuned via the use of a combination of the following flags.
Definition: SimpleGlob.h:129
@ SG_GLOB_FULLSORT
Definition: SimpleGlob.h:138
@ SG_GLOB_NOCHECK
Definition: SimpleGlob.h:133
@ SG_GLOB_TILDE
Definition: SimpleGlob.h:134
@ SG_GLOB_MARK
Definition: SimpleGlob.h:131
@ SG_GLOB_ONLYFILE
Definition: SimpleGlob.h:136
@ SG_GLOB_ERR
Definition: SimpleGlob.h:130
@ SG_GLOB_NODOT
Definition: SimpleGlob.h:137
@ SG_GLOB_ONLYDIR
Definition: SimpleGlob.h:135
@ SG_GLOB_NOSORT
Definition: SimpleGlob.h:132
#define sg_strcmp
Definition: SimpleGlob.h:190
#define sg_strcasecmp
Definition: SimpleGlob.h:191
#define sg_strcpy_s(a, n, b)
Definition: SimpleGlob.h:189
#define sg_strchr
Definition: SimpleGlob.h:186
#define SG_PATH_CHAR
Definition: SimpleGlob.h:384
#define SG_ASSERT(b)
Definition: SimpleGlob.h:209
SG_FileType
Definition: SimpleGlob.h:292
@ SG_FILETYPE_DIR
Definition: SimpleGlob.h:295
@ SG_FILETYPE_FILE
Definition: SimpleGlob.h:294
@ SG_FILETYPE_INVALID
Definition: SimpleGlob.h:293
CSimpleGlobTempl< wchar_t > CSimpleGlobW
wchar_t version of CSimpleGlob
Definition: SimpleGlob.h:940
#define MAX_PATH
Definition: SimpleGlob.h:185
#define SOCHAR_T
Definition: SimpleGlob.h:192
#define sg_strrchr
Definition: SimpleGlob.h:187
CSimpleGlobTempl< char > CSimpleGlobA
ASCII/MBCS version of CSimpleGlob.
Definition: SimpleGlob.h:937
SG_Error
Error return codes.
Definition: SimpleGlob.h:142
@ SG_ERR_MEMORY
Definition: SimpleGlob.h:145
@ SG_SUCCESS
Definition: SimpleGlob.h:143
@ SG_ERR_NOMATCH
Definition: SimpleGlob.h:144
@ SG_ERR_FAILURE
Definition: SimpleGlob.h:146
Implementation of the SimpleGlob class.
Definition: SimpleGlob.h:524
int Init(unsigned int a_uiFlags=0, int a_nReservedSlots=0)
Initialize (or re-initialize) the class in preparation for adding new filespecs.
Definition: SimpleGlob.h:666
~CSimpleGlobTempl()
Deallocate all memory buffers.
Definition: SimpleGlob.h:658
int FileCount() const
Return the number of files in the argv array.
Definition: SimpleGlob.h:586
int Add(const SOCHAR *a_pszFileSpec)
Add a new filespec to the glob.
Definition: SimpleGlob.h:691
SOCHAR * File(int n)
Return the a single file.
Definition: SimpleGlob.h:595
SOCHAR ** Files()
Return the full argv array.
Definition: SimpleGlob.h:589
CSimpleGlobTempl(unsigned int a_uiFlags=0, int a_nReservedSlots=0)
Initialize the class.
Definition: SimpleGlob.h:644
String manipulation functions.
Definition: SimpleGlob.h:214
static int strcasecmp(const char *s1, const char *s2)
Definition: SimpleGlob.h:277
static size_t strlen(const wchar_t *s)
Definition: SimpleGlob.h:242
static void strcpy_s(wchar_t *dst, size_t n, const wchar_t *src)
Definition: SimpleGlob.h:251
static const wchar_t * strrchr(const wchar_t *s, wchar_t c)
Definition: SimpleGlob.h:231
static const char * strchr(const char *s, char c)
Definition: SimpleGlob.h:216
static int strcmp(const char *s1, const char *s2)
Definition: SimpleGlob.h:265
static const wchar_t * strchr(const wchar_t *s, wchar_t c)
Definition: SimpleGlob.h:219
static int strcmp(const wchar_t *s1, const wchar_t *s2)
Definition: SimpleGlob.h:268
static const char * strrchr(const char *s, char c)
Definition: SimpleGlob.h:228
static void strcpy_s(char *dst, size_t n, const char *src)
Definition: SimpleGlob.h:247
static size_t strlen(const char *s)
Definition: SimpleGlob.h:241
char buf[256]
Definition: copy.h:17
Unix glob implementation.
Definition: SimpleGlob.h:389
void FindDone()
Definition: SimpleGlob.h:446
SG_FileType GetFileTypeS(const char *a_pszPath) const
Definition: SimpleGlob.h:480
const char * GetFileNameS(char) const
Definition: SimpleGlob.h:452
bool IsDirS(char) const
Definition: SimpleGlob.h:469
int FindFirstFileS(const char *a_pszFileSpec, unsigned int a_uiFlags)
Definition: SimpleGlob.h:408
void FilePrep()
Definition: SimpleGlob.h:399
bool FindNextFileS(char)
Definition: SimpleGlob.h:431