core/vm/sp_vm_basecontext.cpp
author David Anderson <dvander@alliedmods.net>
Wed Aug 15 20:18:15 2007 +0000 (2007-08-15)
changeset 1339 02e8f2c0f8af
parent 1330 ab94316bb52b
child 1344 a450a8caa531
permissions -rw-r--r--
SourceMod will now spit out errors for scripts that become corrupt and would otherwise be crashing Core. if you get these errors contact the dev team.
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@1269
   260
	cell_t save_sp = ctx->sp;
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@1269
   288
		if ((ctx->sp - (cell_t)(pushcount * sizeof(cell_t))) != 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@1269
   316
dvander@1269
   317
	return err;
dvander@1269
   318
}
dvander@1269
   319
dvander@1269
   320
void BaseContext::SetErrorMessage(const char *msg, va_list ap)
dvander@1269
   321
{
dvander@1269
   322
	m_CustomMsg = true;
dvander@1269
   323
dvander@1269
   324
	vsnprintf(m_MsgCache, sizeof(m_MsgCache), msg, ap);
dvander@1269
   325
}
dvander@1269
   326
dvander@1269
   327
cell_t BaseContext::ThrowNativeErrorEx(int error, const char *msg, ...)
dvander@1269
   328
{
dvander@1269
   329
	if (!m_InExec)
dvander@1269
   330
	{
dvander@1269
   331
		return 0;
dvander@1269
   332
	}
dvander@1269
   333
dvander@1269
   334
	ctx->n_err = error;
dvander@1269
   335
	
dvander@1269
   336
	if (msg)
dvander@1269
   337
	{
dvander@1269
   338
		va_list ap;
dvander@1269
   339
		va_start(ap, msg);
dvander@1269
   340
		SetErrorMessage(msg, ap);
dvander@1269
   341
		va_end(ap);
dvander@1269
   342
	}
dvander@1269
   343
dvander@1269
   344
	return 0;
dvander@1269
   345
}
dvander@1269
   346
dvander@1269
   347
cell_t BaseContext::ThrowNativeError(const char *msg, ...)
dvander@1269
   348
{
dvander@1269
   349
	if (!m_InExec)
dvander@1269
   350
	{
dvander@1269
   351
		return 0;
dvander@1269
   352
	}
dvander@1269
   353
dvander@1269
   354
	ctx->n_err = SP_ERROR_NATIVE;
dvander@1269
   355
dvander@1269
   356
	if (msg)
dvander@1269
   357
	{
dvander@1269
   358
		va_list ap;
dvander@1269
   359
		va_start(ap, msg);
dvander@1269
   360
		SetErrorMessage(msg, ap);
dvander@1269
   361
		va_end(ap);
dvander@1269
   362
	}
dvander@1269
   363
dvander@1269
   364
	return 0;
dvander@1269
   365
}
dvander@1269
   366
dvander@1269
   367
int BaseContext::HeapAlloc(unsigned int cells, cell_t *local_addr, cell_t **phys_addr)
dvander@1269
   368
{
dvander@1269
   369
	cell_t *addr;
dvander@1269
   370
	ucell_t realmem;
dvander@1269
   371
dvander@1269
   372
#if 0
dvander@1269
   373
	if (cells > CELLBOUNDMAX)
dvander@1269
   374
	{
dvander@1269
   375
		return SP_ERROR_ARAM;
dvander@1269
   376
	}
dvander@1269
   377
#else
dvander@1269
   378
	assert(cells < CELLBOUNDMAX);
dvander@1269
   379
#endif
dvander@1269
   380
dvander@1269
   381
	realmem = cells * sizeof(cell_t);
dvander@1269
   382
dvander@1269
   383
	/**
dvander@1269
   384
	 * Check if the space between the heap and stack is sufficient.
dvander@1269
   385
	 */
dvander@1269
   386
	if ((cell_t)(ctx->sp - ctx->hp - realmem) < STACKMARGIN)
dvander@1269
   387
	{
dvander@1269
   388
		return SP_ERROR_HEAPLOW;
dvander@1269
   389
	}
dvander@1269
   390
dvander@1269
   391
	addr = (cell_t *)(ctx->memory + ctx->hp);
dvander@1269
   392
	/* store size of allocation in cells */
dvander@1269
   393
	*addr = (cell_t)cells;
dvander@1269
   394
	addr++;
dvander@1269
   395
	ctx->hp += sizeof(cell_t);
dvander@1269
   396
dvander@1269
   397
	*local_addr = ctx->hp;
dvander@1269
   398
dvander@1269
   399
	if (phys_addr)
dvander@1269
   400
	{
dvander@1269
   401
		*phys_addr = addr;
dvander@1269
   402
	}
dvander@1269
   403
dvander@1269
   404
	ctx->hp += realmem;
dvander@1269
   405
dvander@1269
   406
	return SP_ERROR_NONE;
dvander@1269
   407
}
dvander@1269
   408
