open_toontown_panda3d/pandatool/src/cvscopy/cvsSourceDirectory.cxx

238 lines
5.4 KiB
C++

/**
* PANDA 3D SOFTWARE
* Copyright (c) Carnegie Mellon University. All rights reserved.
*
* All use of this software is subject to the terms of the revised BSD
* license. You should have received a copy of this license along
* with this source code in a file named "LICENSE."
*
* @file cvsSourceDirectory.cxx
* @author drose
* @date 2000-10-31
*/
#include "cvsSourceDirectory.h"
#include "cvsSourceTree.h"
#include "string_utils.h"
#include "pnotify.h"
using std::string;
/**
*
*/
CVSSourceDirectory::
CVSSourceDirectory(CVSSourceTree *tree, CVSSourceDirectory *parent,
const string &dirname) :
_tree(tree),
_parent(parent),
_dirname(dirname)
{
if (_parent == nullptr) {
_depth = 0;
} else {
_depth = _parent->_depth + 1;
}
}
/**
*
*/
CVSSourceDirectory::
~CVSSourceDirectory() {
Children::iterator ci;
for (ci = _children.begin(); ci != _children.end(); ++ci) {
delete (*ci);
}
}
/**
* Returns the local name of this particular directory.
*/
string CVSSourceDirectory::
get_dirname() const {
return _dirname;
}
/**
* Returns the full pathname to this particular directory.
*/
Filename CVSSourceDirectory::
get_fullpath() const {
if (_parent == nullptr) {
return _tree->get_root_fullpath();
}
return Filename(_parent->get_fullpath(), _dirname);
}
/**
* Returns the relative pathname to this particular directory, as seen from
* the root of the tree.
*/
Filename CVSSourceDirectory::
get_path() const {
if (_parent == nullptr) {
return _dirname;
}
return Filename(_parent->get_path(), _dirname);
}
/**
* Returns the relative path to the other directory from this one. This does
* not include a trailing slash.
*/
Filename CVSSourceDirectory::
get_rel_to(const CVSSourceDirectory *other) const {
const CVSSourceDirectory *a = this;
const CVSSourceDirectory *b = other;
if (a == b) {
return ".";
}
string prefix, postfix;
while (a->_depth > b->_depth) {
prefix += "../";
a = a->_parent;
nassertr(a != nullptr, string());
}
while (b->_depth > a->_depth) {
postfix = b->_dirname + "/" + postfix;
b = b->_parent;
nassertr(b != nullptr, string());
}
while (a != b) {
prefix += "../";
postfix = b->_dirname + "/" + postfix;
a = a->_parent;
b = b->_parent;
nassertr(a != nullptr, string());
nassertr(b != nullptr, string());
}
string result = prefix + postfix;
nassertr(!result.empty(), string());
return result.substr(0, result.length() - 1);
}
/**
* Returns the number of subdirectories below this directory.
*/
int CVSSourceDirectory::
get_num_children() const {
return _children.size();
}
/**
* Returns the nth subdirectory below this directory.
*/
CVSSourceDirectory *CVSSourceDirectory::
get_child(int n) const {
nassertr(n >= 0 && n < (int)_children.size(), nullptr);
return _children[n];
}
/**
* Returns the source directory that corresponds to the given relative path
* from this directory, or NULL if there is no match.
*/
CVSSourceDirectory *CVSSourceDirectory::
find_relpath(const string &relpath) {
if (relpath.empty()) {
return this;
}
size_t slash = relpath.find('/');
string first = relpath.substr(0, slash);
string rest;
if (slash != string::npos) {
rest = relpath.substr(slash + 1);
}
if (first.empty() || first == ".") {
return find_relpath(rest);
} else if (first == "..") {
if (_parent != nullptr) {
return _parent->find_relpath(rest);
}
// Tried to back out past the root directory.
return nullptr;
}
// Check for a child with the name indicated by first.
Children::const_iterator ci;
for (ci = _children.begin(); ci != _children.end(); ++ci) {
if (cmp_nocase((*ci)->get_dirname(), first) == 0) {
return (*ci)->find_relpath(rest);
}
}
// No match.
return nullptr;
}
/**
* Returns the source directory that corresponds to the given local directory
* name, or NULL if there is no match.
*/
CVSSourceDirectory *CVSSourceDirectory::
find_dirname(const string &dirname) {
if (cmp_nocase(dirname, _dirname) == 0) {
return this;
}
Children::const_iterator ci;
for (ci = _children.begin(); ci != _children.end(); ++ci) {
CVSSourceDirectory *result = (*ci)->find_dirname(dirname);
if (result != nullptr) {
return result;
}
}
return nullptr;
}
/**
* Recursively scans the contents of the source directory. Fullpath is the
* full path name to the directory; key_filename is the name of a file that
* must exist in each subdirectory for it to be considered part of the
* hierarchy. Returns true on success, false on failure.
*/
bool CVSSourceDirectory::
scan(const Filename &directory, const string &key_filename) {
vector_string contents;
if (!directory.scan_directory(contents)) {
nout << "Unable to scan directory " << directory << "\n";
return false;
}
vector_string::const_iterator fi;
for (fi = contents.begin(); fi != contents.end(); ++fi) {
const string &basename = (*fi);
// Is this possibly a subdirectory name?
Filename next_path(directory, basename);
Filename key(next_path, key_filename);
if (key.exists()) {
CVSSourceDirectory *subdir =
new CVSSourceDirectory(_tree, this, basename);
_children.push_back(subdir);
if (!subdir->scan(next_path, key_filename)) {
return false;
}
} else {
// It's not a subdirectory; call it a regular file.
_tree->add_file(basename, this);
}
}
return true;
}