core/systems/PluginSys.cpp
author David Anderson <dvander@alliedmods.net>
Wed Jan 17 06:48:11 2007 +0000 (2007-01-17)
changeset 305 59ef1afbe958
parent 298 07f6b2fe8468
child 309 51e67f50830e
permissions -rw-r--r--
Added plugin dependencies to extensions
dvander@173
     1
#include <stdio.h>
dvander@173
     2
#include "PluginSys.h"
dvander@229
     3
#include "ShareSys.h"
dvander@190
     4
#include "LibrarySys.h"
dvander@220
     5
#include "HandleSys.h"
dvander@197
     6
#include "sourcemm_api.h"
dvander@209
     7
#include "sourcemod.h"
dvander@203
     8
#include "CTextParsers.h"
dvander@282
     9
#include "CLogger.h"
dvander@298
    10
#include "ExtensionSys.h"
dvander@173
    11
dvander@211
    12
CPluginManager g_PluginSys;
dvander@220
    13
HandleType_t g_PluginType = 0;
dvander@229
    14
IdentityType_t g_PluginIdent = 0;
dvander@173
    15
dvander@209
    16
CPlugin::CPlugin(const char *file)
dvander@209
    17
{
dvander@209
    18
	static int MySerial = 0;
dvander@209
    19
dvander@209
    20
	m_type = PluginType_Private;
dvander@209
    21
	m_status = Plugin_Uncompiled;
dvander@209
    22
	m_serial = ++MySerial;
dvander@209
    23
	m_plugin = NULL;
dvander@209
    24
	m_funcsnum = 0;
dvander@209
    25
	m_priv_funcs = NULL;
dvander@209
    26
	m_pub_funcs = NULL;
dvander@209
    27
	m_errormsg[256] = '\0';
dvander@209
    28
	snprintf(m_filename, sizeof(m_filename), "%s", file);
dvander@229
    29
	m_handle = 0;
dvander@229
    30
	m_ident = NULL;
dvander@209
    31
}
dvander@209
    32
dvander@209
    33
CPlugin::~CPlugin()
dvander@173
    34
{
dvander@298
    35
	if (m_handle)
dvander@298
    36
	{
dvander@298
    37
		HandleSecurity sec;
dvander@298
    38
		sec.pOwner = g_PluginSys.GetIdentity();
dvander@298
    39
		sec.pIdentity = sec.pOwner;
dvander@298
    40
dvander@298
    41
		g_HandleSys.FreeHandle(m_handle, &sec);
dvander@298
    42
		g_ShareSys.DestroyIdentity(m_ident);
dvander@298
    43
	}
dvander@298
    44
dvander@209
    45
	if (m_ctx.base)
dvander@209
    46
	{
dvander@262
    47
		delete m_ctx.base;
dvander@209
    48
		m_ctx.base = NULL;
dvander@209
    49
	}
dvander@209
    50
	if (m_ctx.ctx)
dvander@209
    51
	{
dvander@209
    52
		m_ctx.vm->FreeContext(m_ctx.ctx);
dvander@209
    53
		m_ctx.ctx = NULL;
dvander@209
    54
	}
dvander@209
    55
	if (m_ctx.co)
dvander@209
    56
	{
dvander@209
    57
		m_ctx.vm->AbortCompilation(m_ctx.co);
dvander@209
    58
		m_ctx.co = NULL;
dvander@209
    59
	}
dvander@209
    60
dvander@209
    61
	if (m_pub_funcs)
dvander@209
    62
	{
dvander@209
    63
		for (uint32_t i=0; i<m_plugin->info.publics_num; i++)
dvander@209
    64
		{
dvander@211
    65
			g_PluginSys.ReleaseFunctionToPool(m_pub_funcs[i]);
dvander@209
    66
		}
dvander@209
    67
		delete [] m_pub_funcs;
dvander@209
    68
		m_pub_funcs = NULL;
dvander@209
    69
	}
dvander@209
    70
dvander@209
    71
	if (m_priv_funcs)
dvander@209
    72
	{
dvander@209
    73
		for (unsigned int i=0; i<m_funcsnum; i++)
dvander@209
    74
		{
dvander@211
    75
			g_PluginSys.ReleaseFunctionToPool(m_priv_funcs[i]);
dvander@209
    76
		}
dvander@209
    77
		delete [] m_priv_funcs;
dvander@209
    78
		m_priv_funcs = NULL;
dvander@209
    79
	}
dvander@222
    80
dvander@222
    81
	if (m_plugin)
dvander@222
    82
	{
dvander@222
    83
		g_pSourcePawn->FreeFromMemory(m_plugin);
dvander@222
    84
		m_plugin = NULL;
dvander@222
    85
	}
dvander@229
    86
}
dvander@229
    87
dvander@229
    88
void CPlugin::InitIdentity()
dvander@229
    89
{
dvander@229
    90
	if (!m_handle)
dvander@229
    91
	{
dvander@229
    92
		m_ident = g_ShareSys.CreateIdentity(g_PluginIdent);
dvander@262
    93
		m_handle = g_HandleSys.CreateHandle(g_PluginType, this, g_PluginSys.GetIdentity(), g_PluginSys.GetIdentity(), NULL);
dvander@262
    94
		m_ctx.base->SetIdentity(m_ident);
dvander@229
    95
	}
dvander@209
    96
}
dvander@209
    97
dvander@209
    98
CPlugin *CPlugin::CreatePlugin(const char *file, char *error, size_t maxlength)
dvander@209
    99
{
dvander@209
   100
	char fullpath[PLATFORM_MAX_PATH+1];
dvander@209
   101
	g_LibSys.PathFormat(fullpath, sizeof(fullpath), "%s/plugins/%s", g_SourceMod.GetSMBaseDir(), file);
dvander@209
   102
	FILE *fp = fopen(fullpath, "rb");
dvander@173
   103
dvander@298
   104
	CPlugin *pPlugin = new CPlugin(file);
dvander@298
   105
dvander@173
   106
	if (!fp)
dvander@173
   107
	{
dvander@209
   108
		if (error)
dvander@209
   109
		{
dvander@209
   110
			snprintf(error, maxlength, "Unable to open file");
dvander@209
   111
		}
dvander@298
   112
		pPlugin->m_status = Plugin_BadLoad;
dvander@298
   113
		return pPlugin;
dvander@173
   114
	}
dvander@173
   115
dvander@173
   116
	int err;
dvander@173
   117
	sp_plugin_t *pl = g_pSourcePawn->LoadFromFilePointer(fp, &err);
dvander@173
   118
	if (pl == NULL)
dvander@173
   119
	{
dvander@209
   120
		fclose(fp);
dvander@209
   121
		if (error)
dvander@209
   122
		{
dvander@209
   123
			snprintf(error, maxlength, "Error %d while parsing plugin", err);
dvander@209
   124
		}
dvander@298
   125
		pPlugin->m_status = Plugin_BadLoad;
dvander@298
   126
		return pPlugin;
dvander@173
   127
	}
dvander@173
   128
dvander@173
   129
	fclose(fp);
dvander@173
   130
dvander@209
   131
	pPlugin->m_plugin = pl;
dvander@298
   132
dvander@209
   133
	return pPlugin;
dvander@209
   134
}
dvander@209
   135
dvander@209
   136
ICompilation *CPlugin::StartMyCompile(IVirtualMachine *vm)
dvander@209
   137
{
dvander@209
   138
	if (!m_plugin)
dvander@173
   139
	{
dvander@209
   140
		return NULL;
dvander@173
   141
	}
dvander@173
   142
dvander@209
   143
	/* :NOTICE: We will eventually need to change these natives
dvander@209
   144
	 * for swapping in new contexts
dvander@209
   145
	 */
dvander@209
   146
	if (m_ctx.co || m_ctx.ctx)
dvander@173
   147
	{
dvander@173
   148
		return NULL;
dvander@173
   149
	}
dvander@173
   150
dvander@209
   151
	m_status = Plugin_Uncompiled;
dvander@173
   152
dvander@209
   153
	m_ctx.vm = vm;
dvander@209
   154
	m_ctx.co = vm->StartCompilation(m_plugin);
dvander@209
   155
dvander@209
   156
	return m_ctx.co;
dvander@209
   157
}
dvander@173
   158
dvander@209
   159
