core/smn_keyvalues.cpp
author David Anderson <dvander@alliedmods.net>
Sun Aug 19 18:34:36 2007 +0000 (2007-08-19)
changeset 1361 591f6d2fd11d
parent 1330 ab94316bb52b
child 1401 e3b761515c0a
permissions -rw-r--r--
added helper function for panel text
     1 /**
     2  * vim: set ts=4 :
     3  * =============================================================================
     4  * SourceMod
     5  * Copyright (C) 2004-2007 AlliedModders LLC.  All rights reserved.
     6  * =============================================================================
     7  *
     8  * This program is free software; you can redistribute it and/or modify it under
     9  * the terms of the GNU General Public License, version 3.0, as published by the
    10  * Free Software Foundation.
    11  * 
    12  * This program is distributed in the hope that it will be useful, but WITHOUT
    13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    14  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    15  * details.
    16  *
    17  * You should have received a copy of the GNU General Public License along with
    18  * this program.  If not, see <http://www.gnu.org/licenses/>.
    19  *
    20  * As a special exception, AlliedModders LLC gives you permission to link the
    21  * code of this program (as well as its derivative works) to "Half-Life 2," the
    22  * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
    23  * by the Valve Corporation.  You must obey the GNU General Public License in
    24  * all respects for all other code used.  Additionally, AlliedModders LLC grants
    25  * this exception to all derivative works.  AlliedModders LLC defines further
    26  * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
    27  * or <http://www.sourcemod.net/license.php>.
    28  *
    29  * Version: $Id$
    30  */
    31 
    32 #include "sourcemod.h"
    33 #include "sourcemm_api.h"
    34 #include "sm_stringutil.h"
    35 #include "HandleSys.h"
    36 #include <KeyValues.h>
    37 
    38 HandleType_t g_KeyValueType;
    39 
    40 struct KeyValueStack 
    41 {
    42 	KeyValues *pBase;
    43 	CStack<KeyValues *> pCurRoot;
    44 };
    45 
    46 class KeyValueNatives : 
    47 	public SMGlobalClass,
    48 	public IHandleTypeDispatch
    49 {
    50 public:
    51 	void OnSourceModAllInitialized()
    52 	{
    53 		g_KeyValueType = g_HandleSys.CreateType("KeyValues", this, 0, NULL, NULL, g_pCoreIdent, NULL);
    54 	}
    55 	void OnSourceModShutdown()
    56 	{
    57 		g_HandleSys.RemoveType(g_KeyValueType, g_pCoreIdent);
    58 		g_KeyValueType = 0;
    59 	}
    60 	void OnHandleDestroy(HandleType_t type, void *object)
    61 	{
    62 		KeyValueStack *pStk = reinterpret_cast<KeyValueStack *>(object);
    63 		pStk->pBase->deleteThis();
    64 		delete pStk;
    65 	}
    66 };
    67 
    68 KeyValues *SourceModBase::ReadKeyValuesHandle(Handle_t hndl, HandleError *err, bool root)
    69 {
    70 	HandleError herr;
    71 	HandleSecurity sec;
    72 	KeyValueStack *pStk;
    73 
    74 	sec.pOwner = NULL;
    75 	sec.pIdentity = g_pCoreIdent;
    76 
    77 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
    78 		!= HandleError_None)
    79 	{
    80 		if (err)
    81 		{
    82 			*err = herr;
    83 		}
    84 		return NULL;
    85 	}
    86 
    87 	if (err)
    88 	{
    89 		*err = HandleError_None;
    90 	}
    91 
    92 	return (root) ? pStk->pBase : pStk->pCurRoot.front();
    93 }
    94 
    95 static cell_t smn_KvSetString(IPluginContext *pCtx, const cell_t *params)
    96 {
    97 	Handle_t hndl = static_cast<Handle_t>(params[1]);
    98 	HandleError herr;
    99 	HandleSecurity sec;
   100 	KeyValueStack *pStk;
   101 
   102 	sec.pOwner = NULL;
   103 	sec.pIdentity = g_pCoreIdent;
   104 
   105 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   106 		!= HandleError_None)
   107 	{
   108 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   109 	}
   110 
   111 	char *key, *value;
   112 	pCtx->LocalToStringNULL(params[2], &key);
   113 	pCtx->LocalToString(params[3], &value);
   114 
   115 	pStk->pCurRoot.front()->SetString(key, value);
   116 
   117 	return 1;
   118 }
   119 
   120 static cell_t smn_KvSetNum(IPluginContext *pCtx, const cell_t *params)
   121 {
   122 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   123 	HandleError herr;
   124 	HandleSecurity sec;
   125 	KeyValueStack *pStk;
   126 
   127 	sec.pOwner = NULL;
   128 	sec.pIdentity = g_pCoreIdent;
   129 
   130 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   131 		!= HandleError_None)
   132 	{
   133 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   134 	}
   135 
   136 	char *key;
   137 	pCtx->LocalToStringNULL(params[2], &key);
   138 
   139 	pStk->pCurRoot.front()->SetInt(key, params[3]);
   140 
   141 	return 1;
   142 }
   143 
   144 static cell_t smn_KvSetUInt64(IPluginContext *pCtx, const cell_t *params)
   145 {
   146 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   147 	HandleError herr;
   148 	HandleSecurity sec;
   149 	KeyValueStack *pStk;
   150 
   151 	sec.pOwner = NULL;
   152 	sec.pIdentity = g_pCoreIdent;
   153 
   154 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   155 		!= HandleError_None)
   156 	{
   157 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   158 	}
   159 
   160 	char *key;
   161 	cell_t *addr;
   162 	uint64 value;
   163 	pCtx->LocalToStringNULL(params[2], &key);
   164 	pCtx->LocalToPhysAddr(params[3], &addr);
   165 
   166 	value = static_cast<uint64>(*addr);
   167 	pStk->pCurRoot.front()->SetUint64(key, value);
   168 
   169 	return 1;
   170 }
   171 
   172 static cell_t smn_KvSetFloat(IPluginContext *pCtx, const cell_t *params)
   173 {
   174 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   175 	HandleError herr;
   176 	HandleSecurity sec;
   177 	KeyValueStack *pStk;
   178 
   179 	sec.pOwner = NULL;
   180 	sec.pIdentity = g_pCoreIdent;
   181 
   182 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   183 		!= HandleError_None)
   184 	{
   185 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   186 	}
   187 
   188 	char *key;
   189 	pCtx->LocalToStringNULL(params[2], &key);
   190 
   191 	pStk->pCurRoot.front()->SetFloat(key, sp_ctof(params[3]));
   192 
   193 	return 1;
   194 }
   195 
   196 static cell_t smn_KvSetColor(IPluginContext *pCtx, const cell_t *params)
   197 {
   198 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   199 	HandleError herr;
   200 	HandleSecurity sec;
   201 	KeyValueStack *pStk;
   202 
   203 	sec.pOwner = NULL;
   204 	sec.pIdentity = g_pCoreIdent;
   205 
   206 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   207 		!= HandleError_None)
   208 	{
   209 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   210 	}
   211 
   212 	char *key;
   213 	pCtx->LocalToStringNULL(params[2], &key);
   214 
   215 	Color color(params[3], params[4], params[5], params[6]);
   216 	pStk->pCurRoot.front()->SetColor(key, color);
   217 
   218 	return 1;
   219 }
   220 
   221 static cell_t smn_KvGetString(IPluginContext *pCtx, const cell_t *params)
   222 {
   223 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   224 	HandleError herr;
   225 	HandleSecurity sec;
   226 	KeyValueStack *pStk;
   227 
   228 	sec.pOwner = NULL;
   229 	sec.pIdentity = g_pCoreIdent;
   230 
   231 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   232 		!= HandleError_None)
   233 	{
   234 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   235 	}
   236 
   237 	const char *value;
   238 	char *key, *defvalue;
   239 	pCtx->LocalToStringNULL(params[2], &key);
   240 	pCtx->LocalToString(params[5], &defvalue);
   241 
   242 	value = pStk->pCurRoot.front()->GetString(key, defvalue);
   243 	pCtx->StringToLocalUTF8(params[3], params[4], value, NULL);
   244 
   245 	return 1;
   246 }
   247 
   248 static cell_t smn_KvGetNum(IPluginContext *pCtx, const cell_t *params)
   249 {
   250 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   251 	HandleError herr;
   252 	HandleSecurity sec;
   253 	KeyValueStack *pStk;
   254 
   255 	sec.pOwner = NULL;
   256 	sec.pIdentity = g_pCoreIdent;
   257 
   258 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   259 		!= HandleError_None)
   260 	{
   261 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   262 	}
   263 
   264 	int value;
   265 	char *key;
   266 	pCtx->LocalToStringNULL(params[2], &key);
   267 
   268 	value = pStk->pCurRoot.front()->GetInt(key, params[3]);
   269 
   270 	return value;
   271 }
   272 
   273 static cell_t smn_KvGetFloat(IPluginContext *pCtx, const cell_t *params)
   274 {
   275 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   276 	HandleError herr;
   277 	HandleSecurity sec;
   278 	KeyValueStack *pStk;
   279 
   280 	sec.pOwner = NULL;
   281 	sec.pIdentity = g_pCoreIdent;
   282 
   283 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   284 		!= HandleError_None)
   285 	{
   286 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   287 	}
   288 
   289 	float value;
   290 	char *key;
   291 	pCtx->LocalToStringNULL(params[2], &key);
   292 
   293 	value = pStk->pCurRoot.front()->GetFloat(key, sp_ctof(params[3]));
   294 
   295 	return sp_ftoc(value);
   296 }
   297 
   298 static cell_t smn_KvGetColor(IPluginContext *pCtx, const cell_t *params)
   299 {
   300 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   301 	HandleError herr;
   302 	HandleSecurity sec;
   303 	KeyValueStack *pStk;
   304 
   305 	sec.pOwner = NULL;
   306 	sec.pIdentity = g_pCoreIdent;
   307 
   308 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   309 		!= HandleError_None)
   310 	{
   311 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   312 	}
   313 
   314 	Color color;
   315 	char *key;
   316 	cell_t *r, *g, *b, *a;
   317 	pCtx->LocalToStringNULL(params[2], &key);
   318 	pCtx->LocalToPhysAddr(params[3], &r);
   319 	pCtx->LocalToPhysAddr(params[4], &g);
   320 	pCtx->LocalToPhysAddr(params[5], &b);
   321 	pCtx->LocalToPhysAddr(params[6], &a);
   322 
   323 	color = pStk->pCurRoot.front()->GetColor(key);
   324 	*r = color.r();
   325 	*g = color.g();
   326 	*b = color.b();
   327 	*a = color.a();
   328 
   329 	return 1;
   330 }
   331 
   332 static cell_t smn_KvGetUInt64(IPluginContext *pCtx, const cell_t *params)
   333 {
   334 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   335 	HandleError herr;
   336 	HandleSecurity sec;
   337 	KeyValueStack *pStk;
   338 
   339 	sec.pOwner = NULL;
   340 	sec.pIdentity = g_pCoreIdent;
   341 
   342 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   343 		!= HandleError_None)
   344 	{
   345 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   346 	}
   347 
   348 	char *key;
   349 	cell_t *addr, *defvalue;
   350 	uint64 value;
   351 	pCtx->LocalToStringNULL(params[2], &key);
   352 	pCtx->LocalToPhysAddr(params[3], &addr);
   353 	pCtx->LocalToPhysAddr(params[4], &defvalue);
   354 
   355 	value = pStk->pCurRoot.front()->GetUint64(key, static_cast<uint64>(*defvalue));
   356 	*reinterpret_cast<uint64 *>(addr) = value;
   357 
   358 	return 1;
   359 }
   360 
   361 static cell_t smn_CreateKeyValues(IPluginContext *pCtx, const cell_t *params)
   362 {
   363 	KeyValueStack *pStk;
   364 	char *name, *firstkey, *firstvalue;
   365 	bool is_empty;
   366 
   367 	pCtx->LocalToString(params[1], &name);
   368 	pCtx->LocalToString(params[2], &firstkey);
   369 	pCtx->LocalToString(params[3], &firstvalue);
   370 
   371 	is_empty = (firstkey[0] == '\0');
   372 	pStk = new KeyValueStack;
   373 	pStk->pBase = new KeyValues(name, is_empty ? NULL : firstkey, (is_empty||(firstvalue[0]=='\0')) ? NULL : firstvalue);
   374 	pStk->pCurRoot.push(pStk->pBase);
   375 
   376 	return g_HandleSys.CreateHandle(g_KeyValueType, pStk, pCtx->GetIdentity(), g_pCoreIdent, NULL);
   377 }
   378 
   379 static cell_t smn_KvJumpToKey(IPluginContext *pCtx, const cell_t *params)
   380 {
   381 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   382 	HandleError herr;
   383 	HandleSecurity sec;
   384 	char *name;	
   385 	KeyValueStack *pStk;
   386 
   387 	sec.pOwner = NULL;
   388 	sec.pIdentity = g_pCoreIdent;
   389 
   390 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   391 		!= HandleError_None)
   392 	{
   393 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   394 	}
   395 
   396 	pCtx->LocalToString(params[2], &name);
   397 
   398 	KeyValues *pSubKey = pStk->pCurRoot.front();
   399 	pSubKey = pSubKey->FindKey(name, (params[3]) ? true : false);
   400 	if (!pSubKey)
   401 	{
   402 		return 0;
   403 	}
   404 	pStk->pCurRoot.push(pSubKey);
   405 
   406 	return 1;
   407 }
   408 
   409 static cell_t smn_KvGotoFirstSubKey(IPluginContext *pCtx, const cell_t *params)
   410 {
   411 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   412 	HandleError herr;
   413 	HandleSecurity sec;
   414 	KeyValueStack *pStk;
   415 
   416 	sec.pOwner = NULL;
   417 	sec.pIdentity = g_pCoreIdent;
   418 
   419 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   420 		!= HandleError_None)
   421 	{
   422 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   423 	}
   424 
   425 	KeyValues *pSubKey = pStk->pCurRoot.front();
   426 	KeyValues *pFirstSubKey;
   427 	if (params[2])
   428 	{
   429 		pFirstSubKey = pSubKey->GetFirstTrueSubKey();
   430 	} else {
   431 		pFirstSubKey = pSubKey->GetFirstSubKey();
   432 	}
   433 
   434 	if (!pFirstSubKey)
   435 	{
   436 		return 0;
   437 	}
   438 	pStk->pCurRoot.push(pFirstSubKey);
   439 
   440 	return 1;
   441 }
   442 
   443 static cell_t smn_KvGotoNextKey(IPluginContext *pCtx, const cell_t *params)
   444 {
   445 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   446 	HandleError herr;
   447 	HandleSecurity sec;
   448 	KeyValueStack *pStk;
   449 
   450 	sec.pOwner = NULL;
   451 	sec.pIdentity = g_pCoreIdent;
   452 
   453 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   454 		!= HandleError_None)
   455 	{
   456 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   457 	}
   458 
   459 	KeyValues *pSubKey = pStk->pCurRoot.front();
   460 	if (params[2])
   461 	{
   462 		pSubKey = pSubKey->GetNextTrueSubKey();
   463 	} else {
   464 		pSubKey = pSubKey->GetNextKey();
   465 	}
   466 	if (!pSubKey)
   467 	{
   468 		return 0;
   469 	}
   470 	pStk->pCurRoot.pop();
   471 	pStk->pCurRoot.push(pSubKey);
   472 
   473 	return 1;	
   474 }
   475 
   476 static cell_t smn_KvJumpNextSubKey(IPluginContext *pCtx, const cell_t *params)
   477 {
   478 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   479 	HandleError herr;
   480 	HandleSecurity sec;
   481 	KeyValueStack *pStk;
   482 
   483 	sec.pOwner = NULL;
   484 	sec.pIdentity = g_pCoreIdent;
   485 
   486 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   487 		!= HandleError_None)
   488 	{
   489 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   490 	}
   491 
   492 	KeyValues *pSubKey = pStk->pCurRoot.front();
   493 	KeyValues *pNextKey = pSubKey->GetNextKey();
   494 	if (!pNextKey)
   495 	{
   496 		return 0;
   497 	}
   498 	pStk->pCurRoot.push(pNextKey);
   499 
   500 	return 1;	
   501 }
   502 
   503 static cell_t smn_KvGoBack(IPluginContext *pCtx, const cell_t *params)
   504 {
   505 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   506 	HandleError herr;
   507 	HandleSecurity sec;
   508 	KeyValueStack *pStk;
   509 
   510 	sec.pOwner = NULL;
   511 	sec.pIdentity = g_pCoreIdent;
   512 
   513 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   514 		!= HandleError_None)
   515 	{
   516 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   517 	}
   518 
   519 	if (pStk->pCurRoot.size() == 1)
   520 	{
   521 		return 0;
   522 	}
   523 	pStk->pCurRoot.pop();
   524 
   525 	return 1;
   526 }
   527 
   528 static cell_t smn_KvRewind(IPluginContext *pCtx, const cell_t *params)
   529 {
   530 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   531 	HandleError herr;
   532 	HandleSecurity sec;
   533 	KeyValueStack *pStk;
   534 
   535 	sec.pOwner = NULL;
   536 	sec.pIdentity = g_pCoreIdent;
   537 
   538 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   539 		!= HandleError_None)
   540 	{
   541 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   542 	}
   543 
   544 	while (pStk->pCurRoot.size() > 1)
   545 	{
   546 		pStk->pCurRoot.pop();
   547 	}
   548 
   549 	return 1;
   550 }
   551 
   552 static cell_t smn_KvGetSectionName(IPluginContext *pCtx, const cell_t *params)
   553 {
   554 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   555 	HandleError herr;
   556 	HandleSecurity sec;
   557 	KeyValueStack *pStk;
   558 
   559 	sec.pOwner = NULL;
   560 	sec.pIdentity = g_pCoreIdent;
   561 
   562 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   563 		!= HandleError_None)
   564 	{
   565 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   566 	}
   567 
   568 	KeyValues *pSection = pStk->pCurRoot.front();
   569 	const char *name = pSection->GetName();
   570 	if (!name)
   571 	{
   572 		return 0;
   573 	}
   574 	pCtx->StringToLocalUTF8(params[2], params[3], name, NULL);
   575 
   576 	return 1;
   577 }
   578 
   579 static cell_t smn_KvSetSectionName(IPluginContext *pCtx, const cell_t *params)
   580 {
   581 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   582 	HandleError herr;
   583 	HandleSecurity sec;
   584 	char *name;
   585 	KeyValueStack *pStk;
   586 
   587 	sec.pOwner = NULL;
   588 	sec.pIdentity = g_pCoreIdent;
   589 
   590 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   591 		!= HandleError_None)
   592 	{
   593 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   594 	}
   595 
   596 	pCtx->LocalToString(params[2], &name);
   597 
   598 	KeyValues *pSection = pStk->pCurRoot.front();
   599 	pSection->SetName(name);
   600 
   601 	return 1;
   602 }
   603 
   604 static cell_t smn_KvGetDataType(IPluginContext *pCtx, const cell_t *params)
   605 {
   606 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   607 	HandleError herr;
   608 	HandleSecurity sec;
   609 	char *name;
   610 	KeyValueStack *pStk;
   611 
   612 	sec.pOwner = NULL;
   613 	sec.pIdentity = g_pCoreIdent;
   614 
   615 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   616 		!= HandleError_None)
   617 	{
   618 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   619 	}
   620 
   621 	pCtx->LocalToString(params[2], &name);
   622 
   623 	return pStk->pCurRoot.front()->GetDataType(name);
   624 }
   625 
   626 static cell_t smn_KeyValuesToFile(IPluginContext *pCtx, const cell_t *params)
   627 {
   628 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   629 	HandleError herr;
   630 	HandleSecurity sec;
   631 	char *path;
   632 	KeyValueStack *pStk;
   633 
   634 	sec.pOwner = NULL;
   635 	sec.pIdentity = g_pCoreIdent;
   636 
   637 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   638 		!= HandleError_None)
   639 	{
   640 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   641 	}
   642 
   643 	pCtx->LocalToString(params[2], &path);
   644 
   645 	char realpath[PLATFORM_MAX_PATH];
   646 	g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", path);
   647 
   648 	return pStk->pCurRoot.front()->SaveToFile(basefilesystem, realpath);
   649 }
   650 
   651 static cell_t smn_FileToKeyValues(IPluginContext *pCtx, const cell_t *params)
   652 {
   653 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   654 	HandleError herr;
   655 	HandleSecurity sec;
   656 	char *path;
   657 	KeyValueStack *pStk;
   658 
   659 	sec.pOwner = NULL;
   660 	sec.pIdentity = g_pCoreIdent;
   661 
   662 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   663 		!= HandleError_None)
   664 	{
   665 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   666 	}
   667 
   668 	pCtx->LocalToString(params[2], &path);
   669 
   670 	char realpath[PLATFORM_MAX_PATH];
   671 	g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", path);
   672 
   673 	return pStk->pCurRoot.front()->LoadFromFile(basefilesystem, realpath);
   674 }
   675 
   676 static cell_t smn_KvSetEscapeSequences(IPluginContext *pCtx, const cell_t *params)
   677 {
   678 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   679 	HandleError herr;
   680 	HandleSecurity sec;
   681 	KeyValueStack *pStk;
   682 
   683 	sec.pOwner = NULL;
   684 	sec.pIdentity = g_pCoreIdent;
   685 
   686 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   687 		!= HandleError_None)
   688 	{
   689 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   690 	}
   691 
   692 	pStk->pCurRoot.front()->UsesEscapeSequences(params[2] ? true : false);
   693 
   694 	return 1;
   695 }
   696 
   697 static cell_t smn_KvNodesInStack(IPluginContext *pCtx, const cell_t *params)
   698 {
   699 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   700 	HandleError herr;
   701 	HandleSecurity sec;
   702 	KeyValueStack *pStk;
   703 
   704 	sec.pOwner = NULL;
   705 	sec.pIdentity = g_pCoreIdent;
   706 
   707 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   708 		!= HandleError_None)
   709 	{
   710 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   711 	}
   712 
   713 	return pStk->pCurRoot.size() - 1;
   714 }
   715 
   716 static cell_t smn_KvDeleteThis(IPluginContext *pContext, const cell_t *params)
   717 {
   718 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   719 	HandleError herr;
   720 	HandleSecurity sec;
   721 	KeyValueStack *pStk;
   722 
   723 	sec.pOwner = NULL;
   724 	sec.pIdentity = g_pCoreIdent;
   725 
   726 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   727 		!= HandleError_None)
   728 	{
   729 		return pContext->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   730 	}
   731 
   732 	if (pStk->pCurRoot.size() < 2)
   733 	{
   734 		return 0;
   735 	}
   736 
   737 	KeyValues *pValues = pStk->pCurRoot.front();
   738 	pStk->pCurRoot.pop();
   739 	KeyValues *pRoot = pStk->pCurRoot.front();
   740 
   741 	/* We have to manually verify this since Valve sucks
   742 	 * :TODO: make our own KeyValues.h file and make
   743 	 * the sub stuff private so we can do this ourselves!
   744  	 */
   745 	KeyValues *sub = pRoot->GetFirstSubKey();
   746 	while (sub)
   747 	{
   748 		if (sub == pValues)
   749 		{
   750 			KeyValues *pNext = pValues->GetNextKey();
   751 			pRoot->RemoveSubKey(pValues);
   752 			pValues->deleteThis();
   753 			if (pNext)
   754 			{
   755 				pStk->pCurRoot.push(pNext);
   756 				return 1;
   757 			} else {
   758 				return -1;
   759 			}
   760 		}
   761 		sub = sub->GetNextKey();
   762 	}
   763 
   764 	/* Push this back on :( */
   765 	pStk->pCurRoot.push(pValues);
   766 
   767 	return 0;
   768 }
   769 
   770 static cell_t smn_KvDeleteKey(IPluginContext *pContext, const cell_t *params)
   771 {
   772 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   773 	HandleError herr;
   774 	HandleSecurity sec;
   775 	KeyValueStack *pStk;
   776 
   777 	sec.pOwner = NULL;
   778 	sec.pIdentity = g_pCoreIdent;
   779 
   780 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   781 		!= HandleError_None)
   782 	{
   783 		return pContext->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   784 	}
   785 
   786 	if (pStk->pCurRoot.size() < 2)
   787 	{
   788 		return 0;
   789 	}
   790 
   791 	char *keyName;
   792 	pContext->LocalToString(params[2], &keyName);
   793 
   794 	KeyValues *pRoot = pStk->pCurRoot.front();
   795 	KeyValues *pValues = pRoot->FindKey(keyName);
   796 	if (!pValues)
   797 	{
   798 		return 0;
   799 	}
   800 
   801 	pRoot->RemoveSubKey(pValues);
   802 	pValues->deleteThis();
   803 
   804 	return 1;
   805 }
   806 
   807 static cell_t smn_KvSavePosition(IPluginContext *pContext, const cell_t *params)
   808 {
   809 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   810 	HandleError herr;
   811 	HandleSecurity sec;
   812 	KeyValueStack *pStk;
   813 
   814 	sec.pOwner = NULL;
   815 	sec.pIdentity = g_pCoreIdent;
   816 
   817 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   818 		!= HandleError_None)
   819 	{
   820 		return pContext->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   821 	}
   822 
   823 	if (pStk->pCurRoot.size() < 2)
   824 	{
   825 		return 0;
   826 	}
   827 
   828 	KeyValues *pValues = pStk->pCurRoot.front();
   829 	pStk->pCurRoot.push(pValues);
   830 
   831 	return 1;
   832 }
   833 
   834 static KeyValueNatives s_KeyValueNatives;
   835 
   836 REGISTER_NATIVES(keyvaluenatives)
   837 {
   838 	{"KvSetString",				smn_KvSetString},
   839 	{"KvSetNum",				smn_KvSetNum},
   840 	{"KvSetUInt64",				smn_KvSetUInt64},
   841 	{"KvSetFloat",				smn_KvSetFloat},
   842 	{"KvSetColor",				smn_KvSetColor},
   843 	{"KvGetString",				smn_KvGetString},
   844 	{"KvGetNum",				smn_KvGetNum},
   845 	{"KvGetFloat",				smn_KvGetFloat},
   846 	{"KvGetColor",				smn_KvGetColor},
   847 	{"KvGetUInt64",				smn_KvGetUInt64},
   848 	{"CreateKeyValues",			smn_CreateKeyValues},
   849 	{"KvJumpToKey",				smn_KvJumpToKey},
   850 	{"KvGotoNextKey",			smn_KvGotoNextKey},
   851 	{"KvJumpFirstSubKey",		smn_KvGotoFirstSubKey},		/* BACKWARDS COMPAT SHIM */
   852 	{"KvGotoFirstSubKey",		smn_KvGotoFirstSubKey},
   853 	{"KvJumpNextSubKey",		smn_KvJumpNextSubKey},		/* BACKWARDS COMPAT SHIM */
   854 	{"KvGoBack",				smn_KvGoBack},
   855 	{"KvRewind",				smn_KvRewind},
   856 	{"KvGetSectionName",		smn_KvGetSectionName},
   857 	{"KvSetSectionName",		smn_KvSetSectionName},
   858 	{"KvGetDataType",			smn_KvGetDataType},
   859 	{"KeyValuesToFile",			smn_KeyValuesToFile},
   860 	{"FileToKeyValues",			smn_FileToKeyValues},
   861 	{"KvSetEscapeSequences",	smn_KvSetEscapeSequences},
   862 	{"KvDeleteThis",			smn_KvDeleteThis},
   863 	{"KvDeleteKey",				smn_KvDeleteKey},
   864 	{"KvNodesInStack",			smn_KvNodesInStack},
   865 	{"KvSavePosition",			smn_KvSavePosition},
   866 	{NULL,						NULL}
   867 };