]> git.tdb.fi Git - libs/core.git/blob - source/fs/dir.cpp
Style update: remove alignment
[libs/core.git] / source / fs / dir.cpp
1 #include <cstdlib>
2 #include <cerrno>
3 #include <dirent.h>
4 #include <sys/stat.h>
5 #ifdef WIN32
6 #include <shlobj.h>
7 #endif
8 #include <msp/core/except.h>
9 #include <msp/strings/regex.h>
10 #include <msp/strings/utils.h>
11 #include "dir.h"
12 #include "path.h"
13 #include "stat.h"
14 #include "utils.h"
15
16 using namespace std;
17
18 namespace Msp {
19 namespace FS {
20
21 namespace
22 {
23
24 /**
25 Helper function to determine the location of the program's executable.  Caches
26 the last result to cut down filesystem access with repeated calls.
27 */
28 const Path &get_bin_dir(const string &argv0)
29 {
30         static string last_argv0;
31         static Path bin_dir;
32
33         if(!(argv0==last_argv0))
34         {
35                 Path exe;
36                 if(argv0.find('/')==string::npos)
37                 {
38                         const char *path = getenv("PATH");
39                         vector<string> dirs = split(path, ':');
40                         for(vector<string>::const_iterator i=dirs.begin(); i!=dirs.end(); ++i)
41                                 if(exists(Path(*i)/argv0))
42                                 {
43                                         exe = realpath(Path(*i)/argv0);
44                                         break;
45                                 }
46                 }
47                 else
48                         exe = realpath(argv0);
49
50                 last_argv0 = argv0;
51                 bin_dir = dirname(exe);
52         }
53
54         return bin_dir;
55 }
56
57 }
58
59 void mkdir(const Path &path, int mode)
60 {
61         int err;
62 #ifdef WIN32
63         // The win32 version of this function doesn't take the mode argument.  Go figure.
64         (void)mode;
65         err = ::mkdir(path.str().c_str());
66 #else
67         err = ::mkdir(path.str().c_str(), mode);
68 #endif
69
70         if(err==-1)
71                 throw SystemError("mkdir failed", errno);
72 }
73
74 void mkpath(const Path &path, int mode)
75 {
76         Path p;
77         for(Path::Iterator i=path.begin(); i!=path.end(); ++i)
78         {
79                 p /= *i;
80 #ifdef WIN32
81                 if(p.size()==1 && p.is_absolute())
82                         continue;
83 #endif
84                 struct stat st;
85                 int err = stat(p, st);
86                 if(err==0)
87                 {
88                         if(!S_ISDIR(st.st_mode))
89                                 throw Exception("A component exists and is not a directory");
90                         continue;
91                 }
92                 else if(errno!=ENOENT)
93                         throw SystemError("stat failed", errno);
94                 else
95                         mkdir(p, mode);
96         }
97 }
98
99 void rmdir(const Path &path)
100 {
101         if(::rmdir(path.str().c_str())==-1)
102                 throw SystemError("rmdir failed", errno);
103 }
104
105 void rmdirs(const Path &path)
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 = stat(p.str().c_str());
112                 if(S_ISDIR(st.st_mode))
113                         rmdirs(p);
114                 else
115                         unlink(p);
116         }
117
118         rmdir(path);
119 }
120
121 list<string> list_files(const Path &path)
122 {
123         return list_filtered(path, string());
124 }
125
126 list<string> list_filtered(const Path &path, const string &filter)
127 {
128         Regex r_filter(filter);
129
130         list<string> result;
131         DIR *dir = opendir(path.str().c_str());
132         if(dir)
133         {
134                 while(dirent *de = readdir(dir))
135                 {
136                         const char *fn = de->d_name;
137                         if(fn[0]=='.' && (fn[1]==0 || (fn[1]=='.' && fn[2]==0))) 
138                                 continue;
139                         if(r_filter.match(fn))
140                                 result.push_back(fn);
141                 }
142                 closedir(dir);
143         }
144
145         return result;
146 }
147
148 Path getcwd()
149 {
150         char buf[1024];
151         return ::getcwd(buf, sizeof(buf));
152 }
153
154 Path get_home_dir()
155 {
156 #ifdef WIN32
157         char home[MAX_PATH];
158         if(SHGetFolderPath(0, CSIDL_PERSONAL, 0, 0, home)==S_OK)
159                 return home;
160 #else
161         const char *home = getenv("HOME");
162         if(home)
163                 return home;
164 #endif
165         return ".";
166 }
167
168 Path get_user_data_dir(const string &appname)
169 {
170 #ifdef WIN32
171         char datadir[MAX_PATH];
172         if(SHGetFolderPath(0, CSIDL_LOCAL_APPDATA, 0, 0, datadir)==S_OK)
173                 return Path(datadir)/appname;
174         return ".";
175 #else
176         return get_home_dir()/("."+appname);
177 #endif
178 }
179
180 Path get_sys_conf_dir(const string &argv0)
181 {
182         Path dir = get_bin_dir(argv0);
183
184         if(dir[-1]=="bin" || dir[-1]=="sbin")
185         {
186                 dir /= "..";
187                 if(dir[-1]=="usr")
188                         dir /= "..";
189                 return dir/"etc";
190         }
191         else
192                 return dir;
193 }
194
195 Path get_sys_data_dir(const string &argv0, const string &appname)
196 {
197         Path dir = get_bin_dir(argv0);
198
199         if(dir[-1]=="bin" || dir[-1]=="sbin")
200                 return dir/".."/"share"/appname;
201         else
202                 return dir;
203 }
204
205 Path get_sys_lib_dir(const string &argv0, const string &appname)
206 {
207         Path dir = get_bin_dir(argv0);
208
209         if(dir[-1]=="bin" || dir[-1]=="sbin")
210                 return dir/".."/"lib"/appname;
211         else
212                 return dir;
213 }
214
215 void chdir(const Path &path)
216 {
217         if(::chdir(path.str().c_str())==-1)
218                 throw SystemError("chdir failed", errno);
219 }
220
221 } // namespace FS
222 } // namespace Msp