Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/libraries/core/TclBind.cc @ 6037

Last change on this file since 6037 was 5929, checked in by rgrieder, 15 years ago

Merged core5 branch back to the trunk.
Key features include clean level unloading and an extended XML event system.

Two important notes:
Delete your keybindings.ini files! * or you will still get parser errors when loading the key bindings.
Delete build_dir/lib/modules/libgamestates.module! * or orxonox won't start.
Best thing to do is to delete the build folder ;)

  • Property svn:eol-style set to native
File size: 6.8 KB
Line 
1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *      Fabian 'x3n' Landau
24 *   Co-authors:
25 *      ...
26 *
27 */
28
29#include "TclBind.h"
30
31#include <exception>
32#include <string>
33#include <cpptcl/cpptcl.h>
34
35#include "SpecialConfig.h"
36#include "util/Debug.h"
37#include "util/Exception.h"
38#include "util/StringUtils.h"
39#include "CommandExecutor.h"
40#include "ConsoleCommand.h"
41#include "PathConfig.h"
42#include "TclThreadManager.h"
43
44namespace orxonox
45{
46    SetConsoleCommandShortcut(TclBind, tcl);
47    SetConsoleCommandShortcut(TclBind, bgerror);
48
49    TclBind* TclBind::singletonPtr_s = 0;
50
51    TclBind::TclBind(const std::string& datapath)
52    {
53        this->interpreter_ = 0;
54        this->bSetTclDataPath_ = false;
55        this->setDataPath(datapath);
56    }
57
58    TclBind::~TclBind()
59    {
60        if (this->interpreter_)
61            delete this->interpreter_;
62    }
63
64    void TclBind::setDataPath(const std::string& datapath)
65    {
66        // String has POSIX slashes
67        this->tclDataPath_ = datapath + "tcl" + '/';
68        this->bSetTclDataPath_ = true;
69
70        this->initializeTclInterpreter();
71    }
72
73    void TclBind::initializeTclInterpreter()
74    {
75        if (this->bSetTclDataPath_ && !this->interpreter_)
76        {
77            this->interpreter_ = this->createTclInterpreter();
78
79            this->interpreter_->def("::orxonox::query", TclBind::tcl_query, Tcl::variadic());
80            this->interpreter_->def("::orxonox::crossquery", TclThreadManager::tcl_crossquery, Tcl::variadic());
81            this->interpreter_->def("execute", TclBind::tcl_execute, Tcl::variadic());
82            this->interpreter_->def("::orxonox::crossexecute", TclThreadManager::tcl_crossexecute, Tcl::variadic());
83
84            try
85            {
86                this->interpreter_->eval("proc query        {args}    { ::orxonox::query $args }");
87                this->interpreter_->eval("proc crossquery   {id args} { ::orxonox::crossquery 0 $id $args }");
88                this->interpreter_->eval("proc crossexecute {id args} { ::orxonox::crossquery 0 $id $args }");
89                this->interpreter_->eval("proc running      {}        { return 1 }");
90                this->interpreter_->eval("set id 0");
91                this->interpreter_->eval("rename exit ::tcl::exit; proc exit {} { execute exit }");
92            }
93            catch (Tcl::tcl_error const &e)
94            {   COUT(1) << "Tcl error while creating Tcl-interpreter: " << e.what() << std::endl;   }
95            catch (...)
96            {   COUT(1) << "Error while creating Tcl-interpreter: " << Exception::handleMessage() << std::endl;   }
97        }
98    }
99
100    Tcl::interpreter* TclBind::createTclInterpreter()
101    {
102        Tcl::interpreter* interpreter = new Tcl::interpreter();
103        std::string libpath = TclBind::getTclLibraryPath();
104
105        try
106        {
107            if (libpath != "")
108                interpreter->eval("set tcl_library \"" + libpath + "\"");
109
110            Tcl_Init(interpreter->get());
111
112            interpreter->eval("source \"" + TclBind::getInstance().tclDataPath_ + "/init.tcl\"");
113        }
114        catch (Tcl::tcl_error const &e)
115        {   COUT(1) << "Tcl error while creating Tcl-interpreter: " << e.what() << std::endl; COUT(1) << "Error: Tcl isn't properly initialized. Orxonox might possibly not work like that." << std::endl;   }
116        catch (...)
117        {   COUT(1) << "Error while creating Tcl-interpreter: " << Exception::handleMessage() << std::endl; COUT(1) << "Error: Tcl isn't properly initialized. Orxonox might possibly not work like that." << std::endl;   }
118
119        return interpreter;
120    }
121
122    std::string TclBind::getTclLibraryPath()
123    {
124#ifdef DEPENDENCY_PACKAGE_ENABLE
125        if (PathConfig::isDevelopmentRun())
126            return (std::string(specialConfig::dependencyLibraryDirectory) + "/tcl");
127        else
128            return (PathConfig::getRootPathString() + "lib/tcl");
129#else
130        return "";
131#endif
132    }
133
134    std::string TclBind::tcl_query(Tcl::object const &args)
135    {
136        COUT(4) << "Tcl_query: " << args.get() << std::endl;
137
138        std::string command = stripEnclosingBraces(args.get());
139
140        if (!CommandExecutor::execute(command, false))
141        {
142            COUT(1) << "Error: Can't execute command \"" << command << "\"!" << std::endl;
143        }
144
145        if (CommandExecutor::getLastEvaluation().hasReturnvalue())
146            return CommandExecutor::getLastEvaluation().getReturnvalue().getString();
147
148        return "";
149    }
150
151    void TclBind::tcl_execute(Tcl::object const &args)
152    {
153        COUT(4) << "Tcl_execute: " << args.get() << std::endl;
154        std::string command = stripEnclosingBraces(args.get());
155
156        if (!CommandExecutor::execute(command, false))
157        {
158            COUT(1) << "Error: Can't execute command \"" << command << "\"!" << std::endl;
159        }
160    }
161
162    std::string TclBind::tcl(const std::string& tclcode)
163    {
164        if (TclBind::getInstance().interpreter_)
165        {
166            try
167            {
168                std::string output = TclBind::getInstance().interpreter_->eval("uplevel #0 " + tclcode);
169                if (output != "")
170                {
171                    COUT(0) << "tcl> " << output << std::endl;
172                }
173                return output;
174            }
175            catch (Tcl::tcl_error const &e)
176            {   COUT(1) << "tcl> Error: " << e.what() << std::endl;   }
177            catch (...)
178            {   COUT(1) << "Error while executing Tcl: " << Exception::handleMessage() << std::endl;   }
179        }
180
181        return "";
182    }
183
184    void TclBind::bgerror(std::string error)
185    {
186        COUT(1) << "Tcl background error: " << stripEnclosingBraces(error) << std::endl;
187    }
188
189    bool TclBind::eval(const std::string& tclcode)
190    {
191        try
192        {
193            TclBind::getInstance().interpreter_->eval(tclcode);
194            return true;
195        }
196        catch (Tcl::tcl_error const &e)
197        {   COUT(1) << "Tcl error: " << e.what() << std::endl;   }
198        catch (...)
199        {   COUT(1) << "Error while executing Tcl: " << Exception::handleMessage() << std::endl;   }
200
201        return false;
202    }
203}
Note: See TracBrowser for help on using the repository browser.