Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members

scriptserver.cpp

Go to the documentation of this file.
00001 /* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*-
00002 
00003    this file is part of rcssserver3D
00004    Fri May 9 2003
00005    Copyright (C) 2002,2003 Koblenz University
00006    Copyright (C) 2003 RoboCup Soccer Server 3D Maintenance Group
00007    $Id: scriptserver.cpp,v 1.23 2004/12/21 14:50:57 rollmark Exp $
00008 
00009    This program is free software; you can redistribute it and/or modify
00010    it under the terms of the GNU General Public License as published by
00011    the Free Software Foundation; version 2 of the License.
00012 
00013    This program is distributed in the hope that it will be useful,
00014    but WITHOUT ANY WARRANTY; without even the implied warranty of
00015    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016    GNU General Public License for more details.
00017 
00018    You should have received a copy of the GNU General Public License
00019    along with this program; if not, write to the Free Software
00020    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00021 */
00022 #include <boost/any.hpp>
00023 #include <boost/scoped_array.hpp>
00024 #include <sstream>
00025 #include "scriptserver.h"
00026 #include <zeitgeist/corecontext.h>
00027 #include <zeitgeist/core.h>
00028 #include <zeitgeist/logserver/logserver.h>
00029 #include <zeitgeist/fileserver/fileserver.h>
00030 #include <sys/stat.h>
00031 
00032 using namespace boost;
00033 using namespace std;
00034 using namespace zeitgeist;
00035 
00036 boost::shared_ptr<CoreContext> gMyPrivateContext;
00037 
00038 void
00039 getParameterList(VALUE args, ParameterList& params)
00040 {
00041     int argc = RARRAY(args)->len;
00042 
00043     for (int i = 0; i<argc; ++i)
00044     {
00045         VALUE argument = rb_ary_entry(args, i);
00046         boost::any var;
00047 
00048         // do type conversion
00049         switch (TYPE(argument))
00050         {
00051         case T_STRING:
00052         {
00053             char *c = STR2CSTR(argument);
00054             var = c;
00055             //printf("string: '%s'\n",boost::any_cast<char*>(var));
00056         }
00057         break;
00058         case T_FIXNUM:
00059         {
00060             int i = FIX2INT(argument);
00061             var = i;
00062             //printf("int: '%d'\n", boost::any_cast<int>(var));
00063         }
00064         break;
00065         case T_FLOAT:
00066         {
00067             float f = (float)NUM2DBL(argument);
00068             var = f;
00069             //printf("float: '%f'\n", boost::any_cast<float>(var));
00070         }
00071         break;
00072         case T_TRUE:
00073         {
00074             var = true;
00075             //printf("bool: 'true'\n");
00076         }
00077         break;
00078         case T_FALSE:
00079         {
00080             var = false;
00081             //printf("bool: 'false'\n");
00082         }
00083         break;
00084         }
00085 
00086         params.AddValue(var);
00087     }
00088 }
00089 
00090 GCValue
00091 ScriptServer::GetZeitgeistObject(boost::shared_ptr<Leaf> leaf)
00092 {
00093     GCValue v;
00094 
00095     if (leaf.get() != 0)
00096     {
00097         stringstream ss;
00098         ss << "ZeitgeistObject.new(" << (unsigned long) leaf.get() <<")";
00099         v = RbEvalStringWrap(ss.str());
00100     }
00101 
00102     return v;
00103 }
00104 
00105 
00106 VALUE
00107 selectObject(VALUE /*self*/, VALUE path)
00108 {
00109     shared_ptr<Leaf> leaf = gMyPrivateContext->Select(STR2CSTR(path));
00110     return ScriptServer::GetZeitgeistObject(leaf).Get();
00111 }
00112 
00113 VALUE
00114 selectCall(VALUE /*self*/, VALUE functionName, VALUE args)
00115 {
00116     ParameterList in;
00117     getParameterList(args, in);
00118 
00119     Class::TCmdProc cmd =
00120         gMyPrivateContext->GetObject()->GetClass()->GetCmdProc
00121         (STR2CSTR(functionName));
00122 
00123     GCValue out;
00124 
00125     if (cmd != 0)
00126     {
00127         out = cmd(static_cast<Object*>(gMyPrivateContext->GetObject().get()), in);
00128     } else
00129     {
00130         gMyPrivateContext->GetCore()->GetLogServer()->Error()
00131             << "(ScriptServer) ERROR: Unknown function '"
00132             << STR2CSTR(functionName) << "'" << endl;
00133     }
00134 
00135     return out.Get();
00136 }
00137 
00138 VALUE
00139 thisCall(VALUE /*self*/, VALUE objPointer, VALUE functionName, VALUE args)
00140 {
00141     ParameterList in;
00142     getParameterList(args, in);
00143 
00144     Object *obj = (Object*)NUM2INT(objPointer);
00145     Class::TCmdProc cmd =
00146         obj->GetClass()->GetCmdProc(STR2CSTR(functionName));
00147 
00148     GCValue out;
00149 
00150     if (cmd != 0)
00151     {
00152         out = cmd(obj, in);
00153     } else
00154     {
00155         gMyPrivateContext->GetCore()->GetLogServer()->Error()
00156             << "(ScriptServer) ERROR: Unknown function '"
00157             << STR2CSTR(functionName) << "'" << endl;
00158     }
00159 
00160     return out.Get();
00161 }
00162 
00163 VALUE
00164 importBundle(VALUE /*self*/, VALUE path)
00165 {
00166     gMyPrivateContext->GetCore()->ImportBundle(STR2CSTR(path));
00167     return Qnil;
00168 }
00169 
00170 VALUE
00171 run (VALUE /*self*/, VALUE file)
00172 {
00173     gMyPrivateContext->GetCore()->GetScriptServer()->Run(STR2CSTR(file));
00174     return Qnil;
00175 }
00176 
00177 VALUE
00178 newObject(VALUE /*self*/, VALUE className, VALUE pathStr)
00179 {
00180     shared_ptr<Leaf> leaf =
00181         gMyPrivateContext->New(STR2CSTR(className), STR2CSTR(pathStr));
00182     return ScriptServer::GetZeitgeistObject(leaf).Get();
00183 }
00184 
00185 VALUE
00186 deleteObject(VALUE /*self*/, VALUE name)
00187 {
00188     gMyPrivateContext->Delete(STR2CSTR(name));
00189     return Qnil;
00190 }
00191 
00192 VALUE
00193 getObject(VALUE /*self*/, VALUE path)
00194 {
00195     shared_ptr<Leaf> leaf = gMyPrivateContext->Get(STR2CSTR(path));
00196     return ScriptServer::GetZeitgeistObject(leaf).Get();
00197 }
00198 
00199 VALUE
00200 listObjects(VALUE /*self*/)
00201 {
00202     gMyPrivateContext->ListObjects();
00203     return Qnil;
00204 }
00205 
00206 VALUE
00207 pushd(VALUE /*self*/)
00208 {
00209     gMyPrivateContext->Push();
00210     return Qnil;
00211 }
00212 
00213 VALUE
00214 popd(VALUE /*self*/)
00215 {
00216     gMyPrivateContext->Pop();
00217     return Qnil;
00218 }
00219 
00220 VALUE
00221 dirs(VALUE /*self*/)
00222 {
00223     gMyPrivateContext->Dir();
00224     return Qnil;
00225 }
00226 
00227 ScriptServer::ScriptServer()
00228 {
00229     ruby_init();
00230 
00231     // register built-in commands
00232     rb_define_global_function("selectObject", RUBY_METHOD_FUNC(selectObject), 1);
00233     rb_define_global_function("selectCall",   RUBY_METHOD_FUNC(selectCall), 2);
00234     rb_define_global_function("thisCall",     RUBY_METHOD_FUNC(thisCall), 3);
00235     rb_define_global_function("importBundle", RUBY_METHOD_FUNC(importBundle), 1);
00236     rb_define_global_function("run",          RUBY_METHOD_FUNC(run), 1);
00237     rb_define_global_function("new",          RUBY_METHOD_FUNC(newObject), 2);
00238     rb_define_global_function("delete",       RUBY_METHOD_FUNC(deleteObject), 1);
00239     rb_define_global_function("get",          RUBY_METHOD_FUNC(getObject), 1);
00240     rb_define_global_function("ls",           RUBY_METHOD_FUNC(listObjects), 0);
00241     rb_define_global_function("pushd",        RUBY_METHOD_FUNC(pushd), 0);
00242     rb_define_global_function("popd",         RUBY_METHOD_FUNC(popd), 0);
00243     rb_define_global_function("dirs",         RUBY_METHOD_FUNC(dirs), 0);
00244 
00245     mRelPathPrefix = "../../";
00246 }
00247 
00248 ScriptServer::~ScriptServer()
00249 {
00250 }
00251 
00252 void
00253 ScriptServer::UpdateCachedAllNodes()
00254 {
00255     GetLog()->Debug() << "(ScriptServer) updating cached script variables\n";
00256     GetCore()->GetRoot()->UpdateCached();
00257 }
00258 
00259 bool
00260 ScriptServer::Run(shared_ptr<salt::RFile> file)
00261 {
00262     if (file.get() == 0)
00263     {
00264         return false;
00265     }
00266 
00267     boost::scoped_array<char> buffer(new char[file->Size() + 1]);
00268     file->Read(buffer.get(), file->Size());
00269     buffer[file->Size()] = 0;
00270 
00271     bool ok = Eval(buffer.get());
00272     UpdateCachedAllNodes();
00273     return ok;
00274 }
00275 
00276 bool
00277 ScriptServer::Run(const string &fileName)
00278 {
00279     shared_ptr<salt::RFile> file = GetFile()->Open(fileName.c_str());
00280     if (file.get() == 0)
00281     {
00282         GetLog()->Error() << "(ScriptServer) ERROR: Cannot locate file '"
00283                           << fileName << "'\n";
00284         return false;
00285     }
00286 
00287     GetLog()->Debug() << "(ScriptServer) Running " << fileName << endl;
00288 
00289     return Run(file);
00290 }
00291 
00292 bool
00293 ScriptServer::Eval(const string &command)
00294 {
00295     int error;
00296     RbEvalStringWrap(command,error);
00297     return (error == 0);
00298 }
00299 
00300 bool
00301 ScriptServer::Eval(const std::string &command, GCValue& value)
00302 {
00303     int error;
00304     value = RbEvalStringWrap(command,error);
00305     return (error == 0);
00306 }
00307 
00308 void
00309 ScriptServer::CreateVariable(const string &varName, int value)
00310 {
00311     // create a string with: "createVariable 'varName', value"
00312     stringstream s;
00313     s << "createVariable('" << varName << "', " << value << ")";
00314     Eval(s.str());
00315 }
00316 
00317 void
00318 ScriptServer::CreateVariable(const string &varName, float value)
00319 {
00320     // create a string with: "createVariable 'ns', 'varName', value"
00321     stringstream s;
00322     s << "createVariable('" << varName << "', " << value << ")";
00323     Eval(s.str());
00324 }
00325 
00326 void
00327 ScriptServer::CreateVariable(const string &varName, const string &value)
00328 {
00329     // create a string with: "createVariable 'ns', 'varName', 'value'"
00330     stringstream s;
00331     s << "createVariable('" << varName << "', '" << value << "')";
00332     Eval(s.str());
00333 }
00334 
00335 bool
00336 ScriptServer::ParseVarName(const string& varName, string& nameSpace, string& name)
00337 {
00338     stringstream  ss(varName);
00339     string current;
00340     vector<string> tokens;
00341 
00342     // segment varName
00343     while(! ss.eof())
00344     {
00345         getline(ss, current,'.');
00346         if (current.size())
00347         {
00348             tokens.push_back(current);
00349         }
00350     }
00351 
00352     if (tokens.size() != 2)
00353     {
00354         return false;
00355     }
00356 
00357     nameSpace = tokens[0];
00358     name = tokens[1];
00359 
00360     return (
00361         (nameSpace.size() >= 1) &&
00362         (nameSpace[0] >= 'A') &&
00363         (nameSpace[0] <= 'Z') &&
00364         (name.size() >= 1) &&
00365         (name[0] >= 'A') &&
00366         (name[0] <= 'Z')
00367         );
00368 }
00369 
00370 bool
00371 ScriptServer::ExistsVariable(const string &varName)
00372 {
00373     return (! GetVariable(varName).IsNil());
00374 }
00375 
00376 GCValue
00377 ScriptServer::GetVariable(const string &varName)
00378 {
00379     string nameSpace;
00380     string name;
00381 
00382     if (! ParseVarName(varName,nameSpace,name))
00383     {
00384         return GCValue();
00385     }
00386 
00387     GCValue v;
00388     if (nameSpace != "")
00389     {
00390         // get namespace class
00391         GCValue ns = rb_const_get(rb_cObject, rb_intern(nameSpace.c_str()));
00392 
00393         if (! ns.IsNil())
00394         {
00395             // get member variable of namespace object
00396             ID var = rb_intern(name.c_str());
00397 
00398             int error;
00399             RbArguments arg(ns.Get(), var, 0, 0);
00400             v = rb_protect(
00401                 RbFuncallWrap,
00402                 reinterpret_cast<VALUE>(&arg), &error
00403                 );
00404 
00405             if (error)
00406             {
00407                 GetLog()->Debug() << "(ScriptServer) Ruby ERROR: "
00408                                   << RbGetError() << "\n";
00409                 v = Qnil;
00410             }
00411         }
00412     } else
00413     {
00414         v = rb_const_get(rb_cObject, rb_intern(name.c_str()));
00415     }
00416 
00417     return v;
00418 }
00419 
00420 bool
00421 ScriptServer::GetVariable(const string &varName, int &value)
00422 {
00423     return GetVariable(varName).GetInt(value);
00424 }
00425 
00426 bool
00427 ScriptServer::GetVariable(const std::string &varName, float &value)
00428 {
00429     return GetVariable(varName).GetFloat(value);
00430 }
00431 
00432 bool
00433 ScriptServer::GetVariable(const string &varName, bool &value)
00434 {
00435     return GetVariable(varName).GetBool(value);
00436 }
00437 
00438 bool
00439 ScriptServer::GetVariable(const string &varName, string &value)
00440 {
00441     return GetVariable(varName).GetString(value);
00442 }
00443 
00444 boost::shared_ptr<CoreContext>
00445 ScriptServer::GetContext() const
00446 {
00447     return gMyPrivateContext;
00448 }
00449 
00450 bool
00451 ScriptServer::ConstructInternal()
00452 {
00453     if (! Leaf::ConstructInternal())
00454     {
00455         return false;
00456     }
00457 
00458     gMyPrivateContext = GetCore()->CreateContext();
00459     return true;
00460 }
00461 
00462 void
00463 ScriptServer::SetInitRelPathPrefix(const std::string &relPathPrefix)
00464 {
00465     mRelPathPrefix = relPathPrefix;
00466 }
00467 
00468 bool
00469 ScriptServer::RunInitScriptInternal(const string &sourceDir, const string &name,
00470                                     bool copy, const string& destDir)
00471 {
00472     // run the init script in the sourceDir
00473     string sourcePath = sourceDir + "/" + name;
00474     GetLog()->Debug() << "(ScriptServer) Running " << sourcePath << "... ";
00475 
00476     shared_ptr<salt::StdFile> file(new(salt::StdFile));
00477     if (
00478         (! file->Open(sourcePath.c_str())) ||
00479         (! Run(file))
00480         )
00481     {
00482         GetLog()->Debug() << "failed" << endl;
00483         return false;
00484     } else
00485     {
00486         GetLog()->Debug() << "ok" << endl;
00487     }
00488 
00489     // copy it to the destDir
00490     if (! copy)
00491     {
00492         return true;
00493     }
00494 
00495     string destPath = destDir + "/" + name;
00496 
00497     GetLog()->Normal() << "Copying " << sourcePath
00498                        << " to " << destPath << endl;
00499 
00500     stringstream s;
00501     s << "cp " << sourcePath << " " << destPath;
00502     system(s.str().c_str());
00503 
00504     return true;
00505 }
00506 
00507 bool
00508 ScriptServer::GetDotDirName(string& dotDir)
00509 {
00510     if (mDotName == "")
00511     {
00512         GetLog()->Warning() << "(ScriptServer) WARNING: Dot directory name unset.\n";
00513         return false;
00514     }
00515 
00516     char* home = getenv("HOME");
00517     if (!home)
00518     {
00519         GetLog()->Warning() << "(ScriptServer) WARNING: $HOME is unset.\n";
00520         return false;
00521     }
00522 
00523     dotDir = string(home) + "/" + mDotName;
00524 
00525     return true;
00526 }
00527 
00528 bool
00529 ScriptServer::CreateDotDir(const string& dotDir)
00530 {
00531     char cwd[PATH_MAX+1];
00532     if (getcwd(cwd,sizeof(cwd)) == NULL)
00533     {
00534         GetLog()->Error()
00535             << "(ScriptServer) ERROR: Cannot get current directory\n";
00536         return false;
00537     }
00538 
00539     if (chdir(dotDir.c_str()) == 0)
00540     {
00541         // dot dir exists; change back to original directory
00542         chdir(cwd);
00543         return true;
00544     }
00545 
00546     // dot dir is not existent, try to create it
00547     if (mkdir(dotDir.c_str(),0777) != 0)
00548     {
00549         GetLog()->Error() << "(ScriptServer) ERROR: Cannot create directory '"
00550                           << dotDir << "'\n";
00551         return false;
00552     }
00553 
00554     GetLog()->Normal() << "(ScriptServer) Created Directory '"
00555                        << dotDir << "'\n";
00556 
00557     return true;
00558 }
00559 
00560 bool
00561 ScriptServer::RunInitScript(const string &fileName, const string &relPath,
00562                             EInitScriptType type)
00563 {
00564     string dotDir;
00565     bool validDotDir =
00566         (type == IS_USERLOCAL) &&
00567         GetDotDirName(dotDir) &&
00568         CreateDotDir(dotDir);
00569 
00570     // some macro magic (not at all)
00571     string pkgdatadir = PREFIX "/share/" PACKAGE_NAME;
00572 
00573     bool ok =
00574         (
00575             (
00576                 (validDotDir) && (RunInitScriptInternal(dotDir, fileName, false))
00577                 )
00578             || (RunInitScriptInternal(pkgdatadir,  fileName, validDotDir, dotDir))
00579             || (RunInitScriptInternal(mRelPathPrefix+relPath, fileName, validDotDir, dotDir))
00580             );
00581 
00582     if (! ok)
00583     {
00584         GetLog()->Error() << "(ScriptServer) ERROR: Cannot locate init script '"
00585                           << fileName << "'\n";
00586     }
00587 
00588     return ok;
00589 }
00590 

Generated on Thu Apr 6 15:25:40 2006 for rcssserver3d by  doxygen 1.4.4