diff options
Diffstat (limited to 'common/unqlite/jx9_api.c')
-rw-r--r-- | common/unqlite/jx9_api.c | 1744 |
1 files changed, 1744 insertions, 0 deletions
diff --git a/common/unqlite/jx9_api.c b/common/unqlite/jx9_api.c new file mode 100644 index 0000000..efad097 --- /dev/null +++ b/common/unqlite/jx9_api.c | |||
@@ -0,0 +1,1744 @@ | |||
1 | /* | ||
2 | * Symisc JX9: A Highly Efficient Embeddable Scripting Engine Based on JSON. | ||
3 | * Copyright (C) 2012-2013, Symisc Systems http://jx9.symisc.net/ | ||
4 | * Version 1.7.2 | ||
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://jx9.symisc.net/ | ||
12 | */ | ||
13 | /* $SymiscID: api.c v1.7 FreeBSD 2012-12-18 06:54 stable <chm@symisc.net> $ */ | ||
14 | #ifndef JX9_AMALGAMATION | ||
15 | #include "jx9Int.h" | ||
16 | #endif | ||
17 | /* This file implement the public interfaces presented to host-applications. | ||
18 | * Routines in other files are for internal use by JX9 and should not be | ||
19 | * accessed by users of the library. | ||
20 | */ | ||
21 | #define JX9_ENGINE_MAGIC 0xF874BCD7 | ||
22 | #define JX9_ENGINE_MISUSE(ENGINE) (ENGINE == 0 || ENGINE->nMagic != JX9_ENGINE_MAGIC) | ||
23 | #define JX9_VM_MISUSE(VM) (VM == 0 || VM->nMagic == JX9_VM_STALE) | ||
24 | /* If another thread have released a working instance, the following macros | ||
25 | * evaluates to true. These macros are only used when the library | ||
26 | * is built with threading support enabled which is not the case in | ||
27 | * the default built. | ||
28 | */ | ||
29 | #define JX9_THRD_ENGINE_RELEASE(ENGINE) (ENGINE->nMagic != JX9_ENGINE_MAGIC) | ||
30 | #define JX9_THRD_VM_RELEASE(VM) (VM->nMagic == JX9_VM_STALE) | ||
31 | /* IMPLEMENTATION: jx9@embedded@symisc 311-12-32 */ | ||
32 | /* | ||
33 | * All global variables are collected in the structure named "sJx9MPGlobal". | ||
34 | * That way it is clear in the code when we are using static variable because | ||
35 | * its name start with sJx9MPGlobal. | ||
36 | */ | ||
37 | static struct Jx9Global_Data | ||
38 | { | ||
39 | SyMemBackend sAllocator; /* Global low level memory allocator */ | ||
40 | #if defined(JX9_ENABLE_THREADS) | ||
41 | const SyMutexMethods *pMutexMethods; /* Mutex methods */ | ||
42 | SyMutex *pMutex; /* Global mutex */ | ||
43 | sxu32 nThreadingLevel; /* Threading level: 0 == Single threaded/1 == Multi-Threaded | ||
44 | * The threading level can be set using the [jx9_lib_config()] | ||
45 | * interface with a configuration verb set to | ||
46 | * JX9_LIB_CONFIG_THREAD_LEVEL_SINGLE or | ||
47 | * JX9_LIB_CONFIG_THREAD_LEVEL_MULTI | ||
48 | */ | ||
49 | #endif | ||
50 | const jx9_vfs *pVfs; /* Underlying virtual file system */ | ||
51 | sxi32 nEngine; /* Total number of active engines */ | ||
52 | jx9 *pEngines; /* List of active engine */ | ||
53 | sxu32 nMagic; /* Sanity check against library misuse */ | ||
54 | }sJx9MPGlobal = { | ||
55 | {0, 0, 0, 0, 0, 0, 0, 0, {0}}, | ||
56 | #if defined(JX9_ENABLE_THREADS) | ||
57 | 0, | ||
58 | 0, | ||
59 | 0, | ||
60 | #endif | ||
61 | 0, | ||
62 | 0, | ||
63 | 0, | ||
64 | 0 | ||
65 | }; | ||
66 | #define JX9_LIB_MAGIC 0xEA1495BA | ||
67 | #define JX9_LIB_MISUSE (sJx9MPGlobal.nMagic != JX9_LIB_MAGIC) | ||
68 | /* | ||
69 | * Supported threading level. | ||
70 | * These options have meaning only when the library is compiled with multi-threading | ||
71 | * support.That is, the JX9_ENABLE_THREADS compile time directive must be defined | ||
72 | * when JX9 is built. | ||
73 | * JX9_THREAD_LEVEL_SINGLE: | ||
74 | * In this mode, mutexing is disabled and the library can only be used by a single thread. | ||
75 | * JX9_THREAD_LEVEL_MULTI | ||
76 | * In this mode, all mutexes including the recursive mutexes on [jx9] objects | ||
77 | * are enabled so that the application is free to share the same engine | ||
78 | * between different threads at the same time. | ||
79 | */ | ||
80 | #define JX9_THREAD_LEVEL_SINGLE 1 | ||
81 | #define JX9_THREAD_LEVEL_MULTI 2 | ||
82 | /* | ||
83 | * Configure a running JX9 engine instance. | ||
84 | * return JX9_OK on success.Any other return | ||
85 | * value indicates failure. | ||
86 | * Refer to [jx9_config()]. | ||
87 | */ | ||
88 | JX9_PRIVATE sxi32 jx9EngineConfig(jx9 *pEngine, sxi32 nOp, va_list ap) | ||
89 | { | ||
90 | jx9_conf *pConf = &pEngine->xConf; | ||
91 | int rc = JX9_OK; | ||
92 | /* Perform the requested operation */ | ||
93 | switch(nOp){ | ||
94 | case JX9_CONFIG_ERR_LOG:{ | ||
95 | /* Extract compile-time error log if any */ | ||
96 | const char **pzPtr = va_arg(ap, const char **); | ||
97 | int *pLen = va_arg(ap, int *); | ||
98 | if( pzPtr == 0 ){ | ||
99 | rc = JX9_CORRUPT; | ||
100 | break; | ||
101 | } | ||
102 | /* NULL terminate the error-log buffer */ | ||
103 | SyBlobNullAppend(&pConf->sErrConsumer); | ||
104 | /* Point to the error-log buffer */ | ||
105 | *pzPtr = (const char *)SyBlobData(&pConf->sErrConsumer); | ||
106 | if( pLen ){ | ||
107 | if( SyBlobLength(&pConf->sErrConsumer) > 1 /* NULL '\0' terminator */ ){ | ||
108 | *pLen = (int)SyBlobLength(&pConf->sErrConsumer); | ||
109 | }else{ | ||
110 | *pLen = 0; | ||
111 | } | ||
112 | } | ||
113 | break; | ||
114 | } | ||
115 | case JX9_CONFIG_ERR_ABORT: | ||
116 | /* Reserved for future use */ | ||
117 | break; | ||
118 | default: | ||
119 | /* Unknown configuration verb */ | ||
120 | rc = JX9_CORRUPT; | ||
121 | break; | ||
122 | } /* Switch() */ | ||
123 | return rc; | ||
124 | } | ||
125 | /* | ||
126 | * Configure the JX9 library. | ||
127 | * Return JX9_OK on success. Any other return value indicates failure. | ||
128 | * Refer to [jx9_lib_config()]. | ||
129 | */ | ||
130 | static sxi32 Jx9CoreConfigure(sxi32 nOp, va_list ap) | ||
131 | { | ||
132 | int rc = JX9_OK; | ||
133 | switch(nOp){ | ||
134 | case JX9_LIB_CONFIG_VFS:{ | ||
135 | /* Install a virtual file system */ | ||
136 | const jx9_vfs *pVfs = va_arg(ap, const jx9_vfs *); | ||
137 | sJx9MPGlobal.pVfs = pVfs; | ||
138 | break; | ||
139 | } | ||
140 | case JX9_LIB_CONFIG_USER_MALLOC: { | ||
141 | /* Use an alternative low-level memory allocation routines */ | ||
142 | const SyMemMethods *pMethods = va_arg(ap, const SyMemMethods *); | ||
143 | /* Save the memory failure callback (if available) */ | ||
144 | ProcMemError xMemErr = sJx9MPGlobal.sAllocator.xMemError; | ||
145 | void *pMemErr = sJx9MPGlobal.sAllocator.pUserData; | ||
146 | if( pMethods == 0 ){ | ||
147 | /* Use the built-in memory allocation subsystem */ | ||
148 | rc = SyMemBackendInit(&sJx9MPGlobal.sAllocator, xMemErr, pMemErr); | ||
149 | }else{ | ||
150 | rc = SyMemBackendInitFromOthers(&sJx9MPGlobal.sAllocator, pMethods, xMemErr, pMemErr); | ||
151 | } | ||
152 | break; | ||
153 | } | ||
154 | case JX9_LIB_CONFIG_MEM_ERR_CALLBACK: { | ||
155 | /* Memory failure callback */ | ||
156 | ProcMemError xMemErr = va_arg(ap, ProcMemError); | ||
157 | void *pUserData = va_arg(ap, void *); | ||
158 | sJx9MPGlobal.sAllocator.xMemError = xMemErr; | ||
159 | sJx9MPGlobal.sAllocator.pUserData = pUserData; | ||
160 | break; | ||
161 | } | ||
162 | case JX9_LIB_CONFIG_USER_MUTEX: { | ||
163 | #if defined(JX9_ENABLE_THREADS) | ||
164 | /* Use an alternative low-level mutex subsystem */ | ||
165 | const SyMutexMethods *pMethods = va_arg(ap, const SyMutexMethods *); | ||
166 | #if defined (UNTRUST) | ||
167 | if( pMethods == 0 ){ | ||
168 | rc = JX9_CORRUPT; | ||
169 | } | ||
170 | #endif | ||
171 | /* Sanity check */ | ||
172 | if( pMethods->xEnter == 0 || pMethods->xLeave == 0 || pMethods->xNew == 0){ | ||
173 | /* At least three criticial callbacks xEnter(), xLeave() and xNew() must be supplied */ | ||
174 | rc = JX9_CORRUPT; | ||
175 | break; | ||
176 | } | ||
177 | if( sJx9MPGlobal.pMutexMethods ){ | ||
178 | /* Overwrite the previous mutex subsystem */ | ||
179 | SyMutexRelease(sJx9MPGlobal.pMutexMethods, sJx9MPGlobal.pMutex); | ||
180 | if( sJx9MPGlobal.pMutexMethods->xGlobalRelease ){ | ||
181 | sJx9MPGlobal.pMutexMethods->xGlobalRelease(); | ||
182 | } | ||
183 | sJx9MPGlobal.pMutex = 0; | ||
184 | } | ||
185 | /* Initialize and install the new mutex subsystem */ | ||
186 | if( pMethods->xGlobalInit ){ | ||
187 | rc = pMethods->xGlobalInit(); | ||
188 | if ( rc != JX9_OK ){ | ||
189 | break; | ||
190 | } | ||
191 | } | ||
192 | /* Create the global mutex */ | ||
193 | sJx9MPGlobal.pMutex = pMethods->xNew(SXMUTEX_TYPE_FAST); | ||
194 | if( sJx9MPGlobal.pMutex == 0 ){ | ||
195 | /* | ||
196 | * If the supplied mutex subsystem is so sick that we are unable to | ||
197 | * create a single mutex, there is no much we can do here. | ||
198 | */ | ||
199 | if( pMethods->xGlobalRelease ){ | ||
200 | pMethods->xGlobalRelease(); | ||
201 | } | ||
202 | rc = JX9_CORRUPT; | ||
203 | break; | ||
204 | } | ||
205 | sJx9MPGlobal.pMutexMethods = pMethods; | ||
206 | if( sJx9MPGlobal.nThreadingLevel == 0 ){ | ||
207 | /* Set a default threading level */ | ||
208 | sJx9MPGlobal.nThreadingLevel = JX9_THREAD_LEVEL_MULTI; | ||
209 | } | ||
210 | #endif | ||
211 | break; | ||
212 | } | ||
213 | case JX9_LIB_CONFIG_THREAD_LEVEL_SINGLE: | ||
214 | #if defined(JX9_ENABLE_THREADS) | ||
215 | /* Single thread mode(Only one thread is allowed to play with the library) */ | ||
216 | sJx9MPGlobal.nThreadingLevel = JX9_THREAD_LEVEL_SINGLE; | ||
217 | #endif | ||
218 | break; | ||
219 | case JX9_LIB_CONFIG_THREAD_LEVEL_MULTI: | ||
220 | #if defined(JX9_ENABLE_THREADS) | ||
221 | /* Multi-threading mode (library is thread safe and JX9 engines and virtual machines | ||
222 | * may be shared between multiple threads). | ||
223 | */ | ||
224 | sJx9MPGlobal.nThreadingLevel = JX9_THREAD_LEVEL_MULTI; | ||
225 | #endif | ||
226 | break; | ||
227 | default: | ||
228 | /* Unknown configuration option */ | ||
229 | rc = JX9_CORRUPT; | ||
230 | break; | ||
231 | } | ||
232 | return rc; | ||
233 | } | ||
234 | /* | ||
235 | * [CAPIREF: jx9_lib_config()] | ||
236 | * Please refer to the official documentation for function purpose and expected parameters. | ||
237 | */ | ||
238 | JX9_PRIVATE int jx9_lib_config(int nConfigOp, ...) | ||
239 | { | ||
240 | va_list ap; | ||
241 | int rc; | ||
242 | if( sJx9MPGlobal.nMagic == JX9_LIB_MAGIC ){ | ||
243 | /* Library is already initialized, this operation is forbidden */ | ||
244 | return JX9_LOOKED; | ||
245 | } | ||
246 | va_start(ap, nConfigOp); | ||
247 | rc = Jx9CoreConfigure(nConfigOp, ap); | ||
248 | va_end(ap); | ||
249 | return rc; | ||
250 | } | ||
251 | /* | ||
252 | * Global library initialization | ||
253 | * Refer to [jx9_lib_init()] | ||
254 | * This routine must be called to initialize the memory allocation subsystem, the mutex | ||
255 | * subsystem prior to doing any serious work with the library.The first thread to call | ||
256 | * this routine does the initialization process and set the magic number so no body later | ||
257 | * can re-initialize the library.If subsequent threads call this routine before the first | ||
258 | * thread have finished the initialization process, then the subsequent threads must block | ||
259 | * until the initialization process is done. | ||
260 | */ | ||
261 | static sxi32 Jx9CoreInitialize(void) | ||
262 | { | ||
263 | const jx9_vfs *pVfs; /* Built-in vfs */ | ||
264 | #if defined(JX9_ENABLE_THREADS) | ||
265 | const SyMutexMethods *pMutexMethods = 0; | ||
266 | SyMutex *pMaster = 0; | ||
267 | #endif | ||
268 | int rc; | ||
269 | /* | ||
270 | * If the library is already initialized, then a call to this routine | ||
271 | * is a no-op. | ||
272 | */ | ||
273 | if( sJx9MPGlobal.nMagic == JX9_LIB_MAGIC ){ | ||
274 | return JX9_OK; /* Already initialized */ | ||
275 | } | ||
276 | /* Point to the built-in vfs */ | ||
277 | pVfs = jx9ExportBuiltinVfs(); | ||
278 | /* Install it */ | ||
279 | jx9_lib_config(JX9_LIB_CONFIG_VFS, pVfs); | ||
280 | #if defined(JX9_ENABLE_THREADS) | ||
281 | if( sJx9MPGlobal.nThreadingLevel != JX9_THREAD_LEVEL_SINGLE ){ | ||
282 | pMutexMethods = sJx9MPGlobal.pMutexMethods; | ||
283 | if( pMutexMethods == 0 ){ | ||
284 | /* Use the built-in mutex subsystem */ | ||
285 | pMutexMethods = SyMutexExportMethods(); | ||
286 | if( pMutexMethods == 0 ){ | ||
287 | return JX9_CORRUPT; /* Can't happen */ | ||
288 | } | ||
289 | /* Install the mutex subsystem */ | ||
290 | rc = jx9_lib_config(JX9_LIB_CONFIG_USER_MUTEX, pMutexMethods); | ||
291 | if( rc != JX9_OK ){ | ||
292 | return rc; | ||
293 | } | ||
294 | } | ||
295 | /* Obtain a static mutex so we can initialize the library without calling malloc() */ | ||
296 | pMaster = SyMutexNew(pMutexMethods, SXMUTEX_TYPE_STATIC_1); | ||
297 | if( pMaster == 0 ){ | ||
298 | return JX9_CORRUPT; /* Can't happen */ | ||
299 | } | ||
300 | } | ||
301 | /* Lock the master mutex */ | ||
302 | rc = JX9_OK; | ||
303 | SyMutexEnter(pMutexMethods, pMaster); /* NO-OP if sJx9MPGlobal.nThreadingLevel == JX9_THREAD_LEVEL_SINGLE */ | ||
304 | if( sJx9MPGlobal.nMagic != JX9_LIB_MAGIC ){ | ||
305 | #endif | ||
306 | if( sJx9MPGlobal.sAllocator.pMethods == 0 ){ | ||
307 | /* Install a memory subsystem */ | ||
308 | rc = jx9_lib_config(JX9_LIB_CONFIG_USER_MALLOC, 0); /* zero mean use the built-in memory backend */ | ||
309 | if( rc != JX9_OK ){ | ||
310 | /* If we are unable to initialize the memory backend, there is no much we can do here.*/ | ||
311 | goto End; | ||
312 | } | ||
313 | } | ||
314 | #if defined(JX9_ENABLE_THREADS) | ||
315 | if( sJx9MPGlobal.nThreadingLevel > JX9_THREAD_LEVEL_SINGLE ){ | ||
316 | /* Protect the memory allocation subsystem */ | ||
317 | rc = SyMemBackendMakeThreadSafe(&sJx9MPGlobal.sAllocator, sJx9MPGlobal.pMutexMethods); | ||
318 | if( rc != JX9_OK ){ | ||
319 | goto End; | ||
320 | } | ||
321 | } | ||
322 | #endif | ||
323 | /* Our library is initialized, set the magic number */ | ||
324 | sJx9MPGlobal.nMagic = JX9_LIB_MAGIC; | ||
325 | rc = JX9_OK; | ||
326 | #if defined(JX9_ENABLE_THREADS) | ||
327 | } /* sJx9MPGlobal.nMagic != JX9_LIB_MAGIC */ | ||
328 | #endif | ||
329 | End: | ||
330 | #if defined(JX9_ENABLE_THREADS) | ||
331 | /* Unlock the master mutex */ | ||
332 | SyMutexLeave(pMutexMethods, pMaster); /* NO-OP if sJx9MPGlobal.nThreadingLevel == JX9_THREAD_LEVEL_SINGLE */ | ||
333 | #endif | ||
334 | return rc; | ||
335 | } | ||
336 | /* | ||
337 | * Release an active JX9 engine and it's associated active virtual machines. | ||
338 | */ | ||
339 | static sxi32 EngineRelease(jx9 *pEngine) | ||
340 | { | ||
341 | jx9_vm *pVm, *pNext; | ||
342 | /* Release all active VM */ | ||
343 | pVm = pEngine->pVms; | ||
344 | for(;;){ | ||
345 | if( pEngine->iVm < 1 ){ | ||
346 | break; | ||
347 | } | ||
348 | pNext = pVm->pNext; | ||
349 | jx9VmRelease(pVm); | ||
350 | pVm = pNext; | ||
351 | pEngine->iVm--; | ||
352 | } | ||
353 | /* Set a dummy magic number */ | ||
354 | pEngine->nMagic = 0x7635; | ||
355 | /* Release the private memory subsystem */ | ||
356 | SyMemBackendRelease(&pEngine->sAllocator); | ||
357 | return JX9_OK; | ||
358 | } | ||
359 | /* | ||
360 | * Release all resources consumed by the library. | ||
361 | * If JX9 is already shut when this routine is invoked then this | ||
362 | * routine is a harmless no-op. | ||
363 | * Note: This call is not thread safe. Refer to [jx9_lib_shutdown()]. | ||
364 | */ | ||
365 | static void JX9CoreShutdown(void) | ||
366 | { | ||
367 | jx9 *pEngine, *pNext; | ||
368 | /* Release all active engines first */ | ||
369 | pEngine = sJx9MPGlobal.pEngines; | ||
370 | for(;;){ | ||
371 | if( sJx9MPGlobal.nEngine < 1 ){ | ||
372 | break; | ||
373 | } | ||
374 | pNext = pEngine->pNext; | ||
375 | EngineRelease(pEngine); | ||
376 | pEngine = pNext; | ||
377 | sJx9MPGlobal.nEngine--; | ||
378 | } | ||
379 | #if defined(JX9_ENABLE_THREADS) | ||
380 | /* Release the mutex subsystem */ | ||
381 | if( sJx9MPGlobal.pMutexMethods ){ | ||
382 | if( sJx9MPGlobal.pMutex ){ | ||
383 | SyMutexRelease(sJx9MPGlobal.pMutexMethods, sJx9MPGlobal.pMutex); | ||
384 | sJx9MPGlobal.pMutex = 0; | ||
385 | } | ||
386 | if( sJx9MPGlobal.pMutexMethods->xGlobalRelease ){ | ||
387 | sJx9MPGlobal.pMutexMethods->xGlobalRelease(); | ||
388 | } | ||
389 | sJx9MPGlobal.pMutexMethods = 0; | ||
390 | } | ||
391 | sJx9MPGlobal.nThreadingLevel = 0; | ||
392 | #endif | ||
393 | if( sJx9MPGlobal.sAllocator.pMethods ){ | ||
394 | /* Release the memory backend */ | ||
395 | SyMemBackendRelease(&sJx9MPGlobal.sAllocator); | ||
396 | } | ||
397 | sJx9MPGlobal.nMagic = 0x1928; | ||
398 | } | ||
399 | /* | ||
400 | * [CAPIREF: jx9_lib_shutdown()] | ||
401 | * Please refer to the official documentation for function purpose and expected parameters. | ||
402 | */ | ||
403 | JX9_PRIVATE int jx9_lib_shutdown(void) | ||
404 | { | ||
405 | if( sJx9MPGlobal.nMagic != JX9_LIB_MAGIC ){ | ||
406 | /* Already shut */ | ||
407 | return JX9_OK; | ||
408 | } | ||
409 | JX9CoreShutdown(); | ||
410 | return JX9_OK; | ||
411 | } | ||
412 | /* | ||
413 | * [CAPIREF: jx9_lib_signature()] | ||
414 | * Please refer to the official documentation for function purpose and expected parameters. | ||
415 | */ | ||
416 | JX9_PRIVATE const char * jx9_lib_signature(void) | ||
417 | { | ||
418 | return JX9_SIG; | ||
419 | } | ||
420 | /* | ||
421 | * [CAPIREF: jx9_init()] | ||
422 | * Please refer to the official documentation for function purpose and expected parameters. | ||
423 | */ | ||
424 | JX9_PRIVATE int jx9_init(jx9 **ppEngine) | ||
425 | { | ||
426 | jx9 *pEngine; | ||
427 | int rc; | ||
428 | #if defined(UNTRUST) | ||
429 | if( ppEngine == 0 ){ | ||
430 | return JX9_CORRUPT; | ||
431 | } | ||
432 | #endif | ||
433 | *ppEngine = 0; | ||
434 | /* One-time automatic library initialization */ | ||
435 | rc = Jx9CoreInitialize(); | ||
436 | if( rc != JX9_OK ){ | ||
437 | return rc; | ||
438 | } | ||
439 | /* Allocate a new engine */ | ||
440 | pEngine = (jx9 *)SyMemBackendPoolAlloc(&sJx9MPGlobal.sAllocator, sizeof(jx9)); | ||
441 | if( pEngine == 0 ){ | ||
442 | return JX9_NOMEM; | ||
443 | } | ||
444 | /* Zero the structure */ | ||
445 | SyZero(pEngine, sizeof(jx9)); | ||
446 | /* Initialize engine fields */ | ||
447 | pEngine->nMagic = JX9_ENGINE_MAGIC; | ||
448 | rc = SyMemBackendInitFromParent(&pEngine->sAllocator, &sJx9MPGlobal.sAllocator); | ||
449 | if( rc != JX9_OK ){ | ||
450 | goto Release; | ||
451 | } | ||
452 | #if defined(JX9_ENABLE_THREADS) | ||
453 | SyMemBackendDisbaleMutexing(&pEngine->sAllocator); | ||
454 | #endif | ||
455 | /* Default configuration */ | ||
456 | SyBlobInit(&pEngine->xConf.sErrConsumer, &pEngine->sAllocator); | ||
457 | /* Install a default compile-time error consumer routine */ | ||
458 | pEngine->xConf.xErr = jx9VmBlobConsumer; | ||
459 | pEngine->xConf.pErrData = &pEngine->xConf.sErrConsumer; | ||
460 | /* Built-in vfs */ | ||
461 | pEngine->pVfs = sJx9MPGlobal.pVfs; | ||
462 | #if defined(JX9_ENABLE_THREADS) | ||
463 | if( sJx9MPGlobal.nThreadingLevel > JX9_THREAD_LEVEL_SINGLE ){ | ||
464 | /* Associate a recursive mutex with this instance */ | ||
465 | pEngine->pMutex = SyMutexNew(sJx9MPGlobal.pMutexMethods, SXMUTEX_TYPE_RECURSIVE); | ||
466 | if( pEngine->pMutex == 0 ){ | ||
467 | rc = JX9_NOMEM; | ||
468 | goto Release; | ||
469 | } | ||
470 | } | ||
471 | #endif | ||
472 | /* Link to the list of active engines */ | ||
473 | #if defined(JX9_ENABLE_THREADS) | ||
474 | /* Enter the global mutex */ | ||
475 | SyMutexEnter(sJx9MPGlobal.pMutexMethods, sJx9MPGlobal.pMutex); /* NO-OP if sJx9MPGlobal.nThreadingLevel == JX9_THREAD_LEVEL_SINGLE */ | ||
476 | #endif | ||
477 | MACRO_LD_PUSH(sJx9MPGlobal.pEngines, pEngine); | ||
478 | sJx9MPGlobal.nEngine++; | ||
479 | #if defined(JX9_ENABLE_THREADS) | ||
480 | /* Leave the global mutex */ | ||
481 | SyMutexLeave(sJx9MPGlobal.pMutexMethods, sJx9MPGlobal.pMutex); /* NO-OP if sJx9MPGlobal.nThreadingLevel == JX9_THREAD_LEVEL_SINGLE */ | ||
482 | #endif | ||
483 | /* Write a pointer to the new instance */ | ||
484 | *ppEngine = pEngine; | ||
485 | return JX9_OK; | ||
486 | Release: | ||
487 | SyMemBackendRelease(&pEngine->sAllocator); | ||
488 | SyMemBackendPoolFree(&sJx9MPGlobal.sAllocator,pEngine); | ||
489 | return rc; | ||
490 | } | ||
491 | /* | ||
492 | * [CAPIREF: jx9_release()] | ||
493 | * Please refer to the official documentation for function purpose and expected parameters. | ||
494 | */ | ||
495 | JX9_PRIVATE int jx9_release(jx9 *pEngine) | ||
496 | { | ||
497 | int rc; | ||
498 | if( JX9_ENGINE_MISUSE(pEngine) ){ | ||
499 | return JX9_CORRUPT; | ||
500 | } | ||
501 | #if defined(JX9_ENABLE_THREADS) | ||
502 | /* Acquire engine mutex */ | ||
503 | SyMutexEnter(sJx9MPGlobal.pMutexMethods, pEngine->pMutex); /* NO-OP if sJx9MPGlobal.nThreadingLevel != JX9_THREAD_LEVEL_MULTI */ | ||
504 | if( sJx9MPGlobal.nThreadingLevel > JX9_THREAD_LEVEL_SINGLE && | ||
505 | JX9_THRD_ENGINE_RELEASE(pEngine) ){ | ||
506 | return JX9_ABORT; /* Another thread have released this instance */ | ||
507 | } | ||
508 | #endif | ||
509 | /* Release the engine */ | ||
510 | rc = EngineRelease(&(*pEngine)); | ||
511 | #if defined(JX9_ENABLE_THREADS) | ||
512 | /* Leave engine mutex */ | ||
513 | SyMutexLeave(sJx9MPGlobal.pMutexMethods, pEngine->pMutex); /* NO-OP if sJx9MPGlobal.nThreadingLevel != JX9_THREAD_LEVEL_MULTI */ | ||
514 | /* Release engine mutex */ | ||
515 | SyMutexRelease(sJx9MPGlobal.pMutexMethods, pEngine->pMutex) /* NO-OP if sJx9MPGlobal.nThreadingLevel != JX9_THREAD_LEVEL_MULTI */ | ||
516 | #endif | ||
517 | #if defined(JX9_ENABLE_THREADS) | ||
518 | /* Enter the global mutex */ | ||
519 | SyMutexEnter(sJx9MPGlobal.pMutexMethods, sJx9MPGlobal.pMutex); /* NO-OP if sJx9MPGlobal.nThreadingLevel == JX9_THREAD_LEVEL_SINGLE */ | ||
520 | #endif | ||
521 | /* Unlink from the list of active engines */ | ||
522 | MACRO_LD_REMOVE(sJx9MPGlobal.pEngines, pEngine); | ||
523 | sJx9MPGlobal.nEngine--; | ||
524 | #if defined(JX9_ENABLE_THREADS) | ||
525 | /* Leave the global mutex */ | ||
526 | SyMutexLeave(sJx9MPGlobal.pMutexMethods, sJx9MPGlobal.pMutex); /* NO-OP if sJx9MPGlobal.nThreadingLevel == JX9_THREAD_LEVEL_SINGLE */ | ||
527 | #endif | ||
528 | /* Release the memory chunk allocated to this engine */ | ||
529 | SyMemBackendPoolFree(&sJx9MPGlobal.sAllocator, pEngine); | ||
530 | return rc; | ||
531 | } | ||
532 | /* | ||
533 | * Compile a raw JX9 script. | ||
534 | * To execute a JX9 code, it must first be compiled into a bytecode program using this routine. | ||
535 | * If something goes wrong [i.e: compile-time error], your error log [i.e: error consumer callback] | ||
536 | * should display the appropriate error message and this function set ppVm to null and return | ||
537 | * an error code that is different from JX9_OK. Otherwise when the script is successfully compiled | ||
538 | * ppVm should hold the JX9 bytecode and it's safe to call [jx9_vm_exec(), jx9_vm_reset(), etc.]. | ||
539 | * This API does not actually evaluate the JX9 code. It merely compile and prepares the JX9 script | ||
540 | * for evaluation. | ||
541 | */ | ||
542 | static sxi32 ProcessScript( | ||
543 | jx9 *pEngine, /* Running JX9 engine */ | ||
544 | jx9_vm **ppVm, /* OUT: A pointer to the virtual machine */ | ||
545 | SyString *pScript, /* Raw JX9 script to compile */ | ||
546 | sxi32 iFlags, /* Compile-time flags */ | ||
547 | const char *zFilePath /* File path if script come from a file. NULL otherwise */ | ||
548 | ) | ||
549 | { | ||
550 | jx9_vm *pVm; | ||
551 | int rc; | ||
552 | /* Allocate a new virtual machine */ | ||
553 | pVm = (jx9_vm *)SyMemBackendPoolAlloc(&pEngine->sAllocator, sizeof(jx9_vm)); | ||
554 | if( pVm == 0 ){ | ||
555 | /* If the supplied memory subsystem is so sick that we are unable to allocate | ||
556 | * a tiny chunk of memory, there is no much we can do here. */ | ||
557 | if( ppVm ){ | ||
558 | *ppVm = 0; | ||
559 | } | ||
560 | return JX9_NOMEM; | ||
561 | } | ||
562 | if( iFlags < 0 ){ | ||
563 | /* Default compile-time flags */ | ||
564 | iFlags = 0; | ||
565 | } | ||
566 | /* Initialize the Virtual Machine */ | ||
567 | rc = jx9VmInit(pVm, &(*pEngine)); | ||
568 | if( rc != JX9_OK ){ | ||
569 | SyMemBackendPoolFree(&pEngine->sAllocator, pVm); | ||
570 | if( ppVm ){ | ||
571 | *ppVm = 0; | ||
572 | } | ||
573 | return JX9_VM_ERR; | ||
574 | } | ||
575 | if( zFilePath ){ | ||
576 | /* Push processed file path */ | ||
577 | jx9VmPushFilePath(pVm, zFilePath, -1, TRUE, 0); | ||
578 | } | ||
579 | /* Reset the error message consumer */ | ||
580 | SyBlobReset(&pEngine->xConf.sErrConsumer); | ||
581 | /* Compile the script */ | ||
582 | jx9CompileScript(pVm, &(*pScript), iFlags); | ||
583 | if( pVm->sCodeGen.nErr > 0 || pVm == 0){ | ||
584 | sxu32 nErr = pVm->sCodeGen.nErr; | ||
585 | /* Compilation error or null ppVm pointer, release this VM */ | ||
586 | SyMemBackendRelease(&pVm->sAllocator); | ||
587 | SyMemBackendPoolFree(&pEngine->sAllocator, pVm); | ||
588 | if( ppVm ){ | ||
589 | *ppVm = 0; | ||
590 | } | ||
591 | return nErr > 0 ? JX9_COMPILE_ERR : JX9_OK; | ||
592 | } | ||
593 | /* Prepare the virtual machine for bytecode execution */ | ||
594 | rc = jx9VmMakeReady(pVm); | ||
595 | if( rc != JX9_OK ){ | ||
596 | goto Release; | ||
597 | } | ||
598 | /* Install local import path which is the current directory */ | ||
599 | jx9_vm_config(pVm, JX9_VM_CONFIG_IMPORT_PATH, "./"); | ||
600 | #if defined(JX9_ENABLE_THREADS) | ||
601 | if( sJx9MPGlobal.nThreadingLevel > JX9_THREAD_LEVEL_SINGLE ){ | ||
602 | /* Associate a recursive mutex with this instance */ | ||
603 | pVm->pMutex = SyMutexNew(sJx9MPGlobal.pMutexMethods, SXMUTEX_TYPE_RECURSIVE); | ||
604 | if( pVm->pMutex == 0 ){ | ||
605 | goto Release; | ||
606 | } | ||
607 | } | ||
608 | #endif | ||
609 | /* Script successfully compiled, link to the list of active virtual machines */ | ||
610 | MACRO_LD_PUSH(pEngine->pVms, pVm); | ||
611 | pEngine->iVm++; | ||
612 | /* Point to the freshly created VM */ | ||
613 | *ppVm = pVm; | ||
614 | /* Ready to execute JX9 bytecode */ | ||
615 | return JX9_OK; | ||
616 | Release: | ||
617 | SyMemBackendRelease(&pVm->sAllocator); | ||
618 | SyMemBackendPoolFree(&pEngine->sAllocator, pVm); | ||
619 | *ppVm = 0; | ||
620 | return JX9_VM_ERR; | ||
621 | } | ||
622 | /* | ||
623 | * [CAPIREF: jx9_compile()] | ||
624 | * Please refer to the official documentation for function purpose and expected parameters. | ||
625 | */ | ||
626 | JX9_PRIVATE int jx9_compile(jx9 *pEngine, const char *zSource, int nLen, jx9_vm **ppOutVm) | ||
627 | { | ||
628 | SyString sScript; | ||
629 | int rc; | ||
630 | if( JX9_ENGINE_MISUSE(pEngine) ){ | ||
631 | return JX9_CORRUPT; | ||
632 | } | ||
633 | if( zSource == 0 ){ | ||
634 | /* Empty Jx9 statement ';' */ | ||
635 | zSource = ";"; | ||
636 | nLen = (int)sizeof(char); | ||
637 | } | ||
638 | if( nLen < 0 ){ | ||
639 | /* Compute input length automatically */ | ||
640 | nLen = (int)SyStrlen(zSource); | ||
641 | } | ||
642 | SyStringInitFromBuf(&sScript, zSource, nLen); | ||
643 | #if defined(JX9_ENABLE_THREADS) | ||
644 | /* Acquire engine mutex */ | ||
645 | SyMutexEnter(sJx9MPGlobal.pMutexMethods, pEngine->pMutex); /* NO-OP if sJx9MPGlobal.nThreadingLevel != JX9_THREAD_LEVEL_MULTI */ | ||
646 | if( sJx9MPGlobal.nThreadingLevel > JX9_THREAD_LEVEL_SINGLE && | ||
647 | JX9_THRD_ENGINE_RELEASE(pEngine) ){ | ||
648 | return JX9_ABORT; /* Another thread have released this instance */ | ||
649 | } | ||
650 | #endif | ||
651 | /* Compile the script */ | ||
652 | rc = ProcessScript(&(*pEngine),ppOutVm,&sScript,0,0); | ||
653 | #if defined(JX9_ENABLE_THREADS) | ||
654 | /* Leave engine mutex */ | ||
655 | SyMutexLeave(sJx9MPGlobal.pMutexMethods, pEngine->pMutex); /* NO-OP if sJx9MPGlobal.nThreadingLevel != JX9_THREAD_LEVEL_MULTI */ | ||
656 | #endif | ||
657 | /* Compilation result */ | ||
658 | return rc; | ||
659 | } | ||
660 | /* | ||
661 | * [CAPIREF: jx9_compile_file()] | ||
662 | * Please refer to the official documentation for function purpose and expected parameters. | ||
663 | */ | ||
664 | JX9_PRIVATE int jx9_compile_file(jx9 *pEngine, const char *zFilePath, jx9_vm **ppOutVm) | ||
665 | { | ||
666 | const jx9_vfs *pVfs; | ||
667 | int rc; | ||
668 | if( ppOutVm ){ | ||
669 | *ppOutVm = 0; | ||
670 | } | ||
671 | rc = JX9_OK; /* cc warning */ | ||
672 | if( JX9_ENGINE_MISUSE(pEngine) || SX_EMPTY_STR(zFilePath) ){ | ||
673 | return JX9_CORRUPT; | ||
674 | } | ||
675 | #if defined(JX9_ENABLE_THREADS) | ||
676 | /* Acquire engine mutex */ | ||
677 | SyMutexEnter(sJx9MPGlobal.pMutexMethods, pEngine->pMutex); /* NO-OP if sJx9MPGlobal.nThreadingLevel != JX9_THREAD_LEVEL_MULTI */ | ||
678 | if( sJx9MPGlobal.nThreadingLevel > JX9_THREAD_LEVEL_SINGLE && | ||
679 | JX9_THRD_ENGINE_RELEASE(pEngine) ){ | ||
680 | return JX9_ABORT; /* Another thread have released this instance */ | ||
681 | } | ||
682 | #endif | ||
683 | /* | ||
684 | * Check if the underlying vfs implement the memory map | ||
685 | * [i.e: mmap() under UNIX/MapViewOfFile() under windows] function. | ||
686 | */ | ||
687 | pVfs = pEngine->pVfs; | ||
688 | if( pVfs == 0 || pVfs->xMmap == 0 ){ | ||
689 | /* Memory map routine not implemented */ | ||
690 | rc = JX9_IO_ERR; | ||
691 | }else{ | ||
692 | void *pMapView = 0; /* cc warning */ | ||
693 | jx9_int64 nSize = 0; /* cc warning */ | ||
694 | SyString sScript; | ||
695 | /* Try to get a memory view of the whole file */ | ||
696 | rc = pVfs->xMmap(zFilePath, &pMapView, &nSize); | ||
697 | if( rc != JX9_OK ){ | ||
698 | /* Assume an IO error */ | ||
699 | rc = JX9_IO_ERR; | ||
700 | }else{ | ||
701 | /* Compile the file */ | ||
702 | SyStringInitFromBuf(&sScript, pMapView, nSize); | ||
703 | rc = ProcessScript(&(*pEngine), ppOutVm, &sScript,0,zFilePath); | ||
704 | /* Release the memory view of the whole file */ | ||
705 | if( pVfs->xUnmap ){ | ||
706 | pVfs->xUnmap(pMapView, nSize); | ||
707 | } | ||
708 | } | ||
709 | } | ||
710 | #if defined(JX9_ENABLE_THREADS) | ||
711 | /* Leave engine mutex */ | ||
712 | SyMutexLeave(sJx9MPGlobal.pMutexMethods, pEngine->pMutex); /* NO-OP if sJx9MPGlobal.nThreadingLevel != JX9_THREAD_LEVEL_MULTI */ | ||
713 | #endif | ||
714 | /* Compilation result */ | ||
715 | return rc; | ||
716 | } | ||
717 | /* | ||
718 | * [CAPIREF: jx9_vm_config()] | ||
719 | * Please refer to the official documentation for function purpose and expected parameters. | ||
720 | */ | ||
721 | JX9_PRIVATE int jx9_vm_config(jx9_vm *pVm, int iConfigOp, ...) | ||
722 | { | ||
723 | va_list ap; | ||
724 | int rc; | ||
725 | /* Ticket 1433-002: NULL VM is harmless operation */ | ||
726 | if ( JX9_VM_MISUSE(pVm) ){ | ||
727 | return JX9_CORRUPT; | ||
728 | } | ||
729 | #if defined(JX9_ENABLE_THREADS) | ||
730 | /* Acquire VM mutex */ | ||
731 | SyMutexEnter(sJx9MPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sJx9MPGlobal.nThreadingLevel != JX9_THREAD_LEVEL_MULTI */ | ||
732 | if( sJx9MPGlobal.nThreadingLevel > JX9_THREAD_LEVEL_SINGLE && | ||
733 | JX9_THRD_VM_RELEASE(pVm) ){ | ||
734 | return JX9_ABORT; /* Another thread have released this instance */ | ||
735 | } | ||
736 | #endif | ||
737 | /* Confiugure the virtual machine */ | ||
738 | va_start(ap, iConfigOp); | ||
739 | rc = jx9VmConfigure(&(*pVm), iConfigOp, ap); | ||
740 | va_end(ap); | ||
741 | #if defined(JX9_ENABLE_THREADS) | ||
742 | /* Leave VM mutex */ | ||
743 | SyMutexLeave(sJx9MPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sJx9MPGlobal.nThreadingLevel != JX9_THREAD_LEVEL_MULTI */ | ||
744 | #endif | ||
745 | return rc; | ||
746 | } | ||
747 | /* | ||
748 | * [CAPIREF: jx9_vm_release()] | ||
749 | * Please refer to the official documentation for function purpose and expected parameters. | ||
750 | */ | ||
751 | JX9_PRIVATE int jx9_vm_release(jx9_vm *pVm) | ||
752 | { | ||
753 | jx9 *pEngine; | ||
754 | int rc; | ||
755 | /* Ticket 1433-002: NULL VM is harmless operation */ | ||
756 | if ( JX9_VM_MISUSE(pVm) ){ | ||
757 | return JX9_CORRUPT; | ||
758 | } | ||
759 | #if defined(JX9_ENABLE_THREADS) | ||
760 | /* Acquire VM mutex */ | ||
761 | SyMutexEnter(sJx9MPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sJx9MPGlobal.nThreadingLevel != JX9_THREAD_LEVEL_MULTI */ | ||
762 | if( sJx9MPGlobal.nThreadingLevel > JX9_THREAD_LEVEL_SINGLE && | ||
763 | JX9_THRD_VM_RELEASE(pVm) ){ | ||
764 | return JX9_ABORT; /* Another thread have released this instance */ | ||
765 | } | ||
766 | #endif | ||
767 | pEngine = pVm->pEngine; | ||
768 | rc = jx9VmRelease(&(*pVm)); | ||
769 | #if defined(JX9_ENABLE_THREADS) | ||
770 | /* Leave VM mutex */ | ||
771 | SyMutexLeave(sJx9MPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sJx9MPGlobal.nThreadingLevel != JX9_THREAD_LEVEL_MULTI */ | ||
772 | /* Release VM mutex */ | ||
773 | SyMutexRelease(sJx9MPGlobal.pMutexMethods, pVm->pMutex) /* NO-OP if sJx9MPGlobal.nThreadingLevel != JX9_THREAD_LEVEL_MULTI */ | ||
774 | #endif | ||
775 | if( rc == JX9_OK ){ | ||
776 | /* Unlink from the list of active VM */ | ||
777 | #if defined(JX9_ENABLE_THREADS) | ||
778 | /* Acquire engine mutex */ | ||
779 | SyMutexEnter(sJx9MPGlobal.pMutexMethods, pEngine->pMutex); /* NO-OP if sJx9MPGlobal.nThreadingLevel != JX9_THREAD_LEVEL_MULTI */ | ||
780 | if( sJx9MPGlobal.nThreadingLevel > JX9_THREAD_LEVEL_SINGLE && | ||
781 | JX9_THRD_ENGINE_RELEASE(pEngine) ){ | ||
782 | return JX9_ABORT; /* Another thread have released this instance */ | ||
783 | } | ||
784 | #endif | ||
785 | MACRO_LD_REMOVE(pEngine->pVms, pVm); | ||
786 | pEngine->iVm--; | ||
787 | /* Release the memory chunk allocated to this VM */ | ||
788 | SyMemBackendPoolFree(&pEngine->sAllocator, pVm); | ||
789 | #if defined(JX9_ENABLE_THREADS) | ||
790 | /* Leave engine mutex */ | ||
791 | SyMutexLeave(sJx9MPGlobal.pMutexMethods, pEngine->pMutex); /* NO-OP if sJx9MPGlobal.nThreadingLevel != JX9_THREAD_LEVEL_MULTI */ | ||
792 | #endif | ||
793 | } | ||
794 | return rc; | ||
795 | } | ||
796 | /* | ||
797 | * [CAPIREF: jx9_create_function()] | ||
798 | * Please refer to the official documentation for function purpose and expected parameters. | ||
799 | */ | ||
800 | JX9_PRIVATE int jx9_create_function(jx9_vm *pVm, const char *zName, int (*xFunc)(jx9_context *, int, jx9_value **), void *pUserData) | ||
801 | { | ||
802 | SyString sName; | ||
803 | int rc; | ||
804 | /* Ticket 1433-002: NULL VM is harmless operation */ | ||
805 | if ( JX9_VM_MISUSE(pVm) ){ | ||
806 | return JX9_CORRUPT; | ||
807 | } | ||
808 | SyStringInitFromBuf(&sName, zName, SyStrlen(zName)); | ||
809 | /* Remove leading and trailing white spaces */ | ||
810 | SyStringFullTrim(&sName); | ||
811 | /* Ticket 1433-003: NULL values are not allowed */ | ||
812 | if( sName.nByte < 1 || xFunc == 0 ){ | ||
813 | return JX9_CORRUPT; | ||
814 | } | ||
815 | #if defined(JX9_ENABLE_THREADS) | ||
816 | /* Acquire VM mutex */ | ||
817 | SyMutexEnter(sJx9MPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sJx9MPGlobal.nThreadingLevel != JX9_THREAD_LEVEL_MULTI */ | ||
818 | if( sJx9MPGlobal.nThreadingLevel > JX9_THREAD_LEVEL_SINGLE && | ||
819 | JX9_THRD_VM_RELEASE(pVm) ){ | ||
820 | return JX9_ABORT; /* Another thread have released this instance */ | ||
821 | } | ||
822 | #endif | ||
823 | /* Install the foreign function */ | ||
824 | rc = jx9VmInstallForeignFunction(&(*pVm), &sName, xFunc, pUserData); | ||
825 | #if defined(JX9_ENABLE_THREADS) | ||
826 | /* Leave VM mutex */ | ||
827 | SyMutexLeave(sJx9MPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sJx9MPGlobal.nThreadingLevel != JX9_THREAD_LEVEL_MULTI */ | ||
828 | #endif | ||
829 | return rc; | ||
830 | } | ||
831 | JX9_PRIVATE int jx9DeleteFunction(jx9_vm *pVm,const char *zName) | ||
832 | { | ||
833 | jx9_user_func *pFunc = 0; /* cc warning */ | ||
834 | int rc; | ||
835 | /* Perform the deletion */ | ||
836 | rc = SyHashDeleteEntry(&pVm->hHostFunction, (const void *)zName, SyStrlen(zName), (void **)&pFunc); | ||
837 | if( rc == JX9_OK ){ | ||
838 | /* Release internal fields */ | ||
839 | SySetRelease(&pFunc->aAux); | ||
840 | SyMemBackendFree(&pVm->sAllocator, (void *)SyStringData(&pFunc->sName)); | ||
841 | SyMemBackendPoolFree(&pVm->sAllocator, pFunc); | ||
842 | } | ||
843 | return rc; | ||
844 | } | ||
845 | /* | ||
846 | * [CAPIREF: jx9_create_constant()] | ||
847 | * Please refer to the official documentation for function purpose and expected parameters. | ||
848 | */ | ||
849 | JX9_PRIVATE int jx9_create_constant(jx9_vm *pVm, const char *zName, void (*xExpand)(jx9_value *, void *), void *pUserData) | ||
850 | { | ||
851 | SyString sName; | ||
852 | int rc; | ||
853 | /* Ticket 1433-002: NULL VM is harmless operation */ | ||
854 | if ( JX9_VM_MISUSE(pVm) ){ | ||
855 | return JX9_CORRUPT; | ||
856 | } | ||
857 | SyStringInitFromBuf(&sName, zName, SyStrlen(zName)); | ||
858 | /* Remove leading and trailing white spaces */ | ||
859 | SyStringFullTrim(&sName); | ||
860 | if( sName.nByte < 1 ){ | ||
861 | /* Empty constant name */ | ||
862 | return JX9_CORRUPT; | ||
863 | } | ||
864 | /* TICKET 1433-003: NULL pointer is harmless operation */ | ||
865 | if( xExpand == 0 ){ | ||
866 | return JX9_CORRUPT; | ||
867 | } | ||
868 | #if defined(JX9_ENABLE_THREADS) | ||
869 | /* Acquire VM mutex */ | ||
870 | SyMutexEnter(sJx9MPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sJx9MPGlobal.nThreadingLevel != JX9_THREAD_LEVEL_MULTI */ | ||
871 | if( sJx9MPGlobal.nThreadingLevel > JX9_THREAD_LEVEL_SINGLE && | ||
872 | JX9_THRD_VM_RELEASE(pVm) ){ | ||
873 | return JX9_ABORT; /* Another thread have released this instance */ | ||
874 | } | ||
875 | #endif | ||
876 | /* Perform the registration */ | ||
877 | rc = jx9VmRegisterConstant(&(*pVm), &sName, xExpand, pUserData); | ||
878 | #if defined(JX9_ENABLE_THREADS) | ||
879 | /* Leave VM mutex */ | ||
880 | SyMutexLeave(sJx9MPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sJx9MPGlobal.nThreadingLevel != JX9_THREAD_LEVEL_MULTI */ | ||
881 | #endif | ||
882 | return rc; | ||
883 | } | ||
884 | JX9_PRIVATE int Jx9DeleteConstant(jx9_vm *pVm,const char *zName) | ||
885 | { | ||
886 | jx9_constant *pCons; | ||
887 | int rc; | ||
888 | /* Query the constant hashtable */ | ||
889 | rc = SyHashDeleteEntry(&pVm->hConstant, (const void *)zName, SyStrlen(zName), (void **)&pCons); | ||
890 | if( rc == JX9_OK ){ | ||
891 | /* Perform the deletion */ | ||
892 | SyMemBackendFree(&pVm->sAllocator, (void *)SyStringData(&pCons->sName)); | ||
893 | SyMemBackendPoolFree(&pVm->sAllocator, pCons); | ||
894 | } | ||
895 | return rc; | ||
896 | } | ||
897 | /* | ||
898 | * [CAPIREF: jx9_new_scalar()] | ||
899 | * Please refer to the official documentation for function purpose and expected parameters. | ||
900 | */ | ||
901 | JX9_PRIVATE jx9_value * jx9_new_scalar(jx9_vm *pVm) | ||
902 | { | ||
903 | jx9_value *pObj; | ||
904 | /* Ticket 1433-002: NULL VM is harmless operation */ | ||
905 | if ( JX9_VM_MISUSE(pVm) ){ | ||
906 | return 0; | ||
907 | } | ||
908 | /* Allocate a new scalar variable */ | ||
909 | pObj = (jx9_value *)SyMemBackendPoolAlloc(&pVm->sAllocator, sizeof(jx9_value)); | ||
910 | if( pObj == 0 ){ | ||
911 | return 0; | ||
912 | } | ||
913 | /* Nullify the new scalar */ | ||
914 | jx9MemObjInit(pVm, pObj); | ||
915 | return pObj; | ||
916 | } | ||
917 | /* | ||
918 | * [CAPIREF: jx9_new_array()] | ||
919 | * Please refer to the official documentation for function purpose and expected parameters. | ||
920 | */ | ||
921 | JX9_PRIVATE jx9_value * jx9_new_array(jx9_vm *pVm) | ||
922 | { | ||
923 | jx9_hashmap *pMap; | ||
924 | jx9_value *pObj; | ||
925 | /* Ticket 1433-002: NULL VM is harmless operation */ | ||
926 | if ( JX9_VM_MISUSE(pVm) ){ | ||
927 | return 0; | ||
928 | } | ||
929 | /* Create a new hashmap first */ | ||
930 | pMap = jx9NewHashmap(&(*pVm), 0, 0); | ||
931 | if( pMap == 0 ){ | ||
932 | return 0; | ||
933 | } | ||
934 | /* Associate a new jx9_value with this hashmap */ | ||
935 | pObj = (jx9_value *)SyMemBackendPoolAlloc(&pVm->sAllocator, sizeof(jx9_value)); | ||
936 | if( pObj == 0 ){ | ||
937 | jx9HashmapRelease(pMap, TRUE); | ||
938 | return 0; | ||
939 | } | ||
940 | jx9MemObjInitFromArray(pVm, pObj, pMap); | ||
941 | return pObj; | ||
942 | } | ||
943 | /* | ||
944 | * [CAPIREF: jx9_release_value()] | ||
945 | * Please refer to the official documentation for function purpose and expected parameters. | ||
946 | */ | ||
947 | JX9_PRIVATE int jx9_release_value(jx9_vm *pVm, jx9_value *pValue) | ||
948 | { | ||
949 | /* Ticket 1433-002: NULL VM is a harmless operation */ | ||
950 | if ( JX9_VM_MISUSE(pVm) ){ | ||
951 | return JX9_CORRUPT; | ||
952 | } | ||
953 | if( pValue ){ | ||
954 | /* Release the value */ | ||
955 | jx9MemObjRelease(pValue); | ||
956 | SyMemBackendPoolFree(&pVm->sAllocator, pValue); | ||
957 | } | ||
958 | return JX9_OK; | ||
959 | } | ||
960 | /* | ||
961 | * [CAPIREF: jx9_value_to_int()] | ||
962 | * Please refer to the official documentation for function purpose and expected parameters. | ||
963 | */ | ||
964 | JX9_PRIVATE int jx9_value_to_int(jx9_value *pValue) | ||
965 | { | ||
966 | int rc; | ||
967 | rc = jx9MemObjToInteger(pValue); | ||
968 | if( rc != JX9_OK ){ | ||
969 | return 0; | ||
970 | } | ||
971 | return (int)pValue->x.iVal; | ||
972 | } | ||
973 | /* | ||
974 | * [CAPIREF: jx9_value_to_bool()] | ||
975 | * Please refer to the official documentation for function purpose and expected parameters. | ||
976 | */ | ||
977 | JX9_PRIVATE int jx9_value_to_bool(jx9_value *pValue) | ||
978 | { | ||
979 | int rc; | ||
980 | rc = jx9MemObjToBool(pValue); | ||
981 | if( rc != JX9_OK ){ | ||
982 | return 0; | ||
983 | } | ||
984 | return (int)pValue->x.iVal; | ||
985 | } | ||
986 | /* | ||
987 | * [CAPIREF: jx9_value_to_int64()] | ||
988 | * Please refer to the official documentation for function purpose and expected parameters. | ||
989 | */ | ||
990 | JX9_PRIVATE jx9_int64 jx9_value_to_int64(jx9_value *pValue) | ||
991 | { | ||
992 | int rc; | ||
993 | rc = jx9MemObjToInteger(pValue); | ||
994 | if( rc != JX9_OK ){ | ||
995 | return 0; | ||
996 | } | ||
997 | return pValue->x.iVal; | ||
998 | } | ||
999 | /* | ||
1000 | * [CAPIREF: jx9_value_to_double()] | ||
1001 | * Please refer to the official documentation for function purpose and expected parameters. | ||
1002 | */ | ||
1003 | JX9_PRIVATE double jx9_value_to_double(jx9_value *pValue) | ||
1004 | { | ||
1005 | int rc; | ||
1006 | rc = jx9MemObjToReal(pValue); | ||
1007 | if( rc != JX9_OK ){ | ||
1008 | return (double)0; | ||
1009 | } | ||
1010 | return (double)pValue->x.rVal; | ||
1011 | } | ||
1012 | /* | ||
1013 | * [CAPIREF: jx9_value_to_string()] | ||
1014 | * Please refer to the official documentation for function purpose and expected parameters. | ||
1015 | */ | ||
1016 | JX9_PRIVATE const char * jx9_value_to_string(jx9_value *pValue, int *pLen) | ||
1017 | { | ||
1018 | jx9MemObjToString(pValue); | ||
1019 | if( SyBlobLength(&pValue->sBlob) > 0 ){ | ||
1020 | SyBlobNullAppend(&pValue->sBlob); | ||
1021 | if( pLen ){ | ||
1022 | *pLen = (int)SyBlobLength(&pValue->sBlob); | ||
1023 | } | ||
1024 | return (const char *)SyBlobData(&pValue->sBlob); | ||
1025 | }else{ | ||
1026 | /* Return the empty string */ | ||
1027 | if( pLen ){ | ||
1028 | *pLen = 0; | ||
1029 | } | ||
1030 | return ""; | ||
1031 | } | ||
1032 | } | ||
1033 | /* | ||
1034 | * [CAPIREF: jx9_value_to_resource()] | ||
1035 | * Please refer to the official documentation for function purpose and expected parameters. | ||
1036 | */ | ||
1037 | JX9_PRIVATE void * jx9_value_to_resource(jx9_value *pValue) | ||
1038 | { | ||
1039 | if( (pValue->iFlags & MEMOBJ_RES) == 0 ){ | ||
1040 | /* Not a resource, return NULL */ | ||
1041 | return 0; | ||
1042 | } | ||
1043 | return pValue->x.pOther; | ||
1044 | } | ||
1045 | /* | ||
1046 | * [CAPIREF: jx9_value_compare()] | ||
1047 | * Please refer to the official documentation for function purpose and expected parameters. | ||
1048 | */ | ||
1049 | JX9_PRIVATE int jx9_value_compare(jx9_value *pLeft, jx9_value *pRight, int bStrict) | ||
1050 | { | ||
1051 | int rc; | ||
1052 | if( pLeft == 0 || pRight == 0 ){ | ||
1053 | /* TICKET 1433-24: NULL values is harmless operation */ | ||
1054 | return 1; | ||
1055 | } | ||
1056 | /* Perform the comparison */ | ||
1057 | rc = jx9MemObjCmp(&(*pLeft), &(*pRight), bStrict, 0); | ||
1058 | /* Comparison result */ | ||
1059 | return rc; | ||
1060 | } | ||
1061 | /* | ||
1062 | * [CAPIREF: jx9_result_int()] | ||
1063 | * Please refer to the official documentation for function purpose and expected parameters. | ||
1064 | */ | ||
1065 | JX9_PRIVATE int jx9_result_int(jx9_context *pCtx, int iValue) | ||
1066 | { | ||
1067 | return jx9_value_int(pCtx->pRet, iValue); | ||
1068 | } | ||
1069 | /* | ||
1070 | * [CAPIREF: jx9_result_int64()] | ||
1071 | * Please refer to the official documentation for function purpose and expected parameters. | ||
1072 | */ | ||
1073 | JX9_PRIVATE int jx9_result_int64(jx9_context *pCtx, jx9_int64 iValue) | ||
1074 | { | ||
1075 | return jx9_value_int64(pCtx->pRet, iValue); | ||
1076 | } | ||
1077 | /* | ||
1078 | * [CAPIREF: jx9_result_bool()] | ||
1079 | * Please refer to the official documentation for function purpose and expected parameters. | ||
1080 | */ | ||
1081 | JX9_PRIVATE int jx9_result_bool(jx9_context *pCtx, int iBool) | ||
1082 | { | ||
1083 | return jx9_value_bool(pCtx->pRet, iBool); | ||
1084 | } | ||
1085 | /* | ||
1086 | * [CAPIREF: jx9_result_double()] | ||
1087 | * Please refer to the official documentation for function purpose and expected parameters. | ||
1088 | */ | ||
1089 | JX9_PRIVATE int jx9_result_double(jx9_context *pCtx, double Value) | ||
1090 | { | ||
1091 | return jx9_value_double(pCtx->pRet, Value); | ||
1092 | } | ||
1093 | /* | ||
1094 | * [CAPIREF: jx9_result_null()] | ||
1095 | * Please refer to the official documentation for function purpose and expected parameters. | ||
1096 | */ | ||
1097 | JX9_PRIVATE int jx9_result_null(jx9_context *pCtx) | ||
1098 | { | ||
1099 | /* Invalidate any prior representation and set the NULL flag */ | ||
1100 | jx9MemObjRelease(pCtx->pRet); | ||
1101 | return JX9_OK; | ||
1102 | } | ||
1103 | /* | ||
1104 | * [CAPIREF: jx9_result_string()] | ||
1105 | * Please refer to the official documentation for function purpose and expected parameters. | ||
1106 | */ | ||
1107 | JX9_PRIVATE int jx9_result_string(jx9_context *pCtx, const char *zString, int nLen) | ||
1108 | { | ||
1109 | return jx9_value_string(pCtx->pRet, zString, nLen); | ||
1110 | } | ||
1111 | /* | ||
1112 | * [CAPIREF: jx9_result_string_format()] | ||
1113 | * Please refer to the official documentation for function purpose and expected parameters. | ||
1114 | */ | ||
1115 | JX9_PRIVATE int jx9_result_string_format(jx9_context *pCtx, const char *zFormat, ...) | ||
1116 | { | ||
1117 | jx9_value *p; | ||
1118 | va_list ap; | ||
1119 | int rc; | ||
1120 | p = pCtx->pRet; | ||
1121 | if( (p->iFlags & MEMOBJ_STRING) == 0 ){ | ||
1122 | /* Invalidate any prior representation */ | ||
1123 | jx9MemObjRelease(p); | ||
1124 | MemObjSetType(p, MEMOBJ_STRING); | ||
1125 | } | ||
1126 | /* Format the given string */ | ||
1127 | va_start(ap, zFormat); | ||
1128 | rc = SyBlobFormatAp(&p->sBlob, zFormat, ap); | ||
1129 | va_end(ap); | ||
1130 | return rc; | ||
1131 | } | ||
1132 | /* | ||
1133 | * [CAPIREF: jx9_result_value()] | ||
1134 | * Please refer to the official documentation for function purpose and expected parameters. | ||
1135 | */ | ||
1136 | JX9_PRIVATE int jx9_result_value(jx9_context *pCtx, jx9_value *pValue) | ||
1137 | { | ||
1138 | int rc = JX9_OK; | ||
1139 | if( pValue == 0 ){ | ||
1140 | jx9MemObjRelease(pCtx->pRet); | ||
1141 | }else{ | ||
1142 | rc = jx9MemObjStore(pValue, pCtx->pRet); | ||
1143 | } | ||
1144 | return rc; | ||
1145 | } | ||
1146 | /* | ||
1147 | * [CAPIREF: jx9_result_resource()] | ||
1148 | * Please refer to the official documentation for function purpose and expected parameters. | ||
1149 | */ | ||
1150 | JX9_PRIVATE int jx9_result_resource(jx9_context *pCtx, void *pUserData) | ||
1151 | { | ||
1152 | return jx9_value_resource(pCtx->pRet, pUserData); | ||
1153 | } | ||
1154 | /* | ||
1155 | * [CAPIREF: jx9_context_new_scalar()] | ||
1156 | * Please refer to the official documentation for function purpose and expected parameters. | ||
1157 | */ | ||
1158 | JX9_PRIVATE jx9_value * jx9_context_new_scalar(jx9_context *pCtx) | ||
1159 | { | ||
1160 | jx9_value *pVal; | ||
1161 | pVal = jx9_new_scalar(pCtx->pVm); | ||
1162 | if( pVal ){ | ||
1163 | /* Record value address so it can be freed automatically | ||
1164 | * when the calling function returns. | ||
1165 | */ | ||
1166 | SySetPut(&pCtx->sVar, (const void *)&pVal); | ||
1167 | } | ||
1168 | return pVal; | ||
1169 | } | ||
1170 | /* | ||
1171 | * [CAPIREF: jx9_context_new_array()] | ||
1172 | * Please refer to the official documentation for function purpose and expected parameters. | ||
1173 | */ | ||
1174 | JX9_PRIVATE jx9_value * jx9_context_new_array(jx9_context *pCtx) | ||
1175 | { | ||
1176 | jx9_value *pVal; | ||
1177 | pVal = jx9_new_array(pCtx->pVm); | ||
1178 | if( pVal ){ | ||
1179 | /* Record value address so it can be freed automatically | ||
1180 | * when the calling function returns. | ||
1181 | */ | ||
1182 | SySetPut(&pCtx->sVar, (const void *)&pVal); | ||
1183 | } | ||
1184 | return pVal; | ||
1185 | } | ||
1186 | /* | ||
1187 | * [CAPIREF: jx9_context_release_value()] | ||
1188 | * Please refer to the official documentation for function purpose and expected parameters. | ||
1189 | */ | ||
1190 | JX9_PRIVATE void jx9_context_release_value(jx9_context *pCtx, jx9_value *pValue) | ||
1191 | { | ||
1192 | jx9VmReleaseContextValue(&(*pCtx), pValue); | ||
1193 | } | ||
1194 | /* | ||
1195 | * [CAPIREF: jx9_context_alloc_chunk()] | ||
1196 | * Please refer to the official documentation for function purpose and expected parameters. | ||
1197 | */ | ||
1198 | JX9_PRIVATE void * jx9_context_alloc_chunk(jx9_context *pCtx, unsigned int nByte, int ZeroChunk, int AutoRelease) | ||
1199 | { | ||
1200 | void *pChunk; | ||
1201 | pChunk = SyMemBackendAlloc(&pCtx->pVm->sAllocator, nByte); | ||
1202 | if( pChunk ){ | ||
1203 | if( ZeroChunk ){ | ||
1204 | /* Zero the memory chunk */ | ||
1205 | SyZero(pChunk, nByte); | ||
1206 | } | ||
1207 | if( AutoRelease ){ | ||
1208 | jx9_aux_data sAux; | ||
1209 | /* Track the chunk so that it can be released automatically | ||
1210 | * upon this context is destroyed. | ||
1211 | */ | ||
1212 | sAux.pAuxData = pChunk; | ||
1213 | SySetPut(&pCtx->sChunk, (const void *)&sAux); | ||
1214 | } | ||
1215 | } | ||
1216 | return pChunk; | ||
1217 | } | ||
1218 | /* | ||
1219 | * Check if the given chunk address is registered in the call context | ||
1220 | * chunk container. | ||
1221 | * Return TRUE if registered.FALSE otherwise. | ||
1222 | * Refer to [jx9_context_realloc_chunk(), jx9_context_free_chunk()]. | ||
1223 | */ | ||
1224 | static jx9_aux_data * ContextFindChunk(jx9_context *pCtx, void *pChunk) | ||
1225 | { | ||
1226 | jx9_aux_data *aAux, *pAux; | ||
1227 | sxu32 n; | ||
1228 | if( SySetUsed(&pCtx->sChunk) < 1 ){ | ||
1229 | /* Don't bother processing, the container is empty */ | ||
1230 | return 0; | ||
1231 | } | ||
1232 | /* Perform the lookup */ | ||
1233 | aAux = (jx9_aux_data *)SySetBasePtr(&pCtx->sChunk); | ||
1234 | for( n = 0; n < SySetUsed(&pCtx->sChunk) ; ++n ){ | ||
1235 | pAux = &aAux[n]; | ||
1236 | if( pAux->pAuxData == pChunk ){ | ||
1237 | /* Chunk found */ | ||
1238 | return pAux; | ||
1239 | } | ||
1240 | } | ||
1241 | /* No such allocated chunk */ | ||
1242 | return 0; | ||
1243 | } | ||
1244 | /* | ||
1245 | * [CAPIREF: jx9_context_realloc_chunk()] | ||
1246 | * Please refer to the official documentation for function purpose and expected parameters. | ||
1247 | */ | ||
1248 | JX9_PRIVATE void * jx9_context_realloc_chunk(jx9_context *pCtx, void *pChunk, unsigned int nByte) | ||
1249 | { | ||
1250 | jx9_aux_data *pAux; | ||
1251 | void *pNew; | ||
1252 | pNew = SyMemBackendRealloc(&pCtx->pVm->sAllocator, pChunk, nByte); | ||
1253 | if( pNew ){ | ||
1254 | pAux = ContextFindChunk(pCtx, pChunk); | ||
1255 | if( pAux ){ | ||
1256 | pAux->pAuxData = pNew; | ||
1257 | } | ||
1258 | } | ||
1259 | return pNew; | ||
1260 | } | ||
1261 | /* | ||
1262 | * [CAPIREF: jx9_context_free_chunk()] | ||
1263 | * Please refer to the official documentation for function purpose and expected parameters. | ||
1264 | */ | ||
1265 | JX9_PRIVATE void jx9_context_free_chunk(jx9_context *pCtx, void *pChunk) | ||
1266 | { | ||
1267 | jx9_aux_data *pAux; | ||
1268 | if( pChunk == 0 ){ | ||
1269 | /* TICKET-1433-93: NULL chunk is a harmless operation */ | ||
1270 | return; | ||
1271 | } | ||
1272 | pAux = ContextFindChunk(pCtx, pChunk); | ||
1273 | if( pAux ){ | ||
1274 | /* Mark as destroyed */ | ||
1275 | pAux->pAuxData = 0; | ||
1276 | } | ||
1277 | SyMemBackendFree(&pCtx->pVm->sAllocator, pChunk); | ||
1278 | } | ||
1279 | /* | ||
1280 | * [CAPIREF: jx9_array_fetch()] | ||
1281 | * Please refer to the official documentation for function purpose and expected parameters. | ||
1282 | */ | ||
1283 | JX9_PRIVATE jx9_value * jx9_array_fetch(jx9_value *pArray, const char *zKey, int nByte) | ||
1284 | { | ||
1285 | jx9_hashmap_node *pNode; | ||
1286 | jx9_value *pValue; | ||
1287 | jx9_value skey; | ||
1288 | int rc; | ||
1289 | /* Make sure we are dealing with a valid hashmap */ | ||
1290 | if( (pArray->iFlags & MEMOBJ_HASHMAP) == 0 ){ | ||
1291 | return 0; | ||
1292 | } | ||
1293 | if( nByte < 0 ){ | ||
1294 | nByte = (int)SyStrlen(zKey); | ||
1295 | } | ||
1296 | /* Convert the key to a jx9_value */ | ||
1297 | jx9MemObjInit(pArray->pVm, &skey); | ||
1298 | jx9MemObjStringAppend(&skey, zKey, (sxu32)nByte); | ||
1299 | /* Perform the lookup */ | ||
1300 | rc = jx9HashmapLookup((jx9_hashmap *)pArray->x.pOther, &skey, &pNode); | ||
1301 | jx9MemObjRelease(&skey); | ||
1302 | if( rc != JX9_OK ){ | ||
1303 | /* No such entry */ | ||
1304 | return 0; | ||
1305 | } | ||
1306 | /* Extract the target value */ | ||
1307 | pValue = (jx9_value *)SySetAt(&pArray->pVm->aMemObj, pNode->nValIdx); | ||
1308 | return pValue; | ||
1309 | } | ||
1310 | /* | ||
1311 | * [CAPIREF: jx9_array_walk()] | ||
1312 | * Please refer to the official documentation for function purpose and expected parameters. | ||
1313 | */ | ||
1314 | JX9_PRIVATE int jx9_array_walk(jx9_value *pArray, int (*xWalk)(jx9_value *pValue, jx9_value *, void *), void *pUserData) | ||
1315 | { | ||
1316 | int rc; | ||
1317 | if( xWalk == 0 ){ | ||
1318 | return JX9_CORRUPT; | ||
1319 | } | ||
1320 | /* Make sure we are dealing with a valid hashmap */ | ||
1321 | if( (pArray->iFlags & MEMOBJ_HASHMAP) == 0 ){ | ||
1322 | return JX9_CORRUPT; | ||
1323 | } | ||
1324 | /* Start the walk process */ | ||
1325 | rc = jx9HashmapWalk((jx9_hashmap *)pArray->x.pOther, xWalk, pUserData); | ||
1326 | return rc != JX9_OK ? JX9_ABORT /* User callback request an operation abort*/ : JX9_OK; | ||
1327 | } | ||
1328 | /* | ||
1329 | * [CAPIREF: jx9_array_add_elem()] | ||
1330 | * Please refer to the official documentation for function purpose and expected parameters. | ||
1331 | */ | ||
1332 | JX9_PRIVATE int jx9_array_add_elem(jx9_value *pArray, jx9_value *pKey, jx9_value *pValue) | ||
1333 | { | ||
1334 | int rc; | ||
1335 | /* Make sure we are dealing with a valid hashmap */ | ||
1336 | if( (pArray->iFlags & MEMOBJ_HASHMAP) == 0 ){ | ||
1337 | return JX9_CORRUPT; | ||
1338 | } | ||
1339 | /* Perform the insertion */ | ||
1340 | rc = jx9HashmapInsert((jx9_hashmap *)pArray->x.pOther, &(*pKey), &(*pValue)); | ||
1341 | return rc; | ||
1342 | } | ||
1343 | /* | ||
1344 | * [CAPIREF: jx9_array_add_strkey_elem()] | ||
1345 | * Please refer to the official documentation for function purpose and expected parameters. | ||
1346 | */ | ||
1347 | JX9_PRIVATE int jx9_array_add_strkey_elem(jx9_value *pArray, const char *zKey, jx9_value *pValue) | ||
1348 | { | ||
1349 | int rc; | ||
1350 | /* Make sure we are dealing with a valid hashmap */ | ||
1351 | if( (pArray->iFlags & MEMOBJ_HASHMAP) == 0 ){ | ||
1352 | return JX9_CORRUPT; | ||
1353 | } | ||
1354 | /* Perform the insertion */ | ||
1355 | if( SX_EMPTY_STR(zKey) ){ | ||
1356 | /* Empty key, assign an automatic index */ | ||
1357 | rc = jx9HashmapInsert((jx9_hashmap *)pArray->x.pOther, 0, &(*pValue)); | ||
1358 | }else{ | ||
1359 | jx9_value sKey; | ||
1360 | jx9MemObjInitFromString(pArray->pVm, &sKey, 0); | ||
1361 | jx9MemObjStringAppend(&sKey, zKey, (sxu32)SyStrlen(zKey)); | ||
1362 | rc = jx9HashmapInsert((jx9_hashmap *)pArray->x.pOther, &sKey, &(*pValue)); | ||
1363 | jx9MemObjRelease(&sKey); | ||
1364 | } | ||
1365 | return rc; | ||
1366 | } | ||
1367 | /* | ||
1368 | * [CAPIREF: jx9_array_count()] | ||
1369 | * Please refer to the official documentation for function purpose and expected parameters. | ||
1370 | */ | ||
1371 | JX9_PRIVATE unsigned int jx9_array_count(jx9_value *pArray) | ||
1372 | { | ||
1373 | jx9_hashmap *pMap; | ||
1374 | /* Make sure we are dealing with a valid hashmap */ | ||
1375 | if( (pArray->iFlags & MEMOBJ_HASHMAP) == 0 ){ | ||
1376 | return 0; | ||
1377 | } | ||
1378 | /* Point to the internal representation of the hashmap */ | ||
1379 | pMap = (jx9_hashmap *)pArray->x.pOther; | ||
1380 | return pMap->nEntry; | ||
1381 | } | ||
1382 | /* | ||
1383 | * [CAPIREF: jx9_context_output()] | ||
1384 | * Please refer to the official documentation for function purpose and expected parameters. | ||
1385 | */ | ||
1386 | JX9_PRIVATE int jx9_context_output(jx9_context *pCtx, const char *zString, int nLen) | ||
1387 | { | ||
1388 | SyString sData; | ||
1389 | int rc; | ||
1390 | if( nLen < 0 ){ | ||
1391 | nLen = (int)SyStrlen(zString); | ||
1392 | } | ||
1393 | SyStringInitFromBuf(&sData, zString, nLen); | ||
1394 | rc = jx9VmOutputConsume(pCtx->pVm, &sData); | ||
1395 | return rc; | ||
1396 | } | ||
1397 | /* | ||
1398 | * [CAPIREF: jx9_context_throw_error()] | ||
1399 | * Please refer to the official documentation for function purpose and expected parameters. | ||
1400 | */ | ||
1401 | JX9_PRIVATE int jx9_context_throw_error(jx9_context *pCtx, int iErr, const char *zErr) | ||
1402 | { | ||
1403 | int rc = JX9_OK; | ||
1404 | if( zErr ){ | ||
1405 | rc = jx9VmThrowError(pCtx->pVm, &pCtx->pFunc->sName, iErr, zErr); | ||
1406 | } | ||
1407 | return rc; | ||
1408 | } | ||
1409 | /* | ||
1410 | * [CAPIREF: jx9_context_throw_error_format()] | ||
1411 | * Please refer to the official documentation for function purpose and expected parameters. | ||
1412 | */ | ||
1413 | JX9_PRIVATE int jx9_context_throw_error_format(jx9_context *pCtx, int iErr, const char *zFormat, ...) | ||
1414 | { | ||
1415 | va_list ap; | ||
1416 | int rc; | ||
1417 | if( zFormat == 0){ | ||
1418 | return JX9_OK; | ||
1419 | } | ||
1420 | va_start(ap, zFormat); | ||
1421 | rc = jx9VmThrowErrorAp(pCtx->pVm, &pCtx->pFunc->sName, iErr, zFormat, ap); | ||
1422 | va_end(ap); | ||
1423 | return rc; | ||
1424 | } | ||
1425 | /* | ||
1426 | * [CAPIREF: jx9_context_random_num()] | ||
1427 | * Please refer to the official documentation for function purpose and expected parameters. | ||
1428 | */ | ||
1429 | JX9_PRIVATE unsigned int jx9_context_random_num(jx9_context *pCtx) | ||
1430 | { | ||
1431 | sxu32 n; | ||
1432 | n = jx9VmRandomNum(pCtx->pVm); | ||
1433 | return n; | ||
1434 | } | ||
1435 | /* | ||
1436 | * [CAPIREF: jx9_context_random_string()] | ||
1437 | * Please refer to the official documentation for function purpose and expected parameters. | ||
1438 | */ | ||
1439 | JX9_PRIVATE int jx9_context_random_string(jx9_context *pCtx, char *zBuf, int nBuflen) | ||
1440 | { | ||
1441 | if( nBuflen < 3 ){ | ||
1442 | return JX9_CORRUPT; | ||
1443 | } | ||
1444 | jx9VmRandomString(pCtx->pVm, zBuf, nBuflen); | ||
1445 | return JX9_OK; | ||
1446 | } | ||
1447 | /* | ||
1448 | * [CAPIREF: jx9_context_user_data()] | ||
1449 | * Please refer to the official documentation for function purpose and expected parameters. | ||
1450 | */ | ||
1451 | JX9_PRIVATE void * jx9_context_user_data(jx9_context *pCtx) | ||
1452 | { | ||
1453 | return pCtx->pFunc->pUserData; | ||
1454 | } | ||
1455 | /* | ||
1456 | * [CAPIREF: jx9_context_push_aux_data()] | ||
1457 | * Please refer to the official documentation for function purpose and expected parameters. | ||
1458 | */ | ||
1459 | JX9_PRIVATE int jx9_context_push_aux_data(jx9_context *pCtx, void *pUserData) | ||
1460 | { | ||
1461 | jx9_aux_data sAux; | ||
1462 | int rc; | ||
1463 | sAux.pAuxData = pUserData; | ||
1464 | rc = SySetPut(&pCtx->pFunc->aAux, (const void *)&sAux); | ||
1465 | return rc; | ||
1466 | } | ||
1467 | /* | ||
1468 | * [CAPIREF: jx9_context_peek_aux_data()] | ||
1469 | * Please refer to the official documentation for function purpose and expected parameters. | ||
1470 | */ | ||
1471 | JX9_PRIVATE void * jx9_context_peek_aux_data(jx9_context *pCtx) | ||
1472 | { | ||
1473 | jx9_aux_data *pAux; | ||
1474 | pAux = (jx9_aux_data *)SySetPeek(&pCtx->pFunc->aAux); | ||
1475 | return pAux ? pAux->pAuxData : 0; | ||
1476 | } | ||
1477 | /* | ||
1478 | * [CAPIREF: jx9_context_pop_aux_data()] | ||
1479 | * Please refer to the official documentation for function purpose and expected parameters. | ||
1480 | */ | ||
1481 | JX9_PRIVATE void * jx9_context_pop_aux_data(jx9_context *pCtx) | ||
1482 | { | ||
1483 | jx9_aux_data *pAux; | ||
1484 | pAux = (jx9_aux_data *)SySetPop(&pCtx->pFunc->aAux); | ||
1485 | return pAux ? pAux->pAuxData : 0; | ||
1486 | } | ||
1487 | /* | ||
1488 | * [CAPIREF: jx9_context_result_buf_length()] | ||
1489 | * Please refer to the official documentation for function purpose and expected parameters. | ||
1490 | */ | ||
1491 | JX9_PRIVATE unsigned int jx9_context_result_buf_length(jx9_context *pCtx) | ||
1492 | { | ||
1493 | return SyBlobLength(&pCtx->pRet->sBlob); | ||
1494 | } | ||
1495 | /* | ||
1496 | * [CAPIREF: jx9_function_name()] | ||
1497 | * Please refer to the official documentation for function purpose and expected parameters. | ||
1498 | */ | ||
1499 | JX9_PRIVATE const char * jx9_function_name(jx9_context *pCtx) | ||
1500 | { | ||
1501 | SyString *pName; | ||
1502 | pName = &pCtx->pFunc->sName; | ||
1503 | return pName->zString; | ||
1504 | } | ||
1505 | /* | ||
1506 | * [CAPIREF: jx9_value_int()] | ||
1507 | * Please refer to the official documentation for function purpose and expected parameters. | ||
1508 | */ | ||
1509 | JX9_PRIVATE int jx9_value_int(jx9_value *pVal, int iValue) | ||
1510 | { | ||
1511 | /* Invalidate any prior representation */ | ||
1512 | jx9MemObjRelease(pVal); | ||
1513 | pVal->x.iVal = (jx9_int64)iValue; | ||
1514 | MemObjSetType(pVal, MEMOBJ_INT); | ||
1515 | return JX9_OK; | ||
1516 | } | ||
1517 | /* | ||
1518 | * [CAPIREF: jx9_value_int64()] | ||
1519 | * Please refer to the official documentation for function purpose and expected parameters. | ||
1520 | */ | ||
1521 | JX9_PRIVATE int jx9_value_int64(jx9_value *pVal, jx9_int64 iValue) | ||
1522 | { | ||
1523 | /* Invalidate any prior representation */ | ||
1524 | jx9MemObjRelease(pVal); | ||
1525 | pVal->x.iVal = iValue; | ||
1526 | MemObjSetType(pVal, MEMOBJ_INT); | ||
1527 | return JX9_OK; | ||
1528 | } | ||
1529 | /* | ||
1530 | * [CAPIREF: jx9_value_bool()] | ||
1531 | * Please refer to the official documentation for function purpose and expected parameters. | ||
1532 | */ | ||
1533 | JX9_PRIVATE int jx9_value_bool(jx9_value *pVal, int iBool) | ||
1534 | { | ||
1535 | /* Invalidate any prior representation */ | ||
1536 | jx9MemObjRelease(pVal); | ||
1537 | pVal->x.iVal = iBool ? 1 : 0; | ||
1538 | MemObjSetType(pVal, MEMOBJ_BOOL); | ||
1539 | return JX9_OK; | ||
1540 | } | ||
1541 | /* | ||
1542 | * [CAPIREF: jx9_value_null()] | ||
1543 | * Please refer to the official documentation for function purpose and expected parameters. | ||
1544 | */ | ||
1545 | JX9_PRIVATE int jx9_value_null(jx9_value *pVal) | ||
1546 | { | ||
1547 | /* Invalidate any prior representation and set the NULL flag */ | ||
1548 | jx9MemObjRelease(pVal); | ||
1549 | return JX9_OK; | ||
1550 | } | ||
1551 | /* | ||
1552 | * [CAPIREF: jx9_value_double()] | ||
1553 | * Please refer to the official documentation for function purpose and expected parameters. | ||
1554 | */ | ||
1555 | JX9_PRIVATE int jx9_value_double(jx9_value *pVal, double Value) | ||
1556 | { | ||
1557 | /* Invalidate any prior representation */ | ||
1558 | jx9MemObjRelease(pVal); | ||
1559 | pVal->x.rVal = (jx9_real)Value; | ||
1560 | MemObjSetType(pVal, MEMOBJ_REAL); | ||
1561 | /* Try to get an integer representation also */ | ||
1562 | jx9MemObjTryInteger(pVal); | ||
1563 | return JX9_OK; | ||
1564 | } | ||
1565 | /* | ||
1566 | * [CAPIREF: jx9_value_string()] | ||
1567 | * Please refer to the official documentation for function purpose and expected parameters. | ||
1568 | */ | ||
1569 | JX9_PRIVATE int jx9_value_string(jx9_value *pVal, const char *zString, int nLen) | ||
1570 | { | ||
1571 | if((pVal->iFlags & MEMOBJ_STRING) == 0 ){ | ||
1572 | /* Invalidate any prior representation */ | ||
1573 | jx9MemObjRelease(pVal); | ||
1574 | MemObjSetType(pVal, MEMOBJ_STRING); | ||
1575 | } | ||
1576 | if( zString ){ | ||
1577 | if( nLen < 0 ){ | ||
1578 | /* Compute length automatically */ | ||
1579 | nLen = (int)SyStrlen(zString); | ||
1580 | } | ||
1581 | SyBlobAppend(&pVal->sBlob, (const void *)zString, (sxu32)nLen); | ||
1582 | } | ||
1583 | return JX9_OK; | ||
1584 | } | ||
1585 | /* | ||
1586 | * [CAPIREF: jx9_value_string_format()] | ||
1587 | * Please refer to the official documentation for function purpose and expected parameters. | ||
1588 | */ | ||
1589 | JX9_PRIVATE int jx9_value_string_format(jx9_value *pVal, const char *zFormat, ...) | ||
1590 | { | ||
1591 | va_list ap; | ||
1592 | int rc; | ||
1593 | if((pVal->iFlags & MEMOBJ_STRING) == 0 ){ | ||
1594 | /* Invalidate any prior representation */ | ||
1595 | jx9MemObjRelease(pVal); | ||
1596 | MemObjSetType(pVal, MEMOBJ_STRING); | ||
1597 | } | ||
1598 | va_start(ap, zFormat); | ||
1599 | rc = SyBlobFormatAp(&pVal->sBlob, zFormat, ap); | ||
1600 | va_end(ap); | ||
1601 | return JX9_OK; | ||
1602 | } | ||
1603 | /* | ||
1604 | * [CAPIREF: jx9_value_reset_string_cursor()] | ||
1605 | * Please refer to the official documentation for function purpose and expected parameters. | ||
1606 | */ | ||
1607 | JX9_PRIVATE int jx9_value_reset_string_cursor(jx9_value *pVal) | ||
1608 | { | ||
1609 | /* Reset the string cursor */ | ||
1610 | SyBlobReset(&pVal->sBlob); | ||
1611 | return JX9_OK; | ||
1612 | } | ||
1613 | /* | ||
1614 | * [CAPIREF: jx9_value_resource()] | ||
1615 | * Please refer to the official documentation for function purpose and expected parameters. | ||
1616 | */ | ||
1617 | JX9_PRIVATE int jx9_value_resource(jx9_value *pVal, void *pUserData) | ||
1618 | { | ||
1619 | /* Invalidate any prior representation */ | ||
1620 | jx9MemObjRelease(pVal); | ||
1621 | /* Reflect the new type */ | ||
1622 | pVal->x.pOther = pUserData; | ||
1623 | MemObjSetType(pVal, MEMOBJ_RES); | ||
1624 | return JX9_OK; | ||
1625 | } | ||
1626 | /* | ||
1627 | * [CAPIREF: jx9_value_release()] | ||
1628 | * Please refer to the official documentation for function purpose and expected parameters. | ||
1629 | */ | ||
1630 | JX9_PRIVATE int jx9_value_release(jx9_value *pVal) | ||
1631 | { | ||
1632 | jx9MemObjRelease(pVal); | ||
1633 | return JX9_OK; | ||
1634 | } | ||
1635 | /* | ||
1636 | * [CAPIREF: jx9_value_is_int()] | ||
1637 | * Please refer to the official documentation for function purpose and expected parameters. | ||
1638 | */ | ||
1639 | JX9_PRIVATE int jx9_value_is_int(jx9_value *pVal) | ||
1640 | { | ||
1641 | return (pVal->iFlags & MEMOBJ_INT) ? TRUE : FALSE; | ||
1642 | } | ||
1643 | /* | ||
1644 | * [CAPIREF: jx9_value_is_float()] | ||
1645 | * Please refer to the official documentation for function purpose and expected parameters. | ||
1646 | */ | ||
1647 | JX9_PRIVATE int jx9_value_is_float(jx9_value *pVal) | ||
1648 | { | ||
1649 | return (pVal->iFlags & MEMOBJ_REAL) ? TRUE : FALSE; | ||
1650 | } | ||
1651 | /* | ||
1652 | * [CAPIREF: jx9_value_is_bool()] | ||
1653 | * Please refer to the official documentation for function purpose and expected parameters. | ||
1654 | */ | ||
1655 | JX9_PRIVATE int jx9_value_is_bool(jx9_value *pVal) | ||
1656 | { | ||
1657 | return (pVal->iFlags & MEMOBJ_BOOL) ? TRUE : FALSE; | ||
1658 | } | ||
1659 | /* | ||
1660 | * [CAPIREF: jx9_value_is_string()] | ||
1661 | * Please refer to the official documentation for function purpose and expected parameters. | ||
1662 | */ | ||
1663 | JX9_PRIVATE int jx9_value_is_string(jx9_value *pVal) | ||
1664 | { | ||
1665 | return (pVal->iFlags & MEMOBJ_STRING) ? TRUE : FALSE; | ||
1666 | } | ||
1667 | /* | ||
1668 | * [CAPIREF: jx9_value_is_null()] | ||
1669 | * Please refer to the official documentation for function purpose and expected parameters. | ||
1670 | */ | ||
1671 | JX9_PRIVATE int jx9_value_is_null(jx9_value *pVal) | ||
1672 | { | ||
1673 | return (pVal->iFlags & MEMOBJ_NULL) ? TRUE : FALSE; | ||
1674 | } | ||
1675 | /* | ||
1676 | * [CAPIREF: jx9_value_is_numeric()] | ||
1677 | * Please refer to the official documentation for function purpose and expected parameters. | ||
1678 | */ | ||
1679 | JX9_PRIVATE int jx9_value_is_numeric(jx9_value *pVal) | ||
1680 | { | ||
1681 | int rc; | ||
1682 | rc = jx9MemObjIsNumeric(pVal); | ||
1683 | return rc; | ||
1684 | } | ||
1685 | /* | ||
1686 | * [CAPIREF: jx9_value_is_callable()] | ||
1687 | * Please refer to the official documentation for function purpose and expected parameters. | ||
1688 | */ | ||
1689 | JX9_PRIVATE int jx9_value_is_callable(jx9_value *pVal) | ||
1690 | { | ||
1691 | int rc; | ||
1692 | rc = jx9VmIsCallable(pVal->pVm, pVal); | ||
1693 | return rc; | ||
1694 | } | ||
1695 | /* | ||
1696 | * [CAPIREF: jx9_value_is_scalar()] | ||
1697 | * Please refer to the official documentation for function purpose and expected parameters. | ||
1698 | */ | ||
1699 | JX9_PRIVATE int jx9_value_is_scalar(jx9_value *pVal) | ||
1700 | { | ||
1701 | return (pVal->iFlags & MEMOBJ_SCALAR) ? TRUE : FALSE; | ||
1702 | } | ||
1703 | /* | ||
1704 | * [CAPIREF: jx9_value_is_json_array()] | ||
1705 | * Please refer to the official documentation for function purpose and expected parameters. | ||
1706 | */ | ||
1707 | JX9_PRIVATE int jx9_value_is_json_array(jx9_value *pVal) | ||
1708 | { | ||
1709 | return (pVal->iFlags & MEMOBJ_HASHMAP) ? TRUE : FALSE; | ||
1710 | } | ||
1711 | /* | ||
1712 | * [CAPIREF: jx9_value_is_json_object()] | ||
1713 | * Please refer to the official documentation for function purpose and expected parameters. | ||
1714 | */ | ||
1715 | JX9_PRIVATE int jx9_value_is_json_object(jx9_value *pVal) | ||
1716 | { | ||
1717 | jx9_hashmap *pMap; | ||
1718 | if( (pVal->iFlags & MEMOBJ_HASHMAP) == 0 ){ | ||
1719 | return FALSE; | ||
1720 | } | ||
1721 | pMap = (jx9_hashmap *)pVal->x.pOther; | ||
1722 | if( (pMap->iFlags & HASHMAP_JSON_OBJECT) == 0 ){ | ||
1723 | return FALSE; | ||
1724 | } | ||
1725 | return TRUE; | ||
1726 | } | ||
1727 | /* | ||
1728 | * [CAPIREF: jx9_value_is_resource()] | ||
1729 | * Please refer to the official documentation for function purpose and expected parameters. | ||
1730 | */ | ||
1731 | JX9_PRIVATE int jx9_value_is_resource(jx9_value *pVal) | ||
1732 | { | ||
1733 | return (pVal->iFlags & MEMOBJ_RES) ? TRUE : FALSE; | ||
1734 | } | ||
1735 | /* | ||
1736 | * [CAPIREF: jx9_value_is_empty()] | ||
1737 | * Please refer to the official documentation for function purpose and expected parameters. | ||
1738 | */ | ||
1739 | JX9_PRIVATE int jx9_value_is_empty(jx9_value *pVal) | ||
1740 | { | ||
1741 | int rc; | ||
1742 | rc = jx9MemObjIsEmpty(pVal); | ||
1743 | return rc; | ||
1744 | } | ||