1141cc406Sopenharmony_ci/* sane - Scanner Access Now Easy. 2141cc406Sopenharmony_ci 3141cc406Sopenharmony_ci Copyright (C) 2019 Povilas Kanapickas <povilas@radix.lt> 4141cc406Sopenharmony_ci 5141cc406Sopenharmony_ci This file is part of the SANE package. 6141cc406Sopenharmony_ci 7141cc406Sopenharmony_ci This program is free software; you can redistribute it and/or 8141cc406Sopenharmony_ci modify it under the terms of the GNU General Public License as 9141cc406Sopenharmony_ci published by the Free Software Foundation; either version 2 of the 10141cc406Sopenharmony_ci License, or (at your option) any later version. 11141cc406Sopenharmony_ci 12141cc406Sopenharmony_ci This program is distributed in the hope that it will be useful, but 13141cc406Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 14141cc406Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15141cc406Sopenharmony_ci General Public License for more details. 16141cc406Sopenharmony_ci 17141cc406Sopenharmony_ci You should have received a copy of the GNU General Public License 18141cc406Sopenharmony_ci along with this program. If not, see <https://www.gnu.org/licenses/>. 19141cc406Sopenharmony_ci*/ 20141cc406Sopenharmony_ci 21141cc406Sopenharmony_ci#define DEBUG_DECLARE_ONLY 22141cc406Sopenharmony_ci 23141cc406Sopenharmony_ci#include "error.h" 24141cc406Sopenharmony_ci#include <cstdarg> 25141cc406Sopenharmony_ci#include <cstdlib> 26141cc406Sopenharmony_ci 27141cc406Sopenharmony_cinamespace genesys { 28141cc406Sopenharmony_ci 29141cc406Sopenharmony_ciextern "C" void sanei_debug_msg(int level, int max_level, const char *be, const char *fmt, 30141cc406Sopenharmony_ci std::va_list ap); 31141cc406Sopenharmony_ci 32141cc406Sopenharmony_ci#if (defined(__GNUC__) || defined(__CLANG__)) && (defined(__linux__) || defined(__APPLE__)) 33141cc406Sopenharmony_ciextern "C" char* __cxa_get_globals(); 34141cc406Sopenharmony_ci#endif 35141cc406Sopenharmony_ci 36141cc406Sopenharmony_cistatic unsigned num_uncaught_exceptions() 37141cc406Sopenharmony_ci{ 38141cc406Sopenharmony_ci#if __cplusplus >= 201703L 39141cc406Sopenharmony_ci int count = std::uncaught_exceptions(); 40141cc406Sopenharmony_ci return count >= 0 ? count : 0; 41141cc406Sopenharmony_ci#elif (defined(__GNUC__) || defined(__CLANG__)) && (defined(__linux__) || defined(__APPLE__)) 42141cc406Sopenharmony_ci // the format of the __cxa_eh_globals struct is enshrined into the Itanium C++ ABI and it's 43141cc406Sopenharmony_ci // very unlikely we'll get issues referencing it directly 44141cc406Sopenharmony_ci char* cxa_eh_globals_ptr = __cxa_get_globals(); 45141cc406Sopenharmony_ci return *reinterpret_cast<unsigned*>(cxa_eh_globals_ptr + sizeof(void*)); 46141cc406Sopenharmony_ci#else 47141cc406Sopenharmony_ci return std::uncaught_exception() ? 1 : 0; 48141cc406Sopenharmony_ci#endif 49141cc406Sopenharmony_ci} 50141cc406Sopenharmony_ci 51141cc406Sopenharmony_ciSaneException::SaneException(SANE_Status status) : status_(status) 52141cc406Sopenharmony_ci{ 53141cc406Sopenharmony_ci set_msg(); 54141cc406Sopenharmony_ci} 55141cc406Sopenharmony_ci 56141cc406Sopenharmony_ciSaneException::SaneException(SANE_Status status, const char* format, ...) : status_(status) 57141cc406Sopenharmony_ci{ 58141cc406Sopenharmony_ci std::va_list args; 59141cc406Sopenharmony_ci va_start(args, format); 60141cc406Sopenharmony_ci set_msg(format, args); 61141cc406Sopenharmony_ci va_end(args); 62141cc406Sopenharmony_ci} 63141cc406Sopenharmony_ci 64141cc406Sopenharmony_ciSaneException::SaneException(const char* format, ...) : status_(SANE_STATUS_INVAL) 65141cc406Sopenharmony_ci{ 66141cc406Sopenharmony_ci std::va_list args; 67141cc406Sopenharmony_ci va_start(args, format); 68141cc406Sopenharmony_ci set_msg(format, args); 69141cc406Sopenharmony_ci va_end(args); 70141cc406Sopenharmony_ci} 71141cc406Sopenharmony_ci 72141cc406Sopenharmony_ciSANE_Status SaneException::status() const 73141cc406Sopenharmony_ci{ 74141cc406Sopenharmony_ci return status_; 75141cc406Sopenharmony_ci} 76141cc406Sopenharmony_ci 77141cc406Sopenharmony_ciconst char* SaneException::what() const noexcept 78141cc406Sopenharmony_ci{ 79141cc406Sopenharmony_ci return msg_.c_str(); 80141cc406Sopenharmony_ci} 81141cc406Sopenharmony_ci 82141cc406Sopenharmony_civoid SaneException::set_msg() 83141cc406Sopenharmony_ci{ 84141cc406Sopenharmony_ci const char* status_msg = sane_strstatus(status_); 85141cc406Sopenharmony_ci std::size_t status_msg_len = std::strlen(status_msg); 86141cc406Sopenharmony_ci msg_.reserve(status_msg_len); 87141cc406Sopenharmony_ci msg_ = status_msg; 88141cc406Sopenharmony_ci} 89141cc406Sopenharmony_ci 90141cc406Sopenharmony_civoid SaneException::set_msg(const char* format, std::va_list vlist) 91141cc406Sopenharmony_ci{ 92141cc406Sopenharmony_ci const char* status_msg = sane_strstatus(status_); 93141cc406Sopenharmony_ci std::size_t status_msg_len = std::strlen(status_msg); 94141cc406Sopenharmony_ci 95141cc406Sopenharmony_ci std::va_list vlist2; 96141cc406Sopenharmony_ci va_copy(vlist2, vlist); 97141cc406Sopenharmony_ci int msg_len = std::vsnprintf(nullptr, 0, format, vlist2); 98141cc406Sopenharmony_ci va_end(vlist2); 99141cc406Sopenharmony_ci 100141cc406Sopenharmony_ci if (msg_len < 0) { 101141cc406Sopenharmony_ci const char* formatting_error_msg = "(error formatting arguments)"; 102141cc406Sopenharmony_ci msg_.reserve(std::strlen(formatting_error_msg) + 3 + status_msg_len); 103141cc406Sopenharmony_ci msg_ = formatting_error_msg; 104141cc406Sopenharmony_ci msg_ += " : "; 105141cc406Sopenharmony_ci msg_ += status_msg; 106141cc406Sopenharmony_ci return; 107141cc406Sopenharmony_ci } 108141cc406Sopenharmony_ci 109141cc406Sopenharmony_ci msg_.reserve(msg_len + status_msg_len + 3); 110141cc406Sopenharmony_ci msg_.resize(msg_len + 1, ' '); 111141cc406Sopenharmony_ci std::vsnprintf(&msg_[0], msg_len + 1, format, vlist); 112141cc406Sopenharmony_ci msg_.resize(msg_len, ' '); 113141cc406Sopenharmony_ci 114141cc406Sopenharmony_ci msg_ += " : "; 115141cc406Sopenharmony_ci msg_ += status_msg; 116141cc406Sopenharmony_ci} 117141cc406Sopenharmony_ci 118141cc406Sopenharmony_ciDebugMessageHelper::DebugMessageHelper(const char* func) 119141cc406Sopenharmony_ci{ 120141cc406Sopenharmony_ci func_ = func; 121141cc406Sopenharmony_ci num_exceptions_on_enter_ = num_uncaught_exceptions(); 122141cc406Sopenharmony_ci msg_[0] = '\0'; 123141cc406Sopenharmony_ci DBG(DBG_proc, "%s: start\n", func_); 124141cc406Sopenharmony_ci} 125141cc406Sopenharmony_ci 126141cc406Sopenharmony_ciDebugMessageHelper::DebugMessageHelper(const char* func, const char* format, ...) 127141cc406Sopenharmony_ci{ 128141cc406Sopenharmony_ci func_ = func; 129141cc406Sopenharmony_ci num_exceptions_on_enter_ = num_uncaught_exceptions(); 130141cc406Sopenharmony_ci msg_[0] = '\0'; 131141cc406Sopenharmony_ci DBG(DBG_proc, "%s: start\n", func_); 132141cc406Sopenharmony_ci DBG(DBG_proc, "%s: ", func_); 133141cc406Sopenharmony_ci 134141cc406Sopenharmony_ci std::va_list args; 135141cc406Sopenharmony_ci va_start(args, format); 136141cc406Sopenharmony_ci sanei_debug_msg(DBG_proc, DBG_LEVEL, STRINGIFY(BACKEND_NAME), format, args); 137141cc406Sopenharmony_ci va_end(args); 138141cc406Sopenharmony_ci DBG(DBG_proc, "\n"); 139141cc406Sopenharmony_ci} 140141cc406Sopenharmony_ci 141141cc406Sopenharmony_ci 142141cc406Sopenharmony_ciDebugMessageHelper::~DebugMessageHelper() 143141cc406Sopenharmony_ci{ 144141cc406Sopenharmony_ci if (num_exceptions_on_enter_ < num_uncaught_exceptions()) { 145141cc406Sopenharmony_ci if (msg_[0] != '\0') { 146141cc406Sopenharmony_ci DBG(DBG_error, "%s: failed during %s\n", func_, msg_); 147141cc406Sopenharmony_ci } else { 148141cc406Sopenharmony_ci DBG(DBG_error, "%s: failed\n", func_); 149141cc406Sopenharmony_ci } 150141cc406Sopenharmony_ci } else { 151141cc406Sopenharmony_ci DBG(DBG_proc, "%s: completed\n", func_); 152141cc406Sopenharmony_ci } 153141cc406Sopenharmony_ci} 154141cc406Sopenharmony_ci 155141cc406Sopenharmony_civoid DebugMessageHelper::vstatus(const char* format, ...) 156141cc406Sopenharmony_ci{ 157141cc406Sopenharmony_ci std::va_list args; 158141cc406Sopenharmony_ci va_start(args, format); 159141cc406Sopenharmony_ci std::vsnprintf(msg_, MAX_BUF_SIZE, format, args); 160141cc406Sopenharmony_ci va_end(args); 161141cc406Sopenharmony_ci} 162141cc406Sopenharmony_ci 163141cc406Sopenharmony_civoid DebugMessageHelper::log(unsigned level, const char* msg) 164141cc406Sopenharmony_ci{ 165141cc406Sopenharmony_ci DBG(level, "%s: %s\n", func_, msg); 166141cc406Sopenharmony_ci} 167141cc406Sopenharmony_ci 168141cc406Sopenharmony_civoid DebugMessageHelper::vlog(unsigned level, const char* format, ...) 169141cc406Sopenharmony_ci{ 170141cc406Sopenharmony_ci std::string msg; 171141cc406Sopenharmony_ci 172141cc406Sopenharmony_ci std::va_list args; 173141cc406Sopenharmony_ci 174141cc406Sopenharmony_ci va_start(args, format); 175141cc406Sopenharmony_ci int msg_len = std::vsnprintf(nullptr, 0, format, args); 176141cc406Sopenharmony_ci va_end(args); 177141cc406Sopenharmony_ci 178141cc406Sopenharmony_ci if (msg_len < 0) { 179141cc406Sopenharmony_ci DBG(level, "%s: error formatting error message: %s\n", func_, format); 180141cc406Sopenharmony_ci return; 181141cc406Sopenharmony_ci } 182141cc406Sopenharmony_ci msg.resize(msg_len + 1, ' '); 183141cc406Sopenharmony_ci 184141cc406Sopenharmony_ci va_start(args, format); 185141cc406Sopenharmony_ci std::vsnprintf(&msg.front(), msg.size(), format, args); 186141cc406Sopenharmony_ci va_end(args); 187141cc406Sopenharmony_ci 188141cc406Sopenharmony_ci msg.resize(msg_len, ' '); // strip the null character 189141cc406Sopenharmony_ci 190141cc406Sopenharmony_ci DBG(level, "%s: %s\n", func_, msg.c_str()); 191141cc406Sopenharmony_ci} 192141cc406Sopenharmony_ci 193141cc406Sopenharmony_cienum class LogImageDataStatus 194141cc406Sopenharmony_ci{ 195141cc406Sopenharmony_ci NOT_SET, 196141cc406Sopenharmony_ci ENABLED, 197141cc406Sopenharmony_ci DISABLED 198141cc406Sopenharmony_ci}; 199141cc406Sopenharmony_ci 200141cc406Sopenharmony_cistatic LogImageDataStatus s_log_image_data_setting = LogImageDataStatus::NOT_SET; 201141cc406Sopenharmony_ci 202141cc406Sopenharmony_ciLogImageDataStatus dbg_read_log_image_data_setting() 203141cc406Sopenharmony_ci{ 204141cc406Sopenharmony_ci auto* setting = std::getenv("SANE_DEBUG_GENESYS_IMAGE"); 205141cc406Sopenharmony_ci if (!setting) 206141cc406Sopenharmony_ci return LogImageDataStatus::DISABLED; 207141cc406Sopenharmony_ci auto setting_int = std::strtol(setting, nullptr, 10); 208141cc406Sopenharmony_ci if (setting_int == 0) 209141cc406Sopenharmony_ci return LogImageDataStatus::DISABLED; 210141cc406Sopenharmony_ci return LogImageDataStatus::ENABLED; 211141cc406Sopenharmony_ci} 212141cc406Sopenharmony_ci 213141cc406Sopenharmony_cibool dbg_log_image_data() 214141cc406Sopenharmony_ci{ 215141cc406Sopenharmony_ci if (s_log_image_data_setting == LogImageDataStatus::NOT_SET) { 216141cc406Sopenharmony_ci s_log_image_data_setting = dbg_read_log_image_data_setting(); 217141cc406Sopenharmony_ci } 218141cc406Sopenharmony_ci return s_log_image_data_setting == LogImageDataStatus::ENABLED; 219141cc406Sopenharmony_ci} 220141cc406Sopenharmony_ci 221141cc406Sopenharmony_ci} // namespace genesys 222