From a2513f7403e96fd30eb62318103a405df8e927b0 Mon Sep 17 00:00:00 2001
From: Recolic Keghart <root@recolic.net>
Date: Wed, 19 Feb 2020 04:47:45 -0800
Subject: [PATCH] add fs prettyprint (not enabled), adjust prettyprint
 interface

---
 3rdparty/fs_prettyprint.hpp | 96 +++++++++++++++++++++++++++++++++++++
 3rdparty/prettyprint.hpp    | 11 ++---
 3rdparty/test.cc            |  6 +--
 sys/unix_handy.hpp          | 17 +++++++
 4 files changed, 121 insertions(+), 9 deletions(-)
 create mode 100644 3rdparty/fs_prettyprint.hpp

diff --git a/3rdparty/fs_prettyprint.hpp b/3rdparty/fs_prettyprint.hpp
new file mode 100644
index 0000000..ac269d7
--- /dev/null
+++ b/3rdparty/fs_prettyprint.hpp
@@ -0,0 +1,96 @@
+#ifndef RLIB_FS_STATUS_PRETTYPRINT
+#define RLIB_FS_STATUS_PRETTYPRINT
+
+#include <filesystem>
+#include <iomanip>
+#include <ostream>
+#include <string>
+
+#include <rlib/require/cxx17>
+
+namespace rlib::prettyprint {
+
+namespace impl {
+inline std::string ftypeToString(const std::filesystem::file_type &t) {
+    switch(t) {
+        case std::filesystem::file_type::regular: return "regular file";
+        case std::filesystem::file_type::directory: return "directory";
+        case std::filesystem::file_type::symlink: return "symlink";
+        case std::filesystem::file_type::block: return "block file";
+        case std::filesystem::file_type::character: return "character file";
+        case std::filesystem::file_type::fifo: return "fifo";
+        case std::filesystem::file_type::socket: return "socket";
+        case std::filesystem::file_type::unknown: return "unknown";
+        case std::filesystem::file_type::none: return "none";
+        case std::filesystem::file_type::not_found: return "not_found";
+    }
+    return "";
+}
+
+inline std::string fsizeToString(const size_t fsize) {
+    if(fsize < 1024)
+        return std::to_string(fsize);
+    const auto KiB = (double)fsize / 1024.;
+    if(KiB < 1024) return std::to_string(KiB) + "Ki";
+    const auto MiB = KiB / 1024.;
+    if(MiB < 1024) return std::to_string(MiB) + "Mi";
+    const auto GiB = MiB / 1024.;
+    if(GiB < 1024) return std::to_string(GiB) + "Gi";
+    const auto TiB = GiB / 1024.;
+    if(TiB < 1024) return std::to_string(TiB) + "Ti";
+    const auto PiB = TiB / 1024.;
+    return std::to_string(PiB) + "Pi";
+}
+
+template <typename T>
+std::string try_show_file_size(const T &arg) {
+    try {
+        return fsizeToString(std::filesystem::file_size(arg));
+    }
+    catch(...) {
+        return "-";
+    }
+}
+}
+
+template<typename CharT, typename Traits>
+std::basic_ostream<CharT, Traits>&
+operator<< (std::basic_ostream<CharT, Traits> &os, const std::filesystem::perms& p) {
+    return os 
+        << ((p & std::filesystem::perms::owner_read) != std::filesystem::perms::none ? "r" : "-")
+        << ((p & std::filesystem::perms::owner_write) != std::filesystem::perms::none ? "w" : "-")
+        << ((p & std::filesystem::perms::owner_exec) != std::filesystem::perms::none ? "x" : "-")
+        << ((p & std::filesystem::perms::group_read) != std::filesystem::perms::none ? "r" : "-")
+        << ((p & std::filesystem::perms::group_write) != std::filesystem::perms::none ? "w" : "-")
+        << ((p & std::filesystem::perms::group_exec) != std::filesystem::perms::none ? "x" : "-")
+        << ((p & std::filesystem::perms::others_read) != std::filesystem::perms::none ? "r" : "-")
+        << ((p & std::filesystem::perms::others_write) != std::filesystem::perms::none ? "w" : "-")
+        << ((p & std::filesystem::perms::others_exec) != std::filesystem::perms::none ? "x" : "-")
+    ;
+}
+
+template<typename CharT, typename Traits>
+std::basic_ostream<CharT, Traits>&
+operator<< (std::basic_ostream<CharT, Traits> &os, const std::filesystem::file_type& t) {
+    return os << impl::ftypeToString(t);
+}
+
+template<typename CharT, typename Traits>
+std::basic_ostream<CharT, Traits>&
+operator<< (std::basic_ostream<CharT, Traits> &os, const std::filesystem::directory_entry& entry) {
+#if RLIB_CXX_STD >= 2020
+    auto lastWriteInSysClock = std::chrono::clock_cast<std::chrono::system_clock>(entry.last_write_time());
+#else
+#error A BUG NOT RESOLVED NOW. DO NOT USE THIS LIB.
+    auto lastWriteInSysClock = entry.last_write_time();
+#endif
+    auto lastWrite = std::chrono::system_clock::to_time_t(lastWriteInSysClock);
+    return os << entry.status().permissions() << ' ' << impl::try_show_file_size(entry) << ' ' << std::put_time(std::localtime(&lastWrite), "%F %T") << ' ' << entry.status().type();
+}
+
+
+
+} // end namespace rlib::prettyprint
+
+
+#endif
diff --git a/3rdparty/prettyprint.hpp b/3rdparty/prettyprint.hpp
index ce2226a..69916bf 100644
--- a/3rdparty/prettyprint.hpp
+++ b/3rdparty/prettyprint.hpp
@@ -30,10 +30,9 @@
 #include <utility>
 #include <valarray>
 
