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.
404 lines
12 KiB
404 lines
12 KiB
21 years ago
|
/** @file
|
||
|
|
||
|
$Id$
|
||
|
|
||
|
$Date$
|
||
|
$Author$
|
||
|
|
||
|
@copy © Marc Wäckerlin
|
||
|
@license LGPL, see file <a href="license.html">COPYING</a>
|
||
|
|
||
|
$Log$
|
||
20 years ago
|
Revision 1.5 2005/03/02 22:03:08 marc
|
||
|
some fixes for solaris
|
||
|
|
||
20 years ago
|
Revision 1.4 2005/02/28 07:17:24 marc
|
||
|
Dir is now usable and compilable, also added fixes for Solaris
|
||
|
|
||
20 years ago
|
Revision 1.3 2005/02/18 15:52:20 marc
|
||
|
correection in documentation
|
||
|
|
||
21 years ago
|
Revision 1.2 2005/01/28 07:49:32 marc
|
||
14 years ago
|
Save configuration using file.hxx
|
||
21 years ago
|
|
||
21 years ago
|
Revision 1.1 2005/01/07 00:31:38 marc
|
||
|
initial version
|
||
|
|
||
|
|
||
21 years ago
|
1 2 3 4 5 6 7 8
|
||
21 years ago
|
5678901234567890123456789012345678901234567890123456789012345678901234567890
|
||
21 years ago
|
*/
|
||
21 years ago
|
#ifndef __MRW_FILE_HPP__
|
||
|
#define __MRW_FILE_HPP__
|
||
|
|
||
14 years ago
|
#include <mrw/exception.hxx>
|
||
|
#include <mrw/errno.hxx>
|
||
21 years ago
|
#include <string>
|
||
|
#include <fstream>
|
||
21 years ago
|
#include <sys/types.h>
|
||
|
#include <dirent.h>
|
||
14 years ago
|
#include <cstddef> // offsetof
|
||
|
#include <cstdlib> // abort
|
||
21 years ago
|
|
||
|
namespace mrw {
|
||
21 years ago
|
|
||
|
/** @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++.
|
||
|
*/
|
||
21 years ago
|
class File {
|
||
21 years ago
|
|
||
|
//................................................................ 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;
|
||
|
}
|
||
20 years ago
|
|
||
|
/** @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);
|
||
|
}
|
||
21 years ago
|
};
|
||
|
|
||
|
//============================================================================
|
||
20 years ago
|
/** @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
|
||
|
*/
|
||
21 years ago
|
class Dir {
|
||
|
|
||
|
//............................................................... typedefs
|
||
|
public:
|
||
|
|
||
|
//------------------------------------------------------------------ Entry
|
||
20 years ago
|
/** @brief a directory entry
|
||
|
|
||
|
A Directory Entry. */
|
||
21 years ago
|
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
|
||
20 years ago
|
value returned. This is i.e. true on
|
||
|
LINUX...
|
||
21 years ago
|
*/
|
||
|
enum FileType {
|
||
20 years ago
|
#ifdef _DIRENT_HAVE_D_TYPE
|
||
21 years ago
|
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.
|
||
20 years ago
|
#else
|
||
|
UNKNOWN, REGULAR, DIR, FIFO, SOCKET, CHAR, BLOCK // dummy
|
||
|
#endif
|
||
21 years ago
|
};
|
||
|
|
||
|
//............................................................ methods
|
||
|
public:
|
||
|
|
||
|
Entry(): _new(true) {}
|
||
|
|
||
|
/// Get the name of the actual file.
|
||
20 years ago
|
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) {
|
||
21 years ago
|
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.
|
||
20 years ago
|
FileType type() const throw() {
|
||
|
#ifdef _DIRENT_HAVE_D_TYPE
|
||
21 years ago
|
return FileType(_dirent.d.d_type);
|
||
20 years ago
|
#else
|
||
20 years ago
|
return UNKNOWN;
|
||
20 years ago
|
#endif
|
||
21 years ago
|
}
|
||
|
|
||
20 years ago
|
/// 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");
|
||
20 years ago
|
#ifdef _DIRENT_HAVE_D_TYPE
|
||
20 years ago
|
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
|
||
20 years ago
|
return UNKNOWN_;
|
||
20 years ago
|
#endif
|
||
|
}
|
||
21 years ago
|
//.......................................................... variables
|
||
|
private:
|
||
|
|
||
|
friend class Dir;
|
||
|
|
||
20 years ago
|
#ifdef NAME_MAX
|
||
21 years ago
|
union { // for portability reasons, see "info readdir_r"
|
||
|
dirent d;
|
||
|
char b[offsetof (struct dirent, d_name) + NAME_MAX + 1];
|
||
|
} _dirent;
|
||
20 years ago
|
#else
|
||
|
union { // for portability reasons, see "info readdir_r"
|
||
|
dirent d;
|
||
|
char b[offsetof (struct dirent, d_name) + 1000 + 1];
|
||
|
} _dirent;
|
||
|
#endif
|
||
21 years ago
|
|
||
20 years ago
|
mutable bool _new;
|
||
|
mutable std::string _name;
|
||
21 years ago
|
|
||
|
//............................................................ 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
|
||
20 years ago
|
@param ignoreDots ignore directories <code>.</code> and
|
||
21 years ago
|
<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;
|
||
20 years ago
|
if (readdir_r(_dir, &_entry.entry(), &fake) || !fake) return false;
|
||
|
if (_ignoreDots
|
||
|
&& (_entry.type()==Entry::UNKNOWN || _entry.type()==Entry::DIR)
|
||
|
&& (D==_entry() || DD==_entry()))
|
||
21 years ago
|
return operator bool();
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/** @brief Get the actual directory entry.
|
||
|
|
||
|
Returns the actual directory entry.
|
||
|
|
||
|
@code
|
||
|
mrw::Dir dir("/home");
|
||
|
while (dir) {
|
||
20 years ago
|
mrw::Dir::Entry entry(dir());
|
||
21 years ago
|
...
|
||
|
}
|
||
|
@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;
|
||
|
|
||
21 years ago
|
};
|
||
21 years ago
|
|
||
|
//@}
|
||
21 years ago
|
}
|
||
|
|
||
|
#endif
|