void CPlugin::CancelMyCompile()
dvander@209
   160
{
dvander@209
   161
	if (!m_ctx.co)
dvander@209
   162
	{
dvander@209
   163
		return;
dvander@209
   164
	}
dvander@176
   165
dvander@209
   166
	m_ctx.vm->AbortCompilation(m_ctx.co);
dvander@209
   167
	m_ctx.co = NULL;
dvander@209
   168
	m_ctx.vm = NULL;
dvander@209
   169
}
dvander@209
   170
dvander@209
   171
bool CPlugin::FinishMyCompile(char *error, size_t maxlength)
dvander@209
   172
{
dvander@209
   173
	if (!m_ctx.co)
dvander@176
   174
	{
dvander@209
   175
		return false;
dvander@176
   176
	}
dvander@176
   177
dvander@209
   178
	int err;
dvander@209
   179
	m_ctx.ctx = m_ctx.vm->CompileToContext(m_ctx.co, &err);
dvander@209
   180
	if (!m_ctx.ctx)
dvander@176
   181
	{
dvander@209
   182
		memset(&m_ctx, 0, sizeof(m_ctx));
dvander@298
   183
		if (error)
dvander@209
   184
		{
dvander@209
   185
			snprintf(error, maxlength, "Failed to compile (error %d)", err);
dvander@209
   186
		}
dvander@209
   187
		return false;
dvander@176
   188
	}
dvander@176
   189
dvander@262
   190
	m_ctx.base = new BaseContext(m_ctx.ctx);
dvander@209
   191
	m_ctx.ctx->user[SM_CONTEXTVAR_MYSELF] = (void *)this;
dvander@209
   192
dvander@209
   193
	m_funcsnum = m_ctx.vm->FunctionCount(m_ctx.ctx);
dvander@209
   194
dvander@209
   195
	/**
dvander@209
   196
	 * Note: Since the m_plugin member will never change,
dvander@209
   197
	 * it is safe to assume the function count will never change
dvander@209
   198
	 */
dvander@209
   199
	if (m_funcsnum && m_priv_funcs == NULL)
dvander@209
   200
	{
dvander@209
   201
		m_priv_funcs = new CFunction *[m_funcsnum];
dvander@209
   202
		memset(m_priv_funcs, 0, sizeof(CFunction *) * m_funcsnum);
dvander@209
   203
	} else {
dvander@209
   204
		m_priv_funcs = NULL;
dvander@209
   205
	}
dvander@209
   206
dvander@209
   207
	if (m_plugin->info.publics_num && m_pub_funcs == NULL)
dvander@209
   208
	{
dvander@209
   209
		m_pub_funcs = new CFunction *[m_plugin->info.publics_num];
dvander@209
   210
		memset(m_pub_funcs, 0, sizeof(CFunction *) * m_plugin->info.publics_num);
dvander@209
   211
	} else {
dvander@209
   212
		m_pub_funcs = NULL;
dvander@209
   213
	}
dvander@209
   214
dvander@211
   215
	m_status = Plugin_Created;
faluco@216
   216
	m_ctx.co = NULL;
dvander@211
   217
dvander@209
   218
	UpdateInfo();
dvander@209
   219
dvander@209
   220
	return true;
dvander@209
   221
}
dvander@209
   222
dvander@209
   223
void CPlugin::SetErrorState(PluginStatus status, const char *error_fmt, ...)
dvander@209
   224
{
dvander@209
   225
	m_status = status;
dvander@209
   226
dvander@209
   227
	va_list ap;
dvander@209
   228
	va_start(ap, error_fmt);
dvander@209
   229
	vsnprintf(m_errormsg, sizeof(m_errormsg), error_fmt, ap);
dvander@209
   230
	va_end(ap);
dvander@173
   231
}
dvander@173
   232
dvander@176
   233
IPluginFunction *CPlugin::GetFunctionById(funcid_t func_id)
dvander@176
   234
{
dvander@176
   235
	CFunction *pFunc = NULL;
dvander@176
   236
	funcid_t save = func_id;
dvander@176
   237
dvander@176
   238
	if (func_id & 1)
dvander@176
   239
	{
dvander@176
   240
		func_id >>= 1;
dvander@176
   241
		if (func_id >= m_plugin->info.publics_num)
dvander@176
   242
		{
dvander@176
   243
			return NULL;
dvander@176
   244
		}
dvander@176
   245
		pFunc = m_pub_funcs[func_id];
dvander@176
   246
		if (!pFunc)
dvander@176
   247
		{
dvander@211
   248
			pFunc = g_PluginSys.GetFunctionFromPool(save, this);
dvander@176
   249
			m_pub_funcs[func_id] = pFunc;
dvander@176
   250
		}
dvander@176
   251
	} else {
dvander@176
   252
		func_id >>= 1;
dvander@176
   253
		unsigned int index;
dvander@209
   254
		if (!g_pVM->FunctionLookup(m_ctx.ctx, func_id, &index))
dvander@176
   255
		{
dvander@176
   256
			return NULL;
dvander@176
   257
		}
dvander@176
   258
		pFunc = m_priv_funcs[func_id];
dvander@176
   259
		if (!pFunc)
dvander@176
   260
		{
dvander@211
   261
			pFunc = g_PluginSys.GetFunctionFromPool(save, this);
dvander@176
   262
			m_priv_funcs[func_id] = pFunc;
dvander@176
   263
		}
dvander@176
   264
	}
dvander@176
   265
dvander@176
   266
	return pFunc;
dvander@176
   267
}
dvander@176
   268
dvander@176
   269
IPluginFunction *CPlugin::GetFunctionByName(const char *public_name)
dvander@176
   270
{
dvander@176
   271
	uint32_t index;
dvander@209
   272
	IPluginContext *base = m_ctx.base;
dvander@176
   273
dvander@176
   274
	if (base->FindPublicByName(public_name, &index) != SP_ERROR_NONE)
dvander@176
   275
	{
dvander@176
   276
		return NULL;
dvander@176
   277
	}
dvander@176
   278
dvander@176
   279
	CFunction *pFunc = m_pub_funcs[index];
dvander@176
   280
	if (!pFunc)
dvander@176
   281
	{
dvander@176
   282
		sp_public_t *pub = NULL;
dvander@176
   283
		base->GetPublicByIndex(index, &pub);
dvander@176
   284
		if (pub)
dvander@176
   285
		{
dvander@211
   286
			pFunc = g_PluginSys.GetFunctionFromPool(pub->funcid, this);
dvander@176
   287
			m_pub_funcs[index] = pFunc;
dvander@176
   288
		}
dvander@176
   289
	}
dvander@176
   290
dvander@176
   291
	return pFunc;
dvander@176
   292
}
dvander@176
   293
dvander@173
   294
void CPlugin::UpdateInfo()
dvander@173
   295
{
dvander@173
   296
	/* Now grab the info */
dvander@173
   297
	uint32_t idx;
dvander@173
   298
	IPluginContext *base = GetBaseContext();
dvander@173
   299
	int err = base->FindPubvarByName("myinfo", &idx);
dvander@173
   300
dvander@173
   301
	if (err == SP_ERROR_NONE)
dvander@173
   302
	{
dvander@173
   303
		struct sm_plugininfo_c_t
dvander@173
   304
		{
dvander@173
   305
			cell_t name;
dvander@173
   306
			cell_t description;
dvander@173
   307
			cell_t author;
dvander@173
   308
			cell_t version;
dvander@173
   309
			cell_t url;
dvander@173
   310
		};
dvander@173
   311
		sm_plugininfo_c_t *cinfo;
dvander@173
   312
		cell_t local_addr;
dvander@173
   313
dvander@173
   314
		base->GetPubvarAddrs(idx, &local_addr, (cell_t **)&cinfo);
dvander@173
   315
		base->LocalToString(cinfo->name, (char **)&m_info.name);
dvander@173
   316
		base->LocalToString(cinfo->description, (char **)&m_info.description);
dvander@173
   317
		base->LocalToString(cinfo->author, (char **)&m_info.author);
dvander@173
   318
		base->LocalToString(cinfo->url, (char **)&m_info.url);
dvander@173
   319
		base->LocalToString(cinfo->version, (char **)&m_info.version);
dvander@173
   320
	}
dvander@173
   321
dvander@173
   322
	m_info.author = m_info.author ? m_info.author : "";
dvander@173
   323
	m_info.description = m_info.description ? m_info.description : "";
dvander@173
   324
	m_info.name = m_info.name ? m_info.name : "";
dvander@173
   325
	m_info.url = m_info.url ? m_info.url : "";
dvander@173
   326
	m_info.version = m_info.version ? m_info.version : "";
dvander@173
   327
}
dvander@173
   328
dvander@211
   329
void CPlugin::Call_OnPluginInit()
dvander@211
   330
{
dvander@211
   331
	if (m_status != Plugin_Loaded)
dvander@211
   332
	{
dvander@211
   333
		return;
dvander@211
   334
	}
dvander@211
   335
dvander@211
   336
	m_status = Plugin_Running;
dvander@211
   337
dvander@211
   338
	cell_t result;
dvander@211
   339
	IPluginFunction *pFunction = GetFunctionByName("OnPluginInit");
dvander@211
   340
	if (!pFunction)
dvander@211
   341
	{
dvander@211
   342
		return;
dvander@211
   343
	}
dvander@211
   344
dvander@222
   345
	pFunction->PushCell(m_handle);
dvander@282
   346
	pFunction->Execute(&result);
dvander@282
   347
}
dvander@282
   348
dvander@282
   349
void CPlugin::Call_OnPluginUnload()
dvander@282
   350
{
dvander@282
   351
	if (m_status < Plugin_Paused)
dvander@211
   352
	{
dvander@282
   353
		return;
dvander@211
   354
	}
dvander@282
   355
dvander@282
   356
	cell_t result;
dvander@282
   357
	IPluginFunction *pFunction = GetFunctionByName("OnPluginUnload");
dvander@282
   358
	if (!pFunction)
dvander@282
   359
	{
dvander@282
   360
		return;
dvander@282
   361
	}
dvander@282
   362
dvander@282
   363
	pFunction->Execute(&result);
dvander@211
   364
}
dvander@211
   365
dvander@211
   366
bool CPlugin::Call_AskPluginLoad(char *error, size_t maxlength)
dvander@211
   367
{
dvander@211
   368
	if (m_status != Plugin_Created)
dvander@211
   369
	{
dvander@211
   370
		return false;
dvander@211
   371
	}
dvander@211
   372
faluco@216
   373
	m_status = Plugin_Loaded;
faluco@216
   374
dvander@211
   375
	int err;
dvander@211
   376
	cell_t result;
dvander@211
   377
	IPluginFunction *pFunction = GetFunctionByName("AskPluginLoad");
dvander@211
   378
dvander@211
   379
	if (!pFunction)
dvander@211
   380
	{
dvander@211
   381
		return true;
dvander@211
   382
	}
dvander@211
   383
dvander@222
   384
	pFunction->PushCell(m_handle);
dvander@211
   385
	pFunction->PushCell(g_PluginSys.IsLateLoadTime() ? 1 : 0);
dvander@211
   386
	pFunction->PushStringEx(error, maxlength, 0, SM_PARAM_COPYBACK);
dvander@211
   387
	pFunction->PushCell(maxlength);
dvander@211
   388
	if ((err=pFunction->Execute(&result)) != SP_ERROR_NONE)
dvander@211
   389
	{
dvander@282
   390
		m_status = Plugin_Failed;
dvander@211
   391
		return false;
dvander@211
   392
	}
dvander@211
   393
dvander@282
   394
	if (!result || m_status != Plugin_Loaded)
dvander@211
   395
	{
dvander@282
   396
		m_status = Plugin_Failed;
dvander@211
   397
		return false;
dvander@211
   398
	}
dvander@211
   399
dvander@211
   400
	return true;
dvander@211
   401
}
dvander@211
   402
dvander@173
   403
const sp_plugin_t *CPlugin::GetPluginStructure() const
dvander@173
   404
{
dvander@173
   405
	return m_plugin;
dvander@173
   406
}
dvander@173
   407
dvander@173
   408
IPluginContext *CPlugin::GetBaseContext() const
dvander@173
   409
{
dvander@209
   410
	return m_ctx.base;
dvander@173
   411
}
dvander@173
   412
dvander@173
   413
sp_context_t *CPlugin::GetContext() const
dvander@173
   414
{
dvander@209
   415
	return m_ctx.ctx;
dvander@173
   416
}
dvander@173
   417
dvander@173
   418
const char *CPlugin::GetFilename() const
dvander@173
   419
{
dvander@173
   420
	return m_filename;
dvander@173
   421
}
dvander@173
   422
dvander@174
   423
PluginType CPlugin::GetType() const
dvander@173
   424
{
dvander@174
   425
	return m_type;
dvander@173
   426
}
dvander@173
   427
dvander@173
   428
const sm_plugininfo_t *CPlugin::GetPublicInfo() const
dvander@173
   429
{
dvander@173
   430
	return &m_info;
dvander@173
   431
}
dvander@173
   432
dvander@173
   433
unsigned int CPlugin::GetSerial() const
dvander@173
   434
{
dvander@173
   435
	return m_serial;
dvander@173
   436
}
dvander@173
   437
dvander@173
   438
PluginStatus CPlugin::GetStatus() const
dvander@173
   439
{
dvander@173
   440
	return m_status;
dvander@173
   441
}
dvander@173
   442
dvander@173
   443
bool CPlugin::IsDebugging() const
dvander@173
   444
{
dvander@209
   445
	if (!m_ctx.ctx)
dvander@209
   446
	{
dvander@209
   447
		return false;
dvander@209
   448
	}
dvander@209
   449
dvander@209
   450
	return ((m_ctx.ctx->flags & SP_FLAG_DEBUG) == SP_FLAG_DEBUG);
dvander@173
   451
}
dvander@173
   452
dvander@173
   453
bool CPlugin::SetPauseState(bool paused)
dvander@173
   454
{
dvander@173
   455
	if (paused && GetStatus() != Plugin_Paused)
dvander@173
   456
	{
dvander@173
   457
		return false;
dvander@173
   458
	} else if (!paused && GetStatus() != Plugin_Running) {
dvander@173
   459
		return false;
dvander@173
   460
	}
dvander@282
   461
faluco@288
   462
	m_status = (paused) ? Plugin_Paused : Plugin_Running;
faluco@288
   463
dvander@282
   464
	IPluginFunction *pFunction = GetFunctionByName("OnPluginPauseChange");
dvander@282
   465
	if (pFunction)
dvander@282
   466
	{
dvander@282
   467
		cell_t result;
dvander@282
   468
		pFunction->PushCell(paused ? 1 : 0);
dvander@282
   469
		pFunction->Execute(&result);
dvander@282
   470
	}
dvander@173
   471
dvander@173
   472
	return true;
dvander@173
   473
}
dvander@174
   474
faluco@290
   475
IdentityToken_t *CPlugin::GetIdentity() const
dvander@220
   476
{
dvander@229
   477
	return m_ident;
dvander@220
   478
}
dvander@220
   479
faluco@290
   480
bool CPlugin::ToggleDebugMode(bool debug)
faluco@290
   481
{
faluco@290
   482
	int err;
faluco@290
   483
faluco@290
   484
	if (!IsRunnable())
faluco@290
   485
	{
faluco@290
   486
		return false;
faluco@290
   487
	}
faluco@290
   488
faluco@290
   489
	if ((debug && IsDebugging()) || (!debug && !IsDebugging()))
faluco@290
   490
	{
faluco@290
   491
		return false;
faluco@290
   492
	}
faluco@290
   493
	ICompilation *co = g_pVM->StartCompilation(m_ctx.ctx->plugin);
faluco@290
   494
	if (!g_pVM->SetCompilationOption(co, "debug", (debug) ? "1" : "0"))
faluco@290
   495
	{
faluco@290
   496
		return false;
faluco@290
   497
	}
faluco@290
   498
	sp_context_t *new_ctx = g_pVM->CompileToContext(co, &err);
faluco@290
   499
faluco@290
   500
	memcpy(new_ctx->memory, m_ctx.ctx->memory, m_ctx.ctx->mem_size);
faluco@290
   501
	new_ctx->hp = m_ctx.ctx->hp;
faluco@290
   502
	new_ctx->sp = m_ctx.ctx->sp;
faluco@290
   503
	new_ctx->frm = m_ctx.ctx->frm;
faluco@290
   504
	new_ctx->dbreak = m_ctx.ctx->dbreak;
faluco@290
   505
	new_ctx->context = m_ctx.ctx->context;
faluco@290
   506
	memcpy(new_ctx->user, m_ctx.ctx->user, sizeof(m_ctx.ctx->user));
faluco@290
   507
faluco@290
   508
	g_pVM->FreeContext(m_ctx.ctx);
faluco@290
   509
	m_ctx.ctx = new_ctx;
faluco@290
   510
	m_ctx.base->SetContext(new_ctx);
faluco@290
   511
faluco@290
   512
	UpdateInfo();
faluco@290
   513
faluco@290
   514
	return true;
faluco@290
   515
}
faluco@290
   516
