/** * @brief Update file's modification time. * @param [in] info Contains filename, path and file times to update. */ void files_UpdateFileTime(const DiffFileInfo & info) { String path = paths_ConcatPath(info.path, info.filename); _utimbuf times = {0}; times.modtime = info.mtime; _tutime(path.c_str(), ×); }
/** @brief Return path to right file, including all but file name */ String DIFFITEM::GetRightFilepath(const String &sRightRoot) const { String sPath; if (!diffcode.isSideLeftOnly()) { sPath = paths_ConcatPath(sRightRoot, right.path); } return sPath; }
/** @brief Return path to left file, including all but file name */ String DIFFITEM::GetLeftFilepath(const String &sLeftRoot) const { String sPath; if (!diffcode.isSideRightOnly()) { sPath = paths_ConcatPath(sLeftRoot, left.path); } return sPath; }
/** * @brief Install new filter. * This function is called when user selects "Install" button from GUI. * Function allows easy installation of new filters for user. For example * when user has downloaded filter file from net. First we ask user to * select filter to install. Then we copy selected filter to private * filters folder. */ void FileFiltersDlg::OnBnClickedFilterfileInstall() { CString s; String path; String userPath = theApp.m_globalFileFilter.GetUserFilterPathWithCreate(); if (SelectFile(GetSafeHwnd(), s, path.c_str(), IDS_FILEFILTER_INSTALL, IDS_FILEFILTER_FILEMASK, TRUE)) { String sfile, sext; SplitFilename(s, NULL, &sfile, &sext); String filename = sfile; filename += _T("."); filename += sext; userPath = paths_ConcatPath(userPath, filename); if (!CopyFile(s, userPath.c_str(), TRUE)) { // If file already exists, ask from user // If user wants to, overwrite existing filter if (paths_DoesPathExist(userPath.c_str()) == IS_EXISTING_FILE) { int res = LangMessageBox(IDS_FILEFILTER_OVERWRITE, MB_YESNO | MB_ICONWARNING); if (res == IDYES) { if (!CopyFile(s, userPath.c_str(), FALSE)) { LangMessageBox(IDS_FILEFILTER_INSTALLFAIL, MB_ICONSTOP); } } } else { LangMessageBox(IDS_FILEFILTER_INSTALLFAIL, MB_ICONSTOP); } } else { FileFilterMgr *pMgr = theApp.m_globalFileFilter.GetManager(); pMgr->AddFilter(userPath.c_str()); // Remove all from filterslist and re-add so we can update UI CString selected; m_Filters->RemoveAll(); theApp.m_globalFileFilter.GetFileFilters(m_Filters, selected); UpdateFiltersList(); } } }
/** * @brief Runs diff-engine. */ BOOL CDiffWrapper::RunFileDiff() { String filepath1(m_s1File); String filepath2(m_s2File); replace_char(&*filepath1.begin(), '/', '\\'); replace_char(&*filepath2.begin(), '/', '\\'); BOOL bRet = TRUE; String strFile1Temp(filepath1); String strFile2Temp(filepath2); m_options.SetToDiffUtils(); if (m_bUseDiffList) m_nDiffs = m_pDiffList->GetSize(); if (m_bPluginsEnabled) { // Do the preprocessing now, overwrite the temp files // NOTE: FileTransform_UCS2ToUTF8() may create new temp // files and return new names, those created temp files // are deleted in end of function. if (m_infoPrediffer->bToBeScanned) { // this can only fail if the data can not be saved back (no more // place on disk ???) What to do then ?? FileTransform_Prediffing(strFile1Temp, m_sToFindPrediffer.c_str(), m_infoPrediffer, m_bPathsAreTemp); } else { // This can fail if the prediffer has a problem if (FileTransform_Prediffing(strFile1Temp, *m_infoPrediffer, m_bPathsAreTemp) == FALSE) { // display a message box CString sError; LangFormatString2(sError, IDS_PREDIFFER_ERROR, strFile1Temp.c_str(), m_infoPrediffer->pluginName.c_str()); AfxMessageBox(sError, MB_OK | MB_ICONSTOP); // don't use any more this prediffer m_infoPrediffer->bToBeScanned = FALSE; m_infoPrediffer->pluginName.erase(); } } // We use the same plugin for both files, so it must be defined before // second file ASSERT(m_infoPrediffer->bToBeScanned == FALSE); if (FileTransform_Prediffing(strFile2Temp, *m_infoPrediffer, m_bPathsAreTemp) == FALSE) { // display a message box CString sError; LangFormatString2(sError, IDS_PREDIFFER_ERROR, strFile2Temp.c_str(), m_infoPrediffer->pluginName.c_str()); AfxMessageBox(sError, MB_OK | MB_ICONSTOP); // don't use any more this prediffer m_infoPrediffer->bToBeScanned = FALSE; m_infoPrediffer->pluginName.erase(); } } // Comparing UTF-8 files seems to require this conversion? // I'm still very confused about why, as what the functions // document doing is UCS2 to UTF-8 conversion, nothing else. // Something is wrong here. - Kimmo FileTransform_UCS2ToUTF8(strFile1Temp, m_bPathsAreTemp); FileTransform_UCS2ToUTF8(strFile2Temp, m_bPathsAreTemp); DiffFileData diffdata; diffdata.SetDisplayFilepaths(filepath1.c_str(), filepath2.c_str()); // store true names for diff utils patch file // This opens & fstats both files (if it succeeds) if (!diffdata.OpenFiles(strFile1Temp.c_str(), strFile2Temp.c_str())) { return FALSE; } // Compare the files, if no error was found. // Last param (bin_file) is NULL since we don't // (yet) need info about binary sides. int bin_flag = 0; struct change *script = NULL; bRet = Diff2Files(&script, &diffdata, &bin_flag, NULL); // We don't anymore create diff-files for every rescan. // User can create patch-file whenever one wants to. // We don't need to waste time. But lets keep this as // debugging aid. Sometimes it is very useful to see // what differences diff-engine sees! #ifdef _DEBUG // throw the diff into a temp file String sTempPath = env_GetTempPath(); // get path to Temp folder String path = paths_ConcatPath(sTempPath, _T("Diff.txt")); outfile = _tfopen(path.c_str(), _T("w+")); if (outfile != NULL) { print_normal_script(script); fclose(outfile); outfile = NULL; } #endif // First determine what happened during comparison // If there were errors or files were binaries, don't bother // creating diff-lists or patches // diff_2_files set bin_flag to -1 if different binary // diff_2_files set bin_flag to +1 if same binary if (bin_flag != 0) { m_status.bBinaries = TRUE; if (bin_flag == -1) m_status.bIdentical = FALSE; else m_status.bIdentical = TRUE; } else { // text files according to diffutils, so change script exists m_status.bIdentical = (script == 0); m_status.bBinaries = FALSE; } file_data * inf = diffdata.m_inf; m_status.bLeftMissingNL = inf[0].missing_newline; m_status.bRightMissingNL = inf[1].missing_newline; // Create patch file if (!m_status.bBinaries && m_bCreatePatchFile) { WritePatchFile(script, &inf[0]); } // Go through diffs adding them to WinMerge's diff list // This is done on every WinMerge's doc rescan! if (!m_status.bBinaries && m_bUseDiffList) { LoadWinMergeDiffsFromDiffUtilsScript(script, diffdata.m_inf); } FreeDiffUtilsScript(script); // Done with diffutils filedata diffdata.Close(); if (m_bPluginsEnabled) { // Delete temp files transformation functions possibly created if (lstrcmpi(filepath1.c_str(), strFile1Temp.c_str()) != 0) { if (!::DeleteFile(strFile1Temp.c_str())) { LogErrorString(Fmt(_T("DeleteFile(%s) failed: %s"), strFile1Temp.c_str(), GetSysError(GetLastError()).c_str())); } strFile1Temp.erase(); } if (lstrcmpi(filepath2.c_str(), strFile2Temp.c_str()) != 0) { if (!::DeleteFile(strFile2Temp.c_str())) { LogErrorString(Fmt(_T("DeleteFile(%s) failed: %s"), strFile2Temp.c_str(), GetSysError(GetLastError()).c_str())); } strFile2Temp.erase(); } } return bRet; }
/** * @brief Write logfile */ bool CConfigLog::DoFile(bool writing, String &sError) { CVersionInfo version; String text; m_writing = writing; if (writing) { String sFileName = paths_ConcatPath(env_GetMyDocuments(NULL), WinMergeDocumentsFolder); paths_CreateIfNeeded(sFileName.c_str()); m_sFileName = paths_ConcatPath(sFileName, _T("WinMerge.txt")); if (!m_pfile->OpenCreateUtf8(m_sFileName.c_str())) { const UniFile::UniError &err = m_pfile->GetLastUniError(); sError = err.GetError(); return false; } m_pfile->SetBom(true); m_pfile->WriteBom(); } // Begin log FileWriteString(_T("WinMerge configuration log\r\n")); FileWriteString(_T("--------------------------\r\n")); FileWriteString(_T("Saved to: ")); FileWriteString(m_sFileName.c_str()); FileWriteString(_T("\r\n* Please add this information (or attach this file)\r\n")); FileWriteString(_T("* when reporting bugs.\r\n")); FileWriteString(_T("Module names prefixed with tilda (~) are currently loaded in WinMerge process.\r\n")); // Platform stuff FileWriteString(_T("\r\n\r\nVersion information:\r\n")); FileWriteString(_T(" WinMerge.exe: ")); FileWriteString(version.GetFixedProductVersion().c_str()); String privBuild = version.GetPrivateBuild(); if (!privBuild.empty()) { FileWriteString(_T(" - Private build: ")); FileWriteString(privBuild.c_str()); } text = GetBuildFlags(); FileWriteString(_T("\r\n Build config: ")); FileWriteString(text.c_str()); LPCTSTR szCmdLine = ::GetCommandLine(); ASSERT(szCmdLine != NULL); // Skip the quoted executable file name. if (szCmdLine != NULL) { szCmdLine = _tcschr(szCmdLine, '"'); if (szCmdLine != NULL) { szCmdLine += 1; // skip the opening quote. szCmdLine = _tcschr(szCmdLine, '"'); if (szCmdLine != NULL) { szCmdLine += 1; // skip the closing quote. } } } // The command line include a space after the executable file name, // which mean that empty command line will have length of one. if (lstrlen(szCmdLine) < 2) { szCmdLine = _T(" none"); } FileWriteString(_T("\r\n Command Line: ")); FileWriteString(szCmdLine); FileWriteString(_T("\r\n Windows: ")); text = GetWindowsVer(); FileWriteString(text.c_str()); FileWriteString(_T("\r\n")); WriteVersionOf1(1, _T("COMCTL32.dll")); WriteVersionOf1(1, _T("shlwapi.dll")); WriteVersionOf1(1, _T("MergeLang.dll")); WriteVersionOf1(1, _T("ShellExtension.dll")); WriteVersionOf1(1, _T("ShellExtensionU.dll")); WriteVersionOf1(1, _T("ShellExtensionX64.dll")); // WinMerge settings FileWriteString(_T("\r\nWinMerge configuration:\r\n")); FileWriteString(_T(" Compare settings:\r\n")); WriteItemYesNo(2, _T("Ignore blank lines"), &m_diffOptions.bIgnoreBlankLines); WriteItemYesNo(2, _T("Ignore case"), &m_diffOptions.bIgnoreCase); WriteItemYesNo(2, _T("Ignore carriage return differences"), &m_diffOptions.bIgnoreEol); WriteItemWhitespace(2, _T("Whitespace compare"), &m_diffOptions.nIgnoreWhitespace); WriteItemYesNo(2, _T("Detect moved blocks"), &m_miscSettings.bMovedBlocks); WriteItem(2, _T("Compare method"), m_compareSettings.nCompareMethod); WriteItemYesNo(2, _T("Stop after first diff"), &m_compareSettings.bStopAfterFirst); FileWriteString(_T("\r\n Other settings:\r\n")); WriteItemYesNo(2, _T("Automatic rescan"), &m_miscSettings.bAutomaticRescan); WriteItemYesNoInverted(2, _T("Simple EOL"), &m_miscSettings.bAllowMixedEol); WriteItemYesNo(2, _T("Automatic scroll to 1st difference"), &m_miscSettings.bScrollToFirst); WriteItemYesNo(2, _T("Backup original file"), &m_miscSettings.bBackup); FileWriteString(_T("\r\n Folder compare:\r\n")); WriteItemYesNo(2, _T("Identical files"), &m_viewSettings.bShowIdent); WriteItemYesNo(2, _T("Different files"), &m_viewSettings.bShowDiff); WriteItemYesNo(2, _T("Left Unique files"), &m_viewSettings.bShowUniqueLeft); WriteItemYesNo(2, _T("Right Unique files"), &m_viewSettings.bShowUniqueRight); WriteItemYesNo(2, _T("Binary files"), &m_viewSettings.bShowBinaries); WriteItemYesNo(2, _T("Skipped files"), &m_viewSettings.bShowSkipped); WriteItemYesNo(2, _T("Tree-mode enabled"), &m_viewSettings.bTreeView); FileWriteString(_T("\r\n File compare:\r\n")); WriteItemYesNo(2, _T("Preserve filetimes"), &m_miscSettings.bPreserveFiletimes); WriteItemYesNo(2, _T("Match similar lines"), &m_miscSettings.bMatchSimilarLines); FileWriteString(_T("\r\n Editor settings:\r\n")); WriteItemYesNo(2, _T("View Whitespace"), &m_miscSettings.bViewWhitespace); WriteItemYesNo(2, _T("Merge Mode enabled"), &m_miscSettings.bMergeMode); WriteItemYesNo(2, _T("Show linenumbers"), &m_miscSettings.bShowLinenumbers); WriteItemYesNo(2, _T("Wrap lines"), &m_miscSettings.bWrapLines); WriteItemYesNo(2, _T("Syntax Highlight"), &m_miscSettings.bSyntaxHighlight); WriteItem(2, _T("Tab size"), m_miscSettings.nTabSize); WriteItemYesNoInverted(2, _T("Insert tabs"), &m_miscSettings.nInsertTabs); // Font settings FileWriteString(_T("\r\n Font:\r\n")); FileWriteString(Fmt(_T(" Font facename: %s\r\n"), m_fontSettings.sFacename.c_str())); FileWriteString(Fmt(_T(" Font charset: %d (%s)\r\n"), m_fontSettings.nCharset, FontCharsetName(m_fontSettings.nCharset).c_str())); // System settings FileWriteString(_T("\r\nSystem settings:\r\n")); FileWriteString(_T(" codepage settings:\r\n")); WriteItem(2, _T("ANSI codepage"), GetACP()); WriteItem(2, _T("OEM codepage"), GetOEMCP()); WriteLocaleSettings(GetThreadLocale(), _T("Locale (Thread)")); WriteLocaleSettings(LOCALE_USER_DEFAULT, _T("Locale (User)")); WriteLocaleSettings(LOCALE_SYSTEM_DEFAULT, _T("Locale (System)")); // Codepage settings WriteItemYesNo(1, _T("Detect codepage automatically for RC and HTML files"), &m_cpSettings.bDetectCodepage); WriteItem(1, _T("unicoder codepage"), getDefaultCodepage()); // Plugins FileWriteString(_T("\r\nPlugins:\r\n")); WriteItemYesNo(1, _T("Plugins enabled"), &m_miscSettings.bPluginsEnabled); FileWriteString(_T(" Unpackers: ")); WritePluginsInLogFile(L"FILE_PACK_UNPACK"); WritePluginsInLogFile(L"BUFFER_PACK_UNPACK"); FileWriteString(_T("\r\n Prediffers: ")); WritePluginsInLogFile(L"FILE_PREDIFF"); WritePluginsInLogFile(L"BUFFER_PREDIFF"); FileWriteString(_T("\r\n Editor scripts: ")); WritePluginsInLogFile(L"EDITOR_SCRIPT"); if (IsWindowsScriptThere() == FALSE) FileWriteString(_T("\r\n .sct scripts disabled (Windows Script Host not found)\r\n")); FileWriteString(_T("\r\n\r\n")); WriteArchiveSupport(); CloseFile(); return true; }