msuffix.c

来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 586 行

C
586
字号
/****************************************************************************
*
*                            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:  Suffix (extension) management.
*
****************************************************************************/


#include <unistd.h>
#include <stdlib.h>
#include <string.h>

#include "make.h"
#include "massert.h"
#include "mcache.h"
#include "mmemory.h"
#include "mhash.h"
#include "mmisc.h"
#include "mpathgrp.h"
#include "mrcmsg.h"
#include "msg.h"
#include "msuffix.h"
#include "mtarget.h"


#define HASH_PRIME  13
#define CASESENSITIVE FALSE // Is suffix name case insensitive
STATIC HASHTAB  *sufTab;
STATIC UINT16   nextId;
STATIC UINT16   prevId;     // Has to be one less than nextId


STATIC void freePathRing( PATHRING *pring )
/*****************************************/
{
    PATHRING    *walk;
    PATHRING    *cur;

    if( pring == NULL ) {
        return;
    }

    walk = pring;
    do {
        cur = walk;
        walk = walk->next;
        FreeSafe( cur->name );
        FreeSafe( cur );
    } while( walk != pring );
}


STATIC BOOLEAN freeSuffix( void *node, void *ptr )
/************************************************/
{
    SUFFIX  *suf = node;
    CREATOR *ccur;
    CREATOR *cwalk;

    (void)ptr; // Unused
    FreeSafe( suf->node.name );
    freePathRing( suf->first );

    cwalk = suf->creator;
    while( cwalk != NULL ) {
        ccur = cwalk;
        cwalk = cwalk->next;
        KillTarget( ccur->cretarg->node.name );
        FreeSafe( ccur );
    }

    FreeSafe( suf );

    return( FALSE );
}


extern void ClearSuffixes( void )
/********************************
 * clear all suffix definitions
 */
{
    WalkHashTab( sufTab, freeSuffix, NULL );
    FreeHashTab( sufTab );
    sufTab = NewHashTab( HASH_PRIME );
    nextId = 32768U;
    prevId = nextId - 1;
}


#ifdef __WATCOMC__
#pragma on (check_stack);
#endif
STATIC SUFFIX *findSuffixNode( const char *name, const char **p )
/****************************************************************
 * returns: pointer to SUFFIX named name, or NULL.  If p != NULL, then
 *          *p will be the pointer to the first dot not in the first
 *          position of name.  ie:
 *          .src.dest   returns SUFFIX src, and p = ".dest"
 *          src.dest    same
 *          .src or src returns SUFFIX src, and p = NULL
 */
{
    char        sufname[MAX_SUFFIX];
    const char  *s;
    char        *d;

    assert( name != NULL );

    if( name[0] == DOT ) {
        ++name;
    }

    d = sufname;
    s = name;
    while( *s != NULLCHAR && *s != DOT ) {
        *d++ = *s++;
    }
    *d = NULLCHAR;

    if( p != NULL ) {
        if( *s == DOT ) {
            *p = s;
        } else {
            *p = NULL;
        }
    }

    FixName( sufname );

    return( (SUFFIX *)FindHashNode( sufTab, sufname, CASESENSITIVE ) );
}
#ifdef __WATCOMC__
#pragma off(check_stack);
#endif


extern SUFFIX *FindSuffix( const char *name )
/*******************************************/
{
    return( findSuffixNode( name, NULL ) );
}


extern BOOLEAN SufExists( const char *name )    /* with . */
/******************************************/
{
    assert( name != NULL && name[0] == DOT );

    return( FindSuffix( name ) != NULL );
}


STATIC void AddFrontSuffix( char const *name )
/*********************************************
 * pass name with leading .; adds name to suffix table and assigns id
 * retains use of name after call
 * adds the suffix to the front of the extensions list by giving an id
 * that is decremented instead of incremented for microsoft option only
 */
{
    SUFFIX  *new;

    assert( (name + 1) != NULL && name[0] == DOT && !SufExists( name ) );

    new = CallocSafe( sizeof( *new ) );
    new->node.name = FixName( StrDupSafe( name + 1 ) );
    new->id = prevId;
    --prevId;

    AddHashNode( sufTab, (HASHNODE *)new );
}


extern BOOLEAN SufBothExist( const char *sufsuf )   /* .src.dest */
/************************************************
 *  for MS-Option it only checks if the dependent suffix is defined
 *  so no need for checking the target suffix if it exists
 */
{
    char const  *ptr;

    assert( sufsuf != NULL && sufsuf[0] == DOT &&
        strchr( sufsuf + 1, DOT ) != NULL );

    if( findSuffixNode( sufsuf, &ptr ) == NULL ) {
        return( FALSE );
    }

    if( FindSuffix( ptr ) == NULL ) {
        if( Glob.microsoft == TRUE ) {
            AddFrontSuffix( ptr );
            return( TRUE );
        } else {
            return( FALSE );
        }

    } else {
        return( TRUE );
    }

}


extern void AddSuffix( char *name )
/**********************************
 * pass name with leading .; adds name to suffix table and assigns id
 * retains use of name after call
 */
{
    SUFFIX  *new;
    char    *d;
    char    *s;

    assert( name != NULL && name[0] == DOT && !SufExists( name ) ||
            name != NULL && name[0] == DOT && SufExists( name ) &&
            Glob.microsoft);

    d = name;                   /* shift left by 1 place */
    s = name + 1;
    while( *s != NULLCHAR ) {
        *d++ = *s++;
    }
    *d = NULLCHAR;

    new = CallocSafe( sizeof( *new ) );
    new->node.name = FixName( name );
    new->id = nextId;
    ++nextId;

    AddHashNode( sufTab, (HASHNODE *)new );
}


STATIC void ringPath( PATHRING **pring, const char *path )
/********************************************************/
{
    PATHRING    **tail;
    PATHRING    *new;
    const char  *p;
    size_t      len;

    assert( pring != NULL && path != NULL );

    tail = pring;            /* find "tail" of ring */
    if( *tail != NULL ) {
        do {
            tail = &(*tail)->next;
        } while( *tail != *pring );
    }

    p = path;
    while( *p != NULLCHAR ) {
            /* find end of path in string */
        while( *p != NULLCHAR && *p != PATH_SPLIT && *p != ';' ) {
            ++p;
        }

        new = MallocSafe( sizeof( *new ) );     /* get a new node */
        len = p - path;                         /* get length of sub-path */
        new->name = MallocSafe( len + 1 );      /* make copy of sub-path */
        memcpy( new->name, path, len );
        new->name[len] = NULLCHAR;
        FixName( new->name );

        *tail = new;        /* link into ring - but don't close ring yet */
        tail = &new->next;

        if( *p != NULLCHAR ) {
            ++p;
            path = p;        /* advance to next path in string */
        }
    }
    *tail = *pring;         /* now we finally close the ring up */
}


extern void SetSufPath( const char *name, const char *path )
/**********************************************************/
/* name with . */
{
    SUFFIX      *suf;

    assert( name != NULL && name[0] == DOT );

    suf = FindSuffix( name );

    assert( suf != NULL );

    if( path == NULL ) {
        freePathRing( suf->first );
        suf->first = NULL;
        suf->pathring = NULL;
        return;
    }

    ringPath( &suf->first, path );
    if( suf->pathring == NULL ) {
        suf->pathring = suf->first;
    }
}


STATIC CREATOR *newCreator( void )
/********************************/
{
    return( (CREATOR *)CallocSafe( sizeof( CREATOR ) ) );
}


extern void AddCreator( const char *sufsuf )
/*******************************************
 * add the creation .src.dest
 */
{
    SUFFIX      *src;
    SUFFIX      *dest;
    char const  *ptr;
    CREATOR     *new;
    CREATOR     **cur;

    assert( sufsuf != NULL && sufsuf[0] == DOT &&
        strchr( sufsuf + 1, DOT ) != NULL );

    src = findSuffixNode( sufsuf, &ptr );
    dest = FindSuffix( ptr );

    assert( src != NULL && dest != NULL );

    if( !Glob.microsoft && !Glob.posix && src->id < dest->id ) {
        PrtMsg( ERR | LOC | EXTENSIONS_REVERSED );
    }
    cur = &dest->creator;
    while( *cur != NULL ) {
        if( src->id <= (*cur)->suffix->id ) {
            break;
        }
        cur = &(*cur)->next;
    }

    if( *cur != NULL && src->id == (*cur)->suffix->id ) {
        return;
    }

    new = newCreator();
    new->suffix = src;
    new->cretarg = NewTarget( sufsuf );
    new->cretarg->special = TRUE;
    new->cretarg->sufsuf  = TRUE;

    new->next = *cur;
    *cur = new;

    return;
}


STATIC BOOLEAN printSuf( void *node, void *ptr )
/**********************************************/
{
    SUFFIX      *suf = node;
    CREATOR     *cur;
    PATHRING    *pring;
    TARGET      *targ;
    CLIST       *cmds;
    BOOLEAN     printed;

    (void)ptr; // Unused
    PrtMsg( INF | PSUF_SUFFIX, suf->node.name );
    if( suf->pathring != NULL ) {
        pring = suf->pathring;
        do {
            PrtMsg( INF | PSUF_FOUND_IN, pring->name );
            pring = pring->next;
        } while( pring != suf->pathring );
        printed = TRUE;
    } else {
        printed = FALSE;
    }
    cur = suf->creator;
    if( cur != NULL && printed ) {
        PrtMsg( INF | NEWLINE );
    }
    while( cur != NULL ) {
        PrtMsg( INF | NEOL | PSUF_MADE_FROM, cur->suffix->node.name );
        targ = cur->cretarg;
        PrintTargFlags( targ );
        PrtMsg( INF | NEWLINE );
        cmds = targ->depend->clist;
        if( cmds != NULL ) {
            PrtMsg( INF | PSUF_USING_CMDS );
            PrintCList( cmds );
        }
        cur = cur->next;
        if( cur != NULL ) {
            PrtMsg( INF | NEWLINE );
        }
    }
    PrtMsg( INF | NEWLINE );

    return( FALSE );
}


extern void PrintSuffixes( void )
/*******************************/
{
    WalkHashTab( sufTab, printSuf, NULL );
}


STATIC RET_T chkOneName( char *buffer, TARGET **chktarg )
/*******************************************************/
{
    TARGET  *tmp;

    FixName( buffer );

    if( chktarg != NULL ) {
        tmp = FindTarget( buffer );
        if( tmp != NULL ) {
            *chktarg = tmp;
            return( RET_SUCCESS );
        }
    }
    if( CacheExists( buffer ) ) {
        return( RET_SUCCESS );
    }
    return( RET_ERROR );
}


STATIC RET_T tryPathRing( PATHRING **pring, char *buffer,
    const char *dir, const char *fname, const char *ext, TARGET **chktarg )
/**************************************************************************
 * walk a path ring, and attempt to find fname.ext using different paths
 */
{
    PATHRING    *cur;
    char        fake_name[_MAX_PATH];

    assert( pring != NULL );
    if( *pring == NULL ) {
        return( RET_ERROR );
    }
    if( dir[0] == '\0' ) {
        dir = NULL;
    }
    _makepath( fake_name, NULL, dir, fname, ext );
    cur = *pring;
    do {
        _makepath( buffer, NULL, cur->name, fake_name, NULL );
        if( chkOneName( buffer, chktarg ) == RET_SUCCESS ) {
            if( Glob.optimize ) {       /* nail down pathring here */
                *pring = cur;
            }
            return( RET_SUCCESS );
        }
        cur = cur->next;
    } while( cur != *pring );

    return( RET_ERROR );
}


extern RET_T TrySufPath( char *buffer, const char *filename, TARGET **chktarg,
    BOOLEAN tryenv )
/*****************************************************************************
 * it is NOT necessary that filename != buffer
 * the contents of buffer may be destroyed even if RET_ERROR is returned
 * first checks current directory, then any in suffix path
 * assumes buffer is at least _MAX_PATH, and that if buffer != filename
 * then buffer, and filename do not overlap
 */
{
    PGROUP      *pg;
    SUFFIX      *suffix;
    char        *env;
    PATHRING    *envpath;
    RET_T       ret;

    if( chktarg != NULL ) { /* always NULL the chktarg before working */
        *chktarg = NULL;
    }

    /* check if filename given exists */
    if( filename != buffer ) {
        strcpy( buffer, filename );
    }
    if( chkOneName( buffer, chktarg ) == RET_SUCCESS ) {
        return( RET_SUCCESS );
    }

    /* split up filename */
    pg = SplitPath( filename );

    if( pg->drive[0] != NULLCHAR || isdirc( pg->dir[0] ) ) {
        /* is an absolute path name */
        DropPGroup( pg );
        return( RET_ERROR );
    }

    suffix = FindSuffix( pg->ext );

    ret = RET_ERROR;

    if( suffix == NULL || suffix->pathring == NULL ) {
            /* no suffix info - use %PATH */
        if( tryenv ) {
            env = getenv( "PATH" );
        } else {
            /*
             *  This is an incredible kludge so that Brian could build
             *  the header project from one makefile without making
             *  many changes to the makefile.   Some people are soooo
             *  lazy :)  DJG
             */
            env = getenv( "__SEARCH_PATH__" );
        }
        if( env != NULL ) {
            envpath = NULL;
            ringPath( &envpath, env );

            Glob.cachedir = FALSE;      /* never cache %path */
            ret = tryPathRing( &envpath, buffer, pg->dir, pg->fname, pg->ext,
                chktarg );
            Glob.cachedir = TRUE;

            freePathRing( envpath );
        }
    } else {
        ret = tryPathRing( &suffix->pathring, buffer, pg->dir, pg->fname,
            pg->ext, chktarg );
    }

    DropPGroup( pg );

    return( ret );
}


extern void SuffixInit( void )
/****************************/
{
    sufTab = NewHashTab( HASH_PRIME );
    nextId = 32768U;
    prevId = nextId - 1;
}


extern void SuffixFini( void )
/****************************/
{
#ifdef DEVELOPMENT
    ClearSuffixes();
    FreeHashTab( sufTab );
    sufTab = NULL;
#else
    WalkHashTab( sufTab, freeSuffix, NULL );
    FreeHashTab( sufTab );
#endif
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?