{
/* Both exist and neither is a directory. */
int o_binary = always_text_flag ? O_BINARY : 0;
+ if (!ignore_eol_diff) o_binary = O_BINARY;
/* Open the files and record their descriptors. */
if (inf[0].desc == -2)
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
-CDiffContext::CDiffContext(LPCTSTR pszLeft /*=NULL*/, LPCTSTR pszRight /*=NULL*/)
+CDiffContext::CDiffContext(LPCTSTR pszLeft /*=NULL*/, LPCTSTR pszRight /*=NULL*/, IDiffStatus * piStatus)
{
m_bRecurse=FALSE;
m_strLeft = pszLeft;
pNamesLeft = NULL;
pNamesRight = NULL;
+ m_piStatus = piStatus;
}
CDiffContext::CDiffContext(LPCTSTR pszLeft, LPCTSTR pszRight, CDiffContext& src)
m_strRight = pszRight;
m_pList = src.m_pList;
SetRegExp(src.m_strRegExp);
+ m_piStatus = src.m_piStatus;
pNamesLeft = NULL;
pNamesRight = NULL;
m_pList->AddTail(di);
+
+ if (m_piStatus)
+ m_piStatus->rptFile(code);
}
void CDiffContext::SetRegExp(LPCTSTR pszExp)
#define FILE_LDIRUNIQUE 6
#define FILE_RDIRUNIQUE 7
+class IDiffStatus
+{
+public:
+ virtual void rptFile(BYTE code)=0;
+};
+
class CDiffContext
{
public:
void SetRegExp(LPCTSTR pszExp);
void AddDiff(LPCTSTR pszFilename, LPCTSTR pszLeftDir, LPCTSTR pszRightDir, long ltime, long rtime, BYTE code);
- CDiffContext(LPCTSTR pszLeft = NULL, LPCTSTR pszRight = NULL);
+ CDiffContext(LPCTSTR pszLeft, LPCTSTR pszRight, IDiffStatus * piStatus);
CDiffContext(LPCTSTR pszLeft, LPCTSTR pszRight, CDiffContext& src);
virtual ~CDiffContext();
CString m_strRight;
CRegExp m_rgx;
CString m_strRegExp;
+ IDiffStatus * m_piStatus;
+
struct dirdata ddLeft, ddRight;
char *pNamesLeft;
{
curpos = pos;
DIFFITEM di = m_pCtxt->m_dirlist.GetNext(pos);
+ BOOL leftside = (di.code==FILE_LUNIQUE || di.code==FILE_LDIRUNIQUE);
+ BOOL rightside = (di.code==FILE_RUNIQUE || di.code==FILE_RDIRUNIQUE);
switch (di.code)
{
case FILE_DIFF:
case FILE_RUNIQUE:
case FILE_LDIRUNIQUE:
case FILE_RDIRUNIQUE:
- if (mf->m_bShowUnique
+ if (((mf->m_bShowUniqueLeft && leftside) || (mf->m_bShowUniqueRight && rightside))
&& (!mf->m_bHideBak || !FileExtMatches(di.filename,BACKUP_FILE_EXT)))
{
m_pView->AddItem(cnt, DV_NAME, di.filename);
pWndPopupOwner = pWndPopupOwner->GetParent();
// invoke context menu
+ // this will invoke all the OnUpdate methods to enable/disable the individual items
pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y,
pWndPopupOwner);
}
{
DoCopyFileToLeft();
}
+// User chose (main menu) Copy from left to right
+void CDirView::OnDirCopyFileToRight()
+{
+ DoCopyFileToRight();
+}
// User chose (context men) Copy from right to left
void CDirView::OnCtxtDirCopyFileToLeft()
{
DoCopyFileToLeft();
}
+// User chose (context menu) Copy from left to right
+void CDirView::OnCtxtDirCopyFileToRight()
+{
+ DoCopyFileToRight();
+}
// Prompt & copy item from right to left, if legal
void CDirView::DoCopyFileToLeft()
switch(di.code)
{
case FILE_LUNIQUE:
- ConfirmAndDeleteAndUpdate(slFile, pos, sel);
break;
case FILE_RUNIQUE:
case FILE_DIFF:
break;
case FILE_LDIRUNIQUE:
case FILE_RDIRUNIQUE:
- // TODO 2002-11-22: Enable uniques also, but must write code to do recursive copy
+ // TODO: Would be nice to allow copying directory
+ // but must write code for recursive copy
+ // and worse, this will make the item display invalid (new items not on it)
+ // Perry 2002-11-26
case FILE_SAME:
default:
// Not allowed, and should have been disabled choices anyway
break;
}
}
-
-// Update context menu Copy Right to Left item
-void CDirView::OnUpdateCtxtDirCopyFileToLeft(CCmdUI* pCmdUI)
-{
- DoUpdateDirCopyFileToLeft(pCmdUI);
-}
-
-// Update main menu Copy Right to Left item
-void CDirView::OnUpdateDirCopyFileToLeft(CCmdUI* pCmdUI)
-{
- DoUpdateDirCopyFileToLeft(pCmdUI);
-}
-
-// Should Copy to Left be enabled or disabled ? (both main menu & context menu use this)
-void CDirView::DoUpdateDirCopyFileToLeft(CCmdUI* pCmdUI)
-{
- int sel = m_pList->GetNextItem(-1, LVNI_SELECTED);
- if (sel == -1)
- {
- // no item there
- pCmdUI->Enable(FALSE);
- return;
- }
- // found item (normal case)
- // find item from document
- POSITION pos;
- const DIFFITEM& di = GetDiffItem(sel, pos);
- // what we do depends on comparison result for this item
- switch(di.code)
- {
- case FILE_LUNIQUE:
- pCmdUI->Enable(FALSE); // no right item, so can't copy to left
- break;
- case FILE_RUNIQUE:
- case FILE_DIFF:
- case FILE_BINDIFF:
- pCmdUI->Enable(TRUE);
- break;
- case FILE_SAME:
- pCmdUI->Enable(FALSE);
- break;
- case FILE_LDIRUNIQUE:
- pCmdUI->Enable(FALSE); // no right item, so can't copy to left
- break;
- case FILE_RDIRUNIQUE:
- // TODO 2002-11-22: Enable unique also, but must write code to do recursive copy
- pCmdUI->Enable(FALSE);
- break;
- default:
- pCmdUI->Enable(FALSE);
- break;
- }
-}
-
-
-// Prompt & delete file, & remove its data entries
-void CDirView::ConfirmAndDeleteAndUpdate(LPCTSTR szFile, POSITION pos, int sel)
-{
- // May want an option to suppress these message boxes
-
- if (!mf->ConfirmAndDelete(szFile))
- return;
- // remove item data from document & screen
- GetDocument()->m_pCtxt->m_dirlist.RemoveAt(pos);
- GetListCtrl().DeleteItem(sel);
-}
-
-// User chose (main menu) Copy from left to right
-void CDirView::OnDirCopyFileToRight()
-{
- DoCopyFileToRight();
-}
-
-// User chose (context menu) Copy from left to right
-void CDirView::OnCtxtDirCopyFileToRight()
-{
- DoCopyFileToRight();
-}
-
// Prompt & copy item from left to right, if legal
void CDirView::DoCopyFileToRight()
{
switch(di.code)
{
case FILE_RUNIQUE:
- ConfirmAndDeleteAndUpdate(srFile, pos, sel);
break;
case FILE_LUNIQUE:
case FILE_DIFF:
break;
case FILE_LDIRUNIQUE:
case FILE_RDIRUNIQUE:
- // TODO 2002-11-22: Enable uniques also, but must write code to do recursive copy
+ // see comments in DoCopyFileToLeft
case FILE_SAME:
default:
// Not allowed, and should have been disabled choices anyway
}
// Update context menu Copy Right to Left item
+void CDirView::OnUpdateCtxtDirCopyFileToLeft(CCmdUI* pCmdUI)
+{
+ DoUpdateDirCopyFileToLeft(pCmdUI);
+}
+// Update context menu Copy Left to Right item
void CDirView::OnUpdateCtxtDirCopyFileToRight(CCmdUI* pCmdUI)
{
DoUpdateDirCopyFileToRight(pCmdUI);
}
+// Update main menu Copy Right to Left item
+void CDirView::OnUpdateDirCopyFileToLeft(CCmdUI* pCmdUI)
+{
+ DoUpdateDirCopyFileToLeft(pCmdUI);
+}
// Update main menu Copy Left to Right item
void CDirView::OnUpdateDirCopyFileToRight(CCmdUI* pCmdUI)
{
DoUpdateDirCopyFileToRight(pCmdUI);
}
+// Should Copy to Left be enabled or disabled ? (both main menu & context menu use this)
+void CDirView::DoUpdateDirCopyFileToLeft(CCmdUI* pCmdUI)
+{
+ int sel = m_pList->GetNextItem(-1, LVNI_SELECTED);
+ if (sel == -1)
+ {
+ // no item there
+ pCmdUI->Enable(FALSE);
+ return;
+ }
+ // found item (normal case)
+ // find item from document
+ POSITION pos;
+ const DIFFITEM& di = GetDiffItem(sel, pos);
+ // what we do depends on comparison result for this item
+ switch(di.code)
+ {
+ case FILE_LUNIQUE:
+ pCmdUI->Enable(FALSE); // no right item, so can't copy to left
+ break;
+ case FILE_RUNIQUE:
+ case FILE_DIFF:
+ case FILE_BINDIFF:
+ pCmdUI->Enable(TRUE);
+ break;
+ case FILE_SAME:
+ pCmdUI->Enable(FALSE);
+ break;
+ case FILE_LDIRUNIQUE:
+ pCmdUI->Enable(FALSE); // no right item, so can't copy to left
+ break;
+ case FILE_RDIRUNIQUE:
+ // TODO 2002-11-22: Enable unique also, but must write code to do recursive copy
+ pCmdUI->Enable(TRUE);
+ break;
+ default:
+ pCmdUI->Enable(FALSE);
+ break;
+ }
+}
// Should Copy to Right be enabled or disabled ? (both main menu & context menu use this)
void CDirView::DoUpdateDirCopyFileToRight(CCmdUI* pCmdUI)
{
{
DoDelLeft();
}
+// User chose (context menu) delete right
+void CDirView::OnCtxtDirDelRight()
+{
+ DoDelRight();
+}
// Prompt & delete left, if legal
void CDirView::DoDelLeft()
POSITION pos;
const DIFFITEM& di = GetDiffItem(sel, pos);
- ConfirmAndDeleteAndUpdate(slFile, pos, sel);
+ // need to know if file or directory
+ switch(di.code)
+ {
+ case FILE_LUNIQUE:
+ case FILE_DIFF:
+ case FILE_BINDIFF:
+ ConfirmAndDeleteFileAndUpdate(slFile, pos, sel);
+ break;
+ case FILE_LDIRUNIQUE:
+ ConfirmAndDeleteDirAndUpdate(slFile, pos, sel);
+ break;
+ }
+}
+// Prompt & delete right, if legal
+void CDirView::DoDelRight()
+{
+ int sel = m_pList->GetNextItem(-1, LVNI_SELECTED);
+ if (sel == -1) return;
+
+ CString sl, sr, slFile, srFile;
+ if (!GetSelectedDirNames(sl, sr) || !GetSelectedFileNames(slFile, srFile))
+ return;
+
+ // find item from document
+ POSITION pos;
+ const DIFFITEM& di = GetDiffItem(sel, pos);
+
+ // need to know if file or directory
+ switch(di.code)
+ {
+ case FILE_RUNIQUE:
+ case FILE_DIFF:
+ case FILE_BINDIFF:
+ ConfirmAndDeleteFileAndUpdate(srFile, pos, sel);
+ break;
+ case FILE_RDIRUNIQUE:
+ ConfirmAndDeleteDirAndUpdate(srFile, pos, sel);
+ break;
+ }
}
+// Enable/disable Delete Left menu choice on context menu
void CDirView::OnUpdateCtxtDirDelLeft(CCmdUI* pCmdUI)
{
DoUpdateCtxtDirDelLeft(pCmdUI);
}
-// Should Delete left be enabled or disabled ? (both main menu & context menu use this)
+// Enable/disable Delete Right menu choice on context menu
+void CDirView::OnUpdateCtxtDirDelRight(CCmdUI* pCmdUI)
+{
+ DoUpdateCtxtDirDelRight(pCmdUI);
+}
+
+// Should Delete left be enabled or disabled ?
void CDirView::DoUpdateCtxtDirDelLeft(CCmdUI* pCmdUI)
{
int sel = m_pList->GetNextItem(-1, LVNI_SELECTED);
break;
}
}
-// User chose (context menu) delete right
-void CDirView::OnCtxtDirDelRight()
-{
- DoDelRight();
-}
-
-// Prompt & delete right, if legal
-void CDirView::DoDelRight()
-{
- int sel = m_pList->GetNextItem(-1, LVNI_SELECTED);
- if (sel == -1) return;
-
- CString sl, sr, slFile, srFile;
- if (!GetSelectedDirNames(sl, sr) || !GetSelectedFileNames(slFile, srFile))
- return;
-
- // find item from document
- POSITION pos;
- const DIFFITEM& di = GetDiffItem(sel, pos);
-
- ConfirmAndDeleteAndUpdate(srFile, pos, sel);
-}
-
-void CDirView::OnUpdateCtxtDirDelRight(CCmdUI* pCmdUI)
-{
- DoUpdateCtxtDirDelRight(pCmdUI);
-}
-
// Should Delete right be enabled or disabled ?
void CDirView::DoUpdateCtxtDirDelRight(CCmdUI* pCmdUI)
{
break;
}
}
+
+// Prompt & delete file, & remove its data entries
+void CDirView::ConfirmAndDeleteFileAndUpdate(LPCTSTR szFile, POSITION pos, int sel)
+{
+ // May want an option to suppress these message boxes
+
+ if (!mf->ConfirmAndDeleteFile(szFile))
+ return;
+ // remove item data from document & screen
+ GetDocument()->m_pCtxt->m_dirlist.RemoveAt(pos);
+ GetListCtrl().DeleteItem(sel);
+}
+
+// Prompt & delete directory, & remove its data entries
+void CDirView::ConfirmAndDeleteDirAndUpdate(LPCTSTR szDir, POSITION pos, int sel)
+{
+ // May want an option to suppress these message boxes
+
+ if (!mf->ConfirmAndDeleteDir(szDir))
+ return;
+ // remove item data from document & screen
+ // so, this assumes it is a unique entry (has no children listed)
+ GetDocument()->m_pCtxt->m_dirlist.RemoveAt(pos);
+ GetListCtrl().DeleteItem(sel);
+}
void ModifyPopup(CMenu * pPopup, int nStringResource, int nMenuId, LPCTSTR szPath);
void DoDelLeft();
void DoDelRight();
- void ConfirmAndDeleteAndUpdate(LPCTSTR szFile, POSITION pos, int sel);
void DoUpdateCtxtDirDelLeft(CCmdUI* pCmdUI);
void DoUpdateCtxtDirDelRight(CCmdUI* pCmdUI);
+ void ConfirmAndDeleteFileAndUpdate(LPCTSTR szFile, POSITION pos, int sel);
+ void ConfirmAndDeleteDirAndUpdate(LPCTSTR szDir, POSITION pos, int sel);
};
//{{AFX_MSG_MAP(CMainFrame)
ON_COMMAND(ID_OPTIONS_SHOWDIFFERENT, OnOptionsShowDifferent)
ON_COMMAND(ID_OPTIONS_SHOWIDENTICAL, OnOptionsShowIdentical)
- ON_COMMAND(ID_OPTIONS_SHOWUNIQUE, OnOptionsShowUnique)
+ ON_COMMAND(ID_OPTIONS_SHOWUNIQUELEFT, OnOptionsShowUniqueLeft)
+ ON_COMMAND(ID_OPTIONS_SHOWUNIQUERIGHT, OnOptionsShowUniqueRight)
ON_UPDATE_COMMAND_UI(ID_OPTIONS_SHOWDIFFERENT, OnUpdateOptionsShowdifferent)
ON_UPDATE_COMMAND_UI(ID_OPTIONS_SHOWIDENTICAL, OnUpdateOptionsShowidentical)
- ON_UPDATE_COMMAND_UI(ID_OPTIONS_SHOWUNIQUE, OnUpdateOptionsShowunique)
+ ON_UPDATE_COMMAND_UI(ID_OPTIONS_SHOWUNIQUELEFT, OnUpdateOptionsShowuniqueleft)
+ ON_UPDATE_COMMAND_UI(ID_OPTIONS_SHOWUNIQUERIGHT, OnUpdateOptionsShowuniqueright)
ON_WM_CREATE()
ON_COMMAND(ID_FILE_OPEN, OnFileOpen)
ON_UPDATE_COMMAND_UI(ID_HIDE_BACKUP_FILES, OnUpdateHideBackupFiles)
{
ID_SEPARATOR, // status line indicator
ID_SEPARATOR,
+ ID_SEPARATOR,
ID_INDICATOR_CAPS,
ID_INDICATOR_NUM,
ID_INDICATOR_SCRL,
m_bFirstTime = TRUE;
m_bIgnoreBlankLines = theApp.GetProfileInt(_T("Settings"), _T("IgnoreBlankLines"), FALSE)!=0;
+ m_bEolSensitive = theApp.GetProfileInt(_T("Settings"), _T("EolSensitive"), FALSE)!=0;
m_bIgnoreCase = theApp.GetProfileInt(_T("Settings"), _T("IgnoreCase"), FALSE)!=0;
- m_bShowUnique = theApp.GetProfileInt(_T("Settings"), _T("ShowUnique"), TRUE)!=0;
+ m_bShowUniqueLeft = theApp.GetProfileInt(_T("Settings"), _T("ShowUniqueLeft"), TRUE)!=0;
+ m_bShowUniqueRight = theApp.GetProfileInt(_T("Settings"), _T("ShowUniqueRight"), TRUE)!=0;
m_bShowDiff = theApp.GetProfileInt(_T("Settings"), _T("ShowDifferent"), TRUE)!=0;
m_bShowIdent = theApp.GetProfileInt(_T("Settings"), _T("ShowIdentical"), TRUE)!=0;
m_bBackup = theApp.GetProfileInt(_T("Settings"), _T("BackupFile"), TRUE)!=0;
length_varies = (m_nIgnoreWhitespace!=0);
ignore_case_flag = m_bIgnoreCase;
ignore_blank_lines_flag = m_bIgnoreBlankLines;
- ignore_some_changes = (m_nIgnoreWhitespace!=0) || m_bIgnoreCase || m_bIgnoreBlankLines;
+ ignore_eol_diff = !m_bEolSensitive;
+ ignore_some_changes = (m_nIgnoreWhitespace!=0) || m_bIgnoreCase || m_bIgnoreBlankLines || !m_bEolSensitive;
// build the initial reg expression list
RebuildRegExpList();
return -1; // fail to create
}
m_wndStatusBar.SetPaneInfo(1, ID_DIFFNUM, 0, 150);
+ m_wndStatusBar.SetPaneInfo(2, ID_DIFFSTATUS, 0, 200);
// TODO: Remove this if you don't want tool tips or a resizeable toolbar
m_wndToolBar.SetBarStyle(m_wndToolBar.GetBarStyle() |
m_pMergeDoc->m_strRightFile = szRight;
m_pMergeDoc->m_ltBuf.FreeAll();
m_pMergeDoc->m_rtBuf.FreeAll();
+ m_pMergeDoc->m_ltBuf.SetEolSensitivity(m_bEolSensitive);
+ m_pMergeDoc->m_rtBuf.SetEolSensitivity(m_bEolSensitive);
m_pMergeDoc->m_ltBuf.LoadFromFile(szLeft);
m_pMergeDoc->m_rtBuf.LoadFromFile(szRight);
m_pDirDoc->Redisplay();
}
-void CMainFrame::OnOptionsShowUnique()
+void CMainFrame::OnOptionsShowUniqueLeft()
+{
+ m_bShowUniqueLeft = !m_bShowUniqueLeft;
+ theApp.WriteProfileInt(_T("Settings"), _T("ShowUniqueLeft"), m_bShowUniqueLeft);
+ if (m_pDirDoc != NULL)
+ m_pDirDoc->Redisplay();
+}
+
+void CMainFrame::OnOptionsShowUniqueRight()
{
- m_bShowUnique = !m_bShowUnique;
- theApp.WriteProfileInt(_T("Settings"), _T("ShowUnique"), m_bShowUnique);
+ m_bShowUniqueRight = !m_bShowUniqueRight;
+ theApp.WriteProfileInt(_T("Settings"), _T("ShowUniqueRight"), m_bShowUniqueRight);
if (m_pDirDoc != NULL)
m_pDirDoc->Redisplay();
}
pCmdUI->SetCheck(m_bShowIdent);
}
-void CMainFrame::OnUpdateOptionsShowunique(CCmdUI* pCmdUI)
+void CMainFrame::OnUpdateOptionsShowuniqueleft(CCmdUI* pCmdUI)
{
- pCmdUI->SetCheck(m_bShowUnique);
+ pCmdUI->SetCheck(m_bShowUniqueLeft);
}
+void CMainFrame::OnUpdateOptionsShowuniqueright(CCmdUI* pCmdUI)
+{
+ pCmdUI->SetCheck(m_bShowUniqueRight);
+}
gen.m_nIgnoreWhite = m_nIgnoreWhitespace;
gen.m_bIgnoreCase = m_bIgnoreCase;
gen.m_bIgnoreBlankLines = m_bIgnoreBlankLines;
+ gen.m_bEolSensitive = m_bEolSensitive;
gen.m_bScroll = m_bScrollToFirst;
gen.m_nTabSize = m_nTabSize;
gen.m_bDisableSplash = theApp.m_bDisableSplash;
ignore_all_space_flag = (m_nIgnoreWhitespace==2);
ignore_space_change_flag = (m_nIgnoreWhitespace==1);
ignore_blank_lines_flag = m_bIgnoreBlankLines = gen.m_bIgnoreBlankLines;
+ m_bEolSensitive = gen.m_bEolSensitive;
+ ignore_eol_diff = !m_bEolSensitive;
ignore_case_flag = m_bIgnoreCase = gen.m_bIgnoreCase;
- ignore_some_changes = (m_nIgnoreWhitespace!=0) || m_bIgnoreCase || m_bIgnoreBlankLines;
+ ignore_some_changes = (m_nIgnoreWhitespace!=0) || m_bIgnoreCase || m_bIgnoreBlankLines || !m_bEolSensitive;
length_varies = (m_nIgnoreWhitespace!=0);
m_bIgnoreRegExp = filter.m_bIgnoreRegExp;
}
}
+// callback for progress during diff
+class MainFrmStatus : public IDiffStatus
+{
+public:
+ MainFrmStatus(CMainFrame * pFrame) : m_pFrame(pFrame) { m_pFrame->clearStatus(); }
+ virtual void rptFile(BYTE code) { m_pFrame->rptStatus(code); }
+private:
+ CMainFrame * m_pFrame;
+};
+
+// clear counters used to track diff progress
+void CMainFrame::clearStatus()
+{
+ m_nStatusFileSame = m_nStatusFileDiff = m_nStatusFileBinDiff = m_nStatusFileError
+ = m_nStatusLeftFileOnly = m_nStatusLeftDirOnly = m_nStatusRightFileOnly = m_nStatusRightDirOnly
+ = 0;
+}
+
+// diff completed another file
+void CMainFrame::rptStatus(BYTE code)
+{
+ switch(code)
+ {
+ case FILE_SAME:
+ ++m_nStatusFileSame;
+ break;
+ case FILE_DIFF:
+ ++m_nStatusFileDiff;
+ break;
+ case FILE_BINDIFF:
+ ++m_nStatusFileBinDiff;
+ break;
+ case FILE_ERROR:
+ ++m_nStatusFileError;
+ break;
+ case FILE_LUNIQUE:
+ ++m_nStatusLeftFileOnly;
+ break;
+ case FILE_LDIRUNIQUE:
+ ++m_nStatusLeftDirOnly;
+ break;
+ case FILE_RUNIQUE:
+ ++m_nStatusRightFileOnly;
+ break;
+ case FILE_RDIRUNIQUE:
+ ++m_nStatusRightDirOnly;
+ break;
+ }
+ CString s;
+ // AfxFormatString4 doesn't exist
+ s.Format(_T("s:%d d:%d lf:%d ld:%d rf:%d rd:%d bd:%d e:%d")
+ , m_nStatusFileSame, m_nStatusFileDiff, m_nStatusFileBinDiff, m_nStatusFileError
+ , m_nStatusLeftFileOnly, m_nStatusLeftDirOnly, m_nStatusRightFileOnly, m_nStatusRightDirOnly);
+ m_wndStatusBar.SetPaneText(2, s);
+
+}
BOOL CMainFrame::DoFileOpen(LPCTSTR pszLeft /*=NULL*/, LPCTSTR pszRight /*=NULL*/, BOOL bRecurse /*= FALSE*/)
{
_T("\tLeft: %s\r\n")
_T("\tRight: %s\r\n")
_T("\tRecurse: %d\r\n")
- _T("\tShowUnique: %d\r\n")
+ _T("\tShowUniqueLeft: %d\r\n")
+ _T("\tShowUniqueRight: %d\r\n")
_T("\tShowIdentical: %d\r\n")
_T("\tShowDiff: %d\r\n")
_T("\tHideBak: %d\r\n")
strLeft,
strRight,
bRecurse,
- m_bShowUnique,
+ m_bShowUniqueLeft,
+ m_bShowUniqueRight,
m_bShowIdent,
m_bShowDiff,
m_bHideBak,
m_pDirDoc = (CDirDoc*)theApp.m_pDirTemplate->OpenDocumentFile(NULL);
if (m_pDirDoc != NULL)
{
- CDiffContext *pCtxt = new CDiffContext(strLeft, strRight);
+ MainFrmStatus mfst(this);
+ CDiffContext *pCtxt = new CDiffContext(strLeft, strRight, &mfst);
if (pCtxt != NULL)
{
m_pDirDoc->SetDiffContext(pCtxt);
s.Format(_T("%s\\%s") BACKUP_FILE_EXT, path, name);
// get rid of the dest file
- DeleteFile(s);
+ DeleteFile(s); // (errors are handled from MoveFile below)
// move the sucker
if (!MoveFile(pszPath, s)
}
// Get user language description of error, if available
-static CString
-GetSystemErrorDesc(int nerr)
+CString CMainFrame::GetSystemErrorDesc(int nerr)
{
LPVOID lpMsgBuf;
CString str = _T("?");
}
// trim trailing line returns
-static void TrimRightLines(CString & str)
+void CMainFrame::RemoveLineReturns(CString & str)
{
str.Replace(_T("\n"), _T(""));
str.Replace(_T("\r"), _T(""));
}
// Delete file (return TRUE if deleted, else put up error & return FALSE)
-static BOOL DeleteOrError(LPCTSTR szFile)
+BOOL CMainFrame::DeleteFileOrError(LPCTSTR szFile)
{
- // TODO: 2002-11-22, need to handle deleting directories
if (!DeleteFile(szFile))
{
CString sError = GetSystemErrorDesc(GetLastError());
- TrimRightLines(sError);
+ RemoveLineReturns(sError);
+ sError += (CString)_T(" [") + szFile + _T("]");
CString s;
- AfxFormatString1(s, IDS_DELETE_FAILED, sError);
+ AfxFormatString1(s, IDS_DELETE_FILE_FAILED, sError);
AfxMessageBox(s, MB_OK|MB_ICONSTOP);
return FALSE;
}
}
// Prompt & delete file (return TRUE if deleted)
-BOOL CMainFrame::ConfirmAndDelete(LPCTSTR szFile)
+BOOL CMainFrame::ConfirmAndDeleteFile(LPCTSTR szFile)
+{
+ CString s;
+ AfxFormatString1(s, IDS_CONFIRM_DELETE_FILE, szFile);
+ if (AfxMessageBox(s, MB_YESNO|MB_ICONQUESTION)!=IDYES)
+ return FALSE;
+ return DeleteFileOrError(szFile);
+}
+
+// Prompt & delete directory (return TRUE if deleted)
+BOOL CMainFrame::ConfirmAndDeleteDir(LPCTSTR szDir)
{
CString s;
- AfxFormatString1(s, IDS_CONFIRM_DELETE, szFile);
+ AfxFormatString1(s, IDS_CONFIRM_DELETE_DIR, szDir);
if (AfxMessageBox(s, MB_YESNO|MB_ICONQUESTION)!=IDYES)
return FALSE;
- return DeleteOrError(szFile);
+ return DeleteRecurseDir(szDir);
}
+// delete directory by recursively deleting all contents
+// gives up on first error
+BOOL CMainFrame::DeleteRecurseDir(LPCTSTR szDir)
+{
+ CFileFind finder;
+ CString sSpec = szDir;
+ sSpec += _T("\\*.*");
+ if (finder.FindFile(sSpec))
+ {
+ BOOL done=FALSE;
+ while (!done)
+ {
+ done = !finder.FindNextFile();
+ if (finder.IsDots()) continue;
+ if (finder.IsDirectory())
+ {
+ if (!DeleteRecurseDir(finder.GetFilePath()))
+ return FALSE;
+ }
+ else
+ {
+ if (!DeleteFileOrError(finder.GetFilePath()))
+ return FALSE;
+ }
+ }
+ }
+ finder.Close(); // must close the handle or RemoveDirectory will fail
+ if (!RemoveDirectory(szDir))
+ {
+ CString sError = GetSystemErrorDesc(GetLastError());
+ RemoveLineReturns(sError);
+ sError += (CString)_T(" [") + szDir + _T("]");
+ CString s;
+ AfxFormatString1(s, IDS_DELETE_FILE_FAILED, sError);
+ AfxMessageBox(s, MB_OK|MB_ICONSTOP);
+ return FALSE;
+ }
+ return TRUE;
+}
BOOL CMainFrame::SyncFiles(LPCTSTR pszSrc, LPCTSTR pszDest)
{
return FALSE;
// Now it's just a matter of copying the right file to the left
- DeleteFile(strSavePath);
+ DeleteFile(strSavePath); // (errors are handled from CopyFile below)
if (!CopyFile(pszSrc, strSavePath, FALSE))
{
// Attributes
public:
- BOOL m_bShowUnique;
+ BOOL m_bShowUniqueLeft;
+ BOOL m_bShowUniqueRight;
BOOL m_bShowDiff;
BOOL m_bShowIdent;
BOOL m_bBackup;
LOGFONT m_lfDiff;
BOOL m_bFontSpecified;
+ BOOL m_bEolSensitive;
// Operations
public:
+ CString GetSystemErrorDesc(int nerr);
+ void RemoveLineReturns(CString & str);
+ BOOL DeleteFileOrError(LPCTSTR szFile);
+ BOOL DeleteRecurseDir(LPCTSTR szDir);
+ BOOL ConfirmAndDeleteFile(LPCTSTR szFile);
+ BOOL ConfirmAndDeleteDir(LPCTSTR szDir);
+ void rptStatus(BYTE code);
+ void clearStatus();
+ BOOL SyncFiles(LPCTSTR pszSrc, LPCTSTR pszDest);
+ void UpdateCurrentFileStatus(UINT nStatus);
+ BOOL DoFileOpen(LPCTSTR pszLeft = NULL, LPCTSTR pszRight = NULL, BOOL bRecurse = FALSE);
+ void ShowMergeDoc(LPCTSTR szLeft, LPCTSTR szRight);
+ void UpdateResources();
+ HMENU NewDefaultMenu();
+ BOOL CreateBackup(LPCTSTR pszPath);
+ BOOL CheckSavePath(CString& strSavePath);
// Overrides
// ClassWizard generated virtual function overrides
virtual void ActivateFrame(int nCmdShow = -1);
//}}AFX_VIRTUAL
-// Implementation
+// Implementation methods
+protected:
+ void CleanupFileBufs();
+ virtual ~CMainFrame();
+
+// Public implementation data
public:
BOOL m_bFirstTime;
CString m_strSaveAsPath;
- void CleanupFileBufs();
BOOL m_bIgnoreBlankLines;
BOOL m_bIgnoreCase;
BOOL m_bIgnoreRegExp;
CString m_sPattern;
- void UpdateResources();
- void UpdateCurrentFileStatus(UINT nStatus);
- BOOL ConfirmAndDelete(LPCTSTR szFile);
- BOOL SyncFiles(LPCTSTR pszSrc, LPCTSTR pszDest);
- BOOL CreateBackup(LPCTSTR pszPath);
UINT m_nTabSize;
- BOOL DoFileOpen(LPCTSTR pszLeft = NULL, LPCTSTR pszRight = NULL, BOOL bRecurse = FALSE);
- BOOL CheckSavePath(CString& strSavePath);
CString m_strVssPath;
CString m_strVssProject;
CString m_strVssUser; // BSP - Visual Source Safe User ID
BOOL m_bHideBak;
int m_nIgnoreWhitespace;
BOOL m_bScrollToFirst;
- void ShowMergeDoc(LPCTSTR szLeft, LPCTSTR szRight);
CMergeEditView *m_pLeft, *m_pRight;
CMergeDoc *m_pMergeDoc;
CDirDoc *m_pDirDoc;
- virtual ~CMainFrame();
- HMENU NewDefaultMenu();
+// Implementation data
+protected:
+ int m_nStatusFileSame;
+ int m_nStatusFileDiff;
+ int m_nStatusFileBinDiff;
+ int m_nStatusFileError;
+ int m_nStatusLeftFileOnly;
+ int m_nStatusLeftDirOnly;
+ int m_nStatusRightFileOnly;
+ int m_nStatusRightDirOnly;
+
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
//{{AFX_MSG(CMainFrame)
afx_msg void OnOptionsShowDifferent();
afx_msg void OnOptionsShowIdentical();
- afx_msg void OnOptionsShowUnique();
+ afx_msg void OnOptionsShowUniqueLeft();
+ afx_msg void OnOptionsShowUniqueRight();
afx_msg void OnUpdateOptionsShowdifferent(CCmdUI* pCmdUI);
afx_msg void OnUpdateOptionsShowidentical(CCmdUI* pCmdUI);
- afx_msg void OnUpdateOptionsShowunique(CCmdUI* pCmdUI);
+ afx_msg void OnUpdateOptionsShowuniqueleft(CCmdUI* pCmdUI);
+ afx_msg void OnUpdateOptionsShowuniqueright(CCmdUI* pCmdUI);
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnFileOpen();
afx_msg void OnUpdateHideBackupFiles(CCmdUI* pCmdUI);
BEGIN
MENUITEM "Show &Identical Files", ID_OPTIONS_SHOWIDENTICAL
MENUITEM "Show &Different Files", ID_OPTIONS_SHOWDIFFERENT
- MENUITEM "Show &Unique Files", ID_OPTIONS_SHOWUNIQUE
+ MENUITEM "Show Le&ft Unique Files", ID_OPTIONS_SHOWUNIQUELEFT
+ MENUITEM "Show Ri&ght Unique Files", ID_OPTIONS_SHOWUNIQUERIGHT
MENUITEM "Hide *.&BAK Files", ID_HIDE_BACKUP_FILES
MENUITEM SEPARATOR
MENUITEM "Select &Font...", ID_VIEW_SELECTFONT
VK_BACK, ID_EDIT_UNDO, VIRTKEY, ALT, NOINVERT
VK_DELETE, ID_EDIT_CUT, VIRTKEY, SHIFT, NOINVERT
VK_DOWN, ID_NEXTDIFF, VIRTKEY, ALT, NOINVERT
+ VK_END, ID_LASTDIFF, VIRTKEY, ALT, NOINVERT
VK_F6, ID_NEXT_PANE, VIRTKEY, NOINVERT
VK_F6, ID_PREV_PANE, VIRTKEY, SHIFT, NOINVERT
+ VK_HOME, ID_FIRSTDIFF, VIRTKEY, ALT, NOINVERT
VK_INSERT, ID_EDIT_COPY, VIRTKEY, CONTROL, NOINVERT
VK_INSERT, ID_EDIT_PASTE, VIRTKEY, SHIFT, NOINVERT
VK_LEFT, ID_R2L, VIRTKEY, ALT, NOINVERT
- VK_NEXT, ID_LASTDIFF, VIRTKEY, ALT, NOINVERT
- VK_PRIOR, ID_FIRSTDIFF, VIRTKEY, ALT, NOINVERT
VK_RETURN, ID_CURDIFF, VIRTKEY, ALT, NOINVERT
VK_RIGHT, ID_L2R, VIRTKEY, ALT, NOINVERT
VK_UP, ID_PREVDIFF, VIRTKEY, ALT, NOINVERT
CONTROL "Ignore &case",IDC_IGNCASE_CHECK,"Button",
BS_AUTOCHECKBOX | WS_TABSTOP,17,57,53,10
CONTROL "&Disable Splash Screen",IDC_DISABLE_SPLASH,"Button",
- BS_AUTOCHECKBOX | WS_TABSTOP,17,69,87,10
+ BS_AUTOCHECKBOX | WS_TABSTOP,17,81,87,10
CONTROL "Compare &whitespace",IDC_WHITESPACE,"Button",
BS_AUTORADIOBUTTON | WS_GROUP,128,45,82,10
CONTROL "Ignore whitespace c&hange",IDC_WHITE_CHANGE,"Button",
GROUPBOX "Tabs",IDC_STATIC,7,105,221,30,WS_GROUP
LTEXT "&Tab size:",IDC_STATIC,15,119,30,8
EDITTEXT IDC_TAB_EDIT,47,118,27,12,ES_AUTOHSCROLL
+ CONTROL "Sensitive to &EOL",IDC_EOL_SENSITIVE,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,17,68,69,10
END
IDD_LANGUAGE_SELECT DIALOG DISCARDABLE 0, 0, 213, 111
STRINGTABLE DISCARDABLE
BEGIN
ID_FILE_NEW "Create a new document\nNew"
- ID_FILE_OPEN "Open an existing document\nOpen"
+ ID_FILE_OPEN "Open an existing document\nOpen (Ctrl+O)"
ID_FILE_CLOSE "Close the active document\nClose"
- ID_FILE_SAVE "Save the active document\nSave"
+ ID_FILE_SAVE "Save the active document\nSave (Ctrl+S)"
ID_FILE_SAVE_AS "Save the active document with a new name\nSave As"
ID_FILE_PAGE_SETUP "Change the printing options\nPage Setup"
ID_FILE_PRINT_SETUP "Change the printer and printing options\nPrint Setup"
STRINGTABLE DISCARDABLE
BEGIN
- ID_L2R "Copy the selected text to the right file\nCopy Right (Right Arrow)"
- ID_R2L "Copy the selected text to the left file\nCopy Left (Left Arrow)"
+ ID_L2R "Copy the selected text to the right file\nCopy Right (Alt Right)"
+ ID_R2L "Copy the selected text to the left file\nCopy Left (Alt Left)"
ID_OPTIONS_SHOWIDENTICAL "Displays files that are exactly the same"
ID_OPTIONS_SHOWDIFFERENT "Displays files that have differences"
- ID_OPTIONS_SHOWUNIQUE "Displays files that exist in only one directory"
- ID_PREVDIFF "Scroll to the previous difference\nPrev Diff (Shift+Tab)"
- ID_NEXTDIFF "Scroll to the next difference\nNext Diff (Tab)"
+ ID_PREVDIFF "Scroll to the previous difference\nPrev Diff (Alt Up)"
+ ID_NEXTDIFF "Scroll to the next difference\nNext Diff (Alt Down)"
ID_OPTIONS_BACKUPORIGINALFILE
"Save a copy of the original as *.bak\nBackup"
END
ID_DIR_COPY_FILE_TO_RIGHT "Copy selected file to named directory"
ID_VIEW_LANGUAGE "Select the current user interfacce language\nLanguage"
ID_HELP_CONTENTS "Displays the WinMerge User's Guide\nHelp"
- ID_FIRSTDIFF "Scroll to the first difference\nFirst Diff"
- ID_CURDIFF "Scroll to the current difference\nCurrent Diff"
- ID_LASTDIFF "Scroll to the last difference\nLast Diff"
+ ID_FIRSTDIFF "Scroll to the first difference\nFirst Diff (Alt+Home)"
+ ID_CURDIFF "Scroll to the current difference\nCurrent Diff (Alt+Enter)"
+ ID_LASTDIFF "Scroll to the last difference\nLast Diff (Alt+End)"
ID_DIFFNUM "placeholder"
ID_DIR_DEL_LEFT "Delete selected file on left"
ID_DIR_DEL_RIGHT "Delete selected file on right"
+ ID_DIFFSTATUS "placeholder for status count"
+ ID_OPTIONS_SHOWUNIQUELEFT "Displays files that exist in only on left side"
+ ID_OPTIONS_SHOWUNIQUERIGHT
+ "Displays files that exist in only on right side"
END
STRINGTABLE DISCARDABLE
"Unable to backup original file.\nContinue anyway?"
IDS_PROPERTIES_TITLE "Properties"
IDS_OPEN_TITLE "Open"
- IDS_CONFIRM_DELETE "Delete %1?"
+ IDS_CONFIRM_DELETE_FILE "Delete file %1?"
IDS_EDIT_WINDOW_TITLE_FMT "Edit %1"
IDS_FILESSAME "The selected files are identical."
IDS_FILEUNIQUE "The selected file didn't exist in both directories and therefore couldn't be compared."
STRINGTABLE DISCARDABLE
BEGIN
IDS_DEL_RIGHT_FMT "Del right: %1"
- IDS_DELETE_FAILED "Delete failed: %1"
+ IDS_DELETE_FILE_FAILED "Delete file failed: %1"
+ IDS_CONFIRM_DELETE_DIR "Delete directory %1?"
+ IDS_REMOVE_DIR_FAILED "Remove directory failed: %1"
END
#endif // English (U.S.) resources
m_nTabSize = 0;
m_bIgnoreCase = FALSE;
m_bIgnoreBlankLines = FALSE;
+ m_bEolSensitive = FALSE;
m_bDisableSplash = FALSE;
m_nIgnoreWhite = -1;
//}}AFX_DATA_INIT
DDX_Text(pDX, IDC_TAB_EDIT, m_nTabSize);
DDX_Check(pDX, IDC_IGNCASE_CHECK, m_bIgnoreCase);
DDX_Check(pDX, IDC_IGNBLANKS_CHECK, m_bIgnoreBlankLines);
+ DDX_Check(pDX, IDC_EOL_SENSITIVE, m_bEolSensitive);
DDX_Check(pDX, IDC_DISABLE_SPLASH, m_bDisableSplash);
DDX_Radio(pDX, IDC_WHITESPACE, m_nIgnoreWhite);
//}}AFX_DATA_MAP
UINT m_nTabSize;
BOOL m_bIgnoreCase;
BOOL m_bIgnoreBlankLines;
+ BOOL m_bEolSensitive;
BOOL m_bDisableSplash;
int m_nIgnoreWhite;
//}}AFX_DATA
/* Ignore changes in horizontal white space (-b). */
EXTERN int ignore_space_change_flag;
+/* Ignore end of line differences (at least between UNIX & DOS */
+EXTERN int ignore_eol_diff;
+
/* Ignore all horizontal white space (-w). */
EXTERN int ignore_all_space_flag;
#ifdef __cplusplus
}
-#endif
\ No newline at end of file
+#endif
h = 0;
/* Hash this line until we find a newline. */
+ /* Perry 2002-11-26 added EOL insensitivity */
if (ignore_case_flag)
{
if (ignore_all_space_flag)
else if (ignore_space_change_flag)
while ((c = *p++) != '\n')
{
+ if (ignore_eol_diff && c=='\r' && *p=='\n')
+ continue;
if (isspace (c))
{
while (isspace (c = *p++))
}
else
while ((c = *p++) != '\n')
+ {
+ if (ignore_eol_diff && c=='\r' && *p=='\n')
+ continue;
h = HASH (h, isupper (c) ? tolower (c) : c);
+ }
}
else
{
else if (ignore_space_change_flag)
while ((c = *p++) != '\n')
{
+ if (ignore_eol_diff && c=='\r' && *p=='\n')
+ continue;
if (isspace (c))
{
while (isspace (c = *p++))
}
else
while ((c = *p++) != '\n')
+ {
+ if (ignore_eol_diff && c=='\r' && *p=='\n')
+ continue;
h = HASH (h, c);
+ }
}
hashing_done:;
bucket = &buckets[h % nbuckets];
length = (char const HUGE *) p - ip - ((char const HUGE *) p == incomplete_tail);
+ if (ignore_eol_diff && length>1 && p[-2]=='\r' && p[-1]=='\n')
+ {
+ ((char HUGE *)p)[-2] = '\n';
+ --length;
+ }
for (i = *bucket; ; i = eqs[i].next)
if (!i)
{
// detect both types of EOL for each line
// handles mixed mode files.
+ // Perry (2002-11-26): What about MAC files ? They don't have 0x0A at all. I think this doesn't handle them.
if( c==0x0A )
{
- TCHAR prevChar = pcLineBuf[nCurrentLength-2];
+ // 2002-11-26 Perry fixed bug & added optional sensitivity to CR
// remove EOL characters
- pcLineBuf[nCurrentLength - (prevChar==0x0D?2:1) ] = '\0';
+ if (!m_EolSensitive && nCurrentLength>1)
+ {
+ TCHAR prevChar = pcLineBuf[nCurrentLength-2];
+ pcLineBuf[nCurrentLength - (prevChar==0x0D?2:1) ] = '\0';
+ }
+ else
+ {
+ pcLineBuf[nCurrentLength - 1] = '\0';
+ }
nCurrentLength = 0;
if (m_nSourceEncoding >= 0)
iconvert (pcLineBuf, m_nSourceEncoding, 1, m_nSourceEncoding == 15);
BOOL m_bReadOnly;
BOOL m_bModified;
int m_nCRLFMode;
+ BOOL m_EolSensitive;
BOOL m_bCreateBackupFile;
int m_nUndoBufSize;
int FindLineWithFlag (DWORD dwFlag);
BOOL GetReadOnly () const;
void SetReadOnly (BOOL bReadOnly = TRUE);
+ void SetEolSensitivity(BOOL EolSensitive) { m_EolSensitive = EolSensitive; }
+
// Text modification functions
BOOL InsertText (CCrystalTextView * pSource, int nLine, int nPos, LPCTSTR pszText, int &nEndLine, int &nEndChar, int nAction = CE_ACTION_UNKNOWN, BOOL bUpdate =TRUE);
BOOL DeleteText (CCrystalTextView * pSource, int nStartLine, int nStartPos, int nEndLine, int nEndPos, int nAction = CE_ACTION_UNKNOWN, BOOL bUpdate =TRUE);
--- /dev/null
+2002-11-26 Perry
+ Implemented recursive directory delete
+ Fix bug in EOL handling in crystaltextbuffer, and add optional EOL sensitivity.
+ Added optional EOL insensitivity to gnu diff IO.c.
+ Added status bar progress (file count) indicator during scanning
+ Fixed tooltips of toolbar buttons to list correct hotkeys
+ Split "Show Unique" option into "Show Left Unique" and "Show Right Unique"
+
+2002-12-02
+ Added left files, left dirs, right files, right dirs to status bar feedback
+
#define IDS_PROPERTIES_TITLE 147
#define IDS_OPEN_TITLE 148
#define IDS_CONFIRM_DELETE 149
+#define IDS_CONFIRM_DELETE_FILE 149
#define IDS_EDIT_WINDOW_TITLE_FMT 150
#define IDS_FILESSAME 151
#define IDS_FILEUNIQUE 152
#define IDS_DEL_LEFT_FMT 175
#define IDS_DEL_RIGHT_FMT 176
#define IDS_DELETE_FAILED 177
+#define IDS_DELETE_FILE_FAILED 177
+#define IDS_CONFIRM_DELETE_DIR 178
+#define IDS_REMOVE_DIR_FAILED 179
#define IDB_EQUAL 213
#define IDB_NOTEQUAL 214
#define IDB_RFOLDER 215
#define IDC_WHITE_CHANGE 1025
#define IDC_WHITESPACE 1026
#define IDC_USER 1027
+#define IDC_EOL_SENSITIVE 1027
#define IDC_PASSWORD 1028
#define IDC_DIFFERENCE_COLOR 1031
#define IDC_SEL_DIFFERENCE_COLOR 1032
#define ID_DIFFNUM 32806
#define ID_DIR_DEL_LEFT 32807
#define ID_DIR_DEL_RIGHT 32808
+#define ID_DIFFSTATUS 32809
+#define ID_OPTIONS_SHOWUNIQUELEFT 32810
+#define ID_OPTIONS_SHOWUNIQUERIGHT 32811
// Next default values for new objects
//
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_3D_CONTROLS 1
#define _APS_NEXT_RESOURCE_VALUE 135
-#define _APS_NEXT_COMMAND_VALUE 32809
+#define _APS_NEXT_COMMAND_VALUE 32812
#define _APS_NEXT_CONTROL_VALUE 1032
#define _APS_NEXT_SYMED_VALUE 106
#endif