core/logic/ShareSys.cpp
author Kyle Sanderson <kyle.leet@gmail.com>
Sun May 11 14:36:32 2014 -0700 (2014-05-11)
changeset 4358 52aa5fab9866
parent 4109 10eb68d668af
permissions -rw-r--r--
Optimize native call if statically bound (bug 5842, r=ds,fyren f=dvander).
Original patch written by David Anderson (original r from Fyren).
- Updated to function with the current JIT compiler.
- Took in clean-ups from later-dated patches.
dvander@370
     1
/**
dvander@4067
     2
 * vim: set ts=4 sw=4 tw=99 noet :
ds@1330
     3
 * =============================================================================
dvander@1231
     4
 * SourceMod
ds@1947
     5
 * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
ds@1330
     6
 * =============================================================================
dvander@370
     7
 *
ds@1330
     8
 * This program is free software; you can redistribute it and/or modify it under
ds@1330
     9
 * the terms of the GNU General Public License, version 3.0, as published by the
ds@1330
    10
 * Free Software Foundation.
dvander@1231
    11
 * 
ds@1330
    12
 * This program is distributed in the hope that it will be useful, but WITHOUT
ds@1330
    13
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
ds@1330
    14
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
ds@1330
    15
 * details.
dvander@1231
    16
 *
ds@1330
    17
 * You should have received a copy of the GNU General Public License along with
ds@1330
    18
 * this program.  If not, see <http://www.gnu.org/licenses/>.
dvander@1231
    19
 *
ds@1330
    20
 * As a special exception, AlliedModders LLC gives you permission to link the
ds@1330
    21
 * code of this program (as well as its derivative works) to "Half-Life 2," the
ds@1330
    22
 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
ds@1330
    23
 * by the Valve Corporation.  You must obey the GNU General Public License in
ds@1330
    24
 * all respects for all other code used.  Additionally, AlliedModders LLC grants
ds@1330
    25
 * this exception to all derivative works.  AlliedModders LLC defines further
ds@1330
    26
 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
ds@1330
    27
 * or <http://www.sourcemod.net/license.php>.
dvander@370
    28
 *
dvander@370
    29
 * Version: $Id$
dvander@370
    30
 */
dvander@370
    31
dvander@229
    32
#include "ShareSys.h"
dvander@3872
    33
#include "ExtensionSys.h"
dvander@3872
    34
#include <ILibrarySys.h>
dvander@3872
    35
#include "common_logic.h"
dvander@3872
    36
#include "PluginSys.h"
dvander@229
    37
#include "HandleSys.h"
dvander@4106
    38
#include <assert.h>
dvander@229
    39
dvander@4109
    40
using namespace ke;
dvander@4109
    41
dvander@229
    42
ShareSystem g_ShareSys;
dvander@2086
    43
static unsigned int g_mark_serial = 0;
dvander@229
    44
dvander@229
    45
ShareSystem::ShareSystem()
dvander@229
    46
{
dvander@229
    47
	m_IdentRoot.ident = 0;
dvander@229
    48
	m_TypeRoot = 0;
dvander@229
    49
	m_IfaceType = 0;
dvander@229
    50
	m_CoreType = 0;
dvander@229
    51
}
dvander@229
    52
dvander@229
    53
IdentityToken_t *ShareSystem::CreateCoreIdentity()
dvander@229
    54
{
dvander@229
    55
	if (!m_CoreType)
dvander@229
    56
	{
dvander@229
    57
		m_CoreType = CreateIdentType("CORE");
dvander@229
    58
	}
dvander@229
    59
dvander@868
    60
	return CreateIdentity(m_CoreType, this);
dvander@229
    61
}
dvander@229
    62
dvander@1770
    63
void ShareSystem::Initialize()
dvander@229
    64
{
dvander@262
    65
	TypeAccess sec;
dvander@229
    66
dvander@3872
    67
	handlesys->InitAccessDefaults(&sec, NULL);
dvander@262
    68
	sec.ident = GetIdentRoot();
dvander@262
    69
dvander@3872
    70
	m_TypeRoot = handlesys->CreateType("Identity", this, 0, &sec, NULL, NULL, NULL);
dvander@3872
    71
	m_IfaceType = handlesys->CreateType("Interface", this, 0, NULL, NULL, GetIdentRoot(), NULL);
dvander@229
    72
dvander@229
    73
	/* Initialize our static identity handle */
dvander@3872
    74
	m_IdentRoot.ident = handlesys->CreateHandle(m_TypeRoot, NULL, NULL, GetIdentRoot(), NULL);
dvander@305
    75
dvander@336
    76
	/* Add the Handle System and others... they are too innocent and pure to do it themselves */
dvander@3872
    77
	AddInterface(NULL, handlesys);
dvander@3872
    78
	AddInterface(NULL, libsys);
dvander@229
    79
}
dvander@229
    80
