G:/ScriptBasic/source/ipreproc.c

Go to the documentation of this file.
00001 /*
00002 FILE: ipreproc.c
00003 HEADER: ipreproc.h
00004 
00005 --GNU LGPL
00006 This library is free software; you can redistribute it and/or
00007 modify it under the terms of the GNU Lesser General Public
00008 License as published by the Free Software Foundation; either
00009 version 2.1 of the License, or (at your option) any later version.
00010 
00011 This library is distributed in the hope that it will be useful,
00012 but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014 Lesser General Public License for more details.
00015 
00016 You should have received a copy of the GNU Lesser General Public
00017 License along with this library; if not, write to the Free Software
00018 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019 
00020 TO_HEADER:
00021 
00022 #include "report.h"
00023 #include "sym.h"
00024 #include "lexer.h"
00025 #include "expression.h"
00026 #include "syntax.h"
00027 #include "reader.h"
00028 #include "myalloc.h"
00029 #include "builder.h"
00030 #include "memory.h"
00031 #include "execute.h"
00032 #include "prepext.h"
00033 
00034 typedef struct _Preprocessor {
00035   void *pDllHandle;
00036   void *pFunction;
00037   char *pszPreprocessorName;
00038   struct _Preprocessor *next,*prev;
00039   Prepext pEXT; //extension structure that is passed to the preprocessor
00040   } Preprocessor, *pPreprocessor;
00041 
00042 typedef struct _PreprocObject {
00043   void *pMemorySegment;
00044   unsigned long n;// the number of loaded preprocessors
00045   pPreprocessor pFirst,pLast;
00046   ExecuteObject EXE; // dummy execute object to handle support functions
00047   struct _SbProgram *pSB;
00048   }PreprocObject,*pPreprocObject;
00049 
00050 */
00051 #include <stdio.h>
00052 #include <stdlib.h>
00053 #include <string.h>
00054 #include <ctype.h>
00055 
00056 #ifdef WIN32
00057 #include <process.h>
00058 #else
00059 #ifndef __MACOS__
00060 #include <sys/types.h>
00061 #include <sys/wait.h>
00062 #endif
00063 #endif
00064 
00065 #include "errcodes.h"
00066 #include "conftree.h"
00067 #include "myalloc.h"
00068 #include "uniqfnam.h"
00069 #include "dynlolib.h"
00070 #include "scriba.h"
00071 #include "basext.h"
00072 #include "prepext.h"
00073 #include "ipreproc.h"
00074 
00075 /*POD
00076 =H Internal preprocessor handling
00077 =abstract
00078 This module loads the internal preprocessors
00079 =end
00080 
00081 =toc
00082 
00083 CUT*/
00084 
00085 
00086 /*POD
00087 =section InitStructure
00088 =H Initialize the preprocessor structure
00089 
00090 This function is called after the T<PreprocObject> was allocated.
00091 It initializes the preprocessor handling structures.
00092 /*FUNCTION*/
00093 void ipreproc_InitStructure(pPreprocObject pPre
00094   ){
00095 /*noverbatim
00096 CUT*/
00097 
00098   pPre->n = 0;
00099   pPre->pFirst = NULL;
00100   pPre->pLast = NULL;
00101 
00102 /*
00103 The preprocessor object includes an ExecuteObject. This is needed because
00104 the execute object has a pointer to the support function table that any
00105 extension including preprocessors can use to access system functions
00106 through ScriptBasic. During reading, lexical analysis, syntax analysis
00107 and building there is no real execution context and thus no support table.
00108 (Yes, support table was originally designed for run-time extension modules.)
00109 To have support function during these pre-run steps here we have a dummy
00110 execution context that has nothing but the appropriate pointer to a support
00111 function table. This way preprocessors can use the support functions and the
00112 besXXX macros.
00113 */
00114   memset(&(pPre->EXE),0,sizeof(ExecuteObject));
00115   pPre->EXE.pST = NULL;
00116   pPre->EXE.pSTI = NULL;
00117   }
00118 
00119 /*POD
00120 =section PurgePreprocessorMemory
00121 =H Release all memories allocated by preprocessors
00122 
00123 This fucntion is called from the module T<scriba_*> to release all memory
00124 that was allocated by the preprocessors and were not released.
00125 /*FUNCTION*/
00126 void ipreproc_PurgePreprocessorMemory(pPreprocObject pPre
00127   ){
00128 /*noverbatim
00129 CUT*/
00130   pPreprocessor p;
00131 
00132   for( p = pPre->pFirst ; p ; p = p->next ){
00133     alloc_FinishSegment(p->pEXT.pMemorySegment);
00134     p->pEXT.pMemorySegment = NULL;
00135     }
00136   alloc_FinishSegment(pPre->pMemorySegment);
00137   }
00138 
00139 /*POD
00140 =section InsertPreprocessor
00141 =H Insert a new preprocessor into the preprocessor list
00142 
00143 The preprocessors that are active are stored in a linked list.
00144 When there is any action that needs a preprocessor this list is used
00145 to invoke the preprocessors. The preprocessors are invoked in the order
00146 they were entered into the system. For example if there are two lines
00147 in the source code saying:
00148 
00149 =verbatim
00150 use pre1
00151 use pre2
00152 =noverbatim
00153 
00154 then the preprocessor T<pre1> is loaded first and T<pre2> is loaded afterwards.
00155 When a preprocessor is invoked the preprocesor T<pre1> is called first and T<pre2> is
00156 called on the result. This function allocates a list element and inserts it to the end
00157 of the list.
00158 
00159 /*FUNCTION*/
00160 pPreprocessor ipreproc_InsertPreprocessor(pPreprocObject pPre
00161   ){
00162 /*noverbatim
00163 The argument is the preprocessor object, environment.
00164 
00165 The return value is pointer to the list element or T<NULL> if memory allocation occured.
00166 CUT*/
00167   pPreprocessor pNewPreprocessor;
00168 
00169   pNewPreprocessor = alloc_Alloc(sizeof(Preprocessor),pPre->pMemorySegment);
00170   if( pNewPreprocessor == NULL )return NULL;
00171 
00172   pNewPreprocessor->next = NULL;
00173 
00174   /* if the list is not empty then */
00175   if( pPre->pLast ){/* append it to the end */
00176     pPre->pLast->next = pNewPreprocessor;
00177     pNewPreprocessor->prev = pPre->pLast;
00178     }else
00179     pNewPreprocessor->prev = NULL;
00180   /* this is the last one since now */
00181   pPre->pLast = pNewPreprocessor;
00182 
00183   /* if the list is empty then this is the first one as well */
00184   if( pPre->pFirst == NULL )
00185     pPre->pFirst = pNewPreprocessor;
00186   pPre->n++;
00187 
00188   return pNewPreprocessor;
00189   }
00190 
00191 /*POD
00192 =section DeleteOldPreprocessor
00193 =H Delete a preprocessor from the list of preprocessors
00194 
00195 This function deletes a preprocessor from the list of preprocessors.
00196 The preprocessor was inserted into the list using the function
00197 T<InsertPreprocessor>.
00198 
00199 This function unhooks the element from the list and also releases the memory
00200 that was occupied by the list element. The function does not unload the 
00201 shared object (or DLL under Windows NT) from the memory.
00202 
00203 /*FUNCTION*/
00204 void ipreproc_DeletePreprocessor(pPreprocObject pPre,
00205                                  pPreprocessor pOld
00206   ){
00207 /*noverbatim
00208 
00209 The first argument is the preprocessor object environment. The second argument
00210 is the pointer to the list element to be deleted.
00211 
00212 CUT*/
00213   /* if this is not the first in the list then hook
00214      the previous element to the one that follows this one */
00215   if( pOld->prev )
00216     pOld->prev->next = pOld->next;
00217     else
00218     pPre->pFirst = pOld->next;
00219 
00220   /* if this is not the last one then hook the element that is after it to the previous one */
00221   if( pOld->next )
00222     pOld->next->prev = pOld->prev;
00223   else
00224     pPre->pLast = pOld->prev;
00225 
00226   pPre->n--;
00227 
00228   alloc_FinishSegment(pOld->pEXT.pMemorySegment);
00229   alloc_Free(pOld,pPre->pMemorySegment);
00230   }
00231 
00232 /*POD
00233 =section LoadInternalPreprocessor
00234 =H Load an internal preprocessor
00235 
00236 This function gets the name of an external preprocessor to load. The function
00237 searches the configuration information for the named preprocessor, loads the DLL/SO
00238 and invokes the initiation function of the preprocessor.
00239 
00240 /*FUNCTION*/
00241 int ipreproc_LoadInternalPreprocessor(pPreprocObject pPre,
00242                                       char *pszPreprocessorName
00243   ){
00244 /*noverbatim
00245 The first argument is the pointer to the ScriptBasic preprocessor object to access the
00246 configuration information and the list of loaded preprocessors to put the actual one
00247 on the list.
00248 
00249 The second argument is the name of the preprocessor as named in the configuration file, for example
00250 
00251 =verbatim
00252 preproc (
00253   internal (
00254     sample "C:\\ScriptBasic\\bin\\samplepreprocessor.dll"
00255     )
00256 =noverbatim
00257 
00258 The return value is zero or the error code.
00259 
00260 CUT*/
00261 #define FNLEN 1024
00262   char szBuffer[FNLEN];
00263   char *s;
00264   void *pDllHandle,*pFunction;
00265   int (*preproc)(void *,long *,void *);
00266   pSbProgram pProgram;
00267   int iError;
00268   pPreprocessor pThisPre;
00269   long lCommand;
00270   int bFirst;
00271 #define PREFLEN 17
00272   char *pszDllExtension;
00273   unsigned int cbDllExtension;
00274   CFT_NODE Node;
00275 
00276   pProgram = pPre->pSB;
00277 
00278   pszDllExtension = cft_GetString(pProgram->pCONF,"dll");
00279   if( pszDllExtension == NULL ){
00280 #ifdef WIN32
00281     pszDllExtension = ".dll";
00282 #elif defined(__DARWIN__)
00283     pszDllExtension = ".dylib";
00284 #elif defined(__MACOS__)
00285     pszDllExtension = "";
00286 #else
00287     pszDllExtension = ".so";
00288 #endif
00289     }
00290   cbDllExtension = strlen(pszDllExtension);
00291 
00292   /* check that the preprocessor was not loaded yet */
00293   for( pThisPre = pPre->pFirst ; pThisPre ; pThisPre = pThisPre->next )
00294     if( !strcmp(pThisPre->pszPreprocessorName,pszPreprocessorName) )return COMMAND_ERROR_SUCCESS;
00295 
00296   strcpy(szBuffer,"preproc.internal.");
00297   if( strlen(pszPreprocessorName) > FNLEN - PREFLEN )return READER_ERROR_PREPROC_LONG;
00298   strcpy(szBuffer+PREFLEN,pszPreprocessorName);
00299   s = szBuffer+PREFLEN;
00300   while( *s && ! isspace(*s) )s++; /* chop off optional parameters and/or NL from the end of line */
00301   *s = (char)0;
00302   s = cft_GetString(pProgram->pCONF,szBuffer);
00303   /* if the internal preprocessor was not configured then it still can be used if the DLL or SO file
00304      is copied into the modules library. */
00305   if( NULL == s ){
00306       if( ! cft_GetEx(pProgram->pCONF,"module",&Node,&s,NULL,NULL,NULL) ){
00307         while( 1 ){
00308           if( cft_GetEx(pProgram->pCONF,NULL,&Node,&s,NULL,NULL,NULL) ){
00309             /* if there are no more directories in the configuration */
00310             break;
00311             }
00312           if( ! strcmp(cft_GetKey(pProgram->pCONF,Node),"module") ){
00313             if( strlen(s) + strlen(pszPreprocessorName) > FNLEN )return READER_ERROR_PREPROC_LONG;
00314             strcpy(szBuffer,s);
00315             strcat(szBuffer,pszPreprocessorName);
00316             if( strlen(szBuffer) + cbDllExtension > FNLEN )return READER_ERROR_PREPROC_LONG;
00317             strcat(szBuffer,pszDllExtension);
00318             pDllHandle = dynlolib_LoadLibrary( szBuffer );
00319             if( pDllHandle != NULL )break;
00320             }
00321           Node = cft_EnumNext(pProgram->pCONF,Node);
00322           }
00323         }
00324     }else{
00325     /* if the preprocessor was configured in the config file
00326        not only copied into one of the module directories */
00327     pDllHandle = dynlolib_LoadLibrary(s);
00328     }
00329   if( pDllHandle == NULL )return READER_ERROR_PREPROC_NOTAVA;
00330 
00331   pFunction = dynlolib_GetFunctionByName(pDllHandle,"preproc");
00332   if( pFunction == NULL )return READER_ERROR_PREPROC_NOTVAL;
00333 
00334   bFirst = (pPre->pFirst == NULL);
00335   pThisPre = ipreproc_InsertPreprocessor(pPre);
00336   if( pThisPre == NULL  )return COMMAND_ERROR_MEMORY_LOW;
00337   pThisPre->pszPreprocessorName = alloc_Alloc(strlen(pszPreprocessorName)+1,pPre->pMemorySegment);
00338   if( pThisPre->pszPreprocessorName == NULL )return COMMAND_ERROR_MEMORY_LOW;
00339 
00340   strcpy(pThisPre->pszPreprocessorName,pszPreprocessorName);
00341   pThisPre->pDllHandle = pDllHandle;
00342   pThisPre->pFunction = pFunction;
00343   pThisPre->pEXT.lVersion = IP_INTERFACE_VERSION;
00344   pThisPre->pEXT.pPointer = NULL;
00345   pThisPre->pEXT.pMemorySegment = alloc_InitSegment(pPre->pSB->maf,pPre->pSB->mrf);
00346   if( pThisPre->pEXT.pMemorySegment == NULL )return COMMAND_ERROR_MEMORY_LOW;
00347 
00348   /* if this is the first preprocessor loaded then init
00349      the support function table*/
00350   if( bFirst ){
00351     pPre->EXE.pMemorySegment = pPre->pMemorySegment;
00352     modu_Init(&(pPre->EXE),0);
00353     pPre->EXE.pST->pEo = &(pPre->EXE);
00354     pThisPre->pEXT.pST = pPre->EXE.pST;
00355     }
00356 
00357   preproc = pFunction;
00358   lCommand = PreprocessorLoad;
00359   iError = preproc(&(pThisPre->pEXT),&lCommand,NULL);
00360   if( lCommand == PreprocessorUnload ){
00361     /* unload the current preprocessor */
00362     pDllHandle = pThisPre->pDllHandle;
00363     ipreproc_DeletePreprocessor(pPre,pThisPre);
00364     /* this may happen if the preprocessor is statically linked */
00365     if( pDllHandle )
00366       dynlolib_FreeLibrary(pDllHandle);
00367     }
00368   return iError;
00369   }
00370 
00371 /*POD
00372 =section Process
00373 =H Process preprocessor requests
00374 
00375 This function is used by ScriptBasic at certain points of the execution to
00376 start the preprocessors. It calls each loaded preprocessor one after the
00377 other until there is no more preprocessors or one of them alters the command
00378 variable to T<PreprocessorDone>.
00379 
00380 This function gets three arguments.
00381 
00382 /*FUNCTION*/
00383 int ipreproc_Process(pPreprocObject pPre,
00384                      long lCommand,
00385                      void *pPointer
00386   ){
00387 /*noverbatim
00388 T<pRe> is the preprocessor object.
00389 
00390 T<lCommand> is the command for the preprocessor to execute. For the possible
00391 values look at the file T<prepext.h> (created from T<prepext.c>)
00392 T<enum PreprocessorCommands>
00393 
00394 T<pPointer> is a pointer to a structure. The structure actually depends on the
00395 actual value of T<lCommand>. For different commands this pointer points to different
00396 structures.
00397 
00398 When the preprocessors are called they can alter the T<long> variable T<lCommand>
00399 passed to them by reference.
00400 
00401 When a preprocessor in this variable returns the value T<PreprocessorDone> the
00402 preprocessing in the actual stage is stopped and no further proreprocessor
00403 is invoked. However this has no effect on later preprocessor incocation.
00404 Returning this value in this variable solely means that the preprocessor
00405 has done all work that has to be done at the very point and thus there is
00406 no need of further preprocessor handling.
00407 
00408 When a preprocessor in this variable returns the value T<PreprocessorUnload>
00409 the function unhooks the preprocessor from the list af active preprocessors,
00410 releases all memory that the preprocessor used up and frees the library.
00411 
00412 The return value of the preprocessor functions should be zero or error code.
00413 
00414 The return value of the function T<ipreproc_Process> is zero or the error value of
00415 a preprocessor. If a preprocessor returns a non-zero error code no further
00416 preprocessors are invoked.
00417 
00418 This function can not be used in situation when the preprocessors may return
00419 other value in T<lCommand> than T<PreprocessorDone> or T<PreprocessorContinue>.
00420 CUT*/
00421   pPreprocessor p,pn;
00422   long lCmd;
00423   int (*preproc)(void *,long *,void *);
00424   int iError;
00425   void *pDllHandle;
00426 
00427   p = pPre->pFirst;
00428   while( p ){
00429     lCmd = lCommand;
00430     if( lCommand == 21 ){
00431 printf("");
00432 }
00433     preproc = p->pFunction;
00434     iError = preproc(&(p->pEXT),&lCmd,pPointer);
00435     if( lCmd == PreprocessorDone )break;
00436     if( lCmd == PreprocessorUnload ){
00437       /* unload the current preprocessor */
00438       pDllHandle = p->pDllHandle;
00439       pn = p->next;
00440       ipreproc_DeletePreprocessor(pPre,p);
00441       dynlolib_FreeLibrary(pDllHandle);
00442       p = pn;
00443       continue;
00444       }
00445     if( iError )return iError;
00446     p = p->next;
00447     }
00448   return COMMAND_ERROR_SUCCESS;
00449   }
00450 
00451 
00452 /*POD
00453 =section preproc
00454 =H Preprocessor function
00455 
00456 This function has to be implemented in the external preprocessor and exported from the
00457 DLL/SO file. It has to have the following prototype.
00458 
00459 =verbatim
00460 int DLL_EXPORT preproc(void *p, long *pFUN, void *q);
00461 
00462 =noverbatim
00463 
00464 CUT*/
00465 
00466 /*
00467 If the macro NO_IPREPROC is defined then the calls to ipreproc_Process will not be compiled into the
00468 code and thus it will not waste time. This may be essential to improve the performance on a production
00469 environment that executes already compiled code only and there is no need for anything like a preprocessor
00470 or debugger.
00471 
00472 TO_HEADER:
00473 #ifdef NO_IPREPROC
00474 #define ipreproc_Process(X,Y,Z)
00475 #endif
00476 
00477 */

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