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