dvander@370: /**
ds@653: * vim: set ts=4 :
ds@1330: * =============================================================================
dvander@1231: * SourceMod
ds@1947: * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
ds@1330: * =============================================================================
dvander@370: *
ds@1330: * This program is free software; you can redistribute it and/or modify it under
ds@1330: * the terms of the GNU General Public License, version 3.0, as published by the
ds@1330: * Free Software Foundation.
dvander@1231: *
ds@1330: * This program is distributed in the hope that it will be useful, but WITHOUT
ds@1330: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
ds@1330: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
ds@1330: * details.
dvander@1231: *
ds@1330: * You should have received a copy of the GNU General Public License along with
ds@1330: * this program. If not, see .
dvander@1231: *
ds@1330: * As a special exception, AlliedModders LLC gives you permission to link the
ds@1330: * code of this program (as well as its derivative works) to "Half-Life 2," the
ds@1330: * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
ds@1330: * by the Valve Corporation. You must obey the GNU General Public License in
ds@1330: * all respects for all other code used. Additionally, AlliedModders LLC grants
ds@1330: * this exception to all derivative works. AlliedModders LLC defines further
ds@1330: * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
ds@1330: * or .
dvander@370: *
dvander@370: * Version: $Id$
dvander@370: */
dvander@370:
dvander@229: #include "ShareSys.h"
dvander@229: #include "HandleSys.h"
dvander@304: #include "ExtensionSys.h"
dvander@336: #include "LibrarySys.h"
dvander@2086: #include "PluginSys.h"
dvander@2086: #include "sm_stringutil.h"
dvander@229:
dvander@229: ShareSystem g_ShareSys;
dvander@2086: static unsigned int g_mark_serial = 0;
dvander@229:
dvander@229: ShareSystem::ShareSystem()
dvander@229: {
dvander@229: m_IdentRoot.ident = 0;
dvander@229: m_TypeRoot = 0;
dvander@229: m_IfaceType = 0;
dvander@229: m_CoreType = 0;
dvander@229: }
dvander@229:
dvander@229: IdentityToken_t *ShareSystem::CreateCoreIdentity()
dvander@229: {
dvander@229: if (!m_CoreType)
dvander@229: {
dvander@229: m_CoreType = CreateIdentType("CORE");
dvander@229: }
dvander@229:
dvander@868: return CreateIdentity(m_CoreType, this);
dvander@229: }
dvander@229:
dvander@1770: void ShareSystem::Initialize()
dvander@229: {
dvander@262: TypeAccess sec;
dvander@229:
dvander@262: g_HandleSys.InitAccessDefaults(&sec, NULL);
dvander@262: sec.ident = GetIdentRoot();
dvander@262:
dvander@262: m_TypeRoot = g_HandleSys.CreateType("Identity", this, 0, &sec, NULL, NULL, NULL);
dvander@262: m_IfaceType = g_HandleSys.CreateType("Interface", this, 0, NULL, NULL, GetIdentRoot(), NULL);
dvander@229:
dvander@229: /* Initialize our static identity handle */
dvander@262: m_IdentRoot.ident = g_HandleSys.CreateHandle(m_TypeRoot, NULL, NULL, GetIdentRoot(), NULL);
dvander@305:
dvander@336: /* Add the Handle System and others... they are too innocent and pure to do it themselves */
dvander@305: AddInterface(NULL, &g_HandleSys);
dvander@336: AddInterface(NULL, &g_LibSys);
dvander@229: }
dvander@229:
dvander@229: void ShareSystem::OnSourceModShutdown()
dvander@229: {
dvander@229: if (m_CoreType)
dvander@229: {
dvander@229: g_HandleSys.RemoveType(m_CoreType, GetIdentRoot());
dvander@229: }
dvander@229:
dvander@229: g_HandleSys.RemoveType(m_IfaceType, GetIdentRoot());
dvander@229: g_HandleSys.RemoveType(m_TypeRoot, GetIdentRoot());
dvander@229: }
dvander@229:
dvander@229: IdentityType_t ShareSystem::FindIdentType(const char *name)
dvander@229: {
dvander@229: HandleType_t type;
dvander@229:
dvander@229: if (g_HandleSys.FindHandleType(name, &type))
dvander@229: {
dvander@229: if (g_HandleSys.TypeCheck(type, m_TypeRoot))
dvander@229: {
dvander@229: return type;
dvander@229: }
dvander@229: }
dvander@229:
dvander@229: return 0;
dvander@229: }
dvander@229:
dvander@229: IdentityType_t ShareSystem::CreateIdentType(const char *name)
dvander@229: {
dvander@229: if (!m_TypeRoot)
dvander@229: {
dvander@229: return 0;
dvander@229: }
dvander@229:
dvander@262: return g_HandleSys.CreateType(name, this, m_TypeRoot, NULL, NULL, GetIdentRoot(), NULL);
dvander@229: }
dvander@229:
dvander@229: void ShareSystem::OnHandleDestroy(HandleType_t type, void *object)
dvander@229: {
dvander@283: /* THIS WILL NEVER BE CALLED FOR ANYTHING WITH THE IDENTITY TYPE */
dvander@229: }
dvander@229:
dvander@868: IdentityToken_t *ShareSystem::CreateIdentity(IdentityType_t type, void *ptr)
dvander@229: {
dvander@229: if (!m_TypeRoot)
dvander@229: {
dvander@229: return 0;
dvander@229: }
dvander@229:
dvander@229: /* :TODO: Cache? */
dvander@229: IdentityToken_t *pToken = new IdentityToken_t;
dvander@528:
dvander@528: HandleSecurity sec;
dvander@528: sec.pOwner = sec.pIdentity = GetIdentRoot();
dvander@528:
dvander@528: pToken->ident = g_HandleSys.CreateHandleInt(type, NULL, &sec, NULL, NULL, true);
dvander@868: pToken->ptr = ptr;
dvander@868: pToken->type = type;
dvander@229:
dvander@229: return pToken;
dvander@229: }
dvander@229:
dvander@304: bool ShareSystem::AddInterface(IExtension *myself, SMInterface *iface)
dvander@229: {
dvander@229: if (!iface)
dvander@229: {
dvander@229: return false;
dvander@229: }
dvander@229:
dvander@229: IfaceInfo info;
dvander@229:
dvander@304: info.owner = myself;
dvander@229: info.iface = iface;
dvander@229:
dvander@229: m_Interfaces.push_back(info);
dvander@229:
dvander@229: return true;
dvander@229: }
dvander@229:
dvander@229: bool ShareSystem::RequestInterface(const char *iface_name,
dvander@229: unsigned int iface_vers,
dvander@311: IExtension *myself,
dvander@229: SMInterface **pIface)
dvander@229: {
dvander@229: /* See if the interface exists */
dvander@229: List::iterator iter;
dvander@229: SMInterface *iface;
dvander@304: IExtension *iface_owner;
dvander@229: bool found = false;
dvander@229: for (iter=m_Interfaces.begin(); iter!=m_Interfaces.end(); iter++)
dvander@229: {
dvander@229: IfaceInfo &info = (*iter);
dvander@229: iface = info.iface;
dvander@229: if (strcmp(iface->GetInterfaceName(), iface_name) == 0)
dvander@229: {
dvander@229: if (iface->GetInterfaceVersion() == iface_vers
dvander@229: || iface->IsVersionCompatible(iface_vers))
dvander@229: {
dvander@304: iface_owner = info.owner;
dvander@229: found = true;
dvander@229: break;
dvander@229: }
dvander@229: }
dvander@229: }
dvander@229:
dvander@229: if (!found)
dvander@229: {
dvander@229: return false;
dvander@229: }
dvander@229:
dvander@304: /* Add a dependency node */
dvander@229: if (iface_owner)
dvander@229: {
dvander@304: IfaceInfo info;
dvander@304: info.iface = iface;
dvander@304: info.owner = iface_owner;
dvander@311: g_Extensions.BindDependency(myself, &info);
dvander@229: }
dvander@229:
dvander@304: if (pIface)
dvander@304: {
dvander@304: *pIface = iface;
dvander@304: }
dvander@229:
dvander@304: return true;
dvander@229: }
dvander@229:
dvander@312: void ShareSystem::AddNatives(IExtension *myself, const sp_nativeinfo_t *natives)
dvander@229: {
dvander@2086: CNativeOwner *pOwner;
dvander@2086:
dvander@2086: pOwner = g_Extensions.GetNativeOwner(myself);
dvander@2086:
dvander@2086: pOwner->AddNatives(natives);
dvander@229: }
dvander@229:
dvander@229: void ShareSystem::DestroyIdentity(IdentityToken_t *identity)
dvander@229: {
dvander@262: HandleSecurity sec;
dvander@262:
dvander@262: sec.pOwner = GetIdentRoot();
dvander@262: sec.pIdentity = GetIdentRoot();
dvander@262:
dvander@262: g_HandleSys.FreeHandle(identity->ident, &sec);
dvander@229: delete identity;
dvander@229: }
dvander@229:
dvander@229: void ShareSystem::DestroyIdentType(IdentityType_t type)
dvander@229: {
dvander@229: g_HandleSys.RemoveType(type, GetIdentRoot());
dvander@229: }
dvander@229:
dvander@304: void ShareSystem::RemoveInterfaces(IExtension *pExtension)
dvander@304: {
dvander@304: List::iterator iter = m_Interfaces.begin();
dvander@304:
dvander@304: while (iter != m_Interfaces.end())
dvander@304: {
dvander@304: if ((*iter).owner == pExtension)
dvander@304: {
dvander@304: iter = m_Interfaces.erase(iter);
dvander@2086: }
dvander@2086: else
dvander@2086: {
dvander@304: iter++;
dvander@304: }
dvander@304: }
dvander@304: }
dvander@324:
dvander@324: void ShareSystem::AddDependency(IExtension *myself, const char *filename, bool require, bool autoload)
dvander@324: {
dvander@324: g_Extensions.AddDependency(myself, filename, require, autoload);
dvander@324: }
dvander@324:
dvander@1572: void ShareSystem::RegisterLibrary(IExtension *myself, const char *name)
dvander@1572: {
dvander@1572: g_Extensions.AddLibrary(myself, name);
dvander@1572: }
dvander@1689:
dvander@1689: void ShareSystem::OverrideNatives(IExtension *myself, const sp_nativeinfo_t *natives)
dvander@1689: {
dvander@2086: unsigned int i;
dvander@2086: NativeEntry *pEntry;
dvander@2086: CNativeOwner *pOwner;
dvander@2086:
dvander@2086: pOwner = g_Extensions.GetNativeOwner(myself);
dvander@2086:
dvander@2086: for (i = 0; natives[i].func != NULL && natives[i].name != NULL; i++)
dvander@2086: {
dvander@2086: if ((pEntry = FindNative(natives[i].name)) == NULL)
dvander@2086: {
dvander@2086: continue;
dvander@2086: }
dvander@2086:
dvander@2086: if (pEntry->owner != g_pCoreNatives)
dvander@2086: {
dvander@2086: continue;
dvander@2086: }
dvander@2086:
dvander@2086: if (pEntry->replacement.owner != NULL)
dvander@2086: {
dvander@2086: continue;
dvander@2086: }
dvander@2086:
dvander@2086: /* Now it's safe to add the override */
dvander@2086: pEntry->replacement.func = natives[i].func;
dvander@2086: pEntry->replacement.owner = pOwner;
dvander@2086: pOwner->AddReplacedNative(pEntry);
dvander@2086: }
dvander@2086: }
dvander@2086:
dvander@2086: NativeEntry *ShareSystem::FindNative(const char *name)
dvander@2086: {
dvander@2086: NativeEntry **ppEntry;
dvander@2086:
dvander@2086: if ((ppEntry = m_NtvCache.retrieve(name)) == NULL)
dvander@2086: {
dvander@2086: return NULL;
dvander@2086: }
dvander@2086:
dvander@2086: return *ppEntry;
dvander@2086: }
dvander@2086:
dvander@2086: void ShareSystem::BindNativesToPlugin(CPlugin *pPlugin, bool bCoreOnly)
dvander@2086: {
dvander@2086: NativeEntry *pEntry;
dvander@2086: sp_native_t *native;
dvander@2086: uint32_t i, native_count;
dvander@2086: IPluginContext *pContext;
dvander@2086:
dvander@2086: pContext = pPlugin->GetBaseContext();
dvander@2086:
dvander@2086: /* Generate a new serial ID, mark our dependencies with it. */
dvander@2086: g_mark_serial++;
dvander@2086: pPlugin->PropogateMarkSerial(g_mark_serial);
dvander@2086:
dvander@2086: native_count = pContext->GetNativesNum();
dvander@2086: for (i = 0; i < native_count; i++)
dvander@2086: {
dvander@2086: if (pContext->GetNativeByIndex(i, &native) != SP_ERROR_NONE)
dvander@2086: {
dvander@2086: continue;
dvander@2086: }
dvander@2086:
dvander@2086: /* If we're bound, check if there is a replacement available.
dvander@2086: * If not, this native is totally finalized.
dvander@2086: */
dvander@2086: if (native->status == SP_NATIVE_BOUND)
dvander@2086: {
dvander@2086: pEntry = (NativeEntry *)native->user;
dvander@2086: assert(pEntry != NULL);
dvander@2086: if (pEntry->replacement.owner == NULL
dvander@2086: || (pEntry->replacement.owner != NULL
dvander@2086: && pEntry->replacement.func == native->pfn))
dvander@2086: {
dvander@2086: continue;
dvander@2086: }
dvander@2086: }
dvander@2086: /* Otherwise, the native must be in our cache. */
dvander@2086: else if ((pEntry = FindNative(native->name)) == NULL)
dvander@2086: {
dvander@2086: continue;
dvander@2086: }
dvander@2086:
dvander@2086: if (bCoreOnly && pEntry->owner != g_pCoreNatives)
dvander@2086: {
dvander@2086: continue;
dvander@2086: }
dvander@2086:
dvander@2086: BindNativeToPlugin(pPlugin, native, i, pEntry);
dvander@2086: }
dvander@2086: }
dvander@2086:
dvander@2086: void ShareSystem::BindNativeToPlugin(CPlugin *pPlugin, NativeEntry *pEntry)
dvander@2086: {
dvander@2086: uint32_t i;
dvander@2086: sp_native_t *native;
dvander@2086: IPluginContext *pContext;
dvander@2086:
dvander@2086: pContext = pPlugin->GetBaseContext();
dvander@2086:
dvander@2086: if (pContext->FindNativeByName(pEntry->name, &i) != SP_ERROR_NONE)
dvander@2086: {
dvander@2086: return;
dvander@2086: }
dvander@2086: if (pContext->GetNativeByIndex(i, &native) != SP_ERROR_NONE)
dvander@2086: {
dvander@2086: return;
dvander@2086: }
dvander@2086:
dvander@2086: if (native->status == SP_NATIVE_BOUND)
dvander@2086: {
dvander@2086: return;
dvander@2086: }
dvander@2086:
dvander@2086: BindNativeToPlugin(pPlugin, native, i, pEntry);
dvander@1689: }
dvander@2086:
dvander@2086: void ShareSystem::BindNativeToPlugin(CPlugin *pPlugin,
dvander@2086: sp_native_t *native,
dvander@2086: uint32_t index,
dvander@2086: NativeEntry *pEntry)
dvander@2086: {
dvander@2086: /* Mark as bound... we do the rest next. */
dvander@2086: native->status = SP_NATIVE_BOUND;
dvander@2086: native->user = pEntry;
dvander@2086:
dvander@2086: /* See if a replacement is available. */
dvander@2086: if (pEntry->replacement.owner != NULL)
dvander@2086: {
dvander@2086: /* Perform a replacement bind. */
dvander@2086: native->pfn = pEntry->replacement.func;
dvander@2086: pEntry->replacement.owner->AddWeakRef(WeakNative(pPlugin, index, pEntry));
dvander@2086: }
dvander@2086: else
dvander@2086: {
dvander@2086: /* Perform a normal bind. */
dvander@2086: native->pfn = pEntry->func;
dvander@2086:
dvander@2086: /* We don't bother with dependency crap if the owner is Core. */
dvander@2086: if (pEntry->owner != g_pCoreNatives)
dvander@2086: {
dvander@2086: /* The native is optional, this is a special case */
dvander@2086: if ((native->flags & SP_NTVFLAG_OPTIONAL) == SP_NTVFLAG_OPTIONAL)
dvander@2086: {
dvander@2211: /* Only add if there is a valid owner. */
dvander@2211: if (pEntry->owner != NULL)
dvander@2211: {
dvander@2211: pEntry->owner->AddWeakRef(WeakNative(pPlugin, index));
dvander@2211: }
dvander@2211: else
dvander@2211: {
dvander@2211: native->status = SP_NATIVE_UNBOUND;
dvander@2211: }
dvander@2086: }
dvander@2086: /* Otherwise, we're a strong dependent and not a weak one */
dvander@2086: else
dvander@2086: {
dvander@2086: /* See if this has already been marked as a dependent.
dvander@2226: * If it has, it means this relationship has already occurred,
dvander@2226: * and there is no reason to do it again.
dvander@2226: */
dvander@2086: if (pEntry->owner != pPlugin
dvander@2086: && pEntry->owner->GetMarkSerial() != g_mark_serial)
dvander@2086: {
dvander@2086: /* This has not been marked as a dependency yet */
dvander@2086: //pPlugin->AddDependency(pEntry->owner);
dvander@2086: pEntry->owner->AddDependent(pPlugin);
dvander@2086: pEntry->owner->SetMarkSerial(g_mark_serial);
dvander@2086: }
dvander@2086: }
dvander@2086: }
dvander@2086: }
dvander@2086: }
dvander@2086:
dvander@2086: NativeEntry *ShareSystem::AddNativeToCache(CNativeOwner *pOwner, const sp_nativeinfo_t *ntv)
dvander@2086: {
dvander@2086: NativeEntry *pEntry;
dvander@2086:
dvander@2086: if ((pEntry = FindNative(ntv->name)) == NULL)
dvander@2086: {
dvander@2086: pEntry = new NativeEntry;
dvander@2086:
dvander@2086: pEntry->owner = pOwner;
dvander@2086: pEntry->name = ntv->name;
dvander@2086: pEntry->func = ntv->func;
dvander@2086: pEntry->replacement.func = NULL;
dvander@2086: pEntry->replacement.owner = NULL;
dvander@2086: pEntry->fake = NULL;
dvander@2086:
dvander@2086: m_NtvCache.insert(ntv->name, pEntry);
dvander@2086:
dvander@2086: return pEntry;
dvander@2086: }
dvander@2086:
dvander@2086: if (pEntry->owner != NULL)
dvander@2086: {
dvander@2086: return NULL;
dvander@2086: }
dvander@2086:
dvander@2086: pEntry->owner = pOwner;
dvander@2086: pEntry->func = ntv->func;
dvander@2086: pEntry->name = ntv->name;
dvander@2086:
dvander@2086: return pEntry;
dvander@2086: }
dvander@2086:
dvander@2086: void ShareSystem::ClearNativeFromCache(CNativeOwner *pOwner, const char *name)
dvander@2086: {
dvander@2086: NativeEntry *pEntry;
dvander@2086:
dvander@2086: if ((pEntry = FindNative(name)) == NULL)
dvander@2086: {
dvander@2086: return;
dvander@2086: }
dvander@2086:
dvander@2086: if (pEntry->owner != pOwner)
dvander@2086: {
dvander@2086: return;
dvander@2086: }
dvander@2086:
dvander@2211: if (pEntry->fake != NULL)
dvander@2211: {
dvander@2211: g_pSourcePawn2->DestroyFakeNative(pEntry->func);
dvander@2211: delete pEntry->fake;
dvander@2211: pEntry->fake = NULL;
dvander@2211: }
dvander@2211:
dvander@2086: pEntry->func = NULL;
dvander@2086: pEntry->name = NULL;
dvander@2086: pEntry->owner = NULL;
dvander@2086: pEntry->replacement.func = NULL;
dvander@2086: pEntry->replacement.owner = NULL;
dvander@2086: }
dvander@2086:
dvander@2086: NativeEntry *ShareSystem::AddFakeNative(IPluginFunction *pFunc, const char *name, SPVM_FAKENATIVE_FUNC func)
dvander@2086: {
dvander@2086: FakeNative *pFake;
dvander@2086: NativeEntry *pEntry;
dvander@2086: SPVM_NATIVE_FUNC gate;
dvander@2086:
dvander@2086: if ((pEntry = FindNative(name)) != NULL && pEntry->owner != NULL)
dvander@2086: {
dvander@2086: return NULL;
dvander@2086: }
dvander@2086:
dvander@2086: pFake = new FakeNative;
dvander@2086:
dvander@2193: if ((gate = g_pSourcePawn2->CreateFakeNative(func, pFake)) == NULL)
dvander@2086: {
dvander@2086: delete pFake;
dvander@2086: return NULL;
dvander@2086: }
dvander@2086:
dvander@2086: if (pEntry == NULL)
dvander@2086: {
dvander@2086: pEntry = new NativeEntry;
dvander@2086: m_NtvCache.insert(name, pEntry);
dvander@2086: }
dvander@2086:
dvander@2086: pFake->call = pFunc;
dvander@2086: pFake->ctx = pFunc->GetParentContext();
dvander@2086: strncopy(pFake->name, name, sizeof(pFake->name));
dvander@2086:
dvander@2086: pEntry->fake = pFake;
dvander@2086: pEntry->func = gate;
dvander@2086: pEntry->name = pFake->name;
dvander@2086: pEntry->owner = g_PluginSys.GetPluginByCtx(pFake->ctx->GetContext());
dvander@2086: pEntry->replacement.func = NULL;
dvander@2086: pEntry->replacement.owner = NULL;
dvander@2086:
dvander@2086: return pEntry;
dvander@2086: }
dvander@2841:
dvander@2841: void ShareSystem::AddCapabilityProvider(IExtension *myself, IFeatureProvider *provider,
dvander@2841: const char *name)
dvander@2841: {
dvander@2841: if (m_caps.retrieve(name) != NULL)
dvander@2841: return;
dvander@2841:
dvander@2841: Capability cap;
dvander@2841: cap.ext = myself;
dvander@2841: cap.provider = provider;
dvander@2841:
dvander@2841: m_caps.insert(name, cap);
dvander@2841: }
dvander@2841:
dvander@2841: void ShareSystem::DropCapabilityProvider(IExtension *myself, IFeatureProvider *provider,
dvander@2841: const char *name)
dvander@2841: {
dvander@2841: Capability *pCap = m_caps.retrieve(name);
dvander@2841: if (pCap == NULL)
dvander@2841: return;
dvander@2841:
dvander@2841: if (pCap->ext != myself || pCap->provider != provider)
dvander@2841: return;
dvander@2841:
dvander@2841: m_caps.remove(name);
dvander@2841: }
dvander@2841:
dvander@2841: FeatureStatus ShareSystem::TestFeature(IPluginRuntime *pRuntime, FeatureType feature,
dvander@2841: const char *name)
dvander@2841: {
dvander@2841: switch (feature)
dvander@2841: {
dvander@2841: case FeatureType_Native:
dvander@2841: return TestNative(pRuntime, name);
dvander@2841: case FeatureType_Capability:
dvander@2841: return TestCap(name);
dvander@2841: default:
dvander@2841: break;
dvander@2841: }
dvander@2841:
dvander@2841: return FeatureStatus_Unknown;
dvander@2841: }
dvander@2841:
dvander@2841: FeatureStatus ShareSystem::TestNative(IPluginRuntime *pRuntime, const char *name)
dvander@2841: {
dvander@2841: uint32_t index;
dvander@2841:
dvander@2841: if (pRuntime->FindNativeByName(name, &index) == SP_ERROR_NONE)
dvander@2841: {
dvander@2841: sp_native_t *native;
dvander@2841: if (pRuntime->GetNativeByIndex(index, &native) == SP_ERROR_NONE)
dvander@2841: {
dvander@2841: if (native->status == SP_NATIVE_BOUND)
dvander@2841: return FeatureStatus_Available;
dvander@2841: else
dvander@2841: return FeatureStatus_Unknown;
dvander@2841: }
dvander@2841: }
dvander@2841:
dvander@2841: NativeEntry *entry = FindNative(name);
dvander@2841: if (entry == NULL)
dvander@2841: return FeatureStatus_Unknown;
dvander@2841:
dvander@2841: if ((entry->replacement.owner != NULL || entry->owner != NULL) &&
dvander@2841: (entry->replacement.func != NULL || entry->func != NULL))
dvander@2841: {
dvander@2841: return FeatureStatus_Available;
dvander@2841: }
dvander@2841: else
dvander@2841: {
dvander@2841: return FeatureStatus_Unavailable;
dvander@2841: }
dvander@2841: }
dvander@2841:
dvander@2841: FeatureStatus ShareSystem::TestCap(const char *name)
dvander@2841: {
dvander@2841: Capability *cap = m_caps.retrieve(name);
dvander@2841: if (cap == NULL)
dvander@2841: return FeatureStatus_Unknown;
dvander@2841:
dvander@2841: return cap->provider->GetFeatureStatus(FeatureType_Capability, name);
dvander@2841: }