/* Filename: WVString.cpp */

/*
* $Id: wvstring.cpp 1.8 1997/03/18 19:30:04 dumoulin Exp $
 */

#include <windows.h>
#include <windowsx.h>
#include "wvglob.h"
#include "winvn.h"

#pragma hdrstop

#include <limits.h>
#include "wvclass.h"

// WVString memory management

WMemPool WVString::m_ClassPool(sizeof(WVString), POOLBLOCKSIZE / sizeof(WVString));

WMemPool Pool16  (  16, POOLBLOCKSIZE /  16);
WMemPool Pool24  (  24, POOLBLOCKSIZE /  24);
WMemPool Pool32  (  32, POOLBLOCKSIZE /  32);
WMemPool Pool48  (  48, POOLBLOCKSIZE /  48);
WMemPool Pool64  (  64, POOLBLOCKSIZE /  64);
WMemPool Pool80  (  80, POOLBLOCKSIZE /  80);
WMemPool Pool96  (  96, POOLBLOCKSIZE /  96);
WMemPool Pool112 ( 112, POOLBLOCKSIZE / 112);
WMemPool Pool128 ( 128, POOLBLOCKSIZE / 128);
WMemPool Pool160 ( 160, POOLBLOCKSIZE / 160);
WMemPool Pool192 ( 192, POOLBLOCKSIZE / 192);
WMemPool Pool256 ( 256, POOLBLOCKSIZE / 256);
WMemPool Pool512 ( 512, POOLBLOCKSIZE / 512);
WMemPool Pool1024(1024, POOLBLOCKSIZE /1024);
WMemPool Pool2048(2048, POOLBLOCKSIZE /2048);


LATEST Latest;

void*WVString::operator new(size_t size)
{
#ifdef _DEBUG
  if(size != sizeof(WVString))
  {
    DEBUG_BREAK; //  derived classes must provide their own operator new
  }
#endif

  return m_ClassPool.AllocElement();
}


void WVString::operator delete(void*p)
{
#ifdef _DEBUG
  if(p == 0)  // this should never happen...
  {
    DEBUG_BREAK;
    return;
  }
#endif
  m_ClassPool.FreeElement(p);
}


WVString::WVString(const char*s, const uint32 uLen)
{
  if(s)
  {
    if(uLen)
    {
      m_data = new char[1 + uLen];
      if(m_data)
      {
        strncpy(m_data, s, uLen);
        m_data[uLen] = '\0';
      }
    }
    else
    {
      m_data = new char[1+strlen(s)];
      if(m_data)
        strcpy(m_data, s);
    }
  }
  else
 {
    m_data = new char[1];
    if(m_data)
      *m_data = '\0';
  }
}


//WVString::WVString(const WVString&rhs)
//{
//  m_data = new char[1 + strlen(rhs.m_data)];
//  if(m_data)
//    strcpy(m_data, rhs.m_data);
//}
//    Add a few extra checks - JD 2/14/97

WVString::WVString(const WVString&rhs)
{
	int ilen;

	if (rhs.m_data) 
	{
		ilen = strlen(rhs.m_data);
		if (ilen > 0) 
		{
			m_data = new char[1 + strlen(rhs.m_data)];
			if(m_data)
				strcpy(m_data, rhs.m_data);
		}
	}
	else 
	{
		m_data = new char[1];
		if(m_data)
			*m_data = '\0';
	}
}



WVString::WVString(const WVString&lhs, const WVString&rhs)
{
	m_data = new char[1 + strlen(lhs.m_data) + strlen(rhs.m_data)];
	if(m_data)
	{
		strcpy(m_data, lhs.m_data);
		strcat(m_data, rhs.m_data);
	}
}


WVString::~WVString()
{
	delete [] m_data;
}


WVString& WVString::operator=(const WVString& rhs)
{
	size_t iNewSize;

	//if(strcmp(m_data, rhs.m_data) != 0) // value compare
	if(this != &rhs) // address compare
	{
		if(rhs.m_data) 
		{
			iNewSize = 1 + strlen(rhs.m_data);
			if(AllocSize() < iNewSize)
			{
				delete [] m_data;
				m_data = new char[iNewSize];
			}
			if(m_data)
				strcpy(m_data, rhs.m_data);
		}
		else
		{
			if(!m_data)
			{
				m_data = new char[1];
			}
			if(m_data)
				*m_data = '\0';
		}
	}
	return *this;
}