dvander@1269
   409
int BaseContext::HeapPop(cell_t local_addr)
dvander@1269
   410
{
dvander@1269
   411
	cell_t cellcount;
dvander@1269
   412
	cell_t *addr;
dvander@1269
   413
dvander@1269
   414
	/* check the bounds of this address */
dvander@1269
   415
	local_addr -= sizeof(cell_t);
dvander@1269
   416
	if (local_addr < ctx->heap_base || local_addr >= ctx->sp)
dvander@1269
   417
	{
dvander@1269
   418
		return SP_ERROR_INVALID_ADDRESS;
dvander@1269
   419
	}
dvander@1269
   420
dvander@1269
   421
	addr = (cell_t *)(ctx->memory + local_addr);
dvander@1269
   422
	cellcount = (*addr) * sizeof(cell_t);
dvander@1269
   423
	/* check if this memory count looks valid */
dvander@1269
   424
	if ((signed)(ctx->hp - cellcount - sizeof(cell_t)) != local_addr)
dvander@1269
   425
	{
dvander@1269
   426
		return SP_ERROR_INVALID_ADDRESS;
dvander@1269
   427
	}
dvander@1269
   428
dvander@1269
   429
	ctx->hp = local_addr;
dvander@1269
   430
dvander@1269
   431
	return SP_ERROR_NONE;
dvander@1269
   432
}
dvander@1269
   433
dvander@1269
   434
dvander@1269
   435
int BaseContext::HeapRelease(cell_t local_addr)
dvander@1269
   436
{
dvander@1269
   437
	if (local_addr < ctx->heap_base)
dvander@1269
   438
	{
dvander@1269
   439
		return SP_ERROR_INVALID_ADDRESS;
dvander@1269
   440
	}
dvander@1269
   441
dvander@1269
   442
	ctx->hp = local_addr - sizeof(cell_t);
dvander@1269
   443
dvander@1269
   444
	return SP_ERROR_NONE;
dvander@1269
   445
}
dvander@1269
   446
dvander@1269
   447
int BaseContext::FindNativeByName(const char *name, uint32_t *index)
dvander@1269
   448
{
dvander@1269
   449
	int high;
dvander@1269
   450
dvander@1269
   451
	high = ctx->plugin->info.natives_num - 1;
dvander@1269
   452
dvander@1269
   453
	for (uint32_t i=0; i<ctx->plugin->info.natives_num; i++)
dvander@1269
   454
	{
dvander@1269
   455
		if (strcmp(ctx->natives[i].name, name) == 0)
dvander@1269
   456
		{
dvander@1269
   457
			if (index)
dvander@1269
   458
			{
dvander@1269
   459
				*index = i;
dvander@1269
   460
			}
dvander@1269
   461
			return SP_ERROR_NONE;
dvander@1269
   462
		}
dvander@1269
   463
	}
dvander@1269
   464
dvander@1269
   465
	return SP_ERROR_NOT_FOUND;
dvander@1269
   466
}
dvander@1269
   467
dvander@1269
   468
int BaseContext::GetNativeByIndex(uint32_t index, sp_native_t **native)
dvander@1269
   469
{
dvander@1269
   470
	if (index >= ctx->plugin->info.natives_num)
dvander@1269
   471
	{
dvander@1269
   472
		return SP_ERROR_INDEX;
dvander@1269
   473
	}
dvander@1269
   474
dvander@1269
   475
	if (native)
dvander@1269
   476
	{
dvander@1269
   477
		*native = &(ctx->natives[index]);
dvander@1269
   478
	}
dvander@1269
   479
dvander@1269
   480
	return SP_ERROR_NONE;
dvander@1269
   481
}
dvander@1269
   482
dvander@1269
   483
dvander@1269
   484
uint32_t BaseContext::GetNativesNum()
dvander@1269
   485
{
dvander@1269
   486
	return ctx->plugin->info.natives_num;
dvander@1269
   487
}
dvander@1269
   488
dvander@1269
   489
