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