dvander@229
    81
void ShareSystem::OnSourceModShutdown()
dvander@229
    82
{
dvander@229
    83
	if (m_CoreType)
dvander@229
    84
	{
dvander@3872
    85
		handlesys->RemoveType(m_CoreType, GetIdentRoot());
dvander@229
    86
	}
dvander@229
    87
dvander@3872
    88
	handlesys->RemoveType(m_IfaceType, GetIdentRoot());
dvander@3872
    89
	handlesys->RemoveType(m_TypeRoot, GetIdentRoot());
dvander@229
    90
}
dvander@229
    91
dvander@229
    92
IdentityType_t ShareSystem::FindIdentType(const char *name)
dvander@229
    93
{
dvander@229
    94
	HandleType_t type;
dvander@229
    95
dvander@3872
    96
	if (handlesys->FindHandleType(name, &type))
dvander@229
    97
	{
dvander@229
    98
		if (g_HandleSys.TypeCheck(type, m_TypeRoot))
dvander@229
    99
		{
dvander@229
   100
			return type;
dvander@229
   101
		}
dvander@229
   102
	}
dvander@229
   103
dvander@229
   104
	return 0;
dvander@229
   105
}
dvander@229
   106
dvander@229
   107
IdentityType_t ShareSystem::CreateIdentType(const char *name)
dvander@229
   108
{
dvander@229
   109
	if (!m_TypeRoot)
dvander@229
   110
	{
dvander@229
   111
		return 0;
dvander@229
   112
	}
dvander@229
   113
dvander@3872
   114
	return handlesys->CreateType(name, this, m_TypeRoot, NULL, NULL, GetIdentRoot(), NULL);
dvander@229
   115
}
dvander@229
   116
dvander@229
   117
void ShareSystem::OnHandleDestroy(HandleType_t type, void *object)
dvander@229
   118
{
dvander@283
   119
	/* THIS WILL NEVER BE CALLED FOR ANYTHING WITH THE IDENTITY TYPE */
dvander@229
   120
}
dvander@229
   121
dvander@868
   122
IdentityToken_t *ShareSystem::CreateIdentity(IdentityType_t type, void *ptr)
dvander@229
   123
{
dvander@229
   124
	if (!m_TypeRoot)
dvander@229
   125
	{
dvander@229
   126
		return 0;
dvander@229
   127
	}
dvander@229
   128
dvander@229
   129
	/* :TODO: Cache? */
dvander@229
   130
	IdentityToken_t *pToken = new IdentityToken_t;
dvander@528
   131
dvander@528
   132
	HandleSecurity sec;
dvander@528
   133
	sec.pOwner = sec.pIdentity = GetIdentRoot();
dvander@528
   134
dvander@528
   135
	pToken->ident = g_HandleSys.CreateHandleInt(type, NULL, &sec, NULL, NULL, true);
dvander@868
   136
	pToken->ptr = ptr;
dvander@868
   137
	pToken->type = type;
dvander@229
   138
dvander@229
   139
	return pToken;
dvander@229
   140
}
dvander@229
   141
dvander@304
   142
bool ShareSystem::AddInterface(IExtension *myself, SMInterface *iface)
dvander@229
   143
{
dvander@229
   144
	if (!iface)
dvander@229
   145
	{
dvander@229
   146
		return false;
dvander@229
   147
	}
dvander@229
   148
dvander@229
   149
	IfaceInfo info;
dvander@229
   150
dvander@304
   151
	info.owner = myself;
dvander@229
   152
	info.iface = iface;
dvander@229
   153
	
dvander@229
   154
	m_Interfaces.push_back(info);
dvander@229
   155
dvander@229
   156
	return true;
dvander@229
   157
}
dvander@229
   158
dvander@229
   159
bool ShareSystem::RequestInterface(const char *iface_name, 
dvander@229
   160
								   unsigned int iface_vers, 
dvander@311
   161
								   IExtension *myself, 
dvander@229
   162
								   SMInterface **pIface)
