summaryrefslogtreecommitdiff
path: root/tools/minicargo/helpers.h
diff options
context:
space:
mode:
Diffstat (limited to 'tools/minicargo/helpers.h')
-rw-r--r--tools/minicargo/helpers.h176
1 files changed, 174 insertions, 2 deletions
diff --git a/tools/minicargo/helpers.h b/tools/minicargo/helpers.h
index d9fe7e3c..35e791f1 100644
--- a/tools/minicargo/helpers.h
+++ b/tools/minicargo/helpers.h
@@ -4,14 +4,37 @@
namespace helpers {
+class string_view
+{
+ const char* m_start;
+ const size_t m_len;
+public:
+ string_view(const char* s, size_t n):
+ m_start(s), m_len(n)
+ {
+ }
+
+ bool operator==(const ::std::string& s) const {
+ return *this == s.c_str();
+ }
+ bool operator==(const char* s) const {
+ if(::std::strncmp(m_start, s, m_len) != 0)
+ return false;
+ return s[m_len] == '\0';
+ }
+ friend ::std::string& operator+=(::std::string& x, const string_view& sv) {
+ x.append(sv.m_start, sv.m_start+sv.m_len);
+ return x;
+ }
+};
/// Path helper class (because I don't want to include boost)
class path
{
#ifdef _WIN32
- const char SEP = '\\';
+ static const char SEP = '\\';
#else
- const char SEP = '/';
+ static const char SEP = '/';
#endif
::std::string m_str;
@@ -96,6 +119,155 @@ public:
return m_str;
}
+ class ComponentsIter
+ {
+ const path& p;
+ size_t pos;
+ size_t end;
+
+ friend class path;
+ ComponentsIter(const path& p, size_t i): p(p), pos(i) {
+ end = p.m_str.find(SEP, pos);
+ if(end == ::std::string::npos)
+ end = p.m_str.size();
+ }
+ public:
+ string_view operator*() const {
+ return string_view(p.m_str.c_str() + pos, end - pos);
+ }
+ void operator++() {
+ if(end == p.m_str.size())
+ pos = end;
+ else
+ {
+ pos = end+1;
+ end = p.m_str.find(SEP, pos);
+ if(end == ::std::string::npos)
+ end = p.m_str.size();
+ }
+ }
+ bool operator!=(const ComponentsIter& x) const {
+ return pos != x.pos;
+ }
+ };
+ ComponentsIter begin() const {
+ return ComponentsIter(*this, 0);
+ }
+ ComponentsIter end() const {
+ return ComponentsIter(*this, m_str.size());
+ }
+
+ path normalise() const
+ {
+ path rv;
+ rv.m_str.reserve( m_str.size()+1 );
+
+ for(auto comp : *this)
+ {
+ if( comp == "." ) {
+ // Ignore.
+ }
+ else if( comp == ".." )
+ {
+ // If the path is empty, OR the last element is a "..", push the element
+ if( rv.m_str.empty()
+ || (rv.m_str.size() == 3 && rv.m_str[0] == '.' && rv.m_str[1] == '.' && rv.m_str[2] == SEP)
+ || (rv.m_str.size() > 4 && *(rv.m_str.end()-4) == SEP && *(rv.m_str.end()-3) == '.' && *(rv.m_str.end()-2) == '.' && *(rv.m_str.end()-1) == SEP )
+ )
+ {
+ // Push
+ rv.m_str += comp;
+ rv.m_str += SEP;
+ }
+ else
+ {
+ rv.m_str.pop_back();
+ auto pos = rv.m_str.find_last_of(SEP);
+ if(pos == ::std::string::npos)
+ {
+ rv.m_str.resize(0);
+ }
+ else if( pos == 0 )
+ {
+ // Keep.
+ }
+ else
+ {
+ rv.m_str.resize(pos+1);
+ }
+ }
+ }
+ else {
+ rv.m_str += comp;
+ rv.m_str += SEP;
+ }
+ }
+ rv.m_str.pop_back();
+ return rv;
+ }
+#if 0
+ void normalise_in_place()
+ {
+ size_t insert_point = 0;
+
+ for(size_t read_pos = 0; read_pos < m_str.size(); read_pos ++)
+ {
+ auto pos = m_str.find_first_of(SEP, read_pos);
+ if(pos == ::std::string::npos)
+ pos = m_str.size();
+ auto comp = string_view(m_str.c_str() + read_pos, pos - read_pos);
+
+ bool append;
+ if(comp == ".")
+ {
+ // Advance read without touching insert
+ append = false;
+ }
+ else if( comp == ".." )
+ {
+ // Consume parent (if not a relative component already)
+ // Move insertion point back to the previous separator
+ auto pos = m_str.find_last_of(SEP, insert_point);
+ if(pos == ::std::string::npos)
+ {
+ // Only one component currently (or empty)
+ append = true;
+ }
+ else if(string_view(m_str.c_str() + pos+1, insert_point - pos-1) == "..")
+ {
+ // Last component is ".." - keep adding
+ append = true;
+ }
+ else
+ {
+ insert_point = pos;
+ append = false;
+ }
+ }
+ else
+ {
+ append = true;
+ }
+
+ if(append)
+ {
+ if( read_pos != insert_point )
+ {
+ //assert(read_pos > insert_point);
+ while(read_pos < pos)
+ {
+ m_str[insert_point++] = m_str[read_pos++];
+ }
+ }
+ }
+ else
+ {
+ read_pos = pos;
+ }
+ }
+ }
+#endif
+
friend ::std::ostream& operator<<(::std::ostream& os, const path& p)
{
return os << p.m_str;