/** @file
$ Id $
$ Date $
$ Author $
@ copy & copy ; Marc W & auml ; 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