Esempio n. 1
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. 2
0
/* Fixed:fsqroot(Fixed:value) */
static cell AMX_NATIVE_CALL n_fsqroot(AMX *amx,const cell *params)
{
  cell value=params[1];
  cell low=0;
  cell high=value;
  cell mid[3]={8,0,0};

  if (value<0) {
    amx_RaiseError(amx, AMX_ERR_DOMAIN);
    return 0;
  } /* if */

  while (high-low > 1) {
    mid[1]=mid[2]=(low+high)/2;
    if (n_fmul(amx,mid) < value)
      low=mid[1];
    else
      high=mid[1];
  } /* while */

  /* check whether low or high mark comes closest */
  if (low!=high) {
    cell deltalow, deltahigh;
    mid[1]=mid[2]=low;
    deltalow=value-n_fmul(amx,mid);
    assert(deltalow>=0);
    mid[1]=mid[2]=high;
    deltahigh=n_fmul(amx,mid)-value;
    assert(deltahigh>=0);
    if (deltahigh<=deltalow)
      low=high; /* return "high" mark (comes closer to the answer) */
  } /* if */

  return low;
}
Esempio n. 3
0
static void *fillarray(AMX *amx, PARAM *param, cell *cptr)
{
  int i;
  void *vptr;

  vptr = malloc(param->range * (param->size / 8));
  if (vptr == NULL) {
    amx_RaiseError(amx, AMX_ERR_NATIVE);
    return NULL;
  } /* if */

  assert(param->range > 1);
  if (param->size == 8) {
    unsigned char *ptr = (unsigned char *)vptr;
    for (i = 0; i < param->range; i++)
      *ptr++ = (unsigned char)*cptr++;
  } else if (param->size == 16) {
    unsigned short *ptr = (unsigned short *)vptr;
    for (i = 0; i < param->range; i++)
      *ptr++ = (unsigned short)*cptr++;
  } else {
    unsigned long *ptr = (unsigned long *)vptr;
    for (i = 0; i < param->range; i++)
      *ptr++ = (unsigned long)*cptr++;
  } /* for */

  return vptr;
}
Esempio n. 4
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;
}
Esempio n. 5
0
static cell AMX_NATIVE_CALL sm_lightning(AMX *amx, cell *params)
{
    if(gamestate != GS_LEVEL)
    {
        amx_RaiseError(amx, SC_ERR_GAMEMODE | SC_ERR_MASK);
        return -1;
    }

    P_ForceLightning();
    return 0;
}
Esempio n. 6
0
static cell AMX_NATIVE_CALL n_floatsqroot(AMX *amx,const cell *params)
{
    /*
    *   params[0] = number of bytes
    *   params[1] = float operand
    */
    REAL fA = amx_ctof(params[1]);
    fA = (REAL)sqrt(fA);
    if (fA < 0)
        return amx_RaiseError(amx, AMX_ERR_DOMAIN);
    return amx_ftoc(fA);
}
Esempio n. 7
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. 8
0
static cell AMX_NATIVE_CALL n_floatlog(AMX *amx,const cell *params)
{
    /*
    *   params[0] = number of bytes
    *   params[1] = float operand 1 (value)
    *   params[2] = float operand 2 (base)
    */
    REAL fValue = amx_ctof(params[1]);
    REAL fBase = amx_ctof(params[2]);
    (void)amx;
    if (fValue <= 0.0 || fBase <= 0)
        return amx_RaiseError(amx, AMX_ERR_DOMAIN);
    if (fBase == 10.0) // ??? epsilon
        fValue = (REAL)log10(fValue);
    else
        fValue = (REAL)(log(fValue) / log(fBase));
    return amx_ftoc(fValue);
}
Esempio n. 9
0
static cell AMX_NATIVE_CALL funcidx(AMX *amx,cell *params)
{
  char name[64];
  cell *cstr;
  int index,err;

  amx_GetAddr(amx,params[1],&cstr);
  #if 0 /* if you are paranoia */
    amx_StrLen(cstr,&len);
    if (len>=64) {
      amx_RaiseError(amx,AMX_ERR_NATIVE);
      return 0;
    } /* if */
  #endif
  amx_GetString(name,cstr);
  err=amx_FindPublic(amx,name,&index);
  if (err!=AMX_ERR_NONE)
    index=-1;   /* this is not considered a fatal error */
  return index;
}
Esempio n. 10
0
/* 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);
  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;

  /* 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. 11
0
/* PID: procexec(const commandline[])
 * Executes a program. Returns an "id" representing the new process (or 0 on
 * failure).
 */
