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.
398 lines
12 KiB
398 lines
12 KiB
/** @file |
|
|
|
$Id$ |
|
|
|
$Date$ |
|
$Author$ |
|
|
|
@copy © Marc Wäckerlin |
|
@license LGPL, see file <a href="license.html">COPYING</a> |
|
|
|
$Log$ |
|
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> |
|
|
|
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() { |
|
#ifdef _DIRENT_HAVE_D_TYPE |
|
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"); |
|
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
|
|
|