Line data Source code
1 : /*
2 : * Copyright (c) 2010-2015: G-CSC, Goethe University Frankfurt
3 : * Author: Sebastian Reiter
4 : *
5 : * This file is part of UG4.
6 : *
7 : * UG4 is free software: you can redistribute it and/or modify it under the
8 : * terms of the GNU Lesser General Public License version 3 (as published by the
9 : * Free Software Foundation) with the following additional attribution
10 : * requirements (according to LGPL/GPL v3 §7):
11 : *
12 : * (1) The following notice must be displayed in the Appropriate Legal Notices
13 : * of covered and combined works: "Based on UG4 (www.ug4.org/license)".
14 : *
15 : * (2) The following notice must be displayed at a prominent place in the
16 : * terminal output of covered works: "Based on UG4 (www.ug4.org/license)".
17 : *
18 : * (3) The following bibliography is recommended for citation and must be
19 : * preserved in all covered files:
20 : * "Reiter, S., Vogel, A., Heppner, I., Rupp, M., and Wittum, G. A massively
21 : * parallel geometric multigrid solver on hierarchically distributed grids.
22 : * Computing and visualization in science 16, 4 (2013), 151-164"
23 : * "Vogel, A., Reiter, S., Rupp, M., Nägel, A., and Wittum, G. UG4 -- a novel
24 : * flexible software system for simulating pde based models on high performance
25 : * computers. Computing and visualization in science 16, 4 (2013), 165-179"
26 : *
27 : * This program is distributed in the hope that it will be useful,
28 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
29 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 : * GNU Lesser General Public License for more details.
31 : */
32 :
33 : //extern libraries
34 : #include <cassert>
35 : #include <cstring>
36 : #include <string>
37 : #include <stack>
38 :
39 :
40 : // ug libraries
41 : #include "ug.h"
42 : #include "lua_util.h"
43 : #include "common/util/path_provider.h"
44 : #include "common/util/file_util.h"
45 : #include "bindings_lua.h"
46 : #include "bridge/bridge.h"
47 : #include "registry/class_helper.h"
48 : #include "info_commands.h"
49 : #ifdef UG_DISC
50 : #include "lua_user_data.h"
51 : #endif
52 : #include "registry/class_name_provider.h"
53 : #include "registry/registry.h"
54 : #include "lua_debug.h"
55 : #include "lua_stack.h"
56 : #include "common/util/binary_buffer.h"
57 :
58 :
59 : #ifdef UG_PARALLEL
60 : #include "pcl/pcl.h"
61 : #include "pcl/pcl_util.h"
62 : #endif
63 :
64 : #ifdef USE_LUAJIT
65 : #include <lua.hpp>
66 : #endif
67 :
68 : using namespace std;
69 :
70 : namespace ug
71 : {
72 : #ifdef USE_LUA2C
73 : namespace bridge{
74 : bool RegisterConverter(Registry ®, const char* parentGroup);
75 : }
76 : #endif
77 :
78 : namespace script
79 : {
80 :
81 : #define PL_COULDNT_FIND -2
82 : #define PL_COULDNT_READ -1
83 :
84 :
85 : /**
86 : *
87 : * @param filename
88 : * @param returnedFilename
89 : * @return true if a file can be found at filename
90 : */
91 0 : bool GetNormalFilename(const string &filename, string &returnedFilename)
92 : {
93 0 : if(FileExists(filename.c_str())==false) return false;
94 : returnedFilename = filename;
95 0 : return true;
96 : }
97 :
98 :
99 : /**
100 : * say UG4_ROOT is the root path of ug4 (containing ugbase, apps, scripts and so on)
101 : * This function will search a file (in this order)
102 : * 1.) relative to the current script path.
103 : * 2.) as a normal, i.e. absolute or relative to the working directory, filename
104 : * 3.) relative to SCRIPT_PATH (normally UG4_ROOT/scripts)
105 : * 4.) relative to APPS_PATH (normally UG4_ROOT/apps)
106 : * 5.) relative to UG4_ROOT
107 : * @param filename
108 : * @param absoluteFilename
109 : * @return true if a file could be found at one of the locations
110 : */
111 0 : bool GetAbsoluteUGScriptFilename(const string &filename, string &absoluteFilename)
112 : {
113 : PROFILE_FUNC();
114 0 : return PathProvider::get_filename_relative_to_current_path(filename, absoluteFilename)
115 0 : || GetNormalFilename(filename, absoluteFilename)
116 0 : || PathProvider::get_filename_relative_to_path(SCRIPT_PATH, filename, absoluteFilename)
117 0 : || PathProvider::get_filename_relative_to_path(APPS_PATH, filename, absoluteFilename)
118 0 : || PathProvider::get_filename_relative_to_path(ROOT_PATH, filename, absoluteFilename);
119 : }
120 :
121 :
122 0 : std::string GetAbsoluteUGScriptFilenamePaths()
123 : {
124 0 : std::stringstream ss;
125 0 : ss << "Current Path = " << PathProvider::get_current_path()
126 0 : << ", SCRIPT_PATH = " << PathProvider::get_path(SCRIPT_PATH)
127 0 : << ", APPS_PATH = " << PathProvider::get_path(APPS_PATH)
128 0 : << ", ROOT_PATH = " << PathProvider::get_path(ROOT_PATH);
129 0 : return ss.str();
130 0 : }
131 :
132 : /**
133 : *
134 : * @param _filename the 'relative' script name. \sa GetAbsoluteUGScriptFilename
135 : * @param bDistributedLoad true if loading should be done in parallel
136 : * @param bThrowOnError true if errors should be thrown as UGError, else as return false
137 : * @return true if script could be found and read, false (or UGError) if not
138 : */
139 0 : bool LoadUGScript(const char *_filename, bool bDistributedLoad, bool bThrowOnError)
140 : {
141 : PROFILE_FUNC();
142 0 : string filename=_filename;
143 : string absoluteFilename=filename;
144 :
145 : //UG_LOG("LoadUGScript("<<filename<<", "<<(bDistributedLoad?"true":"false") << "\n");
146 : bool bSuccess = true;
147 : std::vector<char> file;
148 :
149 : #ifdef UG_PARALLEL
150 : if(pcl::NumProcs() == 1) bDistributedLoad = false;
151 : if(pcl::ProcRank() == 0 || bDistributedLoad==false)
152 : bSuccess = GetAbsoluteUGScriptFilename(filename, absoluteFilename);
153 : bSuccess = pcl::AllProcsTrue(bSuccess);
154 : #else
155 0 : bSuccess = GetAbsoluteUGScriptFilename(filename, absoluteFilename);
156 : #endif
157 0 : if(bSuccess == false)
158 : {
159 0 : if(bThrowOnError)
160 : {
161 0 : UG_THROW("Couldn't find script " << _filename << endl
162 : << "Search paths: " << GetAbsoluteUGScriptFilenamePaths() << endl);
163 : }
164 : return false;
165 : }
166 :
167 : #ifdef UG_PARALLEL
168 : if(pcl::ParallelReadFile(absoluteFilename, file, true, bDistributedLoad) == false)
169 : #else
170 0 : if(ReadFile(absoluteFilename.c_str(), file, true) == false)
171 : #endif
172 : {
173 0 : if(bThrowOnError) { UG_THROW("Couldn't read script " << absoluteFilename << endl); }
174 : return false;
175 : }
176 :
177 :
178 : // the current script working path is the path of the script
179 0 : std::string curPath = PathFromFilename(absoluteFilename);
180 : PathProvider::push_current_path(curPath);
181 : {
182 : // parse and execute the script.
183 0 : bSuccess = ParseAndExecuteBuffer(&file[0], (string("@")+absoluteFilename).c_str());
184 : }
185 : PathProvider::pop_current_path();
186 : return bSuccess;
187 0 : }
188 :
189 :
190 :
191 :
192 0 : bool LoadUGScript_Parallel(const char* filename)
193 : {
194 0 : return LoadUGScript(filename, true, true);
195 : }
196 0 : bool LoadUGScript_Single(const char* filename)
197 : {
198 0 : return LoadUGScript(filename, false, true);
199 : }
200 :
201 : static ug::bridge::Registry* g_pRegistry = NULL;
202 :
203 0 : static void UpdateScriptAfterRegistryChange(ug::bridge::Registry* pReg)
204 : {
205 : PROFILE_FUNC();
206 : UG_ASSERT(pReg == g_pRegistry, "static g_pRegistry does not match parameter pReg, someone messed up the registries!");
207 :
208 : // this can be called since CreateBindings automatically avoids
209 : // double registration
210 0 : ug::bridge::lua::CreateBindings_LUA(GetDefaultLuaState(),
211 : *pReg);
212 0 : }
213 :
214 1 : void RegisterDefaultLuaBridge(ug::bridge::Registry* reg, std::string grp)
215 : {
216 2 : if(reg->functionname_registered("ug_load_script"))
217 : return;
218 :
219 2 : reg->add_function("ug_load_script", &LoadUGScript_Parallel, "/ug4/lua",
220 : "success", "", "ONLY IF ALL CORES INVOLVED! Loads and parses a script and returns whether it succeeded.");
221 2 : reg->add_function("ug_load_script_single",
222 : &LoadUGScript_Single, "/ug4/lua",
223 : "success", "", "Loads and parses a script and returns whether it succeeded.");
224 :
225 1 : RegisterLuaDebug(*reg);
226 :
227 : // this define makes sure that no methods are referenced that
228 : // use the algebra, even if no algebra is included.
229 : #ifdef UG_ALGEBRA
230 : // Register info commands
231 1 : RegisterInfoCommands(*reg, grp.c_str());
232 : #ifdef USE_LUA2C
233 : RegisterConverter(*reg, grp.c_str());
234 : #endif
235 :
236 : // Register user functions
237 2 : RegisterLuaUserData(*reg, grp);
238 : #endif
239 : }
240 :
241 : static lua_State* theLuaState = NULL;
242 0 : lua_State* GetDefaultLuaState()
243 : {
244 : // if the state has not already been opened then do it now.
245 0 : if(!theLuaState)
246 : {
247 : PROFILE_BEGIN(CreateLUARegistry);
248 0 : if(!g_pRegistry){
249 : // store a pointer to the registry and avoid multiple callback registration
250 0 : g_pRegistry = &ug::bridge::GetUGRegistry();
251 0 : g_pRegistry->add_callback(UpdateScriptAfterRegistryChange);
252 : }
253 :
254 : // open a lua state
255 0 : theLuaState = lua_open();
256 : #ifdef USE_LUAJIT
257 : UG_ASSERT(theLuaState!=NULL, "FATAL ERROR: Not enough memory for lua?")
258 : #endif
259 :
260 : // open standard libs
261 0 : luaL_openlibs(theLuaState);
262 :
263 : // make metatables available in lua script
264 0 : lua_register(theLuaState, "ug_get_metatable", UGGetMetatable );
265 :
266 : // make base class check available in lua script
267 0 : lua_register(theLuaState, "ug_is_base_class", UGIsBaseClass);
268 :
269 : // make dim check available in lua script
270 0 : lua_register(theLuaState, "ug_dim_compiled", UGDimCompiled);
271 :
272 : // make algebra check available in lua script
273 0 : lua_register(theLuaState, "ug_algebra_compiled", UGAlgebraCompiled);
274 :
275 : // make class name available in lua script
276 0 : lua_register(theLuaState, "ug_class_name", UGGetClassName);
277 0 : lua_register(theLuaState, "ug_class_group", UGGetClassGroup);
278 :
279 : // create lua bindings for registered functions and objects
280 0 : ug::bridge::lua::CreateBindings_LUA(theLuaState, *g_pRegistry);
281 : }
282 :
283 0 : return theLuaState;
284 : }
285 :
286 : /// calls lua_close, which calls delete for all lua objects
287 0 : void ReleaseDefaultLuaState()
288 : {
289 0 : if(theLuaState != NULL)
290 : {
291 0 : lua_close(theLuaState);
292 0 : theLuaState = NULL;
293 : }
294 0 : FinalizeLUADebug();
295 0 : return;
296 : }
297 :
298 :
299 : /// error function to be used for lua_pcall
300 0 : int luaCallStackError( lua_State *L )
301 : {
302 : UG_LOG("LUA-ERROR! Call stack:\n");
303 0 : ug::bridge::LuaStackTrace(0);
304 0 : return 1;
305 : }
306 :
307 :
308 0 : bool ParseAndExecuteBuffer(const char* buffer, const char *bufferName)
309 : {
310 : PROFILE_FUNC();
311 0 : lua_State* L = GetDefaultLuaState();
312 :
313 0 : lua_pushcfunction(L, luaCallStackError);
314 :
315 : PROFILE_BEGIN(luaL_loadbuffer);
316 0 : int error = luaL_loadbuffer(L, buffer, strlen(buffer), bufferName);
317 : PROFILE_END_(luaL_loadbuffer);
318 :
319 0 : if(error == 0)
320 : {
321 : PROFILE_BEGIN(lua_pcall);
322 0 : error = lua_pcall(L, 0, 0, -2);
323 : }
324 :
325 0 : if(error)
326 : {
327 0 : string msg = lua_tostring(L, -1);
328 0 : lua_pop(L, 1);
329 0 : if(msg.find("__UG__LUA__EMPTY__MSG__") == string::npos)
330 0 : throw(LuaError(msg.c_str()));
331 : else
332 0 : throw(LuaError());
333 : }
334 :
335 0 : return true;
336 :
337 : }
338 :
339 :
340 0 : static void GetToStringFromStack(lua_State *L, std::stringstream &ss)
341 : {
342 0 : int nArgs = lua_gettop(L);
343 : int i;
344 0 : lua_getglobal(L, "tostring");
345 :
346 0 : for(i=1; i<=nArgs; i++)
347 : {
348 0 : lua_pushvalue(L, -1);
349 0 : lua_pushvalue(L, i);
350 0 : lua_call(L, 1, 1);
351 0 : const char *s = lua_tostring(L, -1);
352 0 : if(s) ss << s;
353 0 : lua_pop(L, 1);
354 : }
355 0 : lua_pop(L,1);
356 0 : }
357 :
358 : /// UGLuaPrint. Redirects LUA prints to UG_LOG
359 0 : int UGLuaPrint(lua_State *L)
360 : {
361 0 : std::stringstream ss;
362 0 : GetToStringFromStack(L, ss);
363 0 : ss << "\n";
364 0 : UG_LOG(ss.str());
365 0 : return 0;
366 0 : }
367 :
368 : /// UGLuaPrint. Redirects LUA prints to UG_LOG
369 0 : int UGLuaPrintAllProcs(lua_State *L)
370 : {
371 0 : std::stringstream ss;
372 0 : GetToStringFromStack(L, ss);
373 0 : ss << "\n";
374 0 : UG_LOG_ALL_PROCS(ss.str());
375 0 : return 0;
376 0 : }
377 :
378 :
379 : /// UGLuaWrite. Redirects LUA prints to UG_LOG without adding newline at the end
380 0 : int UGLuaWrite(lua_State *L)
381 : {
382 0 : std::stringstream ss;
383 0 : GetToStringFromStack(L, ss);
384 0 : UG_LOG(ss.str());
385 0 : GetLogAssistant().flush();
386 0 : return 0;
387 0 : }
388 :
389 : /// UGLuaErrLog.
390 0 : int UGLuaErrLog(lua_State *L)
391 : {
392 0 : std::stringstream ss;
393 0 : GetToStringFromStack(L, ss);
394 0 : ss << "\n";
395 0 : UG_ERR_LOG(ss.str());
396 0 : GetLogAssistant().flush();
397 0 : return 0;
398 0 : }
399 : //
400 : //static int LuaGetClassName(lua_State *L)
401 : //{
402 : // UG_LOG(lua_typename(L, lua_upvalueindex(1)));
403 : // bridge::IExportedClass* c = (bridge::IExportedClass*)lua_touserdata(L, lua_upvalueindex(1));
404 : // bridge::ParameterStack out;
405 : // if(c)
406 : // out.push(c->name());
407 : // else
408 : // out.push("error");
409 : // return bridge::ParamsToLuaStack(out, L);
410 : //}
411 : //
412 : //static int LuaGetClassGroup(lua_State *L)
413 : //{
414 : // bridge::IExportedClass* c = (bridge::IExportedClass*)lua_touserdata(L, lua_upvalueindex(1));
415 : // bridge::ParameterStack out;
416 : // if(c)
417 : // out.push(c->group());
418 : // else
419 : // out.push("error");
420 : // return bridge::ParamsToLuaStack(out, L);
421 : //}
422 :
423 0 : void RegisterStdLUAFunctions(lua_State *L)
424 : {
425 0 : lua_register(L, "print", UGLuaPrint );
426 0 : lua_register(L, "print_all", UGLuaPrintAllProcs );
427 0 : lua_register(L, "write", UGLuaWrite );
428 0 : lua_register(L, "err_log", UGLuaErrLog);
429 : // lua_register(L, "GetClassName", LuaGetClassName);
430 : // lua_register(L, "GetClassGroup", LuaGetClassGroup);
431 0 : }
432 :
433 0 : int UGGetMetatable(lua_State *L)
434 : {
435 0 : const char* name = lua_tostring(L, -1);
436 0 : if(name){
437 0 : luaL_getmetatable(L, name);
438 0 : return 1;
439 : }
440 0 : lua_pushnil(L);
441 0 : return 1;
442 : }
443 :
444 0 : int UGGetClassName(lua_State *L)
445 : {
446 0 : if(lua_getmetatable(L, -1) != 0)
447 : {
448 0 : lua_pushstring(L, "class_name_node");
449 0 : lua_rawget(L, -2);
450 0 : const ug::bridge::ClassNameNode* classNameNode = (const ug::bridge::ClassNameNode*) lua_touserdata(L, -1);
451 0 : lua_pop(L, 2);
452 :
453 0 : if(classNameNode)
454 : {
455 0 : lua_pushstring(L, classNameNode->name().c_str());
456 0 : return 1;
457 : }
458 0 : else UG_THROW("In UGGetClassName: Something wrong with ClassNameNode.");
459 : }
460 :
461 0 : lua_pushstring(L, "");
462 0 : return 1;
463 : }
464 :
465 0 : int UGGetClassGroup(lua_State *L)
466 : {
467 0 : if(lua_getmetatable(L, -1) != 0)
468 : {
469 0 : lua_pushstring(L, "class_name_node");
470 0 : lua_rawget(L, -2);
471 0 : const ug::bridge::ClassNameNode* classNameNode = (const ug::bridge::ClassNameNode*) lua_touserdata(L, -1);
472 0 : lua_pop(L, 2);
473 :
474 0 : if(classNameNode)
475 : {
476 0 : const bridge::Registry ® = bridge::GetUGRegistry();
477 0 : const bridge::IExportedClass *c = reg.get_class(classNameNode->name());
478 0 : lua_pushstring(L, c->group().c_str());
479 0 : return 1;
480 : }
481 0 : else UG_THROW("In UGGetClassGroup: Something wrong with ClassNameNode.");
482 : }
483 :
484 0 : lua_pushstring(L, "");
485 0 : return 1;
486 : }
487 :
488 :
489 0 : int UGIsBaseClass(lua_State *L)
490 : {
491 0 : const char* derivClass = lua_tostring(L, -1);
492 0 : const char* baseClass = lua_tostring(L, -2);
493 :
494 0 : if(!derivClass || !baseClass)
495 0 : UG_THROW("In UGIsBaseClass: invalid class names passed as arguments.");
496 :
497 0 : luaL_getmetatable(L, derivClass);
498 :
499 0 : if(!lua_isnil(L, -1))
500 : {
501 0 : lua_pushstring(L, "class_name_node");
502 0 : lua_rawget(L, -2);
503 0 : const ug::bridge::ClassNameNode* classNameNode = (const ug::bridge::ClassNameNode*) lua_touserdata(L, -1);
504 0 : lua_pop(L, 2);
505 :
506 0 : if(classNameNode)
507 : {
508 0 : if(!classNameNode->empty())
509 : {
510 0 : if(ClassNameTreeContains(*classNameNode, baseClass))
511 : {
512 0 : lua_pushboolean(L, true);
513 0 : return 1;
514 : }
515 : }
516 0 : lua_pushboolean(L, false);
517 0 : return 1;
518 : }
519 0 : else UG_THROW("In UGIsBaseClasse: Something wrong with ClassNameNode.");
520 : }
521 : else{
522 0 : UG_THROW("In UGIsBaseClass: Cannot find metatable for: "<< derivClass);
523 : }
524 :
525 : return 0;
526 : }
527 :
528 0 : void SetLuaUGArgs(lua_State* L, int argc, char* argv[])
529 : {
530 :
531 0 : lua_newtable(L);
532 : int ugargc=0;
533 0 : for(int i = 0; i < argc; ++i){
534 : // push the index to the table
535 0 : lua_pushnumber(L, ++ugargc);
536 : // push the value to the table
537 0 : lua_pushstring(L, argv[i]);
538 : // create the entry
539 0 : lua_settable(L, -3);
540 : }
541 : // set the tables name
542 0 : lua_setglobal(L, "ugargv");
543 :
544 0 : lua_pushnumber(L, ugargc);
545 0 : lua_setglobal(L, "ugargc");
546 0 : }
547 :
548 :
549 0 : int UGDimCompiled(lua_State *L)
550 : {
551 0 : int dim = lua_tointeger(L, -1);
552 : #if UG_DIM_1
553 0 : if(dim == 1){ lua_pushboolean(L, true); return 1;}
554 : #endif
555 : #if UG_DIM_2
556 0 : if(dim == 2){ lua_pushboolean(L, true); return 1;}
557 : #endif
558 : #if UG_DIM_3
559 0 : if(dim == 3){ lua_pushboolean(L, true); return 1;}
560 : #endif
561 0 : lua_pushboolean(L, false); return 1;
562 : }
563 :
564 0 : int UGAlgebraCompiled(lua_State *L)
565 : {
566 0 : std::string name = lua_tostring(L, -1);
567 : #if UG_CPU_1
568 0 : if(name == "CPU1"){ lua_pushboolean(L, true); return 1;}
569 : #endif
570 : #if UG_CPU_2
571 0 : if(name == "CPU2"){ lua_pushboolean(L, true); return 1;}
572 : #endif
573 : #if UG_CPU_3
574 0 : if(name == "CPU3"){ lua_pushboolean(L, true); return 1;}
575 : #endif
576 : #if UG_CPU_4
577 : if(name == "CPU4"){ lua_pushboolean(L, true); return 1;}
578 : #endif
579 : #if UG_CPU_5
580 : if(name == "CPU5"){ lua_pushboolean(L, true); return 1;}
581 : #endif
582 : #if UG_CPU_6
583 : if(name == "CPU6"){ lua_pushboolean(L, true); return 1;}
584 : #endif
585 : #if UG_CPU_VAR
586 : if(name == "CPUVAR"){ lua_pushboolean(L, true); return 1;}
587 : #endif
588 0 : lua_pushboolean(L, false); return 1;
589 : }
590 :
591 : }}// end of namespace
|