summaryrefslogtreecommitdiffstats
path: root/kommander/widget
diff options
context:
space:
mode:
Diffstat (limited to 'kommander/widget')
-rw-r--r--kommander/widget/Makefile.am20
-rw-r--r--kommander/widget/expression.cpp332
-rw-r--r--kommander/widget/expression.h80
-rw-r--r--kommander/widget/function.cpp135
-rw-r--r--kommander/widget/function.h73
-rw-r--r--kommander/widget/functionlib.cpp1476
-rw-r--r--kommander/widget/invokeclass.cpp61
-rw-r--r--kommander/widget/invokeclass.h56
-rw-r--r--kommander/widget/kmdrmainwindow.cpp36
-rw-r--r--kommander/widget/kmdrmainwindow.h37
-rw-r--r--kommander/widget/kommander_export.h35
-rw-r--r--kommander/widget/kommanderfunctions.cpp349
-rw-r--r--kommander/widget/kommanderwidget.cpp745
-rw-r--r--kommander/widget/kommanderwidget.h162
-rw-r--r--kommander/widget/kommanderwindow.cpp35
-rw-r--r--kommander/widget/kommanderwindow.h37
-rw-r--r--kommander/widget/myprocess.cpp137
-rw-r--r--kommander/widget/myprocess.h58
-rw-r--r--kommander/widget/parsenode.cpp262
-rw-r--r--kommander/widget/parsenode.h129
-rw-r--r--kommander/widget/parser.cpp1243
-rw-r--r--kommander/widget/parser.h197
-rw-r--r--kommander/widget/parserdata.cpp134
-rw-r--r--kommander/widget/parserdata.h50
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