core/smn_keyvalues.cpp
author Scott Ehlert <ds@alliedmods.net>
Wed Nov 19 02:16:45 2008 -0600 (2008-11-19)
changeset 2415 9ac720a36ce4
parent 2414 e28a9247061f
child 2416 4400dd5bc470
permissions -rw-r--r--
Merge.
     1 /**
     2  * vim: set ts=4 :
     3  * =============================================================================
     4  * SourceMod
     5  * Copyright (C) 2004-2008 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 "HalfLife2.h"
    37 #include <KeyValues.h>
    38 #include "utlbuffer.h"
    39 
    40 HandleType_t g_KeyValueType;
    41 
    42 struct KeyValueStack 
    43 {
    44 	KeyValues *pBase;
    45 	CStack<KeyValues *> pCurRoot;
    46 };
    47 
    48 class KeyValueNatives : 
    49 	public SMGlobalClass,
    50 	public IHandleTypeDispatch
    51 {
    52 public:
    53 	void OnSourceModAllInitialized()
    54 	{
    55 		g_KeyValueType = g_HandleSys.CreateType("KeyValues", this, 0, NULL, NULL, g_pCoreIdent, NULL);
    56 	}
    57 	void OnSourceModShutdown()
    58 	{
    59 		g_HandleSys.RemoveType(g_KeyValueType, g_pCoreIdent);
    60 		g_KeyValueType = 0;
    61 	}
    62 	void OnHandleDestroy(HandleType_t type, void *object)
    63 	{
    64 		KeyValueStack *pStk = reinterpret_cast<KeyValueStack *>(object);
    65 		pStk->pBase->deleteThis();
    66 		delete pStk;
    67 	}
    68 	int CalcKVSizeR(KeyValues *pv)
    69 	{
    70 		CUtlBuffer buf;
    71 		int size;
    72 
    73 		pv->RecursiveSaveToFile(buf, 0);
    74 		size = buf.TellMaxPut();
    75 
    76 		buf.Purge();
    77 
    78 		return size;
    79 	}
    80 	bool GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize)
    81 	{
    82 		KeyValueStack *pStk = (KeyValueStack *)object;
    83 		unsigned int size = sizeof(KeyValueStack) + (pStk->pCurRoot.size() * sizeof(KeyValues *));
    84 
    85 		/* Check how much memory the actual thing takes up */		
    86 		size += CalcKVSizeR(pStk->pBase);
    87 
    88 		*pSize = size;
    89 
    90 		return true;
    91 	}
    92 };
    93 
    94 /* From MM:S - metamod_util.cpp */
    95 inline bool pathchar_isalpha(char a)
    96 {
    97 	return (((a & 1<<7) == 0) && isalpha(a));
    98 }
    99 
   100 inline bool pathchar_sep(char a)
   101 {
   102 #if defined WIN32
   103 	return (a == '/' || a == '\\');
   104 #elif defined __linux__
   105 	return (a == '/');
   106 #endif
   107 }
   108 
   109 inline bool pathstr_isabsolute(const char *str)
   110 {
   111 #if defined WIN32
   112 	return (pathchar_isalpha(str[0]) 
   113 		&& str[1] == ':' 
   114 		&& pathchar_sep(str[2]));
   115 #elif defined __linux__
   116 	return (str[0] == '/');
   117 #endif
   118 }
   119 
   120 inline bool pathchar_cmp(char a, char b)
   121 {
   122 #if defined PLATFORM_WINDOWS
   123 	if (pathchar_isalpha(a) && pathchar_isalpha(b))
   124 	{
   125 		return (tolower(a) == tolower(b));
   126 	}
   127 	/* Either path separator is acceptable */
   128 	if (pathchar_sep(a))
   129 	{
   130 		return pathchar_sep(b);
   131 	}
   132 #endif
   133 	return (a == b);
   134 }
   135 
   136 bool UTIL_Relatize(char buffer[],
   137 				   size_t maxlength,
   138 				   const char *relTo,
   139 				   const char *relFrom)
   140 {
   141 	/* We don't allow relative paths in here, force
   142 	* the user to resolve these himself!
   143 	*/
   144 	if (!pathstr_isabsolute(relTo)
   145 		|| !pathstr_isabsolute(relFrom))
   146 	{
   147 		return false;
   148 	}
   149 
   150 #if defined PLATFORM_WINDOWS
   151 	/* Relative paths across drives are not possible */
   152 	if (!pathchar_cmp(relTo[0], relFrom[0]))
   153 	{
   154 		return false;
   155 	}
   156 	/* Get rid of the drive and semicolon part */
   157 	relTo = &relTo[2];
   158 	relFrom = &relFrom[2];
   159 #endif
   160 
   161 	/* Eliminate the common root between the paths */
   162 	const char *rootTo = NULL;
   163 	const char *rootFrom = NULL;
   164 	while (*relTo != '\0' && *relFrom != '\0')
   165 	{
   166 		/* If we get to a new path sequence, start over */
   167 		if (pathchar_sep(*relTo)
   168 			&& pathchar_sep(*relFrom))
   169 		{
   170 			rootTo = relTo;
   171 			rootFrom = relFrom;
   172 			/* If the paths don't compare, stop looking for a common root */
   173 		} else if (!pathchar_cmp(*relTo, *relFrom)) {
   174 			break;
   175 		}
   176 		relTo++;
   177 		relFrom++;
   178 	}
   179 
   180 	/* NULLs shouldn't happen! */
   181 	if (rootTo == NULL
   182 		|| rootFrom == NULL)
   183 	{
   184 		return false;
   185 	}
   186 
   187 	size_t numLevels = 0;
   188 
   189 	/* The root case is special! 
   190 	* Don't count anything from it.
   191 	*/
   192 	if (*(rootTo + 1) != '\0')
   193 	{
   194 		/* Search for how many levels we need to go up.
   195 		* Since the root pointer points to a '/', we increment
   196 		* the initial pointer by one.
   197 		*/
   198 		while (*rootTo != '\0')
   199 		{
   200 			if (pathchar_sep(*rootTo))
   201 			{
   202 				/* Check for an improper trailing slash,
   203 				* just to be nice even though the user 
   204 				* should NOT have done this!
   205 				*/
   206 				if (*(rootTo + 1) == '\0')
   207 				{
   208 					break;
   209 				}
   210 				numLevels++;
   211 			}
   212 			rootTo++;
   213 		}
   214 	}
   215 
   216 	/* Now build the new relative path. */
   217 	size_t len, total = 0;
   218 	while (numLevels--)
   219 	{
   220 		len = _snprintf(&buffer[total], maxlength - total, ".." PLATFORM_SEP_STR);
   221 		if (len >= maxlength - total)
   222 		{
   223 			/* Not enough space in the buffer */
   224 			return false;
   225 		}
   226 		total += len;
   227 	}
   228 
   229 	/* Add the absolute path. */
   230 	len = _snprintf(&buffer[total], maxlength - total, "%s", &rootFrom[1]);
   231 	if (len >= maxlength - total)
   232 	{
   233 		return false;
   234 	}
   235 
   236 	return true;
   237 }
   238 
   239 KeyValues *SourceModBase::ReadKeyValuesHandle(Handle_t hndl, HandleError *err, bool root)
   240 {
   241 	HandleError herr;
   242 	HandleSecurity sec;
   243 	KeyValueStack *pStk;
   244 
   245 	sec.pOwner = NULL;
   246 	sec.pIdentity = g_pCoreIdent;
   247 
   248 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   249 		!= HandleError_None)
   250 	{
   251 		if (err)
   252 		{
   253 			*err = herr;
   254 		}
   255 		return NULL;
   256 	}
   257 
   258 	if (err)
   259 	{
   260 		*err = HandleError_None;
   261 	}
   262 
   263 	return (root) ? pStk->pBase : pStk->pCurRoot.front();
   264 }
   265 
   266 static cell_t smn_KvSetString(IPluginContext *pCtx, const cell_t *params)
   267 {
   268 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   269 	HandleError herr;
   270 	HandleSecurity sec;
   271 	KeyValueStack *pStk;
   272 
   273 	sec.pOwner = NULL;
   274 	sec.pIdentity = g_pCoreIdent;
   275 
   276 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   277 		!= HandleError_None)
   278 	{
   279 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   280 	}
   281 
   282 	char *key, *value;
   283 	pCtx->LocalToStringNULL(params[2], &key);
   284 	pCtx->LocalToString(params[3], &value);
   285 
   286 	pStk->pCurRoot.front()->SetString(key, value);
   287 
   288 	return 1;
   289 }
   290 
   291 static cell_t smn_KvSetNum(IPluginContext *pCtx, const cell_t *params)
   292 {
   293 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   294 	HandleError herr;
   295 	HandleSecurity sec;
   296 	KeyValueStack *pStk;
   297 
   298 	sec.pOwner = NULL;
   299 	sec.pIdentity = g_pCoreIdent;
   300 
   301 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   302 		!= HandleError_None)
   303 	{
   304 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   305 	}
   306 
   307 	char *key;
   308 	pCtx->LocalToStringNULL(params[2], &key);
   309 
   310 	pStk->pCurRoot.front()->SetInt(key, params[3]);
   311 
   312 	return 1;
   313 }
   314 
   315 static cell_t smn_KvSetUInt64(IPluginContext *pCtx, const cell_t *params)
   316 {
   317 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   318 	HandleError herr;
   319 	HandleSecurity sec;
   320 	KeyValueStack *pStk;
   321 
   322 	sec.pOwner = NULL;
   323 	sec.pIdentity = g_pCoreIdent;
   324 
   325 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   326 		!= HandleError_None)
   327 	{
   328 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   329 	}
   330 
   331 	char *key;
   332 	cell_t *addr;
   333 	uint64 value;
   334 	pCtx->LocalToStringNULL(params[2], &key);
   335 	pCtx->LocalToPhysAddr(params[3], &addr);
   336 
   337 	value = static_cast<uint64>(*addr);
   338 	pStk->pCurRoot.front()->SetUint64(key, value);
   339 
   340 	return 1;
   341 }
   342 
   343 static cell_t smn_KvSetFloat(IPluginContext *pCtx, const cell_t *params)
   344 {
   345 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   346 	HandleError herr;
   347 	HandleSecurity sec;
   348 	KeyValueStack *pStk;
   349 
   350 	sec.pOwner = NULL;
   351 	sec.pIdentity = g_pCoreIdent;
   352 
   353 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   354 		!= HandleError_None)
   355 	{
   356 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   357 	}
   358 
   359 	char *key;
   360 	pCtx->LocalToStringNULL(params[2], &key);
   361 
   362 	pStk->pCurRoot.front()->SetFloat(key, sp_ctof(params[3]));
   363 
   364 	return 1;
   365 }
   366 
   367 static cell_t smn_KvSetColor(IPluginContext *pCtx, const cell_t *params)
   368 {
   369 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   370 	HandleError herr;
   371 	HandleSecurity sec;
   372 	KeyValueStack *pStk;
   373 
   374 	sec.pOwner = NULL;
   375 	sec.pIdentity = g_pCoreIdent;
   376 
   377 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   378 		!= HandleError_None)
   379 	{
   380 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   381 	}
   382 
   383 	char *key;
   384 	pCtx->LocalToStringNULL(params[2], &key);
   385 
   386 	Color color(params[3], params[4], params[5], params[6]);
   387 	pStk->pCurRoot.front()->SetColor(key, color);
   388 
   389 	return 1;
   390 }
   391 
   392 static cell_t smn_KvSetVector(IPluginContext *pCtx, const cell_t *params)
   393 {
   394 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   395 	HandleError herr;
   396 	HandleSecurity sec;
   397 	KeyValueStack *pStk;
   398 
   399 	sec.pOwner = NULL;
   400 	sec.pIdentity = g_pCoreIdent;
   401 
   402 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   403 		!= HandleError_None)
   404 	{
   405 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   406 	}
   407 
   408 	char *key;
   409 	char buffer[64];
   410 	cell_t *vector;
   411 	pCtx->LocalToStringNULL(params[2], &key);
   412 	pCtx->LocalToPhysAddr(params[3], &vector);
   413 
   414 	UTIL_Format(buffer, sizeof(buffer), "%f %f %f", sp_ctof(vector[0]), sp_ctof(vector[1]), sp_ctof(vector[2]));
   415 
   416 	pStk->pCurRoot.front()->SetString(key, buffer);
   417 
   418 	return 1;
   419 }
   420 
   421 static cell_t smn_KvGetString(IPluginContext *pCtx, const cell_t *params)
   422 {
   423 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   424 	HandleError herr;
   425 	HandleSecurity sec;
   426 	KeyValueStack *pStk;
   427 
   428 	sec.pOwner = NULL;
   429 	sec.pIdentity = g_pCoreIdent;
   430 
   431 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   432 		!= HandleError_None)
   433 	{
   434 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   435 	}
   436 
   437 	const char *value;
   438 	char *key, *defvalue;
   439 	pCtx->LocalToStringNULL(params[2], &key);
   440 	pCtx->LocalToString(params[5], &defvalue);
   441 
   442 	value = pStk->pCurRoot.front()->GetString(key, defvalue);
   443 	pCtx->StringToLocalUTF8(params[3], params[4], value, NULL);
   444 
   445 	return 1;
   446 }
   447 
   448 static cell_t smn_KvGetNum(IPluginContext *pCtx, const cell_t *params)
   449 {
   450 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   451 	HandleError herr;
   452 	HandleSecurity sec;
   453 	KeyValueStack *pStk;
   454 
   455 	sec.pOwner = NULL;
   456 	sec.pIdentity = g_pCoreIdent;
   457 
   458 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   459 		!= HandleError_None)
   460 	{
   461 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   462 	}
   463 
   464 	int value;
   465 	char *key;
   466 	pCtx->LocalToStringNULL(params[2], &key);
   467 
   468 	value = pStk->pCurRoot.front()->GetInt(key, params[3]);
   469 
   470 	return value;
   471 }
   472 
   473 static cell_t smn_KvGetFloat(IPluginContext *pCtx, const cell_t *params)
   474 {
   475 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   476 	HandleError herr;
   477 	HandleSecurity sec;
   478 	KeyValueStack *pStk;
   479 
   480 	sec.pOwner = NULL;
   481 	sec.pIdentity = g_pCoreIdent;
   482 
   483 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   484 		!= HandleError_None)
   485 	{
   486 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   487 	}
   488 
   489 	float value;
   490 	char *key;
   491 	pCtx->LocalToStringNULL(params[2], &key);
   492 
   493 	value = pStk->pCurRoot.front()->GetFloat(key, sp_ctof(params[3]));
   494 
   495 	return sp_ftoc(value);
   496 }
   497 
   498 static cell_t smn_KvGetColor(IPluginContext *pCtx, const cell_t *params)
   499 {
   500 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   501 	HandleError herr;
   502 	HandleSecurity sec;
   503 	KeyValueStack *pStk;
   504 
   505 	sec.pOwner = NULL;
   506 	sec.pIdentity = g_pCoreIdent;
   507 
   508 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   509 		!= HandleError_None)
   510 	{
   511 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   512 	}
   513 
   514 	Color color;
   515 	char *key;
   516 	cell_t *r, *g, *b, *a;
   517 	pCtx->LocalToStringNULL(params[2], &key);
   518 	pCtx->LocalToPhysAddr(params[3], &r);
   519 	pCtx->LocalToPhysAddr(params[4], &g);
   520 	pCtx->LocalToPhysAddr(params[5], &b);
   521 	pCtx->LocalToPhysAddr(params[6], &a);
   522 
   523 	color = pStk->pCurRoot.front()->GetColor(key);
   524 	*r = color.r();
   525 	*g = color.g();
   526 	*b = color.b();
   527 	*a = color.a();
   528 
   529 	return 1;
   530 }
   531 
   532 static cell_t smn_KvGetUInt64(IPluginContext *pCtx, const cell_t *params)
   533 {
   534 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   535 	HandleError herr;
   536 	HandleSecurity sec;
   537 	KeyValueStack *pStk;
   538 
   539 	sec.pOwner = NULL;
   540 	sec.pIdentity = g_pCoreIdent;
   541 
   542 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   543 		!= HandleError_None)
   544 	{
   545 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   546 	}
   547 
   548 	char *key;
   549 	cell_t *addr, *defvalue;
   550 	uint64 value;
   551 	pCtx->LocalToStringNULL(params[2], &key);
   552 	pCtx->LocalToPhysAddr(params[3], &addr);
   553 	pCtx->LocalToPhysAddr(params[4], &defvalue);
   554 
   555 	value = pStk->pCurRoot.front()->GetUint64(key, static_cast<uint64>(*defvalue));
   556 	*reinterpret_cast<uint64 *>(addr) = value;
   557 
   558 	return 1;
   559 }
   560 
   561 static cell_t smn_KvGetVector(IPluginContext *pCtx, const cell_t *params)
   562 {
   563 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   564 	HandleError herr;
   565 	HandleSecurity sec;
   566 	KeyValueStack *pStk;
   567 
   568 	sec.pOwner = NULL;
   569 	sec.pIdentity = g_pCoreIdent;
   570 
   571 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   572 		!= HandleError_None)
   573 	{
   574 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   575 	}
   576 
   577 	char *key;
   578 	const char *value;
   579 	cell_t *defvector, *outvector;
   580 	char buffer[64];
   581 	pCtx->LocalToStringNULL(params[2], &key);
   582 	pCtx->LocalToPhysAddr(params[3], &outvector);
   583 	pCtx->LocalToPhysAddr(params[4], &defvector);
   584 
   585 	UTIL_Format(buffer, sizeof(buffer), "%f %f %f", sp_ctof(defvector[0]), sp_ctof(defvector[1]), sp_ctof(defvector[2]));
   586 
   587 	value = pStk->pCurRoot.front()->GetString(key, buffer);
   588 
   589 	float out;
   590 	int components = 0;
   591 	while (*value && components < 3)
   592 	{
   593 		while ((*value) && (*value == ' '))
   594 		{
   595 			value++;
   596 		}
   597 
   598 		out = 0.0f;
   599 		bool isnegative;
   600 		if (*value == '-')
   601 		{
   602 			isnegative = true;
   603 			value++;
   604 		}
   605 		else
   606 		{
   607 			isnegative = false;
   608 		}
   609 
   610 		for (; *value && isdigit(*value); ++value)
   611 		{
   612 			out *= 10.0f;
   613 			out += *value - '0';
   614 		}
   615 
   616 		if (*value == '.')
   617 		{
   618 			value++;
   619 			float factor = 0.1f;
   620 			for (; *value && isdigit(*value); ++value)
   621 			{
   622 				out += (*value - '0') * factor;
   623 				factor *= 0.1f;
   624 			}
   625 		}
   626 
   627 		out = (isnegative) ? -out : out;
   628 		outvector[components++] = sp_ftoc(out);
   629 	}
   630 
   631 	return 1;
   632 }
   633 
   634 static cell_t smn_CreateKeyValues(IPluginContext *pCtx, const cell_t *params)
   635 {
   636 	KeyValueStack *pStk;
   637 	char *name, *firstkey, *firstvalue;
   638 	bool is_empty;
   639 
   640 	pCtx->LocalToString(params[1], &name);
   641 	pCtx->LocalToString(params[2], &firstkey);
   642 	pCtx->LocalToString(params[3], &firstvalue);
   643 
   644 	is_empty = (firstkey[0] == '\0');
   645 	pStk = new KeyValueStack;
   646 	pStk->pBase = new KeyValues(name, is_empty ? NULL : firstkey, (is_empty||(firstvalue[0]=='\0')) ? NULL : firstvalue);
   647 	pStk->pCurRoot.push(pStk->pBase);
   648 
   649 	return g_HandleSys.CreateHandle(g_KeyValueType, pStk, pCtx->GetIdentity(), g_pCoreIdent, NULL);
   650 }
   651 
   652 static cell_t smn_KvJumpToKey(IPluginContext *pCtx, const cell_t *params)
   653 {
   654 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   655 	HandleError herr;
   656 	HandleSecurity sec;
   657 	char *name;	
   658 	KeyValueStack *pStk;
   659 
   660 	sec.pOwner = NULL;
   661 	sec.pIdentity = g_pCoreIdent;
   662 
   663 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   664 		!= HandleError_None)
   665 	{
   666 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   667 	}
   668 
   669 	pCtx->LocalToString(params[2], &name);
   670 
   671 	KeyValues *pSubKey = pStk->pCurRoot.front();
   672 	pSubKey = pSubKey->FindKey(name, (params[3]) ? true : false);
   673 	if (!pSubKey)
   674 	{
   675 		return 0;
   676 	}
   677 	pStk->pCurRoot.push(pSubKey);
   678 
   679 	return 1;
   680 }
   681 
   682 static cell_t smn_KvJumpToKeySymbol(IPluginContext *pCtx, const cell_t *params)
   683 {
   684 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   685 	HandleError herr;
   686 	HandleSecurity sec;
   687 	KeyValueStack *pStk;
   688 
   689 	sec.pOwner = NULL;
   690 	sec.pIdentity = g_pCoreIdent;
   691 
   692 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   693 		!= HandleError_None)
   694 	{
   695 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   696 	}
   697 
   698 	KeyValues *pSubKey = pStk->pCurRoot.front();
   699 	pSubKey = pSubKey->FindKey(params[2]);
   700 	if (!pSubKey)
   701 	{
   702 		return 0;
   703 	}
   704 	pStk->pCurRoot.push(pSubKey);
   705 
   706 	return 1;
   707 }
   708 
   709 static cell_t smn_KvGotoFirstSubKey(IPluginContext *pCtx, const cell_t *params)
   710 {
   711 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   712 	HandleError herr;
   713 	HandleSecurity sec;
   714 	KeyValueStack *pStk;
   715 
   716 	sec.pOwner = NULL;
   717 	sec.pIdentity = g_pCoreIdent;
   718 
   719 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   720 		!= HandleError_None)
   721 	{
   722 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   723 	}
   724 
   725 	KeyValues *pSubKey = pStk->pCurRoot.front();
   726 	KeyValues *pFirstSubKey;
   727 	if (params[2])
   728 	{
   729 		pFirstSubKey = pSubKey->GetFirstTrueSubKey();
   730 	} else {
   731 		pFirstSubKey = pSubKey->GetFirstSubKey();
   732 	}
   733 
   734 	if (!pFirstSubKey)
   735 	{
   736 		return 0;
   737 	}
   738 	pStk->pCurRoot.push(pFirstSubKey);
   739 
   740 	return 1;
   741 }
   742 
   743 static cell_t smn_KvGotoNextKey(IPluginContext *pCtx, const cell_t *params)
   744 {
   745 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   746 	HandleError herr;
   747 	HandleSecurity sec;
   748 	KeyValueStack *pStk;
   749 
   750 	sec.pOwner = NULL;
   751 	sec.pIdentity = g_pCoreIdent;
   752 
   753 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   754 		!= HandleError_None)
   755 	{
   756 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   757 	}
   758 
   759 	KeyValues *pSubKey = pStk->pCurRoot.front();
   760 	if (params[2])
   761 	{
   762 		pSubKey = pSubKey->GetNextTrueSubKey();
   763 	} else {
   764 		pSubKey = pSubKey->GetNextKey();
   765 	}
   766 	if (!pSubKey)
   767 	{
   768 		return 0;
   769 	}
   770 	pStk->pCurRoot.pop();
   771 	pStk->pCurRoot.push(pSubKey);
   772 
   773 	return 1;	
   774 }
   775 
   776 static cell_t smn_KvGoBack(IPluginContext *pCtx, const cell_t *params)
   777 {
   778 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   779 	HandleError herr;
   780 	HandleSecurity sec;
   781 	KeyValueStack *pStk;
   782 
   783 	sec.pOwner = NULL;
   784 	sec.pIdentity = g_pCoreIdent;
   785 
   786 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   787 		!= HandleError_None)
   788 	{
   789 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   790 	}
   791 
   792 	if (pStk->pCurRoot.size() == 1)
   793 	{
   794 		return 0;
   795 	}
   796 	pStk->pCurRoot.pop();
   797 
   798 	return 1;
   799 }
   800 
   801 static cell_t smn_KvRewind(IPluginContext *pCtx, const cell_t *params)
   802 {
   803 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   804 	HandleError herr;
   805 	HandleSecurity sec;
   806 	KeyValueStack *pStk;
   807 
   808 	sec.pOwner = NULL;
   809 	sec.pIdentity = g_pCoreIdent;
   810 
   811 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   812 		!= HandleError_None)
   813 	{
   814 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   815 	}
   816 
   817 	while (pStk->pCurRoot.size() > 1)
   818 	{
   819 		pStk->pCurRoot.pop();
   820 	}
   821 
   822 	return 1;
   823 }
   824 
   825 static cell_t smn_KvGetSectionName(IPluginContext *pCtx, const cell_t *params)
   826 {
   827 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   828 	HandleError herr;
   829 	HandleSecurity sec;
   830 	KeyValueStack *pStk;
   831 
   832 	sec.pOwner = NULL;
   833 	sec.pIdentity = g_pCoreIdent;
   834 
   835 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   836 		!= HandleError_None)
   837 	{
   838 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   839 	}
   840 
   841 	KeyValues *pSection = pStk->pCurRoot.front();
   842 	const char *name = pSection->GetName();
   843 	if (!name)
   844 	{
   845 		return 0;
   846 	}
   847 	pCtx->StringToLocalUTF8(params[2], params[3], name, NULL);
   848 
   849 	return 1;
   850 }
   851 
   852 static cell_t smn_KvSetSectionName(IPluginContext *pCtx, const cell_t *params)
   853 {
   854 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   855 	HandleError herr;
   856 	HandleSecurity sec;
   857 	char *name;
   858 	KeyValueStack *pStk;
   859 
   860 	sec.pOwner = NULL;
   861 	sec.pIdentity = g_pCoreIdent;
   862 
   863 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   864 		!= HandleError_None)
   865 	{
   866 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   867 	}
   868 
   869 	pCtx->LocalToString(params[2], &name);
   870 
   871 	KeyValues *pSection = pStk->pCurRoot.front();
   872 	pSection->SetName(name);
   873 
   874 	return 1;
   875 }
   876 
   877 static cell_t smn_KvGetDataType(IPluginContext *pCtx, const cell_t *params)
   878 {
   879 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   880 	HandleError herr;
   881 	HandleSecurity sec;
   882 	char *name;
   883 	KeyValueStack *pStk;
   884 
   885 	sec.pOwner = NULL;
   886 	sec.pIdentity = g_pCoreIdent;
   887 
   888 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   889 		!= HandleError_None)
   890 	{
   891 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   892 	}
   893 
   894 	pCtx->LocalToString(params[2], &name);
   895 
   896 	return pStk->pCurRoot.front()->GetDataType(name);
   897 }
   898 
   899 static cell_t smn_KeyValuesToFile(IPluginContext *pCtx, const cell_t *params)
   900 {
   901 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   902 	HandleError herr;
   903 	HandleSecurity sec;
   904 	char *path;
   905 	KeyValueStack *pStk;
   906 
   907 	sec.pOwner = NULL;
   908 	sec.pIdentity = g_pCoreIdent;
   909 
   910 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   911 		!= HandleError_None)
   912 	{
   913 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   914 	}
   915 
   916 	pCtx->LocalToString(params[2], &path);
   917 
   918 	char realpath[PLATFORM_MAX_PATH];
   919 	char relpath[PLATFORM_MAX_PATH * 2];
   920 	g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", path);
   921 	UTIL_Relatize(relpath, sizeof(relpath), g_SourceMod.GetGamePath(), realpath);
   922 
   923 	return pStk->pCurRoot.front()->SaveToFile(basefilesystem, relpath);
   924 }
   925 
   926 static cell_t smn_FileToKeyValues(IPluginContext *pCtx, const cell_t *params)
   927 {
   928 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   929 	HandleError herr;
   930 	HandleSecurity sec;
   931 	char *path;
   932 	KeyValueStack *pStk;
   933 	KeyValues *kv;
   934 
   935 	sec.pOwner = NULL;
   936 	sec.pIdentity = g_pCoreIdent;
   937 
   938 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   939 		!= HandleError_None)
   940 	{
   941 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   942 	}
   943 
   944 	pCtx->LocalToString(params[2], &path);
   945 
   946 	char realpath[PLATFORM_MAX_PATH];
   947 	char relpath[PLATFORM_MAX_PATH * 2];
   948 	g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", path);
   949 	UTIL_Relatize(relpath, sizeof(relpath), g_SourceMod.GetGamePath(), realpath);
   950 
   951 	kv = pStk->pCurRoot.front();
   952 	return g_HL2.KVLoadFromFile(kv, basefilesystem, relpath);
   953 }
   954 
   955 static cell_t smn_KvSetEscapeSequences(IPluginContext *pCtx, const cell_t *params)
   956 {
   957 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   958 	HandleError herr;
   959 	HandleSecurity sec;
   960 	KeyValueStack *pStk;
   961 
   962 	sec.pOwner = NULL;
   963 	sec.pIdentity = g_pCoreIdent;
   964 
   965 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   966 		!= HandleError_None)
   967 	{
   968 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   969 	}
   970 
   971 	pStk->pCurRoot.front()->UsesEscapeSequences(params[2] ? true : false);
   972 
   973 	return 1;
   974 }
   975 
   976 static cell_t smn_KvNodesInStack(IPluginContext *pCtx, const cell_t *params)
   977 {
   978 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   979 	HandleError herr;
   980 	HandleSecurity sec;
   981 	KeyValueStack *pStk;
   982 
   983 	sec.pOwner = NULL;
   984 	sec.pIdentity = g_pCoreIdent;
   985 
   986 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
   987 		!= HandleError_None)
   988 	{
   989 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
   990 	}
   991 
   992 	return pStk->pCurRoot.size() - 1;
   993 }
   994 
   995 static cell_t smn_KvDeleteThis(IPluginContext *pContext, const cell_t *params)
   996 {
   997 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   998 	HandleError herr;
   999 	HandleSecurity sec;
  1000 	KeyValueStack *pStk;
  1001 
  1002 	sec.pOwner = NULL;
  1003 	sec.pIdentity = g_pCoreIdent;
  1004 
  1005 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
  1006 		!= HandleError_None)
  1007 	{
  1008 		return pContext->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
  1009 	}
  1010 
  1011 	if (pStk->pCurRoot.size() < 2)
  1012 	{
  1013 		return 0;
  1014 	}
  1015 
  1016 	KeyValues *pValues = pStk->pCurRoot.front();
  1017 	pStk->pCurRoot.pop();
  1018 	KeyValues *pRoot = pStk->pCurRoot.front();
  1019 
  1020 	/* We have to manually verify this since Valve sucks
  1021 	 * :TODO: make our own KeyValues.h file and make
  1022 	 * the sub stuff private so we can do this ourselves!
  1023  	 */
  1024 	KeyValues *sub = pRoot->GetFirstSubKey();
  1025 	while (sub)
  1026 	{
  1027 		if (sub == pValues)
  1028 		{
  1029 			KeyValues *pNext = pValues->GetNextKey();
  1030 			pRoot->RemoveSubKey(pValues);
  1031 			pValues->deleteThis();
  1032 			if (pNext)
  1033 			{
  1034 				pStk->pCurRoot.push(pNext);
  1035 				return 1;
  1036 			} else {
  1037 				return -1;
  1038 			}
  1039 		}
  1040 		sub = sub->GetNextKey();
  1041 	}
  1042 
  1043 	/* Push this back on :( */
  1044 	pStk->pCurRoot.push(pValues);
  1045 
  1046 	return 0;
  1047 }
  1048 
  1049 static cell_t smn_KvDeleteKey(IPluginContext *pContext, const cell_t *params)
  1050 {
  1051 	Handle_t hndl = static_cast<Handle_t>(params[1]);
  1052 	HandleError herr;
  1053 	HandleSecurity sec;
  1054 	KeyValueStack *pStk;
  1055 
  1056 	sec.pOwner = NULL;
  1057 	sec.pIdentity = g_pCoreIdent;
  1058 
  1059 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
  1060 		!= HandleError_None)
  1061 	{
  1062 		return pContext->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
  1063 	}
  1064 
  1065 	if (pStk->pCurRoot.size() < 2)
  1066 	{
  1067 		return 0;
  1068 	}
  1069 
  1070 	char *keyName;
  1071 	pContext->LocalToString(params[2], &keyName);
  1072 
  1073 	KeyValues *pRoot = pStk->pCurRoot.front();
  1074 	KeyValues *pValues = pRoot->FindKey(keyName);
  1075 	if (!pValues)
  1076 	{
  1077 		return 0;
  1078 	}
  1079 
  1080 	pRoot->RemoveSubKey(pValues);
  1081 	pValues->deleteThis();
  1082 
  1083 	return 1;
  1084 }
  1085 
  1086 static cell_t smn_KvSavePosition(IPluginContext *pContext, const cell_t *params)
  1087 {
  1088 	Handle_t hndl = static_cast<Handle_t>(params[1]);
  1089 	HandleError herr;
  1090 	HandleSecurity sec;
  1091 	KeyValueStack *pStk;
  1092 
  1093 	sec.pOwner = NULL;
  1094 	sec.pIdentity = g_pCoreIdent;
  1095 
  1096 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
  1097 		!= HandleError_None)
  1098 	{
  1099 		return pContext->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
  1100 	}
  1101 
  1102 	if (pStk->pCurRoot.size() < 2)
  1103 	{
  1104 		return 0;
  1105 	}
  1106 
  1107 	KeyValues *pValues = pStk->pCurRoot.front();
  1108 	pStk->pCurRoot.push(pValues);
  1109 
  1110 	return 1;
  1111 }
  1112 
  1113 static cell_t smn_CopySubkeys(IPluginContext *pContext, const cell_t *params)
  1114 {
  1115 	Handle_t hndl_copied = static_cast<Handle_t>(params[1]);
  1116 	Handle_t hndl_parent = static_cast<Handle_t>(params[2]);
  1117 	HandleError herr;
  1118 	HandleSecurity sec;
  1119 	KeyValueStack *pStk_copied, *pStk_parent;
  1120 
  1121 	sec.pOwner = NULL;
  1122 	sec.pIdentity = g_pCoreIdent;
  1123 
  1124 	if ((herr=g_HandleSys.ReadHandle(hndl_copied, g_KeyValueType, &sec, (void **)&pStk_copied))
  1125 		!= HandleError_None)
  1126 	{
  1127 		return pContext->ThrowNativeError("Invalid key value handle %x (error %d)", hndl_copied, herr);
  1128 	}
  1129 	if ((herr=g_HandleSys.ReadHandle(hndl_parent, g_KeyValueType, &sec, (void **)&pStk_parent))
  1130 		!= HandleError_None)
  1131 	{
  1132 		return pContext->ThrowNativeError("Invalid key value handle %x (error %d)", hndl_parent, herr);
  1133 	}
  1134 
  1135 	pStk_copied->pCurRoot.front()->CopySubkeys(pStk_parent->pCurRoot.front());
  1136 
  1137 	return 1;
  1138 }
  1139 
  1140 static cell_t smn_GetNameSymbol(IPluginContext *pContext, const cell_t *params)
  1141 {
  1142 	Handle_t hndl = static_cast<Handle_t>(params[1]);
  1143 	HandleError herr;
  1144 	HandleSecurity sec;
  1145 	KeyValueStack *pStk;
  1146 	cell_t *val;
  1147 	char *key;
  1148 
  1149 	sec.pOwner = NULL;
  1150 	sec.pIdentity = g_pCoreIdent;
  1151 
  1152 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
  1153 		!= HandleError_None)
  1154 	{
  1155 		return pContext->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
  1156 	}
  1157 
  1158 	if (pStk->pCurRoot.size() < 2)
  1159 	{
  1160 		return 0;
  1161 	}
  1162 
  1163 	pContext->LocalToString(params[2], &key);
  1164 
  1165 	KeyValues *pKv = pStk->pCurRoot.front()->FindKey(key);
  1166 	if (!pKv)
  1167 	{
  1168 		return 0;
  1169 	}
  1170 	pContext->LocalToPhysAddr(params[3], &val);
  1171 	*val = pKv->GetNameSymbol();
  1172 
  1173 	return 1;
  1174 }
  1175 
  1176 static cell_t smn_FindKeyById(IPluginContext *pContext, const cell_t *params)
  1177 {
  1178 	Handle_t hndl = static_cast<Handle_t>(params[1]);
  1179 	HandleError herr;
  1180 	HandleSecurity sec;
  1181 	KeyValueStack *pStk;
  1182 
  1183 	sec.pOwner = NULL;
  1184 	sec.pIdentity = g_pCoreIdent;
  1185 
  1186 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
  1187 		!= HandleError_None)
  1188 	{
  1189 		return pContext->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
  1190 	}
  1191 
  1192 	KeyValues *pKv = pStk->pCurRoot.front()->FindKey(params[2]);
  1193 	if (!pKv)
  1194 	{
  1195 		return 0;
  1196 	}
  1197 
  1198 	pContext->StringToLocalUTF8(params[3], params[4], pKv->GetName(), NULL);
  1199 
  1200 	return 1;
  1201 }
  1202 
  1203 static cell_t smn_KvGetSectionSymbol(IPluginContext *pCtx, const cell_t *params)
  1204 {
  1205 	Handle_t hndl = static_cast<Handle_t>(params[1]);
  1206 	HandleError herr;
  1207 	HandleSecurity sec;
  1208 	KeyValueStack *pStk;
  1209 	cell_t *val;
  1210 
  1211 	sec.pOwner = NULL;
  1212 	sec.pIdentity = g_pCoreIdent;
  1213 
  1214 	if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
  1215 		!= HandleError_None)
  1216 	{
  1217 		return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
  1218 	}
  1219 
  1220 	KeyValues *pSection = pStk->pCurRoot.front();
  1221 
  1222 	pCtx->LocalToPhysAddr(params[2], &val);
  1223 	*val = pSection->GetNameSymbol();
  1224 
  1225 	if (!*val)
  1226 	{
  1227 		return 0;
  1228 	}
  1229 
  1230 	return 1;
  1231 }
  1232 
  1233 static KeyValueNatives s_KeyValueNatives;
  1234 
  1235 REGISTER_NATIVES(keyvaluenatives)
  1236 {
  1237 	{"KvSetString",				smn_KvSetString},
  1238 	{"KvSetNum",				smn_KvSetNum},
  1239 	{"KvSetUInt64",				smn_KvSetUInt64},
  1240 	{"KvSetFloat",				smn_KvSetFloat},
  1241 	{"KvSetColor",				smn_KvSetColor},
  1242 	{"KvGetString",				smn_KvGetString},
  1243 	{"KvGetNum",				smn_KvGetNum},
  1244 	{"KvGetFloat",				smn_KvGetFloat},
  1245 	{"KvGetColor",				smn_KvGetColor},
  1246 	{"KvGetUInt64",				smn_KvGetUInt64},
  1247 	{"CreateKeyValues",			smn_CreateKeyValues},
  1248 	{"KvJumpToKey",				smn_KvJumpToKey},
  1249 	{"KvJumpToKeySymbol",		smn_KvJumpToKeySymbol},
  1250 	{"KvGotoNextKey",			smn_KvGotoNextKey},
  1251 	{"KvGotoFirstSubKey",		smn_KvGotoFirstSubKey},
  1252 	{"KvGoBack",				smn_KvGoBack},
  1253 	{"KvRewind",				smn_KvRewind},
  1254 	{"KvGetSectionName",		smn_KvGetSectionName},
  1255 	{"KvSetSectionName",		smn_KvSetSectionName},
  1256 	{"KvGetDataType",			smn_KvGetDataType},
  1257 	{"KeyValuesToFile",			smn_KeyValuesToFile},
  1258 	{"FileToKeyValues",			smn_FileToKeyValues},
  1259 	{"KvSetEscapeSequences",	smn_KvSetEscapeSequences},
  1260 	{"KvDeleteThis",			smn_KvDeleteThis},
  1261 	{"KvDeleteKey",				smn_KvDeleteKey},
  1262 	{"KvNodesInStack",			smn_KvNodesInStack},
  1263 	{"KvSavePosition",			smn_KvSavePosition},
  1264 	{"KvCopySubkeys",			smn_CopySubkeys},
  1265 	{"KvFindKeyById",			smn_FindKeyById},
  1266 	{"KvGetNameSymbol",			smn_GetNameSymbol},
  1267 	{"KvGetSectionSymbol",		smn_KvGetSectionSymbol},
  1268 	{"KvGetVector",				smn_KvGetVector},
  1269 	{"KvSetVector",				smn_KvSetVector},
  1270 	{NULL,						NULL}
  1271 };