Compare commits

...

26 Commits

Author SHA1 Message Date
Paul Beckingham
c393d47cdf - Corrected bogus .gitignore entry that blocked src/tests/Makefile. 2008-06-13 01:51:51 -04:00
Paul Beckingham
3525b6db2c - Added Bruce Israel for his suggestion of subprojects. 2008-06-13 01:25:38 -04:00
Paul Beckingham
d50efe5e27 - Updated versions 2008-06-13 01:18:53 -04:00
Paul Beckingham
2c0a1ddb3a - Added new feature for 1.2.0 2008-06-13 01:15:49 -04:00
Paul Beckingham
d7ac37783c - Updated documentation to include subproject discussions.
- Added Richard Querin to the AUTHORS file for his contribution of ideas and a .deb package.
2008-06-13 01:02:17 -04:00
Paul Beckingham
03bb50c4ea - Corrected copyright display. 2008-06-13 00:19:54 -04:00
Paul Beckingham
1535010ac9 - "Age" column is now optional for the "list" and "next" reports. 2008-06-13 00:18:28 -04:00
Paul Beckingham
8d90035bbc - Now properly parses dates according to specified date format. 2008-06-12 23:58:58 -04:00
Paul Beckingham
fd7bb9daa9 - Support subprojects. 2008-06-11 02:19:00 -04:00
Paul Beckingham
88b12bc66a - Added caseless keyword comparison to the autocolorization rules. 2008-06-11 01:47:11 -04:00
Paul Beckingham
a8ac82ca22 - Added "What's new in 1.2.0" section. 2008-06-11 01:45:07 -04:00
Paul Beckingham
438f3cb134 - Added caseless comparison when searching keywords in the description. 2008-06-11 01:40:01 -04:00
Paul Beckingham
131693f617 - Fixed bug whereby the "dateformat" configuration variable was being used to display dates, but not parse them. 2008-06-11 01:14:22 -04:00
Paul Beckingham
07d1f63e31 - Bumped version to 1.2.0 2008-06-10 22:59:43 -04:00
Paul Beckingham
73286e8662 - Cleaned up visible copyright.
- Added a "what's new" list to task.html
2008-06-07 23:29:32 -04:00
Paul Beckingham
95c3f78c68 - Added tags to the "long" report. 2008-06-07 23:13:07 -04:00
Paul Beckingham
90df505982 - Added Google AdSense to the task.html page. 2008-06-07 22:53:18 -04:00
Paul Beckingham
e8b7114ce8 - Added the ability to control date formats via the 'dateformat' configuration variable. 2008-06-07 17:09:09 -04:00
Paul Beckingham
714d9c5544 - Included new changes 2008-06-07 13:28:27 -04:00
Paul Beckingham
f2ba9f796b - Bumped version to 1.1.0 2008-06-07 13:23:59 -04:00
Paul Beckingham
e025ecc3d4 - Configurable extra white space via "blanklines" configuration variable. 2008-06-07 13:23:39 -04:00
Paul Beckingham
ccd2b9fc44 - Added Cygwin to the platform list.
- Added missing items to the TUTORIAL file.
- Converted TUTORIAL to HTML, in task.html.
2008-06-06 01:38:37 -04:00
Paul Beckingham
6cb902c499 - Home page update. 2008-06-05 21:08:37 -04:00
Paul Beckingham
d216d40121 - Now points to 1.0.1 2008-06-04 21:22:45 -04:00
Paul Beckingham
08f4ead97e - Fixed bug whereby the UUID generated by the custom generator was not terminated.
- Fixed bug whereby random numbers were used by the custom UUID generator, but srandom/srand was not called first.
2008-06-04 21:00:23 -04:00
Paul Beckingham
f3de5c0711 - Added bare-bones task.html to point to the latest version. 2008-06-04 19:26:35 -04:00
23 changed files with 1950 additions and 265 deletions

10
AUTHORS
View File

@@ -1,6 +1,10 @@
Principal Author Principal Author:
Paul Beckingham, paul@beckingham.net Paul Beckingham, paul@beckingham.net
Contributing Authors With thanks to:
Eugene Kramer
SK
Damian Glenny
Richard Querin
Bruce Israel

View File

@@ -1,8 +1,38 @@
1.1.0 (?) Version numbers are of the form:
- Command line specification of alternate .taskrc file
x.y.z
where the x represents a major version number, or architecture. The y
represents a feature release, and the z represents a patch.
------ plans -------------------------------------
Configurable columns in reports
------ reality ----------------------------------- ------ reality -----------------------------------
1.2.0 (6/13/2008)
+ Bug: "dateformat" configuration variable used to display dates, but
not parse them
+ "task list x" now performs a caseless comparison between "x" and the
description
+ Task sub projects supported
+ "showage" confguration determines whether "Age" column appears on the
"list" and "next" reports
+ Improved TUTORIAL
1.1.0 (6/7/2008)
+ "blanklines" configuration to stop displaying unnecessary white
space and thus work better on small-screen devices
+ "dateformat" configuration now determines how dates are formatted
+ Better formatting of "task tags" output
+ http://www.beckingham.net/task.html home page set up
+ Added tags to the "task long" report
1.0.1 (6/4/2008)
+ Bug: UUID generator not properly terminating string.
+ Bug: srandom/srand not called prior to UUID generation.
1.0.0 (6/3/2008) 1.0.0 (6/3/2008)
+ New movie made, uploaded + New movie made, uploaded
+ Bug: assertion fails on mobile for t v + Bug: assertion fails on mobile for t v
@@ -108,6 +138,7 @@
+ File locking + File locking
+ retain deleted tasks + retain deleted tasks
+ "task info ID" report showing all metadata + "task info ID" report showing all metadata
+ File format v2
[Development hiatus while planning for T, TDB API, new features and the future [Development hiatus while planning for T, TDB API, new features and the future
of the project. Seeded to two testers for feedback, suggestions.] of the project. Seeded to two testers for feedback, suggestions.]

3
NEWS
View File

@@ -1,4 +1,4 @@
Welcome to Task 1.0.0. Welcome to Task 1.2.0.
Task has been built and tested on the following configurations: Task has been built and tested on the following configurations:
@@ -8,6 +8,7 @@ Task has been built and tested on the following configurations:
- Fedora Core 9 - Fedora Core 9
- Ubuntu 8 Hardy Heron - Ubuntu 8 Hardy Heron
- Solaris 10 - Solaris 10
- Cygwin 1.5.25-14
While Task has undergone testing, bugs are sure to remain. If you encounter a While Task has undergone testing, bugs are sure to remain. If you encounter a
bug, please contact me at task@beckingham.net. Here is what you could do, in bug, please contact me at task@beckingham.net. Here is what you could do, in

137
TUTORIAL
View File

