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.
314 lines
9.7 KiB
314 lines
9.7 KiB
|
|
/** @file |
|
|
|
$Id$ |
|
|
|
$Date$ |
|
$Author$ |
|
|
|
@copy © Marc Wäckerlin |
|
@license LGPL, see file <a href="license.html">COPYING</a> |
|
|
|
$Log$ |
|
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 <string> |
|
#include <fstream> |
|
#include <sys/types.h> |
|
#include <dirent.h> |
|
|
|
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; |
|
} |
|
}; |
|
|
|
//============================================================================ |
|
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) { |
|
dirent 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
|
|
|