dvander@229
   163
{
dvander@229
   164
	/* See if the interface exists */
dvander@229
   165
	List<IfaceInfo>::iterator iter;
dvander@229
   166
	SMInterface *iface;
dvander@304
   167
	IExtension *iface_owner;
dvander@229
   168
	bool found = false;
dvander@229
   169
	for (iter=m_Interfaces.begin(); iter!=m_Interfaces.end(); iter++)
dvander@229
   170
	{
dvander@229
   171
		IfaceInfo &info = (*iter);
dvander@229
   172
		iface = info.iface;
dvander@229
   173
		if (strcmp(iface->GetInterfaceName(), iface_name) == 0)
dvander@229
   174
		{
dvander@229
   175
			if (iface->GetInterfaceVersion() == iface_vers
dvander@229
   176
				|| iface->IsVersionCompatible(iface_vers))
dvander@229
   177
			{
dvander@304
   178
				iface_owner = info.owner;
dvander@229
   179
				found = true;
dvander@229
   180
				break;
dvander@229
   181
			}
dvander@229
   182
		}
dvander@229
   183
	}
dvander@229
   184
dvander@229
   185
	if (!found)
dvander@229
   186
	{
dvander@229
   187
		return false;
dvander@229
   188
	}
dvander@229
   189
dvander@304
   190
	/* Add a dependency node */
dvander@229
   191
	if (iface_owner)
dvander@229
   192
	{
dvander@304
   193
		IfaceInfo info;
dvander@304
   194
		info.iface = iface;
dvander@304
   195
		info.owner = iface_owner;
dvander@311
   196
		g_Extensions.BindDependency(myself, &info);
dvander@229
   197
	}
dvander@229
   198
dvander@304
   199
	if (pIface)
dvander@304
   200
	{
dvander@304
   201
		*pIface = iface;
dvander@304
   202
	}
dvander@229
   203
dvander@304
   204
	return true;
dvander@229
   205
}
dvander@229
   206
dvander@312
   207
void ShareSystem::AddNatives(IExtension *myself, const sp_nativeinfo_t *natives)
dvander@229
   208
{
dvander@2086
   209
	CNativeOwner *pOwner;
dvander@2086
   210
dvander@2086
   211
	pOwner = g_Extensions.GetNativeOwner(myself);
dvander@2086
   212
dvander@2086
   213
	pOwner->AddNatives(natives);
dvander@229
   214
}
dvander@229
   215
dvander@229
   216
void ShareSystem::DestroyIdentity(IdentityToken_t *identity)
dvander@229
   217
{
dvander@262
   218
	HandleSecurity sec;
dvander@262
   219
dvander@262
   220
	sec.pOwner = GetIdentRoot();
dvander@262
   221
	sec.pIdentity = GetIdentRoot();
dvander@262
   222
dvander@3872
   223
	handlesys->FreeHandle(identity->ident, &sec);
dvander@229
   224
	delete identity;
dvander@229
   225
}
dvander@229
   226
dvander@229
   227
void ShareSystem::DestroyIdentType(IdentityType_t type)
dvander@229
   228
{
dvander@3872
   229
	handlesys->RemoveType(type, GetIdentRoot());
dvander@229
   230
}
dvander@229
   231
dvander@304
   232
void ShareSystem::RemoveInterfaces(IExtension *pExtension)
dvander@304
   233
{
dvander@304
   234
	List<IfaceInfo>::iterator iter = m_Interfaces.begin();
dvander@304
   235
dvander@304
   236
	while (iter != m_Interfaces.end())
dvander@304
   237
	{
dvander@304
   238
		if ((*iter).owner == pExtension)
dvander@304
   239
		{
dvander@304
   240
			iter = m_Interfaces.erase(iter);
dvander@2086
   241
		}
dvander@2086
   242
		else
dvander@2086
   243
		{
dvander@304
   244
			iter++;
dvander@304
   245
		}
dvander@304
   246
	}
dvander@304
   247
}
dvander@324
   248
dvander@324
   249
void ShareSystem::AddDependency(IExtension *myself, const char *filename, bool require, bool autoload)
dvander@324
   250
{
dvander@324
   251
	g_Extensions.AddDependency(myself, filename, require, autoload);
dvander@324
   252
}
dvander@324
   253
dvander@1572
   254
void ShareSystem::RegisterLibrary(IExtension *myself, const char *name)
dvander@1572
   255
{
dvander@1572
   256
	g_Extensions.AddLibrary(myself, name);
dvander@1572
   257
}
dvander@1689
   258