WVString& WVString::operator=(const char* rhs)
{
	size_t iNewSize; 

	//if((rhs) && (strlen(rhs) > 0))           // JD 2/14/97
	if(rhs)  // okay if strlen(rhs) == 0
	{
		iNewSize = 1 + strlen(rhs);
		if(AllocSize() < iNewSize)
		{
			delete [] m_data;
			m_data = new char[iNewSize];
		}
		if(m_data)
			strcpy(m_data, rhs);
	}
	else
	{
		if(!m_data)
		{
			m_data = new char[1];
		}
		if(m_data)
			*m_data = '\0';
	}
	return *this;
}


WVString& WVString::operator+=(const WVString& rhs)
{
	char*tmp;
	size_t iNewSize = 1 + strlen(m_data) + strlen(rhs.m_data);

	if(iNewSize > AllocSize())
	{
		tmp = new char[iNewSize];
		if(tmp)
		{
			strcpy(tmp, m_data);
			strcat(tmp, rhs.m_data);
			delete [] m_data;
			m_data = tmp;
		}
	}
	else
	{
		strcat(m_data, rhs.m_data);
	}
	return *this;
}


WVString& WVString::operator+=(const char* rhs)
{
	if(rhs)
	{
		char*tmp;
		size_t iNewSize = 1 + strlen(m_data) + strlen(rhs);

		if(iNewSize > AllocSize())
		{
			tmp = new char[iNewSize];
			if(tmp)
			{
				strcpy(tmp, m_data);
				strcat(tmp, rhs);
				delete [] m_data;
				m_data = tmp;
			}
		}
		else
		{
			strcat(m_data, rhs);
		}
	}
	return *this;
}


size_t WVString::AllocSize()
{
	NewStruct* pNS = (NewStruct*) m_data;
	if(!pNS)
		return 0;
	pNS--;
	return pNS->iAllocSize; 
}


char *WVString::MakeBuffer(size_t size)
{
	if( AllocSize() <= size ) 
	{
		delete m_data;
		m_data = new char[ size + 1 ];
	}
	return (char *)m_data;
}

const char *WVSubjString::ParseFilename()
{
	if (bProcessed)
	{
		return m_filename;
	}
	else
	{
		int nStart;
		int nLen;

		const char *p =  ParseSubject(m_data, &nLen, &nFile, &nTotal, &nGroup, &nGroupTotal, NULL );
		if (p)
		{
			nStart = p - m_data;
			m_filename = WVString(p, nLen);
			bProcessed = true;
			return m_filename;
		}
		else
		{
			return NULL;	
		}
	}

}




/*

  C++ Memory management routines

  Written July 1996 H. Brydon

*/


// C++ fixed size memory pool implementation

WMemPool::WMemPool(uint32 uElementSize, unsigned uNumElements)
: m_FreeList(NULL), m_pBlock(NULL),
  m_uElmSize(((uElementSize + sizeof(WMemPool::MemPoolElement)-1) /
    sizeof(WMemPool::MemPoolElement)) * sizeof(WMemPool::MemPoolElement)),
  m_uBlkSize(uNumElements * m_uElmSize)
{
#ifdef _DEBUG
	if(!(m_uElmSize && m_uBlkSize))
    DEBUG_BREAK;
#endif
  //AllocBlock();
}


WMemPool::~WMemPool()
{
	MemPoolBlock*p;
	HANDLE hHeap = GetProcessHeap();
	while(m_pBlock)
	{
#ifdef DEBUGMEMUSAGE
		TRACE2("AllocBlock(): Block of size %u/%u freed\n",
		m_uElmSize, m_uBlkSize);
#endif
		p = m_pBlock->next;
		//delete m_pBlock;
		/*GlobalFreePtr(m_pBlock);*/
		HeapFree( hHeap , 0, m_pBlock);
		m_pBlock = p;
	}
}


