1 // ONELAB - Copyright (C) 2010-2012 C. Geuzaine, F. Henrotte
2 //
3 // See the README.txt file for license information. Please report all
4 // issues on https://gitlab.onelab.info/gmsh/gmsh/issues.
5 
6 #include <algorithm>
7 #include "mathex.h"
8 
9 #include "OnelabClients.h"
10 
11 // reserved keywords for the onelab parser
12 
13 namespace olkey {
14   static std::string deflabel("onelab.tags");
15   static std::string label("OL."), comment("#"), separator(";");
16   static std::string line(label + "line");
17   static std::string begin(label + "block");
18   static std::string end(label + "endblock");
19   static std::string include(label + "include");
20   static std::string message(label + "msg");
21   static std::string showParam(label + "show");
22   static std::string showGmsh(label + "merge");
23   static std::string dump(label + "dump");
24   static std::string ifcond(label + "if");
25   static std::string iftrue(label + "iftrue"), ifntrue(label + "ifntrue");
26   static std::string olelse(label + "else"), olendif(label + "endif");
27   static std::string getValue(label + "get");
28   static std::string mathex(label + "eval");
29 } // namespace olkey
30 
31 // Client member functions defined here because they use parser commands
32 
findCommandLine(const std::string & client,const std::string & host)33 bool MetaModel::findCommandLine(const std::string &client,
34                                 const std::string &host)
35 {
36   std::string fileName;
37   size_t pos;
38 
39   // std::cout << "FHF search cmdl: " << client << " , " << host << std::endl;
40 
41   fileName = getWorkingDir() + genericNameFromArgs + onelabExtension + ".save";
42 
43   std::ifstream infile(fileName.c_str());
44   if(infile.is_open()) {
45     while(infile.good()) {
46       std::string line;
47       getline(infile, line);
48       if((pos = line.find(olkey::separator)) != std::string::npos) {
49         std::string name, action;
50         std::vector<std::string> args;
51         extract(line.substr(0, pos), name, action, args);
52         // (name, action, args) = client.commandLine(cmdl{,rhost{,rdir}})
53         std::string cmdl = "", rhost = "localhost", rdir = "";
54         cmdl = args[0];
55         if(args.size() > 1) rhost = args[1];
56         if(args.size() > 2) rdir = args[2];
57 
58         if(name == client) {
59           if((host.empty() && (rhost != "localhost")) ||
60              (host.size() && (rhost == host))) {
61             OLMsg::SetOnelabString(name + "/CommandLine", cmdl, false);
62             if(rhost.compare("localhost")) {
63               OLMsg::SetOnelabString(name + "/HostName", rhost, false);
64               if(rdir.size())
65                 OLMsg::SetOnelabString(name + "/RemoteDir", rdir, false);
66             }
67             // std::cout << "FHF found cmdl: " << cmdl << "," << rhost <<
68             // std::endl;
69             return true;
70           }
71         }
72       }
73     }
74   }
75   infile.close();
76   return false;
77 }
78 
toChar()79 std::string localSolverClient::toChar()
80 {
81   std::ostringstream sstream;
82 
83   if(getCommandLine().size()) {
84     sstream << getName() << ".commandLine(" << getCommandLine();
85     std::string host = OLMsg::GetOnelabString(getName() + "/HostName");
86     if(host.size() && host.compare("localhost")) {
87       sstream << "," << host;
88       std::string rdir = OLMsg::GetOnelabString(getName() + "/RemoteDir");
89       if(rdir.size()) sstream << "," << rdir;
90     }
91     sstream << ");" << std::endl;
92   }
93   return sstream.str();
94 }
95 
saveCommandLines()96 void MetaModel::saveCommandLines()
97 {
98   std::vector<std::string> arguments, buffer;
99   std::string fileName;
100   fileName = getWorkingDir() + genericNameFromArgs + onelabExtension + ".save";
101 
102   std::ifstream infile(fileName.c_str());
103   if(infile.is_open()) {
104     while(infile.good()) {
105       std::string line;
106       getline(infile, line);
107       size_t pos;
108       if((pos = line.find(olkey::separator)) != std::string::npos) {
109         std::string name, action;
110         std::vector<std::string> args;
111         extract(line.substr(0, pos), name, action, args);
112         std::string host = OLMsg::GetOnelabString(name + "/HostName");
113         std::string rhost = (args.size() >= 2) ? args[1] : "";
114         bool keep = rhost.compare(host);
115         if(keep) buffer.push_back(line);
116       }
117     }
118   }
119   else
120     OLMsg::Warning("The file <%s> cannot be opened", fileName.c_str());
121   infile.close();
122 
123   // save client command lines
124   std::ofstream outfile(fileName.c_str());
125   if(outfile.is_open()) {
126     for(citer it = _clients.begin(); it != _clients.end(); it++) {
127       outfile << (*it)->toChar();
128     }
129     for(std::vector<std::string>::const_iterator it = buffer.begin();
130         it != buffer.end(); it++) {
131       outfile << (*it) << std::endl;
132     }
133   }
134   else
135     OLMsg::Error("The file <%s> cannot be opened", fileName.c_str());
136   outfile.close();
137 }
138 
enclosed(const std::string & in,std::vector<std::string> & arguments,size_t & end)139 int enclosed(const std::string &in, std::vector<std::string> &arguments,
140              size_t &end)
141 {
142   // syntax: (arguments[Ø], arguments[1], ... , arguments[n])
143   // arguments[i] may contain parenthesis
144 
145   size_t pos, cursor;
146   arguments.resize(0);
147 
148   pos = 0;
149   if(in[pos] != '(') {
150     OLMsg::Error("Syntax error: <%s>", in.c_str());
151     return 0;
152   }
153   pos++; // skips '('
154   int count = 1;
155   cursor = pos;
156   do {
157     if(in[pos] == '(')
158       count++;
159     else if(in[pos] == ')')
160       count--;
161     else if(in[pos] == ',') {
162       if(count == 1) {
163         arguments.push_back(removeBlanks(in.substr(cursor, pos - cursor)));
164         cursor = pos + 1; // skips ','
165       }
166       else {
167         // ignore this comma
168       }
169     }
170     pos++;
171   } while(count && (pos < in.size()));
172 
173   // count is 0 when the closing brace has been found.
174   if(count && pos == in.size()) {
175     OLMsg::Error("Syntax error: <%s>", in.c_str());
176     return 0;
177   }
178   else
179     arguments.push_back(removeBlanks(in.substr(cursor, pos - 1 - cursor)));
180   end = pos;
181   return arguments.size();
182 }
183 
extract(const std::string & in,std::string & paramName,std::string & action,std::vector<std::string> & arguments)184 int extract(const std::string &in, std::string &paramName, std::string &action,
185             std::vector<std::string> &arguments)
186 {
187   // syntax: paramName.action( arg1, arg2, ... )
188   size_t pos, cursor;
189   cursor = 0;
190   if((pos = in.find(".", cursor)) == std::string::npos) {
191     OLMsg::Error("Syntax error: <%s>", in.c_str());
192     return 0;
193   }
194   else
195     paramName.assign(sanitize(in.substr(cursor, pos - cursor)));
196   cursor = pos + 1; // skips '.'
197   if((pos = in.find("(", cursor)) == std::string::npos) {
198     OLMsg::Error("Syntax error: <%s>", in.c_str());
199     return 0;
200   }
201   else
202     action.assign(sanitize(in.substr(cursor, pos - cursor)));
203   cursor = pos;
204 
205   int NumArg = enclosed(in.substr(cursor), arguments, pos);
206   // std::cout << "FHF=" << in.substr(cursor+pos) << std::endl;
207   if((in.find_first_not_of(" \t", cursor + pos + 1)) != std::string::npos) {
208     OLMsg::Error("Syntax error in <%s> (forgot a %s ?)",
209                  in.substr(cursor + pos + 1).c_str(), olkey::separator.c_str());
210     return 0;
211   }
212   if(!NumArg) OLMsg::Error("Syntax error: <%s>", in.c_str());
213   return NumArg;
214 }
215 
extractLogic(const std::string & in,std::vector<std::string> & arguments)216 int extractLogic(const std::string &in, std::vector<std::string> &arguments)
217 {
218   // syntax: ( argument[0], argument[1]\in{<,>,<=,>=,==,!=}, arguments[2])
219   size_t pos, cursor;
220   arguments.resize(0);
221   cursor = 0;
222   if((pos = in.find("(", cursor)) == std::string::npos) {
223     OLMsg::Error("Syntax error: <%s>", in.c_str());
224     return 0;
225   }
226 
227   unsigned int count = 1;
228   pos++; // skips '('
229   cursor = pos;
230   do {
231     if(in[pos] == '(') count++;
232     if(in[pos] == ')') count--;
233     if((in[pos] == '<') || (in[pos] == '=') || (in[pos] == '>') ||
234        (in[pos] == '!')) {
235       arguments.push_back(removeBlanks(in.substr(cursor, pos - cursor)));
236       if(count != 1) OLMsg::Error("Syntax error: <%s>", in.c_str());
237       cursor = pos;
238       if(in[pos + 1] == '=') {
239         arguments.push_back(in.substr(cursor, 2));
240         pos++;
241       }
242       else {
243         arguments.push_back(in.substr(cursor, 1));
244       }
245       cursor = pos + 1;
246     }
247     pos++;
248   } while(count && (pos != std::string::npos));
249   // count is 0 when the closing brace is found.
250 
251   if(count)
252     OLMsg::Error("Syntax error: mismatched parenthesis in <%s>", in.c_str());
253   else
254     arguments.push_back(removeBlanks(in.substr(cursor, pos - 1 - cursor)));
255 
256   if((arguments.size() != 1) && (arguments.size() != 3))
257     OLMsg::Error("Syntax error: <%s>", in.c_str());
258   return arguments.size();
259 }
260 
extractExpandPattern(const std::string & str)261 std::string extractExpandPattern(const std::string &str)
262 {
263   size_t posa, posb;
264   posa = str.find_first_of("\"\'<");
265   posb = str.find_last_of("\"\'>");
266   std::string pattern = str.substr(posa + 1, posb - posa - 1);
267   posa = pattern.find("comma");
268   if(posa != std::string::npos) pattern.replace(posa, 5, ",");
269   if(pattern.size() != 3)
270     OLMsg::Error("Incorrect expand pattern <%s>", str.c_str());
271   return pattern;
272 }
273 
longName(const std::string name)274 std::string localSolverClient::longName(const std::string name)
275 {
276   std::set<std::string, ShortNameLessThan>::iterator it;
277   std::string fullName;
278   if((it = _parameters.find(name)) != _parameters.end())
279     fullName.assign(OLMsg::obtainFullName(*it));
280   else
281     fullName.assign(OLMsg::obtainFullName(name));
282   return fullName;
283 }
284 
resolveString(const std::string & line)285 std::string localSolverClient::resolveString(const std::string &line)
286 {
287   // looks for the first OL.get() statement,
288   // returns a onelab::string value from the server, if any, or "" otherwise
289   // if no OL.get() statement found, returns line unchanged.
290   std::vector<onelab::string> strings;
291   std::vector<std::string> arguments;
292   size_t pos, cursor;
293 
294   if((pos = line.find(olkey::getValue)) != std::string::npos) {
295     cursor = pos + olkey::getValue.length();
296     int NumArg = enclosed(line.substr(cursor), arguments, pos);
297     if(NumArg < 1) {
298       OLMsg::Error("Malformed %s statement: <%s>", olkey::getValue.c_str(),
299                    line.c_str());
300       return "??";
301     }
302     std::string paramName = longName(arguments[0]);
303     get(strings, paramName);
304     if(strings.size())
305       return strings[0].getValue();
306     else
307       return "";
308   }
309   return line;
310 }
311 
resolveGetVal(std::string line)312 std::string localSolverClient::resolveGetVal(std::string line)
313 {
314   // looks for OL.get() statements, substitute values from server
315   // then evaluate the resulting string with mathex.
316   // OL.get(name
317   //        {, {choices|range}.{size|comp|expand|index}|attributes.get(args)})
318   std::vector<onelab::number> numbers;
319   std::vector<onelab::string> strings;
320   std::vector<std::string> arguments;
321   std::string buff;
322   size_t pos, pos0, cursor;
323 
324   cursor = 0;
325   while((pos = line.find(olkey::getValue, cursor)) != std::string::npos) {
326     pos0 = pos; // for further use
327     cursor = pos + olkey::getValue.length();
328     int NumArg = enclosed(line.substr(cursor), arguments, pos);
329     if(NumArg < 1) {
330       OLMsg::Error("Malformed %s statement: <%s>", olkey::getValue.c_str(),
331                    line.c_str());
332       return "??";
333     }
334     std::string paramName = longName(arguments[0]);
335     get(numbers, paramName);
336     if(numbers.size()) {
337       std::stringstream Num;
338       if(NumArg == 1) {
339         Num << numbers[0].getValue();
340         buff.assign(Num.str());
341       }
342       else if(NumArg == 2) {
343         std::string name, action;
344         std::vector<std::string> args;
345         extract(arguments[1], name, action, args);
346         if(!name.compare("choices")) {
347           std::vector<double> choices = numbers[0].getChoices();
348           if(!action.compare("size")) { buff.assign(ftoa(choices.size())); }
349           else if(!action.compare("begin")) {
350             buff.assign(ftoa(*choices.begin()));
351           }
352           else if(!action.compare("rbegin")) {
353             buff.assign(ftoa(*choices.rbegin()));
354           }
355           else if(!action.compare("comp")) {
356             int i = atoi(args[0].c_str());
357             if((i >= 0) && (i < (int)choices.size())) Num << choices[i];
358             buff.assign(ftoa(choices[i]));
359           }
360           else if(!action.compare("expand")) {
361             std::string pattern;
362             pattern.assign(extractExpandPattern(args[0]));
363             // OLMsg::Info("Expand parameter <%s> with pattern <%s>",
364             // 	      paramName.c_str(),pattern.c_str());
365             buff.assign(1, pattern[0]);
366             for(std::vector<double>::iterator it = choices.begin();
367                 it != choices.end(); it++) {
368               if(it != choices.begin()) buff.append(1, pattern[1]);
369               buff.append(ftoa(*it));
370             }
371             buff.append(1, pattern[2]);
372           }
373           else if(!action.compare("index")) {
374             Num << numbers[0].getIndex();
375             buff.assign(Num.str());
376           }
377           else
378             OLMsg::Error("Unknown action <%s> in %s statement", action.c_str(),
379                          olkey::getValue.c_str());
380         }
381         else if(!name.compare("range")) {
382           double stp = numbers[0].getStep();
383           double min = numbers[0].getMin();
384           double max = numbers[0].getMax();
385 
386           if((stp == 0) || (min == -onelab::parameter::maxNumber()) ||
387              (max == onelab::parameter::maxNumber()))
388             OLMsg::Error("Invalid range description for parameter <%s>",
389                          paramName.c_str());
390           if(!action.compare("size")) {
391             buff.assign(ftoa(fabs((max - min) / stp)));
392           }
393           else if(!action.compare("comp")) {
394             int i = atof(args[0].c_str());
395             if(stp > 0)
396               Num << min + i * stp;
397             else if(stp < 0)
398               Num << max - i * stp;
399           }
400           else if(!action.compare("expand")) {
401           }
402           else
403             OLMsg::Error("Unknown action <%s> in %s statement", action.c_str(),
404                          olkey::getValue.c_str());
405         }
406         else if(!name.compare(0, 6, "attrib")) {
407           if(!action.compare("get")) {
408             buff.assign(numbers[0].getAttribute(args[0]));
409           }
410         }
411       }
412     }
413     else {
414       get(strings, paramName);
415       if(strings.size())
416         buff.assign(strings[0].getValue());
417       else {
418         OLMsg::Error("resolveGetVal: unknown variable: <%s>",
419                      paramName.c_str());
420         return "??";
421       }
422     }
423     line.replace(pos0, cursor + pos - pos0, buff);
424     cursor = pos0 + buff.length();
425   }
426 
427   // Check now wheter the line contains OL.eval's and resolve them
428   cursor = 0;
429   while((pos = line.find(olkey::mathex, cursor)) != std::string::npos) {
430     size_t pos0 = pos;
431     cursor = pos + olkey::mathex.length();
432     if(enclosed(line.substr(cursor), arguments, pos) != 1) {
433       OLMsg::Error("Malformed %s statement: <%s>", olkey::mathex.c_str(),
434                    line.c_str());
435       return "??";
436     }
437     // std::cout << "MathEx evaluates now <"<< arguments[0]<< "> " << std::endl;
438     smlib::mathex *mathExp = new smlib::mathex();
439     mathExp->expression(arguments[0]);
440     double val = mathExp->eval();
441     // std::cout << "MathEx <" << arguments[0] << "> ="<< val << std::endl;
442     line.replace(pos0, cursor + pos - pos0, ftoa(val));
443   }
444 
445   // Check now wheter the line still contains OL.
446   if((pos = line.find(olkey::label)) != std::string::npos)
447     OLMsg::Error("Unidentified onelab command in <%s>", line.c_str());
448 
449   return line;
450 }
451 
resolveLogicExpr(std::vector<std::string> arguments)452 bool localSolverClient::resolveLogicExpr(std::vector<std::string> arguments)
453 {
454   std::vector<onelab::number> numbers;
455 
456   double val1, val2;
457   std::string str1, str2;
458   bool condition = false;
459 
460   if(arguments.size() == 1) {
461     str1.assign(resolveString(arguments[0]));
462     if(str1.size()) return true;
463     val1 = atof(resolveGetVal(arguments[0]).c_str());
464     return (bool)val1;
465   }
466   else if(arguments.size() == 3) {
467     str1.assign(resolveString(arguments[0]));
468     str2.assign(resolveString(arguments[2]));
469     if(str1.size() && str2.size()) {
470       if(!arguments[1].compare("=="))
471         condition = !str1.compare(str2);
472       else if(!arguments[1].compare("!="))
473         condition = str1.compare(str2);
474       else
475         OLMsg::Error("Unknown logical operator <%s> for strings",
476                      arguments[1].c_str());
477     }
478     else {
479       val1 = atof(resolveGetVal(arguments[0]).c_str());
480       val2 = atof(resolveGetVal(arguments[2]).c_str());
481       if(!arguments[1].compare("<"))
482         condition = (val1 < val2);
483       else if(!arguments[1].compare("<="))
484         condition = (val1 <= val2);
485       else if(!arguments[1].compare(">"))
486         condition = (val1 > val2);
487       else if(!arguments[1].compare(">="))
488         condition = (val1 >= val2);
489       else if(!arguments[1].compare("=="))
490         condition = (val1 == val2);
491       else if(!arguments[1].compare("!="))
492         condition = (val1 != val2);
493       else
494         OLMsg::Error("Unknown logical operator <%s>", arguments[1].c_str());
495     }
496   }
497   else
498     OLMsg::Error("Invalid logical expression");
499   return condition;
500 }
501 
resolveRange(const std::string & in,std::vector<double> & arguments)502 bool localSolverClient::resolveRange(const std::string &in,
503                                      std::vector<double> &arguments)
504 {
505   // syntax: a:b:c or a:b|n with a,b,c numbers and n integer
506   double val;
507   size_t pos, cursor;
508   arguments.resize(0);
509   cursor = 0;
510   if((pos = in.find(":", cursor)) == std::string::npos) {
511     OLMsg::Error("Syntax error in range <%s>", in.c_str());
512     return 0;
513   }
514   else {
515     val = atof(resolveGetVal(in.substr(cursor, pos - cursor)).c_str());
516     arguments.push_back(val);
517   }
518   cursor = pos + 1; // skips ':'
519   if((pos = in.find(":", cursor)) != std::string::npos) {
520     // arguments.push_back(atof(in.substr(cursor,pos-cursor).c_str()));
521     // arguments.push_back(atof(in.substr(pos+1).c_str()));
522     val = atof(resolveGetVal(in.substr(cursor, pos - cursor)).c_str());
523     arguments.push_back(val);
524     val = atof(resolveGetVal(in.substr(pos + 1)).c_str());
525     arguments.push_back(val);
526   }
527   else if((pos = in.find("|", cursor)) != std::string::npos) {
528     // arguments.push_back(atof(in.substr(cursor,pos-cursor).c_str()));
529     // double NumStep = atof(in.substr(pos+1).c_str());
530     // arguments.push_back((arguments[1]-arguments[0])/((NumStep==0)?1:NumStep));
531     val = atof(resolveGetVal(in.substr(cursor, pos - cursor)).c_str());
532     arguments.push_back(val);
533     double NumStep = atof(in.substr(pos + 1).c_str());
534     arguments.push_back((arguments[1] - arguments[0]) /
535                         ((NumStep == 0) ? 1 : NumStep));
536   }
537   else
538     OLMsg::Error("Syntax error in range <%s>", in.c_str());
539   return (arguments.size() == 3);
540 }
541 
parse_sentence(std::string line)542 void localSolverClient::parse_sentence(std::string line)
543 {
544   size_t pos, cursor;
545   std::string name, action, path;
546   std::vector<std::string> arguments;
547   std::vector<onelab::number> numbers;
548   std::vector<onelab::string> strings;
549 
550   cursor = 0;
551   while((pos = line.find(olkey::separator, cursor)) != std::string::npos) {
552     std::string name, action;
553     // std::cout << "line=" << line << std::endl;
554 
555     extract(line.substr(cursor, pos - cursor), name, action, arguments);
556     if(!action.compare("number")) {
557       // syntax: paramName.number(val,path,help,range(optional))
558       double val = 0.0;
559       if(arguments.size() > 1) name.assign(FixOLPath(arguments[1]) + name);
560       _parameters.insert(name);
561       OLMsg::recordFullName(name);
562       get(numbers, name);
563       if(numbers.empty()) {
564         numbers.resize(1);
565         numbers[0].setName(name);
566         if(arguments[0].empty()) {
567           numbers[0].setReadOnly(true);
568           numbers[0].setNeverChanged(true);
569         }
570         else
571           val = atof(resolveGetVal(arguments[0]).c_str());
572         numbers[0].setValue(val);
573       }
574       // else if(arguments[0].empty()) // resets read only parameters
575       // 	  numbers[0].setValue(val);
576 
577       if(arguments.size() > 2) numbers[0].setLabel(unquote(arguments[2]));
578       if(arguments.size() > 3) {
579         std::vector<double> bounds;
580         if(resolveRange(arguments[3], bounds)) {
581           numbers[0].setMin(bounds[0]);
582           numbers[0].setMax(bounds[1]);
583           numbers[0].setStep(bounds[2]);
584         }
585       }
586       set(numbers[0]);
587     }
588     else if(!action.compare("string")) {
589       // syntax: paramName.string(val,path,help)
590       std::string val = "";
591       if(arguments.size() > 1)
592         name.assign(FixOLPath(arguments[1]) + name); // append path
593       _parameters.insert(name);
594       OLMsg::recordFullName(name);
595       get(strings, name);
596       if(strings.empty()) {
597         strings.resize(1);
598         strings[0].setName(name);
599         if(arguments[0].empty()) {
600           strings[0].setReadOnly(true);
601           strings[0].setNeverChanged(true);
602         }
603         else
604           val = resolveGetVal(arguments[0]);
605         strings[0].setValue(val);
606       }
607       // choices list is reset
608       std::vector<std::string> choices;
609       strings[0].setChoices(choices);
610 
611       if(arguments.size() > 2) strings[0].setLabel(unquote(arguments[2]));
612       set(strings[0]);
613     }
614     else if(!action.compare("radioButton")) {
615       // syntax: paramName.radioButton(val,path,label)
616       double val = 0;
617       if(arguments[0].empty())
618         OLMsg::Error("No value given for param <%s>", name.c_str());
619       else
620         val = atof(arguments[0].c_str());
621       if(arguments.size() > 1) name.assign(FixOLPath(arguments[1]) + name);
622       _parameters.insert(name);
623       OLMsg::recordFullName(name);
624       get(numbers, name);
625       if(numbers.size()) {
626         val = numbers[0].getValue(); // use value from server
627       }
628       else {
629         numbers.resize(1);
630         numbers[0].setName(name);
631         numbers[0].setValue(val);
632       }
633       if(arguments.size() > 2) numbers[0].setLabel(unquote(arguments[2]));
634       std::vector<double> choices;
635       choices.push_back(0);
636       choices.push_back(1);
637       numbers[0].setChoices(choices);
638       set(numbers[0]);
639     }
640     else if(!action.compare("range")) {
641       // set the range of an existing number
642       // syntax: paramName.range({a:b:c|a:b#n|min,max,step})
643       if(arguments[0].empty())
644         OLMsg::Error("No argument given for MinMax <%s>", name.c_str());
645       else {
646         name.assign(longName(name));
647         get(numbers, name);
648         if(numbers.size()) { // parameter must exist
649           if(arguments.size() == 1) {
650             std::vector<double> bounds;
651             if(resolveRange(arguments[0], bounds)) {
652               numbers[0].setMin(bounds[0]);
653               numbers[0].setMax(bounds[1]);
654               numbers[0].setStep(bounds[2]);
655             }
656           }
657           else if(arguments.size() == 3) {
658             numbers[0].setMin(atof(arguments[0].c_str()));
659             numbers[0].setMax(atof(arguments[1].c_str()));
660             numbers[0].setStep(atof(arguments[2].c_str()));
661           }
662           else
663             OLMsg::Error("Wrong number of arguments for range <%s>",
664                          name.c_str());
665           set(numbers[0]);
666         }
667         else
668           OLMsg::Error("The parameter <%s> does not exist", name.c_str());
669       }
670     }
671     else if(!action.compare("withinRange")) {
672       // ensure the value is in the prescribed range
673       name.assign(longName(name));
674       get(numbers, name);
675       if(numbers.size()) { // parameter must exist
676         if((numbers[0].getMin() != -onelab::parameter::maxNumber()) &&
677            (numbers[0].getValue() < numbers[0].getMin()))
678           numbers[0].setValue(numbers[0].getMin());
679         if((numbers[0].getMax() != onelab::parameter::maxNumber()) &&
680            (numbers[0].getValue() > numbers[0].getMax()))
681           numbers[0].setValue(numbers[0].getMax());
682         set(numbers[0]);
683       }
684       else
685         OLMsg::Error("The parameter <%s> does not exist", name.c_str());
686     }
687     else if(!action.compare("setValue")) {
688       // a set request together with a setReadOnly(1) forces
689       // the value on server to be changed.
690       name.assign(longName(name));
691       get(numbers, name);
692       if(numbers.size()) {
693         if(arguments[0].size())
694           numbers[0].setValue(atof(resolveGetVal(arguments[0]).c_str()));
695         numbers[0].setReadOnly(1);
696         set(numbers[0]);
697       }
698       else {
699         get(strings, name);
700         if(strings.size()) {
701           if(arguments[0].empty()) // resets an empty string
702             strings[0].setValue("");
703           else
704             strings[0].setValue(arguments[0]);
705           strings[0].setReadOnly(1);
706           set(strings[0]);
707         }
708         else
709           OLMsg::Error("The parameter <%s> does not exist", name.c_str());
710       }
711     }
712     else if(!action.compare("resetChoices")) {
713       name.assign(longName(name));
714       get(numbers, name);
715 
716       if(numbers.size()) { // parameter must exist
717         std::vector<double> choices;
718         numbers[0].setChoices(choices);
719         std::map<double, std::string> valuelabels;
720         numbers[0].setValueLabels(valuelabels);
721         set(numbers[0]);
722       }
723       else {
724         get(strings, name);
725         if(strings.size()) {
726           std::vector<std::string> choices;
727           strings[0].setChoices(choices);
728           set(strings[0]);
729         }
730         else {
731           OLMsg::Error("The parameter <%s> does not exist", name.c_str());
732         }
733       }
734     }
735     else if(!action.compare("addChoices")) {
736       name.assign(longName(name));
737       get(numbers, name);
738       if(numbers.size()) { // parameter must exist
739         std::vector<double> choices = numbers[0].getChoices();
740         for(unsigned int i = 0; i < arguments.size(); i++) {
741           double val = atof(resolveGetVal(arguments[i]).c_str());
742           // if(std::find(choices.begin(),choices.end(),val)==choices.end())
743           choices.push_back(val);
744         }
745         numbers[0].setChoices(choices);
746         set(numbers[0]);
747       }
748       else {
749         get(strings, name);
750         if(strings.size()) {
751           std::vector<std::string> choices = strings[0].getChoices();
752           for(unsigned int i = 0; i < arguments.size(); i++)
753             if(std::find(choices.begin(), choices.end(), arguments[i]) ==
754                choices.end())
755               choices.push_back(arguments[i]);
756           strings[0].setChoices(choices);
757           set(strings[0]);
758         }
759         else {
760           OLMsg::Error("The parameter <%s> does not exist", name.c_str());
761         }
762       }
763     }
764     else if(!action.compare("valueLabels")) {
765       name.assign(longName(name));
766       get(numbers, name);
767       if(numbers.size()) { // parameter must exist
768         if(arguments.size() % 2) {
769           OLMsg::Error("Nb of labels does not match nb of choices for <%s>",
770                        name.c_str());
771         }
772         else {
773           std::vector<double> choices = numbers[0].getChoices();
774           for(unsigned int i = 0; i < arguments.size(); i = i + 2) {
775             double val = atof(resolveGetVal(arguments[i]).c_str());
776             if(std::find(choices.begin(), choices.end(), val) == choices.end())
777               choices.push_back(val);
778             numbers[0].setValueLabel(val, unquote(arguments[i + 1]));
779           }
780           numbers[0].setChoices(choices);
781           set(numbers[0]);
782         }
783       }
784       else
785         OLMsg::Error("The number <%s> does not exist", name.c_str());
786     }
787     else if(!action.compare("setVisible")) {
788       if(arguments[0].empty())
789         OLMsg::Error("Missing argument SetVisible <%s>", name.c_str());
790       else {
791         name.assign(longName(name));
792         get(numbers, name);
793         if(numbers.size()) {
794           numbers[0].setVisible(atof(resolveGetVal(arguments[0]).c_str()));
795           set(numbers[0]);
796         }
797         else {
798           get(strings, name);
799           if(strings.size()) {
800             strings[0].setVisible(atof(resolveGetVal(arguments[0]).c_str()));
801             set(strings[0]);
802           }
803           else {
804             OLMsg::Error("The parameter <%s> does not exist", name.c_str());
805           }
806         }
807       }
808     }
809     else if(!action.compare("setReadOnly")) {
810       if(arguments[0].empty())
811         OLMsg::Error("Missing argument SetReadOnly <%s>", name.c_str());
812       else {
813         name.assign(longName(name));
814         get(numbers, name);
815         if(numbers.size()) {
816           numbers[0].setReadOnly(atof(resolveGetVal(arguments[0]).c_str()));
817           set(numbers[0]);
818         }
819         else {
820           get(strings, name);
821           if(strings.size()) {
822             strings[0].setReadOnly(atof(resolveGetVal(arguments[0]).c_str()));
823             set(strings[0]);
824           }
825           else {
826             OLMsg::Error("The parameter <%s> does not exist", name.c_str());
827           }
828         }
829       }
830     }
831     else if(!action.compare("layout")) {
832       name.assign(longName(name));
833       get(numbers, name);
834       if(numbers.size()) {
835         numbers[0].setReadOnly(0);
836         numbers[0].setAttribute("Highlight", "Ivory");
837         set(numbers[0]);
838       }
839       else {
840         get(strings, name);
841         if(strings.size()) {
842           strings[0].setReadOnly(0);
843           strings[0].setAttribute("Highlight", "Ivory");
844           set(strings[0]);
845         }
846         else {
847           OLMsg::Error("The parameter <%s> does not exist", name.c_str());
848         }
849       }
850     }
851     else if(!action.compare("setAttribute")) {
852       if(arguments.size() != 2)
853         OLMsg::Error("SetAttribute <%s> needs two arguments %d", name.c_str(),
854                      arguments.size());
855       else {
856         name.assign(longName(name));
857         get(numbers, name);
858         if(numbers.size()) {
859           numbers[0].setAttribute(arguments[0].c_str(),
860                                   resolveGetVal(arguments[1]).c_str());
861           set(numbers[0]);
862         }
863         else {
864           get(strings, name);
865           if(strings.size()) {
866             strings[0].setAttribute(arguments[0].c_str(), arguments[1].c_str());
867             set(strings[0]);
868           }
869           else {
870             OLMsg::Error("The parameter <%s> does not exist", name.c_str());
871           }
872         }
873       }
874     }
875     else {
876       client_sentence(name, action, arguments);
877     }
878     cursor = pos + 1;
879   }
880   // check whether
881   if((line.find_first_not_of(" \t", cursor)) != std::string::npos) {
882     OLMsg::Error("Syntax error in <%s> (forgot a %s ?)",
883                  line.substr(cursor).c_str(), olkey::separator.c_str());
884   }
885 }
886 
modify_tags(const std::string lab,const std::string com)887 void localSolverClient::modify_tags(const std::string lab,
888                                     const std::string com)
889 {
890   bool changed = false;
891   if(lab.compare(olkey::label) && lab.size()) {
892     changed = true;
893     olkey::label.assign(lab);
894     olkey::line.assign(olkey::label + "line");
895     olkey::begin.assign(olkey::label + "block");
896     olkey::end.assign(olkey::label + "endblock");
897     olkey::include.assign(olkey::label + "include");
898     olkey::message.assign(olkey::label + "msg");
899     olkey::showParam.assign(olkey::label + "show");
900     olkey::showGmsh.assign(olkey::label + "merge");
901     olkey::dump.assign(olkey::label + "dump");
902     olkey::ifcond.assign(olkey::label + "if");
903     olkey::iftrue.assign(olkey::label + "iftrue");
904     olkey::ifntrue.assign(olkey::label + "ifntrue");
905     olkey::olelse.assign(olkey::label + "else");
906     olkey::olendif.assign(olkey::label + "endif");
907     olkey::getValue.assign(olkey::label + "get");
908     olkey::mathex.assign(olkey::label + "eval");
909   }
910   if(com.compare(olkey::comment) && com.size()) {
911     changed = true;
912     olkey::comment.assign(com);
913   }
914 
915   if(changed)
916     OLMsg::Info("Using now onelab tags <%s,%s>", olkey::label.c_str(),
917                 olkey::comment.c_str());
918 }
919 
parse_oneline(std::string line,std::ifstream & infile)920 void localSolverClient::parse_oneline(std::string line, std::ifstream &infile)
921 {
922   size_t pos, cursor;
923   std::vector<std::string> arguments;
924   std::vector<onelab::number> numbers;
925   std::vector<onelab::string> strings;
926 
927   if((pos = line.find_first_not_of(" \t")) == std::string::npos) {
928     // empty line, skip
929   }
930   else if(!line.compare(pos, olkey::comment.size(), olkey::comment)) {
931     // commented out line, skip
932   }
933   else if((pos = line.find(olkey::deflabel)) != std::string::npos) {
934     // onelab.tags(label,comment);
935     // onelab.tags(); -> reset to default
936     cursor = pos + olkey::deflabel.length();
937     int NumArg = enclosed(line.substr(cursor), arguments, pos);
938     if((NumArg == 1) && arguments[0].empty())
939       modify_tags("", "");
940     else if(NumArg == 2)
941       modify_tags(arguments[0], arguments[1]);
942     else
943       OLMsg::Error("Malformed <%s> statement", olkey::deflabel.c_str());
944   }
945   else if((pos = line.find(olkey::begin)) != std::string::npos) {
946     // onelab.block
947     if(!parse_block(infile))
948       OLMsg::Error("Malformed <%s> block <%s>", olkey::begin.c_str(),
949                    olkey::end.c_str());
950   }
951   else if((pos = line.find(olkey::iftrue)) != std::string::npos) {
952     // onelab.iftrue
953     cursor = pos + olkey::iftrue.length();
954     bool condition = false;
955     if(enclosed(line.substr(cursor), arguments, pos) < 1)
956       OLMsg::Error("Malformed <%s> statement: (%s)", olkey::iftrue.c_str(),
957                    line.c_str());
958     else {
959       get(strings, longName(arguments[0]));
960       if(strings.size())
961         condition = true;
962       else {
963         get(numbers, longName(arguments[0]));
964         if(numbers.size())
965           condition = (bool)numbers[0].getValue();
966         else
967           OLMsg::Error("Unknown parameter <%s> in <%s> statement",
968                        arguments[0].c_str(), olkey::iftrue.c_str());
969       }
970       if(!parse_ifstatement(infile, condition))
971         OLMsg::Error("Malformed <%s> statement: <%s>", olkey::iftrue.c_str(),
972                      arguments[0].c_str());
973     }
974   }
975   else if((pos = line.find(olkey::ifntrue)) != std::string::npos) {
976     // onelab.ifntrue
977     cursor = pos + olkey::ifntrue.length();
978     bool condition = false;
979     if(enclosed(line.substr(cursor), arguments, pos) < 1)
980       OLMsg::Error("Malformed <%s> statement: (%s)", olkey::ifntrue.c_str(),
981                    line.c_str());
982     else {
983       get(strings, longName(arguments[0]));
984       if(strings.size())
985         condition = true;
986       else {
987         get(numbers, longName(arguments[0]));
988         if(numbers.size())
989           condition = (bool)numbers[0].getValue();
990         else {
991           condition = false;
992           // OLMsg::Warning("Unknown parameter <%s> in <%s> statement",
993           // 	       arguments[0].c_str(),olkey::ifntrue.c_str());
994         }
995       }
996       if(!parse_ifstatement(infile, !condition))
997         OLMsg::Error("Malformed <%s> statement: <%s>", olkey::ifntrue.c_str(),
998                      arguments[0].c_str());
999     }
1000   }
1001   else if((pos = line.find(olkey::ifcond)) != std::string::npos) {
1002     // onelab.ifcond
1003     cursor = pos + olkey::ifcond.length();
1004     extractLogic(line.substr(cursor), arguments);
1005     bool condition = resolveLogicExpr(arguments);
1006     if(!parse_ifstatement(infile, condition)) {
1007       OLMsg::Error("Malformed %s statement: <%s>", olkey::ifcond.c_str(),
1008                    line.c_str());
1009     }
1010   }
1011   else if((pos = line.find(olkey::include)) != std::string::npos) {
1012     // onelab.include
1013     cursor = pos + olkey::include.length();
1014     if(enclosed(line.substr(cursor), arguments, pos) < 1)
1015       OLMsg::Error("Malformed <%s> statement: (%s)", olkey::include.c_str(),
1016                    line.c_str());
1017     else {
1018       std::string filename = getWorkingDir() + resolveGetVal(arguments[0]);
1019       OLMsg::Info("Parse file <%s> %s", filename.c_str(),
1020                   parse_onefile(filename) ? "done" : "failed");
1021     }
1022   }
1023   else if((pos = line.find(olkey::message)) != std::string::npos) {
1024     // onelab.message
1025     cursor = pos + olkey::message.length();
1026     if(enclosed(line.substr(cursor), arguments, pos) < 1)
1027       OLMsg::Error("Malformed <%s> statement: (%s)", olkey::message.c_str(),
1028                    line.c_str());
1029     else {
1030       std::string msg = resolveGetVal(arguments[0]);
1031       OLMsg::Info("%s", msg.c_str());
1032     }
1033   }
1034   else if((pos = line.find(olkey::showParam)) != std::string::npos) {
1035     // onelab.showParam
1036     cursor = pos + olkey::showParam.length();
1037     if(enclosed(line.substr(cursor), arguments, pos) < 1)
1038       OLMsg::Error("Malformed <%s> statement: (%s)", olkey::showParam.c_str(),
1039                    line.c_str());
1040     for(unsigned int i = 0; i < arguments.size(); i++) {
1041       std::string lname = longName(arguments[i]);
1042       std::string msg;
1043       get(numbers, lname);
1044       if(numbers.size())
1045         msg.assign(numbers[0].toChar());
1046       else {
1047         get(strings, lname);
1048         if(strings.size())
1049           msg.assign(strings[0].toChar());
1050         else
1051           OLMsg::Error("Unknown parameter <%s> in <%s> statement",
1052                        arguments[i].c_str(), olkey::showParam.c_str());
1053       }
1054       for(unsigned int j = 0; j < msg.size(); j++)
1055         if(msg[j] == onelab::parameter::charSep()) msg[j] = '|';
1056       OLMsg::Info("%s", msg.c_str());
1057     }
1058   }
1059   else if((pos = line.find(olkey::showGmsh)) != std::string::npos) {
1060     // onelab.showGmsh
1061     cursor = pos + olkey::showGmsh.length();
1062     if(enclosed(line.substr(cursor), arguments, pos) < 1)
1063       OLMsg::Error("Malformed <%s> statement: (%s)", olkey::showGmsh.c_str(),
1064                    line.c_str());
1065     else {
1066       std::string fileName = resolveGetVal(arguments[0]);
1067       OLMsg::MergeFile(getWorkingDir() + fileName);
1068     }
1069   }
1070   else if((pos = line.find(olkey::dump)) != std::string::npos) {
1071     // onelab.dump
1072     cursor = pos + olkey::dump.length();
1073     if(enclosed(line.substr(cursor), arguments, pos) < 1) {
1074       OLMsg::Error("Malformed <%s> statement: (%s)", olkey::dump.c_str(),
1075                    line.c_str());
1076     }
1077     else {
1078       FILE *fp = fopen(resolveGetVal(arguments[0]).c_str(), "wb");
1079       if(fp) {
1080         onelab::server::instance()->toFile(fp);
1081         fclose(fp);
1082       }
1083     }
1084   }
1085   else if(isOnelabBlock() ||
1086           (!isOnelabBlock() &&
1087            ((pos = line.find(olkey::line)) != std::string::npos))) {
1088     // either any line with no "OL." within a onelabBlock or a line
1089     // introduced by a "onelab.line" tag not within a onelabBlock
1090     std::string cmds = "", cmd;
1091     size_t posa, posb;
1092     int NbLines = 1;
1093     bool err = false, terminated = false;
1094     do {
1095       // skip tag 'olkey::line' if any
1096       if((pos = line.find(olkey::line)) != std::string::npos)
1097         posa = pos + olkey::line.size();
1098       else
1099         posa = 0;
1100 
1101       // skip trailing comments if any
1102       posb = line.find(olkey::comment);
1103       if(posb == std::string::npos)
1104         cmd.assign(line.substr(posa));
1105       else
1106         cmd.assign(line.substr(posa, posb - posa));
1107 
1108       cmds.append(cmd);
1109 
1110       // check whether "cmd" ends with "olkey::separator"
1111       pos = cmd.find_last_of(olkey::separator);
1112       terminated = (pos != std::string::npos);
1113 
1114       // std::cout << "cmds=<" << cmds << ">" << terminated << std::endl;
1115 
1116       if(!terminated) {
1117         // not found olkey::separator => append the next nonempty line
1118         while(infile.good()) {
1119           getline(infile, line);
1120           NbLines++; // command should not span over more than 20 nonempty lines
1121           if(line.find_first_not_of(" \t") != std::string::npos) break;
1122         }
1123 
1124         if(infile.good()) {
1125           // check that no OL. commands is found except OL.get or OL.eval
1126           if((pos = line.find(olkey::getValue)) != std::string::npos) {
1127             err = false;
1128           }
1129           else if((pos = line.find(olkey::mathex)) != std::string::npos) {
1130             err = false;
1131           }
1132           else if((pos = line.find(olkey::end)) != std::string::npos) {
1133             err = true;
1134             closeOnelabBlock();
1135           }
1136           else if((pos = line.find(olkey::label)) != std::string::npos) {
1137             err = true;
1138           }
1139         }
1140       }
1141     } while(infile.good() && !err && !terminated && NbLines <= 20);
1142 
1143     if(!terminated) {
1144       if(NbLines >= 20)
1145         OLMsg::Error("Command <%s> should not span over more than 20 lines",
1146                      cmds.c_str());
1147       else
1148         OLMsg::Error("Unterminated command <%s>", cmds.c_str());
1149       return;
1150     }
1151     else
1152       parse_sentence(cmds);
1153   }
1154   else if((pos = line.find(olkey::getValue)) != std::string::npos) {
1155     // onelab.getValue: nothing to do
1156   }
1157   else if((pos = line.find(olkey::mathex)) != std::string::npos) {
1158     // onelab.mathex: nothing to do
1159   }
1160   else if((pos = line.find(olkey::label)) != std::string::npos) {
1161     OLMsg::Error("Unknown ONELAB keyword in <%s>", line.c_str());
1162   }
1163   else {
1164     // not a onelab line, skip
1165   }
1166 }
1167 
parse_block(std::ifstream & infile)1168 bool localSolverClient::parse_block(std::ifstream &infile)
1169 {
1170   size_t pos;
1171   std::string line;
1172   openOnelabBlock();
1173   while(infile.good()) {
1174     getline(infile, line);
1175     if((pos = line.find_first_not_of(" \t")) == std::string::npos)
1176       continue; // skip empty line
1177     if((pos = line.find(olkey::end)) != std::string::npos) {
1178       closeOnelabBlock();
1179       return true;
1180     }
1181     parse_oneline(line, infile);
1182   }
1183   return false;
1184 }
1185 
parse_ifstatement(std::ifstream & infile,bool condition)1186 bool localSolverClient::parse_ifstatement(std::ifstream &infile, bool condition)
1187 {
1188   int level;
1189   size_t pos;
1190   std::string line;
1191 
1192   bool trueclause = true;
1193   level = 1;
1194   while(infile.good() && level) {
1195     getline(infile, line);
1196     if(((pos = line.find(olkey::olelse)) != std::string::npos) && (level == 1))
1197       trueclause = false;
1198     else if((pos = line.find(olkey::olendif)) != std::string::npos)
1199       level--;
1200     else if(!(trueclause ^ condition)) // xor bitwise operator
1201       parse_oneline(line, infile);
1202     else { // check for opening if statements
1203       if((pos = line.find(olkey::iftrue)) != std::string::npos)
1204         level++;
1205       else if((pos = line.find(olkey::ifntrue)) != std::string::npos)
1206         level++;
1207       else if((pos = line.find(olkey::ifcond)) != std::string::npos)
1208         level++;
1209     }
1210   }
1211   return level ? false : true;
1212 }
1213 
parse_onefile(std::string fileName,bool mandatory)1214 bool localSolverClient::parse_onefile(std::string fileName, bool mandatory)
1215 {
1216   std::ifstream infile(fileName.c_str());
1217   if(infile.is_open()) {
1218     while(infile.good()) {
1219       std::string line;
1220       getline(infile, line);
1221       parse_oneline(line, infile);
1222     }
1223     infile.close();
1224     return true;
1225   }
1226   else {
1227     return !mandatory;
1228     // if(mandatory)
1229     //   OLMsg::Error("The file <%s> does not exist",fileName.c_str());
1230     // else
1231     //   OLMsg::Warning("The file <%s> does not exist",fileName.c_str());
1232   }
1233 }
1234 
convert_ifstatement(std::ifstream & infile,std::ofstream & outfile,bool condition)1235 bool localSolverClient::convert_ifstatement(std::ifstream &infile,
1236                                             std::ofstream &outfile,
1237                                             bool condition)
1238 {
1239   int level;
1240   size_t pos;
1241   std::string line;
1242 
1243   bool trueclause = true;
1244   level = 1;
1245   while(infile.good() && level) {
1246     getline(infile, line);
1247     if(((pos = line.find(olkey::olelse)) != std::string::npos) && (level == 1))
1248       trueclause = false;
1249     else if((pos = line.find(olkey::olendif)) != std::string::npos)
1250       level--;
1251     else if(!(trueclause ^ condition)) // xor bitwise operator
1252       convert_oneline(line, infile, outfile);
1253     else { // check for opening if statements
1254       if((pos = line.find(olkey::iftrue)) != std::string::npos)
1255         level++;
1256       else if((pos = line.find(olkey::ifntrue)) != std::string::npos)
1257         level++;
1258       else if((pos = line.find(olkey::ifcond)) != std::string::npos)
1259         level++;
1260     }
1261   }
1262   return level ? false : true;
1263 }
1264 
convert_oneline(std::string line,std::ifstream & infile,std::ofstream & outfile)1265 void localSolverClient::convert_oneline(std::string line, std::ifstream &infile,
1266                                         std::ofstream &outfile)
1267 {
1268   size_t pos, cursor;
1269   std::vector<std::string> arguments;
1270   std::vector<onelab::number> numbers;
1271   std::vector<onelab::string> strings;
1272 
1273   if((pos = line.find_first_not_of(" \t")) == std::string::npos) {
1274     // empty line, we keep them
1275     outfile << line << std::endl;
1276   }
1277   else if(!line.compare(pos, olkey::comment.size(), olkey::comment)) {
1278     // commented out, skip the line
1279   }
1280   else if((pos = line.find(olkey::deflabel)) != std::string::npos) {
1281     // onelab.tags(label,comment,separator)
1282     cursor = pos + olkey::deflabel.length();
1283     int NumArg = enclosed(line.substr(cursor), arguments, pos);
1284     if(NumArg == 0)
1285       modify_tags("", "");
1286     else if(NumArg == 2)
1287       modify_tags(arguments[0], arguments[1]);
1288     else
1289       OLMsg::Error("Malformed <%s> statement", olkey::deflabel.c_str());
1290   }
1291   else if((pos = line.find(olkey::begin)) != std::string::npos) {
1292     // onelab.begin
1293     while(infile.good()) {
1294       getline(infile, line);
1295       if((pos = line.find(olkey::end)) != std::string::npos) return;
1296     }
1297     OLMsg::Error("Malformed <%s> block <%s>", olkey::begin.c_str(),
1298                  olkey::end.c_str());
1299   }
1300   else if((pos = line.find(olkey::iftrue)) != std::string::npos) {
1301     // onelab.iftrue
1302     cursor = pos + olkey::iftrue.length();
1303     bool condition = false;
1304     if(enclosed(line.substr(cursor), arguments, pos) < 1)
1305       OLMsg::Error("Malformed <%s> statement: (%s)", olkey::iftrue.c_str(),
1306                    line.c_str());
1307     else {
1308       get(strings, longName(arguments[0]));
1309       if(strings.size())
1310         condition = strings[0].getValue().size();
1311       else {
1312         get(numbers, longName(arguments[0]));
1313         if(numbers.size())
1314           condition = (bool)numbers[0].getValue();
1315         else {
1316           OLMsg::Warning("Unknown parameter <%s> in <%s> statement",
1317                          arguments[0].c_str(), olkey::iftrue.c_str());
1318         }
1319       }
1320       if(!convert_ifstatement(infile, outfile, condition))
1321         OLMsg::Error("Malformed <%s> statement: %s", olkey::iftrue.c_str(),
1322                      arguments[0].c_str());
1323     }
1324   }
1325   else if((pos = line.find(olkey::ifntrue)) != std::string::npos) {
1326     // onelab.ifntrue
1327     cursor = pos + olkey::ifntrue.length();
1328     bool condition = false;
1329     if(enclosed(line.substr(cursor), arguments, pos) < 1)
1330       OLMsg::Error("Malformed <%s> statement: (%s)", olkey::ifntrue.c_str(),
1331                    line.c_str());
1332     else {
1333       get(strings, longName(arguments[0]));
1334       if(strings.size())
1335         condition = strings[0].getValue().size();
1336       else {
1337         get(numbers, longName(arguments[0]));
1338         if(numbers.size())
1339           condition = (bool)numbers[0].getValue();
1340         else {
1341           OLMsg::Warning("Unknown parameter <%s> in <%s> statement",
1342                          arguments[0].c_str(), olkey::ifntrue.c_str());
1343         }
1344       }
1345       if(!convert_ifstatement(infile, outfile, !condition))
1346         OLMsg::Error("Malformed <%s> statement: %s", olkey::ifntrue.c_str(),
1347                      arguments[0].c_str());
1348     }
1349   }
1350   else if((pos = line.find(olkey::ifcond)) != std::string::npos) {
1351     // onelab.ifcond
1352     cursor = pos + olkey::ifcond.length();
1353     extractLogic(line.substr(cursor), arguments);
1354     bool condition = resolveLogicExpr(arguments);
1355     if(!convert_ifstatement(infile, outfile, condition))
1356       OLMsg::Error("Malformed %s statement: <%s>", olkey::ifcond.c_str(),
1357                    line.c_str());
1358   }
1359   else if((pos = line.find(olkey::include)) != std::string::npos) {
1360     // onelab.include
1361     cursor = pos + olkey::include.length();
1362     if(enclosed(line.substr(cursor), arguments, pos) < 1)
1363       OLMsg::Error("Malformed <%s> statement: (%s)", olkey::include.c_str(),
1364                    line.c_str());
1365     else {
1366       std::string filename = getWorkingDir() + resolveGetVal(arguments[0]);
1367       convert_onefile(filename, outfile);
1368     }
1369   }
1370   else if((pos = line.find(olkey::message)) != std::string::npos) {
1371     // onelab.message
1372     cursor = pos + olkey::message.length();
1373     if(enclosed(line.substr(cursor), arguments, pos) < 1)
1374       OLMsg::Error("Malformed <%s> statement: (%s)", olkey::message.c_str(),
1375                    line.c_str());
1376     else {
1377       std::string msg = resolveGetVal(arguments[0]);
1378       OLMsg::Info("%s", msg.c_str());
1379     }
1380   }
1381   else if((pos = line.find(olkey::getValue)) != std::string::npos) {
1382     outfile << resolveGetVal(line) << std::endl;
1383   }
1384   else if((pos = line.find(olkey::label)) != std::string::npos) {
1385     OLMsg::Error("Unidentified onelab command in <%s>", line.c_str());
1386   }
1387   else {
1388     outfile << line << std::endl;
1389   }
1390 }
1391 
preProcess(const std::string & client,const std::string & fullName)1392 void preProcess(const std::string &client, const std::string &fullName)
1393 {
1394   std::vector<std::string> split = SplitOLFileName(fullName);
1395   std::string ifileName = split[1] + split[2]; // remove heading "_" if any
1396   std::string ofileName = split[0] + split[1]; // remove trailing ".ol"
1397 
1398   std::string workDir = SplitFileName(split[1])[0];
1399   localSolverClient *c = new InterfacedClient(client, "", workDir);
1400 
1401   std::ifstream infile(ifileName.c_str());
1402   if(infile.is_open()) {
1403     std::ofstream outfile(ofileName.c_str());
1404     if(outfile.is_open()) {
1405       OLMsg::Info("Preprocess file <%s> into <%s>", ifileName.c_str(),
1406                   ofileName.c_str());
1407       while(infile.good()) {
1408         std::string line;
1409         getline(infile, line);
1410         c->convert_oneline(line, infile, outfile);
1411       }
1412       outfile.close();
1413     }
1414     else
1415       OLMsg::Error("The file <%s> cannot be opened", ofileName.c_str());
1416     infile.close();
1417   }
1418   else
1419     OLMsg::Error("The file <%s> cannot be opened", ifileName.c_str());
1420   delete c;
1421 }
1422 
convert_onefile(std::string fileName,std::ofstream & outfile)1423 void localSolverClient::convert_onefile(std::string fileName,
1424                                         std::ofstream &outfile)
1425 {
1426   std::ifstream infile(fileName.c_str());
1427   if(infile.is_open()) {
1428     OLMsg::Info("Convert file <%s>", fileName.c_str());
1429     while(infile.good()) {
1430       std::string line;
1431       getline(infile, line);
1432       convert_oneline(line, infile, outfile);
1433     }
1434     infile.close();
1435   }
1436   else
1437     OLMsg::Error("The file <%s> cannot be opened", fileName.c_str());
1438 }
1439 
client_sentence(const std::string & name,const std::string & action,const std::vector<std::string> & arguments)1440 void localSolverClient::client_sentence(
1441   const std::string &name, const std::string &action,
1442   const std::vector<std::string> &arguments)
1443 {
1444   OLMsg::Error("The action <%s> is unknown in this context", action.c_str());
1445 }
1446 
client_sentence(const std::string & name,const std::string & action,const std::vector<std::string> & arguments)1447 void MetaModel::client_sentence(const std::string &name,
1448                                 const std::string &action,
1449                                 const std::vector<std::string> &arguments)
1450 {
1451   std::vector<onelab::string> strings;
1452 
1453   if(!action.compare("register")) {
1454     if(isTodo(REGISTER)) {
1455       std::string type = "", cmdl = "", host = "", rdir = "";
1456       // syntax name.register([interf...|native]{,cmdl}) ;
1457       if(!findClientByName(name)) {
1458         OLMsg::Info("Define client <%s>", name.c_str());
1459         if(arguments.size() >= 1) type.assign(resolveGetVal(arguments[0]));
1460         if(arguments.size() >= 2) cmdl.assign(resolveGetVal(arguments[1]));
1461         if(arguments.size() >= 3)
1462           OLMsg::Warning("Unused arguments for client <%s>", name.c_str());
1463 
1464         // if argument 'cmdl' is empty,
1465         // 1. look on server for one remote host cmdl
1466         //    defined by a previous .remote() sentence
1467         // 2. look in the .save file for a local host cmdl
1468         // 3. create an empty parameter restore control to the GUI
1469 
1470         host = OLMsg::GetOnelabString(name + "/HostName");
1471         rdir = OLMsg::GetOnelabString(name + "/RemoteDir");
1472         if(cmdl.empty()) cmdl = OLMsg::GetOnelabString(name + "/CommandLine");
1473 
1474         if(cmdl.empty()) {
1475           host = "localhost";
1476           if(findCommandLine(name, host))
1477             cmdl = OLMsg::GetOnelabString(name + "/CommandLine");
1478         }
1479         if(cmdl.empty()) {
1480           if(OLMsg::hasGmsh) {
1481             onelab::string str;
1482             str.setName(name + "/CommandLine");
1483             str.setKind("file");
1484             str.setVisible(true);
1485             str.setAttribute("Highlight", "Ivory");
1486             set(str);
1487             OLMsg::Error("No commandline found for client <%s>", name.c_str());
1488           }
1489           else { // asks the user in console mode
1490             std::cout << "\nONELAB: Enter pathname of the executable file for <"
1491                       << name << ">" << std::endl;
1492             std::getline(std::cin, cmdl);
1493             OLMsg::SetOnelabString(name + "/CommandLine", cmdl);
1494           }
1495         }
1496         registerClient(name, type, cmdl, host, rdir);
1497       }
1498       else
1499         OLMsg::Error("Redefinition of client <%s>", name.c_str());
1500     }
1501   }
1502   else if(!action.compare("remote") || !action.compare("hostname")) {
1503     if(isTodo(REGISTER)) {
1504       std::string host = "", rdir = "";
1505       if(arguments.size() >= 1) host.assign(resolveGetVal(arguments[0]));
1506       if(arguments.size() >= 2) rdir.assign(resolveGetVal(arguments[1]));
1507       if(arguments.size() >= 3)
1508         OLMsg::Warning("Unused arguments for client <%s>", name.c_str());
1509 
1510       if(host.size()) {
1511         OLMsg::SetOnelabString(name + "/HostName", host, false);
1512         if(rdir.size())
1513           OLMsg::SetOnelabString(name + "/RemoteDir", rdir, false);
1514       }
1515       else {
1516         std::string in = OLMsg::GetOnelabString(name + "/HostName");
1517         if(in.size()) {
1518           std::vector<std::string> split = SplitOLHostName(in);
1519           host = split[0];
1520           rdir = split[1];
1521           OLMsg::SetOnelabString(name + "/HostName", host, false);
1522           if(rdir.size())
1523             OLMsg::SetOnelabString(name + "/RemoteDir", rdir, false);
1524         }
1525         if(!findCommandLine(name, host)) {
1526           if(OLMsg::hasGmsh) {
1527             onelab::string str;
1528             str.setName(name + "/HostName");
1529             str.setVisible(true);
1530             str.setAttribute("Highlight", "Ivory");
1531             set(str);
1532             OLMsg::Error("No hostname found for remote client <%s>",
1533                          name.c_str());
1534           }
1535           else { // asks the user in console mode
1536             std::cout << "\nONELAB: Enter remote host for <" << name
1537                       << "> (name@host:dir)" << std::endl;
1538             std::string in;
1539             std::getline(std::cin, in);
1540             if(in.size()) {
1541               std::vector<std::string> split = SplitOLHostName(in);
1542               OLMsg::SetOnelabString(name + "/HostName", split[0], false);
1543               if(split[1].size())
1544                 OLMsg::SetOnelabString(name + "/RemoteDir", split[1], false);
1545             }
1546           }
1547         }
1548       }
1549     }
1550   }
1551   else if(!action.compare("workingSubdir")) {
1552     localSolverClient *c;
1553     if((c = findClientByName(name)))
1554       c->setWorkingDir(c->getWorkingDir() + arguments[0]);
1555     else
1556       OLMsg::Error("Unknown client <%s>", name.c_str());
1557   }
1558   else if(!action.compare("active")) {
1559     localSolverClient *c;
1560     if(arguments[0].size()) {
1561       if((c = findClientByName(name))) {
1562         c->setActive(atof(resolveGetVal(arguments[0]).c_str()));
1563         // onelab::server::instance()->setChanged(true, c->getName());
1564       }
1565       else
1566         OLMsg::Error("Unknown client <%s>", name.c_str());
1567     }
1568     else
1569       OLMsg::Error("No argument for <%s.Active> statement", name.c_str());
1570   }
1571   else if(!action.compare("in")) {
1572     if(isTodo(REGISTER)) {
1573       get(strings, name + "/InputFiles");
1574       if(strings.empty()) {
1575         strings.resize(1);
1576         strings[0].setName(name + "/InputFiles");
1577       }
1578       strings[0].setKind("file");
1579       strings[0].setVisible(false);
1580       std::vector<std::string> choices;
1581       if(arguments[0].size()) {
1582         for(unsigned int i = 0; i < arguments.size(); i++) {
1583           std::string fileName = resolveGetVal(arguments[i]);
1584           if(std::find(choices.begin(), choices.end(), fileName) ==
1585              choices.end())
1586             choices.push_back(fileName);
1587         }
1588         strings[0].setValue(resolveGetVal(arguments[0]));
1589       }
1590       strings[0].setChoices(choices);
1591       set(strings[0]);
1592     }
1593   }
1594   else if(!action.compare("out")) {
1595     if(isTodo(REGISTER)) {
1596       get(strings, name + "/OutputFiles");
1597       if(strings.empty()) {
1598         strings.resize(1);
1599         strings[0].setName(name + "/OutputFiles");
1600       }
1601       strings[0].setKind("file");
1602       strings[0].setVisible(false);
1603       std::vector<std::string> choices;
1604       if(arguments[0].size()) {
1605         for(unsigned int i = 0; i < arguments.size(); i++) {
1606           std::string fileName = resolveGetVal(arguments[i]);
1607           if(std::find(choices.begin(), choices.end(), fileName) ==
1608              choices.end())
1609             choices.push_back(fileName);
1610         }
1611         strings[0].setValue(resolveGetVal(arguments[0]));
1612       }
1613       strings[0].setChoices(choices);
1614       set(strings[0]);
1615     }
1616   }
1617   else if(!action.compare("run")) {
1618     if(isTodo(REGISTER)) {
1619       if(arguments[0].size()) {
1620         get(strings, name + "/Arguments");
1621         if(strings.empty()) {
1622           strings.resize(1);
1623           strings[0].setName(name + "/Arguments");
1624         }
1625         strings[0].setValue(resolveGetVal(arguments[0]));
1626         strings[0].setVisible(false);
1627         set(strings[0]);
1628       }
1629       if(!OLMsg::GetErrorCount()) {
1630         localSolverClient *c;
1631         if((c = findClientByName(name)))
1632           if(c->checkCommandLine()) c->analyze();
1633       }
1634     }
1635     else if(isTodo(ANALYZE)) {
1636       localSolverClient *c;
1637       if((c = findClientByName(name))) c->analyze();
1638     }
1639     else if(isTodo(COMPUTE)) {
1640       localSolverClient *c;
1641       if((c = findClientByName(name))) {
1642         // onelab::server::instance()->setChanged(false, getName());
1643         bool changed = onelab::server::instance()->getChanged(c->getName());
1644         bool started = isStarted(changed);
1645 
1646         // if(OLMsg::GetVerbosity())
1647         //   std::cout << c->getName() << " active="
1648         // 	    << c->getActive() << " changed="
1649         // 	    << changed << " started="
1650         // 	    << started << " errors=" << OLMsg::GetErrorCount() << std::endl;
1651         if(c->getActive() || started) c->compute();
1652       }
1653     }
1654   }
1655   else if(!action.compare("up")) {
1656     if(arguments.size() % 4 == 0) {
1657       if(isTodo(REGISTER)) {}
1658       else if(isTodo(COMPUTE) && !OLMsg::GetErrorCount()) {
1659         std::vector<std::string> choices;
1660         for(unsigned int i = 0; i < arguments.size(); i++) {
1661           std::string str = resolveGetVal(arguments[i]);
1662           OLMsg::recordFullName(str);
1663           choices.push_back(str);
1664         }
1665         localSolverClient *c;
1666         if((c = findClientByName(name))) c->PostArray(choices);
1667       }
1668     }
1669     else
1670       OLMsg::Error("Wrong number of arguments <%d> for <%s>", arguments.size(),
1671                    action.c_str());
1672   }
1673   else if(!action.compare("alwaysCompute") || !action.compare("preCompute")) {
1674     if(isTodo(REGISTER)) {
1675       localSolverClient *c;
1676       if((c = findClientByName(name))) {
1677         c->compute();
1678         // onelab::server::instance()->setChanged(false, c->getName());
1679       }
1680       else
1681         OLMsg::Error("Unknown client <%s>", name.c_str());
1682     }
1683   }
1684   else if(!action.compare("merge")) {
1685     if(arguments.size() && isTodo(COMPUTE) && !OLMsg::GetErrorCount() &&
1686        (OLMsg::hasGmsh)) {
1687       std::vector<std::string> choices;
1688       for(unsigned int i = 0; i < arguments.size(); i++) {
1689         choices.push_back(resolveGetVal(arguments[i]));
1690       }
1691       localSolverClient *c;
1692       if((c = findClientByName(name))) {
1693         c->GmshMerge(choices);
1694         OLMsg::SetOnelabNumber("Gmsh/NeedReloadGeom", 1, false);
1695       }
1696       else
1697         OLMsg::Error("Unknown client <%s>", name.c_str());
1698     }
1699   }
1700   else if(!action.compare("frontPage")) {
1701     if(isTodo(REGISTER) && OLMsg::hasGmsh && arguments.size() &&
1702        !OLMsg::GetErrorCount()) {
1703       std::vector<std::string> choices;
1704       for(unsigned int i = 0; i < arguments.size(); i++) {
1705         choices.push_back(resolveGetVal(arguments[i]));
1706       }
1707       localSolverClient *c;
1708       if((c = findClientByName(name))) {
1709         c->GmshMerge(choices);
1710         OLMsg::SetOnelabNumber("Gmsh/NeedReloadGeom", 1, false);
1711       }
1712       else
1713         OLMsg::Error("Unknown client <%s>", name.c_str());
1714     }
1715   }
1716   else if(!action.compare("clientStatus")) {
1717     showClientStatus();
1718   }
1719   else
1720     OLMsg::Error("Unknown action <%s>", action.c_str());
1721 }
1722