]> git.tdb.fi Git - libs/core.git/blob - source/fs/dir.cpp
8625b783ef464357439833a0d3685175ab40041a
[libs/core.git] / source / fs / dir.cpp
1 #include <cstdlib>
2 #include <unistd.h>
3 #include <dirent.h>
4 #include <msp/core/application.h>
5 #include <msp/core/systemerror.h>
6 #include <msp/strings/regex.h>
7 #include <msp/strings/utils.h>
8 #include "dir.h"
9 #include "path.h"
10 #include "stat.h"
11 #include "utils.h"
12
13 using namespace std;
14
15 namespace Msp {
16 namespace FS {
17
18 namespace
19 {
20
21 enum
22 {
23 #ifdef _WIN32
24         ITEMSEP = ';'
25 #else
26         ITEMSEP = ':'
27 #endif
28 };
29
30 /** Helper function to determine the location of the program's executable.
31 Caches the last result to cut down filesystem access with repeated calls. */
32 const Path &get_bin_dir(const string &argv0)
33 {
34         static string last_argv0;
35         static Path bin_dir;
36
37         if(!(argv0==last_argv0))
38         {
39                 Path exe;
40                 if(argv0.find('/')==string::npos)
41                 {
42                         const char *path = getenv("PATH");
43                         vector<string> dirs = split(path, ITEMSEP);
44                         for(vector<string>::const_iterator i=dirs.begin(); i!=dirs.end(); ++i)
45                                 if(exists(Path(*i)/argv0))
46                                 {
47                                         exe = realpath(Path(*i)/argv0);
48                                         break;
49                                 }
50                 }
51
52                 if(exe.empty())
53                         exe = realpath(argv0);
54
55                 last_argv0 = argv0;
56                 bin_dir = dirname(exe);
57         }
58
59         return bin_dir;
60 }
61
62 }
63
64
65 not_a_directory::not_a_directory(const Path &p):
66         runtime_error(p.str())
67 { }
68
69
70 void mkpath(const Path &path, int mode)
71 {
72         Path p;
73         for(Path::Iterator i=path.begin(); i!=path.end(); ++i)
74         {
75                 p /= *i;
76 #ifdef _WIN32
77                 if(p.size()==1 && p.is_absolute())
78                         continue;
79 #endif
80                 if(FS::Stat st = stat(p))
81                 {
82                         if(!st.is_directory())
83                                 throw not_a_directory(p);
84                         continue;
85                 }
86                 else
87                         mkdir(p, mode);
88         }
89 }
90
91 void rmpath(const Path &path)
92 {
93         list<string> files = list_files(path);
94         for(list<string>::iterator i=files.begin(); i!=files.end(); ++i)
95         {
96                 Path p = path / *i;
97                 if(is_dir(p))
98                         rmpath(p);
99                 else
100                         unlink(p);
101         }
102
103         rmdir(path);
104 }
105
106 list<string> list_files(const Path &path)
107 {
108         return list_filtered(path, string());
109 }
110
111 list<string> list_filtered(const Path &path, const string &filter)
112 {
113         Regex r_filter(filter);
114
115         list<string> result;
116         DIR *dir = opendir(path.str().c_str());
117         if(!dir)
118                 throw system_error("opendir");
119
120         while(dirent *de = readdir(dir))
121         {
122                 const char *fn = de->d_name;
123                 if(fn[0]=='.' && (fn[1]==0 || (fn[1]=='.' && fn[2]==0))) 
124                         continue;
125                 if(r_filter.match(fn))
126                         result.push_back(fn);
127         }
128         closedir(dir);
129
130         return result;
131 }
132
133 Path get_sys_conf_dir(const string &)
134 {
135         return get_sys_conf_dir();
136 }
137
138 Path get_sys_conf_dir()
139 {
140         const char *argv0 = Application::get_argv0();
141         if(!argv0)
142                 throw logic_error("no startup command");
143
144         Path dir = get_bin_dir(argv0);
145
146         if(dir[-1]=="bin" || dir[-1]=="sbin")
147         {
148                 dir /= "..";
149                 if(dir[-1]=="usr")
150                         dir /= "..";
151                 return dir/"etc";
152         }
153         else
154                 return dir;
155 }
156
157 Path get_sys_data_dir(const string &, const string &)
158 {
159         return get_sys_data_dir();
160 }
161
162 Path get_sys_data_dir()
163 {
164         const char *argv0 = Application::get_argv0();
165         if(!argv0)
166                 throw logic_error("no startup command");
167
168         Path dir = get_bin_dir(argv0);
169
170         if(dir[-1]=="bin" || dir[-1]=="sbin")
171                 return dir/".."/"share"/Application::get_name();
172         else if(dir[-1]=="MacOS")
173                 return dir/".."/"Resources";
174         else
175                 return dir;
176 }
177
178 Path get_sys_lib_dir(const string &, const string &)
179 {
180         return get_sys_lib_dir();
181 }
182
183 Path get_sys_lib_dir()
184 {
185         const char *argv0 = Application::get_argv0();
186         if(!argv0)
187                 throw logic_error("no startup command");
188
189         Path dir = get_bin_dir(argv0);
190
191         if(dir[-1]=="bin" || dir[-1]=="sbin")
192                 return dir/".."/"lib"/Application::get_name();
193         else
194                 return dir;
195 }
196
197 Path path_lookup(const string &name, const list<Path> &paths)
198 {
199         for(list<Path>::const_iterator i=paths.begin(); i!=paths.end(); ++i)
200         {
201                 Path full = *i/name;
202                 if(exists(full))
203                         return realpath(full);
204         }
205
206         return Path();
207 }
208
209 Path path_lookup(const string &name)
210 {
211         const char *path = getenv("PATH");
212         vector<string> dirs = split(path, ITEMSEP);
213         return path_lookup(name, list<Path>(dirs.begin(), dirs.end()));
214 }
215
216 } // namespace FS
217 } // namespace Msp