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