dvander@1689
   259
void ShareSystem::OverrideNatives(IExtension *myself, const sp_nativeinfo_t *natives)
dvander@1689
   260
{
dvander@4106
   261
	assert(false);
dvander@2086
   262
}
dvander@2086
   263
dvander@4109
   264
PassRef<Native> ShareSystem::FindNative(const char *name)
dvander@2086
   265
{
dvander@4109
   266
	NativeCache::Result r = m_NtvCache.find(name);
dvander@4109
   267
	if (!r.found())
dvander@2086
   268
		return NULL;
dvander@4109
   269
	return *r;
dvander@2086
   270
}
dvander@2086
   271
dvander@2086
   272
void ShareSystem::BindNativesToPlugin(CPlugin *pPlugin, bool bCoreOnly)
dvander@2086
   273
{
dvander@2086
   274
	sp_native_t *native;
dvander@2086
   275
	uint32_t i, native_count;
dvander@2086
   276
	IPluginContext *pContext;
dvander@2086
   277
dvander@2086
   278
	pContext = pPlugin->GetBaseContext();
dvander@2086
   279
dvander@2086
   280
	/* Generate a new serial ID, mark our dependencies with it. */
dvander@2086
   281
	g_mark_serial++;
dvander@3872
   282
	pPlugin->PropagateMarkSerial(g_mark_serial);
dvander@2086
   283
dvander@2086
   284
	native_count = pContext->GetNativesNum();
dvander@2086
   285
	for (i = 0; i < native_count; i++)
dvander@2086
   286
	{
dvander@2086
   287
		if (pContext->GetNativeByIndex(i, &native) != SP_ERROR_NONE)
dvander@2086
   288
			continue;
dvander@2086
   289
dvander@4106
   290
		// If we're already bound, no need to do anything else.
dvander@2086
   291
		if (native->status == SP_NATIVE_BOUND)
dvander@4106
   292
			continue;
dvander@4106
   293
dvander@2086
   294
		/* Otherwise, the native must be in our cache. */
dvander@4109
   295
		Ref<Native> pEntry = FindNative(native->name);
dvander@4106
   296
		if (!pEntry)
dvander@2086
   297
			continue;
dvander@2086
   298
dvander@3872
   299
		if (bCoreOnly && pEntry->owner != &g_CoreNatives)
dvander@2086
   300
			continue;
dvander@2086
   301
dvander@2086
   302
		BindNativeToPlugin(pPlugin, native, i, pEntry);
dvander@2086
   303
	}
dvander@2086
   304
}
dvander@2086
   305
dvander@4109
   306
void ShareSystem::BindNativeToPlugin(CPlugin *pPlugin, const Ref<Native> &entry)
dvander@2086
   307
{
dvander@4109
   308
	if (!entry->owner)
dvander@4109
   309
		return;
dvander@2086
   310
dvander@4109
   311
	IPluginContext *pContext = pPlugin->GetBaseContext();
dvander@2086
   312
dvander@4109
   313
	uint32_t i;
dvander@4109
   314
	if (pContext->FindNativeByName(entry->name(), &i) != SP_ERROR_NONE)
dvander@2086
   315
		return;
dvander@4109
   316
dvander@4109
   317
	sp_native_t *native;
dvander@2086
   318
	if (pContext->GetNativeByIndex(i, &native) != SP_ERROR_NONE)
dvander@2086
   319
		return;
dvander@2086
   320
dvander@2086
   321
	if (native->status == SP_NATIVE_BOUND)
dvander@2086
   322
		return;
dvander@2086
   323
dvander@4109
   324
	BindNativeToPlugin(pPlugin, native, i, entry);
dvander@1689
   325
}
dvander@2086
   326
dvander@4109
   327
void ShareSystem::BindNativeToPlugin(CPlugin *pPlugin, sp_native_t *native, uint32_t index,
dvander@4109
   328
                                     const Ref<Native> &pEntry)
