From 49f178ed94b5fad00d25dbd12adea0bf4732f803 Mon Sep 17 00:00:00 2001 From: gatecat Date: Fri, 8 Apr 2022 13:42:54 +0100 Subject: Split up common into kernel,place,route Signed-off-by: gatecat --- common/kernel/log.cc | 198 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 198 insertions(+) create mode 100644 common/kernel/log.cc (limited to 'common/kernel/log.cc') diff --git a/common/kernel/log.cc b/common/kernel/log.cc new file mode 100644 index 00000000..8b1ad43b --- /dev/null +++ b/common/kernel/log.cc @@ -0,0 +1,198 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 Claire Xenia Wolf + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" + +NEXTPNR_NAMESPACE_BEGIN + +NPNR_NORETURN void logv_error(const char *format, va_list ap) NPNR_ATTRIBUTE(noreturn); + +std::vector> log_streams; +log_write_type log_write_function = nullptr; + +std::string log_last_error; +void (*log_error_atexit)() = NULL; + +dict message_count_by_level; +static int log_newline_count = 0; +bool had_nonfatal_error = false; + +std::string stringf(const char *fmt, ...) +{ + std::string string; + va_list ap; + + va_start(ap, fmt); + string = vstringf(fmt, ap); + va_end(ap); + + return string; +} + +std::string vstringf(const char *fmt, va_list ap) +{ + std::string string; + char *str = NULL; + +#if defined(_WIN32) || defined(__CYGWIN__) + int sz = 64 + strlen(fmt), rc; + while (1) { + va_list apc; + va_copy(apc, ap); + str = (char *)realloc(str, sz); + rc = vsnprintf(str, sz, fmt, apc); + va_end(apc); + if (rc >= 0 && rc < sz) + break; + sz *= 2; + } +#else + if (vasprintf(&str, fmt, ap) < 0) + str = NULL; +#endif + + if (str != NULL) { + string = str; + free(str); + } + + return string; +} + +void logv(const char *format, va_list ap, LogLevel level = LogLevel::LOG_MSG) +{ + // + // Trim newlines from the beginning + while (format[0] == '\n' && format[1] != 0) { + log_always("\n"); + format++; + } + + std::string str = vstringf(format, ap); + + if (str.empty()) + return; + + size_t nnl_pos = str.find_last_not_of('\n'); + if (nnl_pos == std::string::npos) + log_newline_count += str.size(); + else + log_newline_count = str.size() - nnl_pos - 1; + + for (auto f : log_streams) + if (f.second <= level) + *f.first << str; + if (log_write_function) + log_write_function(str); +} + +void log_with_level(LogLevel level, const char *format, ...) +{ + message_count_by_level[level]++; + va_list ap; + va_start(ap, format); + logv(format, ap, level); + va_end(ap); +} + +void logv_prefixed(const char *prefix, const char *format, va_list ap, LogLevel level) +{ + std::string message = vstringf(format, ap); + + log_with_level(level, "%s%s", prefix, message.c_str()); + log_flush(); +} + +void log_always(const char *format, ...) +{ + va_list ap; + va_start(ap, format); + logv(format, ap, LogLevel::ALWAYS_MSG); + va_end(ap); +} + +void log(const char *format, ...) +{ + va_list ap; + va_start(ap, format); + logv(format, ap, LogLevel::LOG_MSG); + va_end(ap); +} + +void log_info(const char *format, ...) +{ + va_list ap; + va_start(ap, format); + logv_prefixed("Info: ", format, ap, LogLevel::INFO_MSG); + va_end(ap); +} + +void log_warning(const char *format, ...) +{ + va_list ap; + va_start(ap, format); + logv_prefixed("Warning: ", format, ap, LogLevel::WARNING_MSG); + va_end(ap); +} + +void log_error(const char *format, ...) +{ + va_list ap; + va_start(ap, format); + logv_prefixed("ERROR: ", format, ap, LogLevel::ERROR_MSG); + + if (log_error_atexit) + log_error_atexit(); + + throw log_execution_error_exception(); +} + +void log_break() +{ + if (log_newline_count < 2) + log("\n"); + if (log_newline_count < 2) + log("\n"); +} + +void log_nonfatal_error(const char *format, ...) +{ + va_list ap; + va_start(ap, format); + logv_prefixed("ERROR: ", format, ap, LogLevel::ERROR_MSG); + va_end(ap); + had_nonfatal_error = true; +} + +void log_flush() +{ + for (auto f : log_streams) + f.first->flush(); +} + +NEXTPNR_NAMESPACE_END -- cgit v1.2.3