bugs
====

- make expandString stuff consistent
- KConfigGroup::exists() should return true only if the group contains
  any non-deleted entries (?)
- immutable groups with no entries are not written out and thus lose
  their immutability.
- "C" & "en_US" should be detected early and converted to a null string
  (but also save the original string, so locale() semantics don't change
  at that point).

wishes
======

- use lazy loading
  - load as soon as the first KConfigGroup is instantiated
  - lazy parsing of values is interesting, too - see kconfig_take2 branch
- add $\\VAR and $\\(cmd) escapes to list-quote expanded string
- possibly:
  - preserve unchanged parts of the config literally. problem: comments
    might become stale. so if a comment is already there, add an additional
    comment that indicates that the value was changed (include old value?).
  - api to actively add comments to files, groups and keys
    - option to start these comments with ## as a sign that they should not
      trigger the above change indicator logic.
  - guaranteeing that write order of new keys is preserved
  - detect commented out entries and put actual entries with the same key
    right behind them
- possibly: selective multi-level master diversion
  - this is to support roaming profiles that have machine/user/etc. specific
    settings
  - files, groups and keys can have [$m] and [$s] markers; these cascade
    within each file only. the least significant object (farthest away from
    the master) with an effective $m mode becomes the master (i.e., is
    written to and not read past).
    default is $m for the master file and $s for the default files.
  - the CascadeConfig flag being unset doesn't make things exactly simpler
  - can kdeglobals be handled by this?
  - does this really make sense? promoting an object to profile wide status
    is a conscious decision - which probably needs to be repeated every time
    the value changes.

internals
=========

- clear up bDeleted vs. isNull in entrymap
- make entrymap truly hierarchical
  - an entry map contains its flags, a map of keys and a map of submaps.
    it does NOT contain its name and has no parent pointer.
  - when creating a kconfiggroup, ask parent for the respective submap
    and link it if it is present. if it is not, create one at write op,
    link it and tell parent to add it to its entry map. both query and
    creation are recursive, obviously.
    a kconfiggroup DOES contain its name and has a parent pointer.
  - 3)
- 4)

3)
> We wouldn't have to worry about the KEntryGroup being removed out from
> under us, because the only way that should happen is if the config
> object is destroyed or reparsed, and in those cases you shouldn't be
> using a KConfigGroup from prior to that.
>
i don't think "this is stupid and will not happen" works; [...]
given that cascaded parsing includes writing to existing maps, i think
the simplest approach is clearing the existing structure from keymaps
and resetting the attributes, but leaving the subgroup maps populated,
thus keeping any group refs valid.
the question is about the type of reference held to the entry map.
originally i had thought of pointers. a map would be linked only if it
really existed, otherwise the pointer would be null (thus indicating
reads to return the default immediately and writes to ask the parent to
create a submap). however, keeping that consistent with deletions would
be a nightmare, and with the rescan changing the groups underneath
impossible without each map having a list of referring configgroups.
therefore it might make more sense to always create a corresponding tree
of empty maps when a configroup for a non-existing group is instantiated
- these groups won't be written out (they have no entries and cannot be
immutable) and access to non-existing groups (esp. without an subsequent
write that would actually create it) is rare, so the performance and
memory overhead of this "eager" approach is likely to be negligible. as
a middle way one could use a pointer and lazily populate it on first
access without putting semantics into the pointer being already set,
but i don't think the added complexity will pay off.

4)
> > > > hmm, wait. maybe it would be better if the map did not do actual
> > > > permission checking. the frontend is peppered with asserts already
> > >
> > > that's the group doing permission checking, if this group is immutable
> > > then the entry can't be changed. plus, now that KEntryKey doesn't know
> > > what group it belongs to KEntryMap can't check if the group is
> > > immutable.
> > >
> > > > (need to consider how to handle release builds). in the backend, the
> > > > ugly immutableGroups hack would be unnecessary.
> > >
> > > no, immutableGroups would still be necessary unless i remove all
> > > checking from KGroupEntry and KEntryMap. but, then checks for
> > > immutable would have to be used everywhere that an entry might be
> > > changed.
> > >
> > yes - and the frontend already handles it and the backend *should*
> > handle it (issue warnings for trying to overwrite $i settings).
>
> i don't know, i think most handling of the immutability of a group
> can/should be handled by the KGroupEntry itself. this way we can keep
> all the data about a group in one place and let KGroupEntry keep
> itself in a consistent/valid state.
>
dunno, either. the use cases are:
- backend: writing immutable objects is fine, as long as the
  immutability does not come from a pre-existing default.
  given that there will be multiple backends, it sounds like
  centralizing the check and warning reporting might make sense. otoh,
  such a low-level function might not have enough context to make a
  useful message.
- frontend: obviously, writing immutable objects is not permitted. this
  is already checked everywhere through asserts. in non-debug builds
  these asserts have no effect, but if a write gets that far it means
  that the app already permitted changing the option in the first place
  due to failure to check for immutability. i don't see much point in
  preventing the illegitimate change from being saved, as it can be
  repeated anyway (i'm not really convinced of security through
  exhaustion/boredom of the attacker :).
i'm not sure whether that means that the two use cases need separate
mutators or whether the mutator should not apply any immutability
semantics at all.


overwriting semantics
=====================

generally:
- localized entries cannot exist without an unlocalized "primary" entry,
  so writing a localized key when no corresponding unlocalized key
  exists should print a warning and copy the value to the unlocalized
  key.
- a primary entry in the user config overshadows not only the immediate
  default, but also any localizations of the default. applies also to a
  [$d] marker, obviously.
  a localized entry in the user config overshadows only that
  localization from the default.

write ops:
> > - writing an entry with the localization flag changes really only that
> >   key.
> >   trying to change the globality of the key prints a warning and does
> >   nothing.
- key exists in local config => overwritten
- key does not exist => created
yes, that's the trivial case.

> > - writing an entry without the localization flag deletes all
> >   localizations.
> >   in this case, changing the globality of the key poses no problem.
- the key itself is handled trivially
- if localizations exist in the local config, they are actively purged
- localizations in the default config don't matter, as they will be
  overshadowed by the unlocalized key in the local config

> > - deleting an entry also deletes all localizations.
- if default exists, write [$d] entry
- if no default exists, delete entry
- if localizations exist in the local config, they are actively purged
- localizations in the default config don't matter, as they will be
  overshadowed by the unlocalized key in the local config (as
  localizations cannot exist without a primary key, a deletion marker
  key will be present).

> > - reverting a key to default also restores all localizations.
- any local entries are actively purged