@@ -1,4 +1,4 @@
Task program tutorial, for version 1.0.0 Task program tutorial, for version 1.2.0
---------------------------------------- ----------------------------------------
This guide shows how to quickly set up the task program, and become proficient This guide shows how to quickly set up the task program, and become proficient
@@ -21,10 +21,10 @@ Build the task program according to the directions in the INSTALL file. This
transcript illustrates a typical installation: transcript illustrates a typical installation:
% ls % ls
task-1.0.0.tar.gz task-1.2.0.tar.gz
% gunzip task-1.0.0.tar.gz % gunzip task-1.2.0.tar.gz
% tar xf task-1.0.0.tar % tar xf task-1.2.0.tar
% cd task-1.0.0 % cd task-1.2.0
% ./configure % ./configure
... ...
% make % make
@@ -67,7 +67,7 @@ interface. Let us take a look at those tasks:
% task ls % task ls
ID Project Pri Description ID Project Pri Description
1 Book plane ticket 1 Book plane ticket
2 Rent a tux 2 Rent a tux
3 Reserve a rental car 3 Reserve a rental car
@@ -97,7 +97,7 @@ a project to these tasks:
% task 4 project:Family % task 4 project:Family
% task ls % task ls
ID Project Pri Description ID Project Pri Description
3 Family Send John a birthday card 3 Family Send John a birthday card
2 Wedding Reserve a rental car 2 Wedding Reserve a rental car
1 Wedding Book plane ticket 1 Wedding Book plane ticket
@@ -107,12 +107,46 @@ attributes changed (project, for example), the ids are prone to change. But the
id numbers will remain valid until the next 'ls' command is run. You should id numbers will remain valid until the next 'ls' command is run. You should
only use the ids from the most recent 'ls' command. The ids change, because only use the ids from the most recent 'ls' command. The ids change, because
task is always trying to use small numbers so that it is easy for you to enter task is always trying to use small numbers so that it is easy for you to enter
them correctly. Now that projects are assigned, we can look at just the Wedding them correctly.
project tasks:
Subprojects are supported. If you have a project "Wedding", you can specify
that a task is a subproject "Transport" of "Wedding" by assigning the project
"Wedding.Transport". Let's do this:
% task 2 project:Wedding.Transport
% task ls
ID Project Pri Description
3 Family Send John a birthday card
2 Wedding.Transport Reserve a rental car
1 Wedding Book plane ticket
Task matches the leftmost part of the project when searching, so projects
may be abbreviated:
% task ls project:Wedding.Tra
ID Project Pri Description
2 Wedding.Transport Reserve a rental car
This way of matching projects can be used to see all tasks under the
"Wedding" project and all subprojects:
% task ls project:Wedding % task ls project:Wedding
ID Project Pri Description ID Project Pri Description
2 Wedding.Transport Reserve a rental car
1 Wedding Book plane ticket
Let's reassign 2 back to the "Wedding" project:
% task 2 project:Wedding
Now that projects are assigned, we can look at just the Wedding project tasks:
% task ls project:Wedding
ID Project Pri Description
1 Wedding Book plane ticket 1 Wedding Book plane ticket
2 Wedding Reserve a rental car 2 Wedding Reserve a rental car
@@ -121,14 +155,14 @@ could also have requested:
% task ls ticket plane % task ls ticket plane
ID Project Pri Description ID Project Pri Description
1 Wedding Book plane ticket 1 Wedding Book plane ticket
Now let's prioritize. Priorities can be H, M or L (High, Medium, Low). Now let's prioritize. Priorities can be H, M or L (High, Medium, Low).
% task ls % task ls
ID Project Pri Description ID Project Pri Description
3 Family Send John a birthday card 3 Family Send John a birthday card
2 Wedding Reserve a rental car 2 Wedding Reserve a rental car
1 Wedding Book plane ticket 1 Wedding Book plane ticket
@@ -140,7 +174,7 @@ Now let's prioritize. Priorities can be H, M or L (High, Medium, Low).
% task 3 pri:H % task 3 pri:H
% task ls % task ls
ID Project Pri Description ID Project Pri Description
3 Family H Send John a birthday card 3 Family H Send John a birthday card
1 Wedding H Book plane ticket 1 Wedding H Book plane ticket
2 Wedding M Reserve a rental car 2 Wedding M Reserve a rental car
@@ -161,7 +195,7 @@ command provides more:
% task list % task list
ID Project Pri Due Active Age Description ID Project Pri Due Active Age Description
3 Family H 4 mins Send John a birthday card 3 Family H 4 mins Send John a birthday card
1 Wedding H 5 mins Book plane ticket 1 Wedding H 5 mins Book plane ticket
2 Wedding M 5 mins Reserve a rental car 2 Wedding M 5 mins Reserve a rental car
@@ -173,7 +207,7 @@ sorted by due date, then priority. Let's add due dates:
% task 1 due:7/31/2008 % task 1 due:7/31/2008
% task list % task list
ID Project Pri Due Active Age Description ID Project Pri Due Active Age Description
3 Family H 6/25/2008 6 mins Send John a birthday card 3 Family H 6/25/2008 6 mins Send John a birthday card
1 Wedding H 7/31/2008 7 mins Book plane ticket 1 Wedding H 7/31/2008 7 mins Book plane ticket
2 Wedding M 7 mins Reserve a rental car 2 Wedding M 7 mins Reserve a rental car
@@ -212,7 +246,7 @@ labels.
% task list % task list
ID Project Pri Due Active Age Description ID Project Pri Due Active Age Description
3 Family H 6/25/2008 8 mins Send John a birthday card 3 Family H 6/25/2008 8 mins Send John a birthday card
1 Wedding H 7/31/2008 9 mins Book plane ticket 1 Wedding H 7/31/2008 9 mins Book plane ticket
2 Wedding M 9 mins Reserve a rental car 2 Wedding M 9 mins Reserve a rental car
@@ -224,7 +258,7 @@ labels.
% task list +phone % task list +phone
ID Project Pri Due Active Age Description ID Project Pri Due Active Age Description
1 Wedding H 7/31/2008 9 mins Book plane ticket 1 Wedding H 7/31/2008 9 mins Book plane ticket
2 Wedding M 9 mins Reserve a rental car 2 Wedding M 9 mins Reserve a rental car
@@ -266,7 +300,7 @@ with no arguments will generate a help message that lists all these commands.
% task summary % task summary
Project Remaining Avg age Complete 0% 100% Project Remaining Avg age Complete 0% 100%
Errands 1 3 days 50% XXXXXXXXXXXXXXXX Errands 1 3 days 50% XXXXXXXXXXXXXXXX
Birthdays 3 7 mths 0% Birthdays 3 7 mths 0%
Car 2 2 wks 25% XXXXXXXXX Car 2 2 wks 25% XXXXXXXXX
@@ -316,14 +350,14 @@ with no arguments will generate a help message that lists all these commands.
% task list % task list
ID Project Pri Due Active Age Description ID Project Pri Due Active Age Description
12 Errand L Remember to deposit check 12 Errand L Remember to deposit check
... ...
% task start 12 % task start 12
% task list % task list
ID Project Pri Due Active Age Description ID Project Pri Due Active Age Description
12 Errand L * 3 days Remember to deposit check 12 Errand L * 3 days Remember to deposit check
... ...
@@ -351,7 +385,7 @@ with no arguments will generate a help message that lists all these commands.
This report shows you an overview of how many tasks were added, completed and This report shows you an overview of how many tasks were added, completed and
deleted, by month. It looks like this: deleted, by month. It looks like this:
% task history % task history
Year Month Added Completed Deleted Net Year Month Added Completed Deleted Net
2008 March 21 16 0 5 2008 March 21 16 0 5
@@ -409,14 +443,14 @@ with no arguments will generate a help message that lists all these commands.
% task ls % task ls
ID Project Pri Description ID Project Pri Description
12 Errand L Remember to deposit chekc 12 Errand L Remember to deposit chekc
... ...
% task 12 Remember to deposit bonus check % task 12 Remember to deposit bonus check
% task ls % task ls
ID Project Pri Description ID Project Pri Description
12 Errand L Remember to deposit bonus check 12 Errand L Remember to deposit bonus check
... ...
@@ -430,14 +464,14 @@ with no arguments will generate a help message that lists all these commands.
% task ls % task ls
ID Project Pri Description ID Project Pri Description
12 Errand L Remember to deposit chekc 12 Errand L Remember to deposit chekc
... ...
% task 12 /chekc/check/ % task 12 /chekc/check/
% task ls % task ls
ID Project Pri Description ID Project Pri Description
12 Errand L Remember to deposit check 12 Errand L Remember to deposit check
... ...
@@ -554,8 +588,27 @@ Interacting with the Shell
background) attributes determines the colors used to represent the task. background) attributes determines the colors used to represent the task.
Valid foreground colors are: Valid foreground colors are:
bold underline bold_underline
black bold_black underline_black bold_underline_black
red bold_red underline_red bold_underline_red
green bold_green underline_green bold_underline_green
yellow bold_yellow underline_yellow bold_underline_yellow
blue bold_blue underline_blue bold_underline_blue
magenta bold_magenta underline_magenta bold_underline_magenta
cyan bold_cyan underline_cyan bold_underline_cyan
white bold_white underline_white bold_underline_white
Valid background colors are: Valid background colors are:
on_black on_bright_black
on_red on_bright_red
on_green on_bright_green
on_yellow on_bright_yellow
on_blue on_bright_blue
on_magenta on_bright_magenta
on_cyan on_bright_cyan
on_white on_bright_white
Note that these are not just colors, but combinations of colors and Note that these are not just colors, but combinations of colors and
attributes. attributes.
@@ -602,6 +655,38 @@ Configuring Task
curses Determines whether task uses ncurses to establish the curses Determines whether task uses ncurses to establish the
size of the window you are using, for text wrapping. size of the window you are using, for text wrapping.
blanklines May be "on" or "off". Prevents the display of
unnecessary blank lines so that task makes better use
screen real estate on small-screened devices.
dateformat This is a string of characters that define how task
formats dates. The default value is:
m/d/Y
which means dates look like:
6/7/2008
The string should contain the characters:
m minimal-digit month 1, 12
d minimal-digit day 1, 30
y two-digit year 08
M two-digit month 01, 12
D two-digit day 01, 30
Y four-digit year 2008
The string may also contain other characters to act as
spacers, or formatting. Other values could include:
d/m/Y 7/6/2008
YMD 20080607
m-d-y 6-7-08
showage May be "yes" or "no". Determines whether the "Age"
column appears on the "list" and "next" reports.
color May be "on" or "off". Determines whether task uses color May be "on" or "off". Determines whether task uses
color. color.
@@ -614,7 +699,7 @@ Configuring Task
color.active below) and one optional background color. color.active below) and one optional background color.
color.tagged color.tagged
For example, the value may be: For example, the value may be:
bold_red on_bright_yellow bold_red on_bright_yellow
color.tag.X Colors any task that has the tag X. color.tag.X Colors any task that has the tag X.

12
adsense.html Normal file
View File

@@ -0,0 +1,12 @@
<script type="text/javascript"><!--
google_ad_client = "pub-9709799404235424";
/* Task Main */
google_ad_slot = "8660617875";
google_ad_width = 120;
google_ad_height = 600;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>

View File

@@ -2,7 +2,7 @@
# Process this file with autoconf to produce a configure script. # Process this file with autoconf to produce a configure script.
AC_PREREQ(2.61) AC_PREREQ(2.61)
AC_INIT(task, 1.0.0, bugs@beckingham.net) AC_INIT(task, 1.2.0, bugs@beckingham.net)
AM_INIT_AUTOMAKE AM_INIT_AUTOMAKE
AC_CONFIG_SRCDIR([src/task.cpp]) AC_CONFIG_SRCDIR([src/task.cpp])
AC_CONFIG_HEADER([auto.h]) AC_CONFIG_HEADER([auto.h])
@@ -35,6 +35,8 @@ AC_FUNC_SELECT_ARGTYPES
AC_CHECK_FUNCS([select]) AC_CHECK_FUNCS([select])
AC_CHECK_FUNC(flock, [AC_DEFINE([HAVE_FLOCK], [1], [Found flock])]) AC_CHECK_FUNC(flock, [AC_DEFINE([HAVE_FLOCK], [1], [Found flock])])
AC_CHECK_FUNC(uuid_unparse_lower, [AC_DEFINE([HAVE_UUID], [1], [Found uuid_unparse_lower])]) AC_CHECK_FUNC(uuid_unparse_lower, [AC_DEFINE([HAVE_UUID], [1], [Found uuid_unparse_lower])])
AC_CHECK_FUNC(random, [AC_DEFINE([HAVE_RANDOM], [1], [Found random])])
AC_CHECK_FUNC(srandom, [AC_DEFINE([HAVE_SRANDOM], [1], [Found srandom])])
AC_CONFIG_FILES([Makefile src/Makefile]) AC_CONFIG_FILES([Makefile src/Makefile])
AC_OUTPUT AC_OUTPUT

2
src/.gitignore vendored
View File

@@ -1,2 +1,2 @@
Makefile ./Makefile
*.o *.o

View File

@@ -136,7 +136,7 @@ void Config::createDefault (const std::string& file)
set ("data.location", taskDir); set ("data.location", taskDir);
set ("command.logging", "off"); set ("command.logging", "off");
set ("confirmation", "yes"); set ("confirmation", "yes");
set ("next", 2); set ("next", 1);
set ("curses", "on"); set ("curses", "on");
set ("color", "on"); set ("color", "on");
set ("color.overdue", "red"); set ("color.overdue", "red");

View File

