Update of /cvsroot/anyedit/AnyEditv2/Plugins/Diff In directory sc8-pr-cvs1:/tmp/cvs-serv2505/Plugins/Diff Added Files: Diff.aps Diff.clw Diff.cpp Diff.def Diff.dsp Diff.dsw Diff.ncb Diff.opt Diff.plg Diff.rc DiffDlg.cpp DiffDlg.h DiffEngine.cpp DiffEngine.h FilePartition.cpp FilePartition.h ReadMe.txt Resource.h StdAfx.cpp StdAfx.h Templates.h Log Message: Added Initial plugin support Added diff plugin --- NEW FILE: Diff.aps --- (This appears to be a binary file; contents omitted.) --- NEW FILE: Diff.clw --- ; CLW file contains information for the MFC ClassWizard [General Info] Version=1 ClassCount=1 ResourceCount=1 NewFileInclude1=#include "stdafx.h" Class1=CDiffDlg LastClass=CDiffDlg LastTemplate=CDialog Resource1=IDD_DIALOG1 [DLG:IDD_DIALOG1] Type=1 Class=CDiffDlg ControlCount=9 Control1=IDOK,button,1342242817 Control2=IDCANCEL,button,1342242816 Control3=ID_EDIT1,edit,1350631552 Control4=ID_EDIT2,edit,1350631552 Control5=ID_BUTTON1,button,1342242816 Control6=ID_BUTTON2,button,1342242816 Control7=ID_CHECK1,button,1342242819 Control8=ID_CHECK2,button,1342242819 Control9=65535,button,1342177287 [CLS:CDiffDlg] Type=0 HeaderFile=DiffDlg.h ImplementationFile=DiffDlg.cpp BaseClass=CDialog Filter=D LastObject=IDOK VirtualFilter=dWC --- NEW FILE: Diff.cpp --- // Diff.cpp : Defines the initialization routines for the DLL. // #include "stdafx.h" #include <afxdllx.h> #include "../../Plugin.h" #include "DiffDlg.h" #include "Resource.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif static AFX_EXTENSION_MODULE DiffDLL = { NULL, NULL }; extern "C" int APIENTRY DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) { // Remove this if you use lpReserved UNREFERENCED_PARAMETER(lpReserved); if (dwReason == DLL_PROCESS_ATTACH) { TRACE0("DIFF.DLL Initializing!\n"); // Extension DLL one-time initialization if (!AfxInitExtensionModule(DiffDLL, hInstance)) return 0; // Insert this DLL into the resource chain // NOTE: If this Extension DLL is being implicitly linked to by // an MFC Regular DLL (such as an ActiveX Control) // instead of an MFC application, then you will want to // remove this line from DllMain and put it in a separate // function exported from this Extension DLL. The Regular DLL // that uses this Extension DLL should then explicitly call that // function to initialize this Extension DLL. Otherwise, // the CDynLinkLibrary object will not be attached to the // Regular DLL's resource chain, and serious problems will // result. new CDynLinkLibrary(DiffDLL); } else if (dwReason == DLL_PROCESS_DETACH) { TRACE0("DIFF.DLL Terminating!\n"); // Terminate the library before destructors are called AfxTermExtensionModule(DiffDLL); } return 1; // ok } extern "C" int EntryFunction(CPlugin * plugin) { CDiffDlg dlg; dlg.SetPlugin(plugin); dlg.DoModal(); //plugin->OpenUrl("http://www.google.com"); return 0; } --- NEW FILE: Diff.def --- ; Diff.def : Declares the module parameters for the DLL. LIBRARY "Diff" DESCRIPTION 'Diff Windows Dynamic Link Library' EXPORTS ; Explicit exports can go here EntryFunction --- NEW FILE: Diff.dsp --- # Microsoft Developer Studio Project File - Name="Diff" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 CFG=Diff - Win32 Debug !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "Diff.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "Diff.mak" CFG="Diff - Win32 Debug" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "Diff - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") !MESSAGE "Diff - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") !MESSAGE # Begin Project # PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" CPP=cl.exe MTL=midl.exe RSC=rc.exe !IF "$(CFG)" == "Diff - Win32 Release" # PROP BASE Use_MFC 6 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "Release" # PROP BASE Intermediate_Dir "Release" # PROP BASE Target_Dir "" # PROP Use_MFC 6 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "Release" # PROP Intermediate_Dir "Release" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_WINDLL" /D "_AFXDLL" /Yu"stdafx.h" /FD /c # ADD CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_WINDLL" /D "_AFXDLL" /D "_MBCS" /D "_AFXEXT" /Yu"stdafx.h" /FD /c # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "NDEBUG" /d "_AFXDLL" # ADD RSC /l 0x409 /d "NDEBUG" /d "_AFXDLL" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 /nologo /subsystem:windows /dll /machine:I386 # ADD LINK32 /nologo /subsystem:windows /dll /machine:I386 /out:"../../bin/Plugins/Diff.dll" !ELSEIF "$(CFG)" == "Diff - Win32 Debug" # PROP BASE Use_MFC 6 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir "Debug" # PROP BASE Intermediate_Dir "Debug" # PROP BASE Target_Dir "" # PROP Use_MFC 6 # PROP Use_Debug_Libraries 1 # PROP Output_Dir "Debug" # PROP Intermediate_Dir "Debug" # PROP Target_Dir "" # ADD BASE CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_WINDLL" /D "_AFXDLL" /Yu"stdafx.h" /FD /GZ /c # ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_WINDLL" /D "_AFXDLL" /D "_MBCS" /D "_AFXEXT" /Yu"stdafx.h" /FD /GZ /c # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" # ADD RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept # ADD LINK32 /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept !ENDIF # Begin Target # Name "Diff - Win32 Release" # Name "Diff - Win32 Debug" # Begin Group "Source Files" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" # Begin Group "diffengine" # PROP Default_Filter "" # Begin Source File SOURCE=.\DiffEngine.cpp # End Source File # Begin Source File SOURCE=.\DiffEngine.h # End Source File # Begin Source File SOURCE=.\FilePartition.cpp # End Source File # Begin Source File SOURCE=.\FilePartition.h # End Source File # End Group # Begin Source File SOURCE=.\Diff.cpp # End Source File # Begin Source File SOURCE=.\Diff.def # End Source File # Begin Source File SOURCE=.\Diff.rc # End Source File # Begin Source File SOURCE=.\DiffDlg.cpp # End Source File # Begin Source File SOURCE=.\StdAfx.cpp # ADD CPP /Yc"stdafx.h" # End Source File # End Group # Begin Group "Header Files" # PROP Default_Filter "h;hpp;hxx;hm;inl" # Begin Source File SOURCE=.\DiffDlg.h # End Source File # Begin Source File SOURCE=.\Resource.h # End Source File # Begin Source File SOURCE=.\StdAfx.h # End Source File # End Group # Begin Group "Resource Files" # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" # Begin Source File SOURCE=.\res\Diff.rc2 # End Source File # End Group # Begin Source File SOURCE=.\ReadMe.txt # End Source File # End Target # End Project --- NEW FILE: Diff.dsw --- Microsoft Developer Studio Workspace File, Format Version 6.00 # WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! ############################################################################### Project: "Diff"=.\Diff.dsp - Package Owner=<4> Package=<5> {{{ }}} Package=<4> {{{ }}} ############################################################################### Global: Package=<5> {{{ }}} Package=<3> {{{ }}} ############################################################################### --- NEW FILE: Diff.ncb --- Microsoft C/C++ program database 2.00 --- NEW FILE: Diff.opt --- (This appears to be a binary file; contents omitted.) --- NEW FILE: Diff.plg --- <html> <body> <pre> <h1>Build Log</h1> <h3> --------------------Configuration: Diff - Win32 Release-------------------- </h3> <h3>Command Lines</h3> <h3>Results</h3> Diff.dll - 0 error(s), 0 warning(s) </pre> </body> </html> --- NEW FILE: Diff.rc --- //Microsoft Developer Studio generated resource script. // #include "resource.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 2 resource. // #include "afxres.h" ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // English (U.S.) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) #ifdef _WIN32 LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US #pragma code_page(1252) #endif //_WIN32 #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // TEXTINCLUDE // 1 TEXTINCLUDE DISCARDABLE BEGIN "resource.h\0" END 2 TEXTINCLUDE DISCARDABLE BEGIN "#include ""afxres.h""\r\n" "\0" END 3 TEXTINCLUDE DISCARDABLE BEGIN "#define _AFX_NO_SPLITTER_RESOURCES\r\n" "#define _AFX_NO_OLE_RESOURCES\r\n" "#define _AFX_NO_TRACKER_RESOURCES\r\n" "#define _AFX_NO_PROPERTY_RESOURCES\r\n" "\r\n" "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n" "#ifdef _WIN32\r\n" "LANGUAGE 9, 1\r\n" "#pragma code_page(1252)\r\n" "#endif //_WIN32\r\n" "#include ""res\\Diff.rc2"" // non-Microsoft Visual C++ edited resources\r\n" "#include ""afxres.rc"" // Standard components\r\n" "#endif\r\n" "\0" END #endif // APSTUDIO_INVOKED #ifndef _MAC ///////////////////////////////////////////////////////////////////////////// // // Version // VS_VERSION_INFO VERSIONINFO FILEVERSION 1,0,0,1 PRODUCTVERSION 1,0,0,1 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L #else FILEFLAGS 0x0L #endif FILEOS 0x4L FILETYPE 0x2L FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904B0" BEGIN VALUE "CompanyName", "\0" VALUE "FileDescription", "Diff DLL\0" VALUE "FileVersion", "1, 0, 0, 1\0" VALUE "InternalName", "Diff\0" VALUE "LegalCopyright", "Copyright (C) 2003\0" VALUE "LegalTrademarks", "\0" VALUE "OriginalFilename", "Diff.DLL\0" VALUE "ProductName", "Diff Dynamic Link Library\0" VALUE "ProductVersion", "1, 0, 0, 1\0" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 1200 END END #endif // !_MAC ///////////////////////////////////////////////////////////////////////////// // // Dialog // IDD_DIALOG1 DIALOGEX 0, 0, 283, 82 STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_APPWINDOW CAPTION "diff tool" FONT 8, "MS Sans Serif" BEGIN DEFPUSHBUTTON "Diff",IDOK,171,61,50,14 PUSHBUTTON "Cancel",IDCANCEL,226,61,50,14 EDITTEXT ID_EDIT1,7,13,253,12,ES_AUTOHSCROLL EDITTEXT ID_EDIT2,7,31,253,12,ES_AUTOHSCROLL PUSHBUTTON "...",ID_BUTTON1,261,13,15,12,0,WS_EX_CLIENTEDGE PUSHBUTTON "...",ID_BUTTON2,261,31,15,12,0,WS_EX_CLIENTEDGE CONTROL "case",ID_CHECK1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, 15,60,41,11 CONTROL "indent",ID_CHECK2,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, 60,60,42,11 GROUPBOX "Options",-1,7,50,97,25 END ///////////////////////////////////////////////////////////////////////////// // // DESIGNINFO // #ifdef APSTUDIO_INVOKED GUIDELINES DESIGNINFO DISCARDABLE BEGIN IDD_DIALOG1, DIALOG BEGIN LEFTMARGIN, 7 TOPMARGIN, 7 END END #endif // APSTUDIO_INVOKED #endif // English (U.S.) resources ///////////////////////////////////////////////////////////////////////////// #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 3 resource. // #define _AFX_NO_SPLITTER_RESOURCES #define _AFX_NO_OLE_RESOURCES #define _AFX_NO_TRACKER_RESOURCES #define _AFX_NO_PROPERTY_RESOURCES #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) #ifdef _WIN32 LANGUAGE 9, 1 #pragma code_page(1252) #endif //_WIN32 #include "res\Diff.rc2" // non-Microsoft Visual C++ edited resources #include "afxres.rc" // Standard components #endif ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED --- NEW FILE: DiffDlg.cpp --- // DiffDlg.cpp : implementation file // #include "stdafx.h" #include "Resource.h" #include "DiffDlg.h" #include "FilePartition.h" #include "DiffEngine.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // CDiffDlg dialog CDiffDlg::CDiffDlg(CWnd* pParent /*=NULL*/) : CDialog(CDiffDlg::IDD, pParent) { //{{AFX_DATA_INIT(CDiffDlg) m_bCheckCase = FALSE; m_bCheckIndent = FALSE; m_szFile1 = _T(""); m_szFile2 = _T(""); //}}AFX_DATA_INIT } void CDiffDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CDiffDlg) DDX_Check(pDX, ID_CHECK1, m_bCheckCase); DDX_Check(pDX, ID_CHECK2, m_bCheckIndent); DDX_Text(pDX, ID_EDIT1, m_szFile1); DDX_Text(pDX, ID_EDIT2, m_szFile2); //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(CDiffDlg, CDialog) //{{AFX_MSG_MAP(CDiffDlg) ON_BN_CLICKED(ID_BUTTON1, OnButton1) ON_BN_CLICKED(65535, On65535) //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CDiffDlg message handlers BOOL FileExists(CString &szFilename) { BOOL bFound = FALSE; WIN32_FIND_DATA findFile; HANDLE hContext; hContext=::FindFirstFile(szFilename.GetBuffer(0), &findFile); if ( hContext != INVALID_HANDLE_VALUE ) { ::FindClose(hContext); bFound = TRUE; } return bFound; } BOOL IsAFolder(CString &szFilename) { if (!FileExists(szFilename)) return FALSE; BOOL bIsADirectory = FALSE; WIN32_FIND_DATA findFile; HANDLE hContext; hContext=::FindFirstFile(szFilename.GetBuffer(0), &findFile); if ( hContext != INVALID_HANDLE_VALUE ) { if (findFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) bIsADirectory = TRUE; ::FindClose(hContext); } return bIsADirectory; } BOOL DoDiff(BOOL bSilentMode, CString &szFile1, CString &szFile2, CString &szOutfile, CFileOptions &o) { // make sure those files exist if ( !FileExists(szFile1) ) { TCHAR szError[MAX_PATH]; sprintf(szError, _T("%s does not exist."), szFile1.GetBuffer(0) ); AfxMessageBox(szError); return FALSE; } if ( !FileExists(szFile2) ) { TCHAR szError[MAX_PATH]; sprintf(szError, _T("%s does not exist."), szFile2.GetBuffer(0) ); AfxMessageBox(szError); return FALSE; } CFilePartition f1; CFilePartition f2; BOOL bFile1IsAFolder = IsAFolder(szFile1); BOOL bFile2IsAFolder = IsAFolder(szFile2); if ( bFile1IsAFolder && bFile2IsAFolder ) { // process folders f1.PreProcessFolder( szFile1, o ); f2.PreProcessFolder( szFile2, o ); } else if ( !bFile1IsAFolder && !bFile2IsAFolder) { // process files f1.PreProcess( szFile1, o ); f2.PreProcess( szFile2, o ); } else { // error (folder and a file cannot match, anyway) TCHAR szError[MAX_PATH]; sprintf(szError, _T("%s cannot be compared with %s."), szFile1.GetBuffer(0), szFile2.GetBuffer(0) ); AfxMessageBox(szError); return FALSE; } CFilePartition f1_bis, f2_bis; CDiffEngine d; d.Diff(f1,f2,f1_bis,f2_bis); if ( szOutfile.IsEmpty() ) // default output file for GUI mode szOutfile = "out.html"; d.MySerialize(szOutfile,f1_bis, f2_bis); // open with the default browser if (!bSilentMode) ::ShellExecute(NULL, "open", szOutfile.GetBuffer(0), NULL, NULL, SW_SHOW); return TRUE; } BOOL ExtractFiles(CFileDialog &fd, CString &f1, CString &f2) { if ( fd.m_ofn.lpstrFile[0]=='\0' ) return FALSE; // struct was not used // get directory CString szDir = fd.m_ofn.lpstrFile; // get first file CString szFile1 = fd.m_ofn.lpstrFile + fd.m_ofn.nFileOffset; szFile1 = szDir + "\\" + szFile1; TCHAR *p = fd.m_ofn.lpstrFile + fd.m_ofn.nFileOffset; if (*p==0) return FALSE; while ( *p ) p++; p++; // do we have a double 0 ? if (*p==0) return FALSE; // so, only one file was selected CString szFile2 = p; szFile2 = szDir + "\\" + szFile2; f1 = szFile2; f2 = szFile1; return TRUE; } void CDiffDlg::OnButton1() { UpdateData(TRUE); // update the DDX variables // show open file dialog, and let choose one or more files CFileDialog my_dialog(TRUE,NULL,NULL,OFN_ALLOWMULTISELECT|OFN_FILEMUSTEXIST|OFN_EXPLORER/*flags*/,NULL); my_dialog.m_ofn.lpstrFile = (TCHAR*) malloc( 2*MAX_PATH*sizeof(TCHAR) ); memset( my_dialog.m_ofn.lpstrFile, 0, 2*MAX_PATH*sizeof(TCHAR) ); my_dialog.m_ofn.nMaxFile = 2*MAX_PATH; // number of chars, not number of bytes if (my_dialog.DoModal()==IDOK) { // do we have two files selected ? if (!ExtractFiles(my_dialog, m_szFile1, m_szFile2) ) { UpdateData(TRUE); // update the DDX variables m_szFile1=my_dialog.GetPathName(); UpdateData(FALSE); // update the dialog box } else UpdateData(FALSE); // update the dialog box } free( my_dialog.m_ofn.lpstrFile ); } void CDiffDlg::On65535() { UpdateData(TRUE); // update the DDX variables // show open file dialog, and let choose one or more files CFileDialog my_dialog(TRUE,NULL,NULL,OFN_ALLOWMULTISELECT|OFN_FILEMUSTEXIST|OFN_EXPLORER/*flags*/,NULL); my_dialog.m_ofn.lpstrFile = (TCHAR*) malloc( 2*MAX_PATH*sizeof(TCHAR) ); memset( my_dialog.m_ofn.lpstrFile, 0, 2*MAX_PATH*sizeof(TCHAR) ); my_dialog.m_ofn.nMaxFile = 2*MAX_PATH; // number of chars, not number of bytes if (my_dialog.DoModal()==IDOK) { // do we have two files selected ? if (!ExtractFiles(my_dialog, m_szFile1, m_szFile2) ) { UpdateData(TRUE); // update the DDX variables m_szFile2=my_dialog.GetPathName(); UpdateData(FALSE); // update the dialog box } else UpdateData(FALSE); // update the dialog box } free( my_dialog.m_ofn.lpstrFile ); } void CDiffDlg::OnOK() { UpdateData(TRUE); // update the DDX variables CFileOptions o; if (!m_bCheckCase) o.SetOption( CString("case"), CString("no") ); if (!m_bCheckIndent) o.SetOption( CString("indent"), CString("no") ); CString app_path = parent_plugin->GetAppPath(); app_path+= "Temp\\Diff.html"; if(DoDiff(TRUE, m_szFile1, m_szFile2, app_path, o)) { parent_plugin->OpenUrl(app_path); CDialog::OnOK(); } } void CDiffDlg::SetPlugin(CPlugin *plugin) { parent_plugin = plugin; } --- NEW FILE: DiffDlg.h --- #if !defined(AFX_DIFFDLG_H__2B1B4FCC_CCB6_470E_8FCF_F3D3A802CE45__INCLUDED_) #define AFX_DIFFDLG_H__2B1B4FCC_CCB6_470E_8FCF_F3D3A802CE45__INCLUDED_ #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 // DiffDlg.h : header file // #include "../../plugin.h" #include "Resource.h" ///////////////////////////////////////////////////////////////////////////// // CDiffDlg dialog class CDiffDlg : public CDialog { // Construction public: void SetPlugin(CPlugin * plugin); CDiffDlg(CWnd* pParent = NULL); // standard constructor // Dialog Data //{{AFX_DATA(CDiffDlg) enum { IDD = IDD_DIALOG1 }; BOOL m_bCheckCase; BOOL m_bCheckIndent; CString m_szFile1; CString m_szFile2; //}}AFX_DATA // Overrides // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CDiffDlg) protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support //}}AFX_VIRTUAL // Implementation protected: CPlugin * parent_plugin; // Generated message map functions //{{AFX_MSG(CDiffDlg) afx_msg void OnButton1(); afx_msg void On65535(); virtual void OnOK(); //}}AFX_MSG DECLARE_MESSAGE_MAP() }; //{{AFX_INSERT_LOCATION}} // Microsoft Visual C++ will insert additional declarations immediately before the previous line. #endif // !defined(AFX_DIFFDLG_H__2B1B4FCC_CCB6_470E_8FCF_F3D3A802CE45__INCLUDED_) --- NEW FILE: DiffEngine.cpp --- #include "stdafx.h" #include "FilePartition.h" #include "DiffEngine.h" CDiffEngine::CDiffEngine() { m_szColorText = "#888888"; // default colors m_szColorBackground = "white"; m_szColorChanged = "#FFFFBB"; m_szColorAdded = "#BBFFBB"; m_szColorDeleted = "#FFBBBB"; m_szFooter = "<br><font size='-2' color='#BBBBBB'>AnyEdit Diff Plugin - S.Rodriguez</font>"; } // compare f1 (old version) with f2 (new version) // and build two new copies of those file objects with status on a line by line basis // BOOL CDiffEngine::Diff( /*in*/CFilePartition &f1, /*in*/CFilePartition &f2, /*out*/CFilePartition &f1_bis, /*out*/CFilePartition &f2_bis) { f1_bis.SetName( f1.GetName() ); f2_bis.SetName( f2.GetName() ); long nbf1Lines = f1.GetNBLines(); long nbf2Lines = f2.GetNBLines(); // special empty file case if ( nbf1Lines==0 ) { long nLinef2 = 0; CString s; while ( nLinef2<nbf2Lines ) { f1_bis.AddBlankLine(); f2_bis.AddString( f2.GetRawLine(nLinef2++), Normal); } return TRUE; } long i = 0; long nf2CurrentLine = 0; while ( i<nbf1Lines ) { // process this line (and possibly update indexes as well) long nLinef2 = nf2CurrentLine; if ( nLinef2 >= nbf2Lines ) { // it's time to end the game now while ( i < nbf1Lines ) { f1_bis.AddString( f1.GetRawLine(i), Deleted); f2_bis.AddBlankLine(); i++; } break; } if ( f1.MatchLine(i, f2, /*out*/nLinef2) ) { BOOL bDeleted = FALSE; if (nLinef2 > nf2CurrentLine) { long itmp = nf2CurrentLine; bDeleted = f2.MatchLine(nf2CurrentLine, f1, /*out*/itmp) && (itmp<nLinef2); if (bDeleted) { long j = itmp - i; if(j>0) { while ( j>0 ) { f1_bis.AddString( f1.GetRawLine(i), Deleted); f2_bis.AddBlankLine(); i++; j--; } } else { i++; } // please note nf2CurrentLine is not updated continue; // jump here to loop iteration } } // matched, so either the lines were identical, or f2 has added one or more lines if (nLinef2 > nf2CurrentLine) { // add blank lines to f1_bis long j = nLinef2 - nf2CurrentLine; while ( j>0 ) { f1_bis.AddBlankLine(); f2_bis.AddString( f2.GetRawLine(nLinef2-j), Added ); j--; } } // exactly matched f1_bis.AddString( f1.GetRawLine(i), Normal); f2_bis.AddString( f2.GetRawLine(nLinef2), Normal); nf2CurrentLine = nLinef2 + 1; // next line in f2 } else { // this line is not found at all in f2, either it's because it has been changed, or even deleted long nLinef1 = i; if ( f2.MatchLine(nLinef2, f1, /*out*/nLinef1) ) { // the dual line in f2 can be found in f1, that's because // the current line in f1 has been deleted f1_bis.AddString( f1.GetRawLine(i), Deleted); f2_bis.AddBlankLine(); // this whole block is flagged as deleted if (nLinef1>i+1) { long j = nLinef1 - (i+1); while ( j>0 ) { i++; f1_bis.AddString( f1.GetRawLine(i), Deleted); f2_bis.AddBlankLine(); j--; } } // note : nf2CurrentLine is not incremented } else { // neither added, nor deleted, so it's flagged as changed f1_bis.AddString( f1.GetRawLine(i), Changed); f2_bis.AddString( f2.GetRawLine(nLinef2), Changed); nf2CurrentLine = nLinef2 + 1; // next line in f2 } } i++; // next line in f1 } // are there any remaining lines from f2? while ( nf2CurrentLine < nbf2Lines ) { f1_bis.AddBlankLine(); f2_bis.AddString( f2.GetRawLine(nf2CurrentLine), Added ); nf2CurrentLine++; } return TRUE; } // build html report // void CDiffEngine::SetTitles(CString &szHeader, CString &szFooter) { m_szHeader = szHeader; m_szFooter = szFooter; } void CDiffEngine::SetColorStyles(CString &szText, CString &szBackground, CString &szChanged, CString &szAdded, CString &szDeleted) { m_szColorText = szText; m_szColorBackground = szBackground; m_szColorChanged = szChanged; m_szColorAdded = szAdded; m_szColorDeleted = szDeleted; } CString CDiffEngine::Serialize( /*in*/CFilePartition &f1, /*in*/CFilePartition &f2) { // eval amount of differences between the two files int nAdded_f1, nChanged_f1, nDeleted_f1; f1.HowManyChanges(/*out*/nAdded_f1, /*out*/nChanged_f1, /*out*/nDeleted_f1); int nAdded_f2, nChanged_f2, nDeleted_f2; f2.HowManyChanges(/*out*/nAdded_f2, /*out*/nChanged_f2, /*out*/nDeleted_f2); int nTotal = nAdded_f1 + nDeleted_f1 + nChanged_f1 + nAdded_f2 + nDeleted_f2; if (nTotal==0) m_szHeader += "<font size=-1><b>Files are identical.</font><br>"; else { TCHAR szTmp[128]; sprintf(szTmp,"<font size=-1><b>%d changes between the files.</font><br>", nTotal); m_szHeader += szTmp; } // write html header CString s = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">\r\n" \ "<!-- diff html gen, (c) Stephane Rodriguez - feb 2003 -->\r\n" \ "<HTML>\r\n" \ "<HEAD>\r\n" \ "<TITLE> File Diff </TITLE>\r\n" \ "<style type='text/css'>\r\n"\ "<!--\r\n" \ ".N { background-color:white; }\r\n" \ ".C { background-color:" + m_szColorChanged + "; }\r\n" \ ".A { background-color:" + m_szColorAdded + "; }\r\n" \ ".D { background-color:" + m_szColorDeleted + "; }\r\n" \ "-->\r\n" \ "</style>\r\n" \ "</HEAD>\r\n" \ "\r\n" \ "<BODY BGCOLOR='#FFFFFF'>\r\n" \ "\r\n" + m_szHeader + \ "<table border=0 bgcolor=0 cellpadding=1 cellspacing=1 width=100%><tr><td>\r\n" \ "<table width=100% bgcolor=white border=0 cellpadding=0 cellspacing=0>\r\n" \ "<tr bgColor='#EEEEEE' style='color:0'><td width=50%>old version</td><td width=50%>new version" \ " (<b style='background-color:" + m_szColorChanged + ";width:20'> </b>changed " \ "<b style='background-color:" + m_szColorAdded + ";width:20'> </b>added " \ "<b style='background-color:" + m_szColorDeleted + ";width:20'> </b>deleted) " \ "<FORM ACTION='' style='display:inline'><SELECT id='fontoptions' " \ "onchange='maintable.style.fontSize=this.options[this.selectedIndex].value'>" \ "<option value='6pt'>6pt<option value='7pt'>7pt<option value='8pt'>8pt<option value='9pt' selected>9pt</SELECT> " \ "</FORM></td></tr>\r\n" \ "<tr bgColor='#EEEEEE' style='color:0'><td width=50%><code>" + f1.GetName() + "</code></td><td width=50%><code>" + f2.GetName() + "</code></td></tr>" \ "</table>\r\n" \ "</td></tr>\r\n" \ "</table>\r\n" \ "\r\n" \ "<br>\r\n" \ "\r\n" ; long nbLines = f1.GetNBLines(); if (nbLines==0) { s += "<br>empty files"; } else { s += "<table border=0 bgcolor=0 cellpadding=1 cellspacing=1 width=100%><tr><td>" \ "<table id='maintable' width=100% bgcolor='" + m_szColorBackground + "' cellpadding=0 cellspacing=0 border=0 style='color:" + m_szColorText + ";font-family: Courier New, Helvetica, sans-serif; font-size: 8pt'>\r\n"; } char *arrStatus[4] = { "", " class='C'", " class='A'", " class='D'" }; CString sc; TCHAR szLine[16]; // write content // for (long i=0; i<nbLines; i++) { sprintf(szLine, "<b>%d</b>", i); sc += "<tr><td width=50%" + CString(arrStatus[ f1.GetStatusLine(i) ]) + ">" + CString(szLine) + " " + Escape(f1.GetRawLine(i)) + "</td>"; sc += "<td width=50%" + CString(arrStatus[ f2.GetStatusLine(i) ]) + ">" + CString(szLine) + " " + Escape(f2.GetRawLine(i)) + "</td></tr>"; } // for i s += sc; if (nbLines>0) s += "</table></td></tr></table>\r\n"; // write html footer s += m_szFooter + "</BODY>\r\n" \ "</HTML>\r\n"; return s; } CString CDiffEngine::Escape(CString &s) // a helper aimed to make sure tag symbols are passed as content { CString o; long nSize = s.GetLength(); if (nSize==0) return CString(" "); TCHAR c; BOOL bIndentation = TRUE; for (long i=0; i<nSize; i++) { c = s.GetAt(i); if (bIndentation && (c==' ' || c=='\t')) { if (c==' ') o += " "; else o += " "; continue; } bIndentation = FALSE; if (c=='<') o += "<"; else if (c=='>') o += ">"; else if (c=='&') o += "&"; else o += c; } return o; } BOOL CDiffEngine::ExportAsHtml(/*in*/CString &szFilename, /*in*/CString &szContent) { /*CStdioFile f; if ( !f.Open(szFilename, CFile::modeCreate | CFile::modeWrite | CFile::typeBinary) ) { TCHAR szError[MAX_PATH]; sprintf(szError, "error : cannot create %s\r\n", szFilename.GetBuffer(0) ); OutputDebugString(szError); return FALSE; } f.Write(szContent.GetBuffer(0), szContent.GetLength()); f.Close();*/ FILE * fp; fp = fopen(szFilename,"rw"); fprintf(fp,"%s",szContent); fclose(fp); return TRUE; } BOOL CDiffEngine::ExportAsStdout(/*in*/CString &szContent) { printf ("%s", szContent.GetBuffer(0)); return TRUE; } void CDiffEngine::MySerialize(LPCSTR fname, CFilePartition &f1, CFilePartition &f2) { FILE * fp = fopen(fname,"w+"); // eval amount of differences between the two files int nAdded_f1, nChanged_f1, nDeleted_f1; f1.HowManyChanges(/*out*/nAdded_f1, /*out*/nChanged_f1, /*out*/nDeleted_f1); int nAdded_f2, nChanged_f2, nDeleted_f2; f2.HowManyChanges(/*out*/nAdded_f2, /*out*/nChanged_f2, /*out*/nDeleted_f2); int nTotal = nAdded_f1 + nDeleted_f1 + nChanged_f1 + nAdded_f2 + nDeleted_f2; if (nTotal==0) m_szHeader += "<font size=-1><b>Files are identical.</font><br>"; else { TCHAR szTmp[128]; sprintf(szTmp,"<font size=-1><b>%d changes between the files.</font><br>", nTotal); m_szHeader += szTmp; } // write html header CString s = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">\r\n" \ "<!-- diff html gen, (c) Stephane Rodriguez - feb 2003 -->\r\n" \ "<HTML>\r\n" \ "<HEAD>\r\n" \ "<TITLE> File Diff </TITLE>\r\n" \ "<style type='text/css'>\r\n"\ "<!--\r\n" \ ".N { background-color:white; }\r\n" \ ".C { background-color:" + m_szColorChanged + "; }\r\n" \ ".A { background-color:" + m_szColorAdded + "; }\r\n" \ ".D { background-color:" + m_szColorDeleted + "; }\r\n" \ "-->\r\n" \ "</style>\r\n" \ "</HEAD>\r\n" \ "\r\n" \ "<BODY BGCOLOR='#FFFFFF'>\r\n" \ "\r\n" + m_szHeader + \ "<table border=0 bgcolor=0 cellpadding=1 cellspacing=1 width=100%><tr><td>\r\n" \ "<table width=100% bgcolor=white border=0 cellpadding=0 cellspacing=0>\r\n" \ "<tr bgColor='#EEEEEE' style='color:0'><td width=50%>old version</td><td width=50%>new version" \ " (<b style='background-color:" + m_szColorChanged + ";width:20'> </b>changed " \ "<b style='background-color:" + m_szColorAdded + ";width:20'> </b>added " \ "<b style='background-color:" + m_szColorDeleted + ";width:20'> </b>deleted) " \ "<FORM ACTION='' style='display:inline'><SELECT id='fontoptions' " \ "onchange='maintable.style.fontSize=this.options[this.selectedIndex].value'>" \ "<option value='6pt'>6pt<option value='7pt'>7pt<option value='8pt'>8pt<option value='9pt' selected>9pt</SELECT> " \ "</FORM></td></tr>\r\n" \ "<tr bgColor='#EEEEEE' style='color:0'><td width=50%><code>" + f1.GetName() + "</code></td><td width=50%><code>" + f2.GetName() + "</code></td></tr>" \ "</table>\r\n" \ "</td></tr>\r\n" \ "</table>\r\n" \ "\r\n" \ "<br>\r\n" \ "\r\n" ; long nbLines = f1.GetNBLines(); if (nbLines==0) { s += "<br>empty files"; } else { s += "<table border=0 bgcolor=0 cellpadding=1 cellspacing=1 width=100%><tr><td>" \ "<table id='maintable' width=100% bgcolor='" + m_szColorBackground + "' cellpadding=0 cellspacing=0 border=0 style='color:" + m_szColorText + ";font-family: Courier New, Helvetica, sans-serif; font-size: 8pt'>\r\n"; } fprintf(fp,"%s",s); char *arrStatus[4] = { "", " class='C'", " class='A'", " class='D'" }; CString sc; TCHAR szLine[16]; // write content // for (long i=0; i<nbLines; i++) { sprintf(szLine, "<b>%d</b>", i); sc = "<tr><td width=50%" + CString(arrStatus[ f1.GetStatusLine(i) ]) + ">" + CString(szLine) + " " + Escape(f1.GetRawLine(i)) + "</td>"; sc += "<td width=50%" + CString(arrStatus[ f2.GetStatusLine(i) ]) + ">" + CString(szLine) + " " + Escape(f2.GetRawLine(i)) + "</td></tr>"; fprintf(fp,"%s",sc); } // for i if (nbLines>0) s = "</table></td></tr></table>\r\n"; else s = ""; // write html footer s += m_szFooter + "</BODY>\r\n" \ "</HTML>\r\n"; fprintf(fp,"%s",s); fclose(fp); } --- NEW FILE: DiffEngine.h --- #pragma once // DiffEngine //////////////////////////////////////////////////////// // // ////////////////////////////////////////////////////////////////////// // S.Rodriguez - Feb 2003 ////////////////////////////////////////////////////////////////////// // // class CDiffEngine { // Members protected: CString m_szColorText, m_szColorBackground, m_szColorChanged, m_szColorAdded, m_szColorDeleted; // used by the html renderer CString m_szHeader, m_szFooter; // Constructor public: CDiffEngine(); // Accessors public: void MySerialize(LPCSTR fname,CFilePartition &f1,CFilePartition &f2); // Methods // compare f1 (old version) with f2 (new version) // and build two new copies of those file objects with status on a line by line basis // BOOL Diff( /*in*/CFilePartition &f1, /*in*/CFilePartition &f2, /*out*/CFilePartition &f1_bis, /*out*/CFilePartition &f2_bis); // build html report // void SetTitles(/*in*/CString &szHeader, /*in*/CString &szFooter); void SetColorStyles(/*in*/CString &szText, /*in*/CString &szBackground, /*in*/CString &szChanged, /*in*/CString &szAdded, /*in*/CString &szDeleted); CString Serialize( /*in*/CFilePartition &f1, /*in*/CFilePartition &f2); BOOL ExportAsHtml(/*in*/CString &szFilename, /*in*/CString &szContent); BOOL ExportAsStdout(/*in*/CString &szContent); // Helpers protected: CString Escape(CString &s); }; --- NEW FILE: FilePartition.cpp --- #include "stdafx.h" #include "FilePartition.h" // CFileLine /////////////////////////////////////////////////// // // // Constructor CFileLine::CFileLine() { SetStatus(Normal); } // Accessors long CFileLine::SetLine(/*in*/CString &s, /*in*/CFileOptions &o) // store string and build token { m_s = s; CString so = GetLineWithOptions(s,o); long nToken = 0; long nLength = so.GetLength(); TCHAR *lpString = so.GetBuffer(0); for (long i=0; i<nLength; i++) nToken += 2*nToken + *(lpString++); // (George V. Reilly hint) return nToken; } void CFileLine::SetLine(/*in*/CString &s, /*in*/LineStatus ls) // store string and status (does not eval ID) { m_s = s; SetStatus(ls); } CString CFileLine::GetLine(/*in*/CFileOptions &o) { if ( o.IsDefaultOptions() ) return m_s; else return GetLineWithOptions(m_s,o); } CString CFileLine::GetLineWithOptions(/*in*/CString s,/*in*/CFileOptions &o) { if ( o.IsDefaultOptions() ) return s; CString so = s; // should we take care about indentation differences ? CString szIndentoption = o.GetOption( CString("indent") ); if ( !szIndentoption.IsEmpty() && szIndentoption!="yes") { // no, then remove all 09 and 20 chars from the begin of the string long nSize = so.GetLength(); if (nSize>0) { TCHAR c; BOOL bIndentation = TRUE; for (long i=0; i<nSize && bIndentation; i++) { c = so.GetAt(i); if (c!=0x20 && c!=0x09) bIndentation = FALSE; } so = bIndentation ? so : so.Right( so.GetLength()+1 - i); } } // should we care about case differences ? CString szCaseoption = o.GetOption( CString("case") ); if ( !szCaseoption.IsEmpty() && szCaseoption!="yes") { // no, then make sure we lower the case so.MakeLower(); } return so; } void CFileLine::SetStatus(/*in*/LineStatus ls) { m_status = ls; } LineStatus CFileLine::GetStatus() { return m_status; } // CFileOptions ///////////////////////////////////////////////////// // ///////////////////////////////////////////////////////////////////// // S.Rodriguez - Feb 2003 ///////////////////////////////////////////////////////////////////// // // CFileOptions::CFileOptions() { } // Accessors void CFileOptions::SetOption(/*in*/CString &szOptionName, /*in*/CString &szOptionValue) { // is it a new option ? long nSize = arrOptions.GetSize(); BOOL bFound = FALSE; for (long i=0; i<nSize && !bFound; i++) { CString s = arrOptions.GetAt(i); if (!s.IsEmpty() && s.Find(szOptionName,0)==0) { bFound = TRUE; long n = s.Find(';',0); if (n>-1) s = s.Left(n) + ";" + szOptionValue; else s = s + ";" + szOptionValue; arrOptions.SetAt(i, s); } } // for if (!bFound) { CString s = szOptionName + ";" + szOptionValue; arrOptions.Add(s); } } CString CFileOptions::GetOption(/*in*/CString &szOptionName) { long nSize = arrOptions.GetSize(); for (long i=0; i<nSize; i++) { CString s = arrOptions.GetAt(i); if (!s.IsEmpty() && s.Find(szOptionName,0)==0) { long n = s.Find(';',0); if (n>-1) return s.Right( s.GetLength() - (n+1) ); else return CString(""); } } // for return CString(""); } BOOL CFileOptions::IsDefaultOptions() { return GetOptionCount()==0; } long CFileOptions::GetOptionCount() { return arrOptions.GetSize(); } CString CFileOptions::GetOption(long i) { return (i>=0 && i<GetOptionCount()) ? arrOptions.GetAt(i) : CString(""); } // Methods void CFileOptions::Copy(CFileOptions &src) { long nbOptions = src.GetOptionCount(); for (long i=0; i<nbOptions; i++) arrOptions.Add( src.GetOption(i) ); } // CFilePartition /////////////////////////////////////////////////// // // CFilePartition::CFilePartition() { } CFilePartition::~CFilePartition() { // remember to destroy those CFileLine objects long nSize = GetNBLines(); for (long i=0; i<nSize; i++) delete m_arrLines.GetAt(i); } void CFilePartition::SetName(CString &szName) { m_szFilename = szName; } CString CFilePartition::GetName() { return m_szFilename; } void CFilePartition::SetOptions(/*in*/CFileOptions &options) { m_options.Copy(options); } long CFilePartition::GetNBLines() { return m_arrLines.GetSize(); } CString CFilePartition::GetLine(/*in*/long i) { ASSERT( i>=0 && i<GetNBLines()); CFileLine *pLine = NULL; if (i>=0 && i<GetNBLines()) pLine = m_arrLines.GetAt(i); return pLine ? pLine->GetLine(m_options) : CString(""); } CString CFilePartition::GetRawLine(/*in*/long i) // returns an arbitrary line (not filtered) { CFileOptions o; // default options ASSERT( i>=0 && i<GetNBLines()); CFileLine *pLine = NULL; if (i>=0 && i<GetNBLines()) pLine = m_arrLines.GetAt(i); return pLine ? pLine->GetLine(o) : CString(""); } LineStatus CFilePartition::GetStatusLine(/*in*/long i) { ASSERT( i>=0 && i<GetNBLines()); CFileLine *pLine = NULL; if (i>=0 && i<GetNBLines()) pLine = m_arrLines.GetAt(i); return pLine ? pLine->GetStatus() : Normal; } long *CFilePartition::GetTokens() { return m_arrTokens.GetData(); } void CFilePartition::HowManyChanges(/*out*/int &nAdded, /*out*/int &nChanged, /*out*/int &nDeleted) { nAdded = nChanged = nDeleted = 0; LineStatus currentStatus = Normal; CFileLine *pLine = NULL; long nSize = GetNBLines(); for (long i=0; i<nSize; i++) { pLine = m_arrLines.GetAt(i); if (!pLine) continue; LineStatus ls = pLine->GetStatus(); if (ls!=Normal && currentStatus!=ls) { switch (ls) { case Added: nAdded++; break; case Changed: nChanged++; break; case Deleted: nDeleted++; break; } } } // end for all lines } // PreProcess // // purpose : reads a file, on a line-by-line basis // BOOL CFilePartition::PreProcess(/*in*/CString &szFilename, /*in*/CFileOptions &options) { ASSERT( !szFilename.IsEmpty() ); if (szFilename.IsEmpty()) { OutputDebugString("error : empty input filename\r\n"); return FALSE; } SetName(szFilename); SetOptions(options); // read the file first, // and build the table of tokens CStdioFile f; if ( !f.Open(szFilename, CFile::modeRead) ) { TCHAR szError[MAX_PATH]; sprintf(szError, "error : cannot open %s\r\n", szFilename.GetBuffer(0) ); OutputDebugString(szError); return FALSE; } // CString s; while ( f.ReadString(s) ) AddString(s); f.Close(); return TRUE; } // PreProcessFolder // // purpose : list folders, files and subfolders // and then build a tree-like list out of it // BOOL CFilePartition::PreProcessFolder(/*in*/CString &szFolder, /*in*/CFileOptions &options) { SetName(szFolder); SetOptions(options); long nIndent = 0; // make sure there is no trailing backslash while (!szFolder.IsEmpty() && szFolder.GetAt( szFolder.GetLength()-1 )=='\\') szFolder = szFolder.Left( szFolder.GetLength()-1 ); return PreProcessFolder(szFolder, options, nIndent); } BOOL CFilePartition::PreProcessFolder(/*in*/CString &szFolder, /*in*/CFileOptions &options, /*in/out*/long nIndent) { if (szFolder.IsEmpty()) return FALSE; CSortedArray arrFiles; long i; CString szIndent; for (i=0; i<nIndent; i++) szIndent += " "; // add this folder CString szCurrentFolder = szFolder; int nBackSlash = szCurrentFolder.ReverseFind('\\'); if (nBackSlash>-1) szCurrentFolder = szCurrentFolder.Right( szCurrentFolder.GetLength()-(nBackSlash+1) ); // add the folder in the partition AddString( szIndent + "+ " + szCurrentFolder ); CString szFolderWildCard = szFolder + "\\*.*"; WIN32_FIND_DATA findFile; HANDLE hContext; hContext=::FindFirstFile(szFolderWildCard.GetBuffer(0), &findFile); if ( hContext != INVALID_HANDLE_VALUE ) { do { if (strcmp(findFile.cFileName,".")!=0 && strcmp(findFile.cFileName,"..")!=0) { if (findFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { // it's a folder // CString szSubFolder = szFolder + "\\" + findFile.cFileName; PreProcessFolder(szSubFolder, options, nIndent+1); } else { // it's a file // // GetInformationByHandle OFSTRUCT ofstruct; BY_HANDLE_FILE_INFORMATION infostruct; HFILE hFile = ::OpenFile(szFolder + "\\" + findFile.cFileName, &ofstruct, OF_READ | OF_SHARE_DENY_NONE); if (hFile!=HFILE_ERROR && ::GetFileInformationByHandle( (HANDLE)hFile, &infostruct) ) { SYSTEMTIME stCreate; // Convert the local file time from UTC to system time. FileTimeToSystemTime(&infostruct.ftLastWriteTime, &stCreate); TCHAR sDate[128]; sprintf(sDate, "%02d/%02d/%d %02d:%02d", stCreate.wDay, stCreate.wMonth, stCreate.wYear, stCreate.wHour, stCreate.wMinute); ::_lclose(hFile); arrFiles.InsertSorted( CString(findFile.cFileName + CString(" (") + sDate + ")") ); } } } } while ( ::FindNextFile(hContext, &findFile) ); ::FindClose(hContext); } // add all files at this point long nbFiles = arrFiles.GetSize(); for (i=0; i<nbFiles; i++) AddString( szIndent + " " + arrFiles.GetAt(i) ); return TRUE; } void CFilePartition::AddString(/*in*/CString &s, /*in*/LineStatus ls) { CFileLine *p = new CFileLine(); ASSERT(p); if (p) { p->SetLine(s, ls); m_arrLines.Add( p ); } } void CFilePartition::AddBlankLine() { AddString(CString(""), Normal); } void CFilePartition::AddString(/*in*/CString &s) { CFileLine *p = new CFileLine(); ASSERT(p); if (p) { m_arrTokens.Add( p->SetLine(s, m_options) ); m_arrLines.Add( p ); } } void CFilePartition::Dump(/*in*/CString &szTitle) { TCHAR s[MAX_PATH]; sprintf(s, "%s : %d lines\r\n\r\n", szTitle.GetBuffer(0), GetNBLines() ); OutputDebugString(s); long nSize = GetNBLines(); for (long i=0; i<nSize; i++) { LineStatus ls = GetStatusLine(i); if (ls==Normal) OutputDebugString("Normal "); else if (ls==Changed) OutputDebugString("Changed "); else if (ls==Added) OutputDebugString("Added "); else if (ls==Deleted) OutputDebugString("Deleted "); OutputDebugString( GetLine(i) ); OutputDebugString("\r\n"); } } BOOL CFilePartition::MatchLine(/*in*/long i1, /*in*/CFilePartition &f2, /*out*/long &i2) { ASSERT( m_arrTokens.GetSize()>0 ); if ( m_arrTokens.GetSize()==0 ) return FALSE; ASSERT( i1<GetNBLines() ); if ( i1>=GetNBLines() ) return FALSE; // should never happen though // try to match the current token from f1, into the a subset of f2 tokens // long nf1Token; nf1Token = m_arrTokens[i1]; long *pf2Tokens = f2.GetTokens(); if (!pf2Tokens) return FALSE; BOOL bFound = FALSE; long i = 0; long nf2SubsetLines = f2.GetNBLines() - i2; long *pf2Token = pf2Tokens + i2; // points to the right token while (!bFound && i<nf2SubsetLines) { if (nf1Token == *pf2Token) // fast compare { // make sure strings really match bFound = ( GetLine(i1).Compare( f2.GetLine(i2+i) )==0 ); } pf2Token++; i++; } i--; if (bFound) { i2 += i; return TRUE; } return FALSE; } --- NEW FILE: FilePartition.h --- #include "Templates.h" #pragma once typedef enum {Normal=0, Changed, Added, Deleted} LineStatus; class CFileLine; // forward declaration class CFileOptions; // forward declaration class CFilePartition; // forward declaration // CFileLine /////////////////////////////////////////////// // //////////////////////////////////////////////////////////// // S.Rodriguez - Feb 2003 //////////////////////////////////////////////////////////// // class CFileLine { // Members protected: CString m_s; LineStatus m_status; // Constructor public: CFileLine(); // Accessors public: long SetLine(/*in*/CString &s, /*in*/CFileOptions &o); // store string and build token void SetLine(/*in*/CString &s, /*in*/LineStatus ls); // store string and status (does not eval token) CString GetLine(/*in*/CFileOptions &o); void SetStatus(/*in*/LineStatus ls); LineStatus GetStatus(); // Helpers protected: CString GetLineWithOptions(/*in*/CString s,/*in*/CFileOptions &o); // that's where options are implemented }; typedef CTemplateArray<CFileLine*> ArrayLines; typedef CTemplateArray<long> ArrayLong; typedef CTemplateObjArray<CString> ArrayCString; // CFileOptions ///////////////////////////////////////////////////// // ///////////////////////////////////////////////////////////////////// // S.Rodriguez - Feb 2003 ///////////////////////////////////////////////////////////////////// // // class CFileOptions { // Members protected: ArrayCString arrOptions; // "indent" : should the diff engine see differences in tabs/spaces (default = yes) // "case" : should the diff engine see case differences (default = yes) // how to use this class : // CFileOptions o; // o.SetOption("indent","yes"); // Constructor public: CFileOptions(); // Accessors public: void SetOption(/*in*/CString &szOptionName, /*in*/CString &szOptionValue); CString GetOption(/*in*/CString &szOptionName); BOOL IsDefaultOptions(); long GetOptionCount(); CString GetOption(long i); // Methods void Copy(CFileOptions &src); }; // CFilePartition /////////////////////////////////////////////////// // ///////////////////////////////////////////////////////////////////// // S.Rodriguez - Feb 2003 ///////////////////////////////////////////////////////////////////// // // class CFilePartition { // Members protected: CString m_szFilename; CFileOptions m_options; ArrayLines m_arrLines; ArrayLong m_arrTokens; // Constructor public: CFilePartition(); virtual ~CFilePartition(); // Accessors public: void SetName(/*in*/CString &); CString GetName(); void SetOptions(/*in*/CFileOptions &options); long GetNBLines(); // amount of lines of this file CString GetLine(/*in*/long i); // returns an arbitrary line CString GetRawLine(/*in*/long i); // returns an arbitrary line (not filtered) LineStatus GetStatusLine(/*in*/long i); // returns the status of an arbitrary lin long *GetTokens(); // token table void HowManyChanges(/*out*/int &nAdded, /*out*/int &nChanged, /*out*/int &nDeleted); // Methods BOOL PreProcess(/*in*/CString &szFilename, /*in*/CFileOptions &options); BOOL PreProcessFolder(/*in*/CString &szFolder, /*in*/CFileOptions &options); void AddString(/*in*/CString &s, /*in*/LineStatus ls); void AddBlankLine(); BOOL MatchLine(/*in*/long i1, /*in*/CFilePartition &f2, /*out*/long &i2); void Dump(/*in*/CString &szTitle); // Helpers protected: BOOL PreProcessFolder(/*in*/CString &szFolder, /*in*/CFileOptions &options, /*in/out*/long nIndent); void AddString(/*in*/CString &s); }; --- NEW FILE: ReadMe.txt --- ======================================================================== MICROSOFT FOUNDATION CLASS LIBRARY : Diff ======================================================================== AppWizard has created this Diff DLL for you. This DLL not only demonstrates the basics of using the Microsoft Foundation classes but is also a starting point for writing your DLL. This file contains a summary of what you will find in each of the files that make up your Diff DLL. Diff.dsp This file (the project file) contains information at the project level and is used to build a single project or subproject. Other users can share the project (.dsp) file, but they should export the makefiles locally. Diff.cpp This is the main DLL source file that contains the definition of DllMain(). Diff.rc This is a listing of all of the Microsoft Windows resources that the program uses. It includes the icons, bitmaps, and cursors that are stored in the RES subdirectory. This file can be directly edited in Microsoft Visual C++. Diff.clw This file contains information used by ClassWizard to edit existing classes or add new classes. ClassWizard also uses this file to store information needed to create and edit message maps and dialog data maps and to create prototype member functions. res\Diff.rc2 This file contains resources that are not edited by Microsoft Visual C++. You should place all resources not editable by the resource editor in this file. Diff.def This file contains information about the DLL that must be provided to run with Microsoft Windows. It defines parameters such as the name and description of the DLL. It also exports functions from the DLL. ///////////////////////////////////////////////////////////////////////////// Other standard files: StdAfx.h, StdAfx.cpp These files are used to build a precompiled header (PCH) file named Diff.pch and a precompiled types file named StdAfx.obj. Resource.h This is the standard header file, which defines new resource IDs. Microsoft Visual C++ reads and updates this file. ///////////////////////////////////////////////////////////////////////////// Other notes: AppWizard uses "TODO:" to indicate parts of the source code you should add to or customize. ///////////////////////////////////////////////////////////////////////////// --- NEW FILE: Resource.h --- //{{NO_DEPENDENCIES}} // Microsoft Developer Studio generated include file. // Used by Diff.rc // #define IDD_DIALOG1 1000 #define ID_EDIT1 1000 #define ID_BUTTON1 1001 #define ID_EDIT2 1002 #define ID_BUTTON2 1003 #define ID_CHECK1 1004 #define ID_CHECK2 1005 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 1001 #define _APS_NEXT_COMMAND_VALUE 32771 #define _APS_NEXT_CONTROL_VALUE 1000 #define _APS_NEXT_SYMED_VALUE 1000 #endif #endif --- NEW FILE: StdAfx.cpp --- // stdafx.cpp : source file that includes just the standard includes // Diff.pch will be the pre-compiled header // stdafx.obj will contain the pre-compiled type information #include "stdafx.h" --- NEW FILE: StdAfx.h --- // stdafx.h : include file for standard system include files, // or project specific include files that are used frequently, but // are changed infrequently // #if !defined(AFX_STDAFX_H__58CCA3EA_C439_4F7D_BC66_DCC0204CB494__INCLUDED_) #define AFX_STDAFX_H__58CCA3EA_C439_4F7D_BC66_DCC0204CB494__INCLUDED_ #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 #define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers #include <afxwin.h> // MFC core and standard components #include <afxext.h> // MFC extensions #ifndef _AFX_NO_OLE_SUPPORT #include <afxole.h> // MFC OLE classes #include <afxodlgs.h> // MFC OLE dialog classes #include <afxdisp.h> // MFC Automation classes #endif // _AFX_NO_OLE_SUPPORT #ifndef _AFX_NO_DB_SUPPORT #include <afxdb.h> // MFC ODBC database classes #endif // _AFX_NO_DB_SUPPORT #ifndef _AFX_NO_DAO_SUPPORT #include <afxdao.h> // MFC DAO database classes #endif // _AFX_NO_DAO_SUPPORT #include <afxdtctl.h> // MFC support for Internet Explorer 4 Common Controls #ifndef _AFX_NO_AFXCMN_SUPPORT #include <afxcmn.h> // MFC support for Windows Common Controls #endif // _AFX_NO_AFXCMN_SUPPORT //{{AFX_INSERT_LOCATION}} // Microsoft Visual C++ will insert additional declarations immediately before the previous line. #endif // !defined(AFX_STDAFX_H__58CCA3EA_C439_4F7D_BC66_DCC0204CB494__INCLUDED_) --- NEW FILE: Templates.h --- #pragma once ///////////////////////////////////////////////////////////////////////////////////// // // collection templates // // taken from the Windows MFC // templated // // // template <class T> class CTemplateArray { public: // Construction CTemplateArray(); ~CTemplateArray(); // Attributes int GetSize() const; int GetUpperBound() const; void SetSize(int nNewSize, int nGrowBy = -1); // Operations // Clean up void FreeExtra(); void RemoveAll(); // Accessing elements T GetAt(int nIndex) const; void SetAt(int nIndex, T newElement); T& ElementAt(int nIndex); // Direct Access to the element data (may return NULL) const T* GetData() const; T* GetData(); // Potentially growing the array void SetAtGrow(int nIndex, T newElement); int Add(T newElement); int Append(const CTemplateArray& src); void Copy(const CTemplateArray& src); // overloaded operator helpers T operator[](int nIndex) const; T& operator[](int nIndex); // Operations that move elements around void InsertAt(int nIndex, T newElement, int nCount = 1); void RemoveAt(int nIndex, int nCount = 1); void InsertAt(int nStartIndex, CTemplateArray* pNewArray); void Remove(T oldElement); // Implementation protected: T* m_pData; // the actual array of data int m_nSize; // # of elements (upperBound - 1) int m_nMaxSize; // max allocated int m_nGrowBy; // grow amount protected: // local typedefs for class templates typedef void* BASE_TYPE; typedef void* BASE_ARG_TYPE; }; template <class T> CTemplateArray<T>::CTemplateArray() { m_pData = NULL; m_nSize = m_nMaxSize = m_nGrowBy = 0; } template <class T> CTemplateArray<T>::~CTemplateArray() { delete[] (BYTE*)m_pData; } template <class T> int CTemplateArray<T>::GetSize() const { return m_nSize; } template <class T> int CTemplateArray<T>::GetUpperBound() const { return m_nSize-1; } template <class T> void CTemplateArray<T>::SetSize(int nNewSize, int nGrowBy) { if (nNewSize < 0) return; if (nGrowBy != -1) m_nGrowBy = nGrowBy; // set new size if (nNewSize == 0) { // shrink to nothing delete[] (BYTE*)m_pData; m_pData = NULL; m_nSize = m_nMaxSize = 0; } else if (m_pData == NULL) { // create one with exact size m_pData = (T*) new BYTE[nNewSize * sizeof(T)]; memset(m_pData, 0, nNewSize * sizeof(T)); // zero fill m_nSize = m_nMaxSize = nNewSize; } else if (nNewSize <= m_nMaxSize) { // it fits if (nNewSize > m_nSize) { // initialize the new elements memset(&m_pData[m_nSize], 0, (nNewSize-m_nSize) * sizeof(T)); } m_nSize = nNewSize; } else { // otherwise, grow array int nGrowBy = m_nGrowBy; if (nGrowBy == 0) { // heuristically determine growth when nGrowBy == 0 // (this avoids heap fragmentation in many situations) nGrowBy = (m_nSize/8 > 4)? m_nSize/8 : 4; } int nNewMax; if (nNewSize < m_nMaxSize + nGrowBy) nNewMax = m_nMaxSize + nGrowBy; // granularity else nNewMax = nNewSize; // no slush T* pNewData = (T*) new BYTE[nNewMax * sizeof(T)]; // copy new data from old memcpy(pNewData, m_pData, m_nSize * sizeof(T)); memset(&pNewData[m_nSize], 0, (nNewSize-m_nSize) * sizeof(T)); // get rid of old stuff (note: no destructors called) delete[] (BYTE*)m_pData; m_pData = pNewData; m_nSize = nNewSize; m_nMaxSize = nNewMax; } } template <class T> void CTemplateArray<T>::FreeExtra() { if (m_nSize != m_nMaxSize) { // shrink to desired size T* pNewData = NULL; if (m_nSize != 0) { pNewData = (T*) new BYTE[m_nSize * sizeof(T)]; // copy new data from old memcpy(pNewData, m_pData, m_nSize * sizeof(T)); } // get rid of old stuff (note: no destructors called) delete[] (BYTE*)m_pData; m_pData = pNewData; m_nMaxSize = m_nSize; } } template <class T> void CTemplateArray<T>::RemoveAll() { SetSize(0); } template <class T> T CTemplateArray<T>::GetAt(int nIndex) const { if (nIndex<0 || nIndex>=m_nSize) return NULL; else return m_pData[nIndex]; } template <class T> void CTemplateArray<T>::SetAt(int nIndex, T newElement) { if (nIndex >= 0 && nIndex < m_nSize) m_pData[nIndex] = newElement; } template <class T> T& CTemplateArray<T>::ElementAt(int nIndex) { static T pVoid=NULL; if (nIndex<0 || nIndex>=m_nSize) return pVoid; else return m_pData[nIndex]; } template <class T> const T* CTemplateArray<T>::GetData() const { return (const T*)m_pData; } template <class T> T* CTemplateArray<T>::GetData() { return (T*)m_pData; } template <class T> void CTemplateArray<T>::SetAtGrow(int nIndex, T newElement) { if (nIndex < 0) return; if (nIndex >= m_nSize) SetSize(nIndex+1); m_pData[nIndex] = newElement; } template <class T> int CTemplateArray<T>::Add(T newElement) { int nIndex = m_nSize; SetAtGrow(nIndex, newElement); return nIndex; } template <class T> void CTemplateArray<T>::Remove(T oldElement) { for( int i = 0; i < m_nSize; i++) { if( m_pData[i] == oldElement) { if( i < m_nSize - 1) m_pData[i] = m_pData[i+1]; m_nSize--; return; } } } template <class T> int CTemplateArray<T>::Append(const CTemplateArray& src) { int nOldSize = m_nSize; if (this != &src) { SetSize(m_nSize + src.m_nSize); memcpy(m_pData + nOldSize, src.m_pData, src.m_nSize * sizeof(T)); } return nOldSize; } template <class T> void CTemplateArray<T>::Copy(const CTemplateArray& src) { if (this == &src) return; SetSize(src.m_nSize); memcpy(m_pData, src.m_pData, src.m_nSize * sizeof(T)); } template <class T> T CTemplateArray<T>::operator[](int nIndex) const { return GetAt(nIndex); } template <class T> T& CTemplateArray<T>::operator[](int nIndex) { return ElementAt(nIndex); } template <class T> void CTemplateArray<T>::InsertAt(int nIndex, T newElement, int nCount) { if (nIndex<0 || nCount<=0) return; if (nIndex >= m_nSize) { // adding after the end of the array SetSize(nIndex + nCount); // grow so nIndex is valid } else { // inserting in the middle of the array int nOldSize = m_nSize; SetSize(m_nSize + nCount); // grow it to new size // shift old data up to fill gap memmove(&m_pData[nIndex+nCount], &m_pData[nIndex], (nOldSize-nIndex) * sizeof(T)); // re-init slots we copied from memset(&m_pData[nIndex], 0, nCount * sizeof(T)); } // insert new value in the gap while (nCount-- && (nIndex + nCount <= m_nSize)) m_pData[nIndex++] = newElement; } template <class T> void CTemplateArray<T>::RemoveAt(int nIndex, int nCount) { if (nIndex >= 0 || nCount >= 0 || (nIndex + nCount <= m_nSize) ) { // just remove a range int nMoveCount = m_nSize - (nIndex + nCount); if (nMov... [truncated message content] |