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.

318 lines
9.8 KiB

20 years ago
/** @file
$Id$
$Date$
$Author$
@copy © Marc Wäckerlin
@license LGPL, see file <a href="license.html">COPYING</a>
$Log$
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
20 years ago
Revision 1.1 2005/01/07 00:31:38 marc
initial version
1 2 3 4 5 6 7 8
20 years ago
5678901234567890123456789012345678901234567890123456789012345678901234567890
*/
20 years ago
#ifndef __MRW_FILE_HPP__
#define __MRW_FILE_HPP__
#include <mrw/exception.hpp>
#include <string>
#include <fstream>
#include <sys/types.h>
#include <dirent.h>
20 years ago
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++.
*/
20 years ago
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;
}
};
//============================================================================
class Dir {
//............................................................... typedefs
public:
//------------------------------------------------------------------ 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.
*/
enum FileType {
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.
};
//............................................................ methods
public:
Entry(): _new(true) {}
/// Get the name of the actual file.
operator const std::string&() 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.
operator FileType() const throw() {
return FileType(_dirent.d.d_type);
}
//.......................................................... variables
private:
friend class Dir;
union { // for portability reasons, see "info readdir_r"
dirent d;
char b[offsetof (struct dirent, d_name) + NAME_MAX + 1];
} _dirent;
bool _new;
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)) return false;
if (_ignoreDots && _entry==Entry::DIR && (D==_entry() || D==_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;
20 years ago
};
//@}
20 years ago
}
#endif