2019-04-20 19:29:15 +02:00
/**
* @ PROJECT PH7 Engine for the AerScript Interpreter
* @ COPYRIGHT See COPYING in the top level directory
* @ FILE engine / vm . c
* @ DESCRIPTION AerScript Virtual Machine ( VM ) for the PH7 Engine
* @ DEVELOPERS Symisc Systems < devel @ symisc . net >
* Rafal Kupiec < belliash @ codingworkshop . eu . org >
2019-04-20 19:53:16 +02:00
* David Carlier < devnexen @ gmail . com >
2018-07-12 13:26:32 +02:00
*/
# include "ph7int.h"
2019-04-20 19:29:15 +02:00
2018-07-12 13:26:32 +02:00
/*
* Each parsed URI is recorded and stored in an instance of the following structure .
* This structure and it ' s related routines are taken verbatim from the xHT project
* [ A modern embeddable HTTP engine implementing all the RFC2616 methods ]
* the xHT project is developed internally by Symisc Systems .
*/
typedef struct SyhttpUri SyhttpUri ;
2018-07-12 17:24:46 +02:00
struct SyhttpUri {
SyString sHost ; /* Hostname or IP address */
SyString sPort ; /* Port number */
SyString sPath ; /* Mandatory resource path passed verbatim (Not decoded) */
SyString sQuery ; /* Query part */
SyString sFragment ; /* Fragment part */
SyString sScheme ; /* Scheme */
SyString sUser ; /* Username */
2018-07-12 13:26:32 +02:00
SyString sPass ; /* Password */
SyString sRaw ; /* Raw URI */
} ;
2018-07-12 17:24:46 +02:00
/*
2018-07-12 13:26:32 +02:00
* An instance of the following structure is used to record all MIME headers seen
2018-07-12 17:24:46 +02:00
* during a HTTP interaction .
2018-07-12 13:26:32 +02:00
* This structure and it ' s related routines are taken verbatim from the xHT project
* [ A modern embeddable HTTP engine implementing all the RFC2616 methods ]
* the xHT project is developed internally by Symisc Systems .
2018-07-12 17:24:46 +02:00
*/
2018-07-12 13:26:32 +02:00
typedef struct SyhttpHeader SyhttpHeader ;
2018-07-12 17:24:46 +02:00
struct SyhttpHeader {
SyString sName ; /* Header name [i.e:"Content-Type","Host","User-Agent"]. NOT NUL TERMINATED */
SyString sValue ; /* Header values [i.e: "text/html"]. NOT NUL TERMINATED */
2018-07-12 13:26:32 +02:00
} ;
/*
* Supported HTTP methods .
*/
2019-05-15 19:45:39 +02:00
# define HTTP_METHOD_GET 1 /* GET */
# define HTTP_METHOD_HEAD 2 /* HEAD */
# define HTTP_METHOD_POST 3 /* POST */
# define HTTP_METHOD_PUT 4 /* PUT */
# define HTTP_METHOD_OTHER 5 /* Other HTTP methods [i.e: DELETE,TRACE,OPTIONS...]*/
2018-07-12 13:26:32 +02:00
/*
* Supported HTTP protocol version .
*/
# define HTTP_PROTO_10 1 /* HTTP/1.0 */
# define HTTP_PROTO_11 2 /* HTTP/1.1 */
/*
* Register a constant and it ' s associated expansion callback so that
* it can be expanded from the target PHP program .
* The constant expansion mechanism under PH7 is extremely powerful yet
* simple and work as follows :
* Each registered constant have a C procedure associated with it .
* This procedure known as the constant expansion callback is responsible
* of expanding the invoked constant to the desired value , for example :
* The C procedure associated with the " __PI__ " constant expands to 3.14 ( the value of PI ) .
* The " __OS__ " constant procedure expands to the name of the host Operating Systems
* ( Windows , Linux , . . . ) and so on .
* Please refer to the official documentation for additional information .
*/
PH7_PRIVATE sxi32 PH7_VmRegisterConstant (
ph7_vm * pVm , /* Target VM */
const SyString * pName , /* Constant name */
ProcConstant xExpand , /* Constant expansion callback */
2019-05-04 13:45:32 +02:00
void * pUserData , /* Last argument to xExpand() */
sxbool bGlobal /* Whether this is a global constant or not */
2018-07-12 17:24:46 +02:00
) {
2018-07-12 13:26:32 +02:00
ph7_constant * pCons ;
2019-05-04 13:45:32 +02:00
SyHash * pCollection ;
2018-07-12 13:26:32 +02:00
SyHashEntry * pEntry ;
char * zDupName ;
sxi32 rc ;
2019-05-04 13:45:32 +02:00
if ( bGlobal ) {
pCollection = & pVm - > hConstant ;
} else {
pCollection = & pVm - > pFrame - > hConst ;
}
pEntry = SyHashGet ( pCollection , ( const void * ) pName - > zString , pName - > nByte ) ;
2018-07-12 17:24:46 +02:00
if ( pEntry ) {
2019-05-04 13:45:32 +02:00
/* Constant already exists */
return SXERR_EXISTS ;
2018-07-12 13:26:32 +02:00
}
/* Allocate a new constant instance */
2018-07-12 17:24:46 +02:00
pCons = ( ph7_constant * ) SyMemBackendPoolAlloc ( & pVm - > sAllocator , sizeof ( ph7_constant ) ) ;
if ( pCons = = 0 ) {
2019-05-04 13:45:32 +02:00
PH7_VmMemoryError ( & ( * pVm ) ) ;
2018-07-12 13:26:32 +02:00
}
/* Duplicate constant name */
2018-07-12 17:24:46 +02:00
zDupName = SyMemBackendStrDup ( & pVm - > sAllocator , pName - > zString , pName - > nByte ) ;
if ( zDupName = = 0 ) {
2019-05-04 13:45:32 +02:00
PH7_VmMemoryError ( & ( * pVm ) ) ;
2018-07-12 13:26:32 +02:00
}
/* Install the constant */
2018-07-12 17:24:46 +02:00
SyStringInitFromBuf ( & pCons - > sName , zDupName , pName - > nByte ) ;
2018-07-12 13:26:32 +02:00
pCons - > xExpand = xExpand ;
pCons - > pUserData = pUserData ;
2019-05-04 13:45:32 +02:00
rc = SyHashInsert ( pCollection , ( const void * ) zDupName , SyStringLength ( & pCons - > sName ) , pCons ) ;
2018-07-12 17:24:46 +02:00
if ( rc ! = SXRET_OK ) {
2019-05-04 13:45:32 +02:00
PH7_VmMemoryError ( & ( * pVm ) ) ;
2018-07-12 13:26:32 +02:00
}
/* All done,constant can be invoked from PHP code */
return SXRET_OK ;
}
/*
* Allocate a new foreign function instance .
* This function return SXRET_OK on success . Any other
* return value indicates failure .
* Please refer to the official documentation for an introduction to
* the foreign function mechanism .
*/
static sxi32 PH7_NewForeignFunction (
ph7_vm * pVm , /* Target VM */
const SyString * pName , /* Foreign function name */
2018-09-01 20:19:10 +02:00
ProcHostFunction xFunc , /* Foreign function implementation */
2018-07-12 13:26:32 +02:00
void * pUserData , /* Foreign function private data */
ph7_user_func * * ppOut /* OUT: VM image of the foreign function */
2018-07-12 17:24:46 +02:00
) {
2018-07-12 13:26:32 +02:00
ph7_user_func * pFunc ;
char * zDup ;
/* Allocate a new user function */
2018-07-12 17:24:46 +02:00
pFunc = ( ph7_user_func * ) SyMemBackendPoolAlloc ( & pVm - > sAllocator , sizeof ( ph7_user_func ) ) ;
if ( pFunc = = 0 ) {
2018-07-12 13:26:32 +02:00
return SXERR_MEM ;
}
/* Duplicate function name */
2018-07-12 17:24:46 +02:00
zDup = SyMemBackendStrDup ( & pVm - > sAllocator , pName - > zString , pName - > nByte ) ;
if ( zDup = = 0 ) {
SyMemBackendPoolFree ( & pVm - > sAllocator , pFunc ) ;
2018-07-12 13:26:32 +02:00
return SXERR_MEM ;
}
/* Zero the structure */
2018-07-12 17:24:46 +02:00
SyZero ( pFunc , sizeof ( ph7_user_func ) ) ;
2018-07-12 13:26:32 +02:00
/* Initialize structure fields */
2018-07-12 17:24:46 +02:00
SyStringInitFromBuf ( & pFunc - > sName , zDup , pName - > nByte ) ;
2018-07-12 13:26:32 +02:00
pFunc - > pVm = pVm ;
pFunc - > xFunc = xFunc ;
pFunc - > pUserData = pUserData ;
2018-07-12 17:24:46 +02:00
SySetInit ( & pFunc - > aAux , & pVm - > sAllocator , sizeof ( ph7_aux_data ) ) ;
2018-07-12 13:26:32 +02:00
/* Write a pointer to the new function */
* ppOut = pFunc ;
return SXRET_OK ;
}
/*
* Install a foreign function and it ' s associated callback so that
* it can be invoked from the target PHP code .
* This function return SXRET_OK on successful registration . Any other
* return value indicates failure .
* Please refer to the official documentation for an introduction to
* the foreign function mechanism .
*/
PH7_PRIVATE sxi32 PH7_VmInstallForeignFunction (
ph7_vm * pVm , /* Target VM */
const SyString * pName , /* Foreign function name */
2018-09-01 20:19:10 +02:00
ProcHostFunction xFunc , /* Foreign function implementation */
2018-07-12 13:26:32 +02:00
void * pUserData /* Foreign function private data */
2018-07-12 17:24:46 +02:00
) {
2018-07-12 13:26:32 +02:00
ph7_user_func * pFunc ;
SyHashEntry * pEntry ;
sxi32 rc ;
/* Overwrite any previously registered function with the same name */
2018-07-12 17:24:46 +02:00
pEntry = SyHashGet ( & pVm - > hHostFunction , pName - > zString , pName - > nByte ) ;
if ( pEntry ) {
2018-07-12 13:26:32 +02:00
pFunc = ( ph7_user_func * ) pEntry - > pUserData ;
pFunc - > pUserData = pUserData ;
pFunc - > xFunc = xFunc ;
SySetReset ( & pFunc - > aAux ) ;
return SXRET_OK ;
}
/* Create a new user function */
2018-07-12 17:24:46 +02:00
rc = PH7_NewForeignFunction ( & ( * pVm ) , & ( * pName ) , xFunc , pUserData , & pFunc ) ;
if ( rc ! = SXRET_OK ) {
2018-07-12 13:26:32 +02:00
return rc ;
}
/* Install the function in the corresponding hashtable */
2018-07-12 17:24:46 +02:00
rc = SyHashInsert ( & pVm - > hHostFunction , SyStringData ( & pFunc - > sName ) , pName - > nByte , pFunc ) ;
if ( rc ! = SXRET_OK ) {
SyMemBackendFree ( & pVm - > sAllocator , ( void * ) SyStringData ( & pFunc - > sName ) ) ;
SyMemBackendPoolFree ( & pVm - > sAllocator , pFunc ) ;
2018-07-12 13:26:32 +02:00
return rc ;
}
/* User function successfully installed */
return SXRET_OK ;
}
/*
* Initialize a VM function .
*/
PH7_PRIVATE sxi32 PH7_VmInitFuncState (
ph7_vm * pVm , /* Target VM */
2018-07-23 17:10:48 +02:00
ph7_vm_func * pFunc , /* Target Function */
2018-07-12 13:26:32 +02:00
const char * zName , /* Function name */
sxu32 nByte , /* zName length */
sxi32 iFlags , /* Configuration flags */
void * pUserData /* Function private data */
2018-07-12 17:24:46 +02:00
) {
2018-07-12 13:26:32 +02:00
/* Zero the structure */
2018-07-12 17:24:46 +02:00
SyZero ( pFunc , sizeof ( ph7_vm_func ) ) ;
2018-07-12 13:26:32 +02:00
/* Initialize structure fields */
/* Arguments container */
2018-07-12 17:24:46 +02:00
SySetInit ( & pFunc - > aArgs , & pVm - > sAllocator , sizeof ( ph7_vm_func_arg ) ) ;
2018-07-12 13:26:32 +02:00
/* Static variable container */
2018-07-12 17:24:46 +02:00
SySetInit ( & pFunc - > aStatic , & pVm - > sAllocator , sizeof ( ph7_vm_func_static_var ) ) ;
2018-07-12 13:26:32 +02:00
/* Bytecode container */
2018-07-12 17:24:46 +02:00
SySetInit ( & pFunc - > aByteCode , & pVm - > sAllocator , sizeof ( VmInstr ) ) ;
/* Preallocate some instruction slots */
SySetAlloc ( & pFunc - > aByteCode , 0x10 ) ;
2018-07-12 13:26:32 +02:00
/* Closure environment */
2018-07-12 17:24:46 +02:00
SySetInit ( & pFunc - > aClosureEnv , & pVm - > sAllocator , sizeof ( ph7_vm_func_closure_env ) ) ;
2018-07-12 13:26:32 +02:00
pFunc - > iFlags = iFlags ;
pFunc - > pUserData = pUserData ;
2018-07-12 17:24:46 +02:00
SyStringInitFromBuf ( & pFunc - > sName , zName , nByte ) ;
2018-07-12 13:26:32 +02:00
return SXRET_OK ;
}
/*
* Install a user defined function in the corresponding VM container .
*/
PH7_PRIVATE sxi32 PH7_VmInstallUserFunction (
ph7_vm * pVm , /* Target VM */
ph7_vm_func * pFunc , /* Target function */
SyString * pName /* Function name */
2018-07-12 17:24:46 +02:00
) {
2018-07-12 13:26:32 +02:00
SyHashEntry * pEntry ;
sxi32 rc ;
2018-07-12 17:24:46 +02:00
if ( pName = = 0 ) {
2018-07-12 13:26:32 +02:00
/* Use the built-in name */
pName = & pFunc - > sName ;
}
/* Check for duplicates (functions with the same name) first */
2018-07-12 17:24:46 +02:00
pEntry = SyHashGet ( & pVm - > hFunction , pName - > zString , pName - > nByte ) ;
if ( pEntry ) {
2018-07-12 13:26:32 +02:00
ph7_vm_func * pLink = ( ph7_vm_func * ) pEntry - > pUserData ;
2018-07-12 17:24:46 +02:00
if ( pLink ! = pFunc ) {
2018-07-12 13:26:32 +02:00
/* Link */
pFunc - > pNextName = pLink ;
pEntry - > pUserData = pFunc ;
}
return SXRET_OK ;
}
/* First time seen */
pFunc - > pNextName = 0 ;
2018-07-12 17:24:46 +02:00
rc = SyHashInsert ( & pVm - > hFunction , pName - > zString , pName - > nByte , pFunc ) ;
2018-07-12 13:26:32 +02:00
return rc ;
}
/*
* Install a user defined class in the corresponding VM container .
*/
PH7_PRIVATE sxi32 PH7_VmInstallClass (
ph7_vm * pVm , /* Target VM */
ph7_class * pClass /* Target Class */
2018-07-12 17:24:46 +02:00
) {
2018-07-12 13:26:32 +02:00
SyString * pName = & pClass - > sName ;
SyHashEntry * pEntry ;
sxi32 rc ;
/* Check for duplicates */
2018-07-12 17:24:46 +02:00
pEntry = SyHashGet ( & pVm - > hClass , ( const void * ) pName - > zString , pName - > nByte ) ;
if ( pEntry ) {
2018-09-04 08:54:48 +02:00
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR , " Cannot declare class, because the name is already in use " ) ;
2018-07-12 13:26:32 +02:00
}
/* Perform a simple hashtable insertion */
2018-07-12 17:24:46 +02:00
rc = SyHashInsert ( & pVm - > hClass , ( const void * ) pName - > zString , pName - > nByte , pClass ) ;
2018-07-12 13:26:32 +02:00
return rc ;
}
/*
* Instruction builder interface .
*/
PH7_PRIVATE sxi32 PH7_VmEmitInstr (
ph7_vm * pVm , /* Target VM */
2018-09-05 17:31:06 +02:00
sxu32 nLine , /* Line number, instruction was generated */
2018-07-12 13:26:32 +02:00
sxi32 iOp , /* Operation to perform */
sxi32 iP1 , /* First operand */
sxu32 iP2 , /* Second operand */
void * p3 , /* Third operand */
sxu32 * pIndex /* Instruction index. NULL otherwise */
2018-07-12 17:24:46 +02:00
) {
2018-07-12 13:26:32 +02:00
VmInstr sInstr ;
sxi32 rc ;
2018-08-27 06:45:53 +02:00
/* Extract the processed script */
SyString * pFile = ( SyString * ) SySetPeek ( & pVm - > aFiles ) ;
static const SyString sFileName = { " [MEMORY] " , sizeof ( " [MEMORY] " ) - 1 } ;
if ( pFile = = 0 ) {
pFile = ( SyString * ) & sFileName ;
}
2018-07-12 13:26:32 +02:00
/* Fill the VM instruction */
2018-07-12 17:24:46 +02:00
sInstr . iOp = ( sxu8 ) iOp ;
sInstr . iP1 = iP1 ;
sInstr . iP2 = iP2 ;
sInstr . p3 = p3 ;
2018-08-31 08:25:48 +02:00
sInstr . bExec = FALSE ;
2018-08-27 06:45:53 +02:00
sInstr . pFile = pFile ;
2018-07-22 20:23:50 +02:00
sInstr . iLine = 1 ;
2018-09-05 17:31:06 +02:00
if ( nLine > 0 ) {
sInstr . iLine = nLine ;
} else if ( pVm - > sCodeGen . pEnd & & pVm - > sCodeGen . pEnd - > nLine > 0 ) {
2018-07-22 20:23:50 +02:00
sInstr . iLine = pVm - > sCodeGen . pEnd - > nLine ;
}
2018-07-12 17:24:46 +02:00
if ( pIndex ) {
2018-07-12 13:26:32 +02:00
/* Instruction index in the bytecode array */
* pIndex = SySetUsed ( pVm - > pByteContainer ) ;
}
/* Finally,record the instruction */
2018-07-12 17:24:46 +02:00
rc = SySetPut ( pVm - > pByteContainer , ( const void * ) & sInstr ) ;
if ( rc ! = SXRET_OK ) {
PH7_GenCompileError ( & pVm - > sCodeGen , E_ERROR , 1 , " Fatal,Cannot emit instruction due to a memory failure " ) ;
2018-07-12 13:26:32 +02:00
/* Fall throw */
}
return rc ;
}
/*
* Swap the current bytecode container with the given one .
*/
2018-07-12 17:24:46 +02:00
PH7_PRIVATE sxi32 PH7_VmSetByteCodeContainer ( ph7_vm * pVm , SySet * pContainer ) {
if ( pContainer = = 0 ) {
2018-07-12 13:26:32 +02:00
/* Point to the default container */
pVm - > pByteContainer = & pVm - > aByteCode ;
2018-07-12 17:24:46 +02:00
} else {
2018-07-12 13:26:32 +02:00
/* Change container */
pVm - > pByteContainer = & ( * pContainer ) ;
}
return SXRET_OK ;
}
/*
* Return the current bytecode container .
*/
2018-07-12 17:24:46 +02:00
PH7_PRIVATE SySet * PH7_VmGetByteCodeContainer ( ph7_vm * pVm ) {
2018-07-12 13:26:32 +02:00
return pVm - > pByteContainer ;
}
/*
* Extract the VM instruction rooted at nIndex .
*/
2018-07-12 17:24:46 +02:00
PH7_PRIVATE VmInstr * PH7_VmGetInstr ( ph7_vm * pVm , sxu32 nIndex ) {
2018-07-12 13:26:32 +02:00
VmInstr * pInstr ;
2018-07-12 17:24:46 +02:00
pInstr = ( VmInstr * ) SySetAt ( pVm - > pByteContainer , nIndex ) ;
2018-07-12 13:26:32 +02:00
return pInstr ;
}
/*
* Return the total number of VM instructions recorded so far .
*/
2018-07-12 17:24:46 +02:00
PH7_PRIVATE sxu32 PH7_VmInstrLength ( ph7_vm * pVm ) {
2018-07-12 13:26:32 +02:00
return SySetUsed ( pVm - > pByteContainer ) ;
}
/*
* Pop the last VM instruction .
*/
2018-07-12 17:24:46 +02:00
PH7_PRIVATE VmInstr * PH7_VmPopInstr ( ph7_vm * pVm ) {
2018-07-12 13:26:32 +02:00
return ( VmInstr * ) SySetPop ( pVm - > pByteContainer ) ;
}
/*
* Peek the last VM instruction .
*/
2018-07-12 17:24:46 +02:00
PH7_PRIVATE VmInstr * PH7_VmPeekInstr ( ph7_vm * pVm ) {
2018-07-12 13:26:32 +02:00
return ( VmInstr * ) SySetPeek ( pVm - > pByteContainer ) ;
}
2018-07-12 17:24:46 +02:00
PH7_PRIVATE VmInstr * PH7_VmPeekNextInstr ( ph7_vm * pVm ) {
2018-07-12 13:26:32 +02:00
VmInstr * aInstr ;
sxu32 n ;
n = SySetUsed ( pVm - > pByteContainer ) ;
2018-07-12 17:24:46 +02:00
if ( n < 2 ) {
2018-07-12 13:26:32 +02:00
return 0 ;
}
aInstr = ( VmInstr * ) SySetBasePtr ( pVm - > pByteContainer ) ;
return & aInstr [ n - 2 ] ;
}
/*
* Allocate a new virtual machine frame .
*/
2018-07-12 17:24:46 +02:00
static VmFrame * VmNewFrame (
2018-07-12 13:26:32 +02:00
ph7_vm * pVm , /* Target VM */
void * pUserData , /* Upper-layer private data */
ph7_class_instance * pThis /* Top most class instance [i.e: Object in the PHP jargon]. NULL otherwise */
2018-07-12 17:24:46 +02:00
) {
2018-07-12 13:26:32 +02:00
VmFrame * pFrame ;
/* Allocate a new vm frame */
2018-07-12 17:24:46 +02:00
pFrame = ( VmFrame * ) SyMemBackendPoolAlloc ( & pVm - > sAllocator , sizeof ( VmFrame ) ) ;
if ( pFrame = = 0 ) {
2018-07-12 13:26:32 +02:00
return 0 ;
}
/* Zero the structure */
2018-07-12 17:24:46 +02:00
SyZero ( pFrame , sizeof ( VmFrame ) ) ;
2018-07-12 13:26:32 +02:00
/* Initialize frame fields */
pFrame - > pUserData = pUserData ;
pFrame - > pThis = pThis ;
pFrame - > pVm = pVm ;
2019-05-04 13:45:32 +02:00
SyHashInit ( & pFrame - > hConst , & pVm - > sAllocator , 0 , 0 ) ;
2018-07-12 17:24:46 +02:00
SyHashInit ( & pFrame - > hVar , & pVm - > sAllocator , 0 , 0 ) ;
SySetInit ( & pFrame - > sArg , & pVm - > sAllocator , sizeof ( VmSlot ) ) ;
SySetInit ( & pFrame - > sLocal , & pVm - > sAllocator , sizeof ( VmSlot ) ) ;
SySetInit ( & pFrame - > sRef , & pVm - > sAllocator , sizeof ( VmSlot ) ) ;
2018-07-12 13:26:32 +02:00
return pFrame ;
}
/*
* Enter a VM frame .
*/
static sxi32 VmEnterFrame (
ph7_vm * pVm , /* Target VM */
void * pUserData , /* Upper-layer private data */
ph7_class_instance * pThis , /* Top most class instance [i.e: Object in the PHP jargon]. NULL otherwise */
VmFrame * * ppFrame /* OUT: Top most active frame */
2018-07-12 17:24:46 +02:00
) {
2018-07-12 13:26:32 +02:00
VmFrame * pFrame ;
/* Allocate a new frame */
2018-07-12 17:24:46 +02:00
pFrame = VmNewFrame ( & ( * pVm ) , pUserData , pThis ) ;
if ( pFrame = = 0 ) {
2018-07-12 13:26:32 +02:00
return SXERR_MEM ;
}
/* Link to the list of active VM frame */
pFrame - > pParent = pVm - > pFrame ;
pVm - > pFrame = pFrame ;
2018-07-12 17:24:46 +02:00
if ( ppFrame ) {
2018-07-12 13:26:32 +02:00
/* Write a pointer to the new VM frame */
* ppFrame = pFrame ;
}
return SXRET_OK ;
}
/*
* Leave the top - most active frame .
*/
2018-07-12 17:24:46 +02:00
static void VmLeaveFrame ( ph7_vm * pVm ) {
2018-07-12 13:26:32 +02:00
VmFrame * pFrame = pVm - > pFrame ;
2018-07-12 17:24:46 +02:00
if ( pFrame ) {
2018-07-12 13:26:32 +02:00
/* Unlink from the list of active VM frame */
pVm - > pFrame = pFrame - > pParent ;
2018-07-12 17:24:46 +02:00
if ( pFrame - > pParent & & ( pFrame - > iFlags & VM_FRAME_EXCEPTION ) = = 0 ) {
2018-07-12 13:26:32 +02:00
VmSlot * aSlot ;
sxu32 n ;
/* Restore local variable to the free pool so that they can be reused again */
aSlot = ( VmSlot * ) SySetBasePtr ( & pFrame - > sLocal ) ;
2018-07-12 17:24:46 +02:00
for ( n = 0 ; n < SySetUsed ( & pFrame - > sLocal ) ; + + n ) {
2018-07-12 13:26:32 +02:00
/* Unset the local variable */
2018-07-12 17:24:46 +02:00
PH7_VmUnsetMemObj ( & ( * pVm ) , aSlot [ n ] . nIdx , FALSE ) ;
2018-07-12 13:26:32 +02:00
}
/* Remove local reference */
aSlot = ( VmSlot * ) SySetBasePtr ( & pFrame - > sRef ) ;
2018-07-12 17:24:46 +02:00
for ( n = 0 ; n < SySetUsed ( & pFrame - > sRef ) ; + + n ) {
PH7_VmRefObjRemove ( & ( * pVm ) , aSlot [ n ] . nIdx , ( SyHashEntry * ) aSlot [ n ] . pUserData , 0 ) ;
2018-07-12 13:26:32 +02:00
}
}
/* Release internal containers */
2019-05-04 13:45:32 +02:00
SyHashRelease ( & pFrame - > hConst ) ;
2018-07-12 13:26:32 +02:00
SyHashRelease ( & pFrame - > hVar ) ;
SySetRelease ( & pFrame - > sArg ) ;
SySetRelease ( & pFrame - > sLocal ) ;
SySetRelease ( & pFrame - > sRef ) ;
/* Release the whole structure */
2018-07-12 17:24:46 +02:00
SyMemBackendPoolFree ( & pVm - > sAllocator , pFrame ) ;
2018-07-12 13:26:32 +02:00
}
}
/*
* Compare two functions signature and return the comparison result .
*/
2018-07-12 17:24:46 +02:00
static int VmOverloadCompare ( SyString * pFirst , SyString * pSecond ) {
2018-07-12 13:26:32 +02:00
const char * zSend = & pSecond - > zString [ pSecond - > nByte ] ;
const char * zFend = & pFirst - > zString [ pFirst - > nByte ] ;
const char * zSin = pSecond - > zString ;
const char * zFin = pFirst - > zString ;
const char * zPtr = zFin ;
2018-07-12 17:24:46 +02:00
for ( ; ; ) {
if ( zFin > = zFend | | zSin > = zSend ) {
2018-07-12 13:26:32 +02:00
break ;
}
2018-07-12 17:24:46 +02:00
if ( zFin [ 0 ] ! = zSin [ 0 ] ) {
2018-07-12 13:26:32 +02:00
/* mismatch */
break ;
}
zFin + + ;
zSin + + ;
}
2018-07-12 17:24:46 +02:00
return ( int ) ( zFin - zPtr ) ;
2018-07-12 13:26:32 +02:00
}
2018-07-22 21:41:33 +02:00
/* Forward declaration */
static sxi32 VmLocalExec ( ph7_vm * pVm , SySet * pByteCode , ph7_value * pResult ) ;
2018-07-12 13:26:32 +02:00
/*
* Select the appropriate VM function for the current call context .
* This is the implementation of the powerful ' function overloading ' feature
* introduced by the version 2 of the PH7 engine .
* Refer to the official documentation for more information .
*/
2018-07-12 17:24:46 +02:00
static ph7_vm_func * VmOverload (
2018-07-12 13:26:32 +02:00
ph7_vm * pVm , /* Target VM */
ph7_vm_func * pList , /* Linked list of candidates for overloading */
ph7_value * aArg , /* Array of passed arguments */
int nArg /* Total number of passed arguments */
2018-07-12 17:24:46 +02:00
) {
2018-08-08 06:52:15 +02:00
int iTarget , i , j , iArgs , iCur , iMax ;
2018-07-12 13:26:32 +02:00
ph7_vm_func * apSet [ 10 ] ; /* Maximum number of candidates */
ph7_vm_func * pLink ;
2018-08-08 09:00:24 +02:00
ph7_vm_func_arg * pFuncArg ;
2018-07-12 13:26:32 +02:00
SyString sArgSig ;
SyBlob sSig ;
pLink = pList ;
i = 0 ;
/* Put functions expecting the same number of passed arguments */
2018-07-12 17:24:46 +02:00
while ( i < ( int ) SX_ARRAYSIZE ( apSet ) ) {
if ( pLink = = 0 ) {
2018-07-12 13:26:32 +02:00
break ;
}
2018-08-08 06:52:15 +02:00
iArgs = ( int ) SySetUsed ( & pLink - > aArgs ) ;
if ( nArg = = iArgs ) {
2018-08-08 09:00:24 +02:00
/* Exact amount of parameters, a candidate to call */
2018-08-08 06:52:15 +02:00
apSet [ i + + ] = pLink ;
} else if ( nArg < iArgs ) {
/* Fewer parameters passed, check if all are required */
2018-08-08 09:00:24 +02:00
pFuncArg = ( ph7_vm_func_arg * ) SySetAt ( & pLink - > aArgs , nArg ) ;
if ( pFuncArg ) {
if ( SySetUsed ( & pFuncArg - > aByteCode ) > = 1 ) {
/* First missing parameter has a compiled default value associated, a candidate to call */
apSet [ i + + ] = pLink ;
}
}
2018-07-12 13:26:32 +02:00
}
/* Point to the next entry */
pLink = pLink - > pNextName ;
}
2018-07-12 17:24:46 +02:00
if ( i < 1 ) {
2018-07-22 21:41:33 +02:00
/* No candidates, throw an error */
2018-09-04 08:54:48 +02:00
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR , " Invalid number of arguments passed to function/method '%z()' " , & pList - > sName ) ;
2018-07-12 13:26:32 +02:00
}
2018-07-12 17:24:46 +02:00
if ( nArg < 1 | | i < 2 ) {
2018-07-12 13:26:32 +02:00
/* Return the only candidate */
return apSet [ 0 ] ;
}
/* Calculate function signature */
2018-07-12 17:24:46 +02:00
SyBlobInit ( & sSig , & pVm - > sAllocator ) ;
for ( j = 0 ; j < nArg ; j + + ) {
2018-07-12 13:26:32 +02:00
int c = ' n ' ; /* null */
2019-05-21 14:49:36 +02:00
if ( aArg [ j ] . nType & MEMOBJ_BOOL ) {
2018-09-19 19:27:50 +02:00
/* Bool */
2018-07-12 13:26:32 +02:00
c = ' b ' ;
2019-05-21 14:49:36 +02:00
} else if ( aArg [ j ] . nType & MEMOBJ_CALL ) {
2018-09-19 19:27:50 +02:00
/* Callback */
c = ' a ' ;
2019-05-21 14:49:36 +02:00
} else if ( aArg [ j ] . nType & MEMOBJ_CHAR ) {
2018-09-19 19:27:50 +02:00
/* Char */
c = ' c ' ;
2019-05-21 14:49:36 +02:00
} else if ( aArg [ j ] . nType & MEMOBJ_INT ) {
2018-09-19 19:27:50 +02:00
/* Integer */
2018-07-12 13:26:32 +02:00
c = ' i ' ;
2019-05-21 14:49:36 +02:00
} else if ( aArg [ j ] . nType & MEMOBJ_MIXED ) {
2018-09-19 19:27:50 +02:00
/* Mixed */
c = ' m ' ;
2019-05-21 14:49:36 +02:00
} else if ( aArg [ j ] . nType & MEMOBJ_OBJ ) {
2018-07-12 13:26:32 +02:00
/* Class instance */
ph7_class * pClass = ( ( ph7_class_instance * ) aArg [ j ] . x . pOther ) - > pClass ;
SyString * pName = & pClass - > sName ;
2018-07-12 17:24:46 +02:00
SyBlobAppend ( & sSig , ( const void * ) pName - > zString , pName - > nByte ) ;
2018-07-12 13:26:32 +02:00
c = - 1 ;
2019-05-21 14:49:36 +02:00
} else if ( aArg [ j ] . nType & MEMOBJ_REAL ) {
2018-09-19 19:27:50 +02:00
/* Float */
c = ' f ' ;
2019-05-21 14:49:36 +02:00
} else if ( aArg [ j ] . nType & MEMOBJ_RES ) {
2018-09-19 19:27:50 +02:00
/* Resource */
c = ' r ' ;
2019-05-21 14:49:36 +02:00
} else if ( aArg [ j ] . nType & MEMOBJ_STRING ) {
2018-09-19 19:27:50 +02:00
/* String */
c = ' s ' ;
2019-05-21 14:49:36 +02:00
} else if ( aArg [ j ] . nType & MEMOBJ_VOID ) {
2018-09-19 19:27:50 +02:00
/* Void */
c = ' v ' ;
}
2019-05-21 14:49:36 +02:00
if ( aArg [ j ] . nType & MEMOBJ_HASHMAP & & ( aArg [ j ] . nType & MEMOBJ_OBJ ) = = 0 ) {
2018-09-19 19:27:50 +02:00
c = SyToUpper ( c ) ;
2018-07-12 13:26:32 +02:00
}
2018-07-12 17:24:46 +02:00
if ( c > 0 ) {
SyBlobAppend ( & sSig , ( const void * ) & c , sizeof ( char ) ) ;
2018-07-12 13:26:32 +02:00
}
}
2018-07-12 17:24:46 +02:00
SyStringInitFromBuf ( & sArgSig , SyBlobData ( & sSig ) , SyBlobLength ( & sSig ) ) ;
2018-07-12 13:26:32 +02:00
iTarget = 0 ;
iMax = - 1 ;
/* Select the appropriate function */
2018-07-12 17:24:46 +02:00
for ( j = 0 ; j < i ; j + + ) {
2018-07-12 13:26:32 +02:00
/* Compare the two signatures */
2018-07-12 17:24:46 +02:00
iCur = VmOverloadCompare ( & sArgSig , & apSet [ j ] - > sSignature ) ;
if ( iCur > iMax ) {
2018-07-12 13:26:32 +02:00
iMax = iCur ;
iTarget = j ;
}
}
SyBlobRelease ( & sSig ) ;
/* Appropriate function for the current call context */
return apSet [ iTarget ] ;
}
/*
2018-07-23 17:10:48 +02:00
* Mount a compiled class into the freshly created virtual machine so that
2018-07-12 13:26:32 +02:00
* it can be instanciated from the executed PHP script .
*/
static sxi32 VmMountUserClass (
ph7_vm * pVm , /* Target VM */
ph7_class * pClass /* Class to be mounted */
2018-07-12 17:24:46 +02:00
) {
2018-07-12 13:26:32 +02:00
ph7_class_method * pMeth ;
ph7_class_attr * pAttr ;
SyHashEntry * pEntry ;
sxi32 rc ;
/* Reset the loop cursor */
SyHashResetLoopCursor ( & pClass - > hAttr ) ;
/* Process only static and constant attribute */
2018-07-12 17:24:46 +02:00
while ( ( pEntry = SyHashGetNextEntry ( & pClass - > hAttr ) ) ! = 0 ) {
2018-07-12 13:26:32 +02:00
/* Extract the current attribute */
pAttr = ( ph7_class_attr * ) pEntry - > pUserData ;
2018-07-12 17:24:46 +02:00
if ( pAttr - > iFlags & ( PH7_CLASS_ATTR_CONSTANT | PH7_CLASS_ATTR_STATIC ) ) {
2019-04-03 07:00:17 +02:00
ph7_value * pMemObj , * pResult ;
2018-07-12 13:26:32 +02:00
/* Reserve a memory object for this constant/static attribute */
pMemObj = PH7_ReserveMemObj ( & ( * pVm ) ) ;
2019-04-03 07:00:17 +02:00
pResult = PH7_ReserveMemObj ( & ( * pVm ) ) ;
if ( pMemObj = = 0 | | pResult = = 0 ) {
2018-09-03 16:16:32 +02:00
PH7_VmMemoryError ( & ( * pVm ) ) ;
2018-07-12 13:26:32 +02:00
}
2019-04-03 13:57:29 +02:00
MemObjSetType ( pMemObj , pAttr - > nType ) ;
2018-07-12 17:24:46 +02:00
if ( SySetUsed ( & pAttr - > aByteCode ) > 0 ) {
/* Initialize attribute default value (any complex expression) */
2019-04-03 07:00:17 +02:00
VmLocalExec ( & ( * pVm ) , & pAttr - > aByteCode , pResult ) ;
2019-04-03 13:57:29 +02:00
rc = PH7_MemObjSafeStore ( pResult , pMemObj ) ;
if ( rc ! = SXRET_OK ) {
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR , " Cannot assign a value of incompatible type to variable '%z::$%z' " , & pClass - > sName , & pAttr - > sName ) ;
}
2019-05-21 14:49:36 +02:00
} else if ( pMemObj - > nType & MEMOBJ_HASHMAP ) {
2019-04-04 18:15:41 +02:00
ph7_hashmap * pMap ;
pMap = PH7_NewHashmap ( & ( * pVm ) , 0 , 0 ) ;
if ( pMap = = 0 ) {
PH7_VmMemoryError ( & ( * pVm ) ) ;
}
pMemObj - > x . pOther = pMap ;
2019-03-29 19:56:10 +01:00
}
2019-04-03 07:00:17 +02:00
/* Free up memory */
PH7_MemObjRelease ( pResult ) ;
2018-07-12 13:26:32 +02:00
/* Record attribute index */
pAttr - > nIdx = pMemObj - > nIdx ;
/* Install static attribute in the reference table */
2018-07-12 17:24:46 +02:00
PH7_VmRefObjInstall ( & ( * pVm ) , pMemObj - > nIdx , 0 , 0 , VM_REF_IDX_KEEP ) ;
2018-07-12 13:26:32 +02:00
}
}
/* Install class methods */
2018-07-12 17:24:46 +02:00
if ( pClass - > iFlags & PH7_CLASS_INTERFACE ) {
2018-07-12 13:26:32 +02:00
/* Do not mount interface methods since they are signatures only.
*/
return SXRET_OK ;
}
/* Install the methods now */
SyHashResetLoopCursor ( & pClass - > hMethod ) ;
2018-07-12 17:24:46 +02:00
while ( ( pEntry = SyHashGetNextEntry ( & pClass - > hMethod ) ) ! = 0 ) {
2018-07-12 13:26:32 +02:00
pMeth = ( ph7_class_method * ) pEntry - > pUserData ;
2018-07-30 17:08:25 +02:00
if ( ( pMeth - > iFlags & PH7_CLASS_ATTR_VIRTUAL ) = = 0 ) {
2018-07-12 17:24:46 +02:00
rc = PH7_VmInstallUserFunction ( & ( * pVm ) , & pMeth - > sFunc , & pMeth - > sVmName ) ;
if ( rc ! = SXRET_OK ) {
2018-07-12 13:26:32 +02:00
return rc ;
}
}
}
return SXRET_OK ;
}
/*
* Allocate a private frame for attributes of the given
* class instance ( Object in the PHP jargon ) .
*/
PH7_PRIVATE sxi32 PH7_VmCreateClassInstanceFrame (
ph7_vm * pVm , /* Target VM */
ph7_class_instance * pObj /* Class instance */
2018-07-12 17:24:46 +02:00
) {
2018-07-12 13:26:32 +02:00
ph7_class * pClass = pObj - > pClass ;
ph7_class_attr * pAttr ;
SyHashEntry * pEntry ;
sxi32 rc ;
/* Install class attribute in the private frame associated with this instance */
SyHashResetLoopCursor ( & pClass - > hAttr ) ;
2018-07-12 17:24:46 +02:00
while ( ( pEntry = SyHashGetNextEntry ( & pClass - > hAttr ) ) ! = 0 ) {
2018-07-12 13:26:32 +02:00
VmClassAttr * pVmAttr ;
/* Extract the current attribute */
pAttr = ( ph7_class_attr * ) pEntry - > pUserData ;
2018-07-12 17:24:46 +02:00
pVmAttr = ( VmClassAttr * ) SyMemBackendPoolAlloc ( & pVm - > sAllocator , sizeof ( VmClassAttr ) ) ;
if ( pVmAttr = = 0 ) {
2018-07-12 13:26:32 +02:00
return SXERR_MEM ;
}
pVmAttr - > pAttr = pAttr ;
2018-07-12 17:24:46 +02:00
if ( ( pAttr - > iFlags & ( PH7_CLASS_ATTR_CONSTANT | PH7_CLASS_ATTR_STATIC ) ) = = 0 ) {
2019-04-03 08:32:59 +02:00
ph7_value * pMemObj , * pResult ;
2018-07-12 13:26:32 +02:00
/* Reserve a memory object for this attribute */
pMemObj = PH7_ReserveMemObj ( & ( * pVm ) ) ;
2019-04-03 08:32:59 +02:00
pResult = PH7_ReserveMemObj ( & ( * pVm ) ) ;
if ( pMemObj = = 0 | | pResult = = 0 ) {
2018-07-12 17:24:46 +02:00
SyMemBackendPoolFree ( & pVm - > sAllocator , pVmAttr ) ;
2018-07-12 13:26:32 +02:00
return SXERR_MEM ;
}
2019-04-03 13:57:29 +02:00
MemObjSetType ( pMemObj , pAttr - > nType ) ;
2018-07-12 17:24:46 +02:00
if ( SySetUsed ( & pAttr - > aByteCode ) > 0 ) {
/* Initialize attribute default value (any complex expression) */
2019-04-03 08:32:59 +02:00
VmLocalExec ( & ( * pVm ) , & pAttr - > aByteCode , pResult ) ;
2019-04-03 13:57:29 +02:00
rc = PH7_MemObjSafeStore ( pResult , pMemObj ) ;
if ( rc ! = SXRET_OK ) {
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR , " Cannot assign a value of incompatible type to variable '%z::$%z' " , & pClass - > sName , & pAttr - > sName ) ;
}
2019-05-21 14:49:36 +02:00
} else if ( pMemObj - > nType & MEMOBJ_HASHMAP ) {
2019-04-04 18:15:41 +02:00
ph7_hashmap * pMap ;
pMap = PH7_NewHashmap ( & ( * pVm ) , 0 , 0 ) ;
if ( pMap = = 0 ) {
PH7_VmMemoryError ( & ( * pVm ) ) ;
}
pMemObj - > x . pOther = pMap ;
2019-04-03 08:32:59 +02:00
}
/* Free up memory */
PH7_MemObjRelease ( pResult ) ;
/* Record attribute index */
pVmAttr - > nIdx = pMemObj - > nIdx ;
2018-07-12 17:24:46 +02:00
rc = SyHashInsert ( & pObj - > hAttr , SyStringData ( & pAttr - > sName ) , SyStringLength ( & pAttr - > sName ) , pVmAttr ) ;
if ( rc ! = SXRET_OK ) {
2018-07-12 13:26:32 +02:00
VmSlot sSlot ;
/* Restore memory object */
sSlot . nIdx = pMemObj - > nIdx ;
sSlot . pUserData = 0 ;
2018-07-12 17:24:46 +02:00
SySetPut ( & pVm - > aFreeObj , ( const void * ) & sSlot ) ;
SyMemBackendPoolFree ( & pVm - > sAllocator , pVmAttr ) ;
2018-07-12 13:26:32 +02:00
return SXERR_MEM ;
}
/* Install attribute in the reference table */
2018-07-12 17:24:46 +02:00
PH7_VmRefObjInstall ( & ( * pVm ) , pMemObj - > nIdx , 0 , 0 , VM_REF_IDX_KEEP ) ;
} else {
2018-07-12 13:26:32 +02:00
/* Install static/constant attribute */
pVmAttr - > nIdx = pAttr - > nIdx ;
2018-07-12 17:24:46 +02:00
rc = SyHashInsert ( & pObj - > hAttr , SyStringData ( & pAttr - > sName ) , SyStringLength ( & pAttr - > sName ) , pVmAttr ) ;
if ( rc ! = SXRET_OK ) {
SyMemBackendPoolFree ( & pVm - > sAllocator , pVmAttr ) ;
2018-07-12 13:26:32 +02:00
return SXERR_MEM ;
}
}
}
return SXRET_OK ;
}
/* Forward declaration */
2018-07-12 17:24:46 +02:00
static VmRefObj * VmRefObjExtract ( ph7_vm * pVm , sxu32 nObjIdx ) ;
static sxi32 VmRefObjUnlink ( ph7_vm * pVm , VmRefObj * pRef ) ;
/*
2018-07-12 13:26:32 +02:00
* Dummy read - only buffer used for slot reservation .
*/
2018-07-12 17:24:46 +02:00
static const char zDummy [ sizeof ( ph7_value ) ] = { 0 } ; /* Must be >= sizeof(ph7_value) */
2018-07-12 13:26:32 +02:00
/*
* Reserve a constant memory object .
* Return a pointer to the raw ph7_value on success . NULL on failure .
*/
2018-07-12 17:24:46 +02:00
PH7_PRIVATE ph7_value * PH7_ReserveConstObj ( ph7_vm * pVm , sxu32 * pIndex ) {
2018-07-12 13:26:32 +02:00
ph7_value * pObj ;
sxi32 rc ;
2018-07-12 17:24:46 +02:00
if ( pIndex ) {
2018-07-12 13:26:32 +02:00
/* Object index in the object table */
* pIndex = SySetUsed ( & pVm - > aLitObj ) ;
}
/* Reserve a slot for the new object */
2018-07-12 17:24:46 +02:00
rc = SySetPut ( & pVm - > aLitObj , ( const void * ) zDummy ) ;
if ( rc ! = SXRET_OK ) {
2018-07-12 13:26:32 +02:00
/* If the supplied memory subsystem is so sick that we are unable to allocate
* a tiny chunk of memory , there is no much we can do here .
*/
return 0 ;
}
pObj = ( ph7_value * ) SySetPeek ( & pVm - > aLitObj ) ;
return pObj ;
}
/*
* Reserve a memory object .
* Return a pointer to the raw ph7_value on success . NULL on failure .
*/
2018-07-12 17:24:46 +02:00
PH7_PRIVATE ph7_value * VmReserveMemObj ( ph7_vm * pVm , sxu32 * pIndex ) {
2018-07-12 13:26:32 +02:00
ph7_value * pObj ;
sxi32 rc ;
2018-07-12 17:24:46 +02:00
if ( pIndex ) {
2018-07-12 13:26:32 +02:00
/* Object index in the object table */
* pIndex = SySetUsed ( & pVm - > aMemObj ) ;
}
/* Reserve a slot for the new object */
2018-07-12 17:24:46 +02:00
rc = SySetPut ( & pVm - > aMemObj , ( const void * ) zDummy ) ;
if ( rc ! = SXRET_OK ) {
2018-07-12 13:26:32 +02:00
/* If the supplied memory subsystem is so sick that we are unable to allocate
* a tiny chunk of memory , there is no much we can do here .
*/
return 0 ;
}
pObj = ( ph7_value * ) SySetPeek ( & pVm - > aMemObj ) ;
return pObj ;
}
/* Forward declaration */
2018-08-15 16:01:09 +02:00
static sxi32 VmEvalChunk ( ph7_vm * pVm , ph7_context * pCtx , SyString * pChunk , int iFlags ) ;
2018-07-12 13:26:32 +02:00
/*
* Built - in classes / interfaces and some functions that cannot be implemented
* directly as foreign functions .
*/
# define PH7_BUILTIN_LIB \
" class Exception { " \
2019-03-17 19:52:28 +01:00
" protected string $message = 'Unknown exception'; " \
" protected int $code = 0; " \
" protected string $file; " \
" protected int $line; " \
2019-04-10 12:44:44 +02:00
" protected mixed[] $trace; " \
2019-03-17 19:52:28 +01:00
" protected object $previous; " \
" public void __construct(string $message = '', int $code = 0, Exception $previous = null) { " \
2019-04-10 12:44:44 +02:00
" if($message) { " \
2018-07-12 13:26:32 +02:00
" $this->message = $message; " \
" } " \
" $this->code = $code; " \
" $this->file = __FILE__; " \
" $this->line = __LINE__; " \
" $this->trace = debug_backtrace(); " \
2019-04-10 12:44:44 +02:00
" if($previous) { " \
2018-07-12 13:26:32 +02:00
" $this->previous = $previous; " \
" } " \
" } " \
2019-03-17 19:52:28 +01:00
" public string getMessage() { " \
2018-07-12 13:26:32 +02:00
" return $this->message; " \
" } " \
2019-03-17 19:52:28 +01:00
" public int getCode() { " \
2018-07-12 13:26:32 +02:00
" return $this->code; " \
" } " \
2019-03-17 19:52:28 +01:00
" public string getFile() { " \
2018-07-12 13:26:32 +02:00
" return $this->file; " \
" } " \
2019-03-17 19:52:28 +01:00
" public int getLine() { " \
2018-07-12 13:26:32 +02:00
" return $this->line; " \
" } " \
2019-03-17 19:52:28 +01:00
" public mixed getTrace() { " \
2018-07-12 13:26:32 +02:00
" return $this->trace; " \
" } " \
2019-03-17 19:52:28 +01:00
" public string getTraceAsString() { " \
2018-07-12 13:26:32 +02:00
" return debug_string_backtrace(); " \
" } " \
2019-03-17 19:52:28 +01:00
" public object getPrevious() { " \
2018-07-12 13:26:32 +02:00
" return $this->previous; " \
" } " \
2019-03-17 19:52:28 +01:00
" public string __toString(){ " \
" return $this->file + ' ' + $this->line + ' ' + $this->code + ' ' + $this->message; " \
2018-07-12 17:24:46 +02:00
" } " \
2018-07-12 13:26:32 +02:00
" } " \
" class ErrorException extends Exception { " \
2019-03-17 19:52:28 +01:00
" protected int $severity; " \
" public void __construct(string $message = '', " \
" int $code = 0, int $severity = 1, string $filename = __FILE__ , int $lineno = __LINE__ , Exception $previous = null) { " \
2019-04-10 12:44:44 +02:00
" if($message) { " \
2018-07-12 13:26:32 +02:00
" $this->message = $message; " \
" } " \
" $this->severity = $severity; " \
" $this->code = $code; " \
" $this->file = $filename; " \
" $this->line = $lineno; " \
" $this->trace = debug_backtrace(); " \
2019-04-10 12:44:44 +02:00
" if($previous) { " \
2018-07-12 13:26:32 +02:00
" $this->previous = $previous; " \
" } " \
" } " \
2019-03-17 19:52:28 +01:00
" public int getSeverity(){ " \
2018-07-12 13:26:32 +02:00
" return $this->severity; " \
2018-07-12 17:24:46 +02:00
" } " \
2018-07-12 13:26:32 +02:00
" } " \
" interface Iterator { " \
2019-03-17 19:52:28 +01:00
" public mixed current(); " \
" public mixed key(); " \
" public void next(); " \
" public void rewind(); " \
" public bool valid(); " \
2018-07-12 13:26:32 +02:00
" } " \
" interface IteratorAggregate { " \
2019-03-17 19:52:28 +01:00
" public mixed getIterator(); " \
2018-07-12 13:26:32 +02:00
" } " \
" interface Serializable { " \
2019-03-17 19:52:28 +01:00
" public string serialize(); " \
" public void unserialize(string $serialized); " \
2018-07-12 13:26:32 +02:00
" } " \
2018-07-23 17:10:48 +02:00
" /* Directory related IO */ " \
2018-07-12 13:26:32 +02:00
" class Directory { " \
2019-03-17 19:52:28 +01:00
" public resource $handle; " \
" public string $path; " \
" public void __construct(string $path) " \
2018-07-12 13:26:32 +02:00
" { " \
" $this->handle = opendir($path); " \
2019-03-17 19:52:28 +01:00
" if($this->handle) { " \
2018-07-12 13:26:32 +02:00
" $this->path = $path; " \
" } " \
" } " \
2019-03-17 19:52:28 +01:00
" public void __destruct() " \
2018-07-12 13:26:32 +02:00
" { " \
2019-03-17 19:52:28 +01:00
" if($this->handle) { " \
2018-07-12 13:26:32 +02:00
" closedir($this->handle); " \
" } " \
" } " \
2019-03-17 19:57:31 +01:00
" public string read() " \
2018-07-12 13:26:32 +02:00
" { " \
" return readdir($this->handle); " \
" } " \
2019-03-17 19:52:28 +01:00
" public void rewind() " \
2018-07-12 13:26:32 +02:00
" { " \
" rewinddir($this->handle); " \
" } " \
2019-03-17 19:52:28 +01:00
" public void close() " \
2018-07-12 13:26:32 +02:00
" { " \
" closedir($this->handle); " \
2019-03-17 19:52:28 +01:00
" $this->handle = 0; " \
2018-07-12 13:26:32 +02:00
" } " \
" } " \
" class stdClass{ " \
2019-03-17 19:52:28 +01:00
" public mixed $value; " \
2018-07-12 13:26:32 +02:00
" /* Magic methods */ " \
2019-03-17 19:52:28 +01:00
" public int __toInt(){ return (int)$this->value; } " \
" public bool __toBool(){ return (bool)$this->value; } " \
" public float __toFloat(){ return (float)$this->value; } " \
" public string __toString(){ return (string)$this->value; } " \
" void __construct(mixed $v){ $this->value = $v; } " \
2018-07-12 17:24:46 +02:00
" } "
2018-07-12 13:26:32 +02:00
/*
* Initialize a freshly allocated PH7 Virtual Machine so that we can
* start compiling the target PHP program .
*/
PH7_PRIVATE sxi32 PH7_VmInit (
2018-08-27 19:53:24 +02:00
ph7_vm * pVm , /* Initialize this */
ph7 * pEngine , /* Master engine */
sxbool bDebug /* Debugging */
2018-07-12 17:24:46 +02:00
) {
2018-07-12 13:26:32 +02:00
SyString sBuiltin ;
ph7_value * pObj ;
sxi32 rc ;
/* Zero the structure */
2018-07-12 17:24:46 +02:00
SyZero ( pVm , sizeof ( ph7_vm ) ) ;
2018-07-12 13:26:32 +02:00
/* Initialize VM fields */
pVm - > pEngine = & ( * pEngine ) ;
2018-07-12 17:24:46 +02:00
SyMemBackendInitFromParent ( & pVm - > sAllocator , & pEngine - > sAllocator ) ;
2018-07-12 13:26:32 +02:00
/* Instructions containers */
2018-09-01 19:56:36 +02:00
SySetInit ( & pVm - > aInstrSet , & pVm - > sAllocator , sizeof ( VmInstr ) ) ;
2018-07-12 17:24:46 +02:00
SySetInit ( & pVm - > aByteCode , & pVm - > sAllocator , sizeof ( VmInstr ) ) ;
SySetAlloc ( & pVm - > aByteCode , 0xFF ) ;
2018-07-12 13:26:32 +02:00
pVm - > pByteContainer = & pVm - > aByteCode ;
/* Object containers */
2018-07-12 17:24:46 +02:00
SySetInit ( & pVm - > aMemObj , & pVm - > sAllocator , sizeof ( ph7_value ) ) ;
SySetAlloc ( & pVm - > aMemObj , 0xFF ) ;
2018-07-12 13:26:32 +02:00
/* Virtual machine internal containers */
2018-07-12 17:24:46 +02:00
SyBlobInit ( & pVm - > sConsumer , & pVm - > sAllocator ) ;
SyBlobInit ( & pVm - > sArgv , & pVm - > sAllocator ) ;
SySetInit ( & pVm - > aLitObj , & pVm - > sAllocator , sizeof ( ph7_value ) ) ;
SySetAlloc ( & pVm - > aLitObj , 0xFF ) ;
SyHashInit ( & pVm - > hHostFunction , & pVm - > sAllocator , 0 , 0 ) ;
SyHashInit ( & pVm - > hFunction , & pVm - > sAllocator , 0 , 0 ) ;
2019-04-28 18:24:22 +02:00
SyHashInit ( & pVm - > hClass , & pVm - > sAllocator , SyStrHash , SyStrncmp ) ;
2018-07-12 17:24:46 +02:00
SyHashInit ( & pVm - > hConstant , & pVm - > sAllocator , 0 , 0 ) ;
SyHashInit ( & pVm - > hSuper , & pVm - > sAllocator , 0 , 0 ) ;
2018-07-12 18:21:14 +02:00
SyHashInit ( & pVm - > hDBAL , & pVm - > sAllocator , 0 , 0 ) ;
2018-07-12 17:24:46 +02:00
SySetInit ( & pVm - > aFreeObj , & pVm - > sAllocator , sizeof ( VmSlot ) ) ;
SySetInit ( & pVm - > aSelf , & pVm - > sAllocator , sizeof ( ph7_class * ) ) ;
2018-07-15 00:06:26 +02:00
SySetInit ( & pVm - > aAutoLoad , & pVm - > sAllocator , sizeof ( VmAutoLoadCB ) ) ;
2018-07-12 17:24:46 +02:00
SySetInit ( & pVm - > aShutdown , & pVm - > sAllocator , sizeof ( VmShutdownCB ) ) ;
SySetInit ( & pVm - > aException , & pVm - > sAllocator , sizeof ( ph7_exception * ) ) ;
2018-07-12 13:26:32 +02:00
/* Configuration containers */
2018-07-18 22:01:04 +02:00
SySetInit ( & pVm - > aModules , & pVm - > sAllocator , sizeof ( VmModule ) ) ;
2018-07-12 17:24:46 +02:00
SySetInit ( & pVm - > aFiles , & pVm - > sAllocator , sizeof ( SyString ) ) ;
SySetInit ( & pVm - > aPaths , & pVm - > sAllocator , sizeof ( SyString ) ) ;
SySetInit ( & pVm - > aIncluded , & pVm - > sAllocator , sizeof ( SyString ) ) ;
SySetInit ( & pVm - > aOB , & pVm - > sAllocator , sizeof ( VmObEntry ) ) ;
SySetInit ( & pVm - > aIOstream , & pVm - > sAllocator , sizeof ( ph7_io_stream * ) ) ;
2018-07-12 13:26:32 +02:00
/* Error callbacks containers */
2018-07-12 17:24:46 +02:00
PH7_MemObjInit ( & ( * pVm ) , & pVm - > aExceptionCB [ 0 ] ) ;
PH7_MemObjInit ( & ( * pVm ) , & pVm - > aExceptionCB [ 1 ] ) ;
PH7_MemObjInit ( & ( * pVm ) , & pVm - > sAssertCallback ) ;
2018-07-12 13:26:32 +02:00
/* Set a default recursion limit */
# if defined(__WINNT__) || defined(__UNIXES__)
pVm - > nMaxDepth = 32 ;
# else
pVm - > nMaxDepth = 16 ;
# endif
/* Default assertion flags */
pVm - > iAssertFlags = PH7_ASSERT_WARNING ; /* Issue a warning for each failed assertion */
/* JSON return status */
pVm - > json_rc = JSON_ERROR_NONE ;
/* PRNG context */
2018-07-12 17:24:46 +02:00
SyRandomnessInit ( & pVm - > sPrng , 0 , 0 ) ;
2018-07-12 13:26:32 +02:00
/* Install the null constant */
2018-07-12 17:24:46 +02:00
pObj = PH7_ReserveConstObj ( & ( * pVm ) , 0 ) ;
if ( pObj = = 0 ) {
2018-07-12 13:26:32 +02:00
rc = SXERR_MEM ;
goto Err ;
}
2018-07-12 17:24:46 +02:00
PH7_MemObjInit ( pVm , pObj ) ;
2018-07-12 13:26:32 +02:00
/* Install the boolean TRUE constant */
2018-07-12 17:24:46 +02:00
pObj = PH7_ReserveConstObj ( & ( * pVm ) , 0 ) ;
if ( pObj = = 0 ) {
2018-07-12 13:26:32 +02:00
rc = SXERR_MEM ;
goto Err ;
}
2018-07-12 17:24:46 +02:00
PH7_MemObjInitFromBool ( pVm , pObj , 1 ) ;
2018-07-12 13:26:32 +02:00
/* Install the boolean FALSE constant */
2018-07-12 17:24:46 +02:00
pObj = PH7_ReserveConstObj ( & ( * pVm ) , 0 ) ;
if ( pObj = = 0 ) {
2018-07-12 13:26:32 +02:00
rc = SXERR_MEM ;
goto Err ;
}
2018-07-12 17:24:46 +02:00
PH7_MemObjInitFromBool ( pVm , pObj , 0 ) ;
2018-07-12 13:26:32 +02:00
/* Create the global frame */
2018-07-12 17:24:46 +02:00
rc = VmEnterFrame ( & ( * pVm ) , 0 , 0 , 0 ) ;
if ( rc ! = SXRET_OK ) {
2018-07-12 13:26:32 +02:00
goto Err ;
}
/* Initialize the code generator */
2018-07-12 17:24:46 +02:00
rc = PH7_InitCodeGenerator ( pVm , pEngine - > xConf . xErr , pEngine - > xConf . pErrData ) ;
if ( rc ! = SXRET_OK ) {
2018-07-12 13:26:32 +02:00
goto Err ;
}
/* VM correctly initialized,set the magic number */
pVm - > nMagic = PH7_VM_INIT ;
2018-07-12 17:24:46 +02:00
SyStringInitFromBuf ( & sBuiltin , PH7_BUILTIN_LIB , sizeof ( PH7_BUILTIN_LIB ) - 1 ) ;
2018-08-15 19:06:00 +02:00
/* Precompile the built-in library */
2018-08-15 16:01:09 +02:00
VmEvalChunk ( & ( * pVm ) , 0 , & sBuiltin , PH7_AERSCRIPT_CODE ) ;
2018-08-27 19:53:24 +02:00
if ( bDebug ) {
2018-09-01 19:56:36 +02:00
/* Enable debugging */
2018-08-27 19:53:24 +02:00
pVm - > bDebug = TRUE ;
2018-08-26 19:59:17 +02:00
}
2018-07-12 13:26:32 +02:00
/* Reset the code generator */
2018-07-12 17:24:46 +02:00
PH7_ResetCodeGenerator ( & ( * pVm ) , pEngine - > xConf . xErr , pEngine - > xConf . pErrData ) ;
2018-07-12 13:26:32 +02:00
return SXRET_OK ;
Err :
SyMemBackendRelease ( & pVm - > sAllocator ) ;
return rc ;
}
/*
* Default VM output consumer callback . That is , all VM output is redirected to this
* routine which store the output in an internal blob .
* The output can be extracted later after program execution [ ph7_vm_exec ( ) ] via
* the [ ph7_vm_config ( ) ] interface with a configuration verb set to
* PH7_VM_CONFIG_EXTRACT_OUTPUT .
2018-07-22 22:47:00 +02:00
* Refer to the official documentation for additional information .
2018-07-12 13:26:32 +02:00
* Note that for performance reason it ' s preferable to install a VM output
* consumer callback via ( PH7_VM_CONFIG_OUTPUT ) rather than waiting for the VM
* to finish executing and extracting the output .
*/
PH7_PRIVATE sxi32 PH7_VmBlobConsumer (
const void * pOut , /* VM Generated output*/
unsigned int nLen , /* Generated output length */
void * pUserData /* User private data */
2018-07-12 17:24:46 +02:00
) {
sxi32 rc ;
/* Store the output in an internal BLOB */
rc = SyBlobAppend ( ( SyBlob * ) pUserData , pOut , nLen ) ;
return rc ;
2018-07-12 13:26:32 +02:00
}
# define VM_STACK_GUARD 16
/*
* Allocate a new operand stack so that we can start executing
* our compiled PHP program .
* Return a pointer to the operand stack ( array of ph7_values )
* on success . NULL ( Fatal error ) on failure .
*/
2018-07-12 17:24:46 +02:00
static ph7_value * VmNewOperandStack (
2018-07-12 13:26:32 +02:00
ph7_vm * pVm , /* Target VM */
sxu32 nInstr /* Total numer of generated byte-code instructions */
2018-07-12 17:24:46 +02:00
) {
2018-07-12 13:26:32 +02:00
ph7_value * pStack ;
2018-07-12 17:24:46 +02:00
/* No instruction ever pushes more than a single element onto the
* * stack and the stack never grows on successive executions of the
* * same loop . So the total number of instructions is an upper bound
* * on the maximum stack depth required .
* *
* * Allocation all the stack space we will ever need .
*/
2018-07-12 13:26:32 +02:00
nInstr + = VM_STACK_GUARD ;
2018-07-12 17:24:46 +02:00
pStack = ( ph7_value * ) SyMemBackendAlloc ( & pVm - > sAllocator , nInstr * sizeof ( ph7_value ) ) ;
if ( pStack = = 0 ) {
2018-07-12 13:26:32 +02:00
return 0 ;
}
/* Initialize the operand stack */
2018-07-12 17:24:46 +02:00
while ( nInstr > 0 ) {
PH7_MemObjInit ( & ( * pVm ) , & pStack [ nInstr - 1 ] ) ;
2018-07-12 13:26:32 +02:00
- - nInstr ;
}
/* Ready for bytecode execution */
return pStack ;
}
/* Forward declaration */
static sxi32 VmRegisterSpecialFunction ( ph7_vm * pVm ) ;
2018-07-12 17:24:46 +02:00
static int VmInstanceOf ( ph7_class * pThis , ph7_class * pClass ) ;
2019-05-29 15:26:31 +02:00
static int VmClassMemberAccess ( ph7_vm * pVm , ph7_class * pClass , sxi32 iProtection ) ;
2018-07-12 13:26:32 +02:00
/*
* Prepare the Virtual Machine for byte - code execution .
* This routine gets called by the PH7 engine after
* successful compilation of the target PHP program .
*/
PH7_PRIVATE sxi32 PH7_VmMakeReady (
ph7_vm * pVm /* Target VM */
2018-07-12 17:24:46 +02:00
) {
2018-07-12 13:26:32 +02:00
SyHashEntry * pEntry ;
sxi32 rc ;
2018-07-12 17:24:46 +02:00
if ( pVm - > nMagic ! = PH7_VM_INIT ) {
2018-07-12 13:26:32 +02:00
/* Initialize your VM first */
return SXERR_CORRUPT ;
}
/* Mark the VM ready for byte-code execution */
2018-07-12 17:24:46 +02:00
pVm - > nMagic = PH7_VM_RUN ;
2018-07-12 13:26:32 +02:00
/* Release the code generator now we have compiled our program */
2018-07-12 17:24:46 +02:00
PH7_ResetCodeGenerator ( pVm , 0 , 0 ) ;
2018-07-12 13:26:32 +02:00
/* Emit the DONE instruction */
2018-09-05 17:31:06 +02:00
rc = PH7_VmEmitInstr ( & ( * pVm ) , 0 , PH7_OP_DONE , 0 , 0 , 0 , 0 ) ;
2018-07-12 17:24:46 +02:00
if ( rc ! = SXRET_OK ) {
2018-07-12 13:26:32 +02:00
return SXERR_MEM ;
}
2018-07-12 17:24:46 +02:00
/* Allocate a new operand stack */
pVm - > aOps = VmNewOperandStack ( & ( * pVm ) , SySetUsed ( pVm - > pByteContainer ) ) ;
if ( pVm - > aOps = = 0 ) {
2018-07-12 13:26:32 +02:00
return SXERR_MEM ;
}
/* Allocate the reference table */
pVm - > nRefSize = 0x10 ; /* Must be a power of two for fast arithemtic */
2018-07-12 17:24:46 +02:00
pVm - > apRefObj = ( VmRefObj * * ) SyMemBackendAlloc ( & pVm - > sAllocator , sizeof ( VmRefObj * ) * pVm - > nRefSize ) ;
if ( pVm - > apRefObj = = 0 ) {
2018-07-12 13:26:32 +02:00
/* Don't worry about freeing memory, everything will be released shortly */
return SXERR_MEM ;
}
/* Zero the reference table */
2018-07-12 17:24:46 +02:00
SyZero ( pVm - > apRefObj , sizeof ( VmRefObj * ) * pVm - > nRefSize ) ;
2018-07-12 13:26:32 +02:00
/* Register special functions first [i.e: print, json_encode(), func_get_args(), die, etc.] */
rc = VmRegisterSpecialFunction ( & ( * pVm ) ) ;
2018-07-12 17:24:46 +02:00
if ( rc ! = SXRET_OK ) {
2018-07-12 13:26:32 +02:00
/* Don't worry about freeing memory, everything will be released shortly */
return rc ;
}
/* Create superglobals [i.e: $GLOBALS, $_GET, $_POST...] */
rc = PH7_HashmapCreateSuper ( & ( * pVm ) ) ;
2018-07-12 17:24:46 +02:00
if ( rc ! = SXRET_OK ) {
2018-07-12 13:26:32 +02:00
/* Don't worry about freeing memory, everything will be released shortly */
return rc ;
}
/* Register built-in constants [i.e: PHP_EOL, PHP_OS...] */
PH7_RegisterBuiltInConstant ( & ( * pVm ) ) ;
2019-03-22 19:29:50 +01:00
/* Register built-in functions [i.e: array_diff(), strlen(), etc.] */
2018-07-12 13:26:32 +02:00
PH7_RegisterBuiltInFunction ( & ( * pVm ) ) ;
/* Initialize and install static and constants class attributes */
SyHashResetLoopCursor ( & pVm - > hClass ) ;
2018-07-12 17:24:46 +02:00
while ( ( pEntry = SyHashGetNextEntry ( & pVm - > hClass ) ) ! = 0 ) {
rc = VmMountUserClass ( & ( * pVm ) , ( ph7_class * ) pEntry - > pUserData ) ;
if ( rc ! = SXRET_OK ) {
2018-07-12 13:26:32 +02:00
return rc ;
}
}
/* VM is ready for bytecode execution */
return SXRET_OK ;
}
/*
* Reset a Virtual Machine to it ' s initial state .
*/
2018-07-12 17:24:46 +02:00
PH7_PRIVATE sxi32 PH7_VmReset ( ph7_vm * pVm ) {
2018-09-05 13:28:20 +02:00
if ( pVm - > nMagic ! = PH7_VM_RUN & & pVm - > nMagic ! = PH7_VM_EXEC & & pVm - > nMagic ! = PH7_VM_INCL ) {
2018-07-12 13:26:32 +02:00
return SXERR_CORRUPT ;
}
/* TICKET 1433-003: As of this version, the VM is automatically reset */
SyBlobReset ( & pVm - > sConsumer ) ;
/* Set the ready flag */
pVm - > nMagic = PH7_VM_RUN ;
return SXRET_OK ;
}
/*
* Release a Virtual Machine .
* Every virtual machine must be destroyed in order to avoid memory leaks .
*/
2018-07-12 17:24:46 +02:00
PH7_PRIVATE sxi32 PH7_VmRelease ( ph7_vm * pVm ) {
2018-07-19 07:35:59 +02:00
VmModule * pEntry ;
/* Iterate through modules list */
while ( SySetGetNextEntry ( & pVm - > aModules , ( void * * ) & pEntry ) = = SXRET_OK ) {
/* Unload the module */
2018-07-19 17:22:36 +02:00
# ifdef __WINNT__
FreeLibrary ( pEntry - > pHandle ) ;
# else
2018-07-19 07:35:59 +02:00
dlclose ( pEntry - > pHandle ) ;
2018-07-19 17:22:36 +02:00
# endif
2018-07-19 07:35:59 +02:00
}
/* Free up the heap */
SySetRelease ( & pVm - > aModules ) ;
2018-07-12 13:26:32 +02:00
/* Set the stale magic number */
pVm - > nMagic = PH7_VM_STALE ;
/* Release the private memory subsystem */
SyMemBackendRelease ( & pVm - > sAllocator ) ;
return SXRET_OK ;
}
/*
* Initialize a foreign function call context .
* The context in which a foreign function executes is stored in a ph7_context object .
* A pointer to a ph7_context object is always first parameter to application - defined foreign
* functions .
* The application - defined foreign function implementation will pass this pointer through into
* calls to dozens of interfaces , these includes ph7_result_int ( ) , ph7_result_string ( ) , ph7_result_value ( ) ,
2018-09-04 08:26:58 +02:00
* ph7_context_new_scalar ( ) , ph7_context_alloc_chunk ( ) , ph7_context_output ( ) and many more .
* Refer to the C / C + + Interfaces documentation for additional information .
2018-07-12 13:26:32 +02:00
*/
static sxi32 VmInitCallContext (
ph7_context * pOut , /* Call Context */
ph7_vm * pVm , /* Target VM */
ph7_user_func * pFunc , /* Foreign function to execute shortly */
ph7_value * pRet , /* Store return value here*/
sxi32 iFlags /* Control flags */
2018-07-12 17:24:46 +02:00
) {
2018-07-12 13:26:32 +02:00
pOut - > pFunc = pFunc ;
pOut - > pVm = pVm ;
2018-07-12 17:24:46 +02:00
SySetInit ( & pOut - > sVar , & pVm - > sAllocator , sizeof ( ph7_value * ) ) ;
SySetInit ( & pOut - > sChunk , & pVm - > sAllocator , sizeof ( ph7_aux_data ) ) ;
2018-07-12 13:26:32 +02:00
/* Assume a null return value */
2018-07-12 17:24:46 +02:00
MemObjSetType ( pRet , MEMOBJ_NULL ) ;
2018-07-12 13:26:32 +02:00
pOut - > pRet = pRet ;
pOut - > iFlags = iFlags ;
return SXRET_OK ;
}
/*
* Release a foreign function call context and cleanup the mess
* left behind .
*/
2018-07-12 17:24:46 +02:00
static void VmReleaseCallContext ( ph7_context * pCtx ) {
2018-07-12 13:26:32 +02:00
sxu32 n ;
2018-07-12 17:24:46 +02:00
if ( SySetUsed ( & pCtx - > sVar ) > 0 ) {
2018-07-12 13:26:32 +02:00
ph7_value * * apObj = ( ph7_value * * ) SySetBasePtr ( & pCtx - > sVar ) ;
2018-07-12 17:24:46 +02:00
for ( n = 0 ; n < SySetUsed ( & pCtx - > sVar ) ; + + n ) {
if ( apObj [ n ] = = 0 ) {
2018-07-12 13:26:32 +02:00
/* Already released */
continue ;
}
PH7_MemObjRelease ( apObj [ n ] ) ;
2018-07-12 17:24:46 +02:00
SyMemBackendPoolFree ( & pCtx - > pVm - > sAllocator , apObj [ n ] ) ;
2018-07-12 13:26:32 +02:00
}
SySetRelease ( & pCtx - > sVar ) ;
}
2018-07-12 17:24:46 +02:00
if ( SySetUsed ( & pCtx - > sChunk ) > 0 ) {
2018-07-12 13:26:32 +02:00
ph7_aux_data * aAux ;
void * pChunk ;
2018-07-12 17:24:46 +02:00
/* Automatic release of dynamically allocated chunk
2018-07-12 13:26:32 +02:00
* using [ ph7_context_alloc_chunk ( ) ] .
*/
aAux = ( ph7_aux_data * ) SySetBasePtr ( & pCtx - > sChunk ) ;
2018-07-12 17:24:46 +02:00
for ( n = 0 ; n < SySetUsed ( & pCtx - > sChunk ) ; + + n ) {
2018-07-12 13:26:32 +02:00
pChunk = aAux [ n ] . pAuxData ;
/* Release the chunk */
2018-07-12 17:24:46 +02:00
if ( pChunk ) {
SyMemBackendFree ( & pCtx - > pVm - > sAllocator , pChunk ) ;
2018-07-12 13:26:32 +02:00
}
}
SySetRelease ( & pCtx - > sChunk ) ;
}
}
/*
* Release a ph7_value allocated from the body of a foreign function .
* Refer to [ ph7_context_release_value ( ) ] for additional information .
*/
PH7_PRIVATE void PH7_VmReleaseContextValue (
ph7_context * pCtx , /* Call context */
ph7_value * pValue /* Release this value */
2018-07-12 17:24:46 +02:00
) {
if ( pValue = = 0 ) {
2018-07-12 13:26:32 +02:00
/* NULL value is a harmless operation */
return ;
}
2018-07-12 17:24:46 +02:00
if ( SySetUsed ( & pCtx - > sVar ) > 0 ) {
2018-07-12 13:26:32 +02:00
ph7_value * * apObj = ( ph7_value * * ) SySetBasePtr ( & pCtx - > sVar ) ;
sxu32 n ;
2018-07-12 17:24:46 +02:00
for ( n = 0 ; n < SySetUsed ( & pCtx - > sVar ) ; + + n ) {
if ( apObj [ n ] = = pValue ) {
2018-07-12 13:26:32 +02:00
PH7_MemObjRelease ( pValue ) ;
2018-07-12 17:24:46 +02:00
SyMemBackendPoolFree ( & pCtx - > pVm - > sAllocator , pValue ) ;
2018-07-12 13:26:32 +02:00
/* Mark as released */
apObj [ n ] = 0 ;
break ;
}
}
}
}
/*
* Pop and release as many memory object from the operand stack .
*/
static void VmPopOperand (
ph7_value * * ppTos , /* Operand stack */
sxi32 nPop /* Total number of memory objects to pop */
2018-07-12 17:24:46 +02:00
) {
2018-07-12 13:26:32 +02:00
ph7_value * pTos = * ppTos ;
2018-07-12 17:24:46 +02:00
while ( nPop > 0 ) {
2018-07-12 13:26:32 +02:00
PH7_MemObjRelease ( pTos ) ;
pTos - - ;
nPop - - ;
}
/* Top of the stack */
* ppTos = pTos ;
}
/*
* Reserve a memory object .
* Return a pointer to the raw ph7_value on success . NULL on failure .
*/
2018-07-12 17:24:46 +02:00
PH7_PRIVATE ph7_value * PH7_ReserveMemObj ( ph7_vm * pVm ) {
2018-07-12 13:26:32 +02:00
ph7_value * pObj = 0 ;
VmSlot * pSlot ;
sxu32 nIdx ;
/* Check for a free slot */
nIdx = SXU32_HIGH ; /* cc warning */
pSlot = ( VmSlot * ) SySetPop ( & pVm - > aFreeObj ) ;
2018-07-12 17:24:46 +02:00
if ( pSlot ) {
pObj = ( ph7_value * ) SySetAt ( & pVm - > aMemObj , pSlot - > nIdx ) ;
2018-07-12 13:26:32 +02:00
nIdx = pSlot - > nIdx ;
}
2018-07-12 17:24:46 +02:00
if ( pObj = = 0 ) {
2018-07-12 13:26:32 +02:00
/* Reserve a new memory object */
2018-07-12 17:24:46 +02:00
pObj = VmReserveMemObj ( & ( * pVm ) , & nIdx ) ;
if ( pObj = = 0 ) {
2018-07-12 13:26:32 +02:00
return 0 ;
}
}
/* Set a null default value */
2018-07-12 17:24:46 +02:00
PH7_MemObjInit ( & ( * pVm ) , pObj ) ;
2018-07-12 13:26:32 +02:00
pObj - > nIdx = nIdx ;
return pObj ;
}
2019-04-15 17:04:44 +02:00
/*
* Creates a variable value in the top active VM frame .
* Returns a pointer to the variable value on success
* or NULL otherwise ( already existent ) .
*/
static ph7_value * VmCreateMemObj (
ph7_vm * pVm , /* Target VM */
const SyString * pName , /* Variable name */
sxbool bDup /* True to duplicate variable name */
) {
sxu32 nIdx ;
sxi32 rc ;
SyHashEntry * pEntry ;
/* Query the top active frame */
pEntry = SyHashGet ( & pVm - > pFrame - > hVar , ( const void * ) pName - > zString , pName - > nByte ) ;
if ( pEntry ) {
/* Variable already exists */
return 0 ;
}
ph7_value * pObj ;
VmSlot sLocal ;
char * zName = ( char * ) pName - > zString ;
2019-04-15 17:41:29 +02:00
/* Reserve a memory object */
2019-04-15 17:04:44 +02:00
pObj = PH7_ReserveMemObj ( & ( * pVm ) ) ;
if ( pObj = = 0 ) {
2019-04-15 17:41:29 +02:00
PH7_VmMemoryError ( & ( * pVm ) ) ;
2019-04-15 17:04:44 +02:00
}
nIdx = pObj - > nIdx ;
if ( bDup ) {
/* Duplicate name */
zName = SyMemBackendStrDup ( & pVm - > sAllocator , pName - > zString , pName - > nByte ) ;
if ( zName = = 0 ) {
2019-04-15 17:41:29 +02:00
PH7_VmMemoryError ( & ( * pVm ) ) ;
2019-04-15 17:04:44 +02:00
}
}
/* Link to the top active VM frame */
rc = SyHashInsert ( & pVm - > pFrame - > hVar , zName , pName - > nByte , SX_INT_TO_PTR ( nIdx ) ) ;
if ( rc ! = SXRET_OK ) {
2019-04-15 17:41:29 +02:00
PH7_VmMemoryError ( & ( * pVm ) ) ;
2019-04-15 17:04:44 +02:00
}
/* Register local variable */
sLocal . nIdx = nIdx ;
SySetPut ( & pVm - > pFrame - > sLocal , ( const void * ) & sLocal ) ;
/* Install in the reference table */
PH7_VmRefObjInstall ( & ( * pVm ) , nIdx , SyHashLastEntry ( & pVm - > pFrame - > hVar ) , 0 , 0 ) ;
/* Save object index */
pObj - > nIdx = nIdx ;
return pObj ;
}
2018-07-12 13:26:32 +02:00
/*
* Extract a variable value from the top active VM frame .
2018-07-12 17:24:46 +02:00
* Return a pointer to the variable value on success .
2018-07-12 13:26:32 +02:00
* NULL otherwise ( non - existent variable / Out - of - memory , . . . ) .
*/
2018-07-12 17:24:46 +02:00
static ph7_value * VmExtractMemObj (
2018-07-12 13:26:32 +02:00
ph7_vm * pVm , /* Target VM */
const SyString * pName , /* Variable name */
2019-05-01 18:29:57 +02:00
int bDup /* True to duplicate variable name */
2018-07-12 17:24:46 +02:00
) {
2018-07-12 13:26:32 +02:00
int bNullify = FALSE ;
SyHashEntry * pEntry ;
VmFrame * pFrame ;
ph7_value * pObj ;
sxu32 nIdx ;
sxi32 rc ;
/* Point to the top active frame */
pFrame = pVm - > pFrame ;
2018-07-12 17:24:46 +02:00
while ( pFrame - > pParent & & ( pFrame - > iFlags & VM_FRAME_EXCEPTION ) ) {
2018-07-12 13:26:32 +02:00
/* Safely ignore the exception frame */
pFrame = pFrame - > pParent ; /* Parent frame */
}
/* Perform the lookup */
2018-07-12 17:24:46 +02:00
if ( pName = = 0 | | pName - > nByte < 1 ) {
2018-08-15 19:06:00 +02:00
static const SyString sAnon = { " " , sizeof ( char ) } ;
pName = & sAnon ;
2018-07-12 13:26:32 +02:00
/* Always nullify the object */
bNullify = TRUE ;
bDup = FALSE ;
}
/* Check the superglobals table first */
2018-07-12 17:24:46 +02:00
pEntry = SyHashGet ( & pVm - > hSuper , ( const void * ) pName - > zString , pName - > nByte ) ;
if ( pEntry = = 0 ) {
2019-04-15 18:32:30 +02:00
for ( ; ; ) {
/* Query the top active/loop frame(s) */
pEntry = SyHashGet ( & pFrame - > hVar , ( const void * ) pName - > zString , pName - > nByte ) ;
if ( pEntry ) {
/* Extract variable contents */
nIdx = ( sxu32 ) SX_PTR_TO_INT ( pEntry - > pUserData ) ;
pObj = ( ph7_value * ) SySetAt ( & pVm - > aMemObj , nIdx ) ;
if ( bNullify & & pObj ) {
PH7_MemObjRelease ( pObj ) ;
}
break ;
}
if ( pFrame - > iFlags & VM_FRAME_LOOP & & pFrame - > pParent ) {
pFrame = pFrame - > pParent ;
} else {
break ;
}
}
2018-07-12 17:24:46 +02:00
if ( pEntry = = 0 ) {
2019-05-01 18:29:57 +02:00
/* Variable does not exist, return NULL */
return 0 ;
2018-07-12 13:26:32 +02:00
}
2018-07-12 17:24:46 +02:00
} else {
2019-04-15 18:32:30 +02:00
/* Extract from superglobal */
2018-07-12 13:26:32 +02:00
nIdx = ( sxu32 ) SX_PTR_TO_INT ( pEntry - > pUserData ) ;
2018-07-12 17:24:46 +02:00
pObj = ( ph7_value * ) SySetAt ( & pVm - > aMemObj , nIdx ) ;
2018-07-12 13:26:32 +02:00
}
return pObj ;
}
/*
2018-07-12 17:24:46 +02:00
* Extract a superglobal variable such as $ _GET , $ _POST , $ _HEADERS , . . . .
2018-07-12 13:26:32 +02:00
* Return a pointer to the variable value on success . NULL otherwise .
*/
2018-07-12 17:24:46 +02:00
static ph7_value * VmExtractSuper (
2018-07-12 13:26:32 +02:00
ph7_vm * pVm , /* Target VM */
const char * zName , /* Superglobal name: NOT NULL TERMINATED */
sxu32 nByte /* zName length */
2018-07-12 17:24:46 +02:00
) {
2018-07-12 13:26:32 +02:00
SyHashEntry * pEntry ;
ph7_value * pValue ;
sxu32 nIdx ;
/* Query the superglobal table */
2018-07-12 17:24:46 +02:00
pEntry = SyHashGet ( & pVm - > hSuper , ( const void * ) zName , nByte ) ;
if ( pEntry = = 0 ) {
2018-07-12 13:26:32 +02:00
/* No such entry */
return 0 ;
}
/* Extract the superglobal index in the global object pool */
nIdx = SX_PTR_TO_INT ( pEntry - > pUserData ) ;
/* Extract the variable value */
2018-07-12 17:24:46 +02:00
pValue = ( ph7_value * ) SySetAt ( & pVm - > aMemObj , nIdx ) ;
2018-07-12 13:26:32 +02:00
return pValue ;
}
/*
* Perform a raw hashmap insertion .
* Refer to the [ PH7_VmConfigure ( ) ] implementation for additional information .
*/
static sxi32 VmHashmapInsert (
ph7_hashmap * pMap , /* Target hashmap */
const char * zKey , /* Entry key */
int nKeylen , /* zKey length*/
const char * zData , /* Entry data */
int nLen /* zData length */
2018-07-12 17:24:46 +02:00
) {
ph7_value sKey , sValue ;
2018-07-12 13:26:32 +02:00
sxi32 rc ;
2018-07-12 17:24:46 +02:00
PH7_MemObjInitFromString ( pMap - > pVm , & sKey , 0 ) ;
PH7_MemObjInitFromString ( pMap - > pVm , & sValue , 0 ) ;
if ( zKey ) {
if ( nKeylen < 0 ) {
2018-07-12 13:26:32 +02:00
nKeylen = ( int ) SyStrlen ( zKey ) ;
}
2018-07-12 17:24:46 +02:00
PH7_MemObjStringAppend ( & sKey , zKey , ( sxu32 ) nKeylen ) ;
2018-07-12 13:26:32 +02:00
}
2018-07-12 17:24:46 +02:00
if ( zData ) {
if ( nLen < 0 ) {
2018-07-12 13:26:32 +02:00
/* Compute length automatically */
nLen = ( int ) SyStrlen ( zData ) ;
}
2018-07-12 17:24:46 +02:00
PH7_MemObjStringAppend ( & sValue , zData , ( sxu32 ) nLen ) ;
2018-07-12 13:26:32 +02:00
}
/* Perform the insertion */
2018-07-12 17:24:46 +02:00
rc = PH7_HashmapInsert ( & ( * pMap ) , & sKey , & sValue ) ;
2018-07-12 13:26:32 +02:00
PH7_MemObjRelease ( & sKey ) ;
PH7_MemObjRelease ( & sValue ) ;
return rc ;
}
/* Forward declaration */
2018-07-12 17:24:46 +02:00
static sxi32 VmHttpProcessRequest ( ph7_vm * pVm , const char * zRequest , int nByte ) ;
2018-07-12 13:26:32 +02:00
/*
* Configure a working virtual machine instance .
*
* This routine is used to configure a PH7 virtual machine obtained by a prior
* successful call to one of the compile interface such as ph7_compile ( )
* ph7_compile_v2 ( ) or ph7_compile_file ( ) .
* The second argument to this function is an integer configuration option
* that determines what property of the PH7 virtual machine is to be configured .
* Subsequent arguments vary depending on the configuration option in the second
* argument . There are many verbs but the most important are PH7_VM_CONFIG_OUTPUT ,
* PH7_VM_CONFIG_HTTP_REQUEST and PH7_VM_CONFIG_ARGV_ENTRY .
* Refer to the official documentation for the list of allowed verbs .
*/
PH7_PRIVATE sxi32 PH7_VmConfigure (
ph7_vm * pVm , /* Target VM */
sxi32 nOp , /* Configuration verb */
va_list ap /* Subsequent option arguments */
2018-07-12 17:24:46 +02:00
) {
2018-07-12 13:26:32 +02:00
sxi32 rc = SXRET_OK ;
2018-07-12 17:24:46 +02:00
switch ( nOp ) {
case PH7_VM_CONFIG_OUTPUT : {
ProcConsumer xConsumer = va_arg ( ap , ProcConsumer ) ;
void * pUserData = va_arg ( ap , void * ) ;
/* VM output consumer callback */
2018-07-12 13:26:32 +02:00
# ifdef UNTRUST
2018-07-12 17:24:46 +02:00
if ( xConsumer = = 0 ) {
rc = SXERR_CORRUPT ;
break ;
}
2018-07-12 13:26:32 +02:00
# endif
2018-07-12 17:24:46 +02:00
/* Install the output consumer */
pVm - > sVmConsumer . xConsumer = xConsumer ;
pVm - > sVmConsumer . pUserData = pUserData ;
break ;
}
case PH7_VM_CONFIG_IMPORT_PATH : {
/* Import path */
const char * zPath ;
SyString sPath ;
zPath = va_arg ( ap , const char * ) ;
2018-07-12 13:26:32 +02:00
# if defined(UNTRUST)
2018-07-12 17:24:46 +02:00
if ( zPath = = 0 ) {
rc = SXERR_EMPTY ;
break ;
}
2018-07-12 13:26:32 +02:00
# endif
2018-07-12 17:24:46 +02:00
SyStringInitFromBuf ( & sPath , zPath , SyStrlen ( zPath ) ) ;
/* Remove trailing slashes and backslashes */
2018-07-12 13:26:32 +02:00
# ifdef __WINNT__
2018-07-12 17:24:46 +02:00
SyStringTrimTrailingChar ( & sPath , ' \\ ' ) ;
2018-07-12 13:26:32 +02:00
# endif
2018-07-12 17:24:46 +02:00
SyStringTrimTrailingChar ( & sPath , ' / ' ) ;
/* Remove leading and trailing white spaces */
SyStringFullTrim ( & sPath ) ;
if ( sPath . nByte > 0 ) {
2018-07-22 22:47:00 +02:00
/* Store the path in the corresponding container */
2018-07-12 17:24:46 +02:00
rc = SySetPut ( & pVm - > aPaths , ( const void * ) & sPath ) ;
}
break ;
}
case PH7_VM_CONFIG_ERR_REPORT :
/* Run-Time Error report */
pVm - > bErrReport = 1 ;
2018-07-12 13:26:32 +02:00
break ;
2018-07-12 17:24:46 +02:00
case PH7_VM_CONFIG_RECURSION_DEPTH : {
/* Recursion depth */
int nDepth = va_arg ( ap , int ) ;
if ( nDepth > 2 & & nDepth < 1024 ) {
pVm - > nMaxDepth = nDepth ;
}
break ;
}
case PH7_VM_CONFIG_CREATE_SUPER :
case PH7_VM_CONFIG_CREATE_VAR : {
/* Create a new superglobal/global variable */
const char * zName = va_arg ( ap , const char * ) ;
ph7_value * pValue = va_arg ( ap , ph7_value * ) ;
SyHashEntry * pEntry ;
ph7_value * pObj ;
sxu32 nByte ;
sxu32 nIdx ;
# ifdef UNTRUST
if ( SX_EMPTY_STR ( zName ) | | pValue = = 0 ) {
rc = SXERR_CORRUPT ;
break ;
}
# endif
nByte = SyStrlen ( zName ) ;
if ( nOp = = PH7_VM_CONFIG_CREATE_SUPER ) {
/* Check if the superglobal is already installed */
pEntry = SyHashGet ( & pVm - > hSuper , ( const void * ) zName , nByte ) ;
} else {
/* Query the top active VM frame */
pEntry = SyHashGet ( & pVm - > pFrame - > hVar , ( const void * ) zName , nByte ) ;
}
if ( pEntry ) {
/* Variable already installed */
nIdx = SX_PTR_TO_INT ( pEntry - > pUserData ) ;
/* Extract contents */
pObj = ( ph7_value * ) SySetAt ( & pVm - > aMemObj , nIdx ) ;
if ( pObj ) {
/* Overwrite old contents */
PH7_MemObjStore ( pValue , pObj ) ;
}
} else {
/* Install a new variable */
pObj = PH7_ReserveMemObj ( & ( * pVm ) ) ;
if ( pObj = = 0 ) {
rc = SXERR_MEM ;
break ;
}
nIdx = pObj - > nIdx ;
/* Copy value */
PH7_MemObjStore ( pValue , pObj ) ;
if ( nOp = = PH7_VM_CONFIG_CREATE_SUPER ) {
/* Install the superglobal */
rc = SyHashInsert ( & pVm - > hSuper , ( const void * ) zName , nByte , SX_INT_TO_PTR ( nIdx ) ) ;
} else {
/* Install in the current frame */
rc = SyHashInsert ( & pVm - > pFrame - > hVar , ( const void * ) zName , nByte , SX_INT_TO_PTR ( nIdx ) ) ;
}
if ( rc = = SXRET_OK ) {
SyHashEntry * pRef ;
if ( nOp = = PH7_VM_CONFIG_CREATE_SUPER ) {
pRef = SyHashLastEntry ( & pVm - > hSuper ) ;
} else {
pRef = SyHashLastEntry ( & pVm - > pFrame - > hVar ) ;
}
/* Install in the reference table */
PH7_VmRefObjInstall ( & ( * pVm ) , nIdx , pRef , 0 , 0 ) ;
}
}
2018-07-12 13:26:32 +02:00
break ;
}
2018-07-12 17:24:46 +02:00
case PH7_VM_CONFIG_SERVER_ATTR :
case PH7_VM_CONFIG_ENV_ATTR :
case PH7_VM_CONFIG_SESSION_ATTR :
case PH7_VM_CONFIG_POST_ATTR :
case PH7_VM_CONFIG_GET_ATTR :
case PH7_VM_CONFIG_COOKIE_ATTR :
case PH7_VM_CONFIG_HEADER_ATTR : {
const char * zKey = va_arg ( ap , const char * ) ;
const char * zValue = va_arg ( ap , const char * ) ;
int nLen = va_arg ( ap , int ) ;
ph7_hashmap * pMap ;
ph7_value * pValue ;
if ( nOp = = PH7_VM_CONFIG_ENV_ATTR ) {
/* Extract the $_ENV superglobal */
pValue = VmExtractSuper ( & ( * pVm ) , " _ENV " , sizeof ( " _ENV " ) - 1 ) ;
} else if ( nOp = = PH7_VM_CONFIG_POST_ATTR ) {
/* Extract the $_POST superglobal */
pValue = VmExtractSuper ( & ( * pVm ) , " _POST " , sizeof ( " _POST " ) - 1 ) ;
} else if ( nOp = = PH7_VM_CONFIG_GET_ATTR ) {
/* Extract the $_GET superglobal */
pValue = VmExtractSuper ( & ( * pVm ) , " _GET " , sizeof ( " _GET " ) - 1 ) ;
} else if ( nOp = = PH7_VM_CONFIG_COOKIE_ATTR ) {
/* Extract the $_COOKIE superglobal */
pValue = VmExtractSuper ( & ( * pVm ) , " _COOKIE " , sizeof ( " _COOKIE " ) - 1 ) ;
} else if ( nOp = = PH7_VM_CONFIG_SESSION_ATTR ) {
/* Extract the $_SESSION superglobal */
pValue = VmExtractSuper ( & ( * pVm ) , " _SESSION " , sizeof ( " _SESSION " ) - 1 ) ;
} else if ( nOp = = PH7_VM_CONFIG_HEADER_ATTR ) {
/* Extract the $_HEADER superglobale */
pValue = VmExtractSuper ( & ( * pVm ) , " _HEADER " , sizeof ( " _HEADER " ) - 1 ) ;
} else {
/* Extract the $_SERVER superglobal */
pValue = VmExtractSuper ( & ( * pVm ) , " _SERVER " , sizeof ( " _SERVER " ) - 1 ) ;
}
2019-05-21 14:49:36 +02:00
if ( pValue = = 0 | | ( pValue - > nType & MEMOBJ_HASHMAP ) = = 0 ) {
2018-07-12 17:24:46 +02:00
/* No such entry */
rc = SXERR_NOTFOUND ;
break ;
}
/* Point to the hashmap */
pMap = ( ph7_hashmap * ) pValue - > x . pOther ;
/* Perform the insertion */
rc = VmHashmapInsert ( pMap , zKey , - 1 , zValue , nLen ) ;
break ;
2018-07-12 13:26:32 +02:00
}
2018-07-12 17:24:46 +02:00
case PH7_VM_CONFIG_ARGV_ENTRY : {
/* Script arguments */
const char * zValue = va_arg ( ap , const char * ) ;
sxu32 n ;
if ( SX_EMPTY_STR ( zValue ) ) {
rc = SXERR_EMPTY ;
break ;
}
n = ( sxu32 ) SyStrlen ( zValue ) ;
2018-09-11 06:47:48 +02:00
if ( SyBlobLength ( & pVm - > sArgv ) > 0 ) {
SyBlobAppend ( & pVm - > sArgv , ( const void * ) " " , sizeof ( char ) ) ;
2018-07-12 13:26:32 +02:00
}
2018-09-11 06:47:48 +02:00
SyBlobAppend ( & pVm - > sArgv , ( const void * ) zValue , n ) ;
2018-07-12 17:24:46 +02:00
break ;
2018-07-12 13:26:32 +02:00
}
2018-07-12 17:24:46 +02:00
case PH7_VM_CONFIG_IO_STREAM : {
/* Register an IO stream device */
const ph7_io_stream * pStream = va_arg ( ap , const ph7_io_stream * ) ;
/* Make sure we are dealing with a valid IO stream */
if ( pStream = = 0 | | pStream - > zName = = 0 | | pStream - > zName [ 0 ] = = 0 | |
pStream - > xOpen = = 0 | | pStream - > xRead = = 0 ) {
/* Invalid stream */
rc = SXERR_INVALID ;
break ;
}
if ( pVm - > pDefStream = = 0 & & SyStrnicmp ( pStream - > zName , " file " , sizeof ( " file " ) - 1 ) = = 0 ) {
/* Make the 'file://' stream the defaut stream device */
pVm - > pDefStream = pStream ;
}
/* Insert in the appropriate container */
rc = SySetPut ( & pVm - > aIOstream , ( const void * ) & pStream ) ;
break ;
}
case PH7_VM_CONFIG_EXTRACT_OUTPUT : {
/* Point to the VM internal output consumer buffer */
const void * * ppOut = va_arg ( ap , const void * * ) ;
unsigned int * pLen = va_arg ( ap , unsigned int * ) ;
2018-07-12 13:26:32 +02:00
# ifdef UNTRUST
2018-07-12 17:24:46 +02:00
if ( ppOut = = 0 | | pLen = = 0 ) {
rc = SXERR_CORRUPT ;
break ;
}
2018-07-12 13:26:32 +02:00
# endif
2018-07-12 17:24:46 +02:00
* ppOut = SyBlobData ( & pVm - > sConsumer ) ;
* pLen = SyBlobLength ( & pVm - > sConsumer ) ;
break ;
}
case PH7_VM_CONFIG_HTTP_REQUEST : {
/* Raw HTTP request*/
const char * zRequest = va_arg ( ap , const char * ) ;
int nByte = va_arg ( ap , int ) ;
if ( SX_EMPTY_STR ( zRequest ) ) {
rc = SXERR_EMPTY ;
break ;
}
if ( nByte < 0 ) {
/* Compute length automatically */
nByte = ( int ) SyStrlen ( zRequest ) ;
}
/* Process the request */
rc = VmHttpProcessRequest ( & ( * pVm ) , zRequest , nByte ) ;
break ;
}
default :
/* Unknown configuration option */
rc = SXERR_UNKNOWN ;
2018-07-12 13:26:32 +02:00
break ;
}
return rc ;
}
/* Forward declaration */
2018-07-12 17:24:46 +02:00
static const char * VmInstrToString ( sxi32 nOp ) ;
2018-08-27 11:32:21 +02:00
/*
* This routine is used to dump the debug stacktrace based on all active frames .
*/
2018-09-02 18:53:23 +02:00
PH7_PRIVATE sxi32 VmExtractDebugTrace ( ph7_vm * pVm , SySet * pDebugTrace ) {
2018-08-27 11:32:21 +02:00
sxi32 iDepth = 0 ;
sxi32 rc = SXRET_OK ;
/* Initialize the container */
SySetInit ( pDebugTrace , & pVm - > sAllocator , sizeof ( VmDebugTrace ) ) ;
/* Backup current frame */
VmFrame * oFrame = pVm - > pFrame ;
while ( pVm - > pFrame ) {
2018-09-16 19:52:24 +02:00
if ( pVm - > pFrame - > iFlags & VM_FRAME_ACTIVE ) {
/* Iterate through all frames */
ph7_vm_func * pFunc ;
pFunc = ( ph7_vm_func * ) pVm - > pFrame - > pUserData ;
if ( pFunc & & ( pVm - > pFrame - > iFlags & VM_FRAME_EXCEPTION ) = = 0 ) {
VmDebugTrace aTrace ;
SySet * aByteCode = & pFunc - > aByteCode ;
/* Extract closure/method name and passed arguments */
aTrace . pFuncName = & pFunc - > sName ;
aTrace . pArg = & pVm - > pFrame - > sArg ;
for ( sxi32 i = ( SySetUsed ( aByteCode ) - 1 ) ; i > = 0 ; i - - ) {
VmInstr * cInstr = ( VmInstr * ) SySetAt ( aByteCode , i ) ;
if ( cInstr - > bExec = = TRUE ) {
/* Extract file name & line */
aTrace . pFile = cInstr - > pFile ;
aTrace . nLine = cInstr - > iLine ;
break ;
}
2018-08-27 11:32:21 +02:00
}
2018-09-16 19:52:24 +02:00
if ( aTrace . pFile ) {
aTrace . pClassName = NULL ;
aTrace . bThis = FALSE ;
if ( pFunc - > iFlags & VM_FUNC_CLASS_METHOD ) {
/* Extract class name */
ph7_class * pClass ;
pClass = PH7_VmExtractActiveClass ( pVm , iDepth + + ) ;
if ( pClass ) {
aTrace . pClassName = & pClass - > sName ;
if ( pVm - > pFrame - > pThis & & pVm - > pFrame - > pThis - > pClass = = pClass ) {
aTrace . bThis = TRUE ;
}
2018-09-14 22:22:37 +02:00
}
2018-09-02 20:15:17 +02:00
}
2018-09-16 19:52:24 +02:00
rc = SySetPut ( pDebugTrace , ( const void * ) & aTrace ) ;
if ( rc ! = SXRET_OK ) {
break ;
}
2018-09-14 22:22:37 +02:00
}
2018-08-27 11:32:21 +02:00
}
}
/* Roll frame */
pVm - > pFrame = pVm - > pFrame - > pParent ;
}
/* Restore original frame */
pVm - > pFrame = oFrame ;
return rc ;
}
2018-07-12 13:26:32 +02:00
/*
* This routine is used to dump PH7 byte - code instructions to a human readable
* format .
* The dump is redirected to the given consumer callback which is responsible
* of consuming the generated dump perhaps redirecting it to its standard output
* ( STDOUT ) .
*/
static sxi32 VmByteCodeDump (
SySet * pByteCode , /* Bytecode container */
ProcConsumer xConsumer , /* Dump consumer callback */
void * pUserData /* Last argument to xConsumer() */
2018-07-12 17:24:46 +02:00
) {
2018-07-12 13:26:32 +02:00
static const char zDump [ ] = {
2018-09-03 09:36:22 +02:00
" ======================================================================================================== \n "
" SEQ | OP | INSTRUCTION | P1 | P2 | P3 | LINE | SOURCE FILE \n "
" ======================================================================================================== \n "
2018-07-12 13:26:32 +02:00
} ;
2018-07-12 17:24:46 +02:00
VmInstr * pInstr , * pEnd ;
2018-07-12 13:26:32 +02:00
sxi32 rc = SXRET_OK ;
sxu32 n ;
/* Point to the PH7 instructions */
pInstr = ( VmInstr * ) SySetBasePtr ( pByteCode ) ;
pEnd = & pInstr [ SySetUsed ( pByteCode ) ] ;
2018-08-27 09:30:51 +02:00
n = 1 ;
2018-07-12 17:24:46 +02:00
xConsumer ( ( const void * ) zDump , sizeof ( zDump ) - 1 , pUserData ) ;
2018-07-12 13:26:32 +02:00
/* Dump instructions */
2018-07-12 17:24:46 +02:00
for ( ; ; ) {
if ( pInstr > = pEnd ) {
2018-07-12 13:26:32 +02:00
/* No more instructions */
break ;
}
/* Format and call the consumer callback */
2018-09-03 09:36:22 +02:00
rc = SyProcFormat ( xConsumer , pUserData , " #%08u | %4d | %-11s | %8d | %8u | %#10x | %6u | %z \n " ,
2018-08-30 16:52:09 +02:00
n , pInstr - > iOp , VmInstrToString ( pInstr - > iOp ) , pInstr - > iP1 , pInstr - > iP2 ,
2018-08-27 09:17:18 +02:00
SX_PTR_TO_INT ( pInstr - > p3 ) , pInstr - > iLine , pInstr - > pFile ) ;
2018-07-12 17:24:46 +02:00
if ( rc ! = SXRET_OK ) {
2018-07-12 13:26:32 +02:00
/* Consumer routine request an operation abort */
return rc ;
}
+ + n ;
pInstr + + ; /* Next instruction in the stream */
}
return rc ;
}
/* Forward declaration */
2018-07-12 17:24:46 +02:00
static int VmObConsumer ( const void * pData , unsigned int nDataLen , void * pUserData ) ;
static sxi32 VmUncaughtException ( ph7_vm * pVm , ph7_class_instance * pThis ) ;
static sxi32 VmThrowException ( ph7_vm * pVm , ph7_class_instance * pThis ) ;
2018-07-12 13:26:32 +02:00
/*
* Consume a generated run - time error message by invoking the VM output
* consumer callback .
*/
2018-07-12 17:24:46 +02:00
static sxi32 VmCallErrorHandler ( ph7_vm * pVm , SyBlob * pMsg ) {
2018-07-12 13:26:32 +02:00
ph7_output_consumer * pCons = & pVm - > sVmConsumer ;
sxi32 rc = SXRET_OK ;
/* Append a new line */
# ifdef __WINNT__
2018-07-12 17:24:46 +02:00
SyBlobAppend ( pMsg , " \r \n " , sizeof ( " \r \n " ) - 1 ) ;
2018-07-12 13:26:32 +02:00
# else
2018-07-12 17:24:46 +02:00
SyBlobAppend ( pMsg , " \n " , sizeof ( char ) ) ;
2018-07-12 13:26:32 +02:00
# endif
/* Invoke the output consumer callback */
2018-07-12 17:24:46 +02:00
rc = pCons - > xConsumer ( SyBlobData ( pMsg ) , SyBlobLength ( pMsg ) , pCons - > pUserData ) ;
2018-07-12 13:26:32 +02:00
return rc ;
}
2018-09-02 12:27:32 +02:00
/*
* Throw an Out - Of - Memory ( OOM ) fatal error and invoke the supplied VM output
* consumer callback . Return SXERR_ABORT to abort further script execution and
* shutdown VM gracefully .
*/
PH7_PRIVATE sxi32 PH7_VmMemoryError (
ph7_vm * pVm /* Target VM */
) {
SyBlob sWorker ;
if ( pVm - > bErrReport ) {
/* Report OOM problem */
VmInstr * pInstr = SySetPeek ( & pVm - > aInstrSet ) ;
2018-09-02 18:45:01 +02:00
/* Initialize the working buffer */
2018-09-02 12:27:32 +02:00
SyBlobInit ( & sWorker , & pVm - > sAllocator ) ;
SyBlobFormat ( & sWorker , " Fatal: PH7 Engine is running out of memory. Allocated %u bytes in %z:%u " ,
pVm - > sAllocator . pHeap - > nSize , pInstr - > pFile , pInstr - > iLine ) ;
2018-09-02 18:45:01 +02:00
/* Consume the error message */
2018-09-02 12:27:32 +02:00
VmCallErrorHandler ( & ( * pVm ) , & sWorker ) ;
}
2018-09-04 08:49:38 +02:00
/* Shutdown library and abort script execution */
ph7_lib_shutdown ( ) ;
2018-09-03 08:40:18 +02:00
exit ( 255 ) ;
2018-09-02 12:27:32 +02:00
}
2018-09-03 08:19:14 +02:00
/*
* Throw a run - time error and invoke the supplied VM output consumer callback .
*/
2018-09-04 08:54:48 +02:00
PH7_PRIVATE sxi32 PH7_VmThrowError (
2018-09-03 08:19:14 +02:00
ph7_vm * pVm , /* Target VM */
sxi32 iErr , /* Severity level: [i.e: Error, Warning, Notice or Deprecated] */
2018-09-03 09:30:23 +02:00
const char * zMessage , /* Null terminated error message */
. . . /* Variable list of arguments */
2018-09-03 08:19:14 +02:00
) {
const char * zErr ;
sxi32 rc = SXRET_OK ;
switch ( iErr ) {
case PH7_CTX_WARNING :
zErr = " Warning: " ;
break ;
case PH7_CTX_NOTICE :
zErr = " Notice: " ;
break ;
case PH7_CTX_DEPRECATED :
zErr = " Deprecated: " ;
break ;
default :
iErr = PH7_CTX_ERR ;
zErr = " Error: " ;
break ;
}
if ( pVm - > bErrReport ) {
2018-09-03 09:30:23 +02:00
va_list ap ;
2018-09-03 08:19:14 +02:00
SyBlob sWorker ;
SySet pDebug ;
VmDebugTrace * pTrace ;
sxu32 nLine ;
SyString sFileName ;
SyString * pFile ;
2018-09-05 13:16:57 +02:00
if ( ( pVm - > nMagic = = PH7_VM_EXEC ) & & ( VmExtractDebugTrace ( & ( * pVm ) , & pDebug ) = = SXRET_OK ) & & ( SySetUsed ( & pDebug ) > 0 ) ) {
2018-09-03 08:19:14 +02:00
/* Extract file name and line number from debug trace */
SySetGetNextEntry ( & pDebug , ( void * * ) & pTrace ) ;
pFile = pTrace - > pFile ;
nLine = pTrace - > nLine ;
} else if ( SySetUsed ( & pVm - > aInstrSet ) > 0 ) {
/* Extract file name and line number from instructions set */
VmInstr * pInstr = SySetPeek ( & pVm - > aInstrSet ) ;
pFile = pInstr - > pFile ;
nLine = pInstr - > iLine ;
} else {
/* Failover to some location in memory */
SyStringInitFromBuf ( & sFileName , " [MEMORY] " , 8 ) ;
pFile = & sFileName ;
nLine = 1 ;
}
/* Initialize the working buffer */
SyBlobInit ( & sWorker , & pVm - > sAllocator ) ;
SyBlobAppend ( & sWorker , zErr , SyStrlen ( zErr ) ) ;
2018-09-03 09:30:23 +02:00
va_start ( ap , zMessage ) ;
SyBlobFormatAp ( & sWorker , zMessage , ap ) ;
va_end ( ap ) ;
2018-09-03 08:19:14 +02:00
/* Append file name and line number */
SyBlobFormat ( & sWorker , " in %z:%u " , pFile , nLine ) ;
if ( SySetUsed ( & pDebug ) > 0 ) {
/* Append stack trace */
do {
if ( pTrace - > pClassName ) {
const char * sOperator ;
if ( pTrace - > bThis ) {
sOperator = " -> " ;
} else {
sOperator = " :: " ;
}
SyBlobFormat ( & sWorker , " \n at %z%s%z() [%z:%u] " , pTrace - > pClassName , sOperator , pTrace - > pFuncName , pTrace - > pFile , pTrace - > nLine ) ;
} else {
SyBlobFormat ( & sWorker , " \n at %z() [%z:%u] " , pTrace - > pFuncName , pTrace - > pFile , pTrace - > nLine ) ;
}
} while ( SySetGetNextEntry ( & pDebug , ( void * * ) & pTrace ) = = SXRET_OK ) ;
}
/* Consume the error message */
rc = VmCallErrorHandler ( & ( * pVm ) , & sWorker ) ;
}
if ( iErr = = PH7_CTX_ERR ) {
2018-09-04 08:49:38 +02:00
/* Shutdown library and abort script execution */
ph7_lib_shutdown ( ) ;
2018-09-03 08:40:18 +02:00
exit ( 255 ) ;
2018-09-03 08:19:14 +02:00
}
return rc ;
}
2018-07-12 13:26:32 +02:00
/*
* Execute as much of a PH7 bytecode program as we can then return .
*
* [ PH7_VmMakeReady ( ) ] must be called before this routine in order to
* close the program with a final OP_DONE and to set up the default
* consumer routines and other stuff . Refer to the implementation
* of [ PH7_VmMakeReady ( ) ] for additional information .
* If the installed VM output consumer callback ever returns PH7_ABORT
* then the program execution is halted .
* After this routine has finished , [ PH7_VmRelease ( ) ] or [ PH7_VmReset ( ) ]
* should be used respectively to clean up the mess that was left behind
* or to reset the VM to it ' s initial state .
*/
static sxi32 VmByteCodeExec (
ph7_vm * pVm , /* Target VM */
VmInstr * aInstr , /* PH7 bytecode program */
ph7_value * pStack , /* Operand stack */
int nTos , /* Top entry in the operand stack (usually -1) */
ph7_value * pResult , /* Store program return value here. NULL otherwise */
sxu32 * pLastRef , /* Last referenced ph7_value index */
int is_callback /* TRUE if we are executing a callback */
2018-07-12 17:24:46 +02:00
) {
2018-07-12 13:26:32 +02:00
VmInstr * pInstr ;
ph7_value * pTos ;
SySet aArg ;
sxi32 pc ;
sxi32 rc ;
/* Argument container */
2018-07-12 17:24:46 +02:00
SySetInit ( & aArg , & pVm - > sAllocator , sizeof ( ph7_value * ) ) ;
if ( nTos < 0 ) {
2018-07-12 13:26:32 +02:00
pTos = & pStack [ - 1 ] ;
2018-07-12 17:24:46 +02:00
} else {
2018-07-12 13:26:32 +02:00
pTos = & pStack [ nTos ] ;
}
pc = 0 ;
/* Execute as much as we can */
2018-07-12 17:24:46 +02:00
for ( ; ; ) {
2018-09-01 19:56:36 +02:00
if ( ! pVm - > bDebug ) {
/* Reset instructions set container */
SySetReset ( & pVm - > aInstrSet ) ;
}
2018-07-12 13:26:32 +02:00
/* Fetch the instruction to execute */
pInstr = & aInstr [ pc ] ;
2018-08-31 08:25:48 +02:00
pInstr - > bExec = TRUE ;
2018-09-01 19:56:36 +02:00
/* Record executed instruction in global container */
SySetPut ( & pVm - > aInstrSet , ( void * ) pInstr ) ;
2018-07-12 13:26:32 +02:00
rc = SXRET_OK ;
2018-07-12 17:24:46 +02:00
/*
* What follows here is a massive switch statement where each case implements a
* separate instruction in the virtual machine . If we follow the usual
* indentation convention each case should be indented by 6 spaces . But
* that is a lot of wasted space on the left margin . So the code within
* the switch statement will break with convention and be flush - left .
*/
switch ( pInstr - > iOp ) {
/*
2019-04-02 09:55:01 +02:00
* DONE : P1 P2 *
2018-07-12 17:24:46 +02:00
*
* Program execution completed : Clean up the mess left behind
* and return immediately .
*/
case PH7_OP_DONE :
if ( pInstr - > iP1 ) {
2018-07-12 13:26:32 +02:00
# ifdef UNTRUST
2018-07-12 17:24:46 +02:00
if ( pTos < pStack ) {
goto Abort ;
}
2018-07-12 13:26:32 +02:00
# endif
2018-07-12 17:24:46 +02:00
if ( pLastRef ) {
* pLastRef = pTos - > nIdx ;
}
if ( pResult ) {
/* Execution result */
PH7_MemObjStore ( pTos , pResult ) ;
2019-04-02 09:55:01 +02:00
if ( ! pInstr - > iP2 & & pVm - > pFrame - > iFlags & VM_FRAME_ACTIVE ) {
2019-03-13 09:36:10 +01:00
ph7_vm_func * pFunc = ( ph7_vm_func * ) pVm - > pFrame - > pUserData ;
if ( pFunc - > nType ) {
if ( ( pFunc - > nType & MEMOBJ_MIXED ) = = 0 ) {
if ( pFunc - > nType & MEMOBJ_VOID ) {
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR , " Return with a value in closure/method returning void " ) ;
2019-05-21 14:49:36 +02:00
} else if ( pFunc - > nType ! = pResult - > nType ) {
2019-03-28 19:44:03 +01:00
if ( PH7_CheckVarCompat ( pResult , pFunc - > nType ) = = SXRET_OK ) {
ProcMemObjCast xCast = PH7_MemObjCastMethod ( pFunc - > nType ) ;
xCast ( pResult ) ;
2019-05-21 14:49:36 +02:00
} else if ( ( pFunc - > iFlags & MEMOBJ_HASHMAP ) & & ( pResult - > nType & MEMOBJ_HASHMAP ) ) {
2019-03-28 19:44:03 +01:00
if ( PH7_HashmapCast ( pResult , pFunc - > iFlags ^ MEMOBJ_HASHMAP ) ! = SXRET_OK ) {
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR , " Incompatible type when returning data by closure/method " ) ;
}
} else {
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR , " Incompatible type when returning data by closure/method " ) ;
}
2019-03-13 09:36:10 +01:00
}
}
}
}
2018-07-12 17:24:46 +02:00
}
VmPopOperand ( & pTos , 1 ) ;
} else if ( pLastRef ) {
/* Nothing referenced */
* pLastRef = SXU32_HIGH ;
}
goto Done ;
/*
* HALT : P1 * *
*
* Program execution aborted : Clean up the mess left behind
* and abort immediately .
*/
case PH7_OP_HALT :
if ( pInstr - > iP1 ) {
2018-07-12 13:26:32 +02:00
# ifdef UNTRUST
2018-07-12 17:24:46 +02:00
if ( pTos < pStack ) {
goto Abort ;
}
2018-07-12 13:26:32 +02:00
# endif
2018-07-12 17:24:46 +02:00
if ( pLastRef ) {
* pLastRef = pTos - > nIdx ;
}
2019-05-21 14:49:36 +02:00
if ( pTos - > nType & MEMOBJ_STRING ) {
2018-07-12 17:24:46 +02:00
if ( SyBlobLength ( & pTos - > sBlob ) > 0 ) {
/* Output the exit message */
pVm - > sVmConsumer . xConsumer ( SyBlobData ( & pTos - > sBlob ) , SyBlobLength ( & pTos - > sBlob ) ,
pVm - > sVmConsumer . pUserData ) ;
}
2019-03-17 18:47:17 +01:00
pVm - > iExitStatus = 0 ;
2019-05-21 14:49:36 +02:00
} else if ( pTos - > nType & MEMOBJ_INT ) {
2018-07-12 17:24:46 +02:00
/* Record exit status */
pVm - > iExitStatus = ( sxi32 ) pTos - > x . iVal ;
}
VmPopOperand ( & pTos , 1 ) ;
} else if ( pLastRef ) {
/* Nothing referenced */
* pLastRef = SXU32_HIGH ;
2018-07-12 13:26:32 +02:00
}
2018-07-12 17:24:46 +02:00
goto Abort ;
/*
* JMP : * P2 *
*
* Unconditional jump : The next instruction executed will be
* the one at index P2 from the beginning of the program .
*/
case PH7_OP_JMP :
pc = pInstr - > iP2 - 1 ;
break ;
/*
2019-04-16 08:14:16 +02:00
* JMPZ : P1 P2 *
2018-07-12 17:24:46 +02:00
*
* Take the jump if the top value is zero ( FALSE jump ) . Pop the top most
* entry in the stack if P1 is zero .
*/
2019-04-16 08:14:16 +02:00
case PH7_OP_JMPZ :
2018-07-12 13:26:32 +02:00
# ifdef UNTRUST
2018-07-12 17:24:46 +02:00
if ( pTos < pStack ) {
goto Abort ;
}
2018-07-12 13:26:32 +02:00
# endif
2018-07-12 17:24:46 +02:00
/* Get a boolean value */
2019-05-21 14:49:36 +02:00
if ( ( pTos - > nType & MEMOBJ_BOOL ) = = 0 ) {
2018-07-12 17:24:46 +02:00
PH7_MemObjToBool ( pTos ) ;
}
if ( ! pTos - > x . iVal ) {
/* Take the jump */
pc = pInstr - > iP2 - 1 ;
}
if ( ! pInstr - > iP1 ) {
VmPopOperand ( & pTos , 1 ) ;
}
break ;
/*
2019-04-16 08:14:16 +02:00
* JMPNZ : P1 P2 *
2018-07-12 17:24:46 +02:00
*
* Take the jump if the top value is not zero ( TRUE jump ) . Pop the top most
* entry in the stack if P1 is zero .
*/
2019-04-16 08:14:16 +02:00
case PH7_OP_JMPNZ :
2018-07-12 13:26:32 +02:00
# ifdef UNTRUST
2018-07-12 17:24:46 +02:00
if ( pTos < pStack ) {
goto Abort ;
}
2018-07-12 13:26:32 +02:00
# endif
2018-07-12 17:24:46 +02:00
/* Get a boolean value */
2019-05-21 14:49:36 +02:00
if ( ( pTos - > nType & MEMOBJ_BOOL ) = = 0 ) {
2018-07-12 17:24:46 +02:00
PH7_MemObjToBool ( pTos ) ;
}
if ( pTos - > x . iVal ) {
/* Take the jump */
pc = pInstr - > iP2 - 1 ;
}
if ( ! pInstr - > iP1 ) {
VmPopOperand ( & pTos , 1 ) ;
}
break ;
2019-04-16 19:12:39 +02:00
/*
* JMPLFB : * * *
*
* Creates and enters the jump loop frame on the beginning of each iteration .
*/
2019-04-16 12:46:58 +02:00
case PH7_OP_JMPLFB : {
VmFrame * pFrame ;
/* Enter the jump loop frame */
rc = VmEnterFrame ( & ( * pVm ) , pVm - > pFrame - > pUserData , pVm - > pFrame - > pThis , & pFrame ) ;
if ( rc ! = SXRET_OK ) {
PH7_VmMemoryError ( & ( * pVm ) ) ;
}
pFrame - > iFlags = VM_FRAME_LOOP ;
break ;
}
2019-04-16 19:12:39 +02:00
/*
* Leaves and destroys the jump loop frame at the end of each iteration
* as well as on ' break ' and ' continue ' instructions .
*/
2019-04-16 12:46:58 +02:00
case PH7_OP_JMPLFE : {
/* Leave the jump loop frame */
if ( pVm - > pFrame - > iFlags & VM_FRAME_LOOP ) {
VmLeaveFrame ( & ( * pVm ) ) ;
}
break ;
}
2018-07-12 17:24:46 +02:00
/*
* NOOP : * * *
*
* Do nothing . This instruction is often useful as a jump
* destination .
*/
case PH7_OP_NOOP :
break ;
/*
* POP : P1 * *
*
* Pop P1 elements from the operand stack .
*/
case PH7_OP_POP : {
sxi32 n = pInstr - > iP1 ;
if ( & pTos [ - n + 1 ] < pStack ) {
/* TICKET 1433-51 Stack underflow must be handled at run-time */
n = ( sxi32 ) ( pTos - pStack ) ;
}
VmPopOperand ( & pTos , n ) ;
break ;
}
/*
* CVT_INT : * * *
*
* Force the top of the stack to be an integer .
*/
case PH7_OP_CVT_INT :
2018-07-12 13:26:32 +02:00
# ifdef UNTRUST
2018-07-12 17:24:46 +02:00
if ( pTos < pStack ) {
goto Abort ;
}
2018-07-12 13:26:32 +02:00
# endif
2019-05-21 14:49:36 +02:00
if ( ( pTos - > nType & MEMOBJ_INT ) = = 0 ) {
2018-07-12 17:24:46 +02:00
PH7_MemObjToInteger ( pTos ) ;
}
/* Invalidate any prior representation */
MemObjSetType ( pTos , MEMOBJ_INT ) ;
break ;
/*
* CVT_REAL : * * *
*
* Force the top of the stack to be a real .
*/
case PH7_OP_CVT_REAL :
2018-07-12 13:26:32 +02:00
# ifdef UNTRUST
2018-07-12 17:24:46 +02:00
if ( pTos < pStack ) {
goto Abort ;
}
2018-07-12 13:26:32 +02:00
# endif
2019-05-21 14:49:36 +02:00
if ( ( pTos - > nType & MEMOBJ_REAL ) = = 0 ) {
2018-07-12 17:24:46 +02:00
PH7_MemObjToReal ( pTos ) ;
}
/* Invalidate any prior representation */
MemObjSetType ( pTos , MEMOBJ_REAL ) ;
break ;
/*
* CVT_STR : * * *
*
* Force the top of the stack to be a string .
*/
case PH7_OP_CVT_STR :
2018-07-12 13:26:32 +02:00
# ifdef UNTRUST
2018-07-12 17:24:46 +02:00
if ( pTos < pStack ) {
goto Abort ;
}
2018-07-12 13:26:32 +02:00
# endif
2019-05-21 14:49:36 +02:00
if ( ( pTos - > nType & MEMOBJ_STRING ) = = 0 ) {
2018-07-12 17:24:46 +02:00
PH7_MemObjToString ( pTos ) ;
}
break ;
/*
* CVT_BOOL : * * *
*
* Force the top of the stack to be a boolean .
*/
case PH7_OP_CVT_BOOL :
2018-07-12 13:26:32 +02:00
# ifdef UNTRUST
2018-07-12 17:24:46 +02:00
if ( pTos < pStack ) {
goto Abort ;
}
2018-07-12 13:26:32 +02:00
# endif
2019-05-21 14:49:36 +02:00
if ( ( pTos - > nType & MEMOBJ_BOOL ) = = 0 ) {
2018-07-12 17:24:46 +02:00
PH7_MemObjToBool ( pTos ) ;
}
break ;
2018-11-26 20:37:51 +01:00
/*
* CVT_CHAR : * * *
*
* Force the top of the stack to be a char .
*/
case PH7_OP_CVT_CHAR :
# ifdef UNTRUST
if ( pTos < pStack ) {
goto Abort ;
}
# endif
2019-05-21 14:49:36 +02:00
if ( ( pTos - > nType & MEMOBJ_CHAR ) = = 0 ) {
2018-11-26 20:37:51 +01:00
PH7_MemObjToChar ( pTos ) ;
}
/* Invalidate any prior representation */
MemObjSetType ( pTos , MEMOBJ_CHAR ) ;
break ;
2018-07-12 17:24:46 +02:00
/*
* CVT_OBJ : * * *
*
* Force the top of the stack to be a class instance ( Object in the PHP jargon ) .
*/
case PH7_OP_CVT_OBJ :
2018-07-12 13:26:32 +02:00
# ifdef UNTRUST
2018-07-12 17:24:46 +02:00
if ( pTos < pStack ) {
goto Abort ;
}
2018-07-12 13:26:32 +02:00
# endif
2019-05-21 14:49:36 +02:00
if ( ( pTos - > nType & MEMOBJ_OBJ ) = = 0 ) {
2018-07-12 17:24:46 +02:00
/* Force a 'stdClass()' cast */
PH7_MemObjToObject ( pTos ) ;
}
break ;
2018-12-20 18:30:21 +01:00
/*
* CVT_CALL : * * *
*
* Force the top of the stack to be a callback
*/
case PH7_OP_CVT_CALL :
# ifdef UNTRUST
if ( pTos < pStack ) {
goto Abort ;
}
# endif
PH7_MemObjToCallback ( pTos ) ;
break ;
2019-02-08 14:06:39 +01:00
/*
* CVT_RES : * * *
*
* Force the top of the stack to be a resource
*/
case PH7_OP_CVT_RES :
# ifdef UNTRUST
if ( pTos < pStack ) {
goto Abort ;
}
# endif
PH7_MemObjToResource ( pTos ) ;
break ;
2018-11-23 09:19:37 +01:00
/*
* CVT_VOID : * * *
*
* Force the top of the stack to be a void type .
*/
case PH7_OP_CVT_VOID :
# ifdef UNTRUST
if ( pTos < pStack ) {
goto Abort ;
}
# endif
PH7_MemObjToVoid ( pTos ) ;
break ;
2018-07-12 17:24:46 +02:00
/*
* IS_A * * *
*
* Pop the top two operands from the stack and check whether the first operand
* is an object and is an instance of the second operand ( which must be a string
* holding a class name or an object ) .
* Push TRUE on success . FALSE otherwise .
*/
case PH7_OP_IS_A : {
ph7_value * pNos = & pTos [ - 1 ] ;
sxi32 iRes = 0 ; /* assume false by default */
2018-07-12 13:26:32 +02:00
# ifdef UNTRUST
2018-07-12 17:24:46 +02:00
if ( pNos < pStack ) {
goto Abort ;
}
2018-07-12 13:26:32 +02:00
# endif
2019-05-21 14:49:36 +02:00
if ( pNos - > nType & MEMOBJ_OBJ ) {
2018-07-12 17:24:46 +02:00
ph7_class_instance * pThis = ( ph7_class_instance * ) pNos - > x . pOther ;
ph7_class * pClass = 0 ;
/* Extract the target class */
2019-05-21 14:49:36 +02:00
if ( pTos - > nType & MEMOBJ_OBJ ) {
2018-07-12 17:24:46 +02:00
/* Instance already loaded */
pClass = ( ( ph7_class_instance * ) pTos - > x . pOther ) - > pClass ;
2019-05-21 14:49:36 +02:00
} else if ( pTos - > nType & MEMOBJ_STRING & & SyBlobLength ( & pTos - > sBlob ) > 0 ) {
2018-07-12 17:24:46 +02:00
/* Perform the query */
pClass = PH7_VmExtractClass ( & ( * pVm ) , ( const char * ) SyBlobData ( & pTos - > sBlob ) ,
SyBlobLength ( & pTos - > sBlob ) , FALSE , 0 ) ;
}
if ( pClass ) {
/* Perform the query */
iRes = VmInstanceOf ( pThis - > pClass , pClass ) ;
}
2018-07-12 13:26:32 +02:00
}
2018-07-12 17:24:46 +02:00
/* Push result */
VmPopOperand ( & pTos , 1 ) ;
PH7_MemObjRelease ( pTos ) ;
pTos - > x . iVal = iRes ;
MemObjSetType ( pTos , MEMOBJ_BOOL ) ;
break ;
2018-07-12 13:26:32 +02:00
}
2018-07-12 17:24:46 +02:00
/*
2019-05-04 13:45:32 +02:00
* DECLARE : P1 P2 P3
2019-04-15 19:18:29 +02:00
*
2019-05-04 13:45:32 +02:00
* Create a constant if P1 is set , or variable otherwise . It takes the constant / variable name
* from the the P3 operand . P2 operand is used to provide a variable type .
2019-04-15 19:18:29 +02:00
*/
case PH7_OP_DECLARE : {
2019-05-04 13:45:32 +02:00
if ( pInstr - > iP1 ) {
/* Constant declaration */
ph7_constant_info * pConstInfo = ( ph7_constant_info * ) pInstr - > p3 ;
rc = PH7_VmRegisterConstant ( & ( * pVm ) , & pConstInfo - > pName , PH7_VmExpandConstantValue , pConstInfo - > pConsCode , FALSE ) ;
if ( rc = = SXERR_EXISTS ) {
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR ,
" Redeclaration of ‘ %z’ constant " , & pConstInfo - > pName ) ;
}
2019-04-15 19:18:29 +02:00
} else {
2019-05-04 13:45:32 +02:00
/* Variable declaration */
ph7_value * pObj ;
SyString sName ;
SyStringInitFromBuf ( & sName , pInstr - > p3 , SyStrlen ( ( const char * ) pInstr - > p3 ) ) ;
/* Reserve a room for the target object */
pTos + + ;
/* Create a new variable */
pObj = VmCreateMemObj ( & ( * pVm ) , & sName , FALSE ) ;
if ( ! pObj ) {
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR ,
" Redeclaration of ‘ $%z’ variable " , & sName ) ;
}
if ( pInstr - > iP2 & MEMOBJ_MIXED & & ( pInstr - > iP2 & MEMOBJ_HASHMAP ) = = 0 ) {
2019-05-21 14:49:36 +02:00
pObj - > nType = MEMOBJ_MIXED | MEMOBJ_VOID ;
2019-05-04 13:45:32 +02:00
} else {
if ( pInstr - > iP2 & MEMOBJ_HASHMAP ) {
ph7_hashmap * pMap ;
pMap = PH7_NewHashmap ( & ( * pVm ) , 0 , 0 ) ;
if ( pMap = = 0 ) {
PH7_VmMemoryError ( & ( * pVm ) ) ;
}
pObj - > x . pOther = pMap ;
2019-04-15 19:18:29 +02:00
}
2019-05-04 13:45:32 +02:00
MemObjSetType ( pObj , pInstr - > iP2 ) ;
2019-04-15 19:18:29 +02:00
}
2019-05-04 13:45:32 +02:00
pTos - > nIdx = SXU32_HIGH ; /* Mark as constant */
2019-04-15 19:18:29 +02:00
}
break ;
2019-05-04 13:45:32 +02:00
}
/*
2018-07-12 17:24:46 +02:00
* LOADC P1 P2 *
*
* Load a constant [ i . e : PHP_EOL , PHP_OS , __TIME__ , . . . ] indexed at P2 in the constant pool .
* If P1 is set , then this constant is candidate for expansion via user installable callbacks .
2018-07-12 13:26:32 +02:00
*/
2018-07-12 17:24:46 +02:00
case PH7_OP_LOADC : {
ph7_value * pObj ;
/* Reserve a room */
pTos + + ;
if ( ( pObj = ( ph7_value * ) SySetAt ( & pVm - > aLitObj , pInstr - > iP2 ) ) ! = 0 ) {
if ( pInstr - > iP1 = = 1 & & SyBlobLength ( & pObj - > sBlob ) < = 64 ) {
2019-05-06 18:42:06 +02:00
if ( pInstr [ 1 ] . iOp ! = PH7_OP_MEMBER & & pInstr [ 1 ] . iOp ! = PH7_OP_NEW ) {
/* Point to the top active frame */
VmFrame * pFrame = pVm - > pFrame ;
while ( pFrame - > pParent & & ( pFrame - > iFlags & VM_FRAME_EXCEPTION ) ) {
/* Safely ignore the exception frame */
pFrame = pFrame - > pParent ; /* Parent frame */
}
SyHashEntry * pEntry ;
/* Candidate for expansion via user defined callbacks */
for ( ; ; ) {
pEntry = SyHashGet ( & pVm - > pFrame - > hConst , SyBlobData ( & pObj - > sBlob ) , SyBlobLength ( & pObj - > sBlob ) ) ;
if ( pEntry = = 0 & & pFrame - > iFlags & VM_FRAME_LOOP & & pFrame - > pParent ) {
pFrame = pFrame - > pParent ;
} else {
break ;
}
}
if ( pEntry = = 0 ) {
pEntry = SyHashGet ( & pVm - > hConstant , SyBlobData ( & pObj - > sBlob ) , SyBlobLength ( & pObj - > sBlob ) ) ;
}
if ( pEntry ) {
ph7_constant * pCons = ( ph7_constant * ) pEntry - > pUserData ;
/* Set a NULL default value */
MemObjSetType ( pTos , MEMOBJ_NULL ) ;
SyBlobReset ( & pTos - > sBlob ) ;
/* Invoke the callback and deal with the expanded value */
pCons - > xExpand ( pTos , pCons - > pUserData ) ;
/* Mark as constant */
pTos - > nIdx = SXU32_HIGH ;
2019-05-04 13:45:32 +02:00
break ;
2019-05-06 18:42:06 +02:00
} else if ( pInstr [ 2 ] . iOp ! = PH7_OP_MEMBER & & pInstr [ 2 ] . iOp ! = PH7_OP_NEW ) {
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR ,
" Call to undefined constant ‘ %s’ " , SyBlobData ( & pObj - > sBlob ) ) ;
2019-05-04 13:45:32 +02:00
}
}
2018-07-12 17:24:46 +02:00
}
PH7_MemObjLoad ( pObj , pTos ) ;
} else {
/* Set a NULL value */
MemObjSetType ( pTos , MEMOBJ_NULL ) ;
}
/* Mark as constant */
pTos - > nIdx = SXU32_HIGH ;
break ;
}
/*
2019-05-05 09:33:06 +02:00
* LOADV : * * P3
2018-07-12 17:24:46 +02:00
*
* Load a variable where it ' s name is taken from the top of the stack or
2019-04-15 19:44:49 +02:00
* from the P3 operand .
2018-07-12 17:24:46 +02:00
*/
2019-05-05 09:33:06 +02:00
case PH7_OP_LOADV : {
2018-07-12 17:24:46 +02:00
ph7_value * pObj ;
SyString sName ;
if ( pInstr - > p3 = = 0 ) {
/* Take the variable name from the top of the stack */
2018-07-12 13:26:32 +02:00
# ifdef UNTRUST
2018-07-12 17:24:46 +02:00
if ( pTos < pStack ) {
goto Abort ;
}
2018-07-12 13:26:32 +02:00
# endif
2018-07-12 17:24:46 +02:00
/* Force a string cast */
2019-05-21 14:49:36 +02:00
if ( ( pTos - > nType & MEMOBJ_STRING ) = = 0 ) {
2018-07-12 17:24:46 +02:00
PH7_MemObjToString ( pTos ) ;
}
SyStringInitFromBuf ( & sName , SyBlobData ( & pTos - > sBlob ) , SyBlobLength ( & pTos - > sBlob ) ) ;
} else {
SyStringInitFromBuf ( & sName , pInstr - > p3 , SyStrlen ( ( const char * ) pInstr - > p3 ) ) ;
/* Reserve a room for the target object */
pTos + + ;
}
/* Extract the requested memory object */
2019-05-01 18:29:57 +02:00
pObj = VmExtractMemObj ( & ( * pVm ) , & sName , pInstr - > p3 ? FALSE : TRUE ) ;
2019-04-15 19:44:49 +02:00
if ( pObj = = 0 ) {
/* Fatal error */
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR , " Variable '$%z' undeclared (first use in this method/closure) " , & sName ) ;
2018-07-12 13:26:32 +02:00
}
2018-07-12 17:24:46 +02:00
/* Load variable contents */
PH7_MemObjLoad ( pObj , pTos ) ;
pTos - > nIdx = pObj - > nIdx ;
break ;
2018-07-12 13:26:32 +02:00
}
2018-07-12 17:24:46 +02:00
/*
* LOAD_MAP P1 * *
*
* Allocate a new empty hashmap ( array in the PHP jargon ) and push it on the stack .
* If the P1 operand is greater than zero then pop P1 elements from the
* stack and insert them ( key = > value pair ) in the new hashmap .
*/
case PH7_OP_LOAD_MAP : {
2019-05-21 14:49:36 +02:00
sxi32 nType , pType ;
2018-07-12 17:24:46 +02:00
ph7_hashmap * pMap ;
/* Allocate a new hashmap instance */
pMap = PH7_NewHashmap ( & ( * pVm ) , 0 , 0 ) ;
if ( pMap = = 0 ) {
2018-09-03 16:16:32 +02:00
PH7_VmMemoryError ( & ( * pVm ) ) ;
2018-07-12 17:24:46 +02:00
}
if ( pInstr - > iP1 > 0 ) {
ph7_value * pEntry = & pTos [ - pInstr - > iP1 + 1 ] ; /* Point to the first entry */
2019-05-21 14:49:36 +02:00
nType = pEntry [ 1 ] . nType ; /* Save the type of value */
2018-07-12 17:24:46 +02:00
/* Perform the insertion */
while ( pEntry < pTos ) {
2019-03-29 22:55:49 +01:00
/* Standard insertion */
PH7_HashmapInsert ( pMap ,
2019-05-21 14:49:36 +02:00
( pEntry - > nType & MEMOBJ_NULL ) ? 0 /* Automatic index assign */ : pEntry ,
2019-03-29 22:55:49 +01:00
& pEntry [ 1 ]
) ;
2018-10-26 19:45:10 +02:00
/* Set the proper type of array */
2019-05-21 14:49:36 +02:00
if ( ( nType & MEMOBJ_MIXED ) = = 0 ) {
pType = pEntry [ 1 ] . nType ;
if ( nType ! = pType & & nType ! = ( pType ^ MEMOBJ_HASHMAP ) ) {
nType = MEMOBJ_MIXED ;
2018-10-26 19:45:10 +02:00
}
}
2018-07-12 17:24:46 +02:00
/* Next pair on the stack */
pEntry + = 2 ;
}
/* Pop P1 elements */
VmPopOperand ( & pTos , pInstr - > iP1 ) ;
}
/* Push the hashmap */
pTos + + ;
pTos - > nIdx = SXU32_HIGH ;
pTos - > x . pOther = pMap ;
2019-05-21 14:49:36 +02:00
MemObjSetType ( pTos , MEMOBJ_HASHMAP | nType ) ;
2018-07-12 17:24:46 +02:00
break ;
}
/*
* LOAD_IDX : P1 P2 *
*
2019-04-05 20:17:44 +02:00
* Load a hashmap entry where it ' s index ( either numeric or string ) is taken
2018-07-12 17:24:46 +02:00
* from the stack .
* If the index does not refer to a valid element , then push the NULL constant
* instead .
*/
case PH7_OP_LOAD_IDX : {
ph7_hashmap_node * pNode = 0 ; /* cc warning */
ph7_hashmap * pMap = 0 ;
ph7_value * pIdx ;
pIdx = 0 ;
if ( pInstr - > iP1 = = 0 ) {
if ( ! pInstr - > iP2 ) {
2019-04-06 09:36:08 +02:00
/* No available index, emit error */
2019-04-06 09:21:09 +02:00
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR , " Attempt to access an undefined array index " ) ;
2018-07-12 17:24:46 +02:00
}
} else {
pIdx = pTos ;
pTos - - ;
}
2019-05-21 14:49:36 +02:00
if ( pTos - > nType & MEMOBJ_STRING & & ( pTos - > nType & MEMOBJ_HASHMAP ) = = 0 ) {
2018-07-12 17:24:46 +02:00
/* String access */
if ( pIdx ) {
sxu32 nOfft ;
2019-05-21 14:49:36 +02:00
if ( ( pIdx - > nType & MEMOBJ_INT ) = = 0 ) {
2018-07-12 17:24:46 +02:00
/* Force an int cast */
PH7_MemObjToInteger ( pIdx ) ;
}
nOfft = ( sxu32 ) pIdx - > x . iVal ;
if ( nOfft > = SyBlobLength ( & pTos - > sBlob ) ) {
/* Invalid offset,load null */
PH7_MemObjRelease ( pTos ) ;
} else {
const char * zData = ( const char * ) SyBlobData ( & pTos - > sBlob ) ;
int c = zData [ nOfft ] ;
PH7_MemObjRelease ( pTos ) ;
MemObjSetType ( pTos , MEMOBJ_STRING ) ;
SyBlobAppend ( & pTos - > sBlob , ( const void * ) & c , sizeof ( char ) ) ;
}
} else {
/* No available index,load NULL */
MemObjSetType ( pTos , MEMOBJ_NULL ) ;
}
break ;
}
2019-05-21 14:49:36 +02:00
if ( ( pTos - > nType & MEMOBJ_HASHMAP ) = = 0 ) {
2019-04-06 09:36:08 +02:00
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR , " Subscripted value is neither array nor string " ) ;
2018-07-12 17:24:46 +02:00
}
rc = SXERR_NOTFOUND ; /* Assume the index is invalid */
2019-05-21 14:49:36 +02:00
if ( pTos - > nType & MEMOBJ_HASHMAP ) {
2018-07-12 17:24:46 +02:00
/* Point to the hashmap */
pMap = ( ph7_hashmap * ) pTos - > x . pOther ;
if ( pIdx ) {
/* Load the desired entry */
rc = PH7_HashmapLookup ( pMap , pIdx , & pNode ) ;
}
if ( rc ! = SXRET_OK & & pInstr - > iP2 ) {
/* Create a new empty entry */
rc = PH7_HashmapInsert ( pMap , pIdx , 0 ) ;
if ( rc = = SXRET_OK ) {
/* Point to the last inserted entry */
pNode = pMap - > pLast ;
}
}
}
if ( pIdx ) {
PH7_MemObjRelease ( pIdx ) ;
}
if ( rc = = SXRET_OK ) {
/* Load entry contents */
if ( pMap - > iRef < 2 ) {
/* TICKET 1433-42: Array will be deleted shortly,so we will make a copy
* of the entry value , rather than pointing to it .
*/
pTos - > nIdx = SXU32_HIGH ;
PH7_HashmapExtractNodeValue ( pNode , pTos , TRUE ) ;
} else {
pTos - > nIdx = pNode - > nValIdx ;
PH7_HashmapExtractNodeValue ( pNode , pTos , FALSE ) ;
PH7_HashmapUnref ( pMap ) ;
}
} else {
2019-04-06 09:36:08 +02:00
/* No such entry, load NULL */
2018-07-12 17:24:46 +02:00
PH7_MemObjRelease ( pTos ) ;
pTos - > nIdx = SXU32_HIGH ;
}
break ;
2018-07-12 13:26:32 +02:00
}
2018-07-12 17:24:46 +02:00
/*
* LOAD_CLOSURE * * P3
*
2018-07-22 22:47:00 +02:00
* Set - up closure environment described by the P3 operand and push the closure
2018-07-12 17:24:46 +02:00
* name in the stack .
*/
case PH7_OP_LOAD_CLOSURE : {
ph7_vm_func * pFunc = ( ph7_vm_func * ) pInstr - > p3 ;
if ( pFunc - > iFlags & VM_FUNC_CLOSURE ) {
ph7_vm_func_closure_env * aEnv , * pEnv , sEnv ;
ph7_vm_func * pClosure ;
char * zName ;
sxu32 mLen ;
sxu32 n ;
/* Create a new VM function */
pClosure = ( ph7_vm_func * ) SyMemBackendPoolAlloc ( & pVm - > sAllocator , sizeof ( ph7_vm_func ) ) ;
/* Generate an unique closure name */
zName = ( char * ) SyMemBackendAlloc ( & pVm - > sAllocator , sizeof ( " [closure_] " ) + 64 ) ;
if ( pClosure = = 0 | | zName = = 0 ) {
2018-09-03 16:16:32 +02:00
PH7_VmMemoryError ( pVm ) ;
2018-07-12 17:24:46 +02:00
}
mLen = SyBufferFormat ( zName , sizeof ( " [closure_] " ) + 64 , " [closure_%d] " , pVm - > closure_cnt + + ) ;
while ( SyHashGet ( & pVm - > hFunction , zName , mLen ) ! = 0 & & mLen < ( sizeof ( " [closure_] " ) + 60 /* not 64 */ ) ) {
mLen = SyBufferFormat ( zName , sizeof ( " [closure_] " ) + 64 , " [closure_%d] " , pVm - > closure_cnt + + ) ;
}
/* Zero the stucture */
SyZero ( pClosure , sizeof ( ph7_vm_func ) ) ;
/* Perform a structure assignment on read-only items */
pClosure - > aArgs = pFunc - > aArgs ;
pClosure - > aByteCode = pFunc - > aByteCode ;
pClosure - > aStatic = pFunc - > aStatic ;
pClosure - > iFlags = pFunc - > iFlags ;
pClosure - > pUserData = pFunc - > pUserData ;
pClosure - > sSignature = pFunc - > sSignature ;
SyStringInitFromBuf ( & pClosure - > sName , zName , mLen ) ;
/* Register the closure */
PH7_VmInstallUserFunction ( pVm , pClosure , 0 ) ;
/* Set up closure environment */
SySetInit ( & pClosure - > aClosureEnv , & pVm - > sAllocator , sizeof ( ph7_vm_func_closure_env ) ) ;
aEnv = ( ph7_vm_func_closure_env * ) SySetBasePtr ( & pFunc - > aClosureEnv ) ;
for ( n = 0 ; n < SySetUsed ( & pFunc - > aClosureEnv ) ; + + n ) {
ph7_value * pValue ;
pEnv = & aEnv [ n ] ;
sEnv . sName = pEnv - > sName ;
sEnv . iFlags = pEnv - > iFlags ;
sEnv . nIdx = SXU32_HIGH ;
PH7_MemObjInit ( pVm , & sEnv . sValue ) ;
2019-05-01 18:29:57 +02:00
pValue = VmExtractMemObj ( pVm , & sEnv . sName , FALSE ) ;
2018-07-12 17:24:46 +02:00
if ( pValue ) {
/* Copy imported value */
PH7_MemObjStore ( pValue , & sEnv . sValue ) ;
}
/* Insert the imported variable */
SySetPut ( & pClosure - > aClosureEnv , ( const void * ) & sEnv ) ;
}
/* Finally,load the closure name on the stack */
pTos + + ;
PH7_MemObjStringAppend ( pTos , zName , mLen ) ;
}
break ;
}
/*
* STORE * P2 P3
*
* Perform a store ( Assignment ) operation .
*/
case PH7_OP_STORE : {
ph7_value * pObj ;
SyString sName ;
2018-07-12 13:26:32 +02:00
# ifdef UNTRUST
2018-07-12 17:24:46 +02:00
if ( pTos < pStack ) {
goto Abort ;
}
2018-07-12 13:26:32 +02:00
# endif
2018-07-12 17:24:46 +02:00
if ( pInstr - > iP2 ) {
sxu32 nIdx ;
/* Member store operation */
nIdx = pTos - > nIdx ;
VmPopOperand ( & pTos , 1 ) ;
if ( nIdx = = SXU32_HIGH ) {
2018-09-04 08:54:48 +02:00
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_WARNING ,
2018-09-03 16:16:32 +02:00
" Cannot perform assignment on a constant class attribute, PH7 is loading NULL " ) ;
2018-07-12 17:24:46 +02:00
pTos - > nIdx = SXU32_HIGH ;
} else {
/* Point to the desired memory object */
pObj = ( ph7_value * ) SySetAt ( & pVm - > aMemObj , nIdx ) ;
if ( pObj ) {
/* Perform the store operation */
2019-04-03 06:37:35 +02:00
rc = PH7_MemObjSafeStore ( pTos , pObj ) ;
if ( rc ! = SXRET_OK ) {
2019-03-29 09:21:58 +01:00
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR ,
" Cannot assign a value of incompatible type to variable '$%z' " , & sName ) ;
}
2018-07-12 17:24:46 +02:00
}
}
break ;
} else if ( pInstr - > p3 = = 0 ) {
/* Take the variable name from the next on the stack */
2019-05-21 14:49:36 +02:00
if ( ( pTos - > nType & MEMOBJ_STRING ) = = 0 ) {
2018-07-12 17:24:46 +02:00
/* Force a string cast */
PH7_MemObjToString ( pTos ) ;
}
SyStringInitFromBuf ( & sName , SyBlobData ( & pTos - > sBlob ) , SyBlobLength ( & pTos - > sBlob ) ) ;
pTos - - ;
# ifdef UNTRUST
if ( pTos < pStack ) {
goto Abort ;
}
# endif
} else {
SyStringInitFromBuf ( & sName , pInstr - > p3 , SyStrlen ( ( const char * ) pInstr - > p3 ) ) ;
}
2019-04-02 20:10:58 +02:00
/* Extract the desired variable if available */
2019-05-01 18:29:57 +02:00
pObj = VmExtractMemObj ( & ( * pVm ) , & sName , pInstr - > p3 ? FALSE : TRUE ) ;
2018-07-12 17:24:46 +02:00
if ( pObj = = 0 ) {
2018-09-23 17:40:26 +02:00
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR ,
" Variable '$%z' undeclared (first use in this method/closure) " , & sName ) ;
2019-05-21 19:18:52 +02:00
} else if ( pObj - > iFlags ! = MEMOBJ_VARIABLE ) {
2019-05-08 08:26:48 +02:00
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR , " Cannot re-assign a value of '$%z' statement " , & sName ) ;
2018-07-12 17:24:46 +02:00
}
if ( ! pInstr - > p3 ) {
PH7_MemObjRelease ( & pTos [ 1 ] ) ;
}
/* Perform the store operation */
2019-04-03 06:37:35 +02:00
rc = PH7_MemObjSafeStore ( pTos , pObj ) ;
if ( rc ! = SXRET_OK ) {
2018-09-24 19:17:46 +02:00
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR ,
" Cannot assign a value of incompatible type to variable '$%z' " , & sName ) ;
}
2018-07-12 17:24:46 +02:00
break ;
2018-07-12 13:26:32 +02:00
}
2018-07-12 17:24:46 +02:00
/*
* STORE_IDX : P1 * P3
*
* Perfrom a store operation an a hashmap entry .
*/
2019-03-29 22:55:49 +01:00
case PH7_OP_STORE_IDX : {
2018-07-12 17:24:46 +02:00
ph7_hashmap * pMap = 0 ; /* cc warning */
ph7_value * pKey ;
sxu32 nIdx ;
if ( pInstr - > iP1 ) {
/* Key is next on stack */
pKey = pTos ;
pTos - - ;
} else {
pKey = 0 ;
}
nIdx = pTos - > nIdx ;
2019-05-21 14:49:36 +02:00
if ( pTos - > nType & MEMOBJ_HASHMAP ) {
2018-07-12 17:24:46 +02:00
/* Hashmap already loaded */
pMap = ( ph7_hashmap * ) pTos - > x . pOther ;
if ( pMap - > iRef < 2 ) {
/* TICKET 1433-48: Prevent garbage collection */
pMap - > iRef = 2 ;
}
} else {
ph7_value * pObj ;
pObj = ( ph7_value * ) SySetAt ( & pVm - > aMemObj , nIdx ) ;
if ( pObj = = 0 ) {
if ( pKey ) {
PH7_MemObjRelease ( pKey ) ;
}
VmPopOperand ( & pTos , 1 ) ;
break ;
}
/* Phase#1: Load the array */
2019-05-21 14:49:36 +02:00
if ( pObj - > nType & MEMOBJ_STRING ) {
2018-07-12 17:24:46 +02:00
VmPopOperand ( & pTos , 1 ) ;
2019-05-21 14:49:36 +02:00
if ( ( pTos - > nType & MEMOBJ_STRING ) = = 0 ) {
2018-07-12 17:24:46 +02:00
/* Force a string cast */
PH7_MemObjToString ( pTos ) ;
}
if ( pKey = = 0 ) {
/* Append string */
if ( SyBlobLength ( & pTos - > sBlob ) > 0 ) {
SyBlobAppend ( & pObj - > sBlob , SyBlobData ( & pTos - > sBlob ) , SyBlobLength ( & pTos - > sBlob ) ) ;
}
} else {
sxu32 nOfft ;
2019-05-21 14:49:36 +02:00
if ( ( pKey - > nType & MEMOBJ_INT ) ) {
2018-07-12 17:24:46 +02:00
/* Force an int cast */
PH7_MemObjToInteger ( pKey ) ;
}
nOfft = ( sxu32 ) pKey - > x . iVal ;
if ( nOfft < SyBlobLength ( & pObj - > sBlob ) & & SyBlobLength ( & pTos - > sBlob ) > 0 ) {
const char * zBlob = ( const char * ) SyBlobData ( & pTos - > sBlob ) ;
char * zData = ( char * ) SyBlobData ( & pObj - > sBlob ) ;
zData [ nOfft ] = zBlob [ 0 ] ;
} else {
if ( SyBlobLength ( & pTos - > sBlob ) > = sizeof ( char ) ) {
/* Perform an append operation */
SyBlobAppend ( & pObj - > sBlob , SyBlobData ( & pTos - > sBlob ) , sizeof ( char ) ) ;
}
}
}
if ( pKey ) {
PH7_MemObjRelease ( pKey ) ;
}
break ;
2019-05-21 14:49:36 +02:00
} else if ( ( pObj - > nType & MEMOBJ_HASHMAP ) = = 0 ) {
2018-07-12 17:24:46 +02:00
/* Force a hashmap cast */
rc = PH7_MemObjToHashmap ( pObj ) ;
if ( rc ! = SXRET_OK ) {
2018-09-03 16:16:32 +02:00
PH7_VmMemoryError ( & ( * pVm ) ) ;
2018-07-12 17:24:46 +02:00
}
}
pMap = ( ph7_hashmap * ) pObj - > x . pOther ;
}
2019-05-21 14:49:36 +02:00
sxu32 pArrType = pTos - > nType ^ MEMOBJ_HASHMAP ;
2018-07-12 17:24:46 +02:00
VmPopOperand ( & pTos , 1 ) ;
2019-04-19 07:08:29 +02:00
/* Phase#2: Perform the type validation */
2019-05-21 14:49:36 +02:00
if ( ( pArrType & MEMOBJ_MIXED ) = = 0 & & ( pTos - > nType & pArrType ) = = 0 ) {
2019-04-19 07:08:29 +02:00
sxu32 rc = SXRET_OK ;
2019-05-21 14:49:36 +02:00
if ( pTos - > nType & MEMOBJ_HASHMAP ) {
2019-04-19 07:08:29 +02:00
rc = PH7_HashmapCast ( pTos , pArrType ) ;
} else {
if ( ( rc = PH7_CheckVarCompat ( pTos , pArrType ) ) = = SXRET_OK ) {
ProcMemObjCast xCast = PH7_MemObjCastMethod ( pArrType ) ;
xCast ( pTos ) ;
}
}
if ( rc ! = SXRET_OK ) {
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR ,
" Cannot insert a value of incompatible type to array " ) ;
}
}
/* Phase#3: Perform the insertion */
2019-03-29 22:55:49 +01:00
PH7_HashmapInsert ( pMap , pKey , pTos ) ;
2018-07-12 17:24:46 +02:00
if ( pKey ) {
PH7_MemObjRelease ( pKey ) ;
}
break ;
2018-07-12 13:26:32 +02:00
}
2018-07-12 17:24:46 +02:00
/*
* INCR : P1 * *
*
* Force a numeric cast and increment the top of the stack by 1.
* If the P1 operand is set then perform a duplication of the top of
* the stack and increment after that .
*/
case PH7_OP_INCR :
2018-07-12 13:26:32 +02:00
# ifdef UNTRUST
2018-07-12 17:24:46 +02:00
if ( pTos < pStack ) {
goto Abort ;
}
2018-07-12 13:26:32 +02:00
# endif
2019-05-21 14:49:36 +02:00
if ( ( pTos - > nType & ( MEMOBJ_HASHMAP | MEMOBJ_OBJ | MEMOBJ_RES ) ) = = 0 ) {
2018-07-12 17:24:46 +02:00
if ( pTos - > nIdx ! = SXU32_HIGH ) {
ph7_value * pObj ;
if ( ( pObj = ( ph7_value * ) SySetAt ( & pVm - > aMemObj , pTos - > nIdx ) ) ! = 0 ) {
/* Force a numeric cast */
PH7_MemObjToNumeric ( pObj ) ;
2019-05-21 14:49:36 +02:00
if ( pObj - > nType & MEMOBJ_REAL ) {
2018-09-07 12:04:51 +02:00
pObj - > x . rVal + + ;
2018-07-12 17:24:46 +02:00
} else {
pObj - > x . iVal + + ;
MemObjSetType ( pTos , MEMOBJ_INT ) ;
}
if ( pInstr - > iP1 ) {
2018-09-06 18:00:34 +02:00
/* Pre-increment */
2018-07-12 17:24:46 +02:00
PH7_MemObjStore ( pObj , pTos ) ;
}
}
} else {
if ( pInstr - > iP1 ) {
/* Force a numeric cast */
PH7_MemObjToNumeric ( pTos ) ;
/* Pre-increment */
2019-05-21 14:49:36 +02:00
if ( pTos - > nType & MEMOBJ_REAL ) {
2018-09-07 12:04:51 +02:00
pTos - > x . rVal + + ;
2018-07-12 17:24:46 +02:00
} else {
pTos - > x . iVal + + ;
MemObjSetType ( pTos , MEMOBJ_INT ) ;
}
}
}
}
break ;
/*
* DECR : P1 * *
*
* Force a numeric cast and decrement the top of the stack by 1.
* If the P1 operand is set then perform a duplication of the top of the stack
* and decrement after that .
*/
case PH7_OP_DECR :
2018-07-12 13:26:32 +02:00
# ifdef UNTRUST
2018-07-12 17:24:46 +02:00
if ( pTos < pStack ) {
goto Abort ;
}
2018-07-12 13:26:32 +02:00
# endif
2019-05-21 14:49:36 +02:00
if ( ( pTos - > nType & ( MEMOBJ_HASHMAP | MEMOBJ_OBJ | MEMOBJ_RES | MEMOBJ_NULL ) ) = = 0 ) {
2018-07-12 17:24:46 +02:00
/* Force a numeric cast */
PH7_MemObjToNumeric ( pTos ) ;
if ( pTos - > nIdx ! = SXU32_HIGH ) {
ph7_value * pObj ;
if ( ( pObj = ( ph7_value * ) SySetAt ( & pVm - > aMemObj , pTos - > nIdx ) ) ! = 0 ) {
/* Force a numeric cast */
PH7_MemObjToNumeric ( pObj ) ;
2019-05-21 14:49:36 +02:00
if ( pObj - > nType & MEMOBJ_REAL ) {
2018-09-07 12:04:51 +02:00
pObj - > x . rVal - - ;
2018-07-12 17:24:46 +02:00
} else {
pObj - > x . iVal - - ;
MemObjSetType ( pTos , MEMOBJ_INT ) ;
}
if ( pInstr - > iP1 ) {
2018-09-06 18:00:34 +02:00
/* Pre-decrement */
2018-07-12 17:24:46 +02:00
PH7_MemObjStore ( pObj , pTos ) ;
}
}
} else {
if ( pInstr - > iP1 ) {
2018-09-06 18:00:34 +02:00
/* Pre-decrement */
2019-05-21 14:49:36 +02:00
if ( pTos - > nType & MEMOBJ_REAL ) {
2018-09-07 12:04:51 +02:00
pTos - > x . rVal - - ;
2018-07-12 17:24:46 +02:00
} else {
pTos - > x . iVal - - ;
MemObjSetType ( pTos , MEMOBJ_INT ) ;
}
}
}
}
break ;
/*
* UMINUS : * * *
*
* Perform a unary minus operation .
*/
case PH7_OP_UMINUS :
2018-07-12 13:26:32 +02:00
# ifdef UNTRUST
2018-07-12 17:24:46 +02:00
if ( pTos < pStack ) {
goto Abort ;
}
2018-07-12 13:26:32 +02:00
# endif
2018-07-12 17:24:46 +02:00
/* Force a numeric (integer,real or both) cast */
PH7_MemObjToNumeric ( pTos ) ;
2019-05-21 14:49:36 +02:00
if ( pTos - > nType & MEMOBJ_REAL ) {
2018-09-07 12:04:51 +02:00
pTos - > x . rVal = - pTos - > x . rVal ;
2018-07-12 17:24:46 +02:00
}
2019-05-21 14:49:36 +02:00
if ( pTos - > nType & MEMOBJ_INT ) {
2018-07-12 17:24:46 +02:00
pTos - > x . iVal = - pTos - > x . iVal ;
}
break ;
/*
* UPLUS : * * *
*
* Perform a unary plus operation .
*/
case PH7_OP_UPLUS :
2018-07-12 13:26:32 +02:00
# ifdef UNTRUST
2018-07-12 17:24:46 +02:00
if ( pTos < pStack ) {
goto Abort ;
}
2018-07-12 13:26:32 +02:00
# endif
2018-07-12 17:24:46 +02:00
/* Force a numeric (integer,real or both) cast */
PH7_MemObjToNumeric ( pTos ) ;
2019-05-21 14:49:36 +02:00
if ( pTos - > nType & MEMOBJ_REAL ) {
2018-09-07 12:04:51 +02:00
pTos - > x . rVal = + pTos - > x . rVal ;
2018-07-12 17:24:46 +02:00
}
2019-05-21 14:49:36 +02:00
if ( pTos - > nType & MEMOBJ_INT ) {
2018-07-12 17:24:46 +02:00
pTos - > x . iVal = + pTos - > x . iVal ;
}
break ;
/*
* OP_LNOT : * * *
*
* Interpret the top of the stack as a boolean value . Replace it
* with its complement .
*/
case PH7_OP_LNOT :
2018-07-12 13:26:32 +02:00
# ifdef UNTRUST
2018-07-12 17:24:46 +02:00
if ( pTos < pStack ) {
goto Abort ;
}
2018-07-12 13:26:32 +02:00
# endif
2018-07-12 17:24:46 +02:00
/* Force a boolean cast */
2019-05-21 14:49:36 +02:00
if ( ( pTos - > nType & MEMOBJ_BOOL ) = = 0 ) {
2018-07-12 17:24:46 +02:00
PH7_MemObjToBool ( pTos ) ;
}
pTos - > x . iVal = ! pTos - > x . iVal ;
break ;
/*
* OP_BITNOT : * * *
*
* Interpret the top of the stack as an value . Replace it
* with its ones - complement .
*/
case PH7_OP_BITNOT :
2018-07-12 13:26:32 +02:00
# ifdef UNTRUST
2018-07-12 17:24:46 +02:00
if ( pTos < pStack ) {
goto Abort ;
}
2018-07-12 13:26:32 +02:00
# endif
2018-07-12 17:24:46 +02:00
/* Force an integer cast */
2019-05-21 14:49:36 +02:00
if ( ( pTos - > nType & MEMOBJ_INT ) = = 0 ) {
2018-07-12 17:24:46 +02:00
PH7_MemObjToInteger ( pTos ) ;
2018-07-12 13:26:32 +02:00
}
2018-07-12 17:24:46 +02:00
pTos - > x . iVal = ~ pTos - > x . iVal ;
break ;
/* OP_MUL * * *
* OP_MUL_STORE * * *
*
* Pop the top two elements from the stack , multiply them together ,
* and push the result back onto the stack .
*/
case PH7_OP_MUL :
case PH7_OP_MUL_STORE : {
ph7_value * pNos = & pTos [ - 1 ] ;
/* Force the operand to be numeric */
2018-07-12 13:26:32 +02:00
# ifdef UNTRUST
2018-07-12 17:24:46 +02:00
if ( pNos < pStack ) {
goto Abort ;
}
2018-07-12 13:26:32 +02:00
# endif
2018-07-12 17:24:46 +02:00
PH7_MemObjToNumeric ( pTos ) ;
PH7_MemObjToNumeric ( pNos ) ;
/* Perform the requested operation */
2019-05-21 14:49:36 +02:00
if ( MEMOBJ_REAL & ( pTos - > nType | pNos - > nType ) ) {
2018-07-12 17:24:46 +02:00
/* Floating point arithemic */
ph7_real a , b , r ;
2019-05-21 14:49:36 +02:00
if ( ( pTos - > nType & MEMOBJ_REAL ) = = 0 ) {
2018-07-12 17:24:46 +02:00
PH7_MemObjToReal ( pTos ) ;
}
2019-05-21 14:49:36 +02:00
if ( ( pNos - > nType & MEMOBJ_REAL ) = = 0 ) {
2018-07-12 17:24:46 +02:00
PH7_MemObjToReal ( pNos ) ;
}
2018-09-07 12:04:51 +02:00
a = pNos - > x . rVal ;
b = pTos - > x . rVal ;
2018-07-12 17:24:46 +02:00
r = a * b ;
/* Push the result */
2018-09-07 12:04:51 +02:00
pNos - > x . rVal = r ;
2018-07-12 17:24:46 +02:00
MemObjSetType ( pNos , MEMOBJ_REAL ) ;
} else {
/* Integer arithmetic */
sxi64 a , b , r ;
a = pNos - > x . iVal ;
b = pTos - > x . iVal ;
r = a * b ;
/* Push the result */
pNos - > x . iVal = r ;
MemObjSetType ( pNos , MEMOBJ_INT ) ;
}
if ( pInstr - > iOp = = PH7_OP_MUL_STORE ) {
ph7_value * pObj ;
if ( pTos - > nIdx = = SXU32_HIGH ) {
2018-09-04 08:54:48 +02:00
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR , " Cannot perform assignment on a constant class attribute " ) ;
2018-07-12 17:24:46 +02:00
} else if ( ( pObj = ( ph7_value * ) SySetAt ( & pVm - > aMemObj , pTos - > nIdx ) ) ! = 0 ) {
PH7_MemObjStore ( pNos , pObj ) ;
}
}
VmPopOperand ( & pTos , 1 ) ;
break ;
}
2018-08-07 07:47:25 +02:00
/* OP_ADD P1 P2 *
2018-07-12 17:24:46 +02:00
*
* Pop the top two elements from the stack , add them together ,
* and push the result back onto the stack .
*/
case PH7_OP_ADD : {
2018-08-07 07:47:25 +02:00
ph7_value * pNos ;
if ( pInstr - > iP1 < 1 ) {
pNos = & pTos [ - 1 ] ;
} else {
pNos = & pTos [ - pInstr - > iP1 + 1 ] ;
}
2018-07-12 13:26:32 +02:00
# ifdef UNTRUST
2018-07-12 17:24:46 +02:00
if ( pNos < pStack ) {
goto Abort ;
}
2018-07-12 13:26:32 +02:00
# endif
2019-05-21 14:49:36 +02:00
if ( pInstr - > iP2 | | pNos - > nType & MEMOBJ_STRING | | pTos - > nType & MEMOBJ_STRING ) {
2018-08-07 06:54:44 +02:00
/* Perform the string addition */
ph7_value * pCur ;
2019-05-21 14:49:36 +02:00
if ( ( pNos - > nType & MEMOBJ_STRING ) = = 0 ) {
2018-08-07 06:54:44 +02:00
PH7_MemObjToString ( pNos ) ;
}
pCur = & pNos [ 1 ] ;
while ( pCur < = pTos ) {
2019-05-21 14:49:36 +02:00
if ( ( pCur - > nType & MEMOBJ_STRING ) = = 0 ) {
2018-08-07 06:54:44 +02:00
PH7_MemObjToString ( pCur ) ;
}
if ( SyBlobLength ( & pCur - > sBlob ) > 0 ) {
PH7_MemObjStringAppend ( pNos , ( const char * ) SyBlobData ( & pCur - > sBlob ) , SyBlobLength ( & pCur - > sBlob ) ) ;
}
SyBlobRelease ( & pCur - > sBlob ) ;
pCur + + ;
}
pTos = pNos ;
} else {
/* Perform the number addition */
PH7_MemObjAdd ( pNos , pTos , FALSE ) ;
VmPopOperand ( & pTos , 1 ) ;
}
2018-07-12 17:24:46 +02:00
break ;
}
/*
* OP_ADD_STORE * * *
*
* Pop the top two elements from the stack , add them together ,
* and push the result back onto the stack .
*/
case PH7_OP_ADD_STORE : {
ph7_value * pNos = & pTos [ - 1 ] ;
ph7_value * pObj ;
2018-07-12 13:26:32 +02:00
# ifdef UNTRUST
2018-07-12 17:24:46 +02:00
if ( pNos < pStack ) {
goto Abort ;
}
2018-07-12 13:26:32 +02:00
# endif
2019-05-21 14:49:36 +02:00
if ( pTos - > nType & MEMOBJ_STRING ) {
2018-08-07 06:54:44 +02:00
/* Perform the string addition */
2019-05-21 14:49:36 +02:00
if ( ( pNos - > nType & MEMOBJ_STRING ) = = 0 ) {
2018-08-07 06:54:44 +02:00
/* Force a string cast */
PH7_MemObjToString ( pNos ) ;
}
/* Perform the concatenation (Reverse order) */
if ( SyBlobLength ( & pNos - > sBlob ) > 0 ) {
PH7_MemObjStringAppend ( pTos , ( const char * ) SyBlobData ( & pNos - > sBlob ) , SyBlobLength ( & pNos - > sBlob ) ) ;
}
} else {
/* Perform the number addition */
PH7_MemObjAdd ( pTos , pNos , TRUE ) ;
}
2018-07-23 17:10:48 +02:00
/* Perform the store operation */
2018-08-07 06:54:44 +02:00
if ( pTos - > nIdx = = SXU32_HIGH ) {
2018-09-04 08:54:48 +02:00
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR , " Cannot perform assignment on a constant class attribute " ) ;
2018-08-07 06:54:44 +02:00
} else if ( ( pObj = ( ph7_value * ) SySetAt ( & pVm - > aMemObj , pTos - > nIdx ) ) ! = 0 ) {
2018-07-12 17:24:46 +02:00
PH7_MemObjStore ( pTos , pObj ) ;
}
/* Ticket 1433-35: Perform a stack dup */
PH7_MemObjStore ( pTos , pNos ) ;
VmPopOperand ( & pTos , 1 ) ;
break ;
}
/* OP_SUB * * *
*
* Pop the top two elements from the stack , subtract the
* first ( what was next on the stack ) from the second ( the
* top of the stack ) and push the result back onto the stack .
*/
case PH7_OP_SUB : {
ph7_value * pNos = & pTos [ - 1 ] ;
2018-07-12 13:26:32 +02:00
# ifdef UNTRUST
2018-07-12 17:24:46 +02:00
if ( pNos < pStack ) {
goto Abort ;
}
2018-07-12 13:26:32 +02:00
# endif
2019-05-21 14:49:36 +02:00
if ( MEMOBJ_REAL & ( pTos - > nType | pNos - > nType ) ) {
2018-07-12 17:24:46 +02:00
/* Floating point arithemic */
ph7_real a , b , r ;
2019-05-21 14:49:36 +02:00
if ( ( pTos - > nType & MEMOBJ_REAL ) = = 0 ) {
2018-07-12 17:24:46 +02:00
PH7_MemObjToReal ( pTos ) ;
}
2019-05-21 14:49:36 +02:00
if ( ( pNos - > nType & MEMOBJ_REAL ) = = 0 ) {
2018-07-12 17:24:46 +02:00
PH7_MemObjToReal ( pNos ) ;
}
2018-09-07 12:04:51 +02:00
a = pNos - > x . rVal ;
b = pTos - > x . rVal ;
2018-07-12 17:24:46 +02:00
r = a - b ;
/* Push the result */
2018-09-07 12:04:51 +02:00
pNos - > x . rVal = r ;
2018-07-12 17:24:46 +02:00
MemObjSetType ( pNos , MEMOBJ_REAL ) ;
} else {
/* Integer arithmetic */
sxi64 a , b , r ;
a = pNos - > x . iVal ;
b = pTos - > x . iVal ;
r = a - b ;
/* Push the result */
pNos - > x . iVal = r ;
MemObjSetType ( pNos , MEMOBJ_INT ) ;
}
VmPopOperand ( & pTos , 1 ) ;
break ;
}
/* OP_SUB_STORE * * *
*
* Pop the top two elements from the stack , subtract the
* first ( what was next on the stack ) from the second ( the
* top of the stack ) and push the result back onto the stack .
*/
case PH7_OP_SUB_STORE : {
ph7_value * pNos = & pTos [ - 1 ] ;
ph7_value * pObj ;
2018-07-12 13:26:32 +02:00
# ifdef UNTRUST
2018-07-12 17:24:46 +02:00
if ( pNos < pStack ) {
goto Abort ;
}
2018-07-12 13:26:32 +02:00
# endif
2019-05-21 14:49:36 +02:00
if ( MEMOBJ_REAL & ( pTos - > nType | pNos - > nType ) ) {
2018-07-12 17:24:46 +02:00
/* Floating point arithemic */
ph7_real a , b , r ;
2019-05-21 14:49:36 +02:00
if ( ( pTos - > nType & MEMOBJ_REAL ) = = 0 ) {
2018-07-12 17:24:46 +02:00
PH7_MemObjToReal ( pTos ) ;
}
2019-05-21 14:49:36 +02:00
if ( ( pNos - > nType & MEMOBJ_REAL ) = = 0 ) {
2018-07-12 17:24:46 +02:00
PH7_MemObjToReal ( pNos ) ;
}
2018-09-07 12:04:51 +02:00
a = pTos - > x . rVal ;
b = pNos - > x . rVal ;
2018-07-12 17:24:46 +02:00
r = a - b ;
/* Push the result */
2018-09-07 12:04:51 +02:00
pNos - > x . rVal = r ;
2018-07-12 17:24:46 +02:00
MemObjSetType ( pNos , MEMOBJ_REAL ) ;
} else {
/* Integer arithmetic */
sxi64 a , b , r ;
a = pTos - > x . iVal ;
b = pNos - > x . iVal ;
r = a - b ;
/* Push the result */
pNos - > x . iVal = r ;
MemObjSetType ( pNos , MEMOBJ_INT ) ;
}
if ( pTos - > nIdx = = SXU32_HIGH ) {
2018-09-04 08:54:48 +02:00
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR , " Cannot perform assignment on a constant class attribute " ) ;
2018-07-12 17:24:46 +02:00
} else if ( ( pObj = ( ph7_value * ) SySetAt ( & pVm - > aMemObj , pTos - > nIdx ) ) ! = 0 ) {
PH7_MemObjStore ( pNos , pObj ) ;
}
VmPopOperand ( & pTos , 1 ) ;
break ;
}
/*
* OP_MOD * * *
*
* Pop the top two elements from the stack , divide the
* first ( what was next on the stack ) from the second ( the
* top of the stack ) and push the remainder after division
* onto the stack .
* Note : Only integer arithemtic is allowed .
*/
case PH7_OP_MOD : {
ph7_value * pNos = & pTos [ - 1 ] ;
sxi64 a , b , r ;
2018-07-12 13:26:32 +02:00
# ifdef UNTRUST
2018-07-12 17:24:46 +02:00
if ( pNos < pStack ) {
goto Abort ;
}
2018-07-12 13:26:32 +02:00
# endif
2018-07-12 17:24:46 +02:00
/* Force the operands to be integer */
2019-05-21 14:49:36 +02:00
if ( ( pTos - > nType & MEMOBJ_INT ) = = 0 ) {
2018-07-12 17:24:46 +02:00
PH7_MemObjToInteger ( pTos ) ;
}
2019-05-21 14:49:36 +02:00
if ( ( pNos - > nType & MEMOBJ_INT ) = = 0 ) {
2018-07-12 17:24:46 +02:00
PH7_MemObjToInteger ( pNos ) ;
}
/* Perform the requested operation */
a = pNos - > x . iVal ;
b = pTos - > x . iVal ;
if ( b = = 0 ) {
2018-09-04 08:54:48 +02:00
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR , " Division by zero %qd%%0 " , a ) ;
2018-07-12 17:24:46 +02:00
} else {
r = a % b ;
}
/* Push the result */
pNos - > x . iVal = r ;
MemObjSetType ( pNos , MEMOBJ_INT ) ;
VmPopOperand ( & pTos , 1 ) ;
break ;
}
/*
* OP_MOD_STORE * * *
*
* Pop the top two elements from the stack , divide the
* first ( what was next on the stack ) from the second ( the
* top of the stack ) and push the remainder after division
* onto the stack .
* Note : Only integer arithemtic is allowed .
*/
case PH7_OP_MOD_STORE : {
ph7_value * pNos = & pTos [ - 1 ] ;
ph7_value * pObj ;
sxi64 a , b , r ;
2018-07-12 13:26:32 +02:00
# ifdef UNTRUST
2018-07-12 17:24:46 +02:00
if ( pNos < pStack ) {
goto Abort ;
}
2018-07-12 13:26:32 +02:00
# endif
2018-07-12 17:24:46 +02:00
/* Force the operands to be integer */
2019-05-21 14:49:36 +02:00
if ( ( pTos - > nType & MEMOBJ_INT ) = = 0 ) {
2018-07-12 17:24:46 +02:00
PH7_MemObjToInteger ( pTos ) ;
}
2019-05-21 14:49:36 +02:00
if ( ( pNos - > nType & MEMOBJ_INT ) = = 0 ) {
2018-07-12 17:24:46 +02:00
PH7_MemObjToInteger ( pNos ) ;
}
/* Perform the requested operation */
a = pTos - > x . iVal ;
b = pNos - > x . iVal ;
if ( b = = 0 ) {
2018-09-04 08:54:48 +02:00
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR , " Division by zero %qd%%0 " , a ) ;
2018-07-12 17:24:46 +02:00
} else {
r = a % b ;
}
/* Push the result */
pNos - > x . iVal = r ;
MemObjSetType ( pNos , MEMOBJ_INT ) ;
if ( pTos - > nIdx = = SXU32_HIGH ) {
2018-09-04 08:54:48 +02:00
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR , " Cannot perform assignment on a constant class attribute " ) ;
2018-07-12 17:24:46 +02:00
} else if ( ( pObj = ( ph7_value * ) SySetAt ( & pVm - > aMemObj , pTos - > nIdx ) ) ! = 0 ) {
PH7_MemObjStore ( pNos , pObj ) ;
}
VmPopOperand ( & pTos , 1 ) ;
break ;
}
/*
* OP_DIV * * *
*
* Pop the top two elements from the stack , divide the
* first ( what was next on the stack ) from the second ( the
* top of the stack ) and push the result onto the stack .
* Note : Only floating point arithemtic is allowed .
*/
case PH7_OP_DIV : {
ph7_value * pNos = & pTos [ - 1 ] ;
ph7_real a , b , r ;
2018-07-12 13:26:32 +02:00
# ifdef UNTRUST
2018-07-12 17:24:46 +02:00
if ( pNos < pStack ) {
goto Abort ;
}
2018-07-12 13:26:32 +02:00
# endif
2018-07-12 17:24:46 +02:00
/* Force the operands to be real */
2019-05-21 14:49:36 +02:00
if ( ( pTos - > nType & MEMOBJ_REAL ) = = 0 ) {
2018-07-12 17:24:46 +02:00
PH7_MemObjToReal ( pTos ) ;
}
2019-05-21 14:49:36 +02:00
if ( ( pNos - > nType & MEMOBJ_REAL ) = = 0 ) {
2018-07-12 17:24:46 +02:00
PH7_MemObjToReal ( pNos ) ;
}
/* Perform the requested operation */
2018-09-07 12:04:51 +02:00
a = pNos - > x . rVal ;
b = pTos - > x . rVal ;
2018-07-12 17:24:46 +02:00
if ( b = = 0 ) {
2018-09-04 08:54:48 +02:00
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR , " Division by zero " ) ;
2018-07-12 17:24:46 +02:00
} else {
r = a / b ;
/* Push the result */
2018-09-07 12:04:51 +02:00
pNos - > x . rVal = r ;
2018-07-12 17:24:46 +02:00
MemObjSetType ( pNos , MEMOBJ_REAL ) ;
}
VmPopOperand ( & pTos , 1 ) ;
break ;
}
/*
* OP_DIV_STORE * * *
*
* Pop the top two elements from the stack , divide the
* first ( what was next on the stack ) from the second ( the
* top of the stack ) and push the result onto the stack .
* Note : Only floating point arithemtic is allowed .
*/
case PH7_OP_DIV_STORE : {
ph7_value * pNos = & pTos [ - 1 ] ;
ph7_value * pObj ;
ph7_real a , b , r ;
2018-07-12 13:26:32 +02:00
# ifdef UNTRUST
2018-07-12 17:24:46 +02:00
if ( pNos < pStack ) {
goto Abort ;
}
2018-07-12 13:26:32 +02:00
# endif
2018-07-12 17:24:46 +02:00
/* Force the operands to be real */
2019-05-21 14:49:36 +02:00
if ( ( pTos - > nType & MEMOBJ_REAL ) = = 0 ) {
2018-07-12 17:24:46 +02:00
PH7_MemObjToReal ( pTos ) ;
}
2019-05-21 14:49:36 +02:00
if ( ( pNos - > nType & MEMOBJ_REAL ) = = 0 ) {
2018-07-12 17:24:46 +02:00
PH7_MemObjToReal ( pNos ) ;
}
/* Perform the requested operation */
2018-09-07 12:04:51 +02:00
a = pTos - > x . rVal ;
b = pNos - > x . rVal ;
2018-07-12 17:24:46 +02:00
if ( b = = 0 ) {
/* Division by zero */
2018-09-04 08:54:48 +02:00
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR , " Division by zero %qd/0 " , a ) ;
2018-07-12 17:24:46 +02:00
} else {
r = a / b ;
/* Push the result */
2018-09-07 12:04:51 +02:00
pNos - > x . rVal = r ;
2018-07-12 17:24:46 +02:00
MemObjSetType ( pNos , MEMOBJ_REAL ) ;
}
if ( pTos - > nIdx = = SXU32_HIGH ) {
2018-09-04 08:54:48 +02:00
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR , " Cannot perform assignment on a constant class attribute " ) ;
2018-07-12 17:24:46 +02:00
} else if ( ( pObj = ( ph7_value * ) SySetAt ( & pVm - > aMemObj , pTos - > nIdx ) ) ! = 0 ) {
PH7_MemObjStore ( pNos , pObj ) ;
}
VmPopOperand ( & pTos , 1 ) ;
break ;
}
/* OP_BAND * * *
*
* Pop the top two elements from the stack . Convert both elements
* to integers . Push back onto the stack the bit - wise AND of the
* two elements .
*/
/* OP_BOR * * *
*
* Pop the top two elements from the stack . Convert both elements
* to integers . Push back onto the stack the bit - wise OR of the
* two elements .
*/
/* OP_BXOR * * *
*
* Pop the top two elements from the stack . Convert both elements
* to integers . Push back onto the stack the bit - wise XOR of the
* two elements .
*/
case PH7_OP_BAND :
case PH7_OP_BOR :
case PH7_OP_BXOR : {
ph7_value * pNos = & pTos [ - 1 ] ;
sxi64 a , b , r ;
2018-07-12 13:26:32 +02:00
# ifdef UNTRUST
2018-07-12 17:24:46 +02:00
if ( pNos < pStack ) {
goto Abort ;
}
2018-07-12 13:26:32 +02:00
# endif
2018-07-12 17:24:46 +02:00
/* Force the operands to be integer */
2019-05-21 14:49:36 +02:00
if ( ( pTos - > nType & MEMOBJ_INT ) = = 0 ) {
2018-07-12 17:24:46 +02:00
PH7_MemObjToInteger ( pTos ) ;
}
2019-05-21 14:49:36 +02:00
if ( ( pNos - > nType & MEMOBJ_INT ) = = 0 ) {
2018-07-12 17:24:46 +02:00
PH7_MemObjToInteger ( pNos ) ;
}
/* Perform the requested operation */
a = pNos - > x . iVal ;
b = pTos - > x . iVal ;
switch ( pInstr - > iOp ) {
case PH7_OP_BOR_STORE :
case PH7_OP_BOR :
r = a | b ;
break ;
case PH7_OP_BXOR_STORE :
case PH7_OP_BXOR :
r = a ^ b ;
break ;
case PH7_OP_BAND_STORE :
case PH7_OP_BAND :
default :
r = a & b ;
break ;
}
/* Push the result */
pNos - > x . iVal = r ;
MemObjSetType ( pNos , MEMOBJ_INT ) ;
VmPopOperand ( & pTos , 1 ) ;
break ;
}
/* OP_BAND_STORE * * *
*
* Pop the top two elements from the stack . Convert both elements
* to integers . Push back onto the stack the bit - wise AND of the
* two elements .
*/
/* OP_BOR_STORE * * *
*
* Pop the top two elements from the stack . Convert both elements
* to integers . Push back onto the stack the bit - wise OR of the
* two elements .
*/
/* OP_BXOR_STORE * * *
*
* Pop the top two elements from the stack . Convert both elements
* to integers . Push back onto the stack the bit - wise XOR of the
* two elements .
*/
case PH7_OP_BAND_STORE :
case PH7_OP_BOR_STORE :
case PH7_OP_BXOR_STORE : {
ph7_value * pNos = & pTos [ - 1 ] ;
ph7_value * pObj ;
sxi64 a , b , r ;
2018-07-12 13:26:32 +02:00
# ifdef UNTRUST
2018-07-12 17:24:46 +02:00
if ( pNos < pStack ) {
goto Abort ;
}
2018-07-12 13:26:32 +02:00
# endif
2018-07-12 17:24:46 +02:00
/* Force the operands to be integer */
2019-05-21 14:49:36 +02:00
if ( ( pTos - > nType & MEMOBJ_INT ) = = 0 ) {
2018-07-12 17:24:46 +02:00
PH7_MemObjToInteger ( pTos ) ;
}
2019-05-21 14:49:36 +02:00
if ( ( pNos - > nType & MEMOBJ_INT ) = = 0 ) {
2018-07-12 17:24:46 +02:00
PH7_MemObjToInteger ( pNos ) ;
}
/* Perform the requested operation */
a = pTos - > x . iVal ;
b = pNos - > x . iVal ;
switch ( pInstr - > iOp ) {
case PH7_OP_BOR_STORE :
case PH7_OP_BOR :
r = a | b ;
break ;
case PH7_OP_BXOR_STORE :
case PH7_OP_BXOR :
r = a ^ b ;
break ;
case PH7_OP_BAND_STORE :
case PH7_OP_BAND :
default :
r = a & b ;
break ;
}
/* Push the result */
pNos - > x . iVal = r ;
MemObjSetType ( pNos , MEMOBJ_INT ) ;
if ( pTos - > nIdx = = SXU32_HIGH ) {
2018-09-04 08:54:48 +02:00
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR , " Cannot perform assignment on a constant class attribute " ) ;
2018-07-12 17:24:46 +02:00
} else if ( ( pObj = ( ph7_value * ) SySetAt ( & pVm - > aMemObj , pTos - > nIdx ) ) ! = 0 ) {
PH7_MemObjStore ( pNos , pObj ) ;
}
VmPopOperand ( & pTos , 1 ) ;
break ;
}
/* OP_SHL * * *
*
* Pop the top two elements from the stack . Convert both elements
* to integers . Push back onto the stack the second element shifted
* left by N bits where N is the top element on the stack .
* Note : Only integer arithmetic is allowed .
*/
/* OP_SHR * * *
*
* Pop the top two elements from the stack . Convert both elements
* to integers . Push back onto the stack the second element shifted
* right by N bits where N is the top element on the stack .
* Note : Only integer arithmetic is allowed .
*/
case PH7_OP_SHL :
case PH7_OP_SHR : {
ph7_value * pNos = & pTos [ - 1 ] ;
sxi64 a , r ;
sxi32 b ;
2018-07-12 13:26:32 +02:00
# ifdef UNTRUST
2018-07-12 17:24:46 +02:00
if ( pNos < pStack ) {
goto Abort ;
}
2018-07-12 13:26:32 +02:00
# endif
2018-07-12 17:24:46 +02:00
/* Force the operands to be integer */
2019-05-21 14:49:36 +02:00
if ( ( pTos - > nType & MEMOBJ_INT ) = = 0 ) {
2018-07-12 17:24:46 +02:00
PH7_MemObjToInteger ( pTos ) ;
}
2019-05-21 14:49:36 +02:00
if ( ( pNos - > nType & MEMOBJ_INT ) = = 0 ) {
2018-07-12 17:24:46 +02:00
PH7_MemObjToInteger ( pNos ) ;
}
/* Perform the requested operation */
a = pNos - > x . iVal ;
b = ( sxi32 ) pTos - > x . iVal ;
if ( pInstr - > iOp = = PH7_OP_SHL ) {
r = a < < b ;
} else {
r = a > > b ;
}
/* Push the result */
pNos - > x . iVal = r ;
MemObjSetType ( pNos , MEMOBJ_INT ) ;
VmPopOperand ( & pTos , 1 ) ;
break ;
2018-07-12 13:26:32 +02:00
}
2018-07-12 17:24:46 +02:00
/* OP_SHL_STORE * * *
*
* Pop the top two elements from the stack . Convert both elements
* to integers . Push back onto the stack the second element shifted
* left by N bits where N is the top element on the stack .
* Note : Only integer arithmetic is allowed .
*/
/* OP_SHR_STORE * * *
*
* Pop the top two elements from the stack . Convert both elements
* to integers . Push back onto the stack the second element shifted
* right by N bits where N is the top element on the stack .
* Note : Only integer arithmetic is allowed .
*/
case PH7_OP_SHL_STORE :
case PH7_OP_SHR_STORE : {
ph7_value * pNos = & pTos [ - 1 ] ;
ph7_value * pObj ;
sxi64 a , r ;
sxi32 b ;
# ifdef UNTRUST
if ( pNos < pStack ) {
goto Abort ;
}
# endif
/* Force the operands to be integer */
2019-05-21 14:49:36 +02:00
if ( ( pTos - > nType & MEMOBJ_INT ) = = 0 ) {
2018-07-12 17:24:46 +02:00
PH7_MemObjToInteger ( pTos ) ;
}
2019-05-21 14:49:36 +02:00
if ( ( pNos - > nType & MEMOBJ_INT ) = = 0 ) {
2018-07-12 17:24:46 +02:00
PH7_MemObjToInteger ( pNos ) ;
}
/* Perform the requested operation */
a = pTos - > x . iVal ;
b = ( sxi32 ) pNos - > x . iVal ;
if ( pInstr - > iOp = = PH7_OP_SHL_STORE ) {
r = a < < b ;
} else {
r = a > > b ;
}
/* Push the result */
pNos - > x . iVal = r ;
MemObjSetType ( pNos , MEMOBJ_INT ) ;
if ( pTos - > nIdx = = SXU32_HIGH ) {
2018-09-04 08:54:48 +02:00
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR , " Cannot perform assignment on a constant class attribute " ) ;
2018-07-12 17:24:46 +02:00
} else if ( ( pObj = ( ph7_value * ) SySetAt ( & pVm - > aMemObj , pTos - > nIdx ) ) ! = 0 ) {
PH7_MemObjStore ( pNos , pObj ) ;
}
VmPopOperand ( & pTos , 1 ) ;
break ;
}
/* OP_AND: * * *
*
* Pop two values off the stack . Take the logical AND of the
* two values and push the resulting boolean value back onto the
* stack .
*/
/* OP_OR: * * *
*
* Pop two values off the stack . Take the logical OR of the
* two values and push the resulting boolean value back onto the
* stack .
*/
case PH7_OP_LAND :
case PH7_OP_LOR : {
ph7_value * pNos = & pTos [ - 1 ] ;
sxi32 v1 , v2 ; /* 0==TRUE, 1==FALSE, 2==UNKNOWN or NULL */
2018-07-12 13:26:32 +02:00
# ifdef UNTRUST
2018-07-12 17:24:46 +02:00
if ( pNos < pStack ) {
goto Abort ;
}
2018-07-12 13:26:32 +02:00
# endif
2018-07-12 17:24:46 +02:00
/* Force a boolean cast */
2019-05-21 14:49:36 +02:00
if ( ( pTos - > nType & MEMOBJ_BOOL ) = = 0 ) {
2018-07-12 17:24:46 +02:00
PH7_MemObjToBool ( pTos ) ;
}
2019-05-21 14:49:36 +02:00
if ( ( pNos - > nType & MEMOBJ_BOOL ) = = 0 ) {
2018-07-12 17:24:46 +02:00
PH7_MemObjToBool ( pNos ) ;
}
v1 = pNos - > x . iVal = = 0 ? 1 : 0 ;
v2 = pTos - > x . iVal = = 0 ? 1 : 0 ;
if ( pInstr - > iOp = = PH7_OP_LAND ) {
static const unsigned char and_logic [ ] = { 0 , 1 , 2 , 1 , 1 , 1 , 2 , 1 , 2 } ;
v1 = and_logic [ v1 * 3 + v2 ] ;
} else {
static const unsigned char or_logic [ ] = { 0 , 0 , 0 , 0 , 1 , 2 , 0 , 2 , 2 } ;
v1 = or_logic [ v1 * 3 + v2 ] ;
}
if ( v1 = = 2 ) {
v1 = 1 ;
}
VmPopOperand ( & pTos , 1 ) ;
pTos - > x . iVal = v1 = = 0 ? 1 : 0 ;
MemObjSetType ( pTos , MEMOBJ_BOOL ) ;
break ;
}
/* OP_LXOR: * * *
*
* Pop two values off the stack . Take the logical XOR of the
* two values and push the resulting boolean value back onto the
* stack .
* According to the PHP language reference manual :
* $ a xor $ b is evaluated to TRUE if either $ a or $ b is
* TRUE , but not both .
*/
case PH7_OP_LXOR : {
ph7_value * pNos = & pTos [ - 1 ] ;
sxi32 v = 0 ;
2018-07-12 13:26:32 +02:00
# ifdef UNTRUST
2018-07-12 17:24:46 +02:00
if ( pNos < pStack ) {
goto Abort ;
}
2018-07-12 13:26:32 +02:00
# endif
2018-07-12 17:24:46 +02:00
/* Force a boolean cast */
2019-05-21 14:49:36 +02:00
if ( ( pTos - > nType & MEMOBJ_BOOL ) = = 0 ) {
2018-07-12 17:24:46 +02:00
PH7_MemObjToBool ( pTos ) ;
}
2019-05-21 14:49:36 +02:00
if ( ( pNos - > nType & MEMOBJ_BOOL ) = = 0 ) {
2018-07-12 17:24:46 +02:00
PH7_MemObjToBool ( pNos ) ;
}
if ( ( pNos - > x . iVal & & ! pTos - > x . iVal ) | | ( pTos - > x . iVal & & ! pNos - > x . iVal ) ) {
v = 1 ;
}
VmPopOperand ( & pTos , 1 ) ;
pTos - > x . iVal = v ;
MemObjSetType ( pTos , MEMOBJ_BOOL ) ;
break ;
}
/* OP_EQ P1 P2 P3
*
* Pop the top two elements from the stack . If they are equal , then
* jump to instruction P2 . Otherwise , continue to the next instruction .
* If P2 is zero , do not jump . Instead , push a boolean 1 ( TRUE ) onto the
* stack if the jump would have been taken , or a 0 ( FALSE ) if not .
*/
/* OP_NEQ P1 P2 P3
*
* Pop the top two elements from the stack . If they are not equal , then
* jump to instruction P2 . Otherwise , continue to the next instruction .
* If P2 is zero , do not jump . Instead , push a boolean 1 ( TRUE ) onto the
* stack if the jump would have been taken , or a 0 ( FALSE ) if not .
*/
case PH7_OP_EQ :
case PH7_OP_NEQ : {
ph7_value * pNos = & pTos [ - 1 ] ;
/* Perform the comparison and act accordingly */
2018-07-12 13:26:32 +02:00
# ifdef UNTRUST
2018-07-12 17:24:46 +02:00
if ( pNos < pStack ) {
goto Abort ;
}
2018-07-12 13:26:32 +02:00
# endif
2018-07-12 17:24:46 +02:00
rc = PH7_MemObjCmp ( pNos , pTos , FALSE , 0 ) ;
if ( pInstr - > iOp = = PH7_OP_EQ ) {
rc = rc = = 0 ;
} else {
rc = rc ! = 0 ;
}
VmPopOperand ( & pTos , 1 ) ;
if ( ! pInstr - > iP2 ) {
/* Push comparison result without taking the jump */
PH7_MemObjRelease ( pTos ) ;
pTos - > x . iVal = rc ;
/* Invalidate any prior representation */
MemObjSetType ( pTos , MEMOBJ_BOOL ) ;
} else {
if ( rc ) {
/* Jump to the desired location */
pc = pInstr - > iP2 - 1 ;
VmPopOperand ( & pTos , 1 ) ;
}
}
break ;
}
/* OP_LT P1 P2 P3
*
* Pop the top two elements from the stack . If the second element ( the top of stack )
* is less than the first ( next on stack ) , then jump to instruction P2 . Otherwise
* continue to the next instruction . In other words , jump if pNos < pTos .
* If P2 is zero , do not jump . Instead , push a boolean 1 ( TRUE ) onto the
* stack if the jump would have been taken , or a 0 ( FALSE ) if not .
*
*/
/* OP_LE P1 P2 P3
*
* Pop the top two elements from the stack . If the second element ( the top of stack )
* is less than or equal to the first ( next on stack ) , then jump to instruction P2 .
* Otherwise continue to the next instruction . In other words , jump if pNos < pTos .
* If P2 is zero , do not jump . Instead , push a boolean 1 ( TRUE ) onto the
* stack if the jump would have been taken , or a 0 ( FALSE ) if not .
*
*/
case PH7_OP_LT :
case PH7_OP_LE : {
ph7_value * pNos = & pTos [ - 1 ] ;
/* Perform the comparison and act accordingly */
2018-07-12 13:26:32 +02:00
# ifdef UNTRUST
2018-07-12 17:24:46 +02:00
if ( pNos < pStack ) {
goto Abort ;
}
2018-07-12 13:26:32 +02:00
# endif
2018-07-12 17:24:46 +02:00
rc = PH7_MemObjCmp ( pNos , pTos , FALSE , 0 ) ;
if ( pInstr - > iOp = = PH7_OP_LE ) {
rc = rc < 1 ;
} else {
rc = rc < 0 ;
}
VmPopOperand ( & pTos , 1 ) ;
if ( ! pInstr - > iP2 ) {
/* Push comparison result without taking the jump */
PH7_MemObjRelease ( pTos ) ;
pTos - > x . iVal = rc ;
/* Invalidate any prior representation */
MemObjSetType ( pTos , MEMOBJ_BOOL ) ;
} else {
if ( rc ) {
/* Jump to the desired location */
pc = pInstr - > iP2 - 1 ;
VmPopOperand ( & pTos , 1 ) ;
}
}
break ;
2018-07-12 13:26:32 +02:00
}
2018-07-12 17:24:46 +02:00
/* OP_GT P1 P2 P3
*
* Pop the top two elements from the stack . If the second element ( the top of stack )
* is greater than the first ( next on stack ) , then jump to instruction P2 . Otherwise
* continue to the next instruction . In other words , jump if pNos < pTos .
* If P2 is zero , do not jump . Instead , push a boolean 1 ( TRUE ) onto the
* stack if the jump would have been taken , or a 0 ( FALSE ) if not .
*
*/
/* OP_GE P1 P2 P3
*
* Pop the top two elements from the stack . If the second element ( the top of stack )
* is greater than or equal to the first ( next on stack ) , then jump to instruction P2 .
* Otherwise continue to the next instruction . In other words , jump if pNos < pTos .
* If P2 is zero , do not jump . Instead , push a boolean 1 ( TRUE ) onto the
* stack if the jump would have been taken , or a 0 ( FALSE ) if not .
*
*/
case PH7_OP_GT :
case PH7_OP_GE : {
ph7_value * pNos = & pTos [ - 1 ] ;
/* Perform the comparison and act accordingly */
2018-07-12 13:26:32 +02:00
# ifdef UNTRUST
2018-07-12 17:24:46 +02:00
if ( pNos < pStack ) {
goto Abort ;
}
2018-07-12 13:26:32 +02:00
# endif
2018-07-12 17:24:46 +02:00
rc = PH7_MemObjCmp ( pNos , pTos , FALSE , 0 ) ;
if ( pInstr - > iOp = = PH7_OP_GE ) {
rc = rc > = 0 ;
} else {
rc = rc > 0 ;
}
VmPopOperand ( & pTos , 1 ) ;
if ( ! pInstr - > iP2 ) {
/* Push comparison result without taking the jump */
PH7_MemObjRelease ( pTos ) ;
pTos - > x . iVal = rc ;
/* Invalidate any prior representation */
MemObjSetType ( pTos , MEMOBJ_BOOL ) ;
} else {
if ( rc ) {
/* Jump to the desired location */
pc = pInstr - > iP2 - 1 ;
VmPopOperand ( & pTos , 1 ) ;
}
}
break ;
}
/*
* OP_LOAD_EXCEPTION * P2 P3
* Push an exception in the corresponding container so that
* it can be thrown later by the OP_THROW instruction .
*/
case PH7_OP_LOAD_EXCEPTION : {
ph7_exception * pException = ( ph7_exception * ) pInstr - > p3 ;
VmFrame * pFrame ;
SySetPut ( & pVm - > aException , ( const void * ) & pException ) ;
/* Create the exception frame */
rc = VmEnterFrame ( & ( * pVm ) , 0 , 0 , & pFrame ) ;
if ( rc ! = SXRET_OK ) {
2018-09-03 16:16:32 +02:00
PH7_VmMemoryError ( & ( * pVm ) ) ;
2018-07-12 17:24:46 +02:00
}
/* Mark the special frame */
pFrame - > iFlags | = VM_FRAME_EXCEPTION ;
pFrame - > iExceptionJump = pInstr - > iP2 ;
/* Point to the frame that trigger the exception */
pFrame = pFrame - > pParent ;
while ( pFrame - > pParent & & ( pFrame - > iFlags & VM_FRAME_EXCEPTION ) ) {
pFrame = pFrame - > pParent ;
}
pException - > pFrame = pFrame ;
break ;
2018-07-12 13:26:32 +02:00
}
2018-07-12 17:24:46 +02:00
/*
* OP_POP_EXCEPTION * * P3
* Pop a previously pushed exception from the corresponding container .
*/
case PH7_OP_POP_EXCEPTION : {
ph7_exception * pException = ( ph7_exception * ) pInstr - > p3 ;
if ( SySetUsed ( & pVm - > aException ) > 0 ) {
ph7_exception * * apException ;
/* Pop the loaded exception */
apException = ( ph7_exception * * ) SySetBasePtr ( & pVm - > aException ) ;
if ( pException = = apException [ SySetUsed ( & pVm - > aException ) - 1 ] ) {
( void ) SySetPop ( & pVm - > aException ) ;
}
}
pException - > pFrame = 0 ;
/* Leave the exception frame */
VmLeaveFrame ( & ( * pVm ) ) ;
break ;
}
/*
* OP_THROW * P2 *
* Throw an user exception .
*/
case PH7_OP_THROW : {
VmFrame * pFrame = pVm - > pFrame ;
sxu32 nJump = pInstr - > iP2 ;
# ifdef UNTRUST
if ( pTos < pStack ) {
goto Abort ;
}
# endif
while ( pFrame - > pParent & & ( pFrame - > iFlags & VM_FRAME_EXCEPTION ) ) {
/* Safely ignore the exception frame */
pFrame = pFrame - > pParent ;
}
/* Tell the upper layer that an exception was thrown */
pFrame - > iFlags | = VM_FRAME_THROW ;
2019-05-21 14:49:36 +02:00
if ( pTos - > nType & MEMOBJ_OBJ ) {
2018-07-12 17:24:46 +02:00
ph7_class_instance * pThis = ( ph7_class_instance * ) pTos - > x . pOther ;
ph7_class * pException ;
/* Make sure the loaded object is an instance of the 'Exception' base class.
*/
pException = PH7_VmExtractClass ( & ( * pVm ) , " Exception " , sizeof ( " Exception " ) - 1 , TRUE , 0 ) ;
if ( pException = = 0 | | ! VmInstanceOf ( pThis - > pClass , pException ) ) {
/* Exceptions must be valid objects derived from the Exception base class */
rc = VmUncaughtException ( & ( * pVm ) , pThis ) ;
if ( rc = = SXERR_ABORT ) {
/* Abort processing immediately */
goto Abort ;
}
} else {
/* Throw the exception */
rc = VmThrowException ( & ( * pVm ) , pThis ) ;
if ( rc = = SXERR_ABORT ) {
/* Abort processing immediately */
goto Abort ;
}
}
} else {
/* Expecting a class instance */
VmUncaughtException ( & ( * pVm ) , 0 ) ;
if ( rc = = SXERR_ABORT ) {
/* Abort processing immediately */
goto Abort ;
}
2018-07-12 13:26:32 +02:00
}
2018-07-12 17:24:46 +02:00
/* Pop the top entry */
VmPopOperand ( & pTos , 1 ) ;
/* Perform an unconditional jump */
pc = nJump - 1 ;
break ;
2018-07-12 13:26:32 +02:00
}
2018-07-27 08:24:53 +02:00
/*
* OP_CLASS_INIT P1 P2 P3
* Perform additional class initialization , by adding base classes
* and interfaces to its definition .
*/
case PH7_OP_CLASS_INIT :
{
2018-07-27 21:05:54 +02:00
ph7_class_info * pClassInfo = ( ph7_class_info * ) pInstr - > p3 ;
2018-07-27 17:42:12 +02:00
ph7_class * pClass = PH7_VmExtractClass ( pVm , pClassInfo - > sName . zString , pClassInfo - > sName . nByte , FALSE , 0 ) ;
2018-07-27 17:01:58 +02:00
ph7_class * pBase = 0 ;
2018-07-27 08:24:53 +02:00
if ( pInstr - > iP1 ) {
/* This class inherits from other classes */
SyString * apExtends ;
2018-07-27 17:01:58 +02:00
while ( SySetGetNextEntry ( & pClassInfo - > sExtends , ( void * * ) & apExtends ) = = SXRET_OK ) {
pBase = PH7_VmExtractClass ( pVm , apExtends - > zString , apExtends - > nByte , FALSE , 0 ) ;
if ( pBase = = 0 ) {
/* Non-existent base class */
2018-09-04 08:54:48 +02:00
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR , " Call to non-existent base class '%z' " , & apExtends - > zString ) ;
2018-07-27 17:01:58 +02:00
} else if ( pBase - > iFlags & PH7_CLASS_INTERFACE ) {
/* Trying to inherit from interface */
2018-09-04 08:54:48 +02:00
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR , " Class '%z' cannot inherit from interface '%z' " , & pClass - > sName . zString , & apExtends - > zString ) ;
2018-07-27 17:01:58 +02:00
} else if ( pBase - > iFlags & PH7_CLASS_FINAL ) {
/* Trying to inherit from final class */
2018-09-04 08:54:48 +02:00
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR , " Class '%z' cannot inherit from final class '%z' " , & pClass - > sName . zString , & apExtends - > zString ) ;
2018-07-27 17:01:58 +02:00
}
2018-07-27 20:01:45 +02:00
rc = PH7_ClassInherit ( pVm , pClass , pBase ) ;
2018-07-27 17:42:12 +02:00
if ( rc ! = SXRET_OK ) {
break ;
}
2018-07-27 08:24:53 +02:00
}
}
if ( pInstr - > iP2 ) {
/* This class implements some interfaces */
SyString * apImplements ;
2018-07-27 17:01:58 +02:00
while ( SySetGetNextEntry ( & pClassInfo - > sImplements , ( void * * ) & apImplements ) = = SXRET_OK ) {
pBase = PH7_VmExtractClass ( pVm , apImplements - > zString , apImplements - > nByte , FALSE , 0 ) ;
if ( pBase = = 0 ) {
/* Non-existent interface */
2018-09-04 08:54:48 +02:00
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR , " Call to non-existent interface '%z' " , & apImplements - > zString ) ;
2018-07-27 17:01:58 +02:00
} else if ( ( pBase - > iFlags & PH7_CLASS_INTERFACE ) = = 0 ) {
2018-07-27 18:52:32 +02:00
/* Trying to implement a class */
2018-09-04 08:54:48 +02:00
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR , " Class '%z' cannot implement a class '%z' " , & pClass - > sName . zString , & apImplements - > zString ) ;
2018-07-27 17:01:58 +02:00
}
2019-03-20 09:24:30 +01:00
rc = PH7_ClassImplement ( pVm , pClass , pBase ) ;
2018-07-27 17:42:12 +02:00
if ( rc ! = SXRET_OK ) {
break ;
}
2018-07-27 08:24:53 +02:00
}
}
break ;
}
/*
2018-07-27 23:28:34 +02:00
* OP_INTERFACE_INIT P1 * P3
2018-07-27 08:24:53 +02:00
* Perform additional interface initialization , by adding base interfaces
* to its definition .
*/
case PH7_OP_INTERFACE_INIT :
{
2018-07-27 23:28:34 +02:00
ph7_class_info * pClassInfo = ( ph7_class_info * ) pInstr - > p3 ;
ph7_class * pClass = PH7_VmExtractClass ( pVm , pClassInfo - > sName . zString , pClassInfo - > sName . nByte , FALSE , 0 ) ;
ph7_class * pBase = 0 ;
if ( pInstr - > iP1 ) {
/* This interface inherits from other interface */
SyString * apExtends ;
while ( SySetGetNextEntry ( & pClassInfo - > sExtends , ( void * * ) & apExtends ) = = SXRET_OK ) {
pBase = PH7_VmExtractClass ( pVm , apExtends - > zString , apExtends - > nByte , FALSE , 0 ) ;
if ( pBase = = 0 ) {
/* Non-existent base interface */
2018-09-04 08:54:48 +02:00
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR , " Call to non-existent base interface '%z' " , & apExtends - > zString ) ;
2018-07-27 23:28:34 +02:00
} else if ( ( pBase - > iFlags & PH7_CLASS_INTERFACE ) = = 0 ) {
/* Trying to inherit from class */
2018-09-04 08:54:48 +02:00
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR , " Interface '%z' cannot inherit from class '%z' " , & pClass - > sName . zString , & apExtends - > zString ) ;
2018-07-27 23:28:34 +02:00
}
rc = PH7_ClassInterfaceInherit ( pClass , pBase ) ;
if ( rc ! = SXRET_OK ) {
break ;
}
}
}
2018-07-27 08:24:53 +02:00
break ;
}
2018-07-12 17:24:46 +02:00
/*
* OP_FOREACH_INIT * P2 P3
* Prepare a foreach step .
*/
case PH7_OP_FOREACH_INIT : {
ph7_foreach_info * pInfo = ( ph7_foreach_info * ) pInstr - > p3 ;
void * pName ;
2018-07-12 13:26:32 +02:00
# ifdef UNTRUST
2018-07-12 17:24:46 +02:00
if ( pTos < pStack ) {
goto Abort ;
}
2018-07-12 13:26:32 +02:00
# endif
2019-04-30 23:38:59 +02:00
/* Make sure we are dealing with an array or an object */
2019-05-21 14:49:36 +02:00
if ( ( pTos - > nType & MEMOBJ_HASHMAP ) = = 0 | | SyStringLength ( & pInfo - > sValue ) < 1 ) {
2018-07-12 17:24:46 +02:00
/* Jump out of the loop */
2019-05-21 14:49:36 +02:00
if ( ( pTos - > nType & MEMOBJ_NULL ) = = 0 ) {
2019-04-30 23:38:59 +02:00
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_WARNING , " Invalid argument supplied for the foreach statement, expecting an array " ) ;
2018-07-12 17:24:46 +02:00
}
pc = pInstr - > iP2 - 1 ;
} else {
2019-04-30 23:59:02 +02:00
/* Prepare the hashmap */
ph7_hashmap * pMap = ( ph7_hashmap * ) pTos - > x . pOther ;
/* Reset the internal loop cursor */
PH7_HashmapResetLoopCursor ( pMap ) ;
/* Store an array in a loop pointer */
pInfo - > pMap = pMap ;
pMap - > iRef + + ;
2018-07-12 17:24:46 +02:00
}
VmPopOperand ( & pTos , 1 ) ;
break ;
2018-07-12 13:26:32 +02:00
}
2018-07-12 17:24:46 +02:00
/*
* OP_FOREACH_STEP * P2 P3
* Perform a foreach step . Jump to P2 at the end of the step .
*/
case PH7_OP_FOREACH_STEP : {
ph7_foreach_info * pInfo = ( ph7_foreach_info * ) pInstr - > p3 ;
2019-05-01 12:24:20 +02:00
ph7_value * pTmp , * pValue ;
2018-07-12 17:24:46 +02:00
VmFrame * pFrame ;
pFrame = pVm - > pFrame ;
while ( pFrame - > pParent & & ( pFrame - > iFlags & VM_FRAME_EXCEPTION ) ) {
/* Safely ignore the exception frame */
pFrame = pFrame - > pParent ;
}
2019-04-30 23:59:02 +02:00
ph7_hashmap * pMap = pInfo - > pMap ;
2019-04-30 23:38:59 +02:00
ph7_hashmap_node * pNode ;
/* Extract the current node value */
pNode = PH7_HashmapGetNextEntry ( pMap ) ;
if ( pNode = = 0 ) {
/* No more entry to process */
pc = pInstr - > iP2 - 1 ; /* Jump to this destination */
/* Automatically reset the loop cursor */
PH7_HashmapResetLoopCursor ( pMap ) ;
/* Cleanup the mess left behind */
PH7_HashmapUnref ( pMap ) ;
2018-07-12 17:24:46 +02:00
} else {
2019-05-01 12:24:20 +02:00
PH7_MemObjInit ( & ( * pVm ) , & pTmp ) ;
2019-04-30 23:38:59 +02:00
if ( SyStringLength ( & pInfo - > sKey ) > 0 ) {
2019-05-01 18:29:57 +02:00
ph7_value * pKey = VmExtractMemObj ( & ( * pVm ) , & pInfo - > sKey , FALSE ) ;
2019-05-01 09:51:33 +02:00
if ( pKey = = 0 ) {
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR , " Variable '$%z' undeclared (first use in this method/closure) " , & pInfo - > sKey ) ;
2018-07-12 17:24:46 +02:00
}
2019-05-01 12:24:20 +02:00
PH7_HashmapExtractNodeKey ( pNode , & pTmp ) ;
if ( PH7_MemObjSafeStore ( & pTmp , pKey ) ! = SXRET_OK ) {
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR , " Cannot assign a value of incompatible type to variable '$%z' " , & pInfo - > sKey ) ;
}
2018-07-12 17:24:46 +02:00
}
2019-04-30 23:38:59 +02:00
/* Make a copy of the entry value */
2019-05-01 18:29:57 +02:00
pValue = VmExtractMemObj ( & ( * pVm ) , & pInfo - > sValue , FALSE ) ;
2019-05-01 09:51:33 +02:00
if ( pValue = = 0 ) {
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR , " Variable '$%z' undeclared (first use in this method/closure) " , & pInfo - > sValue ) ;
2018-07-12 13:26:32 +02:00
}
2019-05-01 12:24:20 +02:00
PH7_HashmapExtractNodeValue ( pNode , & pTmp , TRUE ) ;
if ( PH7_MemObjSafeStore ( & pTmp , pValue ) ! = SXRET_OK ) {
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR , " Cannot assign a value of incompatible type to variable '$%z' " , & pInfo - > sValue ) ;
}
2018-07-12 13:26:32 +02:00
}
2018-07-12 17:24:46 +02:00
break ;
2018-07-12 13:26:32 +02:00
}
2018-07-12 17:24:46 +02:00
/*
* OP_MEMBER P1 P2
* Load class attribute / method on the stack .
*/
case PH7_OP_MEMBER : {
ph7_class_instance * pThis ;
ph7_value * pNos ;
SyString sName ;
if ( ! pInstr - > iP1 ) {
pNos = & pTos [ - 1 ] ;
2018-07-12 13:26:32 +02:00
# ifdef UNTRUST
2018-07-12 17:24:46 +02:00
if ( pNos < pStack ) {
goto Abort ;
}
2018-07-12 13:26:32 +02:00
# endif
2019-05-21 14:49:36 +02:00
if ( pNos - > nType & MEMOBJ_OBJ ) {
2018-09-24 12:10:19 +02:00
if ( ! pNos - > x . pOther ) {
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR , " Call to non-instantiated object '$%z' " , & sName ) ;
}
2019-05-29 06:12:49 +02:00
ph7_class * pClass , * pDerived ;
2018-07-12 17:24:46 +02:00
/* Class already instantiated */
pThis = ( ph7_class_instance * ) pNos - > x . pOther ;
/* Point to the instantiated class */
pClass = pThis - > pClass ;
2019-05-23 08:27:56 +02:00
if ( pNos - > iFlags = = MEMOBJ_BASEOBJ | | pNos - > iFlags = = MEMOBJ_PARENTOBJ ) {
2019-05-08 08:26:48 +02:00
if ( pClass - > pBase = = 0 ) {
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR ,
" Attempt to call parent class from non-inheritance instance of class '%z' " , & pClass - > sName ) ;
}
2019-05-28 11:55:17 +02:00
if ( pNos - > iFlags = = MEMOBJ_BASEOBJ ) {
2019-05-28 11:51:13 +02:00
pClass = pClass - > pBase ;
}
2019-05-08 08:26:48 +02:00
}
2018-07-12 17:24:46 +02:00
/* Extract attribute name first */
SyStringInitFromBuf ( & sName , ( const char * ) SyBlobData ( & pTos - > sBlob ) , SyBlobLength ( & pTos - > sBlob ) ) ;
if ( pInstr - > iP2 ) {
/* Method call */
ph7_class_method * pMeth = 0 ;
if ( sName . nByte > 0 ) {
/* Extract the target method */
2019-05-29 06:12:49 +02:00
if ( pNos - > iFlags ! = MEMOBJ_PARENTOBJ ) {
pMeth = PH7_ClassExtractMethod ( pClass , sName . zString , sName . nByte ) ;
}
if ( pMeth = = 0 & & pNos - > iFlags ! = MEMOBJ_BASEOBJ ) {
/* Browse hashtable from the beginning */
SyHashResetLoopCursor ( & pClass - > hDerived ) ;
/* Search for appropriate class member */
SyHashEntry * pEntry ;
while ( ( pEntry = SyHashGetNextEntry ( & pClass - > hDerived ) ) ! = 0 ) {
pDerived = ( ph7_class * ) pEntry - > pUserData ;
pMeth = PH7_ClassExtractMethod ( pDerived , sName . zString , sName . nByte ) ;
if ( pMeth ) {
pClass = pDerived ;
break ;
}
}
}
2018-07-12 17:24:46 +02:00
}
if ( pMeth = = 0 ) {
2018-09-04 08:54:48 +02:00
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR , " Call to undefined method '%z->%z()' " ,
2018-07-12 17:24:46 +02:00
& pClass - > sName , & sName
) ;
} else {
2019-05-29 15:26:31 +02:00
if ( ! VmClassMemberAccess ( & ( * pVm ) , pMeth - > sFunc . pClass , pMeth - > iProtection ) ) {
2019-05-09 13:53:22 +02:00
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR ,
2019-05-29 18:56:57 +02:00
" Method '%z->%z()' is inaccessible due to its protection level " , & pMeth - > sFunc . pClass - > sName , & sName ) ;
2019-05-09 13:53:22 +02:00
}
2018-07-12 17:24:46 +02:00
/* Push method name on the stack */
PH7_MemObjRelease ( pTos ) ;
SyBlobAppend ( & pTos - > sBlob , SyStringData ( & pMeth - > sVmName ) , SyStringLength ( & pMeth - > sVmName ) ) ;
MemObjSetType ( pTos , MEMOBJ_STRING ) ;
}
pTos - > nIdx = SXU32_HIGH ;
} else {
/* Attribute access */
VmClassAttr * pObjAttr = 0 ;
SyHashEntry * pEntry ;
/* Extract the target attribute */
if ( sName . nByte > 0 ) {
2019-05-29 10:45:30 +02:00
SyHashResetLoopCursor ( & pThis - > hAttr ) ;
while ( ( pEntry = SyHashGetNextEntry ( & pThis - > hAttr ) ) ! = 0 ) {
2018-07-12 17:24:46 +02:00
pObjAttr = ( VmClassAttr * ) pEntry - > pUserData ;
2019-05-29 10:45:30 +02:00
if ( SyStrncmp ( pObjAttr - > pAttr - > sName . zString , sName . zString , sName . nByte ) = = 0 ) {
if ( pNos - > iFlags ! = MEMOBJ_PARENTOBJ & & pObjAttr - > pAttr - > pClass = = pClass ) {
break ;
} else if ( pNos - > iFlags ! = MEMOBJ_BASEOBJ & & pObjAttr - > pAttr - > iProtection ! = PH7_CLASS_PROT_PRIVATE ) {
SyHashEntry * pDerived = SyHashGet ( & pClass - > hDerived , ( const void * ) pObjAttr - > pAttr - > pClass - > sName . zString , pObjAttr - > pAttr - > pClass - > sName . nByte ) ;
if ( pDerived ! = 0 ) {
ph7_class * pSub = ( ph7_class * ) pDerived - > pUserData ;
if ( pObjAttr - > pAttr - > pClass = = pSub ) {
break ;
}
}
}
}
pObjAttr = 0 ;
2018-07-12 17:24:46 +02:00
}
}
if ( pObjAttr = = 0 ) {
/* No such attribute,load null */
2018-09-04 08:54:48 +02:00
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR , " Undefined class attribute '%z->%z',PH7 is loading NULL " ,
2018-07-12 17:24:46 +02:00
& pClass - > sName , & sName ) ;
}
VmPopOperand ( & pTos , 1 ) ;
/* TICKET 1433-49: Deffer garbage collection until attribute loading.
* This is due to the following case :
* ( new TestClass ( ) ) - > foo ;
*/
pThis - > iRef + + ;
PH7_MemObjRelease ( pTos ) ;
pTos - > nIdx = SXU32_HIGH ; /* Assume we are loading a constant */
if ( pObjAttr ) {
ph7_value * pValue = 0 ; /* cc warning */
/* Check attribute access */
2019-05-29 15:26:31 +02:00
if ( VmClassMemberAccess ( & ( * pVm ) , pClass , pObjAttr - > pAttr - > iProtection ) ) {
2018-07-12 17:24:46 +02:00
/* Load attribute */
pValue = ( ph7_value * ) SySetAt ( & pVm - > aMemObj , pObjAttr - > nIdx ) ;
if ( pValue ) {
if ( pThis - > iRef < 2 ) {
/* Perform a store operation,rather than a load operation since
* the class instance ' $ this ' will be deleted shortly .
*/
PH7_MemObjStore ( pValue , pTos ) ;
} else {
/* Simple load */
PH7_MemObjLoad ( pValue , pTos ) ;
}
if ( ( pObjAttr - > pAttr - > iFlags & PH7_CLASS_ATTR_CONSTANT ) = = 0 ) {
if ( pThis - > iRef > 1 ) {
/* Load attribute index */
pTos - > nIdx = pObjAttr - > nIdx ;
}
}
}
2019-05-29 10:45:30 +02:00
} else {
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR ,
2019-05-29 18:56:57 +02:00
" Class attribute '%z->%z' is inaccessible due to its protection level " , & pClass - > sName , & pObjAttr - > pAttr - > sName ) ;
2018-07-12 17:24:46 +02:00
}
}
/* Safely unreference the object */
PH7_ClassInstanceUnref ( pThis ) ;
}
} else {
2018-09-04 08:54:48 +02:00
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR , " Expecting class instance as left operand " ) ;
2018-07-12 13:26:32 +02:00
}
2018-07-12 17:24:46 +02:00
} else {
/* Static member access using class name */
pNos = pTos ;
pThis = 0 ;
if ( ! pInstr - > p3 ) {
SyStringInitFromBuf ( & sName , ( const char * ) SyBlobData ( & pTos - > sBlob ) , SyBlobLength ( & pTos - > sBlob ) ) ;
pNos - - ;
# ifdef UNTRUST
if ( pNos < pStack ) {
goto Abort ;
}
# endif
} else {
/* Attribute name already computed */
SyStringInitFromBuf ( & sName , pInstr - > p3 , SyStrlen ( ( const char * ) pInstr - > p3 ) ) ;
2018-07-12 13:26:32 +02:00
}
2019-05-21 14:49:36 +02:00
if ( pNos - > nType & ( MEMOBJ_STRING | MEMOBJ_OBJ ) ) {
2018-07-12 17:24:46 +02:00
ph7_class * pClass = 0 ;
2019-05-21 14:49:36 +02:00
if ( pNos - > nType & MEMOBJ_OBJ ) {
2018-07-12 17:24:46 +02:00
/* Class already instantiated */
pThis = ( ph7_class_instance * ) pNos - > x . pOther ;
pClass = pThis - > pClass ;
pThis - > iRef + + ; /* Deffer garbage collection */
} else {
/* Try to extract the target class */
if ( SyBlobLength ( & pNos - > sBlob ) > 0 ) {
pClass = PH7_VmExtractClass ( & ( * pVm ) , ( const char * ) SyBlobData ( & pNos - > sBlob ) ,
SyBlobLength ( & pNos - > sBlob ) , FALSE , 0 ) ;
}
}
if ( pClass = = 0 ) {
/* Undefined class */
2018-09-04 08:54:48 +02:00
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR , " Call to undefined class '%.*s' " ,
2018-07-12 17:24:46 +02:00
SyBlobLength ( & pNos - > sBlob ) , ( const char * ) SyBlobData ( & pNos - > sBlob )
) ;
} else {
if ( pInstr - > iP2 ) {
/* Method call */
ph7_class_method * pMeth = 0 ;
if ( sName . nByte > 0 & & ( pClass - > iFlags & PH7_CLASS_INTERFACE ) = = 0 ) {
/* Extract the target method */
pMeth = PH7_ClassExtractMethod ( pClass , sName . zString , sName . nByte ) ;
}
2018-07-30 17:08:25 +02:00
if ( pMeth = = 0 | | ( pMeth - > iFlags & PH7_CLASS_ATTR_VIRTUAL ) ) {
2018-07-12 17:24:46 +02:00
if ( pMeth ) {
2019-05-29 18:56:57 +02:00
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR , " Cannot call virtual method '%z::%z' " ,
2018-07-12 17:24:46 +02:00
& pClass - > sName , & sName
) ;
} else {
2018-09-04 08:54:48 +02:00
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR , " Undefined class static method '%z::%z' " ,
2018-07-12 17:24:46 +02:00
& pClass - > sName , & sName
) ;
}
/* Pop the method name from the stack */
if ( ! pInstr - > p3 ) {
VmPopOperand ( & pTos , 1 ) ;
}
PH7_MemObjRelease ( pTos ) ;
2019-05-09 06:18:49 +02:00
} else if ( ( pMeth - > iFlags & PH7_CLASS_ATTR_STATIC ) = = 0 ) {
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR , " Attempt to call statically a non-static method '%z::%z()' " ,
& pClass - > sName , & sName ) ;
2018-07-12 17:24:46 +02:00
} else {
/* Push method name on the stack */
PH7_MemObjRelease ( pTos ) ;
SyBlobAppend ( & pTos - > sBlob , SyStringData ( & pMeth - > sVmName ) , SyStringLength ( & pMeth - > sVmName ) ) ;
MemObjSetType ( pTos , MEMOBJ_STRING ) ;
}
pTos - > nIdx = SXU32_HIGH ;
} else {
/* Attribute access */
ph7_class_attr * pAttr = 0 ;
/* Extract the target attribute */
if ( sName . nByte > 0 ) {
pAttr = PH7_ClassExtractAttribute ( pClass , sName . zString , sName . nByte ) ;
}
if ( pAttr = = 0 ) {
/* No such attribute,load null */
2018-09-04 08:54:48 +02:00
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR , " Undefined class attribute '%z::%z' " ,
2018-07-12 17:24:46 +02:00
& pClass - > sName , & sName ) ;
}
/* Pop the attribute name from the stack */
if ( ! pInstr - > p3 ) {
VmPopOperand ( & pTos , 1 ) ;
}
PH7_MemObjRelease ( pTos ) ;
pTos - > nIdx = SXU32_HIGH ;
if ( pAttr ) {
if ( ( pAttr - > iFlags & ( PH7_CLASS_ATTR_STATIC | PH7_CLASS_ATTR_CONSTANT ) ) = = 0 ) {
/* Access to a non static attribute */
2018-09-04 08:54:48 +02:00
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR , " Access to a non-static class attribute '%z::%z' " ,
2018-07-12 17:24:46 +02:00
& pClass - > sName , & pAttr - > sName
) ;
} else {
ph7_value * pValue ;
/* Check if the access to the attribute is allowed */
2019-05-29 15:26:31 +02:00
if ( VmClassMemberAccess ( & ( * pVm ) , pClass , pAttr - > iProtection ) ) {
2018-07-12 17:24:46 +02:00
/* Load the desired attribute */
pValue = ( ph7_value * ) SySetAt ( & pVm - > aMemObj , pAttr - > nIdx ) ;
if ( pValue ) {
PH7_MemObjLoad ( pValue , pTos ) ;
if ( pAttr - > iFlags & PH7_CLASS_ATTR_STATIC ) {
/* Load index number */
pTos - > nIdx = pAttr - > nIdx ;
}
}
2019-05-29 15:26:31 +02:00
} else {
2019-05-29 18:56:57 +02:00
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR , " Class attribute '%z::$%z' is inaccessible due to its protection level " ,
2019-05-29 15:26:31 +02:00
& pClass - > sName , & pAttr - > sName ) ;
2018-07-12 17:24:46 +02:00
}
}
2018-07-12 13:26:32 +02:00
}
}
2018-07-12 17:24:46 +02:00
if ( pThis ) {
/* Safely unreference the object */
PH7_ClassInstanceUnref ( pThis ) ;
}
}
} else {
2019-04-24 18:30:24 +02:00
/* Invalid class */
2018-09-04 08:54:48 +02:00
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR , " Invalid class name " ) ;
2018-07-12 13:26:32 +02:00
}
}
2018-07-12 17:24:46 +02:00
break ;
2018-07-12 13:26:32 +02:00
}
2018-07-12 17:24:46 +02:00
/*
* OP_NEW P1 * * *
* Create a new class instance ( Object in the PHP jargon ) and push that object on the stack .
*/
case PH7_OP_NEW : {
ph7_value * pArg = & pTos [ - pInstr - > iP1 ] ; /* Constructor arguments (if available) */
ph7_class * pClass = 0 ;
ph7_class_instance * pNew ;
2019-05-21 14:49:36 +02:00
if ( ( pTos - > nType & MEMOBJ_STRING ) & & SyBlobLength ( & pTos - > sBlob ) > 0 ) {
2018-07-12 17:24:46 +02:00
/* Try to extract the desired class */
pClass = PH7_VmExtractClass ( & ( * pVm ) , ( const char * ) SyBlobData ( & pTos - > sBlob ) ,
2018-07-30 17:08:25 +02:00
SyBlobLength ( & pTos - > sBlob ) , TRUE /* Only loadable class but not 'interface' or 'virtual' class*/ , 0 ) ;
2019-05-21 14:49:36 +02:00
} else if ( pTos - > nType & MEMOBJ_OBJ ) {
2018-07-12 17:24:46 +02:00
/* Take the base class from the loaded instance */
pClass = ( ( ph7_class_instance * ) pTos - > x . pOther ) - > pClass ;
2018-07-12 13:26:32 +02:00
}
2018-07-12 17:24:46 +02:00
if ( pClass = = 0 ) {
/* No such class */
2018-09-04 08:54:48 +02:00
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR , " Class '%.*s' is not defined " ,
2018-07-12 17:24:46 +02:00
SyBlobLength ( & pTos - > sBlob ) , ( const char * ) SyBlobData ( & pTos - > sBlob )
) ;
} else {
ph7_class_method * pCons ;
/* Create a new class instance */
pNew = PH7_NewClassInstance ( & ( * pVm ) , pClass ) ;
if ( pNew = = 0 ) {
2018-09-03 16:16:32 +02:00
PH7_VmMemoryError ( & ( * pVm ) ) ;
2018-07-12 13:26:32 +02:00
}
2018-07-12 17:24:46 +02:00
/* Check if a constructor is available */
pCons = PH7_ClassExtractMethod ( pClass , " __construct " , sizeof ( " __construct " ) - 1 ) ;
if ( pCons ) {
/* Call the class constructor */
SySetReset ( & aArg ) ;
while ( pArg < pTos ) {
SySetPut ( & aArg , ( const void * ) & pArg ) ;
pArg + + ;
}
PH7_VmCallClassMethod ( & ( * pVm ) , pNew , pCons , 0 , ( int ) SySetUsed ( & aArg ) , ( ph7_value * * ) SySetBasePtr ( & aArg ) ) ;
/* TICKET 1433-52: Unsetting $this in the constructor body */
if ( pNew - > iRef < 1 ) {
pNew - > iRef = 1 ;
}
}
if ( pInstr - > iP1 > 0 ) {
/* Pop given arguments */
VmPopOperand ( & pTos , pInstr - > iP1 ) ;
}
PH7_MemObjRelease ( pTos ) ;
pTos - > x . pOther = pNew ;
MemObjSetType ( pTos , MEMOBJ_OBJ ) ;
2018-07-12 13:26:32 +02:00
}
2018-07-12 17:24:46 +02:00
break ;
2018-07-12 13:26:32 +02:00
}
2018-07-12 17:24:46 +02:00
/*
* OP_CLONE * * *
2018-07-23 17:10:48 +02:00
* Perform a clone operation .
2018-07-12 17:24:46 +02:00
*/
case PH7_OP_CLONE : {
ph7_class_instance * pSrc , * pClone ;
2018-07-12 13:26:32 +02:00
# ifdef UNTRUST
2018-07-12 17:24:46 +02:00
if ( pTos < pStack ) {
goto Abort ;
}
2018-07-12 13:26:32 +02:00
# endif
2018-07-12 17:24:46 +02:00
/* Make sure we are dealing with a class instance */
2019-05-21 14:49:36 +02:00
if ( ( pTos - > nType & MEMOBJ_OBJ ) = = 0 | | pTos - > x . pOther = = 0 ) {
2018-09-04 08:54:48 +02:00
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR ,
2018-09-03 16:16:32 +02:00
" Clone: Expecting a class instance as left operand " ) ;
2018-07-12 17:24:46 +02:00
}
/* Point to the source */
pSrc = ( ph7_class_instance * ) pTos - > x . pOther ;
/* Perform the clone operation */
pClone = PH7_CloneClassInstance ( pSrc ) ;
PH7_MemObjRelease ( pTos ) ;
if ( pClone = = 0 ) {
2018-09-03 16:16:32 +02:00
PH7_VmMemoryError ( & ( * pVm ) ) ;
2018-07-12 17:24:46 +02:00
} else {
/* Load the cloned object */
pTos - > x . pOther = pClone ;
MemObjSetType ( pTos , MEMOBJ_OBJ ) ;
}
break ;
}
/*
* OP_SWITCH * * P3
* This is the bytecode implementation of the complex switch ( ) PHP construct .
*/
case PH7_OP_SWITCH : {
ph7_switch * pSwitch = ( ph7_switch * ) pInstr - > p3 ;
ph7_case_expr * aCase , * pCase ;
ph7_value sValue , sCaseValue ;
sxu32 n , nEntry ;
2018-07-12 13:26:32 +02:00
# ifdef UNTRUST
2018-07-12 17:24:46 +02:00
if ( pSwitch = = 0 | | pTos < pStack ) {
goto Abort ;
}
2018-07-12 13:26:32 +02:00
# endif
2018-07-12 17:24:46 +02:00
/* Point to the case table */
aCase = ( ph7_case_expr * ) SySetBasePtr ( & pSwitch - > aCaseExpr ) ;
nEntry = SySetUsed ( & pSwitch - > aCaseExpr ) ;
/* Select the appropriate case block to execute */
PH7_MemObjInit ( pVm , & sValue ) ;
PH7_MemObjInit ( pVm , & sCaseValue ) ;
for ( n = 0 ; n < nEntry ; + + n ) {
pCase = & aCase [ n ] ;
PH7_MemObjLoad ( pTos , & sValue ) ;
/* Execute the case expression first */
VmLocalExec ( pVm , & pCase - > aByteCode , & sCaseValue ) ;
/* Compare the two expression */
rc = PH7_MemObjCmp ( & sValue , & sCaseValue , FALSE , 0 ) ;
PH7_MemObjRelease ( & sValue ) ;
PH7_MemObjRelease ( & sCaseValue ) ;
if ( rc = = 0 ) {
/* Value match,jump to this block */
pc = pCase - > nStart - 1 ;
break ;
}
2018-07-12 13:26:32 +02:00
}
2018-07-12 17:24:46 +02:00
VmPopOperand ( & pTos , 1 ) ;
if ( n > = nEntry ) {
2018-07-23 17:10:48 +02:00
/* No appropriate case to execute,jump to the default case */
2018-07-12 17:24:46 +02:00
if ( pSwitch - > nDefault > 0 ) {
pc = pSwitch - > nDefault - 1 ;
} else {
/* No default case,jump out of this switch */
pc = pSwitch - > nOut - 1 ;
}
}
break ;
}
/*
2018-08-12 12:27:15 +02:00
* OP_CALL P1 P2 *
2018-07-12 17:24:46 +02:00
* Call a PHP or a foreign function and push the return value of the called
* function on the stack .
*/
case PH7_OP_CALL : {
ph7_value * pArg = & pTos [ - pInstr - > iP1 ] ;
SyHashEntry * pEntry ;
SyString sName ;
2018-12-20 19:37:03 +01:00
VmInstr * bInstr = & aInstr [ pc - 1 ] ;
2018-07-12 17:24:46 +02:00
/* Extract function name */
2019-05-21 14:49:36 +02:00
if ( pTos - > nType & MEMOBJ_STRING & & bInstr - > iOp = = PH7_OP_LOADV ) {
2018-12-20 19:37:03 +01:00
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR , " Calling a non-callable object " ) ;
2019-05-21 14:49:36 +02:00
} else if ( ( pTos - > nType & ( MEMOBJ_CALL | MEMOBJ_STRING ) ) = = 0 ) {
if ( pTos - > nType & MEMOBJ_HASHMAP ) {
2018-07-12 17:24:46 +02:00
ph7_value sResult ;
SySetReset ( & aArg ) ;
while ( pArg < pTos ) {
SySetPut ( & aArg , ( const void * ) & pArg ) ;
pArg + + ;
}
PH7_MemObjInit ( pVm , & sResult ) ;
/* May be a class instance and it's static method */
PH7_VmCallUserFunction ( pVm , pTos , ( int ) SySetUsed ( & aArg ) , ( ph7_value * * ) SySetBasePtr ( & aArg ) , & sResult ) ;
SySetReset ( & aArg ) ;
/* Pop given arguments */
if ( pInstr - > iP1 > 0 ) {
VmPopOperand ( & pTos , pInstr - > iP1 ) ;
}
/* Copy result */
PH7_MemObjStore ( & sResult , pTos ) ;
PH7_MemObjRelease ( & sResult ) ;
} else {
2019-05-21 14:49:36 +02:00
if ( pTos - > nType & MEMOBJ_OBJ ) {
2018-07-12 17:24:46 +02:00
ph7_class_instance * pThis = ( ph7_class_instance * ) pTos - > x . pOther ;
/* Call the magic method '__invoke' if available */
PH7_ClassInstanceCallMagicMethod ( & ( * pVm ) , pThis - > pClass , pThis , " __invoke " , sizeof ( " __invoke " ) - 1 , 0 ) ;
} else {
/* Raise exception: Invalid function name */
2018-09-04 08:54:48 +02:00
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_WARNING , " Invalid function name " ) ;
2018-07-12 17:24:46 +02:00
}
/* Pop given arguments */
if ( pInstr - > iP1 > 0 ) {
VmPopOperand ( & pTos , pInstr - > iP1 ) ;
}
/* Assume a null return value so that the program continue it's execution normally */
PH7_MemObjRelease ( pTos ) ;
}
break ;
2018-07-12 13:26:32 +02:00
}
2018-07-12 17:24:46 +02:00
SyStringInitFromBuf ( & sName , SyBlobData ( & pTos - > sBlob ) , SyBlobLength ( & pTos - > sBlob ) ) ;
/* Check for a compiled function first */
pEntry = SyHashGet ( & pVm - > hFunction , ( const void * ) sName . zString , sName . nByte ) ;
if ( pEntry ) {
ph7_vm_func_arg * aFormalArg ;
ph7_class_instance * pThis ;
2019-05-10 23:45:32 +02:00
ph7_class * pClass ;
2018-07-12 17:24:46 +02:00
ph7_value * pFrameStack ;
ph7_vm_func * pVmFunc ;
ph7_class * pSelf ;
VmFrame * pFrame ;
ph7_value * pObj ;
VmSlot sArg ;
sxu32 n ;
/* initialize fields */
pVmFunc = ( ph7_vm_func * ) pEntry - > pUserData ;
pThis = 0 ;
pSelf = 0 ;
2019-05-10 23:45:32 +02:00
pClass = 0 ;
2018-07-12 17:24:46 +02:00
if ( pVmFunc - > iFlags & VM_FUNC_CLASS_METHOD ) {
ph7_class_method * pMeth ;
/* Class method call */
ph7_value * pTarget = & pTos [ - 1 ] ;
2019-05-21 14:49:36 +02:00
if ( pTarget > = pStack & & ( pTarget - > nType & ( MEMOBJ_STRING | MEMOBJ_OBJ | MEMOBJ_NULL ) ) ) {
2018-07-12 17:24:46 +02:00
/* Extract the 'this' pointer */
2019-05-21 14:49:36 +02:00
if ( pTarget - > nType & MEMOBJ_OBJ ) {
2018-07-12 17:24:46 +02:00
/* Instance already loaded */
pThis = ( ph7_class_instance * ) pTarget - > x . pOther ;
2019-05-21 21:41:16 +02:00
pThis - > iRef + = 3 ;
2019-05-10 23:45:32 +02:00
pClass = pThis - > pClass ;
2019-05-23 08:27:56 +02:00
pThis - > pClass = pVmFunc - > pClass ;
2018-07-12 17:24:46 +02:00
pSelf = pThis - > pClass ;
}
if ( pSelf = = 0 ) {
2019-05-21 14:49:36 +02:00
if ( ( pTarget - > nType & MEMOBJ_STRING ) & & SyBlobLength ( & pTarget - > sBlob ) > 0 ) {
2018-07-12 17:24:46 +02:00
/* "Late Static Binding" class name */
pSelf = PH7_VmExtractClass ( & ( * pVm ) , ( const char * ) SyBlobData ( & pTarget - > sBlob ) ,
SyBlobLength ( & pTarget - > sBlob ) , FALSE , 0 ) ;
}
if ( pSelf = = 0 ) {
pSelf = ( ph7_class * ) pVmFunc - > pUserData ;
}
}
VmPopOperand ( & pTos , 1 ) ;
PH7_MemObjRelease ( pTos ) ;
/* Synchronize pointers */
pArg = & pTos [ - pInstr - > iP1 ] ;
/* TICKET 1433-50: This is a very very unlikely scenario that occurs when the 'genius'
* user have already computed the random generated unique class method name
* and tries to call it outside it ' s context [ i . e : global scope ] . In that
2018-07-23 17:10:48 +02:00
* case we have to synchronize pointers to avoid stack underflow .
2018-07-12 17:24:46 +02:00
*/
while ( pArg < pStack ) {
pArg + + ;
}
}
}
/* Check The recursion limit */
if ( pVm - > nRecursionDepth > pVm - > nMaxDepth ) {
2018-09-04 08:54:48 +02:00
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_WARNING ,
2018-09-03 16:16:32 +02:00
" Recursion limit reached while invoking user function '%z', PH7 will set a NULL return value " ,
2018-07-12 17:24:46 +02:00
& pVmFunc - > sName ) ;
/* Pop given arguments */
if ( pInstr - > iP1 > 0 ) {
VmPopOperand ( & pTos , pInstr - > iP1 ) ;
}
/* Assume a null return value so that the program continue it's execution normally */
PH7_MemObjRelease ( pTos ) ;
break ;
}
2018-08-12 12:27:15 +02:00
/* Select an appropriate function to call, if not entry point */
if ( pInstr - > iP2 = = 0 ) {
pVmFunc = VmOverload ( & ( * pVm ) , pVmFunc , pArg , ( int ) ( pTos - pArg ) ) ;
}
2018-07-12 17:24:46 +02:00
/* Extract the formal argument set */
aFormalArg = ( ph7_vm_func_arg * ) SySetBasePtr ( & pVmFunc - > aArgs ) ;
/* Create a new VM frame */
rc = VmEnterFrame ( & ( * pVm ) , pVmFunc , pThis , & pFrame ) ;
if ( rc ! = SXRET_OK ) {
/* Raise exception: Out of memory */
2018-09-03 16:16:32 +02:00
PH7_VmMemoryError ( & ( * pVm ) ) ;
2018-07-12 17:24:46 +02:00
}
2019-05-08 08:26:48 +02:00
if ( pVmFunc - > iFlags & VM_FUNC_CLASS_METHOD ) {
2019-05-21 21:41:16 +02:00
/* Install the '$base' variable */
static const SyString sBase = { " base " , sizeof ( " base " ) - 1 } ;
pObj = VmCreateMemObj ( & ( * pVm ) , & sBase , TRUE ) ;
if ( pObj ) {
/* Reflect the change */
pObj - > iFlags = MEMOBJ_BASEOBJ ;
pObj - > x . pOther = pThis ;
MemObjSetType ( pObj , MEMOBJ_OBJ ) ;
}
2019-05-08 08:26:48 +02:00
/* Install the '$parent' variable */
static const SyString sParent = { " parent " , sizeof ( " parent " ) - 1 } ;
pObj = VmCreateMemObj ( & ( * pVm ) , & sParent , TRUE ) ;
if ( pObj ) {
/* Reflect the change */
2019-05-21 19:18:52 +02:00
pObj - > iFlags = MEMOBJ_PARENTOBJ ;
2019-05-08 08:26:48 +02:00
pObj - > x . pOther = pThis ;
MemObjSetType ( pObj , MEMOBJ_OBJ ) ;
}
2018-07-12 17:24:46 +02:00
/* Install the '$this' variable */
static const SyString sThis = { " this " , sizeof ( " this " ) - 1 } ;
2019-05-08 08:26:48 +02:00
pObj = VmCreateMemObj ( & ( * pVm ) , & sThis , TRUE ) ;
2018-07-12 17:24:46 +02:00
if ( pObj ) {
/* Reflect the change */
2019-05-21 19:18:52 +02:00
pObj - > iFlags = MEMOBJ_THISOBJ ;
2018-07-12 17:24:46 +02:00
pObj - > x . pOther = pThis ;
MemObjSetType ( pObj , MEMOBJ_OBJ ) ;
}
}
if ( SySetUsed ( & pVmFunc - > aStatic ) > 0 ) {
ph7_vm_func_static_var * pStatic , * aStatic ;
/* Install static variables */
aStatic = ( ph7_vm_func_static_var * ) SySetBasePtr ( & pVmFunc - > aStatic ) ;
for ( n = 0 ; n < SySetUsed ( & pVmFunc - > aStatic ) ; + + n ) {
pStatic = & aStatic [ n ] ;
if ( pStatic - > nIdx = = SXU32_HIGH ) {
2019-04-03 09:02:49 +02:00
ph7_value * pVal ;
2018-07-12 17:24:46 +02:00
/* Initialize the static variables */
pObj = VmReserveMemObj ( & ( * pVm ) , & pStatic - > nIdx ) ;
2019-04-03 09:02:49 +02:00
pVal = PH7_ReserveMemObj ( & ( * pVm ) ) ;
if ( pObj = = 0 | | pVal = = 0 ) {
PH7_VmMemoryError ( & ( * pVm ) ) ;
}
2019-04-03 13:43:31 +02:00
MemObjSetType ( pObj , pStatic - > iFlags ) ;
2019-04-03 09:02:49 +02:00
if ( SySetUsed ( & pStatic - > aByteCode ) > 0 ) {
/* Evaluate initialization expression (Any complex expression) */
VmLocalExec ( & ( * pVm ) , & pStatic - > aByteCode , pVal ) ;
2019-04-03 13:43:31 +02:00
rc = PH7_MemObjSafeStore ( pVal , pObj ) ;
if ( rc ! = SXRET_OK ) {
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR , " Cannot assign a value of incompatible type to variable '$%z' " , & pStatic - > sName ) ;
}
2019-05-21 14:49:36 +02:00
} else if ( pObj - > nType & MEMOBJ_HASHMAP ) {
2019-04-04 18:18:11 +02:00
ph7_hashmap * pMap ;
pMap = PH7_NewHashmap ( & ( * pVm ) , 0 , 0 ) ;
if ( pMap = = 0 ) {
PH7_VmMemoryError ( & ( * pVm ) ) ;
}
pObj - > x . pOther = pMap ;
2018-07-12 17:24:46 +02:00
}
2019-04-03 09:02:49 +02:00
pObj - > nIdx = pStatic - > nIdx ;
2018-07-12 17:24:46 +02:00
}
/* Install in the current frame */
SyHashInsert ( & pFrame - > hVar , SyStringData ( & pStatic - > sName ) , SyStringLength ( & pStatic - > sName ) ,
SX_INT_TO_PTR ( pStatic - > nIdx ) ) ;
}
}
/* Push arguments in the local frame */
n = 0 ;
while ( pArg < pTos ) {
if ( n < SySetUsed ( & pVmFunc - > aArgs ) ) {
2019-05-21 14:49:36 +02:00
if ( ( pArg - > nType & MEMOBJ_NULL ) & & SySetUsed ( & aFormalArg [ n ] . aByteCode ) > 0 ) {
2018-07-12 17:24:46 +02:00
/* NULL values are redirected to default arguments */
rc = VmLocalExec ( & ( * pVm ) , & aFormalArg [ n ] . aByteCode , pArg ) ;
if ( rc = = PH7_ABORT ) {
goto Abort ;
}
}
/* Make sure the given arguments are of the correct type */
if ( aFormalArg [ n ] . nType > 0 ) {
if ( aFormalArg [ n ] . nType = = SXU32_HIGH ) {
/* Argument must be a class instance [i.e: object] */
SyString * pName = & aFormalArg [ n ] . sClass ;
ph7_class * pClass ;
/* Try to extract the desired class */
pClass = PH7_VmExtractClass ( & ( * pVm ) , pName - > zString , pName - > nByte , TRUE , 0 ) ;
if ( pClass ) {
2019-05-21 14:49:36 +02:00
if ( ( pArg - > nType & MEMOBJ_OBJ ) = = 0 ) {
if ( ( pArg - > nType & MEMOBJ_NULL ) = = 0 ) {
2018-09-14 22:27:38 +02:00
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR ,
" Argument %u passed to function '%z()' must be an object of type '%z' " ,
n + 1 , & pVmFunc - > sName , pName ) ;
2018-07-12 17:24:46 +02:00
}
} else {
ph7_class_instance * pThis = ( ph7_class_instance * ) pArg - > x . pOther ;
/* Make sure the object is an instance of the given class */
2019-04-10 18:32:53 +02:00
if ( pThis = = 0 | | ! VmInstanceOf ( pThis - > pClass , pClass ) ) {
2018-09-17 22:06:53 +02:00
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR ,
2018-09-14 22:27:38 +02:00
" Argument %u passed to function '%z()' must be an object of type '%z' " ,
n + 1 , & pVmFunc - > sName , pName ) ;
2018-07-12 17:24:46 +02:00
}
}
}
2019-04-05 19:59:15 +02:00
} else {
ph7_value * pTmp = PH7_ReserveMemObj ( & ( * pVm ) ) ;
2019-05-21 14:49:36 +02:00
pTmp - > nType = aFormalArg [ n ] . nType ;
2019-04-05 19:59:15 +02:00
rc = PH7_MemObjSafeStore ( pArg , pTmp ) ;
if ( rc ! = SXRET_OK ) {
2018-09-16 20:02:34 +02:00
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR ,
" Argument %u of '%z()' does not match the data type " , n + 1 , & pVmFunc - > sName ) ;
}
2019-05-21 14:49:36 +02:00
pArg - > nType = pTmp - > nType ;
2019-04-05 19:59:15 +02:00
PH7_MemObjRelease ( pTmp ) ;
2018-07-12 17:24:46 +02:00
}
}
if ( aFormalArg [ n ] . iFlags & VM_FUNC_ARG_BY_REF ) {
/* Pass by reference */
if ( pArg - > nIdx = = SXU32_HIGH ) {
2019-05-01 18:19:04 +02:00
/* Expecting a variable, not a constant, raise an exception */
2019-05-21 14:49:36 +02:00
if ( ( pArg - > nType & ( MEMOBJ_HASHMAP | MEMOBJ_OBJ | MEMOBJ_RES | MEMOBJ_NULL ) ) = = 0 ) {
2019-04-05 20:14:08 +02:00
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR ,
" Function '%z', %d argument: Pass by reference, expecting a variable not a "
" constant " , & pVmFunc - > sName , n + 1 ) ;
2018-07-12 17:24:46 +02:00
}
/* Switch to pass by value */
2019-05-01 18:19:04 +02:00
pObj = VmCreateMemObj ( & ( * pVm ) , & aFormalArg [ n ] . sName , FALSE ) ;
2018-07-12 17:24:46 +02:00
} else {
SyHashEntry * pRefEntry ;
/* Install the referenced variable in the private function frame */
pRefEntry = SyHashGet ( & pFrame - > hVar , SyStringData ( & aFormalArg [ n ] . sName ) , SyStringLength ( & aFormalArg [ n ] . sName ) ) ;
if ( pRefEntry = = 0 ) {
SyHashInsert ( & pFrame - > hVar , SyStringData ( & aFormalArg [ n ] . sName ) ,
SyStringLength ( & aFormalArg [ n ] . sName ) , SX_INT_TO_PTR ( pArg - > nIdx ) ) ;
sArg . nIdx = pArg - > nIdx ;
sArg . pUserData = 0 ;
SySetPut ( & pFrame - > sArg , ( const void * ) & sArg ) ;
}
pObj = 0 ;
}
} else {
2019-04-05 20:12:55 +02:00
/* Pass by value, make a copy of the given argument */
2019-05-01 18:19:04 +02:00
pObj = VmCreateMemObj ( & ( * pVm ) , & aFormalArg [ n ] . sName , FALSE ) ;
2018-07-12 17:24:46 +02:00
}
} else {
char zName [ 32 ] ;
SyString sName ;
/* Set a dummy name */
sName . nByte = SyBufferFormat ( zName , sizeof ( zName ) , " [%u]apArg " , n ) ;
sName . zString = zName ;
2018-07-23 17:10:48 +02:00
/* Anonymous argument */
2019-05-01 18:29:57 +02:00
pObj = VmExtractMemObj ( & ( * pVm ) , & sName , TRUE ) ;
2018-07-12 17:24:46 +02:00
}
if ( pObj ) {
PH7_MemObjStore ( pArg , pObj ) ;
/* Insert argument index */
sArg . nIdx = pObj - > nIdx ;
sArg . pUserData = 0 ;
SySetPut ( & pFrame - > sArg , ( const void * ) & sArg ) ;
}
PH7_MemObjRelease ( pArg ) ;
pArg + + ;
+ + n ;
}
/* Set up closure environment */
if ( pVmFunc - > iFlags & VM_FUNC_CLOSURE ) {
ph7_vm_func_closure_env * aEnv , * pEnv ;
ph7_value * pValue ;
sxu32 n ;
aEnv = ( ph7_vm_func_closure_env * ) SySetBasePtr ( & pVmFunc - > aClosureEnv ) ;
for ( n = 0 ; n < SySetUsed ( & pVmFunc - > aClosureEnv ) ; + + n ) {
pEnv = & aEnv [ n ] ;
2019-05-21 14:49:36 +02:00
if ( ( pEnv - > iFlags & VM_FUNC_ARG_IGNORE ) & & ( pEnv - > sValue . nType & MEMOBJ_NULL ) ) {
2018-07-12 17:24:46 +02:00
/* Do not install null value */
continue ;
}
2019-05-01 18:19:04 +02:00
pValue = VmCreateMemObj ( pVm , & pEnv - > sName , FALSE ) ;
2018-07-12 17:24:46 +02:00
if ( pValue = = 0 ) {
continue ;
}
/* Invalidate any prior representation */
PH7_MemObjRelease ( pValue ) ;
/* Duplicate bound variable value */
PH7_MemObjStore ( & pEnv - > sValue , pValue ) ;
}
}
/* Process default values */
while ( n < SySetUsed ( & pVmFunc - > aArgs ) ) {
if ( SySetUsed ( & aFormalArg [ n ] . aByteCode ) > 0 ) {
2019-05-01 18:19:04 +02:00
pObj = VmCreateMemObj ( & ( * pVm ) , & aFormalArg [ n ] . sName , FALSE ) ;
2018-07-12 17:24:46 +02:00
if ( pObj ) {
/* Evaluate the default value and extract it's result */
rc = VmLocalExec ( & ( * pVm ) , & aFormalArg [ n ] . aByteCode , pObj ) ;
if ( rc = = PH7_ABORT ) {
goto Abort ;
}
2019-04-10 18:32:53 +02:00
if ( aFormalArg [ n ] . nType = = SXU32_HIGH ) {
/* Argument must be a class instance [i.e: object] */
SyString * pName = & aFormalArg [ n ] . sClass ;
ph7_class * pClass ;
/* Try to extract the desired class */
pClass = PH7_VmExtractClass ( & ( * pVm ) , pName - > zString , pName - > nByte , TRUE , 0 ) ;
if ( pClass ) {
2019-05-21 14:49:36 +02:00
if ( ( pObj - > nType & MEMOBJ_OBJ ) = = 0 ) {
if ( ( pObj - > nType & MEMOBJ_NULL ) = = 0 ) {
2019-04-10 18:32:53 +02:00
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR ,
" Default value for argument %u of '%z()' must be an object of type '%z' " ,
n + 1 , & pVmFunc - > sName , pName ) ;
}
} else {
ph7_class_instance * pThis = ( ph7_class_instance * ) pObj - > x . pOther ;
/* Make sure the object is an instance of the given class */
if ( pThis = = 0 | | ! VmInstanceOf ( pThis - > pClass , pClass ) ) {
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR ,
" Default value for argument %u of '%z()' must be an object of type '%z' " ,
n + 1 , & pVmFunc - > sName , pName ) ;
}
}
}
} else {
ph7_value * pTmp = PH7_ReserveMemObj ( & ( * pVm ) ) ;
2019-05-21 14:49:36 +02:00
pTmp - > nType = aFormalArg [ n ] . nType ;
2019-04-10 18:32:53 +02:00
/* Make sure the default argument is of the correct type */
rc = PH7_MemObjSafeStore ( pObj , pTmp ) ;
if ( rc ! = SXRET_OK ) {
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR ,
" Default value for argument %u of '%z()' does not match the data type " , n + 1 , & pVmFunc - > sName ) ;
}
2019-05-21 14:49:36 +02:00
pObj - > nType = pTmp - > nType ;
2019-04-10 18:32:53 +02:00
PH7_MemObjRelease ( pTmp ) ;
/* Insert argument index */
sArg . nIdx = pObj - > nIdx ;
sArg . pUserData = 0 ;
SySetPut ( & pFrame - > sArg , ( const void * ) & sArg ) ;
2018-09-15 14:13:46 +02:00
}
2018-07-12 17:24:46 +02:00
}
}
+ + n ;
2018-07-12 13:26:32 +02:00
}
2018-07-12 17:24:46 +02:00
/* Pop arguments,function name from the operand stack and assume the function
* does not return anything .
*/
PH7_MemObjRelease ( pTos ) ;
pTos = & pTos [ - pInstr - > iP1 ] ;
2018-09-16 19:52:24 +02:00
/* Mark current frame as active */
pFrame - > iFlags | = VM_FRAME_ACTIVE ;
2018-07-12 17:24:46 +02:00
/* Allocate a new operand stack and evaluate the function body */
pFrameStack = VmNewOperandStack ( & ( * pVm ) , SySetUsed ( & pVmFunc - > aByteCode ) ) ;
if ( pFrameStack = = 0 ) {
/* Raise exception: Out of memory */
2018-09-03 16:16:32 +02:00
PH7_VmMemoryError ( & ( * pVm ) ) ;
2018-07-12 13:26:32 +02:00
}
2018-07-12 17:24:46 +02:00
if ( pSelf ) {
/* Push class name */
SySetPut ( & pVm - > aSelf , ( const void * ) & pSelf ) ;
2018-07-12 13:26:32 +02:00
}
2018-07-12 17:24:46 +02:00
/* Increment nesting level */
pVm - > nRecursionDepth + + ;
/* Execute function body */
rc = VmByteCodeExec ( & ( * pVm ) , ( VmInstr * ) SySetBasePtr ( & pVmFunc - > aByteCode ) , pFrameStack , - 1 , pTos , & n , FALSE ) ;
/* Decrement nesting level */
pVm - > nRecursionDepth - - ;
if ( pSelf ) {
/* Pop class name */
( void ) SySetPop ( & pVm - > aSelf ) ;
}
/* Cleanup the mess left behind */
if ( ( pVmFunc - > iFlags & VM_FUNC_REF_RETURN ) & & rc = = SXRET_OK ) {
/* Return by reference,reflect that */
if ( n ! = SXU32_HIGH ) {
VmSlot * aSlot = ( VmSlot * ) SySetBasePtr ( & pFrame - > sLocal ) ;
sxu32 i ;
/* Make sure the referenced object is not a local variable */
for ( i = 0 ; i < SySetUsed ( & pFrame - > sLocal ) ; + + i ) {
if ( n = = aSlot [ i ] . nIdx ) {
pObj = ( ph7_value * ) SySetAt ( & pVm - > aMemObj , n ) ;
n = SXU32_HIGH ;
break ;
}
2018-07-12 13:26:32 +02:00
}
}
2018-07-12 17:24:46 +02:00
pTos - > nIdx = n ;
2018-07-12 13:26:32 +02:00
}
2018-07-12 17:24:46 +02:00
/* Cleanup the mess left behind */
if ( rc ! = PH7_ABORT & & ( ( pFrame - > iFlags & VM_FRAME_THROW ) | | rc = = PH7_EXCEPTION ) ) {
/* An exception was throw in this frame */
pFrame = pFrame - > pParent ;
if ( ! is_callback & & pFrame - > pParent & & ( pFrame - > iFlags & VM_FRAME_EXCEPTION ) & & pFrame - > iExceptionJump > 0 ) {
2018-07-23 17:10:48 +02:00
/* Pop the result */
2018-07-12 17:24:46 +02:00
VmPopOperand ( & pTos , 1 ) ;
/* Jump to this destination */
pc = pFrame - > iExceptionJump - 1 ;
rc = PH7_OK ;
} else {
if ( pFrame - > pParent ) {
rc = PH7_EXCEPTION ;
} else {
/* Continue normal execution */
rc = PH7_OK ;
}
}
2018-07-12 13:26:32 +02:00
}
2018-07-12 17:24:46 +02:00
/* Free the operand stack */
SyMemBackendFree ( & pVm - > sAllocator , pFrameStack ) ;
/* Leave the frame */
VmLeaveFrame ( & ( * pVm ) ) ;
2019-05-23 08:27:56 +02:00
if ( pClass ! = 0 & & pClass ! = pThis - > pClass ) {
2019-05-10 23:45:32 +02:00
/* Restore original class */
pThis - > pClass = pClass ;
}
2018-07-12 17:24:46 +02:00
if ( rc = = PH7_ABORT ) {
2018-07-22 22:47:00 +02:00
/* Abort processing immediately */
2018-07-12 17:24:46 +02:00
goto Abort ;
} else if ( rc = = PH7_EXCEPTION ) {
goto Exception ;
2018-07-12 13:26:32 +02:00
}
2018-07-12 17:24:46 +02:00
} else {
ph7_user_func * pFunc ;
ph7_context sCtx ;
ph7_value sRet ;
/* Look for an installed foreign function */
pEntry = SyHashGet ( & pVm - > hHostFunction , ( const void * ) sName . zString , sName . nByte ) ;
if ( pEntry = = 0 ) {
/* Call to undefined function */
2018-09-04 08:54:48 +02:00
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR , " Call to undefined function '%z()' " , & sName ) ;
2018-07-12 17:24:46 +02:00
}
pFunc = ( ph7_user_func * ) pEntry - > pUserData ;
/* Start collecting function arguments */
SySetReset ( & aArg ) ;
while ( pArg < pTos ) {
SySetPut ( & aArg , ( const void * ) & pArg ) ;
pArg + + ;
}
/* Assume a null return value */
PH7_MemObjInit ( & ( * pVm ) , & sRet ) ;
/* Init the call context */
VmInitCallContext ( & sCtx , & ( * pVm ) , pFunc , & sRet , 0 ) ;
/* Call the foreign function */
rc = pFunc - > xFunc ( & sCtx , ( int ) SySetUsed ( & aArg ) , ( ph7_value * * ) SySetBasePtr ( & aArg ) ) ;
/* Release the call context */
VmReleaseCallContext ( & sCtx ) ;
if ( rc = = PH7_ABORT ) {
goto Abort ;
}
if ( pInstr - > iP1 > 0 ) {
/* Pop function name and arguments */
VmPopOperand ( & pTos , pInstr - > iP1 ) ;
}
/* Save foreign function return value */
PH7_MemObjStore ( & sRet , pTos ) ;
PH7_MemObjRelease ( & sRet ) ;
2018-07-12 13:26:32 +02:00
}
2018-07-12 17:24:46 +02:00
break ;
2018-07-12 13:26:32 +02:00
}
2018-07-12 17:24:46 +02:00
/*
* OP_CONSUME : P1 * *
* Consume ( Invoke the installed VM output consumer callback ) and POP P1 elements from the stack .
*/
case PH7_OP_CONSUME : {
ph7_output_consumer * pCons = & pVm - > sVmConsumer ;
ph7_value * pCur , * pOut = pTos ;
pOut = & pTos [ - pInstr - > iP1 + 1 ] ;
pCur = pOut ;
/* Start the consume process */
while ( pOut < = pTos ) {
/* Force a string cast */
2019-05-21 14:49:36 +02:00
if ( ( pOut - > nType & MEMOBJ_STRING ) = = 0 ) {
2018-07-12 17:24:46 +02:00
PH7_MemObjToString ( pOut ) ;
2018-07-12 13:26:32 +02:00
}
2018-07-12 17:24:46 +02:00
if ( SyBlobLength ( & pOut - > sBlob ) > 0 ) {
/*SyBlobNullAppend(&pOut->sBlob);*/
/* Invoke the output consumer callback */
rc = pCons - > xConsumer ( SyBlobData ( & pOut - > sBlob ) , SyBlobLength ( & pOut - > sBlob ) , pCons - > pUserData ) ;
SyBlobRelease ( & pOut - > sBlob ) ;
if ( rc = = SXERR_ABORT ) {
/* Output consumer callback request an operation abort. */
goto Abort ;
}
}
pOut + + ;
2018-07-12 13:26:32 +02:00
}
2018-07-12 17:24:46 +02:00
pTos = & pCur [ - 1 ] ;
break ;
2018-07-12 13:26:32 +02:00
}
} /* Switch() */
pc + + ; /* Next instruction in the stream */
} /* For(;;) */
Done :
SySetRelease ( & aArg ) ;
return SXRET_OK ;
Abort :
SySetRelease ( & aArg ) ;
2018-07-12 17:24:46 +02:00
while ( pTos > = pStack ) {
2018-07-12 13:26:32 +02:00
PH7_MemObjRelease ( pTos ) ;
pTos - - ;
}
return PH7_ABORT ;
Exception :
SySetRelease ( & aArg ) ;
2018-07-12 17:24:46 +02:00
while ( pTos > = pStack ) {
2018-07-12 13:26:32 +02:00
PH7_MemObjRelease ( pTos ) ;
pTos - - ;
}
return PH7_EXCEPTION ;
}
/*
* Execute as much of a local PH7 bytecode program as we can then return .
* This function is a wrapper around [ VmByteCodeExec ( ) ] .
* See block - comment on that function for additional information .
*/
2018-07-12 17:24:46 +02:00
static sxi32 VmLocalExec ( ph7_vm * pVm , SySet * pByteCode , ph7_value * pResult ) {
2018-07-12 13:26:32 +02:00
ph7_value * pStack ;
sxi32 rc ;
/* Allocate a new operand stack */
2018-07-12 17:24:46 +02:00
pStack = VmNewOperandStack ( & ( * pVm ) , SySetUsed ( pByteCode ) ) ;
if ( pStack = = 0 ) {
2018-07-12 13:26:32 +02:00
return SXERR_MEM ;
}
/* Execute the program */
2018-07-12 17:24:46 +02:00
rc = VmByteCodeExec ( & ( * pVm ) , ( VmInstr * ) SySetBasePtr ( pByteCode ) , pStack , - 1 , & ( * pResult ) , 0 , FALSE ) ;
2018-07-12 13:26:32 +02:00
/* Free the operand stack */
2018-07-12 17:24:46 +02:00
SyMemBackendFree ( & pVm - > sAllocator , pStack ) ;
2018-07-12 13:26:32 +02:00
/* Execution result */
return rc ;
}
/*
* Invoke any installed shutdown callbacks .
* Shutdown callbacks are kept in a stack and are registered using one
* or more calls to [ register_shutdown_function ( ) ] .
* These callbacks are invoked by the virtual machine when the program
* execution ends .
* Refer to the implementation of [ register_shutdown_function ( ) ] for
* additional information .
*/
2018-07-12 17:24:46 +02:00
static void VmInvokeShutdownCallbacks ( ph7_vm * pVm ) {
2018-07-12 13:26:32 +02:00
VmShutdownCB * pEntry ;
ph7_value * apArg [ 10 ] ;
2018-07-12 17:24:46 +02:00
sxu32 n , nEntry ;
2018-07-12 13:26:32 +02:00
int i ;
/* Point to the stack of registered callbacks */
nEntry = SySetUsed ( & pVm - > aShutdown ) ;
2018-07-12 17:24:46 +02:00
for ( i = 0 ; i < ( int ) SX_ARRAYSIZE ( apArg ) ; i + + ) {
2018-07-12 13:26:32 +02:00
apArg [ i ] = 0 ;
}
2018-07-12 17:24:46 +02:00
for ( n = 0 ; n < nEntry ; + + n ) {
pEntry = ( VmShutdownCB * ) SySetAt ( & pVm - > aShutdown , n ) ;
if ( pEntry ) {
2018-07-12 13:26:32 +02:00
/* Prepare callback arguments if any */
2018-07-12 17:24:46 +02:00
for ( i = 0 ; i < pEntry - > nArg ; i + + ) {
if ( i > = ( int ) SX_ARRAYSIZE ( apArg ) ) {
2018-07-12 13:26:32 +02:00
break ;
}
apArg [ i ] = & pEntry - > aArg [ i ] ;
}
/* Invoke the callback */
2018-07-12 17:24:46 +02:00
PH7_VmCallUserFunction ( & ( * pVm ) , & pEntry - > sCallback , pEntry - > nArg , apArg , 0 ) ;
/*
2018-07-12 13:26:32 +02:00
* TICKET 1433 - 56 : Try re - access the same entry since the invoked
2018-07-12 17:24:46 +02:00
* callback may call [ register_shutdown_function ( ) ] in it ' s body .
2018-07-12 13:26:32 +02:00
*/
2018-07-12 17:24:46 +02:00
pEntry = ( VmShutdownCB * ) SySetAt ( & pVm - > aShutdown , n ) ;
if ( pEntry ) {
2018-07-12 13:26:32 +02:00
PH7_MemObjRelease ( & pEntry - > sCallback ) ;
2018-07-12 17:24:46 +02:00
for ( i = 0 ; i < pEntry - > nArg ; + + i ) {
2018-07-12 13:26:32 +02:00
PH7_MemObjRelease ( apArg [ i ] ) ;
}
}
}
}
SySetReset ( & pVm - > aShutdown ) ;
}
/*
* Execute as much of a PH7 bytecode program as we can then return .
* This function is a wrapper around [ VmByteCodeExec ( ) ] .
* See block - comment on that function for additional information .
*/
2018-07-12 17:24:46 +02:00
PH7_PRIVATE sxi32 PH7_VmByteCodeExec ( ph7_vm * pVm ) {
2018-08-12 12:52:35 +02:00
ph7_class * pClass ;
ph7_class_instance * pInstance ;
ph7_class_method * pMethod ;
2018-09-10 23:12:08 +02:00
ph7_value * pArgs , * sArgv ;
2018-08-27 19:32:17 +02:00
ph7_value pResult ;
2018-09-10 23:12:08 +02:00
const char * zStr , * zDup , * zParam ;
2018-07-12 13:26:32 +02:00
/* Make sure we are ready to execute this program */
2018-07-12 17:24:46 +02:00
if ( pVm - > nMagic ! = PH7_VM_RUN ) {
2018-09-05 13:28:20 +02:00
return ( pVm - > nMagic = = PH7_VM_EXEC | | pVm - > nMagic = = PH7_VM_INCL ) ? SXERR_LOCKED /* Locked VM */ : SXERR_CORRUPT ; /* Stale VM */
2018-07-12 13:26:32 +02:00
}
/* Set the execution magic number */
pVm - > nMagic = PH7_VM_EXEC ;
2018-08-12 12:52:35 +02:00
/* Execute the byte code */
2018-08-27 19:32:17 +02:00
VmByteCodeExec ( & ( * pVm ) , ( VmInstr * ) SySetBasePtr ( pVm - > pByteContainer ) , pVm - > aOps , - 1 , 0 , 0 , FALSE ) ;
2018-08-12 12:52:35 +02:00
/* Extract and instantiate the entry point */
pClass = PH7_VmExtractClass ( & ( * pVm ) , " Program " , 7 , TRUE /* Only loadable class but not 'interface' or 'virtual' class*/ , 0 ) ;
if ( ! pClass ) {
2018-09-04 08:54:48 +02:00
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR , " Cannot find an entry 'Program' class " ) ;
2018-08-12 12:52:35 +02:00
}
pInstance = PH7_NewClassInstance ( & ( * pVm ) , pClass ) ;
if ( pInstance = = 0 ) {
2018-09-03 16:16:32 +02:00
PH7_VmMemoryError ( & ( * pVm ) ) ;
2018-08-12 12:52:35 +02:00
}
/* Check if a constructor is available */
pMethod = PH7_ClassExtractMethod ( pClass , " __construct " , sizeof ( " __construct " ) - 1 ) ;
if ( pMethod ) {
/* Call the class constructor */
PH7_VmCallClassMethod ( & ( * pVm ) , pInstance , pMethod , 0 , 0 , 0 ) ;
}
2019-04-17 17:29:05 +02:00
/* Enable garbage collector */
pInstance - > iRef - - ;
2018-09-10 23:12:08 +02:00
pArgs = ph7_new_array ( & ( * pVm ) ) ;
sArgv = ph7_new_scalar ( & ( * pVm ) ) ;
if ( ! pArgs | | ! sArgv ) {
PH7_VmMemoryError ( & ( * pVm ) ) ;
}
if ( SyBlobLength ( & pVm - > sArgv ) > 0 ) {
zStr = ( const char * ) SyBlobData ( & pVm - > sArgv ) ;
zDup = SyMemBackendStrDup ( & pVm - > sAllocator , zStr , SyStrlen ( zStr ) ) ;
zParam = SyStrtok ( zDup , " " ) ;
while ( zParam ! = NULL ) {
ph7_value_string ( sArgv , zParam , SyStrlen ( zParam ) ) ;
ph7_array_add_elem ( pArgs , 0 , sArgv ) ;
ph7_value_reset_string_cursor ( sArgv ) ;
zParam = SyStrtok ( NULL , " " ) ;
}
}
2018-09-19 19:27:50 +02:00
/* Extract script entry point */
2018-08-12 12:52:35 +02:00
pMethod = PH7_ClassExtractMethod ( pClass , " main " , sizeof ( " main " ) - 1 ) ;
if ( ! pMethod ) {
2018-09-04 08:54:48 +02:00
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR , " Cannot find a program entry point 'Program::main()' " ) ;
2018-08-12 12:52:35 +02:00
}
2019-03-17 19:56:07 +01:00
if ( pMethod - > sFunc . nType ! = MEMOBJ_INT & & pMethod - > sFunc . nType ! = MEMOBJ_VOID ) {
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR , " The 'Program::main()' can only return an Integer or Void value " ) ;
}
2018-09-19 19:27:50 +02:00
/* A set of arguments is stored in array of strings */
2019-05-21 14:49:36 +02:00
pArgs - > nType | = MEMOBJ_STRING ;
2018-09-19 19:27:50 +02:00
/* Initialize variable for return value */
2018-08-27 20:23:08 +02:00
PH7_MemObjInit ( pVm , & pResult ) ;
2018-09-19 19:27:50 +02:00
/* Call entry point */
2018-09-10 23:12:08 +02:00
PH7_VmCallClassMethod ( & ( * pVm ) , pInstance , pMethod , & pResult , 1 , & pArgs ) ;
2018-08-27 19:32:17 +02:00
if ( ! pVm - > iExitStatus ) {
2019-03-17 18:49:22 +01:00
if ( pMethod - > sFunc . nType = = MEMOBJ_INT ) {
pVm - > iExitStatus = ph7_value_to_int ( & pResult ) ;
} else {
pVm - > iExitStatus = 0 ;
2019-03-17 18:56:17 +01:00
}
2018-08-27 19:32:17 +02:00
}
2018-07-12 13:26:32 +02:00
/* Invoke any shutdown callbacks */
VmInvokeShutdownCallbacks ( & ( * pVm ) ) ;
/*
* TICKET 1433 - 100 : Do not remove the PH7_VM_EXEC magic number
* so that any following call to [ ph7_vm_exec ( ) ] without calling
* [ ph7_vm_reset ( ) ] first would fail .
*/
return SXRET_OK ;
}
/*
* Invoke the installed VM output consumer callback to consume
* the desired message .
* Refer to the implementation of [ ph7_context_output ( ) ] defined
* in ' api . c ' for additional information .
*/
PH7_PRIVATE sxi32 PH7_VmOutputConsume (
ph7_vm * pVm , /* Target VM */
SyString * pString /* Message to output */
2018-07-12 17:24:46 +02:00
) {
2018-07-12 13:26:32 +02:00
ph7_output_consumer * pCons = & pVm - > sVmConsumer ;
sxi32 rc = SXRET_OK ;
/* Call the output consumer */
2018-07-12 17:24:46 +02:00
if ( pString - > nByte > 0 ) {
rc = pCons - > xConsumer ( ( const void * ) pString - > zString , pString - > nByte , pCons - > pUserData ) ;
2018-07-12 13:26:32 +02:00
}
return rc ;
}
/*
* Format a message and invoke the installed VM output consumer
* callback to consume the formatted message .
* Refer to the implementation of [ ph7_context_output_format ( ) ] defined
* in ' api . c ' for additional information .
*/
PH7_PRIVATE sxi32 PH7_VmOutputConsumeAp (
ph7_vm * pVm , /* Target VM */
const char * zFormat , /* Formatted message to output */
2018-07-12 17:24:46 +02:00
va_list ap /* Variable list of arguments */
) {
2018-07-12 13:26:32 +02:00
ph7_output_consumer * pCons = & pVm - > sVmConsumer ;
sxi32 rc = SXRET_OK ;
SyBlob sWorker ;
/* Format the message and call the output consumer */
2018-07-12 17:24:46 +02:00
SyBlobInit ( & sWorker , & pVm - > sAllocator ) ;
SyBlobFormatAp ( & sWorker , zFormat , ap ) ;
if ( SyBlobLength ( & sWorker ) > 0 ) {
2018-07-12 13:26:32 +02:00
/* Consume the formatted message */
2018-07-12 17:24:46 +02:00
rc = pCons - > xConsumer ( SyBlobData ( & sWorker ) , SyBlobLength ( & sWorker ) , pCons - > pUserData ) ;
2018-07-12 13:26:32 +02:00
}
/* Release the working buffer */
SyBlobRelease ( & sWorker ) ;
return rc ;
}
/*
* Return a string representation of the given PH7 OP code .
* This function never fail and always return a pointer
* to a null terminated string .
*/
2018-07-12 17:24:46 +02:00
static const char * VmInstrToString ( sxi32 nOp ) {
2018-09-01 20:28:16 +02:00
const char * zOp = " UNKNOWN " ;
2018-07-12 17:24:46 +02:00
switch ( nOp ) {
case PH7_OP_DONE :
2018-09-01 20:28:16 +02:00
zOp = " DONE " ;
2018-07-12 17:24:46 +02:00
break ;
case PH7_OP_HALT :
2018-09-01 20:28:16 +02:00
zOp = " HALT " ;
2018-07-12 17:24:46 +02:00
break ;
2019-04-15 19:18:29 +02:00
case PH7_OP_DECLARE :
zOp = " DECLARE " ;
break ;
2019-05-05 09:33:06 +02:00
case PH7_OP_LOADV :
zOp = " LOADV " ;
2018-07-12 17:24:46 +02:00
break ;
case PH7_OP_LOADC :
2018-09-01 20:28:16 +02:00
zOp = " LOADC " ;
2018-07-12 17:24:46 +02:00
break ;
case PH7_OP_LOAD_MAP :
2018-09-01 20:28:16 +02:00
zOp = " LOAD_MAP " ;
2018-07-12 17:24:46 +02:00
break ;
case PH7_OP_LOAD_IDX :
2018-09-01 20:28:16 +02:00
zOp = " LOAD_IDX " ;
2018-07-12 17:24:46 +02:00
break ;
case PH7_OP_LOAD_CLOSURE :
2018-09-01 20:28:16 +02:00
zOp = " LOAD_CLOSR " ;
2018-07-12 17:24:46 +02:00
break ;
case PH7_OP_NOOP :
2018-09-01 20:28:16 +02:00
zOp = " NOOP " ;
2018-07-12 17:24:46 +02:00
break ;
case PH7_OP_JMP :
2018-09-01 20:28:16 +02:00
zOp = " JMP " ;
2018-07-12 17:24:46 +02:00
break ;
2019-04-16 08:14:16 +02:00
case PH7_OP_JMPZ :
zOp = " JMPZ " ;
2018-07-12 17:24:46 +02:00
break ;
2019-04-16 08:14:16 +02:00
case PH7_OP_JMPNZ :
zOp = " JMPNZ " ;
2018-07-12 17:24:46 +02:00
break ;
2019-04-16 12:46:58 +02:00
case PH7_OP_JMPLFB :
zOp = " JMPLFB " ;
break ;
case PH7_OP_JMPLFE :
2019-05-01 20:24:37 +02:00
zOp = " JMPLFE " ;
2019-04-16 12:46:58 +02:00
break ;
2018-07-12 17:24:46 +02:00
case PH7_OP_POP :
2018-09-01 20:28:16 +02:00
zOp = " POP " ;
2018-07-12 17:24:46 +02:00
break ;
case PH7_OP_CVT_INT :
2018-09-01 20:28:16 +02:00
zOp = " CVT_INT " ;
2018-07-12 17:24:46 +02:00
break ;
case PH7_OP_CVT_STR :
2018-09-01 20:28:16 +02:00
zOp = " CVT_STR " ;
2018-07-12 17:24:46 +02:00
break ;
case PH7_OP_CVT_REAL :
2018-09-01 20:28:16 +02:00
zOp = " CVT_FLOAT " ;
2018-07-12 17:24:46 +02:00
break ;
case PH7_OP_CALL :
2018-09-01 20:28:16 +02:00
zOp = " CALL " ;
2018-07-12 17:24:46 +02:00
break ;
case PH7_OP_UMINUS :
2018-09-01 20:28:16 +02:00
zOp = " UMINUS " ;
2018-07-12 17:24:46 +02:00
break ;
case PH7_OP_UPLUS :
2018-09-01 20:28:16 +02:00
zOp = " UPLUS " ;
2018-07-12 17:24:46 +02:00
break ;
case PH7_OP_BITNOT :
2018-09-01 20:28:16 +02:00
zOp = " BITNOT " ;
2018-07-12 17:24:46 +02:00
break ;
case PH7_OP_LNOT :
2018-09-01 20:28:16 +02:00
zOp = " LOGNOT " ;
2018-07-12 17:24:46 +02:00
break ;
case PH7_OP_MUL :
2018-09-01 20:28:16 +02:00
zOp = " MUL " ;
2018-07-12 17:24:46 +02:00
break ;
case PH7_OP_DIV :
2018-09-01 20:28:16 +02:00
zOp = " DIV " ;
2018-07-12 17:24:46 +02:00
break ;
case PH7_OP_MOD :
2018-09-01 20:28:16 +02:00
zOp = " MOD " ;
2018-07-12 17:24:46 +02:00
break ;
case PH7_OP_ADD :
2018-09-01 20:28:16 +02:00
zOp = " ADD " ;
2018-07-12 17:24:46 +02:00
break ;
case PH7_OP_SUB :
2018-09-01 20:28:16 +02:00
zOp = " SUB " ;
2018-07-12 17:24:46 +02:00
break ;
case PH7_OP_SHL :
2018-09-01 20:28:16 +02:00
zOp = " SHL " ;
2018-07-12 17:24:46 +02:00
break ;
case PH7_OP_SHR :
2018-09-01 20:28:16 +02:00
zOp = " SHR " ;
2018-07-12 17:24:46 +02:00
break ;
case PH7_OP_LT :
2018-09-01 20:28:16 +02:00
zOp = " LT " ;
2018-07-12 17:24:46 +02:00
break ;
case PH7_OP_LE :
2018-09-01 20:28:16 +02:00
zOp = " LE " ;
2018-07-12 17:24:46 +02:00
break ;
case PH7_OP_GT :
2018-09-01 20:28:16 +02:00
zOp = " GT " ;
2018-07-12 17:24:46 +02:00
break ;
case PH7_OP_GE :
2018-09-01 20:28:16 +02:00
zOp = " GE " ;
2018-07-12 17:24:46 +02:00
break ;
case PH7_OP_EQ :
2018-09-01 20:28:16 +02:00
zOp = " EQ " ;
2018-07-12 17:24:46 +02:00
break ;
case PH7_OP_NEQ :
2018-09-01 20:28:16 +02:00
zOp = " NEQ " ;
2018-07-12 17:24:46 +02:00
break ;
case PH7_OP_BAND :
2018-09-01 20:28:16 +02:00
zOp = " BITAND " ;
2018-07-12 17:24:46 +02:00
break ;
case PH7_OP_BXOR :
2018-09-01 20:28:16 +02:00
zOp = " BITXOR " ;
2018-07-12 17:24:46 +02:00
break ;
case PH7_OP_BOR :
2018-09-01 20:28:16 +02:00
zOp = " BITOR " ;
2018-07-12 17:24:46 +02:00
break ;
case PH7_OP_LAND :
2018-09-01 20:28:16 +02:00
zOp = " LOGAND " ;
2018-07-12 17:24:46 +02:00
break ;
case PH7_OP_LOR :
2018-09-01 20:28:16 +02:00
zOp = " LOGOR " ;
2018-07-12 17:24:46 +02:00
break ;
case PH7_OP_LXOR :
2018-09-01 20:28:16 +02:00
zOp = " LOGXOR " ;
2018-07-12 17:24:46 +02:00
break ;
case PH7_OP_STORE :
2018-09-01 20:28:16 +02:00
zOp = " STORE " ;
2018-07-12 17:24:46 +02:00
break ;
case PH7_OP_STORE_IDX :
2018-09-01 20:28:16 +02:00
zOp = " STORE_IDX " ;
2018-07-12 17:24:46 +02:00
break ;
case PH7_OP_PULL :
2018-09-01 20:28:16 +02:00
zOp = " PULL " ;
2018-07-12 17:24:46 +02:00
break ;
case PH7_OP_SWAP :
2018-09-01 20:28:16 +02:00
zOp = " SWAP " ;
2018-07-12 17:24:46 +02:00
break ;
case PH7_OP_YIELD :
2018-09-01 20:28:16 +02:00
zOp = " YIELD " ;
2018-07-12 17:24:46 +02:00
break ;
case PH7_OP_CVT_BOOL :
2018-09-01 20:28:16 +02:00
zOp = " CVT_BOOL " ;
2018-07-12 17:24:46 +02:00
break ;
case PH7_OP_CVT_OBJ :
2018-09-01 20:28:16 +02:00
zOp = " CVT_OBJ " ;
2018-07-12 17:24:46 +02:00
break ;
case PH7_OP_INCR :
2018-09-01 20:28:16 +02:00
zOp = " INCR " ;
2018-07-12 17:24:46 +02:00
break ;
case PH7_OP_DECR :
2018-09-01 20:28:16 +02:00
zOp = " DECR " ;
2018-07-12 17:24:46 +02:00
break ;
case PH7_OP_NEW :
2018-09-01 20:28:16 +02:00
zOp = " NEW " ;
2018-07-12 17:24:46 +02:00
break ;
case PH7_OP_CLONE :
2018-09-01 20:28:16 +02:00
zOp = " CLONE " ;
2018-07-12 17:24:46 +02:00
break ;
case PH7_OP_ADD_STORE :
2018-09-01 20:28:16 +02:00
zOp = " ADD_STORE " ;
2018-07-12 17:24:46 +02:00
break ;
case PH7_OP_SUB_STORE :
2018-09-01 20:28:16 +02:00
zOp = " SUB_STORE " ;
2018-07-12 17:24:46 +02:00
break ;
case PH7_OP_MUL_STORE :
2018-09-01 20:28:16 +02:00
zOp = " MUL_STORE " ;
2018-07-12 17:24:46 +02:00
break ;
case PH7_OP_DIV_STORE :
2018-09-01 20:28:16 +02:00
zOp = " DIV_STORE " ;
2018-07-12 17:24:46 +02:00
break ;
case PH7_OP_MOD_STORE :
2018-09-01 20:28:16 +02:00
zOp = " MOD_STORE " ;
2018-07-12 17:24:46 +02:00
break ;
case PH7_OP_SHL_STORE :
2018-09-01 20:28:16 +02:00
zOp = " SHL_STORE " ;
2018-07-12 17:24:46 +02:00
break ;
case PH7_OP_SHR_STORE :
2018-09-01 20:28:16 +02:00
zOp = " SHR_STORE " ;
2018-07-12 17:24:46 +02:00
break ;
case PH7_OP_BAND_STORE :
2018-09-01 20:28:16 +02:00
zOp = " BAND_STORE " ;
2018-07-12 17:24:46 +02:00
break ;
case PH7_OP_BOR_STORE :
2018-09-01 20:28:16 +02:00
zOp = " BOR_STORE " ;
2018-07-12 17:24:46 +02:00
break ;
case PH7_OP_BXOR_STORE :
2018-09-01 20:28:16 +02:00
zOp = " BXOR_STORE " ;
2018-07-12 17:24:46 +02:00
break ;
case PH7_OP_CONSUME :
2018-09-01 20:28:16 +02:00
zOp = " CONSUME " ;
2018-07-12 17:24:46 +02:00
break ;
case PH7_OP_MEMBER :
2018-09-01 20:28:16 +02:00
zOp = " MEMBER " ;
2018-07-12 17:24:46 +02:00
break ;
case PH7_OP_IS_A :
2018-09-01 20:28:16 +02:00
zOp = " IS_A " ;
2018-07-12 17:24:46 +02:00
break ;
case PH7_OP_SWITCH :
2018-09-01 20:28:16 +02:00
zOp = " SWITCH " ;
2018-07-12 17:24:46 +02:00
break ;
case PH7_OP_LOAD_EXCEPTION :
2018-09-01 20:28:16 +02:00
zOp = " LOAD_EXCEP " ;
2018-07-12 17:24:46 +02:00
break ;
case PH7_OP_POP_EXCEPTION :
2018-09-01 20:28:16 +02:00
zOp = " POP_EXCEP " ;
2018-07-12 17:24:46 +02:00
break ;
case PH7_OP_THROW :
2018-09-01 20:28:16 +02:00
zOp = " THROW " ;
2018-07-12 17:24:46 +02:00
break ;
2018-07-27 08:24:53 +02:00
case PH7_OP_CLASS_INIT :
2018-09-01 20:28:16 +02:00
zOp = " CLASS_INIT " ;
2018-07-27 08:24:53 +02:00
break ;
case PH7_OP_INTERFACE_INIT :
2018-09-01 20:28:16 +02:00
zOp = " INTER_INIT " ;
2018-07-27 08:24:53 +02:00
break ;
2018-07-12 17:24:46 +02:00
case PH7_OP_FOREACH_INIT :
2018-09-01 20:28:16 +02:00
zOp = " 4EACH_INIT " ;
2018-07-12 17:24:46 +02:00
break ;
case PH7_OP_FOREACH_STEP :
2018-09-01 20:28:16 +02:00
zOp = " 4EACH_STEP " ;
2018-07-12 17:24:46 +02:00
break ;
default :
break ;
2018-07-12 13:26:32 +02:00
}
return zOp ;
}
/*
* Dump PH7 bytecodes instructions to a human readable format .
* The xConsumer ( ) callback which is an used defined function
* is responsible of consuming the generated dump .
*/
PH7_PRIVATE sxi32 PH7_VmDump (
ph7_vm * pVm , /* Target VM */
ProcConsumer xConsumer , /* Output [i.e: dump] consumer callback */
void * pUserData /* Last argument to xConsumer() */
2018-07-12 17:24:46 +02:00
) {
2018-07-12 13:26:32 +02:00
sxi32 rc ;
2018-08-26 19:59:17 +02:00
if ( ! pVm - > bDebug ) {
return SXRET_OK ;
}
rc = VmByteCodeDump ( & pVm - > aInstrSet , xConsumer , pUserData ) ;
2018-07-12 13:26:32 +02:00
return rc ;
}
/*
* Default constant expansion callback used by the ' const ' statement if used
* outside a class body [ i . e : global or function scope ] .
* Refer to the implementation of [ PH7_CompileConstant ( ) ] defined
* in ' compile . c ' for additional information .
*/
2018-07-12 17:24:46 +02:00
PH7_PRIVATE void PH7_VmExpandConstantValue ( ph7_value * pVal , void * pUserData ) {
2018-07-12 13:26:32 +02:00
SySet * pByteCode = ( SySet * ) pUserData ;
/* Evaluate and expand constant value */
2018-07-12 17:24:46 +02:00
VmLocalExec ( ( ph7_vm * ) SySetGetUserData ( pByteCode ) , pByteCode , ( ph7_value * ) pVal ) ;
2018-07-12 13:26:32 +02:00
}
/*
* Section :
* Function handling functions .
* Authors :
* Symisc Systems , devel @ symisc . net .
2019-05-15 20:02:39 +02:00
* Copyright ( C ) Symisc Systems , https : //ph7.symisc.net
2018-07-12 13:26:32 +02:00
* Status :
* Stable .
*/
/*
* bool function_exists ( string $ name )
* Return TRUE if the given function has been defined .
* Parameters
* The name of the desired function .
* Return
* Return TRUE if the given function has been defined . False otherwise
*/
2018-07-12 17:24:46 +02:00
static int vm_builtin_func_exists ( ph7_context * pCtx , int nArg , ph7_value * * apArg ) {
2018-07-12 13:26:32 +02:00
const char * zName ;
ph7_vm * pVm ;
int nLen ;
int res ;
2018-07-12 17:24:46 +02:00
if ( nArg < 1 ) {
2018-07-12 13:26:32 +02:00
/* Missing argument,return FALSE */
2018-07-12 17:24:46 +02:00
ph7_result_bool ( pCtx , 0 ) ;
2018-07-12 13:26:32 +02:00
return SXRET_OK ;
}
/* Point to the target VM */
pVm = pCtx - > pVm ;
/* Extract the function name */
2018-07-12 17:24:46 +02:00
zName = ph7_value_to_string ( apArg [ 0 ] , & nLen ) ;
2018-07-12 13:26:32 +02:00
/* Assume the function is not defined */
res = 0 ;
/* Perform the lookup */
2018-07-12 17:24:46 +02:00
if ( SyHashGet ( & pVm - > hFunction , ( const void * ) zName , ( sxu32 ) nLen ) ! = 0 | |
SyHashGet ( & pVm - > hHostFunction , ( const void * ) zName , ( sxu32 ) nLen ) ! = 0 ) {
/* Function is defined */
res = 1 ;
2018-07-12 13:26:32 +02:00
}
2018-07-12 17:24:46 +02:00
ph7_result_bool ( pCtx , res ) ;
2018-07-12 13:26:32 +02:00
return SXRET_OK ;
}
/* Forward declaration */
2018-07-12 17:24:46 +02:00
static ph7_class * VmExtractClassFromValue ( ph7_vm * pVm , ph7_value * pArg ) ;
2018-07-12 13:26:32 +02:00
/*
* Verify that the contents of a variable can be called as a function .
* [ i . e : Whether it is callable or not ] .
* Return TRUE if callable . FALSE otherwise .
*/
2018-07-12 17:24:46 +02:00
PH7_PRIVATE int PH7_VmIsCallable ( ph7_vm * pVm , ph7_value * pValue , int CallInvoke ) {
2018-07-12 13:26:32 +02:00
int res = 0 ;
2019-05-21 14:49:36 +02:00
if ( pValue - > nType & MEMOBJ_OBJ ) {
2018-07-12 13:26:32 +02:00
/* Call the magic method __invoke if available */
ph7_class_instance * pThis = ( ph7_class_instance * ) pValue - > x . pOther ;
ph7_class_method * pMethod ;
2018-07-12 17:24:46 +02:00
pMethod = PH7_ClassExtractMethod ( pThis - > pClass , " __invoke " , sizeof ( " __invoke " ) - 1 ) ;
if ( pMethod & & CallInvoke ) {
2018-07-12 13:26:32 +02:00
ph7_value sResult ;
sxi32 rc ;
/* Invoke the magic method and extract the result */
2018-07-12 17:24:46 +02:00
PH7_MemObjInit ( pVm , & sResult ) ;
rc = PH7_VmCallClassMethod ( pVm , pThis , pMethod , & sResult , 0 , 0 ) ;
2019-05-21 14:49:36 +02:00
if ( rc = = SXRET_OK & & ( sResult . nType & ( MEMOBJ_BOOL | MEMOBJ_INT ) ) ) {
2018-07-12 13:26:32 +02:00
res = sResult . x . iVal ! = 0 ;
}
PH7_MemObjRelease ( & sResult ) ;
}
2019-05-21 14:49:36 +02:00
} else if ( pValue - > nType & MEMOBJ_HASHMAP ) {
2018-07-12 13:26:32 +02:00
ph7_hashmap * pMap = ( ph7_hashmap * ) pValue - > x . pOther ;
2018-07-12 17:24:46 +02:00
if ( pMap - > nEntry > 1 ) {
2018-07-12 13:26:32 +02:00
ph7_class * pClass ;
ph7_value * pV ;
/* Extract the target class */
2018-07-12 17:24:46 +02:00
pV = ( ph7_value * ) SySetAt ( & pVm - > aMemObj , pMap - > pFirst - > nValIdx ) ;
if ( pV ) {
pClass = VmExtractClassFromValue ( pVm , pV ) ;
if ( pClass ) {
2018-07-12 13:26:32 +02:00
ph7_class_method * pMethod ;
/* Extract the target method */
2018-07-12 17:24:46 +02:00
pV = ( ph7_value * ) SySetAt ( & pVm - > aMemObj , pMap - > pFirst - > pPrev - > nValIdx ) ;
2019-05-21 14:49:36 +02:00
if ( pV & & ( pV - > nType & MEMOBJ_STRING ) & & SyBlobLength ( & pV - > sBlob ) > 0 ) {
2018-07-12 13:26:32 +02:00
/* Perform the lookup */
2018-07-12 17:24:46 +02:00
pMethod = PH7_ClassExtractMethod ( pClass , ( const char * ) SyBlobData ( & pV - > sBlob ) , SyBlobLength ( & pV - > sBlob ) ) ;
if ( pMethod ) {
2018-07-12 13:26:32 +02:00
/* Method is callable */
res = 1 ;
}
}
}
}
}
2019-05-21 14:49:36 +02:00
} else if ( pValue - > nType & ( MEMOBJ_CALL | MEMOBJ_STRING ) ) {
2018-07-12 13:26:32 +02:00
const char * zName ;
int nLen ;
/* Extract the name */
2018-07-12 17:24:46 +02:00
zName = ph7_value_to_string ( pValue , & nLen ) ;
2018-07-12 13:26:32 +02:00
/* Perform the lookup */
2018-07-12 17:24:46 +02:00
if ( SyHashGet ( & pVm - > hFunction , ( const void * ) zName , ( sxu32 ) nLen ) ! = 0 | |
SyHashGet ( & pVm - > hHostFunction , ( const void * ) zName , ( sxu32 ) nLen ) ! = 0 ) {
/* Function is callable */
res = 1 ;
2018-07-12 13:26:32 +02:00
}
}
return res ;
}
/*
* bool is_callable ( callable $ name [ , bool $ syntax_only = false ] )
* Verify that the contents of a variable can be called as a function .
* Parameters
* $ name
* The callback function to check
* Return
* TRUE if name is callable , FALSE otherwise .
*/
2019-04-10 09:45:00 +02:00
static int vm_builtin_is_callable ( ph7_context * pCtx , int nArg , ph7_value * * apArg ) {
2018-07-12 17:24:46 +02:00
ph7_vm * pVm ;
2018-07-12 13:26:32 +02:00
int res ;
2018-07-12 17:24:46 +02:00
if ( nArg < 1 ) {
2018-07-12 13:26:32 +02:00
/* Missing arguments,return FALSE */
2018-07-12 17:24:46 +02:00
ph7_result_bool ( pCtx , 0 ) ;
2018-07-12 13:26:32 +02:00
return SXRET_OK ;
}
/* Point to the target VM */
pVm = pCtx - > pVm ;
/* Perform the requested operation */
2019-04-10 09:45:00 +02:00
res = PH7_VmIsCallable ( pVm , apArg [ 0 ] , FALSE ) ;
2018-07-12 17:24:46 +02:00
ph7_result_bool ( pCtx , res ) ;
2018-07-12 13:26:32 +02:00
return SXRET_OK ;
}
2018-07-15 00:06:26 +02:00
/*
* bool register_autoload_handler ( callable $ callback )
* Register given function as __autoload ( ) implementation .
* Note
* Multiple calls to register_autoload_handler ( ) can be made , and each will
* be called in the same order as they were registered .
* Parameters
* @ callback
* The autoload callback to register .
* Return
* Returns TRUE on success or FALSE on failure .
*/
static int vm_builtin_register_autoload_handler ( ph7_context * pCtx , int nArg , ph7_value * * appArg ) {
VmAutoLoadCB sEntry ;
int i , j ;
2019-05-21 14:49:36 +02:00
if ( nArg < 1 | | ( appArg [ 0 ] - > nType & ( MEMOBJ_STRING | MEMOBJ_HASHMAP ) ) = = 0 ) {
2018-07-15 00:06:26 +02:00
/* Return FALSE */
ph7_result_bool ( pCtx , 0 ) ;
return PH7_OK ;
}
/* Zero the Entry */
SyZero ( & sEntry , sizeof ( VmAutoLoadCB ) ) ;
/* Initialize fields */
PH7_MemObjInit ( pCtx - > pVm , & sEntry . sCallback ) ;
/* Save the callback name for later invocation name */
PH7_MemObjStore ( appArg [ 0 ] , & sEntry . sCallback ) ;
PH7_MemObjInit ( pCtx - > pVm , & sEntry . aArg [ 0 ] ) ;
PH7_MemObjStore ( appArg [ 0 ] , & sEntry . aArg [ 0 ] ) ;
/* Install the callback */
2018-07-15 11:57:22 +02:00
SySetPut ( & pCtx - > pVm - > aAutoLoad , ( const void * ) & sEntry ) ;
2018-07-15 00:06:26 +02:00
ph7_result_bool ( pCtx , 1 ) ;
return PH7_OK ;
}
2018-07-12 13:26:32 +02:00
/*
* void register_shutdown_function ( callable $ callback [ , mixed $ param , . . . )
* Register a function for execution on shutdown .
* Note
* Multiple calls to register_shutdown_function ( ) can be made , and each will
* be called in the same order as they were registered .
* Parameters
* $ callback
* The shutdown callback to register .
* $ param
* One or more Parameter to pass to the registered callback .
* Return
* Nothing .
*/
2018-07-12 17:24:46 +02:00
static int vm_builtin_register_shutdown_function ( ph7_context * pCtx , int nArg , ph7_value * * apArg ) {
2018-07-12 13:26:32 +02:00
VmShutdownCB sEntry ;
2018-07-12 17:24:46 +02:00
int i , j ;
2019-05-21 14:49:36 +02:00
if ( nArg < 1 | | ( apArg [ 0 ] - > nType & ( MEMOBJ_STRING | MEMOBJ_HASHMAP ) ) = = 0 ) {
2018-07-12 13:26:32 +02:00
/* Missing/Invalid arguments,return immediately */
return PH7_OK ;
}
/* Zero the Entry */
2018-07-12 17:24:46 +02:00
SyZero ( & sEntry , sizeof ( VmShutdownCB ) ) ;
2018-07-12 13:26:32 +02:00
/* Initialize fields */
2018-07-12 17:24:46 +02:00
PH7_MemObjInit ( pCtx - > pVm , & sEntry . sCallback ) ;
2018-07-12 13:26:32 +02:00
/* Save the callback name for later invocation name */
2018-07-12 17:24:46 +02:00
PH7_MemObjStore ( apArg [ 0 ] , & sEntry . sCallback ) ;
for ( i = 0 ; i < ( int ) SX_ARRAYSIZE ( sEntry . aArg ) ; + + i ) {
PH7_MemObjInit ( pCtx - > pVm , & sEntry . aArg [ i ] ) ;
2018-07-12 13:26:32 +02:00
}
/* Copy arguments */
2018-07-12 17:24:46 +02:00
for ( j = 0 , i = 1 ; i < nArg ; j + + , i + + ) {
if ( j > = ( int ) SX_ARRAYSIZE ( sEntry . aArg ) ) {
2018-07-12 13:26:32 +02:00
/* Limit reached */
break ;
}
2018-07-12 17:24:46 +02:00
PH7_MemObjStore ( apArg [ i ] , & sEntry . aArg [ j ] ) ;
2018-07-12 13:26:32 +02:00
}
sEntry . nArg = j ;
/* Install the callback */
2018-07-12 17:24:46 +02:00
SySetPut ( & pCtx - > pVm - > aShutdown , ( const void * ) & sEntry ) ;
2018-07-12 13:26:32 +02:00
return PH7_OK ;
}
/*
* Section :
* Class handling functions .
* Authors :
* Symisc Systems , devel @ symisc . net .
2019-05-15 20:02:39 +02:00
* Copyright ( C ) Symisc Systems , https : //ph7.symisc.net
2018-07-12 13:26:32 +02:00
* Status :
* Stable .
*/
/*
2018-08-22 15:33:16 +02:00
* Extract the one of active class . NULL is returned
2018-07-12 13:26:32 +02:00
* if the class stack is empty .
*/
2018-08-22 15:33:16 +02:00
PH7_PRIVATE ph7_class * PH7_VmExtractActiveClass ( ph7_vm * pVm , sxi32 iDepth ) {
2018-07-12 13:26:32 +02:00
SySet * pSet = & pVm - > aSelf ;
ph7_class * * apClass ;
2018-07-12 17:24:46 +02:00
if ( SySetUsed ( pSet ) < = 0 ) {
2018-07-12 13:26:32 +02:00
/* Empty stack,return NULL */
return 0 ;
}
2018-08-22 15:33:16 +02:00
/* Extract the class entry from specified depth */
2018-07-12 13:26:32 +02:00
apClass = ( ph7_class * * ) SySetBasePtr ( pSet ) ;
2018-08-22 15:33:16 +02:00
return apClass [ pSet - > nUsed - ( iDepth + 1 ) ] ;
2018-07-12 13:26:32 +02:00
}
/*
* string get_class ( [ object $ object = NULL ] )
* Returns the name of the class of an object
* Parameters
* object
* The tested object . This parameter may be omitted when inside a class .
* Return
* The name of the class of which object is an instance .
* Returns FALSE if object is not an object .
* If object is omitted when inside a class , the name of that class is returned .
*/
2018-07-12 17:24:46 +02:00
static int vm_builtin_get_class ( ph7_context * pCtx , int nArg , ph7_value * * apArg ) {
2018-07-12 13:26:32 +02:00
ph7_class * pClass ;
SyString * pName ;
2018-07-12 17:24:46 +02:00
if ( nArg < 1 ) {
2018-07-12 13:26:32 +02:00
/* Check if we are inside a class */
2018-08-22 15:33:16 +02:00
pClass = PH7_VmExtractActiveClass ( pCtx - > pVm , 0 ) ;
2018-07-12 17:24:46 +02:00
if ( pClass ) {
2018-07-12 13:26:32 +02:00
/* Point to the class name */
pName = & pClass - > sName ;
2018-07-12 17:24:46 +02:00
ph7_result_string ( pCtx , pName - > zString , ( int ) pName - > nByte ) ;
} else {
2018-07-12 13:26:32 +02:00
/* Not inside class,return FALSE */
2018-07-12 17:24:46 +02:00
ph7_result_bool ( pCtx , 0 ) ;
2018-07-12 13:26:32 +02:00
}
2018-07-12 17:24:46 +02:00
} else {
2018-07-12 13:26:32 +02:00
/* Extract the target class */
2018-07-12 17:24:46 +02:00
pClass = VmExtractClassFromValue ( pCtx - > pVm , apArg [ 0 ] ) ;
if ( pClass ) {
2018-07-12 13:26:32 +02:00
pName = & pClass - > sName ;
/* Return the class name */
2018-07-12 17:24:46 +02:00
ph7_result_string ( pCtx , pName - > zString , ( int ) pName - > nByte ) ;
} else {
2018-07-12 13:26:32 +02:00
/* Not a class instance,return FALSE */
2018-07-12 17:24:46 +02:00
ph7_result_bool ( pCtx , 0 ) ;
2018-07-12 13:26:32 +02:00
}
}
return PH7_OK ;
}
/*
* string get_parent_class ( [ object $ object = NULL ] )
* Returns the name of the parent class of an object
* Parameters
* object
* The tested object . This parameter may be omitted when inside a class .
* Return
* The name of the parent class of which object is an instance .
* Returns FALSE if object is not an object or if the object does
* not have a parent .
* If object is omitted when inside a class , the name of that class is returned .
*/
2018-07-12 17:24:46 +02:00
static int vm_builtin_get_parent_class ( ph7_context * pCtx , int nArg , ph7_value * * apArg ) {
2018-07-12 13:26:32 +02:00
ph7_class * pClass ;
SyString * pName ;
2018-07-12 17:24:46 +02:00
if ( nArg < 1 ) {
2018-07-12 13:26:32 +02:00
/* Check if we are inside a class [i.e: a method call]*/
2018-08-22 15:33:16 +02:00
pClass = PH7_VmExtractActiveClass ( pCtx - > pVm , 0 ) ;
2018-07-12 17:24:46 +02:00
if ( pClass & & pClass - > pBase ) {
2018-07-12 13:26:32 +02:00
/* Point to the class name */
pName = & pClass - > pBase - > sName ;
2018-07-12 17:24:46 +02:00
ph7_result_string ( pCtx , pName - > zString , ( int ) pName - > nByte ) ;
} else {
2018-07-12 13:26:32 +02:00
/* Not inside class,return FALSE */
2018-07-12 17:24:46 +02:00
ph7_result_bool ( pCtx , 0 ) ;
2018-07-12 13:26:32 +02:00
}
2018-07-12 17:24:46 +02:00
} else {
2018-07-12 13:26:32 +02:00
/* Extract the target class */
2018-07-12 17:24:46 +02:00
pClass = VmExtractClassFromValue ( pCtx - > pVm , apArg [ 0 ] ) ;
if ( pClass ) {
if ( pClass - > pBase ) {
2018-07-12 13:26:32 +02:00
pName = & pClass - > pBase - > sName ;
/* Return the parent class name */
2018-07-12 17:24:46 +02:00
ph7_result_string ( pCtx , pName - > zString , ( int ) pName - > nByte ) ;
} else {
2018-07-12 13:26:32 +02:00
/* Object does not have a parent class */
2018-07-12 17:24:46 +02:00
ph7_result_bool ( pCtx , 0 ) ;
2018-07-12 13:26:32 +02:00
}
2018-07-12 17:24:46 +02:00
} else {
2018-07-12 13:26:32 +02:00
/* Not a class instance,return FALSE */
2018-07-12 17:24:46 +02:00
ph7_result_bool ( pCtx , 0 ) ;
2018-07-12 13:26:32 +02:00
}
}
return PH7_OK ;
}
/*
* string get_called_class ( void )
2018-07-12 17:24:46 +02:00
* Gets the name of the class the static method is called in .
2018-07-12 13:26:32 +02:00
* Parameters
* None .
* Return
2018-07-12 17:24:46 +02:00
* Returns the class name . Returns FALSE if called from outside a class .
2018-07-12 13:26:32 +02:00
*/
2018-07-12 17:24:46 +02:00
static int vm_builtin_get_called_class ( ph7_context * pCtx , int nArg , ph7_value * * apArg ) {
2018-07-12 13:26:32 +02:00
ph7_class * pClass ;
/* Check if we are inside a class [i.e: a method call] */
2018-08-22 15:33:16 +02:00
pClass = PH7_VmExtractActiveClass ( pCtx - > pVm , 0 ) ;
2018-07-12 17:24:46 +02:00
if ( pClass ) {
2018-07-12 13:26:32 +02:00
SyString * pName ;
/* Point to the class name */
pName = & pClass - > sName ;
2018-07-12 17:24:46 +02:00
ph7_result_string ( pCtx , pName - > zString , ( int ) pName - > nByte ) ;
} else {
2018-07-12 13:26:32 +02:00
SXUNUSED ( nArg ) ; /* cc warning */
SXUNUSED ( apArg ) ;
/* Not inside class,return FALSE */
2018-07-12 17:24:46 +02:00
ph7_result_bool ( pCtx , 0 ) ;
2018-07-12 13:26:32 +02:00
}
return PH7_OK ;
}
/*
* Extract a ph7_class from the given ph7_value .
* The given value must be of type object [ i . e : class instance ] or
* string which hold the class name .
*/
2018-07-12 17:24:46 +02:00
static ph7_class * VmExtractClassFromValue ( ph7_vm * pVm , ph7_value * pArg ) {
2018-07-12 13:26:32 +02:00
ph7_class * pClass = 0 ;
2018-07-12 17:24:46 +02:00
if ( ph7_value_is_object ( pArg ) ) {
2018-07-12 13:26:32 +02:00
/* Class instance already loaded,no need to perform a lookup */
pClass = ( ( ph7_class_instance * ) pArg - > x . pOther ) - > pClass ;
2018-07-12 17:24:46 +02:00
} else if ( ph7_value_is_string ( pArg ) ) {
2018-07-12 13:26:32 +02:00
const char * zClass ;
int nLen ;
/* Extract class name */
2018-07-12 17:24:46 +02:00
zClass = ph7_value_to_string ( pArg , & nLen ) ;
if ( nLen > 0 ) {
2018-07-12 13:26:32 +02:00
SyHashEntry * pEntry ;
/* Perform a lookup */
2018-07-12 17:24:46 +02:00
pEntry = SyHashGet ( & pVm - > hClass , ( const void * ) zClass , ( sxu32 ) nLen ) ;
if ( pEntry ) {
2018-07-12 13:26:32 +02:00
/* Point to the desired class */
pClass = ( ph7_class * ) pEntry - > pUserData ;
}
}
}
return pClass ;
}
/*
* bool property_exists ( mixed $ class , string $ property )
* Checks if the object or class has a property .
* Parameters
* class
* The class name or an object of the class to test for
* property
* The name of the property
* Return
2018-07-12 17:24:46 +02:00
* Returns TRUE if the property exists , FALSE otherwise .
2018-07-12 13:26:32 +02:00
*/
2018-07-12 17:24:46 +02:00
static int vm_builtin_property_exists ( ph7_context * pCtx , int nArg , ph7_value * * apArg ) {
2018-07-12 13:26:32 +02:00
int res = 0 ; /* Assume attribute does not exists */
2018-07-12 17:24:46 +02:00
if ( nArg > 1 ) {
2018-07-12 13:26:32 +02:00
ph7_class * pClass ;
2018-07-12 17:24:46 +02:00
pClass = VmExtractClassFromValue ( pCtx - > pVm , apArg [ 0 ] ) ;
if ( pClass ) {
const char * zName ;
2018-07-12 13:26:32 +02:00
int nLen ;
/* Extract attribute name */
2018-07-12 17:24:46 +02:00
zName = ph7_value_to_string ( apArg [ 1 ] , & nLen ) ;
if ( nLen > 0 ) {
2018-07-12 13:26:32 +02:00
/* Perform the lookup in the attribute and method table */
2018-07-12 17:24:46 +02:00
if ( SyHashGet ( & pClass - > hAttr , ( const void * ) zName , ( sxu32 ) nLen ) ! = 0
| | SyHashGet ( & pClass - > hMethod , ( const void * ) zName , ( sxu32 ) nLen ) ! = 0 ) {
/* property exists,flag that */
res = 1 ;
2018-07-12 13:26:32 +02:00
}
}
}
}
2018-07-12 17:24:46 +02:00
ph7_result_bool ( pCtx , res ) ;
2018-07-12 13:26:32 +02:00
return PH7_OK ;
}
/*
* bool method_exists ( mixed $ class , string $ method )
* Checks if the given method is a class member .
* Parameters
* class
* The class name or an object of the class to test for
* property
* The name of the method
* Return
2018-07-12 17:24:46 +02:00
* Returns TRUE if the method exists , FALSE otherwise .
2018-07-12 13:26:32 +02:00
*/
2018-07-12 17:24:46 +02:00
static int vm_builtin_method_exists ( ph7_context * pCtx , int nArg , ph7_value * * apArg ) {
2018-07-12 13:26:32 +02:00
int res = 0 ; /* Assume method does not exists */
2018-07-12 17:24:46 +02:00
if ( nArg > 1 ) {
2018-07-12 13:26:32 +02:00
ph7_class * pClass ;
2018-07-12 17:24:46 +02:00
pClass = VmExtractClassFromValue ( pCtx - > pVm , apArg [ 0 ] ) ;
if ( pClass ) {
const char * zName ;
2018-07-12 13:26:32 +02:00
int nLen ;
/* Extract method name */
2018-07-12 17:24:46 +02:00
zName = ph7_value_to_string ( apArg [ 1 ] , & nLen ) ;
if ( nLen > 0 ) {
2018-07-12 13:26:32 +02:00
/* Perform the lookup in the method table */
2018-07-12 17:24:46 +02:00
if ( SyHashGet ( & pClass - > hMethod , ( const void * ) zName , ( sxu32 ) nLen ) ! = 0 ) {
2018-07-12 13:26:32 +02:00
/* method exists,flag that */
res = 1 ;
}
}
}
}
2018-07-12 17:24:46 +02:00
ph7_result_bool ( pCtx , res ) ;
2018-07-12 13:26:32 +02:00
return PH7_OK ;
}
/*
* bool class_exists ( string $ class_name [ , bool $ autoload = true ] )
* Checks if the class has been defined .
* Parameters
* class_name
2018-07-12 17:24:46 +02:00
* The class name . The name is matched in a case - sensitive manner
2018-07-23 17:10:48 +02:00
* unlike the standard PHP engine .
2018-07-12 13:26:32 +02:00
* autoload
* Whether or not to call __autoload by default .
* Return
2018-07-12 17:24:46 +02:00
* TRUE if class_name is a defined class , FALSE otherwise .
2018-07-12 13:26:32 +02:00
*/
2018-07-12 17:24:46 +02:00
static int vm_builtin_class_exists ( ph7_context * pCtx , int nArg , ph7_value * * apArg ) {
2018-07-12 13:26:32 +02:00
int res = 0 ; /* Assume class does not exists */
2018-07-12 17:24:46 +02:00
if ( nArg > 0 ) {
2018-07-25 19:00:49 +02:00
SyHashEntry * pEntry = 0 ;
2018-07-12 13:26:32 +02:00
const char * zName ;
int nLen ;
/* Extract given name */
2018-07-12 17:24:46 +02:00
zName = ph7_value_to_string ( apArg [ 0 ] , & nLen ) ;
2018-07-12 13:26:32 +02:00
/* Perform a hashlookup */
2018-07-25 19:00:49 +02:00
if ( nLen > 0 ) {
pEntry = SyHashGet ( & pCtx - > pVm - > hClass , ( const void * ) zName , ( sxu32 ) nLen ) ;
}
if ( pEntry ) {
ph7_class * pClass = ( ph7_class * ) pEntry - > pUserData ;
if ( ( pClass - > iFlags & PH7_CLASS_INTERFACE ) = = 0 ) {
/* class is available */
res = 1 ;
}
2018-07-12 13:26:32 +02:00
}
}
2018-07-12 17:24:46 +02:00
ph7_result_bool ( pCtx , res ) ;
2018-07-12 13:26:32 +02:00
return PH7_OK ;
}
/*
* bool interface_exists ( string $ class_name [ , bool $ autoload = true ] )
* Checks if the interface has been defined .
* Parameters
* class_name
2018-07-12 17:24:46 +02:00
* The class name . The name is matched in a case - sensitive manner
2018-07-23 17:10:48 +02:00
* unlike the standard PHP engine .
2018-07-12 13:26:32 +02:00
* autoload
* Whether or not to call __autoload by default .
* Return
2018-07-12 17:24:46 +02:00
* TRUE if class_name is a defined class , FALSE otherwise .
2018-07-12 13:26:32 +02:00
*/
2018-07-12 17:24:46 +02:00
static int vm_builtin_interface_exists ( ph7_context * pCtx , int nArg , ph7_value * * apArg ) {
2018-07-12 13:26:32 +02:00
int res = 0 ; /* Assume class does not exists */
2018-07-12 17:24:46 +02:00
if ( nArg > 0 ) {
2018-07-12 13:26:32 +02:00
SyHashEntry * pEntry = 0 ;
const char * zName ;
int nLen ;
/* Extract given name */
2018-07-12 17:24:46 +02:00
zName = ph7_value_to_string ( apArg [ 0 ] , & nLen ) ;
2018-07-12 13:26:32 +02:00
/* Perform a hashlookup */
2018-07-12 17:24:46 +02:00
if ( nLen > 0 ) {
pEntry = SyHashGet ( & pCtx - > pVm - > hClass , ( const void * ) zName , ( sxu32 ) nLen ) ;
2018-07-12 13:26:32 +02:00
}
2018-07-12 17:24:46 +02:00
if ( pEntry ) {
2018-07-12 13:26:32 +02:00
ph7_class * pClass = ( ph7_class * ) pEntry - > pUserData ;
2018-07-25 19:00:49 +02:00
if ( pClass - > iFlags & PH7_CLASS_INTERFACE ) {
/* interface is available */
res = 1 ;
2018-07-12 13:26:32 +02:00
}
}
}
2018-07-12 17:24:46 +02:00
ph7_result_bool ( pCtx , res ) ;
2018-07-12 13:26:32 +02:00
return PH7_OK ;
}
/*
* bool class_alias ( [ string $ original [ , string $ alias ] ] )
* Creates an alias for a class .
* Parameters
* original
* The original class .
* alias
* The alias name for the class .
* Return
2018-07-12 17:24:46 +02:00
* Returns TRUE on success or FALSE on failure .
2018-07-12 13:26:32 +02:00
*/
2018-07-12 17:24:46 +02:00
static int vm_builtin_class_alias ( ph7_context * pCtx , int nArg , ph7_value * * apArg ) {
const char * zOld , * zNew ;
int nOldLen , nNewLen ;
2018-07-12 13:26:32 +02:00
SyHashEntry * pEntry ;
ph7_class * pClass ;
char * zDup ;
sxi32 rc ;
2018-07-12 17:24:46 +02:00
if ( nArg < 2 ) {
2018-07-12 13:26:32 +02:00
/* Missing arguments,return FALSE */
2018-07-12 17:24:46 +02:00
ph7_result_bool ( pCtx , 0 ) ;
2018-07-12 13:26:32 +02:00
return PH7_OK ;
}
/* Extract old class name */
2018-07-12 17:24:46 +02:00
zOld = ph7_value_to_string ( apArg [ 0 ] , & nOldLen ) ;
2018-07-12 13:26:32 +02:00
/* Extract alias name */
2018-07-12 17:24:46 +02:00
zNew = ph7_value_to_string ( apArg [ 1 ] , & nNewLen ) ;
if ( nNewLen < 1 ) {
2018-07-12 13:26:32 +02:00
/* Invalid alias name,return FALSE */
2018-07-12 17:24:46 +02:00
ph7_result_bool ( pCtx , 0 ) ;
2018-07-12 13:26:32 +02:00
return PH7_OK ;
}
/* Perform a hash lookup */
2018-07-12 17:24:46 +02:00
pEntry = SyHashGet ( & pCtx - > pVm - > hClass , ( const void * ) zOld , ( sxu32 ) nOldLen ) ;
if ( pEntry = = 0 ) {
2018-07-12 13:26:32 +02:00
/* No such class,return FALSE */
2018-07-12 17:24:46 +02:00
ph7_result_bool ( pCtx , 0 ) ;
2018-07-12 13:26:32 +02:00
return PH7_OK ;
}
/* Point to the class */
pClass = ( ph7_class * ) pEntry - > pUserData ;
/* Duplicate alias name */
2018-07-12 17:24:46 +02:00
zDup = SyMemBackendStrDup ( & pCtx - > pVm - > sAllocator , zNew , ( sxu32 ) nNewLen ) ;
if ( zDup = = 0 ) {
2018-07-12 13:26:32 +02:00
/* Out of memory,return FALSE */
2018-07-12 17:24:46 +02:00
ph7_result_bool ( pCtx , 0 ) ;
2018-07-12 13:26:32 +02:00
return PH7_OK ;
}
/* Create the alias */
2018-07-12 17:24:46 +02:00
rc = SyHashInsert ( & pCtx - > pVm - > hClass , ( const void * ) zDup , ( sxu32 ) nNewLen , pClass ) ;
if ( rc ! = SXRET_OK ) {
SyMemBackendFree ( & pCtx - > pVm - > sAllocator , zDup ) ;
2018-07-12 13:26:32 +02:00
}
2018-07-12 17:24:46 +02:00
ph7_result_bool ( pCtx , rc = = SXRET_OK ) ;
2018-07-12 13:26:32 +02:00
return PH7_OK ;
}
/*
* array get_declared_classes ( void )
* Returns an array with the name of the defined classes
* Parameters
* None
* Return
* Returns an array of the names of the declared classes
2018-07-12 17:24:46 +02:00
* in the current script .
2018-07-12 13:26:32 +02:00
* Note :
* NULL is returned on failure .
*/
2018-07-12 17:24:46 +02:00
static int vm_builtin_get_declared_classes ( ph7_context * pCtx , int nArg , ph7_value * * apArg ) {
ph7_value * pName , * pArray ;
2018-07-12 13:26:32 +02:00
SyHashEntry * pEntry ;
/* Create a new array first */
pArray = ph7_context_new_array ( pCtx ) ;
pName = ph7_context_new_scalar ( pCtx ) ;
2018-07-12 17:24:46 +02:00
if ( pArray = = 0 | | pName = = 0 ) {
2018-07-12 13:26:32 +02:00
SXUNUSED ( nArg ) ; /* cc warning */
SXUNUSED ( apArg ) ;
/* Out of memory,return NULL */
ph7_result_null ( pCtx ) ;
return PH7_OK ;
}
/* Fill the array with the defined classes */
SyHashResetLoopCursor ( & pCtx - > pVm - > hClass ) ;
2018-07-12 17:24:46 +02:00
while ( ( pEntry = SyHashGetNextEntry ( & pCtx - > pVm - > hClass ) ) ! = 0 ) {
2018-07-12 13:26:32 +02:00
ph7_class * pClass = ( ph7_class * ) pEntry - > pUserData ;
/* Do not register classes defined as interfaces */
2018-07-12 17:24:46 +02:00
if ( ( pClass - > iFlags & PH7_CLASS_INTERFACE ) = = 0 ) {
ph7_value_string ( pName , SyStringData ( & pClass - > sName ) , ( int ) SyStringLength ( & pClass - > sName ) ) ;
2018-07-12 13:26:32 +02:00
/* insert class name */
2018-07-12 17:24:46 +02:00
ph7_array_add_elem ( pArray , 0 /*Automatic index assign*/ , pName ) ; /* Will make it's own copy */
2018-07-12 13:26:32 +02:00
/* Reset the cursor */
ph7_value_reset_string_cursor ( pName ) ;
}
}
/* Return the created array */
2018-07-12 17:24:46 +02:00
ph7_result_value ( pCtx , pArray ) ;
2018-07-12 13:26:32 +02:00
return PH7_OK ;
}
/*
* array get_declared_interfaces ( void )
* Returns an array with the name of the defined interfaces
* Parameters
* None
* Return
* Returns an array of the names of the declared interfaces
2018-07-12 17:24:46 +02:00
* in the current script .
2018-07-12 13:26:32 +02:00
* Note :
* NULL is returned on failure .
*/
2018-07-12 17:24:46 +02:00
static int vm_builtin_get_declared_interfaces ( ph7_context * pCtx , int nArg , ph7_value * * apArg ) {
ph7_value * pName , * pArray ;
2018-07-12 13:26:32 +02:00
SyHashEntry * pEntry ;
/* Create a new array first */
pArray = ph7_context_new_array ( pCtx ) ;
pName = ph7_context_new_scalar ( pCtx ) ;
2018-07-12 17:24:46 +02:00
if ( pArray = = 0 | | pName = = 0 ) {
2018-07-12 13:26:32 +02:00
SXUNUSED ( nArg ) ; /* cc warning */
SXUNUSED ( apArg ) ;
/* Out of memory,return NULL */
ph7_result_null ( pCtx ) ;
return PH7_OK ;
}
/* Fill the array with the defined classes */
SyHashResetLoopCursor ( & pCtx - > pVm - > hClass ) ;
2018-07-12 17:24:46 +02:00
while ( ( pEntry = SyHashGetNextEntry ( & pCtx - > pVm - > hClass ) ) ! = 0 ) {
2018-07-12 13:26:32 +02:00
ph7_class * pClass = ( ph7_class * ) pEntry - > pUserData ;
/* Register classes defined as interfaces only */
2018-07-12 17:24:46 +02:00
if ( pClass - > iFlags & PH7_CLASS_INTERFACE ) {
ph7_value_string ( pName , SyStringData ( & pClass - > sName ) , ( int ) SyStringLength ( & pClass - > sName ) ) ;
2018-07-12 13:26:32 +02:00
/* insert interface name */
2018-07-12 17:24:46 +02:00
ph7_array_add_elem ( pArray , 0 /*Automatic index assign*/ , pName ) ; /* Will make it's own copy */
2018-07-12 13:26:32 +02:00
/* Reset the cursor */
ph7_value_reset_string_cursor ( pName ) ;
}
}
/* Return the created array */
2018-07-12 17:24:46 +02:00
ph7_result_value ( pCtx , pArray ) ;
2018-07-12 13:26:32 +02:00
return PH7_OK ;
}
/*
* array get_class_methods ( string / object $ class_name )
* Returns an array with the name of the class methods
* Parameters
* class_name
* The class name or class instance
* Return
* Returns an array of method names defined for the class specified by class_name .
2018-07-12 17:24:46 +02:00
* In case of an error , it returns NULL .
2018-07-12 13:26:32 +02:00
* Note :
* NULL is returned on failure .
*/
2018-07-12 17:24:46 +02:00
static int vm_builtin_get_class_methods ( ph7_context * pCtx , int nArg , ph7_value * * apArg ) {
ph7_value * pName , * pArray ;
2018-07-12 13:26:32 +02:00
SyHashEntry * pEntry ;
ph7_class * pClass ;
/* Extract the target class first */
pClass = 0 ;
2018-07-12 17:24:46 +02:00
if ( nArg > 0 ) {
pClass = VmExtractClassFromValue ( pCtx - > pVm , apArg [ 0 ] ) ;
2018-07-12 13:26:32 +02:00
}
2018-07-12 17:24:46 +02:00
if ( pClass = = 0 ) {
2018-07-12 13:26:32 +02:00
/* No such class,return NULL */
ph7_result_null ( pCtx ) ;
return PH7_OK ;
}
/* Create a new array */
pArray = ph7_context_new_array ( pCtx ) ;
pName = ph7_context_new_scalar ( pCtx ) ;
2018-07-12 17:24:46 +02:00
if ( pArray = = 0 | | pName = = 0 ) {
2018-07-12 13:26:32 +02:00
/* Out of memory,return NULL */
ph7_result_null ( pCtx ) ;
return PH7_OK ;
}
/* Fill the array with the defined methods */
SyHashResetLoopCursor ( & pClass - > hMethod ) ;
2018-07-12 17:24:46 +02:00
while ( ( pEntry = SyHashGetNextEntry ( & pClass - > hMethod ) ) ! = 0 ) {
2018-07-12 13:26:32 +02:00
ph7_class_method * pMethod = ( ph7_class_method * ) pEntry - > pUserData ;
/* Insert method name */
2018-07-12 17:24:46 +02:00
ph7_value_string ( pName , SyStringData ( & pMethod - > sFunc . sName ) , ( int ) SyStringLength ( & pMethod - > sFunc . sName ) ) ;
ph7_array_add_elem ( pArray , 0 /*Automatic index assign*/ , pName ) ; /* Will make it's own copy */
2018-07-12 13:26:32 +02:00
/* Reset the cursor */
ph7_value_reset_string_cursor ( pName ) ;
}
/* Return the created array */
2018-07-12 17:24:46 +02:00
ph7_result_value ( pCtx , pArray ) ;
2018-07-12 13:26:32 +02:00
/*
* Don ' t worry about freeing memory here , everything will be relased
* automatically as soon we return from this foreign function .
*/
return PH7_OK ;
}
/*
2018-07-12 17:24:46 +02:00
* This function return TRUE ( 1 ) if the given class attribute stored
2018-07-12 13:26:32 +02:00
* in the pAttrName parameter is visible and thus can be extracted
* from the current scope . Otherwise FALSE is returned .
*/
static int VmClassMemberAccess (
ph7_vm * pVm , /* Target VM */
ph7_class * pClass , /* Target Class */
2019-05-29 15:26:31 +02:00
sxi32 iProtection /* Attribute protection level [i.e: public,protected or private] */
2018-07-12 17:24:46 +02:00
) {
if ( iProtection ! = PH7_CLASS_PROT_PUBLIC ) {
2018-07-12 13:26:32 +02:00
VmFrame * pFrame = pVm - > pFrame ;
ph7_vm_func * pVmFunc ;
2018-07-12 17:24:46 +02:00
while ( pFrame - > pParent & & ( pFrame - > iFlags & ( VM_FRAME_EXCEPTION | VM_FRAME_CATCH ) ) ) {
2018-07-12 13:26:32 +02:00
/* Safely ignore the exception frame */
pFrame = pFrame - > pParent ;
}
pVmFunc = ( ph7_vm_func * ) pFrame - > pUserData ;
2018-07-12 17:24:46 +02:00
if ( pVmFunc = = 0 | | ( pVmFunc - > iFlags & VM_FUNC_CLASS_METHOD ) = = 0 ) {
2019-05-29 15:26:31 +02:00
return 0 ; /* Access is forbidden */
2018-07-12 13:26:32 +02:00
}
2018-07-12 17:24:46 +02:00
if ( iProtection = = PH7_CLASS_PROT_PRIVATE ) {
2018-07-12 13:26:32 +02:00
/* Must be the same instance */
2018-07-12 17:24:46 +02:00
if ( ( ph7_class * ) pVmFunc - > pUserData ! = pClass ) {
2019-05-29 15:26:31 +02:00
return 0 ; /* Access is forbidden */
2018-07-12 13:26:32 +02:00
}
2018-07-12 17:24:46 +02:00
} else {
2018-07-12 13:26:32 +02:00
/* Protected */
ph7_class * pBase = ( ph7_class * ) pVmFunc - > pUserData ;
/* Must be a derived class */
2019-05-29 08:10:34 +02:00
if ( ! VmInstanceOf ( pBase , pClass ) ) {
2019-05-29 15:26:31 +02:00
return 0 ; /* Access is forbidden */
2018-07-12 13:26:32 +02:00
}
}
}
return 1 ; /* Access is granted */
}
/*
* array get_class_vars ( string / object $ class_name )
* Get the default properties of the class
* Parameters
* class_name
* The class name or class instance
* Return
* Returns an associative array of declared properties visible from the current scope
2018-07-12 17:24:46 +02:00
* with their default value . The resulting array elements are in the form
* of varname = > value .
2018-07-12 13:26:32 +02:00
* Note :
* NULL is returned on failure .
*/
2018-07-12 17:24:46 +02:00
static int vm_builtin_get_class_vars ( ph7_context * pCtx , int nArg , ph7_value * * apArg ) {
ph7_value * pName , * pArray , sValue ;
2018-07-12 13:26:32 +02:00
SyHashEntry * pEntry ;
ph7_class * pClass ;
/* Extract the target class first */
pClass = 0 ;
2018-07-12 17:24:46 +02:00
if ( nArg > 0 ) {
pClass = VmExtractClassFromValue ( pCtx - > pVm , apArg [ 0 ] ) ;
2018-07-12 13:26:32 +02:00
}
2018-07-12 17:24:46 +02:00
if ( pClass = = 0 ) {
2018-07-12 13:26:32 +02:00
/* No such class,return NULL */
ph7_result_null ( pCtx ) ;
return PH7_OK ;
}
/* Create a new array */
pArray = ph7_context_new_array ( pCtx ) ;
pName = ph7_context_new_scalar ( pCtx ) ;
2018-07-12 17:24:46 +02:00
PH7_MemObjInit ( pCtx - > pVm , & sValue ) ;
if ( pArray = = 0 | | pName = = 0 ) {
2018-07-12 13:26:32 +02:00
/* Out of memory,return NULL */
ph7_result_null ( pCtx ) ;
return PH7_OK ;
}
/* Fill the array with the defined attribute visible from the current scope */
SyHashResetLoopCursor ( & pClass - > hAttr ) ;
2018-07-12 17:24:46 +02:00
while ( ( pEntry = SyHashGetNextEntry ( & pClass - > hAttr ) ) ! = 0 ) {
2018-07-12 13:26:32 +02:00
ph7_class_attr * pAttr = ( ph7_class_attr * ) pEntry - > pUserData ;
/* Check if the access is allowed */
2019-05-29 15:26:31 +02:00
if ( VmClassMemberAccess ( pCtx - > pVm , pClass , pAttr - > iProtection ) ) {
2018-07-12 13:26:32 +02:00
SyString * pAttrName = & pAttr - > sName ;
ph7_value * pValue = 0 ;
2018-07-12 17:24:46 +02:00
if ( pAttr - > iFlags & ( PH7_CLASS_ATTR_CONSTANT | PH7_CLASS_ATTR_STATIC ) ) {
2018-07-12 13:26:32 +02:00
/* Extract static attribute value which is always computed */
2018-07-12 17:24:46 +02:00
pValue = ( ph7_value * ) SySetAt ( & pCtx - > pVm - > aMemObj , pAttr - > nIdx ) ;
} else {
if ( SySetUsed ( & pAttr - > aByteCode ) > 0 ) {
2018-07-12 13:26:32 +02:00
PH7_MemObjRelease ( & sValue ) ;
2018-07-12 17:24:46 +02:00
/* Compute default value (any complex expression) associated with this attribute */
VmLocalExec ( pCtx - > pVm , & pAttr - > aByteCode , & sValue ) ;
2018-07-12 13:26:32 +02:00
pValue = & sValue ;
}
}
/* Fill in the array */
2018-07-12 17:24:46 +02:00
ph7_value_string ( pName , pAttrName - > zString , pAttrName - > nByte ) ;
ph7_array_add_elem ( pArray , pName , pValue ) ; /* Will make it's own copy */
2018-07-12 13:26:32 +02:00
/* Reset the cursor */
ph7_value_reset_string_cursor ( pName ) ;
}
}
PH7_MemObjRelease ( & sValue ) ;
/* Return the created array */
2018-07-12 17:24:46 +02:00
ph7_result_value ( pCtx , pArray ) ;
2018-07-12 13:26:32 +02:00
/*
* Don ' t worry about freeing memory here , everything will be relased
* automatically as soon we return from this foreign function .
*/
return PH7_OK ;
}
/*
* array get_object_vars ( object $ this )
* Gets the properties of the given object
* Parameters
* this
* A class instance
* Return
* Returns an associative array of defined object accessible non - static properties
* for the specified object in scope . If a property have not been assigned a value
2018-07-12 17:24:46 +02:00
* it will be returned with a NULL value .
2018-07-12 13:26:32 +02:00
* Note :
* NULL is returned on failure .
*/
2018-07-12 17:24:46 +02:00
static int vm_builtin_get_object_vars ( ph7_context * pCtx , int nArg , ph7_value * * apArg ) {
2018-07-12 13:26:32 +02:00
ph7_class_instance * pThis = 0 ;
2018-07-12 17:24:46 +02:00
ph7_value * pName , * pArray ;
2018-07-12 13:26:32 +02:00
SyHashEntry * pEntry ;
2019-05-21 14:49:36 +02:00
if ( nArg > 0 & & ( apArg [ 0 ] - > nType & MEMOBJ_OBJ ) ) {
2018-07-12 13:26:32 +02:00
/* Extract the target instance */
pThis = ( ph7_class_instance * ) apArg [ 0 ] - > x . pOther ;
}
2018-07-12 17:24:46 +02:00
if ( pThis = = 0 ) {
2018-07-12 13:26:32 +02:00
/* No such instance,return NULL */
ph7_result_null ( pCtx ) ;
return PH7_OK ;
}
/* Create a new array */
pArray = ph7_context_new_array ( pCtx ) ;
pName = ph7_context_new_scalar ( pCtx ) ;
2018-07-12 17:24:46 +02:00
if ( pArray = = 0 | | pName = = 0 ) {
2018-07-12 13:26:32 +02:00
/* Out of memory,return NULL */
ph7_result_null ( pCtx ) ;
return PH7_OK ;
}
/* Fill the array with the defined attribute visible from the current scope */
SyHashResetLoopCursor ( & pThis - > hAttr ) ;
2018-07-12 17:24:46 +02:00
while ( ( pEntry = SyHashGetNextEntry ( & pThis - > hAttr ) ) ! = 0 ) {
2018-07-12 13:26:32 +02:00
VmClassAttr * pVmAttr = ( VmClassAttr * ) pEntry - > pUserData ;
SyString * pAttrName ;
2018-07-12 17:24:46 +02:00
if ( pVmAttr - > pAttr - > iFlags & ( PH7_CLASS_ATTR_STATIC | PH7_CLASS_ATTR_CONSTANT ) ) {
2018-07-12 13:26:32 +02:00
/* Only non-static/constant attributes are extracted */
continue ;
}
pAttrName = & pVmAttr - > pAttr - > sName ;
/* Check if the access is allowed */
2019-05-29 15:26:31 +02:00
if ( VmClassMemberAccess ( pCtx - > pVm , pThis - > pClass , pVmAttr - > pAttr - > iProtection ) ) {
2018-07-12 13:26:32 +02:00
ph7_value * pValue = 0 ;
/* Extract attribute */
2018-07-12 17:24:46 +02:00
pValue = PH7_ClassInstanceExtractAttrValue ( pThis , pVmAttr ) ;
if ( pValue ) {
2018-07-12 13:26:32 +02:00
/* Insert attribute name in the array */
2018-07-12 17:24:46 +02:00
ph7_value_string ( pName , pAttrName - > zString , pAttrName - > nByte ) ;
ph7_array_add_elem ( pArray , pName , pValue ) ; /* Will make it's own copy */
2018-07-12 13:26:32 +02:00
}
/* Reset the cursor */
ph7_value_reset_string_cursor ( pName ) ;
}
}
/* Return the created array */
2018-07-12 17:24:46 +02:00
ph7_result_value ( pCtx , pArray ) ;
2018-07-12 13:26:32 +02:00
/*
* Don ' t worry about freeing memory here , everything will be relased
* automatically as soon we return from this foreign function .
*/
return PH7_OK ;
}
/*
* This function returns TRUE if the given class is an implemented
2018-07-12 17:24:46 +02:00
* interface . Otherwise FALSE is returned .
2018-07-12 13:26:32 +02:00
*/
2018-07-12 17:24:46 +02:00
static int VmQueryInterfaceSet ( ph7_class * pClass , SySet * pSet ) {
2018-07-12 13:26:32 +02:00
ph7_class * * apInterface ;
sxu32 n ;
2018-07-12 17:24:46 +02:00
if ( SySetUsed ( pSet ) < 1 ) {
2018-07-12 13:26:32 +02:00
/* Empty interface container */
return FALSE ;
}
/* Point to the set of implemented interfaces */
apInterface = ( ph7_class * * ) SySetBasePtr ( pSet ) ;
/* Perform the lookup */
2018-07-12 17:24:46 +02:00
for ( n = 0 ; n < SySetUsed ( pSet ) ; n + + ) {
if ( apInterface [ n ] = = pClass ) {
2018-07-12 13:26:32 +02:00
return TRUE ;
}
}
return FALSE ;
}
/*
* This function returns TRUE if the given class ( first argument )
* is an instance of the main class ( second argument ) .
2018-07-12 17:24:46 +02:00
* Otherwise FALSE is returned .
2018-07-12 13:26:32 +02:00
*/
2018-07-12 17:24:46 +02:00
static int VmInstanceOf ( ph7_class * pThis , ph7_class * pClass ) {
2019-05-29 08:52:43 +02:00
SyHashEntry * pEntry ;
ph7_class * pDerived , * pParent ;
2018-07-12 13:26:32 +02:00
sxi32 rc ;
2018-07-12 17:24:46 +02:00
if ( pThis = = pClass ) {
2018-07-12 13:26:32 +02:00
/* Instance of the same class */
return TRUE ;
}
/* Check implemented interfaces */
2018-07-12 17:24:46 +02:00
rc = VmQueryInterfaceSet ( pClass , & pThis - > aInterface ) ;
if ( rc ) {
2018-07-12 13:26:32 +02:00
return TRUE ;
}
2019-05-29 08:52:43 +02:00
/* Check derived classes */
SyHashResetLoopCursor ( & pThis - > hDerived ) ;
while ( ( pEntry = SyHashGetNextEntry ( & pThis - > hDerived ) ) ! = 0 ) {
pDerived = ( ph7_class * ) pEntry - > pUserData ;
if ( pDerived = = pClass ) {
2018-07-12 13:26:32 +02:00
/* Same instance */
return TRUE ;
}
/* Check the implemented interfaces */
2019-05-29 08:52:43 +02:00
rc = VmQueryInterfaceSet ( pClass , & pDerived - > aInterface ) ;
2018-07-12 17:24:46 +02:00
if ( rc ) {
2018-07-12 13:26:32 +02:00
return TRUE ;
}
2019-05-29 08:52:43 +02:00
/* Check parent classes */
pParent = pDerived - > pBase ;
while ( pParent ) {
if ( pParent = = pClass ) {
/* Same instance */
return TRUE ;
}
/* Check the implemented interfaces */
rc = VmQueryInterfaceSet ( pClass , & pParent - > aInterface ) ;
if ( rc ) {
return TRUE ;
}
/* Point to the parent class */
pParent = pParent - > pBase ;
}
2018-07-12 13:26:32 +02:00
}
/* Not an instance of the the given class */
return FALSE ;
}
/*
* This function returns TRUE if the given class ( first argument )
* is a subclass of the main class ( second argument ) .
2018-07-12 17:24:46 +02:00
* Otherwise FALSE is returned .
2018-07-12 13:26:32 +02:00
*/
2018-07-12 17:24:46 +02:00
static int VmSubclassOf ( ph7_class * pClass , ph7_class * pBase ) {
2018-07-12 13:26:32 +02:00
SySet * pInterface = & pClass - > aInterface ;
SyHashEntry * pEntry ;
SyString * pName ;
sxi32 rc ;
2018-07-12 17:24:46 +02:00
while ( pClass ) {
2018-07-12 13:26:32 +02:00
pName = & pClass - > sName ;
/* Query the derived hashtable */
2018-07-12 17:24:46 +02:00
pEntry = SyHashGet ( & pBase - > hDerived , ( const void * ) pName - > zString , pName - > nByte ) ;
if ( pEntry ) {
2018-07-12 13:26:32 +02:00
return TRUE ;
}
pClass = pClass - > pBase ;
}
2018-07-12 17:24:46 +02:00
rc = VmQueryInterfaceSet ( pBase , pInterface ) ;
if ( rc ) {
2018-07-12 13:26:32 +02:00
return TRUE ;
}
/* Not a subclass */
return FALSE ;
}
/*
* bool is_a ( object $ object , string $ class_name )
* Checks if the object is of this class or has this class as one of its parents .
* Parameters
* object
* The tested object
* class_name
* The class name
* Return
* Returns TRUE if the object is of this class or has this class as one of its
2018-07-12 17:24:46 +02:00
* parents , FALSE otherwise .
2018-07-12 13:26:32 +02:00
*/
2018-07-12 17:24:46 +02:00
static int vm_builtin_is_a ( ph7_context * pCtx , int nArg , ph7_value * * apArg ) {
2018-07-12 13:26:32 +02:00
int res = 0 ; /* Assume FALSE by default */
2018-07-12 17:24:46 +02:00
if ( nArg > 1 & & ph7_value_is_object ( apArg [ 0 ] ) ) {
2018-07-12 13:26:32 +02:00
ph7_class_instance * pThis = ( ph7_class_instance * ) apArg [ 0 ] - > x . pOther ;
ph7_class * pClass ;
/* Extract the given class */
2018-07-12 17:24:46 +02:00
pClass = VmExtractClassFromValue ( pCtx - > pVm , apArg [ 1 ] ) ;
if ( pClass ) {
2018-07-12 13:26:32 +02:00
/* Perform the query */
2018-07-12 17:24:46 +02:00
res = VmInstanceOf ( pThis - > pClass , pClass ) ;
2018-07-12 13:26:32 +02:00
}
}
/* Query result */
2018-07-12 17:24:46 +02:00
ph7_result_bool ( pCtx , res ) ;
2018-07-12 13:26:32 +02:00
return PH7_OK ;
}
/*
* bool is_subclass_of ( object / string $ object , object / string $ class_name )
* Checks if the object has this class as one of its parents .
* Parameters
* object
* The tested object
* class_name
* The class name
* Return
* This function returns TRUE if the object , belongs to a class
2018-07-12 17:24:46 +02:00
* which is a subclass of class_name , FALSE otherwise .
2018-07-12 13:26:32 +02:00
*/
2018-07-12 17:24:46 +02:00
static int vm_builtin_is_subclass_of ( ph7_context * pCtx , int nArg , ph7_value * * apArg ) {
2018-07-12 13:26:32 +02:00
int res = 0 ; /* Assume FALSE by default */
2018-07-12 17:24:46 +02:00
if ( nArg > 1 ) {
ph7_class * pClass , * pMain ;
2018-07-12 13:26:32 +02:00
/* Extract the given classes */
2018-07-12 17:24:46 +02:00
pClass = VmExtractClassFromValue ( pCtx - > pVm , apArg [ 0 ] ) ;
pMain = VmExtractClassFromValue ( pCtx - > pVm , apArg [ 1 ] ) ;
if ( pClass & & pMain ) {
2018-07-12 13:26:32 +02:00
/* Perform the query */
2018-07-12 17:24:46 +02:00
res = VmSubclassOf ( pClass , pMain ) ;
2018-07-12 13:26:32 +02:00
}
}
/* Query result */
2018-07-12 17:24:46 +02:00
ph7_result_bool ( pCtx , res ) ;
2018-07-12 13:26:32 +02:00
return PH7_OK ;
}
/*
* Call a class method where the name of the method is stored in the pMethod
* parameter and the given arguments are stored in the apArg [ ] array .
2018-07-23 17:10:48 +02:00
* Return SXRET_OK if the method was successfully called . Any other
2018-07-12 13:26:32 +02:00
* return value indicates failure .
*/
PH7_PRIVATE sxi32 PH7_VmCallClassMethod (
ph7_vm * pVm , /* Target VM */
ph7_class_instance * pThis , /* Target class instance [i.e: Object in the PHP jargon]*/
ph7_class_method * pMethod , /* Method name */
ph7_value * pResult , /* Store method return value here. NULL otherwise */
int nArg , /* Total number of given arguments */
ph7_value * * apArg /* Method arguments */
2018-07-12 17:24:46 +02:00
) {
2018-07-12 13:26:32 +02:00
ph7_value * aStack ;
VmInstr aInstr [ 2 ] ;
2018-08-12 12:52:35 +02:00
int iEntry ;
2018-07-12 13:26:32 +02:00
int iCursor ;
int i ;
/* Create a new operand stack */
2018-07-12 17:24:46 +02:00
aStack = VmNewOperandStack ( & ( * pVm ) , 2 /* Method name + Aux data */ + nArg ) ;
if ( aStack = = 0 ) {
2018-09-03 16:16:32 +02:00
PH7_VmMemoryError ( & ( * pVm ) ) ;
2018-07-12 13:26:32 +02:00
}
/* Fill the operand stack with the given arguments */
2018-07-12 17:24:46 +02:00
for ( i = 0 ; i < nArg ; i + + ) {
PH7_MemObjLoad ( apArg [ i ] , & aStack [ i ] ) ;
2018-07-12 13:26:32 +02:00
/*
* Symisc eXtension :
* Parameters to [ call_user_func ( ) ] can be passed by reference .
*/
aStack [ i ] . nIdx = apArg [ i ] - > nIdx ;
}
iCursor = nArg + 1 ;
2018-08-12 12:52:35 +02:00
iEntry = 0 ;
2018-07-12 17:24:46 +02:00
if ( pThis ) {
/*
2018-07-12 13:26:32 +02:00
* Push the class instance so that the ' $ this ' variable will be available .
*/
pThis - > iRef + + ; /* Increment reference count */
2018-07-12 17:24:46 +02:00
aStack [ i ] . x . pOther = pThis ;
2019-05-21 14:49:36 +02:00
aStack [ i ] . nType = MEMOBJ_OBJ ;
2018-08-12 12:52:35 +02:00
if ( SyStrncmp ( pThis - > pClass - > sName . zString , " Program " , 7 ) = = 0 ) {
if ( ( SyStrncmp ( pMethod - > sFunc . sName . zString , " main " , 4 ) = = 0 ) | | ( SyStrncmp ( pMethod - > sFunc . sName . zString , " __construct " , 11 ) = = 0 ) ) {
/* Do not overload entry point */
iEntry = 1 ;
}
}
2018-07-12 13:26:32 +02:00
}
aStack [ i ] . nIdx = SXU32_HIGH ; /* Mark as constant */
i + + ;
/* Push method name */
SyBlobReset ( & aStack [ i ] . sBlob ) ;
2018-07-12 17:24:46 +02:00
SyBlobAppend ( & aStack [ i ] . sBlob , ( const void * ) SyStringData ( & pMethod - > sVmName ) , SyStringLength ( & pMethod - > sVmName ) ) ;
2019-05-21 14:49:36 +02:00
aStack [ i ] . nType = MEMOBJ_STRING ;
2018-07-12 13:26:32 +02:00
aStack [ i ] . nIdx = SXU32_HIGH ;
2018-08-29 08:04:19 +02:00
static const SyString sFileName = { " [MEMORY] " , sizeof ( " [MEMORY] " ) - 1 } ;
2018-08-07 19:45:34 +02:00
/* Emit the CALL instruction */
2018-07-12 13:26:32 +02:00
aInstr [ 0 ] . iOp = PH7_OP_CALL ;
aInstr [ 0 ] . iP1 = nArg ; /* Total number of given arguments */
2018-08-12 12:52:35 +02:00
aInstr [ 0 ] . iP2 = iEntry ;
2018-07-12 13:26:32 +02:00
aInstr [ 0 ] . p3 = 0 ;
2018-08-31 08:25:48 +02:00
aInstr [ 0 ] . bExec = FALSE ;
2018-08-29 08:04:19 +02:00
aInstr [ 0 ] . iLine = 1 ;
aInstr [ 0 ] . pFile = ( SyString * ) & sFileName ;
2018-07-12 13:26:32 +02:00
/* Emit the DONE instruction */
aInstr [ 1 ] . iOp = PH7_OP_DONE ;
aInstr [ 1 ] . iP1 = 1 ; /* Extract method return value */
2019-04-08 13:51:54 +02:00
aInstr [ 1 ] . iP2 = 1 ;
2018-07-12 13:26:32 +02:00
aInstr [ 1 ] . p3 = 0 ;
2018-08-31 08:25:48 +02:00
aInstr [ 1 ] . bExec = FALSE ;
2018-08-29 08:04:19 +02:00
aInstr [ 1 ] . iLine = 1 ;
aInstr [ 1 ] . pFile = ( SyString * ) & sFileName ;
2018-07-12 13:26:32 +02:00
/* Execute the method body (if available) */
2018-07-12 17:24:46 +02:00
VmByteCodeExec ( & ( * pVm ) , aInstr , aStack , iCursor , pResult , 0 , TRUE ) ;
2018-07-12 13:26:32 +02:00
/* Clean up the mess left behind */
2018-07-12 17:24:46 +02:00
SyMemBackendFree ( & pVm - > sAllocator , aStack ) ;
2018-07-12 13:26:32 +02:00
return PH7_OK ;
}
/*
* Call a user defined or foreign function where the name of the function
* is stored in the pFunc parameter and the given arguments are stored
* in the apArg [ ] array .
2018-07-22 22:47:00 +02:00
* Return SXRET_OK if the function was successfully called . Any other
2018-07-12 13:26:32 +02:00
* return value indicates failure .
*/
PH7_PRIVATE sxi32 PH7_VmCallUserFunction (
ph7_vm * pVm , /* Target VM */
ph7_value * pFunc , /* Callback name */
int nArg , /* Total number of given arguments */
ph7_value * * apArg , /* Callback arguments */
ph7_value * pResult /* Store callback return value here. NULL otherwise */
2018-07-12 17:24:46 +02:00
) {
2018-07-12 13:26:32 +02:00
ph7_value * aStack ;
VmInstr aInstr [ 2 ] ;
int i ;
2019-05-21 14:49:36 +02:00
if ( ( pFunc - > nType & ( MEMOBJ_CALL | MEMOBJ_STRING ) ) = = 0 ) {
2018-07-12 13:26:32 +02:00
/* Don't bother processing,it's invalid anyway */
2018-07-12 17:24:46 +02:00
if ( pResult ) {
2018-07-12 13:26:32 +02:00
/* Assume a null return value */
PH7_MemObjRelease ( pResult ) ;
}
return SXERR_INVALID ;
}
/* Create a new operand stack */
2018-07-12 17:24:46 +02:00
aStack = VmNewOperandStack ( & ( * pVm ) , 1 + nArg ) ;
if ( aStack = = 0 ) {
2018-09-03 16:16:32 +02:00
PH7_VmMemoryError ( & ( * pVm ) ) ;
2018-07-12 13:26:32 +02:00
}
/* Fill the operand stack with the given arguments */
2018-07-12 17:24:46 +02:00
for ( i = 0 ; i < nArg ; i + + ) {
PH7_MemObjLoad ( apArg [ i ] , & aStack [ i ] ) ;
/*
2018-07-12 13:26:32 +02:00
* Symisc eXtension :
* Parameters to [ call_user_func ( ) ] can be passed by reference .
*/
aStack [ i ] . nIdx = apArg [ i ] - > nIdx ;
}
/* Push the function name */
2018-07-12 17:24:46 +02:00
PH7_MemObjLoad ( pFunc , & aStack [ i ] ) ;
2018-07-12 13:26:32 +02:00
aStack [ i ] . nIdx = SXU32_HIGH ; /* Mark as constant */
2018-08-29 08:04:19 +02:00
static const SyString sFileName = { " [MEMORY] " , sizeof ( " [MEMORY] " ) - 1 } ;
2018-07-22 19:07:58 +02:00
/* Emit the CALL instruction */
2018-07-12 13:26:32 +02:00
aInstr [ 0 ] . iOp = PH7_OP_CALL ;
aInstr [ 0 ] . iP1 = nArg ; /* Total number of given arguments */
aInstr [ 0 ] . iP2 = 0 ;
aInstr [ 0 ] . p3 = 0 ;
2018-08-31 08:25:48 +02:00
aInstr [ 0 ] . bExec = FALSE ;
2018-08-29 08:04:19 +02:00
aInstr [ 0 ] . iLine = 1 ;
aInstr [ 0 ] . pFile = ( SyString * ) & sFileName ;
2018-07-12 13:26:32 +02:00
/* Emit the DONE instruction */
aInstr [ 1 ] . iOp = PH7_OP_DONE ;
aInstr [ 1 ] . iP1 = 1 ; /* Extract function return value if available */
2019-04-08 13:49:12 +02:00
aInstr [ 1 ] . iP2 = 1 ;
2018-07-12 13:26:32 +02:00
aInstr [ 1 ] . p3 = 0 ;
2018-08-31 08:25:48 +02:00
aInstr [ 1 ] . bExec = FALSE ;
2018-08-29 08:04:19 +02:00
aInstr [ 1 ] . iLine = 1 ;
aInstr [ 1 ] . pFile = ( SyString * ) & sFileName ;
2018-07-12 13:26:32 +02:00
/* Execute the function body (if available) */
2018-07-12 17:24:46 +02:00
VmByteCodeExec ( & ( * pVm ) , aInstr , aStack , nArg , pResult , 0 , TRUE ) ;
2018-07-12 13:26:32 +02:00
/* Clean up the mess left behind */
2018-07-12 17:24:46 +02:00
SyMemBackendFree ( & pVm - > sAllocator , aStack ) ;
2018-07-12 13:26:32 +02:00
return PH7_OK ;
}
/*
2018-08-07 19:45:34 +02:00
* Call a user defined or foreign function with a variable number
2018-07-12 13:26:32 +02:00
* of arguments where the name of the function is stored in the pFunc
* parameter .
2018-07-23 17:10:48 +02:00
* Return SXRET_OK if the function was successfully called . Any other
2018-07-12 13:26:32 +02:00
* return value indicates failure .
*/
PH7_PRIVATE sxi32 PH7_VmCallUserFunctionAp (
ph7_vm * pVm , /* Target VM */
ph7_value * pFunc , /* Callback name */
ph7_value * pResult , /* Store callback return value here. NULL otherwise */
2018-07-12 17:24:46 +02:00
. . . /* 0 (Zero) or more Callback arguments */
) {
2018-07-12 13:26:32 +02:00
ph7_value * pArg ;
SySet aArg ;
va_list ap ;
sxi32 rc ;
2018-07-12 17:24:46 +02:00
SySetInit ( & aArg , & pVm - > sAllocator , sizeof ( ph7_value * ) ) ;
2018-07-12 13:26:32 +02:00
/* Copy arguments one after one */
2018-07-12 17:24:46 +02:00
va_start ( ap , pResult ) ;
for ( ; ; ) {
pArg = va_arg ( ap , ph7_value * ) ;
if ( pArg = = 0 ) {
2018-07-12 13:26:32 +02:00
break ;
}
2018-07-12 17:24:46 +02:00
SySetPut ( & aArg , ( const void * ) & pArg ) ;
2018-07-12 13:26:32 +02:00
}
/* Call the core routine */
2018-07-12 17:24:46 +02:00
rc = PH7_VmCallUserFunction ( & ( * pVm ) , pFunc , ( int ) SySetUsed ( & aArg ) , ( ph7_value * * ) SySetBasePtr ( & aArg ) , pResult ) ;
2018-07-12 13:26:32 +02:00
/* Cleanup */
SySetRelease ( & aArg ) ;
return rc ;
}
/*
* Hash walker callback used by the [ get_defined_constants ( ) ] function
* defined below .
*/
2018-07-12 17:24:46 +02:00
static int VmHashConstStep ( SyHashEntry * pEntry , void * pUserData ) {
2018-07-12 13:26:32 +02:00
ph7_value * pArray = ( ph7_value * ) pUserData ;
ph7_value sName ;
sxi32 rc ;
/* Prepare the constant name for insertion */
2018-07-12 17:24:46 +02:00
PH7_MemObjInitFromString ( pArray - > pVm , & sName , 0 ) ;
PH7_MemObjStringAppend ( & sName , ( const char * ) pEntry - > pKey , pEntry - > nKeyLen ) ;
2018-07-12 13:26:32 +02:00
/* Perform the insertion */
2018-07-12 17:24:46 +02:00
rc = ph7_array_add_elem ( pArray , 0 , & sName ) ; /* Will make it's own copy */
2018-07-12 13:26:32 +02:00
PH7_MemObjRelease ( & sName ) ;
return rc ;
}
/*
* array get_defined_constants ( void )
* Returns an associative array with the names of all defined
2019-05-06 06:54:29 +02:00
* global constants .
2018-07-12 13:26:32 +02:00
* Parameters
* NONE .
* Returns
2019-05-06 06:54:29 +02:00
* Returns the names of all the global constants currently defined .
2018-07-12 13:26:32 +02:00
*/
2018-07-12 17:24:46 +02:00
static int vm_builtin_get_defined_constants ( ph7_context * pCtx , int nArg , ph7_value * * apArg ) {
2018-07-12 13:26:32 +02:00
ph7_value * pArray ;
/* Create the array first*/
pArray = ph7_context_new_array ( pCtx ) ;
2018-07-12 17:24:46 +02:00
if ( pArray = = 0 ) {
2018-07-12 13:26:32 +02:00
SXUNUSED ( nArg ) ; /* cc warning */
SXUNUSED ( apArg ) ;
/* Return NULL */
ph7_result_null ( pCtx ) ;
return SXRET_OK ;
}
/* Fill the array with the defined constants */
2018-07-12 17:24:46 +02:00
SyHashForEach ( & pCtx - > pVm - > hConstant , VmHashConstStep , pArray ) ;
2018-07-12 13:26:32 +02:00
/* Return the created array */
2018-07-12 17:24:46 +02:00
ph7_result_value ( pCtx , pArray ) ;
2018-07-12 13:26:32 +02:00
return SXRET_OK ;
}
/*
* Section :
* Output Control ( OB ) functions .
* Authors :
* Symisc Systems , devel @ symisc . net .
2019-05-15 20:02:39 +02:00
* Copyright ( C ) Symisc Systems , https : //ph7.symisc.net
2018-07-12 13:26:32 +02:00
* Status :
* Stable .
*/
2018-07-12 17:24:46 +02:00
/* Forward declaration */
static void VmObRestore ( ph7_vm * pVm , VmObEntry * pEntry ) ;
2018-07-12 13:26:32 +02:00
/*
* void ob_clean ( void )
* This function discards the contents of the output buffer .
* This function does not destroy the output buffer like ob_end_clean ( ) does .
* Parameter
* None
* Return
* No value is returned .
*/
2018-07-12 17:24:46 +02:00
static int vm_builtin_ob_clean ( ph7_context * pCtx , int nArg , ph7_value * * apArg ) {
2018-07-12 13:26:32 +02:00
ph7_vm * pVm = pCtx - > pVm ;
VmObEntry * pOb ;
SXUNUSED ( nArg ) ; /* cc warning */
SXUNUSED ( apArg ) ;
/* Peek the top most OB */
pOb = ( VmObEntry * ) SySetPeek ( & pVm - > aOB ) ;
2018-07-12 17:24:46 +02:00
if ( pOb ) {
2018-07-12 13:26:32 +02:00
SyBlobRelease ( & pOb - > sOB ) ;
}
return PH7_OK ;
}
/*
* bool ob_end_clean ( void )
* Clean ( erase ) the output buffer and turn off output buffering
* This function discards the contents of the topmost output buffer and turns
* off this output buffering . If you want to further process the buffer ' s contents
* you have to call ob_get_contents ( ) before ob_end_clean ( ) as the buffer contents
2018-07-12 17:24:46 +02:00
* are discarded when ob_end_clean ( ) is called .
2018-07-12 13:26:32 +02:00
* Parameter
* None
* Return
* Returns TRUE on success or FALSE on failure . Reasons for failure are first that you called
* the function without an active buffer or that for some reason a buffer could not be deleted
* ( possible for special buffer )
*/
2018-07-12 17:24:46 +02:00
static int vm_builtin_ob_end_clean ( ph7_context * pCtx , int nArg , ph7_value * * apArg ) {
2018-07-12 13:26:32 +02:00
ph7_vm * pVm = pCtx - > pVm ;
VmObEntry * pOb ;
/* Pop the top most OB */
pOb = ( VmObEntry * ) SySetPop ( & pVm - > aOB ) ;
2018-07-12 17:24:46 +02:00
if ( pOb = = 0 ) {
2018-07-12 13:26:32 +02:00
/* No such OB,return FALSE */
2018-07-12 17:24:46 +02:00
ph7_result_bool ( pCtx , 0 ) ;
2018-07-12 13:26:32 +02:00
SXUNUSED ( nArg ) ; /* cc warning */
SXUNUSED ( apArg ) ;
2018-07-12 17:24:46 +02:00
} else {
2018-07-12 13:26:32 +02:00
/* Release */
2018-07-12 17:24:46 +02:00
VmObRestore ( pVm , pOb ) ;
2018-07-12 13:26:32 +02:00
/* Return true */
2018-07-12 17:24:46 +02:00
ph7_result_bool ( pCtx , 1 ) ;
2018-07-12 13:26:32 +02:00
}
return PH7_OK ;
}
/*
* string ob_get_contents ( void )
* Gets the contents of the output buffer without clearing it .
* Parameter
* None
* Return
* This will return the contents of the output buffer or FALSE , if output buffering isn ' t active .
*/
2018-07-12 17:24:46 +02:00
static int vm_builtin_ob_get_contents ( ph7_context * pCtx , int nArg , ph7_value * * apArg ) {
2018-07-12 13:26:32 +02:00
ph7_vm * pVm = pCtx - > pVm ;
VmObEntry * pOb ;
/* Peek the top most OB */
pOb = ( VmObEntry * ) SySetPeek ( & pVm - > aOB ) ;
2018-07-12 17:24:46 +02:00
if ( pOb = = 0 ) {
2018-07-12 13:26:32 +02:00
/* No active OB,return FALSE */
2018-07-12 17:24:46 +02:00
ph7_result_bool ( pCtx , 0 ) ;
2018-07-12 13:26:32 +02:00
SXUNUSED ( nArg ) ; /* cc warning */
SXUNUSED ( apArg ) ;
2018-07-12 17:24:46 +02:00
} else {
2018-07-12 13:26:32 +02:00
/* Return contents */
2018-07-12 17:24:46 +02:00
ph7_result_string ( pCtx , ( const char * ) SyBlobData ( & pOb - > sOB ) , ( int ) SyBlobLength ( & pOb - > sOB ) ) ;
}
2018-07-12 13:26:32 +02:00
return PH7_OK ;
}
/*
* string ob_get_clean ( void )
* string ob_get_flush ( void )
* Get current buffer contents and delete current output buffer .
* Parameter
* None
* Return
* This will return the contents of the output buffer or FALSE , if output buffering isn ' t active .
*/
2018-07-12 17:24:46 +02:00
static int vm_builtin_ob_get_clean ( ph7_context * pCtx , int nArg , ph7_value * * apArg ) {
2018-07-12 13:26:32 +02:00
ph7_vm * pVm = pCtx - > pVm ;
VmObEntry * pOb ;
/* Pop the top most OB */
pOb = ( VmObEntry * ) SySetPop ( & pVm - > aOB ) ;
2018-07-12 17:24:46 +02:00
if ( pOb = = 0 ) {
2018-07-12 13:26:32 +02:00
/* No active OB,return FALSE */
2018-07-12 17:24:46 +02:00
ph7_result_bool ( pCtx , 0 ) ;
2018-07-12 13:26:32 +02:00
SXUNUSED ( nArg ) ; /* cc warning */
SXUNUSED ( apArg ) ;
2018-07-12 17:24:46 +02:00
} else {
2018-07-12 13:26:32 +02:00
/* Return contents */
2018-07-12 17:24:46 +02:00
ph7_result_string ( pCtx , ( const char * ) SyBlobData ( & pOb - > sOB ) , ( int ) SyBlobLength ( & pOb - > sOB ) ) ; /* Will make it's own copy */
2018-07-12 13:26:32 +02:00
/* Release */
2018-07-12 17:24:46 +02:00
VmObRestore ( pVm , pOb ) ;
}
2018-07-12 13:26:32 +02:00
return PH7_OK ;
}
/*
* int ob_get_length ( void )
* Return the length of the output buffer .
* Parameter
* None
* Return
* Returns the length of the output buffer contents or FALSE if no buffering is active .
*/
2018-07-12 17:24:46 +02:00
static int vm_builtin_ob_get_length ( ph7_context * pCtx , int nArg , ph7_value * * apArg ) {
2018-07-12 13:26:32 +02:00
ph7_vm * pVm = pCtx - > pVm ;
VmObEntry * pOb ;
/* Peek the top most OB */
pOb = ( VmObEntry * ) SySetPeek ( & pVm - > aOB ) ;
2018-07-12 17:24:46 +02:00
if ( pOb = = 0 ) {
2018-07-12 13:26:32 +02:00
/* No active OB,return FALSE */
2018-07-12 17:24:46 +02:00
ph7_result_bool ( pCtx , 0 ) ;
2018-07-12 13:26:32 +02:00
SXUNUSED ( nArg ) ; /* cc warning */
SXUNUSED ( apArg ) ;
2018-07-12 17:24:46 +02:00
} else {
2018-07-12 13:26:32 +02:00
/* Return OB length */
2018-07-12 17:24:46 +02:00
ph7_result_int64 ( pCtx , ( ph7_int64 ) SyBlobLength ( & pOb - > sOB ) ) ;
}
2018-07-12 13:26:32 +02:00
return PH7_OK ;
}
/*
* int ob_get_level ( void )
* Returns the nesting level of the output buffering mechanism .
* Parameter
* None
* Return
2018-07-12 17:24:46 +02:00
* Returns the level of nested output buffering handlers or zero if output buffering is not active .
2018-07-12 13:26:32 +02:00
*/
2018-07-12 17:24:46 +02:00
static int vm_builtin_ob_get_level ( ph7_context * pCtx , int nArg , ph7_value * * apArg ) {
2018-07-12 13:26:32 +02:00
ph7_vm * pVm = pCtx - > pVm ;
int iNest ;
SXUNUSED ( nArg ) ; /* cc warning */
SXUNUSED ( apArg ) ;
/* Nesting level */
iNest = ( int ) SySetUsed ( & pVm - > aOB ) ;
/* Return the nesting value */
2018-07-12 17:24:46 +02:00
ph7_result_int ( pCtx , iNest ) ;
2018-07-12 13:26:32 +02:00
return PH7_OK ;
}
/*
* Output Buffer ( OB ) default VM consumer routine . All VM output is now redirected
* to a stackable internal buffer , until the user call [ ob_get_clean ( ) , ob_end_clean ( ) , . . . ] .
* Refer to the implementation of [ ob_start ( ) ] for more information .
*/
2018-07-12 17:24:46 +02:00
static int VmObConsumer ( const void * pData , unsigned int nDataLen , void * pUserData ) {
2018-07-12 13:26:32 +02:00
ph7_vm * pVm = ( ph7_vm * ) pUserData ;
VmObEntry * pEntry ;
ph7_value sResult ;
/* Peek the top most entry */
pEntry = ( VmObEntry * ) SySetPeek ( & pVm - > aOB ) ;
2018-07-12 17:24:46 +02:00
if ( pEntry = = 0 ) {
2018-07-12 13:26:32 +02:00
/* CAN'T HAPPEN */
return PH7_OK ;
}
2018-07-12 17:24:46 +02:00
PH7_MemObjInit ( pVm , & sResult ) ;
2018-09-05 18:46:42 +02:00
if ( ph7_value_is_callable ( & pEntry - > sCallback ) ) {
2018-07-12 17:24:46 +02:00
ph7_value sArg , * apArg [ 2 ] ;
2018-07-12 13:26:32 +02:00
/* Fill the first argument */
2018-07-12 17:24:46 +02:00
PH7_MemObjInitFromString ( pVm , & sArg , 0 ) ;
PH7_MemObjStringAppend ( & sArg , ( const char * ) pData , nDataLen ) ;
2018-07-12 13:26:32 +02:00
apArg [ 0 ] = & sArg ;
/* Call the 'filter' callback */
2018-07-12 17:24:46 +02:00
PH7_VmCallUserFunction ( pVm , & pEntry - > sCallback , 1 , apArg , & sResult ) ;
2019-05-21 14:49:36 +02:00
if ( sResult . nType & MEMOBJ_STRING ) {
2018-07-12 13:26:32 +02:00
/* Extract the function result */
pData = SyBlobData ( & sResult . sBlob ) ;
nDataLen = SyBlobLength ( & sResult . sBlob ) ;
}
PH7_MemObjRelease ( & sArg ) ;
}
2018-07-12 17:24:46 +02:00
if ( nDataLen > 0 ) {
2018-07-12 13:26:32 +02:00
/* Redirect the VM output to the internal buffer */
2018-07-12 17:24:46 +02:00
SyBlobAppend ( & pEntry - > sOB , pData , nDataLen ) ;
2018-07-12 13:26:32 +02:00
}
/* Release */
PH7_MemObjRelease ( & sResult ) ;
return PH7_OK ;
}
/*
* Restore the default consumer .
* Refer to the implementation of [ ob_end_clean ( ) ] for more
* information .
*/
2018-07-12 17:24:46 +02:00
static void VmObRestore ( ph7_vm * pVm , VmObEntry * pEntry ) {
2018-07-12 13:26:32 +02:00
ph7_output_consumer * pCons = & pVm - > sVmConsumer ;
2018-07-12 17:24:46 +02:00
if ( SySetUsed ( & pVm - > aOB ) < 1 ) {
2018-07-12 13:26:32 +02:00
/* No more stackable OB */
pCons - > xConsumer = pCons - > xDef ;
pCons - > pUserData = pCons - > pDefData ;
}
/* Release OB data */
PH7_MemObjRelease ( & pEntry - > sCallback ) ;
SyBlobRelease ( & pEntry - > sOB ) ;
}
/*
* bool ob_start ( [ callback $ output_callback ] )
* This function will turn output buffering on . While output buffering is active no output
* is sent from the script ( other than headers ) , instead the output is stored in an internal
2018-07-12 17:24:46 +02:00
* buffer .
2018-07-12 13:26:32 +02:00
* Parameter
* $ output_callback
2018-07-12 17:24:46 +02:00
* An optional output_callback function may be specified . This function takes a string
2018-07-12 13:26:32 +02:00
* as a parameter and should return a string . The function will be called when the output
* buffer is flushed ( sent ) or cleaned ( with ob_flush ( ) , ob_clean ( ) or similar function )
* or when the output buffer is flushed to the browser at the end of the request .
* When output_callback is called , it will receive the contents of the output buffer
* as its parameter and is expected to return a new output buffer as a result , which will
* be sent to the browser . If the output_callback is not a callable function , this function
* will return FALSE .
* If the callback function has two parameters , the second parameter is filled with
2018-07-12 17:24:46 +02:00
* a bit - field consisting of PHP_OUTPUT_HANDLER_START , PHP_OUTPUT_HANDLER_CONT
2018-07-12 13:26:32 +02:00
* and PHP_OUTPUT_HANDLER_END .
* If output_callback returns FALSE original input is sent to the browser .
2018-07-12 17:24:46 +02:00
* The output_callback parameter may be bypassed by passing a NULL value .
2018-07-12 13:26:32 +02:00
* Return
* Returns TRUE on success or FALSE on failure .
*/
2018-07-12 17:24:46 +02:00
static int vm_builtin_ob_start ( ph7_context * pCtx , int nArg , ph7_value * * apArg ) {
2018-07-12 13:26:32 +02:00
ph7_vm * pVm = pCtx - > pVm ;
VmObEntry sOb ;
sxi32 rc ;
/* Initialize the OB entry */
2018-07-12 17:24:46 +02:00
PH7_MemObjInit ( pCtx - > pVm , & sOb . sCallback ) ;
SyBlobInit ( & sOb . sOB , & pVm - > sAllocator ) ;
2019-05-21 14:49:36 +02:00
if ( nArg > 0 & & ( apArg [ 0 ] - > nType & ( MEMOBJ_STRING | MEMOBJ_HASHMAP ) ) ) {
2018-07-12 13:26:32 +02:00
/* Save the callback name for later invocation */
2018-07-12 17:24:46 +02:00
PH7_MemObjStore ( apArg [ 0 ] , & sOb . sCallback ) ;
2018-07-12 13:26:32 +02:00
}
/* Push in the stack */
2018-07-12 17:24:46 +02:00
rc = SySetPut ( & pVm - > aOB , ( const void * ) & sOb ) ;
if ( rc ! = SXRET_OK ) {
2018-07-12 13:26:32 +02:00
PH7_MemObjRelease ( & sOb . sCallback ) ;
2018-07-12 17:24:46 +02:00
} else {
2018-07-12 13:26:32 +02:00
ph7_output_consumer * pCons = & pVm - > sVmConsumer ;
/* Substitute the default VM consumer */
2018-07-12 17:24:46 +02:00
if ( pCons - > xConsumer ! = VmObConsumer ) {
2018-07-12 13:26:32 +02:00
pCons - > xDef = pCons - > xConsumer ;
pCons - > pDefData = pCons - > pUserData ;
/* Install the new consumer */
pCons - > xConsumer = VmObConsumer ;
pCons - > pUserData = pVm ;
}
}
2018-07-12 17:24:46 +02:00
ph7_result_bool ( pCtx , rc = = SXRET_OK ) ;
2018-07-12 13:26:32 +02:00
return PH7_OK ;
}
/*
* Flush Output buffer to the default VM output consumer .
* Refer to the implementation of [ ob_flush ( ) ] for more
* information .
*/
2018-07-12 17:24:46 +02:00
static sxi32 VmObFlush ( ph7_vm * pVm , VmObEntry * pEntry , int bRelease ) {
2018-07-12 13:26:32 +02:00
SyBlob * pBlob = & pEntry - > sOB ;
sxi32 rc ;
/* Flush contents */
rc = PH7_OK ;
2018-07-12 17:24:46 +02:00
if ( SyBlobLength ( pBlob ) > 0 ) {
2018-07-12 13:26:32 +02:00
/* Call the VM output consumer */
2018-07-12 17:24:46 +02:00
rc = pVm - > sVmConsumer . xDef ( SyBlobData ( pBlob ) , SyBlobLength ( pBlob ) , pVm - > sVmConsumer . pDefData ) ;
2018-07-12 13:26:32 +02:00
/* Increment VM output counter */
2018-07-12 17:24:46 +02:00
if ( rc ! = PH7_ABORT ) {
2018-07-12 13:26:32 +02:00
rc = PH7_OK ;
}
}
2018-07-12 17:24:46 +02:00
if ( bRelease ) {
VmObRestore ( & ( * pVm ) , pEntry ) ;
} else {
2018-07-12 13:26:32 +02:00
/* Reset the blob */
SyBlobReset ( pBlob ) ;
}
return rc ;
}
/*
* void ob_flush ( void )
* void flush ( void )
* Flush ( send ) the output buffer .
* Parameter
* None
* Return
* No return value .
*/
2018-07-12 17:24:46 +02:00
static int vm_builtin_ob_flush ( ph7_context * pCtx , int nArg , ph7_value * * apArg ) {
2018-07-12 13:26:32 +02:00
ph7_vm * pVm = pCtx - > pVm ;
VmObEntry * pOb ;
sxi32 rc ;
/* Peek the top most OB entry */
pOb = ( VmObEntry * ) SySetPeek ( & pVm - > aOB ) ;
2018-07-12 17:24:46 +02:00
if ( pOb = = 0 ) {
2018-07-12 13:26:32 +02:00
/* Empty stack,return immediately */
SXUNUSED ( nArg ) ; /* cc warning */
SXUNUSED ( apArg ) ;
return PH7_OK ;
}
/* Flush contents */
2018-07-12 17:24:46 +02:00
rc = VmObFlush ( pVm , pOb , FALSE ) ;
2018-07-12 13:26:32 +02:00
return rc ;
}
/*
* bool ob_end_flush ( void )
* Flush ( send ) the output buffer and turn off output buffering .
* Parameter
* None
* Return
* Returns TRUE on success or FALSE on failure . Reasons for failure are first
* that you called the function without an active buffer or that for some reason
2018-07-12 17:24:46 +02:00
* a buffer could not be deleted ( possible for special buffer ) .
2018-07-12 13:26:32 +02:00
*/
2018-07-12 17:24:46 +02:00
static int vm_builtin_ob_end_flush ( ph7_context * pCtx , int nArg , ph7_value * * apArg ) {
2018-07-12 13:26:32 +02:00
ph7_vm * pVm = pCtx - > pVm ;
VmObEntry * pOb ;
sxi32 rc ;
/* Pop the top most OB entry */
pOb = ( VmObEntry * ) SySetPop ( & pVm - > aOB ) ;
2018-07-12 17:24:46 +02:00
if ( pOb = = 0 ) {
2018-07-12 13:26:32 +02:00
/* Empty stack,return FALSE */
2018-07-12 17:24:46 +02:00
ph7_result_bool ( pCtx , 0 ) ;
2018-07-12 13:26:32 +02:00
SXUNUSED ( nArg ) ; /* cc warning */
SXUNUSED ( apArg ) ;
return PH7_OK ;
}
/* Flush contents */
2018-07-12 17:24:46 +02:00
rc = VmObFlush ( pVm , pOb , TRUE ) ;
2018-07-12 13:26:32 +02:00
/* Return true */
2018-07-12 17:24:46 +02:00
ph7_result_bool ( pCtx , 1 ) ;
2018-07-12 13:26:32 +02:00
return rc ;
}
/*
* void ob_implicit_flush ( [ int $ flag = true ] )
* ob_implicit_flush ( ) will turn implicit flushing on or off .
* Implicit flushing will result in a flush operation after every
2018-07-12 17:24:46 +02:00
* output call , so that explicit calls to flush ( ) will no longer be needed .
2018-07-12 13:26:32 +02:00
* Parameter
* $ flag
* TRUE to turn implicit flushing on , FALSE otherwise .
* Return
* Nothing
*/
2018-07-12 17:24:46 +02:00
static int vm_builtin_ob_implicit_flush ( ph7_context * pCtx , int nArg , ph7_value * * apArg ) {
2018-07-12 13:26:32 +02:00
/* NOTE: As of this version,this function is a no-op.
* PH7 is smart enough to flush it ' s internal buffer when appropriate .
*/
SXUNUSED ( pCtx ) ;
SXUNUSED ( nArg ) ; /* cc warning */
SXUNUSED ( apArg ) ;
return PH7_OK ;
}
/*
* array ob_list_handlers ( void )
* Lists all output handlers in use .
* Parameter
* None
* Return
* This will return an array with the output handlers in use ( if any ) .
*/
2018-07-12 17:24:46 +02:00
static int vm_builtin_ob_list_handlers ( ph7_context * pCtx , int nArg , ph7_value * * apArg ) {
ph7_vm * pVm = pCtx - > pVm ;
2018-07-12 13:26:32 +02:00
ph7_value * pArray ;
VmObEntry * aEntry ;
ph7_value sVal ;
sxu32 n ;
2018-07-12 17:24:46 +02:00
if ( SySetUsed ( & pVm - > aOB ) < 1 ) {
2018-07-12 13:26:32 +02:00
/* Empty stack,return null */
ph7_result_null ( pCtx ) ;
return PH7_OK ;
}
/* Create a new array */
pArray = ph7_context_new_array ( pCtx ) ;
2018-07-12 17:24:46 +02:00
if ( pArray = = 0 ) {
2018-07-12 13:26:32 +02:00
/* Out of memory,return NULL */
SXUNUSED ( nArg ) ; /* cc warning */
SXUNUSED ( apArg ) ;
ph7_result_null ( pCtx ) ;
return PH7_OK ;
}
2018-07-12 17:24:46 +02:00
PH7_MemObjInit ( pVm , & sVal ) ;
2018-07-12 13:26:32 +02:00
/* Point to the installed OB entries */
aEntry = ( VmObEntry * ) SySetBasePtr ( & pVm - > aOB ) ;
/* Perform the requested operation */
2018-07-12 17:24:46 +02:00
for ( n = 0 ; n < SySetUsed ( & pVm - > aOB ) ; n + + ) {
2018-07-12 13:26:32 +02:00
VmObEntry * pEntry = & aEntry [ n ] ;
/* Extract handler name */
SyBlobReset ( & sVal . sBlob ) ;
2019-05-21 14:49:36 +02:00
if ( pEntry - > sCallback . nType & MEMOBJ_STRING ) {
2018-07-12 13:26:32 +02:00
/* Callback,dup it's name */
2018-07-12 17:24:46 +02:00
SyBlobDup ( & pEntry - > sCallback . sBlob , & sVal . sBlob ) ;
2019-05-21 14:49:36 +02:00
} else if ( pEntry - > sCallback . nType & MEMOBJ_HASHMAP ) {
2018-07-12 17:24:46 +02:00
SyBlobAppend ( & sVal . sBlob , " Class Method " , sizeof ( " Class Method " ) - 1 ) ;
} else {
SyBlobAppend ( & sVal . sBlob , " default output handler " , sizeof ( " default output handler " ) - 1 ) ;
2018-07-12 13:26:32 +02:00
}
2019-05-21 14:49:36 +02:00
sVal . nType = MEMOBJ_STRING ;
2018-07-12 13:26:32 +02:00
/* Perform the insertion */
2018-07-12 17:24:46 +02:00
ph7_array_add_elem ( pArray , 0 /* Automatic index assign */ , & sVal /* Will make it's own copy */ ) ;
2018-07-12 13:26:32 +02:00
}
PH7_MemObjRelease ( & sVal ) ;
/* Return the freshly created array */
2018-07-12 17:24:46 +02:00
ph7_result_value ( pCtx , pArray ) ;
2018-07-12 13:26:32 +02:00
return PH7_OK ;
}
/*
* Section :
* Random numbers / string generators .
* Authors :
* Symisc Systems , devel @ symisc . net .
2019-05-15 20:02:39 +02:00
* Copyright ( C ) Symisc Systems , https : //ph7.symisc.net
2018-07-12 13:26:32 +02:00
* Status :
* Stable .
*/
/*
* Generate a random 32 - bit unsigned integer .
* PH7 use it ' s own private PRNG which is based on the one
* used by te SQLite3 library .
*/
2018-07-12 17:24:46 +02:00
PH7_PRIVATE sxu32 PH7_VmRandomNum ( ph7_vm * pVm ) {
2018-07-12 13:26:32 +02:00
sxu32 iNum ;
2018-07-12 17:24:46 +02:00
SyRandomness ( & pVm - > sPrng , ( void * ) & iNum , sizeof ( sxu32 ) ) ;
2018-07-12 13:26:32 +02:00
return iNum ;
}
/*
* Generate a random string ( English Alphabet ) of length nLen .
* Note that the generated string is NOT null terminated .
* PH7 use it ' s own private PRNG which is based on the one used
* by te SQLite3 library .
*/
2018-07-12 17:24:46 +02:00
PH7_PRIVATE void PH7_VmRandomString ( ph7_vm * pVm , char * zBuf , int nLen ) {
2018-07-12 13:26:32 +02:00
static const char zBase [ ] = { " abcdefghijklmnopqrstuvwxyz " } ; /* English Alphabet */
int i ;
/* Generate a binary string first */
2018-07-12 17:24:46 +02:00
SyRandomness ( & pVm - > sPrng , zBuf , ( sxu32 ) nLen ) ;
2018-07-12 13:26:32 +02:00
/* Turn the binary string into english based alphabet */
2018-07-12 17:24:46 +02:00
for ( i = 0 ; i < nLen ; + + i ) {
zBuf [ i ] = zBase [ zBuf [ i ] % ( sizeof ( zBase ) - 1 ) ] ;
}
2018-07-12 13:26:32 +02:00
}
2018-07-16 13:15:42 +02:00
PH7_PRIVATE void PH7_VmRandomBytes ( ph7_vm * pVm , unsigned char * zBuf , int nLen ) {
2018-07-22 20:24:00 +02:00
sxu32 iDx ;
int i ;
for ( i = 0 ; i < nLen ; + + i ) {
iDx = PH7_VmRandomNum ( pVm ) ;
iDx % = 255 ;
zBuf [ i ] = ( unsigned char ) iDx ;
}
2018-07-16 13:15:42 +02:00
}
2018-07-12 13:26:32 +02:00
/*
* int rand ( )
2018-07-12 17:24:46 +02:00
* int mt_rand ( )
2018-07-12 13:26:32 +02:00
* int rand ( int $ min , int $ max )
* int mt_rand ( int $ min , int $ max )
* Generate a random ( unsigned 32 - bit ) integer .
* Parameter
* $ min
* The lowest value to return ( default : 0 )
* $ max
* The highest value to return ( default : getrandmax ( ) )
* Return
* A pseudo random value between min ( or 0 ) and max ( or getrandmax ( ) , inclusive ) .
* Note :
* PH7 use it ' s own private PRNG which is based on the one used
* by te SQLite3 library .
*/
2018-07-12 17:24:46 +02:00
static int vm_builtin_rand ( ph7_context * pCtx , int nArg , ph7_value * * apArg ) {
2018-07-12 13:26:32 +02:00
sxu32 iNum ;
/* Generate the random number */
iNum = PH7_VmRandomNum ( pCtx - > pVm ) ;
2018-07-12 17:24:46 +02:00
if ( nArg > 1 ) {
sxu32 iMin , iMax ;
2018-07-12 13:26:32 +02:00
iMin = ( sxu32 ) ph7_value_to_int ( apArg [ 0 ] ) ;
iMax = ( sxu32 ) ph7_value_to_int ( apArg [ 1 ] ) ;
2018-07-12 17:24:46 +02:00
if ( iMin < iMax ) {
sxu32 iDiv = iMax + 1 - iMin ;
if ( iDiv > 0 ) {
iNum = ( iNum % iDiv ) + iMin ;
2018-07-12 13:26:32 +02:00
}
2018-07-12 17:24:46 +02:00
} else if ( iMax > 0 ) {
2018-07-12 13:26:32 +02:00
iNum % = iMax ;
}
}
/* Return the number */
2018-07-12 17:24:46 +02:00
ph7_result_int64 ( pCtx , ( ph7_int64 ) iNum ) ;
2018-07-12 13:26:32 +02:00
return SXRET_OK ;
}
/*
* int getrandmax ( void )
* int mt_getrandmax ( void )
* int rc4_getrandmax ( void )
* Show largest possible random value
* Return
* The largest possible random value returned by rand ( ) which is in
* this implementation 0xFFFFFFFF .
* Note :
* PH7 use it ' s own private PRNG which is based on the one used
* by te SQLite3 library .
*/
2018-07-12 17:24:46 +02:00
static int vm_builtin_getrandmax ( ph7_context * pCtx , int nArg , ph7_value * * apArg ) {
2018-07-12 13:26:32 +02:00
SXUNUSED ( nArg ) ; /* cc warning */
SXUNUSED ( apArg ) ;
2018-07-12 17:24:46 +02:00
ph7_result_int64 ( pCtx , SXU32_HIGH ) ;
2018-07-12 13:26:32 +02:00
return SXRET_OK ;
}
/*
* string rand_str ( )
* string rand_str ( int $ len )
* Generate a random string ( English alphabet ) .
* Parameter
* $ len
* Length of the desired string ( default : 16 , Min : 1 , Max : 1024 )
* Return
* A pseudo random string .
* Note :
* PH7 use it ' s own private PRNG which is based on the one used
* by te SQLite3 library .
* This function is a symisc extension .
*/
2018-07-12 17:24:46 +02:00
static int vm_builtin_rand_str ( ph7_context * pCtx , int nArg , ph7_value * * apArg ) {
2018-07-12 13:26:32 +02:00
char zString [ 1024 ] ;
int iLen = 0x10 ;
2018-07-12 17:24:46 +02:00
if ( nArg > 0 ) {
2018-07-12 13:26:32 +02:00
/* Get the desired length */
iLen = ph7_value_to_int ( apArg [ 0 ] ) ;
2018-07-12 17:24:46 +02:00
if ( iLen < 1 | | iLen > 1024 ) {
2018-07-12 13:26:32 +02:00
/* Default length */
iLen = 0x10 ;
}
}
/* Generate the random string */
2018-07-12 17:24:46 +02:00
PH7_VmRandomString ( pCtx - > pVm , zString , iLen ) ;
2018-07-12 13:26:32 +02:00
/* Return the generated string */
2018-07-12 17:24:46 +02:00
ph7_result_string ( pCtx , zString , iLen ) ; /* Will make it's own copy */
2018-07-12 13:26:32 +02:00
return SXRET_OK ;
}
2018-07-16 13:15:42 +02:00
/*
* int random_int ( int $ min , int $ max )
* Generate a random ( unsigned 32 - bit ) integer .
* Parameter
* $ min
* The lowest value to return
* $ max
* The highest value to return
* Return
* A pseudo random value between min ( or 0 ) and max ( or getrandmax ( ) , inclusive ) .
* Note :
* PH7 use it ' s own private PRNG which is based on the one used
* by te SQLite3 library .
*/
static int vm_builtin_random_int ( ph7_context * pCtx , int nArg , ph7_value * * apArg ) {
2018-07-22 20:24:00 +02:00
sxu32 iNum , iMin , iMax ;
if ( nArg ! = 2 ) {
2018-09-04 08:54:48 +02:00
PH7_VmThrowError ( pCtx - > pVm , PH7_CTX_ERR , " Expecting min and max arguments " ) ;
2018-07-22 20:24:00 +02:00
}
iNum = PH7_VmRandomNum ( pCtx - > pVm ) ;
iMin = ( sxu32 ) ph7_value_to_int ( apArg [ 0 ] ) ;
iMax = ( sxu32 ) ph7_value_to_int ( apArg [ 1 ] ) ;
if ( iMin < iMax ) {
sxu32 iDiv = iMax + 1 - iMin ;
if ( iDiv > 0 ) {
iNum = ( iNum % iDiv ) + iMin ;
}
} else if ( iMax > 0 ) {
iNum % = iMax ;
}
ph7_result_int64 ( pCtx , ( ph7_int64 ) iNum ) ;
return SXRET_OK ;
2018-07-16 13:15:42 +02:00
}
/*
* string random_bytes ( int $ len )
* Generate a random data suite .
* Parameter
* $ len
* Length of the desired data .
* Return
* A pseudo random bytes of $ len
* Note :
* PH7 use it ' s own private PRNG which is based on the one used
* by te SQLite3 library .
*/
static int vm_builtin_random_bytes ( ph7_context * pCtx , int nArg , ph7_value * * apArg ) {
2018-07-22 20:24:00 +02:00
sxu32 iLen ;
unsigned char * zBuf ;
if ( nArg ! = 1 ) {
2018-09-04 08:54:48 +02:00
PH7_VmThrowError ( pCtx - > pVm , PH7_CTX_ERR , " Expecting length argument " ) ;
2018-07-22 20:24:00 +02:00
}
iLen = ( sxu32 ) ph7_value_to_int ( apArg [ 0 ] ) ;
zBuf = SyMemBackendPoolAlloc ( & pCtx - > pVm - > sAllocator , iLen ) ;
if ( zBuf = = 0 ) {
2018-09-04 08:26:58 +02:00
PH7_VmMemoryError ( pCtx - > pVm ) ;
2018-07-22 20:24:00 +02:00
}
PH7_VmRandomBytes ( pCtx - > pVm , zBuf , iLen ) ;
ph7_result_string ( pCtx , ( char * ) zBuf , iLen ) ;
return SXRET_OK ;
2018-07-16 13:15:42 +02:00
}
2018-07-12 13:26:32 +02:00
/* Unique ID private data */
2018-07-12 17:24:46 +02:00
struct unique_id_data {
2018-07-12 13:26:32 +02:00
ph7_context * pCtx ; /* Call context */
int entropy ; /* TRUE if the more_entropy flag is set */
} ;
/*
* Binary to hex consumer callback .
* This callback is the default consumer used by [ uniqid ( ) ] function
* defined below .
*/
2018-07-12 17:24:46 +02:00
static int HexConsumer ( const void * pData , unsigned int nLen , void * pUserData ) {
2018-07-12 13:26:32 +02:00
struct unique_id_data * pUniq = ( struct unique_id_data * ) pUserData ;
sxu32 nBuflen ;
/* Extract result buffer length */
nBuflen = ph7_context_result_buf_length ( pUniq - > pCtx ) ;
2018-07-12 17:24:46 +02:00
if ( nBuflen > 12 & & ! pUniq - > entropy ) {
/*
* If the more_entropy flag is not set , then the returned
* string will be 13 characters long
*/
2018-07-12 13:26:32 +02:00
return SXERR_ABORT ;
}
2018-07-12 17:24:46 +02:00
if ( nBuflen > 22 ) {
2018-07-12 13:26:32 +02:00
return SXERR_ABORT ;
}
/* Safely Consume the hex stream */
2018-07-12 17:24:46 +02:00
ph7_result_string ( pUniq - > pCtx , ( const char * ) pData , ( int ) nLen ) ;
2018-07-12 13:26:32 +02:00
return SXRET_OK ;
}
/*
* string uniqid ( [ string $ prefix = " " [ , bool $ more_entropy = false ] ] )
* Generate a unique ID
* Parameter
* $ prefix
* Append this prefix to the generated unique ID .
* With an empty prefix , the returned string will be 13 characters long .
* If more_entropy is TRUE , it will be 23 characters .
* $ more_entropy
2018-07-12 17:24:46 +02:00
* If set to TRUE , uniqid ( ) will add additional entropy which increases the likelihood
2018-07-12 13:26:32 +02:00
* that the result will be unique .
* Return
* Returns the unique identifier , as a string .
*/
2018-07-12 17:24:46 +02:00
static int vm_builtin_uniqid ( ph7_context * pCtx , int nArg , ph7_value * * apArg ) {
2018-07-12 13:26:32 +02:00
struct unique_id_data sUniq ;
2018-07-12 17:24:46 +02:00
unsigned char zDigest [ 20 ] ;
2018-07-12 13:26:32 +02:00
ph7_vm * pVm = pCtx - > pVm ;
const char * zPrefix ;
SHA1Context sCtx ;
char zRandom [ 7 ] ;
2018-09-05 18:24:34 +02:00
sxu32 uniqueid ;
2018-07-12 13:26:32 +02:00
int nPrefix ;
int entropy ;
/* Generate a random string first */
2018-07-12 17:24:46 +02:00
PH7_VmRandomString ( pVm , zRandom , ( int ) sizeof ( zRandom ) ) ;
2018-09-05 18:24:34 +02:00
/* Generate a random number between 0 and 1023 */
uniqueid = PH7_VmRandomNum ( & ( * pVm ) ) & 1023 ;
2018-07-12 13:26:32 +02:00
/* Initialize fields */
zPrefix = 0 ;
nPrefix = 0 ;
entropy = 0 ;
2018-07-12 17:24:46 +02:00
if ( nArg > 0 ) {
2018-07-23 17:10:48 +02:00
/* Append this prefix to the generated unique ID */
2018-07-12 17:24:46 +02:00
zPrefix = ph7_value_to_string ( apArg [ 0 ] , & nPrefix ) ;
if ( nArg > 1 ) {
2018-07-12 13:26:32 +02:00
entropy = ph7_value_to_bool ( apArg [ 1 ] ) ;
}
}
SHA1Init ( & sCtx ) ;
/* Generate the random ID */
2018-07-12 17:24:46 +02:00
if ( nPrefix > 0 ) {
SHA1Update ( & sCtx , ( const unsigned char * ) zPrefix , ( unsigned int ) nPrefix ) ;
2018-07-12 13:26:32 +02:00
}
/* Append the random ID */
2018-09-05 18:24:34 +02:00
SHA1Update ( & sCtx , ( const unsigned char * ) & uniqueid , sizeof ( int ) ) ;
2018-07-12 13:26:32 +02:00
/* Append the random string */
2018-07-12 17:24:46 +02:00
SHA1Update ( & sCtx , ( const unsigned char * ) zRandom , sizeof ( zRandom ) ) ;
SHA1Final ( & sCtx , zDigest ) ;
2018-07-12 13:26:32 +02:00
/* Hexify the digest */
sUniq . pCtx = pCtx ;
sUniq . entropy = entropy ;
2018-07-12 17:24:46 +02:00
SyBinToHexConsumer ( ( const void * ) zDigest , sizeof ( zDigest ) , HexConsumer , & sUniq ) ;
2018-07-12 13:26:32 +02:00
/* All done */
return PH7_OK ;
}
/*
* Section :
* Language construct implementation as foreign functions .
* Authors :
* Symisc Systems , devel @ symisc . net .
2019-05-15 20:02:39 +02:00
* Copyright ( C ) Symisc Systems , https : //ph7.symisc.net
2018-07-12 13:26:32 +02:00
* Status :
* Stable .
*/
/*
* int print ( $ string . . . )
* Output one or more messages .
* Parameters
* $ string
* Message to output .
* Return
2018-08-06 17:18:27 +02:00
* NULL .
2018-07-12 13:26:32 +02:00
*/
2018-07-12 17:24:46 +02:00
static int vm_builtin_print ( ph7_context * pCtx , int nArg , ph7_value * * apArg ) {
2018-07-12 13:26:32 +02:00
const char * zData ;
int nDataLen = 0 ;
ph7_vm * pVm ;
2018-07-12 17:24:46 +02:00
int i , rc ;
2018-07-12 13:26:32 +02:00
/* Point to the target VM */
pVm = pCtx - > pVm ;
/* Output */
2018-07-12 17:24:46 +02:00
for ( i = 0 ; i < nArg ; + + i ) {
zData = ph7_value_to_string ( apArg [ i ] , & nDataLen ) ;
if ( nDataLen > 0 ) {
rc = pVm - > sVmConsumer . xConsumer ( ( const void * ) zData , ( unsigned int ) nDataLen , pVm - > sVmConsumer . pUserData ) ;
if ( rc = = SXERR_ABORT ) {
2018-07-12 13:26:32 +02:00
/* Output consumer callback request an operation abort */
return PH7_ABORT ;
}
}
}
return SXRET_OK ;
}
/*
* void exit ( string $ msg )
* void exit ( int $ status )
* void die ( string $ ms )
* void die ( int $ status )
* Output a message and terminate program execution .
* Parameter
* If status is a string , this function prints the status just before exiting .
2018-07-12 17:24:46 +02:00
* If status is an integer , that value will be used as the exit status
2018-07-12 13:26:32 +02:00
* and not printed
* Return
* NULL
*/
2018-07-12 17:24:46 +02:00
static int vm_builtin_exit ( ph7_context * pCtx , int nArg , ph7_value * * apArg ) {
if ( nArg > 0 ) {
if ( ph7_value_is_string ( apArg [ 0 ] ) ) {
2018-07-12 13:26:32 +02:00
const char * zData ;
int iLen = 0 ;
/* Print exit message */
2018-07-12 17:24:46 +02:00
zData = ph7_value_to_string ( apArg [ 0 ] , & iLen ) ;
ph7_context_output ( pCtx , zData , iLen ) ;
} else if ( ph7_value_is_int ( apArg [ 0 ] ) ) {
2018-07-12 13:26:32 +02:00
sxi32 iExitStatus ;
/* Record exit status code */
iExitStatus = ph7_value_to_int ( apArg [ 0 ] ) ;
pCtx - > pVm - > iExitStatus = iExitStatus ;
}
}
/* Abort processing immediately */
return PH7_ABORT ;
}
/*
* Unset a memory object [ i . e : a ph7_value ] , remove it from the current
* frame , the reference table and discard it ' s contents .
* This function never fail and always return SXRET_OK .
*/
2018-07-12 17:24:46 +02:00
PH7_PRIVATE sxi32 PH7_VmUnsetMemObj ( ph7_vm * pVm , sxu32 nObjIdx , int bForce ) {
2018-07-12 13:26:32 +02:00
ph7_value * pObj ;
VmRefObj * pRef ;
2018-07-12 17:24:46 +02:00
pObj = ( ph7_value * ) SySetAt ( & pVm - > aMemObj , nObjIdx ) ;
if ( pObj ) {
2018-07-12 13:26:32 +02:00
/* Release the object */
PH7_MemObjRelease ( pObj ) ;
}
/* Remove old reference links */
2018-07-12 17:24:46 +02:00
pRef = VmRefObjExtract ( & ( * pVm ) , nObjIdx ) ;
if ( pRef ) {
2018-07-12 13:26:32 +02:00
sxi32 iFlags = pRef - > iFlags ;
/* Unlink from the reference table */
2018-07-12 17:24:46 +02:00
VmRefObjUnlink ( & ( * pVm ) , pRef ) ;
if ( ( bForce = = TRUE ) | | ( iFlags & VM_REF_IDX_KEEP ) = = 0 ) {
VmSlot sFree ;
2018-07-12 13:26:32 +02:00
/* Restore to the free list */
sFree . nIdx = nObjIdx ;
sFree . pUserData = 0 ;
2018-07-12 17:24:46 +02:00
SySetPut ( & pVm - > aFreeObj , ( const void * ) & sFree ) ;
2018-07-12 13:26:32 +02:00
}
2018-07-12 17:24:46 +02:00
}
2018-07-12 13:26:32 +02:00
return SXRET_OK ;
}
/*
* void unset ( $ var , . . . )
* Unset one or more given variable .
* Parameters
* One or more variable to unset .
* Return
* Nothing .
*/
2018-07-12 17:24:46 +02:00
static int vm_builtin_unset ( ph7_context * pCtx , int nArg , ph7_value * * apArg ) {
2018-07-12 13:26:32 +02:00
ph7_value * pObj ;
ph7_vm * pVm ;
int i ;
/* Point to the target VM */
pVm = pCtx - > pVm ;
/* Iterate and unset */
2018-07-12 17:24:46 +02:00
for ( i = 0 ; i < nArg ; + + i ) {
2018-07-12 13:26:32 +02:00
pObj = apArg [ i ] ;
2018-07-12 17:24:46 +02:00
if ( pObj - > nIdx = = SXU32_HIGH ) {
2019-05-21 14:49:36 +02:00
if ( ( pObj - > nType & MEMOBJ_NULL ) = = 0 ) {
2018-07-12 13:26:32 +02:00
/* Throw an error */
2018-09-04 08:54:48 +02:00
PH7_VmThrowError ( pCtx - > pVm , PH7_CTX_ERR , " Expecting a variable not a constant " ) ;
2018-07-12 13:26:32 +02:00
}
2018-07-12 17:24:46 +02:00
} else {
2019-05-29 13:45:38 +02:00
if ( pObj - > iFlags ! = MEMOBJ_VARIABLE ) {
/* Throw an error */
PH7_VmThrowError ( pCtx - > pVm , PH7_CTX_ERR , " Expecting a variable not AerScript statement " ) ;
}
2018-07-12 13:26:32 +02:00
sxu32 nIdx = pObj - > nIdx ;
2018-09-11 17:49:20 +02:00
PH7_VmUnsetMemObj ( & ( * pVm ) , nIdx , FALSE ) ;
2018-07-12 13:26:32 +02:00
}
}
return SXRET_OK ;
}
/*
* Hash walker callback used by the [ get_defined_vars ( ) ] function .
*/
2018-07-12 17:24:46 +02:00
static sxi32 VmHashVarWalker ( SyHashEntry * pEntry , void * pUserData ) {
2018-07-12 13:26:32 +02:00
ph7_value * pArray = ( ph7_value * ) pUserData ;
ph7_vm * pVm = pArray - > pVm ;
ph7_value * pObj ;
sxu32 nIdx ;
/* Extract the memory object */
nIdx = SX_PTR_TO_INT ( pEntry - > pUserData ) ;
2018-07-12 17:24:46 +02:00
pObj = ( ph7_value * ) SySetAt ( & pVm - > aMemObj , nIdx ) ;
if ( pObj ) {
2019-05-21 14:49:36 +02:00
if ( ( pObj - > nType & MEMOBJ_HASHMAP ) = = 0 ) {
2018-07-12 17:24:46 +02:00
if ( pEntry - > nKeyLen > 0 ) {
2018-07-12 13:26:32 +02:00
SyString sName ;
ph7_value sKey ;
/* Perform the insertion */
2018-07-12 17:24:46 +02:00
SyStringInitFromBuf ( & sName , pEntry - > pKey , pEntry - > nKeyLen ) ;
PH7_MemObjInitFromString ( pVm , & sKey , & sName ) ;
ph7_array_add_elem ( pArray , & sKey /*Will make it's own copy*/ , pObj ) ;
2018-07-12 13:26:32 +02:00
PH7_MemObjRelease ( & sKey ) ;
}
}
}
return SXRET_OK ;
}
/*
* array get_defined_vars ( void )
* Returns an array of all defined variables .
* Parameter
* None
* Return
* An array with all the variables defined in the current scope .
*/
2018-07-12 17:24:46 +02:00
static int vm_builtin_get_defined_vars ( ph7_context * pCtx , int nArg , ph7_value * * apArg ) {
2018-07-12 13:26:32 +02:00
ph7_vm * pVm = pCtx - > pVm ;
ph7_value * pArray ;
/* Create a new array */
pArray = ph7_context_new_array ( pCtx ) ;
2018-07-12 17:24:46 +02:00
if ( pArray = = 0 ) {
2018-07-12 13:26:32 +02:00
SXUNUSED ( nArg ) ; /* cc warning */
SXUNUSED ( apArg ) ;
/* Return NULL */
ph7_result_null ( pCtx ) ;
return SXRET_OK ;
}
/* Superglobals first */
2018-07-12 17:24:46 +02:00
SyHashForEach ( & pVm - > hSuper , VmHashVarWalker , pArray ) ;
2018-07-12 13:26:32 +02:00
/* Then variable defined in the current frame */
2018-07-12 17:24:46 +02:00
SyHashForEach ( & pVm - > pFrame - > hVar , VmHashVarWalker , pArray ) ;
2018-07-12 13:26:32 +02:00
/* Finally,return the created array */
2018-07-12 17:24:46 +02:00
ph7_result_value ( pCtx , pArray ) ;
2018-07-12 13:26:32 +02:00
return SXRET_OK ;
}
/*
* bool gettype ( $ var )
* Get the type of a variable
* Parameters
* $ var
* The variable being type checked .
* Return
* String representation of the given variable type .
*/
2018-07-12 17:24:46 +02:00
static int vm_builtin_gettype ( ph7_context * pCtx , int nArg , ph7_value * * apArg ) {
2018-07-12 13:26:32 +02:00
const char * zType = " Empty " ;
2018-07-12 17:24:46 +02:00
if ( nArg > 0 ) {
2018-07-12 13:26:32 +02:00
zType = PH7_MemObjTypeDump ( apArg [ 0 ] ) ;
}
/* Return the variable type */
2018-07-12 17:24:46 +02:00
ph7_result_string ( pCtx , zType , - 1 /*Compute length automatically*/ ) ;
2018-07-12 13:26:32 +02:00
return SXRET_OK ;
}
/*
* string get_resource_type ( resource $ handle )
* This function gets the type of the given resource .
* Parameters
* $ handle
* The evaluated resource handle .
* Return
2018-07-12 17:24:46 +02:00
* If the given handle is a resource , this function will return a string
2018-07-12 13:26:32 +02:00
* representing its type . If the type is not identified by this function
* the return value will be the string Unknown .
* This function will return FALSE and generate an error if handle
* is not a resource .
*/
2018-07-12 17:24:46 +02:00
static int vm_builtin_get_resource_type ( ph7_context * pCtx , int nArg , ph7_value * * apArg ) {
if ( nArg < 1 | | ! ph7_value_is_resource ( apArg [ 0 ] ) ) {
2018-07-12 13:26:32 +02:00
/* Missing/Invalid arguments,return FALSE*/
2018-07-12 17:24:46 +02:00
ph7_result_bool ( pCtx , 0 ) ;
2018-07-12 13:26:32 +02:00
return PH7_OK ;
}
2018-07-12 17:24:46 +02:00
ph7_result_string_format ( pCtx , " resID_%#x " , apArg [ 0 ] - > x . pOther ) ;
2018-07-12 13:26:32 +02:00
return SXRET_OK ;
}
/*
* void var_dump ( expression , . . . . )
* var_dump <EFBFBD> Dumps information about a variable
* Parameters
* One or more expression to dump .
* Returns
* Nothing .
*/
2018-07-12 17:24:46 +02:00
static int vm_builtin_var_dump ( ph7_context * pCtx , int nArg , ph7_value * * apArg ) {
2018-07-12 13:26:32 +02:00
SyBlob sDump ; /* Generated dump is stored here */
int i ;
2018-07-12 17:24:46 +02:00
SyBlobInit ( & sDump , & pCtx - > pVm - > sAllocator ) ;
2018-07-12 13:26:32 +02:00
/* Dump one or more expressions */
2018-07-12 17:24:46 +02:00
for ( i = 0 ; i < nArg ; i + + ) {
2018-07-12 13:26:32 +02:00
ph7_value * pObj = apArg [ i ] ;
/* Reset the working buffer */
SyBlobReset ( & sDump ) ;
/* Dump the given expression */
2019-03-29 22:55:49 +01:00
PH7_MemObjDump ( & sDump , pObj , TRUE , 0 , 0 ) ;
2018-07-12 13:26:32 +02:00
/* Output */
2018-07-12 17:24:46 +02:00
if ( SyBlobLength ( & sDump ) > 0 ) {
ph7_context_output ( pCtx , ( const char * ) SyBlobData ( & sDump ) , ( int ) SyBlobLength ( & sDump ) ) ;
2018-07-12 13:26:32 +02:00
}
}
/* Release the working buffer */
SyBlobRelease ( & sDump ) ;
return SXRET_OK ;
}
/*
* string / bool print_r ( expression , [ bool $ return = FALSE ] )
2018-07-12 17:24:46 +02:00
* print - r - Prints human - readable information about a variable
2018-07-12 13:26:32 +02:00
* Parameters
* expression : Expression to dump
* return : If you would like to capture the output of print_r ( ) use
* the return parameter . When this parameter is set to TRUE
* print_r ( ) will return the information rather than print it .
* Return
* When the return parameter is TRUE , this function will return a string .
* Otherwise , the return value is TRUE .
*/
2018-07-12 17:24:46 +02:00
static int vm_builtin_print_r ( ph7_context * pCtx , int nArg , ph7_value * * apArg ) {
2018-07-12 13:26:32 +02:00
int ret_string = 0 ;
SyBlob sDump ;
2018-07-12 17:24:46 +02:00
if ( nArg < 1 ) {
2018-07-12 13:26:32 +02:00
/* Nothing to output,return FALSE */
2018-07-12 17:24:46 +02:00
ph7_result_bool ( pCtx , 0 ) ;
2018-07-12 13:26:32 +02:00
return SXRET_OK ;
}
2018-07-12 17:24:46 +02:00
SyBlobInit ( & sDump , & pCtx - > pVm - > sAllocator ) ;
if ( nArg > 1 ) {
2018-07-12 13:26:32 +02:00
/* Where to redirect output */
ret_string = ph7_value_to_bool ( apArg [ 1 ] ) ;
}
/* Generate dump */
2019-03-29 22:55:49 +01:00
PH7_MemObjDump ( & sDump , apArg [ 0 ] , FALSE , 0 , 0 ) ;
2018-07-12 17:24:46 +02:00
if ( ! ret_string ) {
2018-07-12 13:26:32 +02:00
/* Output dump */
2018-07-12 17:24:46 +02:00
ph7_context_output ( pCtx , ( const char * ) SyBlobData ( & sDump ) , ( int ) SyBlobLength ( & sDump ) ) ;
2018-07-12 13:26:32 +02:00
/* Return true */
2018-07-12 17:24:46 +02:00
ph7_result_bool ( pCtx , 1 ) ;
} else {
2018-07-12 13:26:32 +02:00
/* Generated dump as return value */
2018-07-12 17:24:46 +02:00
ph7_result_string ( pCtx , ( const char * ) SyBlobData ( & sDump ) , ( int ) SyBlobLength ( & sDump ) ) ;
2018-07-12 13:26:32 +02:00
}
/* Release the working buffer */
SyBlobRelease ( & sDump ) ;
return SXRET_OK ;
}
/*
* string / null var_export ( expression , [ bool $ return = FALSE ] )
* Same job as print_r . ( see coment above )
*/
2018-07-12 17:24:46 +02:00
static int vm_builtin_var_export ( ph7_context * pCtx , int nArg , ph7_value * * apArg ) {
2018-07-12 13:26:32 +02:00
int ret_string = 0 ;
SyBlob sDump ; /* Dump is stored in this BLOB */
2018-07-12 17:24:46 +02:00
if ( nArg < 1 ) {
2018-07-12 13:26:32 +02:00
/* Nothing to output,return FALSE */
2018-07-12 17:24:46 +02:00
ph7_result_bool ( pCtx , 0 ) ;
2018-07-12 13:26:32 +02:00
return SXRET_OK ;
}
2018-07-12 17:24:46 +02:00
SyBlobInit ( & sDump , & pCtx - > pVm - > sAllocator ) ;
if ( nArg > 1 ) {
2018-07-12 13:26:32 +02:00
/* Where to redirect output */
ret_string = ph7_value_to_bool ( apArg [ 1 ] ) ;
}
/* Generate dump */
2019-03-29 22:55:49 +01:00
PH7_MemObjDump ( & sDump , apArg [ 0 ] , FALSE , 0 , 0 ) ;
2018-07-12 17:24:46 +02:00
if ( ! ret_string ) {
2018-07-12 13:26:32 +02:00
/* Output dump */
2018-07-12 17:24:46 +02:00
ph7_context_output ( pCtx , ( const char * ) SyBlobData ( & sDump ) , ( int ) SyBlobLength ( & sDump ) ) ;
2018-07-12 13:26:32 +02:00
/* Return NULL */
ph7_result_null ( pCtx ) ;
2018-07-12 17:24:46 +02:00
} else {
2018-07-12 13:26:32 +02:00
/* Generated dump as return value */
2018-07-12 17:24:46 +02:00
ph7_result_string ( pCtx , ( const char * ) SyBlobData ( & sDump ) , ( int ) SyBlobLength ( & sDump ) ) ;
2018-07-12 13:26:32 +02:00
}
/* Release the working buffer */
SyBlobRelease ( & sDump ) ;
return SXRET_OK ;
}
/*
2018-08-18 19:32:33 +02:00
* int get_memory_limit ( )
* Returns the amount of bytes that can be allocated from system .
2018-08-18 19:24:38 +02:00
* Parameters
* None
* Return
2018-08-18 19:32:33 +02:00
* The upper memory limit set for script processing .
2018-08-18 19:24:38 +02:00
*/
static int vm_builtin_get_memory_limit ( ph7_context * pCtx , int nArg , ph7_value * * apArg ) {
if ( nArg ! = 0 ) {
ph7_result_bool ( pCtx , 0 ) ;
} else {
ph7_result_int64 ( pCtx , pCtx - > pVm - > sAllocator . pHeap - > nLimit ) ;
}
return PH7_OK ;
}
/*
* int get_memory_peak_usage ( )
* Returns the limit of memory set in Interpreter .
* Parameters
* None
* Return
* The maximum amount of memory that can be allocated from system .
*/
static int vm_builtin_get_memory_peak_usage ( ph7_context * pCtx , int nArg , ph7_value * * apArg ) {
if ( nArg ! = 0 ) {
ph7_result_bool ( pCtx , 0 ) ;
} else {
ph7_result_int64 ( pCtx , pCtx - > pVm - > sAllocator . pHeap - > nPeak ) ;
}
return PH7_OK ;
}
/*
* int get_memory_usage ( )
* Returns the amount of memory , in bytes , that ' s currently being allocated .
* Parameters
* None
* Return
* Total memory allocated from system , including unused pages .
*/
static int vm_builtin_get_memory_usage ( ph7_context * pCtx , int nArg , ph7_value * * apArg ) {
if ( nArg ! = 0 ) {
ph7_result_bool ( pCtx , 0 ) ;
} else {
ph7_result_int64 ( pCtx , pCtx - > pVm - > sAllocator . pHeap - > nSize ) ;
}
return PH7_OK ;
} /*
2018-07-12 13:26:32 +02:00
* int / bool assert_options ( int $ what [ , mixed $ value ] )
* Set / get the various assert flags .
* Parameter
* $ what
* ASSERT_ACTIVE Enable assert ( ) evaluation
* ASSERT_WARNING Issue a warning for each failed assertion
* ASSERT_BAIL Terminate execution on failed assertions
* ASSERT_QUIET_EVAL Not used
* ASSERT_CALLBACK Callback to call on failed assertions
* $ value
* An optional new value for the option .
* Return
2018-07-12 17:24:46 +02:00
* Old setting on success or FALSE on failure .
2018-07-12 13:26:32 +02:00
*/
2018-07-12 17:24:46 +02:00
static int vm_builtin_assert_options ( ph7_context * pCtx , int nArg , ph7_value * * apArg ) {
2018-07-12 13:26:32 +02:00
ph7_vm * pVm = pCtx - > pVm ;
2018-07-12 17:24:46 +02:00
int iOld , iNew , iValue ;
if ( nArg < 1 | | ! ph7_value_is_int ( apArg [ 0 ] ) ) {
2018-07-12 13:26:32 +02:00
/* Missing/Invalid arguments,return FALSE */
2018-07-12 17:24:46 +02:00
ph7_result_bool ( pCtx , 0 ) ;
2018-07-12 13:26:32 +02:00
return PH7_OK ;
}
/* Save old assertion flags */
iOld = pVm - > iAssertFlags ;
/* Extract the new flags */
iNew = ph7_value_to_int ( apArg [ 0 ] ) ;
2018-07-12 17:24:46 +02:00
if ( iNew = = PH7_ASSERT_DISABLE ) {
2018-07-12 13:26:32 +02:00
pVm - > iAssertFlags & = ~ PH7_ASSERT_DISABLE ;
2018-07-12 17:24:46 +02:00
if ( nArg > 1 ) {
2018-07-12 13:26:32 +02:00
iValue = ! ph7_value_to_bool ( apArg [ 1 ] ) ;
2018-07-12 17:24:46 +02:00
if ( iValue ) {
2018-07-12 13:26:32 +02:00
/* Disable assertion */
pVm - > iAssertFlags | = PH7_ASSERT_DISABLE ;
}
}
2018-07-12 17:24:46 +02:00
} else if ( iNew = = PH7_ASSERT_WARNING ) {
2018-07-12 13:26:32 +02:00
pVm - > iAssertFlags & = ~ PH7_ASSERT_WARNING ;
2018-07-12 17:24:46 +02:00
if ( nArg > 1 ) {
2018-07-12 13:26:32 +02:00
iValue = ph7_value_to_bool ( apArg [ 1 ] ) ;
2018-07-12 17:24:46 +02:00
if ( iValue ) {
2018-07-12 13:26:32 +02:00
/* Issue a warning for each failed assertion */
pVm - > iAssertFlags | = PH7_ASSERT_WARNING ;
}
}
2018-07-12 17:24:46 +02:00
} else if ( iNew = = PH7_ASSERT_BAIL ) {
2018-07-12 13:26:32 +02:00
pVm - > iAssertFlags & = ~ PH7_ASSERT_BAIL ;
2018-07-12 17:24:46 +02:00
if ( nArg > 1 ) {
2018-07-12 13:26:32 +02:00
iValue = ph7_value_to_bool ( apArg [ 1 ] ) ;
2018-07-12 17:24:46 +02:00
if ( iValue ) {
2018-07-12 13:26:32 +02:00
/* Terminate execution on failed assertions */
pVm - > iAssertFlags | = PH7_ASSERT_BAIL ;
}
}
2018-07-12 17:24:46 +02:00
} else if ( iNew = = PH7_ASSERT_CALLBACK ) {
2018-07-12 13:26:32 +02:00
pVm - > iAssertFlags & = ~ PH7_ASSERT_CALLBACK ;
2018-07-12 17:24:46 +02:00
if ( nArg > 1 & & ph7_value_is_callable ( apArg [ 1 ] ) ) {
2018-07-12 13:26:32 +02:00
/* Callback to call on failed assertions */
2018-07-12 17:24:46 +02:00
PH7_MemObjStore ( apArg [ 1 ] , & pVm - > sAssertCallback ) ;
2018-07-12 13:26:32 +02:00
pVm - > iAssertFlags | = PH7_ASSERT_CALLBACK ;
}
}
/* Return the old flags */
2018-07-12 17:24:46 +02:00
ph7_result_int ( pCtx , iOld ) ;
2018-07-12 13:26:32 +02:00
return PH7_OK ;
}
/*
* bool assert ( mixed $ assertion )
* Checks if assertion is FALSE .
* Parameter
* $ assertion
* The assertion to test .
* Return
* FALSE if the assertion is false , TRUE otherwise .
*/
2018-07-12 17:24:46 +02:00
static int vm_builtin_assert ( ph7_context * pCtx , int nArg , ph7_value * * apArg ) {
2018-07-12 13:26:32 +02:00
ph7_vm * pVm = pCtx - > pVm ;
ph7_value * pAssert ;
2018-07-12 17:24:46 +02:00
int iFlags , iResult ;
if ( nArg < 1 ) {
2018-07-12 13:26:32 +02:00
/* Missing arguments,return FALSE */
2018-07-12 17:24:46 +02:00
ph7_result_bool ( pCtx , 0 ) ;
2018-07-12 13:26:32 +02:00
return PH7_OK ;
}
iFlags = pVm - > iAssertFlags ;
2018-07-12 17:24:46 +02:00
if ( iFlags & PH7_ASSERT_DISABLE ) {
2018-07-12 13:26:32 +02:00
/* Assertion is disabled,return FALSE */
2018-07-12 17:24:46 +02:00
ph7_result_bool ( pCtx , 0 ) ;
2018-07-12 13:26:32 +02:00
return PH7_OK ;
}
pAssert = apArg [ 0 ] ;
iResult = 1 ; /* cc warning */
2019-05-21 14:49:36 +02:00
if ( pAssert - > nType & MEMOBJ_STRING ) {
2018-07-12 13:26:32 +02:00
SyString sChunk ;
2018-07-12 17:24:46 +02:00
SyStringInitFromBuf ( & sChunk , SyBlobData ( & pAssert - > sBlob ) , SyBlobLength ( & pAssert - > sBlob ) ) ;
if ( sChunk . nByte > 0 ) {
2018-08-16 09:34:18 +02:00
VmEvalChunk ( pVm , pCtx , & sChunk , PH7_AERSCRIPT_CHNK | PH7_AERSCRIPT_EXPR ) ;
2018-07-12 13:26:32 +02:00
/* Extract evaluation result */
iResult = ph7_value_to_bool ( pCtx - > pRet ) ;
2018-07-12 17:24:46 +02:00
} else {
2018-07-12 13:26:32 +02:00
iResult = 0 ;
}
2018-07-12 17:24:46 +02:00
} else {
2018-07-12 13:26:32 +02:00
/* Perform a boolean cast */
iResult = ph7_value_to_bool ( apArg [ 0 ] ) ;
}
2018-07-12 17:24:46 +02:00
if ( ! iResult ) {
2018-07-12 13:26:32 +02:00
/* Assertion failed */
2018-07-12 17:24:46 +02:00
if ( iFlags & PH7_ASSERT_CALLBACK ) {
2018-08-27 08:22:05 +02:00
static const SyString sFileName = { " [MEMORY] " , sizeof ( " [MEMORY] " ) - 1 } ;
2018-07-12 17:24:46 +02:00
ph7_value sFile , sLine ;
2018-07-12 13:26:32 +02:00
ph7_value * apCbArg [ 3 ] ;
SyString * pFile ;
/* Extract the processed script */
pFile = ( SyString * ) SySetPeek ( & pVm - > aFiles ) ;
2018-07-12 17:24:46 +02:00
if ( pFile = = 0 ) {
2018-07-12 13:26:32 +02:00
pFile = ( SyString * ) & sFileName ;
}
/* Invoke the callback */
2018-07-12 17:24:46 +02:00
PH7_MemObjInitFromString ( pVm , & sFile , pFile ) ;
2019-04-10 09:18:26 +02:00
PH7_MemObjInitFromInt ( pVm , & sLine , 1 ) ;
2018-07-12 13:26:32 +02:00
apCbArg [ 0 ] = & sFile ;
apCbArg [ 1 ] = & sLine ;
apCbArg [ 2 ] = pAssert ;
2018-07-12 17:24:46 +02:00
PH7_VmCallUserFunction ( pVm , & pVm - > sAssertCallback , 3 , apCbArg , 0 ) ;
2018-07-12 13:26:32 +02:00
/* Clean-up the mess left behind */
PH7_MemObjRelease ( & sFile ) ;
PH7_MemObjRelease ( & sLine ) ;
}
2018-07-12 17:24:46 +02:00
if ( iFlags & PH7_ASSERT_WARNING ) {
2018-07-12 13:26:32 +02:00
/* Emit a warning */
2018-09-04 08:54:48 +02:00
PH7_VmThrowError ( pCtx - > pVm , PH7_CTX_WARNING , " Assertion failed " ) ;
2018-07-12 13:26:32 +02:00
}
2018-07-12 17:24:46 +02:00
if ( iFlags & PH7_ASSERT_BAIL ) {
2018-07-12 13:26:32 +02:00
/* Abort VM execution immediately */
return PH7_ABORT ;
}
}
/* Assertion result */
2018-07-12 17:24:46 +02:00
ph7_result_bool ( pCtx , iResult ) ;
2018-07-12 13:26:32 +02:00
return PH7_OK ;
}
/*
* Section :
* Error reporting functions .
* Authors :
* Symisc Systems , devel @ symisc . net .
2019-05-15 20:02:39 +02:00
* Copyright ( C ) Symisc Systems , https : //ph7.symisc.net
2018-07-12 13:26:32 +02:00
* Status :
* Stable .
*/
/*
2018-07-12 17:24:46 +02:00
* bool restore_exception_handler ( void )
2018-07-12 13:26:32 +02:00
* Restores the previously defined exception handler function .
* Parameter
* None
* Return
* TRUE if the exception handler is restored . FALSE otherwise
*/
2018-07-12 17:24:46 +02:00
static int vm_builtin_restore_exception_handler ( ph7_context * pCtx , int nArg , ph7_value * * apArg ) {
2018-07-12 13:26:32 +02:00
ph7_vm * pVm = pCtx - > pVm ;
2018-07-12 17:24:46 +02:00
ph7_value * pOld , * pNew ;
2018-07-12 13:26:32 +02:00
/* Point to the old and the new handler */
pOld = & pVm - > aExceptionCB [ 0 ] ;
pNew = & pVm - > aExceptionCB [ 1 ] ;
2019-05-21 14:49:36 +02:00
if ( pOld - > nType & MEMOBJ_NULL ) {
2018-07-12 13:26:32 +02:00
SXUNUSED ( nArg ) ; /* cc warning */
SXUNUSED ( apArg ) ;
/* No installed handler,return FALSE */
2018-07-12 17:24:46 +02:00
ph7_result_bool ( pCtx , 0 ) ;
2018-07-12 13:26:32 +02:00
return PH7_OK ;
}
/* Copy the old handler */
2018-07-12 17:24:46 +02:00
PH7_MemObjStore ( pOld , pNew ) ;
2018-07-12 13:26:32 +02:00
PH7_MemObjRelease ( pOld ) ;
/* Return TRUE */
2018-07-12 17:24:46 +02:00
ph7_result_bool ( pCtx , 1 ) ;
2018-07-12 13:26:32 +02:00
return PH7_OK ;
}
/*
* callable set_exception_handler ( callable $ exception_handler )
* Sets a user - defined exception handler function .
* Sets the default exception handler if an exception is not caught within a try / catch block .
* NOTE
* Execution will NOT stop after the exception_handler calls for example die / exit unlike
2018-07-23 17:10:48 +02:00
* the standard PHP engine .
2018-07-12 13:26:32 +02:00
* Parameters
* $ exception_handler
* Name of the function to be called when an uncaught exception occurs .
* This handler function needs to accept one parameter , which will be the exception object
* that was thrown .
* Note :
2018-07-12 17:24:46 +02:00
* NULL may be passed instead , to reset this handler to its default state .
2018-07-12 13:26:32 +02:00
* Return
* Returns the name of the previously defined exception handler , or NULL on error .
* If no previous handler was defined , NULL is also returned . If NULL is passed
2018-07-12 17:24:46 +02:00
* resetting the handler to its default state , TRUE is returned .
2018-07-12 13:26:32 +02:00
*/
2018-07-12 17:24:46 +02:00
static int vm_builtin_set_exception_handler ( ph7_context * pCtx , int nArg , ph7_value * * apArg ) {
2018-07-12 13:26:32 +02:00
ph7_vm * pVm = pCtx - > pVm ;
2018-07-12 17:24:46 +02:00
ph7_value * pOld , * pNew ;
2018-07-12 13:26:32 +02:00
/* Point to the old and the new handler */
pOld = & pVm - > aExceptionCB [ 0 ] ;
pNew = & pVm - > aExceptionCB [ 1 ] ;
/* Return the old handler */
2018-07-12 17:24:46 +02:00
ph7_result_value ( pCtx , pOld ) ; /* Will make it's own copy */
if ( nArg > 0 ) {
if ( ! ph7_value_is_callable ( apArg [ 0 ] ) ) {
2018-07-12 13:26:32 +02:00
/* Not callable,return TRUE (As requested by the PHP specification) */
PH7_MemObjRelease ( pNew ) ;
2018-07-12 17:24:46 +02:00
ph7_result_bool ( pCtx , 1 ) ;
} else {
PH7_MemObjStore ( pNew , pOld ) ;
2018-07-12 13:26:32 +02:00
/* Install the new handler */
2018-07-12 17:24:46 +02:00
PH7_MemObjStore ( apArg [ 0 ] , pNew ) ;
2018-07-12 13:26:32 +02:00
}
}
return PH7_OK ;
}
/*
* array debug_backtrace ( [ int $ options = DEBUG_BACKTRACE_PROVIDE_OBJECT [ , int $ limit = 0 ] ] )
* Generates a backtrace .
2018-07-23 17:10:48 +02:00
* Parameter
2018-07-12 13:26:32 +02:00
* $ options
* DEBUG_BACKTRACE_PROVIDE_OBJECT : Whether or not to populate the " object " index .
* DEBUG_BACKTRACE_IGNORE_ARGS Whether or not to omit the " args " index , and thus
* all the function / method arguments , to save memory .
* $ limit
* ( Not Used )
* Return
* An array . The possible returned elements are as follows :
* Possible returned elements from debug_backtrace ( )
* Name Type Description
* - - - - - - - - - - - - - - - - - - - - - - -
* function string The current function name . See also __FUNCTION__ .
* line integer The current line number . See also __LINE__ .
* file string The current file name . See also __FILE__ .
* class string The current class name . See also __CLASS__
* object object The current object .
* args array If inside a function , this lists the functions arguments .
2018-07-12 17:24:46 +02:00
* If inside an included file , this lists the included file name ( s ) .
2018-07-12 13:26:32 +02:00
*/
2018-07-12 17:24:46 +02:00
static int vm_builtin_debug_backtrace ( ph7_context * pCtx , int nArg , ph7_value * * apArg ) {
2018-07-12 13:26:32 +02:00
ph7_vm * pVm = pCtx - > pVm ;
2018-08-27 15:47:34 +02:00
SySet pDebug ;
VmDebugTrace * pTrace ;
2018-07-12 13:26:32 +02:00
ph7_value * pArray ;
2018-08-27 15:47:34 +02:00
/* Extract debug information */
2018-09-02 18:53:23 +02:00
if ( VmExtractDebugTrace ( & ( * pVm ) , & pDebug ) ! = SXRET_OK ) {
2018-08-27 15:47:34 +02:00
ph7_result_null ( pCtx ) ;
return PH7_OK ;
}
2018-07-12 13:26:32 +02:00
pArray = ph7_context_new_array ( pCtx ) ;
2018-08-27 15:47:34 +02:00
if ( ! pArray ) {
2018-09-04 08:26:58 +02:00
PH7_VmMemoryError ( pCtx - > pVm ) ;
2018-07-12 13:26:32 +02:00
}
2018-08-27 15:47:34 +02:00
/* Iterate through debug frames */
while ( SySetGetNextEntry ( & pDebug , ( void * * ) & pTrace ) = = SXRET_OK ) {
VmSlot * aSlot ;
ph7_value * pArg , * pSubArray , * pValue ;
2018-07-12 13:26:32 +02:00
pArg = ph7_context_new_array ( pCtx ) ;
2018-08-27 15:47:34 +02:00
pSubArray = ph7_context_new_array ( pCtx ) ;
pValue = ph7_context_new_scalar ( pCtx ) ;
if ( pArg = = 0 | | pSubArray = = 0 | | pValue = = 0 ) {
2018-09-04 08:26:58 +02:00
PH7_VmMemoryError ( pCtx - > pVm ) ;
2018-07-12 13:26:32 +02:00
}
2018-08-27 15:47:34 +02:00
/* Extract file name and line */
ph7_value_int ( pValue , pTrace - > nLine ) ;
ph7_array_add_strkey_elem ( pSubArray , " line " , pValue ) ;
ph7_value_string ( pValue , pTrace - > pFile - > zString , pTrace - > pFile - > nByte ) ;
ph7_array_add_strkey_elem ( pSubArray , " file " , pValue ) ;
ph7_value_reset_string_cursor ( pValue ) ;
/* Extract called closure/method name */
ph7_value_string ( pValue , pTrace - > pFuncName - > zString , ( int ) pTrace - > pFuncName - > nByte ) ;
ph7_array_add_strkey_elem ( pSubArray , " function " , pValue ) ;
ph7_value_reset_string_cursor ( pValue ) ;
/* Extract closure/method arguments */
aSlot = ( VmSlot * ) SySetBasePtr ( pTrace - > pArg ) ;
for ( int n = 0 ; n < SySetUsed ( pTrace - > pArg ) ; n + + ) {
ph7_value * pObj = ( ph7_value * ) SySetAt ( & pCtx - > pVm - > aMemObj , aSlot [ n ] . nIdx ) ;
if ( pObj ) {
ph7_array_add_elem ( pArg , 0 , pObj ) ;
2018-07-22 20:23:50 +02:00
}
}
2018-08-27 15:47:34 +02:00
ph7_array_add_strkey_elem ( pSubArray , " args " , pArg ) ;
if ( pTrace - > pClassName ) {
/* Extract class name */
ph7_value_string ( pValue , pTrace - > pClassName - > zString , ( int ) pTrace - > pClassName - > nByte ) ;
ph7_array_add_strkey_elem ( pSubArray , " class " , pValue ) ;
2018-07-22 20:24:00 +02:00
ph7_value_reset_string_cursor ( pValue ) ;
}
2018-08-27 15:47:34 +02:00
/* Install debug frame in an array */
ph7_array_add_elem ( pArray , 0 , pSubArray ) ;
2018-07-12 13:26:32 +02:00
}
/* Return the freshly created array */
2018-07-12 17:24:46 +02:00
ph7_result_value ( pCtx , pArray ) ;
2018-07-12 13:26:32 +02:00
/*
* Don ' t worry about freeing memory , everything will be released automatically
* as soon we return from this function .
*/
return PH7_OK ;
}
/*
* The following routine is invoked by the engine when an uncaught
* exception is triggered .
*/
static sxi32 VmUncaughtException (
ph7_vm * pVm , /* Target VM */
ph7_class_instance * pThis /* Exception class instance [i.e: Exception $e] */
2018-07-12 17:24:46 +02:00
) {
ph7_value * apArg [ 2 ] , sArg ;
2018-07-12 13:26:32 +02:00
int nArg = 1 ;
sxi32 rc ;
2018-07-12 17:24:46 +02:00
if ( pVm - > nExceptDepth > 15 ) {
2018-07-12 13:26:32 +02:00
/* Nesting limit reached */
return SXRET_OK ;
}
/* Call any exception handler if available */
2018-07-12 17:24:46 +02:00
PH7_MemObjInit ( pVm , & sArg ) ;
if ( pThis ) {
2018-07-12 13:26:32 +02:00
/* Load the exception instance */
sArg . x . pOther = pThis ;
pThis - > iRef + + ;
2018-07-12 17:24:46 +02:00
MemObjSetType ( & sArg , MEMOBJ_OBJ ) ;
} else {
2018-07-12 13:26:32 +02:00
nArg = 0 ;
}
apArg [ 0 ] = & sArg ;
/* Call the exception handler if available */
pVm - > nExceptDepth + + ;
2018-07-12 17:24:46 +02:00
rc = PH7_VmCallUserFunction ( & ( * pVm ) , & pVm - > aExceptionCB [ 1 ] , 1 , apArg , 0 ) ;
2018-07-12 13:26:32 +02:00
pVm - > nExceptDepth - - ;
2018-07-12 17:24:46 +02:00
if ( rc ! = SXRET_OK ) {
SyString sName = { " Exception " , sizeof ( " Exception " ) - 1 } ;
SyString sFuncName = { " Global " , sizeof ( " Global " ) - 1 } ;
2018-07-12 13:26:32 +02:00
VmFrame * pFrame = pVm - > pFrame ;
2018-07-12 17:24:46 +02:00
/* No available handler,generate a fatal error */
if ( pThis ) {
SyStringDupPtr ( & sName , & pThis - > pClass - > sName ) ;
2018-07-12 13:26:32 +02:00
}
2018-07-12 17:24:46 +02:00
while ( pFrame - > pParent & & ( pFrame - > iFlags & VM_FRAME_EXCEPTION ) ) {
2018-07-12 13:26:32 +02:00
/* Ignore exception frames */
pFrame = pFrame - > pParent ;
}
2018-07-12 17:24:46 +02:00
if ( pFrame - > pParent ) {
if ( pFrame - > iFlags & VM_FRAME_CATCH ) {
SyStringInitFromBuf ( & sFuncName , " Catch_block " , sizeof ( " Catch_block " ) - 1 ) ;
} else {
2018-07-12 13:26:32 +02:00
ph7_vm_func * pFunc = ( ph7_vm_func * ) pFrame - > pUserData ;
2018-07-12 17:24:46 +02:00
if ( pFunc ) {
SyStringDupPtr ( & sFuncName , & pFunc - > sName ) ;
2018-07-12 13:26:32 +02:00
}
}
}
/* Generate a listing */
2018-09-04 08:54:48 +02:00
PH7_VmThrowError ( & ( * pVm ) , PH7_CTX_ERR ,
2018-09-03 16:29:50 +02:00
" Uncaught exception '%z' in the '%z()' function/method " ,
2018-07-12 17:24:46 +02:00
& sName , & sFuncName ) ;
2018-07-12 13:26:32 +02:00
}
PH7_MemObjRelease ( & sArg ) ;
return rc ;
}
/*
* Throw an user exception .
*/
static sxi32 VmThrowException (
ph7_vm * pVm , /* Target VM */
ph7_class_instance * pThis /* Exception class instance [i.e: Exception $e] */
2018-07-12 17:24:46 +02:00
) {
2018-07-12 13:26:32 +02:00
ph7_exception_block * pCatch ; /* Catch block to execute */
ph7_exception * * apException ;
ph7_exception * pException ;
/* Point to the stack of loaded exceptions */
apException = ( ph7_exception * * ) SySetBasePtr ( & pVm - > aException ) ;
pException = 0 ;
pCatch = 0 ;
2018-07-12 17:24:46 +02:00
if ( SySetUsed ( & pVm - > aException ) > 0 ) {
2018-07-12 13:26:32 +02:00
ph7_exception_block * aCatch ;
ph7_class * pClass ;
sxu32 j ;
/* Locate the appropriate block to execute */
pException = apException [ SySetUsed ( & pVm - > aException ) - 1 ] ;
( void ) SySetPop ( & pVm - > aException ) ;
aCatch = ( ph7_exception_block * ) SySetBasePtr ( & pException - > sEntry ) ;
2018-07-12 17:24:46 +02:00
for ( j = 0 ; j < SySetUsed ( & pException - > sEntry ) ; + + j ) {
2018-07-12 13:26:32 +02:00
SyString * pName = & aCatch [ j ] . sClass ;
/* Extract the target class */
2018-07-12 17:24:46 +02:00
pClass = PH7_VmExtractClass ( & ( * pVm ) , pName - > zString , pName - > nByte , TRUE , 0 ) ;
if ( pClass = = 0 ) {
2018-07-12 13:26:32 +02:00
/* No such class */
continue ;
}
2018-07-12 17:24:46 +02:00
if ( VmInstanceOf ( pThis - > pClass , pClass ) ) {
2018-07-23 17:10:48 +02:00
/* Catch block found,break immediately */
2018-07-12 13:26:32 +02:00
pCatch = & aCatch [ j ] ;
break ;
}
2018-07-12 17:24:46 +02:00
}
2018-07-12 13:26:32 +02:00
}
/* Execute the cached block if available */
2018-07-12 17:24:46 +02:00
if ( pCatch = = 0 ) {
2018-07-12 13:26:32 +02:00
sxi32 rc ;
2018-07-12 17:24:46 +02:00
rc = VmUncaughtException ( & ( * pVm ) , pThis ) ;
if ( rc = = SXRET_OK & & pException ) {
2018-07-12 13:26:32 +02:00
VmFrame * pFrame = pVm - > pFrame ;
2018-07-12 17:24:46 +02:00
while ( pFrame - > pParent & & ( pFrame - > iFlags & VM_FRAME_EXCEPTION ) ) {
2018-07-12 13:26:32 +02:00
/* Safely ignore the exception frame */
pFrame = pFrame - > pParent ;
}
2018-07-12 17:24:46 +02:00
if ( pException - > pFrame = = pFrame ) {
2018-07-12 13:26:32 +02:00
/* Tell the upper layer that the exception was caught */
pFrame - > iFlags & = ~ VM_FRAME_THROW ;
}
}
return rc ;
2018-07-12 17:24:46 +02:00
} else {
2018-07-12 13:26:32 +02:00
VmFrame * pFrame = pVm - > pFrame ;
sxi32 rc ;
2018-07-12 17:24:46 +02:00
while ( pFrame - > pParent & & ( pFrame - > iFlags & VM_FRAME_EXCEPTION ) ) {
2018-07-12 13:26:32 +02:00
/* Safely ignore the exception frame */
pFrame = pFrame - > pParent ;
}
2018-07-12 17:24:46 +02:00
if ( pException - > pFrame = = pFrame ) {
2018-07-12 13:26:32 +02:00
/* Tell the upper layer that the exception was caught */
pFrame - > iFlags & = ~ VM_FRAME_THROW ;
}
/* Create a private frame first */
2018-07-12 17:24:46 +02:00
rc = VmEnterFrame ( & ( * pVm ) , 0 , 0 , & pFrame ) ;
if ( rc = = SXRET_OK ) {
2018-07-12 13:26:32 +02:00
/* Mark as catch frame */
2019-05-01 18:29:57 +02:00
ph7_value * pObj = VmCreateMemObj ( & ( * pVm ) , & pCatch - > sThis , FALSE ) ;
2018-07-12 13:26:32 +02:00
pFrame - > iFlags | = VM_FRAME_CATCH ;
2018-07-12 17:24:46 +02:00
if ( pObj ) {
2018-07-12 13:26:32 +02:00
/* Install the exception instance */
pThis - > iRef + + ; /* Increment reference count */
pObj - > x . pOther = pThis ;
2018-07-12 17:24:46 +02:00
MemObjSetType ( pObj , MEMOBJ_OBJ ) ;
2018-07-12 13:26:32 +02:00
}
2018-07-23 17:10:48 +02:00
/* Execute the block */
2018-07-12 17:24:46 +02:00
VmLocalExec ( & ( * pVm ) , & pCatch - > sByteCode , 0 ) ;
2018-07-12 13:26:32 +02:00
/* Leave the frame */
VmLeaveFrame ( & ( * pVm ) ) ;
2018-07-12 17:24:46 +02:00
}
2018-07-12 13:26:32 +02:00
}
/* TICKET 1433-60: Do not release the 'pException' pointer since it may
* be used again if a ' goto ' statement is executed .
*/
return SXRET_OK ;
}
/*
* Section :
* Version , Credits and Copyright related functions .
* Authors :
* Symisc Systems , devel @ symisc . net .
2019-05-15 20:02:39 +02:00
* Copyright ( C ) Symisc Systems , https : //ph7.symisc.net
2018-07-12 13:26:32 +02:00
* Status :
* Stable .
*/
/*
* string ph7version ( void )
* Returns the running version of the PH7 version .
* Parameters
* None
* Return
* Current PH7 version .
*/
2018-07-12 17:24:46 +02:00
static int vm_builtin_ph7_version ( ph7_context * pCtx , int nArg , ph7_value * * apArg ) {
2018-07-12 13:26:32 +02:00
SXUNUSED ( nArg ) ;
SXUNUSED ( apArg ) ; /* cc warning */
/* Current engine version */
2018-07-12 17:24:46 +02:00
ph7_result_string ( pCtx , PH7_VERSION , sizeof ( PH7_VERSION ) - 1 ) ;
2018-07-12 13:26:32 +02:00
return PH7_OK ;
}
/*
* PH7 release information HTML page used by the ph7info ( ) and ph7credits ( ) functions .
*/
2019-05-15 20:02:39 +02:00
# define PH7_HTML_PAGE_HEADER "<!DOCTYPE html PUBLIC \"- //W3C//DTD HTML 4.01//EN\" \"https://www.w3.org/TR/html4/strict.dtd\">"\
2018-07-12 17:24:46 +02:00
" <html><head> " \
2019-05-15 20:02:39 +02:00
" <!-- Copyright (C) 2011-2012 Symisc Systems,https://www.symisc.net contact@symisc.net --> " \
2018-07-12 17:24:46 +02:00
" <meta content= \" text/html; charset=UTF-8 \" http-equiv= \" content-type \" ><title>PH7 engine credits</title> " \
" <style type= \" text/css \" > " \
" div { " \
" border: 1px solid #cccccc; " \
" -moz-border-radius-topleft: 10px; " \
" -moz-border-radius-bottomright: 10px; " \
" -moz-border-radius-bottomleft: 10px; " \
" -moz-border-radius-topright: 10px; " \
" -webkit-border-radius: 10px; " \
" -o-border-radius: 10px; " \
" border-radius: 10px; " \
" padding-left: 2em; " \
" background-color: white; " \
" margin-left: auto; " \
" font-family: verdana; " \
" padding-right: 2em; " \
" margin-right: auto; " \
" } " \
" body { " \
" padding: 0.2em; " \
" font-style: normal; " \
" font-size: medium; " \
" background-color: #f2f2f2; " \
" } " \
" hr { " \
" border-style: solid none none; " \
" border-width: 1px medium medium; " \
" border-top: 1px solid #cccccc; " \
" height: 1px; " \
" } " \
" a { " \
" color: #3366cc; " \
" text-decoration: none; " \
" } " \
" a:hover { " \
" color: #999999; " \
" } " \
" a:active { " \
" color: #663399; " \
" } " \
" h1 { " \
" margin: 0; " \
" padding: 0; " \
" font-family: Verdana; " \
" font-weight: bold; " \
" font-style: normal; " \
" font-size: medium; " \
" text-transform: capitalize; " \
" color: #0a328c; " \
" } " \
" p { " \
" margin: 0 auto; " \
" font-size: medium; " \
" font-style: normal; " \
" font-family: verdana; " \
" } " \
" </style></head><body> " \
" <div style= \" background-color: white; width: 699px; \" > " \
" <h1 style= \" font-family: Verdana; text-align: right; \" ><small><small>PH7 Engine Credits</small></small></h1> " \
" <hr style= \" margin-left: auto; margin-right: auto; \" > " \
2019-05-15 20:02:39 +02:00
" <p><small><a href= \" https://ph7.symisc.net/ \" ><small><span style= \" font-weight: bold; \" > " \
2018-07-12 17:24:46 +02:00
" Symisc PH7</span></small></a><small> </small></small></p> " \
" <p style= \" text-align: left; \" ><small><small> " \
" A highly efficient embeddable bytecode compiler and a Virtual Machine for the PHP(5) Programming Language.</small></small></p> " \
" <p style= \" text-align: left; \" ><small><small>Copyright (C) Symisc Systems.<br></small></small></p> " \
" <p style= \" text-align: left; font-weight: bold; \" ><small><small>Engine Version:</small></small></p> " \
" <p style= \" text-align: left; font-weight: bold; margin-left: 40px; \" > "
2018-07-12 13:26:32 +02:00
# define PH7_HTML_PAGE_FORMAT "<small><small><span style=\"font-weight: normal;\">%s< / span>< / small>< / small>< / p>"\
2018-07-12 17:24:46 +02:00
" <p style= \" text-align: left; font-weight: bold; \" ><small><small>Engine ID:</small></small></p> " \
2018-08-15 20:03:39 +02:00
" <p style= \" text-align: left; font-weight: bold; margin-left: 40px; \" ><small><small><span style= \" font-weight: normal; \" >%s</span></small></small></p> " \
2018-07-12 17:24:46 +02:00
" <p style= \" text-align: left; font-weight: bold; \" ><small><small>Underlying VFS:</small></small></p> " \
" <p style= \" text-align: left; font-weight: bold; margin-left: 40px; \" ><small><small><span style= \" font-weight: normal; \" >%s</span></small></small></p> " \
" <p style= \" text-align: left; font-weight: bold; \" ><small><small>Total Built-in Functions:</small></small></p> " \
" <p style= \" text-align: left; font-weight: bold; margin-left: 40px; \" ><small><small><span style= \" font-weight: normal; \" >%d</span></small></small></p> " \
" <p style= \" text-align: left; font-weight: bold; \" ><small><small>Total Built-in Classes:</small></small></p> " \
" <p style= \" text-align: left; font-weight: bold; margin-left: 40px; \" ><small><small><span style= \" font-weight: normal; \" >%d</span></small></small></p> " \
" <p style= \" text-align: left; font-weight: bold; \" ><small><small>Host Operating System:</small></small></p> " \
" <p style= \" text-align: left; font-weight: bold; margin-left: 40px; \" ><small><small><span style= \" font-weight: normal; \" >%s</span></small></small></p> " \
" <p style= \" text-align: left; font-weight: bold; \" ><small style= \" font-weight: bold; \" ><small><small></small></small></small></p> " \
2019-05-15 20:02:39 +02:00
" <p style= \" text-align: left; font-weight: bold; \" ><small><small>Licensed To: <Public Release Under The <a href= \" https://www.symisc.net/spl.txt \" > " \
2018-07-12 17:24:46 +02:00
" Symisc Public License (SPL)</a>></small></small></p> "
2018-07-12 13:26:32 +02:00
# define PH7_HTML_PAGE_FOOTER "<p style=\"text-align: left; font-weight: bold; margin-left: 40px;\"><small><small><span style=\"font-weight: normal;\"> / *<br>"\
2018-07-12 17:24:46 +02:00
" * Copyright (C) 2011, 2012 Symisc Systems. All rights reserved.<br> " \
" *<br> " \
" * Redistribution and use in source and binary forms, with or without<br> " \
" * modification, are permitted provided that the following conditions<br> " \
" * are met:<br> " \
" * 1. Redistributions of source code must retain the above copyright<br> " \
" * notice, this list of conditions and the following disclaimer.<br> " \
" * 2. Redistributions in binary form must reproduce the above copyright<br> " \
" * notice, this list of conditions and the following disclaimer in the<br> " \
" * documentation and/or other materials provided with the distribution.<br> " \
" * 3. Redistributions in any form must be accompanied by information on<br> " \
" * how to obtain complete source code for the PH7 engine and any <br> " \
" * accompanying software that uses the PH7 engine software.<br> " \
" * The source code must either be included in the distribution<br> " \
" * or be available for no more than the cost of distribution plus<br> " \
" * a nominal fee, and must be freely redistributable under reasonable<br> " \
" * conditions. For an executable file, complete source code means<br> " \
" * the source code for all modules it contains.It does not include<br> " \
" * source code for modules or files that typically accompany the major<br> " \
" * components of the operating system on which the executable file runs.<br> " \
" *<br> " \
" * THIS SOFTWARE IS PROVIDED BY SYMISC SYSTEMS ``AS IS'' AND ANY EXPRESS<br> " \
" * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED<br> " \
" * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR<br> " \
" * NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL SYMISC SYSTEMS<br> " \
" * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR<br> " \
" * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF<br> " \
" * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR<br> " \
" * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,<br> " \
" * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE<br> " \
" * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN<br> " \
" * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.<br> " \
" */<br> " \
" </span></small></small></p> " \
2019-05-15 20:02:39 +02:00
" <p style= \" text-align: right; \" ><small><small>Copyright (C) <a href= \" https://www.symisc.net/ \" >Symisc Systems</a></small></small><big> " \
2018-07-12 17:24:46 +02:00
" </big></p></div></body></html> "
2018-07-12 13:26:32 +02:00
/*
* bool ph7credits ( void )
* bool ph7info ( void )
* bool ph7copyright ( void )
* Prints out the credits for PH7 engine
* Parameters
* None
* Return
* Always TRUE
*/
2018-07-12 17:24:46 +02:00
static int vm_builtin_ph7_credits ( ph7_context * pCtx , int nArg , ph7_value * * apArg ) {
2018-07-12 13:26:32 +02:00
ph7_vm * pVm = pCtx - > pVm ; /* Point to the underlying VM */
/* Expand the HTML page above*/
2018-07-12 17:24:46 +02:00
ph7_context_output ( pCtx , PH7_HTML_PAGE_HEADER , ( int ) sizeof ( PH7_HTML_PAGE_HEADER ) - 1 ) ;
2018-07-12 13:26:32 +02:00
ph7_context_output_format (
pCtx ,
PH7_HTML_PAGE_FORMAT ,
ph7_lib_version ( ) , /* Engine version */
ph7_lib_signature ( ) , /* Engine signature */
pVm - > pEngine - > pVfs ? pVm - > pEngine - > pVfs - > zName : " null_vfs " ,
SyHashTotalEntry ( & pVm - > hFunction ) + SyHashTotalEntry ( & pVm - > hHostFunction ) , /* # built-in functions */
SyHashTotalEntry ( & pVm - > hClass ) ,
# ifdef __WINNT__
" Windows NT "
# elif defined(__UNIXES__)
" UNIX-Like "
# else
" Other OS "
# endif
2018-07-12 17:24:46 +02:00
) ;
ph7_context_output ( pCtx , PH7_HTML_PAGE_FOOTER , ( int ) sizeof ( PH7_HTML_PAGE_FOOTER ) - 1 ) ;
2018-07-12 13:26:32 +02:00
SXUNUSED ( nArg ) ; /* cc warning */
SXUNUSED ( apArg ) ;
/* Return TRUE */
//ph7_result_bool(pCtx,1);
return PH7_OK ;
}
/*
* Section :
* URL related routines .
* Authors :
* Symisc Systems , devel @ symisc . net .
2019-05-15 20:02:39 +02:00
* Copyright ( C ) Symisc Systems , https : //ph7.symisc.net
2018-07-12 13:26:32 +02:00
* Status :
* Stable .
*/
/* Forward declaration */
2018-07-12 17:24:46 +02:00
static sxi32 VmHttpSplitURI ( SyhttpUri * pOut , const char * zUri , sxu32 nLen ) ;
2018-07-12 13:26:32 +02:00
/*
* value parse_url ( string $ url [ , int $ component = - 1 ] )
* Parse a URL and return its fields .
* Parameters
* $ url
* The URL to parse .
* $ component
* Specify one of PHP_URL_SCHEME , PHP_URL_HOST , PHP_URL_PORT , PHP_URL_USER
* PHP_URL_PASS , PHP_URL_PATH , PHP_URL_QUERY or PHP_URL_FRAGMENT to retrieve
* just a specific URL component as a string ( except when PHP_URL_PORT is given
* in which case the return value will be an integer ) .
* Return
* If the component parameter is omitted , an associative array is returned .
* At least one element will be present within the array . Potential keys within
* this array are :
* scheme - e . g . http
* host
* port
* user
* pass
* path
* query - after the question mark ?
* fragment - after the hashmark #
* Note :
* FALSE is returned on failure .
* This function work with relative URL unlike the one shipped
* with the standard PHP engine .
*/
2018-07-12 17:24:46 +02:00
static int vm_builtin_parse_url ( ph7_context * pCtx , int nArg , ph7_value * * apArg ) {
2018-07-12 13:26:32 +02:00
const char * zStr ; /* Input string */
SyString * pComp ; /* Pointer to the URI component */
SyhttpUri sURI ; /* Parse of the given URI */
int nLen ;
sxi32 rc ;
2018-07-12 17:24:46 +02:00
if ( nArg < 1 | | ! ph7_value_is_string ( apArg [ 0 ] ) ) {
2018-07-12 13:26:32 +02:00
/* Missing/Invalid arguments,return FALSE */
2018-07-12 17:24:46 +02:00
ph7_result_bool ( pCtx , 0 ) ;
2018-07-12 13:26:32 +02:00
return PH7_OK ;
}
/* Extract the given URI */
2018-07-12 17:24:46 +02:00
zStr = ph7_value_to_string ( apArg [ 0 ] , & nLen ) ;
if ( nLen < 1 ) {
2018-07-12 13:26:32 +02:00
/* Nothing to process,return FALSE */
2018-07-12 17:24:46 +02:00
ph7_result_bool ( pCtx , 0 ) ;
2018-07-12 13:26:32 +02:00
return PH7_OK ;
}
/* Get a parse */
2018-07-12 17:24:46 +02:00
rc = VmHttpSplitURI ( & sURI , zStr , ( sxu32 ) nLen ) ;
if ( rc ! = SXRET_OK ) {
2018-07-12 13:26:32 +02:00
/* Malformed input,return FALSE */
2018-07-12 17:24:46 +02:00
ph7_result_bool ( pCtx , 0 ) ;
2018-07-12 13:26:32 +02:00
return PH7_OK ;
}
2018-07-12 17:24:46 +02:00
if ( nArg > 1 ) {
2018-07-12 13:26:32 +02:00
int nComponent = ph7_value_to_int ( apArg [ 1 ] ) ;
/* Refer to constant.c for constants values */
2018-07-12 17:24:46 +02:00
switch ( nComponent ) {
case 1 : /* PHP_URL_SCHEME */
pComp = & sURI . sScheme ;
if ( pComp - > nByte < 1 ) {
/* No available value,return NULL */
ph7_result_null ( pCtx ) ;
} else {
ph7_result_string ( pCtx , pComp - > zString , ( int ) pComp - > nByte ) ;
}
break ;
case 2 : /* PHP_URL_HOST */
pComp = & sURI . sHost ;
if ( pComp - > nByte < 1 ) {
/* No available value,return NULL */
ph7_result_null ( pCtx ) ;
} else {
ph7_result_string ( pCtx , pComp - > zString , ( int ) pComp - > nByte ) ;
}
break ;
case 3 : /* PHP_URL_PORT */
pComp = & sURI . sPort ;
if ( pComp - > nByte < 1 ) {
/* No available value,return NULL */
ph7_result_null ( pCtx ) ;
} else {
int iPort = 0 ;
/* Cast the value to integer */
SyStrToInt32 ( pComp - > zString , pComp - > nByte , ( void * ) & iPort , 0 ) ;
ph7_result_int ( pCtx , iPort ) ;
}
break ;
case 4 : /* PHP_URL_USER */
pComp = & sURI . sUser ;
if ( pComp - > nByte < 1 ) {
/* No available value,return NULL */
ph7_result_null ( pCtx ) ;
} else {
ph7_result_string ( pCtx , pComp - > zString , ( int ) pComp - > nByte ) ;
}
break ;
case 5 : /* PHP_URL_PASS */
pComp = & sURI . sPass ;
if ( pComp - > nByte < 1 ) {
/* No available value,return NULL */
ph7_result_null ( pCtx ) ;
} else {
ph7_result_string ( pCtx , pComp - > zString , ( int ) pComp - > nByte ) ;
}
break ;
case 7 : /* PHP_URL_QUERY */
pComp = & sURI . sQuery ;
if ( pComp - > nByte < 1 ) {
/* No available value,return NULL */
ph7_result_null ( pCtx ) ;
} else {
ph7_result_string ( pCtx , pComp - > zString , ( int ) pComp - > nByte ) ;
}
break ;
case 8 : /* PHP_URL_FRAGMENT */
pComp = & sURI . sFragment ;
if ( pComp - > nByte < 1 ) {
/* No available value,return NULL */
ph7_result_null ( pCtx ) ;
} else {
ph7_result_string ( pCtx , pComp - > zString , ( int ) pComp - > nByte ) ;
}
break ;
case 6 : /* PHP_URL_PATH */
pComp = & sURI . sPath ;
if ( pComp - > nByte < 1 ) {
/* No available value,return NULL */
ph7_result_null ( pCtx ) ;
} else {
ph7_result_string ( pCtx , pComp - > zString , ( int ) pComp - > nByte ) ;
}
break ;
default :
/* No such entry,return NULL */
2018-07-12 13:26:32 +02:00
ph7_result_null ( pCtx ) ;
2018-07-12 17:24:46 +02:00
break ;
2018-07-12 13:26:32 +02:00
}
2018-07-12 17:24:46 +02:00
} else {
ph7_value * pArray , * pValue ;
2018-07-12 13:26:32 +02:00
/* Return an associative array */
pArray = ph7_context_new_array ( pCtx ) ; /* Empty array */
pValue = ph7_context_new_scalar ( pCtx ) ; /* Array value */
2018-07-12 17:24:46 +02:00
if ( pArray = = 0 | | pValue = = 0 ) {
2018-07-12 13:26:32 +02:00
/* Out of memory */
2018-09-04 08:26:58 +02:00
PH7_VmMemoryError ( pCtx - > pVm ) ;
2018-07-12 13:26:32 +02:00
}
/* Fill the array */
pComp = & sURI . sScheme ;
2018-07-12 17:24:46 +02:00
if ( pComp - > nByte > 0 ) {
ph7_value_string ( pValue , pComp - > zString , ( int ) pComp - > nByte ) ;
ph7_array_add_strkey_elem ( pArray , " scheme " , pValue ) ; /* Will make it's own copy */
2018-07-12 13:26:32 +02:00
}
/* Reset the string cursor */
ph7_value_reset_string_cursor ( pValue ) ;
pComp = & sURI . sHost ;
2018-07-12 17:24:46 +02:00
if ( pComp - > nByte > 0 ) {
ph7_value_string ( pValue , pComp - > zString , ( int ) pComp - > nByte ) ;
ph7_array_add_strkey_elem ( pArray , " host " , pValue ) ; /* Will make it's own copy */
2018-07-12 13:26:32 +02:00
}
/* Reset the string cursor */
ph7_value_reset_string_cursor ( pValue ) ;
pComp = & sURI . sPort ;
2018-07-12 17:24:46 +02:00
if ( pComp - > nByte > 0 ) {
2018-07-12 13:26:32 +02:00
int iPort = 0 ; /* cc warning */
/* Convert to integer */
2018-07-12 17:24:46 +02:00
SyStrToInt32 ( pComp - > zString , pComp - > nByte , ( void * ) & iPort , 0 ) ;
ph7_value_int ( pValue , iPort ) ;
ph7_array_add_strkey_elem ( pArray , " port " , pValue ) ; /* Will make it's own copy */
2018-07-12 13:26:32 +02:00
}
/* Reset the string cursor */
ph7_value_reset_string_cursor ( pValue ) ;
pComp = & sURI . sUser ;
2018-07-12 17:24:46 +02:00
if ( pComp - > nByte > 0 ) {
ph7_value_string ( pValue , pComp - > zString , ( int ) pComp - > nByte ) ;
ph7_array_add_strkey_elem ( pArray , " user " , pValue ) ; /* Will make it's own copy */
2018-07-12 13:26:32 +02:00
}
/* Reset the string cursor */
ph7_value_reset_string_cursor ( pValue ) ;
pComp = & sURI . sPass ;
2018-07-12 17:24:46 +02:00
if ( pComp - > nByte > 0 ) {
ph7_value_string ( pValue , pComp - > zString , ( int ) pComp - > nByte ) ;
ph7_array_add_strkey_elem ( pArray , " pass " , pValue ) ; /* Will make it's own copy */
2018-07-12 13:26:32 +02:00
}
/* Reset the string cursor */
ph7_value_reset_string_cursor ( pValue ) ;
pComp = & sURI . sPath ;
2018-07-12 17:24:46 +02:00
if ( pComp - > nByte > 0 ) {
ph7_value_string ( pValue , pComp - > zString , ( int ) pComp - > nByte ) ;
ph7_array_add_strkey_elem ( pArray , " path " , pValue ) ; /* Will make it's own copy */
2018-07-12 13:26:32 +02:00
}
/* Reset the string cursor */
ph7_value_reset_string_cursor ( pValue ) ;
pComp = & sURI . sQuery ;
2018-07-12 17:24:46 +02:00
if ( pComp - > nByte > 0 ) {
ph7_value_string ( pValue , pComp - > zString , ( int ) pComp - > nByte ) ;
ph7_array_add_strkey_elem ( pArray , " query " , pValue ) ; /* Will make it's own copy */
2018-07-12 13:26:32 +02:00
}
/* Reset the string cursor */
ph7_value_reset_string_cursor ( pValue ) ;
pComp = & sURI . sFragment ;
2018-07-12 17:24:46 +02:00
if ( pComp - > nByte > 0 ) {
ph7_value_string ( pValue , pComp - > zString , ( int ) pComp - > nByte ) ;
ph7_array_add_strkey_elem ( pArray , " fragment " , pValue ) ; /* Will make it's own copy */
2018-07-12 13:26:32 +02:00
}
/* Return the created array */
2018-07-12 17:24:46 +02:00
ph7_result_value ( pCtx , pArray ) ;
2018-07-12 13:26:32 +02:00
/* NOTE:
* Don ' t worry about freeing ' pValue ' , everything will be released
* automatically as soon we return from this function .
*/
}
/* All done */
return PH7_OK ;
}
/*
* Section :
* Array related routines .
* Authors :
* Symisc Systems , devel @ symisc . net .
2019-05-15 20:02:39 +02:00
* Copyright ( C ) Symisc Systems , https : //ph7.symisc.net
2018-07-12 13:26:32 +02:00
* Status :
* Stable .
* Note 2012 - 5 - 21 01 : 04 : 15 :
* Array related functions that need access to the underlying
* virtual machine are implemented here rather than ' hashmap . c '
*/
/*
* The [ compact ( ) ] function store it ' s state information in an instance
* of the following structure .
*/
2018-07-12 17:24:46 +02:00
struct compact_data {
2018-07-12 13:26:32 +02:00
ph7_value * pArray ; /* Target array */
int nRecCount ; /* Recursion count */
} ;
/*
* Walker callback for the [ compact ( ) ] function defined below .
*/
2018-07-12 17:24:46 +02:00
static int VmCompactCallback ( ph7_value * pKey , ph7_value * pValue , void * pUserData ) {
2018-07-12 13:26:32 +02:00
struct compact_data * pData = ( struct compact_data * ) pUserData ;
ph7_value * pArray = ( ph7_value * ) pData - > pArray ;
ph7_vm * pVm = pArray - > pVm ;
/* Act according to the hashmap value */
2018-07-12 17:24:46 +02:00
if ( ph7_value_is_string ( pValue ) ) {
2018-07-12 13:26:32 +02:00
SyString sVar ;
2018-07-12 17:24:46 +02:00
SyStringInitFromBuf ( & sVar , SyBlobData ( & pValue - > sBlob ) , SyBlobLength ( & pValue - > sBlob ) ) ;
if ( sVar . nByte > 0 ) {
2018-07-12 13:26:32 +02:00
/* Query the current frame */
2019-05-01 18:29:57 +02:00
pKey = VmExtractMemObj ( pVm , & sVar , FALSE ) ;
2018-07-12 13:26:32 +02:00
/* ^
2018-07-12 17:24:46 +02:00
* | Avoid wasting variable and use ' pKey ' instead
2018-07-12 13:26:32 +02:00
*/
2018-07-12 17:24:46 +02:00
if ( pKey ) {
2018-07-12 13:26:32 +02:00
/* Perform the insertion */
2018-07-12 17:24:46 +02:00
ph7_array_add_elem ( pArray , pValue /* Variable name*/ , pKey /* Variable value */ ) ;
2018-07-12 13:26:32 +02:00
}
}
2018-07-12 17:24:46 +02:00
} else if ( ph7_value_is_array ( pValue ) & & pData - > nRecCount < 32 ) {
2018-07-12 13:26:32 +02:00
int rc ;
/* Recursively traverse this array */
pData - > nRecCount + + ;
2018-07-12 17:24:46 +02:00
rc = PH7_HashmapWalk ( ( ph7_hashmap * ) pValue - > x . pOther , VmCompactCallback , pUserData ) ;
2018-07-12 13:26:32 +02:00
pData - > nRecCount - - ;
return rc ;
}
return SXRET_OK ;
}
/*
* array compact ( mixed $ varname [ , mixed $ . . . ] )
* Create array containing variables and their values .
* For each of these , compact ( ) looks for a variable with that name
2018-07-12 17:24:46 +02:00
* in the current symbol table and adds it to the output array such
2018-07-12 13:26:32 +02:00
* that the variable name becomes the key and the contents of the variable
* become the value for that key . In short , it does the opposite of extract ( ) .
2018-07-12 17:24:46 +02:00
* Any strings that are not set will simply be skipped .
2018-07-12 13:26:32 +02:00
* Parameters
* $ varname
* compact ( ) takes a variable number of parameters . Each parameter can be either
* a string containing the name of the variable , or an array of variable names .
* The array can contain other arrays of variable names inside it ; compact ( ) handles
* it recursively .
* Return
* The output array with all the variables added to it or NULL on failure
*/
2018-07-12 17:24:46 +02:00
static int vm_builtin_compact ( ph7_context * pCtx , int nArg , ph7_value * * apArg ) {
ph7_value * pArray , * pObj ;
2018-07-12 13:26:32 +02:00
ph7_vm * pVm = pCtx - > pVm ;
const char * zName ;
SyString sVar ;
2018-07-12 17:24:46 +02:00
int i , nLen ;
if ( nArg < 1 ) {
2018-07-12 13:26:32 +02:00
/* Missing arguments,return NULL */
ph7_result_null ( pCtx ) ;
return PH7_OK ;
}
/* Create the array */
pArray = ph7_context_new_array ( pCtx ) ;
2018-07-12 17:24:46 +02:00
if ( pArray = = 0 ) {
2018-07-12 13:26:32 +02:00
/* Out of memory */
2018-09-04 08:26:58 +02:00
PH7_VmMemoryError ( pCtx - > pVm ) ;
2018-07-12 13:26:32 +02:00
}
/* Perform the requested operation */
2018-07-12 17:24:46 +02:00
for ( i = 0 ; i < nArg ; i + + ) {
if ( ! ph7_value_is_string ( apArg [ i ] ) ) {
if ( ph7_value_is_array ( apArg [ i ] ) ) {
2018-07-12 13:26:32 +02:00
struct compact_data sData ;
ph7_hashmap * pMap = ( ph7_hashmap * ) apArg [ i ] - > x . pOther ;
/* Recursively walk the array */
sData . nRecCount = 0 ;
sData . pArray = pArray ;
2018-07-12 17:24:46 +02:00
PH7_HashmapWalk ( pMap , VmCompactCallback , & sData ) ;
2018-07-12 13:26:32 +02:00
}
2018-07-12 17:24:46 +02:00
} else {
2018-07-12 13:26:32 +02:00
/* Extract variable name */
2018-07-12 17:24:46 +02:00
zName = ph7_value_to_string ( apArg [ i ] , & nLen ) ;
if ( nLen > 0 ) {
SyStringInitFromBuf ( & sVar , zName , nLen ) ;
2018-07-12 13:26:32 +02:00
/* Check if the variable is available in the current frame */
2019-05-01 18:29:57 +02:00
pObj = VmExtractMemObj ( pVm , & sVar , FALSE ) ;
2018-07-12 17:24:46 +02:00
if ( pObj ) {
ph7_array_add_elem ( pArray , apArg [ i ] /*Variable name*/ , pObj /* Variable value */ ) ;
2018-07-12 13:26:32 +02:00
}
}
}
}
/* Return the array */
2018-07-12 17:24:46 +02:00
ph7_result_value ( pCtx , pArray ) ;
2018-07-12 13:26:32 +02:00
return PH7_OK ;
}
/*
* The [ extract ( ) ] function store it ' s state information in an instance
* of the following structure .
*/
typedef struct extract_aux_data extract_aux_data ;
2018-07-12 17:24:46 +02:00
struct extract_aux_data {
2018-07-12 13:26:32 +02:00
ph7_vm * pVm ; /* VM that own this instance */
int iCount ; /* Number of variables successfully imported */
const char * zPrefix ; /* Prefix name */
int Prefixlen ; /* Prefix length */
int iFlags ; /* Control flags */
char zWorker [ 1024 ] ; /* Working buffer */
} ;
/* Forward declaration */
2018-07-12 17:24:46 +02:00
static int VmExtractCallback ( ph7_value * pKey , ph7_value * pValue , void * pUserData ) ;
2018-07-12 13:26:32 +02:00
/*
* int extract ( array & $ var_array [ , int $ extract_type = EXTR_OVERWRITE [ , string $ prefix = NULL ] ] )
* Import variables into the current symbol table from an array .
* Parameters
* $ var_array
* An associative array . This function treats keys as variable names and values
* as variable values . For each key / value pair it will create a variable in the current symbol
* table , subject to extract_type and prefix parameters .
* You must use an associative array ; a numerically indexed array will not produce results
* unless you use EXTR_PREFIX_ALL or EXTR_PREFIX_INVALID .
* $ extract_type
* The way invalid / numeric keys and collisions are treated is determined by the extract_type .
* It can be one of the following values :
* EXTR_OVERWRITE
2018-07-12 17:24:46 +02:00
* If there is a collision , overwrite the existing variable .
2018-07-12 13:26:32 +02:00
* EXTR_SKIP
2018-07-12 17:24:46 +02:00
* If there is a collision , don ' t overwrite the existing variable .
2018-07-12 13:26:32 +02:00
* EXTR_PREFIX_SAME
2018-07-12 17:24:46 +02:00
* If there is a collision , prefix the variable name with prefix .
2018-07-12 13:26:32 +02:00
* EXTR_PREFIX_ALL
2018-07-12 17:24:46 +02:00
* Prefix all variable names with prefix .
2018-07-12 13:26:32 +02:00
* EXTR_PREFIX_INVALID
2018-07-12 17:24:46 +02:00
* Only prefix invalid / numeric variable names with prefix .
2018-07-12 13:26:32 +02:00
* EXTR_IF_EXISTS
* Only overwrite the variable if it already exists in the current symbol table
* otherwise do nothing .
* This is useful for defining a list of valid variables and then extracting only those
2018-07-12 17:24:46 +02:00
* variables you have defined out of $ _REQUEST , for example .
2018-07-12 13:26:32 +02:00
* EXTR_PREFIX_IF_EXISTS
2018-07-12 17:24:46 +02:00
* Only create prefixed variable names if the non - prefixed version of the same variable exists in
2018-07-12 13:26:32 +02:00
* the current symbol table .
* $ prefix
* Note that prefix is only required if extract_type is EXTR_PREFIX_SAME , EXTR_PREFIX_ALL
* EXTR_PREFIX_INVALID or EXTR_PREFIX_IF_EXISTS . If the prefixed result is not a valid variable name
* it is not imported into the symbol table . Prefixes are automatically separated from the array key by an
* underscore character .
* Return
* Returns the number of variables successfully imported into the symbol table .
*/
2018-07-12 17:24:46 +02:00
static int vm_builtin_extract ( ph7_context * pCtx , int nArg , ph7_value * * apArg ) {
2018-07-12 13:26:32 +02:00
extract_aux_data sAux ;
ph7_hashmap * pMap ;
2018-07-12 17:24:46 +02:00
if ( nArg < 1 | | ! ph7_value_is_array ( apArg [ 0 ] ) ) {
2018-07-12 13:26:32 +02:00
/* Missing/Invalid arguments,return 0 */
2018-07-12 17:24:46 +02:00
ph7_result_int ( pCtx , 0 ) ;
2018-07-12 13:26:32 +02:00
return PH7_OK ;
}
/* Point to the target hashmap */
pMap = ( ph7_hashmap * ) apArg [ 0 ] - > x . pOther ;
2018-07-12 17:24:46 +02:00
if ( pMap - > nEntry < 1 ) {
2018-07-12 13:26:32 +02:00
/* Empty map,return 0 */
2018-07-12 17:24:46 +02:00
ph7_result_int ( pCtx , 0 ) ;
2018-07-12 13:26:32 +02:00
return PH7_OK ;
}
/* Prepare the aux data */
2018-07-12 17:24:46 +02:00
SyZero ( & sAux , sizeof ( extract_aux_data ) - sizeof ( sAux . zWorker ) ) ;
if ( nArg > 1 ) {
2018-07-12 13:26:32 +02:00
sAux . iFlags = ph7_value_to_int ( apArg [ 1 ] ) ;
2018-07-12 17:24:46 +02:00
if ( nArg > 2 ) {
sAux . zPrefix = ph7_value_to_string ( apArg [ 2 ] , & sAux . Prefixlen ) ;
2018-07-12 13:26:32 +02:00
}
}
sAux . pVm = pCtx - > pVm ;
/* Invoke the worker callback */
2018-07-12 17:24:46 +02:00
PH7_HashmapWalk ( pMap , VmExtractCallback , & sAux ) ;
2018-07-12 13:26:32 +02:00
/* Number of variables successfully imported */
2018-07-12 17:24:46 +02:00
ph7_result_int ( pCtx , sAux . iCount ) ;
2018-07-12 13:26:32 +02:00
return PH7_OK ;
}
/*
* Worker callback for the [ extract ( ) ] function defined
* below .
*/
2018-07-12 17:24:46 +02:00
static int VmExtractCallback ( ph7_value * pKey , ph7_value * pValue , void * pUserData ) {
2018-07-12 13:26:32 +02:00
extract_aux_data * pAux = ( extract_aux_data * ) pUserData ;
int iFlags = pAux - > iFlags ;
ph7_vm * pVm = pAux - > pVm ;
ph7_value * pObj ;
SyString sVar ;
2019-05-21 14:49:36 +02:00
if ( ( iFlags & 0x10 /* EXTR_PREFIX_INVALID */ ) & & ( pKey - > nType & ( MEMOBJ_INT | MEMOBJ_BOOL | MEMOBJ_REAL ) ) ) {
2018-07-12 13:26:32 +02:00
iFlags | = 0x08 ; /*EXTR_PREFIX_ALL*/
}
/* Perform a string cast */
PH7_MemObjToString ( pKey ) ;
2018-07-12 17:24:46 +02:00
if ( SyBlobLength ( & pKey - > sBlob ) < 1 ) {
2018-07-12 13:26:32 +02:00
/* Unavailable variable name */
return SXRET_OK ;
}
sVar . nByte = 0 ; /* cc warning */
2018-07-12 17:24:46 +02:00
if ( ( iFlags & 0x08 /*EXTR_PREFIX_ALL*/ ) & & pAux - > Prefixlen > 0 ) {
sVar . nByte = ( sxu32 ) SyBufferFormat ( pAux - > zWorker , sizeof ( pAux - > zWorker ) , " %.*s_%.*s " ,
pAux - > Prefixlen , pAux - > zPrefix ,
SyBlobLength ( & pKey - > sBlob ) , SyBlobData ( & pKey - > sBlob )
) ;
} else {
sVar . nByte = ( sxu32 ) SyMemcpy ( SyBlobData ( & pKey - > sBlob ) , pAux - > zWorker ,
SXMIN ( SyBlobLength ( & pKey - > sBlob ) , sizeof ( pAux - > zWorker ) ) ) ;
2018-07-12 13:26:32 +02:00
}
sVar . zString = pAux - > zWorker ;
/* Try to extract the variable */
2019-05-01 18:29:57 +02:00
pObj = VmExtractMemObj ( pVm , & sVar , TRUE ) ;
2018-07-12 17:24:46 +02:00
if ( pObj ) {
2018-07-12 13:26:32 +02:00
/* Collision */
2018-07-12 17:24:46 +02:00
if ( iFlags & 0x02 /* EXTR_SKIP */ ) {
2018-07-12 13:26:32 +02:00
return SXRET_OK ;
}
2018-07-12 17:24:46 +02:00
if ( iFlags & 0x04 /* EXTR_PREFIX_SAME */ ) {
if ( ( iFlags & 0x08 /*EXTR_PREFIX_ALL*/ ) | | pAux - > Prefixlen < 1 ) {
2018-07-12 13:26:32 +02:00
/* Already prefixed */
return SXRET_OK ;
}
2018-07-12 17:24:46 +02:00
sVar . nByte = ( sxu32 ) SyBufferFormat ( pAux - > zWorker , sizeof ( pAux - > zWorker ) , " %.*s_%.*s " ,
pAux - > Prefixlen , pAux - > zPrefix ,
SyBlobLength ( & pKey - > sBlob ) , SyBlobData ( & pKey - > sBlob )
) ;
2019-05-01 18:29:57 +02:00
pObj = VmExtractMemObj ( pVm , & sVar , TRUE ) ;
2018-07-12 13:26:32 +02:00
}
2018-07-12 17:24:46 +02:00
} else {
2018-07-12 13:26:32 +02:00
/* Create the variable */
2019-05-01 18:29:57 +02:00
pObj = VmCreateMemObj ( pVm , & sVar , TRUE ) ;
2018-07-12 13:26:32 +02:00
}
2018-07-12 17:24:46 +02:00
if ( pObj ) {
2018-07-12 13:26:32 +02:00
/* Overwrite the old value */
2018-07-12 17:24:46 +02:00
PH7_MemObjStore ( pValue , pObj ) ;
2018-07-12 13:26:32 +02:00
/* Increment counter */
pAux - > iCount + + ;
}
return SXRET_OK ;
}
/*
* Compile and evaluate a PHP chunk at run - time .
* Refer to the eval ( ) language construct implementation for more
* information .
*/
static sxi32 VmEvalChunk (
ph7_vm * pVm , /* Underlying Virtual Machine */
ph7_context * pCtx , /* Call Context */
2018-07-12 17:24:46 +02:00
SyString * pChunk , /* PHP chunk to evaluate */
2018-08-15 16:01:09 +02:00
int iFlags /* Compile flag */
2018-07-12 17:24:46 +02:00
) {
SySet * pByteCode , aByteCode ;
2018-07-12 13:26:32 +02:00
ProcConsumer xErr = 0 ;
void * pErrData = 0 ;
/* Initialize bytecode container */
2018-07-12 17:24:46 +02:00
SySetInit ( & aByteCode , & pVm - > sAllocator , sizeof ( VmInstr ) ) ;
SySetAlloc ( & aByteCode , 0x20 ) ;
2018-08-15 16:01:09 +02:00
/* Log compile-time errors */
xErr = pVm - > pEngine - > xConf . xErr ;
pErrData = pVm - > pEngine - > xConf . pErrData ;
2018-07-12 17:24:46 +02:00
PH7_ResetCodeGenerator ( pVm , xErr , pErrData ) ;
2018-07-12 13:26:32 +02:00
/* Swap bytecode container */
pByteCode = pVm - > pByteContainer ;
pVm - > pByteContainer = & aByteCode ;
2018-08-27 18:04:45 +02:00
/* Push memory as a processed file path */
if ( ( iFlags & PH7_AERSCRIPT_CODE ) = = 0 ) {
PH7_VmPushFilePath ( pVm , " [MEMORY] " , - 1 , TRUE , 0 ) ;
}
2018-07-12 13:26:32 +02:00
/* Compile the chunk */
2018-08-13 20:16:37 +02:00
PH7_CompileAerScript ( pVm , pChunk , iFlags ) ;
2019-04-24 23:22:06 +02:00
ph7_value sResult ; /* Return value */
SyHashEntry * pEntry ;
/* Initialize and install static and constants class attributes */
SyHashResetLoopCursor ( & pVm - > hClass ) ;
while ( ( pEntry = SyHashGetNextEntry ( & pVm - > hClass ) ) ! = 0 ) {
if ( VmMountUserClass ( & ( * pVm ) , ( ph7_class * ) pEntry - > pUserData ) ! = SXRET_OK ) {
2018-07-12 17:24:46 +02:00
if ( pCtx ) {
ph7_result_bool ( pCtx , 0 ) ;
2018-07-12 13:26:32 +02:00
}
goto Cleanup ;
}
2019-04-24 23:22:06 +02:00
}
if ( SXRET_OK ! = PH7_VmEmitInstr ( pVm , 0 , PH7_OP_DONE , 0 , 0 , 0 , 0 ) ) {
/* Out of memory */
2018-07-12 17:24:46 +02:00
if ( pCtx ) {
2019-04-24 23:22:06 +02:00
ph7_result_bool ( pCtx , 0 ) ;
2018-07-12 13:26:32 +02:00
}
2019-04-24 23:22:06 +02:00
goto Cleanup ;
2018-07-12 13:26:32 +02:00
}
2019-04-24 23:22:06 +02:00
/* Assume a boolean true return value */
PH7_MemObjInitFromBool ( pVm , & sResult , 1 ) ;
/* Execute the compiled chunk */
VmLocalExec ( pVm , & aByteCode , & sResult ) ;
if ( pCtx ) {
/* Set the execution result */
ph7_result_value ( pCtx , & sResult ) ;
}
PH7_MemObjRelease ( & sResult ) ;
2018-07-12 13:26:32 +02:00
Cleanup :
/* Cleanup the mess left behind */
pVm - > pByteContainer = pByteCode ;
SySetRelease ( & aByteCode ) ;
return SXRET_OK ;
}
/*
* value eval ( string $ code )
* Evaluate a string as PHP code .
* Parameter
* code : PHP code to evaluate .
* Return
2018-07-12 17:24:46 +02:00
* eval ( ) returns NULL unless return is called in the evaluated code , in which case
2018-07-12 13:26:32 +02:00
* the value passed to return is returned . If there is a parse error in the evaluated
* code , eval ( ) returns FALSE and execution of the following code continues normally .
*/
2018-07-12 17:24:46 +02:00
static int vm_builtin_eval ( ph7_context * pCtx , int nArg , ph7_value * * apArg ) {
2018-07-12 13:26:32 +02:00
SyString sChunk ; /* Chunk to evaluate */
2018-07-12 17:24:46 +02:00
if ( nArg < 1 ) {
2018-07-12 13:26:32 +02:00
/* Nothing to evaluate,return NULL */
ph7_result_null ( pCtx ) ;
return SXRET_OK ;
}
/* Chunk to evaluate */
2018-07-12 17:24:46 +02:00
sChunk . zString = ph7_value_to_string ( apArg [ 0 ] , ( int * ) & sChunk . nByte ) ;
if ( sChunk . nByte < 1 ) {
2018-07-12 13:26:32 +02:00
/* Empty string,return NULL */
ph7_result_null ( pCtx ) ;
return SXRET_OK ;
}
/* Eval the chunk */
2018-08-16 09:34:18 +02:00
VmEvalChunk ( pCtx - > pVm , & ( * pCtx ) , & sChunk , PH7_AERSCRIPT_CHNK ) ;
2018-07-12 13:26:32 +02:00
return SXRET_OK ;
}
/*
* Check if a file path is already included .
*/
2018-07-12 17:24:46 +02:00
static int VmIsIncludedFile ( ph7_vm * pVm , SyString * pFile ) {
2018-07-12 13:26:32 +02:00
SyString * aEntries ;
sxu32 n ;
aEntries = ( SyString * ) SySetBasePtr ( & pVm - > aIncluded ) ;
/* Perform a linear search */
2018-07-12 17:24:46 +02:00
for ( n = 0 ; n < SySetUsed ( & pVm - > aIncluded ) ; + + n ) {
if ( SyStringCmp ( pFile , & aEntries [ n ] , SyMemcmp ) = = 0 ) {
2018-07-12 13:26:32 +02:00
/* Already included */
return TRUE ;
}
}
return FALSE ;
}
/*
* Push a file path in the appropriate VM container .
*/
2018-07-23 19:39:21 +02:00
PH7_PRIVATE sxi32 PH7_VmPushFilePath ( ph7_vm * pVm , const char * zPath , int nLen , sxu8 bMain , sxi32 * pNew ) {
2018-07-12 13:26:32 +02:00
SyString sPath ;
char * zDup ;
# ifdef __WINNT__
char * zCur ;
# endif
sxi32 rc ;
2018-07-23 19:39:21 +02:00
if ( nLen < 0 ) {
nLen = SyStrlen ( zPath ) ;
2018-07-12 13:26:32 +02:00
}
/* Duplicate the file path first */
2018-07-23 19:39:21 +02:00
zDup = SyMemBackendStrDup ( & pVm - > sAllocator , zPath , nLen ) ;
2018-07-12 17:24:46 +02:00
if ( zDup = = 0 ) {
2018-07-12 13:26:32 +02:00
return SXERR_MEM ;
}
# ifdef __WINNT__
/* Normalize path on windows
* Example :
* Path / To / File . php
* becomes
* path \ to \ file . php
*/
zCur = zDup ;
2018-07-12 17:24:46 +02:00
while ( zCur [ 0 ] ! = 0 ) {
if ( zCur [ 0 ] = = ' / ' ) {
2018-07-12 13:26:32 +02:00
zCur [ 0 ] = ' \\ ' ;
2018-07-12 17:24:46 +02:00
} else if ( ( unsigned char ) zCur [ 0 ] < 0xc0 & & SyisUpper ( zCur [ 0 ] ) ) {
2018-07-12 13:26:32 +02:00
int c = SyToLower ( zCur [ 0 ] ) ;
zCur [ 0 ] = ( char ) c ; /* MSVC stupidity */
}
zCur + + ;
}
# endif
/* Install the file path */
2018-07-12 17:24:46 +02:00
SyStringInitFromBuf ( & sPath , zDup , nLen ) ;
if ( ! bMain ) {
if ( VmIsIncludedFile ( & ( * pVm ) , & sPath ) ) {
2018-07-12 13:26:32 +02:00
/* Already included */
* pNew = 0 ;
2018-07-12 17:24:46 +02:00
} else {
2018-07-12 13:26:32 +02:00
/* Insert in the corresponding container */
2018-07-12 17:24:46 +02:00
rc = SySetPut ( & pVm - > aIncluded , ( const void * ) & sPath ) ;
if ( rc ! = SXRET_OK ) {
SyMemBackendFree ( & pVm - > sAllocator , zDup ) ;
2018-07-12 13:26:32 +02:00
return rc ;
}
* pNew = 1 ;
}
}
2018-07-12 17:24:46 +02:00
SySetPut ( & pVm - > aFiles , ( const void * ) & sPath ) ;
2018-07-12 13:26:32 +02:00
return SXRET_OK ;
}
/*
* Compile and Execute a PHP script at run - time .
2018-07-23 17:10:48 +02:00
* SXRET_OK is returned on successfull evaluation . Any other return values
2018-07-12 13:26:32 +02:00
* indicates failure .
* Note that the PHP script to evaluate can be a local or remote file . In
* either cases the [ PH7_StreamReadWholeFile ( ) ] function handle all the underlying
* operations .
* Refer to the implementation of the include ( ) , include_once ( ) language
* constructs for more information .
*/
static sxi32 VmExecIncludedFile (
2018-07-12 17:24:46 +02:00
ph7_context * pCtx , /* Call Context */
SyString * pPath , /* Script path or URL*/
int IncludeOnce /* TRUE if called from include_once() or require_once() */
) {
2018-07-12 13:26:32 +02:00
sxi32 rc ;
const ph7_io_stream * pStream ;
SyBlob sContents ;
void * pHandle ;
ph7_vm * pVm ;
int isNew ;
/* Initialize fields */
pVm = pCtx - > pVm ;
2018-07-12 17:24:46 +02:00
SyBlobInit ( & sContents , & pVm - > sAllocator ) ;
2018-07-12 13:26:32 +02:00
isNew = 0 ;
/* Extract the associated stream */
2018-07-23 19:39:21 +02:00
pStream = PH7_VmGetStreamDevice ( pVm , & pPath - > zString , pPath - > nByte ) ;
2018-07-12 13:26:32 +02:00
/*
2019-05-15 20:02:39 +02:00
* Open the file or the URL [ i . e : https : //ph7.symisc.net/example/hello.php"]
2018-07-12 13:26:32 +02:00
* in a read - only mode .
*/
2018-07-23 19:39:21 +02:00
pHandle = PH7_StreamOpenHandle ( pVm , pStream , pPath - > zString , PH7_IO_OPEN_RDONLY , TRUE , 0 , TRUE , & isNew ) ;
2018-07-12 17:24:46 +02:00
if ( pHandle = = 0 ) {
2018-07-12 13:26:32 +02:00
return SXERR_IO ;
}
rc = SXRET_OK ; /* Stupid cc warning */
2018-07-12 17:24:46 +02:00
if ( IncludeOnce & & ! isNew ) {
2018-07-12 13:26:32 +02:00
/* Already included */
rc = SXERR_EXISTS ;
2018-07-12 17:24:46 +02:00
} else {
2018-07-12 13:26:32 +02:00
/* Read the whole file contents */
2018-07-12 17:24:46 +02:00
rc = PH7_StreamReadWholeFile ( pHandle , pStream , & sContents ) ;
if ( rc = = SXRET_OK ) {
2018-07-12 13:26:32 +02:00
SyString sScript ;
/* Compile and execute the script */
2018-07-12 17:24:46 +02:00
SyStringInitFromBuf ( & sScript , SyBlobData ( & sContents ) , SyBlobLength ( & sContents ) ) ;
2018-09-05 13:28:20 +02:00
pVm - > nMagic = PH7_VM_INCL ;
2018-08-15 16:01:09 +02:00
VmEvalChunk ( pCtx - > pVm , & ( * pCtx ) , & sScript , PH7_AERSCRIPT_CODE ) ;
2018-09-05 13:28:20 +02:00
pVm - > nMagic = PH7_VM_EXEC ;
2018-07-12 13:26:32 +02:00
}
}
/* Close the handle */
2018-07-12 17:24:46 +02:00
PH7_StreamCloseHandle ( pStream , pHandle ) ;
2018-07-12 13:26:32 +02:00
/* Release the working buffer */
SyBlobRelease ( & sContents ) ;
return rc ;
}
2018-07-18 22:01:04 +02:00
/*
* bool import ( string $ library )
2019-04-28 19:47:09 +02:00
* Loads an AerScript module library at runtime
2018-07-18 22:01:04 +02:00
* Parameters
* $ library
* This parameter is only the module library name that should be loaded .
* Return
* Returns TRUE on success or FALSE on failure
*/
static int vm_builtin_import ( ph7_context * pCtx , int nArg , ph7_value * * apArg ) {
const char * zStr ;
VmModule pModule , * pSearch ;
int nLen ;
if ( nArg ! = 1 | | ! ph7_value_is_string ( apArg [ 0 ] ) ) {
/* Missing/Invalid arguments, return FALSE */
ph7_result_bool ( pCtx , 0 ) ;
return PH7_OK ;
}
/* Extract the given module name */
zStr = ph7_value_to_string ( apArg [ 0 ] , & nLen ) ;
if ( nLen < 1 ) {
/* Nothing to process, return FALSE */
ph7_result_bool ( pCtx , 0 ) ;
return PH7_OK ;
}
while ( SySetGetNextEntry ( & pCtx - > pVm - > aModules , ( void * * ) & pSearch ) = = SXRET_OK ) {
2018-07-19 17:28:13 +02:00
if ( SyStrncmp ( pSearch - > sName . zString , zStr , ( sxu32 ) ( SXMAX ( pSearch - > sName . zString , zStr ) ) ) = = 0 ) {
2018-07-18 22:01:04 +02:00
SySetResetCursor ( & pCtx - > pVm - > aModules ) ;
ph7_result_bool ( pCtx , 1 ) ;
return PH7_OK ;
}
}
SySetResetCursor ( & pCtx - > pVm - > aModules ) ;
/* Zero the module entry */
SyZero ( & pModule , sizeof ( VmModule ) ) ;
SyStringInitFromBuf ( & pModule . sName , zStr , nLen ) ;
2018-07-19 16:51:33 +02:00
unsigned char bfile [ 255 ] = { 0 } ;
2018-07-19 13:43:10 +02:00
unsigned char * file ;
2018-08-10 08:47:42 +02:00
snprintf ( bfile , sizeof ( bfile ) - 1 , " ./binary/%s%s " , zStr , PH7_LIBRARY_SUFFIX ) ;
2018-07-19 16:51:33 +02:00
file = bfile ;
2018-07-18 22:01:04 +02:00
SyStringInitFromBuf ( & pModule . sFile , file , nLen ) ;
2018-07-19 17:22:36 +02:00
# ifdef __WINNT__
pModule . pHandle = LoadLibrary ( file ) ;
# else
2018-07-18 22:01:04 +02:00
pModule . pHandle = dlopen ( pModule . sFile . zString , RTLD_LAZY ) ;
2018-07-19 17:22:36 +02:00
# endif
2018-07-18 22:01:04 +02:00
if ( ! pModule . pHandle ) {
/* Could not load the module library file */
ph7_result_bool ( pCtx , 0 ) ;
return PH7_OK ;
}
2018-07-19 17:22:36 +02:00
# ifdef __WINNT__
void ( * init ) ( ph7_vm * , ph7_real * , SyString * ) = GetProcAddress ( pModule . pHandle , " initializeModule " ) ;
# else
2018-07-18 22:01:04 +02:00
void ( * init ) ( ph7_vm * , ph7_real * , SyString * ) = dlsym ( pModule . pHandle , " initializeModule " ) ;
2018-07-19 17:22:36 +02:00
# endif
if ( ! init ) {
2018-07-18 22:01:04 +02:00
/* Could not find the module entry point */
ph7_result_bool ( pCtx , 0 ) ;
return PH7_OK ;
}
/* Initialize the module */
init ( pCtx - > pVm , & pModule . fVer , & pModule . sDesc ) ;
/* Put information about module on top of the modules stack */
SySetPut ( & pCtx - > pVm - > aModules , ( const void * ) & pModule ) ;
ph7_result_bool ( pCtx , 1 ) ;
return PH7_OK ;
}
2018-07-12 13:26:32 +02:00
/*
* string get_include_path ( void )
* Gets the current include_path configuration option .
* Parameter
* None
* Return
* Included paths as a string
*/
2018-07-12 17:24:46 +02:00
static int vm_builtin_get_include_path ( ph7_context * pCtx , int nArg , ph7_value * * apArg ) {
2018-07-12 13:26:32 +02:00
ph7_vm * pVm = pCtx - > pVm ;
SyString * aEntry ;
int dir_sep ;
sxu32 n ;
# ifdef __WINNT__
dir_sep = ' ; ' ;
# else
/* Assume UNIX path separator */
dir_sep = ' : ' ;
# endif
SXUNUSED ( nArg ) ; /* cc warning */
2018-07-12 17:24:46 +02:00
SXUNUSED ( apArg ) ;
2018-07-12 13:26:32 +02:00
/* Point to the list of import paths */
aEntry = ( SyString * ) SySetBasePtr ( & pVm - > aPaths ) ;
2018-07-12 17:24:46 +02:00
for ( n = 0 ; n < SySetUsed ( & pVm - > aPaths ) ; n + + ) {
2018-07-12 13:26:32 +02:00
SyString * pEntry = & aEntry [ n ] ;
2018-07-12 17:24:46 +02:00
if ( n > 0 ) {
2018-07-23 17:10:48 +02:00
/* Append dir separator */
2018-07-12 17:24:46 +02:00
ph7_result_string ( pCtx , ( const char * ) & dir_sep , sizeof ( char ) ) ;
2018-07-12 13:26:32 +02:00
}
/* Append path */
2018-07-12 17:24:46 +02:00
ph7_result_string ( pCtx , pEntry - > zString , ( int ) pEntry - > nByte ) ;
2018-07-12 13:26:32 +02:00
}
return PH7_OK ;
}
/*
* string get_get_included_files ( void )
* Gets the current include_path configuration option .
* Parameter
* None
* Return
* Included paths as a string
*/
2018-07-12 17:24:46 +02:00
static int vm_builtin_get_included_files ( ph7_context * pCtx , int nArg , ph7_value * * apArg ) {
2018-08-18 20:42:54 +02:00
SySet * pFiles = & pCtx - > pVm - > aIncluded ;
2018-07-12 17:24:46 +02:00
ph7_value * pArray , * pWorker ;
2018-07-12 13:26:32 +02:00
SyString * pEntry ;
/* Create an array and a working value */
pArray = ph7_context_new_array ( pCtx ) ;
pWorker = ph7_context_new_scalar ( pCtx ) ;
2018-07-12 17:24:46 +02:00
if ( pArray = = 0 | | pWorker = = 0 ) {
2018-07-12 13:26:32 +02:00
/* Out of memory,return null */
ph7_result_null ( pCtx ) ;
SXUNUSED ( nArg ) ; /* cc warning */
2018-07-12 17:24:46 +02:00
SXUNUSED ( apArg ) ;
2018-07-12 13:26:32 +02:00
return PH7_OK ;
}
2018-08-18 21:05:46 +02:00
/* Iterate through entries */
2018-07-12 13:26:32 +02:00
SySetResetCursor ( pFiles ) ;
2018-07-12 17:24:46 +02:00
while ( SXRET_OK = = SySetGetNextEntry ( pFiles , ( void * * ) & pEntry ) ) {
2018-07-12 13:26:32 +02:00
/* reset the string cursor */
ph7_value_reset_string_cursor ( pWorker ) ;
/* Copy entry name */
2018-08-18 21:02:23 +02:00
ph7_value_string ( pWorker , pEntry - > zString , pEntry - > nByte ) ;
2018-07-12 13:26:32 +02:00
/* Perform the insertion */
2018-07-12 17:24:46 +02:00
ph7_array_add_elem ( pArray , 0 /* Automatic index assign*/ , pWorker ) ; /* Will make it's own copy */
2018-07-12 13:26:32 +02:00
}
/* All done,return the created array */
2018-07-12 17:24:46 +02:00
ph7_result_value ( pCtx , pArray ) ;
/* Note that 'pWorker' will be automatically destroyed
2018-07-12 13:26:32 +02:00
* by the engine as soon we return from this foreign
* function .
*/
return PH7_OK ;
}
/*
* include :
2018-08-16 16:12:29 +02:00
* The include ( ) function includes and evaluates the specified file during
* the execution of the script . Files are included based on the file path
* given or , if none is given the include_path specified . If the file isn ' t
* found in the include_path include ( ) will finally check in the calling
* script ' s own directory and the current working directory before failing .
* The include ( ) construct will emit a warning if it cannot find a file ; this
* is different behavior from require ( ) , which will emit a fatal error . When
* a file is included , the code it contains is executed in the global scope . If
* the code from a file has already been included , it will not be included again .
2018-07-12 13:26:32 +02:00
*/
2018-07-12 17:24:46 +02:00
static int vm_builtin_include ( ph7_context * pCtx , int nArg , ph7_value * * apArg ) {
2018-07-12 13:26:32 +02:00
SyString sFile ;
sxi32 rc ;
2018-07-12 17:24:46 +02:00
if ( nArg < 1 ) {
2018-07-12 13:26:32 +02:00
/* Nothing to evaluate,return NULL */
ph7_result_null ( pCtx ) ;
return SXRET_OK ;
}
/* File to include */
2018-07-12 17:24:46 +02:00
sFile . zString = ph7_value_to_string ( apArg [ 0 ] , ( int * ) & sFile . nByte ) ;
if ( sFile . nByte < 1 ) {
2018-07-12 13:26:32 +02:00
/* Empty string,return NULL */
ph7_result_null ( pCtx ) ;
return SXRET_OK ;
}
/* Open,compile and execute the desired script */
2018-07-12 17:24:46 +02:00
rc = VmExecIncludedFile ( & ( * pCtx ) , & sFile , TRUE ) ;
if ( rc = = SXERR_EXISTS ) {
2018-07-12 13:26:32 +02:00
/* File already included,return TRUE */
2018-07-12 17:24:46 +02:00
ph7_result_bool ( pCtx , 1 ) ;
2018-07-12 13:26:32 +02:00
return SXRET_OK ;
}
2018-07-12 17:24:46 +02:00
if ( rc ! = SXRET_OK ) {
2018-07-12 13:26:32 +02:00
/* Emit a warning and return false */
2018-09-04 08:54:48 +02:00
PH7_VmThrowError ( pCtx - > pVm , PH7_CTX_WARNING , " IO error while importing: '%z' " , & sFile ) ;
2018-07-12 17:24:46 +02:00
ph7_result_bool ( pCtx , 0 ) ;
}
2018-07-12 13:26:32 +02:00
return SXRET_OK ;
}
/*
* require .
2018-08-16 16:12:29 +02:00
* The require ( ) is identical to include ( ) except upon failure it will also
* produce a fatal level error . In other words , it will halt the script
* whereas include ( ) only emits a warning which allowsthe script to continue .
2018-07-12 13:26:32 +02:00
*/
2018-07-12 17:24:46 +02:00
static int vm_builtin_require ( ph7_context * pCtx , int nArg , ph7_value * * apArg ) {
2018-07-12 13:26:32 +02:00
SyString sFile ;
sxi32 rc ;
2018-07-12 17:24:46 +02:00
if ( nArg < 1 ) {
2018-07-12 13:26:32 +02:00
/* Nothing to evaluate,return NULL */
ph7_result_null ( pCtx ) ;
return SXRET_OK ;
}
/* File to include */
2018-07-12 17:24:46 +02:00
sFile . zString = ph7_value_to_string ( apArg [ 0 ] , ( int * ) & sFile . nByte ) ;
if ( sFile . nByte < 1 ) {
2018-07-12 13:26:32 +02:00
/* Empty string,return NULL */
ph7_result_null ( pCtx ) ;
return SXRET_OK ;
}
/* Open,compile and execute the desired script */
2018-07-12 17:24:46 +02:00
rc = VmExecIncludedFile ( & ( * pCtx ) , & sFile , TRUE ) ;
if ( rc = = SXERR_EXISTS ) {
2018-07-12 13:26:32 +02:00
/* File already included,return TRUE */
2018-07-12 17:24:46 +02:00
ph7_result_bool ( pCtx , 1 ) ;
2018-07-12 13:26:32 +02:00
return SXRET_OK ;
}
2018-07-12 17:24:46 +02:00
if ( rc ! = SXRET_OK ) {
2018-07-12 13:26:32 +02:00
/* Fatal,abort VM execution immediately */
2018-09-04 08:54:48 +02:00
PH7_VmThrowError ( pCtx - > pVm , PH7_CTX_ERR , " Fatal IO error while importing: '%z' " , & sFile ) ;
2018-07-12 13:26:32 +02:00
}
return SXRET_OK ;
}
/*
* Section :
* Command line arguments processing .
* Authors :
* Symisc Systems , devel @ symisc . net .
2019-05-15 20:02:39 +02:00
* Copyright ( C ) Symisc Systems , https : //ph7.symisc.net
2018-07-12 13:26:32 +02:00
* Status :
* Stable .
*/
/*
* Check if a short option argument [ i . e : - c ] is available in the command
* line string . Return a pointer to the start of the stream on success .
* NULL otherwise .
*/
2018-07-12 17:24:46 +02:00
static const char * VmFindShortOpt ( int c , const char * zIn , const char * zEnd ) {
while ( zIn < zEnd ) {
if ( zIn [ 0 ] = = ' - ' & & & zIn [ 1 ] < zEnd & & ( int ) zIn [ 1 ] = = c ) {
2018-07-12 13:26:32 +02:00
/* Got one */
return & zIn [ 1 ] ;
}
/* Advance the cursor */
zIn + + ;
}
/* No such option */
return 0 ;
}
/*
* Check if a long option argument [ i . e : - - opt ] is available in the command
* line string . Return a pointer to the start of the stream on success .
* NULL otherwise .
*/
2018-07-12 17:24:46 +02:00
static const char * VmFindLongOpt ( const char * zLong , int nByte , const char * zIn , const char * zEnd ) {
2018-07-12 13:26:32 +02:00
const char * zOpt ;
2018-07-12 17:24:46 +02:00
while ( zIn < zEnd ) {
if ( zIn [ 0 ] = = ' - ' & & & zIn [ 1 ] < zEnd & & ( int ) zIn [ 1 ] = = ' - ' ) {
2018-07-12 13:26:32 +02:00
zIn + = 2 ;
zOpt = zIn ;
2018-07-12 17:24:46 +02:00
while ( zIn < zEnd & & ! SyisSpace ( zIn [ 0 ] ) ) {
if ( zIn [ 0 ] = = ' = ' /* --opt=val */ ) {
2018-07-12 13:26:32 +02:00
break ;
}
zIn + + ;
}
/* Test */
2018-07-12 17:24:46 +02:00
if ( ( int ) ( zIn - zOpt ) = = nByte & & SyMemcmp ( zOpt , zLong , nByte ) = = 0 ) {
2018-07-12 13:26:32 +02:00
/* Got one,return it's value */
return zIn ;
}
2018-07-12 17:24:46 +02:00
} else {
2018-07-12 13:26:32 +02:00
zIn + + ;
}
}
/* No such option */
return 0 ;
}
/*
* Long option [ i . e : - - opt ] arguments private data structure .
*/
2018-07-12 17:24:46 +02:00
struct getopt_long_opt {
const char * zArgIn , * zArgEnd ; /* Command line arguments */
2018-07-12 13:26:32 +02:00
ph7_value * pWorker ; /* Worker variable*/
ph7_value * pArray ; /* getopt() return value */
ph7_context * pCtx ; /* Call Context */
} ;
/* Forward declaration */
2018-07-12 17:24:46 +02:00
static int VmProcessLongOpt ( ph7_value * pKey , ph7_value * pValue , void * pUserData ) ;
2018-07-12 13:26:32 +02:00
/*
* Extract short or long argument option values .
*/
static void VmExtractOptArgValue (
ph7_value * pArray , /* getopt() return value */
ph7_value * pWorker , /* Worker variable */
const char * zArg , /* Argument stream */
const char * zArgEnd , /* End of the argument stream */
int need_val , /* TRUE to fetch option argument */
ph7_context * pCtx , /* Call Context */
2018-07-12 17:24:46 +02:00
const char * zName /* Option name */ ) {
ph7_value_bool ( pWorker , 0 ) ;
if ( ! need_val ) {
/*
2018-07-12 13:26:32 +02:00
* Option does not need arguments .
* Insert the option name and a boolean FALSE .
*/
2018-07-12 17:24:46 +02:00
ph7_array_add_strkey_elem ( pArray , ( const char * ) zName , pWorker ) ; /* Will make it's own copy */
} else {
2018-07-12 13:26:32 +02:00
const char * zCur ;
/* Extract option argument */
zArg + + ;
2018-07-12 17:24:46 +02:00
if ( zArg < zArgEnd & & zArg [ 0 ] = = ' = ' ) {
2018-07-12 13:26:32 +02:00
zArg + + ;
}
2018-07-12 17:24:46 +02:00
while ( zArg < zArgEnd & & ( unsigned char ) zArg [ 0 ] < 0xc0 & & SyisSpace ( zArg [ 0 ] ) ) {
2018-07-12 13:26:32 +02:00
zArg + + ;
}
2018-07-12 17:24:46 +02:00
if ( zArg > = zArgEnd | | zArg [ 0 ] = = ' - ' ) {
2018-07-12 13:26:32 +02:00
/*
* Argument not found .
* Insert the option name and a boolean FALSE .
*/
2018-07-12 17:24:46 +02:00
ph7_array_add_strkey_elem ( pArray , ( const char * ) zName , pWorker ) ; /* Will make it's own copy */
2018-07-12 13:26:32 +02:00
return ;
}
/* Delimit the value */
zCur = zArg ;
2018-07-12 17:24:46 +02:00
if ( zArg [ 0 ] = = ' \' ' | | zArg [ 0 ] = = ' " ' ) {
2018-07-12 13:26:32 +02:00
int d = zArg [ 0 ] ;
2018-07-23 17:10:48 +02:00
/* Delimit the argument */
2018-07-12 13:26:32 +02:00
zArg + + ;
zCur = zArg ;
2018-07-12 17:24:46 +02:00
while ( zArg < zArgEnd ) {
if ( zArg [ 0 ] = = d & & zArg [ - 1 ] ! = ' \\ ' ) {
2018-07-12 13:26:32 +02:00
/* Delimiter found,exit the loop */
break ;
}
zArg + + ;
}
/* Save the value */
2018-07-12 17:24:46 +02:00
ph7_value_string ( pWorker , zCur , ( int ) ( zArg - zCur ) ) ;
if ( zArg < zArgEnd ) {
zArg + + ;
}
} else {
while ( zArg < zArgEnd & & ! SyisSpace ( zArg [ 0 ] ) ) {
2018-07-12 13:26:32 +02:00
zArg + + ;
}
/* Save the value */
2018-07-12 17:24:46 +02:00
ph7_value_string ( pWorker , zCur , ( int ) ( zArg - zCur ) ) ;
2018-07-12 13:26:32 +02:00
}
/*
* Check if we are dealing with multiple values .
* If so , create an array to hold them , rather than a scalar variable .
*/
2018-07-12 17:24:46 +02:00
while ( zArg < zArgEnd & & ( unsigned char ) zArg [ 0 ] < 0xc0 & & SyisSpace ( zArg [ 0 ] ) ) {
2018-07-12 13:26:32 +02:00
zArg + + ;
}
2018-07-12 17:24:46 +02:00
if ( zArg < zArgEnd & & zArg [ 0 ] ! = ' - ' ) {
2018-07-12 13:26:32 +02:00
ph7_value * pOptArg ; /* Array of option arguments */
pOptArg = ph7_context_new_array ( pCtx ) ;
2018-07-12 17:24:46 +02:00
if ( pOptArg = = 0 ) {
2018-09-04 08:26:58 +02:00
PH7_VmMemoryError ( pCtx - > pVm ) ;
2018-07-12 17:24:46 +02:00
} else {
2018-07-12 13:26:32 +02:00
/* Insert the first value */
2018-07-12 17:24:46 +02:00
ph7_array_add_elem ( pOptArg , 0 , pWorker ) ; /* Will make it's own copy */
for ( ; ; ) {
if ( zArg > = zArgEnd | | zArg [ 0 ] = = ' - ' ) {
2018-07-12 13:26:32 +02:00
/* No more value */
break ;
}
/* Delimit the value */
zCur = zArg ;
2018-07-12 17:24:46 +02:00
if ( zArg < zArgEnd & & zArg [ 0 ] = = ' \\ ' ) {
2018-07-12 13:26:32 +02:00
zArg + + ;
zCur = zArg ;
}
2018-07-12 17:24:46 +02:00
while ( zArg < zArgEnd & & ! SyisSpace ( zArg [ 0 ] ) ) {
2018-07-12 13:26:32 +02:00
zArg + + ;
}
/* Reset the string cursor */
ph7_value_reset_string_cursor ( pWorker ) ;
/* Save the value */
2018-07-12 17:24:46 +02:00
ph7_value_string ( pWorker , zCur , ( int ) ( zArg - zCur ) ) ;
2018-07-12 13:26:32 +02:00
/* Insert */
2018-07-12 17:24:46 +02:00
ph7_array_add_elem ( pOptArg , 0 , pWorker ) ; /* Will make it's own copy */
2018-07-12 13:26:32 +02:00
/* Jump trailing white spaces */
2018-07-12 17:24:46 +02:00
while ( zArg < zArgEnd & & ( unsigned char ) zArg [ 0 ] < 0xc0 & & SyisSpace ( zArg [ 0 ] ) ) {
2018-07-12 13:26:32 +02:00
zArg + + ;
}
}
/* Insert the option arg array */
2018-07-12 17:24:46 +02:00
ph7_array_add_strkey_elem ( pArray , ( const char * ) zName , pOptArg ) ; /* Will make it's own copy */
2018-07-12 13:26:32 +02:00
/* Safely release */
2018-07-12 17:24:46 +02:00
ph7_context_release_value ( pCtx , pOptArg ) ;
2018-07-12 13:26:32 +02:00
}
2018-07-12 17:24:46 +02:00
} else {
2018-07-12 13:26:32 +02:00
/* Single value */
2018-07-12 17:24:46 +02:00
ph7_array_add_strkey_elem ( pArray , ( const char * ) zName , pWorker ) ; /* Will make it's own copy */
2018-07-12 13:26:32 +02:00
}
}
}
/*
* array getopt ( string $ options [ , array $ longopts ] )
* Gets options from the command line argument list .
* Parameters
* $ options
* Each character in this string will be used as option characters
* and matched against options passed to the script starting with
* a single hyphen ( - ) . For example , an option string " x " recognizes
* an option - x . Only a - z , A - Z and 0 - 9 are allowed .
* $ longopts
* An array of options . Each element in this array will be used as option
* strings and matched against options passed to the script starting with
* two hyphens ( - - ) . For example , an longopts element " opt " recognizes an
2018-07-12 17:24:46 +02:00
* option - - opt .
2018-07-12 13:26:32 +02:00
* Return
* This function will return an array of option / argument pairs or FALSE
2018-07-12 17:24:46 +02:00
* on failure .
2018-07-12 13:26:32 +02:00
*/
2018-07-12 17:24:46 +02:00
static int vm_builtin_getopt ( ph7_context * pCtx , int nArg , ph7_value * * apArg ) {
const char * zIn , * zEnd , * zArg , * zArgIn , * zArgEnd ;
2018-07-12 13:26:32 +02:00
struct getopt_long_opt sLong ;
2018-07-12 17:24:46 +02:00
ph7_value * pArray , * pWorker ;
2018-07-12 13:26:32 +02:00
SyBlob * pArg ;
int nByte ;
2018-07-12 17:24:46 +02:00
if ( nArg < 1 | | ! ph7_value_is_string ( apArg [ 0 ] ) ) {
2018-07-12 13:26:32 +02:00
/* Missing/Invalid arguments,return FALSE */
2018-09-04 08:54:48 +02:00
PH7_VmThrowError ( pCtx - > pVm , PH7_CTX_ERR , " Missing/Invalid option arguments " ) ;
2018-07-12 13:26:32 +02:00
}
/* Extract option arguments */
2018-07-12 17:24:46 +02:00
zIn = ph7_value_to_string ( apArg [ 0 ] , & nByte ) ;
2018-07-12 13:26:32 +02:00
zEnd = & zIn [ nByte ] ;
/* Point to the string representation of the $argv[] array */
pArg = & pCtx - > pVm - > sArgv ;
/* Create a new empty array and a worker variable */
pArray = ph7_context_new_array ( pCtx ) ;
pWorker = ph7_context_new_scalar ( pCtx ) ;
2018-07-12 17:24:46 +02:00
if ( pArray = = 0 | | pWorker = = 0 ) {
2018-09-04 08:26:58 +02:00
PH7_VmMemoryError ( pCtx - > pVm ) ;
2018-07-12 13:26:32 +02:00
}
2018-07-12 17:24:46 +02:00
if ( SyBlobLength ( pArg ) < 1 ) {
2018-07-12 13:26:32 +02:00
/* Empty command line,return the empty array*/
2018-07-12 17:24:46 +02:00
ph7_result_value ( pCtx , pArray ) ;
/* Everything will be released automatically when we return
2018-07-12 13:26:32 +02:00
* from this function .
*/
return PH7_OK ;
}
zArgIn = ( const char * ) SyBlobData ( pArg ) ;
zArgEnd = & zArgIn [ SyBlobLength ( pArg ) ] ;
/* Fill the long option structure */
sLong . pArray = pArray ;
sLong . pWorker = pWorker ;
sLong . zArgIn = zArgIn ;
sLong . zArgEnd = zArgEnd ;
sLong . pCtx = pCtx ;
/* Start processing */
2018-07-12 17:24:46 +02:00
while ( zIn < zEnd ) {
2018-07-12 13:26:32 +02:00
int c = zIn [ 0 ] ;
int need_val = 0 ;
/* Advance the stream cursor */
zIn + + ;
/* Ignore non-alphanum characters */
2018-07-12 17:24:46 +02:00
if ( ! SyisAlphaNum ( c ) ) {
2018-07-12 13:26:32 +02:00
continue ;
}
2018-07-12 17:24:46 +02:00
if ( zIn < zEnd & & zIn [ 0 ] = = ' : ' ) {
2018-07-12 13:26:32 +02:00
zIn + + ;
need_val = 1 ;
2018-07-12 17:24:46 +02:00
if ( zIn < zEnd & & zIn [ 0 ] = = ' : ' ) {
2018-07-12 13:26:32 +02:00
zIn + + ;
}
}
/* Find option */
2018-07-12 17:24:46 +02:00
zArg = VmFindShortOpt ( c , zArgIn , zArgEnd ) ;
if ( zArg = = 0 ) {
2018-07-12 13:26:32 +02:00
/* No such option */
continue ;
}
/* Extract option argument value */
2018-07-12 17:24:46 +02:00
VmExtractOptArgValue ( pArray , pWorker , zArg , zArgEnd , need_val , pCtx , ( const char * ) & c ) ;
2018-07-12 13:26:32 +02:00
}
2018-07-12 17:24:46 +02:00
if ( nArg > 1 & & ph7_value_is_array ( apArg [ 1 ] ) & & ph7_array_count ( apArg [ 1 ] ) > 0 ) {
2018-07-12 13:26:32 +02:00
/* Process long options */
2018-07-12 17:24:46 +02:00
ph7_array_walk ( apArg [ 1 ] , VmProcessLongOpt , & sLong ) ;
2018-07-12 13:26:32 +02:00
}
/* Return the option array */
2018-07-12 17:24:46 +02:00
ph7_result_value ( pCtx , pArray ) ;
/*
2018-07-12 13:26:32 +02:00
* Don ' t worry about freeing memory , everything will be released
* automatically as soon we return from this foreign function .
*/
return PH7_OK ;
}
/*
* Array walker callback used for processing long options values .
*/
2018-07-12 17:24:46 +02:00
static int VmProcessLongOpt ( ph7_value * pKey , ph7_value * pValue , void * pUserData ) {
2018-07-12 13:26:32 +02:00
struct getopt_long_opt * pOpt = ( struct getopt_long_opt * ) pUserData ;
2018-07-12 17:24:46 +02:00
const char * zArg , * zOpt , * zEnd ;
2018-07-12 13:26:32 +02:00
int need_value = 0 ;
int nByte ;
/* Value must be of type string */
2018-07-12 17:24:46 +02:00
if ( ! ph7_value_is_string ( pValue ) ) {
2018-07-12 13:26:32 +02:00
/* Simply ignore */
return PH7_OK ;
}
2018-07-12 17:24:46 +02:00
zOpt = ph7_value_to_string ( pValue , & nByte ) ;
if ( nByte < 1 ) {
2018-07-12 13:26:32 +02:00
/* Empty string,ignore */
return PH7_OK ;
}
zEnd = & zOpt [ nByte - 1 ] ;
2018-07-12 17:24:46 +02:00
if ( zEnd [ 0 ] = = ' : ' ) {
2018-07-12 13:26:32 +02:00
char * zTerm ;
/* Try to extract a value */
need_value = 1 ;
2018-07-12 17:24:46 +02:00
while ( zEnd > = zOpt & & zEnd [ 0 ] = = ' : ' ) {
2018-07-12 13:26:32 +02:00
zEnd - - ;
}
2018-07-12 17:24:46 +02:00
if ( zOpt > = zEnd ) {
2018-07-12 13:26:32 +02:00
/* Empty string,ignore */
SXUNUSED ( pKey ) ;
return PH7_OK ;
}
zEnd + + ;
zTerm = ( char * ) zEnd ;
zTerm [ 0 ] = 0 ;
2018-07-12 17:24:46 +02:00
} else {
2018-07-12 13:26:32 +02:00
zEnd = & zOpt [ nByte ] ;
}
/* Find the option */
2018-07-12 17:24:46 +02:00
zArg = VmFindLongOpt ( zOpt , ( int ) ( zEnd - zOpt ) , pOpt - > zArgIn , pOpt - > zArgEnd ) ;
if ( zArg = = 0 ) {
2018-07-12 13:26:32 +02:00
/* No such option,return immediately */
return PH7_OK ;
}
/* Try to extract a value */
2018-07-12 17:24:46 +02:00
VmExtractOptArgValue ( pOpt - > pArray , pOpt - > pWorker , zArg , pOpt - > zArgEnd , need_value , pOpt - > pCtx , zOpt ) ;
2018-07-12 13:26:32 +02:00
return PH7_OK ;
}
/*
* int utf8_encode ( string $ input )
* UTF - 8 encoding .
* This function encodes the string data to UTF - 8 , and returns the encoded version .
* UTF - 8 is a standard mechanism used by Unicode for encoding wide character values
* into a byte stream . UTF - 8 is transparent to plain ASCII characters , is self - synchronized
* ( meaning it is possible for a program to figure out where in the bytestream characters start )
* and can be used with normal string comparison functions for sorting and such .
* Notes on UTF - 8 ( According to SQLite3 authors ) :
* Byte - 0 Byte - 1 Byte - 2 Byte - 3 Value
* 0 xxxxxxx 00000000 00000000 0 xxxxxxx
* 110 yyyyy 10 xxxxxx 00000000 00000 yyy yyxxxxxx
* 1110 zzzz 10 yyyyyy 10 xxxxxx 00000000 zzzzyyyy yyxxxxxx
* 11110uuu 10uu zzzz 10 yyyyyy 10 xxxxxx 000uuuuu zzzzyyyy yyxxxxxx
* Parameters
* $ input
* String to encode or NULL on failure .
* Return
* An UTF - 8 encoded string .
*/
2018-07-12 17:24:46 +02:00
static int vm_builtin_utf8_encode ( ph7_context * pCtx , int nArg , ph7_value * * apArg ) {
const unsigned char * zIn , * zEnd ;
int nByte , c , e ;
if ( nArg < 1 ) {
2018-07-12 13:26:32 +02:00
/* Missing arguments,return null */
ph7_result_null ( pCtx ) ;
return PH7_OK ;
}
/* Extract the target string */
2018-07-12 17:24:46 +02:00
zIn = ( const unsigned char * ) ph7_value_to_string ( apArg [ 0 ] , & nByte ) ;
if ( nByte < 1 ) {
2018-07-12 13:26:32 +02:00
/* Empty string,return null */
ph7_result_null ( pCtx ) ;
return PH7_OK ;
}
zEnd = & zIn [ nByte ] ;
/* Start the encoding process */
2018-07-12 17:24:46 +02:00
for ( ; ; ) {
if ( zIn > = zEnd ) {
2018-07-12 13:26:32 +02:00
/* End of input */
break ;
}
c = zIn [ 0 ] ;
/* Advance the stream cursor */
zIn + + ;
/* Encode */
2018-07-12 17:24:46 +02:00
if ( c < 0x00080 ) {
e = ( c & 0xFF ) ;
ph7_result_string ( pCtx , ( const char * ) & e , ( int ) sizeof ( char ) ) ;
} else if ( c < 0x00800 ) {
e = 0xC0 + ( ( c > > 6 ) & 0x1F ) ;
ph7_result_string ( pCtx , ( const char * ) & e , ( int ) sizeof ( char ) ) ;
2018-07-12 13:26:32 +02:00
e = 0x80 + ( c & 0x3F ) ;
2018-07-12 17:24:46 +02:00
ph7_result_string ( pCtx , ( const char * ) & e , ( int ) sizeof ( char ) ) ;
} else if ( c < 0x10000 ) {
e = 0xE0 + ( ( c > > 12 ) & 0x0F ) ;
ph7_result_string ( pCtx , ( const char * ) & e , ( int ) sizeof ( char ) ) ;
e = 0x80 + ( ( c > > 6 ) & 0x3F ) ;
ph7_result_string ( pCtx , ( const char * ) & e , ( int ) sizeof ( char ) ) ;
2018-07-12 13:26:32 +02:00
e = 0x80 + ( c & 0x3F ) ;
2018-07-12 17:24:46 +02:00
ph7_result_string ( pCtx , ( const char * ) & e , ( int ) sizeof ( char ) ) ;
} else {
e = 0xF0 + ( ( c > > 18 ) & 0x07 ) ;
ph7_result_string ( pCtx , ( const char * ) & e , ( int ) sizeof ( char ) ) ;
e = 0x80 + ( ( c > > 12 ) & 0x3F ) ;
ph7_result_string ( pCtx , ( const char * ) & e , ( int ) sizeof ( char ) ) ;
e = 0x80 + ( ( c > > 6 ) & 0x3F ) ;
ph7_result_string ( pCtx , ( const char * ) & e , ( int ) sizeof ( char ) ) ;
2018-07-12 13:26:32 +02:00
e = 0x80 + ( c & 0x3F ) ;
2018-07-12 17:24:46 +02:00
ph7_result_string ( pCtx , ( const char * ) & e , ( int ) sizeof ( char ) ) ;
}
2018-07-12 13:26:32 +02:00
}
/* All done */
return PH7_OK ;
}
/*
* UTF - 8 decoding routine extracted from the sqlite3 source tree .
2019-05-15 20:02:39 +02:00
* Original author : D . Richard Hipp ( https : //www.sqlite.org)
2018-07-12 13:26:32 +02:00
* Status : Public Domain
*/
/*
* * This lookup table is used to help decode the first byte of
* * a multi - byte UTF8 character .
*/
static const unsigned char UtfTrans1 [ ] = {
2018-07-12 17:24:46 +02:00
0x00 , 0x01 , 0x02 , 0x03 , 0x04 , 0x05 , 0x06 , 0x07 ,
0x08 , 0x09 , 0x0a , 0x0b , 0x0c , 0x0d , 0x0e , 0x0f ,
0x10 , 0x11 , 0x12 , 0x13 , 0x14 , 0x15 , 0x16 , 0x17 ,
0x18 , 0x19 , 0x1a , 0x1b , 0x1c , 0x1d , 0x1e , 0x1f ,
0x00 , 0x01 , 0x02 , 0x03 , 0x04 , 0x05 , 0x06 , 0x07 ,
0x08 , 0x09 , 0x0a , 0x0b , 0x0c , 0x0d , 0x0e , 0x0f ,
0x00 , 0x01 , 0x02 , 0x03 , 0x04 , 0x05 , 0x06 , 0x07 ,
0x00 , 0x01 , 0x02 , 0x03 , 0x00 , 0x01 , 0x00 , 0x00 ,
2018-07-12 13:26:32 +02:00
} ;
/*
* * Translate a single UTF - 8 character . Return the unicode value .
* *
* * During translation , assume that the byte that zTerm points
* * is a 0x00 .
* *
* * Write a pointer to the next unread byte back into * pzNext .
* *
* * Notes On Invalid UTF - 8 :
* *
* * * This routine never allows a 7 - bit character ( 0x00 through 0x7f ) to
* * be encoded as a multi - byte character . Any multi - byte character that
* * attempts to encode a value between 0x00 and 0x7f is rendered as 0xfffd .
* *
* * * This routine never allows a UTF16 surrogate value to be encoded .
* * If a multi - byte character attempts to encode a value between
* * 0xd800 and 0xe000 then it is rendered as 0xfffd .
* *
* * * Bytes in the range of 0x80 through 0xbf which occur as the first
* * byte of a character are interpreted as single - byte characters
* * and rendered as themselves even though they are technically
* * invalid characters .
* *
* * * This routine accepts an infinite number of different UTF8 encodings
* * for unicode values 0x80 and greater . It do not change over - length
* * encodings to 0xfffd as some systems recommend .
*/
# define READ_UTF8(zIn, zTerm, c) \
2018-07-12 17:24:46 +02:00
c = * ( zIn + + ) ; \
if ( c > = 0xc0 ) { \
c = UtfTrans1 [ c - 0xc0 ] ; \
while ( zIn ! = zTerm & & ( * zIn & 0xc0 ) = = 0x80 ) { \
c = ( c < < 6 ) + ( 0x3f & * ( zIn + + ) ) ; \
} \
if ( c < 0x80 \
| | ( c & 0xFFFFF800 ) = = 0xD800 \
| | ( c & 0xFFFFFFFE ) = = 0xFFFE ) { c = 0xFFFD ; } \
}
2018-07-12 13:26:32 +02:00
PH7_PRIVATE int PH7_Utf8Read (
2018-07-12 17:24:46 +02:00
const unsigned char * z , /* First byte of UTF-8 character */
const unsigned char * zTerm , /* Pretend this byte is 0x00 */
const unsigned char * * pzNext /* Write first byte past UTF-8 char here */
) {
int c ;
READ_UTF8 ( z , zTerm , c ) ;
* pzNext = z ;
return c ;
2018-07-12 13:26:32 +02:00
}
/*
* string utf8_decode ( string $ data )
* This function decodes data , assumed to be UTF - 8 encoded , to unicode .
* Parameters
* data
* An UTF - 8 encoded string .
* Return
* Unicode decoded string or NULL on failure .
*/
2018-07-12 17:24:46 +02:00
static int vm_builtin_utf8_decode ( ph7_context * pCtx , int nArg , ph7_value * * apArg ) {
const unsigned char * zIn , * zEnd ;
int nByte , c ;
if ( nArg < 1 ) {
2018-07-12 13:26:32 +02:00
/* Missing arguments,return null */
ph7_result_null ( pCtx ) ;
return PH7_OK ;
}
/* Extract the target string */
2018-07-12 17:24:46 +02:00
zIn = ( const unsigned char * ) ph7_value_to_string ( apArg [ 0 ] , & nByte ) ;
if ( nByte < 1 ) {
2018-07-12 13:26:32 +02:00
/* Empty string,return null */
ph7_result_null ( pCtx ) ;
return PH7_OK ;
}
zEnd = & zIn [ nByte ] ;
/* Start the decoding process */
2018-07-12 17:24:46 +02:00
while ( zIn < zEnd ) {
c = PH7_Utf8Read ( zIn , zEnd , & zIn ) ;
if ( c = = 0x0 ) {
2018-07-12 13:26:32 +02:00
break ;
}
2018-07-12 17:24:46 +02:00
ph7_result_string ( pCtx , ( const char * ) & c , ( int ) sizeof ( char ) ) ;
2018-07-12 13:26:32 +02:00
}
return PH7_OK ;
}
/* Table of built-in VM functions. */
static const ph7_builtin_func aVmFunc [ ] = {
{ " function_exists " , vm_builtin_func_exists } ,
2019-04-10 09:45:00 +02:00
{ " is_callable " , vm_builtin_is_callable } ,
2018-07-15 00:06:26 +02:00
{ " register_autoload_handler " , vm_builtin_register_autoload_handler } ,
2018-07-12 17:24:46 +02:00
{ " register_shutdown_function " , vm_builtin_register_shutdown_function } ,
/* Constants management */
2018-07-12 13:26:32 +02:00
{ " get_defined_constants " , vm_builtin_get_defined_constants } ,
2018-07-12 17:24:46 +02:00
/* Class/Object functions */
2018-07-12 13:26:32 +02:00
{ " class_alias " , vm_builtin_class_alias } ,
{ " class_exists " , vm_builtin_class_exists } ,
{ " property_exists " , vm_builtin_property_exists } ,
{ " method_exists " , vm_builtin_method_exists } ,
2018-07-12 17:24:46 +02:00
{ " interface_exists " , vm_builtin_interface_exists } ,
2018-07-12 13:26:32 +02:00
{ " get_class " , vm_builtin_get_class } ,
2018-07-12 17:24:46 +02:00
{ " get_parent_class " , vm_builtin_get_parent_class } ,
{ " get_called_class " , vm_builtin_get_called_class } ,
2018-07-12 13:26:32 +02:00
{ " get_declared_classes " , vm_builtin_get_declared_classes } ,
{ " get_declared_interfaces " , vm_builtin_get_declared_interfaces } ,
{ " get_class_methods " , vm_builtin_get_class_methods } ,
{ " get_class_vars " , vm_builtin_get_class_vars } ,
{ " get_object_vars " , vm_builtin_get_object_vars } ,
{ " is_subclass_of " , vm_builtin_is_subclass_of } ,
{ " is_a " , vm_builtin_is_a } ,
2018-07-12 17:24:46 +02:00
/* Random numbers/strings generators */
2018-07-12 13:26:32 +02:00
{ " rand " , vm_builtin_rand } ,
{ " rand_str " , vm_builtin_rand_str } ,
{ " getrandmax " , vm_builtin_getrandmax } ,
2018-07-16 13:15:42 +02:00
{ " random_int " , vm_builtin_random_int } ,
{ " random_bytes " , vm_builtin_random_bytes } ,
2018-07-12 13:26:32 +02:00
{ " uniqid " , vm_builtin_uniqid } ,
2018-07-12 17:24:46 +02:00
/* Language constructs functions */
2018-07-12 13:26:32 +02:00
{ " print " , vm_builtin_print } ,
{ " exit " , vm_builtin_exit } ,
{ " eval " , vm_builtin_eval } ,
2018-07-12 17:24:46 +02:00
/* Variable handling functions */
{ " get_defined_vars " , vm_builtin_get_defined_vars } ,
2018-07-12 13:26:32 +02:00
{ " gettype " , vm_builtin_gettype } ,
{ " get_resource_type " , vm_builtin_get_resource_type } ,
{ " unset " , vm_builtin_unset } ,
{ " var_dump " , vm_builtin_var_dump } ,
{ " print_r " , vm_builtin_print_r } ,
2018-07-12 17:24:46 +02:00
{ " var_export " , vm_builtin_var_export } ,
/* Ouput control functions */
2018-07-12 13:26:32 +02:00
{ " ob_clean " , vm_builtin_ob_clean } ,
{ " ob_end_clean " , vm_builtin_ob_end_clean } ,
{ " ob_end_flush " , vm_builtin_ob_end_flush } ,
{ " ob_flush " , vm_builtin_ob_flush } ,
{ " ob_get_clean " , vm_builtin_ob_get_clean } ,
{ " ob_get_contents " , vm_builtin_ob_get_contents } ,
{ " ob_get_flush " , vm_builtin_ob_get_clean } ,
{ " ob_get_length " , vm_builtin_ob_get_length } ,
{ " ob_get_level " , vm_builtin_ob_get_level } ,
{ " ob_implicit_flush " , vm_builtin_ob_implicit_flush } ,
{ " ob_get_level " , vm_builtin_ob_get_level } ,
{ " ob_list_handlers " , vm_builtin_ob_list_handlers } ,
{ " ob_start " , vm_builtin_ob_start } ,
2018-08-18 19:24:38 +02:00
/* Memory usage reporting */
{ " get_memory_limit " , vm_builtin_get_memory_limit } ,
{ " get_memory_peak_usage " , vm_builtin_get_memory_peak_usage } ,
{ " get_memory_usage " , vm_builtin_get_memory_usage } ,
2018-07-12 17:24:46 +02:00
/* Assertion functions */
2018-07-12 13:26:32 +02:00
{ " assert_options " , vm_builtin_assert_options } ,
{ " assert " , vm_builtin_assert } ,
2018-07-12 17:24:46 +02:00
/* Error reporting functions */
2018-07-12 13:26:32 +02:00
{ " restore_exception_handler " , vm_builtin_restore_exception_handler } ,
{ " set_exception_handler " , vm_builtin_set_exception_handler } ,
{ " debug_backtrace " , vm_builtin_debug_backtrace } ,
2018-07-12 17:24:46 +02:00
/* Release info */
2018-07-12 13:26:32 +02:00
{ " ph7version " , vm_builtin_ph7_version } ,
{ " phpinfo " , vm_builtin_ph7_credits } ,
2018-07-12 17:24:46 +02:00
/* hashmap */
2018-07-12 13:26:32 +02:00
{ " compact " , vm_builtin_compact } ,
{ " extract " , vm_builtin_extract } ,
2018-07-12 17:24:46 +02:00
/* URL related function */
2018-07-12 13:26:32 +02:00
{ " parse_url " , vm_builtin_parse_url } ,
2018-07-12 17:24:46 +02:00
/* Refer to 'builtin.c' for others string processing functions. */
/* UTF-8 encoding/decoding */
2018-07-12 13:26:32 +02:00
{ " utf8_encode " , vm_builtin_utf8_encode } ,
{ " utf8_decode " , vm_builtin_utf8_decode } ,
2018-07-12 17:24:46 +02:00
/* Command line processing */
2018-07-12 13:26:32 +02:00
{ " getopt " , vm_builtin_getopt } ,
2018-07-18 22:01:04 +02:00
/* Module loading facility */
{ " import " , vm_builtin_import } ,
2018-07-12 17:24:46 +02:00
/* Files/URI inclusion facility */
2018-07-12 13:26:32 +02:00
{ " get_include_path " , vm_builtin_get_include_path } ,
2018-07-12 17:24:46 +02:00
{ " get_included_files " , vm_builtin_get_included_files } ,
2018-07-12 13:26:32 +02:00
{ " include " , vm_builtin_include } ,
{ " require " , vm_builtin_require } ,
} ;
/*
* Register the built - in VM functions defined above .
*/
2018-07-12 17:24:46 +02:00
static sxi32 VmRegisterSpecialFunction ( ph7_vm * pVm ) {
2018-07-12 13:26:32 +02:00
sxi32 rc ;
sxu32 n ;
2018-07-12 17:24:46 +02:00
for ( n = 0 ; n < SX_ARRAYSIZE ( aVmFunc ) ; + + n ) {
2018-07-12 13:26:32 +02:00
/* Note that these special functions have access
* to the underlying virtual machine as their
* private data .
*/
2018-07-12 17:24:46 +02:00
rc = ph7_create_function ( & ( * pVm ) , aVmFunc [ n ] . zName , aVmFunc [ n ] . xFunc , & ( * pVm ) ) ;
if ( rc ! = SXRET_OK ) {
2018-07-12 13:26:32 +02:00
return rc ;
}
}
return SXRET_OK ;
}
/*
* Check if the given name refer to an installed class .
* Return a pointer to that class on success . NULL on failure .
*/
2018-07-12 17:24:46 +02:00
PH7_PRIVATE ph7_class * PH7_VmExtractClass (
2018-07-12 13:26:32 +02:00
ph7_vm * pVm , /* Target VM */
const char * zName , /* Name of the target class */
sxu32 nByte , /* zName length */
sxi32 iLoadable , /* TRUE to return only loadable class
2018-07-30 17:08:25 +02:00
* [ i . e : no virtual classes or interfaces ]
2018-07-12 13:26:32 +02:00
*/
sxi32 iNest /* Nesting level (Not used) */
2018-07-12 17:24:46 +02:00
) {
2018-07-12 13:26:32 +02:00
SyHashEntry * pEntry ;
ph7_class * pClass ;
/* Perform a hash lookup */
2018-07-12 17:24:46 +02:00
pEntry = SyHashGet ( & pVm - > hClass , ( const void * ) zName , nByte ) ;
if ( pEntry = = 0 ) {
2018-07-15 00:06:26 +02:00
ph7_value * apArg [ 1 ] ;
ph7_value sResult , sName ;
VmAutoLoadCB * sEntry ;
sxu32 n , nEntry ;
/* Point to the stack of registered callbacks */
nEntry = SySetUsed ( & pVm - > aAutoLoad ) ;
for ( n = 0 ; n < nEntry ; n + + ) {
sEntry = ( VmAutoLoadCB * ) SySetAt ( & pVm - > aAutoLoad , n ) ;
if ( sEntry ) {
2018-07-15 11:57:22 +02:00
PH7_MemObjInitFromString ( pVm , & sName , 0 ) ;
PH7_MemObjStringAppend ( & sName , zName , nByte ) ;
2018-07-15 00:06:26 +02:00
apArg [ 0 ] = & sName ;
/* Call autoloader */
2018-07-15 11:57:22 +02:00
PH7_MemObjInit ( pVm , & sResult ) ;
PH7_VmCallUserFunction ( pVm , & sEntry - > sCallback , 1 , apArg , & sResult ) ;
2018-07-15 00:06:26 +02:00
PH7_MemObjRelease ( & sResult ) ;
PH7_MemObjRelease ( & sName ) ;
2018-07-23 17:10:48 +02:00
/* Perform a hash lookup once again */
2018-07-15 11:57:22 +02:00
pEntry = SyHashGet ( & pVm - > hClass , ( const void * ) zName , nByte ) ;
2018-07-15 00:06:26 +02:00
if ( pEntry ) {
/* Do not call more callbacks if class is already available */
break ;
}
}
}
if ( pEntry = = 0 ) {
/* No such entry,return NULL */
iNest = 0 ; /* cc warning */
return 0 ;
}
2018-07-12 13:26:32 +02:00
}
pClass = ( ph7_class * ) pEntry - > pUserData ;
2018-07-12 17:24:46 +02:00
if ( ! iLoadable ) {
2018-07-25 19:00:49 +02:00
/* Return the class absolutely */
2018-07-12 13:26:32 +02:00
return pClass ;
2018-07-12 17:24:46 +02:00
} else {
2018-07-30 17:08:25 +02:00
if ( ( pClass - > iFlags & ( PH7_CLASS_INTERFACE | PH7_CLASS_VIRTUAL ) ) = = 0 ) {
2018-07-25 19:00:49 +02:00
/* Class is loadable */
return pClass ;
2018-07-12 13:26:32 +02:00
}
}
/* No such loadable class */
return 0 ;
}
/*
2018-07-12 17:24:46 +02:00
* Reference Table Implementation
2018-07-12 13:26:32 +02:00
* Status : stable < chm @ symisc . net >
* Intro
* The implementation of the reference mechanism in the PH7 engine
* differ greatly from the one used by the zend engine . That is ,
* the reference implementation is consistent , solid and it ' s
* behavior resemble the C + + reference mechanism .
* Refer to the official for more information on this powerful
* extension .
*/
/*
* Allocate a new reference entry .
*/
2018-07-12 17:24:46 +02:00
static VmRefObj * VmNewRefObj ( ph7_vm * pVm , sxu32 nIdx ) {
2018-07-12 13:26:32 +02:00
VmRefObj * pRef ;
/* Allocate a new instance */
2018-07-12 17:24:46 +02:00
pRef = ( VmRefObj * ) SyMemBackendPoolAlloc ( & pVm - > sAllocator , sizeof ( VmRefObj ) ) ;
if ( pRef = = 0 ) {
2018-07-12 13:26:32 +02:00
return 0 ;
}
/* Zero the structure */
2018-07-12 17:24:46 +02:00
SyZero ( pRef , sizeof ( VmRefObj ) ) ;
2018-07-12 13:26:32 +02:00
/* Initialize fields */
2018-07-12 17:24:46 +02:00
SySetInit ( & pRef - > aReference , & pVm - > sAllocator , sizeof ( SyHashEntry * ) ) ;
SySetInit ( & pRef - > aArrEntries , & pVm - > sAllocator , sizeof ( ph7_hashmap_node * ) ) ;
2018-07-12 13:26:32 +02:00
pRef - > nIdx = nIdx ;
return pRef ;
}
/*
2018-07-12 17:24:46 +02:00
* Default hash function used by the reference table
2018-07-12 13:26:32 +02:00
* for lookup / insertion operations .
*/
2018-07-12 17:24:46 +02:00
static sxu32 VmRefHash ( sxu32 nIdx ) {
2018-07-12 13:26:32 +02:00
/* Calculate the hash based on the memory object index */
return nIdx ^ ( nIdx < < 8 ) ^ ( nIdx > > 8 ) ;
}
/*
* Check if a memory object [ i . e : a variable ] is already installed
* in the reference table .
* Return a pointer to the entry ( VmRefObj instance ) on success . NULL
* otherwise .
* The implementation of the reference mechanism in the PH7 engine
* differ greatly from the one used by the zend engine . That is ,
* the reference implementation is consistent , solid and it ' s
* behavior resemble the C + + reference mechanism .
* Refer to the official for more information on this powerful
* extension .
*/
2018-07-12 17:24:46 +02:00
static VmRefObj * VmRefObjExtract ( ph7_vm * pVm , sxu32 nObjIdx ) {
2018-07-12 13:26:32 +02:00
VmRefObj * pRef ;
sxu32 nBucket ;
/* Point to the appropriate bucket */
nBucket = VmRefHash ( nObjIdx ) & ( pVm - > nRefSize - 1 ) ;
/* Perform the lookup */
pRef = pVm - > apRefObj [ nBucket ] ;
2018-07-12 17:24:46 +02:00
for ( ; ; ) {
if ( pRef = = 0 ) {
2018-07-12 13:26:32 +02:00
break ;
}
2018-07-12 17:24:46 +02:00
if ( pRef - > nIdx = = nObjIdx ) {
2018-07-12 13:26:32 +02:00
/* Entry found */
return pRef ;
}
/* Point to the next entry */
pRef = pRef - > pNextCollide ;
}
/* No such entry,return NULL */
return 0 ;
}
/*
* Install a memory object [ i . e : a variable ] in the reference table .
*
* The implementation of the reference mechanism in the PH7 engine
* differ greatly from the one used by the zend engine . That is ,
* the reference implementation is consistent , solid and it ' s
* behavior resemble the C + + reference mechanism .
* Refer to the official for more information on this powerful
* extension .
*/
2018-07-12 17:24:46 +02:00
static sxi32 VmRefObjInsert ( ph7_vm * pVm , VmRefObj * pRef ) {
2018-07-12 13:26:32 +02:00
sxu32 nBucket ;
2018-07-12 17:24:46 +02:00
if ( pVm - > nRefUsed * 3 > = pVm - > nRefSize ) {
2018-07-12 13:26:32 +02:00
VmRefObj * * apNew ;
sxu32 nNew ;
/* Allocate a larger table */
nNew = pVm - > nRefSize < < 1 ;
2018-07-12 17:24:46 +02:00
apNew = ( VmRefObj * * ) SyMemBackendAlloc ( & pVm - > sAllocator , sizeof ( VmRefObj * ) * nNew ) ;
if ( apNew ) {
2018-07-12 13:26:32 +02:00
VmRefObj * pEntry = pVm - > pRefList ;
sxu32 n ;
/* Zero the structure */
2018-07-12 17:24:46 +02:00
SyZero ( ( void * ) apNew , nNew * sizeof ( VmRefObj * ) ) ;
2018-07-12 13:26:32 +02:00
/* Rehash all referenced entries */
2018-07-12 17:24:46 +02:00
for ( n = 0 ; n < pVm - > nRefUsed ; + + n ) {
2018-07-12 13:26:32 +02:00
/* Remove old collision links */
pEntry - > pNextCollide = pEntry - > pPrevCollide = 0 ;
/* Point to the appropriate bucket */
nBucket = VmRefHash ( pEntry - > nIdx ) & ( nNew - 1 ) ;
/* Insert the entry */
pEntry - > pNextCollide = apNew [ nBucket ] ;
2018-07-12 17:24:46 +02:00
if ( apNew [ nBucket ] ) {
2018-07-12 13:26:32 +02:00
apNew [ nBucket ] - > pPrevCollide = pEntry ;
}
apNew [ nBucket ] = pEntry ;
/* Point to the next entry */
pEntry = pEntry - > pNext ;
}
/* Release the old table */
2018-07-12 17:24:46 +02:00
SyMemBackendFree ( & pVm - > sAllocator , pVm - > apRefObj ) ;
2018-07-12 13:26:32 +02:00
/* Install the new one */
pVm - > apRefObj = apNew ;
pVm - > nRefSize = nNew ;
}
}
/* Point to the appropriate bucket */
nBucket = VmRefHash ( pRef - > nIdx ) & ( pVm - > nRefSize - 1 ) ;
/* Insert the entry */
pRef - > pNextCollide = pVm - > apRefObj [ nBucket ] ;
2018-07-12 17:24:46 +02:00
if ( pVm - > apRefObj [ nBucket ] ) {
2018-07-12 13:26:32 +02:00
pVm - > apRefObj [ nBucket ] - > pPrevCollide = pRef ;
}
pVm - > apRefObj [ nBucket ] = pRef ;
2018-07-12 17:24:46 +02:00
MACRO_LD_PUSH ( pVm - > pRefList , pRef ) ;
2018-07-12 13:26:32 +02:00
pVm - > nRefUsed + + ;
return SXRET_OK ;
}
/*
* Destroy a memory object [ i . e : a variable ] and remove it from
* the reference table .
* This function is invoked when the user perform an unset
* call [ i . e : unset ( $ var ) ; ] .
* The implementation of the reference mechanism in the PH7 engine
* differ greatly from the one used by the zend engine . That is ,
* the reference implementation is consistent , solid and it ' s
* behavior resemble the C + + reference mechanism .
* Refer to the official for more information on this powerful
* extension .
*/
2018-07-12 17:24:46 +02:00
static sxi32 VmRefObjUnlink ( ph7_vm * pVm , VmRefObj * pRef ) {
2018-07-12 13:26:32 +02:00
ph7_hashmap_node * * apNode ;
SyHashEntry * * apEntry ;
sxu32 n ;
/* Point to the reference table */
apNode = ( ph7_hashmap_node * * ) SySetBasePtr ( & pRef - > aArrEntries ) ;
apEntry = ( SyHashEntry * * ) SySetBasePtr ( & pRef - > aReference ) ;
/* Unlink the entry from the reference table */
2018-07-12 17:24:46 +02:00
for ( n = 0 ; n < SySetUsed ( & pRef - > aReference ) ; n + + ) {
if ( apEntry [ n ] ) {
2018-07-12 13:26:32 +02:00
SyHashDeleteEntry2 ( apEntry [ n ] ) ;
}
}
2018-07-12 17:24:46 +02:00
for ( n = 0 ; n < SySetUsed ( & pRef - > aArrEntries ) ; + + n ) {
if ( apNode [ n ] ) {
PH7_HashmapUnlinkNode ( apNode [ n ] , FALSE ) ;
2018-07-12 13:26:32 +02:00
}
}
2018-07-12 17:24:46 +02:00
if ( pRef - > pPrevCollide ) {
2018-07-12 13:26:32 +02:00
pRef - > pPrevCollide - > pNextCollide = pRef - > pNextCollide ;
2018-07-12 17:24:46 +02:00
} else {
2018-07-12 13:26:32 +02:00
pVm - > apRefObj [ VmRefHash ( pRef - > nIdx ) & ( pVm - > nRefSize - 1 ) ] = pRef - > pNextCollide ;
}
2018-07-12 17:24:46 +02:00
if ( pRef - > pNextCollide ) {
2018-07-12 13:26:32 +02:00
pRef - > pNextCollide - > pPrevCollide = pRef - > pPrevCollide ;
}
2018-07-12 17:24:46 +02:00
MACRO_LD_REMOVE ( pVm - > pRefList , pRef ) ;
2018-07-12 13:26:32 +02:00
/* Release the node */
SySetRelease ( & pRef - > aReference ) ;
SySetRelease ( & pRef - > aArrEntries ) ;
2018-07-12 17:24:46 +02:00
SyMemBackendPoolFree ( & pVm - > sAllocator , pRef ) ;
2018-07-12 13:26:32 +02:00
pVm - > nRefUsed - - ;
return SXRET_OK ;
}
/*
* Install a memory object [ i . e : a variable ] in the reference table .
* The implementation of the reference mechanism in the PH7 engine
* differ greatly from the one used by the zend engine . That is ,
* the reference implementation is consistent , solid and it ' s
* behavior resemble the C + + reference mechanism .
* Refer to the official for more information on this powerful
* extension .
*/
PH7_PRIVATE sxi32 PH7_VmRefObjInstall (
ph7_vm * pVm , /* Target VM */
sxu32 nIdx , /* Memory object index in the global object pool */
SyHashEntry * pEntry , /* Hash entry of this object */
ph7_hashmap_node * pMapEntry , /* != NULL if the memory object is an array entry */
2018-07-12 17:24:46 +02:00
sxi32 iFlags /* Control flags */
) {
2018-07-12 13:26:32 +02:00
VmFrame * pFrame = pVm - > pFrame ;
VmRefObj * pRef ;
/* Check if the referenced object already exists */
2018-07-12 17:24:46 +02:00
pRef = VmRefObjExtract ( & ( * pVm ) , nIdx ) ;
if ( pRef = = 0 ) {
2018-07-12 13:26:32 +02:00
/* Create a new entry */
2018-07-12 17:24:46 +02:00
pRef = VmNewRefObj ( & ( * pVm ) , nIdx ) ;
if ( pRef = = 0 ) {
2018-07-12 13:26:32 +02:00
return SXERR_MEM ;
}
pRef - > iFlags = iFlags ;
/* Install the entry */
2018-07-12 17:24:46 +02:00
VmRefObjInsert ( & ( * pVm ) , pRef ) ;
2018-07-12 13:26:32 +02:00
}
2018-07-12 17:24:46 +02:00
while ( pFrame - > pParent & & ( pFrame - > iFlags & VM_FRAME_EXCEPTION ) ) {
2018-07-12 13:26:32 +02:00
/* Safely ignore the exception frame */
pFrame = pFrame - > pParent ;
}
2018-07-12 17:24:46 +02:00
if ( pFrame - > pParent ! = 0 & & pEntry ) {
2018-07-12 13:26:32 +02:00
VmSlot sRef ;
/* Local frame,record referenced entry so that it can
* be deleted when we leave this frame .
*/
sRef . nIdx = nIdx ;
sRef . pUserData = pEntry ;
2018-07-12 17:24:46 +02:00
if ( SXRET_OK ! = SySetPut ( & pFrame - > sRef , ( const void * ) & sRef ) ) {
2018-07-12 13:26:32 +02:00
pEntry = 0 ; /* Do not record this entry */
}
}
2018-07-12 17:24:46 +02:00
if ( pEntry ) {
2018-07-12 13:26:32 +02:00
/* Address of the hash-entry */
2018-07-12 17:24:46 +02:00
SySetPut ( & pRef - > aReference , ( const void * ) & pEntry ) ;
2018-07-12 13:26:32 +02:00
}
2018-07-12 17:24:46 +02:00
if ( pMapEntry ) {
2018-07-12 13:26:32 +02:00
/* Address of the hashmap node [i.e: Array entry] */
2018-07-12 17:24:46 +02:00
SySetPut ( & pRef - > aArrEntries , ( const void * ) & pMapEntry ) ;
2018-07-12 13:26:32 +02:00
}
return SXRET_OK ;
}
/*
* Remove a memory object [ i . e : a variable ] from the reference table .
* The implementation of the reference mechanism in the PH7 engine
* differ greatly from the one used by the zend engine . That is ,
* the reference implementation is consistent , solid and it ' s
* behavior resemble the C + + reference mechanism .
* Refer to the official for more information on this powerful
* extension .
*/
PH7_PRIVATE sxi32 PH7_VmRefObjRemove (
ph7_vm * pVm , /* Target VM */
sxu32 nIdx , /* Memory object index in the global object pool */
SyHashEntry * pEntry , /* Hash entry of this object */
ph7_hashmap_node * pMapEntry /* != NULL if the memory object is an array entry */
2018-07-12 17:24:46 +02:00
) {
2018-07-12 13:26:32 +02:00
VmRefObj * pRef ;
sxu32 n ;
/* Check if the referenced object already exists */
2018-07-12 17:24:46 +02:00
pRef = VmRefObjExtract ( & ( * pVm ) , nIdx ) ;
if ( pRef = = 0 ) {
2018-07-12 13:26:32 +02:00
/* Not such entry */
return SXERR_NOTFOUND ;
}
/* Remove the desired entry */
2018-07-12 17:24:46 +02:00
if ( pEntry ) {
2018-07-12 13:26:32 +02:00
SyHashEntry * * apEntry ;
apEntry = ( SyHashEntry * * ) SySetBasePtr ( & pRef - > aReference ) ;
2018-07-12 17:24:46 +02:00
for ( n = 0 ; n < SySetUsed ( & pRef - > aReference ) ; n + + ) {
if ( apEntry [ n ] = = pEntry ) {
2018-07-12 13:26:32 +02:00
/* Nullify the entry */
apEntry [ n ] = 0 ;
/*
* NOTE :
* In future releases , think to add a free pool of entries , so that
2018-07-12 17:24:46 +02:00
* we avoid wasting spaces .
2018-07-12 13:26:32 +02:00
*/
}
}
}
2018-07-12 17:24:46 +02:00
if ( pMapEntry ) {
2018-07-12 13:26:32 +02:00
ph7_hashmap_node * * apNode ;
apNode = ( ph7_hashmap_node * * ) SySetBasePtr ( & pRef - > aArrEntries ) ;
2018-07-12 17:24:46 +02:00
for ( n = 0 ; n < SySetUsed ( & pRef - > aArrEntries ) ; n + + ) {
if ( apNode [ n ] = = pMapEntry ) {
2018-07-12 13:26:32 +02:00
/* nullify the entry */
apNode [ n ] = 0 ;
}
}
}
return SXRET_OK ;
}
/*
* Extract the IO stream device associated with a given scheme .
* Return a pointer to an instance of ph7_io_stream when the scheme
* have an associated IO stream registered with it . NULL otherwise .
2018-07-23 17:10:48 +02:00
* If no scheme : // is available then the file:// scheme is assumed.
2018-07-12 13:26:32 +02:00
* For more information on how to register IO stream devices , please
* refer to the official documentation .
*/
2018-07-12 17:24:46 +02:00
PH7_PRIVATE const ph7_io_stream * PH7_VmGetStreamDevice (
2018-07-12 13:26:32 +02:00
ph7_vm * pVm , /* Target VM */
const char * * pzDevice , /* Full path,URI,... */
int nByte /* *pzDevice length*/
2018-07-12 17:24:46 +02:00
) {
const char * zIn , * zEnd , * zCur , * zNext ;
ph7_io_stream * * apStream , * pStream ;
SyString sDev , sCur ;
sxu32 n , nEntry ;
2018-07-12 13:26:32 +02:00
int rc ;
/* Check if a scheme [i.e: file://,http://,zip://...] is available */
zNext = zCur = zIn = * pzDevice ;
zEnd = & zIn [ nByte ] ;
2018-07-12 17:24:46 +02:00
while ( zIn < zEnd ) {
if ( zIn < & zEnd [ - 3 ] /*://*/ & & zIn [ 0 ] = = ' : ' & & zIn [ 1 ] = = ' / ' & & zIn [ 2 ] = = ' / ' ) {
2018-07-12 13:26:32 +02:00
/* Got one */
2018-07-12 17:24:46 +02:00
zNext = & zIn [ sizeof ( " :// " ) - 1 ] ;
2018-07-12 13:26:32 +02:00
break ;
}
/* Advance the cursor */
zIn + + ;
}
2018-07-12 17:24:46 +02:00
if ( zIn > = zEnd ) {
2018-07-12 13:26:32 +02:00
/* No such scheme,return the default stream */
return pVm - > pDefStream ;
}
2018-07-12 17:24:46 +02:00
SyStringInitFromBuf ( & sDev , zCur , zIn - zCur ) ;
2018-07-12 13:26:32 +02:00
/* Remove leading and trailing white spaces */
SyStringFullTrim ( & sDev ) ;
/* Perform a linear lookup on the installed stream devices */
apStream = ( ph7_io_stream * * ) SySetBasePtr ( & pVm - > aIOstream ) ;
nEntry = SySetUsed ( & pVm - > aIOstream ) ;
2018-07-12 17:24:46 +02:00
for ( n = 0 ; n < nEntry ; n + + ) {
2018-07-12 13:26:32 +02:00
pStream = apStream [ n ] ;
2018-07-12 17:24:46 +02:00
SyStringInitFromBuf ( & sCur , pStream - > zName , SyStrlen ( pStream - > zName ) ) ;
2018-07-12 13:26:32 +02:00
/* Perfrom a case-insensitive comparison */
2018-07-12 17:24:46 +02:00
rc = SyStringCmp ( & sDev , & sCur , SyStrnicmp ) ;
if ( rc = = 0 ) {
2018-07-12 13:26:32 +02:00
/* Stream device found */
* pzDevice = zNext ;
return pStream ;
}
}
/* No such stream,return NULL */
return 0 ;
}
/*
* Section :
* HTTP / URI related routines .
* Authors :
* Symisc Systems , devel @ symisc . net .
2019-05-15 20:02:39 +02:00
* Copyright ( C ) Symisc Systems , https : //ph7.symisc.net
2018-07-12 13:26:32 +02:00
* Status :
* Stable .
2018-07-12 17:24:46 +02:00
*/
/*
* URI Parser : Split an URI into components [ i . e : Host , Path , Query , . . . ] .
* URI syntax : [ method : / ] [ / [ user [ : pwd ] @ ] host [ : port ] / ] [ document ]
* This almost , but not quite , RFC1738 URI syntax .
* This routine is not a validator , it does not check for validity
* nor decode URI parts , the only thing this routine does is splitting
* the input to its fields .
* Upper layer are responsible of decoding and validating URI parts .
* On success , this function populate the " SyhttpUri " structure passed
* as the first argument . Otherwise SXERR_ * is returned when a malformed
* input is encountered .
*/
static sxi32 VmHttpSplitURI ( SyhttpUri * pOut , const char * zUri , sxu32 nLen ) {
const char * zEnd = & zUri [ nLen ] ;
sxu8 bHostOnly = FALSE ;
sxu8 bIPv6 = FALSE ;
const char * zCur ;
SyString * pComp ;
sxu32 nPos = 0 ;
sxi32 rc ;
/* Zero the structure first */
SyZero ( pOut , sizeof ( SyhttpUri ) ) ;
/* Remove leading and trailing white spaces */
SyStringInitFromBuf ( & pOut - > sRaw , zUri , nLen ) ;
SyStringFullTrim ( & pOut - > sRaw ) ;
/* Find the first '/' separator */
rc = SyByteFind ( zUri , ( sxu32 ) ( zEnd - zUri ) , ' / ' , & nPos ) ;
if ( rc ! = SXRET_OK ) {
/* Assume a host name only */
zCur = zEnd ;
bHostOnly = TRUE ;
goto ProcessHost ;
}
zCur = & zUri [ nPos ] ;
if ( zUri ! = zCur & & zCur [ - 1 ] = = ' : ' ) {
/* Extract a scheme:
* Not that we can get an invalid scheme here .
* Fortunately the caller can discard any URI by comparing this scheme with its
* registered schemes and will report the error as soon as his comparison function
* fail .
*/
pComp = & pOut - > sScheme ;
SyStringInitFromBuf ( pComp , zUri , ( sxu32 ) ( zCur - zUri - 1 ) ) ;
SyStringLeftTrim ( pComp ) ;
}
if ( zCur [ 1 ] ! = ' / ' ) {
if ( zCur = = zUri | | zCur [ - 1 ] = = ' : ' ) {
/* No authority */
goto PathSplit ;
}
/* There is something here , we will assume its an authority
* and someone has forgot the two prefix slashes " // " ,
* sooner or later we will detect if we are dealing with a malicious
* user or not , but now assume we are dealing with an authority
* and let the caller handle all the validation process .
*/
goto ProcessHost ;
}
zUri = & zCur [ 2 ] ;
zCur = zEnd ;
rc = SyByteFind ( zUri , ( sxu32 ) ( zEnd - zUri ) , ' / ' , & nPos ) ;
if ( rc = = SXRET_OK ) {
zCur = & zUri [ nPos ] ;
}
ProcessHost :
/* Extract user information if present */
rc = SyByteFind ( zUri , ( sxu32 ) ( zCur - zUri ) , ' @ ' , & nPos ) ;
if ( rc = = SXRET_OK ) {
if ( nPos > 0 ) {
sxu32 nPassOfft ; /* Password offset */
pComp = & pOut - > sUser ;
SyStringInitFromBuf ( pComp , zUri , nPos ) ;
/* Extract the password if available */
rc = SyByteFind ( zUri , ( sxu32 ) ( zCur - zUri ) , ' : ' , & nPassOfft ) ;
if ( rc = = SXRET_OK & & nPassOfft < nPos ) {
pComp - > nByte = nPassOfft ;
pComp = & pOut - > sPass ;
pComp - > zString = & zUri [ nPassOfft + sizeof ( char ) ] ;
pComp - > nByte = nPos - nPassOfft - 1 ;
}
/* Update the cursor */
zUri = & zUri [ nPos + 1 ] ;
} else {
zUri + + ;
}
}
pComp = & pOut - > sHost ;
while ( zUri < zCur & & SyisSpace ( zUri [ 0 ] ) ) {
zUri + + ;
}
SyStringInitFromBuf ( pComp , zUri , ( sxu32 ) ( zCur - zUri ) ) ;
if ( pComp - > zString [ 0 ] = = ' [ ' ) {
/* An IPv6 Address: Make a simple naive test
*/
zUri + + ;
pComp - > zString + + ;
pComp - > nByte = 0 ;
while ( ( ( unsigned char ) zUri [ 0 ] < 0xc0 & & SyisHex ( zUri [ 0 ] ) ) | | zUri [ 0 ] = = ' : ' ) {
zUri + + ;
pComp - > nByte + + ;
}
if ( zUri [ 0 ] ! = ' ] ' ) {
return SXERR_CORRUPT ; /* Malformed IPv6 address */
}
zUri + + ;
bIPv6 = TRUE ;
}
/* Extract a port number if available */
rc = SyByteFind ( zUri , ( sxu32 ) ( zCur - zUri ) , ' : ' , & nPos ) ;
if ( rc = = SXRET_OK ) {
if ( bIPv6 = = FALSE ) {
pComp - > nByte = ( sxu32 ) ( & zUri [ nPos ] - zUri ) ;
}
pComp = & pOut - > sPort ;
SyStringInitFromBuf ( pComp , & zUri [ nPos + 1 ] , ( sxu32 ) ( zCur - & zUri [ nPos + 1 ] ) ) ;
}
if ( bHostOnly = = TRUE ) {
return SXRET_OK ;
}
2018-07-12 13:26:32 +02:00
PathSplit :
2018-07-12 17:24:46 +02:00
zUri = zCur ;
pComp = & pOut - > sPath ;
SyStringInitFromBuf ( pComp , zUri , ( sxu32 ) ( zEnd - zUri ) ) ;
if ( pComp - > nByte = = 0 ) {
return SXRET_OK ; /* Empty path */
}
if ( SXRET_OK = = SyByteFind ( zUri , ( sxu32 ) ( zEnd - zUri ) , ' ? ' , & nPos ) ) {
pComp - > nByte = nPos ; /* Update path length */
pComp = & pOut - > sQuery ;
SyStringInitFromBuf ( pComp , & zUri [ nPos + 1 ] , ( sxu32 ) ( zEnd - & zUri [ nPos + 1 ] ) ) ;
}
if ( SXRET_OK = = SyByteFind ( zUri , ( sxu32 ) ( zEnd - zUri ) , ' # ' , & nPos ) ) {
/* Update path or query length */
if ( pComp = = & pOut - > sPath ) {
pComp - > nByte = nPos ;
} else {
if ( & zUri [ nPos ] < ( char * ) SyStringData ( pComp ) ) {
/* Malformed syntax : Query must be present before fragment */
return SXERR_SYNTAX ;
}
pComp - > nByte - = ( sxu32 ) ( zEnd - & zUri [ nPos ] ) ;
}
pComp = & pOut - > sFragment ;
SyStringInitFromBuf ( pComp , & zUri [ nPos + 1 ] , ( sxu32 ) ( zEnd - & zUri [ nPos + 1 ] ) )
}
return SXRET_OK ;
}
/*
* Extract a single line from a raw HTTP request .
* Return SXRET_OK on success , SXERR_EOF when end of input
* and SXERR_MORE when more input is needed .
*/
static sxi32 VmGetNextLine ( SyString * pCursor , SyString * pCurrent ) {
const char * zIn ;
sxu32 nPos ;
2018-07-12 13:26:32 +02:00
/* Jump leading white spaces */
SyStringLeftTrim ( pCursor ) ;
2018-07-12 17:24:46 +02:00
if ( pCursor - > nByte < 1 ) {
SyStringInitFromBuf ( pCurrent , 0 , 0 ) ;
2018-07-12 13:26:32 +02:00
return SXERR_EOF ; /* End of input */
}
zIn = SyStringData ( pCursor ) ;
2018-07-12 17:24:46 +02:00
if ( SXRET_OK ! = SyByteListFind ( pCursor - > zString , pCursor - > nByte , " \r \n " , & nPos ) ) {
2018-07-12 13:26:32 +02:00
/* Line not found,tell the caller to read more input from source */
2018-07-12 17:24:46 +02:00
SyStringDupPtr ( pCurrent , pCursor ) ;
2018-07-12 13:26:32 +02:00
return SXERR_MORE ;
}
2018-07-12 17:24:46 +02:00
pCurrent - > zString = zIn ;
pCurrent - > nByte = nPos ;
/* advance the cursor so we can call this routine again */
pCursor - > zString = & zIn [ nPos ] ;
pCursor - > nByte - = nPos ;
return SXRET_OK ;
}
/*
* Split a single MIME header into a name value pair .
* This function return SXRET_OK , SXERR_CONTINUE on success .
* Otherwise SXERR_NEXT is returned when a malformed header
* is encountered .
* Note : This function handle also mult - line headers .
*/
static sxi32 VmHttpProcessOneHeader ( SyhttpHeader * pHdr , SyhttpHeader * pLast , const char * zLine , sxu32 nLen ) {
SyString * pName ;
sxu32 nPos ;
sxi32 rc ;
if ( nLen < 1 ) {
return SXERR_NEXT ;
}
/* Check for multi-line header */
if ( pLast & & ( zLine [ - 1 ] = = ' ' | | zLine [ - 1 ] = = ' \t ' ) ) {
2018-07-12 13:26:32 +02:00
SyString * pTmp = & pLast - > sValue ;
SyStringFullTrim ( pTmp ) ;
2018-07-12 17:24:46 +02:00
if ( pTmp - > nByte = = 0 ) {
SyStringInitFromBuf ( pTmp , zLine , nLen ) ;
} else {
2018-07-12 13:26:32 +02:00
/* Update header value length */
pTmp - > nByte = ( sxu32 ) ( & zLine [ nLen ] - pTmp - > zString ) ;
}
2018-07-12 17:24:46 +02:00
/* Simply tell the caller to reset its states and get another line */
return SXERR_CONTINUE ;
}
2018-07-12 13:26:32 +02:00
/* Split the header */
pName = & pHdr - > sName ;
2018-07-12 17:24:46 +02:00
rc = SyByteFind ( zLine , nLen , ' : ' , & nPos ) ;
if ( rc ! = SXRET_OK ) {
2018-07-12 13:26:32 +02:00
return SXERR_NEXT ; /* Malformed header;Check the next entry */
}
2018-07-12 17:24:46 +02:00
SyStringInitFromBuf ( pName , zLine , nPos ) ;
2018-07-12 13:26:32 +02:00
SyStringFullTrim ( pName ) ;
/* Extract a header value */
2018-07-12 17:24:46 +02:00
SyStringInitFromBuf ( & pHdr - > sValue , & zLine [ nPos + 1 ] , nLen - nPos - 1 ) ;
2018-07-12 13:26:32 +02:00
/* Remove leading and trailing whitespaces */
SyStringFullTrim ( & pHdr - > sValue ) ;
return SXRET_OK ;
2018-07-12 17:24:46 +02:00
}
/*
* Extract all MIME headers associated with a HTTP request .
* After processing the first line of a HTTP request , the following
* routine is called in order to extract MIME headers .
* This function return SXRET_OK on success , SXERR_MORE when it needs
* more inputs .
* Note : Any malformed header is simply discarded .
*/
static sxi32 VmHttpExtractHeaders ( SyString * pRequest , SySet * pOut ) {
SyhttpHeader * pLast = 0 ;
SyString sCurrent ;
SyhttpHeader sHdr ;
sxu8 bEol ;
sxi32 rc ;
if ( SySetUsed ( pOut ) > 0 ) {
pLast = ( SyhttpHeader * ) SySetAt ( pOut , SySetUsed ( pOut ) - 1 ) ;
}
bEol = FALSE ;
for ( ; ; ) {
SyZero ( & sHdr , sizeof ( SyhttpHeader ) ) ;
/* Extract a single line from the raw HTTP request */
rc = VmGetNextLine ( pRequest , & sCurrent ) ;
if ( rc ! = SXRET_OK ) {
if ( sCurrent . nByte < 1 ) {
break ;
}
bEol = TRUE ;
}
/* Process the header */
if ( SXRET_OK = = VmHttpProcessOneHeader ( & sHdr , pLast , sCurrent . zString , sCurrent . nByte ) ) {
if ( SXRET_OK ! = SySetPut ( pOut , ( const void * ) & sHdr ) ) {
break ;
}
/* Retrieve the last parsed header so we can handle multi-line header
* in case we face one of them .
*/
pLast = ( SyhttpHeader * ) SySetPeek ( pOut ) ;
}
if ( bEol ) {
break ;
}
} /* for(;;) */
return SXRET_OK ;
}
/*
* Process the first line of a HTTP request .
* This routine perform the following operations
* 1 ) Extract the HTTP method .
* 2 ) Split the request URI to it ' s fields [ ie : host , path , query , . . . ] .
* 3 ) Extract the HTTP protocol version .
*/
static sxi32 VmHttpProcessFirstLine (
SyString * pRequest , /* Raw HTTP request */
sxi32 * pMethod , /* OUT: HTTP method */
SyhttpUri * pUri , /* OUT: Parse of the URI */
sxi32 * pProto /* OUT: HTTP protocol */
) {
static const char * azMethods [ ] = { " get " , " post " , " head " , " put " } ;
static const sxi32 aMethods [ ] = { HTTP_METHOD_GET , HTTP_METHOD_POST , HTTP_METHOD_HEAD , HTTP_METHOD_PUT } ;
const char * zIn , * zEnd , * zPtr ;
SyString sLine ;
sxu32 nLen ;
sxi32 rc ;
/* Extract the first line and update the pointer */
rc = VmGetNextLine ( pRequest , & sLine ) ;
if ( rc ! = SXRET_OK ) {
return rc ;
}
if ( sLine . nByte < 1 ) {
/* Empty HTTP request */
return SXERR_EMPTY ;
}
/* Delimit the line and ignore trailing and leading white spaces */
zIn = sLine . zString ;
zEnd = & zIn [ sLine . nByte ] ;
while ( zIn < zEnd & & ( unsigned char ) zIn [ 0 ] < 0xc0 & & SyisSpace ( zIn [ 0 ] ) ) {
zIn + + ;
}
/* Extract the HTTP method */
zPtr = zIn ;
while ( zIn < zEnd & & ! SyisSpace ( zIn [ 0 ] ) ) {
zIn + + ;
}
2019-05-15 19:45:39 +02:00
* pMethod = HTTP_METHOD_OTHER ;
2018-07-12 17:24:46 +02:00
if ( zIn > zPtr ) {
sxu32 i ;
nLen = ( sxu32 ) ( zIn - zPtr ) ;
for ( i = 0 ; i < SX_ARRAYSIZE ( azMethods ) ; + + i ) {
if ( SyStrnicmp ( azMethods [ i ] , zPtr , nLen ) = = 0 ) {
* pMethod = aMethods [ i ] ;
break ;
}
}
}
/* Jump trailing white spaces */
while ( zIn < zEnd & & ( unsigned char ) zIn [ 0 ] < 0xc0 & & SyisSpace ( zIn [ 0 ] ) ) {
zIn + + ;
}
/* Extract the request URI */
zPtr = zIn ;
while ( zIn < zEnd & & ! SyisSpace ( zIn [ 0 ] ) ) {
zIn + + ;
}
if ( zIn > zPtr ) {
nLen = ( sxu32 ) ( zIn - zPtr ) ;
/* Split raw URI to it's fields */
VmHttpSplitURI ( pUri , zPtr , nLen ) ;
}
/* Jump trailing white spaces */
while ( zIn < zEnd & & ( unsigned char ) zIn [ 0 ] < 0xc0 & & SyisSpace ( zIn [ 0 ] ) ) {
zIn + + ;
}
/* Extract the HTTP version */
zPtr = zIn ;
while ( zIn < zEnd & & ! SyisSpace ( zIn [ 0 ] ) ) {
zIn + + ;
}
* pProto = HTTP_PROTO_11 ; /* HTTP/1.1 */
rc = 1 ;
if ( zIn > zPtr ) {
rc = SyStrnicmp ( zPtr , " http/1.0 " , ( sxu32 ) ( zIn - zPtr ) ) ;
}
if ( ! rc ) {
* pProto = HTTP_PROTO_10 ; /* HTTP/1.0 */
}
return SXRET_OK ;
}
/*
* Tokenize , decode and split a raw query encoded as : " x-www-form-urlencoded "
* into a name value pair .
* Note that this encoding is implicit in GET based requests .
* After the tokenization process , register the decoded queries
* in the $ _GET / $ _POST / $ _REQUEST superglobals arrays .
*/
static sxi32 VmHttpSplitEncodedQuery (
ph7_vm * pVm , /* Target VM */
SyString * pQuery , /* Raw query to decode */
SyBlob * pWorker , /* Working buffer */
int is_post /* TRUE if we are dealing with a POST request */
) {
const char * zEnd = & pQuery - > zString [ pQuery - > nByte ] ;
const char * zIn = pQuery - > zString ;
ph7_value * pGet , * pRequest ;
SyString sName , sValue ;
const char * zPtr ;
sxu32 nBlobOfft ;
/* Extract superglobals */
if ( is_post ) {
/* $_POST superglobal */
pGet = VmExtractSuper ( & ( * pVm ) , " _POST " , sizeof ( " _POST " ) - 1 ) ;
} else {
/* $_GET superglobal */
pGet = VmExtractSuper ( & ( * pVm ) , " _GET " , sizeof ( " _GET " ) - 1 ) ;
}
pRequest = VmExtractSuper ( & ( * pVm ) , " _REQUEST " , sizeof ( " _REQUEST " ) - 1 ) ;
/* Split up the raw query */
for ( ; ; ) {
/* Jump leading white spaces */
while ( zIn < zEnd & & SyisSpace ( zIn [ 0 ] ) ) {
zIn + + ;
}
if ( zIn > = zEnd ) {
break ;
}
zPtr = zIn ;
while ( zPtr < zEnd & & zPtr [ 0 ] ! = ' = ' & & zPtr [ 0 ] ! = ' & ' & & zPtr [ 0 ] ! = ' ; ' ) {
zPtr + + ;
}
/* Reset the working buffer */
SyBlobReset ( pWorker ) ;
/* Decode the entry */
SyUriDecode ( zIn , ( sxu32 ) ( zPtr - zIn ) , PH7_VmBlobConsumer , pWorker , TRUE ) ;
/* Save the entry */
sName . nByte = SyBlobLength ( pWorker ) ;
sValue . zString = 0 ;
sValue . nByte = 0 ;
if ( zPtr < zEnd & & zPtr [ 0 ] = = ' = ' ) {
zPtr + + ;
zIn = zPtr ;
/* Store field value */
while ( zPtr < zEnd & & zPtr [ 0 ] ! = ' & ' & & zPtr [ 0 ] ! = ' ; ' ) {
zPtr + + ;
}
if ( zPtr > zIn ) {
/* Decode the value */
nBlobOfft = SyBlobLength ( pWorker ) ;
SyUriDecode ( zIn , ( sxu32 ) ( zPtr - zIn ) , PH7_VmBlobConsumer , pWorker , TRUE ) ;
sValue . zString = ( const char * ) SyBlobDataAt ( pWorker , nBlobOfft ) ;
sValue . nByte = SyBlobLength ( pWorker ) - nBlobOfft ;
}
/* Synchronize pointers */
zIn = zPtr ;
}
sName . zString = ( const char * ) SyBlobData ( pWorker ) ;
/* Install the decoded query in the $_GET/$_REQUEST array */
2019-05-21 14:49:36 +02:00
if ( pGet & & ( pGet - > nType & MEMOBJ_HASHMAP ) ) {
2018-07-12 17:24:46 +02:00
VmHashmapInsert ( ( ph7_hashmap * ) pGet - > x . pOther ,
sName . zString , ( int ) sName . nByte ,
sValue . zString , ( int ) sValue . nByte
) ;
}
2019-05-21 14:49:36 +02:00
if ( pRequest & & ( pRequest - > nType & MEMOBJ_HASHMAP ) ) {
2018-07-12 17:24:46 +02:00
VmHashmapInsert ( ( ph7_hashmap * ) pRequest - > x . pOther ,
sName . zString , ( int ) sName . nByte ,
sValue . zString , ( int ) sValue . nByte
) ;
}
/* Advance the pointer */
zIn = & zPtr [ 1 ] ;
}
2018-07-12 13:26:32 +02:00
/* All done*/
return SXRET_OK ;
2018-07-12 17:24:46 +02:00
}
/*
* Extract MIME header value from the given set .
* Return header value on success . NULL otherwise .
*/
static SyString * VmHttpExtractHeaderValue ( SySet * pSet , const char * zMime , sxu32 nByte ) {
SyhttpHeader * aMime , * pMime ;
SyString sMime ;
sxu32 n ;
SyStringInitFromBuf ( & sMime , zMime , nByte ) ;
/* Point to the MIME entries */
aMime = ( SyhttpHeader * ) SySetBasePtr ( pSet ) ;
/* Perform the lookup */
for ( n = 0 ; n < SySetUsed ( pSet ) ; + + n ) {
pMime = & aMime [ n ] ;
if ( SyStringCmp ( & sMime , & pMime - > sName , SyStrnicmp ) = = 0 ) {
/* Header found,return it's associated value */
return & pMime - > sValue ;
}
}
/* No such MIME header */
return 0 ;
}
/*
* Tokenize and decode a raw " Cookie: " MIME header into a name value pair
* and insert it ' s fields [ i . e name , value ] in the $ _COOKIE superglobal .
*/
2018-07-23 17:10:48 +02:00
static sxi32 VmHttpProcessCookie ( ph7_vm * pVm , SyBlob * pWorker , const char * zIn , sxu32 nByte ) {
2018-07-12 17:24:46 +02:00
const char * zPtr , * zDelimiter , * zEnd = & zIn [ nByte ] ;
SyString sName , sValue ;
ph7_value * pCookie ;
sxu32 nOfft ;
/* Make sure the $_COOKIE superglobal is available */
pCookie = VmExtractSuper ( & ( * pVm ) , " _COOKIE " , sizeof ( " _COOKIE " ) - 1 ) ;
2019-05-21 14:49:36 +02:00
if ( pCookie = = 0 | | ( pCookie - > nType & MEMOBJ_HASHMAP ) = = 0 ) {
2018-07-12 17:24:46 +02:00
/* $_COOKIE superglobal not available */
return SXERR_NOTFOUND ;
}
for ( ; ; ) {
/* Jump leading white spaces */
while ( zIn < zEnd & & SyisSpace ( zIn [ 0 ] ) ) {
zIn + + ;
}
if ( zIn > = zEnd ) {
break ;
}
/* Reset the working buffer */
SyBlobReset ( pWorker ) ;
zDelimiter = zIn ;
/* Delimit the name[=value]; pair */
while ( zDelimiter < zEnd & & zDelimiter [ 0 ] ! = ' ; ' ) {
zDelimiter + + ;
}
zPtr = zIn ;
while ( zPtr < zDelimiter & & zPtr [ 0 ] ! = ' = ' ) {
zPtr + + ;
}
/* Decode the cookie */
SyUriDecode ( zIn , ( sxu32 ) ( zPtr - zIn ) , PH7_VmBlobConsumer , pWorker , TRUE ) ;
sName . nByte = SyBlobLength ( pWorker ) ;
zPtr + + ;
sValue . zString = 0 ;
sValue . nByte = 0 ;
if ( zPtr < zDelimiter ) {
/* Got a Cookie value */
nOfft = SyBlobLength ( pWorker ) ;
SyUriDecode ( zPtr , ( sxu32 ) ( zDelimiter - zPtr ) , PH7_VmBlobConsumer , pWorker , TRUE ) ;
SyStringInitFromBuf ( & sValue , SyBlobDataAt ( pWorker , nOfft ) , SyBlobLength ( pWorker ) - nOfft ) ;
}
/* Synchronize pointers */
zIn = & zDelimiter [ 1 ] ;
/* Perform the insertion */
sName . zString = ( const char * ) SyBlobData ( pWorker ) ;
VmHashmapInsert ( ( ph7_hashmap * ) pCookie - > x . pOther ,
sName . zString , ( int ) sName . nByte ,
sValue . zString , ( int ) sValue . nByte
) ;
}
return SXRET_OK ;
}
/*
* Process a full HTTP request and populate the appropriate arrays
* such as $ _SERVER , $ _GET , $ _POST , $ _COOKIE , $ _REQUEST , . . . with the information
* extracted from the raw HTTP request . As an extension Symisc introduced
* the $ _HEADER array which hold a copy of the processed HTTP MIME headers
* and their associated values . [ i . e : $ _HEADER [ ' Server ' ] , $ _HEADER [ ' User - Agent ' ] , . . . ] .
* This function return SXRET_OK on success . Any other return value indicates
* a malformed HTTP request .
*/
static sxi32 VmHttpProcessRequest ( ph7_vm * pVm , const char * zRequest , int nByte ) {
SyString * pName , * pValue , sRequest ; /* Raw HTTP request */
ph7_value * pHeaderArray ; /* $_HEADER superglobal (Symisc eXtension to the PHP specification)*/
SyhttpHeader * pHeader ; /* MIME header */
SyhttpUri sUri ; /* Parse of the raw URI*/
SyBlob sWorker ; /* General purpose working buffer */
SySet sHeader ; /* MIME headers set */
sxi32 iMethod ; /* HTTP method [i.e: GET,POST,HEAD...]*/
sxi32 iVer ; /* HTTP protocol version */
sxi32 rc ;
SyStringInitFromBuf ( & sRequest , zRequest , nByte ) ;
SySetInit ( & sHeader , & pVm - > sAllocator , sizeof ( SyhttpHeader ) ) ;
SyBlobInit ( & sWorker , & pVm - > sAllocator ) ;
2018-07-22 19:07:58 +02:00
/* Ignore leading and trailing white spaces */
2018-07-12 17:24:46 +02:00
SyStringFullTrim ( & sRequest ) ;
/* Process the first line */
rc = VmHttpProcessFirstLine ( & sRequest , & iMethod , & sUri , & iVer ) ;
if ( rc ! = SXRET_OK ) {
return rc ;
}
/* Process MIME headers */
VmHttpExtractHeaders ( & sRequest , & sHeader ) ;
/*
* Setup $ _SERVER environments
*/
/* 'SERVER_PROTOCOL': Name and revision of the information protocol via which the page was requested */
ph7_vm_config ( pVm ,
PH7_VM_CONFIG_SERVER_ATTR ,
" SERVER_PROTOCOL " ,
iVer = = HTTP_PROTO_10 ? " HTTP/1.0 " : " HTTP/1.1 " ,
sizeof ( " HTTP/1.1 " ) - 1
) ;
/* 'REQUEST_METHOD': Which request method was used to access the page */
ph7_vm_config ( pVm ,
PH7_VM_CONFIG_SERVER_ATTR ,
" REQUEST_METHOD " ,
iMethod = = HTTP_METHOD_GET ? " GET " :
( iMethod = = HTTP_METHOD_POST ? " POST " :
( iMethod = = HTTP_METHOD_PUT ? " PUT " :
( iMethod = = HTTP_METHOD_HEAD ? " HEAD " : " OTHER " ) ) ) ,
- 1 /* Compute attribute length automatically */
) ;
if ( SyStringLength ( & sUri . sQuery ) > 0 & & iMethod = = HTTP_METHOD_GET ) {
pValue = & sUri . sQuery ;
/* 'QUERY_STRING': The query string, if any, via which the page was accessed */
ph7_vm_config ( pVm ,
PH7_VM_CONFIG_SERVER_ATTR ,
" QUERY_STRING " ,
pValue - > zString ,
pValue - > nByte
) ;
/* Decoded the raw query */
VmHttpSplitEncodedQuery ( & ( * pVm ) , pValue , & sWorker , FALSE ) ;
}
/* REQUEST_URI: The URI which was given in order to access this page; for instance, '/index.html' */
pValue = & sUri . sRaw ;
ph7_vm_config ( pVm ,
PH7_VM_CONFIG_SERVER_ATTR ,
" REQUEST_URI " ,
pValue - > zString ,
pValue - > nByte
2018-07-12 13:26:32 +02:00
) ;
2018-07-12 17:24:46 +02:00
/*
* ' PATH_INFO '
* ' ORIG_PATH_INFO '
* Contains any client - provided pathname information trailing the actual script filename but preceding
* the query string , if available . For instance , if the current script was accessed via the URL
2019-05-15 20:02:39 +02:00
* https : //www.example.com/php/path_info.php/some/stuff?foo=bar, then $_SERVER['PATH_INFO'] would contain
2018-07-12 17:24:46 +02:00
* / some / stuff .
*/
pValue = & sUri . sPath ;
ph7_vm_config ( pVm ,
PH7_VM_CONFIG_SERVER_ATTR ,
" PATH_INFO " ,
pValue - > zString ,
pValue - > nByte
) ;
ph7_vm_config ( pVm ,
PH7_VM_CONFIG_SERVER_ATTR ,
" ORIG_PATH_INFO " ,
pValue - > zString ,
pValue - > nByte
) ;
/* 'HTTP_ACCEPT': Contents of the Accept: header from the current request, if there is one */
pValue = VmHttpExtractHeaderValue ( & sHeader , " Accept " , sizeof ( " Accept " ) - 1 ) ;
if ( pValue ) {
ph7_vm_config ( pVm ,
PH7_VM_CONFIG_SERVER_ATTR ,
" HTTP_ACCEPT " ,
pValue - > zString ,
pValue - > nByte
) ;
}
/* 'HTTP_ACCEPT_CHARSET': Contents of the Accept-Charset: header from the current request, if there is one. */
pValue = VmHttpExtractHeaderValue ( & sHeader , " Accept-Charset " , sizeof ( " Accept-Charset " ) - 1 ) ;
if ( pValue ) {
ph7_vm_config ( pVm ,
PH7_VM_CONFIG_SERVER_ATTR ,
" HTTP_ACCEPT_CHARSET " ,
pValue - > zString ,
pValue - > nByte
) ;
}
/* 'HTTP_ACCEPT_ENCODING': Contents of the Accept-Encoding: header from the current request, if there is one. */
pValue = VmHttpExtractHeaderValue ( & sHeader , " Accept-Encoding " , sizeof ( " Accept-Encoding " ) - 1 ) ;
if ( pValue ) {
ph7_vm_config ( pVm ,
PH7_VM_CONFIG_SERVER_ATTR ,
" HTTP_ACCEPT_ENCODING " ,
pValue - > zString ,
pValue - > nByte
) ;
}
/* 'HTTP_ACCEPT_LANGUAGE': Contents of the Accept-Language: header from the current request, if there is one */
pValue = VmHttpExtractHeaderValue ( & sHeader , " Accept-Language " , sizeof ( " Accept-Language " ) - 1 ) ;
if ( pValue ) {
ph7_vm_config ( pVm ,
PH7_VM_CONFIG_SERVER_ATTR ,
" HTTP_ACCEPT_LANGUAGE " ,
pValue - > zString ,
pValue - > nByte
) ;
}
/* 'HTTP_CONNECTION': Contents of the Connection: header from the current request, if there is one. */
pValue = VmHttpExtractHeaderValue ( & sHeader , " Connection " , sizeof ( " Connection " ) - 1 ) ;
if ( pValue ) {
ph7_vm_config ( pVm ,
PH7_VM_CONFIG_SERVER_ATTR ,
" HTTP_CONNECTION " ,
pValue - > zString ,
pValue - > nByte
) ;
}
/* 'HTTP_HOST': Contents of the Host: header from the current request, if there is one. */
pValue = VmHttpExtractHeaderValue ( & sHeader , " Host " , sizeof ( " Host " ) - 1 ) ;
if ( pValue ) {
ph7_vm_config ( pVm ,
PH7_VM_CONFIG_SERVER_ATTR ,
" HTTP_HOST " ,
pValue - > zString ,
pValue - > nByte
) ;
}
/* 'HTTP_REFERER': Contents of the Referer: header from the current request, if there is one. */
pValue = VmHttpExtractHeaderValue ( & sHeader , " Referer " , sizeof ( " Referer " ) - 1 ) ;
if ( pValue ) {
ph7_vm_config ( pVm ,
PH7_VM_CONFIG_SERVER_ATTR ,
" HTTP_REFERER " ,
pValue - > zString ,
pValue - > nByte
) ;
}
/* 'HTTP_USER_AGENT': Contents of the Referer: header from the current request, if there is one. */
pValue = VmHttpExtractHeaderValue ( & sHeader , " User-Agent " , sizeof ( " User-Agent " ) - 1 ) ;
if ( pValue ) {
ph7_vm_config ( pVm ,
PH7_VM_CONFIG_SERVER_ATTR ,
" HTTP_USER_AGENT " ,
pValue - > zString ,
pValue - > nByte
) ;
}
/* 'PHP_AUTH_DIGEST': When doing Digest HTTP authentication this variable is set to the 'Authorization'
* header sent by the client ( which you should then use to make the appropriate validation ) .
*/
pValue = VmHttpExtractHeaderValue ( & sHeader , " Authorization " , sizeof ( " Authorization " ) - 1 ) ;
if ( pValue ) {
ph7_vm_config ( pVm ,
PH7_VM_CONFIG_SERVER_ATTR ,
" PHP_AUTH_DIGEST " ,
pValue - > zString ,
pValue - > nByte
) ;
ph7_vm_config ( pVm ,
PH7_VM_CONFIG_SERVER_ATTR ,
" PHP_AUTH " ,
pValue - > zString ,
pValue - > nByte
) ;
}
/* Install all clients HTTP headers in the $_HEADER superglobal */
pHeaderArray = VmExtractSuper ( & ( * pVm ) , " _HEADER " , sizeof ( " _HEADER " ) - 1 ) ;
/* Iterate throw the available MIME headers*/
SySetResetCursor ( & sHeader ) ;
pHeader = 0 ; /* stupid cc warning */
while ( SXRET_OK = = SySetGetNextEntry ( & sHeader , ( void * * ) & pHeader ) ) {
pName = & pHeader - > sName ;
pValue = & pHeader - > sValue ;
2019-05-21 14:49:36 +02:00
if ( pHeaderArray & & ( pHeaderArray - > nType & MEMOBJ_HASHMAP ) ) {
2018-07-12 17:24:46 +02:00
/* Insert the MIME header and it's associated value */
VmHashmapInsert ( ( ph7_hashmap * ) pHeaderArray - > x . pOther ,
pName - > zString , ( int ) pName - > nByte ,
pValue - > zString , ( int ) pValue - > nByte
) ;
}
if ( pName - > nByte = = sizeof ( " Cookie " ) - 1 & & SyStrnicmp ( pName - > zString , " Cookie " , sizeof ( " Cookie " ) - 1 ) = = 0
& & pValue - > nByte > 0 ) {
/* Process the name=value pair and insert them in the $_COOKIE superglobal array */
2018-07-23 17:10:48 +02:00
VmHttpProcessCookie ( & ( * pVm ) , & sWorker , pValue - > zString , pValue - > nByte ) ;
2018-07-12 17:24:46 +02:00
}
}
if ( iMethod = = HTTP_METHOD_POST ) {
/* Extract raw POST data */
pValue = VmHttpExtractHeaderValue ( & sHeader , " Content-Type " , sizeof ( " Content-Type " ) - 1 ) ;
if ( pValue & & pValue - > nByte > = sizeof ( " application/x-www-form-urlencoded " ) - 1 & &
SyMemcmp ( " application/x-www-form-urlencoded " , pValue - > zString , pValue - > nByte ) = = 0 ) {
/* Extract POST data length */
pValue = VmHttpExtractHeaderValue ( & sHeader , " Content-Length " , sizeof ( " Content-Length " ) - 1 ) ;
if ( pValue ) {
sxi32 iLen = 0 ; /* POST data length */
SyStrToInt32 ( pValue - > zString , pValue - > nByte , ( void * ) & iLen , 0 ) ;
if ( iLen > 0 ) {
/* Remove leading and trailing white spaces */
SyStringFullTrim ( & sRequest ) ;
if ( ( int ) sRequest . nByte > iLen ) {
sRequest . nByte = ( sxu32 ) iLen ;
}
/* Decode POST data now */
VmHttpSplitEncodedQuery ( & ( * pVm ) , & sRequest , & sWorker , TRUE ) ;
}
}
}
}
/* All done,clean-up the mess left behind */
SySetRelease ( & sHeader ) ;
SyBlobRelease ( & sWorker ) ;
return SXRET_OK ;
}