dvander@2086
   329
{
dvander@2086
   330
	/* Mark as bound... we do the rest next. */
dvander@2086
   331
	native->status = SP_NATIVE_BOUND;
dvander@4108
   332
	native->pfn = pEntry->func();
dvander@4106
   333
kyle@4358
   334
	if (pEntry->fake)
kyle@4358
   335
	{
kyle@4358
   336
		/* This native is not necessarily optional, but we don't guarantee
kyle@4358
   337
		 * that its address is long-lived. */
kyle@4358
   338
		native->flags |= SP_NTVFLAG_EPHEMERAL;
kyle@4358
   339
	}
kyle@4358
   340
dvander@4106
   341
	/* We don't bother with dependency crap if the owner is Core. */
dvander@4106
   342
	if (pEntry->owner != &g_CoreNatives)
dvander@2086
   343
	{
dvander@4106
   344
		/* The native is optional, this is a special case */
dvander@4106
   345
		if ((native->flags & SP_NTVFLAG_OPTIONAL) == SP_NTVFLAG_OPTIONAL)
dvander@2086
   346
		{
dvander@4106
   347
			/* Only add if there is a valid owner. */
dvander@4109
   348
			if (pEntry->owner)
dvander@4106
   349
				pEntry->owner->AddWeakRef(WeakNative(pPlugin, index));
dvander@2086
   350
			else
dvander@4106
   351
				native->status = SP_NATIVE_UNBOUND;
dvander@4106
   352
		}
dvander@4106
   353
		/* Otherwise, we're a strong dependent and not a weak one */
dvander@4106
   354
		else
dvander@4106
   355
		{
dvander@4106
   356
			/* See if this has already been marked as a dependent.
dvander@4106
   357
			 * If it has, it means this relationship has already occurred, 
dvander@4106
   358
			 * and there is no reason to do it again.
dvander@4106
   359
			 */
dvander@4106
   360
			if (pEntry->owner != pPlugin->ToNativeOwner() 
dvander@4106
   361
				&& pEntry->owner->GetMarkSerial() != g_mark_serial)
dvander@4106
   362
			{
dvander@4106
   363
				/* This has not been marked as a dependency yet */
dvander@4106
   364
				//pPlugin->AddDependency(pEntry->owner);
dvander@4106
   365
				pEntry->owner->AddDependent(pPlugin);
dvander@4106
   366
				pEntry->owner->SetMarkSerial(g_mark_serial);
dvander@2086
   367
			}
dvander@2086
   368
		}
dvander@2086
   369
	}
dvander@2086
   370
}
dvander@2086
   371
dvander@4109
   372
PassRef<Native> ShareSystem::AddNativeToCache(CNativeOwner *pOwner, const sp_nativeinfo_t *ntv)
dvander@2086
   373
{
dvander@4109
   374
	NativeCache::Insert i = m_NtvCache.findForAdd(ntv->name);
dvander@4109
   375
	if (i.found())
dvander@2086
   376
		return NULL;
dvander@2086
   377
dvander@4109
   378
	Ref<Native> entry = Newborn<Native>(new Native(pOwner, ntv));
dvander@4109
   379
	m_NtvCache.insert(ntv->name, entry);
dvander@4109
   380
	return entry;
dvander@4108
   381
}
dvander@2086
   382
dvander@4108
   383
FakeNative::~FakeNative()
dvander@4108
   384
{
dvander@4108
   385
	g_pSourcePawn2->DestroyFakeNative(gate);
dvander@2086
   386
}
dvander@2086
   387
dvander@2086
   388
void ShareSystem::ClearNativeFromCache(CNativeOwner *pOwner, const char *name)
dvander@2086
   389
{
dvander@4109
   390
	NativeCache::Result r = m_NtvCache.find(name);
dvander@4109
   391
	if (!r.found())
dvander@2086
   392
		return;
dvander@2086
   393
dvander@4109
   394
	Ref<Native> entry(*r);
dvander@4109
   395
	if (entry->owner != pOwner)
dvander@2086
   396
		return;
dvander@2086
   397
dvander@4109
   398
	// Clear out the owner bit as a sanity measure.
dvander@4109
   399
	entry->owner = NULL;
dvander@4109
   400
dvander@4109
   401
	m_NtvCache.remove(r);
dvander@2086
   402
}
dvander@2086
   403
dvander@4109
   404
