Code Cleanup

- Cmake was not updating HAVE_ST_BIRTHTIME.
- NIBBLER_FEATURE_DATE was not properly applied everywhere.
- FEATURE_COLOR was not properly set.
- Some source files failed to include cmake.h, and therefore were not properly
- Removed inefficient use of std::string::substr for guaranteed single character
  strings.
- Integrated Directory::cd.
- Integrated File::ctime, ::btime.
- Integrated Path::operator+.
- Integrated Nibbler::getDigit{2,4,6}.
- Integrated HighResTimer.
  enabling/disabling code.
- All Path objects now expanded internally to absolute form.
- Modified unit tests to accomodate absolute paths.
- Merged new nibbler.t.cpp tests.
- Made various methods const.
- Includes removed from some files, added to others.
This commit is contained in:
Paul Beckingham 2013-05-05 08:33:52 -04:00
parent ebaf09cbe0
commit a1132f0028
24 changed files with 254 additions and 39 deletions

View file

@ -61,6 +61,9 @@
/* Found timegm */
#cmakedefine HAVE_TIMEGM
/* Found st.st_birthtime struct member */
#cmakedefine HAVE_ST_BIRTHTIME
/* Found get_current_dir_name */
#cmakedefine HAVE_GET_CURRENT_DIR_NAME

View file

@ -1575,6 +1575,7 @@ bool A3::is_dom (Nibbler& n, Arg& arg)
////////////////////////////////////////////////////////////////////////////////
bool A3::is_date (Nibbler& n, std::string& result)
{
#ifdef NIBBLER_FEATURE_DATE
std::string date_format = context.config.get ("dateformat");
std::string::size_type start = n.save ();
time_t t;
@ -1586,6 +1587,7 @@ bool A3::is_date (Nibbler& n, std::string& result)
}
n.restore ();
#endif
return false;
}

View file

@ -30,6 +30,8 @@
#include <string>
#define FEATURE_COLOR 1
////////////////////////////////////////////////////////////////////////////////
#define _COLOR_INVERSE 0x00400000 // Inverse attribute.
#define _COLOR_256 0x00200000 // 256-color mode.

View file

@ -133,8 +133,10 @@ Date::Date (const std::string& input, const std::string& format /* = "m/d/Y" */)
// Parse a formatted date.
Nibbler n (input);
#ifdef NIBBLER_FEATURE_DATE
if (n.getDate (format, _t) && n.depleted ())
return;
#endif
// Parse an ISO date.
if (n.getDateISO (_t) && n.depleted ())

View file

@ -29,9 +29,9 @@
#define INCLUDED_DATE
#include <stdio.h>
#include <vector>
#include <string>
class Date;
class Date

View file

@ -91,13 +91,13 @@ bool Directory::create ()
}
////////////////////////////////////////////////////////////////////////////////
bool Directory::remove ()
bool Directory::remove () const
{
return remove_directory (_data);
}
////////////////////////////////////////////////////////////////////////////////
bool Directory::remove_directory (const std::string& dir)
bool Directory::remove_directory (const std::string& dir) const
{
DIR* dp = opendir (dir.c_str ());
if (dp != NULL)
@ -191,6 +191,12 @@ bool Directory::up ()
return false;
}
////////////////////////////////////////////////////////////////////////////////
bool Directory::cd () const
{
return chdir (_data.c_str ()) == 0 ? true : false;
}
////////////////////////////////////////////////////////////////////////////////
void Directory::list (
const std::string& base,

View file

@ -43,17 +43,18 @@ public:
Directory& operator= (const Directory&);
virtual bool create ();
virtual bool remove ();
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&);
bool remove_directory (const std::string&) const;
};
#endif

View file

@ -25,6 +25,7 @@
//
////////////////////////////////////////////////////////////////////////////////
#include <iostream>
#include <stdlib.h>
#include <Context.h>
#include <Date.h>

View file

