1 /* sane - Scanner Access Now Easy.
2
3 Copyright (C) 2019 Povilas Kanapickas <povilas@radix.lt>
4
5 This file is part of the SANE package.
6
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2 of the
10 License, or (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20
21 #ifndef BACKEND_GENESYS_ERROR_H
22 #define BACKEND_GENESYS_ERROR_H
23
24 #include "../include/sane/config.h"
25 #include "../include/sane/sane.h"
26 #include "../include/sane/sanei_backend.h"
27
28 #include <stdexcept>
29 #include <cstdarg>
30 #include <cstring>
31 #include <string>
32 #include <new>
33
34 #define DBG_error0 0 /* errors/warnings printed even with devuglevel 0 */
35 #define DBG_error 1 /* fatal errors */
36 #define DBG_init 2 /* initialization and scanning time messages */
37 #define DBG_warn 3 /* warnings and non-fatal errors */
38 #define DBG_info 4 /* informational messages */
39 #define DBG_proc 5 /* starting/finishing functions */
40 #define DBG_io 6 /* io functions */
41 #define DBG_io2 7 /* io functions that are called very often */
42 #define DBG_data 8 /* log image data */
43
44 namespace genesys {
45
46 class SaneException : public std::exception {
47 public:
48 SaneException(SANE_Status status);
49 SaneException(SANE_Status status, const char* format, ...)
50 #ifdef __GNUC__
51 __attribute__((format(printf, 3, 4)))
52 #endif
53 ;
54
55 SaneException(const char* format, ...)
56 #ifdef __GNUC__
57 __attribute__((format(printf, 2, 3)))
58 #endif
59 ;
60
61 SANE_Status status() const;
62 const char* what() const noexcept override;
63
64 private:
65
66 void set_msg();
67 void set_msg(const char* format, std::va_list vlist);
68
69 std::string msg_;
70 SANE_Status status_;
71 };
72
73 // call a function and throw an exception on error
74 #define TIE(function) \
75 do { \
76 SANE_Status tmp_status = function; \
77 if (tmp_status != SANE_STATUS_GOOD) { \
78 throw ::genesys::SaneException(tmp_status); \
79 } \
80 } while (false)
81
82 class DebugMessageHelper {
83 public:
84 static constexpr unsigned MAX_BUF_SIZE = 120;
85
86 DebugMessageHelper(const char* func);
87 DebugMessageHelper(const char* func, const char* format, ...)
88 #ifdef __GNUC__
89 __attribute__((format(printf, 3, 4)))
90 #endif
91 ;
92
93 ~DebugMessageHelper();
94
status(const char * msg)95 void status(const char* msg) { vstatus("%s", msg); }
96 void vstatus(const char* format, ...)
97 #ifdef __GNUC__
98 __attribute__((format(printf, 2, 3)))
99 #endif
100 ;
101
clear()102 void clear() { msg_[0] = '\n'; }
103
104 void log(unsigned level, const char* msg);
105 void vlog(unsigned level, const char* format, ...)
106 #ifdef __GNUC__
107 __attribute__((format(printf, 3, 4)))
108 #endif
109 ;
110
111 private:
112 const char* func_ = nullptr;
113 char msg_[MAX_BUF_SIZE];
114 unsigned num_exceptions_on_enter_ = 0;
115 };
116
117 #if defined(__GNUC__) || defined(__clang__)
118 #define GENESYS_CURRENT_FUNCTION __PRETTY_FUNCTION__
119 #elif defined(__FUNCSIG__)
120 #define GENESYS_CURRENT_FUNCTION __FUNCSIG__
121 #else
122 #define GENESYS_CURRENT_FUNCTION __func__
123 #endif
124
125 #define DBG_HELPER(var) DebugMessageHelper var(GENESYS_CURRENT_FUNCTION)
126 #define DBG_HELPER_ARGS(var, ...) DebugMessageHelper var(GENESYS_CURRENT_FUNCTION, __VA_ARGS__)
127
128 bool dbg_log_image_data();
129
130 template<class F>
wrap_exceptions_to_status_code(const char * func,F && function)131 SANE_Status wrap_exceptions_to_status_code(const char* func, F&& function)
132 {
133 try {
134 function();
135 return SANE_STATUS_GOOD;
136 } catch (const SaneException& exc) {
137 DBG(DBG_error, "%s: got error: %s\n", func, exc.what());
138 return exc.status();
139 } catch (const std::bad_alloc& exc) {
140 (void) exc;
141 DBG(DBG_error, "%s: failed to allocate memory\n", func);
142 return SANE_STATUS_NO_MEM;
143 } catch (const std::exception& exc) {
144 DBG(DBG_error, "%s: got uncaught exception: %s\n", func, exc.what());
145 return SANE_STATUS_INVAL;
146 } catch (...) {
147 DBG(DBG_error, "%s: got unknown uncaught exception\n", func);
148 return SANE_STATUS_INVAL;
149 }
150 }
151
152 template<class F>
wrap_exceptions_to_status_code_return(const char * func,F && function)153 SANE_Status wrap_exceptions_to_status_code_return(const char* func, F&& function)
154 {
155 try {
156 return function();
157 } catch (const SaneException& exc) {
158 DBG(DBG_error, "%s: got error: %s\n", func, exc.what());
159 return exc.status();
160 } catch (const std::bad_alloc& exc) {
161 (void) exc;
162 DBG(DBG_error, "%s: failed to allocate memory\n", func);
163 return SANE_STATUS_NO_MEM;
164 } catch (const std::exception& exc) {
165 DBG(DBG_error, "%s: got uncaught exception: %s\n", func, exc.what());
166 return SANE_STATUS_INVAL;
167 } catch (...) {
168 DBG(DBG_error, "%s: got unknown uncaught exception\n", func);
169 return SANE_STATUS_INVAL;
170 }
171 }
172
173 template<class F>
catch_all_exceptions(const char * func,F && function)174 void catch_all_exceptions(const char* func, F&& function)
175 {
176 try {
177 function();
178 } catch (const SaneException& exc) {
179 DBG(DBG_error, "%s: got exception: %s\n", func, exc.what());
180 } catch (const std::bad_alloc& exc) {
181 DBG(DBG_error, "%s: got exception: could not allocate memory: %s\n", func, exc.what());
182 } catch (const std::exception& exc) {
183 DBG(DBG_error, "%s: got uncaught exception: %s\n", func, exc.what());
184 } catch (...) {
185 DBG(DBG_error, "%s: got unknown uncaught exception\n", func);
186 }
187 }
188
wrap_status_code_to_exception(SANE_Status status)189 inline void wrap_status_code_to_exception(SANE_Status status)
190 {
191 if (status == SANE_STATUS_GOOD)
192 return;
193 throw SaneException(status);
194 }
195
196 } // namespace genesys
197
198 #endif // BACKEND_GENESYS_ERROR_H
199