Esempio n. 1
0
/* gettime(&hour, &minute, &second)
 * The return value is the number of seconds since 1 January 1970 (Unix system
 * time).
 */
static cell AMX_NATIVE_CALL n_gettime(AMX *amx, const cell *params)
{
  time_t sec1970;
  struct tm gtm;
  cell *cptr;

  assert(params[0]==(int)(3*sizeof(cell)));

  time(&sec1970);

  /* on DOS/Windows, the timezone is usually not set for the C run-time
   * library; in that case gmtime() and localtime() return the same value
   */
  gtm=*localtime(&sec1970);
  cptr=amx_Address(amx,params[1]);
  *cptr=gtm.tm_hour;
  cptr=amx_Address(amx,params[2]);
  *cptr=gtm.tm_min;
  cptr=amx_Address(amx,params[3]);
  *cptr=gtm.tm_sec;

  /* the time() function returns the number of seconds since January 1 1970
   * in Universal Coordinated Time (the successor to Greenwich Mean Time)
   */
  return (cell)sec1970;
}
Esempio n. 2
0
/* bool: gettimer(&milliseconds, bool: &singleshot = false)
 * Retrieves the timer set with settimer(); returns true if a timer
 * was set up, or false otherwise.
 */
static cell AMX_NATIVE_CALL n_gettimer(AMX *amx, const cell *params)
{
  cell *cptr;

  assert(params[0]==(int)(2*sizeof(cell)));
  cptr=amx_Address(amx,params[1]);
  *cptr=timelimit;
  cptr=amx_Address(amx,params[2]);
  *cptr=timerepeat;
  return timelimit>0;
}
Esempio n. 3
0
/* sendstring(const message[], const destination[]="")
 * destination has the format "127.0.0.1:9930"; when set to an empty string,
 * a broadcast is sent.
 * To mark the text as a "string", the function inserts a "byte order mark" in
 * front of it. It does this for Extended ASCII strings too, although this is
 * not entirely correct.
 * Returns true on success, false on failure.
 */
static cell AMX_NATIVE_CALL n_sendstring(AMX *amx, const cell *params)
{
  int r = 0, length;
  cell *cstr;
  char *host, *message, *ptr;
  short port=AMX_DGRAMPORT;

  cstr = amx_Address(amx, params[1]);
  amx_UTF8Len(cstr, &length);

  if ((message = alloca(length + 3 + 1)) != NULL) {
    /* insert the byte order mark (BOM) */
    message[0]='\xef';
    message[1]='\xbb';
    message[2]='\xbf';
    /* if this is a wide string, convert it to UTF-8 */
    if ((ucell)*cstr<=UNPACKEDMAX) {
      ptr=message+3;
      while (*cstr!=0)
        amx_UTF8Put(ptr, &ptr, length - (ptr-message), *cstr++);
      *ptr='\0';
    } else {
      amx_GetString(message+3, cstr, 0, UNLIMITED);
    } /* if */

    amx_StrParam(amx, params[2], host);
    if (host != NULL && (ptr=strchr(host,':'))!=NULL && isdigit(ptr[1])) {
      *ptr++='\0';
      port=(short)atoi(ptr);
    } /* if */
    r= (udp_Send(host,port,message,strlen(message)+1) > 0);
  } /* if */

  return r;
}
Esempio n. 4
0
/** pawnGameGetDetails
* native GameGetDetails(slot, array[64], bool:pack_array = false, maxlength=sizeof array);
* Get Save Game Details.
*/
static cell pawnGameGetDetails(AMX *amx, const cell *params)
{
	ASSERT_PAWN_PARAM( amx, params, 1 );

	if ( params[1] > 254 || params[1] < 0)
		return 0;

	if ( params[4] != 64 )
		return 0;

	cell read_successful = false;
	int32_t * cookie_data = NULL;
	uint8_t data_size = 0;
	uint8_t requested_save_slot = (uint8_t)params[1];

	cell * cptr = amx_Address(amx, params[2]);

	if ( lux::engine )
	{
		cookie_data = Lux_FFI_Game_Details( lux::game_data->GetProjectIdent(), requested_save_slot, &data_size );
		if ( data_size )
		{
			for (uint8_t count = 0; count < data_size; count++)
			{
				*cptr = cookie_data[count];
				cptr ++;
			}
			read_successful = true;

			delete[] cookie_data;
		}
	}

	return read_successful;
}
Esempio n. 5
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;
}
Esempio n. 6
0
static cell AMX_NATIVE_CALL n_strfloat(AMX *amx,const cell *params)
{
    /*
    *   params[0] = number of bytes
    *   params[1] = virtual string address to convert to a float
    */
    char szSource[60];
    cell *pString;
    REAL fNum;
    int nLen;

    (void)amx;
    /* They should have sent us 1 cell. */
    assert(params[0]/sizeof(cell)==1);

    /* Get the real address of the string. */
    pString=amx_Address(amx,params[1]);

    /* Find out how long the string is in characters. */
    amx_StrLen(pString, &nLen);
    if (nLen == 0 || nLen >= sizeof szSource)
        return 0;

    /* Now convert the Pawn string into a C type null terminated string */
    amx_GetString(szSource, pString, 0, sizeof szSource);

    /* Now convert this to a float. */
    fNum = (REAL)atof(szSource);

    return amx_ftoc(fNum);
}
Esempio n. 7
0
File: amxargs.c Progetto: 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;
}
Esempio n. 8
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]);
}
Esempio n. 9
0
/** pawnDialogGetString
* native DialogGetString(line, returnstring{}, maxlength=sizeof returnstring);
*
*/
static cell pawnDialogGetString(AMX *amx, const cell *params)
{
	const char * dialog_string;
	cell * cptr;
	cptr = amx_Address(amx, params[2]);

	dialog_string = Lux_FFI_Dialog_String( (uint32_t)params[1] );

	return Lux_PawnEntity_SetString(cptr, dialog_string, params[3]*sizeof(cell) );
}
Esempio n. 10
0
/* getdate(&year, &month, &day)
 * The return value is the number of days since the start of the year. January
 * 1 is day 1 of the year.
 */