@ -32,6 +32,7 @@
#include <unistd.h>
#include <File.h>
#include <text.h>
#include <cmake.h>
#include <util.h>
#include <i18n.h>
@ -101,7 +102,7 @@ bool File::create ()
}
////////////////////////////////////////////////////////////////////////////////
bool File::remove ()
bool File::remove () const
{
return unlink (_data.c_str ()) == 0 ? true : false;
}
@ -335,6 +336,30 @@ time_t File::mtime () const
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)
{

View file

@ -46,7 +46,7 @@ public:
File& operator= (const File&);
virtual bool create ();
virtual bool remove ();
virtual bool remove () const;
bool open ();
bool openAndLock ();
@ -69,6 +69,8 @@ public:
virtual mode_t mode ();
virtual size_t size () const;
virtual time_t mtime () const;
virtual time_t ctime () const;
virtual time_t btime () const;
static bool create (const std::string&);
static std::string read (const std::string&);

View file

@ -294,6 +294,69 @@ bool Nibbler::getDigit (int& result)
return false;
}
////////////////////////////////////////////////////////////////////////////////
bool Nibbler::getDigit6 (int& result)
{
std::string::size_type i = _cursor;
if (i < _length &&
_length - i >= 6)
{
if (isdigit (_input[i + 0]) &&
isdigit (_input[i + 1]) &&
isdigit (_input[i + 2]) &&
isdigit (_input[i + 3]) &&
isdigit (_input[i + 4]) &&
isdigit (_input[i + 5]))
{
result = strtoimax (_input.substr (_cursor, 6).c_str (), NULL, 10);
_cursor += 6;
return true;
}
}
return false;
}
////////////////////////////////////////////////////////////////////////////////
bool Nibbler::getDigit4 (int& result)
{
std::string::size_type i = _cursor;
if (i < _length &&
_length - i >= 4)
{
if (isdigit (_input[i + 0]) &&
isdigit (_input[i + 1]) &&
isdigit (_input[i + 2]) &&
isdigit (_input[i + 3]))
{
result = strtoimax (_input.substr (_cursor, 4).c_str (), NULL, 10);
_cursor += 4;
return true;
}
}
return false;
}
////////////////////////////////////////////////////////////////////////////////
bool Nibbler::getDigit2 (int& result)
{
std::string::size_type i = _cursor;
if (i < _length &&
_length - i >= 2)
{
if (isdigit (_input[i + 0]) &&
isdigit (_input[i + 1]))
{
result = strtoimax (_input.substr (_cursor, 2).c_str (), NULL, 10);
_cursor += 2;
return true;
}
}
return false;
}
////////////////////////////////////////////////////////////////////////////////
bool Nibbler::getInt (int& result)
{
@ -716,7 +779,6 @@ bool Nibbler::getDateISO (time_t& t)
}
////////////////////////////////////////////////////////////////////////////////
#ifdef NIBBLER_FEATURE_DATE
// Parse the longest integer using the next 'limit' characters of 'result'
// following position 'i' (when strict is true, the number of digits must be
// equal to limit).
@ -758,6 +820,7 @@ bool Nibbler::parseDigits(std::string::size_type& i,
}
////////////////////////////////////////////////////////////////////////////////
#ifdef NIBBLER_FEATURE_DATE
bool Nibbler::getDate (const std::string& format, time_t& t)
{
std::string::size_type i = _cursor;

View file

@ -28,6 +28,8 @@
#ifndef INCLUDED_NIBBLER
#define INCLUDED_NIBBLER
#include <cmake.h>
#define NIBBLER_FEATURE_DATE
//#undef NIBBLER_FEATURE_DATE
@ -63,6 +65,9 @@ public:
bool getN (const int, std::string&);
bool getQuoted (char, std::string&, bool quote = false);
bool getDigit (int&);
bool getDigit6 (int&);
bool getDigit4 (int&);
bool getDigit2 (int&);
bool getInt (int&);
bool getHex (int&);
bool getUnsignedInt (int&);
@ -76,8 +81,8 @@ public:
bool getUUID (std::string&);
bool getPartialUUID (std::string&);
bool getDateISO (time_t&);
#ifdef NIBBLER_FEATURE_DATE
bool parseDigits(std::string::size_type&, int&, unsigned int, bool strict = true);
#ifdef NIBBLER_FEATURE_DATE
bool getDate (const std::string&, time_t&);
#endif
bool getOneOf (const std::vector <std::string>&, std::string&);

View file

@ -33,6 +33,7 @@
#include <pwd.h>
#include <stdio.h>
#include <unistd.h>
#include <limits.h>
#include <Path.h>
#include <cmake.h>
@ -88,6 +89,13 @@ 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
{
@ -153,7 +161,7 @@ bool Path::is_directory () const
////////////////////////////////////////////////////////////////////////////////
bool Path::is_absolute () const
{
if (_data.length () && _data.substr (0, 1) == "/")
if (_data.length () && _data[0] == '/')
return true;
return false;
@ -197,6 +205,8 @@ bool Path::rename (const std::string& new_name)
// ~ --> /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;
@ -234,6 +244,23 @@ std::string Path::expand (const std::string& in)
}
}
// Relative paths
else if (in.length () > 2 &&
in.substr (0, 2) == "./")
{
char buf[PATH_MAX];
getcwd (buf, PATH_MAX - 1);
copy = std::string (buf) + "/" + in.substr (2);
}
else if (in.length () > 1 &&
in[0] != '.' &&
in[0] != '/')
{
char buf[PATH_MAX];
getcwd (buf, PATH_MAX - 1);
copy = std::string (buf) + "/" + in;
}
return copy;
}

