G:/ScriptBasic/source/modumana.c

Go to the documentation of this file.
00001 /* modumana.c
00002 
00003 --GNU LGPL
00004 This library is free software; you can redistribute it and/or
00005 modify it under the terms of the GNU Lesser General Public
00006 License as published by the Free Software Foundation; either
00007 version 2.1 of the License, or (at your option) any later version.
00008 
00009 This library is distributed in the hope that it will be useful,
00010 but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012 Lesser General Public License for more details.
00013 
00014 You should have received a copy of the GNU Lesser General Public
00015 License along with this library; if not, write to the Free Software
00016 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017 
00018  Module manager. Since version 1.0 build 14 module management is moved to the execution level
00019  from the command level. Module management became a general service of the ScriptBasic core
00020  code and is handled mainly in this file.
00021 
00022 */
00023 #include <stdlib.h>
00024 #include <stdio.h>
00025 #include <string.h>
00026 #include <ctype.h>
00027 
00028 #include "basext.h"
00029 #include "sym.h"
00030 #include "errcodes.h"
00031 #include "report.h"
00032 #include "lexer.h"
00033 #include "expression.h"
00034 #include "builder.h"
00035 #include "memory.h"
00036 #include "syntax.h"
00037 #include "execute.h"
00038 #include "myalloc.h"
00039 #include "dynlolib.h"
00040 #include "modumana.h"
00041 
00042 #if BCC32
00043 extern char *_pgmptr;
00044 #endif
00045 extern int GlobalDebugDisplayFlag;
00046 
00047 /*POD
00048 @c Module management
00049 
00050 This file contains all the functions that handle external module management.
00051 
00052 Note that all function names are prepended by T<modu_>
00053 
00054 CUT*/
00055 
00056 /*POD
00057 =H modu_Init
00058 @c Initialize the module management
00059 
00060 This function allocates memory for the external module interface table and
00061 initializes the function pointers.
00062 
00063 If the interface already exists and the function is called again it just
00064 silently returns.
00065 
00066 The second argument can be zero or 1. The normal operation is zero. If T<iForce>
00067 is true the function sets each function pointer to its initial value even if an
00068 initialization has already occured before.
00069 
00070 This can be used in a rare case when a module modifies the interface table and
00071 want to reinitialize it to the original value. Be carefule with such
00072 constructions.
00073 
00074 /*FUNCTION*/
00075 int modu_Init(pExecuteObject pEo,
00076               int iForce
00077   ){
00078 /*noverbatim
00079 CUT*/
00080   if( pEo->pST != NULL && !iForce ) return COMMAND_ERROR_SUCCESS;
00081 
00082   if( pEo->pST == NULL )
00083     pEo->pST = alloc_Alloc(sizeof(SupportTable),pEo->pMemorySegment);
00084   if( pEo->pST == NULL )return COMMAND_ERROR_MEMORY_LOW;
00085   /* If the process level inherited support table is NULL then we are
00086      in a single thread environment. In this case multi-thread modules
00087      may need the STI field pointing to the same support table. */
00088   if( pEo->pSTI == NULL )pEo->pSTI = pEo->pST;
00089   pEo->pST->Alloc               = alloc_Alloc;
00090   pEo->pST->Free                = alloc_Free;
00091   pEo->pST->InitSegment         = alloc_InitSegment;
00092   pEo->pST->SegmentLimit        = alloc_SegmentLimit;
00093   pEo->pST->FreeSegment         = alloc_FreeSegment;
00094   pEo->pST->FinishSegment       = alloc_FinishSegment;
00095   pEo->pST->NewMortalString     = memory_NewMortalString;
00096   pEo->pST->NewMortalLong       = memory_NewMortalLong;
00097   pEo->pST->NewMortalDouble     = memory_NewMortalDouble;
00098   pEo->pST->NewMortalArray      = memory_NewMortalArray;
00099   pEo->pST->NewMortalRef        = memory_NewMortalRef;
00100   pEo->pST->NewString           = memory_NewString;
00101   pEo->pST->NewLong             = memory_NewLong;
00102   pEo->pST->NewDouble           = memory_NewDouble;
00103   pEo->pST->NewArray            = memory_NewArray;
00104   pEo->pST->NewRef              = memory_NewRef;
00105   pEo->pST->ReleaseVariable     = memory_ReleaseVariable;
00106   pEo->pST->SetRef              = memory_SetRef;
00107 
00108   pEo->pST->ConfigData          = cft_GetString;
00109   pEo->pST->FindNode            = cft_FindNode;
00110   pEo->pST->GetEx               = cft_GetEx;
00111   pEo->pST->EnumFirst           = cft_EnumFirst;
00112   pEo->pST->EnumNext            = cft_EnumNext;
00113   pEo->pST->GetKey              = cft_GetKey;
00114 
00115   pEo->pST->NewSymbolTable      = sym_NewSymbolTable;
00116   pEo->pST->FreeSymbolTable     = sym_FreeSymbolTable;
00117   pEo->pST->TraverseSymbolTable = sym_TraverseSymbolTable;
00118   pEo->pST->LookupSymbol        = sym_LookupSymbol;
00119   pEo->pST->DeleteSymbol        = sym_DeleteSymbol;
00120 
00121   pEo->pST->LoadLibrary         = dynlolib_LoadLibrary;
00122   pEo->pST->FreeLibrary         = dynlolib_FreeLibrary;
00123   pEo->pST->GetFunctionByName   = dynlolib_GetFunctionByName;
00124 
00125   pEo->pST->fopen               = file_fopen;
00126   pEo->pST->fclose              = file_fclose;
00127   pEo->pST->size                = file_size;
00128   pEo->pST->time_accessed       = file_time_accessed;
00129   pEo->pST->time_modified       = file_time_modified;
00130   pEo->pST->time_created        = file_time_created;
00131   pEo->pST->isdir               = file_isdir;
00132   pEo->pST->isreg               = file_isreg;
00133   pEo->pST->exists              = file_exists;
00134   pEo->pST->truncate            = file_truncate;
00135   pEo->pST->fgetc               = file_fgetc;
00136   pEo->pST->ferror              = file_ferror;
00137   pEo->pST->fread               = file_fread;
00138   pEo->pST->fwrite              = file_fwrite;
00139   pEo->pST->fputc               = file_fputc;
00140   pEo->pST->flock               = file_flock;
00141   pEo->pST->lock                = file_lock;
00142   pEo->pST->feof                = file_feof;
00143   pEo->pST->mkdir               = file_mkdir;
00144   pEo->pST->rmdir               = file_rmdir;
00145   pEo->pST->remove              = file_remove;
00146   pEo->pST->deltree             = file_deltree;
00147   pEo->pST->MakeDirectory       = file_MakeDirectory;
00148   pEo->pST->opendir             = file_opendir;
00149   pEo->pST->readdir             = file_readdir;
00150   pEo->pST->closedir            = file_closedir;
00151 
00152   pEo->pST->GetOption           = options_Get;
00153   pEo->pST->SetOption           = options_Set;
00154   pEo->pST->ResetOption         = options_Reset;
00155   pEo->pST->Convert2String      = execute_Convert2String;
00156   pEo->pST->Convert2Long        = execute_Convert2LongS;
00157   pEo->pST->GetLongValue        = execute_GetLongValue;
00158   pEo->pST->Convert2Double      = execute_Convert2DoubleS;
00159   pEo->pST->GetDoubleValue      = execute_GetDoubleValue;
00160   pEo->pST->Dereference         = execute_DereferenceS;
00161   pEo->pST->IsStringInteger     = execute_IsStringInteger;
00162 
00163   pEo->pST->InitModuleInterface = modu_Init;
00164   pEo->pST->LoadModule          = modu_LoadModule;
00165   pEo->pST->GetModuleFunctionByName = modu_GetFunctionByName;
00166   pEo->pST->UnloadAllModules    = modu_UnloadAllModules;
00167   pEo->pST->UnloadModule        = modu_UnloadModule;
00168 
00169   pEo->pST->sleep               = sys_sleep;
00170   pEo->pST->curdir              = file_curdir;
00171   pEo->pST->chdir               = file_chdir;
00172   pEo->pST->chown               = file_chown;
00173   pEo->pST->SetCreateTime       = file_SetCreateTime;
00174   pEo->pST->SetModifyTime       = file_SetModifyTime;
00175   pEo->pST->SetAccessTime       = file_SetAccessTime;
00176 
00177   pEo->pST->GetHostName         = file_gethostname;
00178   pEo->pST->GetHost             = file_gethost;
00179   pEo->pST->TcpConnect          = file_tcpconnect;
00180   pEo->pST->TcpSend             = file_tcpsend;
00181   pEo->pST->TcpRecv             = file_tcprecv;
00182   pEo->pST->TcpClose            = file_tcpclose;
00183 
00184   pEo->pST->KillProc            = file_killproc;
00185   pEo->pST->GetOwner            = file_getowner;
00186   pEo->pST->Crypt               = file_fcrypt;
00187 
00188 #pragma warning(disable:4113)
00189   pEo->pST->MD5Init             = MD5Init;
00190   pEo->pST->MD5Update           = MD5Update;
00191   pEo->pST->MD5Final            = MD5Final;
00192 #pragma warning(default:4113)
00193 
00194   pEo->pST->CreateProcess       = file_CreateProcess;
00195 
00196   pEo->pST->CopyCommandTable    = execute_CopyCommandTable;
00197   pEo->pST->GetCommandByName    = execute_GetCommandByName;
00198 
00199   pEo->pST->DupMortalize        = memory_DupMortalize;
00200   pEo->pST->Evaluate            = execute_Evaluate;
00201   pEo->pST->LeftValue           = execute_LeftValue;
00202   pEo->pST->Immortalize         = memory_Immortalize;
00203   pEo->pST->ReleaseMortals      = memory_ReleaseMortals;
00204 
00205 
00206 
00207   pEo->pST->match_index         = match_index;
00208   pEo->pST->match_InitSets      = match_InitSets;
00209   pEo->pST->match_ModifySet     = match_ModifySet;
00210   pEo->pST->match_match         = match_match;
00211   pEo->pST->match_count         = match_count;
00212   pEo->pST->match_parameter     = match_parameter;
00213   pEo->pST->match_size          = match_size;
00214 
00215   pEo->pST->thread_CreateThread = thread_CreateThread;
00216   pEo->pST->thread_ExitThread   = thread_ExitThread;
00217   pEo->pST->thread_InitMutex    = thread_InitMutex;
00218   pEo->pST->thread_FinishMutex  = thread_FinishMutex;
00219   pEo->pST->thread_LockMutex    = thread_LockMutex;
00220   pEo->pST->thread_UnlockMutex  = thread_UnlockMutex;
00221   pEo->pST->shared_InitLock     = shared_InitLock;
00222   pEo->pST->shared_FinishLock   = shared_FinishLock;
00223   pEo->pST->shared_LockRead     = shared_LockRead;
00224   pEo->pST->shared_LockWrite    = shared_LockWrite;
00225   pEo->pST->shared_UnlockRead   = shared_UnlockRead;
00226   pEo->pST->shared_UnlockWrite  = shared_UnlockWrite;
00227 
00228   /* using these callback functions an extension may embed
00229      a ScriptBasic interpreter into the module */
00230 
00231   pEo->pST->scriba_new = scriba_new;
00232   pEo->pST->scriba_destroy = scriba_destroy;
00233   pEo->pST->scriba_NewSbData = scriba_NewSbData;
00234   pEo->pST->scriba_NewSbLong = scriba_NewSbLong;
00235   pEo->pST->scriba_NewSbDouble = scriba_NewSbDouble;
00236   pEo->pST->scriba_NewSbUndef = scriba_NewSbUndef;
00237   pEo->pST->scriba_NewSbString = scriba_NewSbString;
00238   pEo->pST->scriba_NewSbBytes = scriba_NewSbBytes;
00239   pEo->pST->scriba_DestroySbData = scriba_DestroySbData;
00240   pEo->pST->scriba_PurgeReaderMemory = scriba_PurgeReaderMemory;
00241   pEo->pST->scriba_PurgeLexerMemory = scriba_PurgeLexerMemory;
00242   pEo->pST->scriba_PurgeSyntaxerMemory = scriba_PurgeSyntaxerMemory;
00243   pEo->pST->scriba_PurgeBuilderMemory = scriba_PurgeBuilderMemory;
00244   pEo->pST->scriba_PurgeExecuteMemory = scriba_PurgeExecuteMemory;
00245   pEo->pST->scriba_SetFileName = scriba_SetFileName;
00246   pEo->pST->scriba_LoadConfiguration = scriba_LoadConfiguration;
00247   pEo->pST->scriba_InheritConfiguration = scriba_InheritConfiguration;
00248   pEo->pST->scriba_SetCgiFlag = scriba_SetCgiFlag;
00249   pEo->pST->scriba_SetReportFunction = scriba_SetReportFunction;
00250   pEo->pST->scriba_SetReportPointer = scriba_SetReportPointer;
00251   pEo->pST->scriba_SetStdin = scriba_SetStdin;
00252   pEo->pST->scriba_SetStdout = scriba_SetStdout;
00253   pEo->pST->scriba_SetEmbedPointer = scriba_SetEmbedPointer;
00254   pEo->pST->scriba_SetEnvironment = scriba_SetEnvironment;
00255   pEo->pST->scriba_LoadBinaryProgram = scriba_LoadBinaryProgram;
00256   pEo->pST->scriba_InheritBinaryProgram = scriba_InheritBinaryProgram;
00257   pEo->pST->scriba_ReadSource = scriba_ReadSource;
00258   pEo->pST->scriba_DoLexicalAnalysis = scriba_DoLexicalAnalysis;
00259   pEo->pST->scriba_DoSyntaxAnalysis = scriba_DoSyntaxAnalysis;
00260   pEo->pST->scriba_BuildCode = scriba_BuildCode;
00261   pEo->pST->scriba_IsFileBinaryFormat = scriba_IsFileBinaryFormat;
00262   pEo->pST->scriba_GetCacheFileName = scriba_GetCacheFileName;
00263   pEo->pST->scriba_UseCacheFile = scriba_UseCacheFile;
00264   pEo->pST->scriba_SaveCacheFile = scriba_SaveCacheFile;
00265   pEo->pST->scriba_RunExternalPreprocessor = scriba_RunExternalPreprocessor;
00266   pEo->pST->scriba_SaveCode = scriba_SaveCode;
00267   pEo->pST->scriba_SaveCCode = scriba_SaveCCode;
00268   pEo->pST->scriba_LoadSourceProgram = scriba_LoadSourceProgram;
00269   pEo->pST->scriba_Run = scriba_Run;
00270   pEo->pST->scriba_NoRun = scriba_NoRun;
00271   pEo->pST->scriba_ResetVariables = scriba_ResetVariables;
00272   pEo->pST->scriba_Call = scriba_Call;
00273   pEo->pST->scriba_CallArg = scriba_CallArg;
00274   pEo->pST->scriba_DestroySbArgs = scriba_DestroySbArgs;
00275   pEo->pST->scriba_NewSbArgs = scriba_NewSbArgs;
00276   pEo->pST->scriba_CallArgEx = scriba_CallArgEx;
00277   pEo->pST->scriba_LookupFunctionByName = scriba_LookupFunctionByName;
00278   pEo->pST->scriba_LookupVariableByName = scriba_LookupVariableByName;
00279   pEo->pST->scriba_GetVariableType = scriba_GetVariableType;
00280   pEo->pST->scriba_GetVariable = scriba_GetVariable;
00281   pEo->pST->scriba_SetVariable = scriba_SetVariable;
00282 
00283   pEo->pST->log_state = log_state;
00284   pEo->pST->log_init = log_init;
00285   pEo->pST->log_printf = log_printf;
00286   pEo->pST->log_shutdown = log_shutdown;
00287 
00288   pEo->pST->handle_GetHandle = handle_GetHandle;
00289   pEo->pST->handle_GetPointer = handle_GetPointer;
00290   pEo->pST->handle_FreeHandle = handle_FreeHandle;
00291   pEo->pST->handle_DestroyHandleArray = handle_DestroyHandleArray;
00292   pEo->pST->basext_GetArgsF = basext_GetArgsF;
00293 
00294   pEo->pST->pEo                 = pEo;
00295 
00296   return COMMAND_ERROR_SUCCESS;
00297   }
00298 
00299 /*POD
00300 =H modu_Preload
00301 @c Preload the modules configured in the configuration file
00302 
00303 /*FUNCTION*/
00304 int modu_Preload(pExecuteObject pEo
00305   ){
00306 /*noverbatim
00307 CUT*/
00308   char *s;
00309   int iErrorCode;
00310   CFT_NODE Node;
00311 
00312   for( Node = 0;  
00313        ! cft_GetEx(pEo->pConfig,"preload",&Node,&s,NULL,NULL,NULL) ; 
00314        Node = cft_EnumNext(pEo->pConfig,Node) ){
00315     if( (! strcmp(cft_GetKey(pEo->pConfig,Node),"preload") ) &&
00316           (iErrorCode = modu_LoadModule(pEo,s,NULL)) )return iErrorCode;
00317     }
00318   return COMMAND_ERROR_SUCCESS;
00319   }
00320 
00321 /* This global variable should be defined in the file generated by the program makemoduletable.pl */
00322 extern MODLIST StaticallyLinkedModules[];
00323 
00324 /*POD
00325 =H modu_GetModuleFunctionByName
00326 @c Get a function entry point from a module
00327 
00328 This function gets the entrypoint of a module function. This module can either
00329 be statically or dynamically linked to ScriptBasic. This function is one level higher than
00330 R<GetStaticFunctionByName> or 
00331 R<dynlolib_GetFunctionByName>. The first argument to this function
00332 is not the module handle as returned by R<dynlolib_LoadLibrary> but rather the pointer to the
00333 module description structure that holds other information on the modula. Namely the information
00334 that the module is loaded from dll or so, or if the module is linked to the interpreter static.
00335 
00336 /*FUNCTION*/
00337 void *modu_GetModuleFunctionByName(
00338   pModule pThisModule,
00339   char *pszFunctionName
00340   ){
00341 /*noverbatim
00342 CUT*/
00343 
00344   if( pThisModule->ModuleIsStatic )
00345     return modu_GetStaticFunctionByName((void *)pThisModule->ModulePointer,pszFunctionName);
00346   else
00347     return dynlolib_GetFunctionByName((void *)pThisModule->ModulePointer,pszFunctionName);
00348   }
00349 
00350 
00351 /*POD
00352 =H modu_GetStaticFunctionByName
00353 @c Get a function entry point from a statically linked library
00354 
00355 Get the entry point of a function that was linked to the ScriptBasic environment statically.
00356 
00357 This is the counterpart of the function T<dynlolib_GetFunctionByName> for functions in library
00358 linked static. This function searches the T<SLFST> table for the named function and returns the
00359 entry point or T<NULL> if there is no functions with the given name defined.
00360 
00361 /*FUNCTION*/
00362 void *modu_GetStaticFunctionByName(
00363   void *pLibrary,
00364   char *pszFunctionName
00365   ){
00366 /*noverbatim
00367 CUT*/
00368   PSLFST pM = (PSLFST)pLibrary;
00369 
00370   while( pM->name ){
00371     if( !strcmp(pM->name,pszFunctionName) )return pM->function;
00372     pM++;
00373     }
00374   return NULL;
00375   }
00376 
00377 /*POD
00378 =H modu_LoadModule
00379 @c Load a module
00380 
00381 This function loads a module and returns the module pointer to in the argument
00382 T<pThisModule>. If the module is already loaded it just returns the module
00383 pointer.
00384 
00385 When the function is called first time for a module it loads the module, calls
00386 the version negotiation function and the module initializer.
00387 
00388 If module file name given in the argument T<pszLibrary> file name is an absolute
00389 file name this is used as it is. Otherwise the different configured module
00390 directories are seached for the module file, and the operating system specific
00391 extension is also appended to the file name automatically.
00392 
00393 If the caller does not need the pointer to the module the argument T<pThisModule>
00394 can be T<NULL>.
00395 /*FUNCTION*/
00396 int modu_LoadModule(pExecuteObject pEo,
00397                     char *pszLibraryFile,
00398                     pModule **pThisModule
00399   ){
00400 /*noverbatim
00401 CUT*/
00402 #define FNLEN 1024 /* this is the maximal length of a module name with absoule path */
00403   char szBuffer[FNLEN],*s;
00404 #ifdef WIN32
00405   char sData[FNLEN]; /* used to store the full path name to the executable if no module dir is configured */
00406   DWORD i;
00407 #endif
00408   int (*ModuleInitializerFunction)(int, char *, void **);
00409   int (*ExternalFunction)(pSupportTable, void **, pFixSizeMemoryObject, pFixSizeMemoryObject *);
00410   int ModuleRequestedVersion;
00411   pModule *ThisModule;
00412   void *FunctionPointer;
00413   int iResult;
00414   CFT_NODE Node;
00415   char *pszDllExtension;
00416   unsigned int cbDllExtension;
00417   int j;
00418 
00419   pszDllExtension = cft_GetString(pEo->pConfig,"dll");
00420   if( pszDllExtension == NULL ){
00421 #ifdef WIN32
00422     pszDllExtension = ".dll";
00423 #elif defined(__DARWIN__)
00424     pszDllExtension = ".dylib";
00425 #elif defined(__MACOS__)
00426     pszDllExtension = "";
00427 #else
00428     pszDllExtension = ".so";
00429 #endif
00430     }
00431   cbDllExtension = strlen(pszDllExtension);
00432 
00433   /* Check if this module was already loaded. */
00434   ThisModule = &(pEo->modules);
00435   while( *ThisModule && strcmp((*ThisModule)->pszModuleName,pszLibraryFile) )
00436     ThisModule = &( (*ThisModule)->next );
00437 
00438   if( pThisModule )
00439     *pThisModule = ThisModule;
00440   if( *ThisModule )return COMMAND_ERROR_SUCCESS;
00441 
00442   /* Initialize the function pointer table for the call-back functions if it was not
00443      initialized yet        ( 0 means no force) */
00444   if( iResult = modu_Init(pEo,0) )return iResult;
00445 
00446   /* store the module information in the module list */
00447   *ThisModule = ALLOC(sizeof(Module));
00448   if( *ThisModule == NULL )return COMMAND_ERROR_MEMORY_LOW;
00449   (*ThisModule)->pszModuleName = ALLOC( strlen(pszLibraryFile)+1);
00450   if( (*ThisModule)->pszModuleName == NULL )return COMMAND_ERROR_MEMORY_LOW;
00451   strcpy((*ThisModule)->pszModuleName,pszLibraryFile);
00452   (*ThisModule)->ModulePointer = NULL;
00453   (*ThisModule)->next = NULL;
00454   (*ThisModule)->ModuleInternalParameters = NULL;
00455   (*ThisModule)->ModuleIsStatic = 0; /* by default the code in most cases assumes that the modules are
00456                                         not statically linked to the interpreter */
00457 
00458   /* load the module into process space */
00459   s = (*ThisModule)->pszModuleName;
00460 
00461 #ifdef __MACOS__
00462   /* On Mac, an absolute path begins with no colon, and has colons in it.
00463      We treat as a relative path anything starting with a colon or having no colons at all */
00464   if( *s != ':'  && strchr(s, ':')){
00465 #else
00466   if( *s == '/' ||
00467       *s == '\\' ||/* If the user is perverted enough to name a file C:/ under UNIX then he deserves the consequences */
00468       ( s[1] == ':' && (s[2] == '\\' || s[2] == '/') )         ){
00469 #endif
00470     /* this is absolute path, do not prepend or append anything */
00471     (*ThisModule)->ModulePointer = dynlolib_LoadLibrary( s );
00472     if( (*ThisModule)->ModulePointer == NULL )return COMMAND_ERROR_MODULE_LOAD;
00473 
00474     }else{
00475     /* if the module name is not given as absolute path then check if this is a statically linked modules */
00476     j = 0;
00477     while( StaticallyLinkedModules[j].name ){
00478       if( ! strcmp( StaticallyLinkedModules[j].name , s ) ){
00479         /* This is a statically linked module. */
00480         (*ThisModule)->ModulePointer  = StaticallyLinkedModules[j].table;
00481         (*ThisModule)->ModuleIsStatic = 1;
00482         break;
00483         }
00484       j++;
00485       }
00486 
00487     if( (*ThisModule)->ModulePointer == NULL ){
00488       /* relative file name, prepend ModulePath */
00489       if( ! cft_GetEx(pEo->pConfig,"module",&Node,&s,NULL,NULL,NULL) ){
00490         while( 1 ){
00491           if( cft_GetEx(pEo->pConfig,NULL,&Node,&s,NULL,NULL,NULL) ){
00492             /* if there are no more directories in the configuration */
00493             break;
00494             }
00495           if( ! strcmp(cft_GetKey(pEo->pConfig,Node),"module") ){
00496             if( strlen(s) + strlen((*ThisModule)->pszModuleName) > FNLEN )return COMMAND_ERROR_MODULE_LOAD;
00497             strcpy(szBuffer,s);
00498             strcat(szBuffer,(*ThisModule)->pszModuleName);
00499             if( strlen(szBuffer) + cbDllExtension > FNLEN )return COMMAND_ERROR_MODULE_LOAD;
00500             strcat(szBuffer,pszDllExtension);
00501             (*ThisModule)->ModulePointer = dynlolib_LoadLibrary( szBuffer );
00502             if( (*ThisModule)->ModulePointer != NULL )break;
00503             }
00504           Node = cft_EnumNext(pEo->pConfig,Node);
00505           }
00506         }
00507       }
00508 #ifdef WIN32
00509     while( (*ThisModule)->ModulePointer == NULL ){
00510       /* On Windows as a last resort try to find the module file in the same directory as the executable is
00511          or as the very last resort in the directory  scribapath/bin/../modules 
00512          This will ease the installation process for the simple users, who do
00513          not dare to edit the registry.
00514       */
00515       s = _pgmptr;
00516       if( strlen(s) > FNLEN )break;
00517       strcpy(szBuffer,s);
00518       s = szBuffer;
00519       while( *s && ! isspace(*s) )s++;
00520       *s = (char)0;
00521       i = GetFullPathName(szBuffer,
00522                           FNLEN,
00523                           sData,
00524                           &s);
00525       *s = (char)0;
00526       if( strlen(sData) + strlen((*ThisModule)->pszModuleName) + cbDllExtension > FNLEN )break;
00527       strcpy(s,(*ThisModule)->pszModuleName);
00528       strcat(s,pszDllExtension);
00529       (*ThisModule)->ModulePointer = dynlolib_LoadLibrary( sData );
00530       if( (*ThisModule)->ModulePointer != NULL )break;
00531       /* c:\ScriptBasic\bin\scriba.exe */
00532       /*                 s- ^          */
00533       s--; /* step back to the \\*/
00534       if( s <= sData )break;
00535       s--; /*step back before the \\ */
00536       while( s > sData ){
00537         if( *s == '\\' || *s == '/' )break;
00538         s--;
00539         }
00540       if( s <= sData )break;
00541       s++; /* step after c:\ScriptBasic\ */
00542       *s = (char)0;
00543       if( strlen(sData) + 8 + strlen((*ThisModule)->pszModuleName) + cbDllExtension > FNLEN )break;
00544       strcpy(s,"modules\\");
00545       strcpy(s+8,(*ThisModule)->pszModuleName);
00546       strcat(s,pszDllExtension);
00547       (*ThisModule)->ModulePointer = dynlolib_LoadLibrary( sData );
00548       if( (*ThisModule)->ModulePointer != NULL )break;
00549     break;
00550     }
00551 #endif
00552 #ifdef __MACOS__
00553     if( (*ThisModule)->ModulePointer == NULL ){ /* Let MacOS see if it can find it */
00554       strcpy(s,(*ThisModule)->pszModuleName);
00555       (*ThisModule)->ModulePointer = dynlolib_LoadLibrary( s );
00556       }
00557 #endif
00558     if( (*ThisModule)->ModulePointer == NULL )return COMMAND_ERROR_MODULE_LOAD;
00559 
00560     }/*'end if' when the module name is not full path */
00561 
00562   /* call the module version negotiate function */
00563   FunctionPointer = modu_GetModuleFunctionByName(*ThisModule,MODULE_VERSIONER);
00564   if( FunctionPointer ){
00565     ModuleInitializerFunction = FunctionPointer;
00566     (*ThisModule)->ModuleIsActive = 1;
00567     ModuleRequestedVersion = ModuleInitializerFunction((int)INTERFACE_VERSION,(signed char *)pEo->Ver.Variation,&((*ThisModule)->ModuleInternalParameters));
00568     (*ThisModule)->ModuleIsActive = 0;
00569     if( ModuleRequestedVersion == 0 )return COMMAND_ERROR_MODULE_INITIALIZE;
00570     if( ModuleRequestedVersion != INTERFACE_VERSION ){
00571       if( GlobalDebugDisplayFlag ){
00572         fprintf(stderr,"The module requests the interface version %d\n"
00573                        "The interpreter supports the interface version %d\n",
00574                        ModuleRequestedVersion , INTERFACE_VERSION);
00575         }
00576       return COMMAND_ERROR_MODULE_VERSION;
00577       }
00578     }else{
00579     ModuleRequestedVersion = INTERFACE_VERSION; /* and hope the best */
00580     }
00581 
00582   /* call the module initializer function */
00583   FunctionPointer = modu_GetModuleFunctionByName(*ThisModule,MODULE_INITIALIZER);
00584   if( FunctionPointer ){
00585     ExternalFunction = FunctionPointer;
00586     (*ThisModule)->ModuleIsActive = 1;
00587     iResult = ExternalFunction(pEo->pST,&((*ThisModule)->ModuleInternalParameters),NULL,NULL);
00588     (*ThisModule)->ModuleIsActive = 0;
00589     if( iResult != 0 )return iResult;
00590     }
00591   return COMMAND_ERROR_SUCCESS;
00592   }
00593 
00594 /*POD
00595 =H modu_GetFunctionByName
00596 
00597 This function can be called to get the entry point of a function from an external module.
00598 If the module was not loaded yet it is automatically loaded.
00599 
00600 /*FUNCTION*/
00601 int modu_GetFunctionByName(pExecuteObject pEo,
00602                            char *pszLibraryFile,
00603                            char *pszFunctionName,
00604                            void **ppFunction,
00605                            pModule **pThisModule
00606   ){
00607 /*noverbatim
00608 CUT*/
00609   int iResult;
00610   pModule *pMyThisModule;
00611   void *(*ModuleAutoloaderFunction)(pSupportTable, void **, char *, void **);
00612 
00613   if( pThisModule == NULL )pThisModule = &pMyThisModule;
00614   if( iResult = modu_Init(pEo,0) )return iResult;
00615   if( iResult = modu_LoadModule(pEo,pszLibraryFile,pThisModule) )return iResult;
00616   *ppFunction = modu_GetModuleFunctionByName(**pThisModule,pszFunctionName);
00617 
00618   /* if there is no such function exported by the module try to call the autoloader */
00619   if( *ppFunction == NULL &&
00620       (ModuleAutoloaderFunction = modu_GetModuleFunctionByName(**pThisModule,MODULE_AUTOLOADER) ) )
00621     ModuleAutoloaderFunction(pEo->pST,&((**pThisModule)->ModuleInternalParameters),pszFunctionName,ppFunction);
00622   return COMMAND_ERROR_SUCCESS;
00623   }
00624 
00625 /*POD
00626 =H modu_UnloadAllModules
00627 @c Unload all loaded modules
00628 
00629 This function unloads all modules. This is called via the command finalizer mechanizm. If ever any module
00630 was loaded via a "declare sub" statement the command execution sets the command finalizer function
00631 pointer to point to this function.
00632 /*FUNCTION*/
00633 int modu_UnloadAllModules(pExecuteObject pEo
00634   ){
00635 /*noverbatim
00636 
00637 In a multi-threaded environment this function calls the keeper function of the module and in case the
00638 keeper returns 1 the module is kept in memory, though the module finalizer function is called. This
00639 lets multi-thread external modules to keep themselfs in memory even those times when there is not any
00640 interpreter thread using the very module running.
00641 
00642 In that case the module is put on the module list of the process SB object. That list is used to shut down
00643 the modules when the whole process is shut down.
00644 
00645 If there is no process SB object (pEo->pEPo is NULL) then the variation is a single process single thread
00646 implementation of ScriptBasic. In this case this function first calls the module finalizer function
00647 that is usally called in multi-threaded environment every time an interpreter thread is about to finish and
00648 after this the module shutdown function is called, which is called in a multi-thread environment when
00649 the whole process is to be shut down. After that the module is unloaded even if the keeper function said
00650 that the module wants to stay in memory.
00651 
00652 Don't worry about this: it is not abuse. The keeper function saying 1 means that the module has to 
00653 stay in memory after the actual interpreter thread has finished until the process finishes. However
00654 in this very case the process also terminates.
00655 
00656 B<Note:> A one-process one-thread implementation may also behave like a multi thread implementation
00657 allocating a separate process SB object and a program object to run. Then it should inherit the
00658 support table and the execution object of the process SB object to the runnable program object. After
00659 running finish the runned program object and call the shutdown process for the process SB object.
00660 But that is tricky for a single thread implementation.
00661 CUT*/
00662   pModule ThisModule,*pThisModule,pMptr;
00663   void *FunctionPointer;
00664   int (*ExternalFunction)(pSupportTable, void **, pFixSizeMemoryObject, pFixSizeMemoryObject *);
00665   int iActiveModules;
00666   int (*KeeperFunction)(void);
00667 
00668   iActiveModules = 0;
00669   /* Check if this module was already loaded. */
00670   pThisModule = &(pEo->modules);
00671   while( *pThisModule ){
00672     /* call the module finalizer function */
00673     if( (*pThisModule)->ModulePointer ){/* avoid modules not loaded by error */
00674       if( (*pThisModule)->ModuleIsActive ){/* can not unload a module if it is active */
00675         iActiveModules ++;/* count the not unloaded modules that are active */
00676         pThisModule = &((*pThisModule)->next);
00677         }else{
00678         FunctionPointer = modu_GetModuleFunctionByName(*pThisModule,MODULE_FINALIZER);
00679         if( FunctionPointer ){
00680           ExternalFunction = FunctionPointer;
00681           ExternalFunction(pEo->pST,&((*pThisModule)->ModuleInternalParameters),NULL,NULL);
00682           }
00683         /* decide calling the keeper function whether we should call unload or not in multi-thread
00684            environment */
00685         FunctionPointer = modu_GetModuleFunctionByName(*pThisModule,MODULE_KEEPER);
00686         if( FunctionPointer ){
00687           KeeperFunction = FunctionPointer;
00688           if( KeeperFunction() && ! (*pThisModule)->ModuleIsStatic )
00689             dynlolib_FreeLibrary((*pThisModule)->ModulePointer);
00690           else if( pEo->pEPo ){
00691             thread_LockMutex( &(pEo->pEPo->mxModules) );
00692             pMptr = alloc_Alloc(sizeof(Module),pEo->pEPo->pMemorySegment);
00693             if( pMptr == NULL ){
00694               thread_UnlockMutex( &(pEo->pEPo->mxModules) );
00695               return COMMAND_ERROR_MEMORY_LOW;
00696               }
00697             memcpy(pMptr,*pThisModule,sizeof(Module));
00698             pMptr->next = pEo->pEPo->modules;
00699             pEo->pEPo->modules = pMptr;
00700             thread_UnlockMutex( &(pEo->pEPo->mxModules) );
00701             }else{
00702             /* the module wants to stay in memory, but the variation
00703                runs single thread and there is no process level object */
00704             if( ! modu_ShutdownModule(pEo,*pThisModule) && ! (*pThisModule)->ModuleIsStatic )
00705               dynlolib_FreeLibrary((*pThisModule)->ModulePointer);
00706             (*pThisModule)->ModulePointer = NULL;
00707             }
00708           }else{
00709           if( ! (*pThisModule)->ModuleIsStatic )
00710             dynlolib_FreeLibrary((*pThisModule)->ModulePointer);
00711           (*pThisModule)->ModulePointer = NULL;
00712           }
00713         ThisModule = *pThisModule;
00714         *pThisModule = (*pThisModule)->next;
00715         FREE(ThisModule->pszModuleName);
00716         FREE(ThisModule);
00717         }
00718       }else{
00719       /* if the module was not loaded by error, release the space occupied by the error indicating rec */
00720       ThisModule = *pThisModule;
00721       *pThisModule = (*pThisModule)->next;
00722       FREE(ThisModule->pszModuleName);
00723       FREE(ThisModule);
00724       }
00725     }
00726   if( iActiveModules )return COMMAND_ERROR_PARTIAL_UNLOAD;
00727   return COMMAND_ERROR_SUCCESS;
00728   }
00729 
00730 /*POD
00731 =H modu_UnloadModule
00732 @c Unload the named module
00733 
00734 This function unloads the named module. Note that this function is not
00735 called unless some extension module calls it to unload another module.
00736 
00737 Currently there is no support for a module to unload itself.
00738 
00739 /*FUNCTION*/
00740 int modu_UnloadModule(pExecuteObject pEo,
00741                       char *pszLibraryFile
00742   ){
00743 /*noverbatim
00744 CUT*/
00745   pModule *ThisModule,pMptr;
00746   void *FunctionPointer;
00747   int (*ExternalFunction)(pSupportTable, void **, pFixSizeMemoryObject, pFixSizeMemoryObject *);
00748   int (*KeeperFunction)(void);
00749 
00750   ThisModule = &(pEo->modules);
00751   while( *ThisModule && strcmp((*ThisModule)->pszModuleName,pszLibraryFile) )
00752     ThisModule = &( (*ThisModule)->next );
00753 
00754   if( ! *ThisModule )return COMMAND_ERROR_MODULE_NOT_LOADED;
00755   if( (*ThisModule)->ModuleIsActive )return COMMAND_ERROR_MODULE_ACTIVE;
00756   if( *ThisModule ){
00757     if( (*ThisModule)->ModulePointer ){/* avoid modules not loaded by error */
00758       FunctionPointer = modu_GetModuleFunctionByName(*ThisModule,MODULE_FINALIZER);
00759       if( FunctionPointer ){
00760         ExternalFunction = FunctionPointer;
00761         ExternalFunction(pEo->pST,&((*ThisModule)->ModuleInternalParameters),NULL,NULL);
00762         }
00763       /* decide calling the keeper function whether we should call unload or not in multi-thread
00764          environment */
00765       FunctionPointer = modu_GetModuleFunctionByName(*ThisModule,MODULE_KEEPER);
00766       if( FunctionPointer ){
00767         KeeperFunction = FunctionPointer;
00768         if( KeeperFunction() && ! (*ThisModule)->ModuleIsStatic )
00769           dynlolib_FreeLibrary((*ThisModule)->ModulePointer);
00770         else if( pEo->pEPo ){
00771           thread_LockMutex( &(pEo->pEPo->mxModules) );
00772           pMptr = alloc_Alloc(sizeof(Module),pEo->pEPo->pMemorySegment);
00773           if( pMptr == NULL ){
00774             thread_UnlockMutex( &(pEo->pEPo->mxModules) );
00775             return COMMAND_ERROR_MEMORY_LOW;
00776             }
00777           memcpy(pMptr,*ThisModule,sizeof(Module));
00778           pMptr->next = pEo->pEPo->modules;
00779           pEo->pEPo->modules = pMptr;
00780           thread_UnlockMutex( &(pEo->pEPo->mxModules) );
00781           }else{
00782           /* the module wants to stay in memory, but the variation
00783              runs single thread and there is no process level object */
00784           if( ! modu_ShutdownModule(pEo,*ThisModule) && ! (*ThisModule)->ModuleIsStatic )
00785             dynlolib_FreeLibrary((*ThisModule)->ModulePointer);
00786           (*ThisModule)->ModulePointer = NULL;
00787           }
00788         }else{
00789         if( ! (*ThisModule)->ModuleIsStatic )
00790           dynlolib_FreeLibrary((*ThisModule)->ModulePointer);
00791         }
00792       }
00793     *ThisModule = (*ThisModule)->next ;
00794     }
00795   return COMMAND_ERROR_SUCCESS;
00796   }
00797 
00798 /*POD
00799 =H modu_ShutdownModule
00800 @c Shut down a module
00801 
00802 This function calls the shutdown function of a module.
00803 
00804 If the shutdown function performs well and returns SUCCESS this function
00805 also returns success. If the shutdown function returns error code
00806 it means that the module has running thread and thus can not be unloaded.
00807 
00808 /*FUNCTION*/
00809 int modu_ShutdownModule(pExecuteObject pEo,
00810                         pModule pThisModule
00811   ){
00812 /*noverbatim
00813 CUT*/
00814   void *FunctionPointer;
00815   int (*ShutdownFunction)(pSupportTable, void **, pFixSizeMemoryObject, pFixSizeMemoryObject *);
00816   int iError;
00817 
00818   FunctionPointer = modu_GetModuleFunctionByName(pThisModule,MODULE_SHUTDOWN);
00819   if( FunctionPointer != NULL ){
00820     ShutdownFunction = FunctionPointer;
00821     /* shutdown function gets support table, but no internal data, parameters or return value */
00822     iError = ShutdownFunction(pEo->pST,NULL,NULL,NULL);
00823     return iError;
00824     }
00825   return COMMAND_ERROR_SUCCESS;
00826   }

Generated on Sun Mar 12 23:56:31 2006 for ScriptBasic by  doxygen 1.4.6-NO