New class QCronField.

This commit is contained in:
vincent 2015-12-21 17:35:32 +01:00
parent c8a21f4eeb
commit 959f82eba1
6 changed files with 282 additions and 244 deletions

@ -1,5 +1,6 @@
set(${PROJECT}_SRC_FILES
qcron.cpp
qcronfield.cpp
)
set(${PROJECT}_HEADERS

@ -35,173 +35,12 @@ QCron::
_init()
{
_is_valid = true;
_fields[0].field = MINUTE;
_fields[1].field = HOUR;
_fields[2].field = DOM;
_fields[3].field = MONTH;
_fields[4].field = DOW;
_fields[5].field = YEAR;
}
/******************************************************************************/
QString
QCron::
_validCharacters(EField field)
{
Q_UNUSED(field);
return "0123456789*-/,";
}
/******************************************************************************/
QCron::IntNode *
QCron::
QCronField::parseInt(QString & str)
{
IntNode * node = new IntNode();
int value = 0;
int char_idx = 0;
QChar c = str[char_idx];
while (c.isDigit())
{
value = value * 10 + c.digitValue();
c = str[++char_idx];
}
if (char_idx == 0)
{
throw 42;
}
str.remove(0, char_idx);
node->value = value;
//qDebug() << "Parsing an Int :" << value;
switch (field)
{
case MINUTE: if (value < 0 || 59 < value) throw 42; break;
case HOUR: if (value < 0 || 23 < value) throw 42; break;
case DOM: if (value < 1 || 31 < value) throw 42; break;
case MONTH: if (value < 1 || 12 < value) throw 42; break;
case DOW: if (value < 1 || 7 < value) throw 42; break;
case YEAR: if (value < 2016 || 2099 < value) throw 42; break;
default: throw 42; break;
}
return node;
}
QCron::RangeNode*
QCron::
QCronField::parseRange(QString & str)
{
// qDebug() << "Parsing a Range";
if (last_node == NULL)
{
throw 42;
}
RangeNode * range = new RangeNode();
IntNode * begin = dynamic_cast<IntNode *>(last_node);
if (begin == NULL)
{
throw 42;
}
range->begin = begin;
str.remove(0, 1);
IntNode * end = dynamic_cast<IntNode *>(parseInt(str));
if (end == NULL)
{
throw 42;
}
range->end = end;
if (range->begin->value > range->end->value)
{
throw 42;
}
return range;
}
QCron::EveryNode*
QCron::
QCronField::parseEvery(QString & str)
{
// qDebug() << "Parsing an Every";
EveryNode * every = new EveryNode();
every->what = last_node;
str.remove(0, 1);
every->freq = parseInt(str);
return every;
}
QCron::ListNode*
QCron::
QCronField::parseList(QString & str)
{
// qDebug() << "Parsing a List";
ListNode * list = new ListNode();
list->nodes << last_node;
last_node = list;
while (str[0] == ',')
{
str.remove(0, 1);
Node * node = parseNode(str);
list->nodes << node;
last_node = node;
}
return list;
}
QCron::Node *
QCron::
QCronField::
parseNode(QString & str)
{
//qDebug() << "Parsing a node";
QChar c = str[0];
if (c.isDigit())
{
return parseInt(str);
}
else if ("-" == c)
{
return parseRange(str);
}
else if ("/" == c)
{
return parseEvery(str);
}
else if ("*" == c)
{
return new AllNode;
}
else if ("," == c)
{
return parseList(str);
}
throw 42;
}
/******************************************************************************/
void
QCron::
QCronField::
parse(QString & str)
{
try
{
last_node = NULL;
Node * root = parseNode(str);
if (!str.isEmpty())
{
last_node = root;
root = parseNode(str);
}
is_valid = true;
}
catch (int)
{
is_valid = false;
}
_fields[0].setField(MINUTE);
_fields[1].setField(HOUR);
_fields[2].setField(DOM);
_fields[3].setField(MONTH);
_fields[4].setField(DOW);
_fields[5].setField(YEAR);
}
/******************************************************************************/
@ -224,13 +63,17 @@ _parsePattern(QString & pattern)
for (int i = 0; i < 6; ++i)
{
_fields[i].parse(fields[i]);
_is_valid &= _fields[i].is_valid;
_is_valid &= _fields[i].isValid();
}
}
/******************************************************************************/
/*
*/
QDateTime
QCron::
next(int n) const
{
Q_UNUSED(n);
//QCronField seconds = _fields[0];
return QDateTime::currentDateTime();
}

