File indexing completed on 2024-04-28 03:53:15

0001 /*
0002     This file is part of the KDE libraries
0003     SPDX-FileCopyrightText: 2006, 2007 Thomas Braxton <kde.braxton@gmail.com>
0004     SPDX-FileCopyrightText: 1999-2000 Preston Brown <pbrown@kde.org>
0005     SPDX-FileCopyrightText: 1996-2000 Matthias Kalle Dalheimer <kalle@kde.org>
0006 
0007     SPDX-License-Identifier: LGPL-2.0-or-later
0008 */
0009 
0010 #ifndef KCONFIGDATA_P_H
0011 #define KCONFIGDATA_P_H
0012 
0013 #include <QByteArray>
0014 #include <QDebug>
0015 #include <QString>
0016 #include <map>
0017 
0018 /**
0019  * map/dict/list config node entry.
0020  * @internal
0021  */
0022 struct KEntry {
0023     /** Constructor. @internal */
0024     KEntry()
0025         : mValue()
0026         , bDirty(false)
0027         , bGlobal(false)
0028         , bImmutable(false)
0029         , bDeleted(false)
0030         , bExpand(false)
0031         , bReverted(false)
0032         , bLocalizedCountry(false)
0033         , bNotify(false)
0034         , bOverridesGlobal(false)
0035     {
0036     }
0037     /** @internal */
0038     QByteArray mValue;
0039     /**
0040      * Must the entry be written back to disk?
0041      */
0042     bool bDirty : 1;
0043     /**
0044      * Entry should be written to the global config file
0045      */
0046     bool bGlobal : 1;
0047     /**
0048      * Entry can not be modified.
0049      */
0050     bool bImmutable : 1;
0051     /**
0052      * Entry has been deleted.
0053      */
0054     bool bDeleted : 1;
0055     /**
0056      * Whether to apply dollar expansion or not.
0057      */
0058     bool bExpand : 1;
0059     /**
0060      * Entry has been reverted to its default value (from a more global file).
0061      */
0062     bool bReverted : 1;
0063     /**
0064      * Entry is for a localized key. If @c false the value references just language e.g. "de",
0065      * if @c true the value references language and country, e.g. "de_DE".
0066      **/
0067     bool bLocalizedCountry : 1;
0068 
0069     bool bNotify : 1;
0070 
0071     /**
0072      * Entry will need to be written on a non global file even if it matches default value
0073      */
0074     bool bOverridesGlobal : 1;
0075 };
0076 
0077 Q_DECLARE_TYPEINFO(KEntry, Q_RELOCATABLE_TYPE);
0078 
0079 // These operators are used to check whether an entry which is about
0080 // to be written equals the previous value. As such, this intentionally
0081 // omits the dirty/notify flag from the comparison.
0082 inline bool operator==(const KEntry &k1, const KEntry &k2)
0083 {
0084     /* clang-format off */
0085     return k1.bGlobal == k2.bGlobal
0086         && k1.bImmutable == k2.bImmutable
0087         && k1.bDeleted == k2.bDeleted
0088         && k1.bExpand == k2.bExpand
0089         && k1.mValue == k2.mValue;
0090     /* clang-format on */
0091 }
0092 
0093 inline bool operator!=(const KEntry &k1, const KEntry &k2)
0094 {
0095     return !(k1 == k2);
0096 }
0097 
0098 /**
0099  * key structure holding both the actual key and the group
0100  * to which it belongs.
0101  * @internal
0102  */
0103 struct KEntryKey {
0104     /** Constructor. @internal */
0105     KEntryKey(const QString &_group = QString(), const QByteArray &_key = QByteArray(), bool isLocalized = false, bool isDefault = false)
0106         : mGroup(_group)
0107         , mKey(_key)
0108         , bLocal(isLocalized)
0109         , bDefault(isDefault)
0110         , bRaw(false)
0111     {
0112     }
0113     /**
0114      * The "group" to which this EntryKey belongs
0115      */
0116     QString mGroup;
0117     /**
0118      * The _actual_ key of the entry in question
0119      */
0120     QByteArray mKey;
0121     /**
0122      * Entry is localised or not
0123      */
0124     bool bLocal : 1;
0125     /**
0126      * Entry indicates if this is a default value.
0127      */
0128     bool bDefault : 1;
0129     /** @internal
0130      * Key is a raw unprocessed key.
0131      * @warning this should only be set during merging, never for normal use.
0132      */
0133     bool bRaw : 1;
0134 };
0135 
0136 Q_DECLARE_TYPEINFO(KEntryKey, Q_RELOCATABLE_TYPE);
0137 
0138 /**
0139  * Compares two KEntryKeys (needed for std::map). The order is localized, localized-default,
0140  * non-localized, non-localized-default
0141  * @internal
0142  */
0143 inline bool operator<(const KEntryKey &k1, const KEntryKey &k2)
0144 {
0145     int result = k1.mGroup.compare(k2.mGroup);
0146     if (result != 0) {
0147         return result < 0;
0148     }
0149 
0150     result = k1.mKey.compare(k2.mKey);
0151     if (result != 0) {
0152         return result < 0;
0153     }
0154 
0155     if (k1.bLocal != k2.bLocal) {
0156         return k1.bLocal;
0157     }
0158     return (!k1.bDefault && k2.bDefault);
0159 }
0160 
0161 /**
0162  * Light-weight view variant of KEntryKey.
0163  * Used for look-up in the map.
0164  * @internal
0165  */
0166 struct KEntryKeyView {
0167     /** Constructor. @internal */
0168     KEntryKeyView(QStringView _group, QAnyStringView _key, bool isLocalized = false, bool isDefault = false)
0169         : mGroup(_group)
0170         , mKey(_key)
0171         , bLocal(isLocalized)
0172         , bDefault(isDefault)
0173     {
0174     }
0175     /**
0176      * The "group" to which this EntryKey belongs
0177      */
0178     const QStringView mGroup;
0179     /**
0180      * The _actual_ key of the entry in question
0181      */
0182     const QAnyStringView mKey;
0183     /**
0184      * Entry is localised or not
0185      */
0186     bool bLocal : 1;
0187     /**
0188      * Entry indicates if this is a default value.
0189      */
0190     bool bDefault : 1;
0191 };
0192 
0193 template<typename TEntryKey1, typename TEntryKey2>
0194 bool compareEntryKeyViews(const TEntryKey1 &k1, const TEntryKey2 &k2)
0195 {
0196     int result = k1.mGroup.compare(k2.mGroup);
0197     if (result != 0) {
0198         return result < 0;
0199     }
0200 
0201     result = QAnyStringView::compare(k1.mKey, k2.mKey);
0202     if (result != 0) {
0203         return result < 0;
0204     }
0205 
0206     if (k1.bLocal != k2.bLocal) {
0207         return k1.bLocal;
0208     }
0209     return (!k1.bDefault && k2.bDefault);
0210 }
0211 
0212 inline bool operator<(const KEntryKeyView &k1, const KEntryKey &k2)
0213 {
0214     return compareEntryKeyViews(k1, k2);
0215 }
0216 
0217 inline bool operator<(const KEntryKey &k1, const KEntryKeyView &k2)
0218 {
0219     return compareEntryKeyViews(k1, k2);
0220 }
0221 
0222 /**
0223  * Struct to use as Compare type with std::map.
0224  * To enable usage of KEntryKeyView for look-up in the map
0225  * via the template find() overloads.
0226  * @internal
0227  */
0228 struct KEntryKeyCompare {
0229     using is_transparent = void;
0230 
0231     bool operator()(const KEntryKey &k1, const KEntryKey &k2) const
0232     {
0233         return (k1 < k2);
0234     }
0235 
0236     bool operator()(const KEntryKeyView &k1, const KEntryKey &k2) const
0237     {
0238         return (k1 < k2);
0239     }
0240 
0241     bool operator()(const KEntryKey &k1, const KEntryKeyView &k2) const
0242     {
0243         return (k1 < k2);
0244     }
0245 };
0246 
0247 /**
0248  * Returns the minimum key that has @a mGroup == @p group.
0249  *
0250  * @note The returned "minimum key" is consistent with KEntryKey's operator<().
0251  *       The return value of this function can be passed to KEntryMap::lowerBound().
0252  */
0253 inline KEntryKeyView minimumGroupKeyView(const QString &group)
0254 {
0255     return KEntryKeyView(group, QAnyStringView{}, true, false);
0256 }
0257 
0258 QDebug operator<<(QDebug dbg, const KEntryKey &key);
0259 QDebug operator<<(QDebug dbg, const KEntry &entry);
0260 
0261 /**
0262  * \relates KEntry
0263  * type specifying a map of entries (key,value pairs).
0264  * The keys are actually a key in a particular config file group together
0265  * with the group name.
0266  * @internal
0267  */
0268 class KEntryMap : public std::map<KEntryKey, KEntry, KEntryKeyCompare>
0269 {
0270 public:
0271     enum SearchFlag {
0272         SearchDefaults = 1,
0273         SearchLocalized = 2,
0274     };
0275     Q_DECLARE_FLAGS(SearchFlags, SearchFlag)
0276 
0277     enum EntryOption {
0278         EntryDirty = 1,
0279         EntryGlobal = 2,
0280         EntryImmutable = 4,
0281         EntryDeleted = 8,
0282         EntryExpansion = 16,
0283         EntryRawKey = 32,
0284         EntryLocalizedCountry = 64,
0285         EntryNotify = 128,
0286         EntryDefault = (SearchDefaults << 16),
0287         EntryLocalized = (SearchLocalized << 16),
0288     };
0289     Q_DECLARE_FLAGS(EntryOptions, EntryOption)
0290 
0291     iterator findExactEntry(const QString &group, QAnyStringView key = QAnyStringView(), SearchFlags flags = SearchFlags());
0292 
0293     iterator findEntry(const QString &group, QAnyStringView key = QAnyStringView(), SearchFlags flags = SearchFlags());
0294 
0295     const_iterator findEntry(const QString &group, QAnyStringView key = QAnyStringView(), SearchFlags flags = SearchFlags()) const
0296     {
0297         return constFindEntry(group, key, flags);
0298     }
0299 
0300     const_iterator constFindEntry(const QString &group, QAnyStringView key = QAnyStringView(), SearchFlags flags = SearchFlags()) const;
0301 
0302     /**
0303      * Returns true if the entry gets dirtied or false in other case
0304      */
0305     bool setEntry(const QString &group, const QByteArray &key, const QByteArray &value, EntryOptions options);
0306 
0307     void setEntry(const QString &group, const QByteArray &key, const QString &value, EntryOptions options)
0308     {
0309         setEntry(group, key, value.toUtf8(), options);
0310     }
0311 
0312     QString getEntry(const QString &group,
0313                      QAnyStringView key,
0314                      const QString &defaultValue = QString(),
0315                      SearchFlags flags = SearchFlags(),
0316                      bool *expand = nullptr) const;
0317 
0318     bool hasEntry(const QString &group, QAnyStringView key = QAnyStringView(), SearchFlags flags = SearchFlags()) const;
0319 
0320     bool getEntryOption(const const_iterator &it, EntryOption option) const;
0321     bool getEntryOption(const QString &group, QAnyStringView key, SearchFlags flags, EntryOption option) const
0322     {
0323         return getEntryOption(findEntry(group, key, flags), option);
0324     }
0325 
0326     void setEntryOption(iterator it, EntryOption option, bool bf);
0327     void setEntryOption(const QString &group, QAnyStringView key, SearchFlags flags, EntryOption option, bool bf)
0328     {
0329         setEntryOption(findEntry(group, key, flags), option, bf);
0330     }
0331 
0332     bool revertEntry(const QString &group, QAnyStringView key, EntryOptions options, SearchFlags flags = SearchFlags());
0333 
0334     template<typename ConstIteratorUser>
0335     void forEachEntryWhoseGroupStartsWith(const QString &groupPrefix, ConstIteratorUser callback) const
0336     {
0337         for (auto it = lower_bound(minimumGroupKeyView(groupPrefix)), end = cend(); it != end && it->first.mGroup.startsWith(groupPrefix); ++it) {
0338             callback(it);
0339         }
0340     }
0341 
0342     template<typename ConstIteratorPredicate>
0343     bool anyEntryWhoseGroupStartsWith(const QString &groupPrefix, ConstIteratorPredicate predicate) const
0344     {
0345         for (auto it = lower_bound(minimumGroupKeyView(groupPrefix)), end = cend(); it != end && it->first.mGroup.startsWith(groupPrefix); ++it) {
0346             if (predicate(it)) {
0347                 return true;
0348             }
0349         }
0350         return false;
0351     }
0352 
0353     template<typename ConstIteratorUser>
0354     void forEachEntryOfGroup(const QString &theGroup, ConstIteratorUser callback) const
0355     {
0356         const auto theEnd = cend();
0357         auto it = constFindEntry(theGroup);
0358         if (it != theEnd) {
0359             ++it; // advance past the special group entry marker
0360 
0361             for (; (it != theEnd) && (it->first.mGroup == theGroup); ++it) {
0362                 callback(it);
0363             }
0364         }
0365     }
0366 };
0367 Q_DECLARE_OPERATORS_FOR_FLAGS(KEntryMap::SearchFlags)
0368 Q_DECLARE_OPERATORS_FOR_FLAGS(KEntryMap::EntryOptions)
0369 
0370 /**
0371  * \relates KEntry
0372  * type for iterating over keys in a KEntryMap in sorted order.
0373  * @internal
0374  */
0375 typedef KEntryMap::iterator KEntryMapIterator;
0376 
0377 /**
0378  * \relates KEntry
0379  * type for iterating over keys in a KEntryMap in sorted order.
0380  * It is const, thus you cannot change the entries in the iterator,
0381  * only examine them.
0382  * @internal
0383  */
0384 typedef KEntryMap::const_iterator KEntryMapConstIterator;
0385 
0386 #endif