static cell AMX_NATIVE_CALL n_getdate(AMX *amx, const cell *params)
{
  time_t sec1970;
  struct tm gtm;
  cell *cptr;

  assert(params[0]==(int)(3*sizeof(cell)));

  time(&sec1970);

  gtm=*localtime(&sec1970);
  cptr=amx_Address(amx,params[1]);
  *cptr=gtm.tm_year+1900;
  cptr=amx_Address(amx,params[2]);
  *cptr=gtm.tm_mon+1;
  cptr=amx_Address(amx,params[3]);
  *cptr=gtm.tm_mday;

  return gtm.tm_yday+1;
}
Esempio n. 11
0
cell pawn_serialReceive( AMX * amx, const cell * params )
{
	int cnt = ( params[2] < SERIAL_BUF_SZ ) ? params[2] : SERIAL_BUF_SZ;
	cnt = serialReceive( serialBuffer, cnt );
	int i;
	cell * data = amx_Address( amx, params[1] );
	if ( !data )
		return 0;
	for ( i=0; i<cnt; i++)
		data[i] = serialBuffer[i];
    return cnt;
}
Esempio n. 12
0
cell pawn_i2cIo( AMX * amx, const cell * params )
{
	(void)amx;
	uint8_t addr = params[1];
	cell * dataIo = amx_Address( amx, params[2] );
	int writeCnt  = params[3];
	int readCnt   = params[5];
	int timeoutMs = params[6];
    int i;
    for ( i=0; i<writeCnt; i++ )
    	i2cWriteBuffer[i] = dataIo[i];
    int status =i2cIo( addr, i2cWriteBuffer, writeCnt,
    		                 i2cReadBuffer,  readCnt,
    		                 timeoutMs );
    if ( readCnt > 0 )
    {
    	dataIo = amx_Address( amx, params[4] );
    	for ( i=0; i<readCnt; i++ )
    		dataIo[i] = (cell)i2cReadBuffer[i];
    }
    return status;
}
Esempio n. 13
0
/* sendpacket(const packet[], size, const destination[]="")
 * destination has the format "127.0.0.1:9930"; when set to an empty string,
 * a broadcast is sent.
 * Returns true on success, false on failure.
 */
static cell AMX_NATIVE_CALL n_sendpacket(AMX *amx, const cell *params)
{
  cell *cstr;
  char *host, *ptr;
  short port=AMX_DGRAMPORT;

  cstr = amx_Address(amx, params[1]);
  amx_StrParam(amx, params[3], host);
  if (host != NULL && (ptr=strchr(host,':'))!=NULL && isdigit(ptr[1])) {
    *ptr++='\0';
    port=(short)atoi(ptr);
  } /* if */
  return (udp_Send(host,port,(const char *)cstr,params[2] * sizeof(cell)) > 0);
}
Esempio n. 14
0
/* tickcount(&granularity)
 * Returns the number of milliseconds since start-up. For a 32-bit cell, this
 * count overflows after approximately 24 days of continuous operation.
 */
