Example #1
0
/* bool: procread(line[], size=sizeof line, bool:striplf=false, bool:packed=false)
 */
static cell AMX_NATIVE_CALL n_procread(AMX *amx, const cell *params)
{
  TCHAR line[128];
  cell *cptr;
  unsigned long num;
  int index;

  index=0;
  #if defined __WIN32__ || defined _WIN32 || defined WIN32
    if (read_stdout==NULL)
      return 0;
    do {
      if (!ReadFile(read_stdout,line+index,1,&num,NULL))
        break;
      index++;
    } while (index<sizeof(line)/sizeof(line[0])-1 && line[index-1]!=__T('\n'));
  #elif defined __LINUX__ || defined __FreeBSD__ || defined __OpenBSD__ || defined __APPLE__
    if (pipe_from[0]<0)
      return 0;
    do {
      if (read(pipe_from[0],line+index,1)<0)
        break;
      index++;
    } while (index<sizeof(line)/sizeof(line[0])-1 && line[index-1]!=__T('\n'));
  #endif

  if (params[3])
    while (index>0 && (line[index-1]==__T('\r') || line[index-1]==__T('\n')))
      index--;
  line[index]=__T('\0');

  cptr=amx_Address(amx,params[1]);
  amx_SetString(cptr,line,params[4],sizeof(TCHAR)>1,params[2]);
  return 1;
}
Example #2
0
File: amxargs.c Project: z80/mapper
/* bool: argindex(index, value[], maxlength=sizeof value, bool:pack=false)
 * returns true if the option was found and false on error or if the parameter "index" is out of range
 */
static cell AMX_NATIVE_CALL n_argindex(AMX *amx, const cell *params)
{
    const TCHAR *cmdline = rawcmdline();
    const TCHAR *option;
    int length, max;
    TCHAR *str;
    cell *cptr;

    max = (int)params[3];
    if (max <= 0)
        return 0;
    cptr = amx_Address(amx, params[2]);

    if ((option = tokenize(cmdline, params[1], &length)) == NULL) {
        /* option not found, return an empty string */
        *cptr = 0;
        return 0;
    } /* if */

    if (params[4])
        max *= sizeof(cell);
    if (max > length + 1)
        max = length + 1;
    str = (TCHAR *)alloca(max*sizeof(TCHAR));
    if (str == NULL) {
        amx_RaiseError(amx, AMX_ERR_NATIVE);
        return 0;
    } /* if */
    memcpy(str, option, (max - 1) * sizeof(TCHAR));
    str[max - 1] = __T('\0');
    amx_SetString(cptr, (char*)str, (int)params[4], sizeof(TCHAR)>1, max);

    return 1;
}
Example #3
0
// native mysql_fetch_field_string(resultId, field[], buffer[], bufferSize = sizeof(buffer));
static cell AMX_NATIVE_CALL n_mysql_fetch_field_string(AMX* amx, cell* params) {
	CHECK_PARAMS(4);

	ResultEntry* entry = resultController->at(static_cast<unsigned int>(params[1]));
	if (entry == nullptr)
		return 0;

	char* fieldName;
	amx_StrParam(amx, params[2], fieldName);

	if (!fieldName || !strlen(fieldName))
		return 0;

	cell* bufferCell;
	amx_GetAddr(amx, params[3], &bufferCell);

	ColumnInfo::ColumnType fieldType = ColumnInfo::UnknownColumnType;
	const RowInfo::FieldValue* fieldValue = entry->fetch_field(fieldName, fieldType);

	if (fieldType != ColumnInfo::StringColumnType) {
		DebugPrinter::Print("[MySQL] Tried to get column \"%s\" with the wrong data-type, ignored.", fieldName);
		return 0;
	}

	amx_SetString(bufferCell, fieldValue->string_val, 0, 0, static_cast<size_t>(params[4]));
	return strlen(fieldValue->string_val);
}
Example #4
0
/** pawnLanguageString
* native LanguageString(line, returnstring[], maxlength=sizeof returnstring);
*
*/
static cell pawnLanguageString(AMX *amx, const cell *params)
{
	std::string dialog_string;
	cell * cptr;
	cptr = amx_Address(amx, params[2]);

	dialog_string = lux::engine->GetString(params[1]);
	return amx_SetString(cptr, dialog_string.c_str(), 1, 0, params[3]);
}
int main(int argc,char *argv[])
{
  extern int amx_ConsoleInit(AMX *amx);
  extern int amx_ConsoleCleanup(AMX *amx);
  extern int amx_CoreInit(AMX *amx);
  extern int amx_CoredCleanp(AMX *amx);

  size_t memsize;
  void *program;
  AMX amx;
  int index, err;
  cell amx_addr, *phys_addr;
  char output[128];

  if (argc != 4)
    PrintUsage(argv[0]);
  if ((memsize = aux_ProgramSize(argv[1])) == 0)
    PrintUsage(argv[0]);

  program = malloc(memsize);
  if (program == NULL)
    ErrorExit(NULL, AMX_ERR_MEMORY);

  err = aux_LoadProgram(&amx, argv[1], program);
  if (err)
    ErrorExit(&amx, err);

  amx_ConsoleInit(amx);
  err = amx_CoreInit(amx);
  if (err)
    ErrorExit(&amx, err);

  err = amx_FindPublic(&amx, argv[2], &index);
  if (err)
    ErrorExit(&amx, err);

  err = amx_Allot(&amx, strlen(argv[3]) + 1, &amx_addr, &phys_addr);
  if (err)
    ErrorExit(&amx, err);
  amx_SetString(phys_addr, argv[3], 0);

  err = amx_Exec(&amx, NULL, index, 1, amx_addr);
  if (err)
    ErrorExit(&amx, err);

  amx_GetString(output, phys_addr);
  amx_Release(&amx, amx_addr);
  printf("%s returns %s\n", argv[1], output);

  amx_ConsoleCleanup(&amx);
  amx_CoreCleanup(&amx);
  amx_Cleanup(&amx);
  free(program);
  return 0;
}
cell AMX_NATIVE_CALL Natives::GetDynamicVehicleNumberPlate(AMX *amx, cell *params)
{
	CHECK_PARAMS(3, "GetDynamicVehicleNumberPlate");
	boost::unordered_map<int, Item::SharedVehicle>::iterator v = core->getData()->vehicles.find(static_cast<int>(params[1]));
	if (v != core->getData()->vehicles.end())
	{
		cell *text = NULL;
		amx_GetAddr(amx, params[2], &text);
		amx_SetString(text, v->second->numberplate.c_str(), 0, 0, static_cast<size_t>(params[3]));
		return 1;
	}
	return 0;
}
Example #7
0
error_t
	CellMemory::
	SetNextString(char const * val, size_t idx, bool pack)
{
	if (!idx) ++m_cur;
	FAIL(m_cur <= m_count, ERROR_OUT_OF_VARIABLES);
	// 1-indexed array.
	cell *
		addr;
	amx_GetAddr(m_amx, m_params[m_cur], &addr);
	amx_SetString(addr + idx, val, pack, false, strlen(val));
	return OK;
}
cell AMX_NATIVE_CALL Natives::GetDynamic3DTextLabelText(AMX *amx, cell *params)
{
	CHECK_PARAMS(3, "GetDynamic3DTextLabelText");
	boost::unordered_map<int, Item::SharedTextLabel>::iterator t = core->getData()->textLabels.find(static_cast<int>(params[1]));
	if (t != core->getData()->textLabels.end())
	{
		cell *text = NULL;
		amx_GetAddr(amx, params[2], &text);
		amx_SetString(text, t->second->text.c_str(), 0, 0, static_cast<size_t>(params[3]));
		return 1;
	}
	return 0;
}
cell AMX_NATIVE_CALL pawn_regex_replace(AMX* amx, cell* params)
{
	regex_t* RegExpr;
	const char *rexp = NULL, *string = NULL, *replace = NULL;
	cell* addr = NULL;
	amx_GetAddr(amx, params[1], &addr);
	amx_StrParam(amx, params[1], string);
	amx_StrParam(amx, params[2], rexp);
	amx_StrParam(amx, params[3], replace);
	if(string && rexp)
	{
		int r=NULL;
		UChar* pattern = (UChar* )rexp;
		OnigErrorInfo einfo;
		r = onig_new(&RegExpr, pattern, pattern + strlen((char* )pattern), ONIG_OPTION_DEFAULT, ONIG_ENCODING_ASCII, ONIG_SYNTAX_PERL, &einfo);
		//logprintf("[REGEX DEBUG]: rexp %s",pattern);
		if(r != ONIG_NORMAL)
		{
			UChar s[ONIG_MAX_ERROR_MESSAGE_LEN];
			onig_error_code_to_str(s, r, &einfo);
			logprintf("[REGEX ERROR]: %s", s);
			onig_free(RegExpr);
			return -1;
		}
		UChar* str = (UChar* )string;
		OnigRegion *region;
		region = onig_region_new();
		r = onig_search(RegExpr, str, str+strlen((char*) str), str, str+strlen((char*) str), region, ONIG_OPTION_NONE);
		if(r>=0)
		{
			std::string asd = std::string((char*)str);
			asd.replace(asd.begin()+r, asd.begin()+region->end[region->num_regs-1], replace);
			amx_SetString(addr, asd.c_str(), 0, 0, params[1]);
		}
		else if(r<ONIG_MISMATCH)
		{
			UChar s[ONIG_MAX_ERROR_MESSAGE_LEN];
			onig_error_code_to_str(s, r);
			logprintf("[REGEX ERROR]: %s\n", s);
			onig_region_free(region, 1);
			onig_free(RegExpr);
			return -1;
		}
		//logprintf("[REGEX DEBUG]: string %s",str);
		onig_region_free(region, 1);
		onig_free(RegExpr);
		//logprintf("[REGEX DEBUG]: return %d",r);
		return r;
	}
    return -1337;
}
// native GetNativeBacktrace(string[], size = sizeof(string));
cell AMX_NATIVE_CALL GetNativeBacktrace(AMX *amx, cell *params) {
  cell string = params[1];
  cell size = params[2];

  cell *string_ptr;
  if (amx_GetAddr(amx, string, &string_ptr) == AMX_ERR_NONE) {
    std::stringstream stream;
    CrashDetect::PrintNativeBacktrace(stream, 0);
    return amx_SetString(string_ptr, stream.str().c_str(),
                         0, 0, size) == AMX_ERR_NONE;
  }

  return 0;
}
Example #11
0
cell AMX_NATIVE_CALL Dotnet_ReadStringFromPacket(AMX * amx, cell * params)
{
	cell *pPack, *pStr;//, *pLen;
	amx_GetAddr(amx,params[1],&pPack);
	amx_GetAddr(amx,params[2],&pStr);
	//amx_GetAddr(amx,params[3],&pLen);
	Packet* pack = (Packet*)*pPack;
	if (pack == NULL) return 0;
	
	int strlen = pack->ReadUShort();
	pack->pos -= 2;
	amx_SetString(pStr, (char*)pack->pos, 0, 0, strlen);
	pack->ReadString(NULL,0);
	return strlen;
}
Example #12
0
/* strtoarray(dest[], size = sizeof dest, String:source, bool:packed = false) */
static cell AMX_NATIVE_CALL n_bstrtoarray(AMX *amx,cell *params)
{
  char *cstr = bstr2cstr((const bstring)params[3], '#');
  int length = strlen(cstr) + 1;
  cell *cellptr;

  if (params[4])
    length *= sizeof(cell);
  if (params[2] >= length) {
    amx_GetAddr(amx, params[1], &cellptr);
    amx_SetString(cellptr, cstr, params[4], 0);
  } /* if */
  free(cstr);
  return 0;
}
Example #13
0
cell AMX_NATIVE_CALL Natives::CTime_ctime(AMX *pAMX, cell *iParams)
{
	CHECK_PARAMS(3, "ctime");

	cell
		*iPhysAddr
	;
	time_t
		tTime = (time_t)iParams[1]
	;
	amx_GetAddr(pAMX, iParams[2], &iPhysAddr);
	amx_SetString(iPhysAddr, ctime(&tTime), 0, 0, iParams[3]);

	return 1;
}
Example #14
0
void COrm::Variable::SetValue(const char *val)
{
	switch (m_Type)
	{
	case COrm::Variable::Type::INT:
		ConvertStrToData(val, (*m_VariableAddr));
		break;
	case COrm::Variable::Type::FLOAT: {
		float dest = 0.0f;
		if (ConvertStrToData(val, dest))
			(*m_VariableAddr) = amx_ftoc(dest);
		} break;
	case COrm::Variable::Type::STRING:
		amx_SetString(m_VariableAddr, 
			val != nullptr ? val : "NULL", 0, 0, m_VarMaxLen);
		break;
	}
}
Example #15
0
/* bool: argstr(index=0, const option[]="", value[]="", maxlength=sizeof value, bool:pack=false)
 * returns true if the option was found and false otherwise
 */
static cell AMX_NATIVE_CALL n_argstr(AMX *amx, const cell *params)
{
  const TCHAR *option, *key;
  int length, max;
  TCHAR *str;
  cell *cptr;

  max = (int)params[4];
  if (max <= 0)
    return 0;
  amx_StrParam(amx, params[2], key);
  amx_GetAddr(amx, params[3], &cptr);
  if (cptr == NULL) {
    amx_RaiseError(amx, AMX_ERR_NATIVE);
    return 0;
  } /* if */

  option = matcharg(key, (int)params[1], &length);
  if (option == NULL)
    return 0;           /* option not found */

  /* check whether we must write the value of the option at all; in case the
   * size is one cell and that cell is already zero, we do not write anything
   * back
   */
  assert(params[4] > 0);
  if (params[4] > 1 || *cptr != 0) {
    if (params[5])
      max *= sizeof(cell);
    if (max > length + 1)
      max = length + 1;
    str = (TCHAR *)alloca(max*sizeof(TCHAR));
    if (str == NULL) {
      amx_RaiseError(amx, AMX_ERR_NATIVE);
      return 0;
    } /* if */
    memcpy(str, option, (max - 1) * sizeof(TCHAR));
    str[max - 1] = __T('\0');
    amx_SetString(cptr, (char*)str, (int)params[5], sizeof(TCHAR)>1, max);
  } /* if */

  return 1;
}
Example #16
0
cell AMX_NATIVE_CALL Natives::CTime_asctime(AMX *pAMX, cell *iParams)
{
	CHECK_PARAMS(3, "asctime");

	cell
		*iPhysAddr
	;
	amx_GetAddr(pAMX, iParams[1], &iPhysAddr);

	tm
		tmPtr
	;
	g_CTime->SetTimePointer(&tmPtr, iPhysAddr);

	amx_GetAddr(pAMX, iParams[2], &iPhysAddr);
	amx_SetString(iPhysAddr, asctime(&tmPtr), 0, 0, iParams[3]);

	return 1;
}
Example #17
0
int sampgdk_fakeamx_push_string(const char *src, int *size, cell *address) {
  int src_size;
  int error;

  assert(address != NULL);
  assert(src != NULL);

  src_size = (int)strlen(src) + 1;
  if ((error = sampgdk_fakeamx_push(src_size, address)) < 0) {
    return error;
  }

  amx_SetString((cell *)sampgdk_array_get(&global.heap,
                *address / sizeof(cell)), src, 0, 0, src_size);

  if (size != NULL) {
    *size = src_size;
  }

  return 0;
}
cell AMX_NATIVE_CALL pawn_regex_exreplace(AMX* amx, cell* params)
{
	const char *string = NULL, *replace = NULL;
	cell* addr = NULL;
	amx_GetAddr(amx, params[1], &addr);
	amx_StrParam(amx, params[1], string);
	amx_StrParam(amx, params[3], replace);
	if(string)
	{
		int id=(int)params[2];
		if(id>=0 && id<TotalExpressions)
		{
			int r=NULL;
			UChar* str = (UChar* )string;
			onig_region_clear(rexpression[id].zreg);
			r = onig_search(rexpression[id].RegExpr, str, str+strlen(string), str, str+strlen(string), rexpression[id].zreg, ONIG_OPTION_NONE);
			if(r>=0)
			{
				std::string asd = std::string(string);
				asd.replace(asd.begin()+r, asd.begin()+rexpression[id].zreg->end[rexpression[id].zreg->num_regs-1], replace);
				amx_SetString(addr, asd.c_str(), 0, 0, params[1]);
			}
			else if(r<ONIG_MISMATCH)
			{
				UChar s[ONIG_MAX_ERROR_MESSAGE_LEN];
				onig_error_code_to_str(s, r);
				logprintf("[REGEX ERROR]: %s\n", s);
				return -1;
			}
			return r;
		}
		logprintf("[REGEX ERROR]: Call regex_exreplace with undefined parameter at index %d", id);
		return -1;
	}
    return -1337;
}
Example #19
0
cell AMX_NATIVE_CALL Natives::CTime_strftime(AMX *pAMX, cell *iParams)
{
	CHECK_PARAMS(4, "strftime");

	cell
		*iPhysAddr
	;
	amx_GetAddr(pAMX, iParams[4], &iPhysAddr);

	tm
		tmPtr
	;
	g_CTime->SetTimePointer(&tmPtr, iPhysAddr);

	int
		iSize = iParams[2]
	;
	char
		*szFormat = new char[iSize]
	;
	amx_GetAddr(pAMX, iParams[3], &iPhysAddr);
	amx_GetString(szFormat, iPhysAddr, 0, iSize);

	char
		*szBuf = new char[iSize]
	;
	strftime(szBuf, iSize, szFormat, &tmPtr);
	
	amx_GetAddr(pAMX, iParams[1], &iPhysAddr);
	amx_SetString(iPhysAddr, szBuf, 0, 0, iParams[2]);

	delete szFormat;
	delete szBuf;

	return 1;
}
uint32_t CScriptTimers::NewEx(char* _scriptName, uint32_t _interval, uint32_t _repeat, cell* _params, AMX* pAMX)
{
	timerCount++;

	timerData* _timer = new timerData;

	strncpy(_timer->funcName, _scriptName, 255);
	_timer->totalTime = _interval;
	_timer->remainingTime = _interval;
	_timer->timerRepeat = _repeat;
	_timer->timerKilled = 0;
	_timer->timerAMX = pAMX;
	
	cell amx_addr[256];
	
	char* szParamList;
	amx_StrParam(pAMX, _params[4], szParamList);
	int j, numstr, iOff = 5;
	if (szParamList == NULL) j = 0;
	else j = strlen(szParamList);
	numstr = 0;
	while (j)
	{
		j--;
		cell *paddr = NULL;
		if (*(szParamList + j) == 'a')
		{
			int numcells = *get_amxaddr(pAMX, _params[j + iOff + 1]);
			if (amx_Allot(pAMX, numcells, &amx_addr[numstr], &paddr) == AMX_ERR_NONE)
			{
				memcpy(paddr, get_amxaddr(pAMX, _params[j + iOff]), numcells * sizeof (cell));
				numstr++;
			}
		}
		else if (*(szParamList + j) == 's')
		{
			char* szParamText;
			amx_StrParam(pAMX, _params[j + iOff], szParamText);
			if (szParamText != NULL && strlen(szParamText) > 0)
			{
				int numcells = strlen(szParamText) + 1;
				if (amx_Allot(pAMX, numcells, &amx_addr[numstr], &paddr) == AMX_ERR_NONE)
				{
					amx_SetString(paddr, szParamText, 0, 0, UNLIMITED);
					numstr++;
				}
			}
			else
			{
				*szParamText = 1;
				*(szParamText + 1) = 0;
				if (amx_Allot(pAMX, 1, &amx_addr[numstr], &paddr) == AMX_ERR_NONE)
				{
					amx_SetString(paddr, szParamText, 0, 0, UNLIMITED);
					numstr++;
				}
			}
		}
		else
		{
			amx_addr[numstr] = *get_amxaddr(pAMX, _params[j + iOff]);
			numstr++;
		}
	}
	void* mem = NULL;
	if (numstr)
	{
		mem = malloc(numstr * sizeof (cell));
		memcpy(mem, &amx_addr, numstr * sizeof (cell));
		_timer->timerParams = mem;
	}
	else
	{
		_timer->timerParams = NULL;
	}
	_timer->paramCount = numstr;
	
	timersMap.insert(std::pair<uint32_t, timerData*>(timerCount, _timer));
	return timerCount;
}
Example #21
0
// native sscanf(const data[], const format[], (Float,_}:...);
static cell AMX_NATIVE_CALL
	n_sscanf(AMX * amx, cell * params)
{
	if (g_iTrueMax == 0)
	{
		logprintf("sscanf error: System not initialised.");
		return SSCANF_FAIL_RETURN;
	}
	// Friendly note, the most complex set of specifier additions is:
	// 
	//  A<i>(10, 11)[5]
	// 
	// In that exact order - type, default, size.  It's very opposite to how
	// it's done in code, where you would do the eqivalent to:
	// 
	//  <i>[5] = {10, 11}
	// 
	// But this method is vastly simpler to parse in this context!  Technically
	// you can, due to legacy support for 'p', do:
	// 
	//  Ai(10, 11)[5]
	// 
	// But you will get an sscanf warning, and I may remove that ability from
	// the start - that will mean a new function, but an easy to write one.
	// In fact the most complex will probably be something like:
	// 
	//  E<ifs[32]s[8]d>(10, 12.3, Hello there, Hi, 42)
	// 
	// Get the number of parameters passed.  We add one as the indexes are out
	// by one (OBOE - Out By One Error) due to params[0] being the parameter
	// count, not an actual parameter.
	const int
		paramCount = ((int)params[0] / 4) + 1;
	// Could add a check for only 3 parameters here - I can't think of a time
	// when you would not want any return values at all, but that doesn't mean
	// they don't exist - you could just want to check but not save the format.
	// Update - that is now a possibility with the '{...}' specifiers.
	if (paramCount < (2 + 1))
	{
		logprintf("sscanf error: Missing required parameters.");
		return SSCANF_FAIL_RETURN;
	}
	//else if (paramCount == (2 + 1))
	//{
		// Only have an input and a specifier - better hope the whole specifier
		// is quite (i.e. enclosed in '{...}').
	//}
	// Set up function wide values.
	// Get and check the main data.
	// Pointer to the current input data.
	char *
		string;
	STR_PARAM(amx, params[1], string);
	// Pointer to the current format specifier.
	char *
		format;
	STR_PARAM(amx, params[2], format);
	// Check for CallRemoteFunction style null strings and correct.
	if (string[0] == '\1' && string[1] == '\0')
	{
		string[0] = '\0';
	}
	// Current parameter to save data to.
	int
		paramPos = 3;
	cell *
		cptr;
	InitialiseDelimiter();
	// Skip leading space.
	SkipWhitespace(&string);
	bool
		doSave;
	// Code for the rare cases where the WHOLE format is quiet.
	if (*format == '{')
	{
		++format;
		doSave = false;
	}
	else
	{
		doSave = true;
	}
	// Now do the main loop as long as there are variables to store the data in
	// and input string remaining to get the data from.
	while (*string && (paramPos < paramCount || !doSave))
	{
		if (!*format)
		{
			// End of the format string - if we're here we've got all the
			// parameters but there is extra string or variables, which may
			// indicate their code needs fixing, for example:
			// sscanf(data, "ii", var0, var1, var3, var4);
			// There is only two format specifiers, but four returns.  This may
			// also be reached if there is too much input data, but that is
			// considered OK as that is likely a user's fault.
			if (paramPos < paramCount)
			{
				logprintf("sscanf warning: Format specifier does not match parameter count.");
			}
			if (!doSave)
			{
				// Started a quiet section but never explicitly ended it.
				logprintf("sscanf warning: Unclosed quiet section.");
			}
			return SSCANF_TRUE_RETURN;
		}
		else if (IsWhitespace(*format))
		{
			++format;
		}
		else
		{
			switch (*format++)
			{
				case 'L':
					DX(bool, L)
					// FALLTHROUGH
				case 'l':
					DOV(bool, L)
					break;
				case 'B':
					DX(int, B)
					// FALLTHROUGH
				case 'b':
					DO(int, B)
				case 'N':
					DX(int, N)
					// FALLTHROUGH
				case 'n':
					DO(int, N)
				case 'C':
					DX(char, C)
					// FALLTHROUGH
				case 'c':
					DO(char, C)
				case 'I':
				case 'D':
					DX(int, I)
					// FALLTHROUGH
				case 'i':
				case 'd':
					DO(int, I)
				case 'H':
				case 'X':
					DX(int, H)
					// FALLTHROUGH
				case 'h':
				case 'x':
					DO(int, H)
				case 'O':
					DX(int, O)
					// FALLTHROUGH
				case 'o':
					DO(int, O)
				case 'F':
					DXF(double, F)
					// FALLTHROUGH
				case 'f':
					DOF(double, F)
				case 'G':
					DXF(double, G)
					// FALLTHROUGH
				case 'g':
					DOF(double, G)
				case '{':
					if (doSave)
					{
						doSave = false;
					}
					else
					{
						// Already in a quiet section.
						logprintf("sscanf warning: Can't have nestled quiet sections.");
					}
					continue;
				case '}':
					if (doSave)
					{
						logprintf("sscanf warning: Not in a quiet section.");
					}
					else
					{
						doSave = true;
					}
					continue;
				case 'P':
					logprintf("sscanf warning: You can't have an optional delimiter.");
					// FALLTHROUGH
				case 'p':
					// 'P' doesn't exist.
					// Theoretically, for compatibility, this should be:
					// p<delimiter>, but that will break backwards
					// compatibility with anyone doing "p<" to use '<' as a
					// delimiter (doesn't matter how rare that may be).  Also,
					// writing deprecation code and both the new and old code
					// is more trouble than it's worth, and it's slow.
					// UPDATE: I wrote the "GetSingleType" code for 'a' and
					// figured out a way to support legacy and new code, while
					// still maintaining support for the legacy "p<" separator,
					// so here it is:
					ResetDelimiter();
					AddDelimiter(GetSingleType(&format));
					continue;
				case 'Z':
					logprintf("sscanf warning: 'Z' doesn't exist - that would be an optional, deprecated optional string!.");
					// FALLTHROUGH
				case 'z':
					logprintf("sscanf warning: 'z' is deprecated, consider using 'S' instead.");
					// FALLTHROUGH
				case 'S':
					if (IsDelimiter(*string))
					{
						char *
							dest;
						int
							length;
						if (DoSD(&format, &dest, &length))
						{
							// Send the string to PAWN.
							if (doSave)
							{
								amx_GetAddr(amx, params[paramPos++], &cptr);
								amx_SetString(cptr, dest, 0, 0, length);
							}
						}
						break;
					}
					// Implicit "else".
					SkipDefaultEx(&format);
					// FALLTHROUGH
				case 's':
					{
						// Get the length.
						int
							length = GetLength(&format, false);
						char *
							dest;
						DoS(&string, &dest, length, IsEnd(*format));
						// Send the string to PAWN.
						if (doSave)
						{
							amx_GetAddr(amx, params[paramPos++], &cptr);
							amx_SetString(cptr, dest, 0, 0, length);
						}
					}
					break;
				case 'U':
					DX(int, U)
					// FALLTHROUGH
				case 'u':
					DOV(int, U)
					break;
				case 'Q':
					DX(int, Q)
					// FALLTHROUGH
				case 'q':
					DOV(int, Q)
					break;
				case 'R':
					DX(int, R)
					// FALLTHROUGH
				case 'r':
					DOV(int, R)
					break;
				case 'A':
					// We need the default values here.
					if (doSave)
					{
						amx_GetAddr(amx, params[paramPos++], &cptr);
						if (DoA(&format, &string, cptr, true))
						{
							break;
						}
					}
					else
					{
						// Pass a NULL pointer so data isn't saved anywhere.
						if (DoA(&format, &string, NULL, true))
						{
							break;
						}
					}
					return SSCANF_FAIL_RETURN;
				case 'a':
					if (doSave)
					{
						amx_GetAddr(amx, params[paramPos++], &cptr);
						if (DoA(&format, &string, cptr, false))
						{
							break;
						}
					}
					else
					{
						// Pass a NULL pointer so data isn't saved anywhere.
						if (DoA(&format, &string, NULL, false))
						{
							break;
						}
					}
					return SSCANF_FAIL_RETURN;
				case 'E':
					// We need the default values here.
					if (doSave)
					{
						amx_GetAddr(amx, params[paramPos++], &cptr);
						if (DoE(&format, &string, cptr, true))
						{
							break;
						}
					}
					else
					{
						// Pass a NULL pointer so data isn't saved anywhere.
						if (DoE(&format, &string, NULL, true))
						{
							break;
						}
					}
					return SSCANF_FAIL_RETURN;
				case 'e':
					if (doSave)
					{
						amx_GetAddr(amx, params[paramPos++], &cptr);
						if (DoE(&format, &string, cptr, false))
						{
							break;
						}
					}
					else
					{
						// Pass a NULL pointer so data isn't saved anywhere.
						if (DoE(&format, &string, NULL, false))
						{
							break;
						}
					}
					return SSCANF_FAIL_RETURN;
				case 'K':
					// We need the default values here.
					if (doSave)
					{
						amx_GetAddr(amx, params[paramPos++], &cptr);
						if (DoK(amx, &format, &string, cptr, true))
						{
							break;
						}
					}
					else
					{
						// Pass a NULL pointer so data isn't saved anywhere.
						if (DoK(amx, &format, &string, NULL, true))
						{
							break;
						}
					}
					return SSCANF_FAIL_RETURN;
				case 'k':
					if (doSave)
					{
						amx_GetAddr(amx, params[paramPos++], &cptr);
						if (DoK(amx, &format, &string, cptr, false))
						{
							break;
						}
					}
					else
					{
						// Pass a NULL pointer so data isn't saved anywhere.
						if (DoK(amx, &format, &string, NULL, false))
						{
							break;
						}
					}
					return SSCANF_FAIL_RETURN;
				case '\'':
					// Find the end of the literal.
					{
						char
							* str = format,
							* write = format;
						bool
							escape = false;
						while (!IsEnd(*str) && (escape || *str != '\''))
						{
							if (*str == '\\')
							{
								if (escape)
								{
									// "\\" - Go back a step to write this
									// character over the last character (which
									// just happens to be the same character).
									--write;
								}
								escape = !escape;
							}
							else
							{
								if (*str == '\'')
								{
									// Overwrite the escape character with the
									// quote character.  Must have been
									// preceeded by a slash or it wouldn't have
									// got to here in the loop.
									--write;
								}
								escape = false;
							}
							// Copy the string over itself to get rid of excess
							// escape characters.
							// Not sure if it's faster in the average case to
							// always do the copy or check if it's needed.
							// This write is always safe as it makes the string
							// shorter, so we'll never run out of space.  It
							// will also not overwrite the original string.
							*write++ = *str++;
						}
						if (*str == '\'')
						{
							// Correct end.  Make a shorter string to search
							// for.
							*write = '\0';
							// Find the current section of format in string.
							char *
								find = strstr(string, format);
							if (!find)
							{
								// Didn't find the string
								return SSCANF_FAIL_RETURN;
							}
							// Found the string.  Update the current string
							// position to the length of the search term
							// further along from the start of the term.  Use
							// "write" here as we want the escaped string
							// length.
							string = find + (write - format);
							// Move to after the end of the search string.  Use
							// "str" here as we want the unescaped string
							// length.
							format = str + 1;
						}
						else
						{
							logprintf("sscanf warning: Unclosed string literal.");
							char *
								find = strstr(string, format);
							if (!find)
							{
								return SSCANF_FAIL_RETURN;
							}
							string = find + (write - format);
							format = str;
						}
					}
					break;
				case '%':
					logprintf("sscanf warning: sscanf specifiers do not require '%' before them.");
					continue;
				default:
					logprintf("sscanf warning: Unknown format specifier '%c', skipping.", *(format - 1));
					continue;
			}
			// Loop cleanup - only skip one spacer so that we can detect
			// multiple explicit delimiters in a row, for example:
			// 
			// hi     there
			// 
			// is NOT multiple explicit delimiters in a row (they're
			// whitespace).  This however is:
			// 
			// hi , , , there
			// 
			SkipOneSpacer(&string);
		}
	}
	// Temporary to the end of the code.
	ResetDelimiter();
	AddDelimiter(')');
	// We don't need code here to handle the case where paramPos was reached,
	// but the end of the string wasn't - if that's the case there's no
	// problem as we just ignore excess string data.
	while (paramPos < paramCount || !doSave)
	{
		// Loop through if there's still parameters remaining.
		if (!*format)
		{
			logprintf("sscanf warning: Format specifier does not match parameter count.");
			if (!doSave)
			{
				// Started a quiet section but never explicitly ended it.
				logprintf("sscanf warning: Unclosed quiet section.");
			}
			return SSCANF_TRUE_RETURN;
		}
		else if (IsWhitespace(*format))
		{
			++format;
		}
		else
		{
			// Do the main switch again.
			switch (*format++)
			{
				case 'L':
					DE(bool, L)
				case 'B':
					DE(int, B)
				case 'N':
					DE(int, N)
				case 'C':
					DE(char, C)
				case 'I':
				case 'D':
					DE(int, I)
				case 'H':
				case 'X':
					DE(int, H)
				case 'O':
					DE(int, O)
				case 'F':
					DEF(double, F)
				case 'G':
					DEF(double, G)
				case 'U':
					DE(int, U)
				case 'Q':
					DE(int, Q)
				case 'R':
					DE(int, R)
				case 'A':
					if (doSave)
					{
						amx_GetAddr(amx, params[paramPos++], &cptr);
						if (DoA(&format, NULL, cptr, true))
						{
							break;
						}
					}
					else
					{
						// Pass a NULL pointer so data isn't saved anywhere.
						// Also pass NULL data so it knows to only collect the
						// default values.
						if (DoA(&format, NULL, NULL, true))
						{
							break;
						}
					}
					return SSCANF_FAIL_RETURN;
				case 'E':
					if (doSave)
					{
						amx_GetAddr(amx, params[paramPos++], &cptr);
						if (DoE(&format, NULL, cptr, true))
						{
							break;
						}
					}
					else
					{
						// Pass a NULL pointer so data isn't saved anywhere.
						// Also pass NULL data so it knows to only collect the
						// default values.
						if (DoE(&format, NULL, NULL, true))
						{
							break;
						}
					}
					return SSCANF_FAIL_RETURN;
				case 'K':
					if (doSave)
					{
						amx_GetAddr(amx, params[paramPos++], &cptr);
						if (DoK(amx, &format, NULL, cptr, true))
						{
							break;
						}
					}
					else
					{
						// Pass a NULL pointer so data isn't saved anywhere.
						// Also pass NULL data so it knows to only collect the
						// default values.
						if (DoK(amx, &format, NULL, NULL, true))
						{
							break;
						}
					}
					return SSCANF_FAIL_RETURN;
				case '{':
					if (doSave)
					{
						doSave = false;
					}
					else
					{
						// Already in a quiet section.
						logprintf("sscanf warning: Can't have nestled quiet sections.");
					}
					break;
				case '}':
					if (doSave)
					{
						logprintf("sscanf warning: Not in a quiet section.");
					}
					else
					{
						doSave = true;
					}
					break;
				case 'Z':
					logprintf("sscanf warning: 'Z' doesn't exist - that would be an optional, deprecated optional string!.");
					// FALLTHROUGH
				case 'z':
					logprintf("sscanf warning: 'z' is deprecated, consider using 'S' instead.");
					// FALLTHROUGH
				case 'S':
					{
						char *
							dest;
						int
							length;
						if (DoSD(&format, &dest, &length))
						{
							// Send the string to PAWN.
							if (doSave)
							{
								amx_GetAddr(amx, params[paramPos++], &cptr);
								amx_SetString(cptr, dest, 0, 0, length);
							}
						}
					}
					break;
				case 'P':
					logprintf("sscanf warning: You can't have an optional delimiter.");
					// FALLTHROUGH
				case 'p':
					// Discard delimiter.  This only matters when they have
					// real inputs, not the default ones used here.
					GetSingleType(&format);
					continue;
				case '\'':
					// Implicitly optional if the specifiers after it are
					// optional.
					{
						bool
							escape = false;
						while (!IsEnd(*format) && (escape || *format != '\''))
						{
							if (*format == '\\')
							{
								escape = !escape;
							}
							else
							{
								escape = false;
							}
							++format;
						}
						if (*format == '\'')
						{
							++format;
						}
						else
						{
							logprintf("sscanf warning: Unclosed string literal.");
						}
					}
					break;
					// Large block of specifiers all together.
				case 'a':
				case 'b':
				case 'c':
				case 'd':
				case 'e':
				case 'f':
				case 'g':
				case 'h':
				case 'i':
				case 'k':
				case 'l':
				case 'n':
				case 'o':
				case 'q':
				case 'r':
				case 's':
				case 'u':
				case 'x':
					// These are non optional items, but the input string
					// didn't include them, so we fail - this is in fact the
					// most basic definition of a fail (the original)!  We
					// don't need any text warnings here - admittedly we don't
					// know if the format specifier is well formed (there may
					// not be enough return variables for example), but it
					// doesn't matter - the coder should have tested for those
					// things, and the more important thing is that the user
					// didn't enter the correct data.
					return SSCANF_FAIL_RETURN;
				case '%':
					logprintf("sscanf warning: sscanf specifiers do not require '%' before them.");
					break;
				default:
					logprintf("sscanf warning: Unknown format specifier '%c', skipping.", *(format - 1));
					break;
			}
			// Don't need any cleanup here.
		}
	}
	if (*format)
	{
		do
		{
			if (!IsWhitespace(*format))
			{
				// Only print this warning if the remaining characters are not
				// spaces - spaces are allowed, and sometimes required, on the
				// ends of formats (e.g. to stop the final 's' specifier
				// collecting all remaining characters and only get one word).
				// We could check that the remaining specifier is a valid one,
				// but this is only a guide - they shouldn't even have other
				// characters IN the specifier so it doesn't matter - it will
				// point to a bug, which is the important thing.
				if (doSave)
				{
					if (*format == '}')
					{
						logprintf("sscanf warning: Not in a quiet section.");
					}
					else if (*format != '{')
					{
						// Fix the bad display bug.
						logprintf("sscanf warning: Format specifier does not match parameter count.");
					}
					// Only display it once.
					break;
				}
				else
				{
					if (*format == '}')
					{
						doSave = true;
					}
					else
					{
						logprintf("sscanf warning: Format specifier does not match parameter count.");
						break;
					}
				}
			}
			++format;
		}
		while (*format);
	}
	if (!doSave)
	{
		// Started a quiet section but never explicitly ended it.
		logprintf("sscanf warning: Unclosed quiet section.");
	}
	// No more parameters and no more format specifiers which could be read
	// from - this is a valid return!
	return SSCANF_TRUE_RETURN;
}
Example #22
0
/* libcall(const libname[], const funcname[], const typestring[], ...)
 *
 * Loads the DLL or shared library if not yet loaded (the name comparison is
 * case sensitive).
 *
 * typestring format:
 *    Whitespace is permitted between the types, but not inside the type
 *    specification. The string "ii[4]&u16s" is equivalent to "i i[4] &u16 s",
 *    but the latter is easier on the eye.
 *
 * types:
 *    i = signed integer, 16-bit in Windows 3.x, else 32-bit in Win32 and Linux
 *    u = unsigned integer, 16-bit in Windows 3.x, else 32-bit in Win32 and Linux
 *    f = IEEE floating point, 32-bit
 *    p = packed string
 *    s = unpacked string
 *    The difference between packed and unpacked strings is only relevant when
 *    the parameter is passed by reference (see below).
 *
 * pass-by-value and pass-by-reference:
 *    By default, parameters are passed by value. To pass a parameter by
 *    reference, prefix the type letter with an "&":
 *    &i = signed integer passed by reference
 *    i = signed integer passed by value
 *    Same for '&u' versus 'u' and '&f' versus 'f'.
 *
 *    Arrays are passed by "copy & copy-back". That is, libcall() allocates a
 *    block of dynamic memory to copy the array into. On return from the foreign
 *    function, libcall() copies the array back to the abstract machine. The
 *    net effect is similar to pass by reference, but the foreign function does
 *    not work in the AMX stack directly. During the copy and the copy-back
 *    operations, libcall() may also transform the array elements, for example
 *    between 16-bit and 32-bit elements. This is done because Pawn only
 *    supports a single cell size, which may not fit the required integer size
 *    of the foreign function.
 *
 *    See "element ranges" for the syntax of passing an array.
 *
 *    Strings may either be passed by copy, or by "copy & copy-back". When the
 *    string is an output parameter (for the foreign function), the size of the
 *    array that will hold the return string must be indicated between square
 *    brackets behind the type letter (see "element ranges"). When the string
 *    is "input only", this is not needed --libcall() will determine the length
 *    of the input string itself.
 *
 *    The tokens 'p' and 's' are equivalent, but 'p[10]' and 's[10]' are not
 *    equivalent: the latter syntaxes determine whether the output from the
 *    foreign function will be stored as a packed or an unpacked string.
 *
 * element sizes:
 *    Add an integer behind the type letter; for example, 'i16' refers to a
 *    16-bit signed integer. Note that the value behind the type letter must
 *    be either 8, 16 or 32.
 *
 *    You should only use element size specifiers on the 'i' and 'u' types. That
 *    is, do not use these specifiers on 'f', 's' and 'p'.
 *
 * element ranges:
 *    For passing arrays, the size of the array may be given behind the type
 *    letter and optional element size. The token 'u[4]' indicates an array of
 *    four unsigned integers, which are typically 32-bit. The token 'i16[8]'
 *    is an array of 8 signed 16-bit integers. Arrays are always passed by
 *    "copy & copy-back"
 *
 * When compiled as Unicode, this library converts all strings to Unicode
 * strings.
 *
 * The calling convention for the foreign functions is assumed:
 * -  "__stdcall" for Win32,
 * -  "far pascal" for Win16
 * -  and the GCC default for Unix/Linux (_cdecl)
 *
 * C++ name mangling of the called function is not handled (there is no standard
 * convention for name mangling, so there is no portable way to convert C++
 * function names to mangled names). Win32 name mangling (used by default by
 * Microsoft compilers on functions declared as __stdcall) is also not handled.
 *
 * Returns the value of the called function.
 */