int BaseContext::FindPublicByName(const char *name, uint32_t *index)
dvander@1269
   490
{
dvander@1269
   491
	int diff, high, low;
dvander@1269
   492
	uint32_t mid;
dvander@1269
   493
dvander@1269
   494
	high = ctx->plugin->info.publics_num - 1;
dvander@1269
   495
	low = 0;
dvander@1269
   496
dvander@1269
   497
	while (low <= high)
dvander@1269
   498
	{
dvander@1269
   499
		mid = (low + high) / 2;
dvander@1269
   500
		diff = strcmp(ctx->publics[mid].name, name);
dvander@1269
   501
		if (diff == 0)
dvander@1269
   502
		{
dvander@1269
   503
			if (index)
dvander@1269
   504
			{
dvander@1269
   505
				*index = mid;
dvander@1269
   506
			}
dvander@1269
   507
			return SP_ERROR_NONE;
dvander@1269
   508
		} else if (diff < 0) {
dvander@1269
   509
			low = mid + 1;
dvander@1269
   510
		} else {
dvander@1269
   511
			high = mid - 1;
dvander@1269
   512
		}
dvander@1269
   513
	}
dvander@1269
   514
dvander@1269
   515
	return SP_ERROR_NOT_FOUND;
dvander@1269
   516
}
dvander@1269
   517
dvander@1269
   518
int BaseContext::GetPublicByIndex(uint32_t index, sp_public_t **pblic)
dvander@1269
   519
{
dvander@1269
   520
	if (index >= ctx->plugin->info.publics_num)
dvander@1269
   521
	{
dvander@1269
   522
		return SP_ERROR_INDEX;
dvander@1269
   523
	}
dvander@1269
   524
dvander@1269
   525
	if (pblic)
dvander@1269
   526
	{
dvander@1269
   527
		*pblic = &(ctx->publics[index]);
dvander@1269
   528
	}
dvander@1269
   529
dvander@1269
   530
	return SP_ERROR_NONE;
dvander@1269
   531
}
dvander@1269
   532
dvander@1269
   533
uint32_t BaseContext::GetPublicsNum()
dvander@1269
   534
{
dvander@1269
   535
	return ctx->plugin->info.publics_num;
dvander@1269
   536
}
dvander@1269
   537
dvander@1269
   538
int BaseContext::GetPubvarByIndex(uint32_t index, sp_pubvar_t **pubvar)
dvander@1269
   539
{
dvander@1269
   540
	if (index >= ctx->plugin->info.pubvars_num)
dvander@1269
   541
	{
dvander@1269
   542
		return SP_ERROR_INDEX;
dvander@1269
   543
	}
dvander@1269
   544
dvander@1269
   545
	if (pubvar)
dvander@1269
   546
	{
dvander@1269
   547
		*pubvar = &(ctx->pubvars[index]);
dvander@1269
   548
	}
dvander@1269
   549
dvander@1269
   550
	return SP_ERROR_NONE;
dvander@1269
   551
}
dvander@1269
   552
dvander@1269
   553
int BaseContext::FindPubvarByName(const char *name, uint32_t *index)
dvander@1269
   554
{
dvander@1269
   555
	int diff, high, low;
dvander@1269
   556
	uint32_t mid;
dvander@1269
   557
dvander@1269
   558
	high = ctx->plugin->info.pubvars_num - 1;
dvander@1269
   559
	low = 0;
dvander@1269
   560
dvander@1269
   561
	while (low <= high)
dvander@1269
   562
	{
dvander@1269
   563
		mid = (low + high) / 2;
dvander@1269
   564
		diff = strcmp(ctx->pubvars[mid].name, name);
dvander@1269
   565
		if (diff == 0)
dvander@1269
   566
		{
dvander@1269
   567
			if (index)
dvander@1269
   568
			{
dvander@1269
   569
				*index = mid;
dvander@1269
   570
			}
dvander@1269
   571
			return SP_ERROR_NONE;
dvander@1269
   572
		} else if (diff < 0) {
dvander@1269
   573
			low = mid + 1;
dvander@1269
   574
		} else {
dvander@1269
   575
			high = mid - 1;
dvander@1269
   576
		}
dvander@1269
   577
	}
dvander@1269
   578
dvander@1269
   579
	return SP_ERROR_NOT_FOUND;
dvander@1269
   580
}
dvander@1269
   581
dvander@1269
   582
int BaseContext::GetPubvarAddrs(uint32_t index, cell_t *local_addr, cell_t **phys_addr)
dvander@1269
   583
{
dvander@1269
   584
	if (index >= ctx->plugin->info.pubvars_num)
dvander@1269
   585
	{
dvander@1269
   586
		return SP_ERROR_INDEX;
dvander@1269
   587
	}
dvander@1269
   588
dvander@1269
   589
	*local_addr = ctx->plugin->info.pubvars[index].address;
dvander@1269
   590
	*phys_addr = ctx->pubvars[index].offs;
dvander@1269
   591
dvander@1269
   592
	return SP_ERROR_NONE;
dvander@1269
   593
}
dvander@1269
   594
dvander@1269
   595
