mexec.c
来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 2,143 行 · 第 1/4 页
C
2,143 行
/****************************************************************************
*
* 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 execution and inline file handling.
*
****************************************************************************/
#include <sys/types.h>
#if !defined( __UNIX__ )
#include <direct.h>
#include <dos.h>
#endif
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#if defined( __WATCOMC__ ) || !defined( __LINUX__ )
#include <process.h>
#endif
#ifdef __LINUX__
#include <sys/wait.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#ifdef DLLS_IMPLEMENTED
#include <idedrv.h>
#endif
#include "massert.h"
#include "mtypes.h"
#include "mtarget.h"
#include "macros.h"
#include "msysdep.h"
#include "make.h"
#include "mcache.h"
#include "mmemory.h"
#include "mexec.h"
#include "mmisc.h"
#include "mparse.h"
#include "mpreproc.h"
#include "mrcmsg.h"
#include "msg.h"
#include "msuffix.h"
#include "mupdate.h"
#include "mvecstr.h"
STATIC UINT8 lastErrorLevel;
STATIC UINT16 tmpFileNumber; /* temp file number */
STATIC char tmpFileChar ; /* temp file number chari */
STATIC int currentFileHandle; /* %write, %append, %create */
STATIC char *currentFileName;
enum {
FLAG_SHELL = 0x01,
FLAG_SILENT = 0x02,
FLAG_ENV_ARGS = 0x04,
FLAG_IGNORE = 0x08,
FLAG_SHELL_RC = 0x10
};
#define COM_MAX_LEN 16 /* must be able to hold any OS cmdname */
STATIC const char * const dosInternals[] = { /* COMMAND.COM commands */
#if defined( __DOS__ )
"BREAK", /* this list must be in alpha order */
"CALL",
"CD",
"CHDIR",
"CLS",
"COMMAND",
"COPY",
"CTTY",
"DATE",
"DEL",
"DIR",
"ECHO",
#define COM_ECHO 11 /* index of the echo keyword */
"ERASE",
"FOR",
#define COM_FOR 13 /* index of the for keyword */
"IF",
#define COM_IF 14 /* index of the if keyword */
"MD",
"MKDIR",
"PATH",
"PAUSE",
"PROMPT",
"RD",
"REM",
"REN",
"RENAME",
"RM",
#define COM_RM 24
"RMDIR",
"SET",
#define COM_SET 26 /* index of the set keyword */
"TIME",
"TYPE",
"VER",
"VERIFY",
"VOL"
#elif defined( __OS2__ ) || defined( __NT__ )
"BREAK",
"CALL",
"CD",
#define COM_CD 2
"CHCP",
"CHDIR",
#define COM_CHDIR 4
"CLS",
"COPY",
"DATE",
"DEL",
"DETACH",
"DIR",
"DPATH",
"ECHO",
#define COM_ECHO 12 /* index of the echo keyword */
"ENDLOCAL",
"ERASE",
"EXIT",
"EXTPROC",
"FOR",
#define COM_FOR 17
"GOTO",
"IF",
#define COM_IF 19
"MD",
"MKDIR",
"MOVE",
"PATH",
"PAUSE",
"PROMPT",
"RD",
"REM",
"REN",
"RENAME",
"RM",
#define COM_RM 30
"RMDIR",
"SET",
#define COM_SET 32
"SETLOCAL",
"SHIFT",
"START",
"TIME",
"TYPE",
"VER",
"VERIFY",
"VOL"
#elif defined( __UNIX__ )
"BREAK",
"CALL",
"CD",
#define COM_CD 2
"CHCP",
"CHDIR",
#define COM_CHDIR 4
"CLS",
"COPY",
"DATE",
"DEL",
"DETACH",
"DIR",
"DPATH",
"ECHO",
#define COM_ECHO 12 /* index of the echo keyword */
"ENDLOCAL",
"ERASE",
"EXIT",
"EXTPROC",
"FOR",
#define COM_FOR 17
"GOTO",
"IF",
#define COM_IF 19
"MD",
"MKDIR",
"PATH",
"PAUSE",
"PROMPT",
"RD",
"REM",
"REN",
"RENAME",
"RMDIR",
"SET",
#define COM_SET 30
"SETLOCAL",
"SHIFT",
"START",
"TIME",
"TYPE",
"VER",
"VERIFY",
"VOL"
#endif
};
#define CNUM (sizeof( dosInternals ) / sizeof( char * ))
static const char * const percentCmds[] = {
"ABORT",
"APPEND",
"CREATE",
"ERASE",
"MAKE",
"NULL",
"QUIT",
"REN",
"STOP",
"WRITE",
};
#define PNUM (sizeof( percentCmds ) / sizeof( char * ))
enum {
PER_ABORT,
PER_APPEND,
PER_CREATE,
PER_ERASE,
PER_MAKE,
PER_NULL,
PER_QUIT,
PER_RENAME,
PER_STOP,
PER_WRITE
};
enum write_type {
WR_WRITE,
WR_APPEND,
WR_CREATE
};
STATIC RET_T execLine( char *line ); /* called recursively in handleFor */
STATIC NKLIST *noKeepList; /* contains the list of files that
needs to be cleaned when wmake
exits */
STATIC char *createTmpFileName( void )
/*************************************
* create file name for temporary file
*/
{
VECSTR buf;
VECSTR buf2;
char *result;
char *tmpPath;
char fileName[_MAX_PATH];
tmpPath = GetMacroValue( TEMPENVVAR );
if( tmpPath == NULL && !Glob.microsoft ) {
tmpPath = getenv( TEMPENVVAR );
if( tmpPath != NULL ) {
tmpPath = StrDupSafe( tmpPath );
}
}
for( ;; ) {
tmpFileChar = tmpFileNumber % 26 + 'a' ;
buf = StartVec();
FmtStr( fileName, "wm%c%u.tmp", tmpFileChar, tmpFileNumber );
if( tmpPath != NULL ) {
if( strlen( tmpPath ) >= _MAX_PATH ) {
PrtMsg( ERR | FTL | TMP_PATH_TOO_LONG );
FreeVec( buf );
FreeSafe( tmpPath );
return( NULL );
} else if( strlen( tmpPath ) + strlen( fileName ) >= _MAX_PATH ) {
PrtMsg( ERR | FTL | TMP_PATH_TOO_LONG );
FreeSafe( tmpPath );
FreeVec( buf );
return( NULL );
}
}
if( tmpPath == NULL ) {
WriteVec( buf, fileName );
result = FinishVec( buf );
} else {
WriteVec( buf, tmpPath );
if( tmpPath[strlen( tmpPath ) - 1] != BACKSLASH ) {
buf2 = StartVec();
#if defined( __UNIX__ )
WriteVec( buf2, "/" );
#else
WriteVec( buf2, "\\" );
#endif
CatVec( buf, buf2 );
}
buf2 = StartVec();
WriteVec( buf2, fileName );
CatVec( buf, buf2 );
result = FinishVec( buf );
}
if( !existFile( result ) ) {
/* touch the file */
TouchFile( result );
FreeSafe( tmpPath );
return( result );
} else {
FreeSafe( result );
}
tmpFileNumber = (UINT16)((tmpFileNumber + time( NULL )) % 100000);
}
}
STATIC RET_T processInlineFile( int handle, const char *body,
const char *fileName, BOOLEAN writeToFile )
/***********************************************************/
{
int index;
RET_T ret;
char *DeMacroBody;
int currentSent;
BOOLEAN firstTime;
VECSTR outText;
firstTime = TRUE;
index = 0;
currentSent = 0;
ret = RET_SUCCESS;
assert( body != NULL );
// we will push the whole body back into the stream to be fully
// deMacroed
while( body [index] != NULLCHAR ) {
if( body[index] == EOL ) {
InsString( body+currentSent, FALSE );
DeMacroBody = ignoreWSDeMacro( FALSE, ForceDeMacro() );
currentSent = index + 1;
if( writeToFile ) {
size_t bytes = strlen( DeMacroBody );
if( bytes != write( handle, DeMacroBody, bytes ) ) {
ret = RET_ERROR;
}
if( 1 != write( handle, "\n", 1 ) ) {
ret = RET_ERROR;
}
} else {
if( !Glob.noheader ) {
PrtMsg( INF | NEOL | JUST_A_TAB );
}
outText = StartVec();
WriteVec( outText, "echo." );
if( DeMacroBody != NULL ) {
if( *DeMacroBody != 0 ) {
WriteVec( outText, DeMacroBody );
}
FreeSafe( DeMacroBody );
}
if( firstTime == TRUE ) {
WriteVec( outText, " > " );
firstTime = FALSE;
} else {
WriteVec( outText, " >> " );
}
WriteVec( outText, fileName );
DeMacroBody = FinishVec( outText );
PrtMsg( INF | PRNTSTR, DeMacroBody );
}
FreeSafe( DeMacroBody );
}
index++;
}
return( ret );
}
STATIC RET_T writeLineByLine( int handle, const char *body )
/**********************************************************/
{
return( processInlineFile( handle, body, NULL, TRUE ) );
}
STATIC char *RemoveBackSlash( const char *inString )
/***************************************************
* remove backslash from \"
*/
{
char buffer[_MAX_PATH];
char *current;
int pos;
assert( inString != NULL );
current = (char *)inString;
pos = 0;
while( *current != NULLCHAR && pos < _MAX_PATH - 1 ) {
if( *current == BACKSLASH ) {
if( *(current + 1) == DOUBLEQUOTE ) {
buffer[pos++] = DOUBLEQUOTE;
current = current + 2;
continue;
}
}
buffer[pos++] = *( current ++ );
}
buffer[pos] = NULLCHAR;
return( StrDupSafe( buffer ) );
}
STATIC RET_T VerbosePrintTempFile( const FLIST *head )
/****************************************************/
{
FLIST const *current;
RET_T ret = RET_SUCCESS; // success if list empty
current = head;
while( current != NULL ) {
assert( current->fileName != NULL );
ret = processInlineFile( 0, current->body, current->fileName, FALSE );
current = current->next;
}
return( ret );
}
STATIC RET_T createFile( const FLIST *head )
/*******************************************
* create file given information in the FLIST
*/
{
NKLIST *temp;
int handle;
char *fileName = NULL;
char *tmpFileName = NULL;
RET_T ret;
assert( head != NULL );
ret = RET_SUCCESS;
if( head->fileName != NULL ) {
/* Push the filename back into the stream
* and then get it back out using DeMacro to fully DeMacro
*/
UnGetCH( STRM_MAGIC );
InsString( head->fileName, FALSE );
fileName = DeMacro( STRM_MAGIC );
GetCHR(); /* eat STRM_MAGIC */
} else {
ret = RET_ERROR;
}
if( ret != RET_ERROR ) {
tmpFileName = RemoveBackSlash( fileName );
handle = open( tmpFileName, O_TEXT | O_WRONLY | O_CREAT | O_TRUNC,
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP );
if( handle != -1 ) {
if( writeLineByLine( handle, head->body ) == RET_ERROR ) {
PrtMsg( ERR | ERROR_WRITING_FILE, tmpFileName );
ret = RET_ERROR;
}
if( close( handle ) != -1 ) {
if( head->keep == FALSE ) {
temp = NewNKList();
temp->fileName = StrDupSafe( tmpFileName );
temp->next = noKeepList;
noKeepList = temp;
}
} else {
PrtMsg( ERR | ERROR_CLOSING_FILE, tmpFileName );
ret = RET_ERROR;
}
} else {
PrtMsg( ERR | ERROR_OPENING_FILE, tmpFileName );
ret = RET_ERROR;
}
}
FreeSafe( fileName );
FreeSafe( tmpFileName );
return( ret );
}
STATIC RET_T writeInlineFiles( FLIST *head, char **commandIn )
/*************************************************************
* This part writes the inline files
* modifies the command text to show the temporary file names
* assumption is that all << are removed for explicitly defined
* file names so the only << left are for temporary files
*/
{
char *cmdText;
FLIST *current;
RET_T ret;
VECSTR newCommand;
size_t start; // start of cmdText to be copied into newCommand;
size_t index; // current index of cmdText
NKLIST *temp;
assert( *commandIn != NULL );
cmdText = *commandIn;
ret = RET_SUCCESS;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?