Add optional lpSecurityAttributes parameter to CreateDirectory call to make compilati...
[supertux.git] / src / util / file_system.cpp
1 //  SuperTux
2 //  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
3 //
4 //  This program is free software: you can redistribute it and/or modify
5 //  it under the terms of the GNU General Public License as published by
6 //  the Free Software Foundation, either version 3 of the License, or
7 //  (at your option) any later version.
8 //
9 //  This program is distributed in the hope that it will be useful,
10 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
11 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 //  GNU General Public License for more details.
13 //
14 //  You should have received a copy of the GNU General Public License
15 //  along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
17 #include "util/log.hpp"
18
19 #include <sstream>
20 #include <stdexcept>
21 #include <sys/stat.h>
22 #include <sys/types.h>
23 #include <vector>
24
25 #ifdef _WIN32
26 #  include <shlwapi.h>
27 #else
28 #  include <unistd.h>
29 #endif
30
31 namespace FileSystem {
32
33 bool exists(const std::string& path)
34 {
35 #ifdef _WIN32
36   DWORD dwAttrib = GetFileAttributes(path.c_str());
37
38   return (dwAttrib != INVALID_FILE_ATTRIBUTES &&
39           !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
40 #else
41   return !access(path.c_str(), F_OK);
42 #endif
43 }
44
45 bool is_directory(const std::string& path)
46 {
47   struct stat info;
48
49   if (stat(path.c_str(), &info ) != 0)
50   {
51     // access error
52     return false;
53   }
54   else if (info.st_mode & S_IFDIR)
55   {
56     return true;
57   }
58   else
59   {
60     return false;
61   }
62 }
63
64 void mkdir(const std::string& directory)
65 {
66 #ifdef _WIN32
67   if (!CreateDirectory(directory.c_str(), NULL))
68   {
69     throw std::runtime_error("failed to create directory: "  + directory);
70   }
71 #else
72   if (::mkdir(directory.c_str(), 0777) != 0)
73   {
74     throw std::runtime_error("failed to create directory: "  + directory);
75   }
76 #endif
77 }
78
79 std::string dirname(const std::string& filename)
80 {
81   std::string::size_type p = filename.find_last_of('/');
82   if(p == std::string::npos)
83     p = filename.find_last_of('\\');
84   if(p == std::string::npos)
85     return "./";
86
87   return filename.substr(0, p+1);
88 }
89
90 std::string basename(const std::string& filename)
91 {
92   std::string::size_type p = filename.find_last_of('/');
93   if(p == std::string::npos)
94     p = filename.find_last_of('\\');
95   if(p == std::string::npos)
96     return filename;
97
98   return filename.substr(p+1, filename.size()-p-1);
99 }
100
101 std::string strip_extension(const std::string& filename)
102 {
103   std::string::size_type p = filename.find_last_of('.');
104   if(p == std::string::npos)
105     return filename;
106
107   return filename.substr(0, p);
108 }
109
110 std::string normalize(const std::string& filename)
111 {
112   std::vector<std::string> path_stack;
113
114   const char* p = filename.c_str();
115
116   while(true) {
117     while(*p == '/' || *p == '\\') {
118       p++;
119       continue;
120     }
121
122     const char* pstart = p;
123     while(*p != '/' && *p != '\\' && *p != 0) {
124       ++p;
125     }
126
127     size_t len = p - pstart;
128     if(len == 0)
129       break;
130
131     std::string pathelem(pstart, p-pstart);
132     if(pathelem == ".")
133       continue;
134
135     if(pathelem == "..") {
136       if(path_stack.empty()) {
137
138         log_warning << "Invalid '..' in path '" << filename << "'" << std::endl;
139         // push it into the result path so that the user sees his error...
140         path_stack.push_back(pathelem);
141       } else {
142         path_stack.pop_back();
143       }
144     } else {
145       path_stack.push_back(pathelem);
146     }
147   }
148
149   // construct path
150   std::ostringstream result;
151   for(std::vector<std::string>::iterator i = path_stack.begin();
152       i != path_stack.end(); ++i) {
153     result << '/' << *i;
154   }
155   if(path_stack.empty())
156     result << '/';
157
158   return result.str();
159 }
160
161 std::string join(const std::string& lhs, const std::string& rhs)
162 {
163   if (lhs.empty())
164   {
165     return rhs;
166   }
167   else if (lhs.back() == '/')
168   {
169     return lhs + rhs;
170   }
171   else
172   {
173     return lhs + "/" + rhs;
174   }
175 }
176
177 } // namespace FileSystem
178
179 /* EOF */