summaryrefslogtreecommitdiff
path: root/structures.cpp
diff options
context:
space:
mode:
authorDaniel Wilhelm <daniel@wili.li>2014-04-18 17:14:37 +0200
committerDaniel Wilhelm <daniel@wili.li>2014-04-18 17:14:37 +0200
commit8bf668665b107469086f16cb8ad23e47d479d2b4 (patch)
tree66a91ef06a8caa7cd6819dcbe1860693d3eda8d5 /structures.cpp
parent3.21 (diff)
downloadFreeFileSync-8bf668665b107469086f16cb8ad23e47d479d2b4.tar.gz
FreeFileSync-8bf668665b107469086f16cb8ad23e47d479d2b4.tar.bz2
FreeFileSync-8bf668665b107469086f16cb8ad23e47d479d2b4.zip
4.0
Diffstat (limited to 'structures.cpp')
-rw-r--r--structures.cpp284
1 files changed, 199 insertions, 85 deletions
diff --git a/structures.cpp b/structures.cpp
index 0d16f735..98255700 100644
--- a/structures.cpp
+++ b/structures.cpp
@@ -8,6 +8,7 @@
#include "shared/i18n.h"
#include <iterator>
#include <stdexcept>
+#include <ctime>
using namespace zen;
@@ -19,7 +20,7 @@ wxString zen::getVariantName(CompareVariant var)
case CMP_BY_CONTENT:
return _("File content");
case CMP_BY_TIME_SIZE:
- return _("File size and date");
+ return _("File time and size");
}
assert(false);
@@ -27,32 +28,32 @@ wxString zen::getVariantName(CompareVariant var)
}
-wxString zen::getVariantName(SyncConfig::Variant var)
+wxString zen::getVariantName(DirectionConfig::Variant var)
{
switch (var)
{
- case SyncConfig::AUTOMATIC:
+ case DirectionConfig::AUTOMATIC:
return _("<Automatic>");
- case SyncConfig::MIRROR:
+ case DirectionConfig::MIRROR:
return _("Mirror ->>");
- case SyncConfig::UPDATE:
+ case DirectionConfig::UPDATE:
return _("Update ->");
- case SyncConfig::CUSTOM:
+ case DirectionConfig::CUSTOM:
return _("Custom");
}
return _("Error");
}
-DirectionSet zen::extractDirections(const SyncConfig& cfg)
+DirectionSet zen::extractDirections(const DirectionConfig& cfg)
{
DirectionSet output;
switch (cfg.var)
{
- case SyncConfig::AUTOMATIC:
+ case DirectionConfig::AUTOMATIC:
throw std::logic_error("there are no predefined directions for automatic mode!");
- case SyncConfig::MIRROR:
+ case DirectionConfig::MIRROR:
output.exLeftSideOnly = SYNC_DIR_RIGHT;
output.exRightSideOnly = SYNC_DIR_RIGHT;
output.leftNewer = SYNC_DIR_RIGHT;
@@ -61,7 +62,7 @@ DirectionSet zen::extractDirections(const SyncConfig& cfg)
output.conflict = SYNC_DIR_RIGHT;
break;
- case SyncConfig::UPDATE:
+ case DirectionConfig::UPDATE:
output.exLeftSideOnly = SYNC_DIR_RIGHT;
output.exRightSideOnly = SYNC_DIR_NONE;
output.leftNewer = SYNC_DIR_RIGHT;
@@ -70,7 +71,7 @@ DirectionSet zen::extractDirections(const SyncConfig& cfg)
output.conflict = SYNC_DIR_NONE;
break;
- case SyncConfig::CUSTOM:
+ case DirectionConfig::CUSTOM:
output = cfg.custom;
break;
}
@@ -91,19 +92,39 @@ DirectionSet zen::getTwoWaySet()
}
-wxString MainConfiguration::getSyncVariantName()
+wxString MainConfiguration::getCompVariantName() const
{
- const SyncConfig::Variant firstVariant = firstPair.altSyncConfig.get() ?
- firstPair.altSyncConfig->syncConfiguration.var :
- syncConfiguration.var; //fallback to main sync cfg
+ const CompareVariant firstVariant = firstPair.altCmpConfig.get() ?
+ firstPair.altCmpConfig->compareVar :
+ cmpConfig.compareVar; //fallback to main sync cfg
//test if there's a deviating variant within the additional folder pairs
- for (std::vector<FolderPairEnh>::const_iterator i = additionalPairs.begin(); i != additionalPairs.end(); ++i)
+ for (auto fp = additionalPairs.begin(); fp != additionalPairs.end(); ++fp)
{
- const SyncConfig::Variant thisVariant = i->altSyncConfig.get() ?
- i->altSyncConfig->syncConfiguration.var :
- syncConfiguration.var;
+ const CompareVariant thisVariant = fp->altCmpConfig.get() ?
+ fp->altCmpConfig->compareVar :
+ cmpConfig.compareVar; //fallback to main sync cfg
+ if (thisVariant != firstVariant)
+ return _("Multiple...");
+ }
+
+ //seems to be all in sync...
+ return getVariantName(firstVariant);
+}
+
+wxString MainConfiguration::getSyncVariantName() const
+{
+ const DirectionConfig::Variant firstVariant = firstPair.altSyncConfig.get() ?
+ firstPair.altSyncConfig->directionCfg.var :
+ syncCfg.directionCfg.var; //fallback to main sync cfg
+
+ //test if there's a deviating variant within the additional folder pairs
+ for (auto fp = additionalPairs.begin(); fp != additionalPairs.end(); ++fp)
+ {
+ const DirectionConfig::Variant thisVariant = fp->altSyncConfig.get() ?
+ fp->altSyncConfig->directionCfg.var :
+ syncCfg.directionCfg.var;
if (thisVariant != firstVariant)
return _("Multiple...");
}
@@ -235,28 +256,75 @@ namespace
assert_static(std::numeric_limits<zen:: Int64>::is_specialized);
assert_static(std::numeric_limits<zen::UInt64>::is_specialized);
+
+int daysSinceBeginOfWeek(int dayOfWeek) //0-6, 0=Monday, 6=Sunday
+{
+ assert(0 <= dayOfWeek && dayOfWeek <= 6);
+#ifdef FFS_WIN
+ DWORD firstDayOfWeek = 0;
+ if (::GetLocaleInfo(LOCALE_USER_DEFAULT, //__in LCID Locale,
+ LOCALE_IFIRSTDAYOFWEEK | // first day of week specifier, 0-6, 0=Monday, 6=Sunday
+ LOCALE_RETURN_NUMBER, //__in LCTYPE LCType,
+ reinterpret_cast<LPTSTR>(&firstDayOfWeek), //__out LPTSTR lpLCData,
+ sizeof(firstDayOfWeek) / sizeof(TCHAR)) != 0) //__in int cchData
+ {
+ assert(firstDayOfWeek <= 6);
+ return (dayOfWeek + (7 - firstDayOfWeek)) % 7;
+ }
+ else //default
+#endif
+ return dayOfWeek; //let all weeks begin with monday
+}
+
zen::Int64 resolve(size_t value, UnitTime unit, zen::Int64 defaultVal)
{
- double out = value;
+ const time_t utcTimeNow = ::time(NULL);
+ struct tm* localTimeFmt = ::localtime (&utcTimeNow); //utc to local
+
switch (unit)
{
case UTIME_NONE:
return defaultVal;
- case UTIME_SEC:
- return zen::Int64(value);
- case UTIME_MIN:
- out *= 60;
- break;
- case UTIME_HOUR:
- out *= 3600;
- break;
- case UTIME_DAY:
- out *= 24 * 3600;
- break;
+
+ // case UTIME_LAST_X_HOURS:
+ // return Int64(utcTimeNow) - Int64(value) * 3600;
+
+ case UTIME_TODAY:
+ localTimeFmt->tm_sec = 0; //0-61
+ localTimeFmt->tm_min = 0; //0-59
+ localTimeFmt->tm_hour = 0; //0-23
+ return Int64(::mktime(localTimeFmt)); //convert local time back to UTC
+
+ case UTIME_THIS_WEEK:
+ {
+ localTimeFmt->tm_sec = 0; //0-61
+ localTimeFmt->tm_min = 0; //0-59
+ localTimeFmt->tm_hour = 0; //0-23
+ size_t timeFrom = ::mktime(localTimeFmt);
+
+ int dayOfWeek = (localTimeFmt->tm_wday + 6) % 7; //tm_wday := days since Sunday 0-6
+ // +6 == -1 in Z_7
+
+ return Int64(timeFrom) - daysSinceBeginOfWeek(dayOfWeek) * 24 * 3600;
+ }
+ case UTIME_THIS_MONTH:
+ localTimeFmt->tm_sec = 0; //0-61
+ localTimeFmt->tm_min = 0; //0-59
+ localTimeFmt->tm_hour = 0; //0-23
+ localTimeFmt->tm_mday = 1; //1-31
+ return Int64(::mktime(localTimeFmt)); //convert local time back to UTC
+
+ case UTIME_THIS_YEAR:
+ localTimeFmt->tm_sec = 0; //0-61
+ localTimeFmt->tm_min = 0; //0-59
+ localTimeFmt->tm_hour = 0; //0-23
+ localTimeFmt->tm_mday = 1; //1-31
+ localTimeFmt->tm_mon = 0; //0-11
+ return Int64(::mktime(localTimeFmt)); //convert local time back to UTC
}
- return out >= to<double>(std::numeric_limits<zen::Int64>::max()) ? //prevent overflow!!!
- std::numeric_limits<zen::Int64>::max() :
- zen::Int64(out);
+
+ assert(false);
+ return utcTimeNow;
}
zen::UInt64 resolve(size_t value, UnitSize unit, zen::UInt64 defaultVal)
@@ -284,13 +352,13 @@ zen::UInt64 resolve(size_t value, UnitSize unit, zen::UInt64 defaultVal)
void zen::resolveUnits(size_t timeSpan, UnitTime unitTimeSpan,
size_t sizeMin, UnitSize unitSizeMin,
size_t sizeMax, UnitSize unitSizeMax,
- zen::Int64& timeSpanSec, //unit: seconds
- zen::UInt64& sizeMinBy, //unit: bytes
- zen::UInt64& sizeMaxBy) //unit: bytes
+ zen::Int64& timeFrom, //unit: UTC time, seconds
+ zen::UInt64& sizeMinBy, //unit: bytes
+ zen::UInt64& sizeMaxBy) //unit: bytes
{
- timeSpanSec = resolve(timeSpan, unitTimeSpan, std::numeric_limits<zen::Int64>::max());
- sizeMinBy = resolve(sizeMin, unitSizeMin, 0U);
- sizeMaxBy = resolve(sizeMax, unitSizeMax, std::numeric_limits<zen::UInt64>::max());
+ timeFrom = resolve(timeSpan, unitTimeSpan, std::numeric_limits<Int64>::min());
+ sizeMinBy = resolve(sizeMin, unitSizeMin, 0U);
+ sizeMaxBy = resolve(sizeMax, unitSizeMax, std::numeric_limits<UInt64>::max());
}
@@ -309,12 +377,6 @@ bool sameFilter(const std::vector<FolderPairEnh>& folderPairs)
}
-bool isEmpty(const FolderPairEnh& fp)
-{
- return fp == FolderPairEnh();
-}
-
-
FilterConfig mergeFilterConfig(const FilterConfig& global, const FilterConfig& local)
{
FilterConfig out = local;
@@ -330,28 +392,28 @@ FilterConfig mergeFilterConfig(const FilterConfig& global, const FilterConfig& l
out.excludeFilter.Trim(true, false);
//soft filter
- zen::Int64 locTimeSpanSec;
- zen::UInt64 locSizeMinBy;
- zen::UInt64 locSizeMaxBy;
- zen::resolveUnits(out.timeSpan, out.unitTimeSpan,
- out.sizeMin, out.unitSizeMin,
- out.sizeMax, out.unitSizeMax,
- locTimeSpanSec, //unit: seconds
- locSizeMinBy, //unit: bytes
- locSizeMaxBy); //unit: bytes
+ Int64 loctimeFrom;
+ UInt64 locSizeMinBy;
+ UInt64 locSizeMaxBy;
+ resolveUnits(out.timeSpan, out.unitTimeSpan,
+ out.sizeMin, out.unitSizeMin,
+ out.sizeMax, out.unitSizeMax,
+ loctimeFrom, //unit: UTC time, seconds
+ locSizeMinBy, //unit: bytes
+ locSizeMaxBy); //unit: bytes
//soft filter
- zen::Int64 gloTimeSpanSec;
- zen::UInt64 gloSizeMinBy;
- zen::UInt64 gloSizeMaxBy;
- zen::resolveUnits(global.timeSpan, global.unitTimeSpan,
- global.sizeMin, global.unitSizeMin,
- global.sizeMax, global.unitSizeMax,
- gloTimeSpanSec, //unit: seconds
- gloSizeMinBy, //unit: bytes
- gloSizeMaxBy); //unit: bytes
-
- if (gloTimeSpanSec < locTimeSpanSec)
+ Int64 glotimeFrom;
+ UInt64 gloSizeMinBy;
+ UInt64 gloSizeMaxBy;
+ resolveUnits(global.timeSpan, global.unitTimeSpan,
+ global.sizeMin, global.unitSizeMin,
+ global.sizeMax, global.unitSizeMax,
+ glotimeFrom,
+ gloSizeMinBy,
+ gloSizeMaxBy);
+
+ if (glotimeFrom > loctimeFrom)
{
out.timeSpan = global.timeSpan;
out.unitTimeSpan = global.unitTimeSpan;
@@ -368,60 +430,110 @@ FilterConfig mergeFilterConfig(const FilterConfig& global, const FilterConfig& l
}
return out;
}
+
+
+inline
+bool isEmpty(const FolderPairEnh& fp)
+{
+ return fp == FolderPairEnh();
+}
}
-zen::MainConfiguration zen::merge(const std::vector<MainConfiguration>& mainCfgs)
+MainConfiguration zen::merge(const std::vector<MainConfiguration>& mainCfgs)
{
assert(!mainCfgs.empty());
if (mainCfgs.empty())
- return zen::MainConfiguration();
+ return MainConfiguration();
if (mainCfgs.size() == 1) //mergeConfigFilesImpl relies on this!
return mainCfgs[0]; //
//merge folder pair config
std::vector<FolderPairEnh> fpMerged;
- for (std::vector<MainConfiguration>::const_iterator i = mainCfgs.begin(); i != mainCfgs.end(); ++i)
+ for (std::vector<MainConfiguration>::const_iterator iterMain = mainCfgs.begin(); iterMain != mainCfgs.end(); ++iterMain)
{
std::vector<FolderPairEnh> fpTmp;
//list non-empty local configurations
- if (!isEmpty(i->firstPair)) fpTmp.push_back(i->firstPair);
- std::remove_copy_if(i->additionalPairs.begin(), i->additionalPairs.end(), std::back_inserter(fpTmp), &isEmpty);
+ if (!isEmpty(iterMain->firstPair))
+ fpTmp.push_back(iterMain->firstPair);
+ std::copy_if(iterMain->additionalPairs.begin(), iterMain->additionalPairs.end(), std::back_inserter(fpTmp),
+ [](const FolderPairEnh& fp) { return !isEmpty(fp); });
//move all configuration down to item level
for (std::vector<FolderPairEnh>::iterator fp = fpTmp.begin(); fp != fpTmp.end(); ++fp)
{
+ if (!fp->altCmpConfig.get())
+ fp->altCmpConfig = std::make_shared<CompConfig>(iterMain->cmpConfig);
+
if (!fp->altSyncConfig.get())
- fp->altSyncConfig.reset(
- new AlternateSyncConfig(i->syncConfiguration,
- i->handleDeletion,
- i->customDeletionDirectory));
+ fp->altSyncConfig = std::make_shared<SyncConfig>(iterMain->syncCfg);
- fp->localFilter = mergeFilterConfig(i->globalFilter, fp->localFilter);
+ fp->localFilter = mergeFilterConfig(iterMain->globalFilter, fp->localFilter);
}
fpMerged.insert(fpMerged.end(), fpTmp.begin(), fpTmp.end());
}
if (fpMerged.empty())
- return zen::MainConfiguration();
+ return MainConfiguration();
//optimization: remove redundant configuration
- FilterConfig newGlobalFilter;
+ //########################################################################################################################
+ //find out which comparison and synchronization setting are used most often and use them as new "header"
+ std::vector<std::pair<CompConfig, int>> cmpCfgStat;
+ std::vector<std::pair<SyncConfig, int>> syncCfgStat;
+ for (auto fp = fpMerged.begin(); fp != fpMerged.end(); ++fp) //rather inefficient algorithm, but it does not require a less-than operator!
+ {
+ {
+ const CompConfig& cmpCfg = *fp->altCmpConfig;
+
+ auto iter = std::find_if(cmpCfgStat.begin(), cmpCfgStat.end(),
+ [&](const std::pair<CompConfig, int>& entry) { return entry.first == cmpCfg; });
+ if (iter == cmpCfgStat.end())
+ cmpCfgStat.push_back(std::make_pair(cmpCfg, 1));
+ else
+ ++(iter->second);
+ }
+ {
+ const SyncConfig& syncCfg = *fp->altSyncConfig;
+
+ auto iter = std::find_if(syncCfgStat.begin(), syncCfgStat.end(),
+ [&](const std::pair<SyncConfig, int>& entry) { return entry.first == syncCfg; });
+ if (iter == syncCfgStat.end())
+ syncCfgStat.push_back(std::make_pair(syncCfg, 1));
+ else
+ ++(iter->second);
+ }
+ }
+
+ //set most-used comparison and synchronization settions as new header options
+ const CompConfig cmpCfgHead = cmpCfgStat.empty() ? CompConfig() :
+ std::max_element(cmpCfgStat.begin(), cmpCfgStat.end(),
+ [](const std::pair<CompConfig, int>& lhs, const std::pair<CompConfig, int>& rhs) { return lhs.second < rhs.second; })->first;
+
+ const SyncConfig syncCfgHead = syncCfgStat.empty() ? SyncConfig() :
+ std::max_element(syncCfgStat.begin(), syncCfgStat.end(),
+ [](const std::pair<SyncConfig, int>& lhs, const std::pair<SyncConfig, int>& rhs) { return lhs.second < rhs.second; })->first;
+ //########################################################################################################################
+
+ FilterConfig globalFilter;
const bool equalFilters = sameFilter(fpMerged);
if (equalFilters)
- newGlobalFilter = fpMerged[0].localFilter;
+ globalFilter = fpMerged[0].localFilter;
+ //strip redundancy...
for (std::vector<FolderPairEnh>::iterator fp = fpMerged.begin(); fp != fpMerged.end(); ++fp)
{
//if local config matches output global config we don't need local one
+ if (fp->altCmpConfig &&
+ *fp->altCmpConfig == cmpCfgHead)
+ fp->altCmpConfig.reset();
+
if (fp->altSyncConfig &&
- *fp->altSyncConfig == AlternateSyncConfig(mainCfgs[0].syncConfiguration,
- mainCfgs[0].handleDeletion,
- mainCfgs[0].customDeletionDirectory))
+ *fp->altSyncConfig == syncCfgHead)
fp->altSyncConfig.reset();
if (equalFilters) //use global filter in this case
@@ -429,9 +541,11 @@ zen::MainConfiguration zen::merge(const std::vector<MainConfiguration>& mainCfgs
}
//final assembly
- zen::MainConfiguration cfgOut = mainCfgs[0];
- cfgOut.globalFilter = newGlobalFilter;
- cfgOut.firstPair = fpMerged[0];
+ zen::MainConfiguration cfgOut;
+ cfgOut.cmpConfig = cmpCfgHead;
+ cfgOut.syncCfg = syncCfgHead;
+ cfgOut.globalFilter = globalFilter;
+ cfgOut.firstPair = fpMerged[0];
cfgOut.additionalPairs.assign(fpMerged.begin() + 1, fpMerged.end());
return cfgOut;
bgstack15