diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/ShadowCopy/Shadow_Windows7.vcxproj | 16 | ||||
-rw-r--r-- | lib/Thumbnail/Thumbnail.vcxproj | 2 | ||||
-rw-r--r-- | lib/dir_exist_async.h | 40 | ||||
-rw-r--r-- | lib/dir_lock.cpp | 2 | ||||
-rw-r--r-- | lib/ffs_paths.cpp | 11 | ||||
-rw-r--r-- | lib/localization.cpp | 45 | ||||
-rw-r--r-- | lib/parallel_scan.cpp | 49 | ||||
-rw-r--r-- | lib/parallel_scan.h | 4 | ||||
-rw-r--r-- | lib/parse_lng.h | 90 | ||||
-rw-r--r-- | lib/parse_plural.h | 88 | ||||
-rw-r--r-- | lib/perf_check.cpp | 8 | ||||
-rw-r--r-- | lib/process_xml.cpp | 71 | ||||
-rw-r--r-- | lib/process_xml.h | 33 | ||||
-rw-r--r-- | lib/resolve_path.cpp | 5 | ||||
-rw-r--r-- | lib/resources.cpp | 105 | ||||
-rw-r--r-- | lib/resources.h | 40 | ||||
-rw-r--r-- | lib/shadow.cpp | 2 | ||||
-rw-r--r-- | lib/status_handler.h | 2 | ||||
-rw-r--r-- | lib/status_handler_impl.h | 27 | ||||
-rw-r--r-- | lib/versioning.cpp | 4 | ||||
-rw-r--r-- | lib/versioning.h | 2 |
21 files changed, 300 insertions, 346 deletions
diff --git a/lib/ShadowCopy/Shadow_Windows7.vcxproj b/lib/ShadowCopy/Shadow_Windows7.vcxproj index 1f02e675..86df3453 100644 --- a/lib/ShadowCopy/Shadow_Windows7.vcxproj +++ b/lib/ShadowCopy/Shadow_Windows7.vcxproj @@ -97,7 +97,7 @@ <SuppressStartupBanner>true</SuppressStartupBanner> <DebugInformationFormat>EditAndContinue</DebugInformationFormat> <DisableSpecificWarnings>4100;4996</DisableSpecificWarnings> - <AdditionalIncludeDirectories>../..;C:\Program Files\C++\boost</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>../..;C:\Data\C++\boost</AdditionalIncludeDirectories> <SmallerTypeCheck>true</SmallerTypeCheck> <MultiProcessorCompilation>true</MultiProcessorCompilation> </ClCompile> @@ -111,7 +111,7 @@ </ProfileGuidedDatabase> <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> <TargetMachine>MachineX86</TargetMachine> - <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage\lib</AdditionalLibraryDirectories> + <AdditionalLibraryDirectories>C:\Data\C++\Boost\stage\lib</AdditionalLibraryDirectories> <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies> </Link> </ItemDefinitionGroup> @@ -133,7 +133,7 @@ <SuppressStartupBanner>true</SuppressStartupBanner> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> <DisableSpecificWarnings>4100;4996</DisableSpecificWarnings> - <AdditionalIncludeDirectories>../..;C:\Program Files\C++\boost</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>../..;C:\Data\C++\boost</AdditionalIncludeDirectories> <PreprocessorDefinitions>ZEN_WIN;WXINTL_NO_GETTEXT_MACRO;_DEBUG;_WINDOWS;_USRDLL;SHADOWDLL_EXPORTS;USE_SHADOW_WINDOWS7;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SmallerTypeCheck>true</SmallerTypeCheck> <MultiProcessorCompilation>true</MultiProcessorCompilation> @@ -148,7 +148,7 @@ </ProfileGuidedDatabase> <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> <TargetMachine>MachineX64</TargetMachine> - <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage_x64\lib</AdditionalLibraryDirectories> + <AdditionalLibraryDirectories>C:\Data\C++\Boost\stage_x64\lib</AdditionalLibraryDirectories> <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies> </Link> </ItemDefinitionGroup> @@ -169,7 +169,7 @@ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed> <DisableSpecificWarnings>4100;4996</DisableSpecificWarnings> - <AdditionalIncludeDirectories>../..;C:\Program Files\C++\boost</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>../..;C:\Data\C++\boost</AdditionalIncludeDirectories> <MultiProcessorCompilation>true</MultiProcessorCompilation> </ClCompile> <Link> @@ -184,7 +184,7 @@ </ProfileGuidedDatabase> <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> <TargetMachine>MachineX86</TargetMachine> - <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage\lib</AdditionalLibraryDirectories> + <AdditionalLibraryDirectories>C:\Data\C++\Boost\stage\lib</AdditionalLibraryDirectories> <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies> </Link> </ItemDefinitionGroup> @@ -207,7 +207,7 @@ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed> <DisableSpecificWarnings>4100;4996</DisableSpecificWarnings> - <AdditionalIncludeDirectories>../..;C:\Program Files\C++\boost</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>../..;C:\Data\C++\boost</AdditionalIncludeDirectories> <PreprocessorDefinitions>ZEN_WIN;WXINTL_NO_GETTEXT_MACRO;NDEBUG;_WINDOWS;_USRDLL;SHADOWDLL_EXPORTS;USE_SHADOW_WINDOWS7;%(PreprocessorDefinitions)</PreprocessorDefinitions> <MultiProcessorCompilation>true</MultiProcessorCompilation> </ClCompile> @@ -223,7 +223,7 @@ </ProfileGuidedDatabase> <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> <TargetMachine>MachineX64</TargetMachine> - <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage_x64\lib</AdditionalLibraryDirectories> + <AdditionalLibraryDirectories>C:\Data\C++\Boost\stage_x64\lib</AdditionalLibraryDirectories> <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies> </Link> </ItemDefinitionGroup> diff --git a/lib/Thumbnail/Thumbnail.vcxproj b/lib/Thumbnail/Thumbnail.vcxproj index a4719ae7..a98aadab 100644 --- a/lib/Thumbnail/Thumbnail.vcxproj +++ b/lib/Thumbnail/Thumbnail.vcxproj @@ -98,6 +98,7 @@ <AdditionalIncludeDirectories>../..</AdditionalIncludeDirectories> <SmallerTypeCheck>true</SmallerTypeCheck> <MultiProcessorCompilation>true</MultiProcessorCompilation> + <EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet> </ClCompile> <Link> <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile> @@ -167,6 +168,7 @@ <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed> <AdditionalIncludeDirectories>../..</AdditionalIncludeDirectories> <MultiProcessorCompilation>true</MultiProcessorCompilation> + <EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet> </ClCompile> <Link> <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile> diff --git a/lib/dir_exist_async.h b/lib/dir_exist_async.h index 7eb4827e..19e5f745 100644 --- a/lib/dir_exist_async.h +++ b/lib/dir_exist_async.h @@ -21,43 +21,44 @@ namespace //- check existence of all directories in parallel! (avoid adding up search times if multiple network drives are not reachable) //- add reasonable time-out time! //- avoid checking duplicate entries by design: set<Zstring, LessFilename> -std::set<Zstring, LessFilename> getExistingDirsUpdating(const std::set<Zstring, LessFilename>& dirnames, bool allowUserInteraction, ProcessCallback& procCallback) +std::set<Zstring, LessFilename> getExistingDirsUpdating(const std::set<Zstring, LessFilename>& dirnames, + std::set<Zstring, LessFilename>& missing, + bool allowUserInteraction, + ProcessCallback& procCallback) { using namespace zen; - std::list<boost::unique_future<bool>> dirEx; + missing.clear(); - std::for_each(dirnames.begin(), dirnames.end(), - [&](const Zstring& dirname) - { - dirEx.push_back(zen::async2<bool>([=]() -> bool + std::list<std::pair<Zstring, boost::unique_future<bool>>> futureInfo; + for (const Zstring& dirname : dirnames) + if (!dirname.empty()) + futureInfo.push_back(std::make_pair(dirname, async2<bool>([=]() -> bool { - if (dirname.empty()) - return false; #ifdef ZEN_WIN //1. login to network share, if necessary loginNetworkShare(dirname, allowUserInteraction); #endif //2. check dir existence return dirExists(dirname); - })); - }); + }))); std::set<Zstring, LessFilename> output; //don't wait (almost) endlessly like win32 would on not existing network shares: const boost::system_time endTime = boost::get_system_time() + boost::posix_time::seconds(20); //consider CD-rom insert or hard disk spin up time from sleep - auto itDirname = dirnames.begin(); - for (auto it = dirEx.begin(); it != dirEx.end(); (void)++it, ++itDirname) //void: prevent ADL from dragging in boost's ,-overload: "MSVC warning C4913: user defined binary operator ',' exists but no overload could convert all operands" + for (auto& fi : futureInfo) { - procCallback.reportStatus(replaceCpy(_("Searching for folder %x..."), L"%x", fmtFileName(*itDirname), false)); //may throw! + procCallback.reportStatus(replaceCpy(_("Searching for folder %x..."), L"%x", fmtFileName(fi.first), false)); //may throw! while (boost::get_system_time() < endTime && - !it->timed_wait(boost::posix_time::milliseconds(UI_UPDATE_INTERVAL / 2))) + !fi.second.timed_wait(boost::posix_time::milliseconds(UI_UPDATE_INTERVAL / 2))) procCallback.requestUiRefresh(); //may throw! - if (it->is_ready() && it->get()) - output.insert(*itDirname); + if (fi.second.is_ready() && fi.second.get()) + output.insert(fi.first); + else + missing.insert(fi.first); } return output; } @@ -66,9 +67,10 @@ std::set<Zstring, LessFilename> getExistingDirsUpdating(const std::set<Zstring, inline //also silences Clang "unused function" for compilation units depending from getExistingDirsUpdating() only bool dirExistsUpdating(const Zstring& dirname, bool allowUserInteraction, ProcessCallback& procCallback) { - std::set<Zstring, LessFilename> dirnames; - dirnames.insert(dirname); - std::set<Zstring, LessFilename> dirsEx = getExistingDirsUpdating(dirnames, allowUserInteraction, procCallback); + if (dirname.empty()) return false; + std::set<Zstring, LessFilename> missing; + std::set<Zstring, LessFilename> dirsEx = getExistingDirsUpdating({ dirname }, missing, allowUserInteraction, procCallback); + assert(dirsEx.empty() != missing.empty()); return dirsEx.find(dirname) != dirsEx.end(); } } diff --git a/lib/dir_lock.cpp b/lib/dir_lock.cpp index b58e018b..fb016e1e 100644 --- a/lib/dir_lock.cpp +++ b/lib/dir_lock.cpp @@ -443,7 +443,7 @@ void waitOnDirLock(const Zstring& lockfilename, DirLockCallback* callback) //thr const UInt64 fileSizeNew = ::getLockFileSize(lockfilename); //throw FileError if (TICKS_PER_SEC <= 0 || !lastLifeSign.isValid() || !now.isValid()) - throw FileError(L"System Timer failed!"); //no i18n: "should" never throw ;) + throw FileError(L"System timer failed."); //no i18n: "should" never throw ;) if (fileSizeNew != fileSizeOld) //received life sign from lock { diff --git a/lib/ffs_paths.cpp b/lib/ffs_paths.cpp index 0f01b8d1..5c775d3e 100644 --- a/lib/ffs_paths.cpp +++ b/lib/ffs_paths.cpp @@ -7,6 +7,7 @@ #include "ffs_paths.h" #include <zen/file_handling.h> #include <wx/stdpaths.h> +#include <wx/app.h> #include <wx+/string_conv.h> #ifdef ZEN_MAC @@ -61,6 +62,11 @@ bool zen::manualProgramUpdateRequired() Zstring zen::getResourceDir() { + //make independent from wxWidgets global variable "appname"; support being called by RealtimeSync + auto appName = wxTheApp->GetAppName(); + wxTheApp->SetAppName(L"FreeFileSync"); + ZEN_ON_SCOPE_EXIT(wxTheApp->SetAppName(appName)); + #ifdef ZEN_WIN return getInstallDir(); #elif defined ZEN_LINUX @@ -76,6 +82,11 @@ Zstring zen::getResourceDir() Zstring zen::getConfigDir() { + //make independent from wxWidgets global variable "appname"; support being called by RealtimeSync + auto appName = wxTheApp->GetAppName(); + wxTheApp->SetAppName(L"FreeFileSync"); + ZEN_ON_SCOPE_EXIT(wxTheApp->SetAppName(appName)); + #ifdef ZEN_WIN if (isPortableVersion()) return getInstallDir(); diff --git a/lib/localization.cpp b/lib/localization.cpp index 5526cdce..3536ba70 100644 --- a/lib/localization.cpp +++ b/lib/localization.cpp @@ -38,7 +38,7 @@ public: wxLanguage langId() const { return langId_; } - virtual std::wstring translate(const std::wstring& text) + virtual std::wstring translate(const std::wstring& text) override { //look for translation in buffer table auto it = transMapping.find(text); @@ -47,16 +47,16 @@ public: return text; //fallback } - virtual std::wstring translate(const std::wstring& singular, const std::wstring& plural, int n) + virtual std::wstring translate(const std::wstring& singular, const std::wstring& plural, std::int64_t n) override { auto it = transMappingPl.find(std::make_pair(singular, plural)); if (it != transMappingPl.end()) { const size_t formNo = pluralParser->getForm(n); if (formNo < it->second.size()) - return it->second[formNo]; + return replaceCpy(it->second[formNo], L"%x", toGuiString(n)); } - return n == 1 ? singular : plural; //fallback + return replaceCpy(std::abs(n) == 1 ? singular : plural, L"%x", toGuiString(n)); //fallback } private: @@ -87,27 +87,26 @@ FFSTranslation::FFSTranslation(const Zstring& filename, wxLanguage languageId) : lngfile::TranslationPluralMap transPluralInput; lngfile::parseLng(inputStream, header, transInput, transPluralInput); //throw ParsingError - for (lngfile::TranslationMap::const_iterator i = transInput.begin(); i != transInput.end(); ++i) + for (const auto& item : transInput) { - const std::wstring original = utfCvrtTo<std::wstring>(i->first); - const std::wstring translation = utfCvrtTo<std::wstring>(i->second); + const std::wstring original = utfCvrtTo<std::wstring>(item.first); + const std::wstring translation = utfCvrtTo<std::wstring>(item.second); transMapping.insert(std::make_pair(original, translation)); } - for (lngfile::TranslationPluralMap::const_iterator i = transPluralInput.begin(); i != transPluralInput.end(); ++i) + for (const auto& item : transPluralInput) { - const std::wstring singular = utfCvrtTo<std::wstring>(i->first.first); - const std::wstring plural = utfCvrtTo<std::wstring>(i->first.second); - const lngfile::PluralForms& plForms = i->second; + const std::wstring engSingular = utfCvrtTo<std::wstring>(item.first.first); + const std::wstring engPlural = utfCvrtTo<std::wstring>(item.first.second); std::vector<std::wstring> plFormsWide; - for (lngfile::PluralForms::const_iterator j = plForms.begin(); j != plForms.end(); ++j) - plFormsWide.push_back(utfCvrtTo<std::wstring>(*j)); + for (const std::string& pf : item.second) + plFormsWide.push_back(utfCvrtTo<std::wstring>(pf)); - transMappingPl.insert(std::make_pair(std::make_pair(singular, plural), plFormsWide)); + transMappingPl.insert(std::make_pair(std::make_pair(engSingular, engPlural), plFormsWide)); } - pluralParser.reset(new parse_plural::PluralForm(header.pluralDefinition)); //throw parse_plural::ParsingError + pluralParser = make_unique<parse_plural::PluralForm>(header.pluralDefinition); //throw parse_plural::ParsingError } @@ -124,15 +123,15 @@ public: virtual HandleLink onSymlink(const Zchar* shortName, const Zstring& fullName, const SymlinkInfo& details) { return LINK_SKIP; } virtual TraverseCallback* onDir(const Zchar* shortName, const Zstring& fullName) { return nullptr; } - virtual HandleError reportDirError (const std::wstring& msg) { assert(false); return ON_ERROR_IGNORE; } //errors are not really critical in this context - virtual HandleError reportItemError(const std::wstring& msg, const Zchar* shortName) { assert(false); return ON_ERROR_IGNORE; } // + virtual HandleError reportDirError (const std::wstring& msg, size_t retryNumber) { assert(false); return ON_ERROR_IGNORE; } //errors are not really critical in this context + virtual HandleError reportItemError(const std::wstring& msg, size_t retryNumber, const Zchar* shortName) { assert(false); return ON_ERROR_IGNORE; } // private: std::vector<Zstring>& lngFiles_; }; -struct LessTranslation : public std::binary_function<ExistingTranslations::Entry, ExistingTranslations::Entry, bool> +struct LessTranslation { bool operator()(const ExistingTranslations::Entry& lhs, const ExistingTranslations::Entry& rhs) const { @@ -145,7 +144,7 @@ struct LessTranslation : public std::binary_function<ExistingTranslations::Entry rhs.languageName.c_str(), //__in LPCTSTR lpString2, static_cast<int>(rhs.languageName.size())); //__in int cchCount2 if (rv == 0) - throw std::runtime_error("Error comparing strings!"); + throw std::runtime_error("Error comparing strings."); else return rv == CSTR_LESS_THAN; //convert to C-style string compare result @@ -194,10 +193,11 @@ ExistingTranslations::ExistingTranslations() traverseFolder(zen::getResourceDir() + Zstr("Languages"), //throw(); traverseCallback); - for (auto it = lngFiles.begin(); it != lngFiles.end(); ++it) + for (const Zstring& filename : lngFiles) + { try { - const std::string stream = loadBinStream<std::string>(utfCvrtTo<Zstring>(*it)); //throw FileError + const std::string stream = loadBinStream<std::string>(filename); //throw FileError lngfile::TransHeader lngHeader; lngfile::parseHeader(stream, lngHeader); //throw ParsingError @@ -215,7 +215,7 @@ ExistingTranslations::ExistingTranslations() ExistingTranslations::Entry newEntry; newEntry.languageID = locInfo->Language; newEntry.languageName = utfCvrtTo<std::wstring>(lngHeader.languageName); - newEntry.languageFile = utfCvrtTo<std::wstring>(*it); + newEntry.languageFile = utfCvrtTo<std::wstring>(filename); newEntry.translatorName = utfCvrtTo<std::wstring>(lngHeader.translatorName); newEntry.languageFlag = utfCvrtTo<std::wstring>(lngHeader.flagFile); locMapping.push_back(newEntry); @@ -224,6 +224,7 @@ ExistingTranslations::ExistingTranslations() } catch (FileError&) { assert(false); } catch (lngfile::ParsingError&) { assert(false); } //better not show an error message here; scenario: batch jobs + } std::sort(locMapping.begin(), locMapping.end(), LessTranslation()); } diff --git a/lib/parallel_scan.cpp b/lib/parallel_scan.cpp index 433647ca..9c6b16a9 100644 --- a/lib/parallel_scan.cpp +++ b/lib/parallel_scan.cpp @@ -164,20 +164,20 @@ public: itemsScanned(0), activeWorker(0) {} - FillBufferCallback::HandleError reportError(const std::wstring& msg) //blocking call: context of worker thread + FillBufferCallback::HandleError reportError(const std::wstring& msg, size_t retryNumber) //blocking call: context of worker thread { - boost::unique_lock<boost::mutex> dummy(lockErrorMsg); - while (!errorMsg.empty() || errorResponse.get()) + boost::unique_lock<boost::mutex> dummy(lockErrorInfo); + while (errorInfo.get() || errorResponse.get()) conditionCanReportError.timed_wait(dummy, boost::posix_time::milliseconds(50)); //interruption point! - errorMsg = BasicWString(msg); + errorInfo = make_unique<std::pair<BasicWString, size_t>>(BasicWString(msg), retryNumber); while (!errorResponse.get()) conditionGotResponse.timed_wait(dummy, boost::posix_time::milliseconds(50)); //interruption point! FillBufferCallback::HandleError rv = *errorResponse; - errorMsg.clear(); + errorInfo.reset(); errorResponse.reset(); dummy.unlock(); //optimization for condition_variable::notify_all() @@ -188,10 +188,10 @@ public: void processErrors(FillBufferCallback& callback) //context of main thread, call repreatedly { - boost::unique_lock<boost::mutex> dummy(lockErrorMsg); - if (!errorMsg.empty() && !errorResponse.get()) + boost::unique_lock<boost::mutex> dummy(lockErrorInfo); + if (errorInfo.get() && !errorResponse.get()) { - FillBufferCallback::HandleError rv = callback.reportError(copyStringTo<std::wstring>(errorMsg)); //throw! + FillBufferCallback::HandleError rv = callback.reportError(copyStringTo<std::wstring>(errorInfo->first), errorInfo->second); //throw! errorResponse = make_unique<FillBufferCallback::HandleError>(rv); dummy.unlock(); //optimization for condition_variable::notify_all() @@ -254,10 +254,10 @@ public: private: //---- error handling ---- - boost::mutex lockErrorMsg; + boost::mutex lockErrorInfo; boost::condition_variable conditionCanReportError; boost::condition_variable conditionGotResponse; - BasicWString errorMsg; + std::unique_ptr<std::pair<BasicWString, size_t>> errorInfo; //error message + retry number std::unique_ptr<FillBufferCallback::HandleError> errorResponse; //---- status updates ---- @@ -318,8 +318,8 @@ public: virtual TraverseCallback* onDir(const Zchar* shortName, const Zstring& fullName); virtual void releaseDirTraverser(TraverseCallback* trav); - virtual HandleError reportDirError (const std::wstring& msg); - virtual HandleError reportItemError(const std::wstring& msg, const Zchar* shortName); + virtual HandleError reportDirError (const std::wstring& msg, size_t retryNumber); + virtual HandleError reportItemError(const std::wstring& msg, size_t retryNumber, const Zchar* shortName); private: TraverserShared& cfg; @@ -385,7 +385,16 @@ DirCallback::HandleLink DirCallback::onSymlink(const Zchar* shortName, const Zst return LINK_SKIP; case SYMLINK_FOLLOW_LINK: - return cfg.filterInstance->passFileFilter(relNameParentPf_ + shortName) ? LINK_FOLLOW : LINK_SKIP; //filter broken symlinks before trying to follow them! + //filter symlinks before trying to follow them: handle user-excluded broken symlinks! + //since we don't know what the symlink will resolve to, only do this when both variants agree: + if (!cfg.filterInstance->passFileFilter(relNameParentPf_ + shortName)) + { + bool subObjMightMatch = true; + if (!cfg.filterInstance->passDirFilter(relNameParentPf_ + shortName, &subObjMightMatch)) + if (!subObjMightMatch) + return LINK_SKIP; + } + return LINK_FOLLOW; } assert(false); @@ -401,11 +410,11 @@ TraverseCallback* DirCallback::onDir(const Zchar* shortName, const Zstring& full cfg.acb_.reportCurrentFile(fullName, cfg.threadID_); //------------------------------------------------------------------------------------ - const Zstring& relName = relNameParentPf_ + shortName; + const Zstring& relPath = relNameParentPf_ + shortName; //apply filter before processing (use relative name!) bool subObjMightMatch = true; - const bool passFilter = cfg.filterInstance->passDirFilter(relName, &subObjMightMatch); + const bool passFilter = cfg.filterInstance->passDirFilter(relPath, &subObjMightMatch); if (!passFilter && !subObjMightMatch) return nullptr; //do NOT traverse subdirs //else: attention! ensure directory filtering is applied later to exclude actually filtered directories @@ -414,7 +423,7 @@ TraverseCallback* DirCallback::onDir(const Zchar* shortName, const Zstring& full if (passFilter) cfg.acb_.incItemsScanned(); //add 1 element to the progress indicator - return new DirCallback(cfg, relName + FILE_NAME_SEPARATOR, subDir); //releaseDirTraverser() is guaranteed to be called in any case + return new DirCallback(cfg, relPath + FILE_NAME_SEPARATOR, subDir); //releaseDirTraverser() is guaranteed to be called in any case } @@ -425,9 +434,9 @@ void DirCallback::releaseDirTraverser(TraverseCallback* trav) } -DirCallback::HandleError DirCallback::reportDirError(const std::wstring& msg) +DirCallback::HandleError DirCallback::reportDirError(const std::wstring& msg, size_t retryNumber) { - switch (cfg.acb_.reportError(msg)) + switch (cfg.acb_.reportError(msg, retryNumber)) { case FillBufferCallback::ON_ERROR_IGNORE: cfg.failedDirReads_.insert(relNameParentPf_); @@ -441,9 +450,9 @@ DirCallback::HandleError DirCallback::reportDirError(const std::wstring& msg) } -DirCallback::HandleError DirCallback::reportItemError(const std::wstring& msg, const Zchar* shortName) +DirCallback::HandleError DirCallback::reportItemError(const std::wstring& msg, size_t retryNumber, const Zchar* shortName) { - switch (cfg.acb_.reportError(msg)) + switch (cfg.acb_.reportError(msg, retryNumber)) { case FillBufferCallback::ON_ERROR_IGNORE: cfg.failedItemReads_.insert(relNameParentPf_ + shortName); diff --git a/lib/parallel_scan.h b/lib/parallel_scan.h index c3806373..408882bf 100644 --- a/lib/parallel_scan.h +++ b/lib/parallel_scan.h @@ -61,8 +61,8 @@ public: ON_ERROR_RETRY, ON_ERROR_IGNORE }; - virtual HandleError reportError (const std::wstring& msg) = 0; //may throw! - virtual void reportStatus(const std::wstring& msg, int itemsTotal) = 0; // + virtual HandleError reportError (const std::wstring& msg, size_t retryNumber) = 0; //may throw! + virtual void reportStatus(const std::wstring& msg, int itemsTotal ) = 0; // }; //attention: ensure directory filtering is applied later to exclude filtered directories which have been kept as parent folders diff --git a/lib/parse_lng.h b/lib/parse_lng.h index 9aa62816..19a8e751 100644 --- a/lib/parse_lng.h +++ b/lib/parse_lng.h @@ -77,10 +77,17 @@ std::string generateLng(const TranslationUnorderedList& in, const TransHeader& h //--------------------------- implementation --------------------------- +enum class TranslationNewItemPos +{ + REL, + TOP +}; + class TranslationUnorderedList //unordered list of unique translation items { public: - TranslationUnorderedList(TranslationMap&& transOld, TranslationPluralMap&& transPluralOld) : transOld_(std::move(transOld)), transPluralOld_(std::move(transPluralOld)) {} + TranslationUnorderedList(TranslationNewItemPos newItemPos, TranslationMap&& transOld, TranslationPluralMap&& transPluralOld) : + newItemPos_(newItemPos), transOld_(std::move(transOld)), transPluralOld_(std::move(transPluralOld)) {} void addItem(const std::string& orig) { @@ -89,7 +96,15 @@ public: if (it != transOld_.end() && !it->second.empty()) //preserve old translation from .lng file if existing sequence.push_back(std::make_shared<RegularItem>(std::make_pair(orig, it->second))); else - sequence.push_front(std::make_shared<RegularItem>(std::make_pair(orig, std::string()))); //put untranslated items to the front of the .lng file + switch (newItemPos_) + { + case TranslationNewItemPos::REL: + sequence.push_back(std::make_shared<RegularItem>(std::make_pair(orig, std::string()))); + break; + case TranslationNewItemPos::TOP: + sequence.push_front(std::make_shared<RegularItem>(std::make_pair(orig, std::string()))); //put untranslated items to the front of the .lng filebreak; + break; + } } void addItem(const SingularPluralPair& orig) @@ -99,7 +114,15 @@ public: if (it != transPluralOld_.end() && !it->second.empty()) //preserve old translation from .lng file if existing sequence.push_back(std::make_shared<PluralItem>(std::make_pair(orig, it->second))); else - sequence.push_front(std::make_shared<PluralItem>(std::make_pair(orig, PluralForms()))); //put untranslated items to the front of the .lng file + switch (newItemPos_) + { + case TranslationNewItemPos::REL: + sequence.push_back(std::make_shared<PluralItem>(std::make_pair(orig, PluralForms()))); + break; + case TranslationNewItemPos::TOP: + sequence.push_front(std::make_shared<PluralItem>(std::make_pair(orig, PluralForms()))); //put untranslated items to the front of the .lng file + break; + } } bool untranslatedTextExists() const { return std::any_of(sequence.begin(), sequence.end(), [](const std::shared_ptr<Item>& item) { return !item->hasTranslation(); }); } @@ -120,6 +143,7 @@ private: struct RegularItem : public Item { RegularItem(const TranslationMap ::value_type& val) : value(val) {} virtual bool hasTranslation() const { return !value.second.empty(); } TranslationMap ::value_type value; }; struct PluralItem : public Item { PluralItem (const TranslationPluralMap::value_type& val) : value(val) {} virtual bool hasTranslation() const { return !value.second.empty(); } TranslationPluralMap::value_type value; }; + const TranslationNewItemPos newItemPos_; std::list<std::shared_ptr<Item>> sequence; //ordered list of translation elements std::set<TranslationMap ::key_type> transUnique; //check uniqueness @@ -173,7 +197,7 @@ class KnownTokens public: typedef std::map<Token::Type, std::string> TokenMap; - static const TokenMap& asList() + static const TokenMap& getList() { static KnownTokens inst; return inst.tokens; @@ -181,8 +205,8 @@ public: static std::string text(Token::Type t) { - TokenMap::const_iterator it = asList().find(t); - return it != asList().end() ? it->second : std::string(); + auto it = getList().find(t); + return it != getList().end() ? it->second : std::string(); } private: @@ -197,10 +221,10 @@ private: tokens.insert(std::make_pair(Token::TK_TRANS_NAME_END, "</translator>")); tokens.insert(std::make_pair(Token::TK_LOCALE_NAME_BEGIN, "<locale>")); tokens.insert(std::make_pair(Token::TK_LOCALE_NAME_END, "</locale>")); - tokens.insert(std::make_pair(Token::TK_FLAG_FILE_BEGIN, "<flag_image>")); - tokens.insert(std::make_pair(Token::TK_FLAG_FILE_END, "</flag_image>")); - tokens.insert(std::make_pair(Token::TK_PLURAL_COUNT_BEGIN, "<plural_form_count>")); - tokens.insert(std::make_pair(Token::TK_PLURAL_COUNT_END, "</plural_form_count>")); + tokens.insert(std::make_pair(Token::TK_FLAG_FILE_BEGIN, "<image>")); + tokens.insert(std::make_pair(Token::TK_FLAG_FILE_END, "</image>")); + tokens.insert(std::make_pair(Token::TK_PLURAL_COUNT_BEGIN, "<plural_count>")); + tokens.insert(std::make_pair(Token::TK_PLURAL_COUNT_END, "</plural_count>")); tokens.insert(std::make_pair(Token::TK_PLURAL_DEF_BEGIN, "<plural_definition>")); tokens.insert(std::make_pair(Token::TK_PLURAL_DEF_END, "</plural_definition>")); @@ -233,15 +257,15 @@ public: if (pos == stream.end()) return Token(Token::TK_END); - for (auto it = KnownTokens::asList().begin(); it != KnownTokens::asList().end(); ++it) - if (startsWith(it->second)) + for (const auto& token : KnownTokens::getList()) + if (startsWith(token.second)) { - pos += it->second.size(); - return Token(it->first); + pos += token.second.size(); + return Token(token.first); } //rest must be "text" - std::string::const_iterator itBegin = pos; + auto itBegin = pos; while (pos != stream.end() && !startsWithKnownTag()) pos = std::find(pos + 1, stream.end(), '<'); @@ -281,7 +305,7 @@ public: private: bool startsWithKnownTag() const { - return std::any_of(KnownTokens::asList().begin(), KnownTokens::asList().end(), + return std::any_of(KnownTokens::getList().begin(), KnownTokens::getList().end(), [&](const KnownTokens::TokenMap::value_type& p) { return startsWith(p.second); }); } @@ -470,11 +494,35 @@ private: if (pluralInfo.getCount() != static_cast<int>(translation.size())) throw ParsingError(replaceCpy(replaceCpy<std::wstring>(L"Invalid number of plural forms; actual: %x, expected: %y", L"%x", numberTo<std::wstring>(translation.size())), L"%y", numberTo<std::wstring>(pluralInfo.getCount())), scn.posRow(), scn.posCol()); - //ensure the placeholder is used when needed - int pos = 0; - for (auto it = translation.begin(); it != translation.end(); ++it, ++pos) - if (!pluralInfo.isSingleNumberForm(pos) && !contains(*it, "%x")) - throw ParsingError(replaceCpy<std::wstring>(L"Plural form at index position %y is missing the %x placeholder", L"%y", numberTo<std::wstring>(pos)), scn.posRow(), scn.posCol()); + //check for duplicate plural form translations (catch copy & paste errors for single-number form translations) + for (auto it = translation.begin(); it != translation.end(); ++it) + if (!contains(*it, "%x")) + { + auto it2 = std::find(it + 1, translation.end(), *it); + if (it2 != translation.end()) + throw ParsingError(replaceCpy<std::wstring>(L"Duplicate plural form translation at index position %x", L"%x", numberTo<std::wstring>(it2 - translation.begin())), scn.posRow(), scn.posCol()); + } + + for (int pos = 0; pos < static_cast<int>(translation.size()); ++pos) + if (pluralInfo.isSingleNumberForm(pos)) + { + //translation needs to use decimal number if english source does so (e.g. frequently changing text like statistics) + if (contains(original.first, "%x") || + contains(original.first, "1")) + { + const int firstNumber = pluralInfo.getFirstNumber(pos); + if (!(contains(translation[pos], "%x") || + contains(translation[pos], numberTo<std::string>(firstNumber)))) + throw ParsingError(replaceCpy<std::wstring>(replaceCpy<std::wstring>(L"Plural form translation at index position %y needs to use the decimal number %z or the %x placeholder", + L"%y", numberTo<std::wstring>(pos)), L"%z", numberTo<std::wstring>(firstNumber)), scn.posRow(), scn.posCol()); + } + } + else + { + //ensure the placeholder is used when needed + if (!contains(translation[pos], "%x")) + throw ParsingError(replaceCpy<std::wstring>(L"Plural form at index position %y is missing the %x placeholder", L"%y", numberTo<std::wstring>(pos)), scn.posRow(), scn.posCol()); + } auto checkSecondaryPlaceholder = [&](const std::string& placeholder) { diff --git a/lib/parse_plural.h b/lib/parse_plural.h index e9e04dbc..bac933c9 100644 --- a/lib/parse_plural.h +++ b/lib/parse_plural.h @@ -8,6 +8,7 @@ #define PARSE_PLURAL_H_INCLUDED #include <memory> +#include <cstdint> #include <functional> #include <zen/string_base.h> @@ -30,11 +31,11 @@ class PluralForm { public: PluralForm(const std::string& stream); //throw ParsingError - int getForm(int n) const { n_ = n ; return expr->eval(); } + int getForm(std::int64_t n) const { n_ = std::abs(n) ; return static_cast<int>(expr->eval()); } private: - std::shared_ptr<Expr<int>> expr; - mutable int n_; + std::shared_ptr<Expr<std::int64_t>> expr; + mutable std::int64_t n_; }; @@ -46,11 +47,18 @@ class PluralFormInfo public: PluralFormInfo(const std::string& definition, int pluralCount); //throw InvalidPluralForm - int getCount() const { return static_cast<int>(formCount.size()); } - bool isSingleNumberForm(int n) const { return 0 <= n && n < static_cast<int>(formCount.size()) ? formCount[n] == 1 : false; } + int getCount() const { return static_cast<int>(forms.size()); } + bool isSingleNumberForm(int index) const { return 0 <= index && index < static_cast<int>(forms.size()) ? forms[index].count == 1 : false; } + int getFirstNumber (int index) const { return 0 <= index && index < static_cast<int>(forms.size()) ? forms[index].firstNumber : -1; } private: - std::vector<int> formCount; + struct FormInfo + { + FormInfo() : count(0), firstNumber(0) {} + int count; + int firstNumber; //which maps to the plural form index position + }; + std::vector<FormInfo> forms; }; @@ -145,20 +153,20 @@ private: std::shared_ptr<Expr<T>> elseExp_; }; -struct ConstNumberExp : public Expr<int> +struct ConstNumberExp : public Expr<std::int64_t> { - ConstNumberExp(int n) : n_(n) {} - virtual int eval() const { return n_; } + ConstNumberExp(std::int64_t n) : n_(n) {} + virtual std::int64_t eval() const { return n_; } private: - int n_; + std::int64_t n_; }; -struct VariableNumberNExp : public Expr<int> +struct VariableNumberNExp : public Expr<std::int64_t> { - VariableNumberNExp(int& n) : n_(n) {} - virtual int eval() const { return n_; } + VariableNumberNExp(std::int64_t& n) : n_(n) {} + virtual std::int64_t eval() const { return n_; } private: - int& n_; + std::int64_t& n_; }; //------------------------------------------------------------------------------- @@ -186,10 +194,10 @@ struct Token }; Token(Type t) : type(t), number(0) {} - Token(int num) : type(TK_CONST_NUMBER), number(num) {} + Token(std::int64_t num) : type(TK_CONST_NUMBER), number(num) {} Type type; - int number; //if type == TK_CONST_NUMBER + std::int64_t number; //if type == TK_CONST_NUMBER }; class Scanner @@ -233,7 +241,7 @@ public: if (digitEnd != pos) { - int number = zen::stringTo<int>(std::string(pos, digitEnd)); + auto number = zen::stringTo<std::int64_t>(std::string(pos, digitEnd)); pos = digitEnd; return number; } @@ -249,7 +257,7 @@ private: return std::equal(prefix.begin(), prefix.end(), pos); } - typedef std::vector<std::pair<std::string, Token::Type> > TokenList; + typedef std::vector<std::pair<std::string, Token::Type>> TokenList; TokenList tokens; const std::string stream_; @@ -261,14 +269,14 @@ private: class Parser { public: - Parser(const std::string& stream, int& n) : + Parser(const std::string& stream, std::int64_t& n) : scn(stream), tk(scn.nextToken()), n_(n) {} - std::shared_ptr<Expr<int>> parse() //throw ParsingError; return value always bound! + std::shared_ptr<Expr<std::int64_t>> parse() //throw ParsingError; return value always bound! { - auto e = std::dynamic_pointer_cast<Expr<int>>(parseExpression()); //throw ParsingError + auto e = std::dynamic_pointer_cast<Expr<std::int64_t>>(parseExpression()); //throw ParsingError if (!e) throw ParsingError(); expectToken(Token::TK_END); @@ -287,15 +295,15 @@ private: nextToken(); auto ifExp = std::dynamic_pointer_cast<Expr<bool>>(e); - auto thenExp = std::dynamic_pointer_cast<Expr<int>>(parseExpression()); //associativity: <- + auto thenExp = std::dynamic_pointer_cast<Expr<std::int64_t>>(parseExpression()); //associativity: <- expectToken(Token::TK_TERNARY_COLON); nextToken(); - auto elseExp = std::dynamic_pointer_cast<Expr<int>>(parseExpression()); // + auto elseExp = std::dynamic_pointer_cast<Expr<std::int64_t>>(parseExpression()); // if (!ifExp || !thenExp || !elseExp) throw ParsingError(); - return std::make_shared<ConditionalExp<int>>(ifExp, thenExp, elseExp); + return std::make_shared<ConditionalExp<std::int64_t>>(ifExp, thenExp, elseExp); } return e; } @@ -337,8 +345,8 @@ private: nextToken(); std::shared_ptr<Expression> rhs = parseRelational(); - if (t == Token::TK_EQUAL) return makeBiExp(e, rhs, std::equal_to <int>()); //throw ParsingError - if (t == Token::TK_NOT_EQUAL) return makeBiExp(e, rhs, std::not_equal_to<int>()); // + if (t == Token::TK_EQUAL) return makeBiExp(e, rhs, std::equal_to <std::int64_t>()); //throw ParsingError + if (t == Token::TK_NOT_EQUAL) return makeBiExp(e, rhs, std::not_equal_to<std::int64_t>()); // } return e; } @@ -356,10 +364,10 @@ private: nextToken(); std::shared_ptr<Expression> rhs = parseMultiplicative(); - if (t == Token::TK_LESS) return makeBiExp(e, rhs, std::less <int>()); // - if (t == Token::TK_LESS_EQUAL) return makeBiExp(e, rhs, std::less_equal <int>()); //throw ParsingError - if (t == Token::TK_GREATER) return makeBiExp(e, rhs, std::greater <int>()); // - if (t == Token::TK_GREATER_EQUAL) return makeBiExp(e, rhs, std::greater_equal<int>()); // + if (t == Token::TK_LESS) return makeBiExp(e, rhs, std::less <std::int64_t>()); // + if (t == Token::TK_LESS_EQUAL) return makeBiExp(e, rhs, std::less_equal <std::int64_t>()); //throw ParsingError + if (t == Token::TK_GREATER) return makeBiExp(e, rhs, std::greater <std::int64_t>()); // + if (t == Token::TK_GREATER_EQUAL) return makeBiExp(e, rhs, std::greater_equal<std::int64_t>()); // } return e; } @@ -378,7 +386,7 @@ private: if (literal->eval() == 0) throw ParsingError(); - e = makeBiExp(e, rhs, std::modulus<int>()); //throw ParsingError + e = makeBiExp(e, rhs, std::modulus<std::int64_t>()); //throw ParsingError } return e; } @@ -392,7 +400,7 @@ private: } else if (token().type == Token::TK_CONST_NUMBER) { - const int number = token().number; + const std::int64_t number = token().number; nextToken(); return std::make_shared<ConstNumberExp>(number); } @@ -420,7 +428,7 @@ private: Scanner scn; Token tk; - int& n_; + std::int64_t& n_; }; } @@ -431,7 +439,7 @@ PluralFormInfo::PluralFormInfo(const std::string& definition, int pluralCount) / if (pluralCount < 1) throw InvalidPluralForm(); - formCount.resize(pluralCount); + forms.resize(pluralCount); try { parse_plural::PluralForm pf(definition); //throw parse_plural::ParsingError @@ -442,8 +450,12 @@ PluralFormInfo::PluralFormInfo(const std::string& definition, int pluralCount) / for (int j = 0; j < 1000; ++j) { int form = pf.getForm(j); - if (0 <= form && form < static_cast<int>(formCount.size())) - ++formCount[form]; + if (0 <= form && form < static_cast<int>(forms.size())) + { + if (forms[form].count == 0) + forms[form].firstNumber = j; + ++forms[form].count; + } else throw InvalidPluralForm(); } @@ -454,7 +466,7 @@ PluralFormInfo::PluralFormInfo(const std::string& definition, int pluralCount) / } //ensure each form is used at least once: - if (!std::all_of(formCount.begin(), formCount.end(), [](int count) { return count >= 1; })) + if (!std::all_of(forms.begin(), forms.end(), [](const FormInfo& fi) { return fi.count >= 1; })) throw InvalidPluralForm(); } @@ -463,4 +475,4 @@ inline PluralForm::PluralForm(const std::string& stream) : expr(implementation::Parser(stream, n_).parse()) {} //throw ParsingError } -#endif // PARSE_PLURAL_H_INCLUDED
\ No newline at end of file +#endif // PARSE_PLURAL_H_INCLUDED diff --git a/lib/perf_check.cpp b/lib/perf_check.cpp index 0f5506b3..bf232add 100644 --- a/lib/perf_check.cpp +++ b/lib/perf_check.cpp @@ -122,7 +122,7 @@ zen::Opt<std::wstring> PerfCheck::getItemsPerSecond() const const int itemsDelta = itemBack.second.itemCount_ - itemFront.second.itemCount_; if (timeDelta != 0) - return replaceCpy(_("%x items"), L"%x", formatThreeDigitPrecision(itemsDelta * 1000.0 / timeDelta)) + _("/sec"); + return replaceCpy(_("%x items/sec"), L"%x", formatThreeDigitPrecision(itemsDelta * 1000.0 / timeDelta)); } return NoValue(); } @@ -231,10 +231,10 @@ wxString Statistics::getRemainingTime(int objectsCurrent, double dataCurrent) double q = 0; double r = 0; double s = 0; - for (std::list<record>::const_iterator i = measurements.begin(); i != measurements.end(); ++i) + for (const record& rec : measurements) { - const double x_i = i->x_i; - const double f_i = i->f_i; + const double x_i = rec.x_i; + const double f_i = rec.f_i; p += x_i * x_i; q += f_i * x_i; r += f_i; diff --git a/lib/process_xml.cpp b/lib/process_xml.cpp index 4640e472..3e3e72f1 100644 --- a/lib/process_xml.cpp +++ b/lib/process_xml.cpp @@ -10,6 +10,7 @@ #include "ffs_paths.h" #include <zen/file_handling.h> #include <zen/file_io.h> +//#include <zen/time.h> #include "xml_base.h" using namespace zen; @@ -20,8 +21,8 @@ namespace { //------------------------------------------------------------------------------------------------------------------------------- const int XML_FORMAT_VER_GLOBAL = 1; -const int XML_FORMAT_VER_FFS_GUI = 2; -const int XML_FORMAT_VER_FFS_BATCH = 2; +const int XML_FORMAT_VER_FFS_GUI = 3; //for FFS 5.22 +const int XML_FORMAT_VER_FFS_BATCH = 3; // //------------------------------------------------------------------------------------------------------------------------------- } @@ -111,7 +112,7 @@ xmlAccess::XmlGuiConfig xmlAccess::convertBatchToGui(const xmlAccess::XmlBatchCo switch (batchCfg.handleError) { case ON_ERROR_POPUP: - case ON_ERROR_ABORT: + case ON_ERROR_STOP: output.handleError = ON_GUIERROR_POPUP; break; case ON_ERROR_IGNORE: @@ -261,8 +262,8 @@ void writeText(const OnError& value, std::string& output) case ON_ERROR_POPUP: output = "Popup"; break; - case ON_ERROR_ABORT: - output = "Abort"; + case ON_ERROR_STOP: + output = "Stop"; break; } } @@ -274,15 +275,17 @@ bool readText(const std::string& input, OnError& value) zen::trim(tmp); warn_static("remove after migration. 2013.08.20") if (tmp == "Exit") //obsolete - value = ON_ERROR_ABORT; + value = ON_ERROR_STOP; + else if (tmp == "Abort") //obsolete: 2013.09.04 + value = ON_ERROR_STOP; else if (tmp == "Ignore") value = ON_ERROR_IGNORE; else if (tmp == "Popup") value = ON_ERROR_POPUP; - else if (tmp == "Abort") - value = ON_ERROR_ABORT; + else if (tmp == "Stop") + value = ON_ERROR_STOP; else return false; return true; @@ -797,6 +800,25 @@ void writeStruc(const ViewFilterDefault& value, XmlElement& output) actView.attribute("DeleteRight", value.deleteRight); actView.attribute("DoNothing" , value.doNothing); } + + +template <> inline +bool readStruc(const XmlElement& input, ConfigHistoryItem& value) +{ + XmlIn in(input); + bool rv1 = in(value.configFile); + //bool rv2 = in.attribute("LastUsed", value.lastUseTime); + return rv1 /*&& rv2*/; +} + + +template <> inline +void writeStruc(const ConfigHistoryItem& value, XmlElement& output) +{ + XmlOut out(output); + out(value.configFile); + //out.attribute("LastUsed", value.lastUseTime); +} } @@ -805,7 +827,12 @@ namespace void readConfig(const XmlIn& in, CompConfig& cmpConfig) { in["Variant" ](cmpConfig.compareVar); - in["HandleSymlinks"](cmpConfig.handleSymlinks); + + warn_static("remove check after migration. 2013.09.7") + if (in["HandleSymlinks"])//obsolete name + in["HandleSymlinks"](cmpConfig.handleSymlinks); + else + in["Symlinks"](cmpConfig.handleSymlinks); } @@ -1028,15 +1055,17 @@ void readConfig(const XmlIn& in, XmlGlobalSettings& config) { XmlIn inShared = in["Shared"]; - inShared["Language"].attribute("id", config.programLanguage); + inShared["Language"].attribute("Id", config.programLanguage); - inShared["FailSafeFileCopy" ].attribute("Enabled", config.transactionalFileCopy); + inShared["FailSafeFileCopy" ].attribute("Enabled", config.failsafeFileCopy); inShared["CopyLockedFiles" ].attribute("Enabled", config.copyLockedFiles); inShared["CopyFilePermissions" ].attribute("Enabled", config.copyFilePermissions); + inShared["AutomaticRetry" ].attribute("Count" , config.automaticRetryCount); + inShared["AutomaticRetry" ].attribute("Delay" , config.automaticRetryDelay); + inShared["FileTimeTolerance" ].attribute("Seconds", config.fileTimeTolerance); inShared["RunWithBackgroundPriority"].attribute("Enabled", config.runWithBackgroundPriority); inShared["LockDirectoriesDuringSync"].attribute("Enabled", config.createLockFile); inShared["VerifyCopiedFiles" ].attribute("Enabled", config.verifyFileCopy); - inShared["FileTimeTolerance" ].attribute("Seconds", config.fileTimeTolerance); inShared["LastSyncsLogSizeMax" ].attribute("Bytes" , config.lastSyncsLogFileSizeMax); XmlIn inOpt = inShared["OptionalDialogs"]; @@ -1103,6 +1132,7 @@ void readConfig(const XmlIn& in, XmlGlobalSettings& config) //load config file history inGui["LastUsedConfig"](config.gui.lastUsedConfigFiles); + inGui["ConfigHistory"](config.gui.cfgFileHistory); inGui["ConfigHistory"].attribute("MaxSize", config.gui.cfgFileHistMax); @@ -1117,7 +1147,7 @@ void readConfig(const XmlIn& in, XmlGlobalSettings& config) inGui["ExternalApplications"](config.gui.externelApplications); //last update check - inGui["LastUpdateCheck"](config.gui.lastUpdateCheck); + inGui["LastVersionCheck"](config.gui.lastUpdateCheck); //batch specific global settings //XmlIn inBatch = in["Batch"]; @@ -1263,8 +1293,8 @@ namespace { void writeConfig(const CompConfig& cmpConfig, XmlOut& out) { - out["Variant" ](cmpConfig.compareVar); - out["HandleSymlinks"](cmpConfig.handleSymlinks); + out["Variant" ](cmpConfig.compareVar); + out["Symlinks"](cmpConfig.handleSymlinks); } @@ -1409,15 +1439,17 @@ void writeConfig(const XmlGlobalSettings& config, XmlOut& out) { XmlOut outShared = out["Shared"]; - outShared["Language"].attribute("id", config.programLanguage); + outShared["Language"].attribute("Id", config.programLanguage); - outShared["FailSafeFileCopy" ].attribute("Enabled", config.transactionalFileCopy); + outShared["FailSafeFileCopy" ].attribute("Enabled", config.failsafeFileCopy); outShared["CopyLockedFiles" ].attribute("Enabled", config.copyLockedFiles); outShared["CopyFilePermissions" ].attribute("Enabled", config.copyFilePermissions); + outShared["AutomaticRetry" ].attribute("Count" , config.automaticRetryCount); + outShared["AutomaticRetry" ].attribute("Delay" , config.automaticRetryDelay); + outShared["FileTimeTolerance" ].attribute("Seconds", config.fileTimeTolerance); outShared["RunWithBackgroundPriority"].attribute("Enabled", config.runWithBackgroundPriority); outShared["LockDirectoriesDuringSync"].attribute("Enabled", config.createLockFile); outShared["VerifyCopiedFiles" ].attribute("Enabled", config.verifyFileCopy); - outShared["FileTimeTolerance" ].attribute("Seconds", config.fileTimeTolerance); outShared["LastSyncsLogSizeMax" ].attribute("Bytes" , config.lastSyncsLogFileSizeMax); XmlOut outOpt = outShared["OptionalDialogs"]; @@ -1482,6 +1514,7 @@ void writeConfig(const XmlGlobalSettings& config, XmlOut& out) //load config file history outGui["LastUsedConfig"](config.gui.lastUsedConfigFiles); + outGui["ConfigHistory" ](config.gui.cfgFileHistory); outGui["ConfigHistory"].attribute("MaxSize", config.gui.cfgFileHistMax); @@ -1496,7 +1529,7 @@ void writeConfig(const XmlGlobalSettings& config, XmlOut& out) outGui["ExternalApplications"](config.gui.externelApplications); //last update check - outGui["LastUpdateCheck"](config.gui.lastUpdateCheck); + outGui["LastVersionCheck"](config.gui.lastUpdateCheck); //batch specific global settings //XmlOut outBatch = out["Batch"]; diff --git a/lib/process_xml.h b/lib/process_xml.h index 85f2d461..4092c072 100644 --- a/lib/process_xml.h +++ b/lib/process_xml.h @@ -12,6 +12,7 @@ #include "xml_base.h" #include "localization.h" #include "../ui/column_attr.h" +#include "../ui/folder_history_types.h" //#include "ffs_paths.h" namespace xmlAccess @@ -31,7 +32,7 @@ enum OnError { ON_ERROR_IGNORE, ON_ERROR_POPUP, - ON_ERROR_ABORT + ON_ERROR_STOP }; enum OnGuiError @@ -42,7 +43,7 @@ enum OnGuiError typedef std::wstring Description; typedef std::wstring Commandline; -typedef std::vector<std::pair<Description, Commandline> > ExternalApps; +typedef std::vector<std::pair<Description, Commandline>> ExternalApps; //--------------------------------------------------------------------- struct XmlGuiConfig @@ -135,26 +136,30 @@ struct XmlGlobalSettings //Shared (GUI/BATCH) settings XmlGlobalSettings() : programLanguage(zen::retrieveSystemLanguage()), + failsafeFileCopy(true), copyLockedFiles(true), copyFilePermissions(false), - runWithBackgroundPriority(false), + automaticRetryCount(0), + automaticRetryDelay(5), fileTimeTolerance(2), //default 2s: FAT vs NTFS - lastSyncsLogFileSizeMax(100000), //maximum size for LastSyncs.log: use a human-readable number + runWithBackgroundPriority(false), + createLockFile(true), verifyFileCopy(false), - transactionalFileCopy(true), - createLockFile(true) {} + lastSyncsLogFileSizeMax(100000) //maximum size for LastSyncs.log: use a human-readable number + {} int programLanguage; - bool copyLockedFiles; //VSS usage + bool failsafeFileCopy; + bool copyLockedFiles; bool copyFilePermissions; - - bool runWithBackgroundPriority; + size_t automaticRetryCount; + size_t automaticRetryDelay; //unit: [sec] size_t fileTimeTolerance; //max. allowed file time deviation - size_t lastSyncsLogFileSizeMax; - bool verifyFileCopy; //verify copied files - bool transactionalFileCopy; + bool runWithBackgroundPriority; bool createLockFile; + bool verifyFileCopy; //verify copied files + size_t lastSyncsLogFileSizeMax; OptionalDialogs optDialogs; @@ -238,7 +243,7 @@ struct XmlGlobalSettings ExternalApps externelApplications; - std::vector<Zstring> cfgFileHistory; + std::vector<zen::ConfigHistoryItem> cfgFileHistory; size_t cfgFileHistMax; std::vector<Zstring> lastUsedConfigFiles; @@ -259,7 +264,7 @@ struct XmlGlobalSettings bool showIcons; FileIconSize iconSize; - long lastUpdateCheck; //time of last update check + long lastUpdateCheck; //time of last update check ViewFilterDefault viewFilterDefault; wxString guiPerspectiveLast; //used by wxAuiManager diff --git a/lib/resolve_path.cpp b/lib/resolve_path.cpp index 083b1007..768876c9 100644 --- a/lib/resolve_path.cpp +++ b/lib/resolve_path.cpp @@ -508,12 +508,9 @@ void getDirectoryAliasesRecursive(const Zstring& dirname, std::set<Zstring, Less return startsWith(path, prefix); #endif }; - std::for_each(envToDir.begin(), envToDir.end(), - [&](const std::pair<Zstring, Zstring>& entry) - { + for (const auto& entry : envToDir) if (pathStartsWith(dirname, entry.second)) output.insert(MACRO_SEP + entry.first + MACRO_SEP + (dirname.c_str() + entry.second.size())); - }); } //4. replace (all) macros: %USERPROFILE% -> C:\Users\<user> diff --git a/lib/resources.cpp b/lib/resources.cpp deleted file mode 100644 index 6deaf0ec..00000000 --- a/lib/resources.cpp +++ /dev/null @@ -1,105 +0,0 @@ -// ************************************************************************** -// * This file is part of the FreeFileSync project. It is distributed under * -// * GNU General Public License: http://www.gnu.org/licenses/gpl.html * -// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved * -// ************************************************************************** - -#include "resources.h" -#include <memory> -#include <wx/wfstream.h> -#include <wx/zipstrm.h> -#include <wx/image.h> -#include <wx/mstream.h> -#include <zen/utf.h> -#include "ffs_paths.h" - -using namespace zen; - - -const GlobalResources& GlobalResources::instance() -{ - static GlobalResources inst; - return inst; -} - - -namespace -{ -void loadAnimFromZip(wxZipInputStream& zipInput, wxAnimation& anim) -{ - //work around wxWidgets bug: - //construct seekable input stream (zip-input stream is non-seekable) for wxAnimation::Load() - //luckily this method call is very fast: below measurement precision! - std::vector<char> data; - data.reserve(10000); - - int newValue = 0; - while ((newValue = zipInput.GetC()) != wxEOF) - data.push_back(newValue); - - wxMemoryInputStream seekAbleStream(&data.front(), data.size()); //stream does not take ownership of data - - anim.Load(seekAbleStream, wxANIMATION_TYPE_GIF); -} -} - - -GlobalResources::GlobalResources() -{ - wxFFileInputStream input(utfCvrtTo<wxString>(zen::getResourceDir()) + L"Resources.zip"); - if (input.IsOk()) //if not... we don't want to react too harsh here - { - //activate support for .png files - wxImage::AddHandler(new wxPNGHandler); //ownership passed - - wxZipInputStream resourceFile(input, wxConvUTF8); - //do NOT rely on wxConvLocal! On failure shows unhelpful popup "Cannot convert from the charset 'Unknown encoding (-1)'!" - - while (true) - { - std::unique_ptr<wxZipEntry> entry(resourceFile.GetNextEntry()); //take ownership! - if (!entry) - break; - - const wxString name = entry->GetName(); - - //generic image loading - if (name.EndsWith(L".png")) - bitmaps.insert(std::make_pair(name, wxImage(resourceFile, wxBITMAP_TYPE_PNG))); - else if (name == L"wink.gif") - loadAnimFromZip(resourceFile, aniWink); - else if (name == L"working.gif") - loadAnimFromZip(resourceFile, aniWorking); - } - } - -#ifdef ZEN_WIN - //for compatibility it seems we need to stick with a "real" icon - programIconFFS = wxIcon(L"A_FFS_ICON"); - -#elif defined ZEN_LINUX - //attention: make sure to not implicitly call "instance()" again => deadlock on Linux - programIconFFS.CopyFromBitmap(getImage(L"FreeFileSync")); //use big logo bitmap for better quality - -#elif defined ZEN_MAC - assert(getImage(L"FreeFileSync").GetWidth () == getImage(L"FreeFileSync").GetHeight() && - getImage(L"FreeFileSync").GetWidth() % 128 == 0); - //wxWidgets' bitmap to icon conversion on OS X can only deal with very specific sizes - programIconFFS.CopyFromBitmap(getImage(L"FreeFileSync").ConvertToImage().Scale(128, 128, wxIMAGE_QUALITY_HIGH)); //"von hinten durch die Brust ins Auge" -#endif -} - - -const wxBitmap& GlobalResources::getImage(const wxString& imageName) const -{ - auto it = bitmaps.find(!contains(imageName, L'.') ? //assume .png ending if nothing else specified - imageName + L".png" : - imageName); - if (it != bitmaps.end()) - return it->second; - else - { - assert(false); - return wxNullBitmap; - } -} diff --git a/lib/resources.h b/lib/resources.h deleted file mode 100644 index 1cb05f20..00000000 --- a/lib/resources.h +++ /dev/null @@ -1,40 +0,0 @@ -// ************************************************************************** -// * This file is part of the FreeFileSync project. It is distributed under * -// * GNU General Public License: http://www.gnu.org/licenses/gpl.html * -// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved * -// ************************************************************************** - -#ifndef RESOURCES_H_8740257825342532457 -#define RESOURCES_H_8740257825342532457 - -#include <map> -#include <wx/bitmap.h> -#include <wx/animate.h> -#include <wx/icon.h> - - -class GlobalResources -{ -public: - static const GlobalResources& instance(); - - const wxBitmap& getImage(const wxString& name) const; - - //global image resource objects - wxAnimation aniWink; - wxAnimation aniWorking; - wxIcon programIconFFS; - -private: - GlobalResources(); - GlobalResources(const GlobalResources&); - GlobalResources& operator=(const GlobalResources&); - - std::map<wxString, wxBitmap> bitmaps; -}; - - -inline -const wxBitmap& getResourceImage(const wxString& name) { return GlobalResources::instance().getImage(name); } - -#endif //RESOURCES_H_8740257825342532457 diff --git a/lib/shadow.cpp b/lib/shadow.cpp index 808b3b68..d1027f69 100644 --- a/lib/shadow.cpp +++ b/lib/shadow.cpp @@ -118,7 +118,7 @@ Zstring ShadowCopy::makeShadowCopy(const Zstring& inputFile, const std::function L"%y", fmtFileName(filenameFinal))); //get or create instance of shadow volume - VolNameShadowMap::const_iterator it = shadowVol.find(volumeNamePf); + auto it = shadowVol.find(volumeNamePf); if (it == shadowVol.end()) { onBeforeMakeVolumeCopy(volumeNamePf); //notify client before (potentially) blocking some time diff --git a/lib/status_handler.h b/lib/status_handler.h index c19935b1..9a288b6f 100644 --- a/lib/status_handler.h +++ b/lib/status_handler.h @@ -87,7 +87,7 @@ protected: virtual void requestAbortion() { abortRequested = true; - statusText_ =_("Abort requested: Waiting for current operation to finish..."); + statusText_ =_("Stop requested: Waiting for current operation to finish..."); } //this does NOT call abortThisProcess immediately, but when we're out of the C GUI call stack //implement Statistics diff --git a/lib/status_handler_impl.h b/lib/status_handler_impl.h index e1212b65..210e6ecd 100644 --- a/lib/status_handler_impl.h +++ b/lib/status_handler_impl.h @@ -11,32 +11,11 @@ #include <zen/file_error.h> #include "process_callback.h" -//template <typename Function> inline -//bool tryReportingError(Function cmd, ProcessCallback& handler) //return "true" on success, "false" if error was ignored -//{ -// for (;;) -// try -// { -// cmd(); //throw FileError -// return true; -// } -// catch (zen::FileError& error) -// { -// switch (handler.reportError(error.toString())) //may throw! -// { -// case ProcessCallback::IGNORE_ERROR: -// return false; -// case ProcessCallback::RETRY: -// break; //continue with loop -// } -// } -//} - template <typename Function> inline -zen::Opt<std::wstring> tryReportingError2(Function cmd, ProcessCallback& handler) //return ignored error message if available +zen::Opt<std::wstring> tryReportingError(Function cmd, ProcessCallback& handler) //return ignored error message if available { - for (;;) + for (size_t retryNumber = 0;; ++retryNumber) try { cmd(); //throw FileError @@ -44,7 +23,7 @@ zen::Opt<std::wstring> tryReportingError2(Function cmd, ProcessCallback& handler } catch (zen::FileError& error) { - switch (handler.reportError(error.toString())) //may throw! + switch (handler.reportError(error.toString(), retryNumber)) //may throw! { case ProcessCallback::IGNORE_ERROR: return error.toString(); diff --git a/lib/versioning.cpp b/lib/versioning.cpp index 65373499..82696e3a 100644 --- a/lib/versioning.cpp +++ b/lib/versioning.cpp @@ -224,8 +224,8 @@ private: return nullptr; //DON'T traverse into subdirs; moveDirectory works recursively! } - virtual HandleError reportDirError (const std::wstring& msg) { throw FileError(msg); } - virtual HandleError reportItemError(const std::wstring& msg, const Zchar* shortName) { throw FileError(msg); } + virtual HandleError reportDirError (const std::wstring& msg, size_t retryNumber) { throw FileError(msg); } + virtual HandleError reportItemError(const std::wstring& msg, size_t retryNumber, const Zchar* shortName) { throw FileError(msg); } std::vector<Zstring>& files_; std::vector<Zstring>& dirs_; diff --git a/lib/versioning.h b/lib/versioning.h index 33dc31c4..06065656 100644 --- a/lib/versioning.h +++ b/lib/versioning.h @@ -43,7 +43,7 @@ public: timeStamp_(formatTime<Zstring>(Zstr("%Y-%m-%d %H%M%S"), timeStamp)) //e.g. "2012-05-15 131513" { if (timeStamp_.size() != 17) //formatTime() returns empty string on error; unexpected length: e.g. problem in year 10000! - throw FileError(_("Failure to create timestamp for versioning:") + L" \'" + timeStamp_ + L"\'"); + throw FileError(_("Unable to create timestamp for versioning:") + L" \"" + timeStamp_ + L"\""); } bool revisionFile(const Zstring& fullName, const Zstring& relativeName, CallbackMoveFile& callback); //throw FileError; return "false" if file is not existing |