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 + -
显示快捷键?