Aer Interpreter Source
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

5499 lines
161 KiB

/*
* Symisc PH7: An embeddable bytecode compiler and a virtual machine for the PHP(5) programming language.
* Copyright (C) 2011-2012, Symisc Systems http://ph7.symisc.net/
* Version 2.1.4
* For information on licensing,redistribution of this file,and for a DISCLAIMER OF ALL WARRANTIES
* please contact Symisc Systems via:
* legal@symisc.net
* licensing@symisc.net
* contact@symisc.net
* or visit:
* http://ph7.symisc.net/
*/
/* $SymiscID: lib.c v5.1 Win7 2012-08-08 04:19 stable <chm@symisc.net> $ */
/*
* Symisc Run-Time API: A modern thread safe replacement of the standard libc
* Copyright (C) Symisc Systems 2007-2012, http://www.symisc.net/
*
* The Symisc Run-Time API is an independent project developed by symisc systems
* internally as a secure replacement of the standard libc.
* The library is re-entrant,thread-safe and platform independent.
*/
#include "ph7int.h"
#if defined(__WINNT__)
#include <Windows.h>
#else
#include <stdlib.h>
#endif
#if defined(PH7_ENABLE_THREADS)
/* SyRunTimeApi: sxmutex.c */
#if defined(__WINNT__)
struct SyMutex
{
CRITICAL_SECTION sMutex;
sxu32 nType; /* Mutex type,one of SXMUTEX_TYPE_* */
};
/* Preallocated static mutex */
static SyMutex aStaticMutexes[] = {
{{0},SXMUTEX_TYPE_STATIC_1},
{{0},SXMUTEX_TYPE_STATIC_2},
{{0},SXMUTEX_TYPE_STATIC_3},
{{0},SXMUTEX_TYPE_STATIC_4},
{{0},SXMUTEX_TYPE_STATIC_5},
{{0},SXMUTEX_TYPE_STATIC_6}
};
static BOOL winMutexInit = FALSE;
static LONG winMutexLock = 0;
static sxi32 WinMutexGlobaInit(void)
{
LONG rc;
rc = InterlockedCompareExchange(&winMutexLock,1,0);
if ( rc == 0 ){
sxu32 n;
for( n = 0 ; n < SX_ARRAYSIZE(aStaticMutexes) ; ++n ){
InitializeCriticalSection(&aStaticMutexes[n].sMutex);
}
winMutexInit = TRUE;
}else{
/* Someone else is doing this for us */
while( winMutexInit == FALSE ){
Sleep(1);
}
}
return SXRET_OK;
}
static void WinMutexGlobalRelease(void)
{
LONG rc;
rc = InterlockedCompareExchange(&winMutexLock,0,1);
if( rc == 1 ){
/* The first to decrement to zero does the actual global release */
if( winMutexInit == TRUE ){
sxu32 n;
for( n = 0 ; n < SX_ARRAYSIZE(aStaticMutexes) ; ++n ){
DeleteCriticalSection(&aStaticMutexes[n].sMutex);
}
winMutexInit = FALSE;
}
}
}
static SyMutex * WinMutexNew(int nType)
{
SyMutex *pMutex = 0;
if( nType == SXMUTEX_TYPE_FAST || nType == SXMUTEX_TYPE_RECURSIVE ){
/* Allocate a new mutex */
pMutex = (SyMutex *)HeapAlloc(GetProcessHeap(),0,sizeof(SyMutex));
if( pMutex == 0 ){
return 0;
}
InitializeCriticalSection(&pMutex->sMutex);
}else{
/* Use a pre-allocated static mutex */
if( nType > SXMUTEX_TYPE_STATIC_6 ){
nType = SXMUTEX_TYPE_STATIC_6;
}
pMutex = &aStaticMutexes[nType - 3];
}
pMutex->nType = nType;
return pMutex;
}
static void WinMutexRelease(SyMutex *pMutex)
{
if( pMutex->nType == SXMUTEX_TYPE_FAST || pMutex->nType == SXMUTEX_TYPE_RECURSIVE ){
DeleteCriticalSection(&pMutex->sMutex);
HeapFree(GetProcessHeap(),0,pMutex);
}
}
static void WinMutexEnter(SyMutex *pMutex)
{
EnterCriticalSection(&pMutex->sMutex);
}
static sxi32 WinMutexTryEnter(SyMutex *pMutex)
{
#ifdef _WIN32_WINNT
BOOL rc;
/* Only WindowsNT platforms */
rc = TryEnterCriticalSection(&pMutex->sMutex);
if( rc ){
return SXRET_OK;
}else{
return SXERR_BUSY;
}
#else
return SXERR_NOTIMPLEMENTED;
#endif
}
static void WinMutexLeave(SyMutex *pMutex)
{
LeaveCriticalSection(&pMutex->sMutex);
}
/* Export Windows mutex interfaces */
static const SyMutexMethods sWinMutexMethods = {
WinMutexGlobaInit, /* xGlobalInit() */
WinMutexGlobalRelease, /* xGlobalRelease() */
WinMutexNew, /* xNew() */
WinMutexRelease, /* xRelease() */
WinMutexEnter, /* xEnter() */
WinMutexTryEnter, /* xTryEnter() */
WinMutexLeave /* xLeave() */
};
PH7_PRIVATE const SyMutexMethods * SyMutexExportMethods(void)
{
return &sWinMutexMethods;
}
#elif defined(__UNIXES__)
#include <pthread.h>
struct SyMutex
{
pthread_mutex_t sMutex;
sxu32 nType;
};
static SyMutex * UnixMutexNew(int nType)
{
static SyMutex aStaticMutexes[] = {
{PTHREAD_MUTEX_INITIALIZER,SXMUTEX_TYPE_STATIC_1},
{PTHREAD_MUTEX_INITIALIZER,SXMUTEX_TYPE_STATIC_2},
{PTHREAD_MUTEX_INITIALIZER,SXMUTEX_TYPE_STATIC_3},
{PTHREAD_MUTEX_INITIALIZER,SXMUTEX_TYPE_STATIC_4},
{PTHREAD_MUTEX_INITIALIZER,SXMUTEX_TYPE_STATIC_5},
{PTHREAD_MUTEX_INITIALIZER,SXMUTEX_TYPE_STATIC_6}
};
SyMutex *pMutex;
if( nType == SXMUTEX_TYPE_FAST || nType == SXMUTEX_TYPE_RECURSIVE ){
pthread_mutexattr_t sRecursiveAttr;
/* Allocate a new mutex */
pMutex = (SyMutex *)malloc(sizeof(SyMutex));
if( pMutex == 0 ){
return 0;
}
if( nType == SXMUTEX_TYPE_RECURSIVE ){
pthread_mutexattr_init(&sRecursiveAttr);
pthread_mutexattr_settype(&sRecursiveAttr,PTHREAD_MUTEX_RECURSIVE);
}
pthread_mutex_init(&pMutex->sMutex,nType == SXMUTEX_TYPE_RECURSIVE ? &sRecursiveAttr : 0 );
if( nType == SXMUTEX_TYPE_RECURSIVE ){
pthread_mutexattr_destroy(&sRecursiveAttr);
}
}else{
/* Use a pre-allocated static mutex */
if( nType > SXMUTEX_TYPE_STATIC_6 ){
nType = SXMUTEX_TYPE_STATIC_6;
}
pMutex = &aStaticMutexes[nType - 3];
}
pMutex->nType = nType;
return pMutex;
}
static void UnixMutexRelease(SyMutex *pMutex)
{
if( pMutex->nType == SXMUTEX_TYPE_FAST || pMutex->nType == SXMUTEX_TYPE_RECURSIVE ){
pthread_mutex_destroy(&pMutex->sMutex);
free(pMutex);
}
}
static void UnixMutexEnter(SyMutex *pMutex)
{
pthread_mutex_lock(&pMutex->sMutex);
}
static void UnixMutexLeave(SyMutex *pMutex)
{
pthread_mutex_unlock(&pMutex->sMutex);
}
/* Export pthread mutex interfaces */
static const SyMutexMethods sPthreadMutexMethods = {
0, /* xGlobalInit() */
0, /* xGlobalRelease() */
UnixMutexNew, /* xNew() */
UnixMutexRelease, /* xRelease() */
UnixMutexEnter, /* xEnter() */
0, /* xTryEnter() */
UnixMutexLeave /* xLeave() */
};
PH7_PRIVATE const SyMutexMethods * SyMutexExportMethods(void)
{
return &sPthreadMutexMethods;
}
#else
/* Host application must register their own mutex subsystem if the target
* platform is not an UNIX-like or windows systems.
*/
struct SyMutex
{
sxu32 nType;
};
static SyMutex * DummyMutexNew(int nType)
{
static SyMutex sMutex;
SXUNUSED(nType);
return &sMutex;
}
static void DummyMutexRelease(SyMutex *pMutex)
{
SXUNUSED(pMutex);
}
static void DummyMutexEnter(SyMutex *pMutex)
{
SXUNUSED(pMutex);
}
static void DummyMutexLeave(SyMutex *pMutex)
{
SXUNUSED(pMutex);
}
/* Export the dummy mutex interfaces */
static const SyMutexMethods sDummyMutexMethods = {
0, /* xGlobalInit() */
0, /* xGlobalRelease() */
DummyMutexNew, /* xNew() */
DummyMutexRelease, /* xRelease() */
DummyMutexEnter, /* xEnter() */
0, /* xTryEnter() */
DummyMutexLeave /* xLeave() */
};
PH7_PRIVATE const SyMutexMethods * SyMutexExportMethods(void)
{
return &sDummyMutexMethods;
}
#endif /* __WINNT__ */
#endif /* PH7_ENABLE_THREADS */
static void * SyOSHeapAlloc(sxu32 nByte)
{
void *pNew;
#if defined(__WINNT__)
pNew = HeapAlloc(GetProcessHeap(),0,nByte);
#else
pNew = malloc((size_t)nByte);
#endif
return pNew;
}
static void * SyOSHeapRealloc(void *pOld,sxu32 nByte)
{
void *pNew;
#if defined(__WINNT__)
pNew = HeapReAlloc(GetProcessHeap(),0,pOld,nByte);
#else
pNew = realloc(pOld,(size_t)nByte);
#endif
return pNew;
}
static void SyOSHeapFree(void *pPtr)
{
#if defined(__WINNT__)
HeapFree(GetProcessHeap(),0,pPtr);
#else
free(pPtr);
#endif
}
/* SyRunTimeApi:sxstr.c */
PH7_PRIVATE sxu32 SyStrlen(const char *zSrc)
{
register const char *zIn = zSrc;
#if defined(UNTRUST)
if( zIn == 0 ){
return 0;
}
#endif
for(;;){
if( !zIn[0] ){ break; } zIn++;
if( !zIn[0] ){ break; } zIn++;
if( !zIn[0] ){ break; } zIn++;
if( !zIn[0] ){ break; } zIn++;
}
return (sxu32)(zIn - zSrc);
}
PH7_PRIVATE sxi32 SyByteFind(const char *zStr,sxu32 nLen,sxi32 c,sxu32 *pPos)
{
const char *zIn = zStr;
const char *zEnd;
zEnd = &zIn[nLen];
for(;;){
if( zIn >= zEnd ){ break; }if( zIn[0] == c ){ if( pPos ){ *pPos = (sxu32)(zIn - zStr); } return SXRET_OK; } zIn++;
if( zIn >= zEnd ){ break; }if( zIn[0] == c ){ if( pPos ){ *pPos = (sxu32)(zIn - zStr); } return SXRET_OK; } zIn++;
if( zIn >= zEnd ){ break; }if( zIn[0] == c ){ if( pPos ){ *pPos = (sxu32)(zIn - zStr); } return SXRET_OK; } zIn++;
if( zIn >= zEnd ){ break; }if( zIn[0] == c ){ if( pPos ){ *pPos = (sxu32)(zIn - zStr); } return SXRET_OK; } zIn++;
}
return SXERR_NOTFOUND;
}
#ifndef PH7_DISABLE_BUILTIN_FUNC
PH7_PRIVATE sxi32 SyByteFind2(const char *zStr,sxu32 nLen,sxi32 c,sxu32 *pPos)
{
const char *zIn = zStr;
const char *zEnd;
zEnd = &zIn[nLen - 1];
for( ;; ){
if( zEnd < zIn ){ break; } if( zEnd[0] == c ){ if( pPos ){ *pPos = (sxu32)(zEnd - zIn);} return SXRET_OK; } zEnd--;
if( zEnd < zIn ){ break; } if( zEnd[0] == c ){ if( pPos ){ *pPos = (sxu32)(zEnd - zIn);} return SXRET_OK; } zEnd--;
if( zEnd < zIn ){ break; } if( zEnd[0] == c ){ if( pPos ){ *pPos = (sxu32)(zEnd - zIn);} return SXRET_OK; } zEnd--;
if( zEnd < zIn ){ break; } if( zEnd[0] == c ){ if( pPos ){ *pPos = (sxu32)(zEnd - zIn);} return SXRET_OK; } zEnd--;
}
return SXERR_NOTFOUND;
}
#endif /* PH7_DISABLE_BUILTIN_FUNC */
PH7_PRIVATE sxi32 SyByteListFind(const char *zSrc,sxu32 nLen,const char *zList,sxu32 *pFirstPos)
{
const char *zIn = zSrc;
const char *zPtr;
const char *zEnd;
sxi32 c;
zEnd = &zSrc[nLen];
for(;;){
if( zIn >= zEnd ){ break; } for(zPtr = zList ; (c = zPtr[0]) != 0 ; zPtr++ ){ if( zIn[0] == c ){ if( pFirstPos ){ *pFirstPos = (sxu32)(zIn - zSrc); } return SXRET_OK; } } zIn++;
if( zIn >= zEnd ){ break; } for(zPtr = zList ; (c = zPtr[0]) != 0 ; zPtr++ ){ if( zIn[0] == c ){ if( pFirstPos ){ *pFirstPos = (sxu32)(zIn - zSrc); } return SXRET_OK; } } zIn++;
if( zIn >= zEnd ){ break; } for(zPtr = zList ; (c = zPtr[0]) != 0 ; zPtr++ ){ if( zIn[0] == c ){ if( pFirstPos ){ *pFirstPos = (sxu32)(zIn - zSrc); } return SXRET_OK; } } zIn++;
if( zIn >= zEnd ){ break; } for(zPtr = zList ; (c = zPtr[0]) != 0 ; zPtr++ ){ if( zIn[0] == c ){ if( pFirstPos ){ *pFirstPos = (sxu32)(zIn - zSrc); } return SXRET_OK; } } zIn++;
}
return SXERR_NOTFOUND;
}
#ifndef PH7_DISABLE_BUILTIN_FUNC
PH7_PRIVATE sxi32 SyStrncmp(const char *zLeft,const char *zRight,sxu32 nLen)
{
const unsigned char *zP = (const unsigned char *)zLeft;
const unsigned char *zQ = (const unsigned char *)zRight;
if( SX_EMPTY_STR(zP) || SX_EMPTY_STR(zQ) ){
return SX_EMPTY_STR(zP) ? (SX_EMPTY_STR(zQ) ? 0 : -1) :1;
}
if( nLen <= 0 ){
return 0;
}
for(;;){
if( nLen <= 0 ){ return 0; } if( zP[0] == 0 || zQ[0] == 0 || zP[0] != zQ[0] ){ break; } zP++; zQ++; nLen--;
if( nLen <= 0 ){ return 0; } if( zP[0] == 0 || zQ[0] == 0 || zP[0] != zQ[0] ){ break; } zP++; zQ++; nLen--;
if( nLen <= 0 ){ return 0; } if( zP[0] == 0 || zQ[0] == 0 || zP[0] != zQ[0] ){ break; } zP++; zQ++; nLen--;
if( nLen <= 0 ){ return 0; } if( zP[0] == 0 || zQ[0] == 0 || zP[0] != zQ[0] ){ break; } zP++; zQ++; nLen--;
}
return (sxi32)(zP[0] - zQ[0]);
}
#endif
PH7_PRIVATE sxi32 SyStrnicmp(const char *zLeft, const char *zRight,sxu32 SLen)
{
register unsigned char *p = (unsigned char *)zLeft;
register unsigned char *q = (unsigned char *)zRight;
if( SX_EMPTY_STR(p) || SX_EMPTY_STR(q) ){
return SX_EMPTY_STR(p)? SX_EMPTY_STR(q) ? 0 : -1 :1;
}
for(;;){
if( !SLen ){ return 0; }if( !*p || !*q || SyCharToLower(*p) != SyCharToLower(*q) ){ break; }p++;q++;--SLen;
if( !SLen ){ return 0; }if( !*p || !*q || SyCharToLower(*p) != SyCharToLower(*q) ){ break; }p++;q++;--SLen;
if( !SLen ){ return 0; }if( !*p || !*q || SyCharToLower(*p) != SyCharToLower(*q) ){ break; }p++;q++;--SLen;
if( !SLen ){ return 0; }if( !*p || !*q || SyCharToLower(*p) != SyCharToLower(*q) ){ break; }p++;q++;--SLen;
}
return (sxi32)(SyCharToLower(p[0]) - SyCharToLower(q[0]));
}
PH7_PRIVATE sxi32 SyStrnmicmp(const void *pLeft, const void *pRight,sxu32 SLen)
{
return SyStrnicmp((const char *)pLeft,(const char *)pRight,SLen);
}
static sxu32 Systrcpy(char *zDest,sxu32 nDestLen,const char *zSrc,sxu32 nLen)
{
unsigned char *zBuf = (unsigned char *)zDest;
unsigned char *zIn = (unsigned char *)zSrc;
unsigned char *zEnd;
#if defined(UNTRUST)
if( zSrc == (const char *)zDest ){
return 0;
}
#endif
if( nLen <= 0 ){
nLen = SyStrlen(zSrc);
}
zEnd = &zBuf[nDestLen - 1]; /* reserve a room for the null terminator */
for(;;){
if( zBuf >= zEnd || nLen == 0 ){ break;} zBuf[0] = zIn[0]; zIn++; zBuf++; nLen--;
if( zBuf >= zEnd || nLen == 0 ){ break;} zBuf[0] = zIn[0]; zIn++; zBuf++; nLen--;
if( zBuf >= zEnd || nLen == 0 ){ break;} zBuf[0] = zIn[0]; zIn++; zBuf++; nLen--;
if( zBuf >= zEnd || nLen == 0 ){ break;} zBuf[0] = zIn[0]; zIn++; zBuf++; nLen--;
}
zBuf[0] = 0;
return (sxu32)(zBuf-(unsigned char *)zDest);
}
/* SyRunTimeApi:sxmem.c */
PH7_PRIVATE void SyZero(void *pSrc,sxu32 nSize)
{
register unsigned char *zSrc = (unsigned char *)pSrc;
unsigned char *zEnd;
#if defined(UNTRUST)
if( zSrc == 0 || nSize <= 0 ){
return ;
}
#endif
zEnd = &zSrc[nSize];
for(;;){
if( zSrc >= zEnd ){break;} zSrc[0] = 0; zSrc++;
if( zSrc >= zEnd ){break;} zSrc[0] = 0; zSrc++;
if( zSrc >= zEnd ){break;} zSrc[0] = 0; zSrc++;
if( zSrc >= zEnd ){break;} zSrc[0] = 0; zSrc++;
}
}
PH7_PRIVATE sxi32 SyMemcmp(const void *pB1,const void *pB2,sxu32 nSize)
{
sxi32 rc;
if( nSize <= 0 ){
return 0;
}
if( pB1 == 0 || pB2 == 0 ){
return pB1 != 0 ? 1 : (pB2 == 0 ? 0 : -1);
}
SX_MACRO_FAST_CMP(pB1,pB2,nSize,rc);
return rc;
}
PH7_PRIVATE sxu32 SyMemcpy(const void *pSrc,void *pDest,sxu32 nLen)
{
#if defined(UNTRUST)
if( pSrc == 0 || pDest == 0 ){
return 0;
}
#endif
if( pSrc == (const void *)pDest ){
return nLen;
}
SX_MACRO_FAST_MEMCPY(pSrc,pDest,nLen);
return nLen;
}
static void * MemOSAlloc(sxu32 nBytes)
{
sxu32 *pChunk;
pChunk = (sxu32 *)SyOSHeapAlloc(nBytes + sizeof(sxu32));
if( pChunk == 0 ){
return 0;
}
pChunk[0] = nBytes;
return (void *)&pChunk[1];
}
static void * MemOSRealloc(void *pOld,sxu32 nBytes)
{
sxu32 *pOldChunk;
sxu32 *pChunk;
pOldChunk = (sxu32 *)(((char *)pOld)-sizeof(sxu32));
if( pOldChunk[0] >= nBytes ){
return pOld;
}
pChunk = (sxu32 *)SyOSHeapRealloc(pOldChunk,nBytes + sizeof(sxu32));
if( pChunk == 0 ){
return 0;
}
pChunk[0] = nBytes;
return (void *)&pChunk[1];
}
static void MemOSFree(void *pBlock)
{
void *pChunk;
pChunk = (void *)(((char *)pBlock)-sizeof(sxu32));
SyOSHeapFree(pChunk);
}
static sxu32 MemOSChunkSize(void *pBlock)
{
sxu32 *pChunk;
pChunk = (sxu32 *)(((char *)pBlock)-sizeof(sxu32));
return pChunk[0];
}
/* Export OS allocation methods */
static const SyMemMethods sOSAllocMethods = {
MemOSAlloc,
MemOSRealloc,
MemOSFree,
MemOSChunkSize,
0,
0,
0
};
static void * MemBackendAlloc(SyMemBackend *pBackend,sxu32 nByte)
{
SyMemBlock *pBlock;
sxi32 nRetry = 0;
/* Append an extra block so we can tracks allocated chunks and avoid memory
* leaks.
*/
nByte += sizeof(SyMemBlock);
for(;;){
pBlock = (SyMemBlock *)pBackend->pMethods->xAlloc(nByte);
if( pBlock != 0 || pBackend->xMemError == 0 || nRetry > SXMEM_BACKEND_RETRY
|| SXERR_RETRY != pBackend->xMemError(pBackend->pUserData) ){
break;
}
nRetry++;
}
if( pBlock == 0 ){
return 0;
}
pBlock->pNext = pBlock->pPrev = 0;
/* Link to the list of already tracked blocks */
MACRO_LD_PUSH(pBackend->pBlocks,pBlock);
#if defined(UNTRUST)
pBlock->nGuard = SXMEM_BACKEND_MAGIC;
#endif
pBackend->nBlock++;
return (void *)&pBlock[1];
}
PH7_PRIVATE void * SyMemBackendAlloc(SyMemBackend *pBackend,sxu32 nByte)
{
void *pChunk;
#if defined(UNTRUST)
if( SXMEM_BACKEND_CORRUPT(pBackend) ){
return 0;
}
#endif
if( pBackend->pMutexMethods ){
SyMutexEnter(pBackend->pMutexMethods,pBackend->pMutex);
}
pChunk = MemBackendAlloc(&(*pBackend),nByte);
if( pBackend->pMutexMethods ){
SyMutexLeave(pBackend->pMutexMethods,pBackend->pMutex);
}
return pChunk;
}
static void * MemBackendRealloc(SyMemBackend *pBackend,void * pOld,sxu32 nByte)
{
SyMemBlock *pBlock,*pNew,*pPrev,*pNext;
sxu32 nRetry = 0;
if( pOld == 0 ){
return MemBackendAlloc(&(*pBackend),nByte);
}
pBlock = (SyMemBlock *)(((char *)pOld) - sizeof(SyMemBlock));
#if defined(UNTRUST)
if( pBlock->nGuard != SXMEM_BACKEND_MAGIC ){
return 0;
}
#endif
nByte += sizeof(SyMemBlock);
pPrev = pBlock->pPrev;
pNext = pBlock->pNext;
for(;;){
pNew = (SyMemBlock *)pBackend->pMethods->xRealloc(pBlock,nByte);
if( pNew != 0 || pBackend->xMemError == 0 || nRetry > SXMEM_BACKEND_RETRY ||
SXERR_RETRY != pBackend->xMemError(pBackend->pUserData) ){
break;
}
nRetry++;
}
if( pNew == 0 ){
return 0;
}
if( pNew != pBlock ){
if( pPrev == 0 ){
pBackend->pBlocks = pNew;
}else{
pPrev->pNext = pNew;
}
if( pNext ){
pNext->pPrev = pNew;
}
#if defined(UNTRUST)
pNew->nGuard = SXMEM_BACKEND_MAGIC;
#endif
}
return (void *)&pNew[1];
}
PH7_PRIVATE void * SyMemBackendRealloc(SyMemBackend *pBackend,void * pOld,sxu32 nByte)
{
void *pChunk;
#if defined(UNTRUST)
if( SXMEM_BACKEND_CORRUPT(pBackend) ){
return 0;
}
#endif
if( pBackend->pMutexMethods ){
SyMutexEnter(pBackend->pMutexMethods,pBackend->pMutex);
}
pChunk = MemBackendRealloc(&(*pBackend),pOld,nByte);
if( pBackend->pMutexMethods ){
SyMutexLeave(pBackend->pMutexMethods,pBackend->pMutex);
}
return pChunk;
}
static sxi32 MemBackendFree(SyMemBackend *pBackend,void * pChunk)
{
SyMemBlock *pBlock;
pBlock = (SyMemBlock *)(((char *)pChunk) - sizeof(SyMemBlock));
#if defined(UNTRUST)
if( pBlock->nGuard != SXMEM_BACKEND_MAGIC ){
return SXERR_CORRUPT;
}
#endif
/* Unlink from the list of active blocks */
if( pBackend->nBlock > 0 ){
/* Release the block */
#if defined(UNTRUST)
/* Mark as stale block */
pBlock->nGuard = 0x635B;
#endif
MACRO_LD_REMOVE(pBackend->pBlocks,pBlock);
pBackend->nBlock--;
pBackend->pMethods->xFree(pBlock);
}
return SXRET_OK;
}
PH7_PRIVATE sxi32 SyMemBackendFree(SyMemBackend *pBackend,void * pChunk)
{
sxi32 rc;
#if defined(UNTRUST)
if( SXMEM_BACKEND_CORRUPT(pBackend) ){
return SXERR_CORRUPT;
}
#endif
if( pChunk == 0 ){
return SXRET_OK;
}
if( pBackend->pMutexMethods ){
SyMutexEnter(pBackend->pMutexMethods,pBackend->pMutex);
}
rc = MemBackendFree(&(*pBackend),pChunk);
if( pBackend->pMutexMethods ){
SyMutexLeave(pBackend->pMutexMethods,pBackend->pMutex);
}
return rc;
}
#if defined(PH7_ENABLE_THREADS)
PH7_PRIVATE sxi32 SyMemBackendMakeThreadSafe(SyMemBackend *pBackend,const SyMutexMethods *pMethods)
{
SyMutex *pMutex;
#if defined(UNTRUST)
if( SXMEM_BACKEND_CORRUPT(pBackend) || pMethods == 0 || pMethods->xNew == 0){
return SXERR_CORRUPT;
}
#endif
pMutex = pMethods->xNew(SXMUTEX_TYPE_FAST);
if( pMutex == 0 ){
return SXERR_OS;
}
/* Attach the mutex to the memory backend */
pBackend->pMutex = pMutex;
pBackend->pMutexMethods = pMethods;
return SXRET_OK;
}
PH7_PRIVATE sxi32 SyMemBackendDisbaleMutexing(SyMemBackend *pBackend)
{
#if defined(UNTRUST)
if( SXMEM_BACKEND_CORRUPT(pBackend) ){
return SXERR_CORRUPT;
}
#endif
if( pBackend->pMutex == 0 ){
/* There is no mutex subsystem at all */
return SXRET_OK;
}
SyMutexRelease(pBackend->pMutexMethods,pBackend->pMutex);
pBackend->pMutexMethods = 0;
pBackend->pMutex = 0;
return SXRET_OK;
}
#endif
/*
* Memory pool allocator
*/
#define SXMEM_POOL_MAGIC 0xDEAD
#define SXMEM_POOL_MAXALLOC (1<<(SXMEM_POOL_NBUCKETS+SXMEM_POOL_INCR))
#define SXMEM_POOL_MINALLOC (1<<(SXMEM_POOL_INCR))
static sxi32 MemPoolBucketAlloc(SyMemBackend *pBackend,sxu32 nBucket)
{
char *zBucket,*zBucketEnd;
SyMemHeader *pHeader;
sxu32 nBucketSize;
/* Allocate one big block first */
zBucket = (char *)MemBackendAlloc(&(*pBackend),SXMEM_POOL_MAXALLOC);
if( zBucket == 0 ){
return SXERR_MEM;
}
zBucketEnd = &zBucket[SXMEM_POOL_MAXALLOC];
/* Divide the big block into mini bucket pool */
nBucketSize = 1 << (nBucket + SXMEM_POOL_INCR);
pBackend->apPool[nBucket] = pHeader = (SyMemHeader *)zBucket;
for(;;){
if( &zBucket[nBucketSize] >= zBucketEnd ){
break;
}
pHeader->pNext = (SyMemHeader *)&zBucket[nBucketSize];
/* Advance the cursor to the next available chunk */
pHeader = pHeader->pNext;
zBucket += nBucketSize;
}
pHeader->pNext = 0;
return SXRET_OK;
}
static void * MemBackendPoolAlloc(SyMemBackend *pBackend,sxu32 nByte)
{
SyMemHeader *pBucket,*pNext;
sxu32 nBucketSize;
sxu32 nBucket;
if( nByte + sizeof(SyMemHeader) >= SXMEM_POOL_MAXALLOC ){
/* Allocate a big chunk directly */
pBucket = (SyMemHeader *)MemBackendAlloc(&(*pBackend),nByte+sizeof(SyMemHeader));
if( pBucket == 0 ){
return 0;
}
/* Record as big block */
pBucket->nBucket = (sxu32)(SXMEM_POOL_MAGIC << 16) | SXU16_HIGH;
return (void *)(pBucket+1);
}
/* Locate the appropriate bucket */
nBucket = 0;
nBucketSize = SXMEM_POOL_MINALLOC;
while( nByte + sizeof(SyMemHeader) > nBucketSize ){
nBucketSize <<= 1;
nBucket++;
}
pBucket = pBackend->apPool[nBucket];
if( pBucket == 0 ){
sxi32 rc;
rc = MemPoolBucketAlloc(&(*pBackend),nBucket);
if( rc != SXRET_OK ){
return 0;
}
pBucket = pBackend->apPool[nBucket];
}
/* Remove from the free list */
pNext = pBucket->pNext;
pBackend->apPool[nBucket] = pNext;
/* Record bucket&magic number */
pBucket->nBucket = (SXMEM_POOL_MAGIC << 16) | nBucket;
return (void *)&pBucket[1];
}
PH7_PRIVATE void * SyMemBackendPoolAlloc(SyMemBackend *pBackend,sxu32 nByte)
{
void *pChunk;
#if defined(UNTRUST)
if( SXMEM_BACKEND_CORRUPT(pBackend) ){
return 0;
}
#endif
if( pBackend->pMutexMethods ){
SyMutexEnter(pBackend->pMutexMethods,pBackend->pMutex);
}
pChunk = MemBackendPoolAlloc(&(*pBackend),nByte);
if( pBackend->pMutexMethods ){
SyMutexLeave(pBackend->pMutexMethods,pBackend->pMutex);
}
return pChunk;
}
static sxi32 MemBackendPoolFree(SyMemBackend *pBackend,void * pChunk)
{
SyMemHeader *pHeader;
sxu32 nBucket;
/* Get the corresponding bucket */
pHeader = (SyMemHeader *)(((char *)pChunk) - sizeof(SyMemHeader));
/* Sanity check to avoid misuse */
if( (pHeader->nBucket >> 16) != SXMEM_POOL_MAGIC ){
return SXERR_CORRUPT;
}
nBucket = pHeader->nBucket & 0xFFFF;
if( nBucket == SXU16_HIGH ){
/* Free the big block */
MemBackendFree(&(*pBackend),pHeader);
}else{
/* Return to the free list */
pHeader->pNext = pBackend->apPool[nBucket & 0x0f];
pBackend->apPool[nBucket & 0x0f] = pHeader;
}
return SXRET_OK;
}
PH7_PRIVATE sxi32 SyMemBackendPoolFree(SyMemBackend *pBackend,void * pChunk)
{
sxi32 rc;
#if defined(UNTRUST)
if( SXMEM_BACKEND_CORRUPT(pBackend) || pChunk == 0 ){
return SXERR_CORRUPT;
}
#endif
if( pBackend->pMutexMethods ){
SyMutexEnter(pBackend->pMutexMethods,pBackend->pMutex);
}
rc = MemBackendPoolFree(&(*pBackend),pChunk);
if( pBackend->pMutexMethods ){
SyMutexLeave(pBackend->pMutexMethods,pBackend->pMutex);
}
return rc;
}
#if 0
static void * MemBackendPoolRealloc(SyMemBackend *pBackend,void * pOld,sxu32 nByte)
{
sxu32 nBucket,nBucketSize;
SyMemHeader *pHeader;
void * pNew;
if( pOld == 0 ){
/* Allocate a new pool */
pNew = MemBackendPoolAlloc(&(*pBackend),nByte);
return pNew;
}
/* Get the corresponding bucket */
pHeader = (SyMemHeader *)(((char *)pOld) - sizeof(SyMemHeader));
/* Sanity check to avoid misuse */
if( (pHeader->nBucket >> 16) != SXMEM_POOL_MAGIC ){
return 0;
}
nBucket = pHeader->nBucket & 0xFFFF;
if( nBucket == SXU16_HIGH ){
/* Big block */
return MemBackendRealloc(&(*pBackend),pHeader,nByte);
}
nBucketSize = 1 << (nBucket + SXMEM_POOL_INCR);
if( nBucketSize >= nByte + sizeof(SyMemHeader) ){
/* The old bucket can honor the requested size */
return pOld;
}
/* Allocate a new pool */
pNew = MemBackendPoolAlloc(&(*pBackend),nByte);
if( pNew == 0 ){
return 0;
}
/* Copy the old data into the new block */
SyMemcpy(pOld,pNew,nBucketSize);
/* Free the stale block */
MemBackendPoolFree(&(*pBackend),pOld);
return pNew;
}
PH7_PRIVATE void * SyMemBackendPoolRealloc(SyMemBackend *pBackend,void * pOld,sxu32 nByte)
{
void *pChunk;
#if defined(UNTRUST)
if( SXMEM_BACKEND_CORRUPT(pBackend) ){
return 0;
}
#endif
if( pBackend->pMutexMethods ){
SyMutexEnter(pBackend->pMutexMethods,pBackend->pMutex);
}
pChunk = MemBackendPoolRealloc(&(*pBackend),pOld,nByte);
if( pBackend->pMutexMethods ){
SyMutexLeave(pBackend->pMutexMethods,pBackend->pMutex);
}
return pChunk;
}
#endif
PH7_PRIVATE sxi32 SyMemBackendInit(SyMemBackend *pBackend,ProcMemError xMemErr,void * pUserData)
{
#if defined(UNTRUST)
if( pBackend == 0 ){
return SXERR_EMPTY;
}
#endif
/* Zero the allocator first */
SyZero(&(*pBackend),sizeof(SyMemBackend));
pBackend->xMemError = xMemErr;
pBackend->pUserData = pUserData;
/* Switch to the OS memory allocator */
pBackend->pMethods = &sOSAllocMethods;
if( pBackend->pMethods->xInit ){
/* Initialize the backend */
if( SXRET_OK != pBackend->pMethods->xInit(pBackend->pMethods->pUserData) ){
return SXERR_ABORT;
}
}
#if defined(UNTRUST)
pBackend->nMagic = SXMEM_BACKEND_MAGIC;
#endif
return SXRET_OK;
}
PH7_PRIVATE sxi32 SyMemBackendInitFromOthers(SyMemBackend *pBackend,const SyMemMethods *pMethods,ProcMemError xMemErr,void * pUserData)
{
#if defined(UNTRUST)
if( pBackend == 0 || pMethods == 0){
return SXERR_EMPTY;
}
#endif
if( pMethods->xAlloc == 0 || pMethods->xRealloc == 0 || pMethods->xFree == 0 || pMethods->xChunkSize == 0 ){
/* mandatory methods are missing */
return SXERR_INVALID;
}
/* Zero the allocator first */
SyZero(&(*pBackend),sizeof(SyMemBackend));
pBackend->xMemError = xMemErr;
pBackend->pUserData = pUserData;
/* Switch to the host application memory allocator */
pBackend->pMethods = pMethods;
if( pBackend->pMethods->xInit ){
/* Initialize the backend */
if( SXRET_OK != pBackend->pMethods->xInit(pBackend->pMethods->pUserData) ){
return SXERR_ABORT;
}
}
#if defined(UNTRUST)
pBackend->nMagic = SXMEM_BACKEND_MAGIC;
#endif
return SXRET_OK;
}
PH7_PRIVATE sxi32 SyMemBackendInitFromParent(SyMemBackend *pBackend,SyMemBackend *pParent)
{
sxu8 bInheritMutex;
#if defined(UNTRUST)
if( pBackend == 0 || SXMEM_BACKEND_CORRUPT(pParent) ){
return SXERR_CORRUPT;
}
#endif
/* Zero the allocator first */
SyZero(&(*pBackend),sizeof(SyMemBackend));
pBackend->pMethods = pParent->pMethods;
pBackend->xMemError = pParent->xMemError;
pBackend->pUserData = pParent->pUserData;
bInheritMutex = pParent->pMutexMethods ? TRUE : FALSE;
if( bInheritMutex ){
pBackend->pMutexMethods = pParent->pMutexMethods;
/* Create a private mutex */
pBackend->pMutex = pBackend->pMutexMethods->xNew(SXMUTEX_TYPE_FAST);
if( pBackend->pMutex == 0){
return SXERR_OS;
}
}
#if defined(UNTRUST)
pBackend->nMagic = SXMEM_BACKEND_MAGIC;
#endif
return SXRET_OK;
}
static sxi32 MemBackendRelease(SyMemBackend *pBackend)
{
SyMemBlock *pBlock,*pNext;
pBlock = pBackend->pBlocks;
for(;;){
if( pBackend->nBlock == 0 ){
break;
}
pNext = pBlock->pNext;
pBackend->pMethods->xFree(pBlock);
pBlock = pNext;
pBackend->nBlock--;
/* LOOP ONE */
if( pBackend->nBlock == 0 ){
break;
}
pNext = pBlock->pNext;
pBackend->pMethods->xFree(pBlock);
pBlock = pNext;
pBackend->nBlock--;
/* LOOP TWO */
if( pBackend->nBlock == 0 ){
break;
}
pNext = pBlock->pNext;
pBackend->pMethods->xFree(pBlock);
pBlock = pNext;
pBackend->nBlock--;
/* LOOP THREE */
if( pBackend->nBlock == 0 ){
break;
}
pNext = pBlock->pNext;
pBackend->pMethods->xFree(pBlock);
pBlock = pNext;
pBackend->nBlock--;
/* LOOP FOUR */
}
if( pBackend->pMethods->xRelease ){
pBackend->pMethods->xRelease(pBackend->pMethods->pUserData);
}
pBackend->pMethods = 0;
pBackend->pBlocks = 0;
#if defined(UNTRUST)
pBackend->nMagic = 0x2626;
#endif
return SXRET_OK;
}
PH7_PRIVATE sxi32 SyMemBackendRelease(SyMemBackend *pBackend)
{
sxi32 rc;
#if defined(UNTRUST)
if( SXMEM_BACKEND_CORRUPT(pBackend) ){
return SXERR_INVALID;
}
#endif
if( pBackend->pMutexMethods ){
SyMutexEnter(pBackend->pMutexMethods,pBackend->pMutex);
}
rc = MemBackendRelease(&(*pBackend));
if( pBackend->pMutexMethods ){
SyMutexLeave(pBackend->pMutexMethods,pBackend->pMutex);
SyMutexRelease(pBackend->pMutexMethods,pBackend->pMutex);
}
return SXRET_OK;
}
PH7_PRIVATE void * SyMemBackendDup(SyMemBackend *pBackend,const void *pSrc,sxu32 nSize)
{
void *pNew;
#if defined(UNTRUST)
if( pSrc == 0 || nSize <= 0 ){
return 0;
}
#endif
pNew = SyMemBackendAlloc(&(*pBackend),nSize);
if( pNew ){
SyMemcpy(pSrc,pNew,nSize);
}
return pNew;
}
PH7_PRIVATE char * SyMemBackendStrDup(SyMemBackend *pBackend,const char *zSrc,sxu32 nSize)
{
char *zDest;
zDest = (char *)SyMemBackendAlloc(&(*pBackend),nSize + 1);
if( zDest ){
Systrcpy(zDest,nSize+1,zSrc,nSize);
}
return zDest;
}
PH7_PRIVATE sxi32 SyBlobInitFromBuf(SyBlob *pBlob,void *pBuffer,sxu32 nSize)
{
#if defined(UNTRUST)
if( pBlob == 0 || pBuffer == 0 || nSize < 1 ){
return SXERR_EMPTY;
}
#endif
pBlob->pBlob = pBuffer;
pBlob->mByte = nSize;
pBlob->nByte = 0;
pBlob->pAllocator = 0;
pBlob->nFlags = SXBLOB_LOCKED|SXBLOB_STATIC;
return SXRET_OK;
}
PH7_PRIVATE sxi32 SyBlobInit(SyBlob *pBlob,SyMemBackend *pAllocator)
{
#if defined(UNTRUST)
if( pBlob == 0 ){
return SXERR_EMPTY;
}
#endif
pBlob->pBlob = 0;
pBlob->mByte = pBlob->nByte = 0;
pBlob->pAllocator = &(*pAllocator);
pBlob->nFlags = 0;
return SXRET_OK;
}
PH7_PRIVATE sxi32 SyBlobReadOnly(SyBlob *pBlob,const void *pData,sxu32 nByte)
{
#if defined(UNTRUST)
if( pBlob == 0 ){
return SXERR_EMPTY;
}
#endif
pBlob->pBlob = (void *)pData;
pBlob->nByte = nByte;
pBlob->mByte = 0;
pBlob->nFlags |= SXBLOB_RDONLY;
return SXRET_OK;
}
#ifndef SXBLOB_MIN_GROWTH
#define SXBLOB_MIN_GROWTH 16
#endif
static sxi32 BlobPrepareGrow(SyBlob *pBlob,sxu32 *pByte)
{
sxu32 nByte;
void *pNew;
nByte = *pByte;
if( pBlob->nFlags & (SXBLOB_LOCKED|SXBLOB_STATIC) ){
if ( SyBlobFreeSpace(pBlob) < nByte ){
*pByte = SyBlobFreeSpace(pBlob);
if( (*pByte) == 0 ){
return SXERR_SHORT;
}
}
return SXRET_OK;
}
if( pBlob->nFlags & SXBLOB_RDONLY ){
/* Make a copy of the read-only item */
if( pBlob->nByte > 0 ){
pNew = SyMemBackendDup(pBlob->pAllocator,pBlob->pBlob,pBlob->nByte);
if( pNew == 0 ){
return SXERR_MEM;
}
pBlob->pBlob = pNew;
pBlob->mByte = pBlob->nByte;
}else{
pBlob->pBlob = 0;
pBlob->mByte = 0;
}
/* Remove the read-only flag */
pBlob->nFlags &= ~SXBLOB_RDONLY;
}
if( SyBlobFreeSpace(pBlob) >= nByte ){
return SXRET_OK;
}
if( pBlob->mByte > 0 ){
nByte = nByte + pBlob->mByte * 2 + SXBLOB_MIN_GROWTH;
}else if ( nByte < SXBLOB_MIN_GROWTH ){
nByte = SXBLOB_MIN_GROWTH;
}
pNew = SyMemBackendRealloc(pBlob->pAllocator,pBlob->pBlob,nByte);
if( pNew == 0 ){
return SXERR_MEM;
}
pBlob->pBlob = pNew;
pBlob->mByte = nByte;
return SXRET_OK;
}
PH7_PRIVATE sxi32 SyBlobAppend(SyBlob *pBlob,const void *pData,sxu32 nSize)
{
sxu8 *zBlob;
sxi32 rc;
if( nSize < 1 ){
return SXRET_OK;
}
rc = BlobPrepareGrow(&(*pBlob),&nSize);
if( SXRET_OK != rc ){
return rc;
}
if( pData ){
zBlob = (sxu8 *)pBlob->pBlob ;
zBlob = &zBlob[pBlob->nByte];
pBlob->nByte += nSize;
SX_MACRO_FAST_MEMCPY(pData,zBlob,nSize);
}
return SXRET_OK;
}
PH7_PRIVATE sxi32 SyBlobNullAppend(SyBlob *pBlob)
{
sxi32 rc;
sxu32 n;
n = pBlob->nByte;
rc = SyBlobAppend(&(*pBlob),(const void *)"\0",sizeof(char));
if (rc == SXRET_OK ){
pBlob->nByte = n;
}
return rc;
}
PH7_PRIVATE sxi32 SyBlobDup(SyBlob *pSrc,SyBlob *pDest)
{
sxi32 rc = SXRET_OK;
#ifdef UNTRUST
if( pSrc == 0 || pDest == 0 ){
return SXERR_EMPTY;
}
#endif
if( pSrc->nByte > 0 ){
rc = SyBlobAppend(&(*pDest),pSrc->pBlob,pSrc->nByte);
}
return rc;
}
PH7_PRIVATE sxi32 SyBlobCmp(SyBlob *pLeft,SyBlob *pRight)
{
sxi32 rc;
#ifdef UNTRUST
if( pLeft == 0 || pRight == 0 ){
return pLeft ? 1 : -1;
}
#endif
if( pLeft->nByte != pRight->nByte ){
/* Length differ */
return pLeft->nByte - pRight->nByte;
}
if( pLeft->nByte == 0 ){
return 0;
}
/* Perform a standard memcmp() operation */
rc = SyMemcmp(pLeft->pBlob,pRight->pBlob,pLeft->nByte);
return rc;
}
PH7_PRIVATE sxi32 SyBlobReset(SyBlob *pBlob)
{
pBlob->nByte = 0;
if( pBlob->nFlags & SXBLOB_RDONLY ){
pBlob->pBlob = 0;
pBlob->mByte = 0;
pBlob->nFlags &= ~SXBLOB_RDONLY;
}
return SXRET_OK;
}
PH7_PRIVATE sxi32 SyBlobRelease(SyBlob *pBlob)
{
if( (pBlob->nFlags & (SXBLOB_STATIC|SXBLOB_RDONLY)) == 0 && pBlob->mByte > 0 ){
SyMemBackendFree(pBlob->pAllocator,pBlob->pBlob);
}
pBlob->pBlob = 0;
pBlob->nByte = pBlob->mByte = 0;
pBlob->nFlags = 0;
return SXRET_OK;
}
#ifndef PH7_DISABLE_BUILTIN_FUNC
PH7_PRIVATE sxi32 SyBlobSearch(const void *pBlob,sxu32 nLen,const void *pPattern,sxu32 pLen,sxu32 *pOfft)
{
const char *zIn = (const char *)pBlob;
const char *zEnd;
sxi32 rc;
if( pLen > nLen ){
return SXERR_NOTFOUND;
}
zEnd = &zIn[nLen-pLen];
for(;;){
if( zIn > zEnd ){break;} SX_MACRO_FAST_CMP(zIn,pPattern,pLen,rc); if( rc == 0 ){ if( pOfft ){ *pOfft = (sxu32)(zIn - (const char *)pBlob);} return SXRET_OK; } zIn++;
if( zIn > zEnd ){break;} SX_MACRO_FAST_CMP(zIn,pPattern,pLen,rc); if( rc == 0 ){ if( pOfft ){ *pOfft = (sxu32)(zIn - (const char *)pBlob);} return SXRET_OK; } zIn++;
if( zIn > zEnd ){break;} SX_MACRO_FAST_CMP(zIn,pPattern,pLen,rc); if( rc == 0 ){ if( pOfft ){ *pOfft = (sxu32)(zIn - (const char *)pBlob);} return SXRET_OK; } zIn++;
if( zIn > zEnd ){break;} SX_MACRO_FAST_CMP(zIn,pPattern,pLen,rc); if( rc == 0 ){ if( pOfft ){ *pOfft = (sxu32)(zIn - (const char *)pBlob);} return SXRET_OK; } zIn++;
}
return SXERR_NOTFOUND;
}
#endif /* PH7_DISABLE_BUILTIN_FUNC */
/* SyRunTimeApi:sxds.c */
PH7_PRIVATE sxi32 SySetInit(SySet *pSet,SyMemBackend *pAllocator,sxu32 ElemSize)
{
pSet->nSize = 0 ;
pSet->nUsed = 0;
pSet->nCursor = 0;
pSet->eSize = ElemSize;
pSet->pAllocator = pAllocator;
pSet->pBase = 0;
pSet->pUserData = 0;
return SXRET_OK;
}
PH7_PRIVATE sxi32 SySetPut(SySet *pSet,const void *pItem)
{
unsigned char *zbase;
if( pSet->nUsed >= pSet->nSize ){
void *pNew;
if( pSet->pAllocator == 0 ){
return SXERR_LOCKED;
}
if( pSet->nSize <= 0 ){
pSet->nSize = 4;
}
pNew = SyMemBackendRealloc(pSet->pAllocator,pSet->pBase,pSet->eSize * pSet->nSize * 2);
if( pNew == 0 ){
return SXERR_MEM;
}
pSet->pBase = pNew;
pSet->nSize <<= 1;
}
zbase = (unsigned char *)pSet->pBase;
SX_MACRO_FAST_MEMCPY(pItem,&zbase[pSet->nUsed * pSet->eSize],pSet->eSize);
pSet->nUsed++;
return SXRET_OK;
}
PH7_PRIVATE sxi32 SySetAlloc(SySet *pSet,sxi32 nItem)
{
if( pSet->nSize > 0 ){
return SXERR_LOCKED;
}
if( nItem < 8 ){
nItem = 8;
}
pSet->pBase = SyMemBackendAlloc(pSet->pAllocator,pSet->eSize * nItem);
if( pSet->pBase == 0 ){
return SXERR_MEM;
}
pSet->nSize = nItem;
return SXRET_OK;
}
PH7_PRIVATE sxi32 SySetReset(SySet *pSet)
{
pSet->nUsed = 0;
pSet->nCursor = 0;
return SXRET_OK;
}
PH7_PRIVATE sxi32 SySetResetCursor(SySet *pSet)
{
pSet->nCursor = 0;
return SXRET_OK;
}
PH7_PRIVATE sxi32 SySetGetNextEntry(SySet *pSet,void **ppEntry)
{
register unsigned char *zSrc;
if( pSet->nCursor >= pSet->nUsed ){
/* Reset cursor */
pSet->nCursor = 0;
return SXERR_EOF;
}
zSrc = (unsigned char *)SySetBasePtr(pSet);
if( ppEntry ){
*ppEntry = (void *)&zSrc[pSet->nCursor * pSet->eSize];
}
pSet->nCursor++;
return SXRET_OK;
}
#ifndef PH7_DISABLE_BUILTIN_FUNC
PH7_PRIVATE void * SySetPeekCurrentEntry(SySet *pSet)
{
register unsigned char *zSrc;
if( pSet->nCursor >= pSet->nUsed ){
return 0;
}
zSrc = (unsigned char *)SySetBasePtr(pSet);
return (void *)&zSrc[pSet->nCursor * pSet->eSize];
}
#endif /* PH7_DISABLE_BUILTIN_FUNC */
PH7_PRIVATE sxi32 SySetTruncate(SySet *pSet,sxu32 nNewSize)
{
if( nNewSize < pSet->nUsed ){
pSet->nUsed = nNewSize;
}
return SXRET_OK;
}
PH7_PRIVATE sxi32 SySetRelease(SySet *pSet)
{
sxi32 rc = SXRET_OK;
if( pSet->pAllocator && pSet->pBase ){
rc = SyMemBackendFree(pSet->pAllocator,pSet->pBase);
}
pSet->pBase = 0;
pSet->nUsed = 0;
pSet->nCursor = 0;
return rc;
}
PH7_PRIVATE void * SySetPeek(SySet *pSet)
{
const char *zBase;
if( pSet->nUsed <= 0 ){
return 0;
}
zBase = (const char *)pSet->pBase;
return (void *)&zBase[(pSet->nUsed - 1) * pSet->eSize];
}
PH7_PRIVATE void * SySetPop(SySet *pSet)
{
const char *zBase;
void *pData;
if( pSet->nUsed <= 0 ){
return 0;
}
zBase = (const char *)pSet->pBase;
pSet->nUsed--;
pData = (void *)&zBase[pSet->nUsed * pSet->eSize];
return pData;
}
PH7_PRIVATE void * SySetAt(SySet *pSet,sxu32 nIdx)
{
const char *zBase;
if( nIdx >= pSet->nUsed ){
/* Out of range */
return 0;
}
zBase = (const char *)pSet->pBase;
return (void *)&zBase[nIdx * pSet->eSize];
}
/* Private hash entry */
struct SyHashEntry_Pr
{
const void *pKey; /* Hash key */
sxu32 nKeyLen; /* Key length */
void *pUserData; /* User private data */
/* Private fields */
sxu32 nHash;
SyHash *pHash;
SyHashEntry_Pr *pNext,*pPrev; /* Next and previous entry in the list */
SyHashEntry_Pr *pNextCollide,*pPrevCollide; /* Collision list */
};
#define INVALID_HASH(H) ((H)->apBucket == 0)
/* Forward declarartion */
static sxu32 SyBinHash(const void *pSrc,sxu32 nLen);
PH7_PRIVATE sxi32 SyHashInit(SyHash *pHash,SyMemBackend *pAllocator,ProcHash xHash,ProcCmp xCmp)
{
SyHashEntry_Pr **apNew;
#if defined(UNTRUST)
if( pHash == 0 ){
return SXERR_EMPTY;
}
#endif
/* Allocate a new table */
apNew = (SyHashEntry_Pr **)SyMemBackendAlloc(&(*pAllocator),sizeof(SyHashEntry_Pr *) * SXHASH_BUCKET_SIZE);
if( apNew == 0 ){
return SXERR_MEM;
}
SyZero((void *)apNew,sizeof(SyHashEntry_Pr *) * SXHASH_BUCKET_SIZE);
pHash->pAllocator = &(*pAllocator);
pHash->xHash = xHash ? xHash : SyBinHash;
pHash->xCmp = xCmp ? xCmp : SyMemcmp;
pHash->pCurrent = pHash->pList = 0;
pHash->nEntry = 0;
pHash->apBucket = apNew;
pHash->nBucketSize = SXHASH_BUCKET_SIZE;
return SXRET_OK;
}
PH7_PRIVATE sxi32 SyHashRelease(SyHash *pHash)
{
SyHashEntry_Pr *pEntry,*pNext;
#if defined(UNTRUST)
if( INVALID_HASH(pHash) ){
return SXERR_EMPTY;
}
#endif
pEntry = pHash->pList;
for(;;){
if( pHash->nEntry == 0 ){
break;
}
pNext = pEntry->pNext;
SyMemBackendPoolFree(pHash->pAllocator,pEntry);
pEntry = pNext;
pHash->nEntry--;
}
if( pHash->apBucket ){
SyMemBackendFree(pHash->pAllocator,(void *)pHash->apBucket);
}
pHash->apBucket = 0;
pHash->nBucketSize = 0;
pHash->pAllocator = 0;
return SXRET_OK;
}
static SyHashEntry_Pr * HashGetEntry(SyHash *pHash,const void *pKey,sxu32 nKeyLen)
{
SyHashEntry_Pr *pEntry;
sxu32 nHash;
nHash = pHash->xHash(pKey,nKeyLen);
pEntry = pHash->apBucket[nHash & (pHash->nBucketSize - 1)];
for(;;){
if( pEntry == 0 ){
break;
}
if( pEntry->nHash == nHash && pEntry->nKeyLen == nKeyLen &&
pHash->xCmp(pEntry->pKey,pKey,nKeyLen) == 0 ){
return pEntry;
}
pEntry = pEntry->pNextCollide;
}
/* Entry not found */
return 0;
}
PH7_PRIVATE SyHashEntry * SyHashGet(SyHash *pHash,const void *pKey,sxu32 nKeyLen)
{
SyHashEntry_Pr *pEntry;
#if defined(UNTRUST)
if( INVALID_HASH(pHash) ){
return 0;
}
#endif
if( pHash->nEntry < 1 || nKeyLen < 1 ){
/* Don't bother hashing,return immediately */
return 0;
}
pEntry = HashGetEntry(&(*pHash),pKey,nKeyLen);
if( pEntry == 0 ){
return 0;
}
return (SyHashEntry *)pEntry;
}
static sxi32 HashDeleteEntry(SyHash *pHash,SyHashEntry_Pr *pEntry,void **ppUserData)
{
sxi32 rc;
if( pEntry->pPrevCollide == 0 ){
pHash->apBucket[pEntry->nHash & (pHash->nBucketSize - 1)] = pEntry->pNextCollide;
}else{
pEntry->pPrevCollide->pNextCollide = pEntry->pNextCollide;
}
if( pEntry->pNextCollide ){
pEntry->pNextCollide->pPrevCollide = pEntry->pPrevCollide;
}
MACRO_LD_REMOVE(pHash->pList,pEntry);
pHash->nEntry--;
if( ppUserData ){
/* Write a pointer to the user data */
*ppUserData = pEntry->pUserData;
}
/* Release the entry */
rc = SyMemBackendPoolFree(pHash->pAllocator,pEntry);
return rc;
}
PH7_PRIVATE sxi32 SyHashDeleteEntry(SyHash *pHash,const void *pKey,sxu32 nKeyLen,void **ppUserData)
{
SyHashEntry_Pr *pEntry;
sxi32 rc;
#if defined(UNTRUST)
if( INVALID_HASH(pHash) ){
return SXERR_CORRUPT;
}
#endif
pEntry = HashGetEntry(&(*pHash),pKey,nKeyLen);
if( pEntry == 0 ){
return SXERR_NOTFOUND;
}
rc = HashDeleteEntry(&(*pHash),pEntry,ppUserData);
return rc;
}
PH7_PRIVATE sxi32 SyHashDeleteEntry2(SyHashEntry *pEntry)
{
SyHashEntry_Pr *pPtr = (SyHashEntry_Pr *)pEntry;
sxi32 rc;
#if defined(UNTRUST)
if( pPtr == 0 || INVALID_HASH(pPtr->pHash) ){
return SXERR_CORRUPT;
}
#endif
rc = HashDeleteEntry(pPtr->pHash,pPtr,0);
return rc;
}
PH7_PRIVATE sxi32 SyHashResetLoopCursor(SyHash *pHash)
{
#if defined(UNTRUST)
if( INVALID_HASH(pHash) ){
return SXERR_CORRUPT;
}
#endif
pHash->pCurrent = pHash->pList;
return SXRET_OK;
}
PH7_PRIVATE SyHashEntry * SyHashGetNextEntry(SyHash *pHash)
{
SyHashEntry_Pr *pEntry;
#if defined(UNTRUST)
if( INVALID_HASH(pHash) ){
return 0;
}
#endif
if( pHash->pCurrent == 0 || pHash->nEntry <= 0 ){
pHash->pCurrent = pHash->pList;
return 0;
}
pEntry = pHash->pCurrent;
/* Advance the cursor */
pHash->pCurrent = pEntry->pNext;
/* Return the current entry */
return (SyHashEntry *)pEntry;
}
PH7_PRIVATE sxi32 SyHashForEach(SyHash *pHash,sxi32 (*xStep)(SyHashEntry *,void *),void *pUserData)
{
SyHashEntry_Pr *pEntry;
sxi32 rc;
sxu32 n;
#if defined(UNTRUST)
if( INVALID_HASH(pHash) || xStep == 0){
return 0;
}
#endif
pEntry = pHash->pList;
for( n = 0 ; n < pHash->nEntry ; n++ ){
/* Invoke the callback */
rc = xStep((SyHashEntry *)pEntry,pUserData);
if( rc != SXRET_OK ){
return rc;
}
/* Point to the next entry */
pEntry = pEntry->pNext;
}
return SXRET_OK;
}
static sxi32 HashGrowTable(SyHash *pHash)
{
sxu32 nNewSize = pHash->nBucketSize * 2;
SyHashEntry_Pr *pEntry;
SyHashEntry_Pr **apNew;
sxu32 n,iBucket;
/* Allocate a new larger table */
apNew = (SyHashEntry_Pr **)SyMemBackendAlloc(pHash->pAllocator,nNewSize * sizeof(SyHashEntry_Pr *));
if( apNew == 0 ){
/* Not so fatal,simply a performance hit */
return SXRET_OK;
}
/* Zero the new table */
SyZero((void *)apNew,nNewSize * sizeof(SyHashEntry_Pr *));
/* Rehash all entries */
for( n = 0,pEntry = pHash->pList; n < pHash->nEntry ; n++ ){
pEntry->pNextCollide = pEntry->pPrevCollide = 0;
/* Install in the new bucket */
iBucket = pEntry->nHash & (nNewSize - 1);
pEntry->pNextCollide = apNew[iBucket];
if( apNew[iBucket] != 0 ){
apNew[iBucket]->pPrevCollide = pEntry;
}
apNew[iBucket] = pEntry;
/* Point to the next entry */
pEntry = pEntry->pNext;
}
/* Release the old table and reflect the change */
SyMemBackendFree(pHash->pAllocator,(void *)pHash->apBucket);
pHash->apBucket = apNew;
pHash->nBucketSize = nNewSize;
return SXRET_OK;
}
static sxi32 HashInsert(SyHash *pHash,SyHashEntry_Pr *pEntry)
{
sxu32 iBucket = pEntry->nHash & (pHash->nBucketSize - 1);
/* Insert the entry in its corresponding bcuket */
pEntry->pNextCollide = pHash->apBucket[iBucket];
if( pHash->apBucket[iBucket] != 0 ){
pHash->apBucket[iBucket]->pPrevCollide = pEntry;
}
pHash->apBucket[iBucket] = pEntry;
/* Link to the entry list */
MACRO_LD_PUSH(pHash->pList,pEntry);
if( pHash->nEntry == 0 ){
pHash->pCurrent = pHash->pList;
}
pHash->nEntry++;
return SXRET_OK;
}
PH7_PRIVATE sxi32 SyHashInsert(SyHash *pHash,const void *pKey,sxu32 nKeyLen,void *pUserData)
{
SyHashEntry_Pr *pEntry;
sxi32 rc;
#if defined(UNTRUST)
if( INVALID_HASH(pHash) || pKey == 0 ){
return SXERR_CORRUPT;
}
#endif
if( pHash->nEntry >= pHash->nBucketSize * SXHASH_FILL_FACTOR ){
rc = HashGrowTable(&(*pHash));
if( rc != SXRET_OK ){
return rc;
}
}
/* Allocate a new hash entry */
pEntry = (SyHashEntry_Pr *)SyMemBackendPoolAlloc(pHash->pAllocator,sizeof(SyHashEntry_Pr));
if( pEntry == 0 ){
return SXERR_MEM;
}
/* Zero the entry */
SyZero(pEntry,sizeof(SyHashEntry_Pr));
pEntry->pHash = pHash;
pEntry->pKey = pKey;
pEntry->nKeyLen = nKeyLen;
pEntry->pUserData = pUserData;
pEntry->nHash = pHash->xHash(pEntry->pKey,pEntry->nKeyLen);
/* Finally insert the entry in its corresponding bucket */
rc = HashInsert(&(*pHash),pEntry);
return rc;
}
PH7_PRIVATE SyHashEntry * SyHashLastEntry(SyHash *pHash)
{
#if defined(UNTRUST)
if( INVALID_HASH(pHash) ){
return 0;
}
#endif
/* Last inserted entry */
return (SyHashEntry *)pHash->pList;
}
/* SyRunTimeApi:sxutils.c */
PH7_PRIVATE sxi32 SyStrIsNumeric(const char *zSrc,sxu32 nLen,sxu8 *pReal,const char **pzTail)
{
const char *zCur,*zEnd;
#ifdef UNTRUST
if( SX_EMPTY_STR(zSrc) ){
return SXERR_EMPTY;
}
#endif
zEnd = &zSrc[nLen];
/* Jump leading white spaces */
while( zSrc < zEnd && (unsigned char)zSrc[0] < 0xc0 && SyisSpace(zSrc[0]) ){
zSrc++;
}
if( zSrc < zEnd && (zSrc[0] == '+' || zSrc[0] == '-') ){
zSrc++;
}
zCur = zSrc;
if( pReal ){
*pReal = FALSE;
}
for(;;){
if( zSrc >= zEnd || (unsigned char)zSrc[0] >= 0xc0 || !SyisDigit(zSrc[0]) ){ break; } zSrc++;
if( zSrc >= zEnd || (unsigned char)zSrc[0] >= 0xc0 || !SyisDigit(zSrc[0]) ){ break; } zSrc++;
if( zSrc >= zEnd || (unsigned char)zSrc[0] >= 0xc0 || !SyisDigit(zSrc[0]) ){ break; } zSrc++;
if( zSrc >= zEnd || (unsigned char)zSrc[0] >= 0xc0 || !SyisDigit(zSrc[0]) ){ break; } zSrc++;
};
if( zSrc < zEnd && zSrc > zCur ){
int c = zSrc[0];
if( c == '.' ){
zSrc++;
if( pReal ){
*pReal = TRUE;
}
if( pzTail ){
while( zSrc < zEnd && (unsigned char)zSrc[0] < 0xc0 && SyisDigit(zSrc[0]) ){
zSrc++;
}
if( zSrc < zEnd && (zSrc[0] == 'e' || zSrc[0] == 'E') ){
zSrc++;
if( zSrc < zEnd && (zSrc[0] == '+' || zSrc[0] == '-') ){
zSrc++;
}
while( zSrc < zEnd && (unsigned char)zSrc[0] < 0xc0 && SyisDigit(zSrc[0]) ){
zSrc++;
}
}
}
}else if( c == 'e' || c == 'E' ){
zSrc++;
if( pReal ){
*pReal = TRUE;
}
if( pzTail ){
if( zSrc < zEnd && (zSrc[0] == '+' || zSrc[0] == '-') ){
zSrc++;
}
while( zSrc < zEnd && (unsigned char)zSrc[0] < 0xc0 && SyisDigit(zSrc[0]) ){
zSrc++;
}
}
}
}
if( pzTail ){
/* Point to the non numeric part */
*pzTail = zSrc;
}
return zSrc > zCur ? SXRET_OK /* String prefix is numeric */ : SXERR_INVALID /* Not a digit stream */;
}
#define SXINT32_MIN_STR "2147483648"
#define SXINT32_MAX_STR "2147483647"
#define SXINT64_MIN_STR "9223372036854775808"
#define SXINT64_MAX_STR "9223372036854775807"
PH7_PRIVATE sxi32 SyStrToInt32(const char *zSrc,sxu32 nLen,void * pOutVal,const char **zRest)
{
int isNeg = FALSE;
const char *zEnd;
sxi32 nVal = 0;
sxi16 i;
#if defined(UNTRUST)
if( SX_EMPTY_STR(zSrc) ){
if( pOutVal ){
*(sxi32 *)pOutVal = 0;
}
return SXERR_EMPTY;
}
#endif
zEnd = &zSrc[nLen];
while(zSrc < zEnd && SyisSpace(zSrc[0]) ){
zSrc++;
}
if( zSrc < zEnd && ( zSrc[0] == '-' || zSrc[0] == '+' ) ){
isNeg = (zSrc[0] == '-') ? TRUE :FALSE;
zSrc++;
}
/* Skip leading zero */
while(zSrc < zEnd && zSrc[0] == '0' ){
zSrc++;
}
i = 10;
if( (sxu32)(zEnd-zSrc) >= 10 ){
/* Handle overflow */
i = SyMemcmp(zSrc,(isNeg == TRUE) ? SXINT32_MIN_STR : SXINT32_MAX_STR,nLen) <= 0 ? 10 : 9;
}
for(;;){
if(zSrc >= zEnd || !i || !SyisDigit(zSrc[0])){ break; } nVal = nVal * 10 + ( zSrc[0] - '0' ) ; --i ; zSrc++;
if(zSrc >= zEnd || !i || !SyisDigit(zSrc[0])){ break; } nVal = nVal * 10 + ( zSrc[0] - '0' ) ; --i ; zSrc++;
if(zSrc >= zEnd || !i || !SyisDigit(zSrc[0])){ break; } nVal = nVal * 10 + ( zSrc[0] - '0' ) ; --i ; zSrc++;
if(zSrc >= zEnd || !i || !SyisDigit(zSrc[0])){ break; } nVal = nVal * 10 + ( zSrc[0] - '0' ) ; --i ; zSrc++;
}
/* Skip trailing spaces */
while(zSrc < zEnd && SyisSpace(zSrc[0])){
zSrc++;
}
if( zRest ){
*zRest = (char *)zSrc;
}
if( pOutVal ){
if( isNeg == TRUE && nVal != 0 ){
nVal = -nVal;
}
*(sxi32 *)pOutVal = nVal;
}
return (zSrc >= zEnd) ? SXRET_OK : SXERR_SYNTAX;
}
PH7_PRIVATE sxi32 SyStrToInt64(const char *zSrc,sxu32 nLen,void * pOutVal,const char **zRest)
{
int isNeg = FALSE;
const char *zEnd;
sxi64 nVal;
sxi16 i;
#if defined(UNTRUST)
if( SX_EMPTY_STR(zSrc) ){
if( pOutVal ){
*(sxi32 *)pOutVal = 0;
}
return SXERR_EMPTY;
}
#endif
zEnd = &zSrc[nLen];
while(zSrc < zEnd && SyisSpace(zSrc[0]) ){
zSrc++;
}
if( zSrc < zEnd && ( zSrc[0] == '-' || zSrc[0] == '+' ) ){
isNeg = (zSrc[0] == '-') ? TRUE :FALSE;
zSrc++;
}
/* Skip leading zero */
while(zSrc < zEnd && zSrc[0] == '0' ){
zSrc++;
}
i = 19;
if( (sxu32)(zEnd-zSrc) >= 19 ){
i = SyMemcmp(zSrc,isNeg ? SXINT64_MIN_STR : SXINT64_MAX_STR,19) <= 0 ? 19 : 18 ;
}
nVal = 0;
for(;;){
if(zSrc >= zEnd || !i || !SyisDigit(zSrc[0])){ break; } nVal = nVal * 10 + ( zSrc[0] - '0' ) ; --i ; zSrc++;
if(zSrc >= zEnd || !i || !SyisDigit(zSrc[0])){ break; } nVal = nVal * 10 + ( zSrc[0] - '0' ) ; --i ; zSrc++;
if(zSrc >= zEnd || !i || !SyisDigit(zSrc[0])){ break; } nVal = nVal * 10 + ( zSrc[0] - '0' ) ; --i ; zSrc++;
if(zSrc >= zEnd || !i || !SyisDigit(zSrc[0])){ break; } nVal = nVal * 10 + ( zSrc[0] - '0' ) ; --i ; zSrc++;
}
/* Skip trailing spaces */
while(zSrc < zEnd && SyisSpace(zSrc[0])){
zSrc++;
}
if( zRest ){
*zRest = (char *)zSrc;
}
if( pOutVal ){
if( isNeg == TRUE && nVal != 0 ){
nVal = -nVal;
}
*(sxi64 *)pOutVal = nVal;
}
return (zSrc >= zEnd) ? SXRET_OK : SXERR_SYNTAX;
}
PH7_PRIVATE sxi32 SyHexToint(sxi32 c)
{
switch(c){
case '0': return 0;
case '1': return 1;
case '2': return 2;
case '3': return 3;
case '4': return 4;
case '5': return 5;
case '6': return 6;
case '7': return 7;
case '8': return 8;
case '9': return 9;
case 'A': case 'a': return 10;
case 'B': case 'b': return 11;
case 'C': case 'c': return 12;
case 'D': case 'd': return 13;
case 'E': case 'e': return 14;
case 'F': case 'f': return 15;
}
return -1;
}
PH7_PRIVATE sxi32 SyHexStrToInt64(const char *zSrc,sxu32 nLen,void * pOutVal,const char **zRest)
{
const char *zIn,*zEnd;
int isNeg = FALSE;
sxi64 nVal = 0;
#if defined(UNTRUST)
if( SX_EMPTY_STR(zSrc) ){
if( pOutVal ){
*(sxi32 *)pOutVal = 0;
}
return SXERR_EMPTY;
}
#endif
zEnd = &zSrc[nLen];
while( zSrc < zEnd && SyisSpace(zSrc[0]) ){
zSrc++;
}
if( zSrc < zEnd && ( *zSrc == '-' || *zSrc == '+' ) ){
isNeg = (zSrc[0] == '-') ? TRUE :FALSE;
zSrc++;
}
if( zSrc < &zEnd[-2] && zSrc[0] == '0' && (zSrc[1] == 'x' || zSrc[1] == 'X') ){
/* Bypass hex prefix */
zSrc += sizeof(char) * 2;
}
/* Skip leading zero */
while(zSrc < zEnd && zSrc[0] == '0' ){
zSrc++;
}
zIn = zSrc;
for(;;){
if(zSrc >= zEnd || !SyisHex(zSrc[0]) || (int)(zSrc-zIn) > 15) break; nVal = nVal * 16 + SyHexToint(zSrc[0]); zSrc++ ;
if(zSrc >= zEnd || !SyisHex(zSrc[0]) || (int)(zSrc-zIn) > 15) break; nVal = nVal * 16 + SyHexToint(zSrc[0]); zSrc++ ;
if(zSrc >= zEnd || !SyisHex(zSrc[0]) || (int)(zSrc-zIn) > 15) break; nVal = nVal * 16 + SyHexToint(zSrc[0]); zSrc++ ;
if(zSrc >= zEnd || !SyisHex(zSrc[0]) || (int)(zSrc-zIn) > 15) break; nVal = nVal * 16 + SyHexToint(zSrc[0]); zSrc++ ;
}
while( zSrc < zEnd && SyisSpace(zSrc[0]) ){
zSrc++;
}
if( zRest ){
*zRest = zSrc;
}
if( pOutVal ){
if( isNeg == TRUE && nVal != 0 ){
nVal = -nVal;
}
*(sxi64 *)pOutVal = nVal;
}
return zSrc >= zEnd ? SXRET_OK : SXERR_SYNTAX;
}
PH7_PRIVATE sxi32 SyOctalStrToInt64(const char *zSrc,sxu32 nLen,void * pOutVal,const char **zRest)
{
const char *zIn,*zEnd;
int isNeg = FALSE;
sxi64 nVal = 0;
int c;
#if defined(UNTRUST)
if( SX_EMPTY_STR(zSrc) ){
if( pOutVal ){
*(sxi32 *)pOutVal = 0;
}
return SXERR_EMPTY;
}
#endif
zEnd = &zSrc[nLen];
while(zSrc < zEnd && SyisSpace(zSrc[0]) ){
zSrc++;
}
if( zSrc < zEnd && ( zSrc[0] == '-' || zSrc[0] == '+' ) ){
isNeg = (zSrc[0] == '-') ? TRUE :FALSE;
zSrc++;
}
/* Skip leading zero */
while(zSrc < zEnd && zSrc[0] == '0' ){
zSrc++;
}
zIn = zSrc;
for(;;){
if(zSrc >= zEnd || !SyisDigit(zSrc[0])){ break; } if( (c=zSrc[0]-'0') > 7 || (int)(zSrc-zIn) > 20){ break;} nVal = nVal * 8 + c; zSrc++;
if(zSrc >= zEnd || !SyisDigit(zSrc[0])){ break; } if( (c=zSrc[0]-'0') > 7 || (int)(zSrc-zIn) > 20){ break;} nVal = nVal * 8 + c; zSrc++;
if(zSrc >= zEnd || !SyisDigit(zSrc[0])){ break; } if( (c=zSrc[0]-'0') > 7 || (int)(zSrc-zIn) > 20){ break;} nVal = nVal * 8 + c; zSrc++;
if(zSrc >= zEnd || !SyisDigit(zSrc[0])){ break; } if( (c=zSrc[0]-'0') > 7 || (int)(zSrc-zIn) > 20){ break;} nVal = nVal * 8 + c; zSrc++;
}
/* Skip trailing spaces */
while(zSrc < zEnd && SyisSpace(zSrc[0])){
zSrc++;
}
if( zRest ){
*zRest = zSrc;
}
if( pOutVal ){
if( isNeg == TRUE && nVal != 0 ){
nVal = -nVal;
}
*(sxi64 *)pOutVal = nVal;
}
return (zSrc >= zEnd) ? SXRET_OK : SXERR_SYNTAX;
}
PH7_PRIVATE sxi32 SyBinaryStrToInt64(const char *zSrc,sxu32 nLen,void * pOutVal,const char **zRest)
{
const char *zIn,*zEnd;
int isNeg = FALSE;
sxi64 nVal = 0;
int c;
#if defined(UNTRUST)
if( SX_EMPTY_STR(zSrc) ){
if( pOutVal ){
*(sxi32 *)pOutVal = 0;
}
return SXERR_EMPTY;
}
#endif
zEnd = &zSrc[nLen];
while(zSrc < zEnd && SyisSpace(zSrc[0]) ){
zSrc++;
}
if( zSrc < zEnd && ( zSrc[0] == '-' || zSrc[0] == '+' ) ){
isNeg = (zSrc[0] == '-') ? TRUE :FALSE;
zSrc++;
}
if( zSrc < &zEnd[-2] && zSrc[0] == '0' && (zSrc[1] == 'b' || zSrc[1] == 'B') ){
/* Bypass binary prefix */
zSrc += sizeof(char) * 2;
}
/* Skip leading zero */
while(zSrc < zEnd && zSrc[0] == '0' ){
zSrc++;
}
zIn = zSrc;
for(;;){
if(zSrc >= zEnd || (zSrc[0] != '1' && zSrc[0] != '0') || (int)(zSrc-zIn) > 62){ break; } c = zSrc[0] - '0'; nVal = (nVal << 1) + c; zSrc++;
if(zSrc >= zEnd || (zSrc[0] != '1' && zSrc[0] != '0') || (int)(zSrc-zIn) > 62){ break; } c = zSrc[0] - '0'; nVal = (nVal << 1) + c; zSrc++;
if(zSrc >= zEnd || (zSrc[0] != '1' && zSrc[0] != '0') || (int)(zSrc-zIn) > 62){ break; } c = zSrc[0] - '0'; nVal = (nVal << 1) + c; zSrc++;
if(zSrc >= zEnd || (zSrc[0] != '1' && zSrc[0] != '0') || (int)(zSrc-zIn) > 62){ break; } c = zSrc[0] - '0'; nVal = (nVal << 1) + c; zSrc++;
}
/* Skip trailing spaces */
while(zSrc < zEnd && SyisSpace(zSrc[0])){
zSrc++;
}
if( zRest ){
*zRest = zSrc;
}
if( pOutVal ){
if( isNeg == TRUE && nVal != 0 ){
nVal = -nVal;
}
*(sxi64 *)pOutVal = nVal;
}
return (zSrc >= zEnd) ? SXRET_OK : SXERR_SYNTAX;
}
PH7_PRIVATE sxi32 SyStrToReal(const char *zSrc,sxu32 nLen,void * pOutVal,const char **zRest)
{
#define SXDBL_DIG 15
#define SXDBL_MAX_EXP 308
#define SXDBL_MIN_EXP_PLUS 307
static const sxreal aTab[] = {
10,
1.0e2,
1.0e4,
1.0e8,
1.0e16,
1.0e32,
1.0e64,
1.0e128,
1.0e256
};
sxu8 neg = FALSE;
sxreal Val = 0.0;
const char *zEnd;
sxi32 Lim,exp;
sxreal *p = 0;
#ifdef UNTRUST
if( SX_EMPTY_STR(zSrc) ){
if( pOutVal ){
*(sxreal *)pOutVal = 0.0;
}
return SXERR_EMPTY;
}
#endif
zEnd = &zSrc[nLen];
while( zSrc < zEnd && SyisSpace(zSrc[0]) ){
zSrc++;
}
if( zSrc < zEnd && (zSrc[0] == '-' || zSrc[0] == '+' ) ){
neg = zSrc[0] == '-' ? TRUE : FALSE ;
zSrc++;
}
Lim = SXDBL_DIG ;
for(;;){
if(zSrc >= zEnd||!Lim||!SyisDigit(zSrc[0])) break ; Val = Val * 10.0 + (zSrc[0] - '0') ; zSrc++ ; --Lim;
if(zSrc >= zEnd||!Lim||!SyisDigit(zSrc[0])) break ; Val = Val * 10.0 + (zSrc[0] - '0') ; zSrc++ ; --Lim;
if(zSrc >= zEnd||!Lim||!SyisDigit(zSrc[0])) break ; Val = Val * 10.0 + (zSrc[0] - '0') ; zSrc++ ; --Lim;
if(zSrc >= zEnd||!Lim||!SyisDigit(zSrc[0])) break ; Val = Val * 10.0 + (zSrc[0] - '0') ; zSrc++ ; --Lim;
}
if( zSrc < zEnd && ( zSrc[0] == '.' || zSrc[0] == ',' ) ){
sxreal dec = 1.0;
zSrc++;
for(;;){
if(zSrc >= zEnd||!Lim||!SyisDigit(zSrc[0])) break ; Val = Val * 10.0 + (zSrc[0] - '0') ; dec *= 10.0; zSrc++ ;--Lim;
if(zSrc >= zEnd||!Lim||!SyisDigit(zSrc[0])) break ; Val = Val * 10.0 + (zSrc[0] - '0') ; dec *= 10.0; zSrc++ ;--Lim;
if(zSrc >= zEnd||!Lim||!SyisDigit(zSrc[0])) break ; Val = Val * 10.0 + (zSrc[0] - '0') ; dec *= 10.0; zSrc++ ;--Lim;
if(zSrc >= zEnd||!Lim||!SyisDigit(zSrc[0])) break ; Val = Val * 10.0 + (zSrc[0] - '0') ; dec *= 10.0; zSrc++ ;--Lim;
}
Val /= dec;
}
if( neg == TRUE && Val != 0.0 ) {
Val = -Val ;
}
if( Lim <= 0 ){
/* jump overflow digit */
while( zSrc < zEnd ){
if( zSrc[0] == 'e' || zSrc[0] == 'E' ){
break;
}
zSrc++;
}
}
neg = FALSE;
if( zSrc < zEnd && ( zSrc[0] == 'e' || zSrc[0] == 'E' ) ){
zSrc++;
if( zSrc < zEnd && ( zSrc[0] == '-' || zSrc[0] == '+') ){
neg = zSrc[0] == '-' ? TRUE : FALSE ;
zSrc++;
}
exp = 0;
while( zSrc < zEnd && SyisDigit(zSrc[0]) && exp < SXDBL_MAX_EXP ){
exp = exp * 10 + (zSrc[0] - '0');
zSrc++;
}
if( neg ){
if( exp > SXDBL_MIN_EXP_PLUS ) exp = SXDBL_MIN_EXP_PLUS ;
}else if ( exp > SXDBL_MAX_EXP ){
exp = SXDBL_MAX_EXP;
}
for( p = (sxreal *)aTab ; exp ; exp >>= 1 , p++ ){
if( exp & 01 ){
if( neg ){
Val /= *p ;
}else{
Val *= *p;
}
}
}
}
while( zSrc < zEnd && SyisSpace(zSrc[0]) ){
zSrc++;
}
if( zRest ){
*zRest = zSrc;
}
if( pOutVal ){
*(sxreal *)pOutVal = Val;
}
return zSrc >= zEnd ? SXRET_OK : SXERR_SYNTAX;
}
/* SyRunTimeApi:sxlib.c */
static sxu32 SyBinHash(const void *pSrc,sxu32 nLen)
{
register unsigned char *zIn = (unsigned char *)pSrc;
unsigned char *zEnd;
sxu32 nH = 5381;
zEnd = &zIn[nLen];
for(;;){
if( zIn >= zEnd ){ break; } nH = nH * 33 + zIn[0] ; zIn++;
if( zIn >= zEnd ){ break; } nH = nH * 33 + zIn[0] ; zIn++;
if( zIn >= zEnd ){ break; } nH = nH * 33 + zIn[0] ; zIn++;
if( zIn >= zEnd ){ break; } nH = nH * 33 + zIn[0] ; zIn++;
}
return nH;
}
PH7_PRIVATE sxu32 SyStrHash(const void *pSrc,sxu32 nLen)
{
register unsigned char *zIn = (unsigned char *)pSrc;
unsigned char *zEnd;
sxu32 nH = 5381;
zEnd = &zIn[nLen];
for(;;){
if( zIn >= zEnd ){ break; } nH = nH * 33 + SyToLower(zIn[0]); zIn++;
if( zIn >= zEnd ){ break; } nH = nH * 33 + SyToLower(zIn[0]); zIn++;
if( zIn >= zEnd ){ break; } nH = nH * 33 + SyToLower(zIn[0]); zIn++;
if( zIn >= zEnd ){ break; } nH = nH * 33 + SyToLower(zIn[0]); zIn++;
}
return nH;
}
#ifndef PH7_DISABLE_BUILTIN_FUNC
PH7_PRIVATE sxi32 SyBase64Encode(const char *zSrc,sxu32 nLen,ProcConsumer xConsumer,void *pUserData)
{
static const unsigned char zBase64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
unsigned char *zIn = (unsigned char *)zSrc;
unsigned char z64[4];
sxu32 i;
sxi32 rc;
#if defined(UNTRUST)
if( SX_EMPTY_STR(zSrc) || xConsumer == 0){
return SXERR_EMPTY;
}
#endif
for(i = 0; i + 2 < nLen; i += 3){
z64[0] = zBase64[(zIn[i] >> 2) & 0x3F];
z64[1] = zBase64[( ((zIn[i] & 0x03) << 4) | (zIn[i+1] >> 4)) & 0x3F];
z64[2] = zBase64[( ((zIn[i+1] & 0x0F) << 2) | (zIn[i + 2] >> 6) ) & 0x3F];
z64[3] = zBase64[ zIn[i + 2] & 0x3F];
rc = xConsumer((const void *)z64,sizeof(z64),pUserData);
if( rc != SXRET_OK ){return SXERR_ABORT;}
}
if ( i+1 < nLen ){
z64[0] = zBase64[(zIn[i] >> 2) & 0x3F];
z64[1] = zBase64[( ((zIn[i] & 0x03) << 4) | (zIn[i+1] >> 4)) & 0x3F];
z64[2] = zBase64[(zIn[i+1] & 0x0F) << 2 ];
z64[3] = '=';
rc = xConsumer((const void *)z64,sizeof(z64),pUserData);
if( rc != SXRET_OK ){return SXERR_ABORT;}
}else if( i < nLen ){
z64[0] = zBase64[(zIn[i] >> 2) & 0x3F];
z64[1] = zBase64[(zIn[i] & 0x03) << 4];
z64[2] = '=';
z64[3] = '=';
rc = xConsumer((const void *)z64,sizeof(z64),pUserData);
if( rc != SXRET_OK ){return SXERR_ABORT;}
}
return SXRET_OK;
}
PH7_PRIVATE sxi32 SyBase64Decode(const char *zB64,sxu32 nLen,ProcConsumer xConsumer,void *pUserData)
{
static const sxu32 aBase64Trans[] = {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,62,0,0,0,63,52,53,54,55,56,57,58,59,60,61,0,0,0,0,0,0,0,0,1,2,3,4,
5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,0,0,0,0,0,0,26,27,
28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,0,0,
0,0,0
};
sxu32 n,w,x,y,z;
sxi32 rc;
unsigned char zOut[10];
#if defined(UNTRUST)
if( SX_EMPTY_STR(zB64) || xConsumer == 0 ){
return SXERR_EMPTY;
}
#endif
while(nLen > 0 && zB64[nLen - 1] == '=' ){
nLen--;
}
for( n = 0 ; n+3<nLen ; n += 4){
w = aBase64Trans[zB64[n] & 0x7F];
x = aBase64Trans[zB64[n+1] & 0x7F];
y = aBase64Trans[zB64[n+2] & 0x7F];
z = aBase64Trans[zB64[n+3] & 0x7F];
zOut[0] = ((w<<2) & 0xFC) | ((x>>4) & 0x03);
zOut[1] = ((x<<4) & 0xF0) | ((y>>2) & 0x0F);
zOut[2] = ((y<<6) & 0xC0) | (z & 0x3F);
rc = xConsumer((const void *)zOut,sizeof(unsigned char)*3,pUserData);
if( rc != SXRET_OK ){ return SXERR_ABORT;}
}
if( n+2 < nLen ){
w = aBase64Trans[zB64[n] & 0x7F];
x = aBase64Trans[zB64[n+1] & 0x7F];
y = aBase64Trans[zB64[n+2] & 0x7F];
zOut[0] = ((w<<2) & 0xFC) | ((x>>4) & 0x03);
zOut[1] = ((x<<4) & 0xF0) | ((y>>2) & 0x0F);
rc = xConsumer((const void *)zOut,sizeof(unsigned char)*2,pUserData);
if( rc != SXRET_OK ){ return SXERR_ABORT;}
}else if( n+1 < nLen ){
w = aBase64Trans[zB64[n] & 0x7F];
x = aBase64Trans[zB64[n+1] & 0x7F];
zOut[0] = ((w<<2) & 0xFC) | ((x>>4) & 0x03);
rc = xConsumer((const void *)zOut,sizeof(unsigned char)*1,pUserData);
if( rc != SXRET_OK ){ return SXERR_ABORT;}
}
return SXRET_OK;
}
#endif /* PH7_DISABLE_BUILTIN_FUNC */
#define INVALID_LEXER(LEX) ( LEX == 0 || LEX->xTokenizer == 0 )
PH7_PRIVATE sxi32 SyLexInit(SyLex *pLex,SySet *pSet,ProcTokenizer xTokenizer,void *pUserData)
{
SyStream *pStream;
#if defined (UNTRUST)
if ( pLex == 0 || xTokenizer == 0 ){
return SXERR_CORRUPT;
}
#endif
pLex->pTokenSet = 0;
/* Initialize lexer fields */
if( pSet ){
if ( SySetElemSize(pSet) != sizeof(SyToken) ){
return SXERR_INVALID;
}
pLex->pTokenSet = pSet;
}
pStream = &pLex->sStream;
pLex->xTokenizer = xTokenizer;
pLex->pUserData = pUserData;
pStream->nLine = 1;
pStream->nIgn = 0;
pStream->zText = pStream->zEnd = 0;
pStream->pSet = pSet;
return SXRET_OK;
}
PH7_PRIVATE sxi32 SyLexTokenizeInput(SyLex *pLex,const char *zInput,sxu32 nLen,void *pCtxData,ProcSort xSort,ProcCmp xCmp)
{
const unsigned char *zCur;
SyStream *pStream;
SyToken sToken;
sxi32 rc;
#if defined (UNTRUST)
if ( INVALID_LEXER(pLex) || zInput == 0 ){
return SXERR_CORRUPT;
}
#endif
pStream = &pLex->sStream;
/* Point to the head of the input */
pStream->zText = pStream->zInput = (const unsigned char *)zInput;
/* Point to the end of the input */
pStream->zEnd = &pStream->zInput[nLen];
for(;;){
if( pStream->zText >= pStream->zEnd ){
/* End of the input reached */
break;
}
zCur = pStream->zText;
/* Call the tokenizer callback */
rc = pLex->xTokenizer(pStream,&sToken,pLex->pUserData,pCtxData);
if( rc != SXRET_OK && rc != SXERR_CONTINUE ){
/* Tokenizer callback request an operation abort */
if( rc == SXERR_ABORT )