Synopsis - Cross-Reference
File: /src/Support/Path-win32.cc1// 2// Copyright (C) 2004 Stefan Seefeld 3// All rights reserved. 4// Licensed to the public under the terms of the GNU LGPL (>= 2), 5// see the file COPYING for details. 6// 7 8#include "Path.hh" 9#include <vector> 10#include <stdexcept> 11#include <cerrno> 12#include <cstdio> 13#include <windows.h> 14#include <io.h> 15#include <sys/types.h> 16#include <sys/stat.h> 17#include <direct.h> 18#include <algorithm> 19 20using namespace Synopsis; 21 22const char Path::SEPARATOR = '\\'; 23 24std::string Path::cwd() 25{ 26 static std::string path; 27 if (path.empty()) 28 { 29 DWORD size; 30 if ((size = ::GetCurrentDirectoryA(0, 0)) == 0) 31 { 32 throw std::runtime_error("error accessing current working directory"); 33 } 34 char *buf = new char[size]; 35 if (::GetCurrentDirectoryA(size, buf) == 0) 36 { 37 delete [] buf; 38 throw std::runtime_error("error accessing current working directory"); 39 } 40 path = buf; 41 delete [] buf; 42 } 43 return path; 44} 45 46std::string Path::normalize(const std::string &filename) 47{ 48 std::string value = filename; 49 char separator = '\\'; 50 const char *pat1 = "\\.\\"; 51 const char *pat2 = "\\..\\"; 52 if (value[0] != separator && 53 value.size() > 2 && value[1] != ':' && value[2] != '\\') 54 value.insert(0, cwd() + separator); 55 // nothing to do... 56 if (value.find(pat1) == std::string::npos && 57 value.find(pat2) == std::string::npos) return value; 58 59 // for the rest we'll operate on a decomposition of the filename... 60 typedef std::vector<std::string> Components; 61 Components components; 62 63 std::string::size_type b = 0; 64 while (b < value.size()) 65 { 66 std::string::size_type e = value.find(separator, b); 67 components.push_back(value.substr(b, e-b)); 68 b = e == std::string::npos ? std::string::npos : e + 1; 69 } 70 71 // remove all '.' and '' components 72 components.erase(std::remove(components.begin(), components.end(), "."), components.end()); 73 components.erase(std::remove(components.begin(), components.end(), ""), components.end()); 74 // now collapse '..' components with the preceding one 75 while (true) 76 { 77 Components::iterator i = std::find(components.begin(), components.end(), ".."); 78 if (i == components.end()) break; 79 if (i == components.begin()) throw std::invalid_argument("invalid path"); 80 components.erase(i - 1, i + 1); // remove two components 81 } 82 83 // now rebuild the path as a string 84 std::string retn = '/' + components.front(); 85 for (Components::iterator i = components.begin() + 1; i != components.end(); ++i) 86 retn += '/' + *i; 87 return retn; 88} 89 90namespace Synopsis 91{ 92 93void makedirs(const Path &path) 94{ 95 const std::string &dir = path.str(); 96 if (dir.empty()) throw std::runtime_error("empty path in 'makedirs'"); 97 std::string::size_type cursor = 0; 98 while (cursor != std::string::npos) 99 { 100 cursor = dir.find(Path::SEPARATOR, cursor + 1); 101 struct stat st; 102 int error; 103 if ((error = stat(dir.substr(0, cursor).c_str(), &st)) == -1 && 104 errno == ENOENT) 105 _mkdir(dir.substr(0, cursor).c_str()); 106 else if (error) throw std::runtime_error(strerror(errno)); 107 } 108} 109 110}