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