uint32_t BaseContext::GetPubVarsNum()
dvander@1269
   596
{
dvander@1269
   597
	return ctx->plugin->info.pubvars_num;
dvander@1269
   598
}
dvander@1269
   599
dvander@1269
   600
int BaseContext::BindNatives(const sp_nativeinfo_t *natives, unsigned int num, int overwrite)
dvander@1269
   601
{
dvander@1269
   602
	uint32_t i, j, max;
dvander@1269
   603
dvander@1269
   604
	max = ctx->plugin->info.natives_num;
dvander@1269
   605
dvander@1269
   606
	for (i=0; i<max; i++)
dvander@1269
   607
	{
dvander@1269
   608
		if ((ctx->natives[i].status == SP_NATIVE_BOUND) && !overwrite)
dvander@1269
   609
		{
dvander@1269
   610
			continue;
dvander@1269
   611
		}
dvander@1269
   612
dvander@1269
   613
		for (j=0; (natives[j].name) && (!num || j<num); j++)
dvander@1269
   614
		{
dvander@1269
   615
			if (!strcmp(ctx->natives[i].name, natives[j].name))
dvander@1269
   616
			{
dvander@1269
   617
				ctx->natives[i].pfn = natives[j].func;
dvander@1269
   618
				ctx->natives[i].status = SP_NATIVE_BOUND;
dvander@1269
   619
			}
dvander@1269
   620
		}
dvander@1269
   621
	}
dvander@1269
   622
dvander@1269
   623
	return SP_ERROR_NONE;
dvander@1269
   624
}
dvander@1269
   625
dvander@1269
   626
int BaseContext::BindNative(const sp_nativeinfo_t *native)
dvander@1269
   627
{
dvander@1269
   628
	uint32_t index;
dvander@1269
   629
	int err;
dvander@1269
   630
dvander@1269
   631
	if ((err = FindNativeByName(native->name, &index)) != SP_ERROR_NONE)
dvander@1269
   632
	{
dvander@1269
   633
		return err;
dvander@1269
   634
	}
dvander@1269
   635
dvander@1269
   636
	ctx->natives[index].pfn = native->func;
dvander@1269
   637
	ctx->natives[index].status = SP_NATIVE_BOUND;
dvander@1269
   638
dvander@1269
   639
	return SP_ERROR_NONE;
dvander@1269
   640
}
dvander@1269
   641
dvander@1269
   642
int BaseContext::BindNativeToAny(SPVM_NATIVE_FUNC native)
dvander@1269
   643
{
dvander@1269
   644
	uint32_t nativesnum, i;
dvander@1269
   645
dvander@1269
   646
	nativesnum = ctx->plugin->info.natives_num;
dvander@1269
   647
dvander@1269
   648
	for (i=0; i<nativesnum; i++)
dvander@1269
   649
	{
dvander@1269
   650
		if (ctx->natives[i].status == SP_NATIVE_UNBOUND)
dvander@1269
   651
		{
dvander@1269
   652
			ctx->natives[i].pfn = native;
dvander@1269
   653
			ctx->natives[i].status = SP_NATIVE_BOUND;
dvander@1269
   654
		}
dvander@1269
   655
	}
dvander@1269
   656
dvander@1269
   657
	return SP_ERROR_NONE;
dvander@1269
   658
}
dvander@1269
   659
dvander@1269
   660
int BaseContext::LocalToPhysAddr(cell_t local_addr, cell_t **phys_addr)
dvander@1269
   661
{
dvander@1269
   662
	if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size))
dvander@1269
   663
	{
dvander@1269
   664
		return SP_ERROR_INVALID_ADDRESS;
dvander@1269
   665
	}
dvander@1269
   666
dvander@1269
   667
	if (phys_addr)
dvander@1269
   668
	{
dvander@1269
   669
		*phys_addr = (cell_t *)(ctx->memory + local_addr);
dvander@1269
   670
	}
dvander@1269
   671
dvander@1269
   672
	return SP_ERROR_NONE;
dvander@1269
   673
}
dvander@1269
   674
dvander@1269
   675
int BaseContext::PushCell(cell_t value)
dvander@1269
   676
{
dvander@1269
   677
	if ((ctx->hp + STACKMARGIN) > (cell_t)(ctx->sp - sizeof(cell_t)))
dvander@1269
   678
	{
dvander@1269
   679
		return SP_ERROR_STACKLOW;
dvander@1269
   680
	}
dvander@1269
   681
dvander@1269
   682
	ctx->sp -= sizeof(cell_t);
dvander@1269
   683
	*(cell_t *)(ctx->memory + ctx->sp) = value;
dvander@1269
   684
	ctx->pushcount++;
dvander@1269
   685
dvander@1269
   686
	return SP_ERROR_NONE;
dvander@1269
   687
}
dvander@1269
   688
