1/*
2 This file is part of the KDE libraries
3 SPDX-FileCopyrightText: 2006, 2007 Thomas Braxton <kde.braxton@gmail.com>
4 SPDX-FileCopyrightText: 1999-2000 Preston Brown <pbrown@kde.org>
5 SPDX-FileCopyrightText: 1996-2000 Matthias Kalle Dalheimer <kalle@kde.org>
6
7 SPDX-License-Identifier: LGPL-2.0-or-later
8*/
9
10#ifndef KCONFIGDATA_P_H
11#define KCONFIGDATA_P_H
12
13#include <QByteArray>
14#include <QDebug>
15#include <QString>
16#include <map>
17
18/**
19 * map/dict/list config node entry.
20 * @internal
21 */
22struct KEntry {
23 /** Constructor. @internal */
24 KEntry()
25 : mValue()
26 , bDirty(false)
27 , bGlobal(false)
28 , bImmutable(false)
29 , bDeleted(false)
30 , bExpand(false)
31 , bReverted(false)
32 , bLocalizedCountry(false)
33 , bNotify(false)
34 , bOverridesGlobal(false)
35 {
36 }
37 /** @internal */
38 QByteArray mValue;
39 /**
40 * Must the entry be written back to disk?
41 */
42 bool bDirty : 1;
43 /**
44 * Entry should be written to the global config file
45 */
46 bool bGlobal : 1;
47 /**
48 * Entry can not be modified.
49 */
50 bool bImmutable : 1;
51 /**
52 * Entry has been deleted.
53 */
54 bool bDeleted : 1;
55 /**
56 * Whether to apply dollar expansion or not.
57 */
58 bool bExpand : 1;
59 /**
60 * Entry has been reverted to its default value (from a more global file).
61 */
62 bool bReverted : 1;
63 /**
64 * Entry is for a localized key. If @c false the value references just language e.g. "de",
65 * if @c true the value references language and country, e.g. "de_DE".
66 **/
67 bool bLocalizedCountry : 1;
68
69 bool bNotify : 1;
70
71 /**
72 * Entry will need to be written on a non global file even if it matches default value
73 */
74 bool bOverridesGlobal : 1;
75};
76
77Q_DECLARE_TYPEINFO(KEntry, Q_RELOCATABLE_TYPE);
78
79// These operators are used to check whether an entry which is about
80// to be written equals the previous value. As such, this intentionally
81// omits the dirty/notify flag from the comparison.
82inline bool operator==(const KEntry &k1, const KEntry &k2)
83{
84 /* clang-format off */
85 return k1.bGlobal == k2.bGlobal
86 && k1.bImmutable == k2.bImmutable
87 && k1.bDeleted == k2.bDeleted
88 && k1.bExpand == k2.bExpand
89 && k1.mValue == k2.mValue;
90 /* clang-format on */
91}
92
93inline bool operator!=(const KEntry &k1, const KEntry &k2)
94{
95 return !(k1 == k2);
96}
97
98/**
99 * key structure holding both the actual key and the group
100 * to which it belongs.
101 * @internal
102 */
103struct KEntryKey {
104 /** Constructor. @internal */
105 KEntryKey(const QString &_group = QString(), const QByteArray &_key = QByteArray(), bool isLocalized = false, bool isDefault = false)
106 : mGroup(_group)
107 , mKey(_key)
108 , bLocal(isLocalized)
109 , bDefault(isDefault)
110 , bRaw(false)
111 {
112 }
113 /**
114 * The "group" to which this EntryKey belongs
115 */
116 QString mGroup;
117 /**
118 * The _actual_ key of the entry in question
119 */
120 QByteArray mKey;
121 /**
122 * Entry is localised or not
123 */
124 bool bLocal : 1;
125 /**
126 * Entry indicates if this is a default value.
127 */
128 bool bDefault : 1;
129 /** @internal
130 * Key is a raw unprocessed key.
131 * @warning this should only be set during merging, never for normal use.
132 */
133 bool bRaw : 1;
134};
135
136Q_DECLARE_TYPEINFO(KEntryKey, Q_RELOCATABLE_TYPE);
137
138/**
139 * Compares two KEntryKeys (needed for std::map). The order is localized, localized-default,
140 * non-localized, non-localized-default
141 * @internal
142 */
143inline bool operator<(const KEntryKey &k1, const KEntryKey &k2)
144{
145 int result = k1.mGroup.compare(s: k2.mGroup);
146 if (result != 0) {
147 return result < 0;
148 }
149
150 result = k1.mKey.compare(a: k2.mKey);
151 if (result != 0) {
152 return result < 0;
153 }
154
155 if (k1.bLocal != k2.bLocal) {
156 return k1.bLocal;
157 }
158 return (!k1.bDefault && k2.bDefault);
159}
160
161/**
162 * Light-weight view variant of KEntryKey.
163 * Used for look-up in the map.
164 * @internal
165 */
166struct KEntryKeyView {
167 /** Constructor. @internal */
168 KEntryKeyView(QStringView _group, QAnyStringView _key, bool isLocalized = false, bool isDefault = false)
169 : mGroup(_group)
170 , mKey(_key)
171 , bLocal(isLocalized)
172 , bDefault(isDefault)
173 {
174 }
175 /**
176 * The "group" to which this EntryKey belongs
177 */
178 const QStringView mGroup;
179 /**
180 * The _actual_ key of the entry in question
181 */
182 const QAnyStringView mKey;
183 /**
184 * Entry is localised or not
185 */
186 bool bLocal : 1;
187 /**
188 * Entry indicates if this is a default value.
189 */
190 bool bDefault : 1;
191};
192
193template<typename TEntryKey1, typename TEntryKey2>
194bool compareEntryKeyViews(const TEntryKey1 &k1, const TEntryKey2 &k2)
195{
196 int result = k1.mGroup.compare(k2.mGroup);
197 if (result != 0) {
198 return result < 0;
199 }
200
201 result = QAnyStringView::compare(lhs: k1.mKey, rhs: k2.mKey);
202 if (result != 0) {
203 return result < 0;
204 }
205
206 if (k1.bLocal != k2.bLocal) {
207 return k1.bLocal;
208 }
209 return (!k1.bDefault && k2.bDefault);
210}
211
212inline bool operator<(const KEntryKeyView &k1, const KEntryKey &k2)
213{
214 return compareEntryKeyViews(k1, k2);
215}
216
217inline bool operator<(const KEntryKey &k1, const KEntryKeyView &k2)
218{
219 return compareEntryKeyViews(k1, k2);
220}
221
222/**
223 * Struct to use as Compare type with std::map.
224 * To enable usage of KEntryKeyView for look-up in the map
225 * via the template find() overloads.
226 * @internal
227 */
228struct KEntryKeyCompare {
229 using is_transparent = void;
230
231 bool operator()(const KEntryKey &k1, const KEntryKey &k2) const
232 {
233 return (k1 < k2);
234 }
235
236 bool operator()(const KEntryKeyView &k1, const KEntryKey &k2) const
237 {
238 return (k1 < k2);
239 }
240
241 bool operator()(const KEntryKey &k1, const KEntryKeyView &k2) const
242 {
243 return (k1 < k2);
244 }
245};
246
247/**
248 * Returns the minimum key that has @a mGroup == @p group.
249 *
250 * @note The returned "minimum key" is consistent with KEntryKey's operator<().
251 * The return value of this function can be passed to KEntryMap::lowerBound().
252 */
253inline KEntryKeyView minimumGroupKeyView(const QString &group)
254{
255 return KEntryKeyView(group, QAnyStringView{}, true, false);
256}
257
258QDebug operator<<(QDebug dbg, const KEntryKey &key);
259QDebug operator<<(QDebug dbg, const KEntry &entry);
260
261/**
262 * \relates KEntry
263 * type specifying a map of entries (key,value pairs).
264 * The keys are actually a key in a particular config file group together
265 * with the group name.
266 * @internal
267 */
268class KEntryMap : public std::map<KEntryKey, KEntry, KEntryKeyCompare>
269{
270public:
271 enum SearchFlag {
272 SearchDefaults = 1,
273 SearchLocalized = 2,
274 };
275 Q_DECLARE_FLAGS(SearchFlags, SearchFlag)
276
277 enum EntryOption {
278 EntryDirty = 1,
279 EntryGlobal = 2,
280 EntryImmutable = 4,
281 EntryDeleted = 8,
282 EntryExpansion = 16,
283 EntryRawKey = 32,
284 EntryLocalizedCountry = 64,
285 EntryNotify = 128,
286 EntryDefault = (SearchDefaults << 16),
287 EntryLocalized = (SearchLocalized << 16),
288 };
289 Q_DECLARE_FLAGS(EntryOptions, EntryOption)
290
291 iterator findExactEntry(const QString &group, QAnyStringView key = QAnyStringView(), SearchFlags flags = SearchFlags());
292
293 iterator findEntry(const QString &group, QAnyStringView key = QAnyStringView(), SearchFlags flags = SearchFlags());
294
295 const_iterator findEntry(const QString &group, QAnyStringView key = QAnyStringView(), SearchFlags flags = SearchFlags()) const
296 {
297 return constFindEntry(group, key, flags);
298 }
299
300 const_iterator constFindEntry(const QString &group, QAnyStringView key = QAnyStringView(), SearchFlags flags = SearchFlags()) const;
301
302 /**
303 * Returns true if the entry gets dirtied or false in other case
304 */
305 bool setEntry(const QString &group, const QByteArray &key, const QByteArray &value, EntryOptions options);
306
307 void setEntry(const QString &group, const QByteArray &key, const QString &value, EntryOptions options)
308 {
309 setEntry(group, key, value: value.toUtf8(), options);
310 }
311
312 QString getEntry(const QString &group,
313 QAnyStringView key,
314 const QString &defaultValue = QString(),
315 SearchFlags flags = SearchFlags(),
316 bool *expand = nullptr) const;
317
318 bool hasEntry(const QString &group, QAnyStringView key = QAnyStringView(), SearchFlags flags = SearchFlags()) const;
319
320 bool getEntryOption(const const_iterator &it, EntryOption option) const;
321 bool getEntryOption(const QString &group, QAnyStringView key, SearchFlags flags, EntryOption option) const
322 {
323 return getEntryOption(it: findEntry(group, key, flags), option);
324 }
325
326 void setEntryOption(iterator it, EntryOption option, bool bf);
327 void setEntryOption(const QString &group, QAnyStringView key, SearchFlags flags, EntryOption option, bool bf)
328 {
329 setEntryOption(it: findEntry(group, key, flags), option, bf);
330 }
331
332 bool revertEntry(const QString &group, QAnyStringView key, EntryOptions options, SearchFlags flags = SearchFlags());
333
334 template<typename ConstIteratorUser>
335 void forEachEntryWhoseGroupStartsWith(const QString &groupPrefix, ConstIteratorUser callback) const
336 {
337 for (auto it = lower_bound(x: minimumGroupKeyView(group: groupPrefix)), end = cend(); it != end && it->first.mGroup.startsWith(s: groupPrefix); ++it) {
338 callback(it);
339 }
340 }
341
342 template<typename ConstIteratorPredicate>
343 bool anyEntryWhoseGroupStartsWith(const QString &groupPrefix, ConstIteratorPredicate predicate) const
344 {
345 for (auto it = lower_bound(x: minimumGroupKeyView(group: groupPrefix)), end = cend(); it != end && it->first.mGroup.startsWith(s: groupPrefix); ++it) {
346 if (predicate(it)) {
347 return true;
348 }
349 }
350 return false;
351 }
352
353 template<typename ConstIteratorUser>
354 void forEachEntryOfGroup(const QString &theGroup, ConstIteratorUser callback) const
355 {
356 const auto theEnd = cend();
357 auto it = constFindEntry(group: theGroup);
358 if (it != theEnd) {
359 ++it; // advance past the special group entry marker
360
361 for (; (it != theEnd) && (it->first.mGroup == theGroup); ++it) {
362 callback(it);
363 }
364 }
365 }
366};
367Q_DECLARE_OPERATORS_FOR_FLAGS(KEntryMap::SearchFlags)
368Q_DECLARE_OPERATORS_FOR_FLAGS(KEntryMap::EntryOptions)
369
370/**
371 * \relates KEntry
372 * type for iterating over keys in a KEntryMap in sorted order.
373 * @internal
374 */
375typedef KEntryMap::iterator KEntryMapIterator;
376
377/**
378 * \relates KEntry
379 * type for iterating over keys in a KEntryMap in sorted order.
380 * It is const, thus you cannot change the entries in the iterator,
381 * only examine them.
382 * @internal
383 */
384typedef KEntryMap::const_iterator KEntryMapConstIterator;
385
386#endif
387

source code of kconfig/src/core/kconfigdata_p.h