// FileName.cxx #include "dataset_util/FileName.h" #include #include #include "dataset_util/getcwd.h" using std::ostream; typedef FileName::Name Name; //********************************************************************** // Constructor. FileName::FileName(Name name) : m_name(name) { } //********************************************************************** // Validity. bool FileName::is_valid() const { if ( m_name.size() == 0 ) return false; return true; } //********************************************************************** // Is this a full path (/...)? bool FileName::is_fullpath() const { if ( ! is_valid() ) return false; return m_name[0] == delimiter(); } //********************************************************************** // Is this a relative path (.../...)? bool FileName::is_relative() const { if ( ! is_valid() ) return false; return m_name[0] != delimiter(); } //********************************************************************** // Return name with full path. FileName FileName::fullpath() const { if ( ! is_valid() ) return FileName(); if ( is_fullpath() ) { return *this; } Name newname = getcwd() + delimiter() + name(); return FileName(newname); } //********************************************************************** // Return name with no path. Name FileName::nopath_name() const { // Set position at end of string. Name::size_type ipos = m_name.size(); // Find trailing delimiter.. while ( ipos >0 && m_name[ipos-1]!=delimiter() ) --ipos; return (m_name.substr(ipos)); } //********************************************************************** // Return name of directory. Name FileName::directory_name() const { return directory().name(); } //********************************************************************** // Return name with full path. Name FileName::fullpath_name() const { return fullpath().name(); } //********************************************************************** // Return parent directory. FileName FileName::directory() const { // Set position at end of string. Name::size_type ipos = m_name.size(); // Drop trailing delimiters. while ( ipos >0 && m_name[ipos-1]==delimiter() ) --ipos; // Find the preceding delimiter. while ( ipos >0 && m_name[ipos-1]!=delimiter() ) --ipos; // Drop trailing delimiters. while ( ipos >0 && m_name[ipos-1]==delimiter() ) --ipos; if ( ipos == 0 ) { return FileName(""); } return FileName(m_name.substr(0, ipos)); } //********************************************************************** // Return the name without any symbolic links. FileName FileName::unlinked(int maxlink, bool maxerr) const { if ( ! is_valid() ) return *this; char buf[4096]; size_t bufsiz = 4096; // Check if this is a link. int nchar = readlink(m_name.c_str(), buf, bufsiz); bool linkerror = false; if ( nchar <= 0 ) { linkerror = true; int err = errno; if ( err == ENOTDIR ) linkerror = false; if ( err == ENOENT ) linkerror = false; if ( err == EINVAL ) linkerror = false; // Why is this needed? } buf[nchar] = 0; // ..error ==> return invalid name if ( linkerror ) { return FileName(""); } // This name is a symbolic link. if ( nchar > 0 ) { // Exit if the maximum # links has been exceeded. if ( maxlink <= 0 ) { if ( maxerr ) { return FileName(); } else { return *this; } } // Otherwise unlink the link name. FileName newname(buf); // If the link is relative, prepend the path. if ( newname.is_relative() && directory().is_valid() ) { newname = FileName(directory().name() + string_delimiter() + newname.name()); } return newname.unlinked(maxlink-1, maxerr); } // This name is not a symbolic link. FileName dir = directory(); // If there is no parent directory, we are done. if ( ! dir.is_valid() ) { return *this; } // Otherwise unlink the parent. FileName udir = dir.unlinked(maxlink, maxerr); if ( ! udir.is_valid() ) { return FileName(""); } return FileName(udir.name() + string_delimiter() + nopath_name()); } //********************************************************************** // Output stream. ostream& operator<<(ostream& lhs, const FileName& rhs) { if ( rhs.is_valid() ) { lhs << rhs.name(); } else { lhs << "Invalid file name"; } return lhs; } //**********************************************************************