You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

586 lines
12 KiB
C++

// XTPSyntaxEditTextIterator.cpp : implementation file
//
// This file is a part of the XTREME TOOLKIT PRO MFC class library.
// (c)1998-2012 Codejock Software, All Rights Reserved.
//
// THIS SOURCE FILE IS THE PROPERTY OF CODEJOCK SOFTWARE AND IS NOT TO BE
// RE-DISTRIBUTED BY ANY MEANS WHATSOEVER WITHOUT THE EXPRESSED WRITTEN
// CONSENT OF CODEJOCK SOFTWARE.
//
// THIS SOURCE CODE CAN ONLY BE USED UNDER THE TERMS AND CONDITIONS OUTLINED
// IN THE XTREME SYNTAX EDIT LICENSE AGREEMENT. CODEJOCK SOFTWARE GRANTS TO
// YOU (ONE SOFTWARE DEVELOPER) THE LIMITED RIGHT TO USE THIS SOFTWARE ON A
// SINGLE COMPUTER.
//
// CONTACT INFORMATION:
// support@codejock.com
// http://www.codejock.com
//
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
// common includes
#include "Common/XTPSmartPtrInternalT.h"
#include "Common/XTPVC80Helpers.h"
#include "Common/XTPColorManager.h"
// syntax editor includes
#include "XTPSyntaxEditDefines.h"
#include "XTPSyntaxEditStruct.h"
#include "XTPSyntaxEditLexPtrs.h"
#include "XTPSyntaxEditLexParser.h"
#include "XTPSyntaxEditBufferManager.h"
#include "XTPSyntaxEditTextIterator.h"
#define XTP_EDIT_LEX_TEXT_BUF_SIZE 512
#define XTP_EDIT_LEX_TEXT_BUF_START_GAP 10
#ifdef _UNICODE
#define CHAR_W 1
#else
#define CHAR_W 2
#endif
//---------------------------------------------------------------------------
#define CHR_TO_B(nChr) ( (int)((nChr)*sizeof(TCHAR)) )
////////////////////////////////////////////////////////////////////////////
AFX_INLINE int xtpEdit_StrLenInBytes(LPCTSTR pcszStr, int nChars)
{
#ifdef _UNICODE
return (int)_tcsnbcnt(pcszStr, nChars) * sizeof(TCHAR);
#else
return (int)_tcsnbcnt(pcszStr, nChars);
#endif
}
AFX_INLINE int xtpEdit_StrCharsToBytes(LPCTSTR pcszStr, int nChars)
{
#ifdef _UNICODE
UNREFERENCED_PARAMETER(pcszStr);
return nChars * sizeof(TCHAR);
#else
LPCTSTR p2;
if (nChars == 1)
{
p2 = _tcsinc(pcszStr);
}
else
{
p2 = _tcsninc(pcszStr, nChars);
}
int nB = int(p2 - pcszStr);
return nB;
//return _tcsnbcnt(pcszStr, nChars);
#endif
}
////////////////////////////////////////////////////////////////////////////
static const TCHAR szEOL[] = _T("\x0D\x0A");
////////////////////////////////////////////////////////////////////////////
//class CXTPSyntaxEditTextIterator
namespace XTPSyntaxEditLexAnalyser
{
BOOL IsEventSet(HANDLE hEvent);
}
CXTPSyntaxEditTextIterator::CXTPSyntaxEditTextIterator(CXTPSyntaxEditBufferManager* pData)
{
m_pData = pData;
if (!m_pData)
return;
m_pData->InternalAddRef();
int nMaxBackOffset_sch = (int)m_pData->GetLexParser()->GetSchemaOptions(
m_pData->GetFileExt())->m_dwMaxBackParseOffset;
// WARNING! - value should be in reasonable range
ASSERT(nMaxBackOffset_sch >= 10 && nMaxBackOffset_sch <= 10*1000);
m_nBufOffsetB_normal = max(nMaxBackOffset_sch, 20);
m_nBufOffsetB_max = XTP_EDIT_LEX_TEXT_BUF_SIZE;
m_nBufOffsetB = 0;
SeekBegin();
}
CXTPSyntaxEditTextIterator::~CXTPSyntaxEditTextIterator()
{
if (m_pData)
{
m_pData->InternalRelease();
}
}
CString CXTPSyntaxEditTextIterator::GetEOL() const // "\r\n", "\n\r", "\r"
{
if (!m_pData)
{
ASSERT(FALSE);
return szEOL;
}
CString strEOL = m_pData->GetCurCRLF();
return strEOL;
}
void CXTPSyntaxEditTextIterator::SeekBegin()
{
m_LCpos.nLine = 1;
m_LCpos.nCol = 0;
m_mapLine2Len.RemoveAll();
int nEndRow = m_pData->GetRowCount();
int nHSize = max(nEndRow/10, 500);
m_mapLine2Len.InitHashTable(nHSize, FALSE);
m_nNextLine = 1;
m_nBufSizeB = 0;
m_nTmpOffsetC = 0;
m_nTmpOffsetB = 0;
m_nBufOffsetB = XTP_EDIT_LEX_TEXT_BUF_START_GAP;
if (m_arBuffer.GetSize() < max(m_nBufOffsetB_normal, 500))
{
m_arBuffer.SetSize(max(m_nBufOffsetB_normal, 500));
}
memset(m_arBuffer.GetData(), 0, m_arBuffer.GetSize());
TCHAR* pData = GetBuffer(m_nBufOffsetB);
STRCPY_S(pData, _tcslen(szEOL) + 1, szEOL);
m_nBufOffsetB += CHR_TO_B(2);
//---
int nLen = GetLineLen(m_nNextLine, TRUE);
m_bEOF = nLen == 0;
}
BOOL CXTPSyntaxEditTextIterator::SeekPos(const XTP_EDIT_LINECOL& posLC, HANDLE hBreakEvent)
{
SeekBegin();
if (m_bEOF)
{
return FALSE;
}
int nSumLenB = 0;
int nLnStart = posLC.nLine;
while (nSumLenB < m_nBufOffsetB_normal && nLnStart > 1)
{
nSumLenB += GetLineLenBytes(nLnStart, TRUE);
nLnStart--;
if (hBreakEvent && XTPSyntaxEditLexAnalyser::IsEventSet(hBreakEvent))
{
return FALSE;
}
}
m_nNextLine = nLnStart;
GetText();
m_LCpos.nLine = nLnStart;
m_LCpos.nCol = 0;
while (m_LCpos < posLC && !m_bEOF)
{
int nSeek = 1;
if (m_LCpos.nLine < posLC.nLine)
{
nSeek = 0;
if (!m_mapLine2Len.Lookup(m_LCpos.nLine, nSeek) || !nSeek)
{
ASSERT(nSeek || !nSeek && m_LCpos.nLine >= m_pData->GetRowCount());
nSeek = 1;
}
}
else
{
ASSERT(m_LCpos.nLine == posLC.nLine);
nSeek = posLC.nCol - m_LCpos.nCol;
ASSERT(nSeek >=0);
}
if (nSeek <= 0)
{
ASSERT(FALSE);
break;
}
SeekNext(nSeek);
if (hBreakEvent && XTPSyntaxEditLexAnalyser::IsEventSet(hBreakEvent))
{
return FALSE;
}
}
BOOL bRes = (m_LCpos == posLC);
return bRes;
}
LPCTSTR CXTPSyntaxEditTextIterator::GetText(int nCharsBuf) // don't remove line end chars
{
if (!m_pData)
{
ASSERT(FALSE);
return NULL;
}
int nSizeB = (int)m_arBuffer.GetSize();
const int cnReservB = (XTP_EDIT_LEX_TEXT_BUF_SIZE+100)*2;
if (!m_nBufSizeB || (m_nBufSizeB < CHR_TO_B(nCharsBuf)) )
{
int nEndRow = m_pData->GetRowCount();
while (m_nNextLine <= nEndRow && m_nBufSizeB < CHR_TO_B(nCharsBuf) )
{
CString strBuf;
m_pData->GetLineText(m_nNextLine, strBuf, TRUE);
int nLenC = (int)_tcsclen(strBuf);
int nLenB = xtpEdit_StrLenInBytes(strBuf, nLenC);
//---------------------------------------------------------------------------
int nNeedSizeB = m_nBufOffsetB + m_nBufSizeB + nLenB +
max(256, nCharsBuf*2);
if (nNeedSizeB > nSizeB)
{
m_arBuffer.SetSize(nNeedSizeB + cnReservB);
nSizeB = (int)m_arBuffer.GetSize();
}
//---------------------------------------------------------------------------
TCHAR* pBuf = GetBuffer(m_nBufOffsetB + m_nBufSizeB);
ASSERT(*(pBuf-1) != _T('\0'));
ASSERT(*pBuf == _T('\0'));
*pBuf = _T('\0');
STRCPY_S(pBuf, strBuf.GetLength() + 1, strBuf);
ASSERT(nSizeB-m_nBufOffsetB-m_nBufSizeB > nLenB);
m_nBufSizeB += nLenB;
ASSERT(m_nBufSizeB < nSizeB);
m_mapLine2Len[m_nNextLine] = nLenC;
//TRACE(_T("TEXT-ITERATOR: line(%d) len = %d \n"), m_nNextLine, nLenC);
//--------------------------------
if (m_nNextLine == nEndRow)
{
TCHAR* pBufEnd = GetBuffer(m_nBufOffsetB + m_nBufSizeB);
STRCPY_S(pBufEnd, _tcslen(szEOL) + 1, szEOL);
int nLenB2 = xtpEdit_StrLenInBytes(szEOL, 2);
m_nBufSizeB += nLenB2;
ASSERT(m_nBufSizeB < nSizeB);
}
m_nNextLine++;
}
}
ASSERT(m_nBufSizeB < nSizeB);
TCHAR* pText = GetBuffer(m_nBufOffsetB + m_nTmpOffsetB);
return pText;
}
// Move cur pos and return pointer to the text begin;
LPCTSTR CXTPSyntaxEditTextIterator::SeekNext(DWORD dwChars, int nCharsBuf)
{
int nBSize = (int)m_arBuffer.GetSize();
ASSERT(m_nBufSizeB <= nBSize);
if (m_nBufSizeB < CHR_TO_B(nCharsBuf + dwChars))
{
GetText(nCharsBuf + dwChars);
}
if (m_nBufSizeB < CHR_TO_B(dwChars) )
{
dwChars = m_nBufSizeB/sizeof(TCHAR);
}
if (m_nBufSizeB >= CHR_TO_B(dwChars) && m_nBufSizeB)
{
nBSize = (int)m_arBuffer.GetSize();
ASSERT(nBSize > CHR_TO_B(dwChars) );
TCHAR* pText = GetBuffer(m_nBufOffsetB);
//int nStepB = xtpEdit_StrLenInBytes(pText, dwChars);
int nStepB = xtpEdit_StrCharsToBytes(pText, dwChars);
ASSERT(nStepB > 0);
if (m_nBufOffsetB > m_nBufOffsetB_max)
{
int nStepRem = m_nBufOffsetB - m_nBufOffsetB_normal;
ASSERT(nStepRem > 0);
m_arBuffer.RemoveAt(0, nStepRem);
m_nBufOffsetB -= nStepRem;
}
m_nBufOffsetB += nStepB;
m_nBufSizeB -= nStepB;
TCHAR* pBuf = GetBuffer(m_nBufOffsetB + m_nBufSizeB);
ASSERT(*(pBuf-1) != _T('\0'));
ASSERT(*pBuf == _T('\0'));
m_bEOF = m_nBufSizeB <= 0;
if (dwChars && !m_bEOF)
{
LCPosAdd(m_LCpos, dwChars);
}
SetTxtOffset(m_nTmpOffsetC);
pText = GetBuffer(m_nBufOffsetB + m_nTmpOffsetB);
return pText;
}
return NULL;
}
LPCTSTR CXTPSyntaxEditTextIterator::SeekPrev()
{
int nBSize = (int)m_arBuffer.GetSize();
ASSERT(m_nBufSizeB <= nBSize);
if (m_nBufOffsetB <= XTP_EDIT_LEX_TEXT_BUF_START_GAP)
{
XTP_EDIT_LINECOL lcPos = m_LCpos;
//LCPosDec(lcPos);
if (!SeekPos(lcPos))
return NULL;
}
if (m_nBufOffsetB > 0 && m_nBufSizeB > 0 && m_LCpos > XTP_EDIT_LINECOL::Pos1)
{
TCHAR* pText0 = GetBuffer(0);
TCHAR* pText1 = GetBuffer(m_nBufOffsetB);
TCHAR* pText = pText1;
pText = _tcsdec(pText0, pText);
if (!pText)
{
m_nBufOffsetB = 0;
m_bEOF = TRUE;
return NULL;
}
int nStepB = int(pText1 - pText) * sizeof(TCHAR);
m_nBufOffsetB -= nStepB;
m_nBufSizeB += nStepB;
LCPosDec(m_LCpos);
//SetTxtOffset(m_nTmpOffsetC);
//pText = GetBuffer(m_nBufOffsetB + m_nTmpOffsetB);
return pText;
}
return NULL;
}
void CXTPSyntaxEditTextIterator::SetTxtOffset(int nOffsetChars)
{
m_nTmpOffsetC = nOffsetChars;
m_nTmpOffsetB = 0;
if (m_nTmpOffsetC)
{
TCHAR* pText = GetBuffer(m_nBufOffsetB);
if (m_nTmpOffsetC < 0)
{
TCHAR* pText_min = GetBuffer(0);
TCHAR* pText0 = pText;
for (int i = 0; i < labs(nOffsetChars); i++)
{
if (pText0 <= pText_min)
{
break;
}
pText0 = _tcsdec(pText_min, pText0);
}
m_nTmpOffsetB = -1 * int( ((byte*)pText) - ((byte*)pText0) );
}
else
{
m_nTmpOffsetB = xtpEdit_StrLenInBytes(pText, m_nTmpOffsetC);
}
}
}
BOOL CXTPSyntaxEditTextIterator::IsEOF() const
{
return m_bEOF;
}
XTP_EDIT_LINECOL CXTPSyntaxEditTextIterator::GetPosLC() const
{
return m_LCpos;
}
XTP_EDIT_LINECOL CXTPSyntaxEditTextIterator::GetPosLC_last(BOOL bWithEOL) const
{
int nEndRow = m_pData->GetRowCount();
return XTP_EDIT_LINECOL::MakeLineCol(nEndRow, GetLineLen(nEndRow, bWithEOL));
}
void CXTPSyntaxEditTextIterator::LCPosAdd(XTP_EDIT_LINECOL& rLC, int nCharsAdd) const
{
int nLineLen = 0;
int nRestChars = nCharsAdd;
while (nRestChars)
{
if (m_mapLine2Len.Lookup(rLC.nLine, nLineLen))
{
if (nLineLen == 0)
{
break; // last empty line
}
ASSERT(nLineLen > 0);
int nDiff = nLineLen - rLC.nCol;
ASSERT(nDiff >= 0);
if (nDiff <= nRestChars)
{
rLC.nLine++;
rLC.nCol = 0;
nRestChars -= nDiff;
}
else
{
rLC.nCol += nRestChars;
nRestChars = 0;
break;
}
}
else
{
break; // no more lines
}
}
}
void CXTPSyntaxEditTextIterator::LCPosDec(XTP_EDIT_LINECOL& rLC) const
{
rLC.nCol--;
if (rLC.nCol < 0)
{
if (rLC.nLine <= 1)
{
ASSERT(FALSE);
rLC.nCol = 0;
}
else
{
rLC.nLine--;
int nLineLen = 0;
if (m_mapLine2Len.Lookup(rLC.nLine, nLineLen))
{
ASSERT(nLineLen || rLC.nLine == m_pData->GetRowCount());
nLineLen = max(1, nLineLen);
rLC.nCol = nLineLen-1;
}
else
{
if (rLC.nLine >= 1)
{
nLineLen = m_pData->GetLineTextLengthC(rLC.nLine, TRUE);
ASSERT(nLineLen || rLC.nLine == m_pData->GetRowCount());
nLineLen = max(1, nLineLen);
rLC.nCol = nLineLen-1;
}
else
{
ASSERT(FALSE);
rLC.nLine++;
rLC.nCol++;
}
}
}
}
}
int CXTPSyntaxEditTextIterator::GetLineLen(int nLine, BOOL bWithEOL) const
{
if (!m_pData)
{
ASSERT(FALSE);
return 0;
}
int nEndRow = m_pData->GetRowCount();
if (nLine > 0 && nLine <= nEndRow)
{
CString strBuf;
m_pData->GetLineText(nLine, strBuf, bWithEOL);
int nLen = (int)_tcsclen(strBuf);
return nLen;
}
return 0;
}
int CXTPSyntaxEditTextIterator::GetLineLenBytes(int nLine, BOOL bWithEOL) const
{
if (!m_pData)
{
ASSERT(FALSE);
return 0;
}
int nEndRow = m_pData->GetRowCount();
if (nLine > 0 && nLine <= nEndRow)
{
CString strBuf;
m_pData->GetLineText(nLine, strBuf, bWithEOL);
int nLenB = xtpEdit_StrLenInBytes(strBuf, strBuf.GetLength());
return nLenB;
}
return 0;
}
CString CXTPSyntaxEditTextIterator::GetFileExt() const
{
if (!m_pData)
{
ASSERT(FALSE);
return _T("");
}
CString strFN = m_pData->GetFileExt();
return strFN;
}