dvander@1269
   689
int BaseContext::PushCellsFromArray(cell_t array[], unsigned int numcells)
dvander@1269
   690
{
dvander@1269
   691
	unsigned int i;
dvander@1269
   692
	int err;
dvander@1269
   693
dvander@1269
   694
	for (i=0; i<numcells; i++)
dvander@1269
   695
	{
dvander@1269
   696
		if ((err = PushCell(array[i])) != SP_ERROR_NONE)
dvander@1269
   697
		{
dvander@1269
   698
			ctx->sp += (cell_t)(i * sizeof(cell_t));
dvander@1269
   699
			ctx->pushcount -= i;
dvander@1269
   700
			return err;
dvander@1269
   701
		}
dvander@1269
   702
	}
dvander@1269
   703
dvander@1269
   704
	return SP_ERROR_NONE;
dvander@1269
   705
}
dvander@1269
   706
dvander@1269
   707
int BaseContext::PushCellArray(cell_t *local_addr, cell_t **phys_addr, cell_t array[], unsigned int numcells)
dvander@1269
   708
{
dvander@1269
   709
	cell_t *ph_addr;
dvander@1269
   710
	int err;
dvander@1269
   711
dvander@1269
   712
	if ((err = HeapAlloc(numcells, local_addr, &ph_addr)) != SP_ERROR_NONE)
dvander@1269
   713
	{
dvander@1269
   714
		return err;
dvander@1269
   715
	}
dvander@1269
   716
dvander@1269
   717
	memcpy(ph_addr, array, numcells * sizeof(cell_t));
dvander@1269
   718
dvander@1269
   719
	if ((err = PushCell(*local_addr)) != SP_ERROR_NONE)
dvander@1269
   720
	{
dvander@1269
   721
		HeapRelease(*local_addr);
dvander@1269
   722
		return err;
dvander@1269
   723
	}
dvander@1269
   724
dvander@1269
   725
	if (phys_addr)
dvander@1269
   726
	{
dvander@1269
   727
		*phys_addr = ph_addr;
dvander@1269
   728
	}
dvander@1269
   729
dvander@1269
   730
	return SP_ERROR_NONE;
dvander@1269
   731
}
dvander@1269
   732
dvander@1269
   733
int BaseContext::LocalToString(cell_t local_addr, char **addr)
dvander@1269
   734
{
dvander@1269
   735
	if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size))
dvander@1269
   736
	{
dvander@1269
   737
		return SP_ERROR_INVALID_ADDRESS;
dvander@1269
   738
	}
dvander@1269
   739
	*addr = (char *)(ctx->memory + local_addr);
dvander@1269
   740
dvander@1269
   741
	return SP_ERROR_NONE;
dvander@1269
   742
}
dvander@1269
   743
dvander@1269
   744
int BaseContext::PushString(cell_t *local_addr, char **phys_addr, const char *string)
dvander@1269
   745
{
dvander@1269
   746
	char *ph_addr;
dvander@1269
   747
	int err;
dvander@1269
   748
	unsigned int len, numcells = ((len=strlen(string)) + sizeof(cell_t)) / sizeof(cell_t);
dvander@1269
   749
dvander@1269
   750
	if ((err = HeapAlloc(numcells, local_addr, (cell_t **)&ph_addr)) != SP_ERROR_NONE)
dvander@1269
   751
	{
dvander@1269
   752
		return err;
dvander@1269
   753
	}
dvander@1269
   754
dvander@1269
   755
	memcpy(ph_addr, string, len);
dvander@1269
   756
	ph_addr[len] = '\0';
dvander@1269
   757
dvander@1269
   758
	if ((err = PushCell(*local_addr)) != SP_ERROR_NONE)
dvander@1269
   759
	{
dvander@1269
   760
		HeapRelease(*local_addr);
dvander@1269
   761
		return err;
dvander@1269
   762
	}
dvander@1269
   763
dvander@1269
   764
	if (phys_addr)
dvander@1269
   765
	{
dvander@1269
   766
		*phys_addr = ph_addr;
dvander@1269
   767
	}
dvander@1269
   768
dvander@1269
   769
	return SP_ERROR_NONE;
dvander@1269
   770
}
dvander@1269
   771
dvander@1269
   772
int BaseContext::StringToLocal(cell_t local_addr, size_t bytes, const char *source)
dvander@1269
   773
{
dvander@1269
   774
	char *dest;
dvander@1269
   775
	size_t len;
dvander@1269
   776
dvander@1269
   777
	if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size))
dvander@1269
   778
	{
dvander@1269
   779
		return SP_ERROR_INVALID_ADDRESS;
dvander@1269
   780
	}
