Add AMX modules

This commit is contained in:
RD42 2024-03-12 23:39:27 +08:00
parent 7678b765ce
commit 3bdb21283f
13 changed files with 6040 additions and 0 deletions

351
server/amx/amxDGram.c Normal file
View File

@ -0,0 +1,351 @@
/* Datagram sending/receiving module for the Pawn Abstract Machine
*
* This module uses the UDP protocol (from the TCP/IP protocol suite).
*
* Copyright (c) ITB CompuPhase, 2005
*
* This software is provided "as-is", without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software in
* a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
* Version: $Id: amxDGram.c 3367 2005-07-24 12:25:04Z thiadmer $
*/
#include <assert.h>
#include <stdio.h>
#if defined LINUX
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#else
#include <malloc.h>
#include <winsock.h>
#endif
#include "osdefs.h"
#include "amx.h"
#define SRC_BUFSIZE 22
#define BUFLEN 512
#define AMX_DGRAMPORT 9930 /* default port */
static int sLocal;
static unsigned long udp_GetHostAddr(const char *host,int index)
{
unsigned long addr=inet_addr(host);
if (addr==0xffffffffL) {
struct hostent FAR *phost=gethostbyname(host);
if (phost!=NULL) {
/* count the number of addresses in the list */
int count;
for (count=0; phost->h_addr_list[count]!=0; count++)
/* nothing */;
if (index<count)
addr=*(unsigned long *)phost->h_addr_list[index];
} /* if */
} /* if */
return addr;
}
static int udp_Open(void)
{
#if defined __WIN32 || defined _WIN32 || defined WIN32
WORD wVersionRequested = MAKEWORD(1,1);
WSADATA wsaData;
#endif
int optval = 1;
#if defined __WIN32 || defined _WIN32 || defined WIN32
WSAStartup(wVersionRequested, &wsaData);
#endif
if ((sLocal=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
return -1;
if (setsockopt(sLocal, SOL_SOCKET, SO_BROADCAST, (void*)&optval, sizeof optval) == -1)
return -1;
return sLocal;
}
static int udp_Close(void)
{
if (sLocal>=0) {
#if defined __WIN32 || defined _WIN32 || defined WIN32
closesocket(sLocal);
#else
close(sLocal);
#endif
} /* if */
#if defined __WIN32 || defined _WIN32 || defined WIN32
WSACleanup();
#endif
return 0;
}
static int udp_Send(const char *host,short port,const char *message,int size)
{
struct sockaddr_in sRemote;
if (sLocal<0)
return -1;
memset((void *)&sRemote,sizeof sRemote,0);
sRemote.sin_family=AF_INET;
sRemote.sin_port=htons(port);
sRemote.sin_addr.s_addr= (host==NULL) ? htonl(INADDR_BROADCAST) : udp_GetHostAddr(host,0);
if (sendto(sLocal,message,size,0,(struct sockaddr *)&sRemote,sizeof sRemote)==-1)
return -1;
return size;
}
/* This call is blocking
* if source is not NULL, it must point to a buffer that can contain at least
* 22 characters.
*/
static int udp_Receive(char *message,size_t maxmsg,char *source)
{
struct sockaddr_in sSource;
int slen=sizeof(sSource);
int size;
size=recvfrom(sLocal, message, maxmsg, 0, (struct sockaddr *)&sSource, &slen);
if (size==-1)
return -1;
if (source!=NULL)
sprintf(source, "%s:%d", inet_ntoa(sSource.sin_addr), ntohs(sSource.sin_port));
return size;
}
static int udp_IsPacket(void)
{
int result;
fd_set rdset;
struct timeval time;
/* the select() function waits until the socket can be read, or until a
* time-out occurs; the time-out is set to 1 microsecond (the shortest
* delay possible).
*/
time.tv_sec=0;
time.tv_usec=1;
FD_ZERO(&rdset);
FD_SET(sLocal,&rdset);
result=select(0,&rdset,NULL,NULL,&time);
if (result==SOCKET_ERROR)
return -1;
return result != 0;
}
static int udp_Listen(short port)
{
struct sockaddr_in sFrom;
memset((void *)&sFrom,sizeof sFrom,0);
sFrom.sin_family=AF_INET;
sFrom.sin_port=htons(port);
sFrom.sin_addr.s_addr=htonl(INADDR_ANY);
if (bind(sLocal,(struct sockaddr *)&sFrom,sizeof sFrom)==-1)
return -1;
return 0;
}
static AMX_DEBUG PrevIdle = NULL;
static int idxReceiveString = -1;
static int idxReceivePacket = -1;
static short dgramPort = 0;
static int dgramBound = 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, cell *params)
{
int r = 0, length;
cell *cstr;
char *host, *message, *ptr;
short port=AMX_DGRAMPORT;
amx_GetAddr(amx, params[1], &cstr);
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;
}
/* 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, cell *params)
{
cell *cstr;
char *host, *ptr;
short port=AMX_DGRAMPORT;
amx_GetAddr(amx, params[1], &cstr);
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);
}
/* listenport(port)
* A program must call this function from main() or another start-up function
* because the module will use the default port 9930 otherwise.
*/
static cell AMX_NATIVE_CALL n_listenport(AMX *amx, cell *params)
{
(void)amx;
dgramPort = (short)params[1];
return 0;
}
static int AMXAPI amx_DGramIdle(AMX *amx)
{
char message[BUFLEN], source[SRC_BUFSIZE];
cell amx_addr_msg, amx_addr_src;
int len, chars;
int err=0;
assert(idxReceiveString >= 0 || idxReceivePacket >= 0);
if (PrevIdle != NULL)
PrevIdle(amx);
/* set up listener (first call only) */
if (!dgramBound) {
if (dgramPort==0)
dgramPort=AMX_DGRAMPORT; /* use default port if none was set */
if (udp_Listen(dgramPort)==-1)
return AMX_ERR_GENERAL;
dgramBound=1;
} /* if */
if (udp_IsPacket()) {
len=udp_Receive(message, sizeof message / sizeof message[0], source);
amx_PushString(amx,&amx_addr_src,NULL,source,1,0);
/* check the presence of a byte order mark: if it is absent, the received
* packet is no string; also check the packet size against string length
*/
if ((message[0]!='\xef' || message[1]!='\xbb' || message[2]!='\xbf'
|| len!=(int)strlen(message)+1 || idxReceiveString<0) && idxReceivePacket>=0)
{
/* receive as "packet" */
amx_Push(amx,len);
amx_PushArray(amx,&amx_addr_msg,NULL,(cell*)message,len);
err=amx_Exec(amx,NULL,idxReceivePacket);
} else {
const char *msg=message;
if (msg[0]=='\xef' && msg[1]=='\xbb' && msg[2]=='\xbf')
msg+=3; /* skip BOM */
/* optionally convert from UTF-8 to a wide string */
if (amx_UTF8Check(msg,&chars)==AMX_ERR_NONE) {
cell *array=alloca((chars+1)*sizeof(cell));
cell *ptr=array;
if (array!=NULL) {
while (err==AMX_ERR_NONE && *msg!='\0')
amx_UTF8Get(msg,&msg,ptr++);
*ptr=0; /* zero-terminate */
amx_PushArray(amx,&amx_addr_msg,NULL,array,chars+1);
} /* if */
} else {
amx_PushString(amx,&amx_addr_msg,NULL,msg,1,0);
} /* if */
err=amx_Exec(amx,NULL,idxReceiveString);
} /* if */
while (err==AMX_ERR_SLEEP)
err=amx_Exec(amx,NULL,AMX_EXEC_CONT);
amx_Release(amx,amx_addr);
amx_Release(amx,amx_addr_src);
} /* if */
return err;
}
#if defined __cplusplus
extern "C"
#endif
AMX_NATIVE_INFO dgram_Natives[] = {
{ "sendstring", n_sendstring },
{ "sendpacket", n_sendpacket },
{ "listenport", n_listenport },
{ NULL, NULL } /* terminator */
};
int AMXEXPORT amx_DGramInit(AMX *amx)
{
dgramBound = 0;
if (udp_Open()==-1)
return AMX_ERR_GENERAL;
/* see whether there is an @receivestring() function */
if (amx_FindPublic(amx,"@receivestring",&idxReceiveString)==AMX_ERR_NONE
|| amx_FindPublic(amx,"@receivepacket",&idxReceivePacket)==AMX_ERR_NONE)
{
if (amx_GetUserData(amx,AMX_USERTAG('I','d','l','e'),(void**)&PrevIdle)!=AMX_ERR_NONE)
PrevIdle=NULL;
amx_SetUserData(amx,AMX_USERTAG('I','d','l','e'),amx_DGramIdle);
} /* if */
return amx_Register(amx,dgram_Natives,-1);
}
int AMXEXPORT amx_DGramCleanup(AMX *amx)
{
(void)amx;
udp_Close();
return AMX_ERR_NONE;
}

1159
server/amx/amxcons.c Normal file

File diff suppressed because it is too large Load Diff

500
server/amx/amxcore.c Normal file
View File

@ -0,0 +1,500 @@
/* Core module for the Pawn AMX
*
* Copyright (c) ITB CompuPhase, 1997-2005
*
* This software is provided "as-is", without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software in
* a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
* Version: $Id: amxcore.c 3363 2005-07-23 09:03:29Z thiadmer $
*/
#if defined _UNICODE || defined __UNICODE__ || defined UNICODE
# if !defined UNICODE /* for Windows */
# define UNICODE
# endif
# if !defined _UNICODE /* for C library */
# define _UNICODE
# endif
#endif
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <assert.h>
#include "amx.h"
#if defined __WIN32__ || defined _WIN32 || defined WIN32 || defined _Windows
#include <windows.h>
#endif
/* A few compilers do not provide the ANSI C standard "time" functions */
#if !defined SN_TARGET_PS2 && !defined _WIN32_WCE
#include <time.h>
#endif
#if defined _UNICODE
# include <tchar.h>
#elif !defined __T
typedef char TCHAR;
# define __T(string) string
# define _tcschr strchr
# define _tcscpy strcpy
# define _tcsdup strdup
# define _tcslen strlen
#endif
#define CHARBITS (8*sizeof(char))
typedef unsigned char uchar;
#if !defined AMX_NOPROPLIST
typedef struct _property_list {
struct _property_list *next;
cell id;
char *name;
cell value;
//??? safe AMX (owner of the property)
} proplist;
static proplist proproot = { NULL, 0, NULL, 0 };
static proplist *list_additem(proplist *root)
{
proplist *item;
assert(root!=NULL);
if ((item=(proplist *)malloc(sizeof(proplist)))==NULL)
return NULL;
item->name=NULL;
item->id=0;
item->value=0;
item->next=root->next;
root->next=item;
return item;
}
static void list_delete(proplist *pred,proplist *item)
{
assert(pred!=NULL);
assert(item!=NULL);
pred->next=item->next;
assert(item->name!=NULL);
free(item->name);
free(item);
}
static void list_setitem(proplist *item,cell id,char *name,cell value)
{
char *ptr;
assert(item!=NULL);
if ((ptr=(char *)malloc(strlen(name)+1))==NULL)
return;
if (item->name!=NULL)
free(item->name);
strcpy(ptr,name);
item->name=ptr;
item->id=id;
item->value=value;
}
static proplist *list_finditem(proplist *root,cell id,char *name,cell value,
proplist **pred)
{
proplist *item=root->next;
proplist *prev=root;
/* check whether to find by name or by value */
assert(name!=NULL);
if (strlen(name)>0) {
/* find by name */
while (item!=NULL && (item->id!=id || stricmp(item->name,name)!=0)) {
prev=item;
item=item->next;
} /* while */
} else {
/* find by value */
while (item!=NULL && (item->id!=id || item->value!=value)) {
prev=item;
item=item->next;
} /* while */
} /* if */
if (pred!=NULL)
*pred=prev;
return item;
}
#endif
static cell AMX_NATIVE_CALL numargs(AMX *amx, cell *params)
{
AMX_HEADER *hdr;
uchar *data;
cell bytes;
(void)params;
hdr=(AMX_HEADER *)amx->base;
data=amx->data ? amx->data : amx->base+(int)hdr->dat;
/* the number of bytes is on the stack, at "frm + 2*cell" */
bytes= * (cell *)(data+(int)amx->frm+2*sizeof(cell));
/* the number of arguments is the number of bytes divided
* by the size of a cell */
return bytes/sizeof(cell);
}
static cell AMX_NATIVE_CALL getarg(AMX *amx, cell *params)
{
AMX_HEADER *hdr;
uchar *data;
cell value;
hdr=(AMX_HEADER *)amx->base;
data=amx->data ? amx->data : amx->base+(int)hdr->dat;
/* get the base value */
value= * (cell *)(data+(int)amx->frm+((int)params[1]+3)*sizeof(cell));
/* adjust the address in "value" in case of an array access */
value+=params[2]*sizeof(cell);
/* get the value indirectly */
value= * (cell *)(data+(int)value);
return value;
}
static cell AMX_NATIVE_CALL setarg(AMX *amx, cell *params)
{
AMX_HEADER *hdr;
uchar *data;
cell value;
hdr=(AMX_HEADER *)amx->base;
data=amx->data ? amx->data : amx->base+(int)hdr->dat;
/* get the base value */
value= * (cell *)(data+(int)amx->frm+((int)params[1]+3)*sizeof(cell));
/* adjust the address in "value" in case of an array access */
value+=params[2]*sizeof(cell);
/* verify the address */
if (value<0 || value>=amx->hea && value<amx->stk)
return 0;
/* set the value indirectly */
* (cell *)(data+(int)value) = params[3];
return 1;
}
static cell AMX_NATIVE_CALL heapspace(AMX *amx,cell *params)
{
(void)params;
return amx->stk - amx->hea;
}
static cell AMX_NATIVE_CALL funcidx(AMX *amx,cell *params)
{
char name[64];
cell *cstr;
int index,err,len;
amx_GetAddr(amx,params[1],&cstr);
/* verify string length */
amx_StrLen(cstr,&len);
if (len>=64) {
amx_RaiseError(amx,AMX_ERR_NATIVE);
return 0;
} /* if */
amx_GetString(name,cstr,0,UNLIMITED);
err=amx_FindPublic(amx,name,&index);
if (err!=AMX_ERR_NONE)
index=-1; /* this is not considered a fatal error */
return index;
}
static cell AMX_NATIVE_CALL swapchars(AMX *amx,cell *params)
{
union {
cell c;
#if PAWN_CELL_SIZE==16
uchar b[2];
#elif PAWN_CELL_SIZE==32
uchar b[4];
#elif PAWN_CELL_SIZE==64
uchar b[8];
#else
#error Unsupported cell size
#endif
} value;
uchar t;
(void)amx;
assert((size_t)params[0]==sizeof(cell));
value.c = params[1];
#if PAWN_CELL_SIZE==16
t = value.b[0];
value.b[0] = value.b[1];
value.b[1] = t;
#elif PAWN_CELL_SIZE==32
t = value.b[0];
value.b[0] = value.b[3];
value.b[3] = t;
t = value.b[1];
value.b[1] = value.b[2];
value.b[2] = t;
#elif PAWN_CELL_SIZE==64
t = value.b[0];
value.b[0] = value.b[7];
value.b[7] = t;
t = value.b[1];
value.b[1] = value.b[6];
value.b[6] = t;
t = value.b[2];
value.b[2] = value.b[5];
value.b[5] = t;
t = value.b[3];
value.b[3] = value.b[4];
value.b[4] = t;
#else
#error Unsupported cell size
#endif
return value.c;
}
static cell AMX_NATIVE_CALL core_tolower(AMX *amx,cell *params)
{
(void)amx;
#if defined __WIN32__ || defined _WIN32 || defined WIN32
return (cell)CharLower((LPTSTR)params[1]);
#elif defined _Windows
return (cell)AnsiLower((LPSTR)params[1]);
#else
return tolower((int)params[1]);
#endif
}
static cell AMX_NATIVE_CALL core_toupper(AMX *amx,cell *params)
{
(void)amx;
#if defined __WIN32__ || defined _WIN32 || defined WIN32
return (cell)CharUpper((LPTSTR)params[1]);
#elif defined _Windows
return (cell)AnsiUpper((LPSTR)params[1]);
#else
return toupper((int)params[1]);
#endif
}
static cell AMX_NATIVE_CALL core_min(AMX *amx,cell *params)
{
(void)amx;
return params[1] <= params[2] ? params[1] : params[2];
}
static cell AMX_NATIVE_CALL core_max(AMX *amx,cell *params)
{
(void)amx;
return params[1] >= params[2] ? params[1] : params[2];
}
static cell AMX_NATIVE_CALL core_clamp(AMX *amx,cell *params)
{
cell value = params[1];
if (params[2] > params[3]) /* minimum value > maximum value ! */
amx_RaiseError(amx,AMX_ERR_NATIVE);
if (value < params[2])
value = params[2];
else if (value > params[3])
value = params[3];
return value;
}
#if !defined AMX_NOPROPLIST
static char *MakePackedString(cell *cptr)
{
int len;
char *dest;
amx_StrLen(cptr,&len);
dest=(char *)malloc(len+sizeof(cell));
amx_GetString(dest,cptr,0,UNLIMITED);
return dest;
}
static int verify_addr(AMX *amx,cell addr)
{
int err;
cell *cdest;
err=amx_GetAddr(amx,addr,&cdest);
if (err!=AMX_ERR_NONE)
amx_RaiseError(amx,err);
return err;
}
static cell AMX_NATIVE_CALL getproperty(AMX *amx,cell *params)
{
cell *cstr;
char *name;
proplist *item;
amx_GetAddr(amx,params[2],&cstr);
name=MakePackedString(cstr);
item=list_finditem(&proproot,params[1],name,params[3],NULL);
/* if list_finditem() found the value, store the name */
if (item!=NULL && item->value==params[3] && strlen(name)==0) {
int needed=(strlen(item->name)+sizeof(cell)-1)/sizeof(cell); /* # of cells needed */
if (verify_addr(amx,(cell)(params[4]+needed))!=AMX_ERR_NONE) {
free(name);
return 0;
} /* if */
amx_GetAddr(amx,params[4],&cstr);
amx_SetString(cstr,item->name,1,0,UNLIMITED);
} /* if */
free(name);
return (item!=NULL) ? item->value : 0;
}
static cell AMX_NATIVE_CALL setproperty(AMX *amx,cell *params)
{
cell prev=0;
cell *cstr;
char *name;
proplist *item;
amx_GetAddr(amx,params[2],&cstr);
name=MakePackedString(cstr);
item=list_finditem(&proproot,params[1],name,params[3],NULL);
if (item==NULL)
item=list_additem(&proproot);
if (item==NULL) {
amx_RaiseError(amx,AMX_ERR_MEMORY);
} else {
prev=item->value;
if (strlen(name)==0) {
free(name);
amx_GetAddr(amx,params[4],&cstr);
name=MakePackedString(cstr);
} /* if */
list_setitem(item,params[1],name,params[3]);
} /* if */
free(name);
return prev;
}
static cell AMX_NATIVE_CALL delproperty(AMX *amx,cell *params)
{
cell prev=0;
cell *cstr;
char *name;
proplist *item,*pred;
amx_GetAddr(amx,params[2],&cstr);
name=MakePackedString(cstr);
item=list_finditem(&proproot,params[1],name,params[3],&pred);
if (item!=NULL) {
prev=item->value;
list_delete(pred,item);
} /* if */
free(name);
return prev;
}
static cell AMX_NATIVE_CALL existproperty(AMX *amx,cell *params)
{
cell *cstr;
char *name;
proplist *item;
amx_GetAddr(amx,params[2],&cstr);
name=MakePackedString(cstr);
item=list_finditem(&proproot,params[1],name,params[3],NULL);
free(name);
return (item!=NULL);
}
#endif
#if !defined AMX_NORANDOM
/* This routine comes from the book "Inner Loops" by Rick Booth, Addison-Wesley
* (ISBN 0-201-47960-5). This is a "multiplicative congruential random number
* generator" that has been extended to 31-bits (the standard C version returns
* only 15-bits).
*/
#define INITIAL_SEED 0xcaa938dbL
static unsigned long IL_StandardRandom_seed = INITIAL_SEED; /* always use a non-zero seed */
#define IL_RMULT 1103515245L
#if defined __BORLANDC__ || defined __WATCOMC__
#pragma argsused
#endif
static cell AMX_NATIVE_CALL core_random(AMX *amx,cell *params)
{
unsigned long lo, hi, ll, lh, hh, hl;
unsigned long result;
/* one-time initialization (or, mostly one-time) */
#if !defined SN_TARGET_PS2 && !defined _WIN32_WCE
if (IL_StandardRandom_seed == INITIAL_SEED)
IL_StandardRandom_seed=(unsigned long)time(NULL);
#endif
lo = IL_StandardRandom_seed & 0xffff;
hi = IL_StandardRandom_seed >> 16;
IL_StandardRandom_seed = IL_StandardRandom_seed * IL_RMULT + 12345;
ll = lo * (IL_RMULT & 0xffff);
lh = lo * (IL_RMULT >> 16 );
hl = hi * (IL_RMULT & 0xffff);
hh = hi * (IL_RMULT >> 16 );
result = ((ll + 12345) >> 16) + lh + hl + (hh << 16);
result &= ~LONG_MIN; /* remove sign bit */
if (params[1]!=0)
result %= params[1];
return (cell)result;
}
#endif
#if defined __cplusplus
extern "C"
#endif
const AMX_NATIVE_INFO core_Natives[] = {
{ "numargs", numargs },
{ "getarg", getarg },
{ "setarg", setarg },
{ "heapspace", heapspace },
{ "funcidx", funcidx },
{ "swapchars", swapchars },
{ "tolower", core_tolower },
{ "toupper", core_toupper },
{ "min", core_min },
{ "max", core_max },
{ "clamp", core_clamp },
#if !defined AMX_NORANDOM
{ "random", core_random },
#endif
#if !defined AMX_NOPROPLIST
{ "getproperty", getproperty },
{ "setproperty", setproperty },
{ "deleteproperty",delproperty },
{ "existproperty", existproperty },
#endif
{ NULL, NULL } /* terminator */
};
int AMXEXPORT amx_CoreInit(AMX *amx)
{
return amx_Register(amx, core_Natives, -1);
}
int AMXEXPORT amx_CoreCleanup(AMX *amx)
{
(void)amx;
#if !defined AMX_NOPROPLIST
//??? delete only the properties owned by the AMX
while (proproot.next!=NULL)
list_delete(&proproot,proproot.next);
#endif
return AMX_ERR_NONE;
}

86
server/amx/amxdefn.asm Normal file
View File

@ -0,0 +1,86 @@
; Definition of the AMX structure for assembler syntax (NASM)
struc amx_s
_base: resd 1
_dataseg: resd 1
_callback: resd 1
_debug: resd 1
_cip: resd 1
_frm: resd 1
_hea: resd 1
_hlw: resd 1
_stk: resd 1
_stp: resd 1
_flags: resd 1
_usertags: resd 4 ; 4 = AMX_USERNUM (#define'd in amx.h)
_userdata: resd 4 ; 4 = AMX_USERNUM (#define'd in amx.h)
_error: resd 1
_paramcount: resd 1
_pri: resd 1
_alt: resd 1
_reset_stk: resd 1
_reset_hea: resd 1
_syscall_d: resd 1
%ifdef JIT
; the two fields below are for the JIT; they do not exist in
; the non-JIT version of the abstract machine
_reloc_size: resd 1 ; memory block for relocations
_code_size: resd 1 ; memory size of the native code
%endif
endstruc
struc amxhead_s
_size: resd 1 ; size of the "file"
_magic: resw 1 ; signature
_file_version: resb 1; file format version
_amx_version: resb 1 ; required version of the AMX
_h_flags: resw 1
_defsize: resw 1 ; size of one public/native function entry
_cod: resd 1 ; initial value of COD - code block
_dat: resd 1 ; initial value of DAT - data block
_h_hea: resd 1 ; initial value of HEA - start of the heap
_h_stp: resd 1 ; initial value of STP - stack top
_h_cip: resd 1 ; initial value of CIP - the instruction pointer
_publics: resd 1 ; offset to the "public functions" table
_natives: resd 1 ; offset to the "native functions" table
_libraries: resd 1 ; offset to the "library" table
_pubvars: resd 1 ; offset to the "public variables" table
_tags: resd 1 ; offset to the "public tagnames" table
_nametable: resd 1 ; offset to the name table, file version 7 only
endstruc
AMX_ERR_NONE EQU 0
AMX_ERR_EXIT EQU 1
AMX_ERR_ASSERT EQU 2
AMX_ERR_STACKERR EQU 3
AMX_ERR_BOUNDS EQU 4
AMX_ERR_MEMACCESS EQU 5
AMX_ERR_INVINSTR EQU 6
AMX_ERR_STACKLOW EQU 7
AMX_ERR_HEAPLOW EQU 8
AMX_ERR_CALLBACK EQU 9
AMX_ERR_NATIVE EQU 10
AMX_ERR_DIVIDE EQU 11 ; for catching divide errors
AMX_ERR_SLEEP EQU 12
AMX_ERR_MEMORY EQU 16
AMX_ERR_FORMAT EQU 17
AMX_ERR_VERSION EQU 18
AMX_ERR_NOTFOUND EQU 19
AMX_ERR_INDEX EQU 20
AMX_ERR_DEBUG EQU 21
AMX_ERR_INIT EQU 22
AMX_ERR_USERDATA EQU 23
AMX_ERR_INIT_JIT EQU 24
AMX_ERR_PARAMS EQU 25
AMX_ERR_DOMAIN EQU 26
AMX_ERR_GENERAL EQU 27
AMX_FLAG_DEBUG EQU 0002h ; symbolic info. available
AMX_FLAG_COMPACT EQU 0004h
AMX_FLAG_BYTEOPC EQU 0008h
AMX_FLAG_NOCHECKS EQU 0010h
AMX_FLAG_BROWSE EQU 4000h
AMX_FLAG_RELOC EQU 8000h ; jump/call addresses relocated

1633
server/amx/amxexecn.asm Normal file

File diff suppressed because it is too large Load Diff

702
server/amx/amxfile.c Normal file
View File

@ -0,0 +1,702 @@
/* Text file I/O module for the Pawn Abstract Machine
*
* Copyright (c) ITB CompuPhase, 2003-2005
*
* This software is provided "as-is", without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software in
* a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
* Version: $Id: amxfile.c 3363 2005-07-23 09:03:29Z thiadmer $
*/
#if defined _UNICODE || defined __UNICODE__ || defined UNICODE
# if !defined UNICODE /* for Windows */
# define UNICODE
# endif
# if !defined _UNICODE /* for C library */
# define _UNICODE
# endif
#endif
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#if defined __WIN32__ || defined _WIN32 || defined WIN32 || defined __MSDOS__
#include <io.h>
#include <malloc.h>
#endif
#if defined __WIN32__ || defined _WIN32 || defined WIN32 || defined _Windows
#include <windows.h>
#endif
#include "osdefs.h"
#include "amx.h"
#if !defined AMXFILE_VAR
#define AMXFILE_VAR "AMXFILE"
#elif AMXFILE_VAR==""
#undef AMXFILE_VAR
#endif
#if defined _UNICODE
# include <tchar.h>
#elif !defined __T
typedef char TCHAR;
# define __T(string) string
# define _tfopen fopen
# define _tgetenv getenv
# define _tfputs fputs
# define _tcscat strcat
# define _tcschr strchr
# define _tcscpy strcpy
# define _tcsdup strdup
# define _tcslen strlen
# define _tcspbrk strpbrk
# define _tcsrchr strrchr
#endif
#if !defined UNUSED_PARAM
#define UNUSED_PARAM(p) ((void)(p))
#endif
enum filemode {
io_read, /* file must exist */
io_write, /* creates a new file */
io_readwrite, /* file must exist */
io_append, /* file must exist, opened for writing only and seek to the end */
};
enum seek_whence {
seek_start,
seek_current,
seek_end,
};
/* This function only stores unpacked strings. UTF-8 is used for
* Unicode, and packed strings can only store 7-bit and 8-bit
* character sets (ASCII, Latin-1).
*/
static size_t fgets_cell(FILE *fp,cell *string,size_t max,int utf8mode)
{
size_t index;
fpos_t pos;
cell c;
int follow,lastcr;
cell lowmark;
assert(sizeof(cell)>=4);
assert(fp!=NULL);
assert(string!=NULL);
if (max<=0)
return 0;
/* get the position, in case we have to back up */
fgetpos(fp, &pos);
index=0;
follow=0;
lowmark=0;
lastcr=0;
for ( ;; ) {
assert(index<max);
if (index==max-1)
break; /* string fully filled */
if ((c=fgetc(fp))==EOF) {
if (!utf8mode || follow==0)
break; /* no more characters */
/* If an EOF happened halfway an UTF-8 code, the string cannot be
* UTF-8 mode, and we must restart.
*/
index=0;
fsetpos(fp, &pos);
continue;
} /* if */
/* 8-bit characters are unsigned */
if (c<0)
c=-c;
if (utf8mode) {
if (follow>0 && (c & 0xc0)==0x80) {
/* leader code is active, combine with earlier code */
string[index]=(string[index] << 6) | ((unsigned char)c & 0x3f);
if (--follow==0) {
/* encoding a character in more bytes than is strictly needed,
* is not really valid UTF-8; we are strict here to increase
* the chance of heuristic dectection of non-UTF-8 text
* (JAVA writes zero bytes as a 2-byte code UTF-8, which is invalid)
*/
if (string[index]<lowmark)
utf8mode=0;
/* the code positions 0xd800--0xdfff and 0xfffe & 0xffff do not
* exist in UCS-4 (and hence, they do not exist in Unicode)
*/
if (string[index]>=0xd800 && string[index]<=0xdfff
|| string[index]==0xfffe || string[index]==0xffff)
utf8mode=0;
index++;
} /* if */
} else if (follow==0 && (c & 0x80)==0x80) {
/* UTF-8 leader code */
if ((c & 0xe0)==0xc0) {
/* 110xxxxx 10xxxxxx */
follow=1;
lowmark=0x80;
string[index]=c & 0x1f;
} else if ((c & 0xf0)==0xe0) {
/* 1110xxxx 10xxxxxx 10xxxxxx (16 bits, BMP plane) */
follow=2;
lowmark=0x800;
string[index]=c & 0x0f;
} else if ((c & 0xf8)==0xf0) {
/* 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
follow=3;
lowmark=0x10000;
string[index]=c & 0x07;
} else if ((c & 0xfc)==0xf8) {
/* 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */
follow=4;
lowmark=0x200000;
string[index]=c & 0x03;
} else if ((c & 0xfe)==0xfc) {
/* 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx (31 bits) */
follow=5;
lowmark=0x4000000;
string[index]=c & 0x01;
} else {
/* this is invalid UTF-8 */
utf8mode=0;
} /* if */
} else if (follow==0 && (c & 0x80)==0x00) {
/* 0xxxxxxx (US-ASCII) */
string[index++]=c;
if (c==__T('\n'))
break; /* read newline, done */
} else {
/* this is invalid UTF-8 */
utf8mode=0;
} /* if */
if (!utf8mode) {
/* UTF-8 mode was switched just off, which means that non-conforming
* UTF-8 codes were found, which means in turn that the string is
* probably not intended as UTF-8; start over again
*/
index=0;
fsetpos(fp, &pos);
} /* if */
} else {
string[index++]=c;
if (c==__T('\n')) {
break; /* read newline, done */
} else if (lastcr) {
ungetc(c,fp); /* carriage return was read, no newline follows */
break;
} /* if */
lastcr=(c==__T('\r'));
} /* if */
} /* for */
assert(index<max);
string[index]=__T('\0');
return index;
}
static size_t fputs_cell(FILE *fp,cell *string,int utf8mode)
{
size_t count=0;
assert(sizeof(cell)>=4);
assert(fp!=NULL);
assert(string!=NULL);
while (*string!=0) {
if (utf8mode) {
cell c=*string;
if (c<0x80) {
/* 0xxxxxxx */
fputc((unsigned char)c,fp);
} else if (c<0x800) {
/* 110xxxxx 10xxxxxx */
fputc((unsigned char)((c>>6) & 0x1f | 0xc0),fp);
fputc((unsigned char)(c & 0x3f | 0x80),fp);
} else if (c<0x10000) {
/* 1110xxxx 10xxxxxx 10xxxxxx (16 bits, BMP plane) */
fputc((unsigned char)((c>>12) & 0x0f | 0xe0),fp);
fputc((unsigned char)((c>>6) & 0x3f | 0x80),fp);
fputc((unsigned char)(c & 0x3f | 0x80),fp);
} else if (c<0x200000) {
/* 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
fputc((unsigned char)((c>>18) & 0x07 | 0xf0),fp);
fputc((unsigned char)((c>>12) & 0x3f | 0x80),fp);
fputc((unsigned char)((c>>6) & 0x3f | 0x80),fp);
fputc((unsigned char)(c & 0x3f | 0x80),fp);
} else if (c<0x4000000) {
/* 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */
fputc((unsigned char)((c>>24) & 0x03 | 0xf8),fp);
fputc((unsigned char)((c>>18) & 0x3f | 0x80),fp);
fputc((unsigned char)((c>>12) & 0x3f | 0x80),fp);
fputc((unsigned char)((c>>6) & 0x3f | 0x80),fp);
fputc((unsigned char)(c & 0x3f | 0x80),fp);
} else {
/* 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx (31 bits) */
fputc((unsigned char)((c>>30) & 0x01 | 0xfc),fp);
fputc((unsigned char)((c>>24) & 0x3f | 0x80),fp);
fputc((unsigned char)((c>>18) & 0x3f | 0x80),fp);
fputc((unsigned char)((c>>12) & 0x3f | 0x80),fp);
fputc((unsigned char)((c>>6) & 0x3f | 0x80),fp);
fputc((unsigned char)(c & 0x3f | 0x80),fp);
} /* if */
} else {
/* not UTF-8 mode */
fputc((unsigned char)*string,fp);
} /* if */
string++;
count++;
} /* while */
return count;
}
static size_t fgets_char(FILE *fp, char *string, size_t max)
{
size_t index;
int c,lastcr;
index=0;
lastcr=0;
for ( ;; ) {
assert(index<max);
if (index==max-1)
break; /* string fully filled */
if ((c=fgetc(fp))==EOF)
break; /* no more characters */
string[index++]=(char)c;
if (c==__T('\n')) {
break; /* read newline, done */
} else if (lastcr) {
ungetc(c,fp); /* carriage return was read, no newline follows */
break;
} /* if */
lastcr=(c==__T('\r'));
} /* for */
assert(index<max);
string[index]=__T('\0');
return index;
}
#if defined __WIN32__ || defined _WIN32 || defined WIN32
#if defined _UNICODE
wchar_t *_wgetenv(wchar_t *name)
{
static wchar_t buffer[_MAX_PATH];
buffer[0]=L'\0';
GetEnvironmentVariable(name,buffer,sizeof buffer/sizeof(wchar_t));
return buffer[0]!=L'\0' ? buffer : NULL;
}
#else
char *getenv(const char *name)
{
static char buffer[_MAX_PATH];
buffer[0]='\0';
GetEnvironmentVariable(name,buffer,sizeof buffer);
return buffer[0]!='\0' ? buffer : NULL;
}
#endif
#endif
static char *completename(TCHAR *dest, TCHAR *src, size_t size)
{
#if defined AMXFILE_VAR
TCHAR *prefix,*ptr;
size_t len;
/* only files below a specific path are accessible */
prefix=getenv(AMXFILE_VAR);
/* if no specific path for files is present, use the "temporary" path */
if (prefix==NULL)
prefix=getenv(__T("tmp")); /* common under Windows and Unix */
if (prefix==NULL)
prefix=getenv(__T("temp")); /* common under Windows */
if (prefix==NULL)
prefix=getenv(__T("tmpdir")); /* common under Unix */
/* if no path for files is defined, and no temporary directory exists,
* fail the function; this is for security reasons.
*/
if (prefix==NULL)
return NULL;
if (_tcslen(prefix)+1>=size) /* +1 because directory separator is appended */
return NULL;
_tcscpy(dest,prefix);
/* append a directory separator (if not already present) */
len=_tcslen(dest);
if (len==0)
return NULL; /* empty start directory is not allowed */
if (dest[len-1]!=__T(DIRSEP_CHAR) && dest[len-1]!=__T('/') && len+1<size) {
dest[len]=__T(DIRSEP_CHAR);
dest[len+1]=__T('\0');
} /* if */
assert(_tcslen(dest)<size);
/* for DOS/Windows and Unix/Linux, skip everyting up to a comma, because
* this is used to indicate a protocol (e.g. file://C:/myfile.txt)
*/
#if DIRSEP_CHAR!=':'
if ((ptr=_tcsrchr(src,__T(':')))!=NULL) {
src=ptr+1; /* skip protocol/drive and colon */
/* a "drive" specifier is sometimes ended with a vertical bar instead
* of a colon in URL specifications
*/
if ((ptr=_tcschr(src,__T('|')))!=NULL)
src=ptr+1; /* skip drive and vertical bar */
while (src[0]==__T(DIRSEP_CHAR) || src[0]==__T('/'))
src++; /* skip slashes behind the protocol/drive letter */
} /* if */
#endif
/* skip an initial backslash or a drive specifier in the source */
if ((src[0]==__T(DIRSEP_CHAR) || src[0]==__T('/')) && (src[1]==__T(DIRSEP_CHAR) || src[1]==__T('/'))) {
/* UNC path */
char separators[]={__T(DIRSEP_CHAR),__T('/'),__T('\0')};
src+=2;
ptr=_tcspbrk(src,separators);
if (ptr!=NULL)
src=ptr+1;
} else if (src[0]==__T(DIRSEP_CHAR) || src[0]==__T('/')) {
/* simple path starting from the root directory */
src++;
} /* if */
/* disallow any "../" specifications in the source path
* (the check below should be stricter, but directory names with
* trailing periods are rare anyway)
*/
for (ptr=src; *ptr!=__T('\0'); ptr++)
if (ptr[0]==__T('.') && (ptr[1]==__T(DIRSEP_CHAR) || ptr[1]==__T('/')))
return NULL; /* path name is not allowed */
/* concatenate the drive letter to the destination path */
if (_tcslen(dest)+_tcslen(src)>=size)
return NULL;
_tcscat(dest,src);
/* change forward slashes into proper directory separators */
#if DIRSEP_CHAR!='/'
while ((ptr=_tcschr(dest,__T('/')))!=NULL)
*ptr=__T(DIRSEP_CHAR);
#endif
return dest;
#else
if (_tcslen(src)>=size)
return NULL;
_tcscpy(dest,src);
/* change forward slashes into proper directory separators */
#if DIRSEP_CHAR!='/'
while ((ptr=_tcschr(dest,__T('/')))!=NULL)
*ptr=__T(DIRSEP_CHAR);
#endif
return dest;
#endif
}
/* File: fopen(const name[], filemode: mode) */
static cell AMX_NATIVE_CALL n_fopen(AMX *amx, cell *params)
{
TCHAR *attrib,*altattrib;
TCHAR *name,fullname[_MAX_PATH];
FILE *f = NULL;
altattrib=NULL;
switch (params[2] & 0x7fff) {
case io_read:
attrib=__T("rb");
break;
case io_write:
attrib=__T("wb");
break;
case io_readwrite:
attrib=__T("r+b");
altattrib=__T("w+b");
break;
case io_append:
attrib=__T("ab");
break;
default:
return 0;
} /* switch */
/* get the filename */
amx_StrParam(amx,params[1],name);
if (name!=NULL && completename(fullname,name,sizeof fullname)!=NULL) {
f=_tfopen(fullname,attrib);
if (f==NULL && altattrib!=NULL)
f=_tfopen(fullname,altattrib);
} /* if */
return (cell)f;
}
/* fclose(File: handle) */
static cell AMX_NATIVE_CALL n_fclose(AMX *amx, cell *params)
{
UNUSED_PARAM(amx);
return fclose((FILE*)params[1]) == 0;
}
/* fwrite(File: handle, const string[]) */
static cell AMX_NATIVE_CALL n_fwrite(AMX *amx, cell *params)
{
int r = 0;
cell *cptr;
char *str;
int len;
amx_GetAddr(amx,params[2],&cptr);
amx_StrLen(cptr,&len);
if (len==0)
return 0;
if ((ucell)*cptr>UNPACKEDMAX) {
/* the string is packed, write it as an ASCII/ANSI string */
if ((str=(char*)alloca(len + 1))!=NULL)
r=_tfputs(str,(FILE*)params[1]);
} else {
/* the string is unpacked, write it as UTF-8 */
r=fputs_cell((FILE*)params[1],cptr,1);
} /* if */
return r;
}
/* fread(File: handle, string[], size=sizeof string, bool:pack=false) */
static cell AMX_NATIVE_CALL n_fread(AMX *amx, cell *params)
{
int chars,max;
char *str;
cell *cptr;
max=(int)params[3];
if (max<=0)
return 0;
if (params[4])
max*=sizeof(cell);
amx_GetAddr(amx,params[2],&cptr);
str=(char *)alloca(max);
if (str==NULL || cptr==NULL) {
amx_RaiseError(amx, AMX_ERR_NATIVE);
return 0;
} /* if */
if (params[4]) {
/* store as packed string, read an ASCII/ANSI string */
chars=fgets_char((FILE*)params[1],str,max);
assert(chars<max);
amx_SetString(cptr,str,(int)params[4],0,max);
} else {
/* store and unpacked string, interpret UTF-8 */
chars=fgets_cell((FILE*)params[1],cptr,max,1);
} /* if */
assert(chars<max);
return chars;
}
/* fputchar(File: handle, value, bool:utf8 = true) */
static cell AMX_NATIVE_CALL n_fputchar(AMX *amx, cell *params)
{
size_t result;
UNUSED_PARAM(amx);
if (params[3]) {
cell str[2];
str[0]=params[2];
str[1]=0;
result=fputs_cell((FILE*)params[1],str,1);
} else {
fputc((int)params[2],(FILE*)params[1]);
} /* if */
assert(result==0 || result==1);
return result;
}
/* fgetchar(File: handle, value, bool:utf8 = true) */
static cell AMX_NATIVE_CALL n_fgetchar(AMX *amx, cell *params)
{
cell str[2];
size_t result;
UNUSED_PARAM(amx);
if (params[3]) {
result=fgets_cell((FILE*)params[1],str,2,1);
} else {
str[0]=fgetc((FILE*)params[1]);
result= (str[0]!=EOF);
} /* if */
assert(result==0 || result==1);
if (result==0)
return EOF;
else
return str[0];
}
#if PAWN_CELL_SIZE==16
#define aligncell amx_Align16
#elif PAWN_CELL_SIZE==32
#define aligncell amx_Align32
#elif PAWN_CELL_SIZE==64 && (defined _I64_MAX || defined HAVE_I64)
#define aligncell amx_Align64
#else
#error Unsupported cell size
#endif
/* fblockwrite(File: handle, buffer[], size=sizeof buffer) */
static cell AMX_NATIVE_CALL n_fblockwrite(AMX *amx, cell *params)
{
cell *cptr;
cell count;
amx_GetAddr(amx,params[2],&cptr);
if (cptr!=NULL) {
cell max=params[3];
ucell v;
for (count=0; count<max; count++) {
v=(ucell)*cptr++;
if (fwrite(aligncell(&v),sizeof(cell),1,(FILE*)params[1])!=1)
break; /* write error */
} /* for */
} /* if */
return count;
}
/* fblockread(File: handle, buffer[], size=sizeof buffer) */
static cell AMX_NATIVE_CALL n_fblockread(AMX *amx, cell *params)
{
cell *cptr;
cell count;
amx_GetAddr(amx,params[2],&cptr);
if (cptr!=NULL) {
cell max=params[3];
ucell v;
for (count=0; count<max; count++) {
if (fread(&v,sizeof(cell),1,(FILE*)params[1])!=1)
break; /* write error */
*cptr++=(cell)*aligncell(&v);
} /* for */
} /* if */
return count;
}
/* File: ftemp() */
static cell AMX_NATIVE_CALL n_ftemp(AMX *amx, cell *params)
{
UNUSED_PARAM(amx);
UNUSED_PARAM(params);
return (cell)tmpfile();
}
/* fseek(File: handle, position, seek_whence: whence=seek_start) */
static cell AMX_NATIVE_CALL n_fseek(AMX *amx, cell *params)
{
int whence;
switch (params[3]) {
case seek_start:
whence=SEEK_SET;
break;
case seek_current:
whence=SEEK_CUR;
break;
case seek_end:
whence=SEEK_END;
//if (params[2]>0)
// params[2]=-params[2];
break;
default:
return 0;
} /* switch */
UNUSED_PARAM(amx);
return lseek(fileno((FILE*)params[1]),params[2],whence);
}
/* bool: fexist(const name[]) */
static cell AMX_NATIVE_CALL n_fexist(AMX *amx, cell *params)
{
int r=1;
TCHAR *name,fullname[_MAX_PATH];
amx_StrParam(amx,params[1],name);
if (name!=NULL && completename(fullname,name,sizeof fullname)!=NULL)
r=access(fullname,0);
return r==0;
}
/* bool: fremove(const name[]) */
static cell AMX_NATIVE_CALL n_fremove(AMX *amx, cell *params)
{
int r=1;
TCHAR *name,fullname[_MAX_PATH];
amx_StrParam(amx,params[1],name);
if (name!=NULL && completename(fullname,name,sizeof fullname)!=NULL)
r=remove(fullname);
return r==0;
}
/* flength(File: handle) */
static cell AMX_NATIVE_CALL n_flength(AMX *amx, cell *params)
{
long l,c;
int fn=fileno((FILE*)params[1]);
c=lseek(fn,0,SEEK_CUR); /* save the current position */
l=lseek(fn,0,SEEK_END); /* return the file position at its end */
lseek(fn,c,SEEK_SET); /* restore the file pointer */
UNUSED_PARAM(amx);
return l;
}
#if defined __cplusplus
extern "C"
#endif
AMX_NATIVE_INFO file_Natives[] = {
{ "fopen", n_fopen },
{ "fclose", n_fclose },
{ "fwrite", n_fwrite },
{ "fread", n_fread },
{ "fputchar", n_fputchar },
{ "fgetchar", n_fgetchar },
{ "fblockwrite", n_fblockwrite },
{ "fblockread", n_fblockread },
{ "ftemp", n_ftemp },
{ "fseek", n_fseek },
{ "fexist", n_fexist },
{ "flength", n_flength },
{ "fremove", n_fremove },
{ NULL, NULL } /* terminator */
};
int AMXEXPORT amx_FileInit(AMX *amx)
{
return amx_Register(amx, file_Natives, -1);
}
int AMXEXPORT amx_FileCleanup(AMX *amx)
{
UNUSED_PARAM(amx);
return AMX_ERR_NONE;
}

791
server/amx/amxstring.c Normal file
View File

@ -0,0 +1,791 @@
/* String functions for the Pawn Abstract Machine
*
* Copyright (c) ITB CompuPhase, 2005
*
* This software is provided "as-is", without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software in
* a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
* Version: $Id: amxstring.c 3363 2005-07-23 09:03:29Z thiadmer $
*/
#include <ctype.h>
#include <limits.h>
#include <string.h>
#include <assert.h>
#if defined __WIN32__ || defined _WIN32 || defined WIN32 || defined __MSDOS__
#include <malloc.h>
#endif
#include "osdefs.h"
#include "amx.h"
#if defined __WIN32__ || defined _WIN32 || defined WIN32 || defined _Windows
#include <windows.h>
#endif
#define CHARBITS (8*sizeof(char))
/* dest the destination buffer; the buffer must point to the start of a cell
* source the source buffer, this must be aligned to a cell edge
* len the number of characters (bytes) to copy
* offs the offset in dest, in characters (bytes)
*/
static int amx_StrPack(cell *dest,cell *source,int len,int offs)
{
int i;
if ((ucell)*source>UNPACKEDMAX && offs%sizeof(cell)==0) {
/* source string is already packed and the destination is cell-aligned */
unsigned char* pdest=(unsigned char*)dest+offs;
i=(len+sizeof(cell)-1)/sizeof(cell);
memmove(pdest,source,i*sizeof(cell));
/* zero-terminate */
#if BYTE_ORDER==BIG_ENDIAN
pdest+=len;
for (i=len; i==len || i%sizeof(cell)!=0; i++)
*pdest++='\0';
#else
i=(len/sizeof(cell))*sizeof(cell);
pdest+=i;
len=(len==i) ? sizeof(cell) : sizeof(cell)-(len-i);
assert(len>0 && len<=sizeof(cell));
for (i=0; i<len; i++)
*pdest++='\0';
#endif
} else if ((ucell)*source>UNPACKEDMAX) {
/* source string is packed, destination is not aligned */
cell mask,c;
dest+=offs/sizeof(cell); /* increment whole number of cells */
offs%=sizeof(cell); /* get remainder */
mask=(~(ucell)0) >> (offs*CHARBITS);
c=*dest & ~mask;
for (i=0; i<len; i+=sizeof(cell)) {
*dest=c | ((*source >> (offs*CHARBITS)) & mask);
c=(*source << ((sizeof(cell)-offs)*CHARBITS)) & ~mask;
dest++;
source++;
} /* for */
/* add the final cell, but only if there is not already a terminating zero
* in dest
*/
if ((*(dest-1) & 0xff)!=0) {
c &= ~0xff; /* force a terminating zero, for security */
*dest=c;
} /* if */
} else {
/* source string is unpacked: pack string, from top-down */
cell c=0;
if (offs!=0) {
/* get the last cell in "dest" and mask of the characters that must be changed */
cell mask;
dest+=offs/sizeof(cell); /* increment whole number of cells */
offs%=sizeof(cell); /* get remainder */
mask=(~(ucell)0) >> (offs*CHARBITS);
c=(*dest & ~mask) >> ((sizeof(cell)-offs)*CHARBITS);
} /* if */
/* for proper alignement, add the offset to both the starting and the ending
* criterion (so that the number of iterations stays the same)
*/
assert(offs>=0 && offs<sizeof(cell));
for (i=offs; i<len+offs; i++) {
c=(c<<CHARBITS) | (*source++ & 0xff);
if (i%sizeof(cell)==sizeof(cell)-1) {
*dest++=c;
c=0;
} /* if */
} /* for */
if (i%sizeof(cell) != 0) /* store remaining packed characters */
*dest=c << (sizeof(cell)-i%sizeof(cell))*CHARBITS;
else
*dest=0; /* store full cell of zeros */
} /* if */
return AMX_ERR_NONE;
}
static int amx_StrUnpack(cell *dest,cell *source,int len)
{
/* len excludes the terminating '\0' byte */
if ((ucell)*source>UNPACKEDMAX) {
/* unpack string, from bottom up (so string can be unpacked in place) */
cell c;
int i;
for (i=len-1; i>=0; i--) {
c=source[i/sizeof(cell)] >> (sizeof(cell)-i%sizeof(cell)-1)*CHARBITS;
dest[i]=c & UCHAR_MAX;
} /* for */
dest[len]=0; /* zero-terminate */
} else {
/* source string is already unpacked */
while (len-->0)
*dest++=*source++;
*dest=0;
} /* if */
return AMX_ERR_NONE;
}
static unsigned char *packedptr(cell *string,int index)
{
unsigned char *ptr=(unsigned char *)(string+index/sizeof(cell));
#if BYTE_ORDER==BIG_ENDIAN
ptr+=index & (sizeof(cell)-1);
#else
ptr+=(sizeof(cell)-1) - (index & (sizeof(cell)-1));
#endif
return ptr;
}
static cell extractchar(cell *string,int index,int mklower)
{
cell c;
if ((ucell)*string>UNPACKEDMAX)
c=*packedptr(string,index);
else
c=string[index];
if (mklower) {
#if defined __WIN32__ || defined _WIN32 || defined WIN32
c=(cell)CharLower((LPTSTR)c);
#elif defined _Windows
c=(cell)AnsiLower((LPSTR)c);
#else
c=tolower((int)c);
#endif
} /* if */
return c;
}
static int verify_addr(AMX *amx,cell addr)
{
int err;
cell *cdest;
err=amx_GetAddr(amx,addr,&cdest);
if (err!=AMX_ERR_NONE)
amx_RaiseError(amx,err);
return err;
}
/* strlen(const string[])
*/
static cell AMX_NATIVE_CALL n_strlen(AMX *amx,cell *params)
{
cell *cptr;
int len = 0;
if (amx_GetAddr(amx,params[1],&cptr)==AMX_ERR_NONE)
amx_StrLen(cptr,&len);
return len;
}
/* strpack(dest[], const source[], maxlength=sizeof dest)
*/
static cell AMX_NATIVE_CALL n_strpack(AMX *amx,cell *params)
{
cell *cdest,*csrc;
int len,needed,err;
size_t lastaddr;
/* calculate number of cells needed for (packed) destination */
amx_GetAddr(amx,params[2],&csrc);
amx_StrLen(csrc,&len);
if ((unsigned)len>params[3]*sizeof(cell)-1)
len=params[3]*sizeof(cell)-1;
needed=(len+sizeof(cell))/sizeof(cell); /* # of cells needed */
assert(needed>0);
lastaddr=(size_t)(params[1]+sizeof(cell)*needed-1);
if (verify_addr(amx,(cell)lastaddr)!=AMX_ERR_NONE)
return amx_RaiseError(amx,AMX_ERR_NATIVE);
amx_GetAddr(amx,params[1],&cdest);
err=amx_StrPack(cdest,csrc,len,0);
if (err!=AMX_ERR_NONE)
return amx_RaiseError(amx,err);
return len;
}
/* strunpack(dest[], const source[], maxlength=sizeof dest)
*/
static cell AMX_NATIVE_CALL n_strunpack(AMX *amx,cell *params)
{
cell *cdest,*csrc;
int len,err;
size_t lastaddr;
/* calculate number of cells needed for (unpacked) destination */
amx_GetAddr(amx,params[2],&csrc);
amx_StrLen(csrc,&len);
assert(len>=0);
if (len>=params[3])
len=params[3]-1;
lastaddr=(size_t)(params[1]+sizeof(cell)*(len+1)-1);
if (verify_addr(amx,(cell)lastaddr)!=AMX_ERR_NONE)
return amx_RaiseError(amx,AMX_ERR_NATIVE);
amx_GetAddr(amx,params[1],&cdest);
err=amx_StrUnpack(cdest,csrc,len);
if (err!=AMX_ERR_NONE)
return amx_RaiseError(amx,err);
return len;
}
/* strcat(dest[], const source[], maxlength=sizeof dest)
* packed/unpacked attribute is taken from dest[], or from source[] if dest[]
* is an empty string.
*/
static cell AMX_NATIVE_CALL n_strcat(AMX *amx,cell *params)
{
cell *cdest,*csrc;
int len,len2,needed;
int packed,err;
size_t lastaddr;
/* calculate number of cells needed for (packed) destination */
amx_GetAddr(amx,params[2],&csrc);
amx_GetAddr(amx,params[1],&cdest);
amx_StrLen(csrc,&len);
amx_StrLen(cdest,&len2);
packed=(*cdest==0) ? ((ucell)*csrc>UNPACKEDMAX) : ((ucell)*cdest>UNPACKEDMAX);
if (packed) {
if ((unsigned)(len+len2)>params[3]*sizeof(cell)-1)
len=params[3]*sizeof(cell)-len2-1;
needed=(len+len2+sizeof(cell))/sizeof(cell); /* # of cells needed */
assert(needed>0);
lastaddr=(size_t)(params[1]+sizeof(cell)*needed-1);
} else {
if (len+len2>params[3]-1)
len=params[3]-len2-1;
lastaddr=(size_t)(params[1]+sizeof(cell)*(len+len2+1)-1);
} /* if */
if (verify_addr(amx,(cell)lastaddr)!=AMX_ERR_NONE)
return amx_RaiseError(amx,AMX_ERR_NATIVE);
if (packed) {
err=amx_StrPack(cdest,csrc,len,len2);
} else {
/* destination string must either be unpacked, or empty */
assert((ucell)*cdest<=UNPACKEDMAX || len2==0);
err=amx_StrUnpack(cdest+len2,csrc,len);
} /* if */
if (err!=AMX_ERR_NONE)
return amx_RaiseError(amx,err);
return len;
}
static int compare(cell *cstr1,cell *cstr2,int ignorecase,int length,int offs1)
{
int index;
cell c1=0,c2=0;
for (index=0; index<length; index++) {
c1=extractchar(cstr1,index+offs1,ignorecase);
c2=extractchar(cstr2,index,ignorecase);
assert(c1!=0 && c2!=0); /* string lengths are already checked, so zero-bytes should not occur */
if (c1!=c2)
break;
} /* for */
if (c1<c2)
return -1;
if (c1>c2)
return 1;
return 0;
}
/* strcmp(const string1[], const string2[], bool:ignorecase=false, length=cellmax)
*/
static cell AMX_NATIVE_CALL n_strcmp(AMX *amx,cell *params)
{
cell *cstr1,*cstr2;
int len1,len2,len;
cell result;
amx_GetAddr(amx,params[1],&cstr1);
amx_GetAddr(amx,params[2],&cstr2);
/* get the maximum length to compare */
amx_StrLen(cstr1,&len1);
amx_StrLen(cstr2,&len2);
len=len1;
if (len>len2)
len=len2;
if (len>params[4])
len=params[4];
if (len==0)
return 0;
result=compare(cstr1,cstr2,params[3],len,0);
if (result==0 && len!=params[4])
result=len1-len2;
return result;
}
/* strfind(const string[], const sub[], bool:ignorecase=false, offset=0)
*/
static cell AMX_NATIVE_CALL n_strfind(AMX *amx,cell *params)
{
cell *cstr,*csub;
int lenstr,lensub,offs;
cell c,f;
amx_GetAddr(amx,params[1],&cstr);
amx_GetAddr(amx,params[2],&csub);
/* get the maximum length to compare */
amx_StrLen(cstr,&lenstr);
amx_StrLen(csub,&lensub);
if (lensub==0)
return -1;
/* get the start character of the substring, for quicker searching */
f=extractchar(csub,0,params[3]);
assert(f!=0); /* string length is already checked */
for (offs=(int)params[4]; offs+lensub<=lenstr; offs++) {
/* find the initial character */
c=extractchar(csub,0,params[3]);
assert(c!=0); /* string length is already checked */
if (c!=f)
continue;
if (compare(cstr,csub,params[3],lensub,offs)==0)
return offs;
} /* for */
return -1;
}
/* strmid(dest[], const source[], start, end, maxlength=sizeof dest)
* packed/unpacked attribute is taken from source[]
*/
static cell AMX_NATIVE_CALL n_strmid(AMX *amx,cell *params)
{
cell *cdest,*csrc;
int len,needed,err;
int soffs,doffs;
size_t lastaddr;
unsigned char *ptr;
unsigned char c;
/* calculate number of cells needed for (packed) destination */
amx_GetAddr(amx,params[2],&csrc);
amx_GetAddr(amx,params[1],&cdest);
amx_StrLen(csrc,&len);
/* clamp the start/end parameters */
if (params[3]<0)
params[3]=0;
else if (params[3]>len)
params[3]=len;
if (params[4]<params[3])
params[4]=params[3];
else if (params[4]>len)
params[4]=len;
else if (params[3]>params[4])
params[3]=params[4];
len=params[4]-params[3];
if ((ucell)*csrc>UNPACKEDMAX) {
if ((unsigned)len>params[5]*sizeof(cell)-1)
len=params[5]*sizeof(cell)-1;
needed=(len+sizeof(cell))/sizeof(cell); /* # of cells needed */
assert(needed>0);
lastaddr=(size_t)(params[1]+sizeof(cell)*needed-1);
} else {
if (len>params[5]-1)
len=params[5]-1;
lastaddr=(size_t)(params[1]+sizeof(cell)*(len+1)-1);
} /* if */
if (verify_addr(amx,(cell)lastaddr)!=AMX_ERR_NONE)
return amx_RaiseError(amx,AMX_ERR_NATIVE);
if ((ucell)*csrc>UNPACKEDMAX) {
/* first align the source to a cell boundary */
for (doffs=0,soffs=(int)params[3]; (soffs & (sizeof(cell)-1))!=0 && len>1; soffs++,doffs++,len--) {
ptr=packedptr(csrc,soffs);
c=*ptr;
ptr=packedptr(cdest,doffs);
*ptr=c;
} /* for */
err=amx_StrPack(cdest,csrc+soffs/sizeof(cell),len,doffs);
} else {
err=amx_StrUnpack(cdest,csrc+params[3],len);
} /* if */
if (err!=AMX_ERR_NONE)
return amx_RaiseError(amx,err);
return len;
}
/* strdel(string[], start, end)
*/
static cell AMX_NATIVE_CALL n_strdel(AMX *amx,cell *params)
{
cell *cstr;
int index,offs,length;
unsigned char *ptr;
unsigned char c;
/* calculate number of cells needed for (packed) destination */
amx_GetAddr(amx,params[1],&cstr);
amx_StrLen(cstr,&length);
index=(int)params[2];
offs=(int)params[3]-index;
if (index>=length || offs<=0)
return 0;
if (index+offs>length)
offs=length-index;
index--; /* prepare for increment in the top of the loop */
if (((ucell)*cstr>UNPACKEDMAX)) {
do {
index++;
ptr=packedptr(cstr,index+offs);
c=*ptr;
ptr=packedptr(cstr,index);
*ptr=c;
} while (c!='\0');
if (index==0)
*cstr=0;
} else {
do {
index++;
cstr[index]=cstr[index+offs];
} while (cstr[index]!=0);
} /* if */
return 1;
}
/* strins(string[], const substr[], offset, maxlength=sizeof string)
*/
static cell AMX_NATIVE_CALL n_strins(AMX *amx,cell *params)
{
cell *cstr,*csub;
int index,lenstr,lensub,count;
int needed;
size_t lastaddr;
unsigned char *ptr;
cell c;
/* calculate number of cells needed for (packed) destination */
amx_GetAddr(amx,params[1],&cstr);
amx_GetAddr(amx,params[2],&csub);
amx_StrLen(cstr,&lenstr);
amx_StrLen(csub,&lensub);
index=(int)params[3];
if (index>lenstr)
return amx_RaiseError(amx,AMX_ERR_NATIVE);
if (((ucell)*cstr>UNPACKEDMAX)) {
needed=(lenstr+lensub+sizeof(cell))/sizeof(cell); /* # of cells needed */
assert(needed>0);
lastaddr=(size_t)(params[1]+sizeof(cell)*needed-1);
} else {
lastaddr=(size_t)(params[1]+sizeof(cell)*(lenstr+lensub+1)-1);
} /* if */
if (verify_addr(amx,(cell)lastaddr)!=AMX_ERR_NONE)
return amx_RaiseError(amx,AMX_ERR_NATIVE);
if (*cstr==0) {
/* current string is empty (and the insertion point is zero), just make a copy */
assert(index==0);
if ((ucell)*csub>UNPACKEDMAX)
amx_StrPack(cstr,csub,lensub,0);
else
amx_StrUnpack(cstr,csub,lensub);
return 1;
} /* if */
if (((ucell)*cstr>UNPACKEDMAX)) {
/* make room for the new characters */
for (count=lenstr+lensub; count>index; count--) {
ptr=packedptr(cstr,count-lensub);
c=*ptr;
ptr=packedptr(cstr,count);
*ptr=(unsigned char)c;
} /* for */
/* copy in the new characters */
for (count=0; count<lensub; count++) {
c=extractchar(csub,count,0);
ptr=packedptr(cstr,index+count);
*ptr=(unsigned char)c;
} /* for */
} else {
/* make room for the new characters */
for (count=lenstr+lensub; count>index; count--)
cstr[count]=cstr[count-lensub];
/* copy in the new characters */
for (count=0; count<lensub; count++) {
c=extractchar(csub,count,0);
cstr[index+count]=c;
} /* for */
} /* if */
return 1;
}
/* strval(const string[])
*/
static cell AMX_NATIVE_CALL n_strval(AMX *amx,cell *params)
{
char str[50],*ptr;
cell *cstr,result;
int len,negate=0;
amx_GetAddr(amx,params[1],&cstr);
amx_StrLen(cstr,&len);
if (len>=50) {
amx_RaiseError(amx,AMX_ERR_NATIVE);
return 0;
} /* if */
amx_GetString(str,cstr,0,sizeof str);
ptr=str;
result=0;
while (*ptr!='\0' && *ptr<=' ')
ptr++; /* skip whitespace */
if (*ptr=='-') { /* handle sign */
negate=1;
ptr++;
} else if (*ptr=='+') {
ptr++;
} /* if */
while (isdigit(*ptr)) {
result=result*10 + (*ptr-'0');
ptr++;
} /* while */
if (negate)
result=-result;
return result;
}
/* valstr(dest[], value, bool:pack=false) */
static cell AMX_NATIVE_CALL n_valstr(AMX *amx,cell *params)
{
char str[50];
cell value,mult;
cell *cstr;
int len,result,negate=0;
/* find out how many digits are needed */
mult=10;
len=1;
value=params[2];
if (value<0) {
negate=1;
len++;
value=-value;
} /* if */
while (value>=mult) {
len++;
mult*=10;
} /* while */
/* put in the string */
result=len;
str[len--]='\0';
while (len>=negate) {
str[len--]=(char)((value % 10)+'0');
value/=10;
} /* while */
if (negate)
str[0]='-';
amx_GetAddr(amx,params[1],&cstr);
amx_SetString(cstr,str,params[3],0,UNLIMITED);
return result;
}
/* ispacked(const string[]) */
static cell AMX_NATIVE_CALL n_ispacked(AMX *amx,cell *params)
{
cell *cstr;
amx_GetAddr(amx,params[1],&cstr);
return *cstr>=UNPACKEDMAX;
}
/* single character decode and encode */
#define BITMASK 0x3f
#define DEC(c) (((c) - ' ') & BITMASK)
#define ENC(c) (char)(((c) & BITMASK) == 0 ? 0x60 : ((c) & BITMASK) + ' ')
static int uudecode(unsigned char *target, char *source)
{
int len, retval;
len = DEC(*source++);
retval = len;
while (len > 0) {
if (len-- > 0)
*target++ = (unsigned char)(( DEC(source[0]) << 2 ) | ( DEC(source[1]) >> 4 ));
if (len-- > 0)
*target++ = (unsigned char)(( DEC(source[1]) << 4 ) | ( DEC(source[2]) >> 2 ));
if (len-- > 0)
*target++ = (unsigned char)(( DEC(source[2]) << 6 ) | DEC(source[3]) );
source += 4;
} /* while */
return retval;
}
static int uuencode(char *target, unsigned char *source, int length)
{
int split[4];
if (length > BITMASK)
return 0; /* can encode up to 64 bytes */
*target++ = ENC(length);
while (length > 0) {
split[0] = source[0] >> 2; /* split first byte to char. 0 & 1 */
split[1] = source[0] << 4;
if (length > 1) {
split[1] |= source[1] >> 4; /* split 2nd byte to char. 1 & 2 */
split[2] = source[1] << 2;
if (length > 2) {
split[2] |= source[2] >> 6; /* split 3th byte to char. 2 & 3 */
split[3] = source[2];
} /* if */
} /* if */
*target++ = ENC(split[0]);
*target++ = ENC(split[1]);
if (length > 1)
*target++ = ENC(split[2]);
if (length > 2)
*target++ = ENC(split[3]);
source += 3;
length -= 3;
} /* while */
*target = '\0'; /* end string */
return 1;
}
/* uudecode(dest[], const source[], maxlength=sizeof dest)
* Returns the number of bytes (not cells) decoded; if the dest buffer is
* too small, not all bytes are stored.
* Always creates a (packed) array (not a string; the array is not
* zero-terminated).
* A buffer may be decoded "in-place"; the destination size is always smaller
* than the source size.
* Endian issues (for multi-byte values in the data stream) are not handled.
*/
static cell AMX_NATIVE_CALL n_uudecode(AMX *amx,cell *params)
{
cell *cstr;
unsigned char dst[BITMASK+2];
char src[BITMASK+BITMASK/3+2];
int len;
size_t size;
/* get the source */
amx_GetAddr(amx,params[2],&cstr);
amx_GetString(src,cstr,0,sizeof src);
/* decode */
len=uudecode(dst,src);
/* store */
amx_GetAddr(amx,params[1],&cstr);
size=len;
if (size>params[3]*sizeof(cell))
size=params[3]*sizeof(cell);
memcpy(cstr,dst,size);
return len;
}
/* uuencode(dest[], const source[], numbytes, maxlength=sizeof dest)
* Returns the number of characters encoded, excluding the zero string
* terminator; if the dest buffer is too small, not all bytes are stored.
* Always creates a packed string. This string has a newline character at the
* end. A buffer may be encoded "in-place" if the destination is large enough.
* Endian issues (for multi-byte values in the data stream) are not handled.
*/
static cell AMX_NATIVE_CALL n_uuencode(AMX *amx,cell *params)
{
cell *cstr;
unsigned char src[BITMASK+2];
char dst[BITMASK+BITMASK/3+2];
/* get the source */
amx_GetAddr(amx,params[2],&cstr);
/* encode (and check for errors) */
if (uuencode(dst,src,params[3])) {
if (params[4]>0) {
amx_GetAddr(amx,params[1],&cstr);
*cstr=0;
} /* if */
return 0;
} /* if */
/* always add a \n */
assert(strlen(dst)+1<sizeof dst);
strcat(dst,"\n");
/* store */
amx_GetAddr(amx,params[1],&cstr);
amx_SetString(cstr,dst,1,0,params[4]);
return (((params[3]+2)/3) << 2)+2;
}
/* memcpy(dest[], const source[], index=0, numbytes, maxlength=sizeof dest)
* This function can align byte strings in cell arrays, or concatenate two
* byte strings in two arrays. The parameter "index" is a byte offset; "numbytes"
* is the number of bytes to copy. Parameter "maxlength", however, is in cells.
* This function allows copying in-place, for aligning memory buffers.
* Endian issues (for multi-byte values in the data stream) are not handled.
*/
static cell AMX_NATIVE_CALL n_memcpy(AMX *amx,cell *params)
{
cell *cdest,*csrc;
unsigned char *pdest,*psrc;
if (params[3]<0 || params[4]<0 || (params[3]+params[4])>params[5]*(int)sizeof(cell))
return 0;
amx_GetAddr(amx,params[1],&cdest);
amx_GetAddr(amx,params[2],&csrc);
pdest=(unsigned char*)cdest+params[3];
psrc=(unsigned char*)csrc;
memmove(pdest,psrc,params[4]);
return 1;
}
#if defined __cplusplus
extern "C"
#endif
const AMX_NATIVE_INFO string_Natives[] = {
{ "ispacked", n_ispacked },
{ "memcpy", n_memcpy },
{ "strcat", n_strcat },
{ "strcmp", n_strcmp },
{ "strdel", n_strdel },
{ "strfind", n_strfind },
{ "strins", n_strins },
{ "strlen", n_strlen },
{ "strmid", n_strmid },
{ "strpack", n_strpack },
{ "strunpack", n_strunpack },
{ "strval", n_strval },
{ "uudecode", n_uudecode },
{ "uuencode", n_uuencode },
{ "valstr", n_valstr },
{ NULL, NULL } /* terminator */
};
int AMXEXPORT amx_StringInit(AMX *amx)
{
return amx_Register(amx, string_Natives, -1);
}
int AMXEXPORT amx_StringCleanup(AMX *amx)
{
(void)amx;
return AMX_ERR_NONE;
}

101
server/amx/getch.c Normal file
View File

@ -0,0 +1,101 @@
/* Extremely inefficient but portable POSIX getch() */
#include <stdio.h>
#include <string.h>
#include <termios.h> /* for tcgetattr() and tcsetattr() */
#include <unistd.h> /* for read() */
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/time.h>
#include "getch.h"
#ifndef STDIN_FILENO
# define STDIN_FILENO 0
#endif
int
getch (void)
{
struct termios save_termios;
struct termios ios;
int c = 0;
if (!isatty (STDIN_FILENO))
return EOF;
if (tcgetattr (STDIN_FILENO, &save_termios) < 0)
return EOF;
ios = save_termios;
ios.c_lflag &= ~(ICANON | ECHO | ISIG);
ios.c_cc[VMIN] = 1; /* read() will return with one char */
ios.c_cc[VTIME] = 0; /* read() blocks forever */
if (tcsetattr (STDIN_FILENO, TCSANOW, &ios) < 0)
return EOF;
if (read (STDIN_FILENO, &c, 1) != 1)
c = EOF;
tcsetattr (STDIN_FILENO, TCSANOW, &save_termios);
return c;
}
int
kbhit (void)
{
struct termios save_termios;
struct termios ios;
fd_set inp;
struct timeval timeout = {0, 0};
int result;
if (!isatty (STDIN_FILENO))
return 0;
if (tcgetattr (STDIN_FILENO, &save_termios) < 0)
return 0;
ios = save_termios;
ios.c_lflag &= ~(ICANON | ECHO | ISIG);
ios.c_cc[VMIN] = 1; /* read() will return with one char */
ios.c_cc[VTIME] = 0; /* read() blocks forever */
if (tcsetattr (STDIN_FILENO, TCSANOW, &ios) < 0)
return 0;
/* set up select() args */
FD_ZERO(&inp);
FD_SET(STDIN_FILENO, &inp);
result = select (STDIN_FILENO+1, &inp, NULL, NULL, &timeout) == 1;
tcsetattr (STDIN_FILENO, TCSANOW, &save_termios);
return result;
}
#if defined TEST_GETCH
int
main ()
{
int i;
char c[4];
printf("Enter %d keys to continue: ", sizeof c - 1);
fflush (stdout);
memset(c, 0, sizeof c);
for (i=0; i<sizeof c - 1; i++)
c[i] = getch ();
printf("Your input: [%s]\n", c);
printf("Now hit any key to abort: ");
while (!kbhit())
printf(".");
return 0;
}
#endif

15
server/amx/getch.h Normal file
View File

@ -0,0 +1,15 @@
/* Extremely inefficient but portable POSIX getch(), see getch.c */
#ifndef GETCH_H
#define GETCH_H
#if defined __cplusplus
extern "C" {
#endif
int getch(void);
int kbhit(void);
#if defined __cplusplus
}
#endif
#endif /* GETCH_H */

482
server/amx/prefix.c Normal file
View File

@ -0,0 +1,482 @@
/*
* BinReloc - a library for creating relocatable executables
* Written by: Mike Hearn <mike@theoretic.com>
* Hongli Lai <h.lai@chello.nl>
* http://autopackage.org/
*
* This source code is public domain. You can relicense this code
* under whatever license you want.
*
* NOTE: if you're using C++ and are getting "undefined reference
* to br_*", try renaming prefix.c to prefix.cpp
*/
/* WARNING, BEFORE YOU MODIFY PREFIX.C:
*
* If you make changes to any of the functions in prefix.c, you MUST
* change the BR_NAMESPACE macro (in prefix.h).
* This way you can avoid symbol table conflicts with other libraries
* that also happen to use BinReloc.
*
* Example:
* #define BR_NAMESPACE(funcName) foobar_ ## funcName
* --> expands br_locate to foobar_br_locate
*/
#ifndef _PREFIX_C_
#define _PREFIX_C_
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifndef BR_PTHREADS
/* Change 1 to 0 if you don't want pthread support */
#define BR_PTHREADS 1
#endif /* BR_PTHREADS */
#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
#include <string.h>
#include "prefix.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#undef NULL
#define NULL ((void *) 0)
#ifdef __GNUC__
#define br_return_val_if_fail(expr,val) if (!(expr)) {fprintf (stderr, "** BinReloc (%s): assertion %s failed\n", __PRETTY_FUNCTION__, #expr); return val;}
#else
#define br_return_val_if_fail(expr,val) if (!(expr)) return val
#endif /* __GNUC__ */
static br_locate_fallback_func fallback_func = (br_locate_fallback_func) NULL;
static void *fallback_data = NULL;
#ifdef ENABLE_BINRELOC
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <unistd.h>
/**
* br_locate:
* symbol: A symbol that belongs to the app/library you want to locate.
* Returns: A newly allocated string containing the full path of the
* app/library that func belongs to, or NULL on error. This
* string should be freed when not when no longer needed.
*
* Finds out to which application or library symbol belongs, then locate
* the full path of that application or library.
* Note that symbol cannot be a pointer to a function. That will not work.
*
* Example:
* --> main.c
* #include "prefix.h"
* #include "libfoo.h"
*
* int main (int argc, char *argv[]) {
* printf ("Full path of this app: %s\n", br_locate (&argc));
* libfoo_start ();
* return 0;
* }
*
* --> libfoo.c starts here
* #include "prefix.h"
*
* void libfoo_start () {
* --> "" is a symbol that belongs to libfoo (because it's called
* --> from libfoo_start()); that's why this works.
* printf ("libfoo is located in: %s\n", br_locate (""));
* }
*/
char *
br_locate (void *symbol)
{
char line[5000];
FILE *f;
char *path;
br_return_val_if_fail (symbol != NULL, NULL);
f = fopen ("/proc/self/maps", "r");
if (!f) {
if (fallback_func)
return fallback_func(symbol, fallback_data);
else
return NULL;
}
while (!feof (f))
{
unsigned long start, end;
if (!fgets (line, sizeof (line), f))
continue;
if (!strstr (line, " r-xp ") || !strchr (line, '/'))
continue;
sscanf (line, "%lx-%lx ", &start, &end);
if (symbol >= (void *) start && symbol < (void *) end)
{
char *tmp;
size_t len;
/* Extract the filename; it is always an absolute path */
path = strchr (line, '/');
/* Get rid of the newline */
tmp = strrchr (path, '\n');
if (tmp) *tmp = 0;
/* Get rid of "(deleted)" */
len = strlen (path);
if (len > 10 && strcmp (path + len - 10, " (deleted)") == 0)
{
tmp = path + len - 10;
*tmp = 0;
}
fclose(f);
return strdup (path);
}
}
fclose (f);
return NULL;
}
/**
* br_locate_prefix:
* symbol: A symbol that belongs to the app/library you want to locate.
* Returns: A prefix. This string should be freed when no longer needed.
*
* Locates the full path of the app/library that symbol belongs to, and return
* the prefix of that path, or NULL on error.
* Note that symbol cannot be a pointer to a function. That will not work.
*
* Example:
* --> This application is located in /usr/bin/foo
* br_locate_prefix (&argc); --> returns: "/usr"
*/
char *
br_locate_prefix (void *symbol)
{
char *path, *prefix;
br_return_val_if_fail (symbol != NULL, NULL);
path = br_locate (symbol);
if (!path) return NULL;
prefix = br_extract_prefix (path);
free (path);
return prefix;
}
/**
* br_prepend_prefix:
* symbol: A symbol that belongs to the app/library you want to locate.
* path: The path that you want to prepend the prefix to.
* Returns: The new path, or NULL on error. This string should be freed when no
* longer needed.
*
* Gets the prefix of the app/library that symbol belongs to. Prepend that prefix to path.
* Note that symbol cannot be a pointer to a function. That will not work.
*
* Example:
* --> The application is /usr/bin/foo
* br_prepend_prefix (&argc, "/share/foo/data.png"); --> Returns "/usr/share/foo/data.png"
*/
char *
br_prepend_prefix (void *symbol, char *path)
{
char *tmp, *newpath;
br_return_val_if_fail (symbol != NULL, NULL);
br_return_val_if_fail (path != NULL, NULL);
tmp = br_locate_prefix (symbol);
if (!tmp) return NULL;
if (strcmp (tmp, "/") == 0)
newpath = strdup (path);
else
newpath = br_strcat (tmp, path);
/* Get rid of compiler warning ("br_prepend_prefix never used") */
if (0) br_prepend_prefix (NULL, NULL);
free (tmp);
return newpath;
}
#endif /* ENABLE_BINRELOC */
/* Pthread stuff for thread safetiness */
#if BR_PTHREADS && defined(ENABLE_BINRELOC)
#include <pthread.h>
static pthread_key_t br_thread_key;
static pthread_once_t br_thread_key_once = PTHREAD_ONCE_INIT;
static void
br_thread_local_store_fini ()
{
char *specific;
specific = (char *) pthread_getspecific (br_thread_key);
if (specific)
{
free (specific);
pthread_setspecific (br_thread_key, NULL);
}
pthread_key_delete (br_thread_key);
br_thread_key = 0;
}
static void
br_str_free (void *str)
{
if (str)
free (str);
}
static void
br_thread_local_store_init ()
{
if (pthread_key_create (&br_thread_key, br_str_free) == 0)
atexit (br_thread_local_store_fini);
}
#else /* BR_PTHREADS */
#ifdef ENABLE_BINRELOC
static char *br_last_value = (char *) NULL;
static void
br_free_last_value ()
{
if (br_last_value)
free (br_last_value);
}
#endif /* ENABLE_BINRELOC */
#endif /* BR_PTHREADS */
#ifdef ENABLE_BINRELOC
/**
* br_thread_local_store:
* str: A dynamically allocated string.
* Returns: str. This return value must not be freed.
*
* Store str in a thread-local variable and return str. The next
* you run this function, that variable is freed too.
* This function is created so you don't have to worry about freeing
* strings. Just be careful about doing this sort of thing:
*
* some_function( BR_DATADIR("/one.png"), BR_DATADIR("/two.png") )
*
* Examples:
* char *foo;
* foo = br_thread_local_store (strdup ("hello")); --> foo == "hello"
* foo = br_thread_local_store (strdup ("world")); --> foo == "world"; "hello" is now freed.
*/
const char *
br_thread_local_store (char *str)
{
#if BR_PTHREADS
char *specific;
pthread_once (&br_thread_key_once, br_thread_local_store_init);
specific = (char *) pthread_getspecific (br_thread_key);
br_str_free (specific);
pthread_setspecific (br_thread_key, str);
#else /* BR_PTHREADS */
static int initialized = 0;
if (!initialized)
{
atexit (br_free_last_value);
initialized = 1;
}
if (br_last_value)
free (br_last_value);
br_last_value = str;
#endif /* BR_PTHREADS */
return (const char *) str;
}
#endif /* ENABLE_BINRELOC */
/**
* br_strcat:
* str1: A string.
* str2: Another string.
* Returns: A newly-allocated string. This string should be freed when no longer needed.
*
* Concatenate str1 and str2 to a newly allocated string.
*/
char *
br_strcat (const char *str1, const char *str2)
{
char *result;
size_t len1, len2;
if (!str1) str1 = "";
if (!str2) str2 = "";
len1 = strlen (str1);
len2 = strlen (str2);
result = (char *) malloc (len1 + len2 + 1);
memcpy (result, str1, len1);
memcpy (result + len1, str2, len2);
result[len1 + len2] = '\0';
return result;
}
/* Emulates glibc's strndup() */
static char *
br_strndup (char *str, size_t size)
{
char *result = (char *) NULL;
size_t len;
br_return_val_if_fail (str != (char *) NULL, (char *) NULL);
len = strlen (str);
if (!len) return strdup ("");
if (size > len) size = len;
result = (char *) calloc (sizeof (char), len + 1);
memcpy (result, str, size);
return result;
}
/**
* br_extract_dir:
* path: A path.
* Returns: A directory name. This string should be freed when no longer needed.
*
* Extracts the directory component of path. Similar to g_dirname() or the dirname
* commandline application.
*
* Example:
* br_extract_dir ("/usr/local/foobar"); --> Returns: "/usr/local"
*/
char *
br_extract_dir (const char *path)
{
char *end, *result;
br_return_val_if_fail (path != (char *) NULL, (char *) NULL);
end = strrchr (path, '/');
if (!end) return strdup (".");
while (end > path && *end == '/')
end--;
result = br_strndup ((char *) path, end - path + 1);
if (!*result)
{
free (result);
return strdup ("/");
} else
return result;
}
/**
* br_extract_prefix:
* path: The full path of an executable or library.
* Returns: The prefix, or NULL on error. This string should be freed when no longer needed.
*
* Extracts the prefix from path. This function assumes that your executable
* or library is installed in an LSB-compatible directory structure.
*
* Example:
* br_extract_prefix ("/usr/bin/gnome-panel"); --> Returns "/usr"
* br_extract_prefix ("/usr/local/lib/libfoo.so"); --> Returns "/usr/local"
* br_extract_prefix ("/usr/local/libfoo.so"); --> Returns "/usr"
*/
char *
br_extract_prefix (const char *path)
{
char *end, *tmp, *result;
br_return_val_if_fail (path != (char *) NULL, (char *) NULL);
if (!*path) return strdup ("/");
end = strrchr (path, '/');
if (!end) return strdup (path);
tmp = br_strndup ((char *) path, end - path);
if (!*tmp)
{
free (tmp);
return strdup ("/");
}
end = strrchr (tmp, '/');
if (!end) return tmp;
result = br_strndup (tmp, end - tmp);
free (tmp);
if (!*result)
{
free (result);
result = strdup ("/");
}
return result;
}
/**
* br_set_fallback_function:
* func: A function to call to find the binary.
* data: User data to pass to func.
*
* Sets a function to call to find the path to the binary, in
* case "/proc/self/maps" can't be opened. The function set should
* return a string that is safe to free with free().
*/
void
br_set_locate_fallback_func (br_locate_fallback_func func, void *data)
{
fallback_func = func;
fallback_data = data;
}
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* _PREFIX_C */

139
server/amx/prefix.h Normal file
View File

@ -0,0 +1,139 @@
/*
* BinReloc - a library for creating relocatable executables
* Written by: Mike Hearn <mike@theoretic.com>
* Hongli Lai <h.lai@chello.nl>
* http://autopackage.org/
*
* This source code is public domain. You can relicense this code
* under whatever license you want.
*
* See http://autopackage.org/docs/binreloc/ for
* more information and how to use this.
*
* NOTE: if you're using C++ and are getting "undefined reference
* to br_*", try renaming prefix.c to prefix.cpp
*/
#ifndef _PREFIX_H_
#define _PREFIX_H_
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* WARNING, BEFORE YOU MODIFY PREFIX.C:
*
* If you make changes to any of the functions in prefix.c, you MUST
* change the BR_NAMESPACE macro.
* This way you can avoid symbol table conflicts with other libraries
* that also happen to use BinReloc.
*
* Example:
* #define BR_NAMESPACE(funcName) foobar_ ## funcName
* --> expands br_locate to foobar_br_locate
*/
#undef BR_NAMESPACE
#define BR_NAMESPACE(funcName) funcName
#ifdef ENABLE_BINRELOC
#define br_thread_local_store BR_NAMESPACE(br_thread_local_store)
#define br_locate BR_NAMESPACE(br_locate)
#define br_locate_prefix BR_NAMESPACE(br_locate_prefix)
#define br_prepend_prefix BR_NAMESPACE(br_prepend_prefix)
#ifndef BR_NO_MACROS
/* These are convience macros that replace the ones usually used
in Autoconf/Automake projects */
#undef SELFPATH
#undef PREFIX
#undef PREFIXDIR
#undef BINDIR
#undef SBINDIR
#undef DATADIR
#undef LIBDIR
#undef LIBEXECDIR
#undef ETCDIR
#undef SYSCONFDIR
#undef CONFDIR
#undef LOCALEDIR
#define SELFPATH (br_thread_local_store (br_locate ((void *) "")))
#define PREFIX (br_thread_local_store (br_locate_prefix ((void *) "")))
#define PREFIXDIR (br_thread_local_store (br_locate_prefix ((void *) "")))
#define BINDIR (br_thread_local_store (br_prepend_prefix ((void *) "", "/bin")))
#define SBINDIR (br_thread_local_store (br_prepend_prefix ((void *) "", "/sbin")))
#define DATADIR (br_thread_local_store (br_prepend_prefix ((void *) "", "/share")))
#define LIBDIR (br_thread_local_store (br_prepend_prefix ((void *) "", "/lib")))
#define LIBEXECDIR (br_thread_local_store (br_prepend_prefix ((void *) "", "/libexec")))
#define ETCDIR (br_thread_local_store (br_prepend_prefix ((void *) "", "/etc")))
#define SYSCONFDIR (br_thread_local_store (br_prepend_prefix ((void *) "", "/etc")))
#define CONFDIR (br_thread_local_store (br_prepend_prefix ((void *) "", "/etc")))
#define LOCALEDIR (br_thread_local_store (br_prepend_prefix ((void *) "", "/share/locale")))
#endif /* BR_NO_MACROS */
/* The following functions are used internally by BinReloc
and shouldn't be used directly in applications. */
char *br_locate (void *symbol);
char *br_locate_prefix (void *symbol);
char *br_prepend_prefix (void *symbol, char *path);
#endif /* ENABLE_BINRELOC */
const char *br_thread_local_store (char *str);
/* These macros and functions are not guarded by the ENABLE_BINRELOC
* macro because they are portable. You can use these functions.
*/
#define br_strcat BR_NAMESPACE(br_strcat)
#define br_extract_dir BR_NAMESPACE(br_extract_dir)
#define br_extract_prefix BR_NAMESPACE(br_extract_prefix)
#define br_set_locate_fallback_func BR_NAMESPACE(br_set_locate_fallback_func)
#ifndef BR_NO_MACROS
#ifndef ENABLE_BINRELOC
#define BR_SELFPATH(suffix) SELFPATH suffix
#define BR_PREFIX(suffix) PREFIX suffix
#define BR_PREFIXDIR(suffix) BR_PREFIX suffix
#define BR_BINDIR(suffix) BINDIR suffix
#define BR_SBINDIR(suffix) SBINDIR suffix
#define BR_DATADIR(suffix) DATADIR suffix
#define BR_LIBDIR(suffix) LIBDIR suffix
#define BR_LIBEXECDIR(suffix) LIBEXECDIR suffix
#define BR_ETCDIR(suffix) ETCDIR suffix
#define BR_SYSCONFDIR(suffix) SYSCONFDIR suffix
#define BR_CONFDIR(suffix) CONFDIR suffix
#define BR_LOCALEDIR(suffix) LOCALEDIR suffix
#else
#define BR_SELFPATH(suffix) (br_thread_local_store (br_strcat (SELFPATH, suffix)))
#define BR_PREFIX(suffix) (br_thread_local_store (br_strcat (PREFIX, suffix)))
#define BR_PREFIXDIR(suffix) (br_thread_local_store (br_strcat (BR_PREFIX, suffix)))
#define BR_BINDIR(suffix) (br_thread_local_store (br_strcat (BINDIR, suffix)))
#define BR_SBINDIR(suffix) (br_thread_local_store (br_strcat (SBINDIR, suffix)))
#define BR_DATADIR(suffix) (br_thread_local_store (br_strcat (DATADIR, suffix)))
#define BR_LIBDIR(suffix) (br_thread_local_store (br_strcat (LIBDIR, suffix)))
#define BR_LIBEXECDIR(suffix) (br_thread_local_store (br_strcat (LIBEXECDIR, suffix)))
#define BR_ETCDIR(suffix) (br_thread_local_store (br_strcat (ETCDIR, suffix)))
#define BR_SYSCONFDIR(suffix) (br_thread_local_store (br_strcat (SYSCONFDIR, suffix)))
#define BR_CONFDIR(suffix) (br_thread_local_store (br_strcat (CONFDIR, suffix)))
#define BR_LOCALEDIR(suffix) (br_thread_local_store (br_strcat (LOCALEDIR, suffix)))
#endif
#endif
char *br_strcat (const char *str1, const char *str2);
char *br_extract_dir (const char *path);
char *br_extract_prefix(const char *path);
typedef char *(*br_locate_fallback_func) (void *symbol, void *data);
void br_set_locate_fallback_func (br_locate_fallback_func func, void *data);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* _PREFIX_H_ */

47
server/amx/sclinux.h Normal file
View File

@ -0,0 +1,47 @@
/*
* Things needed to compile under linux.
*
* Should be reworked totally to use GNU's 'configure'
*/
#ifndef SCLINUX_H
#define SCLINUX_H
/* getchar() is not a 'cool' replacement for MSDOS getch: Linux/unix depends on the features activated or not about the
* controlling terminal's tty. This means that ioctl(2) calls must be performed, for instance to have the controlling
* terminal tty's in 'raw' mode, if we want to be able to fetch a single character. This also means that everything must
* be put back correctly when the function ends. See GETCH.C for an implementation.
*
* For interactive use of SRUN/SDBG if would be much better to use GNU's readline package: the user would be able to
* have a complete emacs/vi like line editing system.
*/
#include "getch.h"
#define stricmp(a,b) strcasecmp(a,b)
#define strnicmp(a,b,c) strncasecmp(a,b,c)
/*
* WinWorld wants '\'. Unices do not.
*/
#define DIRECTORY_SEP_CHAR '/'
#define DIRECTORY_SEP_STR "/"
/*
* SC assumes that a computer is Little Endian unless told otherwise. It uses
* (and defines) the macros BYTE_ORDER and BIG_ENDIAN.
* For Linux, we must overrule these settings with those defined in glibc.
*/
#if !defined __BYTE_ORDER
# include <stdlib.h>
#endif
#if defined __OpenBSD__ || defined __FreeBSD__
# define __BYTE_ORDER BYTE_ORDER
# define __LITTLE_ENDIAN LITTLE_ENDIAN
# define __BIG_ENDIAN BIG_ENDIAN
#endif
#if !defined __BYTE_ORDER
# error "Can't figure computer byte order (__BYTE_ORDER macro not found)"
#endif
#endif /* SCLINUX_H */

View File

@ -121,6 +121,40 @@
RelativePath="..\ttmath\ttmathuint_x86.h">
</File>
</Filter>
<Filter
Name="amx"
Filter="">
<File
RelativePath=".\amx\amx.c">
</File>
<File
RelativePath=".\amx\amx.h">
</File>
<File
RelativePath=".\amx\amxcons.c">
</File>
<File
RelativePath=".\amx\amxcore.c">
</File>
<File
RelativePath=".\amx\amxDGram.c">
</File>
<File
RelativePath=".\amx\amxfile.c">
</File>
<File
RelativePath=".\amx\amxfloat.c">
</File>
<File
RelativePath=".\amx\amxstring.c">
</File>
<File
RelativePath=".\amx\amxtime.c">
</File>
<File
RelativePath=".\amx\osdefs.h">
</File>
</Filter>
<Filter
Name="raknet"
Filter="">