View file

@ -28,7 +28,6 @@
#ifndef INCLUDED_PATH
#define INCLUDED_PATH
#include <iostream>
#include <vector>
#include <string>
@ -42,6 +41,7 @@ public:
Path& operator= (const Path&);
bool operator== (const Path&);
Path& operator+= (const std::string&);
operator std::string () const;
std::string name () const;

View file

@ -112,3 +112,40 @@ void Timer::subtract (unsigned long value)
}
////////////////////////////////////////////////////////////////////////////////
HighResTimer::HighResTimer ()
{
_start.tv_sec = 0;
_start.tv_usec = 0;
_stop.tv_sec = 0;
_stop.tv_usec = 0;
}
////////////////////////////////////////////////////////////////////////////////
HighResTimer::~HighResTimer ()
{
}
////////////////////////////////////////////////////////////////////////////////
void HighResTimer::start ()
{
gettimeofday (&_start, NULL);
}
////////////////////////////////////////////////////////////////////////////////
void HighResTimer::stop ()
{
gettimeofday (&_stop, NULL);
}
////////////////////////////////////////////////////////////////////////////////
double HighResTimer::total () const
{
if (_stop.tv_sec > 0 || _stop.tv_usec > 0)
return (_stop.tv_sec - _start.tv_sec) +
(_stop.tv_usec - _start.tv_usec) / 1000000.0;
return 0.0;
}
////////////////////////////////////////////////////////////////////////////////

View file

@ -31,6 +31,7 @@
#include <string>
#include <sys/time.h>
// Timer is a scope-activated timer that dumps to std::cout at end of scope.
class Timer
{
public:
@ -52,6 +53,25 @@ private:
unsigned long _total;
};
// HighResTimer is a stop watch with microsecond resolution.
class HighResTimer
{
public:
HighResTimer ();
~HighResTimer ();
HighResTimer (const HighResTimer&);
HighResTimer& operator= (const HighResTimer&);
void start ();
void stop ();
double total () const;
private:
struct timeval _start;
struct timeval _stop;
};
#endif
////////////////////////////////////////////////////////////////////////////////

View file

