mstream.c

来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 537 行 · 第 1/2 页

C
537
字号
/****************************************************************************
*
*                            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:  Stream processing for wmake.
*
****************************************************************************/


#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#ifdef __WATCOMC__
    #include <share.h>
#endif

#include "macros.h"
#include "make.h"
#include "massert.h"
#include "mtypes.h"
#include "mrcmsg.h"
#include "msg.h"
#include "mstream.h"
#include "msuffix.h"
#include "mmemory.h"
#include "mpreproc.h"

/*
 * This file implements something I'll call a "stream".  A stream consists
 * of a sequence of characters, and some special tokens.  The stream works
 * similar to a stack.  The caller stacks input into the stream, and GetCHR()
 * returns the next available character.
 *
 * Objects which the caller may stack consist of: files, null-terminated
 * strings, and single characters.  The corresponding routines are InsFile,
 * and InsOpenFile (for files); InsString (for strings); and UnGetCH for
 * characters.
 *
 * The caller calls GetCHR to receive the next character of input.  This
 * character is one of the standard character set (ie: ASCII) or one of the
 * special tokens.  The token of particular note is STRM_END, which is
 * similar to EOF in buffered input.  When STRM_END has been received, there
 * is no further input available in the stream.
 */

typedef enum {                  /* the different stream types           */
    SENT_FILE,
    SENT_STR,
    SENT_CHAR
} STYPE_T;


/* the most used items are at the top each union member */
typedef struct streamEntry {
    union {                     /* data required for each stream type   */
        struct {
            char    *cur;       /* next character to be read            */
            char    *max;       /* maximum position in buffer           */
            int     fh;         /* Posix i/o handle                     */
            char    *buf;       /* beginning of buffer                  */
            UINT16  line;       /* current line number                  */
            const char *name;   /* file name                            */
            size_t nestLevel;   /* nest level of the file beginning     */
        } file;                 /* for SENT_FILE                        */

        struct {
            const char    *cur; /* current position in string           */
            const char    *str; /* beginning of string                  */
        } str;                  /* for SENT_STR                         */

        STRM_T ch;              /* for SENT_CHAR                        */
    } data;

    struct streamEntry *next;   /* linked list representation of stack  */

    BIT     type : 2;           /* must hold an STYPE_T                 */
    BIT     free : 1;           /* should we free resources?            */

} SENT;


/*
 * We keep two stacks of SENTs - one is the actual stack of SENTs in use.
 * (ie: open files, pending strings...) and the other is a stack of used
 * SENTs which we will reuse as needed.  pushSENT() and popSENT() take care
 * of the details.
 *
 * Important note: headSent is the current head at all times - we pop it
 * WHEN we are done with it - we don't pop it to use it.
 */
STATIC SENT *headSent;      /* stack of sents in use    */
STATIC SENT *freeSent;      /* stack of free sents      */

STATIC int  flagEOF;

STATIC SENT *getSENT( STYPE_T type )
/***********************************
 * get a free sent, and push it into stack.  Determines next char of input.
 */
{
    SENT    *d;

    if( freeSent != NULL ) {    /* check if any free SENTs lying around */
        d = freeSent;
        freeSent = freeSent->next;
    } else {
        d = MallocSafe( sizeof( *d ) );
    }
    d->type = type;
    d->next = headSent;
    headSent = d;
    return( d );
}


STATIC void popSENT( void )
/**************************
 * pop top SENT off stack.  If necessary, close or free the apropriate things.
 */
{
    SENT    *tmp;

    assert( headSent != NULL );

    tmp = headSent;

    switch( tmp->type ) {
    case SENT_FILE:
        if( tmp->free ) {
            close( tmp->data.file.fh );
            PrtMsg( DBG | INF | LOC | FINISHED_FILE, tmp->data.file.name );
        }
        FreeSafe( tmp->data.file.buf );
        FreeSafe( (void *)headSent->data.file.name );
        break;
    case SENT_STR:
        if( tmp->free ) {
            FreeSafe( (void *)headSent->data.str.str );
        }
        break;
    case SENT_CHAR:
        break;
    }

    headSent = tmp->next;       /* advance to next SENT */
    tmp->next = freeSent;       /* push onto free stack */
    freeSent = tmp;
}


STATIC void pushFH( SENT *sent, int fh )
/***************************************
 * given an open file handle, this routine allocates a buffer, and pushes a
 * SENT onto the stack
 */
{
    assert( sent != NULL );

    sent->data.file.fh = fh;
    sent->data.file.buf = MallocSafe( FILE_BUFFER_SIZE );
    sent->data.file.cur = sent->data.file.buf;
    sent->data.file.max = sent->data.file.buf;
    sent->data.file.line = 1;
    sent->data.file.nestLevel = -1;
}


STATIC BOOLEAN fillBuffer( void )
/********************************
 * Fill the top file buffer, and reset counters
 * returns: TRUE if buffer is not empty
 *          FALSE if buffer is empty (EOF)
 */
{
    int     max;
    SENT    *tmp;   /* just to make sure optimizer will registerize this */

    assert( headSent != NULL && headSent->type == SENT_FILE );

    tmp = headSent;

    if( tmp->data.file.nestLevel == -1 ) {
        tmp->data.file.nestLevel = GetNestLevel();
    }

    tmp->data.file.cur = tmp->data.file.buf;

    max = read( tmp->data.file.fh, tmp->data.file.buf, FILE_BUFFER_SIZE - 1 );
    if( max < 0 ) {     /* 31-jul-91 DJG */
        PrtMsg( ERR | READ_ERROR, tmp->data.file.name );
        max = 0;
    } else if( max > 0 && tmp->data.file.buf[max - 1] == '\r' ) {
        /* read one more character if it ends in \r (possibly CRLF) */
        int     max2;

        max2 = read( tmp->data.file.fh, &tmp->data.file.buf[max], 1 );
        if( max2 < 0 ) {     /* 13-sep-03 BEO */
            PrtMsg( ERR | READ_ERROR, tmp->data.file.name );
            max2 = 0;
        }
        max += max2;
    }
    tmp->data.file.max = tmp->data.file.buf + max;
    return( max > 0 );
}


#ifdef __WATCOMC__
#pragma on (check_stack);
#endif
extern RET_T InsFile( const char *name, BOOLEAN envsearch )
/**********************************************************
 * Open file named name, and push it into stream.  If can't find name, it
 * tries an implicit suffix search (possibly using the env variable PATH)
 */
{
    SENT    *tmp;
    int     fh;
    char    path[_MAX_PATH];

    assert( name != NULL );

    if( TrySufPath( path, name, NULL, envsearch ) == RET_SUCCESS ) {
        PrtMsg( DBG | INF |LOC | ENTERING_FILE, path );

        fh = sopen( path, O_RDONLY | O_BINARY, SH_DENYWR );    // 04-jan-94 AFS, 13-sep-03 BEO
        if( fh == -1 ) {
            return( RET_ERROR );
        }

        tmp = getSENT( SENT_FILE );
        tmp->free = TRUE;
        tmp->data.file.name = StrDupSafe( path );

        pushFH( tmp, fh );

        if( !Glob.overide ) {
            UnGetCH( EOL );
            InsString( path, FALSE );
            InsString( "$+$(__MAKEFILES__)$- ", FALSE );
            DefMacro( "__MAKEFILES__" );
        }

        return( RET_SUCCESS );

⌨️ 快捷键说明

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