dictionary.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration | Website: https://openfoam.org
5  \\ / A nd | Copyright (C) 2011-2024 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 "dictionary.H"
27 #include "dictionaryEntry.H"
28 #include "regExp.H"
29 #include "OSHA1stream.H"
30 #include "unitConversion.H"
31 
32 /* * * * * * * * * * * * * * * Static Member Data * * * * * * * * * * * * * */
33 
34 namespace Foam
35 {
37 }
38 
40 
42 (
43  Foam::debug::infoSwitch("writeOptionalEntries", 0)
44 );
45 
46 
47 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
48 
49 const Foam::entry* Foam::dictionary::lookupScopedSubEntryPtr
50 (
51  const word& keyword,
52  bool recursive,
53  bool patternMatch
54 ) const
55 {
56  // Check for the dictionary boundary marker
57  const string::size_type emarkPos = keyword.find('!');
58 
59  if (emarkPos == string::npos || emarkPos == 0)
60  {
61  // Lookup in this dictionary
62 
63  string::size_type slashPos = keyword.find('/');
64 
65  if (slashPos == string::npos)
66  {
67  // Non-scoped lookup
68  return lookupEntryPtr(keyword, recursive, patternMatch);
69  }
70  else
71  {
72  // Extract the first word
73  word firstWord = keyword.substr(0, slashPos);
74  slashPos++;
75 
76  if (firstWord == ".")
77  {
78  return lookupScopedSubEntryPtr
79  (
80  keyword.substr(slashPos),
81  false,
82  patternMatch
83  );
84  }
85  else if (firstWord == "..")
86  {
87  // Go to parent
88  if (&parent_ == &dictionary::null)
89  {
91  << "No parent of current dictionary"
92  << " when searching for "
93  << keyword.substr(slashPos, keyword.size() - slashPos)
94  << exit(FatalIOError);
95  }
96 
97  return parent_.lookupScopedSubEntryPtr
98  (
99  keyword.substr(slashPos),
100  false,
101  patternMatch
102  );
103  }
104  else
105  {
106  const entry* entPtr = lookupScopedSubEntryPtr
107  (
108  firstWord,
109  recursive,
110  patternMatch
111  );
112 
113  if (entPtr && entPtr->isDict())
114  {
115  return entPtr->dict().lookupScopedSubEntryPtr
116  (
117  keyword.substr(slashPos, keyword.size() - slashPos),
118  false,
119  patternMatch
120  );
121  }
122  else
123  {
124  return nullptr;
125  }
126  }
127  }
128  }
129  else
130  {
131  // Lookup in the dictionary specified by file name
132  // created from the part of the keyword before the '!'
133 
134  fileName fName = keyword.substr(0, emarkPos);
135 
136  if (!fName.isAbsolute())
137  {
138  fName = topDict().name().path()/fName;
139  }
140 
141  if (fName == topDict().name())
142  {
144  << "Attempt to re-read current dictionary " << fName
145  << " for keyword "
146  << keyword
147  << exit(FatalIOError);
148  }
149 
150  const word localKeyword = keyword.substr
151  (
152  emarkPos + 1,
153  keyword.size() - emarkPos - 1
154  );
155 
156  includedDictionary dict(fName, *this);
157 
158  const Foam::entry* entryPtr = dict.lookupScopedEntryPtr
159  (
160  localKeyword,
161  recursive,
162  patternMatch
163  );
164 
165  if (!entryPtr)
166  {
168  << "keyword " << localKeyword
169  << " is undefined in dictionary "
170  << dict.name()
171  << exit(FatalIOError);
172  }
173 
174  return entryPtr->clone(*this).ptr();
175  }
176 }
177 
178 
179 bool Foam::dictionary::findInPatterns
180 (
181  const bool patternMatch,
182  const word& Keyword,
184  DLList<autoPtr<regExp>>::const_iterator& reLink
185 ) const
186 {
187  if (patternEntries_.size())
188  {
189  while (wcLink != patternEntries_.end())
190  {
191  if
192  (
193  patternMatch
194  ? reLink()->match(Keyword)
195  : wcLink()->keyword() == Keyword
196  )
197  {
198  return true;
199  }
200 
201  ++reLink;
202  ++wcLink;
203  }
204  }
205 
206  return false;
207 }
208 
209 
210 bool Foam::dictionary::findInPatterns
211 (
212  const bool patternMatch,
213  const word& Keyword,
214  DLList<entry*>::iterator& wcLink,
215  DLList<autoPtr<regExp>>::iterator& reLink
216 )
217 {
218  if (patternEntries_.size())
219  {
220  while (wcLink != patternEntries_.end())
221  {
222  if
223  (
224  patternMatch
225  ? reLink()->match(Keyword)
226  : wcLink()->keyword() == Keyword
227  )
228  {
229  return true;
230  }
231 
232  ++reLink;
233  ++wcLink;
234  }
235  }
236 
237  return false;
238 }
239 
240 
241 void Foam::dictionary::assertNoConvertUnits
242 (
243  const char* typeName,
244  const word& keyword,
245  const unitConversion& defaultUnits,
246  ITstream& is
247 ) const
248 {
249  if (!defaultUnits.standard())
250  {
252  << "Unit conversions are not supported when reading "
253  << typeName << " types" << abort(FatalError);
254  }
255 }
256 
257 
258 template<class T>
259 T Foam::dictionary::readTypeAndConvertUnits
260 (
261  const word& keyword,
262  const unitConversion& defaultUnits,
263  ITstream& is
264 ) const
265 {
266  // Read the units if they are before the value
267  unitConversion units(defaultUnits);
268  const bool haveUnits = units.readIfPresent(keyword, *this, is);
269 
270  // Read the value
271  T value = pTraits<T>(is);
272 
273  // Read the units if they are after the value
274  if (!haveUnits && !is.eof())
275  {
276  units.readIfPresent(keyword, *this, is);
277  }
278 
279  // Modify the value by the unit conversion
280  units.makeStandard(value);
281 
282  return value;
283 }
284 
285 
286 #define IMPLEMENT_SPECIALISED_READ_TYPE(T, nullArg) \
287  \
288  template<> \
289  Foam::T Foam::dictionary::readType \
290  ( \
291  const word& keyword, \
292  const unitConversion& defaultUnits, \
293  ITstream& is \
294  ) const \
295  { \
296  return readTypeAndConvertUnits<T>(keyword, defaultUnits, is); \
297  } \
298  \
299  template<> \
300  Foam::T Foam::dictionary::readType \
301  ( \
302  const word& keyword, \
303  ITstream& is \
304  ) const \
305  { \
306  return readTypeAndConvertUnits<T>(keyword, unitAny, is); \
307  }
308 
309 #define IMPLEMENT_SPECIALISED_READ_LIST_TYPE(T, nullArg) \
310  IMPLEMENT_SPECIALISED_READ_TYPE(List<Foam::T>, nullArg)
311 
314 
315 #undef IMPLEMENT_SPECIALISED_READ_TYPE
316 
317 
318 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
319 
321 :
322  parent_(dictionary::null)
323 {}
324 
325 
327 :
329  parent_(dictionary::null)
330 {}
331 
332 
334 (
335  const dictionary& parentDict,
336  const dictionary& dict
337 )
338 :
340  IDLList<entry>(dict, *this),
341  parent_(parentDict)
342 {
343  forAllIter(IDLList<entry>, *this, iter)
344  {
345  hashedEntries_.insert(iter().keyword(), &iter());
346 
347  if (iter().keyword().isPattern())
348  {
349  patternEntries_.insert(&iter());
350  patternRegexps_.insert
351  (
352  autoPtr<regExp>(new regExp(iter().keyword()))
353  );
354  }
355  }
356 }
357 
358 
360 (
361  const dictionary& dict
362 )
363 :
365  IDLList<entry>(dict, *this),
366  parent_(dictionary::null)
367 {
368  forAllIter(IDLList<entry>, *this, iter)
369  {
370  hashedEntries_.insert(iter().keyword(), &iter());
371 
372  if (iter().keyword().isPattern())
373  {
374  patternEntries_.insert(&iter());
375  patternRegexps_.insert
376  (
377  autoPtr<regExp>(new regExp(iter().keyword()))
378  );
379  }
380  }
381 }
382 
383 
385 (
386  const dictionary* dictPtr
387 )
388 :
389  parent_(dictionary::null)
390 {
391  if (dictPtr)
392  {
393  operator=(*dictPtr);
394  }
395 }
396 
397 
399 {
400  return autoPtr<dictionary>(new dictionary(*this));
401 }
402 
403 
404 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
405 
407 {
408  // cerr<< "~dictionary() " << name() << " " << long(this) << std::endl;
409 }
410 
411 
412 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
413 
415 {
416  const dictionary& p = parent();
417 
418  if (&p != this && !p.name().empty())
419  {
420  return p.topDict();
421  }
422  else
423  {
424  return *this;
425  }
426 }
427 
428 
430 {
431  const dictionary& p = parent();
432 
433  if (&p != this && !p.name().empty())
434  {
435  const word pKeyword = p.topDictKeyword();
436  const char pSeparator = '/';
437  return
438  pKeyword == word::null
439  ? dictName()
440  : word(pKeyword + pSeparator + dictName());
441  }
442  else
443  {
444  return word::null;
445  }
446 }
447 
448 
450 {
451  if (size())
452  {
453  return first()->startLineNumber();
454  }
455  else
456  {
457  return -1;
458  }
459 }
460 
461 
463 {
464  if (size())
465  {
466  return last()->endLineNumber();
467  }
468  else
469  {
470  return -1;
471  }
472 }
473 
474 
476 {
477  OSHA1stream os;
478 
479  // Process entries
480  forAllConstIter(IDLList<entry>, *this, iter)
481  {
482  os << *iter;
483  }
484 
485  return os.digest();
486 }
487 
488 
490 {
491  // Serialise dictionary into a string
492  OStringStream os;
493  write(os, false);
494  IStringStream is(os.str());
495 
496  // Parse string as tokens
497  DynamicList<token> tokens;
498  token t;
499  while (is.read(t))
500  {
501  tokens.append(t);
502  }
503 
504  return tokenList(move(tokens));
505 }
506 
507 
509 (
510  const word& keyword,
511  bool recursive,
512  bool patternMatch
513 ) const
514 {
515  if (hashedEntries_.found(keyword))
516  {
517  return true;
518  }
519  else
520  {
521  if (patternMatch && patternEntries_.size())
522  {
524  patternEntries_.begin();
526  patternRegexps_.begin();
527 
528  // Find in patterns using regular expressions only
529  if (findInPatterns(patternMatch, keyword, wcLink, reLink))
530  {
531  return true;
532  }
533  }
534 
535  if (recursive && &parent_ != &dictionary::null)
536  {
537  return parent_.found(keyword, recursive, patternMatch);
538  }
539  else
540  {
541  return false;
542  }
543  }
544 }
545 
546 
548 (
549  const word& keyword,
550  bool recursive,
551  bool patternMatch
552 ) const
553 {
554  HashTable<entry*>::const_iterator iter = hashedEntries_.find(keyword);
555 
556  if (iter == hashedEntries_.end())
557  {
558  if (patternMatch && patternEntries_.size())
559  {
561  patternEntries_.begin();
563  patternRegexps_.begin();
564 
565  // Find in patterns using regular expressions only
566  if (findInPatterns(patternMatch, keyword, wcLink, reLink))
567  {
568  return wcLink();
569  }
570  }
571 
572  if (recursive && &parent_ != &dictionary::null)
573  {
574  return parent_.lookupEntryPtr(keyword, recursive, patternMatch);
575  }
576  else
577  {
578  return nullptr;
579  }
580  }
581 
582  return iter();
583 }
584 
585 
587 (
588  const word& keyword,
589  bool recursive,
590  bool patternMatch
591 )
592 {
593  HashTable<entry*>::iterator iter = hashedEntries_.find(keyword);
594 
595  if (iter == hashedEntries_.end())
596  {
597  if (patternMatch && patternEntries_.size())
598  {
599  DLList<entry*>::iterator wcLink =
600  patternEntries_.begin();
602  patternRegexps_.begin();
603 
604  // Find in patterns using regular expressions only
605  if (findInPatterns(patternMatch, keyword, wcLink, reLink))
606  {
607  return wcLink();
608  }
609  }
610 
611  if (recursive && &parent_ != &dictionary::null)
612  {
613  return const_cast<dictionary&>(parent_).lookupEntryPtr
614  (
615  keyword,
616  recursive,
617  patternMatch
618  );
619  }
620  else
621  {
622  return nullptr;
623  }
624  }
625 
626  return iter();
627 }
628 
629 
631 (
632  const wordList& keywords,
633  bool recursive,
634  bool patternMatch
635 ) const
636 {
637  const entry* result = nullptr;
638 
639  forAll(keywords, keywordi)
640  {
641  const entry* entryPtr =
642  lookupEntryPtr(keywords[keywordi], recursive, patternMatch);
643 
644  if (entryPtr)
645  {
646  if (result)
647  {
648  IOWarningInFunction((*this))
649  << "Duplicate backwards compatible keywords \""
650  << result->keyword() << "\" and \"" << entryPtr->keyword()
651  << "\" are defined in dictionary " << name() << endl
652  << "The preferred keyword for this entry is \""
653  << keywords[0] << "\"" << endl;
654  }
655  else
656  {
657  result = entryPtr;
658  }
659  }
660  }
661 
662  return result;
663 }
664 
665 
667 (
668  const word& keyword,
669  bool recursive,
670  bool patternMatch
671 ) const
672 {
673  const entry* entryPtr = lookupEntryPtr(keyword, recursive, patternMatch);
674 
675  if (entryPtr == nullptr)
676  {
678  << "keyword " << keyword << " is undefined in dictionary "
679  << name()
680  << exit(FatalIOError);
681  }
682 
683  return *entryPtr;
684 }
685 
686 
688 (
689  const wordList& keywords,
690  bool recursive,
691  bool patternMatch
692 ) const
693 {
694  const entry* entryPtr =
695  lookupEntryPtrBackwardsCompatible(keywords, recursive, patternMatch);
696 
697  if (entryPtr == nullptr)
698  {
699  // Generate error message using the first keyword
700  return lookupEntry(keywords[0], recursive, patternMatch);
701  }
702  else
703  {
704  return *entryPtr;
705  }
706 }
707 
708 
710 (
711  const word& keyword,
712  bool recursive,
713  bool patternMatch
714 ) const
715 {
716  return lookupEntry(keyword, recursive, patternMatch).stream();
717 }
718 
719 
721 (
722  const wordList& keywords,
723  bool recursive,
724  bool patternMatch
725 ) const
726 {
727  return lookupEntryBackwardsCompatible
728  (
729  keywords,
730  recursive,
731  patternMatch
732  ).stream();
733 }
734 
735 
737 (
738  const word& keyword,
739  bool recursive,
740  bool patternMatch
741 ) const
742 {
743  // '!' indicates the top-level directory
744  if (keyword[0] == '!')
745  {
746  // Go up to top level
747  const dictionary* dictPtr = this;
748  while (&dictPtr->parent_ != &dictionary::null)
749  {
750  dictPtr = &dictPtr->parent_;
751  }
752 
753  // At top. Recurse to find entries
754  return dictPtr->lookupScopedSubEntryPtr
755  (
756  keyword.substr(1, keyword.size() - 1),
757  false,
758  patternMatch
759  );
760  }
761  else
762  {
763  return lookupScopedSubEntryPtr
764  (
765  keyword,
766  recursive,
767  patternMatch
768  );
769  }
770 }
771 
772 
774 {
775  word varName = keyword(1, keyword.size() - 1);
776 
777  // Lookup the variable name in the given dictionary
778  const entry* ePtr = lookupScopedEntryPtr(varName, true, true);
779 
780  // If defined insert its entries into this dictionary
781  if (ePtr != nullptr)
782  {
783  const dictionary& addDict = ePtr->dict();
784 
785  forAllConstIter(IDLList<entry>, addDict, iter)
786  {
787  add(iter());
788  }
789 
790  return true;
791  }
792 
793  return false;
794 }
795 
796 
797 bool Foam::dictionary::isDict(const word& keyword) const
798 {
799  // Find non-recursive with patterns
800  const entry* entryPtr = lookupEntryPtr(keyword, false, true);
801 
802  if (entryPtr)
803  {
804  return entryPtr->isDict();
805  }
806  else
807  {
808  return false;
809  }
810 }
811 
812 
814 {
815  const entry* entryPtr = lookupEntryPtr(keyword, false, true);
816 
817  if (entryPtr)
818  {
819  return &entryPtr->dict();
820  }
821  else
822  {
823  return nullptr;
824  }
825 }
826 
827 
829 {
830  entry* entryPtr = lookupEntryPtr(keyword, false, true);
831 
832  if (entryPtr)
833  {
834  return &entryPtr->dict();
835  }
836  else
837  {
838  return nullptr;
839  }
840 }
841 
842 
843 const Foam::dictionary& Foam::dictionary::subDict(const word& keyword) const
844 {
845  const entry* entryPtr = lookupEntryPtr(keyword, false, true);
846 
847  if (entryPtr == nullptr)
848  {
850  << "keyword " << keyword << " is undefined in dictionary "
851  << name()
852  << exit(FatalIOError);
853  }
854  return entryPtr->dict();
855 }
856 
857 
859 {
860  entry* entryPtr = lookupEntryPtr(keyword, false, true);
861 
862  if (entryPtr == nullptr)
863  {
865  << "keyword " << keyword << " is undefined in dictionary "
866  << name()
867  << exit(FatalIOError);
868  }
869  return entryPtr->dict();
870 }
871 
872 
874 (
875  const wordList& keywords
876 ) const
877 {
878  const entry* entryPtr =
879  lookupEntryPtrBackwardsCompatible(keywords, false, true);
880 
881  if (entryPtr == nullptr)
882  {
883  // Generate error message using the first keyword
884  return subDict(keywords[0]);
885  }
886  else
887  {
888  return entryPtr->dict();
889  }
890 }
891 
892 
894 (
895  const word& keyword,
896  const bool mustRead
897 ) const
898 {
899  const entry* entryPtr = lookupEntryPtr(keyword, false, true);
900 
901  if (entryPtr == nullptr)
902  {
903  if (mustRead)
904  {
906  << "keyword " << keyword << " is undefined in dictionary "
907  << name()
908  << exit(FatalIOError);
909  }
910 
911  return dictionary(*this, dictionary(name() + '/' + keyword));
912  }
913  else
914  {
915  return entryPtr->dict();
916  }
917 }
918 
919 
921 (
922  const word& keyword
923 ) const
924 {
925  const entry* entryPtr = lookupEntryPtr(keyword, false, true);
926 
927  if (entryPtr)
928  {
929  return entryPtr->dict();
930  }
931  else
932  {
933  return *this;
934  }
935 }
936 
937 
939 {
940  if (keyword == "")
941  {
942  return *this;
943  }
944  else
945  {
946  const entry* entPtr = lookupScopedEntryPtr
947  (
948  keyword,
949  false,
950  false
951  );
952  if (!entPtr || !entPtr->isDict())
953  {
955  << "keyword " << keyword
956  << " is undefined in dictionary "
957  << name() << " or is not a dictionary"
958  << endl
959  << "Valid keywords are " << keys()
960  << exit(FatalIOError);
961  }
962  return entPtr->dict();
963  }
964 }
965 
966 
968 {
969  return const_cast<dictionary&>
970  (
971  const_cast<const dictionary*>(this)->scopedDict(keyword)
972  );
973 }
974 
975 
977 {
978  wordList keys(size());
979 
980  label nKeys = 0;
981  forAllConstIter(IDLList<entry>, *this, iter)
982  {
983  keys[nKeys++] = iter().keyword();
984  }
985 
986  return keys;
987 }
988 
989 
991 {
992  return hashedEntries_.sortedToc();
993 }
994 
995 
997 {
998  List<keyType> keys(size());
999 
1000  label nKeys = 0;
1001  forAllConstIter(IDLList<entry>, *this, iter)
1002  {
1003  if (iter().keyword().isPattern() ? patterns : !patterns)
1004  {
1005  keys[nKeys++] = iter().keyword();
1006  }
1007  }
1008  keys.setSize(nKeys);
1009 
1010  return keys;
1011 }
1012 
1013 
1014 bool Foam::dictionary::add(entry* entryPtr, bool mergeEntry)
1015 {
1016  HashTable<entry*>::iterator iter = hashedEntries_.find
1017  (
1018  entryPtr->keyword()
1019  );
1020 
1021  if (mergeEntry && iter != hashedEntries_.end())
1022  {
1023  // Merge dictionary with dictionary
1024  if (iter()->isDict() && entryPtr->isDict())
1025  {
1026  iter()->dict().merge(entryPtr->dict());
1027  delete entryPtr;
1028 
1029  return true;
1030  }
1031  else
1032  {
1033  // Replace existing dictionary with entry or vice versa
1034  IDLList<entry>::replace(iter(), entryPtr);
1035  delete iter();
1036  hashedEntries_.erase(iter);
1037 
1038  if (hashedEntries_.insert(entryPtr->keyword(), entryPtr))
1039  {
1040  entryPtr->name() = name() + '/' + entryPtr->keyword();
1041 
1042  if (entryPtr->keyword().isPattern())
1043  {
1044  patternEntries_.insert(entryPtr);
1045  patternRegexps_.insert
1046  (
1047  autoPtr<regExp>(new regExp(entryPtr->keyword()))
1048  );
1049  }
1050 
1051  return true;
1052  }
1053  else
1054  {
1055  IOWarningInFunction((*this))
1056  << "problem replacing entry "<< entryPtr->keyword()
1057  << " in dictionary " << name() << endl;
1058 
1059  IDLList<entry>::remove(entryPtr);
1060  delete entryPtr;
1061  return false;
1062  }
1063  }
1064  }
1065 
1066  if (hashedEntries_.insert(entryPtr->keyword(), entryPtr))
1067  {
1068  entryPtr->name() = name() + '/' + entryPtr->keyword();
1069  IDLList<entry>::append(entryPtr);
1070 
1071  if (entryPtr->keyword().isPattern())
1072  {
1073  patternEntries_.insert(entryPtr);
1074  patternRegexps_.insert
1075  (
1076  autoPtr<regExp>(new regExp(entryPtr->keyword()))
1077  );
1078  }
1079 
1080  return true;
1081  }
1082  else
1083  {
1084  // If function entries are disabled allow duplicate entries
1086  {
1087  entryPtr->name() = name() + '/' + entryPtr->keyword();
1088  IDLList<entry>::append(entryPtr);
1089 
1090  return true;
1091  }
1092  else
1093  {
1094  IOWarningInFunction((*this))
1095  << "attempt to add entry "<< entryPtr->keyword()
1096  << " which already exists in dictionary " << name()
1097  << endl;
1098 
1099  delete entryPtr;
1100  return false;
1101  }
1102  }
1103 }
1104 
1105 
1106 void Foam::dictionary::add(const entry& e, bool mergeEntry)
1107 {
1108  add(e.clone(*this).ptr(), mergeEntry);
1109 }
1110 
1111 
1112 void Foam::dictionary::add(const keyType& k, const word& w, bool overwrite)
1113 {
1114  add(new primitiveEntry(k, token(w)), overwrite);
1115 }
1116 
1117 
1119 (
1120  const keyType& k,
1121  const Foam::string& s,
1122  bool overwrite
1123 )
1124 {
1125  add(new primitiveEntry(k, token(s)), overwrite);
1126 }
1127 
1128 
1129 void Foam::dictionary::add(const keyType& k, const label l, bool overwrite)
1130 {
1131  add(new primitiveEntry(k, token(l)), overwrite);
1132 }
1133 
1134 
1135 void Foam::dictionary::add(const keyType& k, const scalar s, bool overwrite)
1136 {
1137  add(new primitiveEntry(k, token(s)), overwrite);
1138 }
1139 
1140 
1142 (
1143  const keyType& k,
1144  const dictionary& d,
1145  bool mergeEntry
1146 )
1147 {
1148  add(new dictionaryEntry(k, *this, d), mergeEntry);
1149 }
1150 
1151 
1153 {
1154  entry* existingPtr = lookupEntryPtr(entryPtr->keyword(), false, true);
1155 
1156  // Clear dictionary so merge acts like overwrite
1157  if (existingPtr && existingPtr->isDict())
1158  {
1159  existingPtr->dict().clear();
1160  }
1161  add(entryPtr, true);
1162 }
1163 
1164 
1166 {
1167  set(e.clone(*this).ptr());
1168 }
1169 
1170 
1172 {
1173  set(new dictionaryEntry(k, *this, d));
1174 }
1175 
1176 
1177 bool Foam::dictionary::remove(const word& Keyword)
1178 {
1179  HashTable<entry*>::iterator iter = hashedEntries_.find(Keyword);
1180 
1181  if (iter != hashedEntries_.end())
1182  {
1183  // Delete from patterns first
1184  DLList<entry*>::iterator wcLink =
1185  patternEntries_.begin();
1187  patternRegexps_.begin();
1188 
1189  // Find in pattern using exact match only
1190  if (findInPatterns(false, Keyword, wcLink, reLink))
1191  {
1192  patternEntries_.remove(wcLink);
1193  patternRegexps_.remove(reLink);
1194  }
1195 
1196  IDLList<entry>::remove(iter());
1197  delete iter();
1198  hashedEntries_.erase(iter);
1199 
1200  return true;
1201  }
1202  else
1203  {
1204  return false;
1205  }
1206 }
1207 
1208 
1210 (
1211  const keyType& oldKeyword,
1212  const keyType& newKeyword,
1213  bool forceOverwrite
1214 )
1215 {
1216  // No change
1217  if (oldKeyword == newKeyword)
1218  {
1219  return false;
1220  }
1221 
1222  HashTable<entry*>::iterator iter = hashedEntries_.find(oldKeyword);
1223 
1224  // oldKeyword not found - do nothing
1225  if (iter == hashedEntries_.end())
1226  {
1227  return false;
1228  }
1229 
1230  if (iter()->keyword().isPattern())
1231  {
1232  FatalIOErrorInFunction(*this)
1233  << "Old keyword "<< oldKeyword
1234  << " is a pattern."
1235  << "Pattern replacement not yet implemented."
1236  << exit(FatalIOError);
1237  }
1238 
1239 
1240  HashTable<entry*>::iterator iter2 = hashedEntries_.find(newKeyword);
1241 
1242  // newKeyword already exists
1243  if (iter2 != hashedEntries_.end())
1244  {
1245  if (forceOverwrite)
1246  {
1247  if (iter2()->keyword().isPattern())
1248  {
1249  // Delete from patterns first
1250  DLList<entry*>::iterator wcLink =
1251  patternEntries_.begin();
1253  patternRegexps_.begin();
1254 
1255  // Find in patterns using exact match only
1256  if (findInPatterns(false, iter2()->keyword(), wcLink, reLink))
1257  {
1258  patternEntries_.remove(wcLink);
1259  patternRegexps_.remove(reLink);
1260  }
1261  }
1262 
1263  IDLList<entry>::replace(iter2(), iter());
1264  delete iter2();
1265  hashedEntries_.erase(iter2);
1266 
1267  }
1268  else
1269  {
1271  (
1272  *this
1273  ) << "cannot rename keyword "<< oldKeyword
1274  << " to existing keyword " << newKeyword
1275  << " in dictionary " << name() << endl;
1276  return false;
1277  }
1278  }
1279 
1280  // Change name and HashTable, but leave DL-List untouched
1281  iter()->keyword() = newKeyword;
1282  iter()->name() = name() + '/' + newKeyword;
1283  hashedEntries_.erase(oldKeyword);
1284  hashedEntries_.insert(newKeyword, iter());
1285 
1286  if (newKeyword.isPattern())
1287  {
1288  patternEntries_.insert(iter());
1289  patternRegexps_.insert
1290  (
1291  autoPtr<regExp>(new regExp(newKeyword))
1292  );
1293  }
1294 
1295  return true;
1296 }
1297 
1298 
1300 {
1301  // Check for assignment to self
1302  if (this == &dict)
1303  {
1304  FatalIOErrorInFunction(*this)
1305  << "attempted merge to self for dictionary " << name()
1306  << abort(FatalIOError);
1307  }
1308 
1309  bool changed = false;
1310 
1312  {
1313  HashTable<entry*>::iterator fnd = hashedEntries_.find(iter().keyword());
1314 
1315  if (fnd != hashedEntries_.end())
1316  {
1317  // Recursively merge sub-dictionaries
1318  // TODO: merge without copying
1319  if (fnd()->isDict() && iter().isDict())
1320  {
1321  if (fnd()->dict().merge(iter().dict()))
1322  {
1323  changed = true;
1324  }
1325  }
1326  else
1327  {
1328  add(iter().clone(*this).ptr(), true);
1329  changed = true;
1330  }
1331  }
1332  else
1333  {
1334  // Not found - just add
1335  add(iter().clone(*this).ptr());
1336  changed = true;
1337  }
1338  }
1339 
1340  return changed;
1341 }
1342 
1343 
1345 {
1347  hashedEntries_.clear();
1348  patternEntries_.clear();
1349  patternRegexps_.clear();
1350 }
1351 
1352 
1354 {
1355  // Changing parents probably doesn't make much sense,
1356  // but what about the names?
1357  name() = dict.name();
1358 
1360  hashedEntries_.transfer(dict.hashedEntries_);
1361  patternEntries_.transfer(dict.patternEntries_);
1362  patternRegexps_.transfer(dict.patternRegexps_);
1363 }
1364 
1365 
1366 // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
1367 
1369 {
1370  return lookup(keyword);
1371 }
1372 
1373 
1375 {
1376  // Check for assignment to self
1377  if (this == &rhs)
1378  {
1379  FatalIOErrorInFunction(*this)
1380  << "attempted assignment to self for dictionary " << name()
1381  << abort(FatalIOError);
1382  }
1383 
1384  name() = rhs.name();
1385  clear();
1386 
1387  // Create clones of the entries in the given dictionary
1388  // resetting the parentDict to this dictionary
1389 
1390  forAllConstIter(IDLList<entry>, rhs, iter)
1391  {
1392  add(iter().clone(*this).ptr());
1393  }
1394 }
1395 
1396 
1398 {
1399  // Check for assignment to self
1400  if (this == &rhs)
1401  {
1402  FatalIOErrorInFunction(*this)
1403  << "attempted addition assignment to self for dictionary " << name()
1404  << abort(FatalIOError);
1405  }
1406 
1407  forAllConstIter(IDLList<entry>, rhs, iter)
1408  {
1409  add(iter().clone(*this).ptr());
1410  }
1411 }
1412 
1413 
1415 {
1416  // Check for assignment to self
1417  if (this == &rhs)
1418  {
1419  FatalIOErrorInFunction(*this)
1420  << "attempted assignment to self for dictionary " << name()
1421  << abort(FatalIOError);
1422  }
1423 
1424  forAllConstIter(IDLList<entry>, rhs, iter)
1425  {
1426  if (!found(iter().keyword()))
1427  {
1428  add(iter().clone(*this).ptr());
1429  }
1430  }
1431 }
1432 
1433 
1435 {
1436  // Check for assignment to self
1437  if (this == &rhs)
1438  {
1439  FatalIOErrorInFunction(*this)
1440  << "attempted assignment to self for dictionary " << name()
1441  << abort(FatalIOError);
1442  }
1443 
1444  forAllConstIter(IDLList<entry>, rhs, iter)
1445  {
1446  set(iter().clone(*this).ptr());
1447  }
1448 }
1449 
1450 
1451 /* * * * * * * * * * * * * * * * Global operators * * * * * * * * * * * * * */
1452 
1453 Foam::dictionary Foam::operator+
1454 (
1455  const dictionary& dict1,
1456  const dictionary& dict2
1457 )
1458 {
1459  dictionary sum(dict1);
1460  sum += dict2;
1461  return sum;
1462 }
1463 
1464 
1465 Foam::dictionary Foam::operator|
1466 (
1467  const dictionary& dict1,
1468  const dictionary& dict2
1469 )
1470 {
1471  dictionary sum(dict1);
1472  sum |= dict2;
1473  return sum;
1474 }
1475 
1476 
1477 // * * * * * * * * * * * * * * * Global Functions * * * * * * * * * * * * * //
1478 
1480 (
1481  const string& argString,
1482  word& funcName,
1483  wordReList& args,
1484  List<Tuple2<word, string>>& namedArgs
1485 )
1486 {
1487  funcName = argString;
1488 
1489  int argLevel = 0;
1490  bool namedArg = false;
1491  word argName;
1492 
1493  word::size_type start = 0;
1494  word::size_type i = 0;
1495 
1496  for
1497  (
1498  word::const_iterator iter = argString.begin();
1499  iter != argString.end();
1500  ++iter
1501  )
1502  {
1503  char c = *iter;
1504 
1505  if (c == '(')
1506  {
1507  if (argLevel == 0)
1508  {
1509  funcName = argString(start, i - start);
1510  start = i+1;
1511  }
1512  ++argLevel;
1513  }
1514  else if (c == ',' || c == ')')
1515  {
1516  if (argLevel == 1)
1517  {
1518  if (namedArg)
1519  {
1520  namedArgs.append
1521  (
1523  (
1524  argName,
1525  argString(start, i - start)
1526  )
1527  );
1528  namedArg = false;
1529  }
1530  else
1531  {
1532  args.append(wordRe(argString(start, i - start)));
1533  }
1534  start = i+1;
1535  }
1536 
1537  if (c == ')')
1538  {
1539  if (argLevel == 1)
1540  {
1541  break;
1542  }
1543  --argLevel;
1544  }
1545  }
1546  else if (c == '=')
1547  {
1548  argName = argString(start, i - start);
1549  string::stripInvalid<variable>(argName);
1550  start = i+1;
1551  namedArg = true;
1552  }
1553 
1554  ++i;
1555  }
1556 
1557  // Strip whitespace from the function name
1558  string::stripInvalid<word>(funcName);
1559 }
1560 
1561 
1563 (
1564  const string& argString,
1565  wordReList& args,
1566  List<Tuple2<word, string>>& namedArgs
1567 )
1568 {
1569  int argLevel = 0;
1570  bool namedArg = false;
1571  word argName;
1572 
1573  word::size_type start = 0;
1574  word::size_type i = 0;
1575 
1576  for
1577  (
1578  word::const_iterator iter = argString.begin();
1579  iter != argString.end();
1580  ++iter
1581  )
1582  {
1583  char c = *iter;
1584 
1585  if (c == '(')
1586  {
1587  ++argLevel;
1588  }
1589  else if (c == ',' || std::next(iter) == argString.end())
1590  {
1591  if (std::next(iter) == argString.end())
1592  {
1593  if (c == ')')
1594  {
1595  --argLevel;
1596  }
1597 
1598  ++i;
1599  }
1600 
1601  if (argLevel == 0)
1602  {
1603  if (namedArg)
1604  {
1605  namedArgs.append
1606  (
1608  (
1609  argName,
1610  argString(start, i - start)
1611  )
1612  );
1613  namedArg = false;
1614  }
1615  else
1616  {
1617  args.append(wordRe(argString(start, i - start)));
1618  }
1619  start = i+1;
1620  }
1621  }
1622  else if (c == '=')
1623  {
1624  argName = argString(start, i - start);
1625  string::stripInvalid<variable>(argName);
1626  start = i+1;
1627  namedArg = true;
1628  }
1629  else if (c == ')')
1630  {
1631  --argLevel;
1632  }
1633 
1634  ++i;
1635  }
1636 }
1637 
1638 
1640 {
1641  string::size_type i = scopedName.find_last_of('/');
1642 
1643  if (i != string::npos)
1644  {
1645  return Pair<word>
1646  (
1647  scopedName.substr(0, i),
1648  scopedName.substr(i+1, string::npos)
1649  );
1650  }
1651  else
1652  {
1653  return Pair<word>("", scopedName);
1654  }
1655 }
1656 
1657 
1658 // ************************************************************************* //
label k
graph_traits< Graph >::vertices_size_type size_type
Definition: SloanRenumber.C:73
bool found
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:434
#define forAllIter(Container, container, iter)
Iterate across all elements in the container object of type.
Definition: UList.H:459
#define forAllConstIter(Container, container, iter)
Iterate across all elements in the container object of type.
Definition: UList.H:477
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects.
Definition: DynamicList.H:78
DynamicList< T, SizeInc, SizeMult, SizeDiv > & append(const T &)
Append an element at the end of the list.
Definition: DynamicListI.H:296
An STL-conforming const_iterator.
Definition: HashTable.H:498
An STL-conforming iterator.
Definition: HashTable.H:443
Template class for intrusive linked lists.
Definition: ILList.H:67
void transfer(ILList< LListBase, T > &)
Transfer the contents of the argument into this List.
Definition: ILList.C:134
void clear()
Clear the contents of the list.
Definition: ILList.C:121
const word & name() const
Return name.
Definition: IOobject.H:310
virtual Istream & read(token &)
Return next token from stream.
Definition: ISstream.C:133
Input from memory buffer stream.
Definition: IStringStream.H:52
Input token stream.
Definition: ITstream.H:53
An STL-conforming const_iterator.
Definition: LList.H:300
An STL-conforming iterator.
Definition: LList.H:249
Template class for non-intrusive linked lists.
Definition: LList.H:76
friend class iterator
Definition: LList.H:82
friend class const_iterator
Definition: LList.H:85
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: List.H:91
void setSize(const label)
Reset size of List.
Definition: List.C:281
A Foam::OSstream for calculating SHA-1 digests.
Definition: OSHA1stream.H:152
SHA1Digest digest()
Return the SHA-1 digest for the data processed until now.
Definition: OSHA1stream.H:194
Output to memory buffer stream.
Definition: OStringStream.H:52
string str() const
Return the string.
The SHA1 message digest.
Definition: SHA1Digest.H:63
A 2-tuple for storing two objects of different types.
Definition: Tuple2.H:66
An STL-conforming const_iterator.
Definition: UILList.H:237
An STL-conforming iterator.
Definition: UILList.H:188
T * remove(T *p)
Remove and return element.
Definition: UILList.H:142
An auto-pointer similar to the STL auto_ptr but with automatic casting to a reference to the type and...
Definition: autoPtr.H:51
A keyword and a list of tokens is a 'dictionaryEntry'.
const fileName & name() const
Return the dictionary name.
Definition: dictionary.H:111
A list of keyword definitions, which are a keyword followed by any number of values (e....
Definition: dictionary.H:162
bool substituteScopedKeyword(const word &keyword)
Substitute the given scoped keyword prepended by '$' with the.
Definition: dictionary.C:773
static bool writeOptionalEntries
If true write optional keywords and values.
Definition: dictionary.H:262
const dictionary & topDict() const
Return the top of the tree.
Definition: dictionary.C:414
ITstream & operator[](const word &) const
Find and return entry.
Definition: dictionary.C:1368
dictionary subOrEmptyDict(const word &, const bool mustRead=false) const
Find and return a sub-dictionary as a copy, or.
Definition: dictionary.C:894
dictionary()
Construct top-level dictionary null.
Definition: dictionary.C:320
autoPtr< dictionary > clone() const
Construct and return clone.
Definition: dictionary.C:398
void operator<<=(const dictionary &)
Unconditionally include entries from the given dictionary.
Definition: dictionary.C:1434
void transfer(dictionary &)
Transfer the contents of the argument and annul the argument.
Definition: dictionary.C:1353
const dictionary & subDictBackwardsCompatible(const wordList &) const
Find and return a sub-dictionary, trying a list of keywords in.
Definition: dictionary.C:874
const entry * lookupEntryPtr(const word &, bool recursive, bool patternMatch) const
Find and return an entry data stream pointer if present.
Definition: dictionary.C:548
ITstream & lookup(const word &, bool recursive=false, bool patternMatch=true) const
Find and return an entry data stream.
Definition: dictionary.C:710
bool changeKeyword(const keyType &oldKeyword, const keyType &newKeyword, bool forceOverwrite=false)
Change the keyword for an entry,.
Definition: dictionary.C:1210
tokenList tokens() const
Return the dictionary as a list of tokens.
Definition: dictionary.C:489
void set(entry *)
Assign a new entry, overwrite any existing entry.
Definition: dictionary.C:1152
const entry & lookupEntry(const word &, bool recursive, bool patternMatch) const
Find and return an entry data stream if present otherwise error.
Definition: dictionary.C:667
List< keyType > keys(bool patterns=false) const
Return the list of available keys or patterns.
Definition: dictionary.C:996
friend class entry
Declare friendship with the entry class for IO.
Definition: dictionary.H:242
void operator+=(const dictionary &)
Include entries from the given dictionary.
Definition: dictionary.C:1397
const dictionary & optionalSubDict(const word &) const
Find and return a sub-dictionary if found.
Definition: dictionary.C:921
const entry * lookupScopedEntryPtr(const word &, bool recursive, bool patternMatch) const
Find and return an entry data stream pointer if present,.
Definition: dictionary.C:737
word topDictKeyword() const
Return the scoped keyword with which this dictionary can be.
Definition: dictionary.C:429
bool remove(const word &)
Remove an entry specified by keyword.
Definition: dictionary.C:1177
bool isDict(const word &) const
Check if entry is a sub-dictionary.
Definition: dictionary.C:797
const dictionary & subDict(const word &) const
Find and return a sub-dictionary.
Definition: dictionary.C:843
const entry & lookupEntryBackwardsCompatible(const wordList &, bool recursive, bool patternMatch) const
Find and return an entry data stream if present, trying a list.
Definition: dictionary.C:688
label endLineNumber() const
Return line number of last token in dictionary.
Definition: dictionary.C:462
wordList sortedToc() const
Return the sorted table of contents.
Definition: dictionary.C:990
const entry * lookupEntryPtrBackwardsCompatible(const wordList &, bool recursive, bool patternMatch) const
Find and return an entry data stream if present, trying a list.
Definition: dictionary.C:631
void operator|=(const dictionary &)
Conditionally include entries from the given dictionary.
Definition: dictionary.C:1414
bool add(entry *, bool mergeEntry=false)
Add a new entry.
Definition: dictionary.C:1014
void clear()
Clear the dictionary.
Definition: dictionary.C:1344
virtual ~dictionary()
Destructor.
Definition: dictionary.C:406
ITstream & lookupBackwardsCompatible(const wordList &, bool recursive=false, bool patternMatch=true) const
Find and return an entry data stream, trying a list of keywords.
Definition: dictionary.C:721
const dictionary * subDictPtr(const word &) const
Find and return a sub-dictionary pointer if present.
Definition: dictionary.C:813
void operator=(const dictionary &)
Definition: dictionary.C:1374
wordList toc() const
Return the table of contents.
Definition: dictionary.C:976
bool found(const word &, bool recursive=false, bool patternMatch=true) const
Search dictionary for given keyword.
Definition: dictionary.C:509
const dictionary & scopedDict(const word &) const
Find and return a sub-dictionary by scoped lookup.
Definition: dictionary.C:938
label startLineNumber() const
Return line number of first token in dictionary.
Definition: dictionary.C:449
static const dictionary null
Null dictionary.
Definition: dictionary.H:258
bool merge(const dictionary &)
Merge entries from the given dictionary.
Definition: dictionary.C:1299
SHA1Digest digest() const
Return the SHA1 digest of the dictionary contents.
Definition: dictionary.C:475
A keyword and a list of tokens is an 'entry'.
Definition: entry.H:68
virtual bool isDict() const
Return true if this entry is a dictionary.
Definition: entry.H:156
const keyType & keyword() const
Return keyword.
Definition: entry.H:123
virtual const fileName & name() const =0
Return the dictionary name.
virtual const dictionary & dict() const =0
Return dictionary if this entry is a dictionary.
virtual autoPtr< entry > clone(const dictionary &parentDict) const =0
Construct on freestore as copy with reference to the.
static int disableFunctionEntries
Definition: entry.H:86
A class for handling file names.
Definition: fileName.H:82
fileName path() const
Return directory path name (part before last /)
Definition: fileName.C:265
A class for handling keywords in dictionaries.
Definition: keyType.H:69
bool isPattern() const
Should be treated as a match rather than a literal string.
Definition: keyTypeI.H:97
A keyword and a list of tokens is a 'primitiveEntry'. An primitiveEntry can be read,...
Wrapper around POSIX extended regular expressions.
Definition: regExp.H:62
A class for handling character strings derived from std::string.
Definition: string.H:79
A token holds items read from Istream.
Definition: token.H:73
A wordRe is a word, but can also have a regular expression for matching words.
Definition: wordRe.H:77
A class for handling words, derived from string.
Definition: word.H:62
static const word null
An empty word.
Definition: word.H:77
#define IMPLEMENT_SPECIALISED_READ_TYPE(T, nullArg)
Definition: dictionary.C:286
#define IMPLEMENT_SPECIALISED_READ_LIST_TYPE(T, nullArg)
Definition: dictionary.C:309
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:346
gmvFile<< "tracers "<< particles.size()<< nl;forAllConstIter(Cloud< passiveParticle >, particles, iter){ gmvFile<< iter().position().x()<< " ";}gmvFile<< nl;forAllConstIter(Cloud< passiveParticle >, particles, iter){ gmvFile<< iter().position().y()<< " ";}gmvFile<< nl;forAllConstIter(Cloud< passiveParticle >, particles, iter){ gmvFile<< iter().position().z()<< " ";}gmvFile<< nl;forAll(lagrangianScalarNames, i){ word name=lagrangianScalarNames[i];IOField< scalar > s(IOobject(name, runTime.name(), cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
tUEqn clear()
#define IOWarningInFunction(ios)
Report an IO warning using Foam::Warning.
const dimensionedScalar c
Speed of light in a vacuum.
int infoSwitch(const char *name, const int defaultValue=0)
Lookup info switch or add default value.
Definition: debug.C:233
void write(std::ostream &os, const bool binary, List< floatScalar > &fField)
Write floats ascii or binary.
Namespace for OpenFOAM.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
const doubleScalar e
Definition: doubleScalar.H:106
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
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:257
word name(const bool)
Return a word representation of a bool.
Definition: boolIO.C:39
dimensioned< Type > sum(const DimensionedField< Type, GeoMesh > &df)
errorManip< error > abort(error &err)
Definition: errorManip.H:131
void dictArgList(const string &argString, word &configName, wordReList &args, List< Tuple2< word, string >> &namedArgs)
Parse dictionary substitution argument list.
Definition: dictionary.C:1480
labelList first(const UList< labelPair > &p)
Definition: patchToPatch.C:39
const HashTable< unitConversion > & units()
Get the table of unit conversions.
Pair< word > dictAndKeyword(const word &scopedName)
Extracts dict name and keyword.
Definition: dictionary.C:1639
void add(FieldField< Field1, typename typeOfSum< Type1, Type2 >::type > &f, const FieldField< Field1, Type1 > &f1, const FieldField< Field2, Type2 > &f2)
defineTypeNameAndDebug(combustionModel, 0)
T clone(const T &t)
Definition: List.H:55
IOerror FatalIOError
error FatalError
FOR_ALL_FIELD_TYPES(makeFieldSourceTypedef)
void T(FieldField< Field, Type > &f1, const FieldField< Field, Type > &f2)
LList< DLListBase, T > DLList
Definition: DLList.H:43
List< token > tokenList
List of tokens, used for a IOdictionary entry.
Definition: tokenList.H:42
dictionary dict
Foam::argList args(argc, argv)
volScalarField & p