aboutsummaryrefslogtreecommitdiffstats
path: root/common/kernel/log.cc
diff options
context:
space:
mode:
authorgatecat <gatecat@ds0.me>2022-04-08 13:42:54 +0100
committergatecat <gatecat@ds0.me>2022-04-08 13:42:54 +0100
commit49f178ed94b5fad00d25dbd12adea0bf4732f803 (patch)
treeea642e20bc07441a800944390e1f904e6ce5b113 /common/kernel/log.cc
parente42e22575f20b59634f88b5cf694efdb413ff0a0 (diff)
downloadnextpnr-49f178ed94b5fad00d25dbd12adea0bf4732f803.tar.gz
nextpnr-49f178ed94b5fad00d25dbd12adea0bf4732f803.tar.bz2
nextpnr-49f178ed94b5fad00d25dbd12adea0bf4732f803.zip
Split up common into kernel,place,route
Signed-off-by: gatecat <gatecat@ds0.me>
Diffstat (limited to 'common/kernel/log.cc')
-rw-r--r--common/kernel/log.cc198
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