]> git.tdb.fi Git - libs/core.git/blob - source/fs/dir.cpp
Windows uses ; as separator in $PATH
[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                 else
51                         exe = realpath(argv0);
52
53                 last_argv0 = argv0;
54                 bin_dir = dirname(exe);
55         }
56
57         return bin_dir;
58 }
59
60 }
61
62
63 not_a_directory::not_a_directory(const Path &p):
64         runtime_error(p.str())
65 { }
66
67
68 void mkpath(const Path &path, int mode)
69 {
70         Path p;
71         for(Path::Iterator i=path.begin(); i!=path.end(); ++i)
72         {
73                 p /= *i;
74 #ifdef WIN32
75                 if(p.size()==1 && p.is_absolute())
76                         continue;
77 #endif
78                 if(FS::Stat st = stat(p))
79                 {
80                         if(!st.is_directory())
81                                 throw not_a_directory(p);
82                         continue;
83                 }
84                 else
85                         mkdir(p, mode);
86         }
87 }
88
89 void rmpath(const Path &path)
90 {
91         list<string> files = list_files(path);
92         for(list<string>::iterator i=files.begin(); i!=files.end(); ++i)
93         {
94                 Path p = path / *i;
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 getcwd()
132 {
133         char buf[1024];
134         return ::getcwd(buf, sizeof(buf));
135 }
136
137 Path get_sys_conf_dir(const string &argv0)
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(const string &argv0, const string &appname)
153 {
154         Path dir = get_bin_dir(argv0);
155
156         if(dir[-1]=="bin" || dir[-1]=="sbin")
157                 return dir/".."/"share"/appname;
158         else if(dir[-1]=="MacOS")
159                 return dir/".."/"Resources";
160         else
161                 return dir;
162 }
163
164 Path get_sys_lib_dir(const string &argv0, const string &appname)
165 {
166         Path dir = get_bin_dir(argv0);
167
168         if(dir[-1]=="bin" || dir[-1]=="sbin")
169                 return dir/".."/"lib"/appname;
170         else
171                 return dir;
172 }
173
174 void chdir(const Path &path)
175 {
176         if(::chdir(path.str().c_str())==-1)
177                 throw system_error("chdir");
178 }
179
180 } // namespace FS
181 } // namespace Msp