]> git.tdb.fi Git - libs/core.git/blob - source/utils.cpp
strutils.h -> strings/utils.h
[libs/core.git] / source / utils.cpp
1 /*
2 This file is part of libmsppath
3 Copyright © 2006  Mikko Rasa, Mikkosoft Productions
4 Distributed under the LGPL
5 */
6 #include <dirent.h>
7 #include <sys/stat.h>
8 #include <errno.h>
9 #ifndef WIN32
10 #include <fnmatch.h>
11 #endif
12 #include <msp/strings/utils.h>
13 #include "path.h"
14 #include "utils.h"
15
16 using namespace std;
17
18 namespace Msp {
19 namespace Path {
20
21 /**
22 Fixes the case of the given path to match files / directories on the
23 filesystem.  Intended to be used in programs that need to interact with
24 emulated Windows programs.
25 */
26 Path fix_case(const Path &path)
27 {
28         bool found=true;
29         Path result;
30         for(Path::iterator i=path.begin(); i!=path.end(); ++i)
31         {
32                 if(!found || *i=="/")
33                         result/=*i;
34                 else
35                 {
36                         list<string> files;
37                         if(result.size())
38                                 files=list_files(result);
39                         else
40                                 files=list_files(".");
41
42                         found=false;
43                         for(list<string>::iterator j=files.begin(); (j!=files.end() && !found); ++j)
44                                 if(!strcasecmp(*j,*i))
45                                 {
46                                         result/=*j;
47                                         found=true;
48                                 }
49
50                         if(!found)
51                                 result/=*i;
52                 }
53         }
54
55         return result;
56 }
57
58 /**
59 Creates the given directory and any parent directories if needed.
60
61 @param   path  The path to create
62 @param   mode  Access mode for new directories
63
64 @return  0 on success, -1 on error
65 */
66 int mkpath(const Path &path, int mode)
67 {
68         Path p;
69         for(Path::iterator i=path.begin(); i!=path.end(); ++i)
70         {
71                 p/=*i;
72 #ifdef WIN32
73                 if(p.size()==1 && is_windows_drive(*i)) continue;
74 #endif
75                 struct stat st;
76                 int err=stat(p.str().c_str(),&st);
77                 if(err==0)
78                 {
79                         if(!S_ISDIR(st.st_mode))
80                         {
81                                 errno=EEXIST;
82                                 return -1;
83                         }
84                         continue;
85                 }
86                 else if(errno!=ENOENT)
87                         return -1;
88                 else
89                 {
90 #ifdef WIN32
91                         // The win32 version of this function doesn't take the mode argument.  Go figure.
92                         err=mkdir(p.str().c_str());
93 #else
94                         err=mkdir(p.str().c_str(),mode);
95 #endif
96                         if(err==-1) return -1;
97                 }
98         }
99
100         return 0;
101 }
102
103 int rmdir(const Path &path, bool recursive)
104 {
105         if(recursive)
106         {
107                 list<string> files=list_files(path);
108                 for(list<string>::iterator i=files.begin(); i!=files.end(); ++i)
109                 {
110                         Path p=path/ *i;
111                         struct stat st;
112                         stat(p.str().c_str(),&st);
113                         int err=0;
114                         if(S_ISDIR(st.st_mode))
115                                 err=rmdir(p,true);
116                         else
117                                 err=unlink(p.str().c_str());
118                         if(err) return err;
119                 }
120         }
121         return rmdir(path.str().c_str());
122 }
123
124 /**
125 Lists all files in a directory except the implied . and .. entries.
126 */
127 list<string> list_files(const Path &path)
128 {
129         list<string> result;
130         DIR *dir=opendir(path.str().c_str());
131         if(dir)
132         {
133                 while(dirent *de=readdir(dir))
134                 {
135                         const char *fn=de->d_name;
136                         if(fn[0]=='.' && (fn[1]==0 || (fn[1]=='.' && fn[2]==0))) continue;
137                         result.push_back(fn);
138                 }
139                 closedir(dir);
140         }
141         return result;
142 }
143
144 bool exists(const Path &path)
145 {
146         struct stat st;
147         return !stat(path.str().c_str(),&st);
148 }
149
150 Filename splitext(const string &fn)
151 {
152         Filename result;
153         unsigned dot=fn.rfind('.');
154         result.base=fn.substr(0,dot);
155         if(dot!=string::npos)
156                 result.ext=fn.substr(dot);
157         return result;
158 }
159
160 int fnmatch(const string &pat, const Path &fn)
161 {
162 #ifdef WIN32
163         return -1;
164 #else
165         return ::fnmatch(pat.c_str(), fn.str().c_str(), FNM_PATHNAME);
166 #endif
167 }
168
169 Path relative(const Path &path, const Path &base)
170 {
171         Path::iterator i=path.begin();
172         Path::iterator j=base.begin();
173         for(; (i!=path.end() && j!=base.end() && *i==*j); ++i,++j);
174
175         Path result;
176         for(; j!=base.end(); ++j)
177                 result/="..";
178         for(; i!=path.end(); ++i)
179                 result/=*i;
180
181         return result;
182 }
183
184 /**
185 Extracts the basename from the given path.  Same thing as Path::Path(p)[-1],
186 but faster.
187 */
188 string basename(const std::string &p)
189 {
190         unsigned slash=p.rfind(DIRCHAR);
191         if(slash==string::npos)
192                 return p;
193         else
194                 return p.substr(slash+1);
195 }
196
197 } // namespace Path
198 } // namespace Msp