argList.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | Copyright (C) 2011-2015 OpenFOAM Foundation
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
11  OpenFOAM is free software: you can redistribute it and/or modify it
12  under the terms of the GNU General Public License as published by
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
16  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19  for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
23 
24 \*---------------------------------------------------------------------------*/
25 
26 #include "argList.H"
27 #include "OSspecific.H"
28 #include "clock.H"
29 #include "IFstream.H"
30 #include "dictionary.H"
31 #include "IOobject.H"
32 #include "JobInfo.H"
33 #include "labelList.H"
34 #include "regIOobject.H"
35 #include "dynamicCode.H"
36 
37 #include <cctype>
38 
39 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
40 
41 bool Foam::argList::bannerEnabled = true;
49 
50 
51 Foam::argList::initValidTables::initValidTables()
52 {
53  argList::addOption
54  (
55  "case", "dir",
56  "specify alternate case directory, default is the cwd"
57  );
58  argList::addBoolOption("parallel", "run in parallel");
59  validParOptions.set("parallel", "");
60  argList::addOption
61  (
62  "roots", "(dir1 .. dirN)",
63  "slave root directories for distributed running"
64  );
65  validParOptions.set("roots", "(dir1 .. dirN)");
66 
67  argList::addBoolOption
68  (
69  "noFunctionObjects",
70  "do not execute functionObjects"
71  );
72 
73  Pstream::addValidParOptions(validParOptions);
74 }
75 
76 
77 Foam::argList::initValidTables dummyInitValidTables;
78 
79 
80 // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
81 
83 (
84  const word& opt,
85  const string& usage
86 )
87 {
88  addOption(opt, "", usage);
89 }
90 
91 
93 (
94  const word& opt,
95  const string& param,
96  const string& usage
97 )
98 {
99  validOptions.set(opt, param);
100  if (!usage.empty())
101  {
102  optionUsage.set(opt, usage);
103  }
104 }
105 
106 
108 (
109  const word& opt,
110  const string& usage
111 )
112 {
113  if (usage.empty())
114  {
115  optionUsage.erase(opt);
116  }
117  else
118  {
119  optionUsage.set(opt, usage);
120  }
121 }
122 
123 
124 void Foam::argList::addNote(const string& note)
125 {
126  if (!note.empty())
127  {
128  notes.append(note);
129  }
130 }
131 
132 
134 {
135  validOptions.erase(opt);
136  optionUsage.erase(opt);
137 }
138 
139 
141 {
142  bannerEnabled = false;
143 }
144 
145 
147 {
148  removeOption("parallel");
149  removeOption("roots");
150  validParOptions.clear();
151 }
152 
153 
154 void Foam::argList::printOptionUsage
155 (
156  const label location,
157  const string& str
158 )
159 {
160  const string::size_type textWidth = usageMax - usageMin;
161  const string::size_type strLen = str.size();
162 
163  if (strLen)
164  {
165  // minimum of 2 spaces between option and usage:
166  if (string::size_type(location) + 2 <= usageMin)
167  {
168  for (string::size_type i = location; i < usageMin; ++i)
169  {
170  Info<<' ';
171  }
172  }
173  else
174  {
175  // or start a new line
176  Info<< nl;
177  for (string::size_type i = 0; i < usageMin; ++i)
178  {
179  Info<<' ';
180  }
181  }
182 
183  // text wrap
185  while (pos != string::npos && pos + textWidth < strLen)
186  {
187  // potential end point and next point
188  string::size_type curr = pos + textWidth - 1;
189  string::size_type next = string::npos;
190 
191  if (isspace(str[curr]))
192  {
193  // we were lucky: ended on a space
194  next = str.find_first_not_of(" \t\n", curr);
195  }
196  else if (isspace(str[curr+1]))
197  {
198  // the next one is a space - so we are okay
199  curr++; // otherwise the length is wrong
200  next = str.find_first_not_of(" \t\n", curr);
201  }
202  else
203  {
204  // search for end of a previous word break
205  string::size_type prev = str.find_last_of(" \t\n", curr);
206 
207  // reposition to the end of previous word if possible
208  if (prev != string::npos && prev > pos)
209  {
210  curr = prev;
211  }
212  }
213 
214  if (next == string::npos)
215  {
216  next = curr + 1;
217  }
218 
219  // indent following lines (not the first one)
220  if (pos)
221  {
222  for (string::size_type i = 0; i < usageMin; ++i)
223  {
224  Info<<' ';
225  }
226  }
227 
228  Info<< str.substr(pos, (curr - pos)).c_str() << nl;
229  pos = next;
230  }
231 
232  // output the remainder of the string
233  if (pos != string::npos)
234  {
235  // indent following lines (not the first one)
236  if (pos)
237  {
238  for (string::size_type i = 0; i < usageMin; ++i)
239  {
240  Info<<' ';
241  }
242  }
243 
244  Info<< str.substr(pos).c_str() << nl;
245  }
246  }
247  else
248  {
249  Info<< nl;
250  }
251 }
252 
253 
254 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
255 
256 // convert argv -> args_
257 // transform sequences with "(" ... ")" into string lists in the process
258 bool Foam::argList::regroupArgv(int& argc, char**& argv)
259 {
260  int nArgs = 0;
261  int listDepth = 0;
262  string tmpString;
263 
264  // note: we also re-write directly into args_
265  // and use a second pass to sort out args/options
266  for (int argI = 0; argI < argc; ++argI)
267  {
268  if (strcmp(argv[argI], "(") == 0)
269  {
270  ++listDepth;
271  tmpString += "(";
272  }
273  else if (strcmp(argv[argI], ")") == 0)
274  {
275  if (listDepth)
276  {
277  --listDepth;
278  tmpString += ")";
279  if (listDepth == 0)
280  {
281  args_[nArgs++] = tmpString;
282  tmpString.clear();
283  }
284  }
285  else
286  {
287  args_[nArgs++] = argv[argI];
288  }
289  }
290  else if (listDepth)
291  {
292  // quote each string element
293  tmpString += "\"";
294  tmpString += argv[argI];
295  tmpString += "\"";
296  }
297  else
298  {
299  args_[nArgs++] = argv[argI];
300  }
301  }
302 
303  if (tmpString.size())
304  {
305  args_[nArgs++] = tmpString;
306  }
307 
308  args_.setSize(nArgs);
309 
310  return nArgs < argc;
311 }
312 
313 
314 void Foam::argList::getRootCase()
315 {
316  fileName casePath;
317 
318  // [-case dir] specified
319  HashTable<string>::const_iterator iter = options_.find("case");
320 
321  if (iter != options_.end())
322  {
323  casePath = iter();
324  casePath.clean();
325 
326  if (casePath.empty() || casePath == ".")
327  {
328  // handle degenerate form and '-case .' like no -case specified
329  casePath = cwd();
330  options_.erase("case");
331  }
332  else if (!casePath.isAbsolute() && casePath.name() == "..")
333  {
334  // avoid relative cases ending in '..' - makes for very ugly names
335  casePath = cwd()/casePath;
336  casePath.clean();
337  }
338  }
339  else
340  {
341  // nothing specified, use the current dir
342  casePath = cwd();
343  }
344 
345  rootPath_ = casePath.path();
346  globalCase_ = casePath.name();
347  case_ = globalCase_;
348 
349 
350  // Set the case and case-name as an environment variable
351  if (rootPath_.isAbsolute())
352  {
353  // absolute path - use as-is
354  setEnv("FOAM_CASE", rootPath_/globalCase_, true);
355  setEnv("FOAM_CASENAME", globalCase_, true);
356  }
357  else
358  {
359  // qualify relative path
360  casePath = cwd()/rootPath_/globalCase_;
361  casePath.clean();
362 
363  setEnv("FOAM_CASE", casePath, true);
364  setEnv("FOAM_CASENAME", casePath.name(), true);
365  }
366 }
367 
368 
369 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
370 
372 (
373  int& argc,
374  char**& argv,
375  bool checkArgs,
376  bool checkOpts,
377  const bool initialise
378 )
379 :
380  args_(argc),
381  options_(argc)
382 {
383  // Check if this run is a parallel run by searching for any parallel option
384  // If found call runPar which might filter argv
385  for (int argI = 0; argI < argc; ++argI)
386  {
387  if (argv[argI][0] == '-')
388  {
389  const char *optionName = &argv[argI][1];
390 
391  if (validParOptions.found(optionName))
392  {
393  parRunControl_.runPar(argc, argv);
394  break;
395  }
396  }
397  }
398 
399  // convert argv -> args_ and capture ( ... ) lists
400  // for normal arguments and for options
401  regroupArgv(argc, argv);
402 
403  // Get executable name
404  args_[0] = fileName(argv[0]);
405  executable_ = fileName(argv[0]).name();
406 
407  // Check arguments and options, we already have argv[0]
408  int nArgs = 1;
409  argListStr_ = args_[0];
410 
411  for (int argI = 1; argI < args_.size(); ++argI)
412  {
413  argListStr_ += ' ';
414  argListStr_ += args_[argI];
415 
416  if (args_[argI][0] == '-')
417  {
418  const char *optionName = &args_[argI][1];
419 
420  if
421  (
422  (
423  validOptions.found(optionName)
424  && !validOptions[optionName].empty()
425  )
426  || (
427  validParOptions.found(optionName)
428  && !validParOptions[optionName].empty()
429  )
430  )
431  {
432  ++argI;
433  if (argI >= args_.size())
434  {
435  FatalError
436  <<"Option '-" << optionName
437  << "' requires an argument" << endl;
438  printUsage();
439  FatalError.exit();
440  }
441 
442  argListStr_ += ' ';
443  argListStr_ += args_[argI];
444  options_.insert(optionName, args_[argI]);
445  }
446  else
447  {
448  options_.insert(optionName, "");
449  }
450  }
451  else
452  {
453  if (nArgs != argI)
454  {
455  args_[nArgs] = args_[argI];
456  }
457  ++nArgs;
458  }
459  }
460 
461  args_.setSize(nArgs);
462 
463  parse(checkArgs, checkOpts, initialise);
464 }
465 
466 
468 (
469  const argList& args,
470  const HashTable<string>& options,
471  bool checkArgs,
472  bool checkOpts,
473  bool initialise
474 )
475 :
476  parRunControl_(args.parRunControl_),
477  args_(args.args_),
478  options_(options),
479  executable_(args.executable_),
480  rootPath_(args.rootPath_),
481  globalCase_(args.globalCase_),
482  case_(args.case_),
483  argListStr_(args.argListStr_)
484 {
485  parse(checkArgs, checkOpts, initialise);
486 }
487 
488 
490 (
491  bool checkArgs,
492  bool checkOpts,
493  bool initialise
494 )
495 {
496  // Help/documentation options:
497  // -help print the usage
498  // -doc display application documentation in browser
499  // -srcDoc display source code in browser
500  if
501  (
502  options_.found("help")
503  || options_.found("doc")
504  || options_.found("srcDoc")
505  )
506  {
507  if (options_.found("help"))
508  {
509  printUsage();
510  }
511 
512  // only display one or the other
513  if (options_.found("srcDoc"))
514  {
515  displayDoc(true);
516  }
517  else if (options_.found("doc"))
518  {
519  displayDoc(false);
520  }
521 
522  ::exit(0);
523  }
524 
525  // Print the usage message and exit if the number of arguments is incorrect
526  if (!check(checkArgs, checkOpts))
527  {
528  FatalError.exit();
529  }
530 
531 
532  if (initialise)
533  {
534  string dateString = clock::date();
535  string timeString = clock::clockTime();
536 
537  // Print the banner once only for parallel runs
538  if (Pstream::master() && bannerEnabled)
539  {
541  << "Build : " << Foam::FOAMbuild << nl
542  << "Exec : " << argListStr_.c_str() << nl
543  << "Date : " << dateString.c_str() << nl
544  << "Time : " << timeString.c_str() << nl
545  << "Host : " << hostName() << nl
546  << "PID : " << pid() << endl;
547  }
548 
549  jobInfo.add("startDate", dateString);
550  jobInfo.add("startTime", timeString);
551  jobInfo.add("userName", userName());
552  jobInfo.add("foamVersion", word(FOAMversion));
553  jobInfo.add("code", executable_);
554  jobInfo.add("argList", argListStr_);
555  jobInfo.add("currentDir", cwd());
556  jobInfo.add("PPID", ppid());
557  jobInfo.add("PGID", pgid());
558 
559  // add build information - only use the first word
560  {
561  std::string build(Foam::FOAMbuild);
562  std::string::size_type found = build.find(' ');
563  if (found != std::string::npos)
564  {
565  build.resize(found);
566  }
567  jobInfo.add("foamBuild", build);
568  }
569  }
570 
571  // Case is a single processor run unless it is running parallel
572  int nProcs = 1;
573 
574  // Roots if running distributed
575  fileNameList roots;
576 
577 
578  // If this actually is a parallel run
579  if (parRunControl_.parRun())
580  {
581  // For the master
582  if (Pstream::master())
583  {
584  // establish rootPath_/globalCase_/case_ for master
585  getRootCase();
586 
587  // See if running distributed (different roots for different procs)
588  label dictNProcs = -1;
589  fileName source;
590 
591  if (options_.found("roots"))
592  {
593  source = "-roots";
594  IStringStream is(options_["roots"]);
595  roots = readList<fileName>(is);
596 
597  if (roots.size() != 1)
598  {
599  dictNProcs = roots.size()+1;
600  }
601  }
602  else
603  {
604  source = rootPath_/globalCase_/"system/decomposeParDict";
605  IFstream decompDictStream(source);
606 
607  if (!decompDictStream.good())
608  {
609  FatalError
610  << "Cannot read "
611  << decompDictStream.name()
612  << exit(FatalError);
613  }
614 
615  dictionary decompDict(decompDictStream);
616 
617  dictNProcs = readLabel
618  (
619  decompDict.lookup("numberOfSubdomains")
620  );
621 
622  if (decompDict.lookupOrDefault("distributed", false))
623  {
624  decompDict.lookup("roots") >> roots;
625  }
626  }
627 
628  // convenience:
629  // when a single root is specified, use it for all processes
630  if (roots.size() == 1)
631  {
632  const fileName rootName(roots[0]);
633  roots.setSize(Pstream::nProcs()-1, rootName);
634 
635  // adjust dictNProcs for command-line '-roots' option
636  if (dictNProcs < 0)
637  {
638  dictNProcs = roots.size()+1;
639  }
640  }
641 
642 
643  // Check number of processors.
644  // nProcs => number of actual procs
645  // dictNProcs => number of procs specified in decompositionDict
646  // nProcDirs => number of processor directories
647  // (n/a when running distributed)
648  //
649  // - normal running : nProcs = dictNProcs = nProcDirs
650  // - decomposition to more processors : nProcs = dictNProcs
651  // - decomposition to fewer processors : nProcs = nProcDirs
652  if (dictNProcs > Pstream::nProcs())
653  {
654  FatalError
655  << source
656  << " specifies " << dictNProcs
657  << " processors but job was started with "
658  << Pstream::nProcs() << " processors."
659  << exit(FatalError);
660  }
661 
662 
663  // distributed data
664  if (roots.size())
665  {
666  if (roots.size() != Pstream::nProcs()-1)
667  {
668  FatalError
669  << "number of entries in roots "
670  << roots.size()
671  << " is not equal to the number of slaves "
672  << Pstream::nProcs()-1
673  << exit(FatalError);
674  }
675 
676  forAll(roots, i)
677  {
678  roots[i].expand();
679  }
680 
681  // Distribute the master's argument list (with new root)
682  bool hadCaseOpt = options_.found("case");
683  for
684  (
685  int slave = Pstream::firstSlave();
686  slave <= Pstream::lastSlave();
687  slave++
688  )
689  {
690  options_.set("case", roots[slave-1]/globalCase_);
691 
692  OPstream toSlave(Pstream::scheduled, slave);
693  toSlave << args_ << options_;
694  }
695  options_.erase("case");
696 
697  // restore [-case dir]
698  if (hadCaseOpt)
699  {
700  options_.set("case", rootPath_/globalCase_);
701  }
702  }
703  else
704  {
705  // Possibly going to fewer processors.
706  // Check if all procDirs are there.
707  if (dictNProcs < Pstream::nProcs())
708  {
709  label nProcDirs = 0;
710  while
711  (
712  isDir
713  (
714  rootPath_/globalCase_/"processor"
715  + name(++nProcDirs)
716  )
717  )
718  {}
719 
720  if (nProcDirs != Pstream::nProcs())
721  {
722  FatalError
723  << "number of processor directories = "
724  << nProcDirs
725  << " is not equal to the number of processors = "
726  << Pstream::nProcs()
727  << exit(FatalError);
728  }
729  }
730 
731  // Distribute the master's argument list (unaltered)
732  for
733  (
734  int slave = Pstream::firstSlave();
735  slave <= Pstream::lastSlave();
736  slave++
737  )
738  {
739  OPstream toSlave(Pstream::scheduled, slave);
740  toSlave << args_ << options_;
741  }
742  }
743  }
744  else
745  {
746  // Collect the master's argument list
748  fromMaster >> args_ >> options_;
749 
750  // establish rootPath_/globalCase_/case_ for slave
751  getRootCase();
752  }
753 
754  nProcs = Pstream::nProcs();
755  case_ = globalCase_/(word("processor") + name(Pstream::myProcNo()));
756  }
757  else
758  {
759  // establish rootPath_/globalCase_/case_
760  getRootCase();
761  case_ = globalCase_;
762  }
763 
764 
765  stringList slaveProcs;
766 
767  // collect slave machine/pid
768  if (parRunControl_.parRun())
769  {
770  if (Pstream::master())
771  {
772  slaveProcs.setSize(Pstream::nProcs() - 1);
773  string slaveMachine;
774  label slavePid;
775 
776  label procI = 0;
777  for
778  (
779  int slave = Pstream::firstSlave();
780  slave <= Pstream::lastSlave();
781  slave++
782  )
783  {
784  IPstream fromSlave(Pstream::scheduled, slave);
785  fromSlave >> slaveMachine >> slavePid;
786 
787  slaveProcs[procI++] = slaveMachine + "." + name(slavePid);
788  }
789  }
790  else
791  {
793  toMaster << hostName() << pid();
794  }
795  }
796 
797 
798  if (Pstream::master() && bannerEnabled)
799  {
800  Info<< "Case : " << (rootPath_/globalCase_).c_str() << nl
801  << "nProcs : " << nProcs << endl;
802 
803  if (parRunControl_.parRun())
804  {
805  Info<< "Slaves : " << slaveProcs << nl;
806  if (roots.size())
807  {
808  Info<< "Roots : " << roots << nl;
809  }
810  Info<< "Pstream initialized with:" << nl
811  << " floatTransfer : " << Pstream::floatTransfer << nl
812  << " nProcsSimpleSum : " << Pstream::nProcsSimpleSum << nl
813  << " commsType : "
815  << " polling iterations : " << Pstream::nPollProcInterfaces
816  << endl;
817  }
818  }
819 
820  if (initialise)
821  {
822  jobInfo.add("root", rootPath_);
823  jobInfo.add("case", globalCase_);
824  jobInfo.add("nProcs", nProcs);
825  if (slaveProcs.size())
826  {
827  jobInfo.add("slaves", slaveProcs);
828  }
829  if (roots.size())
830  {
831  jobInfo.add("roots", roots);
832  }
833  jobInfo.write();
834 
835  // Switch on signal trapping. We have to wait until after Pstream::init
836  // since this sets up its own ones.
837  sigFpe_.set(bannerEnabled);
838  sigInt_.set(bannerEnabled);
839  sigQuit_.set(bannerEnabled);
840  sigSegv_.set(bannerEnabled);
841 
842  if (bannerEnabled)
843  {
844  Info<< "fileModificationChecking : "
845  << "Monitoring run-time modified files using "
847  [
849  ]
850  << endl;
851 
852  Info<< "allowSystemOperations : ";
854  {
855  Info<< "Allowing user-supplied system call operations" << endl;
856  }
857  else
858  {
859  Info<< "Disallowing user-supplied system call operations"
860  << endl;
861  }
862  }
863 
864  if (Pstream::master() && bannerEnabled)
865  {
866  Info<< endl;
868  }
869  }
870 }
871 
872 
873 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
874 
876 {
877  jobInfo.end();
878 }
879 
880 
881 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
882 
883 bool Foam::argList::setOption(const word& opt, const string& param)
884 {
885  bool changed = false;
886 
887  // only allow valid options
888  if (validOptions.found(opt))
889  {
890  // some options are to be protected
891  if
892  (
893  opt == "case"
894  || opt == "parallel"
895  || opt == "roots"
896  )
897  {
898  FatalError
899  <<"used argList::setOption on a protected option: '"
900  << opt << "'" << endl;
901  FatalError.exit();
902  }
903 
904  if (validOptions[opt].empty())
905  {
906  // bool option
907  if (!param.empty())
908  {
909  // disallow change of type
910  FatalError
911  <<"used argList::setOption to change bool to non-bool: '"
912  << opt << "'" << endl;
913  FatalError.exit();
914  }
915  else
916  {
917  // did not previously exist
918  changed = !options_.found(opt);
919  }
920  }
921  else
922  {
923  // non-bool option
924  if (param.empty())
925  {
926  // disallow change of type
927  FatalError
928  <<"used argList::setOption to change non-bool to bool: '"
929  << opt << "'" << endl;
930  FatalError.exit();
931  }
932  else
933  {
934  // existing value needs changing, or did not previously exist
935  changed = options_.found(opt) ? options_[opt] != param : true;
936  }
937  }
938  }
939  else
940  {
941  FatalError
942  <<"used argList::setOption on an invalid option: '"
943  << opt << "'" << nl << "allowed are the following:"
944  << validOptions << endl;
945  FatalError.exit();
946  }
947 
948  // set/change the option as required
949  if (changed)
950  {
951  options_.set(opt, param);
952  }
953 
954  return changed;
955 }
956 
957 
959 {
960  // only allow valid options
961  if (validOptions.found(opt))
962  {
963  // some options are to be protected
964  if
965  (
966  opt == "case"
967  || opt == "parallel"
968  || opt == "roots"
969  )
970  {
971  FatalError
972  <<"used argList::unsetOption on a protected option: '"
973  << opt << "'" << endl;
974  FatalError.exit();
975  }
976 
977  // remove the option, return true if state changed
978  return options_.erase(opt);
979  }
980  else
981  {
982  FatalError
983  <<"used argList::unsetOption on an invalid option: '"
984  << opt << "'" << nl << "allowed are the following:"
985  << validOptions << endl;
986  FatalError.exit();
987  }
988 
989  return false;
990 }
991 
992 
994 {
995  // output notes directly - no automatic text wrapping
996  if (!notes.empty())
997  {
998  Info<< nl;
1000  {
1001  Info<< iter().c_str() << nl;
1002  }
1003  }
1004 }
1005 
1006 
1008 {
1009  Info<< "\nUsage: " << executable_ << " [OPTIONS]";
1010 
1012  {
1013  Info<< " <" << iter().c_str() << '>';
1014  }
1015 
1016  Info<< "\noptions:\n";
1017 
1018  wordList opts = validOptions.sortedToc();
1019  forAll(opts, optI)
1020  {
1021  const word& optionName = opts[optI];
1022 
1023  HashTable<string>::const_iterator iter = validOptions.find(optionName);
1024  Info<< " -" << optionName;
1025  label len = optionName.size() + 3; // length includes leading ' -'
1026 
1027  if (iter().size())
1028  {
1029  // length includes space and between option/param and '<>'
1030  len += iter().size() + 3;
1031  Info<< " <" << iter().c_str() << '>';
1032  }
1033 
1035  optionUsage.find(optionName);
1036 
1037  if (usageIter != optionUsage.end())
1038  {
1039  printOptionUsage
1040  (
1041  len,
1042  usageIter()
1043  );
1044  }
1045  else
1046  {
1047  Info<< nl;
1048  }
1049  }
1050 
1051  //
1052  // place srcDoc/doc/help options at the end
1053  //
1054  Info<< " -srcDoc";
1055  printOptionUsage
1056  (
1057  9,
1058  "display source code in browser"
1059  );
1060 
1061  Info<< " -doc";
1062  printOptionUsage
1063  (
1064  6,
1065  "display application documentation in browser"
1066  );
1067 
1068  Info<< " -help";
1069  printOptionUsage
1070  (
1071  7,
1072  "print the usage"
1073  );
1074 
1075 
1076  printNotes();
1077 
1078  Info<< nl
1079  <<"Using: OpenFOAM-" << Foam::FOAMversion
1080  << " (see www.OpenFOAM.org)" << nl
1081  <<"Build: " << Foam::FOAMbuild << nl
1082  << endl;
1083 }
1084 
1085 
1086 void Foam::argList::displayDoc(bool source) const
1087 {
1088  const dictionary& docDict = debug::controlDict().subDict("Documentation");
1089  List<fileName> docDirs(docDict.lookup("doxyDocDirs"));
1090  List<fileName> docExts(docDict.lookup("doxySourceFileExts"));
1091 
1092  // for source code: change foo_8C.html to foo_8C_source.html
1093  if (source)
1094  {
1095  forAll(docExts, extI)
1096  {
1097  docExts[extI].replace(".", "_source.");
1098  }
1099  }
1100 
1101  fileName docFile;
1102  bool found = false;
1103 
1104  forAll(docDirs, dirI)
1105  {
1106  forAll(docExts, extI)
1107  {
1108  docFile = docDirs[dirI]/executable_ + docExts[extI];
1109  docFile.expand();
1110 
1111  if (isFile(docFile))
1112  {
1113  found = true;
1114  break;
1115  }
1116  }
1117  if (found)
1118  {
1119  break;
1120  }
1121  }
1122 
1123  if (found)
1124  {
1125  string docBrowser = getEnv("FOAM_DOC_BROWSER");
1126  if (docBrowser.empty())
1127  {
1128  docDict.lookup("docBrowser") >> docBrowser;
1129  }
1130  // can use FOAM_DOC_BROWSER='application file://%f' if required
1131  docBrowser.replaceAll("%f", docFile);
1132 
1133  Info<< "Show documentation: " << docBrowser.c_str() << endl;
1134 
1135  system(docBrowser);
1136  }
1137  else
1138  {
1139  Info<< nl
1140  << "No documentation found for " << executable_
1141  << ", but you can use -help to display the usage\n" << endl;
1142  }
1143 }
1144 
1145 
1146 bool Foam::argList::check(bool checkArgs, bool checkOpts) const
1147 {
1148  bool ok = true;
1149 
1150  if (Pstream::master())
1151  {
1152  if (checkArgs && args_.size() - 1 != validArgs.size())
1153  {
1154  FatalError
1155  << "Wrong number of arguments, expected " << validArgs.size()
1156  << " found " << args_.size() - 1 << endl;
1157  ok = false;
1158  }
1159 
1160  if (checkOpts)
1161  {
1162  forAllConstIter(HashTable<string>, options_, iter)
1163  {
1164  if
1165  (
1166  !validOptions.found(iter.key())
1167  && !validParOptions.found(iter.key())
1168  )
1169  {
1170  FatalError
1171  << "Invalid option: -" << iter.key() << endl;
1172  ok = false;
1173  }
1174  }
1175  }
1176 
1177  if (!ok)
1178  {
1179  printUsage();
1180  }
1181  }
1182 
1183  return ok;
1184 }
1185 
1186 
1188 {
1189  if (!isDir(rootPath()))
1190  {
1191  FatalError
1192  << executable_
1193  << ": cannot open root directory " << rootPath()
1194  << endl;
1195 
1196  return false;
1197  }
1198 
1199  if (!isDir(path()) && Pstream::master())
1200  {
1201  // Allow slaves on non-existing processor directories, created later
1202  FatalError
1203  << executable_
1204  << ": cannot open case directory " << path()
1205  << endl;
1206 
1207  return false;
1208  }
1209 
1210  return true;
1211 }
1212 
1213 
1214 // ************************************************************************* //
Input from memory buffer stream.
Definition: IStringStream.H:49
static HashTable< string > validOptions
A list of valid options.
Definition: argList.H:157
const fileName & rootPath() const
Return root path.
Definition: argListI.H:36
static void addOption(const word &opt, const string &param="", const string &usage="")
Add to an option to validOptions with usage information.
Definition: argList.C:93
word name() const
Return file name (part beyond last /)
Definition: fileName.C:206
bool clean()
Cleanup file name.
Definition: fileName.C:91
const fileName & name() const
Return the name of the stream.
Definition: IFstream.H:116
static SLList< string > validArgs
A list of valid (mandatory) arguments.
Definition: argList.H:154
static const NamedEnum< fileCheckTypes, 4 > fileCheckTypesNames
Definition: regIOobject.H:76
fileName cwd()
Return current working directory path name.
Definition: POSIX.C:247
string & expand(const bool allowEmpty=false)
Expand initial tildes and all occurences of environment variables.
Definition: string.C:98
An STL-conforming const_iterator.
Definition: HashTable.H:470
void runPar(int &argc, char **&argv)
Definition: parRun.H:66
word name(const complex &)
Return a string representation of a complex.
Definition: complex.C:47
pid_t ppid()
Return the parent PID of this process.
Definition: POSIX.C:84
void parse(bool checkArgs, bool checkOpts, bool initialise)
Parse.
Definition: argList.C:490
static string date()
Return the current wall-clock date as a string.
Definition: clock.C:77
fileName path() const
Return the path to the caseName.
Definition: argListI.H:60
bool setEnv(const word &name, const std::string &value, const bool overwrite)
Set an environment variable.
Definition: POSIX.C:120
string getEnv(const word &)
Return environment variable of given name.
Definition: POSIX.C:102
Functions used by OpenFOAM that are specific to POSIX compliant operating systems and need to be repl...
dictionary & controlDict()
The central control dictionary.
Definition: debug.C:90
A class for handling words, derived from string.
Definition: word.H:59
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:59
bool checkRootCase() const
Check root path and case path.
Definition: argList.C:1187
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:76
void printUsage() const
Print usage.
Definition: argList.C:1007
static void removeOption(const word &opt)
Remove option from validOptions and from optionUsage.
Definition: argList.C:133
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
Output inter-processor communications stream.
Definition: OPstream.H:50
const char *const FOAMversion
messageStream Info
static string clockTime()
Return the current wall-clock time as a string.
Definition: clock.C:93
fileName path() const
Return directory path name (part before last /)
Definition: fileName.C:287
void displayDoc(bool source=false) const
Display documentation in browser.
Definition: argList.C:1086
void set(const bool verbose)
Activate SIGFPE signal handler when FOAM_SIGFPE is set.
Definition: sigFpe.C:152
A list of keyword definitions, which are a keyword followed by any number of values (e...
Definition: dictionary.H:137
const dictionary & subDict(const word &) const
Find and return a sub-dictionary.
Definition: dictionary.C:638
static HashTable< string > validParOptions
A list of valid parallel options.
Definition: argList.H:160
Input from file stream.
Definition: IFstream.H:81
static bool floatTransfer
Should compact transfer be used in which floats replace doubles.
Definition: UPstream.H:248
static SLList< string > notes
Additional notes for usage.
Definition: argList.H:166
label readLabel(Istream &is)
Definition: label.H:64
string & replaceAll(const string &oldStr, const string &newStr, size_type start=0)
Replace all occurences of sub-string oldStr with newStr.
Definition: string.C:77
static int allowSystemOperations
Flag if system operations are allowed.
Definition: dynamicCode.H:161
void exit(const int errNo=1)
Exit : can be called for any error to exit program.
Definition: error.C:168
forAllConstIter(PtrDictionary< phaseModel >, mixture.phases(), phase)
Definition: pEqn.H:39
static void noBanner()
Disable emitting the banner information.
Definition: argList.C:140
graph_traits< Graph >::vertices_size_type size_type
Definition: SloanRenumber.C:73
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: HashTable.H:59
Foam::argList::initValidTables dummyInitValidTables
Definition: argList.C:77
static label nProcs(const label communicator=0)
Number of processes in parallel run.
Definition: UPstream.H:386
static const char nl
Definition: Ostream.H:260
virtual ~argList()
Destructor.
Definition: argList.C:875
void setSize(const label)
Reset size of List.
Definition: List.C:318
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
pid_t pgid()
Return the group PID of this process.
Definition: POSIX.C:90
static Stream & writeDivider(Stream &os)
Write the standard file section divider.
Definition: IOobjectI.H:98
void printNotes() const
Print notes (if any)
Definition: argList.C:993
const char *const FOAMbuild
static string::size_type usageMax
Max screen width for displaying usage (default: 80)
Definition: argList.H:172
static string::size_type usageMin
Min offset for displaying usage (default: 20)
Definition: argList.H:169
void set(const bool verbose)
Activate SIGINT signal handler.
Definition: sigInt.C:84
#define forAll(list, i)
Definition: UList.H:421
bool good() const
Return true if next operation might succeed.
Definition: IOstream.H:333
bool setOption(const word &opt, const string &param="")
Set option directly (use with caution)
Definition: argList.C:883
label size() const
Return the number of arguments.
Definition: argListI.H:84
bool add(entry *, bool mergeEntry=false)
Add a new entry.
Definition: dictionary.C:739
static void addBoolOption(const word &opt, const string &usage="")
Add to a bool option to validOptions with usage information.
Definition: argList.C:83
Extract command arguments and options from the supplied argc and argv parameters. ...
Definition: argList.H:102
static int myProcNo(const label communicator=0)
Number of this process (starting from masterNo() = 0)
Definition: UPstream.H:404
bool isAbsolute() const
Return true if file name is absolute.
Definition: fileName.C:57
bool parRun() const
Definition: parRun.H:77
static Stream & writeBanner(Stream &os, bool noHint=false)
Write the standard OpenFOAM file/dictionary banner.
Definition: IOobjectI.H:45
bool found
bool isDir(const fileName &)
Does the name exist as a DIRECTORY in the file system?
Definition: POSIX.C:616
JobInfo jobInfo
Definition: JobInfo.C:35
pid_t pid()
Return the PID of this process.
Definition: POSIX.C:78
int system(const std::string &command)
Execute the specified command.
Definition: POSIX.C:1162
ITstream & lookup(const word &, bool recursive=false, bool patternMatch=true) const
Find and return an entry data stream.
Definition: dictionary.C:452
error FatalError
static int nPollProcInterfaces
Number of polling cycles in processor updates.
Definition: UPstream.H:258
T lookupOrDefault(const word &, const T &, bool recursive=false, bool patternMatch=true) const
Find and return a T,.
Input inter-processor communications stream.
Definition: IPstream.H:50
static int masterNo()
Process index of the master.
Definition: UPstream.H:392
bool check(bool checkArgs=true, bool checkOpts=true) const
Check argument list.
Definition: argList.C:1146
static const NamedEnum< commsTypes, 3 > commsTypeNames
Definition: UPstream.H:71
A class for handling file names.
Definition: fileName.H:69
static HashTable< string > optionUsage
Short usage information for validOptions.
Definition: argList.H:163
string userName()
Return the user&#39;s login name.
Definition: POSIX.C:170
string hostName(const bool full=false)
Return the system&#39;s host name, as per hostname(1)
Definition: POSIX.C:130
static fileCheckTypes fileModificationChecking
Definition: regIOobject.H:128
static bool master(const label communicator=0)
Am I the master process.
Definition: UPstream.H:398
static int firstSlave()
Process index of first slave.
Definition: UPstream.H:421
static int lastSlave(const label communicator=0)
Process index of last slave.
Definition: UPstream.H:427
dimensionedScalar pos(const dimensionedScalar &ds)
static void addNote(const string &)
Add extra notes for the usage information.
Definition: argList.C:124
static commsTypes defaultCommsType
Default commsType.
Definition: UPstream.H:255
bool isFile(const fileName &, const bool checkGzip=true)
Does the name exist as a FILE in the file system?
Definition: POSIX.C:623
void set(const bool verbose)
Activate SIGSEGV signal handler.
Definition: sigSegv.C:86
argList(int &argc, char **&argv, bool checkArgs=true, bool checkOpts=true, bool initialise=true)
Construct from argc and argv.
Definition: argList.C:372
bool isspace(char c)
Definition: char.H:53
void set(const bool verbose)
Activate SIGQUIT signal handler.
Definition: sigQuit.C:86
bool unsetOption(const word &opt)
Unset option directly (use with caution)
Definition: argList.C:958
static void addUsage(const word &opt, const string &usage)
Add option usage information to optionUsage.
Definition: argList.C:108
static void noParallel()
Remove the parallel options.
Definition: argList.C:146
static int nProcsSimpleSum
Number of processors at which the sum algorithm changes from linear.
Definition: UPstream.H:252