Compare commits

...

52 Commits

Author SHA1 Message Date
Paul Beckingham
6673e408a2 - Now uses "defaultwidth" configuration variable for when ncurses support is not available
- Added the new movie to the task.html page
2008-06-19 22:41:09 -04:00
Paul Beckingham
422ad576ea - Added latest bug fix details. 2008-06-19 21:23:15 -04:00
Paul Beckingham
c1a1d13aab - Updated version 1.3.0 to 1.4.0
- Applied "showage" configuration variable to long list
2008-06-19 21:21:21 -04:00
Paul Beckingham
42189ce998 - Added some idea details 2008-06-19 21:01:14 -04:00
Paul Beckingham
43287d7fc9 - Corrected AUTHORS file
- Added new commands to task.html
2008-06-18 01:08:34 -04:00
Paul Beckingham
06f6aaaded - Minor doc updates before 1.3.0 is cut. 2008-06-18 00:45:12 -04:00
Paul Beckingham
0c17986303 - Added "task oldest" command
- Added "task newest" command
2008-06-18 00:41:33 -04:00
Paul Beckingham
feb9959907 - Added new bug fixes to task.html 2008-06-18 00:08:53 -04:00
Paul Beckingham
7409e23ce0 - Displays shorter message when a command is entered incorrectly, and the full usage for "task help". 2008-06-18 00:05:51 -04:00
Paul Beckingham
4572c97c9d - Fixed bug whereby "1 wks" was being improperly pluralized 2008-06-17 23:56:39 -04:00
Paul Beckingham
9bca303113 - Factored out filtering code. 2008-06-17 23:40:37 -04:00
Paul Beckingham
7fb3ab0c3d - Marked bug as fixed. 2008-06-17 23:05:41 -04:00
Paul Beckingham
56037fe3bc - Added latest bug fix. 2008-06-17 23:03:50 -04:00
Paul Beckingham
a2f8ce41cf - Began full command line parser BNF grammar. 2008-06-17 22:54:04 -04:00
Paul Beckingham
598bd3b4ef - Fixed crash bug in Date::toString
- New ideas file.
2008-06-17 22:23:31 -04:00
Paul Beckingham
315a7d69fb - Updated ChangeLog
- Removed AdSense HTML fragment
- Created new ideas.txt file to illustrate usage of proposed features
2008-06-17 22:10:07 -04:00
Paul Beckingham
64fff6c2ff - Added Google Analytics. 2008-06-17 22:03:38 -04:00
Paul Beckingham
969ecd7b5d Merge branch 'master' into 1.3.0 2008-06-17 18:48:23 -04:00
Paul Beckingham
cede865693 - Partial fix to bug - snapshot. 2008-06-17 18:28:24 -04:00
Paul Beckingham
d68395bc51 - Fixed bug whereby if you have more than one task with a due date, 7 days gets added to the entry date of task 2..n 2008-06-17 17:52:12 -04:00
Paul Beckingham
7ec523d5ea - Removed unused std::vector forms of get/set
- Added more defaults to Config::createDefault
2008-06-16 23:37:32 -04:00
Paul Beckingham
08fc906d5f - Updated various documents. 2008-06-16 23:26:22 -04:00
Paul Beckingham
f3e995ef92 Merge branch 'damian' into 1.3.0 2008-06-16 22:26:20 -04:00
Paul Beckingham
a4304c97af - Corrected the "30 days in August" bug.
- Removed odd styling from task.html CSS.
2008-06-16 22:24:49 -04:00
Paul Beckingham
d1ef0d17d5 - Integrated Damian Glenny's changes 2008-06-15 18:38:01 -04:00
Paul Beckingham
c54cb4d6c8 - Bumped version to 1.3.0 2008-06-14 13:55:35 -04:00
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
25 changed files with 2802 additions and 770 deletions

12
AUTHORS
View File

@@ -1,6 +1,14 @@
Principal Author Principal Author:
Paul Beckingham, paul@beckingham.net Paul Beckingham, paul@beckingham.net
Contributing Authors Contributing Authors:
Damian Glenny
With thanks to:
Eugene Kramer
Srijith K
Richard Querin
Bruce Israel
Thomas Engel
Nishiishii

View File

