]> git.tdb.fi Git - libs/core.git/blob - source/fs/utils.cpp
b66b82dd70c90c1ed96b6f0cd13a27087ad4ebf5
[libs/core.git] / source / fs / utils.cpp
1 #include <cstdio>
2 #include <msp/core/systemerror.h>
3 #include <msp/strings/utils.h>
4 #include "dir.h"
5 #include "path.h"
6 #include "stat.h"
7 #include "utils.h"
8
9 using namespace std;
10
11 namespace Msp {
12 namespace FS {
13
14 string basename(const Path &p)
15 {
16         return p[-1];
17 }
18
19 Path dirname(const Path &p)
20 {
21         if(p.size()==1)
22         {
23                 if(p.is_absolute())
24                         return p;
25                 return ".";
26         }
27         return p.subpath(0, p.size()-1);
28 }
29
30 string basepart(const string &fn)
31 {
32         unsigned dot = fn.rfind('.');
33         return fn.substr(0, dot);
34 }
35
36 string extpart(const string &fn)
37 {
38         string::size_type dot = fn.rfind('.');
39         if(dot==string::npos)
40                 return string();
41         return fn.substr(dot);
42 }
43
44 Path fix_case(const Path &path)
45 {
46         bool found = true;
47         Path result;
48         for(Path::Iterator i=path.begin(); i!=path.end(); ++i)
49         {
50                 if(!found || *i=="/")
51                         result /= *i;
52                 else
53                 {
54                         list<string> files;
55                         if(result.size())
56                                 files = list_files(result);
57                         else
58                                 files = list_files(".");
59
60                         found = false;
61                         for(list<string>::iterator j=files.begin(); (j!=files.end() && !found); ++j)
62                                 if(!strcasecmp(*j,*i))
63                                 {
64                                         result /= *j;
65                                         found = true;
66                                 }
67
68                         if(!found)
69                                 result /= *i;
70                 }
71         }
72
73         return result;
74 }
75
76 Path readlink(const Path &link)
77 {
78 #ifdef WIN32
79         (void)link;
80         throw logic_error("no symbolic links on win32");
81 #else
82         char buf[4096];
83         int len = ::readlink(link.str().c_str(), buf, sizeof(buf));
84         if(len==-1)
85                 throw system_error("readlink");
86         return string(buf, len);
87 #endif
88 }
89
90 Path realpath(const Path &path)
91 {
92 #ifdef WIN32
93         if(path.is_absolute())
94                 return path;
95         else
96                 return getcwd()/path;
97 #else
98         list<string> queue(path.begin(), path.end());
99         if(!path.is_absolute())
100         {
101                 Path cwd = getcwd();
102                 queue.insert(queue.begin(), cwd.begin(), cwd.end());
103         }
104
105         Path real;
106         unsigned n_links = 0;
107         while(!queue.empty())
108         {
109                 Path next = real/queue.front();
110                 queue.pop_front();
111
112                 if(is_link(next))
113                 {
114                         if(++n_links>64)
115                                 throw runtime_error("too many symbolic links");
116                         Path link = readlink(next);
117                         queue.insert(queue.begin(), link.begin(), link.end());
118                 }
119                 else
120                         real = next;
121         }
122
123         return real;
124 #endif
125 }
126
127 void rename(const Path &from, const Path &to)
128 {
129         if(::rename(from.str().c_str(), to.str().c_str())==-1)
130                 throw system_error("rename");
131 }
132
133 void unlink(const Path &path)
134 {
135         if(::unlink(path.str().c_str())==-1)
136                 throw system_error("unlink");
137 }
138
139 Path relative(const Path &path, const Path &base)
140 {
141         Path::Iterator i = path.begin();
142         Path::Iterator j = base.begin();
143         for(; (i!=path.end() && j!=base.end() && *i==*j); ++i, ++j) ;
144
145         Path result;
146         for(; j!=base.end(); ++j)
147                 result /= "..";
148         for(; i!=path.end(); ++i)
149                 result /= *i;
150
151         return result;
152 }
153
154 int descendant_depth(const Path &path, const Path &parent)
155 {
156         Path::Iterator i = path.begin();
157         Path::Iterator j = parent.begin();
158         for(; (i!=path.end() && j!=parent.end() && *i==*j); ++i, ++j) ;
159
160         if(j!=parent.end())
161                 return -1;
162         
163         int result = 0;
164         for(; i!=path.end(); ++i)
165                 ++result;
166
167         return result;
168 }
169
170 } // namespace FS
171 } // namespace Msp