removed debug print
[vrfileman] / src / fspath.cc
1 #include <stdio.h>
2 #include <string.h>
3 #include <assert.h>
4 #include <unistd.h>
5 #include <sys/stat.h>
6 #include "fspath.h"
7
8
9 char *make_abs_path(const char *s)
10 {
11         char wd[1024];
12         int slen = s ? strlen(s) : 0;
13         int len = slen;
14         char *res;
15
16         if(!s || *s != '/') {
17                 getcwd(wd, sizeof wd);
18                 int wdlen = strlen(wd);
19                 len = wdlen + 1 + slen;
20
21                 res = new char[len + 1];
22                 if(s) {
23                         sprintf(res, "%s/%s", wd, s);
24                 } else {
25                         memcpy(res, wd, len + 1);
26                 }
27         } else {
28                 res = new char[len + 1];
29                 memcpy(res, s, len + 1);
30         }
31
32         return res;
33 }
34
35 FSPath::FSPath()
36 {
37         abs_path = name = suffix = parent = 0;
38 }
39
40 FSPath::FSPath(const char *s)
41 {
42         abs_path = name = suffix = parent = 0;
43         set_path(s);
44 }
45
46 FSPath::~FSPath()
47 {
48         delete [] abs_path;
49         delete [] parent;
50 }
51
52 FSPath::FSPath(const FSPath &p)
53 {
54         abs_path = name = suffix = parent = 0;
55
56         if(abs_path) {
57                 int len = strlen(p.abs_path);
58                 abs_path = new char[len + 1];
59                 memcpy(abs_path, p.abs_path, len + 1);
60
61                 if(p.name) {
62                         name = abs_path + (p.name - p.abs_path);
63                 }
64                 if(p.suffix) {
65                         suffix = abs_path + (p.suffix - p.abs_path);
66                 }
67         }
68         if(p.parent) {
69                 int len = strlen(p.parent);
70                 parent = new char[len + 1];
71                 memcpy(parent, p.parent, len + 1);
72         }
73 }
74
75 FSPath &FSPath::operator =(const FSPath &p)
76 {
77         if(&p != this) {
78                 delete [] abs_path;
79                 delete [] parent;
80                 abs_path = name = suffix = parent = 0;
81
82                 if(p.abs_path) {
83                         int len = strlen(p.abs_path);
84                         abs_path = new char[len + 1];
85                         memcpy(abs_path, p.abs_path, len + 1);
86
87                         if(p.name) {
88                                 name = abs_path + (p.name - p.abs_path);
89                         }
90                         if(p.suffix) {
91                                 suffix = abs_path + (p.suffix - p.abs_path);
92                         }
93                 }
94                 if(p.parent) {
95                         int len = strlen(p.parent);
96                         parent = new char[len + 1];
97                         memcpy(parent, p.parent, len + 1);
98                 }
99         }
100         return *this;
101 }
102
103 FSPath::FSPath(FSPath &&p)
104 {
105         abs_path = p.abs_path;
106         name = p.name;
107         suffix = p.suffix;
108         parent = p.parent;
109
110         p.abs_path = p.name = p.suffix = p.parent = 0;
111 }
112
113 FSPath &FSPath::operator =(FSPath &&p)
114 {
115         if(&p != this) {
116                 delete [] abs_path;
117                 delete [] parent;
118
119                 abs_path = p.abs_path;
120                 name = p.name;
121                 suffix = p.suffix;
122                 parent = p.parent;
123
124                 p.abs_path = p.name = p.suffix = p.parent = 0;
125         }
126         return *this;
127 }
128
129 void FSPath::sanitize()
130 {
131         // first pass, convert and backslashes to slashes
132         char *s = abs_path;
133         while(*s) {
134                 if(*s == '\\') {
135                         *s = '/';
136                 }
137                 ++s;
138         }
139
140         // second pass, remove any "./" and "foo/.." parts
141         s = abs_path;
142         int len = strlen(s);
143         while((s = strstr(s, "./"))) {
144                 len -= 2;
145                 memmove(s, s + 2, len + 1);
146         }
147         assert(len == (int)strlen(abs_path));
148
149         s = abs_path;
150         while((s = strstr(s, "/.."))) {
151                 char *start = s;
152                 while(start > abs_path && *--start != '/');
153
154                 memmove(start, s + 3, len - 2);
155                 len -= (s + 3) - start;
156                 s = start;
157         }
158         assert(len == (int)strlen(abs_path));
159
160         // remove double slashes
161         while((s = strstr(abs_path, "//"))) {
162                 memmove(s, s + 1, len-- - (s - abs_path));
163         }
164         assert(len == (int)strlen(abs_path));
165
166         // remove trailing slash if abs_path is not just a slash (root)
167         if(len > 1 && abs_path[len - 1] == '/') {
168                 abs_path[--len] = 0;
169         }
170         assert(len == (int)strlen(abs_path));
171
172         // setup name and prefix pointers as necessary
173         name = suffix = 0;
174         s = abs_path;
175         while(*s) {
176                 if(*s == '/') name = s + 1;
177                 if(*s == '.') suffix = s;
178                 ++s;
179         }
180
181         if(!name) {
182                 name = abs_path;        // shouldn't happen, all paths start with a slash
183                 fprintf(stderr, "FSPath::sanitize: absolute path \"%s\" isn't absolute!\n", abs_path);
184         }
185
186         if(suffix == abs_path || suffix <= name) {
187                 suffix = 0;
188         }
189
190         // create parent name string
191         if(abs_path[0] == '/' && abs_path[1] == 0) {
192                 parent = 0;     // root dir has no parent
193         } else {
194                 int plen = name - 1 - abs_path;
195                 assert(plen >= 0);
196
197                 if(plen == 0) {
198                         plen = 1;       // our parent is root, so we need the slash
199                 }
200
201                 parent = new char[plen + 1];
202                 memcpy(parent, abs_path, plen);
203                 parent[plen] = 0;
204         }
205 }
206
207 bool FSPath::set_path(const char *s)
208 {
209         char *tmp = make_abs_path(s);
210         if(!tmp) {
211                 return false;
212         }
213
214         delete [] abs_path;
215         delete [] parent;
216         abs_path = tmp;
217         parent = 0;
218
219         sanitize();
220         return true;
221 }
222
223 const char *FSPath::get_path() const
224 {
225         return abs_path;
226 }
227
228 const char *FSPath::get_name() const
229 {
230         return name;
231 }
232
233 const char *FSPath::get_suffix() const
234 {
235         return suffix;
236 }
237
238 const char *FSPath::get_parent() const
239 {
240         return parent;
241 }
242
243 bool FSPath::append_path(const char *s)
244 {
245         if(!s || !*s) return false;
246
247         if(!abs_path) {
248                 return set_path(s);
249         }
250
251         if(*s == '/') {
252                 return false;   // can't append an absolute path
253         }
254
255         int len = strlen(abs_path) + 1 + strlen(s);
256         try {
257                 char *tmp = new char[len + 1];
258
259                 delete [] abs_path;
260                 abs_path = tmp;
261                 delete [] parent;
262                 parent = 0;
263         }
264         catch(...) {
265                 return false;
266         }
267
268         sanitize();
269         return true;
270 }
271
272 bool FSPath::exists() const
273 {
274         struct stat st;
275         return abs_path && stat(abs_path, &st) != -1;
276 }
277
278 bool FSPath::is_file() const
279 {
280         struct stat st;
281         return abs_path && stat(abs_path, &st) != -1 && S_ISREG(st.st_mode);
282 }
283
284 bool FSPath::is_dir() const
285 {
286         struct stat st;
287         return abs_path && stat(abs_path, &st) != -1 && S_ISDIR(st.st_mode);
288 }
289
290 bool FSPath::is_dev() const
291 {
292         struct stat st;
293         unsigned int devmask = S_IFBLK | S_IFCHR;
294         return abs_path && stat(abs_path, &st) != -1 && (st.st_mode & devmask);
295 }
296
297 FSPath::operator const char* () const
298 {
299         return abs_path;
300 }