@@ -1,8 +1,60 @@
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
- Dependencies
1.4.0 (?)
+ Bug: "showage" configuration variable should apply to all reprts, not
just the ones based on "list"
+ New configuration variable, "defaultwidth" that determines the width
of tables when ncurses support is not available
------ reality ----------------------------------- ------ reality -----------------------------------
1.3.0 (6/18/2008)
+ "task calendar" now displays multiple months per line, adjustable by the
"monthsperline" configuration variable. Feature added by Damian Glenny
+ "task export" can now filter tasks like the reports
+ Factored out code to filter tasks
+ Displays shorter message when a command is entered incorrectly, and the
full usage for "task help"
+ "task oldest" shows the oldest tasks
+ "task newest" shows the newest tasks
+ Bug: Segmentation fault when no "dateformat" configuration variable
specified
+ Bug: Fixed bug whereby if you have more than one task with a due date, 7
days gets added to the entry date of task 2..n
+ Bug: Fixed bug whereby "1 wks" was being improperly pluralized
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 +160,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.4.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

166
TUTORIAL
View File

@@ -1,4 +1,4 @@
Task program tutorial, for version 1.0.0 Task program tutorial, for version 1.4.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.4.0.tar.gz
% gunzip task-1.0.0.tar.gz % gunzip task-1.4.0.tar.gz
% tar xf task-1.0.0.tar % tar xf task-1.4.0.tar
% cd task-1.0.0 % cd task-1.4.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
... ...
@@ -345,13 +379,29 @@ with no arguments will generate a help message that lists all these commands.
% task oldest
-------------
Lists the oldest tasks. Shows 10 tasks by default, but can be set via the
"oldest" configuration variable.
% task newest
-------------
Lists the newest tasks. Shows 10 tasks by default, but can be set via the
"newest" configuration variable.
% task history % task history
-------------- --------------
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 +459,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 +480,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 +604,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 +671,51 @@ 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
(but are not limited to):
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.
monthsperline Determines how many months the "task calendar" command
renders across the screen. Defaults to 1.
oldest Determines how many tasks are shown on the "oldest"
report. Defaults to 10.
newest Determines how many tasks are shown on the "newest"
report. Defaults to 10.
defaultwidth The width of tables used when ncurses support is not
available. Defaults to 80.
color May be "on" or "off". Determines whether task uses color May be "on" or "off". Determines whether task uses
color. color.
@@ -614,7 +728,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.

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.4.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

68
grammar.txt Normal file
View File

@@ -0,0 +1,68 @@
This is a full BNF grammar for the task command line. It is intended that a
future release of task will incorporate a complete lexer/parser implementing
this grammar.
command:
VERSION
| HELP
| PROJECTS
| TAGS
| SUMMARY
| HISTORY
| NEXT
| CALENDAR
| ACTIVE
| OVERDUE
| STATS
| USAGE
| OLDEST
| NEWEST
| EXPORT <file>
| COLOR
| DELETE <id>
| INFO <id>
| START <id>
| DONE <id>
| ADD [<tags>] [<attrs>] [<desc>]
| LIST [<tags>] [<attrs>] [<desc>]
| LONG [<tags>] [<attrs>] [<desc>]
| LS [<tags>] [<attrs>] [<desc>]
| COMPLETED [<tags>] [<attrs>] [<desc>]
| <id> [<tags>] [<attrs>] [<desc>]
| <id> <substitution>
id:
\d+
| \d{8}-\d{4}-\d{4}-\d{12}
tags:
+<tag>
| -<tag>
tag:
\w+
attrs:
<attr>
| <attr> <attrs>
attr:
<name>:<value>
name:
\w+
value:
.+
substitution:
/ <pattern> / <pattern> /
pattern:
.+
file:
?

17
ideas.txt Normal file
View File

@@ -0,0 +1,17 @@
Real Parsing
define grammar for command line
implement flex/bison parser
User-Defined Reports
report.xxx=id,project(2+),priority(1-),description
change all list-based reports to user-defined
Generalized Report Writer
provide column list, sort order, filter
Test Suite
allow .taskrc override
debug=on to cause all cout to be csv
regression tests for every bug, command, feature

2
src/.gitignore vendored
View File

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

View File

