summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorB Stack <bgstack15@gmail.com>2020-03-18 08:59:09 -0400
committerB Stack <bgstack15@gmail.com>2020-03-18 08:59:09 -0400
commit2c4db439d235b68478d90c450289d2d0ba418547 (patch)
tree5c378aa54f4bb65c081cf9a92530d8af1f1f53dd
parentMerge branch '10.20' into 'master' (diff)
downloadFreeFileSync-2c4db439d235b68478d90c450289d2d0ba418547.tar.gz
FreeFileSync-2c4db439d235b68478d90c450289d2d0ba418547.tar.bz2
FreeFileSync-2c4db439d235b68478d90c450289d2d0ba418547.zip
add upstream 10.21
-rwxr-xr-xBugs.txt24
-rwxr-xr-xChangelog.txt22
-rw-r--r--FreeFileSync/Build/Resources/Icons.zipbin389295 -> 388959 bytes
-rw-r--r--FreeFileSync/Build/Resources/Languages.zipbin522133 -> 522150 bytes
-rwxr-xr-x[-rw-r--r--]FreeFileSync/Source/Makefile18
-rwxr-xr-xFreeFileSync/Source/RealTimeSync/Makefile7
-rw-r--r--FreeFileSync/Source/RealTimeSync/application.cpp18
-rw-r--r--FreeFileSync/Source/RealTimeSync/config.cpp4
-rw-r--r--FreeFileSync/Source/RealTimeSync/gui_generated.cpp8
-rw-r--r--FreeFileSync/Source/RealTimeSync/gui_generated.h3
-rw-r--r--FreeFileSync/Source/RealTimeSync/main_dlg.cpp9
-rw-r--r--FreeFileSync/Source/RealTimeSync/main_dlg.h1
-rw-r--r--FreeFileSync/Source/RealTimeSync/monitor.cpp4
-rw-r--r--FreeFileSync/Source/RealTimeSync/tray_menu.cpp2
-rw-r--r--FreeFileSync/Source/afs/abstract.cpp6
-rw-r--r--FreeFileSync/Source/afs/abstract.h10
-rw-r--r--FreeFileSync/Source/afs/abstract_impl.h2
-rw-r--r--FreeFileSync/Source/afs/ftp.cpp42
-rw-r--r--FreeFileSync/Source/afs/ftp_common.h14
-rw-r--r--FreeFileSync/Source/afs/gdrive.cpp54
-rw-r--r--FreeFileSync/Source/afs/native.cpp13
-rw-r--r--FreeFileSync/Source/afs/sftp.cpp45
-rw-r--r--FreeFileSync/Source/application.cpp (renamed from FreeFileSync/Source/base/application.cpp)56
-rw-r--r--FreeFileSync/Source/application.h (renamed from FreeFileSync/Source/base/application.h)0
-rw-r--r--FreeFileSync/Source/base/algorithm.cpp16
-rw-r--r--FreeFileSync/Source/base/algorithm.h3
-rw-r--r--FreeFileSync/Source/base/binary.cpp2
-rw-r--r--FreeFileSync/Source/base/comparison.cpp155
-rw-r--r--FreeFileSync/Source/base/comparison.h5
-rw-r--r--FreeFileSync/Source/base/db_file.cpp137
-rw-r--r--FreeFileSync/Source/base/dir_exist_async.h2
-rw-r--r--FreeFileSync/Source/base/dir_lock.cpp14
-rw-r--r--FreeFileSync/Source/base/file_hierarchy.cpp24
-rw-r--r--FreeFileSync/Source/base/file_hierarchy.h29
-rw-r--r--FreeFileSync/Source/base/lock_holder.h6
-rw-r--r--FreeFileSync/Source/base/parallel_scan.cpp10
-rw-r--r--FreeFileSync/Source/base/parallel_scan.h4
-rw-r--r--FreeFileSync/Source/base/path_filter.h6
-rw-r--r--FreeFileSync/Source/base/resolve_path.cpp18
-rw-r--r--FreeFileSync/Source/base/status_handler_impl.h6
-rw-r--r--FreeFileSync/Source/base/structures.cpp327
-rw-r--r--FreeFileSync/Source/base/structures.h45
-rw-r--r--FreeFileSync/Source/base/synchronization.cpp85
-rw-r--r--FreeFileSync/Source/base/synchronization.h15
-rw-r--r--FreeFileSync/Source/base/versioning.cpp10
-rw-r--r--FreeFileSync/Source/base/versioning.h4
-rw-r--r--FreeFileSync/Source/base_tools.cpp357
-rw-r--r--FreeFileSync/Source/base_tools.h33
-rw-r--r--FreeFileSync/Source/config.cpp (renamed from FreeFileSync/Source/base/config.cpp)41
-rw-r--r--FreeFileSync/Source/config.h (renamed from FreeFileSync/Source/base/config.h)48
-rw-r--r--FreeFileSync/Source/fatal_error.h (renamed from FreeFileSync/Source/base/fatal_error.h)2
-rw-r--r--FreeFileSync/Source/ffs_paths.cpp (renamed from FreeFileSync/Source/base/ffs_paths.cpp)0
-rw-r--r--FreeFileSync/Source/ffs_paths.h (renamed from FreeFileSync/Source/base/ffs_paths.h)0
-rw-r--r--FreeFileSync/Source/help_provider.h (renamed from FreeFileSync/Source/base/help_provider.h)0
-rw-r--r--FreeFileSync/Source/icon_buffer.cpp (renamed from FreeFileSync/Source/base/icon_buffer.cpp)2
-rw-r--r--FreeFileSync/Source/icon_buffer.h (renamed from FreeFileSync/Source/base/icon_buffer.h)2
-rw-r--r--FreeFileSync/Source/localization.cpp (renamed from FreeFileSync/Source/base/localization.cpp)0
-rw-r--r--FreeFileSync/Source/localization.h (renamed from FreeFileSync/Source/base/localization.h)0
-rw-r--r--FreeFileSync/Source/log_file.cpp (renamed from FreeFileSync/Source/base/log_file.cpp)180
-rw-r--r--FreeFileSync/Source/log_file.h (renamed from FreeFileSync/Source/base/log_file.h)13
-rw-r--r--FreeFileSync/Source/parse_lng.h (renamed from FreeFileSync/Source/base/parse_lng.h)6
-rw-r--r--FreeFileSync/Source/parse_plural.h (renamed from FreeFileSync/Source/base/parse_plural.h)0
-rw-r--r--FreeFileSync/Source/perf_check.cpp (renamed from FreeFileSync/Source/base/perf_check.cpp)0
-rw-r--r--FreeFileSync/Source/perf_check.h (renamed from FreeFileSync/Source/base/perf_check.h)0
-rw-r--r--FreeFileSync/Source/return_codes.h (renamed from FreeFileSync/Source/base/return_codes.h)2
-rw-r--r--FreeFileSync/Source/status_handler.cpp (renamed from FreeFileSync/Source/base/status_handler.cpp)0
-rw-r--r--FreeFileSync/Source/status_handler.h (renamed from FreeFileSync/Source/base/status_handler.h)2
-rw-r--r--FreeFileSync/Source/ui/abstract_folder_picker.cpp4
-rw-r--r--FreeFileSync/Source/ui/batch_config.cpp2
-rw-r--r--FreeFileSync/Source/ui/batch_config.h2
-rw-r--r--FreeFileSync/Source/ui/batch_status_handler.cpp27
-rw-r--r--FreeFileSync/Source/ui/batch_status_handler.h8
-rw-r--r--FreeFileSync/Source/ui/cfg_grid.cpp22
-rw-r--r--FreeFileSync/Source/ui/cfg_grid.h2
-rw-r--r--FreeFileSync/Source/ui/file_grid.cpp12
-rw-r--r--FreeFileSync/Source/ui/file_grid.h2
-rw-r--r--FreeFileSync/Source/ui/folder_pair.h2
-rw-r--r--FreeFileSync/Source/ui/folder_selector.cpp3
-rw-r--r--FreeFileSync/Source/ui/gui_generated.cpp180
-rw-r--r--FreeFileSync/Source/ui/gui_generated.h27
-rw-r--r--FreeFileSync/Source/ui/gui_status_handler.cpp36
-rw-r--r--FreeFileSync/Source/ui/gui_status_handler.h6
-rw-r--r--FreeFileSync/Source/ui/log_panel.cpp75
-rw-r--r--FreeFileSync/Source/ui/main_dlg.cpp88
-rw-r--r--FreeFileSync/Source/ui/main_dlg.h6
-rw-r--r--FreeFileSync/Source/ui/progress_indicator.cpp22
-rw-r--r--FreeFileSync/Source/ui/progress_indicator.h6
-rw-r--r--FreeFileSync/Source/ui/small_dlgs.cpp98
-rw-r--r--FreeFileSync/Source/ui/small_dlgs.h2
-rw-r--r--FreeFileSync/Source/ui/sync_cfg.cpp47
-rw-r--r--FreeFileSync/Source/ui/sync_cfg.h2
-rw-r--r--FreeFileSync/Source/ui/tree_grid.cpp6
-rw-r--r--FreeFileSync/Source/ui/version_check.cpp4
-rw-r--r--FreeFileSync/Source/version/version.h2
-rw-r--r--libcurl/curl_wrap.h5
-rw-r--r--libcurl/rest.cpp14
-rw-r--r--libssh2/libssh2_wrap.h6
-rw-r--r--wx+/file_drop.cpp25
-rw-r--r--wx+/file_drop.h3
-rw-r--r--wx+/grid.cpp2
-rw-r--r--wx+/image_resources.cpp2
-rw-r--r--wx+/image_tools.cpp2
-rw-r--r--wx+/popup_dlg.cpp8
-rw-r--r--xBRZ/src/xbrz.cpp271
-rw-r--r--zen/basic_math.h16
-rw-r--r--zen/crc.h58
-rw-r--r--zen/dir_watcher.cpp3
-rw-r--r--zen/error_log.h85
-rw-r--r--zen/file_access.cpp4
-rw-r--r--zen/file_io.cpp6
-rw-r--r--zen/file_io.h2
-rw-r--r--zen/format_unit.cpp5
-rw-r--r--zen/guid.h12
-rw-r--r--zen/http.cpp42
-rw-r--r--zen/http.h8
-rw-r--r--zen/legacy_compiler.h17
-rw-r--r--zen/open_ssl.cpp31
-rw-r--r--zen/perf.h2
-rw-r--r--zen/recycler.cpp4
-rw-r--r--zen/serialize.h38
-rw-r--r--zen/shell_execute.h4
-rw-r--r--zen/socket.h4
-rw-r--r--zen/string_base.h32
-rw-r--r--zen/string_tools.h12
-rw-r--r--zen/string_traits.h3
-rw-r--r--zen/sys_error.cpp184
-rw-r--r--zen/sys_error.h62
-rw-r--r--zen/system.cpp31
-rw-r--r--zen/thread.cpp2
-rw-r--r--zen/thread.h2
-rw-r--r--zen/time.h184
-rw-r--r--zen/zlib_wrap.cpp14
-rw-r--r--zen/zlib_wrap.h6
-rw-r--r--zen/zstring.cpp3
-rw-r--r--zen/zstring.h7
-rw-r--r--zenXml/zenxml/cvrt_struc.h10
-rw-r--r--zenXml/zenxml/dom.h2
-rw-r--r--zenXml/zenxml/xml.h12
138 files changed, 2109 insertions, 1802 deletions
diff --git a/Bugs.txt b/Bugs.txt
index fe61dc97..9d0592c8 100755
--- a/Bugs.txt
+++ b/Bugs.txt
@@ -5,27 +5,25 @@ the ones mentioned below. The remaining issues that are yet to be fixed are list
-----------------
-| libcurl 7.6.7 |
+| libcurl 7.6.9 |
-----------------
__________________________________________________________________________________________________________
/lib/ftp.c
https://github.com/curl/curl/issues/1455
-Add:
- static bool is_routable_ip_v4(unsigned int ip[4])
- {
- if (ip[0] == 127 || //127.0.0.0/8 (localhost)
- ip[0] == 10 || //10.0.0.0/8 (private)
- (ip[0] == 192 && ip[1] == 168) || //192.168.0.0/16 (private)
- (ip[0] == 169 && ip[1] == 254) || //169.254.0.0/16 (link-local)
- (ip[0] == 172 && ip[1] / 16 == 1)) //172.16.0.0/12 (private)
- return false;
- return true;
- }
++ static bool is_routable_ip_v4(unsigned int ip[4])
++ {
++ if (ip[0] == 127 || //127.0.0.0/8 (localhost)
++ ip[0] == 10 || //10.0.0.0/8 (private)
++ (ip[0] == 192 && ip[1] == 168) || //192.168.0.0/16 (private)
++ (ip[0] == 169 && ip[1] == 254) || //169.254.0.0/16 (link-local)
++ (ip[0] == 172 && ip[1] / 16 == 1)) //172.16.0.0/12 (private)
++ return false;
++ return true;
++ }
- if (data->set.ftp_skip_ip)
-
+ bool skipIp = data->set.ftp_skip_ip;
+ if (!skipIp && !is_routable_ip_v4(ip))
+ {
diff --git a/Changelog.txt b/Changelog.txt
index a4103889..cc6a1c8a 100755
--- a/Changelog.txt
+++ b/Changelog.txt
@@ -1,9 +1,27 @@
+FreeFileSync 10.21 [2020-03-17]
+-------------------------------
+Preselect last-used email address
+Select log file format (HTML or plain text)
+Aggregate email notifications when hitting sending limits
+Show code literals in system error messages
+Limit conflict item count for log file warning message
+Show log icon error indicator even if error occured after sync
+Disable background drag & drop when showing modal dialog
+Hide dummy model, vendor names in log files
+Fixed ANSI encoding used for log file time formatting
+Reduced memory consumption for large number of log messages
+Correctly parse lock files despite corrupted trail data
+Show emoji instead of Unicode icon in email subject
+Fixed IWbemServices::ConnectServer error after sync
+Fixed aggregate email logs incomplete truncation
+
+
FreeFileSync 10.20 [2020-02-14]
-------------------------------
-Send email notifications after sync
+Send email notifications after sync (Donation Edition)
Generate log files in HTML format
Detect sync database consistency errors
-Start log file with preview of first 50 errors/warnings
+Start log file with preview of first 25 errors/warnings
Mitigate lock file data corruption
Print Windows error codes in hexadecimal
Fixed missing MTP and network links in folder picker (Linux)
diff --git a/FreeFileSync/Build/Resources/Icons.zip b/FreeFileSync/Build/Resources/Icons.zip
index 79a4dd7f..0a393bbc 100644
--- a/FreeFileSync/Build/Resources/Icons.zip
+++ b/FreeFileSync/Build/Resources/Icons.zip
Binary files differ
diff --git a/FreeFileSync/Build/Resources/Languages.zip b/FreeFileSync/Build/Resources/Languages.zip
index 81e8e960..3f00d604 100644
--- a/FreeFileSync/Build/Resources/Languages.zip
+++ b/FreeFileSync/Build/Resources/Languages.zip
Binary files differ
diff --git a/FreeFileSync/Source/Makefile b/FreeFileSync/Source/Makefile
index 87352ea4..5d4f6b20 100644..100755
--- a/FreeFileSync/Source/Makefile
+++ b/FreeFileSync/Source/Makefile
@@ -28,24 +28,25 @@ LINKFLAGS += `pkg-config --libs libselinux`
endif
CPP_FILES=
+CPP_FILES+=application.cpp
+CPP_FILES+=base_tools.cpp
+CPP_FILES+=config.cpp
+CPP_FILES+=ffs_paths.cpp
+CPP_FILES+=icon_buffer.cpp
+CPP_FILES+=localization.cpp
+CPP_FILES+=log_file.cpp
+CPP_FILES+=perf_check.cpp
+CPP_FILES+=status_handler.cpp
CPP_FILES+=base/algorithm.cpp
-CPP_FILES+=base/application.cpp
CPP_FILES+=base/binary.cpp
CPP_FILES+=base/comparison.cpp
-CPP_FILES+=base/config.cpp
CPP_FILES+=base/db_file.cpp
CPP_FILES+=base/dir_lock.cpp
-CPP_FILES+=base/ffs_paths.cpp
CPP_FILES+=base/file_hierarchy.cpp
-CPP_FILES+=base/icon_buffer.cpp
CPP_FILES+=base/icon_loader.cpp
-CPP_FILES+=base/localization.cpp
-CPP_FILES+=base/log_file.cpp
CPP_FILES+=base/parallel_scan.cpp
CPP_FILES+=base/path_filter.cpp
-CPP_FILES+=base/perf_check.cpp
CPP_FILES+=base/resolve_path.cpp
-CPP_FILES+=base/status_handler.cpp
CPP_FILES+=base/structures.cpp
CPP_FILES+=base/synchronization.cpp
CPP_FILES+=base/versioning.cpp
@@ -90,6 +91,7 @@ CPP_FILES+=../../zen/legacy_compiler.cpp
CPP_FILES+=../../zen/open_ssl.cpp
CPP_FILES+=../../zen/process_priority.cpp
CPP_FILES+=../../zen/shutdown.cpp
+CPP_FILES+=../../zen/sys_error.cpp
CPP_FILES+=../../zen/system.cpp
CPP_FILES+=../../zen/thread.cpp
CPP_FILES+=../../zen/zlib_wrap.cpp
diff --git a/FreeFileSync/Source/RealTimeSync/Makefile b/FreeFileSync/Source/RealTimeSync/Makefile
index 3d0e98ec..9c7f88e0 100755
--- a/FreeFileSync/Source/RealTimeSync/Makefile
+++ b/FreeFileSync/Source/RealTimeSync/Makefile
@@ -20,11 +20,11 @@ CPP_FILES+=tray_menu.cpp
CPP_FILES+=monitor.cpp
CPP_FILES+=folder_selector2.cpp
CPP_FILES+=../afs/abstract.cpp
-CPP_FILES+=../base/icon_buffer.cpp
CPP_FILES+=../base/icon_loader.cpp
-CPP_FILES+=../base/localization.cpp
CPP_FILES+=../base/resolve_path.cpp
-CPP_FILES+=../base/ffs_paths.cpp
+CPP_FILES+=../ffs_paths.cpp
+CPP_FILES+=../icon_buffer.cpp
+CPP_FILES+=../localization.cpp
CPP_FILES+=../../../zen/dir_watcher.cpp
CPP_FILES+=../../../zen/file_access.cpp
CPP_FILES+=../../../zen/file_io.cpp
@@ -32,6 +32,7 @@ CPP_FILES+=../../../zen/file_traverser.cpp
CPP_FILES+=../../../zen/format_unit.cpp
CPP_FILES+=../../../zen/legacy_compiler.cpp
CPP_FILES+=../../../zen/shutdown.cpp
+CPP_FILES+=../../../zen/sys_error.cpp
CPP_FILES+=../../../zen/thread.cpp
CPP_FILES+=../../../zen/zstring.cpp
CPP_FILES+=../../../wx+/file_drop.cpp
diff --git a/FreeFileSync/Source/RealTimeSync/application.cpp b/FreeFileSync/Source/RealTimeSync/application.cpp
index 7f81883b..037d7059 100644
--- a/FreeFileSync/Source/RealTimeSync/application.cpp
+++ b/FreeFileSync/Source/RealTimeSync/application.cpp
@@ -15,12 +15,12 @@
#include <wx+/popup_dlg.h>
#include <wx+/image_resources.h>
#include "config.h"
-#include "../base/localization.h"
-#include "../base/ffs_paths.h"
-#include "../base/return_codes.h"
-#include "../base/fatal_error.h"
-#include "../base/help_provider.h"
#include "../base/resolve_path.h"
+#include "../localization.h"
+#include "../ffs_paths.h"
+#include "../return_codes.h"
+#include "../fatal_error.h"
+#include "../help_provider.h"
#include <gtk/gtk.h>
@@ -61,13 +61,15 @@ bool Application::OnInit()
(fff::getResourceDirPf() + "Gtk3Styles.css").c_str(), //const gchar* path,
&error); //GError** error
if (error)
- throw SysError(formatSystemError(L"gtk_css_provider_load_from_data", replaceCpy(_("Error Code %x"), L"%x", numberTo<std::wstring>(error->code)), utfTo<std::wstring>(error->message)));
+ throw SysError(formatSystemError(L"gtk_css_provider_load_from_data", replaceCpy(_("Error Code %x"), L"%x",
+ numberTo<std::wstring>(error->code)),
+ utfTo<std::wstring>(error->message)));
::gtk_style_context_add_provider_for_screen(::gdk_screen_get_default(), //GdkScreen* screen,
GTK_STYLE_PROVIDER(provider), //GtkStyleProvider* provider,
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); //guint priority
}
- catch (const SysError& e) { std::cerr << utfTo<std::string>(e.toString()) << "\n"; }
+ catch (const SysError& e) { std::cerr << utfTo<std::string>(e.toString()) << '\n'; }
#else
#error unknown GTK version!
#endif
@@ -158,7 +160,7 @@ int Application::OnRun()
fff::logFatalError(e.what()); //it's not always possible to display a message box, e.g. corrupted stack, however low-level file output works!
const auto titleFmt = copyStringTo<std::wstring>(wxTheApp->GetAppDisplayName()) + SPACED_DASH + _("An exception occurred");
- std::cerr << utfTo<std::string>(titleFmt + SPACED_DASH) << e.what() << "\n";
+ std::cerr << utfTo<std::string>(titleFmt + SPACED_DASH) << e.what() << '\n';
return fff::FFS_RC_EXCEPTION;
}
//catch (...) -> let it crash and create mini dump!!!
diff --git a/FreeFileSync/Source/RealTimeSync/config.cpp b/FreeFileSync/Source/RealTimeSync/config.cpp
index 3f084f3a..7051c6d1 100644
--- a/FreeFileSync/Source/RealTimeSync/config.cpp
+++ b/FreeFileSync/Source/RealTimeSync/config.cpp
@@ -8,8 +8,8 @@
#include <zen/file_access.h>
#include <zenxml/xml.h>
#include <wx/intl.h>
-#include "../base/ffs_paths.h"
-#include "../base/localization.h"
+#include "../ffs_paths.h"
+#include "../localization.h"
using namespace zen;
using namespace rts;
diff --git a/FreeFileSync/Source/RealTimeSync/gui_generated.cpp b/FreeFileSync/Source/RealTimeSync/gui_generated.cpp
index 7709981d..dccc3495 100644
--- a/FreeFileSync/Source/RealTimeSync/gui_generated.cpp
+++ b/FreeFileSync/Source/RealTimeSync/gui_generated.cpp
@@ -121,10 +121,13 @@ MainDlgGenerated::MainDlgGenerated( wxWindow* parent, wxWindowID id, const wxStr
m_staticText11->Wrap( -1 );
m_staticText11->SetForegroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_GRAYTEXT ) );
- bSizer152->Add( m_staticText11, 0, wxALIGN_CENTER_VERTICAL|wxLEFT, 2 );
+ bSizer152->Add( m_staticText11, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 2 );
+ m_hyperlink243 = new wxHyperlinkCtrl( this, wxID_ANY, _("Show examples"), wxEmptyString, wxDefaultPosition, wxDefaultSize, wxHL_DEFAULT_STYLE );
+ bSizer152->Add( m_hyperlink243, 0, wxALIGN_CENTER_VERTICAL|wxLEFT, 5 );
- bSizer161->Add( bSizer152, 0, wxALIGN_CENTER_HORIZONTAL|wxBOTTOM|wxRIGHT|wxLEFT, 5 );
+
+ bSizer161->Add( bSizer152, 0, wxALL|wxALIGN_CENTER_HORIZONTAL, 5 );
bSizerMain->Add( bSizer161, 0, wxALL|wxEXPAND, 5 );
@@ -303,6 +306,7 @@ MainDlgGenerated::MainDlgGenerated( wxWindow* parent, wxWindowID id, const wxStr
m_menuFile->Bind(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDlgGenerated::OnMenuQuit ), this, m_menuItemQuit->GetId());
m_menuHelp->Bind(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDlgGenerated::OnShowHelp ), this, m_menuItemContent->GetId());
m_menuHelp->Bind(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDlgGenerated::OnMenuAbout ), this, m_menuItemAbout->GetId());
+ m_hyperlink243->Connect( wxEVT_COMMAND_HYPERLINK, wxHyperlinkEventHandler( MainDlgGenerated::OnHelpRealTimeSync ), NULL, this );
m_bpButtonAddFolder->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDlgGenerated::OnAddFolder ), NULL, this );
m_bpButtonRemoveTopFolder->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDlgGenerated::OnRemoveTopFolder ), NULL, this );
m_buttonStart->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDlgGenerated::OnStart ), NULL, this );
diff --git a/FreeFileSync/Source/RealTimeSync/gui_generated.h b/FreeFileSync/Source/RealTimeSync/gui_generated.h
index 1fd190f0..5cc0f0ca 100644
--- a/FreeFileSync/Source/RealTimeSync/gui_generated.h
+++ b/FreeFileSync/Source/RealTimeSync/gui_generated.h
@@ -24,6 +24,7 @@ namespace zen { class BitmapTextButton; }
#include <wx/stattext.h>
#include <wx/sizer.h>
#include <wx/statbmp.h>
+#include <wx/hyperlink.h>
#include <wx/statline.h>
#include <wx/bmpbuttn.h>
#include <wx/button.h>
@@ -64,6 +65,7 @@ protected:
wxStaticText* m_staticText10;
wxStaticBitmap* m_bitmapBatch;
wxStaticText* m_staticText11;
+ wxHyperlinkCtrl* m_hyperlink243;
wxStaticLine* m_staticline2;
wxPanel* m_panelMain;
wxStaticBitmap* m_bitmapFolders;
@@ -95,6 +97,7 @@ protected:
virtual void OnMenuQuit( wxCommandEvent& event ) { event.Skip(); }
virtual void OnShowHelp( wxCommandEvent& event ) { event.Skip(); }
virtual void OnMenuAbout( wxCommandEvent& event ) { event.Skip(); }
+ virtual void OnHelpRealTimeSync( wxHyperlinkEvent& event ) { event.Skip(); }
virtual void OnAddFolder( wxCommandEvent& event ) { event.Skip(); }
virtual void OnRemoveTopFolder( wxCommandEvent& event ) { event.Skip(); }
virtual void OnStart( wxCommandEvent& event ) { event.Skip(); }
diff --git a/FreeFileSync/Source/RealTimeSync/main_dlg.cpp b/FreeFileSync/Source/RealTimeSync/main_dlg.cpp
index 57e188ea..694d6e79 100644
--- a/FreeFileSync/Source/RealTimeSync/main_dlg.cpp
+++ b/FreeFileSync/Source/RealTimeSync/main_dlg.cpp
@@ -17,9 +17,9 @@
#include "config.h"
#include "tray_menu.h"
#include "app_icon.h"
-#include "../base/help_provider.h"
-#include "../base/icon_buffer.h"
-#include "../base/ffs_paths.h"
+#include "../help_provider.h"
+#include "../icon_buffer.h"
+#include "../ffs_paths.h"
#include "../version/version.h"
#include <gtk/gtk.h>
@@ -177,6 +177,7 @@ void MainDialog::onQueryEndSession()
}
+
void MainDialog::OnShowHelp(wxCommandEvent& event)
{
fff::displayHelpEntry(L"realtimesync", this);
@@ -201,7 +202,7 @@ void MainDialog::OnMenuAbout(wxCommandEvent& event)
#endif
build += SPACED_BULLET;
- build += formatTime<wxString>(FORMAT_DATE, getCompileTime());
+ build += utfTo<wxString>(formatTime(formatDateTag, getCompileTime()));
showNotificationDialog(this, DialogInfoType::info, PopupDialogCfg().
setTitle(_("About")).
diff --git a/FreeFileSync/Source/RealTimeSync/main_dlg.h b/FreeFileSync/Source/RealTimeSync/main_dlg.h
index d20b889c..39052f93 100644
--- a/FreeFileSync/Source/RealTimeSync/main_dlg.h
+++ b/FreeFileSync/Source/RealTimeSync/main_dlg.h
@@ -38,6 +38,7 @@ private:
void OnClose (wxCloseEvent& event ) override { Destroy(); }
void OnShowHelp (wxCommandEvent& event) override;
+ void OnHelpRealTimeSync(wxHyperlinkEvent& event) override { OnShowHelp(event); }
void OnMenuAbout (wxCommandEvent& event) override;
void OnAddFolder (wxCommandEvent& event) override;
void OnRemoveFolder (wxCommandEvent& event);
diff --git a/FreeFileSync/Source/RealTimeSync/monitor.cpp b/FreeFileSync/Source/RealTimeSync/monitor.cpp
index d5266c6c..66a83f3c 100644
--- a/FreeFileSync/Source/RealTimeSync/monitor.cpp
+++ b/FreeFileSync/Source/RealTimeSync/monitor.cpp
@@ -26,10 +26,10 @@ std::set<Zstring, LessNativePath> waitForMissingDirs(const std::vector<Zstring>&
const std::function<void(const Zstring& folderPath)>& requestUiUpdate, std::chrono::milliseconds cbInterval)
{
//early failure! check for unsupported folder paths:
- for (const Zstring& protoName : { Zstr("ftp"), Zstr("sftp"), Zstr("mtp"), Zstr("gdrive") })
+ for (const std::string& protoName : { "ftp", "sftp", "mtp", "gdrive" })
for (const Zstring& phrase : folderPathPhrases)
//hopefully clear enough now: https://freefilesync.org/forum/viewtopic.php?t=4302
- if (startsWithAsciiNoCase(trimCpy(phrase), protoName + Zstr(":")))
+ if (startsWithAsciiNoCase(trimCpy(phrase), protoName + ':'))
throw FileError(replaceCpy(_("The %x protocol does not support directory monitoring:"), L"%x", utfTo<std::wstring>(protoName)) + L"\n\n" + fmtPath(phrase));
for (;;)
diff --git a/FreeFileSync/Source/RealTimeSync/tray_menu.cpp b/FreeFileSync/Source/RealTimeSync/tray_menu.cpp
index a4c1a91a..09928566 100644
--- a/FreeFileSync/Source/RealTimeSync/tray_menu.cpp
+++ b/FreeFileSync/Source/RealTimeSync/tray_menu.cpp
@@ -91,7 +91,7 @@ public:
case TRAY_MODE_WAITING:
assert(!missingFolderPath.empty());
- setTrayIcon(greyScale(trayBmp_), _("Waiting until directory is available:") + L" " + fmtPath(missingFolderPath));
+ setTrayIcon(greyScale(trayBmp_), _("Waiting until directory is available:") + L' ' + fmtPath(missingFolderPath));
break;
case TRAY_MODE_ERROR:
diff --git a/FreeFileSync/Source/afs/abstract.cpp b/FreeFileSync/Source/afs/abstract.cpp
index 9454f68b..10cb7995 100644
--- a/FreeFileSync/Source/afs/abstract.cpp
+++ b/FreeFileSync/Source/afs/abstract.cpp
@@ -399,7 +399,7 @@ void AFS::removeFileIfExists(const AbstractPath& ap) //throw FileError
if (!AFS::itemStillExists(ap)) //throw FileError
return;
}
- catch (const FileError& e2) { throw FileError(replaceCpy(_("Cannot delete file %x."), L"%x", fmtPath(getDisplayPath(ap))), replaceCpy(e2.toString(), L"\n\n", L"\n")); }
+ catch (const FileError& e2) { throw FileError(replaceCpy(_("Cannot delete file %x."), L"%x", fmtPath(getDisplayPath(ap))), replaceCpy(e2.toString(), L"\n\n", L'\n')); }
//more relevant than previous exception (which could be "item not found")
throw;
}
@@ -419,7 +419,7 @@ void AFS::removeSymlinkIfExists(const AbstractPath& ap) //throw FileError
if (!AFS::itemStillExists(ap)) //throw FileError
return;
}
- catch (const FileError& e2) { throw FileError(replaceCpy(_("Cannot delete symbolic link %x."), L"%x", fmtPath(getDisplayPath(ap))), replaceCpy(e2.toString(), L"\n\n", L"\n")); }
+ catch (const FileError& e2) { throw FileError(replaceCpy(_("Cannot delete symbolic link %x."), L"%x", fmtPath(getDisplayPath(ap))), replaceCpy(e2.toString(), L"\n\n", L'\n')); }
//more relevant than previous exception (which could be "item not found")
throw;
}
@@ -439,7 +439,7 @@ void AFS::removeEmptyFolderIfExists(const AbstractPath& ap) //throw FileError
if (!AFS::itemStillExists(ap)) //throw FileError
return;
}
- catch (const FileError& e2) { throw FileError(replaceCpy(_("Cannot delete directory %x."), L"%x", fmtPath(getDisplayPath(ap))), replaceCpy(e2.toString(), L"\n\n", L"\n")); }
+ catch (const FileError& e2) { throw FileError(replaceCpy(_("Cannot delete directory %x."), L"%x", fmtPath(getDisplayPath(ap))), replaceCpy(e2.toString(), L"\n\n", L'\n')); }
//more relevant than previous exception (which could be "item not found")
throw;
diff --git a/FreeFileSync/Source/afs/abstract.h b/FreeFileSync/Source/afs/abstract.h
index bc4932b1..d48c5f87 100644
--- a/FreeFileSync/Source/afs/abstract.h
+++ b/FreeFileSync/Source/afs/abstract.h
@@ -79,7 +79,7 @@ struct AbstractFileSystem //THREAD-SAFETY: "const" member functions must model t
static bool hasNativeTransactionalCopy(const AbstractPath& ap) { return ap.afsDevice.ref().hasNativeTransactionalCopy(); }
//----------------------------------------------------------------------------------------------------------------
- using FileId = zen::Zbase<char>; //AfsDevice-dependent unique ID
+ using FileId = std::string; //AfsDevice-dependent unique ID
enum class ItemType : unsigned char
{
@@ -497,8 +497,8 @@ void AbstractFileSystem::moveAndRenameItem(const AbstractPath& pathFrom, const A
return pathFrom.afsDevice.ref().moveAndRenameItemForSameAfsType(pathFrom.afsPath, pathTo); //throw FileError, ErrorMoveUnsupported
throw ErrorMoveUnsupported(replaceCpy(replaceCpy(_("Cannot move file %x to %y."),
- L"%x", L"\n" + fmtPath(getDisplayPath(pathFrom))),
- L"%y", L"\n" + fmtPath(getDisplayPath(pathTo))), _("Operation not supported between different devices."));
+ L"%x", L'\n' + fmtPath(getDisplayPath(pathFrom))),
+ L"%y", L'\n' + fmtPath(getDisplayPath(pathTo))), _("Operation not supported between different devices."));
}
@@ -530,8 +530,8 @@ void AbstractFileSystem::copySymlink(const AbstractPath& apSource, const Abstrac
return apSource.afsDevice.ref().copySymlinkForSameAfsType(apSource.afsPath, apTarget, copyFilePermissions); //throw FileError
throw FileError(replaceCpy(replaceCpy(_("Cannot copy symbolic link %x to %y."),
- L"%x", L"\n" + fmtPath(getDisplayPath(apSource))),
- L"%y", L"\n" + fmtPath(getDisplayPath(apTarget))), _("Operation not supported between different devices."));
+ L"%x", L'\n' + fmtPath(getDisplayPath(apSource))),
+ L"%y", L'\n' + fmtPath(getDisplayPath(apTarget))), _("Operation not supported between different devices."));
}
}
diff --git a/FreeFileSync/Source/afs/abstract_impl.h b/FreeFileSync/Source/afs/abstract_impl.h
index c2d07828..ceabb6b6 100644
--- a/FreeFileSync/Source/afs/abstract_impl.h
+++ b/FreeFileSync/Source/afs/abstract_impl.h
@@ -123,7 +123,7 @@ public:
size_t read(void* buffer, size_t bytesToRead) //throw <write error>
{
if (bytesToRead == 0) //"read() with a count of 0 returns zero" => indistinguishable from end of file! => check!
- throw std::logic_error("Contract violation! " + std::string(__FILE__) + ":" + zen::numberTo<std::string>(__LINE__));
+ throw std::logic_error("Contract violation! " + std::string(__FILE__) + ':' + zen::numberTo<std::string>(__LINE__));
auto it = static_cast<std::byte*>(buffer);
const auto itEnd = it + bytesToRead;
diff --git a/FreeFileSync/Source/afs/ftp.cpp b/FreeFileSync/Source/afs/ftp.cpp
index e502936a..394c5966 100644
--- a/FreeFileSync/Source/afs/ftp.cpp
+++ b/FreeFileSync/Source/afs/ftp.cpp
@@ -104,8 +104,8 @@ Zstring ansiToUtfEncoding(const std::string& str) //throw SysError
if (!error)
throw SysError(L"g_convert: unknown error. (" + utfTo<std::wstring>(str) + L")"); //user should never see this
- throw SysError(formatSystemError(L"g_convert", replaceCpy(_("Error Code %x"), L"%x", numberTo<std::wstring>(error->code)),
- utfTo<std::wstring>(error->message)) + L" (" + utfTo<std::wstring>(str) + L")");
+ throw SysError(formatSystemError(L"g_convert(" + utfTo<std::wstring>(str) + L")",
+ replaceCpy(_("Error Code %x"), L"%x", numberTo<std::wstring>(error->code)), utfTo<std::wstring>(error->message)) );
}
ZEN_ON_SCOPE_EXIT(::g_free(utfStr));
@@ -134,8 +134,8 @@ std::string utfToAnsiEncoding(const Zstring& str) //throw SysError
if (!error)
throw SysError(L"g_convert: unknown error. (" + utfTo<std::wstring>(str) + L")"); //user should never see this
- throw SysError(formatSystemError(L"g_convert", replaceCpy(_("Error Code %x"), L"%x", numberTo<std::wstring>(error->code)),
- utfTo<std::wstring>(error->message)) + L" (" + utfTo<std::wstring>(str) + L")");
+ throw SysError(formatSystemError(L"g_convert(" + utfTo<std::wstring>(str) + L")",
+ replaceCpy(_("Error Code %x"), L"%x", numberTo<std::wstring>(error->code)), utfTo<std::wstring>(error->message)));
}
ZEN_ON_SCOPE_EXIT(::g_free(ansiStr));
@@ -239,7 +239,7 @@ private:
//----------------------------------------------------------------------------------------------------------------
-std::wstring formatFtpStatusCode(int sc)
+std::wstring formatFtpStatus(int sc)
{
const wchar_t* statusText = [&] //https://en.wikipedia.org/wiki/List_of_FTP_server_return_codes
{
@@ -495,7 +495,7 @@ public:
errorMsg += (errorMsg.empty() ? L"" : L"\n") + trimCpy(utfTo<std::wstring>(headerLines.back())); //that *should* be the servers error response
}
else //failed to get server response
- errorMsg += (errorMsg.empty() ? L"" : L"\n") + formatFtpStatusCode(ftpStatusCode);
+ errorMsg += (errorMsg.empty() ? L"" : L"\n") + formatFtpStatus(ftpStatusCode);
#if 0
//utfTo<std::wstring>(::curl_easy_strerror(ec)) is uninteresting
//use CURLINFO_OS_ERRNO ?? https://curl.haxx.se/libcurl/c/CURLINFO_OS_ERRNO.html
@@ -686,7 +686,7 @@ private:
curl_socket_t currentSocket = 0;
const CURLcode rc = ::curl_easy_getinfo(easyHandle_, CURLINFO_ACTIVESOCKET, &currentSocket);
if (rc != CURLE_OK)
- throw SysError(formatSystemError(L"curl_easy_getinfo: CURLINFO_ACTIVESOCKET", formatCurlStatusCode(rc), utfTo<std::wstring>(::curl_easy_strerror(rc))));
+ throw SysError(formatSystemError(L"curl_easy_getinfo(CURLINFO_ACTIVESOCKET)", formatCurlStatusCode(rc), utfTo<std::wstring>(::curl_easy_strerror(rc))));
if (currentSocket != CURL_SOCKET_BAD)
return currentSocket;
}
@@ -1288,7 +1288,7 @@ private:
}
catch (const SysError& e)
{
- throw SysError(L"Failed to parse FTP response. (" + utfTo<std::wstring>(rawLine) + L")" + (haveGroup ? L"" : L" [no-group]") + L" " + e.toString());
+ throw SysError(L"Failed to parse FTP response. (" + utfTo<std::wstring>(rawLine) + L")" + (haveGroup ? L"" : L" [no-group]") + L' ' + e.toString());
}
}
@@ -1769,7 +1769,7 @@ private:
if (modTime_)
try
{
- const std::string isoTime = formatTime<std::string>("%Y%m%d%H%M%S", getUtcTime(*modTime_)); //returns empty string on failure
+ const std::string isoTime = utfTo<std::string>(formatTime(Zstr("%Y%m%d%H%M%S"), getUtcTime(*modTime_))); //returns empty string on failure
if (isoTime.empty())
throw SysError(L"Invalid modification time (time_t: " + numberTo<std::wstring>(*modTime_) + L")");
@@ -1778,7 +1778,7 @@ private:
if (!session.supportsMfmt(login_.timeoutSec)) //throw SysError
throw SysError(L"Server does not support the MFMT command.");
- session.runSingleFtpCommand("MFMT " + isoTime + " " + session.getServerPathInternal(afsPath_, login_.timeoutSec),
+ session.runSingleFtpCommand("MFMT " + isoTime + ' ' + session.getServerPathInternal(afsPath_, login_.timeoutSec),
true /*requiresUtf8*/, login_.timeoutSec); //throw SysError
//Does MFMT follow symlinks?? Anyway, our FTP implementation supports folder symlinks only
});
@@ -2040,8 +2040,8 @@ private:
void copySymlinkForSameAfsType(const AfsPath& afsPathSource, const AbstractPath& apTarget, bool copyFilePermissions) const override
{
throw FileError(replaceCpy(replaceCpy(_("Cannot copy symbolic link %x to %y."),
- L"%x", L"\n" + fmtPath(getDisplayPath(afsPathSource))),
- L"%y", L"\n" + fmtPath(AFS::getDisplayPath(apTarget))), _("Operation not supported by device."));
+ L"%x", L'\n' + fmtPath(getDisplayPath(afsPathSource))),
+ L"%y", L'\n' + fmtPath(AFS::getDisplayPath(apTarget))), _("Operation not supported by device."));
}
//target existing: undefined behavior! (fail/overwrite/auto-rename)
@@ -2052,8 +2052,8 @@ private:
void moveAndRenameItemForSameAfsType(const AfsPath& pathFrom, const AbstractPath& pathTo) const override //throw FileError, ErrorMoveUnsupported
{
auto generateErrorMsg = [&] { return replaceCpy(replaceCpy(_("Cannot move file %x to %y."),
- L"%x", L"\n" + fmtPath(getDisplayPath(pathFrom))),
- L"%y", L"\n" + fmtPath(AFS::getDisplayPath(pathTo)));
+ L"%x", L'\n' + fmtPath(getDisplayPath(pathFrom))),
+ L"%y", L'\n' + fmtPath(AFS::getDisplayPath(pathTo)));
};
if (compareDeviceSameAfsType(pathTo.afsDevice.ref()) != 0)
@@ -2121,7 +2121,7 @@ Zstring concatenateFtpFolderPathPhrase(const FtpLoginInfo& login, const AfsPath&
{
Zstring port;
if (login.port > 0)
- port = Zstr(":") + numberTo<Zstring>(login.port);
+ port = Zstr(':') + numberTo<Zstring>(login.port);
Zstring options;
if (login.timeoutSec != FtpLoginInfo().timeoutSec)
@@ -2182,11 +2182,11 @@ Zstring fff::condenseToFtpFolderPathPhrase(const FtpLoginInfo& login, const Zstr
loginTmp.timeoutSec = std::max(1, loginTmp.timeoutSec);
- if (startsWithAsciiNoCase(loginTmp.server, Zstr("http:" )) ||
- startsWithAsciiNoCase(loginTmp.server, Zstr("https:")) ||
- startsWithAsciiNoCase(loginTmp.server, Zstr("ftp:" )) ||
- startsWithAsciiNoCase(loginTmp.server, Zstr("ftps:" )) ||
- startsWithAsciiNoCase(loginTmp.server, Zstr("sftp:" )))
+ if (startsWithAsciiNoCase(loginTmp.server, "http:" ) ||
+ startsWithAsciiNoCase(loginTmp.server, "https:") ||
+ startsWithAsciiNoCase(loginTmp.server, "ftp:" ) ||
+ startsWithAsciiNoCase(loginTmp.server, "ftps:" ) ||
+ startsWithAsciiNoCase(loginTmp.server, "sftp:" ))
loginTmp.server = afterFirst(loginTmp.server, Zstr(':'), IF_MISSING_RETURN_NONE);
trim(loginTmp.server, true, false, [](Zchar c) { return c == Zstr('/') || c == Zstr('\\'); });
@@ -2211,7 +2211,7 @@ FtpPathInfo fff::getResolvedFtpPath(const Zstring& folderPathPhrase) //noexcept
const Zstring fullPathOpt = afterFirst(pathPhrase, Zstr('@'), IF_MISSING_RETURN_ALL);
FtpLoginInfo login;
- login.username = decodeFtpUsername(beforeFirst(credentials, Zstr(':'), IF_MISSING_RETURN_ALL)); //support standard FTP syntax, even though ":"
+ login.username = decodeFtpUsername(beforeFirst(credentials, Zstr(':'), IF_MISSING_RETURN_ALL)); //support standard FTP syntax, even though ':'
login.password = afterFirst(credentials, Zstr(':'), IF_MISSING_RETURN_NONE); //is not used by our concatenateSftpFolderPathPhrase()!
const Zstring fullPath = beforeFirst(fullPathOpt, Zstr('|'), IF_MISSING_RETURN_ALL);
diff --git a/FreeFileSync/Source/afs/ftp_common.h b/FreeFileSync/Source/afs/ftp_common.h
index edd3da54..c8fcff0a 100644
--- a/FreeFileSync/Source/afs/ftp_common.h
+++ b/FreeFileSync/Source/afs/ftp_common.h
@@ -35,9 +35,9 @@ inline
Zstring encodeFtpUsername(Zstring name)
{
using namespace zen;
- replace(name, Zstr("%"), Zstr("%25")); //first!
- replace(name, Zstr("@"), Zstr("%40"));
- replace(name, Zstr(":"), Zstr("%3A"));
+ replace(name, Zstr('%'), Zstr("%25")); //first!
+ replace(name, Zstr('@'), Zstr("%40"));
+ replace(name, Zstr(':'), Zstr("%3A"));
return name;
}
@@ -46,10 +46,10 @@ inline
Zstring decodeFtpUsername(Zstring name)
{
using namespace zen;
- replace(name, Zstr("%40"), Zstr("@"));
- replace(name, Zstr("%3A"), Zstr(":"));
- replace(name, Zstr("%3a"), Zstr(":"));
- replace(name, Zstr("%25"), Zstr("%")); //last!
+ replace(name, Zstr("%40"), Zstr('@'));
+ replace(name, Zstr("%3A"), Zstr(':'));
+ replace(name, Zstr("%3a"), Zstr(':'));
+ replace(name, Zstr("%25"), Zstr('%')); //last!
return name;
}
diff --git a/FreeFileSync/Source/afs/gdrive.cpp b/FreeFileSync/Source/afs/gdrive.cpp
index 8c92eb47..467c40fe 100644
--- a/FreeFileSync/Source/afs/gdrive.cpp
+++ b/FreeFileSync/Source/afs/gdrive.cpp
@@ -294,7 +294,7 @@ HttpSession::Result googleHttpsRequest(const std::string& serverRelPath, //throw
{
//https://developers.google.com/drive/api/v3/performance
//"In order to receive a gzip-encoded response you must do two things: Set an Accept-Encoding header, ["gzip" automatically set by HttpSession]
- { CURLOPT_USERAGENT, "FreeFileSync (gzip)" }, // and modify your user agent to contain the string gzip."
+ { CURLOPT_USERAGENT, "FreeFileSync (gzip)" }, //and modify your user agent to contain the string gzip."
};
append(options, extraOptions);
@@ -547,7 +547,7 @@ for (;;) //::accept() blocks forever if no client connects (e.g. user just close
const size_t blockSize = 64 * 1024;
reqLine.resize(reqLine.size() + blockSize);
const size_t bytesReceived = tryReadSocket(clientSocket, &*(reqLine.end() - blockSize), blockSize); //throw SysError
- reqLine.resize(reqLine.size() - blockSize + bytesReceived); //caveat: unsigned arithmetics
+ reqLine.resize(reqLine.size() - (blockSize - bytesReceived)); //caveat: unsigned arithmetics
if (contains(reqLine, "\r\n"))
{
@@ -1058,7 +1058,7 @@ void gdriveMoveAndRenameItem(const std::string& itemId, const std::string& paren
//more Google Drive peculiarities: changing the file name changes modifiedTime!!! => workaround:
//RFC 3339 date-time: e.g. "2018-09-29T08:39:12.053Z"
- const std::string modTimeRfc = formatTime<std::string>("%Y-%m-%dT%H:%M:%S.000Z", getUtcTime(newModTime)); //returns empty string on failure
+ const std::string modTimeRfc = utfTo<std::string>(formatTime(Zstr("%Y-%m-%dT%H:%M:%S.000Z"), getUtcTime(newModTime))); //returns empty string on failure
if (modTimeRfc.empty())
throw SysError(L"Invalid modification time (time_t: " + numberTo<std::wstring>(newModTime) + L")");
@@ -1250,7 +1250,7 @@ std::string /*itemId*/ gdriveUploadFile(const Zstring& fileName, const std::stri
std::string postBuf = "{\n";
if (modTime) //convert to RFC 3339 date-time: e.g. "2018-09-29T08:39:12.053Z"
{
- const std::string& modTimeRfc = formatTime<std::string>("%Y-%m-%dT%H:%M:%S.000Z", getUtcTime(*modTime)); //returns empty string on failure
+ const std::string& modTimeRfc = utfTo<std::string>(formatTime(Zstr("%Y-%m-%dT%H:%M:%S.000Z"), getUtcTime(*modTime))); //returns empty string on failure
if (modTimeRfc.empty())
throw SysError(L"Invalid modification time (time_t: " + numberTo<std::wstring>(*modTime) + L")");
@@ -1345,7 +1345,7 @@ class GoogleAccessBuffer //per-user-session! => serialize access (perf: amortize
public:
GoogleAccessBuffer(const GoogleAccessInfo& accessInfo) : accessInfo_(accessInfo) {}
- GoogleAccessBuffer(MemoryStreamIn<ByteArray>& stream) //throw UnexpectedEndOfStreamError
+ GoogleAccessBuffer(MemoryStreamIn<std::string>& stream) //throw UnexpectedEndOfStreamError
{
accessInfo_.accessToken.validUntil = readNumber<int64_t>(stream); //
accessInfo_.accessToken.value = readContainer<std::string>(stream); //
@@ -1354,7 +1354,7 @@ public:
accessInfo_.userInfo.email = utfTo< Zstring>(readContainer<std::string>(stream)); //
}
- void serialize(MemoryStreamOut<ByteArray>& stream) const
+ void serialize(MemoryStreamOut<std::string>& stream) const
{
writeNumber<int64_t>(stream, accessInfo_.accessToken.validUntil);
static_assert(sizeof(accessInfo_.accessToken.validUntil) <= sizeof(int64_t)); //ensure cross-platform compatibility!
@@ -1379,7 +1379,7 @@ public:
void update(const GoogleAccessInfo& accessInfo)
{
if (!equalAsciiNoCase(accessInfo.userInfo.email, accessInfo_.userInfo.email))
- throw std::logic_error("Contract violation! " + std::string(__FILE__) + ":" + numberTo<std::string>(__LINE__));
+ throw std::logic_error("Contract violation! " + std::string(__FILE__) + ':' + numberTo<std::string>(__LINE__));
accessInfo_ = accessInfo;
}
@@ -1402,7 +1402,7 @@ public:
rootId_ (getRootItemId (accessBuf.getAccessToken())), //throw SysError
accessBuf_(accessBuf) {} //
- GoogleFileState(MemoryStreamIn<ByteArray>& stream, GoogleAccessBuffer& accessBuf, int dbVersion) : accessBuf_(accessBuf) //throw UnexpectedEndOfStreamError
+ GoogleFileState(MemoryStreamIn<std::string>& stream, GoogleAccessBuffer& accessBuf, int dbVersion) : accessBuf_(accessBuf) //throw UnexpectedEndOfStreamError
{
lastSyncToken_ = readContainer<std::string>(stream); //UnexpectedEndOfStreamError
rootId_ = readContainer<std::string>(stream); //
@@ -1441,14 +1441,14 @@ public:
}
}
- void serialize(MemoryStreamOut<ByteArray>& stream) const
+ void serialize(MemoryStreamOut<std::string>& stream) const
{
writeContainer(stream, lastSyncToken_);
writeContainer(stream, rootId_);
for (const auto& [folderId, content] : folderContents_)
if (folderId.empty())
- throw std::logic_error("Contract violation! " + std::string(__FILE__) + ":" + numberTo<std::string>(__LINE__));
+ throw std::logic_error("Contract violation! " + std::string(__FILE__) + ':' + numberTo<std::string>(__LINE__));
else if (content.isKnownFolder)
writeContainer(stream, folderId);
writeContainer(stream, std::string()); //sentinel
@@ -1501,7 +1501,7 @@ public:
const std::string fileId = getItemId(afsPath); //throw SysError
auto it = itemDetails_.find(fileId);
if (it == itemDetails_.end())
- throw std::logic_error("Contract violation! " + std::string(__FILE__) + ":" + numberTo<std::string>(__LINE__));
+ throw std::logic_error("Contract violation! " + std::string(__FILE__) + ':' + numberTo<std::string>(__LINE__));
return *it;
}
@@ -1657,7 +1657,7 @@ private:
notifyFolderContent(registerFileStateDelta(), folderId, readFolderContent(folderId, accessBuf_.getAccessToken())); //throw SysError
if (!folderContents_[folderId].isKnownFolder)
- throw std::logic_error("Contract violation! " + std::string(__FILE__) + ":" + numberTo<std::string>(__LINE__));
+ throw std::logic_error("Contract violation! " + std::string(__FILE__) + ':' + numberTo<std::string>(__LINE__));
childItems = &folderContents_[folderId].childItems;
}
@@ -1668,7 +1668,7 @@ private:
{
if (itFound != itemDetails_.end())
throw SysError(replaceCpy(_("Cannot find %x."), L"%x",
- fmtPath(getGoogleDisplayPath({ accessBuf_.getUserEmail(), AfsPath(nativeAppendPaths(folderPath.value, relPath.front())) }))) + L" " +
+ fmtPath(getGoogleDisplayPath({ accessBuf_.getUserEmail(), AfsPath(nativeAppendPaths(folderPath.value, relPath.front())) }))) + L' ' +
replaceCpy(_("The name %x is used by more than one item in the folder."), L"%x", fmtPath(relPath.front())));
itFound = itDetails;
@@ -1714,7 +1714,7 @@ private:
if (it != itemDetails_.end()) //update
{
if (it->second.isFolder != details->isFolder)
- throw std::logic_error("Contract violation! " + std::string(__FILE__) + ":" + numberTo<std::string>(__LINE__)); //WTF!?
+ throw std::logic_error("Contract violation! " + std::string(__FILE__) + ':' + numberTo<std::string>(__LINE__)); //WTF!?
std::vector<std::string> parentIdsNew = details->parentIds;
std::vector<std::string> parentIdsRemoved = it->second.parentIds;
@@ -1992,7 +1992,7 @@ private:
static void saveSession(const Zstring& dbFilePath, const UserSession& userSession) //throw FileError
{
- MemoryStreamOut<ByteArray> streamOut;
+ MemoryStreamOut<std::string> streamOut;
writeArray(streamOut, DB_FILE_DESCR, sizeof(DB_FILE_DESCR));
writeNumber<int32_t>(streamOut, DB_FILE_VERSION);
@@ -2000,7 +2000,7 @@ private:
userSession.accessBuf.ref().serialize(streamOut);
userSession.fileState.ref().serialize(streamOut);
- ByteArray zstreamOut;
+ std::string zstreamOut;
try
{
zstreamOut = compress(streamOut.ref(), 3 /*compression level: see db_file.cpp*/); //throw SysError
@@ -2012,13 +2012,13 @@ private:
static UserSession loadSession(const Zstring& dbFilePath) //throw FileError
{
- ByteArray zstream = loadBinContainer<ByteArray>(dbFilePath, nullptr /*notifyUnbufferedIO*/); //throw FileError
- ByteArray rawStream;
+ const std::string zstream = loadBinContainer<std::string>(dbFilePath, nullptr /*notifyUnbufferedIO*/); //throw FileError
+ std::string rawStream;
try
{
rawStream = decompress(zstream); //throw SysError
}
- catch (const SysError& e) { throw FileError(_("Database file is corrupted:") + L" " + fmtPath(dbFilePath), e.toString()); }
+ catch (const SysError& e) { throw FileError(_("Database file is corrupted:") + L' ' + fmtPath(dbFilePath), e.toString()); }
MemoryStreamIn streamIn(rawStream);
try
@@ -2041,7 +2041,7 @@ private:
auto fileState = makeSharedRef<GoogleFileState >(streamIn, accessBuf.ref(), version); //throw UnexpectedEndOfStreamError
return { accessBuf, fileState };
}
- catch (UnexpectedEndOfStreamError&) { throw FileError(_("Database file is corrupted:") + L" " + fmtPath(dbFilePath), L"Unexpected end of stream."); }
+ catch (UnexpectedEndOfStreamError&) { throw FileError(_("Database file is corrupted:") + L' ' + fmtPath(dbFilePath), L"Unexpected end of stream."); }
}
struct UserSession
@@ -2162,7 +2162,7 @@ private:
}
else
{
- AFS::FileId fileId = copyStringTo<AFS::FileId>(item.itemId);
+ AFS::FileId fileId = item.itemId;
cb.onFile({ itemName, item.details.fileSize, item.details.modTime, fileId, nullptr /*symlinkInfo*/ }); //throw X
}
}
@@ -2245,7 +2245,7 @@ struct InputStreamGdrive : public AbstractFileSystem::InputStream
const auto& [itemId, gdriveAttr] = fileState.getFileAttributes(gdrivePath_.itemPath); //throw SysError
attr.modTime = gdriveAttr.modTime;
attr.fileSize = gdriveAttr.fileSize;
- attr.fileId = copyStringTo<AFS::FileId>(itemId);
+ attr.fileId = itemId;
});
}
catch (const SysError& e) { throw FileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(getGoogleDisplayPath(gdrivePath_))), e.toString()); }
@@ -2336,7 +2336,7 @@ struct OutputStreamGdrive : public AbstractFileSystem::OutputStreamImpl
fileState.notifyItemCreated(aai.stateDelta, newFileItem);
});
- pFileId.set_value(copyStringTo<AFS::FileId>(fileIdNew));
+ pFileId.set_value(fileIdNew);
}
catch (const SysError& e) { throw FileError(replaceCpy(_("Cannot write file %x."), L"%x", fmtPath(getGoogleDisplayPath(gdrivePath))), e.toString()); }
}
@@ -2621,8 +2621,8 @@ private:
void copySymlinkForSameAfsType(const AfsPath& afsPathSource, const AbstractPath& apTarget, bool copyFilePermissions) const override //throw FileError
{
throw FileError(replaceCpy(replaceCpy(_("Cannot copy symbolic link %x to %y."),
- L"%x", L"\n" + fmtPath(getDisplayPath(afsPathSource))),
- L"%y", L"\n" + fmtPath(AFS::getDisplayPath(apTarget))), _("Operation not supported by device."));
+ L"%x", L'\n' + fmtPath(getDisplayPath(afsPathSource))),
+ L"%y", L'\n' + fmtPath(AFS::getDisplayPath(apTarget))), _("Operation not supported by device."));
}
//target existing: undefined behavior! (fail/overwrite/auto-rename)
@@ -2630,8 +2630,8 @@ private:
void moveAndRenameItemForSameAfsType(const AfsPath& pathFrom, const AbstractPath& pathTo) const override //throw FileError, ErrorMoveUnsupported
{
auto generateErrorMsg = [&] { return replaceCpy(replaceCpy(_("Cannot move file %x to %y."),
- L"%x", L"\n" + fmtPath(getDisplayPath(pathFrom))),
- L"%y", L"\n" + fmtPath(AFS::getDisplayPath(pathTo)));
+ L"%x", L'\n' + fmtPath(getDisplayPath(pathFrom))),
+ L"%y", L'\n' + fmtPath(AFS::getDisplayPath(pathTo)));
};
if (compareDeviceSameAfsType(pathTo.afsDevice.ref()) != 0)
diff --git a/FreeFileSync/Source/afs/native.cpp b/FreeFileSync/Source/afs/native.cpp
index da016788..6e1c96fc 100644
--- a/FreeFileSync/Source/afs/native.cpp
+++ b/FreeFileSync/Source/afs/native.cpp
@@ -118,8 +118,7 @@ std::vector<FsItemRaw> getDirContentFlat(const Zstring& dirPath) //throw FileErr
(itemNameRaw[1] == 0 || (itemNameRaw[1] == '.' && itemNameRaw[2] == 0)))
continue;
- /*
- Unicode normalization is file-system-dependent:
+ /* Unicode normalization is file-system-dependent:
OS Accepts Gives back
---------- ------- ----------
@@ -128,7 +127,7 @@ std::vector<FsItemRaw> getDirContentFlat(const Zstring& dirPath) //throw FileErr
Windows (NTFS, FAT) all <input>
some file systems return precomposed others decomposed UTF8: https://developer.apple.com/library/mac/#qa/qa1173/_index.html
- - OS X edit controls and text fields may return precomposed UTF as directly received by keyboard or decomposed UTF that was copy & pasted in!
+ - OS X edit controls and text fields may return precomposed UTF as directly received by keyboard or decomposed UTF that was copy & pasted!
- Posix APIs require decomposed form: https://freefilesync.org/forum/viewtopic.php?t=2480
=> General recommendation: always preserve input UNCHANGED (both unicode normalization and case sensitivity)
@@ -556,8 +555,8 @@ private:
//=> maybe we can even save some actual I/O in some cases?
if (compareDeviceSameAfsType(pathTo.afsDevice.ref()) != 0)
throw ErrorMoveUnsupported(replaceCpy(replaceCpy(_("Cannot move file %x to %y."),
- L"%x", L"\n" + fmtPath(getDisplayPath(pathFrom))),
- L"%y", L"\n" + fmtPath(AFS::getDisplayPath(pathTo))),
+ L"%x", L'\n' + fmtPath(getDisplayPath(pathFrom))),
+ L"%y", L'\n' + fmtPath(AFS::getDisplayPath(pathTo))),
_("Operation not supported between different devices."));
initComForThread(); //throw FileError
const Zstring nativePathTarget = static_cast<const NativeFileSystem&>(pathTo.afsDevice.ref()).getNativePath(pathTo.afsPath);
@@ -639,7 +638,7 @@ void RecycleSessionNative::recycleItemIfExists(const AbstractPath& itemPath, con
std::optional<Zstring> itemPathNative = AFS::getNativeItemPath(itemPath);
if (!itemPathNative)
- throw std::logic_error("Contract violation! " + std::string(__FILE__) + ":" + numberTo<std::string>(__LINE__));
+ throw std::logic_error("Contract violation! " + std::string(__FILE__) + ':' + numberTo<std::string>(__LINE__));
recycleOrDeleteIfExists(*itemPathNative); //throw FileError
}
@@ -658,7 +657,7 @@ bool fff::acceptsItemPathPhraseNative(const Zstring& itemPathPhrase) //noexcept
trim(path);
- if (startsWith(path, Zstr("["))) //drive letter by volume name syntax
+ if (startsWith(path, Zstr('['))) //drive letter by volume name syntax
return true;
//don't accept relative paths!!! indistinguishable from MTP paths as shown in Explorer's address bar!
diff --git a/FreeFileSync/Source/afs/sftp.cpp b/FreeFileSync/Source/afs/sftp.cpp
index d6279ebd..ed0ff13e 100644
--- a/FreeFileSync/Source/afs/sftp.cpp
+++ b/FreeFileSync/Source/afs/sftp.cpp
@@ -302,7 +302,7 @@ public:
}
else
throw SysError(replaceCpy(_("The server does not support authentication via %x."), L"%x", L"\"username/password\"") +
- L"\n" +_("Required:") + L" " + utfTo<std::wstring>(authList));
+ L'\n' +_("Required:") + L' ' + utfTo<std::wstring>(authList));
}
break;
@@ -310,7 +310,7 @@ public:
{
if (!supportAuthKeyfile)
throw SysError(replaceCpy(_("The server does not support authentication via %x."), L"%x", L"\"key file\"") +
- L"\n" +_("Required:") + L" " + utfTo<std::wstring>(authList));
+ L'\n' +_("Required:") + L' ' + utfTo<std::wstring>(authList));
std::string passphrase = passwordUtf8;
std::string pkStream;
@@ -365,9 +365,9 @@ public:
return nullptr; //other: maybe invalid, maybe not
}();
if (invalidKeyFormat)
- throw SysError(_("Authentication failed.") + L" " +
+ throw SysError(_("Authentication failed.") + L' ' +
replaceCpy<std::wstring>(L"%x is not an OpenSSH or PuTTY private key file.", L"%x",
- fmtPath(sessionId_.privateKeyFilePath) + L" [" + invalidKeyFormat + L"]"));
+ fmtPath(sessionId_.privateKeyFilePath) + L" [" + invalidKeyFormat + L']'));
throw SysError(formatLastSshError(L"libssh2_userauth_publickey_frommemory", nullptr));
}
@@ -511,7 +511,7 @@ public:
if (sshSessions.empty()) return;
if (sshSessions.size() > FD_SETSIZE) //precise: this limit is for both fd_set containers *each*!
- throw FatalSshError(_P("Cannot wait on more than 1 connection at a time.", "Cannot wait on more than %x connections at a time.", FD_SETSIZE) + L" " +
+ throw FatalSshError(_P("Cannot wait on more than 1 connection at a time.", "Cannot wait on more than %x connections at a time.", FD_SETSIZE) + L' ' +
replaceCpy(_("Active connections: %x"), L"%x", numberTo<std::wstring>(sshSessions.size())));
SocketType nfds = 0;
fd_set rfd = {};
@@ -585,7 +585,7 @@ public:
{
if (sshSession.sftpChannels_.empty())
return msg;
- return msg + L" " + replaceCpy(_("Failed to open SFTP channel number %x."), L"%x", numberTo<std::wstring>(sshSession.sftpChannels_.size() + 1));
+ return msg + L' ' + replaceCpy(_("Failed to open SFTP channel number %x."), L"%x", numberTo<std::wstring>(sshSession.sftpChannels_.size() + 1));
};
std::optional<SysError> firstSysError;
@@ -1294,7 +1294,7 @@ private:
{
//libssh2_sftp_read has same semantics as Posix read:
if (bytesToRead == 0) //"read() with a count of 0 returns zero" => indistinguishable from end of file! => check!
- throw std::logic_error("Contract violation! " + std::string(__FILE__) + ":" + numberTo<std::string>(__LINE__));
+ throw std::logic_error("Contract violation! " + std::string(__FILE__) + ':' + numberTo<std::string>(__LINE__));
assert(bytesToRead == getBlockSize());
ssize_t bytesRead = 0;
@@ -1455,7 +1455,7 @@ private:
size_t tryWrite(const void* buffer, size_t bytesToWrite) //throw FileError; may return short! CONTRACT: bytesToWrite > 0
{
if (bytesToWrite == 0)
- throw std::logic_error("Contract violation! " + std::string(__FILE__) + ":" + numberTo<std::string>(__LINE__));
+ throw std::logic_error("Contract violation! " + std::string(__FILE__) + ':' + numberTo<std::string>(__LINE__));
assert(bytesToWrite <= getBlockSize());
ssize_t bytesWritten = 0;
@@ -1682,7 +1682,7 @@ private:
std::string getSymlinkBinaryContent(const AfsPath& afsPath) const override //throw FileError
{
const unsigned int bufSize = 10000;
- std::vector<char> buf(bufSize + 1); //ensure buffer is always null-terminated since we don't evaluate the byte count returned by libssh2_sftp_readlink()!
+ std::string buf(bufSize + 1, '\0'); //ensure buffer is always null-terminated since we don't evaluate the byte count returned by libssh2_sftp_readlink()!
try
{
runSftpCommand(login_, L"libssh2_sftp_readlink", //throw SysError
@@ -1690,7 +1690,8 @@ private:
}
catch (const SysError& e) { throw FileError(replaceCpy(_("Cannot resolve symbolic link %x."), L"%x", fmtPath(getDisplayPath(afsPath))), e.toString()); }
- return &buf[0];
+ buf.resize(strLength(&buf[0]));
+ return buf;
}
//----------------------------------------------------------------------------------------------------------------
@@ -1743,16 +1744,16 @@ private:
void copySymlinkForSameAfsType(const AfsPath& afsPathSource, const AbstractPath& apTarget, bool copyFilePermissions) const override
{
throw FileError(replaceCpy(replaceCpy(_("Cannot copy symbolic link %x to %y."),
- L"%x", L"\n" + fmtPath(getDisplayPath(afsPathSource))),
- L"%y", L"\n" + fmtPath(AFS::getDisplayPath(apTarget))), _("Operation not supported by device."));
+ L"%x", L'\n' + fmtPath(getDisplayPath(afsPathSource))),
+ L"%y", L'\n' + fmtPath(AFS::getDisplayPath(apTarget))), _("Operation not supported by device."));
}
//target existing: undefined behavior! (fail/overwrite/auto-rename) => SFTP will fail with obscure LIBSSH2_FX_FAILURE error message
void moveAndRenameItemForSameAfsType(const AfsPath& pathFrom, const AbstractPath& pathTo) const override //throw FileError, ErrorMoveUnsupported
{
auto generateErrorMsg = [&] { return replaceCpy(replaceCpy(_("Cannot move file %x to %y."),
- L"%x", L"\n" + fmtPath(getDisplayPath(pathFrom))),
- L"%y", L"\n" + fmtPath(AFS::getDisplayPath(pathTo)));
+ L"%x", L'\n' + fmtPath(getDisplayPath(pathFrom))),
+ L"%y", L'\n' + fmtPath(AFS::getDisplayPath(pathTo)));
};
if (compareDeviceSameAfsType(pathTo.afsDevice.ref()) != 0)
@@ -1849,7 +1850,7 @@ Zstring concatenateSftpFolderPathPhrase(const SftpLoginInfo& login, const AfsPat
{
Zstring port;
if (login.port > 0)
- port = Zstr(":") + numberTo<Zstring>(login.port);
+ port = Zstr(':') + numberTo<Zstring>(login.port);
const SftpLoginInfo loginDefault;
@@ -1915,11 +1916,11 @@ Zstring fff::condenseToSftpFolderPathPhrase(const SftpLoginInfo& login, const Zs
loginTmp.timeoutSec = std::max(1, loginTmp.timeoutSec);
loginTmp.traverserChannelsPerConnection = std::max(1, loginTmp.traverserChannelsPerConnection);
- if (startsWithAsciiNoCase(loginTmp.server, Zstr("http:" )) ||
- startsWithAsciiNoCase(loginTmp.server, Zstr("https:")) ||
- startsWithAsciiNoCase(loginTmp.server, Zstr("ftp:" )) ||
- startsWithAsciiNoCase(loginTmp.server, Zstr("ftps:" )) ||
- startsWithAsciiNoCase(loginTmp.server, Zstr("sftp:" )))
+ if (startsWithAsciiNoCase(loginTmp.server, "http:" ) ||
+ startsWithAsciiNoCase(loginTmp.server, "https:") ||
+ startsWithAsciiNoCase(loginTmp.server, "ftp:" ) ||
+ startsWithAsciiNoCase(loginTmp.server, "ftps:" ) ||
+ startsWithAsciiNoCase(loginTmp.server, "sftp:" ))
loginTmp.server = afterFirst(loginTmp.server, Zstr(':'), IF_MISSING_RETURN_NONE);
trim(loginTmp.server, true, false, [](Zchar c) { return c == Zstr('/') || c == Zstr('\\'); });
@@ -1948,7 +1949,7 @@ int fff::getServerMaxChannelsPerConnection(const SftpLoginInfo& login) //throw F
if (numeric::dist(std::chrono::steady_clock::now(), startTime) > SFTP_CHANNEL_LIMIT_DETECTION_TIME_OUT)
throw SysError(_P("Operation timed out after 1 second.", "Operation timed out after %x seconds.",
- std::chrono::seconds(SFTP_CHANNEL_LIMIT_DETECTION_TIME_OUT).count()) + L" " +
+ std::chrono::seconds(SFTP_CHANNEL_LIMIT_DETECTION_TIME_OUT).count()) + L' ' +
replaceCpy(_("Failed to open SFTP channel number %x."), L"%x", numberTo<std::wstring>(exSession->getSftpChannelCount() + 1)));
}
}
@@ -1976,7 +1977,7 @@ SftpPathInfo fff::getResolvedSftpPath(const Zstring& folderPathPhrase) //noexcep
const Zstring fullPathOpt = afterFirst(pathPhrase, Zstr('@'), IF_MISSING_RETURN_ALL);
SftpLoginInfo login;
- login.username = decodeFtpUsername(beforeFirst(credentials, Zstr(':'), IF_MISSING_RETURN_ALL)); //support standard FTP syntax, even though ":"
+ login.username = decodeFtpUsername(beforeFirst(credentials, Zstr(':'), IF_MISSING_RETURN_ALL)); //support standard FTP syntax, even though ':'
login.password = afterFirst(credentials, Zstr(':'), IF_MISSING_RETURN_NONE); //is not used by our concatenateSftpFolderPathPhrase()!
const Zstring fullPath = beforeFirst(fullPathOpt, Zstr('|'), IF_MISSING_RETURN_ALL);
diff --git a/FreeFileSync/Source/base/application.cpp b/FreeFileSync/Source/application.cpp
index 657eac13..65755b0e 100644
--- a/FreeFileSync/Source/base/application.cpp
+++ b/FreeFileSync/Source/application.cpp
@@ -15,17 +15,18 @@
#include <wx+/popup_dlg.h>
#include <wx+/image_resources.h>
#include <wx/msgdlg.h>
-#include "comparison.h"
+#include "afs/concrete.h"
+#include "base/algorithm.h"
+#include "base/comparison.h"
+#include "base/resolve_path.h"
+#include "base/synchronization.h"
+#include "ui/batch_status_handler.h"
+#include "ui/main_dlg.h"
+#include "base_tools.h"
#include "config.h"
-#include "algorithm.h"
-#include "synchronization.h"
#include "help_provider.h"
#include "fatal_error.h"
#include "log_file.h"
-#include "resolve_path.h"
-#include "../ui/batch_status_handler.h"
-#include "../ui/main_dlg.h"
-#include "../afs/concrete.h"
#include <gtk/gtk.h>
@@ -84,14 +85,15 @@ bool Application::OnInit()
(getResourceDirPf() + "Gtk3Styles.css").c_str(), //const gchar* path,
&error); //GError** error
if (error)
- throw SysError(formatSystemError(L"gtk_css_provider_load_from_data",
- replaceCpy(_("Error Code %x"), L"%x", numberTo<std::wstring>(error->code)), utfTo<std::wstring>(error->message)));
+ throw SysError(formatSystemError(L"gtk_css_provider_load_from_data", replaceCpy(_("Error Code %x"), L"%x",
+ numberTo<std::wstring>(error->code)),
+ utfTo<std::wstring>(error->message)));
::gtk_style_context_add_provider_for_screen(::gdk_screen_get_default(), //GdkScreen* screen,
GTK_STYLE_PROVIDER(provider), //GtkStyleProvider* provider,
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); //guint priority
}
- catch (const SysError& e) { std::cerr << utfTo<std::string>(e.toString()) << "\n"; }
+ catch (const SysError& e) { std::cerr << utfTo<std::string>(e.toString()) << '\n'; }
#else
#error unknown GTK version!
#endif
@@ -160,7 +162,7 @@ int Application::OnRun()
logFatalError(e.what()); //it's not always possible to display a message box, e.g. corrupted stack, however low-level file output works!
const auto titleFmt = copyStringTo<std::wstring>(wxTheApp->GetAppDisplayName()) + SPACED_DASH + _("An exception occurred");
- std::cerr << utfTo<std::string>(titleFmt + SPACED_DASH) << e.what() << "\n";
+ std::cerr << utfTo<std::string>(titleFmt + SPACED_DASH) << e.what() << '\n';
return FFS_RC_EXCEPTION;
}
//catch (...) -> let it crash and create mini dump!!!
@@ -197,7 +199,7 @@ void Application::launch(const std::vector<Zstring>& commandArgs)
//error handling strategy unknown and no sync log output available at this point!
auto titleFmt = copyStringTo<std::wstring>(wxTheApp->GetAppDisplayName()) + SPACED_DASH + title;
- std::cerr << utfTo<std::string>(titleFmt + SPACED_DASH + msg) << "\n";
+ std::cerr << utfTo<std::string>(titleFmt + SPACED_DASH + msg) << '\n';
//alternative0: std::wcerr: cannot display non-ASCII at all, so why does it exist???
//alternative1: wxSafeShowMessage => NO console output on Debian x86, WTF!
//alternative2: wxMessageBox() => works, but we probably shouldn't block during command line usage
@@ -210,9 +212,9 @@ void Application::launch(const std::vector<Zstring>& commandArgs)
Zstring globalConfigFile;
bool openForEdit = false;
{
- const Zchar* optionEdit = Zstr("-edit");
- const Zchar* optionDirPair = Zstr("-dirpair");
- const Zchar* optionSendTo = Zstr("-sendto"); //remaining arguments are unspecified number of folder paths; wonky syntax; let's keep it undocumented
+ const char* optionEdit = "-edit";
+ const char* optionDirPair = "-dirpair";
+ const char* optionSendTo = "-sendto"; //remaining arguments are unspecified number of folder paths; wonky syntax; let's keep it undocumented
auto isHelpRequest = [](const Zstring& arg)
{
@@ -220,8 +222,8 @@ void Application::launch(const std::vector<Zstring>& commandArgs)
if (it == arg.begin()) return false; //require at least one prefix character
const Zstring argTmp(it, arg.end());
- return equalAsciiNoCase(argTmp, Zstr("help")) ||
- equalAsciiNoCase(argTmp, Zstr("h")) ||
+ return equalAsciiNoCase(argTmp, "help") ||
+ equalAsciiNoCase(argTmp, "h") ||
argTmp == Zstr("?");
};
@@ -473,23 +475,23 @@ void showSyntaxHelp()
showNotificationDialog(nullptr, DialogInfoType::info, PopupDialogCfg().
setTitle(_("Command line")).
setDetailInstructions(_("Syntax:") + L"\n\n" +
- L"./FreeFileSync" + L"\n" +
- L" [" + _("config files:") + L" *.ffs_gui/*.ffs_batch]" + L"\n" +
- L" [-DirPair " + _("directory") + L" " + _("directory") + L"]" + L"\n" +
- L" [-Edit]" + L"\n" +
- L" [" + _("global config file:") + L" GlobalSettings.xml]" + L"\n" +
+ L"./FreeFileSync" + L'\n' +
+ L" [" + _("config files:") + L" *.ffs_gui/*.ffs_batch]" + L'\n' +
+ L" [-DirPair " + _("directory") + L' ' + _("directory") + L"]" L"\n" +
+ L" [-Edit]" + L'\n' +
+ L" [" + _("global config file:") + L" GlobalSettings.xml]" + L"\n"
L"\n" +
- _("config files:") + L"\n" +
+ _("config files:") + L'\n' +
_("Any number of FreeFileSync \"ffs_gui\" and/or \"ffs_batch\" configuration files.") + L"\n\n" +
- L"-DirPair " + _("directory") + L" " + _("directory") + L"\n" +
+ L"-DirPair " + _("directory") + L' ' + _("directory") + L'\n' +
_("Any number of alternative directory pairs for at most one config file.") + L"\n\n" +
- L"-Edit" + L"\n" +
+ L"-Edit" + "\n" +
_("Open the selected configuration for editing only, without executing it.") + L"\n\n" +
- _("global config file:") + L"\n" +
+ _("global config file:") + L'\n' +
_("Path to an alternate GlobalSettings.xml file.")));
}
@@ -596,7 +598,7 @@ void runBatchMode(const Zstring& globalConfigFilePath, const XmlBatchConfig& bat
catch (AbortProcess&) {} //exit used by statusHandler
BatchStatusHandler::Result r = statusHandler.reportResults(batchCfg.mainCfg.postSyncCommand, batchCfg.mainCfg.postSyncCondition,
- batchCfg.mainCfg.altLogFolderPathPhrase, globalCfg.logfilesMaxAgeDays, logFilePathsToKeep,
+ batchCfg.mainCfg.altLogFolderPathPhrase, globalCfg.logfilesMaxAgeDays, globalCfg.logFormat, logFilePathsToKeep,
batchCfg.mainCfg.emailNotifyAddress, batchCfg.mainCfg.emailNotifyCondition); //noexcept
//----------------------------------------------------------------------
diff --git a/FreeFileSync/Source/base/application.h b/FreeFileSync/Source/application.h
index a52e6617..a52e6617 100644
--- a/FreeFileSync/Source/base/application.h
+++ b/FreeFileSync/Source/application.h
diff --git a/FreeFileSync/Source/base/algorithm.cpp b/FreeFileSync/Source/base/algorithm.cpp
index ddb449d6..2b66e9a5 100644
--- a/FreeFileSync/Source/base/algorithm.cpp
+++ b/FreeFileSync/Source/base/algorithm.cpp
@@ -712,9 +712,9 @@ private:
recurse(folder, dbEntryL, dbEntryR);
}
- const std::wstring txtBothSidesChanged_ = _("Both sides have changed since last synchronization.");
- const std::wstring txtNoSideChanged_ = _("Cannot determine sync-direction:") + L" \n" + _("No change since last synchronization.");
- const std::wstring txtDbNotInSync_ = _("Cannot determine sync-direction:") + L" \n" + _("The database entry is not in sync considering current settings.");
+ const Zstringc txtBothSidesChanged_ = utfTo<Zstringc>(_("Both sides have changed since last synchronization."));
+ const Zstringc txtNoSideChanged_ = utfTo<Zstringc>(_("Cannot determine sync-direction:") + L" \n" + _("No change since last synchronization."));
+ const Zstringc txtDbNotInSync_ = utfTo<Zstringc>(_("Cannot determine sync-direction:") + L" \n" + _("The database entry is not in sync considering current settings."));
const CompareVariant cmpVar_;
const int fileTimeTolerance_;
@@ -736,7 +736,7 @@ std::vector<std::pair<BaseFolderPair*, DirectionConfig>> fff::extractDirectionCf
mainCfg.additionalPairs.end());
if (folderCmp.size() != allPairs.size())
- throw std::logic_error("Contract violation! " + std::string(__FILE__) + ":" + numberTo<std::string>(__LINE__));
+ throw std::logic_error("Contract violation! " + std::string(__FILE__) + ':' + numberTo<std::string>(__LINE__));
std::vector<std::pair<BaseFolderPair*, DirectionConfig>> output;
@@ -779,7 +779,7 @@ void fff::redetermineSyncDirection(const std::vector<std::pair<BaseFolderPair*,
{
std::wstring msg = _("Setting default synchronization directions: Old files will be overwritten with newer files.");
if (directCfgs.size() > 1)
- msg += "\n" + AFS::getDisplayPath(baseFolder->getAbstractPath< LEFT_SIDE>()) + L" " + getVariantNameForLog(dirCfg.var) + L" " +
+ msg += L'\n' + AFS::getDisplayPath(baseFolder->getAbstractPath< LEFT_SIDE>()) + L' ' + getVariantNameForLog(dirCfg.var) + L' ' +
AFS::getDisplayPath(baseFolder->getAbstractPath<RIGHT_SIDE>());
try { callback.reportInfo(msg); /*throw X*/} catch (...) {};
@@ -1089,7 +1089,7 @@ void fff::applyFiltering(FolderComparison& folderCmp, const MainConfiguration& m
if (folderCmp.empty())
return;
else if (folderCmp.size() != mainCfg.additionalPairs.size() + 1)
- throw std::logic_error("Contract violation! " + std::string(__FILE__) + ":" + numberTo<std::string>(__LINE__));
+ throw std::logic_error("Contract violation! " + std::string(__FILE__) + ':' + numberTo<std::string>(__LINE__));
//merge first and additional pairs
std::vector<LocalPairConfig> allPairs;
@@ -1610,11 +1610,11 @@ void fff::deleteFromGridAndHD(const std::vector<FileSystemObject*>& rowsToDelete
if (useRecycleBin &&
std::any_of(recyclerSupported.begin(), recyclerSupported.end(), [](const auto& item) { return !item.second; }))
{
- std::wstring msg = _("The recycle bin is not supported by the following folders. Deleted or overwritten files will not be able to be restored:") + L"\n";
+ std::wstring msg = _("The recycle bin is not supported by the following folders. Deleted or overwritten files will not be able to be restored:") + L'\n';
for (const auto& [folderPath, supported] : recyclerSupported)
if (!supported)
- msg += L"\n" + AFS::getDisplayPath(folderPath);
+ msg += L'\n' + AFS::getDisplayPath(folderPath);
callback.reportWarning(msg, warnRecyclerMissing); //throw?
}
diff --git a/FreeFileSync/Source/base/algorithm.h b/FreeFileSync/Source/base/algorithm.h
index 299a97a0..48d8b7c1 100644
--- a/FreeFileSync/Source/base/algorithm.h
+++ b/FreeFileSync/Source/base/algorithm.h
@@ -8,7 +8,8 @@
#define ALGORITHM_H_34218518475321452548
#include <functional>
-#include "config.h"
+//#include "config.h"
+#include "structures.h"
#include "file_hierarchy.h"
#include "soft_filter.h"
#include "process_callback.h"
diff --git a/FreeFileSync/Source/base/binary.cpp b/FreeFileSync/Source/base/binary.cpp
index db5dee54..f3199f67 100644
--- a/FreeFileSync/Source/base/binary.cpp
+++ b/FreeFileSync/Source/base/binary.cpp
@@ -137,7 +137,7 @@ bool fff::filesHaveSameContent(const AbstractPath& filePath1, const AbstractPath
}
if (totalUnbufferedIO % 2 != 0)
- throw std::logic_error("Contract violation! " + std::string(__FILE__) + ":" + numberTo<std::string>(__LINE__));
+ throw std::logic_error("Contract violation! " + std::string(__FILE__) + ':' + numberTo<std::string>(__LINE__));
return true;
}
diff --git a/FreeFileSync/Source/base/comparison.cpp b/FreeFileSync/Source/base/comparison.cpp
index e705551b..27e23867 100644
--- a/FreeFileSync/Source/base/comparison.cpp
+++ b/FreeFileSync/Source/base/comparison.cpp
@@ -103,14 +103,14 @@ ResolvedBaseFolders initializeBaseFolders(const std::vector<FolderPairCfg>& fpCf
if (!status.failedChecks.empty())
{
- std::wstring msg = _("Cannot find the following folders:") + L"\n";
+ std::wstring msg = _("Cannot find the following folders:") + L'\n';
for (const auto& [folderPath, error] : status.failedChecks)
- msg += L"\n" + AFS::getDisplayPath(folderPath);
+ msg += L'\n' + AFS::getDisplayPath(folderPath);
msg += L"\n___________________________________________";
for (const auto& [folderPath, error] : status.failedChecks)
- msg += L"\n\n" + replaceCpy(error.toString(), L"\n\n", L"\n");
+ msg += L"\n\n" + replaceCpy(error.toString(), L"\n\n", L'\n');
throw FileError(msg);
}
@@ -119,10 +119,10 @@ ResolvedBaseFolders initializeBaseFolders(const std::vector<FolderPairCfg>& fpCf
if (!notExisting.empty())
{
- std::wstring msg = _("The following folders do not yet exist:") + L"\n";
+ std::wstring msg = _("The following folders do not yet exist:") + L'\n';
for (const AbstractPath& folderPath : notExisting)
- msg += L"\n" + AFS::getDisplayPath(folderPath);
+ msg += L'\n' + AFS::getDisplayPath(folderPath);
msg += L"\n\n";
msg += _("The folders are created automatically when needed.");
@@ -142,9 +142,9 @@ ResolvedBaseFolders initializeBaseFolders(const std::vector<FolderPairCfg>& fpCf
for (const auto& [key, aliases] : ciPathAliases)
if (aliases.size() > 1)
{
- msg += L"\n";
+ msg += L'\n';
for (const AbstractPath& aliasPath : aliases)
- msg += L"\n" + AFS::getDisplayPath(aliasPath);
+ msg += L'\n' + AFS::getDisplayPath(aliasPath);
}
callback.reportWarning(msg, warnings.warnFoldersDifferInCase); //throw X
@@ -204,7 +204,7 @@ ComparisonBuffer::ComparisonBuffer(const std::set<DirectoryKey>& foldersToRead,
const std::chrono::steady_clock::time_point compareStartTime = std::chrono::steady_clock::now();
int itemsReported = 0;
- auto onStatusUpdate = [&, textScanning = _("Scanning:") + L" "](const std::wstring& statusLine, int itemsTotal)
+ auto onStatusUpdate = [&, textScanning = _("Scanning:") + L' '](const std::wstring& statusLine, int itemsTotal)
{
callback.updateDataProcessed(itemsTotal - itemsReported, 0); //noexcept
itemsReported = itemsTotal;
@@ -219,9 +219,9 @@ ComparisonBuffer::ComparisonBuffer(const std::set<DirectoryKey>& foldersToRead,
const int64_t totalTimeSec = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::steady_clock::now() - compareStartTime).count();
- callback.reportInfo(_("Comparison finished:") + L" " +
+ callback.reportInfo(_("Comparison finished:") + L' ' +
_P("1 item found", "%x items found", itemsReported) + L" | " +
- _("Time elapsed:") + L" " + copyStringTo<std::wstring>(wxTimeSpan::Seconds(totalTimeSec).Format())); //throw X
+ _("Time elapsed:") + L' ' + copyStringTo<std::wstring>(wxTimeSpan::Seconds(totalTimeSec).Format())); //throw X
}
@@ -236,49 +236,49 @@ const wchar_t arrowRight[] = L"->";
// => only add path info if information is relevant, e.g. conflict is specific to left/right side only
template <SelectedSide side, class FileOrLinkPair> inline
-Zstringw getConflictInvalidDate(const FileOrLinkPair& file)
+Zstringc getConflictInvalidDate(const FileOrLinkPair& file)
{
- return copyStringTo<Zstringw>(replaceCpy(_("File %x has an invalid date."), L"%x", fmtPath(AFS::getDisplayPath(file.template getAbstractPath<side>()))) + L"\n" +
- _("Date:") + L" " + formatUtcToLocalTime(file.template getLastWriteTime<side>()));
+ return utfTo<Zstringc>(replaceCpy(_("File %x has an invalid date."), L"%x", fmtPath(AFS::getDisplayPath(file.template getAbstractPath<side>()))) + L'\n' +
+ _("Date:") + L' ' + formatUtcToLocalTime(file.template getLastWriteTime<side>()));
}
-Zstringw getConflictSameDateDiffSize(const FilePair& file)
+Zstringc getConflictSameDateDiffSize(const FilePair& file)
{
- return copyStringTo<Zstringw>(_("Files have the same date but a different size.") + L"\n" +
- arrowLeft + L" " + _("Date:") + L" " + formatUtcToLocalTime(file.getLastWriteTime< LEFT_SIDE>()) + L" " + _("Size:") + L" " + formatNumber(file.getFileSize<LEFT_SIDE>()) + L"\n" +
- arrowRight + L" " + _("Date:") + L" " + formatUtcToLocalTime(file.getLastWriteTime<RIGHT_SIDE>()) + L" " + _("Size:") + L" " + formatNumber(file.getFileSize<RIGHT_SIDE>()));
+ return utfTo<Zstringc>(_("Files have the same date but a different size.") + L'\n' +
+ arrowLeft + L' ' + _("Date:") + L' ' + formatUtcToLocalTime(file.getLastWriteTime< LEFT_SIDE>()) + L" " + _("Size:") + L' ' + formatNumber(file.getFileSize<LEFT_SIDE>()) + L'\n' +
+ arrowRight + L' ' + _("Date:") + L' ' + formatUtcToLocalTime(file.getLastWriteTime<RIGHT_SIDE>()) + L" " + _("Size:") + L' ' + formatNumber(file.getFileSize<RIGHT_SIDE>()));
}
-Zstringw getConflictSkippedBinaryComparison()
+Zstringc getConflictSkippedBinaryComparison()
{
- return copyStringTo<Zstringw>(_("Content comparison was skipped for excluded files."));
+ return utfTo<Zstringc>(_("Content comparison was skipped for excluded files."));
}
-Zstringw getDescrDiffMetaShortnameCase(const FileSystemObject& fsObj)
+Zstringc getDescrDiffMetaShortnameCase(const FileSystemObject& fsObj)
{
- return copyStringTo<Zstringw>(_("Items differ in attributes only") + L"\n" +
- arrowLeft + L" " + fmtPath(fsObj.getItemName< LEFT_SIDE>()) + L"\n" +
- arrowRight + L" " + fmtPath(fsObj.getItemName<RIGHT_SIDE>()));
+ return utfTo<Zstringc>(_("Items differ in attributes only") + L'\n' +
+ arrowLeft + L' ' + fmtPath(fsObj.getItemName< LEFT_SIDE>()) + L'\n' +
+ arrowRight + L' ' + fmtPath(fsObj.getItemName<RIGHT_SIDE>()));
}
#if 0
template <class FileOrLinkPair>
-Zstringw getDescrDiffMetaData(const FileOrLinkPair& file)
+Zstringc getDescrDiffMetaData(const FileOrLinkPair& file)
{
- return copyStringTo<Zstringw>(_("Items differ in attributes only") + L"\n" +
- arrowLeft + L" " + _("Date:") + L" " + formatUtcToLocalTime(file.template getLastWriteTime< LEFT_SIDE>()) + L"\n" +
- arrowRight + L" " + _("Date:") + L" " + formatUtcToLocalTime(file.template getLastWriteTime<RIGHT_SIDE>()));
+ return utfTo<Zstringc>(_("Items differ in attributes only") + L'\n' +
+ arrowLeft + L' ' + _("Date:") + L' ' + formatUtcToLocalTime(file.template getLastWriteTime< LEFT_SIDE>()) + L'\n' +
+ arrowRight + L' ' + _("Date:") + L' ' + formatUtcToLocalTime(file.template getLastWriteTime<RIGHT_SIDE>()));
}
#endif
-Zstringw getConflictAmbiguousItemName(const Zstring& itemName)
+Zstringc getConflictAmbiguousItemName(const Zstring& itemName)
{
- return copyStringTo<Zstringw>(replaceCpy(_("The name %x is used by more than one item in the folder."), L"%x", fmtPath(itemName)));
+ return utfTo<Zstringc>(replaceCpy(_("The name %x is used by more than one item in the folder."), L"%x", fmtPath(itemName)));
}
//-----------------------------------------------------------------------------
@@ -392,7 +392,7 @@ void categorizeSymlinkByContent(SymlinkPair& symlink, PhaseCallback& callback)
}, callback); //throw X
if (!errMsg.empty())
- symlink.setCategoryConflict(copyStringTo<Zstringw>(errMsg));
+ symlink.setCategoryConflict(utfTo<Zstringc>(errMsg));
else
{
if (binaryContentL == binaryContentR)
@@ -489,7 +489,7 @@ void categorizeFileByContent(FilePair& file, const std::wstring& txtComparingCon
}, acb); //throw ThreadInterruption
if (!errMsg.empty())
- file.setCategoryConflict(copyStringTo<Zstringw>(errMsg));
+ file.setCategoryConflict(utfTo<Zstringc>(errMsg));
else
{
if (haveSameContent)
@@ -542,7 +542,7 @@ std::list<std::shared_ptr<BaseFolderPair>> ComparisonBuffer::compareByContent(co
//PERF_START;
std::list<std::shared_ptr<BaseFolderPair>> output;
- const Zstringw txtConflictSkippedBinaryComparison = getConflictSkippedBinaryComparison(); //avoid premature pess.: save memory via ref-counted string
+ const Zstringc txtConflictSkippedBinaryComparison = getConflictSkippedBinaryComparison(); //avoid premature pess.: save memory via ref-counted string
for (const auto& [folderPair, fpCfg] : workLoad)
{
@@ -654,7 +654,7 @@ std::list<std::shared_ptr<BaseFolderPair>> ComparisonBuffer::compareByContent(co
class MergeSides
{
public:
- MergeSides(const std::map<ZstringNoCase, Zstringw>& errorsByRelPath,
+ MergeSides(const std::map<ZstringNoCase, Zstringc>& errorsByRelPath,
std::vector<FilePair*>& undefinedFilesOut,
std::vector<SymlinkPair*>& undefinedSymlinksOut) :
errorsByRelPath_(errorsByRelPath),
@@ -671,21 +671,21 @@ public:
}
private:
- void mergeTwoSides(const FolderContainer& lhs, const FolderContainer& rhs, const Zstringw* errorMsg, ContainerObject& output);
+ void mergeTwoSides(const FolderContainer& lhs, const FolderContainer& rhs, const Zstringc* errorMsg, ContainerObject& output);
template <SelectedSide side>
- void fillOneSide(const FolderContainer& folderCont, const Zstringw* errorMsg, ContainerObject& output);
+ void fillOneSide(const FolderContainer& folderCont, const Zstringc* errorMsg, ContainerObject& output);
- const Zstringw* checkFailedRead(FileSystemObject& fsObj, const Zstringw* errorMsg);
+ const Zstringc* checkFailedRead(FileSystemObject& fsObj, const Zstringc* errorMsg);
- const std::map<ZstringNoCase, Zstringw>& errorsByRelPath_; //base-relative paths or empty if read-error for whole base directory
+ const std::map<ZstringNoCase, Zstringc>& errorsByRelPath_; //base-relative paths or empty if read-error for whole base directory
std::vector<FilePair*>& undefinedFiles_;
std::vector<SymlinkPair*>& undefinedSymlinks_;
};
inline
-const Zstringw* MergeSides::checkFailedRead(FileSystemObject& fsObj, const Zstringw* errorMsg)
+const Zstringc* MergeSides::checkFailedRead(FileSystemObject& fsObj, const Zstringc* errorMsg)
{
if (!errorMsg)
{
@@ -697,15 +697,15 @@ const Zstringw* MergeSides::checkFailedRead(FileSystemObject& fsObj, const Zstri
if (errorMsg)
{
fsObj.setActive(false);
- fsObj.setCategoryConflict(*errorMsg); //peak memory: Zstringw is ref-counted, unlike std::wstring!
- static_assert(std::is_same_v<const Zstringw&, decltype(*errorMsg)>);
+ fsObj.setCategoryConflict(*errorMsg); //peak memory: Zstringc is ref-counted, unlike std::string!
+ static_assert(std::is_same_v<const Zstringc&, decltype(*errorMsg)>);
}
return errorMsg;
}
template <SelectedSide side>
-void MergeSides::fillOneSide(const FolderContainer& folderCont, const Zstringw* errorMsg, ContainerObject& output)
+void MergeSides::fillOneSide(const FolderContainer& folderCont, const Zstringc* errorMsg, ContainerObject& output)
{
for (const auto& [fileName, attrib] : folderCont.files)
{
@@ -722,7 +722,7 @@ void MergeSides::fillOneSide(const FolderContainer& folderCont, const Zstringw*
for (const auto& [folderName, attrAndSub] : folderCont.folders)
{
FolderPair& newFolder = output.addSubFolder<side>(folderName, attrAndSub.first);
- const Zstringw* errorMsgNew = checkFailedRead(newFolder, errorMsg);
+ const Zstringc* errorMsgNew = checkFailedRead(newFolder, errorMsg);
fillOneSide<side>(attrAndSub.second, errorMsgNew, newFolder); //recurse
}
}
@@ -783,7 +783,7 @@ void matchFolders(const MapType& mapLeft, const MapType& mapRight, ProcessLeftOn
auto itEndCase = std::find_if(itCase + 1, itEndEq, [&](const FileRef& fr) { return getUnicodeNormalForm(fr.ref->first) != getUnicodeNormalForm(itCase->ref->first); });
if (!tryMatchRange(itCase, itEndCase))
{
- const Zstringw& conflictMsg = getConflictAmbiguousItemName(itCase->ref->first);
+ const Zstringc& conflictMsg = getConflictAmbiguousItemName(itCase->ref->first);
std::for_each(itCase, itEndCase, [&](const FileRef& fr)
{
if (fr.leftSide)
@@ -800,16 +800,16 @@ void matchFolders(const MapType& mapLeft, const MapType& mapRight, ProcessLeftOn
}
-void MergeSides::mergeTwoSides(const FolderContainer& lhs, const FolderContainer& rhs, const Zstringw* errorMsg, ContainerObject& output)
+void MergeSides::mergeTwoSides(const FolderContainer& lhs, const FolderContainer& rhs, const Zstringc* errorMsg, ContainerObject& output)
{
using FileData = FolderContainer::FileList::value_type;
- matchFolders(lhs.files, rhs.files, [&](const FileData& fileLeft, const Zstringw* conflictMsg)
+ matchFolders(lhs.files, rhs.files, [&](const FileData& fileLeft, const Zstringc* conflictMsg)
{
FilePair& newItem = output.addSubFile< LEFT_SIDE>(fileLeft .first, fileLeft .second);
checkFailedRead(newItem, conflictMsg ? conflictMsg : errorMsg);
},
- [&](const FileData& fileRight, const Zstringw* conflictMsg)
+ [&](const FileData& fileRight, const Zstringc* conflictMsg)
{
FilePair& newItem = output.addSubFile<RIGHT_SIDE>(fileRight.first, fileRight.second);
checkFailedRead(newItem, conflictMsg ? conflictMsg : errorMsg);
@@ -829,12 +829,12 @@ void MergeSides::mergeTwoSides(const FolderContainer& lhs, const FolderContainer
//-----------------------------------------------------------------------------------------------
using SymlinkData = FolderContainer::SymlinkList::value_type;
- matchFolders(lhs.symlinks, rhs.symlinks, [&](const SymlinkData& symlinkLeft, const Zstringw* conflictMsg)
+ matchFolders(lhs.symlinks, rhs.symlinks, [&](const SymlinkData& symlinkLeft, const Zstringc* conflictMsg)
{
SymlinkPair& newItem = output.addSubLink< LEFT_SIDE>(symlinkLeft .first, symlinkLeft .second);
checkFailedRead(newItem, conflictMsg ? conflictMsg : errorMsg);
},
- [&](const SymlinkData& symlinkRight, const Zstringw* conflictMsg)
+ [&](const SymlinkData& symlinkRight, const Zstringc* conflictMsg)
{
SymlinkPair& newItem = output.addSubLink<RIGHT_SIDE>(symlinkRight.first, symlinkRight.second);
checkFailedRead(newItem, conflictMsg ? conflictMsg : errorMsg);
@@ -853,22 +853,22 @@ void MergeSides::mergeTwoSides(const FolderContainer& lhs, const FolderContainer
//-----------------------------------------------------------------------------------------------
using FolderData = FolderContainer::FolderList::value_type;
- matchFolders(lhs.folders, rhs.folders, [&](const FolderData& dirLeft, const Zstringw* conflictMsg)
+ matchFolders(lhs.folders, rhs.folders, [&](const FolderData& dirLeft, const Zstringc* conflictMsg)
{
FolderPair& newFolder = output.addSubFolder<LEFT_SIDE>(dirLeft.first, dirLeft.second.first);
- const Zstringw* errorMsgNew = checkFailedRead(newFolder, conflictMsg ? conflictMsg : errorMsg);
+ const Zstringc* errorMsgNew = checkFailedRead(newFolder, conflictMsg ? conflictMsg : errorMsg);
this->fillOneSide<LEFT_SIDE>(dirLeft.second.second, errorMsgNew, newFolder); //recurse
},
- [&](const FolderData& dirRight, const Zstringw* conflictMsg)
+ [&](const FolderData& dirRight, const Zstringc* conflictMsg)
{
FolderPair& newFolder = output.addSubFolder<RIGHT_SIDE>(dirRight.first, dirRight.second.first);
- const Zstringw* errorMsgNew = checkFailedRead(newFolder, conflictMsg ? conflictMsg : errorMsg);
+ const Zstringc* errorMsgNew = checkFailedRead(newFolder, conflictMsg ? conflictMsg : errorMsg);
this->fillOneSide<RIGHT_SIDE>(dirRight.second.second, errorMsgNew, newFolder); //recurse
},
[&](const FolderData& dirLeft, const FolderData& dirRight)
{
FolderPair& newFolder = output.addSubFolder(dirLeft.first, dirLeft.second.first, DIR_EQUAL, dirRight.first, dirRight.second.first);
- const Zstringw* errorMsgNew = checkFailedRead(newFolder, errorMsg);
+ const Zstringc* errorMsgNew = checkFailedRead(newFolder, errorMsg);
if (!errorMsgNew)
if (getUnicodeNormalForm(dirLeft.first) !=
@@ -925,12 +925,12 @@ std::shared_ptr<BaseFolderPair> ComparisonBuffer::performComparison(const Resolv
const DirectoryValue* bufValueLeft = getDirValue(fp.folderPathLeft);
const DirectoryValue* bufValueRight = getDirValue(fp.folderPathRight);
- std::map<ZstringNoCase, Zstringw> failedReads; //base-relative paths or empty if read-error for whole base directory
+ std::map<ZstringNoCase, Zstringc> failedReads; //base-relative paths or empty if read-error for whole base directory
{
- auto append = [&](const std::map<Zstring, std::wstring>& c)
+ auto append = [&](const std::map<Zstring, Zstringc>& c)
{
for (const auto& [relPath, errorMsg] : c)
- failedReads.emplace(relPath, copyStringTo<Zstringw>(errorMsg));
+ failedReads.emplace(relPath, errorMsg);
};
//mix failedFolderReads with failedItemReads:
@@ -948,7 +948,7 @@ std::shared_ptr<BaseFolderPair> ComparisonBuffer::performComparison(const Resolv
excludefilterFailedRead += Zstr("*\n");
else
for (const auto& [relPath, errorMsg] : failedReads)
- excludefilterFailedRead += relPath.upperCase + Zstr("\n"); //exclude item AND (potential) child items!
+ excludefilterFailedRead += relPath.upperCase + Zstr('\n'); //exclude item AND (potential) child items!
//somewhat obscure, but it's possible on Linux file systems to have a backslash as part of a file name
//=> avoid misinterpretation when parsing the filter phrase in PathFilter (see path_filter.cpp::addFilterEntry())
@@ -986,37 +986,6 @@ std::shared_ptr<BaseFolderPair> ComparisonBuffer::performComparison(const Resolv
}
-void fff::logNonDefaultSettings(const XmlGlobalSettings& activeSettings, PhaseCallback& callback)
-{
- const XmlGlobalSettings defaultSettings;
- std::wstring changedSettingsMsg;
-
- if (activeSettings.failSafeFileCopy != defaultSettings.failSafeFileCopy)
- changedSettingsMsg += L"\n " + _("Fail-safe file copy") + L" - " + (activeSettings.failSafeFileCopy ? _("Enabled") : _("Disabled"));
-
- if (activeSettings.copyLockedFiles != defaultSettings.copyLockedFiles)
- changedSettingsMsg += L"\n " + _("Copy locked files") + L" - " + (activeSettings.copyLockedFiles ? _("Enabled") : _("Disabled"));
-
- if (activeSettings.copyFilePermissions != defaultSettings.copyFilePermissions)
- changedSettingsMsg += L"\n " + _("Copy file access permissions") + L" - " + (activeSettings.copyFilePermissions ? _("Enabled") : _("Disabled"));
-
- if (activeSettings.fileTimeTolerance != defaultSettings.fileTimeTolerance)
- changedSettingsMsg += L"\n " + _("File time tolerance") + L" - " + numberTo<std::wstring>(activeSettings.fileTimeTolerance);
-
- if (activeSettings.runWithBackgroundPriority != defaultSettings.runWithBackgroundPriority)
- changedSettingsMsg += L"\n " + _("Run with background priority") + L" - " + (activeSettings.runWithBackgroundPriority ? _("Enabled") : _("Disabled"));
-
- if (activeSettings.createLockFile != defaultSettings.createLockFile)
- changedSettingsMsg += L"\n " + _("Lock directories during sync") + L" - " + (activeSettings.createLockFile ? _("Enabled") : _("Disabled"));
-
- if (activeSettings.verifyFileCopy != defaultSettings.verifyFileCopy)
- changedSettingsMsg += L"\n " + _("Verify copied files") + L" - " + (activeSettings.verifyFileCopy ? _("Enabled") : _("Disabled"));
-
- if (!changedSettingsMsg.empty())
- callback.reportInfo(_("Using non-default global settings:") + changedSettingsMsg); //throw X
-}
-
-
FolderComparison fff::compare(WarningDialogs& warnings,
int fileTimeTolerance,
bool allowUserInteraction,
@@ -1062,7 +1031,7 @@ FolderComparison fff::compare(WarningDialogs& warnings,
allowUserInteraction, warnings, callback); //throw X
//directory existence only checked *once* to avoid race conditions!
if (resInfo.resolvedPairs.size() != fpCfgList.size())
- throw std::logic_error("Contract violation! " + std::string(__FILE__) + ":" + numberTo<std::string>(__LINE__));
+ throw std::logic_error("Contract violation! " + std::string(__FILE__) + ':' + numberTo<std::string>(__LINE__));
auto basefolderExisting = [&](const AbstractPath& folderPath) { return contains(resInfo.existingBaseFolders, folderPath); };
@@ -1099,14 +1068,14 @@ FolderComparison fff::compare(WarningDialogs& warnings,
folderPair.folderPathRight, fpCfg.filter.nameFilter.ref()))
{
msg += L"\n\n" +
- AFS::getDisplayPath(folderPair.folderPathLeft) + L"\n" +
+ AFS::getDisplayPath(folderPair.folderPathLeft) + L'\n' +
AFS::getDisplayPath(folderPair.folderPathRight);
if (!pd->relPath.empty())
- msg += L"\n" + _("Exclude:") + L" " + utfTo<std::wstring>(FILE_NAME_SEPARATOR + pd->relPath + FILE_NAME_SEPARATOR);
+ msg += L'\n' + _("Exclude:") + L' ' + utfTo<std::wstring>(FILE_NAME_SEPARATOR + pd->relPath + FILE_NAME_SEPARATOR);
}
if (!msg.empty())
- callback.reportWarning(_("One base folder of a folder pair is contained in the other one.") + L"\n" + //throw X
+ callback.reportWarning(_("One base folder of a folder pair is contained in the other one.") + L'\n' + //throw X
_("The folder should be excluded from synchronization via filter.") + msg, warnings.warnDependentFolderPair);
}
//-------------------end of basic checks------------------------------------------
@@ -1187,7 +1156,7 @@ FolderComparison fff::compare(WarningDialogs& warnings,
}
catch (const std::bad_alloc& e)
{
- callback.reportFatalError(_("Out of memory.") + L" " + utfTo<std::wstring>(e.what()));
+ callback.reportFatalError(_("Out of memory.") + L' ' + utfTo<std::wstring>(e.what()));
return {};
}
}
diff --git a/FreeFileSync/Source/base/comparison.h b/FreeFileSync/Source/base/comparison.h
index b3315926..d547ee05 100644
--- a/FreeFileSync/Source/base/comparison.h
+++ b/FreeFileSync/Source/base/comparison.h
@@ -7,7 +7,7 @@
#ifndef COMPARISON_H_8032178534545426
#define COMPARISON_H_8032178534545426
-#include "config.h"
+//#include "config.h"
#include "file_hierarchy.h"
#include "process_callback.h"
#include "norm_filter.h"
@@ -47,9 +47,6 @@ struct FolderPairCfg
std::vector<FolderPairCfg> extractCompareCfg(const MainConfiguration& mainCfg); //fill FolderPairCfg and resolve folder pairs
-//inform about (important) non-default global settings related to comparison and synchronization
-void logNonDefaultSettings(const XmlGlobalSettings& currentSettings, PhaseCallback& callback);
-
//FFS core routine: output.size() == fpCfgList.size() or 0 on fatal error
FolderComparison compare(WarningDialogs& warnings,
int fileTimeTolerance,
diff --git a/FreeFileSync/Source/base/db_file.cpp b/FreeFileSync/Source/base/db_file.cpp
index 94a6afc4..23e42776 100644
--- a/FreeFileSync/Source/base/db_file.cpp
+++ b/FreeFileSync/Source/base/db_file.cpp
@@ -30,7 +30,7 @@ DEFINE_NEW_FILE_ERROR(FileErrorDatabaseNotExisting)
struct SessionData
{
bool isLeadStream = false;
- ByteArray rawStream;
+ std::string rawStream;
};
bool operator==(const SessionData& lhs, const SessionData& rhs) { return lhs.isLeadStream == rhs.isLeadStream && lhs.rawStream == rhs.rawStream; }
@@ -77,8 +77,8 @@ void saveStreams(const DbStreams& streamList, const AbstractPath& dbPath, const
{
writeContainer<std::string>(memStreamOut, sessionID);
- writeNumber <int8_t >(memStreamOut, sessionData.isLeadStream);
- writeContainer<ByteArray>(memStreamOut, sessionData.rawStream);
+ writeNumber<int8_t>(memStreamOut, sessionData.isLeadStream);
+ writeContainer (memStreamOut, sessionData.rawStream);
}
writeNumber<uint32_t>(memStreamOut, getCrc32(memStreamOut.ref()));
@@ -139,10 +139,10 @@ DbStreams loadStreams(const AbstractPath& dbPath, const IOCallback& notifyUnbuff
{
assert(byteStream.size() >= sizeof(uint32_t)); //obviously in this context!
MemoryStreamOut<std::string> crcStreamOut;
- writeNumber<uint32_t>(crcStreamOut, getCrc32({ byteStream.begin(), byteStream.end() - sizeof(uint32_t) }));
+ writeNumber<uint32_t>(crcStreamOut, getCrc32(byteStream.begin(), byteStream.end() - sizeof(uint32_t)));
if (!endsWith(byteStream, crcStreamOut.ref()))
- throw FileError(_("Database file is corrupted:") + L" " + fmtPath(AFS::getDisplayPath(dbPath)), L"Invalid checksum.");
+ throw FileError(_("Database file is corrupted:") + L' ' + fmtPath(AFS::getDisplayPath(dbPath)), L"Invalid checksum.");
}
DbStreams output;
@@ -157,7 +157,7 @@ DbStreams loadStreams(const AbstractPath& dbPath, const IOCallback& notifyUnbuff
if (version == 9) //TODO: remove migration code at some time! v9 used until 2017-02-01
{
- sessionData.rawStream = readContainer<ByteArray>(memStreamIn); //throw UnexpectedEndOfStreamError
+ sessionData.rawStream = readContainer<std::string>(memStreamIn); //throw UnexpectedEndOfStreamError
MemoryStreamIn streamIn(sessionData.rawStream);
const int streamVersion = readNumber<int32_t>(streamIn); //throw UnexpectedEndOfStreamError
@@ -167,8 +167,8 @@ DbStreams loadStreams(const AbstractPath& dbPath, const IOCallback& notifyUnbuff
}
else
{
- sessionData.isLeadStream = readNumber <int8_t >(memStreamIn) != 0; //throw UnexpectedEndOfStreamError
- sessionData.rawStream = readContainer<ByteArray>(memStreamIn); //
+ sessionData.isLeadStream = readNumber <int8_t >(memStreamIn) != 0; //throw UnexpectedEndOfStreamError
+ sessionData.rawStream = readContainer<std::string>(memStreamIn); //
}
output[sessionID] = std::move(sessionData);
@@ -177,7 +177,7 @@ DbStreams loadStreams(const AbstractPath& dbPath, const IOCallback& notifyUnbuff
}
catch (UnexpectedEndOfStreamError&)
{
- throw FileError(_("Database file is corrupted:") + L" " + fmtPath(AFS::getDisplayPath(dbPath)), L"Unexpected end of stream.");
+ throw FileError(_("Database file is corrupted:") + L' ' + fmtPath(AFS::getDisplayPath(dbPath)), L"Unexpected end of stream.");
}
}
@@ -189,16 +189,16 @@ public:
static void execute(const InSyncFolder& dbFolder, //throw FileError
const std::wstring& displayFilePathL, //used for diagnostics only
const std::wstring& displayFilePathR,
- ByteArray& streamL,
- ByteArray& streamR)
+ std::string& streamL,
+ std::string& streamR)
{
- MemoryStreamOut<ByteArray> outL;
- MemoryStreamOut<ByteArray> outR;
+ MemoryStreamOut<std::string> outL;
+ MemoryStreamOut<std::string> outR;
//save format version
writeNumber<int32_t>(outL, DB_STREAM_VERSION);
writeNumber<int32_t>(outR, DB_STREAM_VERSION);
- auto compStream = [&](const ByteArray& stream) -> ByteArray //throw FileError
+ auto compStream = [&](const std::string& stream) //throw FileError
{
try
{
@@ -227,16 +227,16 @@ public:
generator.recurse(dbFolder);
//PERF_STOP
- const ByteArray bufText = compStream(generator.streamOutText_ .ref());
- const ByteArray bufSmallNum = compStream(generator.streamOutSmallNum_.ref());
- const ByteArray bufBigNum = compStream(generator.streamOutBigNum_ .ref());
+ const std::string bufText = compStream(generator.streamOutText_ .ref());
+ const std::string bufSmallNum = compStream(generator.streamOutSmallNum_.ref());
+ const std::string bufBigNum = compStream(generator.streamOutBigNum_ .ref());
- MemoryStreamOut<ByteArray> streamOut;
+ MemoryStreamOut<std::string> streamOut;
writeContainer(streamOut, bufText);
writeContainer(streamOut, bufSmallNum);
writeContainer(streamOut, bufBigNum);
- const ByteArray& buf = streamOut.ref();
+ const std::string& buf = streamOut.ref();
//distribute "outputBoth" over left and right streams:
const size_t size1stPart = buf.size() / 2;
@@ -245,11 +245,11 @@ public:
writeNumber<uint64_t>(outL, size1stPart);
writeNumber<uint64_t>(outR, size2ndPart);
- if (size1stPart > 0) writeArray(outL, &*buf.begin(), size1stPart);
- if (size2ndPart > 0) writeArray(outR, &*buf.begin() + size1stPart, size2ndPart);
+ if (size1stPart > 0) writeArray(outL, &buf[0], size1stPart);
+ if (size2ndPart > 0) writeArray(outR, &buf[0] + size1stPart, size2ndPart);
- streamL = outL.ref();
- streamR = outR.ref();
+ streamL = std::move(outL.ref());
+ streamR = std::move(outR.ref());
}
private:
@@ -286,25 +286,25 @@ private:
}
}
- static void writeUtf8(MemoryStreamOut<ByteArray>& streamOut, const Zstring& str) { writeContainer(streamOut, utfTo<Zbase<char>>(str)); }
+ static void writeUtf8(MemoryStreamOut<std::string>& streamOut, const Zstring& str) { writeContainer(streamOut, utfTo<std::string>(str)); }
- static void writeFileDescr(MemoryStreamOut<ByteArray>& streamOut, const InSyncDescrFile& descr)
+ static void writeFileDescr(MemoryStreamOut<std::string>& streamOut, const InSyncDescrFile& descr)
{
writeNumber<int64_t>(streamOut, descr.modTime);
writeContainer(streamOut, descr.fileId);
- static_assert(std::is_same_v<decltype(descr.fileId), Zbase<char>>);
+ static_assert(std::is_same_v<decltype(descr.fileId), std::string>);
}
- static void writeLinkDescr(MemoryStreamOut<ByteArray>& streamOut, const InSyncDescrLink& descr)
+ static void writeLinkDescr(MemoryStreamOut<std::string>& streamOut, const InSyncDescrLink& descr)
{
writeNumber<int64_t>(streamOut, descr.modTime);
}
//maximize zlib compression by grouping similar data (=> 20% size reduction!)
// -> further ~5% reduction possible by having one container per data type
- MemoryStreamOut<ByteArray> streamOutText_; //
- MemoryStreamOut<ByteArray> streamOutSmallNum_; //data with bias to lead side (= always left in this context)
- MemoryStreamOut<ByteArray> streamOutBigNum_; //
+ MemoryStreamOut<std::string> streamOutText_; //
+ MemoryStreamOut<std::string> streamOutSmallNum_; //data with bias to lead side (= always left in this context)
+ MemoryStreamOut<std::string> streamOutBigNum_; //
};
@@ -312,12 +312,12 @@ class StreamParser
{
public:
static SharedRef<InSyncFolder> execute(bool leadStreamLeft, //throw FileError
- const ByteArray& streamL,
- const ByteArray& streamR,
+ const std::string& streamL,
+ const std::string& streamR,
const std::wstring& displayFilePathL, //for diagnostics only
const std::wstring& displayFilePathR)
{
- auto decompStream = [&](const ByteArray& stream) -> ByteArray //throw FileError
+ auto decompStream = [&](const std::string& stream) //throw FileError
{
try
{
@@ -338,7 +338,7 @@ public:
const int streamVersionR = readNumber<int32_t>(streamInR); //
if (streamVersion != streamVersionR)
- throw FileError(_("Database file is corrupted:") + L"\n" + fmtPath(displayFilePathL) + L"\n" + fmtPath(displayFilePathR), L"Different stream formats");
+ throw FileError(_("Database file is corrupted:") + L'\n' + fmtPath(displayFilePathL) + L'\n' + fmtPath(displayFilePathR), L"Different stream formats");
//TODO: remove migration code at some time! 2017-02-01
if (streamVersion != 2 &&
@@ -352,23 +352,22 @@ public:
const bool has1stPartR = readNumber<int8_t>(streamInR) != 0; //
if (has1stPartL == has1stPartR)
- throw FileError(_("Database file is corrupted:") + L"\n" + fmtPath(displayFilePathL) + L"\n" + fmtPath(displayFilePathR), L"Second stream part missing");
+ throw FileError(_("Database file is corrupted:") + L'\n' + fmtPath(displayFilePathL) + L'\n' + fmtPath(displayFilePathR), L"Second stream part missing");
if (has1stPartL != leadStreamLeft)
- throw FileError(_("Database file is corrupted:") + L"\n" + fmtPath(displayFilePathL) + L"\n" + fmtPath(displayFilePathR), L"has1stPartL != leadStreamLeft");
+ throw FileError(_("Database file is corrupted:") + L'\n' + fmtPath(displayFilePathL) + L'\n' + fmtPath(displayFilePathR), L"has1stPartL != leadStreamLeft");
- MemoryStreamIn<ByteArray>& in1stPart = leadStreamLeft ? streamInL : streamInR;
- MemoryStreamIn<ByteArray>& in2ndPart = leadStreamLeft ? streamInR : streamInL;
+ MemoryStreamIn<std::string>& in1stPart = leadStreamLeft ? streamInL : streamInR;
+ MemoryStreamIn<std::string>& in2ndPart = leadStreamLeft ? streamInR : streamInL;
const size_t size1stPart = static_cast<size_t>(readNumber<uint64_t>(in1stPart));
const size_t size2ndPart = static_cast<size_t>(readNumber<uint64_t>(in2ndPart));
- ByteArray tmpB;
- tmpB.resize(size1stPart + size2ndPart); //throw std::bad_alloc
- readArray(in1stPart, &*tmpB.begin(), size1stPart); //stream always non-empty
- readArray(in2ndPart, &*tmpB.begin() + size1stPart, size2ndPart); //throw UnexpectedEndOfStreamError
+ std::string tmpB(size1stPart + size2ndPart, '\0'); //throw std::bad_alloc
+ readArray(in1stPart, &tmpB[0], size1stPart); //stream always non-empty
+ readArray(in2ndPart, &tmpB[0] + size1stPart, size2ndPart); //throw UnexpectedEndOfStreamError
- const ByteArray tmpL = readContainer<ByteArray>(streamInL);
- const ByteArray tmpR = readContainer<ByteArray>(streamInR);
+ const std::string tmpL = readContainer<std::string>(streamInL);
+ const std::string tmpR = readContainer<std::string>(streamInR);
auto output = makeSharedRef<InSyncFolder>(InSyncFolder::DIR_STATUS_IN_SYNC);
StreamParserV2 parser(decompStream(tmpL),
@@ -379,22 +378,20 @@ public:
}
else
{
- MemoryStreamIn<ByteArray>& streamInPart1 = leadStreamLeft ? streamInL : streamInR;
- MemoryStreamIn<ByteArray>& streamInPart2 = leadStreamLeft ? streamInR : streamInL;
+ MemoryStreamIn<std::string>& streamInPart1 = leadStreamLeft ? streamInL : streamInR;
+ MemoryStreamIn<std::string>& streamInPart2 = leadStreamLeft ? streamInR : streamInL;
const size_t sizePart1 = static_cast<size_t>(readNumber<uint64_t>(streamInPart1));
const size_t sizePart2 = static_cast<size_t>(readNumber<uint64_t>(streamInPart2));
- ByteArray buf;
- buf.resize(sizePart1 + sizePart2); //throw std::bad_alloc
-
- if (sizePart1 > 0) readArray(streamInPart1, &*buf.begin(), sizePart1); //throw UnexpectedEndOfStreamError
- if (sizePart2 > 0) readArray(streamInPart2, &*buf.begin() + sizePart1, sizePart2); //
+ std::string buf(sizePart1 + sizePart2, '\0');
+ if (sizePart1 > 0) readArray(streamInPart1, &buf[0], sizePart1); //throw UnexpectedEndOfStreamError
+ if (sizePart2 > 0) readArray(streamInPart2, &buf[0] + sizePart1, sizePart2); //
MemoryStreamIn streamIn(buf);
- const ByteArray bufText = readContainer<ByteArray>(streamIn); //
- const ByteArray bufSmallNum = readContainer<ByteArray>(streamIn); //throw UnexpectedEndOfStreamError
- const ByteArray bufBigNum = readContainer<ByteArray>(streamIn); //
+ const std::string bufText = readContainer<std::string>(streamIn); //
+ const std::string bufSmallNum = readContainer<std::string>(streamIn); //throw UnexpectedEndOfStreamError
+ const std::string bufBigNum = readContainer<std::string>(streamIn); //
auto output = makeSharedRef<InSyncFolder>(InSyncFolder::DIR_STATUS_IN_SYNC);
StreamParser parser(streamVersion,
@@ -410,12 +407,12 @@ public:
}
catch (UnexpectedEndOfStreamError&)
{
- throw FileError(_("Database file is corrupted:") + L"\n" + fmtPath(displayFilePathL) + L"\n" + fmtPath(displayFilePathR), L"Unexpected end of stream.");
+ throw FileError(_("Database file is corrupted:") + L'\n' + fmtPath(displayFilePathL) + L'\n' + fmtPath(displayFilePathR), L"Unexpected end of stream.");
}
}
private:
- StreamParser(int streamVersion, const ByteArray& bufText, const ByteArray& bufSmallNumbers, const ByteArray& bufBigNumbers) :
+ StreamParser(int streamVersion, const std::string& bufText, const std::string& bufSmallNumbers, const std::string& bufBigNumbers) :
streamVersion_(streamVersion),
streamInText_(bufText),
streamInSmallNum_(bufSmallNumbers),
@@ -467,20 +464,20 @@ private:
}
}
- static Zstring readUtf8(MemoryStreamIn<ByteArray>& streamIn) { return utfTo<Zstring>(readContainer<Zbase<char>>(streamIn)); } //throw UnexpectedEndOfStreamError
+ static Zstring readUtf8(MemoryStreamIn<std::string>& streamIn) { return utfTo<Zstring>(readContainer<std::string>(streamIn)); } //throw UnexpectedEndOfStreamError
//optional: use null-termination: 5% overall size reduction
//optional: split into streamInText_/streamInSmallNum_: overall size increase! (why?)
- static InSyncDescrFile readFileDescr(MemoryStreamIn<ByteArray>& streamIn) //throw UnexpectedEndOfStreamError
+ static InSyncDescrFile readFileDescr(MemoryStreamIn<std::string>& streamIn) //throw UnexpectedEndOfStreamError
{
//attention: order of function argument evaluation is undefined! So do it one after the other...
const auto modTime = readNumber<int64_t>(streamIn); //throw UnexpectedEndOfStreamError
- const AFS::FileId fileId = readContainer<Zbase<char>>(streamIn);
+ const auto fileId = readContainer<AFS::FileId>(streamIn);
return InSyncDescrFile(modTime, fileId);
}
- static InSyncDescrLink readLinkDescr(MemoryStreamIn<ByteArray>& streamIn) //throw UnexpectedEndOfStreamError
+ static InSyncDescrLink readLinkDescr(MemoryStreamIn<std::string>& streamIn) //throw UnexpectedEndOfStreamError
{
const auto modTime = readNumber<int64_t>(streamIn);
return InSyncDescrLink(modTime);
@@ -490,9 +487,9 @@ private:
class StreamParserV2
{
public:
- StreamParserV2(const ByteArray& bufferL,
- const ByteArray& bufferR,
- const ByteArray& bufferB) :
+ StreamParserV2(const std::string& bufferL,
+ const std::string& bufferR,
+ const std::string& bufferB) :
inputLeft_ (bufferL),
inputRight_(bufferR),
inputBoth_ (bufferB) {}
@@ -532,15 +529,15 @@ private:
}
private:
- MemoryStreamIn<ByteArray> inputLeft_; //data related to one side only
- MemoryStreamIn<ByteArray> inputRight_; //
- MemoryStreamIn<ByteArray> inputBoth_; //data concerning both sides
+ MemoryStreamIn<std::string> inputLeft_; //data related to one side only
+ MemoryStreamIn<std::string> inputRight_; //
+ MemoryStreamIn<std::string> inputBoth_; //data concerning both sides
};
const int streamVersion_;
- MemoryStreamIn<ByteArray> streamInText_; //
- MemoryStreamIn<ByteArray> streamInSmallNum_; //data with bias to lead side
- MemoryStreamIn<ByteArray> streamInBigNum_; //
+ MemoryStreamIn<std::string> streamInText_; //
+ MemoryStreamIn<std::string> streamInSmallNum_; //data with bias to lead side
+ MemoryStreamIn<std::string> streamInBigNum_; //
};
//#######################################################################################################################################
@@ -757,7 +754,7 @@ std::pair<DbStreams::const_iterator,
if (itL->second.isLeadStream != itR->second.isLeadStream)
{
if (itCommonL != streamsLeft.end()) //should not be possible!
- throw FileError(_("Database file is corrupted:") + L"\n" + fmtPath(displayFilePathL) + L"\n" + fmtPath(displayFilePathR),
+ throw FileError(_("Database file is corrupted:") + L'\n' + fmtPath(displayFilePathL) + L'\n' + fmtPath(displayFilePathR),
L"Multiple common sessions found.");
itCommonL = itL;
itCommonR = itR;
diff --git a/FreeFileSync/Source/base/dir_exist_async.h b/FreeFileSync/Source/base/dir_exist_async.h
index 74572919..ff431902 100644
--- a/FreeFileSync/Source/base/dir_exist_async.h
+++ b/FreeFileSync/Source/base/dir_exist_async.h
@@ -103,7 +103,7 @@ FolderStatus getFolderStatusNonBlocking(const std::set<AbstractPath>& folderPath
if (!isReady(future))
output.failedChecks.emplace(folderPath, FileError(replaceCpy(_("Timeout while searching for folder %x."), L"%x", displayPathFmt) +
- L" [" + _P("1 sec", "%x sec", deviceTimeOutSec) + L"]"));
+ L" [" + _P("1 sec", "%x sec", deviceTimeOutSec) + L']'));
else
try
{
diff --git a/FreeFileSync/Source/base/dir_lock.cpp b/FreeFileSync/Source/base/dir_lock.cpp
index ab76158f..5ba444c7 100644
--- a/FreeFileSync/Source/base/dir_lock.cpp
+++ b/FreeFileSync/Source/base/dir_lock.cpp
@@ -149,7 +149,7 @@ LockInformation getLockInfoFromCurrentProcess() //throw FileError
std::vector<char> buffer(10000);
if (::gethostname(&buffer[0], buffer.size()) != 0)
THROW_LAST_FILE_ERROR(_("Cannot get process information."), L"gethostname");
- lockInfo.computerName = osName + " " + &buffer[0] + ".";
+ lockInfo.computerName = osName + ' ' + &buffer[0] + '.';
if (::getdomainname(&buffer[0], buffer.size()) != 0)
THROW_LAST_FILE_ERROR(_("Cannot get process information."), L"getdomainname");
@@ -182,7 +182,7 @@ std::string serialize(const LockInformation& lockInfo)
writeNumber<uint64_t>(streamOut, lockInfo.processId);
writeNumber<uint32_t>(streamOut, getCrc32(streamOut.ref()));
- writeArray(streamOut, "x", 1); //sentinel: mark logical end with a non-whitespace character
+ writeArray(streamOut, "x", 1); //sentinel: mark logical end with a non-space character
return streamOut.ref();
}
@@ -206,12 +206,14 @@ LockInformation unserialize(const std::string& byteStream) //throw UnexpectedEnd
;
else //catch data corruption ASAP + don't rely on std::bad_alloc for consistency checking
{
- std::string byteStreamTrm = trimCpy(byteStream, false, true); //get rid of space chars
- assert(byteStreamTrm.size() >= sizeof(uint32_t) + sizeof('x')); //obviously in this context!
- byteStreamTrm.pop_back();
+ const size_t posEnd = byteStream.rfind('x'); //skip blanks (+ unrelated corrupted data e.g. nulls!)
+ if (posEnd == std::string::npos)
+ throw UnexpectedEndOfStreamError(); //well, not really...!?
+
+ const std::string_view byteStreamTrm = makeStringView(byteStream.begin(), posEnd);
MemoryStreamOut<std::string> crcStreamOut;
- writeNumber<uint32_t>(crcStreamOut, getCrc32({ byteStreamTrm.begin(), byteStreamTrm.end() - sizeof(uint32_t) }));
+ writeNumber<uint32_t>(crcStreamOut, getCrc32(byteStreamTrm.begin(), byteStreamTrm.end() - sizeof(uint32_t)));
if (!endsWith(byteStreamTrm, crcStreamOut.ref()))
throw UnexpectedEndOfStreamError(); //well, not really...!?
diff --git a/FreeFileSync/Source/base/file_hierarchy.cpp b/FreeFileSync/Source/base/file_hierarchy.cpp
index 1f10a793..debaa031 100644
--- a/FreeFileSync/Source/base/file_hierarchy.cpp
+++ b/FreeFileSync/Source/base/file_hierarchy.cpp
@@ -359,7 +359,7 @@ const wchar_t arrowRight[] = L"->";
std::wstring fff::getCategoryDescription(const FileSystemObject& fsObj)
{
- const std::wstring footer = L"\n[" + utfTo<std::wstring>(fsObj. getItemNameAny()) + L"]";
+ const std::wstring footer = L"\n[" + utfTo<std::wstring>(fsObj. getItemNameAny()) + L']';
const CompareFileResult cmpRes = fsObj.getCategory();
switch (cmpRes)
@@ -379,21 +379,21 @@ std::wstring fff::getCategoryDescription(const FileSystemObject& fsObj)
[&](const FilePair& file)
{
descr += std::wstring(L"\n") +
- arrowLeft + L" " + formatUtcToLocalTime(file.getLastWriteTime< LEFT_SIDE>()) + L"\n" +
- arrowRight + L" " + formatUtcToLocalTime(file.getLastWriteTime<RIGHT_SIDE>());
+ arrowLeft + L' ' + formatUtcToLocalTime(file.getLastWriteTime< LEFT_SIDE>()) + L'\n' +
+ arrowRight + L' ' + formatUtcToLocalTime(file.getLastWriteTime<RIGHT_SIDE>());
},
[&](const SymlinkPair& symlink)
{
descr += std::wstring(L"\n") +
- arrowLeft + L" " + formatUtcToLocalTime(symlink.getLastWriteTime< LEFT_SIDE>()) + L"\n" +
- arrowRight + L" " + formatUtcToLocalTime(symlink.getLastWriteTime<RIGHT_SIDE>());
+ arrowLeft + L' ' + formatUtcToLocalTime(symlink.getLastWriteTime< LEFT_SIDE>()) + L'\n' +
+ arrowRight + L' ' + formatUtcToLocalTime(symlink.getLastWriteTime<RIGHT_SIDE>());
});
return descr + footer;
}
case FILE_DIFFERENT_METADATA:
case FILE_CONFLICT:
- return fsObj.getCatExtraDescription() + footer;
+ return utfTo<std::wstring>(fsObj.getCatExtraDescription()) + footer;
}
assert(false);
return std::wstring();
@@ -440,7 +440,7 @@ std::wstring fff::getSyncOpDescription(SyncOperation op)
std::wstring fff::getSyncOpDescription(const FileSystemObject& fsObj)
{
- const std::wstring footer = L"\n[" + utfTo<std::wstring>(fsObj. getItemNameAny()) + L"]";
+ const std::wstring footer = L"\n[" + utfTo<std::wstring>(fsObj. getItemNameAny()) + L']';
const SyncOperation op = fsObj.getSyncOperation();
switch (op)
@@ -466,8 +466,8 @@ std::wstring fff::getSyncOpDescription(const FileSystemObject& fsObj)
if (getUnicodeNormalForm(itemNameOld) !=
getUnicodeNormalForm(itemNameNew)) //detected change in case
- return getSyncOpDescription(op) + L"\n" +
- fmtPath(itemNameOld) + L" " + arrowRight + L"\n" + //show short name only
+ return getSyncOpDescription(op) + L'\n' +
+ fmtPath(itemNameOld) + L' ' + arrowRight + L'\n' + //show short name only
fmtPath(itemNameNew) /*+ footer -> redundant */;
}
return getSyncOpDescription(op) + footer; //fallback
@@ -492,14 +492,14 @@ std::wstring fff::getSyncOpDescription(const FileSystemObject& fsObj)
const Zstring relPathTo = getRelName(*fileTo, onLeft);
//attention: ::SetWindowText() doesn't handle tab characters correctly in combination with certain file names, so don't use them
- return getSyncOpDescription(op) + L"\n" +
+ return getSyncOpDescription(op) + L'\n' +
(beforeLast(relPathFrom, FILE_NAME_SEPARATOR, IF_MISSING_RETURN_NONE) ==
beforeLast(relPathTo, FILE_NAME_SEPARATOR, IF_MISSING_RETURN_NONE) ?
//detected pure "rename"
- fmtPath(afterLast(relPathFrom, FILE_NAME_SEPARATOR, IF_MISSING_RETURN_ALL)) + L" " + arrowRight + L"\n" + //show short name only
+ fmtPath(afterLast(relPathFrom, FILE_NAME_SEPARATOR, IF_MISSING_RETURN_ALL)) + L' ' + arrowRight + L'\n' + //show short name only
fmtPath(afterLast(relPathTo, FILE_NAME_SEPARATOR, IF_MISSING_RETURN_ALL)) :
//"move" or "move + rename"
- fmtPath(relPathFrom) + L" " + arrowRight + L"\n" +
+ fmtPath(relPathFrom) + L' ' + arrowRight + L'\n' +
fmtPath(relPathTo)) /*+ footer -> redundant */;
}
break;
diff --git a/FreeFileSync/Source/base/file_hierarchy.h b/FreeFileSync/Source/base/file_hierarchy.h
index c717e41f..862f5169 100644
--- a/FreeFileSync/Source/base/file_hierarchy.h
+++ b/FreeFileSync/Source/base/file_hierarchy.h
@@ -425,12 +425,12 @@ public:
//comparison result
CompareFileResult getCategory() const { return cmpResult_; }
- std::wstring getCatExtraDescription() const; //only filled if getCategory() == FILE_CONFLICT or FILE_DIFFERENT_METADATA
+ Zstringc getCatExtraDescription() const; //only filled if getCategory() == FILE_CONFLICT or FILE_DIFFERENT_METADATA
//sync settings
SyncDirection getSyncDir() const { return syncDir_; }
void setSyncDir(SyncDirection newDir);
- void setSyncDirConflict(const std::wstring& description); //set syncDir = SyncDirection::NONE + fill conflict description
+ void setSyncDirConflict(const Zstringc& description); //set syncDir = SyncDirection::NONE + fill conflict description
bool isActive() const { return selectedForSync_; }
void setActive(bool active);
@@ -449,8 +449,8 @@ public:
//for use during init in "CompareProcess" only:
template <CompareFileResult res> void setCategory();
- void setCategoryConflict (const Zstringw& description);
- void setCategoryDiffMetadata(const Zstringw& description);
+ void setCategoryConflict (const Zstringc& description);
+ void setCategoryDiffMetadata(const Zstringc& description);
protected:
FileSystemObject(const Zstring& itemNameL,
@@ -488,15 +488,16 @@ private:
void propagateChangedItemName(const Zstring& itemNameOld); //required after any itemName changes
//categorization
- Zstringw cmpResultDescr_; //only filled if getCategory() == FILE_CONFLICT or FILE_DIFFERENT_METADATA
+ Zstringc cmpResultDescr_; //only filled if getCategory() == FILE_CONFLICT or FILE_DIFFERENT_METADATA
+ //conserve memory (avoid std::string SSO overhead + allow ref-counting!)
CompareFileResult cmpResult_; //although this uses 4 bytes there is currently *no* space wasted in class layout!
bool selectedForSync_ = true;
//Note: we model *four* states with following two variables => "syncDirectionConflict is empty or syncDir == NONE" is a class invariant!!!
SyncDirection syncDir_ = SyncDirection::NONE; //1 byte: optimize memory layout!
- Zstringw syncDirectionConflict_; //non-empty if we have a conflict setting sync-direction
- //get rid of std::wstring small string optimization (consumes 32/48 byte on VS2010 x86/x64!)
+ Zstringc syncDirectionConflict_; //non-empty if we have a conflict setting sync-direction
+ //conserve memory (avoid std::string SSO overhead + allow ref-counting!)
Zstring itemNameL_; //slightly redundant under Linux, but on Windows the "same" file paths can differ in case
Zstring itemNameR_; //use as indicator: an empty name means: not existing on this side!
@@ -723,10 +724,10 @@ CompareDirResult FolderPair::getDirCategory() const
inline
-std::wstring FileSystemObject::getCatExtraDescription() const
+Zstringc FileSystemObject::getCatExtraDescription() const
{
assert(getCategory() == FILE_CONFLICT || getCategory() == FILE_DIFFERENT_METADATA);
- return zen::copyStringTo<std::wstring>(cmpResultDescr_);
+ return cmpResultDescr_;
}
@@ -741,11 +742,11 @@ void FileSystemObject::setSyncDir(SyncDirection newDir)
inline
-void FileSystemObject::setSyncDirConflict(const std::wstring& description)
+void FileSystemObject::setSyncDirConflict(const Zstringc& description)
{
assert(!description.empty());
syncDir_ = SyncDirection::NONE;
- syncDirectionConflict_ = zen::copyStringTo<Zstringw>(description);
+ syncDirectionConflict_ = description;
notifySyncCfgChanged();
}
@@ -755,7 +756,7 @@ inline
std::wstring FileSystemObject::getSyncOpConflict() const
{
assert(getSyncOperation() == SO_UNRESOLVED_CONFLICT);
- return zen::copyStringTo<std::wstring>(syncDirectionConflict_);
+ return zen::utfTo<std::wstring>(syncDirectionConflict_);
}
@@ -855,7 +856,7 @@ template <> void FileSystemObject::setCategory<FILE_LEFT_SIDE_ONLY> () = dele
template <> void FileSystemObject::setCategory<FILE_RIGHT_SIDE_ONLY> () = delete; //
inline
-void FileSystemObject::setCategoryConflict(const Zstringw& description)
+void FileSystemObject::setCategoryConflict(const Zstringc& description)
{
assert(!description.empty());
cmpResult_ = FILE_CONFLICT;
@@ -863,7 +864,7 @@ void FileSystemObject::setCategoryConflict(const Zstringw& description)
}
inline
-void FileSystemObject::setCategoryDiffMetadata(const Zstringw& description)
+void FileSystemObject::setCategoryDiffMetadata(const Zstringc& description)
{
assert(!description.empty());
cmpResult_ = FILE_DIFFERENT_METADATA;
diff --git a/FreeFileSync/Source/base/lock_holder.h b/FreeFileSync/Source/base/lock_holder.h
index ab24e9f4..87c075f9 100644
--- a/FreeFileSync/Source/base/lock_holder.h
+++ b/FreeFileSync/Source/base/lock_holder.h
@@ -5,7 +5,7 @@
#include <zen/zstring.h>
#include <zen/stl_tools.h>
#include "dir_lock.h"
-#include "status_handler.h"
+#include "process_callback.h"
namespace fff
@@ -43,8 +43,8 @@ public:
for (const auto& [folderPath, error] : failedLocks)
{
msg += L"\n\n";
- //msg += fmtPath(folderPath) + L"\n" -> seems redundant
- msg += replaceCpy(error.toString(), L"\n\n", L"\n");
+ //msg += fmtPath(folderPath) + L'\n' -> seems redundant
+ msg += replaceCpy(error.toString(), L"\n\n", L'\n');
}
pcb.reportWarning(msg, warnDirectoryLockFailed); //throw X
diff --git a/FreeFileSync/Source/base/parallel_scan.cpp b/FreeFileSync/Source/base/parallel_scan.cpp
index df2839fb..0bac2483 100644
--- a/FreeFileSync/Source/base/parallel_scan.cpp
+++ b/FreeFileSync/Source/base/parallel_scan.cpp
@@ -167,7 +167,7 @@ private:
filePath = currentFile_;
}
if (parallelOpsTotal >= 2)
- return L"[" + _P("1 thread", "%x threads", parallelOpsTotal) + L"] " + filePath;
+ return L'[' + _P("1 thread", "%x threads", parallelOpsTotal) + L"] " + filePath;
else
return filePath;
}
@@ -202,8 +202,8 @@ struct TraverserConfig
const FilterRef filter;
const SymLinkHandling handleSymlinks;
- std::map<Zstring, std::wstring>& failedDirReads;
- std::map<Zstring, std::wstring>& failedItemReads;
+ std::map<Zstring, Zstringc>& failedDirReads;
+ std::map<Zstring, Zstringc>& failedItemReads;
AsyncCallback& acb;
const int threadIdx;
@@ -387,9 +387,9 @@ DirCallback::HandleError DirCallback::reportError(const std::wstring& msg, size_
{
case ON_ERROR_CONTINUE:
if (itemName.empty())
- cfg_.failedDirReads.emplace(beforeLast(parentRelPathPf_, FILE_NAME_SEPARATOR, IF_MISSING_RETURN_NONE), msg);
+ cfg_.failedDirReads.emplace(beforeLast(parentRelPathPf_, FILE_NAME_SEPARATOR, IF_MISSING_RETURN_NONE), utfTo<Zstringc>(msg));
else
- cfg_.failedItemReads.emplace(parentRelPathPf_ + itemName, msg);
+ cfg_.failedItemReads.emplace(parentRelPathPf_ + itemName, utfTo<Zstringc>(msg));
return ON_ERROR_CONTINUE;
case ON_ERROR_RETRY:
diff --git a/FreeFileSync/Source/base/parallel_scan.h b/FreeFileSync/Source/base/parallel_scan.h
index 9aa4bc82..1852d3fd 100644
--- a/FreeFileSync/Source/base/parallel_scan.h
+++ b/FreeFileSync/Source/base/parallel_scan.h
@@ -44,10 +44,10 @@ struct DirectoryValue
FolderContainer folderCont;
//relative paths (or empty string for root) for directories that could not be read (completely), e.g. access denied, or temporary network drop
- std::map<Zstring, std::wstring> failedFolderReads; //with corresponding error message
+ std::map<Zstring, Zstringc> failedFolderReads; //with corresponding error message
//relative paths (never empty) for failure to read single file/dir/symlink with corresponding error message
- std::map<Zstring, std::wstring> failedItemReads;
+ std::map<Zstring, Zstringc> failedItemReads;
};
diff --git a/FreeFileSync/Source/base/path_filter.h b/FreeFileSync/Source/base/path_filter.h
index f1087722..af7d6dc2 100644
--- a/FreeFileSync/Source/base/path_filter.h
+++ b/FreeFileSync/Source/base/path_filter.h
@@ -215,7 +215,7 @@ FilterRef constructFilter(const Zstring& includePhrase,
{
if (NameFilter::isNull(includePhrase, Zstring()))
{
- auto filterTmp = zen::makeSharedRef<NameFilter>(includePhrase2, excludePhrase + Zstr("\n") + excludePhrase2);
+ auto filterTmp = zen::makeSharedRef<NameFilter>(includePhrase2, excludePhrase + Zstr('\n') + excludePhrase2);
if (filterTmp.ref().isNull())
return zen::makeSharedRef<NullFilter>();
@@ -224,9 +224,9 @@ FilterRef constructFilter(const Zstring& includePhrase,
else
{
if (NameFilter::isNull(includePhrase2, Zstring()))
- return zen::makeSharedRef<NameFilter>(includePhrase, excludePhrase + Zstr("\n") + excludePhrase2);
+ return zen::makeSharedRef<NameFilter>(includePhrase, excludePhrase + Zstr('\n') + excludePhrase2);
else
- return zen::makeSharedRef<CombinedFilter>(NameFilter(includePhrase, excludePhrase + Zstr("\n") + excludePhrase2), NameFilter(includePhrase2, Zstring()));
+ return zen::makeSharedRef<CombinedFilter>(NameFilter(includePhrase, excludePhrase + Zstr('\n') + excludePhrase2), NameFilter(includePhrase2, Zstring()));
}
}
diff --git a/FreeFileSync/Source/base/resolve_path.cpp b/FreeFileSync/Source/base/resolve_path.cpp
index 83e6d226..f2737069 100644
--- a/FreeFileSync/Source/base/resolve_path.cpp
+++ b/FreeFileSync/Source/base/resolve_path.cpp
@@ -88,14 +88,14 @@ Zstring resolveRelativePath(const Zstring& relativePath)
std::optional<Zstring> tryResolveMacro(const Zstring& macro) //macro without %-characters
{
//there exist environment variables named %TIME%, %DATE% so check for our internal macros first!
- if (equalAsciiNoCase(macro, Zstr("time")))
- return formatTime<Zstring>(Zstr("%H%M%S"));
+ if (equalAsciiNoCase(macro, "time"))
+ return formatTime(Zstr("%H%M%S"));
- if (equalAsciiNoCase(macro, Zstr("date")))
- return formatTime<Zstring>(FORMAT_ISO_DATE);
+ if (equalAsciiNoCase(macro, "date"))
+ return formatTime(formatIsoDateTag);
- if (equalAsciiNoCase(macro, Zstr("timestamp")))
- return formatTime<Zstring>(Zstr("%Y-%m-%d %H%M%S")); //e.g. "2012-05-15 131513"
+ if (equalAsciiNoCase(macro, "timestamp"))
+ return formatTime(Zstr("%Y-%m-%d %H%M%S")); //e.g. "2012-05-15 131513"
Zstring timeStr;
auto resolveTimePhrase = [&](const Zchar* phrase, const Zchar* format) -> bool
@@ -103,7 +103,7 @@ std::optional<Zstring> tryResolveMacro(const Zstring& macro) //macro without %-c
if (!equalAsciiNoCase(macro, phrase))
return false;
- timeStr = formatTime<Zstring>(format);
+ timeStr = formatTime(format);
return true;
};
@@ -161,9 +161,9 @@ Zstring expandVolumeName(Zstring pathPhrase) // [volname]:\folder [volnam
//we only expect the [.*] pattern at the beginning => do not touch dir names like "C:\somedir\[stuff]"
trim(pathPhrase, true, false);
- if (startsWith(pathPhrase, Zstr("[")))
+ if (startsWith(pathPhrase, Zstr('[')))
{
- const size_t posEnd = pathPhrase.find(Zstr("]"));
+ const size_t posEnd = pathPhrase.find(Zstr(']'));
if (posEnd != Zstring::npos)
{
Zstring volName = Zstring(pathPhrase.c_str() + 1, posEnd - 1);
diff --git a/FreeFileSync/Source/base/status_handler_impl.h b/FreeFileSync/Source/base/status_handler_impl.h
index be6b6fa5..642b2cb0 100644
--- a/FreeFileSync/Source/base/status_handler_impl.h
+++ b/FreeFileSync/Source/base/status_handler_impl.h
@@ -207,7 +207,7 @@ private:
const ThreadStatus* ts = getThreadStatus(); //call while holding "lockCurrentStatus_" lock!!
return ts ? ts->taskIdx : static_cast<size_t>(-2);
}();
- return totalThreadCount_ > 1 ? L"[" + zen::numberTo<std::wstring>(taskIdx + 1) + L"] " : L"";
+ return totalThreadCount_ > 1 ? L'[' + zen::numberTo<std::wstring>(taskIdx + 1) + L"] " : L"";
}
#endif
@@ -252,7 +252,7 @@ private:
}();
}
if (parallelOpsTotal >= 2)
- return L"[" + _P("1 thread", "%x threads", parallelOpsTotal) + L"] " + statusMsg;
+ return L'[' + _P("1 thread", "%x threads", parallelOpsTotal) + L"] " + statusMsg;
else
return statusMsg;
}
@@ -402,7 +402,7 @@ void massParallelExecute(const std::vector<std::pair<AbstractPath, ParallelWorkI
auto& threadGroup = deviceThreadGroups.emplace(afsDevice, ThreadGroup<std::function<void()>>(
1,
- threadGroupName + " " + utfTo<std::string>(AFS::getDisplayPath(AbstractPath(afsDevice, AfsPath()))))).first->second;
+ threadGroupName + ' ' + utfTo<std::string>(AFS::getDisplayPath(AbstractPath(afsDevice, AfsPath()))))).first->second;
for (const std::pair<AbstractPath, ParallelWorkItem>* item : wl)
threadGroup.run([&acb, statusPrio, &itemPath = item->first, &task = item->second]
diff --git a/FreeFileSync/Source/base/structures.cpp b/FreeFileSync/Source/base/structures.cpp
index cd275ac5..1e6758ac 100644
--- a/FreeFileSync/Source/base/structures.cpp
+++ b/FreeFileSync/Source/base/structures.cpp
@@ -10,69 +10,14 @@
#include <ctime>
#include <zen/i18n.h>
#include <zen/time.h>
-#include "path_filter.h"
+//#include "path_filter.h"
#include "../afs/concrete.h"
using namespace zen;
using namespace fff;
-std::vector<unsigned int> fff::fromTimeShiftPhrase(const std::wstring& timeShiftPhrase)
-{
- std::wstring tmp = replaceCpy(timeShiftPhrase, L';', L','); //harmonize , ; and ' '
- replace(tmp, L' ', L','); //
- replace(tmp, L'-', L""); //there is no negative shift => treat as positive!
-
- std::set<unsigned int> minutes;
- for (const std::wstring& part : split(tmp, L',', SplitType::SKIP_EMPTY))
- {
- if (contains(part, L':'))
- minutes.insert(stringTo<unsigned int>(beforeFirst(part, L':', IF_MISSING_RETURN_NONE)) * 60 +
- stringTo<unsigned int>(afterFirst (part, L':', IF_MISSING_RETURN_NONE)));
- else
- minutes.insert(stringTo<unsigned int>(part) * 60);
- }
- minutes.erase(0);
-
- return { minutes.begin(), minutes.end() };
-}
-
-
-std::wstring fff::toTimeShiftPhrase(const std::vector<unsigned int>& ignoreTimeShiftMinutes)
-{
- std::wstring phrase;
- for (auto it = ignoreTimeShiftMinutes.begin(); it != ignoreTimeShiftMinutes.end(); ++it)
- {
- if (it != ignoreTimeShiftMinutes.begin())
- phrase += L", ";
-
- phrase += numberTo<std::wstring>(*it / 60);
- if (*it % 60 != 0)
- phrase += L':' + printNumber<std::wstring>(L"%02d", static_cast<int>(*it % 60));
- }
- return phrase;
-}
-
-
-std::wstring fff::getVariantName(CompareVariant var)
-{
- switch (var)
- {
- case CompareVariant::timeSize:
- return _("File time and size");
- case CompareVariant::content:
- return _("File content");
- case CompareVariant::size:
- return _("File size");
- }
- assert(false);
- return _("Error");
-}
-
-
-namespace
-{
-std::wstring getVariantNameImpl(DirectionConfig::Variant var, const wchar_t* arrowLeft, const wchar_t* arrowRight, const wchar_t* angleRight)
+std::wstring fff::getVariantNameImpl(DirectionConfig::Variant var, const wchar_t* arrowLeft, const wchar_t* arrowRight, const wchar_t* angleRight)
{
switch (var)
{
@@ -88,28 +33,6 @@ std::wstring getVariantNameImpl(DirectionConfig::Variant var, const wchar_t* arr
assert(false);
return _("Error");
}
-}
-
-
-std::wstring fff::getVariantName(DirectionConfig::Variant var)
-{
-#if 1
- const wchar_t arrowLeft [] = L"<\u2013 ";
- const wchar_t arrowRight[] = L" \u2013>";
- const wchar_t angleRight[] = L" >";
-#else
- //const wchar_t arrowLeft [] = L"\u2190 "; //unicode arrows -> too small
- //const wchar_t arrowRight[] = L" \u2192"; //
- //const wchar_t arrowLeft [] = L"\u25C4\u2013 "; //black triangle pointer
- //const wchar_t arrowRight[] = L" \u2013\u25BA"; //
- const wchar_t arrowLeft [] = L"\uFF1C\u2013 "; //fullwidth less-than + en dash
- const wchar_t arrowRight[] = L" \u2013\uFF1E"; //en dash + fullwidth greater-than
- const wchar_t angleRight[] = L" \uFF1E";
- //=> drawback: - not drawn correctly before Vista
- // - RTL: the full width less-than is not mirrored automatically (=> Windows Unicode bug!)
-#endif
- return getVariantNameImpl(var, arrowLeft, arrowRight, angleRight);
-}
//use in sync log files where users expect ANSI: https://freefilesync.org/forum/viewtopic.php?t=4647
@@ -125,7 +48,7 @@ DirectionSet fff::extractDirections(const DirectionConfig& cfg)
switch (cfg.var)
{
case DirectionConfig::TWO_WAY:
- throw std::logic_error("there are no predefined directions for automatic mode! " + std::string(__FILE__) + ":" + numberTo<std::string>(__LINE__));
+ throw std::logic_error("there are no predefined directions for automatic mode! " + std::string(__FILE__) + ':' + numberTo<std::string>(__LINE__));
case DirectionConfig::MIRROR:
output.exLeftSideOnly = SyncDirection::RIGHT;
@@ -185,48 +108,6 @@ DirectionSet fff::getTwoWayUpdateSet()
}
-std::wstring fff::getCompVariantName(const MainConfiguration& mainCfg)
-{
- const CompareVariant firstVariant = mainCfg.firstPair.localCmpCfg ?
- mainCfg.firstPair.localCmpCfg->compareVar :
- mainCfg.cmpCfg.compareVar; //fallback to main sync cfg
-
- //test if there's a deviating variant within the additional folder pairs
- for (const LocalPairConfig& lpc : mainCfg.additionalPairs)
- {
- const CompareVariant thisVariant = lpc.localCmpCfg ?
- lpc.localCmpCfg->compareVar :
- mainCfg.cmpCfg.compareVar; //fallback to main sync cfg
- if (thisVariant != firstVariant)
- return _("Multiple...");
- }
-
- //seems to be all in sync...
- return getVariantName(firstVariant);
-}
-
-
-std::wstring fff::getSyncVariantName(const MainConfiguration& mainCfg)
-{
- const DirectionConfig::Variant firstVariant = mainCfg.firstPair.localSyncCfg ?
- mainCfg.firstPair.localSyncCfg->directionCfg.var :
- mainCfg.syncCfg.directionCfg.var; //fallback to main sync cfg
-
- //test if there's a deviating variant within the additional folder pairs
- for (const LocalPairConfig& lpc : mainCfg.additionalPairs)
- {
- const DirectionConfig::Variant thisVariant = lpc.localSyncCfg ?
- lpc.localSyncCfg->directionCfg.var :
- mainCfg.syncCfg.directionCfg.var;
- if (thisVariant != firstVariant)
- return _("Multiple...");
- }
-
- //seems to be all in sync...
- return getVariantName(firstVariant);
-}
-
-
size_t fff::getDeviceParallelOps(const std::map<AfsDevice, size_t>& deviceParallelOps, const AfsDevice& afsDevice)
{
auto it = deviceParallelOps.find(afsDevice);
@@ -398,205 +279,3 @@ void fff::resolveUnits(size_t timeSpan, UnitTime unitTimeSpan,
sizeMinBy = resolve(sizeMin, unitSizeMin, 0U);
sizeMaxBy = resolve(sizeMax, unitSizeMax, std::numeric_limits<uint64_t>::max());
}
-
-
-namespace
-{
-FilterConfig mergeFilterConfig(const FilterConfig& global, const FilterConfig& local)
-{
- FilterConfig out = local;
-
- //hard filter
- if (NameFilter::isNull(local.includeFilter, Zstring())) //fancy way of checking for "*" include
- out.includeFilter = global.includeFilter;
- //else : if both global and local include filters are set, only local filter is preserved
-
- out.excludeFilter = trimCpy(trimCpy(global.excludeFilter) + Zstr("\n\n") + trimCpy(local.excludeFilter));
-
- //soft filter
- time_t loctimeFrom = 0;
- uint64_t locSizeMinBy = 0;
- uint64_t locSizeMaxBy = 0;
- 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
- time_t glotimeFrom = 0;
- uint64_t gloSizeMinBy = 0;
- uint64_t gloSizeMaxBy = 0;
- 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;
- }
- if (gloSizeMinBy > locSizeMinBy)
- {
- out.sizeMin = global.sizeMin;
- out.unitSizeMin = global.unitSizeMin;
- }
- if (gloSizeMaxBy < locSizeMaxBy)
- {
- out.sizeMax = global.sizeMax;
- out.unitSizeMax = global.unitSizeMax;
- }
- return out;
-}
-
-
-inline
-bool effectivelyEmpty(const LocalPairConfig& lpc)
-{
- return trimCpy(lpc.folderPathPhraseLeft ).empty() &&
- trimCpy(lpc.folderPathPhraseRight).empty();
-}
-}
-
-
-MainConfiguration fff::merge(const std::vector<MainConfiguration>& mainCfgs)
-{
- assert(!mainCfgs.empty());
- if (mainCfgs.empty())
- return MainConfiguration();
-
- if (mainCfgs.size() == 1) //mergeConfigFilesImpl relies on this!
- return mainCfgs[0]; //
-
- //merge folder pair config
- std::vector<LocalPairConfig> mergedCfgs;
- for (const MainConfiguration& mainCfg : mainCfgs)
- {
- std::vector<LocalPairConfig> tmpCfgs;
-
- //skip empty folder pairs
- if (!effectivelyEmpty(mainCfg.firstPair))
- tmpCfgs.push_back(mainCfg.firstPair);
-
- for (const LocalPairConfig& lpc : mainCfg.additionalPairs)
- if (!effectivelyEmpty(lpc))
- tmpCfgs.push_back(lpc);
-
- //move all configuration down to item level
- for (LocalPairConfig& lpc : tmpCfgs)
- {
- if (!lpc.localCmpCfg)
- lpc.localCmpCfg = mainCfg.cmpCfg;
-
- if (!lpc.localSyncCfg)
- lpc.localSyncCfg = mainCfg.syncCfg;
-
- lpc.localFilter = mergeFilterConfig(mainCfg.globalFilter, lpc.localFilter);
- }
- append(mergedCfgs, tmpCfgs);
- }
-
- if (mergedCfgs.empty())
- return MainConfiguration();
-
- //optimization: remove redundant configuration
-
- //########################################################################################################################
- //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 (const LocalPairConfig& lpc : mergedCfgs)
- {
- //a rather inefficient algorithm, but it does not require a less-than operator:
- {
- const CompConfig& cmpCfg = *lpc.localCmpCfg;
-
- auto it = std::find_if(cmpCfgStat.begin(), cmpCfgStat.end(),
- [&](const std::pair<CompConfig, int>& entry) { return effectivelyEqual(entry.first, cmpCfg); });
- if (it == cmpCfgStat.end())
- cmpCfgStat.emplace_back(cmpCfg, 1);
- else
- ++(it->second);
- }
- {
- const SyncConfig& syncCfg = *lpc.localSyncCfg;
-
- auto it = std::find_if(syncCfgStat.begin(), syncCfgStat.end(),
- [&](const std::pair<SyncConfig, int>& entry) { return effectivelyEqual(entry.first, syncCfg); });
- if (it == syncCfgStat.end())
- syncCfgStat.emplace_back(syncCfg, 1);
- else
- ++(it->second);
- }
- }
-
- //set most-used comparison and synchronization settings 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 allFiltersEqual = std::all_of(mergedCfgs.begin(), mergedCfgs.end(), [&](const LocalPairConfig& lpc) { return lpc.localFilter == mergedCfgs[0].localFilter; });
- if (allFiltersEqual)
- globalFilter = mergedCfgs[0].localFilter;
-
- //strip redundancy...
- for (LocalPairConfig& lpc : mergedCfgs)
- {
- //if local config matches output global config we don't need local one
- if (lpc.localCmpCfg &&
- effectivelyEqual(*lpc.localCmpCfg, cmpCfgHead))
- lpc.localCmpCfg = {};
-
- if (lpc.localSyncCfg &&
- effectivelyEqual(*lpc.localSyncCfg, syncCfgHead))
- lpc.localSyncCfg = {};
-
- if (allFiltersEqual) //use global filter in this case
- lpc.localFilter = FilterConfig();
- }
-
- std::map<AfsDevice, size_t> mergedParallelOps;
- for (const MainConfiguration& mainCfg : mainCfgs)
- for (const auto& [rootPath, parallelOps] : mainCfg.deviceParallelOps)
- mergedParallelOps[rootPath] = std::max(mergedParallelOps[rootPath], parallelOps);
-
- //final assembly
- MainConfiguration cfgOut;
- cfgOut.cmpCfg = cmpCfgHead;
- cfgOut.syncCfg = syncCfgHead;
- cfgOut.globalFilter = globalFilter;
- cfgOut.firstPair = mergedCfgs[0];
- cfgOut.additionalPairs.assign(mergedCfgs.begin() + 1, mergedCfgs.end());
- cfgOut.deviceParallelOps = mergedParallelOps;
-
- cfgOut.ignoreErrors = std::all_of(mainCfgs.begin(), mainCfgs.end(), [](const MainConfiguration& mainCfg) { return mainCfg.ignoreErrors; });
-
- cfgOut.automaticRetryCount = std::max_element(mainCfgs.begin(), mainCfgs.end(),
- [](const MainConfiguration& lhs, const MainConfiguration& rhs) { return lhs.automaticRetryCount < rhs.automaticRetryCount; })->automaticRetryCount;
-
- cfgOut.automaticRetryDelay = std::max_element(mainCfgs.begin(), mainCfgs.end(),
- [](const MainConfiguration& lhs, const MainConfiguration& rhs) { return lhs.automaticRetryDelay < rhs.automaticRetryDelay; })->automaticRetryDelay;
-
- for (const MainConfiguration& mainCfg : mainCfgs)
- if (!mainCfg.altLogFolderPathPhrase.empty())
- {
- cfgOut.altLogFolderPathPhrase = mainCfg.altLogFolderPathPhrase;
- break;
- }
-
- //cfgOut.postSyncCommand = -> better leave at default ... !?
- //cfgOut.postSyncCondition = ->
- //cfgOut.emailNotifyAddress = -> better leave at default ... !?
- //cfgOut.emailNotifyCondition = ->
- return cfgOut;
-}
diff --git a/FreeFileSync/Source/base/structures.h b/FreeFileSync/Source/base/structures.h
index 5ee9708a..11e98948 100644
--- a/FreeFileSync/Source/base/structures.h
+++ b/FreeFileSync/Source/base/structures.h
@@ -25,8 +25,6 @@ enum class CompareVariant
size
};
-std::wstring getVariantName(CompareVariant var);
-
enum class SymLinkHandling
{
@@ -150,7 +148,7 @@ bool detectMovedFilesEnabled (const DirectionConfig& cfg);
DirectionSet extractDirections(const DirectionConfig& cfg); //get sync directions: DON'T call for DirectionConfig::TWO_WAY!
-std::wstring getVariantName (DirectionConfig::Variant var);
+std::wstring getVariantNameImpl(DirectionConfig::Variant var, const wchar_t* arrowLeft, const wchar_t* arrowRight, const wchar_t* angleRight);
std::wstring getVariantNameForLog(DirectionConfig::Variant var);
inline
@@ -191,10 +189,6 @@ inline bool operator!=(const CompConfig& lhs, const CompConfig& rhs) { return !(
inline
bool effectivelyEqual(const CompConfig& lhs, const CompConfig& rhs) { return lhs == rhs; } //no change in behavior
-//convert "ignoreTimeShiftMinutes" into compact format:
-std::vector<unsigned int> fromTimeShiftPhrase(const std::wstring& timeShiftPhrase);
-std::wstring toTimeShiftPhrase (const std::vector<unsigned int>& ignoreTimeShiftMinutes);
-
enum class DeletionPolicy
{
@@ -423,12 +417,10 @@ struct MainConfiguration
Zstring altLogFolderPathPhrase; //fill to use different log file folder (other than the default %appdata%\FreeFileSync\Logs)
- Zstring emailNotifyAddress; //optional
+ std::string emailNotifyAddress; //optional
ResultsNotification emailNotifyCondition = ResultsNotification::always;
};
-std::wstring getCompVariantName(const MainConfiguration& mainCfg);
-std::wstring getSyncVariantName(const MainConfiguration& mainCfg);
size_t getDeviceParallelOps(const std::map<AfsDevice, size_t>& deviceParallelOps, const AfsDevice& afsDevice);
void setDeviceParallelOps( std::map<AfsDevice, size_t>& deviceParallelOps, const AfsDevice& afsDevice, size_t parallelOps);
@@ -455,8 +447,37 @@ bool operator==(const MainConfiguration& lhs, const MainConfiguration& rhs)
}
-//facilitate drag & drop config merge:
-MainConfiguration merge(const std::vector<MainConfiguration>& mainCfgs);
+struct WarningDialogs
+{
+ bool warnFolderNotExisting = true;
+ bool warnFoldersDifferInCase = true;
+ bool warnDependentFolderPair = true;
+ bool warnDependentBaseFolders = true;
+ bool warnSignificantDifference = true;
+ bool warnNotEnoughDiskSpace = true;
+ bool warnUnresolvedConflicts = true;
+ bool warnModificationTimeError = true;
+ bool warnRecyclerMissing = true;
+ bool warnInputFieldEmpty = true;
+ bool warnDirectoryLockFailed = true;
+ bool warnVersioningFolderPartOfSync = true;
+};
+inline bool operator==(const WarningDialogs& lhs, const WarningDialogs& rhs)
+{
+ return lhs.warnFolderNotExisting == rhs.warnFolderNotExisting &&
+ lhs.warnFoldersDifferInCase == rhs.warnFoldersDifferInCase &&
+ lhs.warnDependentFolderPair == rhs.warnDependentFolderPair &&
+ lhs.warnDependentBaseFolders == rhs.warnDependentBaseFolders &&
+ lhs.warnSignificantDifference == rhs.warnSignificantDifference &&
+ lhs.warnNotEnoughDiskSpace == rhs.warnNotEnoughDiskSpace &&
+ lhs.warnUnresolvedConflicts == rhs.warnUnresolvedConflicts &&
+ lhs.warnModificationTimeError == rhs.warnModificationTimeError &&
+ lhs.warnRecyclerMissing == rhs.warnRecyclerMissing &&
+ lhs.warnInputFieldEmpty == rhs.warnInputFieldEmpty &&
+ lhs.warnDirectoryLockFailed == rhs.warnDirectoryLockFailed &&
+ lhs.warnVersioningFolderPartOfSync == rhs.warnVersioningFolderPartOfSync;
+}
+inline bool operator!=(const WarningDialogs& lhs, const WarningDialogs& rhs) { return !(lhs == rhs); }
}
#endif //STRUCTURES_H_8210478915019450901745
diff --git a/FreeFileSync/Source/base/synchronization.cpp b/FreeFileSync/Source/base/synchronization.cpp
index 097e3cf0..38ad1771 100644
--- a/FreeFileSync/Source/base/synchronization.cpp
+++ b/FreeFileSync/Source/base/synchronization.cpp
@@ -124,7 +124,9 @@ void SyncStatistics::processFile(const FilePair& file)
break;
case SO_UNRESOLVED_CONFLICT:
- conflictMsgs_.push_back({ file.getRelativePathAny(), file.getSyncOpConflict() });
+ ++conflictCount_;
+ if (conflictsPreview_.size() < SYNC_STATS_CONFLICTS_MAX)
+ conflictsPreview_.push_back({ file.getRelativePathAny(), file.getSyncOpConflict() });
break;
case SO_COPY_METADATA_TO_LEFT:
@@ -178,7 +180,9 @@ void SyncStatistics::processLink(const SymlinkPair& link)
break;
case SO_UNRESOLVED_CONFLICT:
- conflictMsgs_.push_back({ link.getRelativePathAny(), link.getSyncOpConflict() });
+ ++conflictCount_;
+ if (conflictsPreview_.size() < SYNC_STATS_CONFLICTS_MAX)
+ conflictsPreview_.push_back({ link.getRelativePathAny(), link.getSyncOpConflict() });
break;
case SO_MOVE_LEFT_FROM:
@@ -218,7 +222,9 @@ void SyncStatistics::processFolder(const FolderPair& folder)
break;
case SO_UNRESOLVED_CONFLICT:
- conflictMsgs_.push_back({ folder.getRelativePathAny(), folder.getSyncOpConflict() });
+ ++conflictCount_;
+ if (conflictsPreview_.size() < SYNC_STATS_CONFLICTS_MAX)
+ conflictsPreview_.push_back({ folder.getRelativePathAny(), folder.getSyncOpConflict() });
break;
case SO_OVERWRITE_LEFT:
@@ -464,8 +470,8 @@ void verifyFiles(const AbstractPath& sourcePath, const AbstractPath& targetPath,
if (!filesHaveSameContent(sourcePath, targetPath, notifyUnbufferedIO)) //throw FileError, X
throw FileError(replaceCpy(replaceCpy(_("%x and %y have different content."),
- L"%x", L"\n" + fmtPath(AFS::getDisplayPath(sourcePath))),
- L"%y", L"\n" + fmtPath(AFS::getDisplayPath(targetPath))));
+ L"%x", L'\n' + fmtPath(AFS::getDisplayPath(sourcePath))),
+ L"%y", L'\n' + fmtPath(AFS::getDisplayPath(targetPath))));
}
catch (const FileError& e) //add some context to error message
{
@@ -747,7 +753,7 @@ void DeletionHandler::removeDirWithCallback(const AbstractPath& folderPath,//thr
//callbacks run *outside* singleThread_ lock! => fine
auto notifyMove = [&statReporter](const std::wstring& statusText, const std::wstring& displayPathFrom, const std::wstring& displayPathTo)
{
- statReporter.updateStatus(replaceCpy(replaceCpy(statusText, L"%x", L"\n" + fmtPath(displayPathFrom)), L"%y", L"\n" + fmtPath(displayPathTo))); //throw ThreadInterruption
+ statReporter.updateStatus(replaceCpy(replaceCpy(statusText, L"%x", L'\n' + fmtPath(displayPathFrom)), L"%y", L'\n' + fmtPath(displayPathTo))); //throw ThreadInterruption
statReporter.reportDelta(1, 0); //it would be more correct to report *after* work was done!
warn_static("=> indeed; fix!?")
};
@@ -984,7 +990,7 @@ private:
void reportInfo(const std::wstring& rawText, const std::wstring& displayPath) { acb_.reportInfo(replaceCpy(rawText, L"%x", fmtPath(displayPath))); }
void reportInfo(const std::wstring& rawText, const std::wstring& displayPath1, const std::wstring& displayPath2) //throw ThreadInterruption
{
- acb_.reportInfo(replaceCpy(replaceCpy(rawText, L"%x", L"\n" + fmtPath(displayPath1)), L"%y", L"\n" + fmtPath(displayPath2))); //throw ThreadInterruption
+ acb_.reportInfo(replaceCpy(replaceCpy(rawText, L"%x", L'\n' + fmtPath(displayPath1)), L"%y", L'\n' + fmtPath(displayPath2))); //throw ThreadInterruption
}
//target existing after onDeleteTargetFile(): undefined behavior! (fail/overwrite/auto-rename)
@@ -1523,8 +1529,8 @@ void FolderPairSyncer::synchronizeFileInt(FilePair& file, SyncOperation syncOp)
catch (const FileError& e2) //more relevant than previous exception (which could be "item not found")
{
throw FileError(replaceCpy(replaceCpy(_("Cannot copy file %x to %y."),
- L"%x", L"\n" + fmtPath(AFS::getDisplayPath(file.getAbstractPath<sideSrc>()))),
- L"%y", L"\n" + fmtPath(AFS::getDisplayPath(targetPath))), replaceCpy(e2.toString(), L"\n\n", L"\n"));
+ L"%x", L'\n' + fmtPath(AFS::getDisplayPath(file.getAbstractPath<sideSrc>()))),
+ L"%y", L'\n' + fmtPath(AFS::getDisplayPath(targetPath))), replaceCpy(e2.toString(), L"\n\n", L'\n'));
}
//do not check on type (symlink, file, folder) -> if there is a type change, FFS should not be quiet about it!
if (!sourceExists)
@@ -1745,8 +1751,8 @@ void FolderPairSyncer::synchronizeLinkInt(SymlinkPair& symlink, SyncOperation sy
catch (const FileError& e2) //more relevant than previous exception (which could be "item not found")
{
throw FileError(replaceCpy(replaceCpy(_("Cannot copy symbolic link %x to %y."),
- L"%x", L"\n" + fmtPath(AFS::getDisplayPath(symlink.getAbstractPath<sideSrc>()))),
- L"%y", L"\n" + fmtPath(AFS::getDisplayPath(targetPath))), replaceCpy(e2.toString(), L"\n\n", L"\n"));
+ L"%x", L'\n' + fmtPath(AFS::getDisplayPath(symlink.getAbstractPath<sideSrc>()))),
+ L"%y", L'\n' + fmtPath(AFS::getDisplayPath(targetPath))), replaceCpy(e2.toString(), L"\n\n", L'\n'));
}
//do not check on type (symlink, file, folder) -> if there is a type change, FFS should not be quiet about it!
if (!sourceExists)
@@ -2137,7 +2143,7 @@ void fff::synchronize(const std::chrono::system_clock::time_point& syncStartTime
//PERF_START;
if (syncConfig.size() != folderCmp.size())
- throw std::logic_error("Contract violation! " + std::string(__FILE__) + ":" + numberTo<std::string>(__LINE__));
+ throw std::logic_error("Contract violation! " + std::string(__FILE__) + ':' + numberTo<std::string>(__LINE__));
//aggregate basic information
std::vector<SyncStatistics> folderPairStats;
@@ -2189,7 +2195,7 @@ void fff::synchronize(const std::chrono::system_clock::time_point& syncStartTime
std::vector<FolderPairJobType> jobType(folderCmp.size(), FolderPairJobType::PROCESS); //folder pairs may be skipped after fatal errors were found
- std::map<const BaseFolderPair*, std::vector<SyncStatistics::ConflictInfo>> checkUnresolvedConflicts;
+ std::map<const BaseFolderPair*, std::pair<int, std::vector<SyncStatistics::ConflictInfo>>> checkUnresolvedConflicts;
std::vector<std::tuple<AbstractPath, const PathFilter*, bool /*write access*/>> checkReadWriteBaseFolders;
@@ -2216,7 +2222,7 @@ void fff::synchronize(const std::chrono::system_clock::time_point& syncStartTime
const AbstractPath versioningFolderPath = createAbstractPath(folderPairCfg.versioningFolderPhrase);
//aggregate *all* conflicts:
- checkUnresolvedConflicts[&baseFolder] = folderPairStat.getConflicts();
+ checkUnresolvedConflicts[&baseFolder] = std::pair(folderPairStat.conflictCount(), folderPairStat.getConflictsPreview());
//consider *all* paths that might be used during versioning limit at some time
if (folderPairCfg.handleDeletion == DeletionPolicy::versioning &&
@@ -2375,20 +2381,27 @@ void fff::synchronize(const std::chrono::system_clock::time_point& syncStartTime
//-----------------------------------------------------------------
//check if unresolved conflicts exist
- if (std::any_of(checkUnresolvedConflicts.begin(), checkUnresolvedConflicts.end(), [](const auto& item) { return !item.second.empty(); }))
+ if (std::any_of(checkUnresolvedConflicts.begin(), checkUnresolvedConflicts.end(), [](const auto& item) { return item.second.first > 0; }))
{
std::wstring msg = _("The following items have unresolved conflicts and will not be synchronized:");
for (const auto& [baseFolder, conflicts] : checkUnresolvedConflicts)
- if (!conflicts.empty())
+ {
+ const auto& [conflictCount, conflictPreview] = conflicts;
+ if (conflictCount > 0)
{
- msg += L"\n\n" + _("Folder pair:") + L" " +
+ msg += L"\n\n" + _("Folder pair:") + L' ' +
AFS::getDisplayPath(baseFolder->getAbstractPath< LEFT_SIDE>()) + L" <-> " +
AFS::getDisplayPath(baseFolder->getAbstractPath<RIGHT_SIDE>());
- for (const SyncStatistics::ConflictInfo& item : conflicts) //show *all* conflicts in warning message
- msg += L"\n" + utfTo<std::wstring>(item.relPath) + L": " + item.msg;
+ for (const SyncStatistics::ConflictInfo& item : conflictPreview)
+ msg += L'\n' + utfTo<std::wstring>(item.relPath) + L": " + item.msg;
+
+ if (makeUnsigned(conflictCount) > conflictPreview.size())
+ msg += L"\n [...] " + replaceCpy(_P("Showing %y of 1 row", "Showing %y of %x rows", conflictCount), //%x used as plural form placeholder!
+ L"%y", formatNumber(conflictPreview.size()));
}
+ }
callback.reportWarning(msg, warnings.warnUnresolvedConflicts);
}
@@ -2400,7 +2413,7 @@ void fff::synchronize(const std::chrono::system_clock::time_point& syncStartTime
for (const auto& [folderPathL, folderPathR] : checkSignificantDiffPairs)
msg += L"\n\n" +
- AFS::getDisplayPath(folderPathL) + L" <-> " + L"\n" +
+ AFS::getDisplayPath(folderPathL) + L" <-> " + L'\n' +
AFS::getDisplayPath(folderPathR);
callback.reportWarning(msg, warnings.warnSignificantDifference);
@@ -2412,9 +2425,9 @@ void fff::synchronize(const std::chrono::system_clock::time_point& syncStartTime
std::wstring msg = _("Not enough free disk space available in:");
for (const auto& [folderPath, space] : checkDiskSpaceMissing)
- msg += L"\n\n" + AFS::getDisplayPath(folderPath) + L"\n" +
- _("Required:") + L" " + formatFilesizeShort(space.first) + L"\n" +
- _("Available:") + L" " + formatFilesizeShort(space.second);
+ msg += L"\n\n" + AFS::getDisplayPath(folderPath) + L'\n' +
+ _("Required:") + L' ' + formatFilesizeShort(space.first) + L'\n' +
+ _("Available:") + L' ' + formatFilesizeShort(space.second);
callback.reportWarning(msg, warnings.warnNotEnoughDiskSpace);
}
@@ -2424,10 +2437,10 @@ void fff::synchronize(const std::chrono::system_clock::time_point& syncStartTime
std::wstring msg;
for (const auto& [folderPath, supported] : recyclerSupported)
if (!supported)
- msg += L"\n" + AFS::getDisplayPath(folderPath);
+ msg += L'\n' + AFS::getDisplayPath(folderPath);
if (!msg.empty())
- callback.reportWarning(_("The recycle bin is not supported by the following folders. Deleted or overwritten files will not be able to be restored:") + L"\n" + msg,
+ callback.reportWarning(_("The recycle bin is not supported by the following folders. Deleted or overwritten files will not be able to be restored:") + L'\n' + msg,
warnings.warnRecyclerMissing);
}
@@ -2449,11 +2462,11 @@ void fff::synchronize(const std::chrono::system_clock::time_point& syncStartTime
if (!dependentFolders.empty())
{
- std::wstring msg = _("Some files will be synchronized as part of multiple base folders.") + L"\n" +
- _("To avoid conflicts, set up exclude filters so that each updated file is included by only one base folder.") + L"\n";
+ std::wstring msg = _("Some files will be synchronized as part of multiple base folders.") + L'\n' +
+ _("To avoid conflicts, set up exclude filters so that each updated file is included by only one base folder.") + L'\n';
for (const AbstractPath& baseFolderPath : dependentFolders)
- msg += L"\n" + AFS::getDisplayPath(baseFolderPath);
+ msg += L'\n' + AFS::getDisplayPath(baseFolderPath);
callback.reportWarning(msg, warnings.warnDependentBaseFolders);
}
@@ -2470,9 +2483,9 @@ void fff::synchronize(const std::chrono::system_clock::time_point& syncStartTime
if (std::optional<PathDependency> pd = getPathDependency(versioningFolderPath, NullFilter(), folderPath, *filter))
{
std::wstring line = L"\n\n" + _("Versioning folder:") + L" \t" + AFS::getDisplayPath(versioningFolderPath) +
- L"\n" + _("Base folder:") + L" \t" + AFS::getDisplayPath(folderPath);
+ L'\n' + _("Base folder:") + L" \t" + AFS::getDisplayPath(folderPath);
if (pd->basePathParent == folderPath && !pd->relPath.empty())
- line += L"\n" + _("Exclude:") + L" \t" + utfTo<std::wstring>(FILE_NAME_SEPARATOR + pd->relPath + FILE_NAME_SEPARATOR);
+ line += L'\n' + _("Exclude:") + L" \t" + utfTo<std::wstring>(FILE_NAME_SEPARATOR + pd->relPath + FILE_NAME_SEPARATOR);
uniqueMsgs[folderPath] = line;
}
@@ -2480,7 +2493,7 @@ void fff::synchronize(const std::chrono::system_clock::time_point& syncStartTime
msg += perFolderMsg;
}
if (!msg.empty())
- callback.reportWarning(_("The versioning folder is contained in a base folder.") + L"\n" +
+ callback.reportWarning(_("The versioning folder is contained in a base folder.") + L'\n' +
_("The folder should be excluded from synchronization via filter.") + msg, warnings.warnVersioningFolderPartOfSync);
}
@@ -2497,9 +2510,9 @@ void fff::synchronize(const std::chrono::system_clock::time_point& syncStartTime
for (const auto& [key, aliases] : ciPathAliases)
if (aliases.size() > 1)
{
- msg += L"\n";
+ msg += L'\n';
for (const AbstractPath& aliasPath : aliases)
- msg += L"\n" + AFS::getDisplayPath(aliasPath);
+ msg += L'\n' + AFS::getDisplayPath(aliasPath);
}
callback.reportWarning(msg, warnings.warnFoldersDifferInCase); //throw X
}
@@ -2521,7 +2534,7 @@ void fff::synchronize(const std::chrono::system_clock::time_point& syncStartTime
std::wstring msg;
for (const FileError& e : errorsModTime)
{
- std::wstring singleMsg = replaceCpy(e.toString(), L"\n\n", L"\n");
+ std::wstring singleMsg = replaceCpy(e.toString(), L"\n\n", L'\n');
msg += singleMsg + L"\n\n";
}
msg.resize(msg.size() - 2);
@@ -2571,8 +2584,8 @@ void fff::synchronize(const std::chrono::system_clock::time_point& syncStartTime
//------------------------------------------------------------------------------------------
if (folderCmp.size() > 1)
- callback.reportInfo(_("Synchronizing folder pair:") + L" " + getVariantNameForLog(folderPairCfg.syncVariant) + L"\n" + //throw X
- L" " + AFS::getDisplayPath(baseFolder.getAbstractPath< LEFT_SIDE>()) + L"\n" +
+ callback.reportInfo(_("Synchronizing folder pair:") + L' ' + getVariantNameForLog(folderPairCfg.syncVariant) + L'\n' + //throw X
+ L" " + AFS::getDisplayPath(baseFolder.getAbstractPath< LEFT_SIDE>()) + L'\n' +
L" " + AFS::getDisplayPath(baseFolder.getAbstractPath<RIGHT_SIDE>()));
//------------------------------------------------------------------------------------------
diff --git a/FreeFileSync/Source/base/synchronization.h b/FreeFileSync/Source/base/synchronization.h
index c0c5df35..275918b4 100644
--- a/FreeFileSync/Source/base/synchronization.h
+++ b/FreeFileSync/Source/base/synchronization.h
@@ -8,7 +8,8 @@
#define SYNCHRONIZATION_H_8913470815943295
#include <chrono>
-#include "config.h"
+//#include "config.h"
+#include "structures.h"
#include "file_hierarchy.h"
#include "process_callback.h"
@@ -38,8 +39,6 @@ public:
template <SelectedSide side>
bool expectPhysicalDeletion() const { return SelectParam<side>::ref(physicalDeleteLeft_, physicalDeleteRight_); }
- int conflictCount() const { return static_cast<int>(conflictMsgs_.size()); }
-
int64_t getBytesToProcess() const { return bytesToProcess_; }
size_t rowCount () const { return rowsTotal_; }
@@ -48,7 +47,8 @@ public:
Zstring relPath;
std::wstring msg;
};
- const std::vector<ConflictInfo>& getConflicts() const { return conflictMsgs_; }
+ const std::vector<ConflictInfo>& getConflictsPreview() const { return conflictsPreview_; }
+ int conflictCount() const { return conflictCount_; }
private:
void recurse(const ContainerObject& hierObj);
@@ -65,9 +65,14 @@ private:
int deleteRight_ = 0;
bool physicalDeleteLeft_ = false; //at least 1 item will be deleted; considers most "update" cases which also delete items
bool physicalDeleteRight_ = false; //
- std::vector<ConflictInfo> conflictMsgs_; //conflict texts to display as a warning message
+
int64_t bytesToProcess_ = 0;
size_t rowsTotal_ = 0;
+
+ int conflictCount_ = 0;
+ std::vector<ConflictInfo> conflictsPreview_; //conflict texts to display as a warning message
+ static const size_t SYNC_STATS_CONFLICTS_MAX = 25; //=> consider memory consumption, log file size, email size!
+ //limit conflict count! e.g. there may be hundred thousands of "same date but a different size"
};
diff --git a/FreeFileSync/Source/base/versioning.cpp b/FreeFileSync/Source/base/versioning.cpp
index c2b95f8d..bf596d11 100644
--- a/FreeFileSync/Source/base/versioning.cpp
+++ b/FreeFileSync/Source/base/versioning.cpp
@@ -422,14 +422,14 @@ void fff::applyVersioningLimit(const std::set<VersioningLimitFolder>& folderLimi
if (!status.failedChecks.empty())
{
- std::wstring msg = _("Cannot find the following folders:") + L"\n";
+ std::wstring msg = _("Cannot find the following folders:") + L'\n';
for (const auto& [folderPath, error] : status.failedChecks)
- msg += L"\n" + AFS::getDisplayPath(folderPath);
+ msg += L'\n' + AFS::getDisplayPath(folderPath);
msg += L"\n___________________________________________";
for (const auto& [folderPath, error] : status.failedChecks)
- msg += L"\n\n" + replaceCpy(error.toString(), L"\n\n", L"\n");
+ msg += L"\n\n" + replaceCpy(error.toString(), L"\n\n", L'\n');
throw FileError(msg);
}
@@ -453,7 +453,7 @@ void fff::applyVersioningLimit(const std::set<VersioningLimitFolder>& folderLimi
return AFS::TraverserCallback::ON_ERROR_CONTINUE;
};
- const std::wstring textScanning = _("Searching for old file versions:") + L" ";
+ const std::wstring textScanning = _("Searching for old file versions:") + L' ';
auto onStatusUpdate = [&](const std::wstring& statusLine, int itemsTotal)
{
@@ -538,7 +538,7 @@ void fff::applyVersioningLimit(const std::set<VersioningLimitFolder>& folderLimi
//--------- remove excess file versions ---------
Protected<std::map<AbstractPath, size_t>&> folderItemCountShared(folderItemCount);
- const std::wstring txtRemoving = _("Removing old file versions:") + L" ";
+ const std::wstring txtRemoving = _("Removing old file versions:") + L' ';
const std::wstring txtDeletingFolder = _("Deleting folder %x");
std::function<void(const AbstractPath& folderPath, AsyncCallback& acb)> deleteEmptyFolderTask;
diff --git a/FreeFileSync/Source/base/versioning.h b/FreeFileSync/Source/base/versioning.h
index 9c0a9b43..d5edb345 100644
--- a/FreeFileSync/Source/base/versioning.h
+++ b/FreeFileSync/Source/base/versioning.h
@@ -39,12 +39,12 @@ public:
versioningFolderPath_(versioningFolderPath),
versioningStyle_(versioningStyle),
syncStartTime_(syncStartTime),
- timeStamp_(zen::formatTime<Zstring>(Zstr("%Y-%m-%d %H%M%S"), zen::getLocalTime(syncStartTime))) //e.g. "2012-05-15 131513"
+ timeStamp_(zen::formatTime(Zstr("%Y-%m-%d %H%M%S"), zen::getLocalTime(syncStartTime))) //e.g. "2012-05-15 131513"
{
using namespace zen;
if (AbstractFileSystem::isNullPath(versioningFolderPath_))
- throw std::logic_error("Contract violation! " + std::string(__FILE__) + ":" + numberTo<std::string>(__LINE__));
+ throw std::logic_error("Contract violation! " + std::string(__FILE__) + ':' + numberTo<std::string>(__LINE__));
if (timeStamp_.size() != 17) //formatTime() returns empty string on error; unexpected length: e.g. problem in year 10,000!
throw FileError(_("Unable to create time stamp for versioning:") + L" \"" + utfTo<std::wstring>(timeStamp_) + L'"');
diff --git a/FreeFileSync/Source/base_tools.cpp b/FreeFileSync/Source/base_tools.cpp
new file mode 100644
index 00000000..3a7dabbd
--- /dev/null
+++ b/FreeFileSync/Source/base_tools.cpp
@@ -0,0 +1,357 @@
+// *****************************************************************************
+// * This file is part of the FreeFileSync project. It is distributed under *
+// * GNU General Public License: https://www.gnu.org/licenses/gpl-3.0 *
+// * Copyright (C) Zenju (zenju AT freefilesync DOT org) - All Rights Reserved *
+// *****************************************************************************
+
+#include "base_tools.h"
+#include <wx/app.h>
+#include "base/path_filter.h"
+
+using namespace zen;
+using namespace fff;
+
+
+std::wstring fff::getVariantName(CompareVariant var)
+{
+ switch (var)
+ {
+ case CompareVariant::timeSize:
+ return _("File time and size");
+ case CompareVariant::content:
+ return _("File content");
+ case CompareVariant::size:
+ return _("File size");
+ }
+ assert(false);
+ return _("Error");
+}
+
+
+std::wstring fff::getVariantName(DirectionConfig::Variant var)
+{
+ const wchar_t* arrowLeft = L"\u25C4 "; //black triangle pointer
+ const wchar_t* arrowRight = L" \u25BA"; //
+ const wchar_t* angleRight = L" \uFF1E"; //fullwidth greater-than
+ //const wchar_t arrowLeft [] = L"\u2190 "; //unicode arrows -> too small
+ //const wchar_t arrowRight[] = L" \u2192"; //
+
+ if (wxTheApp->GetLayoutDirection() == wxLayout_RightToLeft)
+ {
+ arrowLeft = L"\u25BA "; //not mirrored automatically: Windows/Linux Unicode bug!?
+ arrowRight = L" \u25C4"; //
+ }
+ return getVariantNameImpl(var, arrowLeft, arrowRight, angleRight);
+}
+
+
+std::wstring fff::getCompVariantName(const MainConfiguration& mainCfg)
+{
+ const CompareVariant firstVariant = mainCfg.firstPair.localCmpCfg ?
+ mainCfg.firstPair.localCmpCfg->compareVar :
+ mainCfg.cmpCfg.compareVar; //fallback to main sync cfg
+
+ //test if there's a deviating variant within the additional folder pairs
+ for (const LocalPairConfig& lpc : mainCfg.additionalPairs)
+ {
+ const CompareVariant thisVariant = lpc.localCmpCfg ?
+ lpc.localCmpCfg->compareVar :
+ mainCfg.cmpCfg.compareVar; //fallback to main sync cfg
+ if (thisVariant != firstVariant)
+ return _("Multiple...");
+ }
+
+ //seems to be all in sync...
+ return getVariantName(firstVariant);
+}
+
+
+std::wstring fff::getSyncVariantName(const MainConfiguration& mainCfg)
+{
+ const DirectionConfig::Variant firstVariant = mainCfg.firstPair.localSyncCfg ?
+ mainCfg.firstPair.localSyncCfg->directionCfg.var :
+ mainCfg.syncCfg.directionCfg.var; //fallback to main sync cfg
+
+ //test if there's a deviating variant within the additional folder pairs
+ for (const LocalPairConfig& lpc : mainCfg.additionalPairs)
+ {
+ const DirectionConfig::Variant thisVariant = lpc.localSyncCfg ?
+ lpc.localSyncCfg->directionCfg.var :
+ mainCfg.syncCfg.directionCfg.var;
+ if (thisVariant != firstVariant)
+ return _("Multiple...");
+ }
+
+ //seems to be all in sync...
+ return getVariantName(firstVariant);
+}
+
+
+std::vector<unsigned int> fff::fromTimeShiftPhrase(const std::wstring& timeShiftPhrase)
+{
+ std::wstring tmp = replaceCpy(timeShiftPhrase, L';', L','); //harmonize , ; and ' '
+ replace(tmp, L' ', L','); //
+ replace(tmp, L'-', L""); //there is no negative shift => treat as positive!
+
+ std::set<unsigned int> minutes;
+ for (const std::wstring& part : split(tmp, L',', SplitType::SKIP_EMPTY))
+ {
+ if (contains(part, L':'))
+ minutes.insert(stringTo<unsigned int>(beforeFirst(part, L':', IF_MISSING_RETURN_NONE)) * 60 +
+ stringTo<unsigned int>(afterFirst (part, L':', IF_MISSING_RETURN_NONE)));
+ else
+ minutes.insert(stringTo<unsigned int>(part) * 60);
+ }
+ minutes.erase(0);
+
+ return { minutes.begin(), minutes.end() };
+}
+
+
+std::wstring fff::toTimeShiftPhrase(const std::vector<unsigned int>& ignoreTimeShiftMinutes)
+{
+ std::wstring phrase;
+ for (auto it = ignoreTimeShiftMinutes.begin(); it != ignoreTimeShiftMinutes.end(); ++it)
+ {
+ if (it != ignoreTimeShiftMinutes.begin())
+ phrase += L", ";
+
+ phrase += numberTo<std::wstring>(*it / 60);
+ if (*it % 60 != 0)
+ phrase += L':' + printNumber<std::wstring>(L"%02d", static_cast<int>(*it % 60));
+ }
+ return phrase;
+}
+
+
+void fff::logNonDefaultSettings(const XmlGlobalSettings& activeSettings, PhaseCallback& callback)
+{
+ const XmlGlobalSettings defaultSettings;
+ std::wstring changedSettingsMsg;
+
+ if (activeSettings.failSafeFileCopy != defaultSettings.failSafeFileCopy)
+ changedSettingsMsg += L"\n " + _("Fail-safe file copy") + L" - " + (activeSettings.failSafeFileCopy ? _("Enabled") : _("Disabled"));
+
+ if (activeSettings.copyLockedFiles != defaultSettings.copyLockedFiles)
+ changedSettingsMsg += L"\n " + _("Copy locked files") + L" - " + (activeSettings.copyLockedFiles ? _("Enabled") : _("Disabled"));
+
+ if (activeSettings.copyFilePermissions != defaultSettings.copyFilePermissions)
+ changedSettingsMsg += L"\n " + _("Copy file access permissions") + L" - " + (activeSettings.copyFilePermissions ? _("Enabled") : _("Disabled"));
+
+ if (activeSettings.fileTimeTolerance != defaultSettings.fileTimeTolerance)
+ changedSettingsMsg += L"\n " + _("File time tolerance") + L" - " + numberTo<std::wstring>(activeSettings.fileTimeTolerance);
+
+ if (activeSettings.runWithBackgroundPriority != defaultSettings.runWithBackgroundPriority)
+ changedSettingsMsg += L"\n " + _("Run with background priority") + L" - " + (activeSettings.runWithBackgroundPriority ? _("Enabled") : _("Disabled"));
+
+ if (activeSettings.createLockFile != defaultSettings.createLockFile)
+ changedSettingsMsg += L"\n " + _("Lock directories during sync") + L" - " + (activeSettings.createLockFile ? _("Enabled") : _("Disabled"));
+
+ if (activeSettings.verifyFileCopy != defaultSettings.verifyFileCopy)
+ changedSettingsMsg += L"\n " + _("Verify copied files") + L" - " + (activeSettings.verifyFileCopy ? _("Enabled") : _("Disabled"));
+
+ if (!changedSettingsMsg.empty())
+ callback.reportInfo(_("Using non-default global settings:") + changedSettingsMsg); //throw X
+}
+
+
+namespace
+{
+FilterConfig mergeFilterConfig(const FilterConfig& global, const FilterConfig& local)
+{
+ FilterConfig out = local;
+
+ //hard filter
+ if (NameFilter::isNull(local.includeFilter, Zstring())) //fancy way of checking for "*" include
+ out.includeFilter = global.includeFilter;
+ //else : if both global and local include filters are set, only local filter is preserved
+
+ out.excludeFilter = trimCpy(trimCpy(global.excludeFilter) + Zstr("\n\n") + trimCpy(local.excludeFilter));
+
+ //soft filter
+ time_t loctimeFrom = 0;
+ uint64_t locSizeMinBy = 0;
+ uint64_t locSizeMaxBy = 0;
+ 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
+ time_t glotimeFrom = 0;
+ uint64_t gloSizeMinBy = 0;
+ uint64_t gloSizeMaxBy = 0;
+ 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;
+ }
+ if (gloSizeMinBy > locSizeMinBy)
+ {
+ out.sizeMin = global.sizeMin;
+ out.unitSizeMin = global.unitSizeMin;
+ }
+ if (gloSizeMaxBy < locSizeMaxBy)
+ {
+ out.sizeMax = global.sizeMax;
+ out.unitSizeMax = global.unitSizeMax;
+ }
+ return out;
+}
+
+
+inline
+bool effectivelyEmpty(const LocalPairConfig& lpc)
+{
+ return trimCpy(lpc.folderPathPhraseLeft ).empty() &&
+ trimCpy(lpc.folderPathPhraseRight).empty();
+}
+}
+
+
+MainConfiguration fff::merge(const std::vector<MainConfiguration>& mainCfgs)
+{
+ assert(!mainCfgs.empty());
+ if (mainCfgs.empty())
+ return MainConfiguration();
+
+ if (mainCfgs.size() == 1) //mergeConfigFilesImpl relies on this!
+ return mainCfgs[0]; //
+
+ //merge folder pair config
+ std::vector<LocalPairConfig> mergedCfgs;
+ for (const MainConfiguration& mainCfg : mainCfgs)
+ {
+ std::vector<LocalPairConfig> tmpCfgs;
+
+ //skip empty folder pairs
+ if (!effectivelyEmpty(mainCfg.firstPair))
+ tmpCfgs.push_back(mainCfg.firstPair);
+
+ for (const LocalPairConfig& lpc : mainCfg.additionalPairs)
+ if (!effectivelyEmpty(lpc))
+ tmpCfgs.push_back(lpc);
+
+ //move all configuration down to item level
+ for (LocalPairConfig& lpc : tmpCfgs)
+ {
+ if (!lpc.localCmpCfg)
+ lpc.localCmpCfg = mainCfg.cmpCfg;
+
+ if (!lpc.localSyncCfg)
+ lpc.localSyncCfg = mainCfg.syncCfg;
+
+ lpc.localFilter = mergeFilterConfig(mainCfg.globalFilter, lpc.localFilter);
+ }
+ append(mergedCfgs, tmpCfgs);
+ }
+
+ if (mergedCfgs.empty())
+ return MainConfiguration();
+
+ //optimization: remove redundant configuration
+
+ //########################################################################################################################
+ //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 (const LocalPairConfig& lpc : mergedCfgs)
+ {
+ //a rather inefficient algorithm, but it does not require a less-than operator:
+ {
+ const CompConfig& cmpCfg = *lpc.localCmpCfg;
+
+ auto it = std::find_if(cmpCfgStat.begin(), cmpCfgStat.end(),
+ [&](const std::pair<CompConfig, int>& entry) { return effectivelyEqual(entry.first, cmpCfg); });
+ if (it == cmpCfgStat.end())
+ cmpCfgStat.emplace_back(cmpCfg, 1);
+ else
+ ++(it->second);
+ }
+ {
+ const SyncConfig& syncCfg = *lpc.localSyncCfg;
+
+ auto it = std::find_if(syncCfgStat.begin(), syncCfgStat.end(),
+ [&](const std::pair<SyncConfig, int>& entry) { return effectivelyEqual(entry.first, syncCfg); });
+ if (it == syncCfgStat.end())
+ syncCfgStat.emplace_back(syncCfg, 1);
+ else
+ ++(it->second);
+ }
+ }
+
+ //set most-used comparison and synchronization settings 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 allFiltersEqual = std::all_of(mergedCfgs.begin(), mergedCfgs.end(), [&](const LocalPairConfig& lpc) { return lpc.localFilter == mergedCfgs[0].localFilter; });
+ if (allFiltersEqual)
+ globalFilter = mergedCfgs[0].localFilter;
+
+ //strip redundancy...
+ for (LocalPairConfig& lpc : mergedCfgs)
+ {
+ //if local config matches output global config we don't need local one
+ if (lpc.localCmpCfg &&
+ effectivelyEqual(*lpc.localCmpCfg, cmpCfgHead))
+ lpc.localCmpCfg = {};
+
+ if (lpc.localSyncCfg &&
+ effectivelyEqual(*lpc.localSyncCfg, syncCfgHead))
+ lpc.localSyncCfg = {};
+
+ if (allFiltersEqual) //use global filter in this case
+ lpc.localFilter = FilterConfig();
+ }
+
+ std::map<AfsDevice, size_t> mergedParallelOps;
+ for (const MainConfiguration& mainCfg : mainCfgs)
+ for (const auto& [rootPath, parallelOps] : mainCfg.deviceParallelOps)
+ mergedParallelOps[rootPath] = std::max(mergedParallelOps[rootPath], parallelOps);
+
+ //final assembly
+ MainConfiguration cfgOut;
+ cfgOut.cmpCfg = cmpCfgHead;
+ cfgOut.syncCfg = syncCfgHead;
+ cfgOut.globalFilter = globalFilter;
+ cfgOut.firstPair = mergedCfgs[0];
+ cfgOut.additionalPairs.assign(mergedCfgs.begin() + 1, mergedCfgs.end());
+ cfgOut.deviceParallelOps = mergedParallelOps;
+
+ cfgOut.ignoreErrors = std::all_of(mainCfgs.begin(), mainCfgs.end(), [](const MainConfiguration& mainCfg) { return mainCfg.ignoreErrors; });
+
+ cfgOut.automaticRetryCount = std::max_element(mainCfgs.begin(), mainCfgs.end(),
+ [](const MainConfiguration& lhs, const MainConfiguration& rhs) { return lhs.automaticRetryCount < rhs.automaticRetryCount; })->automaticRetryCount;
+
+ cfgOut.automaticRetryDelay = std::max_element(mainCfgs.begin(), mainCfgs.end(),
+ [](const MainConfiguration& lhs, const MainConfiguration& rhs) { return lhs.automaticRetryDelay < rhs.automaticRetryDelay; })->automaticRetryDelay;
+
+ for (const MainConfiguration& mainCfg : mainCfgs)
+ if (!mainCfg.altLogFolderPathPhrase.empty())
+ {
+ cfgOut.altLogFolderPathPhrase = mainCfg.altLogFolderPathPhrase;
+ break;
+ }
+
+ //cfgOut.postSyncCommand = -> better leave at default ... !?
+ //cfgOut.postSyncCondition = ->
+ //cfgOut.emailNotifyAddress = -> better leave at default ... !?
+ //cfgOut.emailNotifyCondition = ->
+ return cfgOut;
+}
diff --git a/FreeFileSync/Source/base_tools.h b/FreeFileSync/Source/base_tools.h
new file mode 100644
index 00000000..e5ad9a2f
--- /dev/null
+++ b/FreeFileSync/Source/base_tools.h
@@ -0,0 +1,33 @@
+// *****************************************************************************
+// * This file is part of the FreeFileSync project. It is distributed under *
+// * GNU General Public License: https://www.gnu.org/licenses/gpl-3.0 *
+// * Copyright (C) Zenju (zenju AT freefilesync DOT org) - All Rights Reserved *
+// *****************************************************************************
+
+#ifndef STRUCTURE_TOOLS_H_7823097420397434
+#define STRUCTURE_TOOLS_H_7823097420397434
+
+#include "base/structures.h"
+#include "base/process_callback.h"
+#include "config.h"
+
+
+namespace fff
+{
+std::wstring getVariantName(CompareVariant var);
+std::wstring getVariantName(DirectionConfig::Variant var);
+std::wstring getCompVariantName(const MainConfiguration& mainCfg);
+std::wstring getSyncVariantName(const MainConfiguration& mainCfg);
+
+//convert "ignoreTimeShiftMinutes" into compact format:
+std::vector<unsigned int> fromTimeShiftPhrase(const std::wstring& timeShiftPhrase);
+std::wstring toTimeShiftPhrase (const std::vector<unsigned int>& ignoreTimeShiftMinutes);
+
+//inform about (important) non-default global settings related to comparison and synchronization
+void logNonDefaultSettings(const XmlGlobalSettings& currentSettings, PhaseCallback& callback);
+
+//facilitate drag & drop config merge:
+MainConfiguration merge(const std::vector<MainConfiguration>& mainCfgs);
+}
+
+#endif //STRUCTURE_TOOLS_H_7823097420397434
diff --git a/FreeFileSync/Source/base/config.cpp b/FreeFileSync/Source/config.cpp
index 0a170bbb..120ad466 100644
--- a/FreeFileSync/Source/base/config.cpp
+++ b/FreeFileSync/Source/config.cpp
@@ -11,7 +11,7 @@
#include <zen/time.h>
#include <wx/intl.h>
#include "ffs_paths.h"
-//#include "../afs/concrete.h"
+#include "base_tools.h"
using namespace zen;
@@ -662,6 +662,35 @@ bool readText(const std::string& input, UnitTime& value)
return true;
}
+
+template <> inline
+void writeText(const LogFileFormat& value, std::string& output)
+{
+ switch (value)
+ {
+ case LogFileFormat::html:
+ output = "HTML";
+ break;
+ case LogFileFormat::text:
+ output = "Text";
+ break;
+ }
+}
+
+template <> inline
+bool readText(const std::string& input, LogFileFormat& value)
+{
+ const std::string tmp = trimCpy(input);
+ if (tmp == "HTML")
+ value = LogFileFormat::html;
+ else if (tmp == "Text")
+ value = LogFileFormat::text;
+ else
+ return false;
+ return true;
+}
+
+
template <> inline
void writeText(const VersioningStyle& value, std::string& output)
{
@@ -1092,8 +1121,8 @@ void readConfig(const XmlIn& in, SyncConfig& syncCfg, std::map<AfsDevice, size_t
if (syncCfg.versioningStyle == VersioningStyle::replace)
{
- if (endsWithAsciiNoCase(syncCfg.versioningFolderPhrase, Zstr("/%timestamp%")) ||
- endsWithAsciiNoCase(syncCfg.versioningFolderPhrase, Zstr("\\%timestamp%")))
+ if (endsWithAsciiNoCase(syncCfg.versioningFolderPhrase, "/%timestamp%") ||
+ endsWithAsciiNoCase(syncCfg.versioningFolderPhrase, "\\%timestamp%"))
{
syncCfg.versioningFolderPhrase.resize(syncCfg.versioningFolderPhrase.size() - strLength(Zstr("/%timestamp%")));
syncCfg.versioningStyle = VersioningStyle::timestampFolder;
@@ -1173,8 +1202,8 @@ void readConfig(const XmlIn& in, LocalPairConfig& lpc, std::map<AfsDevice, size_
{
auto getParallelOps = [&](const Zstring& folderPathPhrase, size_t& parallelOps)
{
- if (startsWithAsciiNoCase(folderPathPhrase, Zstr("sftp:")) ||
- startsWithAsciiNoCase(folderPathPhrase, Zstr( "ftp:")))
+ if (startsWithAsciiNoCase(folderPathPhrase, "sftp:") ||
+ startsWithAsciiNoCase(folderPathPhrase, "ftp:"))
{
for (const Zstring& optPhrase : split(folderPathPhrase, Zstr("|"), SplitType::SKIP_EMPTY))
if (startsWith(optPhrase, Zstr("con=")))
@@ -1481,6 +1510,7 @@ void readConfig(const XmlIn& in, XmlGlobalSettings& cfg, int formatVer)
inGeneral["LockDirectoriesDuringSync"].attribute("Enabled", cfg.createLockFile);
inGeneral["VerifyCopiedFiles" ].attribute("Enabled", cfg.verifyFileCopy);
inGeneral["LogFiles" ].attribute("MaxAge", cfg.logfilesMaxAgeDays);
+ inGeneral["LogFiles" ].attribute("Format", cfg.logFormat);
inGeneral["NotificationSound" ].attribute("CompareFinished", cfg.soundFileCompareFinished);
inGeneral["NotificationSound" ].attribute("SyncFinished", cfg.soundFileSyncFinished);
inGeneral["ProgressDialog" ].attribute("AutoClose", cfg.autoCloseProgressDialog);
@@ -2205,6 +2235,7 @@ void writeConfig(const XmlGlobalSettings& cfg, XmlOut& out)
outGeneral["LockDirectoriesDuringSync"].attribute("Enabled", cfg.createLockFile);
outGeneral["VerifyCopiedFiles" ].attribute("Enabled", cfg.verifyFileCopy);
outGeneral["LogFiles" ].attribute("MaxAge", cfg.logfilesMaxAgeDays);
+ outGeneral["LogFiles" ].attribute("Format", cfg.logFormat);
outGeneral["NotificationSound" ].attribute("CompareFinished", substituteFfsResourcePath(cfg.soundFileCompareFinished));
outGeneral["NotificationSound" ].attribute("SyncFinished", substituteFfsResourcePath(cfg.soundFileSyncFinished));
outGeneral["ProgressDialog" ].attribute("AutoClose", cfg.autoCloseProgressDialog);
diff --git a/FreeFileSync/Source/base/config.h b/FreeFileSync/Source/config.h
index dcafb207..e76d4770 100644
--- a/FreeFileSync/Source/base/config.h
+++ b/FreeFileSync/Source/config.h
@@ -9,10 +9,11 @@
#include <wx/gdicmn.h>
#include "localization.h"
-#include "structures.h"
-#include "../ui/file_grid_attr.h"
-#include "../ui/tree_grid_attr.h" //RTS: avoid tree grid's "file_hierarchy.h" dependency!
-#include "../ui/cfg_grid.h"
+#include "base/structures.h"
+#include "ui/file_grid_attr.h"
+#include "ui/tree_grid_attr.h" //RTS: avoid tree grid's "file_hierarchy.h" dependency!
+#include "ui/cfg_grid.h"
+#include "log_file.h"
namespace fff
@@ -95,40 +96,6 @@ inline bool operator==(const ConfirmationDialogs& lhs, const ConfirmationDialogs
inline bool operator!=(const ConfirmationDialogs& lhs, const ConfirmationDialogs& rhs) { return !(lhs == rhs); }
-struct WarningDialogs
-{
- bool warnFolderNotExisting = true;
- bool warnFoldersDifferInCase = true;
- bool warnDependentFolderPair = true;
- bool warnDependentBaseFolders = true;
- bool warnSignificantDifference = true;
- bool warnNotEnoughDiskSpace = true;
- bool warnUnresolvedConflicts = true;
- bool warnModificationTimeError = true;
- bool warnRecyclerMissing = true;
- bool warnInputFieldEmpty = true;
- bool warnDirectoryLockFailed = true;
- bool warnVersioningFolderPartOfSync = true;
-};
-inline bool operator==(const WarningDialogs& lhs, const WarningDialogs& rhs)
-{
- return lhs.warnFolderNotExisting == rhs.warnFolderNotExisting &&
- lhs.warnFoldersDifferInCase == rhs.warnFoldersDifferInCase &&
- lhs.warnDependentFolderPair == rhs.warnDependentFolderPair &&
- lhs.warnDependentBaseFolders == rhs.warnDependentBaseFolders &&
- lhs.warnSignificantDifference == rhs.warnSignificantDifference &&
- lhs.warnNotEnoughDiskSpace == rhs.warnNotEnoughDiskSpace &&
- lhs.warnUnresolvedConflicts == rhs.warnUnresolvedConflicts &&
- lhs.warnModificationTimeError == rhs.warnModificationTimeError &&
- lhs.warnRecyclerMissing == rhs.warnRecyclerMissing &&
- lhs.warnInputFieldEmpty == rhs.warnInputFieldEmpty &&
- lhs.warnDirectoryLockFailed == rhs.warnDirectoryLockFailed &&
- lhs.warnVersioningFolderPartOfSync == rhs.warnVersioningFolderPartOfSync;
-}
-inline bool operator!=(const WarningDialogs& lhs, const WarningDialogs& rhs) { return !(lhs == rhs); }
-
-
-
enum class FileIconSize
{
SMALL,
@@ -179,6 +146,7 @@ struct XmlGlobalSettings
bool createLockFile = true;
bool verifyFileCopy = false;
int logfilesMaxAgeDays = 30; //<= 0 := no limit; for log files under %AppData%\FreeFileSync\Logs
+ LogFileFormat logFormat = LogFileFormat::html;
Zstring soundFileCompareFinished;
Zstring soundFileSyncFinished;
@@ -238,8 +206,8 @@ struct XmlGlobalSettings
wxString guiPerspectiveLast; //used by wxAuiManager
} mainDlg;
- Zstring defaultExclusionFilter = Zstr("/.Trash-*/") Zstr("\n")
- Zstr("/.recycle/");
+ Zstring defaultExclusionFilter = "/.Trash-*/" "\n"
+ "/.recycle/";
size_t folderHistoryMax = 20;
std::vector<Zstring> versioningFolderHistory;
diff --git a/FreeFileSync/Source/base/fatal_error.h b/FreeFileSync/Source/fatal_error.h
index a27e423b..84ceb6dc 100644
--- a/FreeFileSync/Source/base/fatal_error.h
+++ b/FreeFileSync/Source/fatal_error.h
@@ -33,7 +33,7 @@ void logFatalError(const std::string& msg) //noexcept
using namespace zen;
assert(false); //this is stuff we like to debug
- const std::string logEntry = "[" + formatTime<std::string>(FORMAT_DATE) + " " + formatTime<std::string>(FORMAT_TIME) + "] " + msg;
+ const std::string logEntry = '[' + utfTo<std::string>(formatTime(formatDateTag) + Zstr(' ') + formatTime(formatTimeTag)) + "] " + msg;
try
{
saveBinContainer(getConfigDirPathPf() + Zstr("LastError.log"), logEntry, nullptr /*notifyUnbufferedIO*/); //throw FileError
diff --git a/FreeFileSync/Source/base/ffs_paths.cpp b/FreeFileSync/Source/ffs_paths.cpp
index 843e702e..843e702e 100644
--- a/FreeFileSync/Source/base/ffs_paths.cpp
+++ b/FreeFileSync/Source/ffs_paths.cpp
diff --git a/FreeFileSync/Source/base/ffs_paths.h b/FreeFileSync/Source/ffs_paths.h
index bf103e28..bf103e28 100644
--- a/FreeFileSync/Source/base/ffs_paths.h
+++ b/FreeFileSync/Source/ffs_paths.h
diff --git a/FreeFileSync/Source/base/help_provider.h b/FreeFileSync/Source/help_provider.h
index d9a1b3fc..d9a1b3fc 100644
--- a/FreeFileSync/Source/base/help_provider.h
+++ b/FreeFileSync/Source/help_provider.h
diff --git a/FreeFileSync/Source/base/icon_buffer.cpp b/FreeFileSync/Source/icon_buffer.cpp
index b10027a6..4b032bd3 100644
--- a/FreeFileSync/Source/base/icon_buffer.cpp
+++ b/FreeFileSync/Source/icon_buffer.cpp
@@ -11,7 +11,7 @@
#include <zen/scope_guard.h>
#include <wx+/image_resources.h>
#include <wx+/dc.h>
-#include "icon_loader.h"
+#include "base/icon_loader.h"
using namespace zen;
diff --git a/FreeFileSync/Source/base/icon_buffer.h b/FreeFileSync/Source/icon_buffer.h
index d6dd504f..b5ce9eae 100644
--- a/FreeFileSync/Source/base/icon_buffer.h
+++ b/FreeFileSync/Source/icon_buffer.h
@@ -11,7 +11,7 @@
#include <memory>
#include <zen/zstring.h>
#include <wx/bitmap.h>
-#include "../afs/abstract.h"
+#include "afs/abstract.h"
namespace fff
diff --git a/FreeFileSync/Source/base/localization.cpp b/FreeFileSync/Source/localization.cpp
index ef1ee778..ef1ee778 100644
--- a/FreeFileSync/Source/base/localization.cpp
+++ b/FreeFileSync/Source/localization.cpp
diff --git a/FreeFileSync/Source/base/localization.h b/FreeFileSync/Source/localization.h
index e635ac1e..e635ac1e 100644
--- a/FreeFileSync/Source/base/localization.h
+++ b/FreeFileSync/Source/localization.h
diff --git a/FreeFileSync/Source/base/log_file.cpp b/FreeFileSync/Source/log_file.cpp
index ac866e9a..b7032137 100644
--- a/FreeFileSync/Source/base/log_file.cpp
+++ b/FreeFileSync/Source/log_file.cpp
@@ -10,7 +10,7 @@
#include <zen/system.h>
#include <wx/datetime.h>
#include "ffs_paths.h"
-#include "../afs/concrete.h"
+#include "afs/concrete.h"
using namespace zen;
using namespace fff;
@@ -35,21 +35,20 @@ std::string generateLogHeaderTxt(const ProcessSummary& s, const ErrorLog& log, i
headerLine += " ";
const TimeComp tc = getLocalTime(std::chrono::system_clock::to_time_t(s.startTime)); //returns empty string on failure
- headerLine += formatTime<std::string>(FORMAT_DATE, tc) + " [" + formatTime<std::string>(FORMAT_TIME, tc) + ']';
+ headerLine += utfTo<std::string>(formatTime(formatDateTag, tc) + Zstr(" [") + formatTime(formatTimeTag, tc) + Zstr(']'));
//assemble summary box
std::vector<std::string> summary;
summary.emplace_back();
- summary.push_back(tabSpace + utfTo<std::string>(getResultsStatusLabel(s.resultStatus)));
+ summary.push_back(tabSpace + utfTo<std::string>(getSyncResultLabel(s.resultStatus)));
summary.emplace_back();
- const int errorCount = log.getItemCount(MSG_TYPE_ERROR | MSG_TYPE_FATAL_ERROR);
- const int warningCount = log.getItemCount(MSG_TYPE_WARNING);
+ const ErrorLog::Stats logCount = log.getStats();
- if (errorCount > 0) summary.push_back(tabSpace + utfTo<std::string>(_("Errors:") + L" " + formatNumber(errorCount)));
- if (warningCount > 0) summary.push_back(tabSpace + utfTo<std::string>(_("Warnings:") + L" " + formatNumber(warningCount)));
+ if (logCount.error + logCount.fatal > 0) summary.push_back(tabSpace + utfTo<std::string>(_("Errors:") + L' ' + formatNumber(logCount.error + logCount.fatal)));
+ if (logCount.warning > 0) summary.push_back(tabSpace + utfTo<std::string>(_("Warnings:") + L' ' + formatNumber(logCount.warning)));
- summary.push_back(tabSpace + utfTo<std::string>(_("Items processed:") + L" " + formatNumber(s.statsProcessed.items) + //show always, even if 0!
+ summary.push_back(tabSpace + utfTo<std::string>(_("Items processed:") + L' ' + formatNumber(s.statsProcessed.items) + //show always, even if 0!
L" (" + formatFilesizeShort(s.statsProcessed.bytes) + L')'));
if ((s.statsTotal.items < 0 && s.statsTotal.bytes < 0) || //no total items/bytes: e.g. for pure folder comparison
@@ -57,11 +56,11 @@ std::string generateLogHeaderTxt(const ProcessSummary& s, const ErrorLog& log, i
;
else
summary.push_back(tabSpace + utfTo<std::string>(_("Items remaining:") +
- L" " + formatNumber (s.statsTotal.items - s.statsProcessed.items) +
+ L' ' + formatNumber (s.statsTotal.items - s.statsProcessed.items) +
L" (" + formatFilesizeShort(s.statsTotal.bytes - s.statsProcessed.bytes) + L')'));
const int64_t totalTimeSec = std::chrono::duration_cast<std::chrono::seconds>(s.totalTime).count();
- summary.push_back(tabSpace + utfTo<std::string>(_("Total time:")) + " " + utfTo<std::string>(wxTimeSpan::Seconds(totalTimeSec).Format()));
+ summary.push_back(tabSpace + utfTo<std::string>(_("Total time:")) + ' ' + utfTo<std::string>(wxTimeSpan::Seconds(totalTimeSec).Format()));
size_t sepLineLen = 0; //calculate max width (considering Unicode!)
for (const std::string& str : summary) sepLineLen = std::max(sepLineLen, unicodeLength(str));
@@ -75,20 +74,21 @@ std::string generateLogHeaderTxt(const ProcessSummary& s, const ErrorLog& log, i
output += '|' + std::string(sepLineLen, '_') + "\n\n";
//------------ warnings/errors preview ----------------
- const int logFailTotal = errorCount + warningCount;
+ const int logFailTotal = logCount.warning + logCount.error + logCount.fatal;
if (logFailTotal > 0)
{
output += '\n' + utfTo<std::string>(_("Errors and warnings:")) + '\n';
output += std::string(SEPARATION_LINE_LEN, '_') + '\n';
int previewCount = 0;
- for (const LogEntry& entry : log)
- if (entry.type & (MSG_TYPE_WARNING | MSG_TYPE_ERROR | MSG_TYPE_FATAL_ERROR))
- {
- output += utfTo<std::string>(formatMessage(entry));
- if (++previewCount >= logFailsPreviewMax)
- break;
- }
+ if (logFailsPreviewMax > 0)
+ for (const LogEntry& entry : log)
+ if (entry.type & (MSG_TYPE_WARNING | MSG_TYPE_ERROR | MSG_TYPE_FATAL_ERROR))
+ {
+ output += utfTo<std::string>(formatMessage(entry));
+ if (++previewCount >= logFailsPreviewMax)
+ break;
+ }
if (logFailTotal > previewCount)
output += " [...] " + utfTo<std::string>(replaceCpy(_P("Showing %y of 1 row", "Showing %y of %x rows", logFailTotal), //%x used as plural form placeholder!
L"%y", formatNumber(previewCount))) + '\n';
@@ -107,17 +107,21 @@ std::string generateLogFooterTxt(const std::wstring& logFilePath, int logItemsTo
output += " [...] " + utfTo<std::string>(replaceCpy(_P("Showing %y of 1 row", "Showing %y of %x rows", logItemsTotal), //%x used as plural form placeholder!
L"%y", formatNumber(logItemsPreviewMax))) + '\n';
- return output += '\n' + utfTo<std::string>(getOsDescription() + /*throw FileError*/ +
- L" [" + getUserName() /*throw FileError*/ + L"] - " + cm.model + L" - " + cm.vendor + L'\n' +
- std::wstring(SEPARATION_LINE_LEN, L'_') + L'\n' +
- _("Log file") + L": " + logFilePath) + '\n';
+ return output += '\n' + std::string(SEPARATION_LINE_LEN, '_') + '\n' +
+
+ utfTo<std::string>(getOsDescription() + /*throw FileError*/ +
+ L" [" + getUserName() /*throw FileError*/ + L']' +
+ (!cm.model .empty() ? L" - " + cm.model : L"") +
+ (!cm.vendor.empty() ? L" - " + cm.vendor : L"") + L'\n' +
+
+ _("Log file") + L": " + logFilePath) + '\n';
}
-std::string htmlTxtImpl(std::string&& str)
+std::string htmlTxt(const std::string_view& str)
{
- trim(str);
std::string msg = htmlSpecialChars(str);
+ trim(msg);
if (!contains(msg, '\n'))
return msg;
@@ -142,8 +146,9 @@ std::string htmlTxtImpl(std::string&& str)
return msgFmt;
}
-std::string htmlTxt(const std::wstring& str) { return htmlTxtImpl(utfTo<std::string>(str)); }
-std::string htmlTxt(const wchar_t* str) { return htmlTxtImpl(utfTo<std::string>(str)); }
+std::string htmlTxt(const Zstring& str) { return htmlTxt(utfTo<std::string>(str)); }
+std::string htmlTxt(const std::wstring& str) { return htmlTxt(utfTo<std::string>(str)); }
+std::string htmlTxt(const wchar_t* str) { return htmlTxt(utfTo<std::string>(str)); }
//Astyle screws up royally with the following raw string literals!
@@ -161,9 +166,9 @@ std::string formatMessageHtml(const LogEntry& entry)
}
return R"( <tr>
- <td valign="top">)" + formatTime<std::string>(FORMAT_TIME, getLocalTime(entry.time)) + R"(</td>
- <td valign="top"><img src="https://freefilesync.org/images/log/)" + typeImage + R"(" width="16" height="16" alt=")" + typeLabel + R"(:" title=")" + typeLabel + R"("></td>
- <td>)" + htmlTxt(entry.message.c_str()) + R"(</td>
+ <td valign="top">)" + htmlTxt(formatTime(formatTimeTag, getLocalTime(entry.time))) + R"(</td>
+ <td valign="top"><img src="https://freefilesync.org/images/log/)" + typeImage + R"(" height="16" alt=")" + typeLabel + R"(:"></td>
+ <td>)" + htmlTxt(makeStringView(entry.message.begin(), entry.message.end())) + R"(</td>
</tr>
)";
}
@@ -182,10 +187,10 @@ std::wstring generateLogTitle(const ProcessSummary& s)
switch (s.resultStatus)
{
- case SyncResult::finishedSuccess: title += utfTo<std::wstring>("\xe2\x9c\x94\xef\xb8\x8f"); break;
- case SyncResult::finishedWarning: title += utfTo<std::wstring>("\xe2\x9a\xa0"); break;
- case SyncResult::finishedError:
- case SyncResult::aborted: title += utfTo<std::wstring>("\xe2\x9d\x8c"); break;
+ case SyncResult::finishedSuccess: title += utfTo<std::wstring>("\xe2\x9c\x94" "\xef\xb8\x8f"); break; //✔️
+ case SyncResult::finishedWarning: title += utfTo<std::wstring>("\xe2\x9a\xa0" "\xef\xb8\x8f"); break; //⚠️
+ case SyncResult::finishedError: //efb88f (U+FE0F): variation selector-16 to prefer emoji over text rendering
+ case SyncResult::aborted: title += utfTo<std::wstring>("\xe2\x9d\x8c" "\xef\xb8\x8f"); break; //❌️
}
return title;
}
@@ -207,7 +212,7 @@ std::string generateLogHeaderHtml(const ProcessSummary& s, const ErrorLog& log,
.log-items img { display: block; }
.log-items td { padding-bottom: 0.1em; }
- .log-items td:nth-child(1) { padding-right: 10px; }
+ .log-items td:nth-child(1) { padding-right: 10px; white-space: nowrap; }
.log-items td:nth-child(2) { padding-right: 10px; }
</style>
</head>
@@ -220,7 +225,7 @@ std::string generateLogHeaderHtml(const ProcessSummary& s, const ErrorLog& log,
const TimeComp tc = getLocalTime(std::chrono::system_clock::to_time_t(s.startTime)); //returns empty string on failure
output += R"( <div><span style="font-weight:600; color:gray;">)" + jobNamesFmt + R"(</span> &nbsp;<span style="white-space:nowrap">)" +
- formatTime<std::string>(FORMAT_DATE, tc) + " &nbsp;" + formatTime<std::string>(FORMAT_TIME, tc) + "</span></div>\n";
+ htmlTxt(formatTime(formatDateTag, tc)) + " &nbsp;" + htmlTxt(formatTime(formatTimeTag, tc)) + "</span></div>\n";
std::string resultsStatusImage;
switch (s.resultStatus)
@@ -234,27 +239,26 @@ std::string generateLogHeaderHtml(const ProcessSummary& s, const ErrorLog& log,
<div style="margin:10px 0; display:inline-block; border-radius:7px; background:#f8f8f8; box-shadow:1px 1px 4px #888; overflow:hidden;">
<div style="background-color:white; border-bottom:1px solid #AAA; font-size:larger; padding:10px;">
<img src="https://freefilesync.org/images/log/)" + resultsStatusImage + R"(" width="32" height="32" alt="" style="vertical-align:middle;">
- <span style="font-weight:600; vertical-align:middle;">)" + htmlTxt(getResultsStatusLabel(s.resultStatus)) + R"(</span>
+ <span style="font-weight:600; vertical-align:middle;">)" + htmlTxt(getSyncResultLabel(s.resultStatus)) + R"(</span>
</div>
<table role="presentation" class="summary-table" style="border-spacing:0; margin-left:10px; padding:5px 10px;">)";
- const int errorCount = log.getItemCount(MSG_TYPE_ERROR | MSG_TYPE_FATAL_ERROR);
- const int warningCount = log.getItemCount(MSG_TYPE_WARNING);
+ const ErrorLog::Stats logCount = log.getStats();
- if (errorCount > 0)
+ if (logCount.error + logCount.fatal > 0)
output += R"(
<tr>
<td>)" + htmlTxt(_("Errors:")) + R"(</td>
<td><img src="https://freefilesync.org/images/log/msg-error.png" width="24" height="24" alt=""></td>
- <td><span style="font-weight:600;">)" + htmlTxt(formatNumber(errorCount)) + R"(</span></td>
+ <td><span style="font-weight:600;">)" + htmlTxt(formatNumber(logCount.error + logCount.fatal)) + R"(</span></td>
</tr>)";
- if (warningCount > 0)
+ if (logCount.warning > 0)
output += R"(
<tr>
<td>)" + htmlTxt(_("Warnings:")) + R"(</td>
<td><img src="https://freefilesync.org/images/log/msg-warning.png" width="24" height="24" alt=""></td>
- <td><span style="font-weight:600;">)" + htmlTxt(formatNumber(warningCount)) + R"(</span></td>
+ <td><span style="font-weight:600;">)" + htmlTxt(formatNumber(logCount.warning)) + R"(</span></td>
</tr>)";
output += R"(
@@ -289,7 +293,7 @@ std::string generateLogHeaderHtml(const ProcessSummary& s, const ErrorLog& log,
)";
//------------ warnings/errors preview ----------------
- const int logFailTotal = errorCount + warningCount;
+ const int logFailTotal = logCount.warning + logCount.error + logCount.fatal;
if (logFailTotal > 0)
{
output += R"(
@@ -298,13 +302,14 @@ std::string generateLogHeaderHtml(const ProcessSummary& s, const ErrorLog& log,
<table class="log-items" style="line-height:1em; border-spacing:0;">
)";
int previewCount = 0;
- for (const LogEntry& entry : log)
- if (entry.type & (MSG_TYPE_WARNING | MSG_TYPE_ERROR | MSG_TYPE_FATAL_ERROR))
- {
- output += formatMessageHtml(entry);
- if (++previewCount >= logFailsPreviewMax)
- break;
- }
+ if (logFailsPreviewMax > 0)
+ for (const LogEntry& entry : log)
+ if (entry.type & (MSG_TYPE_WARNING | MSG_TYPE_ERROR | MSG_TYPE_FATAL_ERROR))
+ {
+ output += formatMessageHtml(entry);
+ if (++previewCount >= logFailsPreviewMax)
+ break;
+ }
output += R"( </table>
)";
if (logFailTotal > previewCount)
@@ -337,14 +342,16 @@ std::string generateLogFooterHtml(const std::wstring& logFilePath, int logItemsT
return output += R"( <br>
- <div>
+ <div style="border-bottom:1px solid #AAA; margin:5px 0;"></div>
+ <div style="font-size:small;">
<img src="https://freefilesync.org/images/log/)" + osImage + R"(" width="24" height="24" alt="" style="vertical-align:middle;">
<span style="vertical-align:middle;">)" + htmlTxt(getOsDescription()) + /*throw FileError*/ +
- " [" + htmlTxt(getUserName()) /*throw FileError*/ + "] &ndash; " + htmlTxt(cm.model) + " &ndash; " + htmlTxt(cm.vendor) + R"(</span>
+ " [" + htmlTxt(getUserName()) /*throw FileError*/ + ']' +
+ (!cm.model .empty() ? " &ndash; " + htmlTxt(cm.model ) : "") +
+ (!cm.vendor.empty() ? " &ndash; " + htmlTxt(cm.vendor) : "") + R"(</span>
</div>
- <div style="border-bottom:1px solid #AAA; margin:5px 0;"></div>
- <div>
- <img src="https://freefilesync.org/images/log/log.png" width="24" height="24" alt=")" + htmlTxt(_("Log file")) + R"(:" title=")" + htmlTxt(_("Log file")) + R"(" style="vertical-align:middle;">
+ <div style="font-size:small;">
+ <img src="https://freefilesync.org/images/log/log.png" width="24" height="24" alt=")" + htmlTxt(_("Log file")) + R"(:" style="vertical-align:middle;">
<span style="font-family: Consolas,'Courier New',Courier,monospace; vertical-align:middle;">)" + htmlTxt(logFilePath) + R"(</span>
</div>
</body>
@@ -358,59 +365,38 @@ std::string generateLogFooterHtml(const std::wstring& logFilePath, int logItemsT
void streamToLogFile(const ProcessSummary& summary, //throw FileError
const ErrorLog& log,
AFS::OutputStream& streamOut,
- const AbstractPath& logFilePath)
+ const AbstractPath& logFilePath,
+ LogFileFormat logFormat)
{
-#if 0
- auto fmtForTxtFile = [needLbReplace = !equalString(LINE_BREAK, '\n')](const std::string& str)
- {
- if (needLbReplace)
- return replaceCpy(str, '\n', LINE_BREAK);
- return str;
- };
-
- std::string buffer = fmtForTxtFile(generateLogHeaderTxt(summary, log, LOG_FAIL_PREVIEW_MAX)); //don't replace line break any earlier
-
- //write log items in blocks instead of creating one big string: memory allocation might fail; think 1 million entries!
- for (const LogEntry& entry : log)
- {
- buffer += fmtForTxtFile(utfTo<std::string>(formatMessage(entry)));
-
- streamOut.write(&buffer[0], buffer.size()); //throw FileError, X
- buffer.clear();
- }
-
const int logItemsTotal = log.end() - log.begin();
const int logItemsPreviewMax = std::numeric_limits<int>::max();
- buffer += fmtForTxtFile(generateLogFooterTxt(AFS::getDisplayPath(logFilePath), logItemsTotal, logItemsPreviewMax)); //throw FileError
-
- //don't forget to flush:
- streamOut.write(&buffer[0], buffer.size()); //throw FileError, X
-
-#else
- std::string buffer = generateLogHeaderHtml(summary, log, LOG_FAIL_PREVIEW_MAX);
+ std::string buffer = logFormat == LogFileFormat::html ?
+ generateLogHeaderHtml(summary, log, LOG_FAIL_PREVIEW_MAX) :
+ generateLogHeaderTxt (summary, log, LOG_FAIL_PREVIEW_MAX);
//write log items in blocks instead of creating one big string: memory allocation might fail; think 1 million entries!
for (const LogEntry& entry : log)
{
- buffer += formatMessageHtml(entry);
+ buffer += logFormat == LogFileFormat::html ?
+ formatMessageHtml(entry) :
+ formatMessage (entry);
streamOut.write(&buffer[0], buffer.size()); //throw FileError, X
buffer.clear();
}
- const int logItemsTotal = log.end() - log.begin();
- const int logItemsPreviewMax = std::numeric_limits<int>::max();
-
- buffer += generateLogFooterHtml(AFS::getDisplayPath(logFilePath), logItemsTotal, logItemsPreviewMax); //throw FileError
+ buffer += logFormat == LogFileFormat::html ?
+ generateLogFooterHtml(AFS::getDisplayPath(logFilePath), logItemsTotal, logItemsPreviewMax) : //throw FileError
+ generateLogFooterTxt (AFS::getDisplayPath(logFilePath), logItemsTotal, logItemsPreviewMax); //throw FileError
//don't forget to flush:
streamOut.write(&buffer[0], buffer.size()); //throw FileError, X
-#endif
}
void saveNewLogFile(const AbstractPath& logFilePath, //throw FileError, X
+ LogFileFormat logFormat,
const ProcessSummary& summary,
const ErrorLog& log,
const std::function<void(const std::wstring& msg)>& notifyStatus /*throw X*/)
@@ -437,7 +423,7 @@ void saveNewLogFile(const AbstractPath& logFilePath, //throw FileError, X
};
std::unique_ptr<AFS::OutputStream> logFileStream = AFS::getOutputStream(logFilePath, std::nullopt /*streamSize*/, std::nullopt /*modTime*/, notifyUnbufferedIO); //throw FileError
- streamToLogFile(summary, log, *logFileStream, logFilePath); //throw FileError, X
+ streamToLogFile(summary, log, *logFileStream, logFilePath, logFormat); //throw FileError, X
logFileStream->finalize(); //throw FileError, X
}
@@ -554,7 +540,7 @@ Zstring fff::getDefaultLogFolderPath() { return getConfigDirPathPf() + Zstr("Log
//"Backup FreeFileSync 2013-09-15 015052.123.html"
//"Backup FreeFileSync 2013-09-15 015052.123 [Error].html"
-AbstractPath fff::generateLogFilePath(const ProcessSummary& summary, const Zstring& altLogFolderPathPhrase /*optional*/)
+AbstractPath fff::generateLogFilePath(LogFileFormat logFormat, const ProcessSummary& summary, const Zstring& altLogFolderPathPhrase /*optional*/)
{
//const std::string colon = "\xcb\xb8"; //="modifier letter raised colon" => regular colon is forbidden in file names on Windows and OS X
//=> too many issues, most notably cmd.exe is not Unicode-aware: https://freefilesync.org/forum/viewtopic.php?t=1679
@@ -575,7 +561,7 @@ AbstractPath fff::generateLogFilePath(const ProcessSummary& summary, const Zstri
logFileName.resize(logFileName.size() - 2);
}
- logFileName += formatTime<Zstring>(Zstr("%Y-%m-%d %H%M%S"), tc) +
+ logFileName += formatTime(Zstr("%Y-%m-%d %H%M%S"), tc) +
Zstr(".") + printNumber<Zstring>(Zstr("%03d"), static_cast<int>(timeMs)); //[ms] should yield a fairly unique name
static_assert(TIME_STAMP_LENGTH == 21);
@@ -593,8 +579,11 @@ AbstractPath fff::generateLogFilePath(const ProcessSummary& summary, const Zstri
if (!failStatus.empty())
logFileName += STATUS_BEGIN_TOKEN + utfTo<Zstring>(failStatus) + STATUS_END_TOKEN;
- logFileName += Zstr(".html");
+ if (logFormat == LogFileFormat::html)
+ logFileName += Zstr(".html");
+ else
+ logFileName += Zstr(".log");
AbstractPath logFolderPath = createAbstractPath(altLogFolderPathPhrase);
if (AFS::isNullPath(logFolderPath))
@@ -608,13 +597,14 @@ void fff::saveLogFile(const AbstractPath& logFilePath, //throw FileError, X
const ProcessSummary& summary,
const ErrorLog& log,
int logfilesMaxAgeDays,
+ LogFileFormat logFormat,
const std::set<AbstractPath>& logFilePathsToKeep,
const std::function<void(const std::wstring& msg)>& notifyStatus /*throw X*/)
{
std::exception_ptr firstError;
try
{
- saveNewLogFile(logFilePath, summary, log, notifyStatus); //throw FileError, X
+ saveNewLogFile(logFilePath, logFormat, summary, log, notifyStatus); //throw FileError, X
}
catch (const FileError&) { if (!firstError) firstError = std::current_exception(); };
@@ -634,7 +624,7 @@ void fff::saveLogFile(const AbstractPath& logFilePath, //throw FileError, X
-void fff::sendLogAsEmail(const Zstring& email, //throw FileError, X
+void fff::sendLogAsEmail(const std::string& email, //throw FileError, X
const ProcessSummary& summary,
const ErrorLog& log,
const AbstractPath& logFilePath,
@@ -644,5 +634,5 @@ void fff::sendLogAsEmail(const Zstring& email, //throw FileError, X
{
throw SysError(_("Requires FreeFileSync Donation Edition"));
}
- catch (const SysError& e) { throw FileError(replaceCpy(_("Cannot send notification email to %x."), L"%x", utfTo<std::wstring>(email)), e.toString()); }
+ catch (const SysError& e) { throw FileError(replaceCpy(_("Cannot send notification email to %x."), L"%x", L'"' + utfTo<std::wstring>(email) + L'"'), e.toString()); }
}
diff --git a/FreeFileSync/Source/base/log_file.h b/FreeFileSync/Source/log_file.h
index 3a3a481c..5eec06ad 100644
--- a/FreeFileSync/Source/base/log_file.h
+++ b/FreeFileSync/Source/log_file.h
@@ -11,24 +11,31 @@
#include <zen/error_log.h>
#include "return_codes.h"
#include "status_handler.h"
-#include "../afs/abstract.h"
+#include "afs/abstract.h"
namespace fff
{
Zstring getDefaultLogFolderPath();
+enum class LogFileFormat
+{
+ html,
+ text
+};
+
-AbstractPath generateLogFilePath(const ProcessSummary& summary, const Zstring& altLogFolderPathPhrase /*optional*/);
+AbstractPath generateLogFilePath(LogFileFormat logFormat, const ProcessSummary& summary, const Zstring& altLogFolderPathPhrase /*optional*/);
void saveLogFile(const AbstractPath& logFilePath, //throw FileError, X
const ProcessSummary& summary,
const zen::ErrorLog& log,
int logfilesMaxAgeDays,
+ LogFileFormat logFormat,
const std::set<AbstractPath>& logFilePathsToKeep,
const std::function<void(const std::wstring& msg)>& notifyStatus /*throw X*/);
-void sendLogAsEmail(const Zstring& email, //throw FileError, X
+void sendLogAsEmail(const std::string& email, //throw FileError, X
const ProcessSummary& summary,
const zen::ErrorLog& log,
const AbstractPath& logFilePath,
diff --git a/FreeFileSync/Source/base/parse_lng.h b/FreeFileSync/Source/parse_lng.h
index 361628e4..24f63d3a 100644
--- a/FreeFileSync/Source/base/parse_lng.h
+++ b/FreeFileSync/Source/parse_lng.h
@@ -488,7 +488,7 @@ private:
throw ParsingError({ L"The & character to mark a menu item access key must not occur at the end of a string", scn_.posRow(), scn_.posCol() });
//if source ends with colon, so must translation (note: character seems to be universally used, even for asian and arabic languages)
- if (endsWith(original, ":") && !endsWithColon(translation))
+ if (endsWith(original, ':') && !endsWithColon(translation))
throw ParsingError({ L"Source text ends with a colon character \":\", but translation does not", scn_.posRow(), scn_.posCol() });
//if source ends with a period, so must translation (note: character seems to be universally used, even for asian and arabic languages)
@@ -601,7 +601,7 @@ private:
throw ParsingError({ L"The & character to mark a menu item access key must not occur at the end of a string", scn_.posRow(), scn_.posCol() });
//if source ends with colon, so must translation (note: character seems to be universally used, even for asian and arabic languages)
- if (endsWith(original.first, ":") || endsWith(original.second, ":"))
+ if (endsWith(original.first, ':') || endsWith(original.second, ':'))
for (const std::string& str : allTexts)
if (!endsWithColon(str))
throw ParsingError({ L"Source text ends with a colon character \":\", but translation does not", scn_.posRow(), scn_.posCol() });
@@ -659,7 +659,7 @@ private:
static bool endsWithColon(const std::string& s)
{
using namespace zen;
- return endsWith(s, ":") ||
+ return endsWith(s, ':') ||
endsWith(s, "\xef\xbc\x9a"); //chinese colon
}
diff --git a/FreeFileSync/Source/base/parse_plural.h b/FreeFileSync/Source/parse_plural.h
index 242dd4a6..242dd4a6 100644
--- a/FreeFileSync/Source/base/parse_plural.h
+++ b/FreeFileSync/Source/parse_plural.h
diff --git a/FreeFileSync/Source/base/perf_check.cpp b/FreeFileSync/Source/perf_check.cpp
index 9493a8a2..9493a8a2 100644
--- a/FreeFileSync/Source/base/perf_check.cpp
+++ b/FreeFileSync/Source/perf_check.cpp
diff --git a/FreeFileSync/Source/base/perf_check.h b/FreeFileSync/Source/perf_check.h
index 2e9ccc6d..2e9ccc6d 100644
--- a/FreeFileSync/Source/base/perf_check.h
+++ b/FreeFileSync/Source/perf_check.h
diff --git a/FreeFileSync/Source/base/return_codes.h b/FreeFileSync/Source/return_codes.h
index 0fe72022..ad9318c6 100644
--- a/FreeFileSync/Source/base/return_codes.h
+++ b/FreeFileSync/Source/return_codes.h
@@ -59,7 +59,7 @@ FfsReturnCode mapToReturnCode(SyncResult syncStatus)
inline
-std::wstring getResultsStatusLabel(SyncResult resultStatus)
+std::wstring getSyncResultLabel(SyncResult resultStatus)
{
switch (resultStatus)
{
diff --git a/FreeFileSync/Source/base/status_handler.cpp b/FreeFileSync/Source/status_handler.cpp
index 19d1e882..19d1e882 100644
--- a/FreeFileSync/Source/base/status_handler.cpp
+++ b/FreeFileSync/Source/status_handler.cpp
diff --git a/FreeFileSync/Source/base/status_handler.h b/FreeFileSync/Source/status_handler.h
index 339f9ebe..9058033b 100644
--- a/FreeFileSync/Source/base/status_handler.h
+++ b/FreeFileSync/Source/status_handler.h
@@ -13,7 +13,7 @@
#include <string>
#include <zen/i18n.h>
#include <zen/basic_math.h>
-#include "process_callback.h"
+#include "base/process_callback.h"
#include "return_codes.h"
diff --git a/FreeFileSync/Source/ui/abstract_folder_picker.cpp b/FreeFileSync/Source/ui/abstract_folder_picker.cpp
index 4c96e6f7..8f2fe782 100644
--- a/FreeFileSync/Source/ui/abstract_folder_picker.cpp
+++ b/FreeFileSync/Source/ui/abstract_folder_picker.cpp
@@ -11,7 +11,7 @@
#include <wx+/popup_dlg.h>
#include <wx+/image_tools.h>
#include "gui_generated.h"
-#include "../base/icon_buffer.h"
+#include "../icon_buffer.h"
using namespace zen;
using namespace fff;
@@ -264,7 +264,7 @@ void AbstractFolderPickerDlg::findAndNavigateToExistingPath(const AbstractPath&
if (!AFS::getParentPath(folderPath))
return m_staticTextStatus->SetLabel(L"");
- m_staticTextStatus->SetLabel(_("Scanning...") + L" " + utfTo<std::wstring>(FILE_NAME_SEPARATOR + folderPath.afsPath.value)); //keep it short!
+ m_staticTextStatus->SetLabel(_("Scanning...") + L' ' + utfTo<std::wstring>(FILE_NAME_SEPARATOR + folderPath.afsPath.value)); //keep it short!
guiQueue_.processAsync([folderPath]() -> std::optional<AFS::ItemType>
{
diff --git a/FreeFileSync/Source/ui/batch_config.cpp b/FreeFileSync/Source/ui/batch_config.cpp
index b158a8ca..51e6eda3 100644
--- a/FreeFileSync/Source/ui/batch_config.cpp
+++ b/FreeFileSync/Source/ui/batch_config.cpp
@@ -14,7 +14,7 @@
#include <wx+/popup_dlg.h>
#include "gui_generated.h"
#include "folder_selector.h"
-#include "../base/help_provider.h"
+#include "../help_provider.h"
using namespace zen;
diff --git a/FreeFileSync/Source/ui/batch_config.h b/FreeFileSync/Source/ui/batch_config.h
index 7bb406b3..35fb73fa 100644
--- a/FreeFileSync/Source/ui/batch_config.h
+++ b/FreeFileSync/Source/ui/batch_config.h
@@ -8,7 +8,7 @@
#define BATCH_CONFIG_H_3921674832168945
#include <wx/window.h>
-#include "../base/config.h"
+#include "../config.h"
namespace fff
diff --git a/FreeFileSync/Source/ui/batch_status_handler.cpp b/FreeFileSync/Source/ui/batch_status_handler.cpp
index 28f1833c..40098bca 100644
--- a/FreeFileSync/Source/ui/batch_status_handler.cpp
+++ b/FreeFileSync/Source/ui/batch_status_handler.cpp
@@ -9,9 +9,9 @@
#include <zen/shutdown.h>
#include <wx+/popup_dlg.h>
#include <wx/app.h>
-#include "../base/resolve_path.h"
-#include "../base/log_file.h"
#include "../afs/concrete.h"
+#include "../base/resolve_path.h"
+#include "../log_file.h"
using namespace zen;
using namespace fff;
@@ -61,8 +61,9 @@ BatchStatusHandler::~BatchStatusHandler()
BatchStatusHandler::Result BatchStatusHandler::reportResults(const Zstring& postSyncCommand, PostSyncCondition postSyncCondition,
- const Zstring& altLogFolderPathPhrase, int logfilesMaxAgeDays, const std::set<AbstractPath>& logFilePathsToKeep,
- const Zstring& emailNotifyAddress, ResultsNotification emailNotifyCondition) //noexcept!!
+ const Zstring& altLogFolderPathPhrase, int logfilesMaxAgeDays, LogFileFormat logFormat,
+ const std::set<AbstractPath>& logFilePathsToKeep,
+ const std::string& emailNotifyAddress, ResultsNotification emailNotifyCondition) //noexcept!!
{
const auto totalTime = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - startTime_);
@@ -76,9 +77,10 @@ BatchStatusHandler::Result BatchStatusHandler::reportResults(const Zstring& post
errorLog_.logMsg(_("Stopped"), MSG_TYPE_ERROR); //= user cancel; *not* a MSG_TYPE_FATAL_ERROR!
return SyncResult::aborted;
}
- else if (errorLog_.getItemCount(MSG_TYPE_ERROR | MSG_TYPE_FATAL_ERROR) > 0)
+ const ErrorLog::Stats logCount = errorLog_.getStats();
+ if (logCount.error + logCount.fatal > 0)
return SyncResult::finishedError;
- else if (errorLog_.getItemCount(MSG_TYPE_WARNING) > 0)
+ else if (logCount.warning > 0)
return SyncResult::finishedWarning;
if (getStatsTotal() == ProgressStats())
@@ -96,7 +98,7 @@ BatchStatusHandler::Result BatchStatusHandler::reportResults(const Zstring& post
totalTime
};
- const AbstractPath logFilePath = generateLogFilePath(summary, altLogFolderPathPhrase);
+ const AbstractPath logFilePath = generateLogFilePath(logFormat, summary, altLogFolderPathPhrase);
//e.g. %AppData%\FreeFileSync\Logs\Backup FreeFileSync 2013-09-15 015052.123 [Error].log
if (const Zstring cmdLine = trimCpy(postSyncCommand);
@@ -113,9 +115,8 @@ BatchStatusHandler::Result BatchStatusHandler::reportResults(const Zstring& post
//::wxSetEnv(L"logfile_path", AFS::getDisplayPath(logFilePath));
////----------------------------------------------------------------------
const Zstring cmdLineExp = expandMacros(cmdLine);
- const int exitCode = shellExecute(cmdLineExp, ExecutionType::sync, false /*hideConsole*/); //throw FileError
- errorLog_.logMsg(_("Executing command:") + L" " + utfTo<std::wstring>(cmdLineExp) + L" [" + replaceCpy(_("Exit Code %x"), L"%x", numberTo<std::wstring>(exitCode)) + L']',
- exitCode == 0 ? MSG_TYPE_INFO : MSG_TYPE_ERROR);
+ errorLog_.logMsg(_("Executing command:") + L' ' + utfTo<std::wstring>(cmdLineExp), MSG_TYPE_INFO);
+ shellExecute(cmdLineExp, ExecutionType::async, false /*hideConsole*/); //throw FileError
}
catch (const FileError& e) { errorLog_.logMsg(e.toString(), MSG_TYPE_ERROR); }
}
@@ -123,7 +124,7 @@ BatchStatusHandler::Result BatchStatusHandler::reportResults(const Zstring& post
//---------------------------- save log file ------------------------------
auto notifyStatusNoThrow = [&](const std::wstring& msg) { try { updateStatus(msg); /*throw AbortProcess*/ } catch (AbortProcess&) {} };
- if (const Zstring notifyEmail = trimCpy(emailNotifyAddress);
+ if (const std::string notifyEmail = trimCpy(emailNotifyAddress);
!notifyEmail.empty())
{
if (getAbortStatus() && *getAbortStatus() == AbortTrigger::user)
@@ -144,7 +145,7 @@ BatchStatusHandler::Result BatchStatusHandler::reportResults(const Zstring& post
try //create not before destruction: 1. avoid issues with FFS trying to sync open log file 2. include status in log file name without extra rename
{
//do NOT use tryReportingError()! saving log files should not be cancellable!
- saveLogFile(logFilePath, summary, errorLog_, logfilesMaxAgeDays, logFilePathsToKeep, notifyStatusNoThrow); //throw FileError
+ saveLogFile(logFilePath, summary, errorLog_, logfilesMaxAgeDays, logFormat, logFilePathsToKeep, notifyStatusNoThrow); //throw FileError
}
catch (const FileError& e) { errorLog_.logMsg(e.toString(), MSG_TYPE_ERROR); }
@@ -299,7 +300,7 @@ ProcessCallback::Response BatchStatusHandler::reportError(const std::wstring& ms
if (retryNumber < automaticRetryCount_)
{
errorLog_.logMsg(msg + L"\n-> " + _("Automatic retry"), MSG_TYPE_INFO);
- delayAndCountDown(_("Automatic retry") + (automaticRetryCount_ <= 1 ? L"" : L" " + numberTo<std::wstring>(retryNumber + 1) + L"/" + numberTo<std::wstring>(automaticRetryCount_)),
+ delayAndCountDown(_("Automatic retry") + (automaticRetryCount_ <= 1 ? L"" : L' ' + numberTo<std::wstring>(retryNumber + 1) + L"/" + numberTo<std::wstring>(automaticRetryCount_)),
automaticRetryDelay_, [&](const std::wstring& statusMsg) { this->updateStatus(_("Error") + L": " + statusMsg); }); //throw AbortProcess
return ProcessCallback::retry;
}
diff --git a/FreeFileSync/Source/ui/batch_status_handler.h b/FreeFileSync/Source/ui/batch_status_handler.h
index b56a4aed..2e59ac7e 100644
--- a/FreeFileSync/Source/ui/batch_status_handler.h
+++ b/FreeFileSync/Source/ui/batch_status_handler.h
@@ -10,8 +10,8 @@
#include <chrono>
#include <zen/error_log.h>
#include "progress_indicator.h"
-#include "../base/config.h"
-#include "../base/status_handler.h"
+#include "../config.h"
+#include "../status_handler.h"
namespace fff
@@ -54,8 +54,8 @@ public:
AbstractPath logFilePath;
};
Result reportResults(const Zstring& postSyncCommand, PostSyncCondition postSyncCondition,
- const Zstring& altLogFolderPathPhrase, int logfilesMaxAgeDays, const std::set<AbstractPath>& logFilePathsToKeep,
- const Zstring& emailNotifyAddress, ResultsNotification emailNotifyCondition); //noexcept!!
+ const Zstring& altLogFolderPathPhrase, int logfilesMaxAgeDays, LogFileFormat logFormat, const std::set<AbstractPath>& logFilePathsToKeep,
+ const std::string& emailNotifyAddress, ResultsNotification emailNotifyCondition); //noexcept!!
private:
bool switchToGuiRequested_ = false;
diff --git a/FreeFileSync/Source/ui/cfg_grid.cpp b/FreeFileSync/Source/ui/cfg_grid.cpp
index 7ae27b42..fca67704 100644
--- a/FreeFileSync/Source/ui/cfg_grid.cpp
+++ b/FreeFileSync/Source/ui/cfg_grid.cpp
@@ -13,8 +13,8 @@
#include <wx+/image_resources.h>
#include <wx+/popup_dlg.h>
#include <wx/settings.h>
-#include "../base/icon_buffer.h"
-#include "../base/ffs_paths.h"
+#include "../icon_buffer.h"
+#include "../ffs_paths.h"
using namespace zen;
using namespace fff;
@@ -88,13 +88,13 @@ void ConfigView::addCfgFilesImpl(const std::vector<Zstring>& filePaths)
std::tie(detail.name, detail.cfgType, detail.isLastRunCfg) = [&]
{
if (equalNativePath(filePath, lastRunConfigPath_))
- return std::make_tuple(utfTo<Zstring>(L"[" + _("Last session") + L"]"), Details::CFG_TYPE_GUI, true);
+ return std::make_tuple(utfTo<Zstring>(L'[' + _("Last session") + L']'), Details::CFG_TYPE_GUI, true);
const Zstring fileName = afterLast(filePath, FILE_NAME_SEPARATOR, IF_MISSING_RETURN_ALL);
- if (endsWithAsciiNoCase(fileName, Zstr(".ffs_gui")))
+ if (endsWithAsciiNoCase(fileName, ".ffs_gui"))
return std::make_tuple(beforeLast(fileName, Zstr('.'), IF_MISSING_RETURN_NONE), Details::CFG_TYPE_GUI, false);
- else if (endsWithAsciiNoCase(fileName, Zstr(".ffs_batch")))
+ else if (endsWithAsciiNoCase(fileName, ".ffs_batch"))
return std::make_tuple(beforeLast(fileName, Zstr('.'), IF_MISSING_RETURN_NONE), Details::CFG_TYPE_BATCH, false);
else
return std::make_tuple(fileName, Details::CFG_TYPE_NONE, false);
@@ -320,14 +320,14 @@ private:
const int daysPast = getDaysPast(item->cfgItem.lastSyncTime);
return daysPast == 0 ? _("Today") : _P("1 day", "%x days", daysPast);
- //return formatTime<std::wstring>(FORMAT_DATE_TIME, getLocalTime(item->lastSyncTime));
+ //return formatTime(formatDateTimeTag, getLocalTime(item->lastSyncTime));
}
break;
case ColumnTypeCfg::lastLog:
if (!item->isLastRunCfg &&
!AFS::isNullPath(item->cfgItem.logFilePath))
- return getResultsStatusLabel(item->cfgItem.logResult);
+ return getSyncResultLabel(item->cfgItem.logResult);
break;
}
return std::wstring();
@@ -570,7 +570,7 @@ private:
if (!item->isLastRunCfg &&
!AFS::isNullPath(item->cfgItem.logFilePath))
- return getResultsStatusLabel(item->cfgItem.logResult) + SPACED_DASH + AFS::getDisplayPath(item->cfgItem.logFilePath);
+ return getSyncResultLabel(item->cfgItem.logResult) + SPACED_DASH + AFS::getDisplayPath(item->cfgItem.logFilePath);
break;
}
return std::wstring();
@@ -630,7 +630,7 @@ ConfigView& cfggrid::getDataView(Grid& grid)
{
if (auto* prov = dynamic_cast<GridDataCfg*>(grid.getDataProvider()))
return prov->getDataView();
- throw std::runtime_error(std::string(__FILE__) + "[" + numberTo<std::string>(__LINE__) + "] cfggrid was not initialized.");
+ throw std::runtime_error(std::string(__FILE__) + '[' + numberTo<std::string>(__LINE__) + "] cfggrid was not initialized.");
}
@@ -662,7 +662,7 @@ int cfggrid::getSyncOverdueDays(Grid& grid)
{
if (auto* prov = dynamic_cast<GridDataCfg*>(grid.getDataProvider()))
return prov->getSyncOverdueDays();
- throw std::runtime_error(std::string(__FILE__) + "[" + numberTo<std::string>(__LINE__) + "] cfggrid was not initialized.");
+ throw std::runtime_error(std::string(__FILE__) + '[' + numberTo<std::string>(__LINE__) + "] cfggrid was not initialized.");
}
@@ -670,7 +670,7 @@ void cfggrid::setSyncOverdueDays(Grid& grid, int syncOverdueDays)
{
auto* prov = dynamic_cast<GridDataCfg*>(grid.getDataProvider());
if (!prov)
- throw std::runtime_error(std::string(__FILE__) + "[" + numberTo<std::string>(__LINE__) + "] cfggrid was not initialized.");
+ throw std::runtime_error(std::string(__FILE__) + '[' + numberTo<std::string>(__LINE__) + "] cfggrid was not initialized.");
prov->setSyncOverdueDays(syncOverdueDays);
grid.Refresh();
diff --git a/FreeFileSync/Source/ui/cfg_grid.h b/FreeFileSync/Source/ui/cfg_grid.h
index 3ace5ff7..5be3ce71 100644
--- a/FreeFileSync/Source/ui/cfg_grid.h
+++ b/FreeFileSync/Source/ui/cfg_grid.h
@@ -10,7 +10,7 @@
#include <wx+/grid.h>
#include <wx+/dc.h>
#include <zen/zstring.h>
-#include "../base/return_codes.h"
+#include "../return_codes.h"
#include "../afs/concrete.h"
diff --git a/FreeFileSync/Source/ui/file_grid.cpp b/FreeFileSync/Source/ui/file_grid.cpp
index 12ff49f8..93708754 100644
--- a/FreeFileSync/Source/ui/file_grid.cpp
+++ b/FreeFileSync/Source/ui/file_grid.cpp
@@ -739,15 +739,15 @@ private:
visitFSObject(*fsObj, [](const FolderPair& folder) {},
[&](const FilePair& file)
{
- toolTip += L"\n" +
- _("Size:") + L" " + zen::formatFilesizeShort(file.getFileSize<side>()) + L"\n" +
- _("Date:") + L" " + zen::formatUtcToLocalTime(file.getLastWriteTime<side>());
+ toolTip += L'\n' +
+ _("Size:") + L' ' + zen::formatFilesizeShort(file.getFileSize<side>()) + L'\n' +
+ _("Date:") + L' ' + zen::formatUtcToLocalTime(file.getLastWriteTime<side>());
},
[&](const SymlinkPair& symlink)
{
- toolTip += L"\n" +
- _("Date:") + L" " + zen::formatUtcToLocalTime(symlink.getLastWriteTime<side>());
+ toolTip += L'\n' +
+ _("Date:") + L' ' + zen::formatUtcToLocalTime(symlink.getLastWriteTime<side>());
});
}
return toolTip;
@@ -1607,7 +1607,7 @@ FileView& filegrid::getDataView(Grid& grid)
if (auto* prov = dynamic_cast<GridDataBase*>(grid.getDataProvider()))
return prov->getDataView();
- throw std::runtime_error("filegrid was not initialized! " + std::string(__FILE__) + ":" + numberTo<std::string>(__LINE__));
+ throw std::runtime_error("filegrid was not initialized! " + std::string(__FILE__) + ':' + numberTo<std::string>(__LINE__));
}
diff --git a/FreeFileSync/Source/ui/file_grid.h b/FreeFileSync/Source/ui/file_grid.h
index a416a0d0..2fadb7c8 100644
--- a/FreeFileSync/Source/ui/file_grid.h
+++ b/FreeFileSync/Source/ui/file_grid.h
@@ -10,7 +10,7 @@
#include <wx+/grid.h>
#include "file_view.h"
#include "file_grid_attr.h"
-#include "../base/icon_buffer.h"
+#include "../icon_buffer.h"
namespace fff
diff --git a/FreeFileSync/Source/ui/folder_pair.h b/FreeFileSync/Source/ui/folder_pair.h
index 419fc751..c3ee65bb 100644
--- a/FreeFileSync/Source/ui/folder_pair.h
+++ b/FreeFileSync/Source/ui/folder_pair.h
@@ -17,7 +17,7 @@
#include "small_dlgs.h"
#include "sync_cfg.h"
#include "../base/norm_filter.h"
-#include "../base/structures.h"
+#include "../base_tools.h"
namespace fff
diff --git a/FreeFileSync/Source/ui/folder_selector.cpp b/FreeFileSync/Source/ui/folder_selector.cpp
index 9afdfe3c..8e2037ba 100644
--- a/FreeFileSync/Source/ui/folder_selector.cpp
+++ b/FreeFileSync/Source/ui/folder_selector.cpp
@@ -15,7 +15,7 @@
#include "small_dlgs.h" //includes structures.h, which defines "AFS"
#include "../afs/concrete.h"
#include "../afs/native.h"
-#include "../base/icon_buffer.h"
+#include "../icon_buffer.h"
@@ -49,6 +49,7 @@ void setFolderPathPhrase(const Zstring& folderPathPhrase, FolderHistoryBox* comb
}
}
+
}
//##############################################################################################################
diff --git a/FreeFileSync/Source/ui/gui_generated.cpp b/FreeFileSync/Source/ui/gui_generated.cpp
index 80dd34d5..78092e06 100644
--- a/FreeFileSync/Source/ui/gui_generated.cpp
+++ b/FreeFileSync/Source/ui/gui_generated.cpp
@@ -619,14 +619,14 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const
bSizer42 = new wxBoxSizer( wxHORIZONTAL );
- m_bitmapLogStatus = new wxStaticBitmap( m_panelLog, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), 0 );
- bSizer42->Add( m_bitmapLogStatus, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
+ m_bitmapSyncResult = new wxStaticBitmap( m_panelLog, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1, -1 ), 0 );
+ bSizer42->Add( m_bitmapSyncResult, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
- m_staticTextLogStatus = new wxStaticText( m_panelLog, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 );
- m_staticTextLogStatus->Wrap( -1 );
- m_staticTextLogStatus->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD, false, wxEmptyString ) );
+ m_staticTextSyncResult = new wxStaticText( m_panelLog, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 );
+ m_staticTextSyncResult->Wrap( -1 );
+ m_staticTextSyncResult->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD, false, wxEmptyString ) );
- bSizer42->Add( m_staticTextLogStatus, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxRIGHT, 10 );
+ bSizer42->Add( m_staticTextSyncResult, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxRIGHT, 10 );
bSizer42->Add( 10, 0, 0, 0, 5 );
@@ -1421,7 +1421,7 @@ ConfigDlgGenerated::ConfigDlgGenerated( wxWindow* parent, wxWindowID id, const w
bSizer176->Add( m_radioBtnSymlinksDirect, 0, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 );
- bSizer1721->Add( bSizer176, 0, wxLEFT|wxEXPAND, 18 );
+ bSizer1721->Add( bSizer176, 0, wxLEFT|wxEXPAND, 15 );
bSizer1721->Add( 0, 0, 1, wxEXPAND, 5 );
@@ -2270,10 +2270,10 @@ ConfigDlgGenerated::ConfigDlgGenerated( wxWindow* parent, wxWindowID id, const w
bSizer291 = new wxBoxSizer( wxHORIZONTAL );
m_bitmapEmail = new wxStaticBitmap( m_panelSyncSettings, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0 );
- bSizer291->Add( m_bitmapEmail, 0, wxRIGHT|wxALIGN_CENTER_VERTICAL, 5 );
+ bSizer291->Add( m_bitmapEmail, 0, wxALIGN_CENTER_VERTICAL, 5 );
m_checkBoxSendEmail = new wxCheckBox( m_panelSyncSettings, wxID_ANY, _("Send email notification:"), wxDefaultPosition, wxDefaultSize, 0 );
- bSizer291->Add( m_checkBoxSendEmail, 0, wxALIGN_CENTER_VERTICAL, 5 );
+ bSizer291->Add( m_checkBoxSendEmail, 0, wxALIGN_CENTER_VERTICAL|wxLEFT, 5 );
bSizer290->Add( bSizer291, 0, 0, 5 );
@@ -2282,22 +2282,22 @@ ConfigDlgGenerated::ConfigDlgGenerated( wxWindow* parent, wxWindowID id, const w
bSizer290->Add( m_comboBoxEmail, 0, wxEXPAND|wxTOP, 5 );
- bSizer287->Add( bSizer290, 1, 0, 5 );
+ bSizer287->Add( bSizer290, 1, wxRIGHT, 5 );
wxBoxSizer* bSizer289;
bSizer289 = new wxBoxSizer( wxVERTICAL );
m_bpButtonEmailAlways = new wxBitmapButton( m_panelSyncSettings, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW|0 );
- bSizer289->Add( m_bpButtonEmailAlways, 0, wxLEFT, 5 );
+ bSizer289->Add( m_bpButtonEmailAlways, 0, 0, 5 );
m_bpButtonEmailErrorWarning = new wxBitmapButton( m_panelSyncSettings, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW|0 );
- bSizer289->Add( m_bpButtonEmailErrorWarning, 0, wxLEFT, 5 );
+ bSizer289->Add( m_bpButtonEmailErrorWarning, 0, 0, 5 );
m_bpButtonEmailErrorOnly = new wxBitmapButton( m_panelSyncSettings, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW|0 );
- bSizer289->Add( m_bpButtonEmailErrorOnly, 0, wxLEFT, 5 );
+ bSizer289->Add( m_bpButtonEmailErrorOnly, 0, 0, 5 );
- bSizer287->Add( bSizer289, 0, 0, 5 );
+ bSizer287->Add( bSizer289, 0, wxLEFT, 5 );
bSizer292->Add( bSizer287, 0, wxEXPAND, 5 );
@@ -2328,11 +2328,11 @@ ConfigDlgGenerated::ConfigDlgGenerated( wxWindow* parent, wxWindowID id, const w
bSizer279 = new wxBoxSizer( wxHORIZONTAL );
m_bitmapLogFile = new wxStaticBitmap( m_panelLogfile, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0 );
- bSizer279->Add( m_bitmapLogFile, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 5 );
+ bSizer279->Add( m_bitmapLogFile, 0, wxALIGN_CENTER_VERTICAL, 5 );
m_checkBoxOverrideLogPath = new wxCheckBox( m_panelLogfile, wxID_ANY, _("&Override default log path:"), wxDefaultPosition, wxDefaultSize, 0 );
m_checkBoxOverrideLogPath->SetValue(true);
- bSizer279->Add( m_checkBoxOverrideLogPath, 1, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
+ bSizer279->Add( m_checkBoxOverrideLogPath, 1, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5 );
m_buttonSelectLogFolder = new wxButton( m_panelLogfile, wxID_ANY, _("Browse"), wxDefaultPosition, wxDefaultSize, 0 );
m_buttonSelectLogFolder->SetToolTip( _("Select a folder") );
@@ -2443,7 +2443,7 @@ ConfigDlgGenerated::ConfigDlgGenerated( wxWindow* parent, wxWindowID id, const w
m_checkBoxAutoRetry->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( ConfigDlgGenerated::OnToggleAutoRetry ), NULL, this );
m_hyperlink1711->Connect( wxEVT_COMMAND_HYPERLINK, wxHyperlinkEventHandler( ConfigDlgGenerated::OnHelpPerformance ), NULL, this );
m_textCtrlInclude->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( ConfigDlgGenerated::OnChangeFilterOption ), NULL, this );
- m_hyperlink171->Connect( wxEVT_COMMAND_HYPERLINK, wxHyperlinkEventHandler( ConfigDlgGenerated::OnHelpShowExamples ), NULL, this );
+ m_hyperlink171->Connect( wxEVT_COMMAND_HYPERLINK, wxHyperlinkEventHandler( ConfigDlgGenerated::OnHelpFilterSettings ), NULL, this );
m_textCtrlExclude->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( ConfigDlgGenerated::OnChangeFilterOption ), NULL, this );
m_choiceUnitMinSize->Connect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( ConfigDlgGenerated::OnChangeFilterOption ), NULL, this );
m_choiceUnitMaxSize->Connect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( ConfigDlgGenerated::OnChangeFilterOption ), NULL, this );
@@ -2474,7 +2474,7 @@ ConfigDlgGenerated::ConfigDlgGenerated( wxWindow* parent, wxWindowID id, const w
m_checkBoxVersionMaxDays->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( ConfigDlgGenerated::OnToggleVersioningLimit ), NULL, this );
m_checkBoxVersionCountMin->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( ConfigDlgGenerated::OnToggleVersioningLimit ), NULL, this );
m_checkBoxVersionCountMax->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( ConfigDlgGenerated::OnToggleVersioningLimit ), NULL, this );
- m_checkBoxSendEmail->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( ConfigDlgGenerated::OnToggleMiscOption ), NULL, this );
+ m_checkBoxSendEmail->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( ConfigDlgGenerated::OnToggleMiscEmail ), NULL, this );
m_bpButtonEmailAlways->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( ConfigDlgGenerated::OnEmailAlways ), NULL, this );
m_bpButtonEmailErrorWarning->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( ConfigDlgGenerated::OnEmailErrorWarning ), NULL, this );
m_bpButtonEmailErrorOnly->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( ConfigDlgGenerated::OnEmailErrorOnly ), NULL, this );
@@ -3937,7 +3937,7 @@ BatchDlgGenerated::BatchDlgGenerated( wxWindow* parent, wxWindowID id, const wxS
bSizer243->Add( m_checkBoxIgnoreErrors, 1, wxALIGN_CENTER_VERTICAL|wxLEFT, 5 );
- bSizer242->Add( bSizer243, 0, wxTOP|wxRIGHT|wxLEFT|wxALIGN_CENTER_HORIZONTAL, 5 );
+ bSizer242->Add( bSizer243, 0, wxTOP|wxRIGHT|wxLEFT, 5 );
wxBoxSizer* bSizer246;
bSizer246 = new wxBoxSizer( wxVERTICAL );
@@ -3954,7 +3954,7 @@ BatchDlgGenerated::BatchDlgGenerated( wxWindow* parent, wxWindowID id, const wxS
bSizer246->Add( m_radioBtnErrorDialogCancel, 0, wxBOTTOM|wxRIGHT|wxLEFT|wxEXPAND, 5 );
- bSizer242->Add( bSizer246, 0, wxALIGN_CENTER_HORIZONTAL, 5 );
+ bSizer242->Add( bSizer246, 0, wxALIGN_CENTER_HORIZONTAL|wxLEFT, 15 );
bSizer180->Add( bSizer242, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
@@ -4372,11 +4372,17 @@ OptionsDlgGenerated::OptionsDlgGenerated( wxWindow* parent, wxWindowID id, const
bSizer160->Add( bSizer178, 0, wxEXPAND, 5 );
- bSizer186->Add( bSizer160, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
+ bSizer186->Add( bSizer160, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
m_staticline39 = new wxStaticLine( m_panel39, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_VERTICAL );
bSizer186->Add( m_staticline39, 0, wxEXPAND, 5 );
+ wxBoxSizer* bSizer293;
+ bSizer293 = new wxBoxSizer( wxHORIZONTAL );
+
+ m_bitmapWarnings = new wxStaticBitmap( m_panel39, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0 );
+ bSizer293->Add( m_bitmapWarnings, 0, wxALL, 5 );
+
wxBoxSizer* bSizer1881;
bSizer1881 = new wxBoxSizer( wxVERTICAL );
@@ -4384,13 +4390,26 @@ OptionsDlgGenerated::OptionsDlgGenerated( wxWindow* parent, wxWindowID id, const
m_staticTextResetDialogs->Wrap( -1 );
m_staticTextResetDialogs->SetForegroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_GRAYTEXT ) );
- bSizer1881->Add( m_staticTextResetDialogs, 0, wxTOP|wxRIGHT|wxLEFT, 5 );
+ bSizer1881->Add( m_staticTextResetDialogs, 0, 0, 5 );
+
+ wxBoxSizer* bSizer292;
+ bSizer292 = new wxBoxSizer( wxHORIZONTAL );
+
+ m_buttonRestoreDialogs = new wxButton( m_panel39, wxID_ANY, _("&Restore"), wxDefaultPosition, wxSize( -1, -1 ), 0 );
+ bSizer292->Add( m_buttonRestoreDialogs, 0, wxALIGN_CENTER_VERTICAL, 5 );
+
+ m_staticTextAllDialogsShown = new wxStaticText( m_panel39, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 );
+ m_staticTextAllDialogsShown->Wrap( -1 );
+ bSizer292->Add( m_staticTextAllDialogsShown, 0, wxALIGN_CENTER_VERTICAL|wxLEFT, 5 );
+
+
+ bSizer1881->Add( bSizer292, 0, wxTOP, 5 );
+
- m_buttonResetDialogs = new zen::BitmapTextButton( m_panel39, wxID_ANY, _("dummy"), wxDefaultPosition, wxSize( -1, -1 ), 0 );
- bSizer1881->Add( m_buttonResetDialogs, 0, wxALL, 5 );
+ bSizer293->Add( bSizer1881, 0, wxTOP|wxBOTTOM|wxRIGHT, 5 );
- bSizer186->Add( bSizer1881, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
+ bSizer186->Add( bSizer293, 0, wxALL, 5 );
bSizer166->Add( bSizer186, 0, wxEXPAND, 5 );
@@ -4405,32 +4424,78 @@ OptionsDlgGenerated::OptionsDlgGenerated( wxWindow* parent, wxWindowID id, const
bSizer258 = new wxBoxSizer( wxHORIZONTAL );
m_bitmapLogFile = new wxStaticBitmap( m_panel39, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0 );
- bSizer258->Add( m_bitmapLogFile, 0, wxALIGN_CENTER_VERTICAL, 5 );
+ bSizer258->Add( m_bitmapLogFile, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
m_staticText163 = new wxStaticText( m_panel39, wxID_ANY, _("Default log path:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText163->Wrap( -1 );
- bSizer258->Add( m_staticText163, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5 );
+ bSizer258->Add( m_staticText163, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxRIGHT, 5 );
m_hyperlinkLogFolder = new wxHyperlinkCtrl( m_panel39, wxID_ANY, _("dummy"), wxEmptyString, wxDefaultPosition, wxDefaultSize, wxHL_DEFAULT_STYLE );
- bSizer258->Add( m_hyperlinkLogFolder, 0, wxALIGN_CENTER_VERTICAL|wxLEFT, 5 );
+ bSizer258->Add( m_hyperlinkLogFolder, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxRIGHT, 5 );
- bSizer259->Add( bSizer258, 0, wxALL|wxEXPAND, 5 );
+ bSizer259->Add( bSizer258, 0, wxALL, 5 );
+
+ wxBoxSizer* bSizer299;
+ bSizer299 = new wxBoxSizer( wxVERTICAL );
+
+ m_staticline83 = new wxStaticLine( m_panel39, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
+ bSizer299->Add( m_staticline83, 0, wxEXPAND, 5 );
+
+ wxBoxSizer* bSizer297;
+ bSizer297 = new wxBoxSizer( wxHORIZONTAL );
+
+ m_staticline82 = new wxStaticLine( m_panel39, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_VERTICAL );
+ bSizer297->Add( m_staticline82, 0, wxEXPAND, 5 );
wxBoxSizer* bSizer282;
bSizer282 = new wxBoxSizer( wxHORIZONTAL );
m_checkBoxLogFilesMaxAge = new wxCheckBox( m_panel39, wxID_ANY, _("&Delete logs after x days:"), wxDefaultPosition, wxDefaultSize, 0 );
- bSizer282->Add( m_checkBoxLogFilesMaxAge, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 5 );
+ bSizer282->Add( m_checkBoxLogFilesMaxAge, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
m_spinCtrlLogFilesMaxAge = new wxSpinCtrl( m_panel39, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( -1, -1 ), wxSP_ARROW_KEYS, 1, 2000000000, 1 );
- bSizer282->Add( m_spinCtrlLogFilesMaxAge, 0, wxALIGN_CENTER_VERTICAL, 5 );
+ bSizer282->Add( m_spinCtrlLogFilesMaxAge, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxRIGHT, 5 );
+
+
+ bSizer297->Add( bSizer282, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
+
+ m_staticline81 = new wxStaticLine( m_panel39, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_VERTICAL );
+ bSizer297->Add( m_staticline81, 0, wxEXPAND, 5 );
+
+ wxBoxSizer* bSizer296;
+ bSizer296 = new wxBoxSizer( wxHORIZONTAL );
+
+ m_staticText184 = new wxStaticText( m_panel39, wxID_ANY, _("Log file format:"), wxDefaultPosition, wxDefaultSize, 0 );
+ m_staticText184->Wrap( -1 );
+ bSizer296->Add( m_staticText184, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
+
+ wxFlexGridSizer* fgSizer251;
+ fgSizer251 = new wxFlexGridSizer( 0, 1, 5, 0 );
+ fgSizer251->SetFlexibleDirection( wxBOTH );
+ fgSizer251->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
+ m_radioBtnLogHtml = new wxRadioButton( m_panel39, wxID_ANY, _("&HTML"), wxDefaultPosition, wxDefaultSize, wxRB_GROUP );
+ m_radioBtnLogHtml->SetValue( true );
+ fgSizer251->Add( m_radioBtnLogHtml, 0, wxEXPAND, 5 );
- bSizer259->Add( bSizer282, 0, wxALL, 5 );
+ m_radioBtnLogText = new wxRadioButton( m_panel39, wxID_ANY, _("&Plain text"), wxDefaultPosition, wxDefaultSize, 0 );
+ fgSizer251->Add( m_radioBtnLogText, 0, wxEXPAND, 5 );
- bSizer166->Add( bSizer259, 0, wxALL|wxEXPAND, 5 );
+ bSizer296->Add( fgSizer251, 0, wxTOP|wxBOTTOM|wxRIGHT, 5 );
+
+
+ bSizer297->Add( bSizer296, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
+
+
+ bSizer299->Add( bSizer297, 0, 0, 5 );
+
+
+ bSizer259->Add( bSizer299, 0, wxALIGN_RIGHT|wxLEFT, 15 );
+
+
+ bSizer166->Add( bSizer259, 0, wxEXPAND, 5 );
m_staticline361 = new wxStaticLine( m_panel39, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
bSizer166->Add( m_staticline361, 0, wxEXPAND, 5 );
@@ -4438,33 +4503,38 @@ OptionsDlgGenerated::OptionsDlgGenerated( wxWindow* parent, wxWindowID id, const
wxBoxSizer* bSizer288;
bSizer288 = new wxBoxSizer( wxVERTICAL );
- wxBoxSizer* bSizer291;
- bSizer291 = new wxBoxSizer( wxHORIZONTAL );
+ wxBoxSizer* bSizer300;
+ bSizer300 = new wxBoxSizer( wxHORIZONTAL );
m_bitmapNotificationSounds = new wxStaticBitmap( m_panel39, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0 );
- bSizer291->Add( m_bitmapNotificationSounds, 0, wxALIGN_CENTER_VERTICAL, 5 );
+ bSizer300->Add( m_bitmapNotificationSounds, 0, wxALIGN_CENTER_VERTICAL, 5 );
m_staticText851 = new wxStaticText( m_panel39, wxID_ANY, _("Notification sounds:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText851->Wrap( -1 );
- bSizer291->Add( m_staticText851, 0, wxALIGN_CENTER_VERTICAL|wxLEFT, 5 );
+ bSizer300->Add( m_staticText851, 0, wxALIGN_CENTER_VERTICAL|wxLEFT, 5 );
+
+ bSizer288->Add( bSizer300, 0, wxTOP|wxRIGHT|wxLEFT, 5 );
- bSizer288->Add( bSizer291, 0, wxALL, 5 );
+ wxBoxSizer* bSizer301;
+ bSizer301 = new wxBoxSizer( wxHORIZONTAL );
- ffgSizer11 = new wxFlexGridSizer( 0, 4, 0, 0 );
- ffgSizer11->AddGrowableCol( 3 );
+
+ bSizer301->Add( 15, 0, 0, 0, 5 );
+
+ ffgSizer11 = new wxFlexGridSizer( 0, 3, 0, 5 );
+ ffgSizer11->AddGrowableCol( 2 );
ffgSizer11->SetFlexibleDirection( wxBOTH );
ffgSizer11->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
-
- ffgSizer11->Add( 10, 0, 0, 0, 5 );
+ m_bitmapCompareDone = new wxStaticBitmap( m_panel39, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0 );
+ ffgSizer11->Add( m_bitmapCompareDone, 0, wxALIGN_CENTER_VERTICAL, 5 );
m_staticText171 = new wxStaticText( m_panel39, wxID_ANY, _("Comparison finished:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText171->Wrap( -1 );
- ffgSizer11->Add( m_staticText171, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT, 5 );
+ m_staticText171->SetForegroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_GRAYTEXT ) );
- m_bitmapCompareDone = new wxStaticBitmap( m_panel39, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0 );
- ffgSizer11->Add( m_bitmapCompareDone, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5 );
+ ffgSizer11->Add( m_staticText171, 0, wxALIGN_CENTER_VERTICAL, 5 );
wxBoxSizer* bSizer290;
bSizer290 = new wxBoxSizer( wxHORIZONTAL );
@@ -4483,15 +4553,14 @@ OptionsDlgGenerated::OptionsDlgGenerated( wxWindow* parent, wxWindowID id, const
ffgSizer11->Add( bSizer290, 0, wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 );
-
- ffgSizer11->Add( 0, 0, 0, 0, 5 );
+ m_bitmapSyncDone = new wxStaticBitmap( m_panel39, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0 );
+ ffgSizer11->Add( m_bitmapSyncDone, 0, wxALIGN_CENTER_VERTICAL, 5 );
m_staticText1711 = new wxStaticText( m_panel39, wxID_ANY, _("Synchronization finished:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText1711->Wrap( -1 );
- ffgSizer11->Add( m_staticText1711, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT, 5 );
+ m_staticText1711->SetForegroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_GRAYTEXT ) );
- m_bitmapSyncDone = new wxStaticBitmap( m_panel39, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0 );
- ffgSizer11->Add( m_bitmapSyncDone, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5 );
+ ffgSizer11->Add( m_staticText1711, 0, wxALIGN_CENTER_VERTICAL, 5 );
wxBoxSizer* bSizer2901;
bSizer2901 = new wxBoxSizer( wxHORIZONTAL );
@@ -4511,10 +4580,13 @@ OptionsDlgGenerated::OptionsDlgGenerated( wxWindow* parent, wxWindowID id, const
ffgSizer11->Add( bSizer2901, 0, wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 );
- bSizer288->Add( ffgSizer11, 0, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 );
+ bSizer301->Add( ffgSizer11, 1, wxALL, 5 );
+
+
+ bSizer288->Add( bSizer301, 0, wxEXPAND, 5 );
- bSizer166->Add( bSizer288, 0, wxALL|wxEXPAND, 5 );
+ bSizer166->Add( bSizer288, 0, wxEXPAND|wxALL, 5 );
m_staticline3611 = new wxStaticLine( m_panel39, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
bSizer166->Add( m_staticline3611, 0, wxEXPAND, 5 );
@@ -4680,7 +4752,7 @@ OptionsDlgGenerated::OptionsDlgGenerated( wxWindow* parent, wxWindowID id, const
// Connect Events
this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( OptionsDlgGenerated::OnClose ) );
- m_buttonResetDialogs->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( OptionsDlgGenerated::OnResetDialogs ), NULL, this );
+ m_buttonRestoreDialogs->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( OptionsDlgGenerated::OnRestoreDialogs ), NULL, this );
m_hyperlinkLogFolder->Connect( wxEVT_COMMAND_HYPERLINK, wxHyperlinkEventHandler( OptionsDlgGenerated::OnShowLogFolder ), NULL, this );
m_checkBoxLogFilesMaxAge->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( OptionsDlgGenerated::OnToggleLogfilesLimit ), NULL, this );
m_textCtrlSoundPathCompareDone->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( OptionsDlgGenerated::OnChangeSoundFilePath ), NULL, this );
@@ -4691,7 +4763,7 @@ OptionsDlgGenerated::OptionsDlgGenerated( wxWindow* parent, wxWindowID id, const
m_bpButtonPlaySyncDone->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( OptionsDlgGenerated::OnPlaySyncDone ), NULL, this );
m_bpButtonAddRow->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( OptionsDlgGenerated::OnAddRow ), NULL, this );
m_bpButtonRemoveRow->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( OptionsDlgGenerated::OnRemoveRow ), NULL, this );
- m_hyperlink17->Connect( wxEVT_COMMAND_HYPERLINK, wxHyperlinkEventHandler( OptionsDlgGenerated::OnHelpShowExamples ), NULL, this );
+ m_hyperlink17->Connect( wxEVT_COMMAND_HYPERLINK, wxHyperlinkEventHandler( OptionsDlgGenerated::OnHelpExternalApps ), NULL, this );
m_buttonDefault->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( OptionsDlgGenerated::OnDefault ), NULL, this );
m_buttonOkay->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( OptionsDlgGenerated::OnOkay ), NULL, this );
m_buttonCancel->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( OptionsDlgGenerated::OnCancel ), NULL, this );
diff --git a/FreeFileSync/Source/ui/gui_generated.h b/FreeFileSync/Source/ui/gui_generated.h
index 761dfb15..07867a58 100644
--- a/FreeFileSync/Source/ui/gui_generated.h
+++ b/FreeFileSync/Source/ui/gui_generated.h
@@ -260,8 +260,8 @@ public:
wxPanel* m_panelTopRight;
fff::FolderHistoryBox* m_folderPathRight;
wxBitmapButton* m_bpButtonSelectAltFolderRight;
- wxStaticBitmap* m_bitmapLogStatus;
- wxStaticText* m_staticTextLogStatus;
+ wxStaticBitmap* m_bitmapSyncResult;
+ wxStaticText* m_staticTextSyncResult;
wxStaticText* m_staticTextProcessed;
wxStaticText* m_staticTextRemaining;
wxPanel* m_panelItemStats;
@@ -503,7 +503,7 @@ protected:
virtual void OnToggleAutoRetry( wxCommandEvent& event ) { event.Skip(); }
virtual void OnHelpPerformance( wxHyperlinkEvent& event ) { event.Skip(); }
virtual void OnChangeFilterOption( wxCommandEvent& event ) { event.Skip(); }
- virtual void OnHelpShowExamples( wxHyperlinkEvent& event ) { event.Skip(); }
+ virtual void OnHelpFilterSettings( wxHyperlinkEvent& event ) { event.Skip(); }
virtual void OnFilterReset( wxCommandEvent& event ) { event.Skip(); }
virtual void OnToggleLocalSyncSettings( wxCommandEvent& event ) { event.Skip(); }
virtual void OnSyncTwoWayDouble( wxMouseEvent& event ) { event.Skip(); }
@@ -528,10 +528,11 @@ protected:
virtual void OnHelpVersioning( wxHyperlinkEvent& event ) { event.Skip(); }
virtual void OnChanegVersioningStyle( wxCommandEvent& event ) { event.Skip(); }
virtual void OnToggleVersioningLimit( wxCommandEvent& event ) { event.Skip(); }
- virtual void OnToggleMiscOption( wxCommandEvent& event ) { event.Skip(); }
+ virtual void OnToggleMiscEmail( wxCommandEvent& event ) { event.Skip(); }
virtual void OnEmailAlways( wxCommandEvent& event ) { event.Skip(); }
virtual void OnEmailErrorWarning( wxCommandEvent& event ) { event.Skip(); }
virtual void OnEmailErrorOnly( wxCommandEvent& event ) { event.Skip(); }
+ virtual void OnToggleMiscOption( wxCommandEvent& event ) { event.Skip(); }
virtual void OnOkay( wxCommandEvent& event ) { event.Skip(); }
virtual void OnCancel( wxCommandEvent& event ) { event.Skip(); }
@@ -1025,25 +1026,33 @@ protected:
wxStaticText* m_staticText93;
wxStaticText* m_staticText932;
wxStaticLine* m_staticline39;
+ wxStaticBitmap* m_bitmapWarnings;
wxStaticText* m_staticTextResetDialogs;
- zen::BitmapTextButton* m_buttonResetDialogs;
+ wxButton* m_buttonRestoreDialogs;
+ wxStaticText* m_staticTextAllDialogsShown;
wxStaticLine* m_staticline191;
wxStaticBitmap* m_bitmapLogFile;
wxStaticText* m_staticText163;
wxHyperlinkCtrl* m_hyperlinkLogFolder;
+ wxStaticLine* m_staticline83;
+ wxStaticLine* m_staticline82;
wxCheckBox* m_checkBoxLogFilesMaxAge;
wxSpinCtrl* m_spinCtrlLogFilesMaxAge;
+ wxStaticLine* m_staticline81;
+ wxStaticText* m_staticText184;
+ wxRadioButton* m_radioBtnLogHtml;
+ wxRadioButton* m_radioBtnLogText;
wxStaticLine* m_staticline361;
wxStaticBitmap* m_bitmapNotificationSounds;
wxStaticText* m_staticText851;
wxFlexGridSizer* ffgSizer11;
- wxStaticText* m_staticText171;
wxStaticBitmap* m_bitmapCompareDone;
+ wxStaticText* m_staticText171;
wxTextCtrl* m_textCtrlSoundPathCompareDone;
wxButton* m_buttonSelectSoundCompareDone;
wxBitmapButton* m_bpButtonPlayCompareDone;
- wxStaticText* m_staticText1711;
wxStaticBitmap* m_bitmapSyncDone;
+ wxStaticText* m_staticText1711;
wxTextCtrl* m_textCtrlSoundPathSyncDone;
wxButton* m_buttonSelectSoundSyncDone;
wxBitmapButton* m_bpButtonPlaySyncDone;
@@ -1069,7 +1078,7 @@ protected:
// Virtual event handlers, overide them in your derived class
virtual void OnClose( wxCloseEvent& event ) { event.Skip(); }
- virtual void OnResetDialogs( wxCommandEvent& event ) { event.Skip(); }
+ virtual void OnRestoreDialogs( wxCommandEvent& event ) { event.Skip(); }
virtual void OnShowLogFolder( wxHyperlinkEvent& event ) { event.Skip(); }
virtual void OnToggleLogfilesLimit( wxCommandEvent& event ) { event.Skip(); }
virtual void OnChangeSoundFilePath( wxCommandEvent& event ) { event.Skip(); }
@@ -1079,7 +1088,7 @@ protected:
virtual void OnPlaySyncDone( wxCommandEvent& event ) { event.Skip(); }
virtual void OnAddRow( wxCommandEvent& event ) { event.Skip(); }
virtual void OnRemoveRow( wxCommandEvent& event ) { event.Skip(); }
- virtual void OnHelpShowExamples( wxHyperlinkEvent& event ) { event.Skip(); }
+ virtual void OnHelpExternalApps( wxHyperlinkEvent& event ) { event.Skip(); }
virtual void OnDefault( wxCommandEvent& event ) { event.Skip(); }
virtual void OnOkay( wxCommandEvent& event ) { event.Skip(); }
virtual void OnCancel( wxCommandEvent& event ) { event.Skip(); }
diff --git a/FreeFileSync/Source/ui/gui_status_handler.cpp b/FreeFileSync/Source/ui/gui_status_handler.cpp
index 8adf1f89..6ad01cd2 100644
--- a/FreeFileSync/Source/ui/gui_status_handler.cpp
+++ b/FreeFileSync/Source/ui/gui_status_handler.cpp
@@ -11,9 +11,9 @@
#include <wx/wupdlock.h>
#include <wx+/popup_dlg.h>
#include "main_dlg.h"
-#include "../base/log_file.h"
-#include "../base/resolve_path.h"
#include "../afs/concrete.h"
+#include "../base/resolve_path.h"
+#include "../log_file.h"
using namespace zen;
using namespace fff;
@@ -148,9 +148,11 @@ StatusHandlerTemporaryPanel::Result StatusHandlerTemporaryPanel::reportResults()
errorLog_.logMsg(_("Stopped"), MSG_TYPE_ERROR); //= user cancel; *not* a MSG_TYPE_FATAL_ERROR!
return SyncResult::aborted;
}
- else if (errorLog_.getItemCount(MSG_TYPE_ERROR | MSG_TYPE_FATAL_ERROR) > 0)
+
+ const ErrorLog::Stats logCount = errorLog_.getStats();
+ if (logCount.error + logCount.fatal > 0)
return SyncResult::finishedError;
- else if (errorLog_.getItemCount(MSG_TYPE_WARNING) > 0)
+ else if (logCount.warning > 0)
return SyncResult::finishedWarning;
else
return SyncResult::finishedSuccess;
@@ -228,7 +230,7 @@ ProcessCallback::Response StatusHandlerTemporaryPanel::reportError(const std::ws
if (retryNumber < automaticRetryCount_)
{
errorLog_.logMsg(msg + L"\n-> " + _("Automatic retry"), MSG_TYPE_INFO);
- delayAndCountDown(_("Automatic retry") + (automaticRetryCount_ <= 1 ? L"" : L" " + numberTo<std::wstring>(retryNumber + 1) + L"/" + numberTo<std::wstring>(automaticRetryCount_)),
+ delayAndCountDown(_("Automatic retry") + (automaticRetryCount_ <= 1 ? L"" : L' ' + numberTo<std::wstring>(retryNumber + 1) + L"/" + numberTo<std::wstring>(automaticRetryCount_)),
automaticRetryDelay_, [&](const std::wstring& statusMsg) { this->updateStatus(_("Error") + L": " + statusMsg); }); //throw AbortProcess
return ProcessCallback::retry;
}
@@ -354,8 +356,9 @@ StatusHandlerFloatingDialog::~StatusHandlerFloatingDialog()
StatusHandlerFloatingDialog::Result StatusHandlerFloatingDialog::reportResults(const Zstring& postSyncCommand, PostSyncCondition postSyncCondition,
- const Zstring& altLogFolderPathPhrase, int logfilesMaxAgeDays, const std::set<AbstractPath>& logFilePathsToKeep,
- const Zstring& emailNotifyAddress, ResultsNotification emailNotifyCondition)
+ const Zstring& altLogFolderPathPhrase, int logfilesMaxAgeDays, LogFileFormat logFormat,
+ const std::set<AbstractPath>& logFilePathsToKeep,
+ const std::string& emailNotifyAddress, ResultsNotification emailNotifyCondition)
{
const auto totalTime = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - startTime_);
@@ -369,9 +372,11 @@ StatusHandlerFloatingDialog::Result StatusHandlerFloatingDialog::reportResults(c
errorLog_.logMsg(_("Stopped"), MSG_TYPE_ERROR); //= user cancel; *not* a MSG_TYPE_FATAL_ERROR!
return SyncResult::aborted;
}
- else if (errorLog_.getItemCount(MSG_TYPE_ERROR | MSG_TYPE_FATAL_ERROR) > 0)
+
+ const ErrorLog::Stats logCount = errorLog_.getStats();
+ if (logCount.error + logCount.fatal > 0)
return SyncResult::finishedError;
- else if (errorLog_.getItemCount(MSG_TYPE_WARNING) > 0)
+ else if (logCount.warning > 0)
return SyncResult::finishedWarning;
if (getStatsTotal() == ProgressStats())
@@ -389,7 +394,7 @@ StatusHandlerFloatingDialog::Result StatusHandlerFloatingDialog::reportResults(c
totalTime
};
- const AbstractPath logFilePath = generateLogFilePath(summary, altLogFolderPathPhrase);
+ const AbstractPath logFilePath = generateLogFilePath(logFormat, summary, altLogFolderPathPhrase);
//e.g. %AppData%\FreeFileSync\Logs\Backup FreeFileSync 2013-09-15 015052.123 [Error].log
if (const Zstring cmdLine = trimCpy(postSyncCommand);
@@ -406,9 +411,8 @@ StatusHandlerFloatingDialog::Result StatusHandlerFloatingDialog::reportResults(c
//::wxSetEnv(L"logfile_path", AFS::getDisplayPath(logFilePath));
////----------------------------------------------------------------------
const Zstring cmdLineExp = expandMacros(cmdLine);
- const int exitCode = shellExecute(cmdLineExp, ExecutionType::sync, false /*hideConsole*/); //throw FileError
- errorLog_.logMsg(_("Executing command:") + L" " + utfTo<std::wstring>(cmdLineExp) + L" [" + replaceCpy(_("Exit Code %x"), L"%x", numberTo<std::wstring>(exitCode)) + L']',
- exitCode == 0 ? MSG_TYPE_INFO : MSG_TYPE_ERROR);
+ errorLog_.logMsg(_("Executing command:") + L' ' + utfTo<std::wstring>(cmdLineExp), MSG_TYPE_INFO);
+ shellExecute(cmdLineExp, ExecutionType::async, false /*hideConsole*/); //throw FileError
}
catch (const FileError& e) { errorLog_.logMsg(e.toString(), MSG_TYPE_ERROR); }
}
@@ -416,7 +420,7 @@ StatusHandlerFloatingDialog::Result StatusHandlerFloatingDialog::reportResults(c
//---------------------------- save log file ------------------------------
auto notifyStatusNoThrow = [&](const std::wstring& msg) { try { updateStatus(msg); /*throw AbortProcess*/ } catch (AbortProcess&) {} };
- if (const Zstring notifyEmail = trimCpy(emailNotifyAddress);
+ if (const std::string notifyEmail = trimCpy(emailNotifyAddress);
!notifyEmail.empty())
{
if (getAbortStatus() && *getAbortStatus() == AbortTrigger::user)
@@ -437,7 +441,7 @@ StatusHandlerFloatingDialog::Result StatusHandlerFloatingDialog::reportResults(c
try //create not before destruction: 1. avoid issues with FFS trying to sync open log file 2. include status in log file name without extra rename
{
//do NOT use tryReportingError()! saving log files should not be cancellable!
- saveLogFile(logFilePath, summary, errorLog_, logfilesMaxAgeDays, logFilePathsToKeep, notifyStatusNoThrow); //throw FileError
+ saveLogFile(logFilePath, summary, errorLog_, logfilesMaxAgeDays, logFormat, logFilePathsToKeep, notifyStatusNoThrow); //throw FileError
}
catch (const FileError& e) { errorLog_.logMsg(e.toString(), MSG_TYPE_ERROR); }
@@ -566,7 +570,7 @@ ProcessCallback::Response StatusHandlerFloatingDialog::reportError(const std::ws
if (retryNumber < automaticRetryCount_)
{
errorLog_.logMsg(msg + L"\n-> " + _("Automatic retry"), MSG_TYPE_INFO);
- delayAndCountDown(_("Automatic retry") + (automaticRetryCount_ <= 1 ? L"" : L" " + numberTo<std::wstring>(retryNumber + 1) + L"/" + numberTo<std::wstring>(automaticRetryCount_)),
+ delayAndCountDown(_("Automatic retry") + (automaticRetryCount_ <= 1 ? L"" : L' ' + numberTo<std::wstring>(retryNumber + 1) + L"/" + numberTo<std::wstring>(automaticRetryCount_)),
automaticRetryDelay_, [&](const std::wstring& statusMsg) { this->updateStatus(_("Error") + L": " + statusMsg); }); //throw AbortProcess
return ProcessCallback::retry;
}
diff --git a/FreeFileSync/Source/ui/gui_status_handler.h b/FreeFileSync/Source/ui/gui_status_handler.h
index 82903078..5f671a82 100644
--- a/FreeFileSync/Source/ui/gui_status_handler.h
+++ b/FreeFileSync/Source/ui/gui_status_handler.h
@@ -11,7 +11,7 @@
#include <wx/event.h>
#include "progress_indicator.h"
#include "main_dlg.h"
-#include "../base/status_handler.h"
+#include "../status_handler.h"
namespace fff
@@ -92,8 +92,8 @@ public:
AbstractPath logFilePath;
};
Result reportResults(const Zstring& postSyncCommand, PostSyncCondition postSyncCondition,
- const Zstring& altLogFolderPathPhrase, int logfilesMaxAgeDays, const std::set<AbstractPath>& logFilePathsToKeep,
- const Zstring& emailNotifyAddress, ResultsNotification emailNotifyCondition); //noexcept!!
+ const Zstring& altLogFolderPathPhrase, int logfilesMaxAgeDays, LogFileFormat logFormat, const std::set<AbstractPath>& logFilePathsToKeep,
+ const std::string& emailNotifyAddress, ResultsNotification emailNotifyCondition); //noexcept!!
private:
SyncProgressDialog* progressDlg_; //managed to have the same lifetime as this handler!
diff --git a/FreeFileSync/Source/ui/log_panel.cpp b/FreeFileSync/Source/ui/log_panel.cpp
index 51cfa703..52322dc9 100644
--- a/FreeFileSync/Source/ui/log_panel.cpp
+++ b/FreeFileSync/Source/ui/log_panel.cpp
@@ -62,7 +62,7 @@ public:
{
time_t time = 0;
MessageType type = MSG_TYPE_INFO;
- Zstringw messageLine;
+ std::string_view messageLine;
bool firstLine = false; //if LogEntry::message spans multiple rows
};
@@ -73,10 +73,10 @@ public:
const Line& line = viewRef_[row];
LogEntryView output;
- output.time = line.logIt_->time;
- output.type = line.logIt_->type;
- output.messageLine = extractLine(line.logIt_->message, line.rowNumber_);
- output.firstLine = line.rowNumber_ == 0; //this is virtually always correct, unless first line of the original message is empty!
+ output.time = line.logIt->time;
+ output.type = line.logIt->type;
+ output.messageLine = extractLine(line.logIt->message, line.row);
+ output.firstLine = line.row == 0; //this is virtually always correct, unless first line of the original message is empty!
return output;
}
return {};
@@ -89,13 +89,12 @@ public:
for (auto it = log_.ref().begin(); it != log_.ref().end(); ++it)
if (it->type & includedTypes)
{
- static_assert(std::is_same_v<GetCharTypeT<Zstringw>, wchar_t>);
- assert(!startsWith(it->message, L'\n'));
+ assert(!startsWith(it->message, '\n'));
size_t rowNumber = 0;
bool lastCharNewline = true;
- for (const wchar_t c : it->message)
- if (c == L'\n')
+ for (const char c : it->message)
+ if (c == '\n')
{
if (!lastCharNewline) //do not reference empty lines!
viewRef_.emplace_back(it, rowNumber);
@@ -111,19 +110,19 @@ public:
}
private:
- static Zstringw extractLine(const Zstringw& message, size_t textRow)
+ static std::string_view extractLine(const Zstringc& message, size_t textRow)
{
auto it1 = message.begin();
for (;;)
{
- auto it2 = std::find_if(it1, message.end(), [](wchar_t c) { return c == L'\n'; });
+ auto it2 = std::find_if(it1, message.end(), [](char c) { return c == '\n'; });
if (textRow == 0)
- return it1 == message.end() ? Zstringw() : Zstringw(&*it1, it2 - it1); //must not dereference iterator pointing to "end"!
+ return makeStringView(it1, it2 - it1);
if (it2 == message.end())
{
assert(false);
- return Zstringw();
+ return makeStringView(it1, 0);
}
it1 = it2 + 1; //skip newline
@@ -133,10 +132,10 @@ private:
struct Line
{
- Line(ErrorLog::const_iterator logIt, size_t rowNumber) : logIt_(logIt), rowNumber_(rowNumber) {}
+ Line(ErrorLog::const_iterator it, size_t rowNum) : logIt(it), row(rowNum) {}
- ErrorLog::const_iterator logIt_; //always bound!
- size_t rowNumber_; //LogEntry::message may span multiple rows
+ ErrorLog::const_iterator logIt; //always bound!
+ size_t row; //LogEntry::message may span multiple rows
};
std::vector<Line> viewRef_; //partial view on log_
@@ -161,12 +160,12 @@ public:
std::wstring getValue(size_t row, ColumnType colType) const override
{
- if (std::optional<MessageView::LogEntryView> entry = msgView_.getEntry(row))
+ if (const std::optional<MessageView::LogEntryView> entry = msgView_.getEntry(row))
switch (static_cast<ColumnTypeLog>(colType))
{
case ColumnTypeLog::time:
if (entry->firstLine)
- return formatTime<std::wstring>(FORMAT_TIME, getLocalTime(entry->time));
+ return utfTo<std::wstring>(formatTime(formatTimeTag, getLocalTime(entry->time)));
break;
case ColumnTypeLog::category:
@@ -185,7 +184,7 @@ public:
break;
case ColumnTypeLog::text:
- return copyStringTo<std::wstring>(entry->messageLine);
+ return utfTo<std::wstring>(entry->messageLine);
}
return std::wstring();
}
@@ -277,7 +276,7 @@ public:
{
wxClientDC dc(&grid.getMainWin());
dc.SetFont(grid.getMainWin().GetFont());
- return 2 * getColumnGapLeft() + dc.GetTextExtent(formatTime<wxString>(FORMAT_TIME)).GetWidth();
+ return 2 * getColumnGapLeft() + dc.GetTextExtent(utfTo<wxString>(formatTime(formatTimeTag))).GetWidth();
}
static int getColumnCategoryDefaultWidth()
@@ -353,9 +352,7 @@ void LogPanel::setLog(const std::shared_ptr<const ErrorLog>& log)
return makeSharedRef<const ErrorLog>(std::move(dummyLog));
}();
- const int errorCount = newLog.ref().getItemCount(MSG_TYPE_ERROR | MSG_TYPE_FATAL_ERROR);
- const int warningCount = newLog.ref().getItemCount(MSG_TYPE_WARNING);
- const int infoCount = newLog.ref().getItemCount(MSG_TYPE_INFO);
+ const ErrorLog::Stats logCount = newLog.ref().getStats();
auto initButton = [](ToggleButton& btn, const wchar_t* imgName, const wxString& tooltip)
{
@@ -363,17 +360,17 @@ void LogPanel::setLog(const std::shared_ptr<const ErrorLog>& log)
btn.SetToolTip(tooltip);
};
- initButton(*m_bpButtonErrors, L"msg_error", _("Error" ) + L" (" + formatNumber(errorCount) + L")");
- initButton(*m_bpButtonWarnings, L"msg_warning", _("Warning") + L" (" + formatNumber(warningCount) + L")");
- initButton(*m_bpButtonInfo, L"msg_info", _("Info" ) + L" (" + formatNumber(infoCount) + L")");
+ initButton(*m_bpButtonErrors, L"msg_error", _("Error" ) + L" (" + formatNumber(logCount.error + logCount.fatal) + L")");
+ initButton(*m_bpButtonWarnings, L"msg_warning", _("Warning") + L" (" + formatNumber(logCount.warning ) + L")");
+ initButton(*m_bpButtonInfo, L"msg_info", _("Info" ) + L" (" + formatNumber(logCount.info ) + L")");
m_bpButtonErrors ->setActive(true);
m_bpButtonWarnings->setActive(true);
- m_bpButtonInfo ->setActive(errorCount + warningCount == 0);
+ m_bpButtonInfo ->setActive(logCount.warning + logCount.error + logCount.fatal == 0);
- m_bpButtonErrors ->Show(errorCount != 0);
- m_bpButtonWarnings->Show(warningCount != 0);
- m_bpButtonInfo ->Show(infoCount != 0);
+ m_bpButtonErrors ->Show(logCount.error + logCount.fatal != 0);
+ m_bpButtonWarnings->Show(logCount.warning != 0);
+ m_bpButtonInfo ->Show(logCount.info != 0);
m_gridMessages->setDataProvider(std::make_shared<GridDataMessages>(newLog));
@@ -385,7 +382,7 @@ MessageView& LogPanel::getDataView()
{
if (auto* prov = dynamic_cast<GridDataMessages*>(m_gridMessages->getDataProvider()))
return prov->getDataView();
- throw std::runtime_error(std::string(__FILE__) + "[" + numberTo<std::string>(__LINE__) + "] m_gridMessages was not initialized.");
+ throw std::runtime_error(std::string(__FILE__) + '[' + numberTo<std::string>(__LINE__) + "] m_gridMessages was not initialized.");
}
@@ -540,7 +537,7 @@ void LogPanel::copySelectionToClipboard()
{
try
{
- Zstringw clipboardString; //guaranteed exponential growth, unlike wxString
+ std::wstring clipBuf; //guaranteed exponential growth, unlike wxString
if (auto prov = m_gridMessages->getDataProvider())
{
@@ -552,24 +549,24 @@ void LogPanel::copySelectionToClipboard()
std::for_each(colAttr.begin(), --colAttr.end(),
[&](const Grid::ColAttributes& ca)
{
- clipboardString += copyStringTo<Zstringw>(prov->getValue(row, ca.type));
- clipboardString += L'\t';
+ clipBuf += prov->getValue(row, ca.type);
+ clipBuf += L'\t';
});
- clipboardString += copyStringTo<Zstringw>(prov->getValue(row, colAttr.back().type));
- clipboardString += L'\n';
+ clipBuf += prov->getValue(row, colAttr.back().type);
+ clipBuf += L'\n';
}
}
//finally write to clipboard
- if (!clipboardString.empty())
+ if (!clipBuf.empty())
if (wxClipboard::Get()->Open())
{
ZEN_ON_SCOPE_EXIT(wxClipboard::Get()->Close());
- wxClipboard::Get()->SetData(new wxTextDataObject(copyStringTo<wxString>(clipboardString))); //ownership passed
+ wxClipboard::Get()->SetData(new wxTextDataObject(std::move(clipBuf))); //ownership passed
}
}
catch (const std::bad_alloc& e)
{
- showNotificationDialog(nullptr, DialogInfoType::error, PopupDialogCfg().setMainInstructions(_("Out of memory.") + L" " + utfTo<std::wstring>(e.what())));
+ showNotificationDialog(nullptr, DialogInfoType::error, PopupDialogCfg().setMainInstructions(_("Out of memory.") + L' ' + utfTo<std::wstring>(e.what())));
}
}
diff --git a/FreeFileSync/Source/ui/main_dlg.cpp b/FreeFileSync/Source/ui/main_dlg.cpp
index d6fb64d4..4dcad8b3 100644
--- a/FreeFileSync/Source/ui/main_dlg.cpp
+++ b/FreeFileSync/Source/ui/main_dlg.cpp
@@ -44,10 +44,10 @@
#include "../base/synchronization.h"
#include "../base/algorithm.h"
#include "../base/resolve_path.h"
-#include "../base/ffs_paths.h"
-#include "../base/help_provider.h"
#include "../base/lock_holder.h"
-#include "../base/localization.h"
+#include "../ffs_paths.h"
+#include "../help_provider.h"
+#include "../localization.h"
#include "../version/version.h"
using namespace zen;
@@ -82,8 +82,8 @@ bool acceptDialogFileDrop(const std::vector<Zstring>& shellItemPaths)
return std::any_of(shellItemPaths.begin(), shellItemPaths.end(), [](const Zstring& shellItemPath)
{
const Zstring ext = getFileExtension(shellItemPath);
- return equalAsciiNoCase(ext, Zstr("ffs_gui")) ||
- equalAsciiNoCase(ext, Zstr("ffs_batch"));
+ return equalAsciiNoCase(ext, "ffs_gui") ||
+ equalAsciiNoCase(ext, "ffs_batch");
});
}
@@ -324,8 +324,8 @@ void MainDialog::create(const Zstring& globalConfigFilePath)
//add default exclusion filter: this is only ever relevant when creating new configurations!
//a default XmlGuiConfig does not need these user-specific exclusions!
Zstring& excludeFilter = guiCfg.mainCfg.globalFilter.excludeFilter;
- if (!excludeFilter.empty() && !endsWith(excludeFilter, Zstr("\n")))
- excludeFilter += Zstr("\n");
+ if (!excludeFilter.empty() && !endsWith(excludeFilter, Zstr('\n')))
+ excludeFilter += Zstr('\n');
excludeFilter += globalSettings.gui.defaultExclusionFilter;
if (!cfgFilePaths.empty())
@@ -463,7 +463,7 @@ MainDialog::MainDialog(const Zstring& globalConfigFilePath,
const wxBitmap& bmpDir = IconBuffer::genericDirIcon (IconBuffer::SIZE_SMALL);
//init log panel
- setRelativeFontSize(*m_staticTextLogStatus, 1.5);
+ setRelativeFontSize(*m_staticTextSyncResult, 1.5);
const wxBitmap& bmpTime = getResourceImage(L"cmp_file_time_sicon");
m_bitmapItemStat->SetBitmap(bmpFile);
m_bitmapTimeStat->SetBitmap(bmpTime);
@@ -701,7 +701,7 @@ MainDialog::MainDialog(const Zstring& globalConfigFilePath,
menu->Append(newItem); //pass ownership
const std::wstring blackStar = utfTo<std::wstring>("\xE2\x98\x85"); //"BLACK STAR"
- m_menubar->Append(menu, blackStar + L" " + replaceCpy(_("FreeFileSync %x is available!"), L"%x", utfTo<std::wstring>(globalSettings.gui.lastOnlineVersion)) + L" " + blackStar);
+ m_menubar->Append(menu, blackStar + L' ' + replaceCpy(_("FreeFileSync %x is available!"), L"%x", utfTo<std::wstring>(globalSettings.gui.lastOnlineVersion)) + L' ' + blackStar);
}
@@ -1246,7 +1246,7 @@ void MainDialog::copySelectionToClipboard(const std::vector<const Grid*>& gridRe
try
{
//perf: wxString doesn't model exponential growth and is unsuitable for large data sets
- Zstringw clipboardString;
+ std::wstring clipBuf;
for (const Grid* grid : gridRefs)
if (auto prov = grid->getDataProvider())
@@ -1258,23 +1258,24 @@ void MainDialog::copySelectionToClipboard(const std::vector<const Grid*>& gridRe
{
std::for_each(colAttr.begin(), colAttr.end() - 1, [&](const Grid::ColAttributes& ca)
{
- clipboardString += copyStringTo<Zstringw>(prov->getValue(row, ca.type));
- clipboardString += L'\t';
+ clipBuf += prov->getValue(row, ca.type);
+ clipBuf += L'\t';
});
- clipboardString += copyStringTo<Zstringw>(prov->getValue(row, colAttr.back().type));
- clipboardString += L'\n';
+ clipBuf += prov->getValue(row, colAttr.back().type);
+ clipBuf += L'\n';
}
}
- if (wxClipboard::Get()->Open())
- {
- ZEN_ON_SCOPE_EXIT(wxClipboard::Get()->Close());
- wxClipboard::Get()->SetData(new wxTextDataObject(copyStringTo<wxString>(clipboardString))); //ownership passed
- }
+ if (!clipBuf.empty())
+ if (wxClipboard::Get()->Open())
+ {
+ ZEN_ON_SCOPE_EXIT(wxClipboard::Get()->Close());
+ wxClipboard::Get()->SetData(new wxTextDataObject(std::move(clipBuf))); //ownership passed
+ }
}
catch (const std::bad_alloc& e)
{
- showNotificationDialog(this, DialogInfoType::error, PopupDialogCfg().setMainInstructions(_("Out of memory.") + L" " + utfTo<std::wstring>(e.what())));
+ showNotificationDialog(this, DialogInfoType::error, PopupDialogCfg().setMainInstructions(_("Out of memory.") + L' ' + utfTo<std::wstring>(e.what())));
}
}
@@ -2403,7 +2404,7 @@ void MainDialog::onMainGridContextRim(bool leftSide, GridClickEvent& event)
//translate default external apps on the fly: 1. "open in explorer" 2. "start directly"
wxString description = translate(it->description);
if (description.empty())
- description = L" "; //wxWidgets doesn't like empty labels
+ description = L' '; //wxWidgets doesn't like empty labels
auto openApp = [this, command = it->cmdLine, leftSide, &selectionLeft, &selectionRight] { openExternalApplication(command, leftSide, selectionLeft, selectionRight); };
@@ -2450,7 +2451,7 @@ void MainDialog::addFilterPhrase(const Zstring& phrase, bool include, bool requi
{
trim(filterString, false, true, [](Zchar c) { return c == FILTER_ITEM_SEPARATOR || c == Zstr('\n') || c == Zstr(' '); });
if (!filterString.empty())
- filterString += Zstr("\n");
+ filterString += Zstr('\n');
filterString += phrase;
}
else
@@ -2460,9 +2461,9 @@ void MainDialog::addFilterPhrase(const Zstring& phrase, bool include, bool requi
if (filterString.empty())
;
else if (endsWith(filterString, FILTER_ITEM_SEPARATOR))
- filterString += Zstr(" ");
+ filterString += Zstr(' ');
else
- filterString += Zstr("\n");
+ filterString += Zstr('\n');
filterString += phrase + Zstr(' ') + FILTER_ITEM_SEPARATOR; //append FILTER_ITEM_SEPARATOR to 'mark' that next extension exclude should write to same line
}
@@ -2506,7 +2507,7 @@ void MainDialog::filterItems(const std::vector<FileSystemObject*>& selection, bo
FileSystemObject* fsObj = *it;
if (it != selection.begin())
- phrase += Zstr("\n");
+ phrase += Zstr('\n');
//#pragma warning(suppress: 6011) -> fsObj bound in this context!
phrase += FILE_NAME_SEPARATOR + fsObj->getRelativePathAny();
@@ -2832,7 +2833,7 @@ void MainDialog::updateUnsavedCfgStatus()
std::vector<std::wstring> jobNames;
for (const Zstring& cfgFilePath : activeConfigFiles_)
jobNames.push_back(equalNativePath(cfgFilePath, lastRunConfigPath_) ?
- L"[" + _("Last session") + L"]" :
+ L'[' + _("Last session") + L']' :
extractJobName(cfgFilePath));
const bool haveUnsavedCfg = lastSavedCfg_ != getConfig();
@@ -3181,8 +3182,8 @@ bool MainDialog::loadConfiguration(const std::vector<Zstring>& filePaths)
//add default exclusion filter: this is only ever relevant when creating new configurations!
//a default XmlGuiConfig does not need these user-specific exclusions!
Zstring& excludeFilter = newGuiCfg.mainCfg.globalFilter.excludeFilter;
- if (!excludeFilter.empty() && !endsWith(excludeFilter, Zstr("\n")))
- excludeFilter += Zstr("\n");
+ if (!excludeFilter.empty() && !endsWith(excludeFilter, Zstr('\n')))
+ excludeFilter += Zstr('\n');
excludeFilter += globalCfg_.gui.defaultExclusionFilter;
if (!filePaths.empty()) //empty cfg file list means "use default"
@@ -3886,7 +3887,7 @@ void MainDialog::OnCompare(wxCommandEvent& event)
m_gridOverview->clearSelection(GridEventPolicy::ALLOW);
//play (optional) sound notification
- if (!globalCfg_.soundFileCompareFinished.empty() && fileAvailable(globalCfg_.soundFileCompareFinished))
+ if (!globalCfg_.soundFileCompareFinished.empty())
{
//wxWidgets shows modal error dialog by default => NO!
wxLog* oldLogTarget = wxLog::SetActiveTarget(new wxLogStderr); //transfer and receive ownership!
@@ -4052,7 +4053,7 @@ void MainDialog::OnStartSync(wxCommandEvent& event)
std::vector<std::wstring> jobNames;
for (const Zstring& cfgFilePath : activeConfigFiles_)
jobNames.push_back(equalNativePath(cfgFilePath, lastRunConfigPath_) ?
- L"[" + _("Last session") + L"]" :
+ L'[' + _("Last session") + L']' :
extractJobName(cfgFilePath));
using FinalRequest = StatusHandlerFloatingDialog::FinalRequest;
@@ -4112,7 +4113,7 @@ void MainDialog::OnStartSync(wxCommandEvent& event)
catch (AbortProcess&) {}
StatusHandlerFloatingDialog::Result r = statusHandler.reportResults(guiCfg.mainCfg.postSyncCommand, guiCfg.mainCfg.postSyncCondition,
- guiCfg.mainCfg.altLogFolderPathPhrase, globalCfg_.logfilesMaxAgeDays, logFilePathsToKeep,
+ guiCfg.mainCfg.altLogFolderPathPhrase, globalCfg_.logfilesMaxAgeDays, globalCfg_.logFormat, logFilePathsToKeep,
guiCfg.mainCfg.emailNotifyAddress, guiCfg.mainCfg.emailNotifyCondition); //noexcept
//---------------------------------------------------------------------------
@@ -4320,7 +4321,7 @@ void MainDialog::updateConfigLastRunStats(time_t lastRunTime, SyncResult result,
void MainDialog::setLastOperationLog(const ProcessSummary& summary, const std::shared_ptr<const zen::ErrorLog>& errorLog)
{
- const wxBitmap statusImage = [&]
+ const wxBitmap syncResultImage = [&]
{
switch (summary.resultStatus)
{
@@ -4336,23 +4337,22 @@ void MainDialog::setLastOperationLog(const ProcessSummary& summary, const std::s
return wxNullBitmap;
}();
- const wxImage statusOverlayImage = [&]
+ const wxImage logOverlayImage = [&]
{
- switch (summary.resultStatus)
+ //don't use "resultStatus": There may be errors after sync, e.g. failure to save log file/send email!
+ if (errorLog)
{
- case SyncResult::finishedSuccess:
- break;
- case SyncResult::finishedWarning:
- return getResourceImage(L"msg_warning_sicon").ConvertToImage();
- case SyncResult::finishedError:
- case SyncResult::aborted:
+ const ErrorLog::Stats logCount = errorLog->getStats();
+ if (logCount.error + logCount.fatal > 0)
return getResourceImage(L"msg_error_sicon").ConvertToImage();
+ if (logCount.warning > 0)
+ return getResourceImage(L"msg_warning_sicon").ConvertToImage();
}
return wxNullImage;
}();
- m_bitmapLogStatus->SetBitmap(statusImage);
- m_staticTextLogStatus->SetLabel(getResultsStatusLabel(summary.resultStatus));
+ m_bitmapSyncResult->SetBitmap(syncResultImage);
+ m_staticTextSyncResult->SetLabel(getSyncResultLabel(summary.resultStatus));
m_staticTextItemsProcessed->SetLabel(formatNumber(summary.statsProcessed.items));
@@ -4383,7 +4383,7 @@ void MainDialog::setLastOperationLog(const ProcessSummary& summary, const std::s
//m_panelItemStats->Layout(); //needed?
//m_panelTimeStats->Layout(); //
- setImage(*m_bpButtonShowLog, layOver(getResourceImage(L"log_file").ConvertToImage(), statusOverlayImage, wxALIGN_BOTTOM | wxALIGN_RIGHT));
+ setImage(*m_bpButtonShowLog, layOver(getResourceImage(L"log_file").ConvertToImage(), logOverlayImage, wxALIGN_BOTTOM | wxALIGN_RIGHT));
m_bpButtonShowLog->Show(static_cast<bool>(errorLog));
}
@@ -5425,7 +5425,7 @@ void MainDialog::OnMenuExportFileList(wxCommandEvent& event)
//write file
FileOutput fileOut(FileOutput::ACC_OVERWRITE, filePath, nullptr /*notifyUnbufferedIO*/); //throw FileError
- fileOut.write(&*header.begin(), header.size()); //throw FileError, (X)
+ fileOut.write(&header[0], header.size()); //throw FileError, (X)
//main grid: write rows one after the other instead of creating one big string: memory allocation might fail; think 1 million rows!
/*
performance test case "export 600.000 rows" to CSV:
diff --git a/FreeFileSync/Source/ui/main_dlg.h b/FreeFileSync/Source/ui/main_dlg.h
index a18a3223..ceef4712 100644
--- a/FreeFileSync/Source/ui/main_dlg.h
+++ b/FreeFileSync/Source/ui/main_dlg.h
@@ -18,10 +18,10 @@
#include "sync_cfg.h"
#include "log_panel.h"
#include "folder_history_box.h"
-#include "../base/status_handler.h"
+#include "../config.h"
+#include "../status_handler.h"
#include "../base/algorithm.h"
-#include "../base/return_codes.h"
-
+#include "../return_codes.h"
namespace fff
{
diff --git a/FreeFileSync/Source/ui/progress_indicator.cpp b/FreeFileSync/Source/ui/progress_indicator.cpp
index 8cb37ee5..04c20716 100644
--- a/FreeFileSync/Source/ui/progress_indicator.cpp
+++ b/FreeFileSync/Source/ui/progress_indicator.cpp
@@ -24,13 +24,13 @@
#include <zen/perf.h>
#include <wx+/choice_enum.h>
#include "gui_generated.h"
-#include "../base/ffs_paths.h"
-#include "../base/perf_check.h"
-#include "../base/icon_buffer.h"
#include "tray_icon.h"
#include "taskbar.h"
#include "log_panel.h"
#include "app_icon.h"
+#include "../ffs_paths.h"
+#include "../perf_check.h"
+#include "../icon_buffer.h"
using namespace zen;
@@ -998,9 +998,9 @@ template <class TopLevelDialog>
void SyncProgressDialogImpl<TopLevelDialog>::setExternalStatus(const wxString& status, const wxString& progress) //progress may be empty!
{
//sys tray: order "top-down": jobname, status, progress
- wxString systrayTooltip = jobName_.empty() ? status : jobName_ + L"\n" + status;
+ wxString systrayTooltip = jobName_.empty() ? status : jobName_ + L'\n' + status;
if (!progress.empty())
- systrayTooltip += L" " + progress;
+ systrayTooltip += L' ' + progress;
//window caption/taskbar; inverse order: progress, status, jobname
wxString title = progress.empty() ? status : progress + L" | " + status;
@@ -1009,7 +1009,7 @@ void SyncProgressDialogImpl<TopLevelDialog>::setExternalStatus(const wxString& s
title += L" | " + jobName_;
const TimeComp tc = getLocalTime(std::chrono::system_clock::to_time_t(syncStartTime_)); //returns empty string on failure
- title += L" | " + formatTime<std::wstring>(FORMAT_DATE_TIME, tc);
+ title += L" | " + utfTo<std::wstring>(formatTime(formatDateTimeTag, tc));
//---------------------------------------------------------------------------
//systray tooltip, if window is minimized
@@ -1341,7 +1341,7 @@ void SyncProgressDialogImpl<TopLevelDialog>::showSummary(SyncResult resultStatus
}();
pnl_.m_bitmapStatus->SetBitmap(statusImage);
- pnl_.m_staticTextPhase->SetLabel(getResultsStatusLabel(resultStatus));
+ pnl_.m_staticTextPhase->SetLabel(getSyncResultLabel(resultStatus));
//pnl_.m_bitmapStatus->SetToolTip(); -> redundant
//show status on Windows 7 taskbar
@@ -1360,7 +1360,7 @@ void SyncProgressDialogImpl<TopLevelDialog>::showSummary(SyncResult resultStatus
}
//----------------------------------
- setExternalStatus(getResultsStatusLabel(resultStatus), wxString());
+ setExternalStatus(getSyncResultLabel(resultStatus), wxString());
//this->EnableCloseButton(true);
@@ -1407,7 +1407,8 @@ void SyncProgressDialogImpl<TopLevelDialog>::showSummary(SyncResult resultStatus
pnl_.m_notebookResult->AddPage(logPanel, _("Log"), false /*bSelect*/);
//show log instead of graph if errors occurred! (not required for ignored warnings)
- if (log.ref().getItemCount(MSG_TYPE_ERROR | MSG_TYPE_FATAL_ERROR) > 0)
+ const ErrorLog::Stats logCount = log.ref().getStats();
+ if (logCount.error + logCount.fatal > 0)
pnl_.m_notebookResult->ChangeSelection(pagePosLog);
//fill image list to cope with wxNotebook image setting design desaster...
@@ -1443,11 +1444,12 @@ void SyncProgressDialogImpl<TopLevelDialog>::showSummary(SyncResult resultStatus
switch (resultStatus)
{
case SyncResult::aborted:
+ warn_static("we really should play sound if cancel on error is set, and only not play if user-aborted")
break;
case SyncResult::finishedError:
case SyncResult::finishedWarning:
case SyncResult::finishedSuccess:
- if (!soundFileSyncComplete_.empty() && fileAvailable(soundFileSyncComplete_))
+ if (!soundFileSyncComplete_.empty())
{
//wxWidgets shows modal error dialog by default => NO!
wxLog* oldLogTarget = wxLog::SetActiveTarget(new wxLogStderr); //transfer and receive ownership!
diff --git a/FreeFileSync/Source/ui/progress_indicator.h b/FreeFileSync/Source/ui/progress_indicator.h
index 5289f5e9..300078fa 100644
--- a/FreeFileSync/Source/ui/progress_indicator.h
+++ b/FreeFileSync/Source/ui/progress_indicator.h
@@ -11,9 +11,9 @@
#include <zen/error_log.h>
#include <zen/zstring.h>
#include <wx/frame.h>
-#include "../base/config.h"
-#include "../base/status_handler.h"
-#include "../base/return_codes.h"
+#include "../config.h"
+#include "../status_handler.h"
+#include "../return_codes.h"
namespace fff
diff --git a/FreeFileSync/Source/ui/small_dlgs.cpp b/FreeFileSync/Source/ui/small_dlgs.cpp
index d7bcebe9..39855f3c 100644
--- a/FreeFileSync/Source/ui/small_dlgs.cpp
+++ b/FreeFileSync/Source/ui/small_dlgs.cpp
@@ -31,19 +31,19 @@
#include "folder_selector.h"
#include "version_check.h"
#include "abstract_folder_picker.h"
+#include "../afs/concrete.h"
+#include "../afs/gdrive.h"
+#include "../afs/ftp.h"
+#include "../afs/sftp.h"
#include "../base/algorithm.h"
-#include "../base/ffs_paths.h"
#include "../base/synchronization.h"
-#include "../base/help_provider.h"
#include "../base/path_filter.h"
-#include "../base/status_handler.h" //uiUpdateDue()
-#include "../base/log_file.h"
-#include "../base/icon_buffer.h"
+#include "../status_handler.h" //uiUpdateDue()
#include "../version/version.h"
-#include "../afs/concrete.h"
-#include "../afs/gdrive.h"
-#include "../afs/sftp.h"
-#include "../afs/ftp.h"
+#include "../log_file.h"
+#include "../ffs_paths.h"
+#include "../help_provider.h"
+#include "../icon_buffer.h"
@@ -98,7 +98,7 @@ AboutDlg::AboutDlg(wxWindow* parent) : AboutDlgGenerated(parent)
#endif
build += SPACED_BULLET;
- build += formatTime<wxString>(FORMAT_DATE, getCompileTime());
+ build += utfTo<wxString>(formatTime(formatDateTag, getCompileTime()));
m_staticTextVersion->SetLabel(replaceCpy(_("Version: %x"), L"%x", build));
@@ -275,7 +275,7 @@ CloudSetupDlg::CloudSetupDlg(wxWindow* parent, Zstring& folderPathPhrase, size_t
m_staticTextConnectionsLabelSub->SetLabel(L"(" + _("Connections") + L")");
//use spacer to keep dialog height stable, no matter if key file options are visible
- bSizerAuthInner->Add(0, m_panelAuth->GetSize().GetHeight());
+ bSizerAuthInner->Add(0, m_panelAuth->GetSize().y);
//---------------------------------------------------------
wxArrayString googleUsers;
@@ -480,10 +480,11 @@ bool CloudSetupDlg::acceptFileDrop(const std::vector<Zstring>& shellItemPaths)
{
if (shellItemPaths.empty())
return false;
+
const Zstring ext = getFileExtension(shellItemPaths[0]);
return ext.empty() ||
- equalAsciiNoCase(ext, Zstr("pem")) ||
- equalAsciiNoCase(ext, Zstr("ppk"));
+ equalAsciiNoCase(ext, "pem") ||
+ equalAsciiNoCase(ext, "ppk");
}
@@ -1051,14 +1052,14 @@ public:
OptionsDlg(wxWindow* parent, XmlGlobalSettings& globalCfg);
private:
- void OnOkay (wxCommandEvent& event) override;
- void OnResetDialogs(wxCommandEvent& event) override;
- void OnDefault (wxCommandEvent& event) override;
- void OnCancel (wxCommandEvent& event) override { EndModal(ReturnSmallDlg::BUTTON_CANCEL); }
- void OnClose (wxCloseEvent& event) override { EndModal(ReturnSmallDlg::BUTTON_CANCEL); }
- void OnAddRow (wxCommandEvent& event) override;
- void OnRemoveRow (wxCommandEvent& event) override;
- void OnHelpShowExamples(wxHyperlinkEvent& event) override { displayHelpEntry(L"external-applications", this); }
+ void OnOkay (wxCommandEvent& event) override;
+ void OnRestoreDialogs(wxCommandEvent& event) override;
+ void OnDefault (wxCommandEvent& event) override;
+ void OnCancel (wxCommandEvent& event) override { EndModal(ReturnSmallDlg::BUTTON_CANCEL); }
+ void OnClose (wxCloseEvent& event) override { EndModal(ReturnSmallDlg::BUTTON_CANCEL); }
+ void OnAddRow (wxCommandEvent& event) override;
+ void OnRemoveRow (wxCommandEvent& event) override;
+ void OnHelpExternalApps(wxHyperlinkEvent& event) override { displayHelpEntry(L"external-applications", this); }
void OnShowLogFolder (wxHyperlinkEvent& event) override;
void OnToggleLogfilesLimit(wxCommandEvent& event) override { updateGui(); }
@@ -1111,10 +1112,9 @@ OptionsDlg::OptionsDlg(wxWindow* parent, XmlGlobalSettings& globalSettings) :
m_hyperlinkLogFolder->SetLabel(utfTo<wxString>(getDefaultLogFolderPath()));
setRelativeFontSize(*m_hyperlinkLogFolder, 1.2);
- m_staticTextResetDialogs->Wrap(std::max(fastFromDIP(250), m_buttonResetDialogs->GetMinSize().x));
-
m_bitmapSettings ->SetBitmap (getResourceImage(L"settings"));
- m_bitmapLogFile ->SetBitmap(shrinkImage(getResourceImage(L"log_file").ConvertToImage(), fastFromDIP(20)));
+ m_bitmapWarnings ->SetBitmap(shrinkImage(getResourceImage(L"msg_warning").ConvertToImage(), fastFromDIP(20)));
+ m_bitmapLogFile ->SetBitmap(shrinkImage(getResourceImage(L"log_file" ).ConvertToImage(), fastFromDIP(20)));
m_bitmapNotificationSounds->SetBitmap (getResourceImage(L"notification_sounds"));
m_bitmapCompareDone ->SetBitmap (getResourceImage(L"compare_sicon"));
m_bitmapSyncDone ->SetBitmap (getResourceImage(L"file_sync_sicon"));
@@ -1123,6 +1123,12 @@ OptionsDlg::OptionsDlg(wxWindow* parent, XmlGlobalSettings& globalSettings) :
m_bpButtonAddRow ->SetBitmapLabel(getResourceImage(L"item_add"));
m_bpButtonRemoveRow ->SetBitmapLabel(getResourceImage(L"item_remove"));
+ m_staticTextAllDialogsShown->SetLabel(L"(" + _("All dialogs shown") + L")");
+
+ m_staticTextResetDialogs->Wrap(std::max(fastFromDIP(250),
+ m_buttonRestoreDialogs ->GetSize().x +
+ m_staticTextAllDialogsShown->GetSize().x));
+
//--------------------------------------------------------------------------------
m_checkBoxFailSafe ->SetValue(globalSettings.failSafeFileCopy);
m_checkBoxCopyLocked ->SetValue(globalSettings.copyLockedFiles);
@@ -1131,19 +1137,29 @@ OptionsDlg::OptionsDlg(wxWindow* parent, XmlGlobalSettings& globalSettings) :
m_checkBoxLogFilesMaxAge->SetValue(globalSettings.logfilesMaxAgeDays > 0);
m_spinCtrlLogFilesMaxAge->SetValue(globalSettings.logfilesMaxAgeDays > 0 ? globalSettings.logfilesMaxAgeDays : XmlGlobalSettings().logfilesMaxAgeDays);
+ switch (globalSettings.logFormat)
+ {
+ case LogFileFormat::html:
+ m_radioBtnLogHtml->SetValue(true);
+ break;
+ case LogFileFormat::text:
+ m_radioBtnLogText->SetValue(true);
+ break;
+ }
+
m_textCtrlSoundPathCompareDone->ChangeValue(utfTo<wxString>(globalSettings.soundFileCompareFinished));
m_textCtrlSoundPathSyncDone ->ChangeValue(utfTo<wxString>(globalSettings.soundFileSyncFinished));
-
- setExtApp(globalSettings.gui.externalApps);
//--------------------------------------------------------------------------------
- updateGui();
-
bSizerLockedFiles->Show(false);
m_gridCustomCommand->SetMargins(0, 0);
//temporarily set dummy value for window height calculations:
setExtApp(std::vector<ExternalApp>(globalSettings.gui.externalApps.size() + 1));
+ confirmDlgs_ = defaultCfg_.confirmDlgs; //
+ warnDlgs_ = defaultCfg_.warnDlgs; //make sure m_staticTextAllDialogsShown is shown
+ autoCloseProgressDialog_ = defaultCfg_.autoCloseProgressDialog; //
+ updateGui();
GetSizer()->SetSizeHints(this); //~=Fit() + SetMinSize()
//=> works like a charm for GTK2 with window resizing problems and title bar corruption; e.g. Debian!!!
@@ -1151,6 +1167,10 @@ OptionsDlg::OptionsDlg(wxWindow* parent, XmlGlobalSettings& globalSettings) :
//restore actual value:
setExtApp(globalSettings.gui.externalApps);
+ confirmDlgs_ = globalSettings.confirmDlgs;
+ warnDlgs_ = globalSettings.warnDlgs;
+ autoCloseProgressDialog_ = globalSettings.autoCloseProgressDialog;
+ updateGui();
//automatically fit column width to match total grid width
Connect(wxEVT_SIZE, wxSizeEventHandler(OptionsDlg::onResize), nullptr, this);
@@ -1183,10 +1203,9 @@ void OptionsDlg::updateGui()
warnDlgs_ != defaultCfg_.warnDlgs ||
autoCloseProgressDialog_ != defaultCfg_.autoCloseProgressDialog;
- setBitmapTextLabel(*m_buttonResetDialogs, shrinkImage(getResourceImage(L"msg_warning").ConvertToImage(), fastFromDIP(20)),
- haveHiddenDialogs ? _("Show hidden dialogs again") : _("All dialogs shown"));
+ m_buttonRestoreDialogs->Enable(haveHiddenDialogs);
+ m_staticTextAllDialogsShown->Show(!haveHiddenDialogs);
Layout();
- m_buttonResetDialogs->Enable(haveHiddenDialogs);
m_spinCtrlLogFilesMaxAge->Enable(m_checkBoxLogFilesMaxAge->GetValue());
@@ -1195,7 +1214,7 @@ void OptionsDlg::updateGui()
}
-void OptionsDlg::OnResetDialogs(wxCommandEvent& event)
+void OptionsDlg::OnRestoreDialogs(wxCommandEvent& event)
{
confirmDlgs_ = defaultCfg_.confirmDlgs;
warnDlgs_ = defaultCfg_.warnDlgs;
@@ -1248,6 +1267,16 @@ void OptionsDlg::OnDefault(wxCommandEvent& event)
m_checkBoxLogFilesMaxAge->SetValue(defaultCfg_.logfilesMaxAgeDays > 0);
m_spinCtrlLogFilesMaxAge->SetValue(defaultCfg_.logfilesMaxAgeDays > 0 ? defaultCfg_.logfilesMaxAgeDays : 14);
+ switch (defaultCfg_.logFormat)
+ {
+ case LogFileFormat::html:
+ m_radioBtnLogHtml->SetValue(true);
+ break;
+ case LogFileFormat::text:
+ m_radioBtnLogText->SetValue(true);
+ break;
+ }
+
m_textCtrlSoundPathCompareDone->ChangeValue(utfTo<wxString>(defaultCfg_.soundFileCompareFinished));
m_textCtrlSoundPathSyncDone ->ChangeValue(utfTo<wxString>(defaultCfg_.soundFileSyncFinished));
@@ -1265,6 +1294,7 @@ void OptionsDlg::OnOkay(wxCommandEvent& event)
globalCfgOut_.copyFilePermissions = m_checkBoxCopyPermissions->GetValue();
globalCfgOut_.logfilesMaxAgeDays = m_checkBoxLogFilesMaxAge->GetValue() ? m_spinCtrlLogFilesMaxAge->GetValue() : -1;
+ globalCfgOut_.logFormat = m_radioBtnLogHtml->GetValue() ? LogFileFormat::html : LogFileFormat::text;
globalCfgOut_.soundFileCompareFinished = utfTo<Zstring>(trimCpy(m_textCtrlSoundPathCompareDone->GetValue()));
globalCfgOut_.soundFileSyncFinished = utfTo<Zstring>(trimCpy(m_textCtrlSoundPathSyncDone ->GetValue()));
@@ -1555,7 +1585,7 @@ ActivationDlg::ActivationDlg(wxWindow* parent,
{
setStandardButtonLayout(*bSizerStdButtons, StdButtons().setCancel(m_buttonCancel));
- SetTitle(std::wstring(L"FreeFileSync ") + ffsVersion + L" [" + _("Donation Edition") + L"]");
+ SetTitle(std::wstring(L"FreeFileSync ") + ffsVersion + L" [" + _("Donation Edition") + L']');
//setMainInstructionFont(*m_staticTextMain);
@@ -1636,7 +1666,7 @@ private:
void updateGui()
{
const double fraction = bytesTotal_ == 0 ? 0 : 1.0 * bytesCurrent_ / bytesTotal_;
- m_staticTextHeader->SetLabel(_("Downloading update...") + L" " +
+ m_staticTextHeader->SetLabel(_("Downloading update...") + L' ' +
numberTo<std::wstring>(numeric::round(fraction * 100)) + L"% (" + formatFilesizeShort(bytesCurrent_) + L")");
m_gaugeProgress->SetValue(numeric::round(fraction * GAUGE_FULL_RANGE));
diff --git a/FreeFileSync/Source/ui/small_dlgs.h b/FreeFileSync/Source/ui/small_dlgs.h
index ace76582..1849dc18 100644
--- a/FreeFileSync/Source/ui/small_dlgs.h
+++ b/FreeFileSync/Source/ui/small_dlgs.h
@@ -8,8 +8,8 @@
#define SMALL_DLGS_H_8321790875018750245
#include <wx/window.h>
-#include "../base/config.h"
#include "../base/synchronization.h"
+#include "../config.h"
namespace fff
diff --git a/FreeFileSync/Source/ui/sync_cfg.cpp b/FreeFileSync/Source/ui/sync_cfg.cpp
index 243fd315..318ec3b9 100644
--- a/FreeFileSync/Source/ui/sync_cfg.cpp
+++ b/FreeFileSync/Source/ui/sync_cfg.cpp
@@ -21,11 +21,12 @@
#include "gui_generated.h"
#include "command_box.h"
#include "folder_selector.h"
-#include "../base/file_hierarchy.h"
-#include "../base/help_provider.h"
-#include "../base/log_file.h"
#include "../base/norm_filter.h"
+#include "../base/file_hierarchy.h"
+#include "../help_provider.h"
+#include "../log_file.h"
#include "../afs/concrete.h"
+#include "../base_tools.h"
@@ -99,7 +100,7 @@ private:
std::map<AfsDevice, size_t> deviceParallelOps_; //
//------------- filter panel --------------------------
- void OnHelpShowExamples(wxHyperlinkEvent& event) override { displayHelpEntry(L"exclude-items", this); }
+ void OnHelpFilterSettings(wxHyperlinkEvent& event) override { displayHelpEntry(L"exclude-items", this); }
void OnChangeFilterOption(wxCommandEvent& event) override { updateFilterGui(); }
void OnFilterReset (wxCommandEvent& event) override { setFilterConfig(FilterConfig()); }
@@ -143,7 +144,13 @@ private:
void OnDeletionRecycler (wxCommandEvent& event) override { handleDeletion_ = DeletionPolicy::recycler; updateSyncGui(); }
void OnDeletionVersioning (wxCommandEvent& event) override { handleDeletion_ = DeletionPolicy::versioning; updateSyncGui(); }
- void OnToggleMiscOption (wxCommandEvent& event) override { updateMiscGui(); }
+ void OnToggleMiscOption(wxCommandEvent& event) override { updateMiscGui(); }
+ void OnToggleMiscEmail (wxCommandEvent& event) override
+ {
+ OnToggleMiscOption(event);
+ if (event.IsChecked()) //optimize UX
+ m_comboBoxEmail->SetFocus(); //
+ }
void OnEmailAlways (wxCommandEvent& event) override { emailNotifyCondition_ = ResultsNotification::always; updateMiscGui(); }
void OnEmailErrorWarning(wxCommandEvent& event) override { emailNotifyCondition_ = ResultsNotification::errorWarning; updateMiscGui(); }
void OnEmailErrorOnly (wxCommandEvent& event) override { emailNotifyCondition_ = ResultsNotification::errorOnly; updateMiscGui(); }
@@ -283,7 +290,7 @@ emailHistoryOut_(emailHistory),
commandHistoryOut_(commandHistory),
globalPairCfg_(globalPairCfg),
localPairCfg_(localPairConfig),
-enableExtraFeatures_(false),
+ enableExtraFeatures_(false),
showMultipleCfgs_(showMultipleCfgs)
{
setStandardButtonLayout(*bSizerStdButtons, StdButtons().setAffirmative(m_buttonOkay).setCancel(m_buttonCancel));
@@ -393,8 +400,8 @@ showMultipleCfgs_(showMultipleCfgs)
enumVersioningStyle_.
add(VersioningStyle::replace, _("Replace"), _("Move files and replace if existing")).
- add(VersioningStyle::timestampFolder, _("Time stamp") + L" [" + _("Folder") + L"]", _("Move files into a time-stamped subfolder")).
- add(VersioningStyle::timestampFile, _("Time stamp") + L" [" + _("File") + L"]", _("Append a time stamp to each file name"));
+ add(VersioningStyle::timestampFolder, _("Time stamp") + L" [" + _("Folder") + L']', _("Move files into a time-stamped subfolder")).
+ add(VersioningStyle::timestampFile, _("Time stamp") + L" [" + _("File") + L']', _("Append a time stamp to each file name"));
m_spinCtrlVersionMaxDays ->SetMinSize({fastFromDIP(60), -1}); //
m_spinCtrlVersionCountMin->SetMinSize({fastFromDIP(60), -1}); //Hack: set size (why does wxWindow::Size() not work?)
@@ -407,7 +414,6 @@ showMultipleCfgs_(showMultipleCfgs)
m_comboBoxEmail->SetHint(/*_("Example:") + */ L"john.doe@example.com");
m_comboBoxEmail->setHistory(emailHistory, emailHistoryMax);
- m_checkBoxSendEmail ->Enable(enableExtraFeatures_);
m_comboBoxEmail ->Enable(enableExtraFeatures_);
m_bpButtonEmailAlways ->Enable(enableExtraFeatures_);
m_bpButtonEmailErrorWarning ->Enable(enableExtraFeatures_);
@@ -455,7 +461,7 @@ showMultipleCfgs_(showMultipleCfgs)
globalPairCfg_.syncCfg.versioningStyle = VersioningStyle::timestampFile; //
globalPairCfg_.syncCfg.versionMaxAgeDays = 30; //
globalPairCfg_.miscCfg.altLogFolderPathPhrase = Zstr("dummy"); //
- globalPairCfg_.miscCfg.emailNotifyAddress = Zstr("dummy"); //
+ globalPairCfg_.miscCfg.emailNotifyAddress = "dummy"; //
selectFolderPairConfig(-1);
@@ -1196,13 +1202,13 @@ MiscSyncConfig ConfigDialog::getMiscSyncOptions() const
//----------------------------------------------------------------------------
Zstring altLogPathPhrase = logfileDir_.getPath();
if (altLogPathPhrase.empty())
- altLogPathPhrase = Zstr(" "); //trigger error message on dialog close
+ altLogPathPhrase = Zstr(' '); //trigger error message on dialog close
miscCfg.altLogFolderPathPhrase = m_checkBoxOverrideLogPath->GetValue() ? altLogPathPhrase : Zstring();
//----------------------------------------------------------------------------
- Zstring emailAddress = m_comboBoxEmail->getValue();
+ std::string emailAddress = utfTo<std::string>(m_comboBoxEmail->getValue());
if (emailAddress.empty())
- emailAddress = Zstr(" "); //trigger error message on dialog close
- miscCfg.emailNotifyAddress = m_checkBoxSendEmail->GetValue() ? emailAddress : Zstring();
+ emailAddress = ' '; //trigger error message on dialog close
+ miscCfg.emailNotifyAddress = m_checkBoxSendEmail->GetValue() ? emailAddress : std::string();
miscCfg.emailNotifyCondition = emailNotifyCondition_;
//----------------------------------------------------------------------------
return miscCfg;
@@ -1264,8 +1270,13 @@ void ConfigDialog::setMiscSyncOptions(const MiscSyncConfig& miscCfg)
logfileDir_.setPath(m_checkBoxOverrideLogPath->GetValue() ? miscCfg.altLogFolderPathPhrase : getDefaultLogFolderPath());
//can't use logfileDir_.setBackgroundText(): no text shown when control is disabled!
//----------------------------------------------------------------------------
+ Zstring defaultEmail;
+ if (const std::vector<Zstring>& history = m_comboBoxEmail->getHistory();
+ !history.empty())
+ defaultEmail = history[0];
+
m_checkBoxSendEmail->SetValue(!trimCpy(miscCfg.emailNotifyAddress).empty());
- m_comboBoxEmail->setValue(miscCfg.emailNotifyAddress);
+ m_comboBoxEmail->setValue(m_checkBoxSendEmail->GetValue() ? utfTo<Zstring>(miscCfg.emailNotifyAddress) : defaultEmail);
emailNotifyCondition_ = miscCfg.emailNotifyCondition;
//----------------------------------------------------------------------------
updateMiscGui();
@@ -1284,7 +1295,7 @@ void ConfigDialog::updateMiscGui()
m_panelComparisonSettings->Layout(); //showing "retry count" can affect bSizerPerformance!
//----------------------------------------------------------------------------
const bool sendEmailEnabled = m_checkBoxSendEmail->GetValue();
- m_bitmapEmail->SetBitmap(shrinkImage(greyScaleIfDisabled(getResourceImage(L"email"), sendEmailEnabled).ConvertToImage(), fastFromDIP(24)));
+ m_bitmapEmail->SetBitmap(greyScaleIfDisabled(getResourceImage(L"email"), sendEmailEnabled).ConvertToImage());
m_comboBoxEmail->Show(sendEmailEnabled);
auto updateButton = [successIcon = getResourceImage(L"msg_success_sicon").ConvertToImage(),
@@ -1334,7 +1345,9 @@ void ConfigDialog::updateMiscGui()
m_bpButtonSelectAltLogFolder->Show(m_checkBoxOverrideLogPath->GetValue()); //
m_panelSyncSettings->Layout(); //after showing/hiding m_buttonSelectLogFolder
- m_panelLogfile->Refresh(); //removes a few artifacts when toggling email notifications
+
+ m_panelSyncSettings->Refresh(); //removes a few artifacts when toggling email notifications
+ m_panelLogfile ->Refresh();//
}
diff --git a/FreeFileSync/Source/ui/sync_cfg.h b/FreeFileSync/Source/ui/sync_cfg.h
index 568b1461..c9e481f7 100644
--- a/FreeFileSync/Source/ui/sync_cfg.h
+++ b/FreeFileSync/Source/ui/sync_cfg.h
@@ -41,7 +41,7 @@ struct MiscSyncConfig
Zstring altLogFolderPathPhrase;
- Zstring emailNotifyAddress;
+ std::string emailNotifyAddress;
ResultsNotification emailNotifyCondition = ResultsNotification::always;
};
diff --git a/FreeFileSync/Source/ui/tree_grid.cpp b/FreeFileSync/Source/ui/tree_grid.cpp
index 963ebdd0..e9a4ab62 100644
--- a/FreeFileSync/Source/ui/tree_grid.cpp
+++ b/FreeFileSync/Source/ui/tree_grid.cpp
@@ -17,7 +17,7 @@
#include <wx+/context_menu.h>
#include <wx+/image_resources.h>
#include <wx+/image_tools.h>
-#include "../base/icon_buffer.h"
+#include "../icon_buffer.h"
using namespace zen;
using namespace fff;
@@ -736,7 +736,7 @@ private:
return dirRight;
else if (dirRight.empty())
return dirLeft;
- return dirLeft + L" " + EN_DASH + L"\n" + dirRight;
+ return dirLeft + L' ' + EN_DASH + L'\n' + dirRight;
}
break;
@@ -1206,7 +1206,7 @@ TreeView& treegrid::getDataView(Grid& grid)
{
if (auto* prov = dynamic_cast<GridDataTree*>(grid.getDataProvider()))
return prov->getDataView();
- throw std::runtime_error(std::string(__FILE__) + "[" + numberTo<std::string>(__LINE__) + "] treegrid was not initialized.");
+ throw std::runtime_error(std::string(__FILE__) + '[' + numberTo<std::string>(__LINE__) + "] treegrid was not initialized.");
}
diff --git a/FreeFileSync/Source/ui/version_check.cpp b/FreeFileSync/Source/ui/version_check.cpp
index 49a1c321..ac74401a 100644
--- a/FreeFileSync/Source/ui/version_check.cpp
+++ b/FreeFileSync/Source/ui/version_check.cpp
@@ -19,7 +19,7 @@
#include <zen/thread.h>
#include <wx+/popup_dlg.h>
#include <wx+/image_resources.h>
-#include "../base/ffs_paths.h"
+#include "../ffs_paths.h"
#include "../version/version.h"
#include "small_dlgs.h"
@@ -167,7 +167,7 @@ void showUpdateAvailableDialog(wxWindow* parent, const std::string& onlineVersio
switch (showConfirmationDialog(parent, DialogInfoType::info, PopupDialogCfg().
setIcon(getResourceImage(L"update_available")).
setTitle(_("Check for Program Updates")).
- setMainInstructions(replaceCpy(_("FreeFileSync %x is available!"), L"%x", utfTo<std::wstring>(onlineVersion)) + L" " + _("Download now?")).
+ setMainInstructions(replaceCpy(_("FreeFileSync %x is available!"), L"%x", utfTo<std::wstring>(onlineVersion)) + L' ' + _("Download now?")).
setDetailInstructions(updateDetailsMsg),
_("&Download")))
{
diff --git a/FreeFileSync/Source/version/version.h b/FreeFileSync/Source/version/version.h
index 933b9f4c..5496cd99 100644
--- a/FreeFileSync/Source/version/version.h
+++ b/FreeFileSync/Source/version/version.h
@@ -3,7 +3,7 @@
namespace fff
{
-const char ffsVersion[] = "10.20"; //internal linkage!
+const char ffsVersion[] = "10.21"; //internal linkage!
const char FFS_VERSION_SEPARATOR = '.';
}
diff --git a/libcurl/curl_wrap.h b/libcurl/curl_wrap.h
index dca056fc..40694e71 100644
--- a/libcurl/curl_wrap.h
+++ b/libcurl/curl_wrap.h
@@ -137,10 +137,11 @@ std::wstring formatCurlStatusCode(CURLcode sc)
ZEN_CHECK_CASE_FOR_CONSTANT(CURLE_AUTH_ERROR);
ZEN_CHECK_CASE_FOR_CONSTANT(CURLE_HTTP3);
ZEN_CHECK_CASE_FOR_CONSTANT(CURL_LAST);
+ ZEN_CHECK_CASE_FOR_CONSTANT(CURLE_QUIC_CONNECT_ERROR);
}
- static_assert(CURL_LAST == CURLE_HTTP3 + 1);
+ static_assert(CURL_LAST == CURLE_QUIC_CONNECT_ERROR + 1);
- return replaceCpy<std::wstring>(L"Curl status %x.", L"%x", numberTo<std::wstring>(static_cast<int>(sc)));
+ return replaceCpy<std::wstring>(L"Curl status %x", L"%x", numberTo<std::wstring>(static_cast<int>(sc)));
}
diff --git a/libcurl/rest.cpp b/libcurl/rest.cpp
index 22583483..0d14dfc2 100644
--- a/libcurl/rest.cpp
+++ b/libcurl/rest.cpp
@@ -125,10 +125,10 @@ HttpSession::Result HttpSession::perform(const std::string& serverRelPath,
}
if (std::any_of(extraOptions.begin(), extraOptions.end(), [](const CurlOption& o) { return o.option == CURLOPT_WRITEFUNCTION || o.option == CURLOPT_READFUNCTION; }))
- throw std::logic_error("Contract violation! " + std::string(__FILE__) + ":" + numberTo<std::string>(__LINE__)); //Option already used here!
+ throw std::logic_error("Contract violation! " + std::string(__FILE__) + ':' + numberTo<std::string>(__LINE__)); //Option already used here!
if (readRequest && std::any_of(extraOptions.begin(), extraOptions.end(), [](const CurlOption& o) { return o.option == CURLOPT_POSTFIELDS; }))
- throw std::logic_error("Contract violation! " + std::string(__FILE__) + ":" + numberTo<std::string>(__LINE__)); //Contradicting options: CURLOPT_READFUNCTION, CURLOPT_POSTFIELDS
+ throw std::logic_error("Contract violation! " + std::string(__FILE__) + ':' + numberTo<std::string>(__LINE__)); //Contradicting options: CURLOPT_READFUNCTION, CURLOPT_POSTFIELDS
//---------------------------------------------------
curl_slist* headers = nullptr; //"libcurl will not copy the entire list so you must keep it!"
@@ -160,15 +160,15 @@ HttpSession::Result HttpSession::perform(const std::string& serverRelPath,
std::rethrow_exception(userCallbackException); //throw X
//=======================================================================================================
- long httpStatusCode = 0; //optional
- /*const CURLcode rc = */ ::curl_easy_getinfo(easyHandle_, CURLINFO_RESPONSE_CODE, &httpStatusCode);
+ long httpStatus = 0; //optional
+ /*const CURLcode rc = */ ::curl_easy_getinfo(easyHandle_, CURLINFO_RESPONSE_CODE, &httpStatus);
if (rcPerf != CURLE_OK)
{
std::wstring errorMsg = trimCpy(utfTo<std::wstring>(curlErrorBuf)); //optional
- if (httpStatusCode != 0) //optional
- errorMsg += (errorMsg.empty() ? L"" : L"\n") + formatHttpStatusCode(httpStatusCode);
+ if (httpStatus != 0) //optional
+ errorMsg += (errorMsg.empty() ? L"" : L"\n") + formatHttpStatus(httpStatus);
#if 0
//utfTo<std::wstring>(::curl_easy_strerror(ec)) is uninteresting
//use CURLINFO_OS_ERRNO ?? https://curl.haxx.se/libcurl/c/CURLINFO_OS_ERRNO.html
@@ -181,5 +181,5 @@ HttpSession::Result HttpSession::perform(const std::string& serverRelPath,
}
lastSuccessfulUseTime_ = std::chrono::steady_clock::now();
- return { static_cast<int>(httpStatusCode) /*, contentType ? contentType : ""*/ };
+ return { static_cast<int>(httpStatus) /*, contentType ? contentType : ""*/ };
}
diff --git a/libssh2/libssh2_wrap.h b/libssh2/libssh2_wrap.h
index 37a62a24..98b73af2 100644
--- a/libssh2/libssh2_wrap.h
+++ b/libssh2/libssh2_wrap.h
@@ -174,8 +174,10 @@ std::wstring formatSshStatusCode(int sc)
ZEN_CHECK_CASE_FOR_CONSTANT(LIBSSH2_ERROR_KNOWN_HOSTS);
ZEN_CHECK_CASE_FOR_CONSTANT(LIBSSH2_ERROR_CHANNEL_WINDOW_FULL);
ZEN_CHECK_CASE_FOR_CONSTANT(LIBSSH2_ERROR_KEYFILE_AUTH_FAILED);
+
+ default:
+ return replaceCpy<std::wstring>(L"SSH status %x", L"%x", numberTo<std::wstring>(sc));
}
- return replaceCpy<std::wstring>(L"SSH status %x.", L"%x", numberTo<std::wstring>(sc));
}
@@ -219,7 +221,7 @@ std::wstring formatSftpStatusCode(unsigned long sc)
case 30: return L"SSH_FX_GROUP_INVALID";
case 31: return L"SSH_FX_NO_MATCHING_BYTE_RANGE_LOCK";
- default: return replaceCpy<std::wstring>(L"SFTP status %x.", L"%x", numberTo<std::wstring>(sc));
+ default: return replaceCpy<std::wstring>(L"SFTP status %x", L"%x", numberTo<std::wstring>(sc));
//*INDENT-ON*
}
}
diff --git a/wx+/file_drop.cpp b/wx+/file_drop.cpp
index 65d5d861..938f9dbd 100644
--- a/wx+/file_drop.cpp
+++ b/wx+/file_drop.cpp
@@ -23,9 +23,23 @@ namespace
class WindowDropTarget : public wxFileDropTarget
{
public:
- WindowDropTarget(wxWindow& dropWindow) : dropWindow_(dropWindow) {}
+ WindowDropTarget(const wxWindow& dropWindow) : dropWindow_(dropWindow) {}
private:
+ wxDragResult OnDragOver(wxCoord x, wxCoord y, wxDragResult def) override
+ {
+ //why the FUCK I is drag & drop still working while showing another modal dialog!???
+ //why the FUCK II is drag & drop working even when dropWindow is disabled!?? [Windows] => we can fix this
+ //why the FUCK III is dropWindow NOT disabled while showing another modal dialog!??? [macOS, Linux] => we CANNOT fix this: FUUUUUUUUUUUUUU...
+ if (!dropWindow_.IsEnabled())
+ return wxDragNone;
+
+ return wxFileDropTarget::OnDragOver(x, y, def);
+ }
+
+ //"bool wxDropTarget::GetData() [...] This method may only be called from within OnData()."
+ //=> FUUUUUUUUUUUUUU........ a.k.a. no support for DragDropValidator during mouse hover! >:(
+
bool OnDropFiles(wxCoord x, wxCoord y, const wxArrayString& fileArray) override
{
/*Linux, MTP: we get an empty file array
@@ -35,6 +49,9 @@ private:
/run/user/1000/gvfs/mtp:host=%5Busb%3A001%2C002%5D/Telefonspeicher/Folder/file.txt
*/
+ if (!dropWindow_.IsEnabled())
+ return false;
+
//wxPoint clientDropPos(x, y)
std::vector<Zstring> filePaths;
for (const wxString& file : fileArray)
@@ -46,12 +63,12 @@ private:
return true;
}
- wxWindow& dropWindow_;
+ const wxWindow& dropWindow_;
};
}
-void zen::setupFileDrop(wxWindow& wnd)
+void zen::setupFileDrop(wxWindow& dropWindow)
{
- wnd.SetDropTarget(new WindowDropTarget(wnd)); /*takes ownership*/
+ dropWindow.SetDropTarget(new WindowDropTarget(dropWindow)); /*takes ownership*/
}
diff --git a/wx+/file_drop.h b/wx+/file_drop.h
index 9826bf27..0a1089fc 100644
--- a/wx+/file_drop.h
+++ b/wx+/file_drop.h
@@ -58,8 +58,7 @@ using FileDropEventFunction = void (wxEvtHandler::*)(FileDropEvent&);
-
-void setupFileDrop(wxWindow& wnd);
+void setupFileDrop(wxWindow& dropWindow);
}
#endif //FILE_DROP_H_09457802957842560325626
diff --git a/wx+/grid.cpp b/wx+/grid.cpp
index fe168df6..c7b43d4a 100644
--- a/wx+/grid.cpp
+++ b/wx+/grid.cpp
@@ -159,7 +159,7 @@ wxSize GridData::drawCellText(wxDC& dc, const wxRect& rect, const std::wstring&
*/
//truncate large texts and add ellipsis
- assert(!contains(text, L"\n"));
+ assert(!contains(text, L'\n'));
std::wstring textTrunc = text;
wxSize extentTrunc = dc.GetTextExtent(textTrunc);
diff --git a/wx+/image_resources.cpp b/wx+/image_resources.cpp
index 070b9112..255a352e 100644
--- a/wx+/image_resources.cpp
+++ b/wx+/image_resources.cpp
@@ -231,7 +231,7 @@ void GlobalBitmaps::init(const Zstring& zipPath)
{
wxMemoryInputStream wxstream(stream.c_str(), stream.size()); //stream does not take ownership of data
//bonus: work around wxWidgets bug: wxAnimation::Load() requires seekable input stream (zip-input stream is not seekable)
-
+
if (endsWith(fileName, L".png"))
{
wxImage img(wxstream, wxBITMAP_TYPE_PNG);
diff --git a/wx+/image_tools.cpp b/wx+/image_tools.cpp
index 8f94d1bc..9fcc5563 100644
--- a/wx+/image_tools.cpp
+++ b/wx+/image_tools.cpp
@@ -120,7 +120,7 @@ std::vector<std::pair<wxString, wxSize>> getTextExtentInfo(const wxString& text,
dc.SetFont(font); //the font parameter of GetMultiLineTextExtent() is not evalated on OS X, wxWidgets 2.9.5, so apply it to the DC directly!
std::vector<std::pair<wxString, wxSize>> lineInfo; //text + extent
- for (const wxString& line : split(text, L"\n", SplitType::ALLOW_EMPTY))
+ for (const wxString& line : split(text, L'\n', SplitType::ALLOW_EMPTY))
lineInfo.emplace_back(line, line.empty() ? wxSize() : dc.GetTextExtent(line));
return lineInfo;
diff --git a/wx+/popup_dlg.cpp b/wx+/popup_dlg.cpp
index 11c4511f..c677cf57 100644
--- a/wx+/popup_dlg.cpp
+++ b/wx+/popup_dlg.cpp
@@ -45,7 +45,7 @@ void setBestInitialSize(wxTextCtrl& ctrl, const wxString& text, wxSize maxSize)
auto itEnd = std::find(it, text.end(), L'\n');
wxString line(it, itEnd);
if (line.empty())
- line = L" "; //GetTextExtent() returns (0, 0) for empty strings!
+ line = L' '; //GetTextExtent() returns (0, 0) for empty strings!
wxSize sz = ctrl.GetTextExtent(line); //exactly gives row height, but does *not* consider newlines
if (evalLineExtent(sz))
@@ -135,8 +135,8 @@ public:
{
wxString text;
if (!cfg.textMain.empty())
- text += L"\n";
- text += trimCpy(cfg.textDetail) + L"\n"; //add empty top/bottom lines *instead* of using border space!
+ text += L'\n';
+ text += trimCpy(cfg.textDetail) + L'\n'; //add empty top/bottom lines *instead* of using border space!
setBestInitialSize(*m_textCtrlTextDetail, text, wxSize(maxWidth, maxHeight));
m_textCtrlTextDetail->ChangeValue(text);
}
@@ -145,7 +145,7 @@ public:
if (checkBoxValue_)
{
- assert(contains(cfg.checkBoxLabel, L"&"));
+ assert(contains(cfg.checkBoxLabel, L'&'));
m_checkBoxCustom->SetLabel(cfg.checkBoxLabel);
m_checkBoxCustom->SetValue(*checkBoxValue_);
}
diff --git a/xBRZ/src/xbrz.cpp b/xBRZ/src/xbrz.cpp
index 5228073f..e2c25810 100644
--- a/xBRZ/src/xbrz.cpp
+++ b/xBRZ/src/xbrz.cpp
@@ -241,8 +241,8 @@ enum BlendType
struct BlendResult
{
BlendType
- /**/blend_f, blend_g,
- /**/blend_j, blend_k;
+ blend_e, blend_f,
+ blend_h, blend_i;
};
@@ -254,62 +254,57 @@ struct Kernel_3x3
g, h, i;
};
-struct Kernel_4x4 //kernel for preprocessing step
+struct Kernel_4x4 : Kernel_3x3
{
- uint32_t
- a, b, c, //
- e, f, g, // support reinterpret_cast from Kernel_4x4 => Kernel_3x3
- i, j, k, //
- m, n, o,
- d, h, l, p;
+ uint32_t j, k, l, m, n, o, p;
};
+/* input kernel for preprocessing step:
+
+ -----------------
+ | A | B | C | P |
+ |---|---|---|---|
+ | D | E | F | O | evaluate the four corners between E, F, H, I
+ |---|---|---|---| input pixel is at position E
+ | G | H | I | N |
+ |---|---|---|---|
+ | J | K | L | M |
+ ----------------- */
-/* input kernel area naming convention:
------------------
-| A | B | C | D |
-|---|---|---|---|
-| E | F | G | H | evaluate the four corners between F, G, J, K
-|---|---|---|---| input pixel is at position F
-| I | J | K | L |
-|---|---|---|---|
-| M | N | O | P |
------------------
-*/
template <class ColorDistance>
FORCE_INLINE //detect blend direction
-BlendResult preProcessCorners(const Kernel_4x4& ker, const xbrz::ScalerCfg& cfg) //result: F, G, J, K corners of "GradientType"
+BlendResult preProcessCorners(const Kernel_4x4& ker, const xbrz::ScalerCfg& cfg) //result: E, F, H, I corners of "GradientType"
{
BlendResult result = {};
- if ((ker.f == ker.g &&
- ker.j == ker.k) ||
- (ker.f == ker.j &&
- ker.g == ker.k))
+ if ((ker.e == ker.f &&
+ ker.h == ker.i) ||
+ (ker.e == ker.h &&
+ ker.f == ker.i))
return result;
auto dist = [&](uint32_t pix1, uint32_t pix2) { return ColorDistance::dist(pix1, pix2, cfg.luminanceWeight); };
- double jg = dist(ker.i, ker.f) + dist(ker.f, ker.c) + dist(ker.n, ker.k) + dist(ker.k, ker.h) + cfg.centerDirectionBias * dist(ker.j, ker.g);
- double fk = dist(ker.e, ker.j) + dist(ker.j, ker.o) + dist(ker.b, ker.g) + dist(ker.g, ker.l) + cfg.centerDirectionBias * dist(ker.f, ker.k);
+ const double hf = dist(ker.g, ker.e) + dist(ker.e, ker.c) + dist(ker.k, ker.i) + dist(ker.i, ker.o) + cfg.centerDirectionBias * dist(ker.h, ker.f);
+ const double ei = dist(ker.d, ker.h) + dist(ker.h, ker.l) + dist(ker.b, ker.f) + dist(ker.f, ker.n) + cfg.centerDirectionBias * dist(ker.e, ker.i);
- if (jg < fk) //test sample: 70% of values max(jg, fk) / min(jg, fk) are between 1.1 and 3.7 with median being 1.8
+ if (hf < ei) //test sample: 70% of values max(hf, ei) / min(hf, ei) are between 1.1 and 3.7 with median being 1.8
{
- const bool dominantGradient = cfg.dominantDirectionThreshold * jg < fk;
- if (ker.f != ker.g && ker.f != ker.j)
- result.blend_f = dominantGradient ? BLEND_DOMINANT : BLEND_NORMAL;
+ const bool dominantGradient = cfg.dominantDirectionThreshold * hf < ei;
+ if (ker.e != ker.f && ker.e != ker.h)
+ result.blend_e = dominantGradient ? BLEND_DOMINANT : BLEND_NORMAL;
- if (ker.k != ker.j && ker.k != ker.g)
- result.blend_k = dominantGradient ? BLEND_DOMINANT : BLEND_NORMAL;
+ if (ker.i != ker.h && ker.i != ker.f)
+ result.blend_i = dominantGradient ? BLEND_DOMINANT : BLEND_NORMAL;
}
- else if (fk < jg)
+ else if (ei < hf)
{
- const bool dominantGradient = cfg.dominantDirectionThreshold * fk < jg;
- if (ker.j != ker.f && ker.j != ker.k)
- result.blend_j = dominantGradient ? BLEND_DOMINANT : BLEND_NORMAL;
+ const bool dominantGradient = cfg.dominantDirectionThreshold * ei < hf;
+ if (ker.h != ker.e && ker.h != ker.i)
+ result.blend_h = dominantGradient ? BLEND_DOMINANT : BLEND_NORMAL;
- if (ker.g != ker.f && ker.g != ker.k)
- result.blend_g = dominantGradient ? BLEND_DOMINANT : BLEND_NORMAL;
+ if (ker.f != ker.e && ker.f != ker.i)
+ result.blend_f = dominantGradient ? BLEND_DOMINANT : BLEND_NORMAL;
}
return result;
}
@@ -371,13 +366,13 @@ template <> inline unsigned char rotateBlendInfo<ROT_270>(unsigned char b) { ret
| D | E | F | input pixel is at position E
|---|---|---|
| G | H | I |
--------------
-*/
+------------- */
+
template <class Scaler, class ColorDistance, RotationDegree rotDeg>
FORCE_INLINE //perf: quite worth it!
void blendPixel(const Kernel_3x3& ker,
uint32_t* target, int trgWidth,
- unsigned char blendInfo, //result of preprocessing all four corners of pixel "e"
+ unsigned char blendInfo, //result of preprocessing all four corners of pixel "E"
const xbrz::ScalerCfg& cfg)
{
//#define a get_a<rotDeg>(ker)
@@ -469,21 +464,21 @@ public:
s_p2(0 <= y + 2 && y + 2 < srcHeight ? src + srcWidth * (y + 2) : nullptr),
srcWidth_(srcWidth) {}
- void readDhlp(Kernel_4x4& ker, int x) const //(x, y) is at kernel position F
+ void readPonm(Kernel_4x4& ker, int x) const //(x, y) is at kernel position E
{
[[likely]] if (const int x_p2 = x + 2; 0 <= x_p2 && x_p2 < srcWidth_)
{
- ker.d = s_m1 ? s_m1[x_p2] : 0;
- ker.h = s_0 ? s_0 [x_p2] : 0;
- ker.l = s_p1 ? s_p1[x_p2] : 0;
- ker.p = s_p2 ? s_p2[x_p2] : 0;
+ ker.p = s_m1 ? s_m1[x_p2] : 0;
+ ker.o = s_0 ? s_0 [x_p2] : 0;
+ ker.n = s_p1 ? s_p1[x_p2] : 0;
+ ker.m = s_p2 ? s_p2[x_p2] : 0;
}
else
{
- ker.d = 0;
- ker.h = 0;
- ker.l = 0;
ker.p = 0;
+ ker.o = 0;
+ ker.n = 0;
+ ker.m = 0;
}
}
@@ -506,13 +501,13 @@ public:
s_p2(src + srcWidth * std::clamp(y + 2, 0, srcHeight - 1)),
srcWidth_(srcWidth) {}
- void readDhlp(Kernel_4x4& ker, int x) const //(x, y) is at kernel position F
+ void readPonm(Kernel_4x4& ker, int x) const //(x, y) is at kernel position E
{
const int x_p2 = std::clamp(x + 2, 0, srcWidth_ - 1);
- ker.d = s_m1[x_p2];
- ker.h = s_0 [x_p2];
- ker.l = s_p1[x_p2];
- ker.p = s_p2[x_p2];
+ ker.p = s_m1[x_p2];
+ ker.o = s_0 [x_p2];
+ ker.n = s_p1[x_p2];
+ ker.m = s_p2[x_p2];
}
private:
@@ -545,61 +540,61 @@ void scaleImage(const uint32_t* src, uint32_t* trg, int srcWidth, int srcHeight,
//initialize at position x = -1
Kernel_4x4 ker4 = {};
- oobReader.readDhlp(ker4, -4); //hack: read a, e, i, m at x = -1
- ker4.a = ker4.d;
- ker4.e = ker4.h;
- ker4.i = ker4.l;
- ker4.m = ker4.p;
-
- oobReader.readDhlp(ker4, -3);
- ker4.b = ker4.d;
- ker4.f = ker4.h;
- ker4.j = ker4.l;
- ker4.n = ker4.p;
-
- oobReader.readDhlp(ker4, -2);
- ker4.c = ker4.d;
- ker4.g = ker4.h;
- ker4.k = ker4.l;
- ker4.o = ker4.p;
-
- oobReader.readDhlp(ker4, -1);
+ oobReader.readPonm(ker4, -4); //hack: read a, d, g, j at x = -1
+ ker4.a = ker4.p;
+ ker4.d = ker4.o;
+ ker4.g = ker4.n;
+ ker4.j = ker4.m;
+
+ oobReader.readPonm(ker4, -3);
+ ker4.b = ker4.p;
+ ker4.e = ker4.o;
+ ker4.h = ker4.n;
+ ker4.k = ker4.m;
+
+ oobReader.readPonm(ker4, -2);
+ ker4.c = ker4.p;
+ ker4.f = ker4.o;
+ ker4.i = ker4.n;
+ ker4.l = ker4.m;
+
+ oobReader.readPonm(ker4, -1);
{
const BlendResult res = preProcessCorners<ColorDistance>(ker4, cfg);
- clearAddTopL(preProcBuf[0], res.blend_k); //set 1st known corner for (0, yFirst)
+ clearAddTopL(preProcBuf[0], res.blend_i); //set 1st known corner for (0, yFirst)
}
for (int x = 0; x < srcWidth; ++x)
{
ker4.a = ker4.b; //shift previous kernel to the left
- ker4.e = ker4.f; // -----------------
- ker4.i = ker4.j; // | A | B | C | D |
- ker4.m = ker4.n; // |---|---|---|---|
- /**/ // | E | F | G | H | (x, yFirst - 1) is at position F
- ker4.b = ker4.c; // |---|---|---|---|
- ker4.f = ker4.g; // | I | J | K | L |
+ ker4.d = ker4.e; // -----------------
+ ker4.g = ker4.h; // | A | B | C | P |
ker4.j = ker4.k; // |---|---|---|---|
- ker4.n = ker4.o; // | M | N | O | P |
+ /**/ // | D | E | F | O | (x, yFirst - 1) is at position E
+ ker4.b = ker4.c; // |---|---|---|---|
+ ker4.e = ker4.f; // | G | H | I | N |
+ ker4.h = ker4.i; // |---|---|---|---|
+ ker4.k = ker4.l; // | J | K | L | M |
/**/ // -----------------
- ker4.c = ker4.d;
- ker4.g = ker4.h;
- ker4.k = ker4.l;
- ker4.o = ker4.p;
+ ker4.c = ker4.p;
+ ker4.f = ker4.o;
+ ker4.i = ker4.n;
+ ker4.l = ker4.m;
- oobReader.readDhlp(ker4, x);
+ oobReader.readPonm(ker4, x);
/* preprocessing blend result:
---------
- | F | G | evaluate corner between F, G, J, K
- |---+---| current input pixel is at position F
- | J | K |
+ | E | F | evaluate corner between E, F, H, I
+ |---+---| current input pixel is at position E
+ | H | I |
--------- */
const BlendResult res = preProcessCorners<ColorDistance>(ker4, cfg);
- addTopR(preProcBuf[x], res.blend_j); //set 2nd known corner for (x, yFirst)
+ addTopR(preProcBuf[x], res.blend_h); //set 2nd known corner for (x, yFirst)
if (x + 1 < srcWidth)
- clearAddTopL(preProcBuf[x + 1], res.blend_k); //set 1st known corner for (x + 1, yFirst)
+ clearAddTopL(preProcBuf[x + 1], res.blend_i); //set 1st known corner for (x + 1, yFirst)
}
}
//------------------------------------------------------------------------------------
@@ -612,85 +607,85 @@ void scaleImage(const uint32_t* src, uint32_t* trg, int srcWidth, int srcHeight,
//initialize at position x = -1
Kernel_4x4 ker4 = {};
- oobReader.readDhlp(ker4, -4); //hack: read a, e, i, m at x = -1
- ker4.a = ker4.d;
- ker4.e = ker4.h;
- ker4.i = ker4.l;
- ker4.m = ker4.p;
-
- oobReader.readDhlp(ker4, -3);
- ker4.b = ker4.d;
- ker4.f = ker4.h;
- ker4.j = ker4.l;
- ker4.n = ker4.p;
-
- oobReader.readDhlp(ker4, -2);
- ker4.c = ker4.d;
- ker4.g = ker4.h;
- ker4.k = ker4.l;
- ker4.o = ker4.p;
-
- oobReader.readDhlp(ker4, -1);
+ oobReader.readPonm(ker4, -4); //hack: read a, d, g, j at x = -1
+ ker4.a = ker4.p;
+ ker4.d = ker4.o;
+ ker4.g = ker4.n;
+ ker4.j = ker4.m;
+
+ oobReader.readPonm(ker4, -3);
+ ker4.b = ker4.p;
+ ker4.e = ker4.o;
+ ker4.h = ker4.n;
+ ker4.k = ker4.m;
+
+ oobReader.readPonm(ker4, -2);
+ ker4.c = ker4.p;
+ ker4.f = ker4.o;
+ ker4.i = ker4.n;
+ ker4.l = ker4.m;
+
+ oobReader.readPonm(ker4, -1);
unsigned char blend_xy1 = 0; //corner blending for current (x, y + 1) position
{
const BlendResult res = preProcessCorners<ColorDistance>(ker4, cfg);
- clearAddTopL(blend_xy1, res.blend_k); //set 1st known corner for (0, y + 1) and buffer for use on next column
+ clearAddTopL(blend_xy1, res.blend_i); //set 1st known corner for (0, y + 1) and buffer for use on next column
- addBottomL(preProcBuf[0], res.blend_g); //set 3rd known corner for (0, y)
+ addBottomL(preProcBuf[0], res.blend_f); //set 3rd known corner for (0, y)
}
for (int x = 0; x < srcWidth; ++x, out += Scaler::scale)
{
ker4.a = ker4.b; //shift previous kernel to the left
- ker4.e = ker4.f; // -----------------
- ker4.i = ker4.j; // | A | B | C | D |
- ker4.m = ker4.n; // |---|---|---|---|
- /**/ // | E | F | G | H | (x, y) is at position F
- ker4.b = ker4.c; // |---|---|---|---|
- ker4.f = ker4.g; // | I | J | K | L |
+ ker4.d = ker4.e; // -----------------
+ ker4.g = ker4.h; // | A | B | C | P |
ker4.j = ker4.k; // |---|---|---|---|
- ker4.n = ker4.o; // | M | N | O | P |
+ /**/ // | D | E | F | O | (x, y) is at position E
+ ker4.b = ker4.c; // |---|---|---|---|
+ ker4.e = ker4.f; // | G | H | I | N |
+ ker4.h = ker4.i; // |---|---|---|---|
+ ker4.k = ker4.l; // | J | K | L | M |
/**/ // -----------------
- ker4.c = ker4.d;
- ker4.g = ker4.h;
- ker4.k = ker4.l;
- ker4.o = ker4.p;
+ ker4.c = ker4.p;
+ ker4.f = ker4.o;
+ ker4.i = ker4.n;
+ ker4.l = ker4.m;
- oobReader.readDhlp(ker4, x);
+ oobReader.readPonm(ker4, x);
//evaluate the four corners on bottom-right of current pixel
unsigned char blend_xy = preProcBuf[x]; //for current (x, y) position
{
/* preprocessing blend result:
---------
- | F | G | evaluate corner between F, G, J, K
- |---+---| current input pixel is at position F
- | J | K |
+ | E | F | evaluate corner between E, F, H, I
+ |---+---| current input pixel is at position E
+ | H | I |
--------- */
const BlendResult res = preProcessCorners<ColorDistance>(ker4, cfg);
- addBottomR(blend_xy, res.blend_f); //all four corners of (x, y) have been determined at this point due to processing sequence!
+ addBottomR(blend_xy, res.blend_e); //all four corners of (x, y) have been determined at this point due to processing sequence!
- addTopR(blend_xy1, res.blend_j); //set 2nd known corner for (x, y + 1)
+ addTopR(blend_xy1, res.blend_h); //set 2nd known corner for (x, y + 1)
preProcBuf[x] = blend_xy1; //store on current buffer position for use on next row
[[likely]] if (x + 1 < srcWidth)
{
//blend_xy1 -> blend_x1y1
- clearAddTopL(blend_xy1, res.blend_k); //set 1st known corner for (x + 1, y + 1) and buffer for use on next column
+ clearAddTopL(blend_xy1, res.blend_i); //set 1st known corner for (x + 1, y + 1) and buffer for use on next column
- addBottomL(preProcBuf[x + 1], res.blend_g); //set 3rd known corner for (x + 1, y)
+ addBottomL(preProcBuf[x + 1], res.blend_f); //set 3rd known corner for (x + 1, y)
}
}
//fill block of size scale * scale with the given color
- fillBlock(out, trgWidth * sizeof(uint32_t), ker4.f, Scaler::scale, Scaler::scale);
+ fillBlock(out, trgWidth * sizeof(uint32_t), ker4.e, Scaler::scale, Scaler::scale);
//place *after* preprocessing step, to not overwrite the results while processing the last pixel!
//blend all four corners of current pixel
if (blendingNeeded(blend_xy))
{
- const auto& ker3 = reinterpret_cast<const Kernel_3x3&>(ker4); //"The Things We Do for Perf"
+ const Kernel_3x3& ker3 = ker4; //"The Things We Do for Perf"
blendPixel<Scaler, ColorDistance, ROT_0 >(ker3, out, trgWidth, blend_xy, cfg);
blendPixel<Scaler, ColorDistance, ROT_90 >(ker3, out, trgWidth, blend_xy, cfg);
blendPixel<Scaler, ColorDistance, ROT_180>(ker3, out, trgWidth, blend_xy, cfg);
@@ -800,8 +795,8 @@ struct Scaler3x : public ColorGradient
{
//model a round corner
alphaGrad<45, 100>(out.template ref<2, 2>(), col); //exact: 0.4545939598
- //alphaGrad<7, 256>(out.template ref<2, 1>(), col); //0.02826017254 -> negligible + avoid conflicts with other rotations for this odd scale
- //alphaGrad<7, 256>(out.template ref<1, 2>(), col); //0.02826017254
+ //alphaGrad<3, 100>(out.template ref<2, 1>(), col); //0.02826017254 -> negligible + avoid overlap with other rotations at this scale
+ //alphaGrad<3, 100>(out.template ref<1, 2>(), col); //0.02826017254
}
};
@@ -957,8 +952,8 @@ struct Scaler5x : public ColorGradient
alphaGrad<86, 100>(out.template ref<4, 4>(), col); //exact: 0.8631434088
alphaGrad<23, 100>(out.template ref<4, 3>(), col); //0.2306749731
alphaGrad<23, 100>(out.template ref<3, 4>(), col); //0.2306749731
- //alphaGrad<1, 64>(out.template ref<4, 2>(), col); //0.01676812367 -> negligible + avoid conflicts with other rotations for this odd scale
- //alphaGrad<1, 64>(out.template ref<2, 4>(), col); //0.01676812367
+ //alphaGrad<2, 100>(out.template ref<4, 2>(), col); //0.01676812367 -> negligible + avoid overlap with other rotations at this scale
+ //alphaGrad<2, 100>(out.template ref<2, 4>(), col); //0.01676812367
}
};
diff --git a/zen/basic_math.h b/zen/basic_math.h
index 8a32ee69..26dda9a6 100644
--- a/zen/basic_math.h
+++ b/zen/basic_math.h
@@ -14,6 +14,7 @@
#include <functional>
#include <cassert>
#include "type_traits.h"
+#include "legacy_compiler.h"
namespace numeric
@@ -53,17 +54,6 @@ double mad(RandomAccessIterator first, RandomAccessIterator last); //note: inval
template <class InputIterator>
double norm2(InputIterator first, InputIterator last);
-//constants
-const double pi = 3.14159265358979323846;
-const double e = 2.71828182845904523536;
-const double sqrt2 = 1.41421356237309504880;
-const double ln2 = 0.693147180559945309417;
-
-#if __cpp_lib_math_constants //C++20
- #error implement math constants from <numbers> header
-#endif
-//static_assert(pi + e + sqrt2 + ln2 == 7.9672352249818781, "whoopsie");
-
//----------------------------------------------------------------------------------
@@ -213,14 +203,14 @@ T power(T value)
inline
double radToDeg(double rad)
{
- return rad * 180.0 / numeric::pi;
+ return rad * (180.0 / std::numbers::pi);
}
inline
double degToRad(double degree)
{
- return degree * numeric::pi / 180.0;
+ return degree / (180.0 / std::numbers::pi);
}
diff --git a/zen/crc.h b/zen/crc.h
index df460a03..0570cced 100644
--- a/zen/crc.h
+++ b/zen/crc.h
@@ -64,38 +64,32 @@ uint32_t getCrc32(ByteIterator first, ByteIterator last) //https://en.wikipedia.
{
constexpr uint32_t crcTable[] =
{
- 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
- 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
- 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
- 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
- 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
- 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
- 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
- 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
- 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
- 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
- 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
- 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
- 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
- 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
- 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
- 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
- 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
- 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
- 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
- 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
- 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
- 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
- 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
- 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
- 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
- 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
- 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
- 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
- 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
- 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
- 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
- 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
+ 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
+ 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+ 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+ 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
+ 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
+ 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
+ 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+ 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
+ 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
+ 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
+ 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
+ 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+ 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+ 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
+ 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
+ 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
+ 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+ 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
+ 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
+ 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
+ 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};
static_assert(arraySize(crcTable) == 256 && arrayAccumulate<uint64_t>(crcTable) == 549755813760);
static_assert(sizeof(typename std::iterator_traits<ByteIterator>::value_type) == 1);
diff --git a/zen/dir_watcher.cpp b/zen/dir_watcher.cpp
index 94632ea4..307b48e5 100644
--- a/zen/dir_watcher.cpp
+++ b/zen/dir_watcher.cpp
@@ -85,7 +85,8 @@ DirWatcher::DirWatcher(const Zstring& dirPath) : //throw FileError
const ErrorCode ec = getLastError(); //copy before directly/indirectly making other system calls!
if (ec == ENOSPC) //fix misleading system message "No space left on device"
throw FileError(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtPath(subDirPath)),
- formatSystemError(L"inotify_add_watch", numberTo<std::wstring>(ec), L"The user limit on the total number of inotify watches was reached or the kernel failed to allocate a needed resource."));
+ formatSystemError(L"inotify_add_watch", L"ENOSPC",
+ L"The user limit on the total number of inotify watches was reached or the kernel failed to allocate a needed resource."));
throw FileError(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtPath(subDirPath)), formatSystemError(L"inotify_add_watch", ec));
}
diff --git a/zen/error_log.h b/zen/error_log.h
index cc52fc6e..ab23e33a 100644
--- a/zen/error_log.h
+++ b/zen/error_log.h
@@ -8,9 +8,7 @@
#define ERROR_LOG_H_8917590832147915
#include <cassert>
-#include <algorithm>
#include <vector>
-//#include <string>
#include "time.h"
#include "i18n.h"
#include "utf.h"
@@ -31,10 +29,10 @@ struct LogEntry
{
time_t time = 0;
MessageType type = MSG_TYPE_FATAL_ERROR;
- Zstringw message; //std::wstring may employ small string optimization: we cannot accept bloating the "ErrorLog::entries_" memory block below (think 1 million items)
+ Zstringc message; //conserve memory (=> avoid std::string SSO overhead!)
};
-std::wstring formatMessage(const LogEntry& entry);
+std::string formatMessage(const LogEntry& entry);
class ErrorLog
@@ -42,7 +40,14 @@ class ErrorLog
public:
void logMsg(const std::wstring& msg, MessageType type);
- int getItemCount(int typeFilter = MSG_TYPE_INFO | MSG_TYPE_WARNING | MSG_TYPE_ERROR | MSG_TYPE_FATAL_ERROR) const;
+ struct Stats
+ {
+ int info = 0;
+ int warning = 0;
+ int error = 0;
+ int fatal = 0;
+ };
+ Stats getStats() const;
//subset of std::vector<> interface:
using const_iterator = std::vector<LogEntry>::const_iterator;
@@ -65,59 +70,79 @@ private:
inline
void ErrorLog::logMsg(const std::wstring& msg, MessageType type)
{
- entries_.push_back({ std::time(nullptr), type, copyStringTo<Zstringw>(msg) });
+ entries_.push_back({ std::time(nullptr), type, utfTo<Zstringc>(msg) });
}
-inline
-int ErrorLog::getItemCount(int typeFilter) const
-{
- return static_cast<int>(std::count_if(entries_.begin(), entries_.end(), [typeFilter](const LogEntry& e) { return e.type & typeFilter; }));
-}
-
-inline
-std::wstring getMessageTypeLabel(MessageType type)
+inline
+ErrorLog::Stats ErrorLog::getStats() const
{
- switch (type)
+ Stats count;
+ for (const LogEntry& entry : entries_)
+ switch (entry.type)
{
case MSG_TYPE_INFO:
- return _("Info");
+ ++count.info;
+ break;
case MSG_TYPE_WARNING:
- return _("Warning");
+ ++count.warning;
+ break;
case MSG_TYPE_ERROR:
- return _("Error");
+ ++count.error;
+ break;
case MSG_TYPE_FATAL_ERROR:
- return _("Serious Error");
+ ++count.fatal;
+ break;
}
- assert(false);
- return std::wstring();
+ assert(static_cast<int>(entries_.size()) == count.info + count.warning + count.error + count.fatal);
+ return count;
+}
+
+
+inline
+std::wstring getMessageTypeLabel(MessageType type)
+{
+ switch (type)
+ {
+ case MSG_TYPE_INFO:
+ return _("Info");
+ case MSG_TYPE_WARNING:
+ return _("Warning");
+ case MSG_TYPE_ERROR:
+ return _("Error");
+ case MSG_TYPE_FATAL_ERROR:
+ return _("Serious Error");
+ }
+ assert(false);
+ return std::wstring();
}
inline
-std::wstring formatMessage(const LogEntry& entry)
+std::string formatMessage(const LogEntry& entry)
{
- std::wstring msgFmt = L"[" + formatTime<std::wstring>(FORMAT_TIME, getLocalTime(entry.time)) + L"] " + getMessageTypeLabel(entry.type) + L": ";
+ std::string msgFmt = '[' + utfTo<std::string>(formatTime(formatTimeTag, getLocalTime(entry.time))) + "] " + utfTo<std::string>(getMessageTypeLabel(entry.type)) + ": ";
const size_t prefixLen = unicodeLength(msgFmt); //consider Unicode!
- const Zstringw msg = trimCpy(entry.message);
- static_assert(std::is_same_v<decltype(msg), const Zstringw>, "don't worry about copying as long as we're using a ref-counted string!");
+ const Zstringc msg = trimCpy(entry.message);
+ static_assert(std::is_same_v<decltype(msg), const Zstringc>, "don't worry about copying as long as we're using a ref-counted string!");
for (auto it = msg.begin(); it != msg.end(); )
- if (*it == L'\n')
+ if (*it == '\n')
{
- msgFmt += L'\n';
- msgFmt.append(prefixLen, L' ');
+ msgFmt += '\n';
+ msgFmt.append(prefixLen, ' ');
++it;
//skip duplicate newlines
- for (;it != msg.end() && *it == L'\n'; ++it)
+ for (; it != msg.end() && *it == '\n'; ++it)
;
}
else
msgFmt += *it++;
- return msgFmt += L'\n';
+ msgFmt += '\n';
+ return msgFmt;
}
}
diff --git a/zen/file_access.cpp b/zen/file_access.cpp
index e23d48be..4f6704d2 100644
--- a/zen/file_access.cpp
+++ b/zen/file_access.cpp
@@ -311,7 +311,7 @@ void moveAndRenameFileSub(const Zstring& pathFrom, const Zstring& pathTo, bool r
{
auto throwException = [&](int ec)
{
- const std::wstring errorMsg = replaceCpy(replaceCpy(_("Cannot move file %x to %y."), L"%x", L"\n" + fmtPath(pathFrom)), L"%y", L"\n" + fmtPath(pathTo));
+ const std::wstring errorMsg = replaceCpy(replaceCpy(_("Cannot move file %x to %y."), L"%x", L'\n' + fmtPath(pathFrom)), L"%y", L'\n' + fmtPath(pathTo));
const std::wstring errorDescr = formatSystemError(L"rename", ec);
if (ec == EXDEV)
@@ -575,7 +575,7 @@ void zen::copySymlink(const Zstring& sourcePath, const Zstring& targetPath, bool
const Zstring linkPath = getSymlinkTargetRaw(sourcePath); //throw FileError; accept broken symlinks
if (::symlink(linkPath.c_str(), targetPath.c_str()) != 0)
- THROW_LAST_FILE_ERROR(replaceCpy(replaceCpy(_("Cannot copy symbolic link %x to %y."), L"%x", L"\n" + fmtPath(sourcePath)), L"%y", L"\n" + fmtPath(targetPath)), L"symlink");
+ THROW_LAST_FILE_ERROR(replaceCpy(replaceCpy(_("Cannot copy symbolic link %x to %y."), L"%x", L'\n' + fmtPath(sourcePath)), L"%y", L'\n' + fmtPath(targetPath)), L"symlink");
//allow only consistent objects to be created -> don't place before ::symlink(); targetPath may already exist!
ZEN_ON_SCOPE_FAIL(try { removeSymlinkPlain(targetPath); /*throw FileError*/ }
diff --git a/zen/file_io.cpp b/zen/file_io.cpp
index e788bcfe..b78259e0 100644
--- a/zen/file_io.cpp
+++ b/zen/file_io.cpp
@@ -68,7 +68,7 @@ FileBase::FileHandle openHandleForRead(const Zstring& filePath) //throw FileErro
return name + printNumber<std::wstring>(L"0%06o", m & S_IFMT);
}();
throw FileError(replaceCpy(_("Cannot open file %x."), L"%x", fmtPath(filePath)),
- _("Unsupported item type.") + L" [" + typeName + L"]");
+ _("Unsupported item type.") + L" [" + typeName + L']');
}
}
//else: let ::open() fail for errors like "not existing"
@@ -100,7 +100,7 @@ FileInput::FileInput(const Zstring& filePath, const IOCallback& notifyUnbuffered
size_t FileInput::tryRead(void* buffer, size_t bytesToRead) //throw FileError, ErrorFileLocked; may return short, only 0 means EOF!
{
if (bytesToRead == 0) //"read() with a count of 0 returns zero" => indistinguishable from end of file! => check!
- throw std::logic_error("Contract violation! " + std::string(__FILE__) + ":" + numberTo<std::string>(__LINE__));
+ throw std::logic_error("Contract violation! " + std::string(__FILE__) + ':' + numberTo<std::string>(__LINE__));
assert(bytesToRead == getBlockSize());
ssize_t bytesRead = 0;
@@ -215,7 +215,7 @@ FileOutput::~FileOutput()
size_t FileOutput::tryWrite(const void* buffer, size_t bytesToWrite) //throw FileError; may return short! CONTRACT: bytesToWrite > 0
{
if (bytesToWrite == 0)
- throw std::logic_error("Contract violation! " + std::string(__FILE__) + ":" + numberTo<std::string>(__LINE__));
+ throw std::logic_error("Contract violation! " + std::string(__FILE__) + ':' + numberTo<std::string>(__LINE__));
assert(bytesToWrite <= getBlockSize());
ssize_t bytesWritten = 0;
diff --git a/zen/file_io.h b/zen/file_io.h
index 54bde5aa..b47c6077 100644
--- a/zen/file_io.h
+++ b/zen/file_io.h
@@ -119,7 +119,7 @@ void saveBinContainer(const Zstring& filePath, const BinContainer& buffer, const
if (!buffer.empty())
{
/*snake oil?*/ fileOut.preAllocateSpaceBestEffort(buffer.size()); //throw FileError
- fileOut.write(&*buffer.begin(), buffer.size()); //throw FileError, X
+ fileOut.write(&buffer[0], buffer.size()); //throw FileError, X
}
fileOut.finalize(); //throw FileError, X
}
diff --git a/zen/format_unit.cpp b/zen/format_unit.cpp
index f2df4153..91a881dc 100644
--- a/zen/format_unit.cpp
+++ b/zen/format_unit.cpp
@@ -11,6 +11,7 @@
#include "i18n.h"
#include "time.h"
#include "globals.h"
+#include "utf.h"
#include <clocale> //thousands separator
#include "utf.h" //
@@ -115,7 +116,7 @@ std::wstring roundToBlock(double timeInHigh,
std::wstring output = formatUnitTime(roundedtimeInLow / unitLowPerHigh, unitHigh);
if (unitLowPerHigh > blockSizeLow)
- output += L" " + formatUnitTime(roundedtimeInLow % unitLowPerHigh, unitLow);
+ output += L' ' + formatUnitTime(roundedtimeInLow % unitLowPerHigh, unitLow);
return output;
}
}
@@ -194,7 +195,7 @@ std::wstring zen::formatUtcToLocalTime(time_t utcTime)
TimeComp loc = getLocalTime(utcTime);
- std::wstring dateString = formatTime<std::wstring>(L"%x %X", loc);
+ std::wstring dateString = utfTo<std::wstring>(formatTime(Zstr("%x %X"), loc));
return !dateString.empty() ? dateString : errorMsg();
}
diff --git a/zen/guid.h b/zen/guid.h
index 657ed07a..88059be8 100644
--- a/zen/guid.h
+++ b/zen/guid.h
@@ -26,8 +26,8 @@ std::string generateGUID() //creates a 16-byte GUID
#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 25) //getentropy() requires glibc 2.25 (ldd --version) PS: CentOS 7 is on 2.17
if (::getentropy(&guid[0], guid.size()) != 0) //"The maximum permitted value for the length argument is 256"
- throw std::runtime_error(std::string(__FILE__) + "[" + numberTo<std::string>(__LINE__) + "] Failed to generate GUID." +
- "\n" + utfTo<std::string>(formatSystemError(L"getentropy", errno)));
+ throw std::runtime_error(std::string(__FILE__) + '[' + numberTo<std::string>(__LINE__) + "] Failed to generate GUID." + "\n\n" +
+ utfTo<std::string>(formatSystemError(L"getentropy", errno)));
#else
class RandomGeneratorPosix
{
@@ -35,8 +35,8 @@ std::string generateGUID() //creates a 16-byte GUID
RandomGeneratorPosix()
{
if (fd_ == -1)
- throw std::runtime_error(std::string(__FILE__) + "[" + numberTo<std::string>(__LINE__) + "] Failed to generate GUID." +
- "\n" + utfTo<std::string>(formatSystemError(L"open", errno)));
+ throw std::runtime_error(std::string(__FILE__) + '[' + numberTo<std::string>(__LINE__) + "] Failed to generate GUID." + "\n\n" +
+ utfTo<std::string>(formatSystemError(L"open", errno)));
}
~RandomGeneratorPosix() { ::close(fd_); }
@@ -47,8 +47,8 @@ std::string generateGUID() //creates a 16-byte GUID
{
const ssize_t bytesRead = ::read(fd_, static_cast<char*>(buf) + offset, size - offset);
if (bytesRead < 1) //0 means EOF => error in this context (should check for buffer overflow, too?)
- throw std::runtime_error(std::string(__FILE__) + "[" + numberTo<std::string>(__LINE__) + "] Failed to generate GUID." +
- "\n" + utfTo<std::string>(formatSystemError(L"read", bytesRead < 0 ? errno : EIO)));
+ throw std::runtime_error(std::string(__FILE__) + '[' + numberTo<std::string>(__LINE__) + "] Failed to generate GUID." + "\n\n" +
+ utfTo<std::string>(formatSystemError(L"read", bytesRead < 0 ? errno : EIO)));
offset += bytesRead;
assert(offset <= size);
}
diff --git a/zen/http.cpp b/zen/http.cpp
index 8cd99d7a..c6a390de 100644
--- a/zen/http.cpp
+++ b/zen/http.cpp
@@ -19,7 +19,7 @@ class HttpInputStream::Impl
public:
Impl(const Zstring& url,
const std::string* postBuf /*issue POST if bound, GET otherwise*/,
- const Zstring& contentType, //required for POST
+ const std::string& contentType, //required for POST
bool disableGetCache /*not relevant for POST (= never cached)*/,
const Zstring& userAgent,
const Zstring* caCertFilePath /*optional: enable certificate validation*/,
@@ -37,9 +37,9 @@ public:
const bool useTls = [&]
{
- if (startsWithAsciiNoCase(url, Zstr("http://")))
+ if (startsWithAsciiNoCase(url, "http://"))
return false;
- if (startsWithAsciiNoCase(url, Zstr("https://")))
+ if (startsWithAsciiNoCase(url, "https://"))
return true;
throw SysError(L"URL uses unexpected protocol.");
}();
@@ -49,7 +49,7 @@ public:
std::map<std::string, std::string, LessAsciiNoCase> headers;
if (postBuf && !contentType.empty())
- headers["Content-Type"] = utfTo<std::string>(contentType);
+ headers["Content-Type"] = contentType;
if (useTls) //HTTP default port: 443, see %WINDIR%\system32\drivers\etc\services
{
@@ -96,7 +96,7 @@ public:
const size_t blockSize = std::min(static_cast<size_t>(1024), memBuf_.size()); //smaller block size: try to only read header part
buf.resize(buf.size() + blockSize);
const size_t bytesReceived = tryRead(&*(buf.end() - blockSize), blockSize); //throw SysError
- buf.resize(buf.size() - blockSize + bytesReceived); //caveat: unsigned arithmetics
+ buf.resize(buf.size() - (blockSize - bytesReceived)); //caveat: unsigned arithmetics
if (contains(buf, headerDelim))
{
@@ -122,8 +122,8 @@ public:
statusCode_ = stringTo<int>(statusItems[1]);
for (const std::string& line : split(headersBuf, "\r\n", SplitType::SKIP_EMPTY))
- responseHeaders_[trimCpy(beforeFirst(line, ":", IF_MISSING_RETURN_ALL))] =
- /**/ trimCpy(afterFirst (line, ":", IF_MISSING_RETURN_NONE));
+ responseHeaders_[trimCpy(beforeFirst(line, ':', IF_MISSING_RETURN_ALL))] =
+ /**/ trimCpy(afterFirst (line, ':', IF_MISSING_RETURN_NONE));
//try to get "Content-Length" header if available
if (const std::string* value = getHeader("Content-Length"))
@@ -236,7 +236,7 @@ namespace
{
std::unique_ptr<HttpInputStream::Impl> sendHttpRequestImpl(const Zstring& url,
const std::string* postBuf /*issue POST if bound, GET otherwise*/,
- const Zstring& contentType, //required for POST
+ const std::string& contentType, //required for POST
const Zstring& userAgent,
const Zstring* caCertFilePath /*optional: enable certificate validation*/,
const IOCallback& notifyUnbufferedIO) //throw SysError, X
@@ -248,8 +248,8 @@ std::unique_ptr<HttpInputStream::Impl> sendHttpRequestImpl(const Zstring& url,
auto response = std::make_unique<HttpInputStream::Impl>(urlRed, postBuf, contentType, false /*disableGetCache*/, userAgent, caCertFilePath, notifyUnbufferedIO); //throw SysError, X
//https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#3xx_Redirection
- const int httpStatusCode = response->getStatusCode();
- if (httpStatusCode / 100 == 3) //e.g. 301, 302, 303, 307... we're not too greedy since we check location, too!
+ const int httpStatus = response->getStatusCode();
+ if (httpStatus / 100 == 3) //e.g. 301, 302, 303, 307... we're not too greedy since we check location, too!
{
const std::string* value = response->getHeader("Location");
if (!value || value->empty())
@@ -259,8 +259,8 @@ std::unique_ptr<HttpInputStream::Impl> sendHttpRequestImpl(const Zstring& url,
}
else
{
- if (httpStatusCode != 200) //HTTP_STATUS_OK(200)
- throw SysError(formatHttpStatusCode(httpStatusCode)); //e.g. HTTP_STATUS_NOT_FOUND(404)
+ if (httpStatus != 200) //HTTP_STATUS_OK(200)
+ throw SysError(formatHttpStatus(httpStatus)); //e.g. HTTP_STATUS_NOT_FOUND(404)
return response;
}
@@ -340,19 +340,19 @@ std::vector<std::pair<std::string, std::string>> zen::xWwwFormUrlDecode(const st
HttpInputStream zen::sendHttpGet(const Zstring& url, const Zstring& userAgent, const Zstring* caCertFilePath, const IOCallback& notifyUnbufferedIO) //throw SysError, X
{
- return sendHttpRequestImpl(url, nullptr /*postBuf*/, Zstr("") /*contentType*/, userAgent, caCertFilePath, notifyUnbufferedIO); //throw SysError, X, X
+ return sendHttpRequestImpl(url, nullptr /*postBuf*/, "" /*contentType*/, userAgent, caCertFilePath, notifyUnbufferedIO); //throw SysError, X, X
}
HttpInputStream zen::sendHttpPost(const Zstring& url, const std::vector<std::pair<std::string, std::string>>& postParams,
const Zstring& userAgent, const Zstring* caCertFilePath, const IOCallback& notifyUnbufferedIO) //throw SysError, X
{
- return sendHttpPost(url, xWwwFormUrlEncode(postParams), Zstr("application/x-www-form-urlencoded"), userAgent, caCertFilePath, notifyUnbufferedIO); //throw SysError, X
+ return sendHttpPost(url, xWwwFormUrlEncode(postParams), "application/x-www-form-urlencoded", userAgent, caCertFilePath, notifyUnbufferedIO); //throw SysError, X
}
-HttpInputStream zen::sendHttpPost(const Zstring& url, const std::string& postBuf, const Zstring& contentType,
+HttpInputStream zen::sendHttpPost(const Zstring& url, const std::string& postBuf, const std::string& contentType,
const Zstring& userAgent, const Zstring* caCertFilePath, const IOCallback& notifyUnbufferedIO) //throw SysError, X
{
return sendHttpRequestImpl(url, &postBuf, contentType, userAgent, caCertFilePath, notifyUnbufferedIO); //throw SysError, X
@@ -365,7 +365,7 @@ bool zen::internetIsAlive() //noexcept
{
auto response = std::make_unique<HttpInputStream::Impl>(Zstr("http://www.google.com/"),
nullptr /*postParams*/,
- Zstr("") /*contentType*/,
+ "" /*contentType*/,
true /*disableGetCache*/,
Zstr("FreeFileSync"),
nullptr /*caCertFilePath*/,
@@ -380,7 +380,7 @@ bool zen::internetIsAlive() //noexcept
}
-std::wstring zen::formatHttpStatusCode(int sc)
+std::wstring zen::formatHttpStatus(int sc)
{
const wchar_t* statusText = [&] //https://en.wikipedia.org/wiki/List_of_HTTP_status_codes
{
@@ -462,13 +462,13 @@ std::wstring zen::formatHttpStatusCode(int sc)
}
-bool zen::isValidEmail(const Zstring& email)
+bool zen::isValidEmail(const std::string& email)
{
//https://en.wikipedia.org/wiki/Email_address#Syntax
//https://tools.ietf.org/html/rfc3696 => note errata! https://www.rfc-editor.org/errata_search.php?rfc=3696
//https://tools.ietf.org/html/rfc5321
- std::string local = utfTo<std::string>(beforeLast(email, Zstr('@'), IF_MISSING_RETURN_NONE));
- std::string domain = utfTo<std::string>( afterLast(email, Zstr('@'), IF_MISSING_RETURN_NONE));
+ std::string local = beforeLast(email, '@', IF_MISSING_RETURN_NONE);
+ std::string domain = afterLast(email, '@', IF_MISSING_RETURN_NONE);
//consider: "t@st"@email.com t\@st@email.com"
auto stripComments = [](std::string& part)
@@ -517,7 +517,7 @@ bool zen::isValidEmail(const Zstring& email)
}
-std::string zen::htmlSpecialChars(const std::string& str)
+std::string zen::htmlSpecialChars(const std::string_view& str)
{
//mirror PHP: https://github.com/php/php-src/blob/e99d5d39239c611e1e7304e79e88545c4e71a073/ext/standard/html_tables.h#L6189
std::string output;
diff --git a/zen/http.h b/zen/http.h
index fbaa09de..09395f8f 100644
--- a/zen/http.h
+++ b/zen/http.h
@@ -48,15 +48,15 @@ HttpInputStream sendHttpPost(const Zstring& url,
const IOCallback& notifyUnbufferedIO /*throw X*/); //throw SysError, X
HttpInputStream sendHttpPost(const Zstring& url,
- const std::string& postBuf, const Zstring& contentType,
+ const std::string& postBuf, const std::string& contentType,
const Zstring& userAgent,
const Zstring* caCertFilePath /*optional: enable certificate validation*/,
const IOCallback& notifyUnbufferedIO /*throw X*/); //throw SysError, X
bool internetIsAlive(); //noexcept
-std::wstring formatHttpStatusCode(int httpStatusCode);
-bool isValidEmail(const Zstring& email);
-std::string htmlSpecialChars(const std::string& str);
+std::wstring formatHttpStatus(int httpStatus);
+bool isValidEmail(const std::string& email);
+std::string htmlSpecialChars(const std::string_view& str);
std::string xWwwFormUrlEncode(const std::vector<std::pair<std::string, std::string>>& paramPairs);
std::vector<std::pair<std::string, std::string>> xWwwFormUrlDecode(const std::string& str);
diff --git a/zen/legacy_compiler.h b/zen/legacy_compiler.h
index 54dd7f59..8d44f3f7 100644
--- a/zen/legacy_compiler.h
+++ b/zen/legacy_compiler.h
@@ -8,11 +8,6 @@
#define LEGACY_COMPILER_H_839567308565656789
-#if !__cpp_lib_erase_if
- #include <vector>
- #include <set>
- #include <map>
-#endif
//https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations
@@ -58,8 +53,18 @@ private:
T* const data_;
};
-//---------------------------------------------------------------------------------
+#if __cpp_lib_math_constants
+ #error get rid of workaround:
+#endif
+
+namespace numbers
+{
+const double pi = 3.14159265358979323846;
+const double e = 2.71828182845904523536;
+const double sqrt2 = 1.41421356237309504880;
+const double ln2 = 0.693147180559945309417;
+}
}
diff --git a/zen/open_ssl.cpp b/zen/open_ssl.cpp
index dc9c8a19..b823f8ca 100644
--- a/zen/open_ssl.cpp
+++ b/zen/open_ssl.cpp
@@ -322,8 +322,8 @@ std::string createSignature(const std::string& message, EVP_PKEY* privateKey) //
reinterpret_cast<unsigned char*>(&signature[0]), //unsigned char* sigret,
&sigLen) != 1) //size_t* siglen
throw SysError(formatLastOpenSSLError(L"EVP_DigestSignFinal"));
- signature.resize(sigLen);
+ signature.resize(sigLen);
return signature;
}
@@ -373,7 +373,7 @@ void zen::verifySignature(const std::string& message, const std::string& signatu
namespace
{
-std::wstring formatSslErrorRaw(int ec)
+std::wstring formatSslErrorCode(int ec)
{
switch (ec)
{
@@ -388,12 +388,15 @@ std::wstring formatSslErrorRaw(int ec)
ZEN_CHECK_CASE_FOR_CONSTANT(SSL_ERROR_WANT_ACCEPT);
ZEN_CHECK_CASE_FOR_CONSTANT(SSL_ERROR_WANT_ASYNC);
ZEN_CHECK_CASE_FOR_CONSTANT(SSL_ERROR_WANT_ASYNC_JOB);
+ ZEN_CHECK_CASE_FOR_CONSTANT(SSL_ERROR_WANT_CLIENT_HELLO_CB);
+
+ default:
+ return replaceCpy<std::wstring>(L"SSL error %x", L"%x", numberTo<std::wstring>(ec));
}
- return L"Unknown SSL error: " + numberTo<std::wstring>(ec);
}
-std::wstring formatX509ErrorRaw(long ec)
+std::wstring formatX509ErrorCode(long ec)
{
switch (ec)
{
@@ -473,8 +476,10 @@ std::wstring formatX509ErrorRaw(long ec)
ZEN_CHECK_CASE_FOR_CONSTANT(X509_V_ERR_OCSP_VERIFY_NEEDED);
ZEN_CHECK_CASE_FOR_CONSTANT(X509_V_ERR_OCSP_VERIFY_FAILED);
ZEN_CHECK_CASE_FOR_CONSTANT(X509_V_ERR_OCSP_CERT_UNKNOWN);
+
+ default:
+ return replaceCpy<std::wstring>(L"X509 error %x", L"%x", numberTo<std::wstring>(ec));
}
- return L"Unknown X509 error: " + numberTo<std::wstring>(ec);
}
}
@@ -487,7 +492,7 @@ public:
{
ZEN_ON_SCOPE_FAIL(cleanup(); /*destructor call would lead to member double clean-up!!!*/);
- ctx_ = ::SSL_CTX_new(TLS_client_method());
+ ctx_ = ::SSL_CTX_new(::TLS_client_method());
if (!ctx_)
throw SysError(formatLastOpenSSLError(L"SSL_CTX_new"));
@@ -526,13 +531,13 @@ public:
const int rv = ::SSL_connect(ssl_); //implicitly calls SSL_set_connect_state()
if (rv != 1)
- throw SysError(formatLastOpenSSLError(L"SSL_connect") + L" " + formatSslErrorRaw(::SSL_get_error(ssl_, rv)));
+ throw SysError(formatLastOpenSSLError(L"SSL_connect") + L' ' + formatSslErrorCode(::SSL_get_error(ssl_, rv)));
if (caCertFilePath)
{
const long verifyResult = ::SSL_get_verify_result(ssl_);
if (verifyResult != X509_V_OK)
- throw SysError(formatSystemError(L"SSL_get_verify_result", formatX509ErrorRaw(verifyResult), L""));
+ throw SysError(formatSystemError(L"SSL_get_verify_result", formatX509ErrorCode(verifyResult), L""));
}
}
@@ -554,7 +559,7 @@ public:
size_t tryRead(void* buffer, size_t bytesToRead) //throw SysError; may return short, only 0 means EOF!
{
if (bytesToRead == 0) //"read() with a count of 0 returns zero" => indistinguishable from end of file! => check!
- throw std::logic_error("Contract violation! " + std::string(__FILE__) + ":" + numberTo<std::string>(__LINE__));
+ throw std::logic_error("Contract violation! " + std::string(__FILE__) + ':' + numberTo<std::string>(__LINE__));
size_t bytesReceived = 0;
const int rv = ::SSL_read_ex(ssl_, buffer, bytesToRead, &bytesReceived);
@@ -564,7 +569,7 @@ public:
if (sslError == SSL_ERROR_ZERO_RETURN || //EOF + close_notify alert
(sslError == SSL_ERROR_SYSCALL && ::ERR_peek_last_error() == 0)) //EOF: only expected for HTTP/1.0
return 0;
- throw SysError(formatLastOpenSSLError(L"SSL_read_ex") + L" " + formatSslErrorRaw(sslError));
+ throw SysError(formatLastOpenSSLError(L"SSL_read_ex") + L' ' + formatSslErrorCode(sslError));
}
assert(bytesReceived > 0); //SSL_read_ex() considers EOF an error!
if (bytesReceived > bytesToRead) //better safe than sorry
@@ -576,12 +581,12 @@ public:
size_t tryWrite(const void* buffer, size_t bytesToWrite) //throw SysError; may return short! CONTRACT: bytesToWrite > 0
{
if (bytesToWrite == 0)
- throw std::logic_error("Contract violation! " + std::string(__FILE__) + ":" + numberTo<std::string>(__LINE__));
+ throw std::logic_error("Contract violation! " + std::string(__FILE__) + ':' + numberTo<std::string>(__LINE__));
size_t bytesWritten = 0;
const int rv = ::SSL_write_ex(ssl_, buffer, bytesToWrite, &bytesWritten);
if (rv != 1)
- throw SysError(formatLastOpenSSLError(L"SSL_write_ex") + L" " + formatSslErrorRaw(::SSL_get_error(ssl_, rv)));
+ throw SysError(formatLastOpenSSLError(L"SSL_write_ex") + L' ' + formatSslErrorCode(::SSL_get_error(ssl_, rv)));
if (bytesWritten > bytesToWrite)
throw SysError(L"SSL_write_ex: buffer overflow.");
@@ -759,7 +764,7 @@ std::string zen::convertPuttyKeyToPkix(const std::string& keyStream, const std::
auto numToBeString = [](size_t n) -> std::string
{
- static_assert(usingLittleEndian()&& sizeof(n) >= 4);
+ static_assert(usingLittleEndian() && sizeof(n) >= 4);
const char* numStr = reinterpret_cast<const char*>(&n);
return { numStr[3], numStr[2], numStr[1], numStr[0] }; //big endian!
};
diff --git a/zen/perf.h b/zen/perf.h
index b6cb5bb0..9f368016 100644
--- a/zen/perf.h
+++ b/zen/perf.h
@@ -98,7 +98,7 @@ public:
const int64_t timeMs = std::chrono::duration_cast<std::chrono::milliseconds>(watch_.elapsed()).count();
const std::string msg = numberTo<std::string>(timeMs) + " ms";
- std::clog << "Perf: duration: " << msg << "\n";
+ std::clog << "Perf: duration: " << msg << '\n';
resultShown_ = true;
}
diff --git a/zen/recycler.cpp b/zen/recycler.cpp
index dc156a6f..f4fd870b 100644
--- a/zen/recycler.cpp
+++ b/zen/recycler.cpp
@@ -45,7 +45,9 @@ bool zen::recycleOrDeleteIfExists(const Zstring& itemPath) //throw FileError
return true;
}
- throw FileError(errorMsg, formatSystemError(L"g_file_trash", replaceCpy(_("Error Code %x"), L"%x", numberTo<std::wstring>(error->code)), utfTo<std::wstring>(error->message)));
+ throw FileError(errorMsg, formatSystemError(L"g_file_trash",
+ replaceCpy(_("Error Code %x"), L"%x", numberTo<std::wstring>(error->code)),
+ utfTo<std::wstring>(error->message)));
//g_quark_to_string(error->domain)
}
return true;
diff --git a/zen/serialize.h b/zen/serialize.h
index dd884e3b..1eabcdec 100644
--- a/zen/serialize.h
+++ b/zen/serialize.h
@@ -25,35 +25,6 @@ namespace zen
binary container for data storage: must support "basic" std::vector interface (e.g. std::vector<std::byte>, std::string, Zbase<char>)
*/
-//binary container reference implementations
-using Utf8String = Zbase<char>; //ref-counted + COW text stream + guaranteed performance: exponential growth
-class ByteArray; //ref-counted byte stream + guaranteed performance: exponential growth -> no COW, but 12% faster than Utf8String (due to no null-termination?)
-
-
-class ByteArray //essentially a std::vector<std::byte> with ref-counted semantics, but no COW! => *almost* value type semantics, but not quite
-{
-public:
- using value_type = std::vector<std::byte>::value_type;
- using iterator = std::vector<std::byte>::iterator;
- using const_iterator = std::vector<std::byte>::const_iterator;
-
- iterator begin() { return buffer_.ref().begin(); }
- iterator end () { return buffer_.ref().end (); }
-
- const_iterator begin() const { return buffer_.ref().begin(); }
- const_iterator end () const { return buffer_.ref().end (); }
-
- void resize(size_t len) { buffer_.ref().resize(len); }
- size_t size() const { return buffer_.ref().size(); }
- bool empty() const { return buffer_.ref().empty(); }
-
- inline friend bool operator==(const ByteArray& lhs, const ByteArray& rhs) { return lhs.buffer_.ref() == rhs.buffer_.ref(); }
-
-private:
- SharedRef<std::vector<std::byte>> buffer_ = makeSharedRef<std::vector<std::byte>>();
- //perf: shared_ptr indirection irrelevant: less than 1% slower!
-};
-
/*
-------------------------------
|Buffered Input Stream Concept|
@@ -158,6 +129,7 @@ struct MemoryStreamOut
}
const BinContainer& ref() const { return buffer_; }
+ /**/ BinContainer& ref() { return buffer_; }
private:
MemoryStreamOut (const MemoryStreamOut&) = delete;
@@ -180,7 +152,7 @@ void bufferedStreamCopy(BufferedInputStream& streamIn, //throw X
{
const size_t blockSize = streamIn.getBlockSize();
if (blockSize == 0)
- throw std::logic_error("Contract violation! " + std::string(__FILE__) + ":" + numberTo<std::string>(__LINE__));
+ throw std::logic_error("Contract violation! " + std::string(__FILE__) + ':' + numberTo<std::string>(__LINE__));
std::vector<std::byte> buffer(blockSize);
for (;;)
@@ -201,7 +173,7 @@ BinContainer bufferedLoad(BufferedInputStream& streamIn) //throw X
const size_t blockSize = streamIn.getBlockSize();
if (blockSize == 0)
- throw std::logic_error("Contract violation! " + std::string(__FILE__) + ":" + numberTo<std::string>(__LINE__));
+ throw std::logic_error("Contract violation! " + std::string(__FILE__) + ':' + numberTo<std::string>(__LINE__));
BinContainer buffer;
for (;;)
@@ -238,7 +210,7 @@ void writeContainer(BufferedOutputStream& stream, const C& cont) //don't even co
const auto len = cont.size();
writeNumber(stream, static_cast<uint32_t>(len));
if (len > 0)
- writeArray(stream, &*cont.begin(), sizeof(typename C::value_type) * len); //don't use c_str(), but access uniformly via STL interface
+ writeArray(stream, &cont[0], sizeof(typename C::value_type) * len); //don't use c_str(), but access uniformly via STL interface
}
@@ -276,7 +248,7 @@ C readContainer(BufferedInputStream& stream) //throw UnexpectedEndOfStreamError
catch (std::length_error&) { throw UnexpectedEndOfStreamError(); } //most likely this is due to data corruption!
catch ( std::bad_alloc&) { throw UnexpectedEndOfStreamError(); } //
- readArray(stream, &*cont.begin(), sizeof(typename C::value_type) * strLength); //throw UnexpectedEndOfStreamError
+ readArray(stream, &cont[0], sizeof(typename C::value_type) * strLength); //throw UnexpectedEndOfStreamError
}
return cont;
}
diff --git a/zen/shell_execute.h b/zen/shell_execute.h
index 580c4558..faea4bd9 100644
--- a/zen/shell_execute.h
+++ b/zen/shell_execute.h
@@ -74,7 +74,7 @@ int shellExecute(const Zstring& command, ExecutionType type, bool hideConsole) /
std::string getCommandOutput(const Zstring& command) //throw SysError
{
//https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/popen.3.html
- FILE* pipe = ::popen(command.c_str(), "r");
+ FILE* pipe = ::popen(command.c_str(), "r");
if (!pipe)
THROW_LAST_SYS_ERROR(L"popen");
ZEN_ON_SCOPE_EXIT(::pclose(pipe));
@@ -97,7 +97,7 @@ std::string getCommandOutput(const Zstring& command) //throw SysError
output.resize(output.size() - (blockSize - bytesRead)); //caveat: unsigned arithmetics
}
while (!::feof(pipe));
-
+
return output;
}
}
diff --git a/zen/socket.h b/zen/socket.h
index 827d446b..3bd0a2a0 100644
--- a/zen/socket.h
+++ b/zen/socket.h
@@ -89,7 +89,7 @@ namespace
size_t tryReadSocket(SocketType socket, void* buffer, size_t bytesToRead) //throw SysError; may return short, only 0 means EOF!
{
if (bytesToRead == 0) //"read() with a count of 0 returns zero" => indistinguishable from end of file! => check!
- throw std::logic_error("Contract violation! " + std::string(__FILE__) + ":" + numberTo<std::string>(__LINE__));
+ throw std::logic_error("Contract violation! " + std::string(__FILE__) + ':' + numberTo<std::string>(__LINE__));
int bytesReceived = 0;
for (;;)
@@ -114,7 +114,7 @@ size_t tryReadSocket(SocketType socket, void* buffer, size_t bytesToRead) //thro
size_t tryWriteSocket(SocketType socket, const void* buffer, size_t bytesToWrite) //throw SysError; may return short! CONTRACT: bytesToWrite > 0
{
if (bytesToWrite == 0)
- throw std::logic_error("Contract violation! " + std::string(__FILE__) + ":" + numberTo<std::string>(__LINE__));
+ throw std::logic_error("Contract violation! " + std::string(__FILE__) + ':' + numberTo<std::string>(__LINE__));
int bytesWritten = 0;
for (;;)
diff --git a/zen/string_base.h b/zen/string_base.h
index 6c835c72..d2e00baf 100644
--- a/zen/string_base.h
+++ b/zen/string_base.h
@@ -221,6 +221,7 @@ public:
Zbase();
Zbase(const Char* str) : Zbase(str, str + strLength(str)) {} //implicit conversion from a C-string!
Zbase(const Char* str, size_t len) : Zbase(str, str + len) {}
+ Zbase(size_t count, Char fillChar);
Zbase(const Zbase& str);
Zbase(Zbase&& tmp) noexcept;
template <class InputIterator>
@@ -251,7 +252,8 @@ public:
size_t length() const;
size_t size () const { return length(); }
const Char* c_str() const { return rawStr_; } //C-string format with 0-termination
- const Char operator[](size_t pos) const;
+ const Char& operator[](size_t pos) const;
+ /**/ Char& operator[](size_t pos);
bool empty() const { return length() == 0; }
void clear();
size_t find (const Zbase& str, size_t pos = 0) const; //
@@ -283,10 +285,11 @@ public:
static const size_t npos = static_cast<size_t>(-1);
private:
- Zbase (int) = delete; //
- Zbase& operator= (int) = delete; //detect usage errors by creating an intentional ambiguity with "Char"
- Zbase& operator+=(int) = delete; //
- void push_back (int) = delete; //
+ Zbase (int) = delete; //
+ Zbase(size_t count, int) = delete; //
+ Zbase& operator= (int) = delete; //detect usage errors by creating an intentional ambiguity with "Char"
+ Zbase& operator+= (int) = delete; //
+ void push_back (int) = delete; //
Char* rawStr_;
};
@@ -360,6 +363,15 @@ Zbase<Char, SP>::Zbase(InputIterator first, InputIterator last)
template <class Char, template <class> class SP> inline
+Zbase<Char, SP>::Zbase(size_t count, Char fillChar)
+{
+ rawStr_ = this->create(count);
+ std::fill(rawStr_, rawStr_ + count, fillChar);
+ rawStr_[count] = 0;
+}
+
+
+template <class Char, template <class> class SP> inline
Zbase<Char, SP>::Zbase(const Zbase<Char, SP>& str)
{
rawStr_ = this->clone(str.rawStr_);
@@ -544,7 +556,15 @@ size_t Zbase<Char, SP>::length() const
template <class Char, template <class> class SP> inline
-const Char Zbase<Char, SP>::operator[](size_t pos) const
+const Char& Zbase<Char, SP>::operator[](size_t pos) const
+{
+ assert(pos < length()); //design by contract! no runtime check!
+ return rawStr_[pos];
+}
+
+
+template <class Char, template <class> class SP> inline
+Char& Zbase<Char, SP>::operator[](size_t pos)
{
assert(pos < length()); //design by contract! no runtime check!
return rawStr_[pos];
diff --git a/zen/string_tools.h b/zen/string_tools.h
index 5c444830..40a4ea52 100644
--- a/zen/string_tools.h
+++ b/zen/string_tools.h
@@ -167,8 +167,8 @@ Char asciiToLower(Char c)
}
-template <class Char> inline
-Char asciiToUpper(Char c)
+ template <class Char> inline
+ Char asciiToUpper(Char c)
{
if (static_cast<Char>('a') <= c && c <= static_cast<Char>('z'))
return static_cast<Char>(c - static_cast<Char>('a') + static_cast<Char>('A'));
@@ -182,13 +182,13 @@ inline int strcmpWithNulls(const char* ptr1, const char* ptr2, size_t num)
inline int strcmpWithNulls(const wchar_t* ptr1, const wchar_t* ptr2, size_t num) { return std::wmemcmp(ptr1, ptr2, num); } //
-template <class Char> inline
-int strcmpAsciiNoCase(const Char* lhs, const Char* rhs, size_t len)
+template <class Char1, class Char2> inline
+int strcmpAsciiNoCase(const Char1* lhs, const Char2* rhs, size_t len)
{
while (len-- > 0)
{
- const Char charL = asciiToLower(*lhs++); //ordering: lower-case chars have higher code points than uppper-case
- const Char charR = asciiToLower(*rhs++); //
+ const Char1 charL = asciiToLower(*lhs++); //ordering: lower-case chars have higher code points than uppper-case
+ const Char2 charR = asciiToLower(*rhs++); //
if (charL != charR)
return static_cast<unsigned int>(charL) - static_cast<unsigned int>(charR); //unsigned char-comparison is the convention!
//unsigned underflow is well-defined!
diff --git a/zen/string_traits.h b/zen/string_traits.h
index f1269130..69d76b44 100644
--- a/zen/string_traits.h
+++ b/zen/string_traits.h
@@ -220,7 +220,8 @@ auto makeStringView(Iterator first, Iterator last)
last - first);
}
-template <class Iterator> inline auto makeStringView(Iterator first, size_t len) { return makeStringView(first, first + len); }
+template <class Iterator> inline
+auto makeStringView(Iterator first, size_t len) { return makeStringView(first, first + len); }
}
#endif //STRING_TRAITS_H_813274321443234
diff --git a/zen/sys_error.cpp b/zen/sys_error.cpp
index 2acaca1d..b802780b 100644
--- a/zen/sys_error.cpp
+++ b/zen/sys_error.cpp
@@ -4,3 +4,187 @@
// * Copyright (C) Zenju (zenju AT freefilesync DOT org) - All Rights Reserved *
// *****************************************************************************
+#include "sys_error.h"
+ #include <cstring>
+
+using namespace zen;
+
+
+
+
+std::wstring zen::getSystemErrorDescription(ErrorCode ec) //return empty string on error
+{
+ const ErrorCode currentError = getLastError(); //not necessarily == ec
+ ZEN_ON_SCOPE_EXIT(errno = currentError);
+
+ std::wstring errorMsg;
+ errorMsg = utfTo<std::wstring>(::strerror(ec));
+ return trimCpy(errorMsg); //Windows messages seem to end with a space...
+}
+
+
+namespace
+{
+std::wstring formatSystemErrorCode(ErrorCode ec)
+{
+ switch (ec) //pretty much all codes currently used on CentOS 7 and macOS 10.15
+ {
+ ZEN_CHECK_CASE_FOR_CONSTANT(EPERM);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENOENT);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ESRCH);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EINTR);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EIO);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENXIO);
+ ZEN_CHECK_CASE_FOR_CONSTANT(E2BIG);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENOEXEC);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EBADF);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ECHILD);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EAGAIN);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENOMEM);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EACCES);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EFAULT);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENOTBLK);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EBUSY);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EEXIST);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EXDEV);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENODEV);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENOTDIR);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EISDIR);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EINVAL);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENFILE);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EMFILE);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENOTTY);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ETXTBSY);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EFBIG);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENOSPC);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ESPIPE);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EROFS);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EMLINK);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EPIPE);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EDOM);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ERANGE);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EDEADLK);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENAMETOOLONG);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENOLCK);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENOSYS);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENOTEMPTY);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ELOOP);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENOMSG);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EIDRM);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENOSTR);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENODATA);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ETIME);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENOSR);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EREMOTE);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENOLINK);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EPROTO);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EMULTIHOP);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EBADMSG);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EOVERFLOW);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EILSEQ);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EUSERS);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENOTSOCK);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EDESTADDRREQ);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EMSGSIZE);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EPROTOTYPE);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENOPROTOOPT);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EPROTONOSUPPORT);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ESOCKTNOSUPPORT);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENOTSUP);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EPFNOSUPPORT);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EAFNOSUPPORT);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EADDRINUSE);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EADDRNOTAVAIL);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENETDOWN);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENETUNREACH);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENETRESET);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ECONNABORTED);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ECONNRESET);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENOBUFS);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EISCONN);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENOTCONN);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ESHUTDOWN);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ETOOMANYREFS);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ETIMEDOUT);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ECONNREFUSED);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EHOSTDOWN);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EHOSTUNREACH);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EALREADY);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EINPROGRESS);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ESTALE);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EDQUOT);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ECANCELED);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EOWNERDEAD);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENOTRECOVERABLE);
+
+ ZEN_CHECK_CASE_FOR_CONSTANT(ECHRNG);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EL2NSYNC);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EL3HLT);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EL3RST);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ELNRNG);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EUNATCH);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENOCSI);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EL2HLT);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EBADE);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EBADR);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EXFULL);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENOANO);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EBADRQC);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EBADSLT);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EBFONT);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENONET);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENOPKG);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EADV);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ESRMNT);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ECOMM);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EDOTDOT);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENOTUNIQ);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EBADFD);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EREMCHG);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ELIBACC);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ELIBBAD);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ELIBSCN);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ELIBMAX);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ELIBEXEC);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ERESTART);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ESTRPIPE);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EUCLEAN);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENOTNAM);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENAVAIL);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EISNAM);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EREMOTEIO);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENOMEDIUM);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EMEDIUMTYPE);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ENOKEY);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EKEYEXPIRED);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EKEYREVOKED);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EKEYREJECTED);
+ ZEN_CHECK_CASE_FOR_CONSTANT(ERFKILL);
+ ZEN_CHECK_CASE_FOR_CONSTANT(EHWPOISON);
+ default:
+ return replaceCpy(_("Error Code %x"), L"%x", numberTo<std::wstring>(ec));
+ }
+}
+}
+
+
+std::wstring zen::formatSystemError(const std::wstring& functionName, ErrorCode ec)
+{
+ return formatSystemError(functionName, formatSystemErrorCode(ec), getSystemErrorDescription(ec));
+}
+
+
+std::wstring zen::formatSystemError(const std::wstring& functionName, const std::wstring& errorCode, const std::wstring& errorMsg)
+{
+ std::wstring output = errorCode + L':';
+
+ const std::wstring errorMsgFmt = trimCpy(errorMsg);
+ if (!errorMsgFmt.empty())
+ {
+ output += L' ';
+ output += errorMsgFmt;
+ }
+
+ output += L" [" + functionName + L']';
+ return output;
+}
diff --git a/zen/sys_error.h b/zen/sys_error.h
index a9347bdd..6bef45ea 100644
--- a/zen/sys_error.h
+++ b/zen/sys_error.h
@@ -8,11 +8,10 @@
#define SYS_ERROR_H_3284791347018951324534
#include <string>
-#include "utf.h"
-#include "i18n.h"
#include "scope_guard.h"
+#include "i18n.h"
+#include "utf.h"
- #include <cstring>
#include <cerrno>
@@ -23,9 +22,8 @@ namespace zen
ErrorCode getLastError();
-std::wstring formatSystemError(const std::wstring& functionName, ErrorCode ec);
std::wstring formatSystemError(const std::wstring& functionName, const std::wstring& errorCode, const std::wstring& errorMsg);
-
+std::wstring formatSystemError(const std::wstring& functionName, ErrorCode ec);
//A low-level exception class giving (non-translated) detail information only - same conceptional level like "GetLastError()"!
@@ -47,11 +45,6 @@ private:
do { const ErrorCode ecInternal = getLastError(); throw SysError(formatSystemError(functionName, ecInternal)); } while (false)
-//helper for error checking macros:
-inline bool validatBool(bool b) { return b; }
-inline bool validatBool(void* b) { return b != nullptr; }
-bool validatBool(int) = delete; //catch unintended bool conversions, e.g. HRESULT
-
@@ -59,56 +52,15 @@ bool validatBool(int) = delete; //catch unintended bool conversions, e.g. HRESUL
inline
ErrorCode getLastError()
{
- return errno; //don't use "::", errno is a macro!
+ return errno; //don't use "::" prefix, errno is a macro!
}
-std::wstring formatSystemErrorRaw(long long) = delete; //intentional overload ambiguity to catch usage errors
-
-inline
-std::wstring formatSystemErrorRaw(ErrorCode ec) //return empty string on error
-{
- const ErrorCode currentError = getLastError(); //not necessarily == lastError
-
- std::wstring errorMsg;
- ZEN_ON_SCOPE_EXIT(errno = currentError);
-
- errorMsg = utfTo<std::wstring>(::strerror(ec));
- trim(errorMsg); //Windows messages seem to end with a blank...
-
- return errorMsg;
-}
+std::wstring getSystemErrorDescription(ErrorCode ec); //return empty string on error
+//intentional overload ambiguity to catch usage errors with HRESULT:
+std::wstring getSystemErrorDescription(long long) = delete;
-std::wstring formatSystemError(const std::wstring& functionName, long long lastError) = delete; //intentional overload ambiguity to catch usage errors with HRESULT!
-
-inline
-std::wstring formatSystemError(const std::wstring& functionName, ErrorCode ec)
-{
- const std::wstring errorCode = numberTo<std::wstring>(ec);
- const std::wstring errorDescr = formatSystemErrorRaw(ec);
-
- return formatSystemError(functionName, replaceCpy(_("Error Code %x"), L"%x", errorCode), errorDescr);
-}
-
-
-inline
-std::wstring formatSystemError(const std::wstring& functionName, const std::wstring& errorCode, const std::wstring& errorMsg)
-{
- std::wstring output = errorCode + L":";
-
- const std::wstring errorMsgFmt = trimCpy(errorMsg);
- if (!errorMsgFmt.empty())
- {
- output += L" ";
- output += errorMsgFmt;
- }
-
- output += L" [" + functionName + L"]";
-
- return output;
-}
-
}
#endif //SYS_ERROR_H_3284791347018951324534
diff --git a/zen/system.cpp b/zen/system.cpp
index 5945484f..9401b94f 100644
--- a/zen/system.cpp
+++ b/zen/system.cpp
@@ -44,6 +44,7 @@ namespace
ComputerModel zen::getComputerModel() //throw FileError
{
+ ComputerModel cm;
try
{
auto tryGetInfo = [](const Zstring& filePath)
@@ -57,9 +58,33 @@ ComputerModel zen::getComputerModel() //throw FileError
}
catch (const FileError& e) { throw SysError(e.toString()); } //errors should be further enriched by context info => SysError
};
- return { tryGetInfo("/sys/devices/virtual/dmi/id/product_name"), //throw SysError
- tryGetInfo("/sys/devices/virtual/dmi/id/sys_vendor") }; //
+ cm.model = tryGetInfo("/sys/devices/virtual/dmi/id/product_name"); //throw SysError
+ cm.vendor = tryGetInfo("/sys/devices/virtual/dmi/id/sys_vendor"); //
+
+ //clean up:
+ for (const char* dummyModel :
+ {
+ "To Be Filled By O.E.M.", "Default string", "empty", "O.E.M", "OEM", "NA",
+ "System Product Name", "Please change product name", "INVALID",
+ })
+ if (equalAsciiNoCase(cm.model, dummyModel))
+ {
+ cm.model.clear();
+ break;
+ }
+
+ for (const char* dummyVendor :
+ {
+ "To Be Filled By O.E.M.", "Default string", "empty", "O.E.M", "OEM", "NA",
+ "System manufacturer", "OEM Manufacturer",
+ })
+ if (equalAsciiNoCase(cm.vendor, dummyVendor))
+ {
+ cm.vendor.clear();
+ break;
+ }
+ return cm;
}
catch (const SysError& e) { throw FileError(_("Cannot get process information."), e.toString()); }
}
@@ -73,7 +98,7 @@ std::wstring zen::getOsDescription() //throw FileError
{
const std::string osName = trimCpy(getCommandOutput("lsb_release --id -s" )); //throw SysError
const std::string osVersion = trimCpy(getCommandOutput("lsb_release --release -s")); //
- return utfTo<std::wstring>(osName + " " + osVersion); //e.g. "CentOS 7.7.1908"
+ return utfTo<std::wstring>(osName + ' ' + osVersion); //e.g. "CentOS 7.7.1908"
}
catch (const SysError& e) { throw FileError(_("Cannot get process information."), e.toString()); }
diff --git a/zen/thread.cpp b/zen/thread.cpp
index 49c6d9b3..6e8b8219 100644
--- a/zen/thread.cpp
+++ b/zen/thread.cpp
@@ -28,7 +28,7 @@ uint64_t getThreadIdNative()
const pid_t tid = ::syscall(SYS_gettid); //no-fail
//"Invalid thread and process IDs": https://devblogs.microsoft.com/oldnewthing/20040223-00/?p=40503
//if (tid == 0) -> not sure this holds on Linux, too!
- // throw std::runtime_error(std::string(__FILE__) + "[" + numberTo<std::string>(__LINE__) + "] Failed to get thread ID.");
+ // throw std::runtime_error(std::string(__FILE__) + '[' + numberTo<std::string>(__LINE__) + "] Failed to get thread ID.");
static_assert(sizeof(uint64_t) >= sizeof(tid));
return tid;
}
diff --git a/zen/thread.h b/zen/thread.h
index d6cafab7..a1d5197c 100644
--- a/zen/thread.h
+++ b/zen/thread.h
@@ -149,7 +149,7 @@ class ThreadGroup
{
public:
ThreadGroup(size_t threadCountMax, const std::string& groupName) : threadCountMax_(threadCountMax), groupName_(groupName)
- { if (threadCountMax == 0) throw std::logic_error("Contract violation! " + std::string(__FILE__) + ":" + numberTo<std::string>(__LINE__)); }
+ { if (threadCountMax == 0) throw std::logic_error("Contract violation! " + std::string(__FILE__) + ':' + numberTo<std::string>(__LINE__)); }
~ThreadGroup()
{
diff --git a/zen/time.h b/zen/time.h
index 27ce518f..9718e5f6 100644
--- a/zen/time.h
+++ b/zen/time.h
@@ -8,7 +8,7 @@
#define TIME_H_8457092814324342453627
#include <ctime>
-#include "string_tools.h"
+#include "zstring.h"
namespace zen
@@ -24,7 +24,7 @@ struct TimeComp //replaces std::tm and SYSTEMTIME
};
inline bool operator==(const TimeComp& lhs, const TimeComp& rhs)
{
- return lhs.year == rhs.year && lhs.month == rhs.month && lhs.day == rhs.day && lhs.hour == rhs.hour && lhs.minute == rhs.minute && lhs.second == rhs.second;
+ return lhs.second == rhs.second && lhs.minute == rhs.minute && lhs.hour == rhs.hour && lhs.day == rhs.day && lhs.month == rhs.month && lhs.year == rhs.year;
}
inline bool operator!=(const TimeComp& lhs, const TimeComp& rhs) { return !(lhs == rhs); }
@@ -37,34 +37,26 @@ time_t utcToTimeT(const TimeComp& tc); //convert UTC time compone
TimeComp getCompileTime(); //returns TimeComp() on error
//----------------------------------------------------------------------------------------------------------------------------------
-
-/*
-format (current) date and time; example:
- formatTime<std::wstring>(L"%Y|%m|%d"); -> "2011|10|29"
- formatTime<std::wstring>(FORMAT_DATE); -> "2011-10-29"
- formatTime<std::wstring>(FORMAT_TIME); -> "17:55:34"
-*/
-template <class String, class String2>
-String formatTime(const String2& format, const TimeComp& tc = getLocalTime()); //format as specified by "std::strftime", returns empty string on failure
+/* format (current) date and time; example:
+ formatTime(Zstr("%Y|%m|%d")); -> "2011|10|29"
+ formatTime(formatDateTag); -> "2011-10-29"
+ formatTime(formatTimeTag); -> "17:55:34" */
+Zstring formatTime(const Zchar* format, const TimeComp& tc = getLocalTime()); //format as specified by "std::strftime", returns empty string on failure
//the "format" parameter of formatTime() is partially specialized with the following type tags:
-const struct FormatDateTag {} FORMAT_DATE = {}; //%x - locale dependent date representation: e.g. 8/23/2001
-const struct FormatTimeTag {} FORMAT_TIME = {}; //%X - locale dependent time representation: e.g. 2:55:02 PM
-const struct FormatDateTimeTag {} FORMAT_DATE_TIME = {}; //%c - locale dependent date and time: e.g. 8/23/2001 2:55:02 PM
+const Zchar* const formatDateTag = Zstr("%x"); //locale-dependent date representation: e.g. 8/23/2001
+const Zchar* const formatTimeTag = Zstr("%X"); //locale-dependent time representation: e.g. 2:55:02 PM
+const Zchar* const formatDateTimeTag = Zstr("%c"); //locale-dependent date and time: e.g. 8/23/2001 2:55:02 PM
-const struct FormatIsoDateTag {} FORMAT_ISO_DATE = {}; //%Y-%m-%d - e.g. 2001-08-23
-const struct FormatIsoTimeTag {} FORMAT_ISO_TIME = {}; //%H:%M:%S - e.g. 14:55:02
-const struct FormatIsoDateTimeTag {} FORMAT_ISO_DATE_TIME = {}; //%Y-%m-%d %H:%M:%S - e.g. 2001-08-23 14:55:02
+const Zchar* const formatIsoDateTag = Zstr("%Y-%m-%d"); //e.g. 2001-08-23
+const Zchar* const formatIsoTimeTag = Zstr("%H:%M:%S"); //e.g. 14:55:02
+const Zchar* const formatIsoDateTimeTag = Zstr("%Y-%m-%d %H:%M:%S"); //e.g. 2001-08-23 14:55:02
//----------------------------------------------------------------------------------------------------------------------------------
-
-/*
-example: parseTime("%Y-%m-%d %H:%M:%S", "2001-08-23 14:55:02");
- parseTime(FORMAT_ISO_DATE_TIME, "2001-08-23 14:55:02");
-*/
+//example: parseTime("%Y-%m-%d %H:%M:%S", "2001-08-23 14:55:02");
+// parseTime(formatIsoDateTimeTag, "2001-08-23 14:55:02");
template <class String, class String2>
TimeComp parseTime(const String& format, const String2& str); //similar to ::strptime()
-
//----------------------------------------------------------------------------------------------------------------------------------
@@ -118,68 +110,6 @@ TimeComp toZenTimeComponents(const std::tm& ctc)
}
-template <class T>
-struct GetFormat; //get default time formats as char* or wchar_t*
-
-template <>
-struct GetFormat<FormatDateTag> //%x - locale dependent date representation: e.g. 08/23/01
-{
- const char* format(char) const { return "%x"; }
- const wchar_t* format(wchar_t) const { return L"%x"; }
-};
-
-template <>
-struct GetFormat<FormatTimeTag> //%X - locale dependent time representation: e.g. 14:55:02
-{
- const char* format(char) const { return "%X"; }
- const wchar_t* format(wchar_t) const { return L"%X"; }
-};
-
-template <>
-struct GetFormat<FormatDateTimeTag> //%c - locale dependent date and time: e.g. Thu Aug 23 14:55:02 2001
-{
- const char* format(char) const { return "%c"; }
- const wchar_t* format(wchar_t) const { return L"%c"; }
-};
-
-template <>
-struct GetFormat<FormatIsoDateTag> //%Y-%m-%d - e.g. 2001-08-23
-{
- const char* format(char) const { return "%Y-%m-%d"; }
- const wchar_t* format(wchar_t) const { return L"%Y-%m-%d"; }
-};
-
-template <>
-struct GetFormat<FormatIsoTimeTag> //%H:%M:%S - e.g. 14:55:02
-{
- const char* format(char) const { return "%H:%M:%S"; }
- const wchar_t* format(wchar_t) const { return L"%H:%M:%S"; }
-};
-
-template <>
-struct GetFormat<FormatIsoDateTimeTag> //%Y-%m-%d %H:%M:%S - e.g. 2001-08-23 14:55:02
-{
- const char* format(char) const { return "%Y-%m-%d %H:%M:%S"; }
- const wchar_t* format(wchar_t) const { return L"%Y-%m-%d %H:%M:%S"; }
-};
-
-
-//strftime() craziness on invalid input:
-// VS 2010: CRASH unless "_invalid_parameter_handler" is set: https://msdn.microsoft.com/en-us/library/ksazx244.aspx
-// GCC: returns 0, apparently no crash. Still, considering some clib maintainer's comments, we should expect the worst!
-inline
-size_t strftimeWrap_impl(char* buffer, size_t bufferSize, const char* format, const std::tm* timeptr)
-{
- return std::strftime(buffer, bufferSize, format, timeptr);
-}
-
-
-inline
-size_t strftimeWrap_impl(wchar_t* buffer, size_t bufferSize, const wchar_t* format, const std::tm* timeptr)
-{
- return std::wcsftime(buffer, bufferSize, format, timeptr);
-}
-
/*
inline
bool isValid(const std::tm& t)
@@ -203,35 +133,6 @@ bool isValid(const std::tm& t)
//tm_isdst
};
*/
-
-template <class CharType> inline
-size_t strftimeWrap(CharType* buffer, size_t bufferSize, const CharType* format, const std::tm* timeptr)
-{
- return strftimeWrap_impl(buffer, bufferSize, format, timeptr);
-}
-
-
-struct UserDefinedFormatTag {};
-struct PredefinedFormatTag {};
-
-template <class String, class String2> inline
-String formatTime(const String2& format, const TimeComp& tc, UserDefinedFormatTag) //format as specified by "std::strftime", returns empty string on failure
-{
- std::tm ctc = toClibTimeComponents(tc);
- std::mktime(&ctc); // unfortunately std::strftime() needs all elements of "struct tm" filled, e.g. tm_wday, tm_yday
- //note: although std::mktime() explicitly expects "local time", calculating weekday and day of year *should* be time-zone and DST independent
-
- GetCharTypeT<String> buffer[256] = {};
- const size_t charsWritten = strftimeWrap(buffer, 256, strBegin(format), &ctc);
- return String(buffer, charsWritten);
-}
-
-
-template <class String, class FormatType> inline
-String formatTime(FormatType, const TimeComp& tc, PredefinedFormatTag)
-{
- return formatTime<String>(GetFormat<FormatType>().format(GetCharTypeT<String>()), tc, UserDefinedFormatTag());
-}
}
@@ -298,28 +199,29 @@ TimeComp getCompileTime()
}
-template <class String, class String2> inline
-String formatTime(const String2& format, const TimeComp& tc)
+inline
+Zstring formatTime(const Zchar* format, const TimeComp& tc)
{
if (tc == TimeComp()) //failure code from getLocalTime()
- return String();
+ return Zstring();
- using FormatTag = std::conditional_t<
- std::is_same_v<String2, FormatDateTag > ||
- std::is_same_v<String2, FormatTimeTag > ||
- std::is_same_v<String2, FormatDateTimeTag > ||
- std::is_same_v<String2, FormatIsoDateTag > ||
- std::is_same_v<String2, FormatIsoTimeTag > ||
- std::is_same_v<String2, FormatIsoDateTimeTag>, impl::PredefinedFormatTag, impl::UserDefinedFormatTag>;
+ std::tm ctc = impl::toClibTimeComponents(tc);
+ std::mktime(&ctc); //unfortunately std::strftime() needs all elements of "struct tm" filled, e.g. tm_wday, tm_yday
+ //note: although std::mktime() explicitly expects "local time", calculating weekday and day of year *should* be time-zone and DST independent
- return impl::formatTime<String>(format, tc, FormatTag());
+ Zstring buffer(256, Zstr('\0'));
+ //strftime() craziness on invalid input:
+ // VS 2010: CRASH unless "_invalid_parameter_handler" is set: https://docs.microsoft.com/en-us/cpp/c-runtime-library/parameter-validation
+ // GCC: returns 0, apparently no crash. Still, considering some clib maintainer's comments, we should expect the worst!
+ // Windows: avoid char-based strftime() which uses ANSI encoding! (e.g. Greek letters for AM/PM)
+ const size_t charsWritten = std::strftime(&buffer[0], buffer.size(), format, &ctc);
+ buffer.resize(charsWritten);
+ return buffer;
}
-namespace impl
-{
template <class String, class String2>
-TimeComp parseTime(const String& format, const String2& str, UserDefinedFormatTag)
+TimeComp parseTime(const String& format, const String2& str)
{
using CharType = GetCharTypeT<String>;
static_assert(std::is_same_v<CharType, GetCharTypeT<String2>>);
@@ -371,11 +273,9 @@ TimeComp parseTime(const String& format, const String2& str, UserDefinedFormatTa
return TimeComp();
const char* months[] = { "jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec" };
- auto itMonth = std::find_if(std::begin(months), std::end(months), [&](const char* name)
+ auto itMonth = std::find_if(std::begin(months), std::end(months), [&](const char* month)
{
- return asciiToLower(itStr[0]) == name[0] &&
- asciiToLower(itStr[1]) == name[1] &&
- asciiToLower(itStr[2]) == name[2];
+ return equalAsciiNoCase(makeStringView(itStr, 3), month);
});
if (itMonth == std::end(months))
return TimeComp();
@@ -422,26 +322,6 @@ TimeComp parseTime(const String& format, const String2& str, UserDefinedFormatTa
return output;
}
-
-
-template <class FormatType, class String> inline
-TimeComp parseTime(FormatType, const String& str, PredefinedFormatTag)
-{
- return parseTime(GetFormat<FormatType>().format(GetCharTypeT<String>()), str, UserDefinedFormatTag());
-}
-}
-
-
-template <class String, class String2> inline
-TimeComp parseTime(const String& format, const String2& str)
-{
- using FormatTag = std::conditional_t<
- std::is_same_v<String, FormatIsoDateTag > ||
- std::is_same_v<String, FormatIsoTimeTag > ||
- std::is_same_v<String, FormatIsoDateTimeTag>, impl::PredefinedFormatTag, impl::UserDefinedFormatTag>;
-
- return impl::parseTime(format, str, FormatTag());
-}
}
#endif //TIME_H_8457092814324342453627
diff --git a/zen/zlib_wrap.cpp b/zen/zlib_wrap.cpp
index 57a0f33c..685843c3 100644
--- a/zen/zlib_wrap.cpp
+++ b/zen/zlib_wrap.cpp
@@ -29,8 +29,10 @@ std::wstring formatZlibStatusCode(int sc)
ZEN_CHECK_CASE_FOR_CONSTANT(Z_MEM_ERROR);
ZEN_CHECK_CASE_FOR_CONSTANT(Z_BUF_ERROR);
ZEN_CHECK_CASE_FOR_CONSTANT(Z_VERSION_ERROR);
+
+ default:
+ return replaceCpy<std::wstring>(L"zlib status %x", L"%x", numberTo<std::wstring>(sc));
}
- return replaceCpy<std::wstring>(L"zlib status %x.", L"%x", numberTo<std::wstring>(sc));
}
}
@@ -53,7 +55,7 @@ size_t zen::impl::zlib_compress(const void* src, size_t srcLen, void* trg, size_
// Z_MEM_ERROR: not enough memory
// Z_BUF_ERROR: not enough room in the output buffer
if (rv != Z_OK || bufferSize > trgLen)
- throw SysError(formatSystemError(L"compress2", formatZlibStatusCode(rv), L"zlib error"));
+ throw SysError(formatSystemError(L"zlib compress2", formatZlibStatusCode(rv), L""));
return bufferSize;
}
@@ -71,7 +73,7 @@ size_t zen::impl::zlib_decompress(const void* src, size_t srcLen, void* trg, siz
// Z_BUF_ERROR: not enough room in the output buffer
// Z_DATA_ERROR: input data was corrupted or incomplete
if (rv != Z_OK || bufferSize > trgLen)
- throw SysError(formatSystemError(L"uncompress", formatZlibStatusCode(rv), L"zlib error"));
+ throw SysError(formatSystemError(L"zlib uncompress", formatZlibStatusCode(rv), L""));
return bufferSize;
}
@@ -96,7 +98,7 @@ public:
memLevel, //int memLevel
Z_DEFAULT_STRATEGY); //int strategy
if (rv != Z_OK)
- throw SysError(formatSystemError(L"deflateInit2", formatZlibStatusCode(rv), L"zlib error"));
+ throw SysError(formatSystemError(L"zlib deflateInit2", formatZlibStatusCode(rv), L""));
}
~Impl()
@@ -108,7 +110,7 @@ public:
size_t read(void* buffer, size_t bytesToRead) //throw SysError, X; return "bytesToRead" bytes unless end of stream!
{
if (bytesToRead == 0) //"read() with a count of 0 returns zero" => indistinguishable from end of file! => check!
- throw std::logic_error("Contract violation! " + std::string(__FILE__) + ":" + numberTo<std::string>(__LINE__));
+ throw std::logic_error("Contract violation! " + std::string(__FILE__) + ':' + numberTo<std::string>(__LINE__));
gzipStream_.next_out = static_cast<Bytef*>(buffer);
gzipStream_.avail_out = static_cast<uInt>(bytesToRead);
@@ -131,7 +133,7 @@ public:
if (rv == Z_STREAM_END)
return bytesToRead - gzipStream_.avail_out;
if (rv != Z_OK)
- throw SysError(formatSystemError(L"deflate", formatZlibStatusCode(rv), L"zlib error"));
+ throw SysError(formatSystemError(L"zlib deflate", formatZlibStatusCode(rv), L""));
if (gzipStream_.avail_out == 0)
return bytesToRead;
diff --git a/zen/zlib_wrap.h b/zen/zlib_wrap.h
index b820a4f8..3db609da 100644
--- a/zen/zlib_wrap.h
+++ b/zen/zlib_wrap.h
@@ -63,7 +63,7 @@ BinContainer compress(const BinContainer& stream, int level) //throw SysError
//save uncompressed stream size for decompression
const uint64_t uncompressedSize = stream.size(); //use portable number type!
contOut.resize(sizeof(uncompressedSize));
- std::memcpy(&*contOut.begin(), &uncompressedSize, sizeof(uncompressedSize));
+ std::memcpy(&contOut[0], &uncompressedSize, sizeof(uncompressedSize));
const size_t bufferEstimate = impl::zlib_compressBound(stream.size()); //upper limit for buffer size, larger than input size!!!
@@ -105,8 +105,8 @@ BinContainer decompress(const BinContainer& stream) //throw SysError
contOut.resize(static_cast<size_t>(uncompressedSize)); //throw std::bad_alloc
}
//most likely this is due to data corruption:
- catch (const std::length_error& e) { throw SysError(L"zlib error: " + _("Out of memory.") + L" " + utfTo<std::wstring>(e.what())); }
- catch (const std::bad_alloc& e) { throw SysError(L"zlib error: " + _("Out of memory.") + L" " + utfTo<std::wstring>(e.what())); }
+ catch (const std::length_error& e) { throw SysError(L"zlib error: " + _("Out of memory.") + L' ' + utfTo<std::wstring>(e.what())); }
+ catch (const std::bad_alloc& e) { throw SysError(L"zlib error: " + _("Out of memory.") + L' ' + utfTo<std::wstring>(e.what())); }
const size_t bytesWritten = impl::zlib_decompress(&*stream.begin() + sizeof(uncompressedSize),
stream.size() - sizeof(uncompressedSize),
diff --git a/zen/zstring.cpp b/zen/zstring.cpp
index ff20b8cf..046a3bd4 100644
--- a/zen/zstring.cpp
+++ b/zen/zstring.cpp
@@ -50,7 +50,8 @@ Zstring getUnicodeNormalForm(const Zstring& str)
{
//fast pre-check:
if (isAsciiString(str)) //perf: in the range of 3.5ns
- return str; //god bless our ref-counting! => save output string memory consumption!
+ return str;
+ static_assert(std::is_same_v<decltype(str), const Zbase<Zchar>&>, "god bless our ref-counting! => save output string memory consumption!");
//Example: const char* decomposed = "\x6f\xcc\x81";
// const char* precomposed = "\xc3\xb3";
diff --git a/zen/zstring.h b/zen/zstring.h
index f24e4299..d5d8c588 100644
--- a/zen/zstring.h
+++ b/zen/zstring.h
@@ -19,8 +19,9 @@
//a high-performance string for interfacing with native OS APIs in multithreaded contexts
using Zstring = zen::Zbase<Zchar>;
-//for special UI-contexts: guaranteed exponential growth + ref-counting
-using Zstringw = zen::Zbase<wchar_t>;
+//for special UI-contexts: guaranteed exponential growth + ref-counting + COW + no SSO overhead
+using Zstringc = zen::Zbase<char>;
+//using Zstringw = zen::Zbase<wchar_t>;
//Caveat: don't expect input/output string sizes to match:
@@ -34,7 +35,7 @@ Zstring makeUpperCopy(const Zstring& str);
Zstring getUnicodeNormalForm(const Zstring& str);
// "In fact, Unicode declares that there is an equivalence relationship between decomposed and composed sequences,
// and conformant software should not treat canonically equivalent sequences, whether composed or decomposed or something in between, as different."
-// http://www.win.tue.nl/~aeb/linux/uc/nfc_vs_nfd.html
+// http://www.win.tue.nl/~aeb/linux/uc/nfc_vs_nfd.html
struct LessUnicodeNormal { bool operator()(const Zstring& lhs, const Zstring& rhs) const { return getUnicodeNormalForm(lhs) < getUnicodeNormalForm(rhs);} };
diff --git a/zenXml/zenxml/cvrt_struc.h b/zenXml/zenxml/cvrt_struc.h
index 9df1c7ba..45109187 100644
--- a/zenXml/zenxml/cvrt_struc.h
+++ b/zenXml/zenxml/cvrt_struc.h
@@ -57,11 +57,11 @@ ZEN_INIT_DETECT_MEMBER(insert) //
template <typename T>
using IsStlContainer = std::bool_constant<
- impl_2384343::HasMemberTypeV_value_type <T> &&
- impl_2384343::HasMemberTypeV_iterator <T> &&
- impl_2384343::HasMemberTypeV_const_iterator<T> &&
- impl_2384343::HasMemberV_begin <T> &&
- impl_2384343::HasMemberV_end <T> &&
+ impl_2384343::HasMemberTypeV_value_type <T>&&
+ impl_2384343::HasMemberTypeV_iterator <T>&&
+ impl_2384343::HasMemberTypeV_const_iterator<T>&&
+ impl_2384343::HasMemberV_begin <T>&&
+ impl_2384343::HasMemberV_end <T>&&
impl_2384343::HasMemberV_insert <T>>;
diff --git a/zenXml/zenxml/dom.h b/zenXml/zenxml/dom.h
index 0f456822..35226fc7 100644
--- a/zenXml/zenxml/dom.h
+++ b/zenXml/zenxml/dom.h
@@ -230,7 +230,7 @@ public:
\code
auto iterPair = elem.getAttributes();
for (auto it = iterPair.first; it != iterPair.second; ++it)
- std::cout << "name: " << it->name << " value: " << it->value << "\n";
+ std::cout << "name: " << it->name << " value: " << it->value << '\n';
\endcode
\return A pair of STL begin/end iterators to access all attributes sequentially as a list of name/value pairs of std::string.
*/
diff --git a/zenXml/zenxml/xml.h b/zenXml/zenxml/xml.h
index 80b60730..4058f7bf 100644
--- a/zenXml/zenxml/xml.h
+++ b/zenXml/zenxml/xml.h
@@ -369,8 +369,8 @@ public:
{
std::vector<String> output;
- for (const std::string& str : log_.ref().elementList())
- output.push_back(utfTo<String>(str));
+ for (const std::string& str : log_.ref().elementList())
+ output.push_back(utfTo<String>(str));
return output;
}
@@ -382,7 +382,7 @@ private:
static std::string getNameFormatted(const XmlElement& elem) //"<Root> <Level1> <Level2>"
{
- return (elem.parent() ? getNameFormatted(*elem.parent()) + " " : std::string()) + "<" + elem.getNameAs<std::string>() + ">";
+ return (elem.parent() ? getNameFormatted(*elem.parent()) + ' ' : std::string()) + '<' + elem.getNameAs<std::string>() + '>';
}
std::string getNameFormatted() const
@@ -399,7 +399,7 @@ private:
std::string getChildNameFormatted(const std::string& childName) const
{
std::string parentName = getNameFormatted();
- return (parentName.empty() ? std::string() : (parentName + " ")) + "<" + childName + ">";
+ return (parentName.empty() ? std::string() : (parentName + ' ')) + '<' + childName + '>';
}
class ErrorLog
@@ -440,9 +440,9 @@ void checkXmlMappingErrors(const XmlIn& xmlInput, const Zstring& filePath) //thr
{
if (xmlInput.haveErrors())
{
- std::wstring msg = _("The following XML elements could not be read:") + L"\n";
+ std::wstring msg = _("The following XML elements could not be read:") + L'\n';
for (const std::wstring& elem : xmlInput.getErrorsAs<std::wstring>())
- msg += L"\n" + elem;
+ msg += L'\n' + elem;
throw FileError(replaceCpy(_("Configuration file %x is incomplete. The missing elements will be set to their default values."), L"%x", fmtPath(filePath)) + L"\n\n" + msg);
}
bgstack15