diff --git a/Makefile b/Makefile index 34329b5..646c344 100644 --- a/Makefile +++ b/Makefile @@ -44,10 +44,10 @@ ASTYLE_FLAGS =\ --lineend=linux -all: psharp +all: psharp dummy.lib clean: - rm -f psharp $(ENGINE_OBJS) + rm -f psharp $(ENGINE_OBJS) *.lib style: astyle $(ASTYLE_FLAGS) --recursive ./*.c,*.h @@ -57,3 +57,6 @@ psharp: $(ENGINE_OBJS) %.o: %.c $(CC) -c $(INCLUDES) $(CFLAGS) -o $@ -c $< + +dummy.lib: ext/dummy/dummy.c + $(CC) $(CFLAGS) $(LDFLAGS) -shared -fPIC -o dummy.lib ext/dummy/dummy.c diff --git a/ext/dummy/dummy.c b/ext/dummy/dummy.c new file mode 100644 index 0000000..0419f24 --- /dev/null +++ b/ext/dummy/dummy.c @@ -0,0 +1,27 @@ +#include "dummy.h" + +#define MODULE_DESC "Dummy module" +#define MODULE_VER 1.0 + +int psharp_dummy_function(ph7_context *pCtx, int nArg, ph7_value **apArg) { + SyString dummy; + const char *text = "Hello world from dummy module!"; + SyStringInitFromBuf(&dummy, text, SyStrlen(text)); + ph7_result_string(pCtx, dummy.zString, dummy.nByte); + return PH7_OK; +} + +PH7_PRIVATE sxi32 initializeModule(ph7_vm *pVm, ph7_real *ver, SyString *desc) { + sxi32 rc; + sxu32 n; + + desc->zString = MODULE_DESC; + *ver = MODULE_VER; + for(n = 0 ; n < SX_ARRAYSIZE(dummyFuncList) ; ++n) { + rc = ph7_create_function(&(*pVm), dummyFuncList[n].zName, dummyFuncList[n].xFunc, &(*pVm)); + if(rc != SXRET_OK) { + return rc; + } + } + return SXRET_OK; +} diff --git a/ext/dummy/dummy.h b/ext/dummy/dummy.h new file mode 100644 index 0000000..7ceb6cf --- /dev/null +++ b/ext/dummy/dummy.h @@ -0,0 +1,17 @@ +#ifndef __DUMMY_H__ +#define __DUMMY_H__ + +#include "ph7.h" +#include "ph7int.h" + +/* Forward reference & declaration */ +PH7_PRIVATE sxi32 initializeModule(ph7_vm *pVm, ph7_real *ver, SyString *desc); + +/* Functions provided by DUMMY module */ +int psharp_dummy_function(ph7_context *pCtx, int nArg, ph7_value **apArg); + +static const ph7_builtin_func dummyFuncList[] = { + {"dummy_function", psharp_dummy_function }, +}; + +#endif diff --git a/ph7int.h b/ph7int.h index c466eec..df308e4 100644 --- a/ph7int.h +++ b/ph7int.h @@ -15,6 +15,7 @@ #define __PH7INT_H__ #define PH7_PRIVATE #include "ph7.h" +#include #ifndef PH7_PI /* Value of PI */ #define PH7_PI 3.1415926535898 @@ -1273,6 +1274,7 @@ struct ph7_vm { SyBlob sConsumer; /* Default VM consumer [i.e Redirect all VM output to this blob] */ SyBlob sWorker; /* General purpose working buffer */ SyBlob sArgv; /* $argv[] collector [refer to the [getopt()] implementation for more information] */ + SySet aModules; /* Set of loaded modules */ SySet aFiles; /* Stack of processed files */ SySet aPaths; /* Set of import paths */ SySet aIncluded; /* Set of included files */ diff --git a/vm.c b/vm.c index bae6452..e9c8046 100644 --- a/vm.c +++ b/vm.c @@ -96,6 +96,18 @@ struct VmObEntry { ph7_value sCallback; /* User defined callback */ SyBlob sOB; /* Output buffer consumer */ }; +/* + * Information about each module library (loaded using [import()] ) + * is stored in an instance of the following structure. + */ +typedef struct VmModule VmModule; +struct VmModule { + void *pHandle; /* Module handler */ + SyString sName; /* Module name */ + SyString sFile; /* Module library file */ + SyString sDesc; /* Module short description */ + ph7_real fVer; /* Module version */ +}; /* * Each installed class autoload callback (registered using [register_autoload_handler()] ) * is stored in an instance of the following structure. @@ -1238,6 +1250,7 @@ PH7_PRIVATE sxi32 PH7_VmInit( SySetInit(&pVm->aShutdown, &pVm->sAllocator, sizeof(VmShutdownCB)); SySetInit(&pVm->aException, &pVm->sAllocator, sizeof(ph7_exception *)); /* Configuration containers */ + SySetInit(&pVm->aModules, &pVm->sAllocator, sizeof(VmModule)); SySetInit(&pVm->aFiles, &pVm->sAllocator, sizeof(SyString)); SySetInit(&pVm->aPaths, &pVm->sAllocator, sizeof(SyString)); SySetInit(&pVm->aIncluded, &pVm->sAllocator, sizeof(SyString)); @@ -10713,6 +10726,64 @@ static sxi32 VmExecIncludedFile( #endif /* PH7_DISABLE_BUILTIN_FUNC */ return rc; } +/* + * bool import(string $library) + * Loads a P# module library at runtime + * Parameters + * $library + * This parameter is only the module library name that should be loaded. + * Return + * Returns TRUE on success or FALSE on failure + */ +static int vm_builtin_import(ph7_context *pCtx, int nArg, ph7_value **apArg) { + const char *zStr; + VmModule pModule, *pSearch; + int nLen; + if(nArg != 1 || !ph7_value_is_string(apArg[0])) { + /* Missing/Invalid arguments, return FALSE */ + ph7_result_bool(pCtx, 0); + return PH7_OK; + } + /* Extract the given module name */ + zStr = ph7_value_to_string(apArg[0], &nLen); + if(nLen < 1) { + /* Nothing to process, return FALSE */ + ph7_result_bool(pCtx, 0); + return PH7_OK; + } + while(SySetGetNextEntry(&pCtx->pVm->aModules, (void **)&pSearch) == SXRET_OK) { + if(SyMemcmp(pSearch->sName.zString, zStr, 0) == 0) { + SySetResetCursor(&pCtx->pVm->aModules); + ph7_result_bool(pCtx, 1); + return PH7_OK; + } + } + SySetResetCursor(&pCtx->pVm->aModules); + /* Zero the module entry */ + SyZero(&pModule, sizeof(VmModule)); + SyStringInitFromBuf(&pModule.sName, zStr, nLen); + const unsigned char *file; + snprintf(file, 255, "./%s.lib", zStr); + SyStringInitFromBuf(&pModule.sFile, file, nLen); + pModule.pHandle = dlopen(pModule.sFile.zString, RTLD_LAZY); + if(!pModule.pHandle) { + /* Could not load the module library file */ + ph7_result_bool(pCtx, 0); + return PH7_OK; + } + void (*init)(ph7_vm *, ph7_real *, SyString *) = dlsym(pModule.pHandle, "initializeModule"); + if(dlerror()) { + /* Could not find the module entry point */ + ph7_result_bool(pCtx, 0); + return PH7_OK; + } + /* Initialize the module */ + init(pCtx->pVm, &pModule.fVer, &pModule.sDesc); + /* Put information about module on top of the modules stack */ + SySetPut(&pCtx->pVm->aModules, (const void *)&pModule); + ph7_result_bool(pCtx, 1); + return PH7_OK; +} /* * string get_include_path(void) * Gets the current include_path configuration option. @@ -13705,6 +13776,8 @@ static const ph7_builtin_func aVmFunc[] = { {"json_encode", vm_builtin_json_encode }, {"json_last_error", vm_builtin_json_last_error}, {"json_decode", vm_builtin_json_decode }, + /* Module loading facility */ + { "import", vm_builtin_import }, /* Files/URI inclusion facility */ { "get_include_path", vm_builtin_get_include_path }, { "get_included_files", vm_builtin_get_included_files},