• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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