Integration - attribute validation
- Implemented digitsOnly primitive. - Implemented noSpaces primitive. - Added unit tests for above. - Att now manages the lists of valid attributes and modifier names. - validName migrated to Att. - validModifiableName migrated to Att. - New Att::validNameValue. - Removed obsolete validDescription. - Removed obsolete validPriority. - Removed obsolete valid.cpp/guess. - Implemented text.cpp/noVerticalSpace. - Added unit tests for text.cpp/noVerticalSpace. - Removed final static lists from valid.cpp.
This commit is contained in:
233
src/Att.cpp
233
src/Att.cpp
@@ -28,9 +28,56 @@
|
|||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "text.h"
|
#include "text.h"
|
||||||
|
#include "color.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include "Date.h"
|
||||||
|
#include "Duration.h"
|
||||||
#include "Att.h"
|
#include "Att.h"
|
||||||
|
|
||||||
|
static char* internalNames[] =
|
||||||
|
{
|
||||||
|
"entry",
|
||||||
|
"start",
|
||||||
|
"end",
|
||||||
|
"mask",
|
||||||
|
"imask",
|
||||||
|
// "limit",
|
||||||
|
};
|
||||||
|
|
||||||
|
static char* modifiableNames[] =
|
||||||
|
{
|
||||||
|
"project",
|
||||||
|
"priority",
|
||||||
|
"fg",
|
||||||
|
"bg",
|
||||||
|
"due",
|
||||||
|
"recur",
|
||||||
|
"until",
|
||||||
|
};
|
||||||
|
|
||||||
|
static char* modifierNames[] =
|
||||||
|
{
|
||||||
|
"before",
|
||||||
|
"after",
|
||||||
|
"under",
|
||||||
|
"over",
|
||||||
|
"below",
|
||||||
|
"above",
|
||||||
|
"none",
|
||||||
|
"any",
|
||||||
|
"is",
|
||||||
|
"isnt",
|
||||||
|
"has",
|
||||||
|
"hasnt",
|
||||||
|
"contains",
|
||||||
|
"startswith",
|
||||||
|
"endswith",
|
||||||
|
};
|
||||||
|
|
||||||
|
#define NUM_INTERNAL_NAMES (sizeof (internalNames) / sizeof (internalNames[0]))
|
||||||
|
#define NUM_MODIFIABLE_NAMES (sizeof (modifiableNames) / sizeof (modifiableNames[0]))
|
||||||
|
#define NUM_MODIFIER_NAMES (sizeof (modifierNames) / sizeof (modifierNames[0]))
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
Att::Att ()
|
Att::Att ()
|
||||||
: mName ("")
|
: mName ("")
|
||||||
@@ -106,6 +153,7 @@ Att::~Att ()
|
|||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// For parsing.
|
||||||
bool Att::valid (const std::string& input) const
|
bool Att::valid (const std::string& input) const
|
||||||
{
|
{
|
||||||
Nibbler n (input);
|
Nibbler n (input);
|
||||||
@@ -132,6 +180,173 @@ bool Att::valid (const std::string& input) const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// TODO Obsolete
|
||||||
|
bool Att::validName (const std::string& name)
|
||||||
|
{
|
||||||
|
if (validModifiableName (name))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < NUM_INTERNAL_NAMES; ++i)
|
||||||
|
if (name == internalNames[i])
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// TODO Obsolete
|
||||||
|
bool Att::validModifiableName (const std::string& name)
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0; i < NUM_MODIFIABLE_NAMES; ++i)
|
||||||
|
if (name == modifiableNames[i])
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool Att::validNameValue (
|
||||||
|
const std::string& name,
|
||||||
|
const std::string& mod,
|
||||||
|
const std::string& value)
|
||||||
|
{
|
||||||
|
std::string writableName = name;
|
||||||
|
std::string writableMod = mod;
|
||||||
|
std::string writableValue = value;
|
||||||
|
bool status = Att::validNameValue (writableName, writableMod, writableValue);
|
||||||
|
|
||||||
|
if (name != writableName)
|
||||||
|
throw std::string ("The attribute '") + name + "' was not fully qualified.";
|
||||||
|
|
||||||
|
if (mod != writableMod)
|
||||||
|
throw std::string ("The modifier '") + mod + "' was not fully qualified.";
|
||||||
|
|
||||||
|
if (value != writableValue)
|
||||||
|
throw std::string ("The value '") + value + "' was not fully qualified.";
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool Att::validNameValue (
|
||||||
|
std::string& name,
|
||||||
|
std::string& mod,
|
||||||
|
std::string& value)
|
||||||
|
{
|
||||||
|
// First, guess at the full attribute name.
|
||||||
|
std::vector <std::string> candidates;
|
||||||
|
for (unsigned i = 0; i < NUM_INTERNAL_NAMES; ++i)
|
||||||
|
candidates.push_back (internalNames[i]);
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < NUM_MODIFIABLE_NAMES; ++i)
|
||||||
|
candidates.push_back (modifiableNames[i]);
|
||||||
|
|
||||||
|
std::vector <std::string> matches;
|
||||||
|
autoComplete (name, candidates, matches);
|
||||||
|
|
||||||
|
if (matches.size () == 0)
|
||||||
|
throw std::string ("Unrecognized attribute '") + name + "'";
|
||||||
|
|
||||||
|
else if (matches.size () != 1)
|
||||||
|
{
|
||||||
|
std::string error = "Ambiguous attribute '" + name + "' - could be either of "; // TODO i18n
|
||||||
|
|
||||||
|
std::string combined;
|
||||||
|
join (combined, ", ", matches);
|
||||||
|
error += combined;
|
||||||
|
|
||||||
|
throw error + combined;
|
||||||
|
}
|
||||||
|
|
||||||
|
name = matches[0];
|
||||||
|
|
||||||
|
// Second, guess at the modifier name.
|
||||||
|
candidates.clear ();
|
||||||
|
for (unsigned i = 0; i < NUM_MODIFIER_NAMES; ++i)
|
||||||
|
candidates.push_back (modifierNames[i]);
|
||||||
|
|
||||||
|
matches.clear ();
|
||||||
|
autoComplete (mod, candidates, matches);
|
||||||
|
|
||||||
|
if (matches.size () == 0)
|
||||||
|
throw std::string ("Unrecognized modifier '") + name + "'";
|
||||||
|
|
||||||
|
else if (matches.size () != 1)
|
||||||
|
{
|
||||||
|
std::string error = "Ambiguous modifier '" + name + "' - could be either of "; // TODO i18n
|
||||||
|
|
||||||
|
std::string combined;
|
||||||
|
join (combined, ", ", matches);
|
||||||
|
error += combined;
|
||||||
|
|
||||||
|
throw error + combined;
|
||||||
|
}
|
||||||
|
|
||||||
|
mod = matches[0];
|
||||||
|
|
||||||
|
// Thirdly, make sure the value has the expected form or values.
|
||||||
|
if (name == "project" && !noSpaces (value))
|
||||||
|
throw std::string ("The '") + name + "' attribute may not contain spaces.";
|
||||||
|
|
||||||
|
else if (name == "priority" && value != "")
|
||||||
|
{
|
||||||
|
value = upperCase (value);
|
||||||
|
if (value != "H" &&
|
||||||
|
value != "M" &&
|
||||||
|
value != "L")
|
||||||
|
throw std::string ("\"") +
|
||||||
|
value +
|
||||||
|
"\" is not a valid priority. Use H, M, L or leave blank.";
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (name == "description" && (value != "" || !noVerticalSpace (value)))
|
||||||
|
throw std::string ("The '") + name + "' attribute must not be blank, and must not contain vertical white space.";
|
||||||
|
|
||||||
|
else if ((name == "fg" || name == "bg") && value != "")
|
||||||
|
Text::guessColor (value);
|
||||||
|
|
||||||
|
else if (name == "due" && value != "")
|
||||||
|
Date (value);
|
||||||
|
|
||||||
|
else if (name == "until" && value != "")
|
||||||
|
Date (value);
|
||||||
|
|
||||||
|
else if (name == "recur" && value != "")
|
||||||
|
Duration (value);
|
||||||
|
|
||||||
|
else if (name == "limit" && (value == "" || !digitsOnly (value)))
|
||||||
|
throw std::string ("The '") + name + "' attribute must be an integer.";
|
||||||
|
|
||||||
|
// Some attributes are intended to be private.
|
||||||
|
else if (name == "entry" ||
|
||||||
|
name == "start" ||
|
||||||
|
name == "end" ||
|
||||||
|
name == "mask" ||
|
||||||
|
name == "imask" ||
|
||||||
|
name == "uuid" ||
|
||||||
|
name == "status")
|
||||||
|
throw std::string ("\"") +
|
||||||
|
name +
|
||||||
|
"\" is not an attribute you may modify directly.";
|
||||||
|
|
||||||
|
else
|
||||||
|
throw std::string ("'") + name + "' is an unrecognized attribute.";
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// TODO Obsolete
|
||||||
|
bool Att::validMod (const std::string& mod)
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0; i < NUM_MODIFIER_NAMES; ++i)
|
||||||
|
if (modifierNames[i] == mod)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// start --> name --> . --> mod --> : --> " --> value --> " --> end
|
// start --> name --> . --> mod --> : --> " --> value --> " --> end
|
||||||
@@ -187,22 +402,10 @@ void Att::parse (Nibbler& n)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
throw std::string ("Missing : after attribute name"); // TODO i18n
|
throw std::string ("Missing : after attribute name"); // TODO i18n
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
/* TODO This might be too slow to include. Test.
|
||||||
bool Att::validMod (const std::string& mod) const
|
validNameValue (mName, mMod, mValue);
|
||||||
{
|
*/
|
||||||
if (mod == "before" || mod == "after" || // i18n: TODO
|
|
||||||
mod == "under" || mod == "over" || // i18n: TODO
|
|
||||||
mod == "below" || mod == "above" || // i18n: TODO
|
|
||||||
mod == "none" || mod == "any" || // i18n: TODO
|
|
||||||
mod == "is" || mod == "isnt" || // i18n: TODO
|
|
||||||
mod == "has" || mod == "hasnt" || // i18n: TODO
|
|
||||||
mod == "contains" || // i18n: TODO
|
|
||||||
mod == "startswith" || mod == "endswith") // i18n: TODO
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|||||||
@@ -44,9 +44,13 @@ public:
|
|||||||
~Att ();
|
~Att ();
|
||||||
|
|
||||||
bool valid (const std::string&) const;
|
bool valid (const std::string&) const;
|
||||||
|
static bool validName (const std::string&);
|
||||||
|
static bool validModifiableName (const std::string&);
|
||||||
|
static bool validNameValue (const std::string&, const std::string&, const std::string&);
|
||||||
|
static bool validNameValue (std::string&, std::string&, std::string&);
|
||||||
|
static bool validMod (const std::string&);
|
||||||
void parse (const std::string&);
|
void parse (const std::string&);
|
||||||
void parse (Nibbler&);
|
void parse (Nibbler&);
|
||||||
bool validMod (const std::string&) const;
|
|
||||||
bool match (const Att&) const;
|
bool match (const Att&) const;
|
||||||
|
|
||||||
std::string composeF4 () const;
|
std::string composeF4 () const;
|
||||||
|
|||||||
@@ -440,7 +440,7 @@ std::cout << "[1;31m# parse post-termination description '" << *arg << "'[0m"
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (validDescription (descCandidate))
|
if (noVerticalSpace (descCandidate))
|
||||||
task.set ("description", descCandidate);
|
task.set ("description", descCandidate);
|
||||||
|
|
||||||
// TODO task.validate ()
|
// TODO task.validate ()
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ std::string handleAdd ()
|
|||||||
if (context.task.get ("priority") == "")
|
if (context.task.get ("priority") == "")
|
||||||
{
|
{
|
||||||
std::string defaultPriority = context.config.get ("default.priority", "");
|
std::string defaultPriority = context.config.get ("default.priority", "");
|
||||||
if (validPriority (defaultPriority))
|
if (Att::validNameValue ("priority", "", defaultPriority))
|
||||||
context.task.set ("priority", defaultPriority);
|
context.task.set ("priority", defaultPriority);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,6 +35,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "T.h"
|
#include "T.h"
|
||||||
#include "Date.h"
|
#include "Date.h"
|
||||||
|
#include "Duration.h"
|
||||||
#include "text.h"
|
#include "text.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
@@ -211,7 +212,7 @@ static void parseTask (T& task, const std::string& after)
|
|||||||
{
|
{
|
||||||
if (value != "")
|
if (value != "")
|
||||||
{
|
{
|
||||||
if (validPriority (value))
|
if (Att::validNameValue ("priority", "", value))
|
||||||
{
|
{
|
||||||
std::cout << "Priority modified." << std::endl;
|
std::cout << "Priority modified." << std::endl;
|
||||||
task.setAttribute ("priority", value);
|
task.setAttribute ("priority", value);
|
||||||
@@ -392,7 +393,8 @@ static void parseTask (T& task, const std::string& after)
|
|||||||
{
|
{
|
||||||
if (value != "")
|
if (value != "")
|
||||||
{
|
{
|
||||||
if (validDuration (value))
|
Duration d;
|
||||||
|
if (d.valid (value))
|
||||||
{
|
{
|
||||||
std::cout << "Recurrence modified." << std::endl;
|
std::cout << "Recurrence modified." << std::endl;
|
||||||
if (task.getAttribute ("due") != "")
|
if (task.getAttribute ("due") != "")
|
||||||
|
|||||||
@@ -175,7 +175,7 @@ static void decorateTask (T& task)
|
|||||||
std::string defaultPriority = context.config.get ("default.priority", "");
|
std::string defaultPriority = context.config.get ("default.priority", "");
|
||||||
if (task.getAttribute ("priority") == "" &&
|
if (task.getAttribute ("priority") == "" &&
|
||||||
defaultPriority != "" &&
|
defaultPriority != "" &&
|
||||||
validPriority (defaultPriority))
|
Att::validNameValue ("priority", "", defaultPriority))
|
||||||
task.setAttribute ("priority", defaultPriority);
|
task.setAttribute ("priority", defaultPriority);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -37,14 +37,8 @@
|
|||||||
#include "../auto.h"
|
#include "../auto.h"
|
||||||
|
|
||||||
// valid.cpp
|
// valid.cpp
|
||||||
void guess (const std::string&, const char**, std::string&);
|
|
||||||
bool validPriority (const std::string&);
|
|
||||||
bool validDescription (const std::string&);
|
|
||||||
bool validDuration (std::string&);
|
|
||||||
void validReportColumns (const std::vector <std::string>&);
|
void validReportColumns (const std::vector <std::string>&);
|
||||||
void validSortColumns (const std::vector <std::string>&, const std::vector <std::string>&);
|
void validSortColumns (const std::vector <std::string>&, const std::vector <std::string>&);
|
||||||
bool validAttribute (std::string&, std::string&);
|
|
||||||
bool validId (const std::string&);
|
|
||||||
bool validTag (const std::string&);
|
bool validTag (const std::string&);
|
||||||
|
|
||||||
// task.cpp
|
// task.cpp
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ Context context;
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
int main (int argc, char** argv)
|
int main (int argc, char** argv)
|
||||||
{
|
{
|
||||||
UnitTest t (94);
|
UnitTest t (109);
|
||||||
|
|
||||||
// void wrapText (std::vector <std::string>& lines, const std::string& text, const int width)
|
// void wrapText (std::vector <std::string>& lines, const std::string& text, const int width)
|
||||||
std::string text = "This is a test of the line wrapping code.";
|
std::string text = "This is a test of the line wrapping code.";
|
||||||
@@ -230,6 +230,27 @@ int main (int argc, char** argv)
|
|||||||
t.is (upperCase (""), "", "upperCase '' -> ''");
|
t.is (upperCase (""), "", "upperCase '' -> ''");
|
||||||
t.is (upperCase ("pre01_:POST"), "PRE01_:POST", "upperCase 'pre01_:POST' -> 'PRE01_:POST'");
|
t.is (upperCase ("pre01_:POST"), "PRE01_:POST", "upperCase 'pre01_:POST' -> 'PRE01_:POST'");
|
||||||
|
|
||||||
|
// bool digitsOnly (const std::string&);
|
||||||
|
t.ok (digitsOnly (""), "digitsOnly '' -> true");
|
||||||
|
t.ok (digitsOnly ("0"), "digitsOnly '0' -> true");
|
||||||
|
t.ok (digitsOnly ("123"), "digitsOnly '123' -> true");
|
||||||
|
t.notok (digitsOnly ("12fa"), "digitsOnly '12fa' -> false");
|
||||||
|
|
||||||
|
// bool noSpaces (const std::string&);
|
||||||
|
t.ok (noSpaces (""), "noSpaces '' -> true");
|
||||||
|
t.ok (noSpaces ("a"), "noSpaces 'a' -> true");
|
||||||
|
t.ok (noSpaces ("abc"), "noSpaces 'abc' -> true");
|
||||||
|
t.notok (noSpaces (" "), "noSpaces ' ' -> false");
|
||||||
|
t.notok (noSpaces ("ab cd"), "noSpaces 'ab cd' -> false");
|
||||||
|
|
||||||
|
// bool noVerticalSpace (const std::string&);
|
||||||
|
t.ok (noVerticalSpace (""), "noVerticalSpace '' -> true");
|
||||||
|
t.ok (noVerticalSpace ("a"), "noVerticalSpace 'a' -> true");
|
||||||
|
t.ok (noVerticalSpace ("abc"), "noVerticalSpace 'abc' -> true");
|
||||||
|
t.notok (noVerticalSpace ("a\nb"), "noVerticalSpace 'a\\nb' -> false");
|
||||||
|
t.notok (noVerticalSpace ("a\rb"), "noVerticalSpace 'a\\rb' -> false");
|
||||||
|
t.notok (noVerticalSpace ("a\fb"), "noVerticalSpace 'a\\fb' -> false");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
30
src/text.cpp
30
src/text.cpp
@@ -27,6 +27,7 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <ctype.h>
|
||||||
#include "Context.h"
|
#include "Context.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "text.h"
|
#include "text.h"
|
||||||
@@ -337,3 +338,32 @@ void guess (
|
|||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool digitsOnly (const std::string& input)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < input.length (); ++i)
|
||||||
|
if (!::isdigit (input[i]))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool noSpaces (const std::string& input)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < input.length (); ++i)
|
||||||
|
if (::isspace (input[i]))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool noVerticalSpace (const std::string& input)
|
||||||
|
{
|
||||||
|
if (input.find_first_of ("\n\r\f") != std::string::npos)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|||||||
@@ -46,6 +46,9 @@ std::string lowerCase (const std::string&);
|
|||||||
std::string upperCase (const std::string&);
|
std::string upperCase (const std::string&);
|
||||||
const char* optionalBlankLine ();
|
const char* optionalBlankLine ();
|
||||||
void guess (const std::string&, std::vector<std::string>&, std::string&);
|
void guess (const std::string&, std::vector<std::string>&, std::string&);
|
||||||
|
bool digitsOnly (const std::string&);
|
||||||
|
bool noSpaces (const std::string&);
|
||||||
|
bool noVerticalSpace (const std::string&);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|||||||
125
src/valid.cpp
125
src/valid.cpp
@@ -40,141 +40,20 @@
|
|||||||
|
|
||||||
extern Context context;
|
extern Context context;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// NOTE: These are static arrays only because there is no initializer list for
|
|
||||||
// std::vector until C++0x.
|
|
||||||
|
|
||||||
// TODO Obsolete
|
|
||||||
static const char* attributes[] =
|
|
||||||
{
|
|
||||||
"project",
|
|
||||||
"priority",
|
|
||||||
"fg",
|
|
||||||
"bg",
|
|
||||||
"due",
|
|
||||||
"entry",
|
|
||||||
"start",
|
|
||||||
"end",
|
|
||||||
"recur",
|
|
||||||
"until",
|
|
||||||
"mask",
|
|
||||||
"imask",
|
|
||||||
// "limit",
|
|
||||||
"",
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO Relocate inside Context.
|
// TODO Relocate inside Context.
|
||||||
static std::vector <std::string> customReports;
|
static std::vector <std::string> customReports;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
void guess (
|
|
||||||
const std::string& type,
|
|
||||||
const char** list,
|
|
||||||
std::string& candidate)
|
|
||||||
{
|
|
||||||
std::vector <std::string> options;
|
|
||||||
for (int i = 0; list[i][0]; ++i)
|
|
||||||
options.push_back (list[i]);
|
|
||||||
|
|
||||||
guess (type, options, candidate);
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
bool validPriority (const std::string& input)
|
|
||||||
{
|
|
||||||
if (input != "H" &&
|
|
||||||
input != "M" &&
|
|
||||||
input != "L" &&
|
|
||||||
input != "")
|
|
||||||
throw std::string ("\"") +
|
|
||||||
input +
|
|
||||||
"\" is not a valid priority. Use H, M, L or leave blank.";
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// All attributes, regardless of usage.
|
|
||||||
// TODO Relocate to Att.cpp.
|
|
||||||
bool validAttribute (std::string& name, std::string& value)
|
|
||||||
{
|
|
||||||
guess ("attribute", attributes, name);
|
|
||||||
if (name != "")
|
|
||||||
{
|
|
||||||
if ((name == "fg" || name == "bg") && value != "")
|
|
||||||
Text::guessColor (value);
|
|
||||||
|
|
||||||
else if (name == "due" && value != "")
|
|
||||||
Date (value);
|
|
||||||
|
|
||||||
else if (name == "until" && value != "")
|
|
||||||
Date (value);
|
|
||||||
|
|
||||||
else if (name == "priority")
|
|
||||||
{
|
|
||||||
value = upperCase (value);
|
|
||||||
return validPriority (value);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Some attributes are intended to be private.
|
|
||||||
else if (name == "entry" ||
|
|
||||||
name == "start" ||
|
|
||||||
name == "end" ||
|
|
||||||
name == "mask" ||
|
|
||||||
name == "imask")
|
|
||||||
throw std::string ("\"") +
|
|
||||||
name +
|
|
||||||
"\" is not an attribute you may modify directly.";
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
bool validId (const std::string& input)
|
|
||||||
{
|
|
||||||
if (input.length () == 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < input.length (); ++i)
|
|
||||||
if (!::isdigit (input[i]))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
bool validTag (const std::string& input)
|
bool validTag (const std::string& input)
|
||||||
{
|
{
|
||||||
if ((input[0] == '-' || input[0] == '+') &&
|
if ((input[0] == '-' || input[0] == '+') &&
|
||||||
input.length () > 1)
|
input.length () > 1 &&
|
||||||
|
noSpaces (input))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
bool validDescription (const std::string& input)
|
|
||||||
{
|
|
||||||
if (input.length () &&
|
|
||||||
input.find ("\r") == std::string::npos &&
|
|
||||||
input.find ("\f") == std::string::npos &&
|
|
||||||
input.find ("\n") == std::string::npos)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
bool validDuration (std::string& input)
|
|
||||||
{
|
|
||||||
try { Duration (input); }
|
|
||||||
catch (...) { return false; }
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
void validReportColumns (const std::vector <std::string>& columns)
|
void validReportColumns (const std::vector <std::string>& columns)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user