Skip to content

Commit

Permalink
Term:cout clog cerr cin (#271)
Browse files Browse the repository at this point in the history
Term::cout Term::clog Term::cin Term::clog
  • Loading branch information
flagarde authored Jul 27, 2023
1 parent ee8ebc1 commit 6fbc24f
Show file tree
Hide file tree
Showing 41 changed files with 870 additions and 446 deletions.
2 changes: 1 addition & 1 deletion cpp-terminal/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ configure_file(version.cpp.in version.cpp)
add_subdirectory(platforms)

# create and configure library target
add_library(cpp-terminal prompt.cpp window.cpp input.cpp terminal.cpp color.cpp key.cpp event.cpp screen.cpp options.cpp cursor.cpp style.cpp io.cpp "${CMAKE_CURRENT_BINARY_DIR}/version.cpp")
add_library(cpp-terminal buffer.cpp iostream.cpp stream.cpp prompt.cpp window.cpp input.cpp terminal.cpp color.cpp key.cpp event.cpp screen.cpp options.cpp cursor.cpp style.cpp "${CMAKE_CURRENT_BINARY_DIR}/version.cpp")
target_link_libraries(cpp-terminal PRIVATE Warnings::Warnings cpp-terminal::cpp-terminal-platforms)
target_compile_options(cpp-terminal PRIVATE $<$<CXX_COMPILER_ID:MSVC>:/utf-8>)
target_include_directories(cpp-terminal PUBLIC $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}> $<BUILD_INTERFACE:${PROJECT_BINARY_DIR}> $<INSTALL_INTERFACE:include>)
Expand Down
136 changes: 136 additions & 0 deletions cpp-terminal/buffer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
#include "cpp-terminal/buffer.hpp"

#include "cpp-terminal/options.hpp"
#include "cpp-terminal/platforms/file.hpp"
#include "cpp-terminal/terminal.hpp"

static std::string remplace(const Term::Buffer::int_type& c)
{
#if defined(_WIN32)
std::string ret;
if(static_cast<char>(c) == '\n') ret = "\r\n";
else
ret.push_back(static_cast<char>(c));
return ret;
#else
std::string ret;
ret.push_back(static_cast<char>(c));
return ret;
#endif
}

static bool newline_sequence(const std::string& str) //https://en.wikipedia.org/wiki/Newline
{
if(str.back() == '\n' || str.back() == '\r' || str.back() == '\036' || str.back() == '\036' || str.back() == '\025') return true;
else
return false;
}

int Term::Buffer::sync()
{
int ret = Term::Private::out.write(m_buffer);
m_buffer.clear();
return ret;
}

Term::Buffer::Buffer(const Term::Buffer::Type& type, const std::streamsize& size)
{
setType(type);
switch(m_type)
{
case Type::Unbuffered: setbuf(nullptr, 0); break;
case Type::LineBuffered:
case Type::FullBuffered: setbuf(&m_buffer[0], size); break;
}
}

void Term::Buffer::setType(const Term::Buffer::Type& type) { m_type = type; }

std::streambuf* Term::Buffer::setbuf(char* s, std::streamsize n)
{
if(s != nullptr) m_buffer.reserve(n);
return this;
}

Term::Buffer::int_type Term::Buffer::underflow()
{
try
{
//TODO Maybe use input function ?
m_buffer.clear();
if(terminal.getOptions().has(Option::Raw))
{
do {
std::string ret{Term::Private::in.read()};
if(!ret.empty())
{
if(ret[0] == '\x7f' || ret[0] == '\b')
{
Term::Private::out.write("\b \b"); //Backspace is DEL, CTRL+Backspace is Backspace '\b'
if(!m_buffer.empty()) m_buffer.erase(m_buffer.size() - 1);
}
else if(ret[0] == '\033')
{
continue; // For now if it's escape sequence do nothing
}
else if(ret[0] <= 31 && ret[0] != '\t' && ret[0] != '\b' && ret[0] != 127 && ret[0] != ' ' && ret[0] != '\n' && ret[0] != '\r') { continue; }
else
{
Term::Private::out.write(ret);
m_buffer += ret;
}
}
} while(m_buffer.empty() || !newline_sequence(m_buffer));
Term::Private::out.write('\n');
}
else
{
do {
std::string ret{Term::Private::in.read()};
m_buffer += ret;
} while(m_buffer.empty());
}
setg(&m_buffer[0], &m_buffer[0], &m_buffer[0] + m_buffer.size());
return traits_type::to_int_type(m_buffer.at(0));
}
catch(...)
{
return traits_type::eof();
}
}

Term::Buffer::int_type Term::Buffer::overflow(int c)
{
if(c != std::char_traits<Term::Buffer::char_type>::eof())
{
switch(m_type)
{
case Type::Unbuffered:
{
Term::Private::out.write(remplace(c));
break;
}
case Type::LineBuffered:
{
m_buffer += remplace(c);
if(static_cast<char>(c) == '\n')
{
Term::Private::out.write(m_buffer);
m_buffer.clear();
}
break;
}
case Type::FullBuffered:
{
if(m_buffer.size() >= m_buffer.capacity())
{
Term::Private::out.write(m_buffer);
m_buffer.clear();
}
m_buffer += remplace(c);
break;
}
}
}
return c;
}
34 changes: 34 additions & 0 deletions cpp-terminal/buffer.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#pragma once

