summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/Batch.icobin116037 -> 117121 bytes
-rw-r--r--lib/ShadowCopy/dll_main.cpp25
-rw-r--r--lib/Thumbnail/dll_main.cpp25
-rw-r--r--lib/db_file.cpp52
-rw-r--r--lib/icon_buffer.cpp28
-rw-r--r--lib/localization.cpp26
-rw-r--r--lib/lock_holder.h4
-rw-r--r--lib/parallel_scan.cpp96
-rw-r--r--lib/parse_lng.h60
-rw-r--r--lib/parse_plural.h12
-rw-r--r--lib/perf_check.cpp14
-rw-r--r--lib/perf_check.h4
-rw-r--r--lib/process_xml.cpp157
-rw-r--r--lib/process_xml.h28
-rw-r--r--lib/resolve_path.cpp27
-rw-r--r--lib/resources.cpp6
-rw-r--r--lib/shadow.cpp8
-rw-r--r--lib/versioning.cpp181
-rw-r--r--lib/versioning.h20
-rw-r--r--lib/xml_base.cpp4
20 files changed, 388 insertions, 389 deletions
diff --git a/lib/Batch.ico b/lib/Batch.ico
index 1856b1fb..f742b9a3 100644
--- a/lib/Batch.ico
+++ b/lib/Batch.ico
Binary files differ
diff --git a/lib/ShadowCopy/dll_main.cpp b/lib/ShadowCopy/dll_main.cpp
deleted file mode 100644
index 4665154a..00000000
--- a/lib/ShadowCopy/dll_main.cpp
+++ /dev/null
@@ -1,25 +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 *
-// **************************************************************************
-
-
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-
-//optional: add init/teardown logic here
-BOOL APIENTRY DllMain(HINSTANCE hinstDLL,
- DWORD fdwReason,
- LPVOID lpvReserved)
-{
- switch (fdwReason)
- {
- case DLL_PROCESS_ATTACH:
- case DLL_PROCESS_DETACH:
- case DLL_THREAD_ATTACH:
- case DLL_THREAD_DETACH:
- break;
- }
- return TRUE;
-}
diff --git a/lib/Thumbnail/dll_main.cpp b/lib/Thumbnail/dll_main.cpp
deleted file mode 100644
index 4665154a..00000000
--- a/lib/Thumbnail/dll_main.cpp
+++ /dev/null
@@ -1,25 +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 *
-// **************************************************************************
-
-
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-
-//optional: add init/teardown logic here
-BOOL APIENTRY DllMain(HINSTANCE hinstDLL,
- DWORD fdwReason,
- LPVOID lpvReserved)
-{
- switch (fdwReason)
- {
- case DLL_PROCESS_ATTACH:
- case DLL_PROCESS_DETACH:
- case DLL_THREAD_ATTACH:
- case DLL_THREAD_DETACH:
- break;
- }
- return TRUE;
-}
diff --git a/lib/db_file.cpp b/lib/db_file.cpp
index f81ada21..7f8da45a 100644
--- a/lib/db_file.cpp
+++ b/lib/db_file.cpp
@@ -68,10 +68,10 @@ void saveStreams(const StreamMapping& streamList, const Zstring& filename) //thr
//save stream list
writeNumber<std::uint32_t>(streamOut, static_cast<std::uint32_t>(streamList.size())); //number of streams, one for each sync-pair
- for (auto iter = streamList.begin(); iter != streamList.end(); ++iter)
+ for (auto it = streamList.begin(); it != streamList.end(); ++it)
{
- writeContainer<std::string >(streamOut, iter->first );
- writeContainer<BinaryStream>(streamOut, iter->second);
+ writeContainer<std::string >(streamOut, it->first );
+ writeContainer<BinaryStream>(streamOut, it->second);
}
saveBinStream(filename, streamOut.get()); //throw FileError
@@ -449,23 +449,23 @@ private:
template <class M, class V>
static V& updateItem(M& map, const Zstring& key, const V& value) //efficient create or update without "default-constructible" requirement (Effective STL, item 24)
{
- auto iter = map.lower_bound(key);
- if (iter != map.end() && !(map.key_comp()(key, iter->first)))
+ auto it = map.lower_bound(key);
+ if (it != map.end() && !(map.key_comp()(key, it->first)))
{
#ifdef FFS_WIN //caveat: key might need to be updated, too, if there is a change in short name case!!!
- if (iter->first != key)
+ if (it->first != key)
{
- map.erase(iter); //don't fiddle with decrementing "iter"! - you might lose while optimizing pointlessly
+ map.erase(it); //don't fiddle with decrementing "it"! - you might lose while optimizing pointlessly
return map.insert(typename M::value_type(key, value)).first->second;
}
else
#endif
{
- iter->second = value;
- return iter->second;
+ it->second = value;
+ return it->second;
}
}
- return map.insert(iter, typename M::value_type(key, value))->second;
+ return map.insert(it, typename M::value_type(key, value))->second;
}
void process(const HierarchyObject::SubFileVec& currentFiles, const Zstring& parentRelativeNamePf, InSyncDir::FileList& dbFiles)
@@ -494,9 +494,9 @@ private:
}
else //not in sync: preserve last synchronous state
{
- auto iter = dbFiles.find(fileMap.getObjShortName());
- if (iter != dbFiles.end())
- toPreserve.insert(&iter->second);
+ auto it = dbFiles.find(fileMap.getObjShortName());
+ if (it != dbFiles.end())
+ toPreserve.insert(&it->second);
}
}
});
@@ -533,9 +533,9 @@ private:
}
else //not in sync: preserve last synchronous state
{
- auto iter = dbLinks.find(linkMap.getObjShortName());
- if (iter != dbLinks.end())
- toPreserve.insert(&iter->second);
+ auto it = dbLinks.find(linkMap.getObjShortName());
+ if (it != dbLinks.end())
+ toPreserve.insert(&it->second);
}
}
});
@@ -565,18 +565,18 @@ private:
//update directory entry only (shallow), but do *not touch* exising child elements!!!
const Zstring& key = dirMap.getObjShortName();
auto insertResult = dbDirs.insert(std::make_pair(key, InSyncDir(InSyncDir::STATUS_IN_SYNC))); //get or create
- auto iter = insertResult.first;
+ auto it = insertResult.first;
#ifdef FFS_WIN //caveat: key might need to be updated, too, if there is a change in short name case!!!
const bool alreadyExisting = !insertResult.second;
- if (alreadyExisting && iter->first != key)
+ if (alreadyExisting && it->first != key)
{
- auto oldValue = std::move(iter->second);
- dbDirs.erase(iter); //don't fiddle with decrementing "iter"! - you might lose while optimizing pointlessly
- iter = dbDirs.insert(InSyncDir::DirList::value_type(key, std::move(oldValue))).first;
+ auto oldValue = std::move(it->second);
+ dbDirs.erase(it); //don't fiddle with decrementing "it"! - you might lose while optimizing pointlessly
+ it = dbDirs.insert(InSyncDir::DirList::value_type(key, std::move(oldValue))).first;
}
#endif
- InSyncDir& dir = iter->second;
+ InSyncDir& dir = it->second;
dir.status = InSyncDir::STATUS_IN_SYNC; //update immediate directory entry
toPreserve.insert(&dir);
recurse(dirMap, dir);
@@ -599,11 +599,11 @@ private:
case DIR_LEFT_SIDE_ONLY:
case DIR_RIGHT_SIDE_ONLY:
{
- auto iter = dbDirs.find(dirMap.getObjShortName());
- if (iter != dbDirs.end())
+ auto it = dbDirs.find(dirMap.getObjShortName());
+ if (it != dbDirs.end())
{
- toPreserve.insert(&iter->second);
- recurse(dirMap, iter->second); //although existing sub-items cannot be in sync, items deleted on both sides *are* in-sync!!!
+ toPreserve.insert(&it->second);
+ recurse(dirMap, it->second); //although existing sub-items cannot be in sync, items deleted on both sides *are* in-sync!!!
}
}
break;
diff --git a/lib/icon_buffer.cpp b/lib/icon_buffer.cpp
index 9274a0b4..1d391dfc 100644
--- a/lib/icon_buffer.cpp
+++ b/lib/icon_buffer.cpp
@@ -97,7 +97,6 @@ public:
wxIcon newIcon; //attention: wxIcon uses reference counting!
#ifdef FFS_WIN
newIcon.SetHICON(clone.handle_);
-
{
//this block costs ~0.04 ms
ICONINFO icoInfo = {};
@@ -129,8 +128,14 @@ public:
//no stretching for now
//newIcon.SetSize(expectedSize, expectedSize); //icon is stretched to this size if referenced HICON differs
-#elif defined FFS_LINUX //
- newIcon.SetPixbuf(clone.handle_); // transfer ownership!!
+#elif defined FFS_LINUX
+ // transfer ownership!!
+#if wxCHECK_VERSION(2, 9, 4)
+ newIcon.CopyFromBitmap(wxBitmap(clone.handle_));
+#else
+ newIcon.SetPixbuf(clone.handle_);
+#endif
+
#endif //
clone.handle_ = nullptr; //
return newIcon;
@@ -273,8 +278,8 @@ IconHolder getGenericFileIcon(IconBuffer::IconSize sz)
const int requestedSize = cvrtSize(sz);
if (GtkIconTheme* defaultTheme = gtk_icon_theme_get_default()) //not owned!
- for (auto iter = std::begin(mimeFileIcons); iter != std::end(mimeFileIcons); ++iter)
- if (GdkPixbuf* pixBuf = gtk_icon_theme_load_icon(defaultTheme, *iter, requestedSize, GTK_ICON_LOOKUP_USE_BUILTIN, nullptr))
+ for (auto it = std::begin(mimeFileIcons); it != std::end(mimeFileIcons); ++it)
+ if (GdkPixbuf* pixBuf = gtk_icon_theme_load_icon(defaultTheme, *it, requestedSize, GTK_ICON_LOOKUP_USE_BUILTIN, nullptr))
return IconHolder(pixBuf); //pass ownership (may be nullptr)
return IconHolder();
#endif
@@ -374,10 +379,8 @@ IconHolder getGenericDirectoryIcon(IconBuffer::IconSize sz)
#endif
}
-
//################################################################################################################################################
-
//---------------------- Shared Data -------------------------
class WorkLoad
{
@@ -400,7 +403,8 @@ public:
boost::unique_lock<boost::mutex> dummy(lockFiles);
filesToLoad = newLoad;
}
- conditionNewFiles.notify_one();
+
+ conditionNewFiles.notify_all(); //instead of notify_one(); workaround bug: https://svn.boost.org/trac/boost/ticket/7796
//condition handling, see: http://www.boost.org/doc/libs/1_43_0/doc/html/thread/synchronization.html#thread.synchronization.condvar_ref
}
@@ -411,7 +415,7 @@ private:
};
-typedef std::map<Zstring, IconHolder, LessFilename> NameIconMap; //entryName/icon -> note: Zstring is thread-safe
+typedef std::map<Zstring, IconHolder, LessFilename> NameIconMap; //entryName/icon -> note: Zstring is "thread-safe like an int"
typedef std::queue<Zstring> IconDbSequence; //entryName
class Buffer
@@ -421,11 +425,11 @@ public:
{
boost::lock_guard<boost::mutex> dummy(lockBuffer);
- auto iter = iconMappping.find(fileName);
- if (iter != iconMappping.end())
+ auto it = iconMappping.find(fileName);
+ if (it != iconMappping.end())
{
if (icon != nullptr)
- *icon = iter->second;
+ *icon = it->second;
return true;
}
return false;
diff --git a/lib/localization.cpp b/lib/localization.cpp
index 5792b3d1..47ed1881 100644
--- a/lib/localization.cpp
+++ b/lib/localization.cpp
@@ -35,21 +35,21 @@ public:
virtual std::wstring translate(const std::wstring& text)
{
//look for translation in buffer table
- const Translation::const_iterator iter = transMapping.find(text);
- if (iter != transMapping.end())
- return iter->second;
+ const Translation::const_iterator it = transMapping.find(text);
+ if (it != transMapping.end())
+ return it->second;
return text; //fallback
}
virtual std::wstring translate(const std::wstring& singular, const std::wstring& plural, int n)
{
- TranslationPlural::const_iterator iter = transMappingPl.find(std::make_pair(singular, plural));
- if (iter != transMappingPl.end())
+ TranslationPlural::const_iterator it = transMappingPl.find(std::make_pair(singular, plural));
+ if (it != transMappingPl.end())
{
const int formNo = pluralParser->getForm(n);
- if (0 <= formNo && formNo < static_cast<int>(iter->second.size()))
- return iter->second[formNo];
+ if (0 <= formNo && formNo < static_cast<int>(it->second.size()))
+ return it->second[formNo];
}
return n == 1 ? singular : plural; //fallback
}
@@ -72,7 +72,7 @@ FFSLocale::FFSLocale(const wxString& filename, wxLanguage languageId) : langId_(
{
inputStream = loadStream(filename); //throw XmlFileError
}
- catch (...)
+ catch (const XmlFileError&)
{
throw lngfile::ParsingError(0, 0);
}
@@ -378,10 +378,10 @@ void zen::setLanguage(int language) //throw FileError
//(try to) retrieve language file
wxString languageFile;
- for (auto iter = ExistingTranslations::get().begin(); iter != ExistingTranslations::get().end(); ++iter)
- if (iter->languageID == language)
+ for (auto it = ExistingTranslations::get().begin(); it != ExistingTranslations::get().end(); ++it)
+ if (it->languageID == language)
{
- languageFile = iter->languageFile;
+ languageFile = it->languageFile;
break;
}
@@ -397,8 +397,8 @@ void zen::setLanguage(int language) //throw FileError
{
throw FileError(replaceCpy(replaceCpy(replaceCpy(_("Error parsing file %x, row %y, column %z."),
L"%x", fmtFileName(toZ(languageFile))),
- L"%y", numberTo<std::wstring>(e.row)),
- L"%z", numberTo<std::wstring>(e.col)));
+ L"%y", numberTo<std::wstring>(e.row + 1)),
+ L"%z", numberTo<std::wstring>(e.col + 1)));
}
catch (PluralForm::ParsingError&)
{
diff --git a/lib/lock_holder.h b/lib/lock_holder.h
index 5ae2f8ae..dd997853 100644
--- a/lib/lock_holder.h
+++ b/lib/lock_holder.h
@@ -23,9 +23,9 @@ public:
std::vector<Zstring> dirs = dirnamesFmt;
vector_remove_if(dirs, [](const Zstring& dir) { return dir.empty(); });
- for (auto iter = dirs.begin(); iter != dirs.end(); ++iter)
+ for (auto it = dirs.begin(); it != dirs.end(); ++it)
{
- const Zstring& dirnameFmt = *iter;
+ const Zstring& dirnameFmt = *it;
if (!dirExistsUpdating(dirnameFmt, allowUserInteraction_, procCallback))
continue;
diff --git a/lib/parallel_scan.cpp b/lib/parallel_scan.cpp
index a31e30ee..94f6b0f4 100644
--- a/lib/parallel_scan.cpp
+++ b/lib/parallel_scan.cpp
@@ -138,30 +138,21 @@ Windows 7: Windows XP:
2 Threads: 42s | 11s 2 Threads: 38s | 8s
=> Traversing does not take any advantage of file locality so that even multiple threads operating on the same disk impose no performance overhead! (even faster on XP)
-*/
-
std::vector<std::set<DirectoryKey>> separateByDistinctDisk(const std::set<DirectoryKey>& dirkeys)
{
- //see perf note: use one thread per dirkey:
- typedef std::map<int, std::set<DirectoryKey>> DiskKeyMapping;
+ //use one thread per physical disk:
+ typedef std::map<DiskInfo, std::set<DirectoryKey>> DiskKeyMapping;
DiskKeyMapping tmp;
- int index = 0;
std::for_each(dirkeys.begin(), dirkeys.end(),
- [&](const DirectoryKey& key) { tmp[++index].insert(key); });
+ [&](const DirectoryKey& key) { tmp[retrieveDiskInfo(key.dirnameFull_)].insert(key); });
- /*
- //use one thread per physical disk:
- typedef std::map<DiskInfo, std::set<DirectoryKey>> DiskKeyMapping;
- DiskKeyMapping tmp;
- std::for_each(dirkeys.begin(), dirkeys.end(),
- [&](const DirectoryKey& key) { tmp[retrieveDiskInfo(key.dirnameFull_)].insert(key); });
- */
std::vector<std::set<DirectoryKey>> buckets;
std::transform(tmp.begin(), tmp.end(), std::back_inserter(buckets),
[&](const DiskKeyMapping::value_type& diskToKey) { return diskToKey.second; });
return buckets;
}
+*/
//------------------------------------------------------------------------------------------
typedef Zbase<wchar_t, StorageRefCountThreadSafe> BasicWString; //thread safe string class for UI texts
@@ -193,7 +184,7 @@ public:
errorResponse.reset();
dummy.unlock(); //optimization for condition_variable::notify_one()
- conditionCanReportError.notify_one();
+ conditionCanReportError.notify_all(); //instead of notify_one(); workaround bug: https://svn.boost.org/trac/boost/ticket/7796
return rv;
}
@@ -207,7 +198,7 @@ public:
errorResponse.reset(new FillBufferCallback::HandleError(rv));
dummy.unlock(); //optimization for condition_variable::notify_one()
- conditionGotResponse.notify_one();
+ conditionGotResponse.notify_all(); //instead of notify_one(); workaround bug: https://svn.boost.org/trac/boost/ticket/7796
}
}
@@ -470,57 +461,53 @@ private:
const std::wstring textApplyingDstHack;
};
#endif
-//------------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------------
class WorkerThread
{
public:
WorkerThread(size_t threadID,
const std::shared_ptr<AsyncCallback>& acb,
- const std::vector<std::pair<DirectoryKey, DirectoryValue*>>& workload) :
+ const DirectoryKey& dirKey,
+ DirectoryValue& dirOutput) :
threadID_(threadID),
acb_(acb),
- workload_(workload) {}
+ dirKey_(dirKey),
+ dirOutput_(dirOutput) {}
void operator()() //thread entry
{
acb_->incActiveWorker();
ZEN_ON_SCOPE_EXIT(acb_->decActiveWorker(););
- std::for_each(workload_.begin(), workload_.end(),
- [&](std::pair<DirectoryKey, DirectoryValue*>& item)
- {
- const Zstring& directoryName = item.first.dirnameFull_;
- DirectoryValue& dirVal = *item.second;
-
- acb_->reportCurrentFile(directoryName, threadID_); //just in case first directory access is blocking
+ acb_->reportCurrentFile(dirKey_.dirnameFull_, threadID_); //just in case first directory access is blocking
- TraverserShared travCfg(threadID_,
- item.first.handleSymlinks_, //shared by all(!) instances of DirCallback while traversing a folder hierarchy
- item.first.filter_,
- dirVal.failedReads,
- *acb_);
+ TraverserShared travCfg(threadID_,
+ dirKey_.handleSymlinks_, //shared by all(!) instances of DirCallback while traversing a folder hierarchy
+ dirKey_.filter_,
+ dirOutput_.failedReads,
+ *acb_);
- DirCallback traverser(travCfg,
- Zstring(),
- dirVal.dirCont);
+ DirCallback traverser(travCfg,
+ Zstring(),
+ dirOutput_.dirCont);
- DstHackCallback* dstCallbackPtr = nullptr;
+ DstHackCallback* dstCallbackPtr = nullptr;
#ifdef FFS_WIN
- DstHackCallbackImpl dstCallback(*acb_, threadID_);
- dstCallbackPtr = &dstCallback;
+ DstHackCallbackImpl dstCallback(*acb_, threadID_);
+ dstCallbackPtr = &dstCallback;
#endif
- //get all files and folders from directoryPostfixed (and subdirectories)
- traverseFolder(directoryName, traverser, dstCallbackPtr); //exceptions may be thrown!
- });
+ //get all files and folders from directoryPostfixed (and subdirectories)
+ traverseFolder(dirKey_.dirnameFull_, traverser, dstCallbackPtr); //exceptions may be thrown!
}
private:
size_t threadID_;
std::shared_ptr<AsyncCallback> acb_;
- std::vector<std::pair<DirectoryKey, DirectoryValue*>> workload_;
+ const DirectoryKey dirKey_;
+ DirectoryValue& dirOutput_;
};
}
@@ -532,13 +519,11 @@ void zen::fillBuffer(const std::set<DirectoryKey>& keysToRead, //in
{
buf.clear();
- std::vector<std::set<DirectoryKey>> buckets = separateByDistinctDisk(keysToRead); //one bucket per physical device
-
FixedList<boost::thread> worker; //note: we cannot use std::vector<boost::thread>: compiler error on GCC 4.7, probably a boost screw-up
zen::ScopeGuard guardWorker = zen::makeGuard([&]
{
- std::for_each(worker.begin(), worker.end(), [](boost::thread& wt) { wt.interrupt(); }); //interrupt all at once, then join
+ std::for_each(worker.begin(), worker.end(), [](boost::thread& wt) { wt.interrupt(); }); //interrupt all at once first, then join
std::for_each(worker.begin(), worker.end(), [](boost::thread& wt)
{
if (wt.joinable()) //= precondition of thread::join(), which throws an exception if violated!
@@ -549,28 +534,21 @@ void zen::fillBuffer(const std::set<DirectoryKey>& keysToRead, //in
std::shared_ptr<AsyncCallback> acb = std::make_shared<AsyncCallback>();
//init worker threads
- for (auto iter = buckets.begin(); iter != buckets.end(); ++iter)
+ std::for_each(keysToRead.begin(), keysToRead.end(),
+ [&](const DirectoryKey& key)
{
- const std::set<DirectoryKey>& bucket = *iter;
-
- std::vector<std::pair<DirectoryKey, DirectoryValue*>> workload;
- std::for_each(bucket.begin(), bucket.end(),
- [&](const DirectoryKey& key)
- {
- auto rv = buf.insert(std::make_pair(key, DirectoryValue()));
- assert(rv.second);
- workload.push_back(std::make_pair(key, &rv.first->second));
- });
+ assert(buf.find(key) == buf.end());
+ DirectoryValue& dirOutput = buf[key];
- const size_t threadId = iter - buckets.begin();
- worker.emplace_back(WorkerThread(threadId, acb, workload));
- }
+ const size_t threadId = worker.size();
+ worker.emplace_back(WorkerThread(threadId, acb, key, dirOutput));
+ });
//wait until done
size_t threadId = 0;
- for (auto iter = worker.begin(); iter != worker.end(); ++iter, ++threadId)
+ for (auto it = worker.begin(); it != worker.end(); ++it, ++threadId)
{
- boost::thread& wt = *iter;
+ boost::thread& wt = *it;
acb->setNotifyingThread(threadId); //process info messages of first (active) thread only
diff --git a/lib/parse_lng.h b/lib/parse_lng.h
index 5eb135a3..92564a1e 100644
--- a/lib/parse_lng.h
+++ b/lib/parse_lng.h
@@ -44,8 +44,8 @@ struct TransHeader
struct ParsingError
{
ParsingError(size_t rowNo, size_t colNo) : row(rowNo), col(colNo) {}
- size_t row;
- size_t col;
+ size_t row; //starting with 0
+ size_t col; //
};
void parseLng(const std::string& fileStream, TransHeader& header, TranslationMap& out, TranslationPluralMap& pluralOut); //throw ParsingError
void parseHeader(const std::string& fileStream, TransHeader& header); //throw ParsingError
@@ -104,11 +104,11 @@ public:
bool untranslatedTextExists() const
{
- for (std::list<RegularItem>::const_iterator i = dump.begin(); i != dump.end(); ++i)
- if (i->value.second.empty())
+ for (auto it = dump.begin(); it != dump.end(); ++it)
+ if (it->value.second.empty())
return true;
- for (std::list<PluralItem>::const_iterator i = dumpPlural.begin(); i != dumpPlural.end(); ++i)
- if (i->value.second.empty())
+ for (auto it = dumpPlural.begin(); it != dumpPlural.end(); ++it)
+ if (it->value.second.empty())
return true;
return false;
}
@@ -180,8 +180,8 @@ public:
static std::string text(Token::Type t)
{
- TokenMap::const_iterator iter = asList().find(t);
- return iter != asList().end() ? iter->second : std::string();
+ TokenMap::const_iterator it = asList().find(t);
+ return it != asList().end() ? it->second : std::string();
}
private:
@@ -198,8 +198,8 @@ private:
tokens.insert(std::make_pair(Token::TK_LOCALE_NAME_END, "</locale>"));
tokens.insert(std::make_pair(Token::TK_FLAG_FILE_BEGIN, "<flag file>"));
tokens.insert(std::make_pair(Token::TK_FLAG_FILE_END, "</flag file>"));
- tokens.insert(std::make_pair(Token::TK_PLURAL_COUNT_BEGIN, "<plural forms>"));
- tokens.insert(std::make_pair(Token::TK_PLURAL_COUNT_END, "</plural forms>"));
+ tokens.insert(std::make_pair(Token::TK_PLURAL_COUNT_BEGIN, "<plural forms>"));
+ tokens.insert(std::make_pair(Token::TK_PLURAL_COUNT_END, "</plural forms>"));
tokens.insert(std::make_pair(Token::TK_PLURAL_DEF_BEGIN, "<plural definition>"));
tokens.insert(std::make_pair(Token::TK_PLURAL_DEF_END, "</plural definition>"));
@@ -252,28 +252,42 @@ public:
return out;
}
- std::pair<size_t, size_t> position() const //current (row/col) beginning with 1
+ size_t posRow() const //current row beginning with 0
{
- //seek last line break
- std::string::const_iterator iter = pos;
- while (iter != stream.begin() && *iter != '\n')
- --iter;
+ //count line endings
+ size_t crSum = 0; //carriage returns
+ size_t nlSum = 0; //new lines
+ for (auto it = stream.begin(); it != pos; ++it)
+ if (*it == '\r')
+ ++crSum;
+ else if (*it == '\n')
+ ++nlSum;
+ assert(crSum == 0 || nlSum == 0 || crSum == nlSum);
+ return std::max(crSum, nlSum); //be compatible with Linux/Mac/Win
+ }
- return std::make_pair(std::count(stream.begin(), pos, '\n') + 1, pos - iter);
+ size_t posCol() const //current col beginning with 0
+ {
+ //seek beginning of line
+ for (auto it = pos; it != stream.begin(); )
+ {
+ --it;
+ if (*it == '\r' || *it == '\n')
+ return pos - it - 1;
+ }
+ return pos - stream.begin();
}
private:
bool startsWithKnownTag() const
{
- for (KnownTokens::TokenMap::const_iterator i = KnownTokens::asList().begin(); i != KnownTokens::asList().end(); ++i)
- if (startsWith(i->second))
- return true;
- return false;
+ return std::any_of(KnownTokens::asList().begin(), KnownTokens::asList().end(),
+ [&](const KnownTokens::TokenMap::value_type& p) { return startsWith(p.second); });
}
bool startsWith(const std::string& prefix) const
{
- if (stream.end() - pos < static_cast<int>(prefix.size()))
+ if (stream.end() - pos < static_cast<ptrdiff_t>(prefix.size()))
return false;
return std::equal(prefix.begin(), prefix.end(), pos);
}
@@ -420,7 +434,7 @@ private:
}
if (!pluralList.empty() && static_cast<int>(pluralList.size()) != formCount) //invalid number of plural forms
- throw ParsingError(scn.position().first, scn.position().second);
+ throw ParsingError(scn.posRow(), scn.posCol());
consumeToken(Token::TK_TRG_END);
@@ -435,7 +449,7 @@ private:
void consumeToken(Token::Type t)
{
if (token().type != t)
- throw ParsingError(scn.position().first, scn.position().second);
+ throw ParsingError(scn.posRow(), scn.posCol());
nextToken();
}
diff --git a/lib/parse_plural.h b/lib/parse_plural.h
index 2b78de89..7af6809e 100644
--- a/lib/parse_plural.h
+++ b/lib/parse_plural.h
@@ -152,6 +152,7 @@ private:
};
Token(Type t) : type(t), number(0) {}
+ Token(int num) : type(TK_CONST_NUMBER), number(num) {}
Type type;
int number; //if type == TK_CONST_NUMBER
@@ -195,13 +196,12 @@ private:
}
auto digitEnd = std::find_if(pos, stream.end(), [](char c) { return !zen::isDigit(c); });
- ptrdiff_t digitCount = digitEnd - pos;
- if (digitCount != 0)
+
+ if (digitEnd != pos)
{
- Token out(Token::TK_CONST_NUMBER);
- out.number = zen::stringTo<int>(std::string(&*pos, digitCount));
- pos += digitCount;
- return out;
+ int number = zen::stringTo<int>(std::string(&*pos, digitEnd - pos));
+ pos = digitEnd;
+ return number;
}
throw ParsingError(); //unknown token
diff --git a/lib/perf_check.cpp b/lib/perf_check.cpp
index 878b41a2..c6a4e2d1 100644
--- a/lib/perf_check.cpp
+++ b/lib/perf_check.cpp
@@ -15,8 +15,8 @@
using namespace zen;
-PerfCheck::PerfCheck(unsigned windowSizeRemainingTime,
- unsigned windowSizeBytesPerSecond) :
+PerfCheck::PerfCheck(unsigned int windowSizeRemainingTime,
+ unsigned int windowSizeBytesPerSecond) :
windowSizeRemTime(windowSizeRemainingTime),
windowSizeBPS(windowSizeBytesPerSecond),
windowMax(std::max(windowSizeRemainingTime, windowSizeBytesPerSecond)) {}
@@ -30,13 +30,13 @@ PerfCheck::~PerfCheck()
outputFile.Write(wxT("Time(ms);Objects;Data\n"));
- for (auto iter = samples.begin(); iter != samples.end(); ++iter)
+ for (auto it = samples.begin(); it != samples.end(); ++it)
{
- outputFile.Write(numberTo<wxString>(iter->first));
+ outputFile.Write(numberTo<wxString>(it->first));
outputFile.Write(wxT(";"));
- outputFile.Write(numberTo<wxString>(iter->second.objCount_));
+ outputFile.Write(numberTo<wxString>(it->second.objCount_));
outputFile.Write(wxT(";"));
- outputFile.Write(numberTo<wxString>(iter->second.data_));
+ outputFile.Write(numberTo<wxString>(it->second.data_));
outputFile.Write(wxT("\n"));
}
*/
@@ -108,6 +108,8 @@ wxString PerfCheck::getBytesPerSecond() const
wxString PerfCheck::getOverallBytesPerSecond() const //for all samples
{
+ warn_static("WTF!? tihs considers window only!")
+
if (!samples.empty())
{
const auto& recordBack = *samples.rbegin();
diff --git a/lib/perf_check.h b/lib/perf_check.h
index b8014582..b60c31c9 100644
--- a/lib/perf_check.h
+++ b/lib/perf_check.h
@@ -13,8 +13,8 @@
class PerfCheck
{
public:
- PerfCheck(unsigned windowSizeRemainingTime, //unit: [ms]
- unsigned windowSizeBytesPerSecond); //
+ PerfCheck(unsigned int windowSizeRemainingTime, //unit: [ms]
+ unsigned int windowSizeBytesPerSecond); //
~PerfCheck();
void addSample(int objectsCurrent, double dataCurrent, long timeMs); //timeMs must be ascending!
diff --git a/lib/process_xml.cpp b/lib/process_xml.cpp
index aed9c35f..a11f841c 100644
--- a/lib/process_xml.cpp
+++ b/lib/process_xml.cpp
@@ -93,7 +93,7 @@ void xmlAccess::OptionalDialogs::resetDialogs()
}
-xmlAccess::XmlGuiConfig xmlAccess::convertBatchToGui(const xmlAccess::XmlBatchConfig& batchCfg)
+xmlAccess::XmlGuiConfig xmlAccess::convertBatchToGui(const xmlAccess::XmlBatchConfig& batchCfg) //noexcept
{
XmlGuiConfig output;
output.mainCfg = batchCfg.mainCfg;
@@ -112,9 +112,10 @@ xmlAccess::XmlGuiConfig xmlAccess::convertBatchToGui(const xmlAccess::XmlBatchCo
}
-xmlAccess::XmlBatchConfig xmlAccess::convertGuiToBatch(const xmlAccess::XmlGuiConfig& guiCfg, const Zstring& referenceFile)
+xmlAccess::XmlBatchConfig xmlAccess::convertGuiToBatch(const xmlAccess::XmlGuiConfig& guiCfg) //noexcept
{
XmlBatchConfig output; //use default batch-settings
+ output.mainCfg = guiCfg.mainCfg;
switch (guiCfg.handleError)
{
@@ -125,19 +126,25 @@ xmlAccess::XmlBatchConfig xmlAccess::convertGuiToBatch(const xmlAccess::XmlGuiCo
output.handleError = ON_ERROR_IGNORE;
break;
}
+ return output;
+}
+
- //try to take over batch-specific settings from reference
- if (!referenceFile.empty() && getXmlType(referenceFile) == XML_TYPE_BATCH)
+xmlAccess::XmlBatchConfig xmlAccess::convertGuiToBatchPreservingExistingBatch(const xmlAccess::XmlGuiConfig& guiCfg, const Zstring& referenceBatchFile) //noexcept
+{
+ //try to take over batch-specific settings from reference file if possible
+ if (!referenceBatchFile.empty())
try
{
- std::vector<Zstring> filenames;
- filenames.push_back(referenceFile);
- mergeConfigs(filenames, output); //throw xmlAccess::FfsXmlError
+ XmlBatchConfig batchCfg;
+ readConfig(referenceBatchFile, batchCfg); //throw FfsXmlError
+
+ batchCfg.mainCfg = guiCfg.mainCfg;
+ return batchCfg;
}
catch (xmlAccess::FfsXmlError&) {}
- output.mainCfg = guiCfg.mainCfg;
- return output;
+ return convertGuiToBatch(guiCfg);
}
@@ -146,9 +153,9 @@ xmlAccess::MergeType xmlAccess::getMergeType(const std::vector<Zstring>& filenam
bool guiCfgExists = false;
bool batchCfgExists = false;
- for (auto iter = filenames.begin(); iter != filenames.end(); ++iter)
+ for (auto it = filenames.begin(); it != filenames.end(); ++it)
{
- switch (xmlAccess::getXmlType(*iter)) //throw()
+ switch (xmlAccess::getXmlType(*it)) //throw()
{
case XML_TYPE_GUI:
guiCfgExists = true;
@@ -164,59 +171,60 @@ xmlAccess::MergeType xmlAccess::getMergeType(const std::vector<Zstring>& filenam
}
}
- if (guiCfgExists && batchCfgExists)
- return MERGE_GUI_BATCH;
- else if (guiCfgExists && !batchCfgExists)
- return MERGE_GUI;
- else if (!guiCfgExists && batchCfgExists)
- return MERGE_BATCH;
+ if (guiCfgExists)
+ return batchCfgExists ? MERGE_GUI_BATCH : MERGE_GUI;
else
- return MERGE_OTHER;
+ return batchCfgExists ? MERGE_BATCH : MERGE_OTHER;
}
namespace
{
template <class XmlCfg>
-XmlCfg loadCfgImpl(const Zstring& filename, std::unique_ptr<xmlAccess::FfsXmlError>& warning) //throw xmlAccess::FfsXmlError
+XmlCfg readConfigNoWarnings(const Zstring& filename, std::unique_ptr<FfsXmlError>& warning) //throw FfsXmlError, but only if "FATAL"
{
XmlCfg cfg;
try
{
- xmlAccess::readConfig(filename, cfg); //throw xmlAccess::FfsXmlError
+ readConfig(filename, cfg); //throw xmlAccess::FfsXmlError
}
- catch (const xmlAccess::FfsXmlError& e)
+ catch (const FfsXmlError& e)
{
- if (e.getSeverity() == xmlAccess::FfsXmlError::FATAL)
+ if (e.getSeverity() == FfsXmlError::FATAL)
throw;
- else
- warning.reset(new xmlAccess::FfsXmlError(e));
+ else if (!warning.get()) warning = make_unique<FfsXmlError>(e);
}
return cfg;
}
+}
-template <class XmlCfg>
-void mergeConfigFilesImpl(const std::vector<Zstring>& filenames, XmlCfg& config) //throw xmlAccess::FfsXmlError
+void xmlAccess::readAnyConfig(const std::vector<Zstring>& filenames, XmlGuiConfig& config) //throw FfsXmlError
{
assert(!filenames.empty());
- if (filenames.empty())
- return;
std::vector<zen::MainConfiguration> mainCfgs;
std::unique_ptr<FfsXmlError> savedWarning;
- std::for_each(filenames.begin(), filenames.end(),
- [&](const Zstring& filename)
+ for (auto it = filenames.begin(); it != filenames.end(); ++it)
{
+ const Zstring& filename = *it;
+ const bool firstLine = it == filenames.begin(); //init all non-"mainCfg" settings with first config file
+
switch (getXmlType(filename))
{
case XML_TYPE_GUI:
- mainCfgs.push_back(loadCfgImpl<XmlGuiConfig>(filename, savedWarning).mainCfg); //throw xmlAccess::FfsXmlError
+ if (firstLine)
+ config = readConfigNoWarnings<XmlGuiConfig>(filename, savedWarning);
+ else
+ mainCfgs.push_back(readConfigNoWarnings<XmlGuiConfig>(filename, savedWarning).mainCfg); //throw FfsXmlError
break;
case XML_TYPE_BATCH:
- mainCfgs.push_back(loadCfgImpl<XmlBatchConfig>(filename, savedWarning).mainCfg); //throw xmlAccess::FfsXmlError
+ if (firstLine)
+ config = convertBatchToGui(readConfigNoWarnings<XmlBatchConfig>(filename, savedWarning));
+ else
+ mainCfgs.push_back(readConfigNoWarnings<XmlBatchConfig>(filename, savedWarning).mainCfg); //throw FfsXmlError
break;
case XML_TYPE_GLOBAL:
@@ -226,32 +234,14 @@ void mergeConfigFilesImpl(const std::vector<Zstring>& filenames, XmlCfg& config)
else
throw FfsXmlError(replaceCpy(_("File %x does not contain a valid configuration."), L"%x", fmtFileName(filename)));
}
- });
-
- try //...to init all non-"mainCfg" settings with first config file
- {
- xmlAccess::readConfig(filenames[0], config); //throw xmlAccess::FfsXmlError
}
- catch (xmlAccess::FfsXmlError&) {}
+ mainCfgs.push_back(config.mainCfg); //save cfg from first line
config.mainCfg = merge(mainCfgs);
if (savedWarning.get()) //"re-throw" exception
throw* savedWarning;
}
-}
-
-
-void xmlAccess::mergeConfigs(const std::vector<Zstring>& filenames, XmlGuiConfig& config) //throw FfsXmlError
-{
- mergeConfigFilesImpl(filenames, config); //throw FfsXmlError
-}
-
-
-void xmlAccess::mergeConfigs(const std::vector<Zstring>& filenames, XmlBatchConfig& config) //throw FfsXmlError
-{
- mergeConfigFilesImpl(filenames, config); //throw FfsXmlError
-}
namespace zen
@@ -662,6 +652,35 @@ bool readText(const std::string& input, UnitSize& value)
template <> inline
+void writeText(const VersioningStyle& value, std::string& output)
+{
+ switch (value)
+ {
+ case VER_STYLE_REPLACE:
+ output = "Replace";
+ break;
+ case VER_STYLE_ADD_TIMESTAMP:
+ output = "AddTimeStamp";
+ break;
+ }
+}
+
+template <> inline
+bool readText(const std::string& input, VersioningStyle& value)
+{
+ std::string tmp = input;
+ zen::trim(tmp);
+ if (tmp == "Replace")
+ value = VER_STYLE_REPLACE;
+ else if (tmp == "AddTimeStamp")
+ value = VER_STYLE_ADD_TIMESTAMP;
+ else
+ return false;
+ return true;
+}
+
+
+template <> inline
void writeText(const DirectionConfig::Variant& value, std::string& output)
{
switch (value)
@@ -776,15 +795,14 @@ void readConfig(const XmlIn& in, SyncConfig& syncCfg)
warn_static("remove after migration?")
if (in["CustomDeletionFolder"])
- {
in["CustomDeletionFolder"](syncCfg.versioningDirectory);//obsolete name
- syncCfg.versionCountLimit = -1; //new parameter
- }
else
- {
in["VersioningFolder"](syncCfg.versioningDirectory);
- in["VersioningFolder"].attribute("Limit", syncCfg.versionCountLimit);
- }
+ warn_static("remove after migration?")
+ if (in["VersioningStyle"]) //new parameter
+ in["VersioningStyle"](syncCfg.versioningStyle);
+ else
+ syncCfg.versioningStyle = VER_STYLE_ADD_TIMESTAMP; //obsolete fallback
}
@@ -893,12 +911,14 @@ void readConfig(const XmlIn& in, xmlAccess::XmlGuiConfig& config)
warn_static("remove after migration?")
if (inGuiCfg["HideFiltered" ]) //obsolete name
+ inGuiCfg["HideFiltered" ](config.hideExcludedItems);
+ else if (inGuiCfg["ShowFiltered" ]) //obsolete name
{
- inGuiCfg["HideFiltered" ](config.showFilteredElements);
- config.showFilteredElements = !config.showFilteredElements;
+ inGuiCfg["ShowFiltered"](config.hideExcludedItems);
+ config.hideExcludedItems = !config.hideExcludedItems;
}
else
- inGuiCfg["ShowFiltered"](config.showFilteredElements);
+ inGuiCfg["HideExcluded"](config.hideExcludedItems);
inGuiCfg["HandleError" ](config.handleError);
inGuiCfg["SyncPreviewActive"](config.showSyncAction);
@@ -1035,12 +1055,12 @@ void readConfig(const XmlIn& in, XmlGlobalSettings& config)
warn_static("remove after migration?")
//convert new internal macro naming convention: %name -> %item_path%; %dir -> %item_folder%
- for (auto iter = config.gui.externelApplications.begin(); iter != config.gui.externelApplications.end(); ++iter)
+ for (auto it = config.gui.externelApplications.begin(); it != config.gui.externelApplications.end(); ++it)
{
- replace(iter->second, L"%nameCo", L"%item2_path%"); //unambiguous "Co" names first
- replace(iter->second, L"%dirCo" , L"%item2_folder%");
- replace(iter->second, L"%name" , L"%item_path%");
- replace(iter->second, L"%dir" , L"%item_folder%");
+ replace(it->second, L"%nameCo", L"%item2_path%"); //unambiguous "Co" names first
+ replace(it->second, L"%dirCo" , L"%item2_folder%");
+ replace(it->second, L"%name" , L"%item_path%");
+ replace(it->second, L"%dir" , L"%item_folder%");
}
@@ -1056,7 +1076,7 @@ template <class ConfigType>
void readConfig(const Zstring& filename, XmlType type, ConfigType& config)
{
XmlDoc doc;
- loadXmlDocument(filename, doc); //throw FfsXmlError
+ loadXmlDocument(filename, doc); //throw FfsXmlError
if (getXmlType(doc) != type) //throw()
throw FfsXmlError(replaceCpy(_("File %x does not contain a valid configuration."), L"%x", fmtFileName(filename)));
@@ -1119,7 +1139,8 @@ void writeConfig(const SyncConfig& syncCfg, XmlOut& out)
out["DeletionPolicy" ](syncCfg.handleDeletion);
out["VersioningFolder"](syncCfg.versioningDirectory);
- out["VersioningFolder"].attribute("Limit", syncCfg.versionCountLimit);
+ //out["VersioningFolder"].attribute("Limit", syncCfg.versionCountLimit);
+ out["VersioningStyle"](syncCfg.versioningStyle);
}
@@ -1213,7 +1234,7 @@ void writeConfig(const XmlGuiConfig& config, XmlOut& out)
//write GUI specific config data
XmlOut outGuiCfg = out["GuiConfig"];
- outGuiCfg["ShowFiltered" ](config.showFilteredElements);
+ outGuiCfg["HideExcluded" ](config.hideExcludedItems);
outGuiCfg["HandleError" ](config.handleError);
outGuiCfg["SyncPreviewActive"](config.showSyncAction);
}
diff --git a/lib/process_xml.h b/lib/process_xml.h
index 8d1d4538..29237081 100644
--- a/lib/process_xml.h
+++ b/lib/process_xml.h
@@ -48,13 +48,13 @@ typedef std::vector<std::pair<Description, Commandline> > ExternalApps;
struct XmlGuiConfig
{
XmlGuiConfig() :
- showFilteredElements(true),
+ hideExcludedItems(false),
handleError(ON_GUIERROR_POPUP),
showSyncAction(true) {} //initialize values
zen::MainConfiguration mainCfg;
- bool showFilteredElements;
+ bool hideExcludedItems;
OnGuiError handleError; //reaction on error situation during synchronization
bool showSyncAction;
};
@@ -63,10 +63,10 @@ struct XmlGuiConfig
inline
bool operator==(const XmlGuiConfig& lhs, const XmlGuiConfig& rhs)
{
- return lhs.mainCfg == rhs.mainCfg &&
- lhs.showFilteredElements == rhs.showFilteredElements &&
- lhs.handleError == rhs.handleError &&
- lhs.showSyncAction == rhs.showSyncAction;
+ return lhs.mainCfg == rhs.mainCfg &&
+ lhs.hideExcludedItems == rhs.hideExcludedItems &&
+ lhs.handleError == rhs.handleError &&
+ lhs.showSyncAction == rhs.showSyncAction;
}
@@ -232,6 +232,7 @@ struct XmlGlobalSettings
//struct Batch
};
+//read/write specific config types
void readConfig(const Zstring& filename, XmlGuiConfig& config); //
void readConfig(const Zstring& filename, XmlBatchConfig& config); //throw FfsXmlError
void readConfig( XmlGlobalSettings& config); //
@@ -240,11 +241,6 @@ void writeConfig(const XmlGuiConfig& config, const Zstring& filename); //
void writeConfig(const XmlBatchConfig& config, const Zstring& filename); //throw FfsXmlError
void writeConfig(const XmlGlobalSettings& config); //
-//config conversion utilities
-XmlGuiConfig convertBatchToGui(const XmlBatchConfig& batchCfg);
-XmlBatchConfig convertGuiToBatch(const XmlGuiConfig& guiCfg, const Zstring& referenceFile);
-
-
//convert (multiple) *.ffs_gui, *.ffs_batch files or combinations of both into target config structure:
enum MergeType
{
@@ -253,10 +249,14 @@ enum MergeType
MERGE_GUI_BATCH, //gui and batch files
MERGE_OTHER
};
-MergeType getMergeType(const std::vector<Zstring>& filenames); //throw ()
+MergeType getMergeType(const std::vector<Zstring>& filenames); //noexcept
-void mergeConfigs(const std::vector<Zstring>& filenames, XmlGuiConfig& config); //throw xmlAccess::FfsXmlError
-void mergeConfigs(const std::vector<Zstring>& filenames, XmlBatchConfig& config); //throw xmlAccess::FfsXmlError
+void readAnyConfig(const std::vector<Zstring>& filenames, XmlGuiConfig& config); //throw FfsXmlError
+
+//config conversion utilities
+XmlGuiConfig convertBatchToGui(const XmlBatchConfig& batchCfg); //noexcept
+XmlBatchConfig convertGuiToBatch(const XmlGuiConfig& guiCfg ); //
+XmlBatchConfig convertGuiToBatchPreservingExistingBatch(const xmlAccess::XmlGuiConfig& guiCfg, const Zstring& referenceBatchFile); //noexcept
std::wstring extractJobName(const Zstring& configFilename);
}
diff --git a/lib/resolve_path.cpp b/lib/resolve_path.cpp
index 248e3507..9c690c9a 100644
--- a/lib/resolve_path.cpp
+++ b/lib/resolve_path.cpp
@@ -212,6 +212,9 @@ std::unique_ptr<Zstring> resolveMacro(const Zstring& macro, //macro without %-ch
if (equalNoCase(macro, Zstr("date")))
return make_unique<Zstring>(formatTime<Zstring>(FORMAT_ISO_DATE));
+ if (equalNoCase(macro, Zstr("timestamp")))
+ return make_unique<Zstring>(formatTime<Zstring>(Zstr("%Y-%m-%d %H%M%S"))); //e.g. "2012-05-15 131513"
+
std::unique_ptr<Zstring> cand;
auto processPhrase = [&](const Zchar* phrase, const Zchar* format) -> bool
{
@@ -224,7 +227,7 @@ std::unique_ptr<Zstring> resolveMacro(const Zstring& macro, //macro without %-ch
if (processPhrase(Zstr("weekday"), Zstr("%A"))) return cand;
if (processPhrase(Zstr("day" ), Zstr("%d"))) return cand;
- if (processPhrase(Zstr("month" ), Zstr("%B"))) return cand;
+ if (processPhrase(Zstr("month" ), Zstr("%m"))) return cand;
if (processPhrase(Zstr("week" ), Zstr("%U"))) return cand;
if (processPhrase(Zstr("year" ), Zstr("%Y"))) return cand;
if (processPhrase(Zstr("hour" ), Zstr("%H"))) return cand;
@@ -233,9 +236,9 @@ std::unique_ptr<Zstring> resolveMacro(const Zstring& macro, //macro without %-ch
//check domain-specific extensions
{
- auto iter = std::find_if(ext.begin(), ext.end(), [&](const std::pair<Zstring, Zstring>& p) { return equalNoCase(macro, p.first); });
- if (iter != ext.end())
- return make_unique<Zstring>(iter->second);
+ auto it = std::find_if(ext.begin(), ext.end(), [&](const std::pair<Zstring, Zstring>& p) { return equalNoCase(macro, p.first); });
+ if (it != ext.end())
+ return make_unique<Zstring>(it->second);
}
//try to resolve as environment variable
@@ -246,9 +249,9 @@ std::unique_ptr<Zstring> resolveMacro(const Zstring& macro, //macro without %-ch
//try to resolve as CSIDL value
{
const auto& csidlMap = CsidlConstants::get();
- auto iter = csidlMap.find(macro);
- if (iter != csidlMap.end())
- return make_unique<Zstring>(iter->second);
+ auto it = csidlMap.find(macro);
+ if (it != csidlMap.end())
+ return make_unique<Zstring>(it->second);
}
#endif
@@ -325,9 +328,9 @@ Zstring getPathByVolumenName(const Zstring& volumeName) //return empty string on
//search for matching path in parallel until first hit
RunUntilFirstHit<Zstring> findFirstMatch;
- for (const wchar_t* iter = &buffer[0]; *iter != 0; iter += strLength(iter) + 1) //list terminated by empty c-string
+ for (const wchar_t* it = &buffer[0]; *it != 0; it += strLength(it) + 1) //list terminated by empty c-string
{
- const Zstring path = iter;
+ const Zstring path = it;
findFirstMatch.addJob([path, volumeName]() -> std::unique_ptr<Zstring>
{
@@ -364,9 +367,9 @@ Zstring getPathByVolumenName(const Zstring& volumeName) //return empty string on
TraverseMedia traverser(deviceList);
traverseFolder("/media", traverser); //traverse one level
- TraverseMedia::DeviceList::const_iterator iter = deviceList.find(volumeName);
- if (iter != deviceList.end())
- return iter->second;
+ TraverseMedia::DeviceList::const_iterator it = deviceList.find(volumeName);
+ if (it != deviceList.end())
+ return it->second;
#endif
return Zstring();
}
diff --git a/lib/resources.cpp b/lib/resources.cpp
index 6d586e54..7d46739e 100644
--- a/lib/resources.cpp
+++ b/lib/resources.cpp
@@ -86,11 +86,11 @@ GlobalResources::GlobalResources()
const wxBitmap& GlobalResources::getImageInt(const wxString& imageName) const
{
- auto iter = bitmaps.find(!contains(imageName, L'.') ? //assume .png ending if nothing else specified
+ auto it = bitmaps.find(!contains(imageName, L'.') ? //assume .png ending if nothing else specified
imageName + L".png" :
imageName);
- if (iter != bitmaps.end())
- return iter->second;
+ if (it != bitmaps.end())
+ return it->second;
else
{
assert(false);
diff --git a/lib/shadow.cpp b/lib/shadow.cpp
index 8ef86f30..6dae97b1 100644
--- a/lib/shadow.cpp
+++ b/lib/shadow.cpp
@@ -108,13 +108,13 @@ Zstring ShadowCopy::makeShadowCopy(const Zstring& inputFile)
}
//get or create instance of shadow volume
- VolNameShadowMap::const_iterator iter = shadowVol.find(volumeNamePf);
- if (iter == shadowVol.end())
+ VolNameShadowMap::const_iterator it = shadowVol.find(volumeNamePf);
+ if (it == shadowVol.end())
{
auto newEntry = std::make_shared<ShadowVolume>(volumeNamePf);
- iter = shadowVol.insert(std::make_pair(volumeNamePf, newEntry)).first;
+ it = shadowVol.insert(std::make_pair(volumeNamePf, newEntry)).first;
}
//return filename alias on shadow copy volume
- return iter->second->geNamePf() + Zstring(inputFile.c_str() + pos + volumeNamePf.length());
+ return it->second->geNamePf() + Zstring(inputFile.c_str() + pos + volumeNamePf.length());
}
diff --git a/lib/versioning.cpp b/lib/versioning.cpp
index b12d7307..d4b6e2b2 100644
--- a/lib/versioning.cpp
+++ b/lib/versioning.cpp
@@ -20,14 +20,14 @@ Zstring getExtension(const Zstring& relativeName) //including "." if extension i
bool impl::isMatchingVersion(const Zstring& shortname, const Zstring& shortnameVersion) //e.g. ("Sample.txt", "Sample.txt 2012-05-15 131513.txt")
{
- auto iter = shortnameVersion.begin();
+ auto it = shortnameVersion.begin();
auto last = shortnameVersion.end();
auto nextDigit = [&]() -> bool
{
- if (iter == last || !isDigit(*iter))
+ if (it == last || !isDigit(*it))
return false;
- ++iter;
+ ++it;
return true;
};
auto nextDigits = [&](size_t count) -> bool
@@ -39,16 +39,16 @@ bool impl::isMatchingVersion(const Zstring& shortname, const Zstring& shortnameV
};
auto nextChar = [&](Zchar c) -> bool
{
- if (iter == last || *iter != c)
+ if (it == last || *it != c)
return false;
- ++iter;
+ ++it;
return true;
};
auto nextStringI = [&](const Zstring& str) -> bool //windows: ignore case!
{
- if (last - iter < static_cast<ptrdiff_t>(str.size()) || !EqualFilename()(str, Zstring(&*iter, str.size())))
+ if (last - it < static_cast<ptrdiff_t>(str.size()) || !EqualFilename()(str, Zstring(&*it, str.size())))
return false;
- iter += str.size();
+ it += str.size();
return true;
};
@@ -62,25 +62,41 @@ bool impl::isMatchingVersion(const Zstring& shortname, const Zstring& shortnameV
nextChar(Zstr(' ')) && //
nextDigits(6) && //HHMMSS
nextStringI(getExtension(shortname)) &&
- iter == last;
+ it == last;
}
namespace
{
+/*
+- handle not existing source
+- create target super directories if missing
+*/
template <class Function>
void moveItemToVersioning(const Zstring& sourceObj, //throw FileError
const Zstring& relativeName,
const Zstring& versioningDirectory,
const Zstring& timestamp,
- Function moveObj) //move source -> target; allowed to throw FileError
+ VersioningStyle versioningStyle,
+ Function moveObj) //move source -> target; may throw FileError
{
assert(!startsWith(relativeName, FILE_NAME_SEPARATOR));
+ assert(!endsWith (relativeName, FILE_NAME_SEPARATOR));
assert(endsWith(sourceObj, relativeName)); //usually, yes, but we might relax this in the future
- //assemble time-stamped version name
- const Zstring targetObj = appendSeparator(versioningDirectory) + relativeName + Zstr(' ') + timestamp + getExtension(relativeName);
- assert(impl::isMatchingVersion(afterLast(relativeName, FILE_NAME_SEPARATOR), afterLast(targetObj, FILE_NAME_SEPARATOR))); //paranoid? no!
+ Zstring targetObj;
+ switch (versioningStyle)
+ {
+ case VER_STYLE_REPLACE:
+ targetObj = appendSeparator(versioningDirectory) + relativeName;
+ break;
+
+ case VER_STYLE_ADD_TIMESTAMP:
+ //assemble time-stamped version name
+ targetObj = appendSeparator(versioningDirectory) + relativeName + Zstr(' ') + timestamp + getExtension(relativeName);
+ assert(impl::isMatchingVersion(afterLast(relativeName, FILE_NAME_SEPARATOR), afterLast(targetObj, FILE_NAME_SEPARATOR))); //paranoid? no!
+ break;
+ }
try
{
@@ -104,11 +120,18 @@ void moveItemToVersioning(const Zstring& sourceObj, //throw FileError
}
-//move source to target across volumes; prerequisite: all super-directories of target exist
-//if target already contains some files/dirs they are seen as remnants of a previous incomplete move
-void moveFile(const Zstring& sourceFile, const Zstring& targetFile, CallbackCopyFile& callback) //throw FileError
+//move source to target across volumes
+//no need to check if: - super-directories of target exist - source exists
+//if target already exists, it is overwritten, even if it is a different type, e.g. a directory!
+template <class Function>
+void moveObject(const Zstring& sourceFile, //throw FileError
+ const Zstring& targetFile,
+ Function copyDelete) //fallback if move failed; may throw FileError
{
+ assert(!dirExists(sourceFile) || symlinkExists(sourceFile)); //we process files and symlinks only
+
//first try to move directly without copying
+ bool targetExisting = false;
try
{
renameFile(sourceFile, targetFile); //throw FileError, ErrorDifferentVolume, ErrorTargetExisting
@@ -116,59 +139,59 @@ void moveFile(const Zstring& sourceFile, const Zstring& targetFile, CallbackCopy
}
//if moving failed treat as error (except when it tried to move to a different volume: in this case we will copy the file)
catch (const ErrorDifferentVolume&) {}
- catch (const ErrorTargetExisting&) {}
+ catch (const ErrorTargetExisting&) { targetExisting = true; }
- //create target
- if (!fileExists(targetFile)) //check even if ErrorTargetExisting: me may have clashed with another item type of the same name!!!
+ if (!targetExisting)
+ targetExisting = somethingExists(targetFile);
+
+ //remove target object
+ if (targetExisting)
+ {
+ if (fileExists(targetFile)) //file or symlink
+ removeFile(targetFile); //throw FileError
+ else if (dirExists(targetFile)) //directory or symlink
+ removeDirectory(targetFile); //throw FileError
+ //we do not expect targetFile to be a directory in general => no callback required
+ else assert(false);
+ }
+
+ copyDelete();
+}
+
+
+void moveFile(const Zstring& sourceFile, const Zstring& targetFile, CallbackCopyFile& callback) //throw FileError
+{
+ moveObject(sourceFile, //throw FileError
+ targetFile,
+ [&]
{
- //file is on a different volume: let's copy it
+ //create target
if (symlinkExists(sourceFile))
copySymlink(sourceFile, targetFile, false); //throw FileError; don't copy filesystem permissions
else
copyFile(sourceFile, targetFile, false, true, &callback); //throw FileError - permissions "false", transactional copy "true"
- }
- //delete source
- removeFile(sourceFile); //throw FileError; newly copied file is NOT deleted if exception is thrown here!
+ //delete source
+ removeFile(sourceFile); //throw FileError; newly copied file is NOT deleted if exception is thrown here!
+ });
}
void moveDirSymlink(const Zstring& sourceLink, const Zstring& targetLink) //throw FileError
{
- //first try to move directly without copying
- try
+ moveObject(sourceLink, //throw FileError
+ targetLink,
+ [&]
{
- renameFile(sourceLink, targetLink); //throw FileError, ErrorDifferentVolume, ErrorTargetExisting
- return; //great, we get away cheaply!
- }
- //if moving failed treat as error (except when it tried to move to a different volume: in this case we will copy the file)
- catch (const ErrorDifferentVolume&) {}
- catch (const ErrorTargetExisting&) {}
-
- //create target
- if (!symlinkExists(targetLink)) //check even if ErrorTargetExisting: me may have clashed with another item type of the same name!!!
- {
- //link is on a different volume: let's copy it
+ //create target
copySymlink(sourceLink, targetLink, false); //throw FileError; don't copy filesystem permissions
- }
- //delete source
- removeDirectory(sourceLink); //throw FileError; newly copied link is NOT deleted if exception is thrown here!
+ //delete source
+ removeDirectory(sourceLink); //throw FileError; newly copied link is NOT deleted if exception is thrown here!
+ });
}
-struct CopyCallbackImpl : public CallbackCopyFile
-{
- CopyCallbackImpl(CallbackMoveFile& callback) : callback_(callback) {}
-
-private:
- virtual void deleteTargetFile(const Zstring& targetFile) { assert(!somethingExists(targetFile)); }
- virtual void updateCopyStatus(Int64 bytesDelta) { callback_.updateStatus(bytesDelta); }
-
- CallbackMoveFile& callback_;
-};
-
-
class TraverseFilesOneLevel : public TraverseCallback
{
public:
@@ -200,18 +223,6 @@ private:
std::vector<Zstring>& files_;
std::vector<Zstring>& dirs_;
};
-
-
-struct RemoveCallbackImpl : public CallbackRemoveDir
-{
- RemoveCallbackImpl(CallbackMoveFile& callback) : callback_(callback) {}
-
-private:
- virtual void notifyFileDeletion(const Zstring& filename) { callback_.updateStatus(0); }
- virtual void notifyDirDeletion (const Zstring& dirname ) { callback_.updateStatus(0); }
-
- CallbackMoveFile& callback_;
-};
}
@@ -221,25 +232,29 @@ void FileVersioner::revisionFile(const Zstring& sourceFile, const Zstring& relat
relativeName,
versioningDirectory_,
timeStamp_,
+ versioningStyle_,
[&](const Zstring& source, const Zstring& target)
{
- callback.onBeforeFileMove(source, target);
+ struct CopyCallbackImpl : public CallbackCopyFile
+ {
+ CopyCallbackImpl(CallbackMoveFile& callback) : callback_(callback) {}
+ private:
+ virtual void deleteTargetFile(const Zstring& targetFile) { assert(!somethingExists(targetFile)); }
+ virtual void updateCopyStatus(Int64 bytesDelta) { callback_.updateStatus(bytesDelta); }
+ CallbackMoveFile& callback_;
+ } copyCallback(callback);
- CopyCallbackImpl copyCallback(callback);
+ callback.onBeforeFileMove(source, target);
moveFile(source, target, copyCallback); //throw FileError
callback.objectProcessed();
});
- fileRelNames.push_back(relativeName);
+ //fileRelNames.push_back(relativeName);
}
void FileVersioner::revisionDir(const Zstring& sourceDir, const Zstring& relativeName, CallbackMoveFile& callback) //throw FileError
{
- //note: we cannot support "throw exception if target already exists": If we did, we would have to do a full cleanup
- //removing all newly created directories in case of an exception so that subsequent tries would not fail with "target already existing".
- //However an exception may also happen during final deletion of source folder, in which case cleanup effectively leads to data loss!
-
//create target
if (symlinkExists(sourceDir)) //on Linux there is just one type of symlinks, and since we do revision file symlinks, we should revision dir symlinks as well!
{
@@ -247,6 +262,7 @@ void FileVersioner::revisionDir(const Zstring& sourceDir, const Zstring& relativ
relativeName,
versioningDirectory_,
timeStamp_,
+ versioningStyle_,
[&](const Zstring& source, const Zstring& target)
{
callback.onBeforeDirMove(source, target);
@@ -254,12 +270,12 @@ void FileVersioner::revisionDir(const Zstring& sourceDir, const Zstring& relativ
callback.objectProcessed();
});
- fileRelNames.push_back(relativeName);
+ //fileRelNames.push_back(relativeName);
}
else
{
assert(!startsWith(relativeName, FILE_NAME_SEPARATOR));
- assert(endsWith(sourceDir, relativeName));
+ assert(endsWith(sourceDir, relativeName)); //usually, yes, but we might relax this in the future
const Zstring targetDir = appendSeparator(versioningDirectory_) + relativeName;
callback.onBeforeDirMove(sourceDir, targetDir);
@@ -272,7 +288,7 @@ void FileVersioner::revisionDir(const Zstring& sourceDir, const Zstring& relativ
try
{
TraverseFilesOneLevel tol(fileList, dirList); //throw FileError
- traverseFolder(sourceDir, tol); //
+ traverseFolder(sourceDir, tol); //
}
catch (FileError&)
{
@@ -293,7 +309,7 @@ void FileVersioner::revisionDir(const Zstring& sourceDir, const Zstring& relativ
callback);
});
- //move directories
+ //move items in subdirectories
std::for_each(dirList.begin(), dirList.end(),
[&](const Zstring& shortname)
{
@@ -303,7 +319,15 @@ void FileVersioner::revisionDir(const Zstring& sourceDir, const Zstring& relativ
});
//delete source
- RemoveCallbackImpl removeCallback(callback);
+ struct RemoveCallbackImpl : public CallbackRemoveDir
+ {
+ RemoveCallbackImpl(CallbackMoveFile& callback) : callback_(callback) {}
+ private:
+ virtual void notifyFileDeletion(const Zstring& filename) { callback_.updateStatus(0); }
+ virtual void notifyDirDeletion (const Zstring& dirname ) { callback_.updateStatus(0); }
+ CallbackMoveFile& callback_;
+ } removeCallback(callback);
+
removeDirectory(sourceDir, &removeCallback); //throw FileError
callback.objectProcessed();
@@ -311,6 +335,7 @@ void FileVersioner::revisionDir(const Zstring& sourceDir, const Zstring& relativ
}
+/*
namespace
{
class TraverseVersionsOneLevel : public TraverseCallback
@@ -329,7 +354,6 @@ private:
};
}
-
void FileVersioner::limitVersions(std::function<void()> updateUI) //throw FileError
{
if (versionCountLimit_ < 0) //no limit!
@@ -340,9 +364,9 @@ void FileVersioner::limitVersions(std::function<void()> updateUI) //throw FileEr
auto getVersionsBuffered = [&](const Zstring& dirname) -> const std::vector<Zstring>&
{
- auto iter = dirBuffer.find(dirname);
- if (iter != dirBuffer.end())
- return iter->second;
+ auto it = dirBuffer.find(dirname);
+ if (it != dirBuffer.end())
+ return it->second;
std::vector<Zstring> fileShortNames;
TraverseVersionsOneLevel tol(fileShortNames, updateUI); //throw FileError
@@ -396,3 +420,4 @@ void FileVersioner::limitVersions(std::function<void()> updateUI) //throw FileEr
});
});
}
+*/ \ No newline at end of file
diff --git a/lib/versioning.h b/lib/versioning.h
index b025511b..3e0dd33c 100644
--- a/lib/versioning.h
+++ b/lib/versioning.h
@@ -13,6 +13,7 @@
#include <zen/zstring.h>
#include <zen/int64.h>
#include <zen/file_error.h>
+#include "../structures.h"
namespace zen
{
@@ -25,19 +26,20 @@ struct CallbackMoveFile;
- creates missing intermediate directories
- does not create empty directories
- handles symlinks
- - ignores already existing target files/dirs (support retry)
- => (unlikely) risk of data loss: race-condition if two FFS instances start at the very same second and process the same filename!!
+ - replaces already existing target files/dirs (supports retry)
+ => (unlikely) risk of data loss for naming convention "versioning":
+ race-condition if two FFS instances start at the very same second OR multiple folder pairs process the same filename!!
*/
class FileVersioner
{
public:
FileVersioner(const Zstring& versioningDirectory, //throw FileError
- const TimeComp& timeStamp,
- int versionCountLimit) : //max versions per file; < 0 := no limit
+ VersioningStyle versioningStyle,
+ const TimeComp& timeStamp) : //max versions per file; < 0 := no limit
+ versioningStyle_(versioningStyle),
versioningDirectory_(versioningDirectory),
- timeStamp_(formatTime<Zstring>(Zstr("%Y-%m-%d %H%M%S"), timeStamp)), //e.g. "2012-05-15 131513"
- versionCountLimit_(versionCountLimit)
+ 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 time stamp for versioning:") + L" \'" + timeStamp_ + L"\'");
@@ -46,14 +48,14 @@ public:
void revisionFile(const Zstring& sourceFile, const Zstring& relativeName, CallbackMoveFile& callback); //throw FileError
void revisionDir (const Zstring& sourceDir, const Zstring& relativeName, CallbackMoveFile& callback); //throw FileError
- void limitVersions(std::function<void()> updateUI); //throw FileError; call when done revisioning!
+ //void limitVersions(std::function<void()> updateUI); //throw FileError; call when done revisioning!
private:
+ const VersioningStyle versioningStyle_;
const Zstring versioningDirectory_;
const Zstring timeStamp_;
- const int versionCountLimit_;
- std::vector<Zstring> fileRelNames; //store list of revisioned file and symlink relative names for limitVersions()
+ //std::vector<Zstring> fileRelNames; //store list of revisioned file and symlink relative names for limitVersions()
};
diff --git a/lib/xml_base.cpp b/lib/xml_base.cpp
index c7650bc0..814b9bdb 100644
--- a/lib/xml_base.cpp
+++ b/lib/xml_base.cpp
@@ -56,8 +56,8 @@ void xmlAccess::loadXmlDocument(const Zstring& filename, XmlDoc& doc) //throw Ff
throw FfsXmlError(
replaceCpy(replaceCpy(replaceCpy(_("Error parsing file %x, row %y, column %z."),
L"%x", fmtFileName(filename)),
- L"%y", numberTo<std::wstring>(e.row)),
- L"%z", numberTo<std::wstring>(e.col)));
+ L"%y", numberTo<std::wstring>(e.row + 1)),
+ L"%z", numberTo<std::wstring>(e.col + 1)));
}
}
bgstack15