summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorDaniel Wilhelm <daniel@wili.li>2014-04-18 17:28:01 +0200
committerDaniel Wilhelm <daniel@wili.li>2014-04-18 17:28:01 +0200
commitfe9eb89ebc1b3c33cbac00a3fa095a14faef9113 (patch)
tree8a3bb620a9acb83fe0057061a86e8f2cb91a9fe1 /lib
parent5.21 (diff)
downloadFreeFileSync-fe9eb89ebc1b3c33cbac00a3fa095a14faef9113.tar.gz
FreeFileSync-fe9eb89ebc1b3c33cbac00a3fa095a14faef9113.tar.bz2
FreeFileSync-fe9eb89ebc1b3c33cbac00a3fa095a14faef9113.zip
5.22
Diffstat (limited to 'lib')
-rw-r--r--lib/ShadowCopy/Shadow_Windows7.vcxproj16
-rw-r--r--lib/Thumbnail/Thumbnail.vcxproj2
-rw-r--r--lib/dir_exist_async.h40
-rw-r--r--lib/dir_lock.cpp2
-rw-r--r--lib/ffs_paths.cpp11
-rw-r--r--lib/localization.cpp45
-rw-r--r--lib/parallel_scan.cpp49
-rw-r--r--lib/parallel_scan.h4
-rw-r--r--lib/parse_lng.h90
-rw-r--r--lib/parse_plural.h88
-rw-r--r--lib/perf_check.cpp8
-rw-r--r--lib/process_xml.cpp71
-rw-r--r--lib/process_xml.h33
-rw-r--r--lib/resolve_path.cpp5
-rw-r--r--lib/resources.cpp105
-rw-r--r--lib/resources.h40
-rw-r--r--lib/shadow.cpp2
-rw-r--r--lib/status_handler.h2
-rw-r--r--lib/status_handler_impl.h27
-rw-r--r--lib/versioning.cpp4
-rw-r--r--lib/versioning.h2
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
bgstack15