+RESULT eDVBDB::startQuery(ePtr<iDVBChannelListQuery> &query, eDVBChannelQuery *q)
+{
+ query = new eDVBDBQuery(this, eServiceReference(), q);
+ return 0;
+}
+
+DEFINE_REF(eDVBDBQuery);
+
+eDVBDBQuery::eDVBDBQuery(eDVBDB *db, const eServiceReference &source, eDVBChannelQuery *query): m_db(db), m_query(query)
+{
+ // TODO: use SOURCE ...
+ m_cursor = m_db->m_services.begin();
+}
+
+RESULT eDVBDBQuery::getNextResult(eServiceReferenceDVB &ref)
+{
+ while (m_cursor != m_db->m_services.end())
+ {
+ ref = m_cursor->first;
+
+ int res = (!m_query) || m_cursor->second->checkFilter(ref, *m_query);
+
+ ++m_cursor;
+
+ if (res)
+ return 0;
+ }
+
+ ref = eServiceReferenceDVB();
+ return 1;
+}
+
+int eDVBDBQuery::compareLessEqual(const eServiceReferenceDVB &a, const eServiceReferenceDVB &b)
+{
+ ePtr<eDVBService> a_service, b_service;
+
+ int sortmode = m_query ? m_query->m_sort : eDVBChannelQuery::tName;
+
+ if ((sortmode == eDVBChannelQuery::tName) || (sortmode == eDVBChannelQuery::tProvider))
+ {
+ if (m_db->getService(a, a_service))
+ return 1;
+ if (m_db->getService(b, b_service))
+ return 1;
+ }
+
+ switch (sortmode)
+ {
+ case eDVBChannelQuery::tName:
+ return a_service->m_service_name_sort < b_service->m_service_name_sort;
+ case eDVBChannelQuery::tProvider:
+ return a_service->m_provider_name < b_service->m_provider_name;
+ case eDVBChannelQuery::tType:
+ return a.getServiceType() < b.getServiceType();
+ case eDVBChannelQuery::tBouquet:
+ return 1;
+ case eDVBChannelQuery::tSatellitePosition:
+ return (a.getDVBNamespace().get() >> 16) < (b.getDVBNamespace().get() >> 16);
+ default:
+ return 1;
+ }
+ return 0;
+}
+
+/* (<name|provider|type|bouquet|satpos|chid> <==|...> <"string"|int>)[||,&& (..)] */
+
+static int decodeType(const std::string &type)
+{
+ if (type == "name")
+ return eDVBChannelQuery::tName;
+ else if (type == "provider")
+ return eDVBChannelQuery::tProvider;
+ else if (type == "type")
+ return eDVBChannelQuery::tType;
+ else if (type == "bouquet")
+ return eDVBChannelQuery::tBouquet;
+ else if (type == "satellitePosition")
+ return eDVBChannelQuery::tSatellitePosition;
+ else if (type == "channelID")
+ return eDVBChannelQuery::tChannelID;
+ else
+ return -1;
+}
+
+ /* never, NEVER write a parser in C++! */
+RESULT parseExpression(ePtr<eDVBChannelQuery> &res, std::list<std::string>::const_iterator begin, std::list<std::string>::const_iterator end)
+{
+ std::list<std::string>::const_iterator end_of_exp;
+ if (*begin == "(")
+ {
+ end_of_exp = begin;
+ while (end_of_exp != end)
+ if (*end_of_exp == ")")
+ break;
+ else
+ ++end_of_exp;
+
+ if (end_of_exp == end)
+ {
+ eDebug("expression parse: end of expression while searching for closing brace");
+ return -1;
+ }
+
+ ++begin;
+ // begin..end_of_exp
+ int r = parseExpression(res, begin, end_of_exp);
+ if (r)
+ return r;
+ ++end_of_exp;
+
+ /* we had only one sub expression */
+ if (end_of_exp == end)
+ {
+ eDebug("only one sub expression");
+ return 0;
+ }
+
+ /* otherwise we have an operator here.. */
+
+ ePtr<eDVBChannelQuery> r2 = res;
+ res = new eDVBChannelQuery();
+ res->m_sort = 0;
+ res->m_p1 = r2;
+ res->m_inverse = 0;
+ r2 = 0;
+
+ if (*end_of_exp == "||")
+ res->m_type = eDVBChannelQuery::tOR;
+ else if (*end_of_exp == "&&")
+ res->m_type = eDVBChannelQuery::tAND;
+ else
+ {
+ eDebug("found operator %s, but only && and || are allowed!", end_of_exp->c_str());
+ res = 0;
+ return 1;
+ }
+
+ ++end_of_exp;
+
+ return parseExpression(res->m_p2, end_of_exp, end);
+ }
+
+ // "begin" <op> "end"
+ std::string type, op, val;
+
+ res = new eDVBChannelQuery();
+ res->m_sort = 0;
+
+ int cnt = 0;
+ while (begin != end)
+ {
+ switch (cnt)
+ {
+ case 0:
+ type = *begin;
+ break;
+ case 1:
+ op = *begin;
+ break;
+ case 2:
+ val = *begin;
+ break;
+ case 3:
+ eDebug("malformed query: got '%s', but expected only <type> <op> <val>", begin->c_str());
+ return 1;
+ }
+ ++begin;
+ ++cnt;
+ }
+
+ if (cnt != 3)
+ {
+ eDebug("malformed query: missing stuff");
+ res = 0;
+ return 1;
+ }
+
+ res->m_type = decodeType(type);
+
+ if (res->m_type == -1)
+ {
+ eDebug("malformed query: invalid type %s", type.c_str());
+ res = 0;
+ return 1;
+ }
+
+ if (op == "==")
+ res->m_inverse = 0;
+ else if (op == "!=")
+ res->m_inverse = 1;
+ else
+ {
+ eDebug("invalid operator %s", op.c_str());
+ res = 0;
+ return 1;
+ }
+
+ res->m_string = val;
+ res->m_int = atoi(val.c_str());
+// res->m_channelid = eDVBChannelID(val);
+
+ return 0;
+}
+
+RESULT eDVBChannelQuery::compile(ePtr<eDVBChannelQuery> &res, std::string query)
+{
+ std::list<std::string> tokens;
+
+ std::string current_token;
+
+ eDebug("splitting %s....", query.c_str());
+ unsigned int i = 0;
+ const char *splitchars="()";
+ int quotemode = 0, lastsplit = 0, lastalnum = 0;
+ while (i <= query.size())
+ {
+ int c = (i < query.size()) ? query[i] : ' ';
+ ++i;
+
+ int issplit = !!strchr(splitchars, c);
+ int isaln = isalnum(c);
+ int iswhite = c == ' ';
+ int isquot = c == '\"';
+
+ if (quotemode)
+ {
+ iswhite = issplit = 0;
+ isaln = lastalnum;
+ }
+
+ if (issplit || iswhite || isquot || lastsplit || (lastalnum != isaln))
+ {
+ if (current_token.size())
+ tokens.push_back(current_token);
+ current_token.clear();
+ }
+
+ if (!(iswhite || isquot))
+ current_token += c;
+
+ if (isquot)
+ quotemode = !quotemode;
+ lastsplit = issplit;
+ lastalnum = isaln;
+ }
+
+// for (std::list<std::string>::const_iterator a(tokens.begin()); a != tokens.end(); ++a)
+// {
+// printf("%s\n", a->c_str());
+// }
+
+ int sort = eDVBChannelQuery::tName;
+ /* check for "ORDER BY ..." */
+ if (tokens.size() > 2)
+ {
+ std::list<std::string>::iterator i = tokens.end();
+ --i; --i; --i;
+ if (*i == "ORDER")
+ {
+ ++i;
+ if (*i == "BY")
+ {
+ ++i;
+ sort = decodeType(*i);
+ tokens.pop_back(); // ...
+ tokens.pop_back(); // BY
+ tokens.pop_back(); // ORDER
+ } else
+ sort = -1;
+ }
+ }
+
+ if (sort == -1)
+ {
+ eWarning("ORDER BY .. string invalid.");
+ res = 0;
+ return -1;
+ }
+
+ eDebug("sort by %d", sort);
+
+ /* now we recursivly parse that. */
+ int r = parseExpression(res, tokens.begin(), tokens.end());
+
+ if (res)
+ res->m_sort = sort;
+
+ eDebug("return: %d", r);
+ return r;
+}
+
+DEFINE_REF(eDVBChannelQuery);