source: nrEngine/src/Script.cpp @ 23

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