dvander@1269
   781
dvander@1269
   782
	if (bytes == 0)
dvander@1269
   783
	{
dvander@1269
   784
		return SP_ERROR_NONE;
dvander@1269
   785
	}
dvander@1269
   786
dvander@1269
   787
	len = strlen(source);
dvander@1269
   788
	dest = (char *)(ctx->memory + local_addr);
dvander@1269
   789
dvander@1269
   790
	if (len >= bytes)
dvander@1269
   791
	{
dvander@1269
   792
		len = bytes - 1;
dvander@1269
   793
	}
dvander@1269
   794
dvander@1269
   795
	memcpy(dest, source, len);
dvander@1269
   796
	dest[len] = '\0';
dvander@1269
   797
dvander@1269
   798
	return SP_ERROR_NONE;
dvander@1269
   799
}
dvander@1269
   800
dvander@1269
   801
inline int __CheckValidChar(char *c)
dvander@1269
   802
{
dvander@1269
   803
	int count;
dvander@1269
   804
	int bytecount = 0;
dvander@1269
   805
dvander@1269
   806
	for (count=1; (*c & 0xC0) == 0x80; count++)
dvander@1269
   807
	{
dvander@1269
   808
		c--;
dvander@1269
   809
	}
dvander@1269
   810
dvander@1269
   811
	switch (*c & 0xF0)
dvander@1269
   812
	{
dvander@1269
   813
	case 0xC0:
dvander@1269
   814
	case 0xD0:
dvander@1269
   815
		{
dvander@1269
   816
			bytecount = 2;
dvander@1269
   817
			break;
dvander@1269
   818
		}
dvander@1269
   819
	case 0xE0:
dvander@1269
   820
		{
dvander@1269
   821
			bytecount = 3;
dvander@1269
   822
			break;
dvander@1269
   823
		}
dvander@1269
   824
	case 0xF0:
dvander@1269
   825
		{
dvander@1269
   826
			bytecount = 4;
dvander@1269
   827
			break;
dvander@1269
   828
		}
dvander@1269
   829
	}
dvander@1269
   830
dvander@1269
   831
	if (bytecount != count)
dvander@1269
   832
	{
dvander@1269
   833
		return count;
dvander@1269
   834
	}
dvander@1269
   835
dvander@1269
   836
	return 0;
dvander@1269
   837
}
dvander@1269
   838
dvander@1269
   839
int BaseContext::StringToLocalUTF8(cell_t local_addr, size_t maxbytes, const char *source, size_t *wrtnbytes)
dvander@1269
   840
{
dvander@1269
   841
	char *dest;
dvander@1269
   842
	size_t len;
dvander@1269
   843
	bool needtocheck = false;
dvander@1269
   844
dvander@1269
   845
	if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size))
dvander@1269
   846
	{
dvander@1269
   847
		return SP_ERROR_INVALID_ADDRESS;
dvander@1269
   848
	}
dvander@1269
   849
	
dvander@1269
   850
	if (maxbytes == 0)
dvander@1269
   851
	{
dvander@1269
   852
		return SP_ERROR_NONE;
dvander@1269
   853
	}
dvander@1269
   854
dvander@1269
   855
	len = strlen(source);
dvander@1269
   856
	dest = (char *)(ctx->memory + local_addr);
dvander@1269
   857
dvander@1269
   858
	if ((size_t)len >= maxbytes)
dvander@1269
   859
	{
dvander@1269
   860
		len = maxbytes - 1;
dvander@1269
   861
		needtocheck = true;
dvander@1269
   862
	}
dvander@1269
   863
dvander@1269
   864
	memcpy(dest, source, len);
dvander@1269
   865
	if ((dest[len-1] & 1<<7) && needtocheck)
dvander@1269
   866
	{
dvander@1269
   867
		len -= __CheckValidChar(dest+len-1);
dvander@1269
   868
	}
dvander@1269
   869
	dest[len] = '\0';
dvander@1269
   870
dvander@1269
   871
	if (wrtnbytes)
dvander@1269
   872
	{
dvander@1269
   873
		*wrtnbytes = len;
dvander@1269
   874
	}
dvander@1269
   875
dvander@1269
   876
	return SP_ERROR_NONE;
dvander@1269
   877
}
dvander@1269
   878
dvander@1269
   879
#define USHR(x) ((unsigned int)(x)>>1)
dvander@1269
   880
dvander@1269
   881
