mirror of
https://github.com/GothenburgBitFactory/taskwarrior.git
synced 2025-07-07 20:06:36 +02:00
Code Cleanup
- Factorize code for parsing date elements. - Better order of blocks for parsing date elements. - Add corresponding minimal-digit date parsing method for reading seconds, minutes and week. - Update documentation and test.
This commit is contained in:
parent
384be4b249
commit
ec330921de
8 changed files with 116 additions and 218 deletions
|
@ -7,6 +7,7 @@ Features
|
|||
+ Stop consider new tasks after quitting a bulk change.
|
||||
+ Removed deprecated 'fg:' and 'bg:' attributes.
|
||||
+ The 'diagnostics' command now reports libuuid details.
|
||||
+ New characters for parsing and formating dates ('n', 's' and 'v').
|
||||
|
||||
Bugs
|
||||
+ Fixed bug #1043, where aliases were not recognized by bash autocompletion.
|
||||
|
|
|
@ -493,7 +493,7 @@ will be applied
|
|||
to the date. Entered dates as well as all other displayed dates in reports
|
||||
are formatted according to dateformat.
|
||||
|
||||
The default value is: m/d/Y. The string should contain the characters:
|
||||
The default value is: m/d/Y. The string can contain the characters:
|
||||
|
||||
.RS
|
||||
.RS
|
||||
|
@ -501,13 +501,13 @@ m minimal-digit month, for example 1 or 12
|
|||
.br
|
||||
d minimal-digit day, for example 1 or 30
|
||||
.br
|
||||
y two-digit year, for example 09
|
||||
y two-digit year, for example 09 or 12
|
||||
.br
|
||||
D two-digit day, for example 01 or 30
|
||||
.br
|
||||
M two-digit month, for example 01 or 12
|
||||
.br
|
||||
Y four-digit year, for example 2009
|
||||
Y four-digit year, for example 2009 or 2012
|
||||
.br
|
||||
a short name of weekday, for example Mon or Wed
|
||||
.br
|
||||
|
@ -517,9 +517,17 @@ b short name of month, for example Jan or Aug
|
|||
.br
|
||||
B long name of month, for example January or August
|
||||
.br
|
||||
V weeknumber, for example 03 or 37
|
||||
v minimal-digit week, for example 3 or 37
|
||||
.br
|
||||
H two-digit hour, for example 03 or 11
|
||||
V two-digit week, for example 03 or 37
|
||||
.br
|
||||
h minimal-digit hour, for example 3 or 21
|
||||
.br
|
||||
n minimal-digit minutes, for example 5 or 42
|
||||
.br
|
||||
s minimal-digit seconds, for example 7 or 47
|
||||
.br
|
||||
H two-digit hour, for example 03 or 21
|
||||
.br
|
||||
N two-digit minutes, for example 05 or 42
|
||||
.br
|
||||
|
@ -527,6 +535,11 @@ S two-digit seconds, for example 07 or 47
|
|||
.RE
|
||||
.RE
|
||||
|
||||
.RS
|
||||
The characters 'v', 'V', 'a' and 'A' can only be used for formatting printed
|
||||
dates (not to parse them).
|
||||
.RE
|
||||
|
||||
.RS
|
||||
The string may also contain other characters to act as spacers, or formatting.
|
||||
Examples for other values of dateformat:
|
||||
|
@ -550,15 +563,15 @@ Examples for other values of dateformat.report:
|
|||
.RS
|
||||
.RS
|
||||
.br
|
||||
a D b Y (V) would do an output as "Fri 24 Jul 2009 (30)"
|
||||
a D b Y (V) would do an output as "Fri 24 Jul 2009 (30)"
|
||||
.br
|
||||
A, B D, Y would do an output as "Friday, July 24, 2009"
|
||||
A, B D, Y would do an output as "Friday, July 24, 2009"
|
||||
.br
|
||||
vV a Y-M-D would do an output as "v30 Fri 2009-07-24"
|
||||
wV a Y-M-D would do an output as "w30 Fri 2009-07-24"
|
||||
.br
|
||||
yMD.HN would do an output as "110124.2342"
|
||||
yMD.HN would do an output as "110124.2342"
|
||||
.br
|
||||
m/d/Y H:N would do an output as "1/24/2011 10:42"
|
||||
m/d/Y H:N would do an output as "1/24/2011 10:42"
|
||||
.br
|
||||
a D b Y H:N:S would do an output as "Mon 24 Jan 2011 11:19:42"
|
||||
.RE
|
||||
|
|
|
@ -238,10 +238,13 @@ const std::string Date::toString (
|
|||
case 'A': sprintf (buffer, "%s", Date::dayName (dayOfWeek ()).c_str ()); break;
|
||||
case 'b': sprintf (buffer, "%.3s", Date::monthName (month ()).c_str ()); break;
|
||||
case 'B': sprintf (buffer, "%.9s", Date::monthName (month ()).c_str ()); break;
|
||||
case 'v': sprintf (buffer, "%d", Date::weekOfYear (Date::dayOfWeek (context.config.get ("weekstart")))); break;
|
||||
case 'V': sprintf (buffer, "%02d", Date::weekOfYear (Date::dayOfWeek (context.config.get ("weekstart")))); break;
|
||||
case 'h': sprintf (buffer, "%d", this->hour ()); break;
|
||||
case 'H': sprintf (buffer, "%02d", this->hour ()); break;
|
||||
case 'n': sprintf (buffer, "%d", this->minute ()); break;
|
||||
case 'N': sprintf (buffer, "%02d", this->minute ()); break;
|
||||
case 's': sprintf (buffer, "%d", this->second ()); break;
|
||||
case 'S': sprintf (buffer, "%02d", this->second ()); break;
|
||||
case 'j': sprintf (buffer, "%d", this->dayOfYear ()); break;
|
||||
case 'J': sprintf (buffer, "%03d", this->dayOfYear ()); break;
|
||||
|
|
272
src/Nibbler.cpp
272
src/Nibbler.cpp
|
@ -717,6 +717,47 @@ bool Nibbler::getDateISO (time_t& t)
|
|||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#ifdef NIBBLER_FEATURE_DATE
|
||||
// Parse the longest integer using the next 'limit' characters of 'result'
|
||||
// following position 'i' (when strict is true, the number of digits must be
|
||||
// equal to limit).
|
||||
bool Nibbler::parseDigits(std::string::size_type& i,
|
||||
int& result,
|
||||
unsigned int limit,
|
||||
bool strict /* = true */)
|
||||
{
|
||||
// If the result has already been set
|
||||
if (result != -1)
|
||||
return false;
|
||||
for (unsigned int f = limit; f > 0; --f)
|
||||
{
|
||||
// Check that the nibbler has enough unparsed characters
|
||||
if (i + f <= _length)
|
||||
{
|
||||
// Check that 'f' of them are digits
|
||||
unsigned int g;
|
||||
for (g = 0; g < f; g++)
|
||||
if (! isdigit (_input[i + g]))
|
||||
break;
|
||||
// Parse the integer when it is the case
|
||||
if (g == f)
|
||||
{
|
||||
if (f == 1)
|
||||
result = _input[i] - '0';
|
||||
else
|
||||
result = atoi (_input.substr (i, f).c_str ());
|
||||
// Update the global cursor before returning
|
||||
i += f;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// Do not try smaller limits if the option is strict on the size
|
||||
if (strict)
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool Nibbler::getDate (const std::string& format, time_t& t)
|
||||
{
|
||||
std::string::size_type i = _cursor;
|
||||
|
@ -728,246 +769,85 @@ bool Nibbler::getDate (const std::string& format, time_t& t)
|
|||
int minute = -1;
|
||||
int second = -1;
|
||||
|
||||
// For parsing, unused.
|
||||
int wday = -1;
|
||||
int week = -1;
|
||||
|
||||
for (unsigned int f = 0; f < format.length (); ++f)
|
||||
{
|
||||
switch (format[f])
|
||||
{
|
||||
case 'm':
|
||||
if (i + 2 <= _length &&
|
||||
isdigit (_input[i + 0]) &&
|
||||
isdigit (_input[i + 1]))
|
||||
{
|
||||
month = atoi (_input.substr (i, 2).c_str ());
|
||||
i += 2;
|
||||
}
|
||||
else if (i + 1 <= _length &&
|
||||
isdigit (_input[i + 0]))
|
||||
{
|
||||
month = _input[i] - '0';
|
||||
i += 1;
|
||||
}
|
||||
else
|
||||
case 'M':
|
||||
if (! parseDigits(i, month, 2, format[f] == 'M'))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
if (i + 2 <= _length &&
|
||||
isdigit (_input[i + 0]) &&
|
||||
isdigit (_input[i + 1]))
|
||||
{
|
||||
day = atoi (_input.substr (i, 2).c_str ());
|
||||
i += 2;
|
||||
}
|
||||
else if (i + 1 <= _length &&
|
||||
isdigit (_input[i + 0]))
|
||||
{
|
||||
day = _input[i] - '0';
|
||||
i += 1;
|
||||
}
|
||||
else
|
||||
case 'D':
|
||||
if (! parseDigits(i, day, 2, format[f] == 'D'))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case 'y':
|
||||
if (i + 2 <= _length &&
|
||||
isdigit (_input[i + 0]) &&
|
||||
isdigit (_input[i + 1]))
|
||||
{
|
||||
year = 2000 + atoi (_input.substr (i, 2).c_str ());
|
||||
i += 2;
|
||||
}
|
||||
else
|
||||
case 'Y':
|
||||
if (! parseDigits(i, year, format[f] == 'y' ? 2 : 4))
|
||||
return false;
|
||||
if (format[f] == 'y')
|
||||
year += 2000;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
case 'H':
|
||||
if (! parseDigits(i, hour, 2, format[f] == 'H'))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case 'M':
|
||||
if (i + 2 <= _length &&
|
||||
isdigit (_input[i + 0]) &&
|
||||
isdigit (_input[i + 1]))
|
||||
{
|
||||
month = atoi (_input.substr (i, 2).c_str ());
|
||||
i += 2;
|
||||
}
|
||||
else
|
||||
case 'n':
|
||||
case 'N':
|
||||
if (! parseDigits(i, minute, 2, format[f] == 'N'))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case 'D':
|
||||
if (i + 2 <= _length &&
|
||||
isdigit (_input[i + 0]) &&
|
||||
isdigit (_input[i + 1]))
|
||||
{
|
||||
day = atoi (_input.substr (i, 2).c_str ());
|
||||
i += 2;
|
||||
}
|
||||
else
|
||||
case 's':
|
||||
case 'S':
|
||||
if (! parseDigits(i, second, 2, format[f] == 'S'))
|
||||
return false;
|
||||
break;
|
||||
|
||||
// Merely parse, not extract.
|
||||
case 'v':
|
||||
case 'V':
|
||||
if (i + 2 <= _length &&
|
||||
isdigit (_input[i + 0]) &&
|
||||
isdigit (_input[i + 1]))
|
||||
{
|
||||
day = atoi (_input.substr (i, 2).c_str ());
|
||||
i += 2;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
break;
|
||||
|
||||
case 'Y':
|
||||
if (i + 4 <= _length &&
|
||||
isdigit (_input[i + 0]) &&
|
||||
isdigit (_input[i + 1]) &&
|
||||
isdigit (_input[i + 2]) &&
|
||||
isdigit (_input[i + 3]))
|
||||
{
|
||||
year = atoi (_input.substr (i, 4).c_str ());
|
||||
i += 4;
|
||||
}
|
||||
else
|
||||
if (! parseDigits(i, week, 2, format[f] == 'V'))
|
||||
return false;
|
||||
break;
|
||||
|
||||
// Merely parse, not extract.
|
||||
case 'a':
|
||||
if (i + 3 <= _length &&
|
||||
! isdigit (_input[i + 0]) &&
|
||||
! isdigit (_input[i + 1]) &&
|
||||
! isdigit (_input[i + 2]))
|
||||
i += 3;
|
||||
else
|
||||
return false;
|
||||
break;
|
||||
|
||||
// Merely parse, not extract.
|
||||
case 'b':
|
||||
if (i + 3 <= _length &&
|
||||
! isdigit (_input[i + 0]) &&
|
||||
! isdigit (_input[i + 1]) &&
|
||||
! isdigit (_input[i + 2]))
|
||||
{
|
||||
month = Date::monthOfYear (_input.substr (i, 3).c_str());
|
||||
i += 3;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
break;
|
||||
|
||||
// Merely parse, not extract.
|
||||
case 'A':
|
||||
if (i + 3 <= _length &&
|
||||
! isdigit (_input[i + 0]) &&
|
||||
! isdigit (_input[i + 1]) &&
|
||||
! isdigit (_input[i + 2]))
|
||||
i += Date::dayName (Date::dayOfWeek (_input.substr (i, 3).c_str ())).size ();
|
||||
{
|
||||
wday = Date::dayOfWeek (_input.substr (i, 3).c_str ());
|
||||
i += (format[f] == 'a') ? 3 : Date::dayName (wday).size ();
|
||||
}
|
||||
else
|
||||
return false;
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
case 'B':
|
||||
if (i + 3 <= _length &&
|
||||
! isdigit (_input[i + 0]) &&
|
||||
! isdigit (_input[i + 1]) &&
|
||||
! isdigit (_input[i + 2]))
|
||||
{
|
||||
month = Date::monthOfYear (_input.substr (i, 3).c_str ());
|
||||
i += Date::monthName (month).size ();
|
||||
}
|
||||
else
|
||||
return false;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
if (i + 2 <= _length &&
|
||||
isdigit (_input[i + 0]) &&
|
||||
isdigit (_input[i + 1]))
|
||||
{
|
||||
hour = atoi (_input.substr (i, 2).c_str ());
|
||||
i += 2;
|
||||
}
|
||||
else if (i + 1 <= _length &&
|
||||
isdigit (_input[i + 0]))
|
||||
{
|
||||
hour = atoi (_input.substr (i, 1).c_str ());
|
||||
i += 1;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
break;
|
||||
|
||||
case 'H':
|
||||
if (i + 2 <= _length &&
|
||||
isdigit (_input[i + 0]) &&
|
||||
isdigit (_input[i + 1]))
|
||||
{
|
||||
hour = atoi (_input.substr (i, 2).c_str ());
|
||||
i += 2;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
break;
|
||||
|
||||
case 'N':
|
||||
if (i + 2 <= _length &&
|
||||
isdigit (_input[i + 0]) &&
|
||||
isdigit (_input[i + 1]))
|
||||
{
|
||||
minute = atoi (_input.substr (i, 2).c_str ());
|
||||
i += 2;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
break;
|
||||
|
||||
case 'S':
|
||||
if (i + 2 <= _length &&
|
||||
isdigit (_input[i + 0]) &&
|
||||
isdigit (_input[i + 1]))
|
||||
{
|
||||
second = atoi (_input.substr (i, 2).c_str ());
|
||||
i += 2;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
break;
|
||||
|
||||
case 'j':
|
||||
if (i + 3 <= _length &&
|
||||
isdigit (_input[i + 0]) &&
|
||||
isdigit (_input[i + 1]) &&
|
||||
isdigit (_input[i + 2]))
|
||||
{
|
||||
day = atoi (_input.substr (i, 3).c_str ());
|
||||
i += 3;
|
||||
}
|
||||
else if (i + 2 <= _length &&
|
||||
isdigit (_input[i + 0]) &&
|
||||
isdigit (_input[i + 1]))
|
||||
{
|
||||
day = atoi (_input.substr (i, 2).c_str ());
|
||||
i += 2;
|
||||
}
|
||||
else if (i + 1 <= _length &&
|
||||
isdigit (_input[i + 0]))
|
||||
{
|
||||
day = atoi (_input.substr (i, 1).c_str ());
|
||||
i += 1;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
break;
|
||||
|
||||
case 'J':
|
||||
if (i + 3 <= _length &&
|
||||
isdigit (_input[i + 0]) &&
|
||||
isdigit (_input[i + 1]) &&
|
||||
isdigit (_input[i + 2]))
|
||||
{
|
||||
day = atoi (_input.substr (i, 3).c_str ());
|
||||
i += 3;
|
||||
if (month != -1)
|
||||
return false;
|
||||
month = Date::monthOfYear (_input.substr (i, 3).c_str());
|
||||
i += (format[f] == 'b') ? 3 : Date::monthName (month).size ();
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
|
|
@ -78,6 +78,7 @@ public:
|
|||
bool getPartialUUID (std::string&);
|
||||
bool getDateISO (time_t&);
|
||||
#ifdef NIBBLER_FEATURE_DATE
|
||||
bool parseDigits(std::string::size_type&, int&, unsigned int, bool strict = true);
|
||||
bool getDate (const std::string&, time_t&);
|
||||
#endif
|
||||
bool getOneOf (const std::vector <std::string>&, std::string&);
|
||||
|
|
|
@ -207,17 +207,17 @@ int main (int argc, char** argv)
|
|||
t.is (fromString7.day (), 1, "ctor (std::string) -> d");
|
||||
t.is (fromString7.year (), 2008, "ctor (std::string) -> y");
|
||||
|
||||
Date fromString8 ("Tue 01 Jan 2008 (01)", "a D b Y (V)");
|
||||
t.is (fromString8.month (), 1, "ctor (std::string) -> m");
|
||||
t.is (fromString8.day (), 1, "ctor (std::string) -> d");
|
||||
Date fromString8 ("Tue 05 Feb 2008 (06)", "a D b Y (V)");
|
||||
t.is (fromString8.month (), 2, "ctor (std::string) -> m");
|
||||
t.is (fromString8.day (), 5, "ctor (std::string) -> d");
|
||||
t.is (fromString8.year (), 2008, "ctor (std::string) -> y");
|
||||
|
||||
Date fromString9 ("Tuesday, January 1, 2008", "A, B d, Y");
|
||||
t.is (fromString9.month (), 1, "ctor (std::string) -> m");
|
||||
t.is (fromString9.day (), 1, "ctor (std::string) -> d");
|
||||
Date fromString9 ("Tuesday, February 5, 2008", "A, B d, Y");
|
||||
t.is (fromString9.month (), 2, "ctor (std::string) -> m");
|
||||
t.is (fromString9.day (), 5, "ctor (std::string) -> d");
|
||||
t.is (fromString9.year (), 2008, "ctor (std::string) -> y");
|
||||
|
||||
Date fromString10 ("v01 Tue 2008-01-01", "vV a Y-M-D");
|
||||
Date fromString10 ("w01 Tue 2008-01-01", "wV a Y-M-D");
|
||||
t.is (fromString10.month (), 1, "ctor (std::string) -> m");
|
||||
t.is (fromString10.day (), 1, "ctor (std::string) -> d");
|
||||
t.is (fromString10.year (), 2008, "ctor (std::string) -> y");
|
||||
|
|
|
@ -57,8 +57,8 @@ if (open my $fh, '>', 'date3.rc')
|
|||
"dateformat=m/d/y\n",
|
||||
"dateformat=m/d/y\n",
|
||||
"weekstart=Monday\n",
|
||||
"dateformat.info=A D B Y (vV)\n",
|
||||
"dateformat.report=A D B Y (vV)\n";
|
||||
"dateformat.info=A D B Y (wV)\n",
|
||||
"dateformat.report=A D B Y (wV)\n";
|
||||
close $fh;
|
||||
ok (-r 'date3.rc', 'Created date3.rc');
|
||||
}
|
||||
|
@ -79,7 +79,7 @@ ok (!-r 'pending.data', 'Removed pending.data');
|
|||
|
||||
qx{../src/task rc:date3.rc add foo due:4/8/10 2>&1};
|
||||
$output = qx{../src/task rc:date3.rc list 2>&1};
|
||||
like ($output, qr/Thursday 08 April 2010 \(v14\)/, 'date format A D B Y (vV) parsed');
|
||||
like ($output, qr/Thursday 08 April 2010 \(w14\)/, 'date format A D B Y (wV) parsed');
|
||||
$output = qx{../src/task rc:date3.rc rc.dateformat.report:"D b Y - a" list 2>&1};
|
||||
like ($output, qr/08 Apr 2010 - Thu/, 'date format D b Y - a parsed');
|
||||
|
||||
|
|
|
@ -545,8 +545,8 @@ int main (int argc, char** argv)
|
|||
t.is (dt.day (), 1, "ctor (std::string) -> d");
|
||||
t.is (dt.year (), 2008, "ctor (std::string) -> y");
|
||||
|
||||
n = Nibbler ("v01 Tue 2008-01-01");
|
||||
t.ok (n.getDate ("vV a Y-M-D", ti), "vV a Y-M-D ok");
|
||||
n = Nibbler ("w01 Tue 2008-01-01");
|
||||
t.ok (n.getDate ("wV a Y-M-D", ti), "wV a Y-M-D ok");
|
||||
dt = Date (ti);
|
||||
t.is (dt.month (), 1, "ctor (std::string) -> m");
|
||||
t.is (dt.day (), 1, "ctor (std::string) -> d");
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue