core/systems/ForwardSys.cpp
author David Anderson <dvander@alliedmods.net>
Sun Nov 12 09:51:39 2006 +0000 (2006-11-12)
changeset 183 78488edd8873
parent 181 1e1570518051
child 186 eebc5de63141
permissions -rw-r--r--
rewrote forward API to use cached parameter pushing instead of immediate pushing
removed copy back cruft since it's no longer needed
removed PushCells() from API requirements, not needed
adjusted documentation and added TODO list to ForwardSys.cpp
various internal improvements
dvander@180
     1
#include <assert.h>
dvander@180
     2
#include "ForwardSys.h"
dvander@180
     3
#include "PluginSys.h"
dvander@180
     4
dvander@183
     5
/**
dvander@183
     6
 * Gensis turns to its source, reduction occurs stepwise although the essence is all one.
dvander@183
     7
 * End of line.  FTL system check.
dvander@183
     8
 *
dvander@183
     9
 * :TODO: Implement the manager.  ho ho ho
dvander@183
    10
 *
dvander@183
    11
 * :TODO: WHAT NEEDS TO BE TESTED IN THIS BEAST (X=done, -=TODO)
dvander@183
    12
 * NORMAL FUNCTIONS:
dvander@183
    13
 * X Push cells
dvander@183
    14
 * X Push cells byref (copyback tested = yes)
dvander@183
    15
 * - Push floats (copyback tested = ??)
dvander@183
    16
 * - Push floats byref (copyback tested = ??)
dvander@183
    17
 * - Push arrays  (copyback tested = ??)
dvander@183
    18
 * - Push strings (copyback tested = ??)
dvander@183
    19
 * VARARG FUNCTIONS:
dvander@183
    20
 * - Pushing no varargs
dvander@183
    21
 * - Push vararg cells (copyback should be verified to not happen = ??)
dvander@183
    22
 * - Push vararg cells byref (copyback tested = ??)
dvander@183
    23
 * - Push vararg floats (copyback should be verified to not happen = ??)
dvander@183
    24
 * - Push vararg floats byref (copyback tested = ??)
dvander@183
    25
 * - Push vararg arrays  (copyback tested = ??)
dvander@183
    26
 * - Push vararg strings (copyback tested = ??)
dvander@183
    27
 */
dvander@183
    28
dvander@180
    29
CForward *CForward::CreateForward(const char *name, ExecType et, unsigned int num_params, ParamType *types, va_list ap)
dvander@180
    30
{
dvander@180
    31
	ParamType _types[SP_MAX_EXEC_PARAMS];
dvander@180
    32
dvander@180
    33
	if (num_params > SP_MAX_EXEC_PARAMS)
dvander@180
    34
	{
dvander@180
    35
		return NULL;
dvander@180
    36
	}
dvander@180
    37
	
dvander@180
    38
	if (types == NULL && num_params)
dvander@180
    39
	{
dvander@180
    40
		for (unsigned int i=0; i<num_params; i++)
dvander@180
    41
		{
dvander@180
    42
			_types[i] = va_arg(ap, ParamType);
dvander@180
    43
			if (_types[i] == Param_VarArgs && (i != num_params - 1))
dvander@180
    44
			{
dvander@180
    45
				return NULL;
dvander@180
    46
			}
dvander@180
    47
		}
dvander@180
    48
		types = _types;
dvander@180
    49
	} else {
dvander@180
    50
		for (unsigned int i=0; i<num_params; i++)
dvander@180
    51
		{
dvander@180
    52
			if (types[i] == Param_VarArgs && (i != num_params - 1))
dvander@180
    53
			{
dvander@180
    54
				return NULL;
dvander@180
    55
			}
dvander@180
    56
		}
dvander@180
    57
	}
dvander@180
    58
dvander@180
    59
	/* First parameter can never be varargs */
dvander@180
    60
	if (types[0] == Param_VarArgs)
dvander@180
    61
	{
dvander@180
    62
		return NULL;
dvander@180
    63
	}
dvander@180
    64
dvander@180
    65
	CForward *pForward = new CForward;
dvander@180
    66
	pForward->m_curparam = 0;
dvander@180
    67
	pForward->m_ExecType = et;
dvander@180
    68
	snprintf(pForward->m_name, FORWARDS_NAME_MAX, "%s", name ? name : "");
dvander@180
    69
	
dvander@180
    70
	for (unsigned int i=0; i<num_params; i++)
dvander@180
    71
	{
dvander@180
    72
		pForward->m_types[i] = types[i];
dvander@180
    73
	}
dvander@180
    74
dvander@180
    75
	if (num_params && types[num_params-1] == Param_VarArgs)
dvander@180
    76
	{
dvander@183
    77
		pForward->m_varargs = num_params--;
dvander@180
    78
	} else {
dvander@180
    79
		pForward->m_varargs = false;
dvander@180
    80
	}
dvander@180
    81
dvander@180
    82
	pForward->m_numparams = num_params;
dvander@180
    83
	pForward->m_errstate = SP_ERROR_NONE;
dvander@180
    84
dvander@180
    85
	return pForward;
dvander@180
    86
}
dvander@180
    87
dvander@180
    88
int CForward::Execute(cell_t *result, IForwardFilter *filter)
dvander@180
    89
{
dvander@180
    90
	if (m_errstate)
dvander@180
    91
	{
dvander@180
    92
		int err = m_errstate;
dvander@180
    93
		Cancel();
dvander@180
    94
		return err;
dvander@180
    95
	}
dvander@180
    96
dvander@180
    97
	if (filter)
dvander@180
    98
	{
dvander@180
    99
		filter->OnExecuteBegin();
dvander@180
   100
	}
dvander@180
   101
dvander@180
   102
	FuncIter iter = m_functions.begin();
dvander@180
   103
	IPluginFunction *func;
dvander@180
   104
	cell_t cur_result = 0;
dvander@180
   105
	cell_t high_result = 0;
dvander@180
   106
	int err;
dvander@180
   107
	unsigned int failed=0, success=0;
dvander@180
   108
	unsigned int save_numcopy = 0;
dvander@183
   109
	unsigned int num_params = m_curparam;
dvander@183
   110
	FwdParamInfo temp_info[SP_MAX_EXEC_PARAMS];
dvander@183
   111
	FwdParamInfo *param;
dvander@183
   112
	ParamType type;
dvander@180
   113
dvander@183
   114
	/* Save local, reset */
dvander@183
   115
	memcpy(temp_info, m_params, sizeof(m_params));
dvander@183
   116
	m_curparam = 0;
dvander@183
   117
dvander@180
   118
	for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
dvander@180
   119
	{
dvander@180
   120
		func = (*iter);
dvander@183
   121
dvander@183
   122
		for (unsigned int i=0; i<num_params; i++)
dvander@180
   123
		{
dvander@183
   124
			param = &temp_info[i];
dvander@183
   125
			if (i >= m_numparams || m_types[i] == Param_Any)
dvander@183
   126
			{
dvander@183
   127
				type = param->pushedas;
dvander@183
   128
			} else {
dvander@183
   129
				type = m_types[i];
dvander@183
   130
			}
dvander@183
   131
			if ((i >= m_numparams) || (type & SP_PARAMFLAG_BYREF))
dvander@180
   132
			{
dvander@183
   133
				/* If we're byref or we're vararg, we always push everything by ref.
dvander@183
   134
				 * Even if they're byval, we must push them byref.
dvander@183
   135
				 */
dvander@183
   136
				if (type == Param_String) 
dvander@180
   137
				{
dvander@183
   138
					func->PushStringEx((char *)param->byref.orig_addr, param->byref.flags);
dvander@183
   139
				} else if (type == Param_Float || type == Param_Cell) {
dvander@183
   140
					func->PushCellByRef(&param->val, 0); 
dvander@183
   141
				} else {
dvander@183
   142
					func->PushArray(param->byref.orig_addr, param->byref.cells, NULL, param->byref.flags);
dvander@183
   143
					assert(type == Param_Array || type == Param_FloatByRef || type == Param_CellByRef);
dvander@180
   144
				}
dvander@183
   145
			} else {
dvander@183
   146
				/* If we're not byref or not vararg, our job is a bit easier. */
dvander@183
   147
				assert(type == Param_Cell || type == Param_Float);
dvander@183
   148
				func->PushCell(param->val);
dvander@180
   149
			}
dvander@180
   150
		}
dvander@183
   151
		
dvander@180
   152
		/* Call the function and deal with the return value.
dvander@180
   153
		 * :TODO: only pass reader if we know we have an array in the list
dvander@180
   154
		 */
dvander@183
   155
		if ((err=func->Execute(&cur_result)) != SP_ERROR_NONE)
dvander@180
   156
		{
dvander@180
   157
			bool handled = false;
dvander@180
   158
			if (filter)
dvander@180
   159
			{
dvander@180
   160
				handled = filter->OnErrorReport(this, func, err);
dvander@180
   161
			}
dvander@180
   162
			if (!handled)
dvander@180
   163
			{
dvander@180
   164
				/* :TODO: invoke global error reporting here */
dvander@180
   165
			}
dvander@180
   166
			failed++;
dvander@180
   167
		} else {
dvander@180
   168
			success++;
dvander@180
   169
			switch (m_ExecType)
dvander@180
   170
			{
dvander@180
   171
			case ET_Event:
dvander@180
   172
				{
dvander@180
   173
					if (cur_result > high_result)
dvander@180
   174
					{
dvander@180
   175
						high_result = cur_result;
dvander@180
   176
					}
dvander@180
   177
					break;
dvander@180
   178
				}
dvander@180
   179
			case ET_Hook:
dvander@180
   180
				{
dvander@180
   181
					if (cur_result > high_result)
dvander@180
   182
					{
dvander@180
   183
						high_result = cur_result;
dvander@180
   184
						if ((ResultType)high_result == Pl_Stop)
dvander@180
   185
						{
dvander@180
   186
							iter = m_functions.end();
dvander@180
   187
							break;
dvander@180
   188
						}
dvander@180
   189
					}
dvander@180
   190
					break;
dvander@180
   191
				}
dvander@180
   192
			case ET_Custom:
dvander@180
   193
				{
dvander@180
   194
					if (filter)
dvander@180
   195
					{
dvander@180
   196
						if (filter->OnFunctionReturn(this, func, &cur_result) == Pl_Stop)
dvander@180
   197
						{
dvander@180
   198
							iter = m_functions.end();
dvander@180
   199
						}
dvander@180
   200
					}
dvander@180
   201
					break;
dvander@180
   202
				}
dvander@180
   203
			}
dvander@180
   204
		}
dvander@180
   205
	}
dvander@180
   206
dvander@180
   207
	if (m_ExecType == ET_Event || m_ExecType == ET_Hook)
dvander@180
   208
	{
dvander@180
   209
		cur_result = high_result;
dvander@180
   210
	} else if (m_ExecType == ET_Ignore) {
dvander@180
   211
		cur_result = 0;
dvander@180
   212
	}
dvander@180
   213
dvander@180
   214
	*result = cur_result;
dvander@180
   215
dvander@180
   216
	if (filter)
dvander@180
   217
	{
dvander@180
   218
		filter->OnExecuteEnd(&cur_result, success, failed);
dvander@180
   219
	}
dvander@180
   220
dvander@180
   221
	return SP_ERROR_NONE;
dvander@180
   222
}
dvander@180
   223
dvander@180
   224
int CForward::PushCell(cell_t cell)
dvander@180
   225
{
dvander@180
   226
	if (m_curparam < m_numparams)
dvander@180
   227
	{
dvander@183
   228
		if (m_types[m_curparam] == Param_Any)
dvander@180
   229
		{
dvander@183
   230
			m_params[m_curparam].pushedas = Param_Cell;
dvander@183
   231
		} else if (m_types[m_curparam] != Param_Cell) {
dvander@180
   232
			return SetError(SP_ERROR_PARAM);
dvander@180
   233
		}
dvander@180
   234
	} else {
dvander@180
   235
		if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
dvander@180
   236
		{
dvander@180
   237
			return SetError(SP_ERROR_PARAMS_MAX);
dvander@180
   238
		}
dvander@183
   239
		m_params[m_curparam].pushedas = Param_Cell;
dvander@180
   240
	}
dvander@180
   241
dvander@183
   242
	m_params[m_curparam++].val = cell;
dvander@180
   243
dvander@180
   244
	return SP_ERROR_NONE;
dvander@180
   245
}
dvander@180
   246
dvander@180
   247
int CForward::PushFloat(float number)
dvander@180
   248
{
dvander@180
   249
	if (m_curparam < m_numparams)
dvander@180
   250
	{
dvander@183
   251
		if (m_types[m_curparam] == Param_Any)
dvander@180
   252
		{
dvander@183
   253
			m_params[m_curparam].pushedas = Param_Float;
dvander@183
   254
		} else if (m_types[m_curparam] != Param_Float) {
dvander@180
   255
			return SetError(SP_ERROR_PARAM);
dvander@180
   256
		}
dvander@180
   257
	} else {
dvander@180
   258
		if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
dvander@180
   259
		{
dvander@180
   260
			return SetError(SP_ERROR_PARAMS_MAX);
dvander@180
   261
		}
dvander@183
   262
		m_params[m_curparam].pushedas = Param_Float;
dvander@180
   263
	}
dvander@180
   264
dvander@183
   265
	m_params[m_curparam++].val = *(cell_t *)&number;
dvander@180
   266
dvander@180
   267
	return SP_ERROR_NONE;
dvander@180
   268
}
dvander@180
   269
dvander@180
   270
int CForward::PushCellByRef(cell_t *cell, int flags)
dvander@180
   271
{
dvander@180
   272
	if (m_curparam < m_numparams)
dvander@180
   273
	{
dvander@180
   274
		if (m_types[m_curparam] != Param_CellByRef && m_types[m_curparam] != Param_Any)
dvander@180
   275
		{
dvander@180
   276
			return SetError(SP_ERROR_PARAM);
dvander@180
   277
		}
dvander@180
   278
	} else {
dvander@180
   279
		if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
dvander@180
   280
		{
dvander@180
   281
			return SetError(SP_ERROR_PARAMS_MAX);
dvander@180
   282
		}
dvander@180
   283
	}
dvander@180
   284
dvander@183
   285
	_Int_PushArray(cell, 1, flags);
dvander@180
   286
	m_curparam++;
dvander@180
   287
dvander@180
   288
	return SP_ERROR_NONE;
dvander@180
   289
}
dvander@180
   290
dvander@180
   291
int CForward::PushFloatByRef(float *num, int flags)
dvander@180
   292
{
dvander@180
   293
	if (m_curparam < m_numparams)
dvander@180
   294
	{
dvander@180
   295
		if (m_types[m_curparam] != Param_FloatByRef && m_types[m_curparam] != Param_Any)
dvander@180
   296
		{
dvander@180
   297
			return SetError(SP_ERROR_PARAM);
dvander@180
   298
		}
dvander@180
   299
	} else {
dvander@180
   300
		if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
dvander@180
   301
		{
dvander@180
   302
			return SetError(SP_ERROR_PARAMS_MAX);
dvander@180
   303
		}
dvander@180
   304
	}
dvander@180
   305
dvander@183
   306
	_Int_PushArray((cell_t *)num, 1, flags);
dvander@180
   307
	m_curparam++;
dvander@180
   308
dvander@180
   309
	return SP_ERROR_NONE;
dvander@180
   310
}
dvander@180
   311
dvander@180
   312
void CForward::_Int_PushArray(cell_t *inarray, unsigned int cells, int flags)
dvander@180
   313
{
dvander@183
   314
	m_params[m_curparam].byref.cells = cells;
dvander@183
   315
	m_params[m_curparam].byref.flags = flags;
dvander@183
   316
	m_params[m_curparam].byref.orig_addr = inarray;
dvander@180
   317
}
dvander@180
   318
dvander@180
   319
