source: nrEngine/src/Script.cpp @ 1

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