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-2016 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;
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 bool Foam::argList::postProcess(int argc, char *argv[])
255 {
256  bool postProcessOption = false;
257 
258  for (int i=1; i<argc; i++)
259  {
260  postProcessOption = argv[i] == '-' + postProcessOptionName;
261  if (postProcessOption) break;
262  }
263 
264  return postProcessOption;
265 }
266 
267 
268 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
269 
270 // Convert argv -> args_
271 // Transform sequences with "(" ... ")" into string lists in the process
272 bool Foam::argList::regroupArgv(int& argc, char**& argv)
273 {
274  int nArgs = 0;
275  int listDepth = 0;
276  string tmpString;
277 
278  // Note: we also re-write directly into args_
279  // and use a second pass to sort out args/options
280  for (int argI = 0; argI < argc; ++argI)
281  {
282  if (strcmp(argv[argI], "(") == 0)
283  {
284  ++listDepth;
285  tmpString += "(";
286  }
287  else if (strcmp(argv[argI], ")") == 0)
288  {
289  if (listDepth)
290  {
291  --listDepth;
292  tmpString += ")";
293  if (listDepth == 0)
294  {
295  args_[nArgs++] = tmpString;
296  tmpString.clear();
297  }
298  }
299  else
300  {
301  args_[nArgs++] = argv[argI];
302  }
303  }
304  else if (listDepth)
305  {
306  // Quote each string element
307  tmpString += "\"";
308  tmpString += argv[argI];
309  tmpString += "\"";
310  }
311  else
312  {
313  args_[nArgs++] = argv[argI];
314  }
315  }
316 
317  if (tmpString.size())
318  {
319  args_[nArgs++] = tmpString;
320  }
321 
322  args_.setSize(nArgs);
323 
324  return nArgs < argc;
325 }
326 
327 
328 void Foam::argList::getRootCase()
329 {
330  fileName casePath;
331 
332  // [-case dir] specified
333  HashTable<string>::const_iterator iter = options_.find("case");
334 
335  if (iter != options_.end())
336  {
337  casePath = iter();
338  casePath.clean();
339 
340  if (casePath.empty() || casePath == ".")
341  {
342  // Handle degenerate form and '-case .' like no -case specified
343  casePath = cwd();
344  options_.erase("case");
345  }
346  else if (!casePath.isAbsolute() && casePath.name() == "..")
347  {
348  // Avoid relative cases ending in '..' - makes for very ugly names
349  casePath = cwd()/casePath;
350  casePath.clean();
351  }
352  }
353  else
354  {
355  // Nothing specified, use the current dir
356  casePath = cwd();
357  }
358 
359  rootPath_ = casePath.path();
360  globalCase_ = casePath.name();
361  case_ = globalCase_;
362 
363 
364  // Set the case and case-name as an environment variable
365  if (rootPath_.isAbsolute())
366  {
367  // Absolute path - use as-is
368  setEnv("FOAM_CASE", rootPath_/globalCase_, true);
369  setEnv("FOAM_CASENAME", globalCase_, true);
370  }
371  else
372  {
373  // Qualify relative path
374  casePath = cwd()/rootPath_/globalCase_;
375  casePath.clean();
376 
377  setEnv("FOAM_CASE", casePath, true);
378  setEnv("FOAM_CASENAME", casePath.name(), true);
379  }
380 }
381 
382 
383 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
384 
386 (
387  int& argc,
388  char**& argv,
389  bool checkArgs,
390  bool checkOpts,
391  const bool initialise
392 )
393 :
394  args_(argc),
395  options_(argc)
396 {
397  // Check if this run is a parallel run by searching for any parallel option
398  // If found call runPar which might filter argv
399  for (int argI = 0; argI < argc; ++argI)
400  {
401  if (argv[argI][0] == '-')
402  {
403  const char *optionName = &argv[argI][1];
404 
405  if (validParOptions.found(optionName))
406  {
407  parRunControl_.runPar(argc, argv);
408  break;
409  }
410  }
411  }
412 
413  // Convert argv -> args_ and capture ( ... ) lists
414  // for normal arguments and for options
415  regroupArgv(argc, argv);
416 
417  // Get executable name
418  args_[0] = fileName(argv[0]);
419  executable_ = fileName(argv[0]).name();
420 
421  // Check arguments and options, we already have argv[0]
422  int nArgs = 1;
423  argListStr_ = args_[0];
424 
425  for (int argI = 1; argI < args_.size(); ++argI)
426  {
427  argListStr_ += ' ';
428  argListStr_ += args_[argI];
429 
430  if (args_[argI][0] == '-')
431  {
432  const char *optionName = &args_[argI][1];
433 
434  if
435  (
436  (
437  validOptions.found(optionName)
438  && !validOptions[optionName].empty()
439  )
440  || (
441  validParOptions.found(optionName)
442  && !validParOptions[optionName].empty()
443  )
444  )
445  {
446  ++argI;
447  if (argI >= args_.size())
448  {
449  FatalError
450  <<"Option '-" << optionName
451  << "' requires an argument" << endl;
452  printUsage();
453  FatalError.exit();
454  }
455 
456  argListStr_ += ' ';
457  argListStr_ += args_[argI];
458  options_.insert(optionName, args_[argI]);
459  }
460  else
461  {
462  options_.insert(optionName, "");
463  }
464  }
465  else
466  {
467  if (nArgs != argI)
468  {
469  args_[nArgs] = args_[argI];
470  }
471  ++nArgs;
472  }
473  }
474 
475  args_.setSize(nArgs);
476 
477  parse(checkArgs, checkOpts, initialise);
478 }
479 
480 
482 (
483  const argList& args,
484  const HashTable<string>& options,
485  bool checkArgs,
486  bool checkOpts,
487  bool initialise
488 )
489 :
490  parRunControl_(args.parRunControl_),
491  args_(args.args_),
492  options_(options),
493  executable_(args.executable_),
494  rootPath_(args.rootPath_),
495  globalCase_(args.globalCase_),
496  case_(args.case_),
497  argListStr_(args.argListStr_)
498 {
499  parse(checkArgs, checkOpts, initialise);
500 }
501 
502 
504 (
505  bool checkArgs,
506  bool checkOpts,
507  bool initialise
508 )
509 {
510  // Help/documentation options:
511  // -help print the usage
512  // -doc display application documentation in browser
513  // -srcDoc display source code in browser
514  if
515  (
516  options_.found("help")
517  || options_.found("doc")
518  || options_.found("srcDoc")
519  )
520  {
521  if (options_.found("help"))
522  {
523  printUsage();
524  }
525 
526  // Only display one or the other
527  if (options_.found("srcDoc"))
528  {
529  displayDoc(true);
530  }
531  else if (options_.found("doc"))
532  {
533  displayDoc(false);
534  }
535 
536  ::exit(0);
537  }
538 
539  // Print the usage message and exit if the number of arguments is incorrect
540  if (!check(checkArgs, checkOpts))
541  {
542  FatalError.exit();
543  }
544 
545 
546  if (initialise)
547  {
548  string dateString = clock::date();
549  string timeString = clock::clockTime();
550 
551  // Print the banner once only for parallel runs
552  if (Pstream::master() && bannerEnabled)
553  {
555  << "Build : " << Foam::FOAMbuild << nl
556  << "Exec : " << argListStr_.c_str() << nl
557  << "Date : " << dateString.c_str() << nl
558  << "Time : " << timeString.c_str() << nl
559  << "Host : " << hostName() << nl
560  << "PID : " << pid() << endl;
561  }
562 
563  jobInfo.add("startDate", dateString);
564  jobInfo.add("startTime", timeString);
565  jobInfo.add("userName", userName());
566  jobInfo.add("foamVersion", word(FOAMversion));
567  jobInfo.add("code", executable_);
568  jobInfo.add("argList", argListStr_);
569  jobInfo.add("currentDir", cwd());
570  jobInfo.add("PPID", ppid());
571  jobInfo.add("PGID", pgid());
572 
573  // Add build information - only use the first word
574  {
575  std::string build(Foam::FOAMbuild);
576  std::string::size_type found = build.find(' ');
577  if (found != std::string::npos)
578  {
579  build.resize(found);
580  }
581  jobInfo.add("foamBuild", build);
582  }
583  }
584 
585  // Case is a single processor run unless it is running parallel
586  int nProcs = 1;
587 
588  // Roots if running distributed
589  fileNameList roots;
590 
591 
592  // If this actually is a parallel run
593  if (parRunControl_.parRun())
594  {
595  // For the master
596  if (Pstream::master())
597  {
598  // Establish rootPath_/globalCase_/case_ for master
599  getRootCase();
600 
601  // See if running distributed (different roots for different procs)
602  label dictNProcs = -1;
603  fileName source;
604 
605  if (options_.found("roots"))
606  {
607  source = "-roots";
608  IStringStream is(options_["roots"]);
609  roots = readList<fileName>(is);
610 
611  if (roots.size() != 1)
612  {
613  dictNProcs = roots.size()+1;
614  }
615  }
616  else
617  {
618  source = rootPath_/globalCase_/"system/decomposeParDict";
619  IFstream decompDictStream(source);
620 
621  if (!decompDictStream.good())
622  {
623  FatalError
624  << "Cannot read "
625  << decompDictStream.name()
626  << exit(FatalError);
627  }
628 
629  dictionary decompDict(decompDictStream);
630 
631  dictNProcs = readLabel
632  (
633  decompDict.lookup("numberOfSubdomains")
634  );
635 
636  if (decompDict.lookupOrDefault("distributed", false))
637  {
638  decompDict.lookup("roots") >> roots;
639  }
640  }
641 
642  // Convenience:
643  // when a single root is specified, use it for all processes
644  if (roots.size() == 1)
645  {
646  const fileName rootName(roots[0]);
647  roots.setSize(Pstream::nProcs()-1, rootName);
648 
649  // adjust dictNProcs for command-line '-roots' option
650  if (dictNProcs < 0)
651  {
652  dictNProcs = roots.size()+1;
653  }
654  }
655 
656 
657  // Check number of processors.
658  // nProcs => number of actual procs
659  // dictNProcs => number of procs specified in decompositionDict
660  // nProcDirs => number of processor directories
661  // (n/a when running distributed)
662  //
663  // - normal running : nProcs = dictNProcs = nProcDirs
664  // - decomposition to more processors : nProcs = dictNProcs
665  // - decomposition to fewer processors : nProcs = nProcDirs
666  if (dictNProcs > Pstream::nProcs())
667  {
668  FatalError
669  << source
670  << " specifies " << dictNProcs
671  << " processors but job was started with "
672  << Pstream::nProcs() << " processors."
673  << exit(FatalError);
674  }
675 
676 
677  // Distributed data
678  if (roots.size())
679  {
680  if (roots.size() != Pstream::nProcs()-1)
681  {
682  FatalError
683  << "number of entries in roots "
684  << roots.size()
685  << " is not equal to the number of slaves "
686  << Pstream::nProcs()-1
687  << exit(FatalError);
688  }
689 
690  forAll(roots, i)
691  {
692  roots[i].expand();
693  }
694 
695  // Distribute the master's argument list (with new root)
696  bool hadCaseOpt = options_.found("case");
697  for
698  (
699  int slave = Pstream::firstSlave();
700  slave <= Pstream::lastSlave();
701  slave++
702  )
703  {
704  options_.set("case", roots[slave-1]/globalCase_);
705 
706  OPstream toSlave(Pstream::scheduled, slave);
707  toSlave << args_ << options_;
708  }
709  options_.erase("case");
710 
711  // Restore [-case dir]
712  if (hadCaseOpt)
713  {
714  options_.set("case", rootPath_/globalCase_);
715  }
716  }
717  else
718  {
719  // Possibly going to fewer processors.
720  // Check if all procDirs are there.
721  if (dictNProcs < Pstream::nProcs())
722  {
723  label nProcDirs = 0;
724  while
725  (
726  isDir
727  (
728  rootPath_/globalCase_/"processor"
729  + name(++nProcDirs)
730  )
731  )
732  {}
733 
734  if (nProcDirs != Pstream::nProcs())
735  {
736  FatalError
737  << "number of processor directories = "
738  << nProcDirs
739  << " is not equal to the number of processors = "
740  << Pstream::nProcs()
741  << exit(FatalError);
742  }
743  }
744 
745  // Distribute the master's argument list (unaltered)
746  for
747  (
748  int slave = Pstream::firstSlave();
749  slave <= Pstream::lastSlave();
750  slave++
751  )
752  {
753  OPstream toSlave(Pstream::scheduled, slave);
754  toSlave << args_ << options_;
755  }
756  }
757  }
758  else
759  {
760  // Collect the master's argument list
762  fromMaster >> args_ >> options_;
763 
764  // Establish rootPath_/globalCase_/case_ for slave
765  getRootCase();
766  }
767 
768  nProcs = Pstream::nProcs();
769  case_ = globalCase_/(word("processor") + name(Pstream::myProcNo()));
770  }
771  else
772  {
773  // Establish rootPath_/globalCase_/case_
774  getRootCase();
775  case_ = globalCase_;
776  }
777 
778 
779  stringList slaveProcs;
780 
781  // Collect slave machine/pid
782  if (parRunControl_.parRun())
783  {
784  if (Pstream::master())
785  {
786  slaveProcs.setSize(Pstream::nProcs() - 1);
787  label proci = 0;
788  for
789  (
790  int slave = Pstream::firstSlave();
791  slave <= Pstream::lastSlave();
792  slave++
793  )
794  {
795  IPstream fromSlave(Pstream::scheduled, slave);
796 
797  string slaveBuild;
798  string slaveMachine;
799  label slavePid;
800  fromSlave >> slaveBuild >> slaveMachine >> slavePid;
801 
802  slaveProcs[proci++] = slaveMachine + "." + name(slavePid);
803 
804  // Check build string to make sure all processors are running
805  // the same build
806  if (slaveBuild != Foam::FOAMbuild)
807  {
809  << "Master is running version " << Foam::FOAMbuild
810  << "; slave " << proci << " is running version "
811  << slaveBuild
812  << exit(FatalError);
813  }
814  }
815  }
816  else
817  {
819  toMaster << string(Foam::FOAMbuild) << hostName() << pid();
820  }
821  }
822 
823 
824  if (Pstream::master() && bannerEnabled)
825  {
826  Info<< "Case : " << (rootPath_/globalCase_).c_str() << nl
827  << "nProcs : " << nProcs << endl;
828 
829  if (parRunControl_.parRun())
830  {
831  Info<< "Slaves : " << slaveProcs << nl;
832  if (roots.size())
833  {
834  Info<< "Roots : " << roots << nl;
835  }
836  Info<< "Pstream initialized with:" << nl
837  << " floatTransfer : " << Pstream::floatTransfer << nl
838  << " nProcsSimpleSum : " << Pstream::nProcsSimpleSum << nl
839  << " commsType : "
841  << " polling iterations : " << Pstream::nPollProcInterfaces
842  << endl;
843  }
844  }
845 
846  if (initialise)
847  {
848  jobInfo.add("root", rootPath_);
849  jobInfo.add("case", globalCase_);
850  jobInfo.add("nProcs", nProcs);
851  if (slaveProcs.size())
852  {
853  jobInfo.add("slaves", slaveProcs);
854  }
855  if (roots.size())
856  {
857  jobInfo.add("roots", roots);
858  }
859  jobInfo.write();
860 
861  // Switch on signal trapping. We have to wait until after Pstream::init
862  // since this sets up its own ones.
863  sigFpe_.set(bannerEnabled);
864  sigInt_.set(bannerEnabled);
865  sigQuit_.set(bannerEnabled);
866  sigSegv_.set(bannerEnabled);
867 
868  if (bannerEnabled)
869  {
870  Info<< "fileModificationChecking : "
871  << "Monitoring run-time modified files using "
873  [
875  ]
876  << endl;
877 
878  Info<< "allowSystemOperations : ";
880  {
881  Info<< "Allowing user-supplied system call operations" << endl;
882  }
883  else
884  {
885  Info<< "Disallowing user-supplied system call operations"
886  << endl;
887  }
888  }
889 
890  if (Pstream::master() && bannerEnabled)
891  {
892  Info<< endl;
894  }
895  }
896 }
897 
898 
899 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
900 
902 {
903  jobInfo.end();
904 }
905 
906 
907 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
908 
909 bool Foam::argList::setOption(const word& opt, const string& param)
910 {
911  bool changed = false;
912 
913  // Only allow valid options
914  if (validOptions.found(opt))
915  {
916  // Some options are to be protected
917  if
918  (
919  opt == "case"
920  || opt == "parallel"
921  || opt == "roots"
922  )
923  {
924  FatalError
925  <<"used argList::setOption on a protected option: '"
926  << opt << "'" << endl;
927  FatalError.exit();
928  }
929 
930  if (validOptions[opt].empty())
931  {
932  // Bool option
933  if (!param.empty())
934  {
935  // Disallow change of type
936  FatalError
937  <<"used argList::setOption to change bool to non-bool: '"
938  << opt << "'" << endl;
939  FatalError.exit();
940  }
941  else
942  {
943  // Did not previously exist
944  changed = !options_.found(opt);
945  }
946  }
947  else
948  {
949  // Non-bool option
950  if (param.empty())
951  {
952  // Disallow change of type
953  FatalError
954  <<"used argList::setOption to change non-bool to bool: '"
955  << opt << "'" << endl;
956  FatalError.exit();
957  }
958  else
959  {
960  // Existing value needs changing, or did not previously exist
961  changed = options_.found(opt) ? options_[opt] != param : true;
962  }
963  }
964  }
965  else
966  {
967  FatalError
968  <<"used argList::setOption on an invalid option: '"
969  << opt << "'" << nl << "allowed are the following:"
970  << validOptions << endl;
971  FatalError.exit();
972  }
973 
974  // Set/change the option as required
975  if (changed)
976  {
977  options_.set(opt, param);
978  }
979 
980  return changed;
981 }
982 
983 
985 {
986  // Only allow valid options
987  if (validOptions.found(opt))
988  {
989  // Some options are to be protected
990  if
991  (
992  opt == "case"
993  || opt == "parallel"
994  || opt == "roots"
995  )
996  {
997  FatalError
998  <<"used argList::unsetOption on a protected option: '"
999  << opt << "'" << endl;
1000  FatalError.exit();
1001  }
1002 
1003  // Remove the option, return true if state changed
1004  return options_.erase(opt);
1005  }
1006  else
1007  {
1008  FatalError
1009  <<"used argList::unsetOption on an invalid option: '"
1010  << opt << "'" << nl << "allowed are the following:"
1011  << validOptions << endl;
1012  FatalError.exit();
1013  }
1014 
1015  return false;
1016 }
1017 
1018 
1020 {
1021  // Output notes directly - no automatic text wrapping
1022  if (!notes.empty())
1023  {
1024  Info<< nl;
1026  {
1027  Info<< iter().c_str() << nl;
1028  }
1029  }
1030 }
1031 
1032 
1034 {
1035  Info<< "\nUsage: " << executable_ << " [OPTIONS]";
1036 
1038  {
1039  Info<< " <" << iter().c_str() << '>';
1040  }
1041 
1042  Info<< "\noptions:\n";
1043 
1044  wordList opts = validOptions.sortedToc();
1045  forAll(opts, optI)
1046  {
1047  const word& optionName = opts[optI];
1048 
1049  HashTable<string>::const_iterator iter = validOptions.find(optionName);
1050  Info<< " -" << optionName;
1051  label len = optionName.size() + 3; // Length includes leading ' -'
1052 
1053  if (iter().size())
1054  {
1055  // Length includes space and between option/param and '<>'
1056  len += iter().size() + 3;
1057  Info<< " <" << iter().c_str() << '>';
1058  }
1059 
1061  optionUsage.find(optionName);
1062 
1063  if (usageIter != optionUsage.end())
1064  {
1065  printOptionUsage
1066  (
1067  len,
1068  usageIter()
1069  );
1070  }
1071  else
1072  {
1073  Info<< nl;
1074  }
1075  }
1076 
1077  // Place srcDoc/doc/help options at the end
1078  Info<< " -srcDoc";
1079  printOptionUsage
1080  (
1081  9,
1082  "display source code in browser"
1083  );
1084 
1085  Info<< " -doc";
1086  printOptionUsage
1087  (
1088  6,
1089  "display application documentation in browser"
1090  );
1091 
1092  Info<< " -help";
1093  printOptionUsage
1094  (
1095  7,
1096  "print the usage"
1097  );
1098 
1099 
1100  printNotes();
1101 
1102  Info<< nl
1103  <<"Using: OpenFOAM-" << Foam::FOAMversion
1104  << " (see www.OpenFOAM.org)" << nl
1105  <<"Build: " << Foam::FOAMbuild << nl
1106  << endl;
1107 }
1108 
1109 
1110 void Foam::argList::displayDoc(bool source) const
1111 {
1112  const dictionary& docDict = debug::controlDict().subDict("Documentation");
1113  List<fileName> docDirs(docDict.lookup("doxyDocDirs"));
1114  List<fileName> docExts(docDict.lookup("doxySourceFileExts"));
1115 
1116  // For source code: change foo_8C.html to foo_8C_source.html
1117  if (source)
1118  {
1119  forAll(docExts, extI)
1120  {
1121  docExts[extI].replace(".", "_source.");
1122  }
1123  }
1124 
1125  fileName docFile;
1126  bool found = false;
1127 
1128  forAll(docDirs, dirI)
1129  {
1130  forAll(docExts, extI)
1131  {
1132  docFile = docDirs[dirI]/executable_ + docExts[extI];
1133  docFile.expand();
1134 
1135  if (isFile(docFile))
1136  {
1137  found = true;
1138  break;
1139  }
1140  }
1141  if (found)
1142  {
1143  break;
1144  }
1145  }
1146 
1147  if (found)
1148  {
1149  string docBrowser = getEnv("FOAM_DOC_BROWSER");
1150  if (docBrowser.empty())
1151  {
1152  docDict.lookup("docBrowser") >> docBrowser;
1153  }
1154  // Can use FOAM_DOC_BROWSER='application file://%f' if required
1155  docBrowser.replaceAll("%f", docFile);
1156 
1157  Info<< "Show documentation: " << docBrowser.c_str() << endl;
1158 
1159  system(docBrowser);
1160  }
1161  else
1162  {
1163  Info<< nl
1164  << "No documentation found for " << executable_
1165  << ", but you can use -help to display the usage\n" << endl;
1166  }
1167 }
1168 
1169 
1170 bool Foam::argList::check(bool checkArgs, bool checkOpts) const
1171 {
1172  bool ok = true;
1173 
1174  if (Pstream::master())
1175  {
1176  if (checkArgs && args_.size() - 1 != validArgs.size())
1177  {
1178  FatalError
1179  << "Wrong number of arguments, expected " << validArgs.size()
1180  << " found " << args_.size() - 1 << endl;
1181  ok = false;
1182  }
1183 
1184  if (checkOpts)
1185  {
1186  forAllConstIter(HashTable<string>, options_, iter)
1187  {
1188  if
1189  (
1190  !validOptions.found(iter.key())
1191  && !validParOptions.found(iter.key())
1192  )
1193  {
1194  FatalError
1195  << "Invalid option: -" << iter.key() << endl;
1196  ok = false;
1197  }
1198  }
1199  }
1200 
1201  if (!ok)
1202  {
1203  printUsage();
1204  }
1205  }
1206 
1207  return ok;
1208 }
1209 
1210 
1212 {
1213  if (!isDir(rootPath()))
1214  {
1215  FatalError
1216  << executable_
1217  << ": cannot open root directory " << rootPath()
1218  << endl;
1219 
1220  return false;
1221  }
1222 
1223  if (!isDir(path()) && Pstream::master())
1224  {
1225  // Allow slaves on non-existing processor directories, created later
1226  FatalError
1227  << executable_
1228  << ": cannot open case directory " << path()
1229  << endl;
1230 
1231  return false;
1232  }
1233 
1234  return true;
1235 }
1236 
1237 
1238 // ************************************************************************* //
static bool floatTransfer
Should compact transfer be used in which floats replace doubles.
Definition: UPstream.H:261
string getEnv(const word &)
Return environment variable of given name.
Definition: POSIX.C:102
string & replaceAll(const string &oldStr, const string &newStr, size_type start=0)
Replace all occurences of sub-string oldStr with newStr.
Definition: string.C:74
void set(const bool verbose)
Activate SIGQUIT signal handler.
Definition: sigQuit.C:82
bool setOption(const word &opt, const string &param="")
Set option directly (use with caution)
Definition: argList.C:909
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:428
static void removeOption(const word &opt)
Remove option from validOptions and from optionUsage.
Definition: argList.C:133
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
static int masterNo()
Process index of the master.
Definition: UPstream.H:405
A class for handling file names.
Definition: fileName.H:69
static Stream & writeBanner(Stream &os, bool noHint=false)
Write the standard OpenFOAM file/dictionary banner.
Definition: IOobjectI.H:45
An STL-conforming const_iterator.
Definition: HashTable.H:470
static word postProcessOptionName
Standard name for the post-processing option.
Definition: argList.H:175
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
bool unsetOption(const word &opt)
Unset option directly (use with caution)
Definition: argList.C:984
static void addUsage(const word &opt, const string &usage)
Add option usage information to optionUsage.
Definition: argList.C:108
error FatalError
A list of keyword definitions, which are a keyword followed by any number of values (e...
Definition: dictionary.H:137
bool clean()
Cleanup file name.
Definition: fileName.C:77
argList(int &argc, char **&argv, bool checkArgs=true, bool checkOpts=true, bool initialise=true)
Construct from argc and argv.
Definition: argList.C:386
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
static int firstSlave()
Process index of first slave.
Definition: UPstream.H:434
pid_t ppid()
Return the parent PID of this process.
Definition: POSIX.C:84
static Stream & writeDivider(Stream &os)
Write the standard file section divider.
Definition: IOobjectI.H:98
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:76
const dictionary & subDict(const word &) const
Find and return a sub-dictionary.
Definition: dictionary.C:633
static int myProcNo(const label communicator=0)
Number of this process (starting from masterNo() = 0)
Definition: UPstream.H:417
bool good() const
Return true if next operation might succeed.
Definition: IOstream.H:333
static int nProcsSimpleSum
Number of processors at which the sum algorithm changes from linear.
Definition: UPstream.H:265
static SLList< string > notes
Additional notes for usage.
Definition: argList.H:166
bool isFile(const fileName &, const bool checkGzip=true)
Does the name exist as a FILE in the file system?
Definition: POSIX.C:492
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:253
static bool master(const label communicator=0)
Am I the master process.
Definition: UPstream.H:411
Foam::argList::initValidTables dummyInitValidTables
Definition: argList.C:77
static void noParallel()
Remove the parallel options.
Definition: argList.C:146
static SLList< string > validArgs
A list of valid (mandatory) arguments.
Definition: argList.H:154
const fileName & name() const
Return the name of the stream.
Definition: IFstream.H:116
bool isDir(const fileName &)
Does the name exist as a DIRECTORY in the file system?
Definition: POSIX.C:486
static bool postProcess(int argc, char *argv[])
Return true if the post-processing option is specified.
Definition: argList.C:254
const char *const FOAMversion
const fileName & rootPath() const
Return root path.
Definition: argListI.H:36
void runPar(int &argc, char **&argv)
Definition: parRun.H:66
virtual ~argList()
Destructor.
Definition: argList.C:901
void exit(const int errNo=1)
Exit : can be called for any error to exit program.
Definition: error.C:168
bool add(entry *, bool mergeEntry=false)
Add a new entry.
Definition: dictionary.C:737
const word & executable() const
Name of executable without the path.
Definition: argListI.H:30
void parse(bool checkArgs, bool checkOpts, bool initialise)
Parse.
Definition: argList.C:504
Input inter-processor communications stream.
Definition: IPstream.H:50
fileName path() const
Return the path to the caseName.
Definition: argListI.H:60
static fileCheckTypes fileModificationChecking
Definition: regIOobject.H:128
Functions used by OpenFOAM that are specific to POSIX compliant operating systems and need to be repl...
dimensionedScalar pos(const dimensionedScalar &ds)
word name() const
Return file name (part beyond last /)
Definition: fileName.C:179
static int nPollProcInterfaces
Number of polling cycles in processor updates.
Definition: UPstream.H:271
string hostName(const bool full=false)
Return the system&#39;s host name, as per hostname(1)
Definition: POSIX.C:130
static HashTable< string > validParOptions
A list of valid parallel options.
Definition: argList.H:160
A class for handling words, derived from string.
Definition: word.H:59
Extract command arguments and options from the supplied argc and argv parameters. ...
Definition: argList.H:102
static int allowSystemOperations
Flag if system operations are allowed.
Definition: dynamicCode.H:161
bool check(bool checkArgs=true, bool checkOpts=true) const
Check argument list.
Definition: argList.C:1170
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
bool checkRootCase() const
Check root path and case path.
Definition: argList.C:1211
string userName()
Return the user&#39;s login name.
Definition: POSIX.C:170
static HashTable< string > optionUsage
Short usage information for validOptions.
Definition: argList.H:163
graph_traits< Graph >::vertices_size_type size_type
Definition: SloanRenumber.C:73
void printNotes() const
Print notes (if any)
Definition: argList.C:1019
forAllConstIter(PtrDictionary< phaseModel >, mixture.phases(), phase)
Definition: pEqn.H:29
label readLabel(Istream &is)
Definition: label.H:64
static string clockTime()
Return the current wall-clock time as a string.
Definition: clock.C:93
bool isAbsolute() const
Return true if file name is absolute.
Definition: fileName.C:57
pid_t pid()
Return the PID of this process.
Definition: POSIX.C:78
static const char nl
Definition: Ostream.H:262
Input from file stream.
Definition: IFstream.H:81
static const NamedEnum< commsTypes, 3 > commsTypeNames
Definition: UPstream.H:71
Output inter-processor communications stream.
Definition: OPstream.H:50
pid_t pgid()
Return the group PID of this process.
Definition: POSIX.C:90
word name(const complex &)
Return a string representation of a complex.
Definition: complex.C:47
static string date()
Return the current wall-clock date as a string.
Definition: clock.C:77
static commsTypes defaultCommsType
Default commsType.
Definition: UPstream.H:268
void setSize(const label)
Reset size of List.
Definition: List.C:295
static label nProcs(const label communicator=0)
Number of processes in parallel run.
Definition: UPstream.H:399
void set(const bool verbose)
Activate SIGINT signal handler.
Definition: sigInt.C:80
bool isspace(char c)
Definition: char.H:53
string & expand(const bool allowEmpty=false)
Expand initial tildes and all occurences of environment variables.
Definition: string.C:95
Input from memory buffer stream.
Definition: IStringStream.H:49
fileName cwd()
Return current working directory path name.
Definition: POSIX.C:246
JobInfo jobInfo
Definition: JobInfo.C:35
void set(const bool verbose)
Activate SIGFPE signal handler when FOAM_SIGFPE is set.
Definition: sigFpe.C:148
messageStream Info
label size() const
Return the number of arguments.
Definition: argListI.H:84
static void noBanner()
Disable emitting the banner information.
Definition: argList.C:140
static const NamedEnum< fileCheckTypes, 4 > fileCheckTypesNames
Definition: regIOobject.H:76
void displayDoc(bool source=false) const
Display documentation in browser.
Definition: argList.C:1110
static void addBoolOption(const word &opt, const string &usage="")
Add to a bool option to validOptions with usage information.
Definition: argList.C:83
bool parRun() const
Definition: parRun.H:77
static void addNote(const string &)
Add extra notes for the usage information.
Definition: argList.C:124
void set(const bool verbose)
Activate SIGSEGV signal handler.
Definition: sigSegv.C:82
static string::size_type usageMin
Min offset for displaying usage (default: 20)
Definition: argList.H:169
const char *const FOAMbuild
void printUsage() const
Print usage.
Definition: argList.C:1033
dictionary & controlDict()
The central control dictionary.
Definition: debug.C:92
fileName path() const
Return directory path name (part before last /)
Definition: fileName.C:249
T lookupOrDefault(const word &, const T &, bool recursive=false, bool patternMatch=true) const
Find and return a T,.
A class for handling character strings derived from std::string.
Definition: string.H:74
#define FatalErrorIn(functionName)
Report an error message using Foam::FatalError.
Definition: error.H:314
static string::size_type usageMax
Max screen width for displaying usage (default: 80)
Definition: argList.H:172
bool found
static HashTable< string > validOptions
A list of valid options.
Definition: argList.H:157
bool setEnv(const word &name, const std::string &value, const bool overwrite)
Set an environment variable.
Definition: POSIX.C:120
int system(const std::string &command)
Execute the specified command.
Definition: POSIX.C:1020
static int lastSlave(const label communicator=0)
Process index of last slave.
Definition: UPstream.H:440
ITstream & lookup(const word &, bool recursive=false, bool patternMatch=true) const
Find and return an entry data stream.
Definition: dictionary.C:451