void WMemPool::AllocBlock()  // 335.11
{
	size_t iSize = sizeof(MemPoolBlock) + m_uBlkSize;
	unsigned num;
#ifdef DEBUGFREEALLOC
	char *pch;
#endif

	num = m_uBlkSize/m_uElmSize;
	iSize = iSize + (num * 4);
	/*MemPoolBlock* pBlk = (MemPoolBlock *) GlobalAllocPtr(GMEM_FIXED, iSize);*/
	MemPoolBlock* pBlk= (MemPoolBlock *) HeapAlloc( GetProcessHeap(), 0, iSize);

	if(pBlk)
	{
#ifdef DEBUGMEMUSAGE
		TRACE3("AllocBlock(): Block of size %u/%u (%u total) allocated\n",
		m_uElmSize, m_uBlkSize, iSize);
#endif    
        pBlk->next = m_pBlock;
        m_pBlock = pBlk;
        MemPoolElement*pe = &pBlk->pe;
		

#ifdef DEBUGFREEALLOC
        num = m_uBlkSize/(m_uElmSize+4); //S.Yoshida FIX
#else
        num = m_uBlkSize/m_uElmSize;
#endif
		while(--num > 0)
        {
#ifdef DEBUGFREEALLOC
			pch = ((char *) pe + m_uElmSize );
			*pch = 'F';
			pe->next = (MemPoolElement*) ((char*) pe + m_uElmSize + 4 );
			pe = pe->next;
#else
			pe->next = (MemPoolElement*) ((char*) pe + m_uElmSize);
			pe = pe->next;
#endif
		}
#ifdef DEBUGFREEALLOC
		pch = ((char *) pe + m_uElmSize );
		*pch = 'F';
#endif
		pe->next = m_FreeList;
		m_FreeList = &pBlk->pe;
	}
#ifdef DEBUGMEMUSAGE
	else
	{
		TRACE1("AllocBlock(): No memory for block of size %u!\n", iSize);
		DEBUG_BREAK;
	}
#endif
}


