diff options
| -rw-r--r-- | dev/kernel/src/FS/HeFS.cc | 82 | ||||
| -rw-r--r-- | dev/kernel/src/PEFCodeMgr.cc | 4 | ||||
| -rw-r--r-- | dev/kernel/src/UserProcessScheduler.cc | 4 | ||||
| -rw-r--r-- | tooling/mkfs.h | 8 | ||||
| -rw-r--r-- | tooling/mkfs.hefs.cc | 17 | ||||
| -rw-r--r-- | tooling/rang.h | 711 |
6 files changed, 411 insertions, 415 deletions
diff --git a/dev/kernel/src/FS/HeFS.cc b/dev/kernel/src/FS/HeFS.cc index 89415ee5..0969d2a5 100644 --- a/dev/kernel/src/FS/HeFS.cc +++ b/dev/kernel/src/FS/HeFS.cc @@ -29,7 +29,8 @@ namespace Detail { /// @note This function is used to traverse the RB-Tree of the filesystem. /// @internal Internal filesystem use only. STATIC ATTRIBUTE(unused) _Output Void - hefsi_traverse_tree(HEFS_INDEX_NODE_DIRECTORY* dir, Lba& start); + hefsi_traverse_tree(HEFS_INDEX_NODE_DIRECTORY* dir, DriveTrait* mnt, const Lba& start_ind, + Lba& start, const BOOL alloc_in_mind = NO); /// @brief Get the index node of a file or directory. /// @param root The root node of the filesystem. @@ -74,19 +75,52 @@ namespace Detail { /// @param start The starting point of the traversal. /// @note This function is used to traverse the RB-Tree of the filesystem. /// @internal Internal filesystem use only. - STATIC ATTRIBUTE(unused) _Output Void - hefsi_traverse_tree(HEFS_INDEX_NODE_DIRECTORY* dir, Lba& start) { - if (dir->fNext != 0) { - start = dir->fNext; - } else if (dir->fPrev != 0) { - start = dir->fPrev; - } else { - if (dir->fParent != 0) { - start = dir->fParent; + STATIC ATTRIBUTE(unused) Void + hefsi_traverse_tree(HEFS_INDEX_NODE_DIRECTORY* dir, DriveTrait* mnt, const Lba& ind_start, + Lba& start, const BOOL alloc_in_mind) { + if (!mnt || !dir) return; + + BOOL check_is_good = NO; + + while (YES) { + mnt->fPacket.fPacketLba = start; + mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); + mnt->fPacket.fPacketContent = dir; + mnt->fInput(mnt->fPacket); + + if (dir->fNext != 0) { + if (check_is_good) break; + + start = dir->fNext; + + check_is_good = YES; + continue; } else if (dir->fPrev != 0) { - start = dir->fPrev; + if (check_is_good) break; + + start = dir->fPrev; + check_is_good = YES; + continue; } else { - start += kHeFSINDStartOffset; + if (dir->fParent != 0) { + if (check_is_good) break; + + start = dir->fParent; + check_is_good = YES; + continue; + } else if (dir->fPrev != 0) { + if (check_is_good) break; + + start = dir->fPrev; + check_is_good = YES; + continue; + } else { + if (!alloc_in_mind) break; + + if (start < 1) start = ind_start; + + start += kHeFSINDStartOffset; + } } } @@ -320,13 +354,13 @@ namespace Detail { } child += sizeof(HEFS_INDEX_NODE_DIRECTORY); - if (child < root->fStartIND || child > root->fEndIND) break; + if (child > root->fEndIND) break; } dirent->fColor = kHeFSRed; dirent->fChild = child; - if (child > root->fEndIND) dirent->fChild = root->fEndIND; + if (child > root->fEndIND) dirent->fChild = root->fStartIND; } for (SizeT index = 0UL; index < (kHeFSSliceCount * 2); index += 2) { @@ -358,7 +392,7 @@ namespace Detail { return YES; } - hefsi_traverse_tree(tmpdir, start); + hefsi_traverse_tree(tmpdir, mnt, root->fStartIND, start, YES); if (start > root->fEndIND || start == 0) break; } @@ -404,7 +438,7 @@ namespace Detail { } } - hefsi_traverse_tree(dir, start); + hefsi_traverse_tree(dir, mnt, root->fStartIND, start); if (start > root->fEndIND || start == 0) break; } } @@ -493,7 +527,7 @@ namespace Detail { } } - hefsi_traverse_tree(dir, start); + hefsi_traverse_tree(dir, mnt, root->fStartIND, start); if (start > root->fEndIND || start == 0) break; } } @@ -544,7 +578,7 @@ namespace Detail { } } - hefsi_traverse_tree(dir, start); + hefsi_traverse_tree(dir, mnt, root->fStartIND, start); if (start > root->fEndIND || start == 0) break; } @@ -632,7 +666,7 @@ namespace Detail { if (dir_parent->fNext == start) { hefsi_rotate_tree(start, mnt, YES); - hefsi_traverse_tree(dir_parent, start); + hefsi_traverse_tree(dir_parent, mnt, root->fStartIND, start); if (start > root->fEndIND || start == 0) break; @@ -658,7 +692,7 @@ namespace Detail { hefsi_rotate_tree(start, mnt, NO); - hefsi_traverse_tree(dir, start); + hefsi_traverse_tree(dir, mnt, root->fStartIND, start); if (start > root->fEndIND || start == 0) break; } @@ -750,7 +784,7 @@ _Output Bool HeFileSystemParser::Format(_Input _Output DriveTrait* drive, _Input const SizeT dir_max = max_lba / 20; // 20% for directory metadata const SizeT inode_max = max_lba / 10; // 10% for inodes - root->fStartIND = drive->fLbaStart + kHeFSINDStartOffset; + root->fStartIND = drive->fLbaStart + kHeFSINDStartOffset + sizeof(HEFS_BOOT_NODE); root->fEndIND = root->fStartIND + dir_max; root->fStartIN = root->fEndIND + kHeFSINDStartOffset; @@ -799,7 +833,7 @@ _Output Bool HeFileSystemParser::Format(_Input _Output DriveTrait* drive, _Input return NO; } - const Utf8Char* kFileMap[kHeFSPreallocateCount] = { + const Utf8Char kFileMap[kHeFSPreallocateCount][kHeFSFileNameLen] = { u8"/", u8"/boot", u8"/system", u8"/network", u8"/devices", u8"/media", u8"/vm", }; @@ -847,7 +881,9 @@ _Output Bool HeFileSystemParser::CreateDirectory(_Input DriveTrait* drive, _Inpu urt_copy_memory((VoidPtr) dir, name, urt_string_len(dir) + 1); if (Detail::hefsi_allocate_index_node_directory(root, drive, name, flags)) { - Detail::hefsi_balance_filesystem(root, drive); + // todo: make it smarter for high-throughput. + if (root->fINDCount > 1024) Detail::hefsi_balance_filesystem(root, drive); + mm_delete_heap((VoidPtr) root); delete[] name; return YES; diff --git a/dev/kernel/src/PEFCodeMgr.cc b/dev/kernel/src/PEFCodeMgr.cc index 40a0cff9..5da3a499 100644 --- a/dev/kernel/src/PEFCodeMgr.cc +++ b/dev/kernel/src/PEFCodeMgr.cc @@ -246,8 +246,8 @@ namespace Utils { stacksym = ErrorOr<VoidPtr>{(VoidPtr) new UIntPtr(kSchedMaxStackSz)}; } - if ((*(volatile UIntPtr*)stacksym.Leak().Leak()) > kSchedMaxStackSz) { - *(volatile UIntPtr*)stacksym.Leak().Leak() = kSchedMaxStackSz; + if ((*(volatile UIntPtr*) stacksym.Leak().Leak()) > kSchedMaxStackSz) { + *(volatile UIntPtr*) stacksym.Leak().Leak() = kSchedMaxStackSz; } UserProcessScheduler::The().CurrentTeam().AsArray()[id].Kind = process_kind; diff --git a/dev/kernel/src/UserProcessScheduler.cc b/dev/kernel/src/UserProcessScheduler.cc index 5012e8a3..45a95b5b 100644 --- a/dev/kernel/src/UserProcessScheduler.cc +++ b/dev/kernel/src/UserProcessScheduler.cc @@ -490,8 +490,7 @@ SizeT UserProcessScheduler::Run() noexcept { return 0UL; } - if (kCurrentlySwitching) - return 0UL; + if (kCurrentlySwitching) return 0UL; kCurrentlySwitching = Yes; @@ -503,7 +502,6 @@ SizeT UserProcessScheduler::Run() noexcept { //! Check if the process needs to be run. if (UserProcessHelper::CanBeScheduled(process)) { - if (process.StackSize > kSchedMaxStackSz) { kout << "The process: " << process.Name << ", has not a valid stack size! Crashing it...\r"; process.Crash(); diff --git a/tooling/mkfs.h b/tooling/mkfs.h index 650261db..7180b179 100644 --- a/tooling/mkfs.h +++ b/tooling/mkfs.h @@ -6,9 +6,9 @@ #pragma once +#include <tooling/rang.h> #include <iostream> #include <string> -#include <tooling/rang.h> /// @internal namespace mkfs { @@ -28,9 +28,9 @@ inline std::basic_string<CharType> get_option(const std::basic_string<CharType>& } inline auto console_out() -> std::ostream& { - std::ostream& conout = std::cout; - conout << rang::fg::red << "mkfs: " << rang::style::reset; + std::ostream& conout = std::cout; + conout << rang::fg::red << "mkfs: " << rang::style::reset; - return conout; + return conout; } } // namespace mkfs
\ No newline at end of file diff --git a/tooling/mkfs.hefs.cc b/tooling/mkfs.hefs.cc index d9928858..23772023 100644 --- a/tooling/mkfs.hefs.cc +++ b/tooling/mkfs.hefs.cc @@ -16,10 +16,8 @@ static size_t kSectorSize = 512; int main(int argc, char** argv) { if (argc < 2) { - mkfs::console_out() << - "hefs: Usage: mkfs.hefs -L <label> -s <sector_size> -p <part_start> -e " << - "<part_end> -S <disk_size> -o <output_device>" - << std::endl; + mkfs::console_out() << "hefs: Usage: mkfs.hefs -L <label> -s <sector_size> -p <part_start> -e " + << "<part_end> -S <disk_size> -o <output_device>" << std::endl; return EXIT_FAILURE; } @@ -51,8 +49,8 @@ int main(int argc, char** argv) { std::strtol(mkfs::get_option<char>(args, "-S").data(), nullptr, 10) * 1024 * 1024 * 1024; if (kDiskSize == 0) { - mkfs::console_out() << "hefs: Error: Unable to deduce future disk size for output_device: " << output_device - << std::endl; + mkfs::console_out() << "hefs: Error: Unable to deduce future disk size for output_device: " + << output_device << std::endl; return EXIT_FAILURE; } @@ -61,7 +59,7 @@ int main(int argc, char** argv) { if (!filesystem.good()) { mkfs::console_out() << "hefs: Info: Unable to open output_device: " << output_device - << std::endl; + << std::endl; return EXIT_FAILURE; } @@ -92,7 +90,7 @@ int main(int argc, char** argv) { if (!filesystem.good()) { mkfs::console_out() << "hefs: Error: Unable to write FS to output_device: " << output_device - << std::endl; + << std::endl; return EXIT_FAILURE; } @@ -101,8 +99,7 @@ int main(int argc, char** argv) { filesystem.flush(); filesystem.close(); - mkfs::console_out() << "hefs: Info: Wrote FS to output_device: " << output_device - << std::endl; + mkfs::console_out() << "hefs: Info: Wrote FS to output_device: " << output_device << std::endl; return EXIT_SUCCESS; }
\ No newline at end of file diff --git a/tooling/rang.h b/tooling/rang.h index 204ab1dc..5d1c68ef 100644 --- a/tooling/rang.h +++ b/tooling/rang.h @@ -17,14 +17,14 @@ #elif defined(OS_WIN) #if defined(_WIN32_WINNT) && (_WIN32_WINNT < 0x0600) -#error \ - "Please include rang.hpp before any windows system headers or set _WIN32_WINNT at least to _WIN32_WINNT_VISTA" +#error \ + "Please include rang.hpp before any windows system headers or set _WIN32_WINNT at least to _WIN32_WINNT_VISTA" #elif !defined(_WIN32_WINNT) #define _WIN32_WINNT _WIN32_WINNT_VISTA #endif -#include <windows.h> #include <io.h> +#include <windows.h> #include <memory> // Only defined in windows 10 onwards, redefining in lower windows since it @@ -49,448 +49,413 @@ namespace rang { * Note that on Windows terminals bold style is same as fgB color. */ enum class style { - reset = 0, - bold = 1, - dim = 2, - italic = 3, - underline = 4, - blink = 5, - rblink = 6, - reversed = 7, - conceal = 8, - crossed = 9 + reset = 0, + bold = 1, + dim = 2, + italic = 3, + underline = 4, + blink = 5, + rblink = 6, + reversed = 7, + conceal = 8, + crossed = 9 }; enum class fg { - black = 30, - red = 31, - green = 32, - yellow = 33, - blue = 34, - magenta = 35, - cyan = 36, - gray = 37, - reset = 39 + black = 30, + red = 31, + green = 32, + yellow = 33, + blue = 34, + magenta = 35, + cyan = 36, + gray = 37, + reset = 39 }; enum class bg { - black = 40, - red = 41, - green = 42, - yellow = 43, - blue = 44, - magenta = 45, - cyan = 46, - gray = 47, - reset = 49 + black = 40, + red = 41, + green = 42, + yellow = 43, + blue = 44, + magenta = 45, + cyan = 46, + gray = 47, + reset = 49 }; enum class fgB { - black = 90, - red = 91, - green = 92, - yellow = 93, - blue = 94, - magenta = 95, - cyan = 96, - gray = 97 + black = 90, + red = 91, + green = 92, + yellow = 93, + blue = 94, + magenta = 95, + cyan = 96, + gray = 97 }; enum class bgB { - black = 100, - red = 101, - green = 102, - yellow = 103, - blue = 104, - magenta = 105, - cyan = 106, - gray = 107 + black = 100, + red = 101, + green = 102, + yellow = 103, + blue = 104, + magenta = 105, + cyan = 106, + gray = 107 }; enum class control { // Behaviour of rang function calls - Off = 0, // toggle off rang style/color calls - Auto = 1, // (Default) autodect terminal and colorize if needed - Force = 2 // force ansi color output to non terminal streams + Off = 0, // toggle off rang style/color calls + Auto = 1, // (Default) autodect terminal and colorize if needed + Force = 2 // force ansi color output to non terminal streams }; // Use rang::setControlMode to set rang control mode enum class winTerm { // Windows Terminal Mode - Auto = 0, // (Default) automatically detects wheter Ansi or Native API - Ansi = 1, // Force use Ansi API - Native = 2 // Force use Native API + Auto = 0, // (Default) automatically detects wheter Ansi or Native API + Ansi = 1, // Force use Ansi API + Native = 2 // Force use Native API }; // Use rang::setWinTermMode to explicitly set terminal API for Windows // Calling rang::setWinTermMode have no effect on other OS namespace rang_implementation { - inline std::atomic<control> &controlMode() noexcept - { - static std::atomic<control> value(control::Auto); - return value; - } + inline std::atomic<control>& controlMode() noexcept { + static std::atomic<control> value(control::Auto); + return value; + } - inline std::atomic<winTerm> &winTermMode() noexcept - { - static std::atomic<winTerm> termMode(winTerm::Auto); - return termMode; - } + inline std::atomic<winTerm>& winTermMode() noexcept { + static std::atomic<winTerm> termMode(winTerm::Auto); + return termMode; + } - inline bool supportsColor() noexcept - { + inline bool supportsColor() noexcept { #if defined(OS_LINUX) || defined(OS_MAC) - static const bool result = [] { - const char *Terms[] - = { "ansi", "color", "console", "cygwin", "gnome", - "konsole", "kterm", "linux", "msys", "putty", - "rxvt", "screen", "vt100", "xterm" }; - - const char *env_p = std::getenv("TERM"); - if (env_p == nullptr) { - return false; - } - return std::any_of(std::begin(Terms), std::end(Terms), - [&](const char *term) { - return std::strstr(env_p, term) != nullptr; - }); - }(); + static const bool result = [] { + const char* Terms[] = {"ansi", "color", "console", "cygwin", "gnome", "konsole", "kterm", + "linux", "msys", "putty", "rxvt", "screen", "vt100", "xterm"}; + + const char* env_p = std::getenv("TERM"); + if (env_p == nullptr) { + return false; + } + return std::any_of(std::begin(Terms), std::end(Terms), + [&](const char* term) { return std::strstr(env_p, term) != nullptr; }); + }(); #elif defined(OS_WIN) - // All windows versions support colors through native console methods - static constexpr bool result = true; + // All windows versions support colors through native console methods + static constexpr bool result = true; #endif - return result; - } + return result; + } #ifdef OS_WIN - - inline bool isMsysPty(int fd) noexcept - { - // Dynamic load for binary compability with old Windows - const auto ptrGetFileInformationByHandleEx - = reinterpret_cast<decltype(&GetFileInformationByHandleEx)>( - GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), - "GetFileInformationByHandleEx")); - if (!ptrGetFileInformationByHandleEx) { - return false; - } - - HANDLE h = reinterpret_cast<HANDLE>(_get_osfhandle(fd)); - if (h == INVALID_HANDLE_VALUE) { - return false; - } - - // Check that it's a pipe: - if (GetFileType(h) != FILE_TYPE_PIPE) { - return false; - } - - // POD type is binary compatible with FILE_NAME_INFO from WinBase.h - // It have the same alignment and used to avoid UB in caller code - struct MY_FILE_NAME_INFO { - DWORD FileNameLength; - WCHAR FileName[MAX_PATH]; - }; - - auto pNameInfo = std::unique_ptr<MY_FILE_NAME_INFO>( - new (std::nothrow) MY_FILE_NAME_INFO()); - if (!pNameInfo) { - return false; - } - - // Check pipe name is template of - // {"cygwin-","msys-"}XXXXXXXXXXXXXXX-ptyX-XX - if (!ptrGetFileInformationByHandleEx(h, FileNameInfo, pNameInfo.get(), - sizeof(MY_FILE_NAME_INFO))) { - return false; - } - std::wstring name(pNameInfo->FileName, pNameInfo->FileNameLength / sizeof(WCHAR)); - if ((name.find(L"msys-") == std::wstring::npos - && name.find(L"cygwin-") == std::wstring::npos) - || name.find(L"-pty") == std::wstring::npos) { - return false; - } - - return true; + inline bool isMsysPty(int fd) noexcept { + // Dynamic load for binary compability with old Windows + const auto ptrGetFileInformationByHandleEx = + reinterpret_cast<decltype(&GetFileInformationByHandleEx)>( + GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "GetFileInformationByHandleEx")); + if (!ptrGetFileInformationByHandleEx) { + return false; } -#endif + HANDLE h = reinterpret_cast<HANDLE>(_get_osfhandle(fd)); + if (h == INVALID_HANDLE_VALUE) { + return false; + } - inline bool isTerminal(const std::streambuf *osbuf) noexcept - { - using std::cerr; - using std::clog; - using std::cout; -#if defined(OS_LINUX) || defined(OS_MAC) - if (osbuf == cout.rdbuf()) { - static const bool cout_term = isatty(fileno(stdout)) != 0; - return cout_term; - } else if (osbuf == cerr.rdbuf() || osbuf == clog.rdbuf()) { - static const bool cerr_term = isatty(fileno(stderr)) != 0; - return cerr_term; - } -#elif defined(OS_WIN) - if (osbuf == cout.rdbuf()) { - static const bool cout_term - = (_isatty(_fileno(stdout)) || isMsysPty(_fileno(stdout))); - return cout_term; - } else if (osbuf == cerr.rdbuf() || osbuf == clog.rdbuf()) { - static const bool cerr_term - = (_isatty(_fileno(stderr)) || isMsysPty(_fileno(stderr))); - return cerr_term; - } -#endif - return false; + // Check that it's a pipe: + if (GetFileType(h) != FILE_TYPE_PIPE) { + return false; } - template <typename T> - using enableStd = typename std::enable_if< - std::is_same<T, rang::style>::value || std::is_same<T, rang::fg>::value - || std::is_same<T, rang::bg>::value || std::is_same<T, rang::fgB>::value - || std::is_same<T, rang::bgB>::value, - std::ostream &>::type; + // POD type is binary compatible with FILE_NAME_INFO from WinBase.h + // It have the same alignment and used to avoid UB in caller code + struct MY_FILE_NAME_INFO { + DWORD FileNameLength; + WCHAR FileName[MAX_PATH]; + }; + auto pNameInfo = std::unique_ptr<MY_FILE_NAME_INFO>(new (std::nothrow) MY_FILE_NAME_INFO()); + if (!pNameInfo) { + return false; + } -#ifdef OS_WIN + // Check pipe name is template of + // {"cygwin-","msys-"}XXXXXXXXXXXXXXX-ptyX-XX + if (!ptrGetFileInformationByHandleEx(h, FileNameInfo, pNameInfo.get(), + sizeof(MY_FILE_NAME_INFO))) { + return false; + } + std::wstring name(pNameInfo->FileName, pNameInfo->FileNameLength / sizeof(WCHAR)); + if ((name.find(L"msys-") == std::wstring::npos && + name.find(L"cygwin-") == std::wstring::npos) || + name.find(L"-pty") == std::wstring::npos) { + return false; + } - struct SGR { // Select Graphic Rendition parameters for Windows console - BYTE fgColor; // foreground color (0-15) lower 3 rgb bits + intense bit - BYTE bgColor; // background color (0-15) lower 3 rgb bits + intense bit - BYTE bold; // emulated as FOREGROUND_INTENSITY bit - BYTE underline; // emulated as BACKGROUND_INTENSITY bit - BOOLEAN inverse; // swap foreground/bold & background/underline - BOOLEAN conceal; // set foreground/bold to background/underline - }; + return true; + } - enum class AttrColor : BYTE { // Color attributes for console screen buffer - black = 0, - red = 4, - green = 2, - yellow = 6, - blue = 1, - magenta = 5, - cyan = 3, - gray = 7 - }; +#endif - inline HANDLE getConsoleHandle(const std::streambuf *osbuf) noexcept - { - if (osbuf == std::cout.rdbuf()) { - static const HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE); - return hStdout; - } else if (osbuf == std::cerr.rdbuf() || osbuf == std::clog.rdbuf()) { - static const HANDLE hStderr = GetStdHandle(STD_ERROR_HANDLE); - return hStderr; - } - return INVALID_HANDLE_VALUE; + inline bool isTerminal(const std::streambuf* osbuf) noexcept { + using std::cerr; + using std::clog; + using std::cout; +#if defined(OS_LINUX) || defined(OS_MAC) + if (osbuf == cout.rdbuf()) { + static const bool cout_term = isatty(fileno(stdout)) != 0; + return cout_term; + } else if (osbuf == cerr.rdbuf() || osbuf == clog.rdbuf()) { + static const bool cerr_term = isatty(fileno(stderr)) != 0; + return cerr_term; } - - inline bool setWinTermAnsiColors(const std::streambuf *osbuf) noexcept - { - HANDLE h = getConsoleHandle(osbuf); - if (h == INVALID_HANDLE_VALUE) { - return false; - } - DWORD dwMode = 0; - if (!GetConsoleMode(h, &dwMode)) { - return false; - } - dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; - if (!SetConsoleMode(h, dwMode)) { - return false; - } - return true; +#elif defined(OS_WIN) + if (osbuf == cout.rdbuf()) { + static const bool cout_term = (_isatty(_fileno(stdout)) || isMsysPty(_fileno(stdout))); + return cout_term; + } else if (osbuf == cerr.rdbuf() || osbuf == clog.rdbuf()) { + static const bool cerr_term = (_isatty(_fileno(stderr)) || isMsysPty(_fileno(stderr))); + return cerr_term; } +#endif + return false; + } - inline bool supportsAnsi(const std::streambuf *osbuf) noexcept - { - using std::cerr; - using std::clog; - using std::cout; - if (osbuf == cout.rdbuf()) { - static const bool cout_ansi - = (isMsysPty(_fileno(stdout)) || setWinTermAnsiColors(osbuf)); - return cout_ansi; - } else if (osbuf == cerr.rdbuf() || osbuf == clog.rdbuf()) { - static const bool cerr_ansi - = (isMsysPty(_fileno(stderr)) || setWinTermAnsiColors(osbuf)); - return cerr_ansi; - } - return false; - } + template <typename T> + using enableStd = typename std::enable_if< + std::is_same<T, rang::style>::value || std::is_same<T, rang::fg>::value || + std::is_same<T, rang::bg>::value || std::is_same<T, rang::fgB>::value || + std::is_same<T, rang::bgB>::value, + std::ostream&>::type; - inline const SGR &defaultState() noexcept - { - static const SGR defaultSgr = []() -> SGR { - CONSOLE_SCREEN_BUFFER_INFO info; - WORD attrib = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; - if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), - &info) - || GetConsoleScreenBufferInfo(GetStdHandle(STD_ERROR_HANDLE), - &info)) { - attrib = info.wAttributes; - } - SGR sgr = { 0, 0, 0, 0, FALSE, FALSE }; - sgr.fgColor = attrib & 0x0F; - sgr.bgColor = (attrib & 0xF0) >> 4; - return sgr; - }(); - return defaultSgr; - } +#ifdef OS_WIN - inline BYTE ansi2attr(BYTE rgb) noexcept - { - static const AttrColor rev[8] - = { AttrColor::black, AttrColor::red, AttrColor::green, - AttrColor::yellow, AttrColor::blue, AttrColor::magenta, - AttrColor::cyan, AttrColor::gray }; - return static_cast<BYTE>(rev[rgb]); + struct SGR { // Select Graphic Rendition parameters for Windows console + BYTE fgColor; // foreground color (0-15) lower 3 rgb bits + intense bit + BYTE bgColor; // background color (0-15) lower 3 rgb bits + intense bit + BYTE bold; // emulated as FOREGROUND_INTENSITY bit + BYTE underline; // emulated as BACKGROUND_INTENSITY bit + BOOLEAN inverse; // swap foreground/bold & background/underline + BOOLEAN conceal; // set foreground/bold to background/underline + }; + + enum class AttrColor : BYTE { // Color attributes for console screen buffer + black = 0, + red = 4, + green = 2, + yellow = 6, + blue = 1, + magenta = 5, + cyan = 3, + gray = 7 + }; + + inline HANDLE getConsoleHandle(const std::streambuf* osbuf) noexcept { + if (osbuf == std::cout.rdbuf()) { + static const HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE); + return hStdout; + } else if (osbuf == std::cerr.rdbuf() || osbuf == std::clog.rdbuf()) { + static const HANDLE hStderr = GetStdHandle(STD_ERROR_HANDLE); + return hStderr; } + return INVALID_HANDLE_VALUE; + } - inline void setWinSGR(rang::bg col, SGR &state) noexcept - { - if (col != rang::bg::reset) { - state.bgColor = ansi2attr(static_cast<BYTE>(col) - 40); - } else { - state.bgColor = defaultState().bgColor; - } + inline bool setWinTermAnsiColors(const std::streambuf* osbuf) noexcept { + HANDLE h = getConsoleHandle(osbuf); + if (h == INVALID_HANDLE_VALUE) { + return false; } - - inline void setWinSGR(rang::fg col, SGR &state) noexcept - { - if (col != rang::fg::reset) { - state.fgColor = ansi2attr(static_cast<BYTE>(col) - 30); - } else { - state.fgColor = defaultState().fgColor; - } + DWORD dwMode = 0; + if (!GetConsoleMode(h, &dwMode)) { + return false; } - - inline void setWinSGR(rang::bgB col, SGR &state) noexcept - { - state.bgColor = (BACKGROUND_INTENSITY >> 4) - | ansi2attr(static_cast<BYTE>(col) - 100); + dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; + if (!SetConsoleMode(h, dwMode)) { + return false; } - - inline void setWinSGR(rang::fgB col, SGR &state) noexcept - { - state.fgColor - = FOREGROUND_INTENSITY | ansi2attr(static_cast<BYTE>(col) - 90); + return true; + } + + inline bool supportsAnsi(const std::streambuf* osbuf) noexcept { + using std::cerr; + using std::clog; + using std::cout; + if (osbuf == cout.rdbuf()) { + static const bool cout_ansi = (isMsysPty(_fileno(stdout)) || setWinTermAnsiColors(osbuf)); + return cout_ansi; + } else if (osbuf == cerr.rdbuf() || osbuf == clog.rdbuf()) { + static const bool cerr_ansi = (isMsysPty(_fileno(stderr)) || setWinTermAnsiColors(osbuf)); + return cerr_ansi; } - - inline void setWinSGR(rang::style style, SGR &state) noexcept - { - switch (style) { - case rang::style::reset: state = defaultState(); break; - case rang::style::bold: state.bold = FOREGROUND_INTENSITY; break; - case rang::style::underline: - case rang::style::blink: - state.underline = BACKGROUND_INTENSITY; - break; - case rang::style::reversed: state.inverse = TRUE; break; - case rang::style::conceal: state.conceal = TRUE; break; - default: break; - } + return false; + } + + inline const SGR& defaultState() noexcept { + static const SGR defaultSgr = []() -> SGR { + CONSOLE_SCREEN_BUFFER_INFO info; + WORD attrib = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; + if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info) || + GetConsoleScreenBufferInfo(GetStdHandle(STD_ERROR_HANDLE), &info)) { + attrib = info.wAttributes; + } + SGR sgr = {0, 0, 0, 0, FALSE, FALSE}; + sgr.fgColor = attrib & 0x0F; + sgr.bgColor = (attrib & 0xF0) >> 4; + return sgr; + }(); + return defaultSgr; + } + + inline BYTE ansi2attr(BYTE rgb) noexcept { + static const AttrColor rev[8] = {AttrColor::black, AttrColor::red, AttrColor::green, + AttrColor::yellow, AttrColor::blue, AttrColor::magenta, + AttrColor::cyan, AttrColor::gray}; + return static_cast<BYTE>(rev[rgb]); + } + + inline void setWinSGR(rang::bg col, SGR& state) noexcept { + if (col != rang::bg::reset) { + state.bgColor = ansi2attr(static_cast<BYTE>(col) - 40); + } else { + state.bgColor = defaultState().bgColor; } + } - inline SGR ¤t_state() noexcept - { - static SGR state = defaultState(); - return state; + inline void setWinSGR(rang::fg col, SGR& state) noexcept { + if (col != rang::fg::reset) { + state.fgColor = ansi2attr(static_cast<BYTE>(col) - 30); + } else { + state.fgColor = defaultState().fgColor; } - - inline WORD SGR2Attr(const SGR &state) noexcept - { - WORD attrib = 0; - if (state.conceal) { - if (state.inverse) { - attrib = (state.fgColor << 4) | state.fgColor; - if (state.bold) - attrib |= FOREGROUND_INTENSITY | BACKGROUND_INTENSITY; - } else { - attrib = (state.bgColor << 4) | state.bgColor; - if (state.underline) - attrib |= FOREGROUND_INTENSITY | BACKGROUND_INTENSITY; - } - } else if (state.inverse) { - attrib = (state.fgColor << 4) | state.bgColor; - if (state.bold) attrib |= BACKGROUND_INTENSITY; - if (state.underline) attrib |= FOREGROUND_INTENSITY; - } else { - attrib = state.fgColor | (state.bgColor << 4) | state.bold - | state.underline; - } - return attrib; + } + + inline void setWinSGR(rang::bgB col, SGR& state) noexcept { + state.bgColor = (BACKGROUND_INTENSITY >> 4) | ansi2attr(static_cast<BYTE>(col) - 100); + } + + inline void setWinSGR(rang::fgB col, SGR& state) noexcept { + state.fgColor = FOREGROUND_INTENSITY | ansi2attr(static_cast<BYTE>(col) - 90); + } + + inline void setWinSGR(rang::style style, SGR& state) noexcept { + switch (style) { + case rang::style::reset: + state = defaultState(); + break; + case rang::style::bold: + state.bold = FOREGROUND_INTENSITY; + break; + case rang::style::underline: + case rang::style::blink: + state.underline = BACKGROUND_INTENSITY; + break; + case rang::style::reversed: + state.inverse = TRUE; + break; + case rang::style::conceal: + state.conceal = TRUE; + break; + default: + break; } - - template <typename T> - inline void setWinColorAnsi(std::ostream &os, T const value) - { - os << "\033[" << static_cast<int>(value) << "m"; + } + + inline SGR& current_state() noexcept { + static SGR state = defaultState(); + return state; + } + + inline WORD SGR2Attr(const SGR& state) noexcept { + WORD attrib = 0; + if (state.conceal) { + if (state.inverse) { + attrib = (state.fgColor << 4) | state.fgColor; + if (state.bold) attrib |= FOREGROUND_INTENSITY | BACKGROUND_INTENSITY; + } else { + attrib = (state.bgColor << 4) | state.bgColor; + if (state.underline) attrib |= FOREGROUND_INTENSITY | BACKGROUND_INTENSITY; + } + } else if (state.inverse) { + attrib = (state.fgColor << 4) | state.bgColor; + if (state.bold) attrib |= BACKGROUND_INTENSITY; + if (state.underline) attrib |= FOREGROUND_INTENSITY; + } else { + attrib = state.fgColor | (state.bgColor << 4) | state.bold | state.underline; } - - template <typename T> - inline void setWinColorNative(std::ostream &os, T const value) - { - const HANDLE h = getConsoleHandle(os.rdbuf()); - if (h != INVALID_HANDLE_VALUE) { - setWinSGR(value, current_state()); - // Out all buffered text to console with previous settings: - os.flush(); - SetConsoleTextAttribute(h, SGR2Attr(current_state())); - } + return attrib; + } + + template <typename T> + inline void setWinColorAnsi(std::ostream& os, T const value) { + os << "\033[" << static_cast<int>(value) << "m"; + } + + template <typename T> + inline void setWinColorNative(std::ostream& os, T const value) { + const HANDLE h = getConsoleHandle(os.rdbuf()); + if (h != INVALID_HANDLE_VALUE) { + setWinSGR(value, current_state()); + // Out all buffered text to console with previous settings: + os.flush(); + SetConsoleTextAttribute(h, SGR2Attr(current_state())); } - - template <typename T> - inline enableStd<T> setColor(std::ostream &os, T const value) - { - if (winTermMode() == winTerm::Auto) { - if (supportsAnsi(os.rdbuf())) { - setWinColorAnsi(os, value); - } else { - setWinColorNative(os, value); - } - } else if (winTermMode() == winTerm::Ansi) { - setWinColorAnsi(os, value); - } else { - setWinColorNative(os, value); - } - return os; + } + + template <typename T> + inline enableStd<T> setColor(std::ostream& os, T const value) { + if (winTermMode() == winTerm::Auto) { + if (supportsAnsi(os.rdbuf())) { + setWinColorAnsi(os, value); + } else { + setWinColorNative(os, value); + } + } else if (winTermMode() == winTerm::Ansi) { + setWinColorAnsi(os, value); + } else { + setWinColorNative(os, value); } + return os; + } #else - template <typename T> - inline enableStd<T> setColor(std::ostream &os, T const value) - { - return os << "\033[" << static_cast<int>(value) << "m"; - } + template <typename T> + inline enableStd<T> setColor(std::ostream& os, T const value) { + return os << "\033[" << static_cast<int>(value) << "m"; + } #endif } // namespace rang_implementation template <typename T> -inline rang_implementation::enableStd<T> operator<<(std::ostream &os, - const T value) -{ - const control option = rang_implementation::controlMode(); - switch (option) { - case control::Auto: - return rang_implementation::supportsColor() - && rang_implementation::isTerminal(os.rdbuf()) - ? rang_implementation::setColor(os, value) - : os; - case control::Force: return rang_implementation::setColor(os, value); - default: return os; - } +inline rang_implementation::enableStd<T> operator<<(std::ostream& os, const T value) { + const control option = rang_implementation::controlMode(); + switch (option) { + case control::Auto: + return rang_implementation::supportsColor() && rang_implementation::isTerminal(os.rdbuf()) + ? rang_implementation::setColor(os, value) + : os; + case control::Force: + return rang_implementation::setColor(os, value); + default: + return os; + } } -inline void setWinTermMode(const rang::winTerm value) noexcept -{ - rang_implementation::winTermMode() = value; +inline void setWinTermMode(const rang::winTerm value) noexcept { + rang_implementation::winTermMode() = value; } -inline void setControlMode(const control value) noexcept -{ - rang_implementation::controlMode() = value; +inline void setControlMode(const control value) noexcept { + rang_implementation::controlMode() = value; } } // namespace rang |