int BaseContext::LookupFile(ucell_t addr, const char **filename)
dvander@1269
   882
{
dvander@1269
   883
	int high, low, mid;
dvander@1269
   884
dvander@1269
   885
	high = ctx->plugin->debug.files_num;
dvander@1269
   886
	low = -1;
dvander@1269
   887
dvander@1269
   888
	while (high - low > 1)
dvander@1269
   889
	{
dvander@1269
   890
		mid = USHR(low + high);
dvander@1269
   891
		if (ctx->files[mid].addr <= addr)
dvander@1269
   892
		{
dvander@1269
   893
			low = mid;
dvander@1269
   894
		} else {
dvander@1269
   895
			high = mid;
dvander@1269
   896
		}
dvander@1269
   897
	}
dvander@1269
   898
dvander@1269
   899
	if (low == -1)
dvander@1269
   900
	{
dvander@1269
   901
		return SP_ERROR_NOT_FOUND;
dvander@1269
   902
	}
dvander@1269
   903
dvander@1269
   904
	*filename = ctx->files[low].name;
dvander@1269
   905
dvander@1269
   906
	return SP_ERROR_NONE;
dvander@1269
   907
}
dvander@1269
   908
dvander@1269
   909
int BaseContext::LookupFunction(ucell_t addr, const char **name)
dvander@1269
   910
{
dvander@1269
   911
	uint32_t iter, max = ctx->plugin->debug.syms_num;
dvander@1269
   912
dvander@1269
   913
	for (iter=0; iter<max; iter++)
dvander@1269
   914
	{
dvander@1269
   915
		if ((ctx->symbols[iter].sym->ident == SP_SYM_FUNCTION) 
dvander@1269
   916
			&& (ctx->symbols[iter].codestart <= addr) 
dvander@1269
   917
			&& (ctx->symbols[iter].codeend > addr))
dvander@1269
   918
		{
dvander@1269
   919
			break;
dvander@1269
   920
		}
dvander@1269
   921
	}
dvander@1269
   922
dvander@1269
   923
	if (iter >= max)
dvander@1269
   924
	{
dvander@1269
   925
		return SP_ERROR_NOT_FOUND;
dvander@1269
   926
	}
dvander@1269
   927
dvander@1269
   928
	*name = ctx->symbols[iter].name;
dvander@1269
   929
dvander@1269
   930
	return SP_ERROR_NONE;
dvander@1269
   931
}
dvander@1269
   932
dvander@1269
   933
int BaseContext::LookupLine(ucell_t addr, uint32_t *line)
dvander@1269
   934
{
dvander@1269
   935
	int high, low, mid;
dvander@1269
   936
dvander@1269
   937
	high = ctx->plugin->debug.lines_num;
dvander@1269
   938
	low = -1;
dvander@1269
   939
dvander@1269
   940
	while (high - low > 1)
dvander@1269
   941
	{
dvander@1269
   942
		mid = USHR(low + high);
dvander@1269
   943
		if (ctx->lines[mid].addr <= addr)
dvander@1269
   944
		{
dvander@1269
   945
			low = mid;
dvander@1269
   946
		} else {
dvander@1269
   947
			high = mid;
dvander@1269
   948
		}
dvander@1269
   949
	}
dvander@1269
   950
dvander@1269
   951
	if (low == -1)
dvander@1269
   952
	{
dvander@1269
   953
		return SP_ERROR_NOT_FOUND;
dvander@1269
   954
	}
dvander@1269
   955
dvander@1269
   956
	/* Since the CIP occurs BEFORE the line, we have to add one */
dvander@1269
   957
	*line = ctx->lines[low].line + 1;
dvander@1269
   958
dvander@1269
   959
	return SP_ERROR_NONE;
dvander@1269
   960
}
dvander@1269
   961
dvander@1269
   962
IPluginFunction *BaseContext::GetFunctionById(funcid_t func_id)
dvander@1269
   963
{
dvander@1269
   964
	CFunction *pFunc = NULL;
dvander@1269
   965
dvander@1269
   966
	if (func_id & 1)
dvander@1269
   967
	{
dvander@1269
   968
		func_id >>= 1;
dvander@1269
   969
		if (func_id >= ctx->plugin->info.publics_num)
dvander@1269
   970
		{
dvander@1269
   971
			return NULL;
dvander@1269
   972
		}
dvander@1269
   973
		pFunc = m_pub_funcs[func_id];
dvander@1269
   974
		if (!pFunc)
dvander@1269
   975
		{
dvander@1339
   976
			m_pub_funcs[func_id] = new CFunction(ctx->publics[func_id].code_offs, this, ctx->publics[func_id].funcid);
dvander@1269
   977
			pFunc = m_pub_funcs[func_id];
dvander@1269
   978
		} else if (pFunc->IsInvalidated()) {
dvander@1339
   979
			pFunc->Set(ctx->publics[func_id].code_offs, this, ctx->publics[func_id].funcid);
dvander@1269
   980
		}
dvander@1269
   981
	} else {
dvander@1269
   982
		/* :TODO: currently not used */
dvander@1269
   983
#if 0
dvander@1269
   984
		func_id >>= 1;
dvander@1269
   985
		unsigned int index;
dvander@1269
   986
		if (!g_pVM->FunctionLookup(ctx, func_id, &index))
dvander@1269
   987
		{
dvander@1269
   988
			return NULL;
dvander@1269
   989
		}
dvander@1269
   990
		pFunc = m_priv_funcs[func_id];
dvander@1269
   991
		if (!pFunc)
dvander@1269
   992
		{
dvander@1269
   993
			m_priv_funcs[func_id] = new CFunction(save, this);
dvander@1269
   994
			pFunc = m_priv_funcs[func_id];
dvander@1269
   995
		}
dvander@1269
   996
#endif
dvander@1269
   997
		assert(false);
dvander@1269
   998
	}
dvander@1269
   999
dvander@1269
  1000
	return pFunc;
dvander@1269
  1001
}
dvander@1269
  1002
