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-2017 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"
38 
39 #include <cctype>
40 
41 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
42 
43 bool Foam::argList::bannerEnabled = true;
52 
53 Foam::argList::initValidTables::initValidTables()
54 {
55  argList::addOption
56  (
57  "case", "dir",
58  "specify alternate case directory, default is the cwd"
59  );
60  argList::addBoolOption("parallel", "run in parallel");
61  validParOptions.set("parallel", "");
62  argList::addOption
63  (
64  "roots", "(dir1 .. dirN)",
65  "slave root directories for distributed running"
66  );
67  validParOptions.set("roots", "(dir1 .. dirN)");
68 
69  argList::addBoolOption
70  (
71  "noFunctionObjects",
72  "do not execute functionObjects"
73  );
74 
75  Pstream::addValidParOptions(validParOptions);
76 }
77 
78 
79 Foam::argList::initValidTables dummyInitValidTables;
80 
81 
82 // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
83 
85 (
86  const word& opt,
87  const string& usage
88 )
89 {
90  addOption(opt, "", usage);
91 }
92 
93 
95 (
96  const word& opt,
97  const string& param,
98  const string& usage
99 )
100 {
101  validOptions.set(opt, param);
102  if (!usage.empty())
103  {
104  optionUsage.set(opt, usage);
105  }
106 }
107 
108 
110 (
111  const word& opt,
112  const string& usage
113 )
114 {
115  if (usage.empty())
116  {
117  optionUsage.erase(opt);
118  }
119  else
120  {
121  optionUsage.set(opt, usage);
122  }
123 }
124 
125 
126 void Foam::argList::addNote(const string& note)
127 {
128  if (!note.empty())
129  {
130  notes.append(note);
131  }
132 }
133 
134 
136 {
137  validOptions.erase(opt);
138  optionUsage.erase(opt);
139 }
140 
141 
143 {
144  bannerEnabled = false;
145 }
146 
147 
149 {
150  removeOption("parallel");
151  removeOption("roots");
152  validParOptions.clear();
153 }
154 
155 
156 void Foam::argList::printOptionUsage
157 (
158  const label location,
159  const string& str
160 )
161 {
162  const string::size_type textWidth = usageMax - usageMin;
163  const string::size_type strLen = str.size();
164 
165  if (strLen)
166  {
167  // Minimum of 2 spaces between option and usage:
168  if (string::size_type(location) + 2 <= usageMin)
169  {
170  for (string::size_type i = location; i < usageMin; ++i)
171  {
172  Info<<' ';
173  }
174  }
175  else
176  {
177  // or start a new line
178  Info<< nl;
179  for (string::size_type i = 0; i < usageMin; ++i)
180  {
181  Info<<' ';
182  }
183  }
184 
185  // Text wrap
187  while (pos != string::npos && pos + textWidth < strLen)
188  {
189  // Potential end point and next point
190  string::size_type curr = pos + textWidth - 1;
191  string::size_type next = string::npos;
192 
193  if (isspace(str[curr]))
194  {
195  // We were lucky: ended on a space
196  next = str.find_first_not_of(" \t\n", curr);
197  }
198  else if (isspace(str[curr+1]))
199  {
200  // The next one is a space - so we are okay
201  curr++; // otherwise the length is wrong
202  next = str.find_first_not_of(" \t\n", curr);
203  }
204  else
205  {
206  // Search for end of a previous word break
207  string::size_type prev = str.find_last_of(" \t\n", curr);
208 
209  // Reposition to the end of previous word if possible
210  if (prev != string::npos && prev > pos)
211  {
212  curr = prev;
213  }
214  }
215 
216  if (next == string::npos)
217  {
218  next = curr + 1;
219  }
220 
221  // Indent following lines (not the first one)
222  if (pos)
223  {
224  for (string::size_type i = 0; i < usageMin; ++i)
225  {
226  Info<<' ';
227  }
228  }
229 
230  Info<< str.substr(pos, (curr - pos)).c_str() << nl;
231  pos = next;
232  }
233 
234  // Output the remainder of the string
235  if (pos != string::npos)
236  {
237  // Indent following lines (not the first one)
238  if (pos)
239  {
240  for (string::size_type i = 0; i < usageMin; ++i)
241  {
242  Info<<' ';
243  }
244  }
245 
246  Info<< str.substr(pos).c_str() << nl;
247  }
248  }
249  else
250  {
251  Info<< nl;
252  }
253 }
254 
255 
256 bool Foam::argList::postProcess(int argc, char *argv[])
257 {
258  bool postProcessOption = false;
259 
260  for (int i=1; i<argc; i++)
261  {
262  postProcessOption = argv[i] == '-' + postProcessOptionName;
263  if (postProcessOption) break;
264  }
265 
266  return postProcessOption;
267 }
268 
269 
270 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
271 
272 // Convert argv -> args_
273 // Transform sequences with "(" ... ")" into string lists in the process
274 bool Foam::argList::regroupArgv(int& argc, char**& argv)
275 {
276  int nArgs = 0;
277  int listDepth = 0;
278  string tmpString;
279 
280  // Note: we also re-write directly into args_
281  // and use a second pass to sort out args/options
282  for (int argI = 0; argI < argc; ++argI)
283  {
284  if (strcmp(argv[argI], "(") == 0)
285  {
286  ++listDepth;
287  tmpString += "(";
288  }
289  else if (strcmp(argv[argI], ")") == 0)
290  {
291  if (listDepth)
292  {
293  --listDepth;
294  tmpString += ")";
295  if (listDepth == 0)
296  {
297  args_[nArgs++] = tmpString;
298  tmpString.clear();
299  }
300  }
301  else
302  {
303  args_[nArgs++] = argv[argI];
304  }
305  }
306  else if (listDepth)
307  {
308  // Quote each string element
309  tmpString += "\"";
310  tmpString += argv[argI];
311  tmpString += "\"";
312  }
313  else
314  {
315  args_[nArgs++] = argv[argI];
316  }
317  }
318 
319  if (tmpString.size())
320  {
321  args_[nArgs++] = tmpString;
322  }
323 
324  args_.setSize(nArgs);
325 
326  return nArgs < argc;
327 }
328 
329 
330 void Foam::argList::getRootCase()
331 {
332  fileName casePath;
333 
334  // [-case dir] specified
335  HashTable<string>::const_iterator iter = options_.find("case");
336 
337  if (iter != options_.end())
338  {
339  casePath = iter();
340  casePath.clean();
341 
342  if (casePath.empty() || casePath == ".")
343  {
344  // Handle degenerate form and '-case .' like no -case specified
345  casePath = cwd();
346  options_.erase("case");
347  }
348  else if (!casePath.isAbsolute() && casePath.name() == "..")
349  {
350  // Avoid relative cases ending in '..' - makes for very ugly names
351  casePath = cwd()/casePath;
352  casePath.clean();
353  }
354  }
355  else
356  {
357  // Nothing specified, use the current dir
358  casePath = cwd();
359  }
360 
361  rootPath_ = casePath.path();
362  globalCase_ = casePath.name();
363  case_ = globalCase_;
364 
365 
366  // Set the case and case-name as an environment variable
367  if (rootPath_.isAbsolute())
368  {
369  // Absolute path - use as-is
370  setEnv("FOAM_CASE", rootPath_/globalCase_, true);
371  setEnv("FOAM_CASENAME", globalCase_, true);
372  }
373  else
374  {
375  // Qualify relative path
376  casePath = cwd()/rootPath_/globalCase_;
377  casePath.clean();
378 
379  setEnv("FOAM_CASE", casePath, true);
380  setEnv("FOAM_CASENAME", casePath.name(), true);
381  }
382 }
383 
384 
385 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
386 
388 (
389  int& argc,
390  char**& argv,
391  bool checkArgs,
392  bool checkOpts,
393  const bool initialise
394 )
395 :
396  args_(argc),
397  options_(argc)
398 {
399  // Check if this run is a parallel run by searching for any parallel option
400  // If found call runPar which might filter argv
401  for (int argI = 0; argI < argc; ++argI)
402  {
403  if (argv[argI][0] == '-')
404  {
405  const char *optionName = &argv[argI][1];
406 
407  if (validParOptions.found(optionName))
408  {
409  parRunControl_.runPar(argc, argv);
410  break;
411  }
412  }
413  }
414 
415  // Convert argv -> args_ and capture ( ... ) lists
416  // for normal arguments and for options
417  regroupArgv(argc, argv);
418 
419  // Get executable name
420  args_[0] = fileName(argv[0]);
421  executable_ = fileName(argv[0]).name();
422 
423  // Check arguments and options, we already have argv[0]
424  int nArgs = 1;
425  argListStr_ = args_[0];
426 
427  for (int argI = 1; argI < args_.size(); ++argI)
428  {
429  argListStr_ += ' ';
430  argListStr_ += args_[argI];
431 
432  if (args_[argI][0] == '-')
433  {
434  const char *optionName = &args_[argI][1];
435 
436  if
437  (
438  (
439  validOptions.found(optionName)
440  && !validOptions[optionName].empty()
441  )
442  || (
443  validParOptions.found(optionName)
444  && !validParOptions[optionName].empty()
445  )
446  )
447  {
448  ++argI;
449  if (argI >= args_.size())
450  {
451  FatalError
452  <<"Option '-" << optionName
453  << "' requires an argument" << endl;
454  printUsage();
455  FatalError.exit();
456  }
457 
458  argListStr_ += ' ';
459  argListStr_ += args_[argI];
460  options_.insert(optionName, args_[argI]);
461  }
462  else
463  {
464  options_.insert(optionName, "");
465  }
466  }
467  else
468  {
469  if (nArgs != argI)
470  {
471  args_[nArgs] = args_[argI];
472  }
473  ++nArgs;
474  }
475  }
476 
477  args_.setSize(nArgs);
478 
479  parse(checkArgs, checkOpts, initialise);
480 }
481 
482 
484 (
485  const argList& args,
486  const HashTable<string>& options,
487  bool checkArgs,
488  bool checkOpts,
489  bool initialise
490 )
491 :
492  parRunControl_(args.parRunControl_),
493  args_(args.args_),
494  options_(options),
495  executable_(args.executable_),
496  rootPath_(args.rootPath_),
497  globalCase_(args.globalCase_),
498  case_(args.case_),
499  argListStr_(args.argListStr_)
500 {
501  parse(checkArgs, checkOpts, initialise);
502 }
503 
504 
506 (
507  bool checkArgs,
508  bool checkOpts,
509  bool initialise
510 )
511 {
512  // Help/documentation options:
513  // -help print the usage
514  // -doc display application documentation in browser
515  // -srcDoc display source code in browser
516  if
517  (
518  options_.found("help")
519  || options_.found("doc")
520  || options_.found("srcDoc")
521  )
522  {
523  if (options_.found("help"))
524  {
525  printUsage();
526  }
527 
528  // Only display one or the other
529  if (options_.found("srcDoc"))
530  {
531  displayDoc(true);
532  }
533  else if (options_.found("doc"))
534  {
535  displayDoc(false);
536  }
537 
538  ::exit(0);
539  }
540 
541  // Print the usage message and exit if the number of arguments is incorrect
542  if (!check(checkArgs, checkOpts))
543  {
544  FatalError.exit();
545  }
546 
547 
548  if (initialise)
549  {
550  string dateString = clock::date();
551  string timeString = clock::clockTime();
552 
553  // Print the banner once only for parallel runs
554  if (Pstream::master() && bannerEnabled)
555  {
557  << "Build : " << Foam::FOAMbuild << nl
558  << "Exec : " << argListStr_.c_str() << nl
559  << "Date : " << dateString.c_str() << nl
560  << "Time : " << timeString.c_str() << nl
561  << "Host : " << hostName() << nl
562  << "PID : " << pid() << endl;
563  }
564 
565  jobInfo.add("startDate", dateString);
566  jobInfo.add("startTime", timeString);
567  jobInfo.add("userName", userName());
568  jobInfo.add("foamVersion", word(FOAMversion));
569  jobInfo.add("code", executable_);
570  jobInfo.add("argList", argListStr_);
571  jobInfo.add("currentDir", cwd());
572  jobInfo.add("PPID", ppid());
573  jobInfo.add("PGID", pgid());
574 
575  // Add build information - only use the first word
576  {
577  std::string build(Foam::FOAMbuild);
578  std::string::size_type found = build.find(' ');
579  if (found != std::string::npos)
580  {
581  build.resize(found);
582  }
583  jobInfo.add("foamBuild", build);
584  }
585  }
586 
587 
588  // Set fileHandler. In increasing order of priority:
589  // 1. default = uncollated
590  // 2. environment var FOAM_FILEHANDLER
591  // 3. etc/controlDict optimisationSwitches 'fileHandler'
592  // 4. system/controlDict 'fileHandler' (not handled here; done in TimeIO.C)
593 
594  {
595  word handlerType(getEnv("FOAM_FILEHANDLER"));
596  HashTable<string>::const_iterator iter = options_.find("fileHandler");
597  if (iter != options_.end())
598  {
599  handlerType = iter();
600  }
601 
602  if (handlerType.empty())
603  {
604  handlerType = fileOperation::defaultFileHandler;
605  }
606 
607  autoPtr<fileOperation> handler
608  (
610  (
611  handlerType,
612  bannerEnabled
613  )
614  );
615  Foam::fileHandler(handler);
616  }
617 
618  // Case is a single processor run unless it is running parallel
619  int nProcs = 1;
620 
621  // Roots if running distributed
622  fileNameList roots;
623 
624  // If this actually is a parallel run
625  if (parRunControl_.parRun())
626  {
627  // For the master
628  if (Pstream::master())
629  {
630  // Establish rootPath_/globalCase_/case_ for master
631  getRootCase();
632 
633  // See if running distributed (different roots for different procs)
634  label dictNProcs = -1;
635  fileName source;
636 
637  if (options_.found("roots"))
638  {
639  source = "-roots";
640  IStringStream is(options_["roots"]);
641  roots = readList<fileName>(is);
642 
643  if (roots.size() != 1)
644  {
645  dictNProcs = roots.size()+1;
646  }
647  }
648  else
649  {
650  source = rootPath_/globalCase_/"system/decomposeParDict";
651  IFstream decompDictStream(source);
652 
653  if (!decompDictStream.good())
654  {
655  FatalError
656  << "Cannot read "
657  << decompDictStream.name()
658  << exit(FatalError);
659  }
660 
661  dictionary decompDict(decompDictStream);
662 
663  dictNProcs = readLabel
664  (
665  decompDict.lookup("numberOfSubdomains")
666  );
667 
668  if (decompDict.lookupOrDefault("distributed", false))
669  {
670  decompDict.lookup("roots") >> roots;
671  }
672  }
673 
674  // Convenience:
675  // when a single root is specified, use it for all processes
676  if (roots.size() == 1)
677  {
678  const fileName rootName(roots[0]);
679  roots.setSize(Pstream::nProcs()-1, rootName);
680 
681  // adjust dictNProcs for command-line '-roots' option
682  if (dictNProcs < 0)
683  {
684  dictNProcs = roots.size()+1;
685  }
686  }
687 
688 
689  // Check number of processors.
690  // nProcs => number of actual procs
691  // dictNProcs => number of procs specified in decompositionDict
692  // nProcDirs => number of processor directories
693  // (n/a when running distributed)
694  //
695  // - normal running : nProcs = dictNProcs = nProcDirs
696  // - decomposition to more processors : nProcs = dictNProcs
697  // - decomposition to fewer processors : nProcs = nProcDirs
698  if (dictNProcs > Pstream::nProcs())
699  {
700  FatalError
701  << source
702  << " specifies " << dictNProcs
703  << " processors but job was started with "
704  << Pstream::nProcs() << " processors."
705  << exit(FatalError);
706  }
707 
708 
709  // Distributed data
710  if (roots.size())
711  {
712  if (roots.size() != Pstream::nProcs()-1)
713  {
714  FatalError
715  << "number of entries in roots "
716  << roots.size()
717  << " is not equal to the number of slaves "
718  << Pstream::nProcs()-1
719  << exit(FatalError);
720  }
721 
722  forAll(roots, i)
723  {
724  roots[i].expand();
725  }
726 
727  // Distribute the master's argument list (with new root)
728  bool hadCaseOpt = options_.found("case");
729  for
730  (
731  int slave = Pstream::firstSlave();
732  slave <= Pstream::lastSlave();
733  slave++
734  )
735  {
736  options_.set("case", roots[slave-1]/globalCase_);
737 
739  toSlave << args_ << options_;
740  }
741  options_.erase("case");
742 
743  // Restore [-case dir]
744  if (hadCaseOpt)
745  {
746  options_.set("case", rootPath_/globalCase_);
747  }
748  }
749  else
750  {
751  // Possibly going to fewer processors.
752  // Check if all procDirs are there.
753  if (dictNProcs < Pstream::nProcs())
754  {
755  label nProcDirs = 0;
756  while
757  (
758  isDir
759  (
760  rootPath_/globalCase_/"processor"
761  + name(++nProcDirs)
762  )
763  )
764  {}
765 
766  if (nProcDirs != Pstream::nProcs())
767  {
768  FatalError
769  << "number of processor directories = "
770  << nProcDirs
771  << " is not equal to the number of processors = "
772  << Pstream::nProcs()
773  << exit(FatalError);
774  }
775  }
776 
777  // Distribute the master's argument list (unaltered)
778  for
779  (
780  int slave = Pstream::firstSlave();
781  slave <= Pstream::lastSlave();
782  slave++
783  )
784  {
786  toSlave << args_ << options_;
787  }
788  }
789  }
790  else
791  {
792  // Collect the master's argument list
793  IPstream fromMaster
794  (
797  );
798  fromMaster >> args_ >> options_;
799 
800  // Establish rootPath_/globalCase_/case_ for slave
801  getRootCase();
802  }
803 
804  nProcs = Pstream::nProcs();
805  case_ = globalCase_/(word("processor") + name(Pstream::myProcNo()));
806  }
807  else
808  {
809  // Establish rootPath_/globalCase_/case_
810  getRootCase();
811  case_ = globalCase_;
812  }
813 
814 
815  stringList slaveProcs;
816 
817  // Collect slave machine/pid
818  if (parRunControl_.parRun())
819  {
820  if (Pstream::master())
821  {
822  slaveProcs.setSize(Pstream::nProcs() - 1);
823  label proci = 0;
824  for
825  (
826  int slave = Pstream::firstSlave();
827  slave <= Pstream::lastSlave();
828  slave++
829  )
830  {
831  IPstream fromSlave(Pstream::commsTypes::scheduled, slave);
832 
833  string slaveBuild;
834  string slaveMachine;
835  label slavePid;
836  fromSlave >> slaveBuild >> slaveMachine >> slavePid;
837 
838  slaveProcs[proci++] = slaveMachine + "." + name(slavePid);
839 
840  // Check build string to make sure all processors are running
841  // the same build
842  if (slaveBuild != Foam::FOAMbuild)
843  {
845  << "Master is running version " << Foam::FOAMbuild
846  << "; slave " << proci << " is running version "
847  << slaveBuild
848  << exit(FatalError);
849  }
850  }
851  }
852  else
853  {
854  OPstream toMaster
855  (
858  );
859  toMaster << string(Foam::FOAMbuild) << hostName() << pid();
860  }
861  }
862 
863 
864  if (Pstream::master() && bannerEnabled)
865  {
866  Info<< "Case : " << (rootPath_/globalCase_).c_str() << nl
867  << "nProcs : " << nProcs << endl;
868 
869  if (parRunControl_.parRun())
870  {
871  Info<< "Slaves : " << slaveProcs << nl;
872  if (roots.size())
873  {
874  Info<< "Roots : " << roots << nl;
875  }
876  Info<< "Pstream initialized with:" << nl
877  << " floatTransfer : " << Pstream::floatTransfer << nl
878  << " nProcsSimpleSum : " << Pstream::nProcsSimpleSum << nl
879  << " commsType : "
881  << " polling iterations : " << Pstream::nPollProcInterfaces
882  << endl;
883  }
884  }
885 
886  if (initialise)
887  {
888  jobInfo.add("root", rootPath_);
889  jobInfo.add("case", globalCase_);
890  jobInfo.add("nProcs", nProcs);
891  if (slaveProcs.size())
892  {
893  jobInfo.add("slaves", slaveProcs);
894  }
895  if (roots.size())
896  {
897  jobInfo.add("roots", roots);
898  }
899  jobInfo.write();
900 
901  // Switch on signal trapping. We have to wait until after Pstream::init
902  // since this sets up its own ones.
903  sigFpe_.set(bannerEnabled);
904  sigInt_.set(bannerEnabled);
905  sigQuit_.set(bannerEnabled);
906  sigSegv_.set(bannerEnabled);
907 
908  if (bannerEnabled)
909  {
910  Info<< "fileModificationChecking : "
911  << "Monitoring run-time modified files using "
913  [
915  ];
916  if
917  (
918  (
921  )
922  || (
925  )
926  )
927  {
928  Info<< " (fileModificationSkew "
930  }
931  Info<< endl;
932 
933  Info<< "allowSystemOperations : ";
935  {
936  Info<< "Allowing user-supplied system call operations" << endl;
937  }
938  else
939  {
940  Info<< "Disallowing user-supplied system call operations"
941  << endl;
942  }
943  }
944 
945  if (Pstream::master() && bannerEnabled)
946  {
947  Info<< endl;
949  }
950  }
951 }
952 
953 
954 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
955 
957 {
958  jobInfo.end();
959 
960  // Delete file handler to flush any remaining IO
961  autoPtr<fileOperation> dummy(nullptr);
962  fileHandler(dummy);
963 }
964 
965 
966 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
967 
968 bool Foam::argList::setOption(const word& opt, const string& param)
969 {
970  bool changed = false;
971 
972  // Only allow valid options
973  if (validOptions.found(opt))
974  {
975  // Some options are to be protected
976  if
977  (
978  opt == "case"
979  || opt == "parallel"
980  || opt == "roots"
981  )
982  {
983  FatalError
984  <<"used argList::setOption on a protected option: '"
985  << opt << "'" << endl;
986  FatalError.exit();
987  }
988 
989  if (validOptions[opt].empty())
990  {
991  // Bool option
992  if (!param.empty())
993  {
994  // Disallow change of type
995  FatalError
996  <<"used argList::setOption to change bool to non-bool: '"
997  << opt << "'" << endl;
998  FatalError.exit();
999  }
1000  else
1001  {
1002  // Did not previously exist
1003  changed = !options_.found(opt);
1004  }
1005  }
1006  else
1007  {
1008  // Non-bool option
1009  if (param.empty())
1010  {
1011  // Disallow change of type
1012  FatalError
1013  <<"used argList::setOption to change non-bool to bool: '"
1014  << opt << "'" << endl;
1015  FatalError.exit();
1016  }
1017  else
1018  {
1019  // Existing value needs changing, or did not previously exist
1020  changed = options_.found(opt) ? options_[opt] != param : true;
1021  }
1022  }
1023  }
1024  else
1025  {
1026  FatalError
1027  <<"used argList::setOption on an invalid option: '"
1028  << opt << "'" << nl << "allowed are the following:"
1029  << validOptions << endl;
1030  FatalError.exit();
1031  }
1032 
1033  // Set/change the option as required
1034  if (changed)
1035  {
1036  options_.set(opt, param);
1037  }
1038 
1039  return changed;
1040 }
1041 
1042 
1044 {
1045  // Only allow valid options
1046  if (validOptions.found(opt))
1047  {
1048  // Some options are to be protected
1049  if
1050  (
1051  opt == "case"
1052  || opt == "parallel"
1053  || opt == "roots"
1054  )
1055  {
1056  FatalError
1057  <<"used argList::unsetOption on a protected option: '"
1058  << opt << "'" << endl;
1059  FatalError.exit();
1060  }
1061 
1062  // Remove the option, return true if state changed
1063  return options_.erase(opt);
1064  }
1065  else
1066  {
1067  FatalError
1068  <<"used argList::unsetOption on an invalid option: '"
1069  << opt << "'" << nl << "allowed are the following:"
1070  << validOptions << endl;
1071  FatalError.exit();
1072  }
1073 
1074  return false;
1075 }
1076 
1077 
1079 {
1080  // Output notes directly - no automatic text wrapping
1081  if (!notes.empty())
1082  {
1083  Info<< nl;
1085  {
1086  Info<< iter().c_str() << nl;
1087  }
1088  }
1089 }
1090 
1091 
1093 {
1094  Info<< "\nUsage: " << executable_ << " [OPTIONS]";
1095 
1097  {
1098  Info<< " <" << iter().c_str() << '>';
1099  }
1100 
1101  Info<< "\noptions:\n";
1102 
1103  wordList opts = validOptions.sortedToc();
1104  forAll(opts, optI)
1105  {
1106  const word& optionName = opts[optI];
1107 
1108  HashTable<string>::const_iterator iter = validOptions.find(optionName);
1109  Info<< " -" << optionName;
1110  label len = optionName.size() + 3; // Length includes leading ' -'
1111 
1112  if (iter().size())
1113  {
1114  // Length includes space and between option/param and '<>'
1115  len += iter().size() + 3;
1116  Info<< " <" << iter().c_str() << '>';
1117  }
1118 
1120  optionUsage.find(optionName);
1121 
1122  if (usageIter != optionUsage.end())
1123  {
1124  printOptionUsage
1125  (
1126  len,
1127  usageIter()
1128  );
1129  }
1130  else
1131  {
1132  Info<< nl;
1133  }
1134  }
1135 
1136  // Place srcDoc/doc/help options at the end
1137  Info<< " -srcDoc";
1138  printOptionUsage
1139  (
1140  9,
1141  "display source code in browser"
1142  );
1143 
1144  Info<< " -doc";
1145  printOptionUsage
1146  (
1147  6,
1148  "display application documentation in browser"
1149  );
1150 
1151  Info<< " -help";
1152  printOptionUsage
1153  (
1154  7,
1155  "print the usage"
1156  );
1157 
1158 
1159  printNotes();
1160 
1161  Info<< nl
1162  <<"Using: OpenFOAM-" << Foam::FOAMversion
1163  << " (see www.OpenFOAM.org)" << nl
1164  <<"Build: " << Foam::FOAMbuild << nl
1165  << endl;
1166 }
1167 
1168 
1169 void Foam::argList::displayDoc(bool source) const
1170 {
1171  const dictionary& docDict = debug::controlDict().subDict("Documentation");
1172  List<fileName> docDirs(docDict.lookup("doxyDocDirs"));
1173  fileName docExt(docDict.lookup("doxySourceFileExt"));
1174 
1175  // For source code: change foo_8C.html to foo_8C_source.html
1176  if (source)
1177  {
1178  docExt.replace(".", "_source.");
1179  }
1180 
1181  fileName docFile;
1182  fileName httpServer;
1183  bool found = false;
1184 
1185  forAll(docDirs, dirI)
1186  {
1187  // An HTTP server is treated as a special case ...
1188  if (docDirs[dirI].component(0) == "http:")
1189  {
1190  httpServer = docDirs[dirI]/executable_ + docExt;
1191  }
1192  else
1193  {
1194  // ... all other entries are treated as local directories
1195 
1196  // Remove the optional "file://"
1197  if (docDirs[dirI].component(0) == "file:")
1198  {
1199  docDirs[dirI].replace("file://", string::null);
1200  }
1201 
1202 
1203  // Expand the file name
1204  docFile = docDirs[dirI]/executable_ + docExt;
1205  docFile.expand();
1206 
1207  // Check the existence of the file
1208  if (isFile(docFile))
1209  {
1210  found = true;
1211  break;
1212  }
1213  }
1214  }
1215 
1216  if (found || httpServer != fileName::null)
1217  {
1218  string docBrowser = getEnv("FOAM_DOC_BROWSER");
1219  if (docBrowser.empty())
1220  {
1221  docDict.lookup("docBrowser") >> docBrowser;
1222  }
1223 
1224  if (found)
1225  {
1226  docBrowser += " file://" + docFile;
1227  }
1228  else
1229  {
1230  docBrowser += " " + httpServer;
1231  }
1232 
1233  Info<< "Show documentation: " << docBrowser.c_str() << endl;
1234 
1235  system(docBrowser);
1236  }
1237  else
1238  {
1239  Info<< nl
1240  << "No documentation found for " << executable_
1241  << ", but you can use -help to display the usage\n" << endl;
1242  }
1243 }
1244 
1245 
1246 bool Foam::argList::check(bool checkArgs, bool checkOpts) const
1247 {
1248  bool ok = true;
1249 
1250  if (Pstream::master())
1251  {
1252  if (checkArgs && args_.size() - 1 != validArgs.size())
1253  {
1254  FatalError
1255  << "Wrong number of arguments, expected " << validArgs.size()
1256  << " found " << args_.size() - 1 << endl;
1257  ok = false;
1258  }
1259 
1260  if (checkOpts)
1261  {
1262  forAllConstIter(HashTable<string>, options_, iter)
1263  {
1264  if
1265  (
1266  !validOptions.found(iter.key())
1267  && !validParOptions.found(iter.key())
1268  )
1269  {
1270  FatalError
1271  << "Invalid option: -" << iter.key() << endl;
1272  ok = false;
1273  }
1274  }
1275  }
1276 
1277  if (!ok)
1278  {
1279  printUsage();
1280  }
1281  }
1282 
1283  return ok;
1284 }
1285 
1286 
1288 {
1289  if (!fileHandler().isDir(rootPath()))
1290  {
1291  FatalError
1292  << executable_
1293  << ": cannot open root directory " << rootPath()
1294  << endl;
1295 
1296  return false;
1297  }
1298 
1299  fileName pathDir(fileHandler().filePath(path()));
1300 
1301  if (pathDir.empty() && Pstream::master())
1302  {
1303  // Allow slaves on non-existing processor directories, created later
1304  // (e.g. redistributePar)
1305  FatalError
1306  << executable_
1307  << ": cannot open case directory " << path()
1308  << endl;
1309 
1310  return false;
1311  }
1312 
1313  return true;
1314 }
1315 
1316 
1317 // ************************************************************************* //
static bool floatTransfer
Should compact transfer be used in which floats replace doubles.
Definition: UPstream.H:262
string getEnv(const word &)
Return environment variable of given name.
Definition: POSIX.C:104
bool checkRootCase() const
Check root path and case path.
Definition: argList.C:1287
void set(const bool verbose)
Activate SIGQUIT signal handler.
Definition: sigQuit.C:82
const word & executable() const
Name of executable without the path.
Definition: argListI.H:30
bool setOption(const word &opt, const string &param="")
Set option directly (use with caution)
Definition: argList.C:968
#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:135
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:406
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:481
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:1043
static void addUsage(const word &opt, const string &usage)
Add option usage information to optionUsage.
Definition: argList.C:110
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:78
argList(int &argc, char **&argv, bool checkArgs=true, bool checkOpts=true, bool initialise=true)
Construct from argc and argv.
Definition: argList.C:388
const fileName & rootPath() const
Return root path.
Definition: argListI.H:36
static int firstSlave()
Process index of first slave.
Definition: UPstream.H:435
Template class for non-intrusive linked lists.
Definition: LList.H:51
pid_t ppid()
Return the parent PID of this process.
Definition: POSIX.C:86
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:163
static const fileName null
An empty fileName.
Definition: fileName.H:97
static int myProcNo(const label communicator=0)
Number of this process (starting from masterNo() = 0)
Definition: UPstream.H:418
static int nProcsSimpleSum
Number of processors at which the sum algorithm changes from linear.
Definition: UPstream.H:266
static SLList< string > notes
Additional notes for usage.
Definition: argList.H:166
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:412
Foam::argList::initValidTables dummyInitValidTables
Definition: argList.C:79
static void noParallel()
Remove the parallel options.
Definition: argList.C:148
static SLList< string > validArgs
A list of valid (mandatory) arguments.
Definition: argList.H:154
static bool postProcess(int argc, char *argv[])
Return true if the post-processing option is specified.
Definition: argList.C:256
const char *const FOAMversion
void runPar(int &argc, char **&argv)
Definition: parRun.H:66
virtual ~argList()
Destructor.
Definition: argList.C:956
bool good() const
Return true if next operation might succeed.
Definition: IOstream.H:333
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:814
static autoPtr< fileOperation > New(const word &type, const bool verbose)
Select type.
const dictionary & subDict(const word &) const
Find and return a sub-dictionary.
Definition: dictionary.C:692
void parse(bool checkArgs, bool checkOpts, bool initialise)
Parse.
Definition: argList.C:506
Input inter-processor communications stream.
Definition: IPstream.H:50
Functions used by OpenFOAM that are specific to POSIX compliant operating systems and need to be repl...
dimensionedScalar pos(const dimensionedScalar &ds)
void displayDoc(bool source=false) const
Display documentation in browser.
Definition: argList.C:1169
static int nPollProcInterfaces
Number of polling cycles in processor updates.
Definition: UPstream.H:272
string hostName(const bool full=false)
Return the system&#39;s host name, as per hostname(1)
Definition: POSIX.C:132
static HashTable< string > validParOptions
A list of valid parallel options.
Definition: argList.H:160
void printNotes() const
Print notes (if any)
Definition: argList.C:1078
bool isAbsolute() const
Return true if file name is absolute.
Definition: fileName.C:58
bool isDir(const fileName &, const bool followLink=true)
Does the name exist as a DIRECTORY in the file system?
Definition: POSIX.C:536
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
const fileName & name() const
Return the name of the stream.
Definition: IFstream.H:116
static int allowSystemOperations
Flag if system operations are allowed.
Definition: dynamicCode.H:161
static void addOption(const word &opt, const string &param="", const string &usage="")
Add to an option to validOptions with usage information.
Definition: argList.C:95
word name() const
Return file name (part beyond last /)
Definition: fileName.C:180
string userName()
Return the user&#39;s login name.
Definition: POSIX.C:172
label size() const
Return the number of arguments.
Definition: argListI.H:84
const fileOperation & fileHandler()
Get current file handler.
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
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
static const string null
An empty string.
Definition: string.H:86
pid_t pid()
Return the PID of this process.
Definition: POSIX.C:80
bool isFile(const fileName &, const bool checkGzip=true, const bool followLink=true)
Does the name exist as a FILE in the file system?
Definition: POSIX.C:551
static const char nl
Definition: Ostream.H:262
static fileCheckTypes fileModificationChecking
Type of file modification checking.
Definition: IOobject.H:208
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:92
word name(const complex &)
Return a string representation of a complex.
Definition: complex.C:47
fileName path() const
Return the path to the caseName.
Definition: argListI.H:60
static string date()
Return the current wall-clock date as a string.
Definition: clock.C:77
static const NamedEnum< fileCheckTypes, 4 > fileCheckTypesNames
Definition: IOobject.H:131
static commsTypes defaultCommsType
Default commsType.
Definition: UPstream.H:269
void setSize(const label)
Reset size of List.
Definition: List.C:281
string & replace(const string &oldStr, const string &newStr, size_type start=0)
Replace first occurence of sub-string oldStr with newStr.
Definition: string.C:56
static label nProcs(const label communicator=0)
Number of processes in parallel run.
Definition: UPstream.H:400
void set(const bool verbose)
Activate SIGINT signal handler.
Definition: sigInt.C:80
bool isspace(char c)
Definition: char.H:53
static word defaultFileHandler
Default fileHandler.
Definition: fileOperation.H:81
T lookupOrDefault(const word &, const T &, bool recursive=false, bool patternMatch=true) const
Find and return a T,.
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:248
JobInfo jobInfo
Definition: JobInfo.C:35
void set(const bool verbose)
Activate SIGFPE signal handler when FOAM_SIGFPE is set.
Definition: sigFpe.C:152
static float fileModificationSkew
Definition: regIOobject.H:124
messageStream Info
bool check(bool checkArgs=true, bool checkOpts=true) const
Check argument list.
Definition: argList.C:1246
static void noBanner()
Disable emitting the banner information.
Definition: argList.C:142
fileName path() const
Return directory path name (part before last /)
Definition: fileName.C:250
An auto-pointer similar to the STL auto_ptr but with automatic casting to a reference to the type and...
Definition: PtrList.H:52
static void addBoolOption(const word &opt, const string &usage="")
Add to a bool option to validOptions with usage information.
Definition: argList.C:85
static void addNote(const string &)
Add extra notes for the usage information.
Definition: argList.C:126
void set(const bool verbose)
Activate SIGSEGV signal handler.
Definition: sigSegv.C:82
bool parRun() const
Definition: parRun.H:77
static string::size_type usageMin
Min offset for displaying usage (default: 20)
Definition: argList.H:169
const char *const FOAMbuild
dictionary & controlDict()
The central control dictionary.
Definition: debug.C:94
void printUsage() const
Print usage.
Definition: argList.C:1092
A class for handling character strings derived from std::string.
Definition: string.H:74
void component(FieldField< Field, typename FieldField< Field, Type >::cmptType > &sf, const FieldField< Field, Type > &f, const direction d)
#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:122
int system(const std::string &command)
Execute the specified command.
Definition: POSIX.C:1193
ITstream & lookup(const word &, bool recursive=false, bool patternMatch=true) const
Find and return an entry data stream.
Definition: dictionary.C:576
static int lastSlave(const label communicator=0)
Process index of last slave.
Definition: UPstream.H:441