/* * 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 $ */ #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_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_ident()] * Please refer to the official documentation for function purpose and expected parameters. */ const char * ph7_lib_ident(void) { return PH7_IDENT; } /* * [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 */ #endif #if defined(PH7_ENABLE_THREADS) /* 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; } /* * 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 ProcessScript( ph7 *pEngine, /* Running PH7 engine */ ph7_vm **ppVm, /* OUT: A pointer to the virtual machine */ SyString *pScript, /* Raw PHP script to compile */ sxi32 iFlags, /* Compile-time flags */ const char *zFilePath /* File path if script come from a file. NULL otherwise */ ) { ph7_vm *pVm; int rc; /* 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( ppVm ){ *ppVm = 0; } return PH7_NOMEM; } if( iFlags < 0 ){ /* Default compile-time flags */ iFlags = 0; } /* Initialize the Virtual Machine */ rc = PH7_VmInit(pVm,&(*pEngine)); if( rc != PH7_OK ){ SyMemBackendPoolFree(&pEngine->sAllocator,pVm); if( ppVm ){ *ppVm = 0; } return PH7_VM_ERR; } if( zFilePath ){ /* Push processed file path */ PH7_VmPushFilePath(pVm,zFilePath,-1,TRUE,0); } /* Reset the error message consumer */ SyBlobReset(&pEngine->xConf.sErrConsumer); /* Compile the script */ PH7_CompileScript(pVm,&(*pScript),iFlags); 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; } /* Install local import path which is the current directory */ ph7_vm_config(pVm,PH7_VM_CONFIG_IMPORT_PATH,"./"); #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++; /* Point to the freshly created VM */ *ppVm = pVm; /* 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(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 = ProcessScript(&(*pEngine),ppOutVm,&sScript,0,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_v2()] * Please refer to the official documentation for function purpose and expected parameters. */ int ph7_compile_v2(ph7 *pEngine,const char *zSource,int nLen,ph7_vm **ppOutVm,int iFlags) { 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 = ProcessScript(&(*pEngine),ppOutVm,&sScript,iFlags,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,int iFlags) { const ph7_vfs *pVfs; int rc; if( ppOutVm ){ *ppOutVm = 0; } 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 = ProcessScript(&(*pEngine),ppOutVm,&sScript,iFlags,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_v2()] * Please refer to the official documentation for function purpose and expected parameters. */ int ph7_vm_dump_v2(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 /* Confiugure 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->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_throw_error()] * Please refer to the official documentation for function purpose and expected parameters. */ int ph7_context_throw_error(ph7_context *pCtx,int iErr,const char *zErr) { int rc = PH7_OK; if( zErr ){ rc = PH7_VmThrowError(pCtx->pVm,&pCtx->pFunc->sName,iErr,zErr); } return rc; } /* * [CAPIREF: ph7_context_throw_error_format()] * Please refer to the official documentation for function purpose and expected parameters. */ int ph7_context_throw_error_format(ph7_context *pCtx,int iErr,const char *zFormat,...) { va_list ap; int rc; if( zFormat == 0){ return PH7_OK; } va_start(ap,zFormat); rc = PH7_VmThrowErrorAp(pCtx->pVm,&pCtx->pFunc->sName,iErr,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->rVal = (ph7_real)Value; MemObjSetType(pVal,MEMOBJ_REAL); /* Try to get an integer representation also */ PH7_MemObjTryInteger(pVal); 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; }