faluco@290
   517
bool CPlugin::IsRunnable() const
faluco@290
   518
{
faluco@290
   519
	return (m_status <= Plugin_Paused) ? true : false;
faluco@290
   520
}
faluco@290
   521
dvander@174
   522
/*******************
dvander@174
   523
 * PLUGIN ITERATOR *
dvander@174
   524
 *******************/
dvander@190
   525
dvander@213
   526
CPluginManager::CPluginIterator::CPluginIterator(List<CPlugin *> *_mylist)
dvander@174
   527
{
dvander@174
   528
	mylist = _mylist;
faluco@216
   529
	Reset();
dvander@174
   530
}
dvander@174
   531
dvander@174
   532
IPlugin *CPluginManager::CPluginIterator::GetPlugin()
dvander@174
   533
{
dvander@174
   534
	return (*current);
dvander@174
   535
}
dvander@174
   536
dvander@174
   537
bool CPluginManager::CPluginIterator::MorePlugins()
dvander@174
   538
{
dvander@174
   539
	return (current != mylist->end());
dvander@174
   540
}
dvander@174
   541
dvander@174
   542
void CPluginManager::CPluginIterator::NextPlugin()
dvander@174
   543
{
dvander@174
   544
	current++;
dvander@174
   545
}
dvander@174
   546
dvander@174
   547
void CPluginManager::CPluginIterator::Release()
dvander@174
   548
{
dvander@211
   549
	g_PluginSys.ReleaseIterator(this);
dvander@174
   550
}
dvander@174
   551
dvander@174
   552
CPluginManager::CPluginIterator::~CPluginIterator()
dvander@174
   553
{
dvander@174
   554
}
dvander@174
   555
dvander@174
   556
void CPluginManager::CPluginIterator::Reset()
dvander@174
   557
{
dvander@174
   558
	current = mylist->begin();
dvander@174
   559
}
dvander@174
   560
dvander@174
   561
/******************
dvander@174
   562
 * PLUGIN MANAGER *
dvander@174
   563
 ******************/
dvander@174
   564
dvander@211
   565
CPluginManager::CPluginManager()
dvander@211
   566
{
dvander@211
   567
	m_LoadLookup = sm_trie_create();
dvander@211
   568
	m_AllPluginsLoaded = false;
dvander@229
   569
	m_MyIdent = NULL;
dvander@211
   570
}
dvander@211
   571
dvander@211
   572
CPluginManager::~CPluginManager()
dvander@211
   573
{
dvander@282
   574
	/* :NOTICE: 
dvander@282
   575
	 * Ignore the fact that there might be plugins in the cache.
dvander@282
   576
	 * This usually means that Core is not being unloaded properly, and everything
dvander@282
   577
	 * will crash anyway.  YAY
dvander@282
   578
	 */
dvander@211
   579
	sm_trie_destroy(m_LoadLookup);
dvander@211
   580
}
dvander@211
   581
dvander@211
   582
dvander@213
   583
void CPluginManager::LoadAll_FirstPass(const char *config, const char *basedir)
dvander@190
   584
{
dvander@203
   585
	/* First read in the database of plugin settings */
dvander@203
   586
	SMCParseError err;
dvander@203
   587
	unsigned int line, col;
faluco@216
   588
	m_AllPluginsLoaded = false;
dvander@273
   589
	if ((err=g_TextParser.ParseFile_SMC(config, &m_PluginInfo, &line, &col)) != SMCParse_Okay)
dvander@203
   590
	{
dvander@305
   591
		g_Logger.LogError("[SM] Encountered fatal error parsing file \"%s\"", config);
dvander@282
   592
		const char *err_msg = g_TextParser.GetSMCErrorString(err);
dvander@282
   593
		if (err_msg)
dvander@282
   594
		{
dvander@305
   595
			g_Logger.LogError("[SM] Parse error encountered: \"%s\"", err_msg);
dvander@282
   596
		}
dvander@203
   597
	}
dvander@203
   598
dvander@209
   599
	LoadPluginsFromDir(basedir, NULL);
dvander@209
   600
}
dvander@203
   601
dvander@209
   602
void CPluginManager::LoadPluginsFromDir(const char *basedir, const char *localpath)
dvander@209
   603
{
dvander@209
   604
	char base_path[PLATFORM_MAX_PATH+1];
dvander@209
   605
dvander@209
   606
	/* Form the current path to start reading from */
dvander@209
   607
	if (localpath == NULL)
dvander@209
   608
	{
dvander@209
   609
		g_LibSys.PathFormat(base_path, sizeof(base_path), "%s", basedir);
dvander@209
   610
	} else {
dvander@209
   611
		g_LibSys.PathFormat(base_path, sizeof(base_path), "%s/%s", basedir, localpath);
dvander@209
   612
	}
dvander@209
   613
dvander@209
   614
	IDirectory *dir = g_LibSys.OpenDirectory(base_path);
dvander@209
   615
dvander@209
   616
	if (!dir)
dvander@209
   617
	{
dvander@282
   618
		char error[256];
dvander@282
   619
		g_LibSys.GetPlatformError(error, sizeof(error));
dvander@305
   620
		g_Logger.LogError("[SM] Failure reading from plugins path: %s", localpath);
dvander@305
   621
		g_Logger.LogError("[SM] Platform returned error: %s", error);
dvander@209
   622
		return;
dvander@209
   623
	}
dvander@209
   624
dvander@190
   625
	while (dir->MoreFiles())
dvander@190
   626
	{
dvander@209
   627
		if (dir->IsEntryDirectory() 
dvander@209
   628
			&& (strcmp(dir->GetEntryName(), ".") != 0)
dvander@209
   629
			&& (strcmp(dir->GetEntryName(), "..") != 0)
dvander@209
   630
			&& (strcmp(dir->GetEntryName(), "disabled") != 0)
dvander@209
   631
			&& (strcmp(dir->GetEntryName(), "optional") != 0))
dvander@190
   632
		{
dvander@209
   633
			char new_local[PLATFORM_MAX_PATH+1];
dvander@209
   634
			if (localpath == NULL)
dvander@209
   635
			{
dvander@209
   636
				/* If no path yet, don't add a former slash */
dvander@209
   637
				snprintf(new_local, sizeof(new_local), "%s", dir->GetEntryName());
dvander@209
   638
			} else {
dvander@209
   639
				g_LibSys.PathFormat(new_local, sizeof(new_local), "%s/%s", localpath, dir->GetEntryName());
dvander@209
   640
			}
dvander@209
   641
			LoadPluginsFromDir(basedir, new_local);
dvander@209
   642
		} else if (dir->IsEntryFile()) {
dvander@209
   643
			const char *name = dir->GetEntryName();
dvander@209
   644
			size_t len = strlen(name);
dvander@211
   645
			if (len >= 4
dvander@211
   646
				&& strcmp(&name[len-4], ".smx") == 0)
dvander@209
   647
			{
dvander@211
   648
				/* If the filename matches, load the plugin */
dvander@211
   649
				char plugin[PLATFORM_MAX_PATH+1];
dvander@211
   650
				if (localpath == NULL)
dvander@211
   651
				{
dvander@211
   652
					snprintf(plugin, sizeof(plugin), "%s", name);
dvander@211
   653
				} else {
dvander@211
   654
					g_LibSys.PathFormat(plugin, sizeof(plugin), "%s/%s", localpath, name);
dvander@211
   655
				}
dvander@211
   656
				LoadAutoPlugin(plugin);
dvander@209
   657
			}
dvander@209
   658
		}
dvander@209
   659
		dir->NextEntry();
dvander@209
   660
	}
dvander@209
   661
	g_LibSys.CloseDirectory(dir);
dvander@209
   662
}
dvander@209
   663
dvander@211
   664
