From 34934677718051aec37377fdab1ddf9fe7cfd95a Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 7 May 2007 02:58:58 +0000 Subject: [PATCH] small rewrite of how keyvalues iterator and get deleted. phew! --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40759 --- core/smn_keyvalues.cpp | 109 +++++++++++++++++++++++++++++++--- plugins/include/keyvalues.inc | 36 +++++++++-- 2 files changed, 132 insertions(+), 13 deletions(-) diff --git a/core/smn_keyvalues.cpp b/core/smn_keyvalues.cpp index 8803f177..95073117 100644 --- a/core/smn_keyvalues.cpp +++ b/core/smn_keyvalues.cpp @@ -389,7 +389,7 @@ static cell_t smn_KvJumpToKey(IPluginContext *pCtx, const cell_t *params) return 1; } -static cell_t smn_KvJumpFirstSubKey(IPluginContext *pCtx, const cell_t *params) +static cell_t smn_KvGotoFirstSubKey(IPluginContext *pCtx, const cell_t *params) { Handle_t hndl = static_cast(params[1]); HandleError herr; @@ -406,7 +406,14 @@ static cell_t smn_KvJumpFirstSubKey(IPluginContext *pCtx, const cell_t *params) } KeyValues *pSubKey = pStk->pCurRoot.front(); - KeyValues *pFirstSubKey = pSubKey->GetFirstSubKey(); + KeyValues *pFirstSubKey; + if (params[2]) + { + pFirstSubKey = pSubKey->GetFirstTrueSubKey(); + } else { + pFirstSubKey = pSubKey->GetFirstSubKey(); + } + if (!pFirstSubKey) { return 0; @@ -416,6 +423,39 @@ static cell_t smn_KvJumpFirstSubKey(IPluginContext *pCtx, const cell_t *params) return 1; } +static cell_t smn_KvGotoNextKey(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + KeyValueStack *pStk; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr); + } + + KeyValues *pSubKey = pStk->pCurRoot.front(); + if (params[2]) + { + pSubKey = pSubKey->GetNextKey(); + } else { + pSubKey = pSubKey->GetNextTrueSubKey(); + } + if (!pSubKey) + { + return 0; + } + pStk->pCurRoot.pop(); + pStk->pCurRoot.push(pSubKey); + + return 1; +} + static cell_t smn_KvJumpNextSubKey(IPluginContext *pCtx, const cell_t *params) { Handle_t hndl = static_cast(params[1]); @@ -679,10 +719,35 @@ static cell_t smn_KvDeleteThis(IPluginContext *pContext, const cell_t *params) KeyValues *pValues = pStk->pCurRoot.front(); pStk->pCurRoot.pop(); - pStk->pCurRoot.front()->RemoveSubKey(pValues); - pValues->deleteThis(); + KeyValues *pRoot = pStk->pCurRoot.front(); - return 1; + /* We have to manually verify this since Valve sucks + * :TODO: make our own KeyValues.h file and make + * the sub stuff private so we can do this ourselves! + */ + KeyValues *sub = pRoot->GetFirstSubKey(); + while (sub) + { + if (sub == pValues) + { + KeyValues *pNext = pValues->GetNextKey(); + pRoot->RemoveSubKey(pValues); + pValues->deleteThis(); + if (pNext) + { + pStk->pCurRoot.push(pNext); + return 1; + } else { + return -1; + } + } + sub = sub->GetNextKey(); + } + + /* Push this back on :( */ + pStk->pCurRoot.push(pValues); + + return 0; } static cell_t smn_KvDeleteKey(IPluginContext *pContext, const cell_t *params) @@ -722,6 +787,33 @@ static cell_t smn_KvDeleteKey(IPluginContext *pContext, const cell_t *params) return 1; } +static cell_t smn_KvSavePosition(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + KeyValueStack *pStk; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr); + } + + if (pStk->pCurRoot.size() < 2) + { + return 0; + } + + KeyValues *pValues = pStk->pCurRoot.front(); + pStk->pCurRoot.push(pValues); + + return 1; +} + static KeyValueNatives s_KeyValueNatives; REGISTER_NATIVES(keyvaluenatives) @@ -738,8 +830,10 @@ REGISTER_NATIVES(keyvaluenatives) {"KvGetUint64", smn_KvGetUint64}, {"CreateKeyValues", smn_CreateKeyValues}, {"KvJumpToKey", smn_KvJumpToKey}, - {"KvJumpFirstSubKey", smn_KvJumpFirstSubKey}, - {"KvJumpNextSubKey", smn_KvJumpNextSubKey}, + {"KvGotoNextKey", smn_KvGotoNextKey}, + {"KvJumpFirstSubKey", smn_KvGotoFirstSubKey}, /* BACKWARDS COMPAT SHIM */ + {"KvGotoFirstSubKey", smn_KvGotoFirstSubKey}, + {"KvJumpNextSubKey", smn_KvJumpNextSubKey}, /* BACKWARDS COMPAT SHIM */ {"KvGoBack", smn_KvGoBack}, {"KvRewind", smn_KvRewind}, {"KvGetSectionName", smn_KvGetSectionName}, @@ -751,5 +845,6 @@ REGISTER_NATIVES(keyvaluenatives) {"KvDeleteThis", smn_KvDeleteThis}, {"KvDeleteKey", smn_KvDeleteKey}, {"KvNodesInStack", smn_KvNodesInStack}, + {"KvSavePosition", smn_KvSavePosition}, {NULL, NULL} }; diff --git a/plugins/include/keyvalues.inc b/plugins/include/keyvalues.inc index bb373d67..6c816319 100644 --- a/plugins/include/keyvalues.inc +++ b/plugins/include/keyvalues.inc @@ -176,21 +176,37 @@ native bool:KvJumpToKey(Handle:kv, const String:key[], bool:create=false); /** * Sets the current position in the KeyValues tree to the first sub key. + * This native adds to the internal traversal stack. * * @param kv KeyValues Handle. + * @param keyOnly If false, non-keys will be traversed (values). * @return True on success, false if there was no first sub key. * @error Invalid Handle. */ -native bool:KvJumpFirstSubKey(Handle:kv); +native bool:KvGotoFirstSubKey(Handle:kv, bool:keyOnly=true); /** * Sets the current position in the KeyValues tree to the next sub key. + * This native does NOT add to the internal traversal stack, and thus + * KvGoBack() is not needed for each successive call to this function. * * @param kv KeyValues Handle. + * @param keyOnly If false, non-keys will be traversed (values). * @return True on success, false if there was no next sub key. * @error Invalid Handle. */ -native bool:KvJumpNextSubKey(Handle:kv); +native bool:KvGotoNextKey(Handle:kv, bool:keyOnly=true); + +/** + * Saves the current position in the traversal stack onto the traversal + * stack. This can be useful if you wish to use KvGotoNextKey() and + * have the previous key saved for backwards traversal. + * + * @param kv KeyValues Handle. + * @noreturn + * @error Invalid Handle. + */ +native KvSavePosition(Handle:kv); /** * Removes the given key from the current position. @@ -203,19 +219,27 @@ native bool:KvJumpNextSubKey(Handle:kv); native bool:KvDeleteKey(Handle:kv, const String:key[]); /** - * Removes the current sub-key and jumps back one position, using the previous - * position as the search point. This will not work if used on the root node. + * Removes the current sub-key and attempts to set the position + * to the sub-key after the removed one. If no such sub-key exists, + * the position will be the parent key in the traversal stack. + * Given the sub-key having position "N" in the traversal stack, the + * removal will always take place from position "N-1." * * @param kv KeyValues Handle. - * @return True on success, false if there was no sub key. + * @return 1 if removal succeeded and there was another key. + * 0 if the current node was not contained in the + * previous node, or no previous node exists. + * -1 if removal succeeded and there were no more keys, + * thus the state is as if KvGoBack() was called. * @error Invalid Handle. */ -native bool:KvDeleteThis(Handle:kv); +native KvDeleteThis(Handle:kv); /** * Jumps back to the previous position. Returns false if there are no * previous positions (i.e., at the root node). This should be called * once for each successful Jump call, in order to return to the top node. + * This function pops one node off the internal traversal stack. * * @param kv KeyValues Handle. * @return True on success, false if there is no higher node.