#include <cstddef>
#include <cstdint>
#include <streambuf>

namespace Term
{

class Buffer : public std::streambuf
{
public:
enum class Type : std::uint8_t
{
Unbuffered,
LineBuffered,
FullBuffered,
};
explicit Buffer(const Term::Buffer::Type& type = Term::Buffer::Type::LineBuffered, const std::streamsize& size = BUFSIZ);
virtual ~Buffer() = default;

protected:
virtual Term::Buffer::int_type underflow() final;
virtual Term::Buffer::int_type overflow(int c = std::char_traits<Term::Buffer::char_type>::eof());
virtual int sync() final;

private:
void setType(const Term::Buffer::Type& type);
std::streambuf* setbuf(char* s, std::streamsize n) final;
std::string m_buffer;
Term::Buffer::Type m_type{Term::Buffer::Type::LineBuffered};
};

} // namespace Term
23 changes: 0 additions & 23 deletions cpp-terminal/io.cpp

This file was deleted.

21 changes: 0 additions & 21 deletions cpp-terminal/io.hpp

This file was deleted.

46 changes: 46 additions & 0 deletions cpp-terminal/iostream.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#include "cpp-terminal/iostream.hpp"

#include <iostream>
#include <new>

namespace Term
{
// Output
static char coutBuf[sizeof(Term::TOstream)];
TOstream& cout = reinterpret_cast<Term::TOstream&>(coutBuf);
static char cerrBuf[sizeof(Term::TOstream)];
TOstream& cerr = reinterpret_cast<Term::TOstream&>(cerrBuf);
static char clogBuf[sizeof(Term::TOstream)];
TOstream& clog = reinterpret_cast<Term::TOstream&>(clogBuf);
// Input
static char cinBuf[sizeof(Term::TIstream)];
TIstream& cin = reinterpret_cast<Term::TIstream&>(cinBuf);
} // namespace Term */

int Term::StreamInitializer::m_counter{0};

void Term::StreamInitializer::init()
{
if(m_counter++ == 0)
{
std::ios_base::Init();
new(&Term::cout) TOstream(Term::Buffer::Type::FullBuffered, BUFSIZ);
new(&Term::clog) TOstream(Term::Buffer::Type::LineBuffered, BUFSIZ);
new(&Term::cerr) TOstream(Term::Buffer::Type::Unbuffered, 0);
new(&Term::cin) TIstream(Term::Buffer::Type::FullBuffered, BUFSIZ);
std::cin.rdbuf(Term::cin.rdbuf());
}
}

Term::StreamInitializer::StreamInitializer() { init(); }

Term::StreamInitializer::~StreamInitializer()
{
if(--m_counter == 0)
{
(&Term::cout)->~TOstream();
(&Term::cerr)->~TOstream();
(&Term::clog)->~TOstream();
(&Term::cin)->~TIstream();
}
}
30 changes: 30 additions & 0 deletions cpp-terminal/iostream.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#pragma once

#include "cpp-terminal/stream.hpp"

namespace Term
{

extern TIstream& cin;
extern TOstream& cout;
extern TOstream& cerr;
extern TOstream& clog;

class StreamInitializer
{
public:
StreamInitializer();
static void init();
~StreamInitializer();
StreamInitializer(const StreamInitializer&) = delete;
StreamInitializer& operator=(const StreamInitializer&) = delete;
StreamInitializer(StreamInitializer&&) = delete;
StreamInitializer& operator=(StreamInitializer&&) = delete;

private:
static int m_counter;
};

static StreamInitializer m_streams;

} // namespace Term
8 changes: 4 additions & 4 deletions cpp-terminal/platforms/cursor.cpp
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
#include "cpp-terminal/cursor.hpp"

#if defined(_WIN32)
#include "cpp-terminal/platforms/file.hpp"
#include "windows.h"
#else
#include "cpp-terminal/input.hpp"
#include "cpp-terminal/terminal.hpp"
#endif

#include "cpp-terminal/platforms/file.hpp"

Term::Cursor Term::cursor_position()
{
#if defined(_WIN32)
CONSOLE_SCREEN_BUFFER_INFO inf;
if(GetConsoleScreenBufferInfo(Private::std_cout.getHandler(), &inf)) return Term::Cursor(inf.dwCursorPosition.Y + 1, inf.dwCursorPosition.X + 1);
if(GetConsoleScreenBufferInfo(Private::out.handle(), &inf)) return Term::Cursor(inf.dwCursorPosition.Y + 1, inf.dwCursorPosition.X + 1);
else
return Term::Cursor(0, 0);
#else
Term::terminal << Term::cursor_position_report();
Term::Private::out.write(Term::cursor_position_report());
Term::Cursor c;
while((c = Platform::read_raw()).empty()) continue;
return c;
Expand Down
Loading

0 comments on commit 6fbc24f

Please sign in to comment.