• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #pragma once
2 #ifndef IWLOG_H
3 #define IWLOG_H
4 
5 /**************************************************************************************************
6  * IOWOW library
7  *
8  * MIT License
9  *
10  * Copyright (c) 2012-2020 Softmotions Ltd <info@softmotions.com>
11  *
12  * Permission is hereby granted, free of charge, to any person obtaining a copy
13  * of this software and associated documentation files (the "Software"), to deal
14  * in the Software without restriction, including without limitation the rights
15  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16  *  copies of the Software, and to permit persons to whom the Software is
17  * furnished to do so, subject to the following conditions:
18  *
19  * The above copyright notice and this permission notice shall be included in all
20  * copies or substantial portions of the Software.
21  *
22  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28  * SOFTWARE.
29  *************************************************************************************************/
30 
31 #ifdef __clang__
32 #pragma clang diagnostic push
33 #pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
34 #endif
35 
36 /**
37  * @file
38  * @brief Error logging/reporting routines.
39  * @author Anton Adamansky (adamansky@softmotions.com)
40  *
41  * Before using API of this module you should call
42  * `iw_init(void)` iowow module initialization routine.
43  *
44  * By default all logging output redirected to the `stderr`
45  * you can owerride it by passing  instance of `IWLOG_DEFAULT_OPTS`
46  * to the `iwlog_set_logfn_opts(void*)`
47  *
48  * A custom error logging function may be implemented with `IWLOG_FN` signature
49  * and registered by `void iwlog_set_logfn(IWLOG_FN fp)`
50  *
51  * The following methods normally used for logging:
52  * @verbatim
53     iwlog_{debug,info,warn,error}
54     iwlog_ecode_{debug,info,warn,error} @endverbatim
55  */
56 
57 #include "iowow.h"
58 
59 #include <stdint.h>
60 #include <stdarg.h>
61 #include <stdio.h>
62 
63 #ifdef __APPLE__
64 #include <xlocale.h>
65 #else
66 #include <locale.h>
67 #endif
68 
69 IW_EXTERN_C_START
70 
71 #ifndef IW_ERROR_START
72 #define IW_ERROR_START 70000
73 #endif
74 
75 /**
76  * @enum iw_ecode
77  * @brief Common used error codes.
78  */
79 typedef enum {
80   IW_OK = 0,                      /**< No error. */
81   IW_ERROR_FAIL = IW_ERROR_START, /**< Unspecified error. */
82   IW_ERROR_ERRNO,                 /**< Error with expected errno status set. */
83   IW_ERROR_IO_ERRNO,        /**< IO error with expected errno status set. */
84   IW_ERROR_NOT_EXISTS,      /**< Resource is not exists. */
85   IW_ERROR_READONLY,        /**< Resource is readonly. */
86   IW_ERROR_ALREADY_OPENED,  /**< Resource is already opened. */
87   IW_ERROR_THREADING,       /**< Threading error. */
88   IW_ERROR_THREADING_ERRNO, /**< Threading error with errno status set. */
89   IW_ERROR_ASSERTION,       /**< Generic assertion error. */
90   IW_ERROR_INVALID_HANDLE,  /**< Invalid HANDLE value. */
91   IW_ERROR_OUT_OF_BOUNDS,   /**< Invalid bounds specified. */
92   IW_ERROR_NOT_IMPLEMENTED, /**< Method is not implemented. */
93   IW_ERROR_ALLOC,           /**< Memory allocation failed. */
94   IW_ERROR_INVALID_STATE,   /**< Illegal state error. */
95   IW_ERROR_NOT_ALIGNED,     /**< Argument is not aligned properly. */
96   IW_ERROR_FALSE,           /**< Request rejection/false response. */
97   IW_ERROR_INVALID_ARGS,    /**< Invalid function arguments. */
98   IW_ERROR_OVERFLOW,        /**< Overflow. */
99   IW_ERROR_INVALID_VALUE    /**< Invalid value. */
100 } iw_ecode;
101 
102 /**
103  * @enum iwlog_lvl
104  * @brief Available logging vebosity levels.
105  */
106 typedef enum {
107   IWLOG_ERROR = 0,
108   IWLOG_WARN = 1,
109   IWLOG_INFO = 2,
110   IWLOG_DEBUG = 3
111 } iwlog_lvl;
112 
113 /**
114  * @brief Options for the default logging function.
115  * @see iwlog_set_logfn_opts(void*)
116  */
117 typedef struct {
118   FILE *out; /**< Output file stream. Default: `stderr`  */
119 } IWLOG_DEFAULT_OPTS;
120 
121 /**
122  * @brief Logging function pointer.
123  *
124  * @param locale Locale used to print error message.
125  * @param lvl Log level.
126  * @param ecode Error code specified.
127  * @param errno_code Optional errno code. Set it to 0 if errno not used.
128  * @param file File name. Can be `NULL`
129  * @param line Line number in the file.
130  * @param ts Message time-stamp
131  * @param fmt `printf` style message format
132  * @return Not zero error code in the case of error.
133  *
134  * @see iwlog_set_logfn(IWLOG_FN)
135  */
136 typedef iwrc(*IWLOG_FN)(FILE *out, locale_t locale, iwlog_lvl lvl, iwrc ecode,
137                         int errno_code, int werror_code, const char *file,
138                         int line, uint64_t ts, void *opts, const char *fmt,
139                         va_list argp);
140 
141 /**
142  * @brief Return the locale aware error code explanation message.
143  *
144  * @param locale Locale used. Can be `NULL`
145  * @param ecode Error code
146  * @return Message string describes a given error code or `NULL` if
147  *         no message found.
148  */
149 typedef const char *(*IWLOG_ECODE_FN)(locale_t locale, uint32_t ecode);
150 
151 /**
152  * @brief Attach the specified @a errno_code code into @a rc code
153  * @param rc IOWOW error code
154  * @param errno_code Error code will be embedded into.
155  * @return Updated rc code
156  */
157 IW_EXPORT iwrc iwrc_set_errno(iwrc rc, int errno_code);
158 
159 /**
160  * @brief Strip the attached `errno` code from the specified @a rc and
161  * return errno code.
162  *
163  * @param rc `errno` code or `0`
164  */
165 IW_EXPORT uint32_t iwrc_strip_errno(iwrc *rc);
166 
167 #ifdef _WIN32
168 
169 /**
170  * @brief Attach the specified windows @a werror code into @a rc code
171  * @param rc IOWOW error code
172  * @param errno_code Error code will be embedded into.
173  * @return Updated rc code
174  */
175 IW_EXPORT iwrc iwrc_set_werror(iwrc rc, uint32_t werror);
176 
177 /**
178  * @brief Strip the attached windows `werror` code from the specified @a rc and
179  * return this errno code.
180  *
181  * @param rc `errno` code or `0`
182  */
183 IW_EXPORT uint32_t iwrc_strip_werror(iwrc *rc);
184 
185 #endif
186 
187 /**
188  * @brief Remove embedded @a errno code from the passed @a rc
189  * @param [in,out] rc
190  */
191 IW_EXPORT void iwrc_strip_code(iwrc *rc);
192 
193 /**
194  * @brief Sets current logging function.
195  * @warning Not thread safe.
196  *
197  * @param fp Logging function pointer.
198  * @return Not zero if error occured.
199  */
200 IW_EXPORT void iwlog_set_logfn(IWLOG_FN fp);
201 
202 /**
203  * @brief Get a default logging function.
204  */
205 IW_EXPORT IWLOG_FN iwlog_get_logfn(void);
206 
207 /**
208  * @brief Set opaque options structure for the
209  *        current logging function implementation.
210  * @param opts
211  * @see `IWLOG_DEFAULT_OPTS`
212  * @see `IWLOG_FN`
213  */
214 IW_EXPORT void iwlog_set_logfn_opts(void *opts);
215 
216 /**
217  * @brief Returns string representation of a given error code.
218  * @param ecode Error code
219  * @return
220  */
221 IW_EXPORT const char *iwlog_ecode_explained(iwrc ecode);
222 
223 /**
224  * @brief Register error code explanation function.
225  * @note Up to `128` @a fp functions can be registered.
226  * @param fp
227  * @return `0` on success or error code.
228  */
229 IW_EXPORT iwrc iwlog_register_ecodefn(IWLOG_ECODE_FN fp);
230 
231 /**
232  * @brief Logs a message.
233  * @param lvl       Logging level.
234  * @param ecode     Error code or zero.
235  * @param file      Module file, can be `NULL`
236  * @param line      Line in module.
237  * @param fmt       Printf like message format.
238  * @return
239  */
240 IW_EXPORT iwrc iwlog(iwlog_lvl lvl, iwrc ecode, const char *file, int line,
241                      const char *fmt, ...);
242 
243 IW_EXPORT void iwlog2(iwlog_lvl lvl, iwrc ecode, const char *file, int line,
244                       const char *fmt, ...);
245 
246 IW_EXPORT iwrc iwlog_va(FILE *out, iwlog_lvl lvl, iwrc ecode, const char *file, int line,
247                         const char *fmt, va_list argp);
248 
249 #ifdef _DEBUG
250 #define iwlog_debug(IW_fmt, ...) \
251   iwlog2(IWLOG_DEBUG, 0, __FILE__, __LINE__, (IW_fmt), ##__VA_ARGS__)
252 #else
253 #define iwlog_debug(IW_fmt, ...)
254 #endif
255 #define iwlog_info(IW_fmt, ...) \
256   iwlog2(IWLOG_INFO, 0, __FILE__, __LINE__, (IW_fmt), ##__VA_ARGS__)
257 #define iwlog_warn(IW_fmt, ...) \
258   iwlog2(IWLOG_WARN, 0, __FILE__, __LINE__, (IW_fmt), ##__VA_ARGS__)
259 #define iwlog_error(IW_fmt, ...) \
260   iwlog2(IWLOG_ERROR, 0, __FILE__, __LINE__, (IW_fmt), ##__VA_ARGS__)
261 
262 #ifdef _DEBUG
263 #define iwlog_debug2(IW_fmt) \
264   iwlog2(IWLOG_DEBUG, 0, __FILE__, __LINE__, (IW_fmt))
265 #else
266 #define iwlog_debug2(IW_fmt)
267 #endif
268 #define iwlog_info2(IW_fmt) iwlog2(IWLOG_INFO, 0, __FILE__, __LINE__, (IW_fmt))
269 #define iwlog_warn2(IW_fmt) iwlog2(IWLOG_WARN, 0, __FILE__, __LINE__, (IW_fmt))
270 #define iwlog_error2(IW_fmt) \
271   iwlog2(IWLOG_ERROR, 0, __FILE__, __LINE__, (IW_fmt))
272 
273 #ifdef _DEBUG
274 #define iwlog_ecode_debug(IW_ecode, IW_fmt, ...) \
275   iwlog2(IWLOG_DEBUG, (IW_ecode), __FILE__, __LINE__, (IW_fmt), ##__VA_ARGS__)
276 #else
277 #define iwlog_ecode_debug(IW_ecode, IW_fmt, ...)
278 #endif
279 #define iwlog_ecode_info(IW_ecode, IW_fmt, ...) \
280   iwlog2(IWLOG_INFO, (IW_ecode), __FILE__, __LINE__, (IW_fmt), ##__VA_ARGS__)
281 #define iwlog_ecode_warn(IW_ecode, IW_fmt, ...) \
282   iwlog2(IWLOG_WARN, (IW_ecode), __FILE__, __LINE__, (IW_fmt), ##__VA_ARGS__)
283 #define iwlog_ecode_error(IW_ecode, IW_fmt, ...) \
284   iwlog2(IWLOG_ERROR, (IW_ecode), __FILE__, __LINE__, (IW_fmt), ##__VA_ARGS__)
285 
286 #ifdef _DEBUG
287 #define iwlog_ecode_debug2(IW_ecode, IW_fmt) \
288   iwlog2(IWLOG_DEBUG, (IW_ecode), __FILE__, __LINE__, (IW_fmt))
289 #else
290 #define iwlog_ecode_debug2(IW_ecode, IW_fmt)
291 #endif
292 #define iwlog_ecode_info2(IW_ecode, IW_fmt) \
293   iwlog2(IWLOG_INFO, (IW_ecode), __FILE__, __LINE__, (IW_fmt))
294 #define iwlog_ecode_warn2(IW_ecode, IW_fmt) \
295   iwlog2(IWLOG_WARN, (IW_ecode), __FILE__, __LINE__, (IW_fmt))
296 #define iwlog_ecode_error2(IW_ecode, IW_fmt) \
297   iwlog2(IWLOG_ERROR, (IW_ecode), __FILE__, __LINE__, (IW_fmt))
298 
299 #ifdef _DEBUG
300 #define iwlog_ecode_debug3(IW_ecode) \
301   iwlog2(IWLOG_DEBUG, (IW_ecode), __FILE__, __LINE__, "")
302 #else
303 #define iwlog_ecode_debug3(IW_ecode)
304 #endif
305 #define iwlog_ecode_info3(IW_ecode) iwlog2(IWLOG_INFO, (IW_ecode), __FILE__, __LINE__, ""))
306 #define iwlog_ecode_warn3(IW_ecode) \
307   iwlog2(IWLOG_WARN, (IW_ecode), __FILE__, __LINE__, "")
308 #define iwlog_ecode_error3(IW_ecode) \
309   iwlog2(IWLOG_ERROR, (IW_ecode), __FILE__, __LINE__, "")
310 
311 #define IWRC(IW_act, IW_rc)                                  \
312   {                                                          \
313     iwrc __iwrc = (IW_act);                                  \
314     if (__iwrc) {                                            \
315       if (!(IW_rc))                                          \
316         (IW_rc) = __iwrc;                                    \
317       else                                                   \
318         iwlog2(IWLOG_ERROR, __iwrc, __FILE__, __LINE__, ""); \
319     }                                                        \
320   }
321 
322 #define IWRC2(IW_act, IW_lvl)                                 \
323   {                                                           \
324     iwrc __iwrc = (IW_act);                                   \
325     if (__iwrc) {                                             \
326       iwlog2(IWLOG_##IW_lvl, __iwrc, __FILE__, __LINE__, ""); \
327     }                                                         \
328   }
329 
330 #define IWRC3(IW_act, IW_rc, IW_lvl)                            \
331   {                                                             \
332     iwrc __iwrc = (IW_act);                                     \
333     if (__iwrc) {                                               \
334       if (!(IW_rc))                                             \
335         (IW_rc) = __iwrc;                                       \
336       else                                                      \
337         iwlog2(IWLOG_##IW_lvl, __iwrc, __FILE__, __LINE__, ""); \
338     }                                                           \
339   }
340 
341 /**
342  * @brief Initiate this submodule.
343  * @return `0` on success or error code.
344  */
345 IW_EXPORT iwrc iwlog_init(void);
346 
347 #ifdef __clang__
348 #pragma clang diagnostic pop
349 #endif
350 
351 IW_EXTERN_C_END
352 #endif
353