// 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; }