static cell AMX_NATIVE_CALL n_libcall(AMX *amx, const cell *params)
{
  const TCHAR *libname, *funcname, *typestring;
  MODLIST *item;
  int paramidx, typeidx, idx;
  PARAM ps[MAXPARAMS];
  cell *cptr,result;
  LIBFUNC LibFunc;

  amx_StrParam(amx, params[1], libname);
  item = findlib(&ModRoot, amx, libname);
  if (item == NULL)
    item = addlib(&ModRoot, amx, libname);
  if (item == NULL) {
    amx_RaiseError(amx, AMX_ERR_NATIVE);
    return 0;
  } /* if */

  /* library is loaded, get the function */
  amx_StrParam(amx, params[2], funcname);
  LibFunc=(LIBFUNC)SearchProcAddress(item->inst, funcname);
  if (LibFunc==NULL) {
    amx_RaiseError(amx, AMX_ERR_NATIVE);
    return 0;
  } /* if */

  #if defined HAVE_DYNCALL_H
    /* (re-)initialize the dyncall library */
    if (dcVM==NULL) {
      dcVM=dcNewCallVM(4096);
      dcMode(dcVM,DC_CALL_C_X86_WIN32_STD);
    } /* if */
    dcReset(dcVM);
  #endif

  /* decode the parameters */
  paramidx=typeidx=0;
  amx_StrParam(amx, params[3], typestring);
  while (paramidx < MAXPARAMS && typestring[typeidx]!=__T('\0')) {
    /* skip white space */
    while (typestring[typeidx]!=__T('\0') && typestring[typeidx]<=__T(' '))
      typeidx++;
    if (typestring[typeidx]==__T('\0'))
      break;
    /* save "pass-by-reference" token */
    ps[paramidx].type=0;
    if (typestring[typeidx]==__T('&')) {
      ps[paramidx].type=BYREF;
      typeidx++;
    } /* if */
    /* store type character */
    ps[paramidx].type |= (unsigned char)typestring[typeidx];
    typeidx++;
    /* set default size, then check for an explicit size */
    #if defined __WIN32__ || defined _WIN32 || defined WIN32
      ps[paramidx].size=32;
    #elif defined _Windows
      ps[paramidx].size=16;
    #endif
    if (_istdigit(typestring[typeidx])) {
      ps[paramidx].size=(unsigned char)_tcstol(&typestring[typeidx],NULL,10);
      while (_istdigit(typestring[typeidx]))
        typeidx++;
    } /* if */
    /* set default range, then check for an explicit range */
    ps[paramidx].range=1;
    if (typestring[typeidx]=='[') {
      ps[paramidx].range=_tcstol(&typestring[typeidx+1],NULL,10);
      while (typestring[typeidx]!=']' && typestring[typeidx]!='\0')
        typeidx++;
      ps[paramidx].type |= BYREF; /* arrays are always passed by reference */
      typeidx++;                  /* skip closing ']' too */
    } /* if */
    /* get pointer to parameter */
    cptr=amx_Address(amx,params[paramidx+4]);
    switch (ps[paramidx].type) {
    case 'i': /* signed integer */
    case 'u': /* unsigned integer */
    case 'f': /* floating point */
      assert(ps[paramidx].range==1);
      ps[paramidx].v.val=(int)*cptr;
      break;
    case 'i' | BYREF:
    case 'u' | BYREF:
    case 'f' | BYREF:
      ps[paramidx].v.ptr=cptr;
      if (ps[paramidx].range>1) {
        /* convert array and pass by address */
        ps[paramidx].v.ptr = fillarray(amx, &ps[paramidx], cptr);
      } /* if */
      break;
    case 'p':
    case 's':
    case 'p' | BYREF:
    case 's' | BYREF:
      if (ps[paramidx].type=='s' || ps[paramidx].type=='p') {
        int len;
        /* get length of input string */
        amx_StrLen(cptr,&len);
        len++;            /* include '\0' */
        /* check max. size */
        if (len<ps[paramidx].range)
          len=ps[paramidx].range;
        ps[paramidx].range=len;
      } /* if */
      ps[paramidx].v.ptr=malloc(ps[paramidx].range*sizeof(TCHAR));
      if (ps[paramidx].v.ptr==NULL)
        return amx_RaiseError(amx, AMX_ERR_NATIVE);
      amx_GetString((char *)ps[paramidx].v.ptr,cptr,sizeof(TCHAR)>1,UNLIMITED);
      break;
    default:
      /* invalid parameter type */
      return amx_RaiseError(amx, AMX_ERR_NATIVE);
    } /* switch */
    paramidx++;
  } /* while */
  if ((params[0]/sizeof(cell)) - 3 != (size_t)paramidx)
    return amx_RaiseError(amx, AMX_ERR_NATIVE); /* format string does not match number of parameters */

  #if defined HAVE_DYNCALL_H
    for (idx = 0; idx < paramidx; idx++) {
      if ((ps[idx].type=='i' || ps[idx].type=='u' || ps[idx].type=='f') && ps[idx].range==1) {
        switch (ps[idx].size) {
        case 8:
          dcArgChar(dcVM,(unsigned char)(ps[idx].v.val & 0xff));
          break;
        case 16:
          dcArgShort(dcVM,(unsigned short)(ps[idx].v.val & 0xffff));
          break;
        default:
          dcArgLong(dcVM,ps[idx].v.val);
        } /* switch */
      } else {
        dcArgPointer(dcVM,ps[idx].v.ptr);
      } /* if */
    } /* for */
    result=(cell)dcCallPointer(dcVM,(void*)LibFunc);
  #else /* HAVE_DYNCALL_H */
    /* push the parameters to the stack (left-to-right in 16-bit; right-to-left
     * in 32-bit)
     */
#if defined __WIN32__ || defined _WIN32 || defined WIN32
    for (idx=paramidx-1; idx>=0; idx--) {
#else
    for (idx=0; idx<paramidx; idx++) {
#endif
      if ((ps[idx].type=='i' || ps[idx].type=='u' || ps[idx].type=='f') && ps[idx].range==1) {
        switch (ps[idx].size) {
        case 8:
          push((unsigned char)(ps[idx].v.val & 0xff));
          break;
        case 16:
          push((unsigned short)(ps[idx].v.val & 0xffff));
          break;
        default:
          push(ps[idx].v.val);
        } /* switch */
      } else {
        push(ps[idx].v.ptr);
      } /* if */
    } /* for */

    /* call the function; all parameters are already pushed to the stack (the
     * function should remove the parameters from the stack)
     */
    result=LibFunc();
  #endif /* HAVE_DYNCALL_H */

  /* store return values and free allocated memory */
  for (idx=0; idx<paramidx; idx++) {
    switch (ps[idx].type) {
    case 'p':
    case 's':
      free(ps[idx].v.ptr);
      break;
    case 'p' | BYREF:
    case 's' | BYREF:
      cptr=amx_Address(amx,params[idx+4]);
      amx_SetString(cptr,(char *)ps[idx].v.ptr,ps[idx].type==('p'|BYREF),sizeof(TCHAR)>1,UNLIMITED);
      free(ps[idx].v.ptr);
      break;
    case 'i':
    case 'u':
    case 'f':
      assert(ps[idx].range==1);
      break;
    case 'i' | BYREF:
    case 'u' | BYREF:
    case 'f' | BYREF:
      cptr=amx_Address(amx,params[idx+4]);
      if (ps[idx].range==1) {
        /* modify directly in the AMX (no memory block was allocated */
        switch (ps[idx].size) {
        case 8:
          *cptr= (ps[idx].type==('i' | BYREF)) ? (long)((signed char)*cptr) : (*cptr & 0xff);
          break;
        case 16:
          *cptr= (ps[idx].type==('i' | BYREF)) ? (long)((short)*cptr) : (*cptr & 0xffff);
          break;
        } /* switch */
      } else {
        int i;
        for (i=0; i<ps[idx].range; i++) {
          switch (ps[idx].size) {
          case 8:
            *cptr= (ps[idx].type==('i' | BYREF)) ? ((signed char*)ps[idx].v.ptr)[i] : ((unsigned char*)ps[idx].v.ptr)[i];
            break;
          case 16:
            *cptr= (ps[idx].type==('i' | BYREF)) ? ((short*)ps[idx].v.ptr)[i] : ((unsigned short*)ps[idx].v.ptr)[i];
            break;
          default:
            *cptr= (ps[idx].type==('i' | BYREF)) ? ((long*)ps[idx].v.ptr)[i] : ((unsigned long*)ps[idx].v.ptr)[i];
          } /* switch */
        } /* for */
        free((char *)ps[idx].v.ptr);
      } /* if */
      break;
    default:
      assert(0);
    } /* switch */
  } /* for */

  return result;
}

/* bool: libfree(const libname[]="")
 * When the name is an empty string, this function frees all libraries (for this
 * abstract machine). The name comparison is case sensitive.
 * Returns true if one or more libraries were freed.
 */
static cell AMX_NATIVE_CALL n_libfree(AMX *amx, const cell *params)
{
  const TCHAR *libname;
  amx_StrParam(amx,params[1],libname);
  return freelib(&ModRoot,amx,libname) > 0;
}

#else /* HAVE_DYNCALL_H || WIN32_FFI */

static cell AMX_NATIVE_CALL n_libcall(AMX *amx, const cell *params)
{
  (void)amx;
  (void)params;
  return 0;
}
Example #23
0
int Invoke::callNative(const PAWN::Native * native, ...)
{
	if (amx_list.empty() || amx_map.find(native->name) == amx_map.end())
	{
		return 0;
	}

	unsigned int amx_addr = amx_map[native->name], count = strlen(native->data), variables = 0;
	cell * params = new cell[count + 1], * physAddr[6];
	params[0] = count * sizeof(cell);
	va_list input;
	va_start(input, native);
	for (unsigned int i = 0; i < count; ++i)
	{
		switch (native->data[i])
		{
			case 'd':
			case 'i':
			{
				params[i + 1] = va_arg(input, int);
			}
			break;
			case 'f':
			{
				float value = (float)va_arg(input, double);
				params[i + 1] = amx_ftoc(value);
			}
			break;
			case 's':
			{
				char * string = va_arg(input, char *);
				amx_Allot(amx_list.front(), strlen(string) + 1, &params[i + 1], &physAddr[variables++]);
				amx_SetString(physAddr[variables - 1], string, 0, 0, strlen(string) + 1);
			}
			break;
			case 'v':
			{
				va_arg(input, void *);
				amx_Allot(amx_list.front(), 1, &params[i + 1], &physAddr[variables++]);
			}
			break;
			case 'p':
			{
				va_arg(input, void *);
				int size = va_arg(input, int);
				amx_Allot(amx_list.front(), size, &params[++i], &physAddr[variables++]);
				params[i + 1] = size;
			}
			break;
		}
	}
	va_end(input);
	amx_Function_t amx_Function = (amx_Function_t)amx_addr;
	int value = amx_Function(amx_list.front(), params);
	if (variables)
	{
		variables = 0;
		va_start(input, native);
		for (unsigned int i = 0; i < count; ++i)
		{
			switch (native->data[i])
			{
				case 's':
				{
					amx_Release(amx_list.front(), params[i + 1]);
				}
				break;
				case 'v':
				{
					unsigned int * value = va_arg(input, unsigned int *), * returnValue = (unsigned int *)physAddr[variables++];
					* value = * returnValue;
					amx_Release(amx_list.front(), params[i + 1]);
				}
				break;
				case 'p':
				{
					char * text = va_arg(input, char *);
					int size = va_arg(input, int);
					amx_GetString(text, physAddr[variables++], 0, size);
					amx_Release(amx_list.front(), params[++i]);
				}
				break;
				default:
				{
					va_arg(input, void *);
				}
				break;
			}
		}
		va_end(input);
	}
	delete [] params;
	return value;
}
Example #24
0
cell FakeAmxPush(const char *s) {
    cell address = FakeAmxPush(strlen(s));
    amx_SetString(::fakeAmxData + address, s, 0, 0, strlen(s) + 1);
    return address;
}