AlliedModders

AlliedModders (https://forums.alliedmods.net/index.php)
-   Snippets and Tutorials (https://forums.alliedmods.net/forumdisplay.php?f=112)
-   -   [STOCK] merge KeyValues (https://forums.alliedmods.net/showthread.php?t=278595)

statistician 02-04-2016 02:14

[STOCK] merge KeyValues
 
Here's a stock to merge two KeyValues together (and a couple others that are used).

Code:

#define MAX_SECTION_LENGTH    128

/**
 * Returns whether ot not the current key is an empty tree (section).
 *
 * @param kv    KeyValues handle.
 * @return      True if current key is a tree and is empty, false otherwise.
 */
stock bool KvIsEmptyTree(Handle kv) {
    if (KvGotoFirstSubKey(kv, false)) {
        KvGoBack(kv);
        return false;
    }

    char value[128];
    KvGetString(kv, NULL_STRING, value, sizeof(value), "#novalue");
    return StrEqual(value, "#novalue"); // is it an empty tree
}

/**
 * Returns whether ot not the current key is a tree (section).
 *
 * @param kv    KeyValues handle.
 * @return      True if current key is a tree (section), false otherwise.
 */
stock bool KvIsTree(Handle kv) {
    if (KvGotoFirstSubKey(kv, false)) {
        KvGoBack(kv);
        return true;
    }

    char value[128];
    KvGetString(kv, NULL_STRING, value, sizeof(value), "#novalue");
    return StrEqual(value, "#novalue"); // is it an empty tree
}

/**
 * Jumps to a key that is on the same level as the current one,
 * if such a key exists.
 *
 * @param kv    KeyValues handle.
 * @return      True if the key existed, false otherwise.
 */
stock bool KvJumpToSiblingKey(Handle kv, char[] target) {
    char start[MAX_SECTION_LENGTH];
    KvGetSectionName(kv, start, sizeof(start));

    if (KvNodesInStack(kv) == 0)
        return StrEqual(start, target);

    KvGoBack(kv);
    if (KvJumpToKey(kv, target))
        return true;

    KvJumpToKey(kv, start);
    return false;
}

/**
 * Merges two KeyValues into one.
 *
 * @param kv_to        KeyValues handle to which new information should be written.
 * @param kv_form      KeyValues handle from which new information should be copied.
 * @noreturn
 */
stock void KvMerge(Handle kv_to, Handle kv_from) {
    char key_from[MAX_SECTION_LENGTH], value_from[MAX_SECTION_LENGTH];
    do {
        KvGetSectionName(kv_from, key_from, sizeof(key_from));

        if (KvIsEmptyTree(kv_from)) {
            KvGoBack(kv_to);
            KvJumpToKey(kv_to, key_from, true);
        } else if (KvIsTree(kv_from)) {
            KvGotoFirstSubKey(kv_from, false);

            if (!KvJumpToSiblingKey(kv_to, key_from)) {
                KvJumpToKey(kv_to, key_from, true);
                KvGetSectionName(kv_from, key_from, sizeof(key_from));
                if (KvIsTree(kv_from)) {
                    KvJumpToKey(kv_to, key_from, true);
                    KvGoBack(kv_to);
                } else {
                    KvGetString(kv_from, NULL_STRING, value_from, sizeof(value_from));
                    KvSetString(kv_to, key_from, value_from);
                }
            }

            KvGotoFirstSubKey(kv_to, false);

            KvMerge(kv_to, kv_from);

            KvGoBack(kv_from);
            KvGoBack(kv_to);
        } else {
            KvGetString(kv_from, NULL_STRING, value_from, sizeof(value_from));
            KvGoBack(kv_to);
            KvSetString(kv_to, key_from, value_from);
            KvGotoFirstSubKey(kv_to, false);
        }
    } while (KvGotoNextKey(kv_from, false));
}

I haven't tested merging extensively, but it worked for the cases I did test. Let me know if you have suggestions or notice any problems.

Example:

kv1:

Code:

"KeyValues"
{
    "key1"    "value"

    "names" {
        "name1"    "bob"
        "name2"    "james"
    }
}

kv2:

Code:

"KeyValues"
{
    "key2"    "value"

    "names" {
        "name3"    "mike"
        "name4"    "henry"
    }
}

If I do KvMerge(kv1, kv2), kv1 is now:

Code:

"KeyValues"
{
    "key1"    "value"
    "key2"    "value"

    "names" {
        "name1"    "bob"
        "name2"    "james"
        "name3"    "mike"
        "name4"    "henry"
    }
}


eyal282 02-10-2019 05:20

Re: [STOCK] merge KeyValues
 
This seems not to work for merging from a specific point. After all it nulls your current position after using the stock. Any way to support merging from a position?


All times are GMT -4. The time now is 08:16.

Powered by vBulletin®
Copyright ©2000 - 2024, vBulletin Solutions, Inc.