//well i have discovered that gabe newell is very fat, so i wrote this comment now
dvander@211
   665
//:TODO: remove this function, create a better wrapper for LoadPlugin()/LoadAutoPlugin()
dvander@298
   666
bool CPluginManager::_LoadPlugin(CPlugin **_plugin, const char *path, bool debug, PluginType type, char error[], size_t err_max)
dvander@209
   667
{
dvander@211
   668
	/**
dvander@211
   669
	 * Does this plugin already exist?
dvander@211
   670
	 */
dvander@211
   671
	CPlugin *pPlugin;
dvander@298
   672
	if (sm_trie_retrieve(m_LoadLookup, path, (void **)&pPlugin))
dvander@211
   673
	{
dvander@211
   674
		/* First check the type */
dvander@211
   675
		PluginType type = pPlugin->GetType();
dvander@211
   676
		if (type == PluginType_Private
dvander@211
   677
			|| type == PluginType_Global)
dvander@211
   678
		{
dvander@298
   679
			return true;
dvander@211
   680
		}
dvander@211
   681
		/* Check to see if we should try reloading it */
dvander@211
   682
		if (pPlugin->GetStatus() == Plugin_BadLoad
dvander@282
   683
			|| pPlugin->GetStatus() == Plugin_Error
dvander@282
   684
			|| pPlugin->GetStatus() == Plugin_Failed)
dvander@211
   685
		{
dvander@211
   686
			UnloadPlugin(pPlugin);
dvander@211
   687
		}
dvander@211
   688
	}
dvander@211
   689
dvander@298
   690
	pPlugin = CPlugin::CreatePlugin(path, error, err_max);
dvander@209
   691
dvander@209
   692
	assert(pPlugin != NULL);
dvander@209
   693
dvander@209
   694
	pPlugin->m_type = PluginType_MapUpdated;
dvander@209
   695
dvander@209
   696
	ICompilation *co = NULL;
dvander@209
   697
dvander@209
   698
	if (pPlugin->m_status == Plugin_Uncompiled)
dvander@209
   699
	{
dvander@209
   700
		co = pPlugin->StartMyCompile(g_pVM);
dvander@209
   701
	}
dvander@209
   702
dvander@209
   703
	PluginSettings *pset;
dvander@209
   704
	unsigned int setcount = m_PluginInfo.GetSettingsNum();
dvander@209
   705
	for (unsigned int i=0; i<setcount; i++)
dvander@209
   706
	{
dvander@298
   707
		if ((pset=m_PluginInfo.GetSettingsIfMatch(i, path)) == NULL)
dvander@209
   708
		{
dvander@209
   709
			continue;
dvander@209
   710
		}
dvander@209
   711
		pPlugin->m_type = pset->type_val;
dvander@209
   712
		if (co)
dvander@209
   713
		{
dvander@209
   714
			for (unsigned int j=0; j<pset->opts_num; j++)
dvander@209
   715
			{
dvander@209
   716
				const char *key, *val;
dvander@209
   717
				m_PluginInfo.GetOptionsForPlugin(pset, j, &key, &val);
dvander@209
   718
				if (!key || !val)
dvander@209
   719
				{
dvander@209
   720
					continue;
dvander@209
   721
				}
dvander@209
   722
				if (!g_pVM->SetCompilationOption(co, key, val))
dvander@209
   723
				{
dvander@298
   724
					if (error)
dvander@298
   725
					{
dvander@298
   726
						snprintf(error, err_max, "Unable to set JIT option (key \"%s\") (value \"%s\")", key, val);
dvander@298
   727
					}
dvander@209
   728
					pPlugin->CancelMyCompile();
dvander@298
   729
					pPlugin->m_status = Plugin_Failed;
dvander@209
   730
					co = NULL;
dvander@209
   731
					break;
dvander@209
   732
				}
dvander@209
   733
			}
dvander@190
   734
		}
dvander@190
   735
	}
dvander@209
   736
dvander@298
   737
	/* Do the actual compiling */
dvander@209
   738
	if (co)
dvander@209
   739
	{
dvander@209
   740
		pPlugin->FinishMyCompile(NULL, 0);
dvander@209
   741
		co = NULL;
dvander@209
   742
	}
dvander@209
   743
dvander@298
   744
	/* Get the status */
dvander@211
   745
	if (pPlugin->GetStatus() == Plugin_Created)
dvander@211
   746
	{
dvander@211
   747
		AddCoreNativesToPlugin(pPlugin);
dvander@229
   748
		pPlugin->InitIdentity();
dvander@298
   749
		pPlugin->Call_AskPluginLoad(error, err_max);
dvander@211
   750
	}
dvander@211
   751
dvander@298
   752
	if (_plugin)
dvander@298
   753
	{
dvander@298
   754
		*_plugin = pPlugin;
dvander@298
   755
	}
dvander@298
   756
dvander@298
   757
	return (pPlugin->GetStatus() == Plugin_Loaded);
dvander@190
   758
}
dvander@190
   759
dvander@174
   760
IPlugin *CPluginManager::LoadPlugin(const char *path, bool debug, PluginType type, char error[], size_t err_max)
dvander@174
   761
{
dvander@298
   762
	CPlugin *pl;
dvander@211
   763
dvander@298
   764
	if (!_LoadPlugin(&pl, path, debug, type, error, err_max))
dvander@211
   765
	{
dvander@298
   766
		delete pl;
dvander@174
   767
		return NULL;
dvander@174
   768
	}
dvander@174
   769
dvander@298
   770
	AddPlugin(pl);
dvander@298
   771
dvander@298
   772
	return pl;
dvander@298
   773
}
dvander@298
   774
dvander@298
   775
void CPluginManager::LoadAutoPlugin(const char *plugin)
dvander@298
   776
{
dvander@298
   777
	CPlugin *pl;
dvander@298
   778
	char error[255] = "Unknown error";
dvander@298
   779
dvander@298
   780
	if (!_LoadPlugin(&pl, plugin, false, PluginType_MapUpdated, error, sizeof(error)))
dvander@209
   781
	{
dvander@305
   782
		g_Logger.LogError("[SM] Failed to load plugin \"%s\": %s", plugin, error);
dvander@298
   783
		pl->SetErrorState(Plugin_Failed, "%s", error);
dvander@209
   784
	}
dvander@209
   785
dvander@298
   786
	AddPlugin(pl);
dvander@209
   787
}
dvander@209
   788
dvander@211
   789
void CPluginManager::AddPlugin(CPlugin *pPlugin)
dvander@209
   790
{
dvander@174
   791
	List<IPluginsListener *>::iterator iter;
dvander@174
   792
	IPluginsListener *pListener;
dvander@298
   793
dvander@174
   794
	for (iter=m_listeners.begin(); iter!=m_listeners.end(); iter++)
dvander@174
   795
	{
dvander@174
   796
		pListener = (*iter);
dvander@174
   797
		pListener->OnPluginCreated(pPlugin);
dvander@174
   798
	}
dvander@174
   799
dvander@298
   800
	m_plugins.push_back(pPlugin);
dvander@298
   801
	sm_trie_insert(m_LoadLookup, pPlugin->m_filename, pPlugin);
dvander@211
   802
}
dvander@211
   803
dvander@213
   804
void CPluginManager::LoadAll_SecondPass()
dvander@213
   805
{
dvander@213
   806
	List<CPlugin *>::iterator iter;
dvander@213
   807
	CPlugin *pPlugin;
dvander@213
   808
dvander@213
   809
	for (iter=m_plugins.begin(); iter!=m_plugins.end(); iter++)
dvander@213
   810
	{
dvander@213
   811
		pPlugin = (*iter);
dvander@213
   812
		if (pPlugin->GetStatus() == Plugin_Loaded)
dvander@213
   813
		{
dvander@298
   814
			/* :TODO: fix */
dvander@298
   815
			RunSecondPass(pPlugin, NULL, 0);
dvander@213
   816
		}
dvander@213
   817
	}
dvander@298
   818
faluco@216
   819
	m_AllPluginsLoaded = true;
dvander@213
   820
}
dvander@213
   821
dvander@298
   822
