summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2016-08-01 01:16:15 -0400
committerDavid Robillard <d@drobilla.net>2016-08-01 03:43:56 -0400
commitff6d8a87f9569a42c7827428f2329280c9b633b9 (patch)
treed7ccbeaac5381e8cfd07c4ad5efd0872de65fd45
parent7eb24a2761deb9604f1c6b813e6de69876088f9e (diff)
downloadingen-ff6d8a87f9569a42c7827428f2329280c9b633b9.tar.gz
ingen-ff6d8a87f9569a42c7827428f2329280c9b633b9.tar.bz2
ingen-ff6d8a87f9569a42c7827428f2329280c9b633b9.zip
Implement LV2 log extension as host
Only print color logs if output is a terminal.
-rw-r--r--ingen/Log.hpp22
-rw-r--r--ingen/URIs.hpp1
-rw-r--r--src/Configuration.cpp1
-rw-r--r--src/Log.cpp157
-rw-r--r--src/URIs.cpp1
-rw-r--r--src/World.cpp6
-rw-r--r--src/server/UndoStack.cpp1
-rw-r--r--wscript6
8 files changed, 160 insertions, 35 deletions
diff --git a/ingen/Log.hpp b/ingen/Log.hpp
index 6c88e9a4..a868e714 100644
--- a/ingen/Log.hpp
+++ b/ingen/Log.hpp
@@ -1,6 +1,6 @@
/*
This file is part of Ingen.
- Copyright 2007-2015 David Robillard <http://drobilla.net/>
+ Copyright 2007-2016 David Robillard <http://drobilla.net/>
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
@@ -21,6 +21,7 @@
#include <boost/format.hpp>
+#include "ingen/LV2Features.hpp"
#include "ingen/ingen.h"
#include "lv2/lv2plug.in/ns/ext/log/log.h"
@@ -34,20 +35,39 @@ class INGEN_API Log {
public:
Log(LV2_Log_Log* log, URIs& uris);
+ struct Feature : public LV2Features::Feature {
+ const char* uri() const { return LV2_LOG__log; }
+
+ SPtr<LV2_Feature> feature(World* world, Node* block);
+
+ struct Handle {
+ LV2_Log_Log lv2_log;
+ Log* log;
+ Node* node;
+ };
+ };
+
void error(const std::string& msg);
void info(const std::string& msg);
void warn(const std::string& msg);
+ void trace(const std::string& msg);
inline void error(const fmt& fmt) { error(fmt.str()); }
inline void info(const fmt& fmt) { info(fmt.str()); }
inline void warn(const fmt& fmt) { warn(fmt.str()); }
+ int vtprintf(LV2_URID type, const char* fmt, va_list args);
+
void set_flush(bool f) { _flush = f; }
+ void set_trace(bool f) { _trace = f; }
private:
+ void print(FILE* stream, const std::string& msg);
+
LV2_Log_Log* _log;
URIs& _uris;
bool _flush;
+ bool _trace;
};
} // namespace Ingen
diff --git a/ingen/URIs.hpp b/ingen/URIs.hpp
index 52921085..9fc771da 100644
--- a/ingen/URIs.hpp
+++ b/ingen/URIs.hpp
@@ -127,6 +127,7 @@ public:
const Quark ingen_value;
const Quark log_Error;
const Quark log_Note;
+ const Quark log_Trace;
const Quark log_Warning;
const Quark lv2_AudioPort;
const Quark lv2_CVPort;
diff --git a/src/Configuration.cpp b/src/Configuration.cpp
index 0f3e3d53..7df565be 100644
--- a/src/Configuration.cpp
+++ b/src/Configuration.cpp
@@ -65,6 +65,7 @@ Configuration::Configuration(Forge& forge)
add("path", "path", 'L', "Target path for loaded graph", SESSION, forge.String, Atom());
add("queueSize", "queue-size", 'q', "Event queue size", GLOBAL, forge.Int, forge.make(4096));
add("flushLog", "flush-log", 'f', "Flush logs after every entry", SESSION, forge.Bool, forge.make(false));
+ add("trace", "trace", 't', "Show LV2 plugin trace messages", SESSION, forge.Bool, forge.make(false));
add("humanNames", "human-names", 0, "Show human names in GUI", GUI, forge.Bool, forge.make(true));
add("portLabels", "port-labels", 0, "Show port labels in GUI", GUI, forge.Bool, forge.make(true));
add("graphDirectory", "graph-directory", 0, "Default directory for opening graphs", GUI, forge.String, Atom());
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 <http://drobilla.net/>
+ Copyright 2007-2016 David Robillard <http://drobilla.net/>
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 <http://www.gnu.org/licenses/>.
*/
-#include <iostream>
+#include <stdio.h>
#include "ingen/Log.hpp"
+#include "ingen/Node.hpp"
#include "ingen/URIs.hpp"
+#include "ingen/World.hpp"
+
+#ifdef HAVE_ISATTY
+# include <unistd.h>
+#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<LV2_Feature>
+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<LV2_Feature>(f, &free_log_feature);
}
} // namespace Ingen
diff --git a/src/URIs.cpp b/src/URIs.cpp
index 005490c4..b272e48e 100644
--- a/src/URIs.cpp
+++ b/src/URIs.cpp
@@ -110,6 +110,7 @@ URIs::URIs(Forge& f, URIMap* map, LilvWorld* lworld)
, ingen_value (forge, map, lworld, INGEN__value)
, log_Error (forge, map, lworld, LV2_LOG__Error)
, log_Note (forge, map, lworld, LV2_LOG__Note)
+ , log_Trace (forge, map, lworld, LV2_LOG__Trace)
, log_Warning (forge, map, lworld, LV2_LOG__Warning)
, lv2_AudioPort (forge, map, lworld, LV2_CORE__AudioPort)
, lv2_CVPort (forge, map, lworld, LV2_CORE__CVPort)
diff --git a/src/World.cpp b/src/World.cpp
index 105363b6..38b27a9a 100644
--- a/src/World.cpp
+++ b/src/World.cpp
@@ -111,8 +111,8 @@ public:
, uri_map(new URIMap(log, map, unmap))
, forge(new Forge(*uri_map))
, uris(new URIs(*forge, uri_map, lilv_world))
- , log(lv2_log, *uris)
, conf(*forge)
+ , log(lv2_log, *uris)
{
// Parse default configuration files
std::list<std::string> files = conf.load_default("ingen", "options.ttl");
@@ -123,12 +123,14 @@ public:
// Parse command line options, overriding configuration file values
conf.parse(argc, argv);
log.set_flush(conf.option("flush-log").get<int32_t>());
+ log.set_trace(conf.option("trace").get<int32_t>());
lv2_features = new LV2Features();
lv2_features->add_feature(uri_map->urid_map_feature());
lv2_features->add_feature(uri_map->urid_unmap_feature());
lv2_features->add_feature(SPtr<InstanceAccess>(new InstanceAccess()));
lv2_features->add_feature(SPtr<DataAccess>(new DataAccess()));
+ lv2_features->add_feature(SPtr<Log::Feature>(new Log::Feature()));
lilv_world_load_all(lilv_world);
// Set up RDF namespaces
@@ -215,8 +217,8 @@ public:
Forge* forge;
URIs* uris;
LV2_Log_Log* lv2_log;
- Log log;
Configuration conf;
+ Log log;
SPtr<Interface> interface;
SPtr<EngineBase> engine;
SPtr<Serialiser> serialiser;
diff --git a/src/server/UndoStack.cpp b/src/server/UndoStack.cpp
index f8a7f37b..77d26871 100644
--- a/src/server/UndoStack.cpp
+++ b/src/server/UndoStack.cpp
@@ -15,7 +15,6 @@
*/
#include <ctime>
-#include <iostream>
#include "ingen/URIMap.hpp"
#include "ingen/URIs.hpp"
diff --git a/wscript b/wscript
index ce3ab0b5..f898b24a 100644
--- a/wscript
+++ b/wscript
@@ -86,6 +86,12 @@ def configure(conf):
define_name = 'HAVE_POSIX_MEMALIGN',
mandatory = False)
+ conf.check(function_name = 'isatty',
+ header_name = 'unistd.h',
+ defines = '_POSIX_SOURCE=1',
+ define_name = 'HAVE_ISATTY',
+ mandatory = False)
+
if not Options.options.no_socket:
conf.check(function_name = 'socket',
header_name = 'sys/socket.h',