core/vm/sp_vm_basecontext.cpp
author Scott Ehlert <ds@alliedmods.net>
Wed Aug 15 06:19:30 2007 +0000 (2007-08-15)
changeset 1330 ab94316bb52b
parent 1269 27397584df9c
child 1339 02e8f2c0f8af
permissions -rw-r--r--
Updated license headers on virtually all files with extremely minor changes in the name of some sort of strange consistency.
All plugin and include file headers also have been changed to say about GPL3 instead of GPL2.

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