00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
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
00049 switch (TYPE(argument))
00050 {
00051 case T_STRING:
00052 {
00053 char *c = STR2CSTR(argument);
00054 var = c;
00055
00056 }
00057 break;
00058 case T_FIXNUM:
00059 {
00060 int i = FIX2INT(argument);
00061 var = i;
00062
00063 }
00064 break;
00065 case T_FLOAT:
00066 {
00067 float f = (float)NUM2DBL(argument);
00068 var = f;
00069
00070 }
00071 break;
00072 case T_TRUE:
00073 {
00074 var = true;
00075
00076 }
00077 break;
00078 case T_FALSE:
00079 {
00080 var = false;
00081
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 , 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 , 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 , 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 , VALUE path)
00165 {
00166 gMyPrivateContext->GetCore()->ImportBundle(STR2CSTR(path));
00167 return Qnil;
00168 }
00169
00170 VALUE
00171 run (VALUE , VALUE file)
00172 {
00173 gMyPrivateContext->GetCore()->GetScriptServer()->Run(STR2CSTR(file));
00174 return Qnil;
00175 }
00176
00177 VALUE
00178 newObject(VALUE , 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 , VALUE name)
00187 {
00188 gMyPrivateContext->Delete(STR2CSTR(name));
00189 return Qnil;
00190 }
00191
00192 VALUE
00193 getObject(VALUE , 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 )
00201 {
00202 gMyPrivateContext->ListObjects();
00203 return Qnil;
00204 }
00205
00206 VALUE
00207 pushd(VALUE )
00208 {
00209 gMyPrivateContext->Push();
00210 return Qnil;
00211 }
00212
00213 VALUE
00214 popd(VALUE )
00215 {
00216 gMyPrivateContext->Pop();
00217 return Qnil;
00218 }
00219
00220 VALUE
00221 dirs(VALUE )
00222 {
00223 gMyPrivateContext->Dir();
00224 return Qnil;
00225 }
00226
00227 ScriptServer::ScriptServer()
00228 {
00229 ruby_init();
00230
00231
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
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
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
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
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
00391 GCValue ns = rb_const_get(rb_cObject, rb_intern(nameSpace.c_str()));
00392
00393 if (! ns.IsNil())
00394 {
00395
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
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
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
00542 chdir(cwd);
00543 return true;
00544 }
00545
00546
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
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