diff --git a/CMakeLists.txt b/CMakeLists.txt index 4fecb7e..7d98540 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -102,14 +102,6 @@ set (PACKAGE_TARNAME "${PACKAGE}") set (PACKAGE_VERSION "${VERSION}") set (PACKAGE_STRING "${PACKAGE} ${VERSION}") -message ("-- Looking for pthread") -find_package (Threads) -if (THREADS_FOUND) - set (HAVE_LIBPTHREAD true) - set (TASKD_INCLUDE_DIRS ${TASKD_INCLUDE_DIRS} ${THREADS_INCLUDE_DIR}) - set (TASKD_LIBRARIES ${TASKD_LIBRARIES} ${THREADS_LIBRARIES}) -endif (THREADS_FOUND) - # include the readline library finder module set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules") diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9daf404..d4e565a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -8,9 +8,7 @@ set (tasksh_SRCS diag.cpp prompt.cpp review.cpp Color.cpp Color.h - Path.cpp Path.h - File.cpp File.h - Directory.cpp Directory.h + FS.cpp FS.h text.cpp text.h util.cpp util.h) diff --git a/src/Directory.cpp b/src/Directory.cpp deleted file mode 100644 index af0a694..0000000 --- a/src/Directory.cpp +++ /dev/null @@ -1,241 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2006 - 2015, Paul Beckingham, Federico Hernandez. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// -// http://www.opensource.org/licenses/mit-license.php -// -//////////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined SOLARIS || defined NETBSD -#include -#endif - -//////////////////////////////////////////////////////////////////////////////// -Directory::Directory () -{ -} - -//////////////////////////////////////////////////////////////////////////////// -Directory::Directory (const Directory& other) -: File::File (other) -{ -} - -//////////////////////////////////////////////////////////////////////////////// -Directory::Directory (const File& other) -: File::File (other) -{ -} - -//////////////////////////////////////////////////////////////////////////////// -Directory::Directory (const Path& other) -: File::File (other) -{ -} - -//////////////////////////////////////////////////////////////////////////////// -Directory::Directory (const std::string& in) -: File::File (in) -{ -} - -//////////////////////////////////////////////////////////////////////////////// -Directory::~Directory () -{ -} - -//////////////////////////////////////////////////////////////////////////////// -Directory& Directory::operator= (const Directory& other) -{ - if (this != &other) - { - File::operator= (other); - } - - return *this; -} - -//////////////////////////////////////////////////////////////////////////////// -bool Directory::create (int mode /* = 0755 */) -{ - return mkdir (_data.c_str (), mode) == 0 ? true : false; -} - -//////////////////////////////////////////////////////////////////////////////// -bool Directory::remove () const -{ - return remove_directory (_data); -} - -//////////////////////////////////////////////////////////////////////////////// -bool Directory::remove_directory (const std::string& dir) const -{ - DIR* dp = opendir (dir.c_str ()); - if (dp != NULL) - { - struct dirent* de; - while ((de = readdir (dp)) != NULL) - { - if (!strcmp (de->d_name, ".") || - !strcmp (de->d_name, "..")) - continue; - -#if defined (SOLARIS) || defined (HAIKU) - struct stat s; - lstat ((dir + "/" + de->d_name).c_str (), &s); - if (S_ISDIR (s.st_mode)) - remove_directory (dir + "/" + de->d_name); - else - unlink ((dir + "/" + de->d_name).c_str ()); -#else - if (de->d_type == DT_UNKNOWN) - { - struct stat s; - lstat ((dir + "/" + de->d_name).c_str (), &s); - if (S_ISDIR (s.st_mode)) - de->d_type = DT_DIR; - } - if (de->d_type == DT_DIR) - remove_directory (dir + "/" + de->d_name); - else - unlink ((dir + "/" + de->d_name).c_str ()); -#endif - } - - closedir (dp); - } - - return rmdir (dir.c_str ()) ? false : true; -} - -//////////////////////////////////////////////////////////////////////////////// -std::vector Directory::list () -{ - std::vector files; - list (_data, files, false); - return files; -} - -//////////////////////////////////////////////////////////////////////////////// -std::vector Directory::listRecursive () -{ - std::vector files; - list (_data, files, true); - return files; -} - -//////////////////////////////////////////////////////////////////////////////// -std::string Directory::cwd () -{ -#ifdef HAVE_GET_CURRENT_DIR_NAME - char *buf = get_current_dir_name (); - if (buf == NULL) - throw std::bad_alloc (); - std::string result (buf); - free (buf); - return result; -#else - char buf[PATH_MAX]; - getcwd (buf, PATH_MAX - 1); - return std::string (buf); -#endif -} - -//////////////////////////////////////////////////////////////////////////////// -bool Directory::up () -{ - if (_data == "/") - return false; - - auto slash = _data.rfind ('/'); - if (slash == 0) - { - _data = "/"; // Root dir should retain the slash. - return true; - } - else if (slash != std::string::npos) - { - _data = _data.substr (0, slash); - return true; - } - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -bool Directory::cd () const -{ - return chdir (_data.c_str ()) == 0 ? true : false; -} - -//////////////////////////////////////////////////////////////////////////////// -void Directory::list ( - const std::string& base, - std::vector & results, - bool recursive) -{ - DIR* dp = opendir (base.c_str ()); - if (dp != NULL) - { - struct dirent* de; - while ((de = readdir (dp)) != NULL) - { - if (!strcmp (de->d_name, ".") || - !strcmp (de->d_name, "..")) - continue; - -#if defined (SOLARIS) || defined (HAIKU) - struct stat s; - stat ((base + "/" + de->d_name).c_str (), &s); - if (recursive && S_ISDIR (s.st_mode)) - list (base + "/" + de->d_name, results, recursive); - else - results.push_back (base + "/" + de->d_name); -#else - if (recursive && de->d_type == DT_UNKNOWN) - { - struct stat s; - lstat ((base + "/" + de->d_name).c_str (), &s); - if (S_ISDIR (s.st_mode)) - de->d_type = DT_DIR; - } - if (recursive && de->d_type == DT_DIR) - list (base + "/" + de->d_name, results, recursive); - else - results.push_back (base + "/" + de->d_name); -#endif - } - - closedir (dp); - } -} - -//////////////////////////////////////////////////////////////////////////////// diff --git a/src/Directory.h b/src/Directory.h deleted file mode 100644 index aef7d5e..0000000 --- a/src/Directory.h +++ /dev/null @@ -1,60 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2006 - 2015, Paul Beckingham, Federico Hernandez. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// -// http://www.opensource.org/licenses/mit-license.php -// -//////////////////////////////////////////////////////////////////////////////// - -#ifndef INCLUDED_DIRECTORY -#define INCLUDED_DIRECTORY - -#include - -class Directory : public File -{ -public: - Directory (); - Directory (const Directory&); - Directory (const File&); - Directory (const Path&); - Directory (const std::string&); - virtual ~Directory (); - - Directory& operator= (const Directory&); - - virtual bool create (int mode = 0755); - virtual bool remove () const; - - std::vector list (); - std::vector listRecursive (); - - static std::string cwd (); - bool up (); - bool cd () const; - -private: - void list (const std::string&, std::vector &, bool); - bool remove_directory (const std::string&) const; -}; - -#endif -//////////////////////////////////////////////////////////////////////////////// diff --git a/src/FS.cpp b/src/FS.cpp new file mode 100644 index 0000000..6782b9d --- /dev/null +++ b/src/FS.cpp @@ -0,0 +1,990 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Copyright 2006 - 2015, Paul Beckingham, Federico Hernandez. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +// http://www.opensource.org/licenses/mit-license.php +// +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined SOLARIS || defined NETBSD || defined FREEBSD +#include +#endif + +// Fixes build with musl libc. +#ifndef GLOB_TILDE +#define GLOB_TILDE 0 +#endif + +#ifndef GLOB_BRACE +#define GLOB_BRACE 0 +#endif + +//////////////////////////////////////////////////////////////////////////////// +std::ostream& operator<< (std::ostream& out, const Path& path) +{ + out << path._data; + return out; +} + +//////////////////////////////////////////////////////////////////////////////// +Path::Path () +{ +} + +//////////////////////////////////////////////////////////////////////////////// +Path::Path (const Path& other) +{ + if (this != &other) + { + _original = other._original; + _data = other._data; + } +} + +//////////////////////////////////////////////////////////////////////////////// +Path::Path (const std::string& in) +{ + _original = in; + _data = expand (in); +} + +//////////////////////////////////////////////////////////////////////////////// +Path::~Path () +{ +} + +//////////////////////////////////////////////////////////////////////////////// +Path& Path::operator= (const Path& other) +{ + if (this != &other) + { + this->_original = other._original; + this->_data = other._data; + } + + return *this; +} + +//////////////////////////////////////////////////////////////////////////////// +bool Path::operator== (const Path& other) +{ + return _data == other._data; +} + +//////////////////////////////////////////////////////////////////////////////// +Path& Path::operator+= (const std::string& dir) +{ + _data += "/" + dir; + return *this; +} + +//////////////////////////////////////////////////////////////////////////////// +Path::operator std::string () const +{ + return _data; +} + +//////////////////////////////////////////////////////////////////////////////// +std::string Path::name () const +{ + if (_data.length ()) + { + auto slash = _data.rfind ('/'); + if (slash != std::string::npos) + return _data.substr (slash + 1, std::string::npos); + } + + return _data; +} + +//////////////////////////////////////////////////////////////////////////////// +std::string Path::parent () const +{ + if (_data.length ()) + { + auto slash = _data.rfind ('/'); + if (slash != std::string::npos) + return _data.substr (0, slash); + } + + return ""; +} + +//////////////////////////////////////////////////////////////////////////////// +std::string Path::extension () const +{ + if (_data.length ()) + { + auto dot = _data.rfind ('.'); + if (dot != std::string::npos) + return _data.substr (dot + 1, std::string::npos); + } + + return ""; +} + +//////////////////////////////////////////////////////////////////////////////// +bool Path::exists () const +{ + return access (_data.c_str (), F_OK) ? false : true; +} + +//////////////////////////////////////////////////////////////////////////////// +bool Path::is_directory () const +{ + struct stat s = {0}; + if (! stat (_data.c_str (), &s) && + S_ISDIR (s.st_mode)) + return true; + + return false; +} + +//////////////////////////////////////////////////////////////////////////////// +bool Path::is_absolute () const +{ + if (_data.length () && _data[0] == '/') + return true; + + return false; +} + +//////////////////////////////////////////////////////////////////////////////// +bool Path::is_link () const +{ + struct stat s = {0}; + if (! lstat (_data.c_str (), &s) && + S_ISLNK (s.st_mode)) + return true; + + return false; +} + +//////////////////////////////////////////////////////////////////////////////// +bool Path::readable () const +{ + return access (_data.c_str (), R_OK) ? false : true; +} + +//////////////////////////////////////////////////////////////////////////////// +bool Path::writable () const +{ + return access (_data.c_str (), W_OK) ? false : true; +} + +//////////////////////////////////////////////////////////////////////////////// +bool Path::executable () const +{ + return access (_data.c_str (), X_OK) ? false : true; +} + +//////////////////////////////////////////////////////////////////////////////// +bool Path::rename (const std::string& new_name) +{ + std::string expanded = expand (new_name); + if (_data != expanded) + { + if (::rename (_data.c_str (), expanded.c_str ()) == 0) + { + _data = expanded; + return true; + } + } + + return false; +} + +//////////////////////////////////////////////////////////////////////////////// +// ~ --> /home/user +// ~foo/x --> /home/foo/s +// ~/x --> /home/foo/x +// ./x --> $PWD/x +// x --> $PWD/x +std::string Path::expand (const std::string& in) +{ + std::string copy = in; + + auto tilde = copy.find ("~"); + std::string::size_type slash; + + if (tilde != std::string::npos) + { + const char *home = getenv("HOME"); + if (home == NULL) + { + struct passwd* pw = getpwuid (getuid ()); + home = pw->pw_dir; + } + + // Convert: ~ --> /home/user + if (copy.length () == 1) + copy = home; + + // Convert: ~/x --> /home/user/x + else if (copy.length () > tilde + 1 && + copy[tilde + 1] == '/') + { + copy.replace (tilde, 1, home); + } + + // Convert: ~foo/x --> /home/foo/x + else if ((slash = copy.find ("/", tilde)) != std::string::npos) + { + std::string name = copy.substr (tilde + 1, slash - tilde - 1); + struct passwd* pw = getpwnam (name.c_str ()); + if (pw) + copy.replace (tilde, slash - tilde, pw->pw_dir); + } + } + + // Relative paths + else if (in.length () > 2 && + in.substr (0, 2) == "./") + { + copy = Directory::cwd () + "/" + in.substr (2); + } + else if (in.length () > 1 && + in[0] != '.' && + in[0] != '/') + { + copy = Directory::cwd () + "/" + in; + } + + return copy; +} + +//////////////////////////////////////////////////////////////////////////////// +std::vector Path::glob (const std::string& pattern) +{ + std::vector results; + + glob_t g; +#ifdef SOLARIS + if (!::glob (pattern.c_str (), GLOB_ERR, NULL, &g)) +#else + if (!::glob (pattern.c_str (), GLOB_ERR | GLOB_BRACE | GLOB_TILDE, NULL, &g)) +#endif + for (int i = 0; i < (int) g.gl_pathc; ++i) + results.push_back (g.gl_pathv[i]); + + globfree (&g); + return results; +} + +//////////////////////////////////////////////////////////////////////////////// +File::File () +: Path::Path () +, _fh (NULL) +, _h (-1) +, _locked (false) +{ +} + +//////////////////////////////////////////////////////////////////////////////// +File::File (const Path& other) +: Path::Path (other) +, _fh (NULL) +, _h (-1) +, _locked (false) +{ +} + +//////////////////////////////////////////////////////////////////////////////// +File::File (const File& other) +: Path::Path (other) +, _fh (NULL) +, _h (-1) +, _locked (false) +{ +} + +//////////////////////////////////////////////////////////////////////////////// +File::File (const std::string& in) +: Path::Path (in) +, _fh (NULL) +, _h (-1) +, _locked (false) +{ +} + +//////////////////////////////////////////////////////////////////////////////// +File::~File () +{ + if (_fh) + close (); +} + +//////////////////////////////////////////////////////////////////////////////// +File& File::operator= (const File& other) +{ + if (this != &other) + Path::operator= (other); + + _locked = false; + return *this; +} + +//////////////////////////////////////////////////////////////////////////////// +bool File::create (int mode /* = 0640 */) +{ + if (open ()) + { + fchmod (_h, mode); + close (); + return true; + } + + return false; +} + +//////////////////////////////////////////////////////////////////////////////// +bool File::remove () const +{ + return unlink (_data.c_str ()) == 0 ? true : false; +} + +//////////////////////////////////////////////////////////////////////////////// +bool File::open () +{ + if (_data != "") + { + if (! _fh) + { + bool already_exists = exists (); + if (already_exists) + if (!readable () || !writable ()) + throw std::string (format ("Missing permissions for '{1}'", _data)); + + _fh = fopen (_data.c_str (), (already_exists ? "r+" : "w+")); + if (_fh) + { + _h = fileno (_fh); + _locked = false; + return true; + } + } + else + return true; + } + + return false; +} + +//////////////////////////////////////////////////////////////////////////////// +bool File::openAndLock () +{ + return open () && lock (); +} + +//////////////////////////////////////////////////////////////////////////////// +void File::close () +{ + if (_fh) + { + if (_locked) + unlock (); + + fclose (_fh); + _fh = NULL; + _h = -1; + _locked = false; + } +} + +//////////////////////////////////////////////////////////////////////////////// +bool File::lock () +{ + _locked = false; + if (_fh && _h != -1) + { + // l_type l_whence l_start l_len l_pid + struct flock fl = {F_WRLCK, SEEK_SET, 0, 0, 0 }; + fl.l_pid = getpid (); + if (fcntl (_h, F_SETLKW, &fl) == 0) + _locked = true; + } + + return _locked; +} + +//////////////////////////////////////////////////////////////////////////////// +void File::unlock () +{ + if (_locked) + { + // l_type l_whence l_start l_len l_pid + struct flock fl = {F_UNLCK, SEEK_SET, 0, 0, 0 }; + fl.l_pid = getpid (); + + fcntl (_h, F_SETLK, &fl); + _locked = false; + } +} + +//////////////////////////////////////////////////////////////////////////////// +// Opens if necessary. +void File::read (std::string& contents) +{ + contents = ""; + contents.reserve (size ()); + + std::ifstream in (_data.c_str ()); + if (in.good ()) + { + std::string line; + line.reserve (512 * 1024); + while (getline (in, line)) + contents += line + "\n"; + + in.close (); + } +} + +//////////////////////////////////////////////////////////////////////////////// +// Opens if necessary. +void File::read (std::vector & contents) +{ + contents.clear (); + + std::ifstream in (_data.c_str ()); + if (in.good ()) + { + std::string line; + line.reserve (512 * 1024); + while (getline (in, line)) + contents.push_back (line); + + in.close (); + } +} + +//////////////////////////////////////////////////////////////////////////////// +// Opens if necessary. +void File::write (const std::string& line) +{ + if (!_fh) + open (); + + if (_fh) + fputs (line.c_str (), _fh); +} + +//////////////////////////////////////////////////////////////////////////////// +// Opens if necessary. +void File::write (const std::vector & lines) +{ + if (!_fh) + open (); + + if (_fh) + { + for (auto& line : lines) + fputs (line.c_str (), _fh); + } +} + +//////////////////////////////////////////////////////////////////////////////// +// Opens if necessary. +void File::append (const std::string& line) +{ + if (!_fh) + open (); + + if (_fh) + { + fseek (_fh, 0, SEEK_END); + fputs (line.c_str (), _fh); + } +} + +//////////////////////////////////////////////////////////////////////////////// +// Opens if necessary. +void File::append (const std::vector & lines) +{ + if (!_fh) + open (); + + if (_fh) + { + fseek (_fh, 0, SEEK_END); + for (auto& line : lines) + fputs ((line + "\n").c_str (), _fh); + } +} + +//////////////////////////////////////////////////////////////////////////////// +void File::truncate () +{ + if (!_fh) + open (); + + if (_fh) + ftruncate (_h, 0); +} + +//////////////////////////////////////////////////////////////////////////////// +// S_IFMT 0170000 type of file +// S_IFIFO 0010000 named pipe (fifo) +// S_IFCHR 0020000 character special +// S_IFDIR 0040000 directory +// S_IFBLK 0060000 block special +// S_IFREG 0100000 regular +// S_IFLNK 0120000 symbolic link +// S_IFSOCK 0140000 socket +// S_IFWHT 0160000 whiteout +// S_ISUID 0004000 set user id on execution +// S_ISGID 0002000 set group id on execution +// S_ISVTX 0001000 save swapped text even after use +// S_IRUSR 0000400 read permission, owner +// S_IWUSR 0000200 write permission, owner +// S_IXUSR 0000100 execute/search permission, owner +mode_t File::mode () +{ + struct stat s; + if (!stat (_data.c_str (), &s)) + return s.st_mode; + + return 0; +} + +//////////////////////////////////////////////////////////////////////////////// +size_t File::size () const +{ + struct stat s; + if (!stat (_data.c_str (), &s)) + return s.st_size; + + return 0; +} + +//////////////////////////////////////////////////////////////////////////////// +time_t File::mtime () const +{ + struct stat s; + if (!stat (_data.c_str (), &s)) + return s.st_mtime; + + return 0; +} + +//////////////////////////////////////////////////////////////////////////////// +time_t File::ctime () const +{ + struct stat s; + if (!stat (_data.c_str (), &s)) + return s.st_ctime; + + return 0; +} + +//////////////////////////////////////////////////////////////////////////////// +time_t File::btime () const +{ + struct stat s; + if (!stat (_data.c_str (), &s)) +#ifdef HAVE_ST_BIRTHTIME + return s.st_birthtime; +#else + return s.st_ctime; +#endif + + return 0; +} + +//////////////////////////////////////////////////////////////////////////////// +bool File::create (const std::string& name, int mode /* = 0640 */) +{ + std::string full_name = expand (name); + std::ofstream out (full_name.c_str ()); + if (out.good ()) + { + out.close (); + chmod (full_name.c_str (), mode); + return true; + } + + return false; +} + +//////////////////////////////////////////////////////////////////////////////// +std::string File::read (const std::string& name) +{ + std::string contents = ""; + + std::ifstream in (name.c_str ()); + if (in.good ()) + { + std::string line; + line.reserve (1024); + while (getline (in, line)) + contents += line + "\n"; + + in.close (); + } + + return contents; +} + +//////////////////////////////////////////////////////////////////////////////// +bool File::read (const std::string& name, std::string& contents) +{ + contents = ""; + + std::ifstream in (name.c_str ()); + if (in.good ()) + { + std::string line; + line.reserve (1024); + while (getline (in, line)) + contents += line + "\n"; + + in.close (); + return true; + } + + return false; +} + +//////////////////////////////////////////////////////////////////////////////// +bool File::read (const std::string& name, std::vector & contents) +{ + contents.clear (); + + std::ifstream in (name.c_str ()); + if (in.good ()) + { + std::string line; + line.reserve (1024); + while (getline (in, line)) + contents.push_back (line); + + in.close (); + return true; + } + + return false; +} + +//////////////////////////////////////////////////////////////////////////////// +bool File::write (const std::string& name, const std::string& contents) +{ + std::ofstream out (expand (name).c_str (), + std::ios_base::out | std::ios_base::trunc); + if (out.good ()) + { + out << contents; + out.close (); + return true; + } + + return false; +} + +//////////////////////////////////////////////////////////////////////////////// +bool File::write ( + const std::string& name, + const std::vector & lines, + bool addNewlines /* = true */) +{ + std::ofstream out (expand (name).c_str (), + std::ios_base::out | std::ios_base::trunc); + if (out.good ()) + { + for (auto& line : lines) + { + out << line; + + if (addNewlines) + out << "\n"; + } + + out.close (); + return true; + } + + return false; +} + +//////////////////////////////////////////////////////////////////////////////// +bool File::append (const std::string& name, const std::string& contents) +{ + std::ofstream out (expand (name).c_str (), + std::ios_base::out | std::ios_base::app); + if (out.good ()) + { + out << contents; + out.close (); + return true; + } + + return false; +} + +//////////////////////////////////////////////////////////////////////////////// +bool File::append ( + const std::string& name, + const std::vector & lines, + bool addNewlines /* = true */) +{ + std::ofstream out (expand (name).c_str (), + std::ios_base::out | std::ios_base::app); + if (out.good ()) + { + for (auto& line : lines) + { + out << line; + + if (addNewlines) + out << "\n"; + } + + out.close (); + return true; + } + + return false; +} + +//////////////////////////////////////////////////////////////////////////////// +bool File::remove (const std::string& name) +{ + return unlink (expand (name).c_str ()) == 0 ? true : false; +} + +//////////////////////////////////////////////////////////////////////////////// +Directory::Directory () +{ +} + +//////////////////////////////////////////////////////////////////////////////// +Directory::Directory (const Directory& other) +: File::File (other) +{ +} + +//////////////////////////////////////////////////////////////////////////////// +Directory::Directory (const File& other) +: File::File (other) +{ +} + +//////////////////////////////////////////////////////////////////////////////// +Directory::Directory (const Path& other) +: File::File (other) +{ +} + +//////////////////////////////////////////////////////////////////////////////// +Directory::Directory (const std::string& in) +: File::File (in) +{ +} + +//////////////////////////////////////////////////////////////////////////////// +Directory::~Directory () +{ +} + +//////////////////////////////////////////////////////////////////////////////// +Directory& Directory::operator= (const Directory& other) +{ + if (this != &other) + { + File::operator= (other); + } + + return *this; +} + +//////////////////////////////////////////////////////////////////////////////// +bool Directory::create (int mode /* = 0755 */) +{ + return mkdir (_data.c_str (), mode) == 0 ? true : false; +} + +//////////////////////////////////////////////////////////////////////////////// +bool Directory::remove () const +{ + return remove_directory (_data); +} + +//////////////////////////////////////////////////////////////////////////////// +bool Directory::remove_directory (const std::string& dir) const +{ + DIR* dp = opendir (dir.c_str ()); + if (dp != NULL) + { + struct dirent* de; + while ((de = readdir (dp)) != NULL) + { + if (!strcmp (de->d_name, ".") || + !strcmp (de->d_name, "..")) + continue; + +#if defined (SOLARIS) || defined (HAIKU) + struct stat s; + lstat ((dir + "/" + de->d_name).c_str (), &s); + if (S_ISDIR (s.st_mode)) + remove_directory (dir + "/" + de->d_name); + else + unlink ((dir + "/" + de->d_name).c_str ()); +#else + if (de->d_type == DT_UNKNOWN) + { + struct stat s; + lstat ((dir + "/" + de->d_name).c_str (), &s); + if (S_ISDIR (s.st_mode)) + de->d_type = DT_DIR; + } + if (de->d_type == DT_DIR) + remove_directory (dir + "/" + de->d_name); + else + unlink ((dir + "/" + de->d_name).c_str ()); +#endif + } + + closedir (dp); + } + + return rmdir (dir.c_str ()) ? false : true; +} + +//////////////////////////////////////////////////////////////////////////////// +std::vector Directory::list () +{ + std::vector files; + list (_data, files, false); + return files; +} + +//////////////////////////////////////////////////////////////////////////////// +std::vector Directory::listRecursive () +{ + std::vector files; + list (_data, files, true); + return files; +} + +//////////////////////////////////////////////////////////////////////////////// +std::string Directory::cwd () +{ +#ifdef HAVE_GET_CURRENT_DIR_NAME + char *buf = get_current_dir_name (); + if (buf == NULL) + throw std::bad_alloc (); + std::string result (buf); + free (buf); + return result; +#else + char buf[PATH_MAX]; + getcwd (buf, PATH_MAX - 1); + return std::string (buf); +#endif +} + +//////////////////////////////////////////////////////////////////////////////// +bool Directory::up () +{ + if (_data == "/") + return false; + + auto slash = _data.rfind ('/'); + if (slash == 0) + { + _data = "/"; // Root dir should retain the slash. + return true; + } + else if (slash != std::string::npos) + { + _data = _data.substr (0, slash); + return true; + } + + return false; +} + +//////////////////////////////////////////////////////////////////////////////// +bool Directory::cd () const +{ + return chdir (_data.c_str ()) == 0 ? true : false; +} + +//////////////////////////////////////////////////////////////////////////////// +void Directory::list ( + const std::string& base, + std::vector & results, + bool recursive) +{ + DIR* dp = opendir (base.c_str ()); + if (dp != NULL) + { + struct dirent* de; + while ((de = readdir (dp)) != NULL) + { + if (!strcmp (de->d_name, ".") || + !strcmp (de->d_name, "..")) + continue; + +#if defined (SOLARIS) || defined (HAIKU) + struct stat s; + stat ((base + "/" + de->d_name).c_str (), &s); + if (recursive && S_ISDIR (s.st_mode)) + list (base + "/" + de->d_name, results, recursive); + else + results.push_back (base + "/" + de->d_name); +#else + if (recursive && de->d_type == DT_UNKNOWN) + { + struct stat s; + lstat ((base + "/" + de->d_name).c_str (), &s); + if (S_ISDIR (s.st_mode)) + de->d_type = DT_DIR; + } + if (recursive && de->d_type == DT_DIR) + list (base + "/" + de->d_name, results, recursive); + else + results.push_back (base + "/" + de->d_name); +#endif + } + + closedir (dp); + } +} + +//////////////////////////////////////////////////////////////////////////////// diff --git a/src/File.h b/src/FS.h similarity index 66% rename from src/File.h rename to src/FS.h index a3d1df7..d44df7e 100644 --- a/src/File.h +++ b/src/FS.h @@ -24,14 +24,47 @@ // //////////////////////////////////////////////////////////////////////////////// -#ifndef INCLUDED_FILE -#define INCLUDED_FILE +#ifndef INCLUDED_FS +#define INCLUDED_FS #include #include #include #include -#include + +class Path +{ +public: + Path (); + Path (const Path&); + Path (const std::string&); + virtual ~Path (); + + Path& operator= (const Path&); + bool operator== (const Path&); + Path& operator+= (const std::string&); + operator std::string () const; + + std::string name () const; + std::string parent () const; + std::string extension () const; + bool exists () const; + bool is_directory () const; + bool is_absolute () const; + bool is_link () const; + bool readable () const; + bool writable () const; + bool executable () const; + bool rename (const std::string&); + + // Statics + static std::string expand (const std::string&); + static std::vector glob (const std::string&); + +public: + std::string _original; + std::string _data; +}; class File : public Path { @@ -52,7 +85,7 @@ public: void close (); bool lock (); - bool waitForLock (); + void unlock (); void read (std::string&); void read (std::vector &); @@ -87,5 +120,35 @@ private: bool _locked; }; +class Directory : public File +{ +public: + Directory (); + Directory (const Directory&); + Directory (const File&); + Directory (const Path&); + Directory (const std::string&); + virtual ~Directory (); + + Directory& operator= (const Directory&); + + virtual bool create (int mode = 0755); + virtual bool remove () const; + + std::vector list (); + std::vector listRecursive (); + + static std::string cwd (); + bool up (); + bool cd () const; + +private: + void list (const std::string&, std::vector &, bool); + bool remove_directory (const std::string&) const; +}; + +std::ostream& operator<< (std::ostream&, const Path&); + #endif //////////////////////////////////////////////////////////////////////////////// + diff --git a/src/File.cpp b/src/File.cpp deleted file mode 100644 index eef8244..0000000 --- a/src/File.cpp +++ /dev/null @@ -1,532 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2006 - 2015, Paul Beckingham, Federico Hernandez. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// -// http://www.opensource.org/licenses/mit-license.php -// -//////////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include -#ifdef SOLARIS -#include // for flock() replacement -#include // for memset() -#else -#include -#endif -#include -#include -#include -#include -#include - -//////////////////////////////////////////////////////////////////////////////// -File::File () -: Path::Path () -, _fh (NULL) -, _h (-1) -, _locked (false) -{ -} - -//////////////////////////////////////////////////////////////////////////////// -File::File (const Path& other) -: Path::Path (other) -, _fh (NULL) -, _h (-1) -, _locked (false) -{ -} - -//////////////////////////////////////////////////////////////////////////////// -File::File (const File& other) -: Path::Path (other) -, _fh (NULL) -, _h (-1) -, _locked (false) -{ -} - -//////////////////////////////////////////////////////////////////////////////// -File::File (const std::string& in) -: Path::Path (in) -, _fh (NULL) -, _h (-1) -, _locked (false) -{ -} - -//////////////////////////////////////////////////////////////////////////////// -File::~File () -{ - if (_fh) - close (); -} - -//////////////////////////////////////////////////////////////////////////////// -File& File::operator= (const File& other) -{ - if (this != &other) - Path::operator= (other); - - _locked = false; - return *this; -} - -//////////////////////////////////////////////////////////////////////////////// -bool File::create (int mode /* = 0640 */) -{ - if (open ()) - { - fchmod (_h, mode); - close (); - return true; - } - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -bool File::remove () const -{ - return unlink (_data.c_str ()) == 0 ? true : false; -} - -//////////////////////////////////////////////////////////////////////////////// -bool File::open () -{ - if (_data != "") - { - if (! _fh) - { - bool already_exists = exists (); - if (already_exists) - if (!readable () || !writable ()) - throw std::string (format (STRING_FILE_PERMS, _data)); - - _fh = fopen (_data.c_str (), (already_exists ? "r+" : "w+")); - if (_fh) - { - _h = fileno (_fh); - _locked = false; - return true; - } - } - else - return true; - } - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -bool File::openAndLock () -{ - return open () && lock (); -} - -//////////////////////////////////////////////////////////////////////////////// -void File::close () -{ - if (_fh) - { - fclose (_fh); - _fh = NULL; - _h = -1; - _locked = false; - } -} - -//////////////////////////////////////////////////////////////////////////////// -bool File::lock () -{ - if (_fh && _h != -1) - { - // Try three times before failing. - int retry = 0; - while (flock (_h, LOCK_NB | LOCK_EX) && ++retry <= 3) - ; - - if (retry <= 3) - { - _locked = true; - return true; - } - } - - _locked = false; - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -bool File::waitForLock () -{ - if (_locked) - return true; - - if (_fh && _h != -1) - if (flock (_h, LOCK_EX) == 0) - { - _locked = true; - return true; - } - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -// Opens if necessary. -void File::read (std::string& contents) -{ - contents = ""; - contents.reserve (size ()); - - std::ifstream in (_data.c_str ()); - if (in.good ()) - { - std::string line; - line.reserve (512 * 1024); - while (getline (in, line)) - contents += line + "\n"; - - in.close (); - } -} - -//////////////////////////////////////////////////////////////////////////////// -// Opens if necessary. -void File::read (std::vector & contents) -{ - contents.clear (); - - std::ifstream in (_data.c_str ()); - if (in.good ()) - { - std::string line; - line.reserve (512 * 1024); - while (getline (in, line)) - contents.push_back (line); - - in.close (); - } -} - -//////////////////////////////////////////////////////////////////////////////// -// Opens if necessary. -void File::write (const std::string& line) -{ - if (!_fh) - open (); - - if (_fh) - fputs (line.c_str (), _fh); -} - -//////////////////////////////////////////////////////////////////////////////// -// Opens if necessary. -void File::write (const std::vector & lines) -{ - if (!_fh) - open (); - - if (_fh) - { - std::vector ::const_iterator it; - for (it = lines.begin (); it != lines.end (); ++it) - fputs (it->c_str (), _fh); - } -} - -//////////////////////////////////////////////////////////////////////////////// -// Opens if necessary. -void File::append (const std::string& line) -{ - if (!_fh) - open (); - - if (_fh) - { - fseek (_fh, 0, SEEK_END); - fputs (line.c_str (), _fh); - } -} - -//////////////////////////////////////////////////////////////////////////////// -// Opens if necessary. -void File::append (const std::vector & lines) -{ - if (!_fh) - open (); - - if (_fh) - { - fseek (_fh, 0, SEEK_END); - std::vector ::const_iterator it; - for (it = lines.begin (); it != lines.end (); ++it) - fputs (((*it) + "\n").c_str (), _fh); - } -} - -//////////////////////////////////////////////////////////////////////////////// -void File::truncate () -{ - if (!_fh) - open (); - - if (_fh) - ftruncate (_h, 0); -} - -//////////////////////////////////////////////////////////////////////////////// -// S_IFMT 0170000 type of file -// S_IFIFO 0010000 named pipe (fifo) -// S_IFCHR 0020000 character special -// S_IFDIR 0040000 directory -// S_IFBLK 0060000 block special -// S_IFREG 0100000 regular -// S_IFLNK 0120000 symbolic link -// S_IFSOCK 0140000 socket -// S_IFWHT 0160000 whiteout -// S_ISUID 0004000 set user id on execution -// S_ISGID 0002000 set group id on execution -// S_ISVTX 0001000 save swapped text even after use -// S_IRUSR 0000400 read permission, owner -// S_IWUSR 0000200 write permission, owner -// S_IXUSR 0000100 execute/search permission, owner -mode_t File::mode () -{ - struct stat s; - if (!stat (_data.c_str (), &s)) - return s.st_mode; - - return 0; -} - -//////////////////////////////////////////////////////////////////////////////// -size_t File::size () const -{ - struct stat s; - if (!stat (_data.c_str (), &s)) - return s.st_size; - - return 0; -} - -//////////////////////////////////////////////////////////////////////////////// -time_t File::mtime () const -{ - struct stat s; - if (!stat (_data.c_str (), &s)) - return s.st_mtime; - - return 0; -} - -//////////////////////////////////////////////////////////////////////////////// -time_t File::ctime () const -{ - struct stat s; - if (!stat (_data.c_str (), &s)) - return s.st_ctime; - - return 0; -} - -//////////////////////////////////////////////////////////////////////////////// -time_t File::btime () const -{ - struct stat s; - if (!stat (_data.c_str (), &s)) -#ifdef HAVE_ST_BIRTHTIME - return s.st_birthtime; -#else - return s.st_ctime; -#endif - - return 0; -} - -//////////////////////////////////////////////////////////////////////////////// -bool File::create (const std::string& name, int mode /* = 0640 */) -{ - std::string full_name = expand (name); - std::ofstream out (full_name.c_str ()); - if (out.good ()) - { - out.close (); - chmod (full_name.c_str (), mode); - return true; - } - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -std::string File::read (const std::string& name) -{ - std::string contents = ""; - - std::ifstream in (name.c_str ()); - if (in.good ()) - { - std::string line; - line.reserve (1024); - while (getline (in, line)) - contents += line + "\n"; - - in.close (); - } - - return contents; -} - -//////////////////////////////////////////////////////////////////////////////// -bool File::read (const std::string& name, std::string& contents) -{ - contents = ""; - - std::ifstream in (name.c_str ()); - if (in.good ()) - { - std::string line; - line.reserve (1024); - while (getline (in, line)) - contents += line + "\n"; - - in.close (); - return true; - } - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -bool File::read (const std::string& name, std::vector & contents) -{ - contents.clear (); - - std::ifstream in (name.c_str ()); - if (in.good ()) - { - std::string line; - line.reserve (1024); - while (getline (in, line)) - contents.push_back (line); - - in.close (); - return true; - } - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -bool File::write (const std::string& name, const std::string& contents) -{ - std::ofstream out (expand (name).c_str (), - std::ios_base::out | std::ios_base::trunc); - if (out.good ()) - { - out << contents; - out.close (); - return true; - } - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -bool File::write ( - const std::string& name, - const std::vector & lines, - bool addNewlines /* = true */) -{ - std::ofstream out (expand (name).c_str (), - std::ios_base::out | std::ios_base::trunc); - if (out.good ()) - { - std::vector ::const_iterator it; - for (it = lines.begin (); it != lines.end (); ++it) - { - out << *it; - - if (addNewlines) - out << "\n"; - } - - out.close (); - return true; - } - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -bool File::append (const std::string& name, const std::string& contents) -{ - std::ofstream out (expand (name).c_str (), - std::ios_base::out | std::ios_base::app); - if (out.good ()) - { - out << contents; - out.close (); - return true; - } - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -bool File::append ( - const std::string& name, - const std::vector & lines, - bool addNewlines /* = true */) -{ - std::ofstream out (expand (name).c_str (), - std::ios_base::out | std::ios_base::app); - if (out.good ()) - { - std::vector ::const_iterator it; - for (it = lines.begin (); it != lines.end (); ++it) - { - out << *it; - - if (addNewlines) - out << "\n"; - } - - out.close (); - return true; - } - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -bool File::remove (const std::string& name) -{ - return unlink (expand (name).c_str ()) == 0 ? true : false; -} - -//////////////////////////////////////////////////////////////////////////////// - diff --git a/src/Path.cpp b/src/Path.cpp deleted file mode 100644 index 908e5d0..0000000 --- a/src/Path.cpp +++ /dev/null @@ -1,301 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2006 - 2015, Paul Beckingham, Federico Hernandez. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// -// http://www.opensource.org/licenses/mit-license.php -// -//////////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// Fixes build with musl libc. -#ifndef GLOB_TILDE -#define GLOB_TILDE 0 -#endif - -#ifndef GLOB_BRACE -#define GLOB_BRACE 0 -#endif - -//////////////////////////////////////////////////////////////////////////////// -std::ostream& operator<< (std::ostream& out, const Path& path) -{ - out << path._data; - return out; -} - -//////////////////////////////////////////////////////////////////////////////// -Path::Path () -{ -} - -//////////////////////////////////////////////////////////////////////////////// -Path::Path (const Path& other) -{ - if (this != &other) - { - _original = other._original; - _data = other._data; - } -} - -//////////////////////////////////////////////////////////////////////////////// -Path::Path (const std::string& in) -{ - _original = in; - _data = expand (in); -} - -//////////////////////////////////////////////////////////////////////////////// -Path::~Path () -{ -} - -//////////////////////////////////////////////////////////////////////////////// -Path& Path::operator= (const Path& other) -{ - if (this != &other) - { - this->_original = other._original; - this->_data = other._data; - } - - return *this; -} - -//////////////////////////////////////////////////////////////////////////////// -bool Path::operator== (const Path& other) -{ - return _data == other._data; -} - -//////////////////////////////////////////////////////////////////////////////// -Path& Path::operator+= (const std::string& dir) -{ - _data += "/" + dir; - return *this; -} - -//////////////////////////////////////////////////////////////////////////////// -Path::operator std::string () const -{ - return _data; -} - -//////////////////////////////////////////////////////////////////////////////// -std::string Path::name () const -{ - if (_data.length ()) - { - auto slash = _data.rfind ('/'); - if (slash != std::string::npos) - return _data.substr (slash + 1, std::string::npos); - } - - return _data; -} - -//////////////////////////////////////////////////////////////////////////////// -std::string Path::parent () const -{ - if (_data.length ()) - { - auto slash = _data.rfind ('/'); - if (slash != std::string::npos) - return _data.substr (0, slash); - } - - return ""; -} - -//////////////////////////////////////////////////////////////////////////////// -std::string Path::extension () const -{ - if (_data.length ()) - { - auto dot = _data.rfind ('.'); - if (dot != std::string::npos) - return _data.substr (dot + 1, std::string::npos); - } - - return ""; -} - -//////////////////////////////////////////////////////////////////////////////// -bool Path::exists () const -{ - return access (_data.c_str (), F_OK) ? false : true; -} - -//////////////////////////////////////////////////////////////////////////////// -bool Path::is_directory () const -{ - struct stat s = {0}; - if (! stat (_data.c_str (), &s) && - S_ISDIR (s.st_mode)) - return true; - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -bool Path::is_absolute () const -{ - if (_data.length () && _data[0] == '/') - return true; - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -bool Path::is_link () const -{ - struct stat s = {0}; - if (! lstat (_data.c_str (), &s) && - S_ISLNK (s.st_mode)) - return true; - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -bool Path::readable () const -{ - return access (_data.c_str (), R_OK) ? false : true; -} - -//////////////////////////////////////////////////////////////////////////////// -bool Path::writable () const -{ - return access (_data.c_str (), W_OK) ? false : true; -} - -//////////////////////////////////////////////////////////////////////////////// -bool Path::executable () const -{ - return access (_data.c_str (), X_OK) ? false : true; -} - -//////////////////////////////////////////////////////////////////////////////// -bool Path::rename (const std::string& new_name) -{ - std::string expanded = expand (new_name); - if (_data != expanded) - { - if (::rename (_data.c_str (), expanded.c_str ()) == 0) - { - _data = expanded; - return true; - } - } - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -// ~ --> /home/user -// ~foo/x --> /home/foo/s -// ~/x --> /home/foo/x -// ./x --> $PWD/x -// x --> $PWD/x -std::string Path::expand (const std::string& in) -{ - std::string copy = in; - - auto tilde = copy.find ("~"); - std::string::size_type slash; - - if (tilde != std::string::npos) - { - const char *home = getenv("HOME"); - if (home == NULL) - { - struct passwd* pw = getpwuid (getuid ()); - home = pw->pw_dir; - } - - // Convert: ~ --> /home/user - if (copy.length () == 1) - copy = home; - - // Convert: ~/x --> /home/user/x - else if (copy.length () > tilde + 1 && - copy[tilde + 1] == '/') - { - copy.replace (tilde, 1, home); - } - - // Convert: ~foo/x --> /home/foo/x - else if ((slash = copy.find ("/", tilde)) != std::string::npos) - { - std::string name = copy.substr (tilde + 1, slash - tilde - 1); - struct passwd* pw = getpwnam (name.c_str ()); - if (pw) - copy.replace (tilde, slash - tilde, pw->pw_dir); - } - } - - // Relative paths - else if (in.length () > 2 && - in.substr (0, 2) == "./") - { - copy = Directory::cwd () + "/" + in.substr (2); - } - else if (in.length () > 1 && - in[0] != '.' && - in[0] != '/') - { - copy = Directory::cwd () + "/" + in; - } - - return copy; -} - -//////////////////////////////////////////////////////////////////////////////// -std::vector Path::glob (const std::string& pattern) -{ - std::vector results; - - glob_t g; -#ifdef SOLARIS - if (!::glob (pattern.c_str (), GLOB_ERR, NULL, &g)) -#else - if (!::glob (pattern.c_str (), GLOB_ERR | GLOB_BRACE | GLOB_TILDE, NULL, &g)) -#endif - for (int i = 0; i < (int) g.gl_pathc; ++i) - results.push_back (g.gl_pathv[i]); - - globfree (&g); - return results; -} - -//////////////////////////////////////////////////////////////////////////////// diff --git a/src/Path.h b/src/Path.h deleted file mode 100644 index be7a02e..0000000 --- a/src/Path.h +++ /dev/null @@ -1,70 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2006 - 2015, Paul Beckingham, Federico Hernandez. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// -// http://www.opensource.org/licenses/mit-license.php -// -//////////////////////////////////////////////////////////////////////////////// - -#ifndef INCLUDED_PATH -#define INCLUDED_PATH - -#include -#include - -class Path -{ -public: - Path (); - Path (const Path&); - Path (const std::string&); - virtual ~Path (); - - Path& operator= (const Path&); - bool operator== (const Path&); - Path& operator+= (const std::string&); - operator std::string () const; - - std::string name () const; - std::string parent () const; - std::string extension () const; - bool exists () const; - bool is_directory () const; - bool is_absolute () const; - bool is_link () const; - bool readable () const; - bool writable () const; - bool executable () const; - bool rename (const std::string&); - - // Statics - static std::string expand (const std::string&); - static std::vector glob (const std::string&); - -public: - std::string _original; - std::string _data; -}; - -std::ostream& operator<< (std::ostream&, const Path&); - -#endif -//////////////////////////////////////////////////////////////////////////////// diff --git a/src/diag.cpp b/src/diag.cpp index f980fba..d33519e 100644 --- a/src/diag.cpp +++ b/src/diag.cpp @@ -30,7 +30,7 @@ #include #include #include -#include +#include #include #include diff --git a/test/.gitignore b/test/.gitignore index 6104120..da541de 100644 --- a/test/.gitignore +++ b/test/.gitignore @@ -1,6 +1,4 @@ run_all all.log color.t -path.t -file.t -directory.t +fs.t diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 3ee3371..15f35ec 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -4,7 +4,7 @@ include_directories (${CMAKE_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/test ${TASKSH_INCLUDE_DIRS}) -set (test_SRCS color.t path.t file.t directory.t) +set (test_SRCS color.t fs.t) message ("-- Configuring run_all") if (${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR}) @@ -35,9 +35,7 @@ add_custom_target (build_tests DEPENDS ${test_SRCS} foreach (src_FILE ${test_SRCS}) add_executable (${src_FILE} "${src_FILE}.cpp" ../src/Color.cpp - ../src/Path.cpp - ../src/File.cpp - ../src/Directory.cpp + ../src/FS.cpp ../src/text.cpp test.cpp) target_link_libraries (${src_FILE} ${TASKSH_LIBRARIES}) diff --git a/test/file.t.cpp b/test/file.t.cpp deleted file mode 100644 index d4649a2..0000000 --- a/test/file.t.cpp +++ /dev/null @@ -1,98 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2006 - 2015, Paul Beckingham, Federico Hernandez. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// -// http://www.opensource.org/licenses/mit-license.php -// -//////////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include -#include - -int main (int argc, char** argv) -{ - UnitTest t (27); - - // Ensure environment has no influence. - unsetenv ("TASKDATA"); - unsetenv ("TASKRC"); - - Directory tmp ("tmp"); - tmp.create (); - t.ok (tmp.exists (), "tmp dir created."); - - File::write ("tmp/file.t.txt", "This is a test\n"); - File f6 ("tmp/file.t.txt"); - t.ok (f6.size () == 15, "File::size tmp/file.t.txt good"); - t.ok (f6.mode () & S_IRUSR, "File::mode tmp/file.t.txt good"); - t.ok (File::remove ("tmp/file.t.txt"), "File::remove tmp/file.t.txt good"); - - // operator (std::string) const; - t.is ((std::string) f6, Directory::cwd () + "/tmp/file.t.txt", "File::operator (std::string) const"); - - t.ok (File::create ("tmp/file.t.create"), "File::create tmp/file.t.create good"); - t.ok (File::remove ("tmp/file.t.create"), "File::remove tmp/file.t.create good"); - - // basename (std::string) const; - t.is (f6.name (), "file.t.txt", "File::basename tmp/file.t.txt --> file.t.txt"); - - // dirname (std::string) const; - t.is (f6.parent (), Directory::cwd () + "/tmp", "File::dirname tmp/file.t.txt --> tmp"); - - // bool rename (const std::string&); - File f7 ("tmp/file.t.2.txt"); - f7.append ("something\n"); - f7.close (); - - t.ok (f7.rename ("tmp/file.t.3.txt"), "File::rename did not fail"); - t.is (f7._data, Directory::cwd () + "/tmp/file.t.3.txt", "File::rename stored new name"); - t.ok (f7.exists (), "File::rename new file exists"); - t.ok (f7.remove (), "File::remove tmp/file.t.3.txt good"); - t.notok (f7.exists (), "File::remove new file no longer exists"); - - // Test permissions. - File f8 ("tmp/file.t.perm.txt"); - f8.create (0744); - t.ok (f8.exists (), "File::create perm file exists"); - mode_t m = f8.mode (); - t.ok (m & S_IFREG, "File::mode tmp/file.t.perm.txt S_IFREG good"); - t.ok (m & S_IRUSR, "File::mode tmp/file.t.perm.txt r-------- good"); - t.ok (m & S_IWUSR, "File::mode tmp/file.t.perm.txt -w------- good"); - t.ok (m & S_IXUSR, "File::mode tmp/file.t.perm.txt --x------ good"); - t.ok (m & S_IRGRP, "File::mode tmp/file.t.perm.txt ---r----- good"); - t.notok (m & S_IWGRP, "File::mode tmp/file.t.perm.txt ----w---- good"); - t.notok (m & S_IXGRP, "File::mode tmp/file.t.perm.txt -----x--- good"); - t.ok (m & S_IROTH, "File::mode tmp/file.t.perm.txt ------r-- good"); - t.notok (m & S_IWOTH, "File::mode tmp/file.t.perm.txt -------w- good"); - t.notok (m & S_IXOTH, "File::mode tmp/file.t.perm.txt --------x good"); - f8.remove (); - t.notok (f8.exists (), "File::remove perm file no longer exists"); - - tmp.remove (); - t.notok (tmp.exists (), "tmp dir removed."); - - return 0; -} - -//////////////////////////////////////////////////////////////////////////////// diff --git a/test/directory.t.cpp b/test/fs.t.cpp similarity index 56% rename from test/directory.t.cpp rename to test/fs.t.cpp index 54e169e..eff3bb3 100644 --- a/test/directory.t.cpp +++ b/test/fs.t.cpp @@ -27,21 +27,149 @@ #include #include #include -#include +#include #include int main (int argc, char** argv) { - UnitTest t (49); + UnitTest t (108); // Ensure environment has no influence. unsetenv ("TASKDATA"); unsetenv ("TASKRC"); + // Path (); + Path p0; + t.is (p0._data, "", "Path::Path"); + + // Path (const Path&); + Path p1 = Path ("foo"); + t.is (p1._data, Directory::cwd () + "/foo", "Path::operator="); + + // Path (const std::string&); + Path p2 ("~"); + t.ok (p2._data != "~", "~ expanded to " + p2._data); + + Path p3 ("/tmp"); + t.ok (p3._data == "/tmp", "/tmp -> /tmp"); + + // Path& operator= (const Path&); + Path p3_copy (p3); + t.is (p3._data, p3_copy._data, "Path::Path (Path&)"); + + // operator (std::string) const; + t.is ((std::string) p3, "/tmp", "Path::operator (std::string) const"); + + // std::string name () const; + Path p4 ("/a/b/c/file.ext"); + t.is (p4.name (), "file.ext", "/a/b/c/file.ext name is file.ext"); + + // std::string parent () const; + t.is (p4.parent (), "/a/b/c", "/a/b/c/file.ext parent is /a/b/c"); + + // std::string extension () const; + t.is (p4.extension (), "ext", "/a/b/c/file.ext extension is ext"); + + // bool exists () const; + t.ok (p2.exists (), "~ exists"); + t.ok (p3.exists (), "/tmp exists"); + + // bool is_directory () const; + t.ok (p2.is_directory (), "~ is_directory"); + t.ok (p3.is_directory (), "/tmp is_directory"); + + // bool readable () const; + t.ok (p2.readable (), "~ readable"); + t.ok (p3.readable (), "/tmp readable"); + + // bool writable () const; + t.ok (p2.writable (), "~ writable"); + t.ok (p3.writable (), "/tmp writable"); + + // bool executable () const; + t.ok (p2.executable (), "~ executable"); + t.ok (p3.executable (), "/tmp executable"); + + // static std::string expand (const std::string&); + t.ok (Path::expand ("~") != "~", "Path::expand ~ != ~"); + t.ok (Path::expand ("~/") != "~/", "Path::expand ~/ != ~/"); + + // static std::vector glob (const std::string&); + std::vector out = Path::glob ("/tmp"); + t.ok (out.size () == 1, "/tmp -> 1 result"); + t.is (out[0], "/tmp", "/tmp -> /tmp"); + + out = Path::glob ("/t?p"); + t.ok (out.size () == 1, "/t?p -> 1 result"); + t.is (out[0], "/tmp", "/t?p -> /tmp"); + + out = Path::glob ("/[s-u]mp"); + t.ok (out.size () == 1, "/[s-u]mp -> 1 result"); + t.is (out[0], "/tmp", "/[s-u]mp -> /tmp"); + + // bool is_absolute () const; + t.notok (p0.is_absolute (), "'' !is_absolute"); + t.ok (p1.is_absolute (), "foo is_absolute"); + t.ok (p2.is_absolute (), "~ is_absolute (after expansion)"); + t.ok (p3.is_absolute (), "/tmp is_absolute"); + t.ok (p4.is_absolute (), "/a/b/c/file.ext is_absolute"); + Directory tmp ("tmp"); tmp.create (); t.ok (tmp.exists (), "tmp dir created."); + File::write ("tmp/file.t.txt", "This is a test\n"); + File f6 ("tmp/file.t.txt"); + t.ok (f6.size () == 15, "File::size tmp/file.t.txt good"); + t.ok (f6.mode () & S_IRUSR, "File::mode tmp/file.t.txt good"); + t.ok (File::remove ("tmp/file.t.txt"), "File::remove tmp/file.t.txt good"); + + // operator (std::string) const; + t.is ((std::string) f6, Directory::cwd () + "/tmp/file.t.txt", "File::operator (std::string) const"); + + t.ok (File::create ("tmp/file.t.create"), "File::create tmp/file.t.create good"); + t.ok (File::remove ("tmp/file.t.create"), "File::remove tmp/file.t.create good"); + + // basename (std::string) const; + t.is (f6.name (), "file.t.txt", "File::basename tmp/file.t.txt --> file.t.txt"); + + // dirname (std::string) const; + t.is (f6.parent (), Directory::cwd () + "/tmp", "File::dirname tmp/file.t.txt --> tmp"); + + // bool rename (const std::string&); + File f7 ("tmp/file.t.2.txt"); + f7.append ("something\n"); + f7.close (); + + t.ok (f7.rename ("tmp/file.t.3.txt"), "File::rename did not fail"); + t.is (f7._data, Directory::cwd () + "/tmp/file.t.3.txt", "File::rename stored new name"); + t.ok (f7.exists (), "File::rename new file exists"); + t.ok (f7.remove (), "File::remove tmp/file.t.3.txt good"); + t.notok (f7.exists (), "File::remove new file no longer exists"); + + // Test permissions. + File f8 ("tmp/file.t.perm.txt"); + f8.create (0744); + t.ok (f8.exists (), "File::create perm file exists"); + mode_t m = f8.mode (); + t.ok (m & S_IFREG, "File::mode tmp/file.t.perm.txt S_IFREG good"); + t.ok (m & S_IRUSR, "File::mode tmp/file.t.perm.txt r-------- good"); + t.ok (m & S_IWUSR, "File::mode tmp/file.t.perm.txt -w------- good"); + t.ok (m & S_IXUSR, "File::mode tmp/file.t.perm.txt --x------ good"); + t.ok (m & S_IRGRP, "File::mode tmp/file.t.perm.txt ---r----- good"); + t.notok (m & S_IWGRP, "File::mode tmp/file.t.perm.txt ----w---- good"); + t.notok (m & S_IXGRP, "File::mode tmp/file.t.perm.txt -----x--- good"); + t.ok (m & S_IROTH, "File::mode tmp/file.t.perm.txt ------r-- good"); + t.notok (m & S_IWOTH, "File::mode tmp/file.t.perm.txt -------w- good"); + t.notok (m & S_IXOTH, "File::mode tmp/file.t.perm.txt --------x good"); + f8.remove (); + t.notok (f8.exists (), "File::remove perm file no longer exists"); + + tmp.remove (); + t.notok (tmp.exists (), "tmp dir removed."); + tmp.create (); + t.ok (tmp.exists (), "tmp dir created."); + // Directory (const File&); // Directory (const Path&); Directory d0 (Path ("tmp")); @@ -126,11 +254,11 @@ int main (int argc, char** argv) t.notok (d9.up (), "parent / --> false"); // Test permissions. - umask(0022); + umask (0022); Directory d10 ("tmp/dir.perm"); d10.create (0750); t.ok (d10.exists (), "Directory::create perm file exists"); - mode_t m = d10.mode (); + m = d10.mode (); t.ok (m & S_IFDIR, "Directory::mode tmp/dir.perm S_IFDIR good"); t.ok (m & S_IRUSR, "Directory::mode tmp/dir.perm r-------- good"); t.ok (m & S_IWUSR, "Directory::mode tmp/dir.perm -w------- good"); diff --git a/test/path.t.cpp b/test/path.t.cpp deleted file mode 100644 index 360e69b..0000000 --- a/test/path.t.cpp +++ /dev/null @@ -1,120 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2006 - 2015, Paul Beckingham, Federico Hernandez. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// -// http://www.opensource.org/licenses/mit-license.php -// -//////////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include -#include - -int main (int argc, char** argv) -{ - UnitTest t (32); - - // Ensure environment has no influence. - unsetenv ("TASKDATA"); - unsetenv ("TASKRC"); - - // Path (); - Path p0; - t.is (p0._data, "", "Path::Path"); - - // Path (const Path&); - Path p1 = Path ("foo"); - t.is (p1._data, Directory::cwd () + "/foo", "Path::operator="); - - // Path (const std::string&); - Path p2 ("~"); - t.ok (p2._data != "~", "~ expanded to " + p2._data); - - Path p3 ("/tmp"); - t.ok (p3._data == "/tmp", "/tmp -> /tmp"); - - // Path& operator= (const Path&); - Path p3_copy (p3); - t.is (p3._data, p3_copy._data, "Path::Path (Path&)"); - - // operator (std::string) const; - t.is ((std::string) p3, "/tmp", "Path::operator (std::string) const"); - - // std::string name () const; - Path p4 ("/a/b/c/file.ext"); - t.is (p4.name (), "file.ext", "/a/b/c/file.ext name is file.ext"); - - // std::string parent () const; - t.is (p4.parent (), "/a/b/c", "/a/b/c/file.ext parent is /a/b/c"); - - // std::string extension () const; - t.is (p4.extension (), "ext", "/a/b/c/file.ext extension is ext"); - - // bool exists () const; - t.ok (p2.exists (), "~ exists"); - t.ok (p3.exists (), "/tmp exists"); - - // bool is_directory () const; - t.ok (p2.is_directory (), "~ is_directory"); - t.ok (p3.is_directory (), "/tmp is_directory"); - - // bool readable () const; - t.ok (p2.readable (), "~ readable"); - t.ok (p3.readable (), "/tmp readable"); - - // bool writable () const; - t.ok (p2.writable (), "~ writable"); - t.ok (p3.writable (), "/tmp writable"); - - // bool executable () const; - t.ok (p2.executable (), "~ executable"); - t.ok (p3.executable (), "/tmp executable"); - - // static std::string expand (const std::string&); - t.ok (Path::expand ("~") != "~", "Path::expand ~ != ~"); - t.ok (Path::expand ("~/") != "~/", "Path::expand ~/ != ~/"); - - // static std::vector glob (const std::string&); - std::vector out = Path::glob ("/tmp"); - t.ok (out.size () == 1, "/tmp -> 1 result"); - t.is (out[0], "/tmp", "/tmp -> /tmp"); - - out = Path::glob ("/t?p"); - t.ok (out.size () == 1, "/t?p -> 1 result"); - t.is (out[0], "/tmp", "/t?p -> /tmp"); - - out = Path::glob ("/[s-u]mp"); - t.ok (out.size () == 1, "/[s-u]mp -> 1 result"); - t.is (out[0], "/tmp", "/[s-u]mp -> /tmp"); - - // bool is_absolute () const; - t.notok (p0.is_absolute (), "'' !is_absolute"); - t.ok (p1.is_absolute (), "foo is_absolute"); - t.ok (p2.is_absolute (), "~ is_absolute (after expansion)"); - t.ok (p3.is_absolute (), "/tmp is_absolute"); - t.ok (p4.is_absolute (), "/a/b/c/file.ext is_absolute"); - - return 0; -} - -////////////////////////////////////////////////////////////////////////////////