147 lines
3.2 KiB
C++
147 lines
3.2 KiB
C++
|
//
|
||
|
// SortString.cpp
|
||
|
//
|
||
|
|
||
|
#include "stdafx.h"
|
||
|
#include "SortStr.h"
|
||
|
|
||
|
#define ISDIGIT(ch) ((UINT)((char)(ch) - '0') <= 9)
|
||
|
#define ROUND_UP(val, quantum) ((val) + (((quantum) - ((val) % (quantum))) % (quantum)))
|
||
|
|
||
|
extern "C" BOOL SafeRealloc(LPVOID FAR* ppv, UINT cb)
|
||
|
{
|
||
|
LPVOID pv2;
|
||
|
|
||
|
if (*ppv == NULL)
|
||
|
{
|
||
|
pv2 = malloc(cb);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pv2 = realloc(*ppv, cb);
|
||
|
}
|
||
|
|
||
|
if (pv2 == NULL)
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
*ppv = pv2;
|
||
|
return TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
extern "C" void SafeFree(LPVOID FAR* ppv)
|
||
|
{
|
||
|
if (*ppv)
|
||
|
{
|
||
|
free(*ppv);
|
||
|
*ppv = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
extern "C" BOOL SafeGrowArray(LPVOID FAR* ppv, UINT FAR* pArrayMax, UINT nSizeWanted, UINT nGrowBy, UINT cbElement)
|
||
|
{
|
||
|
// Round up to next multiple of nGrowBy
|
||
|
UINT newMax = ROUND_UP(nSizeWanted, nGrowBy);
|
||
|
if (newMax > *pArrayMax)
|
||
|
{
|
||
|
if (!SafeRealloc(ppv, newMax * cbElement))
|
||
|
return FALSE;
|
||
|
*pArrayMax = newMax;
|
||
|
}
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
// A custom compare routine that will put strings like "100+" after "9"
|
||
|
int WINAPI CompareStringsWithNumbers(LPCTSTR psz1, LPCTSTR psz2)
|
||
|
{
|
||
|
if (ISDIGIT(*psz1) && ISDIGIT(*psz2))
|
||
|
{
|
||
|
int nVal1 = MyAtoi(psz1);
|
||
|
int nVal2 = MyAtoi(psz2);
|
||
|
|
||
|
if (nVal1 < nVal2)
|
||
|
return -1;
|
||
|
else if (nVal1 > nVal2)
|
||
|
return 1;
|
||
|
else
|
||
|
{
|
||
|
while (ISDIGIT(*psz1))
|
||
|
psz1++;
|
||
|
while (ISDIGIT(*psz2))
|
||
|
psz2++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return lstrcmpi(psz1, psz2);
|
||
|
}
|
||
|
|
||
|
|
||
|
CSortedStringArray::CSortedStringArray(SORTSTRING_COMPARE_PROC pfnCustomCompare /*=NULL*/)
|
||
|
{
|
||
|
m_prgStrings = NULL;
|
||
|
m_cStrings = 0;
|
||
|
m_maxStrings = 0;
|
||
|
|
||
|
if (pfnCustomCompare == NULL)
|
||
|
pfnCustomCompare = lstrcmpi;
|
||
|
m_pfnCompare = pfnCustomCompare;
|
||
|
}
|
||
|
|
||
|
CSortedStringArray::~CSortedStringArray()
|
||
|
{
|
||
|
for (int iString = m_cStrings-1; iString >= 0; iString--)
|
||
|
{
|
||
|
delete [] ((LPBYTE)m_prgStrings[iString] - sizeof(DWORD));
|
||
|
}
|
||
|
SafeFree((void**)&m_prgStrings);
|
||
|
}
|
||
|
|
||
|
int CSortedStringArray::Add(LPCTSTR psz, DWORD dwData)
|
||
|
{
|
||
|
for (int iItem = 0; iItem < m_cStrings; iItem++)
|
||
|
{
|
||
|
if ((*m_pfnCompare)(psz, m_prgStrings[iItem]) < 0)
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (SafeGrowArray((void**)&m_prgStrings, (UINT*)&m_maxStrings, (UINT)m_cStrings+1, 40, sizeof(LPTSTR)))
|
||
|
{
|
||
|
int cch = lstrlen(psz);
|
||
|
LPTSTR pszNew = new TCHAR[ (cch+1)*sizeof(TCHAR) + sizeof(DWORD) ];
|
||
|
if (pszNew)
|
||
|
{
|
||
|
memmove(&m_prgStrings[iItem+1], &m_prgStrings[iItem], (m_cStrings - iItem) * sizeof(LPTSTR));
|
||
|
*((DWORD*)pszNew) = dwData;
|
||
|
pszNew += sizeof(DWORD) / sizeof(TCHAR);
|
||
|
lstrcpy(pszNew, psz);
|
||
|
m_prgStrings[iItem] = pszNew;
|
||
|
|
||
|
m_cStrings++;
|
||
|
return iItem;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
SORTSTRING_COMPARE_PROC CSortedStringArray::_pfnCompare;
|
||
|
|
||
|
int __cdecl CSortedStringArray::_crtCompareHelper(const void* elem1, const void* elem2)
|
||
|
{
|
||
|
return _pfnCompare(*((LPCTSTR*)elem1), *((LPCTSTR*)elem2));
|
||
|
}
|
||
|
|
||
|
int CSortedStringArray::Find(LPCTSTR pszString) const
|
||
|
{
|
||
|
// REVIEW: This isn't safe if this function is called on multiple threads
|
||
|
_pfnCompare = m_pfnCompare;
|
||
|
LPTSTR* pResult = (LPTSTR*)bsearch(&pszString, m_prgStrings, m_cStrings, sizeof(LPTSTR), _crtCompareHelper);
|
||
|
if (pResult == NULL)
|
||
|
return -1;
|
||
|
else
|
||
|
return (int)(pResult - m_prgStrings);
|
||
|
}
|