Win32 tweaks
[libs/core.git] / source / path.cpp
1 /*
2 This file is part of libmsppath
3 Copyright © 2006  Mikko Rasa, Mikkosoft Productions
4 Distributed under the LGPL
5 */
6 #include <msp/strutils.h>
7 #include "utils.h"
8 #include "path.h"
9 #include "utils.h"
10
11 using namespace std;
12
13 namespace Msp {
14 namespace Path {
15
16 /**
17 Returns the number of components in the path.
18 */
19 unsigned Path::size() const
20 {
21         if(!path.size()) return 0;
22         if(path.size()==1 && path[0]==DIRCHAR) return 1;
23         unsigned count=1;
24         for(string::const_iterator i=path.begin(); i!=path.end(); ++i)
25                 if(*i==DIRCHAR) ++count;
26         return count;
27 }
28
29 bool Path::is_absolute() const
30 {
31 #ifdef WIN32
32         if(is_windows_drive((*this)[0])) return true;
33 #endif
34         if(path[0]==DIRCHAR) return true;
35         return false;
36 }
37
38 Path Path::subpath(unsigned start, unsigned count) const
39 {
40         Path result;
41         iterator i=begin();
42         for(unsigned j=0; (j<start && i!=end()); ++j)
43                 ++i;
44         for(unsigned j=0; (j<count && i!=end()); ++j)
45         {
46                 result/=*i;
47                 ++i;
48         }
49         return result;
50 }
51
52 /**
53 Attaches another path to the end of this one.  An absolute path replaces the
54 existing data.  ".." elements annihilate the last component and "." elements
55 are ignored.
56 */
57 Path &Path::operator/=(const Path &p)
58 {
59         if(p.is_absolute())
60                 path=p.path;
61         else
62         {
63                 for(iterator i=p.begin(); i!=p.end(); ++i)
64                 {
65                         if(*i=="..")
66                         {
67                                 unsigned slash=path.rfind(DIRCHAR);
68 #ifdef WIN32
69                                 if(is_windows_drive(path.substr(0,slash))) ++slash;
70 #endif
71                                 if(slash==0) ++slash;
72                                 if(slash==string::npos)
73                                         path="";
74                                 else
75                                         path.erase(slash);
76                         }
77                         else if(*i!=".")
78                         {
79                                 if(path.size()>1 || (path.size()==1 && path[0]!=DIRCHAR))
80                                         path+=DIRCHAR;
81                                 path+=*i;
82                         }
83                 }
84         }
85         return *this;
86 }
87
88 /**
89 Returns the path component at the specified index.  Negative indices count from
90 the end of the path.
91 */
92 string Path::operator[](int n) const
93 {
94         if(n>=0)
95         {
96                 for(iterator i=begin(); i!=end(); ++i,--n)
97                         if(!n) return *i;
98         }
99         else
100         {
101                 for(iterator i=--end();; --i)
102                 {
103                         if(!++n) return *i;
104                         if(i==begin()) break;
105                 }
106         }
107
108         return "";
109 }
110
111 bool Path::operator==(const Path &p) const
112 {
113 #ifdef WIN32
114         return !strcasecmp(path, p.path);
115 #else
116         return path==p.path;
117 #endif
118 }
119
120 void Path::init(const std::string &p)
121 {
122         unsigned start=0;
123         bool absolute=false;
124         if(p[0]==DIRCHAR)
125                 absolute=true;
126         while(1)
127         {
128                 unsigned slash=p.find_first_of("/\\",start);
129                 if(slash>start)
130                 {
131                         if(path.size() || absolute)
132                                 path+=DIRCHAR;
133                         path+=p.substr(start,slash-start);
134                 }
135                 if(slash==string::npos)
136                         break;
137                 start=slash+1;
138         }
139 }
140
141 Path::iterator::iterator(const Path &p):
142         path(p),
143         start(0)
144 {
145         if(path.path[0]==DIRCHAR)
146                 end=1;
147 #ifdef WIN32
148         else if(path.path[2]==DIRCHAR && is_windows_drive(path.path.substr(0,2)))
149                 end=2;
150 #endif
151         else
152                 end=path.path.find(DIRCHAR);
153 }
154
155 Path::iterator &Path::iterator::operator++()
156 {
157         start=end;
158         if(start>=path.path.size()) return *this;
159         if(path.path[start]==DIRCHAR) ++start;
160         end=path.path.find(DIRCHAR,start);
161         return *this;
162 }
163
164 Path::iterator &Path::iterator::operator--()
165 {
166         end=start;
167         if(end==0) return *this;
168         if(end>1 && end<path.path.size() && path.path[end]!=DIRCHAR) --end;
169         start=path.path.rfind(DIRCHAR,end-1);
170         if(start==string::npos)
171                 start=0;
172         else if(start<end-1)
173                 ++start;
174         return *this;
175 }
176
177 string Path::iterator::operator*() const
178 {
179         if(start>=path.path.size()) return "";
180         if(start==end) return "";
181         return path.path.substr(start,end-start);
182 }
183
184 } // namespace Path
185 } // namespace Msp