From 925a54dec965b0c52d312616f9f42902fd5fac2e Mon Sep 17 00:00:00 2001
From: "Robin.Mueller" <robin.mueller.m@gmail.com>
Date: Thu, 4 Jun 2020 01:06:03 +0200
Subject: [PATCH] more improvements for servicei nterface

---
 serviceinterface/ServiceInterfaceBuffer.cpp | 28 +++++++----
 serviceinterface/ServiceInterfaceBuffer.h   |  5 +-
 serviceinterface/ServiceInterfaceStream.cpp | 22 ++++++++-
 serviceinterface/ServiceInterfaceStream.h   | 51 +++++++++++----------
 4 files changed, 69 insertions(+), 37 deletions(-)

diff --git a/serviceinterface/ServiceInterfaceBuffer.cpp b/serviceinterface/ServiceInterfaceBuffer.cpp
index 93de88b3..92f08cae 100644
--- a/serviceinterface/ServiceInterfaceBuffer.cpp
+++ b/serviceinterface/ServiceInterfaceBuffer.cpp
@@ -8,10 +8,11 @@ extern "C" void printChar(const char*, bool errStream);
 #ifndef UT699
 
 ServiceInterfaceBuffer::ServiceInterfaceBuffer(std::string setMessage,
-        bool errStream, bool addCrToPreamble, uint16_t port):
+		bool addCrToPreamble, bool buffered , bool errStream, uint16_t port):
 		isActive(true), logMessage(setMessage),
