Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1600 lines
36 KiB

/*****************************************************************************/
/** Microsoft LAN Manager **/
/** Copyright(c) Microsoft Corp., 1987-1990 **/
/*****************************************************************************/
/*****************************************************************************
File : filehndl.cxx
Title : file i/o handler for the MIDL compiler. Handles nested
: file accessing, preprocessed file handling etc
Description : Used by the compiler for handling import files, pre-
processing of files etc
History :
25-Aug-1990 VibhasC Create
26-Aug-1990 VibhasC Add functionality
*****************************************************************************/
/****************************************************************************
*** local defines
***************************************************************************/
#define MAX_LINE_LENGTH (256)
#define INTERMEDIATE_EXT ("._i")
#define SMART_INCLUDE_STRING ("smart_include")
/****************************************************************************
*** include files
***************************************************************************/
#include "nulldefs.h"
extern "C"
{
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <process.h>
#include <ctype.h>
#include <errno.h>
#include <malloc.h>
#include <fcntl.h>
#include <sys\types.h>
#include <sys\stat.h>
#include <io.h>
#include <errno.h>
#include <share.h>
}
#include "common.hxx"
#include "errors.hxx"
#include "filehndl.hxx"
#include "cmdana.hxx"
#include "control.hxx"
#include "textsub.hxx"
/****************************************************************************
*** public data
***************************************************************************/
short DebugLine = 0;
char * pDebugFile;
/****************************************************************************
*** extern procs
***************************************************************************/
extern void StripSlashes( char * );
extern void ChangeToForwardSlash( char *, char * );
extern STATUS_T CreateFullPathAndFName( char *, char **, char ** );
/****************************************************************************
*** extern data
***************************************************************************/
extern int errno;
extern CCONTROL * pCompiler;
extern CMD_ARG * pCommand;
/*** _nfa_info *************************************************************
* Purpose : constructor for the _nfa_info class
* Input : nothing
* Output :
* Notes : Initialize
***************************************************************************/
_nfa_info::_nfa_info( void )
{
BOOL fMinusIDefined = pCommand->IsSwitchDefined(SWITCH_I);
BOOL fNoDefIDirDefined = pCommand->IsSwitchDefined(SWITCH_NO_DEF_IDIR);
char * pDefault = ".";
char * pEnv = (char *)0;
char * pIPaths = (char *)0;
char * p1 = (char *)0;
char * p2 = (char *)0;
char * p3 = (char *)0;
/***
*** init
***/
pFileList = 0;
pPathList = (PATH_LIST *)NULL;
pStack = pStackFirst= (IN_STACK_ELEMENT *)NULL;
iCurLexLevel = 0;
Flags.fPreProcess = 0;
Flags.fFileSet = 0;
Flags.fEOI = 0;
Flags.fBaseFileName= 0;
Flags.fInInclude = 0;
// macro expansion handling
iText = 0;
pTextDict = new ISTACK( 10 );
// init the search paths. If the -no_def-idir switch is defined, then
// dont set the default paths. But if the -no_def_idir switch IS defined,
// then if the -I switch is not found, set the current path to .
if( fMinusIDefined )
pIPaths = pCommand->GetMinusISpecification();
if( !( pEnv = getenv( "INCLUDE" ) ) )
pEnv = getenv( "include" );
//
// make a copy of this because we will be doing strtoks on this.
//
if( pEnv )
{
// use p1 as temp;
p1 = new char [ strlen( pEnv ) + 1 ];
strcpy( p1, pEnv );
pEnv = p1;
}
p1 = pDefault;
p2 = pIPaths;
p3 = pEnv;
if( fNoDefIDirDefined && fMinusIDefined )
{
p1 = p3 = (char *)0;
}
else if( fNoDefIDirDefined && !fMinusIDefined )
{
p2 = p3 = (char *)0;
}
else if( !fNoDefIDirDefined && !fMinusIDefined )
{
p1 = pDefault;
p2 = (char *)0;
p3 = pEnv;
}
SetSearchPathsInOrder( p1, p2, p3 );
if( pIPaths ) delete pIPaths;
//
// we have made a copy of the env variable, so we can delete this copy
// now.
//
if( pEnv ) delete pEnv;
}
void
_nfa_info::Init()
{
CMD_ARG * pCommandProcessor = pCompiler->GetCommandProcessor();
#if 0
if( pCommandProcessor->IsSwitchDefined( SWITCH_I ) )
pCommandProcessor->RegisterPaths();
#endif // 0
// set preprocessing on or off depending upon the need
if( !pCommandProcessor->IsSwitchDefined( SWITCH_NO_CPP ) )
SetPreProcessingOn();
}
void
_nfa_info::SetSearchPathsInOrder(
char * p1,
char * p2,
char * p3 )
{
if( p1 )
RegisterIt( p1 );
if( p2 )
RegisterIt( p2 );
if( p3 )
RegisterIt( p3 );
}
void
_nfa_info::RegisterIt(
char * pPath
)
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Routine Description:
register command paths.
Arguments:
pPath - pointer to path bein registered.
Return Value:
None.
Notes:
We expect the path components to be separated by a ';'. register those
with the import controller. This function must become part of the import
controller class.
----------------------------------------------------------------------------*/
{
#define TOKEN_STRING (";")
char * pToken = strtok( pPath, TOKEN_STRING );
if( pToken )
{
SetPath( pToken );
while( pToken = strtok( (char *)NULL, TOKEN_STRING ) )
{
SetPath( pToken );
}
}
}
void
_nfa_info::RegisterTextSubsObject(
TEXT_BUFFER * pT )
{
pTextDict->Push( (IDICTELEMENT) pT );
iText++;
}
_nfa_info::~_nfa_info()
{
EndOperations();
}
/*** GetLexLevel **********************************************************
* Purpose : to return the current lexical level of the nfa
* Input : nothing
* Output : current lexical level
* Notes :
**************************************************************************/
short
NFA_INFO::GetLexLevel( void )
{
return iCurLexLevel;
}
/*** PushLexLevel **********************************************************
* Purpose : push lexical level in preparation of a new input file
* Input : nothing
* Output : 0 if all is well, error otherwise.
* Notes :
**************************************************************************/
short
NFA_INFO::PushLexLevel ( void )
{
// if an attempt to push the lexical level without opening any file
// at that level was made, assert
assert( Flags.fFileSet == 1 );
// close the current file, record its position so that we can start
// reading at the same place when we come back to it on a poplexlevel
pStack->ulPos = ftell( pStack->hFile );
// fclose(pStack->hFile);
// pStack->fOpen = 0;
Flags.fFileSet = 0;
iCurLexLevel++;
return 0;
}
/*** PopLexLevel **********************************************************
* Purpose : pop the lexical level
* Input : nothing
* Output : returns STATUS_OK if all is well.Error otherwise
* Notes : pop involves, re-opening the input file, if it was closed
* : retsoring the input file handle back, deleting the stack
* : element for that lexical level.
*************************************************************************/
STATUS_T
NFA_INFO::PopLexLevel( void )
{
IN_STACK_ELEMENT * pCurStack;
char * pName;
assert( iCurLexLevel > 0 );
//
// remove the current stack level, by closing the file at that
// level and deleting the stack element. reduce the current lexical
// level by one
//
iCurLexLevel--;
if( ! pStack->fRedundantImport )
EndOneOperation( pStack );
pCurStack = pStack = pStack->pPrev;
delete pStack->pNext;
pStack->pNext = (IN_STACK_ELEMENT *)NULL;
//
// if the file at this lexical level is closed, open it
//
pName = pStack->pName;
if( !pStack->fOpen )
{
char *pName = pStack->pName;
if( (pStack->hFile = fopen( pName, "rb" )) == (FILE *)NULL)
{
RpcError((char *)NULL, 0, INPUT_OPEN, pName);
return INPUT_OPEN;
}
// restore the system-wide file handle
pStack->fOpen = 1;
}
// the input file is open now, position it to where it was before
// we changed current lexical level
if( fseek( pStack->hFile, pStack->ulPos, SEEK_SET) )
{
RpcError((char *)NULL, 0, INPUT_READ, pName);
return INPUT_READ;
}
// everything is fine , lets go
return STATUS_OK;
}
STATUS_T
NFA_INFO::EndOperations()
{
IN_STACK_ELEMENT * pS = pStackFirst;
while( pStackFirst = pS )
{
EndOneOperation( pS );
pS = pS->pNext;
delete pStackFirst;
}
pStackFirst = pStack = (IN_STACK_ELEMENT *)0;
return STATUS_OK;
}
STATUS_T
NFA_INFO::EndOneOperation( IN_STACK_ELEMENT * pSElement)
{
BOOL fSavePP = pCommand->IsSwitchDefined( SWITCH_SAVEPP );
if( pSElement && pSElement->hFile )
{
fclose( pSElement->hFile );
if( Flags.fPreProcess && !fSavePP )
{
MIDL_UNLINK( pSElement->pIFileName );
delete pSElement->pIFileName;
}
if( pSElement->pMIFileName && !fSavePP )
{
MIDL_UNLINK( pSElement->pMIFileName );
delete pSElement->pMIFileName;
}
}
return STATUS_OK;
}
/*** SetNewInputFile *******************************************************
* Purpose : to set the input file to a new one
* Input : pointer to the new input file name
* Output : STATUS_OK if all is ok, error otherwise.
* Notes :
**************************************************************************/
STATUS_T
NFA_INFO::SetNewInputFile(
char *pFullInputName)
{
FILE *hFile = (FILE *)NULL;
STATUS_T uError;
IN_STACK_ELEMENT *pStackCur = pStack;
char agNameBuf[ _MAX_DRIVE+_MAX_DIR+_MAX_FNAME+_MAX_EXT+1];
char agDrive[_MAX_DRIVE];
char agPath[_MAX_DIR];
char agName[_MAX_FNAME];
char agExt[_MAX_EXT];
char *pPath;
char *pIFileName = (char *)NULL,
*pMIFileName = (char *) NULL;
char fMunged = 0;
char *pFullName = new char[ strlen( pFullInputName ) + 1];
//
// if the filename has any forward slashes, change them to back-slashes.
//
ChangeToForwardSlash( pFullInputName, pFullName );
// if we have seen this file before, do not process it again, just return
// an error
if( IsDuplicateInput( pFullName ) )
{
pStack = new IN_STACK_ELEMENT;
if(pStackCur)
{
pStackCur->pNext = pStack;
pStack->pPrev = pStackCur;
}
else
{
pStack->pPrev = (IN_STACK_ELEMENT *)NULL;
pStackFirst = pStack;
}
pStack->pNext = (IN_STACK_ELEMENT *)NULL;
pStack->fNewLine = 0;
pStack->fRedundantImport = 1;
pStack->fOpen = 1;
pStack->ulPos =
pStack->fShadow =
pStack->uShadowLine =
pStack->uShadowCol = 0;
pStack->uCol =
pStack->uLine = 1;
pStack->pShadowName =
pStack->pName = pFullName;
pStack->pIFileName = pIFileName;
pStack->hFile = hFile;
Flags.fFileSet = 1;
return STATUS_OK;
}
// We need to find details of the file name. We need to see if the user
// has already specified path, if so, override the current paths.
// if the user has specified a file extension, get the extension. We
// need to do that in order to have uniformity with the case where
// a preprocessed file is input with a different extension
_splitpath( pFullName, agDrive, agPath, agName, agExt );
// fprintf( stdout, "Processing %s:\n", pFullName);
if( (strcmp( agExt, ".h" ) == 0 ) &&
pCommand->IsSwitchDefined( SWITCH_HPP ) )
{
agDrive[0] = '\0';
strcpy( agPath, ".\\");
strcpy( agNameBuf, agPath );
strcat( agNameBuf, agName );
strcpy( agExt, ".mi");
strcat( agNameBuf, agExt );
FILE *h = fopen( agNameBuf, "w" );
if( h == (FILE *)0 )
return INTERMEDIATE_FILE_CREATE;
fprintf( h, "[local]\n interface __I%s\n{\n#include <%s>\n}\n", agName, pFullName );
fclose(h);
pMIFileName = new char[ strlen(agNameBuf) + 1 ];
strcpy( pMIFileName, agNameBuf );
}
else
{
// if file is specified with a path, the user knows fully the location
// else search for the path of the file
pPath = agPath;
if( !*pPath && !agDrive[0] )
{
sprintf(agNameBuf, "%s%s", agName, agExt);
if( (pPath = SearchForFile(agNameBuf)) == (char *)NULL)
{
RpcError((char *)NULL, 0, INPUT_OPEN, agNameBuf);
return INPUT_OPEN;
}
strcpy(agPath, pPath);
}
else
{
// there is a path specification, which we must tag to this name
// for all subsequent accesses to the file although it should not
// be considered as part of the list of paths the user gave.
// Remember, in our file list we store the paths too
pPath = new char[ strlen(agPath) + 1];
strcpy( pPath, agPath );
}
}
// do we need to preprocess the file ?
fprintf( stdout, "Processing " );
if( agDrive[0] )
fprintf( stdout, "%s", agDrive );
if( agPath[0] )
fprintf( stdout, "%s", agPath );
if( agName[0] )
fprintf( stdout, "%s", agName );
if( agExt[0] )
fprintf( stdout, "%s", agExt );
fprintf( stdout, "\n" );
fflush( stdout );
if(Flags.fPreProcess)
{
if(uError = PreProcess( agDrive, agPath, agName, agExt))
return uError;
// copy the actual new extension
// agDrive[0] = '\0';
// agPath[0] = '\0';
strcpy(agExt, ".i");
}
// at this point we have all the filename info necessary to open the
// file and process it.
sprintf(agNameBuf, "%s%s%s%s", agDrive, agPath, agName, agExt);
if(Flags.fPreProcess)
{
pIFileName = new char[strlen(agNameBuf)+1];
strcpy( pIFileName, agNameBuf );
}
else
pIFileName = (char *)NULL;
if( (hFile = fopen(agNameBuf, "rb")) == (FILE *)NULL)
{
// error obtained while reading file, return the error
RpcError((char *)NULL, 0, INPUT_OPEN, agNameBuf);
return INPUT_OPEN;
}
// file was sucessfully opened, initialize its info
// if a file has not been set at this nested level , a stack element
// must be allocated for it. else the current file must be closed
if( ! Flags.fFileSet )
{
pStack = new IN_STACK_ELEMENT;
if(pStackCur)
{
pStackCur->pNext = pStack;
pStack->pPrev = pStackCur;
}
else
{
pStack->pPrev = (IN_STACK_ELEMENT *)NULL;
pStackFirst = pStack;
}
pStack->pNext = (IN_STACK_ELEMENT *)NULL;
pStack->fNewLine = 1;
Flags.fFileSet = 1;
}
else
{
// file was set. That means input was coming from a file. Close
// that file.
fclose(pStack->hFile);
}
pStack->fOpen = 1;
pStack->fRedundantImport = 0;
pStack->ulPos =
pStack->fShadow =
pStack->uShadowLine =
pStack->uShadowCol = 0;
pStack->uCol =
pStack->uLine = 1;
pStack->pShadowName =
pStack->pName = pFullName;
pStack->pIFileName = pIFileName;
pStack->pMIFileName = pMIFileName;
pStack->hFile = hFile;
// add the file to the list of files that we have seen
AddFileToFileList(pFullName, pPath);
return STATUS_OK;
}
/*** AddFileToFileList ******************************************************
* Purpose : to add filename to the list of files we have input from
* Input : filename to add to the list of files, file path
* Output : STATUS_OK if all is well, error otherwise
* Notes :
****************************************************************************/
STATUS_T
NFA_INFO::AddFileToFileList(
char *pName ,
char *pPath )
{
FNAME_LIST *pList = pFileList;
FNAME_LIST *pTemp;
char agNameBuf[ _MAX_DRIVE+_MAX_DIR+_MAX_FNAME+_MAX_EXT+1];
char * pN;
char * pP;
STATUS_T Status;
char agDrive[_MAX_DRIVE];
char agPath[_MAX_DIR];
char agName[_MAX_FNAME];
char agExt[_MAX_EXT];
BOOL fNameHadNoPath = FALSE;
#if 1
_splitpath( pName, agDrive, agPath, agName, agExt );
//
// if the filename came with a path component choose that to add to the file
// list else use the path parameter.
//
strcpy( agNameBuf, agDrive );
strcat( agNameBuf, agPath );
if( fNameHadNoPath = (strlen( agNameBuf ) == 0 ) )
strcpy( agNameBuf, pPath );
if( pPath[ strlen(pPath) - 1] != '\\' )
strcat( agNameBuf, "\\" );
//
// if the filename had a path component, then dont use that name, use the
// name provided by splitpath.
//
if( fNameHadNoPath )
strcat( agNameBuf, pName );
else
{
strcat( agNameBuf, agName );
strcat( agNameBuf, agExt );
}
if( (Status = CreateFullPathAndFName( agNameBuf, &pP, &pN )) != STATUS_OK )
return OUT_OF_MEMORY;
#endif // 1
while(pList && pList->pNext) pList = pList->pNext;
if(! (pTemp = new FNAME_LIST) )
return OUT_OF_MEMORY;
if(pList)
pList->pNext = pTemp;
else
pFileList = pTemp;
pList = pTemp;
#if 0
pList->pName = new char[ strlen( pName ) + 1];
strcpy(pList->pName, pName);
pList->pPath = pPath;
#else // 0
pList->pName = pN;
pList->pPath = pP;
#endif // 0
pList->pNext = (FNAME_LIST *)NULL;
return STATUS_OK;
}
STATUS_T
CreateFullPathAndFName( char * pInput, char **ppPOut, char **ppNOut )
{
char agNameBuf[ _MAX_DRIVE+_MAX_DIR+_MAX_FNAME+_MAX_EXT+1];
char agDrive[_MAX_DRIVE];
char agPath[_MAX_DIR];
char agName[_MAX_FNAME];
char agExt[_MAX_EXT];
_fullpath( agNameBuf, pInput,_MAX_DRIVE+_MAX_DIR+_MAX_FNAME+_MAX_EXT+1);
_splitpath( agNameBuf, agDrive, agPath, agName, agExt );
strcpy( agNameBuf, agDrive );
strcat( agNameBuf, agPath );
*ppPOut = new char [strlen( agNameBuf ) + 1];
strcpy( *ppPOut, agNameBuf );
strcpy( agNameBuf, agName );
strcat( agNameBuf, agExt );
*ppNOut = new char [strlen( agNameBuf ) + 1];
strcpy( *ppNOut, agNameBuf );
return STATUS_OK;
}
BOOL
NFA_INFO::IsDuplicateInput(
char * pThisName)
{
FNAME_LIST *pList = pFileList;
char * pN;
char * pP;
BOOL f = FALSE;
char agNameBuf[ _MAX_DRIVE+_MAX_DIR+_MAX_FNAME+_MAX_EXT+1];
char agDrive[_MAX_DRIVE];
char agPath[_MAX_DIR];
char agName[_MAX_FNAME];
char agExt[_MAX_EXT];
//
// if the file did not come with a path component, then try the normal
// search for file.
//
_splitpath( pThisName, agDrive, agPath, agName, agExt );
strcpy( agNameBuf, agDrive );
strcat( agNameBuf, agPath );
if( strlen( agNameBuf ) == 0 )
{
if( pP = SearchForFile( pThisName ) )
{
strcpy( agNameBuf, pP );
strcat( agNameBuf, pThisName );
}
else
{
strcpy( agNameBuf, pThisName );
}
}
else
strcpy( agNameBuf, pThisName );
CreateFullPathAndFName( agNameBuf, &pP, &pN );
while( pList && pList->pName )
{
#if 0
if( strcmp( pList->pName, pThisName ) == 0 )
return 1;
#else // 0
if( (stricmp( pList->pName , pN ) == 0 ) &&
(stricmp( pList->pPath , pP ) == 0 )
)
{
f = TRUE;
break;
}
#endif // 0
pList = pList->pNext;
}
delete pN;
delete pP;
return f;
}
/*** SetPath *****************************************************************
* Purpose : to add a string to the list of possible paths
* Input : path to add to the list of paths
* Output : STATUS_OK if all is well, error otherwise
* Notes :
****************************************************************************/
STATUS_T
NFA_INFO::SetPath(
char *pPath )
{
PATH_LIST *pList = pPathList;
PATH_LIST *pTemp;
long Len;
while(pList && pList->pNext) pList = pList->pNext;
if(! (pTemp = new PATH_LIST) )
return OUT_OF_MEMORY;
if(pList)
pList->pNext = pTemp;
else
pPathList = pTemp;
// The user could specify a path using a leading space, for example, he can
// specify the -I with a leading space. Even tho the -I should be presented
// to the user with the leading space, we should not get confused. We omit
// leading spaces.
while( isspace( *pPath ) ) pPath++;
pList = pTemp;
pList->pPath = new char[ (Len = strlen(pPath)) + 2];// one possible "\\"
pList->pNext = (PATH_LIST *)NULL;
strcpy( pList->pPath, pPath );
if( Len && (pPath[ Len - 1 ] != '\\' ) )
strcat( pList->pPath, "\\");
return STATUS_OK;
}
/*** SetPreProcessingOn *****************************************************
* Purpose : to set preprocessing on
* Input : nothing
* Output : STATUS_OK if all is well, error otherwise
* Notes : Set the preprocessing flag on. This denotes that preprocessing
* : will be on for all the files that are input to the compiler
****************************************************************************/
STATUS_T
NFA_INFO::SetPreProcessingOn(void)
{
Flags.fPreProcess = 1;
return STATUS_OK;
}
/*** SearchForFile ********************************************************
* Purpose : to search for a file in a previously registered set of paths
* Input : file name
* Output : (char *)NULL if the file was not found in the given set of paths
* : else a pointer to the path where it was found
* Notes :
*************************************************************************/
char *
NFA_INFO::SearchForFile(
char *pName)
{
PATH_LIST *pPathTemp = pPathList;
char agNameBuf[ _MAX_DRIVE+_MAX_DIR+_MAX_FNAME+_MAX_EXT+1];
// the name is guaranteed not to have path or drive info, just the
// base name and extension. We must figure out the paths, from
// the list of paths that we have registered so far
while(pPathTemp)
{
sprintf(agNameBuf, "%s%s", pPathTemp->pPath, pName);
#if 0
if( hFile = fopen( agNameBuf, "rb"))
{
fclose(hFile); // dont use up file handle
return pPathTemp->pPath;
}
#endif // 0
// check for existence only. The read errors need to be checked
// only at read time.
if( _access( agNameBuf, 0 ) == 0 )
return pPathTemp->pPath;
pPathTemp = pPathTemp->pNext;
}
// we did not find the file, return an error
return (char *)NULL;
}
/*** PreProcess ************************************************************
* Purpose : to preprocess the given file into an intermediate file
* Input : drive, path, name and current extension of the file
* Output : STATUS_OK if all is well, error otherwise
* Notes : The c compiler uses the /E switch to generate the
* : the preprocessed output with line numbers to a file.
* : Now the way to do the preprocessing is to spawn the
* : c compiler with the /E switch. But we need to redirect the
* : output to a file. To force the spawnee to redirect, we
* : must also do the redirection in this process, so that the
* : spawnee inherits our file handles.
**************************************************************************/
STATUS_T
NFA_INFO::PreProcess(
char *pDrive,
char *pPath,
char *pName,
char *pExt )
{
STATUS_T Status = STATUS_OK;
char agNameBuf[ _MAX_DRIVE+_MAX_DIR+_MAX_FNAME+_MAX_EXT+1];
char * pCppCmd = (pCompiler->GetCommandProcessor())->GetCPPCmd();
char * pExtPosition;
int SpawnError;
int StdoutSave;
int StderrSave;
int IFHandle;
BOOL fStderrSaved = FALSE;
FILE * hIFile;
int XHandle;
FILE * hXHandle;
BOOL fEraseFile = FALSE;
char * pIntFileName;
// generate the name of the intermediate file into a buffer
#if 1
char * pPathTemp = (char *)0;
if( (pPathTemp = getenv( "TMP" ) ) ||
(pPathTemp = getenv( "TEMP" ) ) ||
(pPathTemp = getenv( "tmp" ) ) ||
(pPathTemp = getenv( "temp" ) ) )
{
strcpy( agNameBuf, pPathTemp );
}
else
{
strcpy(agNameBuf,pDrive);
strcat(agNameBuf,pPath);
}
if( agNameBuf[ strlen(agNameBuf)-1 ] != '\\')
strcat(agNameBuf,"\\");
#else // 1
strcpy(agNameBuf,pDrive);
strcat(agNameBuf,pPath);
if( *pPath && (pPath[ strlen(pPath)-1 ] != '\\'))
strcat(agNameBuf,"\\");
#endif // 1
strcat(agNameBuf,pName);
// write the extension and
// note the place where the file extension started
pExtPosition = agNameBuf + strlen(agNameBuf);
strcat(agNameBuf,".i");
pIntFileName = new char [strlen( agNameBuf ) + 1];
strcpy( pIntFileName, agNameBuf );
// open the intermediate file for writing.
if( (hIFile = _fsopen( agNameBuf, "w", SH_DENYWR )) == (FILE *)0 )
{
RpcError( (char *)NULL,
0,
Status = INTERMEDIATE_FILE_CREATE,
agNameBuf);
return Status;
}
IFHandle = MIDL_FILENO( hIFile );
#if 0
if( (IFHandle = _creat( agNameBuf, (int)(S_IREAD | S_IWRITE) ) ) == -1 )
{
RpcError( (char *)NULL,
0,
Status = INTERMEDIATE_FILE_CREATE,
agNameBuf);
return Status;
}
#endif // 0
// save the current stdout handle
if( (StdoutSave = _dup(1)) == -1 )
{
RpcError( (char *)NULL,
0,
Status = OUT_OF_SYSTEM_FILE_HANDLES,
(char *)NULL);
return Status;
}
// now force the stdout to refer to the intermediate file handle,
// thus establishing redirection.
if( _dup2( IFHandle, 1 ) == -1 )
{
RpcError( (char *)NULL,
0,
Status = OUT_OF_SYSTEM_FILE_HANDLES,
(char *)NULL);
return Status;
}
if( pCommand->IsSwitchDefined(SWITCH_X) )
{
fStderrSaved = TRUE;
#if 1
if( (hXHandle = fopen( "nul", "w" ) ) == (FILE *)0 )
{
RpcError( (char *)NULL,
0,
Status = INTERMEDIATE_FILE_CREATE,
"nul");
return Status;
}
XHandle = MIDL_FILENO( hXHandle );
#else // 1
if( (XHandle = _creat( "nul", (int)(S_IWRITE) ) ) == -1 )
{
RpcError( (char *)NULL,
0,
Status = INTERMEDIATE_FILE_CREATE,
"nul");
return Status;
}
#endif // 1
// save the current stderr handle
if( (StderrSave = _dup(2)) == -1 )
{
RpcError( (char *)NULL,
0,
Status = OUT_OF_SYSTEM_FILE_HANDLES,
(char *)NULL);
return Status;
}
// now force the stdout to refer to the intermediate file handle,
// thus establishing redirection.
if( _dup2( XHandle, 2 ) == -1 )
{
RpcError( (char *)NULL,
0,
Status = OUT_OF_SYSTEM_FILE_HANDLES,
(char *)NULL);
return Status;
}
}
// From now on, stdout is no longer stdout, till we restore it back.
// thus if there are intermediate errors, stdout MUST be restored
// before returning.
// From now on, stderr is no longer stderr, till we restore it back.
// stderr MUST be restored before returning.
#if 1
strcpy( agNameBuf, pDrive );
strcat(agNameBuf,pPath);
if( *pPath && (pPath[ strlen(pPath)-1 ] != '\\'))
strcat(agNameBuf,"\\");
strcat( agNameBuf, pName );
strcat( agNameBuf, pExt );
#else // 1
strcpy( pExtPosition, pExt );
#endif // 1
#if 0 /////////////////////////////////////////////////////////////////
// cannot use printf here, stdout is redirected !!
fprintf( stderr, "Filename given to CPP : %s\n", agNameBuf );
fprintf(stderr, "pCppCmd = %s\n", pCppCmd );
fprintf(stderr, "CmdArg.GetCPPOpt = %s\n", pCompiler->GetCommandProcessor()->GetCPPOpt() );
fprintf(stderr, "agNameBuf = %s\n", agNameBuf);
#endif // 0 ///////////////////////////////////////////////////////////
SpawnError = MIDL_SPAWNLP( P_WAIT
,pCppCmd
,pCppCmd
,(pCompiler->GetCommandProcessor())->GetCPPOpt()
,agNameBuf
,(char *)NULL );
// before doing anything, close the intermediate file handle
fclose( hIFile );
#if 0
_close( IFHandle );
#endif // 0
// restore the stdout back
_dup2( StdoutSave, 1 );
if( fStderrSaved )
{
fclose( hXHandle );
_dup2( StderrSave, 2 );
}
if( SpawnError == -1 )
{
extern int errno;
switch( errno )
{
case ENOMEM:
Status = OUT_OF_MEMORY;
break;
case ENOENT:
Status = NO_PREPROCESSOR;
break;
case ENOEXEC:
Status = PREPROCESSOR_INVALID;
break;
default:
Status = PREPROCESSOR_EXEC;
break;
}
RpcError((char *)NULL, 0, Status , pCppCmd);
fEraseFile = TRUE;
}
else if( SpawnError )
{
char buf[10];
sprintf(buf, "(%d)", SpawnError );
RpcError((char *)NULL, 0, Status = PREPROCESSOR_ERROR, buf);
fEraseFile = TRUE;
}
if( fEraseFile )
{
MIDL_UNLINK( pIntFileName );
}
delete pIntFileName;
//
// if the temp name was found from the env variable, then
// make the drive and path buffers point to the env variable
//
if( pPathTemp )
{
*pDrive = *pPath = '\0';
strcpy( pPath , pPathTemp );
if( (pPath[ strlen(pPath)-1 ] != '\\'))
strcat(pPath,"\\");
}
return Status;
}
/*** GetChar ****************************************************************
* Purpose : get a character from the input stream
* Input : nothing
* Output : a character from the file
* Notes : returns 0 if at end of file
****************************************************************************/
short
NFA_INFO::GetChar( void )
{
short ch;
extern BOOL fRedundantImport;
// if there is a macro expansion buffer, then return the
// characters from there, else return it from the file
if( iText )
{
TEXT_BUFFER * pT = (TEXT_BUFFER *) pTextDict->GetTop();
if( pT )
{
if( ( ch = pT->GetChar()) != 0 )
return ch;
else
{
pT = (TEXT_BUFFER * )pTextDict->Pop();
delete pT;
iText--;
}
}
}
if( pStack->fRedundantImport )
{
fRedundantImport = TRUE;
return 0x0;
}
if( !Flags.fFileSet || !pStack->fOpen) return 0;
again:
if( (((ch=fgetc(pStack->hFile)) == EOF) && feof(pStack->hFile)) ||
(ch == 0x1a) )
return 0;
if(ch == 0x0d || ch == ('L' - 0x40) )
goto again;
// if the line starts off with a '#', it may be a line number
// indicator.
if( pStack->fNewLine && ((ch == ' ' ) || (ch == 0x09)) )
goto again;
if(pStack->fNewLine && (ch == '#'))
{
unsigned long SavePos = ftell(pStack->hFile);
char buffer[_MAX_DRIVE + _MAX_PATH + _MAX_FNAME + _MAX_EXT ];
short Count = 0;
short fLinePresent = 0;
// it coule be a # <space> number or #line <space> number
while( (ch = fgetc( pStack->hFile ) ) == ' ' );
if( isdigit( ch ) )
{
fLinePresent = 1;
}
else
{
buffer[ Count++ ] = (char)ch;
// if it is #line, the first 5 characters will be #line
while(Count < 4)
buffer[Count++] = (char) fgetc(pStack->hFile);
buffer[Count] = '\0';
fLinePresent = (strcmp( buffer, "line" ) == 0 );
if( fLinePresent )
while( (ch = fgetc( pStack->hFile )) == ' ' );
}
if( fLinePresent )
{
Count = 0;
do
{
buffer[Count++] = (char) ch;
} while( (ch = fgetc(pStack->hFile)) != ' ');
buffer[Count] = '\0';
// line to be seen now is the line number indicated.
// but the line number indicator is on a line
// previous to that it indicates, so reflect that in
// the line number
pStack->uLine = atoi(buffer) - 1;
while( (ch=fgetc(pStack->hFile)) == ' ');
Count = 0;
// buffer[Count++] = ch;
// fgetc(pStack->hFile); // skip the quote
if(ch == '\"')
{
while( (ch=fgetc(pStack->hFile)) != '\"')
{
buffer[Count++] = (char) ch;
}
buffer[Count] = 0;
// fgetc(pStack->hFile); // skip the quote again
// make the collected filename as the new name
StripSlashes( buffer );
if(strcmp(buffer, pStack->pName) != 0)
{
pStack->pName = new char[Count+1];
strcpy(pStack->pName, buffer);
}
}
while( (ch = fgetc( pStack->hFile )) != '\n');
/****
if( !Flags.fBaseFileName )
{
pBaseName = new char[ Count+1 ];
strcpy( pBaseName, buffer );
Flags.fBaseFileName = 1;
}
if( strcmp( pBaseName, pStack->pName ) )
{
Flags.fInInclude = 1;
}
else
Flags.fInInclude = 0;
****/
goto newline;
}
else
{
fseek(pStack->hFile, SavePos, SEEK_SET);
ch = '#';
}
}
newline:
if(ch == '\n')
{
DebugLine = pStack->uLine++;
pDebugFile= pStack->pName;
pStack->uCol = 1;
pStack->fNewLine = 1;
}
else
{
pStack->uCol++;
pStack->fNewLine = 0;
}
return ch;
}
/*** UnGetChar **************************************************************
* Purpose : to unget the given character
* Input : the character to unget
* Output : the character which was unget-ed
* Notes :
***************************************************************************/
short
NFA_INFO::UnGetChar(
short c)
{
if( iText )
{
TEXT_BUFFER * pT = (TEXT_BUFFER *) pTextDict->GetTop();
if( pT )
{
c = pT->UnGetChar( c );
}
}
if( !Flags.fFileSet || !pStack->fOpen) return 0;
fseek( pStack->hFile, -1L, SEEK_CUR);
if(c == '\n')
{
pStack->uLine--;
// dont know what to do with column, really
}
else
pStack->uCol--;
return c;
}
/*** GetCurrentInputDetails *************************************************
* Purpose : to return details of the current input
* Input : pointer to name pointer, pointer to line no, pointer to col
* Output : STATUS_OK if all is well, error otherwise
* Notes :
****************************************************************************/
STATUS_T
NFA_INFO::GetCurrentInputDetails(
char **ppName,
short *pLineNo,
short *pColNo )
{
if(!pStack)
{
(*ppName) = "";
(*pLineNo) = 0;
(*pColNo) = 0;
return NO_INPUT_FILE;
}
(*ppName) = pStack->pName;
(*pLineNo) = pStack->uLine;
(*pColNo) = pStack->uCol;
return STATUS_OK;
}
/*** GetInputDetails ********************************************************
* Purpose : to return details of the input
* Input : pointer to name pointer, pointer to line no, pointer to col
* Output : STATUS_OK if all is well, error otherwise
* Notes :
****************************************************************************/
STATUS_T
NFA_INFO::GetInputDetails(
char **ppName,
short *pLineNo)
{
if(!pStack)
{
(*ppName) = "";
(*pLineNo) = 0;
return NO_INPUT_FILE;
}
(*ppName) = pStack->pShadowName;
(*pLineNo) = pStack->uLine;
return STATUS_OK;
}
/*** GetInputDetails ********************************************************
* Purpose : to return details of the current input
* Input : pointer to name pointer
* Output : STATUS_OK if all is well, error otherwise
* Notes :
****************************************************************************/
STATUS_T
NFA_INFO::GetInputDetails(
char **ppName)
{
if(!pStack) return NO_INPUT_FILE;
(*ppName) = pStack->pShadowName;
return STATUS_OK;
}
void
NFA_INFO::SetEOIFlag()
{
Flags.fEOI = 1;
}
short
NFA_INFO::GetEOIFlag()
{
return (BOOL)Flags.fEOI;
}
BOOL
NFA_INFO::IsInInclude()
{
return Flags.fInInclude;
}
/****************************************************************************
**** temp functions to see if things are fine
****************************************************************************/
void
NFA_INFO::Dump()
{
PATH_LIST *pPathTemp = pPathList;
FNAME_LIST *pNameTemp = pFileList;
printf("\nDump of file handler data structure:");
printf("\nPreprocessing :%d", Flags.fPreProcess);
printf("\nfFileSet :%d", Flags.fFileSet);
printf("\nCurrentLexLevel :%d", iCurLexLevel);
printf("\n");
if(pPathTemp)
{
printf("\nList of paths:");
while( pPathTemp )
{
printf("\nPATH: %s", pPathTemp->pPath);
pPathTemp = pPathTemp->pNext;
}
}
if(pNameTemp)
{
printf("\nList of input files so far:");
while(pNameTemp)
{
printf("\nFILE: %s", pNameTemp->pName);
pNameTemp = pNameTemp->pNext;
}
}
}
/******************************************************************************
* general utility routines
******************************************************************************/
/*** SplitFileName ************************************************************
* Purpose : to analyse the filename and return individual components
* Input : pointers to individual components
* Output : nothing
* Notes :
*****************************************************************************/
void
SplitFileName(
char * pFullName,
char ** pagDrive,
char ** pagPath,
char ** pagName,
char ** pagExt )
{
char agDrive[ _MAX_DRIVE ];
char agPath[ _MAX_DIR ];
char agName[ _MAX_FNAME ];
char agExt[ _MAX_EXT ];
_splitpath( pFullName, agDrive, agPath, agName, agExt );
if( agDrive[0] )
{
(*pagDrive) = new char[ strlen(agDrive) + 1 ];
strcpy( (*pagDrive), agDrive );
}
else
{
(*pagDrive) = new char[ 1 ];
*(*pagDrive) = '\0';
}
if( agPath[0] )
{
(*pagPath) = new char[ strlen(agPath) + 1 ];
strcpy( (*pagPath), agPath );
}
else
{
(*pagPath) = new char[ 2 + 1 ];
strcpy( (*pagPath), ".\\");
}
if( agName[0] )
{
(*pagName) = new char[ strlen(agName) + 1 ];
strcpy( (*pagName), agName );
}
else
{
(*pagName) = new char[ 1 ];
*(*pagName) = '\0';
}
if( agExt[0] )
{
(*pagExt) = new char[ strlen(agExt) + 1 ];
strcpy( (*pagExt), agExt );
}
else
{
(*pagExt) = new char[ 1 ];
*(*pagExt) = '\0';
}
}
void
StripSlashes(
char * p )
{
char * pSave = p;
char * p1;
char * dest = new char [ 256 ],
* destSave = dest;
short n;
if( p )
{
dest[0] = 0;
while( p1 = strstr( p, "\\\\" ) )
{
strncpy( dest, p, n = p1 - p );
dest += n;
*dest++ = '\\';
*dest = 0;
p = p1 + 2;
while( *p == '\\') p++;
}
strcat( dest, p );
strcpy( pSave, destSave );
}
delete destSave;
}
void
ChangeToForwardSlash(
char * pFullInputName,
char * pFullName )
{
short ch;
while( (ch = *pFullInputName++ ) )
{
if( ch == '/' )
ch = '\\';
*pFullName++ = (char) ch;
}
*pFullName = '\0';
}