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

1972 lines
61 KiB

3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
  1. /*
  2. * Symisc PH7: An embeddable bytecode compiler and a virtual machine for the PHP(5) programming language.
  3. * Copyright (C) 2011-2012, Symisc Systems http://ph7.symisc.net/
  4. * Version 2.1.4
  5. * For information on licensing,redistribution of this file,and for a DISCLAIMER OF ALL WARRANTIES
  6. * please contact Symisc Systems via:
  7. * legal@symisc.net
  8. * licensing@symisc.net
  9. * contact@symisc.net
  10. * or visit:
  11. * http://ph7.symisc.net/
  12. */
  13. /* $SymiscID: api.c v2.0 FreeBSD 2012-08-18 06:54 stable <chm@symisc.net> $ */
  14. #include "ph7int.h"
  15. /* This file implement the public interfaces presented to host-applications.
  16. * Routines in other files are for internal use by PH7 and should not be
  17. * accessed by users of the library.
  18. */
  19. #define PH7_ENGINE_MAGIC 0xF874BCD7
  20. #define PH7_ENGINE_MISUSE(ENGINE) (ENGINE == 0 || ENGINE->nMagic != PH7_ENGINE_MAGIC)
  21. #define PH7_VM_MISUSE(VM) (VM == 0 || VM->nMagic == PH7_VM_STALE)
  22. /* If another thread have released a working instance,the following macros
  23. * evaluates to true. These macros are only used when the library
  24. * is built with threading support enabled which is not the case in
  25. * the default built.
  26. */
  27. #define PH7_THRD_ENGINE_RELEASE(ENGINE) (ENGINE->nMagic != PH7_ENGINE_MAGIC)
  28. #define PH7_THRD_VM_RELEASE(VM) (VM->nMagic == PH7_VM_STALE)
  29. /* IMPLEMENTATION: ph7@embedded@symisc 311-12-32 */
  30. /*
  31. * All global variables are collected in the structure named "sMPGlobal".
  32. * That way it is clear in the code when we are using static variable because
  33. * its name start with sMPGlobal.
  34. */
  35. static struct Global_Data {
  36. SyMemBackend sAllocator; /* Global low level memory allocator */
  37. #if defined(PH7_ENABLE_THREADS)
  38. const SyMutexMethods *pMutexMethods; /* Mutex methods */
  39. SyMutex *pMutex; /* Global mutex */
  40. sxu32 nThreadingLevel; /* Threading level: 0 == Single threaded/1 == Multi-Threaded
  41. * The threading level can be set using the [ph7_lib_config()]
  42. * interface with a configuration verb set to
  43. * PH7_LIB_CONFIG_THREAD_LEVEL_SINGLE or
  44. * PH7_LIB_CONFIG_THREAD_LEVEL_MULTI
  45. */
  46. #endif
  47. const ph7_vfs *pVfs; /* Underlying virtual file system */
  48. sxi32 nEngine; /* Total number of active engines */
  49. ph7 *pEngines; /* List of active engine */
  50. sxu32 nMagic; /* Sanity check against library misuse */
  51. } sMPGlobal = {
  52. {0, 0, 0, 0, 0, 0, 0, 0, {0}},
  53. #if defined(PH7_ENABLE_THREADS)
  54. 0,
  55. 0,
  56. 0,
  57. #endif
  58. 0,
  59. 0,
  60. 0,
  61. 0
  62. };
  63. #define PH7_LIB_MAGIC 0xEA1495BA
  64. /*
  65. * Supported threading level.
  66. * These options have meaning only when the library is compiled with multi-threading
  67. * support.That is,the PH7_ENABLE_THREADS compile time directive must be defined
  68. * when PH7 is built.
  69. * PH7_THREAD_LEVEL_SINGLE:
  70. * In this mode,mutexing is disabled and the library can only be used by a single thread.
  71. * PH7_THREAD_LEVEL_MULTI
  72. * In this mode, all mutexes including the recursive mutexes on [ph7] objects
  73. * are enabled so that the application is free to share the same engine
  74. * between different threads at the same time.
  75. */
  76. #define PH7_THREAD_LEVEL_SINGLE 1
  77. #define PH7_THREAD_LEVEL_MULTI 2
  78. /*
  79. * Configure a running PH7 engine instance.
  80. * return PH7_OK on success.Any other return
  81. * value indicates failure.
  82. * Refer to [ph7_config()].
  83. */
  84. static sxi32 EngineConfig(ph7 *pEngine, sxi32 nOp, va_list ap) {
  85. ph7_conf *pConf = &pEngine->xConf;
  86. int rc = PH7_OK;
  87. /* Perform the requested operation */
  88. switch(nOp) {
  89. case PH7_CONFIG_ERR_OUTPUT: {
  90. ProcConsumer xConsumer = va_arg(ap, ProcConsumer);
  91. void *pUserData = va_arg(ap, void *);
  92. /* Compile time error consumer routine */
  93. if(xConsumer == 0) {
  94. rc = PH7_CORRUPT;
  95. break;
  96. }
  97. /* Install the error consumer */
  98. pConf->xErr = xConsumer;
  99. pConf->pErrData = pUserData;
  100. break;
  101. }
  102. case PH7_CONFIG_ERR_LOG: {
  103. /* Extract compile-time error log if any */
  104. const char **pzPtr = va_arg(ap, const char **);
  105. int *pLen = va_arg(ap, int *);
  106. if(pzPtr == 0) {
  107. rc = PH7_CORRUPT;
  108. break;
  109. }
  110. /* NULL terminate the error-log buffer */
  111. SyBlobNullAppend(&pConf->sErrConsumer);
  112. /* Point to the error-log buffer */
  113. *pzPtr = (const char *)SyBlobData(&pConf->sErrConsumer);
  114. if(pLen) {
  115. if(SyBlobLength(&pConf->sErrConsumer) > 1 /* NULL '\0' terminator */) {
  116. *pLen = (int)SyBlobLength(&pConf->sErrConsumer);
  117. } else {
  118. *pLen = 0;
  119. }
  120. }
  121. break;
  122. }
  123. case PH7_CONFIG_ERR_ABORT:
  124. /* Reserved for future use */
  125. break;
  126. default:
  127. /* Unknown configuration verb */
  128. rc = PH7_CORRUPT;
  129. break;
  130. } /* Switch() */
  131. return rc;
  132. }
  133. /*
  134. * Configure the PH7 library.
  135. * return PH7_OK on success.Any other return value
  136. * indicates failure.
  137. * Refer to [ph7_lib_config()].
  138. */
  139. static sxi32 PH7CoreConfigure(sxi32 nOp, va_list ap) {
  140. int rc = PH7_OK;
  141. switch(nOp) {
  142. case PH7_LIB_CONFIG_VFS: {
  143. /* Install a virtual file system */
  144. const ph7_vfs *pVfs = va_arg(ap, const ph7_vfs *);
  145. sMPGlobal.pVfs = pVfs;
  146. break;
  147. }
  148. case PH7_LIB_CONFIG_USER_MALLOC: {
  149. /* Use an alternative low-level memory allocation routines */
  150. const SyMemMethods *pMethods = va_arg(ap, const SyMemMethods *);
  151. /* Save the memory failure callback (if available) */
  152. ProcMemError xMemErr = sMPGlobal.sAllocator.xMemError;
  153. void *pMemErr = sMPGlobal.sAllocator.pUserData;
  154. if(pMethods == 0) {
  155. /* Use the built-in memory allocation subsystem */
  156. rc = SyMemBackendInit(&sMPGlobal.sAllocator, xMemErr, pMemErr);
  157. } else {
  158. rc = SyMemBackendInitFromOthers(&sMPGlobal.sAllocator, pMethods, xMemErr, pMemErr);
  159. }
  160. break;
  161. }
  162. case PH7_LIB_CONFIG_MEM_ERR_CALLBACK: {
  163. /* Memory failure callback */
  164. ProcMemError xMemErr = va_arg(ap, ProcMemError);
  165. void *pUserData = va_arg(ap, void *);
  166. sMPGlobal.sAllocator.xMemError = xMemErr;
  167. sMPGlobal.sAllocator.pUserData = pUserData;
  168. break;
  169. }
  170. case PH7_LIB_CONFIG_USER_MUTEX: {
  171. #if defined(PH7_ENABLE_THREADS)
  172. /* Use an alternative low-level mutex subsystem */
  173. const SyMutexMethods *pMethods = va_arg(ap, const SyMutexMethods *);
  174. #if defined (UNTRUST)
  175. if(pMethods == 0) {
  176. rc = PH7_CORRUPT;
  177. }
  178. #endif
  179. /* Sanity check */
  180. if(pMethods->xEnter == 0 || pMethods->xLeave == 0 || pMethods->xNew == 0) {
  181. /* At least three criticial callbacks xEnter(),xLeave() and xNew() must be supplied */
  182. rc = PH7_CORRUPT;
  183. break;
  184. }
  185. if(sMPGlobal.pMutexMethods) {
  186. /* Overwrite the previous mutex subsystem */
  187. SyMutexRelease(sMPGlobal.pMutexMethods, sMPGlobal.pMutex);
  188. if(sMPGlobal.pMutexMethods->xGlobalRelease) {
  189. sMPGlobal.pMutexMethods->xGlobalRelease();
  190. }
  191. sMPGlobal.pMutex = 0;
  192. }
  193. /* Initialize and install the new mutex subsystem */
  194. if(pMethods->xGlobalInit) {
  195. rc = pMethods->xGlobalInit();
  196. if(rc != PH7_OK) {
  197. break;
  198. }
  199. }
  200. /* Create the global mutex */
  201. sMPGlobal.pMutex = pMethods->xNew(SXMUTEX_TYPE_FAST);
  202. if(sMPGlobal.pMutex == 0) {
  203. /*
  204. * If the supplied mutex subsystem is so sick that we are unable to
  205. * create a single mutex,there is no much we can do here.
  206. */
  207. if(pMethods->xGlobalRelease) {
  208. pMethods->xGlobalRelease();
  209. }
  210. rc = PH7_CORRUPT;
  211. break;
  212. }
  213. sMPGlobal.pMutexMethods = pMethods;
  214. if(sMPGlobal.nThreadingLevel == 0) {
  215. /* Set a default threading level */
  216. sMPGlobal.nThreadingLevel = PH7_THREAD_LEVEL_MULTI;
  217. }
  218. #endif
  219. break;
  220. }
  221. case PH7_LIB_CONFIG_THREAD_LEVEL_SINGLE:
  222. #if defined(PH7_ENABLE_THREADS)
  223. /* Single thread mode(Only one thread is allowed to play with the library) */
  224. sMPGlobal.nThreadingLevel = PH7_THREAD_LEVEL_SINGLE;
  225. #endif
  226. break;
  227. case PH7_LIB_CONFIG_THREAD_LEVEL_MULTI:
  228. #if defined(PH7_ENABLE_THREADS)
  229. /* Multi-threading mode (library is thread safe and PH7 engines and virtual machines
  230. * may be shared between multiple threads).
  231. */
  232. sMPGlobal.nThreadingLevel = PH7_THREAD_LEVEL_MULTI;
  233. #endif
  234. break;
  235. default:
  236. /* Unknown configuration option */
  237. rc = PH7_CORRUPT;
  238. break;
  239. }
  240. return rc;
  241. }
  242. /*
  243. * [CAPIREF: ph7_lib_config()]
  244. * Please refer to the official documentation for function purpose and expected parameters.
  245. */
  246. int ph7_lib_config(int nConfigOp, ...) {
  247. va_list ap;
  248. int rc;
  249. if(sMPGlobal.nMagic == PH7_LIB_MAGIC) {
  250. /* Library is already initialized,this operation is forbidden */
  251. return PH7_LOOKED;
  252. }
  253. va_start(ap, nConfigOp);
  254. rc = PH7CoreConfigure(nConfigOp, ap);
  255. va_end(ap);
  256. return rc;
  257. }
  258. /*
  259. * Global library initialization
  260. * Refer to [ph7_lib_init()]
  261. * This routine must be called to initialize the memory allocation subsystem,the mutex
  262. * subsystem prior to doing any serious work with the library.The first thread to call
  263. * this routine does the initialization process and set the magic number so no body later
  264. * can re-initialize the library.If subsequent threads call this routine before the first
  265. * thread have finished the initialization process, then the subsequent threads must block
  266. * until the initialization process is done.
  267. */
  268. static sxi32 PH7CoreInitialize(void) {
  269. const ph7_vfs *pVfs; /* Built-in vfs */
  270. #if defined(PH7_ENABLE_THREADS)
  271. const SyMutexMethods *pMutexMethods = 0;
  272. SyMutex *pMaster = 0;
  273. #endif
  274. int rc;
  275. /*
  276. * If the library is already initialized,then a call to this routine
  277. * is a no-op.
  278. */
  279. if(sMPGlobal.nMagic == PH7_LIB_MAGIC) {
  280. return PH7_OK; /* Already initialized */
  281. }
  282. /* Point to the built-in vfs */
  283. pVfs = PH7_ExportBuiltinVfs();
  284. /* Install it */
  285. ph7_lib_config(PH7_LIB_CONFIG_VFS, pVfs);
  286. #if defined(PH7_ENABLE_THREADS)
  287. if(sMPGlobal.nThreadingLevel != PH7_THREAD_LEVEL_SINGLE) {
  288. pMutexMethods = sMPGlobal.pMutexMethods;
  289. if(pMutexMethods == 0) {
  290. /* Use the built-in mutex subsystem */
  291. pMutexMethods = SyMutexExportMethods();
  292. if(pMutexMethods == 0) {
  293. return PH7_CORRUPT; /* Can't happen */
  294. }
  295. /* Install the mutex subsystem */
  296. rc = ph7_lib_config(PH7_LIB_CONFIG_USER_MUTEX, pMutexMethods);
  297. if(rc != PH7_OK) {
  298. return rc;
  299. }
  300. }
  301. /* Obtain a static mutex so we can initialize the library without calling malloc() */
  302. pMaster = SyMutexNew(pMutexMethods, SXMUTEX_TYPE_STATIC_1);
  303. if(pMaster == 0) {
  304. return PH7_CORRUPT; /* Can't happen */
  305. }
  306. }
  307. /* Lock the master mutex */
  308. rc = PH7_OK;
  309. SyMutexEnter(pMutexMethods, pMaster); /* NO-OP if sMPGlobal.nThreadingLevel == PH7_THREAD_LEVEL_SINGLE */
  310. if(sMPGlobal.nMagic != PH7_LIB_MAGIC) {
  311. #endif
  312. if(sMPGlobal.sAllocator.pMethods == 0) {
  313. /* Install a memory subsystem */
  314. rc = ph7_lib_config(PH7_LIB_CONFIG_USER_MALLOC, 0); /* zero mean use the built-in memory backend */
  315. if(rc != PH7_OK) {
  316. /* If we are unable to initialize the memory backend,there is no much we can do here.*/
  317. goto End;
  318. }
  319. }
  320. #if defined(PH7_ENABLE_THREADS)
  321. if(sMPGlobal.nThreadingLevel > PH7_THREAD_LEVEL_SINGLE) {
  322. /* Protect the memory allocation subsystem */
  323. rc = SyMemBackendMakeThreadSafe(&sMPGlobal.sAllocator, sMPGlobal.pMutexMethods);
  324. if(rc != PH7_OK) {
  325. goto End;
  326. }
  327. }
  328. #endif
  329. /* Our library is initialized,set the magic number */
  330. sMPGlobal.nMagic = PH7_LIB_MAGIC;
  331. rc = PH7_OK;
  332. #if defined(PH7_ENABLE_THREADS)
  333. } /* sMPGlobal.nMagic != PH7_LIB_MAGIC */
  334. #endif
  335. End:
  336. #if defined(PH7_ENABLE_THREADS)
  337. /* Unlock the master mutex */
  338. SyMutexLeave(pMutexMethods, pMaster); /* NO-OP if sMPGlobal.nThreadingLevel == PH7_THREAD_LEVEL_SINGLE */
  339. #endif
  340. return rc;
  341. }
  342. /*
  343. * [CAPIREF: ph7_lib_init()]
  344. * Please refer to the official documentation for function purpose and expected parameters.
  345. */
  346. int ph7_lib_init(void) {
  347. int rc;
  348. rc = PH7CoreInitialize();
  349. return rc;
  350. }
  351. /*
  352. * Release an active PH7 engine and it's associated active virtual machines.
  353. */
  354. static sxi32 EngineRelease(ph7 *pEngine) {
  355. ph7_vm *pVm, *pNext;
  356. /* Release all active VM */
  357. pVm = pEngine->pVms;
  358. for(;;) {
  359. if(pEngine->iVm <= 0) {
  360. break;
  361. }
  362. pNext = pVm->pNext;
  363. PH7_VmRelease(pVm);
  364. pVm = pNext;
  365. pEngine->iVm--;
  366. }
  367. /* Set a dummy magic number */
  368. pEngine->nMagic = 0x7635;
  369. /* Release the private memory subsystem */
  370. SyMemBackendRelease(&pEngine->sAllocator);
  371. return PH7_OK;
  372. }
  373. /*
  374. * Release all resources consumed by the library.
  375. * If PH7 is already shut down when this routine
  376. * is invoked then this routine is a harmless no-op.
  377. * Note: This call is not thread safe.
  378. * Refer to [ph7_lib_shutdown()].
  379. */
  380. static void PH7CoreShutdown(void) {
  381. ph7 *pEngine, *pNext;
  382. /* Release all active engines first */
  383. pEngine = sMPGlobal.pEngines;
  384. for(;;) {
  385. if(sMPGlobal.nEngine < 1) {
  386. break;
  387. }
  388. pNext = pEngine->pNext;
  389. EngineRelease(pEngine);
  390. pEngine = pNext;
  391. sMPGlobal.nEngine--;
  392. }
  393. #if defined(PH7_ENABLE_THREADS)
  394. /* Release the mutex subsystem */
  395. if(sMPGlobal.pMutexMethods) {
  396. if(sMPGlobal.pMutex) {
  397. SyMutexRelease(sMPGlobal.pMutexMethods, sMPGlobal.pMutex);
  398. sMPGlobal.pMutex = 0;
  399. }
  400. if(sMPGlobal.pMutexMethods->xGlobalRelease) {
  401. sMPGlobal.pMutexMethods->xGlobalRelease();
  402. }
  403. sMPGlobal.pMutexMethods = 0;
  404. }
  405. sMPGlobal.nThreadingLevel = 0;
  406. #endif
  407. if(sMPGlobal.sAllocator.pMethods) {
  408. /* Release the memory backend */
  409. SyMemBackendRelease(&sMPGlobal.sAllocator);
  410. }
  411. sMPGlobal.nMagic = 0x1928;
  412. }
  413. /*
  414. * [CAPIREF: ph7_lib_shutdown()]
  415. * Please refer to the official documentation for function purpose and expected parameters.
  416. */
  417. int ph7_lib_shutdown(void) {
  418. if(sMPGlobal.nMagic != PH7_LIB_MAGIC) {
  419. /* Already shut */
  420. return PH7_OK;
  421. }
  422. PH7CoreShutdown();
  423. return PH7_OK;
  424. }
  425. /*
  426. * [CAPIREF: ph7_lib_is_threadsafe()]
  427. * Please refer to the official documentation for function purpose and expected parameters.
  428. */
  429. int ph7_lib_is_threadsafe(void) {
  430. if(sMPGlobal.nMagic != PH7_LIB_MAGIC) {
  431. return 0;
  432. }
  433. #if defined(PH7_ENABLE_THREADS)
  434. if(sMPGlobal.nThreadingLevel > PH7_THREAD_LEVEL_SINGLE) {
  435. /* Muli-threading support is enabled */
  436. return 1;
  437. } else {
  438. /* Single-threading */
  439. return 0;
  440. }
  441. #else
  442. return 0;
  443. #endif
  444. }
  445. /*
  446. * [CAPIREF: ph7_lib_version()]
  447. * Please refer to the official documentation for function purpose and expected parameters.
  448. */
  449. const char *ph7_lib_version(void) {
  450. return PH7_VERSION;
  451. }
  452. /*
  453. * [CAPIREF: ph7_lib_signature()]
  454. * Please refer to the official documentation for function purpose and expected parameters.
  455. */
  456. const char *ph7_lib_signature(void) {
  457. return PH7_SIG;
  458. }
  459. /*
  460. * [CAPIREF: ph7_lib_ident()]
  461. * Please refer to the official documentation for function purpose and expected parameters.
  462. */
  463. const char *ph7_lib_ident(void) {
  464. return PH7_IDENT;
  465. }
  466. /*
  467. * [CAPIREF: ph7_lib_copyright()]
  468. * Please refer to the official documentation for function purpose and expected parameters.
  469. */
  470. const char *ph7_lib_copyright(void) {
  471. return PH7_COPYRIGHT;
  472. }
  473. /*
  474. * [CAPIREF: ph7_config()]
  475. * Please refer to the official documentation for function purpose and expected parameters.
  476. */
  477. int ph7_config(ph7 *pEngine, int nConfigOp, ...) {
  478. va_list ap;
  479. int rc;
  480. if(PH7_ENGINE_MISUSE(pEngine)) {
  481. return PH7_CORRUPT;
  482. }
  483. #if defined(PH7_ENABLE_THREADS)
  484. /* Acquire engine mutex */
  485. SyMutexEnter(sMPGlobal.pMutexMethods, pEngine->pMutex); /* NO-OP if sMPGlobal.nThreadingLevel != PH7_THREAD_LEVEL_MULTI */
  486. if(sMPGlobal.nThreadingLevel > PH7_THREAD_LEVEL_SINGLE &&
  487. PH7_THRD_ENGINE_RELEASE(pEngine)) {
  488. return PH7_ABORT; /* Another thread have released this instance */
  489. }
  490. #endif
  491. va_start(ap, nConfigOp);
  492. rc = EngineConfig(&(*pEngine), nConfigOp, ap);
  493. va_end(ap);
  494. #if defined(PH7_ENABLE_THREADS)
  495. /* Leave engine mutex */
  496. SyMutexLeave(sMPGlobal.pMutexMethods, pEngine->pMutex); /* NO-OP if sMPGlobal.nThreadingLevel != PH7_THREAD_LEVEL_MULTI */
  497. #endif
  498. return rc;
  499. }
  500. /*
  501. * [CAPIREF: ph7_init()]
  502. * Please refer to the official documentation for function purpose and expected parameters.
  503. */
  504. int ph7_init(ph7 **ppEngine) {
  505. ph7 *pEngine;
  506. int rc;
  507. #if defined(UNTRUST)
  508. if(ppEngine == 0) {
  509. return PH7_CORRUPT;
  510. }
  511. #endif
  512. *ppEngine = 0;
  513. /* One-time automatic library initialization */
  514. rc = PH7CoreInitialize();
  515. if(rc != PH7_OK) {
  516. return rc;
  517. }
  518. /* Allocate a new engine */
  519. pEngine = (ph7 *)SyMemBackendPoolAlloc(&sMPGlobal.sAllocator, sizeof(ph7));
  520. if(pEngine == 0) {
  521. return PH7_NOMEM;
  522. }
  523. /* Zero the structure */
  524. SyZero(pEngine, sizeof(ph7));
  525. /* Initialize engine fields */
  526. pEngine->nMagic = PH7_ENGINE_MAGIC;
  527. rc = SyMemBackendInitFromParent(&pEngine->sAllocator, &sMPGlobal.sAllocator);
  528. if(rc != PH7_OK) {
  529. goto Release;
  530. }
  531. #if defined(PH7_ENABLE_THREADS)
  532. SyMemBackendDisbaleMutexing(&pEngine->sAllocator);
  533. #endif
  534. /* Default configuration */
  535. SyBlobInit(&pEngine->xConf.sErrConsumer, &pEngine->sAllocator);
  536. /* Install a default compile-time error consumer routine */
  537. ph7_config(pEngine, PH7_CONFIG_ERR_OUTPUT, PH7_VmBlobConsumer, &pEngine->xConf.sErrConsumer);
  538. /* Built-in vfs */
  539. pEngine->pVfs = sMPGlobal.pVfs;
  540. #if defined(PH7_ENABLE_THREADS)
  541. if(sMPGlobal.nThreadingLevel > PH7_THREAD_LEVEL_SINGLE) {
  542. /* Associate a recursive mutex with this instance */
  543. pEngine->pMutex = SyMutexNew(sMPGlobal.pMutexMethods, SXMUTEX_TYPE_RECURSIVE);
  544. if(pEngine->pMutex == 0) {
  545. rc = PH7_NOMEM;
  546. goto Release;
  547. }
  548. }
  549. #endif
  550. /* Link to the list of active engines */
  551. #if defined(PH7_ENABLE_THREADS)
  552. /* Enter the global mutex */
  553. SyMutexEnter(sMPGlobal.pMutexMethods, sMPGlobal.pMutex); /* NO-OP if sMPGlobal.nThreadingLevel == PH7_THREAD_LEVEL_SINGLE */
  554. #endif
  555. MACRO_LD_PUSH(sMPGlobal.pEngines, pEngine);
  556. sMPGlobal.nEngine++;
  557. #if defined(PH7_ENABLE_THREADS)
  558. /* Leave the global mutex */
  559. SyMutexLeave(sMPGlobal.pMutexMethods, sMPGlobal.pMutex); /* NO-OP if sMPGlobal.nThreadingLevel == PH7_THREAD_LEVEL_SINGLE */
  560. #endif
  561. /* Write a pointer to the new instance */
  562. *ppEngine = pEngine;
  563. return PH7_OK;
  564. Release:
  565. SyMemBackendRelease(&pEngine->sAllocator);
  566. SyMemBackendPoolFree(&sMPGlobal.sAllocator, pEngine);
  567. return rc;
  568. }
  569. /*
  570. * [CAPIREF: ph7_release()]
  571. * Please refer to the official documentation for function purpose and expected parameters.
  572. */
  573. int ph7_release(ph7 *pEngine) {
  574. int rc;
  575. if(PH7_ENGINE_MISUSE(pEngine)) {
  576. return PH7_CORRUPT;
  577. }
  578. #if defined(PH7_ENABLE_THREADS)
  579. /* Acquire engine mutex */
  580. SyMutexEnter(sMPGlobal.pMutexMethods, pEngine->pMutex); /* NO-OP if sMPGlobal.nThreadingLevel != PH7_THREAD_LEVEL_MULTI */
  581. if(sMPGlobal.nThreadingLevel > PH7_THREAD_LEVEL_SINGLE &&
  582. PH7_THRD_ENGINE_RELEASE(pEngine)) {
  583. return PH7_ABORT; /* Another thread have released this instance */
  584. }
  585. #endif
  586. /* Release the engine */
  587. rc = EngineRelease(&(*pEngine));
  588. #if defined(PH7_ENABLE_THREADS)
  589. /* Leave engine mutex */
  590. SyMutexLeave(sMPGlobal.pMutexMethods, pEngine->pMutex); /* NO-OP if sMPGlobal.nThreadingLevel != PH7_THREAD_LEVEL_MULTI */
  591. /* Release engine mutex */
  592. SyMutexRelease(sMPGlobal.pMutexMethods, pEngine->pMutex) /* NO-OP if sMPGlobal.nThreadingLevel != PH7_THREAD_LEVEL_MULTI */
  593. /* Enter the global mutex */
  594. SyMutexEnter(sMPGlobal.pMutexMethods, sMPGlobal.pMutex); /* NO-OP if sMPGlobal.nThreadingLevel == PH7_THREAD_LEVEL_SINGLE */
  595. #endif
  596. /* Unlink from the list of active engines */
  597. MACRO_LD_REMOVE(sMPGlobal.pEngines, pEngine);
  598. sMPGlobal.nEngine--;
  599. #if defined(PH7_ENABLE_THREADS)
  600. /* Leave the global mutex */
  601. SyMutexLeave(sMPGlobal.pMutexMethods, sMPGlobal.pMutex); /* NO-OP if sMPGlobal.nThreadingLevel == PH7_THREAD_LEVEL_SINGLE */
  602. #endif
  603. /* Release the memory chunk allocated to this engine */
  604. SyMemBackendPoolFree(&sMPGlobal.sAllocator, pEngine);
  605. return rc;
  606. }
  607. /*
  608. * Compile a raw PHP script.
  609. * To execute a PHP code, it must first be compiled into a byte-code program using this routine.
  610. * If something goes wrong [i.e: compile-time error], your error log [i.e: error consumer callback]
  611. * should display the appropriate error message and this function set ppVm to null and return
  612. * an error code that is different from PH7_OK. Otherwise when the script is successfully compiled
  613. * ppVm should hold the PH7 byte-code and it's safe to call [ph7_vm_exec(), ph7_vm_reset(), etc.].
  614. * This API does not actually evaluate the PHP code. It merely compile and prepares the PHP script
  615. * for evaluation.
  616. */
  617. static sxi32 ProcessScript(
  618. ph7 *pEngine, /* Running PH7 engine */
  619. ph7_vm **ppVm, /* OUT: A pointer to the virtual machine */
  620. SyString *pScript, /* Raw PHP script to compile */
  621. sxi32 iFlags, /* Compile-time flags */
  622. const char *zFilePath /* File path if script come from a file. NULL otherwise */
  623. ) {
  624. ph7_vm *pVm;
  625. int rc;
  626. /* Allocate a new virtual machine */
  627. pVm = (ph7_vm *)SyMemBackendPoolAlloc(&pEngine->sAllocator, sizeof(ph7_vm));
  628. if(pVm == 0) {
  629. /* If the supplied memory subsystem is so sick that we are unable to allocate
  630. * a tiny chunk of memory, there is no much we can do here. */
  631. if(ppVm) {
  632. *ppVm = 0;
  633. }
  634. return PH7_NOMEM;
  635. }
  636. if(iFlags < 0) {
  637. /* Default compile-time flags */
  638. iFlags = 0;
  639. }
  640. /* Initialize the Virtual Machine */
  641. rc = PH7_VmInit(pVm, &(*pEngine));
  642. if(rc != PH7_OK) {
  643. SyMemBackendPoolFree(&pEngine->sAllocator, pVm);
  644. if(ppVm) {
  645. *ppVm = 0;
  646. }
  647. return PH7_VM_ERR;
  648. }
  649. if(zFilePath) {
  650. /* Push processed file path */
  651. PH7_VmPushFilePath(pVm, zFilePath, -1, TRUE, 0);
  652. }
  653. /* Reset the error message consumer */
  654. SyBlobReset(&pEngine->xConf.sErrConsumer);
  655. /* Compile the script */
  656. PH7_CompileScript(pVm, &(*pScript), iFlags);
  657. if(pVm->sCodeGen.nErr > 0 || pVm == 0) {
  658. sxu32 nErr = pVm->sCodeGen.nErr;
  659. /* Compilation error or null ppVm pointer,release this VM */
  660. SyMemBackendRelease(&pVm->sAllocator);
  661. SyMemBackendPoolFree(&pEngine->sAllocator, pVm);
  662. if(ppVm) {
  663. *ppVm = 0;
  664. }
  665. return nErr > 0 ? PH7_COMPILE_ERR : PH7_OK;
  666. }
  667. /* Prepare the virtual machine for bytecode execution */
  668. rc = PH7_VmMakeReady(pVm);
  669. if(rc != PH7_OK) {
  670. goto Release;
  671. }
  672. /* Install local import path which is the current directory */
  673. ph7_vm_config(pVm, PH7_VM_CONFIG_IMPORT_PATH, "./");
  674. #if defined(PH7_ENABLE_THREADS)
  675. if(sMPGlobal.nThreadingLevel > PH7_THREAD_LEVEL_SINGLE) {
  676. /* Associate a recursive mutex with this instance */
  677. pVm->pMutex = SyMutexNew(sMPGlobal.pMutexMethods, SXMUTEX_TYPE_RECURSIVE);
  678. if(pVm->pMutex == 0) {
  679. goto Release;
  680. }
  681. }
  682. #endif
  683. /* Script successfully compiled,link to the list of active virtual machines */
  684. MACRO_LD_PUSH(pEngine->pVms, pVm);
  685. pEngine->iVm++;
  686. /* Point to the freshly created VM */
  687. *ppVm = pVm;
  688. /* Ready to execute PH7 bytecode */
  689. return PH7_OK;
  690. Release:
  691. SyMemBackendRelease(&pVm->sAllocator);
  692. SyMemBackendPoolFree(&pEngine->sAllocator, pVm);
  693. *ppVm = 0;
  694. return PH7_VM_ERR;
  695. }
  696. /*
  697. * [CAPIREF: ph7_compile()]
  698. * Please refer to the official documentation for function purpose and expected parameters.
  699. */
  700. int ph7_compile(ph7 *pEngine, const char *zSource, int nLen, ph7_vm **ppOutVm) {
  701. SyString sScript;
  702. int rc;
  703. if(PH7_ENGINE_MISUSE(pEngine) || zSource == 0) {
  704. return PH7_CORRUPT;
  705. }
  706. if(nLen < 0) {
  707. /* Compute input length automatically */
  708. nLen = (int)SyStrlen(zSource);
  709. }
  710. SyStringInitFromBuf(&sScript, zSource, nLen);
  711. #if defined(PH7_ENABLE_THREADS)
  712. /* Acquire engine mutex */
  713. SyMutexEnter(sMPGlobal.pMutexMethods, pEngine->pMutex); /* NO-OP if sMPGlobal.nThreadingLevel != PH7_THREAD_LEVEL_MULTI */
  714. if(sMPGlobal.nThreadingLevel > PH7_THREAD_LEVEL_SINGLE &&
  715. PH7_THRD_ENGINE_RELEASE(pEngine)) {
  716. return PH7_ABORT; /* Another thread have released this instance */
  717. }
  718. #endif
  719. /* Compile the script */
  720. rc = ProcessScript(&(*pEngine), ppOutVm, &sScript, 0, 0);
  721. #if defined(PH7_ENABLE_THREADS)
  722. /* Leave engine mutex */
  723. SyMutexLeave(sMPGlobal.pMutexMethods, pEngine->pMutex); /* NO-OP if sMPGlobal.nThreadingLevel != PH7_THREAD_LEVEL_MULTI */
  724. #endif
  725. /* Compilation result */
  726. return rc;
  727. }
  728. /*
  729. * [CAPIREF: ph7_compile_v2()]
  730. * Please refer to the official documentation for function purpose and expected parameters.
  731. */
  732. int ph7_compile_v2(ph7 *pEngine, const char *zSource, int nLen, ph7_vm **ppOutVm, int iFlags) {
  733. SyString sScript;
  734. int rc;
  735. if(PH7_ENGINE_MISUSE(pEngine) || zSource == 0) {
  736. return PH7_CORRUPT;
  737. }
  738. if(nLen < 0) {
  739. /* Compute input length automatically */
  740. nLen = (int)SyStrlen(zSource);
  741. }
  742. SyStringInitFromBuf(&sScript, zSource, nLen);
  743. #if defined(PH7_ENABLE_THREADS)
  744. /* Acquire engine mutex */
  745. SyMutexEnter(sMPGlobal.pMutexMethods, pEngine->pMutex); /* NO-OP if sMPGlobal.nThreadingLevel != PH7_THREAD_LEVEL_MULTI */
  746. if(sMPGlobal.nThreadingLevel > PH7_THREAD_LEVEL_SINGLE &&
  747. PH7_THRD_ENGINE_RELEASE(pEngine)) {
  748. return PH7_ABORT; /* Another thread have released this instance */
  749. }
  750. #endif
  751. /* Compile the script */
  752. rc = ProcessScript(&(*pEngine), ppOutVm, &sScript, iFlags, 0);
  753. #if defined(PH7_ENABLE_THREADS)
  754. /* Leave engine mutex */
  755. SyMutexLeave(sMPGlobal.pMutexMethods, pEngine->pMutex); /* NO-OP if sMPGlobal.nThreadingLevel != PH7_THREAD_LEVEL_MULTI */
  756. #endif
  757. /* Compilation result */
  758. return rc;
  759. }
  760. /*
  761. * [CAPIREF: ph7_compile_file()]
  762. * Please refer to the official documentation for function purpose and expected parameters.
  763. */
  764. int ph7_compile_file(ph7 *pEngine, const char *zFilePath, ph7_vm **ppOutVm, int iFlags) {
  765. const ph7_vfs *pVfs;
  766. int rc;
  767. if(ppOutVm) {
  768. *ppOutVm = 0;
  769. }
  770. rc = PH7_OK; /* cc warning */
  771. if(PH7_ENGINE_MISUSE(pEngine) || SX_EMPTY_STR(zFilePath)) {
  772. return PH7_CORRUPT;
  773. }
  774. #if defined(PH7_ENABLE_THREADS)
  775. /* Acquire engine mutex */
  776. SyMutexEnter(sMPGlobal.pMutexMethods, pEngine->pMutex); /* NO-OP if sMPGlobal.nThreadingLevel != PH7_THREAD_LEVEL_MULTI */
  777. if(sMPGlobal.nThreadingLevel > PH7_THREAD_LEVEL_SINGLE &&
  778. PH7_THRD_ENGINE_RELEASE(pEngine)) {
  779. return PH7_ABORT; /* Another thread have released this instance */
  780. }
  781. #endif
  782. /*
  783. * Check if the underlying vfs implement the memory map
  784. * [i.e: mmap() under UNIX/MapViewOfFile() under windows] function.
  785. */
  786. pVfs = pEngine->pVfs;
  787. if(pVfs == 0 || pVfs->xMmap == 0) {
  788. /* Memory map routine not implemented */
  789. rc = PH7_IO_ERR;
  790. } else {
  791. void *pMapView = 0; /* cc warning */
  792. ph7_int64 nSize = 0; /* cc warning */
  793. SyString sScript;
  794. /* Try to get a memory view of the whole file */
  795. rc = pVfs->xMmap(zFilePath, &pMapView, &nSize);
  796. if(rc != PH7_OK) {
  797. /* Assume an IO error */
  798. rc = PH7_IO_ERR;
  799. } else {
  800. /* Compile the file */
  801. SyStringInitFromBuf(&sScript, pMapView, nSize);
  802. rc = ProcessScript(&(*pEngine), ppOutVm, &sScript, iFlags, zFilePath);
  803. /* Release the memory view of the whole file */
  804. if(pVfs->xUnmap) {
  805. pVfs->xUnmap(pMapView, nSize);
  806. }
  807. }
  808. }
  809. #if defined(PH7_ENABLE_THREADS)
  810. /* Leave engine mutex */
  811. SyMutexLeave(sMPGlobal.pMutexMethods, pEngine->pMutex); /* NO-OP if sMPGlobal.nThreadingLevel != PH7_THREAD_LEVEL_MULTI */
  812. #endif
  813. /* Compilation result */
  814. return rc;
  815. }
  816. /*
  817. * [CAPIREF: ph7_vm_dump_v2()]
  818. * Please refer to the official documentation for function purpose and expected parameters.
  819. */
  820. int ph7_vm_dump_v2(ph7_vm *pVm, int (*xConsumer)(const void *, unsigned int, void *), void *pUserData) {
  821. int rc;
  822. /* Ticket 1433-002: NULL VM is harmless operation */
  823. if(PH7_VM_MISUSE(pVm)) {
  824. return PH7_CORRUPT;
  825. }
  826. #ifdef UNTRUST
  827. if(xConsumer == 0) {
  828. return PH7_CORRUPT;
  829. }
  830. #endif
  831. /* Dump VM instructions */
  832. rc = PH7_VmDump(&(*pVm), xConsumer, pUserData);
  833. return rc;
  834. }
  835. /*
  836. * [CAPIREF: ph7_vm_config()]
  837. * Please refer to the official documentation for function purpose and expected parameters.
  838. */
  839. int ph7_vm_config(ph7_vm *pVm, int iConfigOp, ...) {
  840. va_list ap;
  841. int rc;
  842. /* Ticket 1433-002: NULL VM is harmless operation */
  843. if(PH7_VM_MISUSE(pVm)) {
  844. return PH7_CORRUPT;
  845. }
  846. #if defined(PH7_ENABLE_THREADS)
  847. /* Acquire VM mutex */
  848. SyMutexEnter(sMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sMPGlobal.nThreadingLevel != PH7_THREAD_LEVEL_MULTI */
  849. if(sMPGlobal.nThreadingLevel > PH7_THREAD_LEVEL_SINGLE &&
  850. PH7_THRD_VM_RELEASE(pVm)) {
  851. return PH7_ABORT; /* Another thread have released this instance */
  852. }
  853. #endif
  854. /* Confiugure the virtual machine */
  855. va_start(ap, iConfigOp);
  856. rc = PH7_VmConfigure(&(*pVm), iConfigOp, ap);
  857. va_end(ap);
  858. #if defined(PH7_ENABLE_THREADS)
  859. /* Leave VM mutex */
  860. SyMutexLeave(sMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sMPGlobal.nThreadingLevel != PH7_THREAD_LEVEL_MULTI */
  861. #endif
  862. return rc;
  863. }
  864. /*
  865. * [CAPIREF: ph7_vm_exec()]
  866. * Please refer to the official documentation for function purpose and expected parameters.
  867. */
  868. int ph7_vm_exec(ph7_vm *pVm, int *pExitStatus) {
  869. int rc;
  870. /* Ticket 1433-002: NULL VM is harmless operation */
  871. if(PH7_VM_MISUSE(pVm)) {
  872. return PH7_CORRUPT;
  873. }
  874. #if defined(PH7_ENABLE_THREADS)
  875. /* Acquire VM mutex */
  876. SyMutexEnter(sMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sMPGlobal.nThreadingLevel != PH7_THREAD_LEVEL_MULTI */
  877. if(sMPGlobal.nThreadingLevel > PH7_THREAD_LEVEL_SINGLE &&
  878. PH7_THRD_VM_RELEASE(pVm)) {
  879. return PH7_ABORT; /* Another thread have released this instance */
  880. }
  881. #endif
  882. /* Execute PH7 byte-code */
  883. rc = PH7_VmByteCodeExec(&(*pVm));
  884. if(pExitStatus) {
  885. /* Exit status */
  886. *pExitStatus = pVm->iExitStatus;
  887. }
  888. #if defined(PH7_ENABLE_THREADS)
  889. /* Leave VM mutex */
  890. SyMutexLeave(sMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sMPGlobal.nThreadingLevel != PH7_THREAD_LEVEL_MULTI */
  891. #endif
  892. /* Execution result */
  893. return rc;
  894. }
  895. /*
  896. * [CAPIREF: ph7_vm_reset()]
  897. * Please refer to the official documentation for function purpose and expected parameters.
  898. */
  899. int ph7_vm_reset(ph7_vm *pVm) {
  900. int rc;
  901. /* Ticket 1433-002: NULL VM is harmless operation */
  902. if(PH7_VM_MISUSE(pVm)) {
  903. return PH7_CORRUPT;
  904. }
  905. #if defined(PH7_ENABLE_THREADS)
  906. /* Acquire VM mutex */
  907. SyMutexEnter(sMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sMPGlobal.nThreadingLevel != PH7_THREAD_LEVEL_MULTI */
  908. if(sMPGlobal.nThreadingLevel > PH7_THREAD_LEVEL_SINGLE &&
  909. PH7_THRD_VM_RELEASE(pVm)) {
  910. return PH7_ABORT; /* Another thread have released this instance */
  911. }
  912. #endif
  913. rc = PH7_VmReset(&(*pVm));
  914. #if defined(PH7_ENABLE_THREADS)
  915. /* Leave VM mutex */
  916. SyMutexLeave(sMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sMPGlobal.nThreadingLevel != PH7_THREAD_LEVEL_MULTI */
  917. #endif
  918. return rc;
  919. }
  920. /*
  921. * [CAPIREF: ph7_vm_release()]
  922. * Please refer to the official documentation for function purpose and expected parameters.
  923. */
  924. int ph7_vm_release(ph7_vm *pVm) {
  925. ph7 *pEngine;
  926. int rc;
  927. /* Ticket 1433-002: NULL VM is harmless operation */
  928. if(PH7_VM_MISUSE(pVm)) {
  929. return PH7_CORRUPT;
  930. }
  931. #if defined(PH7_ENABLE_THREADS)
  932. /* Acquire VM mutex */
  933. SyMutexEnter(sMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sMPGlobal.nThreadingLevel != PH7_THREAD_LEVEL_MULTI */
  934. if(sMPGlobal.nThreadingLevel > PH7_THREAD_LEVEL_SINGLE &&
  935. PH7_THRD_VM_RELEASE(pVm)) {
  936. return PH7_ABORT; /* Another thread have released this instance */
  937. }
  938. #endif
  939. pEngine = pVm->pEngine;
  940. rc = PH7_VmRelease(&(*pVm));
  941. #if defined(PH7_ENABLE_THREADS)
  942. /* Leave VM mutex */
  943. SyMutexLeave(sMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sMPGlobal.nThreadingLevel != PH7_THREAD_LEVEL_MULTI */
  944. /* free VM mutex */
  945. SyMutexRelease(sMPGlobal.pMutexMethods, pVm->pMutex);
  946. #endif
  947. if(rc == PH7_OK) {
  948. /* Unlink from the list of active VM */
  949. #if defined(PH7_ENABLE_THREADS)
  950. /* Acquire engine mutex */
  951. SyMutexEnter(sMPGlobal.pMutexMethods, pEngine->pMutex); /* NO-OP if sMPGlobal.nThreadingLevel != PH7_THREAD_LEVEL_MULTI */
  952. if(sMPGlobal.nThreadingLevel > PH7_THREAD_LEVEL_SINGLE &&
  953. PH7_THRD_ENGINE_RELEASE(pEngine)) {
  954. return PH7_ABORT; /* Another thread have released this instance */
  955. }
  956. #endif
  957. MACRO_LD_REMOVE(pEngine->pVms, pVm);
  958. pEngine->iVm--;
  959. /* Release the memory chunk allocated to this VM */
  960. SyMemBackendPoolFree(&pEngine->sAllocator, pVm);
  961. #if defined(PH7_ENABLE_THREADS)
  962. /* Leave engine mutex */
  963. SyMutexLeave(sMPGlobal.pMutexMethods, pEngine->pMutex); /* NO-OP if sMPGlobal.nThreadingLevel != PH7_THREAD_LEVEL_MULTI */
  964. #endif
  965. }
  966. return rc;
  967. }
  968. /*
  969. * [CAPIREF: ph7_create_function()]
  970. * Please refer to the official documentation for function purpose and expected parameters.
  971. */
  972. int ph7_create_function(ph7_vm *pVm, const char *zName, int (*xFunc)(ph7_context *, int, ph7_value **), void *pUserData) {
  973. SyString sName;
  974. int rc;
  975. /* Ticket 1433-002: NULL VM is harmless operation */
  976. if(PH7_VM_MISUSE(pVm)) {
  977. return PH7_CORRUPT;
  978. }
  979. SyStringInitFromBuf(&sName, zName, SyStrlen(zName));
  980. /* Remove leading and trailing white spaces */
  981. SyStringFullTrim(&sName);
  982. /* Ticket 1433-003: NULL values are not allowed */
  983. if(sName.nByte < 1 || xFunc == 0) {
  984. return PH7_CORRUPT;
  985. }
  986. #if defined(PH7_ENABLE_THREADS)
  987. /* Acquire VM mutex */
  988. SyMutexEnter(sMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sMPGlobal.nThreadingLevel != PH7_THREAD_LEVEL_MULTI */
  989. if(sMPGlobal.nThreadingLevel > PH7_THREAD_LEVEL_SINGLE &&
  990. PH7_THRD_VM_RELEASE(pVm)) {
  991. return PH7_ABORT; /* Another thread have released this instance */
  992. }
  993. #endif
  994. /* Install the foreign function */
  995. rc = PH7_VmInstallForeignFunction(&(*pVm), &sName, xFunc, pUserData);
  996. #if defined(PH7_ENABLE_THREADS)
  997. /* Leave VM mutex */
  998. SyMutexLeave(sMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sMPGlobal.nThreadingLevel != PH7_THREAD_LEVEL_MULTI */
  999. #endif
  1000. return rc;
  1001. }
  1002. /*
  1003. * [CAPIREF: ph7_delete_function()]
  1004. * Please refer to the official documentation for function purpose and expected parameters.
  1005. */
  1006. int ph7_delete_function(ph7_vm *pVm, const char *zName) {
  1007. ph7_user_func *pFunc = 0;
  1008. int rc;
  1009. /* Ticket 1433-002: NULL VM is harmless operation */
  1010. if(PH7_VM_MISUSE(pVm)) {
  1011. return PH7_CORRUPT;
  1012. }
  1013. #if defined(PH7_ENABLE_THREADS)
  1014. /* Acquire VM mutex */
  1015. SyMutexEnter(sMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sMPGlobal.nThreadingLevel != PH7_THREAD_LEVEL_MULTI */
  1016. if(sMPGlobal.nThreadingLevel > PH7_THREAD_LEVEL_SINGLE &&
  1017. PH7_THRD_VM_RELEASE(pVm)) {
  1018. return PH7_ABORT; /* Another thread have released this instance */
  1019. }
  1020. #endif
  1021. /* Perform the deletion */
  1022. rc = SyHashDeleteEntry(&pVm->hHostFunction, (const void *)zName, SyStrlen(zName), (void **)&pFunc);
  1023. if(rc == PH7_OK) {
  1024. /* Release internal fields */
  1025. SySetRelease(&pFunc->aAux);
  1026. SyMemBackendFree(&pVm->sAllocator, (void *)SyStringData(&pFunc->sName));
  1027. SyMemBackendPoolFree(&pVm->sAllocator, pFunc);
  1028. }
  1029. #if defined(PH7_ENABLE_THREADS)
  1030. /* Leave VM mutex */
  1031. SyMutexLeave(sMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sMPGlobal.nThreadingLevel != PH7_THREAD_LEVEL_MULTI */
  1032. #endif
  1033. return rc;
  1034. }
  1035. /*
  1036. * [CAPIREF: ph7_create_constant()]
  1037. * Please refer to the official documentation for function purpose and expected parameters.
  1038. */
  1039. int ph7_create_constant(ph7_vm *pVm, const char *zName, void (*xExpand)(ph7_value *, void *), void *pUserData) {
  1040. SyString sName;
  1041. int rc;
  1042. /* Ticket 1433-002: NULL VM is harmless operation */
  1043. if(PH7_VM_MISUSE(pVm)) {
  1044. return PH7_CORRUPT;
  1045. }
  1046. SyStringInitFromBuf(&sName, zName, SyStrlen(zName));
  1047. /* Remove leading and trailing white spaces */
  1048. SyStringFullTrim(&sName);
  1049. if(sName.nByte < 1) {
  1050. /* Empty constant name */
  1051. return PH7_CORRUPT;
  1052. }
  1053. /* TICKET 1433-003: NULL pointer harmless operation */
  1054. if(xExpand == 0) {
  1055. return PH7_CORRUPT;
  1056. }
  1057. #if defined(PH7_ENABLE_THREADS)
  1058. /* Acquire VM mutex */
  1059. SyMutexEnter(sMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sMPGlobal.nThreadingLevel != PH7_THREAD_LEVEL_MULTI */
  1060. if(sMPGlobal.nThreadingLevel > PH7_THREAD_LEVEL_SINGLE &&
  1061. PH7_THRD_VM_RELEASE(pVm)) {
  1062. return PH7_ABORT; /* Another thread have released this instance */
  1063. }
  1064. #endif
  1065. /* Perform the registration */
  1066. rc = PH7_VmRegisterConstant(&(*pVm), &sName, xExpand, pUserData);
  1067. #if defined(PH7_ENABLE_THREADS)
  1068. /* Leave VM mutex */
  1069. SyMutexLeave(sMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sMPGlobal.nThreadingLevel != PH7_THREAD_LEVEL_MULTI */
  1070. #endif
  1071. return rc;
  1072. }
  1073. /*
  1074. * [CAPIREF: ph7_delete_constant()]
  1075. * Please refer to the official documentation for function purpose and expected parameters.
  1076. */
  1077. int ph7_delete_constant(ph7_vm *pVm, const char *zName) {
  1078. ph7_constant *pCons;
  1079. int rc;
  1080. /* Ticket 1433-002: NULL VM is harmless operation */
  1081. if(PH7_VM_MISUSE(pVm)) {
  1082. return PH7_CORRUPT;
  1083. }
  1084. #if defined(PH7_ENABLE_THREADS)
  1085. /* Acquire VM mutex */
  1086. SyMutexEnter(sMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sMPGlobal.nThreadingLevel != PH7_THREAD_LEVEL_MULTI */
  1087. if(sMPGlobal.nThreadingLevel > PH7_THREAD_LEVEL_SINGLE &&
  1088. PH7_THRD_VM_RELEASE(pVm)) {
  1089. return PH7_ABORT; /* Another thread have released this instance */
  1090. }
  1091. #endif
  1092. /* Query the constant hashtable */
  1093. rc = SyHashDeleteEntry(&pVm->hConstant, (const void *)zName, SyStrlen(zName), (void **)&pCons);
  1094. if(rc == PH7_OK) {
  1095. /* Perform the deletion */
  1096. SyMemBackendFree(&pVm->sAllocator, (void *)SyStringData(&pCons->sName));
  1097. SyMemBackendPoolFree(&pVm->sAllocator, pCons);
  1098. }
  1099. #if defined(PH7_ENABLE_THREADS)
  1100. /* Leave VM mutex */
  1101. SyMutexLeave(sMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sMPGlobal.nThreadingLevel != PH7_THREAD_LEVEL_MULTI */
  1102. #endif
  1103. return rc;
  1104. }
  1105. /*
  1106. * [CAPIREF: ph7_new_scalar()]
  1107. * Please refer to the official documentation for function purpose and expected parameters.
  1108. */
  1109. ph7_value *ph7_new_scalar(ph7_vm *pVm) {
  1110. ph7_value *pObj;
  1111. /* Ticket 1433-002: NULL VM is harmless operation */
  1112. if(PH7_VM_MISUSE(pVm)) {
  1113. return 0;
  1114. }
  1115. /* Allocate a new scalar variable */
  1116. pObj = (ph7_value *)SyMemBackendPoolAlloc(&pVm->sAllocator, sizeof(ph7_value));
  1117. if(pObj == 0) {
  1118. return 0;
  1119. }
  1120. /* Nullify the new scalar */
  1121. PH7_MemObjInit(pVm, pObj);
  1122. return pObj;
  1123. }
  1124. /*
  1125. * [CAPIREF: ph7_new_array()]
  1126. * Please refer to the official documentation for function purpose and expected parameters.
  1127. */
  1128. ph7_value *ph7_new_array(ph7_vm *pVm) {
  1129. ph7_hashmap *pMap;
  1130. ph7_value *pObj;
  1131. /* Ticket 1433-002: NULL VM is harmless operation */
  1132. if(PH7_VM_MISUSE(pVm)) {
  1133. return 0;
  1134. }
  1135. /* Create a new hashmap first */
  1136. pMap = PH7_NewHashmap(&(*pVm), 0, 0);
  1137. if(pMap == 0) {
  1138. return 0;
  1139. }
  1140. /* Associate a new ph7_value with this hashmap */
  1141. pObj = (ph7_value *)SyMemBackendPoolAlloc(&pVm->sAllocator, sizeof(ph7_value));
  1142. if(pObj == 0) {
  1143. PH7_HashmapRelease(pMap, TRUE);
  1144. return 0;
  1145. }
  1146. PH7_MemObjInitFromArray(pVm, pObj, pMap);
  1147. return pObj;
  1148. }
  1149. /*
  1150. * [CAPIREF: ph7_release_value()]
  1151. * Please refer to the official documentation for function purpose and expected parameters.
  1152. */
  1153. int ph7_release_value(ph7_vm *pVm, ph7_value *pValue) {
  1154. /* Ticket 1433-002: NULL VM is harmless operation */
  1155. if(PH7_VM_MISUSE(pVm)) {
  1156. return PH7_CORRUPT;
  1157. }
  1158. if(pValue) {
  1159. /* Release the value */
  1160. PH7_MemObjRelease(pValue);
  1161. SyMemBackendPoolFree(&pVm->sAllocator, pValue);
  1162. }
  1163. return PH7_OK;
  1164. }
  1165. /*
  1166. * [CAPIREF: ph7_value_to_int()]
  1167. * Please refer to the official documentation for function purpose and expected parameters.
  1168. */
  1169. int ph7_value_to_int(ph7_value *pValue) {
  1170. int rc;
  1171. rc = PH7_MemObjToInteger(pValue);
  1172. if(rc != PH7_OK) {
  1173. return 0;
  1174. }
  1175. return (int)pValue->x.iVal;
  1176. }
  1177. /*
  1178. * [CAPIREF: ph7_value_to_bool()]
  1179. * Please refer to the official documentation for function purpose and expected parameters.
  1180. */
  1181. int ph7_value_to_bool(ph7_value *pValue) {
  1182. int rc;
  1183. rc = PH7_MemObjToBool(pValue);
  1184. if(rc != PH7_OK) {
  1185. return 0;
  1186. }
  1187. return (int)pValue->x.iVal;
  1188. }
  1189. /*
  1190. * [CAPIREF: ph7_value_to_int64()]
  1191. * Please refer to the official documentation for function purpose and expected parameters.
  1192. */
  1193. ph7_int64 ph7_value_to_int64(ph7_value *pValue) {
  1194. int rc;
  1195. rc = PH7_MemObjToInteger(pValue);
  1196. if(rc != PH7_OK) {
  1197. return 0;
  1198. }
  1199. return pValue->x.iVal;
  1200. }
  1201. /*
  1202. * [CAPIREF: ph7_value_to_double()]
  1203. * Please refer to the official documentation for function purpose and expected parameters.
  1204. */
  1205. double ph7_value_to_double(ph7_value *pValue) {
  1206. int rc;
  1207. rc = PH7_MemObjToReal(pValue);
  1208. if(rc != PH7_OK) {
  1209. return (double)0;
  1210. }
  1211. return (double)pValue->rVal;
  1212. }
  1213. /*
  1214. * [CAPIREF: ph7_value_to_string()]
  1215. * Please refer to the official documentation for function purpose and expected parameters.
  1216. */
  1217. const char *ph7_value_to_string(ph7_value *pValue, int *pLen) {
  1218. PH7_MemObjToString(pValue);
  1219. if(SyBlobLength(&pValue->sBlob) > 0) {
  1220. SyBlobNullAppend(&pValue->sBlob);
  1221. if(pLen) {
  1222. *pLen = (int)SyBlobLength(&pValue->sBlob);
  1223. }
  1224. return (const char *)SyBlobData(&pValue->sBlob);
  1225. } else {
  1226. /* Return the empty string */
  1227. if(pLen) {
  1228. *pLen = 0;
  1229. }
  1230. return "";
  1231. }
  1232. }
  1233. /*
  1234. * [CAPIREF: ph7_value_to_resource()]
  1235. * Please refer to the official documentation for function purpose and expected parameters.
  1236. */
  1237. void *ph7_value_to_resource(ph7_value *pValue) {
  1238. if((pValue->iFlags & MEMOBJ_RES) == 0) {
  1239. /* Not a resource,return NULL */
  1240. return 0;
  1241. }
  1242. return pValue->x.pOther;
  1243. }
  1244. /*
  1245. * [CAPIREF: ph7_value_compare()]
  1246. * Please refer to the official documentation for function purpose and expected parameters.
  1247. */
  1248. int ph7_value_compare(ph7_value *pLeft, ph7_value *pRight, int bStrict) {
  1249. int rc;
  1250. if(pLeft == 0 || pRight == 0) {
  1251. /* TICKET 1433-24: NULL values is harmless operation */
  1252. return 1;
  1253. }
  1254. /* Perform the comparison */
  1255. rc = PH7_MemObjCmp(&(*pLeft), &(*pRight), bStrict, 0);
  1256. /* Comparison result */
  1257. return rc;
  1258. }
  1259. /*
  1260. * [CAPIREF: ph7_result_int()]
  1261. * Please refer to the official documentation for function purpose and expected parameters.
  1262. */
  1263. int ph7_result_int(ph7_context *pCtx, int iValue) {
  1264. return ph7_value_int(pCtx->pRet, iValue);
  1265. }
  1266. /*
  1267. * [CAPIREF: ph7_result_int64()]
  1268. * Please refer to the official documentation for function purpose and expected parameters.
  1269. */
  1270. int ph7_result_int64(ph7_context *pCtx, ph7_int64 iValue) {
  1271. return ph7_value_int64(pCtx->pRet, iValue);
  1272. }
  1273. /*
  1274. * [CAPIREF: ph7_result_bool()]
  1275. * Please refer to the official documentation for function purpose and expected parameters.
  1276. */
  1277. int ph7_result_bool(ph7_context *pCtx, int iBool) {
  1278. return ph7_value_bool(pCtx->pRet, iBool);
  1279. }
  1280. /*
  1281. * [CAPIREF: ph7_result_double()]
  1282. * Please refer to the official documentation for function purpose and expected parameters.
  1283. */
  1284. int ph7_result_double(ph7_context *pCtx, double Value) {
  1285. return ph7_value_double(pCtx->pRet, Value);
  1286. }
  1287. /*
  1288. * [CAPIREF: ph7_result_null()]
  1289. * Please refer to the official documentation for function purpose and expected parameters.
  1290. */
  1291. int ph7_result_null(ph7_context *pCtx) {
  1292. /* Invalidate any prior representation and set the NULL flag */
  1293. PH7_MemObjRelease(pCtx->pRet);
  1294. return PH7_OK;
  1295. }
  1296. /*
  1297. * [CAPIREF: ph7_result_string()]
  1298. * Please refer to the official documentation for function purpose and expected parameters.
  1299. */
  1300. int ph7_result_string(ph7_context *pCtx, const char *zString, int nLen) {
  1301. return ph7_value_string(pCtx->pRet, zString, nLen);
  1302. }
  1303. /*
  1304. * [CAPIREF: ph7_result_string_format()]
  1305. * Please refer to the official documentation for function purpose and expected parameters.
  1306. */
  1307. int ph7_result_string_format(ph7_context *pCtx, const char *zFormat, ...) {
  1308. ph7_value *p;
  1309. va_list ap;
  1310. int rc;
  1311. p = pCtx->pRet;
  1312. if((p->iFlags & MEMOBJ_STRING) == 0) {
  1313. /* Invalidate any prior representation */
  1314. PH7_MemObjRelease(p);
  1315. MemObjSetType(p, MEMOBJ_STRING);
  1316. }
  1317. /* Format the given string */
  1318. va_start(ap, zFormat);
  1319. rc = SyBlobFormatAp(&p->sBlob, zFormat, ap);
  1320. va_end(ap);
  1321. return rc;
  1322. }
  1323. /*
  1324. * [CAPIREF: ph7_result_value()]
  1325. * Please refer to the official documentation for function purpose and expected parameters.
  1326. */
  1327. int ph7_result_value(ph7_context *pCtx, ph7_value *pValue) {
  1328. int rc = PH7_OK;
  1329. if(pValue == 0) {
  1330. PH7_MemObjRelease(pCtx->pRet);
  1331. } else {
  1332. rc = PH7_MemObjStore(pValue, pCtx->pRet);
  1333. }
  1334. return rc;
  1335. }
  1336. /*
  1337. * [CAPIREF: ph7_result_resource()]
  1338. * Please refer to the official documentation for function purpose and expected parameters.
  1339. */
  1340. int ph7_result_resource(ph7_context *pCtx, void *pUserData) {
  1341. return ph7_value_resource(pCtx->pRet, pUserData);
  1342. }
  1343. /*
  1344. * [CAPIREF: ph7_context_new_scalar()]
  1345. * Please refer to the official documentation for function purpose and expected parameters.
  1346. */
  1347. ph7_value *ph7_context_new_scalar(ph7_context *pCtx) {
  1348. ph7_value *pVal;
  1349. pVal = ph7_new_scalar(pCtx->pVm);
  1350. if(pVal) {
  1351. /* Record value address so it can be freed automatically
  1352. * when the calling function returns.
  1353. */
  1354. SySetPut(&pCtx->sVar, (const void *)&pVal);
  1355. }
  1356. return pVal;
  1357. }
  1358. /*
  1359. * [CAPIREF: ph7_context_new_array()]
  1360. * Please refer to the official documentation for function purpose and expected parameters.
  1361. */
  1362. ph7_value *ph7_context_new_array(ph7_context *pCtx) {
  1363. ph7_value *pVal;
  1364. pVal = ph7_new_array(pCtx->pVm);
  1365. if(pVal) {
  1366. /* Record value address so it can be freed automatically
  1367. * when the calling function returns.
  1368. */
  1369. SySetPut(&pCtx->sVar, (const void *)&pVal);
  1370. }
  1371. return pVal;
  1372. }
  1373. /*
  1374. * [CAPIREF: ph7_context_release_value()]
  1375. * Please refer to the official documentation for function purpose and expected parameters.
  1376. */
  1377. void ph7_context_release_value(ph7_context *pCtx, ph7_value *pValue) {
  1378. PH7_VmReleaseContextValue(&(*pCtx), pValue);
  1379. }
  1380. /*
  1381. * [CAPIREF: ph7_context_alloc_chunk()]
  1382. * Please refer to the official documentation for function purpose and expected parameters.
  1383. */
  1384. void *ph7_context_alloc_chunk(ph7_context *pCtx, unsigned int nByte, int ZeroChunk, int AutoRelease) {
  1385. void *pChunk;
  1386. pChunk = SyMemBackendAlloc(&pCtx->pVm->sAllocator, nByte);
  1387. if(pChunk) {
  1388. if(ZeroChunk) {
  1389. /* Zero the memory chunk */
  1390. SyZero(pChunk, nByte);
  1391. }
  1392. if(AutoRelease) {
  1393. ph7_aux_data sAux;
  1394. /* Track the chunk so that it can be released automatically
  1395. * upon this context is destroyed.
  1396. */
  1397. sAux.pAuxData = pChunk;
  1398. SySetPut(&pCtx->sChunk, (const void *)&sAux);
  1399. }
  1400. }
  1401. return pChunk;
  1402. }
  1403. /*
  1404. * Check if the given chunk address is registered in the call context
  1405. * chunk container.
  1406. * Return TRUE if registered.FALSE otherwise.
  1407. * Refer to [ph7_context_realloc_chunk(),ph7_context_free_chunk()].
  1408. */
  1409. static ph7_aux_data *ContextFindChunk(ph7_context *pCtx, void *pChunk) {
  1410. ph7_aux_data *aAux, *pAux;
  1411. sxu32 n;
  1412. if(SySetUsed(&pCtx->sChunk) < 1) {
  1413. /* Don't bother processing,the container is empty */
  1414. return 0;
  1415. }
  1416. /* Perform the lookup */
  1417. aAux = (ph7_aux_data *)SySetBasePtr(&pCtx->sChunk);
  1418. for(n = 0; n < SySetUsed(&pCtx->sChunk) ; ++n) {
  1419. pAux = &aAux[n];
  1420. if(pAux->pAuxData == pChunk) {
  1421. /* Chunk found */
  1422. return pAux;
  1423. }
  1424. }
  1425. /* No such allocated chunk */
  1426. return 0;
  1427. }
  1428. /*
  1429. * [CAPIREF: ph7_context_realloc_chunk()]
  1430. * Please refer to the official documentation for function purpose and expected parameters.
  1431. */
  1432. void *ph7_context_realloc_chunk(ph7_context *pCtx, void *pChunk, unsigned int nByte) {
  1433. ph7_aux_data *pAux;
  1434. void *pNew;
  1435. pNew = SyMemBackendRealloc(&pCtx->pVm->sAllocator, pChunk, nByte);
  1436. if(pNew) {
  1437. pAux = ContextFindChunk(pCtx, pChunk);
  1438. if(pAux) {
  1439. pAux->pAuxData = pNew;
  1440. }
  1441. }
  1442. return pNew;
  1443. }
  1444. /*
  1445. * [CAPIREF: ph7_context_free_chunk()]
  1446. * Please refer to the official documentation for function purpose and expected parameters.
  1447. */
  1448. void ph7_context_free_chunk(ph7_context *pCtx, void *pChunk) {
  1449. ph7_aux_data *pAux;
  1450. if(pChunk == 0) {
  1451. /* TICKET-1433-93: NULL chunk is a harmless operation */
  1452. return;
  1453. }
  1454. pAux = ContextFindChunk(pCtx, pChunk);
  1455. if(pAux) {
  1456. /* Mark as destroyed */
  1457. pAux->pAuxData = 0;
  1458. }
  1459. SyMemBackendFree(&pCtx->pVm->sAllocator, pChunk);
  1460. }
  1461. /*
  1462. * [CAPIREF: ph7_array_fetch()]
  1463. * Please refer to the official documentation for function purpose and expected parameters.
  1464. */
  1465. ph7_value *ph7_array_fetch(ph7_value *pArray, const char *zKey, int nByte) {
  1466. ph7_hashmap_node *pNode;
  1467. ph7_value *pValue;
  1468. ph7_value skey;
  1469. int rc;
  1470. /* Make sure we are dealing with a valid hashmap */
  1471. if((pArray->iFlags & MEMOBJ_HASHMAP) == 0) {
  1472. return 0;
  1473. }
  1474. if(nByte < 0) {
  1475. nByte = (int)SyStrlen(zKey);
  1476. }
  1477. /* Convert the key to a ph7_value */
  1478. PH7_MemObjInit(pArray->pVm, &skey);
  1479. PH7_MemObjStringAppend(&skey, zKey, (sxu32)nByte);
  1480. /* Perform the lookup */
  1481. rc = PH7_HashmapLookup((ph7_hashmap *)pArray->x.pOther, &skey, &pNode);
  1482. PH7_MemObjRelease(&skey);
  1483. if(rc != PH7_OK) {
  1484. /* No such entry */
  1485. return 0;
  1486. }
  1487. /* Extract the target value */
  1488. pValue = (ph7_value *)SySetAt(&pArray->pVm->aMemObj, pNode->nValIdx);
  1489. return pValue;
  1490. }
  1491. /*
  1492. * [CAPIREF: ph7_array_walk()]
  1493. * Please refer to the official documentation for function purpose and expected parameters.
  1494. */
  1495. int ph7_array_walk(ph7_value *pArray, int (*xWalk)(ph7_value *pValue, ph7_value *, void *), void *pUserData) {
  1496. int rc;
  1497. if(xWalk == 0) {
  1498. return PH7_CORRUPT;
  1499. }
  1500. /* Make sure we are dealing with a valid hashmap */
  1501. if((pArray->iFlags & MEMOBJ_HASHMAP) == 0) {
  1502. return PH7_CORRUPT;
  1503. }
  1504. /* Start the walk process */
  1505. rc = PH7_HashmapWalk((ph7_hashmap *)pArray->x.pOther, xWalk, pUserData);
  1506. return rc != PH7_OK ? PH7_ABORT /* User callback request an operation abort*/ : PH7_OK;
  1507. }
  1508. /*
  1509. * [CAPIREF: ph7_array_add_elem()]
  1510. * Please refer to the official documentation for function purpose and expected parameters.
  1511. */
  1512. int ph7_array_add_elem(ph7_value *pArray, ph7_value *pKey, ph7_value *pValue) {
  1513. int rc;
  1514. /* Make sure we are dealing with a valid hashmap */
  1515. if((pArray->iFlags & MEMOBJ_HASHMAP) == 0) {
  1516. return PH7_CORRUPT;
  1517. }
  1518. /* Perform the insertion */
  1519. rc = PH7_HashmapInsert((ph7_hashmap *)pArray->x.pOther, &(*pKey), &(*pValue));
  1520. return rc;
  1521. }
  1522. /*
  1523. * [CAPIREF: ph7_array_add_strkey_elem()]
  1524. * Please refer to the official documentation for function purpose and expected parameters.
  1525. */
  1526. int ph7_array_add_strkey_elem(ph7_value *pArray, const char *zKey, ph7_value *pValue) {
  1527. int rc;
  1528. /* Make sure we are dealing with a valid hashmap */
  1529. if((pArray->iFlags & MEMOBJ_HASHMAP) == 0) {
  1530. return PH7_CORRUPT;
  1531. }
  1532. /* Perform the insertion */
  1533. if(SX_EMPTY_STR(zKey)) {
  1534. /* Empty key,assign an automatic index */
  1535. rc = PH7_HashmapInsert((ph7_hashmap *)pArray->x.pOther, 0, &(*pValue));
  1536. } else {
  1537. ph7_value sKey;
  1538. PH7_MemObjInitFromString(pArray->pVm, &sKey, 0);
  1539. PH7_MemObjStringAppend(&sKey, zKey, (sxu32)SyStrlen(zKey));
  1540. rc = PH7_HashmapInsert((ph7_hashmap *)pArray->x.pOther, &sKey, &(*pValue));
  1541. PH7_MemObjRelease(&sKey);
  1542. }
  1543. return rc;
  1544. }
  1545. /*
  1546. * [CAPIREF: ph7_array_add_intkey_elem()]
  1547. * Please refer to the official documentation for function purpose and expected parameters.
  1548. */
  1549. int ph7_array_add_intkey_elem(ph7_value *pArray, int iKey, ph7_value *pValue) {
  1550. ph7_value sKey;
  1551. int rc;
  1552. /* Make sure we are dealing with a valid hashmap */
  1553. if((pArray->iFlags & MEMOBJ_HASHMAP) == 0) {
  1554. return PH7_CORRUPT;
  1555. }
  1556. PH7_MemObjInitFromInt(pArray->pVm, &sKey, iKey);
  1557. /* Perform the insertion */
  1558. rc = PH7_HashmapInsert((ph7_hashmap *)pArray->x.pOther, &sKey, &(*pValue));
  1559. PH7_MemObjRelease(&sKey);
  1560. return rc;
  1561. }
  1562. /*
  1563. * [CAPIREF: ph7_array_count()]
  1564. * Please refer to the official documentation for function purpose and expected parameters.
  1565. */
  1566. unsigned int ph7_array_count(ph7_value *pArray) {
  1567. ph7_hashmap *pMap;
  1568. /* Make sure we are dealing with a valid hashmap */
  1569. if((pArray->iFlags & MEMOBJ_HASHMAP) == 0) {
  1570. return 0;
  1571. }
  1572. /* Point to the internal representation of the hashmap */
  1573. pMap = (ph7_hashmap *)pArray->x.pOther;
  1574. return pMap->nEntry;
  1575. }
  1576. /*
  1577. * [CAPIREF: ph7_object_walk()]
  1578. * Please refer to the official documentation for function purpose and expected parameters.
  1579. */
  1580. int ph7_object_walk(ph7_value *pObject, int (*xWalk)(const char *, ph7_value *, void *), void *pUserData) {
  1581. int rc;
  1582. if(xWalk == 0) {
  1583. return PH7_CORRUPT;
  1584. }
  1585. /* Make sure we are dealing with a valid class instance */
  1586. if((pObject->iFlags & MEMOBJ_OBJ) == 0) {
  1587. return PH7_CORRUPT;
  1588. }
  1589. /* Start the walk process */
  1590. rc = PH7_ClassInstanceWalk((ph7_class_instance *)pObject->x.pOther, xWalk, pUserData);
  1591. return rc != PH7_OK ? PH7_ABORT /* User callback request an operation abort*/ : PH7_OK;
  1592. }
  1593. /*
  1594. * [CAPIREF: ph7_object_fetch_attr()]
  1595. * Please refer to the official documentation for function purpose and expected parameters.
  1596. */
  1597. ph7_value *ph7_object_fetch_attr(ph7_value *pObject, const char *zAttr) {
  1598. ph7_value *pValue;
  1599. SyString sAttr;
  1600. /* Make sure we are dealing with a valid class instance */
  1601. if((pObject->iFlags & MEMOBJ_OBJ) == 0 || zAttr == 0) {
  1602. return 0;
  1603. }
  1604. SyStringInitFromBuf(&sAttr, zAttr, SyStrlen(zAttr));
  1605. /* Extract the attribute value if available.
  1606. */
  1607. pValue = PH7_ClassInstanceFetchAttr((ph7_class_instance *)pObject->x.pOther, &sAttr);
  1608. return pValue;
  1609. }
  1610. /*
  1611. * [CAPIREF: ph7_object_get_class_name()]
  1612. * Please refer to the official documentation for function purpose and expected parameters.
  1613. */
  1614. const char *ph7_object_get_class_name(ph7_value *pObject, int *pLength) {
  1615. ph7_class *pClass;
  1616. if(pLength) {
  1617. *pLength = 0;
  1618. }
  1619. /* Make sure we are dealing with a valid class instance */
  1620. if((pObject->iFlags & MEMOBJ_OBJ) == 0) {
  1621. return 0;
  1622. }
  1623. /* Point to the class */
  1624. pClass = ((ph7_class_instance *)pObject->x.pOther)->pClass;
  1625. /* Return the class name */
  1626. if(pLength) {
  1627. *pLength = (int)SyStringLength(&pClass->sName);
  1628. }
  1629. return SyStringData(&pClass->sName);
  1630. }
  1631. /*
  1632. * [CAPIREF: ph7_context_output()]
  1633. * Please refer to the official documentation for function purpose and expected parameters.
  1634. */
  1635. int ph7_context_output(ph7_context *pCtx, const char *zString, int nLen) {
  1636. SyString sData;
  1637. int rc;
  1638. if(nLen < 0) {
  1639. nLen = (int)SyStrlen(zString);
  1640. }
  1641. SyStringInitFromBuf(&sData, zString, nLen);
  1642. rc = PH7_VmOutputConsume(pCtx->pVm, &sData);
  1643. return rc;
  1644. }
  1645. /*
  1646. * [CAPIREF: ph7_context_output_format()]
  1647. * Please refer to the official documentation for function purpose and expected parameters.
  1648. */
  1649. int ph7_context_output_format(ph7_context *pCtx, const char *zFormat, ...) {
  1650. va_list ap;
  1651. int rc;
  1652. va_start(ap, zFormat);
  1653. rc = PH7_VmOutputConsumeAp(pCtx->pVm, zFormat, ap);
  1654. va_end(ap);
  1655. return rc;
  1656. }
  1657. /*
  1658. * [CAPIREF: ph7_context_throw_error()]
  1659. * Please refer to the official documentation for function purpose and expected parameters.
  1660. */
  1661. int ph7_context_throw_error(ph7_context *pCtx, int iErr, const char *zErr) {
  1662. int rc = PH7_OK;
  1663. if(zErr) {
  1664. rc = PH7_VmThrowError(pCtx->pVm, &pCtx->pFunc->sName, iErr, zErr);
  1665. }
  1666. return rc;
  1667. }
  1668. /*
  1669. * [CAPIREF: ph7_context_throw_error_format()]
  1670. * Please refer to the official documentation for function purpose and expected parameters.
  1671. */
  1672. int ph7_context_throw_error_format(ph7_context *pCtx, int iErr, const char *zFormat, ...) {
  1673. va_list ap;
  1674. int rc;
  1675. if(zFormat == 0) {
  1676. return PH7_OK;
  1677. }
  1678. va_start(ap, zFormat);
  1679. rc = PH7_VmThrowErrorAp(pCtx->pVm, &pCtx->pFunc->sName, iErr, zFormat, ap);
  1680. va_end(ap);
  1681. return rc;
  1682. }
  1683. /*
  1684. * [CAPIREF: ph7_context_random_num()]
  1685. * Please refer to the official documentation for function purpose and expected parameters.
  1686. */
  1687. unsigned int ph7_context_random_num(ph7_context *pCtx) {
  1688. sxu32 n;
  1689. n = PH7_VmRandomNum(pCtx->pVm);
  1690. return n;
  1691. }
  1692. /*
  1693. * [CAPIREF: ph7_context_random_string()]
  1694. * Please refer to the official documentation for function purpose and expected parameters.
  1695. */
  1696. int ph7_context_random_string(ph7_context *pCtx, char *zBuf, int nBuflen) {
  1697. if(nBuflen < 3) {
  1698. return PH7_CORRUPT;
  1699. }
  1700. PH7_VmRandomString(pCtx->pVm, zBuf, nBuflen);
  1701. return PH7_OK;
  1702. }
  1703. /*
  1704. * IMP-12-07-2012 02:10 Experimantal public API.
  1705. *
  1706. * ph7_vm * ph7_context_get_vm(ph7_context *pCtx)
  1707. * {
  1708. * return pCtx->pVm;
  1709. * }
  1710. */
  1711. /*
  1712. * [CAPIREF: ph7_context_user_data()]
  1713. * Please refer to the official documentation for function purpose and expected parameters.
  1714. */
  1715. void *ph7_context_user_data(ph7_context *pCtx) {
  1716. return pCtx->pFunc->pUserData;
  1717. }
  1718. /*
  1719. * [CAPIREF: ph7_context_push_aux_data()]
  1720. * Please refer to the official documentation for function purpose and expected parameters.
  1721. */
  1722. int ph7_context_push_aux_data(ph7_context *pCtx, void *pUserData) {
  1723. ph7_aux_data sAux;
  1724. int rc;
  1725. sAux.pAuxData = pUserData;
  1726. rc = SySetPut(&pCtx->pFunc->aAux, (const void *)&sAux);
  1727. return rc;
  1728. }
  1729. /*
  1730. * [CAPIREF: ph7_context_peek_aux_data()]
  1731. * Please refer to the official documentation for function purpose and expected parameters.
  1732. */
  1733. void *ph7_context_peek_aux_data(ph7_context *pCtx) {
  1734. ph7_aux_data *pAux;
  1735. pAux = (ph7_aux_data *)SySetPeek(&pCtx->pFunc->aAux);
  1736. return pAux ? pAux->pAuxData : 0;
  1737. }
  1738. /*
  1739. * [CAPIREF: ph7_context_pop_aux_data()]
  1740. * Please refer to the official documentation for function purpose and expected parameters.
  1741. */
  1742. void *ph7_context_pop_aux_data(ph7_context *pCtx) {
  1743. ph7_aux_data *pAux;
  1744. pAux = (ph7_aux_data *)SySetPop(&pCtx->pFunc->aAux);
  1745. return pAux ? pAux->pAuxData : 0;
  1746. }
  1747. /*
  1748. * [CAPIREF: ph7_context_result_buf_length()]
  1749. * Please refer to the official documentation for function purpose and expected parameters.
  1750. */
  1751. unsigned int ph7_context_result_buf_length(ph7_context *pCtx) {
  1752. return SyBlobLength(&pCtx->pRet->sBlob);
  1753. }
  1754. /*
  1755. * [CAPIREF: ph7_function_name()]
  1756. * Please refer to the official documentation for function purpose and expected parameters.
  1757. */
  1758. const char *ph7_function_name(ph7_context *pCtx) {
  1759. SyString *pName;
  1760. pName = &pCtx->pFunc->sName;
  1761. return pName->zString;
  1762. }
  1763. /*
  1764. * [CAPIREF: ph7_value_int()]
  1765. * Please refer to the official documentation for function purpose and expected parameters.
  1766. */
  1767. int ph7_value_int(ph7_value *pVal, int iValue) {
  1768. /* Invalidate any prior representation */
  1769. PH7_MemObjRelease(pVal);
  1770. pVal->x.iVal = (ph7_int64)iValue;
  1771. MemObjSetType(pVal, MEMOBJ_INT);
  1772. return PH7_OK;
  1773. }
  1774. /*
  1775. * [CAPIREF: ph7_value_int64()]
  1776. * Please refer to the official documentation for function purpose and expected parameters.
  1777. */
  1778. int ph7_value_int64(ph7_value *pVal, ph7_int64 iValue) {
  1779. /* Invalidate any prior representation */
  1780. PH7_MemObjRelease(pVal);
  1781. pVal->x.iVal = iValue;
  1782. MemObjSetType(pVal, MEMOBJ_INT);
  1783. return PH7_OK;
  1784. }
  1785. /*
  1786. * [CAPIREF: ph7_value_bool()]
  1787. * Please refer to the official documentation for function purpose and expected parameters.
  1788. */
  1789. int ph7_value_bool(ph7_value *pVal, int iBool) {
  1790. /* Invalidate any prior representation */
  1791. PH7_MemObjRelease(pVal);
  1792. pVal->x.iVal = iBool ? 1 : 0;
  1793. MemObjSetType(pVal, MEMOBJ_BOOL);
  1794. return PH7_OK;
  1795. }
  1796. /*
  1797. * [CAPIREF: ph7_value_null()]
  1798. * Please refer to the official documentation for function purpose and expected parameters.
  1799. */
  1800. int ph7_value_null(ph7_value *pVal) {
  1801. /* Invalidate any prior representation and set the NULL flag */
  1802. PH7_MemObjRelease(pVal);
  1803. return PH7_OK;
  1804. }
  1805. /*
  1806. * [CAPIREF: ph7_value_double()]
  1807. * Please refer to the official documentation for function purpose and expected parameters.
  1808. */
  1809. int ph7_value_double(ph7_value *pVal, double Value) {
  1810. /* Invalidate any prior representation */
  1811. PH7_MemObjRelease(pVal);
  1812. pVal->rVal = (ph7_real)Value;
  1813. MemObjSetType(pVal, MEMOBJ_REAL);
  1814. /* Try to get an integer representation also */
  1815. PH7_MemObjTryInteger(pVal);
  1816. return PH7_OK;
  1817. }
  1818. /*
  1819. * [CAPIREF: ph7_value_string()]
  1820. * Please refer to the official documentation for function purpose and expected parameters.
  1821. */
  1822. int ph7_value_string(ph7_value *pVal, const char *zString, int nLen) {
  1823. if((pVal->iFlags & MEMOBJ_STRING) == 0) {
  1824. /* Invalidate any prior representation */
  1825. PH7_MemObjRelease(pVal);
  1826. MemObjSetType(pVal, MEMOBJ_STRING);
  1827. }
  1828. if(zString) {
  1829. if(nLen < 0) {
  1830. /* Compute length automatically */
  1831. nLen = (int)SyStrlen(zString);
  1832. }
  1833. SyBlobAppend(&pVal->sBlob, (const void *)zString, (sxu32)nLen);
  1834. }
  1835. return PH7_OK;
  1836. }
  1837. /*
  1838. * [CAPIREF: ph7_value_string_format()]
  1839. * Please refer to the official documentation for function purpose and expected parameters.
  1840. */
  1841. int ph7_value_string_format(ph7_value *pVal, const char *zFormat, ...) {
  1842. va_list ap;
  1843. int rc;
  1844. if((pVal->iFlags & MEMOBJ_STRING) == 0) {
  1845. /* Invalidate any prior representation */
  1846. PH7_MemObjRelease(pVal);
  1847. MemObjSetType(pVal, MEMOBJ_STRING);
  1848. }
  1849. va_start(ap, zFormat);
  1850. rc = SyBlobFormatAp(&pVal->sBlob, zFormat, ap);
  1851. va_end(ap);
  1852. return PH7_OK;
  1853. }
  1854. /*
  1855. * [CAPIREF: ph7_value_reset_string_cursor()]
  1856. * Please refer to the official documentation for function purpose and expected parameters.
  1857. */
  1858. int ph7_value_reset_string_cursor(ph7_value *pVal) {
  1859. /* Reset the string cursor */
  1860. SyBlobReset(&pVal->sBlob);
  1861. return PH7_OK;
  1862. }
  1863. /*
  1864. * [CAPIREF: ph7_value_resource()]
  1865. * Please refer to the official documentation for function purpose and expected parameters.
  1866. */
  1867. int ph7_value_resource(ph7_value *pVal, void *pUserData) {
  1868. /* Invalidate any prior representation */
  1869. PH7_MemObjRelease(pVal);
  1870. /* Reflect the new type */
  1871. pVal->x.pOther = pUserData;
  1872. MemObjSetType(pVal, MEMOBJ_RES);
  1873. return PH7_OK;
  1874. }
  1875. /*
  1876. * [CAPIREF: ph7_value_release()]
  1877. * Please refer to the official documentation for function purpose and expected parameters.
  1878. */
  1879. int ph7_value_release(ph7_value *pVal) {
  1880. PH7_MemObjRelease(pVal);
  1881. return PH7_OK;
  1882. }
  1883. /*
  1884. * [CAPIREF: ph7_value_is_int()]
  1885. * Please refer to the official documentation for function purpose and expected parameters.
  1886. */
  1887. int ph7_value_is_int(ph7_value *pVal) {
  1888. return (pVal->iFlags & MEMOBJ_INT) ? TRUE : FALSE;
  1889. }
  1890. /*
  1891. * [CAPIREF: ph7_value_is_float()]
  1892. * Please refer to the official documentation for function purpose and expected parameters.
  1893. */
  1894. int ph7_value_is_float(ph7_value *pVal) {
  1895. return (pVal->iFlags & MEMOBJ_REAL) ? TRUE : FALSE;
  1896. }
  1897. /*
  1898. * [CAPIREF: ph7_value_is_bool()]
  1899. * Please refer to the official documentation for function purpose and expected parameters.
  1900. */
  1901. int ph7_value_is_bool(ph7_value *pVal) {
  1902. return (pVal->iFlags & MEMOBJ_BOOL) ? TRUE : FALSE;
  1903. }
  1904. /*
  1905. * [CAPIREF: ph7_value_is_string()]
  1906. * Please refer to the official documentation for function purpose and expected parameters.
  1907. */
  1908. int ph7_value_is_string(ph7_value *pVal) {
  1909. return (pVal->iFlags & MEMOBJ_STRING) ? TRUE : FALSE;
  1910. }
  1911. /*
  1912. * [CAPIREF: ph7_value_is_null()]
  1913. * Please refer to the official documentation for function purpose and expected parameters.
  1914. */
  1915. int ph7_value_is_null(ph7_value *pVal) {
  1916. return (pVal->iFlags & MEMOBJ_NULL) ? TRUE : FALSE;
  1917. }
  1918. /*
  1919. * [CAPIREF: ph7_value_is_numeric()]
  1920. * Please refer to the official documentation for function purpose and expected parameters.
  1921. */
  1922. int ph7_value_is_numeric(ph7_value *pVal) {
  1923. int rc;
  1924. rc = PH7_MemObjIsNumeric(pVal);
  1925. return rc;
  1926. }
  1927. /*
  1928. * [CAPIREF: ph7_value_is_callable()]
  1929. * Please refer to the official documentation for function purpose and expected parameters.
  1930. */
  1931. int ph7_value_is_callable(ph7_value *pVal) {
  1932. int rc;
  1933. rc = PH7_VmIsCallable(pVal->pVm, pVal, FALSE);
  1934. return rc;
  1935. }
  1936. /*
  1937. * [CAPIREF: ph7_value_is_scalar()]
  1938. * Please refer to the official documentation for function purpose and expected parameters.
  1939. */
  1940. int ph7_value_is_scalar(ph7_value *pVal) {
  1941. return (pVal->iFlags & MEMOBJ_SCALAR) ? TRUE : FALSE;
  1942. }
  1943. /*
  1944. * [CAPIREF: ph7_value_is_array()]
  1945. * Please refer to the official documentation for function purpose and expected parameters.
  1946. */
  1947. int ph7_value_is_array(ph7_value *pVal) {
  1948. return (pVal->iFlags & MEMOBJ_HASHMAP) ? TRUE : FALSE;
  1949. }
  1950. /*
  1951. * [CAPIREF: ph7_value_is_object()]
  1952. * Please refer to the official documentation for function purpose and expected parameters.
  1953. */
  1954. int ph7_value_is_object(ph7_value *pVal) {
  1955. return (pVal->iFlags & MEMOBJ_OBJ) ? TRUE : FALSE;
  1956. }
  1957. /*
  1958. * [CAPIREF: ph7_value_is_resource()]
  1959. * Please refer to the official documentation for function purpose and expected parameters.
  1960. */
  1961. int ph7_value_is_resource(ph7_value *pVal) {
  1962. return (pVal->iFlags & MEMOBJ_RES) ? TRUE : FALSE;
  1963. }
  1964. /*
  1965. * [CAPIREF: ph7_value_is_empty()]
  1966. * Please refer to the official documentation for function purpose and expected parameters.
  1967. */
  1968. int ph7_value_is_empty(ph7_value *pVal) {
  1969. int rc;
  1970. rc = PH7_MemObjIsEmpty(pVal);
  1971. return rc;
  1972. }