bool CPluginManager::RunSecondPass(CPlugin *pPlugin, char *error, size_t maxlength)
dvander@211
   823
{
dvander@298
   824
	/* Find any extensions this plugin needs */
dvander@298
   825
	struct _ext
dvander@298
   826
	{
dvander@298
   827
		cell_t name;
dvander@298
   828
		cell_t file;
dvander@298
   829
		cell_t autoload;
dvander@298
   830
		cell_t required;
dvander@298
   831
	} *ext;
dvander@298
   832
dvander@298
   833
	IPluginContext *pBase = pPlugin->GetBaseContext();
dvander@298
   834
	uint32_t num = pBase->GetPubVarsNum();
dvander@298
   835
	sp_pubvar_t *pubvar;
dvander@298
   836
	IExtension *pExt;
dvander@298
   837
	char path[PLATFORM_MAX_PATH+1];
dvander@298
   838
	char *file, *name;
dvander@298
   839
	for (uint32_t i=0; i<num; i++)
dvander@298
   840
	{
dvander@298
   841
		if (pBase->GetPubvarByIndex(i, &pubvar) != SP_ERROR_NONE)
dvander@298
   842
		{
dvander@298
   843
			continue;
dvander@298
   844
		}
dvander@298
   845
		if (strncmp(pubvar->name, "__ext_", 6) == 0)
dvander@298
   846
		{
dvander@298
   847
			ext = (_ext *)pubvar->offs;
dvander@298
   848
			if (!ext->required && !ext->autoload)
dvander@298
   849
			{
dvander@298
   850
				continue;
dvander@298
   851
			}
dvander@298
   852
			if (pBase->LocalToString(ext->file, &file) != SP_ERROR_NONE)
dvander@298
   853
			{
dvander@298
   854
				continue;
dvander@298
   855
			}
dvander@298
   856
			if (pBase->LocalToString(ext->name, &name) != SP_ERROR_NONE)
dvander@298
   857
			{
dvander@298
   858
				continue;
dvander@298
   859
			}
dvander@298
   860
			snprintf(path, PLATFORM_MAX_PATH, "%s.%s", file, PLATFORM_LIB_EXT);
dvander@298
   861
			pExt = NULL;
dvander@298
   862
			/* Attempt to auto-load if necessary */
dvander@298
   863
			if (ext->autoload)
dvander@298
   864
			{
dvander@298
   865
				pExt = g_Extensions.LoadAutoExtension(path);
dvander@298
   866
			}
dvander@305
   867
			/* See if we can find a similar extension */
dvander@298
   868
			if (ext->required && !pExt)
dvander@298
   869
			{
dvander@298
   870
				if ((pExt = g_Extensions.FindExtensionByFile(path)) == NULL)
dvander@298
   871
				{
dvander@298
   872
					pExt = g_Extensions.FindExtensionByName(name);
dvander@298
   873
				}
dvander@298
   874
			}
dvander@305
   875
			/* If we're requiring and got an extension and it's loaded, bind it */
dvander@305
   876
			if (ext->required && pExt && pExt->IsLoaded())
dvander@305
   877
			{
dvander@305
   878
				g_Extensions.BindChildPlugin(pExt, pPlugin);
dvander@305
   879
			}
dvander@305
   880
			/* If we're requiring and we didn't get an extension or it's not loaded, error */
dvander@298
   881
			if (ext->required && (!pExt || !pExt->IsLoaded()))
dvander@298
   882
			{
dvander@298
   883
				if (error)
dvander@298
   884
				{
dvander@298
   885
					snprintf(error, maxlength, "Required extension \"%s\" (file \"%s\") not found", name, file);
dvander@298
   886
				}
dvander@298
   887
				pPlugin->m_status = Plugin_Failed;
dvander@298
   888
				return false;
dvander@298
   889
			}
dvander@298
   890
		}
dvander@298
   891
	}
dvander@211
   892
dvander@211
   893
	/* Finish by telling all listeners */
dvander@211
   894
	List<IPluginsListener *>::iterator iter;
dvander@211
   895
	IPluginsListener *pListener;
dvander@211
   896
	for (iter=m_listeners.begin(); iter!=m_listeners.end(); iter++)
dvander@211
   897
	{
dvander@211
   898
		pListener = (*iter);
dvander@211
   899
		pListener->OnPluginLoaded(pPlugin);
dvander@211
   900
	}
dvander@298
   901
	
dvander@298
   902
	/* Tell this plugin to finish initializing itself */
dvander@298
   903
	pPlugin->Call_OnPluginInit();
dvander@298
   904
dvander@298
   905
	return true;
dvander@211
   906
}
dvander@211
   907
dvander@211
   908
void CPluginManager::AddCoreNativesToPlugin(CPlugin *pPlugin)
dvander@211
   909
{
dvander@211
   910
	List<sp_nativeinfo_t *>::iterator iter;
dvander@211
   911
dvander@211
   912
	for (iter=m_natives.begin(); iter!=m_natives.end(); iter++)
dvander@211
   913
	{
dvander@211
   914
		sp_nativeinfo_t *natives = (*iter);
dvander@211
   915
		IPluginContext *ctx = pPlugin->GetBaseContext();
dvander@211
   916
		unsigned int i=0;
dvander@211
   917
		/* Attempt to bind every native! */
dvander@211
   918
		while (natives[i].func != NULL)
dvander@211
   919
		{
dvander@211
   920
			ctx->BindNative(&natives[i++]);
dvander@211
   921
		}
dvander@211
   922
	}
dvander@174
   923
}
dvander@174
   924
dvander@174
   925
bool CPluginManager::UnloadPlugin(IPlugin *plugin)
dvander@174
   926
{
dvander@174
   927
	CPlugin *pPlugin = (CPlugin *)plugin;
dvander@298
   928
dvander@298
   929
	/* This prevents removal during insertion or anything else weird */
dvander@298
   930
	if (m_plugins.find(pPlugin) == m_plugins.end())
dvander@298
   931
	{
dvander@298
   932
		return false;
dvander@298
   933
	}
dvander@298
   934
dvander@174
   935
	List<IPluginsListener *>::iterator iter;
dvander@174
   936
	IPluginsListener *pListener;
dvander@282
   937
dvander@282
   938
	if (pPlugin->GetStatus() >= Plugin_Error)
dvander@282
   939
	{
dvander@282
   940
		/* Notify listeners of unloading */
dvander@282
   941
		for (iter=m_listeners.begin(); iter!=m_listeners.end(); iter++)
dvander@282
   942
		{
dvander@282
   943
			pListener = (*iter);
dvander@282
   944
			pListener->OnPluginUnloaded(pPlugin);
dvander@282
   945
		}
dvander@282
   946
		/* Notify plugin */
dvander@282
   947
		pPlugin->Call_OnPluginUnload();
dvander@282
   948
	}
dvander@282
   949
dvander@174
   950
	for (iter=m_listeners.begin(); iter!=m_listeners.end(); iter++)
dvander@174
   951
	{
dvander@282
   952
		/* Notify listeners of destruction */
dvander@174
   953
		pListener = (*iter);
dvander@174
   954
		pListener->OnPluginDestroyed(pPlugin);
dvander@174
   955
	}
dvander@211
   956
dvander@282
   957
	/* Remove us from the lookup table and linked list */
dvander@213
   958
	m_plugins.remove(pPlugin);
dvander@211
   959
	sm_trie_delete(m_LoadLookup, pPlugin->m_filename);
dvander@176
   960
	
dvander@282
   961
	/* Tell the plugin to delete itself */
dvander@174
   962
	delete pPlugin;
dvander@174
   963
dvander@174
   964
	return true;
dvander@174
   965
}
dvander@174
   966
dvander@174
   967
IPlugin *CPluginManager::FindPluginByContext(const sp_context_t *ctx)
dvander@174
   968
{
dvander@174
   969
	IPlugin *pl = (IPlugin *)ctx->user[SM_CONTEXTVAR_MYSELF];
dvander@174
   970
	return pl;
dvander@174
   971
}
dvander@174
   972
dvander@174
   973
unsigned int CPluginManager::GetPluginCount()
dvander@174
   974
{
dvander@174
   975
	return m_plugins.size();
dvander@174
   976
}
dvander@174
   977
dvander@174
   978
void CPluginManager::AddPluginsListener(IPluginsListener *listener)
dvander@174
   979
{
dvander@174
   980
	m_listeners.push_back(listener);
dvander@174
   981
}
dvander@174
   982
dvander@174
   983