-		addCrToPreamble(addCrToPreamble), errStream(errStream) {
-	if(not errStream) {
+		addCrToPreamble(addCrToPreamble), buffered(buffered),
+		errStream(errStream) {
+	if(buffered) {
 		// Set pointers if the stream is buffered.
 		setp( buf, buf + BUF_SIZE );
 	}
@@ -26,16 +27,27 @@ void ServiceInterfaceBuffer::putChars(char const* begin, char const* end) {
 	memcpy(array, begin, length);
 
 	for(; begin != end; begin++){
-		printChar(begin, false);
+		if(errStream) {
+			printChar(begin, true);
+		}
+		else {
+			printChar(begin, false);
+		}
+
 	}
 }
 
 #endif
 
 int ServiceInterfaceBuffer::overflow(int c) {
-	if(errStream and this->isActive) {
+	if(not buffered and this->isActive) {
 		if (c != Traits::eof()) {
-			printChar(reinterpret_cast<const char*>(&c), true);
+			if(errStream) {
+				printChar(reinterpret_cast<const char*>(&c), true);
+			}
+			else {
+				printChar(reinterpret_cast<const char*>(&c), false);
+			}
 		}
 		return 0;
 	}
@@ -53,8 +65,8 @@ int ServiceInterfaceBuffer::overflow(int c) {
 }
 
 int ServiceInterfaceBuffer::sync(void) {
-	if(not this->isActive or errStream) {
-		if(not errStream) {
+	if(not this->isActive) {
+		if(not buffered) {
 			setp(buf, buf + BUF_SIZE - 1);
 		}
 		return 0;
diff --git a/serviceinterface/ServiceInterfaceBuffer.h b/serviceinterface/ServiceInterfaceBuffer.h
index 74facafe..e3927007 100644
--- a/serviceinterface/ServiceInterfaceBuffer.h
+++ b/serviceinterface/ServiceInterfaceBuffer.h
@@ -19,8 +19,8 @@ class ServiceInterfaceBuffer:
         public std::streambuf {
 	friend class ServiceInterfaceStream;
 public:
-	ServiceInterfaceBuffer(std::string setMessage, bool errStream,
-			bool addCrToPreamble, uint16_t port);
+	ServiceInterfaceBuffer(std::string setMessage, bool addCrToPreamble,
+			bool buffered, bool errStream, uint16_t port);
 
 protected:
 	bool isActive;
@@ -41,6 +41,7 @@ private:
 	//! This is useful for some terminal programs which do not have
 	//! implicit carriage return with newline characters.
 	bool addCrToPreamble;
+	bool buffered;
 	//! This specifies to print to stderr and work in unbuffered mode.
 	bool errStream;
 
diff --git a/serviceinterface/ServiceInterfaceStream.cpp b/serviceinterface/ServiceInterfaceStream.cpp
index 78371548..bef8136e 100644
--- a/serviceinterface/ServiceInterfaceStream.cpp
+++ b/serviceinterface/ServiceInterfaceStream.cpp
@@ -1,9 +1,9 @@
 #include <framework/serviceinterface/ServiceInterfaceStream.h>
 
 ServiceInterfaceStream::ServiceInterfaceStream(std::string setMessage,
-		bool errStream, bool addCrToPreamble, uint16_t port) :
+		bool addCrToPreamble, bool buffered, bool errStream, uint16_t port) :
 		std::ostream(&buf),
-		buf(setMessage, errStream, addCrToPreamble, port) {
+		buf(setMessage, addCrToPreamble, buffered, errStream,  port) {
 }
 
 void ServiceInterfaceStream::setActive( bool myActive) {
@@ -13,3 +13,21 @@ void ServiceInterfaceStream::setActive( bool myActive) {
 std::string ServiceInterfaceStream::getPreamble() {
 	return buf.getPreamble();
 }
+
+void ServiceInterfaceStream::print(std::string error,
+		bool withPreamble, bool withNewline, bool flush) {
+	if(not buffered and withPreamble) {
+		*this << getPreamble() << error;
+	}
+	else {
+		*this << error;
+	}
+
+	if(withNewline) {
+		*this << "\n";
+	}
+	// if mode is non-buffered, no need to flush.
+	if(flush and buffered) {
+		this->flush();
+	}
+}
diff --git a/serviceinterface/ServiceInterfaceStream.h b/serviceinterface/ServiceInterfaceStream.h
index 375a1875..9b8b5b6e 100644
--- a/serviceinterface/ServiceInterfaceStream.h
+++ b/serviceinterface/ServiceInterfaceStream.h
@@ -5,19 +5,11 @@
 #include <iostream>
 #include <cstdio>
 
-/* Unfortunately, there must be a forward declaration of the log front end
- * (MUST be defined in main), to let the system know where to write to.
- * The ServiceInterfaceStream instances, which are declared below and
- * can instantaited somewhere else can be passed to these front ends by passing
- * their underlying buffers with .rdbuf() */
-namespace sif {
-extern std::ostream debug;
-extern std::ostream info;
-extern std::ostream warning;
-extern std::ostream error;
-}
-
-
+/**
+ * Generic service interface stream which can be used like std::cout or
+ * std::cerr but has additional capability. Add preamble and timestamp
+ * to output. Can be run in buffered or unbuffered mode.
+ */
 class ServiceInterfaceStream :
         public std::ostream {
 protected:
@@ -27,14 +19,14 @@ public:
      * This constructor is used by specifying the preamble message.
      * Optionally, the output can be directed to stderr and a CR character
      * can be prepended to the preamble.
-     * @param set_message
-     * @param errStream
-     * @param addCrToPreamble
-     * @param port
+     * @param setMessage message of preamble.
+     * @param addCrToPreamble Useful for applications like Puttty.
+     * @param buffered specify whether to use buffered mode.
+     * @param errStream specify which output stream to use (stderr or stdout).
      */
     ServiceInterfaceStream(std::string setMessage,
-    		bool errStream = false, bool addCrToPreamble = false,
-			uint16_t port = 1234);
+    		bool addCrToPreamble = false, bool buffered = true,
+			bool errStream = false, uint16_t port = 1234);
 
     //! An inactive stream will not print anything.
 	void setActive( bool );
@@ -45,15 +37,24 @@ public:
 	 * @return Preamle consisting of log message and timestamp.
 	 */
 	std::string getPreamble();
+
+	/**
+	 * This prints an error with a preamble. Useful if using the unbuffered
+	 * mode. Flushes in default mode (prints immediately).
+	 */
+	void print(std::string error, bool withPreamble = true,
+			bool withNewline = true, bool flush = true);
+
+	bool buffered = false;
 };
 
-// Forward declaration of interface streams. These are needed so the public
-// functions can be used by including this header
+// Forward declaration of interface streams. These should be instantiated in
+// main. They can then be used like std::cout or std::cerr.
 namespace sif {
-extern ServiceInterfaceStream debugStream;
-extern ServiceInterfaceStream infoStream;
-extern ServiceInterfaceStream warningStream;
-extern ServiceInterfaceStream errorStream;
+extern ServiceInterfaceStream debug;
+extern ServiceInterfaceStream info;
+extern ServiceInterfaceStream warning;
+extern ServiceInterfaceStream error;
 }
 
 #endif /* FRAMEWORK_SERVICEINTERFACE_SERVICEINTERFACESTREAM_H_ */