/* 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; }
/* 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; }
/* 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; }
/** 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; }
/* 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; }
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); }
/* 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; }
/** 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]); }
/** 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) ); }
/* 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; }
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; }
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; }
/* 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); }
/* 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; }
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; }
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; }
/* 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; }
/** 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 ); }
/* 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; }
/** 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; }
/* 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; }