diff options
39 files changed, 586 insertions, 702 deletions
diff --git a/project2/Jamfile.jam b/project2/Jamfile.jam index 5eb1c27..80befb9 100644 --- a/project2/Jamfile.jam +++ b/project2/Jamfile.jam @@ -58,7 +58,7 @@ lib p2common :  	iterate.cpp paramChecker.cpp presenter.cpp rawView.cpp logger.cpp if.cpp xmlScriptParser.cpp viewHost.cpp  	sourceObject.cpp task.cpp variables.cpp variableConvert.cpp view.cpp xmlObjectLoader.cpp exceptions.cpp  	sessionClearTask.cpp session.cpp sessionSetTask.cpp commonObjects.cpp xmlPresenter.cpp taskHost.cpp checkHost.cpp -	rowView.cpp rowSet.cpp rowProcessor.cpp config.cpp fileStrmVarWriter.cpp noOutputExecute.cpp +	rowView.cpp rowSet.cpp rowProcessor.cpp config.cpp fileStrmVarWriter.cpp noOutputExecute.cpp columns.cpp scopeObject.cpp  	transform.cpp transformHtml.cpp transformText.cpp definedColumns.cpp structExceptHandling.cpp validDateCheck.cpp  	variables-modconfig.cpp  	variables-modlookup.cpp diff --git a/project2/columns.cpp b/project2/columns.cpp new file mode 100644 index 0000000..a2511f6 --- /dev/null +++ b/project2/columns.cpp @@ -0,0 +1,23 @@ +#include "columns.h" +#include <libxml++/nodes/textnode.h> + +Column::Column(unsigned int i, const xmlpp::Element * p) : +	idx(i), +	name(p->get_attribute("name") ? p->get_attribute_value("name") : p->get_child_text()->get_content()), +	defValue(p, "default", false) +{ +} + +Column::Column(unsigned int i, const Glib::ustring & n, const Variable & v) : +	idx(i), +	name(n), +	defValue(v) +{ +} + +Column * +Column::make(unsigned int idx, const xmlpp::Element * p) +{ +	return new Column(idx, p); +} + diff --git a/project2/columns.h b/project2/columns.h new file mode 100644 index 0000000..8b9b9b3 --- /dev/null +++ b/project2/columns.h @@ -0,0 +1,33 @@ +#ifndef COLUMNS_H +#define COLUMNS_H + +#include <libxml++/nodes/element.h> +#include "variables.h" +#include <boost/multi_index_container.hpp> +#include <boost/multi_index/member.hpp> +#include <boost/multi_index/ordered_index.hpp> + +class Column : public IntrusivePtrBase { +	public: +		Column(unsigned int idx, const xmlpp::Element * p); +		Column(unsigned int i, const Glib::ustring & n, const Variable & v = Variable(Null())); + +		static Column * make(unsigned int idx, const xmlpp::Element * p); + +		const unsigned int idx; +		const Glib::ustring name; +		const Variable defValue; +}; + +struct byColIdx {}; +struct byColName {}; +typedef boost::multi_index::multi_index_container<boost::intrusive_ptr<Column>, +				boost::multi_index::indexed_by< +				boost::multi_index::ordered_unique< +				boost::multi_index::tag<byColName>, BOOST_MULTI_INDEX_MEMBER(Column, const Glib::ustring, name)>, +				boost::multi_index::ordered_unique< +				boost::multi_index::tag<byColIdx>,  BOOST_MULTI_INDEX_MEMBER(Column, const unsigned int, idx)> +				> > Columns; + +#endif + diff --git a/project2/console/consoleAppEngine.h b/project2/console/consoleAppEngine.h index 3d54a18..5e0a403 100644 --- a/project2/console/consoleAppEngine.h +++ b/project2/console/consoleAppEngine.h @@ -1,5 +1,5 @@ -#ifndef CGIAPPENGINE_H -#define CGIAPPENGINE_H +#ifndef CONSOLEAPPENGINE_H +#define CONSOLEAPPENGINE_H  #include "../appEngine.h"  #include "../task.h" diff --git a/project2/definedColumns.cpp b/project2/definedColumns.cpp index 1361453..5260e51 100644 --- a/project2/definedColumns.cpp +++ b/project2/definedColumns.cpp @@ -1,84 +1,31 @@  #include "definedColumns.h" -#include <boost/foreach.hpp> +#include <boost/function.hpp>  #include <libxml++/nodes/textnode.h> -DefinedColumns::DefinedColumns(const xmlpp::Element * p) : -	RowSet(p) +DefinedColumns::DefinedColumns(const xmlpp::Element * p, const Glib::ustring & colPath, const ColCreator & func)  {  	unsigned int colNo = 0; -	BOOST_FOREACH(const xmlpp::Node * node, p->find("columns/column")) { +	BOOST_FOREACH(const xmlpp::Node * node, p->find(colPath)) {  		const xmlpp::Element * elem = dynamic_cast<const xmlpp::Element *>(node);  		if (elem) { -			columns.insert(Column(colNo++, elem)); +			columns.insert(func(colNo++, elem));  		}  	}  } -DefinedColumns::Column::Column(unsigned int i, const Glib::ustring & c) : -	idx(i), -	col(c), -	defValue(VariableType()) +ColumnValues::ColumnValues(const DefinedColumns * rs) : +	rowSet(rs)  { +	fields.resize(rs->columns.size());  } -DefinedColumns::Column::Column(unsigned int i, const xmlpp::Element * p) : -	idx(i), -	col(p->get_child_text()->get_content()), -	defValue(p, "default", false) +ColumnValues::~ColumnValues()  {  } -void -DefinedColumns::Column::operator=(const VariableType & v) const +const Columns & +ColumnValues::getColumns() const  { -	value = v; -} - -const Glib::ustring & -DefinedColumns::getColumnName(unsigned int col) const -{ -	Columns::index<byColIdx>::type::iterator i = columns.get<byColIdx>().find(col); -	if (i != columns.get<byColIdx>().end()) { -		return i->col; -	} -	throw RowSet::FieldOutOfRange(col); -} - -unsigned int -DefinedColumns::columnCount() const -{ -	return columns.size(); -} - -VariableType -DefinedColumns::getCurrentValue(unsigned int col) const -{ -	Columns::index<byColIdx>::type::iterator i = columns.get<byColIdx>().find(col); -	if (i != columns.get<byColIdx>().end()) { -		return i->value; -	} -	throw RowSet::FieldOutOfRange(col); -} - -bool -DefinedColumns::isNull(unsigned int col) const -{ -	return (columns.get<byColIdx>().find(col) == columns.get<byColIdx>().end()); -} - -bool -DefinedColumns::isNull(const Glib::ustring & col) const -{ -	return (columns.get<byColName>().find(col) == columns.get<byColName>().end()); -} - -VariableType -DefinedColumns::getCurrentValue(const Glib::ustring & col) const -{ -	Columns::const_iterator i = columns.get<byColName>().find(col); -	if (i != columns.end()) { -		return i->value; -	} -	throw RowSet::FieldDoesNotExist(col); +	return rowSet->columns;  } diff --git a/project2/definedColumns.h b/project2/definedColumns.h index d6f2ba3..2fc6bbd 100644 --- a/project2/definedColumns.h +++ b/project2/definedColumns.h @@ -2,47 +2,26 @@  #define DEFINEDCOLUMNS_H  #include <libxml++/nodes/element.h> -#include <boost/multi_index_container.hpp> -#include <boost/multi_index/member.hpp> -#include <boost/multi_index/ordered_index.hpp> +#include <boost/foreach.hpp>  #include "variables.h"  #include "rowSet.h" +#include "columns.h" -class DefinedColumns : public RowSet { +class DefinedColumns {  	public: -		DefinedColumns(const xmlpp::Element *); - -		unsigned int columnCount() const; -		const Glib::ustring & getColumnName(unsigned int col) const; -		VariableType getCurrentValue(const Glib::ustring & id) const; -		VariableType getCurrentValue(unsigned int col) const; -		bool isNull(unsigned int col) const; -		bool isNull(const Glib::ustring & id) const; - -	protected: -		class Column { -			public: -				Column(unsigned int idx, const Glib::ustring &); -				Column(unsigned int idx, const xmlpp::Element * p); - -				void operator=(const VariableType &) const; - -				const unsigned int idx; -				const Glib::ustring col; -				mutable VariableType value; -				const Variable defValue; -		}; -		struct byColIdx {}; -		struct byColName {}; -		typedef boost::multi_index::multi_index_container< -			Column, -			boost::multi_index::indexed_by< -				boost::multi_index::ordered_unique< -				boost::multi_index::tag<byColName>, BOOST_MULTI_INDEX_MEMBER(Column, const Glib::ustring, col)>, -				boost::multi_index::ordered_unique< -				boost::multi_index::tag<byColIdx>,  BOOST_MULTI_INDEX_MEMBER(Column, const unsigned int, idx)> -				> > Columns; -		mutable Columns columns; +		typedef boost::function2<Column *, unsigned int, const xmlpp::Element *> ColCreator; +		DefinedColumns(const xmlpp::Element * p, const Glib::ustring & colPath, const ColCreator & func); +		Columns columns; +}; + +class ColumnValues : public RowState { +	public: +		ColumnValues(const DefinedColumns *); +		virtual ~ColumnValues(); + +		virtual const Columns & getColumns() const; + +		const DefinedColumns * const rowSet;  };  #endif diff --git a/project2/fileRows.cpp b/project2/fileRows.cpp index 58dde13..d7c8fca 100644 --- a/project2/fileRows.cpp +++ b/project2/fileRows.cpp @@ -29,17 +29,15 @@ FileRows::setFilter(const Glib::ustring &)  }  void -FileRows::execute(const RowProcessor * rp) const +FileRows::execute(const Glib::ustring &, const RowProcessor * rp) const  { -	rowNum = 1;  	FileStarChannel c(doOpen());  	c.set_encoding(encoding);  	gunichar ch; -	begin(); +	ParseState ps(this, rp);  	while (c.read(ch) == Glib::IO_STATUS_NORMAL) { -		this->pushChar(ch, rp); +		this->pushChar(ch, ps);  	} -	end(rp);  }  FileStarChannel diff --git a/project2/fileRows.h b/project2/fileRows.h index a4cc863..0cf3f1d 100644 --- a/project2/fileRows.h +++ b/project2/fileRows.h @@ -12,7 +12,7 @@ class FileRows : public StreamRows {  		FileRows(const xmlpp::Element * p);  		~FileRows(); -		void execute(const RowProcessor *) const; +		void execute(const Glib::ustring &, const RowProcessor *) const;  		virtual void loadComplete(const CommonObjects *);  		virtual void setFilter(const Glib::ustring &); diff --git a/project2/fileStrmVarWriter.cpp b/project2/fileStrmVarWriter.cpp index 1af99dc..51fb487 100644 --- a/project2/fileStrmVarWriter.cpp +++ b/project2/fileStrmVarWriter.cpp @@ -49,9 +49,11 @@ void FileStreamVariableWriter::operator()(const double & i) const {  	fprintf(out, "%g", i);  }  void FileStreamVariableWriter::operator()(const Glib::ustring & i) const { +	fputc('\'', out);  	if (fwrite(i.c_str(), i.bytes(), 1, out) < 1) {  		// Care much? None of the others check.  	} +	fputc('\'', out);  }  void FileStreamVariableWriter::operator()(const boost::posix_time::ptime & i) const {  	fprintf(out, "[%s]", boost::posix_time::to_iso_extended_string(i).c_str()); diff --git a/project2/fsRows.cpp b/project2/fsRows.cpp index 5ae8221..b308f38 100644 --- a/project2/fsRows.cpp +++ b/project2/fsRows.cpp @@ -28,17 +28,24 @@ const Glib::ustring field_group("owningGroup");  const Glib::ustring field_mode("mode");  const Glib::ustring field_perms("perms");  const Glib::ustring field_type("type"); +static +Columns defCols() { +	Columns rtn; +	rtn.insert(new Column(0, "absPath")); +	return rtn; +} +const Columns FsRows::SearchState::col(defCols()); -bool FsRows::SpecBase::recurse(const FsRows *) const { return true; } -bool FsRows::SpecBase::matches(const FsRows *) const { return true; } -const boost::filesystem::path & FsRows::SpecBase::curPath(const FsRows * fs) const { return fs->curPath; } -unsigned int FsRows::SpecBase::depth(const FsRows * fs) const { return fs->depth; } -struct stat & FsRows::SpecBase::curStat(const FsRows * fs) const { return fs->curStat; } +bool FsRows::SpecBase::recurse(const SearchState *) const { return true; } +bool FsRows::SpecBase::matches(const SearchState *) const { return true; } +const boost::filesystem::path & FsRows::SpecBase::curPath(const SearchState * fs) const { return fs->curPath; } +unsigned int FsRows::SpecBase::depth(const SearchState * fs) const { return fs->depth; } +const struct stat & FsRows::SpecBase::curStat(const SearchState * fs) const { return fs->curStat; }  class FsRowSpecName : public FsRows::SpecBase {  	public:  		FsRowSpecName(const Glib::ustring & v) : pattern(v) { } -		bool matches(const FsRows * fs) const { +		bool matches(const FsRows::SearchState * fs) const {  			// Based on code written by Jack Handy - jakkhandy@hotmail.com  			// from http://www.codeproject.com/KB/string/wildcmp.aspx  			Glib::ustring::const_iterator wild = pattern.begin(); @@ -85,7 +92,7 @@ class FsRowSpecName : public FsRows::SpecBase {  class FsRowSpecType : public FsRows::SpecBase {  	public:  		FsRowSpecType(const Glib::ustring & v) : types(v) { } -		bool matches(const FsRows * fs) const { +		bool matches(const FsRows::SearchState * fs) const {  			if (S_ISREG(curStat(fs).st_mode)) {  				return types.find('f') != Glib::ustring::npos;  			} @@ -114,7 +121,7 @@ class FsRowSpecType : public FsRows::SpecBase {  class FsRowSpecMaxDepth : public FsRows::SpecBase {  	public:  		FsRowSpecMaxDepth(const Glib::ustring & v) : maxDepth(boost::lexical_cast<unsigned int>(v)) { } -		bool recurse(const FsRows * fs) const { +		bool recurse(const FsRows::SearchState * fs) const {  			return (depth(fs) < maxDepth);  		}  		const unsigned int maxDepth; @@ -134,11 +141,6 @@ FsRows::loadComplete(const CommonObjects *)  {  } -void -FsRows::setFilter(const Glib::ustring &) -{ -} -  FsRows::Path  normalisePath(const std::string & p)  { @@ -150,12 +152,9 @@ normalisePath(const std::string & p)  }  void -FsRows::execute(const RowProcessor * rp) const +FsRows::execute(const Glib::ustring &, const RowProcessor * rp) const  { -	rowNum = 1; -	depth = 0; -	fsRoot = normalisePath(rp->getParameter("root")); -	specs.clear(); +	SearchState ss(normalisePath(rp->getParameter("root")));  	SpecSpec s;  	typedef SpecSpec & (*splitter)(SpecSpec &, const Glib::ustring &, bool (*)(gunichar), boost::algorithm::token_compress_mode_type);  	splitter split = &boost::algorithm::split; @@ -163,134 +162,108 @@ FsRows::execute(const RowProcessor * rp) const  	for (SpecSpec::const_iterator sf = s.begin(); sf != s.end(); ) {  		const Glib::ustring & name = (*sf++);  		if (name == "-name") { -			specs.insert(new FsRowSpecName(*sf++)); +			ss.specs.insert(new FsRowSpecName(*sf++));  		}  		else if (name == "-type") { -			specs.insert(new FsRowSpecType(*sf++)); +			ss.specs.insert(new FsRowSpecType(*sf++));  		}  		else if (name == "-maxdepth") { -			specs.insert(new FsRowSpecMaxDepth(*sf++)); +			ss.specs.insert(new FsRowSpecMaxDepth(*sf++));  		}  		else {  			throw NotSupported(name);  		}  	} -	execute(fsRoot, rp); +	execute(ss, ss.fsRoot, rp);  }  void -FsRows::execute(const Path & dir, const RowProcessor * rp) const +FsRows::execute(SearchState & ss, const Path & dir, const RowProcessor * rp) const  { -	depth += 1; +	ss.depth += 1;  	try {  		DirEnt end;  		for (DirEnt itr(dir); itr != end; ++itr) { -			curPathStr = itr->path().string(); -			curPath = itr->path(); -			stat(curPathStr.c_str(), &curStat); +			ss.curPathStr = itr->path().string(); +			ss.curPath = itr->path(); +			stat(ss.curPathStr.c_str(), &ss.curStat); -			if (boost::algorithm::all(specs, boost::bind(&SpecBase::matches, _1, this))) { -				rp->rowReady(); -				rowNum += 1; +			if (boost::algorithm::all(ss.specs, boost::bind(&SpecBase::matches, _1, &ss))) { +				ss.process(rp);  			} -			if (S_ISDIR(curStat.st_mode) && boost::algorithm::all(specs, boost::bind(&SpecBase::recurse, _1, this))) { -				execute(*itr, rp); +			if (S_ISDIR(ss.curStat.st_mode) && boost::algorithm::all(ss.specs, boost::bind(&SpecBase::recurse, _1, &ss))) { +				execute(ss, *itr, rp);  			}  		}  	}  	catch (const boost::filesystem::filesystem_error & e) {  		Logger()->messagef(LOG_WARNING, "%s when processing '%s'", e.what(), dir.string().c_str());  	} -	depth -= 1; +	ss.depth -= 1;  } -unsigned int -FsRows::columnCount() const -{ -	return 1; -} - -bool -FsRows::isNull(unsigned int) const -{ -	return false; -} - -bool -FsRows::isNull(const Glib::ustring &) const -{ -	return false; -} - -VariableType -FsRows::getCurrentValue(const Glib::ustring &) const -{ -	return curPathStr; -} - -VariableType -FsRows::getCurrentValue(unsigned int) const +FsRows::SearchState::SearchState(const Path & dir) : +	fsRoot(dir)  { -	return curPathStr;  } -const Glib::ustring & -FsRows::getColumnName(unsigned int) const +const Columns & +FsRows::SearchState::getColumns() const  { -	return field_absPath; +	return col;  } -RowSet::RowAttribute -FsRows::resolveAttr(const Glib::ustring & a) const +RowState::RowAttribute +FsRows::SearchState::resolveAttr(const Glib::ustring & a) const  {  	if (a == field_relPath) { -		return boost::bind(&FsRows::fileRelPath, this); +		return boost::bind(&FsRows::SearchState::fileRelPath, this);  	}  	if (a == field_size) { -		return boost::bind(&FsRows::fileSize, this); +		return boost::bind(&FsRows::SearchState::fileSize, this);  	}  	if (a == field_modDate) { -		return boost::bind(&FsRows::fileModDate, this); +		return boost::bind(&FsRows::SearchState::fileModDate, this);  	}  	if (a == field_user) { -		return boost::bind(&FsRows::fileUser, this); +		return boost::bind(&FsRows::SearchState::fileUser, this);  	}  	if (a == field_group) { -		return boost::bind(&FsRows::fileGroup, this); +		return boost::bind(&FsRows::SearchState::fileGroup, this);  	}  	if (a == field_mode) { -		return boost::bind(&FsRows::fileMode, this); +		return boost::bind(&FsRows::SearchState::fileMode, this);  	}  	if (a == field_perms) { -		return boost::bind(&FsRows::filePerms, this); +		return boost::bind(&FsRows::SearchState::filePerms, this);  	}  	if (a == field_type) { -		return boost::bind(&FsRows::fileType, this); +		return boost::bind(&FsRows::SearchState::fileType, this);  	} -	return RowSet::resolveAttr(a); +	return RowState::resolveAttr(a);  }  VariableType -FsRows::fileRelPath() const +FsRows::SearchState::fileRelPath() const  {  	return curPathStr.substr(fsRoot.string().length() - 1);  }  VariableType -FsRows::fileSize() const +FsRows::SearchState::fileSize() const  {  	return curStat.st_size;  }  VariableType -FsRows::fileModDate() const +FsRows::SearchState::fileModDate() const  {  	return boost::posix_time::from_time_t(curStat.st_mtime);  }  VariableType -FsRows::fileUser() const +FsRows::SearchState::fileUser() const  {  	struct passwd * p = getpwuid(curStat.st_uid);  	if (p) { @@ -302,7 +275,7 @@ FsRows::fileUser() const  }  VariableType -FsRows::fileGroup() const +FsRows::SearchState::fileGroup() const  {  	struct group * g = getgrgid(curStat.st_gid);  	if (g) { @@ -314,19 +287,19 @@ FsRows::fileGroup() const  }  VariableType -FsRows::fileMode() const +FsRows::SearchState::fileMode() const  {  	throw NotSupported(__PRETTY_FUNCTION__);  }  VariableType -FsRows::filePerms() const +FsRows::SearchState::filePerms() const  {  	throw NotSupported(__PRETTY_FUNCTION__);  }  VariableType -FsRows::fileType() const +FsRows::SearchState::fileType() const  {  	throw NotSupported(__PRETTY_FUNCTION__);  } diff --git a/project2/fsRows.h b/project2/fsRows.h index 4e559cd..8cd1a9f 100644 --- a/project2/fsRows.h +++ b/project2/fsRows.h @@ -13,14 +13,15 @@ class CommonObjects;  /// Project2 component to create a row set based on files and directories on the local filesystem  class FsRows : public RowSet {  	public: +		class SearchState;  		class SpecBase : public virtual IntrusivePtrBase {  			public: -				virtual bool recurse(const FsRows * fs) const; -				virtual bool matches(const FsRows * fs) const; +				virtual bool recurse(const SearchState * fs) const; +				virtual bool matches(const SearchState * fs) const;  			protected: -				const boost::filesystem::path & curPath(const FsRows * fs) const; -				unsigned int depth(const FsRows * fs) const; -				struct stat & curStat(const FsRows * fs) const; +				const boost::filesystem::path & curPath(const SearchState * fs) const; +				unsigned int depth(const SearchState * fs) const; +				const struct stat & curStat(const SearchState * fs) const;  		};  		typedef boost::intrusive_ptr<SpecBase> SpecBasePtr;  		typedef std::set<SpecBasePtr> SpecBases; @@ -30,35 +31,34 @@ class FsRows : public RowSet {  		FsRows(const xmlpp::Element * p);  		~FsRows(); -		void execute(const RowProcessor *) const; +		void execute(const Glib::ustring &, const RowProcessor *) const;  		virtual void loadComplete(const CommonObjects *); -		virtual void setFilter(const Glib::ustring &); -		unsigned int columnCount() const; -		const Glib::ustring & getColumnName(unsigned int col) const; -		VariableType getCurrentValue(const Glib::ustring & id) const; -		VariableType getCurrentValue(unsigned int col) const; -		bool isNull(unsigned int col) const; -		bool isNull(const Glib::ustring & id) const; -		virtual RowAttribute resolveAttr(const Glib::ustring & attrName) const; +		class SearchState : public RowState { +			public: +				SearchState(const boost::filesystem::path & r); -		VariableType fileRelPath() const; -		VariableType fileSize() const; -		VariableType fileModDate() const; -		VariableType fileUser() const; -		VariableType fileGroup() const; -		VariableType fileMode() const; -		VariableType filePerms() const; -		VariableType fileType() const; +				virtual RowAttribute resolveAttr(const Glib::ustring & attrName) const; +				virtual const Columns & getColumns() const; -	protected: -		void execute(const Path & dir, const RowProcessor *) const; -		mutable SpecBases specs; -		mutable boost::filesystem::path fsRoot; -		mutable boost::filesystem::path curPath; -		mutable Glib::ustring curPathStr; -		mutable unsigned int depth; -		mutable struct stat curStat; +				VariableType fileRelPath() const; +				VariableType fileSize() const; +				VariableType fileModDate() const; +				VariableType fileUser() const; +				VariableType fileGroup() const; +				VariableType fileMode() const; +				VariableType filePerms() const; +				VariableType fileType() const; +				static const Columns col; +				SpecBases specs; +				const boost::filesystem::path fsRoot; +				boost::filesystem::path curPath; +				Glib::ustring curPathStr; +				unsigned int depth; +				struct stat curStat; +		}; +	protected: +		void execute(SearchState &, const Path & dir, const RowProcessor *) const;  		friend class SpecBase;  }; diff --git a/project2/iterate.cpp b/project2/iterate.cpp index 795b356..99c5004 100644 --- a/project2/iterate.cpp +++ b/project2/iterate.cpp @@ -26,7 +26,7 @@ Iterate::loadComplete(const CommonObjects * co)  }  void -Iterate::rowReady() const +Iterate::rowReady(const RowState *) const  {  	executeChildren();  } @@ -34,38 +34,14 @@ Iterate::rowReady() const  void  Iterate::execute() const  { -	if (!filter.empty()) { -		source->setFilter(filter); -	} -	RowSet::beginRow(source.get()); -	try { -		source->execute(this); -		RowSet::endRow(source.get()); -	} -	catch (...) { -		RowSet::endRow(source.get()); -		throw; -	} +	source->execute(filter, this);  }  void  Iterate::executeChildren() const  {  	BOOST_FOREACH(const Tasks::value_type & sq, normal) { -		if (dynamic_cast<const RowProcessor *>(sq.get())) { -			sq->execute(); -		} -		else { -			RowSet::beginRow(NULL); -			try { -				sq->execute(); -				RowSet::endRow(NULL); -			} -			catch (...) { -				RowSet::endRow(NULL); -				throw; -			} -		} +		sq->execute();  	}  } diff --git a/project2/iterate.h b/project2/iterate.h index 9ea0f94..50fd879 100644 --- a/project2/iterate.h +++ b/project2/iterate.h @@ -16,7 +16,7 @@ class Iterate : public IHaveSubTasks, public RowProcessor {  		virtual ~Iterate();  		void loadComplete(const CommonObjects *); -		void rowReady() const; +		void rowReady(const RowState *) const;  		void execute() const;  	protected: diff --git a/project2/regexRows.cpp b/project2/regexRows.cpp index 6d75d3a..1dab636 100644 --- a/project2/regexRows.cpp +++ b/project2/regexRows.cpp @@ -7,7 +7,8 @@  DECLARE_LOADER("regexrows", RegexRows);  RegexRows::RegexRows(const xmlpp::Element * p) : -	DefinedColumns(p), +	DefinedColumns(p, "columns/column", boost::bind(&Column::make, _1, _2)), +	RowSet(p),  	sourceText(p, "sourceText"),  	regex(p, "regex")  { @@ -23,28 +24,19 @@ RegexRows::loadComplete(const CommonObjects*)  }  void -RegexRows::setFilter(const Glib::ustring&) +RegexRows::execute(const Glib::ustring&, const RowProcessor * rp) const  { -} - -void -RegexRows::execute(const RowProcessor * rp) const -{ -	rowNum = 1;  	Glib::RefPtr<Glib::Regex> reg = Glib::Regex::create(regex(), Glib::REGEX_CASELESS | Glib::REGEX_DOTALL);  	Glib::MatchInfo matches;  	if (reg->match(sourceText(), matches)) { +		ColumnValues cv(this);  		do { -			unsigned int cols = std::min<unsigned int>(matches.get_match_count(), DefinedColumns::columnCount() + 1); +			unsigned int cols = std::min<unsigned int>(matches.get_match_count(), cv.rowSet->columns.size() + 1);  			unsigned int n;  			for (n = 1; n < cols; n += 1) { -				*DefinedColumns::columns.get<byColIdx>().find(n - 1) = matches.fetch(n); -			} -			for (; n < DefinedColumns::columnCount() + 1; n += 1) { -				*DefinedColumns::columns.get<byColIdx>().find(n - 1) = Null(); +				cv.fields[n - 1] = matches.fetch(n);  			} -			rp->rowReady(); -			rowNum += 1; +			cv.process(rp);  		} while (matches.next());  	}  } diff --git a/project2/regexRows.h b/project2/regexRows.h index b4b6446..cef2e71 100644 --- a/project2/regexRows.h +++ b/project2/regexRows.h @@ -5,13 +5,12 @@  #include "variables.h"  /// Base class for Project2 components that create a row set based on the contents of a byte stream -class RegexRows : public DefinedColumns { +class RegexRows : public DefinedColumns, public RowSet {  	public:  		RegexRows(const xmlpp::Element * p);  		~RegexRows();  		void loadComplete(const CommonObjects*); -		void setFilter(const Glib::ustring&); -		void execute(const RowProcessor*) const; +		void execute(const Glib::ustring&, const RowProcessor*) const;  	private:  		const Variable sourceText; diff --git a/project2/rowProcessor.h b/project2/rowProcessor.h index 0f421f9..38142e5 100644 --- a/project2/rowProcessor.h +++ b/project2/rowProcessor.h @@ -10,7 +10,6 @@  class RowProcessor : public IHaveParameters {  	public:  		RowProcessor(const xmlpp::Element *); -		virtual void rowReady() const = 0;  		void loadComplete(const CommonObjects *);  		const std::string recordSource; @@ -18,6 +17,9 @@ class RowProcessor : public IHaveParameters {  	protected:  		boost::intrusive_ptr<RowSet> source; +	private: +		friend class RowState; +		virtual void rowReady(const RowState *) const = 0;  };  #endif diff --git a/project2/rowSet.cpp b/project2/rowSet.cpp index cfbb9cf..acc9246 100644 --- a/project2/rowSet.cpp +++ b/project2/rowSet.cpp @@ -1,15 +1,16 @@  #include "rowSet.h"  #include "commonObjects.h" +#include "scopeObject.h"  #include "logger.h"  #include "variables.h" +#include "rowProcessor.h"  #include <boost/foreach.hpp>  #include <boost/bind.hpp> -RowSet::RowValuesStack RowSet::stack; +RowState::RowValuesStack RowState::stack;  RowSet::RowSet(const xmlpp::Element * p) : -	SourceObject(p), -	rowNum(-1) +	SourceObject(p)  {  } @@ -17,34 +18,76 @@ RowSet::~RowSet()  {  } +RowState::RowState() : +	rowNum(0) +{ +} + +RowState::~RowState() +{ +} +  void -RowSet::beginRow(const RowSet * r) +RowState::process(const RowProcessor * rp, bool r)  { -	stack.push_back(r); +	rowNum += 1; +	stack.push_back(this); +	ScopeObject s(boost::bind(&RowState::RowValuesStack::pop_back, &stack)); +	rp->rowReady(this); +	if (r) { +		reset(); +	}  }  void -RowSet::endRow(const RowSet * r) +RowState::reset()  { -	if (stack.back() != r) { -		Logger()->messagef(LOG_CRIT, "%s: stack is corrupted", __PRETTY_FUNCTION__); -		std::abort(); +	BOOST_FOREACH(FieldValues::value_type & v, fields) { +		v = Null();  	} -	stack.pop_back(); +} + +void +RowState::blankRow() +{ +	rowNum += 1;  }  VariableType -RowSet::getRowNum() const +RowState::getRowNum() const  {  	return rowNum;  } -RowSet::RowAttribute -RowSet::resolveAttr(const Glib::ustring & attrName) const +RowState::RowAttribute +RowState::resolveAttr(const Glib::ustring & attrName) const  {  	if (attrName == "rownum") { -		return boost::bind(&RowSet::getRowNum, this); +		return boost::bind(&RowState::getRowNum, this);  	}  	throw AttributeDoesNotExist(attrName);  } +VariableType +RowState::getCurrentValue(const Glib::ustring & col) const +{ +	const Columns & columns = getColumns(); +	Columns::index<byColName>::type::iterator di = columns.get<byColName>().find(col); +	if (di != columns.get<byColName>().end()) { +		if (!boost::get<Null>(&fields[(*di)->idx])) { +			return fields[(*di)->idx]; +		} +		return (*di)->defValue; +	} +	throw RowSet::FieldDoesNotExist(col); +} + +void +RowState::foreachColumn(const ColumnAction & action) const +{ +	const Columns & columns = getColumns(); +	BOOST_FOREACH(const Columns::value_type & col, columns.get<byColName>()) { +		action(col->idx, col->name, (!boost::get<Null>(&fields[col->idx])) ? fields[col->idx] : col->defValue()); +	} +} + diff --git a/project2/rowSet.h b/project2/rowSet.h index a907cd2..a9919f9 100644 --- a/project2/rowSet.h +++ b/project2/rowSet.h @@ -5,6 +5,7 @@  #include <set>  #include "sourceObject.h"  #include "exceptions.h" +#include "columns.h"  #include <boost/function.hpp>  class RowProcessor; @@ -13,37 +14,48 @@ class VariableType;  typedef boost::intrusive_ptr<RowSet> RowSetPtr;  typedef boost::intrusive_ptr<const RowSet> ConstRowSetPtr; +class RowState; +  /// Base class for Project2 components that provide a row set representation of data  class RowSet : public SourceObject {  	public: -		typedef boost::function0<VariableType> RowAttribute;  		SimpleNumericException(ParentOutOfRange); -		SimpleMessageException(AttributeDoesNotExist);  		SimpleMessageException(FieldDoesNotExist);  		SimpleNumericException(FieldOutOfRange); -		typedef std::vector<const RowSet *> RowValuesStack; +  		RowSet(const xmlpp::Element *);  		virtual ~RowSet() = 0; -		virtual void setFilter(const Glib::ustring &) = 0; -		virtual unsigned int columnCount() const = 0; -		virtual const Glib::ustring & getColumnName(unsigned int col) const = 0; -		virtual VariableType getCurrentValue(const Glib::ustring & id) const = 0; -		virtual VariableType getCurrentValue(unsigned int col) const = 0; -		virtual bool isNull(unsigned int col) const = 0; -		virtual bool isNull(const Glib::ustring & id) const = 0; +		virtual void execute(const Glib::ustring &, const RowProcessor *) const = 0; +}; + +class RowState { +	public: +		RowState(); +		virtual ~RowState(); + +		typedef boost::function0<VariableType> RowAttribute; +		typedef boost::function3<void, unsigned int, const Glib::ustring &, const VariableType &> ColumnAction; +		SimpleMessageException(AttributeDoesNotExist); +  		VariableType getRowNum() const; -		virtual void execute(const RowProcessor *) const = 0; +		void process(const RowProcessor *, bool reset = true); +		void blankRow(); +		void reset(); +		virtual VariableType getCurrentValue(const Glib::ustring & id) const;  		virtual RowAttribute resolveAttr(const Glib::ustring & attrName) const; +		void foreachColumn(const ColumnAction & action) const; +		virtual const Columns & getColumns() const = 0; + +		typedef std::vector<VariableType> FieldValues; +		FieldValues fields; -		static const RowValuesStack & Stack() { return stack; } -		static void beginRow(const RowSet * r); -		static void endRow(const RowSet * r); -	protected: -		mutable unsigned long int rowNum; +		typedef std::vector<const RowState *> RowValuesStack; +		static const RowValuesStack & Stack() { return stack; }  	private: +		unsigned int rowNum;  		static RowValuesStack stack;  }; diff --git a/project2/rowView.cpp b/project2/rowView.cpp index 8e22c4b..2ac5081 100644 --- a/project2/rowView.cpp +++ b/project2/rowView.cpp @@ -1,7 +1,9 @@  #include "rowView.h"  #include "presenter.h" +#include "scopeObject.h"  #include "xmlObjectLoader.h"  #include <boost/foreach.hpp> +#include <boost/bind.hpp>  #include <libxml++/nodes/textnode.h>  DECLARE_LOADER("view", RowView); @@ -36,14 +38,11 @@ RowView::loadComplete(const CommonObjects * co)  }  void -RowView::rowReady() const +RowView::rowReady(const RowState * rs) const  {  	presenter->pushSub(recordName);  	if (viewColumns.empty()) { -		unsigned int cols = source->columnCount(); -		for (unsigned int c = 0; c < cols; c += 1) { -			presenter->addField(source->getColumnName(c), source->getCurrentValue(c)); -		} +		rs->foreachColumn(boost::bind(&Presenter::addField, presenter, _2, _3));  	}  	else {  		BOOST_FOREACH(const Columns::value_type & col, viewColumns) { @@ -57,22 +56,10 @@ RowView::rowReady() const  void  RowView::execute(const Presenter * p) const  { -	if (!filter.empty()) { -		source->setFilter(filter); -	}  	presenter = p;  	presenter->pushSub(rootName); -	RowSet::beginRow(source.get()); -	try { -		source->execute(this); -		RowSet::endRow(source.get()); -		presenter->popSub(); -	} -	catch (...) { -		presenter->popSub(); -		RowSet::endRow(source.get()); -		throw; -	} +	ScopeObject pres(boost::bind(&Presenter::popSub, p)); +	source->execute(filter, this);  }  void diff --git a/project2/rowView.h b/project2/rowView.h index 3652e37..c065414 100644 --- a/project2/rowView.h +++ b/project2/rowView.h @@ -14,7 +14,7 @@ class RowView : public View, public RowProcessor {  		void loadComplete(const CommonObjects *);  		void execute(const Presenter *) const; -		void rowReady() const; +		void rowReady(const RowState *) const;  		const Glib::ustring rootName;  		const Glib::ustring recordName; diff --git a/project2/safeMapFind.h b/project2/safeMapFind.h new file mode 100644 index 0000000..b27caf3 --- /dev/null +++ b/project2/safeMapFind.h @@ -0,0 +1,27 @@ +#ifndef SAFEMAPFIND_H +#define SAFEMAPFIND_H + +template <class Ex, class Map> +typename Map::const_iterator +safeMapFind(const Map & map, const typename Map::key_type & key) +{ +	typename Map::const_iterator i = map.find(key); +	if (i == map.end()) { +		throw Ex(key); +	} +	return i; +} + +template <class Map> +typename Map::mapped_type +defaultMapFind(const Map & map, const typename Map::key_type & key, const typename Map::mapped_type & def = typename Map::mapped_type()) +{ +	typename Map::const_iterator i = map.find(key); +	if (i == map.end()) { +		return def; +	} +	return i->second; +} + +#endif + diff --git a/project2/scopeObject.cpp b/project2/scopeObject.cpp new file mode 100644 index 0000000..268fd2c --- /dev/null +++ b/project2/scopeObject.cpp @@ -0,0 +1,23 @@ +#include "scopeObject.h" +#include "logger.h" + +ScopeObject::ScopeObject(const Event & onexitpre, const Event & onsuccess, const Event & onfailure, const Event & onexitpost) : +	onExitPre(onexitpre), +	onSuccess(onsuccess), +	onFailure(onfailure), +	onExitPost(onexitpost) +{ +} + +ScopeObject::~ScopeObject() +{ +	if (onExitPre) onExitPre(); +	if (std::uncaught_exception()) { +		if (onFailure) onFailure(); +	} +	else { +		if (onSuccess) onSuccess(); +	} +	if (onExitPost) onExitPost(); +} + diff --git a/project2/scopeObject.h b/project2/scopeObject.h new file mode 100644 index 0000000..d019e7d --- /dev/null +++ b/project2/scopeObject.h @@ -0,0 +1,20 @@ +#ifndef SCOPE_OBJECT_H +#define SCOPE_OBJECT_H + +#include <boost/function.hpp> + +class ScopeObject { +	public: +		typedef boost::function0<void> Event; +		ScopeObject(const Event &, const Event & = Event(), const Event & = Event(), const Event & = Event()); +		~ScopeObject(); + +	private: +		const Event onExitPre; +		const Event onSuccess; +		const Event onFailure; +		const Event onExitPost; +}; + +#endif + diff --git a/project2/sqlMergeTask.cpp b/project2/sqlMergeTask.cpp index fdc6340..2c38bf1 100644 --- a/project2/sqlMergeTask.cpp +++ b/project2/sqlMergeTask.cpp @@ -1,4 +1,5 @@  #include "sqlMergeTask.h" +#include "columns.h"  #include "commonObjects.h"  #include "rdbmsDataSource.h"  #include "exceptions.h" @@ -9,10 +10,11 @@  #include <stdexcept>  #include <boost/algorithm/string/join.hpp>  #include <boost/foreach.hpp> +#include <boost/bind.hpp>  #include <libxml++/nodes/textnode.h>  bool SqlMergeTask::defaultUseTempTable = true; -static void attach(boost::intrusive_ptr<IHaveSubTasks> i, ModifyCommand * insert); +static void attach(boost::intrusive_ptr<IHaveSubTasks> i, DB::ModifyCommand * insert);  class SqlMergeInsert;  typedef boost::intrusive_ptr<SqlMergeInsert> SqlMergeInsertPtr; @@ -34,8 +36,8 @@ class SqlMergeInsert : IHaveParameters, public Task {  			insert->execute();  		}  	private: -		friend void attach(SqlMergeInsertPtr i, ModifyCommand * insert); -		ModifyCommand * insert; +		friend void attach(SqlMergeInsertPtr i, DB::ModifyCommand * insert); +		DB::ModifyCommand * insert;  };  DECLARE_LOADER("sqlmerge", SqlMergeTask); @@ -139,7 +141,7 @@ void  SqlMergeTask::createTempTable() const  {  	if (useView) { -		ModifyCommand * cv = destdb->newModifyCommand(stringf( +		DB::ModifyCommand * cv = destdb->newModifyCommand(stringf(  					"CREATE VIEW %s AS %s",  					dtablet.c_str(),  					boost::algorithm::join(sqls, " UNION ").c_str())); @@ -147,7 +149,7 @@ SqlMergeTask::createTempTable() const  		delete cv;  	}  	else { -		ModifyCommand * ctt = destdb->newModifyCommand(stringf( +		DB::ModifyCommand * ctt = destdb->newModifyCommand(stringf(  					"CREATE TEMPORARY TABLE %s AS SELECT * FROM %s WHERE 0=1",  					dtablet.c_str(),  					dtable.c_str())); @@ -155,7 +157,7 @@ SqlMergeTask::createTempTable() const  		delete ctt;  		BOOST_FOREACH(Columns::value_type c, cols) {  			if (!c->maptable.empty()) { -				ModifyCommand * at = destdb->newModifyCommand(stringf( +				DB::ModifyCommand * at = destdb->newModifyCommand(stringf(  							"ALTER TABLE %s ADD COLUMN %s VARCHAR(1000)",  							dtablet.c_str(),  							c->mapcolumn.c_str())); @@ -170,7 +172,7 @@ void  SqlMergeTask::dropTempTable() const  {  	if (tempTableCreated) { -		ModifyCommand * d; +		DB::ModifyCommand * d;  		if (useView) {  			 d = destdb->newModifyCommand("DROP VIEW " + dtablet);  		} @@ -190,13 +192,13 @@ SqlMergeTask::createTempKey() const  	idx.appendf("ALTER TABLE %s ADD CONSTRAINT pk_%s PRIMARY KEY(%s)",  			dtablet.c_str(), dtablet.c_str(),  			boost::algorithm::join(keys, ", ").c_str()); -	ModifyCommand * at = destdb->newModifyCommand(idx); +	DB::ModifyCommand * at = destdb->newModifyCommand(idx);  	at->execute();  	delete at;  	/* Indexes */  	int n = 0;  	BOOST_FOREACH(const Keys::value_type & i, indexes) { -		ModifyCommand * ci = destdb->newModifyCommand(stringf( +		DB::ModifyCommand * ci = destdb->newModifyCommand(stringf(  					"CREATE INDEX idx_%s_%d ON %s(%s)",  					dtablet.c_str(), n, dtablet.c_str(), i.c_str()));  		ci->execute(); @@ -204,7 +206,7 @@ SqlMergeTask::createTempKey() const  		n += 1;  	}  } -ModifyCommand * +DB::ModifyCommand *  SqlMergeTask::insertCommand() const  {  	Buffer ins; @@ -230,7 +232,7 @@ SqlMergeTask::insertCommand() const  class Populate : public NoOutputExecute {  	public: -		Populate(ModifyCommand * c) : +		Populate(DB::ModifyCommand * c) :  			SourceObject(__FUNCTION__),  			NoOutputExecute(__FUNCTION__),  			cmd(c) @@ -241,40 +243,21 @@ class Populate : public NoOutputExecute {  		}  		void execute() const  		{ -			const RowSet * iter = *++RowSet::Stack().rbegin(); -			if (idxs.empty()) { -				idxs.resize(iter->columnCount()); -				// Sure this can be improved upon... but hey. -				// Find each columns alphabetical index -				unsigned int cols = iter->columnCount(); -				for (unsigned int c = 0; c < cols; c += 1) { -					idxs[c] = 0; -					for (unsigned int d = 0; d < cols; d += 1) { -						if (c != d && iter->getColumnName(d) < iter->getColumnName(c)) { -							idxs[c]++; -						} -					} -				} -			} -			unsigned int cols = iter->columnCount(); -			for (unsigned int c = 0; c < cols; c += 1) { -				try { -					boost::apply_visitor<const SqlVariableBinder, const VariableType>(SqlVariableBinder(cmd, idxs[c]), iter->getCurrentValue(c)); -				} -				catch (const RowSet::FieldDoesNotExist &) { -					cmd->bindNull(idxs[c]); -				} -			} +			unsigned int idx = 0; +			RowState::Stack().back()->foreachColumn(boost::bind(&Populate::bind, this, boost::ref(idx), _3));  			cmd->execute();  		}  	private: -		mutable std::vector<unsigned int> idxs; -		ModifyCommand * cmd; +		void bind(unsigned int & idx, const VariableType & value) const +		{ +			boost::apply_visitor<const SqlVariableBinder, const VariableType>(SqlVariableBinder(cmd, idx++), value); +		} +		DB::ModifyCommand * cmd;  };  typedef boost::intrusive_ptr<Populate> PopulatePtr;  void -attach(SqlMergeInsertPtr i, ModifyCommand * insert) +attach(SqlMergeInsertPtr i, DB::ModifyCommand * insert)  {  	if (i) {  		i->insert = insert; @@ -282,7 +265,7 @@ attach(SqlMergeInsertPtr i, ModifyCommand * insert)  }  static void -attach(boost::intrusive_ptr<IHaveSubTasks> i, ModifyCommand * insert) +attach(boost::intrusive_ptr<IHaveSubTasks> i, DB::ModifyCommand * insert)  {  	if (!i) {  		return; @@ -322,13 +305,13 @@ SqlMergeTask::copyToTempTable() const  			ins.append((*c)->column);  		}  		ins.appendf(" FROM (%s) tmp_src", sql.c_str()); -		ModifyCommand * cttt = destdb->newModifyCommand(ins); +		DB::ModifyCommand * cttt = destdb->newModifyCommand(ins);  		cttt->execute();  		delete cttt;  	}  	BOOST_FOREACH(Columns::value_type c, cols) {  		if (!c->maptable.empty()) { -			ModifyCommand * utt = destdb->newModifyCommand( +			DB::ModifyCommand * utt = destdb->newModifyCommand(  					stringf(  						"UPDATE %s d SET %s = (SELECT m.%s FROM %s m WHERE m.%s = d.%s) WHERE %s IS NULL",  						dtablet.c_str(), diff --git a/project2/sqlMergeTask.h b/project2/sqlMergeTask.h index fc72a93..c9e206c 100644 --- a/project2/sqlMergeTask.h +++ b/project2/sqlMergeTask.h @@ -62,8 +62,8 @@ class SqlMergeTask : public Task {  		Sources sources;  		std::list<std::string>	sqls;  	protected: -		ModifyCommand * insertCommand() const; -		ModifyCommand * insCmd; +		DB::ModifyCommand * insertCommand() const; +		DB::ModifyCommand * insCmd;  	public:  		const DB::Connection * destdb; diff --git a/project2/sqlRows.cpp b/project2/sqlRows.cpp index 2b8745f..fb2de33 100644 --- a/project2/sqlRows.cpp +++ b/project2/sqlRows.cpp @@ -33,15 +33,6 @@ SqlRows::loadComplete(const CommonObjects * co)  	db = co->dataSource<RdbmsDataSource>(dataSource());  } -void -SqlRows::setFilter(const Glib::ustring & name) -{ -	SqlCommand::FiltersRangeType r = sqlCommand.filters.equal_range(name); -	for (SqlCommand::Filters::const_iterator i = r.first; i != r.second; i++) { -		i->second->active = true; -	} -} -  class HandleAsVariableType : public DB::HandleField {  	public:  		void null() { @@ -62,58 +53,45 @@ class HandleAsVariableType : public DB::HandleField {  		VariableType variable;  }; -VariableType -SqlRows::getCurrentValue(const Glib::ustring & id) const -{ -	HandleAsVariableType h; -	(*query)[id].apply(h); -	return h.variable; -} - -VariableType -SqlRows::getCurrentValue(unsigned int col) const -{ -	HandleAsVariableType h; -	(*query)[col].apply(h); -	return h.variable; -} - -bool -SqlRows::isNull(unsigned int col) const +SqlRows::SqlState::SqlState(SelectPtr s) : +	query(s)  { -	return (*query)[col].isNull();  } -bool -SqlRows::isNull(const Glib::ustring & col) const +const Columns & +SqlRows::SqlState::getColumns() const  { -	return (*query)[col].isNull(); -} - -unsigned int -SqlRows::columnCount() const -{ -	return query->columnCount(); -} - -const Glib::ustring & -SqlRows::getColumnName(unsigned int col) const -{ -	return (*query)[col].name; +	if (columns.empty()) { +		for (unsigned int c = 0; c < query->columnCount(); c++) { +			columns.insert(new Column(c, (*query)[c].name)); +		} +	} +	return columns;  }  void -SqlRows::execute(const RowProcessor * rp) const +SqlRows::execute(const Glib::ustring & filter, const RowProcessor * rp) const  { -	rowNum = 1; +	SqlCommand::FiltersRangeType r = sqlCommand.filters.equal_range(filter); +	for (SqlCommand::Filters::const_iterator i = r.first; i != r.second; i++) { +		i->second->active = true; +	}  	unsigned int offset = 0;  	Glib::ustring sql;  	sqlCommand.writeSql(sql); -	query = SelectPtr(db->getReadonly().newSelectCommand(sql)); -	sqlCommand.bindParams(rp, query.get(), offset); -	while (query->fetch()) { -		rp->rowReady(); -		rowNum += 1; +	SqlState ss(SelectPtr(db->getReadonly().newSelectCommand(sql))); +	sqlCommand.bindParams(rp, ss.query.get(), offset); +	while (ss.query->fetch()) { +		HandleAsVariableType h; +		if (ss.fields.empty()) { +			ss.fields.resize(ss.query->columnCount()); +		} +		for (unsigned int c = 0; c < ss.query->columnCount(); c++) { +			const DB::Column & col = (*ss.query)[c]; +			col.apply(h); +			ss.fields[c] = h.variable; +		} +		ss.process(rp);  	}  } diff --git a/project2/sqlRows.h b/project2/sqlRows.h index 901023b..10f57f1 100644 --- a/project2/sqlRows.h +++ b/project2/sqlRows.h @@ -16,15 +16,8 @@ class SqlRows : public RowSet {  		SqlRows(const xmlpp::Element * p);  		~SqlRows(); -		void execute(const RowProcessor *) const; +		void execute(const Glib::ustring &, const RowProcessor *) const;  		virtual void loadComplete(const CommonObjects *); -		virtual void setFilter(const Glib::ustring &); -		unsigned int columnCount() const; -		const Glib::ustring & getColumnName(unsigned int col) const; -		VariableType getCurrentValue(const Glib::ustring & id) const; -		VariableType getCurrentValue(unsigned int col) const; -		bool isNull(unsigned int col) const; -		bool isNull(const Glib::ustring & id) const;  		const Variable dataSource; @@ -80,7 +73,14 @@ class SqlRows : public RowSet {  		};  		SqlCommand sqlCommand;  		typedef boost::shared_ptr<DB::SelectCommand> SelectPtr; -		mutable SelectPtr query; +		class SqlState : public RowState { +			public: +				SqlState(SelectPtr query); +				const Columns & getColumns() const; +				SelectPtr query; +				mutable Columns columns; +				friend class SqlRows; +		};  		const RdbmsDataSource * db;  }; diff --git a/project2/streamRows.cpp b/project2/streamRows.cpp index 825dc60..98d7f03 100644 --- a/project2/streamRows.cpp +++ b/project2/streamRows.cpp @@ -2,7 +2,8 @@  #include "rowProcessor.h"  StreamRows::StreamRows(const xmlpp::Element * p) : -	DefinedColumns(p), +	DefinedColumns(p, "columns/column", boost::bind(&Column::make, _1, _2)), +	RowSet(p),  	fieldSep(p->get_attribute_value("fieldSep")[0]),  	quoteChar(p->get_attribute_value("quoteChar")[0]),  	keepBlankRows(p->get_attribute_value("keepBlankRows") == "true"), @@ -10,11 +11,8 @@ StreamRows::StreamRows(const xmlpp::Element * p) :  	newline(p->get_attribute_value("newline")),  	newlin(newline, 0, newline.length() - 1),  	encoding(p->get_attribute_value("encoding")), -	skipheader(atoi(p->get_attribute_value("skipheader").c_str())), -	inQuotes(false), -	prevWasQuote(false) +	skipheader(atoi(p->get_attribute_value("skipheader").c_str()))  { -	mkCols = columns.empty();  }  StreamRows::~StreamRows() @@ -22,113 +20,85 @@ StreamRows::~StreamRows()  }  void -StreamRows::addColumn(Glib::ustring & tok) const -{ -	for (Glib::ustring::iterator i = tok.begin(); i != tok.end(); ) { -		if (!isalnum(*i)) { -			tok.erase(i); -		} -		else { -			i++; -		} -	} -	columns.insert(Column(columns.size(), tok)); -} - -void -StreamRows::begin() const -{ -	curCol = columns.get<byColIdx>().begin(); -	tok.clear(); -} - -void -StreamRows::pushChar(gunichar c, const RowProcessor * rp) const +StreamRows::pushChar(gunichar c, ParseState & ps) const  { -	if ((!inQuotes) && (c == *newline.rbegin()) && (tok.compare(tok.length() - newlin.length(), newlin.length(), newlin) == 0)) { +	if ((!ps.inQuotes) && (c == *newline.rbegin()) && (ps.tok.compare(ps.tok.length() - newlin.length(), newlin.length(), newlin) == 0)) {  		if (skipheader) { -			skipheader -= 1; +			ps.skipheader -= 1;  		}  		else { -			tok.erase(tok.length() - newlin.length()); -			if (!mkCols) { -				if (!tok.empty()) { -					*curCol++ = VariableType(tok); -				} -				if (keepBlankRows || curCol != columns.get<byColIdx>().begin()) { -					while (curCol != columns.get<byColIdx>().end()) { -						*curCol++ = curCol->defValue; -					} -					rp->rowReady(); -					rowNum += 1; -				} -				else if (countBlankRows) { -					rowNum += 1; -				} +			ps.tok.erase(ps.tok.length() - newlin.length()); +			if (!ps.tok.empty()) { +				*ps.curCol++ = VariableType(ps.tok);  			} -			else { -				if (!tok.empty()) { -					addColumn(tok); +			if (keepBlankRows || ps.curCol != ps.fields.begin()) { +				while (ps.curCol != ps.fields.end()) { +					*ps.curCol++ = Null();  				} -				mkCols = false; +				ps.process(ps.rp);  			} -			curCol = columns.get<byColIdx>().begin(); +			else if (countBlankRows) { +				ps.blankRow(); +			} +			ps.curCol = ps.fields.begin();  		} -		tok.clear(); +		ps.tok.clear();  	}  	else if (c == quoteChar) { -		if (prevWasQuote) { -			tok += c; -			prevWasQuote = false; -			inQuotes = !inQuotes; +		if (ps.prevWasQuote) { +			ps.tok += c; +			ps.prevWasQuote = false; +			ps.inQuotes = !ps.inQuotes;  		}  		else { -			prevWasQuote = inQuotes; -			inQuotes = !inQuotes; +			ps.prevWasQuote = ps.inQuotes; +			ps.inQuotes = !ps.inQuotes;  		}  	} -	else if ((!inQuotes) && (c == fieldSep)) { -		prevWasQuote = false; +	else if ((!ps.inQuotes) && (c == fieldSep)) { +		ps.prevWasQuote = false;  		if (skipheader == 0) { -			if (mkCols) { -				addColumn(tok); -			} -			else { -				*curCol++ = VariableType(tok); -			} +			*ps.curCol++ = VariableType(ps.tok);  		} -		tok.clear(); +		ps.tok.clear();  	}  	else { -		prevWasQuote = false; -		tok += c; +		ps.prevWasQuote = false; +		ps.tok += c;  	}  } +StreamRows::ParseState::ParseState(const StreamRows * rows, const RowProcessor * proc) : +	ColumnValues(rows), +	sr(rows), +	rp(proc), +	inQuotes(false), +	prevWasQuote(false), +	curCol(fields.begin()) +{ +} + +StreamRows::ParseState::~ParseState() +{ +	sr->end(*this); +} +  void -StreamRows::end(const RowProcessor * rp) const +StreamRows::end(ParseState & ps) const  { -	if (!tok.empty()) { +	if (!ps.tok.empty()) {  		if (skipheader == 0) { -			if (mkCols) { -				addColumn(tok); -			} -			else { -				*curCol++ = VariableType(tok); -			} +			*ps.curCol++ = VariableType(ps.tok);  		}  	} -	if (keepBlankRows || curCol != columns.get<byColIdx>().begin()) { -		while (curCol != columns.get<byColIdx>().end()) { -			*curCol++ = curCol->defValue; +	if (keepBlankRows || ps.curCol != ps.fields.begin()) { +		while (ps.curCol != ps.fields.end()) { +			*ps.curCol++ = Null();  		} -		rp->rowReady(); -		rowNum += 1; +		ps.process(ps.rp);  	}  	else if (countBlankRows) { -		rowNum += 1; +		ps.blankRow();  	} -	curCol = columns.get<byColIdx>().begin(); -	tok.clear();  } diff --git a/project2/streamRows.h b/project2/streamRows.h index 4dd9064..2d10116 100644 --- a/project2/streamRows.h +++ b/project2/streamRows.h @@ -7,18 +7,29 @@  class RowProcessor;  /// Base class for Project2 components that create a row set based on the contents of a byte stream -class StreamRows : public DefinedColumns { +class StreamRows : public DefinedColumns, public RowSet {  	public:  		StreamRows(const xmlpp::Element * p);  		~StreamRows();  	protected: -		void begin() const; -		void pushChar(gunichar ch, const RowProcessor *) const; -		void end(const RowProcessor *) const; - -	private: -		void addColumn(Glib::ustring & rawtok) const; +		class ParseState : public ColumnValues { +			public: +				ParseState(const StreamRows *, const RowProcessor *); +				~ParseState(); + +				const StreamRows * sr; +				const RowProcessor * rp; +				size_t skipheader; +				bool inQuotes; +				bool prevWasQuote; +				Glib::ustring tok; +				FieldValues::iterator curCol; + +				friend class StreamRows; +		}; +		void pushChar(gunichar ch, ParseState &) const; +		void end(ParseState &) const;  	public:  		const gunichar fieldSep; @@ -28,13 +39,7 @@ class StreamRows : public DefinedColumns {  		const Glib::ustring newline;  		const Glib::ustring newlin;  		const std::string encoding; -		// Used in callback -		mutable size_t skipheader; -		mutable bool mkCols; -		mutable bool inQuotes; -		mutable bool prevWasQuote; -		mutable Glib::ustring tok; -		mutable Columns::index<byColIdx>::type::iterator curCol; +		const size_t skipheader;  };  #endif diff --git a/project2/tablepatch.cpp b/project2/tablepatch.cpp index aacedbb..f87f60e 100644 --- a/project2/tablepatch.cpp +++ b/project2/tablepatch.cpp @@ -6,6 +6,8 @@  #include <buffer.h>  #include <boost/algorithm/string/join.hpp> +using namespace DB; +  TablePatch::TablePatch(const Connection & wdb, const TablePatch::Table & s, const TablePatch::Table & d,  		const TablePatch::Columns & c) :      src(s), diff --git a/project2/tablepatch.h b/project2/tablepatch.h index 7352635..0174294 100644 --- a/project2/tablepatch.h +++ b/project2/tablepatch.h @@ -8,8 +8,6 @@  #include <modifycommand.h>  #include <selectcommand.h> -using namespace DB; -  class TablePatch {      public:          typedef std::string Table; @@ -23,7 +21,7 @@ class TablePatch {                  const char * what() const throw();          }; -        TablePatch(const Connection & db, const Table & src, const Table & dest, const Columns & cols); +        TablePatch(const DB::Connection & db, const Table & src, const Table & dest, const Columns & cols);          void            addKey(const Column & col);          void            patch(const char * where, const char * order); @@ -37,7 +35,7 @@ class TablePatch {          Table           dest;          PrimaryKey      pk;          Columns 		cols; -        const Connection &db; +        const DB::Connection &db;  };  #endif diff --git a/project2/urlRows.cpp b/project2/urlRows.cpp index 5669925..f8f7eed 100644 --- a/project2/urlRows.cpp +++ b/project2/urlRows.cpp @@ -24,27 +24,21 @@ UrlRows::loadComplete(const CommonObjects *)  {  } -void -UrlRows::setFilter(const Glib::ustring &) -{ -	throw NotSupported(__PRETTY_FUNCTION__); -} -  size_t  UrlRows::handleDataHelper(const char * ptr, size_t size, size_t nmemb, void *stream)  {  	const callback * cb = static_cast<const callback *>(stream); -	size_t used = cb->urlRows->handleData(cb->rp, ptr, size * nmemb); +	size_t used = cb->urlRows->handleData(cb->ps, ptr, size * nmemb);  	return used;  }  size_t -UrlRows::handleData(const RowProcessor * rp, const char * bytes, size_t bytesLen) const +UrlRows::handleData(ParseState & ps, const char * bytes, size_t bytesLen) const  {  	size_t used = 0, len = 0;  	const gchar * utf8 = convertRequired ? g_convert(bytes, bytesLen, "utf-8", encoding.c_str(), &used, &len, NULL) : bytes;  	for (const gchar * iter = utf8; *iter; iter = g_utf8_next_char(iter)) { -		this->pushChar(*iter, rp); +		this->pushChar(*iter, ps);  	}  	if (convertRequired) {  		// We allocated it.. sooo.... @@ -57,21 +51,19 @@ UrlRows::handleData(const RowProcessor * rp, const char * bytes, size_t bytesLen  }  void -UrlRows::execute(const RowProcessor * rp) const +UrlRows::execute(const Glib::ustring &, const RowProcessor * rp) const  { -	rowNum = 1; -	begin();  	CurlHandle::Ptr c = newCurl();  	callback cb(this, rp);  	c->setopt(CURLOPT_WRITEDATA, &cb);  	c->setopt(CURLOPT_WRITEFUNCTION, &handleDataHelper);  	c->perform(); -	end(rp);  }  UrlRows::callback::callback(const UrlRows * u, const RowProcessor * r) :  	urlRows(u), -	rp(r) +	rp(r), +	ps(u, r)  {  } diff --git a/project2/urlRows.h b/project2/urlRows.h index ca1894d..98273bd 100644 --- a/project2/urlRows.h +++ b/project2/urlRows.h @@ -15,17 +15,17 @@ class UrlRows : public StreamRows, CurlHelper {  		~UrlRows();  		virtual void loadComplete(const CommonObjects *); -		void execute(const RowProcessor *) const; -		virtual void setFilter(const Glib::ustring &); +		void execute(const Glib::ustring &, const RowProcessor *) const;  	private:  		struct callback {  			callback(const UrlRows * urlRows, const RowProcessor * rp);  			const UrlRows * urlRows;  			const RowProcessor * rp; +			mutable ParseState ps;  		};  		static size_t handleDataHelper(const char * ptr, size_t size, size_t nmemb, void * stream); -		size_t handleData(const RowProcessor * rp, const char * bytes, size_t bytesLen) const; +		size_t handleData(ParseState &, const char * bytes, size_t bytesLen) const;  		bool convertRequired;  }; diff --git a/project2/variables-modlookup.cpp b/project2/variables-modlookup.cpp index 24c4167..6ba489a 100644 --- a/project2/variables-modlookup.cpp +++ b/project2/variables-modlookup.cpp @@ -84,24 +84,20 @@ class VariableLookup : public VariableImplDyn, public RowProcessor {  		void fillCache() const  		{  			BOOST_FOREACH(const RowSets::value_type & rs, rowSets) { -				cs = rs; -				rs->execute(this); +				rs->execute(filter, this);  			} -			cs.reset();  			Logger()->messagef(LOG_DEBUG, "%s: %s has filled cached with %zu items",  					__PRETTY_FUNCTION__, name.c_str(), map.size());  		} -		void rowReady() const +		void rowReady(const RowState * rs) const  		{  			Key k; -			k.reserve(cs->columnCount() - 1);  			BOOST_FOREACH(const Parameters::value_type & p, parameters) { -				k.push_back(cs->getCurrentValue(p.first)); +				k.push_back(rs->getCurrentValue(p.first));  			} -			map[k] = cs->getCurrentValue(name); +			map[k] = rs->getCurrentValue(name);  		}  		mutable Map map; -		mutable RowSetPtr cs;  		typedef ANONSTORAGEOF(RowSet) RowSets;  		RowSets rowSets;  		const Glib::ustring name; diff --git a/project2/variables.cpp b/project2/variables.cpp index 516e187..70f51b8 100644 --- a/project2/variables.cpp +++ b/project2/variables.cpp @@ -166,13 +166,10 @@ class VariableParent : public VariableImplDyn {  		{  			try {  				if (!getValue) { -					RowSet::RowValuesStack::const_reverse_iterator r = RowSet::Stack().rbegin(); -					for (size_t p = depth; p--; r++) ; -					if (r == RowSet::Stack().rend()) { +					if (depth > RowState::Stack().size()) {  						throw RowSet::ParentOutOfRange(depth);  					} -					; -					bind(*r); +					bind(RowState::Stack()[RowState::Stack().size() - depth]);  				}  				return getValue();  			} @@ -190,14 +187,13 @@ class VariableParent : public VariableImplDyn {  			}  		}  	protected: -		void bind(ConstRowSetPtr row) const +		void bind(const RowState * row) const  		{  			if (attr) {  				getValue = boost::bind(row->resolveAttr(name));  			}  			else { -				typedef VariableType (RowSet::*gCV)(const Glib::ustring &) const; -				getValue = boost::bind((gCV)&RowSet::getCurrentValue, row, name); +				getValue = boost::bind(&RowState::getCurrentValue, row, name);  			}  		}  		const size_t depth; diff --git a/project2/xmlRows.cpp b/project2/xmlRows.cpp index bd958a5..8982945 100644 --- a/project2/xmlRows.cpp +++ b/project2/xmlRows.cpp @@ -25,6 +25,7 @@ XmlRows::XmlRows(const xmlpp::Element * p) :  	boost::split(root, recordRoot, boost::is_any_of("/"));  	boost::split(trigger, recordTrigger, boost::is_any_of("/")); +	unsigned int col = 0;  	BOOST_FOREACH(const xmlpp::Node * node, p->find("fields/field")) {  		const xmlpp::Element * elem = dynamic_cast<const xmlpp::Element *>(node);  		if (elem) { @@ -38,12 +39,10 @@ XmlRows::XmlRows(const xmlpp::Element * p) :  				p.push_back(Glib::ustring(It->begin(), It->end()));  			} -			fields[p] = elem->get_attribute_value("name"); +			fields[p] = col; +			fieldNames.insert(new Column(col++, elem->get_attribute_value("name")));  		}  	} -	BOOST_FOREACH(const Interests::value_type & v, fields) { -		fieldNames.push_back(v.second); -	}  }  XmlRows::~XmlRows() @@ -55,58 +54,9 @@ XmlRows::loadComplete(const CommonObjects *)  {  } +static  void -XmlRows::setFilter(const Glib::ustring &) -{ -	throw NotSupported(__PRETTY_FUNCTION__); -} - -VariableType -XmlRows::getCurrentValue(const Glib::ustring & id) const -{ -	Values::const_iterator i = values.find(id); -	if (i == values.end()) { -		throw FieldDoesNotExist(id); -	} -	return i->second; -} - -VariableType -XmlRows::getCurrentValue(unsigned int col) const -{ -	Values::const_iterator i = values.find(fieldNames[col]); -	if (i == values.end()) { -		throw FieldDoesNotExist(""); -	} -	return i->second; -} - -bool -XmlRows::isNull(unsigned int col) const -{ -	return (values.find(fieldNames[col]) == values.end()); -} - -bool -XmlRows::isNull(const Glib::ustring & col) const -{ -	return (values.find(col) == values.end()); -} - -unsigned int -XmlRows::columnCount() const -{ -	return fields.size(); -} - -const Glib::ustring & -XmlRows::getColumnName(unsigned int col) const -{ -	return fieldNames[col]; -} - -void -store(const XmlRows::Path & position, XmlRows::Values & values, const XmlRows::Interests & fields, const xmlChar * val) +store(const XmlRows::Path & position, RowState::FieldValues & values, const XmlRows::Interests & fields, const xmlChar * val)  {  	XmlRows::Interests::const_iterator i = fields.find(position);  	if (i != fields.end()) { @@ -115,14 +65,14 @@ store(const XmlRows::Path & position, XmlRows::Values & values, const XmlRows::I  }  void -XmlRows::execute(const RowProcessor * rp) const +XmlRows::execute(const Glib::ustring &, const RowProcessor * rp) const  { -	rowNum = 1;  	xmlTextReaderPtr reader = xmlReaderForFile(filename.c_str(), NULL, 0);  	if (reader == NULL) {  		throw std::runtime_error("Failed to open file");  	} +	XmlState xs(this);  	Path position;  	bool enableCapture = false;  	while (xmlTextReaderRead(reader) == 1) { @@ -138,16 +88,15 @@ XmlRows::execute(const RowProcessor * rp) const  							std::string attr("@");  							attr += (const char *)xmlTextReaderConstName(reader);  							p.push_back(attr); -							store(p, values, fields, xmlTextReaderConstValue(reader)); +							store(p, xs.fields, fields, xmlTextReaderConstValue(reader));  						}  					}  					if (empty) {  						if (position == trigger) { -							rp->rowReady(); -							rowNum += 1; +							xs.process(rp, false);  						}  						if (position == root) { -							values.clear(); +							xs.reset();  						}  						position.pop_back();  					} @@ -155,17 +104,16 @@ XmlRows::execute(const RowProcessor * rp) const  				break;  			case XML_READER_TYPE_TEXT:  				if (enableCapture) { -					store(position, values, fields, xmlTextReaderConstValue(reader)); +					store(position, xs.fields, fields, xmlTextReaderConstValue(reader));  				}  				break;  			case XML_READER_TYPE_END_ELEMENT:  				if (enableCapture) {  					if (position == trigger) { -						rp->rowReady(); -						rowNum += 1; +						xs.process(rp, false);  					}  					if (position == root) { -						values.clear(); +						xs.reset();  					}  				}  				position.pop_back(); @@ -176,3 +124,13 @@ XmlRows::execute(const RowProcessor * rp) const  	xmlCleanupParser();  } +XmlRows::XmlState::XmlState(const XmlRows * rows) : +	rs(rows) +{ +} +const Columns & +XmlRows::XmlState::getColumns() const +{ +	return rs->fieldNames; +} + diff --git a/project2/xmlRows.h b/project2/xmlRows.h index efbaf5e..3ab889e 100644 --- a/project2/xmlRows.h +++ b/project2/xmlRows.h @@ -9,35 +9,32 @@  /// Project2 component to create a row set based on the contents of an XML file  class XmlRows : public RowSet {  	public: -		typedef std::map<Glib::ustring, Glib::ustring> Values;  		typedef std::vector<std::string> Path; -		typedef std::map<Path, Glib::ustring> Interests; +		typedef std::map<Path, unsigned int> Interests;  		XmlRows(const xmlpp::Element * p);  		~XmlRows(); -		void execute(const RowProcessor *) const; +		void execute(const Glib::ustring &, const RowProcessor *) const;  		virtual void loadComplete(const CommonObjects *); -		virtual void setFilter(const Glib::ustring &); -		unsigned int columnCount() const; -		const Glib::ustring & getColumnName(unsigned int col) const; -		VariableType getCurrentValue(const Glib::ustring & id) const; -		VariableType getCurrentValue(unsigned int col) const; -		bool isNull(unsigned int col) const; -		bool isNull(const Glib::ustring & id) const;  		const Glib::ustring recordRoot;  		const Glib::ustring recordTrigger;  		const std::string filename;  	private: -		mutable Values values; +		class XmlState : public RowState { +			public: +				XmlState(const XmlRows *); +				const Columns & getColumns() const; +				const XmlRows * rs; +		};  		Path root;  		Path trigger;  		Interests fields;  		bool anyInterestingAttributes; -		std::vector<Glib::ustring> fieldNames; +		Columns fieldNames;  };  #endif diff --git a/project2/xslRows.cpp b/project2/xslRows.cpp index 999f196..07d57b6 100644 --- a/project2/xslRows.cpp +++ b/project2/xslRows.cpp @@ -1,4 +1,5 @@  #include "xslRows.h" +#include "safeMapFind.h"  #include "rowProcessor.h"  #include "logger.h"  #include "xml.h" @@ -46,16 +47,6 @@ XslRows::loadComplete(const CommonObjects *)  {  } -void -XslRows::setFilter(const Glib::ustring & f) -{ -	FilterViews::const_iterator i = fvs.find(f); -	if (i == fvs.end()) { -		throw FilterNotFound(f); -	} -	fv = i->second; -} -  bool  XslRows::asHtml() const  { @@ -75,8 +66,10 @@ XslRows::newCurl() const  }  void -XslRows::execute(const RowProcessor * rp) const +XslRows::execute(const Glib::ustring & filter, const RowProcessor * rp) const  { +	FilterViewPtr fv = safeMapFind<FilterNotFound>(fvs, filter)->second; +  	typedef boost::shared_ptr<xmlXPathObject> xmlXPathObjectSPtr;  	typedef boost::shared_ptr<xmlXPathContext> xmlXPathContextSPtr;  	xmlDocPtr doc = getDocument(url(), encoding()); @@ -91,16 +84,15 @@ XslRows::execute(const RowProcessor * rp) const  	if (!xpathObj || !xpathObj->nodesetval) {  		throw XpathEvalError(xmlGetLastError()->message);  	} -	rowNum = 1;  	Logger()->messagef(LOG_INFO, "%d nodes matched %s", xpathObj->nodesetval->nodeNr, (const char *)(fv->root())); +	XslState xs(fv);  	for (int row = 0; row < xpathObj->nodesetval->nodeNr; row += 1) {  		xmlNodePtr rowRoot = xpathObj->nodesetval->nodeTab[row];  		xpathCtx->node = rowRoot; -		values.clear(); -		BOOST_FOREACH(const FilterView::XPaths::value_type & xp, fv->xpaths) { -			VariableType path(xp.second()); +		BOOST_FOREACH(const Columns::value_type & _xp, fv->columns.get<byColIdx>()) { +			const FilterViewColumn * xp = static_cast<const FilterViewColumn *>(_xp.get()); +			const VariableType & path(xp->path);  			if (boost::get<Null>(&path)) { -				values[xp.first] = Null();  				continue;  			}  			xmlXPathObjectSPtr xpathObjI = xmlXPathObjectSPtr(xmlXPathEvalExpression(path, xpathCtx.get()), xmlXPathFreeObject); @@ -108,10 +100,10 @@ XslRows::execute(const RowProcessor * rp) const  				throw XpathEvalError(xmlGetLastError()->message);  			}  			if (xpathObjI->floatval) { -				values[xp.first] = xpathObjI->floatval; +				xs.fields[xp->idx] = xpathObjI->floatval;  			}  			else if (xpathObjI->stringval) { -				values[xp.first] = Glib::ustring((const char *)xpathObjI->stringval); +				xs.fields[xp->idx] = Glib::ustring((const char *)xpathObjI->stringval);  			}  			else if (xpathObjI->nodesetval) {  				Glib::ustring str; @@ -127,64 +119,41 @@ XslRows::execute(const RowProcessor * rp) const  						}  					}  				} -				values[xp.first] = str; -			} -			else { -				values[xp.first] = Null(); +				xs.fields[xp->idx] = str;  			}  		} -		rp->rowReady(); -		rowNum += 1; +		xs.process(rp);  	}  }  XslRows::FilterView::FilterView(const xmlpp::Element * p) : +	DefinedColumns(p, "field", boost::bind(XslRows::FilterViewColumn::make, _1, _2)),  	name(p->get_attribute_value("name")),  	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"), Variable(elem, "xpath"))); -		} -	}  } -VariableType -XslRows::getCurrentValue(const Glib::ustring & id) const +XslRows::FilterViewColumn::FilterViewColumn(unsigned int idx, const xmlpp::Element * p) : +	Column(idx, p), +	path(p, "xpath")  { -	return values.find(id)->second;  } -VariableType -XslRows::getCurrentValue(unsigned int col) const -{ -	return getCurrentValue(getColumnName(col)); -} - -bool -XslRows::isNull(unsigned int col) const -{ -	return isNull(getColumnName(col)); -} - -bool -XslRows::isNull(const Glib::ustring & col) const +XslRows::FilterViewColumn * +XslRows::FilterViewColumn::make(unsigned int idx, const xmlpp::Element * p)  { -	return (values.find(col) == values.end()); +	return new FilterViewColumn(idx, p);  } -unsigned int -XslRows::columnCount() const +XslRows::XslState::XslState(FilterViewCPtr f) : +	fv(f)  { -	return fv->xpaths.size(); +	fields.resize(f->columns.size());  } -const Glib::ustring & -XslRows::getColumnName(unsigned int col) const +const Columns & +XslRows::XslState::getColumns() const  { -	FilterView::XPaths::const_iterator i = fv->xpaths.begin(); -	while (col--) i++; -	return i->first; +	return fv->columns;  } diff --git a/project2/xslRows.h b/project2/xslRows.h index a30ca02..e33932f 100644 --- a/project2/xslRows.h +++ b/project2/xslRows.h @@ -9,6 +9,7 @@  #include "variables.h"  #include "xslRowsCache.h"  #include "curlHelper.h" +#include "definedColumns.h"  /// Project2 component to create a row set based on the contents of an XML resource and specific XPaths with its hierarchy  class XslRows : public RowSet, XslRowsCache, CurlHelper { @@ -16,21 +17,20 @@ class XslRows : public RowSet, XslRowsCache, CurlHelper {  		XslRows(const xmlpp::Element * p);  		~XslRows(); -		void execute(const RowProcessor *) const; +		void execute(const Glib::ustring &, const RowProcessor *) const;  		virtual void loadComplete(const CommonObjects *); -		virtual void setFilter(const Glib::ustring &); -		unsigned int columnCount() const; -		const Glib::ustring & getColumnName(unsigned int col) const; -		VariableType getCurrentValue(const Glib::ustring & id) const; -		VariableType getCurrentValue(unsigned int col) const; -		bool isNull(unsigned int col) const; -		bool isNull(const Glib::ustring & id) const;  		const bool html;  		const bool warnings;  	private: -		class FilterView : public virtual IntrusivePtrBase { +		class FilterViewColumn : public Column { +			public: +				FilterViewColumn(unsigned int, const xmlpp::Element *); +				static FilterViewColumn * make(unsigned int, const xmlpp::Element *); +				const Variable path; +		}; +		class FilterView : public DefinedColumns, public virtual IntrusivePtrBase {  			public:  				typedef std::map<const Glib::ustring, Variable> XPaths; @@ -38,21 +38,25 @@ class XslRows : public RowSet, XslRowsCache, CurlHelper {  				const Glib::ustring name;  				const Variable root; -				XPaths xpaths;  		};  		typedef boost::intrusive_ptr<FilterView> FilterViewPtr; +		typedef boost::intrusive_ptr<const FilterView> FilterViewCPtr;  		typedef std::map<const Glib::ustring, FilterViewPtr> FilterViews;  		FilterViews fvs; -		FilterViewPtr fv;  		virtual CurlHandle::Ptr newCurl() const;  		virtual bool asHtml() const;  		virtual bool withWarnings() const;  		typedef std::map<const Glib::ustring, Glib::ustring> Namespaces; -		mutable Namespaces namespaces; -		typedef std::map<const Glib::ustring, VariableType> Values; -		mutable Values values; +		Namespaces namespaces; +		class XslState : public RowState { +			public: +				XslState(FilterViewCPtr); +				const Columns & getColumns() const; +			private: +				const FilterViewCPtr fv; +		};  		const Variable encoding;  };  | 
