2 Copyright (C) 2001-2006, William Joseph.
5 This file is part of GtkRadiant.
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 #if !defined(INCLUDED_FS_FILESYSTEM_H)
23 #define INCLUDED_FS_FILESYSTEM_H
25 #include "string/string.h"
30 inline unsigned int path_get_depth(const char* path)
32 unsigned int depth = 0;
33 while(path != 0 && path[0] != '\0')
35 path = strchr(path, '/');
45 /// \brief A generic unix-style file-system which maps paths to files and directories.
46 /// Provides average O(log n) find and insert methods.
47 /// \param file_type The data type which represents a file.
48 template<typename file_type>
49 class GenericFileSystem
56 Path(const char* path)
57 : m_path(path), m_depth(path_get_depth(c_str()))
60 Path(StringRange range)
61 : m_path(range), m_depth(path_get_depth(c_str()))
64 bool operator<(const Path& other) const
66 return string_less_nocase(c_str(), other.c_str());
68 unsigned int depth() const
72 const char* c_str() const
74 return m_path.c_str();
85 Entry(file_type* file) : m_file(file)
88 file_type* file() const
92 bool is_directory() const
98 typedef std::map<Path, Entry> Entries;
102 typedef typename Entries::iterator iterator;
103 typedef typename Entries::value_type value_type;
104 typedef Entry entry_type;
108 return m_entries.begin();
112 return m_entries.end();
115 /// \brief Returns the file at \p path.
116 /// Creates all directories below \p path if they do not exist.
117 /// O(log n) on average.
118 entry_type& operator[](const Path& path)
121 const char* end = path_remove_directory(path.c_str());
122 while(end[0] != '\0')
124 Path dir(StringRange(path.c_str(), end));
125 m_entries.insert(value_type(dir, Entry(0)));
126 end = path_remove_directory(end);
130 return m_entries[path];
133 /// \brief Returns the file at \p path or end() if not found.
134 iterator find(const Path& path)
136 return m_entries.find(path);
139 iterator begin(const char* root)
143 return m_entries.begin();
145 iterator i = m_entries.find(root);
146 if(i == m_entries.end())
153 /// \brief Performs a depth-first traversal of the file-system subtree rooted at \p root.
154 /// Traverses the entire tree if \p root is "".
155 /// Calls \p visitor.file() with the path to each file relative to the filesystem root.
156 /// Calls \p visitor.directory() with the path to each directory relative to the filesystem root.
157 template<typename visitor_type>
158 void traverse(visitor_type visitor, const char* root)
160 unsigned int start_depth = path_get_depth(root);
161 unsigned int skip_depth = 0;
162 for(iterator i = begin(root); i != end() && i->first.depth() > start_depth; ++i)
164 if(i->first.depth() == skip_depth)
170 if(!i->second.is_directory())
172 visitor.file(i->first.c_str());
174 else if(visitor.directory(i->first.c_str(), i->first.depth() - start_depth))
176 skip_depth = i->first.depth();