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-2022 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 /** 72 * @enum iw_ecode 73 * @brief Common used error codes. 74 */ 75 typedef enum { 76 IW_OK = 0, /**< No error. */ 77 IW_ERROR_FAIL = IW_ERROR_START, /**< Unspecified error. */ 78 IW_ERROR_ERRNO, /**< Error with expected errno status set. */ 79 IW_ERROR_IO_ERRNO, /**< IO error with expected errno status set. */ 80 IW_ERROR_AGAIN, 81 IW_ERROR_NOT_EXISTS, /**< Resource is not exists. */ 82 IW_ERROR_READONLY, /**< Resource is readonly. */ 83 IW_ERROR_ALREADY_OPENED, /**< Resource is already opened. */ 84 IW_ERROR_THREADING, /**< Threading error. */ 85 IW_ERROR_THREADING_ERRNO, /**< Threading error with errno status set. */ 86 IW_ERROR_ASSERTION, /**< Generic assertion error. */ 87 IW_ERROR_INVALID_HANDLE, /**< Invalid HANDLE value. */ 88 IW_ERROR_OUT_OF_BOUNDS, /**< Invalid bounds specified. */ 89 IW_ERROR_NOT_IMPLEMENTED, /**< Method is not implemented. */ 90 IW_ERROR_ALLOC, /**< Memory allocation failed. */ 91 IW_ERROR_INVALID_STATE, /**< Illegal state error. */ 92 IW_ERROR_NOT_ALIGNED, /**< Argument is not aligned properly. */ 93 IW_ERROR_FALSE, /**< Request rejection/false response. */ 94 IW_ERROR_INVALID_ARGS, /**< Invalid function arguments. */ 95 IW_ERROR_OVERFLOW, /**< Overflow. */ 96 IW_ERROR_INVALID_VALUE, /**< Invalid value. */ 97 IW_ERROR_UNEXPECTED_RESPONSE, /**< Unexpected response (IW_ERROR_UNEXPECTED_RESPONSE) */ 98 IW_ERROR_NOT_ALLOWED, /**< Action is not allowed. (IW_ERROR_NOT_ALLOWED) */ 99 IW_ERROR_UNSUPPORTED, /**< Unsupported opration. (IW_ERROR_UNSUPPORTED) */ 100 IW_ERROR_EOF, /**< End of IO stream/file (IW_ERROR_EOF) */ 101 IW_ERROR_UNEXPECTED_INPUT, /**< Unexpected input/data (IW_ERROR_UNEXPECTED_INPUT) */ 102 IW_ERROR_IO, /**< IO error (IW_ERROR_IO) */ 103 IW_ERROR_INVALID_CONFIG, /**< Invalid configuration (IW_ERROR_INVALID_CONFIG) */ 104 } iw_ecode; 105 106 /** 107 * @enum iwlog_lvl 108 * @brief Available logging vebosity levels. 109 */ 110 typedef enum { 111 IWLOG_ERROR = 0, 112 IWLOG_WARN = 1, 113 IWLOG_INFO = 2, 114 IWLOG_VERBOSE = 3, 115 IWLOG_DEBUG = 4, 116 } iwlog_lvl; 117 118 /** 119 * @brief Options for the default logging function. 120 * @see iwlog_set_logfn_opts(void*) 121 */ 122 typedef struct { 123 FILE *out; /**< Output file stream. Default: `stderr` */ 124 } IWLOG_DEFAULT_OPTS; 125 126 /** 127 * @brief Logging function pointer. 128 * 129 * @param locale Locale used to print error message. 130 * @param lvl Log level. 131 * @param ecode Error code specified. 132 * @param errno_code Optional errno code. Set it to 0 if errno not used. 133 * @param file File name. Can be `NULL` 134 * @param line Line number in the file. 135 * @param ts Message time-stamp 136 * @param fmt `printf` style message format 137 * @return Not zero error code in the case of error. 138 * 139 * @see iwlog_set_logfn(IWLOG_FN) 140 */ 141 typedef iwrc (*IWLOG_FN)( 142 FILE *out, locale_t locale, iwlog_lvl lvl, iwrc ecode, 143 int errno_code, int werror_code, const char *file, 144 int line, uint64_t ts, void *opts, const char *fmt, 145 va_list argp, bool no_va); 146 147 /** 148 * @brief Return the locale aware error code explanation message. 149 * 150 * @param locale Locale used. Can be `NULL` 151 * @param ecode Error code 152 * @return Message string describes a given error code or `NULL` if 153 * no message found. 154 */ 155 typedef const char* (*IWLOG_ECODE_FN)(locale_t locale, uint32_t ecode); 156 157 /** 158 * @brief Attach the specified @a errno_code code into @a rc code 159 * @param rc IOWOW error code 160 * @param errno_code Error code will be embedded into. 161 * @return Updated rc code 162 */ 163 IW_EXPORT iwrc iwrc_set_errno(iwrc rc, int errno_code); 164 165 /** 166 * @brief Strip the attached `errno` code from the specified @a rc and 167 * return errno code. 168 * 169 * @param rc `errno` code or `0` 170 */ 171 IW_EXPORT uint32_t iwrc_strip_errno(iwrc *rc); 172 173 #ifdef _WIN32 174 175 /** 176 * @brief Attach the specified windows @a werror code into @a rc code 177 * @param rc IOWOW error code 178 * @param errno_code Error code will be embedded into. 179 * @return Updated rc code 180 */ 181 IW_EXPORT iwrc iwrc_set_werror(iwrc rc, uint32_t werror); 182 183 /** 184 * @brief Strip the attached windows `werror` code from the specified @a rc and 185 * return this errno code. 186 * 187 * @param rc `errno` code or `0` 188 */ 189 IW_EXPORT uint32_t iwrc_strip_werror(iwrc *rc); 190 191 #endif 192 193 /** 194 * @brief Remove embedded @a errno code from the passed @a rc 195 * @param [in,out] rc 196 */ 197 IW_EXPORT void iwrc_strip_code(iwrc *rc); 198 199 /** 200 * @brief Sets current logging function. 201 * @warning Not thread safe. 202 * 203 * @param fp Logging function pointer. 204 * @return Not zero if error occured. 205 */ 206 IW_EXPORT void iwlog_set_logfn(IWLOG_FN fp, void *opts); 207 208 /** 209 * @brief Get a default logging function. 210 * 211 */ 212 IW_EXPORT IWLOG_FN iwlog_get_logfn(void); 213 214 /** 215 * @brief Returns string representation of a given error code. 216 * @param ecode Error code 217 * @return 218 */ 219 IW_EXPORT const char* iwlog_ecode_explained(iwrc ecode); 220 221 /** 222 * @brief Register error code explanation function. 223 * @note Up to `128` @a fp functions can be registered. 224 * @param fp 225 * @return `0` on success or error code. 226 */ 227 IW_EXPORT iwrc iwlog_register_ecodefn(IWLOG_ECODE_FN fp); 228 229 /** 230 * @brief Logs a message. 231 * @param lvl Logging level. 232 * @param ecode Error code or zero. 233 * @param file Module file, can be `NULL` 234 * @param line Line in module. 235 * @param fmt Printf like message format. 236 * @return 237 */ 238 IW_EXPORT iwrc iwlog( 239 iwlog_lvl lvl, iwrc ecode, const char *file, int line, 240 const char *fmt, ...) __attribute__((format(__printf__, 5, 6))); 241 242 IW_EXPORT void iwlog2( 243 iwlog_lvl lvl, iwrc ecode, const char *file, int line, 244 const char *fmt, ...) __attribute__((format(__printf__, 5, 6))); 245 246 IW_EXPORT void iwlog3( 247 iwlog_lvl lvl, iwrc ecode, const char *file, int line, 248 const char *data); 249 250 IW_EXPORT iwrc iwlog_va( 251 FILE *out, iwlog_lvl lvl, iwrc ecode, const char *file, int line, 252 const char *fmt, va_list argp, bool no_va); 253 254 #ifdef _DEBUG 255 #define iwlog_debug(IW_fmt, ...) \ 256 iwlog2(IWLOG_DEBUG, 0, __FILE__, __LINE__, (IW_fmt), ## __VA_ARGS__) 257 #else 258 #define iwlog_debug(IW_fmt, ...) 259 #endif 260 #define iwlog_verbose(IW_fmt, ...) \ 261 iwlog2(IWLOG_VERBOSE, 0, __FILE__, __LINE__, (IW_fmt), ## __VA_ARGS__) 262 #define iwlog_info(IW_fmt, ...) \ 263 iwlog2(IWLOG_INFO, 0, __FILE__, __LINE__, (IW_fmt), ## __VA_ARGS__) 264 #define iwlog_warn(IW_fmt, ...) \ 265 iwlog2(IWLOG_WARN, 0, __FILE__, __LINE__, (IW_fmt), ## __VA_ARGS__) 266 #define iwlog_error(IW_fmt, ...) \ 267 iwlog2(IWLOG_ERROR, 0, __FILE__, __LINE__, (IW_fmt), ## __VA_ARGS__) 268 269 #ifdef _DEBUG 270 #define iwlog_debug2(IW_fmt) \ 271 iwlog3(IWLOG_DEBUG, 0, __FILE__, __LINE__, (IW_fmt)) 272 #else 273 #define iwlog_debug2(IW_fmt) 274 #endif 275 #define iwlog_verbose2(IW_fmt) iwlog3(IWLOG_VERBOSE, 0, __FILE__, __LINE__, (IW_fmt)) 276 #define iwlog_info2(IW_fmt) iwlog3(IWLOG_INFO, 0, __FILE__, __LINE__, (IW_fmt)) 277 #define iwlog_warn2(IW_fmt) iwlog3(IWLOG_WARN, 0, __FILE__, __LINE__, (IW_fmt)) 278 #define iwlog_error2(IW_fmt) \ 279 iwlog3(IWLOG_ERROR, 0, __FILE__, __LINE__, (IW_fmt)) 280 281 #ifdef _DEBUG 282 #define iwlog_ecode_debug(IW_ecode, IW_fmt, ...) \ 283 iwlog2(IWLOG_DEBUG, (IW_ecode), __FILE__, __LINE__, (IW_fmt), ## __VA_ARGS__) 284 #else 285 #define iwlog_ecode_debug(IW_ecode, IW_fmt, ...) 286 #endif 287 #define iwlog_ecode_verbose(IW_ecode, IW_fmt, ...) \ 288 iwlog2(IWLOG_VERBOSE, (IW_ecode), __FILE__, __LINE__, (IW_fmt), ## __VA_ARGS__) 289 #define iwlog_ecode_info(IW_ecode, IW_fmt, ...) \ 290 iwlog2(IWLOG_INFO, (IW_ecode), __FILE__, __LINE__, (IW_fmt), ## __VA_ARGS__) 291 #define iwlog_ecode_warn(IW_ecode, IW_fmt, ...) \ 292 iwlog2(IWLOG_WARN, (IW_ecode), __FILE__, __LINE__, (IW_fmt), ## __VA_ARGS__) 293 #define iwlog_ecode_error(IW_ecode, IW_fmt, ...) \ 294 iwlog2(IWLOG_ERROR, (IW_ecode), __FILE__, __LINE__, (IW_fmt), ## __VA_ARGS__) 295 296 #ifdef _DEBUG 297 #define iwlog_ecode_debug2(IW_ecode, IW_fmt) \ 298 iwlog3(IWLOG_DEBUG, (IW_ecode), __FILE__, __LINE__, (IW_fmt)) 299 #else 300 #define iwlog_ecode_debug2(IW_ecode, IW_fmt) 301 #endif 302 #define iwlog_ecode_verbose2(IW_ecode, IW_fmt) \ 303 iwlog3(IWLOG_VERBOSE, (IW_ecode), __FILE__, __LINE__, (IW_fmt)) 304 #define iwlog_ecode_info2(IW_ecode, IW_fmt) \ 305 iwlog3(IWLOG_INFO, (IW_ecode), __FILE__, __LINE__, (IW_fmt)) 306 #define iwlog_ecode_warn2(IW_ecode, IW_fmt) \ 307 iwlog3(IWLOG_WARN, (IW_ecode), __FILE__, __LINE__, (IW_fmt)) 308 #define iwlog_ecode_error2(IW_ecode, IW_fmt) \ 309 iwlog3(IWLOG_ERROR, (IW_ecode), __FILE__, __LINE__, (IW_fmt)) 310 311 #ifdef _DEBUG 312 #define iwlog_ecode_debug3(IW_ecode) \ 313 iwlog3(IWLOG_DEBUG, (IW_ecode), __FILE__, __LINE__, "") 314 #else 315 #define iwlog_ecode_debug3(IW_ecode) 316 #endif 317 #define iwlog_ecode_verbose3(IW_ecode) iwlog3(IWLOG_VERBOSE, (IW_ecode), __FILE__, __LINE__, "")) 318 #define iwlog_ecode_info3(IW_ecode) iwlog3(IWLOG_INFO, (IW_ecode), __FILE__, __LINE__, "")) 319 #define iwlog_ecode_warn3(IW_ecode) \ 320 iwlog3(IWLOG_WARN, (IW_ecode), __FILE__, __LINE__, "") 321 #define iwlog_ecode_error3(IW_ecode) \ 322 iwlog3(IWLOG_ERROR, (IW_ecode), __FILE__, __LINE__, "") 323 324 #define IWRC(IW_act, IW_rc) \ 325 { \ 326 iwrc __iwrc = (IW_act); \ 327 if (__iwrc) { \ 328 if (!(IW_rc)) \ 329 (IW_rc) = __iwrc; \ 330 else \ 331 iwlog3(IWLOG_ERROR, __iwrc, __FILE__, __LINE__, ""); \ 332 } \ 333 } 334 335 #define IWRC2(IW_act, IW_lvl) \ 336 { \ 337 iwrc __iwrc = (IW_act); \ 338 if (__iwrc) { \ 339 iwlog3(IWLOG_ ## IW_lvl, __iwrc, __FILE__, __LINE__, ""); \ 340 } \ 341 } 342 343 #define IWRC3(IW_act, IW_rc, IW_lvl) \ 344 { \ 345 iwrc __iwrc = (IW_act); \ 346 if (__iwrc) { \ 347 if (!(IW_rc)) \ 348 (IW_rc) = __iwrc; \ 349 else \ 350 iwlog3(IWLOG_ ## IW_lvl, __iwrc, __FILE__, __LINE__, ""); \ 351 } \ 352 } 353 354 /** 355 * @brief Initiate this submodule. 356 * @return `0` on success or error code. 357 */ 358 IW_EXPORT iwrc iwlog_init(void); 359 360 #ifdef __clang__ 361 #pragma clang diagnostic pop 362 #endif 363 364 IW_EXTERN_C_END 365 #endif 366