diff --git a/src/Context.h b/src/Context.h index 765de97a9..0ad6511f7 100644 --- a/src/Context.h +++ b/src/Context.h @@ -34,7 +34,7 @@ #include "Subst.h" #include "Cmd.h" #include "Task.h" -#include "TDB2.h" +#include "TDB.h" #include "StringTable.h" class Context @@ -67,7 +67,7 @@ public: Sequence sequence; Subst subst; Task task; - TDB2 tdb; + TDB tdb; StringTable stringtable; std::string program; std::vector args; diff --git a/src/Makefile.am b/src/Makefile.am index 1212259c1..d3e6bd4d3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -2,10 +2,10 @@ bin_PROGRAMS = task task_SOURCES = Att.cpp Cmd.cpp Config.cpp Context.cpp Date.cpp Duration.cpp \ Filter.cpp Grid.cpp Keymap.cpp Location.cpp Nibbler.cpp \ Record.cpp Sequence.cpp StringTable.cpp Subst.cpp Task.cpp \ - TDB2.cpp Table.cpp Timer.cpp color.cpp command.cpp edit.cpp \ + TDB.cpp Table.cpp Timer.cpp color.cpp command.cpp edit.cpp \ import.cpp interactive.cpp valid.cpp recur.cpp report.cpp \ custom.cpp rules.cpp main.cpp text.cpp util.cpp \ Att.h Cmd.h Config.h Context.h Date.h Duration.h Filter.h \ Grid.h Keymap.h Location.h Nibbler.h Record.h Sequence.h \ - StringTable.h Subst.h Task.h TDB2.h Table.h Timer.h color.h \ + StringTable.h Subst.h Task.h TDB.h Table.h Timer.h color.h \ i18n.h main.h text.h util.h diff --git a/src/TDB.cpp b/src/TDB.cpp index 3621d995b..a299d4672 100644 --- a/src/TDB.cpp +++ b/src/TDB.cpp @@ -24,386 +24,311 @@ // USA // //////////////////////////////////////////////////////////////////////////////// -#include -#include -#include -#include -#include -#include -#include "T.h" -#include "TDB.h" +#include +#include +#include +#include +#include +#include "text.h" #include "util.h" +#include "TDB.h" +#include "main.h" //////////////////////////////////////////////////////////////////////////////// +// The ctor/dtor do nothing. +// The lock/unlock methods hold the file open. +// There should be only one commit. +// +// +- TDB::TDB +// | +// | +- TDB::lock +// | | open +// | | [lock] +// | | +// | | +- TDB::load (Filter) +// | | | read all +// | | | apply filter +// | | | return subset +// | | | +// | | +- TDB::add (T) +// | | | +// | | +- TDB::update (T, T') +// | | | +// | | +- TDB::commit +// | | write all +// | | +// | +- TDB::unlock +// | [unlock] +// | close +// | +// +- TDB::~TDB +// [TDB::unlock] +// TDB::TDB () -: mPendingFile ("") -, mCompletedFile ("") +: mLock (true) +, mAllOpenAndLocked (false) , mId (1) -, mNoLock (false) { } //////////////////////////////////////////////////////////////////////////////// TDB::~TDB () { + if (mAllOpenAndLocked) + unlock (); } //////////////////////////////////////////////////////////////////////////////// -void TDB::dataDirectory (const std::string& directory) +void TDB::clear () { - if (! access (expandPath (directory).c_str (), F_OK)) - { - mPendingFile = directory + "/pending.data"; - mCompletedFile = directory + "/completed.data"; - } - else - { - std::string error = "Directory '"; - error += directory; - error += "' does not exist, or is not readable and writable."; - throw error; - } + mLocations.clear (); + mLock = true; + + if (mAllOpenAndLocked) + unlock (); + + mAllOpenAndLocked = false; } //////////////////////////////////////////////////////////////////////////////// -// Combine allPendingT with allCompletedT. -// Note: this method is O(N1) + O(N2), where N2 is not bounded. -bool TDB::allT (std::vector & all) +void TDB::location (const std::string& path) { - all.clear (); + if (access (expandPath (path).c_str (), F_OK)) + throw std::string ("Data location '") + + path + + "' does not exist, or is not readable and writable."; - // Retrieve all the pending records. - std::vector allp; - if (allPendingT (allp)) + mLocations.push_back (Location (path)); +} + +//////////////////////////////////////////////////////////////////////////////// +void TDB::lock (bool lockFile /* = true */) +{ + mLock = lockFile; + + mPending.clear (); +// mCompleted.clear (); + mNew.clear (); + mPending.clear (); + + foreach (location, mLocations) { - std::vector ::iterator i; - for (i = allp.begin (); i != allp.end (); ++i) - all.push_back (*i); + location->pending = openAndLock (location->path + "/pending.data"); + location->completed = openAndLock (location->path + "/completed.data"); + } - // Retrieve all the completed records. - std::vector allc; - if (allCompletedT (allc)) + mAllOpenAndLocked = true; +} + +//////////////////////////////////////////////////////////////////////////////// +void TDB::unlock () +{ + if (mAllOpenAndLocked) + { + mPending.clear (); +// mCompleted.clear (); + mNew.clear (); + mModified.clear (); + + foreach (location, mLocations) { - for (i = allc.begin (); i != allc.end (); ++i) - all.push_back (*i); - - return true; - } - } - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -// Only accesses to the pending file result in Tasks that have assigned ids. -bool TDB::pendingT (std::vector & all) -{ - all.clear (); - - std::vector lines; - if (readLockedFile (mPendingFile, lines)) - { - mId = 1; - - int line = 1; - std::vector ::iterator it; - for (it = lines.begin (); it != lines.end (); ++it) - { - try - { - T t (*it); - t.setId (mId++); - if (t.getStatus () == T::pending) - all.push_back (t); - } - - catch (std::string& e) - { - std::stringstream more; - more << " Line " << line << ", in " << "pending.data"; - - throw e + more.str (); - } - - ++line; + fclose (location->pending); + location->pending = NULL; + fclose (location->completed); + location->completed = NULL; } - return true; + mAllOpenAndLocked = false; } - - return false; } //////////////////////////////////////////////////////////////////////////////// -// Only accesses to the pending file result in Tasks that have assigned ids. -bool TDB::allPendingT (std::vector & all) +// Returns number of filtered tasks. +// Note: tasks.clear () is deliberately not called, to allow the combination of +// multiple files. +int TDB::load (std::vector & tasks, Filter& filter) { - all.clear (); + loadPending (tasks, filter); + loadCompleted (tasks, filter); - std::vector lines; - if (readLockedFile (mPendingFile, lines)) + return tasks.size (); +} + +//////////////////////////////////////////////////////////////////////////////// +// Returns number of filtered tasks. +// Note: tasks.clear () is deliberately not called, to allow the combination of +// multiple files. +int TDB::loadPending (std::vector & tasks, Filter& filter) +{ + std::string file; + int line_number; + + try { - mId = 1; - - int line = 1; - std::vector ::iterator it; - for (it = lines.begin (); it != lines.end (); ++it) + char line[T_LINE_MAX]; + foreach (location, mLocations) { - try - { - T t (*it); - t.setId (mId++); - all.push_back (t); - } + line_number = 1; + file = location->path + "/pending.data"; - catch (std::string& e) - { - std::stringstream more; - more << " Line " << line << ", in " << "pending.data"; - - throw e + more.str (); - } - - ++line; - } - - return true; - } - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -bool TDB::completedT (std::vector & all) const -{ - all.clear (); - - std::vector lines; - if (readLockedFile (mCompletedFile, lines)) - { - int line = 1; - std::vector ::iterator it; - for (it = lines.begin (); it != lines.end (); ++it) - { - try - { - T t (*it); - if (t.getStatus () != T::deleted) - all.push_back (t); - } - - catch (std::string& e) - { - std::stringstream more; - more << " Line " << line << ", in " << "pending.data"; - - throw e + more.str (); - } - - ++line; - } - - return true; - } - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -bool TDB::allCompletedT (std::vector & all) const -{ - all.clear (); - - std::vector lines; - if (readLockedFile (mCompletedFile, lines)) - { - int line = 1; - std::vector ::iterator it; - for (it = lines.begin (); it != lines.end (); ++it) - { - try - { - T t (*it); - all.push_back (t); - } - - catch (std::string& e) - { - std::stringstream more; - more << " Line " << line << ", in " << "pending.data"; - - throw e + more.str (); - } - - ++line; - } - - return true; - } - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -bool TDB::addT (const T& t) -{ - T task (t); - std::vector tags; - task.getTags (tags); - - // +tag or -tag are both considered valid tags to add to a new pending task. - // Generating an error here would not be friendly. - for (unsigned int i = 0; i < tags.size (); ++i) - { - if (tags[i][0] == '-' || tags[i][0] == '+') - { - task.removeTag (tags[i]); - task.addTag (tags[i].substr (1, std::string::npos)); - } - } - - if (task.getStatus () == T::pending || - task.getStatus () == T::recurring) - { - return writePending (task); - } - - return writeCompleted (task); -} - -//////////////////////////////////////////////////////////////////////////////// -bool TDB::modifyT (const T& t) -{ - T modified (t); - - std::vector all; - allPendingT (all); - - std::vector pending; - - std::vector ::iterator it; - for (it = all.begin (); it != all.end (); ++it) - { - if (it->getId () == t.getId ()) - { - modified.setUUID (it->getUUID ()); - pending.push_back (modified); - } - else - pending.push_back (*it); - } - - return overwritePending (pending); -} - -//////////////////////////////////////////////////////////////////////////////// -bool TDB::lock (FILE* file) const -{ - if (mNoLock) - return true; - - return flock (fileno (file), LOCK_EX) ? false : true; -} - -//////////////////////////////////////////////////////////////////////////////// -bool TDB::overwritePending (std::vector & all) -{ - // Write a single task to the pending file - FILE* out; - if ((out = fopen (mPendingFile.c_str (), "w"))) - { - int retry = 0; - if (!mNoLock) - while (flock (fileno (out), LOCK_EX) && ++retry <= 3) - delay (0.1); - - std::vector ::iterator it; - for (it = all.begin (); it != all.end (); ++it) - fputs (it->compose ().c_str (), out); - - fclose (out); - return true; - } - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -bool TDB::writePending (const T& t) -{ - // Write a single task to the pending file - FILE* out; - if ((out = fopen (mPendingFile.c_str (), "a"))) - { - int retry = 0; - if (!mNoLock) - while (flock (fileno (out), LOCK_EX) && ++retry <= 3) - delay (0.1); - - fputs (t.compose ().c_str (), out); - fclose (out); - return true; - } - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -bool TDB::writeCompleted (const T& t) -{ - // Write a single task to the pending file - FILE* out; - if ((out = fopen (mCompletedFile.c_str (), "a"))) - { - int retry = 0; - if (!mNoLock) - while (flock (fileno (out), LOCK_EX) && ++retry <= 3) - delay (0.1); - - fputs (t.compose ().c_str (), out); - - fclose (out); - return true; - } - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -bool TDB::readLockedFile ( - const std::string& file, - std::vector & contents) const -{ - contents.clear (); - - if (! access (file.c_str (), F_OK | R_OK)) - { - FILE* in; - if ((in = fopen (file.c_str (), "r"))) - { - int retry = 0; - if (!mNoLock) - while (flock (fileno (in), LOCK_EX) && ++retry <= 3) - delay (0.1); - - char line[T_LINE_MAX]; - while (fgets (line, T_LINE_MAX, in)) + fseek (location->pending, 0, SEEK_SET); + while (fgets (line, T_LINE_MAX, location->pending)) { int length = ::strlen (line); if (length > 1) { + // TODO Add hidden attribute indicating source? line[length - 1] = '\0'; // Kill \n - contents.push_back (line); - } - } + Task task (line); + task.id = mId++; - fclose (in); - return true; + mPending.push_back (task); + if (filter.pass (task)) + tasks.push_back (task); + } + + ++line_number; + } } } - return false; + catch (std::string& e) + { + std::stringstream s; + s << " int " << file << " at line " << line_number; + throw e + s.str (); + } + + return tasks.size (); +} + +//////////////////////////////////////////////////////////////////////////////// +// Returns number of filtered tasks. +// Note: tasks.clear () is deliberately not called, to allow the combination of +// multiple files. +int TDB::loadCompleted (std::vector & tasks, Filter& filter) +{ + std::string file; + int line_number; + + try + { + char line[T_LINE_MAX]; + foreach (location, mLocations) + { + // TODO If the filter contains Status:x where x is not deleted or + // completed, then this can be skipped. + + line_number = 1; + file = location->path + "/completed.data"; + + fseek (location->completed, 0, SEEK_SET); + while (fgets (line, T_LINE_MAX, location->completed)) + { + int length = ::strlen (line); + if (length > 1) + { + // TODO Add hidden attribute indicating source? + line[length - 1] = '\0'; // Kill \n + Task task (line); + task.id = mId++; + +// mCompleted.push_back (task); + if (filter.pass (task)) + tasks.push_back (task); + } + + ++line_number; + } + } + } + + catch (std::string& e) + { + std::stringstream s; + s << " int " << file << " at line " << line_number; + throw e + s.str (); + } + + return tasks.size (); +} + +//////////////////////////////////////////////////////////////////////////////// +// TODO Write to transaction log. +// Note: mLocations[0] is where all tasks are written. +void TDB::add (Task& task) +{ + mNew.push_back (task); +} + +//////////////////////////////////////////////////////////////////////////////// +// TODO Write to transaction log. +void TDB::update (Task& before, Task& after) +{ + mModified.push_back (after); +} + +//////////////////////////////////////////////////////////////////////////////// +// TODO Writes all, including comments +// Interestingly, only the pending file gets written to. The completed file is +// only modified by TDB::gc. +int TDB::commit () +{ + int quantity = mNew.size () + mModified.size (); + + // This is an optimization. If there are only new tasks, and none were + // modified, simply seek to the end of pending and write. + if (mNew.size () && ! mModified.size ()) + { + fseek (mLocations[0].pending, 0, SEEK_END); + foreach (task, mNew) + { + mPending.push_back (*task); + fputs (task->composeF4 ().c_str (), mLocations[0].pending); + } + + mNew.clear (); + return quantity; + } + + // The alternative is to potentially rewrite both files. + else if (mNew.size () || mModified.size ()) + { + foreach (task, mPending) + foreach (mtask, mModified) + if (task->id == mtask->id) + *task = *mtask; + + mModified.clear (); + + foreach (task, mNew) + mPending.push_back (*task); + + mNew.clear (); + + // Write out all pending. + fseek (mLocations[0].pending, 0, SEEK_SET); + // TODO Do I need to truncate the file? Does file I/O even work that way + // any more? I forget. + foreach (task, mPending) + fputs (task->composeF4 ().c_str (), mLocations[0].pending); + } + + return quantity; +} + +//////////////////////////////////////////////////////////////////////////////// +// TODO -> FF4 +void TDB::upgrade () +{ + // TODO Read all pending + // TODO Write out all pending + + // TODO Read all completed + // TODO Write out all completed + + throw std::string ("unimplemented TDB::upgrade"); } //////////////////////////////////////////////////////////////////////////////// @@ -412,7 +337,7 @@ bool TDB::readLockedFile ( int TDB::gc () { int count = 0; - +/* // Read everything from the pending file. std::vector all; allPendingT (all); @@ -442,21 +367,33 @@ int TDB::gc () // task was transferred. if (count) overwritePending (pending); - +*/ return count; } //////////////////////////////////////////////////////////////////////////////// -int TDB::nextId () +FILE* TDB::openAndLock (const std::string& file) { - return mId++; + // Check for access. + if (access (file.c_str (), F_OK | R_OK | W_OK)) + throw std::string ("Task does not have the correct permissions for '") + + file + "'."; + + // Open the file. + FILE* in = fopen (file.c_str (), "r+"); + if (!in) + throw std::string ("Could not open '") + file + "'."; + + // Lock if desired. Try three times before failing. + int retry = 0; + if (mLock) + while (flock (fileno (in), LOCK_EX) && ++retry <= 3) + delay (0.1); + + if (retry > 3) + throw std::string ("Could not lock '") + file + "'."; + + return in; } //////////////////////////////////////////////////////////////////////////////// -void TDB::noLock () -{ - mNoLock = true; -} - -//////////////////////////////////////////////////////////////////////////////// - diff --git a/src/TDB.h b/src/TDB.h index e2c0257ec..1af552d16 100644 --- a/src/TDB.h +++ b/src/TDB.h @@ -27,41 +27,54 @@ #ifndef INCLUDED_TDB #define INCLUDED_TDB +#include #include #include -#include "T.h" +#include +#include +#include + +// Length of longest line. +#define T_LINE_MAX 32768 class TDB { public: - TDB (); - ~TDB (); + TDB (); // Default constructor + ~TDB (); // Destructor - void dataDirectory (const std::string&); - bool allT (std::vector &); - bool pendingT (std::vector &); - bool allPendingT (std::vector &); - bool completedT (std::vector &) const; - bool allCompletedT (std::vector &) const; - bool addT (const T&); - bool modifyT (const T&); - int gc (); - int nextId (); + void clear (); + void location (const std::string&); - void noLock (); + void lock (bool lockFile = true); + void unlock (); + + int load (std::vector &, Filter&); + int loadPending (std::vector &, Filter&); + int loadCompleted (std::vector &, Filter&); + + void add (Task&); // Single task add to pending + void update (Task&, Task&); // Single task update to pending + int commit (); // Write out all tasks + void upgrade (); // Convert both files to FF4 + int gc (); // Clean up pending private: - bool lock (FILE*) const; - bool overwritePending (std::vector &); - bool writePending (const T&); - bool writeCompleted (const T&); - bool readLockedFile (const std::string&, std::vector &) const; + FILE* openAndLock (const std::string&); private: - std::string mPendingFile; - std::string mCompletedFile; + std::vector mLocations; + bool mLock; + bool mAllOpenAndLocked; int mId; - bool mNoLock; + + std::vector mPending; // Contents of pending.data +// std::vector mCompleted; // Contents of completed.data + + std::vector mNew; // Uncommitted new tasks + std::vector mModified; // Uncommitted modified tasks + + // TODO Need cache of raw file contents to preserve comments. }; #endif diff --git a/src/TDB2.cpp b/src/TDB2.cpp deleted file mode 100644 index 2c9357d89..000000000 --- a/src/TDB2.cpp +++ /dev/null @@ -1,346 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// task - a command line task list manager. -// -// Copyright 2006 - 2009, Paul Beckingham. -// All rights reserved. -// -// This program is free software; you can redistribute it and/or modify it under -// the terms of the GNU General Public License as published by the Free Software -// Foundation; either version 2 of the License, or (at your option) any later -// version. -// -// This program is distributed in the hope that it will be useful, but WITHOUT -// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more -// details. -// -// You should have received a copy of the GNU General Public License along with -// this program; if not, write to the -// -// Free Software Foundation, Inc., -// 51 Franklin Street, Fifth Floor, -// Boston, MA -// 02110-1301 -// USA -// -//////////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include -#include -#include "text.h" -#include "util.h" -#include "TDB2.h" -#include "main.h" - -//////////////////////////////////////////////////////////////////////////////// -// The ctor/dtor do nothing. -// The lock/unlock methods hold the file open. -// There should be only one commit. -// -// +- TDB::TDB -// | -// | +- TDB::lock -// | | open -// | | [lock] -// | | -// | | +- TDB::load (Filter) -// | | | read all -// | | | apply filter -// | | | return subset -// | | | -// | | +- TDB::add (T) -// | | | -// | | +- TDB::update (T, T') -// | | | -// | | +- TDB::commit -// | | write all -// | | -// | +- TDB::unlock -// | [unlock] -// | close -// | -// +- TDB::~TDB -// [TDB::unlock] -// -TDB2::TDB2 () -: mLock (true) -, mAllOpenAndLocked (false) -, mId (1) -{ -} - -//////////////////////////////////////////////////////////////////////////////// -TDB2::~TDB2 () -{ - if (mAllOpenAndLocked) - unlock (); -} - -//////////////////////////////////////////////////////////////////////////////// -void TDB2::clear () -{ - mLocations.clear (); - mLock = true; - - if (mAllOpenAndLocked) - unlock (); - - mAllOpenAndLocked = false; -} - -//////////////////////////////////////////////////////////////////////////////// -void TDB2::location (const std::string& path) -{ - if (access (expandPath (path).c_str (), F_OK)) - throw std::string ("Data location '") + - path + - "' does not exist, or is not readable and writable."; - - mLocations.push_back (Location (path)); -} - -//////////////////////////////////////////////////////////////////////////////// -void TDB2::lock (bool lockFile /* = true */) -{ - mLock = lockFile; - - foreach (location, mLocations) - { - location->pending = openAndLock (location->path + "/pending.data"); - location->completed = openAndLock (location->path + "/completed.data"); - } - - mAllOpenAndLocked = true; -} - -//////////////////////////////////////////////////////////////////////////////// -void TDB2::unlock () -{ - if (mAllOpenAndLocked) - { - foreach (location, mLocations) - { - fclose (location->pending); - location->pending = NULL; - fclose (location->completed); - location->completed = NULL; - } - - mAllOpenAndLocked = false; - } -} - -//////////////////////////////////////////////////////////////////////////////// -// Returns number of filtered tasks. -// Note: tasks.clear () is deliberately not called, to allow the combination of -// multiple files. -int TDB2::load (std::vector & tasks, Filter& filter) -{ - loadPending (tasks, filter); - loadCompleted (tasks, filter); - - return tasks.size (); -} - -//////////////////////////////////////////////////////////////////////////////// -// Returns number of filtered tasks. -// Note: tasks.clear () is deliberately not called, to allow the combination of -// multiple files. -int TDB2::loadPending (std::vector & tasks, Filter& filter) -{ - std::string file; - int line_number; - - try - { - char line[T_LINE_MAX]; - foreach (location, mLocations) - { - line_number = 1; - file = location->path + "/pending.data"; - - fseek (location->pending, 0, SEEK_SET); - while (fgets (line, T_LINE_MAX, location->pending)) - { - int length = ::strlen (line); - if (length > 1) - { - // TODO Add hidden attribute indicating source? - line[length - 1] = '\0'; // Kill \n - Task task (line); - task.id = mId++; - - if (filter.pass (task)) - tasks.push_back (task); - } - - ++line_number; - } - } - } - - catch (std::string& e) - { - std::stringstream s; - s << " int " << file << " at line " << line_number; - throw e + s.str (); - } - - return tasks.size (); -} - -//////////////////////////////////////////////////////////////////////////////// -// Returns number of filtered tasks. -// Note: tasks.clear () is deliberately not called, to allow the combination of -// multiple files. -int TDB2::loadCompleted (std::vector & tasks, Filter& filter) -{ - std::string file; - int line_number; - - try - { - char line[T_LINE_MAX]; - foreach (location, mLocations) - { - // TODO If the filter contains Status:x where x is not deleted or - // completed, then this can be skipped. - - line_number = 1; - file = location->path + "/completed.data"; - - fseek (location->completed, 0, SEEK_SET); - while (fgets (line, T_LINE_MAX, location->completed)) - { - int length = ::strlen (line); - if (length > 1) - { - // TODO Add hidden attribute indicating source? - line[length - 1] = '\0'; // Kill \n - Task task (line); - task.id = mId++; - - if (filter.pass (task)) - tasks.push_back (task); - } - - ++line_number; - } - } - } - - catch (std::string& e) - { - std::stringstream s; - s << " int " << file << " at line " << line_number; - throw e + s.str (); - } - - return tasks.size (); -} - -//////////////////////////////////////////////////////////////////////////////// -// TODO Write to transaction log. -// Note: mLocations[0] is where all tasks are written. -void TDB2::add (Task& after) -{ - // Seek to end of pending. - fseek (mLocations[0].pending, 0, SEEK_END); - - // Write after.composeF4 (). - fputs (after.composeF4 ().c_str (), mLocations[0].pending); -} - -//////////////////////////////////////////////////////////////////////////////// -// TODO Write to transaction log. -void TDB2::update (Task& before, Task& after) -{ - throw std::string ("unimplemented TDB2::update"); -} - -//////////////////////////////////////////////////////////////////////////////// -// TODO Writes all, including comments -int TDB2::commit () -{ - // TODO Two passes: first the pending file. - // then the completed file. - - throw std::string ("unimplemented TDB2::commit"); -} - -//////////////////////////////////////////////////////////////////////////////// -// TODO -> FF4 -void TDB2::upgrade () -{ - throw std::string ("unimplemented TDB2::upgrade"); -} - -//////////////////////////////////////////////////////////////////////////////// -// Scans the pending tasks for any that are completed or deleted, and if so, -// moves them to the completed.data file. Returns a count of tasks moved. -int TDB2::gc () -{ - int count = 0; -/* - // Read everything from the pending file. - std::vector all; - allPendingT (all); - - // A list of the truly pending tasks. - std::vector pending; - - std::vector::iterator it; - for (it = all.begin (); it != all.end (); ++it) - { - // Some tasks stay in the pending file. - if (it->getStatus () == T::pending || - it->getStatus () == T::recurring) - { - pending.push_back (*it); - } - - // Others are transferred to the completed file. - else - { - writeCompleted (*it); - ++count; - } - } - - // Dump all clean tasks into pending. But don't bother unless at least one - // task was transferred. - if (count) - overwritePending (pending); -*/ - return count; -} - -//////////////////////////////////////////////////////////////////////////////// -FILE* TDB2::openAndLock (const std::string& file) -{ - // Check for access. - if (access (file.c_str (), F_OK | R_OK | W_OK)) - throw std::string ("Task does not have the correct permissions for '") + - file + "'."; - - // Open the file. - FILE* in = fopen (file.c_str (), "r+"); - if (!in) - throw std::string ("Could not open '") + file + "'."; - - // Lock if desired. Try three times before failing. - int retry = 0; - if (mLock) - while (flock (fileno (in), LOCK_EX) && ++retry <= 3) - delay (0.1); - - if (retry > 3) - throw std::string ("Could not lock '") + file + "'."; - - return in; -} - -//////////////////////////////////////////////////////////////////////////////// diff --git a/src/TDB2.h b/src/TDB2.h deleted file mode 100644 index bd099c442..000000000 --- a/src/TDB2.h +++ /dev/null @@ -1,75 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// task - a command line task list manager. -// -// Copyright 2006 - 2009, Paul Beckingham. -// All rights reserved. -// -// This program is free software; you can redistribute it and/or modify it under -// the terms of the GNU General Public License as published by the Free Software -// Foundation; either version 2 of the License, or (at your option) any later -// version. -// -// This program is distributed in the hope that it will be useful, but WITHOUT -// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more -// details. -// -// You should have received a copy of the GNU General Public License along with -// this program; if not, write to the -// -// Free Software Foundation, Inc., -// 51 Franklin Street, Fifth Floor, -// Boston, MA -// 02110-1301 -// USA -// -//////////////////////////////////////////////////////////////////////////////// -#ifndef INCLUDED_TDB2 -#define INCLUDED_TDB2 - -#include -#include -#include -#include -#include -#include - -// Length of longest line. -#define T_LINE_MAX 32768 - -class TDB2 -{ -public: - TDB2 (); // Default constructor - ~TDB2 (); // Destructor - - void clear (); - void location (const std::string&); - - void lock (bool lockFile = true); - void unlock (); - - int load (std::vector &, Filter&); - int loadPending (std::vector &, Filter&); - int loadCompleted (std::vector &, Filter&); - - void add (Task&); // Single task add to pending - void update (Task&, Task&); // Single task update to pending - int commit (); // Write out all tasks - void upgrade (); // Convert both files to FF4 - int gc (); // Clean up pending - -private: - FILE* openAndLock (const std::string&); - -private: - std::vector mLocations; - bool mLock; - bool mAllOpenAndLocked; - int mId; - - // TODO Need cache of raw file contents to preserve comments. -}; - -#endif -//////////////////////////////////////////////////////////////////////////////// diff --git a/src/tests/.gitignore b/src/tests/.gitignore index 09b9555f7..dd6441689 100644 --- a/src/tests/.gitignore +++ b/src/tests/.gitignore @@ -1,5 +1,4 @@ t.t -t2.t t.benchmark.t tdb.t date.t diff --git a/src/tests/Makefile b/src/tests/Makefile index 95c1f6d6f..2d5a6b96b 100644 --- a/src/tests/Makefile +++ b/src/tests/Makefile @@ -1,9 +1,9 @@ -PROJECT = t2.t tdb.t date.t duration.t t.benchmark.t text.t autocomplete.t \ +PROJECT = t.t tdb.t date.t duration.t t.benchmark.t text.t autocomplete.t \ config.t seq.t att.t stringtable.t record.t nibbler.t subst.t filt.t \ cmd.t CFLAGS = -I. -I.. -Wall -pedantic -ggdb3 -fno-rtti LFLAGS = -L/usr/local/lib -lncurses -OBJECTS = ../TDB2.o ../Task.o ../valid.o ../text.o ../Date.o ../Table.o \ +OBJECTS = ../TDB.o ../Task.o ../valid.o ../text.o ../Date.o ../Table.o \ ../Duration.o ../util.o ../Config.o ../Sequence.o ../Att.o ../Cmd.o \ ../Record.o ../StringTable.o ../Subst.o ../Nibbler.o ../Location.o \ ../Filter.o ../Context.o ../Keymap.o ../command.o ../interactive.o \ @@ -23,8 +23,8 @@ clean: .cpp.o: g++ -c $(CFLAGS) $< -t2.t: t2.t.o $(OBJECTS) test.o - g++ t2.t.o $(OBJECTS) test.o $(LFLAGS) -o t2.t +t.t: t.t.o $(OBJECTS) test.o + g++ t.t.o $(OBJECTS) test.o $(LFLAGS) -o t.t tdb.t: tdb.t.o $(OBJECTS) test.o g++ tdb.t.o $(OBJECTS) test.o $(LFLAGS) -o tdb.t diff --git a/src/tests/t2.t.cpp b/src/tests/t.t.cpp similarity index 100% rename from src/tests/t2.t.cpp rename to src/tests/t.t.cpp