aboutsummaryrefslogtreecommitdiffstats
path: root/Plugins/ScriptingTcl/scriptingtcl.h
blob: f853f07096a691c39e3c9da1ef10dd403587e8b7 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
#ifndef SCRIPTINGTCL_H
#define SCRIPTINGTCL_H

#include "scriptingtcl_global.h"
#include "plugins/genericplugin.h"
#include "plugins/scriptingplugin.h"
#include "db/sqlquery.h"
#include <QCache>
#include <tcl.h>

class QMutex;
struct Tcl_Interp;
struct Tcl_Obj;

class SCRIPTINGTCLSHARED_EXPORT ScriptingTcl : public GenericPlugin, public DbAwareScriptingPlugin
{
        Q_OBJECT
        SQLITESTUDIO_PLUGIN("scriptingtcl.json")

    public:
        ScriptingTcl();
        ~ScriptingTcl();

        bool init();
        void deinit();
        QString getLanguage() const;
        Context* createContext();
        void releaseContext(Context* context);
        void resetContext(Context* context);
        void setVariable(Context* context, const QString& name, const QVariant& value);
        QVariant getVariable(Context* context, const QString& name);
        bool hasError(Context* context) const;
        QString getErrorMessage(Context* context) const;
        QString getIconPath() const;
        QVariant evaluate(Context* context, const QString& code, const QList<QVariant>& args, Db* db, bool locking = false);
        QVariant evaluate(const QString& code, const QList<QVariant>& args, Db* db, bool locking = false, QString* errorMessage = nullptr);

    private:
        class ScriptObject
        {
            public:
                ScriptObject(const QString& code);
                ~ScriptObject();

                Tcl_Obj* getTclObj();

            private:
                Tcl_Obj* obj = nullptr;
        };

        class ContextTcl : public ScriptingPlugin::Context
        {
            public:
                ContextTcl();
                ~ContextTcl();

                void reset();

                Tcl_Interp* interp = nullptr;
                QCache<QString,ScriptObject> scriptCache;
                QString error;
                Db* db = nullptr;
                bool useDbLocking = false;

            private:
                void init();
        };

        enum class TclDataType
        {
            Boolean,
            BooleanString,
            Double,
            Int,
            WideInt,
            Bignum,
            Bytearray,
            String,
            List,
            Dict,
            UNKNOWN
        };

        ContextTcl* getContext(ScriptingPlugin::Context* context) const;
        QVariant compileAndEval(ContextTcl* ctx, const QString& code, Db* db, bool locking);
        QVariant extractResult(ContextTcl* ctx);
        void setArgs(ContextTcl* ctx, const QList<QVariant>& args);

        static Tcl_Obj* argsToList(const QList<QVariant>& args);
        static QVariant tclObjToVariant(Tcl_Obj* obj);
        static QString tclObjToString(Tcl_Obj* obj);
        static Tcl_Obj* variantToTclObj(const QVariant& value);
        static Tcl_Obj* stringToTclObj(const QString& value);
        static int dbCommand(ClientData clientData, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]);
        static int initTclCommand(ClientData clientData, Tcl_Interp* interp, int objc, Tcl_Obj* const objv[]);
        static int dbEval(ContextTcl* ctx, Tcl_Interp* interp, Tcl_Obj* const objv[]);
        static int dbEvalRowByRow(ContextTcl* ctx, Tcl_Interp* interp, Tcl_Obj* const objv[]);
        static int dbEvalDeepResults(ContextTcl* ctx, Tcl_Interp* interp, Tcl_Obj* const objv[]);
        static int dbEvalOneColumn(ContextTcl* ctx, Tcl_Interp* interp, Tcl_Obj* const objv[]);
        static SqlQueryPtr dbCommonEval(ContextTcl* ctx, Tcl_Interp* interp, Tcl_Obj* const objv[]);
        static int setArrayVariable(Tcl_Interp* interp, const QString& arrayName, const QHash<QString,QVariant>& hash);
        static void setVariable(Tcl_Interp* interp, const QString& name, const QVariant& value);
        static QVariant getVariable(Tcl_Interp* interp, const QString& name);

        static const constexpr int cacheSize = 5;

        ContextTcl* mainContext = nullptr;
        QList<Context*> contexts;
        QMutex* mainInterpMutex = nullptr;
};

#endif // SCRIPTINGTCL_H