G:/ScriptBasic/source/commands/external.c

Go to the documentation of this file.
00001 /*external.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 */
00019 
00020 #include <stdlib.h>
00021 #include <stdio.h>
00022 #include <string.h>
00023 
00024 #include "../command.h"
00025 #include "../dynlolib.h"
00026 #include "../basext.h"
00027 #include "../builder.h"
00028 #include "../modumana.h"
00029 
00030 /*POD
00031 =H EXTERNAL
00032 
00033 This file contains the implementation of the commands that handle the load
00034 and execution of external functions. These functions are stored in dynamically
00035 loaded libraries and are loaded on demand when they are first called.
00036 
00037 CUT*/
00038 
00039 
00040 
00041 /* structure to store the function entry point and the module structure address for the function */
00042 typedef struct _InstructionData {
00043   void *FunctionPointer;
00044   pModule ModulePointer;
00045   } InstructionData, *pInstructionData;
00046 
00133 void COMMAND_EXTERNAL(pExecuteObject pEo){
00134 #if NOTIMP_EXTERNAL
00135 NOTIMPLEMENTED;
00136 _FunctionFinishLabel:;
00137 #else
00138   MortalList _ThisCommandMortals=NULL;
00139   pMortalList _pThisCommandMortals = &_ThisCommandMortals;
00140   unsigned long _ActualNode=PROGRAMCOUNTER;
00141   pModule *ThisModule;
00142   int iErrorCode;
00143   char *pszLibraryFile;
00144   char *pszFunctionName;
00145   long NumberOfArguments;
00146   NODE nItem,nExpression;
00147   long i;
00148   void *FunctionPointer;
00149   pInstructionData *ppInstPointer;
00150   pFixSizeMemoryObject ParameterArray,SaveLocalVariables;
00151   int (*ExternalFunction)(pSupportTable, void **, pFixSizeMemoryObject, pFixSizeMemoryObject *);
00152   char *(*pfszErrMsg)(pSupportTable, void **, int);
00153   int iResult;
00154 
00155   /* if the execution is just running through the declaration */
00156   if( ! pEo->fWeAreCallingFuction )return;
00157 
00158   /* we need this variable, but should be set to NULL in case an error happens and the function returns 
00159      see more comment at the end of this function */
00160   SaveLocalVariables = pEo->LocalVariables;
00161   pEo->LocalVariables = NULL;
00162 
00163   /* The very first thing is to check if there was any external function call before, and
00164      if this is the first then initialize the data structure, which is needed to call external
00165      functions. */
00166   if( iResult = modu_Init(pEo,0) )ERROR(iResult);
00167 
00168   ppInstPointer = (pInstructionData *)&PARAMETEREXEC;
00169   if( *ppInstPointer ){/* if the function was already called and we already know the entry point */
00170     FunctionPointer = (*ppInstPointer)->FunctionPointer;
00171     ThisModule = &((*ppInstPointer)->ModulePointer);
00172     if( FunctionPointer == NULL )ERROR(COMMAND_ERROR_MODULE_FUNCTION);
00173     }else{
00174     /* get the name of the function */
00175     pszFunctionName = PARAMETERSTRING;
00176     NEXTPARAMETER;
00177 
00178     /* get the file name of the library where the function is defined */
00179     pszLibraryFile = PARAMETERSTRING;
00180     if( iResult =modu_GetFunctionByName(pEo,pszLibraryFile,pszFunctionName,&FunctionPointer,&ThisModule) )ERROR(iResult);
00181 
00182     if( FunctionPointer == NULL )ERROR(COMMAND_ERROR_MODULE_FUNCTION);
00183     *ppInstPointer = ALLOC(sizeof(InstructionData));
00184     if( *ppInstPointer == NULL )ERROR(COMMAND_ERROR_MEMORY_LOW);
00185     (*ppInstPointer)->ModulePointer = *ThisModule;
00186     /* now the module is loaded, get the function pointer */
00187     (*ppInstPointer)->FunctionPointer = FunctionPointer;
00188     }
00189 
00190   /* count the function arguments */
00191   NumberOfArguments = 0L;
00192   for( nItem = pEo->FunctionArgumentsNode ; nItem ; nItem = CDR(nItem) )
00193     NumberOfArguments ++;
00194 
00195   /* Allocate the array to store the parameters. */
00196   if( NumberOfArguments ){
00197     ParameterArray = memory_NewArray(pEo->pMo,1,NumberOfArguments);
00198     if( ParameterArray == NULL )ERROR(COMMAND_ERROR_MEMORY_LOW);
00199     }else ParameterArray = NULL;
00200 
00201   /* evaluate the arguments of the function */
00202   pEo->LocalVariables = SaveLocalVariables; /* Note that the pEo->LocalVariables pointer was set to NULL,
00203                                                because it has to be NULL when this command returns, and any
00204                                                error condition can return. (It took 4 hours to debug.)
00205                                             */
00206   nItem = pEo->FunctionArgumentsNode;
00207   i = 0;
00208   while( nItem ){
00209     i++ ;
00210     nExpression = CAR(nItem);
00211     switch( OPCODE(nExpression) ){
00212       case eNTYPE_ARR:
00213         ParameterArray->Value.aValue[i-1] = memory_NewRef(pEo->pMo);
00214         memory_SetRef(pEo->pMo,ParameterArray->Value.aValue+i-1,execute_LeftValueArray(pEo,nExpression,_pThisCommandMortals,&iErrorCode));
00215         break;
00216       case eNTYPE_SAR:
00217         ParameterArray->Value.aValue[i-1] = memory_NewRef(pEo->pMo);
00218         memory_SetRef(pEo->pMo,ParameterArray->Value.aValue+i-1,execute_LeftValueSarray(pEo,nExpression,_pThisCommandMortals,&iErrorCode));
00219         break;
00220       case eNTYPE_LVR:
00221         ParameterArray->Value.aValue[i-1] = memory_NewRef(pEo->pMo);
00222         memory_SetRef(pEo->pMo,ParameterArray->Value.aValue+i-1,&(pEo->LocalVariables->Value.aValue[pEo->CommandArray[nExpression-1].Parameter.Variable.Serial-1]));
00223         break;
00224       case eNTYPE_GVR:
00225         ParameterArray->Value.aValue[i-1] = memory_NewRef(pEo->pMo);
00226         memory_SetRef(pEo->pMo,ParameterArray->Value.aValue+i-1,&(pEo->GlobalVariables->Value.aValue[pEo->CommandArray[nExpression-1].Parameter.Variable.Serial-1]));
00227         break;
00228       default:
00229         ParameterArray->Value.aValue[i-1] = EVALUATEEXPRESSION(nExpression);
00230         ASSERTOKE;
00231         if( ParameterArray->Value.aValue[i-1] )
00232           memory_Immortalize(ParameterArray->Value.aValue[i-1],_pThisCommandMortals);
00233         break;
00234       }
00235     nItem = CDR(nItem);
00236     }
00237   ExternalFunction = FunctionPointer;
00238   pEo->pFunctionResult = NULL;
00239   memory_ReleaseMortals(pEo->pMo,&_ThisCommandMortals);
00240   /* we do not need the _pThisCommandMortal variable anymore. We use it to save the old value
00241      of the pGlobalMortalList, which is the mortal list of the caller.
00242   */
00243   _pThisCommandMortals = pEo->pGlobalMortalList;
00244   /* we set the pGlobalMortalList to point to the _ThisCommandMortals. This means that the
00245      interface function will use the mortal list of this command and not the mortal list
00246      of the caller. All mortal variables of the interface functionwill be released when this
00247      function ENDs.
00248   */
00249   pEo->pGlobalMortalList = &_ThisCommandMortals;
00250   /* We have to NULL the list of local variables, because it holds the old value,
00251      pointing to the array of local variables of the caller. After returning the execution
00252      code assumes that the pEo->LocalVariables points to the local variables array of the
00253      subroutine and releases it. Before inserting this line here the code released the caller
00254      local variables, and calling any external module from a function having local variables
00255      casued segmentation fault when the code returned from the external function and tried to
00256      access any local variable. If this variable is set to NULL the execution module assumes
00257      that there were no local variables of the called function. And we do not indeed have local
00258      variables in an external function, because they have quite different local variable mechanism,
00259      simply they have local C variables.
00260   */
00261   pEo->LocalVariables = NULL;
00262   (*ThisModule)->ModuleIsActive = 1;
00263   iResult = ExternalFunction(pEo->pST,&((*ThisModule)->ModuleInternalParameters),ParameterArray,&(pEo->pFunctionResult));
00264   pEo->pszModuleError = NULL;
00265   if( iResult ){
00266     pfszErrMsg = modu_GetModuleFunctionByName(*ThisModule,MODULE_ERRMSG);
00267     if( pfszErrMsg ){
00268      pEo->pszModuleError = pfszErrMsg(pEo->pST,&((*ThisModule)->ModuleInternalParameters),iResult);
00269      }
00270     }
00271   (*ThisModule)->ModuleIsActive = 0;
00272   /* The interface functions from the external modules return mortal values. We have to immortalize this
00273      variable otherwise it is freed by the statement hidden in the macro END at the end of this function.
00274   */
00275   if( pEo->pFunctionResult && IsMortal(pEo->pFunctionResult) )
00276       memory_Immortalize(pEo->pFunctionResult,pEo->pGlobalMortalList);
00277 
00278   if( ParameterArray )
00279     memory_ReleaseVariable(pEo->pMo,ParameterArray);
00280 
00281   /* here we restore the pGlobalMortalList so that the caller can use it as it was */
00282   pEo->pGlobalMortalList = _pThisCommandMortals;
00283   if( iResult )ERROR(iResult);
00284   pEo->fStop = fStopRETURN;
00285 
00286 _FunctionFinishLabel:
00287   memory_ReleaseMortals(pEo->pMo,&_ThisCommandMortals);\
00288   iErrorCode = 0;
00289 #endif
00290   }
00313 void COMMAND_EXTERNAM(pExecuteObject pEo){
00314 #if NOTIMP_EXTERNAL
00315 NOTIMPLEMENTED;
00316 _FunctionFinishLabel:;
00317 #else
00318   MortalList _ThisCommandMortals=NULL;
00319   pMortalList _pThisCommandMortals = &_ThisCommandMortals;
00320   pMortalList pSaveGlobalMortalList;
00321   unsigned long _ActualNode=PROGRAMCOUNTER;
00322   pModule *ThisModule;
00323   char *pszLibraryFile;
00324   char *pszFunctionName;
00325   void *FunctionPointer;
00326   pInstructionData *ppInstPointer;
00327   pFixSizeMemoryObject SaveLocalVariables;
00328   int (*ExternalFunction)(pExecuteObject, void **);
00329   int iResult;
00330   char *(*pfszErrMsg)(pSupportTable, void **, int);
00331 
00332   /* if the execution is just running through the declaration */
00333   if( ! pEo->fWeAreCallingFuction )return;
00334 
00335   pSaveGlobalMortalList = pEo->pGlobalMortalList;
00336   pEo->pGlobalMortalList = &_ThisCommandMortals;
00337 
00338   /* we need this variable, but should be set to NULL in case an error happens and the function returns 
00339      see more comment at the end of this function */
00340   SaveLocalVariables = pEo->LocalVariables;
00341   pEo->LocalVariables = NULL;
00342 
00343   /* The very first thing is to check if there was any external function call before, and
00344      if this is the first then initialize the data structure, which is needed to call external
00345      functions. */
00346   if( iResult = modu_Init(pEo,0) )ERROR(iResult);
00347 
00348   ppInstPointer = (pInstructionData *)&PARAMETEREXEC;
00349   if( *ppInstPointer ){/* if the command was already called and we already know the entry point */
00350     FunctionPointer = (*ppInstPointer)->FunctionPointer;
00351     ThisModule = &((*ppInstPointer)->ModulePointer);
00352     if( FunctionPointer == NULL )ERROR(COMMAND_ERROR_MODULE_FUNCTION);
00353     }else{
00354     /* get the name of the function */
00355     pszFunctionName = PARAMETERSTRING;
00356     NEXTPARAMETER;
00357 
00358     /* get the file name of the library where the function is defined */
00359     pszLibraryFile = PARAMETERSTRING;
00360 
00361     if( iResult =modu_GetFunctionByName(pEo,pszLibraryFile,pszFunctionName,&FunctionPointer,&ThisModule) )ERROR(iResult);
00362 
00363     if( FunctionPointer == NULL )ERROR(COMMAND_ERROR_MODULE_FUNCTION);
00364     *ppInstPointer = ALLOC(sizeof(InstructionData));
00365     if( *ppInstPointer == NULL )ERROR(COMMAND_ERROR_MEMORY_LOW);
00366     (*ppInstPointer)->ModulePointer = *ThisModule;
00367     /* now the module is loaded, get the function pointer */
00368     (*ppInstPointer)->FunctionPointer = FunctionPointer;
00369     }
00370 
00371   pEo->OperatorNode = pEo->FunctionArgumentsNode;
00372 
00373   pEo->pOpResult = NULL;
00374   pEo->ErrorCode = 0;
00375   ExternalFunction = FunctionPointer;
00376   (*ThisModule)->ModuleIsActive = 1;
00377   ExternalFunction(pEo,&((*ThisModule)->ModuleInternalParameters));
00378   if( pEo->ErrorCode ){
00379     pfszErrMsg = modu_GetModuleFunctionByName(*ThisModule,MODULE_ERRMSG);
00380     if( pfszErrMsg ){
00381      pEo->pszModuleError = pfszErrMsg(pEo->pST,&((*ThisModule)->ModuleInternalParameters),pEo->ErrorCode);
00382      }
00383     }
00384   (*ThisModule)->ModuleIsActive = 0;
00385   /* The interface functions from the external modules return mortal values. We have to immortalize this
00386      variable otherwise it is freed by the statement hidden in the macro END at the end of this function.
00387   */
00388   pEo->pFunctionResult = pEo->pOpResult;
00389   if( pEo->pFunctionResult && IsMortal(pEo->pFunctionResult) )
00390       memory_Immortalize(pEo->pFunctionResult,pEo->pGlobalMortalList);
00391 
00392   /* here we restore the pGlobalMortalList so that the caller can use it as it was */
00393   pEo->pGlobalMortalList = _pThisCommandMortals;
00394   if( pEo->ErrorCode )ERROR(pEo->ErrorCode);
00395   pEo->fStop = fStopRETURN;
00396 
00397 _FunctionFinishLabel:
00398   memory_ReleaseMortals(pEo->pMo,&_ThisCommandMortals);
00399   pEo->pGlobalMortalList = pSaveGlobalMortalList;
00400 #endif
00401   }

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