source: nrEngine/src/Script.cpp @ 25

Revision 25, 10.1 KB checked in by art, 13 years ago (diff)
Line 
1/***************************************************************************
2 *                                                                         *
3 *   (c) Art Tevs, MPI Informatik Saarbruecken                             *
4 *       mailto: <tevs@mpi-sb.mpg.de>                                      *
5 *                                                                         *
6 *   This program is free software; you can redistribute it and/or modify  *
7 *   it under the terms of the GNU General Public License as published by  *
8 *   the Free Software Foundation; either version 2 of the License, or     *
9 *   (at your option) any later version.                                   *
10 *                                                                         *
11 ***************************************************************************/
12
13
14//----------------------------------------------------------------------------------
15// Includes
16//----------------------------------------------------------------------------------
17#include "Script.h"
18#include "ScriptEngine.h"
19#include "Clock.h"
20#include "Log.h"
21#include "Kernel.h"
22
23namespace nrEngine {
24
25        //----------------------------------------------------------------------------------
26        Script::Script() : IScript("Script")
27        {
28                mLastLine = 0;
29                mLoop = NO_LOOP;
30                mTime = 0;
31                bRunStepwise = true;
32                mStopTime = 0;
33                mRunningTimeLength = 0;
34        }
35
36        //----------------------------------------------------------------------------------
37        Script::~Script()
38        {
39                unloadRes();
40        }
41
42
43        //----------------------------------------------------------------------------------
44        Result Script::loadFromString(const std::string& str)
45        {
46                // set task name as resource name
47                setTaskName(getResName() + "_ScriptTask");
48               
49                // setup content
50                mContent = str;
51                return parse(mContent);
52        }
53
54        //------------------------------------------------------------------------------
55        Result Script::parse(const std::string& script){
56
57                std::stringstream str(script);
58                if (script.length() == 0 || !str.good()) return OK;
59
60                // get linewise
61                char buf[1024];
62                std::string buffer;
63                std::string::size_type pos;
64                std::string line;
65                int32 l = 0;
66
67                while (!str.eof()){
68                        l ++;
69                        mLastLine = l;
70
71                        str.getline(buf, 1024);
72                        buffer = std::string(buf);
73
74                        // get the line without comments
75                        pos = buffer.find("//");
76                        if (pos == std::string::npos)
77                                line = buffer;
78                        else
79                                line = buffer.substr(0, pos);
80
81                        // if the line is empty, so get the next one
82                        if (line.length() == 0) continue;
83
84                        // check for script parameters
85                        pos = line.find('^');
86                        if (pos != std::string::npos){
87                                std::string param = trim(line.substr(pos+1));
88                                if (!setParameter(param)){
89                                        NR_Log(Log::LOG_ENGINE, Log::LL_ERROR, "Script: Unknown local parameter %s in line %d", param.c_str(), l);
90                                        return SCRIPT_PARSE_ERROR;
91                                }
92                                continue;
93                        }
94
95                        // check if we do have any command in the line
96                        pos = line.find_first_not_of(' ', 0);
97                        if (pos == std::string::npos)
98                                continue;
99                       
100                       
101                        // check for the timestamp
102                        pos = line.find('|');
103                        Command cmd;
104                        cmd.timestamp = 0;
105                        cmd.estimatedStart = 0;
106
107                        // timestamp found, so do extra stuff with this kind of commands
108                        if(pos != std::string::npos ){
109
110                                // retrieve the timestamp and the command and store it into the command buffer
111                                std::string time = trim(line.substr(0,pos));
112                                std::string command = line.substr(pos+1);
113                               
114                                // try to convert the time and add the command to the list
115                                try{
116                                        cmd.timestamp = boost::lexical_cast<float32>(time);
117                                        tokenize(command, cmd.cmd, cmd.args);
118                                        if (cmd.args.size() > 0 && cmd.args[0].length() > 0)
119                                        {
120                                                if (cmd.cmd == std::string("_stop_"))
121                                                {
122                                                        mRunningTimeLength = cmd.timestamp;
123                                                }else
124                                                        mTimedCommand.push_back(cmd);
125                                        }
126                                }catch(...){
127                                        NR_Log(Log::LOG_ENGINE, Log::LL_ERROR, "Script: Unknown syntax in %d\n", l);
128                                        return SCRIPT_PARSE_ERROR;
129                                }
130
131                        // timestamp not found, so it is a simple command
132                        }else{
133                                tokenize(line, cmd.cmd, cmd.args);
134                                if (cmd.args.size() > 0 && cmd.args[0].length() > 0)
135                                {
136                                        mCommand.push_back(cmd);
137                                }
138                        }
139                }
140
141                resetCommandFifo();
142                resetTimedCommandFifo();
143               
144                // if we got any command so we are valid
145                return OK;
146        }
147
148        //------------------------------------------------------------------------------
149        void Script::tokenize(const std::string& str, std::string& cmd, std::vector<std::string>& tokens)
150        {
151                // do not tokenize if we do not get any token
152                if (str.length() == 0) return;
153               
154                using namespace std;
155               
156                // tokenize on space characters
157                const string delimiters = " ";
158               
159                // Skip delimiters at beginning.
160                string::size_type lastPos = str.find_first_not_of(delimiters, 0);
161               
162                // Find first "non-delimiter".
163                string::size_type pos     = str.find_first_of(delimiters, lastPos);
164       
165                while (pos != string::npos || lastPos != string::npos)
166                {
167                        // Found a token, add it to the vector.
168                        if (pos  - lastPos > 0) 
169                                tokens.push_back(str.substr(lastPos, pos - lastPos));
170
171                        // Skip delimiters.  Note the "not_of"
172                        lastPos = str.find_first_not_of(delimiters, pos);
173
174                        // Find next "non-delimiter"
175                        pos = str.find_first_of(delimiters, lastPos);
176                }
177
178                // now the first element in the token list is the command name
179                cmd = tokens[0];
180        }
181
182        //------------------------------------------------------------------------------
183        bool Script::setParameter(const std::string& param){
184
185                if (param == "loop")
186                        mLoop |= LOOP;
187                else if (param == "loop_seq")
188                        mLoop |= LOOP_COMMAND;
189                else if (param == "loop_timed")
190                        mLoop |= LOOP_TIMED_COMMAND;
191                else if (param == "runcomplete")
192                        bRunStepwise = false;
193                else if (param == "runonce")
194                        setRunOnce(true);
195                else
196                        return false;
197
198                return true;
199        }
200
201        //------------------------------------------------------------------------------
202        void Script::resetCommandFifo()
203        {
204                // the untimed command fifo is very simple
205                // the commands are executed in the way they were found in the file
206                mCommandFifo.clear();
207                for (uint32 i=0; i < mCommand.size(); i++){
208                        mCommandFifo.push_front(i);
209                }
210        }
211
212        //------------------------------------------------------------------------------
213        void Script::resetTimedCommandFifo()
214        {
215                // the timed commands are also setted in the fifo
216                // the estimated end time is also computed
217                mTimedCommandFifo.clear();
218                for (uint32 i=0; i < mTimedCommand.size(); i++)
219                {
220                        mTimedCommandFifo.push_front(i);
221                        mTimedCommand[i].estimatedStart = Engine::sClock()->getTime() + mTimedCommand[i].timestamp;
222                }
223        }
224
225        //----------------------------------------------------------------------------------
226        Result Script::step()
227        {
228                // update time
229                mTime = Engine::sClock()->getTime();
230                if (mStopTime == 0 && mRunningTimeLength > 0)
231                        mStopTime = mTime + mRunningTimeLength;
232                       
233                // ----- timed commands (quasi parallel execution) -----
234                // scan through the command fifo
235                std::list<int32>::iterator it;
236                for (it = mTimedCommandFifo.begin(); it != mTimedCommandFifo.end(); )
237                {
238                        int32 id = *it;
239                        mTimedCommand[id].time = mTime;
240
241                        //printf("%s: %f %f\n", mTimedCommand[id].cmd.c_str(), mTimedCommand[id].estimatedStart, mTimedCommand[id].time);
242                       
243                        // if the estimated start time is reeached, so start the command and remove it from the queue
244                        if (mTimedCommand[id].estimatedStart < mTimedCommand[id].time)
245                        {
246                                // remove the command from the fifo
247                                it = mTimedCommandFifo.erase(it);
248
249                                // call the commando
250                                Engine::sScriptEngine()->call(mTimedCommand[id].cmd, mTimedCommand[id].args);
251                        }else
252                                it ++;
253                }
254               
255                // ----- sequentiall commands -----
256                if (mCommandFifo.size())
257                {
258                        // get the id of the command
259                        int32 id = mCommandFifo.back();
260                        mCommandFifo.pop_back();
261
262                        // check if we have a stop commando
263                        if (mCommand[id].cmd != std::string("_stop_"))
264                        {
265                                Engine::sScriptEngine()->call(mCommand[id].cmd, mCommand[id].args);
266                        }else{
267                                Engine::sKernel()->RemoveTask(this->getTaskID());
268                        }
269                        // check for time reset command
270                        if (mCommand[id].cmd != std::string("_reset_script_time_"))
271                        {
272                                resetTimedCommandFifo();
273                        }
274                }
275
276                // reset the command list
277                reset();
278
279                // check whenever execution time of the script exceeds
280                if (mTime > mStopTime && mStopTime > 0)
281                {
282                                Engine::sKernel()->RemoveTask(this->getTaskID());
283                }
284
285                return OK;
286        }
287
288        //----------------------------------------------------------------------------------
289        bool Script::hasCommands()
290        {
291                if (mCommandFifo.size() == 0 && mTimedCommandFifo.size() == 0 && !(mLoop & LOOP_COMMAND) && !(mLoop & LOOP_TIMED_COMMAND))
292                        return false;
293               
294                return true;
295        }
296       
297        //----------------------------------------------------------------------------------
298        Result Script::run()
299        {
300                // check whenver this script is running stepwise
301                if (bRunStepwise) return step();
302
303                return fullRun();
304        }
305
306       
307        //----------------------------------------------------------------------------------
308        Result Script::fullRun()
309        {
310
311                // check for looped script
312                static bool warned = false;
313                if (!warned && mLoop & LOOP_COMMAND){
314                        warned = true;
315                        NR_Log(Log::LOG_ENGINE, Log::LL_WARNING, "Script: %s - you are executing a looped script!!! Check this!!!", getResName().c_str());
316                }
317
318                // loop the content of the script if script should be looped
319                bool bLoop = false;
320                do {
321                        // we go through the whole command list and execute it.
322                        while (mCommandFifo.size() > 0)
323                        {
324                                // get the id of the command
325                                int32 id = mCommandFifo.back();
326                                mCommandFifo.pop_back();
327
328                                // execute it
329                                Engine::sScriptEngine()->call(mCommand[id].cmd, mCommand[id].args);
330                        }
331       
332                        // reset the list and check if the task is removed from the kernel
333                        reset();
334                        bLoop = hasCommands();
335                       
336                } while(bLoop && (mLoop & LOOP_COMMAND));
337                       
338                return OK;
339        }
340
341        //--------------------------------------------------------------------
342        void Script::onStartScript()
343        {
344                // reset the script, so it can run
345                resetCommandFifo();
346                resetTimedCommandFifo();
347        }
348
349        //----------------------------------------------------------------------------------
350        bool Script::reset()
351        {
352                if (mCommandFifo.size() == 0 && (mLoop & LOOP_COMMAND)){
353                        resetCommandFifo();
354                }else if (mTimedCommandFifo.size() == 0 && (mLoop & LOOP_TIMED_COMMAND)){
355                        resetTimedCommandFifo();
356                }
357                return true;
358        }
359       
360};
361
Note: See TracBrowser for help on using the repository browser.