1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
17 //-----------------------------------------------------------------------------
19 //-----------------------------------------------------------------------------
23 #include "nel/misc/common.h"
24 #include "nel/misc/thread.h"
25 #include "nel/misc/command.h"
27 #include "stdin_monitor_thread.h"
30 //-----------------------------------------------------------------------------
32 //-----------------------------------------------------------------------------
37 //-----------------------------------------------------------------------------
38 // class CStdinMonitorThread
39 //-----------------------------------------------------------------------------
41 class CStdinMonitorThread
: public NLMISC::IRunnable
45 CStdinMonitorThread();
47 // main routine executed when the thread is started
50 // interface for adding commands, retrieving commands and verifying whether there are commands waiting
51 void pushCommand(std::string nextCommand
);
52 std::string
popCommand();
53 bool commandWaiting() const;
56 std::string _NextCommand
;
57 volatile bool _CommandWaiting
;
61 //-----------------------------------------------------------------------------
62 // methods CStdinMonitorThread
63 //-----------------------------------------------------------------------------
65 CStdinMonitorThread::CStdinMonitorThread()
67 _CommandWaiting
= false;
70 void CStdinMonitorThread::run ()
74 // wait for the main thread to deal with the previous command
75 while (commandWaiting())
80 // get the next command from the command line
81 char theCommand
[1024] = "";
82 if (!fgets(theCommand
, sizeofarray(theCommand
), stdin
))
84 nlwarning("fgets failed");
88 // push the command to allow reader thread to deal with it
89 pushCommand(theCommand
);
93 void CStdinMonitorThread::pushCommand(std::string nextCommand
)
95 // wait for the previous command to be treated
96 while (_CommandWaiting
)
101 // copy the next command into the appropriate buffer
102 _NextCommand
= nextCommand
;
104 while (!_NextCommand
.empty()
105 && (_NextCommand
[_NextCommand
.size()-1] == '\n'
106 || _NextCommand
[_NextCommand
.size()-1] == '\r'))
108 _NextCommand
= _NextCommand
.substr(0, _NextCommand
.size()-1);
111 // set the _CommandWaiting flag, to allow reader thread to treat the new command
112 _CommandWaiting
= true;
115 std::string
CStdinMonitorThread::popCommand()
117 // wait for a command to be ligned up (waiting)
118 while (!_CommandWaiting
)
122 // copy out the next command
123 std::string result
= _NextCommand
;
125 // clear out the next command variable ready for its next use
126 _NextCommand
.clear();
128 // clear the _CommandWaiting flag, to allow writer thread to add a new command
129 _CommandWaiting
= false;
131 // all done so return the command
135 bool CStdinMonitorThread::commandWaiting() const
137 return _CommandWaiting
;
141 //-----------------------------------------------------------------------------
142 // class CStdinMonitorSingleton
143 //-----------------------------------------------------------------------------
145 class CStdinMonitorSingleton
: public IStdinMonitorSingleton
148 // static for getting hold of the singleton instance
149 static CStdinMonitorSingleton
* getInstance();
151 // methods required by IStdinMonitorSingleton
157 // this is a singleton so dissallow construction from outside...
158 CStdinMonitorSingleton();
159 CStdinMonitorSingleton(const CStdinMonitorSingleton
&);
160 CStdinMonitorSingleton
& operator =(const CStdinMonitorSingleton
&);
163 // data for the singleton instance
164 CStdinMonitorThread
* _StdinMonitorThreadInstance
;
165 NLMISC::IThread
* _StdinMonitorThreadHandle
;
169 //-----------------------------------------------------------------------------
170 // methods IStdinMonitorSingleton
171 //-----------------------------------------------------------------------------
173 IStdinMonitorSingleton
* IStdinMonitorSingleton::getInstance()
175 return CStdinMonitorSingleton::getInstance();
179 //-----------------------------------------------------------------------------
180 // methods CStdinMonitorSingleton
181 //-----------------------------------------------------------------------------
183 CStdinMonitorSingleton
* CStdinMonitorSingleton::getInstance()
185 static CStdinMonitorSingleton
* instance
= NULL
;
187 instance
= new CStdinMonitorSingleton
;
191 void CStdinMonitorSingleton::init()
193 _StdinMonitorThreadInstance
= new CStdinMonitorThread
;
194 _StdinMonitorThreadHandle
= NLMISC::IThread::create (_StdinMonitorThreadInstance
, 1024*4*4);
195 _StdinMonitorThreadHandle
->start();
198 void CStdinMonitorSingleton::update()
200 // if we're not initialised yet then return
201 if (_StdinMonitorThreadInstance
== NULL
)
204 // if there's a command waiting then treat it (not more than one command per visit)
205 if (_StdinMonitorThreadInstance
->commandWaiting())
207 std::string nextCommand
= _StdinMonitorThreadInstance
->popCommand();
208 if (!nextCommand
.empty())
210 NLMISC::ICommand::execute(nextCommand
,*NLMISC::InfoLog
);
215 void CStdinMonitorSingleton::release()
217 // if we've never been initialised or we've already been released thent there's nothing more to do...
218 if (_StdinMonitorThreadInstance
== NULL
)
221 // terminate the thread and wait for it to finish
222 _StdinMonitorThreadHandle
->terminate();
223 _StdinMonitorThreadHandle
->wait();
225 // destroy the thread object instance and reset the pointer to NULL to mark as 'uninitialised'
226 delete _StdinMonitorThreadInstance
;
227 _StdinMonitorThreadInstance
= NULL
;
230 CStdinMonitorSingleton::CStdinMonitorSingleton()
232 _StdinMonitorThreadHandle
= NULL
;
233 _StdinMonitorThreadInstance
= NULL
;
236 CStdinMonitorSingleton::CStdinMonitorSingleton(const CStdinMonitorSingleton
&)
238 _StdinMonitorThreadHandle
= NULL
;
239 _StdinMonitorThreadInstance
= NULL
;
242 CStdinMonitorSingleton
& CStdinMonitorSingleton::operator =(const CStdinMonitorSingleton
&)