source: Sophya/trunk/SophyaLib/SysTools/commander.cc@ 2955

Last change on this file since 2955 was 2955, checked in by ansari, 19 years ago

Ajout gestionnaire signal ds ZThread et correction/adaptation gestion des threads (killthr) dans Commander - Reza 29 mai 2006

File size: 65.4 KB
Line 
1#include "sopnamsp.h"
2#include "commander.h"
3#include <stdio.h>
4#include <stdlib.h>
5#include <unistd.h>
6#include <ctype.h>
7#include <math.h>
8#include <signal.h>
9
10#include "strutil.h"
11#include "strutilxx.h"
12#include "cexpre.h"
13#include "rpneval.h"
14#include "srandgen.h"
15#include "zthread.h"
16
17
18namespace SOPHYA {
19
20// Differents code de retour specifiques
21#define CMD_RETURN_RC 99900
22#define CMD_BREAK_RC 99990
23#define CMD_BREAKEXE_RC 99999
24
25// ------------------------------------------------------------
26// Bloc de commandes (Foreach, ...)
27// Classe CommanderBloc
28// ------------------------------------------------------------
29/*!
30 \internal
31 \class SOPHYA::CommanderBloc
32 \ingroup SysTools
33 Class for internal use by class Commander to handle loops
34*/
35class CommanderBloc {
36public:
37 enum BType { BT_None, BT_ForeachList, BT_ForeachInt, BT_ForeachFloat,
38 BT_ForeachLineInFile };
39
40 CommanderBloc(Commander* piac, CommanderBloc* par, string& kw, vector<string>& args);
41 ~CommanderBloc();
42 inline CommanderBloc* Parent() { return(parent); }
43 inline bool CheckOK() { return blkok; }
44 inline void AddLine(string& line)
45 { lines.push_back(line); bloclineid.push_back(lines.size()); }
46 void AddLine(string& line, string& kw);
47 inline void AddBloc(CommanderBloc* blk)
48 { blocs.push_back(blk); bloclineid.push_back(-blocs.size()); }
49
50 // Execution complete du bloc (boucle)
51 int Execute();
52 // Execution pour un element de bloc
53 int ExecuteOnce(string& lvv);
54
55 inline int& TestLevel() { return testlevel; }
56 inline int& LoopLevel() { return looplevel; }
57 inline bool CheckBloc()
58 { return ((testlevel == 0)&&(looplevel == 0)&&(!scrdef)); }
59
60protected:
61 Commander* _commander;
62 CommanderBloc* parent;
63 bool blkok; // true -> block OK
64 BType typ; // foreach , integer loop, float loop, test
65 string varname;
66 string filename; // forinfile bloc
67 vector<string> strlist;
68 vector<string> lines;
69 vector<CommanderBloc *> blocs;
70 vector<int> bloclineid;
71 int i1,i2,di;
72 float f1,f2,df;
73 int testlevel; // niveau d'imbrication des if
74 int looplevel; // niveau d'imbrication des for/foreach
75 bool scrdef; // true -> commande defscript ds for/foreach
76};
77
78/* --Methode-- */
79CommanderBloc::CommanderBloc(Commander* piac, CommanderBloc* par, string& kw, vector<string>& args)
80{
81_commander = piac;
82parent = par;
83blkok = false;
84typ = BT_None;
85i1 = 0; i2 = -1; di = 1;
86f1 = 0.; f2 = -1.; df = 1.;
87testlevel = looplevel = 0;
88scrdef = false;
89
90if ((args.size() < 2) || !isalpha((int)args[0][0]) ) return;
91if ((kw != "foreach") && (kw != "for") && (kw != "forinfile")) return;
92if (!piac->CheckVarName(args[0])) return;
93varname = args[0];
94
95//if (isalpha((int)args[1][0]) ) { This is a foreach bloc with string list
96if (kw == "forinfile") {
97 filename = args[1];
98 typ = BT_ForeachLineInFile;
99 blkok = true;
100}
101else if (kw == "foreach" ) { // This is a foreach bloc with string list
102 if ( (args[1] == "(") && (args[args.size()-1] == ")") ) {
103 // foreach varname ( w1 w2 w3 ... )
104 for(int kk=2; kk<args.size()-1; kk++) strlist.push_back(args[kk]);
105 }
106 else {
107 // foreach varname WordVectorName
108 if (!piac->GetVar(args[1], strlist)) return;
109 }
110 if (strlist.size() < 1) return;
111 typ = BT_ForeachList;
112 blkok = true;
113}
114else { // This is an integer or float loop
115 size_t l = args[1].length();
116 size_t p = args[1].find(':');
117 size_t pp = args[1].find('.');
118 bool fl = (pp < l) ? true : false; // Float loop or integer loop
119 if (p >= l) return; // Syntaxe error
120 string a1 = args[1].substr(0, p);
121 string aa = args[1].substr(p+1);
122 p = aa.find(':');
123 string a2, a3;
124 bool hasa3 = false;
125 if (p < aa.length() ) {
126 a2 = aa.substr(0,p);
127 a3 = aa.substr(p+1);
128 hasa3 = true;
129 }
130 else a2 = aa;
131 if (fl) {
132 typ = BT_ForeachFloat;
133 blkok = true;
134 f1 = atof(a1.c_str());
135 f2 = atof(a2.c_str());
136 if (hasa3) df = atof(a3.c_str());
137 else df = 1.;
138 }
139 else {
140 typ = BT_ForeachInt;
141 blkok = true;
142 i1 = atoi(a1.c_str());
143 i2 = atoi(a2.c_str());
144 if (hasa3) di = atoi(a3.c_str());
145 else di = 1;
146 }
147 }
148}
149
150/* --Methode-- */
151CommanderBloc::~CommanderBloc()
152{
153for(int k=0; k<blocs.size(); k++) delete blocs[k];
154}
155
156/* --Methode-- */
157void CommanderBloc::AddLine(string& line, string& kw)
158{
159 AddLine(line);
160 if (kw == "if") testlevel++;
161 else if (kw == "endif") testlevel--;
162 else if ((kw == "for") || (kw == "foreach")) looplevel++;
163 else if (kw == "end") looplevel--;
164 else if (kw == "defscript") scrdef = true;
165}
166
167/* --Methode-- */
168int CommanderBloc::Execute()
169{
170int k=0;
171char buff[32];
172int rcc = 0;
173
174int mxloop = _commander->GetMaxLoopLimit();
175
176if (typ == BT_ForeachLineInFile) { // foreach line in file loop
177 ifstream is(filename.c_str());
178 char buff[256];
179 string line;
180 while (!is.eof()) {
181 /* Reza, Juin 2005 : Remplace par getline(istream, string) - plus sur
182 is.getline(buff, 256); line += buff; */
183 rcc = 0;
184 line = "";
185 getline(is,line);
186 if (is.good() || is.eof()) {
187 rcc = ExecuteOnce(line);
188 if (rcc == CMD_BREAKEXE_RC) return rcc;
189 else if (rcc == CMD_BREAK_RC) break;
190 }
191 }
192}
193else if (typ == BT_ForeachList) { // foreach string loop
194 for(k=0; k<strlist.size(); k++) {
195 rcc = ExecuteOnce(strlist[k]);
196 if (rcc == CMD_BREAKEXE_RC) return rcc;
197 else if (rcc == CMD_BREAK_RC) break;
198 }
199}
200else if (typ == BT_ForeachInt) { // Integer loop
201 for(int i=i1; i<i2; i+=di) {
202 k++;
203 if ((mxloop>0) && (k > mxloop)) {
204 cout << ">>> Maximum CommanderBloc loop limit ("<< mxloop << ") -> break " << endl;
205 break;
206 }
207 sprintf(buff, "%d", i);
208 string lvv = buff;
209 rcc = ExecuteOnce(lvv);
210 if (rcc == CMD_BREAKEXE_RC) return rcc;
211 else if (rcc == CMD_BREAK_RC) break;
212 }
213}
214else if (typ == BT_ForeachFloat) { // float loop
215 for(double f=f1; f<f2; f+=df) {
216 k++;
217 if ((mxloop>0) && (k > mxloop)) {
218 cout << ">>> Maximum CommanderBloc loop limit ("<< mxloop << ") -> break " << endl;
219 break;
220 }
221 sprintf(buff, "%g", f);
222 string lvv = buff;
223 rcc = ExecuteOnce(lvv);
224 if (rcc == CMD_BREAKEXE_RC) return rcc;
225 else if (rcc == CMD_BREAK_RC) break;
226 }
227}
228return(rcc);
229}
230
231/* --Methode-- */
232int CommanderBloc::ExecuteOnce(string& lvv)
233{
234 int kj=0;
235 int kk=0;
236 int rcc = 0;
237 _commander->SetVar(varname, lvv);
238 for(kj=0; kj<bloclineid.size(); kj++) {
239 rcc = 0;
240 kk = bloclineid[kj];
241 if (kk > 0)
242 rcc = _commander->Interpret(lines[kk-1]);
243 else
244 rcc = blocs[-kk-1]->Execute();
245 if (rcc == CMD_BREAKEXE_RC) return (rcc);
246 if (rcc == CMD_BREAK_RC) break;
247 }
248 return rcc;
249}
250
251// ---------------------------------------------------------------
252// Classe CommanderScript
253// Definition et execution d'un script de Commander
254// script : Une liste de commande Commander - Lors de l'execution,
255// les variables-argument $# $0 $1 sont definies.
256// ---------------------------------------------------------------
257
258/*!
259 \internal
260 \class SOPHYA::CommanderScript
261 \ingroup SysTools
262 Class for internal use by class Commander to handle functions
263 or scripts
264*/
265
266class CommanderScript {
267public:
268 CommanderScript(Commander* piac, string const& name, string const& comm);
269 virtual ~CommanderScript();
270
271 void AddLine(string& line, string& kw);
272 virtual int Execute(vector<string>& args);
273
274 inline string& Name() { return mName; }
275 inline string& Comment() { return mComm; }
276 inline int& TestLevel() { return testlevel; }
277 inline int& LoopLevel() { return looplevel; }
278 inline bool CheckScript()
279 { return ((testlevel == 0)&&(looplevel == 0)&&(!scrdef)&&fgok); }
280
281protected:
282 Commander* _commander;
283 string mName;
284 string mComm;
285 vector<string> lines;
286 int testlevel; // niveau d'imbrication des if
287 int looplevel; // niveau d'imbrication des for/foreach
288 bool scrdef; // true -> commande defscript ds for/foreach
289 bool fgok; // Script name OK
290
291};
292
293/* --Methode-- */
294CommanderScript::CommanderScript(Commander* piac, string const& name,
295 string const& comm)
296{
297_commander = piac;
298testlevel = looplevel = 0;
299scrdef = false;
300mName = name;
301if (!isalpha(name[0])) fgok = false;
302else fgok = true;
303mComm = comm;
304}
305
306/* --Methode-- */
307CommanderScript::~CommanderScript()
308{
309}
310
311/* --Methode-- */
312void CommanderScript::AddLine(string& line, string& kw)
313{
314 if (kw == "if") testlevel++;
315 else if (kw == "endif") testlevel--;
316 else if ((kw == "for") || (kw == "foreach")) looplevel++;
317 else if (kw == "end") looplevel--;
318 else if (kw == "defscript") scrdef = true;
319 lines.push_back(line);
320}
321
322/* --Methode-- */
323int CommanderScript::Execute(vector<string>& args)
324{
325 int rcc;
326 if (!CheckScript()) return(-1);
327 cout << " CommanderScript::Execute() - Executing script " << Name() << endl;
328 for(int k=0; k<lines.size(); k++) {
329 rcc = _commander->Interpret(lines[k]);
330 if ( (rcc == CMD_BREAKEXE_RC) || (rcc == CMD_RETURN_RC) ) break;
331 }
332 return(rcc);
333}
334
335
336// ------------------------------------------------------------
337// Classe CommandExeThr
338// ------------------------------------------------------------
339/*!
340 \internal
341 \class SOPHYA::CommandExeThr
342 \ingroup SysTools
343 Class for internal use by class Commander for command execution in separate threads.
344 The command execution is carried in method run() which has its own exception handling bloc.
345*/
346class CommandExeThr : public ZThread {
347public:
348 CommandExeThr(uint_8 id, CmdExecutor * cmdex, string& keyw,
349 vector<string>& args, string& toks);
350 virtual void run();
351 inline uint_8 Id() { return _id; }
352 inline bool IfDone() { return _fgdone; }
353 inline string& Tokens() { return _toks; }
354 inline string& Keyword() { return _keyw; }
355protected:
356 uint_8 _id;
357 CmdExecutor * _cmdex;
358 string _keyw, _toks;
359 vector<string> _args;
360 bool _fgdone;
361};
362
363/* --Methode-- */
364CommandExeThr::CommandExeThr(uint_8 id, CmdExecutor * cmdex, string& keyw,
365 vector<string>& args, string& toks)
366{
367 _id = id;
368 _cmdex = cmdex;
369 _keyw = keyw;
370 if (args.size() > 1)
371 for(size_t k=0; k<args.size()-1; k++) _args.push_back(args[k]);
372 _toks = toks;
373 for(size_t k=_toks.size()-1; k>0; k--)
374 if (_toks[k] == '&') { _toks[k] = ' '; break; }
375 _fgdone = false;
376}
377
378/* --Methode-- */
379void CommandExeThr::run()
380{
381 int rc = 0;
382 try {
383 rc = _cmdex->Execute(_keyw, _args, _toks);
384 }
385 catch (PThrowable& exc) {
386 cout << "CommandExeThr::run() Catched Exception Msg()= "
387 << exc.Msg() << endl;
388 rc = -77;
389 }
390 catch (std::exception& sex) {
391 cout << "CommandExeThr::run() Catched std::exception what()= "
392 << sex.what() << endl;
393 rc = -78;
394 }
395 catch (...) {
396 cout << "CommandExeThr::run() Catched unknown (...) exception " << endl;
397 rc = -79;
398 }
399 _fgdone = true;
400 setRC(rc);
401}
402
403// ------------------------------------------------------------
404// Classe Commander
405// ------------------------------------------------------------
406typedef void (* DlModuleInitEndFunction) ();
407
408/*!
409 \class Commander
410 \ingroup SysTools
411 \brief Simple command interpreter
412
413 This Simple command interpreter with c-shell like syntax
414 can be used to add scripting capabilities
415 to applications.
416
417 Although the interpreter has many limitations compared to
418 c-shell, or Tcl , it provides some interesting possibilities:
419
420 - Extended arithmetic operations (c-like and RPN)
421 - Simple and vector variables
422 - Script definition
423 - Command execution in separate threads
424 - Dynamic Load
425
426 \sa CmdExecutor CExpressionEvaluator RPNExpressionEvaluator
427
428 Usage example:
429 \code
430 #include "commander.h"
431 ...
432 Commander cmd;
433 char* ss[3] = {"foreach f ( AA bbb CCCC ddddd )", "echo $f" , "end"};
434 for(int k=0; k<3; k++) {
435 string line = ss[k];
436 cmd.Interpret(line);
437 }
438 \endcode
439*/
440
441#define _MAGENTA_ 1
442
443static Commander* cur_commander = NULL;
444/* --Methode-- */
445/*!
446 \brief Constructor. Initializes variable list and copies \c history.pic to \c hisold.pic
447 if \b fgsigstop == true , calls ZThread::ActivateExitOnSignal()
448*/
449Commander::Commander(bool fgsigzt)
450{
451system("cp history.pic hisold.pic");
452hist.open("history.pic");
453histon = true;
454trace = false; timing = false;
455gltimer = NULL;
456felevel = 0;
457
458mulinecmd = "";
459mulinefg = false;
460spromptmul = "Cmd> ";
461SetCurrentPrompt(spromptmul);
462SetDefaultPrompt(spromptmul);
463curscript = NULL;
464
465_xstatus = 0;
466 _retstr = "";
467
468// Controle du flot d'execution
469 fgexebrk = false;
470
471CmdBlks.push(NULL);
472list<char> xtx;
473TestsStack.push(xtx);
474curtestresult = true;
475
476// Pour la numerotation et l'identification des threads
477ThrId = 0;
478
479// Numero de help-groupe courant - Le premier groupe ajoute aura un gid = 1
480// gid = 0 n'existe pas : c'est le groupe de toutes les commandes
481cmdgrpid = 0;
482
483string grp = "Commander";
484string gdesc = "Basic (generic) interpreter (class SOPHYA::Commander) builtin commands";
485AddHelpGroup(grp, gdesc);
486
487string kw = "Commander";
488string usage;
489usage = ">>> (Commander) Interpreter's keywords : \n";
490usage += " > set varname string # To set a variable, $varname \n";
491usage += " > unset varname # clear variable definition \n";
492usage += " > rpneval varname RPNExpression # Reverse Polish Notation evaluation \n";
493usage += " > varname = ArithmeticExpression # C-like Expression evaluation \n";
494usage += " > varname = 'String' # Set variable vname \n";
495usage += " > var2words varname wordvarname [sep] # to break varname into words \n";
496usage += " > echo string # output string \n";
497usage += " > echo2file filename string # Append the string to the specified file \n";
498usage += " > alias name string # define a command alias \n";
499usage += " > foreach varname ( string-list ) # Loop \n";
500usage += " > for varname i1:i2[:di] # Integer loop \n";
501usage += " > for varname f1:f2[:df] # Float loop \n";
502usage += " > forinfile varname FileName # Loop over lines in file \n";
503usage += " > end # end loops \n";
504usage += " > if ( test ) then # Conditional test : a == != < > <= >= b \n";
505usage += " > else # Conditional \n";
506usage += " > endif # End of conditional if bloc \n";
507usage += " > break # Delete (clears) all test and loop blocs \n";
508usage += " > return # Stops command execution from a file \n";
509usage += " > defscript endscript # Command script definition \n";
510usage += " > listvars # List of variable names and values \n";
511usage += " > listalias # List of alias names and values \n";
512usage += " > listcommands # List of all known commands \n";
513usage += " > listscripts # List of all known scripts \n";
514usage += " > clearcript # Clear a script definition \n";
515usage += " > thrlist # List of command execution threads (& as the last character) \n";
516usage += " > clearthrlist # Removes finished threads from the list \n";
517usage += " > killthr Id # Try to stop a given thread (ThrId=id) by sending SIGUSR1 \n";
518usage += " > cancelthr Id # Try to cancel a given thread (ThrId=id) \n";
519usage += " > waitthr # Waits until all active threads have finished (join()) \n";
520usage += " > exec filename # Execute commands from file \n";
521usage += " > help <command_name> # <command_name> usage info \n";
522usage += " > sleep nsec # sleep nsec seconds \n";
523usage += " > readstdin varname # reads a line from stdin into $varname \n";
524usage += " > timingon timingoff traceon traceoff \n";
525RegisterHelp(kw, usage, grp);
526
527kw = "RPNEvaluator";
528usage = " Reverse Polish Notation (HP calculator like) expression evaluation \n";
529usage += " >> Stack: \n";
530usage += " ... (4) (3) z=(2) y=(1) x=(0)=Stack.Top() \n";
531usage += " >> Examples: \n";
532usage += " - sin(PI/6): pi 6 / sin \n";
533usage += " - 1*2*...*5: 1 2 3 4 5 product \n";
534usage += " - x=x+y: x = $x $y * \n";
535usage += " >>> Stack operations : \n";
536usage += " print x<>y pop push (duplicate x) \n";
537usage += " >>> Constants (Cst pushed to stack): \n";
538usage += " pi e \n";
539usage += " >>> Arithmetic operators (x,y) --> x@y \n";
540usage += " + - * / % ( (int)y % (int)x )\n";
541usage += " >>> F(X): x --> F(x) \n";
542usage += " chs sqrt sq log log10 exp \n";
543usage += " fabs floor ceil \n";
544usage += " cos sin tan acos asin atan deg2rad rad2deg \n";
545usage += " >>> F(X,Y): (x,y) --> F(x,y) \n";
546usage += " pow atan2 \n";
547usage += " >>> F(): random number generators \n";
548usage += " rand (flat 0..1) norand (normal/gaussian) \n";
549usage += " >>> Stack sum/product/mean/sigma/sigma^2 \n";
550usage += " sum product mean sigma sigma2 sigmean (y->sigma x->mean) \n";
551RegisterHelp(kw, usage, grp);
552
553kw = "autoiniranf";
554usage = "> Automatic random number generator initialisation\n";
555usage += " by Auto_Ini_Ranf(int lp) \n";
556usage += " Usage: autoiniranf";
557RegisterCommand(kw, usage, NULL, grp);
558
559kw = "CExpEvaluator";
560usage = "> Evaluation of C-like expression (used in V = C-like-Expression) \n";
561usage += " >>> Arithmetic operators, parenthesis ( + - * / ) \n";
562usage += " >>> Functions : sqrt fabs floor hypot \n";
563usage += " ... exp log log10 pow ; sinh cosh tanh \n";
564usage += " ... sin cos tan asin acos atan atan2 \n";
565usage += " ... rand01() randpm1() gaurand() \n";
566usage += " >>> Constants : Pi = M_PI E = M_E \n";
567usage += " Example: x = 5.*(2.+sin(0.3*Pi))";
568RegisterCommand(kw, usage, NULL, grp);
569
570kw = "shell execute";
571usage = "> shell command_string # Execute shell command\n";
572usage += "> cshell command_string # Execute cshell command\n";
573usage += "---Examples:\n";
574usage += " > shell ls\n";
575usage += " > cshell echo '$LD_LIBRARY_PATH'; map2cl -h; ls\n";
576usage += " > shell myfile.csh [arg1] [arg2] [...]\n";
577usage += " (where the first line of \"myfile.csh\" is \"#!/bin/csh\")\n";
578RegisterCommand(kw, usage, NULL, grp);
579
580
581AddInterpreter(this);
582curcmdi = this;
583if (fgsigzt) ZThread::ActivateExitOnSignal(SIGUSR1);
584}
585
586/* --Methode-- */
587Commander::~Commander()
588{
589hist.close();
590if (gltimer) { delete gltimer; gltimer = NULL; }
591Modmap::iterator it;
592for(it = modmap.begin(); it != modmap.end(); it++) {
593 string name = (*it).first + "_end";
594 DlModuleInitEndFunction fend = (*it).second->GetFunction(name);
595 if (fend) fend();
596 delete (*it).second;
597 }
598
599for(ScriptList::iterator sit = mScripts.begin();
600 sit != mScripts.end(); sit++) delete (*sit).second;
601
602if (cur_commander == this) cur_commander = NULL;
603}
604
605/* --Methode-- */
606Commander* Commander::GetInterpreter()
607{
608return(cur_commander);
609}
610
611/* --Methode-- */
612//! Returns the string \c Commander as the interpreter's name.
613string Commander::Name()
614{
615return("Commander");
616}
617
618/* --Methode-- */
619//! Add the \b grp help group with description \b desc.
620void Commander::AddHelpGroup(string& grp, string& desc)
621{
622 int gid;
623 CheckHelpGrp(grp, gid, desc);
624}
625
626/* --Methode-- */
627/*!
628 \brief Register a command executor associated with a given keyword.
629 \param keyw : keyword identifying the command
630 \param usage : the command help and usage information
631 \param ce : CmdExecutor pointer for this a command. The same object can be registered
632 multiple time for different commands.
633 \param grp : The help group corresponding to this command.
634*/
635void Commander::RegisterCommand(string& keyw, string& usage, CmdExecutor * ce, string& grp)
636{
637if (!ce) {
638 RegisterHelp(keyw, usage, grp);
639 return;
640 }
641int gid;
642CheckHelpGrp(grp,gid);
643cmdex cme;
644cme.group = gid;
645cme.us = usage;
646cme.cex = ce;
647cmdexmap[keyw] = cme;
648}
649
650/* --Methode-- */
651/*!
652 \brief Register a help text.
653 \param keyw : help keyword
654 \param usage : help text
655 \param grp : help group
656*/
657void Commander::RegisterHelp(string& keyw, string& usage, string& grp)
658{
659int gid;
660CheckHelpGrp(grp,gid);
661cmdex cme;
662cme.group = gid;
663cme.us = usage;
664cme.cex = NULL;
665helpexmap[keyw] = cme;
666}
667
668/* --Methode-- */
669bool Commander::CheckHelpGrp(string& grp, int& gid, string& desc)
670{
671gid = 0;
672CmdHGroup::iterator it = cmdhgrp.find(grp);
673if (it == cmdhgrp.end()) {
674 cmdgrpid++; gid = cmdgrpid;
675 hgrpst hgs; hgs.gid = gid; hgs.desc = desc;
676 cmdhgrp[grp] = hgs;
677 return true;
678 }
679else {
680 if (desc.length() > 0) (*it).second.desc = desc;
681 gid = (*it).second.gid;
682 return false;
683}
684}
685
686
687/* --Methode-- */
688/*!
689 \brief Dynamic loader for modules
690
691 A module is a shared library extending the application functionalities.
692 Typically, a module adds new commands to the interpreter. Once loaded,
693 the module is activated (initialized) by calling a function with the
694 name \b modulename_init . This function should be declared extern C
695 to avoid C++ name mangling. A cleanup function \b modulename_end
696 is called by the Commander destructor.
697
698 \param fnameso : Shared library name containing the module functions
699 and classes.
700 \param name : Module name. This string is used to form module
701 initializer and cleanup function name \c name_init \c name_end
702*/
703void Commander::LoadModule(string& fnameso, string& name)
704{
705PDynLinkMgr * dynlink = new PDynLinkMgr(fnameso, false);
706if (dynlink == NULL) {
707 cerr << "Commander/LoadModule_Error: Pb opening SO " << fnameso << endl;
708 return;
709 }
710string fname = name + "_init";
711DlModuleInitEndFunction finit = dynlink->GetFunction(fname);
712if (!finit) {
713 cerr << "Commander/LoadModule_Error: Pb linking " << fname << endl;
714 return;
715 }
716cout << "Commander/LoadModule_Info: Initialisation module" << name
717 << " " << fname << "() ..." << endl;
718finit();
719modmap[name] = dynlink;
720return;
721}
722
723/* --Methode-- */
724//! Declare a new interpreter
725void Commander::AddInterpreter(CmdInterpreter * cl)
726{
727if (!cl) return;
728interpmap[cl->Name()] = cl;}
729
730/* --Methode-- */
731//! Select an interpreter by its name as the current interpreter.
732void Commander::SelInterpreter(string& name)
733{
734InterpMap::iterator it = interpmap.find(name);
735if (it == interpmap.end()) return;
736curcmdi = (*it).second;
737}
738
739
740
741/* Fonction */
742static string GetStringFrStdin(Commander* piac)
743{
744char buff[128];
745fgets(buff, 128, stdin);
746buff[127] = '\0';
747return((string)buff);
748}
749
750/* --Methode-- */
751/*!
752 \brief Method which has to be invoked to interpret a given command line or string.
753*/
754int Commander::Interpret(string& s)
755{
756int rc = 0;
757ScriptList::iterator sit;
758
759// Si le flag d'arret d'execution a ete positionne on returne avec le code
760// de BREAKEXECUTION
761if (fgexebrk) {
762 cout << " ===> Commander::Interpret() - STOP Execution (CMD_BREAKEXE_RC)" << endl;
763 fgexebrk = false; return CMD_BREAKEXE_RC;
764}
765
766// On saute de commandes vides
767size_t l;
768l = s.length();
769if (!mulinefg && (l < 1)) return(0);
770
771// On enregistre les commandes
772if (histon) hist << s << endl;
773
774if (s[0] == '#') return(0); // si c'est un commentaire
775
776// Logique de gestion des lignes suite
777// un \ en derniere position indique la presence d'une ligne suite
778size_t lnb = s.find_last_not_of(' ');
779if (s[lnb] == '\\' ) { // Lignes suite ...
780 mulinecmd += s.substr(0,lnb);
781 if (!mulinefg) {
782 spromptmul = GetCurrentPrompt();
783 SetCurrentPrompt("...? ");
784 mulinefg = true;
785 }
786 return(0);
787}
788
789if (mulinefg) { // Il y avait des lignes suite
790 s = mulinecmd + s;
791 l = s.length();
792 mulinecmd = "";
793 mulinefg = false;
794 SetCurrentPrompt(spromptmul);
795}
796
797// Removing leading blanks
798size_t p,q;
799
800// On enleve le dernier caractere, si celui-ci est \n
801if (s[l-1] == '\n') s[l-1] = '\0';
802p=s.find_first_not_of(" \t");
803if (p < l) s = s.substr(p);
804// >>>> Substitution d'alias (1er mot)
805CmdStrList::iterator it;
806p = 0;
807q = s.find_first_of(" \t");
808l = s.length();
809string w1 = (q < l) ? s.substr(p,q-p) : s.substr(p);
810it = mAliases.find(w1);
811if (it != mAliases.end()) {
812 s = (q < l) ? ((*it).second + s.substr(q)) : (*it).second ;
813 l = s.length();
814 p=s.find_first_not_of(" \t");
815 if (p < l) s = s.substr(p);
816 p = 0;
817 q = s.find_first_of(" ");
818 }
819
820// >>>> Separating keyword
821string toks,kw;
822if (q < l)
823 { kw = s.substr(p,q-p); toks = s.substr(q, l-q); }
824else { kw = s.substr(p,l-p); toks = ""; }
825
826// les mot-cle end else endif doivent etre le seul mot de la ligne
827if ( (kw == "end") || (kw == "else") || (kw == "endif") || (kw == "endscript") ) {
828 size_t ltk = toks.length();
829 if (toks.find_first_not_of(" \t") < ltk) {
830 cerr << "Commander::Interpret()/syntax error near end else endif endscript \n"
831 << "line: " << s << endl;
832 _xstatus = 91;
833 return(91);
834 }
835}
836
837// On verifie si on est en train de definir un script
838if (curscript) {
839 if (kw == "endscript") {
840 if (curscript->CheckScript()) {
841 sit = mScripts.find(curscript->Name());
842 if (sit != mScripts.end()) {
843 cout << "Commander::Interpret() replacing script "
844 << curscript->Name() << endl;
845 CommanderScript* scr = mScripts[curscript->Name()];
846 mScripts.erase(sit);
847 delete scr;
848 }
849 cout << "Commander::Interpret() Script " << curscript->Name()
850 << " defined successfully" << endl;
851 mScripts[curscript->Name()] = curscript;
852 SetCurrentPrompt("Cmd> ");
853 curscript = NULL;
854 _xstatus = 0;
855 return(0);
856 }
857 else {
858 cout << "Commander::Interpret() Error in Script " << curscript->Name()
859 << " definition " << endl;
860 SetCurrentPrompt("Cmd> ");
861 curscript = NULL;
862 _xstatus = 92;
863 return(92);
864 }
865 }
866 else curscript->AddLine(s, kw);
867 _xstatus = 0;
868 return(0);
869}
870// On verifie si nous sommes dans un bloc (for , foreach)
871if (CmdBlks.top() != NULL) { // On est dans un bloc
872 if ( (kw == "for") || (kw == "foreach") || (kw == "forinfile") ) felevel++;
873 else if (kw == "end") felevel--;
874
875 int rcbex = 0;
876 if (felevel == 0) { // Il faut executer le bloc
877 CommanderBloc* curb = CmdBlks.top();
878 CmdBlks.top() = curb->Parent();
879 SetCurrentPrompt("Cmd> ");
880 if (!curb->CheckBloc()) {
881 cerr << "Commander::Interpret()/syntax error - unbalenced if ... endif"
882 << " within for/foreach/forinfile bloc ! " << endl;
883 delete curb;
884 _xstatus = 93;
885 return(93);
886 }
887 // cout << " *DBG* Executing bloc " << endl;
888 bool ohv = histon;
889 histon = false;
890 if (curtestresult) {
891 // We push also CommanderBloc and testresult on the stack
892 CmdBlks.push(NULL);
893 list<char> xtx;
894 TestsStack.push(xtx);
895 rcbex = curb->Execute();
896 // And CommanderBloc and TestResult from the corresponding stacks
897 PopStack(false);
898 }
899 SetCurrentPrompt(defprompt);
900 delete curb;
901 histon = ohv;
902 }
903 else CmdBlks.top()->AddLine(s, kw);
904 _xstatus = rcbex;
905 return(rcbex);
906}
907else if (kw == "end") {
908 cerr << "Commander::Interpret()/syntax error - end outside for/foreach/forinfile bloc \n"
909 << "line: " << s << endl;
910 _xstatus = 94;
911 return(94);
912}
913
914// Sommes-nous dans un bloc de test if then else
915if (TestsStack.top().size() > 0) { // Nous sommes ds un bloc if
916 if (kw == "else") {
917 if ((*tresit) & 2) {
918 cerr << "Commander::Interpret()/syntax error - multiple else in if bloc \n"
919 << "line: " << s << endl;
920 _xstatus = 95;
921 return(95);
922 }
923 else {
924 const char * npr = ((*tresit)&1) ? "else-F> " : "else-T> ";
925 if ((*tresit)&1) curtestresult = false;
926 SetCurrentPrompt(npr);
927 (*tresit) |= 2;
928 _xstatus = 0;
929 return(0);
930 }
931 }
932 else if (kw == "endif") {
933 list<char>::iterator dbit = tresit;
934 tresit--;
935 TestsStack.top().erase(dbit);
936 const char * npr = "Cmd> ";
937 if (TestsStack.top().size() > 1) {
938 curtestresult = true;
939 list<char>::iterator it;
940 for(it=TestsStack.top().begin(); it!=TestsStack.top().end(); it++) {
941 // Si on n'est pas ds le else et le if est faux
942 if ( !((*it)&2) && !((*it)&1) ) curtestresult = false;
943 // Si on est ds else et le if etait vrai !
944 if ( ((*it)&2) && ((*it)&1) ) curtestresult = false;
945 if (!curtestresult) break;
946 }
947
948 if (!((*tresit)&2))
949 npr = ((*tresit)&1) ? "if-T> " : "if-F> ";
950 else
951 npr = ((*tresit)&1) ? "else-F> " : "else-T> ";
952 }
953 else curtestresult = true;
954 SetCurrentPrompt(npr);
955 _xstatus = 0;
956 return(0);
957 }
958}
959else if ((kw == "else") || (kw == "endif")) {
960 cerr << "Commander::Interpret()/syntax error - else,endif outside if bloc \n"
961 << "line: " << s << endl;
962 _xstatus = 91;
963 return(91);
964}
965
966bool fgcont = true;
967if (TestsStack.top().size() > 0) { // Resultat de if ou else
968 list<char>::iterator it;
969 for(it=TestsStack.top().begin(); it!=TestsStack.top().end(); it++) {
970 // Si on n'est pas ds le else et le if est faux
971 if ( !((*it)&2) && !((*it)&1) ) fgcont = false;
972 // Si on est ds else et le if etait vrai !
973 if ( ((*it)&2) && ((*it)&1) ) fgcont = false;
974 if (!fgcont) break;
975 }
976}
977
978if ((!fgcont) && (kw != "if")) {
979 _xstatus = 0;
980 return(0);
981}
982
983
984// Les mots cles break et return peuvent de sortir de boucles/scripts/execfile
985if (kw == "break") return CMD_BREAK_RC;
986else if (kw == "return") {
987 _retstr = toks;
988 return CMD_RETURN_RC;
989}
990
991// Nous ne sommes donc pas dans un bloc .... Substitution de variables
992string s2;
993int rcs ;
994
995rcs = SubstituteVars(s, s2);
996if (rcs) {
997 cerr << "Commander::Interpret()/syntax error in SubstituteVars() \n"
998 << "line: " << s << endl;
999 _xstatus = 99;
1000 return(99);
1001}
1002// >>>> Separating keyword and tokens
1003vector<string> tokens;
1004vector<bool> qottoks;
1005/* decoupage en mots */
1006LineToWords(s2, kw, tokens, qottoks, toks, true);
1007
1008// Si c'est un for/foreach, on cree un nouveau bloc
1009if ((kw == "foreach") || (kw == "for") || (kw == "forinfile") ) {
1010 // cout << " *DBG* We got a foreach... " << endl;
1011 CommanderBloc* bloc = new CommanderBloc(this, CmdBlks.top(), kw, tokens);
1012 if (!bloc->CheckOK()) {
1013 cerr << "Commander::Interpret() for/foreach syntax Error ! " << endl;
1014 delete bloc;
1015 _xstatus = 91;
1016 return(91);
1017 }
1018 felevel++;
1019 if (CmdBlks.top()) CmdBlks.top()->AddBloc(bloc);
1020 else SetCurrentPrompt("for...> ");
1021 CmdBlks.top() = bloc;
1022 // cout << " *DBG* New Bloc created ... " << endl;
1023 return(0);
1024 }
1025else if (kw == "if") { // Un test if
1026 bool restst = true;
1027 int rct = EvaluateTest(tokens, s, restst);
1028 if (rct) {
1029 cerr << "Commander::Interpret() if syntax Error ! " << "line: " << s << endl;
1030 _xstatus = 91;
1031 return(91);
1032 }
1033 char res_tst = (restst) ? 1 : 0;
1034 TestsStack.top().push_back(res_tst);
1035 if (TestsStack.top().size() == 1) tresit = TestsStack.top().begin();
1036 else tresit++;
1037 const char * npr = (restst) ? "if-T> " : "if-F> ";
1038 SetCurrentPrompt(npr);
1039}
1040else if ((tokens.size() > 0) && (tokens[0] == "=")) {
1041 // x = Expression
1042 if (qottoks[1]) { // decodage sous forme de chaine
1043 SetVariable(kw, tokens[1]);
1044 }
1045 else {
1046 try {
1047 double res = 0.;
1048 if (tokens.size() > 2) {
1049 string sex = tokens[1];
1050 for(int js=2; js<tokens.size(); js++) sex += tokens[js];
1051 CExpressionEvaluator cex(sex);
1052 res = cex.Value();
1053 }
1054 else {
1055 CExpressionEvaluator cex(tokens[1]);
1056 res = cex.Value();
1057 }
1058 char cbuff[64];
1059 sprintf(cbuff,"%g",res);
1060 string vv = cbuff;
1061 SetVariable(kw, vv);
1062 }
1063 catch (CExprException& cexerr) {
1064 cerr << "Commander::Interpret() evaluation Error : \n " << "line: " << s
1065 << " \n Msg=" << cexerr.Msg() << endl;
1066 _xstatus = 98;
1067 return(98);
1068 }
1069 }
1070}
1071else if (kw == "defscript") { // definition de script
1072 if (tokens.size() > 0) {
1073 if (tokens.size() < 2) tokens.push_back("");
1074 curscript = new CommanderScript(this, tokens[0], tokens[1]);
1075 SetCurrentPrompt("Script...> ");
1076 return(0);
1077 }
1078 else {
1079 cerr << "Commander::Interpret() No script name in defscript" << "line: " << s << endl;
1080 _xstatus = 91;
1081 return(91);
1082 }
1083}
1084else {
1085 // Si c'est le nom d'un script
1086 sit = mScripts.find(kw);
1087 if (sit != mScripts.end()) {
1088 bool ohv = histon;
1089 histon = false;
1090 tokens.insert(tokens.begin(), kw);
1091 PushStack(tokens);
1092 (*sit).second->Execute(tokens);
1093 PopStack(true);
1094 histon = ohv;
1095 }
1096 // Execution de commandes
1097 else rc = ExecuteCommandLine(kw, tokens, toks);
1098 _xstatus = rc;
1099 return(rc);
1100}
1101// cout << "Commander::Do() DBG KeyW= " << kw << " NbArgs= " << tokens.size() << endl;
1102// for(int ii=0; ii<tokens.size(); ii++)
1103// cout << "arg[ " << ii << " ] : " << tokens[ii] << endl;
1104
1105return(0);
1106}
1107
1108//! Can be called asynchronously (from a separate thread) to break (halt) execution (in loops, scripts ...)
1109void Commander::StopExecution()
1110{
1111 fgexebrk = true;
1112}
1113
1114
1115/* --Methode-- */
1116int Commander::LineToWords(string& line, string& kw, vector<string>& tokens,
1117 vector<bool>& qottoks, string& toks, bool uq)
1118{
1119if (line.length() < 1) return(0);
1120int nw = 1;
1121size_t p = line.find_first_not_of(" ");
1122line = line.substr(p);
1123p = 0;
1124size_t q = line.find_first_of(" ");
1125size_t l = line.length();
1126
1127if (q < l)
1128 { kw = line.substr(p,q-p); toks = line.substr(q, l-q); }
1129else { kw = line.substr(p,l-p); toks = ""; }
1130
1131q = 0;
1132while (q < l) {
1133 bool swq = false; // true -> chaine delimite par ' ou "
1134 p = toks.find_first_not_of(" \t",q+1); // au debut d'un token
1135 if (p>=l) break;
1136 if ( uq && ((toks[p] == '\'') || (toks[p] == '"')) ) {
1137 q = toks.find(toks[p],p+1);
1138 if (q>=l) {
1139 cerr << "Commander::LineToWords/Syntax Error - Unbalenced quotes " << toks[p] << '.' << endl;
1140 return(-1);
1141 }
1142 p++; swq = true;
1143 }
1144 else {
1145 q = toks.find_first_of(" \t",p); // la fin du token;
1146 }
1147 string token = toks.substr(p,q-p);
1148 tokens.push_back(token);
1149 qottoks.push_back(swq);
1150 nw++;
1151 }
1152
1153return(nw);
1154}
1155
1156/* --Methode-- */
1157int Commander::SubstituteVars(string & s, string & s2)
1158// Variable substitution
1159{
1160
1161int iarr = -1; // index d'element de tableau
1162size_t p,q,q2,q3,l;
1163
1164s2="";
1165p = 0;
1166l = s.length();
1167string vn, vv;
1168while (p < l) {
1169 iarr = -1;
1170 q = s.find('$',p);
1171 if (q > l) break;
1172 q2 = s.find('\'',p);
1173 if ((q2 < l) && (q2 < q)) { // On saute la chaine delimitee par ' '
1174 q2 = s.find('\'',q2+1);
1175 if (q2 >= l) {
1176 cerr << " Syntax error - Unbalenced quotes !!! " << endl;
1177 return(1);
1178 }
1179 s2 += s.substr(p, q2-p+1);
1180 p = q2+1; continue;
1181 }
1182 // cout << "DBG: " << s2 << " p= " << p << " q= " << q << " L= " << l << endl;
1183 if ((q>0) && (s[q-1] == '\\')) { // Escape character \$
1184 s2 += (s.substr(p,q-1-p) + '$') ; p = q+1;
1185 continue;
1186 }
1187 if (q >= l-1) {
1188 cerr << " Syntax error - line ending with $ !!! " << endl;
1189 return(2);
1190 }
1191 vn = "";
1192 if ( s[q+1] == '{' ) { // Variable in the form ${name}
1193 q2 = s.find('}',q+1);
1194 if (q2 >= l) {
1195 cerr << " Syntax error - Unbalenced brace {} !!! " << endl;
1196 return(3);
1197 }
1198 vn = s.substr(q+2,q2-q-2);
1199 q2++;
1200 }
1201 else if ( s[q+1] == '(' ) { // Variable in the form $(name)
1202 q2 = s.find(')',q+1);
1203 if (q2 >= l) {
1204 cerr << " Syntax error - Unbalenced parenthesis () !!! " << endl;
1205 return(3);
1206 }
1207 vn = s.substr(q+2,q2-q-2);
1208 q2++;
1209 }
1210 else if ( s[q+1] == '[' ) { // Variable in the form $[varname] -> This is $$varname
1211 q2 = s.find(']',q+1);
1212 if (q2 >= l) {
1213 cerr << " Syntax error - Unbalenced brace [] !!! " << endl;
1214 return(4);
1215 }
1216 vn = s.substr(q+2,q2-q-2);
1217 if (!Var2Str(vn, vv)) return(5);
1218 vn = vv;
1219 q2++;
1220 }
1221 else {
1222 if (s[q+1] == '#' ) q3 = q+2; // Variable in the form $#varname
1223 else q3 = q+1;
1224 q2 = s.find_first_of(" .:+-*/,[](){}&|!$\"'<>^%=#@\\",q3);
1225 if (q2 > l) q2 = l;
1226 q3 = q2;
1227 vn = s.substr(q+1, q2-q-1);
1228 // Si variable de type $varname[index] : element de tableau
1229 if ((q2 < l) && (s[q2] == '[') ) {
1230 q3 = s.find_first_of("]",q2+1);
1231 string sia = s.substr(q2+1, q3-q2-1);
1232 if (sia.length() < 1) {
1233 cerr << " Syntax error - in $varname[index] : $"
1234 << vn << "[" << sia <<"]" << endl;
1235 return(4);
1236 }
1237 if (isalpha(sia[0])) {
1238 string sia2;
1239 if (!Var2Str(sia, sia2) || (sia2.length() < 1)) {
1240 cerr << " Syntax error - in $varname[index] : $"
1241 << vn << "[" << sia <<"]" << endl;
1242 return(4);
1243 }
1244 sia = sia2;
1245 }
1246 int rcdia = ctoi(sia.c_str(), &iarr);
1247 if (rcdia < 0) {
1248 cerr << " Syntax error - in $varname[iarr] : $"
1249 << vn << "[" << sia <<"]" << endl;
1250 return(4);
1251 }
1252 }
1253 }
1254 if (iarr < 0) {
1255 if (!Var2Str(vn, vv)) return(5);
1256 s2 += (s.substr(p, q-p) + vv);
1257 p = q2;
1258 }
1259 else {
1260 if (! Var2Str(vn, iarr, vv) ) {
1261 cerr << " Substitution error - word index out of range in "
1262 << "$varname[iarr] : $" << vn << "[" << iarr <<"]" << endl;
1263 return(4);
1264 }
1265 else s2 += (s.substr(p, q-p) + vv);
1266 p = q3+1;
1267 }
1268}
1269if (p < l) s2 += s.substr(p);
1270
1271p = s2.find_first_not_of(" \t");
1272if (p < l) s2 = s2.substr(p);
1273
1274return(0);
1275}
1276
1277/* --Methode-- */
1278bool Commander::Var2Str(string const & vn, string & vv)
1279{
1280if (vn.length() < 1) {
1281 cerr << " Commander::Var2Str/Error: length(varname=" << vn << ")<1 !" << endl;
1282 vv = ""; return(false);
1283}
1284// Variable de type $# $0 $1 ... (argument de .pic ou de script)
1285int ka = 0;
1286char buff[32];
1287
1288if (vn == "#") {
1289 if (ArgsStack.empty()) {
1290 cerr << " Commander::Var2Str/Error: ArgsStack empty ! "
1291 << " ($" << vn << ")" << endl;
1292 vv = ""; return(false);
1293 }
1294 char buff[32];
1295 long an = ArgsStack.top().size();
1296 if (an > 0) an--; // Pour se conformer a l'usage de csh : Nb args sans le $0
1297 sprintf(buff,"%ld", an);
1298 vv = buff; return(true);
1299}
1300else if (vn == "*") {
1301 if (ArgsStack.empty()) {
1302 cerr << " Commander::Var2Str/Error: ArgsStack empty ! "
1303 << " ($" << vn << ")" << endl;
1304 vv = ""; return(false);
1305 }
1306 vv = ArgsStack.top()[0];
1307 for(int ssk=1; ssk<ArgsStack.top().size(); ssk++) vv += ArgsStack.top()[ssk];
1308 return(true);
1309}
1310else if (ctoi(vn.c_str(), &ka) > 0) { // $0 $1 $2 ...
1311 if (ArgsStack.empty()) {
1312 cerr << " Commander::Var2Str/Error: ArgsStack empty ! "
1313 << " ($" << vn << ")" << endl;
1314 vv = ""; return(false);
1315 }
1316 if ( (ka < 0) || (ka >= ArgsStack.top().size()) ) {
1317 cerr << " Commander::Var2Str/Error: ArgsStack index <0 or >=args.size() ! "
1318 << " ($" << vn << ")" << endl;
1319 vv = ""; return(false);
1320 }
1321 vv = ArgsStack.top()[ka]; return(true);
1322}
1323else if (vn[0] == '#') { // Variable de type $#vname --> size(vname)
1324 CmdVarList::iterator it = variables.find(vn.substr(1));
1325 if (it == variables.end()) {
1326 cerr << " Commander::Var2Str/Error #vname Undefined variable "
1327 << vn << " ! " << endl;
1328 vv = ""; return(false);
1329 }
1330 sprintf(buff,"%d", (int)(*it).second.size());
1331 vv = buff; return(true);
1332}
1333else if (vn == "status") {
1334 sprintf(buff,"%d", _xstatus);
1335 vv = buff;
1336 return true;
1337}
1338else if ((vn == "retstr") || (vn == "retval")) {
1339 vv = _retstr;
1340 return true;
1341}
1342else { // Variable de l'interpreteur, ou de l'environnement application , env. global
1343 if (GetVar(vn, vv)) return true;
1344 else if (GetVarApp(vn, vv)) return true;
1345 else if (GetVarEnv(vn, vv)) return true;
1346 else {
1347 cerr << " Commander::Var2Str/Error Undefined variable "
1348 << vn << " ! " << endl;
1349 vv = ""; return false;
1350 }
1351}
1352
1353return false;
1354}
1355
1356/* --Methode-- */
1357bool Commander::SetVariable(string const & vn, string const & vv)
1358{
1359 // On verifie si le nom est de type vname[idx]
1360 size_t p,q,l;
1361 l = vn.length();
1362 p = vn.find('[');
1363 if (p < l) {
1364 q = vn.find(']');
1365 if (q != (l-1)) {
1366 cout << "Commander::Str2Var/SetVar() - Bad varname with []: "
1367 << vn << endl;
1368 return false;
1369 }
1370 string vna = vn.substr(0, p);
1371 string sia = vn.substr(p+1, q-(p+1));
1372 if (isalpha(sia[0])) {
1373 string sia2;
1374 if (!Var2Str(sia, sia2) || (sia2.length() < 1)) {
1375 cerr << "Commander::Str2Var/SetVar() Syntax error- varname[index]:"
1376 << vn << endl;
1377 return false;
1378 }
1379 sia = sia2;
1380 }
1381 int iarr;
1382 int rcdia = ctoi(sia.c_str(), &iarr);
1383 if (rcdia < 0) {
1384 cerr << "Commander::Str2Var/SetVar() Syntax error- varname[iarr]: "
1385 << vn << endl;
1386 return false;
1387 }
1388 return SetVar(vna, iarr, vv);
1389 }
1390 else {
1391 if (vn == "status") {
1392 _xstatus = atoi(vv.c_str());
1393 return true;
1394 }
1395 else if (vn == "retstr") {
1396 _retstr = vv;
1397 return true;
1398 }
1399 else return SetVar(vn, vv);
1400 }
1401}
1402
1403/* --Methode-- */
1404bool Commander::GetVar(string const & vn, string & vv)
1405{
1406 CmdVarList::iterator it = variables.find(vn);
1407 if (it == variables.end()) {
1408 vv = "";
1409 return false;
1410 }
1411 vv = (*it).second[0];
1412 if ((*it).second.size() > 1) {
1413 for(int k=1; k<(*it).second.size(); k++) {
1414 vv += ' '; vv += (*it).second[k];
1415 }
1416 }
1417 return true;
1418}
1419
1420/* --Methode-- */
1421bool Commander::GetVar(string const & vn, int idx, string & vv)
1422{
1423 vv = "";
1424 CmdVarList::iterator it = variables.find(vn);
1425 if (it == variables.end()) return false;
1426 if ((idx < 0) || (idx > (*it).second.size()-1))
1427 return false;
1428 vv = (*it).second[idx];
1429 return true;
1430}
1431
1432/* --Methode-- */
1433bool Commander::GetVar(string const & vn, vector<string> & vv)
1434{
1435 vv.clear();
1436 // vv.erase(vv.begin(),vv.end());
1437 CmdVarList::iterator it = variables.find(vn);
1438 if (it == variables.end()) return false;
1439 vv = (*it).second;
1440 return true;
1441}
1442
1443/* --Methode-- */
1444bool Commander::SetVar(string const & vn, string const & val)
1445{
1446 if ( !CheckVarName(vn) ) {
1447 cerr << "Commander::SetVar( " << vn << " ...) Bad VarName " << endl;
1448 return(false);
1449 }
1450 bool fg = false;
1451 vector<string> nouv;
1452 nouv.push_back(val);
1453 CmdVarList::iterator it = variables.find(vn);
1454 if (it == variables.end()) variables[vn] = nouv;
1455 else {
1456 (*it).second = nouv;
1457 fg = true;
1458 }
1459 return fg;
1460}
1461
1462/* --Methode-- */
1463bool Commander::SetVar(string const & vn, int idx, string const & val)
1464{
1465 if ( !CheckVarName(vn) ) {
1466 cerr << "Commander::SetVar( " << vn << " ,idx, ...) Bad VarName " << endl;
1467 return(false);
1468 }
1469 if ((vn == "status") || (vn == "retstr")) {
1470 cerr << "Commander::SetVar(vn,idx,val) ERROR - special var status/retstr "
1471 << endl;
1472 return(false);
1473 }
1474 if (idx < 0) {
1475 cout << "Commander::SetVar(vn," << idx << ",...) Error idx < 0" << endl;
1476 return(false);
1477 }
1478 bool fg = false;
1479 CmdVarList::iterator it = variables.find(vn);
1480 if (it == variables.end()) {
1481 vector<string> nouv;
1482 for(int j=0; j<idx; j++) nouv.push_back("");
1483 nouv.push_back(val);
1484 variables[vn] = nouv;
1485 }
1486 else {
1487 if (idx >= (*it).second.size())
1488 for(int j=(*it).second.size(); j<=idx; j++) (*it).second.push_back("");
1489 (*it).second[idx] = val;
1490 fg = true;
1491 }
1492 return fg;
1493}
1494
1495/* --Methode-- */
1496bool Commander::SetVar(string const & vn, vector<string> const & val)
1497{
1498 if ( !CheckVarName(vn) ) {
1499 cerr << "Commander::SetVar( " << vn << " ...) Bad VarName " << endl;
1500 return(false);
1501 }
1502 if ((vn == "status") || (vn == "retstr")) {
1503 cerr << "Commander::SetVar(vn, vector<string>) ERROR - special var status/retstr "
1504 << endl;
1505 return(false);
1506 }
1507 bool fg = false;
1508 CmdVarList::iterator it = variables.find(vn);
1509 if (it == variables.end()) variables[vn] = val;
1510 else {
1511 (*it).second = val;
1512 fg = true;
1513 }
1514 return fg;
1515}
1516
1517/* --Methode-- */
1518bool Commander::CheckVarName(string const & vn)
1519{
1520 size_t l,k;
1521 l = vn.length();
1522 if (l < 1) return false;
1523 if (!isalpha(vn[0])) return false;
1524 for(k=1; k<l; k++)
1525 if ((!isalnum(vn[k])) && (vn[k] != '_')) return false;
1526 return true;
1527}
1528
1529/* --Methode-- */
1530bool Commander::DeleteVar(string const & vn)
1531{
1532 CmdVarList::iterator it = variables.find(vn);
1533 if (it == variables.end()) {
1534 cerr << "Commander::DeleteVar() Var " << vn << " undefined!" << endl;
1535 return false;
1536 }
1537 variables.erase(it);
1538 return true;
1539}
1540
1541/* --Methode-- */
1542void Commander::ListVar()
1543{
1544 cout << " ---- Commander::ListVar() List of defined variables ---- "
1545 << endl;
1546 CmdVarList::iterator it;
1547 for(it = variables.begin(); it != variables.end(); it++) {
1548 string vn = (*it).first;
1549 int vs = (*it).second.size();
1550 cout << vn << " -> Size= " << vs << endl;
1551 }
1552 cout << "---------------------------------------------------------- "
1553 << endl;
1554}
1555
1556/* --Methode-- */
1557bool Commander::GetVarApp(string const & vn, string & vv)
1558{
1559 vv = "";
1560 // cout << " Commander::GetVarApp() Not available ! " << endl;
1561 return false;
1562}
1563
1564/* --Methode-- */
1565bool Commander::SetVarApp(string const & vn, string const & vv)
1566{
1567 // cout << " Commander::SetVarApp() Not available ! " << endl;
1568 return false;
1569}
1570
1571/* --Methode-- */
1572bool Commander::DeleteVarApp(string const & vn)
1573{
1574 // cout << " Commander::DeleteVarApp() Not available ! " << endl;
1575 return false;
1576}
1577
1578/* --Methode-- */
1579void Commander::ListVarApp()
1580{
1581 // cout << " Commander::ListVarApp() Not available ! " << endl;
1582 return;
1583}
1584
1585
1586/* --Methode-- */
1587bool Commander::GetVarEnv(string const & vn, string & vv)
1588{
1589 char* vev = getenv(vn.c_str());
1590 if (vev) {
1591 vv = vev;
1592 return true;
1593 }
1594 else {
1595 vv = "";
1596 return false;
1597 }
1598}
1599
1600/* --Methode-- */
1601bool Commander::SetVarEnv(string const & vn, string const & vv)
1602{
1603 string pev = vn;
1604 pev += '=';
1605 pev += vv;
1606// if defined(Linux) || defined(AIX)
1607// Reza - 28/04/2004
1608// putenv de Linux ne declare pas la variable char *string const
1609// On ne doit meme pas utiliser une variable automatique
1610// J'alloue donc un nouveau tableau - mais qui va le liberer ?
1611// Idem AIX , Reza Dec 2005
1612// Pb apparu avec g++ 4 sur darwin (Mac) - Jan 2006
1613// Je fais copie pour tout le monde
1614 char* bev = new char[pev.size()+1];
1615 strcpy(bev, pev.c_str());
1616 if (putenv(bev) == 0) return true;
1617// else
1618// if (putenv(pev.c_str()) == 0) return true;
1619// endif
1620 else return false;
1621}
1622
1623/* --Methode-- */
1624bool Commander::DeleteVarEnv(string const & vn)
1625{
1626 // cout << " Commander::DeleteVarEnv() Not available ! " << endl;
1627 return false;
1628}
1629
1630/* --Methode-- */
1631void Commander::ListVarEnv()
1632{
1633 cout << " Commander::ListVarEnv() Not available ! " << endl;
1634 return;
1635}
1636
1637
1638/* --Methode-- */
1639string Commander::GetTmpDir()
1640{
1641 return("/tmp");
1642}
1643
1644/* --Methode-- */
1645void Commander::SetCurrentPrompt(const char* pr)
1646{
1647 curprompt = pr;
1648}
1649
1650/* --Methode-- */
1651void Commander::ShowMessage(const char * msg, int att)
1652{
1653 cout << msg ;
1654}
1655
1656
1657
1658/* --Methode-- */
1659int Commander::EvaluateTest(vector<string> & args, string & line, bool & res)
1660{
1661 res = true;
1662 if ((args.size() != 6) || (args[5] != "then") ||
1663 (args[0] != "(") || (args[4] != ")") ) return(1);
1664 if (args[2] == "==") res = (args[1] == args[3]);
1665 else if (args[2] == "!=") res = (args[1] != args[3]);
1666 else if (args[2] == "<")
1667 res = (atof(args[1].c_str()) < atof(args[3].c_str()));
1668 else if (args[2] == ">")
1669 res = (atof(args[1].c_str()) > atof(args[3].c_str()));
1670 else if (args[2] == "<=")
1671 res = (atof(args[1].c_str()) <= atof(args[3].c_str()));
1672 else if (args[2] == ">=")
1673 res = (atof(args[1].c_str()) >= atof(args[3].c_str()));
1674 else return(2);
1675 return(0);
1676}
1677
1678
1679/* --Methode-- */
1680int Commander::EvalRPNExpr(vector<string> & args, string & line)
1681{
1682 // A virer - Reza 15/03/2004
1683 return(0);
1684}
1685
1686/* --Methode-- */
1687void Commander::PushStack(vector<string>& args)
1688{
1689 // We push the argument list (args) on the stack
1690 ArgsStack.push(args);
1691 // We push also CommanderBloc and testresult on the stack
1692 CmdBlks.push(NULL);
1693 list<char> xtx;
1694 TestsStack.push(xtx);
1695
1696}
1697
1698/* --Methode-- */
1699void Commander::PopStack(bool psta)
1700{
1701 // We remove the argument list (args) from the stack
1702 if (psta) ArgsStack.pop();
1703 // And CommanderBloc and TestResult from the corresponding stacks
1704 CommanderBloc* curb = CmdBlks.top();
1705 while (curb != NULL) {
1706 CommanderBloc* parb = curb->Parent();
1707 delete curb; curb = parb;
1708 }
1709 CmdBlks.pop();
1710 TestsStack.pop();
1711}
1712
1713/* --Methode-- */
1714int Commander::ExecuteCommandLine(string & kw, vector<string> & tokens, string & toks)
1715{
1716int rc = 0;
1717
1718// >>>>>>>>>>> Commande d'interpreteur
1719if (kw == "help") {
1720 if (tokens.size() > 0) cout << GetUsage(tokens[0]) << endl;
1721 else {
1722 string kwh = "Commander";
1723 cout << GetUsage(kwh) << endl;
1724 }
1725 }
1726else if (kw == "sleep") {
1727 if (tokens.size() < 1) {
1728 cout << "Commander::Interpret() Usage: sleep nsec " << endl;
1729 return(1);
1730 }
1731 int nsec = atoi(tokens[0].c_str());
1732 cout << "Commander::Interpret() sleep " << nsec << " seconds" << endl;
1733 sleep(nsec);
1734}
1735
1736else if (kw == "set") {
1737 if (tokens.size() < 2) {
1738 cout << "Commander::Interpret() Usage: set varname value or set vecvar ( w1 w2 ... ) " << endl;
1739 return(1);
1740 }
1741
1742 if (tokens.size() == 2)
1743 SetVariable(tokens[0], tokens[1]);
1744 else {
1745 if ( (tokens[1] != "(") || (tokens[tokens.size()-1] != ")") ) {
1746 cout << "Commander::Interpret() Usage: set vecvar ( w1 w2 ... ) " << endl;
1747 return(1);
1748 }
1749 string vname = tokens[0];
1750 vector<string>::iterator vit;
1751 vit = tokens.begin(); tokens.erase(vit);
1752 vit = tokens.begin(); tokens.erase(vit);
1753 tokens.pop_back();
1754 SetVar(vname, tokens);
1755 }
1756 return 0;
1757}
1758else if (kw == "var2words") {
1759 if (tokens.size() < 2) {
1760 cout << "Commander::Interpret() Usage: var2words varname wordvarname [sep]" << endl;
1761 return(1);
1762 }
1763 char sep = ' ';
1764 if (tokens.size() > 2) sep = tokens[2][0];
1765 string vv;
1766 if (!GetVar(tokens[0], vv)) {
1767 cout << "Commander::Interpret() var2words/Error No variable with name " << tokens[0] << endl;
1768 return 2;
1769 }
1770 vector<string> vs;
1771 FillVStringFrString(vv, vs, sep);
1772 SetVar(tokens[1], vs);
1773}
1774else if (kw == "alias") {
1775 if (tokens.size() < 2) { cout << "Commander::Interpret() Usage: alias aliasname string" << endl; return(0); }
1776 if ((tokens[0].length() < 1) || !isalpha((int)tokens[0][0]) ) {
1777 cerr << "Commander::Interpret()/Error alias name should start with alphabetic" << endl;
1778 return(1);
1779 }
1780 string xx = tokens[1];
1781 for (int kk=2; kk<tokens.size(); kk++) xx += (' ' + tokens[kk]);
1782 mAliases[tokens[0]] = xx;
1783}
1784
1785else if ( (kw == "unset") || (kw == "clearvar") ) {
1786 if (tokens.size() < 1) {
1787 cout << "Commander::Interpret() Usage: unset/clearvar varname" << endl;
1788 return(1);
1789 }
1790 else DeleteVar(tokens[0]);
1791}
1792// Evaluation d'expression en notation polonaise inverse
1793else if (kw == "rpneval") {
1794 try {
1795 RPNExpressionEvaluator rpn(tokens, 1);
1796 double res = rpn.Value();
1797 char cbuff[64];
1798 sprintf(cbuff,"%g",res);
1799 string vv = cbuff;
1800 SetVariable(tokens[0],vv);
1801 return 0;
1802 }
1803 catch (RPNExprException& rpnerr) {
1804 cerr << " rpneval: Syntax error - Msg=" << rpnerr.Msg()
1805 << " \n Line=" << toks << endl;
1806 return 98;
1807 }
1808}
1809else if (kw == "echo") {
1810 for (int ii=0; ii<tokens.size(); ii++)
1811 cout << tokens[ii] << " " ;
1812 cout << endl;
1813 }
1814else if (kw == "echo2file") {
1815 if (tokens.size() < 1) {
1816 cout << "Commander::Interpret() Usage: echo2file filename [string ] " << endl;
1817 return(1);
1818 }
1819 ofstream ofs(tokens[0].c_str(), ios::app);
1820 for (int ii=1; ii<tokens.size(); ii++)
1821 ofs << tokens[ii] << " " ;
1822 ofs << endl;
1823 }
1824else if (kw == "readstdin") {
1825 if (tokens.size() < 1) { cout << "Commander::Interpret() Usage: readstdin varname" << endl; return(0); }
1826 if ((tokens[0].length() < 1) || !isalpha((int)tokens[0][0]) ) {
1827 cerr << "Commander::Interpret()/Error Variable name should start with alphabetic" << endl;
1828 return(0);
1829 }
1830 ShowMessage(">>> Reading From StdIn \n", _MAGENTA_);
1831 cout << tokens[0] << " ? " << endl;
1832 SetVar(tokens[0], GetStringFrStdin(this) );
1833 }
1834
1835else if (kw == "listvars" || kw == "listvar") ListVar();
1836else if (kw == "listalias") {
1837 cout << "Commander::Interpret() Alias List , AliasName = Value \n";
1838 CmdStrList::iterator it;
1839 for(it = mAliases.begin(); it != mAliases.end(); it++)
1840 cout << (*it).first << " = " << (*it).second << "\n";
1841 cout << endl;
1842 }
1843else if (kw == "listcommands") {
1844 cout << "---- Commander::Interpret() Command List ----- \n";
1845 CmdExmap::iterator it;
1846 int kc = 0;
1847 for(it = cmdexmap.begin(); it != cmdexmap.end(); it++) {
1848 cout << (*it).first << " ";
1849 kc++;
1850 if (kc >= 5) { cout << "\n"; kc = 0; }
1851 }
1852 cout << endl;
1853 }
1854else if (kw == "listscripts") {
1855 cout << "---- Commander::Interpret() Script List ----- \n";
1856 for(ScriptList::iterator sit = mScripts.begin();
1857 sit != mScripts.end(); sit++)
1858 cout << " Script: " << (*sit).second->Name() << " - "
1859 << (*sit).second->Comment() << endl;
1860}
1861else if (kw == "clearscript") {
1862 if (tokens.size() < 1) {
1863 cout << "Commander::Interpret() Usage: clearscript scriptname" << endl;
1864 return(0);
1865 }
1866 ScriptList::iterator sit = mScripts.find(tokens[0]);
1867 if (sit == mScripts.end()) {
1868 cout << "Commander::Interpret() No script with name" << tokens[0] << endl;
1869 return(0);
1870 }
1871 else {
1872 delete (*sit).second;
1873 mScripts.erase(sit);
1874 cout << "Commander::Interpret() script " << tokens[0] << " cleared" << endl;
1875 return(0);
1876 }
1877}
1878//---------------------------------------------
1879//--- Commandes de gestion des threads ------
1880//---------------------------------------------
1881else if (kw == "thrlist") {
1882 ListThreads();
1883 return(0);
1884}
1885else if ( (kw == "killthr") || (kw == "cancelthr") ) {
1886 if (tokens.size() < 1) {
1887 cout << "Commander::Interpret() Usage: killthr/cancelthr thrid" << endl;
1888 return(0);
1889 }
1890 uint_8 id = atol(tokens[0].c_str());
1891 bool fgkill = false;
1892 if (kw == "killthr") fgkill = true;
1893 StopThr(id, fgkill);
1894 return (0);
1895}
1896else if (kw == "waitthr") {
1897 WaitThreads();
1898 return (0);
1899}
1900else if (kw == "cleanthrlist") {
1901 CleanThrList();
1902 return (0);
1903}
1904
1905else if (kw == "traceon") { cout << "Commander::Interpret() -> Trace ON mode " << endl; trace = true; }
1906else if (kw == "traceoff") { cout << "Commander::Interpret() -> Trace OFF mode " << endl; trace = false; }
1907else if (kw == "timingon") {
1908 cout << "Commander::Interpret() -> Timing ON mode " << endl;
1909 if (gltimer) delete gltimer; gltimer = new Timer("PIA-CmdInterpreter "); timing = true;
1910 }
1911else if (kw == "timingoff") {
1912 cout << "Commander::Interpret() -> Timing OFF mode " << endl;
1913 if (gltimer) delete gltimer; gltimer = NULL; timing = false;
1914 }
1915else if (kw == "exec") {
1916 if (tokens.size() < 1) { cout << "Commander::Interpret() Usage: exec filename" << endl; return(0); }
1917 ExecFile(tokens[0], tokens);
1918 }
1919else if (kw == "autoiniranf") {
1920 Auto_Ini_Ranf(1);
1921 return(0);
1922}
1923else if (kw == "shell") {
1924 if (tokens.size() < 1) { cout << "Commander::Interpret() Usage: shell cmdline" << endl; return(0); }
1925 string cmd;
1926 for (int ii=0; ii<tokens.size(); ii++)
1927 cmd += (tokens[ii] + ' ');
1928 system(cmd.c_str());
1929 }
1930else if (kw == "cshell") {
1931 if(tokens.size()<1) {cout<<"Commander::Interpret() Usage: cshell cmdline"<<endl; return(0);}
1932 string cmd="";
1933 for(int ii=0;ii<tokens.size();ii++) cmd+=(tokens[ii]+' ');
1934 CShellExecute(cmd);
1935 }
1936
1937// Execution d'une commande enregistree
1938else rc = ExecuteCommand(kw, tokens, toks);
1939
1940if (timing) gltimer->Split();
1941return(rc);
1942}
1943
1944/* --Methode-- */
1945int Commander::ParseLineExecute(string& line, bool qw)
1946 // Si qw == true, on decoupe entre '' ou "" ou espaces
1947{
1948vector<string> tokens;
1949vector<bool> qottoks;
1950string kw, toks;
1951if (line.length() < 1) return(0);
1952LineToWords(line, kw, tokens, qottoks, toks, qw);
1953return(ExecuteCommand(kw, tokens, toks));
1954}
1955
1956/* --Methode-- */
1957int Commander::ExecuteCommand(string& keyw, vector<string>& args, string& toks)
1958{
1959 int rc = -1;
1960 CmdExmap::iterator it = cmdexmap.find(keyw);
1961 if (it == cmdexmap.end()) cout << "No such command : " << keyw << " ! " << endl;
1962 else {
1963 if ((*it).second.cex) {
1964 // Doit-on l'executer sous forme de thread separe ?
1965 if ( (args.size()>0) && (args[args.size()-1] == "&") &&
1966 ((*it).second.cex->IsThreadable(keyw)) ) {
1967 ThrId++;
1968 CommandExeThr * thr = new CommandExeThr(ThrId, (*it).second.cex, keyw, args, toks);
1969 CmdThrExeList.push_back(thr);
1970 cout << " Commander::ExecuteCommand() : Thread execution of command " << keyw << endl;
1971 thr->start();
1972 if (CmdThrExeList.size() > 5) CleanThrList();
1973 rc = 0;
1974 }
1975 else rc = (*it).second.cex->Execute(keyw, args, toks);
1976 }
1977 else cout << "Dont know how to execute " << keyw << " ? " << endl;
1978 }
1979 return(rc);
1980}
1981
1982/* --Methode-- */
1983int Commander::ExecFile(string& file, vector<string>& args)
1984{
1985char line_buff[1024];
1986FILE *fip;
1987int rcc = 0;
1988if ( (fip = fopen(file.c_str(),"r")) == NULL ) {
1989 if (file.find('.') >= file.length()) {
1990 cout << "Commander::Exec(): Error opening file " << file << endl;
1991 file += ".pic";
1992 cout << " Trying file " << file << endl;
1993 fip = fopen(file.c_str(),"r");
1994 }
1995 }
1996
1997if(fip == NULL) {
1998 cerr << "Commander::Exec() Error opening file " << file << endl;
1999 hist << "##! Commander::Exec() Error opening file " << file << endl;
2000 return(0);
2001 }
2002
2003// hist << "### Executing commands from " << file << endl;
2004PushStack(args);
2005if (trace) {
2006 ShowMessage("### Executing commands from ", _MAGENTA_);
2007 ShowMessage(file.c_str(), _MAGENTA_);
2008 ShowMessage("\n", _MAGENTA_);
2009 }
2010
2011bool ohv = histon;
2012histon = false;
2013while (fgets(line_buff,1023,fip) != NULL)
2014 {
2015 if (trace) ShowMessage(line_buff, _MAGENTA_);
2016 line_buff[strlen(line_buff)-1] = '\0'; /* LF/CR de la fin */
2017 string line(line_buff);
2018 rcc = Interpret(line);
2019 if ((rcc == CMD_RETURN_RC) || (rcc == CMD_BREAKEXE_RC)) break;
2020 }
2021histon = ohv;
2022
2023// hist << "### End of Exec( " << file << " ) " << endl;
2024if (trace) {
2025 ShowMessage("### End of Exec( ", _MAGENTA_);
2026 ShowMessage(file.c_str(), _MAGENTA_);
2027 ShowMessage(" ) \n", _MAGENTA_);
2028 }
2029
2030PopStack(true);
2031
2032return(0);
2033}
2034
2035/* --Methode-- */
2036void Commander::ListThreads()
2037{
2038 cout << "--- Commander::ListThreads()- command execution threads NThread="
2039 << CmdThrExeList.size() << " ---" << endl;
2040 for(list<CommandExeThr *>::iterator tit = CmdThrExeList.begin();
2041 tit != CmdThrExeList.end(); tit++) {
2042 cout << "Id=" << (*tit)->Id();
2043 if ( (*tit)->IfRunning() ) cout << " Executing";
2044 else if ( (*tit)->IfDone() ) cout << " Finished , Rc= " << (*tit)->getRC();
2045 else cout << " Stopped/Canceled";
2046 cout << " (Cmd= " << (*tit)->Keyword() << " " << (*tit)->Tokens().substr(0,35);
2047 if ((*tit)->Tokens().length() > 35) cout << "... )" << endl;
2048 else cout << " )" << endl;
2049 }
2050}
2051/* --Methode-- */
2052void Commander::StopThr(uint_8 id, bool fgkill)
2053{
2054 for(list<CommandExeThr *>::iterator tit = CmdThrExeList.begin();
2055 tit != CmdThrExeList.end(); tit++) {
2056 if ( ((*tit)->Id() == id) && ((*tit)->IfRunning()) ) {
2057 if (fgkill) {
2058 (*tit)->kill(SIGUSR1);
2059 cout << "Commander::StopThr() Send signal SIGUSR1 to Thread Id= " << id << endl;
2060 }
2061 else {
2062 (*tit)->cancel();
2063 cout << "Commander::StopThr() Canceling Thread Id= " << id << endl;
2064 }
2065 return;
2066 }
2067 }
2068 cout << "Commander::StopThr()/Error: No active thread with Id= " << id << endl;
2069}
2070
2071/* --Methode-- */
2072void Commander::CleanThrList()
2073{
2074 cout << "---- Commander::CleanThrList() Cleaning thrlist ----- \n";
2075 list<CommandExeThr *> thrcopie;
2076 int ncl = 0;
2077 for(list<CommandExeThr *>::iterator tit = CmdThrExeList.begin();
2078 tit != CmdThrExeList.end(); tit++) {
2079 if ( ((*tit)->IfEnded() || (*tit)->IfStopped()) && (ncl < 3) ) {
2080 cout << " Thread Id= " << (*tit)->Id() << " rc= " << (*tit)->getRC() << " Cleaned" << endl;
2081 delete (*tit);
2082 ncl++;
2083 }
2084 else thrcopie.push_back((*tit));
2085 }
2086 CmdThrExeList = thrcopie;
2087 cout << " ... " << CmdThrExeList.size() << " threads still active " << endl;
2088}
2089
2090/* --Methode-- */
2091void Commander::WaitThreads()
2092{
2093 cout << "---- Commander::WaitThreads() Wait/Join command execution threads - NThread="
2094 << CmdThrExeList.size() << " ----- " << endl;
2095 for(list<CommandExeThr *>::iterator tit = CmdThrExeList.begin();
2096 tit != CmdThrExeList.end(); tit++) {
2097 try {
2098 if (! (*tit)->IfDone()) (*tit)->join();
2099 }
2100 catch (std::exception & e) {
2101 cout << " Commander::WaitThreads()/Exception msg= " << e.what() << endl;
2102 }
2103 cout << " Joined thread Id= " << (*tit)->Id() << " rc= " << (*tit)->getRC() << endl;
2104 delete (*tit);
2105 }
2106 CmdThrExeList.erase(CmdThrExeList.begin(), CmdThrExeList.end());
2107}
2108
2109/* --Methode-- */
2110int Commander::CShellExecute(string cmd)
2111{
2112 if(cmd.size()<=0) return -1;
2113
2114 string fname = GetTmpDir(); fname += "cshell_exec_pia.csh";
2115
2116 string cmdrm = "rm -f " + fname;
2117 system(cmdrm.c_str());
2118
2119 FILE *fip = fopen(fname.c_str(),"w");
2120 if(fip==NULL) {
2121 cout << "Commander/CShellExecute_Error: fopen("<<fname<<") failed"<<endl;
2122 return -2;
2123 }
2124 fprintf(fip,"#!/bin/csh\n\n");
2125 fprintf(fip,"%s\n",cmd.c_str());
2126 fprintf(fip,"\nexit 0\n");
2127 fclose(fip);
2128
2129 cmd = "csh "; cmd += fname;
2130 system(cmd.c_str());
2131
2132 system(cmdrm.c_str());
2133
2134 return 0;
2135}
2136
2137static string* videstr = NULL;
2138/* --Methode-- */
2139string& Commander::GetUsage(const string& kw)
2140{
2141bool fndok = false;
2142CmdExmap::iterator it = cmdexmap.find(kw);
2143if (it == cmdexmap.end()) {
2144 it = helpexmap.find(kw);
2145 if (it != helpexmap.end()) fndok = true;
2146 }
2147 else fndok = true;
2148if (fndok) return( (*it).second.us );
2149// Keyword pas trouve
2150if (videstr == NULL) videstr = new string("");
2151*videstr = "Nothing known about " + kw + " ?? ";
2152return(*videstr);
2153
2154}
2155
2156
2157/* Les definitions suivantes doivent se trouver ds l'en-tete du fichier LaTeX
2158 \newcommand{\piacommand}[1]{
2159 \framebox{\bf \Large #1 } \index{#1} % (Command)
2160 }
2161
2162 \newcommand{\piahelpitem}[1]{
2163 \framebox{\bf \Large #1 } \index{#1} (Help item)
2164 }
2165
2166 \newcommand{\myppageref}[1]{ (p. \pageref{#1} ) }
2167*/
2168
2169// Fonction qui remplace tout caractere non alphanumerique en Z
2170static void check_latex_reflabel(string & prl)
2171{
2172 for(int k=0; k<prl.length(); k++)
2173 if (! isalnum(prl[k]) ) prl[k] = 'Z';
2174}
2175
2176// Fonction qui remplace _ en \_
2177static string check_latex_underscore(string const & mot)
2178{
2179 string rs;
2180 for(int k=0; k<mot.length(); k++) {
2181 if (mot[k] == '_') rs += "\\_";
2182 else rs += mot[k];
2183 }
2184 return rs;
2185}
2186
2187/* --Methode-- */
2188/*!
2189 \brief Produces a LaTeX file containing the registered command helps
2190 The file \b fname is created and can be inserted into a LaTeX document
2191 in order to produce the list of registered commands and corresponding description
2192 texts.
2193 The LaTeX file should contain the following definitions:
2194\verbatim
2195 \newcommand{\piacommand}[1]{
2196 \framebox{\bf \Large #1 } \index{#1} % (Command)
2197 }
2198
2199 \newcommand{\piahelpitem}[1]{
2200 \framebox{\bf \Large #1 } \index{#1} (Help item)
2201 }
2202
2203 \newcommand{\myppageref}[1]{ (p. \pageref{#1} ) }
2204
2205\endverbatim
2206*/
2207void Commander::HelptoLaTeX(string const & fname)
2208{
2209FILE *fip;
2210if ((fip = fopen(fname.c_str(), "w")) == NULL) {
2211 cout << "Commander::HelptoLaTex_Error: fopen( " << fname << endl;
2212 return;
2213 }
2214
2215fputs("% ----- Liste des groupes de Help ----- \n",fip);
2216fputs("List of {\\bf piapp} on-line Help groups: \n", fip);
2217fputs("\\begin{itemize} \n",fip);
2218string prl;
2219string mol;
2220CmdHGroup::iterator it;
2221for(it = cmdhgrp.begin(); it != cmdhgrp.end(); it++) {
2222 if ((*it).first == "All") continue;
2223 prl = (*it).first; check_latex_reflabel(prl);
2224 mol = check_latex_underscore((*it).first);
2225 fprintf(fip,"\\item {\\bf %s } (p. \\pageref{%s}) \n",
2226 mol.c_str(), prl.c_str());
2227}
2228
2229fputs("\\end{itemize} \n",fip);
2230
2231fputs("\\vspace*{10mm} \n",fip);
2232
2233CmdExmap::iterator ite;
2234fputs("% ----- Liste de toutes les commandes et help item ----- \n",fip);
2235fputs("\\vspace{5mm} \n",fip);
2236// fputs("\\begin{table}[h!] \n", fip);
2237fputs("\\begin{center} \n ", fip);
2238fputs("\\rule{2cm}{1mm} List of {\\bf piapp} Help items \\rule{2cm}{1mm} \\\\ \n", fip);
2239fputs("\\vspace{3mm} \n",fip);
2240fputs("\\begin{tabular}{llllll} \n", fip);
2241int kt = 0;
2242for(ite = helpexmap.begin(); ite != helpexmap.end(); ite++) {
2243 prl = (*ite).first; check_latex_reflabel(prl);
2244 mol = check_latex_underscore((*ite).first);
2245 fprintf(fip,"%s & p. \\pageref{%s} ", mol.c_str(), prl.c_str() );
2246 kt++;
2247 if (kt < 3) fputs(" & ", fip);
2248 else { fputs(" \\\\ \n", fip); kt = 0; }
2249 }
2250if (kt == 1) fputs(" & & & \\\\ \n", fip);
2251else if (kt == 2) fputs(" & \\\\ \n", fip);
2252fputs("\\end{tabular} \n", fip);
2253fputs("\\end{center} \n", fip);
2254//fputs("\\end{table} \n", fip);
2255fputs("\\newpage \n",fip);
2256
2257int gid;
2258for(it = cmdhgrp.begin(); it != cmdhgrp.end(); it++) {
2259 gid = (*it).second.gid;
2260 if (gid == 0) continue;
2261 // fputs("\\begin{table}[h!] \n",fip);
2262 fputs("\\vspace{6mm} \n",fip);
2263 fputs("\\begin{center} \n ", fip);
2264 fprintf(fip, "\\rule{2cm}{0.5mm} \\makebox[60mm]{{ \\bf %s } help group} \\rule{2cm}{0.5mm} \\\\ \n",
2265 (*it).first.c_str());
2266 fputs("\\vspace{3mm} \n",fip);
2267 fputs("\\begin{tabular}{llllll} \n", fip);
2268 kt = 0;
2269 for(ite = helpexmap.begin(); ite != helpexmap.end(); ite++) {
2270 if ((*ite).second.group != gid) continue;
2271 prl = (*ite).first; check_latex_reflabel(prl);
2272 mol = check_latex_underscore((*ite).first);
2273 fprintf(fip,"%s & p. \\pageref{%s} ", mol.c_str(), prl.c_str() );
2274 kt++;
2275 if (kt < 3) fputs(" & ", fip);
2276 else { fputs(" \\\\ \n", fip); kt = 0; }
2277 }
2278 for(ite = cmdexmap.begin(); ite != cmdexmap.end(); ite++) {
2279 if ((*ite).second.group != gid) continue;
2280 prl = (*ite).first; check_latex_reflabel(prl);
2281 mol = check_latex_underscore((*ite).first);
2282 fprintf(fip,"%s & p. \\pageref{%s} ", mol.c_str(), prl.c_str() );
2283 kt++;
2284 if (kt < 3) fputs(" & ", fip);
2285 else { fputs(" \\\\ \n", fip); kt = 0; }
2286 }
2287 if (kt == 1) fputs(" & & & \\\\ \n", fip);
2288 else if (kt == 2) fputs(" & \\\\ \n", fip);
2289 fputs("\\end{tabular} \n", fip);
2290 fputs("\\end{center} \n", fip);
2291 // fputs("\\end{table} \n",fip);
2292 // fputs("\\vspace{5mm} \n",fip);
2293}
2294// fputs("\\newline \n",fip);
2295
2296fputs("% ----- Liste des commandes dans chaque groupe ----- \n",fip);
2297fputs("\\newpage \n",fip);
2298
2299for(it = cmdhgrp.begin(); it != cmdhgrp.end(); it++) {
2300 gid = (*it).second.gid;
2301 if (gid == 0) continue;
2302 prl = (*it).first; check_latex_reflabel(prl);
2303 fprintf(fip,"\\subsection{%s} \\label{%s} \n",
2304 (*it).first.c_str(), prl.c_str());
2305 if ((*it).second.desc.length() > 0)
2306 fprintf(fip,"%s \n \\\\[2mm] ", (*it).second.desc.c_str());
2307 fprintf(fip,"\\noindent \n");
2308 for(ite = helpexmap.begin(); ite != helpexmap.end(); ite++) {
2309 if ((*ite).second.group != gid) continue;
2310 prl = (*ite).first; check_latex_reflabel(prl);
2311 mol = check_latex_underscore((*ite).first);
2312 fprintf(fip,"\\piahelpitem{%s} \\label{%s} \n",
2313 mol.c_str(), prl.c_str());
2314 fputs("\\begin{verbatim} \n",fip);
2315 fprintf(fip,"%s\n", (*ite).second.us.c_str());
2316 fputs("\\end{verbatim} \n",fip);
2317 }
2318 for(ite = cmdexmap.begin(); ite != cmdexmap.end(); ite++) {
2319 if ((*ite).second.group != gid) continue;
2320 prl = (*ite).first; check_latex_reflabel(prl);
2321 mol = check_latex_underscore((*ite).first);
2322 fprintf(fip,"\\piacommand{%s} \\label{%s} \n",
2323 mol.c_str(), prl.c_str());
2324 fputs("\\begin{verbatim} \n",fip);
2325 fprintf(fip,"%s\n", (*ite).second.us.c_str());
2326 fputs("\\end{verbatim} \n",fip);
2327 }
2328}
2329
2330fclose(fip);
2331cout << " Commander::HelptoLaTeX() - LaTeX format help written to file " << fname << endl;
2332
2333return;
2334}
2335
2336
2337} // End of namespace SOPHYA
2338
Note: See TracBrowser for help on using the repository browser.