From ff6d8a87f9569a42c7827428f2329280c9b633b9 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Mon, 1 Aug 2016 01:16:15 -0400 Subject: Implement LV2 log extension as host Only print color logs if output is a terminal. --- src/Log.cpp | 157 ++++++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 126 insertions(+), 31 deletions(-) (limited to 'src/Log.cpp') diff --git a/src/Log.cpp b/src/Log.cpp index c72f3dbb..b2d30b7d 100644 --- a/src/Log.cpp +++ b/src/Log.cpp @@ -1,6 +1,6 @@ /* This file is part of Ingen. - Copyright 2007-2015 David Robillard + Copyright 2007-2016 David Robillard Ingen is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free @@ -14,65 +14,160 @@ along with Ingen. If not, see . */ -#include +#include #include "ingen/Log.hpp" +#include "ingen/Node.hpp" #include "ingen/URIs.hpp" +#include "ingen/World.hpp" + +#ifdef HAVE_ISATTY +# include +#else +inline int isatty(int fd) { return 0; } +#endif namespace Ingen { -static const char* const ANSI_RESET = "\033[0m"; -static const char* const ANSI_RED = "\033[0;31m"; -//static const char* const ANSI_GREEN = "\033[0;32m"; -static const char* const ANSI_YELLOW = "\033[0;33m"; -//static const char* const ANSI_BLUE = "\033[0;34m"; -//static const char* const ANSI_MAGENTA = "\033[0;35m"; -//static const char* const ANSI_CYAN = "\033[0;36m"; -//static const char* const ANSI_WHITE = "\033[0;37m"; +class ColorContext { +public: + enum class Color { RED = 31, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE }; + + ColorContext(FILE* stream, Color color) : stream(stream) { + if (isatty(fileno(stream))) { + fprintf(stream, "\033[0;%dm", color); + } + } + + ~ColorContext() { + if (isatty(fileno(stream))) { + fprintf(stream, "\033[0m"); + fflush(stream); + } + } + + + FILE* stream; +}; Log::Log(LV2_Log_Log* log, URIs& uris) : _log(log) , _uris(uris) , _flush(false) + , _trace(false) {} void Log::error(const std::string& msg) { - if (_log) { - _log->printf(_log->handle, _uris.log_Error, "%s", msg.c_str()); - } else { - std::cerr << ANSI_RED << msg << ANSI_RESET; - if (_flush) { - std::flush(std::cerr); - } - } + va_list args; + vtprintf(_uris.log_Error, msg.c_str(), args); } void Log::warn(const std::string& msg) { - if (_log) { - _log->printf(_log->handle, _uris.log_Warning, "%s", msg.c_str()); - } else { - std::cerr << ANSI_YELLOW << msg << ANSI_RESET; - if (_flush) { - std::flush(std::cerr); - } - } + va_list args; + vtprintf(_uris.log_Warning, msg.c_str(), args); } void Log::info(const std::string& msg) { + va_list args; + vtprintf(_uris.log_Note, msg.c_str(), args); +} + +void +Log::trace(const std::string& msg) +{ + va_list args; + vtprintf(_uris.log_Trace, msg.c_str(), args); +} + +void +Log::print(FILE* stream, const std::string& msg) +{ + fprintf(stream, "%s", msg.c_str()); + if (_flush) { + fflush(stdout); + } +} + +int +Log::vtprintf(LV2_URID type, const char* fmt, va_list args) +{ + int ret = 0; if (_log) { - _log->printf(_log->handle, _uris.log_Note, "%s", msg.c_str()); + ret = _log->vprintf(_log->handle, type, fmt, args); + } else if (type == _uris.log_Error) { + ColorContext ctx(stderr, ColorContext::Color::RED); + ret = vfprintf(stderr, fmt, args); + } else if (type == _uris.log_Warning) { + ColorContext ctx(stderr, ColorContext::Color::YELLOW); + ret = vfprintf(stderr, fmt, args); + } else if (type == _uris.log_Note) { + ColorContext ctx(stderr, ColorContext::Color::GREEN); + ret = vfprintf(stdout, fmt, args); + } else if (_trace && type == _uris.log_Trace) { + ColorContext ctx(stderr, ColorContext::Color::GREEN); + ret = vfprintf(stderr, fmt, args); } else { - std::cout << msg; - if (_flush) { - std::flush(std::cout); - } + fprintf(stderr, "Unknown log type %d\n", type); + return 0; } + if (_flush) { + fflush(stdout); + } + return ret; +} + +static int +log_vprintf(LV2_Log_Handle handle, LV2_URID type, const char* fmt, va_list args) +{ + Log::Feature::Handle* f = (Log::Feature::Handle*)handle; + va_list noargs; + + int ret = f->log->vtprintf(type, f->node->path().c_str(), noargs); + ret += f->log->vtprintf(type, ": ", noargs); + ret += f->log->vtprintf(type, fmt, args); + + return ret; +} + +static int +log_printf(LV2_Log_Handle handle, LV2_URID type, const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + const int ret = log_vprintf(handle, type, fmt, args); + va_end(args); + + return ret; +} + +static void +free_log_feature(LV2_Feature* feature) { + LV2_Log_Log* lv2_log = (LV2_Log_Log*)feature->data; + free(lv2_log->handle); + free(feature); +} + +SPtr +Log::Feature::feature(World* world, Node* block) +{ + Handle* handle = (Handle*)calloc(1, sizeof(Handle)); + handle->lv2_log.handle = handle; + handle->lv2_log.printf = log_printf; + handle->lv2_log.vprintf = log_vprintf; + handle->log = &world->log(); + handle->node = block; + + LV2_Feature* f = (LV2_Feature*)malloc(sizeof(LV2_Feature)); + f->URI = LV2_LOG__log; + f->data = &handle->lv2_log; + + return SPtr(f, &free_log_feature); } } // namespace Ingen -- cgit v1.2.1