]> git.tdb.fi Git - libs/core.git/blob - source/utils.cpp
Rename the library as mspfs
[libs/core.git] / source / utils.cpp
1 /* $Id$
2
3 This file is part of libmspfs
4 Copyright © 2006-2008  Mikko Rasa, Mikkosoft Productions
5 Distributed under the LGPL
6 */
7
8 #include <dirent.h>
9 #include <cerrno>
10 #include <cstdlib>
11 #include <msp/core/except.h>
12 #ifndef WIN32
13 #include <fnmatch.h>
14 #else
15 #include <msp/strings/glob.h>
16 #endif
17 #include <msp/strings/utils.h>
18 #include "path.h"
19 #include "utils.h"
20
21 using namespace std;
22
23 namespace Msp {
24
25 /**
26 Fixes the case of the given path to match files / directories on the
27 filesystem.  Intended to be used in programs that need to interact with
28 emulated Windows programs.
29 */
30 Path fix_case(const Path &path)
31 {
32         bool found=true;
33         Path result;
34         for(Path::Iterator i=path.begin(); i!=path.end(); ++i)
35         {
36                 if(!found || *i=="/")
37                         result/=*i;
38                 else
39                 {
40                         list<string> files;
41                         if(result.size())
42                                 files=list_files(result);
43                         else
44                                 files=list_files(".");
45
46                         found=false;
47                         for(list<string>::iterator j=files.begin(); (j!=files.end() && !found); ++j)
48                                 if(!strcasecmp(*j,*i))
49                                 {
50                                         result/=*j;
51                                         found=true;
52                                 }
53
54                         if(!found)
55                                 result/=*i;
56                 }
57         }
58
59         return result;
60 }
61
62 void mkdir(const Path &path, int mode)
63 {
64         int err;
65 #ifdef WIN32
66         // The win32 version of this function doesn't take the mode argument.  Go figure.
67         (void)mode;
68         err=::mkdir(path.str().c_str());
69 #else
70         err=::mkdir(path.str().c_str(), mode);
71 #endif
72
73         if(err==-1)
74                 throw SystemError("mkdir failed", errno);
75 }
76
77 /**
78 Creates a directory and any parent directories if needed.
79
80 @param   path  The path to create
81 @param   mode  Access mode for new directories
82
83 @return  0 on success, -1 on error
84 */
85 void mkpath(const Path &path, int mode)
86 {
87         Path p;
88         for(Path::Iterator i=path.begin(); i!=path.end(); ++i)
89         {
90                 p/=*i;
91 #ifdef WIN32
92                 if(p.size()==1 && is_windows_drive(*i))
93                         continue;
94 #endif
95                 struct stat st;
96                 int err=stat(p, st);
97                 if(err==0)
98                 {
99                         if(!S_ISDIR(st.st_mode))
100                                 throw Exception("A component exists and is not a directory");
101                         continue;
102                 }
103                 else if(errno!=ENOENT)
104                         throw SystemError("stat failed", errno);
105                 else
106                         mkdir(p, mode);
107         }
108 }
109
110 void rmdir(const Path &path)
111 {
112         if(::rmdir(path.str().c_str())==-1)
113                 throw SystemError("rmdir failed", errno);
114 }
115
116 void rmdirs(const Path &path)
117 {
118         list<string> files=list_files(path);
119         for(list<string>::iterator i=files.begin(); i!=files.end(); ++i)
120         {
121                 Path p=path / *i;
122                 struct stat st=stat(p.str().c_str());
123                 if(S_ISDIR(st.st_mode))
124                         rmdirs(p);
125                 else
126                         unlink(p);
127         }
128
129         rmdir(path);
130 }
131
132 void unlink(const Path &path)
133 {
134         if(::unlink(path.str().c_str())==-1)
135                 throw SystemError("unlink failed", errno);
136 }
137
138 list<string> list_files(const Path &path)
139 {
140         list<string> result;
141         DIR *dir=opendir(path.str().c_str());
142         if(dir)
143         {
144                 while(dirent *de=readdir(dir))
145                 {
146                         const char *fn=de->d_name;
147                         if(fn[0]=='.' && (fn[1]==0 || (fn[1]=='.' && fn[2]==0))) 
148                                 continue;
149                         result.push_back(fn);
150                 }
151                 closedir(dir);
152         }
153
154         return result;
155 }
156
157 bool exists(const Path &path)
158 {
159         return access(path.str().c_str(), F_OK)==0;
160 }
161
162 bool is_dir(const Path &path)
163 {
164         struct stat st;
165         if(stat(path, st)==0)
166                 return S_ISDIR(st.st_mode);
167         return false;
168 }
169
170 Filename splitext(const string &fn)
171 {
172         Filename result;
173         unsigned dot=fn.rfind('.');
174         result.base=fn.substr(0, dot);
175         if(dot!=string::npos)
176                 result.ext=fn.substr(dot);
177         return result;
178 }
179
180 int fnmatch(const string &pat, const Path &fn)
181 {
182 #ifdef WIN32
183         return globcasematch(pat, fn.str());
184 #else
185         return ::fnmatch(pat.c_str(), fn.str().c_str(), FNM_PATHNAME);
186 #endif
187 }
188
189 Path relative(const Path &path, const Path &base)
190 {
191         Path::Iterator i=path.begin();
192         Path::Iterator j=base.begin();
193         for(; (i!=path.end() && j!=base.end() && *i==*j); ++i, ++j) ;
194
195         Path result;
196         for(; j!=base.end(); ++j)
197                 result/="..";
198         for(; i!=path.end(); ++i)
199                 result/=*i;
200
201         return result;
202 }
203
204 /**
205 Extracts the basename from the given path.  Same thing as Path::Path(p)[-1],
206 but faster.
207 */
208 string basename(const std::string &p)
209 {
210         unsigned slash=p.rfind(DIRCHAR);
211         if(slash==string::npos)
212                 return p;
213         else
214                 return p.substr(slash+1);
215 }
216
217 int stat(const Path &fn, struct stat &st)
218 {
219         return ::stat(fn.str().c_str(), &st);
220 }
221
222 struct stat stat(const Path &fn)
223 {
224         struct stat st;
225         if(stat(fn, st)==-1)
226                 throw SystemError("stat failed", errno);
227         return st;
228 }
229
230 Path getcwd()
231 {
232         char buf[1024];
233         return ::getcwd(buf, sizeof(buf));
234 }
235
236 Path get_home_dir()
237 {
238 #ifndef WIN32
239         const char *home=getenv("HOME");
240         if(home)
241                 return home;
242         return ".";
243 #else
244         return ".";
245 #endif
246 }
247
248 void chdir(const Path &path)
249 {
250         if(::chdir(path.str().c_str())==-1)
251                 throw SystemError("chdir failed", errno);
252 }
253
254 } // namespace Msp