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 */