New grow and skid sounds from remaxim
[supertux.git] / src / file_system.cpp
index af243f8..be39082 100644 (file)
-#include <config.h>
+//  $Id$
+//
+//  SuperTux
+//  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
+//
+//  This program is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU General Public License
+//  as published by the Free Software Foundation; either version 2
+//  of the License, or (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with this program; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
-#include "file_system.h"
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <dirent.h>
-#ifndef WIN32
-#include <libgen.h>
-#endif
+#include <config.h>
 
-#include "resources.h"
+#include "log.hpp"
+#include "file_system.hpp"
 
-#ifdef WIN32
-#define mkdir(dir, mode)    mkdir(dir)
-#endif
+#include <string>
+#include <vector>
+#include <sstream>
 
 namespace FileSystem
 {
 
-/* Does the given file exist and is it accessible? */
-bool faccessible(const std::string& filename)
+std::string dirname(const std::string& filename)
 {
-  FILE* f = fopen(filename.c_str(), "r");
-  if(f == 0)
-    return false;
+  std::string::size_type p = filename.find_last_of('/');
+  if(p == std::string::npos)
+    p = filename.find_last_of('\\');
+  if(p == std::string::npos)
+    return "./";
 
-  fclose(f);
-  return true;
+  return filename.substr(0, p+1);
 }
 
-/* Can we write to this location? */
-bool fwriteable(const std::string& filename)
+std::string basename(const std::string& filename)
 {
-  FILE* f = fopen(filename.c_str(), "wa");
-  if (f == 0)
-    return false;
-  
-  fclose(f);
-  return true;
-}
+  std::string::size_type p = filename.find_last_of('/');
+  if(p == std::string::npos)
+    p = filename.find_last_of('\\');
+  if(p == std::string::npos)
+    return filename;
 
-/* Makes sure a directory is created in either the SuperTux home directory or the SuperTux base directory.*/
-bool fcreatedir(const std::string& relative_dir)
-{
-  std::string path = user_dir + "/" + relative_dir + "/";
-  if(mkdir(path.c_str(),0755) == 0)
-    return true;
-  
-  path = datadir + "/" + relative_dir + "/";
-  if(mkdir(path.c_str(),0755) == 0)
-    return true;
-    
-  return false;
+  return filename.substr(p+1, filename.size()-p-1);
 }
 
-/* Get all names of sub-directories in a certain directory. */
-/* Returns the number of sub-directories found. */
-/* Note: The user has to free the allocated space. */
-std::set<std::string> dsubdirs(const std::string &rel_path,
-    const std::string& expected_file)
+std::string strip_extension(const std::string& filename)
 {
-  DIR *dirStructP;
-  struct dirent *direntp;
-  std::set<std::string> sdirs;
-  std::string filename;
-  std::string path = user_dir + "/" + rel_path;
-
-  if((dirStructP = opendir(path.c_str())) != NULL)
-    {
-      while((direntp = readdir(dirStructP)) != NULL)
-        {
-          std::string absolute_filename;
-          struct stat buf;
-
-          absolute_filename = path + "/" + direntp->d_name;
-
-          if (stat(absolute_filename.c_str(), &buf) == 0 && S_ISDIR(buf.st_mode))
-            {
-              if(!expected_file.empty())
-                {
-                  filename = path + "/" + direntp->d_name + "/" + expected_file;
-                  if(!faccessible(filename))
-                    continue;
-                }
-
-             sdirs.insert(direntp->d_name);
-            }
-        }
-      closedir(dirStructP);
-    }
+  std::string::size_type p = filename.find_last_of('.');
+  if(p == std::string::npos)
+    return filename;
 
-  path = datadir + "/" + rel_path;
-  if((dirStructP = opendir(path.c_str())) != NULL)
-    {
-      while((direntp = readdir(dirStructP)) != NULL)
-        {
-          std::string absolute_filename;
-          struct stat buf;
-
-          absolute_filename = path + "/" + direntp->d_name;
-
-          if (stat(absolute_filename.c_str(), &buf) == 0 && S_ISDIR(buf.st_mode))
-            {
-              if(!expected_file.empty())
-                {
-                  filename = path + "/" + direntp->d_name + "/" + expected_file;
-                  if(!faccessible(filename.c_str()))
-                    {
-                      continue;
-                    }
-                  else
-                    {
-                      filename = user_dir + "/" + rel_path + "/" + direntp->d_name + "/" + expected_file;
-                      if(faccessible(filename.c_str()))
-                        continue;
-                    }
-                }
-
-             sdirs.insert(direntp->d_name);
-            }
-        }
-      closedir(dirStructP);
-    }
-
-  return sdirs;
+  return filename.substr(0, p);
 }
 
-std::set<std::string> dfiles(const std::string& rel_path,
-    const std::string& glob, const std::string& exception_str)
+std::string normalize(const std::string& filename)
 {
-  DIR *dirStructP;
-  struct dirent *direntp;
-  std::set<std::string> sdirs;
-  std::string path = user_dir + "/" + rel_path;
-
-  if((dirStructP = opendir(path.c_str())) != NULL)
-    {
-      while((direntp = readdir(dirStructP)) != NULL)
-        {
-          std::string absolute_filename;
-          struct stat buf;
-
-          absolute_filename = path + "/" + direntp->d_name;
-
-          if (stat(absolute_filename.c_str(), &buf) == 0 && S_ISREG(buf.st_mode))
-            {
-              if(!exception_str.empty())
-                {
-                  if(strstr(direntp->d_name,exception_str.c_str()) != NULL)
-                    continue;
-                }
-              if(!glob.empty())
-                if(strstr(direntp->d_name,glob.c_str()) == NULL)
-                  continue;
-
-             sdirs.insert(direntp->d_name);
-            }
-        }
-      closedir(dirStructP);
-    }
+  std::vector<std::string> path_stack;
 
-  path = datadir + "/" + rel_path;
-  if((dirStructP = opendir(path.c_str())) != NULL)
-    {
-      while((direntp = readdir(dirStructP)) != NULL)
-        {
-          std::string absolute_filename;
-          struct stat buf;
-
-          absolute_filename = path + "/" + direntp->d_name;
-
-          if (stat(absolute_filename.c_str(), &buf) == 0 && S_ISREG(buf.st_mode))
-            {
-              if(!exception_str.empty())
-                {
-                  if(strstr(direntp->d_name,exception_str.c_str()) != NULL)
-                    continue;
-                }
-              if(!glob.empty())
-                if(strstr(direntp->d_name,glob.c_str()) == NULL)
-                  continue;
-
-             sdirs.insert(direntp->d_name);
-            }
-        }
-      closedir(dirStructP);
-    }
-
-  return sdirs;
-}
+  const char* p = filename.c_str();
 
-std::string dirname(const std::string& filename)
-{
-  std::string::size_type p = filename.find_last_of('/');
-  if(p == std::string::npos)                              
-    return "";
-  
-  return filename.substr(0, p+1);
-}
+  while(true) {
+    while(*p == '/' || *p == '\\') {
+      p++;
+      continue;
+    }
 
-std::set<std::string> read_directory(const std::string& pathname)
-{
-  std::set<std::string> dirnames;
-  
-  DIR* dir = opendir(pathname.c_str());
-  if (dir)
-    {
-      struct dirent *direntp;
-      
-      while((direntp = readdir(dir)))
-        {
-          dirnames.insert(direntp->d_name);
-        }
-      
-      closedir(dir);
+    const char* pstart = p;
+    while(*p != '/' && *p != '\\' && *p != 0) {
+      ++p;
     }
 
-  return dirnames;
+    size_t len = p - pstart;
+    if(len == 0)
+      break;
+
+    std::string pathelem(pstart, p-pstart);
+    if(pathelem == ".")
+      continue;
+
+    if(pathelem == "..") {
+      if(path_stack.empty()) {
+
+        log_warning << "Invalid '..' in path '" << filename << "'" << std::endl;
+        // push it into the result path so that the user sees his error...
+        path_stack.push_back(pathelem);
+      } else {
+        path_stack.pop_back();
+      }
+    } else {
+      path_stack.push_back(pathelem);
+    }
+  }
+
+  // construct path
+  std::ostringstream result;
+  for(std::vector<std::string>::iterator i = path_stack.begin();
+      i != path_stack.end(); ++i) {
+    result << '/' << *i;
+  }
+  if(path_stack.empty())
+    result << '/';
+
+  return result.str();
 }
 
 }
-