void *wv_malloc( size_t iReqSize )
{
	size_t iGetSize;
	NewStruct*memory = NULL;
	if(iReqSize == 0)          
	{
		iReqSize = 1;
	}
	iGetSize = iReqSize + sizeof(NewStruct);

	if(iGetSize <= 16)
	{
		static size_t iAllocSize = 16 - sizeof(NewStruct);
		if(memory = (NewStruct*) Pool16.AllocElement())
		  memory->iAllocSize = iAllocSize;
	}
	else if(iGetSize <= 24)
	{
		static size_t iAllocSize = 24 - sizeof(NewStruct);
		if(memory = (NewStruct*) Pool24.AllocElement())
		  memory->iAllocSize = iAllocSize;
	}
	else if(iGetSize <= 32)
	{
		static size_t iAllocSize = 32 - sizeof(NewStruct);
		if(memory = (NewStruct*) Pool32.AllocElement())
		  memory->iAllocSize = iAllocSize;
	}
	else if(iGetSize <= 48)
	{
		static size_t iAllocSize = 48 - sizeof(NewStruct);
		if(memory = (NewStruct*) Pool48.AllocElement())
		  memory->iAllocSize = iAllocSize;
	}
	else if(iGetSize <= 64)
	{
		static size_t iAllocSize = 64 - sizeof(NewStruct);
		if(memory = (NewStruct*) Pool64.AllocElement())
		  memory->iAllocSize = iAllocSize;
	}
	else if(iGetSize <= 80)
	{
		static size_t iAllocSize = 80 - sizeof(NewStruct);
		if(memory = (NewStruct*) Pool80.AllocElement())
		  memory->iAllocSize = iAllocSize;
	}
	else if(iGetSize <= 96)
	{
		static size_t iAllocSize = 96 - sizeof(NewStruct);
		if(memory = (NewStruct*) Pool96.AllocElement())
		  memory->iAllocSize = iAllocSize;
	}
	else if(iGetSize <= 112)
	{
		static size_t iAllocSize = 112 - sizeof(NewStruct);
		if(memory = (NewStruct*) Pool112.AllocElement())
		  memory->iAllocSize = iAllocSize;
	}
	else if(iGetSize <= 128)
	{
		static size_t iAllocSize = 128 - sizeof(NewStruct);
		if(memory = (NewStruct*) Pool128.AllocElement())
		  memory->iAllocSize = iAllocSize;
	}
	else if(iGetSize <= 160)
	{
		static size_t iAllocSize = 160 - sizeof(NewStruct);
		if(memory = (NewStruct*) Pool160.AllocElement())
		  memory->iAllocSize = iAllocSize;
	}
	else if(iGetSize <= 192)
	{
		static size_t iAllocSize = 192 - sizeof(NewStruct);
		if(memory = (NewStruct*) Pool192.AllocElement())
		  memory->iAllocSize = iAllocSize;
	}
	else if(iGetSize <= 256)
	{
		static size_t iAllocSize = 256 - sizeof(NewStruct);
		if(memory = (NewStruct*) Pool256.AllocElement())
		  memory->iAllocSize = iAllocSize;
	}
	else if(iGetSize <= 512)
	{
		static size_t iAllocSize = 512 - sizeof(NewStruct);
		if(memory = (NewStruct*) Pool512.AllocElement())
		  memory->iAllocSize = iAllocSize;
	}
	else if(iGetSize <= 1024)
	{
		static size_t iAllocSize = 1024 - sizeof(NewStruct);
		if(memory = (NewStruct*) Pool1024.AllocElement())
		  memory->iAllocSize = iAllocSize;
	}
	else if(iGetSize <= 2048)
	{
		static size_t iAllocSize = 2048 - sizeof(NewStruct);
		if(memory = (NewStruct*) Pool2048.AllocElement())
		  memory->iAllocSize = iAllocSize;
	}
	if (!memory)
	{
		/*if(memory = (NewStruct*) GlobalAllocPtr(GMEM_FIXED, iGetSize))*/
		if(memory = (NewStruct*) HeapAlloc( GetProcessHeap(), 0, iGetSize))
		{
#ifdef DEBUGMEMUSAGE
			TRACE2("operator new: Memory block of size %u/%u allocated\n",
			iReqSize, iGetSize);
#endif      
			memory->iAllocSize = iGetSize - sizeof(NewStruct);
		}
	}   
#ifdef DEBUGMEMUSAGE
	if(memory)
	{
		static uint32 iSeqNo = 0;
		memory->iSeqCtr = ++iSeqNo;
	}
#endif
	if (memory)
		return (void*) &memory[1];
	return NULL;
}

void * __cdecl operator new(size_t iReqSize)
{
	return wv_malloc( iReqSize );
}

#ifdef __GNUC__

void * __cdecl operator new[](size_t iReqSize)
{
	return wv_malloc( iReqSize );
}

void * __cdecl operator new[](size_t iReqSize, size_t ReqSize1)
{
	if (!iReqSize) iReqSize = 1;
	if (!ReqSize1) ReqSize1 = 1;
	return wv_malloc( iReqSize * ReqSize1 );
}

#else
// A Huge pointer version of the new operator to fix
// allocation problems with Win16. (JD 1/7/97)
#ifdef __WATCOMC__
/* Watcom follows the C++ standard (?) to overload new */
/* like described on page 131 ff. in: */
/* Microsoft Corporation: C++ Tutorial for MS-DOS and Windows Operating Systems, Version 8.0 */
/* Microsoft Corp., Redmond, Washington 98952-6399 */
/* german 2nd Edition by Microsoft Press Deutschland ISBN 3-86063-019-9 */
/* i.e. first parameter must exist and has to be size_t */
/* optional more parameters can follows, to call like: */
/* ptr = new(parm2,pram3 ..) type[parm1]; */
/* the first parameter passed through is calculated as parm1*sizeof(type) (Heirich19970602)*/
#ifdef _WIN32
 void *operator new (size_t ReqSize1, unsigned long lReqSize)
 { return new (lReqSize) char[ReqSize1]; }
 void *operator new [] (size_t ReqSize1, unsigned long lReqSize)
#else
 void *operator new (size_t ReqSize1, unsigned long lReqSize)
 { return new (lReqSize) char[ReqSize1]; }
 void *operator new [] (size_t ReqSize1, unsigned long lReqSize)
