Repository :
https://github.com/FarGroup/FarManager
On branch : master
Link :
https://github.com/FarGroup/FarManager/commit/216786efa659ca54b16c01943ae3346b3ab3c690
>---------------------------------------------------------------
commit 216786efa659ca54b16c01943ae3346b3ab3c690
Author: Alex Alabuzhev <
alab...@gmail.com>
Date: Sun Sep 21 18:07:05 2025 +0100
Exception handling improvements
>---------------------------------------------------------------
216786efa659ca54b16c01943ae3346b3ab3c690
far/changelog | 5 +++++
far/diskmenu.cpp | 2 +-
far/exception.hpp | 2 +-
far/main.cpp | 11 ++++++++++-
far/message.cpp | 2 +-
far/sqlitedb.cpp | 45 +++++++++++++++++++++++++++++++++++++--------
far/sqlitedb.hpp | 14 +++++++++++++-
far/vbuild.m4 | 2 +-
8 files changed, 69 insertions(+), 14 deletions(-)
diff --git a/far/changelog b/far/changelog
index 02659dd27..6502d92e8 100644
--- a/far/changelog
+++ b/far/changelog
@@ -1,3 +1,8 @@
+--------------------------------------------------------------------------------
+drkns 2025-09-21 18:06:25+01:00 - build 6563
+
+1. Exception handling improvements.
+
--------------------------------------------------------------------------------
drkns 2025-09-21 15:41:04+01:00 - build 6562
diff --git a/far/diskmenu.cpp b/far/diskmenu.cpp
index b519527ae..f8e7e942f 100644
--- a/far/diskmenu.cpp
+++ b/far/diskmenu.cpp
@@ -1355,7 +1355,7 @@ static int ChangeDiskMenu(panel_ptr Owner, int Pos, bool FirstCall)
if (!ErrorState.What.empty())
Builder.AddTextWrap(ErrorState.What, true);
- if (ErrorState.any())
+ if (ErrorState.Win32Error)
Builder.AddTextWrap(ErrorState.system_error(), true);
Builder.AddOKCancel(lng::MRetry, lng::MCancel);
diff --git a/far/exception.hpp b/far/exception.hpp
index a5054d6d0..721dd74d4 100644
--- a/far/exception.hpp
+++ b/far/exception.hpp
@@ -129,7 +129,7 @@ class far_exception: public detail::far_std_exception
/*
For the cases where it is pretty clear what is wrong, no need to show the stack etc.
*/
-class far_known_exception final: public far_exception
+class far_known_exception: public virtual far_exception
{
public:
explicit far_known_exception(string_view const Message, source_location const& Location = source_location::current()):
diff --git a/far/main.cpp b/far/main.cpp
index 352b778f4..e62a5d29e 100644
--- a/far/main.cpp
+++ b/far/main.cpp
@@ -72,6 +72,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "exception.hpp"
#include "log.hpp"
#include "strmix.hpp"
+#include "message.hpp"
// Platform:
#include "platform.debug.hpp"
@@ -943,7 +944,15 @@ static int mainImpl(std::span<const wchar_t* const> const Args)
return cpp_try(
[&]
{
- return MainProcess(strEditName, strViewName, DestNames[0], DestNames[1], StartLine, StartChar);
+ try
+ {
+ return MainProcess(strEditName, strViewName, DestNames[0], DestNames[1], StartLine, StartChar);
+ }
+ catch (far_known_exception const& e)
+ {
+ Message(FMSG_WARNING, e, msg(lng::MError), {}, { lng::MQuit });
+ return EXIT_FAILURE;
+ }
},
[](source_location const& Location) -> int
{
diff --git a/far/message.cpp b/far/message.cpp
index c4023b929..67f3d0379 100644
--- a/far/message.cpp
+++ b/far/message.cpp
@@ -184,7 +184,7 @@ static message_result MessageImpl(
Context.ErrorState = *ErrorState;
ErrorMessage = Context.ErrorState->What;
- if (Context.ErrorState->any())
+ if (Context.ErrorState->Win32Error)
SystemErrorMessage = Context.ErrorState->system_error();
if (!SystemErrorMessage.empty())
diff --git a/far/sqlitedb.cpp b/far/sqlitedb.cpp
index eaeee16bf..06c660137 100644
--- a/far/sqlitedb.cpp
+++ b/far/sqlitedb.cpp
@@ -104,11 +104,11 @@ namespace
string GetDatabaseName(sqlite::sqlite3* Db, string_view const DbName = {})
{
if (!DbName.empty())
- return string(PointToName(DbName));
+ return string(DbName);
const auto NamePtr = sqlite::sqlite3_db_filename(Db, "main");
const string Name(NamePtr? *NamePtr? encoding::utf8::get_chars(NamePtr) : SQLiteDb::memory_db_name : L"unknown"sv);
- return string(PointToName(Name));
+ return Name;
}
string GetLastErrorString(sqlite::sqlite3* Db)
@@ -116,17 +116,46 @@ namespace
return encoding::utf8::get_chars(sqlite::sqlite3_errmsg(Db));
}
+ bool is_user_problem(int const ErrorCode)
+ {
+ // These are errors that typically only the user can fix.
+ // No point in recording dumps, creating bug_report etc., just show them the message.
+ switch (ErrorCode)
+ {
+ case SQLITE_PERM: // Access permission denied
+ case SQLITE_NOMEM: // A malloc() failed
+ case SQLITE_READONLY: // Attempt to write a readonly database
+ case SQLITE_IOERR: // Some kind of disk I/O error occurred
+ case SQLITE_CORRUPT: // The database disk image is malformed
+ case SQLITE_FULL: // Insertion failed because database is full
+ case SQLITE_CANTOPEN: // Unable to open the database file
+ case SQLITE_AUTH: // Authorization denied
+ case SQLITE_NOTADB: // File opened that is not a database file
+ return true;
+
+ default:
+ return false;
+ }
+ }
+
[[noreturn]]
void throw_exception(string_view const DatabaseName, int const ErrorCode, string_view const ErrorString = {}, int const SystemErrorCode = 0, string_view const Sql = {}, int const ErrorOffset = -1, source_location const& Location = source_location::current())
{
- throw far_sqlite_exception(ErrorCode, far::format(L"[{}] - SQLite error {}: {}{}{}{}"sv,
- DatabaseName,
+ const auto IsUserProblem = is_user_problem(ErrorCode);
+
+ const auto Message = far::format(L"SQLite error {}: {}\n{}{}{}{}"sv,
ErrorCode,
ErrorString.empty()? GetErrorString(ErrorCode) : ErrorString,
- SystemErrorCode? far::format(L" ({})"sv, os::format_error(SystemErrorCode)) : L""sv,
- Sql.empty()? L""sv : far::format(L" while executing \"{}\""sv, Sql),
- ErrorOffset == -1? L""sv : far::format(L" at position {}"sv, ErrorOffset)
- ), Location);
+ DatabaseName,
+ IsUserProblem || !SystemErrorCode? L""sv : far::format(L"\n({})"sv, os::format_error(SystemErrorCode)),
+ IsUserProblem || Sql.empty()? L""sv : far::format(L"\nwhile executing\n\"{}\""sv, Sql),
+ IsUserProblem || ErrorOffset == -1? L""sv : far::format(L" at position {}"sv, ErrorOffset)
+ );
+
+ if (IsUserProblem)
+ throw far_known_sqlite_exception(ErrorCode, Message, Location);
+ else
+ throw far_sqlite_exception(ErrorCode, Message, Location);
}
[[noreturn]]
diff --git a/far/sqlitedb.hpp b/far/sqlitedb.hpp
index dd972bcae..4808839f5 100644
--- a/far/sqlitedb.hpp
+++ b/far/sqlitedb.hpp
@@ -54,7 +54,7 @@ namespace sqlite
struct sqlite3_stmt;
}
-class far_sqlite_exception final: public far_exception
+class far_sqlite_exception: public virtual far_exception
{
public:
explicit far_sqlite_exception(int const ErrorCode, string_view const Message, source_location const& Location = source_location::current()) :
@@ -68,6 +68,18 @@ private:
int m_ErrorCode;
};
+class far_known_sqlite_exception final: public far_known_exception, public far_sqlite_exception
+{
+public:
+ explicit far_known_sqlite_exception(int const ErrorCode, string_view const Message, source_location const& Location = source_location::current()):
+ far_exception(Message, false, Location),
+ far_known_exception(Message, Location),
+ far_sqlite_exception(ErrorCode, Message, Location)
+ {
+ }
+};
+
+
class SQLiteDb: virtual protected transactional
{
public:
diff --git a/far/vbuild.m4 b/far/vbuild.m4
index 97017b6f5..251c00a92 100644
--- a/far/vbuild.m4
+++ b/far/vbuild.m4
@@ -1 +1 @@
-6562
+6563