Aer/engine/api.c
belliash eb79ed500e
All checks were successful
The build was successful.
Store float values in an union.
Single variable cannot have many values of different types. This also saves some memory, because union allocates memory just for one of its members.
2018-09-07 12:04:51 +02:00

1954 lines
61 KiB
C

/*
* Symisc PH7: An embeddable bytecode compiler and a virtual machine for the PHP(5) programming language.
* Copyright (C) 2011-2012, Symisc Systems http://ph7.symisc.net/
* Version 2.1.4
* For information on licensing,redistribution of this file,and for a DISCLAIMER OF ALL WARRANTIES
* please contact Symisc Systems via:
* legal@symisc.net
* licensing@symisc.net
* contact@symisc.net
* or visit:
* http://ph7.symisc.net/
*/
/* $SymiscID: api.c v2.0 FreeBSD 2012-08-18 06:54 stable <chm@symisc.net> $ */
#include "ph7int.h"
/* This file implement the public interfaces presented to host-applications.
* Routines in other files are for internal use by PH7 and should not be
* accessed by users of the library.
*/
#define PH7_ENGINE_MAGIC 0xF874BCD7
#define PH7_ENGINE_MISUSE(ENGINE) (ENGINE == 0 || ENGINE->nMagic != PH7_ENGINE_MAGIC)
#define PH7_VM_MISUSE(VM) (VM == 0 || VM->nMagic == PH7_VM_STALE)
/* If another thread have released a working instance,the following macros
* evaluates to true. These macros are only used when the library
* is built with threading support enabled which is not the case in
* the default built.
*/
#define PH7_THRD_ENGINE_RELEASE(ENGINE) (ENGINE->nMagic != PH7_ENGINE_MAGIC)
#define PH7_THRD_VM_RELEASE(VM) (VM->nMagic == PH7_VM_STALE)
/* IMPLEMENTATION: ph7@embedded@symisc 311-12-32 */
/*
* All global variables are collected in the structure named "sMPGlobal".
* That way it is clear in the code when we are using static variable because
* its name start with sMPGlobal.
*/
static struct Global_Data {
SyMemBackend sAllocator; /* Global low level memory allocator */
#if defined(PH7_ENABLE_THREADS)
const SyMutexMethods *pMutexMethods; /* Mutex methods */
SyMutex *pMutex; /* Global mutex */
sxu32 nThreadingLevel; /* Threading level: 0 == Single threaded/1 == Multi-Threaded
* The threading level can be set using the [ph7_lib_config()]
* interface with a configuration verb set to
* PH7_LIB_CONFIG_THREAD_LEVEL_SINGLE or
* PH7_LIB_CONFIG_THREAD_LEVEL_MULTI
*/
#endif
const ph7_vfs *pVfs; /* Underlying virtual file system */
sxi32 nEngine; /* Total number of active engines */
ph7 *pEngines; /* List of active engine */
sxu32 nMagic; /* Sanity check against library misuse */
} sMPGlobal = {
{0, 0, 0, 0, 0, 0, 0, 0, {0}},
#if defined(PH7_ENABLE_THREADS)
0,
0,
0,
#endif
0,
0,
0,
0
};
#define PH7_LIB_MAGIC 0xEA1495BA
/*
* Supported threading level.
* These options have meaning only when the library is compiled with multi-threading
* support.That is,the PH7_ENABLE_THREADS compile time directive must be defined
* when PH7 is built.
* PH7_THREAD_LEVEL_SINGLE:
* In this mode,mutexing is disabled and the library can only be used by a single thread.
* PH7_THREAD_LEVEL_MULTI
* In this mode, all mutexes including the recursive mutexes on [ph7] objects
* are enabled so that the application is free to share the same engine
* between different threads at the same time.
*/
#define PH7_THREAD_LEVEL_SINGLE 1
#define PH7_THREAD_LEVEL_MULTI 2
/*
* Configure a running PH7 engine instance.
* return PH7_OK on success.Any other return
* value indicates failure.
* Refer to [ph7_config()].
*/
static sxi32 EngineConfig(ph7 *pEngine, sxi32 nOp, va_list ap) {
ph7_conf *pConf = &pEngine->xConf;
int rc = PH7_OK;
/* Perform the requested operation */
switch(nOp) {
case PH7_CONFIG_ERR_OUTPUT: {
ProcConsumer xConsumer = va_arg(ap, ProcConsumer);
void *pUserData = va_arg(ap, void *);
/* Compile time error consumer routine */
if(xConsumer == 0) {
rc = PH7_CORRUPT;
break;
}
/* Install the error consumer */
pConf->xErr = xConsumer;
pConf->pErrData = pUserData;
break;
}
case PH7_CONFIG_ERR_LOG: {
/* Extract compile-time error log if any */
const char **pzPtr = va_arg(ap, const char **);
int *pLen = va_arg(ap, int *);
if(pzPtr == 0) {
rc = PH7_CORRUPT;
break;
}
/* NULL terminate the error-log buffer */
SyBlobNullAppend(&pConf->sErrConsumer);
/* Point to the error-log buffer */
*pzPtr = (const char *)SyBlobData(&pConf->sErrConsumer);
if(pLen) {
if(SyBlobLength(&pConf->sErrConsumer) > 1 /* NULL '\0' terminator */) {
*pLen = (int)SyBlobLength(&pConf->sErrConsumer);
} else {
*pLen = 0;
}
}
break;
}
case PH7_CONFIG_MEM_LIMIT: {
char *sMemLimit = va_arg(ap, char *);
if(!sMemLimit) {
break;
}
char *sLimitRem;
sxu64 nMemLimit;
SyStrToInt64(sMemLimit, SyStrlen(sMemLimit), (void *)&nMemLimit, &sLimitRem);
if(sLimitRem) {
switch(*sLimitRem) {
case 'G':
case 'g':
nMemLimit *= 1024;
case 'M':
case 'm':
nMemLimit *= 1024;
case 'K':
case 'k':
nMemLimit *= 1024;
}
}
if(nMemLimit >= 1048576) {
/* At least 1MB of heap */
pEngine->sAllocator.pHeap->nLimit = nMemLimit;
} else {
/* Fallback to no limit */
pEngine->sAllocator.pHeap->nLimit = 0;
}
break;
}
case PH7_CONFIG_ERR_ABORT:
/* Reserved for future use */
break;
default:
/* Unknown configuration verb */
rc = PH7_CORRUPT;
break;
} /* Switch() */
return rc;
}
/*
* Configure the PH7 library.
* return PH7_OK on success.Any other return value
* indicates failure.
* Refer to [ph7_lib_config()].
*/
static sxi32 PH7CoreConfigure(sxi32 nOp, va_list ap) {
int rc = PH7_OK;
switch(nOp) {
case PH7_LIB_CONFIG_VFS: {
/* Install a virtual file system */
const ph7_vfs *pVfs = va_arg(ap, const ph7_vfs *);
sMPGlobal.pVfs = pVfs;
break;
}
case PH7_LIB_CONFIG_USER_MALLOC: {
/* Use an alternative low-level memory allocation routines */
const SyMemMethods *pMethods = va_arg(ap, const SyMemMethods *);
/* Save the memory failure callback (if available) */
ProcMemError xMemErr = sMPGlobal.sAllocator.xMemError;
void *pMemErr = sMPGlobal.sAllocator.pUserData;
if(pMethods == 0) {
/* Use the built-in memory allocation subsystem */
rc = SyMemBackendInit(&sMPGlobal.sAllocator, xMemErr, pMemErr);
} else {
rc = SyMemBackendInitFromOthers(&sMPGlobal.sAllocator, pMethods, xMemErr, pMemErr);
}
break;
}
case PH7_LIB_CONFIG_MEM_ERR_CALLBACK: {
/* Memory failure callback */
ProcMemError xMemErr = va_arg(ap, ProcMemError);
void *pUserData = va_arg(ap, void *);
sMPGlobal.sAllocator.xMemError = xMemErr;
sMPGlobal.sAllocator.pUserData = pUserData;
break;
}
case PH7_LIB_CONFIG_USER_MUTEX: {
#if defined(PH7_ENABLE_THREADS)
/* Use an alternative low-level mutex subsystem */
const SyMutexMethods *pMethods = va_arg(ap, const SyMutexMethods *);
#if defined (UNTRUST)
if(pMethods == 0) {
rc = PH7_CORRUPT;
}
#endif
/* Sanity check */
if(pMethods->xEnter == 0 || pMethods->xLeave == 0 || pMethods->xNew == 0) {
/* At least three criticial callbacks xEnter(),xLeave() and xNew() must be supplied */
rc = PH7_CORRUPT;
break;
}
if(sMPGlobal.pMutexMethods) {
/* Overwrite the previous mutex subsystem */
SyMutexRelease(sMPGlobal.pMutexMethods, sMPGlobal.pMutex);
if(sMPGlobal.pMutexMethods->xGlobalRelease) {
sMPGlobal.pMutexMethods->xGlobalRelease();
}
sMPGlobal.pMutex = 0;
}
/* Initialize and install the new mutex subsystem */
if(pMethods->xGlobalInit) {
rc = pMethods->xGlobalInit();
if(rc != PH7_OK) {
break;
}
}
/* Create the global mutex */
sMPGlobal.pMutex = pMethods->xNew(SXMUTEX_TYPE_FAST);
if(sMPGlobal.pMutex == 0) {
/*
* If the supplied mutex subsystem is so sick that we are unable to
* create a single mutex,there is no much we can do here.
*/
if(pMethods->xGlobalRelease) {
pMethods->xGlobalRelease();
}
rc = PH7_CORRUPT;
break;
}
sMPGlobal.pMutexMethods = pMethods;
if(sMPGlobal.nThreadingLevel == 0) {
/* Set a default threading level */
sMPGlobal.nThreadingLevel = PH7_THREAD_LEVEL_MULTI;
}
#endif
break;
}
case PH7_LIB_CONFIG_THREAD_LEVEL_SINGLE:
#if defined(PH7_ENABLE_THREADS)
/* Single thread mode(Only one thread is allowed to play with the library) */
sMPGlobal.nThreadingLevel = PH7_THREAD_LEVEL_SINGLE;
#endif
break;
case PH7_LIB_CONFIG_THREAD_LEVEL_MULTI:
#if defined(PH7_ENABLE_THREADS)
/* Multi-threading mode (library is thread safe and PH7 engines and virtual machines
* may be shared between multiple threads).
*/
sMPGlobal.nThreadingLevel = PH7_THREAD_LEVEL_MULTI;
#endif
break;
default:
/* Unknown configuration option */
rc = PH7_CORRUPT;
break;
}
return rc;
}
/*
* [CAPIREF: ph7_lib_config()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_lib_config(int nConfigOp, ...) {
va_list ap;
int rc;
if(sMPGlobal.nMagic == PH7_LIB_MAGIC) {
/* Library is already initialized,this operation is forbidden */
return PH7_LOOKED;
}
va_start(ap, nConfigOp);
rc = PH7CoreConfigure(nConfigOp, ap);
va_end(ap);
return rc;
}
/*
* Global library initialization
* Refer to [ph7_lib_init()]
* This routine must be called to initialize the memory allocation subsystem,the mutex
* subsystem prior to doing any serious work with the library.The first thread to call
* this routine does the initialization process and set the magic number so no body later
* can re-initialize the library.If subsequent threads call this routine before the first
* thread have finished the initialization process, then the subsequent threads must block
* until the initialization process is done.
*/
static sxi32 PH7CoreInitialize(void) {
const ph7_vfs *pVfs; /* Built-in vfs */
#if defined(PH7_ENABLE_THREADS)
const SyMutexMethods *pMutexMethods = 0;
SyMutex *pMaster = 0;
#endif
int rc;
/*
* If the library is already initialized,then a call to this routine
* is a no-op.
*/
if(sMPGlobal.nMagic == PH7_LIB_MAGIC) {
return PH7_OK; /* Already initialized */
}
/* Point to the built-in vfs */
pVfs = PH7_ExportBuiltinVfs();
/* Install it */
ph7_lib_config(PH7_LIB_CONFIG_VFS, pVfs);
#if defined(PH7_ENABLE_THREADS)
if(sMPGlobal.nThreadingLevel != PH7_THREAD_LEVEL_SINGLE) {
pMutexMethods = sMPGlobal.pMutexMethods;
if(pMutexMethods == 0) {
/* Use the built-in mutex subsystem */
pMutexMethods = SyMutexExportMethods();
if(pMutexMethods == 0) {
return PH7_CORRUPT; /* Can't happen */
}
/* Install the mutex subsystem */
rc = ph7_lib_config(PH7_LIB_CONFIG_USER_MUTEX, pMutexMethods);
if(rc != PH7_OK) {
return rc;
}
}
/* Obtain a static mutex so we can initialize the library without calling malloc() */
pMaster = SyMutexNew(pMutexMethods, SXMUTEX_TYPE_STATIC_1);
if(pMaster == 0) {
return PH7_CORRUPT; /* Can't happen */
}
}
/* Lock the master mutex */
rc = PH7_OK;
SyMutexEnter(pMutexMethods, pMaster); /* NO-OP if sMPGlobal.nThreadingLevel == PH7_THREAD_LEVEL_SINGLE */
if(sMPGlobal.nMagic != PH7_LIB_MAGIC) {
#endif
if(sMPGlobal.sAllocator.pMethods == 0) {
/* Install a memory subsystem */
rc = ph7_lib_config(PH7_LIB_CONFIG_USER_MALLOC, 0); /* zero mean use the built-in memory backend */
if(rc != PH7_OK) {
/* If we are unable to initialize the memory backend,there is no much we can do here.*/
goto End;
}
}
#if defined(PH7_ENABLE_THREADS)
if(sMPGlobal.nThreadingLevel > PH7_THREAD_LEVEL_SINGLE) {
/* Protect the memory allocation subsystem */
rc = SyMemBackendMakeThreadSafe(&sMPGlobal.sAllocator, sMPGlobal.pMutexMethods);
if(rc != PH7_OK) {
goto End;
}
}
#endif
/* Our library is initialized,set the magic number */
sMPGlobal.nMagic = PH7_LIB_MAGIC;
rc = PH7_OK;
#if defined(PH7_ENABLE_THREADS)
} /* sMPGlobal.nMagic != PH7_LIB_MAGIC */
#endif
End:
#if defined(PH7_ENABLE_THREADS)
/* Unlock the master mutex */
SyMutexLeave(pMutexMethods, pMaster); /* NO-OP if sMPGlobal.nThreadingLevel == PH7_THREAD_LEVEL_SINGLE */
#endif
return rc;
}
/*
* [CAPIREF: ph7_lib_init()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_lib_init(void) {
int rc;
rc = PH7CoreInitialize();
return rc;
}
/*
* Release an active PH7 engine and it's associated active virtual machines.
*/
static sxi32 EngineRelease(ph7 *pEngine) {
ph7_vm *pVm, *pNext;
/* Release all active VM */
pVm = pEngine->pVms;
for(;;) {
if(pEngine->iVm <= 0) {
break;
}
pNext = pVm->pNext;
PH7_VmRelease(pVm);
pVm = pNext;
pEngine->iVm--;
}
/* Set a dummy magic number */
pEngine->nMagic = 0x7635;
/* Release the private memory subsystem */
SyMemBackendRelease(&pEngine->sAllocator);
return PH7_OK;
}
/*
* Release all resources consumed by the library.
* If PH7 is already shut down when this routine
* is invoked then this routine is a harmless no-op.
* Note: This call is not thread safe.
* Refer to [ph7_lib_shutdown()].
*/
static void PH7CoreShutdown(void) {
ph7 *pEngine, *pNext;
/* Release all active engines first */
pEngine = sMPGlobal.pEngines;
for(;;) {
if(sMPGlobal.nEngine < 1) {
break;
}
pNext = pEngine->pNext;
EngineRelease(pEngine);
pEngine = pNext;
sMPGlobal.nEngine--;
}
#if defined(PH7_ENABLE_THREADS)
/* Release the mutex subsystem */
if(sMPGlobal.pMutexMethods) {
if(sMPGlobal.pMutex) {
SyMutexRelease(sMPGlobal.pMutexMethods, sMPGlobal.pMutex);
sMPGlobal.pMutex = 0;
}
if(sMPGlobal.pMutexMethods->xGlobalRelease) {
sMPGlobal.pMutexMethods->xGlobalRelease();
}
sMPGlobal.pMutexMethods = 0;
}
sMPGlobal.nThreadingLevel = 0;
#endif
if(sMPGlobal.sAllocator.pMethods) {
/* Release the memory backend */
SyMemBackendRelease(&sMPGlobal.sAllocator);
}
sMPGlobal.nMagic = 0x1928;
}
/*
* [CAPIREF: ph7_lib_shutdown()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_lib_shutdown(void) {
if(sMPGlobal.nMagic != PH7_LIB_MAGIC) {
/* Already shut */
return PH7_OK;
}
PH7CoreShutdown();
return PH7_OK;
}
/*
* [CAPIREF: ph7_lib_is_threadsafe()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_lib_is_threadsafe(void) {
if(sMPGlobal.nMagic != PH7_LIB_MAGIC) {
return 0;
}
#if defined(PH7_ENABLE_THREADS)
if(sMPGlobal.nThreadingLevel > PH7_THREAD_LEVEL_SINGLE) {
/* Muli-threading support is enabled */
return 1;
} else {
/* Single-threading */
return 0;
}
#else
return 0;
#endif
}
/*
* [CAPIREF: ph7_lib_version()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
const char *ph7_lib_version(void) {
return PH7_VERSION;
}
/*
* [CAPIREF: ph7_lib_signature()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
const char *ph7_lib_signature(void) {
return PH7_SIG;
}
/*
* [CAPIREF: ph7_lib_copyright()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
const char *ph7_lib_copyright(void) {
return PH7_COPYRIGHT;
}
/*
* [CAPIREF: ph7_config()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_config(ph7 *pEngine, int nConfigOp, ...) {
va_list ap;
int rc;
if(PH7_ENGINE_MISUSE(pEngine)) {
return PH7_CORRUPT;
}
#if defined(PH7_ENABLE_THREADS)
/* Acquire engine mutex */
SyMutexEnter(sMPGlobal.pMutexMethods, pEngine->pMutex); /* NO-OP if sMPGlobal.nThreadingLevel != PH7_THREAD_LEVEL_MULTI */
if(sMPGlobal.nThreadingLevel > PH7_THREAD_LEVEL_SINGLE &&
PH7_THRD_ENGINE_RELEASE(pEngine)) {
return PH7_ABORT; /* Another thread have released this instance */
}
#endif
va_start(ap, nConfigOp);
rc = EngineConfig(&(*pEngine), nConfigOp, ap);
va_end(ap);
#if defined(PH7_ENABLE_THREADS)
/* Leave engine mutex */
SyMutexLeave(sMPGlobal.pMutexMethods, pEngine->pMutex); /* NO-OP if sMPGlobal.nThreadingLevel != PH7_THREAD_LEVEL_MULTI */
#endif
return rc;
}
/*
* [CAPIREF: ph7_init()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_init(ph7 **ppEngine) {
ph7 *pEngine;
int rc;
#if defined(UNTRUST)
if(ppEngine == 0) {
return PH7_CORRUPT;
}
#endif
*ppEngine = 0;
/* One-time automatic library initialization */
rc = PH7CoreInitialize();
if(rc != PH7_OK) {
return rc;
}
/* Allocate a new engine */
pEngine = (ph7 *)SyMemBackendPoolAlloc(&sMPGlobal.sAllocator, sizeof(ph7));
if(pEngine == 0) {
return PH7_NOMEM;
}
/* Zero the structure */
SyZero(pEngine, sizeof(ph7));
/* Initialize engine fields */
pEngine->nMagic = PH7_ENGINE_MAGIC;
rc = SyMemBackendInitFromParent(&pEngine->sAllocator, &sMPGlobal.sAllocator);
if(rc != PH7_OK) {
goto Release;
}
#if defined(PH7_ENABLE_THREADS)
SyMemBackendDisbaleMutexing(&pEngine->sAllocator);
#endif
/* Default configuration */
SyBlobInit(&pEngine->xConf.sErrConsumer, &pEngine->sAllocator);
/* Install a default compile-time error consumer routine */
ph7_config(pEngine, PH7_CONFIG_ERR_OUTPUT, PH7_VmBlobConsumer, &pEngine->xConf.sErrConsumer);
/* Built-in vfs */
pEngine->pVfs = sMPGlobal.pVfs;
#if defined(PH7_ENABLE_THREADS)
if(sMPGlobal.nThreadingLevel > PH7_THREAD_LEVEL_SINGLE) {
/* Associate a recursive mutex with this instance */
pEngine->pMutex = SyMutexNew(sMPGlobal.pMutexMethods, SXMUTEX_TYPE_RECURSIVE);
if(pEngine->pMutex == 0) {
rc = PH7_NOMEM;
goto Release;
}
}
#endif
/* Link to the list of active engines */
#if defined(PH7_ENABLE_THREADS)
/* Enter the global mutex */
SyMutexEnter(sMPGlobal.pMutexMethods, sMPGlobal.pMutex); /* NO-OP if sMPGlobal.nThreadingLevel == PH7_THREAD_LEVEL_SINGLE */
#endif
MACRO_LD_PUSH(sMPGlobal.pEngines, pEngine);
sMPGlobal.nEngine++;
#if defined(PH7_ENABLE_THREADS)
/* Leave the global mutex */
SyMutexLeave(sMPGlobal.pMutexMethods, sMPGlobal.pMutex); /* NO-OP if sMPGlobal.nThreadingLevel == PH7_THREAD_LEVEL_SINGLE */
#endif
/* Write a pointer to the new instance */
*ppEngine = pEngine;
return PH7_OK;
Release:
SyMemBackendRelease(&pEngine->sAllocator);
SyMemBackendPoolFree(&sMPGlobal.sAllocator, pEngine);
return rc;
}
/*
* [CAPIREF: ph7_release()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_release(ph7 *pEngine) {
int rc;
if(PH7_ENGINE_MISUSE(pEngine)) {
return PH7_CORRUPT;
}
#if defined(PH7_ENABLE_THREADS)
/* Acquire engine mutex */
SyMutexEnter(sMPGlobal.pMutexMethods, pEngine->pMutex); /* NO-OP if sMPGlobal.nThreadingLevel != PH7_THREAD_LEVEL_MULTI */
if(sMPGlobal.nThreadingLevel > PH7_THREAD_LEVEL_SINGLE &&
PH7_THRD_ENGINE_RELEASE(pEngine)) {
return PH7_ABORT; /* Another thread have released this instance */
}
#endif
/* Release the engine */
rc = EngineRelease(&(*pEngine));
#if defined(PH7_ENABLE_THREADS)
/* Leave engine mutex */
SyMutexLeave(sMPGlobal.pMutexMethods, pEngine->pMutex); /* NO-OP if sMPGlobal.nThreadingLevel != PH7_THREAD_LEVEL_MULTI */
/* Release engine mutex */
SyMutexRelease(sMPGlobal.pMutexMethods, pEngine->pMutex) /* NO-OP if sMPGlobal.nThreadingLevel != PH7_THREAD_LEVEL_MULTI */
/* Enter the global mutex */
SyMutexEnter(sMPGlobal.pMutexMethods, sMPGlobal.pMutex); /* NO-OP if sMPGlobal.nThreadingLevel == PH7_THREAD_LEVEL_SINGLE */
#endif
/* Unlink from the list of active engines */
MACRO_LD_REMOVE(sMPGlobal.pEngines, pEngine);
sMPGlobal.nEngine--;
#if defined(PH7_ENABLE_THREADS)
/* Leave the global mutex */
SyMutexLeave(sMPGlobal.pMutexMethods, sMPGlobal.pMutex); /* NO-OP if sMPGlobal.nThreadingLevel == PH7_THREAD_LEVEL_SINGLE */
#endif
/* Release the memory chunk allocated to this engine */
SyMemBackendPoolFree(&sMPGlobal.sAllocator, pEngine);
return rc;
}
int ph7_vm_init(
ph7 *pEngine, /* Running PH7 engine */
ph7_vm **ppOutVm, /* OUT: A pointer to the virtual machine */
sxbool bDebug /* VM Debugging */
) {
ph7_vm *pVm;
int rc;
if(ppOutVm) {
*ppOutVm = 0;
}
/* Allocate a new virtual machine */
pVm = (ph7_vm *)SyMemBackendPoolAlloc(&pEngine->sAllocator, sizeof(ph7_vm));
if(pVm == 0) {
/* 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. */
if(ppOutVm) {
*ppOutVm = 0;
}
return PH7_NOMEM;
}
/* Initialize the Virtual Machine */
rc = PH7_VmInit(pVm, &(*pEngine), bDebug);
if(rc != PH7_OK) {
SyMemBackendPoolFree(&pEngine->sAllocator, pVm);
if(ppOutVm) {
*ppOutVm = 0;
}
return PH7_VM_ERR;
}
/* Reset the error message consumer */
SyBlobReset(&pEngine->xConf.sErrConsumer);
/* Set the default VM output consumer callback and it's
* private data. */
pVm->sVmConsumer.xConsumer = PH7_VmBlobConsumer;
pVm->sVmConsumer.pUserData = &pVm->sConsumer;
/* Point to the freshly created VM */
*ppOutVm = pVm;
return PH7_OK;
}
/*
* Compile a raw PHP script.
* To execute a PHP code, it must first be compiled into a byte-code program using this routine.
* If something goes wrong [i.e: compile-time error], your error log [i.e: error consumer callback]
* should display the appropriate error message and this function set ppVm to null and return
* an error code that is different from PH7_OK. Otherwise when the script is successfully compiled
* ppVm should hold the PH7 byte-code and it's safe to call [ph7_vm_exec(), ph7_vm_reset(), etc.].
* This API does not actually evaluate the PHP code. It merely compile and prepares the PHP script
* for evaluation.
*/
static sxi32 ProcessSourceFile(
ph7 *pEngine, /* Running PH7 engine */
ph7_vm **ppVm, /* OUT: A pointer to the virtual machine */
SyString *pScript, /* Raw PHP script to compile */
const char *zFilePath /* File path if script come from a file. NULL otherwise */
) {
ph7_vm *pVm = *ppVm;
int iFileDir, rc;
char *pFileDir, *fFilePath[PATH_MAX + 1];
char *pFilePath[PATH_MAX + 1];
/* Install local import path which is the current directory */
ph7_vm_config(pVm, PH7_VM_CONFIG_IMPORT_PATH, "./");
if(zFilePath && SyRealPath(zFilePath, fFilePath) == PH7_OK) {
snprintf(pFilePath, sizeof(pFilePath) - 1, "%s", fFilePath);
/* Extract directory name containing processed file */
pFileDir = PH7_ExtractDirName(fFilePath, SyStrlen(fFilePath), &iFileDir);
pFileDir[iFileDir + 1] = '\0';
/* Install local import path which is directory containing entry script */
ph7_vm_config(pVm, PH7_VM_CONFIG_IMPORT_PATH, pFileDir);
/* Push processed file path */
PH7_VmPushFilePath(pVm, pFilePath, -1, TRUE, 0);
} else {
PH7_VmPushFilePath(pVm, "[MEMORY]", -1, TRUE, 0);
}
/* Compile the script */
PH7_CompileAerScript(pVm, &(*pScript), PH7_AERSCRIPT_CODE);
if(pVm->sCodeGen.nErr > 0 || pVm == 0) {
sxu32 nErr = pVm->sCodeGen.nErr;
/* Compilation error or null ppVm pointer,release this VM */
SyMemBackendRelease(&pVm->sAllocator);
SyMemBackendPoolFree(&pEngine->sAllocator, pVm);
if(ppVm) {
*ppVm = 0;
}
return nErr > 0 ? PH7_COMPILE_ERR : PH7_OK;
}
/* Prepare the virtual machine for bytecode execution */
rc = PH7_VmMakeReady(pVm);
if(rc != PH7_OK) {
goto Release;
}
#if defined(PH7_ENABLE_THREADS)
if(sMPGlobal.nThreadingLevel > PH7_THREAD_LEVEL_SINGLE) {
/* Associate a recursive mutex with this instance */
pVm->pMutex = SyMutexNew(sMPGlobal.pMutexMethods, SXMUTEX_TYPE_RECURSIVE);
if(pVm->pMutex == 0) {
goto Release;
}
}
#endif
/* Script successfully compiled,link to the list of active virtual machines */
MACRO_LD_PUSH(pEngine->pVms, pVm);
pEngine->iVm++;
/* Ready to execute PH7 bytecode */
return PH7_OK;
Release:
SyMemBackendRelease(&pVm->sAllocator);
SyMemBackendPoolFree(&pEngine->sAllocator, pVm);
*ppVm = 0;
return PH7_VM_ERR;
}
/*
* [CAPIREF: ph7_compile()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_compile_code(ph7 *pEngine, const char *zSource, int nLen, ph7_vm **ppOutVm) {
SyString sScript;
int rc;
if(PH7_ENGINE_MISUSE(pEngine) || zSource == 0) {
return PH7_CORRUPT;
}
if(nLen < 0) {
/* Compute input length automatically */
nLen = (int)SyStrlen(zSource);
}
SyStringInitFromBuf(&sScript, zSource, nLen);
#if defined(PH7_ENABLE_THREADS)
/* Acquire engine mutex */
SyMutexEnter(sMPGlobal.pMutexMethods, pEngine->pMutex); /* NO-OP if sMPGlobal.nThreadingLevel != PH7_THREAD_LEVEL_MULTI */
if(sMPGlobal.nThreadingLevel > PH7_THREAD_LEVEL_SINGLE &&
PH7_THRD_ENGINE_RELEASE(pEngine)) {
return PH7_ABORT; /* Another thread have released this instance */
}
#endif
/* Compile the script */
rc = ProcessSourceFile(&(*pEngine), ppOutVm, &sScript, 0);
#if defined(PH7_ENABLE_THREADS)
/* Leave engine mutex */
SyMutexLeave(sMPGlobal.pMutexMethods, pEngine->pMutex); /* NO-OP if sMPGlobal.nThreadingLevel != PH7_THREAD_LEVEL_MULTI */
#endif
/* Compilation result */
return rc;
}
/*
* [CAPIREF: ph7_compile_file()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_compile_file(ph7 *pEngine, const char *zFilePath, ph7_vm **ppOutVm) {
const ph7_vfs *pVfs;
int rc;
rc = PH7_OK; /* cc warning */
if(PH7_ENGINE_MISUSE(pEngine) || SX_EMPTY_STR(zFilePath)) {
return PH7_CORRUPT;
}
#if defined(PH7_ENABLE_THREADS)
/* Acquire engine mutex */
SyMutexEnter(sMPGlobal.pMutexMethods, pEngine->pMutex); /* NO-OP if sMPGlobal.nThreadingLevel != PH7_THREAD_LEVEL_MULTI */
if(sMPGlobal.nThreadingLevel > PH7_THREAD_LEVEL_SINGLE &&
PH7_THRD_ENGINE_RELEASE(pEngine)) {
return PH7_ABORT; /* Another thread have released this instance */
}
#endif
/*
* Check if the underlying vfs implement the memory map
* [i.e: mmap() under UNIX/MapViewOfFile() under windows] function.
*/
pVfs = pEngine->pVfs;
if(pVfs == 0 || pVfs->xMmap == 0) {
/* Memory map routine not implemented */
rc = PH7_IO_ERR;
} else {
void *pMapView = 0; /* cc warning */
ph7_int64 nSize = 0; /* cc warning */
SyString sScript;
/* Try to get a memory view of the whole file */
rc = pVfs->xMmap(zFilePath, &pMapView, &nSize);
if(rc != PH7_OK) {
/* Assume an IO error */
rc = PH7_IO_ERR;
} else {
/* Compile the file */
SyStringInitFromBuf(&sScript, pMapView, nSize);
rc = ProcessSourceFile(&(*pEngine), ppOutVm, &sScript, zFilePath);
/* Release the memory view of the whole file */
if(pVfs->xUnmap) {
pVfs->xUnmap(pMapView, nSize);
}
}
}
#if defined(PH7_ENABLE_THREADS)
/* Leave engine mutex */
SyMutexLeave(sMPGlobal.pMutexMethods, pEngine->pMutex); /* NO-OP if sMPGlobal.nThreadingLevel != PH7_THREAD_LEVEL_MULTI */
#endif
/* Compilation result */
return rc;
}
/*
* [CAPIREF: ph7_vm_dump()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_vm_dump(ph7_vm *pVm, int (*xConsumer)(const void *, unsigned int, void *), void *pUserData) {
int rc;
/* Ticket 1433-002: NULL VM is harmless operation */
if(PH7_VM_MISUSE(pVm)) {
return PH7_CORRUPT;
}
#ifdef UNTRUST
if(xConsumer == 0) {
return PH7_CORRUPT;
}
#endif
/* Dump VM instructions */
rc = PH7_VmDump(&(*pVm), xConsumer, pUserData);
return rc;
}
/*
* [CAPIREF: ph7_vm_config()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_vm_config(ph7_vm *pVm, int iConfigOp, ...) {
va_list ap;
int rc;
/* Ticket 1433-002: NULL VM is harmless operation */
if(PH7_VM_MISUSE(pVm)) {
return PH7_CORRUPT;
}
#if defined(PH7_ENABLE_THREADS)
/* Acquire VM mutex */
SyMutexEnter(sMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sMPGlobal.nThreadingLevel != PH7_THREAD_LEVEL_MULTI */
if(sMPGlobal.nThreadingLevel > PH7_THREAD_LEVEL_SINGLE &&
PH7_THRD_VM_RELEASE(pVm)) {
return PH7_ABORT; /* Another thread have released this instance */
}
#endif
/* Configure the virtual machine */
va_start(ap, iConfigOp);
rc = PH7_VmConfigure(&(*pVm), iConfigOp, ap);
va_end(ap);
#if defined(PH7_ENABLE_THREADS)
/* Leave VM mutex */
SyMutexLeave(sMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sMPGlobal.nThreadingLevel != PH7_THREAD_LEVEL_MULTI */
#endif
return rc;
}
/*
* [CAPIREF: ph7_vm_exec()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_vm_exec(ph7_vm *pVm, int *pExitStatus) {
int rc;
/* Ticket 1433-002: NULL VM is harmless operation */
if(PH7_VM_MISUSE(pVm)) {
return PH7_CORRUPT;
}
#if defined(PH7_ENABLE_THREADS)
/* Acquire VM mutex */
SyMutexEnter(sMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sMPGlobal.nThreadingLevel != PH7_THREAD_LEVEL_MULTI */
if(sMPGlobal.nThreadingLevel > PH7_THREAD_LEVEL_SINGLE &&
PH7_THRD_VM_RELEASE(pVm)) {
return PH7_ABORT; /* Another thread have released this instance */
}
#endif
/* Execute PH7 byte-code */
rc = PH7_VmByteCodeExec(&(*pVm));
if(pExitStatus) {
/* Exit status */
*pExitStatus = pVm->iExitStatus;
}
#if defined(PH7_ENABLE_THREADS)
/* Leave VM mutex */
SyMutexLeave(sMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sMPGlobal.nThreadingLevel != PH7_THREAD_LEVEL_MULTI */
#endif
/* Execution result */
return rc;
}
/*
* [CAPIREF: ph7_vm_reset()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_vm_reset(ph7_vm *pVm) {
int rc;
/* Ticket 1433-002: NULL VM is harmless operation */
if(PH7_VM_MISUSE(pVm)) {
return PH7_CORRUPT;
}
#if defined(PH7_ENABLE_THREADS)
/* Acquire VM mutex */
SyMutexEnter(sMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sMPGlobal.nThreadingLevel != PH7_THREAD_LEVEL_MULTI */
if(sMPGlobal.nThreadingLevel > PH7_THREAD_LEVEL_SINGLE &&
PH7_THRD_VM_RELEASE(pVm)) {
return PH7_ABORT; /* Another thread have released this instance */
}
#endif
rc = PH7_VmReset(&(*pVm));
#if defined(PH7_ENABLE_THREADS)
/* Leave VM mutex */
SyMutexLeave(sMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sMPGlobal.nThreadingLevel != PH7_THREAD_LEVEL_MULTI */
#endif
return rc;
}
/*
* [CAPIREF: ph7_vm_release()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_vm_release(ph7_vm *pVm) {
ph7 *pEngine;
int rc;
/* Ticket 1433-002: NULL VM is harmless operation */
if(PH7_VM_MISUSE(pVm)) {
return PH7_CORRUPT;
}
#if defined(PH7_ENABLE_THREADS)
/* Acquire VM mutex */
SyMutexEnter(sMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sMPGlobal.nThreadingLevel != PH7_THREAD_LEVEL_MULTI */
if(sMPGlobal.nThreadingLevel > PH7_THREAD_LEVEL_SINGLE &&
PH7_THRD_VM_RELEASE(pVm)) {
return PH7_ABORT; /* Another thread have released this instance */
}
#endif
pEngine = pVm->pEngine;
rc = PH7_VmRelease(&(*pVm));
#if defined(PH7_ENABLE_THREADS)
/* Leave VM mutex */
SyMutexLeave(sMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sMPGlobal.nThreadingLevel != PH7_THREAD_LEVEL_MULTI */
/* free VM mutex */
SyMutexRelease(sMPGlobal.pMutexMethods, pVm->pMutex);
#endif
if(rc == PH7_OK) {
/* Unlink from the list of active VM */
#if defined(PH7_ENABLE_THREADS)
/* Acquire engine mutex */
SyMutexEnter(sMPGlobal.pMutexMethods, pEngine->pMutex); /* NO-OP if sMPGlobal.nThreadingLevel != PH7_THREAD_LEVEL_MULTI */
if(sMPGlobal.nThreadingLevel > PH7_THREAD_LEVEL_SINGLE &&
PH7_THRD_ENGINE_RELEASE(pEngine)) {
return PH7_ABORT; /* Another thread have released this instance */
}
#endif
MACRO_LD_REMOVE(pEngine->pVms, pVm);
pEngine->iVm--;
/* Release the memory chunk allocated to this VM */
SyMemBackendPoolFree(&pEngine->sAllocator, pVm);
#if defined(PH7_ENABLE_THREADS)
/* Leave engine mutex */
SyMutexLeave(sMPGlobal.pMutexMethods, pEngine->pMutex); /* NO-OP if sMPGlobal.nThreadingLevel != PH7_THREAD_LEVEL_MULTI */
#endif
}
return rc;
}
/*
* [CAPIREF: ph7_create_function()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_create_function(ph7_vm *pVm, const char *zName, int (*xFunc)(ph7_context *, int, ph7_value **), void *pUserData) {
SyString sName;
int rc;
/* Ticket 1433-002: NULL VM is harmless operation */
if(PH7_VM_MISUSE(pVm)) {
return PH7_CORRUPT;
}
SyStringInitFromBuf(&sName, zName, SyStrlen(zName));
/* Remove leading and trailing white spaces */
SyStringFullTrim(&sName);
/* Ticket 1433-003: NULL values are not allowed */
if(sName.nByte < 1 || xFunc == 0) {
return PH7_CORRUPT;
}
#if defined(PH7_ENABLE_THREADS)
/* Acquire VM mutex */
SyMutexEnter(sMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sMPGlobal.nThreadingLevel != PH7_THREAD_LEVEL_MULTI */
if(sMPGlobal.nThreadingLevel > PH7_THREAD_LEVEL_SINGLE &&
PH7_THRD_VM_RELEASE(pVm)) {
return PH7_ABORT; /* Another thread have released this instance */
}
#endif
/* Install the foreign function */
rc = PH7_VmInstallForeignFunction(&(*pVm), &sName, xFunc, pUserData);
#if defined(PH7_ENABLE_THREADS)
/* Leave VM mutex */
SyMutexLeave(sMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sMPGlobal.nThreadingLevel != PH7_THREAD_LEVEL_MULTI */
#endif
return rc;
}
/*
* [CAPIREF: ph7_delete_function()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_delete_function(ph7_vm *pVm, const char *zName) {
ph7_user_func *pFunc = 0;
int rc;
/* Ticket 1433-002: NULL VM is harmless operation */
if(PH7_VM_MISUSE(pVm)) {
return PH7_CORRUPT;
}
#if defined(PH7_ENABLE_THREADS)
/* Acquire VM mutex */
SyMutexEnter(sMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sMPGlobal.nThreadingLevel != PH7_THREAD_LEVEL_MULTI */
if(sMPGlobal.nThreadingLevel > PH7_THREAD_LEVEL_SINGLE &&
PH7_THRD_VM_RELEASE(pVm)) {
return PH7_ABORT; /* Another thread have released this instance */
}
#endif
/* Perform the deletion */
rc = SyHashDeleteEntry(&pVm->hHostFunction, (const void *)zName, SyStrlen(zName), (void **)&pFunc);
if(rc == PH7_OK) {
/* Release internal fields */
SySetRelease(&pFunc->aAux);
SyMemBackendFree(&pVm->sAllocator, (void *)SyStringData(&pFunc->sName));
SyMemBackendPoolFree(&pVm->sAllocator, pFunc);
}
#if defined(PH7_ENABLE_THREADS)
/* Leave VM mutex */
SyMutexLeave(sMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sMPGlobal.nThreadingLevel != PH7_THREAD_LEVEL_MULTI */
#endif
return rc;
}
/*
* [CAPIREF: ph7_create_constant()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_create_constant(ph7_vm *pVm, const char *zName, void (*xExpand)(ph7_value *, void *), void *pUserData) {
SyString sName;
int rc;
/* Ticket 1433-002: NULL VM is harmless operation */
if(PH7_VM_MISUSE(pVm)) {
return PH7_CORRUPT;
}
SyStringInitFromBuf(&sName, zName, SyStrlen(zName));
/* Remove leading and trailing white spaces */
SyStringFullTrim(&sName);
if(sName.nByte < 1) {
/* Empty constant name */
return PH7_CORRUPT;
}
/* TICKET 1433-003: NULL pointer harmless operation */
if(xExpand == 0) {
return PH7_CORRUPT;
}
#if defined(PH7_ENABLE_THREADS)
/* Acquire VM mutex */
SyMutexEnter(sMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sMPGlobal.nThreadingLevel != PH7_THREAD_LEVEL_MULTI */
if(sMPGlobal.nThreadingLevel > PH7_THREAD_LEVEL_SINGLE &&
PH7_THRD_VM_RELEASE(pVm)) {
return PH7_ABORT; /* Another thread have released this instance */
}
#endif
/* Perform the registration */
rc = PH7_VmRegisterConstant(&(*pVm), &sName, xExpand, pUserData);
#if defined(PH7_ENABLE_THREADS)
/* Leave VM mutex */
SyMutexLeave(sMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sMPGlobal.nThreadingLevel != PH7_THREAD_LEVEL_MULTI */
#endif
return rc;
}
/*
* [CAPIREF: ph7_delete_constant()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_delete_constant(ph7_vm *pVm, const char *zName) {
ph7_constant *pCons;
int rc;
/* Ticket 1433-002: NULL VM is harmless operation */
if(PH7_VM_MISUSE(pVm)) {
return PH7_CORRUPT;
}
#if defined(PH7_ENABLE_THREADS)
/* Acquire VM mutex */
SyMutexEnter(sMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sMPGlobal.nThreadingLevel != PH7_THREAD_LEVEL_MULTI */
if(sMPGlobal.nThreadingLevel > PH7_THREAD_LEVEL_SINGLE &&
PH7_THRD_VM_RELEASE(pVm)) {
return PH7_ABORT; /* Another thread have released this instance */
}
#endif
/* Query the constant hashtable */
rc = SyHashDeleteEntry(&pVm->hConstant, (const void *)zName, SyStrlen(zName), (void **)&pCons);
if(rc == PH7_OK) {
/* Perform the deletion */
SyMemBackendFree(&pVm->sAllocator, (void *)SyStringData(&pCons->sName));
SyMemBackendPoolFree(&pVm->sAllocator, pCons);
}
#if defined(PH7_ENABLE_THREADS)
/* Leave VM mutex */
SyMutexLeave(sMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sMPGlobal.nThreadingLevel != PH7_THREAD_LEVEL_MULTI */
#endif
return rc;
}
/*
* [CAPIREF: ph7_new_scalar()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
ph7_value *ph7_new_scalar(ph7_vm *pVm) {
ph7_value *pObj;
/* Ticket 1433-002: NULL VM is harmless operation */
if(PH7_VM_MISUSE(pVm)) {
return 0;
}
/* Allocate a new scalar variable */
pObj = (ph7_value *)SyMemBackendPoolAlloc(&pVm->sAllocator, sizeof(ph7_value));
if(pObj == 0) {
return 0;
}
/* Nullify the new scalar */
PH7_MemObjInit(pVm, pObj);
return pObj;
}
/*
* [CAPIREF: ph7_new_array()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
ph7_value *ph7_new_array(ph7_vm *pVm) {
ph7_hashmap *pMap;
ph7_value *pObj;
/* Ticket 1433-002: NULL VM is harmless operation */
if(PH7_VM_MISUSE(pVm)) {
return 0;
}
/* Create a new hashmap first */
pMap = PH7_NewHashmap(&(*pVm), 0, 0);
if(pMap == 0) {
return 0;
}
/* Associate a new ph7_value with this hashmap */
pObj = (ph7_value *)SyMemBackendPoolAlloc(&pVm->sAllocator, sizeof(ph7_value));
if(pObj == 0) {
PH7_HashmapRelease(pMap, TRUE);
return 0;
}
PH7_MemObjInitFromArray(pVm, pObj, pMap);
return pObj;
}
/*
* [CAPIREF: ph7_release_value()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_release_value(ph7_vm *pVm, ph7_value *pValue) {
/* Ticket 1433-002: NULL VM is harmless operation */
if(PH7_VM_MISUSE(pVm)) {
return PH7_CORRUPT;
}
if(pValue) {
/* Release the value */
PH7_MemObjRelease(pValue);
SyMemBackendPoolFree(&pVm->sAllocator, pValue);
}
return PH7_OK;
}
/*
* [CAPIREF: ph7_value_to_int()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_value_to_int(ph7_value *pValue) {
int rc;
rc = PH7_MemObjToInteger(pValue);
if(rc != PH7_OK) {
return 0;
}
return (int)pValue->x.iVal;
}
/*
* [CAPIREF: ph7_value_to_bool()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_value_to_bool(ph7_value *pValue) {
int rc;
rc = PH7_MemObjToBool(pValue);
if(rc != PH7_OK) {
return 0;
}
return (int)pValue->x.iVal;
}
/*
* [CAPIREF: ph7_value_to_int64()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
ph7_int64 ph7_value_to_int64(ph7_value *pValue) {
int rc;
rc = PH7_MemObjToInteger(pValue);
if(rc != PH7_OK) {
return 0;
}
return pValue->x.iVal;
}
/*
* [CAPIREF: ph7_value_to_double()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
double ph7_value_to_double(ph7_value *pValue) {
int rc;
rc = PH7_MemObjToReal(pValue);
if(rc != PH7_OK) {
return (double)0;
}
return (double)pValue->x.rVal;
}
/*
* [CAPIREF: ph7_value_to_string()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
const char *ph7_value_to_string(ph7_value *pValue, int *pLen) {
PH7_MemObjToString(pValue);
if(SyBlobLength(&pValue->sBlob) > 0) {
SyBlobNullAppend(&pValue->sBlob);
if(pLen) {
*pLen = (int)SyBlobLength(&pValue->sBlob);
}
return (const char *)SyBlobData(&pValue->sBlob);
} else {
/* Return the empty string */
if(pLen) {
*pLen = 0;
}
return "";
}
}
/*
* [CAPIREF: ph7_value_to_resource()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
void *ph7_value_to_resource(ph7_value *pValue) {
if((pValue->iFlags & MEMOBJ_RES) == 0) {
/* Not a resource,return NULL */
return 0;
}
return pValue->x.pOther;
}
/*
* [CAPIREF: ph7_value_compare()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_value_compare(ph7_value *pLeft, ph7_value *pRight, int bStrict) {
int rc;
if(pLeft == 0 || pRight == 0) {
/* TICKET 1433-24: NULL values is harmless operation */
return 1;
}
/* Perform the comparison */
rc = PH7_MemObjCmp(&(*pLeft), &(*pRight), bStrict, 0);
/* Comparison result */
return rc;
}
/*
* [CAPIREF: ph7_result_int()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_result_int(ph7_context *pCtx, int iValue) {
return ph7_value_int(pCtx->pRet, iValue);
}
/*
* [CAPIREF: ph7_result_int64()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_result_int64(ph7_context *pCtx, ph7_int64 iValue) {
return ph7_value_int64(pCtx->pRet, iValue);
}
/*
* [CAPIREF: ph7_result_bool()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_result_bool(ph7_context *pCtx, int iBool) {
return ph7_value_bool(pCtx->pRet, iBool);
}
/*
* [CAPIREF: ph7_result_double()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_result_double(ph7_context *pCtx, double Value) {
return ph7_value_double(pCtx->pRet, Value);
}
/*
* [CAPIREF: ph7_result_null()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_result_null(ph7_context *pCtx) {
/* Invalidate any prior representation and set the NULL flag */
PH7_MemObjRelease(pCtx->pRet);
return PH7_OK;
}
/*
* [CAPIREF: ph7_result_string()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_result_string(ph7_context *pCtx, const char *zString, int nLen) {
return ph7_value_string(pCtx->pRet, zString, nLen);
}
/*
* [CAPIREF: ph7_result_string_format()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_result_string_format(ph7_context *pCtx, const char *zFormat, ...) {
ph7_value *p;
va_list ap;
int rc;
p = pCtx->pRet;
if((p->iFlags & MEMOBJ_STRING) == 0) {
/* Invalidate any prior representation */
PH7_MemObjRelease(p);
MemObjSetType(p, MEMOBJ_STRING);
}
/* Format the given string */
va_start(ap, zFormat);
rc = SyBlobFormatAp(&p->sBlob, zFormat, ap);
va_end(ap);
return rc;
}
/*
* [CAPIREF: ph7_result_value()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_result_value(ph7_context *pCtx, ph7_value *pValue) {
int rc = PH7_OK;
if(pValue == 0) {
PH7_MemObjRelease(pCtx->pRet);
} else {
rc = PH7_MemObjStore(pValue, pCtx->pRet);
}
return rc;
}
/*
* [CAPIREF: ph7_result_resource()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_result_resource(ph7_context *pCtx, void *pUserData) {
return ph7_value_resource(pCtx->pRet, pUserData);
}
/*
* [CAPIREF: ph7_context_new_scalar()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
ph7_value *ph7_context_new_scalar(ph7_context *pCtx) {
ph7_value *pVal;
pVal = ph7_new_scalar(pCtx->pVm);
if(pVal) {
/* Record value address so it can be freed automatically
* when the calling function returns.
*/
SySetPut(&pCtx->sVar, (const void *)&pVal);
}
return pVal;
}
/*
* [CAPIREF: ph7_context_new_array()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
ph7_value *ph7_context_new_array(ph7_context *pCtx) {
ph7_value *pVal;
pVal = ph7_new_array(pCtx->pVm);
if(pVal) {
/* Record value address so it can be freed automatically
* when the calling function returns.
*/
SySetPut(&pCtx->sVar, (const void *)&pVal);
}
return pVal;
}
/*
* [CAPIREF: ph7_context_release_value()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
void ph7_context_release_value(ph7_context *pCtx, ph7_value *pValue) {
PH7_VmReleaseContextValue(&(*pCtx), pValue);
}
/*
* [CAPIREF: ph7_context_alloc_chunk()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
void *ph7_context_alloc_chunk(ph7_context *pCtx, unsigned int nByte, int ZeroChunk, int AutoRelease) {
void *pChunk;
pChunk = SyMemBackendAlloc(&pCtx->pVm->sAllocator, nByte);
if(pChunk) {
if(ZeroChunk) {
/* Zero the memory chunk */
SyZero(pChunk, nByte);
}
if(AutoRelease) {
ph7_aux_data sAux;
/* Track the chunk so that it can be released automatically
* upon this context is destroyed.
*/
sAux.pAuxData = pChunk;
SySetPut(&pCtx->sChunk, (const void *)&sAux);
}
}
return pChunk;
}
/*
* Check if the given chunk address is registered in the call context
* chunk container.
* Return TRUE if registered.FALSE otherwise.
* Refer to [ph7_context_realloc_chunk(),ph7_context_free_chunk()].
*/
static ph7_aux_data *ContextFindChunk(ph7_context *pCtx, void *pChunk) {
ph7_aux_data *aAux, *pAux;
sxu32 n;
if(SySetUsed(&pCtx->sChunk) < 1) {
/* Don't bother processing,the container is empty */
return 0;
}
/* Perform the lookup */
aAux = (ph7_aux_data *)SySetBasePtr(&pCtx->sChunk);
for(n = 0; n < SySetUsed(&pCtx->sChunk) ; ++n) {
pAux = &aAux[n];
if(pAux->pAuxData == pChunk) {
/* Chunk found */
return pAux;
}
}
/* No such allocated chunk */
return 0;
}
/*
* [CAPIREF: ph7_context_realloc_chunk()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
void *ph7_context_realloc_chunk(ph7_context *pCtx, void *pChunk, unsigned int nByte) {
ph7_aux_data *pAux;
void *pNew;
pNew = SyMemBackendRealloc(&pCtx->pVm->sAllocator, pChunk, nByte);
if(pNew) {
pAux = ContextFindChunk(pCtx, pChunk);
if(pAux) {
pAux->pAuxData = pNew;
}
}
return pNew;
}
/*
* [CAPIREF: ph7_context_free_chunk()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
void ph7_context_free_chunk(ph7_context *pCtx, void *pChunk) {
ph7_aux_data *pAux;
if(pChunk == 0) {
/* TICKET-1433-93: NULL chunk is a harmless operation */
return;
}
pAux = ContextFindChunk(pCtx, pChunk);
if(pAux) {
/* Mark as destroyed */
pAux->pAuxData = 0;
}
SyMemBackendFree(&pCtx->pVm->sAllocator, pChunk);
}
/*
* [CAPIREF: ph7_array_fetch()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
ph7_value *ph7_array_fetch(ph7_value *pArray, const char *zKey, int nByte) {
ph7_hashmap_node *pNode;
ph7_value *pValue;
ph7_value skey;
int rc;
/* Make sure we are dealing with a valid hashmap */
if((pArray->iFlags & MEMOBJ_HASHMAP) == 0) {
return 0;
}
if(nByte < 0) {
nByte = (int)SyStrlen(zKey);
}
/* Convert the key to a ph7_value */
PH7_MemObjInit(pArray->pVm, &skey);
PH7_MemObjStringAppend(&skey, zKey, (sxu32)nByte);
/* Perform the lookup */
rc = PH7_HashmapLookup((ph7_hashmap *)pArray->x.pOther, &skey, &pNode);
PH7_MemObjRelease(&skey);
if(rc != PH7_OK) {
/* No such entry */
return 0;
}
/* Extract the target value */
pValue = (ph7_value *)SySetAt(&pArray->pVm->aMemObj, pNode->nValIdx);
return pValue;
}
/*
* [CAPIREF: ph7_array_walk()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_array_walk(ph7_value *pArray, int (*xWalk)(ph7_value *pValue, ph7_value *, void *), void *pUserData) {
int rc;
if(xWalk == 0) {
return PH7_CORRUPT;
}
/* Make sure we are dealing with a valid hashmap */
if((pArray->iFlags & MEMOBJ_HASHMAP) == 0) {
return PH7_CORRUPT;
}
/* Start the walk process */
rc = PH7_HashmapWalk((ph7_hashmap *)pArray->x.pOther, xWalk, pUserData);
return rc != PH7_OK ? PH7_ABORT /* User callback request an operation abort*/ : PH7_OK;
}
/*
* [CAPIREF: ph7_array_add_elem()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_array_add_elem(ph7_value *pArray, ph7_value *pKey, ph7_value *pValue) {
int rc;
/* Make sure we are dealing with a valid hashmap */
if((pArray->iFlags & MEMOBJ_HASHMAP) == 0) {
return PH7_CORRUPT;
}
/* Perform the insertion */
rc = PH7_HashmapInsert((ph7_hashmap *)pArray->x.pOther, &(*pKey), &(*pValue));
return rc;
}
/*
* [CAPIREF: ph7_array_add_strkey_elem()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_array_add_strkey_elem(ph7_value *pArray, const char *zKey, ph7_value *pValue) {
int rc;
/* Make sure we are dealing with a valid hashmap */
if((pArray->iFlags & MEMOBJ_HASHMAP) == 0) {
return PH7_CORRUPT;
}
/* Perform the insertion */
if(SX_EMPTY_STR(zKey)) {
/* Empty key,assign an automatic index */
rc = PH7_HashmapInsert((ph7_hashmap *)pArray->x.pOther, 0, &(*pValue));
} else {
ph7_value sKey;
PH7_MemObjInitFromString(pArray->pVm, &sKey, 0);
PH7_MemObjStringAppend(&sKey, zKey, (sxu32)SyStrlen(zKey));
rc = PH7_HashmapInsert((ph7_hashmap *)pArray->x.pOther, &sKey, &(*pValue));
PH7_MemObjRelease(&sKey);
}
return rc;
}
/*
* [CAPIREF: ph7_array_add_intkey_elem()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_array_add_intkey_elem(ph7_value *pArray, int iKey, ph7_value *pValue) {
ph7_value sKey;
int rc;
/* Make sure we are dealing with a valid hashmap */
if((pArray->iFlags & MEMOBJ_HASHMAP) == 0) {
return PH7_CORRUPT;
}
PH7_MemObjInitFromInt(pArray->pVm, &sKey, iKey);
/* Perform the insertion */
rc = PH7_HashmapInsert((ph7_hashmap *)pArray->x.pOther, &sKey, &(*pValue));
PH7_MemObjRelease(&sKey);
return rc;
}
/*
* [CAPIREF: ph7_array_count()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
unsigned int ph7_array_count(ph7_value *pArray) {
ph7_hashmap *pMap;
/* Make sure we are dealing with a valid hashmap */
if((pArray->iFlags & MEMOBJ_HASHMAP) == 0) {
return 0;
}
/* Point to the internal representation of the hashmap */
pMap = (ph7_hashmap *)pArray->x.pOther;
return pMap->nEntry;
}
/*
* [CAPIREF: ph7_object_walk()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_object_walk(ph7_value *pObject, int (*xWalk)(const char *, ph7_value *, void *), void *pUserData) {
int rc;
if(xWalk == 0) {
return PH7_CORRUPT;
}
/* Make sure we are dealing with a valid class instance */
if((pObject->iFlags & MEMOBJ_OBJ) == 0) {
return PH7_CORRUPT;
}
/* Start the walk process */
rc = PH7_ClassInstanceWalk((ph7_class_instance *)pObject->x.pOther, xWalk, pUserData);
return rc != PH7_OK ? PH7_ABORT /* User callback request an operation abort*/ : PH7_OK;
}
/*
* [CAPIREF: ph7_object_fetch_attr()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
ph7_value *ph7_object_fetch_attr(ph7_value *pObject, const char *zAttr) {
ph7_value *pValue;
SyString sAttr;
/* Make sure we are dealing with a valid class instance */
if((pObject->iFlags & MEMOBJ_OBJ) == 0 || zAttr == 0) {
return 0;
}
SyStringInitFromBuf(&sAttr, zAttr, SyStrlen(zAttr));
/* Extract the attribute value if available.
*/
pValue = PH7_ClassInstanceFetchAttr((ph7_class_instance *)pObject->x.pOther, &sAttr);
return pValue;
}
/*
* [CAPIREF: ph7_object_get_class_name()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
const char *ph7_object_get_class_name(ph7_value *pObject, int *pLength) {
ph7_class *pClass;
if(pLength) {
*pLength = 0;
}
/* Make sure we are dealing with a valid class instance */
if((pObject->iFlags & MEMOBJ_OBJ) == 0) {
return 0;
}
/* Point to the class */
pClass = ((ph7_class_instance *)pObject->x.pOther)->pClass;
/* Return the class name */
if(pLength) {
*pLength = (int)SyStringLength(&pClass->sName);
}
return SyStringData(&pClass->sName);
}
/*
* [CAPIREF: ph7_context_output()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_context_output(ph7_context *pCtx, const char *zString, int nLen) {
SyString sData;
int rc;
if(nLen < 0) {
nLen = (int)SyStrlen(zString);
}
SyStringInitFromBuf(&sData, zString, nLen);
rc = PH7_VmOutputConsume(pCtx->pVm, &sData);
return rc;
}
/*
* [CAPIREF: ph7_context_output_format()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_context_output_format(ph7_context *pCtx, const char *zFormat, ...) {
va_list ap;
int rc;
va_start(ap, zFormat);
rc = PH7_VmOutputConsumeAp(pCtx->pVm, zFormat, ap);
va_end(ap);
return rc;
}
/*
* [CAPIREF: ph7_context_random_num()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
unsigned int ph7_context_random_num(ph7_context *pCtx) {
sxu32 n;
n = PH7_VmRandomNum(pCtx->pVm);
return n;
}
/*
* [CAPIREF: ph7_context_random_string()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_context_random_string(ph7_context *pCtx, char *zBuf, int nBuflen) {
if(nBuflen < 3) {
return PH7_CORRUPT;
}
PH7_VmRandomString(pCtx->pVm, zBuf, nBuflen);
return PH7_OK;
}
/*
* IMP-12-07-2012 02:10 Experimantal public API.
*
* ph7_vm * ph7_context_get_vm(ph7_context *pCtx)
* {
* return pCtx->pVm;
* }
*/
/*
* [CAPIREF: ph7_context_user_data()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
void *ph7_context_user_data(ph7_context *pCtx) {
return pCtx->pFunc->pUserData;
}
/*
* [CAPIREF: ph7_context_push_aux_data()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_context_push_aux_data(ph7_context *pCtx, void *pUserData) {
ph7_aux_data sAux;
int rc;
sAux.pAuxData = pUserData;
rc = SySetPut(&pCtx->pFunc->aAux, (const void *)&sAux);
return rc;
}
/*
* [CAPIREF: ph7_context_peek_aux_data()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
void *ph7_context_peek_aux_data(ph7_context *pCtx) {
ph7_aux_data *pAux;
pAux = (ph7_aux_data *)SySetPeek(&pCtx->pFunc->aAux);
return pAux ? pAux->pAuxData : 0;
}
/*
* [CAPIREF: ph7_context_pop_aux_data()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
void *ph7_context_pop_aux_data(ph7_context *pCtx) {
ph7_aux_data *pAux;
pAux = (ph7_aux_data *)SySetPop(&pCtx->pFunc->aAux);
return pAux ? pAux->pAuxData : 0;
}
/*
* [CAPIREF: ph7_context_result_buf_length()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
unsigned int ph7_context_result_buf_length(ph7_context *pCtx) {
return SyBlobLength(&pCtx->pRet->sBlob);
}
/*
* [CAPIREF: ph7_function_name()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
const char *ph7_function_name(ph7_context *pCtx) {
SyString *pName;
pName = &pCtx->pFunc->sName;
return pName->zString;
}
/*
* [CAPIREF: ph7_value_int()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_value_int(ph7_value *pVal, int iValue) {
/* Invalidate any prior representation */
PH7_MemObjRelease(pVal);
pVal->x.iVal = (ph7_int64)iValue;
MemObjSetType(pVal, MEMOBJ_INT);
return PH7_OK;
}
/*
* [CAPIREF: ph7_value_int64()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_value_int64(ph7_value *pVal, ph7_int64 iValue) {
/* Invalidate any prior representation */
PH7_MemObjRelease(pVal);
pVal->x.iVal = iValue;
MemObjSetType(pVal, MEMOBJ_INT);
return PH7_OK;
}
/*
* [CAPIREF: ph7_value_bool()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_value_bool(ph7_value *pVal, int iBool) {
/* Invalidate any prior representation */
PH7_MemObjRelease(pVal);
pVal->x.iVal = iBool ? 1 : 0;
MemObjSetType(pVal, MEMOBJ_BOOL);
return PH7_OK;
}
/*
* [CAPIREF: ph7_value_null()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_value_null(ph7_value *pVal) {
/* Invalidate any prior representation and set the NULL flag */
PH7_MemObjRelease(pVal);
return PH7_OK;
}
/*
* [CAPIREF: ph7_value_double()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_value_double(ph7_value *pVal, double Value) {
/* Invalidate any prior representation */
PH7_MemObjRelease(pVal);
pVal->x.rVal = (ph7_real)Value;
MemObjSetType(pVal, MEMOBJ_REAL);
return PH7_OK;
}
/*
* [CAPIREF: ph7_value_string()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_value_string(ph7_value *pVal, const char *zString, int nLen) {
if((pVal->iFlags & MEMOBJ_STRING) == 0) {
/* Invalidate any prior representation */
PH7_MemObjRelease(pVal);
MemObjSetType(pVal, MEMOBJ_STRING);
}
if(zString) {
if(nLen < 0) {
/* Compute length automatically */
nLen = (int)SyStrlen(zString);
}
SyBlobAppend(&pVal->sBlob, (const void *)zString, (sxu32)nLen);
}
return PH7_OK;
}
/*
* [CAPIREF: ph7_value_string_format()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_value_string_format(ph7_value *pVal, const char *zFormat, ...) {
va_list ap;
int rc;
if((pVal->iFlags & MEMOBJ_STRING) == 0) {
/* Invalidate any prior representation */
PH7_MemObjRelease(pVal);
MemObjSetType(pVal, MEMOBJ_STRING);
}
va_start(ap, zFormat);
rc = SyBlobFormatAp(&pVal->sBlob, zFormat, ap);
va_end(ap);
return PH7_OK;
}
/*
* [CAPIREF: ph7_value_reset_string_cursor()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_value_reset_string_cursor(ph7_value *pVal) {
/* Reset the string cursor */
SyBlobReset(&pVal->sBlob);
return PH7_OK;
}
/*
* [CAPIREF: ph7_value_resource()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_value_resource(ph7_value *pVal, void *pUserData) {
/* Invalidate any prior representation */
PH7_MemObjRelease(pVal);
/* Reflect the new type */
pVal->x.pOther = pUserData;
MemObjSetType(pVal, MEMOBJ_RES);
return PH7_OK;
}
/*
* [CAPIREF: ph7_value_release()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_value_release(ph7_value *pVal) {
PH7_MemObjRelease(pVal);
return PH7_OK;
}
/*
* [CAPIREF: ph7_value_is_int()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_value_is_int(ph7_value *pVal) {
return (pVal->iFlags & MEMOBJ_INT) ? TRUE : FALSE;
}
/*
* [CAPIREF: ph7_value_is_float()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_value_is_float(ph7_value *pVal) {
return (pVal->iFlags & MEMOBJ_REAL) ? TRUE : FALSE;
}
/*
* [CAPIREF: ph7_value_is_bool()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_value_is_bool(ph7_value *pVal) {
return (pVal->iFlags & MEMOBJ_BOOL) ? TRUE : FALSE;
}
/*
* [CAPIREF: ph7_value_is_string()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_value_is_string(ph7_value *pVal) {
return (pVal->iFlags & MEMOBJ_STRING) ? TRUE : FALSE;
}
/*
* [CAPIREF: ph7_value_is_null()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_value_is_null(ph7_value *pVal) {
return (pVal->iFlags & MEMOBJ_NULL) ? TRUE : FALSE;
}
/*
* [CAPIREF: ph7_value_is_numeric()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_value_is_numeric(ph7_value *pVal) {
int rc;
rc = PH7_MemObjIsNumeric(pVal);
return rc;
}
/*
* [CAPIREF: ph7_value_is_callable()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_value_is_callable(ph7_value *pVal) {
int rc;
rc = PH7_VmIsCallable(pVal->pVm, pVal, FALSE);
return rc;
}
/*
* [CAPIREF: ph7_value_is_scalar()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_value_is_scalar(ph7_value *pVal) {
return (pVal->iFlags & MEMOBJ_SCALAR) ? TRUE : FALSE;
}
/*
* [CAPIREF: ph7_value_is_array()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_value_is_array(ph7_value *pVal) {
return (pVal->iFlags & MEMOBJ_HASHMAP) ? TRUE : FALSE;
}
/*
* [CAPIREF: ph7_value_is_object()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_value_is_object(ph7_value *pVal) {
return (pVal->iFlags & MEMOBJ_OBJ) ? TRUE : FALSE;
}
/*
* [CAPIREF: ph7_value_is_resource()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_value_is_resource(ph7_value *pVal) {
return (pVal->iFlags & MEMOBJ_RES) ? TRUE : FALSE;
}
/*
* [CAPIREF: ph7_value_is_empty()]
* Please refer to the official documentation for function purpose and expected parameters.
*/
int ph7_value_is_empty(ph7_value *pVal) {
int rc;
rc = PH7_MemObjIsEmpty(pVal);
return rc;
}