Skip to content

Commit

Permalink
Args #155 (#283)
Browse files Browse the repository at this point in the history
  • Loading branch information
flagarde committed Aug 2, 2023
1 parent 6fbc24f commit b8661e3
Show file tree
Hide file tree
Showing 20 changed files with 392 additions and 96 deletions.
9 changes: 1 addition & 8 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,7 @@ cmake_install.cmake
CMakeCache.txt

# Clion
cmake-build-release/
cmake-build-release-visual-studio/
cmake-build-release-cygwin/
cmake-build-debug/
cmake-build-debug-visual-studio/
cmake-build-debug-cygwin/
cmake-build-minsizerel/
cmake-build-relwithdebinfo/
cmake-build*
.idea/

# cmake
Expand Down
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 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")
add_library(cpp-terminal args.cpp 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
15 changes: 15 additions & 0 deletions cpp-terminal/args.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#include "cpp-terminal/args.hpp"
namespace Term
{

Term::Argc::Argc() {}

Term::Argc::operator long unsigned int() { return static_cast<int>(Term::Arguments::argc()); }

Term::Argc::operator long unsigned int() const { return static_cast<int>(Term::Arguments::argc()); }

Term::Arguments::Arguments() {}

std::string Term::Arguments::operator[](const std::size_t& i) const { return m_args[i]; }

} // namespace Term
34 changes: 34 additions & 0 deletions cpp-terminal/args.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#pragma once

#include <string>
#include <vector>

namespace Term
{

class Arguments
{
public:
Arguments();
static std::size_t argc();
static std::vector<std::string> argv();
std::string operator[](const std::size_t&) const;

private:
static void parse();
static std::vector<std::string> m_args;
static bool m_parsed;
};

class Argc
{
public:
Argc();
operator long unsigned int();
operator long unsigned int() const;
};

static const Arguments argv;
static const Argc argc;

} // namespace Term
12 changes: 8 additions & 4 deletions cpp-terminal/buffer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,25 @@
namespace Term
{

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

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 Term::Buffer::int_type overflow(int c = std::char_traits<Term::Buffer::char_type>::eof()) final;
virtual int sync() final;

private:
Expand Down
2 changes: 1 addition & 1 deletion cpp-terminal/color.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class Color
Bit3,
Bit4,
Bit8,
Bit24,
Bit24
};
/*
* The 3bit/4bit colors for the terminal
Expand Down
2 changes: 1 addition & 1 deletion cpp-terminal/exception.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace Term
class Exception : public std::exception
{
public:
Exception(const std::string& what) : m_what(what){};
Exception(const std::string& what) : m_what(what) {}
virtual const char* what() const noexcept override { return m_what.c_str(); }

private:
Expand Down
2 changes: 1 addition & 1 deletion cpp-terminal/options.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ enum class Option : int
SignalKeys = 3,
NoSignalKeys = -3,
Cursor = 4,
NoCursor = -4,
NoCursor = -4
};

class Options
Expand Down
2 changes: 1 addition & 1 deletion cpp-terminal/platforms/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
add_library(cpp-terminal-platforms STATIC terminal.cpp tty.cpp terminfo.cpp input.cpp screen.cpp cursor.cpp file.cpp env.cpp)
add_library(cpp-terminal-platforms STATIC conversion.cpp args.cpp terminal.cpp tty.cpp terminfo.cpp input.cpp screen.cpp cursor.cpp file.cpp env.cpp)
target_link_libraries(cpp-terminal-platforms PRIVATE Warnings::Warnings)
target_compile_options(cpp-terminal-platforms PRIVATE $<$<CXX_COMPILER_ID:MSVC>:/utf-8 /wd4668 /wd4514>)
target_include_directories(cpp-terminal-platforms PRIVATE $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}> $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}> $<BUILD_INTERFACE:${PROJECT_BINARY_DIR}> $<INSTALL_INTERFACE:include>)
Expand Down
86 changes: 86 additions & 0 deletions cpp-terminal/platforms/args.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
#include "cpp-terminal/args.hpp"

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

#if defined(_WIN32)
#include <memory>
// clang-format off
#include <windows.h>
#include <processenv.h>
// clang-format on
#elif defined(__APPLE__)
#include <crt_externs.h>
#else
#include <algorithm>
#include <fstream>
#include <limits>
#endif

void Term::Arguments::parse()
{
if(m_parsed == true) return;
#if defined(_WIN32)
int argc{0};
std::unique_ptr<LPWSTR[], void (*)(wchar_t**)> wargv = std::unique_ptr<LPWSTR[], void (*)(wchar_t**)>(CommandLineToArgvW(GetCommandLineW(), &argc), [](wchar_t** ptr) { LocalFree(ptr); });
if(wargv == nullptr)
{
m_parsed = false;
return;
}
else
{
m_args.reserve(static_cast<std::size_t>(argc));
for(std::size_t i = 0; i != static_cast<std::size_t>(argc); ++i) { m_args.push_back(Term::Private::to_utf8(&wargv.get()[i][0])); }
m_parsed = true;
}
#elif defined(__APPLE__)
int argc{*_NSGetArgc()};
m_args.reserve(argc);
char** argv{*_NSGetArgv()};
for(std::size_t i = 0; i != argc; ++i) { m_args.push_back(argv[i]); }
m_parsed = true;
#else
std::string cmdline;
std::fstream fs;
std::fstream::iostate old_iostate{fs.exceptions()};
try
{
fs.exceptions(std::ifstream::failbit | std::ifstream::badbit);
fs.open("/proc/self/cmdline", std::fstream::in | std::fstream::binary);
fs.ignore(std::numeric_limits<std::streamsize>::max());
cmdline.resize(fs.gcount());
fs.seekg(0, std::ios_base::beg);
fs.get(&cmdline[0], cmdline.size());
fs.exceptions(old_iostate);
if(fs.is_open()) fs.close();
const std::size_t argc = static_cast<std::size_t>(std::count(cmdline.begin(), cmdline.end(), '\0'));
m_args.reserve(argc);
for(std::string::iterator it = cmdline.begin(); it != cmdline.end(); it = std::find(it, cmdline.end(), '\0') + 1) { m_args.push_back(cmdline.data() + (it - cmdline.begin())); }
m_parsed = true;
}
catch(...)
{
fs.exceptions(old_iostate);
if(fs.is_open()) fs.close();
m_parsed = false;
m_args.clear();
m_parsed = false;
}
#endif
}

std::size_t Term::Arguments::argc()
{
parse();
return m_args.size();
}

std::vector<std::string> Term::Arguments::argv()
{
parse();
return m_args;
}

bool Term::Arguments::m_parsed = false;

std::vector<std::string> Term::Arguments::m_args = std::vector<std::string>();
104 changes: 104 additions & 0 deletions cpp-terminal/platforms/conversion.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
#include "cpp-terminal/platforms/conversion.hpp"

#include "cpp-terminal/exception.hpp"

#if defined(_WIN32)
#include <windows.h>
#endif

namespace Term
{
namespace Private
{

#if defined(_WIN32)
std::string to_utf8(LPCWCH utf16Str)
{
int size_needed = WideCharToMultiByte(CP_UTF8, 0, utf16Str, -1, nullptr, 0, nullptr, nullptr);
std::string ret(size_needed, '\0');
WideCharToMultiByte(CP_UTF8, 0, utf16Str, wcslen(utf16Str), &ret[0], size_needed, nullptr, nullptr);
return ret.c_str();
}
#endif

static constexpr std::uint8_t UTF8_ACCEPT = 0;
static constexpr std::uint8_t UTF8_REJECT = 0xf;

std::uint8_t utf8_decode_step(std::uint8_t state, std::uint8_t octet, std::uint32_t* cpp)
{
static const std::uint32_t utf8ClassTab[0x10] = {
0x88888888UL, 0x88888888UL, 0x99999999UL, 0x99999999UL, 0xaaaaaaaaUL, 0xaaaaaaaaUL, 0xaaaaaaaaUL, 0xaaaaaaaaUL, 0x222222ffUL, 0x22222222UL, 0x22222222UL, 0x22222222UL, 0x3333333bUL, 0x33433333UL, 0xfff5666cUL, 0xffffffffUL,
};

static const std::uint32_t utf8StateTab[0x10] = {
0xfffffff0UL, 0xffffffffUL, 0xfffffff1UL, 0xfffffff3UL, 0xfffffff4UL, 0xfffffff7UL, 0xfffffff6UL, 0xffffffffUL, 0x33f11f0fUL, 0xf3311f0fUL, 0xf33f110fUL, 0xfffffff2UL, 0xfffffff5UL, 0xffffffffUL, 0xffffffffUL, 0xffffffffUL,
};

const std::uint8_t reject = (state >> 3), nonAscii = (octet >> 7);
const std::uint8_t class_ = (!nonAscii ? 0 : (0xf & (utf8ClassTab[(octet >> 3) & 0xf] >> (4 * (octet & 7)))));

*cpp = (state == UTF8_ACCEPT ? (octet & (0xffU >> class_)) : ((octet & 0x3fU) | (*cpp << 6)));

return (reject ? 0xf : (0xf & (utf8StateTab[class_] >> (4 * (state & 7)))));
}

void codepoint_to_utf8(std::string& s, char32_t c)
{
if(c > 0x0010FFFF) { throw Term::Exception("Invalid UTF32 codepoint."); }
char bytes[4];
int nbytes = 1;
char32_t d = c;
if(c >= 0x10000)
{
nbytes++;
bytes[3] = ((d | 0x80) & 0xBF);
d >>= 6;
}
if(c >= 0x800)
{
nbytes++;
bytes[2] = ((d | 0x80) & 0xBF);
d >>= 6;
}
if(c >= 0x80)
{
nbytes++;
bytes[1] = ((d | 0x80) & 0xBF);
d >>= 6;
}
static const unsigned char mask[4] = {0x00, 0xC0, 0xE0, 0xF0};
bytes[0] = static_cast<char>(d | mask[nbytes - 1]);
s.append(bytes, nbytes);
}

std::u32string utf8_to_utf32(const std::string& s)
{
std::uint32_t codepoint{};
std::uint8_t state = UTF8_ACCEPT;
std::u32string r{};
for(char i: s)
{
state = utf8_decode_step(state, i, &codepoint);
if(state == UTF8_ACCEPT) { r.push_back(codepoint); }
else if(state == UTF8_REJECT) { throw Term::Exception("Invalid byte in UTF8 encoded string"); }
}
if(state != UTF8_ACCEPT) { throw Term::Exception("Expected more bytes in UTF8 encoded string"); }
return r;
}

std::string utf32_to_utf8(const std::u32string& s)
{
std::string r{};
for(char32_t i: s) { codepoint_to_utf8(r, i); }
return r;
}

std::string vector_to_string(const std::vector<char>& vector)
{
std::string string;
for(char i: vector) { string.push_back(i); }
return string;
}

} // namespace Private
} // namespace Term

0 comments on commit b8661e3

Please sign in to comment.