mirror of
https://github.com/dashr9230/SA-MP.git
synced 2024-12-22 14:37:29 +08:00
Add AMX modules
This commit is contained in:
parent
7678b765ce
commit
3bdb21283f
351
server/amx/amxDGram.c
Normal file
351
server/amx/amxDGram.c
Normal 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
1159
server/amx/amxcons.c
Normal file
File diff suppressed because it is too large
Load Diff
500
server/amx/amxcore.c
Normal file
500
server/amx/amxcore.c
Normal 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
86
server/amx/amxdefn.asm
Normal 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
1633
server/amx/amxexecn.asm
Normal file
File diff suppressed because it is too large
Load Diff
702
server/amx/amxfile.c
Normal file
702
server/amx/amxfile.c
Normal 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
791
server/amx/amxstring.c
Normal 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
101
server/amx/getch.c
Normal 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
15
server/amx/getch.h
Normal 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
482
server/amx/prefix.c
Normal 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
139
server/amx/prefix.h
Normal 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
47
server/amx/sclinux.h
Normal 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 */
|
@ -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="">
|
||||
|
Loading…
Reference in New Issue
Block a user