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