diff options
Diffstat (limited to 'kommander/widget')
24 files changed, 5879 insertions, 0 deletions
diff --git a/kommander/widget/Makefile.am b/kommander/widget/Makefile.am new file mode 100644 index 00000000..410d57c9 --- /dev/null +++ b/kommander/widget/Makefile.am @@ -0,0 +1,20 @@ +lib_LTLIBRARIES = libkommanderwidget.la + +# set the include path for X, qt and KDE +INCLUDES = -I$(top_srcdir)/kommander/plugin -I$(top_srcdir)/kommander/factory $(all_includes) + +# the library search path. +libkommanderwidget_la_LDFLAGS = $(KDE_RPATH) $(all_libraries) -no-undefined + +# the libraries to link against. +libkommanderwidget_la_LIBADD = $(top_builddir)/kommander/factory/libkommanderfactory.la $(LIB_KIO) $(LIB_KDEUI) $(LIB_QT) + +libkommanderwidget_la_SOURCES = expression.cpp function.cpp functionlib.cpp \ + invokeclass.cpp kmdrmainwindow.cpp kommanderfunctions.cpp kommanderwidget.cpp \ + kommanderwindow.cpp myprocess.cpp parsenode.cpp parser.cpp parserdata.cpp + +include_HEADERS = kommanderwidget.h kommander_export.h + +# let automoc handle all of the meta source files (moc) +METASOURCES = AUTO +noinst_HEADERS = invokeclass.h kmdrmainwindow.h diff --git a/kommander/widget/expression.cpp b/kommander/widget/expression.cpp new file mode 100644 index 00000000..88d46b51 --- /dev/null +++ b/kommander/widget/expression.cpp @@ -0,0 +1,332 @@ +/*************************************************************************** + expression.cpp - Expression parser + ------------------- + copyright : (C) 2004 Michal Rudolf <mrudolf@kdewebdwev.org> + + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "expression.h" + +#include <klocale.h> + +Expression::Expression() : m_start(0), m_error(false) +{ +} + +Expression::Expression(const QString& expr) +{ + *this = expr; +} + +Expression& Expression::operator=(const QString& s) +{ + m_start = 0; + m_error = false; + m_parts.clear(); + const QString single = "()<>!+-/*%"; + int start = 0; + int len = s.length(); + int i = 0; + while (i < len) + { + if (((s[i] == '>' || s[i] == '<' || s[i] == '=' || s[i] == '!') && + s[i + 1] == '=') || (s[i] == '<' && s[i + 1] == '>')) + { + m_parts.append(QVariant(s.mid(i, 2))); + i += 2; + } else if (s[i].isDigit()) + { + i++; + bool decimal = false; + while (i < len && (s[i].isDigit() || (!decimal && s[i] == QChar('.')))) + { + if (s[i] == '.') + decimal = true; + i++; + } + if (decimal) + m_parts.append(QVariant(s.mid(start, i - start).toDouble())); + else + m_parts.append(QVariant(s.mid(start, i - start).toInt())); + } else if (single.contains(s[i])) + m_parts.append(QVariant(QString(s[i++]))); + else if (s[i] == '\"') + { + i++; + while (i < len && s[i] != '\"') + i++; + m_parts.append(QVariant(s.mid(start + 1, i - start - 1))); + i++; + } else if (s[i].isSpace()) + while (i < len && s[i].isSpace()) + i++; + else + { + while (i < len && !s[i].isSpace()) + i++; + QString keyword = s.mid(start, i - start); + if (keyword == "true") + m_parts.append(QVariant(true)); + else if (keyword == "false") + m_parts.append(QVariant(false)); + else /* will be deprecated soon */ + m_parts.append(QVariant(keyword)); + } + start = i; + } + return *this; +} + +QString Expression::next() const +{ + if (m_start < m_parts.count()) + return m_parts[m_start].toString(); + else + return QString(); +} + +bool Expression::validate() +{ + if (m_start >= m_parts.count()) + setError(); + return !m_error; +} +Expression::Type Expression::commonType(const QVariant v1, const QVariant v2) const +{ + if (v1.type() == QVariant::String || v2.type() == QVariant::String) + return TypeString; + else if (v1.type() == QVariant::Double || v2.type() == QVariant::Double) + return TypeDouble; + return TypeInt; +} + +static int expression_compareDouble(const double A, const double B) +{ + return A<B ? -1 : (A==B ? 0 : 1); +} + + +int Expression::compare(const QVariant v1, const QVariant v2) const +{ + switch (commonType(v1, v2)) { + case TypeString: return v1.toString().compare(v2.toString()); + case TypeDouble: return expression_compareDouble(v1.toDouble(), v2.toDouble()); + case TypeInt: return v1.toInt() - v2.toInt(); + default: return 0; + } +} + + +void Expression::setError(int pos) +{ + m_errorPosition = pos == -1 ? m_start : pos; + m_error = true; +} + +QVariant Expression::parseNumber() +{ + if (!validate()) + return -1; + return m_parts[m_start++]; +} + +QVariant Expression::parseMinus() +{ + if (!validate()) return -1; + bool sign = next() == "-"; + if (sign) + { + m_start++; + QVariant value = parseNumber(); + if (value.type() == QVariant::Double) + return -value.toDouble(); + else + return -value.toInt(); + } + else + return parseNumber(); +} + + + +QVariant Expression::parseBracket() +{ + if (!validate()) return -1; + if (next() == "(") + { + m_start++; + QVariant value = parse(); + if (next() == ")") + m_start++; + else + setError(); + return value; + } + else + return parseMinus(); +} + + +QVariant Expression::parseMultiply() +{ + if (!validate()) return -1; + QVariant value = parseBracket(); + QString op = next(); + while (op == "*" || op == "/" || op == "%") + { + m_start++; + QVariant value2 = parseBracket(); + Type mode = commonType(value, value2); + if (op == "*") + { + if (mode == TypeDouble) + value = value.toDouble() * value2.toDouble(); + else + value = value.toInt() * value2.toInt(); + } + else if (op == "/") + { + if (value2.toInt() == 0) + return i18n("error"); + if (mode == TypeDouble || value.toInt() != value.toInt() / value2.toInt() * value2.toInt()) + value = value.toDouble() / value2.toDouble(); + else + value = value.toInt() / value2.toInt(); + } + else + { + if (value2.toInt() == 0) + return i18n("error"); + if (mode == TypeDouble) + value = value.toDouble() / value2.toInt(); + else + value = value.toInt() / value2.toInt(); + } + op = next(); + } + return value; +} + +QVariant Expression::parseAdd() +{ + if (!validate()) return -1; + QVariant value = parseMultiply(); + QString op = next(); + while (op == "+" || op == "-") + { + m_start++; + QVariant value2 = parseMultiply(); + Type mode = commonType(value, value2); + if (op == "+") + if (mode == TypeDouble) + value = value.toDouble() + value2.toDouble(); + else + value = value.toInt() + value2.toInt(); + else + if (mode == TypeDouble) + value = value.toDouble() - value2.toDouble(); + else + value = value.toInt() - value2.toInt(); + op = next(); + } + return value; +} + +QVariant Expression::parseComparison() +{ + if (!validate()) return -1; + QVariant value = parseAdd(); + QString cmp = next(); + if (cmp == "<" || cmp == "<=" || cmp == "==" || cmp == ">=" || cmp == ">" || cmp == "<>" || cmp == "!=") + { + m_start++; + QVariant value2 = parseAdd(); + if (cmp == "<") + return compare(value, value2) < 0; + else if (cmp == "<=") + return compare(value, value2) <= 0; + else if (cmp == "==") + return compare(value, value2) == 0; + else if (cmp == ">=") + return compare(value, value2) >= 0; + else if (cmp == "<>" || cmp == "!=") + return compare(value, value2) != 0; + else + return compare(value, value2) > 0; + } + return value; +} + +QVariant Expression::parseNot() +{ + if (next() == "!" || next() == "not") + { + m_start++; + return !parseComparison().asBool(); + } + else + return parseComparison(); +} + +QVariant Expression::parseAnd() +{ + if (!validate()) return -1; + QVariant value = parseNot(); + while (next() == "&&" || next() == "and") + { + m_start++; + value = parseNot().toBool() && value.toBool(); + } + + return value; +} + +QVariant Expression::parseOr() +{ + if (!validate()) return -1; + QVariant value = parseAnd(); + while (next() == "||" || next() == "or") + { + m_start++; + value = parseAnd().toBool() || value.toBool(); + } + return value; +} + +QVariant Expression::parse() +{ + return parseOr(); +} + +QVariant Expression::value(bool* valid) +{ + m_start = 0; + m_error = false; + QVariant val = parse(); + if (valid) + *valid = !m_error && m_start == m_parts.count(); + return val; +} + +QVariant Expression::value(const QString& s, bool* valid) +{ + *this = s; + return value(valid); +} + +bool Expression::isTrue(const QString& s, bool* valid) +{ + QVariant v = value(s, valid); + return (v.type() == QVariant::String && !v.toString().isNull()) || + (v.type() != QVariant::String && v.toInt() != 0); +} + diff --git a/kommander/widget/expression.h b/kommander/widget/expression.h new file mode 100644 index 00000000..7ab163e2 --- /dev/null +++ b/kommander/widget/expression.h @@ -0,0 +1,80 @@ +/*************************************************************************** + expression.h - Expression parser + ------------------- + copyright : (C) 2004 Michal Rudolf <mrudolf@kdewebdwev.org> + + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef _HAVE_EXPRESSION_H_ +#define _HAVE_EXPRESSION_H_ + +#include <qstring.h> +#include <qvaluelist.h> +#include <qvariant.h> + +class Expression +{ +public: + Expression(); + Expression(const QString& expr); + /* set string to parse */ + Expression& operator=(const QString& s); + /* calculate value */ + QVariant value(bool* valid = 0); + /* equivalent of setString(s) and value(valid) */ + QVariant value(const QString& s, bool* valid = 0); + /* equivalent of setString(s) and checking if value(valid) is true */ + bool isTrue(const QString& s, bool* valid = 0); +private: + enum Type {TypeInt, TypeDouble, TypeString}; + /* parsing function - top-down approach */ + /* parse terminal (number or string) */ + QVariant parseNumber(); + /* parse -x expression */ + QVariant parseMinus(); + /* parse (x) expression */ + QVariant parseBracket(); + /* parse x*y, x/y and x%y expressions */ + QVariant parseMultiply(); + /* parse x+y and x-y expressions */ + QVariant parseAdd(); + /* parse !x and (equivalent) not x expressions */ + QVariant parseNot(); + /* parse x==y, x<=y, x>=y, x<y and x>y expressions */ + QVariant parseComparison(); + /* parse x && y, (equivalent) x and y expressions */ + QVariant parseAnd(); + /* parse x || y and (equivalent) x or y expressions */ + QVariant parseOr(); + /* starting point of parsing - just call first function above */ + QVariant parse(); + + /* check if we still have next argument */ + bool validate(); + /* return next argument to parse or null if there is none */ + QString next() const; + /* set error position for future error reporting */ + void setError(int pos = -1); + /* compare various types of QVariant (strings, floats, ints */ + int compare(const QVariant v1, const QVariant v2) const; + /* return common type for binary operations */ + Type commonType(const QVariant v1, const QVariant v2) const; + + QValueList<QVariant> m_parts; + uint m_start; + bool m_error; + uint m_errorPosition; + +}; + +#endif + diff --git a/kommander/widget/function.cpp b/kommander/widget/function.cpp new file mode 100644 index 00000000..3bcd21cd --- /dev/null +++ b/kommander/widget/function.cpp @@ -0,0 +1,135 @@ +/*************************************************************************** + function.cpp - Functions for internal parser + ------------------- + copyright : (C) 2004 Michal Rudolf <mrudolf@kdewebdwev.org> + + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software{} you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation{} either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "function.h" + +using namespace Parse; + +Function::Function() : m_function(0), m_minArgs(0), m_maxArgs(0) +{ +} + +Function::Function(FunctionPointer fp, ValueType value, const TypeList& params, uint min, uint max) + : m_params(params) +{ + m_function = fp; + m_returnValue = value; + m_minArgs = min <= m_params.count() ? min : m_params.count(); + m_maxArgs = max >= m_params.count() ? max : m_params.count(); +} + +Function::Function(FunctionPointer fp, ValueType value, ValueType param1, uint min, uint max) +{ + m_function = fp; + m_returnValue = value; + m_params.append(param1); + m_minArgs = min <= 1 ? min : 1; + m_maxArgs = max >= 1 ? max : 1; +} + +Function::Function(FunctionPointer fp, ValueType value, ValueType param1, ValueType param2, uint min , + uint max) +{ + m_function = fp; + m_returnValue = value; + m_params.append(param1); + m_params.append(param2); + m_minArgs = min <= 2 ? min : 2; + m_maxArgs = max >= 2 ? max : 2; +} + +Function::Function(FunctionPointer fp, ValueType value, ValueType param1, ValueType param2, ValueType param3, + uint min, uint max) +{ + m_function = fp; + m_returnValue = value; + m_params.append(param1); + m_params.append(param2); + m_params.append(param3); + m_minArgs = min <= 3 ? min : 3; + m_maxArgs = max >= 3 ? max : 3; +} + +Function::Function(FunctionPointer fp, ValueType value, ValueType param1, ValueType param2, ValueType param3, + ValueType param4, uint min, uint max) +{ + m_function = fp; + m_returnValue = value; + m_params.append(param1); + m_params.append(param2); + m_params.append(param3); + m_params.append(param4); + m_minArgs = min <= 4 ? min : 4; + m_maxArgs = max >= 4 ? max : 4; +} + +Function::Function(FunctionPointer fp, ValueType value, ValueType param1, ValueType param2, ValueType param3, + ValueType param4, ValueType param5, uint min, uint max) +{ + m_function = fp; + m_returnValue = value; + m_params.append(param1); + m_params.append(param2); + m_params.append(param3); + m_params.append(param4); + m_params.append(param5); + m_minArgs = min <= 5 ? min : 5; + m_maxArgs = max >= 5 ? max : 5; +} + +bool Function::isVoid() const +{ + return returnValue() == ValueNone; +} + +ValueType Function::returnValue() const +{ + return m_returnValue; +} + +ValueType Function::argType(uint i) const +{ + if (i < m_params.count()) + return m_params[i]; + else if (i < m_maxArgs) + return m_params.last(); + else + return ValueNone; +} + +uint Function::minArgs() const +{ + return m_minArgs; +} + +uint Function::maxArgs() const +{ + return m_maxArgs; +} + +bool Function::isValid(const ParameterList& params) const +{ + return params.count() >= minArgs() && params.count() <= maxArgs(); +} + +ParseNode Function::execute(Parser* P, const ParameterList& params) const +{ + if (m_function) + return m_function(P, params); + else + return ParseNode(); +} + diff --git a/kommander/widget/function.h b/kommander/widget/function.h new file mode 100644 index 00000000..fbd8b99b --- /dev/null +++ b/kommander/widget/function.h @@ -0,0 +1,73 @@ +/*************************************************************************** + function.h - Functions for internal parser + ------------------- + copyright : (C) 2004 Michal Rudolf <mrudolf@kdewebdwev.org> + + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef _HAVE_FUNCTION_H_ +#define _HAVE_FUNCTION_H_ + +#include "parsenode.h" +#include <qvaluevector.h> + +class Parser; + +typedef QValueVector<ParseNode> ParameterList; +typedef QValueVector<Parse::ValueType> TypeList; +typedef ParseNode(*FunctionPointer)(Parser*, const ParameterList&); + +class Function +{ + public: + /* default constructor - empty function */ + Function(); + /* construct a function from parameterlist */ + Function(FunctionPointer fp, Parse::ValueType value, const TypeList& params, uint min = 99999, + uint max = 0); + /* construct a function from parameters */ + Function(FunctionPointer fp, Parse::ValueType value, Parse::ValueType param1, uint min = 99999, + uint max = 0); + Function(FunctionPointer fp, Parse::ValueType value, Parse::ValueType param1, Parse::ValueType param2, + uint min = 99999, uint max = 0); + Function(FunctionPointer fp, Parse::ValueType value, Parse::ValueType param1, Parse::ValueType param2, + Parse::ValueType param3, uint min = 99999, uint max = 0); + Function(FunctionPointer fp, Parse::ValueType value, Parse::ValueType param1, Parse::ValueType param2, + Parse::ValueType param3, Parse::ValueType param4, uint min = 99999, uint max = 0); + Function(FunctionPointer fp, Parse::ValueType value, Parse::ValueType param1, Parse::ValueType param2, + Parse::ValueType param3, Parse::ValueType param4, Parse::ValueType param5, + uint min = 99999, uint max = 0); + /* if function returns value */ + bool isVoid() const; + /* type of returned value */ + Parse::ValueType returnValue() const; + /* type of i-th argument */ + Parse::ValueType argType(uint i) const; + /* minimum number of arguments */ + uint minArgs() const; + /* maximum number of arguments */ + uint maxArgs() const; + /* check whether given list is appropriate for this function */ + bool isValid(const ParameterList& params) const; + /* execute */ + ParseNode execute(Parser* P, const ParameterList& params) const; + +private: + FunctionPointer m_function; + TypeList m_params; + Parse::ValueType m_returnValue; + uint m_minArgs; + uint m_maxArgs; +}; + +#endif + diff --git a/kommander/widget/functionlib.cpp b/kommander/widget/functionlib.cpp new file mode 100644 index 00000000..3389d523 --- /dev/null +++ b/kommander/widget/functionlib.cpp @@ -0,0 +1,1476 @@ +/*************************************************************************** + functionlib.cpp - Standard library of functions + ------------------- + copyright : (C) 2004-2006 Michal Rudolf <mrudolf@kdewebdwev.org> + + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "parserdata.h" +#include "parser.h" +#include "specials.h" +#include "specialinformation.h" +#include "myprocess.h" +#include "kommanderwidget.h" +#include "invokeclass.h" +#include "kommanderfactory.h" + +#include <iostream> +#include <stdlib.h> + +#include <qfile.h> +#include <qtextstream.h> +#include <qstringlist.h> +#include <qmetaobject.h> + +#include <kdebug.h> +#include <kmessagebox.h> +#include <dcopclient.h> +#include <kapplication.h> +#include <kcolordialog.h> +#include <kfiledialog.h> +#include <kglobal.h> +#include <kinputdialog.h> +#include <klocale.h> +#include <kpassdlg.h> + +using namespace Parse; + +/******************* String functions ********************************/ +static ParseNode f_stringLength(Parser*, const ParameterList& params) +{ + return params[0].toString().length(); +} + +static ParseNode f_stringContains(Parser*, const ParameterList& params) +{ + return params[0].toString().contains(params[1].toString()); +} + +static ParseNode f_stringCompare(Parser*, const ParameterList& params) +{ + int result = QString::compare(params[0].toString(),params[1].toString()); + if (result < 0) + { + result = -1; + } else + if (result > 0) + { + result = 1; + } + return result; +} + +static ParseNode f_stringFind(Parser*, const ParameterList& params) +{ + return params[0].toString().find(params[1].toString(), params.count() == 3 ? params[2].toInt() : 0); +} + +static ParseNode f_stringFindRev(Parser*, const ParameterList& params) +{ + return params[0].toString().findRev(params[1].toString(), + params.count() == 3 ? params[2].toInt() : params[0].toString().length()); +} + +static ParseNode f_stringCount(Parser*, const ParameterList& params) +{ + int c = 0; + int s = 0; + while (params[0].toString().find(params[1].toString(), s) > -1) + { + s = params[0].toString().find(params[1].toString(), s) + 1; + c++; + } + return c; +} + +static ParseNode f_stringLeft(Parser*, const ParameterList& params) +{ + return params[0].toString().left(params[1].toInt()); +} + +static ParseNode f_stringRight(Parser*, const ParameterList& params) +{ + return params[0].toString().right(params[1].toInt()); +} + +static ParseNode f_stringMid(Parser*, const ParameterList& params) +{ + return params[0].toString().mid(params[1].toInt(), params.count() == 3 ? params[2].toInt() : 0xffffffff); +} + +static ParseNode f_stringRemove(Parser*, const ParameterList& params) +{ + return params[0].toString().remove(params[1].toString()); +} + +static ParseNode f_stringReplace(Parser*, const ParameterList& params) +{ + return params[0].toString().replace(params[1].toString(), params[2].toString()); +} + +static ParseNode f_stringLower(Parser*, const ParameterList& params) +{ + return params[0].toString().lower(); +} + +static ParseNode f_stringUpper(Parser*, const ParameterList& params) +{ + return params[0].toString().upper(); +} + +static ParseNode f_stringIsEmpty(Parser*, const ParameterList& params) +{ + return params[0].toString().isEmpty(); +} + +static ParseNode f_stringSort(Parser*, const ParameterList& params) +{ + if (params.count() == 2 ) + { + QStringList tmplst = QStringList::split(params[1].toString(), params[0].toString()); + tmplst.sort(); + return tmplst.join(params[1].toString()); + } + else + { + QStringList tmplst = QStringList::split("\n", params[0].toString()); + tmplst.sort(); + return tmplst.join("\n"); + } +} +static ParseNode f_stringTrim(Parser*, const ParameterList& params) +{ + return params[0].toString().stripWhiteSpace(); +} + +static ParseNode f_stringPadLeft(Parser*, const ParameterList& params) +{ + if (params.count() == 2 ) + return params[0].toString().rightJustify(params[1].toInt(), ' ', false); + QString s = params[2].toString(); + QChar ch = s.at(0); + return params[0].toString().rightJustify(params[1].toInt(), ch, false); +} + +static ParseNode f_stringPadRight(Parser*, const ParameterList& params) +{ + if (params.count() == 2 ) + return params[0].toString().leftJustify(params[1].toInt(), ' ', false); + QString s = params[2].toString(); + QChar ch = s.at(0); + return params[0].toString().leftJustify(params[1].toInt(), ch, false); +} + +static ParseNode f_stringSection(Parser*, const ParameterList& params) +{ + return params[0].toString().section(params[1].toString(), params[2].toInt(), + params.count() == 4 ? params[3].toInt() : params[2].toInt()); +} + +static ParseNode f_stringArgs(Parser*, const ParameterList& params) +{ + if (params.count() == 2) + return params[0].toString().arg(params[1].toString()); + else if (params.count() == 3) + return params[0].toString().arg(params[1].toString()).arg(params[2].toString()); + else + return params[0].toString().arg(params[1].toString()).arg(params[2].toString()).arg(params[3].toString()); +} + +static ParseNode f_stringIsNumber(Parser*, const ParameterList& params) +{ + bool ok; + params[0].toString().toDouble(&ok); + return ok; +} + +static ParseNode f_stringToInt(Parser*, const ParameterList& params) +{ + return params[0].toString().toInt(); +} + +static ParseNode f_stringToDouble(Parser*, const ParameterList& params) +{ + return params[0].toString().toDouble(); +} + +static ParseNode f_return(Parser* p, const ParameterList& params) +{ + KommanderWidget * w = p->currentWidget(); + if (w) + w->setGlobal(w->widgetName() + "_RESULT", params[0].toString()); + return params[0]; +} + +static ParseNode f_stringRound(Parser*, const ParameterList& params) +{ + QString s; + s.sprintf("%."+params[1].toString()+"f", params[0].toDouble()); + return s; +} + +/******************* Debug function ********************************/ +static ParseNode f_debug(Parser*, const ParameterList& params) +{ + for (uint i=0; i<params.count(); i++) + std::cerr << params[i].toString(); + std::cerr << "\n"; + fflush(stderr); + return ParseNode(); +} + +static ParseNode f_echo(Parser*, const ParameterList& params) +{ + for (uint i=0; i<params.count(); i++) + std::cout << params[i].toString(); + fflush(stdout); + return ParseNode(); +} + + + +/******************* File function ********************************/ +static ParseNode f_fileRead(Parser*, const ParameterList& params) +{ + QFile file(params[0].toString()); + if (!file.exists() || !file.open(IO_ReadOnly)) + return ParseNode(""); + QTextStream text(&file); + return text.read(); +} + +static ParseNode f_fileWrite(Parser*, const ParameterList& params) +{ + QString fname = params[0].toString(); + if (fname.isEmpty()) + return 0; + QFile file(fname); + if (!file.open(IO_WriteOnly)) + return 0; + QTextStream text(&file); + for (uint i=1; i<params.count(); i++) + text << params[i].toString(); + return 1; +} + +static ParseNode f_fileAppend(Parser*, const ParameterList& params) +{ + QString fname = params[0].toString(); + if (fname.isEmpty()) + return 0; + QFile file(fname); + if (!file.open(IO_WriteOnly | IO_Append)) + return 0; + QTextStream text(&file); + for (uint i=1; i<params.count(); i++) + text << params[i].toString(); + return 1; +} + +static ParseNode f_fileExists(Parser*, const ParameterList& params) +{ + QFile file(params[0].toString()); + if (!file.exists()) + return 0; + else + return 1; +} + +static ParseNode f_executeSlot(Parser* parser, const ParameterList& params) +{ + ParameterList::ConstIterator it = params.begin(); + QString slotName = (*it).toString()+"("; + ++it; + QString widgetName = (*it).toString(); + KommanderWidget* widget = parser->currentWidget(); + if (!widget) + return ParseNode::error("unknown widget"); + widget = widget->widgetByName(widgetName); + if (!widget) + return ParseNode::error("unknown widget"); + QObject *object = widget->object(); + if (!object) + return ParseNode::error("unknown widget"); + QStrList slotSignatures = object->metaObject()->slotNames(true); + QStringList slotNames = QStringList::fromStrList(slotSignatures); + int slotNum = -1; + uint i = 0; + while (i < slotNames.count()) + { + if (slotNames[i].startsWith(slotName)) + { + slotNum = i; + break; + } + i++; + } + if (slotNum == -1) + return ParseNode::error("unknown function"); + QStringList args; + ++it; // skip widget + while (it != params.end()) + { + args += (*it).toString(); + ++it; + } + InvokeClass* inv = new InvokeClass(0); + inv->invokeSlot(object, slotSignatures.at(slotNum), args); + inv->deleteLater(); + + return ParseNode(); +} + + +/******************* DCOP function ********************************/ +static ParseNode f_dcopid(Parser*, const ParameterList& ) +{ + return QString(kapp->dcopClient()->appId()); +} + +static ParseNode f_pid(Parser*, const ParameterList& ) +{ + return QString::number(getpid()); +} + +static ParseNode f_parentPid(Parser*p, const ParameterList& ) +{ + return p->variable("_PARENTPID").toString().isEmpty() ? QString::number(getppid()) : p->variable("_PARENTPID"); +} + +static ParseNode f_internalDcop(Parser* parser, const ParameterList& params) +{ + SpecialFunction function = SpecialInformation::functionObject("DCOP", params[0].toString()); + int functionId = SpecialInformation::function(Group::DCOP, params[0].toString()); + if (functionId == -1) + return f_executeSlot(parser, params); + //return ParseNode::error("unknown function"); + else if ((uint)function.minArg() > params.count() - 1) + return ParseNode::error("too few parameters"); + else if ((uint)function.maxArg() < params.count() - 1) + return ParseNode::error("too many parameters"); + KommanderWidget* widget = parser->currentWidget(); + if (widget) + widget = widget->widgetByName(params[1].toString()); + if (!widget) + return ParseNode::error("unknown widget"); + QStringList args; + ParameterList::ConstIterator it = params.begin(); + ++it; // skip function + ++it; // skip widget + while (it != params.end()) + { + args += (*it).toString(); + ++it; + } + return widget->handleDCOP(functionId, args); +} + + +static ParseNode f_dcop(Parser*, const ParameterList& params) +{ + QCString appId = params[0].toString().latin1(); + QCString object = params[1].toString().latin1(); + QString function = params[2].toString().section('(', 0, 0); + QStringList items = QStringList::split(",", params[2].toString().section('(', 1, 1).section(')', 0, 0)); + QByteArray byteData; + QDataStream byteDataStream(byteData, IO_WriteOnly); + + if (items.count() != params.count() - 3) + { + qDebug("Wrong number of parameters"); + return ParseNode(); + } + int i = 3; + for (QStringList::Iterator it = items.begin(); it != items.end(); ++it) + { + *it = (*it).stripWhiteSpace(); + if (*it == "int") + byteDataStream << params[i++].toInt(); + else if (*it == "long") + byteDataStream << params[i++].toInt(); + else if (*it == "float") + byteDataStream << params[i++].toDouble(); + else if (*it == "double") + byteDataStream << params[i++].toDouble(); + else if (*it == "bool") + byteDataStream << (bool)params[i++].toInt(); + else if (*it == "QStringList") + if (params[i].toString().find('\n') != -1) + byteDataStream << QStringList::split("\n", params[i++].toString(), true); + else + byteDataStream << QStringList::split("\\n", params[i++].toString(), true); + else + byteDataStream << params[i++].toString(); + } + function.append(QString("(%1)").arg(items.join(","))); + QCString replyType, byteReply; + DCOPClient* cl = KApplication::dcopClient(); + if (!cl || !cl->call(appId, object, function.latin1(), + byteData, replyType, byteReply)) + { + qDebug("DCOP failure"); + return ParseNode(); + } + QDataStream byteReplyStream(byteReply, IO_ReadOnly); + if (replyType == "QString") + { + QString text; + byteReplyStream >> text; + return text; + } + else if(replyType == "int") + { + int i; + byteReplyStream >> i; + return i; + } + else if(replyType == "bool") + { + bool b; + byteReplyStream >> b; + return b; + } + else if (replyType == "QStringList") + { + QStringList text; + byteReplyStream >> text; + return text.join("\n"); + } + else if(replyType != "void") + { + qDebug("%s", QString("DCOP return type %1 is not yet implemented.").arg(replyType.data()).latin1()); + } + + return ParseNode(); +} + +static ParseNode f_createWidget(Parser* p, const ParameterList& params) +{ + QString widgetName = params[0].toString(); + QString widgetType = params[1].toString(); + QString parentName = params[2].toString(); + KommanderWidget *widget = p->currentWidget()->widgetByName(parentName); + if (!widget) + return ParseNode::error("unknown widget"); + QWidget *parent = dynamic_cast<QWidget*>(widget->object()); + QWidget *w = KommanderFactory::createWidget(widgetType, parent, widgetName.latin1()); + if (w) + w->adjustSize(); + return ParseNode(); +} + +static ParseNode f_widgetExists(Parser* p, const ParameterList& params) +{ + QString widgetName = params[0].toString(); + KommanderWidget *widget = p->currentWidget()->widgetByName(widgetName); + return (widget ? true : false); +} + + +static ParseNode f_connect(Parser* p, const ParameterList& params) +{ + QString sender = params[0].toString(); + QString signal = QString::number(QSIGNAL_CODE) + params[1].toString(); + QString receiver = params[2].toString(); + QString slot = QString::number(QSLOT_CODE) + params[3].toString(); + KommanderWidget *senderW = p->currentWidget()->widgetByName(sender); + if (!senderW) + return ParseNode::error("unknown widget"); + KommanderWidget *receiverW = p->currentWidget()->widgetByName(receiver); + if (!receiverW) + return ParseNode::error("unknown widget"); + dynamic_cast<QObject*>(senderW)->connect(dynamic_cast<QObject*>(senderW), signal.ascii(), dynamic_cast<QObject*>(receiverW), slot.ascii()); + return ParseNode(); +} + +static ParseNode f_disconnect(Parser* p, const ParameterList& params) +{ + QString sender = params[0].toString(); + QString signal = QString::number(QSIGNAL_CODE) + params[1].toString(); + QString receiver = params[2].toString(); + QString slot = QString::number(QSLOT_CODE) + params[3].toString(); + KommanderWidget *senderW = p->currentWidget()->widgetByName(sender); + if (!senderW) + return ParseNode::error("unknown widget"); + KommanderWidget *receiverW = p->currentWidget()->widgetByName(receiver); + if (!receiverW) + return ParseNode::error("unknown widget"); + dynamic_cast<QObject*>(senderW)->disconnect(dynamic_cast<QObject*>(senderW), signal.ascii(), dynamic_cast<QObject*>(receiverW), slot.ascii()); + return ParseNode(); +} + + +static ParseNode f_exec(Parser* P, const ParameterList& params) +{ + MyProcess proc(P->currentWidget()); + QString text; +// qDebug("Trying %s", params[0].toString().latin1()); + if (params.count() > 1) + text = proc.run(params[0].toString().local8Bit(), params[1].toString()); + else + text = proc.run(params[0].toString().local8Bit()); + return text; +} + +static ParseNode f_execBackground(Parser* P, const ParameterList& params) +{ + MyProcess proc(P->currentWidget()); + proc.setBlocking(false); + QString text; + qDebug("Trying %s", params[0].toString().latin1()); + if (params.count() > 1) + text = proc.run(params[0].toString().local8Bit(), params[1].toString()); + else + text = proc.run(params[0].toString().local8Bit()); + return text; +} + +static ParseNode f_dialog(Parser* P, const ParameterList& params) +{ + QString a_dialog = params[0].toString().local8Bit(); + QString a_params = params[1].toString().local8Bit(); + + QString pFileName = P->currentWidget()->global("_KDDIR") + QString("/") + a_dialog; + QFileInfo pDialogFile(pFileName); + if (!pDialogFile.exists()) + { + pFileName = a_dialog; + pDialogFile.setFile(pFileName); + if (!pDialogFile.exists()) + return QString(); + } + QString cmd = QString("kmdr-executor %1 %2 _PARENTPID=%3 _PARENTDCOPID=kmdr-executor-%4") + .arg(pFileName).arg(a_params).arg(getpid()).arg(getpid()); + + MyProcess proc(P->currentWidget()); + QString text; + text = proc.run(cmd); + + return text; +} + +static ParseNode f_i18n(Parser*, const ParameterList& params) +{ + return KGlobal::locale()->translate(params[0].toString()); +} + +static ParseNode f_env(Parser*, const ParameterList& params) +{ + return QString(getenv(params[0].toString().latin1())); +} + +/******************* Array functions ********************************/ +static ParseNode f_arrayClear(Parser* P, const ParameterList& params) +{ + P->unsetArray(params[0].toString()); + return ParseNode(); +} + +static ParseNode f_arrayCount(Parser* P, const ParameterList& params) +{ + if (P->isArray(params[0].toString())) + return (uint)(P->array(params[0].toString()).count()); + else + return (uint)0; +} + +static ParseNode f_arrayKeys(Parser* P, const ParameterList& params) +{ + if (!P->isArray(params[0].toString())) + return ParseNode(); + return QStringList(P->array(params[0].toString()).keys()).join("\n"); +} + +static ParseNode f_arrayValues(Parser* P, const ParameterList& params) +{ + if (!P->isArray(params[0].toString())) + return ParseNode(); + QValueList<ParseNode> values = P->array(params[0].toString()).values(); + QString array; + for (QValueList<ParseNode>::ConstIterator it = values.begin(); it != values.end(); ++it ) + array += (*it).toString() + '\n'; + return array; +} + +static ParseNode f_arrayRemove(Parser* P, const ParameterList& params) +{ + if (P->isArray(params[0].toString())) + P->unsetArray(params[0].toString(), params[1].toString()); + return ParseNode(); +} + +static ParseNode f_arrayToString(Parser* P, const ParameterList& params) +{ + QString name = params[0].toString(); + if (!P->isArray(name)) + return ParseNode(); + QString array; + QStringList keys = P->array(name).keys(); + QValueList<ParseNode> values = P->array(name).values(); + + QStringList::Iterator it = keys.begin(); + QValueList<ParseNode>::Iterator itval = values.begin(); + while (*it) + { + array += QString("%1\t%2\n").arg(*it).arg((*itval).toString()); + ++it; + ++itval; + } + return array; +} + +static ParseNode f_arrayFromString(Parser* P, const ParameterList& params) +{ + QString name = params[0].toString(); + QStringList lines = QStringList::split("\n", params[1].toString()); + for (QStringList::Iterator it = lines.begin(); it != lines.end(); ++it ) + { + QString key = (*it).section('\t', 0, 0).stripWhiteSpace(); + if (!key.isEmpty()) + P->setArray(name, key, (*it).section('\t', 1)); + } + return ParseNode(); +} + + +static ParseNode f_arrayIndexedFromString(Parser* P, const ParameterList& params) +{ + QString name = params[0].toString(); + QStringList lines; + if (params.count() == 2) + lines = QStringList::split('\t', params[1].toString(), true); + else + lines = QStringList::split(params[2].toString(), params[1].toString(), true); + int i = 0; + for (QStringList::Iterator it = lines.begin(); it != lines.end(); ++it ) + { + P->setArray(name, QString::number(i), (*it)); + i++; + } + return ParseNode(); +} + +static ParseNode f_arrayIndexedToString(Parser* P, const ParameterList& params) +{ + QString name = params[0].toString(); + if (!P->isArray(name)) + return ParseNode(); + QString separator = "\t"; + if (params.count() == 2) + separator = params[1].toString(); + QString array; + int count = P->array(name).keys().count(); + QValueList<ParseNode> values = P->array(name).values(); + + for (int i = 0; i < count; i++) + { + if (i != 0) + array.append(separator); + array.append(P->arrayValue(name, QString::number(i)).toString()); + } + return array; +} + +static ParseNode f_arrayIndexedRemoveElements(Parser* P, const ParameterList& params) +{ + QString name = params[0].toString(); + if (!P->isArray(name)) + return ParseNode(); + int key = params[1].toInt(); + int num = 0; + if (params.count() == 3) + num = params[2].toInt() - 1; + if (num < 0) + num = 0; + QString array; + QStringList keys = P->array(name).keys(); + int count = keys.count(); + if (key + num > count - 1 || key < 0) + return ParseNode(); //out of index range + for (int i = 0; i < count; i++) + { + if (keys.contains(QString::number(i)) != 1) + return ParseNode(); //array is not indexed + } + for (int i = key; i <= key + num; i++) + { + P->unsetArray(name, QString::number(i)); + } + int j = key; + for (int i = key + num + 1; i < count; i++) + { + P->setArray(name, QString::number(j), P->arrayValue(name, QString::number(i))); + j++; + } + for (int i = 1; i <= num + 1; i++) + { + P->unsetArray(name, QString::number(count - i)); + } + return ParseNode(); +} + + +static ParseNode f_arrayIndexedInsertElements(Parser* P, const ParameterList& params) +{ + QString name = params[0].toString(); + if (!P->isArray(name)) + return ParseNode(); + int key = params[1].toInt(); + QStringList keys = P->array(name).keys(); + int count = keys.count(); + if (key > count || key < 0) + return ParseNode(); //out of index range + QString separator = "\t"; + if (params.count() == 4) + separator = params[3].toString(); + QStringList elements = QStringList::split(separator, params[2].toString(), true); + int num = elements.count(); + for (int i = count - 1; i >= key; i--) + { + P->setArray(name, QString::number(i + num), P->arrayValue(name, QString::number(i))); + } + int i = key; + for (QStringList::Iterator it = elements.begin(); it != elements.end(); ++it ) + { + P->setArray(name, QString::number(i), (*it)); + i++; + } + return ParseNode(); +} + +static ParseNode f_arrayFlipCopy(Parser* P, const ParameterList& params) +{ + QString name = params[0].toString(); + if (!P->isArray(name)) + return ParseNode(); + QString arr = params[1].toString(); + const QMap<QString, ParseNode> A = P->array(name); + for (QMapConstIterator<QString, ParseNode> It = A.begin(); It != A.end(); ++It ) + { + P->setArray(arr, (*It).toString(), It.key() ); + } + return ParseNode(); +} + +/*********** matrix (2D array) functions ********/ +static ParseNode f_matrixClear(Parser* P, const ParameterList& params) +{ + P->unsetMatrix(params[0].toString()); + return ParseNode(); +} + +static ParseNode f_matrixToString(Parser* P, const ParameterList& params) +{ + QString name = params[0].toString(); + if (!P->isMatrix(name)) + return ParseNode(); + QString matrix; + QString colhead; + const QMap<QString, QMap<QString, ParseNode> > A = P->matrix(name); + int r = 0; + int c = 0; + int frow = 0; + int fcol = 0; + if (params.count() >= 1) + frow = params[1].toInt(); //row headings + if (params.count() >= 2) + fcol = params[2].toInt(); //col headings + QString tmp; + typedef QMap<int, QString> col_map; + col_map col_head; + for (QMapConstIterator<QString, QMap<QString, ParseNode> > It1 = A.begin(); It1 != A.end(); ++It1 ) + { + const QMap<QString, ParseNode> B = It1.data(); + for (QMapConstIterator<QString, ParseNode> It2 = B.begin(); It2 != B.end(); ++It2 ) + { + bool colfound = false; + for (QMapConstIterator<int, QString> It3 = col_head.begin(); It3 != col_head.end(); ++It3 ) + { + if (It2.key() == (*It3)) + { + colfound = true; + break; + } + } + if (!colfound) + { + col_head[c] = It2.key(); + if (c > 0) + colhead.append("\t"); + colhead.append(It2.key()); + c++; + } + } + } + if (fcol && frow) + colhead.prepend("\t"); + for (QMapConstIterator<QString, QMap<QString, ParseNode> > It1 = A.begin(); It1 != A.end(); ++It1) + { + if (r > 0 ) + matrix.append("\n"); + if (frow) //add row keys + { + tmp = It1.key(); + matrix.append(tmp+"\t"); + } + c = 0; + const QMap<int, QString> B = col_head; + for (QMapConstIterator<int, QString> It2 = B.begin(); It2 != B.end(); ++It2 ) + { + if (c > 0) + matrix.append("\t"); + matrix.append(P->matrixValue(name, It1.key(), (*It2) ).toString()); + c++; + } + r++; + } + if (fcol) + matrix.prepend(colhead+"\n"); + return matrix; +} + +static ParseNode f_matrixFromString(Parser* P, const ParameterList& params) +{ + QString name = params[0].toString(); + QStringList rows = QStringList::split("\n", params[1].toString()); + int r = 0; + int frow = 0; + int fcol = 0; + QString rkey; + QMap<int, QString> colhead; + if (params.count() > 1) + frow = params[2].toInt(); //row headings + if (params.count() > 2) + fcol = params[3].toInt(); //col headings + for (QStringList::Iterator itr = rows.begin(); itr != rows.end(); ++itr ) + { + int c = 0; + QString ckey; + QStringList cols = QStringList::split("\t", (*itr), true); + for (QStringList::Iterator itc = cols.begin(); itc != cols.end(); ++itc ) + { + QString val = (*itc).stripWhiteSpace(); + if (frow) + { + if (c == 0 && !val.isEmpty()) + { + rkey = val; + } + } + else + rkey = QString::number(r); + if (fcol && r == 0 && c >= 0) + { + if (!val.isEmpty()) + colhead[c] = val; + else + colhead[c] = QString::number(c); + } + if (!val.isEmpty() && !(c == 0 && frow) && !(r == 0 && fcol)) + { + if (fcol) + ckey = colhead[c]; + else + ckey = QString::number(c); + P->setMatrix(name, rkey, ckey, val); + } + c++; + } + r++; + } + return ParseNode(); +} + +static ParseNode f_matrixRows(Parser* P, const ParameterList& params) +{ + if (P->isMatrix(params[0].toString())) + return (uint)(P->matrix(params[0].toString()).count()); + else + return (uint)0; + +} + +static ParseNode f_matrixRowKeys(Parser* P, const ParameterList& params) +{ + QString name = params[0].toString(); + if (!P->isMatrix(name)) + return ParseNode(); + QString matrix; + QString tmp; + QString separator = "\t"; + if (params.count() == 2) + separator = params[1].toString(); + const QMap<QString, QMap<QString, ParseNode> > A = P->matrix(name); + int r = 0; + for (QMapConstIterator<QString, QMap<QString, ParseNode> > It1 = A.begin(); It1 != A.end(); ++It1) + { + if (r > 0 ) + matrix.append(separator); + tmp = It1.key(); + matrix.append(tmp); + r++; + } + return matrix; +} + +static ParseNode f_matrixFindRow(Parser* P, const ParameterList& params) +{ + QString name = params[0].toString(); + if (!P->isMatrix(name)) + return ParseNode(); + QString col = params[1].toString(); + QString val = params[2].toString(); + QString tmp; + int i = 0; + int find; + if (params.count() == 4) + find = params[3].toInt(); + else + find = 0; + const QMap<QString, QMap<QString, ParseNode> > A = P->matrix(name); + for (QMapConstIterator<QString, QMap<QString, ParseNode> > It = A.begin(); It != A.end(); ++It) + { + if (val == P->matrixValue(name, It.key(), col).toString()) + { + if (find == i) + return It.key(); + i++; + } + } + return ParseNode(); +} + +static ParseNode f_matrixCols(Parser* P, const ParameterList& params) +{ + QString name = params[0].toString(); + if (P->isMatrix(name)) + { + typedef QMap<int, QString> col_map; + col_map col_head; + uint cols = 0; + const QMap<QString, QMap<QString, ParseNode> > A = P->matrix(name); + for (QMapConstIterator<QString, QMap<QString, ParseNode> > It = A.begin(); It != A.end(); ++It) + { + const QMap<QString, ParseNode> B = It.data(); + for (QMapConstIterator<QString, ParseNode> It2 = B.begin(); It2 != B.end(); ++It2 ) + { + bool colfound = false; + for (QMapConstIterator<int, QString> It3 = col_head.begin(); It3 != col_head.end(); ++It3 ) + { + if (It2.key() == (*It3)) + { + colfound = true; + break; + } + } + if (!colfound) + { + col_head[cols] = It2.key(); + cols++; + } + } + } + return (uint)cols; + } + else + return (uint)0; +} + +static ParseNode f_matrixColumnKeys(Parser* P, const ParameterList& params) +{ + QString name = params[0].toString(); + if (!P->isMatrix(name)) + return ParseNode(); + QString matrix; + QString tmp; + QString separator = "\t"; + if (params.count() == 2) + separator = params[1].toString(); + const QMap<QString, QMap<QString, ParseNode> > A = P->matrix(name); + QStringList colnames; + int c =0; + + typedef QMap<int, QString> col_map; + col_map col_head; + for (QMapConstIterator<QString, QMap<QString, ParseNode> > It1 = A.begin(); It1 != A.end(); ++It1 ) + { + const QMap<QString, ParseNode> B = It1.data(); + for (QMapConstIterator<QString, ParseNode> It2 = B.begin(); It2 != B.end(); ++It2 ) + { + bool colfound = false; + for (QMapConstIterator<int, QString> It3 = col_head.begin(); It3 != col_head.end(); ++It3 ) + { + if (It2.key() == (*It3)) + { + colfound = true; + break; + } + } + if (!colfound) + { + col_head[c] = It2.key(); + if (c > 0) + matrix.append(separator); + matrix.append(It2.key()); + c++; + } + } + } + return matrix; +} + +static ParseNode f_matrixRowToArray(Parser* P, const ParameterList& params) +{ + QString mtr = params[0].toString(); + if (P->isMatrix(mtr)) + { + const QMap<QString, QMap<QString, ParseNode> > A = P->matrix(mtr); + int i = 0; + int rclear = 1; + int ridx = 1; + if (params.count() > 2) + rclear = params[3].toInt(); + if (params.count() > 3) + ridx = params[4].toInt(); + QString arr = params[2].toString(); + if (rclear) + P->unsetArray(arr); + for (QMapConstIterator<QString, QMap<QString, ParseNode> > It1 = A.begin(); It1 != A.end(); ++It1) + { + if (It1.key() == params[1].toString() ) + { + const QMap<QString, ParseNode> B = It1.data(); + for (QMapConstIterator<QString, ParseNode> It2 = B.begin(); It2 != B.end(); ++It2 ) + { + if (ridx) + P->setArray(arr, QString::number(i), (*It2)); + else + P->setArray(arr, It2.key(), (*It2)); + i++; + } + } + } + } + return ParseNode(); +} + +static ParseNode f_matrixColumnToArray(Parser* P, const ParameterList& params) +{ + QString name = params[0].toString(); + if (P->isMatrix(name)) + { + const QMap<QString, QMap<QString, ParseNode> > A = P->matrix(name); + for (QMapConstIterator<QString, QMap<QString, ParseNode> > It1 = A.begin(); It1 != A.end(); ++It1) + { + const QMap<QString, ParseNode> B = It1.data(); + for (QMapConstIterator<QString, ParseNode> It2 = B.begin(); It2 != B.end(); ++It2 ) + { + if (It2.key() == params[1].toString() ) + { + P->setArray(params[2].toString(), It1.key(), (*It2)); + } + } + } + } + return ParseNode(); +} + +static ParseNode f_matrixColumnToIndexedArray(Parser* P, const ParameterList& params) +{ + QString name = params[0].toString(); + if (P->isMatrix(name)) + { + const QMap<QString, QMap<QString, ParseNode> > A = P->matrix(name); + int i = 0; + for (QMapConstIterator<QString, QMap<QString, ParseNode> > It1 = A.begin(); It1 != A.end(); ++It1) + { + const QMap<QString, ParseNode> B = It1.data(); + for (QMapConstIterator<QString, ParseNode> It2 = B.begin(); It2 != B.end(); ++It2 ) + { + if (It2.key() == params[1].toString() ) + { + P->setArray(params[2].toString(), QString::number(i), (*It2)); + i++; + } + } + } + } + return ParseNode(); +} + +static ParseNode f_matrixAddRow(Parser* P, const ParameterList& params) +{ + QString name = params[0].toString(); + QString rowkey = params[1].toString(); + QStringList rows = QStringList::split("\n", params[2].toString()); + for (QStringList::Iterator itr = rows.begin(); itr != rows.end(); ++itr ) + { + QStringList cols = QStringList::split("\t", (*itr)); + if (cols.count() != 2 ) + continue; + QStringList::Iterator itc = cols.begin(); + QString rkey = (*itc).stripWhiteSpace(); + ++itc; + QString rval = (*itc).stripWhiteSpace(); + if (!rkey.isEmpty() && !rval.isEmpty()) + P->setMatrix(name, rowkey, rkey, rval); + } + return ParseNode(); +} + +static ParseNode f_matrixRemoveRow(Parser* P, const ParameterList& params) +{ + QString name = params[0].toString(); + if (!P->isMatrix(name)) + return ParseNode(); + QString rowkey = params[1].toString(); + int found = 0; + const QMap<QString, QMap<QString, ParseNode> > A = P->matrix(name); + if (A.contains(rowkey)) + { + P->unsetMatrix(name, rowkey); + found = 1; + } + return QString::number(found); +} +/* +static ParseNode f_matrixAddColumn(Parser* P, const ParameterList& params) +{ +} +*/ +static ParseNode f_matrixRemoveColumn(Parser* P, const ParameterList& params) +{ + QString name = params[0].toString(); + QString colkey = params[1].toString(); + if (!P->isMatrix(name)) + return ParseNode(); + int found = 0; + const QMap<QString, QMap<QString, ParseNode> > A = P->matrix(name); + for (QMapConstIterator<QString, QMap<QString, ParseNode> > It = A.begin(); It != A.end(); ++It) + { + if (A[It.key()].contains(colkey)) + found = 1; + P->unsetMatrix(name, It.key(), colkey); + } + return QString::number(found); +} +/* +static ParseNode f_matrixIndexedCopy(Parser* P, const ParameterList& params) +{ +} +*/ +/********** input functions *********************/ +static ParseNode f_inputColor(Parser*, const ParameterList& params) +{ + QColor color; + if (params.count()) + color.setNamedColor(params[0].toString()); + KColorDialog::getColor(color); + return color.name(); +} + +static ParseNode f_inputText(Parser*, const ParameterList& params) +{ + QString value; + if (params.count() > 2) + value = params[2].toString(); + return KInputDialog::getText(params[0].toString(), params[1].toString(), value); +} + +static ParseNode f_inputPassword(Parser*, const ParameterList& params) +{ + QCString value; + if (params.count() > 1) + value = params[1].toString().local8Bit(); + KPasswordDialog::getPassword(value, params[0].toString()); + return QString::fromLocal8Bit(value); +} + +static ParseNode f_inputValue(Parser*, const ParameterList& params) +{ + return KInputDialog::getInteger(params[0].toString(), params[1].toString(), + params[2].toInt(), params[3].toInt(), params[4].toInt(), + params.count() > 5 ? params[5].toInt() : 1, + (bool*)0); +} + +static ParseNode f_inputValueDouble(Parser*, const ParameterList& params) +{ + return KInputDialog::getDouble(params[0].toString(), params[1].toString(), + params[2].toDouble(), params[3].toDouble(), params[4].toDouble(), + params.count() > 5 ? params[5].toDouble() : 0.1); +} + +static ParseNode f_inputOpenFile(Parser*, const ParameterList& params) +{ + QString startdir, filter, caption; + if (params.count() > 0) + startdir = params[0].toString(); + if (params.count() > 1) + filter = params[1].toString(); + if (params.count() > 2) + caption = params[2].toString(); + return KFileDialog::getOpenFileName(startdir, filter, 0, caption); +} + +static ParseNode f_inputOpenFiles(Parser*, const ParameterList& params) +{ + QString startdir, filter, caption; + if (params.count() > 0) + startdir = params[0].toString(); + if (params.count() > 1) + filter = params[1].toString(); + if (params.count() > 2) + caption = params[2].toString(); + return KFileDialog::getOpenFileNames(startdir, filter, 0, caption).join("\n"); +} + +static ParseNode f_inputSaveFile(Parser*, const ParameterList& params) +{ + QString startdir, filter, caption; + if (params.count() > 0) + startdir = params[0].toString(); + if (params.count() > 1) + filter = params[1].toString(); + if (params.count() > 2) + caption = params[2].toString(); + return KFileDialog::getSaveFileName(startdir, filter, 0, caption); +} + +static ParseNode f_inputDirectory(Parser*, const ParameterList& params) +{ + QString startdir, caption; + if (params.count() > 0) + startdir = params[0].toString(); + if (params.count() > 1) + caption = params[1].toString(); + return KFileDialog::getExistingDirectory(startdir, 0, caption); +} + +static ParseNode f_message_info(Parser*, const ParameterList& params) +{ + QString text, caption; + if (params.count() > 0) + text = params[0].toString(); + if (params.count() > 1) + caption = params[1].toString(); + KMessageBox::information(0, text, caption); + return 1; +} + +static ParseNode f_message_error(Parser*, const ParameterList& params) +{ + QString text, caption; + if (params.count() > 0) + text = params[0].toString(); + if (params.count() > 1) + caption = params[1].toString(); + KMessageBox::error(0, text, caption); + return 1; +} + +static ParseNode f_message_warning(Parser*, const ParameterList& params) +{ + int result; + QString text, caption, button1, button2, button3; + if (params.count() > 0) + text = params[0].toString(); + if (params.count() > 1) + caption = params[1].toString(); + if (params.count() > 2) + button1 = params[2].toString(); + if (params.count() > 3) + button2 = params[3].toString(); + if (params.count() > 4) + button3 = params[4].toString(); + if (button1.isNull()) + result = KMessageBox::warningYesNo(0, text, caption); + else if (button3.isNull()) + result = KMessageBox::warningYesNo(0, text, caption, button1, button2); + else + result = KMessageBox::warningYesNoCancel(0, text, caption, button1, button2, button3); + switch(result) + { + case KMessageBox::Yes: + return 1; + case KMessageBox::No: + return 2; + case KMessageBox::Cancel: + return 3; + default: + return 0; + } +} + +static ParseNode f_message_question(Parser*, const ParameterList& params) +{ + int result; + QString text, caption, button1, button2, button3; + if (params.count() > 0) + text = params[0].toString(); + if (params.count() > 1) + caption = params[1].toString(); + if (params.count() > 2) + button1 = params[2].toString(); + if (params.count() > 3) + button2 = params[3].toString(); + if (params.count() > 4) + button3 = params[4].toString(); + if (button1.isNull()) + result = KMessageBox::questionYesNo(0, text, caption); + else if (button3.isNull()) + result = KMessageBox::questionYesNo(0, text, caption, button1, button2); + else + result = KMessageBox::questionYesNoCancel(0, text, caption, button1, button2, button3); + switch(result) + { + case KMessageBox::Yes: + return 1; + case KMessageBox::No: + return 2; + case KMessageBox::Cancel: + return 3; + default: + return 0; + } +} + +static ParseNode f_read_setting(Parser* parser, const ParameterList& params) +{ + QString def; + if (params.count() > 1) + def = params[1].toString(); + if (parser->currentWidget()) + { + QString fname = parser->currentWidget()->fileName(); + if (fname.isEmpty()) + return ParseNode(); + KConfig cfg("kommanderrc", true); + cfg.setGroup(fname); + return cfg.readEntry(params[0].toString(), def); + } + return ParseNode(); +} + +static ParseNode f_write_setting(Parser* parser, const ParameterList& params) +{ + if (parser->currentWidget()) + { + QString fname = parser->currentWidget()->fileName(); + if (fname.isEmpty()) + return ParseNode(); + KConfig cfg("kommanderrc", false); + cfg.setGroup(fname); + cfg.writeEntry(params[0].toString(), params[1].toString()); + } + return ParseNode(); +} + + + + +void ParserData::registerStandardFunctions() +{ + registerFunction("str_length", Function(&f_stringLength, ValueInt, ValueString)); + registerFunction("str_contains", Function(&f_stringContains, ValueInt, ValueString, ValueString)); + registerFunction("str_compare", Function(&f_stringCompare, ValueInt, ValueString, ValueString)); + registerFunction("str_find", Function(&f_stringFind, ValueInt, ValueString, ValueString, ValueInt, 2)); + registerFunction("str_findrev", Function(&f_stringFindRev, ValueInt, ValueString, ValueString, ValueInt, 2)); + registerFunction("str_left", Function(&f_stringLeft, ValueString, ValueString, ValueInt)); + registerFunction("str_count", Function(&f_stringCount, ValueInt, ValueString, ValueString)); + registerFunction("str_right", Function(&f_stringRight, ValueString, ValueString, ValueInt)); + registerFunction("str_mid", Function(&f_stringMid, ValueString, ValueString, ValueInt, ValueInt, 2)); + registerFunction("str_remove", Function(&f_stringRemove, ValueString, ValueString, ValueString)); + registerFunction("str_replace", Function(&f_stringReplace, ValueString, ValueString, ValueString, ValueString)); + registerFunction("str_lower", Function(&f_stringLower, ValueString, ValueString)); + registerFunction("str_upper", Function(&f_stringUpper, ValueString, ValueString)); + registerFunction("str_section", Function(&f_stringSection, ValueString, ValueString, ValueString, ValueInt, ValueInt, 3)); + registerFunction("str_args", Function(&f_stringArgs, ValueString, ValueString, 2, 4)); + registerFunction("str_isnumber", Function(&f_stringIsNumber, ValueInt, ValueString)); + registerFunction("str_isempty", Function(&f_stringIsEmpty, ValueInt, ValueString)); + registerFunction("str_toint", Function(&f_stringToInt, ValueString, ValueInt, 1)); + registerFunction("str_todouble", Function(&f_stringToDouble, ValueString, ValueDouble, 1)); + registerFunction("str_round", Function(&f_stringRound, ValueInt, ValueDouble, ValueInt, 2)); + registerFunction("str_sort", Function(&f_stringSort, ValueString, ValueString, ValueString, 1, 2)); + registerFunction("str_trim", Function(&f_stringTrim, ValueString, ValueString, 1)); + registerFunction("str_padLeft", Function(&f_stringPadLeft, ValueString, ValueInt, ValueString, ValueString, 1, 2)); + registerFunction("str_padRight", Function(&f_stringPadRight, ValueString, ValueInt, ValueString, ValueString, 1, 2)); + registerFunction("return", Function(&f_return, ValueNone, ValueString, 1, 1)); + registerFunction("debug", Function(&f_debug, ValueNone, ValueString, 1, 100)); + registerFunction("echo", Function(&f_echo, ValueNone, ValueString, 1, 100)); + registerFunction("file_read", Function(&f_fileRead, ValueString, ValueString, 1, 1)); + registerFunction("file_write", Function(&f_fileWrite, ValueInt, ValueString, ValueString, 2, 100)); + registerFunction("file_append", Function(&f_fileAppend, ValueInt, ValueString, ValueString, 2, 100)); + registerFunction("file_exists", Function(&f_fileExists, ValueString, ValueString, 1, 1)); + registerFunction("internalDcop", Function(&f_internalDcop, ValueString, ValueString, ValueString, 2, 100)); + registerFunction("executeSlot", Function(&f_executeSlot, ValueString, ValueString, ValueString, 2, 100)); + registerFunction("createWidget", Function(&f_createWidget, ValueString, ValueString, ValueString, 3, 100)); + registerFunction("widgetExists", Function(&f_widgetExists, ValueString, 1)); + registerFunction("connect", Function(&f_connect, ValueString, ValueString, ValueString, ValueString, 4, 4)); + registerFunction("disconnect", Function(&f_disconnect, ValueString, ValueString, ValueString, ValueString, 4, 4)); + registerFunction("dcop", Function(&f_dcop, ValueString, ValueString, ValueString, 3, 100)); + registerFunction("dcopid", Function(&f_dcopid, ValueString, ValueNone, 0, 0)); + registerFunction("pid", Function(&f_pid, ValueString, ValueNone, 0, 0)); + registerFunction("parentPid", Function(&f_parentPid, ValueString, ValueNone, 0, 0)); + registerFunction("dialog", Function(&f_dialog, ValueString, ValueString, ValueString, 1, 2)); + registerFunction("exec", Function(&f_exec, ValueString, ValueString, ValueString, 1, 2)); + registerFunction("execBackground", Function(&f_execBackground, ValueString, ValueString, ValueString, 1, 2)); + registerFunction("i18n", Function(&f_i18n, ValueString, ValueString)); + registerFunction("env", Function(&f_env, ValueString, ValueString)); + registerFunction("readSetting", Function(&f_read_setting, ValueString, ValueString, ValueString, 1)); + registerFunction("writeSetting", Function(&f_write_setting, ValueNone, ValueString, ValueString)); + registerFunction("array_clear", Function(&f_arrayClear, ValueNone, ValueString)); + registerFunction("array_count", Function(&f_arrayCount, ValueInt, ValueString)); + registerFunction("array_keys", Function(&f_arrayKeys, ValueString, ValueString)); + registerFunction("array_values", Function(&f_arrayValues, ValueString, ValueString)); + registerFunction("array_tostring", Function(&f_arrayToString, ValueString, ValueString)); + registerFunction("array_fromstring", Function(&f_arrayFromString, ValueNone, ValueString, ValueString)); + registerFunction("array_indexedfromstring", Function(&f_arrayIndexedFromString, ValueNone, ValueString, ValueString, ValueString, 2, 3)); + registerFunction("array_indexedtostring", Function(&f_arrayIndexedToString, ValueNone, ValueString, ValueString, 1, 2)); + registerFunction("array_indexedRemoveElements", Function(&f_arrayIndexedRemoveElements, ValueNone, ValueString, ValueInt, ValueInt, 2 , 3)); + registerFunction("array_indexedInsertElements", Function(&f_arrayIndexedInsertElements, ValueNone, ValueString, ValueInt, ValueString, ValueString, 3, 4)); + registerFunction("array_remove", Function(&f_arrayRemove, ValueNone, ValueString, ValueString)); + registerFunction("matrix_fromString", Function(&f_matrixFromString, ValueNone, ValueString, ValueString, ValueInt, ValueInt, 2, 4)); + registerFunction("matrix_toString", Function(&f_matrixToString, ValueNone, ValueString, ValueInt, ValueInt, 1, 3)); + registerFunction("matrix_clear", Function(&f_matrixClear, ValueNone, ValueString)); + registerFunction("matrix_rows", Function(&f_matrixRows, ValueInt, ValueString)); + registerFunction("matrix_columns", Function(&f_matrixCols, ValueInt, ValueString)); + registerFunction("matrix_rowToArray", Function(&f_matrixRowToArray, ValueNone, ValueString, ValueInt, ValueString, ValueInt, ValueInt, 3, 5)); + registerFunction("matrix_columnToArray", Function(&f_matrixColumnToArray, ValueNone, ValueString, ValueString, ValueString, 3, 3)); + registerFunction("matrix_columnToIndexedArray", Function(&f_matrixColumnToIndexedArray, ValueNone, ValueString, ValueString, ValueString, 3, 3)); + registerFunction("array_flipCopy", Function(&f_arrayFlipCopy, ValueNone, ValueString, ValueString, 2, 2)); + registerFunction("matrix_rowKeys", Function(&f_matrixRowKeys, ValueString, ValueString, ValueString, 1, 2)); + registerFunction("matrix_columnKeys", Function(&f_matrixColumnKeys, ValueString, ValueString, ValueString, 1, 2)); + registerFunction("matrix_addRow", Function(&f_matrixAddRow, ValueNone, ValueString, ValueString, ValueString, 3, 3)); + registerFunction("matrix_removeRow", Function(&f_matrixRemoveRow, ValueInt, ValueString, ValueString, 2, 2)); + registerFunction("matrix_removeColumn", Function(&f_matrixRemoveColumn, ValueInt, ValueString, ValueString, 2, 2)); + registerFunction("matrix_findRow", Function(&f_matrixFindRow, ValueString, ValueString, ValueString, ValueString, 3, 4)); + + registerFunction("input_color", Function(&f_inputColor, ValueString, ValueString, 0)); + registerFunction("input_text", Function(&f_inputText, ValueString, ValueString, ValueString, ValueString, 2)); + registerFunction("input_password", Function(&f_inputPassword, ValueString, ValueString, ValueString, 1)); + registerFunction("input_value", Function(&f_inputValue, ValueInt, ValueString, ValueString, ValueInt, ValueInt, + ValueInt, ValueInt, 6)); + registerFunction("input_double", Function(&f_inputValueDouble, ValueDouble, ValueString, ValueString, ValueDouble, ValueDouble, + ValueDouble, ValueDouble, 6)); + registerFunction("input_openfile", Function(&f_inputOpenFile, ValueString, ValueString, ValueString, ValueString, 0)); + registerFunction("input_openfiles", Function(&f_inputOpenFiles, ValueString, ValueString, ValueString, ValueString, 0)); + registerFunction("input_savefile", Function(&f_inputSaveFile, ValueString, ValueString, ValueString, ValueString, 0)); + registerFunction("input_directory", Function(&f_inputDirectory, ValueString, ValueString, ValueString, 0)); + registerFunction("message_info", Function(&f_message_info, ValueInt, ValueString, ValueString, 1)); + registerFunction("message_error", Function(&f_message_error, ValueInt, ValueString, ValueString, 1)); + registerFunction("message_warning", Function(&f_message_warning, ValueInt, ValueString, ValueString, + ValueString, ValueString, ValueString, 1)); + registerFunction("message_question", Function(&f_message_question, ValueInt, ValueString, ValueString, + ValueString, ValueString, ValueString, 1)); +} + diff --git a/kommander/widget/invokeclass.cpp b/kommander/widget/invokeclass.cpp new file mode 100644 index 00000000..b5de4678 --- /dev/null +++ b/kommander/widget/invokeclass.cpp @@ -0,0 +1,61 @@ +// +// C++ Interface: invokeclass +// +// Description: +// +// +// Author: Andras Mantia <amantia@kde.org>, (C) 2008 +// +// Copyright: See COPYING file that comes with this distribution +// +// + +#include "invokeclass.h" + +#include <qcolor.h> +#include <qregexp.h> + +InvokeClass::InvokeClass(QObject *parent):QObject(parent) +{ + m_acceptedSlots = acceptedSlots(); +} + +void InvokeClass::invokeSlot(QObject *object, const QString& slot, QStringList args) +{ + QString invokeName = slot; + invokeName = invokeName.mid(invokeName.find('(')); + invokeName.prepend(QString::number(QSIGNAL_CODE) + "invoke"); + QString slotName = QString::number(QSLOT_CODE) + slot; + connect(this, invokeName.ascii(), object, slotName.ascii()); + + if (args.count() == 0) + emit invoke(); + else + { + QString slotArgStr = slot.section(QRegExp("\\(|\\)"), 1); + uint argNum = slotArgStr.contains(',') + 1; + for (uint i = args.count(); i < argNum; i++) + args << ""; + //poor man's invokeMetaObject + if (slotArgStr == m_acceptedSlots[0]) + emit invoke(args[0]); + else if (slotArgStr == m_acceptedSlots[1]) + emit invoke(args[0], args[1]); + else if (slotArgStr == m_acceptedSlots[2]) + emit invoke(args[0].upper()=="TRUE" || args[0] =="1"? true : false); + else if (slotArgStr == m_acceptedSlots[3]) + emit invoke(args[0].toInt()); + else if (slotArgStr == m_acceptedSlots[4]) + emit invoke(args[0].toInt(), args[1].toInt()); + else if (slotArgStr == m_acceptedSlots[5]) + emit invoke(args[0].toInt(), args[1].toInt(), args[2].toInt()); + else if (slotArgStr == m_acceptedSlots[6]) + emit invoke(args[0].toInt(), args[1].toInt(), args[2].toInt(), args[3].toInt()); + else if (slotArgStr == m_acceptedSlots[7]) + emit invoke(QColor(args[0])); + } + + disconnect(this, invokeName.ascii(), object, slotName.ascii()); +} + +#include "invokeclass.moc" diff --git a/kommander/widget/invokeclass.h b/kommander/widget/invokeclass.h new file mode 100644 index 00000000..61688b3e --- /dev/null +++ b/kommander/widget/invokeclass.h @@ -0,0 +1,56 @@ +// +// C++ Interface: invokeclass +// +// Description: +// +// +// Author: Andras Mantia <amantia@kde.org>, (C) 2008 +// +// Copyright: See COPYING file that comes with this distribution +// +// + +#ifndef INVOKECLASS_H +#define INVOKECLASS_H + +#include <qobject.h> +#include <qstringlist.h> + +class InvokeClass : public QObject { +Q_OBJECT +public: + InvokeClass(QObject *parent); + void invokeSlot(QObject *object, const QString& slot, QStringList args); + + static QStringList acceptedSlots() + { + static QStringList acceptedSlots; + acceptedSlots << "const QString&"; + acceptedSlots << "const QString&,const QString&"; + acceptedSlots << "bool"; + acceptedSlots << "int"; + acceptedSlots << "int,int"; + acceptedSlots << "int,int,int"; + acceptedSlots << "int,int,int,int"; + acceptedSlots << "const QColor&"; + + return acceptedSlots; + } + +signals: + void invoke(); + void invoke(const QString&); + void invoke(const QString&,const QString&); + void invoke(bool); + void invoke(int); + void invoke(int,int); + void invoke(int,int,int); + void invoke(int,int,int,int); + void invoke(const QColor&); + +private: + QStringList m_acceptedSlots; + +}; + +#endif diff --git a/kommander/widget/kmdrmainwindow.cpp b/kommander/widget/kmdrmainwindow.cpp new file mode 100644 index 00000000..cfe79d0c --- /dev/null +++ b/kommander/widget/kmdrmainwindow.cpp @@ -0,0 +1,36 @@ +// +// C++ Implementation: KmdrMainWindow +// +// Description: +// +// +// Author: Andras Mantia <amantia@kdewebdev.org>, (C) 2008 +// +// Copyright: See COPYING file that comes with this distribution +// +// +#include "kmdrmainwindow.h" + +#include <qtimer.h> + +KmdrMainWindow::KmdrMainWindow(QWidget *parent, const char *name, WFlags f) + : KMainWindow(parent, name, f) +{ + QTimer::singleShot(10, this, SIGNAL(initialize())); +} + + +KmdrMainWindow::~KmdrMainWindow() +{ +} + +bool KmdrMainWindow::queryClose() +{ + bool quit = KMainWindow::queryClose(); + if (quit) + emit destroy(); + return quit; +} + + +#include "kmdrmainwindow.moc" diff --git a/kommander/widget/kmdrmainwindow.h b/kommander/widget/kmdrmainwindow.h new file mode 100644 index 00000000..059b514e --- /dev/null +++ b/kommander/widget/kmdrmainwindow.h @@ -0,0 +1,37 @@ +// +// C++ Interface: KmdrMainWindow +// +// Description: +// +// +// Author: Andras Mantia <amantia@kdewebdev.org>, (C) 2008 +// +// Copyright: See COPYING file that comes with this distribution +// +// +#ifndef KmdrMainWindow_H +#define KmdrMainWindow_H + +#include <kmainwindow.h> + +/** + @author Andras Mantia <amantia@kdewebdev.org> +*/ +class KmdrMainWindow : public KMainWindow +{ +Q_OBJECT +public: + KmdrMainWindow(QWidget *parent = 0, const char *name = 0, WFlags f = WType_TopLevel | WDestructiveClose); + + ~KmdrMainWindow(); + +protected: + virtual bool queryClose(); + +signals: + void initialize(); + void destroy(); + +}; + +#endif diff --git a/kommander/widget/kommander_export.h b/kommander/widget/kommander_export.h new file mode 100644 index 00000000..f97e739c --- /dev/null +++ b/kommander/widget/kommander_export.h @@ -0,0 +1,35 @@ +/* + This file is part of kommander project + Copyright (c) 2005 Laurent Montel <montel@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef _KOMMANDER_EXPORT_H +#define _KOMMANDER_EXPORT_H + +#include <kdeversion.h> + +#if KDE_IS_VERSION(3,3,90) + +#include <kdemacros.h> + +#define KOMMANDER_EXPORT KDE_EXPORT + +#else +#define KOMMANDER_EXPORT +#endif +#endif /* _KOMMANDER_EXPORT_H */ diff --git a/kommander/widget/kommanderfunctions.cpp b/kommander/widget/kommanderfunctions.cpp new file mode 100644 index 00000000..a5a678db --- /dev/null +++ b/kommander/widget/kommanderfunctions.cpp @@ -0,0 +1,349 @@ +/*************************************************************************** + kommanderfunctions.cpp - Text widget core functionality + ------------------- + copyright : (C) 2004 Michal Rudolf <mrudolf@kdewebdwev.org> + + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include <iostream> +#include <stdlib.h> + +#include <qfile.h> +#include <qregexp.h> +#include <qtextstream.h> + +#include <dcopclient.h> +#include <kapplication.h> +#include <kconfig.h> +#include <klocale.h> +#include <kglobal.h> + +#include "kommanderwidget.h" +#include "specials.h" +#include "specialinformation.h" +#include "expression.h" +#include "parser.h" + +QString KommanderWidget::evalFunction(const QString& function, const QStringList& args) +{ + switch (SpecialInformation::function(Group::Kommander, function)) { + case Kommander::widgetText: + return handleDCOP(DCOP::text); + case Kommander::selectedWidgetText: + return handleDCOP(DCOP::selection); + case Kommander::dcopid: + return kapp->dcopClient()->appId(); + case Kommander::pid: + return QString().setNum(getpid()); + case Kommander::null: + return QString(); + case Kommander::comment: + return QString("#"); + case Kommander::exec: + return execCommand(args[0]); + case Kommander::dcop: + return DCOPQuery(args); + case Kommander::parentPid: + return global("_PARENTPID").isEmpty() ? QString().setNum(getppid()) : global("_PARENTPID"); + case Kommander::env: + return QString(getenv(args[0].latin1())); + case Kommander::i18n: + return KGlobal::locale()->translate(args[0]); + case Kommander::global: + return global(args[0]); + case Kommander::setGlobal: + setGlobal(args[0], args[1]); + return QString(); + case Kommander::debug: + qDebug("%s", args[0].latin1()); + fflush(stderr); + return QString::null; + case Kommander::echo: + for (uint i=0; i<args.count(); i++) + std::cout << args[i].latin1(); + fflush(stdout); + return QString::null; + case Kommander::readSetting: + { + QString fname = fileName(); + if (!fname.isEmpty()) + { + KConfig cfg("kommanderrc", true); + cfg.setGroup(fname); + return cfg.readEntry(args[0], args[1]); + } + return QString::null; + } + case Kommander::writeSetting: + { + QString fname = fileName(); + if (!fname.isEmpty()) + { + KConfig cfg("kommanderrc", false); + cfg.setGroup(fname); + cfg.writeEntry(args[0], args[1]); + } + return QString::null; + } + case Kommander::dialog: + if (args.count() > 1) + return runDialog(args[0], args[1]); + else + return runDialog(args[0]); + case Kommander::expr: + { + Expression expr(args[0]); + bool ok; + QVariant value = expr.value(&ok); + return ok ? value.toString() : QString(); + } + default: + return QString(); + } +} + + +QString KommanderWidget::evalExecBlock(const QStringList& args, const QString& s, int& pos) +{ + int f = s.find("@execEnd", pos); + if (f == -1) + { + printError(i18n("Unterminated @execBegin ... @execEnd block.")); + return QString(); + } + else + { + QString shell = args.count() ? args[0] : QString(); + int start = pos; + pos = f + QString("@execEnd").length()+1; + return execCommand(evalAssociatedText(s.mid(start, f - start)), shell); + } +} + +QString KommanderWidget::evalForEachBlock(const QStringList& args, const QString& s, int& pos) +{ + int f = s.find("@end", pos); +//FIXME: better detection of block boundaries + if (f == -1) + { + printError(i18n("Unterminated @forEach ... @end block.")); + return QString(); + } + else + { + int start = pos; + pos = f + QString("@end").length()+1; + QString var = args[0]; + QStringList loop = QStringList::split("\n", args[1]); + QString output; + QString block = substituteVariable(s.mid(start, f - start), QString("%1_count").arg(var), + QString::number(loop.count())); + QString varidx = QString("%1_index").arg(var); + for (uint i=0; i<loop.count(); i++) + output += evalAssociatedText(substituteVariable(substituteVariable(block, varidx, QString::number(i+1)), + var, loop[i])); + return output; + } +} + +QString KommanderWidget::evalForBlock(const QStringList& args, const QString& s, int& pos) +{ + int f = s.find("@end", pos); +//FIXME: better detection of block boundaries + if (f == -1) + { + printError(i18n("Unterminated @forEach ... @end block.")); + return QString(); + } + else + { + int start = pos; + pos = f + QString("@end").length()+1; + QString block = s.mid(start, f - start); + QString variable = args[0]; + + Expression expr; + int loopstart = expr.value(args[1]).toInt(); + int loopend = expr.value(args[2]).toInt(); + int loopstep = 1; + if (args.count() > 3) + { + loopstep = expr.value(args[3]).toInt(); + if (!loopstep) + loopstep = 1; + } + + QString output; + for (int i=loopstart; i<=loopend; i+=loopstep) + { + output += evalAssociatedText(substituteVariable(block, variable, QString::number(i))); + } + return output; + } +} + +QString KommanderWidget::evalIfBlock(const QStringList& args, const QString& s, int& pos) +{ + int f = s.find("@endif", pos); +//FIXME: better detection of block boundaries; add error message + if (f == -1) + { + pos = s.length()+1; + printError(i18n("Unterminated @if ... @endif block.")); + return QString(); + } + else + { + QString block = s.mid(pos, f - pos); + pos = f + QString("@endif").length()+1; + Expression expr; + if (expr.isTrue(args[0])) + return evalAssociatedText(block); + return QString(); + } +} + +QString KommanderWidget::evalSwitchBlock(const QStringList& args, const QString& s, int& pos) +{ + int f = s.find("@end", pos); +//FIXME: better detection of block boundaries; add error message + if (f == -1) + { + printError(i18n("Unterminated @switch ... @end block.")); + return QString(); + } + else + { + QString block = s.mid(pos, f - pos); + pos = f + QString("@end").length()+1; + f = parseBlockBoundary(block, 0, "@case"); + bool finished = f == -1; + while (!finished) + { + f += 5; + int end = parseBlockBoundary(block, f, "@case"); + if (end == -1) + { + end = block.length(); + finished = true; + } + bool ok; + QString value = parseBrackets(block, f, ok); + if (!ok) + break; + if (value == args[0] || value == "*") + return evalAssociatedText(block.mid(f, end-f)); + f = end; + } + return QString(); + } +} + + + +QString KommanderWidget::evalArrayFunction(const QString& function, const QStringList& args) +{ + Parser parser(internalParserData()); + int fname = SpecialInformation::function(Group::Array, function); + QString array = args[0].startsWith("_") ? args[0] : QString("_")+ args[0]; + + if (fname == Array::setValue) + parser.setArray(array, args[1], args[2]); + else if (fname == Array::fromString) + { + QStringList lines = QStringList::split("\n", args[1]); + for (QStringList::Iterator it = lines.begin(); it != lines.end(); ++it) + { + QString key = (*it).section('\t', 0, 0).stripWhiteSpace(); + if (!key.isEmpty()) + parser.setArray(array, key, (*it).section('\t', 1)); + } + } + else if (!parser.isArray(array)) + return QString(); + else switch (fname) { + case Array::value: + return parser.arrayValue(array, args[1]).toString(); + case Array::keys: + { + const QMap<QString, ParseNode> map = parser.array(array); + QStringList keys; + for (QMap<QString, ParseNode>::ConstIterator it = map.begin(); it != map.end(); ++it) + keys.append(it.key()); + return keys.join("\n"); + } + case Array::values: + { + const QMap<QString, ParseNode> map = parser.array(array); + QStringList values; + for (QMap<QString, ParseNode>::ConstIterator it = map.begin(); it != map.end(); ++it) + values.append(it.data().toString()); + return values.join("\n"); + } + case Array::clear: + parser.unsetArray(array); + return QString(); + case Array::remove: + parser.unsetArray(array, args[1]); + return QString(); + case Array::count: + return QString::number(parser.array(array).count()); + case Array::toString: + { + const QMap<QString, ParseNode> map = parser.array(array); + QString arraystring; + for (QMap<QString, ParseNode>::ConstIterator it = map.begin(); it != map.end(); ++it) + arraystring += QString("%1\t%2\n").arg(it.key()).arg(it.data().toString()); + return arraystring; + } + default: + return QString(); + } + return QString(); +} + + +QString KommanderWidget::evalWidgetFunction(const QString& identifier, const QString& s, int& pos) +{ + KommanderWidget* pWidget = parseWidget(identifier); + if (!pWidget) + { + printError(i18n("Unknown widget: @%1.").arg(identifier)); + return QString(); + } + if (s[pos] == '.') + { + pos++; + bool ok = true; + QString function = parseIdentifier(s, pos); + QStringList args = parseFunction("DCOP", function, s, pos, ok); + if (!ok) + return QString(); + args.prepend(pWidget->widgetName()); + QString prototype = SpecialInformation::prototype(Group::DCOP, + SpecialInformation::function(Group::DCOP, function)); + return localDCOPQuery(prototype, args); + } + else if (pWidget == this) + { + printError(i18n("Infinite loop: @%1 called inside @%2.").arg(pWidget->widgetName()) + .arg(pWidget->widgetName())); + return QString(); + } + else if (!pWidget->hasAssociatedText()) + { + printError(i18n("Script for @%1 is empty.").arg(pWidget->widgetName())); + return QString(); + } + return pWidget->evalAssociatedText(); +} + diff --git a/kommander/widget/kommanderwidget.cpp b/kommander/widget/kommanderwidget.cpp new file mode 100644 index 00000000..525f662b --- /dev/null +++ b/kommander/widget/kommanderwidget.cpp @@ -0,0 +1,745 @@ +/*************************************************************************** + kommanderwidget.cpp - Text widget core functionality + ------------------- + copyright : (C) 2002-2003 Marc Britton <consume@optusnet.com.au> + (C) 2004 Michal Rudolf <mrudolf@kdewebdwev.org> + + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + + + /* KDE INCLUDES */ +#include <dcopclient.h> +#include <kapplication.h> +#include <kdebug.h> +#include <klocale.h> +#include <kdialogbase.h> +#include <kmessagebox.h> +#include <kprocess.h> + +/* QT INCLUDES */ +#include <qcstring.h> +#include <qdatastream.h> +#include <qfileinfo.h> +#include <qobject.h> +#include <qobjectlist.h> +#include <qregexp.h> +#include <qstring.h> +#include <qstringlist.h> +#include <qvaluelist.h> +#include <qvariant.h> + + +/* UNIX INCLUDES */ +#include <unistd.h> +#include <stdlib.h> + +/* OTHER INCLUDES */ +#include "myprocess.h" +#include "kommanderwidget.h" +#include "specials.h" +#include "specialinformation.h" +#include "parser.h" +#include "parserdata.h" +#include "kommanderwindow.h" + +KommanderWidget::KommanderWidget(QObject *a_thisObject) +{ + m_thisObject = a_thisObject; +} + +KommanderWidget::~KommanderWidget() +{ +} + +void KommanderWidget::setAssociatedText(const QStringList& a_associations) +{ + m_associatedText = a_associations; + while(m_associatedText.count() < (states().count())) + m_associatedText += QString(); // sync states and associations +} + +QStringList KommanderWidget::associatedText() const +{ + return m_associatedText; +} + +bool KommanderWidget::hasAssociatedText() +{ + int index = states().findIndex(currentState()); + if (index == -1 || m_associatedText[index].isEmpty()) + return false; + return true; +} + + +void KommanderWidget::setPopulationText(const QString& a_txt) +{ + m_populationText = a_txt; +} + +QString KommanderWidget::populationText() const +{ + return m_populationText; +} + +QStringList KommanderWidget::states() const +{ + return m_states; +} + +QStringList KommanderWidget::displayStates() const +{ + return m_displayStates; +} + +void KommanderWidget::setStates(const QStringList& a_states) +{ + m_states = a_states; +} + +void KommanderWidget::setDisplayStates(const QStringList& a_displayStates) +{ + m_displayStates = a_displayStates; +} + +QString KommanderWidget::evalAssociatedText() // expands and returns associated text as a string +{ + int index = ( states().findIndex( currentState()) ); + if (index == -1) + { + printError(i18n("Invalid state for associated text.")); + return QString(); + } + return evalAssociatedText(m_associatedText[index]); +} + +QString KommanderWidget::evalAssociatedText(const QString& a_text) +{ + /* New internal parser is used if global flag is set */ + if ((KommanderWidget::useInternalParser && !a_text.startsWith("#!")) || a_text.startsWith("#!kommander")) + { + Parser p(internalParserData()); + p.setWidget(this); + p.setString(a_text); + if (!p.setString(a_text) || !p.parse()) + printError(i18n("Line %1: %2.\n").arg(p.errorLine()+1).arg(p.errorMessage())); + return QString(); + } + /* Old macro-only parser is implemented below */ + + bool parserType = KommanderWidget::useInternalParser; + KommanderWidget::useInternalParser = false; //shebang is used, switch to old parser + + QString evalText; + int pos = 0, baseTextLength = a_text.length(); + while (pos < baseTextLength) + { + int ident = a_text.find(ESCCHAR, pos); + if (ident == -1) { + evalText += a_text.mid(pos); + break; + } + evalText += a_text.mid(pos, ident - pos); + pos = ident+1; + + /* escaped @ */ + if (pos < baseTextLength-1 && a_text[pos] == ESCCHAR) + { + evalText += ESCCHAR; + pos++; + continue; + } + + QString identifier = parseIdentifier(a_text, pos); + /* comment */ + if (identifier.isEmpty()) + { + if (pos < baseTextLength && a_text[pos] == '#') { // comment + int newpos = a_text.find('\n', pos+1); + if (newpos == -1) + newpos = a_text.length(); + if (pos > 1 && a_text[pos-2] == '\n') + newpos++; + pos = newpos; + } + else + evalText += ESCCHAR; // single @ + continue; + } + bool ok = true; + QStringList args; + + + + /* Standard, non-prefixed special */ + if (identifier == "if") // if required special handling as it takes expression + { + QString arg = parseBrackets(a_text, pos, ok); + if (!ok) + return QString(); + args.append(evalAssociatedText(arg)); + evalText += evalIfBlock(args, a_text, pos); + } + else if (SpecialInformation::function(Group::Kommander, identifier) != -1) + { + args = parseFunction("Kommander", identifier, a_text, pos, ok); + if (!ok) + return QString(); + else if (identifier == "execBegin") + evalText += evalExecBlock(args, a_text, pos); + else if (identifier == "forEach") + evalText += evalForEachBlock(args, a_text, pos); + else if (identifier == "for") + evalText += evalForBlock(args, a_text, pos); + else if (identifier == "switch") + evalText += evalSwitchBlock(args, a_text, pos); + else if (identifier == "if") + evalText += evalIfBlock(args, a_text, pos); + else + evalText += evalFunction(identifier, args); + } + + /* Widget special */ + else if (parseWidget(identifier)) + evalText += evalWidgetFunction(identifier, a_text, pos); + else if (a_text[pos] == '.') + { + pos++; + QString function = parseIdentifier(a_text, pos); + args = parseFunction(identifier, function, a_text, pos, ok); + if (!ok) + return QString(); + switch (SpecialInformation::group(identifier)) + { + case Group::Array: + evalText += evalArrayFunction(function, args); + break; + case Group::String: + evalText += Parser::function(internalParserData(), "str_" + function, args); + break; + case Group::File: + evalText += Parser::function(internalParserData(), "file_" + function, args); + break; + case Group::Message: + evalText += Parser::function(internalParserData(), "message_" + function, args); + break; + case Group::Input: + evalText += Parser::function(internalParserData(), "input_" + function, args); + break; + default: + return QString(); + } + } + else + { + printError(i18n("Unknown special: \'%1\'.").arg(identifier)); + return QString(); + } + } + + KommanderWidget::useInternalParser = parserType; + return evalText; +} + + +QString KommanderWidget::DCOPQuery(const QStringList& a_query) +{ + QString app = a_query[0]; + app.remove("\""); + QCString appId = app.latin1(), object = a_query[1].latin1(); + + // parse function arguments + QString function = a_query[2], pTypes; + function.remove(' '); + int start = function.find('('); + bool ok = false; + if (start != -1) + pTypes = parseBrackets(function, start, ok); + else + { + ok = true; + function += "()"; + } + if (!ok) + { + printError(i18n("Unmatched parenthesis in DCOP call \'%1\'.").arg(a_query[2])); + return QString(); + } + const QStringList argTypes = parseArgs(pTypes, ok); + if (!ok || argTypes.count() != a_query.count() - 3) + { + printError(i18n("Incorrect arguments in DCOP call \'%1\'.").arg(a_query[2])); + return QString(); + } + + QCString replyType; + QByteArray byteData, byteReply; + QDataStream byteDataStream(byteData, IO_WriteOnly); + for (uint i=0 ; i<argTypes.count(); i++) { + if (argTypes[i] == "int") + byteDataStream << a_query[i+3].toInt(); + else if (argTypes[i] == "long") + byteDataStream << a_query[i+3].toLong(); + else if (argTypes[i] == "float") + byteDataStream << a_query[i+3].toFloat(); + else if (argTypes[i] == "double") + byteDataStream << a_query[i+3].toDouble(); + else if (argTypes[i] == "bool") + byteDataStream << (bool)(a_query[i+3] != "false" && a_query[i+3] != "false" && a_query[i+3] != "0"); + else if (argTypes[i] == "QStringList") + if (a_query[i+3].find('\n') != -1) + byteDataStream << QStringList::split("\n", a_query[i+3], true); + else + byteDataStream << QStringList::split("\\n", a_query[i+3], true); + else + byteDataStream << a_query[i+3]; + } + + DCOPClient *cl = KApplication::dcopClient(); + if (!cl || !cl->call(appId, object, function.latin1(), byteData, replyType, byteReply)) + { + printError(i18n("Tried to perform DCOP query, but failed.")); + return QString(); + } + + QDataStream byteReplyStream(byteReply, IO_ReadOnly); + if (replyType == "QString") + { + QString text; + byteReplyStream >> text; + return text; + } + else if(replyType == "int") + { + int i; + byteReplyStream >> i; + return QString::number(i); + } + else if(replyType == "bool") + { + bool b; + byteReplyStream >> b; + return QString::number(b); + } + else if (replyType == "QStringList") + { + QStringList text; + byteReplyStream >> text; + return text.join("\n"); + } + else if(replyType != "void") + { + printError(i18n("DCOP return type %1 is not yet implemented.").arg(replyType.data())); + } + + return QString(); +} + +QString KommanderWidget::localDCOPQuery(const QString function, const QStringList& args) +{ + QStringList pArgs; + pArgs.append(kapp->dcopClient()->appId()); + pArgs.append("KommanderIf"); + pArgs.append(function); + for (uint i=0; i<args.count(); i++) + pArgs.append(args[i]); + return DCOPQuery(pArgs); +} + +QString KommanderWidget::localDCOPQuery(const QString function, const QString& arg1, + const QString& arg2, const QString& arg3, const QString& arg4) +{ + QStringList pArgs; + pArgs.append(kapp->dcopClient()->appId()); + pArgs.append("KommanderIf"); + pArgs.append(function); + pArgs.append(arg1); + pArgs.append(arg2); + if (!arg3.isNull()) + pArgs.append(arg3); + if (!arg4.isNull()) + pArgs.append(arg4); + return DCOPQuery(pArgs); +} + + +QString KommanderWidget::execCommand(const QString& a_command, const QString& a_shell) const +{ + MyProcess proc(this); + QString text = proc.run(a_command.local8Bit(), a_shell.latin1()); +//FIXME check if exec was successful + return text; +} + +QString KommanderWidget::runDialog(const QString& a_dialog, const QString& a_params) +{ + QString pFileName = localDCOPQuery("global(QString)", "_KDDIR") + QString("/") + a_dialog; + QFileInfo pDialogFile(pFileName); + if (!pDialogFile.exists()) + { + pFileName = a_dialog; + pDialogFile.setFile(pFileName); + if (!pDialogFile.exists()) + return QString(); + } + QString cmd = QString("kmdr-executor %1 %2 _PARENTPID=%3 _PARENTDCOPID=kmdr-executor-%4") + .arg(pFileName).arg(a_params).arg(getpid()).arg(getpid()); + return execCommand(cmd); +} + + +void KommanderWidget::printError(const QString& a_error) const +{ + if (showErrors) + { + KDialogBase* dialog = new KDialogBase("Error", KDialogBase::Yes | KDialogBase::No | KDialogBase::Cancel, + KDialogBase::Yes, KDialogBase::No, 0, 0, true, false, + i18n("Continue"), i18n("Continue && Ignore Next Errors"), i18n("Stop")); + switch (KMessageBox::createKMessageBox(dialog, QMessageBox::Warning, + i18n("<qt>Error in widget <b>%1</b>:<p><i>%2</i></qt>").arg(QString(m_thisObject->name())) + .arg(a_error), QStringList(), QString(), 0, 0)) + { + case KDialogBase::No: + showErrors = false; + case KDialogBase::Yes: + break; + case KDialogBase::Cancel: + if (parentDialog()->inherits("QDialog")) + { + parentDialog()->close(); + exit(-1); + } + else if (parentDialog()->inherits("QMainWindow")) + kapp->quit(); + } + } + else + { + kdError() << i18n("Error in widget %1:\n %2\n").arg(m_thisObject->name()).arg(a_error); + } +} + + + +QString KommanderWidget::parseIdentifier(const QString& s, int& from) const +{ + uint start = from; + while (start < s.length() && s[start].isSpace()) + start++; + uint end = start; + while (end < s.length() && (s[end].isLetterOrNumber() || s[end] == '_')) + end++; + from = end; + return s.mid(start, end-start); +} + +QString KommanderWidget::parseBrackets(const QString& s, int& from, bool& ok) const +{ + ok = true; + uint start = from; + while (start < s.length() && s[start].isSpace()) + start++; + if (start == s.length() || s[start] != '(') + return QString(); + bool quoteSingle = false, quoteDouble = false; + int brackets = 1; + for (uint end = start+1; end < s.length(); end++) + { + if (!quoteDouble && s[end] == '\'' && s[end-1] != '\\') + quoteSingle = !quoteSingle; + else if (!quoteSingle && s[end] == '\"' && s[end-1] != '\\') + quoteDouble = !quoteDouble; + else if (!quoteDouble && !quoteSingle && s[end] == '(') + brackets++; + else if (!quoteDouble && !quoteSingle && s[end] == ')') + { + brackets--; + if (!brackets) { + from = end + 1; + return s.mid(start+1, end-start-1); + } + } + } + ok = false; + return QString(); +} + + +QStringList KommanderWidget::parseArgs(const QString& s, bool &ok) +{ + QStringList argList; + bool quoteDouble = false, quoteSingle = false; + uint i, start = 0, brackets=0; + for (i = 0; i < s.length(); i++) + { + /* Handle brackets */ + if (s[i] == '(' && !quoteSingle && !quoteDouble) + brackets++; + else if (s[i] == ')' && !quoteSingle && !quoteDouble) + brackets--; + /* Ignore everything in brackets */ + else if (!brackets) + { + if (s[i] == '\'' && s[i-1] != '\\' && !quoteDouble) + quoteSingle = !quoteSingle; + else if (s[i] == '\"' && s[i-1] != '\\' && !quoteSingle) + quoteDouble = !quoteDouble; + else if (s[i] == ',' && !quoteDouble && !quoteSingle) + { + QString arg = s.mid(start, i - start).stripWhiteSpace(); + if (!arg.isEmpty()) + argList.append(evalAssociatedText(parseQuotes(arg))); + start = i+1; + } + } + } + if (!quoteDouble && !quoteSingle) + { + QString arg = s.mid(start, s.length() - start + 1).stripWhiteSpace(); + if (!arg.isEmpty()) + argList.append(evalAssociatedText(parseQuotes(arg))); + } + ok = !quoteDouble && !quoteSingle; + + return argList; +} + +QString KommanderWidget::parseQuotes(const QString& s) const +{ + if (s[0] == s[s.length()-1] && (s[0] == '\'' || s[0] == '\"')) + { + QMemArray<QChar> buf(s.length()); + int start = 0; + int end = s.length() - 1; + for (int i=1; i<end; i++) + if (s[i] == '\\') + { + if (s[i+1] == 't') + buf[start++] = '\t'; + else if (s[i+1] == 'n') + buf[start++] = '\n'; + else if (s[i+1] == '\\') + buf[start++] = '\\'; + else + { + buf[start++] = s[i]; + i--; + } + i++; + } + else + buf[start++] = s[i]; + return QString(buf, start); + //return s.mid(1, s.length()-2); + } + else return s; +} + +bool KommanderWidget::isWidget(const QString& a_name) const +{ + return parseWidget(a_name); +} + +KommanderWidget* KommanderWidget::widgetByName(const QString& a_name) const +{ + return parseWidget(a_name); +} + + +KommanderWidget* KommanderWidget::parseWidget(const QString& widgetName) const +{ + if (QString(parentDialog()->name()) == widgetName) + return dynamic_cast <KommanderWidget*>(parentDialog()); + QCString s = widgetName.lower() == "self" ? m_thisObject->name() : widgetName.latin1(); + QObject* childObj = parentDialog()->child(s); +/* if (!childObj) + { + Parser parser(internalParserData()); + QString variableValue = parser.variable(widgetName).toString(); + s = variableValue.lower() == "self" ? m_thisObject->name() : variableValue.latin1(); + childObj = parentDialog()->child(s); + }*/ + return dynamic_cast <KommanderWidget*>(childObj); +} + +QStringList KommanderWidget::parseFunction(const QString& group, const QString& function, + const QString& s, int& from, bool& ok) +{ + ok = true; + bool success = false; + QString arg = parseBrackets(s, from, ok); + if (!ok) + { + printError(i18n("Unmatched parenthesis after \'%1\'.").arg(function)); + return QString(); + } + const QStringList args = parseArgs(arg, ok); + int gname = SpecialInformation::group(group); + int fname = SpecialInformation::function(gname, function); + bool extraArg = gname == Group::DCOP; + + if (!ok) + printError(i18n("Unmatched quotes in argument of \'%1\'.").arg(function)); + else if (gname == -1) + printError(i18n("Unknown function group: \'%1\'.").arg(group)); + else if (fname == -1 && !extraArg) + printError(i18n("Unknown function: \'%1\' in group '%2'.").arg(function).arg(group)); + else if (fname == -1 && extraArg) + printError(i18n("Unknown widget function: \'%1\'.").arg(function)); + else if ((int)args.count() + extraArg < SpecialInformation::minArg(gname, fname)) + printError(i18n("Not enough arguments for \'%1\' (%2 instead of %3).<p>" + "Correct syntax is: %4") + .arg(function).arg(args.count() + extraArg).arg(SpecialInformation::minArg(gname, fname)) + .arg(SpecialInformation::prototype(gname, fname, SpecialFunction::ShowArgumentNames))); + else if ((int)args.count() + extraArg > SpecialInformation::maxArg(gname, fname)) + printError(i18n("Too many arguments for \'%1\' (%2 instead of %3).<p>" + "Correct syntax is: %4") + .arg(function).arg(args.count() + extraArg).arg(SpecialInformation::maxArg(gname, fname)) + .arg(SpecialInformation::prototype(gname, fname, SpecialFunction::ShowArgumentNames))); + else + success = true; + ok = success; + return args; +} + +int KommanderWidget::parseBlockBoundary(const QString& s, int from, const QStringList& args) const +{ + int shortest = -1; + for (uint i=0; i<args.count(); i++) + { + int match = s.find(args[i], from); + if (shortest > match || shortest == -1) + shortest = match; + } + return shortest; +} + + + +QString KommanderWidget::substituteVariable(QString text, QString variable, QString value) const +{ + QString var = QString("@%1").arg(variable); + QString newtext; + int newpos, pos = 0; + while (true) + { + newpos = text.find(var, pos); + if (newpos != -1) + { + newtext += text.mid(pos, newpos-pos); + newtext += value; + pos = newpos + var.length(); + } else + { + newtext += text.mid(pos); + break; + } + } + return newtext; +} + + + +QWidget* KommanderWidget::parentDialog() const +{ + QObject *superParent = m_thisObject; + while (superParent->parent()) + { + superParent = superParent->parent(); + if (superParent->inherits("QDialog") || superParent->inherits("QMainWindow")) + break; + } + return (QWidget*)superParent; +} + + + + +QString KommanderWidget::global(const QString& variableName) +{ + QString var = variableName.startsWith("_") ? variableName : QString("_")+ variableName; + Parser parser(internalParserData()); + return parser.variable(var).toString(); +} + +void KommanderWidget::setGlobal(const QString& variableName, const QString& value) +{ + QString var = variableName.startsWith("_") ? variableName : QString("_")+ variableName; + Parser parser(internalParserData()); + parser.setVariable(var, value); +} + +QString KommanderWidget::handleDCOP(const int function, const QStringList& args) +{ + QWidget* current = dynamic_cast<QWidget*>(m_thisObject); + if (!current) + return QString(); + switch(function) { + case DCOP::setEnabled: + current->setEnabled( args[0] != "false" && args[0] != "0"); + break; + case DCOP::setVisible: + current->setShown(args[0] != "false" && args[0] != "0"); + break; + case DCOP::type: + return current->className(); + case DCOP::children: + { + QStringList matching; + QObjectList* widgets = current->queryList("QWidget", 0, false, args.count() == 0 || args[0] != "false"); + for (QObject* w = widgets->first(); w; w = widgets->next()) + if (w->name() && (dynamic_cast<KommanderWidget*>(w))) + matching.append(w->name()); + return matching.join("\n"); + } + } + return QString(); +} + +bool KommanderWidget::isFunctionSupported(int f) +{ + return f == DCOP::setEnabled || f == DCOP::setVisible || f == DCOP::children || f == DCOP::type; +} + +bool KommanderWidget::isCommonFunction(int f) +{ + return f == DCOP::setEnabled || f == DCOP::setVisible || f == DCOP::children || f == DCOP::type; +} + +ParserData* KommanderWidget::internalParserData() const +{ + return m_parserData; +} + +QString KommanderWidget::fileName() +{ + KommanderWindow* window = dynamic_cast<KommanderWindow*>(parentDialog()); + if (window) + return QString(window->fileName()); + else + return QString(); +} + +QString KommanderWidget::widgetName() const +{ + if (m_thisObject) + return QString::fromLatin1(m_thisObject->name()); + else + return QString(); +} + +bool KommanderWidget::inEditor = false; +bool KommanderWidget::showErrors = true; +bool KommanderWidget::useInternalParser = false; +ParserData* KommanderWidget::m_parserData = new ParserData; + + diff --git a/kommander/widget/kommanderwidget.h b/kommander/widget/kommanderwidget.h new file mode 100644 index 00000000..90a748b2 --- /dev/null +++ b/kommander/widget/kommanderwidget.h @@ -0,0 +1,162 @@ +/*************************************************************************** + kommanderwidget.h - Text widget core functionality + ------------------- + copyright : (C) 2002-2003 Marc Britton <consume@optusnet.com.au> + (C) 2004 Michal Rudolf <mrudolf@kdewebdwev.org> + + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef _HAVE_KOMMANDERWIDGET_H_ +#define _HAVE_KOMMANDERWIDGET_H_ + +/* KDE INCLUDES */ +#include <kprocess.h> + +#include "kommander_export.h" +/* QT INCLUDES */ +#include <qmap.h> +#include <qobject.h> +#include <qpair.h> +#include <qstring.h> +#include <qstringlist.h> + +class ParserData; + +class KOMMANDER_EXPORT KommanderWidget +{ + friend class MyProcess; +public: + KommanderWidget(QObject *); + virtual ~KommanderWidget(); + + //List of available states. Most widgets have only one state, but f. e. radiobutton has both + // 'checked' and 'unchecked' + virtual QStringList states() const; + virtual QStringList displayStates() const; + virtual QString currentState() const = 0; + + virtual bool isKommanderWidget() const = 0; + + // Associated script + virtual void setAssociatedText(const QStringList& a_associations); + virtual QStringList associatedText() const; + virtual bool hasAssociatedText(); + + // Execute default script, expanding all @macros. + virtual QString evalAssociatedText(); + // Execute given script, expanding all @macros. + virtual QString evalAssociatedText(const QString&); + // Evaluate given Kommander function using given args. + virtual QString evalFunction(const QString& function, const QStringList& args); + // Parse and evaluate function for given widget, converting it to appropriate DCOP call. + virtual QString evalWidgetFunction(const QString& identifier, const QString& s, int& pos); + // Evaluate given array function using given args. + virtual QString evalArrayFunction(const QString&, const QStringList&); + // Parse and evaluate given execBegin..execEnd block. + virtual QString evalExecBlock(const QStringList&, const QString& s, int& pos); + // Parse and evaluate given forEach..end block. + virtual QString evalForEachBlock(const QStringList&, const QString& s, int& pos); + // Parse and evaluate given for..end block. + virtual QString evalForBlock(const QStringList&, const QString& s, int& pos); + // Parse and evaluate given switch..case..end block. + virtual QString evalSwitchBlock(const QStringList&, const QString& s, int& pos); + // Parse and evaluate given if..endif block. + virtual QString evalIfBlock(const QStringList&, const QString& s, int& pos); + // Population text. It will become widgetText after populate() is called + virtual QString populationText() const; + virtual void setPopulationText(const QString&); + virtual void populate() = 0; + + // Handles all widget-specific DCOP calls + virtual QString handleDCOP(int function, const QStringList& args = QStringList()); + // Checks if appropriate function is supported by widget. By default all functions + // are reported as supported: use this to allow recognizing incorrect function calls. + virtual bool isFunctionSupported(int function); + // Checks if the function is common widget function (i. e. supported by all widgets) + virtual bool isCommonFunction(int function); + // Checks if the string is a valid widget name) + virtual bool isWidget(const QString& a_name) const; + // Returns widget from name + virtual KommanderWidget* widgetByName(const QString& a_name) const; + // Returns current widget name; + virtual QString widgetName() const; + // Returns filename associated with the dialog + virtual QString fileName(); + + QObject* object() { return m_thisObject;} + + + // Recognizes editor vs executor mode + static bool inEditor; + // Prints errors in message boxes, not in stderr + static bool showErrors; + // Default parser + static bool useInternalParser; + // Return global variable value + QString global(const QString& variableName); + // Set global variable value + void setGlobal(const QString& variableName, const QString& value); + +protected: + virtual void setStates(const QStringList& a_states); + virtual void setDisplayStates(const QStringList& a_displayStates); + + // Execute DCOP query and return its result or null on failure + // Only QString and int are now handled + QString DCOPQuery(const QStringList& args); + QString localDCOPQuery(const QString function, const QStringList& args = QStringList()); + QString localDCOPQuery(const QString function, const QString& arg1, + const QString& arg2, const QString& arg3 = QString::null, + const QString& arg4 = QString::null); + // Execute given command, return its result + QString execCommand(const QString& a_command, const QString& a_shell = QString::null) const; + // Find and run dialog (with optional parameters) + QString runDialog(const QString& a_dialog, const QString& a_params = QString::null); + // Display error message a_error; display current class name if no other is given + void printError(const QString& a_error) const; + // Auxiliary functions for parser + // Find matching brackets starting from current position + QString parseBrackets(const QString& s, int& from, bool& ok) const; + // Return identifier: the longest string of letters and numbers starting from i + QString parseIdentifier(const QString& s, int& from) const; + // Parse arguments for given function. Returns list of arguments without quotations + QStringList parseArgs(const QString& s, bool &ok); + // Remove quotes from given identifier + QString parseQuotes(const QString& s) const; + // Parse function + QStringList parseFunction(const QString& group, const QString& function, + const QString& s, int& from, bool& ok); + // Detect and return block boundary + int parseBlockBoundary(const QString& s, int from, const QStringList& args) const; + + // Parse given identifier as widget name + KommanderWidget* parseWidget(const QString& name) const; + // Return parent dialog of this widget + QWidget* parentDialog() const; + QString substituteVariable(QString text, QString variable, QString value) const; + + ParserData* internalParserData() const; + + QObject *m_thisObject; + QStringList m_states; + QStringList m_displayStates; + QStringList m_associatedText; + QString m_populationText; + + // Internal parser data + static ParserData* m_parserData; +}; + + +#define ESCCHAR '@' + +#endif diff --git a/kommander/widget/kommanderwindow.cpp b/kommander/widget/kommanderwindow.cpp new file mode 100644 index 00000000..b536eb87 --- /dev/null +++ b/kommander/widget/kommanderwindow.cpp @@ -0,0 +1,35 @@ +/*************************************************************************** + kommanderwindow.cpp - Kommander window widgets + ------------------- + copyright : (C) 2004 by Michal Rudolf <mrudolf@kdewebdev.org> + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "kommanderwindow.h" + +KommanderWindow::KommanderWindow(QObject* object) : KommanderWidget(object) +{ +} + +KommanderWindow::~KommanderWindow() +{ +} + + +void KommanderWindow::setFileName(const QString& s) +{ + m_fileName = s; +} + +QString KommanderWindow::fileName() +{ + return m_fileName; +} diff --git a/kommander/widget/kommanderwindow.h b/kommander/widget/kommanderwindow.h new file mode 100644 index 00000000..023bd395 --- /dev/null +++ b/kommander/widget/kommanderwindow.h @@ -0,0 +1,37 @@ +/*************************************************************************** + kommanderwindow.h - Kommander window widgets + ------------------- + copyright : (C) 2004 by Michal Rudolf <mrudolf@kdewebdev.org> + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef _HAVE_KOMMANDERWINDOW_H_ +#define _HAVE_KOMMANDERWINDOW_H_ + +#include "kommanderwidget.h" +#include "kommander_export.h" +class KOMMANDER_EXPORT KommanderWindow : public KommanderWidget +{ +public: + KommanderWindow(QObject *); + virtual ~KommanderWindow(); + virtual void setFileName(const QString& s); + virtual QString fileName(); +protected: + +private: + QString m_fileName; +}; + + + +#endif + diff --git a/kommander/widget/myprocess.cpp b/kommander/widget/myprocess.cpp new file mode 100644 index 00000000..e7e05e3b --- /dev/null +++ b/kommander/widget/myprocess.cpp @@ -0,0 +1,137 @@ +/*************************************************************************** + myprocess.cpp - Wrapper class for running shell processes + ------------------- + copyright : (C) 2002 by Marc Britton + email : consume@optusnet.com.au + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ +/* KDE INCLUDES */ +#include <klocale.h> +#include <kprocess.h> +#include <klocale.h> + +/* QT INCLUDES */ +#include <qapplication.h> +#include <qobject.h> +#include <qstring.h> + +/* OTHER INCLUDES */ +#include "myprocess.h" +#include "kommanderwidget.h" + +MyProcess::MyProcess(const KommanderWidget *a_atw) + : m_atw(a_atw), m_loopStarted(false), m_blocking(true), mProcess(0) +{ +} + +void qt_enter_modal(QWidget *widget); +void qt_leave_modal(QWidget *widget); + +void MyProcess::setBlocking(bool blocking) +{ + m_blocking = blocking; +} + +QString MyProcess::output() const +{ + return m_output; +} + +bool MyProcess::isBlocking() const +{ + return m_blocking; +} + + +void MyProcess::cancel() +{ + if (mProcess) { + delete mProcess; + mProcess = 0; + } +} + +QString MyProcess::run(const QString& a_command, const QString& a_shell) +{ + QString at = a_command.stripWhiteSpace(); + if (at.isEmpty()) + { + emit processExited(0); + return QString(); + } + + QString shellName = a_shell; + if (shellName.isEmpty()) + shellName = "/bin/sh"; + + // Look for shell + if (at.startsWith("#!")) { + int eol = at.find("\n"); + if (eol == -1) + eol = at.length(); + shellName = at.mid(2, eol-1).stripWhiteSpace(); + at = at.mid(eol+1); + } + m_input = at.local8Bit(); + + mProcess = new KProcess; + (*mProcess) << shellName.latin1(); + + connect(mProcess, SIGNAL(receivedStdout(KProcess*, char*, int)), + SLOT(slotReceivedStdout(KProcess*, char*, int))); + connect(mProcess, SIGNAL(processExited(KProcess*)), SLOT(slotProcessExited(KProcess*))); + + if(!mProcess->start(KProcess::NotifyOnExit, KProcess::All)) + { + m_atw->printError(i18n("<qt>Failed to start shell process<br><b>%1</b></qt>").arg(shellName)); + return QString(); + } + mProcess->writeStdin(m_input, m_input.length()); + mProcess->closeStdin(); + + if (!m_blocking) + return QString(); + else + { + QWidget dummy(0, 0, WType_Dialog | WShowModal); + dummy.setFocusPolicy(QWidget::NoFocus); + m_loopStarted = true; + qt_enter_modal(&dummy); + qApp->enter_loop(); + qt_leave_modal(&dummy); + + if (!m_output.isEmpty() && m_output[m_output.length()-1] == '\n') + return m_output.left(m_output.length()-1); + else + return m_output; + } +} + +void MyProcess::slotReceivedStdout(KProcess*, char* a_buffer, int a_len) +{ + m_output += QString::fromLocal8Bit(a_buffer, a_len); + emit processReceivedStdout(this, a_buffer, a_len); +} + +void MyProcess::slotProcessExited(KProcess* process) +{ + if (m_loopStarted) + { + qApp->exit_loop(); + m_loopStarted = false; + } + delete process; + if (!m_blocking) + emit processExited(this); + mProcess = 0; +} + +#include "myprocess.moc" diff --git a/kommander/widget/myprocess.h b/kommander/widget/myprocess.h new file mode 100644 index 00000000..8487f170 --- /dev/null +++ b/kommander/widget/myprocess.h @@ -0,0 +1,58 @@ +/*************************************************************************** + myprocess.h - Wrapper class for running shell processes + ------------------- + copyright : (C) 2002 by Marc Britton + email : consume@optusnet.com.au + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ +#ifndef _HAVE_MYPROCESS_H_ +#define _HAVE_MYPROCESS_H_ + +/* KDE INCLUDES */ +#include <kprocess.h> + +/* QT INCLUDES */ +#include <qstring.h> +#include <qobject.h> +#include "kommander_export.h" + +class KommanderWidget; + +class KOMMANDER_EXPORT MyProcess : public QObject +{ + Q_OBJECT +public: + MyProcess(const KommanderWidget *); + // Run given command, using a_shell as a shell (this can be overridden by shebang in the first line) + // Process is run in blocking mode. + QString run(const QString& a_command, const QString& a_shell = "/bin/sh"); + // Kill running process + void cancel(); + void setBlocking(bool blocking); + bool isBlocking() const; + QString output() const; +signals: + void processExited(MyProcess*); + void processReceivedStdout(MyProcess*, char*, int); +private slots: + void slotReceivedStdout(KProcess*, char*, int); + void slotProcessExited(KProcess*); +protected: + const KommanderWidget *m_atw; + QString m_output; + QCString m_input; + bool m_loopStarted; + bool m_blocking; + bool m_handleOutput; + KProcess* mProcess; +}; + +#endif diff --git a/kommander/widget/parsenode.cpp b/kommander/widget/parsenode.cpp new file mode 100644 index 00000000..09ad66a7 --- /dev/null +++ b/kommander/widget/parsenode.cpp @@ -0,0 +1,262 @@ +/*************************************************************************** + parsenode.cpp - Single parsed item + ------------------- + copyright : (C) 2004 Michal Rudolf <mrudolf@kdewebdwev.org> + + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "parsenode.h" + +using namespace Parse; + +ParseNode::ParseNode() : m_type(ValueNone), m_context(-1) +{ +} + +ParseNode::ParseNode(const QString& s) : m_type(ValueString), m_string(s), m_context(-1) +{ +} + +ParseNode::ParseNode(int i) : m_type(ValueInt), m_int(i), m_context(-1) +{ +} + +ParseNode::ParseNode(uint i) : m_type(ValueInt), m_int(i), m_context(-1) +{ +} + +ParseNode::ParseNode(double d) : m_type(ValueDouble), m_double(d), m_context(-1) +{ +} + +ParseNode::ParseNode(Keyword k) : m_type(ValueKeyword), m_keyword(k), m_string(QString::null), m_context(-1) +{ +} + +ParseNode::ParseNode(Keyword k, const QString& name) : m_type(ValueKeyword), m_keyword(k), m_context(-1) +{ + m_string = (k == Variable) ? name : QString::null; +} + +ParseNode ParseNode::error(const QString& s) +{ + ParseNode p; + p.m_string = s; + p.m_type = ValueError; + return p; +} + +ValueType ParseNode::type() const +{ + return m_type; +} + +Keyword ParseNode::keyword() const +{ + return isKeyword() ? m_keyword : Invalid; +} + +QString ParseNode::toString() const +{ + switch(type()) { + case ValueString: return m_string; + case ValueInt: return QString::number(m_int); + case ValueDouble: return QString::number(m_double); + default: return QString(); + } +} + +int ParseNode::toInt() const +{ + switch(type()) { + case ValueInt: return m_int; + case ValueDouble: return (int)m_double; + case ValueString: return m_string.toInt(); + default: return 0; + } +} + +double ParseNode::toDouble() const +{ + switch(type()) { + case ValueDouble: return m_double; + case ValueInt: return (double)m_int; + case ValueString: return m_string.toDouble(); + default: return 0.0; + } +} + +bool ParseNode::toBool() const +{ + return toInt() != 0; +} + +bool ParseNode::isValid() const +{ + return type() != ValueError; +} + +bool ParseNode::isKeyword() const +{ + return type() == ValueKeyword; +} + +bool ParseNode::isKeyword(Keyword k) const +{ + return type() == ValueKeyword && keyword() == k; +} + +bool ParseNode::isVariable() const +{ + return type() == ValueKeyword && keyword() == Variable; +} + +bool ParseNode::isArray() const +{ + return type() == ValueKeyword && keyword() == Array; +} + +QString ParseNode::variableName() const +{ + return isVariable() ? m_string : QString(); +} + +QString ParseNode::arrayName() const +{ + return isArray() ? m_string : QString(); +} + +QString ParseNode::errorMessage() const +{ + return isValid() ? QString() : m_string; +} + + +ValueType ParseNode::commonType(const ParseNode& p) const +{ + if (type() == ValueKeyword || p.type() == ValueKeyword) + return ValueKeyword; + else if (type() == ValueString || p.type() == ValueString) + return ValueString; + else if (type() == ValueDouble || p.type() == ValueDouble) + return ValueDouble; + return ValueInt; +} + +static int parsenode_compareDouble(const double A, const double B) +{ + return A<B ? -1 : (A==B ? 0 : 1); +} + +int ParseNode::compare(const ParseNode& p) const +{ + switch (commonType(p)) + { + case ValueString: return toString().compare(p.toString()); + case ValueDouble: return parsenode_compareDouble(toDouble(), p.toDouble()); + case ValueInt: return toInt() - p.toInt(); + default: return 0; + } +} + +bool ParseNode::operator==(int i) const +{ + return toInt() == i; +} + +bool ParseNode::operator==(bool b) const +{ + return toBool() == b; +} + +bool ParseNode::operator==(const QString& s) const +{ + return toString() == s; +} + +bool ParseNode::operator==(const ParseNode& p) const +{ + return compare(p) == 0; +} + +bool ParseNode::operator!=(const ParseNode& p) const +{ + return compare(p) != 0; +} + +bool ParseNode::operator>=(const ParseNode& p) const +{ + return compare(p) >= 0; +} + +bool ParseNode::operator<=(const ParseNode& p) const +{ + return compare(p) <= 0; +} + +bool ParseNode::operator>(const ParseNode& p) const +{ + return compare(p) > 0; +} + +bool ParseNode::operator<(const ParseNode& p) const +{ + return compare(p) < 0; +} + +void ParseNode::setValue(int i) +{ + m_type = ValueInt; + m_int = i; +} + +void ParseNode::setValue(double d) +{ + m_type = ValueDouble; + m_double = d; +} + +void ParseNode::setValue(const QString& s) +{ + m_type = ValueString; + m_string = s; +} + +void ParseNode::setVariable(const QString& name) +{ + m_type = ValueKeyword; + m_keyword = Variable; + m_string = name; +} + +void ParseNode::setArray(const QString& name) +{ + m_type = ValueKeyword; + m_keyword = Array; + m_string = name; +} + +bool ParseNode::isValue() const +{ + return m_type <= ValueValue; +} + +void ParseNode::setContext(int c) +{ + m_context = c; +} + +int ParseNode::context() const +{ + return m_context; +} + diff --git a/kommander/widget/parsenode.h b/kommander/widget/parsenode.h new file mode 100644 index 00000000..305b0998 --- /dev/null +++ b/kommander/widget/parsenode.h @@ -0,0 +1,129 @@ +/*************************************************************************** + parsenode.cpp - Single parsed item + ------------------- + copyright : (C) 2004 Michal Rudolf <mrudolf@kdewebdwev.org> + + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef _HAVE_PARSENODE_H_ +#define _HAVE_PARSENODE_H_ + +#include <qstring.h> + +namespace Parse +{ + enum Keyword {For, To, Step, End, While, Do, Foreach, In, If, Then, Else, Elseif, Endif, Switch, Case, + Break, Continue, Exit, Dot, Semicolon, Comma, Assign, Less, LessEqual, Greater, GreaterEqual, Equal, NotEqual, + Not, And, Or, False, True, LeftParenthesis, RightParenthesis, LeftBracket, DoubleBracket, RightBracket, LeftCurlyBrace, RightCurlyBrace, PlusEqual, MinusEqual, Increment, Decrement, + Plus, Minus, Multiply, Divide, Mod, LastRealKeyword = Mod, Variable, Invalid, Array, Matrix, ArrKeyVal}; + + enum KeywordGroup {GroupComparison, GroupAdd, GroupMultiply, GroupMisc}; + enum ValueType {ValueString, ValueInt, ValueDouble, ValueValue = ValueDouble, ValueKeyword, + ValueNone, ValueError}; + + enum Mode{Execute, CheckOnly}; + + enum Flow{FlowStandard, FlowContinue, FlowBreak, FlowExit}; +} + +class ParseNode { +public: + /* Default constructor */ + ParseNode(); + /* Create node from string */ + ParseNode(const QString& s); + /* Create node from integer */ + ParseNode(int i); + /* Create node from integer */ + ParseNode(uint i); + /* Create node from double */ + ParseNode(double d); + /* Create node from keyword */ + ParseNode(Parse::Keyword k); + /* Create node from keyword and variable name */ + ParseNode(Parse::Keyword k, const QString& s); + /* Create error node with optional error message */ + static ParseNode error(const QString& s); + + /* Return current type */ + Parse::ValueType type() const; + /* Return current keyword if appropriate */ + Parse::Keyword keyword() const; + /* Cast value to string */ + QString toString() const; + /* Cast value to integer */ + int toInt() const; + /* Cast value to double */ + double toDouble() const; + /* Cast value to bool */ + bool toBool() const; + /* Check if a value is valid */ + bool isValid() const; + /* Check if current value is a keyword */ + bool isKeyword() const; + /* Check if current value is a given keyword */ + bool isKeyword(Parse::Keyword k) const; + /* Check if current value is a variable */ + bool isVariable() const; + /* Check if current value is an Array */ + bool isArray() const; + /* Return the name of variable */ + QString variableName() const; + /* Return the name of array */ + QString arrayName() const; + /* Return error message if applicable */ + QString errorMessage() const; + /* Calculate common type for two nodes */ + Parse::ValueType commonType(const ParseNode& p) const; + /* Find common type and compare values */ + int compare(const ParseNode& p) const; + /* Various comparing functions */ + bool operator==(int i) const; + bool operator==(bool b) const; + bool operator==(const QString& s) const; + bool operator==(const ParseNode& p) const; + bool operator!=(const ParseNode& p) const; + bool operator>=(const ParseNode& p) const; + bool operator<=(const ParseNode& p) const; + bool operator>(const ParseNode& p) const; + bool operator<(const ParseNode& p) const; + /* set value as integer */ + void setValue(int i); + /* set value as double */ + void setValue(double d); + /* set value as string */ + void setValue(const QString& s); + /* set value as variable */ + void setVariable(const QString& name); + /* set value as array */ + void setArray(const QString& name); + /* check if it is correct value */ + bool isValue() const; + /* for setting some context information, f. e. for bug reporting */ + void setContext(int c); + /* get current context */ + int context() const; + +private: + Parse::ValueType m_type; + union { + int m_int; + double m_double; + Parse::Keyword m_keyword; + }; + QString m_string; + int m_context; +}; + + +#endif + diff --git a/kommander/widget/parser.cpp b/kommander/widget/parser.cpp new file mode 100644 index 00000000..9bc9637b --- /dev/null +++ b/kommander/widget/parser.cpp @@ -0,0 +1,1243 @@ +/*************************************************************************** + parser.cpp - Internal parser + ------------------- + copyright : (C) 2004-2006 Michal Rudolf <mrudolf@kdewebdwev.org> + + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include <klocale.h> + +#include "parser.h" +#include "parserdata.h" +#include "kommanderwidget.h" + +using namespace Parse; + +QString unescape(QString s) +{ + return s.replace("\\\"", "\"").replace("\\t", "\t").replace("\\n", "\n").replace("\\\\", "\\"); +} + +Parser::Parser(ParserData* pData) : m_data(pData), m_start(0), m_error(QString::null), m_errorPosition(0), + m_widget(0) +{ +} + +Parser::Parser(ParserData* pData, const QString& expr) : m_data(pData), m_start(0), + m_error(QString::null), m_errorPosition(0), m_widget(0) +{ + setString(expr); +} + +bool Parser::setString(const QString& s) +{ + reset(); + m_parts.clear(); + uint lines = 0; + uint start = 0; + uint i = 0; + while (start < s.length()) + { + if (s[start].isSpace() && s[start] != '\n') + start++; + else if (s[start] == '\\' && start < s.length() - 1 && s[start+1] == '\n') + start += 2; + else if (s[start] == ';') + { + insertNode(Semicolon, lines); + start++; + } + else if (s[start] == '\n') + { + if (m_parts.count() && !m_parts.last().isKeyword(Semicolon)) + insertNode(Semicolon, lines); + lines++; + start++; + } + else if (s[start] == '\"') // quoted string: "abc" + { + bool escaped = false; + for (i = start + 1; i < s.length() && (s[i] != '\"' || s[i-1] == '\\'); i++) + if (!escaped) + escaped = s[i] == '\\'; + if (escaped) + insertNode(unescape(s.mid(start + 1, i - start - 1)), lines); + else + insertNode(s.mid(start + 1, i - start - 1), lines); + start = i+1; + } + else if (s[start].isDigit()) // number: 1000 or 2.45 + { + bool decimal = false; + for (i = start+1; s[i].isDigit() || (!decimal && s[i] == QChar('.')); i++) + if (s[i] == '.') + decimal = true; + if (decimal) + insertNode(s.mid(start, i - start).toDouble(), lines); + else + insertNode(s.mid(start, i - start).toInt(), lines); + start = i; + } + else if (s[start].isLetter() || s[start] == '_') // keyword + { + for (i = start+1; s[i].isLetterOrNumber() || s[i] == '_'; i++) + ; + QString name = s.mid(start, i - start); + insertNode(ParseNode(m_data->stringToKeyword(name), name), lines); + start = i; + } // comment + else if (s[start] == '#' || (s[start] == '/' && start < s.length() +1 && s[start+1] == '/')) + { + while (start < s.length() && s[start] != '\n') + start++; + } // enable /* */ block comments + else if (s[start] == '/' && start < s.length() +1 && s[start+1] == '*') + { + start += 2; + while (start < s.length() +1 && !(s[start] == '*' && s[start+1] == '/')) + { + start++; + } + start += 2; + } // special keyword: <> + else if (m_data->stringToKeyword(s.mid(start, 2)) <= LastRealKeyword) + { + insertNode(m_data->stringToKeyword(s.mid(start, 2)), lines); + start += 2; + } // special keyword: < + else if (m_data->stringToKeyword(s.mid(start, 1)) <= LastRealKeyword) + { + insertNode(m_data->stringToKeyword(s.mid(start, 1)), lines); + start++; + } + else // Bad character + { + insertNode(s.mid(start, 1), lines); + setError(i18n("Invalid character: '%1'").arg(s[start]), m_parts.count()-1); + return false; + } + } + return true; +} + +void Parser::setWidget(KommanderWidget* w) +{ + m_widget = w; +} + +void Parser::insertNode(ParseNode p, int line) +{ + p.setContext(line); + m_parts.append(p); +} + +QString Parser::errorMessage() const +{ + return m_error; +} + +QString Parser::function(ParserData* data, const QString& name, const QStringList& params) +{ + ParameterList par; + for (QStringList::ConstIterator Iter = params.begin(); Iter != params.end(); ++Iter) + par.append(*Iter); + Function f = data->function(name); + return f.execute(0, par).toString(); +} + +QString Parser::expression(Mode mode) +{ + reset(); + ParseNode p = parseExpression(mode); + if (!isError()) + return p.toString(); + else + return QString(); +} + +bool Parser::isError() const +{ + return !m_error.isNull(); +} + + +bool Parser::command(Mode mode) +{ + reset(); + parseCommand(mode); + return !isError(); +} + +bool Parser::parse(Mode mode) +{ + reset(); + parseBlock(mode); + return !isError(); +} + +int Parser::errorLine() const +{ + if (isError()) + return m_parts[m_errorPosition].context(); + else + return -1; +} + +ParseNode Parser::parseConstant(Parse::Mode) +{ + ParseNode p = next(); + m_start++; + if (!p.isValue()) + { + setError(i18n("Constant value expected")); + return ParseNode(); + } + return p; +} +//attempting to allow assign or copy of array, so far with no joy +ParseNode Parser::parseValue(Mode mode) +{ + ParseNode p = next(); + //QString p2 = QString(p.toString()); + //qDebug("parseValue p2 = "+p2); + if (isFunction()) + return parseFunction(mode); + else if (isWidget()) + return parseWidget(mode); + else if (tryVariable(CheckOnly)) + { + if (tryKeyword(LeftBracket, CheckOnly)) + { + QString index = parseValue(mode).toString(); + if (tryKeyword(DoubleBracket, CheckOnly)) + {//2D array "matrix" + QString index2 = parseValue(mode).toString(); + tryKeyword(RightBracket); + QString arr = p.variableName(); + return matrixValue(arr, index, index2); + } + tryKeyword(RightBracket); + QString arr = p.variableName(); + return arrayValue(arr, index); + } + else if (tryKeyword(Dot, CheckOnly)) + { + QString value = variable(p.variableName()).toString(); + if (m_widget && m_widget->isWidget(value)) + { + m_start--; + return parseWidget(mode, value); + }else if (mode == Execute) + { + setError(i18n("'%1' (%2) is not a widget").arg(p.variableName()).arg(variable(p.variableName()).toString())); + return ParseNode(); + } else + { + //this means it looks like a widget, but it is unknown. As we only check + //the syntax, we should ignore the error an parse as a widget. + m_start = m_start - 2; + return parseWidget(mode); + } + } + else if (tryKeyword(LeftParenthesis, CheckOnly)) + { + setError(i18n("'%1' is not a function").arg(p.variableName())); + return ParseNode(); + } + else + p = variable(p.variableName()); + } + else if (tryKeyword(False, CheckOnly)) + return ParseNode(0); + else if (tryKeyword(True, CheckOnly)) + return ParseNode(1); +/* else if (isArray(p2)) + { + qDebug("returning array fpr p2"); + return p2; + }*/ + else if (p.isKeyword()) + setError(i18n("Expected value")); + else // single value + m_start++; + return p; +} + +ParseNode Parser::parseMultiply(Mode mode) +{ + ParseNode p = parseParenthesis(mode); + while (m_data->keywordGroup(next().keyword()) == GroupMultiply) + { + Keyword k = next().keyword(); + m_start++; + ParseNode p2 = parseParenthesis(mode); + ValueType type = p.commonType(p2); + if (mode == Execute) + { + if (k == Multiply) + if (type == ValueInt) + p = p.toInt() * p2.toInt(); + else + p = p.toDouble() * p2.toDouble(); + else if (k == Divide) + { + if (p2.toDouble() == 0.0) + setError(i18n("Divide by zero")); + else + if (type == ValueInt) + p = p.toInt() / p2.toInt(); + else + p = p.toDouble() / p2.toDouble(); + } + else /* k == Mod */ + { + if (p2.toInt() == 0) + setError(i18n("Divide by zero")); + else + p = p.toInt() - p.toInt() / p2.toInt() * p2.toInt(); + } + } + } + return p; +} + +ParseNode Parser::parseAdd(Mode mode) +{ + ParseNode p = parseMultiply(mode); + while (m_data->keywordGroup(next().keyword()) == GroupAdd) + { + Keyword k = next().keyword(); + m_start++; + ParseNode p2 = parseMultiply(mode); + ValueType type = p.commonType(p2); + if (mode == Execute) + { + if (k == Plus) + if (type == ValueString) + p = QString(p.toString() + p2.toString()); + else if (type == ValueDouble) + p = p.toDouble() + p2.toDouble(); + else + p = p.toInt() + p2.toInt(); + else /* k == Minus */ + if (type == ValueDouble) + p = p.toDouble() - p2.toDouble(); + else + p = p.toInt() - p2.toInt(); + } + } + return p; +} + +ParseNode Parser::parseSignedNumber(Mode mode) +{ + if (tryKeyword(Minus, CheckOnly)) + { + ParseNode p = parseValue(mode); + if (p.type() == ValueDouble) + return ParseNode(-p.toDouble()); + else + return ParseNode(-p.toInt()); + } + else + return parseValue(mode); +} + +ParseNode Parser::parseComparison(Mode mode) +{ + ParseNode p1 = parseAdd(mode); + if (m_data->keywordGroup(next().keyword()) == GroupComparison) + { + Keyword k = next().keyword(); + m_start++; + ParseNode p2 = parseAdd(mode); + switch (k) { + case Less: return ParseNode(p1 < p2); + case LessEqual: return ParseNode(p1 <= p2); + case Equal: return ParseNode(p1 == p2); + case NotEqual: return ParseNode(p1 != p2); + case GreaterEqual: return ParseNode(p1 >= p2); + case Greater: return ParseNode(p1 > p2); + default: ; + } + } + return p1; +} + +ParseNode Parser::parseParenthesis(Mode mode) +{ + if (tryKeyword(LeftParenthesis, CheckOnly)) + { + ParseNode p = parseExpression(mode); + tryKeyword(RightParenthesis); + return p; + } + else + return parseSignedNumber(mode); +} + + +ParseNode Parser::parseNot(Mode mode) +{ + if (tryKeyword(Not, CheckOnly)) + return !parseComparison(mode).toBool(); + else + return parseComparison(mode); +} + +ParseNode Parser::parseAnd(Mode mode) +{ + ParseNode p = parseNot(mode); + while (tryKeyword(And, CheckOnly)) + { + if (p == false) + parseNot(CheckOnly); + else + p = parseNot(mode); + } + return p; +} + +ParseNode Parser::parseOr(Mode mode) +{ + ParseNode p = parseAnd(mode); + while (tryKeyword(Or, CheckOnly)) + { + if (p == true) + parseAnd(CheckOnly); + else + p = parseAnd(mode); + } + return p; +} + +ParseNode Parser::parseCondition(Mode mode) +{ + return parseOr(mode); +} + +ParseNode Parser::parseExpression(Mode mode) +{ + return parseOr(mode); +} + +ParseNode Parser::parseFunction(Mode mode) +{ + int pos = m_start; + QString name = next().variableName(); + //qDebug("Parsing function: "+name); + Function f = m_data->function(name); + m_start++; + ParameterList params; + + if (tryKeyword(LeftParenthesis, CheckOnly) && !tryKeyword(RightParenthesis, CheckOnly)) + { + do { + params.append(parseExpression(mode)); + } while (tryKeyword(Comma, CheckOnly)); + tryKeyword(RightParenthesis); + } + if (f.minArgs() > params.count()) + setError(i18n("in function '%1': %2").arg(name).arg(i18n("too few parameters")), pos); + else if (f.maxArgs() < params.count()) + setError(i18n("in function '%1': %2").arg(name).arg(i18n("too many parameters")), pos); + else if (mode == Execute) + { + ParseNode p = f.execute(this, params); + if (!p.isValid()) + { + setError(i18n("in function '%1': %2").arg(name).arg(p.errorMessage()), pos); + return ParseNode(); + } + else + return p; + } + return ParseNode(); +} + +ParseNode Parser::parseWidget(Mode mode, const QString &widgetName) +{ + int pos = m_start; + QString widget; + if (widgetName.isNull()) + widget = nextVariable(mode); + else + widget = widgetName; + Function f = m_data->function("internalDcop"); + + if (!tryKeyword(Dot)) + return ParseNode(); + QString var = nextVariable(); + if (var.isNull()) + return ParseNode(); + ParameterList params; + params.append(var); + params.append(widget); + + if (tryKeyword(LeftParenthesis, CheckOnly) && !tryKeyword(RightParenthesis, CheckOnly)) + { + do { + params.append(parseExpression(mode)); + } while (tryKeyword(Comma, CheckOnly)); + tryKeyword(RightParenthesis); + } + if (mode == Execute) + { + ParseNode p = f.execute(this, params); + if (!p.isValid()) + { + setError(i18n("in widget function '%1.%2': %3").arg(widget).arg(var).arg(p.errorMessage()), pos); + return ParseNode(); + } + else + return p; + } + return ParseNode(); +} + + +ParseNode Parser::parseAssignment(Mode mode) +{ + QString var = nextVariable(); + //qDebug("var = "+var+" Pos:"+QString::number(m_start)); + if (tryKeyword(LeftBracket, CheckOnly)) + { + QString index = parseValue(mode).toString(); + if (tryKeyword(DoubleBracket, CheckOnly)) + {//2D array "matrix" + ParseNode p1 = next(); //move along... + QString index2 = parseValue(mode).toString(); + tryKeyword(RightBracket); + p1 = next(); + ParseNode p2 = matrixValue(var, index, index2); + if (p1.isKeyword(PlusEqual)) + { + tryKeyword(PlusEqual); + ParseNode p = parseExpression(mode); + if (mode == Execute) + { + if (p2.type() == ValueString) + p = QString(p2.toString() + p.toString()); + else if (p2.type() == ValueDouble) + p = p2.toDouble() + p.toDouble(); + else + p = p2.toInt() + p.toInt(); + setMatrix(var, index, index2, p); + } + } + else if (p1.isKeyword(MinusEqual)) + { + tryKeyword(MinusEqual); + ParseNode p = parseExpression(mode); + if (mode == Execute) + { + if (p2.type() == ValueDouble) + p = p2.toDouble() - p.toDouble(); + else + p = p2.toInt() - p.toInt(); + setMatrix(var, index, index2, p); + } + } + else if (p1.isKeyword(Increment)) + { + tryKeyword(Increment); + if (mode == Execute) + { + p2 = p2.toInt() + 1; + setMatrix(var, index, index2, p2); + } + } + else if (p1.isKeyword(Decrement)) + { + tryKeyword(Decrement); + if (mode == Execute) + { + p2 = p2.toInt() - 1; + setMatrix(var, index, index2, p2); + } + } + else + { + tryKeyword(Assign); + ParseNode p = parseExpression(mode); + if (mode == Execute) + setMatrix(var, index, index2, p); + } + } + else + { + tryKeyword(RightBracket); + ParseNode p1 = next(); + // seems awkward and pedantic but array values are now handled like variables + // for special assign with oparator + ParseNode p2 = arrayValue(var, index); + if (p1.isKeyword(PlusEqual)) + { + tryKeyword(PlusEqual); + ParseNode p = parseExpression(mode); + if (mode == Execute) + { + if (p2.type() == ValueString) + p = QString(p2.toString() + p.toString()); + else if (p2.type() == ValueDouble) + p = p2.toDouble() + p.toDouble(); + else + p = p2.toInt() + p.toInt(); + setArray(var, index, p); + } + } + else if (p1.isKeyword(MinusEqual)) + { + tryKeyword(MinusEqual); + ParseNode p = parseExpression(mode); + if (mode == Execute) + { + if (p2.type() == ValueDouble) + p = p2.toDouble() - p.toDouble(); + else + p = p2.toInt() - p.toInt(); + setArray(var, index, p); + } + } + else if (p1.isKeyword(Increment)) + { + tryKeyword(Increment); + if (mode == Execute) + { + p2 = p2.toInt() + 1; + setArray(var, index, p2); + } + } + else if (p1.isKeyword(Decrement)) + { + tryKeyword(Decrement); + if (mode == Execute) + { + p2 = p2.toInt() - 1; + setArray(var, index, p2); + } + } + else + { + tryKeyword(Assign); + ParseNode p = parseExpression(mode); + if (mode == Execute) + setArray(var, index, p); + } + } + } + else if (tryKeyword(Assign, CheckOnly)) + { + ParseNode p = parseExpression(mode); + if (mode == Execute) + { + setVariable(var, p); + } + } + else if (tryKeyword(PlusEqual, CheckOnly)) + { + ParseNode p = parseExpression(mode); + if (mode == Execute) + { + ParseNode p2 = variable(var); + if (p2.type() == ValueString) + p = QString(p2.toString() + p.toString()); + else if (p2.type() == ValueDouble) + p = p2.toDouble() + p.toDouble(); + else + p = p2.toInt() + p.toInt(); + setVariable(var, p); + } + } + else if (tryKeyword(MinusEqual, CheckOnly)) + { + ParseNode p = parseExpression(mode); + if (mode == Execute) + { + ParseNode p2 = variable(var); + if (p2.type() == ValueDouble) + p = p2.toDouble() - p.toDouble(); + else + p = p2.toInt() - p.toInt(); + setVariable(var, p); + } + } + else if (tryKeyword(Increment, CheckOnly)) + { + //ParseNode p = parseExpression(mode); + if (mode == Execute) + { + ParseNode p = variable(var); + p = p.toInt() + 1; + setVariable(var, p); + } + } + else if (tryKeyword(Decrement, CheckOnly)) + { + //ParseNode p = parseExpression(mode); + if (mode == Execute) + { + ParseNode p = variable(var); + p = p.toInt() - 1; + setVariable(var, p); + } + } + else if (tryKeyword(Dot, CheckOnly)) + { + QString value = variable(var).toString(); + if (m_widget && m_widget->isWidget(value)) + { + m_start--; + return parseWidget(mode, value); + } else + if (mode == CheckOnly) + { + //this means it looks like a widget, but it is unknown. As we only check + //the syntax, we should ignore the error an parse as a widget. + m_start = m_start - 2; + return parseWidget(mode); + } else + setError(i18n("'%1' is not a widget").arg(var)); + } + else if (tryKeyword(LeftParenthesis, CheckOnly)) + setError(i18n("'%1' is not a function").arg(var)); + else + setError(i18n("Unexpected symbol after variable '%1'").arg(var)); + + return ParseNode(); +} + +Flow Parser::parseIf(Mode mode) +{ + ParseNode p = next(); + Flow flow = FlowStandard; + bool matched = false; + bool thenFound = false; + do { + m_start++; + Mode m = matched ? CheckOnly : mode; + p = parseCondition(m); + thenFound = tryKeyword(Then, CheckOnly); + if (!thenFound) + tryKeyword(LeftCurlyBrace); + bool condition = !matched && p.toBool(); + if (condition) + { + flow = parseBlock(mode); + if (flow == FlowExit) + return flow; + } + else + parseBlock(CheckOnly); + matched = matched || p.toBool(); + if (!thenFound) + tryKeyword(RightCurlyBrace); + } while (nextElseIf() == true); + bool braceFound = false; + if (tryKeyword(Else, CheckOnly)) + { + braceFound = tryKeyword(LeftCurlyBrace, CheckOnly); + if (!matched) + flow = parseBlock(mode); + else + parseBlock(CheckOnly); + } + if (braceFound) + tryKeyword(RightCurlyBrace); + if (thenFound) + tryKeyword(Endif); + return flow; +} + +bool Parser::nextElseIf() +{ + ParseNode p1 = next(); + if (p1.isKeyword(Elseif)) + return true; + else + { + ParseNode p2 = next(); + if (p1.isKeyword(Else) && p2.isKeyword(If) ) + return true; + } + return false; +} + +Parse::Flow Parser::parseWhile(Mode mode) +{ + m_start++; + int start = m_start; + bool running = true; + Parse::Flow flow = FlowStandard; + bool doFound = false; + while (running) + { + m_start = start; + ParseNode p = parseCondition(mode); + doFound = tryKeyword(Do, CheckOnly); + if (!doFound && !tryKeyword(LeftCurlyBrace)) + break; + running = p.toBool(); + flow = parseBlock(running ? mode : CheckOnly); + if ( flow == FlowBreak || flow == FlowExit) + break; + } + if (flow != FlowExit) + { + if (doFound) + tryKeyword(End); + else + tryKeyword(RightCurlyBrace); + return FlowStandard; + } + else + return FlowExit; +} + +Parse::Flow Parser::parseFor(Mode mode) +{ + m_start++; + QString var = nextVariable(); + tryKeyword(Assign); + int start = parseExpression(mode).toInt(); + tryKeyword(To); + int end = parseExpression(mode).toInt(); + int step = 1; + if (tryKeyword(Step, CheckOnly)) + step = parseExpression(mode).toInt(); + + bool doFound = tryKeyword(Do, CheckOnly); + if (!doFound) + tryKeyword(LeftCurlyBrace); + int block = m_start; + Parse::Flow flow = FlowStandard; + if (end >= start && step > 0) + { + for (int i = start; i <= end; i+=step) + { + m_start = block; + setVariable(var, ParseNode(i)); + flow = parseBlock(mode); + if (flow == FlowBreak || flow == FlowExit) + break; + } + } else if (end <= start && step < 0) + { + for (int i = start; i >= end; i+=step) + { + m_start = block; + setVariable(var, ParseNode(i)); + flow = parseBlock(mode); + if (flow == FlowBreak || flow == FlowExit) + break; + } + } else + parseBlock(Parse::CheckOnly); + if (flow != FlowExit) + { + if (doFound) + tryKeyword(End); + else + tryKeyword(RightCurlyBrace); + return FlowStandard; + } + else + return FlowExit; +} + +Parse::Flow Parser::parseForeach(Mode mode) +{ + m_start++; + QString var = nextVariable(); + QString var2 = ""; + bool matrixfound = tryKeyword(ArrKeyVal, CheckOnly); + if (matrixfound == true) + { + m_start--; + tryKeyword(ArrKeyVal); + var2 = nextVariable(); + } + tryKeyword(In); + QString arr = nextVariable(); + bool doFound = tryKeyword(Do, CheckOnly); + if (!doFound) + tryKeyword(LeftCurlyBrace); + int start = m_start; + Parse::Flow flow = FlowStandard; + if (isArray(arr) && array(arr).count() && !matrixfound) + { + const QMap<QString, ParseNode> A = array(arr); + for (QMapConstIterator<QString, ParseNode> It = A.begin(); It != A.end(); ++It) + { + m_start = start; + setVariable(var, It.key()); + flow = parseBlock(mode); + if (flow == FlowBreak || flow == FlowExit) + break; + } + } + else if (isMatrix(arr) && matrix(arr).count() ) + { + const QMap<QString, QMap<QString, ParseNode> > A = matrix(arr); + for (QMapConstIterator<QString, QMap<QString, ParseNode> > It = A.begin(); It != A.end(); ++It) + { + m_start = start; + setVariable(var, It.key()); + if (matrixfound == true) + { + const QMap<QString, ParseNode> B = It.data(); + for (QMapConstIterator<QString, ParseNode> It2 = B.begin(); It2 != B.end(); ++It2 ) + { + m_start = start; + setVariable(var2, It2.key()); + flow = parseBlock(mode); + if (flow == FlowBreak || flow == FlowExit) + break; + } + } + else + { + flow = parseBlock(mode); + if (flow == FlowBreak || flow == FlowExit) + break; + } + } + } + else + parseBlock(CheckOnly); + if (flow != FlowExit) + { + if (doFound) + tryKeyword(End); + else + tryKeyword(RightCurlyBrace); + return FlowStandard; + } + else + return FlowExit; +} + +void Parser::parseSwitch(Mode mode) +{ + m_start++; + QString var = nextVariable(); + ParseNode caseValue = variable(var); + bool executed = false; + bool braceFound = false; + braceFound = tryKeyword(LeftCurlyBrace, CheckOnly); + tryKeyword(Semicolon, CheckOnly); + while (tryKeyword(Case, CheckOnly)) + { + ParseNode p = parseConstant(); + bool matched = mode == Execute && p == caseValue; + parseBlock(matched ? Execute : CheckOnly); + if (matched) + executed = true; + } + if (tryKeyword(Else, CheckOnly)) + parseBlock(executed ? CheckOnly : mode); + if (!braceFound) + tryKeyword(End); + else + tryKeyword(RightCurlyBrace); +} + +Flow Parser::parseCommand(Mode mode) +{ + ParseNode p = next(); + QString p2 = p.toString(); + //qDebug("Parsing command: "+p2); + if (next().isKeyword(If)) + return parseIf(mode); + else if (next().isKeyword(While)) + return parseWhile(mode); + else if (next().isKeyword(For)) + return parseFor(mode); + else if (next().isKeyword(Foreach)) + return parseForeach(mode); + else if (next().isKeyword(Switch)) + parseSwitch(mode); + else if (tryKeyword(Continue, CheckOnly)) + return FlowContinue; + else if (tryKeyword(Break, CheckOnly)) + return FlowBreak; + else if (isFunction()) + { + QString name = next().variableName(); + parseFunction(mode); + if (name == "return" && mode == Execute) + return FlowExit; + } + else if (isWidget()) + parseWidget(mode); + else if (next().isVariable()) + parseAssignment(mode); + else if (tryKeyword(Exit, CheckOnly)) + { + if (mode == Execute) + return FlowExit; + } + return FlowStandard; +} + +Flow Parser::parseBlock(Mode mode) +{ + Flow flow = parseCommand(mode); + while (tryKeyword(Semicolon, CheckOnly) && flow != FlowExit) + { + if (flow == FlowStandard) + flow = parseCommand(mode); + else + parseCommand(CheckOnly); + } + return flow; +} + + + + +ParseNode Parser::next() const +{ + if (isError() || m_start >= m_parts.count()) + return ParseNode(); + return m_parts[m_start]; +} + +bool Parser::tryKeyword(Keyword k, Mode mode) +{ + if (next().isKeyword(k)) + { + m_start++; + return true; + } + if (mode == Execute) + { + if (k == Dot) + setError(i18n("Expected '%1'<br><br>Possible cause of the error is having a variable with the same name as a widget").arg(m_data->keywordToString(k))); + else + setError(i18n("Expected '%1' got '%2'.").arg(m_data->keywordToString(k)).arg(next().toString())); + } + return false; +} + +bool Parser::tryVariable(Mode mode) +{ + if (next().isVariable()) + { + QString name = next().variableName(); + m_start++; + return true; + } + if (mode == Execute) + setError(i18n("Expected variable")); + return false; +} + +QString Parser::nextVariable(Mode mode) +{ + if (next().isVariable()) + { + QString name = next().variableName(); + m_start++; + return name; + } + else if (mode == Execute) + setError(i18n("Expected variable")); + return QString(); +} + + +bool Parser::isFunction() const +{ + return next().isVariable() && m_data->isFunction(next().variableName()); +} + +bool Parser::isWidget() const +{ + return m_widget && next().isVariable() && m_widget->isWidget(next().variableName()); +} + +void Parser::reset() +{ + m_start = 0; + m_error = QString::null; + m_errorPosition = 0; +} + +void Parser::setError(const QString& msg) +{ + setError(msg, m_start); +} + +void Parser::setError(const QString& msg, int pos) +{ + if (m_error.isNull()) + { + m_errorPosition = pos; + m_error = msg; + } +} + +void Parser::setVariable(const QString& name, ParseNode value) +{ + if (isGlobal(name)) + m_globalVariables[name] = value; + else + m_variables[name] = value; +} + +ParseNode Parser::variable(const QString& name) const +{ + if (isGlobal(name)) + return m_globalVariables.contains(name) ? m_globalVariables[name] : ParseNode(); + else + return m_variables.contains(name) ? m_variables[name] : ParseNode(); +} + +bool Parser::isGlobal(const QString& name) const +{ + return !name.isEmpty() && name[0] == '_'; +} + +bool Parser::isVariable(const QString& name) const +{ + return m_variables.contains(name) || m_globalVariables.contains(name); +} + +void Parser::unsetVariable(const QString& key) +{ + if (isGlobal(key)) + m_globalVariables.remove(key); + else + m_variables.remove(key); +} + +const QMap<QString, ParseNode>& Parser::array(const QString& name) const +{ + if (isGlobal(name)) + return m_globalArrays[name]; + else + return m_arrays[name]; +} + +bool Parser::isArray(const QString& name) const +{ + return m_arrays.contains(name) || m_globalArrays.contains(name); +} + +void Parser::setArray(const QString& name, const QString& key, ParseNode value) +{ + if (isGlobal(name)) + m_globalArrays[name][key] = value; + else + m_arrays[name][key] = value; +} + +void Parser::unsetArray(const QString& name, const QString& key) +{ + if (isGlobal(name)) + { + if (key.isNull()) + m_globalArrays.remove(name); + else if (isArray(name)) + m_globalArrays[name].remove(key); + } + else + { + if (key.isNull()) + m_arrays.remove(name); + else if (isArray(name)) + m_arrays[name].remove(key); + } +} + +ParseNode Parser::arrayValue(const QString& name, const QString& key) const +{ + if (!isArray(name)) + return ParseNode(); + if (isGlobal(name)) + return m_globalArrays[name].contains(key) ? m_globalArrays[name][key] : ParseNode(); + else + return m_arrays[name].contains(key) ? m_arrays[name][key] : ParseNode(); +} + +// 2D arrays "Matrix" +const QMap<QString, QMap<QString, ParseNode> >& Parser::matrix(const QString& name) const +{ + if (isGlobal(name)) + return m_globalMatrices[name]; + else + return m_matrices[name]; +} + +bool Parser::isMatrix(const QString& name) const +{ + return m_matrices.contains(name) || m_globalMatrices.contains(name); +} + +void Parser::setMatrix(const QString& name, const QString& keyr, const QString& keyc, ParseNode value) +{ + if (isGlobal(name)) + m_globalMatrices[name][keyr][keyc] = value; + else + m_matrices[name][keyr][keyc] = value; +} + +void Parser::unsetMatrix(const QString& name, const QString& keyr, const QString& keyc) +{ + if (isGlobal(name)) + { + if (keyr.isNull()) + m_globalMatrices.remove(name); + else if (isMatrix(name)) + { + if (keyc.isNull()) + m_globalMatrices[name].remove(keyr); + else + m_globalMatrices[name][keyr].remove(keyc); + } + } + else + { + if (keyr.isNull()) + m_matrices.remove(name); + else if (isMatrix(name)) + { + if (keyc.isNull()) + m_matrices[name].remove(keyr); + else + m_matrices[name][keyr].remove(keyc); + } + } +} + +ParseNode Parser::matrixValue(const QString& name, const QString& keyr, const QString& keyc) const +{ + if (!isMatrix(name)) + return ParseNode(); + if (isGlobal(name)) + return m_globalMatrices[name].contains(keyr) && m_globalMatrices[name][keyr].contains(keyc) ? m_globalMatrices[name][keyr][keyc] : ParseNode(); + else + return m_matrices[name].contains(keyr) && m_matrices[name][keyr].contains(keyc) ? m_matrices[name][keyr][keyc] : ParseNode(); +} + + + +KommanderWidget* Parser::currentWidget() const +{ + return m_widget; +} + +QMap<QString, ParseNode> Parser::m_globalVariables; +QMap<QString, QMap<QString, ParseNode> > Parser::m_globalArrays; +QMap<QString, QMap<QString, QMap<QString, ParseNode> > > Parser::m_globalMatrices; + diff --git a/kommander/widget/parser.h b/kommander/widget/parser.h new file mode 100644 index 00000000..cc7c6010 --- /dev/null +++ b/kommander/widget/parser.h @@ -0,0 +1,197 @@ +/*************************************************************************** + parser.h - Internal parser + ------------------- + copyright : (C) 2004 Michal Rudolf <mrudolf@kdewebdwev.org> + + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef _HAVE_PARSER_H_ +#define _HAVE_PARSER_H_ + +#include "kommander_export.h" +#include "parsenode.h" + +#include <qvaluevector.h> +#include <qstringlist.h> +#include <qmap.h> + +class KommanderWidget; +class ParserData; + +class Parser +{ +public: + Parser(ParserData* data); + Parser(ParserData* data, const QString& expr); + // set string to parse + bool setString(const QString& s); + // set Kommander widget associated with parser + void setWidget(KommanderWidget* w); + + // parse generic expression + QString expression(Parse::Mode mode = Parse::Execute); + // execute single command; return true if ok + bool command(Parse::Mode mode = Parse::Execute); + // special class method to execute single parser function without creating parser object + static QString function(ParserData* data, const QString& name, const QStringList& params); + // execute whole block; return true if ok + bool parse(Parse::Mode mode = Parse::Execute); + // return line of errorneous node + int errorLine() const; + // return error message + QString errorMessage() const; + + // check if this is a name of standard variable + bool isVariable(const QString& name) const; + // set variable value + void setVariable(const QString& name, ParseNode value); + // unset variable + void unsetVariable(const QString& key); + // get variable value + ParseNode variable(const QString& name) const; + // access associative array + const QMap<QString, ParseNode>& array(const QString& name) const; + // check if this is a name of an array + bool isArray(const QString& name) const; + // set array key + void setArray(const QString& name, const QString& key, ParseNode value); + // unset array key or whole array + void unsetArray(const QString& name, const QString& key = QString::null); + // array value + ParseNode arrayValue(const QString& name, const QString& key) const; + // access 2D array + const QMap<QString, QMap<QString, ParseNode> >& matrix(const QString& name) const; + // check if this is name of a 2D array + bool isMatrix(const QString& name) const; + // set array key + void setMatrix(const QString& name, const QString& keyr, const QString& keyc, ParseNode value); + // unset array key or whole array + void unsetMatrix(const QString& name, const QString& keyr = QString::null, const QString& keyc = QString::null); + // array value + ParseNode matrixValue(const QString& name, const QString& keyr, const QString& keyc) const; + // get associated widget + KommanderWidget* currentWidget() const; + +private: + // parsing function - top-down approach + + // parse const + ParseNode parseConstant(Parse::Mode mode = Parse::Execute); + // parse value (literal or variable) + ParseNode parseValue(Parse::Mode mode = Parse::Execute); + // parse multiplication, division and mod (x*y, x/y, x%y) + ParseNode parseMultiply(Parse::Mode mode = Parse::Execute); + // parse sum (x+y, x-y) + ParseNode parseAdd(Parse::Mode mode = Parse::Execute); + // parse signed numeric (+x, -x) + ParseNode parseSignedNumber(Parse::Mode mode = Parse::Execute); + + /* + // parse string expression + ParseNode parseStringValue(Parse::Mode mode = Parse::Execute); + // parse string concatenation (x+y) + ParseNode parseConcatenation(Parse::Mode mode = Parse::Execute); + */ + + // parse comparisons (x==y, x<y, x>y, x!=y, x<>y, x<=y, x>=y + ParseNode parseComparison(Parse::Mode mode = Parse::Execute); + // parse boolean not (!x, not x) + ParseNode parseNot(Parse::Mode mode = Parse::Execute); + // parse boolean and (x&&y, x and y) + ParseNode parseAnd(Parse::Mode mode = Parse::Execute); + // parse boolean or (x||y, x or y) + ParseNode parseOr(Parse::Mode mode = Parse::Execute); + // parse generic condition + ParseNode parseCondition(Parse::Mode mode = Parse::Execute); + + // parse (x) expression + ParseNode parseParenthesis(Parse::Mode mode = Parse::Execute); + // parse generic expression + ParseNode parseExpression(Parse::Mode mode = Parse::Execute); + // parse parameters + ParseNode parseFunction(Parse::Mode mode = Parse::Execute); + // parse widget function + ParseNode parseWidget(Parse::Mode mode = Parse::Execute, const QString &widgetName = QString::null); + + // parse assignment + ParseNode parseAssignment(Parse::Mode mode = Parse::Execute); + // parse conditional + Parse::Flow parseIf(Parse::Mode mode = Parse::Execute); + // parse assignment + Parse::Flow parseCommand(Parse::Mode mode = Parse::Execute); + // parse while loop + Parse::Flow parseWhile(Parse::Mode mode = Parse::Execute); + // parse for loop + Parse::Flow parseFor(Parse::Mode mode = Parse::Execute); + // parse foreach loop + Parse::Flow parseForeach(Parse::Mode mode = Parse::Execute); + // parse switch block + void parseSwitch(Parse::Mode mode = Parse::Execute); + // parse whole block + Parse::Flow parseBlock(Parse::Mode mode = Parse::Execute); + + // insert next node + void insertNode(ParseNode p, int line); + // next item to be parsed + ParseNode next() const; + // next is Else or Else && If? + bool nextElseIf(); + // check if next item is keyword k, if so - go further, if no, set error + bool tryKeyword(Parse::Keyword k, Parse::Mode mode = Parse::Execute); + // check if next item is a variable, if so, return its name + bool tryVariable(Parse::Mode mode = Parse::Execute); + + // get the name of the next node treated as variable + QString nextVariable(Parse::Mode mode = Parse::Execute); + // check whether variable/array name is global (preceded with _) + bool isGlobal(const QString& name) const; + // check if next item is a function + bool isFunction() const; + // check if next item is a widget + bool isWidget() const; + + // reset to default state + void reset(); + // set error state if no error was set before; err is expected symbol that wasn't found + void setError(const QString& msg); + void setError(const QString& msg, int pos); + // check whether parsing was successful + bool isError() const; + + // parsing data + ParserData* m_data; + // current parsing position + uint m_start; + // current error message + QString m_error; + // in case of error, this keeps position of first error + uint m_errorPosition; + // parsing nodes + QValueVector<ParseNode> m_parts; + // variables + QMap<QString, ParseNode> m_variables; + // arrays + QMap<QString, QMap<QString, ParseNode> > m_arrays; + // 2D arrays + QMap<QString, QMap<QString, QMap<QString, ParseNode> > > m_matrices; + // Kommander + KommanderWidget* m_widget; + // global variables + static QMap<QString, ParseNode> m_globalVariables; + // global arrays + static QMap<QString, QMap<QString, ParseNode> > m_globalArrays; + // global 2D arrays + static QMap<QString, QMap<QString, QMap<QString, ParseNode> > > m_globalMatrices; +}; + +#endif + diff --git a/kommander/widget/parserdata.cpp b/kommander/widget/parserdata.cpp new file mode 100644 index 00000000..778be3d6 --- /dev/null +++ b/kommander/widget/parserdata.cpp @@ -0,0 +1,134 @@ +/*************************************************************************** + parserdata.cpp - Parser data: keywords, functions etc. + ------------------- + copyright : (C) 2004 Michal Rudolf <mrudolf@kdewebdwev.org> + + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "parserdata.h" +using namespace Parse; + +KeywordGroup ParserData::keywordGroup(Keyword k) const +{ + if (m_groups.contains(k)) + return m_groups[k]; + else + return GroupMisc; +} + +Keyword ParserData::stringToKeyword(const QString& s) const +{ + QString k = s.lower(); + if (m_keywords.contains(k)) + return m_keywords[k]; + else + return Variable; +} + +QString ParserData::keywordToString(Parse::Keyword k) const +{ + for (QMapConstIterator<QString, Keyword> it = m_keywords.begin(); it != m_keywords.end(); ++it) + if (it.data() == k) + return it.key(); + return QString(); +} + +bool ParserData::registerFunction(const QString& name, Function f) +{ + m_functions[name.lower()] = f; + return true; +} + +ParserData::ParserData() +{ + m_keywords["for"] = For; + m_keywords["foreach"] = Foreach; + m_keywords["in"] = In; + m_keywords["end"] = End; + m_keywords["if"] = If; + m_keywords["then"] = Then; + m_keywords["else"] = Else; + m_keywords["elseif"] = Elseif; + m_keywords["endif"] = Endif; + m_keywords["{"] = LeftCurlyBrace; + m_keywords["}"] = RightCurlyBrace; + m_keywords["switch"] = Switch; + m_keywords["case"] = Case; + m_keywords["while"] = While; + m_keywords["to"] = To; + m_keywords["step"] = Step; + m_keywords["do"] = Do; + m_keywords["break"] = Break; + m_keywords["continue"] = Continue; + m_keywords["exit"] = Exit; + m_keywords["."] = Dot; + m_keywords[";"] = Semicolon; + m_keywords[","] = Comma; + m_keywords["="] = Assign; + m_keywords["<"] = Less; + m_keywords["<="] = LessEqual; + m_keywords[">"] = Greater; + m_keywords[">="] = GreaterEqual; + m_keywords["=="] = Equal; + m_keywords["!="] = NotEqual; + m_keywords["<>"] = NotEqual; + m_keywords["not"] = Not; + m_keywords["!"] = Not; + m_keywords["and"] = And; + m_keywords["&&"] = And; + m_keywords["or"] = Or; + m_keywords["||"] = Or; + m_keywords["false"] = False; + m_keywords["true"] = True; + m_keywords["("] = LeftParenthesis; + m_keywords[")"] = RightParenthesis; + m_keywords["["] = LeftBracket; + m_keywords["]["] = DoubleBracket; + m_keywords["]"] = RightBracket; + m_keywords["+"] = Plus; + m_keywords["-"] = Minus; + m_keywords["*"] = Multiply; + m_keywords["/"] = Divide; + m_keywords["%"] = Mod; + m_keywords["+="] = PlusEqual; + m_keywords["-="] = MinusEqual; + m_keywords["++"] = Increment; + m_keywords["--"] = Decrement; + m_keywords["mod"] = Mod; + m_keywords["with"] = ArrKeyVal; + + m_groups[Less] = GroupComparison; + m_groups[LessEqual] = GroupComparison; + m_groups[Equal] = GroupComparison; + m_groups[NotEqual] = GroupComparison; + m_groups[Greater] = GroupComparison; + m_groups[GreaterEqual] = GroupComparison; + + m_groups[Plus] = GroupAdd; + m_groups[Minus] = GroupAdd; + m_groups[Multiply] = GroupMultiply; + m_groups[Divide] = GroupMultiply; + m_groups[Mod] = GroupMultiply; + + registerStandardFunctions(); +} + +bool ParserData::isFunction(const QString& name) const +{ + return m_functions.contains(name.lower()); +} + +const Function& ParserData::function(const QString& name) const +{ + return m_functions[name.lower()]; +} + diff --git a/kommander/widget/parserdata.h b/kommander/widget/parserdata.h new file mode 100644 index 00000000..4c7f8d50 --- /dev/null +++ b/kommander/widget/parserdata.h @@ -0,0 +1,50 @@ +/*************************************************************************** + parserdata.h - Parser data: keywords, functions etc. + ------------------- + copyright : (C) 2004 Michal Rudolf <mrudolf@kdewebdwev.org> + + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef _HAVE_PARSERDATA_H_ +#define _HAVE_PARSERDATA_H_ + +#include "parsenode.h" +#include "function.h" +#include <qmap.h> + +class ParserData { +public: + /* initialize keywords */ + ParserData(); + /* Return group of given keyword */ + Parse::KeywordGroup keywordGroup(Parse::Keyword k) const; + /* Convert string to keyword */ + Parse::Keyword stringToKeyword(const QString& s) const; + /* Convert keyword to string */ + QString keywordToString(Parse::Keyword k) const; + /* register a function */ + bool registerFunction(const QString& name, Function f); + /* check if this is a name of standard function */ + bool isFunction(const QString& name) const; + /* Return function with given name. Warning: this function has undefined behavior when there is + no such function. */ + const Function& function(const QString& name) const; +private: + // register standard function + void registerStandardFunctions(); + QMap<QString, Parse::Keyword> m_keywords; + QMap<Parse::Keyword, Parse::KeywordGroup> m_groups; + QMap<QString, Function> m_functions; +}; + + +#endif |