file.h

Go to the documentation of this file.
00001 /*
00002  * file.h
00003  *
00004  * Copyright (c) 2003-2009  Thomas A. Vaughan
00005  * All rights reserved.
00006  *
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions are met:
00010  *     * Redistributions of source code must retain the above copyright
00011  *       notice, this list of conditions and the following disclaimer.
00012  *     * Redistributions in binary form must reproduce the above copyright
00013  *       notice, this list of conditions and the following disclaimer in the
00014  *       documentation and/or other materials provided with the distribution.
00015  *     * Neither the name of the <organization> nor the
00016  *       names of its contributors may be used to endorse or promote products
00017  *       derived from this software without specific prior written permission.
00018  *
00019  * THIS SOFTWARE IS PROVIDED BY THOMAS A. VAUGHAN ''AS IS'' AND ANY
00020  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00021  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00022  * DISCLAIMED. IN NO EVENT SHALL THOMAS A. VAUGHAN BE LIABLE FOR ANY
00023  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00024  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00025  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00026  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00027  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00028  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00029  *
00030  *
00031  * Helpful file/filename utilities
00032  */
00033 
00034 #ifndef WAVEPACKET_UTIL_FILE_H__
00035 #define WAVEPACKET_UTIL_FILE_H__
00036 
00037 
00038 // includes --------------------------------------------------------------------
00039 #include "common/common.h"
00040 
00041 #ifdef WIN32
00042 
00043 // win32 filesystem headers
00044 
00045 #else   // WIN32
00046 
00047 // posix filesystem headers
00048 #include <dirent.h>
00049 #include <unistd.h>
00050 #include <sys/errno.h>
00051 #include <sys/file.h>
00052 
00053 #endif  // WIN32
00054 
00055 
00056 // doxygen block
00057 
00058 /// \ingroup general
00059 /*@{*/
00060 
00061 ////////////////////////////////////////////////////////////////////////////////
00062 ///
00063 /// \defgroup util Utility Library
00064 ///
00065 /// Very low-level utility APIs and objects.  More or less a grab bag of
00066 /// parsing, file, and date-based helper methods. 
00067 ///     
00068 ////////////////////////////////////////////////////////////////////////////////
00069 /*@{*/
00070 
00071 
00072 /*
00073  * Filename APIs
00074  */
00075 
00076 
00077 // GetExtension() -- gets the extension for the specified filename.  Returns
00078 // NULL if there is no extension (no period in the name).  Can return an
00079 // empty string if the filename ends in a period.
00080 const char * GetExtension(IN const char * filename) throw();
00081 
00082 
00083 
00084 /// returns true if the given filename ends with the specified string (NOT
00085 ///     case-sensitive)
00086 bool hasExtension(IN const char * filename, IN const char * extension) throw();
00087 
00088 
00089 // GetFileRoot() -- gets the root name from the given filename (strips out
00090 // any path information, and the filename extension)
00091 void GetFileRoot(IN const char * filename,
00092                 OUT std::string& file_root);
00093 
00094 // GetParentDirectory() -- given a full path, return the parent directory
00095 // string will be empty if this is the root directory.
00096 void GetParentDirectory(IN const char * filename,
00097         OUT std::string& directory) throw();
00098 
00099 /// retrieves the highest known folder for the given file.
00100 /// returns a pointer to the beginning of the filename now relative to
00101 ///     the top directory
00102 const char * getTopDirectory(IN const char * filename,
00103                 OUT std::string& topDir);
00104 
00105 
00106 /// given a starting filename, and then a path relative to that, return
00107 ///     the full path of the file.  Examples:
00108 ///  - getPathRelativeTo("foo/bar.txt", "hi.txt") --> "foo/hi.txt"
00109 ///  - getPathRelativeTo("foo/bar.txt", "x/hi.txt") --> "foo/x/hi.txt"
00110 ///  - getPathRelativeTo("foo/bar.txt", "../hi.txt") --> "hi.txt"
00111 ///  - getPathRelativeTo("foo/models/x.model", "../textures/y.texture")
00112 ///     --> "foo/textures/y.texture"
00113 std::string getPathRelativeTo(IN const char * startFilename,
00114                                 IN const char * relFilename);
00115 
00116 
00117 /// given a starting path (directory), append another piece of the path
00118 void appendPath(IN const char * parentDirectory,
00119                                 IN const char * nextPath,
00120                                 OUT std::string& path);
00121 
00122 
00123 // GetFilename() -- given a full path, return just the tail filename
00124 const char * GetFilename(IN const char * path) throw();
00125 
00126 // getTempfile() - given a full path, return a temp file in the same directory
00127 void getTempfile(IN const char * path,
00128                 OUT std::string& tempfile) throw();
00129 
00130 // getUserHomePath() - determines the path to the user's home directory
00131 void getUserHomePath(OUT std::string& path);
00132 
00133 // ContainsWhitespace() - does this string contain whitespace?
00134 bool ContainsWhitespace(IN const char * test) throw();
00135 
00136 // doesPathExist() - does this path exist?
00137 bool doesPathExist(IN const char * path) throw();
00138 
00139 // createEmptyFileIfDoesNotExist() -- yup, creates empty file if none already there
00140 void createEmptyFileIfDoesNotExist(IN const char * path) throw();
00141 
00142 
00143 /// does a recursive directory walk, and returns all paths relative to root
00144 void walkDirectoryTree(IN const char * rootDirectory,
00145                                 IN const char * matchExtension, ///< can be null
00146                                 OUT VecString& paths);
00147 
00148 
00149 
00150 /// throws a (hopefully) descriptive error based on errno passed in
00151 #define THROW_ERROR( error , args )                                     \
00152         {                                                               \
00153                 if (error) {                                            \
00154                         char buffer[512];                               \
00155                         strerror_r(error, buffer, sizeof(buffer));      \
00156                         WAVE_EX(wex);                                   \
00157                         wex << "Encountered an error (" << error;       \
00158                         wex << "): " << buffer;                         \
00159                         wex << "\n" << args ;                           \
00160                 }                                                       \
00161         }
00162 
00163 
00164 
00165 /// smart file descriptor -- only use this for low-level objects!  You probably
00166 ///     want to use nstream or iostreams instead.
00167 class smart_fd {
00168 public:
00169         // constructor, destructor ---------------------------------------------
00170         smart_fd(void) throw() : m_fd(-1) { }
00171         smart_fd(IN int fd) throw() : m_fd(fd) { }
00172         ~smart_fd(void) throw() { this->clear(); }
00173 
00174         // accessors -----------------------------------------------------------
00175         void clear(void) throw() {
00176                         if (m_fd > -1) {
00177                                 if (close(m_fd)) {
00178                                         DPRINTF("Failed to close descriptor");
00179                                 }
00180                                 m_fd = -1;
00181                         }
00182                 }
00183 
00184         bool open(IN const char * path, IN int flags) {
00185                         this->clear();
00186                         m_fd = ::open(path, flags);
00187                         return (m_fd > -1);
00188                 }
00189 
00190         operator int(void) const throw() { return m_fd; }
00191 
00192         operator bool(void) const throw() { return (m_fd > -1); }
00193         bool operator !(void) const throw() { return (m_fd < 0); }
00194 
00195 private:
00196         // we do not want to allow copy construction--who closes?
00197         smart_fd(IN const smart_fd&);
00198 
00199         // private member data -------------------------------------------------
00200         int             m_fd;   // file descriptor
00201 };
00202 
00203 
00204 
00205 /// smart directory handle.  You probably don't want to use this!  Use the
00206 /// nstream interfaces instead.  This is for low-level filesystem access.
00207 ///
00208 /// Why no constructor that takes a path?  Because opening a directory can fail!
00209 /// Always use the open() method, and always check the result.
00210 class smart_dir {
00211 public:
00212         // constructor, destructor ---------------------------------------------
00213         smart_dir(void) throw() : m_dir(NULL) { }
00214         ~smart_dir(void) throw() { this->clear(); }
00215 
00216         // smart_dir class interface methods -----------------------------------
00217         void clear(void) throw() {
00218                         if (m_dir) {
00219                                 closedir(m_dir);
00220                                 m_dir = NULL;
00221                         }
00222                 }
00223 
00224         operator bool(void) const throw() { return !!m_dir; }
00225 
00226         void open(IN const char * path) {
00227                         this->clear();
00228                         m_dir = opendir(path);
00229                         if (!m_dir) {
00230                                 THROW_ERROR(errno,
00231                                     "Failed to open directory: " << path);
00232                         }
00233                 }
00234 
00235         void close(void) throw() { this->clear(); }
00236 
00237         bool getNextEntry(OUT struct dirent& entry) {
00238                         ASSERT(m_dir, "need to open directory first!");
00239                         struct dirent * result = NULL;
00240                         THROW_ERROR(readdir_r(m_dir, &entry, &result),
00241                             "Failed to read next directory entry");
00242                         return (result != NULL);
00243                 }
00244 
00245 private:
00246         // hidden constructors -------------------------------------------------
00247         smart_dir(IN const smart_dir&);
00248 
00249         // private member data -------------------------------------------------
00250         DIR *           m_dir;  // directory handle
00251 };
00252 
00253 
00254 
00255 /// advisory locking object
00256 /// \b WARNING: has no effect in Windows
00257 class AdvisoryLock {
00258 public:
00259         typedef int error_t;
00260 
00261         AdvisoryLock(void) throw() : m_fd(-1) { }
00262         ~AdvisoryLock(void) throw() {
00263                 this->unlock();
00264                 }
00265 
00266         bool attemptLock(IN const char * filename,
00267                         IN int operation) throw() {
00268                         ASSERT(filename, "NULL filename");
00269                         ASSERT(-1 == m_fd, "lock object already used");
00270 
00271 #ifdef WIN32
00272                         operation = operation;  // ignore parameter
00273                         m_fd = 0;
00274 #else   // WIN32
00275                         // open file descriptor
00276                         m_fd = open(filename, O_RDONLY);
00277                         if (-1 == m_fd) {
00278                                 error_t error = errno;
00279                                 DPRINTF("Could not open file: %s", filename);
00280                                 DPRINTF("Open failed with error %d : %s",
00281                                     error, strerror(error));
00282                                 return false;
00283                         }
00284 
00285                         // acquire lock
00286                         int result = flock(m_fd, operation);
00287                         if (-1 == result) {
00288                                 close(m_fd);
00289                                 m_fd = -1;
00290                                 error_t error = errno;
00291                                 DPRINTF("Lock failed with error %d : %s",
00292                                     error, strerror(error));
00293                                 return false;
00294                         }
00295 #endif  // WIN32
00296                         // success!
00297                         return true;
00298                 }
00299 
00300         void unlock(void) throw() {
00301 #ifndef WIN32
00302                         if (-1 != m_fd) {
00303                                 flock(m_fd, LOCK_UN);
00304                                 close(m_fd);
00305                                 m_fd = -1;
00306                         }
00307 #endif  // WIN32
00308                 }
00309 
00310 private:
00311         int             m_fd;   // file descriptor
00312 };
00313 
00314 
00315 /*@}*/  // end of documentation block
00316 
00317 #endif  // WAVEPACKET_UTIL_FILE_H__
00318