PassRef<Native> ShareSystem::AddFakeNative(IPluginFunction *pFunc, const char *name, SPVM_FAKENATIVE_FUNC func)
dvander@2086
   405
{
dvander@4109
   406
	Ref<Native> entry(FindNative(name));
dvander@4109
   407
	if (entry)
dvander@2086
   408
		return NULL;
dvander@2086
   409
dvander@4109
   410
	AutoPtr<FakeNative> fake(new FakeNative(name, pFunc));
dvander@2086
   411
dvander@4108
   412
	fake->gate = g_pSourcePawn2->CreateFakeNative(func, fake);
dvander@4108
   413
	if (!fake->gate)
dvander@2086
   414
		return NULL;
dvander@2086
   415
dvander@4108
   416
	CNativeOwner *owner = g_PluginSys.GetPluginByCtx(fake->ctx->GetContext());
dvander@2086
   417
dvander@4109
   418
	entry = Newborn<Native>(new Native(owner, fake.take()));
dvander@4109
   419
	m_NtvCache.insert(name, entry);
dvander@2086
   420
dvander@4109
   421
	return entry;
dvander@2086
   422
}
dvander@2841
   423
dvander@2841
   424
void ShareSystem::AddCapabilityProvider(IExtension *myself, IFeatureProvider *provider,
dvander@2841
   425
		                                const char *name)
dvander@2841
   426
{
dvander@4067
   427
	if (m_caps.contains(name))
dvander@2841
   428
		return;
dvander@2841
   429
dvander@2841
   430
	Capability cap;
dvander@2841
   431
	cap.ext = myself;
dvander@2841
   432
	cap.provider = provider;
dvander@2841
   433
dvander@2841
   434
	m_caps.insert(name, cap);
dvander@2841
   435
}
dvander@2841
   436
dvander@2841
   437
void ShareSystem::DropCapabilityProvider(IExtension *myself, IFeatureProvider *provider,
dvander@2841
   438
		                                 const char *name)
dvander@2841
   439
{
dvander@4067
   440
	StringHashMap<Capability>::Result r = m_caps.find(name);
dvander@4067
   441
	if (!r.found())
dvander@4067
   442
		return;
dvander@4067
   443
	if (r->value.ext != myself || r->value.provider != provider)
dvander@2841
   444
		return;
dvander@2841
   445
dvander@4067
   446
	m_caps.remove(r);
dvander@2841
   447
}
dvander@2841
   448
dvander@2841
   449
FeatureStatus ShareSystem::TestFeature(IPluginRuntime *pRuntime, FeatureType feature, 
dvander@2841
   450
                                       const char *name)
dvander@2841
   451
{
dvander@2841
   452
	switch (feature)
dvander@2841
   453
	{
dvander@2841
   454
	case FeatureType_Native:
dvander@2841
   455
		return TestNative(pRuntime, name);
dvander@2841
   456
	case FeatureType_Capability:
dvander@2841
   457
		return TestCap(name);
dvander@2841
   458
	default:
dvander@2841
   459
		break;
dvander@2841
   460
	}
dvander@2841
   461
dvander@2841
   462
	return FeatureStatus_Unknown;
dvander@2841
   463
}
dvander@2841
   464
dvander@2841
   465
FeatureStatus ShareSystem::TestNative(IPluginRuntime *pRuntime, const char *name)
dvander@2841
   466
{
dvander@2841
   467
	uint32_t index;
dvander@2841
   468
dvander@2841
   469
	if (pRuntime->FindNativeByName(name, &index) == SP_ERROR_NONE)
dvander@2841
   470
	{
dvander@2841
   471
		sp_native_t *native;
dvander@2841
   472
		if (pRuntime->GetNativeByIndex(index, &native) == SP_ERROR_NONE)
dvander@2841
   473
		{
dvander@2841
   474
			if (native->status == SP_NATIVE_BOUND)
dvander@2841
   475
				return FeatureStatus_Available;
dvander@2841
   476
			else
dvander@2841
   477
				return FeatureStatus_Unknown;
dvander@2841
   478
		}
dvander@2841
   479
	}
dvander@2841
   480
dvander@4109
   481
	Ref<Native> entry = FindNative(name);
dvander@4106
   482
	if (!entry)
dvander@2841
   483
		return FeatureStatus_Unknown;
dvander@2841
   484
dvander@4106
   485
	return FeatureStatus_Unavailable;
dvander@2841
   486
}
dvander@2841
   487
dvander@2841
   488
FeatureStatus ShareSystem::TestCap(const char *name)
dvander@2841
   489
{
dvander@4067
   490
	StringHashMap<Capability>::Result r = m_caps.find(name);
dvander@4067
   491
	if (!r.found())
dvander@2841
   492
		return FeatureStatus_Unknown;
dvander@2841
   493
dvander@4067
   494
	return r->value.provider->GetFeatureStatus(FeatureType_Capability, name);
dvander@2841
   495
}