27 #include "cif++/utilities.hpp" 29 #include "revision.hpp" 46 #if not defined(_MSC_VER) 47 #include <sys/ioctl.h> 51 namespace fs = std::filesystem;
65 write_version_string(s,
false);
74 #include <libloaderapi.h> 84 CONSOLE_SCREEN_BUFFER_INFO csbi;
85 ::GetConsoleScreenBufferInfo(::GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
86 return csbi.srWindow.Right - csbi.srWindow.Left + 1;
89 std::string GetExecutablePath()
93 DWORD
n = ::GetModuleFileNameW(
nullptr, buffer,
sizeof(buffer) /
sizeof(WCHAR));
95 throw std::runtime_error(
"could not get exe path");
97 std::wstring ws(buffer);
100 std::wstring_convert<std::codecvt_utf8<wchar_t>> conv1;
101 std::string u8str = conv1.to_bytes(ws);
112 uint32_t result = 80;
114 if (isatty(STDOUT_FILENO))
117 ioctl(0, TIOCGWINSZ, &w);
128 char path[1024] =
"";
129 if (readlink(
"/proc/self/exe", path,
sizeof(path)) == -1)
130 throw std::runtime_error(
"could not get exe path "s + strerror(errno));
153 if (mThread.joinable())
157 void PrintProgress();
162 int64_t mLastConsumed = 0;
163 int mSpinnerIndex = 0;
167 std::chrono::time_point<std::chrono::system_clock>
168 mStart = std::chrono::system_clock::now();
176 bool printedAny =
false;
182 std::this_thread::sleep_for(2s);
184 std::unique_lock lock(mMutex);
186 if (mStop
or mConsumed == mMax)
189 auto elapsed = std::chrono::system_clock::now() - mStart;
191 if (elapsed < std::chrono::seconds(5))
220 const char *kBlocks[] = {
235 msg.reserve(width + 1);
236 if (mMessage.length() <= 20)
239 if (msg.length() < 20)
240 msg.append(20 - msg.length(),
' ');
243 msg = mMessage.substr(0, 17) +
"...";
247 int64_t consumed = mConsumed;
248 float progress =
static_cast<float>(consumed) / mMax;
249 int pi =
static_cast<int>(std::ceil(progress * 33 * 8));
255 for (
int i = 0;
i < 33; ++
i)
268 const char kSpinner[] = {
' ',
'.',
'o',
'O',
'0',
'O',
'o',
'.'};
269 const size_t kSpinnerCount =
sizeof(kSpinner);
271 if (mLastConsumed < consumed)
273 mLastConsumed = consumed;
274 mSpinnerIndex = (mSpinnerIndex + 1) % kSpinnerCount;
277 const char spinner[2] = {kSpinner[mSpinnerIndex], 0};
288 std::cout <<
'\r' << msg;
295 std::ostream &operator<<(std::ostream &os, const std::chrono::duration<double> &t)
297 uint64_t s =
static_cast<uint64_t
>(
std::trunc(t.count()));
298 if (s > 24 * 60 * 60)
300 auto days = s / (24 * 60 * 60);
307 auto hours = s / (60 * 60);
314 auto minutes = s / 60;
315 os << minutes <<
"m ";
319 double ss = s + 1e-6 * (t.count() - s);
321 os << std::fixed << std::setprecision(1) << ss <<
's';
330 std::chrono::duration<double> elapsed = std::chrono::system_clock::now() - mStart;
332 std::ostringstream msgstr;
333 msgstr << mAction <<
" done in " << elapsed <<
" seconds";
334 auto msg = msgstr.str();
338 if (msg.length() < width)
339 msg += std::string(width - msg.length(),
' ');
341 std::cout <<
'\r' << msg << std::endl;
344 Progress::Progress(int64_t inMax,
const std::string &inAction)
347 if (isatty(STDOUT_FILENO) and
VERBOSE >= 0)
351 Progress::~Progress()
353 if (m_impl !=
nullptr)
359 void Progress::consumed(int64_t inConsumed)
361 if (m_impl !=
nullptr and
362 (m_impl->mConsumed += inConsumed) >= m_impl->mMax)
368 void Progress::progress(int64_t inProgress)
370 if (m_impl !=
nullptr and
371 (m_impl->mConsumed = inProgress) >= m_impl->mMax)
377 void Progress::message(
const std::string &inMessage)
379 if (m_impl !=
nullptr)
381 std::unique_lock lock(m_impl->mMutex);
382 m_impl->mMessage = inMessage;
411 extern "C" CIFPP_EXPORT
const mrsrc::rsrc_imp *gResourceIndexDefault[1] = {};
412 extern "C" CIFPP_EXPORT
const char *gResourceDataDefault[1] = {};
413 extern "C" CIFPP_EXPORT
const char *gResourceNameDefault[1] = {};
419 #pragma comment(linker, "/alternatename:gResourceIndex=gResourceIndexDefault") 420 #pragma comment(linker, "/alternatename:gResourceData=gResourceDataDefault") 421 #pragma comment(linker, "/alternatename:gResourceName=gResourceNameDefault") 447 const char *
data(
unsigned int offset)
const 449 return m_data + offset;
452 const char *
name(
unsigned int offset)
const 454 return m_name + offset;
461 if (gResourceIndex[0].m_child > 0
or gResourceIndex[0].m_size > 0)
471 const char *m_data =
"";
472 const char *m_name =
"";
488 : m_impl(other.m_impl)
494 m_impl = other.m_impl;
498 rsrc(std::filesystem::path path);
500 std::string
name()
const {
return rsrc_data::instance().name(m_impl->m_name); }
502 const char *
data()
const {
return rsrc_data::instance().data(m_impl->m_data); }
504 unsigned long size()
const {
return m_impl->m_size; }
506 explicit operator bool()
const {
return m_impl != NULL and m_impl->m_size > 0; }
508 template <
typename RSRC>
539 if (m_cur.m_impl->m_next)
540 m_cur.m_impl = rsrc_data::instance().index() + m_cur.m_impl->m_next;
542 m_cur.m_impl =
nullptr;
565 if (m_impl and m_impl->m_child)
566 impl = rsrc_data::instance().index() + m_impl->
m_child;
584 inline rsrc::rsrc(std::filesystem::path p)
586 m_impl = rsrc_data::instance().index();
593 while (m_impl !=
nullptr and pb != pe)
598 for (
rsrc child : *
this)
600 if (child.
name() == name)
616 template <
typename CharT,
typename Traits>
657 std::swap(m_begin, rhs.m_begin);
658 std::swap(m_end, rhs.m_end);
659 std::swap(m_current, rhs.m_current);
665 m_begin =
reinterpret_cast<const char_type *
>(m_rsrc.data());
666 m_end =
reinterpret_cast<const char_type *
>(m_rsrc.data() + m_rsrc.size());
672 if (m_current == m_end)
673 return traits_type::eof();
675 return traits_type::to_int_type(*m_current);
680 if (m_current == m_end)
681 return traits_type::eof();
683 return traits_type::to_int_type(*m_current++);
686 int_type pbackfail(int_type ch)
688 if (m_current == m_begin
or (ch != traits_type::eof() and ch != m_current[-1]))
689 return traits_type::eof();
691 return traits_type::to_int_type(*--m_current);
694 std::streamsize showmanyc()
696 assert(std::less_equal<const char *>()(m_current, m_end));
697 return m_end - m_current;
700 pos_type seekoff(off_type off, std::ios_base::seekdir dir, std::ios_base::openmode which)
704 case std::ios_base::beg:
705 m_current = m_begin + off;
708 case std::ios_base::end:
709 m_current = m_end + off;
712 case std::ios_base::cur:
720 if (m_current < m_begin)
723 if (m_current > m_end)
726 return m_current - m_begin;
729 pos_type seekpos(pos_type pos, std::ios_base::openmode which)
731 m_current = m_begin + pos;
733 if (m_current < m_begin)
736 if (m_current > m_end)
739 return m_current - m_begin;
744 const char_type *m_begin;
745 const char_type *m_end;
746 const char_type *m_current;
754 template <
typename CharT,
typename Traits>
766 using __istream_type = std::basic_istream<CharT, Traits>;
772 : __istream_type(&m_buffer)
775 this->init(&m_buffer);
779 : __istream_type(&m_buffer)
782 this->init(&m_buffer);
788 : __istream_type(
std::move(rhs))
789 , m_buffer(
std::move(rhs.m_buffer))
791 __istream_type::set_rdbuf(&m_buffer);
798 __istream_type::operator=(std::move(rhs));
799 m_buffer = std::move(rhs.m_buffer);
805 __istream_type::swap(rhs);
806 m_buffer.
swap(rhs.m_buffer);
830 static std::unique_ptr<ResourcePool> s_instance(
new ResourcePool);
838 if (fs::exists(dir, ec) and not ec)
839 mDirs.push_front(dir);
845 pushDir(fs::path(path));
848 void pushAlias(
const std::string &name, std::filesystem::path dataFile)
851 if (not fs::exists(dataFile, ec)
or ec)
852 throw std::runtime_error(
"Attempt to add a file resource for " + name +
" that cannot be used (" + dataFile.string() +
") :" + ec.message());
854 mLocalResources[name] = dataFile;
857 std::unique_ptr<std::istream> load(fs::path name);
862 std::unique_ptr<std::ifstream> open(fs::path &p)
864 std::unique_ptr<std::ifstream> result;
870 std::unique_ptr<std::ifstream> file(
new std::ifstream(p, std::ios::binary));
872 result.reset(file.release());
882 std::map<std::string, std::filesystem::path> mLocalResources;
883 std::deque<fs::path> mDirs;
886 ResourcePool::ResourcePool()
888 #if defined(DATA_DIR) 892 pushDir(getenv(
"LIBCIFPP_DATA_DIR"));
894 auto ccp4 = getenv(
"CCP4");
896 pushDir(fs::path(ccp4) /
"share" /
"libcifpp");
898 #if defined(CACHE_DIR) 905 std::unique_ptr<std::istream> result;
910 if (mLocalResources.count(name.string()))
911 result = open(mLocalResources[name.string()]);
913 for (
auto di = mDirs.begin(); not result and
di != mDirs.end(); ++
di)
916 if (fs::exists(p2, ec) and not ec)
921 if (not result and (gResourceIndex[0].m_child > 0
or gResourceIndex[0].m_size > 0))
uint32_t get_terminal_width()
basic_streambuf(basic_streambuf &&rhs)
std::ptrdiff_t difference_type
basic_istream(basic_istream &&rhs)
std::atomic< int64_t > mConsumed
traits_type::int_type int_type
bool operator==(const iterator_t &rhs) const
const char gResourceData[1]
iterator_t operator++(int)
const char * data(unsigned int offset) const
static rsrc_data & instance()
iterator_t & operator++()
basic_streambuf(const rsrc &rsrc)
constructor taking a rsrc
std::input_iterator_tag iterator_category
basic_istream & operator=(basic_istream &&rhs)
const mrsrc::rsrc_imp gResourceIndex[1]
iterator_t & operator=(const iterator_t &i)
const __attribute__((weak)) mrsrc const __attribute__((weak)) char gResourceData[]
std::unique_ptr< std::istream > load_resource(std::filesystem::path name)
void add_file_resource(const std::string &name, std::filesystem::path dataFile)
traits_type::pos_type pos_type
void swap(basic_istream &rhs)
static ResourcePool & instance()
const char * name(unsigned int offset) const
Class mrsrc::rsrc contains a pointer to the data in the resource, as well as offering an iterator int...
rsrc & operator=(const rsrc &other)
traits_type::int_type int_type
traits_type::off_type off_type
unsigned long size() const
const char gResourceName[1]
bool operator!=(const iterator_t &rhs) const
basic_streambuf(const std::string &path)
constructor taking a path to the resource in memory
basic_istream(const std::string &path)
basic_istream(rsrc &resource)
__streambuf_type * rdbuf() const
void add_data_directory(std::filesystem::path dataDir)
traits_type::off_type off_type
std::string get_version_nr()
void pushAlias(const std::string &name, std::filesystem::path dataFile)
iterator_t(const iterator_t &i)
iterator_t(const rsrc_imp *cur)
Internal data structure as generated by mrc.
const char * data() const
traits_type::pos_type pos_type
void pushDir(const char *path)
ProgressImpl(int64_t inMax, const std::string &inAction)
void pushDir(fs::path dir)
basic_streambuf & operator=(basic_streambuf &&rhs)
const rsrc_imp * index() const
std::unique_ptr< std::istream > load(fs::path name)
std::string get_executable_path()
void swap(basic_streambuf &rhs)