void CPluginManager::RemovePluginsListener(IPluginsListener *listener)
dvander@174
   984
{
dvander@174
   985
	m_listeners.remove(listener);
dvander@174
   986
}
dvander@174
   987
dvander@174
   988
IPluginIterator *CPluginManager::GetPluginIterator()
dvander@174
   989
{
dvander@174
   990
	if (m_iters.empty())
dvander@174
   991
	{
dvander@174
   992
		return new CPluginIterator(&m_plugins);
dvander@174
   993
	} else {
dvander@174
   994
		CPluginIterator *iter = m_iters.front();
dvander@174
   995
		m_iters.pop();
faluco@216
   996
		iter->Reset();
dvander@174
   997
		return iter;
dvander@174
   998
	}
dvander@174
   999
}
dvander@174
  1000
dvander@174
  1001
void CPluginManager::ReleaseIterator(CPluginIterator *iter)
dvander@174
  1002
{
dvander@174
  1003
	m_iters.push(iter);
dvander@174
  1004
}
dvander@176
  1005
dvander@176
  1006
void CPluginManager::ReleaseFunctionToPool(CFunction *func)
dvander@176
  1007
{
dvander@177
  1008
	if (!func)
dvander@177
  1009
	{
dvander@177
  1010
		return;
dvander@177
  1011
	}
dvander@177
  1012
	func->Cancel();
dvander@176
  1013
	m_funcpool.push(func);
dvander@176
  1014
}
dvander@176
  1015
dvander@176
  1016
CFunction *CPluginManager::GetFunctionFromPool(funcid_t f, CPlugin *plugin)
dvander@176
  1017
{
dvander@176
  1018
	if (m_funcpool.empty())
dvander@176
  1019
	{
dvander@176
  1020
		return new CFunction(f, plugin);
dvander@176
  1021
	} else {
dvander@176
  1022
		CFunction *func = m_funcpool.front();
dvander@176
  1023
		m_funcpool.pop();
dvander@176
  1024
		func->Set(f, plugin);
dvander@176
  1025
		return func;
dvander@176
  1026
	}
dvander@176
  1027
}
dvander@176
  1028
dvander@203
  1029
bool CPluginManager::TestAliasMatch(const char *alias, const char *localpath)
dvander@203
  1030
{
dvander@203
  1031
	/* As an optimization, we do not call strlen, but compute the length in the first pass */
dvander@203
  1032
	size_t alias_len = 0;
dvander@203
  1033
	size_t local_len = 0;
dvander@203
  1034
dvander@203
  1035
	const char *ptr = alias;
dvander@203
  1036
	unsigned int alias_explicit_paths = 0;
dvander@203
  1037
	unsigned int alias_path_end = 0;
dvander@203
  1038
	while (*ptr != '\0')
dvander@203
  1039
	{
dvander@203
  1040
		if (*ptr == '\\' || *ptr == '/')
dvander@203
  1041
		{
dvander@203
  1042
			alias_explicit_paths++;
dvander@203
  1043
			alias_path_end = alias_len;
dvander@203
  1044
		}
dvander@203
  1045
		alias_len++;
dvander@203
  1046
		ptr++;
dvander@203
  1047
	}
dvander@203
  1048
dvander@209
  1049
	if (alias_explicit_paths && alias_path_end == alias_len - 1)
dvander@203
  1050
	{
dvander@203
  1051
		/* Trailing slash is totally invalid here */
dvander@203
  1052
		return false;
dvander@203
  1053
	}
dvander@203
  1054
dvander@203
  1055
	ptr = localpath;
dvander@203
  1056
	unsigned int local_explicit_paths = 0;
dvander@203
  1057
	unsigned int local_path_end = 0;
dvander@203
  1058
	while (*ptr != '\0')
dvander@203
  1059
	{
dvander@203
  1060
		if (*ptr == '\\' || *ptr == '/')
dvander@203
  1061
		{
dvander@203
  1062
			local_explicit_paths++;
dvander@203
  1063
			local_path_end = local_len;
dvander@203
  1064
		}
dvander@203
  1065
		local_len++;
dvander@203
  1066
		ptr++;
dvander@203
  1067
	}
dvander@203
  1068
dvander@203
  1069
	/* If the alias has more explicit paths than the real path,
dvander@203
  1070
	 * no match will be possible.
dvander@203
  1071
	 */
dvander@203
  1072
	if (alias_explicit_paths > local_explicit_paths)
dvander@203
  1073
	{
dvander@203
  1074
		return false;
dvander@203
  1075
	}
dvander@203
  1076
dvander@203
  1077
	if (alias_explicit_paths)
dvander@203
  1078
	{
dvander@203
  1079
		/* We need to find if the paths match now.  For example, these should all match:
dvander@203
  1080
		 * csdm     csdm
dvander@203
  1081
		 * csdm     optional/csdm
dvander@203
  1082
		 * csdm/ban optional/crab/csdm/ban
dvander@203
  1083
		*/
dvander@203
  1084
		const char *aliasptr = alias;
dvander@203
  1085
		const char *localptr = localpath;
dvander@203
  1086
		bool match = true;
dvander@203
  1087
		do
dvander@203
  1088
		{
dvander@203
  1089
			if (*aliasptr != *localptr)
dvander@203
  1090
			{
dvander@203
  1091
				/* We have to knock one path off */
dvander@203
  1092
				local_explicit_paths--;
dvander@203
  1093
				if (alias_explicit_paths > local_explicit_paths)
dvander@203
  1094
				{
dvander@203
  1095
					/* Skip out if we're gonna have an impossible match */
dvander@203
  1096
					return false;
dvander@203
  1097
				}
dvander@203
  1098
				/* Eat up localptr tokens until we get a result */
dvander@203
  1099
				while (((localptr - localpath) < (int)local_path_end)
dvander@203
  1100
					&& *localptr != '/'
dvander@203
  1101
					&& *localptr != '\\')
dvander@203
  1102
				{
dvander@203
  1103
					localptr++;
dvander@203
  1104
				}
dvander@203
  1105
				/* Check if we hit the end of our searchable area.
dvander@203
  1106
				 * This probably isn't possible because of the path 
dvander@203
  1107
				 * count check, but it's a good idea anyway.
dvander@203
  1108
				 */
dvander@203
  1109
				if ((localptr - localpath) >= (int)local_path_end)
dvander@203
  1110
				{
dvander@203
  1111
					return false;
dvander@203
  1112
				} else {
dvander@203
  1113
					/* Consume the slash token */
dvander@203
  1114
					localptr++;
dvander@203
  1115
				}
dvander@203
  1116
				/* Reset the alias pointer so we can continue consuming */
dvander@203
  1117
				aliasptr = alias;
dvander@203
  1118
				match = false;
dvander@203
  1119
				continue;
dvander@203
  1120
			}
dvander@203
  1121
			/* Note:
dvander@203
  1122
			 * This is safe because if localptr terminates early, aliasptr will too
dvander@203
  1123
			 */
dvander@203
  1124
			do
dvander@203
  1125
			{
dvander@203
  1126
				/* We should never reach the end of the string because of this check. */
dvander@203
  1127
				bool aliasend = (aliasptr - alias) > (int)alias_path_end;
dvander@203
  1128
				bool localend = (localptr - localpath) > (int)local_path_end;
dvander@203
  1129
				if (aliasend || localend)
dvander@203
  1130
				{
dvander@203
  1131
					if (aliasend && localend)
dvander@203
  1132
					{
dvander@203
  1133
						/* we matched, and we can break out now */
dvander@203
  1134
						match = true;
dvander@203
  1135
						break;
dvander@203
  1136
					}
dvander@203
  1137
					/* Otherwise, we've hit the end somehow and rest won't match up.  Break out. */
dvander@203
  1138
					match = false;
dvander@203
  1139
					break;
dvander@203
  1140
				}
dvander@203
  1141
dvander@203
  1142
				/* If we got here, it's safe to compare the next two tokens */
dvander@203
  1143
				if (*localptr != *aliasptr)
dvander@203
  1144
				{
dvander@203
  1145
					match = false;
dvander@203
  1146
					break;
dvander@203
  1147
				}
dvander@203
  1148
				localptr++;
dvander@203
  1149
				aliasptr++;
dvander@203
  1150
			} while (true);
dvander@203
  1151
		} while (!match);
dvander@203
  1152
	}
dvander@203
  1153
dvander@203
  1154
	/* If we got here, it's time to compare filenames */
dvander@203
  1155
	const char *aliasptr = alias;
dvander@203
  1156
	const char *localptr = localpath;
dvander@203
  1157
dvander@203
  1158
	if (alias_explicit_paths)
dvander@203
  1159
	{
dvander@203
  1160
		aliasptr = &alias[alias_path_end + 1];
dvander@203
  1161
	}
dvander@203
  1162
dvander@203
  1163
	if (local_explicit_paths)
dvander@203
  1164
	{
dvander@203
  1165
		localptr = &localpath[local_path_end + 1];
dvander@203
  1166
	}
dvander@203
  1167
dvander@203
  1168
	while (true)
dvander@203
  1169
	{
dvander@203
  1170
		if (*aliasptr == '*')
dvander@203
  1171
		{
dvander@203
  1172
			/* First, see if this is the last character */
dvander@203
  1173
			if (aliasptr - alias == alias_len - 1)
dvander@203
  1174
			{
dvander@203
  1175
				/* If so, there's no need to match anything else */
dvander@203
  1176
				return true;
dvander@203
  1177
			}
dvander@203
  1178
			/* Otherwise, we need to search for an appropriate matching sequence in local.
dvander@203
  1179
			 * Note that we only need to search up to the next asterisk.
dvander@203
  1180
			 */
dvander@203
  1181
			aliasptr++;
dvander@203
  1182
			bool match = true;
dvander@203
  1183
			const char *local_orig = localptr;
dvander@203
  1184
			do
dvander@203
  1185
			{
dvander@203
  1186
				match = true;
dvander@203
  1187
				while (*aliasptr != '\0' && *aliasptr != '*')
dvander@203
  1188
				{
dvander@203
  1189
					/* Since aliasptr is never '\0', localptr hitting the end will fail */
dvander@203
  1190
					if (*aliasptr != *localptr)
dvander@203
  1191
					{
dvander@203
  1192
						match = false;
dvander@203
  1193
						break;
dvander@203
  1194
					}
dvander@203
  1195
					aliasptr++;
dvander@203
  1196
					localptr++;
dvander@203
  1197
				}
dvander@203
  1198
				if (!match)
dvander@203
  1199
				{
dvander@203
  1200
					/* If we didn't get a match, we need to advance the search stream.
dvander@203
  1201
					 * This will let us skip tokens while still searching for another match.
dvander@203
  1202
					 */
dvander@203
  1203
					localptr = ++local_orig;
dvander@203
  1204
					/* Make sure we don't go out of bounds */
dvander@203
  1205
					if (*localptr == '\0')
dvander@203
  1206
					{
dvander@203
  1207
						break;
dvander@203
  1208
					}
dvander@203
  1209
				}
dvander@203
  1210
			} while (!match);
dvander@203
  1211
dvander@203
  1212
			if (!match)
dvander@203
  1213
			{
dvander@203
  1214
				return false;
dvander@203
  1215
			} else {
dvander@203
  1216
				/* If we got a match, move on to the next token */
dvander@203
  1217
				continue;
dvander@203
  1218
			}
dvander@203
  1219
		} else if (*aliasptr == '\0') {
dvander@203
  1220
			if (*localptr == '\0'
dvander@203
  1221
				||
dvander@203
  1222
				strcmp(localptr, ".smx") == 0)
dvander@203
  1223
			{
dvander@203
  1224
				return true;
dvander@203
  1225
			} else {
dvander@203
  1226
				return false;
dvander@203
  1227
			}
dvander@203
  1228
		} else if (*aliasptr != *localptr) {
dvander@203
  1229
			return false;
dvander@203
  1230
		}
dvander@203
  1231
		aliasptr++;
dvander@203
  1232
		localptr++;
dvander@203
  1233
	}
dvander@203
  1234
dvander@203
  1235
	return true;
dvander@203
  1236
}
dvander@203
  1237
