Merge remote-tracking branch 'upstream/master' into sdkhooks-blocked

This commit is contained in:
Ryan Stecker 2014-09-02 00:04:54 -05:00
commit 88c6d3d9a7
138 changed files with 6209 additions and 4680 deletions

View File

@ -190,7 +190,7 @@ class SMConfig(object):
cxx.cflags += ['-Wno-unused-result']
if have_clang:
cxx.cxxflags += ['-Wno-implicit-exception-spec-mismatch']
if (builder.target_platform == 'mac' and cxx.version >= '5.1') or cxx.version >= '3.4':
if cxx.version >= 'apple-clang-5.1' or cxx.version >= 'clang-3.4':
cxx.cxxflags += ['-Wno-deprecated-register']
else:
cxx.cxxflags += ['-Wno-deprecated']

View File

@ -1,6 +0,0 @@
Contributing
------------
Please visit [our wiki](https://wiki.alliedmods.net/Contributing_to_SourceMod) for information on how to contribute to Sourcemod.
As a sidenote, [Travis](https://travis-ci.org/alliedmodders/sourcemod) will automatically build your PR to make sure it compiles on Linux.

View File

@ -31,7 +31,6 @@ project.sources += [
'smn_console.cpp',
'UserMessages.cpp',
'MenuManager.cpp',
'smn_core.cpp',
'smn_hudtext.cpp',
'smn_usermsgs.cpp',
'MenuStyle_Base.cpp',
@ -53,17 +52,14 @@ for sdk_name in SM.sdks:
compiler = binary.compiler
if sdk.name == 'csgo':
# Protobuf 2.3 headers have some signed/unsigned compares. I believe that it's fixed in later versions, but Valve.
if compiler.cxx.behavior == 'gcc':
compiler.cflags += ['-Wno-sign-compare']
compiler.cxxincludes += [
os.path.join(sdk.path, 'common', 'protobuf-2.3.0', 'src'),
os.path.join(sdk.path, 'common', 'protobuf-2.5.0', 'src'),
os.path.join(sdk.path, 'public', 'engine', 'protobuf'),
os.path.join(sdk.path, 'public', 'game', 'shared', 'csgo', 'protobuf')
]
elif sdk.name == 'dota':
compiler.cxxincludes += [
os.path.join(sdk.path, 'common', 'protobuf-2.4.1', 'src'),
os.path.join(sdk.path, 'common', 'protobuf-2.5.0', 'src'),
os.path.join(sdk.path, 'public', 'engine', 'protobuf'),
os.path.join(sdk.path, 'public', 'game', 'shared', 'protobuf'),
os.path.join(sdk.path, 'public', 'game', 'shared', 'dota', 'protobuf')
@ -110,6 +106,7 @@ for sdk_name in SM.sdks:
binary.sources += [
os.path.join(sdk.path, 'public', 'engine', 'protobuf', 'networkbasetypes.pb.cc'),
os.path.join(sdk.path, 'public', 'engine', 'protobuf', 'netmessages.pb.cc'),
os.path.join(sdk.path, 'public', 'engine', 'protobuf', 'network_connection.pb.cc'),
os.path.join(sdk.path, 'public', 'game', 'shared', 'protobuf', 'ai_activity.pb.cc'),
os.path.join(sdk.path, 'public', 'game', 'shared', 'protobuf', 'usermessages.pb.cc'),
os.path.join(sdk.path, 'public', 'game', 'shared', 'dota', 'protobuf', 'dota_commonmessages.pb.cc'),

View File

@ -76,9 +76,12 @@ void CDataPack::ResetSize()
size_t CDataPack::CreateMemory(size_t size, void **addr)
{
CheckSize(sizeof(size_t) + size);
CheckSize(sizeof(char) + sizeof(size_t) + size);
size_t pos = m_curptr - m_pBase;
*(char *)m_curptr = Raw;
m_curptr += sizeof(char);
*(size_t *)m_curptr = size;
m_curptr += sizeof(size_t);
@ -88,14 +91,17 @@ size_t CDataPack::CreateMemory(size_t size, void **addr)
}
m_curptr += size;
m_size += sizeof(size_t) + size;
m_size += sizeof(char) + sizeof(size_t) + size;
return pos;
}
void CDataPack::PackCell(cell_t cell)
{
CheckSize(sizeof(size_t) + sizeof(cell_t));
CheckSize(sizeof(char) + sizeof(size_t) + sizeof(cell_t));
*(char *)m_curptr = Cell;
m_curptr += sizeof(char);
*(size_t *)m_curptr = sizeof(cell_t);
m_curptr += sizeof(size_t);
@ -103,12 +109,15 @@ void CDataPack::PackCell(cell_t cell)
*(cell_t *)m_curptr = cell;
m_curptr += sizeof(cell_t);
m_size += sizeof(size_t) + sizeof(cell_t);
m_size += sizeof(char) + sizeof(size_t) + sizeof(cell_t);
}
void CDataPack::PackFloat(float val)
{
CheckSize(sizeof(size_t) + sizeof(float));
CheckSize(sizeof(char) + sizeof(size_t) + sizeof(float));
*(char *)m_curptr = Float;
m_curptr += sizeof(char);
*(size_t *)m_curptr = sizeof(float);
m_curptr += sizeof(size_t);
@ -116,15 +125,18 @@ void CDataPack::PackFloat(float val)
*(float *)m_curptr = val;
m_curptr += sizeof(float);
m_size += sizeof(size_t) + sizeof(float);
m_size += sizeof(char) + sizeof(size_t) + sizeof(float);
}
void CDataPack::PackString(const char *string)
{
size_t len = strlen(string);
size_t maxsize = sizeof(size_t) + len + 1;
size_t maxsize = sizeof(char) + sizeof(size_t) + len + 1;
CheckSize(maxsize);
*(char *)m_curptr = String;
m_curptr += sizeof(char);
// Pack the string length first for buffer overrun checking.
*(size_t *)m_curptr = len;
m_curptr += sizeof(size_t);
@ -160,10 +172,16 @@ bool CDataPack::SetPosition(size_t pos) const
cell_t CDataPack::ReadCell() const
{
if (!IsReadable(sizeof(size_t) + sizeof(cell_t)))
if (!IsReadable(sizeof(char) + sizeof(size_t) + sizeof(cell_t)))
{
return 0;
}
if (*reinterpret_cast<char *>(m_curptr) != Cell)
{
return 0;
}
m_curptr += sizeof(char);
if (*reinterpret_cast<size_t *>(m_curptr) != sizeof(cell_t))
{
return 0;
@ -178,10 +196,16 @@ cell_t CDataPack::ReadCell() const
float CDataPack::ReadFloat() const
{
if (!IsReadable(sizeof(size_t) + sizeof(float)))
if (!IsReadable(sizeof(char) + sizeof(size_t) + sizeof(float)))
{
return 0;
}
if (*reinterpret_cast<char *>(m_curptr) != Float)
{
return 0;
}
m_curptr += sizeof(char);
if (*reinterpret_cast<size_t *>(m_curptr) != sizeof(float))
{
return 0;
@ -201,10 +225,15 @@ bool CDataPack::IsReadable(size_t bytes) const
const char *CDataPack::ReadString(size_t *len) const
{
if (!IsReadable(sizeof(size_t)))
if (!IsReadable(sizeof(char) + sizeof(size_t)))
{
return NULL;
}
if (*reinterpret_cast<char *>(m_curptr) != String)
{
return NULL;
}
m_curptr += sizeof(char);
size_t real_len = *(size_t *)m_curptr;
@ -237,6 +266,11 @@ void *CDataPack::ReadMemory(size_t *size) const
{
return NULL;
}
if (*reinterpret_cast<char *>(m_curptr) != Raw)
{
return NULL;
}
m_curptr += sizeof(char);
size_t bytecount = *(size_t *)m_curptr;
m_curptr += sizeof(size_t);
@ -257,3 +291,43 @@ void *CDataPack::ReadMemory(size_t *size) const
return ptr;
}
void CDataPack::PackFunction(cell_t function)
{
CheckSize(sizeof(char) + sizeof(size_t) + sizeof(cell_t));
*(char *)m_curptr = Function;
m_curptr += sizeof(char);
*(size_t *)m_curptr = sizeof(cell_t);
m_curptr += sizeof(size_t);
*(cell_t *)m_curptr = function;
m_curptr += sizeof(cell_t);
m_size += sizeof(char) + sizeof(size_t) + sizeof(cell_t);
}
cell_t CDataPack::ReadFunction() const
{
if (!IsReadable(sizeof(char) + sizeof(size_t) + sizeof(cell_t)))
{
return 0;
}
if (*reinterpret_cast<char *>(m_curptr) != Function)
{
return 0;
}
m_curptr += sizeof(char);
if (*reinterpret_cast<size_t *>(m_curptr) != sizeof(cell_t))
{
return 0;
}
m_curptr += sizeof(size_t);
cell_t val = *reinterpret_cast<cell_t *>(m_curptr);
m_curptr += sizeof(cell_t);
return val;
}

View File

@ -51,12 +51,14 @@ public: //IDataReader
const char *ReadString(size_t *len) const;
void *GetMemory() const;
void *ReadMemory(size_t *size) const;
cell_t ReadFunction() const;
public: //IDataPack
void ResetSize();
void PackCell(cell_t cell);
void PackFloat(float val);
void PackString(const char *string);
size_t CreateMemory(size_t size, void **addr);
void PackFunction(cell_t function);
public:
void Initialize();
private:
@ -66,6 +68,14 @@ private:
mutable char *m_curptr;
size_t m_capacity;
size_t m_size;
enum DataPackType {
Raw,
Cell,
Float,
String,
Function
};
};
#endif //_INCLUDE_SOURCEMOD_CDATAPACK_H_

View File

@ -383,7 +383,7 @@ bool ConCmdManager::AddAdminCommand(IPluginFunction *pFunction,
{
if (!m_CmdGrps.add(i, group))
return false;
i->value = NoAddRef(new CommandGroup());
i->value = new CommandGroup();
}
Ref<CommandGroup> cmdgroup = i->value;

View File

@ -648,8 +648,11 @@ QueryCvarCookie_t ConVarManager::QueryClientConVar(edict_t *pPlayer, const char
return InvalidQueryCvarCookie;
}
ConVarQuery query = {cookie, pCallback, (cell_t)hndl, IndexOfEdict(pPlayer)};
m_ConVarQueries.push_back(query);
if (pCallback != NULL)
{
ConVarQuery query = { cookie, pCallback, (cell_t) hndl, IndexOfEdict(pPlayer) };
m_ConVarQueries.push_back(query);
}
#endif
return cookie;
@ -753,6 +756,13 @@ void ConVarManager::OnQueryCvarValueFinished(QueryCvarCookie_t cookie, CEntityIn
void ConVarManager::OnQueryCvarValueFinished(QueryCvarCookie_t cookie, edict_t *pPlayer, EQueryCvarValueStatus result, const char *cvarName, const char *cvarValue)
#endif // SE_DOTA
{
#if SOURCE_ENGINE == SE_CSGO
if (g_Players.HandleConVarQuery(cookie, pPlayer, result, cvarName, cvarValue))
{
return;
}
#endif
IPluginFunction *pCallback = NULL;
cell_t value = 0;
List<ConVarQuery>::iterator iter;

View File

@ -195,7 +195,7 @@ class GenericCommandHooker : public IConCommandLinkListener
size_t index;
if (!FindVtable(vtable, index))
{
g_Logger.LogError("Console detour tried to unhook command \"%s\" but it wasn't found", pBase->GetName());
logger->LogError("Console detour tried to unhook command \"%s\" but it wasn't found", pBase->GetName());
return;
}
@ -219,7 +219,7 @@ public:
if (dispatch.thisptroffs < 0)
{
g_Logger.LogError("Command filter could not determine ConCommand layout");
logger->LogError("Command filter could not determine ConCommand layout");
return false;
}
@ -228,7 +228,7 @@ public:
if (!vtables.size())
{
g_Logger.LogError("Command filter could not find any cvars!");
logger->LogError("Command filter could not find any cvars!");
return false;
}

View File

@ -262,7 +262,7 @@ void CoreConfig::Initialize()
{
/* :TODO: This won't actually log or print anything :( - So fix that somehow */
const char *error = textparsers->GetSMCErrorString(err);
g_Logger.LogFatal("[SM] Error encountered parsing core config file: %s", error ? error : "");
logger->LogFatal("[SM] Error encountered parsing core config file: %s", error ? error : "");
}
}
@ -274,7 +274,7 @@ SMCResult CoreConfig::ReadSMC_KeyValue(const SMCStates *states, const char *key,
if (err == ConfigResult_Reject)
{
/* This is a fatal error */
g_Logger.LogFatal("Config error (key: %s) (value: %s) %s", key, value, error);
logger->LogFatal("Config error (key: %s) (value: %s) %s", key, value, error);
}
return SMCResult_Continue;
@ -469,7 +469,7 @@ bool SM_ExecuteConfig(IPlugin *pl, AutoConfig *cfg, bool can_create)
}
else
{
g_Logger.LogError("Failed to auto generate config for %s, make sure the directory has write permission.", pl->GetFilename());
logger->LogError("Failed to auto generate config for %s, make sure the directory has write permission.", pl->GetFilename());
return can_create;
}
}

View File

@ -155,7 +155,7 @@ void EventManager::FireGameEvent(IGameEvent *pEvent)
Just need to add ourselves as a listener to make our hook on IGameEventManager2::FireEvent work */
}
#if SOURCE_ENGINE >= SE_LEFT4DEAD
#if SOURCE_ENGINE >= SE_LEFT4DEAD && SOURCE_ENGINE != SE_DOTA
int EventManager::GetEventDebugID()
{
return EVENT_DEBUG_ID_INIT;

View File

@ -110,7 +110,7 @@ public: // IPluginsListener
void OnPluginUnloaded(IPlugin *plugin);
public: // IGameEventListener2
void FireGameEvent(IGameEvent *pEvent);
#if SOURCE_ENGINE >= SE_LEFT4DEAD
#if SOURCE_ENGINE >= SE_LEFT4DEAD && SOURCE_ENGINE != SE_DOTA
int GetEventDebugID();
#endif
public:

View File

@ -168,7 +168,7 @@ void CHalfLife2::InitLogicalEntData()
if (!addr)
{
// Key exists so notify if lookup fails, but try other method.
g_Logger.LogError("Failed lookup of gEntList directly - Reverting to lookup via LevelShutdown");
logger->LogError("Failed lookup of gEntList directly - Reverting to lookup via LevelShutdown");
}
else
{
@ -186,7 +186,7 @@ void CHalfLife2::InitLogicalEntData()
int offset;
if (!g_pGameConf->GetOffset("gEntList", &offset))
{
g_Logger.LogError("Logical Entities not supported by this mod (gEntList) - Reverting to networkable entities only");
logger->LogError("Logical Entities not supported by this mod (gEntList) - Reverting to networkable entities only");
return;
}
@ -198,7 +198,7 @@ void CHalfLife2::InitLogicalEntData()
// If we have g_EntList from either of the above methods, make sure we can get the offset from it to EntInfo as well
if (g_EntList && !g_pGameConf->GetOffset("EntInfo", &entInfoOffset))
{
g_Logger.LogError("Logical Entities not supported by this mod (EntInfo) - Reverting to networkable entities only");
logger->LogError("Logical Entities not supported by this mod (EntInfo) - Reverting to networkable entities only");
g_EntList = NULL;
return;
}
@ -211,7 +211,7 @@ void CHalfLife2::InitLogicalEntData()
if (!g_EntList && !g_pEntInfoList)
{
g_Logger.LogError("Failed lookup of gEntList - Reverting to networkable entities only");
logger->LogError("Failed lookup of gEntList - Reverting to networkable entities only");
return;
}
}
@ -225,7 +225,7 @@ void CHalfLife2::InitCommandLine()
ke::AutoPtr<ILibrary> lib(g_LibSys.OpenLibrary(TIER0_NAME, error, sizeof(error)));
if (lib == NULL)
{
g_Logger.LogError("Could not load %s: %s", TIER0_NAME, error);
logger->LogError("Could not load %s: %s", TIER0_NAME, error);
return;
}
@ -242,7 +242,7 @@ void CHalfLife2::InitCommandLine()
ke::AutoPtr<ILibrary> lib(g_LibSys.OpenLibrary(VSTDLIB_NAME, error, sizeof(error)));
if (lib == NULL)
{
g_Logger.LogError("Could not load %s: %s", VSTDLIB_NAME, error);
logger->LogError("Could not load %s: %s", VSTDLIB_NAME, error);
return;
}
@ -251,7 +251,7 @@ void CHalfLife2::InitCommandLine()
if (m_pGetCommandLine == NULL)
{
g_Logger.LogError("Could not locate any command line functionality");
logger->LogError("Could not locate any command line functionality");
}
}

View File

@ -39,61 +39,12 @@
#include "logic_bridge.h"
#include <sourcemod_version.h>
Logger g_Logger;
bool g_in_game_log_hook = false;
static LoggerCore g_LoggerCore;
SH_DECL_HOOK1_void(IVEngineServer, LogPrint, SH_NOATTRIB, false, const char *);
/**
* :TODO: This should be creating the log folder if it doesn't exist
*/
ConfigResult Logger::OnSourceModConfigChanged(const char *key,
const char *value,
ConfigSource source,
char *error,
size_t maxlength)
{
if (strcasecmp(key, "Logging") == 0)
{
bool state;
if (strcasecmp(value, "on") == 0)
{
state = true;
} else if (strcasecmp(value, "off") == 0) {
state = false;
} else {
UTIL_Format(error, maxlength, "Invalid value: must be \"on\" or \"off\"");
return ConfigResult_Reject;
}
if (source == ConfigSource_Console)
{
state ? EnableLogging() : DisableLogging();
} else {
m_InitialState = state;
}
return ConfigResult_Accept;
} else if (strcasecmp(key, "LogMode") == 0) {
if (strcasecmp(value, "daily") == 0)
{
m_Mode = LoggingMode_Daily;
} else if (strcasecmp(value, "map") == 0) {
m_Mode = LoggingMode_PerMap;
} else if (strcasecmp(value, "game") == 0) {
m_Mode = LoggingMode_Game;
} else {
UTIL_Format(error, maxlength, "Invalid value: must be [daily|map|game]");
return ConfigResult_Reject;
}
return ConfigResult_Accept;
}
return ConfigResult_Ignore;
}
static void HookLogPrint(const char *message)
{
g_in_game_log_hook = true;
@ -104,477 +55,16 @@ static void HookLogPrint(const char *message)
RETURN_META(MRES_SUPERCEDE);
}
void Logger::OnSourceModStartup(bool late)
void LoggerCore::OnSourceModStartup(bool late)
{
InitLogger(m_Mode);
SH_ADD_HOOK(IVEngineServer, LogPrint, engine, SH_STATIC(HookLogPrint), false);
}
void Logger::OnSourceModAllShutdown()
void LoggerCore::OnSourceModAllShutdown()
{
CloseLogger();
SH_REMOVE_HOOK(IVEngineServer, LogPrint, engine, SH_STATIC(HookLogPrint), false);
}
void Logger::OnSourceModLevelChange(const char *mapName)
{
MapChange(mapName);
}
void Logger::_NewMapFile()
{
if (!m_Active)
{
return;
}
/* Append "Log file closed" to previous log file */
_CloseFile();
char _filename[256];
int i = 0;
time_t t;
GetAdjustedTime(&t);
tm *curtime = localtime(&t);
while (true)
{
g_SourceMod.BuildPath(Path_SM, _filename, sizeof(_filename), "logs/L%02d%02d%03d.log", curtime->tm_mon + 1, curtime->tm_mday, i);
FILE *fp = fopen(_filename, "r");
if (!fp)
{
break;
}
fclose(fp);
i++;
}
m_NrmFileName.assign(_filename);
FILE *fp = fopen(m_NrmFileName.c_str(), "w");
if (!fp)
{
char error[255];
g_LibSys.GetPlatformError(error, sizeof(error));
LogFatal("[SM] Unexpected fatal logging error (file \"%s\")", m_NrmFileName.c_str());
LogFatal("[SM] Platform returned error: \"%s\"", error);
LogFatal("[SM] Logging has been disabled.");
m_Active = false;
return;
} else {
char date[32];
strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime);
fprintf(fp, "L %s: SourceMod log file started (file \"L%02d%02d%03d.log\") (Version \"%s\")\n", date, curtime->tm_mon + 1, curtime->tm_mday, i, SOURCEMOD_VERSION);
fclose(fp);
}
}
void Logger::_CloseFile()
{
if (!m_Active)
{
return;
}
FILE *fp = NULL;
if (!m_NrmFileName.empty())
{
fp = fopen(m_NrmFileName.c_str(), "r+");
if (fp)
{
fseek(fp, 0, SEEK_END);
LogMessage("Log file closed.");
fclose(fp);
}
m_NrmFileName.clear();
}
if (!m_ErrMapStart)
{
return;
}
fp = fopen(m_ErrFileName.c_str(), "r+");
if (fp)
{
fseek(fp, 0, SEEK_END);
LogError("Error log file session closed.");
fclose(fp);
}
m_ErrFileName.clear();
}
void Logger::InitLogger(LoggingMode mode)
{
m_Mode = mode;
m_Active = m_InitialState;
time_t t;
GetAdjustedTime(&t);
tm *curtime = localtime(&t);
m_NrmCurDay = curtime->tm_mday;
m_ErrCurDay = curtime->tm_mday;
char _filename[256];
g_SourceMod.BuildPath(Path_SM, _filename, sizeof(_filename), "logs/errors_%04d%02d%02d.log", curtime->tm_year + 1900, curtime->tm_mon + 1, curtime->tm_mday);
m_ErrFileName.assign(_filename);
switch (m_Mode)
{
case LoggingMode_PerMap:
{
if (!m_Active)
{
m_DelayedStart = true;
}
break;
}
case LoggingMode_Daily:
{
g_SourceMod.BuildPath(Path_SM, _filename, sizeof(_filename), "logs/L%04d%02d%02d.log", curtime->tm_year + 1900, curtime->tm_mon + 1, curtime->tm_mday);
m_NrmFileName.assign(_filename);
m_DailyPrintHdr = true;
break;
}
default:
{
/* do nothing... */
break;
}
}
}
void Logger::CloseLogger()
{
_CloseFile();
}
void Logger::LogToOpenFile(FILE *fp, const char *msg, ...)
{
if (!m_Active)
{
return;
}
va_list ap;
va_start(ap, msg);
LogToOpenFileEx(fp, msg, ap);
va_end(ap);
}
void Logger::LogToFileOnly(FILE *fp, const char *msg, ...)
{
if (!m_Active)
{
return;
}
va_list ap;
va_start(ap, msg);
LogToFileOnlyEx(fp, msg, ap);
va_end(ap);
}
void Logger::LogToOpenFileEx(FILE *fp, const char *msg, va_list ap)
{
if (!m_Active)
{
return;
}
static ConVar *sv_logecho = icvar->FindVar("sv_logecho");
char buffer[3072];
UTIL_FormatArgs(buffer, sizeof(buffer), msg, ap);
char date[32];
time_t t;
GetAdjustedTime(&t);
tm *curtime = localtime(&t);
strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime);
fprintf(fp, "L %s: %s\n", date, buffer);
if (!sv_logecho || sv_logecho->GetBool())
{
g_SMAPI->ConPrintf("L %s: %s\n", date, buffer);
}
}
void Logger::LogToFileOnlyEx(FILE *fp, const char *msg, va_list ap)
{
if (!m_Active)
{
return;
}
char buffer[3072];
UTIL_FormatArgs(buffer, sizeof(buffer), msg, ap);
char date[32];
time_t t;
GetAdjustedTime(&t);
tm *curtime = localtime(&t);
strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime);
fprintf(fp, "L %s: %s\n", date, buffer);
fflush(fp);
}
void Logger::LogMessage(const char *vafmt, ...)
{
va_list ap;
va_start(ap, vafmt);
LogMessageEx(vafmt, ap);
va_end(ap);
}
void Logger::LogMessageEx(const char *vafmt, va_list ap)
{
if (!m_Active)
{
return;
}
if (m_Mode == LoggingMode_Game)
{
_PrintToGameLog(vafmt, ap);
return;
}
if (m_DelayedStart)
{
m_DelayedStart = false;
_NewMapFile();
}
time_t t;
GetAdjustedTime(&t);
tm *curtime = localtime(&t);
FILE *fp = NULL;
if (m_Mode == LoggingMode_PerMap)
{
fp = fopen(m_NrmFileName.c_str(), "a+");
if (!fp)
{
_NewMapFile();
fp = fopen(m_NrmFileName.c_str(), "a+");
if (!fp)
{
goto print_error;
}
}
} else {
if (m_NrmCurDay != curtime->tm_mday)
{
char _filename[256];
g_SourceMod.BuildPath(Path_SM, _filename, sizeof(_filename), "logs/L%04d%02d%02d.log", curtime->tm_year + 1900, curtime->tm_mon + 1, curtime->tm_mday);
m_NrmFileName.assign(_filename);
m_NrmCurDay = curtime->tm_mday;
m_DailyPrintHdr = true;
}
fp = fopen(m_NrmFileName.c_str(), "a+");
}
if (fp)
{
if (m_DailyPrintHdr)
{
char date[32];
m_DailyPrintHdr = false;
strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime);
fprintf(fp, "L %s: SourceMod log file session started (file \"L%04d%02d%02d.log\") (Version \"%s\")\n", date, curtime->tm_year + 1900, curtime->tm_mon + 1, curtime->tm_mday, SOURCEMOD_VERSION);
}
LogToOpenFileEx(fp, vafmt, ap);
fclose(fp);
} else {
goto print_error;
}
return;
print_error:
char error[255];
g_LibSys.GetPlatformError(error, sizeof(error));
LogFatal("[SM] Unexpected fatal logging error (file \"%s\")", m_NrmFileName.c_str());
LogFatal("[SM] Platform returned error: \"%s\"", error);
LogFatal("[SM] Logging has been disabled.");
m_Active = false;
}
void Logger::LogError(const char *vafmt, ...)
{
va_list ap;
va_start(ap, vafmt);
LogErrorEx(vafmt, ap);
va_end(ap);
}
void Logger::LogErrorEx(const char *vafmt, va_list ap)
{
if (!m_Active)
{
return;
}
time_t t;
GetAdjustedTime(&t);
tm *curtime = localtime(&t);
if (curtime->tm_mday != m_ErrCurDay)
{
char _filename[256];
g_SourceMod.BuildPath(Path_SM, _filename, sizeof(_filename), "logs/errors_%04d%02d%02d.log", curtime->tm_year + 1900, curtime->tm_mon + 1, curtime->tm_mday);
m_ErrFileName.assign(_filename);
m_ErrCurDay = curtime->tm_mday;
m_ErrMapStart = false;
}
FILE *fp = fopen(m_ErrFileName.c_str(), "a+");
if (fp)
{
if (!m_ErrMapStart)
{
char date[32];
strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime);
fprintf(fp, "L %s: SourceMod error session started\n", date);
fprintf(fp, "L %s: Info (map \"%s\") (file \"errors_%04d%02d%02d.log\")\n", date, m_CurMapName.c_str(), curtime->tm_year + 1900, curtime->tm_mon + 1, curtime->tm_mday);
m_ErrMapStart = true;
}
LogToOpenFileEx(fp, vafmt, ap);
fclose(fp);
}
else
{
char error[255];
g_LibSys.GetPlatformError(error, sizeof(error));
LogFatal("[SM] Unexpected fatal logging error (file \"%s\")", m_NrmFileName.c_str());
LogFatal("[SM] Platform returned error: \"%s\"", error);
LogFatal("[SM] Logging has been disabled.");
m_Active = false;
return;
}
}
void Logger::MapChange(const char *mapname)
{
m_CurMapName.assign(mapname);
switch (m_Mode)
{
case LoggingMode_Daily:
{
LogMessage("-------- Mapchange to %s --------", mapname);
break;
}
case LoggingMode_PerMap:
{
_NewMapFile();
break;
}
default:
{
/* Do nothing... */
break;
}
}
if (m_ErrMapStart)
{
LogError("Error log file session closed.");
}
m_ErrMapStart = false;
}
void Logger::_PrintToGameLog(const char *fmt, va_list ap)
{
char msg[3072];
size_t len;
len = vsnprintf(msg, sizeof(msg)-2, fmt, ap);
len = (len >= sizeof(msg)) ? (sizeof(msg) - 2) : len;
msg[len++] = '\n';
msg[len] = '\0';
Engine_LogPrintWrapper(msg);
}
const char *Logger::GetLogFileName(LogType type) const
{
switch (type)
{
case LogType_Normal:
{
return m_NrmFileName.c_str();
}
case LogType_Error:
{
return m_ErrFileName.c_str();
}
default:
{
return "";
}
}
}
LoggingMode Logger::GetLoggingMode() const
{
return m_Mode;
}
void Logger::EnableLogging()
{
if (m_Active)
{
return;
}
m_Active = true;
LogMessage("[SM] Logging enabled manually by user.");
}
void Logger::DisableLogging()
{
if (!m_Active)
{
return;
}
LogMessage("[SM] Logging disabled manually by user.");
m_Active = false;
}
void Logger::LogFatal(const char *msg, ...)
{
va_list ap;
va_start(ap, msg);
LogFatalEx(msg, ap);
va_end(ap);
}
void Logger::LogFatalEx(const char *msg, va_list ap)
{
/* :TODO: make this print all pretty-like
* In fact, the pretty log printing function should be abstracted.
* It's already implemented twice which is bad.
*/
char path[PLATFORM_MAX_PATH];
g_SourceMod.BuildPath(Path_Game, path, sizeof(path), "sourcemod_fatal.log");
FILE *fp = fopen(path, "at");
if (fp)
{
m_Active = true;
LogToOpenFileEx(fp, msg, ap);
m_Active = false;
fclose(fp);
}
}
bool g_in_game_log_hook = false;
void Engine_LogPrintWrapper(const char *msg)
{
if (g_in_game_log_hook)

View File

@ -38,76 +38,13 @@
using namespace SourceHook;
enum LogType
class LoggerCore : public SMGlobalClass
{
LogType_Normal,
LogType_Error
};
enum LoggingMode
{
LoggingMode_Daily,
LoggingMode_PerMap,
LoggingMode_Game
};
class Logger : public SMGlobalClass
{
public:
Logger() : m_Mode(LoggingMode_Daily), m_ErrMapStart(false),
m_Active(false), m_DelayedStart(false), m_DailyPrintHdr(false),
m_InitialState(true)
{
}
public: //SMGlobalClass
ConfigResult OnSourceModConfigChanged(const char *key,
const char *value,
ConfigSource source,
char *error,
size_t maxlength);
void OnSourceModStartup(bool late);
void OnSourceModAllShutdown();
void OnSourceModLevelChange(const char *mapName);
public:
void InitLogger(LoggingMode mode);
void CloseLogger();
void EnableLogging();
void DisableLogging();
void LogMessage(const char *msg, ...);
void LogMessageEx(const char *msg, va_list ap);
void LogError(const char *msg, ...);
void LogErrorEx(const char *msg, va_list ap);
void LogFatal(const char *msg, ...);
void LogFatalEx(const char *msg, va_list ap);
void LogToOpenFile(FILE *fp, const char *msg, ...);
void LogToOpenFileEx(FILE *fp, const char *msg, va_list ap);
/* This version does not print to console, and is thus thread-safe */
void LogToFileOnly(FILE *fp, const char *msg, ...);
void LogToFileOnlyEx(FILE *fp, const char *msg, va_list ap);
void MapChange(const char *mapname);
const char *GetLogFileName(LogType type) const;
LoggingMode GetLoggingMode() const;
private:
void _CloseFile();
void _NewMapFile();
void _PrintToGameLog(const char *fmt, va_list ap);
private:
String m_NrmFileName;
String m_ErrFileName;
String m_CurMapName;
LoggingMode m_Mode;
int m_NrmCurDay;
int m_ErrCurDay;
bool m_ErrMapStart;
bool m_Active;
bool m_DelayedStart;
bool m_DailyPrintHdr;
bool m_InitialState;
};
void Engine_LogPrintWrapper(const char *msg);
extern bool g_in_game_log_hook;
extern Logger g_Logger;
#endif // _INCLUDE_SOURCEMOD_CLOGGER_H_

View File

@ -36,6 +36,7 @@
#include "sm_stringutil.h"
#include "sourcehook.h"
#include "sm_srvcmds.h"
#include "logic_bridge.h"
NextMapManager g_NextMap;
@ -130,7 +131,7 @@ void NextMapManager::HookChangeLevel(const char *map, const char *unknown, const
{
if (g_forcedChange)
{
g_Logger.LogMessage("[SM] Changed map to \"%s\"", map);
logger->LogMessage("[SM] Changed map to \"%s\"", map);
RETURN_META(MRES_IGNORED);
}
@ -141,7 +142,7 @@ void NextMapManager::HookChangeLevel(const char *map, const char *unknown, const
RETURN_META(MRES_IGNORED);
}
g_Logger.LogMessage("[SM] Changed map to \"%s\"", newmap);
logger->LogMessage("[SM] Changed map to \"%s\"", newmap);
UTIL_Format(m_tempChangeInfo.m_mapName, sizeof(m_tempChangeInfo.m_mapName), newmap);
UTIL_Format(m_tempChangeInfo.m_changeReason, sizeof(m_tempChangeInfo.m_changeReason), "Normal level change");

View File

@ -502,6 +502,9 @@ bool PlayerManager::OnClientConnect(edict_t *pEntity, const char *pszName, const
/* Get the client's language */
if (m_QueryLang)
{
#if SOURCE_ENGINE == SE_CSGO
pPlayer->m_LangId = translator->GetServerLanguage();
#else
const char *name;
if (!pPlayer->IsFakeClient() && (name=engine->GetClientConVarValue(client, "cl_language")))
{
@ -510,6 +513,7 @@ bool PlayerManager::OnClientConnect(edict_t *pEntity, const char *pszName, const
} else {
pPlayer->m_LangId = translator->GetServerLanguage();
}
#endif
}
List<IClientListener *>::iterator iter;
@ -727,6 +731,13 @@ void PlayerManager::OnClientPutInServer(edict_t *pEntity, const char *playername
}
pPlayer->Authorize_Post();
}
#if SOURCE_ENGINE == SE_CSGO
else
{
// Not a bot
pPlayer->m_LanguageCookie = g_ConVarManager.QueryClientConVar(pEntity, "cl_language", NULL, 0);
}
#endif
if (playerinfo)
{
@ -1227,7 +1238,7 @@ void PlayerManager::OnClientSettingsChanged(edict_t *pEntity)
if ((networkid_force = engine->GetClientConVarValue(client, "networkid_force")) && networkid_force[0] != '\0')
{
unsigned int accountId = pPlayer->GetSteamAccountID();
g_Logger.LogMessage("\"%s<%d><STEAM_1:%d:%d><>\" has bad networkid (id \"%s\") (ip \"%s\")",
logger->LogMessage("\"%s<%d><STEAM_1:%d:%d><>\" has bad networkid (id \"%s\") (ip \"%s\")",
new_name, pPlayer->GetUserId(), accountId & 1, accountId >> 1, networkid_force, pPlayer->GetIPAddress());
pPlayer->Kick("NetworkID spoofing detected.");
@ -1862,6 +1873,24 @@ void CmdMaxplayersCallback()
g_Players.MaxPlayersChanged();
}
#if SOURCE_ENGINE == SE_CSGO
bool PlayerManager::HandleConVarQuery(QueryCvarCookie_t cookie, edict_t *pPlayer, EQueryCvarValueStatus result, const char *cvarName, const char *cvarValue)
{
for (int i = 1; i <= m_maxClients; i++)
{
if (m_Players[i].m_LanguageCookie == cookie)
{
unsigned int langid;
m_Players[i].m_LangId = (translator->GetLanguageByName(cvarValue, &langid)) ? langid : translator->GetServerLanguage();
return true;
}
}
return false;
}
#endif
/*******************
*** PLAYER CODE ***
@ -1886,6 +1915,9 @@ CPlayer::CPlayer()
m_bIsReplay = false;
m_Serial.value = -1;
m_SteamAccountID = 0;
#if SOURCE_ENGINE == SE_CSGO
m_LanguageCookie = InvalidQueryCvarCookie;
#endif
}
void CPlayer::Initialize(const char *name, const char *ip, edict_t *pEntity)
@ -1966,6 +1998,9 @@ void CPlayer::Disconnect()
m_bIsReplay = false;
m_Serial.value = -1;
m_SteamAccountID = 0;
#if SOURCE_ENGINE == SE_CSGO
m_LanguageCookie = InvalidQueryCvarCookie;
#endif
}
void CPlayer::SetName(const char *name)

View File

@ -131,6 +131,9 @@ private:
bool m_bIsReplay;
serial_t m_Serial;
unsigned int m_SteamAccountID;
#if SOURCE_ENGINE == SE_CSGO
QueryCvarCookie_t m_LanguageCookie;
#endif
};
class PlayerManager :
@ -211,6 +214,9 @@ public:
unsigned int GetReplyTo();
unsigned int SetReplyTo(unsigned int reply);
void MaxPlayersChanged(int newvalue = -1);
#if SOURCE_ENGINE == SE_CSGO
bool HandleConVarQuery(QueryCvarCookie_t cookie, edict_t *pPlayer, EQueryCvarValueStatus result, const char *cvarName, const char *cvarValue);
#endif
private:
#if SOURCE_ENGINE == SE_DOTA
void OnServerActivate();

View File

@ -66,6 +66,8 @@ binary.sources += [
'sm_trie.cpp',
'smn_console.cpp',
'ProfileTools.cpp',
'Logger.cpp',
'smn_core.cpp',
]
if builder.target_platform == 'windows':
binary.sources += ['thread/WinThreads.cpp']

View File

@ -198,11 +198,11 @@ private:
if (!m_bFileNameLogged)
{
smcore.LogError("[SM] Parse error(s) detected in file \"%s\":", m_File);
logger->LogError("[SM] Parse error(s) detected in file \"%s\":", m_File);
m_bFileNameLogged = true;
}
smcore.LogError("[SM] (Line %d): %s", states ? states->line : 0, buffer);
logger->LogError("[SM] (Line %d): %s", states ? states->line : 0, buffer);
}
private:
bool m_bFileNameLogged;

View File

@ -89,11 +89,11 @@ void DBManager::OnSourceModLevelChange(const char *mapName)
ke::AutoLock lock(&m_ConfigLock);
if ((err = textparsers->ParseFile_SMC(m_Filename, this, &states)) != SMCError_Okay)
{
smcore.LogError("[SM] Detected parse error(s) in file \"%s\"", m_Filename);
logger->LogError("[SM] Detected parse error(s) in file \"%s\"", m_Filename);
if (err != SMCError_Custom)
{
const char *txt = textparsers->GetSMCErrorString(err);
smcore.LogError("[SM] Line %d: %s", states.line, txt);
logger->LogError("[SM] Line %d: %s", states.line, txt);
}
}
}
@ -541,7 +541,7 @@ bool DBManager::AddToThreadQueue(IDBThreadOperation *op, PrioQueueLevel prio)
{
if (!s_OneTimeThreaderErrorMsg)
{
smcore.LogError("[SM] Unable to create db threader (error unknown)");
logger->LogError("[SM] Unable to create db threader (error unknown)");
s_OneTimeThreaderErrorMsg = true;
}
m_Worker = NULL;

View File

@ -32,6 +32,7 @@
#include <IPluginSys.h>
#include <stdarg.h>
#include "DebugReporter.h"
#include "Logger.h"
DebugReport g_DbgReporter;
@ -49,7 +50,7 @@ void DebugReport::OnDebugSpew(const char *msg, ...)
smcore.FormatArgs(buffer, sizeof(buffer), msg, ap);
va_end(ap);
smcore.Log("[SM] %s", buffer);
g_Logger.LogMessage("[SM] %s", buffer);
}
void DebugReport::GenerateError(IPluginContext *ctx, cell_t func_idx, int err, const char *message, ...)
@ -71,12 +72,12 @@ void DebugReport::GenerateErrorVA(IPluginContext *ctx, cell_t func_idx, int err,
if (error)
{
smcore.LogError("[SM] Plugin \"%s\" encountered error %d: %s", plname, err, error);
g_Logger.LogError("[SM] Plugin \"%s\" encountered error %d: %s", plname, err, error);
} else {
smcore.LogError("[SM] Plugin \"%s\" encountered unknown error %d", plname, err);
g_Logger.LogError("[SM] Plugin \"%s\" encountered unknown error %d", plname, err);
}
smcore.LogError("[SM] %s", buffer);
g_Logger.LogError("[SM] %s", buffer);
if (func_idx != -1)
{
@ -86,7 +87,7 @@ void DebugReport::GenerateErrorVA(IPluginContext *ctx, cell_t func_idx, int err,
sp_public_t *function;
if (ctx->GetRuntime()->GetPublicByIndex(func_idx, &function) == SP_ERROR_NONE)
{
smcore.LogError("[SM] Unable to call function \"%s\" due to above error(s).", function->name);
g_Logger.LogError("[SM] Unable to call function \"%s\" due to above error(s).", function->name);
}
}
}
@ -106,18 +107,18 @@ void DebugReport::GenerateCodeError(IPluginContext *pContext, uint32_t code_addr
if (error)
{
smcore.LogError("[SM] Plugin \"%s\" encountered error %d: %s", plname, err, error);
g_Logger.LogError("[SM] Plugin \"%s\" encountered error %d: %s", plname, err, error);
} else {
smcore.LogError("[SM] Plugin \"%s\" encountered unknown error %d", plname, err);
g_Logger.LogError("[SM] Plugin \"%s\" encountered unknown error %d", plname, err);
}
smcore.LogError("[SM] %s", buffer);
g_Logger.LogError("[SM] %s", buffer);
IPluginDebugInfo *pDebug;
if ((pDebug = pContext->GetRuntime()->GetDebugInfo()) == NULL)
{
smcore.LogError("[SM] Debug mode is not enabled for \"%s\"", plname);
smcore.LogError("[SM] To enable debug mode, edit plugin_settings.cfg, or type: sm plugins debug %d on",
g_Logger.LogError("[SM] Debug mode is not enabled for \"%s\"", plname);
g_Logger.LogError("[SM] To enable debug mode, edit plugin_settings.cfg, or type: sm plugins debug %d on",
_GetPluginIndex(pContext));
return;
}
@ -125,9 +126,9 @@ void DebugReport::GenerateCodeError(IPluginContext *pContext, uint32_t code_addr
const char *name;
if (pDebug->LookupFunction(code_addr, &name) == SP_ERROR_NONE)
{
smcore.LogError("[SM] Unable to call function \"%s\" due to above error(s).", name);
g_Logger.LogError("[SM] Unable to call function \"%s\" due to above error(s).", name);
} else {
smcore.LogError("[SM] Unable to call function (name unknown, address \"%x\").", code_addr);
g_Logger.LogError("[SM] Unable to call function (name unknown, address \"%x\").", code_addr);
}
}
@ -139,7 +140,7 @@ void DebugReport::OnContextExecuteError(IPluginContext *ctx, IContextTrace *erro
if (n_err != SP_ERROR_NATIVE)
{
smcore.LogError("[SM] Plugin encountered error %d: %s",
g_Logger.LogError("[SM] Plugin encountered error %d: %s",
n_err,
error->GetErrorString());
}
@ -149,26 +150,26 @@ void DebugReport::OnContextExecuteError(IPluginContext *ctx, IContextTrace *erro
const char *custerr;
if ((custerr=error->GetCustomErrorString()) != NULL)
{
smcore.LogError("[SM] Native \"%s\" reported: %s", lastname, custerr);
g_Logger.LogError("[SM] Native \"%s\" reported: %s", lastname, custerr);
} else {
smcore.LogError("[SM] Native \"%s\" encountered a generic error.", lastname);
g_Logger.LogError("[SM] Native \"%s\" encountered a generic error.", lastname);
}
}
if (!error->DebugInfoAvailable())
{
smcore.LogError("[SM] Debug mode is not enabled for \"%s\"", plname);
smcore.LogError("[SM] To enable debug mode, edit plugin_settings.cfg, or type: sm plugins debug %d on",
g_Logger.LogError("[SM] Debug mode is not enabled for \"%s\"", plname);
g_Logger.LogError("[SM] To enable debug mode, edit plugin_settings.cfg, or type: sm plugins debug %d on",
_GetPluginIndex(ctx));
return;
}
CallStackInfo stk_info;
int i = 0;
smcore.LogError("[SM] Displaying call stack trace for plugin \"%s\":", plname);
g_Logger.LogError("[SM] Displaying call stack trace for plugin \"%s\":", plname);
while (error->GetTraceInfo(&stk_info))
{
smcore.LogError("[SM] [%d] Line %d, %s::%s()",
g_Logger.LogError("[SM] [%d] Line %d, %s::%s()",
i++,
stk_info.line,
stk_info.filename,

View File

@ -606,7 +606,7 @@ IExtension *CExtensionManager::LoadAutoExtension(const char *path, bool bErrorOn
{
if (bErrorOnMissing || libsys->IsPathFile(p->GetPath()))
{
smcore.LogError("[SM] Unable to load extension \"%s\": %s", path, error);
logger->LogError("[SM] Unable to load extension \"%s\": %s", path, error);
}
p->SetError(error);
@ -1360,6 +1360,24 @@ void CExtensionManager::CallOnCoreMapStart(edict_t *pEdictList, int edictCount,
}
}
void CExtensionManager::CallOnCoreMapEnd()
{
IExtensionInterface *pAPI;
List<CExtension *>::iterator iter;
for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++)
{
if ((pAPI = (*iter)->GetAPI()) == NULL)
{
continue;
}
if (pAPI->GetExtensionVersion() > 7)
{
pAPI->OnCoreMapEnd();
}
}
}
const CVector<IExtension *> *CExtensionManager::ListExtensions()
{
CVector<IExtension *> *list = new CVector<IExtension *>();

View File

@ -173,6 +173,7 @@ public:
void AddLibrary(IExtension *pSource, const char *library);
bool LibraryExists(const char *library);
void CallOnCoreMapStart(edict_t *pEdictList, int edictCount, int clientMax);
void CallOnCoreMapEnd();
void AddRawDependency(IExtension *ext, IdentityToken_t *other, void *iface);
const CVector<IExtension *> *ListExtensions();
void FreeExtensionList(const CVector<IExtension *> *list);

View File

@ -301,8 +301,8 @@ SMCResult CGameConfig::ReadSMC_NewSection(const SMCStates *states, const char *n
if (error[0] != '\0')
{
m_IgnoreLevel = 1;
smcore.LogError("[SM] Error while parsing CRC section for \"%s\" (%s):", m_Game, m_CurFile);
smcore.LogError("[SM] %s", error);
logger->LogError("[SM] Error while parsing CRC section for \"%s\" (%s):", m_Game, m_CurFile);
logger->LogError("[SM] %s", error);
} else {
m_ParseState = PSTATE_GAMEDEFS_CRC_BINARY;
}
@ -335,8 +335,8 @@ SMCResult CGameConfig::ReadSMC_NewSection(const SMCStates *states, const char *n
{
if (strcmp(name, "linux") != 0 && strcmp(name, "windows") != 0 && strcmp(name, "mac") != 0)
{
smcore.LogError("[SM] Error while parsing Address section for \"%s\" (%s):", m_Address, m_CurFile);
smcore.LogError("[SM] Unrecognized platform \"%s\"", name);
logger->LogError("[SM] Error while parsing Address section for \"%s\" (%s):", m_Address, m_CurFile);
logger->LogError("[SM] Unrecognized platform \"%s\"", name);
}
m_IgnoreLevel = 1;
}
@ -435,7 +435,7 @@ SMCResult CGameConfig::ReadSMC_KeyValue(const SMCStates *states, const char *key
}
else
{
smcore.LogError("[SM] Error parsing Address \"%s\", does not support more than %d read offsets (gameconf \"%s\")", m_Address, limit, m_CurFile);
logger->LogError("[SM] Error parsing Address \"%s\", does not support more than %d read offsets (gameconf \"%s\")", m_Address, limit, m_CurFile);
}
} else if (strcmp(key, "signature") == 0) {
strncopy(m_AddressSignature, value, sizeof(m_AddressSignature));
@ -503,7 +503,7 @@ SMCResult CGameConfig::ReadSMC_LeavingSection(const SMCStates *states)
if (((strcmp(m_Game, "*") != 0) && strcmp(m_Game, "#default") != 0)
&& (!m_Offsets.retrieve(m_offset)))
{
smcore.LogError("[SM] Unable to find property %s.%s (file \"%s\") (mod \"%s\")",
logger->LogError("[SM] Unable to find property %s.%s (file \"%s\") (mod \"%s\")",
m_Class,
m_Prop,
m_CurFile,
@ -556,7 +556,7 @@ SMCResult CGameConfig::ReadSMC_LeavingSection(const SMCStates *states)
void *final_addr = NULL;
if (addrInBase == NULL)
{
smcore.LogError("[SM] Unrecognized library \"%s\" (gameconf \"%s\")",
logger->LogError("[SM] Unrecognized library \"%s\" (gameconf \"%s\")",
s_TempSig.library,
m_CurFile);
}
@ -570,7 +570,7 @@ SMCResult CGameConfig::ReadSMC_LeavingSection(const SMCStates *states)
if (VirtualQuery(addrInBase, &mem, sizeof(mem)))
final_addr = g_MemUtils.ResolveSymbol(mem.AllocationBase, &s_TempSig.sig[1]);
else
smcore.LogError("[SM] Unable to find library \"%s\" in memory (gameconf \"%s\")", s_TempSig.library, m_File);
logger->LogError("[SM] Unable to find library \"%s\" in memory (gameconf \"%s\")", s_TempSig.library, m_File);
#elif defined PLATFORM_POSIX
Dl_info info;
/* GNU only: returns 0 on error, inconsistent! >:[ */
@ -585,12 +585,12 @@ SMCResult CGameConfig::ReadSMC_LeavingSection(const SMCStates *states)
final_addr = dlsym(handle, &s_TempSig.sig[1]);
dlclose(handle);
} else {
smcore.LogError("[SM] Unable to load library \"%s\" (gameconf \"%s\")",
logger->LogError("[SM] Unable to load library \"%s\" (gameconf \"%s\")",
s_TempSig.library,
m_File);
}
} else {
smcore.LogError("[SM] Unable to find library \"%s\" in memory (gameconf \"%s\")",
logger->LogError("[SM] Unable to find library \"%s\" in memory (gameconf \"%s\")",
s_TempSig.library,
m_File);
}
@ -827,8 +827,8 @@ bool CGameConfig::Reparse(char *error, size_t maxlength)
{
const char *msg = textparsers->GetSMCErrorString(err);
smcore.LogError("[SM] Error parsing master gameconf file \"%s\":", path);
smcore.LogError("[SM] Error %d on line %d, col %d: %s",
logger->LogError("[SM] Error parsing master gameconf file \"%s\":", path);
logger->LogError("[SM] Error %d on line %d, col %d: %s",
err,
state.line,
state.col,
@ -915,8 +915,8 @@ bool CGameConfig::EnterFile(const char *file, char *error, size_t maxlength)
{
const char *msg = textparsers->GetSMCErrorString(err);
smcore.LogError("[SM] Error parsing gameconfig file \"%s\":", m_CurFile);
smcore.LogError("[SM] Error %d on line %d, col %d: %s",
logger->LogError("[SM] Error parsing gameconfig file \"%s\":", m_CurFile);
logger->LogError("[SM] Error %d on line %d, col %d: %s",
err,
state.line,
state.col,
@ -1082,6 +1082,7 @@ bool GameConfigManager::LoadGameConfigFile(const char *file, IGameConfig **_pCon
}
pConfig = new CGameConfig(file);
pConfig->AddRef();
/* :HACKHACK: Don't parse the main config file */
bool retval = true;

View File

@ -957,8 +957,8 @@ bool HandleSystem::InitAccessDefaults(TypeAccess *pTypeAccess, HandleAccess *pHa
}
#define HANDLE_LOG_VERY_BAD(message, ...) \
smcore.LogFatal(message, ##__VA_ARGS__); \
smcore.LogError(message, ##__VA_ARGS__);
logger->LogFatal(message, ##__VA_ARGS__); \
logger->LogError(message, ##__VA_ARGS__);
bool HandleSystem::TryAndFreeSomeHandles()
{

551
core/logic/Logger.cpp Normal file
View File

@ -0,0 +1,551 @@
/**
* vim: set ts=4 sw=4 :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2009 AlliedModders LLC. All rights reserved.
* =============================================================================
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 3.0, as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
* As a special exception, AlliedModders LLC gives you permission to link the
* code of this program (as well as its derivative works) to "Half-Life 2," the
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
* by the Valve Corporation. You must obey the GNU General Public License in
* all respects for all other code used. Additionally, AlliedModders LLC grants
* this exception to all derivative works. AlliedModders LLC defines further
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
* or <http://www.sourcemod.net/license.php>.
*
* Version: $Id$
*/
#include <time.h>
#include <cstdarg>
#include "Logger.h"
#include <sourcemod_version.h>
#include <ISourceMod.h>
Logger g_Logger;
/**
* :TODO: This should be creating the log folder if it doesn't exist
*/
ConfigResult Logger::OnSourceModConfigChanged(const char *key,
const char *value,
ConfigSource source,
char *error,
size_t maxlength)
{
if (strcasecmp(key, "Logging") == 0)
{
bool state;
if (strcasecmp(value, "on") == 0)
{
state = true;
} else if (strcasecmp(value, "off") == 0) {
state = false;
} else {
smcore.Format(error, maxlength, "Invalid value: must be \"on\" or \"off\"");
return ConfigResult_Reject;
}
if (source == ConfigSource_Console)
{
state ? EnableLogging() : DisableLogging();
} else {
m_InitialState = state;
}
return ConfigResult_Accept;
} else if (strcasecmp(key, "LogMode") == 0) {
if (strcasecmp(value, "daily") == 0)
{
m_Mode = LoggingMode_Daily;
} else if (strcasecmp(value, "map") == 0) {
m_Mode = LoggingMode_PerMap;
} else if (strcasecmp(value, "game") == 0) {
m_Mode = LoggingMode_Game;
} else {
smcore.Format(error, maxlength, "Invalid value: must be [daily|map|game]");
return ConfigResult_Reject;
}
return ConfigResult_Accept;
}
return ConfigResult_Ignore;
}
void Logger::OnSourceModStartup(bool late)
{
InitLogger(m_Mode);
}
void Logger::OnSourceModAllShutdown()
{
CloseLogger();
}
void Logger::OnSourceModLevelChange(const char *mapName)
{
MapChange(mapName);
}
void Logger::_NewMapFile()
{
if (!m_Active)
{
return;
}
/* Append "Log file closed" to previous log file */
_CloseFile();
char _filename[256];
int i = 0;
time_t t = g_pSM->GetAdjustedTime();
tm *curtime = localtime(&t);
while (true)
{
g_pSM->BuildPath(Path_SM, _filename, sizeof(_filename), "logs/L%02d%02d%03d.log", curtime->tm_mon + 1, curtime->tm_mday, i);
FILE *fp = fopen(_filename, "r");
if (!fp)
{
break;
}
fclose(fp);
i++;
}
m_NrmFileName.assign(_filename);
FILE *fp = fopen(m_NrmFileName.c_str(), "w");
if (!fp)
{
char error[255];
libsys->GetPlatformError(error, sizeof(error));
LogFatal("[SM] Unexpected fatal logging error (file \"%s\")", m_NrmFileName.c_str());
LogFatal("[SM] Platform returned error: \"%s\"", error);
LogFatal("[SM] Logging has been disabled.");
m_Active = false;
return;
} else {
char date[32];
strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime);
fprintf(fp, "L %s: SourceMod log file started (file \"L%02d%02d%03d.log\") (Version \"%s\")\n", date, curtime->tm_mon + 1, curtime->tm_mday, i, SOURCEMOD_VERSION);
fclose(fp);
}
}
void Logger::_CloseFile()
{
if (!m_Active)
{
return;
}
FILE *fp = NULL;
if (!m_NrmFileName.empty())
{
fp = fopen(m_NrmFileName.c_str(), "r+");
if (fp)
{
fseek(fp, 0, SEEK_END);
LogMessage("Log file closed.");
fclose(fp);
}
m_NrmFileName.clear();
}
if (!m_ErrMapStart)
{
return;
}
fp = fopen(m_ErrFileName.c_str(), "r+");
if (fp)
{
fseek(fp, 0, SEEK_END);
LogError("Error log file session closed.");
fclose(fp);
}
m_ErrFileName.clear();
}
void Logger::InitLogger(LoggingMode mode)
{
m_Mode = mode;
m_Active = m_InitialState;
time_t t = g_pSM->GetAdjustedTime();
tm *curtime = localtime(&t);
m_NrmCurDay = curtime->tm_mday;
m_ErrCurDay = curtime->tm_mday;
char _filename[256];
g_pSM->BuildPath(Path_SM, _filename, sizeof(_filename), "logs/errors_%04d%02d%02d.log", curtime->tm_year + 1900, curtime->tm_mon + 1, curtime->tm_mday);
m_ErrFileName.assign(_filename);
switch (m_Mode)
{
case LoggingMode_PerMap:
{
if (!m_Active)
{
m_DelayedStart = true;
}
break;
}
case LoggingMode_Daily:
{
g_pSM->BuildPath(Path_SM, _filename, sizeof(_filename), "logs/L%04d%02d%02d.log", curtime->tm_year + 1900, curtime->tm_mon + 1, curtime->tm_mday);
m_NrmFileName.assign(_filename);
m_DailyPrintHdr = true;
break;
}
default:
{
/* do nothing... */
break;
}
}
}
void Logger::CloseLogger()
{
_CloseFile();
}
void Logger::LogToOpenFile(FILE *fp, const char *msg, ...)
{
if (!m_Active)
{
return;
}
va_list ap;
va_start(ap, msg);
LogToOpenFileEx(fp, msg, ap);
va_end(ap);
}
void Logger::LogToFileOnly(FILE *fp, const char *msg, ...)
{
if (!m_Active)
{
return;
}
va_list ap;
va_start(ap, msg);
LogToFileOnlyEx(fp, msg, ap);
va_end(ap);
}
void Logger::LogToOpenFileEx(FILE *fp, const char *msg, va_list ap)
{
if (!m_Active)
{
return;
}
static ConVar *sv_logecho = smcore.FindConVar("sv_logecho");
char buffer[3072];
smcore.FormatArgs(buffer, sizeof(buffer), msg, ap);
char date[32];
time_t t = g_pSM->GetAdjustedTime();
tm *curtime = localtime(&t);
strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime);
fprintf(fp, "L %s: %s\n", date, buffer);
if (!sv_logecho || smcore.GetCvarBool(sv_logecho))
{
static char conBuffer[4096];
smcore.Format(conBuffer, sizeof(conBuffer), "L %s: %s\n", date, buffer);
smcore.ConPrint(conBuffer);
}
}
void Logger::LogToFileOnlyEx(FILE *fp, const char *msg, va_list ap)
{
if (!m_Active)
{
return;
}
char buffer[3072];
smcore.FormatArgs(buffer, sizeof(buffer), msg, ap);
char date[32];
time_t t = g_pSM->GetAdjustedTime();
tm *curtime = localtime(&t);
strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime);
fprintf(fp, "L %s: %s\n", date, buffer);
fflush(fp);
}
void Logger::LogMessage(const char *vafmt, ...)
{
va_list ap;
va_start(ap, vafmt);
LogMessageEx(vafmt, ap);
va_end(ap);
}
void Logger::LogMessageEx(const char *vafmt, va_list ap)
{
if (!m_Active)
{
return;
}
if (m_Mode == LoggingMode_Game)
{
_PrintToGameLog(vafmt, ap);
return;
}
if (m_DelayedStart)
{
m_DelayedStart = false;
_NewMapFile();
}
time_t t = g_pSM->GetAdjustedTime();
tm *curtime = localtime(&t);
FILE *fp = NULL;
if (m_Mode == LoggingMode_PerMap)
{
fp = fopen(m_NrmFileName.c_str(), "a+");
if (!fp)
{
_NewMapFile();
fp = fopen(m_NrmFileName.c_str(), "a+");
if (!fp)
{
goto print_error;
}
}
} else {
if (m_NrmCurDay != curtime->tm_mday)
{
char _filename[256];
g_pSM->BuildPath(Path_SM, _filename, sizeof(_filename), "logs/L%04d%02d%02d.log", curtime->tm_year + 1900, curtime->tm_mon + 1, curtime->tm_mday);
m_NrmFileName.assign(_filename);
m_NrmCurDay = curtime->tm_mday;
m_DailyPrintHdr = true;
}
fp = fopen(m_NrmFileName.c_str(), "a+");
}
if (fp)
{
if (m_DailyPrintHdr)
{
char date[32];
m_DailyPrintHdr = false;
strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime);
fprintf(fp, "L %s: SourceMod log file session started (file \"L%04d%02d%02d.log\") (Version \"%s\")\n", date, curtime->tm_year + 1900, curtime->tm_mon + 1, curtime->tm_mday, SOURCEMOD_VERSION);
}
LogToOpenFileEx(fp, vafmt, ap);
fclose(fp);
} else {
goto print_error;
}
return;
print_error:
char error[255];
libsys->GetPlatformError(error, sizeof(error));
LogFatal("[SM] Unexpected fatal logging error (file \"%s\")", m_NrmFileName.c_str());
LogFatal("[SM] Platform returned error: \"%s\"", error);
LogFatal("[SM] Logging has been disabled.");
m_Active = false;
}
void Logger::LogError(const char *vafmt, ...)
{
va_list ap;
va_start(ap, vafmt);
LogErrorEx(vafmt, ap);
va_end(ap);
}
void Logger::LogErrorEx(const char *vafmt, va_list ap)
{
if (!m_Active)
{
return;
}
time_t t = g_pSM->GetAdjustedTime();
tm *curtime = localtime(&t);
if (curtime->tm_mday != m_ErrCurDay)
{
char _filename[256];
g_pSM->BuildPath(Path_SM, _filename, sizeof(_filename), "logs/errors_%04d%02d%02d.log", curtime->tm_year + 1900, curtime->tm_mon + 1, curtime->tm_mday);
m_ErrFileName.assign(_filename);
m_ErrCurDay = curtime->tm_mday;
m_ErrMapStart = false;
}
FILE *fp = fopen(m_ErrFileName.c_str(), "a+");
if (fp)
{
if (!m_ErrMapStart)
{
char date[32];
strftime(date, sizeof(date), "%m/%d/%Y - %H:%M:%S", curtime);
fprintf(fp, "L %s: SourceMod error session started\n", date);
fprintf(fp, "L %s: Info (map \"%s\") (file \"errors_%04d%02d%02d.log\")\n", date, m_CurMapName.c_str(), curtime->tm_year + 1900, curtime->tm_mon + 1, curtime->tm_mday);
m_ErrMapStart = true;
}
LogToOpenFileEx(fp, vafmt, ap);
fclose(fp);
}
else
{
char error[255];
libsys->GetPlatformError(error, sizeof(error));
LogFatal("[SM] Unexpected fatal logging error (file \"%s\")", m_NrmFileName.c_str());
LogFatal("[SM] Platform returned error: \"%s\"", error);
LogFatal("[SM] Logging has been disabled.");
m_Active = false;
return;
}
}
void Logger::MapChange(const char *mapname)
{
m_CurMapName.assign(mapname);
switch (m_Mode)
{
case LoggingMode_Daily:
{
LogMessage("-------- Mapchange to %s --------", mapname);
break;
}
case LoggingMode_PerMap:
{
_NewMapFile();
break;
}
default:
{
/* Do nothing... */
break;
}
}
if (m_ErrMapStart)
{
LogError("Error log file session closed.");
}
m_ErrMapStart = false;
}
void Logger::_PrintToGameLog(const char *fmt, va_list ap)
{
char msg[3072];
size_t len;
len = vsnprintf(msg, sizeof(msg)-2, fmt, ap);
len = (len >= sizeof(msg)) ? (sizeof(msg) - 2) : len;
msg[len++] = '\n';
msg[len] = '\0';
smcore.LogToGame(msg);
}
const char *Logger::GetLogFileName(LogType type) const
{
switch (type)
{
case LogType_Normal:
{
return m_NrmFileName.c_str();
}
case LogType_Error:
{
return m_ErrFileName.c_str();
}
default:
{
return "";
}
}
}
LoggingMode Logger::GetLoggingMode() const
{
return m_Mode;
}
void Logger::EnableLogging()
{
if (m_Active)
{
return;
}
m_Active = true;
LogMessage("[SM] Logging enabled manually by user.");
}
void Logger::DisableLogging()
{
if (!m_Active)
{
return;
}
LogMessage("[SM] Logging disabled manually by user.");
m_Active = false;
}
void Logger::LogFatal(const char *msg, ...)
{
va_list ap;
va_start(ap, msg);
LogFatalEx(msg, ap);
va_end(ap);
}
void Logger::LogFatalEx(const char *msg, va_list ap)
{
/* :TODO: make this print all pretty-like
* In fact, the pretty log printing function should be abstracted.
* It's already implemented twice which is bad.
*/
char path[PLATFORM_MAX_PATH];
g_pSM->BuildPath(Path_Game, path, sizeof(path), "sourcemod_fatal.log");
FILE *fp = fopen(path, "at");
if (fp)
{
m_Active = true;
LogToOpenFileEx(fp, msg, ap);
m_Active = false;
fclose(fp);
}
}

111
core/logic/Logger.h Normal file
View File

@ -0,0 +1,111 @@
/**
* vim: set ts=4 :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
* =============================================================================
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 3.0, as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
* As a special exception, AlliedModders LLC gives you permission to link the
* code of this program (as well as its derivative works) to "Half-Life 2," the
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
* by the Valve Corporation. You must obey the GNU General Public License in
* all respects for all other code used. Additionally, AlliedModders LLC grants
* this exception to all derivative works. AlliedModders LLC defines further
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
* or <http://www.sourcemod.net/license.php>.
*
* Version: $Id$
*/
#ifndef _INCLUDE_SOURCEMOD_CLOGGER_H_
#define _INCLUDE_SOURCEMOD_CLOGGER_H_
#include <stdio.h>
#include <sh_string.h>
#include "common_logic.h"
using namespace SourceHook;
enum LogType
{
LogType_Normal,
LogType_Error
};
enum LoggingMode
{
LoggingMode_Daily,
LoggingMode_PerMap,
LoggingMode_Game
};
class Logger : public SMGlobalClass, public ILogger
{
public:
Logger() : m_Mode(LoggingMode_Daily), m_ErrMapStart(false),
m_Active(false), m_DelayedStart(false), m_DailyPrintHdr(false),
m_InitialState(true)
{
}
public: //SMGlobalClass
ConfigResult OnSourceModConfigChanged(const char *key,
const char *value,
ConfigSource source,
char *error,
size_t maxlength);
void OnSourceModStartup(bool late);
void OnSourceModAllShutdown();
void OnSourceModLevelChange(const char *mapName);
public:
void InitLogger(LoggingMode mode);
void CloseLogger();
void EnableLogging();
void DisableLogging();
void LogMessage(const char *msg, ...);
void LogMessageEx(const char *msg, va_list ap);
void LogError(const char *msg, ...);
void LogErrorEx(const char *msg, va_list ap);
void LogFatal(const char *msg, ...);
void LogFatalEx(const char *msg, va_list ap);
void LogToOpenFile(FILE *fp, const char *msg, ...);
void LogToOpenFileEx(FILE *fp, const char *msg, va_list ap);
/* This version does not print to console, and is thus thread-safe */
void LogToFileOnly(FILE *fp, const char *msg, ...);
void LogToFileOnlyEx(FILE *fp, const char *msg, va_list ap);
void MapChange(const char *mapname);
const char *GetLogFileName(LogType type) const;
LoggingMode GetLoggingMode() const;
private:
void _CloseFile();
void _NewMapFile();
void _PrintToGameLog(const char *fmt, va_list ap);
private:
String m_NrmFileName;
String m_ErrFileName;
String m_CurMapName;
LoggingMode m_Mode;
int m_NrmCurDay;
int m_ErrCurDay;
bool m_ErrMapStart;
bool m_Active;
bool m_DelayedStart;
bool m_DailyPrintHdr;
bool m_InitialState;
};
extern Logger g_Logger;
#endif // _INCLUDE_SOURCEMOD_CLOGGER_H_

View File

@ -42,6 +42,7 @@
#include "GameConfigs.h"
#include "common_logic.h"
#include "Translator.h"
#include "Logger.h"
CPluginManager g_PluginSys;
HandleType_t g_PluginType = 0;
@ -844,8 +845,8 @@ void CPluginManager::LoadPluginsFromDir(const char *basedir, const char *localpa
{
char error[256];
libsys->GetPlatformError(error, sizeof(error));
smcore.LogError("[SM] Failure reading from plugins path: %s", localpath);
smcore.LogError("[SM] Platform returned error: %s", error);
g_Logger.LogError("[SM] Failure reading from plugins path: %s", localpath);
g_Logger.LogError("[SM] Platform returned error: %s", error);
return;
}
@ -990,9 +991,9 @@ LoadRes CPluginManager::_LoadPlugin(CPlugin **aResult, const char *path, bool de
} else {
if (bulletinUrl[0] != '\0')
{
smcore.Log("%s: Known malware detected. See %s for more info, blocking disabled in core.cfg", pPlugin->GetFilename(), bulletinUrl);
g_Logger.LogMessage("%s: Known malware detected. See %s for more info, blocking disabled in core.cfg", pPlugin->GetFilename(), bulletinUrl);
} else {
smcore.Log("%s: Possible malware or illegal plugin detected, blocking disabled in core.cfg", pPlugin->GetFilename());
g_Logger.LogMessage("%s: Possible malware or illegal plugin detected, blocking disabled in core.cfg", pPlugin->GetFilename());
}
}
}
@ -1094,7 +1095,7 @@ void CPluginManager::LoadAutoPlugin(const char *plugin)
if ((res=_LoadPlugin(&pl, plugin, false, PluginType_MapUpdated, error, sizeof(error))) == LoadRes_Failure)
{
smcore.LogError("[SM] Failed to load plugin \"%s\": %s.", plugin, error);
g_Logger.LogError("[SM] Failed to load plugin \"%s\": %s.", plugin, error);
pl->SetErrorState(
pl->GetStatus() <= Plugin_Created ? Plugin_BadLoad : pl->GetStatus(),
"%s",
@ -1136,7 +1137,7 @@ void CPluginManager::LoadAll_SecondPass()
error[0] = '\0';
if (!RunSecondPass(pPlugin, error, sizeof(error)))
{
smcore.LogError("[SM] Unable to load plugin \"%s\": %s", pPlugin->GetFilename(), error);
g_Logger.LogError("[SM] Unable to load plugin \"%s\": %s", pPlugin->GetFilename(), error);
pPlugin->SetErrorState(Plugin_Failed, "%s", error);
}
}

View File

@ -122,6 +122,13 @@ ProfileToolManager::OnRootConsoleCommand2(const char *cmdname, const ICommandArg
active_ = nullptr;
return;
}
if (strcmp(cmdname, "dump") == 0) {
if (active_) {
// if we have an active profiler, dump it
active_->Dump();
return;
}
}
if (args->ArgC() < 4) {
if (strcmp(cmdname, "start") == 0) {
@ -154,6 +161,15 @@ ProfileToolManager::OnRootConsoleCommand2(const char *cmdname, const ICommandArg
StartFromConsole(tool);
return;
}
if (strcmp(cmdname, "dump") == 0) {
IProfilingTool *tool = FindToolByName(toolname);
if (!tool) {
rootmenu->ConsolePrint("No tool with the name \"%s\" was found.", toolname);
return;
}
tool->Dump();
return;
}
if (strcmp(cmdname, "help") == 0) {
IProfilingTool *tool = FindToolByName(toolname);
if (!tool) {
@ -169,5 +185,6 @@ ProfileToolManager::OnRootConsoleCommand2(const char *cmdname, const ICommandArg
rootmenu->DrawGenericOption("list", "List all available profiling tools.");
rootmenu->DrawGenericOption("start", "Start a profile with a given tool.");
rootmenu->DrawGenericOption("stop", "Stop the current profile session.");
rootmenu->DrawGenericOption("dump", "Dumps output from the current profile session.");
rootmenu->DrawGenericOption("help", "Display help text for a profiler.");
}

View File

@ -375,7 +375,7 @@ PassRef<Native> ShareSystem::AddNativeToCache(CNativeOwner *pOwner, const sp_nat
if (i.found())
return NULL;
Ref<Native> entry = Newborn<Native>(new Native(pOwner, ntv));
Ref<Native> entry = new Native(pOwner, ntv);
m_NtvCache.insert(ntv->name, entry);
return entry;
}
@ -415,7 +415,7 @@ PassRef<Native> ShareSystem::AddFakeNative(IPluginFunction *pFunc, const char *n
CNativeOwner *owner = g_PluginSys.GetPluginByCtx(fake->ctx->GetContext());
entry = Newborn<Native>(new Native(owner, fake.take()));
entry = new Native(owner, fake.take());
m_NtvCache.insert(name, entry);
return entry;

View File

@ -96,11 +96,11 @@ void CPhraseFile::ParseWarning(const char *message, ...)
if (!m_FileLogged)
{
smcore.LogError("[SM] Warning(s) encountered in translation file \"%s\"", m_File.c_str());
logger->LogError("[SM] Warning(s) encountered in translation file \"%s\"", m_File.c_str());
m_FileLogged = true;
}
smcore.LogError("[SM] %s", buffer);
logger->LogError("[SM] %s", buffer);
}
void CPhraseFile::ReparseFile()
@ -142,8 +142,8 @@ void CPhraseFile::ReparseFile()
msg = m_ParseError.c_str();
}
smcore.LogError("[SM] Fatal error encountered parsing translation file \"%s\"", m_File.c_str());
smcore.LogError("[SM] Error (line %d, column %d): %s", states.line, states.col, msg);
logger->LogError("[SM] Fatal error encountered parsing translation file \"%s\"", m_File.c_str());
logger->LogError("[SM] Error (line %d, column %d): %s", states.line, states.col, msg);
}
const char *code;
@ -175,10 +175,10 @@ void CPhraseFile::ReparseFile()
msg = m_ParseError.c_str();
}
smcore.LogError("[SM] Fatal error encountered parsing translation file \"%s/%s\"",
logger->LogError("[SM] Fatal error encountered parsing translation file \"%s/%s\"",
code,
m_File.c_str());
smcore.LogError("[SM] Error (line %d, column %d): %s",
logger->LogError("[SM] Error (line %d, column %d): %s",
states.line,
states.col,
msg);
@ -831,13 +831,13 @@ void Translator::RebuildLanguageDatabase()
str_err = m_CustomError.c_str();
}
smcore.LogError("[SM] Failed to parse language header file: \"%s\"", path);
smcore.LogError("[SM] Parse error (line %d, column %d): %s", states.line, states.col, str_err);
logger->LogError("[SM] Failed to parse language header file: \"%s\"", path);
logger->LogError("[SM] Parse error (line %d, column %d): %s", states.line, states.col, str_err);
}
if (!m_LCodeLookup.retrieve(m_InitialLang, &m_ServerLang))
{
smcore.LogError("Server language was set to bad language \"%s\" -- reverting to English", m_InitialLang);
logger->LogError("Server language was set to bad language \"%s\" -- reverting to English", m_InitialLang);
smcore.strncopy(m_InitialLang, "en", sizeof(m_InitialLang));
m_ServerLang = SOURCEMOD_LANGUAGE_ENGLISH;
@ -845,7 +845,7 @@ void Translator::RebuildLanguageDatabase()
if (!m_Languages.size())
{
smcore.LogError("[SM] Fatal error, no languages found! Translation will not work.");
logger->LogError("[SM] Fatal error, no languages found! Translation will not work.");
}
for (size_t i=0; i<m_Files.size(); i++)
@ -872,7 +872,7 @@ SMCResult Translator::ReadSMC_NewSection(const SMCStates *states, const char *na
if (!m_InLanguageSection)
{
smcore.LogError("[SM] Warning: Unrecognized section \"%s\" in languages.cfg", name);
logger->LogError("[SM] Warning: Unrecognized section \"%s\" in languages.cfg", name);
}
return SMCResult_Continue;
@ -1025,11 +1025,11 @@ bool CoreTranslate(char *buffer, size_t maxlength, const char *format, unsigned
{
if (fail_phrase != NULL)
{
smcore.LogError("[SM] Could not find core phrase: %s", fail_phrase);
logger->LogError("[SM] Could not find core phrase: %s", fail_phrase);
}
else
{
smcore.LogError("[SM] Unknown fatal error while translating a core phrase.");
logger->LogError("[SM] Unknown fatal error while translating a core phrase.");
}
return false;

View File

@ -50,6 +50,7 @@
#include "ForwardSys.h"
#include "AdminCache.h"
#include "ProfileTools.h"
#include "Logger.h"
sm_core_t smcore;
IHandleSys *handlesys = &g_HandleSys;
@ -72,6 +73,8 @@ ISourcePawnEngine *g_pSourcePawn;
ISourcePawnEngine2 *g_pSourcePawn2;
CNativeOwner g_CoreNatives;
IScriptManager *scripts = &g_PluginSys;
IExtensionSys *extsys = &g_Extensions;
ILogger *logger = &g_Logger;
static void AddCorePhraseFile(const char *filename)
{
@ -140,6 +143,7 @@ static sm_logic_t logic =
&g_Forwards,
&g_Admins,
NULL,
&g_Logger,
-1.0f
};

View File

@ -53,6 +53,8 @@ extern IPlayerManager *playerhelpers;
extern IAdminSystem *adminsys;
extern IGameHelpers *gamehelpers;
extern IScriptManager *scripts;
extern IExtensionSys *extsys;
extern ILogger *logger;
#endif /* _INCLUDE_SOURCEMOD_COMMON_LOGIC_H_ */

View File

@ -52,7 +52,7 @@ using namespace SourceHook;
* Add 1 to the RHS of this expression to bump the intercom file
* This is to prevent mismatching core/logic binaries
*/
#define SM_LOGIC_MAGIC (0x0F47C0DE - 28)
#define SM_LOGIC_MAGIC (0x0F47C0DE - 29)
#if defined SM_LOGIC
class IVEngineServer
@ -83,6 +83,7 @@ class IFileSystem_Logic
public:
virtual const char *FindFirstEx(const char *pWildCard, const char *pPathID, FileFindHandle_t *pHandle) = 0;
virtual const char *FindNext(FileFindHandle_t handle) = 0;
virtual bool FindIsDirectory(FileFindHandle_t handle) = 0;
virtual void FindClose(FileFindHandle_t handle) = 0;
virtual FileHandle_t Open(const char *pFileName, const char *pOptions, const char *pathID = 0) = 0;
virtual void Close(FileHandle_t file) = 0;
@ -90,6 +91,17 @@ public:
virtual bool EndOfFile(FileHandle_t file) = 0;
virtual bool FileExists(const char *pFileName, const char *pPathID = 0) = 0;
virtual unsigned int Size(const char *pFileName, const char *pPathID = 0) = 0;
virtual int Read(void* pOutput, int size, FileHandle_t file) = 0;
virtual int Write(void const* pInput, int size, FileHandle_t file) = 0;
virtual void Seek(FileHandle_t file, int post, int seekType) = 0;
virtual unsigned int Tell(FileHandle_t file) = 0;
virtual int FPrint(FileHandle_t file, const char *pData) = 0;
virtual void Flush(FileHandle_t file) = 0;
virtual bool IsOk(FileHandle_t file) = 0;
virtual void RemoveFile(const char *pRelativePath, const char *pathID = 0) = 0;
virtual void RenameFile(char const *pOldPath, char const *pNewPath, const char *pathID = 0) = 0;
virtual bool IsDirectory(const char *pFileName, const char *pathID = 0) = 0;
virtual void CreateDirHierarchy(const char *path, const char *pathID = 0) = 0;
};
namespace SourceMod
@ -211,6 +223,15 @@ public:
virtual void AddRawDependency(IExtension *myself, IdentityToken_t *token, void *iface) = 0;
virtual const CVector<IExtension *> *ListExtensions() = 0;
virtual void FreeExtensionList(const CVector<IExtension *> *list) = 0;
virtual void CallOnCoreMapEnd() = 0;
};
class ILogger
{
public:
virtual void LogMessage(const char *msg, ...) = 0;
virtual void LogError(const char *msg, ...) = 0;
virtual void LogFatal(const char *msg, ...) = 0;
};
class AutoPluginList
@ -273,13 +294,10 @@ struct sm_core_t
ConVar * (*FindConVar)(const char*);
unsigned int (*strncopy)(char*, const char*, size_t);
char * (*TrimWhitespace)(char *, size_t &);
void (*LogError)(const char*, ...);
void (*LogFatal)(const char*, ...);
void (*Log)(const char*, ...);
void (*LogToFile)(FILE *fp, const char*, ...);
void (*LogToGame)(const char *message);
void (*ConPrint)(const char *message);
const char * (*GetCvarString)(ConVar*);
bool (*GetCvarBool)(ConVar*);
size_t (*Format)(char*, size_t, const char*, ...);
size_t (*FormatArgs)(char*, size_t, const char*,va_list ap);
bool (*gnprintf)(char *, size_t, const char *, IPhraseCollection *, void **,
@ -325,7 +343,7 @@ struct sm_logic_t
char *(*ReplaceEx)(char *, size_t, const char *, size_t, const char *, size_t, bool);
size_t (*DecodeHexString)(unsigned char *, size_t, const char *);
IGameConfig * (*GetCoreGameConfig)();
bool (*OnLogPrint)(const char *msg); // true to supercede
bool (*OnLogPrint)(const char *msg); // true to supersede
IDebugListener *debugger;
void (*GenerateError)(IPluginContext *, cell_t, int, const char *, ...);
void (*AddNatives)(sp_nativeinfo_t *natives);
@ -339,6 +357,7 @@ struct sm_logic_t
IForwardManager *forwardsys;
IAdminSystem *adminsys;
IdentityToken_t *core_ident;
ILogger *logger;
float sentinel;
};

View File

@ -163,7 +163,7 @@ private:
cell_t data_;
};
struct CellTrie : public ke::Refcounted<CellTrie>
struct CellTrie
{
StringHashMap<Entry> map;
};
@ -204,8 +204,7 @@ public: //IHandleTypeDispatch
{
if (type == htCellTrie)
{
CellTrie *pTrie = (CellTrie *)object;
pTrie->Release();
delete (CellTrie *)object;
} else {
TrieSnapshot *snapshot = (TrieSnapshot *)object;
delete snapshot;

View File

@ -32,14 +32,14 @@
#include <time.h>
#include <string.h>
#include <stdlib.h>
#include "sm_stringutil.h"
#include "sm_globals.h"
#include "sourcemod.h"
#include "LibrarySys.h"
#include "TimerSys.h"
#include "common_logic.h"
#include "Logger.h"
#include <ISourceMod.h>
#include <ITranslator.h>
#include <sourcehook.h>
#include <sh_memory.h>
#include "logic_bridge.h"
#if defined PLATFORM_WINDOWS
#include <windows.h>
@ -50,9 +50,11 @@
#endif
HandleType_t g_PlIter;
ConVar sm_datetime_format("sm_datetime_format", "%m/%d/%Y - %H:%M:%S", 0, "Default formatting time rules");
IForward *g_OnLogAction = NULL;
static ConVar *sm_datetime_format = NULL;
class CoreNativeHelpers :
public SMGlobalClass,
public IHandleTypeDispatch
@ -75,6 +77,8 @@ public:
Param_Cell,
Param_Cell,
Param_String);
sm_datetime_format = smcore.FindConVar("sm_datetime_format");
}
void OnHandleDestroy(HandleType_t type, void *object)
{
@ -119,14 +123,14 @@ void LogAction(Handle_t hndl, int type, int client, int target, const char *mess
g_Logger.LogMessage("[%s] %s", logtag, message);
}
static cell_t ThrowError(IPluginContext *pContext, const cell_t *params)
static cell_t ThrowError(IPluginContext *pContext, const cell_t *params)
{
char buffer[512];
g_SourceMod.SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE);
g_pSM->SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE);
g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 1);
g_pSM->FormatString(buffer, sizeof(buffer), pContext, params, 1);
if (pContext->GetLastNativeError() == SP_ERROR_NONE)
{
@ -138,7 +142,7 @@ static cell_t ThrowError(IPluginContext *pContext, const cell_t *params)
static cell_t GetTime(IPluginContext *pContext, const cell_t *params)
{
time_t t = GetAdjustedTime();
time_t t = g_pSM->GetAdjustedTime();
cell_t *addr;
pContext->LocalToPhysAddr(params[1], &addr);
@ -168,14 +172,14 @@ static cell_t FormatTime(IPluginContext *pContext, const cell_t *params)
if (format == NULL)
{
format = const_cast<char *>(sm_datetime_format.GetString());
format = const_cast<char *>(smcore.GetCvarString(sm_datetime_format));
}
#if defined SUBPLATFORM_SECURECRT
_invalid_parameter_handler handler = _set_invalid_parameter_handler(_ignore_invalid_parameter);
#endif
time_t t = (params[4] == -1) ? GetAdjustedTime() : (time_t)params[4];
time_t t = (params[4] == -1) ? g_pSM->GetAdjustedTime() : (time_t)params[4];
size_t written = strftime(buffer, params[2], format, localtime(&t));
#if defined SUBPLATFORM_SECURECRT
@ -384,7 +388,7 @@ static cell_t SetFailState(IPluginContext *pContext, const cell_t *params)
{
char buffer[2048];
g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 1);
g_pSM->FormatString(buffer, sizeof(buffer), pContext, params, 1);
if (pContext->GetLastNativeError() != SP_ERROR_NONE)
{
pPlugin->SetErrorState(Plugin_Error, "%s", str);
@ -433,14 +437,14 @@ static cell_t AutoExecConfig(IPluginContext *pContext, const cell_t *params)
static char temp_file[PLATFORM_MAX_PATH];
char *ptr;
g_LibSys.GetFileFromPath(temp_str, sizeof(temp_str), plugin->GetFilename());
libsys->GetFileFromPath(temp_str, sizeof(temp_str), plugin->GetFilename());
if ((ptr = strstr(temp_str, ".smx")) != NULL)
{
*ptr = '\0';
}
/* We have the raw filename! */
UTIL_Format(temp_file, sizeof(temp_file), "plugin.%s", temp_str);
g_pSM->Format(temp_file, sizeof(temp_file), "plugin.%s", temp_str);
cfg = temp_file;
}
@ -506,8 +510,8 @@ static cell_t LibraryExists(IPluginContext *pContext, const cell_t *params)
static cell_t sm_LogAction(IPluginContext *pContext, const cell_t *params)
{
char buffer[2048];
g_SourceMod.SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE);
g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 3);
g_pSM->SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE);
g_pSM->FormatString(buffer, sizeof(buffer), pContext, params, 3);
if (pContext->GetLastNativeError() != SP_ERROR_NONE)
{
@ -527,7 +531,7 @@ static cell_t LogToFile(IPluginContext *pContext, const cell_t *params)
pContext->LocalToString(params[1], &file);
char path[PLATFORM_MAX_PATH];
g_SourceMod.BuildPath(Path_Game, path, sizeof(path), "%s", file);
g_pSM->BuildPath(Path_Game, path, sizeof(path), "%s", file);
FILE *fp = fopen(path, "at");
if (!fp)
@ -536,8 +540,8 @@ static cell_t LogToFile(IPluginContext *pContext, const cell_t *params)
}
char buffer[2048];
g_SourceMod.SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE);
g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
g_pSM->SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE);
g_pSM->FormatString(buffer, sizeof(buffer), pContext, params, 2);
if (pContext->GetLastNativeError() != SP_ERROR_NONE)
{
@ -560,7 +564,7 @@ static cell_t LogToFileEx(IPluginContext *pContext, const cell_t *params)
pContext->LocalToString(params[1], &file);
char path[PLATFORM_MAX_PATH];
g_SourceMod.BuildPath(Path_Game, path, sizeof(path), "%s", file);
g_pSM->BuildPath(Path_Game, path, sizeof(path), "%s", file);
FILE *fp = fopen(path, "at");
if (!fp)
@ -569,8 +573,8 @@ static cell_t LogToFileEx(IPluginContext *pContext, const cell_t *params)
}
char buffer[2048];
g_SourceMod.SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE);
g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
g_pSM->SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE);
g_pSM->FormatString(buffer, sizeof(buffer), pContext, params, 2);
if (pContext->GetLastNativeError() != SP_ERROR_NONE)
{
@ -653,10 +657,10 @@ static cell_t RequireFeature(IPluginContext *pContext, const cell_t *params)
char default_message[255];
SMPlugin *pPlugin = scripts->FindPluginByContext(pContext->GetContext());
g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 3);
g_pSM->FormatString(buffer, sizeof(buffer), pContext, params, 3);
if (pContext->GetLastNativeError() != SP_ERROR_NONE || buffer[0] == '\0')
{
UTIL_Format(default_message, sizeof(default_message), "Feature \"%s\" not available", name);
g_pSM->Format(default_message, sizeof(default_message), "Feature \"%s\" not available", name);
msg = default_message;
}
pPlugin->SetErrorState(Plugin_Error, "%s", msg);
@ -743,19 +747,19 @@ static cell_t StoreToAddress(IPluginContext *pContext, const cell_t *params)
REGISTER_NATIVES(coreNatives)
{
{"AutoExecConfig", AutoExecConfig},
{"GetPluginFilename", GetPluginFilename},
{"GetPluginInfo", GetPluginInfo},
{"GetPluginIterator", GetPluginIterator},
{"GetPluginStatus", GetPluginStatus},
{"GetSysTickCount", GetSysTickCount},
{"ThrowError", ThrowError},
{"GetTime", GetTime},
{"IsPluginDebugging", IsPluginDebugging},
{"FormatTime", FormatTime},
{"GetPluginIterator", GetPluginIterator},
{"MorePlugins", MorePlugins},
{"ReadPlugin", ReadPlugin},
{"ThrowError", ThrowError},
{"GetPluginStatus", GetPluginStatus},
{"GetPluginFilename", GetPluginFilename},
{"IsPluginDebugging", IsPluginDebugging},
{"GetPluginInfo", GetPluginInfo},
{"SetFailState", SetFailState},
{"FormatTime", FormatTime},
{"GetSysTickCount", GetSysTickCount},
{"AutoExecConfig", AutoExecConfig},
{"MarkNativeAsOptional", MarkNativeAsOptional},
{"RegPluginLibrary", RegPluginLibrary},
{"LibraryExists", LibraryExists},
@ -770,5 +774,4 @@ REGISTER_NATIVES(coreNatives)
{"LoadFromAddress", LoadFromAddress},
{"StoreToAddress", StoreToAddress},
{NULL, NULL},
};
};

View File

@ -148,6 +148,27 @@ static cell_t smn_WritePackString(IPluginContext *pContext, const cell_t *params
return 1;
}
static cell_t smn_WritePackFunction(IPluginContext *pContext, const cell_t *params)
{
Handle_t hndl = static_cast<Handle_t>(params[1]);
HandleError herr;
HandleSecurity sec;
IDataPack *pDataPack;
sec.pOwner = pContext->GetIdentity();
sec.pIdentity = g_pCoreIdent;
if ((herr = handlesys->ReadHandle(hndl, g_DataPackType, &sec, (void **)&pDataPack))
!= HandleError_None)
{
return pContext->ThrowNativeError("Invalid data pack handle %x (error %d)", hndl, herr);
}
pDataPack->PackFunction(params[2]);
return 1;
}
static cell_t smn_ReadPackCell(IPluginContext *pContext, const cell_t *params)
{
Handle_t hndl = static_cast<Handle_t>(params[1]);
@ -164,7 +185,7 @@ static cell_t smn_ReadPackCell(IPluginContext *pContext, const cell_t *params)
return pContext->ThrowNativeError("Invalid data pack handle %x (error %d)", hndl, herr);
}
if (!pDataPack->IsReadable(sizeof(size_t) + sizeof(cell_t)))
if (!pDataPack->IsReadable(sizeof(char) + sizeof(size_t) + sizeof(cell_t)))
{
return pContext->ThrowNativeError("DataPack operation is out of bounds.");
}
@ -188,7 +209,7 @@ static cell_t smn_ReadPackFloat(IPluginContext *pContext, const cell_t *params)
return pContext->ThrowNativeError("Invalid data pack handle %x (error %d)", hndl, herr);
}
if (!pDataPack->IsReadable(sizeof(size_t) + sizeof(float)))
if (!pDataPack->IsReadable(sizeof(char) + sizeof(size_t) + sizeof(float)))
{
return pContext->ThrowNativeError("DataPack operation is out of bounds.");
}
@ -223,6 +244,30 @@ static cell_t smn_ReadPackString(IPluginContext *pContext, const cell_t *params)
return 1;
}
static cell_t smn_ReadPackFunction(IPluginContext *pContext, const cell_t *params)
{
Handle_t hndl = static_cast<Handle_t>(params[1]);
HandleError herr;
HandleSecurity sec;
IDataPack *pDataPack;
sec.pOwner = pContext->GetIdentity();
sec.pIdentity = g_pCoreIdent;
if ((herr = handlesys->ReadHandle(hndl, g_DataPackType, &sec, (void **)&pDataPack))
!= HandleError_None)
{
return pContext->ThrowNativeError("Invalid data pack handle %x (error %d)", hndl, herr);
}
if (!pDataPack->IsReadable(sizeof(char) + sizeof(size_t) + sizeof(cell_t)))
{
return pContext->ThrowNativeError("DataPack operation is out of bounds.");
}
return pDataPack->ReadFunction();
}
static cell_t smn_ResetPack(IPluginContext *pContext, const cell_t *params)
{
Handle_t hndl = static_cast<Handle_t>(params[1]);
@ -318,9 +363,11 @@ REGISTER_NATIVES(datapacknatives)
{"WritePackCell", smn_WritePackCell},
{"WritePackFloat", smn_WritePackFloat},
{"WritePackString", smn_WritePackString},
{"WritePackFunction", smn_WritePackFunction},
{"ReadPackCell", smn_ReadPackCell},
{"ReadPackFloat", smn_ReadPackFloat},
{"ReadPackString", smn_ReadPackString},
{"ReadPackFunction", smn_ReadPackFunction},
{"ResetPack", smn_ResetPack},
{"GetPackPosition", smn_GetPackPosition},
{"SetPackPosition", smn_SetPackPosition},

File diff suppressed because it is too large Load Diff

View File

@ -202,8 +202,8 @@ public:
{
errmsg = "Unknown error";
}
smcore.LogError("[SM] Could not parse file \"%s\"", m_ConfigFile);
smcore.LogError("[SM] Error on line %d (col %d): %s", states.line, states.col, errmsg);
logger->LogError("[SM] Could not parse file \"%s\"", m_ConfigFile);
logger->LogError("[SM] Error on line %d (col %d): %s", states.line, states.col, errmsg);
}
else
{

View File

@ -120,7 +120,7 @@ public: //ICommandTargetProcessor
Handle_t hndl = handlesys->CreateHandleEx(htCellArray, array, &sec, NULL, NULL);
AutoHandleCloner ahc(hndl, sec);
if (ahc.getClone() == BAD_HANDLE) {
smcore.LogError("[SM] Could not allocate a handle (%s, %d)", __FILE__, __LINE__);
logger->LogError("[SM] Could not allocate a handle (%s, %d)", __FILE__, __LINE__);
delete array;
return false;
}

View File

@ -86,6 +86,7 @@ IExtensionSys *extsys;
IHandleSys *handlesys;
IForwardManager *forwardsys;
IAdminSystem *adminsys;
ILogger *logger;
class VEngineServer_Logic : public IVEngineServer_Logic
{
@ -146,6 +147,10 @@ public:
{
return filesystem->FindNext(handle);
}
bool FindIsDirectory(FileFindHandle_t handle)
{
return filesystem->FindIsDirectory(handle);
}
void FindClose(FileFindHandle_t handle)
{
filesystem->FindClose(handle);
@ -174,6 +179,50 @@ public:
{
return filesystem->Size(pFileName, pPathID);
}
int Read(void* pOutput, int size, FileHandle_t file)
{
return filesystem->Read(pOutput, size, file);
}
int Write(void const* pInput, int size, FileHandle_t file)
{
return filesystem->Write(pInput, size, file);
}
void Seek(FileHandle_t file, int pos, int seekType)
{
filesystem->Seek(file, pos, (FileSystemSeek_t) seekType);
}
unsigned int Tell(FileHandle_t file)
{
return filesystem->Tell(file);
}
int FPrint(FileHandle_t file, const char *pData)
{
return filesystem->FPrintf(file, "%s", pData);
}
void Flush(FileHandle_t file)
{
filesystem->Flush(file);
}
bool IsOk(FileHandle_t file)
{
return filesystem->IsOk(file);
}
void RemoveFile(const char *pRelativePath, const char *pathID)
{
filesystem->RemoveFile(pRelativePath, pathID);
}
void RenameFile(char const *pOldPath, char const *pNewPath, const char *pathID)
{
filesystem->RenameFile(pOldPath, pNewPath, pathID);
}
bool IsDirectory(const char *pFileName, const char *pathID)
{
return filesystem->IsDirectory(pFileName, pathID);
}
void CreateDirHierarchy(const char *path, const char *pathID)
{
filesystem->CreateDirHierarchy(path, pathID);
}
};
static VFileSystem_Logic logic_filesystem;
@ -251,46 +300,13 @@ static VPlayerInfo_Logic logic_playerinfo;
static ConVar sm_show_activity("sm_show_activity", "13", FCVAR_SPONLY, "Activity display setting (see sourcemod.cfg)");
static ConVar sm_immunity_mode("sm_immunity_mode", "1", FCVAR_SPONLY, "Mode for deciding immunity protection");
static ConVar sm_datetime_format("sm_datetime_format", "%m/%d/%Y - %H:%M:%S", 0, "Default formatting time rules");
static ConVar *find_convar(const char *name)
{
return icvar->FindVar(name);
}
static void log_error(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
g_Logger.LogErrorEx(fmt, ap);
va_end(ap);
}
static void log_fatal(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
g_Logger.LogFatalEx(fmt, ap);
va_end(ap);
}
static void log_message(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
g_Logger.LogMessageEx(fmt, ap);
va_end(ap);
}
static void log_to_file(FILE *fp, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
g_Logger.LogToOpenFileEx(fp, fmt, ap);
va_end(ap);
}
static void log_to_game(const char *message)
{
Engine_LogPrintWrapper(message);
@ -306,6 +322,11 @@ static const char *get_cvar_string(ConVar* cvar)
return cvar->GetString();
}
static bool get_cvar_bool(ConVar* cvar)
{
return cvar->GetBool();
}
static bool get_game_name(char *buffer, size_t maxlength)
{
KeyValues *pGameInfo = new KeyValues("GameInfo");
@ -561,13 +582,10 @@ static sm_core_t core_bridge =
find_convar,
strncopy,
UTIL_TrimWhitespace,
log_error,
log_fatal,
log_message,
log_to_file,
log_to_game,
conprint,
get_cvar_string,
get_cvar_bool,
UTIL_Format,
UTIL_FormatArgs,
gnprintf,
@ -636,6 +654,7 @@ void InitLogicBridge()
handlesys = logicore.handlesys;
forwardsys = logicore.forwardsys;
adminsys = logicore.adminsys;
logger = logicore.logger;
}
bool StartLogicBridge(char *error, size_t maxlength)

View File

@ -48,5 +48,6 @@ extern IExtensionSys *extsys;
extern IHandleSys *handlesys;
extern IForwardManager *forwardsys;
extern IAdminSystem *adminsys;
extern ILogger *logger;
#endif /* _INCLUDE_SOURCEMOD_LOGIC_BRIDGE_H_ */

View File

@ -1216,7 +1216,7 @@ static cell_t AddCommandListener(IPluginContext *pContext, const cell_t *params)
if (strcasecmp(name, "sm") == 0)
{
g_Logger.LogError("Request to register \"sm\" command denied.");
logger->LogError("Request to register \"sm\" command denied.");
return 0;
}

View File

@ -167,7 +167,7 @@ void SourceMod_Core::OnVSPListening(IServerPluginCallbacks *iface)
/* This shouldn't happen */
if (!iface)
{
g_Logger.LogFatal("Metamod:Source version is out of date. SourceMod requires 1.4.2 or greater.");
logger->LogFatal("Metamod:Source version is out of date. SourceMod requires 1.4.2 or greater.");
return;
}

View File

@ -395,6 +395,7 @@ void SourceModBase::LevelShutdown()
{
g_pOnMapEnd->Execute(NULL);
}
extsys->CallOnCoreMapEnd();
g_Timers.RemoveMapChangeTimers();
@ -572,9 +573,9 @@ void SourceModBase::LogMessage(IExtension *pExt, const char *format, ...)
if (tag)
{
g_Logger.LogMessage("[%s] %s", tag, buffer);
logger->LogMessage("[%s] %s", tag, buffer);
} else {
g_Logger.LogMessage("%s", buffer);
logger->LogMessage("%s", buffer);
}
}
@ -591,9 +592,9 @@ void SourceModBase::LogError(IExtension *pExt, const char *format, ...)
if (tag)
{
g_Logger.LogError("[%s] %s", tag, buffer);
logger->LogError("[%s] %s", tag, buffer);
} else {
g_Logger.LogError("%s", buffer);
logger->LogError("%s", buffer);
}
}

View File

@ -73,6 +73,14 @@ VProfTool::Stop(void (*render)(const char *fmt, ...))
RenderHelp(render);
}
void
VProfTool::Dump()
{
g_VProfCurrentProfile.Pause();
g_VProfCurrentProfile.OutputReport(VPRT_FULL);
g_VProfCurrentProfile.Resume();
}
bool
VProfTool::IsActive()
{
@ -105,5 +113,5 @@ VProfTool::LeaveScope()
void
VProfTool::RenderHelp(void (*render)(const char *fmt, ...))
{
render("Use vprof_generate_report in your console to analyze a profile session.");
render("Use 'sm prof dump vprof' or one of the vprof_generate_report commands in your console to analyze a profile session.");
}

View File

@ -44,6 +44,7 @@ public:
const char *Description() KE_OVERRIDE;
bool Start() KE_OVERRIDE;
void Stop(void (*render)(const char *fmt, ...)) KE_OVERRIDE;
void Dump() KE_OVERRIDE;
bool IsActive() KE_OVERRIDE;
bool IsAttached() KE_OVERRIDE;
void EnterScope(const char *group, const char *name) KE_OVERRIDE;

View File

@ -219,7 +219,7 @@ void ClientPrefs::DatabaseConnect()
char error[256];
int errCode = 0;
Database = Newborn<IDatabase>(Driver->Connect(DBInfo, true, error, sizeof(error)));
Database = AdoptRef(Driver->Connect(DBInfo, true, error, sizeof(error)));
if (!Database)
{

View File

@ -106,7 +106,7 @@ static cell_t MatchRegex(IPluginContext *pCtx, const cell_t *params)
if ((err=g_pHandleSys->ReadHandle(hndl, g_RegexHandle, &sec, (void **)&x)) != HandleError_None)
{
return pCtx->ThrowNativeError("Invalid file handle %x (error %d)", hndl, err);
return pCtx->ThrowNativeError("Invalid regex handle %x (error %d)", hndl, err);
}
if (!x)
@ -159,7 +159,7 @@ static cell_t GetRegexSubString(IPluginContext *pCtx, const cell_t *params)
if ((err=g_pHandleSys->ReadHandle(hndl, g_RegexHandle, &sec, (void **)&x)) != HandleError_None)
{
return pCtx->ThrowNativeError("Invalid file handle %x (error %d)", hndl, err);
return pCtx->ThrowNativeError("Invalid regex handle %x (error %d)", hndl, err);
}
if (!x)

View File

@ -12,9 +12,9 @@
}
"FireBullets"
{
"windows" "112"
"linux" "113"
"mac" "113"
"windows" "113"
"linux" "114"
"mac" "114"
}
"OnTakeDamage"
{
@ -24,15 +24,15 @@
}
"PreThink"
{
"windows" "331"
"linux" "332"
"mac" "332"
"windows" "333"
"linux" "334"
"mac" "334"
}
"PostThink"
{
"windows" "332"
"linux" "333"
"mac" "333"
"windows" "334"
"linux" "335"
"mac" "335"
}
"SetTransmit"
{
@ -78,39 +78,39 @@
}
"VPhysicsUpdate"
{
"windows" "157"
"linux" "158"
"mac" "158"
"windows" "158"
"linux" "159"
"mac" "159"
}
"Weapon_CanSwitchTo"
{
"windows" "265"
"linux" "266"
"mac" "266"
"windows" "267"
"linux" "268"
"mac" "268"
}
"Weapon_CanUse"
{
"windows" "259"
"linux" "260"
"mac" "260"
"windows" "261"
"linux" "262"
"mac" "262"
}
"Weapon_Drop"
{
"windows" "264"
"linux" "265"
"mac" "265"
}
"Weapon_Equip"
{
"windows" "262"
"linux" "263"
"mac" "263"
}
"Weapon_Equip"
{
"windows" "260"
"linux" "261"
"mac" "261"
}
"Weapon_Switch"
{
"windows" "263"
"linux" "264"
"mac" "264"
"windows" "265"
"linux" "266"
"mac" "266"
}
}
}

View File

@ -30,9 +30,9 @@
}
"PreThink"
{
"windows" "344"
"linux" "345"
"mac" "345"
"windows" "345"
"linux" "346"
"mac" "346"
}
"PostThink"
{

View File

@ -48,21 +48,6 @@
}
}
/* No longer necessary. Remove later. */
"#default"
{
"Signatures"
{
"EntityFactory"
{
"library" "server"
"windows" "\xB8\x01\x00\x00\x00\x84\x2A\x2A\x2A\x2A\x2A\x75\x1D\x09\x2A\x2A\x2A\x2A\x2A\xB9\x2A\x2A\x2A\x2A\xE8\x2A\x2A\x2A\x2A\x68\x2A\x2A\x2A\x2A\xE8\x2A\x2A\x2A\x2A\x83\xC4\x04\xB8\x2A\x2A\x2A\x2A\xC3"
"linux" "@_Z23EntityFactoryDictionaryv"
"mac" "@_Z23EntityFactoryDictionaryv"
}
}
}
/* SetUserInfo data */
"#default"
{

View File

@ -131,57 +131,57 @@
{
"GiveNamedItem"
{
"windows" "400"
"linux" "401"
"mac" "401"
"windows" "402"
"linux" "403"
"mac" "403"
}
"RemovePlayerItem"
{
"windows" "271"
"linux" "272"
"mac" "272"
}
"Weapon_GetSlot"
{
"windows" "269"
"linux" "270"
"mac" "270"
}
"Weapon_GetSlot"
{
"windows" "267"
"linux" "268"
"mac" "268"
}
"Ignite"
{
"windows" "208"
"linux" "209"
"mac" "209"
"windows" "210"
"linux" "211"
"mac" "211"
}
"Extinguish"
{
"windows" "212"
"linux" "213"
"mac" "213"
"windows" "214"
"linux" "215"
"mac" "215"
}
"Teleport"
{
"windows" "108"
"linux" "109"
"mac" "109"
"windows" "109"
"linux" "110"
"mac" "110"
}
"CommitSuicide"
{
"windows" "442"
"linux" "442"
"mac" "442"
"windows" "444"
"linux" "444"
"mac" "444"
}
"GetVelocity"
{
"windows" "140"
"linux" "141"
"mac" "141"
"windows" "141"
"linux" "142"
"mac" "142"
}
"EyeAngles"
{
"windows" "131"
"linux" "132"
"mac" "132"
"windows" "132"
"linux" "133"
"mac" "133"
}
"AcceptInput"
{
@ -197,9 +197,9 @@
}
"WeaponEquip"
{
"windows" "260"
"linux" "261"
"mac" "261"
"windows" "262"
"linux" "263"
"mac" "263"
}
"Activate"
{
@ -209,15 +209,15 @@
}
"PlayerRunCmd"
{
"windows" "418"
"linux" "419"
"mac" "419"
"windows" "420"
"linux" "421"
"mac" "421"
}
"GiveAmmo"
{
"windows" "251"
"linux" "252"
"mac" "252"
"windows" "253"
"linux" "254"
"mac" "254"
}
}
}

View File

@ -131,9 +131,9 @@
{
"GiveNamedItem"
{
"windows" "412"
"linux" "413"
"mac" "413"
"windows" "413"
"linux" "414"
"mac" "414"
}
"RemovePlayerItem"
{
@ -167,9 +167,9 @@
}
"CommitSuicide"
{
"windows" "451"
"linux" "451"
"mac" "451"
"windows" "452"
"linux" "452"
"mac" "452"
}
"GetVelocity"
{
@ -209,9 +209,9 @@
}
"PlayerRunCmd"
{
"windows" "430"
"linux" "431"
"mac" "431"
"windows" "431"
"linux" "432"
"mac" "432"
}
"GiveAmmo"
{

View File

@ -118,18 +118,21 @@ LoadBanReasons()
decl String:sectionName[255];
if(!KvGetSectionName(g_hKvBanReasons, sectionName, sizeof(sectionName)))
{
return SetFailState("Error in %s: File corrupt or in the wrong format", g_BanReasonsPath);
SetFailState("Error in %s: File corrupt or in the wrong format", g_BanReasonsPath);
return;
}
if(strcmp(sectionName, "banreasons") != 0)
{
return SetFailState("Error in %s: Couldn't find 'banreasons'", g_BanReasonsPath);
SetFailState("Error in %s: Couldn't find 'banreasons'", g_BanReasonsPath);
return;
}
//Reset kvHandle
KvRewind(g_hKvBanReasons);
} else {
return SetFailState("Error in %s: File not found, corrupt or in the wrong format", g_BanReasonsPath);
SetFailState("Error in %s: File not found, corrupt or in the wrong format", g_BanReasonsPath);
return;
}
}

View File

@ -168,7 +168,13 @@ forward OnClientCookiesCached(client);
* @param maxlen Max length of the output buffer.
* @noreturn
*/
functag public void CookieMenuHandler(client, CookieMenuAction:action, any:info, String:buffer[], maxlen);
typedef CookieMenuHandler = function void (
int client,
CookieMenuAction action,
any info,
char[] buffer,
int maxlen
);
/**
* Add a new prefab item to the client cookie settings menu.

View File

@ -140,7 +140,7 @@ stock ReplyToTargetError(client, reason)
* @param clients Array to fill with unique, valid client indexes.
* @return True if pattern was recognized, false otherwise.
*/
functag public bool:MultiTargetFilter(const String:pattern[], Handle:clients);
typedef MultiTargetFilter = function bool (const char[] pattern, Handle clients);
/**
* Adds a multi-target filter function for ProcessTargetString().

View File

@ -328,7 +328,7 @@ native FormatActivitySource(client, target, const String:namebuf[], maxlength);
* @return An Action value. Not handling the command
* means that Source will report it as "not found."
*/
functag public Action:SrvCmd(args);
typedef SrvCmd = function Action (int args);
/**
* Creates a server-only console command, or hooks an already existing one.
@ -352,7 +352,7 @@ native RegServerCmd(const String:cmd[], SrvCmd:callback, const String:descriptio
* @return An Action value. Not handling the command
* means that Source will report it as "not found."
*/
functag public Action:ConCmd(client, args);
typedef ConCmd = function Action (int client, int args);
/**
* Creates a console command, or hooks an already existing one.
@ -456,7 +456,7 @@ native Handle:FindConVar(const String:name[]);
* @param newValue String containing the new value of the convar.
* @noreturn
*/
functag public void ConVarChanged(Handle:convar, const String:oldValue[], const String:newValue[]);
typedef ConVarChanged = function void (Handle convar, const char[] oldValue, const char[] newValue);
/**
* Creates a hook for when a console variable's value is changed.
@ -669,7 +669,7 @@ native SetConVarBounds(Handle:convar, ConVarBounds:type, bool:set, Float:value=0
*/
native GetConVarName(Handle:convar, String:name[], maxlength);
funcenum ConVarQueryFinished
union ConVarQueryFinished
{
/**
* Called when a query to retrieve a client's console variable has finished.
@ -683,7 +683,7 @@ funcenum ConVarQueryFinished
* @param value Value that was passed when query was started.
* @noreturn
*/
public(QueryCookie:cookie, client, ConVarQueryResult:result, const String:cvarName[], const String:cvarValue[], any:value),
function void (QueryCookie cookie, int client, ConVarQueryResult result, const char[] cvarName, const char[] cvarValue, any value);
/**
* Called when a query to retrieve a client's console variable has finished.
@ -696,7 +696,7 @@ funcenum ConVarQueryFinished
* @param convarValue Value of client convar that was queried if successful. This will be "" if it was not.
* @noreturn
*/
public(QueryCookie:cookie, client, ConVarQueryResult:result, const String:cvarName[], const String:cvarValue[])
function void (QueryCookie cookie, int client, ConVarQueryResult result, const char[] cvarName, const char[] cvarValue);
};
/**
@ -905,7 +905,7 @@ native RemoveServerTag(const String:tag[]);
* @param argc Argument count.
* @return Action to take (see extended notes above).
*/
functag public Action:CommandListener(client, const String:command[], argc);
typedef CommandListener = function Action (int client, const char[] command, int argc);
#define FEATURECAP_COMMANDLISTENER "command listener"

View File

@ -72,6 +72,16 @@ native WritePackFloat(Handle:pack, Float:val);
*/
native WritePackString(Handle:pack, const String:str[]);
/**
* Packs a function pointer into a data pack.
*
* @param pack Handle to the data pack.
* @param fktptr Function pointer to add.
* @noreturn
* @error Invalid handle.
*/
native WritePackFunction(Handle:pack, Function:fktptr);
/**
* Reads a cell from a data pack.
*
@ -101,6 +111,15 @@ native Float:ReadPackFloat(Handle:pack);
*/
native ReadPackString(Handle:pack, String:buffer[], maxlen);
/**
* Reads a function pointer from a data pack.
*
* @param pack Handle to the data pack.
* @return Function pointer.
* @error Invalid handle, or bounds error.
*/
native Function ReadPackFunction(Handle:pack);
/**
* Resets the position in a data pack.
*

View File

@ -643,7 +643,7 @@ native SQL_UnlockDatabase(Handle:database);
* @param data Data passed in via the original threaded invocation.
* @noreturn
*/
functag public void SQLTCallback(Handle:owner, Handle:hndl, const String:error[], any:data);
typedef SQLTCallback = function void (Handle owner, Handle hndl, const char[] error, any data);
/**
* Tells whether two database handles both point to the same database
@ -713,7 +713,7 @@ native Transaction:SQL_CreateTransaction();
* @param queryData An array of each data value passed to SQL_AddQuery().
* @noreturn
*/
functag public void SQLTxnSuccess(Handle:db, any:data, numQueries, Handle:results[], any:queryData[]);
typedef SQLTxnSuccess = function void (Handle db, any data, int numQueries, Handle[] results, any[] queryData);
/**
* Callback for a failed transaction.
@ -726,7 +726,7 @@ functag public void SQLTxnSuccess(Handle:db, any:data, numQueries, Handle:result
* @param queryData An array of each data value passed to SQL_AddQuery().
* @noreturn
*/
functag public void SQLTxnFailure(Handle:db, any:data, numQueries, const String:error[], failIndex, any:queryData[]);
typedef SQLTxnFailure = function void (Handle db, any data, int numQueries, const char[] error, int failIndex, any[] queryData);
/**
* Adds a query to a transaction object.

View File

@ -48,7 +48,7 @@ enum EventHookMode
/**
* Hook function types for events.
*/
funcenum EventHook
union EventHook
{
/**
* Called when a game event is fired.
@ -59,7 +59,7 @@ funcenum EventHook
* @param dontBroadcast True if event was not broadcast to clients, false otherwise.
* @return Ignored for post hooks. Plugin_Handled will block event if hooked as pre.
*/
Action:public(Handle:event, const String:name[], bool:dontBroadcast),
function Action (Handle event, const char[] name, bool dontBroadcast);
/**
* Called when a game event is fired.
*
@ -69,7 +69,7 @@ funcenum EventHook
* @param dontBroadcast True if event was not broadcast to clients, false otherwise.
* @noreturn
*/
public(Handle:event, const String:name[], bool:dontBroadcast),
function void (Handle event, const char[] name, bool dontBroadcast);
};
/**

View File

@ -108,9 +108,14 @@ native BuildPath(PathType:type, String:buffer[], maxlength, const String:fmt[],
* @note OpenDirectory() supports the "file://" notation.
*
* @param path Path to open.
* @param use_valve_fs If true, the Valve file system will be used instead.
* This can be used to find files existing in any of
* the Valve search paths, rather than solely files
* existing directly in the gamedir.
* @param valve_path_id If use_valve_fs, a search path from gameinfo or NULL_STRING for all search paths.
* @return A Handle to the directory, INVALID_HANDLE on open error.
*/
native Handle:OpenDirectory(const String:path[]);
native Handle:OpenDirectory(const String:path[], bool:use_valve_fs=false, const String:valve_path_id[]="GAME");
/**
* Reads the current directory entry as a local filename, then moves to the next file.
@ -136,17 +141,27 @@ native bool:ReadDirEntry(Handle:dir, String:buffer[], maxlength, &FileType:type=
*
* @param file File to open.
* @param mode Open mode.
* @param use_valve_fs If true, the Valve file system will be used instead.
* This can be used to find files existing in valve
* search paths, rather than solely files existing directly
* in the gamedir.
* @param valve_path_id If use_valve_fs, a search path from gameinfo or NULL_STRING for all search paths.
* @return A Handle to the file, INVALID_HANDLE on open error.
*/
native Handle:OpenFile(const String:file[], const String:mode[]);
native Handle:OpenFile(const String:file[], const String:mode[], bool:use_valve_fs=false, const String:valve_path_id[]="GAME");
/**
* Deletes a file.
*
* @param path Path of the file to delete.
* @return True on success, false otherwise.
* @param use_valve_fs If true, the Valve file system will be used instead.
* This can be used to delete files existing in the Valve
* search path, rather than solely files existing directly
* in the gamedir.
* @param valve_path_id If use_valve_fs, a search path from gameinfo or NULL_STRING for all search paths.
* @return True on success, false on failure or if file not immediately removed.
*/
native bool:DeleteFile(const String:path[]);
native bool:DeleteFile(const String:path[], bool:use_valve_fs=false, const String:valve_path_id[]="DEFAULT_WRITE_PATH");
/**
* Reads a line from a text file.
@ -304,28 +319,38 @@ native FilePosition(Handle:file);
* @param path Path to the file.
* @param use_valve_fs If true, the Valve file system will be used instead.
* This can be used to find files existing in any of
* the GAME search paths, rather than solely files
* the Valve search paths, rather than solely files
* existing directly in the gamedir.
* @param valve_path_id If use_valve_fs, a search path from gameinfo or NULL_STRING for all search paths.
* @return True if the file exists, false otherwise.
*/
native bool:FileExists(const String:path[], bool:use_valve_fs=false);
native bool:FileExists(const String:path[], bool:use_valve_fs=false, const String:valve_path_id[]="GAME");
/**
* Renames a file.
*
* @param newpath New path to the file.
* @param oldpath Path to the existing file.
* @return True on success, false otherwise.
* @param use_valve_fs If true, the Valve file system will be used instead.
* This can be used to rename files in the game's
* Valve search paths, rather than directly in the gamedir.
* @param valve_path_id If use_valve_fs, a search path from gameinfo or NULL_STRING for all search paths.
* @return True on success or use_valve_fs specified, false otherwise.
*/
native bool:RenameFile(const String:newpath[], const String:oldpath[]);
native bool:RenameFile(const String:newpath[], const String:oldpath[], bool:use_valve_fs=false, const String:valve_path_id[]="DEFAULT_WRITE_PATH");
/**
* Checks if a directory exists.
*
* @param path Path to the directory.
* @param use_valve_fs If true, the Valve file system will be used instead.
* This can be used to find files existing in any of
* the Valve search paths, rather than solely files
* existing directly in the gamedir.
* @param valve_path_id If use_valve_fs, a search path from gameinfo or NULL_STRING for all search paths.
* @return True if the directory exists, false otherwise.
*/
native bool:DirExists(const String:path[]);
native bool:DirExists(const String:path[], bool:use_valve_fs=false, const String:valve_path_id[]="GAME");
/**
* Get the file size in bytes.
@ -333,18 +358,20 @@ native bool:DirExists(const String:path[]);
* @param path Path to the file.
* @param use_valve_fs If true, the Valve file system will be used instead.
* This can be used to find files existing in any of
* the GAME search paths, rather than solely files
* the Valve search paths, rather than solely files
* existing directly in the gamedir.
* @param valve_path_id If use_valve_fs, a search path from gameinfo or NULL_STRING for all search paths.
* @return File size in bytes, -1 if file not found.
*/
native FileSize(const String:path[], bool:use_valve_fs=false);
native FileSize(const String:path[], bool:use_valve_fs=false, const String:valve_path_id[]="GAME");
/**
* Flushes a file's buffered output; any buffered output
* is immediately written to the file.
*
* @param file Handle to the file.
* @return True on success, false on failure.
* @return True on success or use_valve_fs specified with OpenFile,
* otherwise false on failure.
*/
native FlushFile(Handle:file);
@ -373,8 +400,22 @@ native bool:RemoveDir(const String:path[]);
* @param path Path to create.
* @param mode Permissions (default is o=rx,g=rx,u=rwx). Note that folders must have
* the execute bit set on Linux. On Windows, the mode is ignored.
* @param use_valve_fs If true, the Valve file system will be used instead.
* This can be used to create folders in the game's
* Valve search paths, rather than directly in the gamedir.
* @param valve_path_id If use_valve_fs, a search path from gameinfo or NULL_STRING for default.
* In this case, mode is ignored.
*/
native bool:CreateDirectory(const String:path[], mode);
native bool:CreateDirectory(const String:path[], mode, bool:use_valve_fs=false, const String:valve_path_id[]="DEFAULT_WRITE_PATH");
/**
* Changes a file or directories permissions.
*
* @param path Path to the file.
* @param mode Permissions to set.
* @return True on success, false otherwise.
*/
native bool:SetFilePermissions(const String:path[], mode);
/**
* Returns a file timestamp as a unix timestamp.

View File

@ -35,6 +35,7 @@
#endif
#define _float_included
#if !defined __sourcepawn2__
/**
* Converts an integer into a floating point value.
*
@ -42,6 +43,7 @@
* @return Floating point value.
*/
native Float:float(value);
#endif
/**
* Multiplies two floats together.

View File

@ -357,7 +357,7 @@ native Call_Cancel();
* @param numParams Number of parameters passed to the native.
* @return Value for the native call to return.
*/
functag public int NativeCall(Handle:plugin, numParams);
typedef NativeCall = function int (Handle plugin, int numParams);
/**
* Creates a dynamic native. This should only be called in AskPluginLoad(), or
@ -508,7 +508,7 @@ native FormatNativeString(out_param,
* @param data Data passed to the RequestFrame native.
* @noreturn
*/
functag public void RequestFrameCallback(any:data);
typedef RequestFrameCallback = function void (any data);
/**
* Creates a single use Next Frame hook.

View File

@ -59,7 +59,6 @@ native SetGlobalTransTarget(client);
/**
* Retrieves the language number of a client.
* Currently this simply returns the server language index.
*
* @param client Client index.
* @return Language number client is using.

View File

@ -123,7 +123,7 @@ forward Action:OnLogAction(Handle:source,
* @return Plugin_Handled or Plugin_Stop will prevent the message
* from being written to the log file.
*/
functag public Action:GameLogHook(const String:message[]);
typedef GameLogHook = function Action (const char[] message);
/**
* Adds a game log hook.

View File

@ -151,7 +151,7 @@ enum MenuSource
* @param param1 First action parameter (usually the client).
* @param param2 Second action parameter (usually the item).
*/
functag public int MenuHandler(Menu:menu, MenuAction:action, param1, param2);
typedef MenuHandler = function int (Menu menu, MenuAction action, int param1, int param2);
/**
* Creates a new, empty menu using the default style.
@ -527,12 +527,14 @@ stock bool:VoteMenuToAll(Handle:menu, time, flags=0)
* defines.
* @noreturn
*/
functag public void VoteHandler(Menu:menu,
num_votes,
num_clients,
const client_info[][2],
num_items,
const item_info[][2]);
typedef VoteHandler = function void (
Menu menu,
int num_votes,
int num_clients,
const int client_info[][2],
int num_items,
const int item_info[][2]
);
/**
* Sets an advanced vote handling callback. If this callback is set,

View File

@ -197,91 +197,91 @@ enum UseType
Use_Toggle
};
funcenum SDKHookCB
union SDKHookCB
{
// PreThink/Post
// PostThink/Post
public(client),
function void (int client);
// Spawn
Action:public(entity),
function Action (int entity);
// GroundEntChanged
// SpawnPost
// Think/Post
// VPhysicsUpdate/Post
public(entity),
function void (int entity);
// EndTouch
// StartTouch
// Touch
// Blocked
Action:public(entity, other),
function Action (int entity, int other);
// EndTouchPost
// StartTouchPost
// TouchPost
public(entity, other),
function void (int entity, int other);
// SetTransmit
Action:public(entity, client),
function Action (int entity, int client);
// WeaponCanSwitchTo
// WeaponCanUse
// WeaponDrop
// WeaponEquip
// WeaponSwitch
Action:public(client, weapon),
function Action (int client, int weapon);
// WeaponCanSwitchToPost
// WeaponCanUsePost
// WeaponDropPost
// WeaponEquipPost
// WeaponSwitchPost
public(client, weapon),
function void (int client, int weapon);
// GetMaxHealth (ep2v and later)
Action:public(entity, &maxhealth),
function Action (int entity, int &maxhealth);
// OnTakeDamage
// Note: The weapon parameter is not used by all games and damage sources.
// Note: Force application is dependent on game and damage type(s)
// SDKHooks 1.0+
Action:public(victim, &attacker, &inflictor, &Float:damage, &damagetype),
function Action (int victim, int &attacker, int &inflictor, float &damage, int &damagetype),
// SDKHooks 2.0+
Action:public(victim, &attacker, &inflictor, &Float:damage, &damagetype, &weapon, Float:damageForce[3], Float:damagePosition[3]),
function Action (int victim, int &attacker, int &inflictor, float &damage, int &damagetype, int &weapon, float[3] damageForce, float[3] damagePosition);
// SDKHooks 2.1+ (can check for support at runtime using GetFeatureStatus on SDKHook_DmgCustomInOTD capability.
// DON'T attempt to access 'damagecustom' var if feature status != available
Action:public(victim, &attacker, &inflictor, &Float:damage, &damagetype, &weapon,
Float:damageForce[3], Float:damagePosition[3], damagecustom),
function Action (int victim, int &attacker, int &inflictor, float &damage, int &damagetype, int &weapon,
float[3] damageForce, float[3] damagePosition, int damagecustom);
// OnTakeDamagePost
public(victim, attacker, inflictor, Float:damage, damagetype),
public(victim, attacker, inflictor, Float:damage, damagetype, weapon, const Float:damageForce[3], const Float:damagePosition[3]),
function void (int victim, int attacker, int inflictor, float damage, int damagetype);
function void (int victim, int attacker, int inflictor, float damage, int damagetype, const float[3] damageForce, const float[3] damagePosition);
// FireBulletsPost
public(client, shots, const String:weaponname[]),
function void (int client, int shots, const char[] weaponname);
// TraceAttack
Action:public(victim, &attacker, &inflictor, &Float:damage, &damagetype, &ammotype, hitbox, hitgroup),
function Action (int victim, int &attacker, int &inflictor, float &damage, int &damagetype, int &ammotype, int hitbox, int hitgroup);
// TraceAttackPost
public(victim, attacker, inflictor, Float:damage, damagetype, ammotype, hitbox, hitgroup),
function void (int victim, int attacker, int inflictor, float damage, int damagetype, int ammotype, int hitbox, int hitgroup);
// ShouldCollide
bool:public(entity, collisiongroup, contentsmask, bool:originalResult),
function bool (int entity, int collisiongroup, int contentsmask, bool originalResult);
// Use
Action:public(entity, activator, caller, UseType:type, Float:value),
function Action (int entity, int activator, int caller, UseType type, float value);
// UsePost
public(entity, activator, caller, UseType:type, Float:value),
function void (int entity, int activator, int caller, UseType type, float value);
// Reload
Action:public(weapon),
function Action (int weapon);
// Reload post
public(weapon, bool:bSuccessful)
function void (int weapon, bool bSuccessful);
};

View File

@ -44,7 +44,7 @@
* @param delay Delay in seconds? before the event gets fired.
* @noreturn
*/
functag public void EntityOutput(const String:output[], caller, activator, Float:delay);
typedef EntityOutput = function void (const char[] output, int caller, int activator, float delay);
/**
* Add an entity output hook on a entity classname

View File

@ -283,7 +283,16 @@ native Float:GetDistGainFromSoundLevel(soundlevel, Float:distance);
* @return Plugin_Continue to allow the sound to be played, Plugin_Stop to block it,
* Plugin_Changed when any parameter has been modified.
*/
functag public Action:AmbientSHook(String:sample[PLATFORM_MAX_PATH], &entity, &Float:volume, &level, &pitch, Float:pos[3], &flags, &Float:delay);
typedef AmbientSHook = function Action (
char sample[PLATFORM_MAX_PATH],
int &entity,
float &volume,
int &level,
int &pitch,
float pos[3],
int &flags,
float &delay
);
/**
* Called when a sound is going to be emitted to one or more clients.
@ -301,7 +310,17 @@ functag public Action:AmbientSHook(String:sample[PLATFORM_MAX_PATH], &entity, &F
* @return Plugin_Continue to allow the sound to be played, Plugin_Stop to block it,
* Plugin_Changed when any parameter has been modified.
*/
functag public Action:NormalSHook(clients[64], &numClients, String:sample[PLATFORM_MAX_PATH], &entity, &channel, &Float:volume, &level, &pitch, &flags);
typedef NormalSHook = function Action (
int clients[64],
int &numClients,
char sample[PLATFORM_MAX_PATH],
int &entity,
int &channel,
float &volume,
int &level,
int &pitch,
int &flags
);
/**
* Hooks all played ambient sounds.

View File

@ -44,7 +44,7 @@
* @param delay Delay in seconds to send the TE.
* @return Plugin_Continue to allow the transmission of the TE, Plugin_Stop to block it.
*/
functag public Action:TEHook(const String:te_name[], const Players[], numClients, Float:delay);
typedef TEHook = function Action (const char[] te_name, const int[] Players, int numClients, float delay);
/**
* Hooks a temp entity.

View File

@ -110,7 +110,7 @@ enum RayType
RayType_Infinite /**< The trace ray will go from the start position to infinity using a direction vector. */
};
funcenum TraceEntityFilter
union TraceEntityFilter
{
/**
* Called on entity filtering.
@ -119,7 +119,7 @@ funcenum TraceEntityFilter
* @param contentsMask Contents Mask.
* @return True to allow the current entity to be hit, otherwise false.
*/
bool:public(entity, contentsMask),
function bool (int entity, int contentsMask);
/**
* Called on entity filtering.
@ -129,7 +129,7 @@ funcenum TraceEntityFilter
* @param data Data value, if used.
* @return True to allow the current entity to be hit, otherwise false.
*/
bool:public(entity, contentsMask, any:data),
function bool (int entity, int contentsMask, any data);
};
/**
@ -371,4 +371,4 @@ native TR_GetPlaneNormal(Handle:hndl, Float:normal[3]);
* @param pos Vector buffer to store data in.
* @return True if outside world, otherwise false.
*/
native TR_PointOutsideWorld(Float:pos[3]);
native TR_PointOutsideWorld(Float:pos[3]);

View File

@ -98,7 +98,7 @@ native SortStrings(String:array[][], array_size, SortOrder:order = Sort_Ascendin
* 0 if first is equal to second
* 1 if first should go after second
*/
functag public int SortFunc1D(elem1, elem2, const array[], Handle:hndl);
typedef SortFunc1D = function int (int elem1, int elem2, const int[] array, Handle hndl);
/**
* Sorts a custom 1D array. You must pass in a comparison function.
@ -123,10 +123,10 @@ native SortCustom1D(array[], array_size, SortFunc1D:sortfunc, Handle:hndl=INVALI
* 0 if first is equal to second
* 1 if first should go after second
*/
funcenum SortFunc2D
union SortFunc2D
{
public(elem1[], elem2[], const array[][], Handle:hndl),
public(String:elem1[], String:elem2[], const String:array[][], Handle:hndl),
function int (int[] elem1, int[] elem2, const int[][] array, Handle hndl);
function int (char[] elem1, char[] elem2, const char[][] array, Handle hndl);
};
/**
@ -163,7 +163,7 @@ native SortADTArray(Handle:array, SortOrder:order, SortType:type);
* 0 if first is equal to second
* 1 if first should go after second
*/
functag public int SortFuncADTArray(index1, index2, Handle:array, Handle:hndl);
typedef SortFuncADTArray = function int (int index1, int index2, Handle array, Handle hndl);
/**
* Custom sorts an ADT Array. You must pass in a comparison function.
@ -173,4 +173,4 @@ functag public int SortFuncADTArray(index1, index2, Handle:array, Handle:hndl);
* @param hndl Optional Handle to pass through the comparison calls.
* @noreturn
*/
native SortADTArrayCustom(Handle:array, SortFuncADTArray:sortfunc, Handle:hndl=INVALID_HANDLE);
native SortADTArrayCustom(Handle:array, SortFuncADTArray:sortfunc, Handle:hndl=INVALID_HANDLE);

View File

@ -108,7 +108,7 @@ native bool:SMC_GetErrorString(SMCError:error, String:buffer[], buf_max);
* @param smc The SMC Parse Handle.
* @noreturn
*/
functag public void SMC_ParseStart(Handle:smc);
typedef SMC_ParseStart = function void (Handle smc);
/**
* Sets the SMC_ParseStart function of a parse Handle.
@ -128,7 +128,7 @@ native SMC_SetParseStart(Handle:smc, SMC_ParseStart:func);
* @param failed True if parsing failed, false otherwise.
* @noreturn
*/
functag public void SMC_ParseEnd(Handle:smc, bool:halted, bool:failed);
typedef SMC_ParseEnd = function void (Handle smc, bool halted, bool failed);
/**
* Sets the SMC_ParseEnd of a parse handle.
@ -149,7 +149,7 @@ native SMC_SetParseEnd(Handle:smc, SMC_ParseEnd:func);
* @param opt_quotes True if the section name was quote-enclosed in the file.
* @return An SMCResult action to take.
*/
functag public SMCResult:SMC_NewSection(Handle:smc, const String:name[], bool:opt_quotes);
typedef SMC_NewSection = function SMCResult (Handle smc, const char[] name, bool opt_quotes);
/**
* Called when the parser finds a new key/value pair.
@ -162,7 +162,7 @@ functag public SMCResult:SMC_NewSection(Handle:smc, const String:name[], bool:op
* @param value_quotes Whether or not the value was enclosed in quotes.
* @return An SMCResult action to take.
*/
functag public SMCResult:SMC_KeyValue(Handle:smc, const String:key[], const String:value[], bool:key_quotes, bool:value_quotes);
typedef SMC_KeyValue = function SMCResult (Handle smc, const char[] key, const char[] value, bool key_quotes, bool value_quotes);
/**
* Called when the parser finds the end of the current section.
@ -170,7 +170,7 @@ functag public SMCResult:SMC_KeyValue(Handle:smc, const String:key[], const Stri
* @param smc The SMC Parse Handle.
* @return An SMCResult action to take.
*/
functag public SMCResult:SMC_EndSection(Handle:smc);
typedef SMC_EndSection = function SMCResult (Handle smc);
/**
* Sets the three main reader functions.
@ -191,7 +191,7 @@ native SMC_SetReaders(Handle:smc, SMC_NewSection:ns, SMC_KeyValue:kv, SMC_EndSec
* @param lineno The line number it occurs on.
* @return An SMCResult action to take.
*/
functag public SMCResult:SMC_RawLine(Handle:smc, const String:line[], lineno);
typedef SMC_RawLine = function SMCResult (Handle smc, const char[] line, int lineno);
/**
* Sets a raw line reader on an SMC parser Handle.

View File

@ -153,6 +153,10 @@ enum TFCond
TFCond_HalloweenTiny,
TFCond_HalloweenInHell,
TFCond_HalloweenGhostMode,
TFCond_DodgeChance = 79,
TFCond_Parachute,
TFCond_BlastJumping,
};
const Float:TFCondDuration_Infinite = -1.0;
@ -447,5 +451,6 @@ public __ext_tf2_SetNTVOptional()
MarkNativeAsOptional("TF2_GetClass");
MarkNativeAsOptional("TF2_IsPlayerInDuel");
MarkNativeAsOptional("TF2_IsHolidayActive");
MarkNativeAsOptional("TF2_RemoveWearable");
}
#endif

View File

@ -249,6 +249,7 @@ enum {
TF_WEAPON_SPELLBOOK,
TF_WEAPON_SPELLBOOK_PROJECTILE,
TF_WEAPON_SNIPERRIFLE_CLASSIC,
TF_WEAPON_PARACHUTE,
};
// TF2 Weapon Loadout Slots
@ -435,6 +436,20 @@ stock TF2_RemoveWeaponSlot(client, slot)
new weaponIndex;
while ((weaponIndex = GetPlayerWeaponSlot(client, slot)) != -1)
{
// bug #6206
// papering over a valve bug where a weapon's extra wearables aren't properly removed from the weapon's owner
new extraWearable = GetEntPropEnt(weaponIndex, Prop_Send, "m_hExtraWearable");
if (extraWearable != -1)
{
TF2_RemoveWearable(client, extraWearable);
}
extraWearable = GetEntPropEnt(weaponIndex, Prop_Send, "m_hExtraWearableViewModel");
if (extraWearable != -1)
{
TF2_RemoveWearable(client, extraWearable);
}
RemovePlayerItem(client, weaponIndex);
AcceptEntityInput(weaponIndex, "Kill");
}

View File

@ -45,7 +45,7 @@
/**
* Any of the following prototypes will work for a timed function.
*/
funcenum Timer
union Timer
{
/**
* Called when the timer interval has elapsed.
@ -55,7 +55,7 @@ funcenum Timer
* @return Plugin_Stop to stop a repeating timer, any other value for
* default behavior.
*/
Action:public(Handle:timer, Handle:hndl),
function Action(Handle timer, Handle hndl);
/**
* Called when the timer interval has elapsed.
@ -65,7 +65,7 @@ funcenum Timer
* @return Plugin_Stop to stop a repeating timer, any other value for
* default behavior.
*/
Action:public(Handle:timer, any:data),
function Action(Handle timer, any data);
/**
* Called when the timer interval has elapsed.
@ -74,7 +74,7 @@ funcenum Timer
* @return Plugin_Stop to stop a repeating timer, any other value for
* default behavior.
*/
Action:public(Handle:timer),
function Action(Handle timer);
};
/**

View File

@ -127,12 +127,14 @@ enum TopMenuObject
* @param maxlength Output buffer (if used).
* @noreturn
*/
functag public void TopMenuHandler(Handle:topmenu,
TopMenuAction:action,
TopMenuObject:topobj_id,
param,
String:buffer[],
maxlength);
typedef TopMenuHandler = function void (
Handle topmenu,
TopMenuAction action,
TopMenuObject topobj_id,
int param,
char[] buffer,
int maxlength
);
/**
* Creates a TopMenu.

View File

@ -140,7 +140,7 @@ native EndMessage();
* blocks the message from being sent, and Plugin_Continue
* resumes normal functionality.
*/
functag public Action:MsgHook(UserMsg:msg_id, Handle:msg, const players[], playersNum, bool:reliable, bool:init);
typedef MsgHook = function Action (UserMsg msg_id, Handle msg, const int[] players, int playersNum, bool reliable, bool init);
/**
* Called when a message hook has completed.
@ -149,7 +149,7 @@ functag public Action:MsgHook(UserMsg:msg_id, Handle:msg, const players[], playe
* @param sent True if message was sent, false if blocked.
* @noreturn
*/
functag public void MsgPostHook(UserMsg:msg_id, bool:sent);
typedef MsgPostHook = function void (UserMsg msg_id, bool sent);
/**
* Hooks a user message.

View File

@ -113,6 +113,13 @@ namespace SourceMod
* @return Pointer to the data, or NULL if out of bounds.
*/
virtual void *ReadMemory(size_t *size) const =0;
/**
* @brief Reads a function pointer from the data stream.
*
* @return A function pointer read from the current position.
*/
virtual cell_t ReadFunction() const =0;
};
/**
@ -160,6 +167,13 @@ namespace SourceMod
* @return Current position of the stream beforehand.
*/
virtual size_t CreateMemory(size_t size, void **addr) =0;
/**
* @brief Packs one function pointer into the data stream.
*
* @param function The function pointer to write.
*/
virtual void PackFunction(cell_t function) =0;
};
}

View File

@ -135,8 +135,9 @@ namespace SourceMod
*
* V6 - added TestFeature() to IShareSys.
* V7 - added OnDependenciesDropped() to IExtensionInterface.
* V8 - added OnCoreMapEnd() to IExtensionInterface.
*/
#define SMINTERFACE_EXTENSIONAPI_VERSION 7
#define SMINTERFACE_EXTENSIONAPI_VERSION 8
/**
* @brief The interface an extension must expose.
@ -325,6 +326,15 @@ namespace SourceMod
virtual void OnDependenciesDropped()
{
}
/**
* @brief Called on level shutdown
*
*/
virtual void OnCoreMapEnd()
{
}
};
/**

View File

@ -35,12 +35,15 @@
namespace ke {
// See the comment above Refcounted<T> for more information. This class is
// identical, except changing the reference count is guaranteed to be atomic
// with respect to other threads changing the reference count.
template <typename T>
class RefcountedThreadsafe
{
public:
RefcountedThreadsafe()
: refcount_(1)
: refcount_(0)
{
}

View File

@ -37,18 +37,28 @@ namespace ke {
template <typename T> class Ref;
// Holds a refcounted T without addrefing it. This is similar to PassRef<>
// below, but is intended only for freshly allocated objects which start
// with reference count 1, and we don't want to add an extra ref just by
// assigning to PassRef<> or Ref<>.
// Objects in AMTL inheriting from Refcounted will have an initial refcount
// of 0. However, in some systems (such as COM), the initial refcount is 1,
// or functions may return raw pointers that have been AddRef'd. In these
// cases it would be a mistake to use Ref<> or PassRef<>, since the object
// would leak an extra reference.
//
// This container holds a refcounted object without addrefing it. This is
// intended only for interacting with functions which return an object that
// has been manually AddRef'd. Note that this will perform a Release(), so
// so it is necessary to assign it to retain the object.
template <typename T>
class Newborn
class AlreadyRefed
{
public:
Newborn(T *t)
AlreadyRefed(T *t)
: thing_(t)
{
}
~AlreadyRefed() {
if (thing_)
thing_->Release();
}
T *release() const {
return ReturnAndVoid(thing_);
@ -59,10 +69,10 @@ class Newborn
};
template <typename T>
static inline Newborn<T>
NoAddRef(T *t)
static inline AlreadyRefed<T>
AdoptRef(T *t)
{
return Newborn<T>(t);
return AlreadyRefed<T>(t);
}
// When returning a value, we'd rather not be needlessly changing the refcount,
@ -81,7 +91,14 @@ class PassRef
{
}
PassRef(const Newborn<T *> &other)
PassRef(const AlreadyRefed<T *> &other)
: thing_(other.release())
{
// Don't addref, newborn means already addref'd.
}
template <typename S>
PassRef(const AlreadyRefed<S *> &other)
: thing_(other.release())
{
// Don't addref, newborn means already addref'd.
@ -134,7 +151,7 @@ class PassRef
private:
// Disallowed operators.
PassRef &operator =(T *other);
PassRef &operator =(Newborn<T> &other);
PassRef &operator =(AlreadyRefed<T> &other);
void AddRef() {
if (thing_)
@ -149,13 +166,18 @@ class PassRef
mutable T *thing_;
};
// Classes which are refcounted should inherit from this.
// Classes which are refcounted should inherit from this. Note that reference
// counts start at 0 in AMTL, rather than 1. This avoids the complexity of
// having to adopt the initial ref upon allocation. However, this also means
// invoking Release() on a newly allocated object is illegal. Newborn objects
// must either be assigned to a Ref or PassRef (NOT an AdoptRef/AlreadyRefed),
// or must be deleted using |delete|.
template <typename T>
class Refcounted
{
public:
Refcounted()
: refcount_(1)
: refcount_(0)
{
}
@ -217,7 +239,12 @@ class Ref
: thing_(other.release())
{
}
Ref(const Newborn<T> &other)
Ref(const AlreadyRefed<T> &other)
: thing_(other.release())
{
}
template <typename S>
Ref(const AlreadyRefed<S> &other)
: thing_(other.release())
{
}
@ -255,7 +282,7 @@ class Ref
}
template <typename S>
Ref &operator =(const Newborn<S> &other) {
Ref &operator =(const AlreadyRefed<S> &other) {
Release();
thing_ = other.release();
return *this;

View File

@ -1044,6 +1044,15 @@ namespace SourcePawn
* @param render Function to render any help messages.
*/
virtual void Stop(void (*render)(const char *fmt, ...)) = 0;
/**
* @brief Dump profiling information.
*
* Informs the profiling tool to dump any current profiling information
* it has accumulated. The format and location of the output is profiling
* tool specific.
*/
virtual void Dump() = 0;
/**
* @brief Returns whether or not the profiler is currently profiling.

View File

@ -36,8 +36,8 @@
* @file sp_vm_types.h
* @brief Contains all run-time SourcePawn structures.
*/
#include "sp_file_headers.h"
#include <stddef.h>
#include <stdint.h>
typedef uint32_t ucell_t; /**< Unsigned 32bit integer */
typedef int32_t cell_t; /**< Basic 32bit signed integer type for plugins */
@ -189,10 +189,25 @@ typedef struct sp_debug_line_s
uint32_t line; /**< Line number */
} sp_debug_line_t;
/**
* @brief These structures are equivalent.
*/
typedef sp_fdbg_arraydim_t sp_debug_arraydim_t;
// Occurs after an fdbg_symbol entry, for each dimension.
typedef struct sp_debug_arraydim_s
{
int16_t tagid; /**< Tag id */
uint32_t size; /**< Size of dimension */
} sp_debug_arraydim_t;
// Same as from <smx/smx-v1-headers.h>.
typedef struct sp_debug_symbol_raw_s
{
int32_t addr; /**< Address rel to DAT or stack frame */
int16_t tagid; /**< Tag id */
uint32_t codestart; /**< Start scope validity in code */
uint32_t codeend; /**< End scope validity in code */
uint8_t ident; /**< Variable type */
uint8_t vclass; /**< Scope class (local vs global) */
uint16_t dimcount; /**< Dimension count (for arrays) */
uint32_t name; /**< Offset into debug nametable */
} sp_debug_symbol_raw_t;
/**
* @brief The majority of this struct is already located in the parent
@ -200,11 +215,11 @@ typedef sp_fdbg_arraydim_t sp_debug_arraydim_t;
*/
typedef struct sp_debug_symbol_s
{
uint32_t codestart; /**< Relocated code address */
uint32_t codeend; /**< Relocated code end address */
const char * name; /**< Relocated name */
sp_debug_arraydim_t *dims; /**< Relocated dimension struct, if any */
sp_fdbg_symbol_t *sym; /**< Pointer to original symbol */
uint32_t codestart; /**< Relocated code address */
uint32_t codeend; /**< Relocated code end address */
const char * name; /**< Relocated name */
sp_debug_arraydim_t *dims; /**< Relocated dimension struct, if any */
sp_debug_symbol_raw_t *sym; /**< Pointer to original symbol */
} sp_debug_symbol_t;
#endif //_INCLUDE_SOURCEPAWN_VM_TYPES_H

View File

@ -42,6 +42,7 @@ binary = SM.Program(builder, 'spcomp')
compiler = binary.compiler
compiler.includes += [
os.path.join(builder.sourcePath, 'public'),
os.path.join(builder.sourcePath, 'public', 'amtl'),
os.path.join(builder.sourcePath, 'public', 'sourcepawn'),
os.path.join(builder.sourcePath, 'sourcepawn', 'compiler'),
os.path.join(builder.buildPath, 'includes'),
@ -50,7 +51,8 @@ compiler.includes += [
compiler.sourcedeps += packed_includes
if compiler.cc.behavior == 'gcc':
compiler.cflags += ['-std=c99', '-Wno-format']
compiler.cflags += ['-Wno-format']
compiler.c_only_flags += ['-std=c99']
if builder.target_platform == 'linux':
compiler.postlink += ['-lgcc', '-lm']
elif compiler.cc.behavior == 'msvc':
@ -58,10 +60,10 @@ elif compiler.cc.behavior == 'msvc':
compiler.linkflags.append('/SUBSYSTEM:CONSOLE')
compiler.cxxflags.remove('/TP')
compiler.defines += ['HAVE_STDINT_H']
if builder.target_platform == 'linux':
compiler.defines += [
'LINUX',
'HAVE_STDINT_H',
'AMX_ANSIONLY',
'ENABLE_BINRELOC',
'_GNU_SOURCE'
@ -69,32 +71,31 @@ if builder.target_platform == 'linux':
elif builder.target_platform == 'mac':
compiler.defines += [
'DARWIN',
'HAVE_STDINT_H',
'AMX_ANSIONLY',
'ENABLE_BINRELOC',
'HAVE_SAFESTR'
]
binary.sources += [
'libpawnc.c',
'lstring.c',
'memfile.c',
'pawncc.c',
'sc1.c',
'sc2.c',
'sc3.c',
'sc4.c',
'sc5.c',
'sc6.c',
'sc7.c',
'scexpand.c',
'sci18n.c',
'sclist.c',
'scmemfil.c',
'scstate.c',
'sctracker.c',
'scvars.c',
'sp_file.c',
'libpawnc.cpp',
'lstring.cpp',
'memfile.cpp',
'pawncc.cpp',
'sc1.cpp',
'sc2.cpp',
'sc3.cpp',
'sc4.cpp',
'sc5.cpp',
'sc6.cpp',
'sc7.cpp',
'scexpand.cpp',
'sci18n.cpp',
'sclist.cpp',
'scmemfil.cpp',
'scstate.cpp',
'sctracker.cpp',
'scvars.cpp',
'sp_file.cpp',
'zlib/adler32.c',
'zlib/compress.c',
'zlib/crc32.c',
@ -107,7 +108,7 @@ binary.sources += [
'zlib/trees.c',
'zlib/uncompr.c',
'zlib/zutil.c',
'sp_symhash.c'
'sp_symhash.cpp'
]
if builder.target_platform != 'windows':
binary.sources.append('binreloc.c')

View File

@ -34,8 +34,12 @@
#include <sclinux.h>
#endif
#if defined HAVE_STDINT_H
# include <stddef.h>
# include <stdint.h>
#endif
#if defined __GNUC__
#include <stdint.h>
#if !defined HAVE_STDINT_H
#define HAVE_STDINT_H
#endif

View File

@ -1,173 +1,173 @@
/* Abstract Machine for the Pawn compiler, debugger support
*
* This file contains extra definitions that are convenient for debugger
* support.
*
* Copyright (c) ITB CompuPhase, 2005
*
* This software is provided "as-is", without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software in
* a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
* Version: $Id$
*/
#ifndef AMXDBG_H_INCLUDED
#define AMXDBG_H_INCLUDED
#ifndef AMX_H_INCLUDED
#include "amx.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
/* Some compilers do not support the #pragma align, which should be fine. Some
* compilers give a warning on unknown #pragmas, which is not so fine...
*/
#if defined SN_TARGET_PS2 || defined __GNUC__
#define AMX_NO_ALIGN
#endif
#if defined __GNUC__
#define PACKED __attribute__((packed))
#else
#define PACKED
#endif
#if !defined AMX_NO_ALIGN
#if defined LINUX || defined __FreeBSD__
#pragma pack(1) /* structures must be packed (byte-aligned) */
#elif defined MACOS && defined __MWERKS__
#pragma options align=mac68k
#else
#pragma pack(push)
#pragma pack(1) /* structures must be packed (byte-aligned) */
#if defined __TURBOC__
#pragma option -a- /* "pack" pragma for older Borland compilers */
#endif
#endif
#endif
typedef struct tagAMX_DBG_HDR {
int32_t size PACKED; /* size of the debug information chunk */
uint16_t magic PACKED; /* signature, must be 0xf1ef */
char file_version; /* file format version */
char amx_version; /* required version of the AMX */
int16_t flags PACKED; /* currently unused */
int16_t files PACKED; /* number of entries in the "file" table */
int32_t lines PACKED; /* number of entries in the "line" table */
int32_t symbols PACKED; /* number of entries in the "symbol" table */
int16_t tags PACKED; /* number of entries in the "tag" table */
int16_t automatons PACKED; /* number of entries in the "automaton" table */
int16_t states PACKED; /* number of entries in the "state" table */
} PACKED AMX_DBG_HDR;
#define AMX_DBG_MAGIC 0xf1ef
typedef struct tagAMX_DBG_FILE {
ucell address PACKED; /* address in the code segment where generated code (for this file) starts */
const char name[1]; /* ASCII string, zero-terminated */
} PACKED AMX_DBG_FILE;
typedef struct tagAMX_DBG_LINE {
ucell address PACKED; /* address in the code segment where generated code (for this line) starts */
int32_t line PACKED; /* line number */
} PACKED AMX_DBG_LINE;
typedef struct tagAMX_DBG_SYMBOL {
ucell address PACKED; /* address in the data segment or relative to the frame */
int16_t tag PACKED; /* tag for the symbol */
ucell codestart PACKED; /* address in the code segment from which this symbol is valid (in scope) */
ucell codeend PACKED; /* address in the code segment until which this symbol is valid (in scope) */
char ident; /* kind of symbol (function/variable) */
char vclass; /* class of symbol (global/local) */
int16_t dim PACKED; /* number of dimensions */
const char name[1]; /* ASCII string, zero-terminated */
} PACKED AMX_DBG_SYMBOL;
typedef struct tagAMX_DBG_SYMDIM {
int16_t tag PACKED; /* tag for the array dimension */
ucell size PACKED; /* size of the array dimension */
} PACKED AMX_DBG_SYMDIM;
typedef struct tagAMX_DBG_TAG {
int16_t tag PACKED; /* tag id */
const char name[1]; /* ASCII string, zero-terminated */
} PACKED AMX_DBG_TAG;
typedef struct tagAMX_DBG_MACHINE {
int16_t automaton PACKED; /* automaton id */
ucell address PACKED; /* address of state variable */
const char name[1]; /* ASCII string, zero-terminated */
} PACKED AMX_DBG_MACHINE;
typedef struct tagAMX_DBG_STATE {
int16_t state PACKED; /* state id */
int16_t automaton PACKED; /* automaton id */
const char name[1]; /* ASCII string, zero-terminated */
} PACKED AMX_DBG_STATE;
typedef struct tagAMX_DBG {
AMX_DBG_HDR _FAR *hdr PACKED; /* points to the AMX_DBG header */
AMX_DBG_FILE _FAR **filetbl PACKED;
AMX_DBG_LINE _FAR *linetbl PACKED;
AMX_DBG_SYMBOL _FAR **symboltbl PACKED;
AMX_DBG_TAG _FAR **tagtbl PACKED;
AMX_DBG_MACHINE _FAR **automatontbl PACKED;
AMX_DBG_STATE _FAR **statetbl PACKED;
} PACKED AMX_DBG;
#if !defined iVARIABLE
#define iVARIABLE 1 /* cell that has an address and that can be fetched directly (lvalue) */
#define iREFERENCE 2 /* iVARIABLE, but must be dereferenced */
#define iARRAY 3
#define iREFARRAY 4 /* an array passed by reference (i.e. a pointer) */
#define iFUNCTN 9
#endif
int AMXAPI dbg_FreeInfo(AMX_DBG *amxdbg);
int AMXAPI dbg_LoadInfo(AMX_DBG *amxdbg, void *dbg_addr);
int AMXAPI dbg_LookupFile(AMX_DBG *amxdbg, ucell address, const char **filename);
int AMXAPI dbg_LookupFunction(AMX_DBG *amxdbg, ucell address, const char **funcname);
int AMXAPI dbg_LookupLine(AMX_DBG *amxdbg, ucell address, long *line);
int AMXAPI dbg_GetFunctionAddress(AMX_DBG *amxdbg, const char *funcname, const char *filename, ucell *address);
int AMXAPI dbg_GetLineAddress(AMX_DBG *amxdbg, long line, const char *filename, ucell *address);
int AMXAPI dbg_GetAutomatonName(AMX_DBG *amxdbg, int automaton, const char **name);
int AMXAPI dbg_GetStateName(AMX_DBG *amxdbg, int state, const char **name);
int AMXAPI dbg_GetTagName(AMX_DBG *amxdbg, int tag, const char **name);
int AMXAPI dbg_GetVariable(AMX_DBG *amxdbg, const char *symname, ucell scopeaddr, const AMX_DBG_SYMBOL **sym);
int AMXAPI dbg_GetArrayDim(AMX_DBG *amxdbg, const AMX_DBG_SYMBOL *sym, const AMX_DBG_SYMDIM **symdim);
#if !defined AMX_NO_ALIGN
#if defined LINUX || defined __FreeBSD__
#pragma pack() /* reset default packing */
#elif defined MACOS && defined __MWERKS__
#pragma options align=reset
#else
#pragma pack(pop) /* reset previous packing */
#endif
#endif
#ifdef __cplusplus
}
#endif
#endif /* AMXDBG_H_INCLUDED */
/* Abstract Machine for the Pawn compiler, debugger support
*
* This file contains extra definitions that are convenient for debugger
* support.
*
* Copyright (c) ITB CompuPhase, 2005
*
* This software is provided "as-is", without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software in
* a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
* Version: $Id$
*/
#ifndef AMXDBG_H_INCLUDED
#define AMXDBG_H_INCLUDED
#ifndef AMX_H_INCLUDED
#include "amx.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
/* Some compilers do not support the #pragma align, which should be fine. Some
* compilers give a warning on unknown #pragmas, which is not so fine...
*/
#if defined SN_TARGET_PS2 || defined __GNUC__
#define AMX_NO_ALIGN
#endif
#if defined __GNUC__
#define PACKED __attribute__((packed))
#else
#define PACKED
#endif
#if !defined AMX_NO_ALIGN
#if defined LINUX || defined __FreeBSD__
#pragma pack(1) /* structures must be packed (byte-aligned) */
#elif defined MACOS && defined __MWERKS__
#pragma options align=mac68k
#else
#pragma pack(push)
#pragma pack(1) /* structures must be packed (byte-aligned) */
#if defined __TURBOC__
#pragma option -a- /* "pack" pragma for older Borland compilers */
#endif
#endif
#endif
typedef struct tagAMX_DBG_HDR {
int32_t size PACKED; /* size of the debug information chunk */
uint16_t magic PACKED; /* signature, must be 0xf1ef */
char file_version; /* file format version */
char amx_version; /* required version of the AMX */
int16_t flags PACKED; /* currently unused */
int16_t files PACKED; /* number of entries in the "file" table */
int32_t lines PACKED; /* number of entries in the "line" table */
int32_t symbols PACKED; /* number of entries in the "symbol" table */
int16_t tags PACKED; /* number of entries in the "tag" table */
int16_t automatons PACKED; /* number of entries in the "automaton" table */
int16_t states PACKED; /* number of entries in the "state" table */
} PACKED AMX_DBG_HDR;
#define AMX_DBG_MAGIC 0xf1ef
typedef struct tagAMX_DBG_FILE {
ucell address PACKED; /* address in the code segment where generated code (for this file) starts */
char name[1]; /* ASCII string, zero-terminated */
} PACKED AMX_DBG_FILE;
typedef struct tagAMX_DBG_LINE {
ucell address PACKED; /* address in the code segment where generated code (for this line) starts */
int32_t line PACKED; /* line number */
} PACKED AMX_DBG_LINE;
typedef struct tagAMX_DBG_SYMBOL {
ucell address PACKED; /* address in the data segment or relative to the frame */
int16_t tag PACKED; /* tag for the symbol */
ucell codestart PACKED; /* address in the code segment from which this symbol is valid (in scope) */
ucell codeend PACKED; /* address in the code segment until which this symbol is valid (in scope) */
char ident; /* kind of symbol (function/variable) */
char vclass; /* class of symbol (global/local) */
int16_t dim PACKED; /* number of dimensions */
char name[1]; /* ASCII string, zero-terminated */
} PACKED AMX_DBG_SYMBOL;
typedef struct tagAMX_DBG_SYMDIM {
int16_t tag PACKED; /* tag for the array dimension */
ucell size PACKED; /* size of the array dimension */
} PACKED AMX_DBG_SYMDIM;
typedef struct tagAMX_DBG_TAG {
int16_t tag PACKED; /* tag id */
char name[1]; /* ASCII string, zero-terminated */
} PACKED AMX_DBG_TAG;
typedef struct tagAMX_DBG_MACHINE {
int16_t automaton PACKED; /* automaton id */
ucell address PACKED; /* address of state variable */
char name[1]; /* ASCII string, zero-terminated */
} PACKED AMX_DBG_MACHINE;
typedef struct tagAMX_DBG_STATE {
int16_t state PACKED; /* state id */
int16_t automaton PACKED; /* automaton id */
char name[1]; /* ASCII string, zero-terminated */
} PACKED AMX_DBG_STATE;
typedef struct tagAMX_DBG {
AMX_DBG_HDR _FAR *hdr PACKED; /* points to the AMX_DBG header */
AMX_DBG_FILE _FAR **filetbl PACKED;
AMX_DBG_LINE _FAR *linetbl PACKED;
AMX_DBG_SYMBOL _FAR **symboltbl PACKED;
AMX_DBG_TAG _FAR **tagtbl PACKED;
AMX_DBG_MACHINE _FAR **automatontbl PACKED;
AMX_DBG_STATE _FAR **statetbl PACKED;
} PACKED AMX_DBG;
#if !defined iVARIABLE
#define iVARIABLE 1 /* cell that has an address and that can be fetched directly (lvalue) */
#define iREFERENCE 2 /* iVARIABLE, but must be dereferenced */
#define iARRAY 3
#define iREFARRAY 4 /* an array passed by reference (i.e. a pointer) */
#define iFUNCTN 9
#endif
int AMXAPI dbg_FreeInfo(AMX_DBG *amxdbg);
int AMXAPI dbg_LoadInfo(AMX_DBG *amxdbg, void *dbg_addr);
int AMXAPI dbg_LookupFile(AMX_DBG *amxdbg, ucell address, const char **filename);
int AMXAPI dbg_LookupFunction(AMX_DBG *amxdbg, ucell address, const char **funcname);
int AMXAPI dbg_LookupLine(AMX_DBG *amxdbg, ucell address, long *line);
int AMXAPI dbg_GetFunctionAddress(AMX_DBG *amxdbg, const char *funcname, const char *filename, ucell *address);
int AMXAPI dbg_GetLineAddress(AMX_DBG *amxdbg, long line, const char *filename, ucell *address);
int AMXAPI dbg_GetAutomatonName(AMX_DBG *amxdbg, int automaton, const char **name);
int AMXAPI dbg_GetStateName(AMX_DBG *amxdbg, int state, const char **name);
int AMXAPI dbg_GetTagName(AMX_DBG *amxdbg, int tag, const char **name);
int AMXAPI dbg_GetVariable(AMX_DBG *amxdbg, const char *symname, ucell scopeaddr, const AMX_DBG_SYMBOL **sym);
int AMXAPI dbg_GetArrayDim(AMX_DBG *amxdbg, const AMX_DBG_SYMBOL *sym, const AMX_DBG_SYMDIM **symdim);
#if !defined AMX_NO_ALIGN
#if defined LINUX || defined __FreeBSD__
#pragma pack() /* reset default packing */
#elif defined MACOS && defined __MWERKS__
#pragma options align=reset
#else
#pragma pack(pop) /* reset previous packing */
#endif
#endif
#ifdef __cplusplus
}
#endif
#endif /* AMXDBG_H_INCLUDED */

View File

@ -1,409 +0,0 @@
// vim: set sts=8 ts=4 sw=4 tw=99 noet:
/* LIBPAWNC.C
*
* A "glue file" for building the Pawn compiler as a DLL or shared library.
*
* Copyright (c) ITB CompuPhase, 2000-2006
*
* This software is provided "as-is", without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software in
* a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
* Version: $Id$
*/
#include <assert.h>
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include "sc.h"
#include "memfile.h"
#if defined LINUX || defined __FreeBSD__ || defined __OpenBSD__ || defined DARWIN
#include <sys/types.h>
#include <sys/stat.h>
#endif
/* pc_printf()
* Called for general purpose "console" output. This function prints general
* purpose messages; errors go through pc_error(). The function is modelled
* after printf().
*/
int pc_printf(const char *message,...)
{
int ret;
va_list argptr;
va_start(argptr,message);
ret=vprintf(message,argptr);
va_end(argptr);
return ret;
}
/* pc_error()
* Called for producing error output.
* number the error number (as documented in the manual)
* message a string describing the error with embedded %d and %s tokens
* filename the name of the file currently being parsed
* firstline the line number at which the expression started on which
* the error was found, or -1 if there is no "starting line"
* lastline the line number at which the error was detected
* argptr a pointer to the first of a series of arguments (for macro
* "va_arg")
* Return:
* If the function returns 0, the parser attempts to continue compilation.
* On a non-zero return value, the parser aborts.
*/
int pc_error(int number,char *message,char *filename,int firstline,int lastline,va_list argptr)
{
static char *prefix[3]={ "error", "fatal error", "warning" };
if (number!=0) {
char *pre;
int idx;
if (number < 160)
idx = 0;
else if (number < 200)
idx = 1;
else
idx = 2;
pre=prefix[idx];
if (firstline>=0)
fprintf(stdout,"%s(%d -- %d) : %s %03d: ",filename,firstline,lastline,pre,number);
else
fprintf(stdout,"%s(%d) : %s %03d: ",filename,lastline,pre,number);
} /* if */
vfprintf(stdout,message,argptr);
fflush(stdout);
return 0;
}
typedef struct src_file_s {
FILE *fp; // Set if writing.
char *buffer; // IO buffer.
char *pos; // IO position.
char *end; // End of buffer.
size_t maxlength; // Maximum length of the writable buffer.
} src_file_t;
/* pc_opensrc()
* Opens a source file (or include file) for reading. The "file" does not have
* to be a physical file, one might compile from memory.
* filename the name of the "file" to read from
* Return:
* The function must return a pointer, which is used as a "magic cookie" to
* all I/O functions. When failing to open the file for reading, the
* function must return NULL.
* Note:
* Several "source files" may be open at the same time. Specifically, one
* file can be open for reading and another for writing.
*/
void *pc_opensrc(char *filename)
{
FILE *fp = NULL;
long length;
src_file_t *src = NULL;
#if defined LINUX || defined __FreeBSD__ || defined __OpenBSD__ || defined DARWIN
struct stat fileInfo;
if (stat(filename, &fileInfo) != 0) {
return NULL;
}
if (S_ISDIR(fileInfo.st_mode)) {
return NULL;
}
#endif
if ((fp = fopen(filename, "rb")) == NULL)
return NULL;
if (fseek(fp, 0, SEEK_END) == -1)
goto err;
if ((length = ftell(fp)) == -1)
goto err;
if (fseek(fp, 0, SEEK_SET) == -1)
goto err;
if ((src = (src_file_t *)calloc(1, sizeof(src_file_t))) == NULL)
goto err;
if ((src->buffer = (char *)calloc(length, sizeof(char))) == NULL)
goto err;
if (fread(src->buffer, length, 1, fp) != 1)
goto err;
src->pos = src->buffer;
src->end = src->buffer + length;
fclose(fp);
return src;
err:
pc_closesrc(src);
fclose(fp);
return NULL;
}
/* pc_createsrc()
* Creates/overwrites a source file for writing. The "file" does not have
* to be a physical file, one might compile from memory.
* filename the name of the "file" to create
* Return:
* The function must return a pointer which is used as a "magic cookie" to
* all I/O functions. When failing to open the file for reading, the
* function must return NULL.
* Note:
* Several "source files" may be open at the same time. Specifically, one
* file can be open for reading and another for writing.
*/
void *pc_createsrc(char *filename)
{
src_file_t *src = (src_file_t *)calloc(1, sizeof(src_file_t));
if (!src)
return NULL;
if ((src->fp = fopen(filename, "wt")) == NULL) {
pc_closesrc(src);
return NULL;
}
src->maxlength = 1024;
if ((src->buffer = (char *)calloc(1, src->maxlength)) == NULL) {
pc_closesrc(src);
return NULL;
}
src->pos = src->buffer;
src->end = src->buffer + src->maxlength;
return src;
}
/* pc_closesrc()
* Closes a source file (or include file). The "handle" parameter has the
* value that pc_opensrc() returned in an earlier call.
*/
void pc_closesrc(void *handle)
{
src_file_t *src = (src_file_t *)handle;
if (!src)
return;
if (src->fp) {
fwrite(src->buffer, src->pos - src->buffer, 1, src->fp);
fclose(src->fp);
}
free(src->buffer);
free(src);
}
/* pc_readsrc()
* Reads a single line from the source file (or up to a maximum number of
* characters if the line in the input file is too long).
*/
char *pc_readsrc(void *handle,unsigned char *target,int maxchars)
{
src_file_t *src = (src_file_t *)handle;
char *outptr = (char *)target;
char *outend = outptr + maxchars;
assert(!src->fp);
if (src->pos == src->end)
return NULL;
while (outptr < outend && src->pos < src->end) {
char c = *src->pos++;
*outptr++ = c;
if (c == '\n')
break;
if (c == '\r') {
// Handle CRLF.
if (src->pos < src->end && *src->pos == '\n') {
src->pos++;
if (outptr < outend)
*outptr++ = '\n';
}
break;
}
}
// Caller passes in a buffer of size >= maxchars+1.
*outptr = '\0';
return (char *)target;
}
/* pc_writesrc()
* Writes to to the source file. There is no automatic line ending; to end a
* line, write a "\n".
*/
int pc_writesrc(void *handle,unsigned char *source)
{
char *str = (char *)source;
size_t len = strlen(str);
src_file_t *src = (src_file_t *)handle;
assert(src->fp && src->maxlength);
if (src->pos + len > src->end) {
char *newbuf;
size_t newmax = src->maxlength;
size_t newlen = (src->pos - src->buffer) + len;
while (newmax < newlen) {
// Grow by 1.5X
newmax += newmax + newmax / 2;
if (newmax < src->maxlength)
abort();
}
newbuf = (char *)realloc(src->buffer, newmax);
if (!newbuf)
abort();
src->pos = newbuf + (src->pos - src->buffer);
src->end = newbuf + newmax;
src->buffer = newbuf;
src->maxlength = newmax;
}
strcpy(src->pos, str);
src->pos += len;
return 0;
}
void *pc_getpossrc(void *handle,void *position)
{
src_file_t *src = (src_file_t *)handle;
assert(!src->fp);
return (void *)(ptrdiff_t)(src->pos - src->buffer);
}
/* pc_resetsrc()
* "position" may only hold a pointer that was previously obtained from
* pc_getpossrc()
*/
void pc_resetsrc(void *handle,void *position)
{
src_file_t *src = (src_file_t *)handle;
ptrdiff_t pos = (ptrdiff_t)position;
assert(!src->fp);
assert(pos >= 0 && src->buffer + pos <= src->end);
src->pos = src->buffer + pos;
}
int pc_eofsrc(void *handle)
{
src_file_t *src = (src_file_t *)handle;
assert(!src->fp);
return src->pos == src->end;
}
/* should return a pointer, which is used as a "magic cookie" to all I/O
* functions; return NULL for failure
*/
void *pc_openasm(char *filename)
{
#if defined __MSDOS__ || defined SC_LIGHT
return fopen(filename,"w+t");
#else
return mfcreate(filename);
#endif
}
void pc_closeasm(void *handle, int deletefile)
{
#if defined __MSDOS__ || defined SC_LIGHT
if (handle!=NULL)
fclose((FILE*)handle);
if (deletefile)
remove(outfname);
#else
if (handle!=NULL) {
if (!deletefile)
mfdump((MEMFILE*)handle);
mfclose((MEMFILE*)handle);
} /* if */
#endif
}
void pc_resetasm(void *handle)
{
assert(handle!=NULL);
#if defined __MSDOS__ || defined SC_LIGHT
fflush((FILE*)handle);
fseek((FILE*)handle,0,SEEK_SET);
#else
mfseek((MEMFILE*)handle,0,SEEK_SET);
#endif
}
int pc_writeasm(void *handle,char *string)
{
#if defined __MSDOS__ || defined SC_LIGHT
return fputs(string,(FILE*)handle) >= 0;
#else
return mfputs((MEMFILE*)handle,string);
#endif
}
char *pc_readasm(void *handle, char *string, int maxchars)
{
#if defined __MSDOS__ || defined SC_LIGHT
return fgets(string,maxchars,(FILE*)handle);
#else
return mfgets((MEMFILE*)handle,string,maxchars);
#endif
}
extern memfile_t *bin_file;
/* Should return a pointer, which is used as a "magic cookie" to all I/O
* functions; return NULL for failure.
*/
void *pc_openbin(char *filename)
{
return memfile_creat(filename, 1);
}
void pc_closebin(void *handle,int deletefile)
{
if (deletefile)
{
memfile_destroy((memfile_t *)handle);
bin_file = NULL;
} else {
bin_file = (memfile_t *)handle;
}
}
/* pc_resetbin()
* Can seek to any location in the file.
* The offset is always from the start of the file.
*/
void pc_resetbin(void *handle,long offset)
{
memfile_seek((memfile_t *)handle, offset);
}
int pc_writebin(void *handle,void *buffer,int size)
{
return memfile_write((memfile_t *)handle, buffer, size);
}
long pc_lengthbin(void *handle)
{
return memfile_tell((memfile_t *)handle);
}

View File

@ -0,0 +1,382 @@
// vim: set sts=8 ts=4 sw=4 tw=99 noet:
/* LIBPAWNC.C
*
* A "glue file" for building the Pawn compiler as a DLL or shared library.
*
* Copyright (c) ITB CompuPhase, 2000-2006
*
* This software is provided "as-is", without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software in
* a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
* Version: $Id$
*/
#include <assert.h>
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include "sc.h"
#include "memfile.h"
#if defined LINUX || defined __FreeBSD__ || defined __OpenBSD__ || defined DARWIN
#include <sys/types.h>
#include <sys/stat.h>
#endif
/* pc_printf()
* Called for general purpose "console" output. This function prints general
* purpose messages; errors go through pc_error(). The function is modelled
* after printf().
*/
int pc_printf(const char *message,...)
{
int ret;
va_list argptr;
va_start(argptr,message);
ret=vprintf(message,argptr);
va_end(argptr);
return ret;
}
/* pc_error()
* Called for producing error output.
* number the error number (as documented in the manual)
* message a string describing the error with embedded %d and %s tokens
* filename the name of the file currently being parsed
* firstline the line number at which the expression started on which
* the error was found, or -1 if there is no "starting line"
* lastline the line number at which the error was detected
* argptr a pointer to the first of a series of arguments (for macro
* "va_arg")
* Return:
* If the function returns 0, the parser attempts to continue compilation.
* On a non-zero return value, the parser aborts.
*/
int pc_error(int number,const char *message,const char *filename,int firstline,int lastline,va_list argptr)
{
static const char *prefix[3]={ "error", "fatal error", "warning" };
if (number!=0) {
int idx;
if (number < 160)
idx = 0;
else if (number < 200)
idx = 1;
else
idx = 2;
const char *pre=prefix[idx];
if (firstline>=0)
fprintf(stdout,"%s(%d -- %d) : %s %03d: ",filename,firstline,lastline,pre,number);
else
fprintf(stdout,"%s(%d) : %s %03d: ",filename,lastline,pre,number);
} /* if */
vfprintf(stdout,message,argptr);
fflush(stdout);
return 0;
}
typedef struct src_file_s {
FILE *fp; // Set if writing.
char *buffer; // IO buffer.
char *pos; // IO position.
char *end; // End of buffer.
size_t maxlength; // Maximum length of the writable buffer.
} src_file_t;
/* pc_opensrc()
* Opens a source file (or include file) for reading. The "file" does not have
* to be a physical file, one might compile from memory.
* filename the name of the "file" to read from
* Return:
* The function must return a pointer, which is used as a "magic cookie" to
* all I/O functions. When failing to open the file for reading, the
* function must return NULL.
* Note:
* Several "source files" may be open at the same time. Specifically, one
* file can be open for reading and another for writing.
*/
void *pc_opensrc(char *filename)
{
FILE *fp = NULL;
long length;
src_file_t *src = NULL;
#if defined LINUX || defined __FreeBSD__ || defined __OpenBSD__ || defined DARWIN
struct stat fileInfo;
if (stat(filename, &fileInfo) != 0) {
return NULL;
}
if (S_ISDIR(fileInfo.st_mode)) {
return NULL;
}
#endif
if ((fp = fopen(filename, "rb")) == NULL)
return NULL;
if (fseek(fp, 0, SEEK_END) == -1)
goto err;
if ((length = ftell(fp)) == -1)
goto err;
if (fseek(fp, 0, SEEK_SET) == -1)
goto err;
if ((src = (src_file_t *)calloc(1, sizeof(src_file_t))) == NULL)
goto err;
if ((src->buffer = (char *)calloc(length, sizeof(char))) == NULL)
goto err;
if (fread(src->buffer, length, 1, fp) != 1)
goto err;
src->pos = src->buffer;
src->end = src->buffer + length;
fclose(fp);
return src;
err:
pc_closesrc(src);
fclose(fp);
return NULL;
}
/* pc_createsrc()
* Creates/overwrites a source file for writing. The "file" does not have
* to be a physical file, one might compile from memory.
* filename the name of the "file" to create
* Return:
* The function must return a pointer which is used as a "magic cookie" to
* all I/O functions. When failing to open the file for reading, the
* function must return NULL.
* Note:
* Several "source files" may be open at the same time. Specifically, one
* file can be open for reading and another for writing.
*/
void *pc_createsrc(char *filename)
{
src_file_t *src = (src_file_t *)calloc(1, sizeof(src_file_t));
if (!src)
return NULL;
if ((src->fp = fopen(filename, "wt")) == NULL) {
pc_closesrc(src);
return NULL;
}
src->maxlength = 1024;
if ((src->buffer = (char *)calloc(1, src->maxlength)) == NULL) {
pc_closesrc(src);
return NULL;
}
src->pos = src->buffer;
src->end = src->buffer + src->maxlength;
return src;
}
/* pc_closesrc()
* Closes a source file (or include file). The "handle" parameter has the
* value that pc_opensrc() returned in an earlier call.
*/
void pc_closesrc(void *handle)
{
src_file_t *src = (src_file_t *)handle;
if (!src)
return;
if (src->fp) {
fwrite(src->buffer, src->pos - src->buffer, 1, src->fp);
fclose(src->fp);
}
free(src->buffer);
free(src);
}
/* pc_readsrc()
* Reads a single line from the source file (or up to a maximum number of
* characters if the line in the input file is too long).
*/
char *pc_readsrc(void *handle,unsigned char *target,int maxchars)
{
src_file_t *src = (src_file_t *)handle;
char *outptr = (char *)target;
char *outend = outptr + maxchars;
assert(!src->fp);
if (src->pos == src->end)
return NULL;
while (outptr < outend && src->pos < src->end) {
char c = *src->pos++;
*outptr++ = c;
if (c == '\n')
break;
if (c == '\r') {
// Handle CRLF.
if (src->pos < src->end && *src->pos == '\n') {
src->pos++;
if (outptr < outend)
*outptr++ = '\n';
}
break;
}
}
// Caller passes in a buffer of size >= maxchars+1.
*outptr = '\0';
return (char *)target;
}
/* pc_writesrc()
* Writes to to the source file. There is no automatic line ending; to end a
* line, write a "\n".
*/
int pc_writesrc(void *handle,unsigned char *source)
{
char *str = (char *)source;
size_t len = strlen(str);
src_file_t *src = (src_file_t *)handle;
assert(src->fp && src->maxlength);
if (src->pos + len > src->end) {
char *newbuf;
size_t newmax = src->maxlength;
size_t newlen = (src->pos - src->buffer) + len;
while (newmax < newlen) {
// Grow by 1.5X
newmax += newmax + newmax / 2;
if (newmax < src->maxlength)
abort();
}
newbuf = (char *)realloc(src->buffer, newmax);
if (!newbuf)
abort();
src->pos = newbuf + (src->pos - src->buffer);
src->end = newbuf + newmax;
src->buffer = newbuf;
src->maxlength = newmax;
}
strcpy(src->pos, str);
src->pos += len;
return 0;
}
void *pc_getpossrc(void *handle,void *position)
{
src_file_t *src = (src_file_t *)handle;
assert(!src->fp);
return (void *)(ptrdiff_t)(src->pos - src->buffer);
}
/* pc_resetsrc()
* "position" may only hold a pointer that was previously obtained from
* pc_getpossrc()
*/
void pc_resetsrc(void *handle,void *position)
{
src_file_t *src = (src_file_t *)handle;
ptrdiff_t pos = (ptrdiff_t)position;
assert(!src->fp);
assert(pos >= 0 && src->buffer + pos <= src->end);
src->pos = src->buffer + pos;
}
int pc_eofsrc(void *handle)
{
src_file_t *src = (src_file_t *)handle;
assert(!src->fp);
return src->pos == src->end;
}
/* should return a pointer, which is used as a "magic cookie" to all I/O
* functions; return NULL for failure
*/
void *pc_openasm(char *filename)
{
return mfcreate(filename);
}
void pc_closeasm(void *handle, int deletefile)
{
if (handle!=NULL) {
if (!deletefile)
mfdump((MEMFILE*)handle);
mfclose((MEMFILE*)handle);
} /* if */
}
void pc_resetasm(void *handle)
{
mfseek((MEMFILE*)handle,0,SEEK_SET);
}
int pc_writeasm(void *handle,const char *string)
{
return mfputs((MEMFILE*)handle,string);
}
char *pc_readasm(void *handle, char *string, int maxchars)
{
return mfgets((MEMFILE*)handle,string,maxchars);
}
extern memfile_t *bin_file;
/* Should return a pointer, which is used as a "magic cookie" to all I/O
* functions; return NULL for failure.
*/
void *pc_openbin(char *filename)
{
return memfile_creat(filename, 1);
}
void pc_closebin(void *handle,int deletefile)
{
if (deletefile) {
memfile_destroy((memfile_t *)handle);
bin_file = NULL;
} else {
bin_file = (memfile_t *)handle;
}
}
/* pc_resetbin()
* Can seek to any location in the file.
* The offset is always from the start of the file.
*/
void pc_resetbin(void *handle,long offset)
{
memfile_seek((memfile_t *)handle, offset);
}
int pc_writebin(void *handle,void *buffer,int size)
{
return memfile_write((memfile_t *)handle, buffer, size);
}
long pc_lengthbin(void *handle)
{
return memfile_tell((memfile_t *)handle);
}

View File

@ -37,7 +37,7 @@
* will be copied. Always NUL terminates (unless siz == 0).
* Returns strlen(src); if retval >= siz, truncation occurred.
*/
size_t
extern "C" size_t
strlcpy(char *dst, const char *src, size_t siz)
{
char *d = dst;
@ -93,7 +93,7 @@ strlcpy(char *dst, const char *src, size_t siz)
* Returns strlen(src) + MIN(siz, strlen(initial dst)).
* If retval >= siz, truncation occurred.
*/
size_t
extern "C" size_t
strlcat(char *dst, const char *src, size_t siz)
{
char *d = dst;

View File

@ -9,10 +9,18 @@
#if !defined HAVE_SAFESTR
size_t
#if defined(__cplusplus)
# define EXPORT extern "C"
#else
# define EXPORT
#endif
EXPORT size_t
strlcpy(char *dst, const char *src, size_t siz);
size_t
EXPORT size_t
strlcat(char *dst, const char *src, size_t siz);
#undef EXPORT
#endif

View File

@ -52,4 +52,15 @@ long memfile_tell(memfile_t *mf);
*/
void memfile_reset(memfile_t *mf);
typedef memfile_t MEMFILE;
MEMFILE *mfcreate(const char *filename);
void mfclose(MEMFILE *mf);
int mfdump(MEMFILE *mf);
long mflength(const MEMFILE *mf);
long mfseek(MEMFILE *mf,long offset,int whence);
unsigned int mfwrite(MEMFILE *mf,const unsigned char *buffer,unsigned int size);
unsigned int mfread(MEMFILE *mf,unsigned char *buffer,unsigned int size);
char *mfgets(MEMFILE *mf,char *string,unsigned int size);
int mfputs(MEMFILE *mf,const char *string);
#endif //_INCLUDE_MEMFILE_H

View File

@ -1,615 +0,0 @@
#include <stdio.h>
#include <setjmp.h>
#include <assert.h>
#include <string.h>
#include "memfile.h"
#include "sp_file.h"
#include "amx.h"
#include "amxdbg.h"
#include "osdefs.h"
#include "zlib/zlib.h"
#if defined LINUX || defined DARWIN
#include <unistd.h>
#elif defined WIN32
#include <io.h>
#endif
enum FileSections
{
FS_Code, /* required */
FS_Data, /* required */
FS_Publics,
FS_Pubvars,
FS_Natives,
FS_Nametable, /* required */
FS_DbgFile,
FS_DbgSymbol,
FS_DbgLine,
FS_DbgTags,
FS_DbgNatives,
FS_DbgAutomaton,
FS_DbgState,
FS_DbgStrings,
FS_DbgInfo,
FS_Tags,
/* --- */
FS_Number,
};
int pc_printf(const char *message,...);
int pc_compile(int argc, char **argv);
void sfwrite(const void *buf, size_t size, size_t count, sp_file_t *spf);
memfile_t *bin_file = NULL;
jmp_buf brkout;
#define sARGS_MAX 32 /* number of arguments a function can have, max */
#define sDIMEN_MAX 4 /* maximum number of array dimensions */
typedef struct t_arg_s
{
uint8_t ident;
int16_t tag;
char *name;
uint16_t dimcount;
sp_fdbg_arraydim_t dims[sDIMEN_MAX];
} t_arg;
typedef struct t_native_s
{
char *name;
int16_t ret_tag;
uint16_t num_args;
t_arg args[sARGS_MAX];
} t_native;
t_native *native_list = NULL;
int main(int argc, char *argv[])
{
if (pc_compile(argc,argv) == 0)
{
AMX_HEADER *hdr;
AMX_DBG_HDR *dbg = NULL;
int err;
uint32_t i;
sp_file_t *spf;
memfile_t *dbgtab = NULL; //dbgcrab
unsigned char *dbgptr = NULL;
uint32_t sections[FS_Number] = {1,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0};
FILE *fp;
if (bin_file == NULL)
{
return 0;
}
hdr = (AMX_HEADER *)bin_file->base;
if ((spf=spfw_create(bin_file->name, NULL)) == NULL)
{
pc_printf("Error creating binary file!\n");
memfile_destroy(bin_file);
return 0;
}
if ((err=setjmp(brkout))!=0)
{
goto write_error;
}
spfw_add_section(spf, ".code");
spfw_add_section(spf, ".data");
sections[FS_Publics] = (hdr->natives - hdr->publics) / hdr->defsize;
if (sections[FS_Publics])
{
spfw_add_section(spf, ".publics");
}
sections[FS_Pubvars] = (hdr->tags - hdr->pubvars) / hdr->defsize;
if (sections[FS_Pubvars])
{
spfw_add_section(spf, ".pubvars");
}
sections[FS_Natives] = (hdr->libraries - hdr->natives) / hdr->defsize;
if (sections[FS_Natives])
{
spfw_add_section(spf, ".natives");
}
sections[FS_Tags] = (hdr->nametable - hdr->tags) / hdr->defsize;
if (sections[FS_Tags])
{
spfw_add_section(spf, ".tags");
}
spfw_add_section(spf, ".names");
if (hdr->flags & AMX_FLAG_DEBUG)
{
dbg = (AMX_DBG_HDR *)((unsigned char *)hdr + hdr->size);
if (dbg->magic != AMX_DBG_MAGIC)
{
pc_printf("Error reading AMX_DBG_HDR, debug data will not be written.");
} else {
dbgtab = memfile_creat("", 512);
dbgptr = (unsigned char *)dbg + sizeof(AMX_DBG_HDR);
if ((sections[FS_DbgNatives] = sections[FS_Natives]) > 0)
{
spfw_add_section(spf, ".dbg.natives");
}
if (dbg->files)
{
spfw_add_section(spf, ".dbg.files");
sections[FS_DbgFile] = dbg->files;
}
if (dbg->lines)
{
spfw_add_section(spf, ".dbg.lines");
sections[FS_DbgLine] = dbg->lines;
}
if (dbg->symbols)
{
spfw_add_section(spf, ".dbg.symbols");
sections[FS_DbgSymbol] = dbg->symbols;
}
sections[FS_DbgInfo] = 1;
sections[FS_DbgStrings] = 1;
spfw_add_section(spf, ".dbg.info");
spfw_add_section(spf, ".dbg.strings");
}
}
spfw_finalize_header(spf);
/**
* Begin writing each of our known tables out
*/
if (sections[FS_Code])
{
sp_file_code_t cod;
unsigned char *cbase;
cod.cellsize = sizeof(cell);
cod.codesize = hdr->dat - hdr->cod;
cod.codeversion = hdr->amx_version;
cod.flags = 0;
if (hdr->flags & AMX_FLAG_DEBUG)
{
cod.flags |= SP_FLAG_DEBUG;
}
cod.code = sizeof(cod);
cod.main = hdr->cip;
/* write the code */
cbase = (unsigned char *)hdr + hdr->cod;
sfwrite(&cod, sizeof(cod), 1, spf);
sfwrite(cbase, cod.codesize, 1, spf);
spfw_next_section(spf);
}
if (sections[FS_Data])
{
sp_file_data_t dat;
unsigned char *dbase = (unsigned char *)hdr + hdr->dat;
dat.datasize = hdr->hea - hdr->dat;
dat.memsize = hdr->stp;
dat.data = sizeof(dat);
/* write header */
sfwrite(&dat, sizeof(dat), 1, spf);
if (dat.datasize)
{
/* write data */
sfwrite(dbase, dat.datasize, 1, spf);
}
spfw_next_section(spf);
}
if (sections[FS_Publics])
{
sp_file_publics_t *pbtbl;
AMX_FUNCSTUBNT *stub;
unsigned char *stubptr;
uint32_t publics = sections[FS_Publics];
pbtbl = (sp_file_publics_t *)malloc(sizeof(sp_file_publics_t) * publics);
stubptr = (unsigned char *)hdr + hdr->publics;
for (i=0; i<publics; i++)
{
stub = (AMX_FUNCSTUBNT *)stubptr;
pbtbl[i].address = stub->address;
pbtbl[i].name = stub->nameofs - (hdr->nametable + sizeof(uint16_t));
stubptr += hdr->defsize;
}
if (publics)
{
sfwrite(pbtbl, sizeof(sp_file_publics_t), publics, spf);
}
free(pbtbl);
spfw_next_section(spf);
}
if (sections[FS_Pubvars])
{
sp_file_pubvars_t *pbvars;
AMX_FUNCSTUBNT *stub;
unsigned char *stubptr;
uint32_t pubvars = sections[FS_Pubvars];
pbvars = (sp_file_pubvars_t *)malloc(sizeof(sp_file_pubvars_t) * pubvars);
stubptr = (unsigned char *)hdr + hdr->pubvars;
for (i=0; i<pubvars; i++)
{
stub = (AMX_FUNCSTUBNT *)stubptr;
pbvars[i].address = stub->address;
pbvars[i].name = stub->nameofs - (hdr->nametable + sizeof(uint16_t));
stubptr += hdr->defsize;
}
if (pubvars)
{
sfwrite(pbvars, sizeof(sp_file_pubvars_t), pubvars, spf);
}
free(pbvars);
spfw_next_section(spf);
}
if (sections[FS_Natives])
{
sp_file_natives_t *nvtbl;
AMX_FUNCSTUBNT *stub;
unsigned char *stubptr;
uint32_t natives = (hdr->libraries - hdr->natives) / hdr->defsize;
nvtbl = (sp_file_natives_t *)malloc(sizeof(sp_file_natives_t) * natives);
stubptr = (unsigned char *)hdr + hdr->natives;
for (i=0; i<natives; i++)
{
stub = (AMX_FUNCSTUBNT *)stubptr;
nvtbl[i].name = stub->nameofs - (hdr->nametable + sizeof(uint16_t));
stubptr += hdr->defsize;
}
if (natives)
{
sfwrite(nvtbl, sizeof(sp_file_natives_t), natives, spf);
}
free(nvtbl);
spfw_next_section(spf);
}
if (sections[FS_Tags])
{
uint32_t numTags = (uint32_t)sections[FS_Tags];
AMX_FUNCSTUBNT *stub;
sp_file_tag_t tag;
for (i=0; i<numTags; i++)
{
stub = (AMX_FUNCSTUBNT *)((unsigned char *)hdr + hdr->tags + (i * hdr->defsize));
tag.tag_id = stub->address;
tag.name = stub->nameofs - (hdr->nametable + sizeof(uint16_t));
sfwrite(&tag, sizeof(sp_file_tag_t), 1, spf);
}
spfw_next_section(spf);
}
if (sections[FS_Nametable])
{
unsigned char *base;
uint32_t namelen;
/* write the entire block */
base = (unsigned char *)hdr + hdr->nametable + sizeof(uint16_t);
/**
* note - the name table will be padded to sizeof(cell) bytes.
* this may clip at most an extra three bytes in!
*/
namelen = hdr->cod - hdr->nametable;
sfwrite(base, namelen, 1, spf);
spfw_next_section(spf);
}
if (hdr->flags & AMX_FLAG_DEBUG)
{
sp_fdbg_info_t info;
memset(&info, 0, sizeof(sp_fdbg_info_t));
if (sections[FS_Natives])
{
uint16_t j;
uint32_t idx;
uint32_t name;
uint32_t natives = (hdr->libraries - hdr->natives) / hdr->defsize;
sfwrite(&natives, sizeof(uint32_t), 1, spf);
for (idx=0; idx<natives; idx++)
{
sfwrite(&idx, sizeof(uint32_t), 1, spf);
name = (uint32_t)memfile_tell(dbgtab);
memfile_write(dbgtab, native_list[idx].name, strlen(native_list[idx].name) + 1);
sfwrite(&name, sizeof(uint32_t), 1, spf);
sfwrite(&native_list[idx].ret_tag, sizeof(int16_t), 1, spf);
sfwrite(&native_list[idx].num_args, sizeof(uint16_t), 1, spf);
/* Go through arguments */
for (j = 0; j < native_list[idx].num_args; j++)
{
sfwrite(&native_list[idx].args[j].ident, sizeof(uint8_t), 1, spf);
sfwrite(&native_list[idx].args[j].tag, sizeof(int16_t), 1, spf);
sfwrite(&native_list[idx].args[j].dimcount, sizeof(uint16_t), 1, spf);
name = (uint32_t)memfile_tell(dbgtab);
sfwrite(&name, sizeof(uint32_t), 1, spf);
memfile_write(dbgtab,
native_list[idx].args[j].name,
strlen(native_list[idx].args[j].name) + 1);
if (native_list[idx].args[j].dimcount)
{
sfwrite(native_list[idx].args[j].dims,
sizeof(sp_fdbg_arraydim_t),
native_list[idx].args[j].dimcount,
spf);
}
free(native_list[idx].args[j].name);
}
free(native_list[idx].name);
}
free(native_list);
spfw_next_section(spf);
}
if (sections[FS_DbgFile])
{
uint32_t idx;
sp_fdbg_file_t dbgfile;
AMX_DBG_FILE *_ptr;
uint32_t len;
for (idx=0; idx<sections[FS_DbgFile]; idx++)
{
/* get entry info */
_ptr = (AMX_DBG_FILE *)dbgptr;
len = strlen(_ptr->name);
/* store */
dbgfile.addr = _ptr->address;
dbgfile.name = (uint32_t)memfile_tell(dbgtab);
sfwrite(&dbgfile, sizeof(sp_fdbg_file_t), 1, spf);
/* write to tab, then move to next */
memfile_write(dbgtab, _ptr->name, len + 1);
dbgptr += sizeof(AMX_DBG_FILE) + len;
info.num_files++;
}
spfw_next_section(spf);
}
if (sections[FS_DbgLine])
{
uint32_t idx;
AMX_DBG_LINE *line;
sp_fdbg_line_t dbgline;
for (idx=0; idx<sections[FS_DbgLine]; idx++)
{
/* get entry info */
line = (AMX_DBG_LINE *)dbgptr;
/* store */
dbgline.addr = (uint32_t)line->address;
dbgline.line = (uint32_t)line->line;
sfwrite(&dbgline, sizeof(sp_fdbg_line_t), 1, spf);
/* move to next */
dbgptr += sizeof(AMX_DBG_LINE);
info.num_lines++;
}
spfw_next_section(spf);
}
if (sections[FS_DbgSymbol])
{
uint32_t idx;
uint32_t dnum;
AMX_DBG_SYMBOL *sym;
AMX_DBG_SYMDIM *dim;
sp_fdbg_symbol_t dbgsym;
sp_fdbg_arraydim_t dbgdim;
uint32_t len;
for (idx=0; idx<sections[FS_DbgSymbol]; idx++)
{
/* get entry info */
sym = (AMX_DBG_SYMBOL *)dbgptr;
/* store */
dbgsym.addr = (int32_t)sym->address;
dbgsym.tagid = sym->tag;
dbgsym.codestart = (uint32_t)sym->codestart;
dbgsym.codeend = (uint32_t)sym->codeend;
dbgsym.dimcount = (uint16_t)sym->dim;
dbgsym.vclass = (uint8_t)sym->vclass;
dbgsym.ident = (uint8_t)sym->ident;
dbgsym.name = (uint32_t)memfile_tell(dbgtab);
sfwrite(&dbgsym, sizeof(sp_fdbg_symbol_t), 1, spf);
/* write to tab */
len = strlen(sym->name);
memfile_write(dbgtab, sym->name, len + 1);
/* move to next */
dbgptr += sizeof(AMX_DBG_SYMBOL) + len;
/* look for any dimensions */
info.num_syms++;
for (dnum=0; dnum<dbgsym.dimcount; dnum++)
{
/* get entry info */
dim = (AMX_DBG_SYMDIM *)dbgptr;
/* store */
dbgdim.size = (uint32_t)dim->size;
dbgdim.tagid = dim->tag;
sfwrite(&dbgdim, sizeof(sp_fdbg_arraydim_t), 1, spf);
/* move to next */
dbgptr += sizeof(AMX_DBG_SYMDIM);
info.num_arrays++;
}
}
spfw_next_section(spf);
}
sfwrite(&info, sizeof(sp_fdbg_info_t), 1, spf);
spfw_next_section(spf);
if (sections[FS_DbgStrings])
{
sfwrite(dbgtab->base, sizeof(char), dbgtab->usedoffs, spf);
spfw_next_section(spf);
}
}
spfw_finalize_all(spf);
/**
* do compression
* new block for scoping only
*/
{
memfile_t *pOrig = (memfile_t *)spf->handle;
sp_file_hdr_t *pHdr;
unsigned char *proper;
size_t size;
Bytef *zcmp;
uLong disksize;
size_t header_size;
int err = Z_OK;
/* reuse this memory block! */
memfile_reset(bin_file);
/* copy tip of header */
memfile_write(bin_file, pOrig->base, sizeof(sp_file_hdr_t));
/* get pointer to header */
pHdr = (sp_file_hdr_t *)bin_file->base;
/* copy the rest of the header */
memfile_write(bin_file,
(unsigned char *)pOrig->base + sizeof(sp_file_hdr_t),
pHdr->dataoffs - sizeof(sp_file_hdr_t));
header_size = pHdr->dataoffs;
size = pHdr->imagesize - header_size;
proper = (unsigned char *)pOrig->base + header_size;
/* get initial size estimate */
disksize = compressBound(pHdr->imagesize);
pHdr->disksize = (uint32_t)disksize;
zcmp = (Bytef *)malloc(pHdr->disksize);
if ((err=compress2(zcmp,
&disksize,
(Bytef *)proper,
(uLong)size,
Z_BEST_COMPRESSION))
!= Z_OK)
{
free(zcmp);
pc_printf("Unable to compress (Z): error %d\n", err);
pc_printf("Falling back to no compression.");
memfile_write(bin_file,
proper,
size);
} else {
pHdr->disksize = (uint32_t)disksize + header_size;
pHdr->compression = SPFILE_COMPRESSION_GZ;
memfile_write(bin_file,
(unsigned char *)zcmp,
disksize);
free(zcmp);
}
}
spfw_destroy(spf);
memfile_destroy(dbgtab);
/**
* write file
*/
if ((fp=fopen(bin_file->name, "wb")) != NULL)
{
fwrite(bin_file->base, bin_file->usedoffs, 1, fp);
fclose(fp);
} else {
pc_printf("Unable to open %s for writing!", bin_file->name);
}
memfile_destroy(bin_file);
return 0;
write_error:
pc_printf("Error writing to file: %s", bin_file->name);
spfw_destroy(spf);
unlink(bin_file->name);
memfile_destroy(bin_file);
memfile_destroy(dbgtab);
return 1;
}
return 1;
}
void sfwrite(const void *buf, size_t size, size_t count, sp_file_t *spf)
{
if (spf->funcs.fnWrite(buf, size, count, spf->handle) != count)
{
longjmp(brkout, 1);
}
}
void sp_fdbg_ntv_start(int num_natives)
{
if (num_natives == 0)
{
return;
}
native_list = (t_native *)malloc(sizeof(t_native) * num_natives);
memset(native_list, 0, sizeof(t_native) * num_natives);
}
#include "sc.h"
void sp_fdbg_ntv_hook(int index, symbol *sym)
{
int i, j;
t_native *native;
native = &native_list[index];
native->name = strdup(sym->name);
for (i = 0; i < sMAXARGS; i++)
{
if (sym->dim.arglist[i].ident == 0)
{
break;
}
native->num_args++;
native->args[i].tag = sym->dim.arglist[i].tags == NULL ? 0 : sym->dim.arglist[i].tags[0];
native->args[i].name = strdup(sym->dim.arglist[i].name);
native->args[i].ident = sym->dim.arglist[i].ident;
native->args[i].dimcount = sym->dim.arglist[i].numdim;
for (j = 0; j < native->args[i].dimcount; j++)
{
native->args[i].dims[j].size = sym->dim.arglist[i].dim[j];
native->args[i].dims[j].tagid = sym->dim.arglist[i].idxtag[j];
}
}
native->ret_tag = sym->tag;
}

View File

@ -0,0 +1,581 @@
#include <stdio.h>
#include <setjmp.h>
#include <assert.h>
#include <string.h>
#include "memfile.h"
#include "sp_file.h"
#include "amx.h"
#include "amxdbg.h"
#include "osdefs.h"
#include "zlib/zlib.h"
#if defined LINUX || defined DARWIN
#include <unistd.h>
#elif defined WIN32
#include <io.h>
#endif
enum FileSections
{
FS_Code, /* required */
FS_Data, /* required */
FS_Publics,
FS_Pubvars,
FS_Natives,
FS_Nametable, /* required */
FS_DbgFile,
FS_DbgSymbol,
FS_DbgLine,
FS_DbgTags,
FS_DbgNatives,
FS_DbgAutomaton,
FS_DbgState,
FS_DbgStrings,
FS_DbgInfo,
FS_Tags,
/* --- */
FS_Number,
};
int pc_printf(const char *message,...);
int pc_compile(int argc, char **argv);
void sfwrite(const void *buf, size_t size, size_t count, sp_file_t *spf);
memfile_t *bin_file = NULL;
jmp_buf brkout;
#define sARGS_MAX 32 /* number of arguments a function can have, max */
#define sDIMEN_MAX 4 /* maximum number of array dimensions */
typedef struct t_arg_s
{
uint8_t ident;
int16_t tag;
char *name;
uint16_t dimcount;
sp_fdbg_arraydim_t dims[sDIMEN_MAX];
} t_arg;
typedef struct t_native_s
{
char *name;
int16_t ret_tag;
uint16_t num_args;
t_arg args[sARGS_MAX];
} t_native;
t_native *native_list = NULL;
int main(int argc, char *argv[])
{
if (pc_compile(argc,argv) != 0)
return 1;
AMX_HEADER *hdr;
AMX_DBG_HDR *dbg = NULL;
int err;
uint32_t i;
sp_file_t *spf;
memfile_t *dbgtab = NULL; //dbgcrab
unsigned char *dbgptr = NULL;
uint32_t sections[FS_Number] = {1,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0};
FILE *fp;
if (bin_file == NULL)
return 0;
hdr = (AMX_HEADER *)bin_file->base;
if ((spf=spfw_create(bin_file->name, NULL)) == NULL) {
pc_printf("Error creating binary file!\n");
memfile_destroy(bin_file);
return 0;
}
if ((err=setjmp(brkout))!=0)
goto write_error;
spfw_add_section(spf, ".code");
spfw_add_section(spf, ".data");
sections[FS_Publics] = (hdr->natives - hdr->publics) / hdr->defsize;
if (sections[FS_Publics])
spfw_add_section(spf, ".publics");
sections[FS_Pubvars] = (hdr->tags - hdr->pubvars) / hdr->defsize;
if (sections[FS_Pubvars])
spfw_add_section(spf, ".pubvars");
sections[FS_Natives] = (hdr->libraries - hdr->natives) / hdr->defsize;
if (sections[FS_Natives])
spfw_add_section(spf, ".natives");
sections[FS_Tags] = (hdr->nametable - hdr->tags) / hdr->defsize;
if (sections[FS_Tags])
spfw_add_section(spf, ".tags");
spfw_add_section(spf, ".names");
if (hdr->flags & AMX_FLAG_DEBUG) {
dbg = (AMX_DBG_HDR *)((unsigned char *)hdr + hdr->size);
if (dbg->magic != AMX_DBG_MAGIC) {
pc_printf("Error reading AMX_DBG_HDR, debug data will not be written.");
} else {
dbgtab = memfile_creat("", 512);
dbgptr = (unsigned char *)dbg + sizeof(AMX_DBG_HDR);
if ((sections[FS_DbgNatives] = sections[FS_Natives]) > 0)
spfw_add_section(spf, ".dbg.natives");
if (dbg->files) {
spfw_add_section(spf, ".dbg.files");
sections[FS_DbgFile] = dbg->files;
}
if (dbg->lines) {
spfw_add_section(spf, ".dbg.lines");
sections[FS_DbgLine] = dbg->lines;
}
if (dbg->symbols) {
spfw_add_section(spf, ".dbg.symbols");
sections[FS_DbgSymbol] = dbg->symbols;
}
sections[FS_DbgInfo] = 1;
sections[FS_DbgStrings] = 1;
spfw_add_section(spf, ".dbg.info");
spfw_add_section(spf, ".dbg.strings");
}
}
spfw_finalize_header(spf);
/**
* Begin writing each of our known tables out
*/
if (sections[FS_Code]) {
sp_file_code_t cod;
unsigned char *cbase;
cod.cellsize = sizeof(cell);
cod.codesize = hdr->dat - hdr->cod;
cod.codeversion = hdr->amx_version;
cod.flags = 0;
if (hdr->flags & AMX_FLAG_DEBUG)
{
cod.flags |= SP_FLAG_DEBUG;
}
cod.code = sizeof(cod);
cod.main = hdr->cip;
/* write the code */
cbase = (unsigned char *)hdr + hdr->cod;
sfwrite(&cod, sizeof(cod), 1, spf);
sfwrite(cbase, cod.codesize, 1, spf);
spfw_next_section(spf);
}
if (sections[FS_Data]) {
sp_file_data_t dat;
unsigned char *dbase = (unsigned char *)hdr + hdr->dat;
dat.datasize = hdr->hea - hdr->dat;
dat.memsize = hdr->stp;
dat.data = sizeof(dat);
/* write header */
sfwrite(&dat, sizeof(dat), 1, spf);
if (dat.datasize) {
/* write data */
sfwrite(dbase, dat.datasize, 1, spf);
}
spfw_next_section(spf);
}
if (sections[FS_Publics]) {
sp_file_publics_t *pbtbl;
AMX_FUNCSTUBNT *stub;
unsigned char *stubptr;
uint32_t publics = sections[FS_Publics];
pbtbl = (sp_file_publics_t *)malloc(sizeof(sp_file_publics_t) * publics);
stubptr = (unsigned char *)hdr + hdr->publics;
for (i=0; i<publics; i++) {
stub = (AMX_FUNCSTUBNT *)stubptr;
pbtbl[i].address = stub->address;
pbtbl[i].name = stub->nameofs - (hdr->nametable + sizeof(uint16_t));
stubptr += hdr->defsize;
}
if (publics)
sfwrite(pbtbl, sizeof(sp_file_publics_t), publics, spf);
free(pbtbl);
spfw_next_section(spf);
}
if (sections[FS_Pubvars]) {
sp_file_pubvars_t *pbvars;
AMX_FUNCSTUBNT *stub;
unsigned char *stubptr;
uint32_t pubvars = sections[FS_Pubvars];
pbvars = (sp_file_pubvars_t *)malloc(sizeof(sp_file_pubvars_t) * pubvars);
stubptr = (unsigned char *)hdr + hdr->pubvars;
for (i=0; i<pubvars; i++) {
stub = (AMX_FUNCSTUBNT *)stubptr;
pbvars[i].address = stub->address;
pbvars[i].name = stub->nameofs - (hdr->nametable + sizeof(uint16_t));
stubptr += hdr->defsize;
}
if (pubvars)
sfwrite(pbvars, sizeof(sp_file_pubvars_t), pubvars, spf);
free(pbvars);
spfw_next_section(spf);
}
if (sections[FS_Natives]) {
sp_file_natives_t *nvtbl;
AMX_FUNCSTUBNT *stub;
unsigned char *stubptr;
uint32_t natives = (hdr->libraries - hdr->natives) / hdr->defsize;
nvtbl = (sp_file_natives_t *)malloc(sizeof(sp_file_natives_t) * natives);
stubptr = (unsigned char *)hdr + hdr->natives;
for (i=0; i<natives; i++) {
stub = (AMX_FUNCSTUBNT *)stubptr;
nvtbl[i].name = stub->nameofs - (hdr->nametable + sizeof(uint16_t));
stubptr += hdr->defsize;
}
if (natives) {
sfwrite(nvtbl, sizeof(sp_file_natives_t), natives, spf);
}
free(nvtbl);
spfw_next_section(spf);
}
if (sections[FS_Tags]) {
uint32_t numTags = (uint32_t)sections[FS_Tags];
AMX_FUNCSTUBNT *stub;
sp_file_tag_t tag;
for (i=0; i<numTags; i++) {
stub = (AMX_FUNCSTUBNT *)((unsigned char *)hdr + hdr->tags + (i * hdr->defsize));
tag.tag_id = stub->address;
tag.name = stub->nameofs - (hdr->nametable + sizeof(uint16_t));
sfwrite(&tag, sizeof(sp_file_tag_t), 1, spf);
}
spfw_next_section(spf);
}
if (sections[FS_Nametable]) {
unsigned char *base;
uint32_t namelen;
/* write the entire block */
base = (unsigned char *)hdr + hdr->nametable + sizeof(uint16_t);
/**
* note - the name table will be padded to sizeof(cell) bytes.
* this may clip at most an extra three bytes in!
*/
namelen = hdr->cod - hdr->nametable;
sfwrite(base, namelen, 1, spf);
spfw_next_section(spf);
}
if (hdr->flags & AMX_FLAG_DEBUG) {
sp_fdbg_info_t info;
memset(&info, 0, sizeof(sp_fdbg_info_t));
if (sections[FS_Natives]) {
uint16_t j;
uint32_t idx;
uint32_t name;
uint32_t natives = (hdr->libraries - hdr->natives) / hdr->defsize;
sfwrite(&natives, sizeof(uint32_t), 1, spf);
for (idx=0; idx<natives; idx++) {
sfwrite(&idx, sizeof(uint32_t), 1, spf);
name = (uint32_t)memfile_tell(dbgtab);
memfile_write(dbgtab, native_list[idx].name, strlen(native_list[idx].name) + 1);
sfwrite(&name, sizeof(uint32_t), 1, spf);
sfwrite(&native_list[idx].ret_tag, sizeof(int16_t), 1, spf);
sfwrite(&native_list[idx].num_args, sizeof(uint16_t), 1, spf);
/* Go through arguments */
for (j = 0; j < native_list[idx].num_args; j++) {
sfwrite(&native_list[idx].args[j].ident, sizeof(uint8_t), 1, spf);
sfwrite(&native_list[idx].args[j].tag, sizeof(int16_t), 1, spf);
sfwrite(&native_list[idx].args[j].dimcount, sizeof(uint16_t), 1, spf);
name = (uint32_t)memfile_tell(dbgtab);
sfwrite(&name, sizeof(uint32_t), 1, spf);
memfile_write(dbgtab,
native_list[idx].args[j].name,
strlen(native_list[idx].args[j].name) + 1);
if (native_list[idx].args[j].dimcount) {
sfwrite(native_list[idx].args[j].dims,
sizeof(sp_fdbg_arraydim_t),
native_list[idx].args[j].dimcount,
spf);
}
free(native_list[idx].args[j].name);
}
free(native_list[idx].name);
}
free(native_list);
spfw_next_section(spf);
}
if (sections[FS_DbgFile]) {
uint32_t idx;
sp_fdbg_file_t dbgfile;
AMX_DBG_FILE *_ptr;
uint32_t len;
for (idx=0; idx<sections[FS_DbgFile]; idx++) {
/* get entry info */
_ptr = (AMX_DBG_FILE *)dbgptr;
len = strlen(_ptr->name);
/* store */
dbgfile.addr = _ptr->address;
dbgfile.name = (uint32_t)memfile_tell(dbgtab);
sfwrite(&dbgfile, sizeof(sp_fdbg_file_t), 1, spf);
/* write to tab, then move to next */
memfile_write(dbgtab, _ptr->name, len + 1);
dbgptr += sizeof(AMX_DBG_FILE) + len;
info.num_files++;
}
spfw_next_section(spf);
}
if (sections[FS_DbgLine]) {
uint32_t idx;
AMX_DBG_LINE *line;
sp_fdbg_line_t dbgline;
for (idx=0; idx<sections[FS_DbgLine]; idx++) {
/* get entry info */
line = (AMX_DBG_LINE *)dbgptr;
/* store */
dbgline.addr = (uint32_t)line->address;
dbgline.line = (uint32_t)line->line;
sfwrite(&dbgline, sizeof(sp_fdbg_line_t), 1, spf);
/* move to next */
dbgptr += sizeof(AMX_DBG_LINE);
info.num_lines++;
}
spfw_next_section(spf);
}
if (sections[FS_DbgSymbol]) {
uint32_t idx;
uint32_t dnum;
AMX_DBG_SYMBOL *sym;
AMX_DBG_SYMDIM *dim;
sp_fdbg_symbol_t dbgsym;
sp_fdbg_arraydim_t dbgdim;
uint32_t len;
for (idx=0; idx<sections[FS_DbgSymbol]; idx++) {
/* get entry info */
sym = (AMX_DBG_SYMBOL *)dbgptr;
/* store */
dbgsym.addr = (int32_t)sym->address;
dbgsym.tagid = sym->tag;
dbgsym.codestart = (uint32_t)sym->codestart;
dbgsym.codeend = (uint32_t)sym->codeend;
dbgsym.dimcount = (uint16_t)sym->dim;
dbgsym.vclass = (uint8_t)sym->vclass;
dbgsym.ident = (uint8_t)sym->ident;
dbgsym.name = (uint32_t)memfile_tell(dbgtab);
sfwrite(&dbgsym, sizeof(sp_fdbg_symbol_t), 1, spf);
/* write to tab */
len = strlen(sym->name);
memfile_write(dbgtab, sym->name, len + 1);
/* move to next */
dbgptr += sizeof(AMX_DBG_SYMBOL) + len;
/* look for any dimensions */
info.num_syms++;
for (dnum=0; dnum<dbgsym.dimcount; dnum++)
{
/* get entry info */
dim = (AMX_DBG_SYMDIM *)dbgptr;
/* store */
dbgdim.size = (uint32_t)dim->size;
dbgdim.tagid = dim->tag;
sfwrite(&dbgdim, sizeof(sp_fdbg_arraydim_t), 1, spf);
/* move to next */
dbgptr += sizeof(AMX_DBG_SYMDIM);
info.num_arrays++;
}
}
spfw_next_section(spf);
}
sfwrite(&info, sizeof(sp_fdbg_info_t), 1, spf);
spfw_next_section(spf);
if (sections[FS_DbgStrings]) {
sfwrite(dbgtab->base, sizeof(char), dbgtab->usedoffs, spf);
spfw_next_section(spf);
}
}
spfw_finalize_all(spf);
/**
* do compression
* new block for scoping only
*/
{
memfile_t *pOrig = (memfile_t *)spf->handle;
sp_file_hdr_t *pHdr;
unsigned char *proper;
size_t size;
Bytef *zcmp;
uLong disksize;
size_t header_size;
int err = Z_OK;
/* reuse this memory block! */
memfile_reset(bin_file);
/* copy tip of header */
memfile_write(bin_file, pOrig->base, sizeof(sp_file_hdr_t));
/* get pointer to header */
pHdr = (sp_file_hdr_t *)bin_file->base;
/* copy the rest of the header */
memfile_write(bin_file,
(unsigned char *)pOrig->base + sizeof(sp_file_hdr_t),
pHdr->dataoffs - sizeof(sp_file_hdr_t));
header_size = pHdr->dataoffs;
size = pHdr->imagesize - header_size;
proper = (unsigned char *)pOrig->base + header_size;
/* get initial size estimate */
disksize = compressBound(pHdr->imagesize);
pHdr->disksize = (uint32_t)disksize;
zcmp = (Bytef *)malloc(pHdr->disksize);
if ((err=compress2(zcmp,
&disksize,
(Bytef *)proper,
(uLong)size,
Z_BEST_COMPRESSION))
!= Z_OK)
{
free(zcmp);
pc_printf("Unable to compress (Z): error %d\n", err);
pc_printf("Falling back to no compression.");
memfile_write(bin_file,
proper,
size);
} else {
pHdr->disksize = (uint32_t)disksize + header_size;
pHdr->compression = SPFILE_COMPRESSION_GZ;
memfile_write(bin_file,
(unsigned char *)zcmp,
disksize);
free(zcmp);
}
}
spfw_destroy(spf);
memfile_destroy(dbgtab);
/**
* write file
*/
if ((fp=fopen(bin_file->name, "wb")) != NULL) {
fwrite(bin_file->base, bin_file->usedoffs, 1, fp);
fclose(fp);
} else {
pc_printf("Unable to open %s for writing!", bin_file->name);
}
memfile_destroy(bin_file);
return 0;
write_error:
pc_printf("Error writing to file: %s", bin_file->name);
spfw_destroy(spf);
unlink(bin_file->name);
memfile_destroy(bin_file);
memfile_destroy(dbgtab);
return 1;
}
void sfwrite(const void *buf, size_t size, size_t count, sp_file_t *spf)
{
if (spf->funcs.fnWrite(buf, size, count, spf->handle) != count)
longjmp(brkout, 1);
}
void sp_fdbg_ntv_start(int num_natives)
{
if (num_natives == 0)
return;
native_list = (t_native *)malloc(sizeof(t_native) * num_natives);
memset(native_list, 0, sizeof(t_native) * num_natives);
}
#include "sc.h"
void sp_fdbg_ntv_hook(int index, symbol *sym)
{
int i, j;
t_native *native;
native = &native_list[index];
native->name = strdup(sym->name);
for (i = 0; i < sMAXARGS; i++) {
if (sym->dim.arglist[i].ident == 0)
break;
native->num_args++;
native->args[i].tag = sym->dim.arglist[i].tags == NULL ? 0 : sym->dim.arglist[i].tags[0];
native->args[i].name = strdup(sym->dim.arglist[i].name);
native->args[i].ident = sym->dim.arglist[i].ident;
native->args[i].dimcount = sym->dim.arglist[i].numdim;
for (j = 0; j < native->args[i].dimcount; j++) {
native->args[i].dims[j].size = sym->dim.arglist[i].dim[j];
native->args[i].dims[j].tagid = sym->dim.arglist[i].idxtag[j];
}
}
native->ret_tag = sym->tag;
}
#if defined __linux__ || defined __APPLE__
extern "C" void __cxa_pure_virtual(void)
{
}
void *operator new(size_t size)
{
return malloc(size);
}
void *operator new[](size_t size)
{
return malloc(size);
}
void operator delete(void *ptr)
{
free(ptr);
}
void operator delete[](void * ptr)
{
free(ptr);
}
#endif

View File

@ -357,7 +357,7 @@ typedef struct {
/* Tokens recognized by lex()
* Some of these constants are assigned as well to the variable "lastst" (see SC1.C)
*/
enum {
enum TokenKind {
/* value of first multi-character operator */
tFIRST = 256,
/* multi-character operators */
@ -431,6 +431,8 @@ enum {
tSWITCH,
tTAGOF,
tTHEN,
tTYPEDEF,
tUNION,
tVOID,
tWHILE,
/* compiler directives */
@ -536,18 +538,13 @@ typedef enum s_optmark {
#define CELL_MAX (((ucell)1 << (sizeof(cell)*8-1)) - 1)
/* interface functions */
#if defined __cplusplus
extern "C" {
#endif
/*
* Functions you call from the "driver" program
*/
int pc_compile(int argc, char **argv);
int pc_addconstant(char *name,cell value,int tag);
int pc_addtag(char *name);
int pc_addtag_flags(char *name, int flags);
int pc_addconstant(const char *name,cell value,int tag);
int pc_addtag(const char *name);
int pc_addtag_flags(const char *name, int flags);
int pc_findtag(const char *name);
constvalue *pc_tagptr(const char *name);
int pc_enablewarning(int number,int enable);
@ -563,7 +560,7 @@ const char *type_to_name(int tag);
int pc_printf(const char *message,...);
/* error report function */
int pc_error(int number,char *message,char *filename,int firstline,int lastline,va_list argptr);
int pc_error(int number,const char *message,const char *filename,int firstline,int lastline,va_list argptr);
/* input from source file */
void *pc_opensrc(char *filename); /* reading only */
@ -579,7 +576,7 @@ int pc_eofsrc(void *handle);
void *pc_openasm(char *filename); /* read/write */
void pc_closeasm(void *handle,int deletefile);
void pc_resetasm(void *handle);
int pc_writeasm(void *handle,char *str);
int pc_writeasm(void *handle,const char *str);
char *pc_readasm(void *handle,char *target,int maxchars);
/* output to binary (.AMX) file */
@ -589,161 +586,144 @@ void pc_resetbin(void *handle,long offset);
int pc_writebin(void *handle,void *buffer,int size);
long pc_lengthbin(void *handle); /* return the length of the file */
#if defined __cplusplus
}
#endif
/* by default, functions and variables used in throughout the compiler
* files are "external"
*/
#if !defined SC_FUNC
#define SC_FUNC
#endif
#if !defined SC_VDECL
#define SC_VDECL extern
#endif
#if !defined SC_VDEFINE
#define SC_VDEFINE
#endif
void sp_fdbg_ntv_start(int num_natives);
void sp_fdbg_ntv_hook(int index, symbol *sym);
/* function prototypes in SC1.C */
SC_FUNC void set_extension(char *filename,char *extension,int force);
SC_FUNC symbol *fetchfunc(char *name);
SC_FUNC char *operator_symname(char *symname,char *opername,int tag1,int tag2,int numtags,int resulttag);
SC_FUNC char *funcdisplayname(char *dest,char *funcname);
SC_FUNC int constexpr(cell *val,int *tag,symbol **symptr);
SC_FUNC constvalue *append_constval(constvalue *table,const char *name,cell val,int index);
SC_FUNC constvalue *find_constval(constvalue *table,char *name,int index);
SC_FUNC void delete_consttable(constvalue *table);
SC_FUNC symbol *add_constant(char *name,cell val,int vclass,int tag);
SC_FUNC void exporttag(int tag);
SC_FUNC void sc_attachdocumentation(symbol *sym);
SC_FUNC constvalue *find_tag_byval(int tag);
SC_FUNC int get_actual_compound(symbol *sym);
void set_extension(char *filename,const char *extension,int force);
symbol *fetchfunc(char *name);
char *operator_symname(char *symname,const char *opername,int tag1,int tag2,int numtags,int resulttag);
char *funcdisplayname(char *dest,char *funcname);
int exprconst(cell *val,int *tag,symbol **symptr);
constvalue *append_constval(constvalue *table,const char *name,cell val,int index);
constvalue *find_constval(constvalue *table,char *name,int index);
void delete_consttable(constvalue *table);
symbol *add_constant(const char *name,cell val,int vclass,int tag);
void exporttag(int tag);
void sc_attachdocumentation(symbol *sym);
constvalue *find_tag_byval(int tag);
int get_actual_compound(symbol *sym);
/* function prototypes in SC2.C */
#define PUSHSTK_P(v) { stkitem s_; s_.pv=(v); pushstk(s_); }
#define PUSHSTK_I(v) { stkitem s_; s_.i=(v); pushstk(s_); }
#define POPSTK_P() (popstk().pv)
#define POPSTK_I() (popstk().i)
SC_FUNC void pushstk(stkitem val);
SC_FUNC stkitem popstk(void);
SC_FUNC void clearstk(void);
SC_FUNC int plungequalifiedfile(char *name); /* explicit path included */
SC_FUNC int plungefile(char *name,int try_currentpath,int try_includepaths); /* search through "include" paths */
SC_FUNC void preprocess(void);
SC_FUNC void lexinit(void);
SC_FUNC int lex(cell *lexvalue,char **lexsym);
SC_FUNC int lextok(token_t *tok);
SC_FUNC int lexpeek(int id);
SC_FUNC void lexpush(void);
SC_FUNC void lexclr(int clreol);
SC_FUNC int matchtoken(int token);
SC_FUNC int tokeninfo(cell *val,char **str);
SC_FUNC int needtoken(int token);
SC_FUNC int matchtoken2(int id, token_t *tok);
SC_FUNC int expecttoken(int id, token_t *tok);
SC_FUNC int matchsymbol(token_ident_t *ident);
SC_FUNC int needsymbol(token_ident_t *ident);
SC_FUNC int peek_same_line();
SC_FUNC int require_newline(int allow_semi);
SC_FUNC void litadd(cell value);
SC_FUNC void litinsert(cell value,int pos);
SC_FUNC int alphanum(char c);
SC_FUNC int ishex(char c);
SC_FUNC void delete_symbol(symbol *root,symbol *sym);
SC_FUNC void delete_symbols(symbol *root,int level,int del_labels,int delete_functions);
SC_FUNC int refer_symbol(symbol *entry,symbol *bywhom);
SC_FUNC void markusage(symbol *sym,int usage);
SC_FUNC symbol *findglb(const char *name,int filter);
SC_FUNC symbol *findloc(const char *name);
SC_FUNC symbol *findconst(const char *name,int *matchtag);
SC_FUNC symbol *finddepend(const symbol *parent);
SC_FUNC symbol *addsym(const char *name,cell addr,int ident,int vclass,int tag, int usage);
SC_FUNC symbol *addvariable(const char *name,cell addr,int ident,int vclass,int tag,
void pushstk(stkitem val);
stkitem popstk(void);
void clearstk(void);
int plungequalifiedfile(char *name); /* explicit path included */
int plungefile(char *name,int try_currentpath,int try_includepaths); /* search through "include" paths */
void preprocess(void);
void lexinit(void);
int lex(cell *lexvalue,char **lexsym);
int lextok(token_t *tok);
int lexpeek(int id);
void lexpush(void);
void lexclr(int clreol);
int matchtoken(int token);
int tokeninfo(cell *val,char **str);
int needtoken(int token);
int matchtoken2(int id, token_t *tok);
int expecttoken(int id, token_t *tok);
int matchsymbol(token_ident_t *ident);
int needsymbol(token_ident_t *ident);
int peek_same_line();
int require_newline(int allow_semi);
void litadd(cell value);
void litinsert(cell value,int pos);
int alphanum(char c);
int ishex(char c);
void delete_symbol(symbol *root,symbol *sym);
void delete_symbols(symbol *root,int level,int del_labels,int delete_functions);
int refer_symbol(symbol *entry,symbol *bywhom);
void markusage(symbol *sym,int usage);
symbol *findglb(const char *name,int filter);
symbol *findloc(const char *name);
symbol *findconst(const char *name,int *matchtag);
symbol *finddepend(const symbol *parent);
symbol *addsym(const char *name,cell addr,int ident,int vclass,int tag, int usage);
symbol *addvariable(const char *name,cell addr,int ident,int vclass,int tag,
int dim[],int numdim,int idxtag[]);
SC_FUNC symbol *addvariable2(const char *name,cell addr,int ident,int vclass,int tag,
symbol *addvariable2(const char *name,cell addr,int ident,int vclass,int tag,
int dim[],int numdim,int idxtag[],int slength);
SC_FUNC symbol *addvariable3(declinfo_t *decl,cell addr,int vclass,int slength);
SC_FUNC int getlabel(void);
SC_FUNC char *itoh(ucell val);
symbol *addvariable3(declinfo_t *decl,cell addr,int vclass,int slength);
int getlabel(void);
char *itoh(ucell val);
#define MATCHTAG_COERCE 0x1 // allow coercion
#define MATCHTAG_SILENT 0x2 // silence the error(213) warning
#define MATCHTAG_COMMUTATIVE 0x4 // order does not matter
/* function prototypes in SC3.C */
SC_FUNC int check_userop(void (*oper)(void),int tag1,int tag2,int numparam,
int check_userop(void (*oper)(void),int tag1,int tag2,int numparam,
value *lval,int *resulttag);
SC_FUNC int matchtag(int formaltag,int actualtag,int allowcoerce);
SC_FUNC int checktag(int tags[],int numtags,int exprtag);
SC_FUNC int expression(cell *val,int *tag,symbol **symptr,int chkfuncresult,value *_lval);
SC_FUNC int sc_getstateid(constvalue **automaton,constvalue **state);
SC_FUNC cell array_totalsize(symbol *sym);
SC_FUNC int matchtag_string(int ident, int tag);
SC_FUNC int checktag_string(value *sym1, value *sym2);
SC_FUNC int checktags_string(int tags[], int numtags, value *sym1);
SC_FUNC int lvalexpr(svalue *sval);
int matchtag(int formaltag,int actualtag,int allowcoerce);
int checktag(int tags[],int numtags,int exprtag);
int expression(cell *val,int *tag,symbol **symptr,int chkfuncresult,value *_lval);
int sc_getstateid(constvalue **automaton,constvalue **state);
cell array_totalsize(symbol *sym);
int matchtag_string(int ident, int tag);
int checktag_string(value *sym1, value *sym2);
int checktags_string(int tags[], int numtags, value *sym1);
int lvalexpr(svalue *sval);
/* function prototypes in SC4.C */
SC_FUNC void writeleader(symbol *root);
SC_FUNC void writetrailer(void);
SC_FUNC void begcseg(void);
SC_FUNC void begdseg(void);
SC_FUNC void setline(int chkbounds);
SC_FUNC void setfiledirect(char *name);
SC_FUNC void setlinedirect(int line);
SC_FUNC void setlabel(int index);
SC_FUNC void markexpr(optmark type,const char *name,cell offset);
SC_FUNC void startfunc(char *fname);
SC_FUNC void endfunc(void);
SC_FUNC void alignframe(int numbytes);
SC_FUNC void rvalue(value *lval);
SC_FUNC void address(symbol *ptr,regid reg);
SC_FUNC void store(value *lval);
SC_FUNC void loadreg(cell address,regid reg);
SC_FUNC void storereg(cell address,regid reg);
SC_FUNC void memcopy(cell size);
SC_FUNC void copyarray(symbol *sym,cell size);
SC_FUNC void fillarray(symbol *sym,cell size,cell value);
SC_FUNC void ldconst(cell val,regid reg);
SC_FUNC void moveto1(void);
SC_FUNC void move_alt(void);
SC_FUNC void pushreg(regid reg);
SC_FUNC void pushval(cell val);
SC_FUNC void popreg(regid reg);
SC_FUNC void genarray(int dims, int _autozero);
SC_FUNC void swap1(void);
SC_FUNC void ffswitch(int label);
SC_FUNC void ffcase(cell value,char *labelname,int newtable);
SC_FUNC void ffcall(symbol *sym,const char *label,int numargs);
SC_FUNC void ffret(int remparams);
SC_FUNC void ffabort(int reason);
SC_FUNC void ffbounds(cell size);
SC_FUNC void jumplabel(int number);
SC_FUNC void defstorage(void);
SC_FUNC void modstk(int delta);
SC_FUNC void setstk(cell value);
SC_FUNC void modheap(int delta);
SC_FUNC void modheap_i();
SC_FUNC void setheap_pri(void);
SC_FUNC void setheap(cell value);
SC_FUNC void cell2addr(void);
SC_FUNC void cell2addr_alt(void);
SC_FUNC void addr2cell(void);
SC_FUNC void char2addr(void);
SC_FUNC void charalign(void);
SC_FUNC void addconst(cell value);
SC_FUNC void setheap_save(cell value);
SC_FUNC void stradjust(regid reg);
SC_FUNC void invoke_getter(struct methodmap_method_s *method);
SC_FUNC void invoke_setter(struct methodmap_method_s *method, int save);
SC_FUNC void inc_pri();
SC_FUNC void dec_pri();
void writeleader(symbol *root);
void writetrailer(void);
void begcseg(void);
void begdseg(void);
void setline(int chkbounds);
void setfiledirect(char *name);
void setlinedirect(int line);
void setlabel(int index);
void markexpr(optmark type,const char *name,cell offset);
void startfunc(char *fname);
void endfunc(void);
void alignframe(int numbytes);
void rvalue(value *lval);
void address(symbol *ptr,regid reg);
void store(value *lval);
void loadreg(cell address,regid reg);
void storereg(cell address,regid reg);
void memcopy(cell size);
void copyarray(symbol *sym,cell size);
void fillarray(symbol *sym,cell size,cell value);
void ldconst(cell val,regid reg);
void moveto1(void);
void move_alt(void);
void pushreg(regid reg);
void pushval(cell val);
void popreg(regid reg);
void genarray(int dims, int _autozero);
void swap1(void);
void ffswitch(int label);
void ffcase(cell value,char *labelname,int newtable);
void ffcall(symbol *sym,const char *label,int numargs);
void ffret(int remparams);
void ffabort(int reason);
void ffbounds(cell size);
void jumplabel(int number);
void defstorage(void);
void modstk(int delta);
void setstk(cell value);
void modheap(int delta);
void modheap_i();
void setheap_pri(void);
void setheap(cell value);
void cell2addr(void);
void cell2addr_alt(void);
void addr2cell(void);
void char2addr(void);
void charalign(void);
void addconst(cell value);
void setheap_save(cell value);
void stradjust(regid reg);
void invoke_getter(struct methodmap_method_s *method);
void invoke_setter(struct methodmap_method_s *method, int save);
void inc_pri();
void dec_pri();
void load_hidden_arg();
/* Code generation functions for arithmetic operators.
*
@ -753,218 +733,204 @@ SC_FUNC void dec_pri();
* | +--------- "u"nsigned operator, "s"igned operator or "b"oth
* +------------- "o"perator
*/
SC_FUNC void os_mult(void); /* multiplication (signed) */
SC_FUNC void os_div(void); /* division (signed) */
SC_FUNC void os_mod(void); /* modulus (signed) */
SC_FUNC void ob_add(void); /* addition */
SC_FUNC void ob_sub(void); /* subtraction */
SC_FUNC void ob_sal(void); /* shift left (arithmetic) */
SC_FUNC void os_sar(void); /* shift right (arithmetic, signed) */
SC_FUNC void ou_sar(void); /* shift right (logical, unsigned) */
SC_FUNC void ob_or(void); /* bitwise or */
SC_FUNC void ob_xor(void); /* bitwise xor */
SC_FUNC void ob_and(void); /* bitwise and */
SC_FUNC void ob_eq(void); /* equality */
SC_FUNC void ob_ne(void); /* inequality */
SC_FUNC void relop_prefix(void);
SC_FUNC void relop_suffix(void);
SC_FUNC void os_le(void); /* less or equal (signed) */
SC_FUNC void os_ge(void); /* greater or equal (signed) */
SC_FUNC void os_lt(void); /* less (signed) */
SC_FUNC void os_gt(void); /* greater (signed) */
void os_mult(void); /* multiplication (signed) */
void os_div(void); /* division (signed) */
void os_mod(void); /* modulus (signed) */
void ob_add(void); /* addition */
void ob_sub(void); /* subtraction */
void ob_sal(void); /* shift left (arithmetic) */
void os_sar(void); /* shift right (arithmetic, signed) */
void ou_sar(void); /* shift right (logical, unsigned) */
void ob_or(void); /* bitwise or */
void ob_xor(void); /* bitwise xor */
void ob_and(void); /* bitwise and */
void ob_eq(void); /* equality */
void ob_ne(void); /* inequality */
void relop_prefix(void);
void relop_suffix(void);
void os_le(void); /* less or equal (signed) */
void os_ge(void); /* greater or equal (signed) */
void os_lt(void); /* less (signed) */
void os_gt(void); /* greater (signed) */
SC_FUNC void lneg(void);
SC_FUNC void neg(void);
SC_FUNC void invert(void);
SC_FUNC void nooperation(void);
SC_FUNC void inc(value *lval);
SC_FUNC void dec(value *lval);
SC_FUNC void jmp_ne0(int number);
SC_FUNC void jmp_eq0(int number);
SC_FUNC void outval(cell val,int newline);
void lneg(void);
void neg(void);
void invert(void);
void nooperation(void);
void inc(value *lval);
void dec(value *lval);
void jmp_ne0(int number);
void jmp_eq0(int number);
void outval(cell val,int newline);
/* function prototypes in SC5.C */
SC_FUNC int error(int number,...);
SC_FUNC void errorset(int code,int line);
int error(int number,...);
void errorset(int code,int line);
/* function prototypes in SC6.C */
SC_FUNC int assemble(FILE *fout,FILE *fin);
int assemble(void *fout,void *fin);
/* function prototypes in SC7.C */
SC_FUNC void stgbuffer_cleanup(void);
SC_FUNC void stgmark(char mark);
SC_FUNC void stgwrite(const char *st);
SC_FUNC void stgout(int index);
SC_FUNC void stgdel(int index,cell code_index);
SC_FUNC int stgget(int *index,cell *code_index);
SC_FUNC void stgset(int onoff);
SC_FUNC int phopt_init(void);
SC_FUNC int phopt_cleanup(void);
void stgbuffer_cleanup(void);
void stgmark(char mark);
void stgwrite(const char *st);
void stgout(int index);
void stgdel(int index,cell code_index);
int stgget(int *index,cell *code_index);
void stgset(int onoff);
int phopt_init(void);
int phopt_cleanup(void);
/* function prototypes in SCLIST.C */
SC_FUNC char* duplicatestring(const char* sourcestring);
SC_FUNC stringpair *insert_alias(char *name,char *alias);
SC_FUNC stringpair *find_alias(char *name);
SC_FUNC int lookup_alias(char *target,char *name);
SC_FUNC void delete_aliastable(void);
SC_FUNC stringlist *insert_path(char *path);
SC_FUNC char *get_path(int index);
SC_FUNC void delete_pathtable(void);
SC_FUNC stringpair *insert_subst(char *pattern,char *substitution,int prefixlen);
SC_FUNC int get_subst(int index,char **pattern,char **substitution);
SC_FUNC stringpair *find_subst(char *name,int length);
SC_FUNC int delete_subst(char *name,int length);
SC_FUNC void delete_substtable(void);
SC_FUNC stringlist *insert_sourcefile(char *string);
SC_FUNC char *get_sourcefile(int index);
SC_FUNC void delete_sourcefiletable(void);
SC_FUNC stringlist *insert_docstring(char *string);
SC_FUNC char *get_docstring(int index);
SC_FUNC void delete_docstring(int index);
SC_FUNC void delete_docstringtable(void);
SC_FUNC stringlist *insert_autolist(char *string);
SC_FUNC char *get_autolist(int index);
SC_FUNC void delete_autolisttable(void);
SC_FUNC stringlist *insert_dbgfile(const char *filename);
SC_FUNC stringlist *insert_dbgline(int linenr);
SC_FUNC stringlist *insert_dbgsymbol(symbol *sym);
SC_FUNC char *get_dbgstring(int index);
SC_FUNC void delete_dbgstringtable(void);
SC_FUNC stringlist *get_dbgstrings();
/* function prototypes in SCMEMFILE.C */
#if !defined tMEMFILE
typedef unsigned char MEMFILE;
#define tMEMFILE 1
#endif
MEMFILE *mfcreate(const char *filename);
void mfclose(MEMFILE *mf);
int mfdump(MEMFILE *mf);
long mflength(const MEMFILE *mf);
long mfseek(MEMFILE *mf,long offset,int whence);
unsigned int mfwrite(MEMFILE *mf,const unsigned char *buffer,unsigned int size);
unsigned int mfread(MEMFILE *mf,unsigned char *buffer,unsigned int size);
char *mfgets(MEMFILE *mf,char *string,unsigned int size);
int mfputs(MEMFILE *mf,const char *string);
char* duplicatestring(const char* sourcestring);
stringpair *insert_alias(char *name,char *alias);
stringpair *find_alias(char *name);
int lookup_alias(char *target,char *name);
void delete_aliastable(void);
stringlist *insert_path(char *path);
char *get_path(int index);
void delete_pathtable(void);
stringpair *insert_subst(const char *pattern,const char *substitution,int prefixlen);
int get_subst(int index,char **pattern,char **substitution);
stringpair *find_subst(char *name,int length);
int delete_subst(char *name,int length);
void delete_substtable(void);
stringlist *insert_sourcefile(char *string);
char *get_sourcefile(int index);
void delete_sourcefiletable(void);
stringlist *insert_docstring(char *string);
char *get_docstring(int index);
void delete_docstring(int index);
void delete_docstringtable(void);
stringlist *insert_autolist(const char *string);
char *get_autolist(int index);
void delete_autolisttable(void);
stringlist *insert_dbgfile(const char *filename);
stringlist *insert_dbgline(int linenr);
stringlist *insert_dbgsymbol(symbol *sym);
char *get_dbgstring(int index);
void delete_dbgstringtable(void);
stringlist *get_dbgstrings();
/* function prototypes in SCI18N.C */
#define MAXCODEPAGE 12
SC_FUNC int cp_path(const char *root,const char *directory);
SC_FUNC int cp_set(const char *name);
SC_FUNC cell cp_translate(const unsigned char *string,const unsigned char **endptr);
SC_FUNC cell get_utf8_char(const unsigned char *string,const unsigned char **endptr);
SC_FUNC int scan_utf8(FILE *fp,const char *filename);
int cp_path(const char *root,const char *directory);
int cp_set(const char *name);
cell cp_translate(const unsigned char *string,const unsigned char **endptr);
cell get_utf8_char(const unsigned char *string,const unsigned char **endptr);
int scan_utf8(void *fp,const char *filename);
/* function prototypes in SCSTATE.C */
SC_FUNC constvalue *automaton_add(const char *name);
SC_FUNC constvalue *automaton_find(const char *name);
SC_FUNC constvalue *automaton_findid(int id);
SC_FUNC constvalue *state_add(const char *name,int fsa_id);
SC_FUNC constvalue *state_find(const char *name,int fsa_id);
SC_FUNC constvalue *state_findid(int id);
SC_FUNC void state_buildlist(int **list,int *listsize,int *count,int stateid);
SC_FUNC int state_addlist(int *list,int count,int fsa_id);
SC_FUNC void state_deletetable(void);
SC_FUNC int state_getfsa(int listid);
SC_FUNC int state_count(int listid);
SC_FUNC int state_inlist(int listid,int state);
SC_FUNC int state_listitem(int listid,int index);
SC_FUNC void state_conflict(symbol *root);
SC_FUNC int state_conflict_id(int listid1,int listid2);
constvalue *automaton_add(const char *name);
constvalue *automaton_find(const char *name);
constvalue *automaton_findid(int id);
constvalue *state_add(const char *name,int fsa_id);
constvalue *state_find(const char *name,int fsa_id);
constvalue *state_findid(int id);
void state_buildlist(int **list,int *listsize,int *count,int stateid);
int state_addlist(int *list,int count,int fsa_id);
void state_deletetable(void);
int state_getfsa(int listid);
int state_count(int listid);
int state_inlist(int listid,int state);
int state_listitem(int listid,int index);
void state_conflict(symbol *root);
int state_conflict_id(int listid1,int listid2);
/* external variables (defined in scvars.c) */
#if !defined SC_SKIP_VDECL
typedef struct HashTable HashTable;
SC_VDECL struct HashTable *sp_Globals;
SC_VDECL symbol loctab; /* local symbol table */
SC_VDECL symbol glbtab; /* global symbol table */
SC_VDECL cell *litq; /* the literal queue */
SC_VDECL unsigned char pline[]; /* the line read from the input file */
SC_VDECL const unsigned char *lptr;/* points to the current position in "pline" */
SC_VDECL constvalue tagname_tab;/* tagname table */
SC_VDECL constvalue libname_tab;/* library table (#pragma library "..." syntax) */
SC_VDECL constvalue *curlibrary;/* current library */
SC_VDECL int pc_addlibtable; /* is the library table added to the AMX file? */
SC_VDECL symbol *curfunc; /* pointer to current function */
SC_VDECL char *inpfname; /* name of the file currently read from */
SC_VDECL char outfname[]; /* intermediate (assembler) file name */
SC_VDECL char binfname[]; /* binary file name */
SC_VDECL char errfname[]; /* error file name */
SC_VDECL char sc_ctrlchar; /* the control character (or escape character) */
SC_VDECL char sc_ctrlchar_org;/* the default control character */
SC_VDECL int litidx; /* index to literal table */
SC_VDECL int litmax; /* current size of the literal table */
SC_VDECL int stgidx; /* index to the staging buffer */
SC_VDECL int sc_labnum; /* number of (internal) labels */
SC_VDECL int staging; /* true if staging output */
SC_VDECL cell declared; /* number of local cells declared */
SC_VDECL cell glb_declared; /* number of global cells declared */
SC_VDECL cell code_idx; /* number of bytes with generated code */
SC_VDECL int ntv_funcid; /* incremental number of native function */
SC_VDECL int errnum; /* number of errors */
SC_VDECL int warnnum; /* number of warnings */
SC_VDECL int sc_debug; /* debug/optimization options (bit field) */
SC_VDECL int sc_packstr; /* strings are packed by default? */
SC_VDECL int sc_asmfile; /* create .ASM file? */
SC_VDECL int sc_listing; /* create .LST file? */
SC_VDECL int sc_compress; /* compress bytecode? */
SC_VDECL int sc_needsemicolon;/* semicolon required to terminate expressions? */
SC_VDECL int sc_dataalign; /* data alignment value */
SC_VDECL int sc_alignnext; /* must frame of the next function be aligned? */
SC_VDECL int pc_docexpr; /* must expression be attached to documentation comment? */
SC_VDECL int sc_showincludes; /* show include files? */
SC_VDECL int curseg; /* 1 if currently parsing CODE, 2 if parsing DATA */
SC_VDECL cell pc_stksize; /* stack size */
SC_VDECL cell pc_amxlimit; /* abstract machine size limit (code + data, or only code) */
SC_VDECL cell pc_amxram; /* abstract machine data size limit */
SC_VDECL int freading; /* is there an input file ready for reading? */
SC_VDECL int fline; /* the line number in the current file */
SC_VDECL short fnumber; /* number of files in the file table (debugging) */
SC_VDECL short fcurrent; /* current file being processed (debugging) */
SC_VDECL short sc_intest; /* true if inside a test */
SC_VDECL int sideeffect; /* true if an expression causes a side-effect */
SC_VDECL int stmtindent; /* current indent of the statement */
SC_VDECL int indent_nowarn; /* skip warning "217 loose indentation" */
SC_VDECL int sc_tabsize; /* number of spaces that a TAB represents */
SC_VDECL short sc_allowtags; /* allow/detect tagnames in lex() */
SC_VDECL int sc_status; /* read/write status */
SC_VDECL int sc_err_status; /* TRUE if errors should be generated even if sc_status = SKIP */
SC_VDECL int sc_rationaltag; /* tag for rational numbers */
SC_VDECL int rational_digits; /* number of fractional digits */
SC_VDECL int sc_allowproccall;/* allow/detect tagnames in lex() */
SC_VDECL short sc_is_utf8; /* is this source file in UTF-8 encoding */
SC_VDECL char *pc_deprecate; /* if non-NULL, mark next declaration as deprecated */
SC_VDECL int sc_curstates; /* ID of the current state list */
SC_VDECL int pc_optimize; /* (peephole) optimization level */
SC_VDECL int pc_memflags; /* special flags for the stack/heap usage */
SC_VDECL int pc_functag; /* global function tag */
SC_VDECL int pc_tag_string; /* global String tag */
SC_VDECL int pc_tag_void; /* global void tag */
SC_VDECL int pc_tag_object; /* root object tag */
SC_VDECL int pc_tag_bool; /* global bool tag */
SC_VDECL int pc_tag_null_t; /* the null type */
SC_VDECL int pc_tag_nullfunc_t; /* the null function type */
SC_VDECL int pc_anytag; /* global any tag */
SC_VDECL int glbstringread; /* last global string read */
SC_VDECL int sc_require_newdecls; /* only newdecls are allowed */
extern struct HashTable *sp_Globals;
extern symbol loctab; /* local symbol table */
extern symbol glbtab; /* global symbol table */
extern cell *litq; /* the literal queue */
extern unsigned char pline[]; /* the line read from the input file */
extern const unsigned char *lptr;/* points to the current position in "pline" */
extern constvalue tagname_tab;/* tagname table */
extern constvalue libname_tab;/* library table (#pragma library "..." syntax) */
extern constvalue *curlibrary;/* current library */
extern int pc_addlibtable; /* is the library table added to the AMX file? */
extern symbol *curfunc; /* pointer to current function */
extern char *inpfname; /* name of the file currently read from */
extern char outfname[]; /* intermediate (assembler) file name */
extern char binfname[]; /* binary file name */
extern char errfname[]; /* error file name */
extern char sc_ctrlchar; /* the control character (or escape character) */
extern char sc_ctrlchar_org;/* the default control character */
extern int litidx; /* index to literal table */
extern int litmax; /* current size of the literal table */
extern int stgidx; /* index to the staging buffer */
extern int sc_labnum; /* number of (internal) labels */
extern int staging; /* true if staging output */
extern cell declared; /* number of local cells declared */
extern cell glb_declared; /* number of global cells declared */
extern cell code_idx; /* number of bytes with generated code */
extern int ntv_funcid; /* incremental number of native function */
extern int errnum; /* number of errors */
extern int warnnum; /* number of warnings */
extern int sc_debug; /* debug/optimization options (bit field) */
extern int sc_packstr; /* strings are packed by default? */
extern int sc_asmfile; /* create .ASM file? */
extern int sc_listing; /* create .LST file? */
extern int sc_compress; /* compress bytecode? */
extern int sc_needsemicolon;/* semicolon required to terminate expressions? */
extern int sc_dataalign; /* data alignment value */
extern int sc_alignnext; /* must frame of the next function be aligned? */
extern int pc_docexpr; /* must expression be attached to documentation comment? */
extern int sc_showincludes; /* show include files? */
extern int curseg; /* 1 if currently parsing CODE, 2 if parsing DATA */
extern cell pc_stksize; /* stack size */
extern cell pc_amxlimit; /* abstract machine size limit (code + data, or only code) */
extern cell pc_amxram; /* abstract machine data size limit */
extern int freading; /* is there an input file ready for reading? */
extern int fline; /* the line number in the current file */
extern short fnumber; /* number of files in the file table (debugging) */
extern short fcurrent; /* current file being processed (debugging) */
extern short sc_intest; /* true if inside a test */
extern int sideeffect; /* true if an expression causes a side-effect */
extern int stmtindent; /* current indent of the statement */
extern int indent_nowarn; /* skip warning "217 loose indentation" */
extern int sc_tabsize; /* number of spaces that a TAB represents */
extern short sc_allowtags; /* allow/detect tagnames in lex() */
extern int sc_status; /* read/write status */
extern int sc_err_status; /* TRUE if errors should be generated even if sc_status = SKIP */
extern int sc_rationaltag; /* tag for rational numbers */
extern int rational_digits; /* number of fractional digits */
extern int sc_allowproccall;/* allow/detect tagnames in lex() */
extern short sc_is_utf8; /* is this source file in UTF-8 encoding */
extern char *pc_deprecate; /* if non-NULL, mark next declaration as deprecated */
extern int sc_curstates; /* ID of the current state list */
extern int pc_optimize; /* (peephole) optimization level */
extern int pc_memflags; /* special flags for the stack/heap usage */
extern int pc_functag; /* global function tag */
extern int pc_tag_string; /* global String tag */
extern int pc_tag_void; /* global void tag */
extern int pc_tag_object; /* root object tag */
extern int pc_tag_bool; /* global bool tag */
extern int pc_tag_null_t; /* the null type */
extern int pc_tag_nullfunc_t; /* the null function type */
extern int pc_anytag; /* global any tag */
extern int glbstringread; /* last global string read */
extern int sc_require_newdecls; /* only newdecls are allowed */
SC_VDECL constvalue sc_automaton_tab; /* automaton table */
SC_VDECL constvalue sc_state_tab; /* state table */
extern constvalue sc_automaton_tab; /* automaton table */
extern constvalue sc_state_tab; /* state table */
SC_VDECL FILE *inpf; /* file read from (source or include) */
SC_VDECL FILE *inpf_org; /* main source file */
SC_VDECL FILE *outf; /* file written to */
extern void *inpf; /* file read from (source or include) */
extern void *inpf_org; /* main source file */
extern void *outf; /* file written to */
SC_VDECL jmp_buf errbuf; /* target of longjmp() on a fatal error */
extern jmp_buf errbuf; /* target of longjmp() on a fatal error */
#if !defined SC_LIGHT
SC_VDECL int sc_makereport; /* generate a cross-reference report */
extern int sc_makereport; /* generate a cross-reference report */
#endif
#if defined WIN32
#if !defined snprintf
#define snprintf _snprintf
#endif
# if !defined snprintf
# define snprintf _snprintf
# define vsnprintf _vsnprintf
# endif
#endif
#endif /* SC_SKIP_VDECL */

File diff suppressed because it is too large Load Diff

View File

@ -47,7 +47,7 @@ static cell litchar(const unsigned char **lptr,int flags);
static symbol *find_symbol(const symbol *root,const char *name,int fnumber,int automaton,int *cmptag);
static void substallpatterns(unsigned char *line,int buffersize);
static int match(char *st,int end);
static int match(const char *st,int end);
static int alpha(char c);
#define SKIPMODE 1 /* bit field in "#if" stack */
@ -86,7 +86,7 @@ static double pow10(double d)
static stkitem *stack=NULL;
static int stkidx=0,stktop=0;
SC_FUNC void pushstk(stkitem val)
void pushstk(stkitem val)
{
assert(stkidx<=stktop);
if (stkidx==stktop) {
@ -109,7 +109,7 @@ SC_FUNC void pushstk(stkitem val)
stkidx+=1;
}
SC_FUNC stkitem popstk(void)
stkitem popstk(void)
{
if (stkidx==0) {
stkitem s;
@ -121,7 +121,7 @@ SC_FUNC stkitem popstk(void)
return stack[stkidx];
}
SC_FUNC void clearstk(void)
void clearstk(void)
{
assert(stack!=NULL || stktop==0);
if (stack!=NULL) {
@ -132,9 +132,10 @@ SC_FUNC void clearstk(void)
assert(stktop==0);
}
SC_FUNC int plungequalifiedfile(char *name)
int plungequalifiedfile(char *name)
{
static char *extensions[] = { ".inc", ".p", ".pawn" };
static const char *extensions[] = { ".inc", ".p", ".pawn" };
void *fp;
char *ext;
int ext_idx;
@ -184,7 +185,7 @@ static char *extensions[] = { ".inc", ".p", ".pawn" };
return TRUE;
}
SC_FUNC int plungefile(char *name,int try_currentpath,int try_includepaths)
int plungefile(char *name,int try_currentpath,int try_includepaths)
{
int result=FALSE;
@ -671,11 +672,11 @@ static int ftoi(cell *val,const unsigned char *curptr)
exp=(exp*10)+(*ptr-'0');
ptr++;
} /* while */
#if defined __GNUC__
fmult=pow10(exp*sign);
#else
fmult=pow(10,exp*sign);
#endif
#if defined __GNUC__
fmult=pow10(exp*sign);
#else
fmult=pow(10.0,exp*sign);
#endif
fnum *= fmult;
dnum *= (unsigned long)(fmult+0.5);
} /* if */
@ -796,7 +797,7 @@ static int preproc_expr(cell *val,int *tag)
term=strchr((char*)pline,'\0');
assert(term!=NULL);
chrcat((char*)pline,PREPROC_TERM); /* the "DEL" code (see SC.H) */
result=constexpr(val,tag,NULL); /* get value (or 0 on error) */
result=exprconst(val,tag,NULL); /* get value (or 0 on error) */
*term='\0'; /* erase the token (if still present) */
lexclr(FALSE); /* clear any "pushed" tokens */
return result;
@ -1251,7 +1252,7 @@ static int command(void)
break;
default: {
char s2[20];
extern char *sc_tokens[];/* forward declaration */
extern const char *sc_tokens[];/* forward declaration */
if (tok<256)
sprintf(s2,"%c",(char)tok);
else
@ -1482,7 +1483,7 @@ static char *strdel(char *str,size_t len)
return str;
}
static char *strins(char *dest,char *src,size_t srclen)
static char *strins(char *dest,const char *src,size_t srclen)
{
size_t destlen=strlen(dest);
assert(srclen<=strlen(src));
@ -1792,7 +1793,7 @@ static int scanellipsis(const unsigned char *lptr)
* pline (altered)
* freading (referred to only)
*/
SC_FUNC void preprocess(void)
void preprocess(void)
{
int iscommand;
@ -1931,7 +1932,7 @@ static full_token_t *next_token()
return &sTokenBuffer->tokens[cursor];
}
SC_FUNC void lexinit(void)
void lexinit(void)
{
stkidx=0; /* index for pushstk() and popstk() */
iflevel=0; /* preprocessor: nesting of "#if" is currently 0 */
@ -1943,7 +1944,7 @@ SC_FUNC void lexinit(void)
sTokenBuffer = &sNormalBuffer;
}
char *sc_tokens[] = {
const char *sc_tokens[] = {
"*=", "/=", "%=", "+=", "-=", "<<=", ">>>=", ">>=", "&=", "^=", "|=",
"||", "&&", "==", "!=", "<=", ">=", "<<", ">>>", ">>", "++", "--",
"...", "..", "::",
@ -1961,7 +1962,8 @@ char *sc_tokens[] = {
"public",
"return",
"sizeof", "sleep", "static", "stock", "struct", "switch",
"tagof", "*then",
"tagof", "*then", "typedef",
"union",
"void",
"while",
"#assert", "#define", "#else", "#elseif", "#emit", "#endif", "#endinput",
@ -1969,7 +1971,7 @@ char *sc_tokens[] = {
"#tryinclude", "#undef",
";", ";", "-integer value-", "-rational value-", "-identifier-",
"-label-", "-string-"
};
};
static full_token_t *advance_token_ptr()
{
@ -2000,10 +2002,9 @@ static void lexpop()
sTokenBuffer->cursor = 0;
}
SC_FUNC int lex(cell *lexvalue,char **lexsym)
int lex(cell *lexvalue,char **lexsym)
{
int i,toolong,newline;
char **tokptr;
const unsigned char *starttoken;
if (sTokenBuffer->depth > 0) {
@ -2054,7 +2055,7 @@ SC_FUNC int lex(cell *lexvalue,char **lexsym)
tok->start.col = (int)(lptr - pline);
i=tFIRST;
tokptr=sc_tokens;
const char **tokptr=sc_tokens;
while (i<=tMIDDLE) { /* match multi-character operators */
if (*lptr==**tokptr && match(*tokptr,FALSE)) {
tok->id = i;
@ -2259,7 +2260,7 @@ SC_FUNC int lex(cell *lexvalue,char **lexsym)
* to read and return the information from these variables, rather than
* to read in a new token from the input file.
*/
SC_FUNC void lexpush(void)
void lexpush(void)
{
assert(sTokenBuffer->depth < MAX_TOKEN_DEPTH);
sTokenBuffer->depth++;
@ -2276,7 +2277,7 @@ SC_FUNC void lexpush(void)
* symbol (a not continue with some old one). This is required upon return
* from Assembler mode, and in a few cases after detecting an syntax error.
*/
SC_FUNC void lexclr(int clreol)
void lexclr(int clreol)
{
sTokenBuffer->depth = 0;
if (clreol) {
@ -2286,7 +2287,7 @@ SC_FUNC void lexclr(int clreol)
}
// Return true if the symbol is ahead, false otherwise.
SC_FUNC int lexpeek(int id)
int lexpeek(int id)
{
if (matchtoken(id)) {
lexpush();
@ -2305,7 +2306,7 @@ SC_FUNC int lexpeek(int id)
* (i.e. not present in the source code) should not be pushed back, which is
* why it is sometimes important to distinguish the two.
*/
SC_FUNC int matchtoken(int token)
int matchtoken(int token)
{
cell val;
char *str;
@ -2338,7 +2339,7 @@ SC_FUNC int matchtoken(int token)
*
* The token itself is the return value. Normally, this one is already known.
*/
SC_FUNC int tokeninfo(cell *val,char **str)
int tokeninfo(cell *val,char **str)
{
*val = current_token()->value;
*str = current_token()->str;
@ -2352,7 +2353,7 @@ SC_FUNC int tokeninfo(cell *val,char **str)
* this function returns 1 for "token found" and 2 for "statement termination
* token" found; see function matchtoken() for details.
*/
SC_FUNC int needtoken(int token)
int needtoken(int token)
{
char s1[20],s2[20];
int t;
@ -2379,7 +2380,7 @@ SC_FUNC int needtoken(int token)
// If the next token is on the current line, return that token. Otherwise,
// return tNEWLINE.
SC_FUNC int peek_same_line()
int peek_same_line()
{
// We should not call this without having parsed at least one token.
assert(sTokenBuffer->num_tokens > 0);
@ -2407,7 +2408,7 @@ SC_FUNC int peek_same_line()
return tEOL;
}
SC_FUNC int require_newline(int allow_semi)
int require_newline(int allow_semi)
{
if (allow_semi) {
// Semicolon must be on the same line.
@ -2440,7 +2441,7 @@ SC_FUNC int require_newline(int allow_semi)
*
* Global references: lptr (altered)
*/
static int match(char *st,int end)
static int match(const char *st,int end)
{
int k;
const unsigned char *ptr;
@ -2482,7 +2483,7 @@ static void chk_grow_litq(void)
* Global references: litidx (altered)
* litq (altered)
*/
SC_FUNC void litadd(cell value)
void litadd(cell value)
{
chk_grow_litq();
assert(litidx<litmax);
@ -2497,7 +2498,7 @@ SC_FUNC void litadd(cell value)
* Global references: litidx (altered)
* litq (altered)
*/
SC_FUNC void litinsert(cell value,int pos)
void litinsert(cell value,int pos)
{
chk_grow_litq();
assert(litidx<litmax);
@ -2632,7 +2633,7 @@ static int alpha(char c)
*
* Test if character "c" is alphanumeric ("a".."z", "0".."9", "_" or "@")
*/
SC_FUNC int alphanum(char c)
int alphanum(char c)
{
return (alpha(c) || isdigit(c));
}
@ -2641,7 +2642,7 @@ SC_FUNC int alphanum(char c)
*
* Test if character "c" is a hexadecimal digit ("0".."9" or "a".."f").
*/
SC_FUNC int ishex(char c)
int ishex(char c)
{
return (c>='0' && c<='9') || (c>='a' && c<='f') || (c>='A' && c<='F');
}
@ -2717,7 +2718,7 @@ static void free_symbol(symbol *sym)
free(sym);
}
SC_FUNC void delete_symbol(symbol *root,symbol *sym)
void delete_symbol(symbol *root,symbol *sym)
{
symbol *origRoot=root;
/* find the symbol and its predecessor
@ -2738,7 +2739,7 @@ SC_FUNC void delete_symbol(symbol *root,symbol *sym)
free_symbol(sym);
}
SC_FUNC int get_actual_compound(symbol *sym)
int get_actual_compound(symbol *sym)
{
if (sym->ident == iARRAY || sym->ident == iREFARRAY) {
while (sym->parent)
@ -2748,7 +2749,7 @@ SC_FUNC int get_actual_compound(symbol *sym)
return sym->compound;
}
SC_FUNC void delete_symbols(symbol *root,int level,int delete_labels,int delete_functions)
void delete_symbols(symbol *root,int level,int delete_labels,int delete_functions)
{
symbol *origRoot=root;
symbol *sym,*parent_sym;
@ -2908,7 +2909,7 @@ static symbol *find_symbol_child(const symbol *root,const symbol *sym)
* bywhom will be the function that uses a variable or that calls
* the function.
*/
SC_FUNC int refer_symbol(symbol *entry,symbol *bywhom)
int refer_symbol(symbol *entry,symbol *bywhom)
{
int count;
@ -2950,7 +2951,7 @@ SC_FUNC int refer_symbol(symbol *entry,symbol *bywhom)
return TRUE;
}
SC_FUNC void markusage(symbol *sym,int usage)
void markusage(symbol *sym,int usage)
{
assert(sym!=NULL);
sym->usage |= (char)usage;
@ -2974,7 +2975,7 @@ SC_FUNC void markusage(symbol *sym,int usage)
*
* Returns a pointer to the global symbol (if found) or NULL (if not found)
*/
SC_FUNC symbol *findglb(const char *name,int filter)
symbol *findglb(const char *name,int filter)
{
/* find a symbol with a matching automaton first */
symbol *sym=NULL;
@ -3010,12 +3011,12 @@ SC_FUNC symbol *findglb(const char *name,int filter)
* Returns a pointer to the local symbol (if found) or NULL (if not found).
* See add_symbol() how the deepest nesting level is searched first.
*/
SC_FUNC symbol *findloc(const char *name)
symbol *findloc(const char *name)
{
return find_symbol(&loctab,name,-1,-1,NULL);
}
SC_FUNC symbol *findconst(const char *name,int *cmptag)
symbol *findconst(const char *name,int *cmptag)
{
symbol *sym;
@ -3033,7 +3034,7 @@ SC_FUNC symbol *findconst(const char *name,int *cmptag)
return sym;
}
SC_FUNC symbol *finddepend(const symbol *parent)
symbol *finddepend(const symbol *parent)
{
symbol *sym;
@ -3048,7 +3049,7 @@ SC_FUNC symbol *finddepend(const symbol *parent)
* Adds a symbol to the symbol table (either global or local variables,
* or global and local constants).
*/
SC_FUNC symbol *addsym(const char *name,cell addr,int ident,int vclass,int tag,int usage)
symbol *addsym(const char *name,cell addr,int ident,int vclass,int tag,int usage)
{
symbol entry, **refer;
@ -3083,13 +3084,13 @@ SC_FUNC symbol *addsym(const char *name,cell addr,int ident,int vclass,int tag,i
return add_symbol(&loctab,&entry,FALSE);
}
SC_FUNC symbol *addvariable(const char *name,cell addr,int ident,int vclass,int tag,
symbol *addvariable(const char *name,cell addr,int ident,int vclass,int tag,
int dim[],int numdim,int idxtag[])
{
return addvariable2(name,addr,ident,vclass,tag,dim,numdim,idxtag,0);
}
SC_FUNC symbol *addvariable3(declinfo_t *decl,cell addr,int vclass,int slength)
symbol *addvariable3(declinfo_t *decl,cell addr,int vclass,int slength)
{
typeinfo_t *type = &decl->type;
return addvariable2(
@ -3105,7 +3106,7 @@ SC_FUNC symbol *addvariable3(declinfo_t *decl,cell addr,int vclass,int slength)
);
}
SC_FUNC symbol *addvariable2(const char *name,cell addr,int ident,int vclass,int tag,
symbol *addvariable2(const char *name,cell addr,int ident,int vclass,int tag,
int dim[],int numdim,int idxtag[],int slength)
{
symbol *sym;
@ -3154,7 +3155,7 @@ SC_FUNC symbol *addvariable2(const char *name,cell addr,int ident,int vclass,int
* Returns te next internal label number. The global variable sc_labnum is
* initialized to zero.
*/
SC_FUNC int getlabel(void)
int getlabel(void)
{
return sc_labnum++;
}
@ -3164,7 +3165,7 @@ SC_FUNC int getlabel(void)
* Converts a number to a hexadecimal string and returns a pointer to that
* string. This function is NOT re-entrant.
*/
SC_FUNC char *itoh(ucell val)
char *itoh(ucell val)
{
static char itohstr[30];
char *ptr;
@ -3199,13 +3200,13 @@ static char itohstr[30];
return itohstr;
}
SC_FUNC int lextok(token_t *tok)
int lextok(token_t *tok)
{
tok->id = lex(&tok->val, &tok->str);
return tok->id;
}
SC_FUNC int expecttoken(int id, token_t *tok)
int expecttoken(int id, token_t *tok)
{
int rval = needtoken(id);
if (rval) {
@ -3217,7 +3218,7 @@ SC_FUNC int expecttoken(int id, token_t *tok)
return FALSE;
}
SC_FUNC int matchtoken2(int id, token_t *tok)
int matchtoken2(int id, token_t *tok)
{
if (matchtoken(id)) {
tok->id = tokeninfo(&tok->val, &tok->str);
@ -3226,7 +3227,7 @@ SC_FUNC int matchtoken2(int id, token_t *tok)
return FALSE;
}
SC_FUNC int matchsymbol(token_ident_t *ident)
int matchsymbol(token_ident_t *ident)
{
if (lextok(&ident->tok) != tSYMBOL) {
lexpush();
@ -3237,7 +3238,7 @@ SC_FUNC int matchsymbol(token_ident_t *ident)
return TRUE;
}
SC_FUNC int needsymbol(token_ident_t *ident)
int needsymbol(token_ident_t *ident)
{
if (!expecttoken(tSYMBOL, &ident->tok))
return FALSE;

View File

@ -35,7 +35,7 @@ static int skim(int *opstr,void (*testfunc)(int),int dropval,int endval,
int (*hier)(value*),value *lval);
static void dropout(int lvalue,void (*testfunc)(int val),int exit1,value *lval);
static int plnge(int *opstr,int opoff,int (*hier)(value *lval),value *lval,
char *forcetag,int chkbitwise);
const char *forcetag,int chkbitwise);
static int plnge1(int (*hier)(value *lval),value *lval);
static void plnge2(void (*oper)(void),
int (*hier)(value *lval),
@ -113,16 +113,20 @@ static int nextop(int *opidx,int *list)
return FALSE; /* entire list scanned, nothing found */
}
SC_FUNC int check_userop(void (*oper)(void),int tag1,int tag2,int numparam,
int check_userop(void (*oper)(void),int tag1,int tag2,int numparam,
value *lval,int *resulttag)
{
static char *binoperstr[] = { "*", "/", "%", "+", "-", "", "", "",
"", "", "", "<=", ">=", "<", ">", "==", "!=" };
static int binoper_savepri[] = { FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
FALSE, FALSE, FALSE, FALSE, FALSE,
TRUE, TRUE, TRUE, TRUE, FALSE, FALSE };
static char *unoperstr[] = { "!", "-", "++", "--" };
static void (*unopers[])(void) = { lneg, neg, user_inc, user_dec };
static const char *binoperstr[] = {
"*", "/", "%", "+", "-", "", "", "",
"", "", "", "<=", ">=", "<", ">", "==", "!="
};
static int binoper_savepri[] = { FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
FALSE, FALSE, FALSE, FALSE, FALSE,
TRUE, TRUE, TRUE, TRUE, FALSE, FALSE
};
static const char *unoperstr[] = { "!", "-", "++", "--" };
static void (*unopers[])(void) = { lneg, neg, user_inc, user_dec };
char opername[4] = "", symbolname[sNAMEMAX+1];
int i,swapparams,savepri,savealt;
int paramspassed;
@ -286,7 +290,7 @@ static void (*unopers[])(void) = { lneg, neg, user_inc, user_dec };
return TRUE;
}
SC_FUNC int checktags_string(int tags[], int numtags, value *sym1)
int checktags_string(int tags[], int numtags, value *sym1)
{
int i;
if (sym1->ident == iARRAY || sym1->ident == iREFARRAY)
@ -301,7 +305,7 @@ SC_FUNC int checktags_string(int tags[], int numtags, value *sym1)
return FALSE;
}
SC_FUNC int checktag_string(value *sym1, value *sym2)
int checktag_string(value *sym1, value *sym2)
{
if (sym1->ident == iARRAY || sym2->ident == iARRAY ||
sym1->ident == iREFARRAY || sym2->ident == iREFARRAY)
@ -317,7 +321,7 @@ SC_FUNC int checktag_string(value *sym1, value *sym2)
return FALSE;
}
SC_FUNC const char *type_to_name(int tag)
const char *type_to_name(int tag)
{
if (tag == 0)
return "int";
@ -335,7 +339,7 @@ SC_FUNC const char *type_to_name(int tag)
return "unknown";
}
SC_FUNC int matchtag_string(int ident, int tag)
int matchtag_string(int ident, int tag)
{
if (ident == iARRAY || ident == iREFARRAY)
return FALSE;
@ -413,15 +417,81 @@ static int matchobjecttags(int formaltag, int actualtag, int flags)
return obj_typeerror(133, formaltag, actualtag);
}
static int matchreturntag(functag_t *t, symbol *sym)
static int matchreturntag(const functag_t *formal, const functag_t *actual)
{
if (t->ret_tag == sym->tag)
return TRUE;
if (t->ret_tag == pc_tag_void && (sym->tag == 0 && !(sym->usage & uRETVALUE)))
if (formal->ret_tag == actual->ret_tag)
return TRUE;
if (formal->ret_tag == pc_tag_void) {
if (actual->ret_tag == 0 && !(actual->usage & uRETVALUE))
return TRUE;
}
return FALSE;
}
static int funcarg_compare(const funcarg_t *formal, const funcarg_t *actual)
{
// Check type.
if (actual->ident != formal->ident)
return FALSE;
// Check rank.
if (actual->dimcount != formal->dimcount)
return FALSE;
// Check arity.
for (int i = 0; i < formal->dimcount; i++) {
if (actual->dims[i] != formal->dims[i])
return FALSE;
}
// Check tags.
if (actual->tagcount != formal->tagcount)
return FALSE;
for (int i = 0; i < formal->tagcount; i++) {
// Note we invert the order we pass things to matchtag() here. If the
// typedef specifies base type X, and the function specifies derived
// type Y, we want this to type since such an assignment is valid.
//
// Most programming languages do not subtype arguments like this. We do
// it in SourcePawn to preserve compatibility during the Transitional
// Syntax effort.
int actual_tag = actual->tags[i];
int formal_tag = formal->tags[i];
if (!matchtag(actual_tag, formal_tag, MATCHTAG_SILENT|MATCHTAG_COERCE))
return FALSE;
}
return TRUE;
}
static int functag_compare(const functag_t *formal, const functag_t *actual)
{
// Check return types.
if (!matchreturntag(formal, actual))
return FALSE;
// Make sure there are no trailing arguments.
if (actual->argcount > formal->argcount)
return FALSE;
// Check arguments.
for (int i = 0; i < formal->argcount; i++) {
const funcarg_t *formal_arg = &formal->args[i];
if (i >= actual->argcount) {
if (formal_arg->ommittable)
return TRUE;
return FALSE;
}
const funcarg_t *actual_arg = &actual->args[i];
if (!funcarg_compare(formal_arg, actual_arg))
return FALSE;
}
return TRUE;
}
static int matchfunctags(int formaltag, int actualtag)
{
if (formaltag == pc_functag && (actualtag & FUNCTAG))
@ -433,141 +503,23 @@ static int matchfunctags(int formaltag, int actualtag)
if (!(actualtag & FUNCTAG))
return FALSE;
constvalue *v = find_tag_byval(actualtag);
int index;
short usage = uPUBLIC;
symbol *sym, *found = NULL;
funcenum_t *e;
functag_t *t;
if (strncmp(v->name, "$Func", 5) != 0)
functag_t *actual = functag_find_intrinsic(actualtag);
if (!actual)
return FALSE;
/* Now we have to go about looking up each function in this enum. WHICH IS IT. */
e = funcenums_find_byval(formaltag);
funcenum_t *e = funcenums_find_by_tag(formaltag);
if (!e)
return FALSE;
assert(v->name[5] == '@' || v->name[5] == '!');
/* Deduce which function type this is */
if (v->name[5] == '@')
{
usage = uPUBLIC;
} else if (v->name[5] == '!') {
usage = uSTOCK;
}
index = atoi(&v->name[6]);
assert(index >= 0);
/* Find the function, either by public idx or code addr */
if (usage == uPUBLIC) {
for (sym=glbtab.next; sym!=NULL; sym=sym->next) {
if (sym->ident==iFUNCTN && (sym->usage & uPUBLIC)!=0 && (sym->vclass == sGLOBAL)) {
if (index-- == 0) {
found = sym;
break;
}
}
}
} else if (usage == uSTOCK) {
for (sym=glbtab.next; sym!=NULL; sym=sym->next) {
if (sym->ident==iFUNCTN && (sym->vclass == sGLOBAL)) {
if (sym->codeaddr == index) {
found = sym;
break;
}
}
}
}
if (!found) {
assert(found);
return FALSE;
}
/* Wow, we now have:
* 1) The functional enum deduced from formaltag
* 2) The function trying to be shoved in deduced from actualtag
* Now we have to check if it matches any one of the functags inside the enum.
*/
t = e->first;
while (t) {
int curarg,skip=0,i;
arginfo *func_arg;
funcarg_t *enum_arg;
/* Check return type first. */
if (!matchreturntag(t, sym)) {
t = t->next;
continue;
}
/* Check usage */
if (t->type != usage) {
t = t->next;
continue;
}
/* Begin iterating arguments */
for (curarg=0; curarg<t->argcount; curarg++) {
enum_arg = &t->args[curarg];
/* Check whether we've exhausted our arguments */
if (sym->dim.arglist[curarg].ident == 0) {
/* Can we bail out early? */
if (!enum_arg->ommittable) {
/* No! */
skip = 1;
}
break;
}
func_arg = &sym->dim.arglist[curarg];
/* First check the ident type */
if (enum_arg->ident != func_arg->ident) {
skip = 1;
break;
}
/* Next check arrayness */
if (enum_arg->dimcount != func_arg->numdim) {
skip = 1;
break;
}
if (enum_arg->dimcount > 0) {
for (i=0; i<enum_arg->dimcount; i++) {
if (enum_arg->dims[i] != func_arg->dim[i]) {
skip = 1;
break;
}
}
if (skip)
break;
}
/* Lastly, check the tags */
if (enum_arg->tagcount != func_arg->numtags) {
skip = 1;
break;
}
/* They should all be in the same order just for clarity... */
for (i=0; i<enum_arg->tagcount; i++) {
if (!matchtag(func_arg->tags[i], enum_arg->tags[i], MATCHTAG_SILENT|MATCHTAG_COERCE)) {
skip = 1;
break;
}
}
if (skip)
break;
}
if (!skip) {
/* Make sure there are no trailing arguments */
if (sym->dim.arglist[curarg].ident == 0)
return TRUE;
}
t = t->next;
for (functag_t *formal = e->first; formal; formal = formal->next) {
if (functag_compare(formal, actual))
return TRUE;
}
return FALSE;
}
SC_FUNC int matchtag(int formaltag, int actualtag, int flags)
int matchtag(int formaltag, int actualtag, int flags)
{
if (formaltag == actualtag)
return TRUE;
@ -771,7 +723,7 @@ static void checkfunction(value *lval)
* Plunge to a lower level
*/
static int plnge(int *opstr,int opoff,int (*hier)(value *lval),value *lval,
char *forcetag,int chkbitwise)
const char *forcetag,int chkbitwise)
{
int lvalue,opidx;
int count;
@ -914,10 +866,10 @@ static void plnge2(void (*oper)(void),
checkfunction(lval1);
checkfunction(lval2);
if (lval1->ident==iARRAY || lval1->ident==iREFARRAY) {
char *ptr=(lval1->sym!=NULL) ? lval1->sym->name : "-unknown-";
const char *ptr=(lval1->sym!=NULL) ? lval1->sym->name : "-unknown-";
error(33,ptr); /* array must be indexed */
} else if (lval2->ident==iARRAY || lval2->ident==iREFARRAY) {
char *ptr=(lval2->sym!=NULL) ? lval2->sym->name : "-unknown-";
const char *ptr=(lval2->sym!=NULL) ? lval2->sym->name : "-unknown-";
error(33,ptr); /* array must be indexed */
} /* if */
/* ??? ^^^ should do same kind of error checking with functions */
@ -1006,7 +958,7 @@ static cell calc(cell left,void (*oper)(),cell right,char *boolresult)
return 0;
}
SC_FUNC int lvalexpr(svalue *sval)
int lvalexpr(svalue *sval)
{
memset(sval, 0, sizeof(*sval));
@ -1019,7 +971,7 @@ SC_FUNC int lvalexpr(svalue *sval)
return sval->val.ident;
}
SC_FUNC int expression(cell *val,int *tag,symbol **symptr,int chkfuncresult,value *_lval)
int expression(cell *val,int *tag,symbol **symptr,int chkfuncresult,value *_lval)
{
value lval={0};
pushheaplist();
@ -1042,7 +994,7 @@ SC_FUNC int expression(cell *val,int *tag,symbol **symptr,int chkfuncresult,valu
return lval.ident;
}
SC_FUNC int sc_getstateid(constvalue **automaton,constvalue **state)
int sc_getstateid(constvalue **automaton,constvalue **state)
{
char name[sNAMEMAX+1];
cell val;
@ -1085,7 +1037,7 @@ SC_FUNC int sc_getstateid(constvalue **automaton,constvalue **state)
assert(*automaton!=NULL);
*state=state_find(name,fsa);
if (*state==NULL) {
char *fsaname=(*automaton)->name;
const char *fsaname=(*automaton)->name;
if (*fsaname=='\0')
fsaname="<main>";
error(87,name,fsaname); /* unknown state for automaton */
@ -1095,7 +1047,7 @@ SC_FUNC int sc_getstateid(constvalue **automaton,constvalue **state)
return 1;
}
SC_FUNC cell array_totalsize(symbol *sym)
cell array_totalsize(symbol *sym)
{
cell length;
@ -2281,48 +2233,36 @@ restart:
} /* if */
if (sym!=NULL && lval1->ident==iFUNCTN) {
assert(sym->ident==iFUNCTN);
if (sc_allowproccall) {
// Note: this is unreachable in SourceMod, we don't support paren-less calls.
callfunction(sym,NULL,lval1,FALSE);
} else if ((sym->usage & uNATIVE) != uNATIVE) {
symbol *oldsym=sym;
int n=-1,iter=0;
int usage = ((sym->usage & uPUBLIC) == uPUBLIC) ? uPUBLIC : 0;
cell code_addr=0;
for (sym=glbtab.next; sym!=NULL; sym=sym->next) {
if (sym->ident==iFUNCTN && sym->vclass == sGLOBAL && (!usage || (sym->usage & usage)))
{
if (strcmp(sym->name, lval1->sym->name)==0) {
n = iter;
code_addr = sym->codeaddr;
break;
}
iter++;
}
}
if (n!=-1) {
char faketag[sNAMEMAX+1];
lval1->sym=NULL;
lval1->ident=iCONSTEXPR;
/* Generate a quick pseudo-tag! */
if (usage == uPUBLIC) {
lval1->constval=(n<<1)|1;
snprintf(faketag, sizeof(faketag)-1, "$Func@%d", n);
} else {
lval1->constval=(code_addr<<1)|0;
snprintf(faketag, sizeof(faketag)-1, "$Func!%d", code_addr);
error(153);
}
lval1->tag=pc_addtag_flags(faketag, FIXEDTAG|FUNCTAG);
oldsym->usage |= uREAD;
sym->usage |= uREAD;
} else {
error(76); /* invalid function call, or syntax error */
} /* if */
if (sym->usage & uNATIVE) {
error(76);
return FALSE;
} else {
error(76); /* invalid function call, or syntax error */
}
int public_index = 0;
symbol *target = NULL;
for (symbol *iter = glbtab.next; iter; iter = iter->next) {
if (iter->ident != iFUNCTN || iter->vclass != sGLOBAL)
continue;
if (strcmp(iter->name, lval1->sym->name) == 0) {
target = iter;
break;
}
if (iter->usage & uPUBLIC)
public_index++;
}
if (!target || !(target->usage & uPUBLIC)) {
error(76);
return FALSE;
}
funcenum_t *fe = funcenum_for_symbol(target);
lval1->sym = NULL;
lval1->ident = iCONSTEXPR;
lval1->constval = (public_index << 1) | 1;
lval1->tag = fe->tag;
target->usage |= uREAD;
} /* if */
return lvalue;
}
@ -2590,7 +2530,7 @@ static int nesting=0;
sc_allowproccall=FALSE; /* parameters may not use procedure call syntax */
if ((sym->flags & flgDEPRECATED)!=0) {
char *ptr= (sym->documentation!=NULL) ? sym->documentation : "";
const char *ptr= (sym->documentation!=NULL) ? sym->documentation : "";
error(234,sym->name,ptr); /* deprecated (probably a native function) */
} /* if */
@ -2621,10 +2561,9 @@ static int nesting=0;
do {
if (!pending_this && matchtoken('.')) {
namedparams=TRUE;
if (needtoken(tSYMBOL))
tokeninfo(&lexval,&lexstr);
else
lexstr="";
if (!needtoken(tSYMBOL))
break;
tokeninfo(&lexval,&lexstr);
argpos=findnamedarg(arg,lexstr);
if (argpos<0) {
error(17,lexstr); /* undefined symbol */

Some files were not shown because too many files have changed in this diff Show More