C++ Library containing a lot of needful things: Stack Trace, Command Line Parser, Resource Handling, Configuration Files, Unix Command Execution, Directories, Regular Expressions, Tokenizer, Function Trace, Standard Extensions.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

403 lines
12 KiB

/** @file
$Id$
$Date$
$Author$
@copy © Marc Wäckerlin
@license LGPL, see file <a href="license.html">COPYING</a>
$Log$
Revision 1.5 2005/03/02 22:03:08 marc
some fixes for solaris
Revision 1.4 2005/02/28 07:17:24 marc
Dir is now usable and compilable, also added fixes for Solaris
Revision 1.3 2005/02/18 15:52:20 marc
correection in documentation
Revision 1.2 2005/01/28 07:49:32 marc
Save configuration using file.hpp
Revision 1.1 2005/01/07 00:31:38 marc
initial version
1 2 3 4 5 6 7 8
5678901234567890123456789012345678901234567890123456789012345678901234567890
*/
#ifndef __MRW_FILE_HPP__
#define __MRW_FILE_HPP__
#include <mrw/exception.hpp>
#include <mrw/errno.hpp>
#include <string>
#include <fstream>
#include <sys/types.h>
#include <dirent.h>
#include <cstddef> // offsetof
#include <cstdlib> // abort
namespace mrw {
/** @defgroup sysFile File and System Utilities
@brief By now, some utilies for file handling, i.e. a copy command.
Some file and system specific utilities are missing in C++ and
often there is even no good alternative in C libraries.
*/
//@{
//============================================================================
/** @brief File handling utilities.
Utilities for file access in C++.
*/
class File {
//................................................................ methods
public:
/** @brief Copy a file.
Copy a file to a new location.
First the source file is fully read into memory, then written
to the destination. If the source file cannot be fully read,
the destination is left untouched.
@throw mrw::invalid_argument if read or write fails
@param from the source file name
@param to the destination file name
@note If the destination file already exists, it will be overwritten.
*/
static void copy(const std::string& from,
const std::string& to) throw(std::exception) {
std::ofstream os(to.c_str());
os<<read(from);
if (!os) throw mrw::invalid_argument("Cannot write file: '"+to+"'");
}
/** @brief Read a file fully into memory.
Read a file fully into memory.
@throw mrw::invalid_argument if read fails
@param filename the file to read
@return the file's contents
*/
static std::string read(const std::string& filename)
throw(std::exception) {
std::string contents; // declare on top to allow compiler optimization
std::ifstream is(filename.c_str());
std::string::size_type sz(size(is, filename));
contents.resize(sz); // make buffer long enough to store all
is.read(contents.begin().operator->(), sz); // hack to get the buffer
if (!is.good() && is.eof())
throw mrw::invalid_argument("Cannot read file: '"+filename+"'");
return contents;
};
/** @brief Save a string to a file.
A string is stored in a file, the whole file is overwritten by
the contents of the string. This is the counterpart of
read(const std::string&).
@throw mrw::invalid_argument if write fails
@param filename the name of the output file
@param contents the text to be written to the file
*/
static void save(const std::string& filename, const std::string& contents)
throw(std::exception) {
std::ofstream file(filename.c_str());
if (!(file<<contents))
throw mrw::invalid_argument("Cannot write file '"+filename+"'");
}
/** @brief Get the size of a file
Get the size of a file.
@throw mrw::invalid_argument if read fails
@param filename the file name
@return the file's size
*/
static std::string::size_type size(const std::string& filename)
throw(std::exception) {
std::ifstream is(filename.c_str());
if (!is)
throw mrw::invalid_argument("Cannot get size of file: '"
+filename+"'");
is.seekg(0, std::ios::end);
if (!is)
throw mrw::invalid_argument("Cannot get size of file: '"
+filename+"'");
return is.tellg();
}
/** @brief Get the size of a file
Get the size of a file.
@throw mrw::invalid_argument if read fails
@param file the filestream
@param filename the name of the file (required for the exception)
@return the file's size
*/
static std::string::size_type size(std::ifstream& file,
const std::string& filename = "")
throw(std::exception) {
if (!file)
throw mrw::invalid_argument("Cannot get size of file: '"
+filename+"'");
file.seekg(0, std::ios::end);
std::string::size_type sz(file.tellg());
file.seekg(0, std::ios::beg);
if (!file)
throw mrw::invalid_argument("Cannot get size of file: '"
+filename+"'");
return sz;
}
/** @brief Remove a file
Remove a file
@throw mrw::unix_error in case of failure,
i.e. if the file does not exist
@param file the file name
*/
static void remove(const std::string& file) throw(std::exception) {
if (unlink(file.c_str()))
throw mrw::unix_error("Cannot remove file "+file);
}
};
//============================================================================
/** @brief Directory access
Parse through directories:
@code
mrw::Dir dir(mrw::ifelse(getenv("HOME"), ""));
while (dir) {
std::cout<<"Found ["<<dir().typestr()<<"] "<<dir().name()<<std::endl;
}
@endcode
*/
class Dir {
//............................................................... typedefs
public:
//------------------------------------------------------------------ Entry
/** @brief a directory entry
A Directory Entry. */
class Entry {
//........................................................... typedefs
public:
/** @brief The type of the actual file.
The type of the actual file.
@note On some systems UNKNOWN is the only
value returned. This is i.e. true on
LINUX...
*/
enum FileType {
#ifdef _DIRENT_HAVE_D_TYPE
UNKNOWN = DT_UNKNOWN, ///< The type is unknown.
REGULAR = DT_REG, ///< A regular file.
DIR = DT_DIR, ///< A directory.
FIFO = DT_FIFO, ///< A named pipe, or FIFO.
SOCKET = DT_SOCK, ///< A local-domain socket.
CHAR = DT_CHR, ///< A character device.
BLOCK = DT_BLK ///< A block device.
#else
UNKNOWN, REGULAR, DIR, FIFO, SOCKET, CHAR, BLOCK // dummy
#endif
};
//............................................................ methods
public:
Entry(): _new(true) {}
/// Get the name of the actual file.
operator const std::string&() const throw(std::bad_exception) {
if (_new) { // only convert to string once
_new = false;
_name = _dirent.d.d_name;
}
return _name;
}
/// Get the name of the actual file.
const std::string& name() const throw(std::bad_exception) {
if (_new) { // only convert to string once
_new = false;
_name = _dirent.d.d_name;
}
return _name;
}
/// Get the name of the actual file.
const std::string& operator()() throw(std::bad_exception) {
return *this;
}
/// Get the type of the actual file.
FileType type() const throw() {
#ifdef _DIRENT_HAVE_D_TYPE
return FileType(_dirent.d.d_type);
#else
return UNKNOWN;
#endif
}
/// Get the type of the actual file as string.
const std::string& typestr() const throw() {
static const std::string UNKNOWN_("UNKNOWN");
static const std::string REGULAR_("REGULAR");
static const std::string DIR_("DIR");
static const std::string FIFO_("FIFO");
static const std::string SOCKET_("SOCKET");
static const std::string CHAR_("CHAR");
static const std::string BLOCK_("BLOCK");
#ifdef _DIRENT_HAVE_D_TYPE
switch (_dirent.d.d_type) {
case UNKNOWN: return UNKNOWN_;
case REGULAR: return REGULAR_;
case DIR: return DIR_;
case FIFO: return FIFO_;
case SOCKET: return SOCKET_;
case CHAR: return CHAR_;
case BLOCK: return BLOCK_;
}
abort(); // this line is never reached
#else
return UNKNOWN_;
#endif
}
//.......................................................... variables
private:
friend class Dir;
#ifdef NAME_MAX
union { // for portability reasons, see "info readdir_r"
dirent d;
char b[offsetof (struct dirent, d_name) + NAME_MAX + 1];
} _dirent;
#else
union { // for portability reasons, see "info readdir_r"
dirent d;
char b[offsetof (struct dirent, d_name) + 1000 + 1];
} _dirent;
#endif
mutable bool _new;
mutable std::string _name;
//............................................................ methods
private:
dirent& entry() throw() {
_new = true;
return _dirent.d;
}
};
//------------------------------------------------------------------------
//................................................................ methods
public:
/** @brief Open a directory for reading the file list.
Open a directory for reading the file list.
@throw mrw::invalid_argument if directory cannot be opened
@param dir name of the directory to open
@param ignoreDots ignore directories <code>.</code> and
<code>..</code> (self anf top)
*/
Dir(const std::string& dir, bool ignoreDots=true) throw(std::exception):
_ignoreDots(ignoreDots), _dir(opendir(dir.c_str())) {
if (!_dir)
throw mrw::invalid_argument("Cannot read directory: '"+dir+'\'');
}
/// Directory is closed automatically in the destructor.
~Dir() throw() {
closedir(_dir);
}
/** @brief Advance to the next directory entry.
Advance to the next directory entry.
@code
mrw::Dir dir("/home");
while (dir) ...
@endcode
@return
- @c true if an entry has been found
- @c false if there are no more entries left
@warning If you call this method again after @c false was
returned, behaviour is unspecified, but a crash
is probable.
*/
operator bool() throw() {
static const std::string D("."), DD("..");
static dirent* fake;
if (readdir_r(_dir, &_entry.entry(), &fake) || !fake) return false;
if (_ignoreDots
&& (_entry.type()==Entry::UNKNOWN || _entry.type()==Entry::DIR)
&& (D==_entry() || DD==_entry()))
return operator bool();
return true;
}
/** @brief Get the actual directory entry.
Returns the actual directory entry.
@code
mrw::Dir dir("/home");
while (dir) {
mrw::Dir::Entry entry(dir());
...
}
@endcode
@return the actual directory entry
@warning You must first call operator bool(), otherwise the
behaviour is undefined, but a crash is probable.
*/
const Entry& operator()() {
return _entry;
}
//.............................................................. variables
private:
bool _ignoreDots;
DIR* _dir;
Entry _entry;
};
//@}
}
#endif