faluco@290
  1238
bool CPluginManager::IsLateLoadTime() const
dvander@176
  1239
{
dvander@211
  1240
	return (m_AllPluginsLoaded || g_SourceMod.IsLateLoadInMap());
dvander@176
  1241
}
dvander@220
  1242
dvander@220
  1243
void CPluginManager::OnSourceModAllInitialized()
dvander@220
  1244
{
dvander@229
  1245
	m_MyIdent = g_ShareSys.CreateCoreIdentity();
dvander@229
  1246
dvander@262
  1247
	HandleAccess sec;
dvander@262
  1248
	g_HandleSys.InitAccessDefaults(NULL, &sec);
dvander@220
  1249
dvander@262
  1250
	sec.access[HandleAccess_Delete] = HANDLE_RESTRICT_IDENTITY;
dvander@262
  1251
	sec.access[HandleAccess_Clone] = HANDLE_RESTRICT_IDENTITY;
dvander@262
  1252
dvander@262
  1253
	g_PluginType = g_HandleSys.CreateType("Plugin", this, 0, NULL, &sec, m_MyIdent, NULL);
dvander@229
  1254
	g_PluginIdent = g_ShareSys.CreateIdentType("PLUGIN");
dvander@220
  1255
}
dvander@220
  1256
dvander@220
  1257
void CPluginManager::OnSourceModShutdown()
dvander@220
  1258
{
dvander@298
  1259
	List<CPlugin *>::iterator iter;
dvander@298
  1260
	while ( (iter = m_plugins.begin()) != m_plugins.end() )
dvander@298
  1261
	{
dvander@298
  1262
		UnloadPlugin((*iter));
dvander@298
  1263
	}
dvander@298
  1264
dvander@229
  1265
	g_HandleSys.RemoveType(g_PluginType, m_MyIdent);
dvander@229
  1266
	g_ShareSys.DestroyIdentType(g_PluginIdent);
dvander@229
  1267
	g_ShareSys.DestroyIdentity(m_MyIdent);
dvander@220
  1268
}
dvander@220
  1269
dvander@220
  1270
void CPluginManager::OnHandleDestroy(HandleType_t type, void *object)
dvander@220
  1271
{
dvander@220
  1272
	/* We don't care about the internal object, actually */
dvander@220
  1273
}
dvander@233
  1274
dvander@233
  1275
void CPluginManager::RegisterNativesFromCore(sp_nativeinfo_t *natives)
dvander@233
  1276
{
dvander@233
  1277
	m_natives.push_back(natives);
dvander@233
  1278
}
dvander@247
  1279
dvander@247
  1280
IPlugin *CPluginManager::PluginFromHandle(Handle_t handle, HandleError *err)
dvander@247
  1281
{
dvander@247
  1282
	IPlugin *pPlugin;
dvander@247
  1283
	HandleError _err;
dvander@247
  1284
dvander@262
  1285
	HandleSecurity sec;
dvander@262
  1286
dvander@262
  1287
	sec.pOwner = NULL;
dvander@262
  1288
	sec.pIdentity = m_MyIdent;
dvander@262
  1289
dvander@262
  1290
	if ((_err=g_HandleSys.ReadHandle(handle, g_PluginType, &sec, (void **)&pPlugin)) != HandleError_None)
dvander@247
  1291
	{
dvander@247
  1292
		pPlugin = NULL;
dvander@247
  1293
	}
dvander@247
  1294
dvander@247
  1295
	if (err)
dvander@247
  1296
	{
dvander@247
  1297
		*err = _err;
dvander@247
  1298
	}
dvander@247
  1299
dvander@247
  1300
	return pPlugin;
dvander@247
  1301
}
faluco@290
  1302
faluco@290
  1303
CPlugin *CPluginManager::GetPluginByOrder(int num)
faluco@290
  1304
{
faluco@290
  1305
	if (num < 1 || num > (int)GetPluginCount())
faluco@290
  1306
	{
faluco@290
  1307
		return NULL;
faluco@290
  1308
	}
faluco@290
  1309
faluco@290
  1310
	CPlugin *pl;
faluco@290
  1311
	int id = 1;
faluco@290
  1312
faluco@290
  1313
	IPluginIterator *iter = GetPluginIterator();
faluco@290
  1314
	for (; iter->MorePlugins() && id<num; iter->NextPlugin(), id++) {}
faluco@290
  1315
faluco@290
  1316
	pl = (CPlugin *)(iter->GetPlugin());
faluco@290
  1317
	iter->Release();
faluco@290
  1318
faluco@290
  1319
	return pl;
dvander@298
  1320
}