]> git.tdb.fi Git - libs/core.git/blob - source/fs/dir.cpp
c0583cc5ca6fd9011065ed24d89e2d788e2cdcd8
[libs/core.git] / source / fs / dir.cpp
1 #include <cstdlib>
2 #include <unistd.h>
3 #include <dirent.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('/')==string::npos)
40                 {
41                         const char *path = getenv("PATH");
42                         vector<string> dirs = split(path, ITEMSEP);
43                         for(vector<string>::const_iterator i=dirs.begin(); i!=dirs.end(); ++i)
44                                 if(exists(Path(*i)/argv0))
45                                 {
46                                         exe = realpath(Path(*i)/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(Path::Iterator i=path.begin(); i!=path.end(); ++i)
73         {
74                 p /= *i;
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         list<string> files = list_files(path);
93         for(list<string>::iterator i=files.begin(); i!=files.end(); ++i)
94         {
95                 Path p = path / *i;
96                 if(is_dir(p))
97                         rmpath(p);
98                 else
99                         unlink(p);
100         }
101
102         rmdir(path);
103 }
104
105 list<string> list_files(const Path &path)
106 {
107         return list_filtered(path, string());
108 }
109
110 list<string> list_filtered(const Path &path, const string &filter)
111 {
112         Regex r_filter(filter);
113
114         list<string> result;
115         DIR *dir = opendir(path.str().c_str());
116         if(!dir)
117                 throw system_error("opendir");
118
119         while(dirent *de = readdir(dir))
120         {
121                 const char *fn = de->d_name;
122                 if(fn[0]=='.' && (fn[1]==0 || (fn[1]=='.' && fn[2]==0))) 
123                         continue;
124                 if(r_filter.match(fn))
125                         result.push_back(fn);
126         }
127         closedir(dir);
128
129         return result;
130 }
131
132 Path getcwd()
133 {
134         char buf[1024];
135         return ::getcwd(buf, sizeof(buf));
136 }
137
138 Path get_sys_conf_dir(const string &argv0)
139 {
140         Path dir = get_bin_dir(argv0);
141
142         if(dir[-1]=="bin" || dir[-1]=="sbin")
143         {
144                 dir /= "..";
145                 if(dir[-1]=="usr")
146                         dir /= "..";
147                 return dir/"etc";
148         }
149         else
150                 return dir;
151 }
152
153 Path get_sys_data_dir(const string &argv0, const string &appname)
154 {
155         Path dir = get_bin_dir(argv0);
156
157         if(dir[-1]=="bin" || dir[-1]=="sbin")
158                 return dir/".."/"share"/appname;
159         else if(dir[-1]=="MacOS")
160                 return dir/".."/"Resources";
161         else
162                 return dir;
163 }
164
165 Path get_sys_lib_dir(const string &argv0, const string &appname)
166 {
167         Path dir = get_bin_dir(argv0);
168
169         if(dir[-1]=="bin" || dir[-1]=="sbin")
170                 return dir/".."/"lib"/appname;
171         else
172                 return dir;
173 }
174
175 void chdir(const Path &path)
176 {
177         if(::chdir(path.str().c_str())==-1)
178                 throw system_error("chdir");
179 }
180
181 } // namespace FS
182 } // namespace Msp