NT4/private/windows/win4help/common/ctable.cpp
2020-09-30 17:12:29 +02:00

1234 lines
27 KiB
C++

/************************************************************************
* *
* CTABLE.CPP *
* *
* Copyright (C) Microsoft Corporation 1993-1994 *
* All Rights reserved. *
* *
************************************************************************/
#include "stdafx.h"
#ifndef _CTABLE_INCLUDED
#include "ctable.h"
#endif
const int TABLE_ALLOC_SIZE = 4096; // allocate in page increments
const int MAX_POINTERS = (2048 * 1024); // 2 meg, 524,288 strings
const int MAX_STRINGS = (10 * 1024 * 1024) - 4096L; // 10 megs
// Align on 32 bits for Intel, 64 bits for MIPS
#ifdef _X86_
const int ALIGNMENT = 4;
#else
const int ALIGNMENT = 8;
#endif
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/***************************************************************************
FUNCTION: CreateTable
PURPOSE: Creates a table with the specified initial size
COMMENTS:
MODIFICATION DATES:
11-Dec-1990 [ralphw]
***************************************************************************/
CTable::CTable()
{
InitializeTable();
}
/***************************************************************************
FUNCTION: =
PURPOSE: Copies a table -- only works with tables containing ONLY
strings. Won't work with tables that combined data with
the strings.
PARAMETERS:
tblSrc
RETURNS:
COMMENTS:
MODIFICATION DATES:
26-Mar-1994 [ralphw]
***************************************************************************/
const CTable& CTable::operator =(const CTable& tblSrc)
{
Empty();
return (*this += tblSrc);
}
/***************************************************************************
FUNCTION: +=
PURPOSE: Appends the contents of a table to this table -- only works
with tables containing ONLY strings. Won't work with tables
that combined data with the strings.
PARAMETERS:
tblSrc
RETURNS:
COMMENTS:
MODIFICATION DATES:
26-Mar-1994 [ralphw]
***************************************************************************/
const CTable& CTable::operator +=(const CTable& tblSrc)
{
int srcpos = 1;
while (srcpos < tblSrc.endpos) {
if (endpos >= maxpos)
IncreaseTableBuffer();
if ((ppszTable[endpos] =
TableMalloc(strlen(tblSrc.ppszTable[srcpos]) + 1)) == NULL) {
OOM();
return *this;
}
strcpy(ppszTable[endpos++], tblSrc.ppszTable[srcpos++]);
}
return *this;
}
/***************************************************************************
FUNCTION: ~CTable
PURPOSE: Close the table and free all memory associated with it
RETURNS:
COMMENTS:
MODIFICATION DATES:
26-Feb-1990 [ralphw]
27-Mar-1990 [ralphw]
Pass the address of the handle, so that we can set it to NULL.
This eliminates the chance of using a handle after it's memory
has been freed.
***************************************************************************/
CTable::~CTable(void)
{
if (pszBase) {
VirtualFree(pszBase, cbStrings, MEM_DECOMMIT);
VirtualFree(pszBase, 0, MEM_RELEASE);
}
if (ppszTable) {
VirtualFree(ppszTable, cbPointers, MEM_DECOMMIT);
VirtualFree(ppszTable, 0, MEM_RELEASE);
}
}
/***************************************************************************
FUNCTION: CTable::Empty
PURPOSE: Empties the current table by freeing all memory, then
recreating the table using the default size
PARAMETERS:
void
RETURNS:
COMMENTS:
MODIFICATION DATES:
22-Feb-1994 [ralphw]
***************************************************************************/
void STDCALL CTable::Empty(void)
{
if (pszBase) {
VirtualFree(pszBase, cbStrings, MEM_DECOMMIT);
VirtualFree(pszBase, 0, MEM_RELEASE);
}
if (ppszTable) {
VirtualFree(ppszTable, cbPointers, MEM_DECOMMIT);
VirtualFree(ppszTable, 0, MEM_RELEASE);
}
InitializeTable();
}
/***************************************************************************
FUNCTION: GetString
PURPOSE: get a line from the table
RETURNS: FALSE if there are no more lines
COMMENTS:
If no strings have been placed into the table, the return value
is FALSE.
MODIFICATION DATES:
01-Jan-1990 [ralphw]
***************************************************************************/
BOOL STDCALL CTable::GetString(PSTR pszDst)
{
*pszDst = 0; // clear the line no matter what happens
if (curpos >= endpos)
return FALSE;
strcpy(pszDst, (PCSTR) ppszTable[curpos++]);
return TRUE;
}
BOOL STDCALL CTable::GetString(PSTR pszDst, int pos)
{
*pszDst = 0; // clear the line no matter what happens
if (pos >= endpos || pos == 0)
return FALSE;
strcpy(pszDst, (PCSTR) ppszTable[pos]);
return TRUE;
}
BOOL STDCALL CTable::GetIntAndString(int* plVal, PSTR pszDst)
{
*pszDst = 0; // clear the line no matter what happens
if (curpos >= endpos)
return FALSE;
*plVal = *(int *) ppszTable[curpos];
strcpy(pszDst, (PCSTR) ppszTable[curpos++] + sizeof(int));
return TRUE;
}
BOOL FASTCALL CTable::GetInt(int* plVal)
{
if (curpos >= endpos)
return FALSE;
*plVal = *(int *) ppszTable[curpos++];
return TRUE;
}
/***************************************************************************
FUNCTION: CTable::RemoveString
PURPOSE: Removes the string from the table
PARAMETERS:
pos
RETURNS:
COMMENTS:
Note that this does NOT free the memory used by the string, it
simply removes the pointer to the allocated memory. The memory
will be freed when the table is freed.
REVIEW: we could keep a free list of freed memory that would include
strings that were removed, and strings that were replaced where
the replaced string ended up being larger then the original.
MODIFICATION DATES:
21-Feb-1994 [ralphw]
***************************************************************************/
void STDCALL CTable::RemoveString(int pos)
{
if (pos > endpos)
return;
if (pos < endpos)
memcpy(&ppszTable[pos], &ppszTable[pos + 1],
sizeof(PSTR) * (endpos - pos));
endpos--;
}
BOOL STDCALL CTable::InsertString(const char* pszString, int pos)
{
if (pos > endpos)
return FALSE;
if (pos < 1)
pos = 1;
if (endpos + 1 >= maxpos)
IncreaseTableBuffer();
// nake a hole for the new entry
memmove(&ppszTable[pos + 1], &ppszTable[pos],
sizeof(PSTR) * (endpos - pos));
endpos++;
if ((ppszTable[pos] =
TableMalloc(strlen(pszString) + 1)) == NULL)
return FALSE; // this will be really, really bad...
strcpy(ppszTable[pos], pszString);
return TRUE;
}
/***************************************************************************
FUNCTION: AddString
PURPOSE: Add a string to a table
RETURNS:
COMMENTS:
MODIFICATION DATES:
01-Jan-1990 [ralphw]
***************************************************************************/
int STDCALL CTable::AddString(const char * pszString)
{
if (endpos >= maxpos)
IncreaseTableBuffer();
if ((ppszTable[endpos] =
TableMalloc(strlen(pszString) + 1)) == NULL)
return 0;
strcpy(ppszTable[endpos], pszString);
return endpos++;
}
int STDCALL CTable::AddData(int cb, const void* pdata)
{
if (endpos >= maxpos)
IncreaseTableBuffer();
if ((ppszTable[endpos] = TableMalloc(cb)) == NULL)
return 0;
memcpy(ppszTable[endpos], pdata, cb);
return endpos++;
}
int STDCALL CTable::AddIntAndString(int lVal, PCSTR pszString)
{
if (endpos >= maxpos)
IncreaseTableBuffer();
if ((ppszTable[endpos] =
TableMalloc(strlen(pszString) + 1 + sizeof(int))) == NULL)
return 0;
*(int*) ppszTable[endpos] = lVal;
strcpy(ppszTable[endpos] + sizeof(int), pszString);
return endpos++;
}
/***************************************************************************
FUNCTION: IncreaseTableBuffer
PURPOSE: Called when we need more room for string pointers
PARAMETERS:
RETURNS:
COMMENTS:
MODIFICATION DATES:
23-Feb-1992 [ralphw]
***************************************************************************/
void STDCALL CTable::IncreaseTableBuffer(void)
{
if (!VirtualAlloc((PBYTE) ppszTable + cbPointers, TABLE_ALLOC_SIZE,
MEM_COMMIT, PAGE_READWRITE)) {
OOM();
return;
}
cbPointers += TABLE_ALLOC_SIZE;
maxpos = cbPointers / sizeof(PSTR);
}
/***************************************************************************
FUNCTION: TableMalloc
PURPOSE: Suballocate memory
RETURNS:
pointer to the memory
COMMENTS:
Instead of allocating memory for each string, memory is used from 4K
blocks. When the table is freed, all memory is freed as a single
unit. This has the advantage of speed for adding strings, speed for
freeing all strings, and low memory overhead to save strings.
MODIFICATION DATES:
26-Feb-1990 [ralphw]
26-Mar-1994 [ralphw]
Ported to 32-bits
***************************************************************************/
PSTR STDCALL CTable::TableMalloc(int cb)
{
/*
* Align allocation request so that all allocations fall on an
* alignment boundary (32 bits for Intel, 64 bits for MIPS).
*/
cb = (cb & (ALIGNMENT - 1)) ?
cb / ALIGNMENT * ALIGNMENT + ALIGNMENT : cb;
if (CurOffset + cb >= cbStrings) {
int cbNew = cbStrings + TABLE_ALLOC_SIZE;
while (cbNew < CurOffset + cb)
cbNew += TABLE_ALLOC_SIZE;
// We rely on VirtualAlloc to fail if cbStrings exceeds MAX_STRINGS
if (!VirtualAlloc(pszBase + cbStrings, cbNew - cbStrings,
MEM_COMMIT, PAGE_READWRITE)) {
OOM();
return NULL;
}
cbStrings = cbNew;
}
int offset = CurOffset;
CurOffset += cb;
return pszBase + offset;
}
/***************************************************************************
FUNCTION: SetPosition
PURPOSE: Sets the position for reading from the table
RETURNS:
COMMENTS:
MODIFICATION DATES:
26-Feb-1990 [ralphw]
16-Oct-1990 [ralphw]
If table position is to large, set to the end of the table,
not the last line.
***************************************************************************/
BOOL FASTCALL CTable::SetPosition(int pos)
{
if (pos >= endpos)
pos = endpos;
curpos = ((pos == 0) ? 1 : pos);
return TRUE;
}
/***************************************************************************
FUNCTION: IsStringInTable
PURPOSE: Determine if the string is already in the table
RETURNS: position if the string is already in the table,
0 if the string isn't found
COMMENTS:
The comparison is case-insensitive, and is considerably
slower then IsCSStringInTable
MODIFICATION DATES:
02-Mar-1990 [ralphw]
***************************************************************************/
int STDCALL CTable::IsStringInTable(PCSTR pszString)
{
int i;
size_t cbString = strlen(pszString);
char chLower;
char chUpper;
if (!lcid) {
/*
* Skip over as many strings as we can by just checking the first
* letter. This avoids the overhead of the _stricmp() function call.
*/
chLower = tolower(*pszString);
chUpper = toupper(*pszString);
for (i = 1; i < endpos; i++) {
if ((*ppszTable[i] == chLower || *ppszTable[i] == chUpper) &&
strlen(ppszTable[i]) == cbString &&
_stricmp(ppszTable[i], pszString) == 0)
return i;
}
}
else { // Use NLS string comparison
char szBuf[2];
LCMapString(lcid, LCMAP_LOWERCASE, pszString, 1, szBuf, 1);
chLower = szBuf[0];
LCMapString(lcid, LCMAP_UPPERCASE, pszString, 1, szBuf, 1);
chUpper = szBuf[0];
for (i = 1; i < endpos; i++) {
/*
* We assume that most of the time we will not find the
* string. We try to discover that the string doesn't
* match as quickly as possible. First we check the first
* letter, and if that doesn't match, try the next string.
* If the first letter matches, then confirm that the
* strings are the same length. Only if the first character
* matches and the strings have the same length do we
* call the time-comsuming CompareStringA function.
*/
if ((*ppszTable[i] == chLower || *ppszTable[i] == chUpper) &&
strlen(ppszTable[i]) == cbString &&
CompareStringA(lcid, fsCompareI | NORM_IGNORECASE,
pszString, cbString, ppszTable[i], cbString) == 2)
return i;
}
}
return 0;
}
/***************************************************************************
FUNCTION: CTable::IsCSStringInTable
PURPOSE: Case-sensitive search for a string in a table
PARAMETERS:
pszString
RETURNS:
COMMENTS:
MODIFICATION DATES:
12-Jun-1994 [ralphw]
***************************************************************************/
int STDCALL CTable::IsCSStringInTable(PCSTR pszString)
{
char szBuf[sizeof(DWORD) + 1];
DWORD cmp;
if (strlen(pszString) < sizeof(DWORD)) {
memset(szBuf, 0, sizeof(DWORD) + 1);
strcpy(szBuf, pszString);
cmp = *(DWORD*) szBuf;
}
else
cmp = *(DWORD*) pszString;
for (int i = 1; i < endpos; i++) {
if (cmp == *(DWORD*) ppszTable[i] &&
strcmp(ppszTable[i], pszString) == 0)
return i;
}
return 0;
}
/***************************************************************************
FUNCTION: CTable::IsStringInTable
PURPOSE: Find case-sensitive string in the table
PARAMETERS:
hash
pszString
RETURNS:
COMMENTS:
MODIFICATION DATES:
05-Feb-1995 [ralphw]
***************************************************************************/
int STDCALL CTable::IsStringInTable(HASH hash, PCSTR pszString)
{
for (int i = 1; i < endpos; i++) {
if (hash == *(HASH *) ppszTable[i]) {
if (strcmp(ppszTable[i] + sizeof(HASH), pszString) == 0)
return i;
}
}
return 0;
}
/***************************************************************************
FUNCTION: CTable::IsHashInTable
PURPOSE: Find out if the hash number exists in the table
PARAMETERS:
hash
RETURNS:
COMMENTS:
Assumes case-insensitive hash number, and no collisions
MODIFICATION DATES:
05-Feb-1995 [ralphw]
***************************************************************************/
int STDCALL CTable::IsHashInTable(HASH hash)
{
for (int i = 1; i < endpos; i++) {
if (hash == *(HASH *) ppszTable[i])
return i;
}
return 0;
}
/***************************************************************************
FUNCTION: ReplaceString
PURPOSE: Replaces the current string at the specified position with
a new string
RETURNS: TRUE if the function is succesful, FALSE if an error occurred.
An error occurs if the specified position is beyond the end
of the table.
COMMENTS:
If the new string is the same size or smaller then the original
string, then it is copied over the original string. Otherwise,
a new string buffer is allocated, and the pointer for the specified
position is changed to point to the new buffer. Note that the old
string's memory is not freed -- it simply becomes unavailable.
MODIFICATION DATES:
08-Oct-1991 [ralphw]
Updated to transfer associated line number
***************************************************************************/
BOOL STDCALL CTable::ReplaceString(const char * pszNewString, int pos)
{
if (pos > endpos)
return FALSE;
if (pos == 0)
pos = 1;
/*
* If the new string is larger then the old string, then allocate a
* new buffer for it.
*/
if (strlen(pszNewString) > (size_t) strlen(ppszTable[pos])) {
if ((ppszTable[pos] =
TableMalloc(strlen(pszNewString) + 1)) == NULL)
return FALSE;
}
strcpy(ppszTable[pos], pszNewString);
return TRUE;
}
BOOL STDCALL CTable::ReplaceString(const char * pszNewString, const char * pszOldString)
{
int pos = IsCSStringInTable(pszOldString);
if (pos)
return ReplaceString(pszNewString, pos);
else
return FALSE;
}
/***************************************************************************
FUNCTION: AddDblToTable
PURPOSE: Add two strings to the table
RETURNS:
COMMENTS:
This function checks to see if the second string has already been
added, and if so, it merely sets the pointer to the original string,
rather then allocating memory for a new copy of the string.
MODIFICATION DATES:
08-Mar-1991 [ralphw]
***************************************************************************/
int STDCALL CTable::AddString(const char *pszStr1, const char *pszStr2)
{
int ui;
AddString(pszStr1);
if ((ui = IsSecondaryStringInTable(pszStr2)) != 0) {
if (endpos >= maxpos)
IncreaseTableBuffer();
ppszTable[endpos++] = ppszTable[ui];
return endpos - 1;
}
else {
return AddString(pszStr2);
}
}
/***************************************************************************
FUNCTION: IsPrimaryStringInTable
PURPOSE:
RETURNS:
COMMENTS:
MODIFICATION DATES:
03-Apr-1991 [ralphw]
***************************************************************************/
int STDCALL CTable::IsPrimaryStringInTable(const char *pszString)
{
int i;
size_t cbString = strlen(pszString);
char chLower;
char chUpper;
if (!lcid) {
/*
* Skip over as many strings as we can by just checking the first
* letter. This avoids the overhead of the _stricmp() function call.
*/
chLower = tolower(*pszString);
chUpper = toupper(*pszString);
for (i = 1; i < endpos; i += 2) {
if ((*ppszTable[i] == chLower || *ppszTable[i] == chUpper) &&
strlen(ppszTable[i]) == cbString &&
_stricmp(ppszTable[i], pszString) == 0)
return i;
}
}
else { // Use NLS string comparison
char szBuf[2];
LCMapString(lcid, LCMAP_LOWERCASE, pszString, 1, szBuf, 1);
chLower = szBuf[0];
LCMapString(lcid, LCMAP_UPPERCASE, pszString, 1, szBuf, 1);
chUpper = szBuf[0];
for (i = 1; i < endpos; i += 2) {
/*
* We assume that most of the time we will not find the
* string. We try to discover that the string doesn't
* match as quickly as possible. First we check the first
* letter, and if that doesn't match, try the next string.
* If the first letter matches, then confirm that the
* strings are the same length. Only if the first character
* matches and the strings have the same length do we
* call the time-comsuming CompareStringA function.
*/
if ((*ppszTable[i] == chLower || *ppszTable[i] == chUpper) &&
strlen(ppszTable[i]) == cbString &&
CompareStringA(lcid, fsCompareI | NORM_IGNORECASE,
pszString, cbString, ppszTable[i], cbString) == 2)
return i;
}
}
return 0;
}
/***************************************************************************
FUNCTION: IsSecondaryStringInTable
PURPOSE:
RETURNS:
COMMENTS:
MODIFICATION DATES:
03-Apr-1991 [ralphw]
***************************************************************************/
int STDCALL CTable::IsSecondaryStringInTable(const char *pszString)
{
int i;
size_t cbString = strlen(pszString);
char chLower;
char chUpper;
if (!lcid) {
/*
* Skip over as many strings as we can by just checking the first
* letter. This avoids the overhead of the _stricmp() function call.
*/
chLower = tolower(*pszString);
chUpper = toupper(*pszString);
for (i = 2; i < endpos; i++) {
if ((*ppszTable[i] == chLower || *ppszTable[i] == chUpper) &&
strlen(ppszTable[i]) == cbString &&
_stricmp(ppszTable[i], pszString) == 0)
return i;
}
}
else { // Use NLS string comparison
char szBuf[2];
LCMapString(lcid, LCMAP_LOWERCASE, pszString, 1, szBuf, 1);
chLower = szBuf[0];
LCMapString(lcid, LCMAP_UPPERCASE, pszString, 1, szBuf, 1);
chUpper = szBuf[0];
for (i = 2; i < endpos; i++) {
/*
* We assume that most of the time we will not find the
* string. We try to discover that the string doesn't
* match as quickly as possible. First we check the first
* letter, and if that doesn't match, try the next string.
* If the first letter matches, then confirm that the
* strings are the same length. Only if the first character
* matches and the strings have the same length do we
* call the time-comsuming CompareStringA function.
*/
if ((*ppszTable[i] == chLower || *ppszTable[i] == chUpper) &&
strlen(ppszTable[i]) == cbString &&
CompareStringA(lcid, fsCompareI | NORM_IGNORECASE,
pszString, cbString, ppszTable[i], cbString) == 2)
return i;
}
}
return 0;
}
/***************************************************************************
FUNCTION: SortTable
PURPOSE: Sort the current buffer
RETURNS:
COMMENTS:
MODIFICATION DATES:
01-Jan-1990 [ralphw]
***************************************************************************/
void CTable::SortTable(void)
{
if (endpos < 3) // don't sort one entry
return;
// We do this for speed and because JChicago build 122 gives incorrect
// results for CompareStringA
if (lcid && LANGIDFROMLCID(lcid) != 0x0409) {
fsSortFlags = fsCompare;
doLcidSort(1, (int) endpos - 1);
}
else
doSort(1, (int) endpos - 1);
}
/***************************************************************************
FUNCTION: doSort
PURPOSE:
RETURNS:
COMMENTS:
Use QSORT algorithm
MODIFICATION DATES:
27-Mar-1990 [ralphw]
***************************************************************************/
void STDCALL CTable::doSort(int left, int right)
{
int last;
if (left >= right) // return if nothing to sort
return;
// REVIEW: should be a flag before trying this -- we may already know
// that they won't be in order.
// Only sort if there are elements out of order.
j = right - 1;
while (j >= left) {
// REVIEW: lstrcmp is NOT case-sensitive!!!
if (strcmp(ppszTable[j] + SortColumn,
ppszTable[j + 1] + SortColumn) > 0)
break;
else
j--;
}
if (j < left)
return;
sTmp = (left + right) / 2;
pszTmp = ppszTable[left];
ppszTable[left] = ppszTable[sTmp];
ppszTable[sTmp] = pszTmp;
last = left;
for (j = left + 1; j <= right; j++) {
if (strcmp(ppszTable[j] + SortColumn,
ppszTable[left] + SortColumn) < 0) {
sTmp = ++last;
pszTmp = ppszTable[sTmp];
ppszTable[sTmp] = ppszTable[j];
ppszTable[j] = pszTmp;
}
}
pszTmp = ppszTable[left];
ppszTable[left] = ppszTable[last];
ppszTable[last] = pszTmp;
/*
* REVIEW: we need to add some sort of stack depth check to prevent
* overflow of the stack.
*/
if (left < last - 1)
doSort(left, last - 1);
if (last + 1 < right)
doSort(last + 1, right);
}
/***************************************************************************
FUNCTION: CTable::doLcidSort
PURPOSE: Sort using CompareStringA
PARAMETERS:
left
right
RETURNS:
COMMENTS:
MODIFICATION DATES:
03-Jun-1994 [ralphw]
***************************************************************************/
void STDCALL CTable::doLcidSort(int left, int right)
{
int last;
if (left >= right) // return if nothing to sort
return;
// REVIEW: should be a flag before trying this -- we may already know
// that they won't be in order.
// Only sort if there are elements out of order.
j = right - 1;
while (j >= left) {
if (CompareStringA(lcid, fsSortFlags, ppszTable[j] + SortColumn, -1,
ppszTable[j + 1] + SortColumn, -1) > 2)
break;
else
j--;
}
if (j < left)
return;
sTmp = (left + right) / 2;
pszTmp = ppszTable[left];
ppszTable[left] = ppszTable[sTmp];
ppszTable[sTmp] = pszTmp;
last = left;
for (j = left + 1; j <= right; j++) {
if (CompareStringA(lcid, fsSortFlags, ppszTable[j] + SortColumn, -1,
ppszTable[left] + SortColumn, -1) < 2) {
sTmp = ++last;
pszTmp = ppszTable[sTmp];
ppszTable[sTmp] = ppszTable[j];
ppszTable[j] = pszTmp;
}
}
pszTmp = ppszTable[left];
ppszTable[left] = ppszTable[last];
ppszTable[last] = pszTmp;
/*
* REVIEW: we need to add some sort of stack depth check to prevent
* overflow of the stack.
*/
if (left < last - 1)
doLcidSort(left, last - 1);
if (last + 1 < right)
doLcidSort(last + 1, right);
}
/***************************************************************************
FUNCTION: SortTablei
PURPOSE: Case-insensitive sort
RETURNS:
COMMENTS:
MODIFICATION DATES:
01-Jan-1990 [ralphw]
***************************************************************************/
void CTable::SortTablei(void)
{
int pos;
if (endpos < 3) // don't sort one entry
return;
if (lcid) {
fsSortFlags = fsCompareI | NORM_IGNORECASE;
doLcidSort(1, endpos - 1);
for (pos = 1; pos < endpos - 2; pos++) {
if (strlen(ppszTable[pos] + SortColumn) ==
strlen(ppszTable[pos + 1] + SortColumn) &&
CompareStringA(lcid, fsCompare, ppszTable[pos] + SortColumn, -1,
ppszTable[pos + 1] + SortColumn, -1) == 3) {
PSTR pszTmp = ppszTable[pos];
ppszTable[pos] = ppszTable[pos + 1];
ppszTable[pos + 1] = pszTmp;
if (pos > 2)
pos -= 2;
}
}
}
else
doSorti(1, (int) endpos - 1);
}
/***************************************************************************
FUNCTION: doSort
PURPOSE:
RETURNS:
COMMENTS:
Use QSORT algorithm
MODIFICATION DATES:
27-Mar-1990 [ralphw]
***************************************************************************/
void STDCALL CTable::doSorti(int left, int right)
{
int last;
if (left >= right) // return if nothing to sort
return;
// REVIEW: should be a flag before trying this -- we may already know
// that they won't be in order.
// Only sort if there are elements out of order.
j = right - 1;
while (j >= left) {
// REVIEW: lstrcmp is NOT case-sensitive!!!
if (_stricmp(ppszTable[j] + SortColumn,
ppszTable[j + 1] + SortColumn) > 0)
break;
else
j--;
}
if (j < left)
return;
sTmp = (left + right) / 2;
pszTmp = ppszTable[left];
ppszTable[left] = ppszTable[sTmp];
ppszTable[sTmp] = pszTmp;
last = left;
for (j = left + 1; j <= right; j++) {
if (_stricmp(ppszTable[j] + SortColumn,
ppszTable[left] + SortColumn) < 0) {
sTmp = ++last;
pszTmp = ppszTable[sTmp];
ppszTable[sTmp] = ppszTable[j];
ppszTable[j] = pszTmp;
}
}
pszTmp = ppszTable[left];
ppszTable[left] = ppszTable[last];
ppszTable[last] = pszTmp;
/*
* REVIEW: we need to add some sort of stack depth check to prevent
* overflow of the stack.
*/
if (left < last - 1)
doSorti(left, last - 1);
if (last + 1 < right)
doSorti(last + 1, right);
}
/***************************************************************************
FUNCTION: CTable::InitializeTable
PURPOSE: Initializes the table
PARAMETERS:
uInitialSize
RETURNS:
COMMENTS:
Called by constructor and Empty()
MODIFICATION DATES:
23-Feb-1994 [ralphw]
***************************************************************************/
void STDCALL CTable::InitializeTable(void)
{
// Allocate memory for the strings
pszBase = (PSTR) VirtualAlloc(NULL, MAX_STRINGS, MEM_RESERVE,
PAGE_READWRITE);
if (!pszBase) {
OOM();
return;
}
if (!VirtualAlloc(pszBase, cbStrings = TABLE_ALLOC_SIZE, MEM_COMMIT,
PAGE_READWRITE))
OOM();
// Allocate memory for the string pointers
ppszTable = (PSTR *) VirtualAlloc(NULL, MAX_POINTERS, MEM_RESERVE,
PAGE_READWRITE);
if (!ppszTable) {
OOM();
return;
}
if (!VirtualAlloc(ppszTable, cbPointers = TABLE_ALLOC_SIZE, MEM_COMMIT,
PAGE_READWRITE))
OOM();
curpos = 1; // set to one so that sorting works
endpos = 1;
maxpos = cbPointers / sizeof(PSTR);
SortColumn = 0;
CurOffset = 0;
lcid = 0;
}
void FASTCALL CTable::SetSorting(LCID lcid, DWORD fsCompareI, DWORD fsCompare)
{
this->lcid = lcid;
this->fsCompareI = fsCompareI;
this->fsCompare = fsCompare;
}
void STDCALL CTable::RemoveDuplicateHashStrings(void)
{
for (int i = 1; i < endpos - 2; i++) {
if (*(HASH *) ppszTable[i] == *(HASH *) ppszTable[i + 1] &&
(strcmp(ppszTable[i] + sizeof(HASH),
ppszTable[i + 1] + sizeof(HASH)) == 0)) {
HASH hash = *(HASH *) ppszTable[i];
PSTR psz = ppszTable[i] + sizeof(HASH);
int j = i + 2;
while (j < endpos && hash == *(HASH *) ppszTable[j] &&
(strcmp(psz, ppszTable[j] + sizeof(HASH)) == 0))
j++;
j--;
memcpy(&ppszTable[i], &ppszTable[j],
sizeof(PSTR) * (endpos - (j - 1)));
endpos -= (j - i);
}
}
}