macros.c
来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 1,398 行 · 第 1/3 页
C
1,398 行
/****************************************************************************
*
* Open Watcom Project
*
* Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
*
* ========================================================================
*
* This file contains Original Code and/or Modifications of Original
* Code as defined in and that are subject to the Sybase Open Watcom
* Public License version 1.0 (the 'License'). You may not use this file
* except in compliance with the License. BY USING THIS FILE YOU AGREE TO
* ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
* provided with the Original Code and Modifications, and is also
* available at www.sybase.com/developer/opensource.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
* NON-INFRINGEMENT. Please see the License for the specific language
* governing rights and limitations under the License.
*
* ========================================================================
*
* Description: Macro parsing and processing routines.
*
****************************************************************************/
#if !defined( __UNIX__ ) // NAME_MAX clashes with that in UNIX <limits.h>
#include <direct.h> // Needed for getcwd()
#else
#include <sys/types.h> // Implicitly included by <direct.h>
#endif
#include <stdlib.h>
#include <string.h>
#ifdef __WATCOMC__
#include <env.h> // For setenv()
#endif
#include "massert.h"
#include "mtypes.h"
#include "mstream.h"
#include "mlex.h"
#include "mhash.h"
#include "macros.h"
#include "make.h"
#include "mmemory.h"
#include "mmisc.h"
#include "mpathgrp.h"
#include "mpreproc.h"
#include "mrcmsg.h"
#include "msg.h"
#include "mupdate.h"
#include "mvecstr.h"
/* arbitrarily set the length of the command line */
#define MAX_COMMANDLINE (_MAX_PATH * 5)
/*
* macros are stored in a hash table
*/
#define HASH_PRIME 37
typedef struct Macro {
HASHNODE node; /* name is at name.node */
const char *value;
BIT readonly; /* ie: from command line */
} MACRO;
STATIC HASHTAB *macTab; /* head for the macro lookup table */
/*
* dirBuf is a static buffer used by procPath to store the result of a
* form-specifier macro; and it is used by GetMacroValue for %CDRIVE/%CWD.
* It is not allocated until needed.
*/
STATIC char *dirBuf;
/*
* This variable is to be able to do partial deMacro intead of full deMacro
* for ms-option. This is needed by the inference rules
* in ms nmake at which it deMacros the macros latter on in time
*/
BOOLEAN ImplicitDeMacro;
/*
* Only Useful in ms option if it is partDeMacro then we only deMacro
* everything except for special DeMacro characters
*
*/
BOOLEAN IsPartDeMacro;
BOOLEAN DoingBuiltIn; /* Are we parsing builtin macros */
#ifdef CLEAN_ENVIRONMENT_VAR
/* This contains the old environment values before wmake actually */
/* redefines them - only valid in ms-option */
STATIC ELIST *OldEnvValues;
#endif
STATIC char *getDirBuf( void )
/****************************/
{
if( dirBuf == NULL ) {
dirBuf = MallocSafe( _MAX_PATH );
}
return( dirBuf );
}
static void massageDollarOctothorpe( char *p )
/********************************************/
{
assert( p != NULL );
for( ; *p; ++p ) {
switch( *p ) {
case '$':
*p = TMP_DOL_C;
break;
case '#':
*p = TMP_COMMENT_C;
break;
}
}
}
extern const char *procPath( const char *fullpath )
/**************************************************
* process fullpath according to the form qualifier in CurAttr.num
* returns: pointer to a static buffer
*/
{
PGROUP *pg;
char *current;
if( fullpath == NULL ) {
return( NULL );
}
getDirBuf();
pg = SplitPath( fullpath );
switch( CurAttr.num ) {
case FORM_FULL:
_makepath( dirBuf, pg->drive, pg->dir, pg->fname, pg->ext );
break;
case FORM_NOEXT:
_makepath( dirBuf, pg->drive, pg->dir, pg->fname, NULL );
break;
case FORM_NOEXT_NOPATH:
_makepath( dirBuf, NULL, NULL, pg->fname, NULL );
break;
case FORM_NOPATH:
_makepath( dirBuf, NULL, NULL, pg->fname, pg->ext );
break;
case FORM_PATH:
_makepath( dirBuf, pg->drive, pg->dir, NULL, NULL );
if( Glob.microsoft) {
if( dirBuf[0] == NULLCHAR ) {
dirBuf[0] = '.';
dirBuf[1] = NULLCHAR;
} else {
current = dirBuf;
while( *current != NULLCHAR ) {
++current;
}
if( *(current - 1) == '\\' ) {
*(current - 1) = NULLCHAR;
}
}
}
break;
case FORM_EXT:
_makepath( dirBuf, NULL, NULL, NULL, pg->ext );
break;
default:
dirBuf[0] = '\0';
}
DropPGroup( pg );
massageDollarOctothorpe( dirBuf );
return( dirBuf );
}
STATIC const char *specialValue( TOKEN_T t )
/*******************************************
* process the special macro t
* returns: pointer to a static buffer
*/
{
char const *dirBufGot = NULL;
assert( t == MAC_CUR || t == MAC_FIRST || t == MAC_LAST );
assert( FORM_MIN < CurAttr.num && CurAttr.num < FORM_MAX );
switch( t ) {
case MAC_CUR: dirBufGot = GetCurTarg(); break;
case MAC_FIRST: dirBufGot = GetFirstDep(); break;
case MAC_LAST: dirBufGot = GetLastDep(); break;
}
return( procPath( dirBufGot ) );
}
STATIC void makeMacroName( char *buffer, const char *name )
/**********************************************************
* convert name to internal form (upcased)
* buffer must be at least as large as name
* Microsoft and POSIX environment variables are case sensitive
*/
{
assert( IsMacroName( name ) );
if( Glob.microsoft || Glob.posix ) {
strcpy( buffer, name );
} else {
while( (*buffer = toupper( *name )) != NULLCHAR ) {
++buffer, ++name;
}
}
}
STATIC MACRO *getMacroNode( const char *name )
/*********************************************
* returns: pointer to MACRO with this name
*/
{
BOOLEAN caseSensitive;
assert( name != NULL && *name != ENVVAR );
if( Glob.microsoft || Glob.posix ) {
caseSensitive = TRUE;
} else {
caseSensitive = FALSE;
}
return( (MACRO *)FindHashNode( macTab, name, caseSensitive ) );
}
STATIC char *findEqual( char *inString )
/***************************************
* returns" pointer to equals sign if found
*/
{
char *ret;
ret = strrchr( inString, EQUAL );
if( ret == inString ) {
ret = NULL;
}
return( ret );
}
STATIC RET_T getOldNewString( char *inString, char **oldString,
char **newString )
/*************************************************************/
{
char *equal;
equal = findEqual( inString );
if( equal == NULL ) {
return( RET_ERROR );
} else {
*oldString = inString;
*equal = NULLCHAR;
*newString = equal + 1;
return( RET_SUCCESS );
}
}
STATIC char *doStringSubstitute( const char *name, const char *oldString,
const char *newString )
/************************************************************************
* $(macroname:oldstr=newstr)
* substitute any occurence of oldstr with new str
*/
{
VECSTR output;
char const *current;
char const *start;
size_t old_len;
output = StartVec();
WriteVec( output, "" );
assert( name != NULL && oldString != NULL && newString != NULL );
old_len = strlen( oldString );
for( start = current = name; *current != NULLCHAR; current++ ) {
if( strncmp( current, oldString, old_len ) == 0 ) {
CatNStrToVec( output, start, current - start );
CatStrToVec( output, newString );
start = current + old_len;
current = start - 1;
}
}
CatStrToVec( output, start );
return( FinishVec( output ) );
}
#ifdef __WATCOMC__
#pragma on (check_stack);
#endif
STATIC const char *GetMacroValueProcess( const char *name )
/**********************************************************
* returns: pointer to text of macro (incl. environment vars)
*/
{
char macro[MAX_MAC_NAME];
MACRO *cur;
char *env;
BOOLEAN cdrive;
BOOLEAN cwd;
char *p;
int pos;
makeMacroName( macro, name ); // Does assert( IsMacroName( name ) );
if( *macro == ENVVAR ) {
env = getenv( macro + 1 );
if( env != NULL ) {
return( env );
}
cdrive = strcmp( macro + 1, "CDRIVE" ) == 0 ||
strcmp( macro + 1, "__CDRIVE__" ) == 0;
cwd = strcmp( macro + 1, "CWD" ) == 0 ||
strcmp( macro + 1, "__CWD__" ) == 0;
if( cdrive || cwd ) {
if( getcwd( getDirBuf(), _MAX_PATH ) == NULL ) {
return( NULL );
}
p = strchr( dirBuf, ':' );
if( cdrive ) {
if( p != NULL ) {
*p = NULLCHAR;
} else {
dirBuf[0] = NULLCHAR;
}
return( dirBuf );
} else { /* cwd */
if( p != NULL ) {
return( p + 1 );
}
return( dirBuf );
}
}
return( NULL );
}
cur = getMacroNode( macro );
if( cur != NULL ) {
return( cur->value );
}
// If not defined as a macro then get it as a Environment variable
if( Glob.microsoft || Glob.posix ) {
// Check if macro is all caps in NMAKE mode
if( Glob.microsoft ) {
for( pos = 0; macro[pos] != NULLCHAR; ++pos ) {
if( macro[pos] != toupper( macro[pos] ) ) {
return( NULL );
}
}
}
env = getenv( macro );
if( env != NULL ) {
return( env );
}
}
return( NULL );
}
#ifdef __WATCOMC__
#pragma off(check_stack);
#endif
extern char *GetMacroValue( const char *name )
/*********************************************
* Now we need to check for string substitution
* $(MACRONAME:oldstring=newstring)
*/
{
char *InName;
const char *beforeSub;
char *afterSub;
char *current;
char *new;
char *old;
char *line;
InName = StrDupSafe( name );
current = strchr( InName, COLON );
if( current == NULL ) {
beforeSub = GetMacroValueProcess( InName );
if( beforeSub == NULL ) {
afterSub = NULL;
} else {
afterSub = StrDupSafe( beforeSub );
}
} else {
*current++ = NULLCHAR;
beforeSub = GetMacroValueProcess( InName );
if( beforeSub == NULL ) {
afterSub = NULL;
} else {
line = NULL;
// recursively expand so $(macro:sub) OK if macro contains another
if( strchr( beforeSub, DOLLAR ) != NULL ) {
UnGetCH( STRM_MAGIC );
InsString( beforeSub, FALSE );
beforeSub = line = DeMacro( STRM_MAGIC );
GetCHR(); // eat STRM_MAGIC
}
if( beforeSub == NULL ) {
afterSub = NULL;
} else {
if( getOldNewString( current, &old, &new ) == RET_SUCCESS ) {
afterSub = doStringSubstitute( beforeSub, old, new );
} else {
afterSub = NULL;
PrtMsg( ERR | LOC | INVALID_STRING_SUBSTITUTE );
}
if( line ) {
FreeSafe( line );
}
}
}
}
FreeSafe( InName );
return( afterSub );
}
STATIC char *trimMacroValue( char *v )
/************************************/
{
int space;
char *t;
char *p;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?