mirror of
https://github.com/YosysHQ/nextpnr.git
synced 2026-05-05 15:43:30 +00:00
Split up common into kernel,place,route
Signed-off-by: gatecat <gatecat@ds0.me>
This commit is contained in:
198
common/kernel/log.cc
Normal file
198
common/kernel/log.cc
Normal file
@@ -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
|
||||
Reference in New Issue
Block a user