Cleanup: Combined File, Path and Directory into FS

- The three objects are related and always travel together, so they are now
  combined.
This commit is contained in:
Paul Beckingham 2015-05-25 10:11:41 -04:00
parent ff88d9da16
commit 3e043291f0
20 changed files with 689 additions and 935 deletions

View file

@ -30,8 +30,7 @@
#include <vector>
#include <map>
#include <Lexer.h>
#include <Path.h>
#include <File.h>
#include <FS.h>
// Represents a single argument.
class A

View file

@ -12,18 +12,16 @@ set (task_SRCS CLI.cpp CLI.h
DOM.cpp DOM.h
Date.cpp Date.h
Dates.cpp Dates.h
Directory.cpp Directory.h
Duration.cpp Duration.h
Eval.cpp Eval.h
File.cpp File.h
Filter.cpp Filter.h
FS.cpp FS.h
Hooks.cpp Hooks.h
ISO8601.cpp ISO8601.h
JSON.cpp JSON.h
Lexer.cpp Lexer.h
Msg.cpp Msg.h
Nibbler.cpp Nibbler.h
Path.cpp Path.h
RX.cpp RX.h
TDB2.cpp TDB2.h
Task.cpp Task.h

View file

@ -33,9 +33,8 @@
#include <inttypes.h>
#include <unistd.h>
#include <stdlib.h>
#include <Directory.h>
#include <Date.h>
#include <File.h>
#include <FS.h>
#include <Timer.h>
#include <JSON.h>
#include <Config.h>

View file

@ -30,7 +30,7 @@
#include <map>
#include <vector>
#include <string>
#include <File.h>
#include <FS.h>
class Config : public std::map <std::string, std::string>
{

View file

@ -34,8 +34,7 @@
#include <string.h>
#include <unistd.h>
#include <Context.h>
#include <Directory.h>
#include <File.h>
#include <FS.h>
#include <Eval.h>
#include <Variant.h>
#include <text.h>

View file

@ -34,9 +34,7 @@
#include <TDB2.h>
#include <Hooks.h>
#include <DOM.h>
#include <Path.h>
#include <File.h>
#include <Directory.h>
#include <FS.h>
#include <CLI.h>
#include <Timer.h>

View file

@ -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 <cmake.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <Directory.h>
#if defined SOLARIS || defined NETBSD || defined FREEBSD
#include <limits.h>
#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 <std::string> Directory::list ()
{
std::vector <std::string> files;
list (_data, files, false);
return files;
}
////////////////////////////////////////////////////////////////////////////////
std::vector <std::string> Directory::listRecursive ()
{
std::vector <std::string> 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 <std::string>& 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);
}
}
////////////////////////////////////////////////////////////////////////////////

View file

@ -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 <File.h>
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 <std::string> list ();
std::vector <std::string> listRecursive ();
static std::string cwd ();
bool up ();
bool cd () const;
private:
void list (const std::string&, std::vector <std::string>&, bool);
bool remove_directory (const std::string&) const;
};
#endif
////////////////////////////////////////////////////////////////////////////////

View file

@ -26,16 +26,286 @@
#include <cmake.h>
#include <fstream>
#include <glob.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <pwd.h>
#include <File.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <dirent.h>
#include <string.h>
#include <errno.h>
#include <text.h>
#include <util.h>
#include <i18n.h>
#include <FS.h>
#if defined SOLARIS || defined NETBSD || defined FREEBSD
#include <limits.h>
#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 <std::string> Path::glob (const std::string& pattern)
{
std::vector <std::string> 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 ()
@ -518,4 +788,203 @@ bool File::remove (const std::string& name)
}
////////////////////////////////////////////////////////////////////////////////
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 <std::string> Directory::list ()
{
std::vector <std::string> files;
list (_data, files, false);
return files;
}
////////////////////////////////////////////////////////////////////////////////
std::vector <std::string> Directory::listRecursive ()
{
std::vector <std::string> 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 <std::string>& 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);
}
}
////////////////////////////////////////////////////////////////////////////////

View file

@ -24,14 +24,47 @@
//
////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDED_FILE
#define INCLUDED_FILE
#ifndef INCLUDED_FS
#define INCLUDED_FS
#include <stdio.h>
#include <string>
#include <vector>
#include <sys/stat.h>
#include <Path.h>
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<std::string> glob (const std::string&);
public:
std::string _original;
std::string _data;
};
class File : public Path
{
@ -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 <std::string> list ();
std::vector <std::string> listRecursive ();
static std::string cwd ();
bool up ();
bool cd () const;
private:
void list (const std::string&, std::vector <std::string>&, bool);
bool remove_directory (const std::string&) const;
};
std::ostream& operator<< (std::ostream&, const Path&);
#endif
////////////////////////////////////////////////////////////////////////////////

