summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorDaniel Wilhelm <daniel@wili.li>2014-04-18 17:22:55 +0200
committerDaniel Wilhelm <daniel@wili.li>2014-04-18 17:22:55 +0200
commitc4182431ac7d9d306fdd2267e082fa4cec6fec2c (patch)
tree865cca543c062b7af2586f85cee19f9af4e7614d /lib
parent5.11 (diff)
downloadFreeFileSync-c4182431ac7d9d306fdd2267e082fa4cec6fec2c.tar.gz
FreeFileSync-c4182431ac7d9d306fdd2267e082fa4cec6fec2c.tar.bz2
FreeFileSync-c4182431ac7d9d306fdd2267e082fa4cec6fec2c.zip
5.12
Diffstat (limited to 'lib')
-rw-r--r--lib/binary.cpp18
-rw-r--r--lib/binary.h2
-rw-r--r--lib/dir_exist_async.h2
-rw-r--r--lib/localization.cpp124
-rw-r--r--lib/lock_holder.h2
-rw-r--r--lib/parse_lng.h191
-rw-r--r--lib/parse_plural.h524
-rw-r--r--lib/perf_check.cpp23
-rw-r--r--lib/perf_check.h1
-rw-r--r--lib/process_xml.cpp95
-rw-r--r--lib/process_xml.h17
-rw-r--r--lib/resources.cpp4
-rw-r--r--lib/status_handler.cpp2
-rw-r--r--lib/status_handler.h2
-rw-r--r--lib/versioning.cpp82
-rw-r--r--lib/versioning.h32
16 files changed, 589 insertions, 532 deletions
diff --git a/lib/binary.cpp b/lib/binary.cpp
index 10994cc9..4ef30c15 100644
--- a/lib/binary.cpp
+++ b/lib/binary.cpp
@@ -85,7 +85,6 @@ bool zen::filesHaveSameContent(const Zstring& filename1, const Zstring& filename
FileInput file2(filename2); //
BufferSize bufferSize;
- UInt64 bytesCompared;
TickVal lastDelayViolation = getTicks();
@@ -96,14 +95,19 @@ bool zen::filesHaveSameContent(const Zstring& filename1, const Zstring& filename
const TickVal startTime = getTicks();
- const size_t length1 = file1.read(&memory1[0], bufferSize); //returns actual number of bytes read; throw FileError()
- const size_t length2 = file2.read(&memory2[0], bufferSize); //
+ const size_t length1 = file1.read(&memory1[0], bufferSize); //throw FileError()
+ const size_t length2 = file2.read(&memory2[0], bufferSize); //returns actual number of bytes read
+ //send progress updates immediately after reading to reliably allow speed calculations for our clients!
+ callback.updateCompareStatus(to<Int64>(std::max(length1, length2)));
- const TickVal now = getTicks();
+ if (length1 != length2 || ::memcmp(&memory1[0], &memory2[0], length1) != 0)
+ return false;
//-------- dynamically set buffer size to keep callback interval between 100 - 500ms ---------------------
if (TICKS_PER_SEC > 0)
{
+ const TickVal now = getTicks();
+
const std::int64_t loopTime = dist(startTime, now) * 1000 / TICKS_PER_SEC; //unit: [ms]
if (loopTime < 100)
{
@@ -120,12 +124,6 @@ bool zen::filesHaveSameContent(const Zstring& filename1, const Zstring& filename
}
}
//------------------------------------------------------------------------------------------------
-
- if (length1 != length2 || ::memcmp(&memory1[0], &memory2[0], length1) != 0)
- return false;
-
- bytesCompared += length1;
- callback.updateCompareStatus(bytesCompared); //send progress updates
}
while (!file1.eof());
diff --git a/lib/binary.h b/lib/binary.h
index 83409e19..8a4abe6b 100644
--- a/lib/binary.h
+++ b/lib/binary.h
@@ -16,7 +16,7 @@ namespace zen
struct CompareCallback
{
virtual ~CompareCallback() {}
- virtual void updateCompareStatus(UInt64 totalBytes) = 0;
+ virtual void updateCompareStatus(Int64 bytesDelta) = 0;
};
bool filesHaveSameContent(const Zstring& filename1, const Zstring& filename2, CompareCallback& callback); //throw FileError
diff --git a/lib/dir_exist_async.h b/lib/dir_exist_async.h
index a02facad..306c9ab9 100644
--- a/lib/dir_exist_async.h
+++ b/lib/dir_exist_async.h
@@ -31,7 +31,7 @@ bool dirExistsUpdating(const Zstring& dirname, bool allowUserInteraction, Proces
//2. check dir existence
return zen::dirExists(dirname);
});
- while (!ft.timed_wait(boost::posix_time::milliseconds(UI_UPDATE_INTERVAL)))
+ while (!ft.timed_wait(boost::posix_time::milliseconds(UI_UPDATE_INTERVAL / 2)))
procCallback.requestUiRefresh(); //may throw!
return ft.get();
}
diff --git a/lib/localization.cpp b/lib/localization.cpp
index 47ed1881..78e03545 100644
--- a/lib/localization.cpp
+++ b/lib/localization.cpp
@@ -28,23 +28,22 @@ namespace
class FFSLocale : public TranslationHandler
{
public:
- FFSLocale(const wxString& filename, wxLanguage languageId); //throw lngfile::ParsingError, PluralForm::ParsingError
+ FFSLocale(const wxString& filename, wxLanguage languageId); //throw lngfile::ParsingError, parse_plural::ParsingError
wxLanguage langId() const { return langId_; }
virtual std::wstring translate(const std::wstring& text)
{
//look for translation in buffer table
- const Translation::const_iterator it = transMapping.find(text);
- if (it != transMapping.end())
+ auto it = transMapping.find(text);
+ if (it != transMapping.end() && !it->second.empty())
return it->second;
-
return text; //fallback
}
virtual std::wstring translate(const std::wstring& singular, const std::wstring& plural, int n)
{
- TranslationPlural::const_iterator it = transMappingPl.find(std::make_pair(singular, plural));
+ auto it = transMappingPl.find(std::make_pair(singular, plural));
if (it != transMappingPl.end())
{
const int formNo = pluralParser->getForm(n);
@@ -55,17 +54,17 @@ public:
}
private:
- typedef std::map<std::wstring, std::wstring> Translation;
+ typedef hash_map<std::wstring, std::wstring> Translation; //hash_map is 15% faster than std::map on GCC
typedef std::map<std::pair<std::wstring, std::wstring>, std::vector<std::wstring> > TranslationPlural;
Translation transMapping; //map original text |-> translation
TranslationPlural transMappingPl;
- std::unique_ptr<PluralForm> pluralParser;
+ std::unique_ptr<parse_plural::PluralForm> pluralParser; //bound!
wxLanguage langId_;
};
-FFSLocale::FFSLocale(const wxString& filename, wxLanguage languageId) : langId_(languageId) //throw lngfile::ParsingError, PluralForm::ParsingError
+FFSLocale::FFSLocale(const wxString& filename, wxLanguage languageId) : langId_(languageId) //throw lngfile::ParsingError, parse_plural::ParsingError
{
std::string inputStream;
try
@@ -86,7 +85,6 @@ FFSLocale::FFSLocale(const wxString& filename, wxLanguage languageId) : langId_(
{
const std::wstring original = utfCvrtTo<std::wstring>(i->first);
const std::wstring translation = utfCvrtTo<std::wstring>(i->second);
- assert(!translation.empty());
transMapping.insert(std::make_pair(original, translation));
}
@@ -100,13 +98,10 @@ FFSLocale::FFSLocale(const wxString& filename, wxLanguage languageId) : langId_(
for (lngfile::PluralForms::const_iterator j = plForms.begin(); j != plForms.end(); ++j)
plFormsWide.push_back(utfCvrtTo<std::wstring>(*j));
- assert(!plFormsWide.empty());
-
transMappingPl.insert(std::make_pair(std::make_pair(singular, plural), plFormsWide));
}
- pluralParser.reset(new PluralForm(header.pluralDefinition)); //throw PluralForm::ParsingError
-}
+ pluralParser.reset(new parse_plural::PluralForm(header.pluralDefinition)); //throw parse_plural::ParsingError
}
@@ -151,6 +146,7 @@ struct LessTranslation : public std::binary_function<ExistingTranslations::Entry
#endif
}
};
+}
ExistingTranslations::ExistingTranslations()
@@ -173,10 +169,10 @@ ExistingTranslations::ExistingTranslations()
traverseFolder(zen::getResourceDir() + Zstr("Languages"), //throw();
traverseCallback);
- for (auto i = lngFiles.begin(); i != lngFiles.end(); ++i)
+ for (auto it = lngFiles.begin(); it != lngFiles.end(); ++it)
try
{
- std::string stream = loadStream(*i); //throw XmlFileError
+ std::string stream = loadStream(*it); //throw XmlFileError
try
{
lngfile::TransHeader lngHeader;
@@ -191,7 +187,7 @@ ExistingTranslations::ExistingTranslations()
ExistingTranslations::Entry newEntry;
newEntry.languageID = locInfo->Language;
newEntry.languageName = utfCvrtTo<wxString>(lngHeader.languageName);
- newEntry.languageFile = utfCvrtTo<wxString>(*i);
+ newEntry.languageFile = utfCvrtTo<wxString>(*it);
newEntry.translatorName = utfCvrtTo<wxString>(lngHeader.translatorName);
newEntry.languageFlag = utfCvrtTo<wxString>(lngHeader.flagFile);
locMapping.push_back(newEntry);
@@ -205,12 +201,59 @@ ExistingTranslations::ExistingTranslations()
}
+const std::vector<ExistingTranslations::Entry>& ExistingTranslations::get()
+{
+ static ExistingTranslations instance;
+ return instance.locMapping;
+}
+
+
namespace
{
wxLanguage mapLanguageDialect(wxLanguage language)
{
- switch (static_cast<int>(language)) //map language dialects
+ switch (static_cast<int>(language)) //avoid enumeration value wxLANGUAGE_*' not handled in switch [-Wswitch-enum]
{
+ //variants of wxLANGUAGE_ARABIC
+ case wxLANGUAGE_ARABIC_ALGERIA:
+ case wxLANGUAGE_ARABIC_BAHRAIN:
+ case wxLANGUAGE_ARABIC_EGYPT:
+ case wxLANGUAGE_ARABIC_IRAQ:
+ case wxLANGUAGE_ARABIC_JORDAN:
+ case wxLANGUAGE_ARABIC_KUWAIT:
+ case wxLANGUAGE_ARABIC_LEBANON:
+ case wxLANGUAGE_ARABIC_LIBYA:
+ case wxLANGUAGE_ARABIC_MOROCCO:
+ case wxLANGUAGE_ARABIC_OMAN:
+ case wxLANGUAGE_ARABIC_QATAR:
+ case wxLANGUAGE_ARABIC_SAUDI_ARABIA:
+ case wxLANGUAGE_ARABIC_SUDAN:
+ case wxLANGUAGE_ARABIC_SYRIA:
+ case wxLANGUAGE_ARABIC_TUNISIA:
+ case wxLANGUAGE_ARABIC_UAE:
+ case wxLANGUAGE_ARABIC_YEMEN:
+ return wxLANGUAGE_ARABIC;
+
+ //variants of wxLANGUAGE_ENGLISH_UK
+ case wxLANGUAGE_ENGLISH_AUSTRALIA:
+ case wxLANGUAGE_ENGLISH_NEW_ZEALAND:
+ case wxLANGUAGE_ENGLISH_TRINIDAD:
+ case wxLANGUAGE_ENGLISH_CARIBBEAN:
+ case wxLANGUAGE_ENGLISH_JAMAICA:
+ case wxLANGUAGE_ENGLISH_BELIZE:
+ case wxLANGUAGE_ENGLISH_EIRE:
+ case wxLANGUAGE_ENGLISH_SOUTH_AFRICA:
+ case wxLANGUAGE_ENGLISH_ZIMBABWE:
+ case wxLANGUAGE_ENGLISH_BOTSWANA:
+ case wxLANGUAGE_ENGLISH_DENMARK:
+ return wxLANGUAGE_ENGLISH_UK;
+
+ //variants of wxLANGUAGE_ENGLISH_US
+ case wxLANGUAGE_ENGLISH:
+ case wxLANGUAGE_ENGLISH_CANADA:
+ case wxLANGUAGE_ENGLISH_PHILIPPINES:
+ return wxLANGUAGE_ENGLISH_US;
+
//variants of wxLANGUAGE_GERMAN
case wxLANGUAGE_GERMAN_AUSTRIAN:
case wxLANGUAGE_GERMAN_BELGIUM:
@@ -281,6 +324,7 @@ wxLanguage mapLanguageDialect(wxLanguage language)
case wxLANGUAGE_NORWEGIAN_NYNORSK:
return wxLANGUAGE_NORWEGIAN_BOKMAL;
+ //languages without variants:
//case wxLANGUAGE_CZECH:
//case wxLANGUAGE_DANISH:
//case wxLANGUAGE_FINNISH:
@@ -296,41 +340,6 @@ wxLanguage mapLanguageDialect(wxLanguage language)
//case wxLANGUAGE_KOREAN:
//case wxLANGUAGE_UKRAINIAN:
//case wxLANGUAGE_CROATIAN:
-
- //variants of wxLANGUAGE_ARABIC
- case wxLANGUAGE_ARABIC_ALGERIA:
- case wxLANGUAGE_ARABIC_BAHRAIN:
- case wxLANGUAGE_ARABIC_EGYPT:
- case wxLANGUAGE_ARABIC_IRAQ:
- case wxLANGUAGE_ARABIC_JORDAN:
- case wxLANGUAGE_ARABIC_KUWAIT:
- case wxLANGUAGE_ARABIC_LEBANON:
- case wxLANGUAGE_ARABIC_LIBYA:
- case wxLANGUAGE_ARABIC_MOROCCO:
- case wxLANGUAGE_ARABIC_OMAN:
- case wxLANGUAGE_ARABIC_QATAR:
- case wxLANGUAGE_ARABIC_SAUDI_ARABIA:
- case wxLANGUAGE_ARABIC_SUDAN:
- case wxLANGUAGE_ARABIC_SYRIA:
- case wxLANGUAGE_ARABIC_TUNISIA:
- case wxLANGUAGE_ARABIC_UAE:
- case wxLANGUAGE_ARABIC_YEMEN:
- return wxLANGUAGE_ARABIC;
-
- //variants of wxLANGUAGE_ENGLISH_UK
- case wxLANGUAGE_ENGLISH_AUSTRALIA:
- case wxLANGUAGE_ENGLISH_NEW_ZEALAND:
- case wxLANGUAGE_ENGLISH_TRINIDAD:
- case wxLANGUAGE_ENGLISH_CARIBBEAN:
- case wxLANGUAGE_ENGLISH_JAMAICA:
- case wxLANGUAGE_ENGLISH_BELIZE:
- case wxLANGUAGE_ENGLISH_EIRE:
- case wxLANGUAGE_ENGLISH_SOUTH_AFRICA:
- case wxLANGUAGE_ENGLISH_ZIMBABWE:
- case wxLANGUAGE_ENGLISH_BOTSWANA:
- case wxLANGUAGE_ENGLISH_DENMARK:
- return wxLANGUAGE_ENGLISH_UK;
-
default:
return language;
}
@@ -391,7 +400,7 @@ void zen::setLanguage(int language) //throw FileError
else
try
{
- zen::setTranslator(new FFSLocale(languageFile, static_cast<wxLanguage>(language))); //throw lngfile::ParsingError, PluralForm::ParsingError
+ zen::setTranslator(new FFSLocale(languageFile, static_cast<wxLanguage>(language))); //throw lngfile::ParsingError, parse_plural::ParsingError
}
catch (lngfile::ParsingError& e)
{
@@ -400,7 +409,7 @@ void zen::setLanguage(int language) //throw FileError
L"%y", numberTo<std::wstring>(e.row + 1)),
L"%z", numberTo<std::wstring>(e.col + 1)));
}
- catch (PluralForm::ParsingError&)
+ catch (parse_plural::ParsingError&)
{
throw FileError(L"Invalid Plural Form");
}
@@ -422,10 +431,3 @@ int zen::retrieveSystemLanguage()
{
return mapLanguageDialect(static_cast<wxLanguage>(wxLocale::GetSystemLanguage()));
}
-
-
-const std::vector<ExistingTranslations::Entry>& ExistingTranslations::get()
-{
- static ExistingTranslations instance;
- return instance.locMapping;
-}
diff --git a/lib/lock_holder.h b/lib/lock_holder.h
index dd997853..d4fe27a9 100644
--- a/lib/lock_holder.h
+++ b/lib/lock_holder.h
@@ -46,7 +46,7 @@ public:
try
{
- //lock file creation is synchronous and may block noticably for very slow devices (usb sticks, mapped cloud storages)
+ //lock file creation is synchronous and may block noticeably for very slow devices (usb sticks, mapped cloud storages)
procCallback.forceUiRefresh(); //=> make sure the right folder name is shown on GUI during this time!
lockHolder.insert(std::make_pair(dirnameFmt, DirLock(dirnameFmt + Zstr("sync") + LOCK_FILE_ENDING, &callback)));
}
diff --git a/lib/parse_lng.h b/lib/parse_lng.h
index 92564a1e..b5afe50c 100644
--- a/lib/parse_lng.h
+++ b/lib/parse_lng.h
@@ -51,19 +51,7 @@ void parseLng(const std::string& fileStream, TransHeader& header, TranslationMap
void parseHeader(const std::string& fileStream, TransHeader& header); //throw ParsingError
class TranslationList; //unordered list of unique translation items
-void generateLng(const TranslationList& in, const TransHeader& header, std::string& fileStream);
-
-
-
-
-
-
-
-
-
-
-
-
+std::string generateLng(const TranslationList& in, const TransHeader& header);
@@ -114,7 +102,7 @@ public:
}
private:
- friend void generateLng(const TranslationList& in, const TransHeader& header, std::string& fileStream);
+ friend std::string generateLng(const TranslationList& in, const TransHeader& header);
struct Item {virtual ~Item() {} };
struct RegularItem : public Item { RegularItem(const TranslationMap ::value_type& val) : value(val) {} TranslationMap ::value_type value; };
@@ -218,7 +206,11 @@ private:
class Scanner
{
public:
- Scanner(const std::string& fileStream) : stream(fileStream), pos(stream.begin()) {}
+ Scanner(const std::string& fileStream) : stream(fileStream), pos(stream.begin())
+ {
+ if (zen::startsWith(stream, zen::BYTE_ORDER_MARK_UTF8))
+ pos += zen::strLength(zen::BYTE_ORDER_MARK_UTF8);
+ }
Token nextToken()
{
@@ -228,19 +220,19 @@ public:
if (pos == stream.end())
return Token(Token::TK_END);
- for (KnownTokens::TokenMap::const_iterator i = KnownTokens::asList().begin(); i != KnownTokens::asList().end(); ++i)
- if (startsWith(i->second))
+ for (auto it = KnownTokens::asList().begin(); it != KnownTokens::asList().end(); ++it)
+ if (startsWith(it->second))
{
- pos += i->second.size();
- return Token(i->first);
+ pos += it->second.size();
+ return Token(it->first);
}
//rest must be "text"
- std::string::const_iterator textBegin = pos;
+ std::string::const_iterator itBegin = pos;
while (pos != stream.end() && !startsWithKnownTag())
pos = std::find(pos + 1, stream.end(), '<');
- std::string text(textBegin, pos);
+ std::string text(itBegin, pos);
normalize(text); //remove whitespace from end ect.
@@ -255,13 +247,8 @@ public:
size_t posRow() const //current row beginning with 0
{
//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;
+ const size_t crSum = std::count(stream.begin(), pos, '\r'); //carriage returns
+ const size_t nlSum = std::count(stream.begin(), pos, '\n'); //new lines
assert(crSum == 0 || nlSum == 0 || crSum == nlSum);
return std::max(crSum, nlSum); //be compatible with Linux/Mac/Win
}
@@ -294,32 +281,15 @@ private:
static void normalize(std::string& text)
{
- //remmove whitespace from end
- while (!text.empty() && zen::isWhiteSpace(*text.rbegin()))
- text.resize(text.size() - 1);
-
- //ensure c-style line breaks
+ zen::trim(text); //remmove whitespace from end
//Delimiter:
//----------
//Linux: 0xA \n
//Mac: 0xD \r
//Win: 0xD 0xA \r\n <- language files are in Windows format
- if (text.find('\r') != std::string::npos)
- {
- std::string tmp;
- for (std::string::const_iterator i = text.begin(); i != text.end(); ++i)
- if (*i == '\r')
- {
- std::string::const_iterator next = i + 1;
- if (next != text.end() && *next == '\n')
- ++i;
- tmp += '\n';
- }
- else
- tmp += *i;
- text = tmp;
- }
+ zen::replace(text, "\r\n", '\n'); //
+ zen::replace(text, "\r", '\n'); //ensure c-style line breaks
}
const std::string stream;
@@ -334,7 +304,6 @@ public:
void parse(TranslationMap& out, TranslationPluralMap& pluralOut, TransHeader& header)
{
- //header
parseHeader(header);
//items
@@ -399,9 +368,7 @@ private:
nextToken();
}
consumeToken(Token::TK_TRG_END);
-
- if (!translation.empty()) //only add if translation is existing
- out.insert(std::make_pair(original, translation));
+ out.insert(std::make_pair(original, translation));
}
void parsePlural(TranslationPluralMap& pluralOut, int formCount)
@@ -437,20 +404,23 @@ private:
throw ParsingError(scn.posRow(), scn.posCol());
consumeToken(Token::TK_TRG_END);
-
- if (!pluralList.empty()) //only add if translation is existing
- pluralOut.insert(std::make_pair(SingularPluralPair(engSingular, engPlural), pluralList));
+ pluralOut.insert(std::make_pair(SingularPluralPair(engSingular, engPlural), pluralList));
}
void nextToken() { tk = scn.nextToken(); }
const Token& token() const { return tk; }
- void consumeToken(Token::Type t)
+ void consumeToken(Token::Type t) //throw ParsingError
+ {
+ expectToken(t); //throw ParsingError
+ nextToken();
+ }
+
+ void expectToken(Token::Type t) //throw ParsingError
{
if (token().type != t)
throw ParsingError(scn.posRow(), scn.posCol());
- nextToken();
}
Scanner scn;
@@ -464,24 +434,22 @@ void parseLng(const std::string& fileStream, TransHeader& header, TranslationMap
out.clear();
pluralOut.clear();
- //skip UTF-8 Byte Ordering Mark
- LngParser prs(zen::startsWith(fileStream, zen::BYTE_ORDER_MARK_UTF8) ? fileStream.substr(3) : fileStream);
- prs.parse(out, pluralOut, header);
+ LngParser(fileStream).parse(out, pluralOut, header);
}
inline
void parseHeader(const std::string& fileStream, TransHeader& header) //throw ParsingError
{
- //skip UTF-8 Byte Ordering Mark
- LngParser prs(zen::startsWith(fileStream, zen::BYTE_ORDER_MARK_UTF8) ? fileStream.substr(3) : fileStream);
- prs.parseHeader(header);
+ LngParser(fileStream).parseHeader(header);
}
inline
void formatMultiLineText(std::string& text)
{
+ assert(!zen::contains(text, "\r\n"));
+
if (text.find('\n') != std::string::npos) //multiple lines
{
if (*text.begin() != '\n')
@@ -492,49 +460,46 @@ void formatMultiLineText(std::string& text)
}
-const std::string LB = "\n";
-const std::string TAB = "\t";
-
-
-void generateLng(const TranslationList& in, const TransHeader& header, std::string& fileStream)
+std::string generateLng(const TranslationList& in, const TransHeader& header)
{
+ std::string out;
//header
- fileStream += KnownTokens::text(Token::TK_HEADER_BEGIN) + LB;
+ out += KnownTokens::text(Token::TK_HEADER_BEGIN) + '\n';
- fileStream += TAB + KnownTokens::text(Token::TK_LANG_NAME_BEGIN);
- fileStream += header.languageName;
- fileStream += KnownTokens::text(Token::TK_LANG_NAME_END) + LB;
+ out += '\t' + KnownTokens::text(Token::TK_LANG_NAME_BEGIN);
+ out += header.languageName;
+ out += KnownTokens::text(Token::TK_LANG_NAME_END) + '\n';
- fileStream += TAB + KnownTokens::text(Token::TK_TRANS_NAME_BEGIN);
- fileStream += header.translatorName;
- fileStream += KnownTokens::text(Token::TK_TRANS_NAME_END) + LB;
+ out += '\t' + KnownTokens::text(Token::TK_TRANS_NAME_BEGIN);
+ out += header.translatorName;
+ out += KnownTokens::text(Token::TK_TRANS_NAME_END) + '\n';
- fileStream += TAB + KnownTokens::text(Token::TK_LOCALE_NAME_BEGIN);
- fileStream += header.localeName;
- fileStream += KnownTokens::text(Token::TK_LOCALE_NAME_END) + LB;
+ out += '\t' + KnownTokens::text(Token::TK_LOCALE_NAME_BEGIN);
+ out += header.localeName;
+ out += KnownTokens::text(Token::TK_LOCALE_NAME_END) + '\n';
- fileStream += TAB + KnownTokens::text(Token::TK_FLAG_FILE_BEGIN);
- fileStream += header.flagFile;
- fileStream += KnownTokens::text(Token::TK_FLAG_FILE_END) + LB;
+ out += '\t' + KnownTokens::text(Token::TK_FLAG_FILE_BEGIN);
+ out += header.flagFile;
+ out += KnownTokens::text(Token::TK_FLAG_FILE_END) + '\n';
- fileStream += TAB + KnownTokens::text(Token::TK_PLURAL_COUNT_BEGIN);
- fileStream += zen::numberTo<std::string>(header.pluralCount);
- fileStream += KnownTokens::text(Token::TK_PLURAL_COUNT_END) + LB;
+ out += '\t' + KnownTokens::text(Token::TK_PLURAL_COUNT_BEGIN);
+ out += zen::numberTo<std::string>(header.pluralCount);
+ out += KnownTokens::text(Token::TK_PLURAL_COUNT_END) + '\n';
- fileStream += TAB + KnownTokens::text(Token::TK_PLURAL_DEF_BEGIN);
- fileStream += header.pluralDefinition;
- fileStream += KnownTokens::text(Token::TK_PLURAL_DEF_END) + LB;
+ out += '\t' + KnownTokens::text(Token::TK_PLURAL_DEF_BEGIN);
+ out += header.pluralDefinition;
+ out += KnownTokens::text(Token::TK_PLURAL_DEF_END) + '\n';
- fileStream += KnownTokens::text(Token::TK_HEADER_END) + LB;
+ out += KnownTokens::text(Token::TK_HEADER_END) + '\n';
- fileStream += LB;
+ out += '\n';
//items
- for (std::vector<TranslationList::Item*>::const_iterator i = in.sequence.begin(); i != in.sequence.end(); ++i)
+ for (auto it = in.sequence.begin(); it != in.sequence.end(); ++it)
{
- const TranslationList::RegularItem* regular = dynamic_cast<const TranslationList::RegularItem*>(*i);
- const TranslationList::PluralItem* plural = dynamic_cast<const TranslationList::PluralItem*>(*i);
+ const TranslationList::RegularItem* regular = dynamic_cast<const TranslationList::RegularItem*>(*it);
+ const TranslationList::PluralItem* plural = dynamic_cast<const TranslationList::PluralItem* >(*it);
if (regular)
{
@@ -544,13 +509,13 @@ void generateLng(const TranslationList& in, const TransHeader& header, std::stri
formatMultiLineText(original);
formatMultiLineText(translation);
- fileStream += KnownTokens::text(Token::TK_SRC_BEGIN);
- fileStream += original;
- fileStream += KnownTokens::text(Token::TK_SRC_END) + LB;
+ out += KnownTokens::text(Token::TK_SRC_BEGIN);
+ out += original;
+ out += KnownTokens::text(Token::TK_SRC_END) + '\n';
- fileStream += KnownTokens::text(Token::TK_TRG_BEGIN);
- fileStream += translation;
- fileStream += KnownTokens::text(Token::TK_TRG_END) + LB + LB;
+ out += KnownTokens::text(Token::TK_TRG_BEGIN);
+ out += translation;
+ out += KnownTokens::text(Token::TK_TRG_END) + '\n' + '\n';
}
else if (plural)
@@ -562,34 +527,36 @@ void generateLng(const TranslationList& in, const TransHeader& header, std::stri
formatMultiLineText(engSingular);
formatMultiLineText(engPlural);
- fileStream += KnownTokens::text(Token::TK_SRC_BEGIN) + LB;
- fileStream += KnownTokens::text(Token::TK_PLURAL_BEGIN);
- fileStream += engSingular;
- fileStream += KnownTokens::text(Token::TK_PLURAL_END) + LB;
- fileStream += KnownTokens::text(Token::TK_PLURAL_BEGIN);
- fileStream += engPlural;
- fileStream += KnownTokens::text(Token::TK_PLURAL_END) + LB;
- fileStream += KnownTokens::text(Token::TK_SRC_END) + LB;
+ out += KnownTokens::text(Token::TK_SRC_BEGIN) + '\n';
+ out += KnownTokens::text(Token::TK_PLURAL_BEGIN);
+ out += engSingular;
+ out += KnownTokens::text(Token::TK_PLURAL_END) + '\n';
+ out += KnownTokens::text(Token::TK_PLURAL_BEGIN);
+ out += engPlural;
+ out += KnownTokens::text(Token::TK_PLURAL_END) + '\n';
+ out += KnownTokens::text(Token::TK_SRC_END) + '\n';
- fileStream += KnownTokens::text(Token::TK_TRG_BEGIN);
- if (!forms.empty()) fileStream += LB;
+ out += KnownTokens::text(Token::TK_TRG_BEGIN);
+ if (!forms.empty()) out += '\n';
for (PluralForms::const_iterator j = forms.begin(); j != forms.end(); ++j)
{
std::string plForm = *j;
formatMultiLineText(plForm);
- fileStream += KnownTokens::text(Token::TK_PLURAL_BEGIN);
- fileStream += plForm;
- fileStream += KnownTokens::text(Token::TK_PLURAL_END) + LB;
+ out += KnownTokens::text(Token::TK_PLURAL_BEGIN);
+ out += plForm;
+ out += KnownTokens::text(Token::TK_PLURAL_END) + '\n';
}
- fileStream += KnownTokens::text(Token::TK_TRG_END) + LB + LB;
+ out += KnownTokens::text(Token::TK_TRG_END) + '\n' + '\n';
}
else
{
throw std::logic_error("that's what you get for brittle design ;)");
}
}
+ assert(!zen::contains(out, "\r\n") && !zen::contains(out, "\r"));
+ return zen::replaceCpy(out, '\n', "\r\n"); //back to win line endings
}
}
diff --git a/lib/parse_plural.h b/lib/parse_plural.h
index 7af6809e..c3591881 100644
--- a/lib/parse_plural.h
+++ b/lib/parse_plural.h
@@ -7,11 +7,45 @@
#ifndef PARSE_PLURAL_H_INCLUDED
#define PARSE_PLURAL_H_INCLUDED
-#include <list>
#include <memory>
#include <functional>
#include <zen/string_base.h>
+namespace parse_plural
+{
+//expression interface
+struct Expression { virtual ~Expression() {} };
+
+template <class T>
+struct Expr : public Expression
+{
+ typedef T ValueType;
+ virtual ValueType eval() const = 0;
+};
+
+
+class ParsingError {};
+
+class PluralForm
+{
+public:
+ PluralForm(const std::string& stream); //throw ParsingError
+ int getForm(int n) const { n_ = n ; return expr->eval(); }
+
+private:
+ std::shared_ptr<Expr<int>> expr;
+ mutable int n_;
+};
+
+
+
+
+
+
+
+
+//--------------------------- implementation ---------------------------
+
//http://www.gnu.org/software/hello/manual/gettext/Plural-forms.html
//http://translate.sourceforge.net/wiki/l10n/pluralforms
/*
@@ -52,55 +86,57 @@ pm-expression:
variable-number-n-expression
constant-number-expression
( expression )
-*/
-
-//expression interface
-struct Expression { virtual ~Expression() {} };
+.po format,e.g.: (n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)
+*/
-template <class T>
-struct Expr : public Expression
+namespace implementation
{
- typedef T ValueType;
- virtual ValueType eval() const = 0;
-};
-
//specific binary expression based on STL function objects
template <class StlOp>
struct BinaryExp : public Expr<typename StlOp::result_type>
{
- typedef const Expr<typename StlOp::first_argument_type > ExpLhs;
- typedef const Expr<typename StlOp::second_argument_type> ExpRhs;
+ typedef std::shared_ptr<Expr<typename StlOp::first_argument_type >> ExpLhs;
+ typedef std::shared_ptr<Expr<typename StlOp::second_argument_type>> ExpRhs;
- BinaryExp(const ExpLhs& lhs, const ExpRhs& rhs, StlOp biop) : lhs_(lhs), rhs_(rhs), biop_(biop) {}
- virtual typename StlOp::result_type eval() const { return biop_(lhs_.eval(), rhs_.eval()); }
- const ExpLhs& lhs_;
- const ExpRhs& rhs_;
+ BinaryExp(const ExpLhs& lhs, const ExpRhs& rhs, StlOp biop) : lhs_(lhs), rhs_(rhs), biop_(biop) { assert(lhs && rhs); }
+ virtual typename StlOp::result_type eval() const { return biop_(lhs_->eval(), rhs_->eval()); }
+private:
+ ExpLhs lhs_;
+ ExpRhs rhs_;
StlOp biop_;
};
template <class StlOp> inline
-BinaryExp<StlOp> makeBiExp(const Expression& lhs, const Expression& rhs, StlOp biop) //throw std::bad_cast
+std::shared_ptr<BinaryExp<StlOp>> makeBiExp(const std::shared_ptr<Expression>& lhs, const std::shared_ptr<Expression>& rhs, StlOp biop) //throw ParsingError
{
- return BinaryExp<StlOp>(dynamic_cast<const Expr<typename StlOp::first_argument_type >&>(lhs), //throw std::bad_cast
- dynamic_cast<const Expr<typename StlOp::second_argument_type>&>(rhs), biop); //
+ auto exLeft = std::dynamic_pointer_cast<Expr<typename StlOp::first_argument_type >>(lhs);
+ auto exRight = std::dynamic_pointer_cast<Expr<typename StlOp::second_argument_type>>(rhs);
+ if (!exLeft || !exRight)
+ throw ParsingError();
+ return std::make_shared<BinaryExp<StlOp>>(exLeft, exRight, biop);
}
template <class T>
-struct TernaryExp : public Expr<T>
+struct ConditionalExp : public Expr<T>
{
- TernaryExp(const Expr<bool>& ifExp, const Expr<T>& thenExp, const Expr<T>& elseExp) : ifExp_(ifExp), thenExp_(thenExp), elseExp_(elseExp) {}
- virtual typename Expr<T>::ValueType eval() const { return ifExp_.eval() ? thenExp_.eval() : elseExp_.eval(); }
- const Expr<bool>& ifExp_;
- const Expr<T>& thenExp_;
- const Expr<T>& elseExp_;
+ ConditionalExp(const std::shared_ptr<Expr<bool>>& ifExp,
+ const std::shared_ptr<Expr<T>>& thenExp,
+ const std::shared_ptr<Expr<T>>& elseExp) : ifExp_(ifExp), thenExp_(thenExp), elseExp_(elseExp) { assert(ifExp && thenExp && elseExp); }
+
+ virtual typename Expr<T>::ValueType eval() const { return ifExp_->eval() ? thenExp_->eval() : elseExp_->eval(); }
+private:
+ std::shared_ptr<Expr<bool>> ifExp_;
+ std::shared_ptr<Expr<T>> thenExp_;
+ std::shared_ptr<Expr<T>> elseExp_;
};
struct ConstNumberExp : public Expr<int>
{
ConstNumberExp(int n) : n_(n) {}
virtual int eval() const { return n_; }
+private:
int n_;
};
@@ -108,296 +144,276 @@ struct VariableNumberNExp : public Expr<int>
{
VariableNumberNExp(int& n) : n_(n) {}
virtual int eval() const { return n_; }
+private:
int& n_;
};
+//-------------------------------------------------------------------------------
-class PluralForm
+struct Token
{
-public:
- struct ParsingError {};
-
- //.po format,e.g.: (n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)
- PluralForm(const std::string& phrase) : n_(0)
+ enum Type
{
- Parser(phrase, //in
- expr, n_, dump); //out
- }
+ TK_TERNARY_QUEST,
+ TK_TERNARY_COLON,
+ TK_OR,
+ TK_AND,
+ TK_EQUAL,
+ TK_NOT_EQUAL,
+ TK_LESS,
+ TK_LESS_EQUAL,
+ TK_GREATER,
+ TK_GREATER_EQUAL,
+ TK_MODULUS,
+ TK_VARIABLE_N,
+ TK_CONST_NUMBER,
+ TK_BRACKET_LEFT,
+ TK_BRACKET_RIGHT,
+ TK_END
+ };
- int getForm(int n) const { n_ = n ; return expr->eval(); }
+ Token(Type t) : type(t), number(0) {}
+ Token(int num) : type(TK_CONST_NUMBER), number(num) {}
-private:
- typedef std::list<std::shared_ptr<Expression> > DumpList;
+ Type type;
+ int number; //if type == TK_CONST_NUMBER
+};
- struct Token
+class Scanner
+{
+public:
+ Scanner(const std::string& stream) : stream_(stream), pos(stream_.begin())
{
- enum Type
- {
- TK_TERNARY_QUEST,
- TK_TERNARY_COLON,
- TK_OR,
- TK_AND,
- TK_EQUAL,
- TK_NOT_EQUAL,
- TK_LESS,
- TK_LESS_EQUAL,
- TK_GREATER,
- TK_GREATER_EQUAL,
- TK_MODULUS,
- TK_VARIABLE_N,
- TK_CONST_NUMBER,
- TK_BRACKET_LEFT,
- TK_BRACKET_RIGHT,
- TK_END
- };
-
- 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
- };
+ tokens.push_back(std::make_pair("?" , Token::TK_TERNARY_QUEST));
+ tokens.push_back(std::make_pair(":" , Token::TK_TERNARY_COLON));
+ tokens.push_back(std::make_pair("||", Token::TK_OR ));
+ tokens.push_back(std::make_pair("&&", Token::TK_AND ));
+ tokens.push_back(std::make_pair("==", Token::TK_EQUAL ));
+ tokens.push_back(std::make_pair("!=", Token::TK_NOT_EQUAL ));
+ tokens.push_back(std::make_pair("<=", Token::TK_LESS_EQUAL ));
+ tokens.push_back(std::make_pair("<" , Token::TK_LESS ));
+ tokens.push_back(std::make_pair(">=", Token::TK_GREATER_EQUAL));
+ tokens.push_back(std::make_pair(">" , Token::TK_GREATER ));
+ tokens.push_back(std::make_pair("%" , Token::TK_MODULUS ));
+ tokens.push_back(std::make_pair("n" , Token::TK_VARIABLE_N ));
+ tokens.push_back(std::make_pair("N" , Token::TK_VARIABLE_N ));
+ tokens.push_back(std::make_pair("(" , Token::TK_BRACKET_LEFT ));
+ tokens.push_back(std::make_pair(")" , Token::TK_BRACKET_RIGHT));
+ }
- class Scanner
+ Token nextToken()
{
- public:
- Scanner(const std::string& phrase) : stream(phrase), pos(stream.begin())
- {
- tokens.push_back(std::make_pair("?" , Token::TK_TERNARY_QUEST));
- tokens.push_back(std::make_pair(":" , Token::TK_TERNARY_COLON));
- tokens.push_back(std::make_pair("||", Token::TK_OR ));
- tokens.push_back(std::make_pair("&&", Token::TK_AND ));
- tokens.push_back(std::make_pair("==", Token::TK_EQUAL ));
- tokens.push_back(std::make_pair("!=", Token::TK_NOT_EQUAL ));
- tokens.push_back(std::make_pair("<=", Token::TK_LESS_EQUAL ));
- tokens.push_back(std::make_pair("<" , Token::TK_LESS ));
- tokens.push_back(std::make_pair(">=", Token::TK_GREATER_EQUAL));
- tokens.push_back(std::make_pair(">" , Token::TK_GREATER ));
- tokens.push_back(std::make_pair("%" , Token::TK_MODULUS ));
- tokens.push_back(std::make_pair("n" , Token::TK_VARIABLE_N ));
- tokens.push_back(std::make_pair("N" , Token::TK_VARIABLE_N ));
- tokens.push_back(std::make_pair("(" , Token::TK_BRACKET_LEFT ));
- tokens.push_back(std::make_pair(")" , Token::TK_BRACKET_RIGHT));
- }
-
- Token nextToken()
- {
- //skip whitespace
- pos = std::find_if(pos, stream.end(), [](char c) { return !zen::isWhiteSpace(c); });
+ //skip whitespace
+ pos = std::find_if(pos, stream_.end(), [](char c) { return !zen::isWhiteSpace(c); });
- if (pos == stream.end())
- return Token::TK_END;
+ if (pos == stream_.end())
+ return Token::TK_END;
- for (auto iter = tokens.begin(); iter != tokens.end(); ++iter)
- if (startsWith(iter->first))
- {
- pos += iter->first.size();
- return Token(iter->second);
- }
-
- auto digitEnd = std::find_if(pos, stream.end(), [](char c) { return !zen::isDigit(c); });
-
- if (digitEnd != pos)
+ for (auto iter = tokens.begin(); iter != tokens.end(); ++iter)
+ if (startsWith(iter->first))
{
- int number = zen::stringTo<int>(std::string(&*pos, digitEnd - pos));
- pos = digitEnd;
- return number;
+ pos += iter->first.size();
+ return Token(iter->second);
}
- throw ParsingError(); //unknown token
- }
+ auto digitEnd = std::find_if(pos, stream_.end(), [](char c) { return !zen::isDigit(c); });
- private:
- bool startsWith(const std::string& prefix) const
+ if (digitEnd != pos)
{
- if (stream.end() - pos < static_cast<ptrdiff_t>(prefix.size()))
- return false;
- return std::equal(prefix.begin(), prefix.end(), pos);
+ int number = zen::stringTo<int>(std::string(pos, digitEnd));
+ pos = digitEnd;
+ return number;
}
- typedef std::vector<std::pair<std::string, Token::Type> > TokenList;
- TokenList tokens;
+ throw ParsingError(); //unknown token
+ }
- const std::string stream;
- std::string::const_iterator pos;
- };
+private:
+ bool startsWith(const std::string& prefix) const
+ {
+ if (stream_.end() - pos < static_cast<ptrdiff_t>(prefix.size()))
+ return false;
+ return std::equal(prefix.begin(), prefix.end(), pos);
+ }
+ typedef std::vector<std::pair<std::string, Token::Type> > TokenList;
+ TokenList tokens;
+
+ const std::string stream_;
+ std::string::const_iterator pos;
+};
+
+//-------------------------------------------------------------------------------
+
+class Parser
+{
+public:
+ Parser(const std::string& stream, int& n) :
+ scn(stream),
+ tk(scn.nextToken()),
+ n_(n) {}
- class Parser
+ std::shared_ptr<Expr<int>> parse() //throw ParsingError; return value always bound!
{
- public:
- Parser(const std::string& phrase, //in
- const Expr<int>*& expr, int& n, PluralForm::DumpList& dump) : //out
- scn(phrase),
- tk(scn.nextToken()),
- n_(n),
- dump_(dump)
- {
- try
- {
- const Expression& e = parse(); //throw std::bad_cast, ParsingError
- expr = &dynamic_cast<const Expr<int>&>(e); //
- }
- catch (std::bad_cast&) { throw ParsingError(); }
+ auto e = std::dynamic_pointer_cast<Expr<int>>(parseExpression()); //throw ParsingError
+ if (!e)
+ throw ParsingError();
+ expectToken(Token::TK_END);
+ return e;
+ }
- consumeToken(Token::TK_END);
- }
+private:
+ std::shared_ptr<Expression> parseExpression() { return parseConditional(); }//throw ParsingError
- private:
- void nextToken() { tk = scn.nextToken(); }
- const Token& token() const { return tk; }
+ std::shared_ptr<Expression> parseConditional() //throw ParsingError
+ {
+ std::shared_ptr<Expression> e = parseLogicalOr();
- void consumeToken(Token::Type t) //throw ParsingError
+ if (token().type == Token::TK_TERNARY_QUEST)
{
- if (token().type != t)
- throw ParsingError();
nextToken();
- }
- const Expression& parse() { return parseConditional(); }; //throw std::bad_cast, ParsingError
+ auto ifExp = std::dynamic_pointer_cast<Expr<bool>>(e);
+ auto thenExp = std::dynamic_pointer_cast<Expr<int>>(parseExpression()); //associativity: <-
- const Expression& parseConditional()
- {
- const Expression& e = parseLogicalOr();
+ expectToken(Token::TK_TERNARY_COLON);
+ nextToken();
- if (token().type == Token::TK_TERNARY_QUEST)
- {
- nextToken();
- const Expression& thenEx = parse(); //associativity: <-
- consumeToken(Token::TK_TERNARY_COLON);
- const Expression& elseEx = parse(); //
-
- return manageObj(TernaryExp<int>(dynamic_cast<const Expr<bool>&>(e), //
- dynamic_cast<const Expr<int>&>(thenEx), //throw std::bad_cast
- dynamic_cast<const Expr<int>&>(elseEx))); //
- }
- return e;
+ auto elseExp = std::dynamic_pointer_cast<Expr<int>>(parseExpression()); //
+ if (!ifExp || !thenExp || !elseExp)
+ throw ParsingError();
+ return std::make_shared<ConditionalExp<int>>(ifExp, thenExp, elseExp);
}
+ return e;
+ }
- const Expression& parseLogicalOr()
+ std::shared_ptr<Expression> parseLogicalOr()
+ {
+ std::shared_ptr<Expression> e = parseLogicalAnd();
+ while (token().type == Token::TK_OR) //associativity: ->
{
- const Expression* e = &parseLogicalAnd();
- while (token().type == Token::TK_OR) //associativity: ->
- {
- nextToken();
- const Expression& rhs = parseLogicalAnd();
- e = &manageObj(makeBiExp(*e, rhs, std::logical_or<bool>())); //throw std::bad_cast
- }
- return *e;
+ nextToken();
+
+ std::shared_ptr<Expression> rhs = parseLogicalAnd();
+ e = makeBiExp(e, rhs, std::logical_or<bool>()); //throw ParsingError
}
+ return e;
+ }
- const Expression& parseLogicalAnd()
+ std::shared_ptr<Expression> parseLogicalAnd()
+ {
+ std::shared_ptr<Expression> e = parseEquality();
+ while (token().type == Token::TK_AND) //associativity: ->
{
- const Expression* e = &parseEquality();
- while (token().type == Token::TK_AND) //associativity: ->
- {
- nextToken();
- const Expression& rhs = parseEquality();
+ nextToken();
+ std::shared_ptr<Expression> rhs = parseEquality();
- e = &manageObj(makeBiExp(*e, rhs, std::logical_and<bool>())); //throw std::bad_cast
- }
- return *e;
+ e = makeBiExp(e, rhs, std::logical_and<bool>()); //throw ParsingError
}
+ return e;
+ }
- const Expression& parseEquality()
- {
- const Expression& e = parseRelational();
+ std::shared_ptr<Expression> parseEquality()
+ {
+ std::shared_ptr<Expression> e = parseRelational();
- Token::Type t = token().type;
- if (t == Token::TK_EQUAL || t == Token::TK_NOT_EQUAL) //associativity: n/a
- {
- nextToken();
- const Expression& rhs = parseRelational();
+ Token::Type t = token().type;
+ if (t == Token::TK_EQUAL || //associativity: n/a
+ t == Token::TK_NOT_EQUAL)
+ {
+ nextToken();
+ std::shared_ptr<Expression> rhs = parseRelational();
- if (t == Token::TK_EQUAL) return manageObj(makeBiExp(e, rhs, std::equal_to <int>())); //throw std::bad_cast
- if (t == Token::TK_NOT_EQUAL) return manageObj(makeBiExp(e, rhs, std::not_equal_to<int>())); //
- }
- return e;
+ 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>()); //
}
+ return e;
+ }
- const Expression& parseRelational()
- {
- const Expression& e = parseMultiplicative();
+ std::shared_ptr<Expression> parseRelational()
+ {
+ std::shared_ptr<Expression> e = parseMultiplicative();
- Token::Type t = token().type;
- if (t == Token::TK_LESS || //associativity: n/a
- t == Token::TK_LESS_EQUAL ||
- t == Token::TK_GREATER ||
- t == Token::TK_GREATER_EQUAL)
- {
- nextToken();
- const Expression& rhs = parseMultiplicative();
+ Token::Type t = token().type;
+ if (t == Token::TK_LESS || //associativity: n/a
+ t == Token::TK_LESS_EQUAL ||
+ t == Token::TK_GREATER ||
+ t == Token::TK_GREATER_EQUAL)
+ {
+ nextToken();
+ std::shared_ptr<Expression> rhs = parseMultiplicative();
- if (t == Token::TK_LESS) return manageObj(makeBiExp(e, rhs, std::less <int>())); //
- if (t == Token::TK_LESS_EQUAL) return manageObj(makeBiExp(e, rhs, std::less_equal <int>())); //throw std::bad_cast
- if (t == Token::TK_GREATER) return manageObj(makeBiExp(e, rhs, std::greater <int>())); //
- if (t == Token::TK_GREATER_EQUAL) return manageObj(makeBiExp(e, rhs, std::greater_equal<int>())); //
- }
- return e;
+ 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>()); //
}
+ return e;
+ }
- const Expression& parseMultiplicative()
- {
- const Expression* e = &parsePrimary();
+ std::shared_ptr<Expression> parseMultiplicative()
+ {
+ std::shared_ptr<Expression> e = parsePrimary();
- while (token().type == Token::TK_MODULUS) //associativity: ->
- {
- nextToken();
- const Expression& rhs = parsePrimary();
+ while (token().type == Token::TK_MODULUS) //associativity: ->
+ {
+ nextToken();
+ std::shared_ptr<Expression> rhs = parsePrimary();
- //"compile-time" check: n % 0
- if (auto literal = dynamic_cast<const ConstNumberExp*>(&rhs))
- if (literal->eval() == 0)
- throw ParsingError();
+ //"compile-time" check: n % 0
+ if (auto literal = std::dynamic_pointer_cast<ConstNumberExp>(rhs))
+ if (literal->eval() == 0)
+ throw ParsingError();
- e = &manageObj(makeBiExp(*e, rhs, std::modulus<int>())); //throw std::bad_cast
- }
- return *e;
+ e = makeBiExp(e, rhs, std::modulus<int>()); //throw ParsingError
}
+ return e;
+ }
- const Expression& parsePrimary()
+ std::shared_ptr<Expression> parsePrimary()
+ {
+ if (token().type == Token::TK_VARIABLE_N)
{
- if (token().type == Token::TK_VARIABLE_N)
- {
- nextToken();
- return manageObj(VariableNumberNExp(n_));
- }
- else if (token().type == Token::TK_CONST_NUMBER)
- {
- const int number = token().number;
- nextToken();
- return manageObj(ConstNumberExp(number));
- }
- else if (token().type == Token::TK_BRACKET_LEFT)
- {
- nextToken();
- const Expression& e = parse();
-
- consumeToken(Token::TK_BRACKET_RIGHT);
- return e;
- }
- else
- throw ParsingError();
+ nextToken();
+ return std::make_shared<VariableNumberNExp>(n_);
}
-
- template <class T>
- const T& manageObj(const T& obj)
+ else if (token().type == Token::TK_CONST_NUMBER)
{
- dump_.push_back(std::make_shared<T>(obj));
- return static_cast<T&>(*dump_.back());
+ const int number = token().number;
+ nextToken();
+ return std::make_shared<ConstNumberExp>(number);
}
+ else if (token().type == Token::TK_BRACKET_LEFT)
+ {
+ nextToken();
+ std::shared_ptr<Expression> e = parseExpression();
- Scanner scn;
- Token tk;
+ expectToken(Token::TK_BRACKET_RIGHT);
+ nextToken();
+ return e;
+ }
+ else
+ throw ParsingError();
+ }
- int& n_;
- DumpList& dump_; //manage polymorphc object lifetimes
- };
+ void nextToken() { tk = scn.nextToken(); }
+ const Token& token() const { return tk; }
- const Expr<int>* expr;
- mutable int n_;
+ void expectToken(Token::Type t) //throw ParsingError
+ {
+ if (token().type != t)
+ throw ParsingError();
+ }
- PluralForm::DumpList dump; //manage polymorphc object lifetimes
+ Scanner scn;
+ Token tk;
+ int& n_;
};
+}
+
+
+inline
+PluralForm::PluralForm(const std::string& stream) : expr(implementation::Parser(stream, n_).parse()) {} //throw ParsingError
+}
-#endif // PARSE_PLURAL_H_INCLUDED
+#endif // PARSE_PLURAL_H_INCLUDED \ No newline at end of file
diff --git a/lib/perf_check.cpp b/lib/perf_check.cpp
index c6a4e2d1..85a98910 100644
--- a/lib/perf_check.cpp
+++ b/lib/perf_check.cpp
@@ -98,34 +98,13 @@ wxString PerfCheck::getBytesPerSecond() const
const double timeDelta = recordBack.first - recordFront.first;
const double dataDelta = recordBack.second.data_ - recordFront.second.data_;
- if (!numeric::isNull(timeDelta))
- if (dataDelta > 0) //may be negative if user cancels copying
+ if (!numeric::isNull(timeDelta) && dataDelta > 0)
return filesizeToShortString(zen::Int64(dataDelta * 1000 / timeDelta)) + _("/sec");
}
return L"-"; //fallback
}
-wxString PerfCheck::getOverallBytesPerSecond() const //for all samples
-{
- warn_static("WTF!? tihs considers window only!")
-
- if (!samples.empty())
- {
- const auto& recordBack = *samples.rbegin();
- const auto& recordFront = *samples.begin();
- //-----------------------------------------------------------------------------------------------
- const double timeDelta = recordBack.first - recordFront.first;
- const double dataDelta = recordBack.second.data_ - recordFront.second.data_;
-
- if (!numeric::isNull(timeDelta))
- if (dataDelta > 0) //may be negative if user cancels copying
- return zen::filesizeToShortString(zen::Int64(dataDelta * 1000 / timeDelta)) + _("/sec");
- }
- return L"-"; //fallback
-}
-
-
/*
class for calculation of remaining time:
----------------------------------------
diff --git a/lib/perf_check.h b/lib/perf_check.h
index b60c31c9..f314f842 100644
--- a/lib/perf_check.h
+++ b/lib/perf_check.h
@@ -21,7 +21,6 @@ public:
wxString getRemainingTime(double dataRemaining) const;
wxString getBytesPerSecond() const; //for window
- wxString getOverallBytesPerSecond() const; //for all samples
private:
const long windowSizeRemTime; //unit: [ms]
diff --git a/lib/process_xml.cpp b/lib/process_xml.cpp
index a11f841c..e38749f9 100644
--- a/lib/process_xml.cpp
+++ b/lib/process_xml.cpp
@@ -75,7 +75,7 @@ void setXmlType(XmlDoc& doc, XmlType type) //throw()
wxString xmlAccess::getGlobalConfigFile()
{
- return toWx(zen::getConfigDir()) + wxT("GlobalSettings.xml");
+ return toWx(zen::getConfigDir()) + L"GlobalSettings.xml";
}
@@ -761,6 +761,64 @@ void writeStruc(const ColumnAttributeNavi& value, XmlElement& output)
out.attribute("Width", value.offset_);
out.attribute("Stretch", value.stretch_);
}
+
+
+template <> inline
+bool readStruc(const XmlElement& input, ViewFilterDefault& value)
+{
+ XmlIn in(input);
+
+ bool success = true;
+ auto readAttr = [&](XmlIn& elemIn, const char name[], bool& v)
+ {
+ if (!elemIn.attribute(name, v))
+ success = false;
+ };
+
+ XmlIn catView = in["CategoryView"];
+ readAttr(catView, "LeftOnly" , value.leftOnly);
+ readAttr(catView, "RightOnly" , value.rightOnly);
+ readAttr(catView, "LeftNewer" , value.leftNewer);
+ readAttr(catView, "RightNewer", value.rightNewer);
+ readAttr(catView, "Different" , value.different);
+ readAttr(catView, "Equal" , value.equal);
+ readAttr(catView, "Conflict" , value.conflict);
+
+ XmlIn actView = in["ActionView"];
+ readAttr(actView, "CreateLeft" , value.createLeft);
+ readAttr(actView, "CreateRight", value.createRight);
+ readAttr(actView, "UpdateLeft" , value.updateLeft);
+ readAttr(actView, "UpdateRight", value.updateRight);
+ readAttr(actView, "DeleteLeft" , value.deleteLeft);
+ readAttr(actView, "DeleteRight", value.deleteRight);
+ readAttr(actView, "DoNothing" , value.doNothing);
+
+ return success; //[!] avoid short-circuit evaluation above
+}
+
+template <> inline
+void writeStruc(const ViewFilterDefault& value, XmlElement& output)
+{
+ XmlOut out(output);
+
+ XmlOut catView = out["CategoryView"];
+ catView.attribute("LeftOnly" , value.leftOnly);
+ catView.attribute("RightOnly" , value.rightOnly);
+ catView.attribute("LeftNewer" , value.leftNewer);
+ catView.attribute("RightNewer", value.rightNewer);
+ catView.attribute("Different" , value.different);
+ catView.attribute("Equal" , value.equal);
+ catView.attribute("Conflict" , value.conflict);
+
+ XmlOut actView = out["ActionView"];
+ actView.attribute("CreateLeft" , value.createLeft);
+ actView.attribute("CreateRight", value.createRight);
+ actView.attribute("UpdateLeft" , value.updateLeft);
+ actView.attribute("UpdateRight", value.updateRight);
+ actView.attribute("DeleteLeft" , value.deleteLeft);
+ actView.attribute("DeleteRight", value.deleteRight);
+ actView.attribute("DoNothing" , value.doNothing);
+}
}
@@ -798,8 +856,12 @@ void readConfig(const XmlIn& in, SyncConfig& syncCfg)
in["CustomDeletionFolder"](syncCfg.versioningDirectory);//obsolete name
else
in["VersioningFolder"](syncCfg.versioningDirectory);
+
warn_static("remove after migration?")
- if (in["VersioningStyle"]) //new parameter
+ if (in["VersioningFolder"] &&
+ in["VersioningFolder"].get()->getAttribute("Style", syncCfg.versioningStyle)) //new parameter, do not complain when missing
+ ;
+ else if (in["VersioningStyle"]) //obsolete name
in["VersioningStyle"](syncCfg.versioningStyle);
else
syncCfg.versioningStyle = VER_STYLE_ADD_TIMESTAMP; //obsolete fallback
@@ -921,7 +983,16 @@ void readConfig(const XmlIn& in, xmlAccess::XmlGuiConfig& config)
inGuiCfg["HideExcluded"](config.hideExcludedItems);
inGuiCfg["HandleError" ](config.handleError);
- inGuiCfg["SyncPreviewActive"](config.showSyncAction);
+
+ warn_static("remove after migration?")
+ if (inGuiCfg["SyncPreviewActive"]) //obsolete name
+ inGuiCfg["SyncPreviewActive"](config.showSyncAction);
+ else
+ {
+ std::string val;
+ if (inGuiCfg["MiddleGridView"](val)) //refactor into enum!?
+ config.showSyncAction = val == "Action";
+ }
}
@@ -1003,7 +1074,7 @@ void readConfig(const XmlIn& in, XmlGlobalSettings& config)
inWnd.attribute("Maximized", config.gui.isMaximized);
XmlIn inManualDel = inWnd["ManualDeletion"];
- inManualDel.attribute("DeleteOnBothSides", config.gui.deleteOnBothSides);
+ //inManualDel.attribute("DeleteOnBothSides", config.gui.deleteOnBothSides);
inManualDel.attribute("UseRecycler" , config.gui.useRecyclerForManualDeletion);
inWnd["CaseSensitiveSearch" ](config.gui.textSearchRespectCase);
@@ -1031,7 +1102,8 @@ void readConfig(const XmlIn& in, XmlGlobalSettings& config)
inColRight(config.gui.columnAttribRight);
//###########################################################
- inWnd["Layout"](config.gui.guiPerspectiveLast);
+ inWnd["ViewFilterDefault"](config.gui.viewFilterDefault);
+ inWnd["Layout" ](config.gui.guiPerspectiveLast);
//load config file history
warn_static("remove after migration?")
@@ -1140,7 +1212,7 @@ void writeConfig(const SyncConfig& syncCfg, XmlOut& out)
out["DeletionPolicy" ](syncCfg.handleDeletion);
out["VersioningFolder"](syncCfg.versioningDirectory);
//out["VersioningFolder"].attribute("Limit", syncCfg.versionCountLimit);
- out["VersioningStyle"](syncCfg.versioningStyle);
+ out["VersioningFolder"].attribute("Style", syncCfg.versioningStyle);
}
@@ -1234,9 +1306,9 @@ void writeConfig(const XmlGuiConfig& config, XmlOut& out)
//write GUI specific config data
XmlOut outGuiCfg = out["GuiConfig"];
- outGuiCfg["HideExcluded" ](config.hideExcludedItems);
- outGuiCfg["HandleError" ](config.handleError);
- outGuiCfg["SyncPreviewActive"](config.showSyncAction);
+ outGuiCfg["HideExcluded" ](config.hideExcludedItems);
+ outGuiCfg["HandleError" ](config.handleError);
+ outGuiCfg["MiddleGridView"](config.showSyncAction ? "Action" : "Category"); //refactor into enum!?
}
void writeConfig(const XmlBatchConfig& config, XmlOut& out)
@@ -1296,7 +1368,7 @@ void writeConfig(const XmlGlobalSettings& config, XmlOut& out)
outWnd.attribute("Maximized", config.gui.isMaximized);
XmlOut outManualDel = outWnd["ManualDeletion"];
- outManualDel.attribute("DeleteOnBothSides", config.gui.deleteOnBothSides);
+ //outManualDel.attribute("DeleteOnBothSides", config.gui.deleteOnBothSides);
outManualDel.attribute("UseRecycler" , config.gui.useRecyclerForManualDeletion);
outWnd["CaseSensitiveSearch" ](config.gui.textSearchRespectCase);
@@ -1323,7 +1395,8 @@ void writeConfig(const XmlGlobalSettings& config, XmlOut& out)
outColRight(config.gui.columnAttribRight);
//###########################################################
- outWnd["Layout"](config.gui.guiPerspectiveLast);
+ outWnd["ViewFilterDefault"](config.gui.viewFilterDefault);
+ outWnd["Layout" ](config.gui.guiPerspectiveLast);
//load config file history
outGui["LastUsedConfig"](config.gui.lastUsedConfigFiles);
diff --git a/lib/process_xml.h b/lib/process_xml.h
index 29237081..d0396d6e 100644
--- a/lib/process_xml.h
+++ b/lib/process_xml.h
@@ -112,6 +112,18 @@ enum FileIconSize
};
+struct ViewFilterDefault
+{
+ ViewFilterDefault() : equal(false)
+ {
+ leftOnly = rightOnly = leftNewer = rightNewer = different = conflict = true;
+ createLeft = createRight = updateLeft = updateRight = deleteLeft = deleteRight = doNothing = true;
+ }
+ bool equal;
+ bool leftOnly, rightOnly, leftNewer, rightNewer, different, conflict; //category view
+ bool createLeft, createRight, updateLeft, updateRight, deleteLeft, deleteRight, doNothing; //action view
+};
+
wxString getGlobalConfigFile();
struct XmlGlobalSettings
@@ -161,7 +173,7 @@ struct XmlGlobalSettings
cfgFileHistMax(30),
folderHistMax(15),
onCompletionHistoryMax(8),
- deleteOnBothSides(false),
+ //deleteOnBothSides(false),
useRecyclerForManualDeletion(true), //enable if OS supports it; else user will have to activate first and then get an error message
#ifdef FFS_WIN
textSearchRespectCase(false),
@@ -216,7 +228,7 @@ struct XmlGlobalSettings
std::vector<std::wstring> onCompletionHistory;
size_t onCompletionHistoryMax;
- bool deleteOnBothSides;
+ //bool deleteOnBothSides;
bool useRecyclerForManualDeletion;
bool textSearchRespectCase;
@@ -225,6 +237,7 @@ struct XmlGlobalSettings
long lastUpdateCheck; //time of last update check
+ ViewFilterDefault viewFilterDefault;
wxString guiPerspectiveLast; //used by wxAuiManager
} gui;
diff --git a/lib/resources.cpp b/lib/resources.cpp
index 7d46739e..2f7daeaf 100644
--- a/lib/resources.cpp
+++ b/lib/resources.cpp
@@ -87,8 +87,8 @@ GlobalResources::GlobalResources()
const wxBitmap& GlobalResources::getImageInt(const wxString& imageName) const
{
auto it = bitmaps.find(!contains(imageName, L'.') ? //assume .png ending if nothing else specified
- imageName + L".png" :
- imageName);
+ imageName + L".png" :
+ imageName);
if (it != bitmaps.end())
return it->second;
else
diff --git a/lib/status_handler.cpp b/lib/status_handler.cpp
index c24c6f50..fd3b2d96 100644
--- a/lib/status_handler.cpp
+++ b/lib/status_handler.cpp
@@ -22,7 +22,7 @@ void zen::updateUiNow()
namespace
{
-const std::int64_t TICKS_UPDATE_INTERVAL = UI_UPDATE_INTERVAL* ticksPerSec() / 1000;
+const std::int64_t TICKS_UPDATE_INTERVAL = UI_UPDATE_INTERVAL * ticksPerSec() / 1000;
TickVal lastExec = getTicks();
};
diff --git a/lib/status_handler.h b/lib/status_handler.h
index 93f9892c..ed496824 100644
--- a/lib/status_handler.h
+++ b/lib/status_handler.h
@@ -67,7 +67,7 @@ protected:
refNumbers(numbersTotal_, currentPhase_) = std::make_pair(objectsTotal, dataTotal);
}
- virtual void updateProcessedData(int objectsDelta, Int64 dataDelta) { updateData(numbersCurrent_, objectsDelta, dataDelta); } //note: these methods should NOT throw in order
+ virtual void updateProcessedData(int objectsDelta, Int64 dataDelta) { updateData(numbersCurrent_, objectsDelta, dataDelta); } //note: these methods MUST NOT throw in order
virtual void updateTotalData (int objectsDelta, Int64 dataDelta) { updateData(numbersTotal_ , objectsDelta, dataDelta); } //to properly allow undoing setting of statistics!
virtual void requestUiRefresh()
diff --git a/lib/versioning.cpp b/lib/versioning.cpp
index d4b6e2b2..a72433cc 100644
--- a/lib/versioning.cpp
+++ b/lib/versioning.cpp
@@ -226,8 +226,26 @@ private:
}
-void FileVersioner::revisionFile(const Zstring& sourceFile, const Zstring& relativeName, CallbackMoveFile& callback) //throw FileError
+bool FileVersioner::revisionFile(const Zstring& sourceFile, const Zstring& relativeName, CallbackMoveFile& callback) //throw FileError
{
+ struct CallbackMoveFileImpl : public CallbackMoveDir
+ {
+ CallbackMoveFileImpl(CallbackMoveFile& callback) : callback_(callback) {}
+ private:
+ virtual void onBeforeFileMove(const Zstring& fileFrom, const Zstring& fileTo) {}
+ virtual void onBeforeDirMove (const Zstring& dirFrom, const Zstring& dirTo ) {}
+ virtual void updateStatus(Int64 bytesDelta) { callback_.updateStatus(bytesDelta); }
+ CallbackMoveFile& callback_;
+ } cb(callback);
+
+ return revisionFileImpl(sourceFile, relativeName, cb); //throw FileError
+}
+
+
+bool FileVersioner::revisionFileImpl(const Zstring& sourceFile, const Zstring& relativeName, CallbackMoveDir& callback) //throw FileError
+{
+ bool moveSuccessful = false;
+
moveItemToVersioning(sourceFile, //throw FileError
relativeName,
versioningDirectory_,
@@ -235,26 +253,38 @@ void FileVersioner::revisionFile(const Zstring& sourceFile, const Zstring& relat
versioningStyle_,
[&](const Zstring& source, const Zstring& target)
{
+ callback.onBeforeFileMove(source, target); //if we're called by revisionDirImpl() we know that "source" exists!
+ //when called by revisionFile(), "source" might not exist, however onBeforeFileMove() is not propagated in this case!
+
struct CopyCallbackImpl : public CallbackCopyFile
{
- CopyCallbackImpl(CallbackMoveFile& callback) : callback_(callback) {}
+ CopyCallbackImpl(CallbackMoveDir& callback) : callback_(callback) {}
private:
virtual void deleteTargetFile(const Zstring& targetFile) { assert(!somethingExists(targetFile)); }
virtual void updateCopyStatus(Int64 bytesDelta) { callback_.updateStatus(bytesDelta); }
- CallbackMoveFile& callback_;
+ CallbackMoveDir& callback_;
} copyCallback(callback);
- callback.onBeforeFileMove(source, target);
moveFile(source, target, copyCallback); //throw FileError
- callback.objectProcessed();
+ moveSuccessful = true;
});
+ return moveSuccessful;
+}
+
- //fileRelNames.push_back(relativeName);
+void FileVersioner::revisionDir(const Zstring& sourceDir, const Zstring& relativeName, CallbackMoveDir& callback) //throw FileError
+{
+ //no error situation if directory is not existing! manual deletion relies on it!
+ if (!somethingExists(sourceDir))
+ return; //neither directory nor any other object (e.g. broken symlink) with that name existing
+ revisionDirImpl(sourceDir, relativeName, callback); //throw FileError
}
-void FileVersioner::revisionDir(const Zstring& sourceDir, const Zstring& relativeName, CallbackMoveFile& callback) //throw FileError
+void FileVersioner::revisionDirImpl(const Zstring& sourceDir, const Zstring& relativeName, CallbackMoveDir& callback) //throw FileError
{
+ assert(somethingExists(sourceDir)); //[!]
+
//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!
{
@@ -267,10 +297,7 @@ void FileVersioner::revisionDir(const Zstring& sourceDir, const Zstring& relativ
{
callback.onBeforeDirMove(source, target);
moveDirSymlink(source, target); //throw FileError
- callback.objectProcessed();
});
-
- //fileRelNames.push_back(relativeName);
}
else
{
@@ -278,24 +305,15 @@ void FileVersioner::revisionDir(const Zstring& sourceDir, const Zstring& relativ
assert(endsWith(sourceDir, relativeName)); //usually, yes, but we might relax this in the future
const Zstring targetDir = appendSeparator(versioningDirectory_) + relativeName;
- callback.onBeforeDirMove(sourceDir, targetDir);
-
//makeDirectory(targetDir); //FileError -> create only when needed in moveFileToVersioning(); avoids empty directories
//traverse source directory one level
std::vector<Zstring> fileList; //list of *short* names
std::vector<Zstring> dirList; //
- try
{
TraverseFilesOneLevel tol(fileList, dirList); //throw FileError
traverseFolder(sourceDir, tol); //
}
- catch (FileError&)
- {
- if (!somethingExists(sourceDir)) //no source at all is not an error (however a file as source when a directory is expected, *is* an error!)
- return; //object *not* processed
- throw;
- }
const Zstring sourceDirPf = appendSeparator(sourceDir);
const Zstring relnamePf = appendSeparator(relativeName);
@@ -304,33 +322,23 @@ void FileVersioner::revisionDir(const Zstring& sourceDir, const Zstring& relativ
std::for_each(fileList.begin(), fileList.end(),
[&](const Zstring& shortname)
{
- revisionFile(sourceDirPf + shortname, //throw FileError
- relnamePf + shortname,
- callback);
+ revisionFileImpl(sourceDirPf + shortname, //throw FileError
+ relnamePf + shortname,
+ callback);
});
//move items in subdirectories
std::for_each(dirList.begin(), dirList.end(),
[&](const Zstring& shortname)
{
- revisionDir(sourceDirPf + shortname, //throw FileError
- relnamePf + shortname,
- callback);
+ revisionDirImpl(sourceDirPf + shortname, //throw FileError
+ relnamePf + shortname,
+ callback);
});
//delete source
- 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();
+ callback.onBeforeDirMove(sourceDir, targetDir);
+ removeDirectory(sourceDir); //throw FileError
}
}
diff --git a/lib/versioning.h b/lib/versioning.h
index 3e0dd33c..faa96359 100644
--- a/lib/versioning.h
+++ b/lib/versioning.h
@@ -17,6 +17,7 @@
namespace zen
{
+struct CallbackMoveDir;
struct CallbackMoveFile;
//e.g. move C:\Source\subdir\Sample.txt -> D:\Revisions\subdir\Sample.txt 2012-05-15 131513.txt
@@ -42,15 +43,18 @@ 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 time stamp for versioning:") + L" \'" + timeStamp_ + L"\'");
+ throw FileError(_("Failure to create timestamp for versioning:") + L" \'" + timeStamp_ + L"\'");
}
- void revisionFile(const Zstring& sourceFile, const Zstring& relativeName, CallbackMoveFile& callback); //throw FileError
- void revisionDir (const Zstring& sourceDir, const Zstring& relativeName, CallbackMoveFile& callback); //throw FileError
+ bool revisionFile(const Zstring& sourceFile, const Zstring& relativeName, CallbackMoveFile& callback); //throw FileError; return "false" if file is not existing
+ void revisionDir (const Zstring& sourceDir, const Zstring& relativeName, CallbackMoveDir& callback); //throw FileError
//void limitVersions(std::function<void()> updateUI); //throw FileError; call when done revisioning!
private:
+ bool revisionFileImpl(const Zstring& sourceFile, const Zstring& relativeName, CallbackMoveDir& callback); //throw FileError
+ void revisionDirImpl (const Zstring& sourceDir, const Zstring& relativeName, CallbackMoveDir& callback); //throw FileError
+
const VersioningStyle versioningStyle_;
const Zstring versioningDirectory_;
const Zstring timeStamp_;
@@ -59,22 +63,20 @@ private:
};
-struct CallbackMoveFile
+struct CallbackMoveFile //see CallbackCopyFile for limitations when throwing exceptions!
{
- virtual ~CallbackMoveFile() {} //see CallbackCopyFile for limitations when throwing exceptions!
-
- virtual void onBeforeFileMove(const Zstring& fileFrom, const Zstring& fileTo) = 0; //one call before each (planned) move
- virtual void onBeforeDirMove (const Zstring& dirFrom, const Zstring& dirTo ) = 0; //
- virtual void objectProcessed() = 0; //one call after each completed move (count objects total)
-
- //called frequently if move has to revert to copy + delete:
- virtual void updateStatus(Int64 bytesDelta) = 0;
+ virtual ~CallbackMoveFile() {}
+ virtual void updateStatus(Int64 bytesDelta) = 0; //called frequently if move has to revert to copy + delete:
};
+struct CallbackMoveDir //see CallbackCopyFile for limitations when throwing exceptions!
+{
+ virtual ~CallbackMoveDir() {}
-
-
-
+ virtual void onBeforeFileMove(const Zstring& fileFrom, const Zstring& fileTo) = 0; //one call for each *existing* object!
+ virtual void onBeforeDirMove (const Zstring& dirFrom, const Zstring& dirTo ) = 0; //
+ virtual void updateStatus(Int64 bytesDelta) = 0; //called frequently if move has to revert to copy + delete:
+};
bgstack15