@@ -116,6 +116,9 @@ void Config::createDefault (const std::string& file)
fprintf (out, "confirmation=yes\n"); fprintf (out, "confirmation=yes\n");
fprintf (out, "#nag=Note: try to stick to high priority tasks. See \"task next\".\n"); fprintf (out, "#nag=Note: try to stick to high priority tasks. See \"task next\".\n");
fprintf (out, "next=2\n"); fprintf (out, "next=2\n");
fprintf (out, "dateformat=m/d/Y\n");
fprintf (out, "showage=yes\n");
fprintf (out, "monthsperline=1\n");
fprintf (out, "curses=on\n"); fprintf (out, "curses=on\n");
fprintf (out, "color=on\n"); fprintf (out, "color=on\n");
@@ -136,7 +139,10 @@ 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 ("dateformat", "m/d/Y");
set ("showage", "yes");
set ("monthsperline", 3);
set ("curses", "on"); set ("curses", "on");
set ("color", "on"); set ("color", "on");
set ("color.overdue", "red"); set ("color.overdue", "red");
@@ -246,29 +252,6 @@ void Config::set (const std::string& key, const std::string& value)
(*this)[key] = value; (*this)[key] = value;
} }
////////////////////////////////////////////////////////////////////////////////
// The vector form of Config::get assumes the single value is comma-separated,
// and splits accordingly.
void Config::get (
const std::string& key,
std::vector <std::string>& values)
{
values.clear ();
split (values, (*this)[key], ',');
}
////////////////////////////////////////////////////////////////////////////////
// The vector form of Config::set joins the values together with commas, and
// stores the single value.
void Config::set (
const std::string& key,
const std::vector <std::string>& values)
{
std::string conjoined;
join (conjoined, ",", values);
(*this)[key] = conjoined;
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Provide a vector of all configuration keys. // Provide a vector of all configuration keys.
void Config::all (std::vector<std::string>& items) void Config::all (std::vector<std::string>& items)

View File

@@ -47,11 +47,9 @@ public:
bool get (const std::string&, bool); bool get (const std::string&, bool);
int get (const std::string&, const int); int get (const std::string&, const int);
double get (const std::string&, const double); double get (const std::string&, const double);
void get (const std::string&, std::vector <std::string>&);
void set (const std::string&, const int); void set (const std::string&, const int);
void set (const std::string&, const double); void set (const std::string&, const double);
void set (const std::string&, const std::string&); void set (const std::string&, const std::string&);
void set (const std::string&, const std::vector <std::string>&);
void all (std::vector <std::string>&); void all (std::vector <std::string>&);
}; };

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,32 @@ void Date::toMDY (int& m, int& d, int& y)
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void Date::toString (std::string& output) const std::string Date::toString (const std::string& format /*= "m/d/Y" */) const
{ {
output = toString (); // Making this local copy seems to fix a bug. Remove the local copy and you'll
} // see segmentation faults and all kinds of gibberish.
std::string localFormat = format;
//////////////////////////////////////////////////////////////////////////////// char buffer[12];
std::string Date::toString (void) std::string formatted;
{ for (unsigned int i = 0; i < localFormat.length (); ++i)
int m, d, y; {
toMDY (m, d, y); char c = localFormat[i];
switch (c)
{
case 'm': sprintf (buffer, "%d", this->month ()); break;
case 'M': sprintf (buffer, "%02d", this->month ()); break;
case 'd': sprintf (buffer, "%d", this->day ()); break;
case 'D': sprintf (buffer, "%02d", this->day ()); break;
case 'y': sprintf (buffer, "%02d", this->year () % 100); break;
case 'Y': sprintf (buffer, "%d", this->year ()); break;
default: sprintf (buffer, "%c", c); break;
}
char formatted [11]; formatted += buffer;
sprintf (formatted, "%d/%d/%d", m, d, y); }
return std::string (formatted);
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&); const std::string toString (const std::string& format = "m/d/Y") const;
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

@@ -120,12 +120,15 @@ static const char* commands[] =
"delete", "delete",
"done", "done",
"export", "export",
"help",
"history", "history",
"info", "info",
"list", "list",
"long", "long",
"ls", "ls",
"newest",
"next", "next",
"oldest",
"overdue", "overdue",
"projects", "projects",
"start", "start",
@@ -185,29 +188,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 +214,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 +222,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 +322,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 +357,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];

File diff suppressed because it is too large Load Diff

View File

@@ -36,6 +36,10 @@
#include "T.h" #include "T.h"
#include "../auto.h" #include "../auto.h"
#ifndef min
#define min(a,b) ((a) < (b) ? (a) : (b))
#endif
#ifndef max #ifndef max
#define max(a,b) ((a) > (b) ? (a) : (b)) #define max(a,b) ((a) > (b) ? (a) : (b))
#endif #endif
@@ -49,8 +53,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&);
@@ -69,6 +73,8 @@ void handleReportCalendar (const TDB&, T&, Config&);
void handleReportActive (const TDB&, T&, Config&); void handleReportActive (const TDB&, T&, Config&);
void handleReportOverdue (const TDB&, T&, Config&); void handleReportOverdue (const TDB&, T&, Config&);
void handleReportStats (const TDB&, T&, Config&); void handleReportStats (const TDB&, T&, Config&);
void handleReportOldest (const TDB&, T&, Config&);
void handleReportNewest (const TDB&, T&, Config&);
void handleVersion (Config&); void handleVersion (Config&);
void handleExport (const TDB&, T&, Config&); void handleExport (const TDB&, T&, Config&);
void handleDelete (const TDB&, T&, Config&); void handleDelete (const TDB&, T&, Config&);
@@ -97,6 +103,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

