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.

1875 lines
59 KiB

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