#include <ctype.h>
#include "globals.h"
#include "memalloc.h"
#include "parser.h"
#include "macro.h"
#include "input.h"
#include "lqueue.h"
#include "myassert.h"
#define DETECTCTRLZ 1
#define FILESEQ 0
char *commentbuffer;
struct asym *FileCur;
struct asym *LineCur;
enum src_item_type {
SIT_FILE,
SIT_MACRO,
};
struct src_item {
struct src_item *next;
uint_8 type;
uint_16 srcfile;
union {
void *content;
FILE *file;
struct macro_instance *mi;
};
uint_32 line_num;
};
static struct src_item *SrcFree;
#define src_stack ModuleInfo.g.src_stack
#if FILESEQ
struct qdesc FileSeq;
#endif
#ifdef DEBUG_OUT
struct asm_tok *end_tokenarray;
char *end_stringbuf;
static int_32 cntflines;
static int_32 cntlines;
extern int_32 cnttok0;
extern int_32 cnttok1;
extern int_32 cntppl0;
extern int_32 cntppl1;
extern int_32 cntppl2;
#endif
static char *srclinebuffer;
char *token_stringbuf;
#if defined(__UNIX__)
#define INC_PATH_DELIM ':'
#define INC_PATH_DELIM_STR ":"
#define DIR_SEPARATOR '/'
#define filecmp strcmp
#define ISPC( x ) ( x == '/' )
#define ISABS( x ) ( *x == '/' )
#else
#define INC_PATH_DELIM ';'
#define INC_PATH_DELIM_STR ";"
#define DIR_SEPARATOR '\\'
#define filecmp _stricmp
#define ISPC( x ) ( x == '/' || x == '\\' || x == ':' )
#define ISABS( x ) ( *x == '/' || *x == '\\' || ( *x && *(x+1) == ':' && ( *(x+2) == '/' || *(x+2) == '\\' ) ) )
#endif
#if 0#endif
const char *GetFNamePart( const char *fname )
{
const char *rc;
for ( rc = fname; *fname; fname++ )
if ( ISPC( *fname ) )
rc = fname + 1;
return( rc );
}
char *GetExtPart( const char *fname )
{
char *rc;
for( rc = NULL; *fname; fname++ ) {
if( *fname == '.' ) {
rc = (char *)fname;
} else if( ISPC( *fname ) ) {
rc = NULL;
}
}
return( rc ? rc : (char *)fname );
}
static unsigned AddFile( char const *fname )
{
unsigned index;
DebugMsg1(("AddFile(%s) enter, curr index=%u\n", fname, ModuleInfo.g.cnt_fnames ));
for( index = 0; index < ModuleInfo.g.cnt_fnames; index++ ) {
if( filecmp( fname, ModuleInfo.g.FNames[index] ) == 0 ) {
return( index );
}
}
if ( ( index % 64 ) == 0 ) {
struct fname_item *newfn;
newfn = (struct fname_item *)MemAlloc( ( index + 64 ) * sizeof( struct fname_item ) );
if ( ModuleInfo.g.FNames ) {
memcpy( newfn, ModuleInfo.g.FNames, index * sizeof( struct fname_item ) );
MemFree( ModuleInfo.g.FNames );
}
ModuleInfo.g.FNames = newfn;
}
ModuleInfo.g.cnt_fnames++;
ModuleInfo.g.FNames[index] = (char *)LclAlloc( strlen( fname ) + 1 );
strcpy( ModuleInfo.g.FNames[index], fname );
return( index );
}
const struct fname_item *GetFName( unsigned index )
{
return( ModuleInfo.g.FNames+index );
}
static void FreeFiles( void )
{
#if FASTMEM==0
int i;
src_stack->next = SrcFree;
SrcFree = src_stack;
#endif
src_stack = NULL;
#if FASTMEM==0
while ( SrcFree ) {
struct src_item *next;
next = SrcFree->next;
LclFree( SrcFree );
SrcFree = next;
};
for ( i = 0; i < ModuleInfo.g.cnt_fnames; i++ ) {
LclFree( ModuleInfo.g.FNames[i].fname );
}
#endif
if ( ModuleInfo.g.FNames ) {
MemFree( ModuleInfo.g.FNames );
ModuleInfo.g.FNames = NULL;
}
return;
}
void ClearSrcStack( void )
{
struct src_item *nextfile;
DeleteLineQueue();
for( ; src_stack->next ; src_stack = nextfile ) {
nextfile = src_stack->next;
if ( src_stack->type == SIT_FILE ) {
fclose( src_stack->file );
}
src_stack->next = SrcFree;
SrcFree = src_stack;
}
return;
}
void UpdateLineNumber( struct asym *sym, void *p )
{
struct src_item *curr;
for ( curr = src_stack; curr ; curr = curr->next )
if ( curr->type == SIT_FILE ) {
sym->value = curr->line_num;
break;
}
return;
}
uint_32 GetLineNumber( void )
{
UpdateLineNumber( LineCur, NULL );
return( LineCur->uvalue );
}
#ifdef DEBUG_OUT
extern unsigned GetLqLine( void );
char *GetTopLine( char *buffer )
{
*buffer = NULLC;
if ( ModuleInfo.GeneratedCode )
sprintf( buffer, "(%u)", GetLqLine() );
else if( src_stack->type == SIT_MACRO )
sprintf( buffer, "[%s.%" I32_SPEC "u]", src_stack->mi->macro->name, src_stack->line_num );
return( buffer );
}
char *GetTopSrcName( void )
{
if ( src_stack->type == SIT_MACRO )
return( src_stack->mi->macro->name );
return( GetFName( src_stack->srcfile )->fname );
}
#endif
static char *my_fgets( char *buffer, int max, FILE *fp )
{
char *ptr = buffer;
char *last = buffer + max;
int c;
c = getc( fp );
while( ptr < last ) {
switch ( c ) {
case '\r':
break;
case '\n':
#ifdef DEBUG_OUT
if ( Parse_Pass == PASS_1 )
cntflines++;
#endif
*ptr = NULLC;
return( buffer );
#if DETECTCTRLZ
case 0x1a:
#endif
case EOF:
*ptr = NULLC;
return( ptr > buffer ? buffer : NULL );
default:
*ptr++ = c;
}
c = getc( fp );
}
EmitErr( LINE_TOO_LONG );
*(ptr-1) = NULLC;
return( buffer );
}
#if FILESEQ
void AddFileSeq( unsigned file )
{
struct file_seq *node;
node = LclAlloc( sizeof( struct file_seq ) );
node->next = NULL;
node->file = file;
if ( FileSeq.head == NULL )
FileSeq.head = FileSeq.tail = node;
else {
((struct file_seq *)FileSeq.tail)->next = node;
FileSeq.tail = node;
}
}
#endif
struct src_item *PushSrcItem( char type, void *pv )
{
struct src_item *curr;
if ( SrcFree ) {
curr = SrcFree;
SrcFree = curr->next;
} else
curr = LclAlloc( sizeof( struct src_item ) );
curr->next = src_stack;
src_stack = curr;
curr->type = type;
curr->content = pv;
curr->line_num = 0;
return( curr );
}
void PushMacro( struct macro_instance *mi )
{
DebugMsg1(( "PushMacro(%s)\n", mi->macro->name ));
PushSrcItem( SIT_MACRO, mi );
return;
}
#if FASTMEM==0
bool MacroInUse( struct dsym *macro )
{
struct src_item *curr;
for ( curr = src_stack; curr ; curr = curr->next )
if ( curr->type == SIT_MACRO && curr->mi->macro == ¯o->sym )
return( TRUE );
return( FALSE );
}
#endif
unsigned get_curr_srcfile( void )
{
struct src_item *curr;
for ( curr = src_stack; curr ; curr = curr->next )
if ( curr->type == SIT_FILE )
return( curr->srcfile );
return( ModuleInfo.srcfile );
}
#if FASTPASS
void set_curr_srcfile( unsigned file, uint_32 line_num )
{
if ( file != 0xFFF )
src_stack->srcfile = file;
src_stack->line_num = line_num;
return;
}
#endif
void SetLineNumber( unsigned line )
{
src_stack->line_num = line;
return;
}
int GetCurrSrcPos( char *buffer )
{
struct src_item *curr;
for( curr = src_stack; curr; curr = curr->next ) {
if ( curr->type == SIT_FILE ) {
return( sprintf( buffer, ModuleInfo.EndDirFound == FALSE ? "%s(%" I32_SPEC "u) : " : "%s : ", GetFName( curr->srcfile )->fname , curr->line_num ) );
}
}
*buffer = NULLC;
return( 0 );
}
void print_source_nesting_structure( void )
{
struct src_item *curr;
unsigned tab = 1;
if ( src_stack == NULL || src_stack->next == NULL )
return;
for( curr = src_stack; curr->next ; curr = curr->next ) {
if( curr->type == SIT_FILE ) {
PrintNote( NOTE_INCLUDED_BY, tab, "", GetFName( curr->srcfile )->fname, curr->line_num );
tab++;
} else {
if (*(curr->mi->macro->name) == NULLC ) {
PrintNote( NOTE_ITERATION_MACRO_CALLED_FROM, tab, "", "MacroLoop", curr->line_num, curr->mi->macro->value + 1 );
} else {
PrintNote( NOTE_MACRO_CALLED_FROM, tab, "", curr->mi->macro->name, curr->line_num, GetFNamePart( GetFName(((struct dsym *)curr->mi->macro)->e.macroinfo->srcfile)->fname ) ) ;
}
tab++;
}
}
PrintNote( NOTE_MAIN_LINE_CODE, tab, "", GetFName( curr->srcfile )->fname, curr->line_num );
}
static FILE *open_file_in_include_path( const char *name, char fullpath[] )
{
char *curr;
char *next;
int i;
int namelen;
FILE *file = NULL;
while( isspace( *name ) )
name++;
curr = ModuleInfo.g.IncludePath;
namelen = strlen( name );
DebugMsg(("open_file_in_include_path(%s) enter\n", name ));
for ( ; curr; curr = next ) {
next = strchr( curr, INC_PATH_DELIM );
if ( next ) {
i = next - curr;
next++;
} else {
i = strlen( curr );
}
if ( i == 0 || ( ( i + namelen ) >= FILENAME_MAX ) )
continue;
memcpy( fullpath, curr, i );
if( fullpath[i-1] != '/'
#if !defined(__UNIX__)
&& fullpath[i-1] != '\\' && fullpath[i-1] != ':'
#endif
) {
fullpath[i] = DIR_SEPARATOR;
i++;
}
strcpy( fullpath+i, name );
DebugMsg(("open_file_in_include_path: >%s<\n", fullpath ));
file = fopen( fullpath, "rb" );
if( file ) {
break;
}
}
DebugMsg(("open_file_in_include_path()=%p\n", file ));
return( file );
}
FILE *SearchFile( const char *path, bool queue )
{
FILE *file = NULL;
struct src_item *fl;
const char *fn;
bool isabs;
char fullpath[FILENAME_MAX];
DebugMsg1(("SearchFile(%s) enter\n", path ));
fn = GetFNamePart( path );
isabs = ISABS( path );
if ( !isabs ) {
for ( fl = src_stack; fl ; fl = fl->next ) {
if ( fl->type == SIT_FILE ) {
const char *fn2;
char *src;
src = GetFName( fl->srcfile )->fname;
fn2 = GetFNamePart( src );
if ( fn2 != src ) {
int i = fn2 - src;
memcpy( fullpath, src, i );
strcpy( fullpath + i, path );
if ( file = fopen( fullpath, "rb" ) ) {
DebugMsg1(("SearchFile(): file found, fopen(%s)=%X\n", fullpath, file ));
path = fullpath;
if(file)
setvbuf( file, NULL, _IOFBF, 4096*4 );
}
#ifdef DEBUG_OUT
else
DebugMsg1(("SearchFile(): fopen(%s) failed\n", fullpath ));
#endif
}
break;
}
}
}
if ( file == NULL ) {
fullpath[0] = NULLC;
file = fopen( path, "rb" );
if(file)
setvbuf(file, NULL, _IOFBF, 4096*4 );
DebugMsg1(("SearchFile(): fopen(%s)=%X\n", path, file ));
if( file == NULL && ModuleInfo.g.IncludePath != NULL && !isabs ) {
if ( file = open_file_in_include_path( path, fullpath ) ) {
DebugMsg1(("SearchFile(): open_file_in_include_path(%s)=%X [%s]\n", path, file, fullpath ));
path = fullpath;
}
#ifdef DEBUG_OUT
else
DebugMsg1(("SearchFile(): open_file_in_include_path(%s)=NULL\n", path ));
#endif
}
if( file == NULL ) {
EmitErr( CANNOT_OPEN_FILE, path, ErrnoStr() );
return( NULL );
}
}
if ( queue ) {
fl = PushSrcItem( SIT_FILE, file );
fl->srcfile = AddFile( path );
FileCur->string_ptr = GetFName( fl->srcfile )->fname;
#if FILESEQ
if ( Options.line_numbers && Parse_Pass == PASS_1 )
AddFileSeq( fl->srcfile );
#endif
}
return( file );
}
char *GetTextLine( char *buffer )
{
struct src_item *curr = src_stack;
if ( curr->type == SIT_FILE ) {
if( my_fgets( buffer, MAX_LINE_LEN, curr->file ) ) {
curr->line_num++;
#ifdef DEBUG_OUT
if ( Parse_Pass == PASS_1 ) cntlines++;
#endif
return( buffer );
}
if ( curr->next ) {
fclose( curr->file );
src_stack = curr->next;
curr->next = SrcFree;
SrcFree = curr;
}
for( curr = src_stack; curr->type != SIT_FILE; curr = curr->next );
FileCur->string_ptr = GetFName( curr->srcfile)->fname;
#if FILESEQ
if ( Options.line_numbers && Parse_Pass == PASS_1 )
AddFileSeq( curr->srcfile );
#endif
} else {
curr->mi->currline = ( curr->mi->currline ? curr->mi->currline->next : curr->mi->startline );
if ( curr->mi->currline ) {
if ( curr->mi->currline->ph_count ) {
fill_placeholders( buffer,
curr->mi->currline->line,
curr->mi->parmcnt,
curr->mi->localstart, curr->mi->parm_array );
} else {
strcpy( buffer, curr->mi->currline->line );
}
curr->line_num++;
#ifdef DEBUG_OUT
if ( Parse_Pass == PASS_1 ) cntlines++;
#endif
return( buffer );
}
src_stack = curr->next;
curr->next = SrcFree;
SrcFree = curr;
}
return( NULL );
}
void AddStringToIncludePath( const char *string )
{
char *tmp;
int len;
DebugMsg(("AddStringToIncludePath(%s) enter\n", string ));
while( isspace( *string ) )
string++;
len = strlen( string );
if ( len == 0 )
return;
if( ModuleInfo.g.IncludePath == NULL ) {
ModuleInfo.g.IncludePath = MemAlloc( len + 1 );
strcpy( ModuleInfo.g.IncludePath, string );
} else {
tmp = ModuleInfo.g.IncludePath;
ModuleInfo.g.IncludePath = MemAlloc( strlen( tmp ) + sizeof( INC_PATH_DELIM_STR ) +
len + 1 );
strcpy( ModuleInfo.g.IncludePath, tmp );
strcat( ModuleInfo.g.IncludePath, INC_PATH_DELIM_STR );
strcat( ModuleInfo.g.IncludePath, string );
MemFree( tmp );
}
}
#if 0#endif
#ifdef __I86__
#define SIZE_SRCLINES ( MAX_LINE_LEN * 2 )
#define SIZE_TOKENARRAY ( sizeof( struct asm_tok ) * MAX_TOKEN )
#define SIZE_STRINGBUFFER ( MAX_LINE_LEN * 2 )
#else
#define SIZE_SRCLINES ( MAX_LINE_LEN * ( MAX_MACRO_NESTING + 1 ) )
#define SIZE_TOKENARRAY ( sizeof( struct asm_tok ) * MAX_TOKEN * MAX_MACRO_NESTING )
#define SIZE_STRINGBUFFER ( MAX_LINE_LEN * MAX_MACRO_NESTING )
#endif
struct asm_tok *PushInputStatus( struct input_status *oldstat )
{
oldstat->token_stringbuf = token_stringbuf;
oldstat->token_count = Token_Count;
oldstat->currsource = CurrSource;
if ( ModuleInfo.CurrComment ) {
int i = strlen( CurrSource );
oldstat->CurrComment = CurrSource + i;
strcpy( oldstat->CurrComment, ModuleInfo.CurrComment );
} else
oldstat->CurrComment = NULL;
oldstat->line_flags = ModuleInfo.line_flags;
token_stringbuf = StringBufferEnd;
ModuleInfo.tokenarray += Token_Count + 1;
CurrSource = GetAlignedPointer( CurrSource, strlen( CurrSource ) );
return( ModuleInfo.tokenarray );
}
void PopInputStatus( struct input_status *newstat )
{
StringBufferEnd = token_stringbuf;
token_stringbuf = newstat->token_stringbuf;
Token_Count = newstat->token_count;
CurrSource = newstat->currsource;
if ( newstat->CurrComment ) {
ModuleInfo.CurrComment = commentbuffer;
strcpy( ModuleInfo.CurrComment, newstat->CurrComment );
*newstat->CurrComment = NULLC;
} else
ModuleInfo.CurrComment = NULL;
ModuleInfo.tokenarray -= Token_Count + 1;
ModuleInfo.line_flags = newstat->line_flags;
return;
}
void InputInit( void )
{
struct src_item *fl;
SrcFree = NULL;
#if FILESEQ
FileSeq.head = NULL;
#endif
srclinebuffer = LclAlloc( SIZE_SRCLINES + SIZE_TOKENARRAY + SIZE_STRINGBUFFER );
commentbuffer = srclinebuffer + SIZE_SRCLINES - MAX_LINE_LEN;
ModuleInfo.tokenarray = (struct asm_tok *)( srclinebuffer + SIZE_SRCLINES );
token_stringbuf = srclinebuffer + SIZE_SRCLINES + SIZE_TOKENARRAY;
fl = PushSrcItem( SIT_FILE, CurrFile[ASM] );
fl->srcfile = ModuleInfo.srcfile = AddFile( CurrFName[ASM] );
FileCur->string_ptr = GetFName( fl->srcfile )->fname;
}
void InputPassInit( void )
{
src_stack->line_num = 0;
CurrSource = srclinebuffer;
*CurrSource = NULLC;
StringBufferEnd = token_stringbuf;
return;
}
void InputFini( void )
{
if ( ModuleInfo.g.IncludePath )
MemFree( ModuleInfo.g.IncludePath );
FreeFiles();
ModuleInfo.tokenarray = NULL;
LclFree( srclinebuffer );
}