windows-nt/Source/XPSP1/NT/com/rpc/midl/driver/ppcmd.cxx

288 lines
7.7 KiB
C++
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Copyright (c) 1989-1999 Microsoft Corporation
Module Name:
ppcmd.cxx
Abstract:
This file preprocesses the command line to check for response file
input.
Notes:
This file extends the register args routine from the command analyser to
incorporate the response files.
Author:
vibhasc 03-16-91 Created to conform to coding guidelines.
NishadM 02-03-97 rewrite to simplify, allow DBCS, remove bugs
----------------------------------------------------------------------------*/
#if 0
Notes
-----
We want to make implementations of the response file completely transparent
to the rest of the compiler. The response file is specified to midl using
the syntax:
midl <some switches> @full response file path name <more switches>.
We dont want to restrict the user from specifyin the response file at any
place in the command line, any number of times. At the same time we do not
want the command analyser to even bother about the response file, to keep
implementation very localised. In order to do that, we do a preprocessing
on the command line to look for the response file command.
The command analyser expects the arguments in an argv like array. The
preprocessor will creates this array, expanding all response file commands
into this array, so that the command analyser does not even notice the
difference.
We use our fancy dynamic array implementation to create this argv-like
array.
Things to keep in mind:
1. The response file needs to be parsed.
2. Each option must be completely specified in a command line. i.e
the option cannot be continued in a separate line using the continuation
character or anything.
3. Each switch must be presented just the same way that the os command
processor does. We need to analyse the string for escaped '"'
#endif // 0
#pragma warning ( disable : 4514 )
/*****************************************************************************
local defines and includes
*****************************************************************************/
#include "nulldefs.h"
extern "C" {
#include <stdio.h>
#include <string.h>
#include <ctype.h>
}
#include "common.hxx"
#include "errors.hxx"
#include "idict.hxx"
extern BOOL fNoLogo;
extern void RpcError( char *, short, STATUS_T, char *);
bool
AnalyseResponseFile (
char* p,
IDICT* pIDict
);
char *
ParseResponseFile (
FILE* h,
unsigned int uLineNumber,
char* szFilename
);
/*****************************************************************************/
bool
PPCmdEngine(
int argc,
char * argv[],
IDICT * pIDict )
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Routine Description:
command preprocessor engine.
Arguments:
argc - count of the number of arguments
argv - vector of arguments to the program
pIDict - dictionary of arguments to be returned.
Return Value:
Pointer to an indexed dictionary (actually a dynamic array ), containing
the entire set of arguments, including the ones from the response file.
Notes:
Go thru each of the arguments. If you find a response file switch, pick up
the arguments from the response file and add to the argument list.
----------------------------------------------------------------------------*/
{
int iArg;
char * p,
* q;
bool fNoLogo = false;
for( iArg = 0; iArg < argc ; ++iArg )
{
p = argv[ iArg ];
switch( *p )
{
case '@':
fNoLogo |= AnalyseResponseFile( p, pIDict );
break;
case '/':
case '-':
// detect /nologo early in the cmd parse
if ( !strcmp( p+1, "nologo" ) )
fNoLogo = true;
// fall through
default:
q = new char[ strlen( p ) + 1 ];
strcpy( q, p );
pIDict->AddElement( (IDICTELEMENT) q );
break;
}
}
return !fNoLogo;
}
bool
AnalyseResponseFile (
char* p,
IDICT* pIDict
)
{
FILE* pResponseFile;
bool fNoLogo = false;
// try to open the response file.
// ++p to skip '@' preceding the filename.
if ( ( pResponseFile = fopen( ++p, "r") ) == (FILE *)NULL )
{
RpcError( (char *)0, 1, CANNOT_OPEN_RESP_FILE, p );
}
else
{
char* szArg = 0;
unsigned int uLineNumber = 1;
// the response file successfully opened. parse it.
while ( ( szArg = ParseResponseFile(
pResponseFile,
uLineNumber,
p
) ) != 0 )
{
if ( 0 == strcmp(szArg, "-nologo")
|| 0 == strcmp(szArg, "/nologo") )
{
fNoLogo = true;
}
pIDict->AddElement( szArg );
}
fclose( pResponseFile );
}
return fNoLogo;
}
char *
ParseResponseFile (
FILE* h,
unsigned int uLineNumber,
char* szFilename
)
{
char szTempArg[1024];
char* p = szTempArg;
int ch = 0;
// initialize pTempArg
*p = 0;
// remove all the leading spaces
do
{
ch = fgetc( h );
if ( ch == '\n' )
{
uLineNumber++;
}
}
while ( isspace( ch ) );
if ( ch == '"' )
{
// if the argument is within quotes,
// all chars including spaces make up the
// argument. The quote is treated as a delimiter
do
{
ch = fgetc( h );
*p++ = (char) ch;
if ( ch == '\\' )
{
// double back slash is interpreted as one.
ch = fgetc( h );
*p++ = (char) ch;
if ( ch == '\\' )
{
p--;
}
}
else if ( ch == '\n' )
{
uLineNumber++;
}
}
while ( ch != '"' && ch != EOF );
*(p - 1) = 0;
}
else if ( ch == '@' )
{
// first char of the argument is a '@'
// this means a response file with a response
// file. Flag an error.
RpcError( szFilename,
(short)uLineNumber,
NESTED_RESP_FILE,
(char *)0 );
}
else if ( ch != EOF )
{
// if the argument is not with in quotes,
// white spaces are delimiters.
*p++ = (char)ch;
do
{
ch = fgetc( h );
*p++ = (char)ch;
if ( ch == '\n' )
{
uLineNumber++;
}
}
while ( !isspace( ch ) && ch != EOF );
*(p - 1) = 0;
}
size_t nSize = strlen( szTempArg );
char* szRet = 0;
if ( nSize != 0 )
{
szRet = new char[nSize+1];
if ( szRet != 0 )
{
strcpy( szRet, szTempArg );
}
}
return szRet;
}