diff options
author | gatecat <gatecat@ds0.me> | 2022-04-08 14:32:33 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-04-08 14:32:33 +0100 |
commit | 57681e69ce75c781142908cf128bc3f3f59e2f6b (patch) | |
tree | ea642e20bc07441a800944390e1f904e6ce5b113 /common/kernel/log.cc | |
parent | e42e22575f20b59634f88b5cf694efdb413ff0a0 (diff) | |
parent | 49f178ed94b5fad00d25dbd12adea0bf4732f803 (diff) | |
download | nextpnr-57681e69ce75c781142908cf128bc3f3f59e2f6b.tar.gz nextpnr-57681e69ce75c781142908cf128bc3f3f59e2f6b.tar.bz2 nextpnr-57681e69ce75c781142908cf128bc3f3f59e2f6b.zip |
Merge pull request #973 from YosysHQ/gatecat/folder-tidy
Split up common into kernel,place,route
Diffstat (limited to 'common/kernel/log.cc')
-rw-r--r-- | common/kernel/log.cc | 198 |
1 files changed, 198 insertions, 0 deletions
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 <claire@yosyshq.com> + * + * 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 <list> +#include <map> +#include <set> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <vector> + +#include "log.h" + +NEXTPNR_NAMESPACE_BEGIN + +NPNR_NORETURN void logv_error(const char *format, va_list ap) NPNR_ATTRIBUTE(noreturn); + +std::vector<std::pair<std::ostream *, LogLevel>> log_streams; +log_write_type log_write_function = nullptr; + +std::string log_last_error; +void (*log_error_atexit)() = NULL; + +dict<LogLevel, int, loglevel_hash_ops> 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 |