G:/ScriptBasic/source/epreproc.c

Go to the documentation of this file.
00001 /*
00002 FILE: epreproc.c
00003 HEADER: epreproc.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 */
00023 #include <stdio.h>
00024 #include <stdlib.h>
00025 #include <string.h>
00026 #include <ctype.h>
00027 
00028 #ifdef WIN32
00029 #include <process.h>
00030 #else
00031 #ifndef __MACOS__ /* No such thing as command line parameters on classic Mac */
00032 #include <sys/types.h>
00033 #include <sys/wait.h>
00034 #endif
00035 #endif
00036 
00037 #include "errcodes.h"
00038 #include "conftree.h"
00039 #include "myalloc.h"
00040 #include "uniqfnam.h"
00041 #include "epreproc.h"
00042 
00043 /*POD
00044 =H External preprocessor handling
00045 
00046 This module starts the external preprocessors.
00047 
00048 =toc
00049 
00050 CUT*/
00051 
00052 /*POD
00053 =section epreproc
00054 =H Execute external preprocessors
00055 
00056 This function executes the external preprocessors that are
00057 needed to be executed either by the command line options or
00058 driven by the extensions.
00059 
00060 The command line option preprocessors are executed as listed
00061 in the character array T<ppszArgPreprocessor>. These preprocessors
00062 are checked to be run first.
00063 
00064 If there is no preprocessors defined on the command line then the
00065 preprocessors defined in the config file for the extensions are
00066 executed. The input file name is also modified by the code.
00067 The input file name is modified so that it will contain the source
00068 code file name after the preprocessing.
00069 
00070 The return value of the function is the error code. This is T<PREPROC_ERROR_SUCCESS>
00071 if the preprocessing was successful. This value is zero. If the return
00072 value is positive this is one of the error codes defined in the file T<errcodes.def>
00073 prefixed by T<PREPROC_>.
00074 
00075 /*FUNCTION*/
00076 int epreproc(ptConfigTree pCONF,
00077              char *pszInputFileName,
00078              char **pszOutputFileName,
00079              char **ppszArgPreprocessor,
00080              void *(*thismalloc)(unsigned int),
00081              void (*thisfree)(void *)
00082   ){
00083 /*noverbatim
00084 
00085 The first argument T<pCONF> is the configuration data pointer which is passed to the
00086 configuration handling routines.
00087 
00088 The second argument T<pszInputFileName> is the pointer to the pointer to the input file name.
00089 
00090 The third argument is an output variable. This will point to the output file name upon success
00091 or to NULL. If this variable is NULL then an error has occured or the file needed no preprocessing.
00092 The two cases can be separated based on the return value of the function. If the file needed
00093 preprocessing and the preprocessing was successfully executed then this variable will point
00094 to a ZCHAR string allocated via the function T<thismalloc>. This is the responsibility of the
00095 caller to deallocate this memory space after use calling the function pointed by T<thisfree>.
00096 
00097 The fourth argument T<ppszArgPreprocessor> is an array of preprocessors to be used
00098 on the input file. This array contains pointers that point to ZCHAR strings.
00099 The ZCHAR strings contain the symbolic names of the external preprocessors that
00100 are defined in the configuration file. The configuration file defines
00101 the actual executable for the preprocessor and the temporary directory where the
00102 preprocessed file is stored. The final element of this pointer array should be T<NULL>.
00103 If the pointer T<ppszArgPreprocessor> is T<NULL> or the pointer array pointed by this
00104 contains only the terminating T<NULL> pointer then the extensions of the file name are
00105 used to determine what preprocessors are to be applied. Preprocessors are applied from
00106 left to right order of the file extensions.
00107 
00108 The arguments T<thismalloc> and T<thisfree> should point to T<malloc> and T<free> or to
00109 a similar functioning function pair. These functions will be used via the T<myalloc.c> module
00110 and also to allocate the new T<pszOutputFileName> string in case of success. This means that the
00111 caller should use the function pointed by T<thisfree> to release the string pointed by
00112 T<pszOutputFileName> after the function has returned.
00113 
00114 CUT*/
00115   char *pszEPreprocExe,
00116        *pszEPreprocDir,
00117 #define MAXPPARGS 40
00118        *ppa[MAXPPARGS];
00119 #define PCKL 40
00120   char szPreprocConfigKey[PCKL]; /* this is epreproc$ext where ext is the extension */
00121 #define FULL_PATH_BUFFER_LENGTH 256
00122   char *PreprocessedFileName;
00123   char EPreProcCmdLin[FULL_PATH_BUFFER_LENGTH];
00124   int slen;
00125   void *pMemorySegment;
00126   char *s,*q;
00127   char **ppszPreprocessor = ppszArgPreprocessor;
00128   int iPreprIndex,i;
00129   char *pszLastFileName;
00130 #if (!defined(WIN32) && !defined(__MACOS__))
00131   pid_t pid;
00132   int exit_code;
00133 #endif
00134 
00135   *pszOutputFileName = NULL; /* This is the default return value in case of error or in case of
00136                                 null operation (aka: no preprocessing needed). */
00137   if( pszInputFileName == NULL )return COMMAND_ERROR_SUCCESS;
00138   pMemorySegment = alloc_InitSegment(thismalloc,thisfree);
00139   if( pMemorySegment == NULL )return COMMAND_ERROR_MEMORY_LOW;
00140 
00141   if( ppszPreprocessor == NULL || *ppszPreprocessor == NULL ){
00142     /* if no preprocessor was specified on the command line then
00143        try to figure out what preprocessors we have to use based
00144        on the extension of the source file. Build the ppszPreprocessor
00145        array and the later is going to use it as if it were given
00146        as argument. */
00147 
00148     /* Calculate the number of extensions. */
00149     s = pszInputFileName;
00150     slen = 0; /* count the extensions in this variable */
00151     while( *s ){
00152       if( *s == '.' )slen++;
00153       s++;
00154       }
00155     /* if there is no preprocessor defined on the command line and
00156        there is no extension of the file name */
00157     if( slen == 0 ){
00158       alloc_FinishSegment(pMemorySegment);
00159       return PREPROC_ERROR_SUCCESS;
00160       }
00161 
00162     slen ++; /* count the final NULL, which is the terminating element of the array */
00163 
00164     /* Allocate space for the preprocessor array. */
00165     ppszPreprocessor = alloc_Alloc(slen*sizeof(char *),pMemorySegment);
00166     if( ppszPreprocessor == NULL ){
00167       alloc_FinishSegment(pMemorySegment);
00168       return PREPROC_ERROR_MEMORY_LOW;
00169       }
00170     for( i = 0 ; i < slen ; i++ )ppszPreprocessor[i] = NULL;
00171 
00172     s = pszInputFileName;
00173     iPreprIndex = 0;
00174     while( *s ){
00175       /* find the first/next extension */
00176       while( *s && *s != '.' )s++;
00177       if( ! *s )break; /* there is no more extensions */
00178       s++; /* step over the dot before the extension */
00179       if( ! *s )break; /* there is no more extensions */
00180 
00181       strcpy(szPreprocConfigKey,"preproc.extensions.");
00182       q = szPreprocConfigKey + 19; /* 19 = strlen("preproc.extensions.") */
00183       slen = 19;/* we have copied 19 characters so far */
00184       /* copy the extension after the "epreproc$" string */
00185       while( *s && *s != '.' ){
00186         /* if the extension is such long (30 chars or more) then there
00187            is surely no preprocessor configured for it */
00188         if( slen >= PCKL ){
00189           /* reset the extension copiing */
00190           q = szPreprocConfigKey + 19; /* 19 = strlen("preproc.extensions.") */
00191           break;
00192           }
00193         /* copy the character */
00194         *q++ = *s++;
00195         /* count the character copied */
00196         slen++;
00197         }
00198       *q = (char)0;
00199 
00200       /* get the symbolic name of the preprocessor assigned to the extension */
00201       ppszPreprocessor[iPreprIndex] = cft_GetString(pCONF,szPreprocConfigKey);
00202       /* this is OK if there is no preprocessor configured for an extension, but if there is
00203          then have the pointer to the configuration constant string and step with the index.
00204          we do not need to check the index value. It can not step over the allocated space,
00205          because we have allocated space for as many preprocessort symbolic name string pointer
00206           as many dots there are in the file name and there can only be less or equal number of
00207          preprocessors. Over indexing would be something serious internal error. */
00208       if( ppszPreprocessor[iPreprIndex] )iPreprIndex++;
00209       }
00210     }
00211 
00212   /* ----------------------------------------------------------------------------------
00213      At this point of exection we have all the preprocessor symbolic names in the
00214      array ppszPreprocessor. This was given either by argument or built up based on the
00215      extensions. We only have to apply it.
00216      ---------------------------------------------------------------------------------- */
00217 
00218   /* This pointer points to the actual input file of the preprocessor. At the first
00219      preprocessing this is the input file name. On the next runs this is the output
00220      of the previous preprocessors. */
00221   pszLastFileName = pszInputFileName;
00222 
00223   for( iPreprIndex = 0 ;  ppszPreprocessor[iPreprIndex] ; iPreprIndex++ ){
00224     pszEPreprocExe = pszEPreprocDir = NULL;
00225     if( strlen(ppszPreprocessor[iPreprIndex]) < PCKL - 10 ){/* 10 = strlen("eprep$xxx$") */
00226       /* figure out the exe of the external preprocessor */
00227       strcpy(szPreprocConfigKey,"preproc.external.");
00228       strcat(szPreprocConfigKey,ppszPreprocessor[iPreprIndex]);
00229       strcat(szPreprocConfigKey,".executable");
00230       pszEPreprocExe = cft_GetString(pCONF,szPreprocConfigKey);
00231       /* figure out the directory for the preprocessed file */
00232       strcpy(szPreprocConfigKey,"preproc.external.");
00233       strcat(szPreprocConfigKey,ppszPreprocessor[iPreprIndex]);
00234       strcat(szPreprocConfigKey,".directory");
00235       pszEPreprocDir = cft_GetString(pCONF,szPreprocConfigKey);
00236       }
00237     /* if there is no configured executable or temporary file directory for the preprocessor
00238      then this is a preprocessor error (or maybe the specified preprocessor symbolic name
00239      is too long. */
00240     if( pszEPreprocExe == NULL ){
00241       alloc_FinishSegment(pMemorySegment);
00242       return PREPROC_ERROR_CONFIG_EXE;
00243       }
00244     if( pszEPreprocDir == NULL ){
00245       alloc_FinishSegment(pMemorySegment);
00246       return PREPROC_ERROR_CONFIG_DIR;
00247       }
00248 
00249     /* Allocate space to hold the full path of the preprocessor output file name. */
00250     PreprocessedFileName = alloc_Alloc(strlen(pszEPreprocDir)+UNIQ_FILE_NAME_LENGTH,pMemorySegment);
00251     if( PreprocessedFileName == NULL ){
00252       alloc_FinishSegment(pMemorySegment);
00253       return PREPROC_ERROR_MEMORY_LOW;
00254       }
00255     strcpy(PreprocessedFileName,pszEPreprocDir);
00256     s = PreprocessedFileName + strlen(PreprocessedFileName); /* point to the end of the directory */
00257     /* create a unique file name from the full path of the source and append it after the directory. */
00258     uniqfnam(pszLastFileName,s);
00259 
00260     /* create the ppa argumentum list for the preprocessor */
00261 #define CHKARGN if( i >= MAXPPARGS-1 ){\
00262                   alloc_FinishSegment(pMemorySegment);\
00263                   return PREPROC_ERROR_CONFIG_EXE;\
00264                   }
00265 
00266     strcpy(EPreProcCmdLin,pszEPreprocExe);/* copy it not to destroy the config string */
00267     q = EPreProcCmdLin;
00268     i = 1;
00269     ppa[0] = q;
00270     while( *q ){
00271       if( isspace(*q) ){
00272         CHKARGN
00273         *q = (char)0;
00274         ppa[i] = q+1;
00275         if( *(ppa[i]) )i++;
00276         }
00277       q++;
00278       }
00279     CHKARGN
00280     ppa[i++] = pszLastFileName;
00281     pszLastFileName = PreprocessedFileName;
00282     CHKARGN
00283     ppa[i++] = PreprocessedFileName;
00284     CHKARGN
00285     ppa[i++] = NULL;
00286 #ifdef WIN32
00287     if( spawnvp(_P_WAIT,EPreProcCmdLin,ppa) ){
00288       alloc_FinishSegment(pMemorySegment);
00289       return PREPROC_ERROR_FAIL;
00290       }
00291 #elif defined(__MACOS__)
00292     return PREPROC_ERROR_FAIL;
00293 #else
00294     if( ! (pid = fork()) ){
00295       /* we are the child process */
00296       execvp(EPreProcCmdLin,ppa);
00297       /* because execvp does not return executing this exit(1) is surely an error */
00298       exit(1);
00299       }
00300     waitpid(pid,&exit_code,0);
00301     if( exit_code ){
00302       alloc_FinishSegment(pMemorySegment);
00303       return PREPROC_ERROR_FAIL;
00304       }
00305 #endif
00306     }
00307   *pszOutputFileName = thismalloc(strlen(pszLastFileName)+1);
00308   if( *pszOutputFileName == NULL ){
00309     alloc_FinishSegment(pMemorySegment);
00310     return PREPROC_ERROR_MEMORY_LOW;
00311     }
00312   strcpy(*pszOutputFileName,pszLastFileName);
00313   alloc_FinishSegment(pMemorySegment);
00314   return PREPROC_ERROR_SUCCESS;
00315   }

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