]> git.tdb.fi Git - libs/core.git/blob - source/fs/dir.cpp
99de180d20ed026812e7fcb2e371dc843a0c333f
[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(DIRSEP)==string::npos)
41                         if(const char *path = getenv("PATH"))
42                         {
43                                 for(const string &d: split(path, ITEMSEP))
44                                         if(exists(Path(d)/argv0))
45                                         {
46                                                 exe = realpath(Path(d)/argv0);
47                                                 break;
48                                         }
49                         }
50
51                 if(exe.empty())
52                         exe = realpath(argv0);
53
54                 last_argv0 = argv0;
55                 bin_dir = dirname(exe);
56         }
57
58         return bin_dir;
59 }
60
61 }
62
63
64 not_a_directory::not_a_directory(const Path &p):
65         runtime_error(p.str())
66 { }
67
68
69 void mkpath(const Path &path, int mode)
70 {
71         Path p;
72         for(const string &c: path)
73         {
74                 p /= c;
75 #ifdef _WIN32
76                 if(p.size()==1 && p.is_absolute())
77                         continue;
78 #endif
79                 if(FS::Stat st = stat(p))
80                 {
81                         if(!st.is_directory())
82                                 throw not_a_directory(p);
83                         continue;
84                 }
85                 else
86                         mkdir(p, mode);
87         }
88 }
89
90 void rmpath(const Path &path)
91 {
92         for(const string &f: list_files(path))
93         {
94                 Path p = path/f;
95                 if(is_dir(p))
96                         rmpath(p);
97                 else
98                         unlink(p);
99         }
100
101         rmdir(path);
102 }
103
104 list<string> list_files(const Path &path)
105 {
106         return list_filtered(path, string());
107 }
108
109 list<string> list_filtered(const Path &path, const string &filter)
110 {
111         Regex r_filter(filter);
112
113         list<string> result;
114         DIR *dir = opendir(path.str().c_str());
115         if(!dir)
116                 throw system_error("opendir");
117
118         while(dirent *de = readdir(dir))
119         {
120                 const char *fn = de->d_name;
121                 if(fn[0]=='.' && (fn[1]==0 || (fn[1]=='.' && fn[2]==0))) 
122                         continue;
123                 if(r_filter.match(fn))
124                         result.push_back(fn);
125         }
126         closedir(dir);
127
128         return result;
129 }
130
131 Path get_sys_conf_dir()
132 {
133         const char *argv0 = Application::get_argv0();
134         if(!argv0)
135                 throw logic_error("no startup command");
136
137         Path dir = get_bin_dir(argv0);
138
139         if(dir[-1]=="bin" || dir[-1]=="sbin")
140         {
141                 dir /= "..";
142                 if(dir[-1]=="usr")
143                         dir /= "..";
144                 return dir/"etc";
145         }
146         else
147                 return dir;
148 }
149
150 Path get_sys_data_dir()
151 {
152         const char *argv0 = Application::get_argv0();
153         if(!argv0)
154                 throw logic_error("no startup command");
155
156         Path dir = get_bin_dir(argv0);
157
158         if(dir[-1]=="bin" || dir[-1]=="sbin")
159                 return dir/".."/"share"/Application::get_name();
160         else if(dir[-1]=="MacOS")
161                 return dir/".."/"Resources";
162         else
163                 return dir;
164 }
165
166 Path get_sys_lib_dir()
167 {
168         const char *argv0 = Application::get_argv0();
169         if(!argv0)
170                 throw logic_error("no startup command");
171
172         Path dir = get_bin_dir(argv0);
173
174         if(dir[-1]=="bin" || dir[-1]=="sbin")
175                 return dir/".."/"lib"/Application::get_name();
176         else
177                 return dir;
178 }
179
180 Path path_lookup(const string &name, const list<Path> &paths)
181 {
182         for(const Path &p: paths)
183         {
184                 Path full = p/name;
185                 if(exists(full))
186                         return realpath(full);
187         }
188
189         return Path();
190 }
191
192 Path path_lookup(const string &name)
193 {
194         const char *path = getenv("PATH");
195         list<string> dirs = split(path, ITEMSEP);
196         return path_lookup(name, list<Path>(dirs.begin(), dirs.end()));
197 }
198
199 } // namespace FS
200 } // namespace Msp