diff options
Diffstat (limited to 'build/timestamp.cxx')
-rw-r--r-- | build/timestamp.cxx | 154 |
1 files changed, 154 insertions, 0 deletions
diff --git a/build/timestamp.cxx b/build/timestamp.cxx new file mode 100644 index 0000000..db8efb2 --- /dev/null +++ b/build/timestamp.cxx @@ -0,0 +1,154 @@ +// file : build/timestamp.cxx -*- C++ -*- +// copyright : Copyright (c) 2014-2015 Code Synthesis Tools CC +// license : MIT; see accompanying LICENSE file + +#include <build/timestamp> + +#include <unistd.h> // stat +#include <sys/types.h> // stat +#include <sys/stat.h> // stat + +#include <time.h> // localtime, gmtime, strftime + +#include <ostream> +#include <system_error> + +using namespace std; + +namespace build +{ + // Figuring out whether we have the nanoseconds in some form. + // + template <typename S> + constexpr auto nsec (const S* s) -> decltype(s->st_mtim.tv_nsec) + { + return s->st_mtim.tv_nsec; // POSIX (GNU/Linux, Solaris). + } + + template <typename S> + constexpr auto nsec (const S* s) -> decltype(s->st_mtimespec.tv_nsec) + { + return s->st_mtimespec.tv_nsec; // MacOS X. + } + + template <typename S> + constexpr auto nsec (const S* s) -> decltype(s->st_mtime_n) + { + return s->st_mtime_n; // AIX 5.2 and later. + } + + template <typename S> + constexpr int nsec (...) {return 0;} + + timestamp + path_timestamp (const std::string& p) + { + struct stat s; + if (stat (p.c_str (), &s) != 0) + { + if (errno == ENOENT || errno == ENOTDIR) + return timestamp_nonexistent; + else + throw system_error (errno, system_category ()); + } + + return system_clock::from_time_t (s.st_mtime) + + chrono::duration_cast<duration> ( + chrono::nanoseconds (nsec<struct stat> (&s))); + } + + ostream& + operator<< (ostream& os, timestamp ts) + { + // @@ replace with put_time() + // + + time_t t (system_clock::to_time_t (ts)); + + if (t == 0) + return os << "<nonexistent>"; + + std::tm tm; + if (localtime_r (&t, &tm) == nullptr) + throw system_error (errno, system_category ()); + + // If year is greater than 9999, we will overflow. + // + char buf[20]; // YYYY-MM-DD HH:MM:SS\0 + if (strftime (buf, sizeof (buf), "%Y-%m-%d %H:%M:%S", &tm) == 0) + return os << "<beyond year 9999>"; + + os << buf; + + using namespace chrono; + + timestamp sec (system_clock::from_time_t (t)); + nanoseconds ns (duration_cast<nanoseconds> (ts - sec)); + + if (ns != nanoseconds::zero ()) + { + os << '.'; + os.width (9); + os.fill ('0'); + os << ns.count (); + } + + return os; + } + + ostream& + operator<< (ostream& os, duration d) + { + // @@ replace with put_time() + // + + timestamp ts; // Epoch. + ts += d; + + time_t t (system_clock::to_time_t (ts)); + + const char* fmt (nullptr); + if (t >= 365 * 12 * 24 * 60 * 60) + fmt = "%Y-%m-%d %H:%M:%S"; + else if (t >= 12 * 24 * 60* 60) + fmt = "%m-%d %H:%M:%S"; + else if (t >= 24 * 60* 60) + fmt = "%d %H:%M:%S"; + else if (t >= 60 * 60) + fmt = "%H:%M:%S"; + else if (t >= 60) + fmt = "%M:%S"; + else if (t >= 1) + fmt = "%S"; + + if (fmt != nullptr) + { + std::tm tm; + if (gmtime_r (&t, &tm) == nullptr) + throw system_error (errno, system_category ()); + + char buf[20]; // YYYY-MM-DD HH:MM:SS\0 + if (strftime (buf, sizeof (buf), fmt, &tm) == 0) + return os << "<beyond 9999 years>"; + + os << buf; + } + + using namespace chrono; + + timestamp sec (system_clock::from_time_t (t)); + nanoseconds ns (duration_cast<nanoseconds> (ts - sec)); + + if (ns != nanoseconds::zero ()) + { + os << '.'; + os.width (9); + os.fill ('0'); + os << ns.count (); + } + else if (fmt == 0) + os << '0'; + + return os; + } +} |