static cell AMX_NATIVE_CALL n_tickcount(AMX *amx, const cell *params)
{
  cell *cptr;

  assert(params[0]==(int)sizeof(cell));

  INIT_TIMER();
  cptr=amx_Address(amx,params[1]);
  #if defined __WIN32__ || defined _WIN32 || defined WIN32
    *cptr=1000;               	/* granularity = 1 ms */
  #else
    *cptr=(cell)CLOCKS_PER_SEC;	/* in Unix/Linux, this is often 100 */
  #endif
  return gettimestamp() & 0x7fffffff;
}
Esempio n. 15
0
static cell AMX_NATIVE_CALL n_strfixed(AMX *amx,const cell *params)
{
  char str[50],*ptr;
  cell *cstr,intpart,decimals;
  long multiplier,divisor;
  int len,sign=1;

  cstr=amx_Address(amx,params[1]);
  amx_StrLen(cstr,&len);
  if (len>=50) {
    amx_RaiseError(amx,AMX_ERR_NATIVE);
    return 0;
  } /* if */
  amx_GetString(str,cstr,0,UNLIMITED);
  ptr=str;
  intpart=0;
  decimals=0;
  multiplier=MULTIPLIER;
  divisor=1;
  while (*ptr!='\0' && *ptr<=' ')
    ptr++;              /* skip whitespace */
  if (*ptr=='-') {      /* handle sign */
    sign=-1;
    ptr++;
  } else if (*ptr=='+') {
    ptr++;
  } /* if */
  while (isdigit(*ptr)) {
    intpart=intpart*10 + (*ptr-'0');
    ptr++;
  } /* while */
  if (*ptr=='.') {
    ptr++;
    len=0;
    while (isdigit(*ptr) && len<8) {
      decimals=decimals*10 + (*ptr-'0');
      if (multiplier>1)
        multiplier/=10;
      else
        divisor*=10;
      ptr++;
      len++;
    } /* while */
  } /* if */
  return ((intpart*MULTIPLIER) + (decimals*multiplier+(divisor/2))/divisor) * sign;
}
Esempio n. 16
0
cell pawn_serialSend( AMX * amx, const cell * params )
{
	int i = 0;
	int cnt = 0;
	cell * data = amx_Address( amx, params[1] );
	while ( i < params[2] )
	{
		int j;
        for ( j=0; j<SERIAL_BUF_SZ; j++, i++ )
        {
        	if ( i >= params[2] )
        		break;
        	serialBuffer[j] = (uint8_t)data[i];
        }
        cnt += serialSend( serialBuffer, j );
	}
    return cnt;
}
Esempio n. 17
0
File: amxargs.c Progetto: z80/mapper
/* bool: argvalue(index=0, const option[]="", &value=cellmin)
 * returns true if the option was found and false otherwise
 */
static cell AMX_NATIVE_CALL n_argvalue(AMX *amx, const cell *params)
{
    const TCHAR *option, *key;
    int length;
    cell *cptr;

    amx_StrParam(amx, params[2], key);
    cptr = amx_Address(amx, params[3]);

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

    /* check whether we must write the value of the option at all */
    if (length > 0 && (_istdigit(*option) || *option == __T('-')))
        *cptr = _tcstol(option, NULL, 10);

    return 1;
}
Esempio n. 18
0
/** pawnGameSave
* native GameSave(slot, detail[64],  maxlength=sizeof detail );
* Save Current Game.
*/
static cell pawnGameSave(AMX *amx, const cell *params)
{
	ASSERT_PAWN_PARAM( amx, params, 3 );

	if ( params[1] > 254 || params[1] < 0)
		return 0;

	uint8_t requested_save_slot = (uint8_t)params[1];
	int32_t * cookie_data = new int32_t[64];

	cell * cptr = amx_Address(amx, params[2]);
	for ( uint8_t count = 0; count < 64; count++ )
	{
		cookie_data[count] = (int32_t)*cptr;
		cptr++;
	}

	return Lux_FFI_Game_Save( requested_save_slot, cookie_data );

}
Esempio n. 19
0
File: amxargs.c Progetto: z80/mapper
/* 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);
    cptr = amx_Address(amx, params[3]);

    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;
}
Esempio n. 20
0
/** pawnGameDetails
* native GameDetails(id, slot, array[64], bool:pack_array = false, maxlength=sizeof array);
* Get another games Save Game Details.
*/
static cell pawnGameDetails(AMX *amx, const cell *params)
{
	if ( params[2] > 254 || params[2] < 0)
		return 0;

	if ( params[5] != 64 )
		return 0;

	cell read_successful = false;
	uint32_t game_id = (uint32_t)params[1];
	uint8_t requested_save_slot = (uint8_t)params[2];
	int32_t * cookie_data = NULL;
	uint8_t data_size = 0;


	cell * cptr = amx_Address(amx, params[3]);

	if ( lux::engine )
	{
		cookie_data = Lux_FFI_Game_Details( game_id, requested_save_slot, &data_size );
		if ( data_size )
		{
			for (uint8_t count = 0; count < 64; count++)
			{
				*cptr = cookie_data[count];
				cptr ++;
			}

			delete[] cookie_data;
			read_successful = true;
		}
	}



	return read_successful;
}
Esempio n. 21
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;
}