?? ccrystaltextbuffer.cpp
字號:
#include "stdafx.h"
#include <malloc.h>
#include "editcmd.h"
#include "CCrystalTextBuffer.h"
#ifndef __AFXPRIV_H__
#pragma message("Include <afxpriv.h> in your stdafx.h to avoid this message")
#include <afxpriv.h>
#endif
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
// Line allocation granularity
#define CHAR_ALIGN 16
#define ALIGN_BUF_SIZE(size) ((size) / CHAR_ALIGN) * CHAR_ALIGN + CHAR_ALIGN;
#define UNDO_BUF_SIZE 1024
const TCHAR crlf[] = _T("\r\n");
#ifdef _DEBUG
#define _ADVANCED_BUGCHECK 1
#endif
/////////////////////////////////////////////////////////////////////////////
// CCrystalTextBuffer::SUndoRecord
void CCrystalTextBuffer::SUndoRecord::SetText(LPCTSTR pszText)
{
m_pszText = NULL;
if (pszText != NULL && pszText[0] != _T('\0'))
{
int nLength = _tcslen(pszText);
if (nLength > 1)
{
m_pszText = new TCHAR[(nLength + 1) * sizeof(TCHAR)];
_tcscpy(m_pszText, pszText);
}
else
{
m_szText[0] = pszText[0];
}
}
}
void CCrystalTextBuffer::SUndoRecord::FreeText()
{
if (HIWORD((DWORD) m_pszText) != 0)
delete m_pszText;
}
/////////////////////////////////////////////////////////////////////////////
// CCrystalTextBuffer::CUpdateContext
void CCrystalTextBuffer::CInsertContext::RecalcPoint(CPoint &ptPoint)
{
ASSERT(m_ptEnd.y > m_ptStart.y ||
m_ptEnd.y == m_ptStart.y && m_ptEnd.x >= m_ptStart.x);
if (ptPoint.y < m_ptStart.y)
return;
if (ptPoint.y > m_ptStart.y)
{
ptPoint.y += (m_ptEnd.y - m_ptStart.y);
return;
}
if (ptPoint.x <= m_ptStart.x)
return;
ptPoint.y += (m_ptEnd.y - m_ptStart.y);
ptPoint.x = m_ptEnd.x + (ptPoint.x - m_ptStart.x);
}
void CCrystalTextBuffer::CDeleteContext::RecalcPoint(CPoint &ptPoint)
{
ASSERT(m_ptEnd.y > m_ptStart.y ||
m_ptEnd.y == m_ptStart.y && m_ptEnd.x >= m_ptStart.x);
if (ptPoint.y < m_ptStart.y)
return;
if (ptPoint.y > m_ptEnd.y)
{
ptPoint.y -= (m_ptEnd.y - m_ptStart.y);
return;
}
if (ptPoint.y == m_ptEnd.y && ptPoint.x >= m_ptEnd.x)
{
ptPoint.y = m_ptStart.y;
ptPoint.x = m_ptStart.x + (ptPoint.x - m_ptEnd.x);
return;
}
if (ptPoint.y == m_ptStart.y)
{
if (ptPoint.x > m_ptStart.x)
ptPoint.x = m_ptStart.x;
return;
}
ptPoint = m_ptStart;
}
/////////////////////////////////////////////////////////////////////////////
// CCrystalTextBuffer
IMPLEMENT_DYNCREATE(CCrystalTextBuffer, CCmdTarget)
CCrystalTextBuffer::CCrystalTextBuffer()
{
m_bInit = FALSE;
m_bReadOnly = FALSE;
m_bModified = FALSE;
m_bCreateBackupFile = FALSE;
m_nUndoPosition = 0;
}
CCrystalTextBuffer::~CCrystalTextBuffer()
{
ASSERT(! m_bInit); // You must call FreeAll() before deleting the object
}
BEGIN_MESSAGE_MAP(CCrystalTextBuffer, CCmdTarget)
//{{AFX_MSG_MAP(CCrystalTextBuffer)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CCrystalTextBuffer message handlers
void CCrystalTextBuffer::InsertLine(LPCTSTR pszLine, int nLength /*= -1*/, int nPosition /*= -1*/)
{
if (nLength == -1)
{
if (pszLine == NULL)
nLength = 0;
else
nLength = lstrlen(pszLine);
}
SLineInfo li;
li.m_nLength = nLength;
li.m_nMax = ALIGN_BUF_SIZE(li.m_nLength);
ASSERT(li.m_nMax >= li.m_nLength);
if (li.m_nMax > 0)
li.m_pcLine = new TCHAR[li.m_nMax];
if (li.m_nLength > 0)
memcpy(li.m_pcLine, pszLine, sizeof(TCHAR) * li.m_nLength);
if (nPosition == -1)
m_aLines.Add(li);
else
m_aLines.InsertAt(nPosition, li);
#ifdef _DEBUG
int nLines = m_aLines.GetSize();
if (nLines % 5000 == 0)
TRACE1("%d lines loaded!\n", nLines);
#endif
}
void CCrystalTextBuffer::AppendLine(int nLineIndex, LPCTSTR pszChars, int nLength /*= -1*/)
{
if (nLength == -1)
{
if (pszChars == NULL)
return;
nLength = lstrlen(pszChars);
}
if (nLength == 0)
return;
register SLineInfo &li = m_aLines[nLineIndex];
int nBufNeeded = li.m_nLength + nLength;
if (nBufNeeded > li.m_nMax)
{
li.m_nMax = ALIGN_BUF_SIZE(nBufNeeded);
ASSERT(li.m_nMax >= li.m_nLength + nLength);
TCHAR *pcNewBuf = new TCHAR[li.m_nMax];
if (li.m_nLength > 0)
memcpy(pcNewBuf, li.m_pcLine, sizeof(TCHAR) * li.m_nLength);
delete li.m_pcLine;
li.m_pcLine = pcNewBuf;
}
memcpy(li.m_pcLine + li.m_nLength, pszChars, sizeof(TCHAR) * nLength);
li.m_nLength += nLength;
ASSERT(li.m_nLength <= li.m_nMax);
}
void CCrystalTextBuffer::FreeAll()
{
// Free text
int nCount = m_aLines.GetSize();
for (int I = 0; I < nCount; I ++)
{
if (m_aLines[I].m_nMax > 0)
delete m_aLines[I].m_pcLine;
}
m_aLines.RemoveAll();
// Free undo buffer
int nBufSize = m_aUndoBuf.GetSize();
for (I = 0; I < nBufSize; I ++)
m_aUndoBuf[I].FreeText();
m_aUndoBuf.RemoveAll();
m_bInit = FALSE;
}
BOOL CCrystalTextBuffer::InitNew(int nCrlfStyle /*= CRLF_STYLE_DOS*/)
{
ASSERT(! m_bInit);
ASSERT(m_aLines.GetSize() == 0);
ASSERT(nCrlfStyle >= 0 && nCrlfStyle <= 2);
InsertLine(_T(""));
m_bInit = TRUE;
m_bReadOnly = FALSE;
m_nCRLFMode = nCrlfStyle;
m_bModified = FALSE;
m_nSyncPosition = m_nUndoPosition = 0;
m_bUndoGroup = m_bUndoBeginGroup = FALSE;
m_nUndoBufSize = UNDO_BUF_SIZE;
ASSERT(m_aUndoBuf.GetSize() == 0);
UpdateViews(NULL, NULL, UPDATE_RESET);
return TRUE;
}
BOOL CCrystalTextBuffer::GetReadOnly() const
{
bool dd =m_bInit;
ASSERT(m_bInit); // Text buffer not yet initialized.
//you must call InitNew() or LoadFromFile() first!
return m_bReadOnly;
}
void CCrystalTextBuffer::SetReadOnly(BOOL bReadOnly /*= TRUE*/)
{
ASSERT(m_bInit); // Text buffer not yet initialized.
// You must call InitNew() or LoadFromFile() first!
m_bReadOnly = bReadOnly;
}
static const char *crlfs[] =
{
"\x0d\x0a", // DOS/Windows style
"\x0a\x0d", // UNIX style
"\x0a" // Macintosh style
};
BOOL CCrystalTextBuffer::LoadFromFile(LPCTSTR pszFileName, int nCrlfStyle /*= CRLF_STYLE_AUTOMATIC*/)
{
ASSERT(! m_bInit);
ASSERT(m_aLines.GetSize() == 0);
HANDLE hFile = NULL;
int nCurrentMax = 256;
char *pcLineBuf = new char[nCurrentMax];
BOOL bSuccess = FALSE;
__try
{
DWORD dwFileAttributes = ::GetFileAttributes(pszFileName);
if (dwFileAttributes == (DWORD) -1)
__leave;
hFile = ::CreateFile(pszFileName, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
if (hFile == INVALID_HANDLE_VALUE)
__leave;
int nCurrentLength = 0;
const DWORD dwBufSize = 32768;
char *pcBuf = (char *) _alloca(dwBufSize);
DWORD dwCurSize;
if (! ::ReadFile(hFile, pcBuf, dwBufSize, &dwCurSize, NULL))
__leave;
if (nCrlfStyle == CRLF_STYLE_AUTOMATIC)
{
// Try to determine current CRLF mode
for (DWORD I = 0; I < dwCurSize; I ++)
{
if (pcBuf[I] == _T('\x0a'))
break;
}
if (I == dwCurSize)
{
// By default (or in the case of empty file), set DOS style
nCrlfStyle = CRLF_STYLE_DOS;
}
else
{
// Otherwise, analyse the first occurance of line-feed character
if (I > 0 && pcBuf[I - 1] == _T('\x0d'))
{
nCrlfStyle = CRLF_STYLE_DOS;
}
else
{
if (I < dwCurSize - 1 && pcBuf[I + 1] == _T('\x0d'))
nCrlfStyle = CRLF_STYLE_UNIX;
else
nCrlfStyle = CRLF_STYLE_MAC;
}
}
}
ASSERT(nCrlfStyle >= 0 && nCrlfStyle <= 2);
m_nCRLFMode = nCrlfStyle;
const char *crlf = crlfs[nCrlfStyle];
m_aLines.SetSize(0, 4096);
DWORD dwBufPtr = 0;
int nCrlfPtr = 0;
USES_CONVERSION;
while (dwBufPtr < dwCurSize)
{
int c = pcBuf[dwBufPtr];
dwBufPtr ++;
if (dwBufPtr == dwCurSize && dwCurSize == dwBufSize)
{
if (! ::ReadFile(hFile, pcBuf, dwBufSize, &dwCurSize, NULL))
__leave;
dwBufPtr = 0;
}
pcLineBuf[nCurrentLength] = (char) c;
nCurrentLength ++;
if (nCurrentLength == nCurrentMax)
{
// Reallocate line buffer
nCurrentMax += 256;
char *pcNewBuf = new char[nCurrentMax];
memcpy(pcNewBuf, pcLineBuf, nCurrentLength);
delete pcLineBuf;
pcLineBuf = pcNewBuf;
}
if ((char) c == crlf[nCrlfPtr])
{
nCrlfPtr ++;
if (crlf[nCrlfPtr] == 0)
{
pcLineBuf[nCurrentLength - nCrlfPtr] = 0;
InsertLine(A2T(pcLineBuf));
nCurrentLength = 0;
nCrlfPtr = 0;
}
}
else
nCrlfPtr = 0;
}
pcLineBuf[nCurrentLength] = 0;
InsertLine(A2T(pcLineBuf));
ASSERT(m_aLines.GetSize() > 0); // At least one empty line must present
m_bInit = TRUE;
m_bReadOnly = (dwFileAttributes & FILE_ATTRIBUTE_READONLY) != 0;
m_bModified = FALSE;
m_bUndoGroup = m_bUndoBeginGroup = FALSE;
m_nUndoBufSize = UNDO_BUF_SIZE;
m_nSyncPosition = m_nUndoPosition = 0;
ASSERT(m_aUndoBuf.GetSize() == 0);
bSuccess = TRUE;
UpdateViews(NULL, NULL, UPDATE_RESET);
}
__finally
{
if (pcLineBuf != NULL)
delete pcLineBuf;
if (hFile != NULL)
::CloseHandle(hFile);
}
return bSuccess;
}
BOOL CCrystalTextBuffer::SaveToFile(LPCTSTR pszFileName, int nCrlfStyle /*= CRLF_STYLE_AUTOMATIC*/, BOOL bClearModifiedFlag /*= TRUE*/)
{
ASSERT(nCrlfStyle == CRLF_STYLE_AUTOMATIC || nCrlfStyle == CRLF_STYLE_DOS||
nCrlfStyle == CRLF_STYLE_UNIX || nCrlfStyle == CRLF_STYLE_MAC);
ASSERT(m_bInit);
HANDLE hTempFile = INVALID_HANDLE_VALUE;
HANDLE hSearch = INVALID_HANDLE_VALUE;
TCHAR szTempFileDir[_MAX_PATH + 1];
TCHAR szTempFileName[_MAX_PATH + 1];
TCHAR szBackupFileName[_MAX_PATH + 1];
BOOL bSuccess = FALSE;
__try
{
TCHAR drive[_MAX_PATH], dir[_MAX_PATH], name[_MAX_PATH], ext[_MAX_PATH];
#ifdef _UNICODE
_wsplitpath(pszFileName, drive, dir, name, ext);
#else
_splitpath(pszFileName, drive, dir, name, ext);
#endif
lstrcpy(szTempFileDir, drive);
lstrcat(szTempFileDir, dir);
lstrcpy(szBackupFileName, pszFileName);
lstrcat(szBackupFileName, _T(".bak"));
if (::GetTempFileName(szTempFileDir, _T("CRE"), 0, szTempFileName) == 0)
__leave;
hTempFile = ::CreateFile(szTempFileName, GENERIC_WRITE, 0, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -