core/vm/sp_vm_basecontext.cpp
author David Anderson <dvander@alliedmods.net>
Sun Aug 26 17:41:02 2007 +0000 (2007-08-26)
changeset 1369 bd9ccced1b1a
parent 1367 0253af5c3bee
child 1382 5399d6f24417
permissions -rw-r--r--
fixed amb834 - command callbacks could potentially occur on invalid clients in very rare cases
dvander@1231
     1
/**
dvander@1231
     2
 * vim: set ts=4 :
ds@1330
     3
 * =============================================================================
dvander@1231
     4
 * SourcePawn
dvander@1231
     5
 * Copyright (C) 2004-2007 AlliedModders LLC.  All rights reserved.
ds@1330
     6
 * =============================================================================
dvander@1231
     7
 *
ds@1330
     8
 * This program is free software; you can redistribute it and/or modify it under
ds@1330
     9
 * the terms of the GNU General Public License, version 3.0, as published by the
ds@1330
    10
 * Free Software Foundation.
dvander@1231
    11
 * 
ds@1330
    12
 * This program is distributed in the hope that it will be useful, but WITHOUT
ds@1330
    13
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
ds@1330
    14
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
ds@1330
    15
 * details.
dvander@1231
    16
 *
ds@1330
    17
 * You should have received a copy of the GNU General Public License along with
ds@1330
    18
 * this program.  If not, see <http://www.gnu.org/licenses/>.
dvander@1231
    19
 *
ds@1330
    20
 * As a special exception, AlliedModders LLC gives you permission to link the
ds@1330
    21
 * code of this program (as well as its derivative works) to "Half-Life 2," the
ds@1330
    22
 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
ds@1330
    23
 * by the Valve Corporation.  You must obey the GNU General Public License in
ds@1330
    24
 * all respects for all other code used.  Additionally, AlliedModders LLC grants
ds@1330
    25
 * this exception to all derivative works.  AlliedModders LLC defines further
ds@1330
    26
 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
ds@1330
    27
 * or <http://www.sourcemod.net/license.php>.
dvander@1231
    28
 *
dvander@1231
    29
 * Version: $Id$
dvander@1269
    30
 */
dvander@1269
    31
dvander@1269
    32
#include <string.h>
dvander@1269
    33
#include <stdarg.h>
dvander@1269
    34
#include <assert.h>
dvander@1269
    35
#include <limits.h>
dvander@1269
    36
#include "sp_vm_api.h"
dvander@1269
    37
#include "sp_vm_basecontext.h"
dvander@1269
    38
#include "sp_vm_engine.h"
dvander@1269
    39
dvander@1269
    40
#ifdef SOURCEMOD_BUILD
dvander@1269
    41
#include "Logger.h"
dvander@1339
    42
#include "DebugReporter.h"
dvander@1269
    43
#endif
dvander@1269
    44
dvander@1269
    45
using namespace SourcePawn;
dvander@1269
    46
dvander@1269
    47
extern SourcePawnEngine g_SourcePawn;
dvander@1269
    48
dvander@1269
    49
#define CELLBOUNDMAX	(INT_MAX/sizeof(cell_t))
dvander@1269
    50
#define STACKMARGIN		((cell_t)(16*sizeof(cell_t)))
dvander@1269
    51
dvander@1269
    52
int GlobalDebugBreak(sp_context_t *ctx, uint32_t frm, uint32_t cip)
dvander@1269
    53
{
dvander@1269
    54
	g_SourcePawn.RunTracer(ctx, frm, cip);
dvander@1269
    55
dvander@1269
    56
	return SP_ERROR_NONE;
dvander@1269
    57
}
dvander@1269
    58
dvander@1269
    59
BaseContext::BaseContext(sp_context_t *_ctx)
dvander@1269
    60
{
dvander@1269
    61
	ctx = _ctx;
dvander@1269
    62
	ctx->context = this;
dvander@1269
    63
	ctx->dbreak = GlobalDebugBreak;
dvander@1269
    64
	m_InExec = false;
dvander@1269
    65
	m_CustomMsg = false;
dvander@1269
    66
	m_funcsnum = ctx->vmbase->FunctionCount(ctx);
dvander@1269
    67
#if 0
dvander@1269
    68
	m_priv_funcs = NULL;
dvander@1269
    69
#endif
dvander@1269
    70
	m_pub_funcs = NULL;
dvander@1269
    71
dvander@1269
    72
#if 0
dvander@1269
    73
	/**
dvander@1269
    74
	 * Note: Since the m_plugin member will never change,
dvander@1269
    75
	 * it is safe to assume the function count will never change
dvander@1269
    76
	 */
dvander@1269
    77
	if (m_funcsnum && m_priv_funcs == NULL)
dvander@1269
    78
	{
dvander@1269
    79
		m_priv_funcs = new CFunction *[m_funcsnum];
dvander@1269
    80
		memset(m_priv_funcs, 0, sizeof(CFunction *) * m_funcsnum);
dvander@1269
    81
	} else {
dvander@1269
    82
		m_priv_funcs = NULL;
dvander@1269
    83
	}
dvander@1269
    84
#endif
dvander@1269
    85
dvander@1269
    86
	if (ctx->plugin->info.publics_num && m_pub_funcs == NULL)
dvander@1269
    87
	{
dvander@1269
    88
		m_pub_funcs = new CFunction *[ctx->plugin->info.publics_num];
dvander@1269
    89
		memset(m_pub_funcs, 0, sizeof(CFunction *) * ctx->plugin->info.publics_num);
dvander@1269
    90
	} else {
dvander@1269
    91
		m_pub_funcs = NULL;
dvander@1269
    92
	}
dvander@1269
    93
dvander@1269
    94
	/* Initialize the null references */
dvander@1269
    95
	uint32_t index;
dvander@1269
    96
	if (FindPubvarByName("NULL_VECTOR", &index) == SP_ERROR_NONE)
dvander@1269
    97
	{
dvander@1269
    98
		sp_pubvar_t *pubvar;
dvander@1269
    99
		GetPubvarByIndex(index, &pubvar);
dvander@1269
   100
		m_pNullVec = pubvar->offs;
dvander@1269
   101
	} else {
dvander@1269
   102
		m_pNullVec = NULL;
dvander@1269
   103
	}
dvander@1269
   104
dvander@1269
   105
	if (FindPubvarByName("NULL_STRING", &index) == SP_ERROR_NONE)
dvander@1269
   106
	{
dvander@1269
   107
		sp_pubvar_t *pubvar;
dvander@1269
   108
		GetPubvarByIndex(index, &pubvar);
dvander@1269
   109
		m_pNullString = pubvar->offs;
dvander@1269
   110
	} else {
dvander@1269
   111
		m_pNullString = NULL;
dvander@1269
   112
	}
dvander@1269
   113
}
dvander@1269
   114
dvander@1269
   115
void BaseContext::FlushFunctionCache()
dvander@1269
   116
{
dvander@1269
   117
	if (m_pub_funcs)
dvander@1269
   118
	{
dvander@1269
   119
		for (uint32_t i=0; i<ctx->plugin->info.publics_num; i++)
dvander@1269
   120
		{
dvander@1269
   121
			delete m_pub_funcs[i];
dvander@1269
   122
			m_pub_funcs[i] = NULL;
dvander@1269
   123
		}
dvander@1269
   124
	}
dvander@1269
   125
dvander@1269
   126
#if 0
dvander@1269
   127
	if (m_priv_funcs)
dvander@1269
   128
	{
dvander@1269
   129
		for (unsigned int i=0; i<m_funcsnum; i++)
dvander@1269
   130
		{
dvander@1269
   131
			delete m_priv_funcs[i];
dvander@1269
   132
			m_priv_funcs[i] = NULL;
dvander@1269
   133
		}
dvander@1269
   134
	}
dvander@1269
   135
#endif
dvander@1269
   136
}
dvander@1269
   137
dvander@1269
   138
void BaseContext::RefreshFunctionCache()
dvander@1269
   139
{
dvander@1269
   140
	if (m_pub_funcs)
dvander@1269
   141
	{
dvander@1269
   142
		sp_public_t *pub;
dvander@1269
   143
		for (uint32_t i=0; i<ctx->plugin->info.publics_num; i++)
dvander@1269
   144
		{
dvander@1269
   145
			if (!m_pub_funcs[i])
dvander@1269
   146
			{
dvander@1269
   147
				continue;
dvander@1269
   148
			}
dvander@1269
   149
			if (GetPublicByIndex(i, &pub) != SP_ERROR_NONE)
dvander@1269
   150
			{
dvander@1269
   151
				continue;
dvander@1269
   152
			}
dvander@1339
   153
			m_pub_funcs[i]->Set(pub->code_offs, this, pub->funcid);
dvander@1269
   154
		}
dvander@1269
   155
	}
dvander@1269
   156
dvander@1269
   157
#if 0
dvander@1269
   158
	if (m_priv_funcs)
dvander@1269
   159
	{
dvander@1269
   160
		for (unsigned int i=0; i<m_funcsnum; i++)
dvander@1269
   161
		{
dvander@1269
   162
			if (!m_priv_funcs[i])
dvander@1269
   163
			{
dvander@1269
   164
				continue;
dvander@1269
   165
			}
dvander@1269
   166
			g_pVM->
dvander@1269
   167
		}
dvander@1269
   168
	}
dvander@1269
   169
#endif
dvander@1269
   170
}
dvander@1269
   171
dvander@1269
   172
BaseContext::~BaseContext()
dvander@1269
   173
{
dvander@1269
   174
	FlushFunctionCache();
dvander@1269
   175
	delete [] m_pub_funcs;
dvander@1269
   176
	m_pub_funcs = NULL;
dvander@1269
   177
#if 0
dvander@1269
   178
	delete [] m_priv_funcs;
dvander@1269
   179
	m_priv_funcs = NULL;
dvander@1269
   180
#endif
dvander@1269
   181
}
dvander@1269
   182
dvander@1269
   183
void BaseContext::SetContext(sp_context_t *_ctx)
dvander@1269
   184
{
dvander@1269
   185
	if (!_ctx)
dvander@1269
   186
	{
dvander@1269
   187
		return;
dvander@1269
   188
	}
dvander@1269
   189
	ctx = _ctx;
dvander@1269
   190
	ctx->context = this;
dvander@1269
   191
	ctx->dbreak = GlobalDebugBreak;
dvander@1269
   192
	RefreshFunctionCache();
dvander@1269
   193
}
dvander@1269
   194
dvander@1269
   195
IVirtualMachine *BaseContext::GetVirtualMachine()
dvander@1269
   196
{
dvander@1269
   197
	return (IVirtualMachine *)ctx->vmbase;
dvander@1269
   198
}
dvander@1269
   199
dvander@1269
   200
sp_context_t *BaseContext::GetContext()
dvander@1269
   201
{
dvander@1269
   202
	return ctx;
dvander@1269
   203
}
dvander@1269
   204
dvander@1269
   205
bool BaseContext::IsDebugging()
dvander@1269
   206
{
dvander@1269
   207
	return (ctx->flags & SPFLAG_PLUGIN_DEBUG);
dvander@1269
   208
}
dvander@1269
   209
dvander@1269
   210
int BaseContext::SetDebugBreak(SPVM_DEBUGBREAK newpfn, SPVM_DEBUGBREAK *oldpfn)
dvander@1269
   211
{
dvander@1269
   212
	if (!IsDebugging())
dvander@1269
   213
	{
dvander@1269
   214
		return SP_ERROR_NOTDEBUGGING;
dvander@1269
   215
	}
dvander@1269
   216
dvander@1269
   217
	*oldpfn = ctx->dbreak;
dvander@1269
   218
	ctx->dbreak = newpfn;
dvander@1269
   219
dvander@1269
   220
	return SP_ERROR_NONE;
dvander@1269
   221
}
dvander@1269
   222
dvander@1269
   223
IPluginDebugInfo *BaseContext::GetDebugInfo()
dvander@1269
   224
{
dvander@1339
   225
	if (!IsDebugging())
dvander@1339
   226
	{
dvander@1339
   227
		return NULL;
dvander@1339
   228
	}
dvander@1269
   229
	return this;
dvander@1269
   230
}
dvander@1269
   231
dvander@1269
   232
int BaseContext::Execute(uint32_t code_addr, cell_t *result)
dvander@1269
   233
{
dvander@1269
   234
	if ((ctx->flags & SPFLAG_PLUGIN_PAUSED) == SPFLAG_PLUGIN_PAUSED)
dvander@1269
   235
	{
dvander@1269
   236
		return SP_ERROR_NOT_RUNNABLE;
dvander@1269
   237
	}
dvander@1269
   238
dvander@1269
   239
	/* tada, prevent a crash */
dvander@1269
   240
	cell_t _ignore_result;
dvander@1269
   241
	if (!result)
dvander@1269
   242
	{
dvander@1269
   243
		result = &_ignore_result;
dvander@1269
   244
	}
dvander@1269
   245
dvander@1269
   246
	IVirtualMachine *vm = (IVirtualMachine *)ctx->vmbase;
dvander@1269
   247
dvander@1269
   248
	uint32_t pushcount = ctx->pushcount;
dvander@1269
   249
	int err;
dvander@1269
   250
dvander@1339
   251
	if ((err = PushCell(pushcount++)) != SP_ERROR_NONE)
dvander@1339
   252
	{
dvander@1339
   253
#if defined SOURCEMOD_BUILD
dvander@1339
   254
		g_DbgReporter.GenerateCodeError(this, code_addr, err, "Stack error; cannot complete execution!");
dvander@1339
   255
#endif
dvander@1339
   256
		return SP_ERROR_NOT_RUNNABLE;
dvander@1339
   257
	}
dvander@1269
   258
	ctx->pushcount = 0;
dvander@1269
   259
dvander@1367
   260
	cell_t save_sp = ctx->sp + (pushcount * sizeof(cell_t));
dvander@1269
   261
	cell_t save_hp = ctx->hp;
dvander@1269
   262
	uint32_t n_idx = ctx->n_idx;
dvander@1269
   263
dvander@1269
   264
	bool wasExec = m_InExec;
dvander@1269
   265
dvander@1269
   266
	/* Clear the error state, if any */
dvander@1269
   267
	ctx->n_err = SP_ERROR_NONE;
dvander@1269
   268
	ctx->n_idx = 0;
dvander@1269
   269
	m_InExec = true;
dvander@1269
   270
	m_MsgCache[0] = '\0';
dvander@1269
   271
	m_CustomMsg = false;
dvander@1269
   272
dvander@1269
   273
	g_SourcePawn.PushTracer(ctx);
dvander@1269
   274
dvander@1269
   275
	err = vm->ContextExecute(ctx, code_addr, result);
dvander@1269
   276
dvander@1269
   277
	m_InExec = wasExec;
dvander@1269
   278
dvander@1269
   279
	/**
dvander@1269
   280
	 * :TODO: Calling from a plugin in here will erase the cached message...
dvander@1269
   281
	 * Should that be documented?
dvander@1269
   282
	 */
dvander@1269
   283
	g_SourcePawn.PopTracer(err, m_CustomMsg ? m_MsgCache : NULL);
dvander@1269
   284
dvander@1339
   285
#if defined SOURCEMOD_BUILD
dvander@1269
   286
	if (err == SP_ERROR_NONE)
dvander@1269
   287
	{
dvander@1367
   288
		if (ctx->sp != save_sp)
dvander@1269
   289
		{
dvander@1339
   290
			g_DbgReporter.GenerateCodeError(this,
dvander@1339
   291
				code_addr,
dvander@1339
   292
				SP_ERROR_STACKLEAK,
dvander@1339
   293
				"Stack leak detected: sp:%d should be %d!",
dvander@1339
   294
				ctx->sp,
dvander@1339
   295
				save_sp);
dvander@1269
   296
		}
dvander@1269
   297
		if (ctx->hp != save_hp)
dvander@1269
   298
		{
dvander@1339
   299
			g_DbgReporter.GenerateCodeError(this,
dvander@1339
   300
				code_addr,
dvander@1339
   301
				SP_ERROR_HEAPLEAK,
dvander@1339
   302
				"Heap leak detected: sp:%d should be %d!",
dvander@1339
   303
				ctx->hp,
dvander@1339
   304
				save_hp);
dvander@1269
   305
		}
dvander@1269
   306
	}
dvander@1269
   307
#endif
dvander@1339
   308
dvander@1269
   309
	if (err != SP_ERROR_NONE)
dvander@1269
   310
	{
dvander@1269
   311
		ctx->sp = save_sp;
dvander@1269
   312
		ctx->hp = save_hp;
dvander@1269
   313
	}
dvander@1269
   314
dvander@1269
   315
	ctx->n_idx = n_idx;
dvander@1367
   316
	ctx->n_err = SP_ERROR_NONE;
dvander@1367
   317
	m_MsgCache[0] = '\0';
dvander@1367
   318
	m_CustomMsg = false;
dvander@1269
   319
dvander@1269
   320
	return err;
dvander@1269
   321
}
dvander@1269
   322
dvander@1269
   323
void BaseContext::SetErrorMessage(const char *msg, va_list ap)
dvander@1269
   324
{
dvander@1269
   325
	m_CustomMsg = true;
dvander@1269
   326
dvander@1269
   327
	vsnprintf(m_MsgCache, sizeof(m_MsgCache), msg, ap);
dvander@1269
   328
}
dvander@1269
   329
dvander@1269
   330
cell_t BaseContext::ThrowNativeErrorEx(int error, const char *msg, ...)
dvander@1269
   331
{
dvander@1269
   332
	if (!m_InExec)
dvander@1269
   333
	{
dvander@1269
   334
		return 0;
dvander@1269
   335
	}
dvander@1269
   336
dvander@1269
   337
	ctx->n_err = error;
dvander@1269
   338
	
dvander@1269
   339
	if (msg)
dvander@1269
   340
	{
dvander@1269
   341
		va_list ap;
dvander@1269
   342
		va_start(ap, msg);
dvander@1269
   343
		SetErrorMessage(msg, ap);
dvander@1269
   344
		va_end(ap);
dvander@1269
   345
	}
dvander@1269
   346
dvander@1269
   347
	return 0;
dvander@1269
   348
}
dvander@1269
   349
dvander@1269
   350
cell_t BaseContext::ThrowNativeError(const char *msg, ...)
dvander@1269
   351
{
dvander@1269
   352
	if (!m_InExec)
dvander@1269
   353
	{
dvander@1269
   354
		return 0;
dvander@1269
   355
	}
dvander@1269
   356
dvander@1269
   357
	ctx->n_err = SP_ERROR_NATIVE;
dvander@1269
   358
dvander@1269
   359
	if (msg)
dvander@1269
   360
	{
dvander@1269
   361
		va_list ap;
dvander@1269
   362
		va_start(ap, msg);
dvander@1269
   363
		SetErrorMessage(msg, ap);
dvander@1269
   364
		va_end(ap);
dvander@1269
   365
	}
dvander@1269
   366
dvander@1269
   367
	return 0;
dvander@1269
   368
}
dvander@1269
   369
dvander@1269
   370
int BaseContext::HeapAlloc(unsigned int cells, cell_t *local_addr, cell_t **phys_addr)
dvander@1269
   371
{
dvander@1269
   372
	cell_t *addr;
dvander@1269
   373
	ucell_t realmem;
dvander@1269
   374
dvander@1269
   375
#if 0
dvander@1269
   376
	if (cells > CELLBOUNDMAX)
dvander@1269
   377
	{
dvander@1269
   378
		return SP_ERROR_ARAM;
dvander@1269
   379
	}
dvander@1269
   380
#else
dvander@1269
   381
	assert(cells < CELLBOUNDMAX);
dvander@1269
   382
#endif
dvander@1269
   383
dvander@1269
   384
	realmem = cells * sizeof(cell_t);
dvander@1269
   385
dvander@1269
   386
	/**
dvander@1269
   387
	 * Check if the space between the heap and stack is sufficient.
dvander@1269
   388
	 */
dvander@1269
   389
	if ((cell_t)(ctx->sp - ctx->hp - realmem) < STACKMARGIN)
dvander@1269
   390
	{
dvander@1269
   391
		return SP_ERROR_HEAPLOW;
dvander@1269
   392
	}
dvander@1269
   393
dvander@1269
   394
	addr = (cell_t *)(ctx->memory + ctx->hp);
dvander@1269
   395
	/* store size of allocation in cells */
dvander@1269
   396
	*addr = (cell_t)cells;
dvander@1269
   397
	addr++;
dvander@1269
   398
	ctx->hp += sizeof(cell_t);
dvander@1269
   399
dvander@1269
   400
	*local_addr = ctx->hp;
dvander@1269
   401
dvander@1269
   402
	if (phys_addr)
dvander@1269
   403
	{
dvander@1269
   404
		*phys_addr = addr;
dvander@1269
   405
	}
dvander@1269
   406
dvander@1269
   407
	ctx->hp += realmem;
dvander@1269
   408
dvander@1269
   409
	return SP_ERROR_NONE;
dvander@1269
   410
}
dvander@1269
   411
dvander@1269
   412
int BaseContext::HeapPop(cell_t local_addr)
dvander@1269
   413
{
dvander@1269
   414
	cell_t cellcount;
dvander@1269
   415
	cell_t *addr;
dvander@1269
   416
dvander@1269
   417
	/* check the bounds of this address */
dvander@1269
   418
	local_addr -= sizeof(cell_t);
dvander@1269
   419
	if (local_addr < ctx->heap_base || local_addr >= ctx->sp)
dvander@1269
   420
	{
dvander@1269
   421
		return SP_ERROR_INVALID_ADDRESS;
dvander@1269
   422
	}
dvander@1269
   423
dvander@1269
   424
	addr = (cell_t *)(ctx->memory + local_addr);
dvander@1269
   425
	cellcount = (*addr) * sizeof(cell_t);
dvander@1269
   426
	/* check if this memory count looks valid */
dvander@1269
   427
	if ((signed)(ctx->hp - cellcount - sizeof(cell_t)) != local_addr)
dvander@1269
   428
	{
dvander@1269
   429
		return SP_ERROR_INVALID_ADDRESS;
dvander@1269
   430
	}
dvander@1269
   431
dvander@1269
   432
	ctx->hp = local_addr;
dvander@1269
   433
dvander@1269
   434
	return SP_ERROR_NONE;
dvander@1269
   435
}
dvander@1269
   436
dvander@1269
   437
dvander@1269
   438
int BaseContext::HeapRelease(cell_t local_addr)
dvander@1269
   439
{
dvander@1269
   440
	if (local_addr < ctx->heap_base)
dvander@1269
   441
	{
dvander@1269
   442
		return SP_ERROR_INVALID_ADDRESS;
dvander@1269
   443
	}
dvander@1269
   444
dvander@1269
   445
	ctx->hp = local_addr - sizeof(cell_t);
dvander@1269
   446
dvander@1269
   447
	return SP_ERROR_NONE;
dvander@1269
   448
}
dvander@1269
   449
dvander@1269
   450
int BaseContext::FindNativeByName(const char *name, uint32_t *index)
dvander@1269
   451
{
dvander@1269
   452
	int high;
dvander@1269
   453
dvander@1269
   454
	high = ctx->plugin->info.natives_num - 1;
dvander@1269
   455
dvander@1269
   456
	for (uint32_t i=0; i<ctx->plugin->info.natives_num; i++)
dvander@1269
   457
	{
dvander@1269
   458
		if (strcmp(ctx->natives[i].name, name) == 0)
dvander@1269
   459
		{
dvander@1269
   460
			if (index)
dvander@1269
   461
			{
dvander@1269
   462
				*index = i;
dvander@1269
   463
			}
dvander@1269
   464
			return SP_ERROR_NONE;
dvander@1269
   465
		}
dvander@1269
   466
	}
dvander@1269
   467
dvander@1269
   468
	return SP_ERROR_NOT_FOUND;
dvander@1269
   469
}
dvander@1269
   470
dvander@1269
   471
int BaseContext::GetNativeByIndex(uint32_t index, sp_native_t **native)
dvander@1269
   472
{
dvander@1269
   473
	if (index >= ctx->plugin->info.natives_num)
dvander@1269
   474
	{
dvander@1269
   475
		return SP_ERROR_INDEX;
dvander@1269
   476
	}
dvander@1269
   477
dvander@1269
   478
	if (native)
dvander@1269
   479
	{
dvander@1269
   480
		*native = &(ctx->natives[index]);
dvander@1269
   481
	}
dvander@1269
   482
dvander@1269
   483
	return SP_ERROR_NONE;
dvander@1269
   484
}
dvander@1269
   485
dvander@1269
   486
dvander@1269
   487
uint32_t BaseContext::GetNativesNum()
dvander@1269
   488
{
dvander@1269
   489
	return ctx->plugin->info.natives_num;
dvander@1269
   490
}
dvander@1269
   491
dvander@1269
   492
int BaseContext::FindPublicByName(const char *name, uint32_t *index)
dvander@1269
   493
{
dvander@1269
   494
	int diff, high, low;
dvander@1269
   495
	uint32_t mid;
dvander@1269
   496
dvander@1269
   497
	high = ctx->plugin->info.publics_num - 1;
dvander@1269
   498
	low = 0;
dvander@1269
   499
dvander@1269
   500
	while (low <= high)
dvander@1269
   501
	{
dvander@1269
   502
		mid = (low + high) / 2;
dvander@1269
   503
		diff = strcmp(ctx->publics[mid].name, name);
dvander@1269
   504
		if (diff == 0)
dvander@1269
   505
		{
dvander@1269
   506
			if (index)
dvander@1269
   507
			{
dvander@1269
   508
				*index = mid;
dvander@1269
   509
			}
dvander@1269
   510
			return SP_ERROR_NONE;
dvander@1269
   511
		} else if (diff < 0) {
dvander@1269
   512
			low = mid + 1;
dvander@1269
   513
		} else {
dvander@1269
   514
			high = mid - 1;
dvander@1269
   515
		}
dvander@1269
   516
	}
dvander@1269
   517
dvander@1269
   518
	return SP_ERROR_NOT_FOUND;
dvander@1269
   519
}
dvander@1269
   520
dvander@1269
   521
int BaseContext::GetPublicByIndex(uint32_t index, sp_public_t **pblic)
dvander@1269
   522
{
dvander@1269
   523
	if (index >= ctx->plugin->info.publics_num)
dvander@1269
   524
	{
dvander@1269
   525
		return SP_ERROR_INDEX;
dvander@1269
   526
	}
dvander@1269
   527
dvander@1269
   528
	if (pblic)
dvander@1269
   529
	{
dvander@1269
   530
		*pblic = &(ctx->publics[index]);
dvander@1269
   531
	}
dvander@1269
   532
dvander@1269
   533
	return SP_ERROR_NONE;
dvander@1269
   534
}
dvander@1269
   535
dvander@1269
   536
uint32_t BaseContext::GetPublicsNum()
dvander@1269
   537
{
dvander@1269
   538
	return ctx->plugin->info.publics_num;
dvander@1269
   539
}
dvander@1269
   540
dvander@1269
   541
int BaseContext::GetPubvarByIndex(uint32_t index, sp_pubvar_t **pubvar)
dvander@1269
   542
{
dvander@1269
   543
	if (index >= ctx->plugin->info.pubvars_num)
dvander@1269
   544
	{
dvander@1269
   545
		return SP_ERROR_INDEX;
dvander@1269
   546
	}
dvander@1269
   547
dvander@1269
   548
	if (pubvar)
dvander@1269
   549
	{
dvander@1269
   550
		*pubvar = &(ctx->pubvars[index]);
dvander@1269
   551
	}
dvander@1269
   552
dvander@1269
   553
	return SP_ERROR_NONE;
dvander@1269
   554
}
dvander@1269
   555
dvander@1269
   556
int BaseContext::FindPubvarByName(const char *name, uint32_t *index)
dvander@1269
   557
{
dvander@1269
   558
	int diff, high, low;
dvander@1269
   559
	uint32_t mid;
dvander@1269
   560
dvander@1269
   561
	high = ctx->plugin->info.pubvars_num - 1;
dvander@1269
   562
	low = 0;
dvander@1269
   563
dvander@1269
   564
	while (low <= high)
dvander@1269
   565
	{
dvander@1269
   566
		mid = (low + high) / 2;
dvander@1269
   567
		diff = strcmp(ctx->pubvars[mid].name, name);
dvander@1269
   568
		if (diff == 0)
dvander@1269
   569
		{
dvander@1269
   570
			if (index)
dvander@1269
   571
			{
dvander@1269
   572
				*index = mid;
dvander@1269
   573
			}
dvander@1269
   574
			return SP_ERROR_NONE;
dvander@1269
   575
		} else if (diff < 0) {
dvander@1269
   576
			low = mid + 1;
dvander@1269
   577
		} else {
dvander@1269
   578
			high = mid - 1;
dvander@1269
   579
		}
dvander@1269
   580
	}
dvander@1269
   581
dvander@1269
   582
	return SP_ERROR_NOT_FOUND;
dvander@1269
   583
}
dvander@1269
   584
dvander@1269
   585
int BaseContext::GetPubvarAddrs(uint32_t index, cell_t *local_addr, cell_t **phys_addr)
dvander@1269
   586
{
dvander@1269
   587
	if (index >= ctx->plugin->info.pubvars_num)
dvander@1269
   588
	{
dvander@1269
   589
		return SP_ERROR_INDEX;
dvander@1269
   590
	}
dvander@1269
   591
dvander@1269
   592
	*local_addr = ctx->plugin->info.pubvars[index].address;
dvander@1269
   593
	*phys_addr = ctx->pubvars[index].offs;
dvander@1269
   594
dvander@1269
   595
	return SP_ERROR_NONE;
dvander@1269
   596
}
dvander@1269
   597
dvander@1269
   598
uint32_t BaseContext::GetPubVarsNum()
dvander@1269
   599
{
dvander@1269
   600
	return ctx->plugin->info.pubvars_num;
dvander@1269
   601
}
dvander@1269
   602
dvander@1269
   603
int BaseContext::BindNatives(const sp_nativeinfo_t *natives, unsigned int num, int overwrite)
dvander@1269
   604
{
dvander@1269
   605
	uint32_t i, j, max;
dvander@1269
   606
dvander@1269
   607
	max = ctx->plugin->info.natives_num;
dvander@1269
   608
dvander@1269
   609
	for (i=0; i<max; i++)
dvander@1269
   610
	{
dvander@1269
   611
		if ((ctx->natives[i].status == SP_NATIVE_BOUND) && !overwrite)
dvander@1269
   612
		{
dvander@1269
   613
			continue;
dvander@1269
   614
		}
dvander@1269
   615
dvander@1269
   616
		for (j=0; (natives[j].name) && (!num || j<num); j++)
dvander@1269
   617
		{
dvander@1269
   618
			if (!strcmp(ctx->natives[i].name, natives[j].name))
dvander@1269
   619
			{
dvander@1269
   620
				ctx->natives[i].pfn = natives[j].func;
dvander@1269
   621
				ctx->natives[i].status = SP_NATIVE_BOUND;
dvander@1269
   622
			}
dvander@1269
   623
		}
dvander@1269
   624
	}
dvander@1269
   625
dvander@1269
   626
	return SP_ERROR_NONE;
dvander@1269
   627
}
dvander@1269
   628
dvander@1269
   629
int BaseContext::BindNative(const sp_nativeinfo_t *native)
dvander@1269
   630
{
dvander@1269
   631
	uint32_t index;
dvander@1269
   632
	int err;
dvander@1269
   633
dvander@1269
   634
	if ((err = FindNativeByName(native->name, &index)) != SP_ERROR_NONE)
dvander@1269
   635
	{
dvander@1269
   636
		return err;
dvander@1269
   637
	}
dvander@1269
   638
dvander@1269
   639
	ctx->natives[index].pfn = native->func;
dvander@1269
   640
	ctx->natives[index].status = SP_NATIVE_BOUND;
dvander@1269
   641
dvander@1269
   642
	return SP_ERROR_NONE;
dvander@1269
   643
}
dvander@1269
   644
dvander@1269
   645
int BaseContext::BindNativeToAny(SPVM_NATIVE_FUNC native)
dvander@1269
   646
{
dvander@1269
   647
	uint32_t nativesnum, i;
dvander@1269
   648
dvander@1269
   649
	nativesnum = ctx->plugin->info.natives_num;
dvander@1269
   650
dvander@1269
   651
	for (i=0; i<nativesnum; i++)
dvander@1269
   652
	{
dvander@1269
   653
		if (ctx->natives[i].status == SP_NATIVE_UNBOUND)
dvander@1269
   654
		{
dvander@1269
   655
			ctx->natives[i].pfn = native;
dvander@1269
   656
			ctx->natives[i].status = SP_NATIVE_BOUND;
dvander@1269
   657
		}
dvander@1269
   658
	}
dvander@1269
   659
dvander@1269
   660
	return SP_ERROR_NONE;
dvander@1269
   661
}
dvander@1269
   662
dvander@1269
   663
int BaseContext::LocalToPhysAddr(cell_t local_addr, cell_t **phys_addr)
dvander@1269
   664
{
dvander@1269
   665
	if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size))
dvander@1269
   666
	{
dvander@1269
   667
		return SP_ERROR_INVALID_ADDRESS;
dvander@1269
   668
	}
dvander@1269
   669
dvander@1269
   670
	if (phys_addr)
dvander@1269
   671
	{
dvander@1269
   672
		*phys_addr = (cell_t *)(ctx->memory + local_addr);
dvander@1269
   673
	}
dvander@1269
   674
dvander@1269
   675
	return SP_ERROR_NONE;
dvander@1269
   676
}
dvander@1269
   677
dvander@1269
   678
int BaseContext::PushCell(cell_t value)
dvander@1269
   679
{
dvander@1269
   680
	if ((ctx->hp + STACKMARGIN) > (cell_t)(ctx->sp - sizeof(cell_t)))
dvander@1269
   681
	{
dvander@1269
   682
		return SP_ERROR_STACKLOW;
dvander@1269
   683
	}
dvander@1269
   684
dvander@1269
   685
	ctx->sp -= sizeof(cell_t);
dvander@1269
   686
	*(cell_t *)(ctx->memory + ctx->sp) = value;
dvander@1269
   687
	ctx->pushcount++;
dvander@1269
   688
dvander@1269
   689
	return SP_ERROR_NONE;
dvander@1269
   690
}
dvander@1269
   691
dvander@1269
   692
int BaseContext::PushCellsFromArray(cell_t array[], unsigned int numcells)
dvander@1269
   693
{
dvander@1269
   694
	unsigned int i;
dvander@1269
   695
	int err;
dvander@1269
   696
dvander@1269
   697
	for (i=0; i<numcells; i++)
dvander@1269
   698
	{
dvander@1269
   699
		if ((err = PushCell(array[i])) != SP_ERROR_NONE)
dvander@1269
   700
		{
dvander@1269
   701
			ctx->sp += (cell_t)(i * sizeof(cell_t));
dvander@1269
   702
			ctx->pushcount -= i;
dvander@1269
   703
			return err;
dvander@1269
   704
		}
dvander@1269
   705
	}
dvander@1269
   706
dvander@1269
   707
	return SP_ERROR_NONE;
dvander@1269
   708
}
dvander@1269
   709
dvander@1269
   710
int BaseContext::PushCellArray(cell_t *local_addr, cell_t **phys_addr, cell_t array[], unsigned int numcells)
dvander@1269
   711
{
dvander@1269
   712
	cell_t *ph_addr;
dvander@1269
   713
	int err;
dvander@1269
   714
dvander@1269
   715
	if ((err = HeapAlloc(numcells, local_addr, &ph_addr)) != SP_ERROR_NONE)
dvander@1269
   716
	{
dvander@1269
   717
		return err;
dvander@1269
   718
	}
dvander@1269
   719
dvander@1269
   720
	memcpy(ph_addr, array, numcells * sizeof(cell_t));
dvander@1269
   721
dvander@1269
   722
	if ((err = PushCell(*local_addr)) != SP_ERROR_NONE)
dvander@1269
   723
	{
dvander@1269
   724
		HeapRelease(*local_addr);
dvander@1269
   725
		return err;
dvander@1269
   726
	}
dvander@1269
   727
dvander@1269
   728
	if (phys_addr)
dvander@1269
   729
	{
dvander@1269
   730
		*phys_addr = ph_addr;
dvander@1269
   731
	}
dvander@1269
   732
dvander@1269
   733
	return SP_ERROR_NONE;
dvander@1269
   734
}
dvander@1269
   735
dvander@1269
   736
int BaseContext::LocalToString(cell_t local_addr, char **addr)
dvander@1269
   737
{
dvander@1269
   738
	if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size))
dvander@1269
   739
	{
dvander@1269
   740
		return SP_ERROR_INVALID_ADDRESS;
dvander@1269
   741
	}
dvander@1269
   742
	*addr = (char *)(ctx->memory + local_addr);
dvander@1269
   743
dvander@1269
   744
	return SP_ERROR_NONE;
dvander@1269
   745
}
dvander@1269
   746
dvander@1269
   747
int BaseContext::PushString(cell_t *local_addr, char **phys_addr, const char *string)
dvander@1269
   748
{
dvander@1269
   749
	char *ph_addr;
dvander@1269
   750
	int err;
dvander@1269
   751
	unsigned int len, numcells = ((len=strlen(string)) + sizeof(cell_t)) / sizeof(cell_t);
dvander@1269
   752
dvander@1269
   753
	if ((err = HeapAlloc(numcells, local_addr, (cell_t **)&ph_addr)) != SP_ERROR_NONE)
dvander@1269
   754
	{
dvander@1269
   755
		return err;
dvander@1269
   756
	}
dvander@1269
   757
dvander@1269
   758
	memcpy(ph_addr, string, len);
dvander@1269
   759
	ph_addr[len] = '\0';
dvander@1269
   760
dvander@1269
   761
	if ((err = PushCell(*local_addr)) != SP_ERROR_NONE)
dvander@1269
   762
	{
dvander@1269
   763
		HeapRelease(*local_addr);
dvander@1269
   764
		return err;
dvander@1269
   765
	}
dvander@1269
   766
dvander@1269
   767
	if (phys_addr)
dvander@1269
   768
	{
dvander@1269
   769
		*phys_addr = ph_addr;
dvander@1269
   770
	}
dvander@1269
   771
dvander@1269
   772
	return SP_ERROR_NONE;
dvander@1269
   773
}
dvander@1269
   774
dvander@1269
   775
int BaseContext::StringToLocal(cell_t local_addr, size_t bytes, const char *source)
dvander@1269
   776
{
dvander@1269
   777
	char *dest;
dvander@1269
   778
	size_t len;
dvander@1269
   779
dvander@1269
   780
	if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size))
dvander@1269
   781
	{
dvander@1269
   782
		return SP_ERROR_INVALID_ADDRESS;
dvander@1269
   783
	}
dvander@1269
   784
dvander@1269
   785
	if (bytes == 0)
dvander@1269
   786
	{
dvander@1269
   787
		return SP_ERROR_NONE;
dvander@1269
   788
	}
dvander@1269
   789
dvander@1269
   790
	len = strlen(source);
dvander@1269
   791
	dest = (char *)(ctx->memory + local_addr);
dvander@1269
   792
dvander@1269
   793
	if (len >= bytes)
dvander@1269
   794
	{
dvander@1269
   795
		len = bytes - 1;
dvander@1269
   796
	}
dvander@1269
   797
dvander@1269
   798
	memcpy(dest, source, len);
dvander@1269
   799
	dest[len] = '\0';
dvander@1269
   800
dvander@1269
   801
	return SP_ERROR_NONE;
dvander@1269
   802
}
dvander@1269
   803
dvander@1269
   804
inline int __CheckValidChar(char *c)
dvander@1269
   805
{
dvander@1269
   806
	int count;
dvander@1269
   807
	int bytecount = 0;
dvander@1269
   808
dvander@1269
   809
	for (count=1; (*c & 0xC0) == 0x80; count++)
dvander@1269
   810
	{
dvander@1269
   811
		c--;
dvander@1269
   812
	}
dvander@1269
   813
dvander@1269
   814
	switch (*c & 0xF0)
dvander@1269
   815
	{
dvander@1269
   816
	case 0xC0:
dvander@1269
   817
	case 0xD0:
dvander@1269
   818
		{
dvander@1269
   819
			bytecount = 2;
dvander@1269
   820
			break;
dvander@1269
   821
		}
dvander@1269
   822
	case 0xE0:
dvander@1269
   823
		{
dvander@1269
   824
			bytecount = 3;
dvander@1269
   825
			break;
dvander@1269
   826
		}
dvander@1269
   827
	case 0xF0:
dvander@1269
   828
		{
dvander@1269
   829
			bytecount = 4;
dvander@1269
   830
			break;
dvander@1269
   831
		}
dvander@1269
   832
	}
dvander@1269
   833
dvander@1269
   834
	if (bytecount != count)
dvander@1269
   835
	{
dvander@1269
   836
		return count;
dvander@1269
   837
	}
dvander@1269
   838
dvander@1269
   839
	return 0;
dvander@1269
   840
}
dvander@1269
   841
dvander@1269
   842
int BaseContext::StringToLocalUTF8(cell_t local_addr, size_t maxbytes, const char *source, size_t *wrtnbytes)
dvander@1269
   843
{
dvander@1269
   844
	char *dest;
dvander@1269
   845
	size_t len;
dvander@1269
   846
	bool needtocheck = false;
dvander@1269
   847
dvander@1269
   848
	if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size))
dvander@1269
   849
	{
dvander@1269
   850
		return SP_ERROR_INVALID_ADDRESS;
dvander@1269
   851
	}
dvander@1269
   852
	
dvander@1269
   853
	if (maxbytes == 0)
dvander@1269
   854
	{
dvander@1269
   855
		return SP_ERROR_NONE;
dvander@1269
   856
	}
dvander@1269
   857
dvander@1269
   858
	len = strlen(source);
dvander@1269
   859
	dest = (char *)(ctx->memory + local_addr);
dvander@1269
   860
dvander@1269
   861
	if ((size_t)len >= maxbytes)
dvander@1269
   862
	{
dvander@1269
   863
		len = maxbytes - 1;
dvander@1269
   864
		needtocheck = true;
dvander@1269
   865
	}
dvander@1269
   866
dvander@1269
   867
	memcpy(dest, source, len);
dvander@1269
   868
	if ((dest[len-1] & 1<<7) && needtocheck)
dvander@1269
   869
	{
dvander@1269
   870
		len -= __CheckValidChar(dest+len-1);
dvander@1269
   871
	}
dvander@1269
   872
	dest[len] = '\0';
dvander@1269
   873
dvander@1269
   874
	if (wrtnbytes)
dvander@1269
   875
	{
dvander@1269
   876
		*wrtnbytes = len;
dvander@1269
   877
	}
dvander@1269
   878
dvander@1269
   879
	return SP_ERROR_NONE;
dvander@1269
   880
}
dvander@1269
   881
dvander@1269
   882
#define USHR(x) ((unsigned int)(x)>>1)
dvander@1269
   883
dvander@1269
   884
int BaseContext::LookupFile(ucell_t addr, const char **filename)
dvander@1269
   885
{
dvander@1269
   886
	int high, low, mid;
dvander@1269
   887
dvander@1269
   888
	high = ctx->plugin->debug.files_num;
dvander@1269
   889
	low = -1;
dvander@1269
   890
dvander@1269
   891
	while (high - low > 1)
dvander@1269
   892
	{
dvander@1269
   893
		mid = USHR(low + high);
dvander@1269
   894
		if (ctx->files[mid].addr <= addr)
dvander@1269
   895
		{
dvander@1269
   896
			low = mid;
dvander@1269
   897
		} else {
dvander@1269
   898
			high = mid;
dvander@1269
   899
		}
dvander@1269
   900
	}
dvander@1269
   901
dvander@1269
   902
	if (low == -1)
dvander@1269
   903
	{
dvander@1269
   904
		return SP_ERROR_NOT_FOUND;
dvander@1269
   905
	}
dvander@1269
   906
dvander@1269
   907
	*filename = ctx->files[low].name;
dvander@1269
   908
dvander@1269
   909
	return SP_ERROR_NONE;
dvander@1269
   910
}
dvander@1269
   911
dvander@1269
   912
int BaseContext::LookupFunction(ucell_t addr, const char **name)
dvander@1269
   913
{
dvander@1269
   914
	uint32_t iter, max = ctx->plugin->debug.syms_num;
dvander@1269
   915
dvander@1269
   916
	for (iter=0; iter<max; iter++)
dvander@1269
   917
	{
dvander@1269
   918
		if ((ctx->symbols[iter].sym->ident == SP_SYM_FUNCTION) 
dvander@1269
   919
			&& (ctx->symbols[iter].codestart <= addr) 
dvander@1269
   920
			&& (ctx->symbols[iter].codeend > addr))
dvander@1269
   921
		{
dvander@1269
   922
			break;
dvander@1269
   923
		}
dvander@1269
   924
	}
dvander@1269
   925
dvander@1269
   926
	if (iter >= max)
dvander@1269
   927
	{
dvander@1269
   928
		return SP_ERROR_NOT_FOUND;
dvander@1269
   929
	}
dvander@1269
   930
dvander@1269
   931
	*name = ctx->symbols[iter].name;
dvander@1269
   932
dvander@1269
   933
	return SP_ERROR_NONE;
dvander@1269
   934
}
dvander@1269
   935
dvander@1269
   936
int BaseContext::LookupLine(ucell_t addr, uint32_t *line)
dvander@1269
   937
{
dvander@1269
   938
	int high, low, mid;
dvander@1269
   939
dvander@1269
   940
	high = ctx->plugin->debug.lines_num;
dvander@1269
   941
	low = -1;
dvander@1269
   942
dvander@1269
   943
	while (high - low > 1)
dvander@1269
   944
	{
dvander@1269
   945
		mid = USHR(low + high);
dvander@1269
   946
		if (ctx->lines[mid].addr <= addr)
dvander@1269
   947
		{
dvander@1269
   948
			low = mid;
dvander@1269
   949
		} else {
dvander@1269
   950
			high = mid;
dvander@1269
   951
		}
dvander@1269
   952
	}
dvander@1269
   953
dvander@1269
   954
	if (low == -1)
dvander@1269
   955
	{
dvander@1269
   956
		return SP_ERROR_NOT_FOUND;
dvander@1269
   957
	}
dvander@1269
   958
dvander@1269
   959
	/* Since the CIP occurs BEFORE the line, we have to add one */
dvander@1269
   960
	*line = ctx->lines[low].line + 1;
dvander@1269
   961
dvander@1269
   962
	return SP_ERROR_NONE;
dvander@1269
   963
}
dvander@1269
   964
dvander@1269
   965
IPluginFunction *BaseContext::GetFunctionById(funcid_t func_id)
dvander@1269
   966
{
dvander@1269
   967
	CFunction *pFunc = NULL;
dvander@1269
   968
dvander@1269
   969
	if (func_id & 1)
dvander@1269
   970
	{
dvander@1269
   971
		func_id >>= 1;
dvander@1269
   972
		if (func_id >= ctx->plugin->info.publics_num)
dvander@1269
   973
		{
dvander@1269
   974
			return NULL;
dvander@1269
   975
		}
dvander@1269
   976
		pFunc = m_pub_funcs[func_id];
dvander@1269
   977
		if (!pFunc)
dvander@1269
   978
		{
dvander@1339
   979
			m_pub_funcs[func_id] = new CFunction(ctx->publics[func_id].code_offs, this, ctx->publics[func_id].funcid);
dvander@1269
   980
			pFunc = m_pub_funcs[func_id];
dvander@1269
   981
		} else if (pFunc->IsInvalidated()) {
dvander@1339
   982
			pFunc->Set(ctx->publics[func_id].code_offs, this, ctx->publics[func_id].funcid);
dvander@1269
   983
		}
dvander@1269
   984
	} else {
dvander@1269
   985
		/* :TODO: currently not used */
dvander@1269
   986
#if 0
dvander@1269
   987
		func_id >>= 1;
dvander@1269
   988
		unsigned int index;
dvander@1269
   989
		if (!g_pVM->FunctionLookup(ctx, func_id, &index))
dvander@1269
   990
		{
dvander@1269
   991
			return NULL;
dvander@1269
   992
		}
dvander@1269
   993
		pFunc = m_priv_funcs[func_id];
dvander@1269
   994
		if (!pFunc)
dvander@1269
   995
		{
dvander@1269
   996
			m_priv_funcs[func_id] = new CFunction(save, this);
dvander@1269
   997
			pFunc = m_priv_funcs[func_id];
dvander@1269
   998
		}
dvander@1269
   999
#endif
dvander@1269
  1000
	}
dvander@1269
  1001
dvander@1269
  1002
	return pFunc;
dvander@1269
  1003
}
dvander@1269
  1004
dvander@1269
  1005
IPluginFunction *BaseContext::GetFunctionByName(const char *public_name)
dvander@1269
  1006
{
dvander@1269
  1007
	uint32_t index;
dvander@1269
  1008
dvander@1269
  1009
	if (FindPublicByName(public_name, &index) != SP_ERROR_NONE)
dvander@1269
  1010
	{
dvander@1269
  1011
		return NULL;
dvander@1269
  1012
	}
dvander@1269
  1013
dvander@1269
  1014
	CFunction *pFunc = m_pub_funcs[index];
dvander@1269
  1015
	if (!pFunc)
dvander@1269
  1016
	{
dvander@1269
  1017
		sp_public_t *pub = NULL;
dvander@1269
  1018
		GetPublicByIndex(index, &pub);
dvander@1269
  1019
		if (pub)
dvander@1269
  1020
		{
dvander@1339
  1021
			m_pub_funcs[index] = new CFunction(pub->code_offs, this, pub->funcid);
dvander@1269
  1022
		}
dvander@1269
  1023
		pFunc = m_pub_funcs[index];
dvander@1269
  1024
	} else if (pFunc->IsInvalidated()) {
dvander@1269
  1025
		sp_public_t *pub = NULL;
dvander@1269
  1026
		GetPublicByIndex(index, &pub);
dvander@1269
  1027
		if (pub)
dvander@1269
  1028
		{
dvander@1339
  1029
			pFunc->Set(pub->code_offs, this, pub->funcid);
dvander@1269
  1030
		} else {
dvander@1269
  1031
			pFunc = NULL;
dvander@1269
  1032
		}
dvander@1269
  1033
	}
dvander@1269
  1034
dvander@1269
  1035
	return pFunc;
dvander@1269
  1036
}
dvander@1269
  1037
dvander@1269
  1038
int BaseContext::LocalToStringNULL(cell_t local_addr, char **addr)
dvander@1269
  1039
{
dvander@1269
  1040
	int err;
dvander@1269
  1041
	if ((err = LocalToString(local_addr, addr)) != SP_ERROR_NONE)
dvander@1269
  1042
	{
dvander@1269
  1043
		return err;
dvander@1269
  1044
	}
dvander@1269
  1045
dvander@1269
  1046
	if ((cell_t *)*addr == m_pNullString)
dvander@1269
  1047
	{
dvander@1269
  1048
		*addr = NULL;
dvander@1269
  1049
	}
dvander@1269
  1050
dvander@1269
  1051
	return SP_ERROR_NONE;
dvander@1269
  1052
}
dvander@1269
  1053
dvander@1269
  1054
#if defined SOURCEMOD_BUILD
dvander@1269
  1055
SourceMod::IdentityToken_t *BaseContext::GetIdentity()
dvander@1269
  1056
{
dvander@1269
  1057
	return m_pToken;
dvander@1269
  1058
}
dvander@1269
  1059
dvander@1269
  1060
void BaseContext::SetIdentity(SourceMod::IdentityToken_t *token)
dvander@1269
  1061
{
dvander@1269
  1062
	m_pToken = token;
dvander@1269
  1063
}
dvander@1269
  1064
dvander@1269
  1065
cell_t *BaseContext::GetNullRef(SP_NULL_TYPE type)
dvander@1269
  1066
{
dvander@1269
  1067
	if (type == SP_NULL_VECTOR)
dvander@1269
  1068
	{
dvander@1269
  1069
		return m_pNullVec;
dvander@1269
  1070
	}
dvander@1269
  1071
dvander@1269
  1072
	return NULL;
dvander@1269
  1073
}
dvander@1269
  1074
#endif