-#ifndef RLIB_3RD_ENABLE_PRETTYPRINT
 namespace rlib {
     namespace _3rdparty {
-#endif
+// 3rd party code begin
 namespace pretty_print
 {
     namespace detail
@@ -451,11 +450,11 @@ namespace std
         return stream << pretty_print::print_container_helper<T, TChar, TCharTraits>(container);
     }
 }
-#ifndef RLIB_3RD_ENABLE_PRETTYPRINT
+// 3rd party code end.
     }
 } // end namespace rlib::3rdparty
-#endif // RLIB_3RD_ENABLE_PRETTYPRINT 
-
-
+namespace rlib {
+    namespace prettyprint = ::rlib::_3rdparty::std;
+}
 
 #endif  // H_PRETTY_PRINT
diff --git a/3rdparty/test.cc b/3rdparty/test.cc
index 89a3519..95c8ef4 100644
--- a/3rdparty/test.cc
+++ b/3rdparty/test.cc
@@ -1,9 +1,9 @@
 #include "prettyprint.hpp"
 #include <rlib/stdio.hpp>
 #include <list>
-using namespace rlib;
+using namespace rlib::prettyprint;
 
 int main() {
-    std::list ls {1,3,2};
-    _3rdparty::std::operator<<(std::cout, ls);
+    std::list<int> ls {1,3,2};
+    std::cout << ls;
 }
diff --git a/sys/unix_handy.hpp b/sys/unix_handy.hpp
index ffc63bc..c65110b 100644
--- a/sys/unix_handy.hpp
+++ b/sys/unix_handy.hpp
@@ -2,6 +2,7 @@
 #define RLIB_UNIX_HANDY_HPP_
 
 #include <unistd.h>
+
 #include <sys/socket.h>
 #include <sys/types.h>
 #include <netdb.h>
@@ -13,6 +14,22 @@
 #error rlib/sys/unix_handy.hpp is not for Windows.
 #endif
 
+namespace rlib {
+    // args DOES NOT contain the "$0".
+    inline void execs(std::string path, std::vector<std::string> args) {
+        const size_t max_args = 1022;
+        if(args.size() > max_args)
+            throw std::out_of_range("too many arguments");
+        char* arr[max_args + 2];
+        arr[0] = (char *)path.c_str();
+        for(auto cter = 0; cter < args.size(); ++cter)
+            arr[cter+1] = (char *)args[cter].c_str();
+        arr[args.size() + 1] = 0;
+    
+        ::execv(path.c_str(), arr);
+    }
+}
+
 // Deprecated. Use sys/sio.hpp
 #if 1+1 == 4
 namespace rlib {
-- 
GitLab