@@ -57,29 +57,134 @@ Date::Date (const int m, const int d, const int y)
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
Date::Date (const std::string& mdy) Date::Date (const std::string& mdy, const std::string format /* = "m/d/Y" */)
{ {
size_t firstSlash = mdy.find ("/"); int month = 0;
size_t secondSlash = mdy.find ("/", firstSlash + 1); int day = 0;
if (firstSlash != std::string::npos && int year = 0;
secondSlash != std::string::npos)
{
int m = ::atoi (mdy.substr (0, firstSlash ).c_str ());
int d = ::atoi (mdy.substr (firstSlash + 1, secondSlash - firstSlash).c_str ());
int y = ::atoi (mdy.substr (secondSlash + 1, std::string::npos ).c_str ());
if (!valid (m, d, y))
throw std::string ("\"") + mdy + "\" is not a valid date.";
// Duplicate Date::Date (const int, const int, const int); unsigned int i = 0; // Index into mdy.
struct tm t = {0};
t.tm_mday = d; for (unsigned int f = 0; f < format.length (); ++f)
t.tm_mon = m - 1; {
t.tm_year = y - 1900; switch (format[f])
{
// Single or double digit.
case 'm':
if (i >= mdy.length () ||
! ::isdigit (mdy[i]))
{
throw std::string ("\"") + mdy + "\" is not a valid date.";
}
if (i + 1 < mdy.length () &&
mdy[i + 0] == '1' &&
(mdy[i + 1] == '0' || mdy[i + 1] == '1' || mdy[i + 1] == '2'))
{
month = ::atoi (mdy.substr (i, 2).c_str ());
i += 2;
}
else
{
month = ::atoi (mdy.substr (i, 1).c_str ());
++i;
}
break;
case 'd':
if (i >= mdy.length () ||
! ::isdigit (mdy[i]))
{
throw std::string ("\"") + mdy + "\" is not a valid date.";
}
if (i + 1 < mdy.length () &&
(mdy[i + 0] == '1' || mdy[i + 0] == '2' || mdy[i + 0] == '3') &&
::isdigit (mdy[i + 1]))
{
day = ::atoi (mdy.substr (i, 2).c_str ());
i += 2;
}
else
{
day = ::atoi (mdy.substr (i, 1).c_str ());
++i;
}
break;
// Double digit.
case 'y':
if (i + 1 >= mdy.length () ||
! ::isdigit (mdy[i + 0]) ||
! ::isdigit (mdy[i + 1]))
{
throw std::string ("\"") + mdy + "\" is not a valid date.";
}
year = ::atoi (mdy.substr (i, 2).c_str ()) + 2000;
i += 2;
break;
case 'M':
if (i + 1 >= mdy.length () ||
! ::isdigit (mdy[i + 0]) ||
! ::isdigit (mdy[i + 1]))
{
throw std::string ("\"") + mdy + "\" is not a valid date.";
}
month = ::atoi (mdy.substr (i, 2).c_str ());
i += 2;
break;
case 'D':
if (i + 1 >= mdy.length () ||
! ::isdigit (mdy[i + 0]) ||
! ::isdigit (mdy[i + 1]))
{
throw std::string ("\"") + mdy + "\" is not a valid date.";
}
day = ::atoi (mdy.substr (i, 2).c_str ());
i += 2;
break;
// Quadruple digit.
case 'Y':
if (i + 3 >= mdy.length () ||
! ::isdigit (mdy[i + 0]) ||
! ::isdigit (mdy[i + 1]) ||
! ::isdigit (mdy[i + 2]) ||
! ::isdigit (mdy[i + 3]))
{
throw std::string ("\"") + mdy + "\" is not a valid date.";
}
year = ::atoi (mdy.substr (i, 4).c_str ());
i += 4;
break;
default:
if (i >= mdy.length () ||
mdy[i] != format[f])
{
throw std::string ("\"") + mdy + "\" is not a valid date.";
}
++i;
break;
}
}
if (!valid (month, day, year))
throw std::string ("\"") + mdy + "\" is not a valid date.";
// Duplicate Date::Date (const int, const int, const int);
struct tm t = {0};
t.tm_mday = day;
t.tm_mon = month - 1;
t.tm_year = year - 1900;
mT = mktime (&t); mT = mktime (&t);
}
else
throw std::string ("\"") + mdy + "\" is not a valid date.";
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@@ -116,20 +221,68 @@ void Date::toMDY (int& m, int& d, int& y)
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void Date::toString (std::string& output) std::string Date::toString (const std::string& format /*= "m/d/Y"*/)
{ {
output = toString (); std::string formatted;
} for (unsigned int i = 0; i < format.length (); ++i)
{
switch (format[i])
{
case 'm':
{
char m[3];
sprintf (m, "%d", this->month ());
formatted += m;
}
break;
//////////////////////////////////////////////////////////////////////////////// case 'M':
std::string Date::toString (void) {
{ char m[3];
int m, d, y; sprintf (m, "%02d", this->month ());
toMDY (m, d, y); formatted += m;
}
break;
char formatted [11]; case 'd':
sprintf (formatted, "%d/%d/%d", m, d, y); {
return std::string (formatted); char d[3];
sprintf (d, "%d", this->day ());
formatted += d;
}
break;
case 'D':
{
char d[3];
sprintf (d, "%02d", this->day ());
formatted += d;
}
break;
case 'y':
{
char y[3];
sprintf (y, "%02d", this->year () % 100);
formatted += y;
}
break;
case 'Y':
{
char y[5];
sprintf (y, "%d", this->year ());
formatted += y;
}
break;
default:
formatted += format[i];
break;
}
}
return formatted;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View File

@@ -37,15 +37,14 @@ public:
Date (); Date ();
Date (time_t); Date (time_t);
Date (const int, const int, const int); Date (const int, const int, const int);
Date (const std::string&); Date (const std::string&, const std::string format = "m/d/Y");
Date (const Date&); Date (const Date&);
virtual ~Date (); virtual ~Date ();
void toEpoch (time_t&); void toEpoch (time_t&);
time_t toEpoch (); time_t toEpoch ();
void toMDY (int&, int&, int&); void toMDY (int&, int&, int&);
void toString (std::string&); std::string toString (const std::string& format = "m/d/Y");
std::string toString (void);
static bool valid (const int, const int, const int); static bool valid (const int, const int, const int);
static bool leapYear (int); static bool leapYear (int);

View File

@@ -275,20 +275,8 @@ const std::string T::compose () const
int count = 0; int count = 0;
foreach (i, mAttributes) foreach (i, mAttributes)
{ {
std::string converted = i->second;
// Date attributes may need conversion to epoch.
if (i->first == "due" ||
i->first == "start" ||
i->first == "entry" ||
i->first == "end")
{
if (i->second.find ("/") != std::string::npos)
validDate (converted);
}
line += (count > 0 ? " " : ""); line += (count > 0 ? " " : "");
line += i->first + ":" + converted; line += i->first + ":" + i->second;
++count; ++count;
} }

View File

@@ -659,6 +659,12 @@ void Table::suppressWS ()
mSuppressWS = true; mSuppressWS = true;
} }
////////////////////////////////////////////////////////////////////////////////
void Table::setDateFormat (const std::string& dateFormat)
{
mDateFormat = dateFormat;
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
int Table::rowCount () int Table::rowCount ()
{ {
@@ -771,8 +777,8 @@ void Table::sort (std::vector <int>& order)
else else
{ {
Date dl ((std::string)*left); Date dl ((std::string)*left, mDateFormat);
Date dr ((std::string)*right); Date dr ((std::string)*right, mDateFormat);
if (dl > dr) if (dl > dr)
SWAP SWAP
} }
@@ -789,8 +795,8 @@ void Table::sort (std::vector <int>& order)
else else
{ {
Date dl ((std::string)*left); Date dl ((std::string)*left, mDateFormat);
Date dr ((std::string)*right); Date dr ((std::string)*right, mDateFormat);
if (dl < dr) if (dl < dr)
SWAP SWAP
} }

View File

@@ -79,6 +79,7 @@ public:
void setCellBg (int, int, Text::color); void setCellBg (int, int, Text::color);
void suppressWS (); void suppressWS ();
void setDateFormat (const std::string&);
int rowCount (); int rowCount ();
int columnCount (); int columnCount ();
@@ -128,6 +129,7 @@ private:
// Misc... // Misc...
bool mSuppressWS; bool mSuppressWS;
std::string mDateFormat;
}; };
#endif #endif

View File

@@ -185,29 +185,13 @@ static bool isCommand (const std::string& candidate)
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
bool validDate (std::string& date) bool validDate (std::string& date, Config& conf)
{ {
size_t firstSlash = date.find ("/"); Date test (date, conf.get ("dateformat", "m/d/Y"));
size_t secondSlash = date.find ("/", firstSlash + 1);
if (firstSlash != std::string::npos &&
secondSlash != std::string::npos)
{
int m = ::atoi (date.substr (0, firstSlash ).c_str ());
int d = ::atoi (date.substr (firstSlash + 1, secondSlash - firstSlash).c_str ());
int y = ::atoi (date.substr (secondSlash + 1, std::string::npos ).c_str ());
if (!Date::valid (m, d, y))
throw std::string ("\"") + date + "\" is not a valid date.";
// Convert to epoch form. char epoch[12];
Date dt (m, d, y); sprintf (epoch, "%d", (int) test.toEpoch ());
time_t t; date = epoch;
dt.toEpoch (t);
char converted[12];
sprintf (converted, "%u", (unsigned int) t);
date = converted;
}
else
throw std::string ("Badly formed date - use the MM/DD/YYYY format");
return true; return true;
} }
@@ -227,7 +211,7 @@ static bool validPriority (std::string& input)
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
static bool validAttribute (std::string& name, std::string& value) static bool validAttribute (std::string& name, std::string& value, Config& conf)
{ {
guess ("attribute", attributes, name); guess ("attribute", attributes, name);
@@ -235,7 +219,7 @@ static bool validAttribute (std::string& name, std::string& value)
guess ("color", colors, value); guess ("color", colors, value);
else if (name == "due" && value != "") else if (name == "due" && value != "")
validDate (value); validDate (value, conf);
else if (name == "priority") else if (name == "priority")
{ {
@@ -335,7 +319,8 @@ static bool validSubstitution (
void parse ( void parse (
std::vector <std::string>& args, std::vector <std::string>& args,
std::string& command, std::string& command,
T& task) T& task,
Config& conf)
{ {
command = ""; command = "";
@@ -369,7 +354,7 @@ void parse (
std::string name = arg.substr (0, colon); std::string name = arg.substr (0, colon);
std::string value = arg.substr (colon + 1, std::string::npos); std::string value = arg.substr (colon + 1, std::string::npos);
if (validAttribute (name, value)) if (validAttribute (name, value, conf))
task.setAttribute (name, value); task.setAttribute (name, value);
} }

View File

@@ -210,8 +210,9 @@ void autoColorize (T& task, Text::color& fg, Text::color& bg)
{ {
if (it->first.substr (0, 14) == "color.keyword.") if (it->first.substr (0, 14) == "color.keyword.")
{ {
std::string value = it->first.substr (14, std::string::npos); std::string value = lowerCase (it->first.substr (14, std::string::npos));
if (task.getDescription ().find (value) != std::string::npos) std::string desc = lowerCase (task.getDescription ());
if (desc.find (value) != std::string::npos)
{ {
fg = gsFg[it->first]; fg = gsFg[it->first];
bg = gsBg[it->first]; bg = gsBg[it->first];

View File

@@ -70,6 +70,7 @@ void usage (Config& conf)
table.setColumnWidth (1, Table::minimum); table.setColumnWidth (1, Table::minimum);
table.setColumnWidth (2, Table::flexible); table.setColumnWidth (2, Table::flexible);
table.setTableWidth (width); table.setTableWidth (width);
table.setDateFormat (conf.get ("dateformat", "m/d/Y"));
int row = table.addRow (); int row = table.addRow ();
table.addCell (row, 0, "Usage:"); table.addCell (row, 0, "Usage:");
@@ -207,6 +208,13 @@ int main (int argc, char** argv)
// TODO Find out what this is, and either promote it to live code, or remove it. // TODO Find out what this is, and either promote it to live code, or remove it.
// std::set_terminate (__gnu_cxx::__verbose_terminate_handler); // std::set_terminate (__gnu_cxx::__verbose_terminate_handler);
// Set up randomness.
#ifdef HAVE_SRANDOM
srandom (time (NULL));
#else
srand (time (NULL));
#endif
try try
{ {
// Load the config file from the home directory. If the file cannot be // Load the config file from the home directory. If the file cannot be
@@ -235,7 +243,7 @@ int main (int argc, char** argv)
std::string command; std::string command;
T task; T task;
parse (args, command, task); parse (args, command, task, conf);
if (command == "add") handleAdd (tdb, task, conf); if (command == "add") handleAdd (tdb, task, conf);
else if (command == "projects") handleProjects (tdb, task, conf); else if (command == "projects") handleProjects (tdb, task, conf);
@@ -278,22 +286,6 @@ int main (int argc, char** argv)
return 0; return 0;
} }
////////////////////////////////////////////////////////////////////////////////
std::string epochToString (const std::string& epoch)
{
char formatted[12] = {0};
if (epoch.length () && epoch.find ("/") == std::string::npos)
{
Date dt (::atoi (epoch.c_str ()));
int m, d, y;
dt.toMDY (m, d, y);
sprintf (formatted, "%d/%d/%04d", m, d, y);
}
return formatted;
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void handleAdd (const TDB& tdb, T& task, Config& conf) void handleAdd (const TDB& tdb, T& task, Config& conf)
{ {
@@ -335,6 +327,7 @@ void handleProjects (const TDB& tdb, T& task, Config& conf)
table.setColumnUnderline (1); table.setColumnUnderline (1);
table.setColumnJustification (1, Table::right); table.setColumnJustification (1, Table::right);
table.setDateFormat (conf.get ("dateformat", "m/d/Y"));
foreach (i, unique) foreach (i, unique)
{ {
@@ -343,9 +336,9 @@ void handleProjects (const TDB& tdb, T& task, Config& conf)
table.addCell (row, 1, i->second); table.addCell (row, 1, i->second);
} }
std::cout << std::endl std::cout << optionalBlankLine (conf)
<< table.render () << table.render ()
<< std::endl << optionalBlankLine (conf)
<< unique.size () << unique.size ()
<< (unique.size () == 1 ? " project" : " projects") << (unique.size () == 1 ? " project" : " projects")
<< std::endl; << std::endl;
@@ -377,11 +370,12 @@ void handleTags (const TDB& tdb, T& task, Config& conf)
} }
// Render a list of tag names from the map. // Render a list of tag names from the map.
std::cout << optionalBlankLine (conf);
foreach (i, unique) foreach (i, unique)
std::cout << i->first << std::endl; std::cout << i->first << std::endl;
if (unique.size ()) if (unique.size ())
std::cout << std::endl std::cout << optionalBlankLine (conf)
<< unique.size () << unique.size ()
<< (unique.size () == 1 ? " tag" : " tags") << (unique.size () == 1 ? " tag" : " tags")
<< std::endl; << std::endl;
@@ -415,6 +409,8 @@ void handleList (const TDB& tdb, T& task, Config& conf)
initializeColorRules (conf); initializeColorRules (conf);
bool showAge = conf.get ("showage", true);
// Create a table for output. // Create a table for output.
Table table; Table table;
table.setTableWidth (width); table.setTableWidth (width);
@@ -423,7 +419,7 @@ void handleList (const TDB& tdb, T& task, Config& conf)
table.addColumn ("Pri"); table.addColumn ("Pri");
table.addColumn ("Due"); table.addColumn ("Due");
table.addColumn ("Active"); table.addColumn ("Active");
table.addColumn ("Age"); if (showAge) table.addColumn ("Age");
table.addColumn ("Description"); table.addColumn ("Description");
table.setColumnUnderline (0); table.setColumnUnderline (0);
@@ -432,27 +428,29 @@ void handleList (const TDB& tdb, T& task, Config& conf)
table.setColumnUnderline (3); table.setColumnUnderline (3);
table.setColumnUnderline (4); table.setColumnUnderline (4);
table.setColumnUnderline (5); table.setColumnUnderline (5);
table.setColumnUnderline (6); if (showAge) table.setColumnUnderline (6);
table.setColumnWidth (0, Table::minimum); table.setColumnWidth (0, Table::minimum);
table.setColumnWidth (1, Table::minimum); table.setColumnWidth (1, Table::minimum);
table.setColumnWidth (2, Table::minimum); table.setColumnWidth (2, Table::minimum);
table.setColumnWidth (3, Table::minimum); table.setColumnWidth (3, Table::minimum);
table.setColumnWidth (4, Table::minimum); table.setColumnWidth (4, Table::minimum);
table.setColumnWidth (5, Table::minimum); if (showAge) table.setColumnWidth (5, Table::minimum);
table.setColumnWidth (6, Table::flexible); table.setColumnWidth ((showAge ? 6 : 5), Table::flexible);
table.setColumnJustification (0, Table::right); table.setColumnJustification (0, Table::right);
table.setColumnJustification (3, Table::right); table.setColumnJustification (3, Table::right);
table.setColumnJustification (5, Table::right); if (showAge) table.setColumnJustification (5, Table::right);
table.sortOn (3, Table::ascendingDate); table.sortOn (3, Table::ascendingDate);
table.sortOn (2, Table::descendingPriority); table.sortOn (2, Table::descendingPriority);
table.sortOn (1, Table::ascendingCharacter); table.sortOn (1, Table::ascendingCharacter);
table.setDateFormat (conf.get ("dateformat", "m/d/Y"));
// Split any description specified into words. // Split any description specified into words.
std::vector <std::string> descWords; std::vector <std::string> descWords;
split (descWords, task.getDescription (), ' '); split (descWords, lowerCase (task.getDescription ()), ' ');
// Get all the tags to match against. // Get all the tags to match against.
std::vector <std::string> tagList; std::vector <std::string> tagList;
@@ -468,9 +466,10 @@ void handleList (const TDB& tdb, T& task, Config& conf)
T refTask (tasks[i]); T refTask (tasks[i]);
// Apply description filter. // Apply description filter.
std::string desc = lowerCase (refTask.getDescription ());
unsigned int matches = 0; unsigned int matches = 0;
for (unsigned int w = 0; w < descWords.size (); ++w) for (unsigned int w = 0; w < descWords.size (); ++w)
if (refTask.getDescription ().find (descWords[w]) != std::string::npos) if (desc.find (descWords[w]) != std::string::npos)
++matches; ++matches;
if (matches == descWords.size ()) if (matches == descWords.size ())
@@ -478,8 +477,16 @@ void handleList (const TDB& tdb, T& task, Config& conf)
// Apply attribute filter. // Apply attribute filter.
matches = 0; matches = 0;
foreach (a, attrList) foreach (a, attrList)
if (a->second == refTask.getAttribute (a->first)) {
if (a->first == "project")
{
if (a->second.length () <= refTask.getAttribute (a->first).length ())
if (a->second == refTask.getAttribute (a->first).substr (0, a->second.length ()))
++matches;
}
else if (a->second == refTask.getAttribute (a->first))
++matches; ++matches;
}
if (matches == attrList.size ()) if (matches == attrList.size ())
{ {
@@ -496,14 +503,10 @@ void handleList (const TDB& tdb, T& task, Config& conf)
bool overdue = false; bool overdue = false;
Date now; Date now;
std::string due = refTask.getAttribute ("due"); std::string due = refTask.getAttribute ("due");
if (due.length () && due.find ("/") == std::string::npos) if (due.length ())
{ {
Date dt (::atoi (due.c_str ())); Date dt (::atoi (due.c_str ()));
int m, d, y; due = dt.toString (conf.get ("dateformat", "m/d/Y"));
dt.toMDY (m, d, y);
char formatted[12];
sprintf (formatted, "%d/%d/%04d", m, d, y);
due = formatted;
overdue = (dt < now) ? true : false; overdue = (dt < now) ? true : false;
now += 7 * 86400; now += 7 * 86400;
@@ -516,7 +519,7 @@ void handleList (const TDB& tdb, T& task, Config& conf)
std::string age; std::string age;
std::string created = refTask.getAttribute ("entry"); std::string created = refTask.getAttribute ("entry");
if (created.length () && created.find ("/") == std::string::npos) if (created.length ())
{ {
Date dt (::atoi (created.c_str ())); Date dt (::atoi (created.c_str ()));
formatTimeDeltaDays (age, (time_t) (now - dt)); formatTimeDeltaDays (age, (time_t) (now - dt));
@@ -529,8 +532,8 @@ void handleList (const TDB& tdb, T& task, Config& conf)
table.addCell (row, 2, refTask.getAttribute ("priority")); table.addCell (row, 2, refTask.getAttribute ("priority"));
table.addCell (row, 3, due); table.addCell (row, 3, due);
table.addCell (row, 4, active); table.addCell (row, 4, active);
table.addCell (row, 5, age); if (showAge) table.addCell (row, 5, age);
table.addCell (row, 6, refTask.getDescription ()); table.addCell (row, (showAge ? 6 : 5), refTask.getDescription ());
if (conf.get ("color", true)) if (conf.get ("color", true))
{ {
@@ -554,9 +557,9 @@ void handleList (const TDB& tdb, T& task, Config& conf)
} }
if (table.rowCount ()) if (table.rowCount ())
std::cout << std::endl std::cout << optionalBlankLine (conf)
<< table.render () << table.render ()
<< std::endl << optionalBlankLine (conf)
<< table.rowCount () << table.rowCount ()
<< (table.rowCount () == 1 ? " task" : " tasks") << (table.rowCount () == 1 ? " task" : " tasks")
<< std::endl; << std::endl;
@@ -593,6 +596,7 @@ void handleSmallList (const TDB& tdb, T& task, Config& conf)
// Create a table for output. // Create a table for output.
Table table; Table table;
table.setTableWidth (width); table.setTableWidth (width);
table.setDateFormat (conf.get ("dateformat", "m/d/Y"));
table.addColumn ("ID"); table.addColumn ("ID");
table.addColumn ("Project"); table.addColumn ("Project");
table.addColumn ("Pri"); table.addColumn ("Pri");
@@ -616,7 +620,7 @@ void handleSmallList (const TDB& tdb, T& task, Config& conf)
// Split any description specified into words. // Split any description specified into words.
std::vector <std::string> descWords; std::vector <std::string> descWords;
split (descWords, task.getDescription (), ' '); split (descWords, lowerCase (task.getDescription ()), ' ');
// Get all the tags to match against. // Get all the tags to match against.
std::vector <std::string> tagList; std::vector <std::string> tagList;
@@ -632,9 +636,10 @@ void handleSmallList (const TDB& tdb, T& task, Config& conf)
T refTask (tasks[i]); T refTask (tasks[i]);
// Apply description filter. // Apply description filter.
std::string desc = lowerCase (refTask.getDescription ());
unsigned int matches = 0; unsigned int matches = 0;
for (unsigned int w = 0; w < descWords.size (); ++w) for (unsigned int w = 0; w < descWords.size (); ++w)
if (refTask.getDescription ().find (descWords[w]) != std::string::npos) if (desc.find (descWords[w]) != std::string::npos)
++matches; ++matches;
if (matches == descWords.size ()) if (matches == descWords.size ())
@@ -642,8 +647,16 @@ void handleSmallList (const TDB& tdb, T& task, Config& conf)
// Apply attribute filter. // Apply attribute filter.
matches = 0; matches = 0;
foreach (a, attrList) foreach (a, attrList)
if (a->second == refTask.getAttribute (a->first)) {
if (a->first == "project")
{
if (a->second.length () <= refTask.getAttribute (a->first).length ())
if (a->second == refTask.getAttribute (a->first).substr (0, a->second.length ()))
++matches;
}
else if (a->second == refTask.getAttribute (a->first))
++matches; ++matches;
}
if (matches == attrList.size ()) if (matches == attrList.size ())
{ {
@@ -660,14 +673,10 @@ void handleSmallList (const TDB& tdb, T& task, Config& conf)
bool overdue = false; bool overdue = false;
Date now; Date now;
std::string due = refTask.getAttribute ("due"); std::string due = refTask.getAttribute ("due");
if (due.length () && due.find ("/") == std::string::npos) if (due.length ())
{ {
Date dt (::atoi (due.c_str ())); Date dt (::atoi (due.c_str ()));
int m, d, y; due = dt.toString (conf.get ("dateformat", "m/d/Y"));
dt.toMDY (m, d, y);
char formatted[12];
sprintf (formatted, "%d/%d/%04d", m, d, y);
due = formatted;
overdue = (dt < now) ? true : false; overdue = (dt < now) ? true : false;
now += 7 * 86400; now += 7 * 86400;
@@ -680,7 +689,7 @@ void handleSmallList (const TDB& tdb, T& task, Config& conf)
std::string age; std::string age;
std::string created = refTask.getAttribute ("entry"); std::string created = refTask.getAttribute ("entry");
if (created.length () && created.find ("/") == std::string::npos) if (created.length ())
{ {
Date dt (::atoi (created.c_str ())); Date dt (::atoi (created.c_str ()));
formatTimeDeltaDays (age, (time_t) (now - dt)); formatTimeDeltaDays (age, (time_t) (now - dt));
@@ -715,9 +724,9 @@ void handleSmallList (const TDB& tdb, T& task, Config& conf)
} }
if (table.rowCount ()) if (table.rowCount ())
std::cout << std::endl std::cout << optionalBlankLine (conf)
<< table.render () << table.render ()
<< std::endl << optionalBlankLine (conf)
<< table.rowCount () << table.rowCount ()
<< (table.rowCount () == 1 ? " task" : " tasks") << (table.rowCount () == 1 ? " task" : " tasks")
<< std::endl; << std::endl;
@@ -753,6 +762,7 @@ void handleCompleted (const TDB& tdb, T& task, Config& conf)
// Create a table for output. // Create a table for output.
Table table; Table table;
table.setTableWidth (width); table.setTableWidth (width);
table.setDateFormat (conf.get ("dateformat", "m/d/Y"));
table.addColumn ("Done"); table.addColumn ("Done");
table.addColumn ("Project"); table.addColumn ("Project");
table.addColumn ("Description"); table.addColumn ("Description");
@@ -773,7 +783,7 @@ void handleCompleted (const TDB& tdb, T& task, Config& conf)
// Split any description specified into words. // Split any description specified into words.
std::vector <std::string> descWords; std::vector <std::string> descWords;
split (descWords, task.getDescription (), ' '); split (descWords, lowerCase (task.getDescription ()), ' ');
// Get all the tags to match against. // Get all the tags to match against.
std::vector <std::string> tagList; std::vector <std::string> tagList;
@@ -789,9 +799,10 @@ void handleCompleted (const TDB& tdb, T& task, Config& conf)
T refTask (tasks[i]); T refTask (tasks[i]);
// Apply description filter. // Apply description filter.
std::string desc = lowerCase (refTask.getDescription ());
unsigned int matches = 0; unsigned int matches = 0;
for (unsigned int w = 0; w < descWords.size (); ++w) for (unsigned int w = 0; w < descWords.size (); ++w)
if (refTask.getDescription ().find (descWords[w]) != std::string::npos) if (desc.find (descWords[w]) != std::string::npos)
++matches; ++matches;
if (matches == descWords.size ()) if (matches == descWords.size ())
@@ -799,8 +810,16 @@ void handleCompleted (const TDB& tdb, T& task, Config& conf)
// Apply attribute filter. // Apply attribute filter.
matches = 0; matches = 0;
foreach (a, attrList) foreach (a, attrList)
if (a->second == refTask.getAttribute (a->first)) {
if (a->first == "project")
{
if (a->second.length () <= refTask.getAttribute (a->first).length ())
if (a->second == refTask.getAttribute (a->first).substr (0, a->second.length ()))
++matches;
}
else if (a->second == refTask.getAttribute (a->first))
++matches; ++matches;
}
if (matches == attrList.size ()) if (matches == attrList.size ())
{ {
@@ -818,7 +837,7 @@ void handleCompleted (const TDB& tdb, T& task, Config& conf)
// All criteria match, so add refTask to the output table. // All criteria match, so add refTask to the output table.
int row = table.addRow (); int row = table.addRow ();
table.addCell (row, 0, end.toString ()); table.addCell (row, 0, end.toString (conf.get ("dateformat", "m/d/Y")));
table.addCell (row, 1, refTask.getAttribute ("project")); table.addCell (row, 1, refTask.getAttribute ("project"));
table.addCell (row, 2, refTask.getDescription ()); table.addCell (row, 2, refTask.getDescription ());
@@ -836,9 +855,9 @@ void handleCompleted (const TDB& tdb, T& task, Config& conf)
} }
if (table.rowCount ()) if (table.rowCount ())
std::cout << std::endl std::cout << optionalBlankLine (conf)
<< table.render () << table.render ()
<< std::endl << optionalBlankLine (conf)
<< table.rowCount () << table.rowCount ()
<< (table.rowCount () == 1 ? " task" : " tasks") << (table.rowCount () == 1 ? " task" : " tasks")
<< std::endl; << std::endl;
@@ -868,6 +887,7 @@ void handleInfo (const TDB& tdb, T& task, Config& conf)
Table table; Table table;
table.setTableWidth (width); table.setTableWidth (width);
table.setDateFormat (conf.get ("dateformat", "m/d/Y"));
table.addColumn ("Name"); table.addColumn ("Name");
table.addColumn ("Value"); table.addColumn ("Value");
@@ -927,12 +947,13 @@ void handleInfo (const TDB& tdb, T& task, Config& conf)
{ {
row = table.addRow (); row = table.addRow ();
table.addCell (row, 0, "Due"); table.addCell (row, 0, "Due");
table.addCell (row, 1, epochToString (due));
if (due.length () && due.find ("/") == std::string::npos) Date dt (::atoi (due.c_str ()));
due = dt.toString (conf.get ("dateformat", "m/d/Y"));
table.addCell (row, 1, due);
if (due.length ())
{ {
Date dt (::atoi (due.c_str ()));
overdue = (dt < now) ? true : false; overdue = (dt < now) ? true : false;
now += 7 * 86400; now += 7 * 86400;
imminent = dt < now ? true : false; imminent = dt < now ? true : false;
@@ -952,7 +973,8 @@ void handleInfo (const TDB& tdb, T& task, Config& conf)
{ {
row = table.addRow (); row = table.addRow ();
table.addCell (row, 0, "Start"); table.addCell (row, 0, "Start");
table.addCell (row, 1, epochToString (refTask.getAttribute ("start"))); Date dt (::atoi (refTask.getAttribute ("start").c_str ()));
table.addCell (row, 1, dt.toString (conf.get ("dateformat", "m/d/Y")));
} }
// end // end
@@ -960,7 +982,8 @@ void handleInfo (const TDB& tdb, T& task, Config& conf)
{ {
row = table.addRow (); row = table.addRow ();
table.addCell (row, 0, "End"); table.addCell (row, 0, "End");
table.addCell (row, 1, epochToString (refTask.getAttribute ("end"))); Date dt (::atoi (refTask.getAttribute ("end").c_str ()));
table.addCell (row, 1, dt.toString (conf.get ("dateformat", "m/d/Y")));
} }
// tags ... // tags ...
@@ -982,11 +1005,12 @@ void handleInfo (const TDB& tdb, T& task, Config& conf)
row = table.addRow (); row = table.addRow ();
table.addCell (row, 0, "Entered"); table.addCell (row, 0, "Entered");
std::string entry = epochToString (refTask.getAttribute ("entry")); Date dt (::atoi (refTask.getAttribute ("entry").c_str ()));
std::string entry = dt.toString (conf.get ("dateformat", "m/d/Y"));
std::string age; std::string age;
std::string created = refTask.getAttribute ("entry"); std::string created = refTask.getAttribute ("entry");
if (created.length () && created.find ("/") == std::string::npos) if (created.length ())
{ {
Date dt (::atoi (created.c_str ())); Date dt (::atoi (created.c_str ()));
formatTimeDeltaDays (age, (time_t) (now - dt)); formatTimeDeltaDays (age, (time_t) (now - dt));
@@ -997,9 +1021,9 @@ void handleInfo (const TDB& tdb, T& task, Config& conf)
} }
if (table.rowCount ()) if (table.rowCount ())
std::cout << std::endl std::cout << optionalBlankLine (conf)
<< table.render () << table.render ()
<< std::endl << optionalBlankLine (conf)
<< table.rowCount () << table.rowCount ()
<< (table.rowCount () == 1 ? " task" : " tasks") << (table.rowCount () == 1 ? " task" : " tasks")
<< std::endl; << std::endl;
@@ -1034,6 +1058,7 @@ void handleLongList (const TDB& tdb, T& task, Config& conf)
// Create a table for output. // Create a table for output.
Table table; Table table;
table.setTableWidth (width); table.setTableWidth (width);
table.setDateFormat (conf.get ("dateformat", "m/d/Y"));
table.addColumn ("ID"); table.addColumn ("ID");
table.addColumn ("Project"); table.addColumn ("Project");
table.addColumn ("Pri"); table.addColumn ("Pri");
@@ -1041,6 +1066,7 @@ void handleLongList (const TDB& tdb, T& task, Config& conf)
table.addColumn ("Start"); table.addColumn ("Start");
table.addColumn ("Due"); table.addColumn ("Due");
table.addColumn ("Age"); table.addColumn ("Age");
table.addColumn ("Tags");
table.addColumn ("Description"); table.addColumn ("Description");
table.setColumnUnderline (0); table.setColumnUnderline (0);
@@ -1051,6 +1077,7 @@ void handleLongList (const TDB& tdb, T& task, Config& conf)
table.setColumnUnderline (5); table.setColumnUnderline (5);
table.setColumnUnderline (6); table.setColumnUnderline (6);
table.setColumnUnderline (7); table.setColumnUnderline (7);
table.setColumnUnderline (8);
table.setColumnWidth (0, Table::minimum); table.setColumnWidth (0, Table::minimum);
table.setColumnWidth (1, Table::minimum); table.setColumnWidth (1, Table::minimum);
@@ -1059,7 +1086,8 @@ void handleLongList (const TDB& tdb, T& task, Config& conf)
table.setColumnWidth (4, Table::minimum); table.setColumnWidth (4, Table::minimum);
table.setColumnWidth (5, Table::minimum); table.setColumnWidth (5, Table::minimum);
table.setColumnWidth (6, Table::minimum); table.setColumnWidth (6, Table::minimum);
table.setColumnWidth (7, Table::flexible); table.setColumnWidth (7, Table::minimum);
table.setColumnWidth (8, Table::flexible);
table.setColumnJustification (0, Table::right); table.setColumnJustification (0, Table::right);
table.setColumnJustification (3, Table::right); table.setColumnJustification (3, Table::right);
@@ -1073,7 +1101,7 @@ void handleLongList (const TDB& tdb, T& task, Config& conf)
// Split any description specified into words. // Split any description specified into words.
std::vector <std::string> descWords; std::vector <std::string> descWords;
split (descWords, task.getDescription (), ' '); split (descWords, lowerCase (task.getDescription ()), ' ');
// Get all the tags to match against. // Get all the tags to match against.
std::vector <std::string> tagList; std::vector <std::string> tagList;
@@ -1089,9 +1117,10 @@ void handleLongList (const TDB& tdb, T& task, Config& conf)
T refTask (tasks[i]); T refTask (tasks[i]);
// Apply description filter. // Apply description filter.
std::string desc = lowerCase (refTask.getDescription ());
unsigned int matches = 0; unsigned int matches = 0;
for (unsigned int w = 0; w < descWords.size (); ++w) for (unsigned int w = 0; w < descWords.size (); ++w)
if (refTask.getDescription ().find (descWords[w]) != std::string::npos) if (desc.find (descWords[w]) != std::string::npos)
++matches; ++matches;
if (matches == descWords.size ()) if (matches == descWords.size ())
@@ -1099,8 +1128,16 @@ void handleLongList (const TDB& tdb, T& task, Config& conf)
// Apply attribute filter. // Apply attribute filter.
matches = 0; matches = 0;
foreach (a, attrList) foreach (a, attrList)
if (a->second == refTask.getAttribute (a->first)) {
if (a->first == "project")
{
if (a->second.length () <= refTask.getAttribute (a->first).length ())
if (a->second == refTask.getAttribute (a->first).substr (0, a->second.length ()))
++matches;
}
else if (a->second == refTask.getAttribute (a->first))
++matches; ++matches;
}
if (matches == attrList.size ()) if (matches == attrList.size ())
{ {
@@ -1115,39 +1152,27 @@ void handleLongList (const TDB& tdb, T& task, Config& conf)
Date now; Date now;
std::string started = refTask.getAttribute ("start"); std::string started = refTask.getAttribute ("start");
if (started.length () && started.find ("/") == std::string::npos) if (started.length ())
{ {
Date dt (::atoi (started.c_str ())); Date dt (::atoi (started.c_str ()));
int m, d, y; started = dt.toString (conf.get ("dateformat", "m/d/Y"));
dt.toMDY (m, d, y);
char formatted[12];
sprintf (formatted, "%d/%d/%04d", m, d, y);
started = formatted;
} }
std::string entered = refTask.getAttribute ("entry"); std::string entered = refTask.getAttribute ("entry");
if (entered.length () && entered.find ("/") == std::string::npos) if (entered.length ())
{ {
Date dt (::atoi (entered.c_str ())); Date dt (::atoi (entered.c_str ()));
int m, d, y; entered = dt.toString (conf.get ("dateformat", "m/d/Y"));
dt.toMDY (m, d, y);
char formatted[12];
sprintf (formatted, "%d/%d/%04d", m, d, y);
entered = formatted;
} }
// Now format the matching task. // Now format the matching task.
bool imminent = false; bool imminent = false;
bool overdue = false; bool overdue = false;
std::string due = refTask.getAttribute ("due"); std::string due = refTask.getAttribute ("due");
if (due.length () && due.find ("/") == std::string::npos) if (due.length ())
{ {
Date dt (::atoi (due.c_str ())); Date dt (::atoi (due.c_str ()));
int m, d, y; due = dt.toString (conf.get ("dateformat", "m/d/Y"));
dt.toMDY (m, d, y);
char formatted[12];
sprintf (formatted, "%d/%d/%04d", m, d, y);
due = formatted;
overdue = (dt < now) ? true : false; overdue = (dt < now) ? true : false;
now += 7 * 86400; now += 7 * 86400;
@@ -1156,12 +1181,18 @@ void handleLongList (const TDB& tdb, T& task, Config& conf)
std::string age; std::string age;
std::string created = refTask.getAttribute ("entry"); std::string created = refTask.getAttribute ("entry");
if (created.length () && created.find ("/") == std::string::npos) if (created.length ())
{ {
Date dt (::atoi (created.c_str ())); Date dt (::atoi (created.c_str ()));
formatTimeDeltaDays (age, (time_t) (now - dt)); formatTimeDeltaDays (age, (time_t) (now - dt));
} }
// Make a list of tags.
std::string tags;
std::vector <std::string> all;
refTask.getTags (all);
join (tags, " ", all);
// All criteria match, so add refTask to the output table. // All criteria match, so add refTask to the output table.
int row = table.addRow (); int row = table.addRow ();
table.addCell (row, 0, refTask.getId ()); table.addCell (row, 0, refTask.getId ());
@@ -1171,7 +1202,8 @@ void handleLongList (const TDB& tdb, T& task, Config& conf)
table.addCell (row, 4, started); table.addCell (row, 4, started);
table.addCell (row, 5, due); table.addCell (row, 5, due);
table.addCell (row, 6, age); table.addCell (row, 6, age);
table.addCell (row, 7, refTask.getDescription ()); table.addCell (row, 7, tags);
table.addCell (row, 8, refTask.getDescription ());
if (conf.get ("color", true)) if (conf.get ("color", true))
{ {
@@ -1195,9 +1227,9 @@ void handleLongList (const TDB& tdb, T& task, Config& conf)
} }
if (table.rowCount ()) if (table.rowCount ())
std::cout << std::endl std::cout << optionalBlankLine (conf)
<< table.render () << table.render ()
<< std::endl << optionalBlankLine (conf)
<< table.rowCount () << table.rowCount ()
<< (table.rowCount () == 1 ? " task" : " tasks") << (table.rowCount () == 1 ? " task" : " tasks")
<< std::endl; << std::endl;
@@ -1291,6 +1323,7 @@ void handleReportSummary (const TDB& tdb, T& task, Config& conf)
table.setColumnJustification (3, Table::right); table.setColumnJustification (3, Table::right);
table.sortOn (0, Table::ascendingCharacter); table.sortOn (0, Table::ascendingCharacter);
table.setDateFormat (conf.get ("dateformat", "m/d/Y"));
int barWidth = 30; int barWidth = 30;
foreach (i, allProjects) foreach (i, allProjects)
@@ -1341,9 +1374,9 @@ void handleReportSummary (const TDB& tdb, T& task, Config& conf)
} }
if (table.rowCount ()) if (table.rowCount ())
std::cout << std::endl std::cout << optionalBlankLine (conf)
<< table.render () << table.render ()
<< std::endl << optionalBlankLine (conf)
<< table.rowCount () << table.rowCount ()
<< (table.rowCount () == 1 ? " project" : " projects") << (table.rowCount () == 1 ? " project" : " projects")
<< std::endl; << std::endl;
@@ -1399,15 +1432,18 @@ void handleReportNext (const TDB& tdb, T& task, Config& conf)
initializeColorRules (conf); initializeColorRules (conf);
bool showAge = conf.get ("showage", true);
// Create a table for output. // Create a table for output.
Table table; Table table;
table.setTableWidth (width); table.setTableWidth (width);
table.setDateFormat (conf.get ("dateformat", "m/d/Y"));
table.addColumn ("ID"); table.addColumn ("ID");
table.addColumn ("Project"); table.addColumn ("Project");
table.addColumn ("Pri"); table.addColumn ("Pri");
table.addColumn ("Due"); table.addColumn ("Due");
table.addColumn ("Active"); table.addColumn ("Active");
table.addColumn ("Age"); if (showAge) table.addColumn ("Age");
table.addColumn ("Description"); table.addColumn ("Description");
table.setColumnUnderline (0); table.setColumnUnderline (0);
@@ -1416,19 +1452,19 @@ void handleReportNext (const TDB& tdb, T& task, Config& conf)
table.setColumnUnderline (3); table.setColumnUnderline (3);
table.setColumnUnderline (4); table.setColumnUnderline (4);
table.setColumnUnderline (5); table.setColumnUnderline (5);
table.setColumnUnderline (6); if (showAge) table.setColumnUnderline (6);
table.setColumnWidth (0, Table::minimum); table.setColumnWidth (0, Table::minimum);
table.setColumnWidth (1, Table::minimum); table.setColumnWidth (1, Table::minimum);
table.setColumnWidth (2, Table::minimum); table.setColumnWidth (2, Table::minimum);
table.setColumnWidth (3, Table::minimum); table.setColumnWidth (3, Table::minimum);
table.setColumnWidth (4, Table::minimum); table.setColumnWidth (4, Table::minimum);
table.setColumnWidth (5, Table::minimum); if (showAge) table.setColumnWidth (5, Table::minimum);
table.setColumnWidth (6, Table::flexible); table.setColumnWidth ((showAge ? 6 : 5), Table::flexible);
table.setColumnJustification (0, Table::right); table.setColumnJustification (0, Table::right);
table.setColumnJustification (3, Table::right); table.setColumnJustification (3, Table::right);
table.setColumnJustification (5, Table::right); if (showAge) table.setColumnJustification (5, Table::right);
table.sortOn (3, Table::ascendingDate); table.sortOn (3, Table::ascendingDate);
table.sortOn (2, Table::descendingPriority); table.sortOn (2, Table::descendingPriority);
@@ -1436,7 +1472,7 @@ void handleReportNext (const TDB& tdb, T& task, Config& conf)
// Split any description specified into words. // Split any description specified into words.
std::vector <std::string> descWords; std::vector <std::string> descWords;
split (descWords, task.getDescription (), ' '); split (descWords, lowerCase (task.getDescription ()), ' ');
// Get all the tags to match against. // Get all the tags to match against.
std::vector <std::string> tagList; std::vector <std::string> tagList;
@@ -1452,9 +1488,10 @@ void handleReportNext (const TDB& tdb, T& task, Config& conf)
T refTask (pending[*i]); T refTask (pending[*i]);
// Apply description filter. // Apply description filter.
std::string desc = lowerCase (refTask.getDescription ());
unsigned int matches = 0; unsigned int matches = 0;
for (unsigned int w = 0; w < descWords.size (); ++w) for (unsigned int w = 0; w < descWords.size (); ++w)
if (refTask.getDescription ().find (descWords[w]) != std::string::npos) if (desc.find (descWords[w]) != std::string::npos)
++matches; ++matches;
if (matches == descWords.size ()) if (matches == descWords.size ())
@@ -1462,8 +1499,16 @@ void handleReportNext (const TDB& tdb, T& task, Config& conf)
// Apply attribute filter. // Apply attribute filter.
matches = 0; matches = 0;
foreach (a, attrList) foreach (a, attrList)
if (a->second == refTask.getAttribute (a->first)) {
if (a->first == "project")
{
if (a->second.length () <= refTask.getAttribute (a->first).length ())
if (a->second == refTask.getAttribute (a->first).substr (0, a->second.length ()))
++matches;
}
else if (a->second == refTask.getAttribute (a->first))
++matches; ++matches;
}
if (matches == attrList.size ()) if (matches == attrList.size ())
{ {
@@ -1480,14 +1525,10 @@ void handleReportNext (const TDB& tdb, T& task, Config& conf)
bool overdue = false; bool overdue = false;
Date now; Date now;
std::string due = refTask.getAttribute ("due"); std::string due = refTask.getAttribute ("due");
if (due.length () && due.find ("/") == std::string::npos) if (due.length ())
{ {
Date dt (::atoi (due.c_str ())); Date dt (::atoi (due.c_str ()));
int m, d, y; due = dt.toString (conf.get ("dateformat", "m/d/Y"));
dt.toMDY (m, d, y);
char formatted[12];
sprintf (formatted, "%d/%d/%04d", m, d, y);
due = formatted;
overdue = (dt < now) ? true : false; overdue = (dt < now) ? true : false;
now += 7 * 86400; now += 7 * 86400;
@@ -1500,7 +1541,7 @@ void handleReportNext (const TDB& tdb, T& task, Config& conf)
std::string age; std::string age;
std::string created = refTask.getAttribute ("entry"); std::string created = refTask.getAttribute ("entry");
if (created.length () && created.find ("/") == std::string::npos) if (created.length ())
{ {
Date dt (::atoi (created.c_str ())); Date dt (::atoi (created.c_str ()));
formatTimeDeltaDays (age, (time_t) (now - dt)); formatTimeDeltaDays (age, (time_t) (now - dt));
@@ -1513,8 +1554,8 @@ void handleReportNext (const TDB& tdb, T& task, Config& conf)
table.addCell (row, 2, refTask.getAttribute ("priority")); table.addCell (row, 2, refTask.getAttribute ("priority"));
table.addCell (row, 3, due); table.addCell (row, 3, due);
table.addCell (row, 4, active); table.addCell (row, 4, active);
table.addCell (row, 5, age); if (showAge) table.addCell (row, 5, age);
table.addCell (row, 6, refTask.getDescription ()); table.addCell (row, (showAge ? 6 : 5), refTask.getDescription ());
if (conf.get ("color", true)) if (conf.get ("color", true))
{ {
@@ -1538,9 +1579,9 @@ void handleReportNext (const TDB& tdb, T& task, Config& conf)
} }
if (table.rowCount ()) if (table.rowCount ())
std::cout << std::endl std::cout << optionalBlankLine (conf)
<< table.render () << table.render ()
<< std::endl << optionalBlankLine (conf)
<< table.rowCount () << table.rowCount ()
<< (table.rowCount () == 1 ? " task" : " tasks") << (table.rowCount () == 1 ? " task" : " tasks")
<< std::endl; << std::endl;
@@ -1654,6 +1695,7 @@ void handleReportHistory (const TDB& tdb, T& task, Config& conf)
// Now build the table. // Now build the table.
Table table; Table table;
table.setDateFormat (conf.get ("dateformat", "m/d/Y"));
table.addColumn ("Year"); table.addColumn ("Year");
table.addColumn ("Month"); table.addColumn ("Month");
table.addColumn ("Added"); table.addColumn ("Added");
@@ -1721,7 +1763,7 @@ void handleReportHistory (const TDB& tdb, T& task, Config& conf)
} }
if (table.rowCount ()) if (table.rowCount ())
std::cout << std::endl std::cout << optionalBlankLine (conf)
<< table.render () << table.render ()
<< std::endl; << std::endl;
else else
@@ -1756,7 +1798,7 @@ void handleReportUsage (const TDB& tdb, T& task, Config& conf)
{ {
T task; T task;
std::string commandName; std::string commandName;
parse (args, commandName, task); parse (args, commandName, task, conf);
usage[commandName]++; usage[commandName]++;
} }
@@ -1775,6 +1817,7 @@ void handleReportUsage (const TDB& tdb, T& task, Config& conf)
table.setColumnUnderline (1); table.setColumnUnderline (1);
table.setColumnJustification (1, Table::right); table.setColumnJustification (1, Table::right);
table.sortOn (1, Table::descendingNumeric); table.sortOn (1, Table::descendingNumeric);
table.setDateFormat (conf.get ("dateformat", "m/d/Y"));
foreach (i, usage) foreach (i, usage)
{ {
@@ -1784,7 +1827,7 @@ void handleReportUsage (const TDB& tdb, T& task, Config& conf)
} }
if (table.rowCount ()) if (table.rowCount ())
std::cout << std::endl std::cout << optionalBlankLine (conf)
<< table.render () << table.render ()
<< std::endl; << std::endl;
else else
@@ -1804,6 +1847,7 @@ std::string renderMonth (
Config& conf) Config& conf)
{ {
Table table; Table table;
table.setDateFormat (conf.get ("dateformat", "m/d/Y"));
table.addColumn (" "); table.addColumn (" ");
table.addColumn ("Su"); table.addColumn ("Su");
table.addColumn ("Mo"); table.addColumn ("Mo");
@@ -1904,8 +1948,8 @@ void handleReportCalendar (const TDB& tdb, T& task, Config& conf)
std::cout << Date::monthName (mFrom) std::cout << Date::monthName (mFrom)
<< " " << " "
<< yFrom << yFrom
<< std::endl << optionalBlankLine (conf)
<< std::endl << optionalBlankLine (conf)
<< renderMonth (mFrom, yFrom, today, pending, conf) << renderMonth (mFrom, yFrom, today, pending, conf)
<< std::endl; << std::endl;
@@ -1923,7 +1967,7 @@ void handleReportCalendar (const TDB& tdb, T& task, Config& conf)
<< ", " << ", "
<< Text::colorize (Text::black, Text::on_red, "overdue") << Text::colorize (Text::black, Text::on_red, "overdue")
<< "." << "."
<< std::endl << optionalBlankLine (conf)
<< std::endl; << std::endl;
} }
@@ -1950,6 +1994,7 @@ void handleReportActive (const TDB& tdb, T& task, Config& conf)
// Create a table for output. // Create a table for output.
Table table; Table table;
table.setTableWidth (width); table.setTableWidth (width);
table.setDateFormat (conf.get ("dateformat", "m/d/Y"));
table.addColumn ("ID"); table.addColumn ("ID");
table.addColumn ("Project"); table.addColumn ("Project");
table.addColumn ("Pri"); table.addColumn ("Pri");
@@ -1975,10 +2020,6 @@ void handleReportActive (const TDB& tdb, T& task, Config& conf)
table.sortOn (2, Table::descendingPriority); table.sortOn (2, Table::descendingPriority);
table.sortOn (1, Table::ascendingCharacter); table.sortOn (1, Table::ascendingCharacter);
// Split any description specified into words.
std::vector <std::string> descWords;
split (descWords, task.getDescription (), ' ');
// Get all the tags to match against. // Get all the tags to match against.
std::vector <std::string> tagList; std::vector <std::string> tagList;
task.getTags (tagList); task.getTags (tagList);
@@ -1996,14 +2037,10 @@ void handleReportActive (const TDB& tdb, T& task, Config& conf)
bool imminent = false; bool imminent = false;
bool overdue = false; bool overdue = false;
std::string due = refTask.getAttribute ("due"); std::string due = refTask.getAttribute ("due");
if (due.length () && due.find ("/") == std::string::npos) if (due.length ())
{ {
Date dt (::atoi (due.c_str ())); Date dt (::atoi (due.c_str ()));
int m, d, y; due = dt.toString (conf.get ("dateformat", "m/d/Y"));
dt.toMDY (m, d, y);
char formatted[12];
sprintf (formatted, "%d/%d/%04d", m, d, y);
due = formatted;
Date now; Date now;
overdue = dt < now ? true : false; overdue = dt < now ? true : false;
@@ -2039,9 +2076,9 @@ void handleReportActive (const TDB& tdb, T& task, Config& conf)
} }
if (table.rowCount ()) if (table.rowCount ())
std::cout << std::endl std::cout << optionalBlankLine (conf)
<< table.render () << table.render ()
<< std::endl << optionalBlankLine (conf)
<< table.rowCount () << table.rowCount ()
<< (table.rowCount () == 1 ? " task" : " tasks") << (table.rowCount () == 1 ? " task" : " tasks")
<< std::endl; << std::endl;
@@ -2072,6 +2109,7 @@ void handleReportOverdue (const TDB& tdb, T& task, Config& conf)
// Create a table for output. // Create a table for output.
Table table; Table table;
table.setTableWidth (width); table.setTableWidth (width);
table.setDateFormat (conf.get ("dateformat", "m/d/Y"));
table.addColumn ("ID"); table.addColumn ("ID");
table.addColumn ("Project"); table.addColumn ("Project");
table.addColumn ("Pri"); table.addColumn ("Pri");
@@ -2097,10 +2135,6 @@ void handleReportOverdue (const TDB& tdb, T& task, Config& conf)
table.sortOn (2, Table::descendingPriority); table.sortOn (2, Table::descendingPriority);
table.sortOn (1, Table::ascendingCharacter); table.sortOn (1, Table::ascendingCharacter);
// Split any description specified into words.
std::vector <std::string> descWords;
split (descWords, task.getDescription (), ' ');
// Get all the tags to match against. // Get all the tags to match against.
std::vector <std::string> tagList; std::vector <std::string> tagList;
task.getTags (tagList); task.getTags (tagList);
@@ -2118,14 +2152,10 @@ void handleReportOverdue (const TDB& tdb, T& task, Config& conf)
std::string due; std::string due;
if ((due = refTask.getAttribute ("due")) != "") if ((due = refTask.getAttribute ("due")) != "")
{ {
if (due.length () && due.find ("/") == std::string::npos) if (due.length ())
{ {
Date dt (::atoi (due.c_str ())); Date dt (::atoi (due.c_str ()));
int m, d, y; due = dt.toString (conf.get ("dateformat", "m/d/Y"));
dt.toMDY (m, d, y);
char formatted[12];
sprintf (formatted, "%d/%d/%04d", m, d, y);
due = formatted;
// If overdue. // If overdue.
if (dt < now) if (dt < now)
@@ -2155,9 +2185,9 @@ void handleReportOverdue (const TDB& tdb, T& task, Config& conf)
} }
if (table.rowCount ()) if (table.rowCount ())
std::cout << std::endl std::cout << optionalBlankLine (conf)
<< table.render () << table.render ()
<< std::endl << optionalBlankLine (conf)
<< table.rowCount () << table.rowCount ()
<< (table.rowCount () == 1 ? " task" : " tasks") << (table.rowCount () == 1 ? " task" : " tasks")
<< std::endl; << std::endl;
@@ -2219,9 +2249,9 @@ void handleReportStats (const TDB& tdb, T& task, Config& conf)
if (tasks.size ()) if (tasks.size ())
{ {
Date e (earliest); Date e (earliest);
std::cout << "Oldest task " << e.toString () << std::endl; std::cout << "Oldest task " << e.toString (conf.get ("dateformat", "m/d/Y")) << std::endl;
Date l (latest); Date l (latest);
std::cout << "Newest task " << l.toString () << std::endl; std::cout << "Newest task " << l.toString (conf.get ("dateformat", "m/d/Y")) << std::endl;
std::cout << "Task used for " << formatSeconds (latest - earliest) << std::endl; std::cout << "Task used for " << formatSeconds (latest - earliest) << std::endl;
} }
@@ -2265,6 +2295,7 @@ void handleVersion (Config& conf)
// Create a table for output. // Create a table for output.
Table table; Table table;
table.setTableWidth (width); table.setTableWidth (width);
table.setDateFormat (conf.get ("dateformat", "m/d/Y"));
table.addColumn ("Config variable"); table.addColumn ("Config variable");
table.addColumn ("Value"); table.addColumn ("Value");
table.setColumnUnderline (0); table.setColumnUnderline (0);
@@ -2288,7 +2319,7 @@ void handleVersion (Config& conf)
} }
} }
std::cout << "Copyright (C) 2006 - 2008 Paul Beckingham." std::cout << "Copyright (C) 2006 - 2008, P. Beckingham."
<< std::endl << std::endl
<< PACKAGE << PACKAGE
<< " " << " "
@@ -2302,7 +2333,6 @@ void handleVersion (Config& conf)
<< "under certain conditions; again, see the COPYING file for details." << "under certain conditions; again, see the COPYING file for details."
<< std::endl << std::endl
<< std::endl << std::endl
<< std::endl
<< table.render () << table.render ()
<< std::endl; << std::endl;
@@ -2508,7 +2538,7 @@ void handleModify (const TDB& tdb, T& task, Config& conf)
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void handleColor (Config& conf) void handleColor (Config& conf)
{ {
std::cout << std::endl << "Foreground" << std::endl std::cout << optionalBlankLine (conf) << "Foreground" << std::endl
<< " " << " "
<< Text::colorize (Text::bold, Text::nocolor, "bold") << " " << Text::colorize (Text::bold, Text::nocolor, "bold") << " "
<< Text::colorize (Text::underline, Text::nocolor, "underline") << " " << Text::colorize (Text::underline, Text::nocolor, "underline") << " "
@@ -2579,7 +2609,7 @@ void handleColor (Config& conf)
<< " " << Text::colorize (Text::nocolor, Text::on_white, "on_white") << " " << " " << Text::colorize (Text::nocolor, Text::on_white, "on_white") << " "
<< Text::colorize (Text::nocolor, Text::on_bright_white, "on_bright_white") << std::endl << Text::colorize (Text::nocolor, Text::on_bright_white, "on_bright_white") << std::endl
<< std::endl; << optionalBlankLine (conf);
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View File

@@ -49,8 +49,8 @@ for (typeof (c) *foreach_p = & (c); \
++i) ++i)
// parse.cpp // parse.cpp
void parse (std::vector <std::string>&, std::string&, T&); void parse (std::vector <std::string>&, std::string&, T&, Config&);
bool validDate (std::string&); bool validDate (std::string&, Config&);
// task.cpp // task.cpp
void handleAdd (const TDB&, T&, Config&); void handleAdd (const TDB&, T&, Config&);
@@ -97,6 +97,7 @@ int autoComplete (const std::string&, const std::vector<std::string>&, std::vect
void formatTimeDeltaDays (std::string&, time_t); void formatTimeDeltaDays (std::string&, time_t);
std::string formatSeconds (time_t); std::string formatSeconds (time_t);
const std::string uuid (); const std::string uuid ();
const char* optionalBlankLine (Config&);
// rules.cpp // rules.cpp
void initializeColorRules (Config&); void initializeColorRules (Config&);

View File

@@ -1,5 +1,6 @@
t.t t.t
tdb.t tdb.t
date.t
pending.data pending.data
completed.data completed.data

28
src/tests/Makefile Normal file
View File

@@ -0,0 +1,28 @@
PROJECT = t.t tdb.t date.t
CFLAGS = -I. -I.. -Wall -pedantic -ggdb3 -fno-rtti
LFLAGS = -L/usr/local/lib
OBJECTS = ../TDB.o ../T.o ../parse.o ../text.o ../Date.o ../util.o ../Config.o
all: $(PROJECT)
install: $(PROJECT)
@echo unimplemented
test: $(PROJECT)
@echo unimplemented
clean:
-rm *.o $(PROJECT)
.cpp.o:
g++ -c $(CFLAGS) $<
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
date.t: date.t.o $(OBJECTS) test.o
g++ date.t.o $(OBJECTS) test.o $(LFLAGS) -o date.t

113
src/tests/date.t.cpp Normal file
View File

@@ -0,0 +1,113 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2005 - 2008, Paul Beckingham. All rights reserved.
//
////////////////////////////////////////////////////////////////////////////////
#include <iostream>
#include <Date.h>
#include <test.h>
////////////////////////////////////////////////////////////////////////////////
int main (int argc, char** argv)
{
plan (63);
Date now;
Date yesterday;
yesterday -= 1;
ok (yesterday <= now, "yesterday <= now");
ok (yesterday < now, "yesterday < now");
notok (yesterday == now, "!(yesterday == now)");
ok (yesterday != now, "yesterday != now");
ok (now >= yesterday, "now >= yesterday");
ok (now > yesterday, "now > yesterday");
ok (Date::valid (2, 29, 2008), "valid: 2/29/2008");
notok (Date::valid (2, 29, 2007), "invalid: 2/29/2007");
ok (Date::leapYear (2008), "2008 is a leap year");
notok (Date::leapYear (2007), "2007 is not a leap year");
ok (Date::leapYear (2000), "2000 is a leap year");
ok (Date::leapYear (1900), "1900 is a leap year");
is (Date::daysInMonth (2, 2008), 29, "29 days in February 2008");
is (Date::daysInMonth (2, 2007), 28, "28 days in February 2007");
is (Date::monthName (1), "January", "1 = January");
is (Date::monthName (2), "February", "2 = February");
is (Date::monthName (3), "March", "3 = March");
is (Date::monthName (4), "April", "4 = April");
is (Date::monthName (5), "May", "5 = May");
is (Date::monthName (6), "June", "6 = June");
is (Date::monthName (7), "July", "7 = July");
is (Date::monthName (8), "August", "8 = August");
is (Date::monthName (9), "September", "9 = September");
is (Date::monthName (10), "October", "10 = October");
is (Date::monthName (11), "November", "11 = November");
is (Date::monthName (12), "December", "12 = December");
is (Date::dayName (0), "Sunday", "0 == Sunday");
is (Date::dayName (1), "Monday", "1 == Monday");
is (Date::dayName (2), "Tuesday", "2 == Tuesday");
is (Date::dayName (3), "Wednesday", "3 == Wednesday");
is (Date::dayName (4), "Thursday", "4 == Thursday");
is (Date::dayName (5), "Friday", "5 == Friday");
is (Date::dayName (6), "Saturday", "6 == Saturday");
Date happyNewYear (1, 1, 2008);
is (happyNewYear.dayOfWeek (), 2, "1/1/2008 == Tuesday");
is (happyNewYear.month (), 1, "1/1/2008 == January");
is (happyNewYear.day (), 1, "1/1/2008 == 1");
is (happyNewYear.year (), 2008, "1/1/2008 == 2008");
is (now - yesterday, 1, "today - yesterday == 1");
is (happyNewYear.toString (), "1/1/2008", "toString 1/1/2008");
int m, d, y;
happyNewYear.toMDY (m, d, y);
is (m, 1, "1/1/2008 == January");
is (d, 1, "1/1/2008 == 1");
is (y, 2008, "1/1/2008 == 2008");
Date epoch (9, 8, 2001);
ok ((int)epoch.toEpoch () < 1000000000, "9/8/2001 < 1,000,000,000");
epoch += 86400;
ok ((int)epoch.toEpoch () > 1000000000, "9/9/2001 > 1,000,000,000");
Date fromEpoch (epoch.toEpoch ());
is (fromEpoch.toString (), epoch.toString (), "ctor (time_t)");
Date fromString1 ("1/1/2008");
is (fromString1.month (), 1, "ctor (std::string) -> m");
is (fromString1.day (), 1, "ctor (std::string) -> d");
is (fromString1.year (), 2008, "ctor (std::string) -> y");
Date fromString2 ("1/1/2008", "m/d/Y");
is (fromString2.month (), 1, "ctor (std::string) -> m");
is (fromString2.day (), 1, "ctor (std::string) -> d");
is (fromString2.year (), 2008, "ctor (std::string) -> y");
Date fromString3 ("20080101", "YMD");
is (fromString3.month (), 1, "ctor (std::string) -> m");
is (fromString3.day (), 1, "ctor (std::string) -> d");
is (fromString3.year (), 2008, "ctor (std::string) -> y");
Date fromString4 ("12/31/2007");
is (fromString4.month (), 12, "ctor (std::string) -> m");
is (fromString4.day (), 31, "ctor (std::string) -> d");
is (fromString4.year (), 2007, "ctor (std::string) -> y");
Date fromString5 ("12/31/2007", "m/d/Y");
is (fromString5.month (), 12, "ctor (std::string) -> m");
is (fromString5.day (), 31, "ctor (std::string) -> d");
is (fromString5.year (), 2007, "ctor (std::string) -> y");
Date fromString6 ("20071231", "YMD");
is (fromString6.month (), 12, "ctor (std::string) -> m");
is (fromString6.day (), 31, "ctor (std::string) -> d");
is (fromString6.year (), 2007, "ctor (std::string) -> y");
return 0;
}
////////////////////////////////////////////////////////////////////////////////

View File

@@ -29,6 +29,9 @@
#include <string> #include <string>
#include "task.h" #include "task.h"
static const char* newline = "\n";
static const char* noline = "";
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
void wrapText ( void wrapText (
std::vector <std::string>& lines, std::vector <std::string>& lines,
@@ -283,3 +286,12 @@ std::string lowerCase (const std::string& input)
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
const char* optionalBlankLine (Config& conf)
{
if (conf.get ("blanklines", true) == true)
return newline;
return noline;
}
////////////////////////////////////////////////////////////////////////////////

View File

@@ -182,14 +182,18 @@ const std::string uuid ()
static char randomHexDigit () static char randomHexDigit ()
{ {
static char digits[] = "0123456789abcdef"; static char digits[] = "0123456789abcdef";
#ifdef HAVE_RANDOM
return digits[random () % 16]; return digits[random () % 16];
#else
return digits[rand () % 16];
#endif
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
const std::string uuid () const std::string uuid ()
{ {
// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
char id [37]; char id [48] = {0};
id[0] = randomHexDigit (); id[0] = randomHexDigit ();
id[1] = randomHexDigit (); id[1] = randomHexDigit ();
id[2] = randomHexDigit (); id[2] = randomHexDigit ();

1227
task.html Normal file

File diff suppressed because it is too large Load Diff