#pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "global.h" #define LOG !(ov4::GLOBAL_DEBUG && verbose) ? (void)0 : ov4::LogVoidify() & std::clog namespace ov4 { struct LogVoidify { void operator&(std::ostream&) const {} }; inline constexpr int DECIMAL = 10; inline constexpr int NUMBER_LENGTH = 70; // even enough for binary // async-signal-safe void safe_print(const char *s, bool ignore_wrap = false); // async-signal-safe void safe_print(int x); // async-signal-safe void safe_debug(const char *s, bool ignore_wrap = false); // async-signal-safe void safe_debug(int x); // async-signal-safe bool isnum(const char *s); // async-signal-safe void reverse(char *str, int length); // async-signal-safe char *itoa(int num, char* str, int base); // async-signal-safe // remove '\n' from the string // when replacemen = '\0', '\n' is deleted (instead of really replacing by '\0' ) void wrap_eliminator(char *s, char replacement = '\0'); // async-signal-safe void _write_helper(const char *s); template void _safe_output_handler(T x) { int errno_old = errno; if constexpr (std::is_same_v) // int { char buffer[MAXLINE]; itoa(x, buffer, DECIMAL); _write_helper(buffer); } else if constexpr (std::is_same_v || std::is_same_v) // C-style string { _write_helper(x); } else // ??? { static_assert(false, "_safe_output_handler: unsopported type"); } errno = errno_old; } inline void safe_output() { ; // empty } // async-signal-safe output function // example: // safe_output("string", 123, variable); template void safe_output(T x, T_arg ...arg) { int errno_old = errno; _safe_output_handler(x); safe_output(arg...); errno = errno_old; } // async-signal-safe output function // example: // safe_output("string", 123, variable); template void safe_logger(T_arg ...arg) { int errno_old = errno; if (GLOBAL_DEBUG && verbose) { safe_output(arg...); } errno = errno_old; } void unix_error(const char *msg); void app_error(const char *msg); template void logger(std::format_string fmt, Args&&... args) { if constexpr (GLOBAL_DEBUG) { if (verbose) { print(std::clog, fmt, std::forward(args)...); std::clog.flush(); } } } template void loggerln(std::format_string fmt, Args&&... args) { if constexpr (GLOBAL_DEBUG) { if (verbose) { println(std::clog, fmt, std::forward(args)...); std::clog.flush(); } } } }