@ -46,8 +46,8 @@ if (open my $fh, '>', 'color.rc')
# Test the errors colors
my $output = qx{../src/task rc:color.rc rc.debug:on add due:__ 2>&1 >/dev/null};
like ($output, qr/^\033\[33mThe\ duration\ '__'\ was\ not\ recognized\ as\ valid,\ with\ correct\ units\ like\ '3days'\.\033\[0m$/xms, 'color.error');
like ($output, qr/^\033\[32mTimer\ Config::load\ \(color.rc\) .* \033\[0m$/xms, 'color.debug');
like ($output, qr/^\033\[34mUsing\ alternate\ .taskrc\ file\ color.rc\033\[0m$/xms, 'color.header');
like ($output, qr/^\033\[32mTimer\ Config::load\ \(.+color.rc\) .* \033\[0m$/xms, 'color.debug');
like ($output, qr/^\033\[34mUsing\ alternate\ .taskrc\ file\ /xms, 'color.header');
like ($output, qr/^\033\[31mConfiguration\ override\ rc.debug:on\033\[0m$/xms, 'color.footnote');
# Cleanup.

View file

@ -51,17 +51,17 @@ int main (int argc, char** argv)
// Directory (const Directory&);
Directory d3 (d2);
t.is (d3._data, "tmp", "Directory (Directory&)");
t.is (d3._data, Directory::cwd () + "/tmp", "Directory (Directory&)");
// Directory (const std::string&);
Directory d4 ("tmp/test_directory");
// Directory& operator= (const Directory&);
Directory d5 = d4;
t.is (d5._data, "tmp/test_directory", "Directory::operator=");
t.is (d5._data, Directory::cwd () + "/tmp/test_directory", "Directory::operator=");
// operator (std::string) const;
t.is ((std::string) d3, "tmp", "Directory::operator (std::string) const");
t.is ((std::string) d3, Directory::cwd () + "/tmp", "Directory::operator (std::string) const");
// virtual bool create ();
t.ok (d5.create (), "Directory::create tmp/test_directory");
@ -77,15 +77,15 @@ int main (int argc, char** argv)
std::vector <std::string> files = d5.list ();
std::sort (files.begin (), files.end ());
t.is ((int)files.size (), 2, "Directory::list 1 file");
t.is (files[0], "tmp/test_directory/dir", "file[0] is tmp/test_directory/dir");
t.is (files[1], "tmp/test_directory/f0", "file[1] is tmp/test_directory/f0");
t.is (files[0], Directory::cwd () + "/tmp/test_directory/dir", "file[0] is tmp/test_directory/dir");
t.is (files[1], Directory::cwd () + "/tmp/test_directory/f0", "file[1] is tmp/test_directory/f0");
// std::vector <std::string> listRecursive ();
files = d5.listRecursive ();
std::sort (files.begin (), files.end ());
t.is ((int)files.size (), 2, "Directory::list 1 file");
t.is (files[0], "tmp/test_directory/dir/f1", "file is tmp/test_directory/dir/f1");
t.is (files[1], "tmp/test_directory/f0", "file is tmp/test_directory/f0");
t.is (files[0], Directory::cwd () + "/tmp/test_directory/dir/f1", "file is tmp/test_directory/dir/f1");
t.is (files[1], Directory::cwd () + "/tmp/test_directory/f0", "file is tmp/test_directory/f0");
// virtual bool remove ();
t.ok (File::remove (d5._data + "/f0"), "File::remove tmp/test_directory/f0");

View file

@ -49,9 +49,9 @@ like ($stderr, qr/^The duration '__' was not recognized as valid, with correct u
# Check that headers are sent to standard error
$stdout = qx{../src/task rc:outerr.rc list 2> /dev/null};
unlike ($stdout, qr/^Using alternate .taskrc file outerr.rc$/ms, 'Headers are not sent to stdout');
unlike ($stdout, qr/^Using alternate .taskrc file .+outerr.rc$/ms, 'Headers are not sent to stdout');
$stderr = qx{../src/task rc:outerr.rc list 2>&1 >/dev/null};
like ($stderr, qr/^Using alternate .taskrc file outerr.rc$/ms, 'Headers are sent to stderr');
like ($stderr, qr/^Using alternate .taskrc file .+outerr.rc$/ms, 'Headers are sent to stderr');
# Check that footnotes are sent to standard error
$stdout = qx{../src/task rc:outerr.rc rc.debug:on list 2> /dev/null};
@ -61,9 +61,9 @@ like ($stderr, qr/^Configuration override rc.debug:on$/ms, 'Footnotes are sent t
# Check that debugs are sent to standard error
$stdout = qx{../src/task rc:outerr.rc rc.debug:on list 2> /dev/null};
unlike ($stdout, qr/^Timer Config::load \(outerr.rc\) /ms, 'Debugs are not sent to stdout');
unlike ($stdout, qr/^Timer Config::load \(.+outerr.rc\) /ms, 'Debugs are not sent to stdout');
$stderr = qx{../src/task rc:outerr.rc rc.debug:on list 2>&1 >/dev/null};
like ($stderr, qr/^Timer Config::load \(outerr.rc\) /ms, 'Debugs are sent to stderr');
like ($stderr, qr/^Timer Config::load \(.+outerr.rc\) /ms, 'Debugs are sent to stderr');
# Cleanup.
unlink qw(pending.data completed.data undo.data backlog.data outerr.rc);

View file

@ -47,7 +47,7 @@ int main (int argc, char** argv)
t.ok (File::remove ("tmp/file.t.txt"), "File::remove tmp/file.t.txt good");
// operator (std::string) const;
t.is ((std::string) f6, "tmp/file.t.txt", "File::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");
@ -56,7 +56,7 @@ int main (int argc, char** argv)
t.is (f6.name (), "file.t.txt", "File::basename tmp/file.t.txt --> file.t.txt");
// dirname (std::string) const;
t.is (f6.parent (), "tmp", "File::dirname tmp/file.t.txt --> /tmp");
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");
@ -64,7 +64,7 @@ int main (int argc, char** argv)
f7.close ();
t.ok (f7.rename ("tmp/file.t.3.txt"), "File::rename did not fail");
t.is (f7._data, "tmp/file.t.3.txt", "File::rename stored new name");
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");

View file

@ -39,15 +39,15 @@ int main (int argc, char** argv)
{
#ifdef NIBBLER_FEATURE_DATE
#ifdef NIBBLER_FEATURE_REGEX
UnitTest t (396);
UnitTest t (402);
#else
UnitTest t (372);
UnitTest t (378);
#endif
#else
#ifdef NIBBLER_FEATURE_REGEX
UnitTest t (346);
UnitTest t (338);
#else
UnitTest t (322);
UnitTest t (314);
#endif
#endif
@ -258,6 +258,24 @@ int main (int argc, char** argv)
t.is (i, 2, " '2x' : getDigit () -> 2");
t.notok (n.getDigit (i), " 'x' : getDigit () -> false");
// bool getDigit6 (int&);
t.diag ("Nibbler::getDigit6");
n = Nibbler ("654321");
t.ok (n.getDigit6 (i), " 654321 : getDigit6 () -> true");
t.is (i, 654321, " 654321 : getDigit6 () -> 654321");
// bool getDigit4 (int&);
t.diag ("Nibbler::getDigit4");
n = Nibbler ("4321");
t.ok (n.getDigit4 (i), " 4321 : getDigit4 () -> true");
t.is (i, 4321, " 4321 : getDigit4 () -> 4321");
// bool getDigit2 (int&);
t.diag ("Nibbler::getDigit2");
n = Nibbler ("21");
t.ok (n.getDigit2 (i), " 21 : getDigit2 () -> true");
t.is (i, 21, " 21 : getDigit2 () -> 21");
// bool getInt (int&);
t.diag ("Nibbler::getInt");
n = Nibbler ("123 -4");

View file

@ -27,6 +27,7 @@
#include <Context.h>
#include <Path.h>
#include <Directory.h>
#include <test.h>
Context context;
@ -37,11 +38,11 @@ int main (int argc, char** argv)
// Path ();
Path p0;
t.ok (p0._data == "", "Path::Path");
t.is (p0._data, "", "Path::Path");
// Path (const Path&);
Path p1 = Path ("foo");
t.ok (p1._data == "foo", "Path::operator=");
t.is (p1._data, Directory::cwd () + "/foo", "Path::operator=");
// Path (const std::string&);
Path p2 ("~");
@ -106,7 +107,7 @@ int main (int argc, char** argv)
// bool is_absolute () const;
t.notok (p0.is_absolute (), "'' !is_absolute");
t.notok (p1.is_absolute (), "foo !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");

View file

@ -1,4 +1,4 @@
#! /usr/bin/env perl
#!/usr/bin/env perl
use strict;
use warnings;

View file

@ -43,16 +43,16 @@ if (open my $fh, '>', 'shadow.rc')
}
my $output = qx{../src/task rc:shadow.rc add one 2>&1 >/dev/null};
like ($output, qr/\[Shadow file '\.\/shadow\.txt' updated\.\]/, 'shadow file updated on add');
like ($output, qr/\[Shadow file '.+\/shadow\.txt' updated\.\]/, 'shadow file updated on add');
$output = qx{../src/task rc:shadow.rc list 2>&1 >/dev/null};
unlike ($output, qr/\[Shadow file '\.\/shadow\.txt' updated\.\]/, 'shadow file not updated on list');
unlike ($output, qr/\[Shadow file '.+\/shadow\.txt' updated\.\]/, 'shadow file not updated on list');
$output = qx{../src/task rc:shadow.rc 1 delete 2>&1 >/dev/null};
like ($output, qr/\[Shadow file '\.\/shadow\.txt' updated\.\]/, 'shadow file updated on delete');
like ($output, qr/\[Shadow file '.+\/shadow\.txt' updated\.\]/, 'shadow file updated on delete');
$output = qx{../src/task rc:shadow.rc list 2>&1 >/dev/null};
unlike ($output, qr/\[Shadow file '\.\/shadow\.txt' updated\.\]/, 'shadow file not updated on list');
unlike ($output, qr/\[Shadow file '.+\/shadow\.txt' updated\.\]/, 'shadow file not updated on list');
# Inspect the shadow file.
my $file = slurp ('./shadow.txt');