summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrandomdan <randomdan@localhost>2011-02-03 12:45:52 +0000
committerrandomdan <randomdan@localhost>2011-02-03 12:45:52 +0000
commitc8c81d7327f38f7b4ab7c83da75d5ae4480e4dce (patch)
treecccf064db358c6f7aacf004dc68e677f6175dfa0
parentChange FsRows to return a ptime for moddate (diff)
downloadproject2-c8c81d7327f38f7b4ab7c83da75d5ae4480e4dce.tar.bz2
project2-c8c81d7327f38f7b4ab7c83da75d5ae4480e4dce.tar.xz
project2-c8c81d7327f38f7b4ab7c83da75d5ae4480e4dce.zip
Add missing conversion in generic visitor
Whole new improved variable system (does drop VariableParse, no longer required) Add option to count, but not include, blank lines in proc and file rows File file rows to open files, not execute them Fix to ODBC API with strings that don't use the whole buffer XML changes to site to use new variable system Changes to GB importer to use FS rows and new SQL merge now that it's a) tested and b) variable parse has gone
-rw-r--r--project2/fileRows.cpp22
-rw-r--r--project2/fileRows.h1
-rw-r--r--project2/fsRows.cpp12
-rw-r--r--project2/genericVisitor.h8
-rw-r--r--project2/iHaveParameters.cpp2
-rw-r--r--project2/regexCheck.cpp2
-rw-r--r--project2/rowView.cpp3
-rw-r--r--project2/sendmailTask.cpp8
-rw-r--r--project2/sessionSetTask.cpp2
-rw-r--r--project2/sqlMergeTask.cpp2
-rw-r--r--project2/sqlRows.cpp4
-rw-r--r--project2/tablepatch.cpp186
-rw-r--r--project2/variables.cpp209
-rw-r--r--project2/variables.h12
-rw-r--r--project2/xslRows.cpp24
15 files changed, 265 insertions, 232 deletions
diff --git a/project2/fileRows.cpp b/project2/fileRows.cpp
index 28de335..036cf4c 100644
--- a/project2/fileRows.cpp
+++ b/project2/fileRows.cpp
@@ -10,10 +10,11 @@ ElementLoaderImpl<FileRows> filerowsLoader("filerows");
FileRows::FileRows(const xmlpp::Element * p) :
SourceObject(p),
RowSet(p),
- path(p->get_attribute_value("path")),
+ path(p, "path"),
fieldSep(p->get_attribute_value("fieldSep")[0]),
quoteChar(p->get_attribute_value("quoteChar")[0]),
keepBlankRows(p->get_attribute_value("keepBlankRows") == "true"),
+ countBlankRows(p->get_attribute_value("keepBlankRows") == "count"),
newline(p->get_attribute_value("newline")),
encoding(p->get_attribute_value("encoding"))
{
@@ -106,13 +107,18 @@ FileRows::execute(const RowProcessor * rp) const
curCol++;
}
}
- if (!mkCols && (keepBlankRows || !values.empty())) {
- while (values.size() < columns.size()) {
- values.push_back(ValPtr(new Glib::ustring()));
- curCol++;
+ if (!mkCols) {
+ if (keepBlankRows || !values.empty()) {
+ while (values.size() < columns.size()) {
+ values.push_back(ValPtr(new Glib::ustring()));
+ curCol++;
+ }
+ rp->rowReady();
+ rowNum += 1;
+ }
+ else if (countBlankRows) {
+ rowNum +=1;
}
- rp->rowReady();
- rowNum += 1;
}
values.clear();
}
@@ -166,7 +172,7 @@ FileRows::addColumn(const Glib::ustring & rawtok) const
FileStarChannel
FileRows::doOpen() const
{
- FILE * f = LexicalCall<const char *, FILE *>(boost::bind(&popen, _1, "r"), path());
+ FILE * f = LexicalCall<const char *, FILE *>(boost::bind(&fopen, _1, "r"), path());
if (!f) {
throw FileNotReadable();
}
diff --git a/project2/fileRows.h b/project2/fileRows.h
index 0c5e3ce..1edff0b 100644
--- a/project2/fileRows.h
+++ b/project2/fileRows.h
@@ -40,6 +40,7 @@ class FileRows : public RowSet {
gunichar fieldSep;
gunichar quoteChar;
bool keepBlankRows;
+ bool countBlankRows;
std::string newline;
std::string encoding;
typedef std::vector<Glib::ustring> Columns;
diff --git a/project2/fsRows.cpp b/project2/fsRows.cpp
index 49bb57c..486dc90 100644
--- a/project2/fsRows.cpp
+++ b/project2/fsRows.cpp
@@ -135,14 +135,19 @@ FsRows::setFilter(const Glib::ustring &)
{
}
+FsRows::Path
+normalisePath(FsRows::Path & p)
+{
+ return (p / ".").remove_filename();
+}
+
void
FsRows::execute(const RowProcessor * rp) const
{
rowNum = 1;
depth = 0;
- fsRoot = boost::lexical_cast<boost::filesystem::path>(rp->getParameter("root"));
+ fsRoot = LexicalCall<Path, Path>(boost::bind(&normalisePath, _1), rp->getParameter("root"));
// Ensure there is a trailing /
- fsRoot = (fsRoot / ".").remove_filename();
specs.clear();
SpecSpec s;
typedef SpecSpec & (*splitter)(SpecSpec &, const Glib::ustring &, bool (*)(gunichar), boost::algorithm::token_compress_mode_type);
@@ -187,7 +192,8 @@ FsRows::execute(const Path & dir, const RowProcessor * rp) const
}
}
}
- catch (const boost::filesystem::basic_filesystem_error<Path> &) {
+ catch (const boost::filesystem::basic_filesystem_error<Path> & e) {
+ fprintf(stderr, "err %s\n", e.what());
}
depth -= 1;
}
diff --git a/project2/genericVisitor.h b/project2/genericVisitor.h
index 2e66e19..ce45f3f 100644
--- a/project2/genericVisitor.h
+++ b/project2/genericVisitor.h
@@ -71,6 +71,14 @@ namespace LexicalVisitorHelper {
return func(boost::posix_time::to_iso_extended_string(i));
}
};
+ template <typename T, typename S, typename R>
+ class lexical_run<T, boost::shared_ptr<const S>, R> {
+ public:
+ R operator()(const boost::function1<R, T> & func, const boost::shared_ptr<const S> & i) const
+ {
+ return func(boost::lexical_cast<T>(*i));
+ }
+ };
template <typename S, typename R>
class lexical_run<const char *, boost::shared_ptr<const S>, R> {
public:
diff --git a/project2/iHaveParameters.cpp b/project2/iHaveParameters.cpp
index 68d657a..84adee5 100644
--- a/project2/iHaveParameters.cpp
+++ b/project2/iHaveParameters.cpp
@@ -21,7 +21,7 @@ IHaveParameters::~IHaveParameters()
IHaveParameters::Parameter::Parameter(const xmlpp::Element * p) :
name(p->get_attribute_value("name")),
- value(p->get_attribute("value"))
+ value(p, "value")
{
}
diff --git a/project2/regexCheck.cpp b/project2/regexCheck.cpp
index edd2c38..5921a06 100644
--- a/project2/regexCheck.cpp
+++ b/project2/regexCheck.cpp
@@ -9,7 +9,7 @@ ElementLoaderImpl<RegexCheck> regexCheckLoader("regexcheck");
RegexCheck::RegexCheck(const xmlpp::Element * p) :
SourceObject(p),
ParamChecker(p),
- applyTo(p->get_attribute("apply-to")),
+ applyTo(p, "apply-to"),
regex(xmlChildText(p, "regex").raw())
{
}
diff --git a/project2/rowView.cpp b/project2/rowView.cpp
index 10fece5..2306474 100644
--- a/project2/rowView.cpp
+++ b/project2/rowView.cpp
@@ -14,7 +14,8 @@ RowView::RowView(const xmlpp::Element * p) :
BOOST_FOREACH(xmlpp::Node * node, p->find("columns/column")) {
const xmlpp::Element * elem = dynamic_cast<const xmlpp::Element *>(node);
if (elem) {
- viewColumns.insert(Columns::value_type(elem->get_attribute_value("name"), Variable::makeParent(elem->get_child_text()->get_content(), 0)));
+ viewColumns.insert(Columns::value_type(elem->get_attribute_value("name"),
+ Variable::makeParent(elem->get_child_text()->get_content(), elem->get_attribute_value("source") == "attribute", 0)));
}
}
LoaderBase loader("http://project2.randomdan.homeip.net", true);
diff --git a/project2/sendmailTask.cpp b/project2/sendmailTask.cpp
index 60de51c..7987d72 100644
--- a/project2/sendmailTask.cpp
+++ b/project2/sendmailTask.cpp
@@ -23,10 +23,10 @@ typedef boost::shared_ptr<xmlDoc> XmlDocumentPtr;
SendMailTask::SendMailTask(const xmlpp::Element * p) :
SourceObject(p),
Task(p),
- to(p->get_attribute("to")),
- subject(p->get_attribute("subject")),
- from(p->get_attribute("from")),
- server(p->get_attribute("server")),
+ to(p, "to"),
+ subject(p, "subject"),
+ from(p, "from"),
+ server(p, "server"),
present(p->get_attribute_value("present").raw())
{
}
diff --git a/project2/sessionSetTask.cpp b/project2/sessionSetTask.cpp
index df96c66..a4b0e44 100644
--- a/project2/sessionSetTask.cpp
+++ b/project2/sessionSetTask.cpp
@@ -11,7 +11,7 @@ SessionSetTask::SessionSetTask(const xmlpp::Element * p) :
SourceObject(p),
Task(p),
key(p->get_attribute_value("key")),
- value(p->get_attribute("value"))
+ value(p, "value")
{
}
diff --git a/project2/sqlMergeTask.cpp b/project2/sqlMergeTask.cpp
index b982473..2436f1f 100644
--- a/project2/sqlMergeTask.cpp
+++ b/project2/sqlMergeTask.cpp
@@ -42,7 +42,7 @@ ElementLoaderImpl<SqlMergeInsert> sqlmergeinsertLoader("sqlmergeinsert");
SqlMergeTask::SqlMergeTask(const xmlpp::Element * p) :
SourceObject(p),
Task(p),
- updateWhere(p->get_attribute_value("updatewhere")),
+ updateWhere(p, "updatewhere", false),
patchOrder(p->get_attribute_value("patchorder")),
earlyKeys(p->get_attribute_value("earlykeys") == "yes"),
useView(p->get_attribute_value("useview") == "yes"),
diff --git a/project2/sqlRows.cpp b/project2/sqlRows.cpp
index d4c6cd8..31948df 100644
--- a/project2/sqlRows.cpp
+++ b/project2/sqlRows.cpp
@@ -45,8 +45,8 @@ SqlRows::setFilter(const Glib::ustring & name)
class HandleAsVariableType : public ODBC::HandleField {
public:
void null() { }
- void string(const std::vector<char> & c) {
- variable = boost::shared_ptr<Glib::ustring>(new Glib::ustring(&c[0], &c[c.size()]));
+ void string(const std::vector<char> & c, size_t l) {
+ variable = boost::shared_ptr<Glib::ustring>(new Glib::ustring(&c[0], &c[l]));
}
void integer(SQLINTEGER i) {
variable = i;
diff --git a/project2/tablepatch.cpp b/project2/tablepatch.cpp
index 6f9c62f..ddf7e03 100644
--- a/project2/tablepatch.cpp
+++ b/project2/tablepatch.cpp
@@ -37,8 +37,8 @@ TablePatch::patch(const char * where, const char * order)
if (pk.size() == 0) {
throw PatchCheckFailure();
}
- doDeletes((where && *where) ? where : NULL, order);
- doUpdates((where && *where) ? where : NULL, order);
+ doDeletes(where, order);
+ doUpdates(where, order);
doInserts(order);
}
@@ -91,7 +91,7 @@ TablePatch::doDeletes(const char * where, const char * order)
if (where && *where) {
toDelSql.appendf(" AND %s", where);
}
- if (order) {
+ if (order && *order) {
toDelSql.appendf(" ORDER BY %s", order);
}
toDelSql.append(")");
@@ -102,100 +102,100 @@ TablePatch::doDeletes(const char * where, const char * order)
void
TablePatch::doUpdates(const char * where, const char * order)
{
- if (cols.size() == pk.size()) {
- // Can't "change" anything... it's all part of the key
- return;
- }
- // -----------------------------------------------------------------
- // Build SQL for list of updates to perform ------------------------
- // -----------------------------------------------------------------
- Buffer toUpdSel;
- toUpdSel.append("SELECT ");
- foreach (Columns::const_iterator, cols, col) {
- if (pk.find(*col) == pk.end()) {
- toUpdSel.appendf("b.%s, ",
- col->c_str());
- }
+ if (cols.size() == pk.size()) {
+ // Can't "change" anything... it's all part of the key
+ return;
}
- foreach (Columns::const_iterator, cols, col) {
- if (pk.find(*col) != pk.end()) {
- toUpdSel.appendf("b.%s, ",
- col->c_str());
- }
- }
- toUpdSel.appendf("0 FROM %s a, %s b",
- dest.c_str(), src.c_str());
- foreach (PKI, pk, pki) {
- if (pki == pk.begin()) {
- toUpdSel.append(" WHERE ");
- }
- else {
- toUpdSel.append(" AND ");
- }
- toUpdSel.appendf(" a.%s = b.%s",
- pki->c_str(), pki->c_str());
- }
- if (where && *where) {
- toUpdSel.appendf(" AND %s", where);
- }
- toUpdSel.append(" AND (");
- bool first = true;
- foreach (Columns::const_iterator, cols, col) {
- if (pk.find(*col) == pk.end()) {
- if (!first) {
- toUpdSel.append(" OR ");
- }
- first = false;
- toUpdSel.appendf(
- " (((CASE WHEN (a.%s IS NULL AND b.%s IS NULL) THEN 1 ELSE 0 END) \
- + (CASE WHEN(a.%s = b.%s) THEN 1 ELSE 0 END)) = 0)",
- col->c_str(), col->c_str(), col->c_str(), col->c_str());
- }
- }
- toUpdSel.append(")");
- if (order) {
- toUpdSel.appendf(" ORDER BY %s", order);
- }
- // -----------------------------------------------------------------
- // Build SQL to perform updates ------------------------------------
- // -----------------------------------------------------------------
- Buffer updSql;
- updSql.appendf("UPDATE %s SET ",
- dest.c_str());
- first = true;
- foreach (Columns::const_iterator, cols, col) {
- if (pk.find(*col) == pk.end()) {
- if (!first) {
- updSql.append(", ");
- }
- first = false;
- updSql.appendf(" %s = ?",
- col->c_str());
- }
- }
- foreach (PKI, pk, pki) {
- if (pki == pk.begin()) {
- updSql.append(" WHERE ");
- }
- else {
- updSql.append(" AND ");
- }
- updSql.appendf(" %s = ?",
- pki->c_str());
- }
- // -----------------------------------------------------------------
- // Iterator over update list make changes --------------------------
- // -----------------------------------------------------------------
- SelectCommand toUpd(db, toUpdSel);
- ModifyCommand upd(db, updSql);
- int cs = cols.size();
+ // -----------------------------------------------------------------
+ // Build SQL for list of updates to perform ------------------------
+ // -----------------------------------------------------------------
+ Buffer toUpdSel;
+ toUpdSel.append("SELECT ");
+ foreach (Columns::const_iterator, cols, col) {
+ if (pk.find(*col) == pk.end()) {
+ toUpdSel.appendf("b.%s, ",
+ col->c_str());
+ }
+ }
+ foreach (Columns::const_iterator, cols, col) {
+ if (pk.find(*col) != pk.end()) {
+ toUpdSel.appendf("b.%s, ",
+ col->c_str());
+ }
+ }
+ toUpdSel.appendf("0 FROM %s a, %s b",
+ dest.c_str(), src.c_str());
+ foreach (PKI, pk, pki) {
+ if (pki == pk.begin()) {
+ toUpdSel.append(" WHERE ");
+ }
+ else {
+ toUpdSel.append(" AND ");
+ }
+ toUpdSel.appendf(" a.%s = b.%s",
+ pki->c_str(), pki->c_str());
+ }
+ if (where && *where) {
+ toUpdSel.appendf(" AND %s", where);
+ }
+ toUpdSel.append(" AND (");
+ bool first = true;
+ foreach (Columns::const_iterator, cols, col) {
+ if (pk.find(*col) == pk.end()) {
+ if (!first) {
+ toUpdSel.append(" OR ");
+ }
+ first = false;
+ toUpdSel.appendf(
+ " (((CASE WHEN (a.%s IS NULL AND b.%s IS NULL) THEN 1 ELSE 0 END) \
+ + (CASE WHEN(a.%s = b.%s) THEN 1 ELSE 0 END)) = 0)",
+ col->c_str(), col->c_str(), col->c_str(), col->c_str());
+ }
+ }
+ toUpdSel.append(")");
+ if (order && *order) {
+ toUpdSel.appendf(" ORDER BY %s", order);
+ }
+ // -----------------------------------------------------------------
+ // Build SQL to perform updates ------------------------------------
+ // -----------------------------------------------------------------
+ Buffer updSql;
+ updSql.appendf("UPDATE %s SET ",
+ dest.c_str());
+ first = true;
+ foreach (Columns::const_iterator, cols, col) {
+ if (pk.find(*col) == pk.end()) {
+ if (!first) {
+ updSql.append(", ");
+ }
+ first = false;
+ updSql.appendf(" %s = ?",
+ col->c_str());
+ }
+ }
+ foreach (PKI, pk, pki) {
+ if (pki == pk.begin()) {
+ updSql.append(" WHERE ");
+ }
+ else {
+ updSql.append(" AND ");
+ }
+ updSql.appendf(" %s = ?",
+ pki->c_str());
+ }
+ // -----------------------------------------------------------------
+ // Iterator over update list make changes --------------------------
+ // -----------------------------------------------------------------
+ SelectCommand toUpd(db, toUpdSel);
+ ModifyCommand upd(db, updSql);
+ int cs = cols.size();
toUpd.execute();
for (int c = 0; c < cs; c += 1) {
toUpd[c].rebind(&upd, c);
}
- while (toUpd.fetch()) {
- upd.execute(false);
- }
+ while (toUpd.fetch()) {
+ upd.execute(false);
+ }
}
void
@@ -247,7 +247,7 @@ TablePatch::doInserts(const char * order)
toInsSql.appendf(" a.%s IS NULL",
pki->c_str());
}
- if (order) {
+ if (order && *order) {
toInsSql.appendf(" ORDER BY %s", order);
}
ModifyCommand(db, toInsSql).execute();
diff --git a/project2/variables.cpp b/project2/variables.cpp
index c8b2571..130d210 100644
--- a/project2/variables.cpp
+++ b/project2/variables.cpp
@@ -13,9 +13,35 @@
#include <boost/function.hpp>
#include <boost/bind.hpp>
+class UnknownVariableType : public std::exception { };
+class UnknownVariableSource : public std::exception { };
+class NoVariableDefinition : public std::exception { };
+
+static
+VariableType
+makeVariableType(const Glib::ustring & src, const std::string & type, const std::string & format = std::string())
+{
+ if (type == "stringptr" || type.empty()) return boost::shared_ptr<Glib::ustring>(new Glib::ustring(src));
+ if (type == "string") return src;
+ if (type == "int") return boost::lexical_cast<int>(src);
+ if (type == "uint") return boost::lexical_cast<unsigned int>(src);
+ if (type == "lint") return boost::lexical_cast<long int>(src);
+ if (type == "luint") return boost::lexical_cast<long unsigned int>(src);
+ if (type == "llint") return boost::lexical_cast<long long int>(src);
+ if (type == "lluint") return boost::lexical_cast<long long unsigned int>(src);
+ if (type == "float") return boost::lexical_cast<float>(src);
+ if (type == "double") return boost::lexical_cast<double>(src);
+ if (type == "datetime") return boost::posix_time::time_from_string(src);
+ if (type == "datetimeptr") return boost::shared_ptr<boost::posix_time::ptime>(new boost::posix_time::ptime(boost::posix_time::time_from_string(src)));
+ throw UnknownVariableType();
+}
+
class VariableLiteral : public VariableImpl {
public:
- VariableLiteral(const Glib::ustring & src) : VariableImpl(src), val(src) { }
+ VariableLiteral(const Glib::ustring & src, const std::string & type = std::string()) :
+ val(makeVariableType(src, type))
+ {
+ }
virtual const VariableType & value() const { return val; }
private:
@@ -24,17 +50,31 @@ class VariableLiteral : public VariableImpl {
class VariableImplDyn : public VariableImpl {
public:
- VariableImplDyn(const Glib::ustring & src) : VariableImpl(src), cacheValid(false) { }
+ VariableImplDyn(const xmlpp::Element * e) :
+ cacheValid(false)
+ {
+ try {
+ defaultValue = Variable(e, "default");
+ }
+ catch (NoVariableDefinition) {
+ // That's cool... no default
+ }
+ }
virtual const VariableType & value() const = 0;
protected:
mutable VariableType cache;
mutable bool cacheValid;
+ boost::optional<Variable> defaultValue;
};
class VariableSession : public VariableImplDyn {
public:
- VariableSession(const Glib::ustring & src) : VariableImplDyn(src) { }
+ VariableSession(const xmlpp::Element * e) :
+ VariableImplDyn(e),
+ name(e->get_attribute_value("name"))
+ {
+ }
const VariableType & value() const
{
try {
@@ -44,15 +84,21 @@ class VariableSession : public VariableImplDyn {
if (!defaultValue) {
throw;
}
- cache = *defaultValue;
+ cache = (*defaultValue)();
}
return cache;
}
+ private:
+ const Glib::ustring name;
};
class VariableParam : public VariableImplDyn {
public:
- VariableParam(const Glib::ustring & src) : VariableImplDyn(src) { }
+ VariableParam(const xmlpp::Element * e) :
+ VariableImplDyn(e),
+ name(e->get_attribute_value("name"))
+ {
+ }
const VariableType & value() const
{
if (!cacheValid) {
@@ -63,33 +109,41 @@ class VariableParam : public VariableImplDyn {
if (!defaultValue) {
throw;
}
- cache = *defaultValue;
+ cache = (*defaultValue)();
}
cacheValid = true;
}
return cache;
}
+ private:
+ const Glib::ustring name;
};
class VariableUri : public VariableImplDyn {
public:
- VariableUri(const Glib::ustring & src) : VariableImplDyn(src) { }
+ VariableUri(const xmlpp::Element * e) :
+ VariableImplDyn(e),
+ index(atoi(e->get_attribute_value("index").c_str()))
+ {
+ }
const VariableType & value() const
{
if (!cacheValid) {
try {
- cache = ApplicationEngine::getCurrent()->env()->getParamUri(atoi(name.c_str()));
+ cache = ApplicationEngine::getCurrent()->env()->getParamUri(index);
}
catch (UriElementOutOfRange) {
if (!defaultValue) {
throw;
}
- cache = *defaultValue;
+ cache = (*defaultValue)();
}
cacheValid = true;
}
return cache;
}
+ private:
+ unsigned int index;
};
static void assignHelper(VariableType & dest, const VariableType & src) {
@@ -98,19 +152,21 @@ static void assignHelper(VariableType & dest, const VariableType & src) {
class VariableParent : public VariableImplDyn, public RowUser {
public:
- VariableParent(const Glib::ustring & src, const RowUser * d) :
- VariableImplDyn(src),
+ VariableParent(const xmlpp::Element * e, const RowUser * d) :
+ VariableImplDyn(e),
row(NULL),
- depth(src.find_first_not_of('^')),
- attr(src[depth] == '!'),
+ depth(atoi(e->get_attribute_value("depth").c_str())),
+ attr(e->get_attribute("attribute")),
+ name(attr ? e->get_attribute_value("attribute") : e->get_attribute_value("name")),
dep(d)
{
}
- VariableParent(const Glib::ustring & name, unsigned int d) :
- VariableImplDyn(name),
+ VariableParent(const Glib::ustring & n, bool a, unsigned int d) :
+ VariableImplDyn(NULL),
row(NULL),
depth(d),
- attr(name[0] == '!'),
+ attr(a),
+ name(n),
dep(NULL)
{
}
@@ -146,13 +202,13 @@ class VariableParent : public VariableImplDyn, public RowUser {
if (!defaultValue) {
throw;
}
- cache = *defaultValue;
+ cache = (*defaultValue)();
}
catch (RowSet::FieldDoesNotExist) {
if (!defaultValue) {
throw;
}
- cache = *defaultValue;
+ cache = (*defaultValue)();
}
cacheValid = true;
}
@@ -177,57 +233,57 @@ class VariableParent : public VariableImplDyn, public RowUser {
mutable ConstRowSetPtr row;
const size_t depth;
const bool attr;
+ const Glib::ustring name;
const RowUser * dep;
mutable boost::function2<void, VariableType &, ConstRowSetPtr> getValue;
};
-class VariableParse : public VariableImplDyn, public RowUser {
+class VariableFixed : public VariableImpl {
public:
- VariableParse(const Glib::ustring & src) :
- VariableImplDyn(src)
+ VariableFixed(VariableType v) :
+ var(v)
{
- boost::tokenizer<boost::char_separator<char> > tokens(source.raw(), boost::char_separator<char>(" "));
- BOOST_FOREACH(std::string t, tokens) {
- vars.push_back(Variable::create(t, this));
- }
}
const VariableType & value() const
{
- if (!cacheValid) {
- Glib::ustring newCache;
- BOOST_FOREACH(Variable::VariableImplPtr v, vars) {
- if (newCache.length()) {
- newCache.append(" ");
- }
- typedef Glib::ustring & (Glib::ustring::*appender)(const Glib::ustring &);
- LexicalCall<Glib::ustring, Glib::ustring &>(boost::bind((appender)&Glib::ustring::append, newCache, _1), v->value());
- }
- cache = newCache;
- cacheValid = true;
- }
- return cache;
- }
- void rowChanged() const
- {
- cacheValid = false;
+ return var;
}
private:
- std::list<Variable::VariableImplPtr> vars;
+ VariableType var;
};
-Variable::Variable(const Glib::ustring & s) :
- var(create(s))
-{
-}
-
-Variable::Variable(const xmlpp::Attribute * a) :
- var(create(a->get_value()))
-{
-}
-
-Variable::Variable(const xmlpp::Element * e) :
- var(create(e->get_child_text()->get_content()))
+Variable::Variable(const xmlpp::Element * e, const Glib::ustring & n, bool required, VariableType def)
{
+ xmlpp::Attribute * a = e->get_attribute(n);
+ if (a) {
+ var = new VariableLiteral(a->get_value());
+ return;
+ }
+ xmlpp::Element::NodeList cs = e->get_children(n);
+ if (cs.size() == 1) {
+ const xmlpp::Element * c = dynamic_cast<const xmlpp::Element *>(cs.front());
+ if (c) {
+ Glib::ustring source = c->get_attribute_value("source");
+ if (source == "session")
+ var = new VariableSession(c);
+ else if (source == "parent")
+ var = new VariableParent(c, NULL);
+ else if (source == "uri")
+ var = new VariableUri(c);
+ else if (source == "param")
+ var = new VariableParam(c);
+ else if (source == "literal" || source.empty())
+ var = new VariableLiteral(c->get_attribute_value("value"), c->get_attribute_value("type"));
+ else
+ throw UnknownVariableSource();
+ return;
+ }
+ }
+ if (!required) {
+ var = new VariableFixed(def);
+ return;
+ }
+ throw NoVariableDefinition();
}
Variable::Variable(VariableImpl * v) :
@@ -235,50 +291,13 @@ Variable::Variable(VariableImpl * v) :
{
}
-Variable::VariableImplPtr
-Variable::create(const Glib::ustring & s, RowUser * dep)
+VariableImpl::~VariableImpl()
{
- if (s.empty()) {
- return VariableImplPtr(new VariableLiteral(s));
- }
- switch (s[0]) {
- case '$': // param
- return VariableImplPtr(new VariableParam(s));
- case '%': // session
- return VariableImplPtr(new VariableSession(s));
- case '^': // parent
- return VariableImplPtr(new VariableParent(s, dep));
- case '/': // uri
- return VariableImplPtr(new VariableUri(s));
- case '*': // parser
- return VariableImplPtr(new VariableParse(s.substr(1)));
- case '=': // literal (explicit)
- return VariableImplPtr(new VariableLiteral(s.substr(1)));
- default:
- return VariableImplPtr(new VariableLiteral(s));
- }
}
Variable
-Variable::makeParent(const Glib::ustring & n, unsigned int d)
-{
- return Variable(new VariableParent(n, d));
-}
-
-VariableImpl::VariableImpl(const Glib::ustring & src) :
- source(src)
-{
- Glib::ustring::const_iterator nameStart = std::find_if(source.begin(), source.end(), Glib::Unicode::isalnum);
- Glib::ustring::const_iterator nameEnd = std::find(nameStart, source.end(), '|');
- name = Glib::ustring(nameStart, nameEnd);
- Glib::ustring::const_iterator defaultStart = nameEnd;
- if (defaultStart != source.end()) {
- defaultStart++;
- defaultValue = Glib::ustring(defaultStart, source.end());
- }
-}
-
-VariableImpl::~VariableImpl()
+Variable::makeParent(const Glib::ustring & name, bool attr, unsigned int dep)
{
+ return Variable(new VariableParent(name, attr, dep));
}
diff --git a/project2/variables.h b/project2/variables.h
index 0b27419..2cccd5e 100644
--- a/project2/variables.h
+++ b/project2/variables.h
@@ -38,23 +38,17 @@ class VariableImpl : public virtual IntrusivePtrBase {
virtual const VariableType & value() const = 0;
protected:
- VariableImpl(const Glib::ustring & src);
virtual ~VariableImpl() = 0;
-
- const Glib::ustring source;
- Glib::ustring name;
- boost::optional<VariableType> defaultValue;
};
class Variable {
public:
typedef boost::intrusive_ptr<VariableImpl> VariableImplPtr;
- Variable(const xmlpp::Attribute *);
- Variable(const xmlpp::Element *);
- Variable(const Glib::ustring & s);
+ Variable(const xmlpp::Element *, const Glib::ustring & n, bool required = true, VariableType def = VariableType());
- static Variable makeParent(const Glib::ustring & name, unsigned int depth);
+ static Variable makeFromCode(const Glib::ustring & s);
+ static Variable makeParent(const Glib::ustring & name, bool attr, unsigned int depth);
operator const VariableType & () const { return var->value(); }
const VariableType & operator()() const { return var->value(); }
diff --git a/project2/xslRows.cpp b/project2/xslRows.cpp
index aa53540..0b981aa 100644
--- a/project2/xslRows.cpp
+++ b/project2/xslRows.cpp
@@ -20,7 +20,7 @@ class ResourceDownloadError : public std::exception { };
XslRows::XslRows(const xmlpp::Element * p) :
SourceObject(p),
RowSet(p),
- url(p->get_attribute_value("url")),
+ url(p, "url"),
html(p->get_attribute_value("html") == "true"),
warnings(p->get_attribute_value("warnings") != "false")
{
@@ -102,17 +102,19 @@ XslRows::getDocument(const Glib::ustring & url) const
void
XslRows::execute(const RowProcessor * rp) const
{
+ typedef boost::shared_ptr<xmlXPathObject> xmlXPathObjectSPtr;
+ typedef boost::shared_ptr<xmlXPathContext> xmlXPathContextSPtr;
xmlDocPtr doc = LexicalCall<Glib::ustring, xmlDocPtr>(boost::bind(&XslRows::getDocument, this, _1), url());
- xmlXPathContextPtr xpathCtx = xmlXPathNewContext(doc);
+ xmlXPathContextSPtr xpathCtx = xmlXPathContextSPtr(xmlXPathNewContext(doc), xmlXPathFreeContext);
if (!xpathCtx) {
throw XpathInitError();
}
BOOST_FOREACH(const Namespaces::value_type & ns, namespaces) {
- xmlXPathRegisterNs(xpathCtx, BAD_CAST ns.first.c_str(), BAD_CAST ns.second.c_str());
+ xmlXPathRegisterNs(xpathCtx.get(), BAD_CAST ns.first.c_str(), BAD_CAST ns.second.c_str());
}
- xmlXPathObjectPtr xpathObj = LexicalCall<const xmlChar *, xmlXPathObjectPtr>(boost::bind(&xmlXPathEvalExpression, _1, xpathCtx), fv->root());
+ xmlXPathObjectSPtr xpathObj = xmlXPathObjectSPtr(
+ LexicalCall<const xmlChar *, xmlXPathObjectPtr>(boost::bind(&xmlXPathEvalExpression, _1, xpathCtx.get()), fv->root()), xmlXPathFreeObject);
if (!xpathObj || !xpathObj->nodesetval) {
- xmlXPathFreeContext(xpathCtx);
throw XpathEvalError();
}
rowNum = 1;
@@ -121,10 +123,9 @@ XslRows::execute(const RowProcessor * rp) const
xpathCtx->node = rowRoot;
values.clear();
BOOST_FOREACH(const FilterView::XPaths::value_type & xp, fv->xpaths) {
- xmlXPathObjectPtr xpathObjI = LexicalCall<const xmlChar *, xmlXPathObjectPtr>(boost::bind(&xmlXPathEvalExpression, _1, xpathCtx), xp.second());
+ xmlXPathObjectSPtr xpathObjI = xmlXPathObjectSPtr(LexicalCall<const xmlChar *, xmlXPathObjectPtr>(
+ boost::bind(&xmlXPathEvalExpression, _1, xpathCtx.get()), xp.second()), xmlXPathFreeObject);
if (!xpathObjI) {
- xmlXPathFreeObject(xpathObj);
- xmlXPathFreeContext(xpathCtx);
throw XpathEvalError();
}
if (xpathObjI->floatval) {
@@ -139,23 +140,20 @@ XslRows::execute(const RowProcessor * rp) const
values[xp.first] = boost::shared_ptr<const Glib::ustring>(new Glib::ustring((const char *)val));
}
}
- xmlXPathFreeObject(xpathObjI);
}
rp->rowReady();
rowNum += 1;
}
- xmlXPathFreeObject(xpathObj);
- xmlXPathFreeContext(xpathCtx);
}
XslRows::FilterView::FilterView(const xmlpp::Element * p) :
name(p->get_attribute_value("name")),
- root(p->get_attribute_value("root"))
+ root(p, "root")
{
BOOST_FOREACH(const xmlpp::Node * node, p->find("field")) {
const xmlpp::Element * elem = dynamic_cast<const xmlpp::Element *>(node);
if (elem) {
- xpaths.insert(XPaths::value_type(elem->get_attribute_value("name"), elem->get_attribute_value("xpath")));
+ xpaths.insert(XPaths::value_type(elem->get_attribute_value("name"), Variable(elem, "xpath")));
}
}
}