@ -2,6 +2,8 @@
#define _QCRON_HPP
#include <QObject>
#include <QDateTime>
#include "qcronfield.hpp"
class QCron : public QObject
{
@ -12,87 +14,25 @@ public:
QCron(QString & pattern);
~QCron();
// Features.
// Accessors.
void setBeginning(const QDateTime & date_time)
{ _beginning = date_time; }
bool isValid() const
{ return _is_valid; }
// Features.
QDateTime next(int n = 1) const;
signals:
void activated();
void deactivated();
private:
enum EField
{
MINUTE,
HOUR,
DOM,
MONTH,
DOW,
YEAR
};
struct Node
{
virtual ~Node() {}
};
struct ValueNode : public Node
{
};
struct IntNode : public ValueNode
{
int value;
};
struct StrNode : public ValueNode
{
};
struct AllNode : public ValueNode
{
};
struct RangeNode : public Node
{
IntNode * begin;
IntNode * end;
};
struct EveryNode : public Node
{
Node * what;
IntNode * freq;
};
struct ListNode : public Node
{
QList<Node*> nodes;
};
struct QCronField
{
EField field;
bool is_valid;
Node * last_node;
Node * root;
QCronField()
: is_valid(false)
{}
IntNode * parseInt(QString & str);
RangeNode* parseRange(QString & str);
EveryNode* parseEvery(QString & str);
ListNode * parseList(QString & str);
Node * parseNode(QString & str);
void parse(QString&);
};
bool _is_valid;
QCronField _fields[6];
QDateTime _beginning;
void _init();
void _parsePattern(QString & pattern);

165
src/qcronfield.cpp Normal file

@ -0,0 +1,165 @@
#include "qcronfield.hpp"
/******************************************************************************/
QCronField::
QCronField()
: _is_valid(false)
{}
/******************************************************************************/
IntNode *
QCronField::
_parseInt(QString & str)
{
IntNode * node = new IntNode();
int value = 0;
int char_idx = 0;
QChar c = str[char_idx];
while (c.isDigit())
{
value = value * 10 + c.digitValue();
c = str[++char_idx];
}
if (char_idx == 0)
{
throw 42;
}
str.remove(0, char_idx);
node->value = value;
//qDebug() << "Parsing an Int :" << value;
switch (_field)
{
case MINUTE: if (value < 0 || 59 < value) throw 42; break;
case HOUR: if (value < 0 || 23 < value) throw 42; break;
case DOM: if (value < 1 || 31 < value) throw 42; break;
case MONTH: if (value < 1 || 12 < value) throw 42; break;
case DOW: if (value < 1 || 7 < value) throw 42; break;
case YEAR: if (value < 2016 || 2099 < value) throw 42; break;
default: throw 42; break;
}
return node;
}
/******************************************************************************/
RangeNode*
QCronField::
_parseRange(QString & str)
{
// qDebug() << "Parsing a Range";
if (_last_node == NULL)
{
throw 42;
}
RangeNode * range = new RangeNode();
IntNode * begin = dynamic_cast<IntNode *>(_last_node);
if (begin == NULL)
{
throw 42;
}
range->begin = begin;
str.remove(0, 1);
IntNode * end = dynamic_cast<IntNode *>(_parseInt(str));
if (end == NULL)
{
throw 42;
}
range->end = end;
if (range->begin->value > range->end->value)
{
throw 42;
}
return range;
}
/******************************************************************************/
EveryNode*
QCronField::
_parseEvery(QString & str)
{
// qDebug() << "Parsing an Every";
EveryNode * every = new EveryNode();
every->what = _last_node;
str.remove(0, 1);
every->freq = _parseInt(str);
return every;
}
/******************************************************************************/
ListNode*
QCronField::
_parseList(QString & str)
{
// qDebug() << "Parsing a List";
ListNode * list = new ListNode();
list->nodes << _last_node;
_last_node = list;
while (str[0] == ',')
{
str.remove(0, 1);
Node * node = _parseNode(str);
list->nodes << node;
_last_node = node;
}
return list;
}
/******************************************************************************/
Node *
QCronField::
_parseNode(QString & str)
{
//qDebug() << "Parsing a node";
QChar c = str[0];
if (c.isDigit())
{
return _parseInt(str);
}
else if ("-" == c)
{
return _parseRange(str);
}
else if ("/" == c)
{
return _parseEvery(str);
}
else if ("*" == c)
{
return new AllNode;
}
else if ("," == c)
{
return _parseList(str);
}
throw 42;
}
/******************************************************************************/
void
QCronField::
parse(QString & str)
{
try
{
_last_node = NULL;
Node * _root = _parseNode(str);
if (!str.isEmpty())
{
_last_node = _root;
_root = _parseNode(str);
}
_is_valid = true;
}
catch (int)
{
_is_valid = false;
}
}
/******************************************************************************/

84
src/qcronfield.hpp Normal file

@ -0,0 +1,84 @@
#ifndef _QCRONFIELD_HPP
#define _QCRONFIELD_HPP
#include <QList>
#include <QString>
enum EField
{
MINUTE,
HOUR,
DOM,
MONTH,
DOW,
YEAR
};
struct Node
{
virtual ~Node() {}
};
struct ValueNode : public Node
{
};
struct IntNode : public ValueNode
{
int value;
};
struct StrNode : public ValueNode
{
};
struct AllNode : public ValueNode
{
};
struct RangeNode : public Node
{
IntNode * begin;
IntNode * end;
};
struct EveryNode : public Node
{
Node * what;
IntNode * freq;
};
struct ListNode : public Node
{
QList<Node*> nodes;
};
class QCronField
{
public:
QCronField();
// Accessors.
void setField(EField field)
{ _field = field; }
// Features.
void parse(QString & str);
bool isValid() const
{ return _is_valid; }
private:
EField _field;
bool _is_valid;
Node * _last_node;
Node * _root;
IntNode * _parseInt(QString & str);
RangeNode* _parseRange(QString & str);
EveryNode* _parseEvery(QString & str);
ListNode * _parseList(QString & str);
Node * _parseNode(QString & str);
};
#endif

@ -8,7 +8,12 @@ void
QCronTest::
basics()
{
QFAIL("Nothing here.");
QDateTime now = QDateTime::currentDateTime();
QCron c("* * * * * *");
c.setBeginning(now);
QDateTime next = c.next();
qDebug() << next;
QFAIL("Nope!");
}
/******************************************************************************/