1 /*
2  * Copyright (C) 2004-2020 ZNC, see the NOTICE file for details.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef ZNC_CONFIG_H
18 #define ZNC_CONFIG_H
19 
20 #include <znc/zncconfig.h>
21 #include <znc/ZNCString.h>
22 
23 class CFile;
24 class CConfig;
25 
26 struct CConfigEntry {
27     CConfigEntry();
28     CConfigEntry(const CConfig& Config);
29     CConfigEntry(const CConfigEntry& other);
30     ~CConfigEntry();
31     CConfigEntry& operator=(const CConfigEntry& other);
32 
33     CConfig* m_pSubConfig;
34 };
35 
36 class CConfig {
37   public:
CConfig()38     CConfig() : m_ConfigEntries(), m_SubConfigs() {}
39 
40     typedef std::map<CString, VCString> EntryMap;
41     typedef std::map<CString, CConfigEntry> SubConfig;
42     typedef std::map<CString, SubConfig> SubConfigMap;
43 
44     typedef EntryMap::const_iterator EntryMapIterator;
45     typedef SubConfigMap::const_iterator SubConfigMapIterator;
46 
BeginEntries()47     EntryMapIterator BeginEntries() const { return m_ConfigEntries.begin(); }
EndEntries()48     EntryMapIterator EndEntries() const { return m_ConfigEntries.end(); }
49 
BeginSubConfigs()50     SubConfigMapIterator BeginSubConfigs() const {
51         return m_SubConfigs.begin();
52     }
EndSubConfigs()53     SubConfigMapIterator EndSubConfigs() const { return m_SubConfigs.end(); }
54 
AddKeyValuePair(const CString & sName,const CString & sValue)55     void AddKeyValuePair(const CString& sName, const CString& sValue) {
56         if (sName.empty() || sValue.empty()) {
57             return;
58         }
59 
60         m_ConfigEntries[sName].push_back(sValue);
61     }
62 
AddSubConfig(const CString & sTag,const CString & sName,CConfig Config)63     bool AddSubConfig(const CString& sTag, const CString& sName,
64                       CConfig Config) {
65         SubConfig& conf = m_SubConfigs[sTag];
66         SubConfig::const_iterator it = conf.find(sName);
67 
68         if (it != conf.end()) {
69             return false;
70         }
71 
72         conf[sName] = Config;
73         return true;
74     }
75 
76     bool FindStringVector(const CString& sName, VCString& vsList,
77                           bool bErase = true) {
78         EntryMap::iterator it = m_ConfigEntries.find(sName);
79         vsList.clear();
80         if (it == m_ConfigEntries.end()) return false;
81         vsList = it->second;
82 
83         if (bErase) {
84             m_ConfigEntries.erase(it);
85         }
86 
87         return true;
88     }
89 
90     bool FindStringEntry(const CString& sName, CString& sRes,
91                          const CString& sDefault = "") {
92         EntryMap::iterator it = m_ConfigEntries.find(sName);
93         sRes = sDefault;
94         if (it == m_ConfigEntries.end() || it->second.empty()) return false;
95         sRes = it->second.front();
96         it->second.erase(it->second.begin());
97         if (it->second.empty()) m_ConfigEntries.erase(it);
98         return true;
99     }
100 
101     bool FindBoolEntry(const CString& sName, bool& bRes,
102                        bool bDefault = false) {
103         CString s;
104         if (FindStringEntry(sName, s)) {
105             bRes = s.ToBool();
106             return true;
107         }
108         bRes = bDefault;
109         return false;
110     }
111 
112     bool FindUIntEntry(const CString& sName, unsigned int& uRes,
113                        unsigned int uDefault = 0) {
114         CString s;
115         if (FindStringEntry(sName, s)) {
116             uRes = s.ToUInt();
117             return true;
118         }
119         uRes = uDefault;
120         return false;
121     }
122 
123     bool FindUShortEntry(const CString& sName, unsigned short& uRes,
124                          unsigned short uDefault = 0) {
125         CString s;
126         if (FindStringEntry(sName, s)) {
127             uRes = s.ToUShort();
128             return true;
129         }
130         uRes = uDefault;
131         return false;
132     }
133 
134     bool FindDoubleEntry(const CString& sName, double& fRes,
135                          double fDefault = 0) {
136         CString s;
137         if (FindStringEntry(sName, s)) {
138             fRes = s.ToDouble();
139             return true;
140         }
141         fRes = fDefault;
142         return false;
143     }
144 
145     bool FindSubConfig(const CString& sName, SubConfig& Config,
146                        bool bErase = true) {
147         SubConfigMap::iterator it = m_SubConfigs.find(sName);
148         if (it == m_SubConfigs.end()) {
149             Config.clear();
150             return false;
151         }
152         Config = it->second;
153 
154         if (bErase) {
155             m_SubConfigs.erase(it);
156         }
157 
158         return true;
159     }
160 
empty()161     bool empty() const {
162         return m_ConfigEntries.empty() && m_SubConfigs.empty();
163     }
164 
165     bool Parse(CFile& file, CString& sErrorMsg);
166     void Write(CFile& file, unsigned int iIndentation = 0);
167 
168   private:
169     EntryMap m_ConfigEntries;
170     SubConfigMap m_SubConfigs;
171 };
172 
173 #endif  // !ZNC_CONFIG_H
174