]> git.tdb.fi Git - libs/core.git/blob - source/utils.cpp
Add relative() to utils
[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/strutils.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 int mkpath(const Path &path, int mode)
59 {
60         Path p;
61         for(Path::iterator i=path.begin(); i!=path.end(); ++i)
62         {
63                 p/=*i;
64 #ifdef WIN32
65                 if(p.size()==1 && is_windows_drive(*i)) continue;
66 #endif
67                 struct stat st;
68                 int err=stat(p.str().c_str(),&st);
69                 if(err==0)
70                 {
71                         if(!S_ISDIR(st.st_mode))
72                         {
73                                 errno=EEXIST;
74                                 return -1;
75                         }
76                         continue;
77                 }
78                 else if(errno!=ENOENT)
79                         return -1;
80                 else
81                 {
82 #ifdef WIN32
83                         // The win32 version of this function doesn't take the mode argument.  Go figure.
84                         err=mkdir(p.str().c_str());
85 #else
86                         err=mkdir(p.str().c_str(),mode);
87 #endif
88                         if(err==-1) return -1;
89                 }
90         }
91
92         return 0;
93 }
94
95 int rmdir(const Path &path, bool recursive)
96 {
97         if(recursive)
98         {
99                 list<string> files=list_files(path);
100                 for(list<string>::iterator i=files.begin(); i!=files.end(); ++i)
101                 {
102                         Path p=path/ *i;
103                         struct stat st;
104                         stat(p.str().c_str(),&st);
105                         int err=0;
106                         if(S_ISDIR(st.st_mode))
107                                 err=rmdir(p,true);
108                         else
109                                 err=unlink(p.str().c_str());
110                         if(err) return err;
111                 }
112         }
113         return rmdir(path.str().c_str());
114 }
115
116 /**
117 Lists all files in a directory except the implied . and .. entries.
118 */
119 list<string> list_files(const Path &path)
120 {
121         list<string> result;
122         DIR *dir=opendir(path.str().c_str());
123         if(dir)
124         {
125                 while(dirent *de=readdir(dir))
126                 {
127                         const char *fn=de->d_name;
128                         if(fn[0]=='.' && (fn[1]==0 || (fn[1]=='.' && fn[2]==0))) continue;
129                         result.push_back(fn);
130                 }
131                 closedir(dir);
132         }
133         return result;
134 }
135
136 bool exists(const Path &path)
137 {
138         struct stat st;
139         return !stat(path.str().c_str(),&st);
140 }
141
142 Filename splitext(const string &fn)
143 {
144         Filename result;
145         unsigned dot=fn.rfind('.');
146         result.base=fn.substr(0,dot);
147         if(dot!=string::npos)
148                 result.ext=fn.substr(dot);
149         return result;
150 }
151
152 int fnmatch(const string &pat, const Path &fn)
153 {
154 #ifdef WIN32
155         return -1;
156 #else
157         return ::fnmatch(pat.c_str(), fn.str().c_str(), FNM_PATHNAME);
158 #endif
159 }
160
161 Path relative(const Path &path, const Path &base)
162 {
163         Path::iterator i=path.begin();
164         Path::iterator j=base.begin();
165         for(; (i!=path.end() && j!=base.end() && *i==*j); ++i,++j);
166
167         Path result;
168         for(; j!=base.end(); ++j)
169                 result/="..";
170         for(; i!=path.end(); ++i)
171                 result/=*i;
172
173         return result;
174 }
175
176 } // namespace Path
177 } // namespace Msp