View file

@ -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 <cmake.h>
#include <fstream>
#include <glob.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <pwd.h>
#include <stdio.h>
#include <unistd.h>
#include <limits.h>
#include <Directory.h>
#include <Path.h>
// 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 <std::string> Path::glob (const std::string& pattern)
{
std::vector <std::string> 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;
}
////////////////////////////////////////////////////////////////////////////////

View file

@ -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 <vector>
#include <string>
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<std::string> glob (const std::string&);
public:
std::string _original;
std::string _data;
};
std::ostream& operator<< (std::ostream&, const Path&);
#endif
////////////////////////////////////////////////////////////////////////////////

View file

@ -32,7 +32,7 @@
#include <string>
#include <stdio.h>
#include <ViewText.h>
#include <File.h>
#include <FS.h>
#include <Task.h>
// TF2 Class represents a single file in the task database.

View file

@ -32,7 +32,7 @@
#include <i18n.h>
#include <main.h>
#include <Context.h>
#include <Directory.h>
#include <FS.h>
#include <ViewText.h>
#include <CmdShow.h>

4
test/.gitignore vendored
View file

@ -11,11 +11,10 @@ color.t
config.t
date.t
dates.t
directory.t
dom.t
duration.t
eval.t
file.t
fs.t
i18n.t
iso8601d.t
iso8601p.t
@ -24,7 +23,6 @@ lexer.t
list.t
msg.t
nibbler.t
path.t
rx.t
t.t
t2.t

View file

@ -6,16 +6,15 @@ include_directories (${CMAKE_SOURCE_DIR}
${CMAKE_SOURCE_DIR}/test
${TASK_INCLUDE_DIRS})
set (test_SRCS autocomplete.t color.t config.t date.t directory.t dom.t
file.t i18n.t json.t list.t msg.t nibbler.t path.t rx.t t.t t2.t
t3.t tdb2.t text.t utf8.t util.t view.t json_test lexer.t
iso8601d.t iso8601p.t duration.t variant_add.t
variant_and.t variant_cast.t variant_divide.t variant_equal.t
variant_exp.t variant_gt.t variant_gte.t variant_inequal.t
variant_lt.t variant_lte.t variant_match.t variant_math.t
variant_modulo.t variant_multiply.t variant_nomatch.t
variant_not.t variant_or.t variant_partial.t variant_subtract.t
variant_xor.t eval.t dates.t)
set (test_SRCS autocomplete.t color.t config.t date.t dom.t fs.t i18n.t json.t
list.t msg.t nibbler.t rx.t t.t t2.t t3.t tdb2.t text.t utf8.t
util.t view.t json_test lexer.t iso8601d.t iso8601p.t duration.t
variant_add.t variant_and.t variant_cast.t variant_divide.t
variant_equal.t variant_exp.t variant_gt.t variant_gte.t
variant_inequal.t variant_lt.t variant_lte.t variant_match.t
variant_math.t variant_modulo.t variant_multiply.t
variant_nomatch.t variant_not.t variant_or.t variant_partial.t
variant_subtract.t variant_xor.t eval.t dates.t)
message ("-- Configuring run_all")
if (${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR})

View file

@ -1,101 +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 <cmake.h>
#include <stdlib.h>
#include <Context.h>
#include <File.h>
#include <Directory.h>
#include <test.h>
Context context;
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;
}
////////////////////////////////////////////////////////////////////////////////

View file

@ -28,23 +28,151 @@
#include <algorithm>
#include <stdlib.h>
#include <Context.h>
#include <Directory.h>
#include <FS.h>
#include <test.h>
Context context;
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 <std::string> glob (const std::string&);
std::vector <std::string> 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"));
@ -133,7 +261,7 @@ int main (int argc, char** argv)
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");

View file

@ -28,7 +28,7 @@
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <File.h>
#include <FS.h>
#include <JSON.h>
#include <Context.h>

View file

@ -1,123 +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 <cmake.h>
#include <stdlib.h>
#include <Context.h>
#include <Path.h>
#include <Directory.h>
#include <test.h>
Context context;
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 <std::string> glob (const std::string&);
std::vector <std::string> 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;
}
////////////////////////////////////////////////////////////////////////////////