int CForward::PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr, int flags)
dvander@180
   320
{
dvander@180
   321
	/* We don't allow this here */
dvander@180
   322
	if (!inarray)
dvander@180
   323
	{
dvander@180
   324
		return SetError(SP_ERROR_PARAM);
dvander@180
   325
	}
dvander@180
   326
dvander@180
   327
	if (m_curparam < m_numparams)
dvander@180
   328
	{
dvander@183
   329
		if (m_types[m_curparam] == Param_Any)
dvander@180
   330
		{
dvander@183
   331
			m_params[m_curparam].pushedas = Param_Array;
dvander@183
   332
		} else if (m_types[m_curparam] != Param_Array) {
dvander@180
   333
			return SetError(SP_ERROR_PARAM);
dvander@180
   334
		}
dvander@180
   335
	} else {
dvander@180
   336
		if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
dvander@180
   337
		{
dvander@180
   338
			return SetError(SP_ERROR_PARAMS_MAX);
dvander@180
   339
		}
dvander@183
   340
		m_params[m_curparam].pushedas = Param_Array;
dvander@180
   341
	}
dvander@180
   342
dvander@180
   343
	if (phys_addr)
dvander@180
   344
	{
dvander@180
   345
		*phys_addr = NULL;
dvander@180
   346
	}
dvander@180
   347
dvander@180
   348
	_Int_PushArray(inarray, cells, flags);
dvander@180
   349
dvander@180
   350
	m_curparam++;
dvander@180
   351
dvander@180
   352
	return SP_ERROR_NONE;
dvander@180
   353
}
dvander@180
   354
dvander@180
   355
int CForward::PushString(const char *string)
dvander@180
   356
{
dvander@180
   357
	if (m_curparam < m_numparams)
dvander@180
   358
	{
dvander@183
   359
		if (m_types[m_curparam] == Param_Any)
dvander@180
   360
		{
dvander@183
   361
			m_params[m_curparam].pushedas = Param_String;
dvander@183
   362
		} else if (m_types[m_curparam] == Param_String) {
dvander@180
   363
			return SetError(SP_ERROR_PARAM);
dvander@180
   364
		}
dvander@180
   365
	} else {
dvander@180
   366
		if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
dvander@180
   367
		{
dvander@180
   368
			return SetError(SP_ERROR_PARAMS_MAX);
dvander@180
   369
		}
dvander@183
   370
		m_params[m_curparam].pushedas = Param_String;
dvander@180
   371
	}
dvander@180
   372
dvander@183
   373
	_Int_PushArray((cell_t *)string, 0, 0);
dvander@180
   374
	m_curparam++;
dvander@180
   375
dvander@180
   376
	return SP_ERROR_NONE;
dvander@180
   377
}
dvander@180
   378
dvander@183
   379
int CForward::PushStringEx(char *string, int flags)
dvander@180
   380
{
dvander@180
   381
	if (m_curparam < m_numparams)
dvander@180
   382
	{
dvander@183
   383
		if (m_types[m_curparam] == Param_Any)
dvander@180
   384
		{
dvander@183
   385
			m_params[m_curparam].pushedas = Param_String;
dvander@183
   386
		} else if (m_types[m_curparam] == Param_String) {
dvander@180
   387
			return SetError(SP_ERROR_PARAM);
dvander@180
   388
		}
dvander@180
   389
	} else {
dvander@180
   390
		if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
dvander@180
   391
		{
dvander@180
   392
			return SetError(SP_ERROR_PARAMS_MAX);
dvander@180
   393
		}
dvander@183
   394
		m_params[m_curparam].pushedas = Param_String;
dvander@180
   395
	}
dvander@180
   396
dvander@183
   397
	_Int_PushArray((cell_t *)string, 0, flags);
dvander@180
   398
	m_curparam++;
dvander@180
   399
dvander@180
   400
	return SP_ERROR_NONE;
dvander@180
   401
}
dvander@180
   402
dvander@180
   403
void CForward::Cancel()
dvander@180
   404
{
dvander@180
   405
	if (!m_curparam)
dvander@180
   406
	{
dvander@180
   407
		return;
dvander@180
   408
	}
dvander@180
   409
dvander@183
   410
	m_curparam = 0;
dvander@180
   411
	m_errstate = SP_ERROR_NONE;
dvander@180
   412
}
dvander@180
   413
dvander@180
   414
bool CForward::AddFunction(sp_context_t *ctx, funcid_t index)
dvander@180
   415
{
dvander@180
   416
	IPlugin *pPlugin = g_PluginMngr.FindPluginByContext(ctx);
dvander@180
   417
	if (!pPlugin)
dvander@180
   418
	{
dvander@180
   419
		return false;
dvander@180
   420
	}
dvander@180
   421
dvander@180
   422
	IPluginFunction *pFunc = pPlugin->GetFunctionById(index);
dvander@180
   423
	if (!pFunc)
dvander@180
   424
	{
dvander@180
   425
		return false;
dvander@180
   426
	}
dvander@180
   427
dvander@180
   428
	return AddFunction(pFunc);
dvander@180
   429
}
dvander@180
   430
dvander@180
   431
bool CForward::RemoveFunction(IPluginFunction *func)
dvander@180
   432
{
dvander@180
   433
	bool found = false;
dvander@180
   434
	FuncIter iter;
dvander@180
   435
	IPluginFunction *pNext = NULL;
dvander@180
   436
dvander@180
   437
	for (iter=m_functions.begin(); iter!=m_functions.end();)
dvander@180
   438
	{
dvander@180
   439
		if ((*iter) == func)
dvander@180
   440
		{
dvander@180
   441
			found = true;
dvander@180
   442
			/* If this iterator is being used, swap in a new one !*/
dvander@180
   443
			iter = m_functions.erase(iter);
dvander@180
   444
		} else {
dvander@180
   445
			iter++;
dvander@180
   446
		}
dvander@180
   447
	}
dvander@180
   448
dvander@180
   449
	/* Cancel a call, if any */
dvander@183
   450
	if (found || m_curparam)
dvander@180
   451
	{
dvander@180
   452
		func->Cancel();
dvander@180
   453
	}
dvander@180
   454
dvander@180
   455
	return found;
dvander@180
   456
}
dvander@180
   457
dvander@180
   458
unsigned int CForward::RemoveFunctionsOfPlugin(IPlugin *plugin)
dvander@180
   459
{
dvander@180
   460
	FuncIter iter;
dvander@180
   461
	IPluginFunction *func;
dvander@180
   462
	unsigned int removed = 0;
dvander@180
   463
	for (iter=m_functions.begin(); iter!=m_functions.end();)
dvander@180
   464
	{
dvander@180
   465
		func = (*iter);
dvander@180
   466
		if (func->GetParentPlugin() == plugin)
dvander@180
   467
		{
dvander@180
   468
			iter = m_functions.erase(iter);
dvander@180
   469
			removed++;
dvander@180
   470
		} else {
dvander@180
   471
			iter++;
dvander@180
   472
		}
dvander@180
   473
	}
dvander@180
   474
dvander@180
   475
	return removed;
dvander@180
   476
}
dvander@180
   477
dvander@180
   478
bool CForward::AddFunction(IPluginFunction *func)
dvander@180
   479
{
dvander@180
   480
	if (m_curparam)
dvander@180
   481
	{
dvander@180
   482
		return false;
dvander@180
   483
	}
dvander@180
   484
dvander@183
   485
	//:TODO: eventually we will tell the plugin we're using it
dvander@183
   486
	m_functions.push_back(func);
dvander@180
   487
dvander@180
   488
	return true;
dvander@180
   489
}
dvander@180
   490
dvander@180
   491
const char *CForward::GetForwardName()
dvander@180
   492
{
dvander@180
   493
	return m_name;
dvander@180
   494
}
dvander@180
   495
dvander@180
   496
unsigned int CForward::GetFunctionCount()
dvander@180
   497
{
dvander@180
   498
	return m_functions.size();
dvander@180
   499
}
dvander@180
   500
dvander@180
   501
ExecType CForward::GetExecType()
dvander@180
   502
{
dvander@180
   503
	return m_ExecType;
dvander@180
   504
}