@@ -80,19 +80,19 @@ void formatTimeDeltaDays (std::string& output, time_t delta)
if (days > 365) if (days > 365)
sprintf (formatted, "%.1f yrs", (days / 365.2422)); sprintf (formatted, "%.1f yrs", (days / 365.2422));
else if (days > 84) else if (days > 84)
sprintf (formatted, "%1d mths", (int) (days / 30.6)); sprintf (formatted, "%1d mth%s", (int) (days / 30.6), ((int) (days / 30.6) == 1 ? "" : "s"));
else if (days > 13) else if (days > 13)
sprintf (formatted, "%d wks", (int) (days / 7.0)); sprintf (formatted, "%d wk%s", (int) (days / 7.0), ((int) (days / 7.0) == 1 ? "" : "s"));
else if (days > 5.0) else if (days > 5.0)
sprintf (formatted, "%d days", (int) days); sprintf (formatted, "%d day%s", (int) days, ((int) days == 1 ? "" : "s"));
else if (days > 1.0) else if (days > 1.0)
sprintf (formatted, "%.1f days", days); sprintf (formatted, "%.1f days", days);
else if (days * 24 > 1.0) else if (days * 24 > 1.0)
sprintf (formatted, "%d hrs", (int) (days * 24.0)); sprintf (formatted, "%d hr%s", (int) (days * 24.0), ((int) (days * 24.0) == 1 ? "" : "s"));
else if (days * 24 * 60 > 1) else if (days * 24 * 60 > 1)
sprintf (formatted, "%d mins", (int) (days * 24 * 60)); sprintf (formatted, "%d min%s", (int) (days * 24 * 60), ((int) (days * 24 * 60) == 1 ? "" : "s"));
else if (days * 24 * 60 * 60 > 1) else if (days * 24 * 60 * 60 > 1)
sprintf (formatted, "%d secs", (int) (days * 24 * 60 * 60)); sprintf (formatted, "%d sec%s", (int) (days * 24 * 60 * 60), ((int) (days * 24 * 60 * 60) == 1 ? "" : "s"));
else else
strcpy (formatted, "-"); strcpy (formatted, "-");
@@ -108,19 +108,19 @@ std::string formatSeconds (time_t delta)
if (days > 365) if (days > 365)
sprintf (formatted, "%.1f yrs", (days / 365.2422)); sprintf (formatted, "%.1f yrs", (days / 365.2422));
else if (days > 84) else if (days > 84)
sprintf (formatted, "%1d mths", (int) (days / 30.6)); sprintf (formatted, "%1d mth%s", (int) (days / 30.6), ((int) (days / 30.6) == 1 ? "" : "s"));
else if (days > 13) else if (days > 13)
sprintf (formatted, "%d wks", (int) (days / 7.0)); sprintf (formatted, "%d wk%s", (int) (days / 7.0), ((int) (days / 7.0) == 1 ? "" : "s"));
else if (days > 5.0) else if (days > 5.0)
sprintf (formatted, "%d days", (int) days); sprintf (formatted, "%d day%s", (int) days, ((int) days == 1 ? "" : "s"));
else if (days > 1.0) else if (days > 1.0)
sprintf (formatted, "%.1f days", days); sprintf (formatted, "%.1f days", days);
else if (days * 24 > 1.0) else if (days * 24 > 1.0)
sprintf (formatted, "%d hrs", (int) (days * 24.0)); sprintf (formatted, "%d hr%s", (int) (days * 24.0), ((int) (days * 24) == 1 ? "" : "s"));
else if (days * 24 * 60 > 1) else if (days * 24 * 60 > 1)
sprintf (formatted, "%d mins", (int) (days * 24 * 60)); sprintf (formatted, "%d min%s", (int) (days * 24 * 60), ((int) (days * 24 * 60) == 1 ? "" : "s"));
else if (days * 24 * 60 * 60 > 1) else if (days * 24 * 60 * 60 > 1)
sprintf (formatted, "%d secs", (int) (days * 24 * 60 * 60)); sprintf (formatted, "%d sec%s", (int) (days * 24 * 60 * 60), ((int) (days * 24 * 60 * 60) == 1 ? "" : "s"));
else else
strcpy (formatted, "-"); strcpy (formatted, "-");
@@ -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 ();

1317
task.html Normal file

File diff suppressed because it is too large Load Diff