dvander@1269
  1003
IPluginFunction *BaseContext::GetFunctionByName(const char *public_name)
dvander@1269
  1004
{
dvander@1269
  1005
	uint32_t index;
dvander@1269
  1006
dvander@1269
  1007
	if (FindPublicByName(public_name, &index) != SP_ERROR_NONE)
dvander@1269
  1008
	{
dvander@1269
  1009
		return NULL;
dvander@1269
  1010
	}
dvander@1269
  1011
dvander@1269
  1012
	CFunction *pFunc = m_pub_funcs[index];
dvander@1269
  1013
	if (!pFunc)
dvander@1269
  1014
	{
dvander@1269
  1015
		sp_public_t *pub = NULL;
dvander@1269
  1016
		GetPublicByIndex(index, &pub);
dvander@1269
  1017
		if (pub)
dvander@1269
  1018
		{
dvander@1339
  1019
			m_pub_funcs[index] = new CFunction(pub->code_offs, this, pub->funcid);
dvander@1269
  1020
		}
dvander@1269
  1021
		pFunc = m_pub_funcs[index];
dvander@1269
  1022
	} else if (pFunc->IsInvalidated()) {
dvander@1269
  1023
		sp_public_t *pub = NULL;
dvander@1269
  1024
		GetPublicByIndex(index, &pub);
dvander@1269
  1025
		if (pub)
dvander@1269
  1026
		{
dvander@1339
  1027
			pFunc->Set(pub->code_offs, this, pub->funcid);
dvander@1269
  1028
		} else {
dvander@1269
  1029
			pFunc = NULL;
dvander@1269
  1030
		}
dvander@1269
  1031
	}
dvander@1269
  1032
dvander@1269
  1033
	return pFunc;
dvander@1269
  1034
}
dvander@1269
  1035
dvander@1269
  1036
int BaseContext::LocalToStringNULL(cell_t local_addr, char **addr)
dvander@1269
  1037
{
dvander@1269
  1038
	int err;
dvander@1269
  1039
	if ((err = LocalToString(local_addr, addr)) != SP_ERROR_NONE)
dvander@1269
  1040
	{
dvander@1269
  1041
		return err;
dvander@1269
  1042
	}
dvander@1269
  1043
dvander@1269
  1044
	if ((cell_t *)*addr == m_pNullString)
dvander@1269
  1045
	{
dvander@1269
  1046
		*addr = NULL;
dvander@1269
  1047
	}
dvander@1269
  1048
dvander@1269
  1049
	return SP_ERROR_NONE;
dvander@1269
  1050
}
dvander@1269
  1051
dvander@1269
  1052
#if defined SOURCEMOD_BUILD
dvander@1269
  1053
SourceMod::IdentityToken_t *BaseContext::GetIdentity()
dvander@1269
  1054
{
dvander@1269
  1055
	return m_pToken;
dvander@1269
  1056
}
dvander@1269
  1057
dvander@1269
  1058
void BaseContext::SetIdentity(SourceMod::IdentityToken_t *token)
dvander@1269
  1059
{
dvander@1269
  1060
	m_pToken = token;
dvander@1269
  1061
}
dvander@1269
  1062
dvander@1269
  1063
cell_t *BaseContext::GetNullRef(SP_NULL_TYPE type)
dvander@1269
  1064
{
dvander@1269
  1065
	if (type == SP_NULL_VECTOR)
dvander@1269
  1066
	{
dvander@1269
  1067
		return m_pNullVec;
dvander@1269
  1068
	}
dvander@1269
  1069
dvander@1269
  1070
	return NULL;
dvander@1269
  1071
}
dvander@1269
  1072
#endif