source: nrEngine/src/Script.cpp @ 24

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