ds@1952: /** ds@1952: * vim: set ts=4 : ds@1952: * ============================================================================= ds@1952: * SourceMod ds@1952: * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. ds@1952: * ============================================================================= ds@1952: * ds@1952: * This program is free software; you can redistribute it and/or modify it under ds@1952: * the terms of the GNU General Public License, version 3.0, as published by the ds@1952: * Free Software Foundation. ds@1952: * ds@1952: * This program is distributed in the hope that it will be useful, but WITHOUT ds@1952: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS ds@1952: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more ds@1952: * details. ds@1952: * ds@1952: * You should have received a copy of the GNU General Public License along with ds@1952: * this program. If not, see . ds@1952: * ds@1952: * As a special exception, AlliedModders LLC gives you permission to link the ds@1952: * code of this program (as well as its derivative works) to "Half-Life 2," the ds@1952: * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software ds@1952: * by the Valve Corporation. You must obey the GNU General Public License in ds@1952: * all respects for all other code used. Additionally, AlliedModders LLC grants ds@1952: * this exception to all derivative works. AlliedModders LLC defines further ds@1952: * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), ds@1952: * or . ds@1952: * ds@1952: * Version: $Id$ ds@1952: */ ds@1952: ds@1952: #include ds@1952: #include ds@1952: #include ds@1952: #include "sm_stringutil.h" ds@1952: #include "sm_globals.h" ds@1952: #include "sourcemod.h" ds@1952: #include "PluginSys.h" ds@1952: #include "HandleSys.h" ds@1952: #include "LibrarySys.h" ds@1952: #include "TimerSys.h" ds@1952: #include "ForwardSys.h" ds@1952: #include "Logger.h" ds@1952: #include "ExtensionSys.h" ds@1952: ds@1952: #if defined PLATFORM_WINDOWS ds@1952: #include ds@1952: #elif defined PLATFORM_LINUX ds@1952: #include ds@1952: #include ds@1952: #include ds@1952: #endif ds@1952: ds@1952: HandleType_t g_PlIter; ds@1952: ConVar sm_datetime_format("sm_datetime_format", "%m/%d/%Y - %H:%M:%S", 0, "Default formatting time rules"); ds@1952: IForward *g_OnLogAction = NULL; ds@1952: ds@1952: class CoreNativeHelpers : ds@1952: public SMGlobalClass, ds@1952: public IHandleTypeDispatch ds@1952: { ds@1952: public: ds@1952: void OnSourceModAllInitialized() ds@1952: { ds@1952: HandleAccess hacc; ds@1952: g_HandleSys.InitAccessDefaults(NULL, &hacc); ds@1952: hacc.access[HandleAccess_Clone] = HANDLE_RESTRICT_IDENTITY|HANDLE_RESTRICT_OWNER; ds@1952: ds@1952: g_PlIter = g_HandleSys.CreateType("PluginIterator", this, 0, NULL, NULL, g_pCoreIdent, NULL); ds@1952: ds@1952: g_OnLogAction = g_Forwards.CreateForward("OnLogAction", ds@1952: ET_Hook, ds@1952: 5, ds@1952: NULL, ds@1952: Param_Cell, ds@1952: Param_Cell, ds@1952: Param_Cell, ds@1952: Param_Cell, ds@1952: Param_String); ds@1952: } ds@1952: void OnHandleDestroy(HandleType_t type, void *object) ds@1952: { ds@1952: IPluginIterator *iter = (IPluginIterator *)object; ds@1952: iter->Release(); ds@1952: } ds@1952: void OnSourceModShutdown() ds@1952: { ds@1952: g_Forwards.ReleaseForward(g_OnLogAction); ds@1952: g_HandleSys.RemoveType(g_PlIter, g_pCoreIdent); ds@1952: } ds@1952: } g_CoreNativeHelpers; ds@1952: ds@1952: void LogAction(Handle_t hndl, int type, int client, int target, const char *message) ds@1952: { ds@1952: if (g_OnLogAction->GetFunctionCount()) ds@1952: { ds@1952: cell_t result = 0; ds@1952: g_OnLogAction->PushCell(hndl); ds@1952: g_OnLogAction->PushCell(type); ds@1952: g_OnLogAction->PushCell(client); ds@1952: g_OnLogAction->PushCell(target); ds@1952: g_OnLogAction->PushString(message); ds@1952: g_OnLogAction->Execute(&result); ds@1952: ds@1952: if (result >= (ResultType)Pl_Handled) ds@1952: { ds@1952: return; ds@1952: } ds@1952: } ds@1952: ds@1952: const char *logtag = "SM"; ds@1952: if (type == 2) ds@1952: { ds@1952: HandleError err; ds@1952: IPlugin *pPlugin = g_PluginSys.PluginFromHandle(hndl, &err); ds@1952: if (pPlugin) ds@1952: { ds@1952: logtag = pPlugin->GetFilename(); ds@1952: } ds@1952: } ds@1952: ds@1952: g_Logger.LogMessage("[%s] %s", logtag, message); ds@1952: } ds@1952: ds@1952: static cell_t ThrowError(IPluginContext *pContext, const cell_t *params) ds@1952: { ds@1952: char buffer[512]; ds@1952: dvander@2042: g_SourceMod.SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE); ds@1952: ds@1952: g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 1); ds@1952: ds@1952: if (pContext->GetContext()->n_err == SP_ERROR_NONE) ds@1952: { ds@1952: pContext->ThrowNativeErrorEx(SP_ERROR_ABORTED, "%s", buffer); ds@1952: } ds@1952: ds@1952: return 0; ds@1952: } ds@1952: ds@1952: static cell_t GetTime(IPluginContext *pContext, const cell_t *params) ds@1952: { ds@1952: time_t t = GetAdjustedTime(); ds@1952: cell_t *addr; ds@1952: pContext->LocalToPhysAddr(params[1], &addr); ds@1952: ds@1952: *(time_t *)addr = t; ds@1952: ds@1952: return static_cast(t); ds@1952: } ds@1952: ds@1952: #if defined SUBPLATFORM_SECURECRT ds@1952: void _ignore_invalid_parameter( ds@1952: const wchar_t * expression, ds@1952: const wchar_t * function, ds@1952: const wchar_t * file, ds@1952: unsigned int line, ds@1952: uintptr_t pReserved ds@1952: ) ds@1952: { ds@1952: /* Wow we don't care, thanks Microsoft. */ ds@1952: } ds@1952: #endif ds@1952: ds@1952: static cell_t FormatTime(IPluginContext *pContext, const cell_t *params) ds@1952: { ds@1952: char *format, *buffer; ds@1952: pContext->LocalToString(params[1], &buffer); ds@1952: pContext->LocalToStringNULL(params[3], &format); ds@1952: ds@1952: if (format == NULL) ds@1952: { ds@1952: format = const_cast(sm_datetime_format.GetString()); ds@1952: } ds@1952: ds@1952: #if defined SUBPLATFORM_SECURECRT ds@1952: _invalid_parameter_handler handler = _set_invalid_parameter_handler(_ignore_invalid_parameter); ds@1952: #endif ds@1952: ds@1952: time_t t = (params[4] == -1) ? GetAdjustedTime() : (time_t)params[4]; ds@1952: size_t written = strftime(buffer, params[2], format, localtime(&t)); ds@1952: ds@1952: #if defined SUBPLATFORM_SECURECRT ds@1952: _set_invalid_parameter_handler(handler); ds@1952: #endif ds@1952: ds@1952: if (params[2] && format[0] != '\0' && !written) ds@1952: { ds@1952: pContext->ThrowNativeError("Invalid time format or buffer too small"); ds@1952: return 0; ds@1952: } ds@1952: ds@1952: return 1; ds@1952: } ds@1952: ds@1952: static cell_t GetPluginIterator(IPluginContext *pContext, const cell_t *params) ds@1952: { ds@1952: IPluginIterator *iter = g_PluginSys.GetPluginIterator(); ds@1952: ds@1952: Handle_t hndl = g_HandleSys.CreateHandle(g_PlIter, iter, pContext->GetIdentity(), g_pCoreIdent, NULL); ds@1952: ds@1952: if (hndl == BAD_HANDLE) ds@1952: { ds@1952: iter->Release(); ds@1952: } ds@1952: ds@1952: return hndl; ds@1952: } ds@1952: ds@1952: static cell_t MorePlugins(IPluginContext *pContext, const cell_t *params) ds@1952: { ds@1952: Handle_t hndl = (Handle_t)params[1]; ds@1952: HandleError err; ds@1952: IPluginIterator *pIter; ds@1952: ds@1952: HandleSecurity sec; ds@1952: sec.pIdentity = g_pCoreIdent; ds@1952: sec.pOwner = pContext->GetIdentity(); ds@1952: ds@1952: if ((err=g_HandleSys.ReadHandle(hndl, g_PlIter, &sec, (void **)&pIter)) != HandleError_None) ds@1952: { ds@1952: return pContext->ThrowNativeError("Could not read Handle %x (error %d)", hndl, err); ds@1952: } ds@1952: ds@1952: return pIter->MorePlugins() ? 1 : 0; ds@1952: } ds@1952: ds@1952: static cell_t ReadPlugin(IPluginContext *pContext, const cell_t *params) ds@1952: { ds@1952: Handle_t hndl = (Handle_t)params[1]; ds@1952: HandleError err; ds@1952: IPluginIterator *pIter; ds@1952: ds@1952: HandleSecurity sec; ds@1952: sec.pIdentity = g_pCoreIdent; ds@1952: sec.pOwner = pContext->GetIdentity(); ds@1952: ds@1952: if ((err=g_HandleSys.ReadHandle(hndl, g_PlIter, &sec, (void **)&pIter)) != HandleError_None) ds@1952: { ds@1952: return pContext->ThrowNativeError("Could not read Handle %x (error %d)", hndl, err); ds@1952: } ds@1952: ds@1952: CPlugin *pPlugin = (CPlugin *)pIter->GetPlugin(); ds@1952: if (!pPlugin) ds@1952: { ds@1952: return BAD_HANDLE; ds@1952: } ds@1952: ds@1952: pIter->NextPlugin(); ds@1952: ds@1952: return pPlugin->GetMyHandle(); ds@1952: } ds@1952: ds@1952: CPlugin *GetPluginFromHandle(IPluginContext *pContext, Handle_t hndl) ds@1952: { ds@1952: if (hndl == BAD_HANDLE) ds@1952: { ds@1952: return g_PluginSys.GetPluginByCtx(pContext->GetContext()); ds@1952: } else { ds@1952: HandleError err; ds@1952: CPlugin *pPlugin = (CPlugin *)g_PluginSys.PluginFromHandle(hndl, &err); ds@1952: if (!pPlugin) ds@1952: { ds@1952: pContext->ThrowNativeError("Could not read Handle %x (error %d)", hndl, err); ds@1952: } ds@1952: return pPlugin; ds@1952: } ds@1952: } ds@1952: ds@1952: static cell_t GetPluginStatus(IPluginContext *pContext, const cell_t *params) ds@1952: { ds@1952: CPlugin *pPlugin = GetPluginFromHandle(pContext, params[1]); ds@1952: if (!pPlugin) ds@1952: { ds@1952: return 0; ds@1952: } ds@1952: ds@1952: return pPlugin->GetStatus(); ds@1952: } ds@1952: ds@1952: static cell_t GetPluginFilename(IPluginContext *pContext, const cell_t *params) ds@1952: { ds@1952: CPlugin *pPlugin = GetPluginFromHandle(pContext, params[1]); ds@1952: if (!pPlugin) ds@1952: { ds@1952: return 0; ds@1952: } ds@1952: ds@1952: pContext->StringToLocalUTF8(params[2], params[3], pPlugin->GetFilename(), NULL); ds@1952: ds@1952: return 1; ds@1952: } ds@1952: ds@1952: static cell_t IsPluginDebugging(IPluginContext *pContext, const cell_t *params) ds@1952: { ds@1952: CPlugin *pPlugin = GetPluginFromHandle(pContext, params[1]); ds@1952: if (!pPlugin) ds@1952: { ds@1952: return 0; ds@1952: } ds@1952: ds@1952: return pPlugin->IsDebugging() ? 1 : 0; ds@1952: } ds@1952: ds@1952: /* Local to plugins only */ ds@1952: enum PluginInfo ds@1952: { ds@1952: PlInfo_Name, /**< Plugin name */ ds@1952: PlInfo_Author, /**< Plugin author */ ds@1952: PlInfo_Description, /**< Plugin description */ ds@1952: PlInfo_Version, /**< Plugin verison */ ds@1952: PlInfo_URL, /**< Plugin URL */ ds@1952: }; ds@1952: ds@1952: static cell_t GetPluginInfo(IPluginContext *pContext, const cell_t *params) ds@1952: { ds@1952: CPlugin *pPlugin = GetPluginFromHandle(pContext, params[1]); ds@1952: if (!pPlugin) ds@1952: { ds@1952: return 0; ds@1952: } ds@1952: ds@1952: const sm_plugininfo_t *info = pPlugin->GetPublicInfo(); ds@1952: ds@1952: if (!info) ds@1952: { ds@1952: return 0; ds@1952: } ds@1952: ds@1952: const char *str = NULL; ds@1952: ds@1952: switch ((PluginInfo)params[2]) ds@1952: { ds@1952: case PlInfo_Name: ds@1952: { ds@1952: str = info->name; ds@1952: break; ds@1952: } ds@1952: case PlInfo_Author: ds@1952: { ds@1952: str = info->author; ds@1952: break; ds@1952: } ds@1952: case PlInfo_Description: ds@1952: { ds@1952: str = info->description; ds@1952: break; ds@1952: } ds@1952: case PlInfo_Version: ds@1952: { ds@1952: str = info->version; ds@1952: break; ds@1952: } ds@1952: case PlInfo_URL: ds@1952: { ds@1952: str = info->url; ds@1952: break; ds@1952: } ds@1952: } ds@1952: ds@1952: if (!str || str[0] == '\0') ds@1952: { ds@1952: return 0; ds@1952: } ds@1952: ds@1952: pContext->StringToLocalUTF8(params[3], params[4], str, NULL); ds@1952: ds@1952: return 1; ds@1952: } ds@1952: ds@1952: static cell_t SetFailState(IPluginContext *pContext, const cell_t *params) ds@1952: { ds@1952: char *str; ds@1952: CPlugin *pPlugin; ds@1952: ds@1952: pContext->LocalToString(params[1], &str); ds@1952: pPlugin = g_PluginSys.GetPluginByCtx(pContext->GetContext()); ds@1952: ds@1952: if (params[0] == 1) ds@1952: { ds@1952: pPlugin->SetErrorState(Plugin_Error, "%s", str); ds@1952: ds@1952: return pContext->ThrowNativeErrorEx(SP_ERROR_ABORTED, "%s", str); ds@1952: } ds@1952: else ds@1952: { ds@1952: char buffer[2048]; ds@1952: ds@1952: g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 1); ds@1952: if (pContext->GetContext()->n_err != SP_ERROR_NONE) ds@1952: { ds@1952: pPlugin->SetErrorState(Plugin_Error, "%s", str); ds@1952: return pContext->ThrowNativeErrorEx(SP_ERROR_ABORTED, "Formatting error (%s)", str); ds@1952: } ds@1952: else ds@1952: { ds@1952: pPlugin->SetErrorState(Plugin_Error, "%s", buffer); ds@1952: return pContext->ThrowNativeErrorEx(SP_ERROR_ABORTED, "%s", buffer); ds@1952: } ds@1952: } ds@1952: ds@1952: return 0; ds@1952: } ds@1952: ds@1952: static cell_t GetSysTickCount(IPluginContext *pContext, const cell_t *params) ds@1952: { ds@1952: #if defined PLATFORM_WINDOWS ds@1952: return (cell_t)GetTickCount(); ds@1952: #elif defined PLATFORM_LINUX ds@1952: tms tm; ds@1952: clock_t ticks = times(&tm); ds@1952: long ticks_per_sec = sysconf(_SC_CLK_TCK); ds@1952: double fticks = (double)ticks / (double)ticks_per_sec; ds@1952: fticks *= 1000.0f; ds@1952: if (fticks > INT_MAX) ds@1952: { ds@1952: double r = (int)(fticks / INT_MAX) * (double)INT_MAX; ds@1952: fticks -= r; ds@1952: } ds@1952: return (cell_t)fticks; ds@1952: #endif ds@1952: } ds@1952: ds@1952: static cell_t AutoExecConfig(IPluginContext *pContext, const cell_t *params) ds@1952: { ds@1952: CPlugin *plugin = g_PluginSys.GetPluginByCtx(pContext->GetContext()); ds@1952: ds@1952: char *cfg, *folder; ds@1952: pContext->LocalToString(params[2], &cfg); ds@1952: pContext->LocalToString(params[3], &folder); ds@1952: ds@1952: if (cfg[0] == '\0') ds@1952: { ds@1952: static char temp_str[255]; ds@1952: static char temp_file[PLATFORM_MAX_PATH]; ds@1952: char *ptr; ds@1952: ds@1952: g_LibSys.GetFileFromPath(temp_str, sizeof(temp_str), plugin->GetFilename()); ds@1952: if ((ptr = strstr(temp_str, ".smx")) != NULL) ds@1952: { ds@1952: *ptr = '\0'; ds@1952: } ds@1952: ds@1952: /* We have the raw filename! */ ds@1952: UTIL_Format(temp_file, sizeof(temp_file), "plugin.%s", temp_str); ds@1952: cfg = temp_file; ds@1952: } ds@1952: ds@1952: plugin->AddConfig(params[1] ? true : false, cfg, folder); ds@1952: ds@1952: return 1; ds@1952: } ds@1952: ds@1952: static cell_t MarkNativeAsOptional(IPluginContext *pContext, const cell_t *params) ds@1952: { ds@1952: char *name; ds@1952: uint32_t idx; ds@1952: sp_context_t *ctx = pContext->GetContext(); ds@1952: ds@1952: pContext->LocalToString(params[1], &name); ds@1952: if (pContext->FindNativeByName(name, &idx) != SP_ERROR_NONE) ds@1952: { ds@1952: /* Oops! This HAS to silently fail! */ ds@1952: return 0; ds@1952: } ds@1952: ds@1952: ctx->natives[idx].flags |= SP_NTVFLAG_OPTIONAL; ds@1952: ds@1952: return 1; ds@1952: } ds@1952: ds@1952: static cell_t RegPluginLibrary(IPluginContext *pContext, const cell_t *params) ds@1952: { ds@1952: char *name; ds@1952: CPlugin *pl = g_PluginSys.GetPluginByCtx(pContext->GetContext()); ds@1952: ds@1952: pContext->LocalToString(params[1], &name); ds@1952: ds@1952: pl->AddLibrary(name); ds@1952: ds@1952: return 1; ds@1952: } ds@1952: ds@1952: static cell_t LibraryExists(IPluginContext *pContext, const cell_t *params) ds@1952: { ds@1952: char *str; ds@1952: pContext->LocalToString(params[1], &str); ds@1952: ds@1952: if (g_PluginSys.LibraryExists(str)) ds@1952: { ds@1952: return 1; ds@1952: } ds@1952: ds@1952: if (g_Extensions.LibraryExists(str)) ds@1952: { ds@1952: return 1; ds@1952: } ds@1952: ds@1952: return 0; ds@1952: } ds@1952: ds@1952: static cell_t sm_LogAction(IPluginContext *pContext, const cell_t *params) ds@1952: { ds@1952: char buffer[2048]; dvander@2042: g_SourceMod.SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE); ds@1952: g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 3); ds@1952: ds@1952: if (pContext->GetContext()->n_err != SP_ERROR_NONE) ds@1952: { ds@1952: return 0; ds@1952: } ds@1952: ds@1952: CPlugin *pPlugin = g_PluginSys.GetPluginByCtx(pContext->GetContext()); ds@1952: ds@1952: LogAction(pPlugin->GetMyHandle(), 2, params[1], params[2], buffer); ds@1952: ds@1952: return 1; ds@1952: } ds@1952: ds@1952: static cell_t LogToFile(IPluginContext *pContext, const cell_t *params) ds@1952: { ds@1952: char *file; ds@1952: pContext->LocalToString(params[1], &file); ds@1952: ds@1952: char path[PLATFORM_MAX_PATH]; ds@1952: g_SourceMod.BuildPath(Path_Game, path, sizeof(path), "%s", file); ds@1952: ds@1952: FILE *fp = fopen(path, "at"); ds@1952: if (!fp) ds@1952: { ds@1952: return pContext->ThrowNativeError("Could not open file \"%s\"", path); ds@1952: } ds@1952: ds@1952: char buffer[2048]; dvander@2042: g_SourceMod.SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE); ds@1952: g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2); ds@1952: ds@1952: if (pContext->GetContext()->n_err != SP_ERROR_NONE) ds@1952: { ds@1952: fclose(fp); ds@1952: return 0; ds@1952: } ds@1952: ds@1952: CPlugin *pPlugin = g_PluginSys.GetPluginByCtx(pContext->GetContext()); ds@1952: ds@1952: g_Logger.LogToOpenFile(fp, "[%s] %s", pPlugin->GetFilename(), buffer); ds@1952: ds@1952: fclose(fp); ds@1952: ds@1952: return 1; ds@1952: } ds@1952: ds@1952: static cell_t LogToFileEx(IPluginContext *pContext, const cell_t *params) ds@1952: { ds@1952: char *file; ds@1952: pContext->LocalToString(params[1], &file); ds@1952: ds@1952: char path[PLATFORM_MAX_PATH]; ds@1952: g_SourceMod.BuildPath(Path_Game, path, sizeof(path), "%s", file); ds@1952: ds@1952: FILE *fp = fopen(path, "at"); ds@1952: if (!fp) ds@1952: { ds@1952: return pContext->ThrowNativeError("Could not open file \"%s\"", path); ds@1952: } ds@1952: ds@1952: char buffer[2048]; dvander@2042: g_SourceMod.SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE); ds@1952: g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2); ds@1952: ds@1952: if (pContext->GetContext()->n_err != SP_ERROR_NONE) ds@1952: { ds@1952: fclose(fp); ds@1952: return 0; ds@1952: } ds@1952: ds@1952: g_Logger.LogToOpenFile(fp, "%s", buffer); ds@1952: ds@1952: fclose(fp); ds@1952: ds@1952: return 1; ds@1952: } ds@1952: ds@1952: static cell_t GetExtensionFileStatus(IPluginContext *pContext, const cell_t *params) ds@1952: { ds@1952: char *str; ds@1952: pContext->LocalToString(params[1], &str); ds@1952: ds@1952: IExtension *pExtension = g_Extensions.FindExtensionByFile(str); ds@1952: ds@1952: if (!pExtension) ds@1952: { ds@1952: return -2; ds@1952: } ds@1952: ds@1952: if (!pExtension->IsLoaded()) ds@1952: { ds@1952: return -1; ds@1952: } ds@1952: ds@1952: char *error; ds@1952: pContext->LocalToString(params[2], &error); ds@1952: if (!pExtension->IsRunning(error, params[3])) ds@1952: { ds@1952: return 0; ds@1952: } ds@1952: ds@1952: return 1; ds@1952: } ds@1952: ds@1952: static cell_t FindPluginByNumber(IPluginContext *pContext, const cell_t *params) ds@1952: { ds@1952: CPlugin *pPlugin = g_PluginSys.GetPluginByOrder(params[1]); ds@1952: ds@1952: if (pPlugin == NULL) ds@1952: { ds@1952: return BAD_HANDLE; ds@1952: } ds@1952: ds@1952: return pPlugin->GetMyHandle(); ds@1952: } ds@1952: ds@1952: REGISTER_NATIVES(coreNatives) ds@1952: { ds@1952: {"AutoExecConfig", AutoExecConfig}, ds@1952: {"GetPluginFilename", GetPluginFilename}, ds@1952: {"GetPluginInfo", GetPluginInfo}, ds@1952: {"GetPluginIterator", GetPluginIterator}, ds@1952: {"GetPluginStatus", GetPluginStatus}, ds@1952: {"GetSysTickCount", GetSysTickCount}, ds@1952: {"GetTime", GetTime}, ds@1952: {"IsPluginDebugging", IsPluginDebugging}, ds@1952: {"MorePlugins", MorePlugins}, ds@1952: {"ReadPlugin", ReadPlugin}, ds@1952: {"ThrowError", ThrowError}, ds@1952: {"SetFailState", SetFailState}, ds@1952: {"FormatTime", FormatTime}, ds@1952: {"MarkNativeAsOptional", MarkNativeAsOptional}, ds@1952: {"RegPluginLibrary", RegPluginLibrary}, ds@1952: {"LibraryExists", LibraryExists}, ds@1952: {"LogAction", sm_LogAction}, ds@1952: {"LogToFile", LogToFile}, ds@1952: {"LogToFileEx", LogToFileEx}, ds@1952: {"GetExtensionFileStatus", GetExtensionFileStatus}, ds@1952: {"FindPluginByNumber", FindPluginByNumber}, ds@1952: {NULL, NULL}, ds@1952: }; ds@1952: