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