#endif
#else
#ifdef _WIN32
 void __far *operator new(size_t lReqSize, size_t ReqSize1)
#else
 void __huge *operator new(unsigned long lReqSize, size_t ReqSize1)
#endif
#endif
{
  size_t lGetSize;
  NewStruct*memory = NULL;
#ifdef __WATCOMC__
  if (ReqSize1 == 0)
  {
      ReqSize1 = 1;
  }
#else
  if(lReqSize == 0)          
  {
    lReqSize = 1;
  }
#endif
  lGetSize = (lReqSize * ReqSize1) + sizeof(NewStruct);

  /*if(memory = (NewStruct*) GlobalAllocPtr(GMEM_FIXED, lGetSize))*/
   if(memory = (NewStruct*) HeapAlloc( GetProcessHeap(), 0, lGetSize))

    {
#ifdef DEBUGMEMUSAGE
      TRACE2("operator new: Memory block of size %lu/%lu allocated\n",
        lReqSize, lGetSize);
#endif      
      memory->iAllocSize = lGetSize - sizeof(NewStruct);
    }
#ifdef DEBUGMEMUSAGE 
  if(memory)
  {
    static int iSeqNo = 0;
    memory->iSeqCtr = ++iSeqNo;
  } else {
    return NULL;
  }
#endif
  if (memory)
     return (void*) &memory[1];
  return NULL;
}


#endif

void wv_free(void*p)
{
	if(p)
	{
		NewStruct* pNS = (NewStruct*) p;
    
        pNS--;
		switch(pNS->iAllocSize)
		{
		case  16 - sizeof(NewStruct):
		  Pool16.FreeElement(pNS);
		  break;
		case  24 - sizeof(NewStruct):
		  Pool24.FreeElement(pNS);
		  break;
		case  32 - sizeof(NewStruct):
		  Pool32.FreeElement(pNS);
		  break;
		case  48 - sizeof(NewStruct):
		  Pool48.FreeElement(pNS);
		  break;
		case  64 - sizeof(NewStruct):
		  Pool64.FreeElement(pNS);
		  break;
		case  80 - sizeof(NewStruct):
		  Pool80.FreeElement(pNS);
		  break;
		case  96 - sizeof(NewStruct):
		  Pool96.FreeElement(pNS);
		  break;
		case  112 - sizeof(NewStruct):
		  Pool112.FreeElement(pNS);
		  break;
		case  128 - sizeof(NewStruct):
		  Pool128.FreeElement(pNS);
		  break;
		case  160 - sizeof(NewStruct):
		  Pool160.FreeElement(pNS);
		  break;
		case  192 - sizeof(NewStruct):
		  Pool192.FreeElement(pNS);
		  break;
		case  256 - sizeof(NewStruct):
		  Pool256.FreeElement(pNS);
		  break;
		case  512 - sizeof(NewStruct):
		  Pool512.FreeElement(pNS);
		  break;
		case  1024 - sizeof(NewStruct):
		  Pool1024.FreeElement(pNS);
		  break;
		case  2048 - sizeof(NewStruct):
		  Pool2048.FreeElement(pNS);
		  break;
		default:
#ifdef DEBUGMEMUSAGE
      //TRACE1("operator delete: Memory block of size %lu being freed\n",
      //  pNS->iAllocSize + sizeof(NewStruct));
#endif
      //if ((pNS->iAllocSize < 64000)  && (pNS->iAllocSize > 0))
      //{
           /*GlobalFreePtr(pNS);*/
			HeapFree( GetProcessHeap(), 0, pNS);

      //                }
      //  else
      //{
      //  TRACE2("operator delete failed: Memory block of size %lu (Hex %Z08) too big\n",
      //    pNS->iAllocSize + sizeof(NewStruct), pNS->iAllocSize + sizeof(NewStruct));
      //  DEBUG_BREAK;
      //}
		}
	}
}

#if defined (__GNUC__) || (_MSC_VER)
void __cdecl operator delete(void*p)
{
  wv_free(p);
}
#endif
#if defined (__GNUC__)
void __cdecl operator delete[](void *p)
{
  wv_free(p);
}
#endif