static cell AMX_NATIVE_CALL n_procexec(AMX *amx, const cell *params)
{
  TCHAR *pgmname;
  #if defined __WIN32__ || defined _WIN32 || defined WIN32
    BOOL IsWinNT;
    OSVERSIONINFO VerInfo;
    STARTUPINFO si;
    SECURITY_ATTRIBUTES sa;
    SECURITY_DESCRIPTOR sd;
    PROCESS_INFORMATION pi;
  #elif defined _Windows
    HINSTANCE hinst;
  #elif defined __LINUX__ || defined __FreeBSD__ || defined __OpenBSD__ || defined __APPLE__
  	pid_t pid;
  #endif

  amx_StrParam(amx,params[1],pgmname);

  #if defined __WIN32__ || defined _WIN32 || defined WIN32
    /* most of this code comes from a "Borland Network" article, combined
     * with some knowledge gained from a CodeProject article
     */
    closepipe();

    VerInfo.dwOSVersionInfoSize=sizeof(OSVERSIONINFO);
    GetVersionEx(&VerInfo);
    IsWinNT = VerInfo.dwPlatformId==VER_PLATFORM_WIN32_NT;

    if (IsWinNT) {       //initialize security descriptor (Windows NT)
      InitializeSecurityDescriptor(&sd,SECURITY_DESCRIPTOR_REVISION);
      SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE);
      sa.lpSecurityDescriptor = &sd;
    } else {
      sa.lpSecurityDescriptor = NULL;
    } /* if */
    sa.nLength = sizeof(SECURITY_ATTRIBUTES);
    sa.bInheritHandle = TRUE;         //allow inheritable handles

    if (!CreatePipe(&newstdin,&write_stdin,&sa,0)) { //create stdin pipe
      amx_RaiseError(amx, AMX_ERR_NATIVE);
      return 0;
    } /* if */
    if (!CreatePipe(&read_stdout,&newstdout,&sa,0)) { //create stdout pipe
      closepipe();
      amx_RaiseError(amx, AMX_ERR_NATIVE);
      return 0;
    } /* if */

    GetStartupInfo(&si);      //set startupinfo for the spawned process
    si.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
    si.wShowWindow = SW_SHOWNORMAL;
    si.hStdOutput = newstdout;
    si.hStdError = newstdout;     //set the new handles for the child process
    si.hStdInput = newstdin;

    /* spawn the child process */
    if (!CreateProcess(NULL,(TCHAR*)pgmname,NULL,NULL,TRUE,CREATE_NEW_CONSOLE,NULL,NULL,&si,&pi)) {
      closepipe();
      return 0;
    } /* if */
    CloseHandle(pi.hThread);
    CloseHandle(pi.hProcess);
    Sleep(100);
    return pi.dwProcessId;
  #elif defined _Windows
    hinst=WinExec(pgmname,SW_SHOW);
    if (hinst<=32)
      hinst=0;
    return (cell)hinst;
  #elif defined __LINUX__ || defined __FreeBSD__ || defined __OpenBSD__ || defined __APPLE__
    /* set up communication pipes first */
    closepipe();
    if (pipe(pipe_to)!=0 || pipe(pipe_from)!=0) {
      closepipe();
      amx_RaiseError(amx, AMX_ERR_NATIVE);
      return 0;
    } /* if */

    /* attempt to fork */
    if ((pid=fork())<0) {
      closepipe();
      amx_RaiseError(amx, AMX_ERR_NATIVE);
      return 0;
    } /* if */

    if (pid==0) {
      /* this is the child process */
      #define MAX_ARGS  10
      TCHAR *args[MAX_ARGS];
      int i;
      dup2(pipe_to[0],STDIN_FILENO);    /* replace stdin with the in side of the pipe */
      dup2(pipe_from[1],STDOUT_FILENO); /* replace stdout with the out side of the pipe */
      close(pipe_to[0]);                /* the pipes are no longer needed */
      close(pipe_to[1]);
      close(pipe_from[0]);
      close(pipe_from[1]);
      pipe_to[0]=-1;
      pipe_to[1]=-1;
      pipe_from[0]=-1;
      pipe_from[1]=-1;
      /* split off the option(s) */
      assert(MAX_ARGS>=2);              /* args[0] is reserved */
      memset(args,0,MAX_ARGS*sizeof(TCHAR*));
      args[0]=pgmname;
      for (i=1; i<MAX_ARGS && args[i-1]!=NULL; i++) {
        if ((args[i]=strchr(args[i-1],' '))!=NULL) {
          args[i][0]='\0';
          args[i]+=1;
        } /* if */
      } /* for */
      /* replace the child fork with a new process */
      if(execvp(pgmname,args)<0)
        return 0;
    } else {
      close(pipe_to[0]);                /* close unused pipes */
      close(pipe_from[1]);
      pipe_to[0]=-1;
      pipe_from[1]=-1;
    } /* if */
    return pid;
  #else
    return (system(pgmname)==0);
  #endif
}
Esempio n. 12
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;
}
Esempio n. 13
0
static cell AMX_NATIVE_CALL n_fmuldiv(AMX *amx,const cell *params)
{
#if !USE_ANSI_C
#if defined __WATCOMC__ && defined __386__

  cell __fmuldiv(void);
  cell a=params[1];
  cell b=params[2];
  cell c=params[3];

  if (c==0) {
    amx_RaiseError(amx,AMX_ERR_DIVIDE);
    return 0;
  } /* if */

  #pragma aux __fmuldiv = \
    "mov    eax, [a]"     \
    "mov    ecx, [c]"     \
    "imul   [b]"          \
    "mov    ebx, ecx"     \
    "shr    ecx, 1"       \
    "add    eax, ecx"     \
    "adc    edx, 0"       \
    "idiv   ebx"          \
    "mov    [a], eax"     \
    modify [eax ebx ecx edx];
  __fmuldiv();
  return a;

#elif _MSC_VER>=9 && defined _WIN32

  __int64 a;
  cell divisor=params[3];
  if (divisor==0) {
    amx_RaiseError(amx,AMX_ERR_DIVIDE);
    return 0;
  } /* if */
  a=((__int64)params[1] * (__int64)params[2] + (__int64)(divisor/2)) / (__int64)divisor;
  return (cell)a;

#elif defined __BORLANDC__  && __BORLANDC__ >= 0x500  && (defined __32BIT__ || defined __WIN32__)

  __int64 a;
  cell divisor=params[3];
  if (divisor==0) {
    amx_RaiseError(amx,AMX_ERR_DIVIDE);
    return 0;
  } /* if */
  a=((__int64)params[1] * (__int64)params[2] + (__int64)(divisor/2)) / (__int64)divisor;
  return (cell)a;

#elif defined __GNUC__

  long long a;
  cell divisor=params[3];
  if (divisor==0) {
    amx_RaiseError(amx,AMX_ERR_DIVIDE);
    return 0;
  } /* if */
  a=((long long)params[1] * (long long)params[2] + (long long)(divisor/2)) / (long long)divisor;
  return (cell)a;

#else
  #error Unsupported compiler configuration, but USE_ANSI_C is false
#endif

#else // USE_ANSI_C

  ucell a,b,c,d;
  ucell v[2];
  cell sign=1;
  cell divisor=params[3];

  assert(MULTIPLIER<=(1L<<16));

  if (divisor==0) {
    amx_RaiseError(amx,AMX_ERR_DIVIDE);
    return 0;
  } /* if */

  /* make all three operands positive values, but keep the sign of the result */
  if (params[1]<0) {
    ((cell*)params)[1]=-params[1];
    sign=-sign;     /* negate result */
  } /* if */
  if (params[2]<0) {
    ((cell*)params)[2]=-params[2];
    sign=-sign;     /* negate result */
  } /* if */
  if (divisor<0) {
    divisor=-divisor;
    sign=-sign;     /* negate result */
  } /* if */

  a = HIWORD(params[1]);
  b = LOWORD(params[1]);
  c = HIWORD(params[2]);
  d = LOWORD(params[2]);

  /* store the intermediate into a 64-bit/128-bit number */
  v[1]=c*a;
  v[0]=d*b;
  ADD_WRAP(v[0],v[1],d*a << WORDSHIFT);
  ADD_WRAP(v[0],v[1],c*b << WORDSHIFT);

  /* add half of the divisor, to round the data */
  ADD_WRAP(v[0],v[1],(ucell)divisor/2);

  /* if the divisor is smaller than v[1], the result will not fit in a cell */
  if ((ucell)divisor<v[1]) {
    amx_RaiseError(amx,AMX_ERR_DOMAIN);
    return 0;
  } /* if */

  return (cell)div64_32(v,(ucell)divisor) * sign;
#endif
}
Esempio n. 14
0
static cell AMX_NATIVE_CALL n_fdiv(AMX *amx,const cell *params)
{
#if !USE_ANSI_C
#if defined __WATCOMC__ && defined __386__

  cell __fdiv(void);
  cell a=params[1];
  cell b=params[2];
  #if MULTIPLIER != 1000
    #error Assembler chunks must be modified for a different base
  #endif

  if (b==0) {
    amx_RaiseError(amx,AMX_ERR_DIVIDE);
    return 0;
  } /* if */

  #pragma aux __fdiv =    \
    "mov    eax, [a]"     \
    "mov    ecx, [b]"     \
    "cdq"                 \
    "mov    ebx, 1000"    \
    "imul   ebx"          \
    "mov    ebx, ecx"     \
    "shr    ecx, 1"       \
    "add    eax, ecx"     \
    "adc    edx, 0"       \
    "idiv   ebx"          \
    "mov    [a], eax"     \
    modify [eax ebx ecx edx];
  __fdiv();
  return a;

#elif _MSC_VER>=9 && defined _WIN32

  __int64 a;
  cell divisor=params[2];
  if (divisor==0) {
    amx_RaiseError(amx,AMX_ERR_DIVIDE);
    return 0;
  } /* if */
  a=((__int64)params[1] * (__int64)MULTIPLIER + (__int64)(divisor/2)) / (__int64)divisor;
  return (cell)a;

#elif defined __BORLANDC__  && __BORLANDC__ >= 0x500  && (defined __32BIT__ || defined __WIN32__)

  __int64 a;
  cell divisor=params[2];
  if (divisor==0) {
    amx_RaiseError(amx,AMX_ERR_DIVIDE);
    return 0;
  } /* if */
  a=((__int64)params[1] * (__int64)MULTIPLIER + (__int64)(divisor/2)) / (__int64)divisor;
  return (cell)a;

#elif defined __GNUC__

  long long a;
  cell divisor=params[2];
  if (divisor==0) {
    amx_RaiseError(amx,AMX_ERR_DIVIDE);
    return 0;
  } /* if */
  a=((long long)params[1] * (long long)MULTIPLIER + (long long)(divisor/2)) / (long long)divisor;
  return (cell)a;

#else
  #error Unsupported compiler configuration, but USE_ANSI_C is false
#endif

#else // USE_ANSI_C

  /* The dividend must be scaled prior to division. The dividend
   * is a 32-bit number, however, so when shifted, it will become
   * a value that no longer fits in a 32-bit variable. This routine
   * does the division by using only 16-bit and 32-bit values, but
   * with considerable effort.
   * If your compiler supports 64-bit integers, modify this routine
   * to use them. If your processor can do a simple 64-bit by 32-bit
   * division in assembler, write assembler chunks.
   * In other words: the straight C routine that follows is correct
   * and portable, but use it only as a last resort.
   *
   * This function was adapted from source code that appeared in
   * Dr. Dobb's Journal, August 1992, page 117.
   */

  cell dividend=params[1];
  cell divisor=params[2];
  cell sign=1;
  ucell b[2];

  if (divisor==0) {
    amx_RaiseError(amx,AMX_ERR_NATIVE);
    return 0;
  } /* if */

  /* make both operands positive values, but keep the sign of the result */
  if (dividend<0) {
    dividend=-dividend;
    sign=-sign;     /* negate result */
  } /* if */
  if (divisor<0) {
    divisor=-divisor;
    sign=-sign;     /* negate result */
  } /* if */

  /* pre-scale the dividend into a 64-bit/128-bit number */
  b[0]=dividend*MULTIPLIER;
  b[1]=(HIWORD(dividend)*MULTIPLIER) >> WORDSHIFT;

  /* add half of the divisor, to round the data */
  b[0]+=(ucell)divisor/2;
  if (b[0]<(ucell)divisor/2)
    b[1]+=1;  /* wrap-around ocurred */

  /* if the divisor is smaller than b[1], the result will not fit in a cell */
  if ((ucell)divisor<b[1]) {
    amx_RaiseError(amx,AMX_ERR_DOMAIN);
    return 0;
  } /* if */

  return (cell)div64_32(b,(ucell)divisor) * sign;
#endif
}
Esempio n. 15
0
static cell AMX_NATIVE_CALL n_fmul(AMX *amx,const cell *params)
{
#if !USE_ANSI_C
#if defined __WATCOMC__ && defined __386__

  cell __fmul(void);
  cell a=params[1];
  cell b=params[2];
  #if MULTIPLIER != 1000
    #error Assembler chunks must be modified for a different base
  #endif
  #pragma aux __fmul =    \
    "mov    eax, [a]"     \
    "mov    ebx, 1000"    \
    "imul   [b]"          \
    "add    eax, 500"     \
    "adc    edx, 0"       \
    "idiv   ebx"          \
    "mov    [a], eax"     \
    modify [eax ebx edx];
  __fmul();
  (void)amx;
  return a;

#elif _MSC_VER>=9 && defined _WIN32

  __int64 a=(__int64)params[1] * (__int64)params[2];
  a=(a+MULTIPLIER/2) / MULTIPLIER;
  (void)amx;
  return (cell)a;

#elif defined __BORLANDC__  && __BORLANDC__ >= 0x500 && (defined __32BIT__ || defined __WIN32__)

  __int64 a=(__int64)params[1] * (__int64)params[2];
  a=(a+MULTIPLIER/2) / MULTIPLIER;
  (void)amx;
  return (cell)a;

#elif defined __GNUC__

  long long a=(long long)params[1] * (long long)params[2];
  a=(a+MULTIPLIER/2) / MULTIPLIER;
  (void)amx;
  return (cell)a;

#else
  #error Unsupported compiler configuration, but USE_ANSI_C is false
#endif

#else // USE_ANSI_C

  /* (Xs * Ys) == (X*Y)ss, where "s" stands for scaled.
   * The desired result is (X*Y)s, so we must unscale once.
   * but we cannot do this before multiplication, because of loss
   * of precision, and we cannot do it after the multiplication
   * because of the possible overflow.
   * The technique used here is to cut the multiplicands into
   * components and to multiply these components separately:
   *
   * Assume Xs == (A << 16) + B and Ys == (C << 16) + D, where A, B,
   * C and D are 16 bit numbers.
   *
   *    A B
   *    C D
   *    --- *
   *    D*B + (D*A << 16) + (C*B << 16) + (C*A << (16+16))
   *
   * Thus we have built a 64-bit number, which can now be scaled back
   * to 32-bit by dividing by the scale factor.
   */
  #define ADD_WRAP(var,carry,expr)  (((var)+=(expr)), ((carry)+=((var)<(expr)) ? 1 : 0))
  ucell a,b,c,d;
  ucell v[2];
  cell sign=1;

  (void)amx;
  assert(MULTIPLIER<=(1L<<WORDSHIFT));

  /* make both operands positive values, but keep the sign of the result */
  if (params[1]<0) {
    ((cell*)params)[1]=-params[1];
    sign=-sign;     /* negate result */
  } /* if */
  if (params[2]<0) {
    ((cell*)params)[2]=-params[2];
    sign=-sign;     /* negate result */
  } /* if */

  a = HIWORD(params[1]);
  b = LOWORD(params[1]);
  c = HIWORD(params[2]);
  d = LOWORD(params[2]);

  /* store the intermediate into a 64-bit/128-bit number */
  v[1]=c*a;
  v[0]=d*b;
  ADD_WRAP(v[0],v[1],d*a << WORDSHIFT);
  ADD_WRAP(v[0],v[1],c*b << WORDSHIFT);

  /* add half of the divisor, to round the data */
  ADD_WRAP(v[0],v[1],MULTIPLIER/2);

  /* if the divisor is smaller than v[1], the result will not fit in a cell */
  if (MULTIPLIER<v[1]) {
    amx_RaiseError(amx,AMX_ERR_DOMAIN);
    return 0;
  } /* if */

  return (cell)div64_32(v,MULTIPLIER) * sign;
#endif
}