mexec.c

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

C
2,143
字号
    newCommand = StartVec();
    WriteVec( newCommand, "" );
    index      = 0;
    start      = index;
    current    = head;

    while( current != NULL && ret == RET_SUCCESS &&
           cmdText[index] != NULLCHAR ) {
        // if the filename is the inline symbol then we need change
        // the filename into a temp filename
        if( strcmp( current->fileName, INLINE_SYMBOL ) == 0 ) {
            for( ;; ) {
                if( cmdText[index] == LESSTHAN ) {
                    if( cmdText[index + 1] == LESSTHAN ) {
                        index += 2;
                        break;
                    }
                } else if( cmdText[index] == NULLCHAR ) {
                    /* not possible to come here*/
                    ret = RET_ERROR;
                    break;
                }
                ++index;
            }
            if( ret == RET_ERROR ) {
                break;
            }
            CatNStrToVec( newCommand, cmdText+start, index-start-2 );
            start = index;
            FreeSafe( current->fileName );
            current->fileName = createTmpFileName();

            CatStrToVec( newCommand, current->fileName );
        }
        if( !Glob.noexec ) {
            ret = createFile( current );
        } else {
            if( current->keep == FALSE ) {
                temp = NewNKList();
                temp->fileName = StrDupSafe( current->fileName );
                temp->next     = noKeepList;
                noKeepList     = temp;
            }
        }
        current = current->next;
    }
    CatNStrToVec( newCommand, cmdText+start, strlen( cmdText ) - start );
    FreeSafe( cmdText );
    *commandIn = FinishVec( newCommand );
    return( ret );
}


STATIC int findInternal( const char *cmd )
/*****************************************
 * check cmd for command.com command, return index if it is
 * return CNUM if is of form x:
 * otherwise return -1
 * expects cmd to be just the command - ie: no args
 */
{
    char * const    *key;
    size_t          len;
    char            buff[COM_MAX_LEN];

    assert( cmd != NULL );
    /* test if of form x: */
    if( isalpha( *cmd ) && cmd[1] == ':' && cmd[2] == NULLCHAR ) {
        return( CNUM );
    }
    for( ;; ) {
        key = bsearch( &cmd, dosInternals, CNUM, sizeof( char * ),
              (int (*)( const void *, const void * ))KWCompare );
        if( key != NULL ) {
            break;
        }
        len = strlen( cmd );
        if( len > 1 && len < COM_MAX_LEN ) {
            if( cmd[len - 1] == '.' ) {
                // should work if buff == cmd (i.e., cd..)
                strcpy( buff, cmd );
                buff[len - 1] = '\0';
                cmd = buff;
                continue;
            }
        }
        return( -1 );
    }
    return( key - (char **)dosInternals );
}


STATIC RET_T percentMake( char *arg )
/************************************
 * do a recursive make of the target in arg
 */
{
    TARGET      *calltarg;
    RET_T       ret;
    char        *buf;
    char        *start;
    char        *finish;
    BOOLEAN     newtarg;
    BOOLEAN     more_targets;

    /* %make <target> <target> ... */
    buf = MallocSafe( _MAX_PATH );

    ret = RET_ERROR;
    start = arg;
    for( ;; ) {
        start = SkipWS( start );
        if( *start == NULLCHAR ) {
            break;
        }
        more_targets = FALSE;
        finish = start;
        for( ;; ) {
            if( *finish == NULLCHAR ) {
                break;
            }
            if( isws( *finish ) ) {
                more_targets = TRUE;
                *finish = NULLCHAR;
                break;
            }
            ++finish;
        }

        /* try to find this file on path or in targets */
        ret = TrySufPath( buf, start, &calltarg, FALSE );

        newtarg = FALSE;
        if( ( ret == RET_SUCCESS && calltarg == NULL ) || ret == RET_ERROR ) {
            /* Either file doesn't exist, or it exists and we don't already
             * have a target for it.  Either way, we create a new target.
             */
            calltarg = NewTarget( buf );
            newtarg = TRUE;
        }
        ret = Update( calltarg );
        if( newtarg && Glob.noexec == FALSE ) {
            /* we created a target - don't need it any more */
            KillTarget( calltarg->node.name );
        }
        if( more_targets ) {
            *finish = ' ';
        }
        start = finish;
    }
    FreeSafe( buf );

    return( ret );
}


STATIC void closeCurrentFile( void )
/**********************************/
{
    if( currentFileHandle != -1 ) {
        close( currentFileHandle );
    }
    if( currentFileName != NULL ) {
        FreeSafe( currentFileName );
        currentFileName = NULL;
    }
    CacheRelease();     /* so that the cache is updated */
}


STATIC RET_T percentWrite( char *arg, enum write_type type )
/**********************************************************/
{
    char        *p;
    char const  *text;
    char        *fn;
    char const  *cmd_name;
    int         open_flags;
    size_t      len;

    assert( arg != NULL );

    if( Glob.noexec ) {
        return( RET_SUCCESS );
    }

    p = SkipWS( arg );
    fn = p;

    if( *p != DOUBLEQUOTE ) {
        while( isfilec( *p ) ) {
            ++p;
        }
    } else {
        ++p;    // Skip the first quote
        ++fn;
        while( *p!= DOUBLEQUOTE && *p!= NULLCHAR ) {
             ++p;
        }
        if( *p!= NULLCHAR ) {
            *p = NULLCHAR;
            p++;
        }
    }

    if( *p != NULLCHAR ) {
        if( !isws( *p ) ) {
            switch( type ) {
            case WR_APPEND:
                cmd_name = percentCmds[PER_APPEND];
                break;
            case WR_CREATE:
                cmd_name = percentCmds[PER_CREATE];
                break;
            case WR_WRITE:
                cmd_name = percentCmds[PER_WRITE];
                break;
            default:
                cmd_name = "?";
                break;
            }
            PrtMsg( ERR | SYNTAX_ERROR_IN, cmd_name );
            closeCurrentFile();
            return( RET_ERROR );
        }
        *p = '\0';          /* terminate file name */
        ++p;
        text = p;           /* set text pointer */
        p += strlen( p );   /* find null terminator */
    } else {
        *p = '\0';          /* terminate file name */
        text = p;           /* set text pointer */
    }

    /* now text points to the beginning of string to write, and p points to
     * the end of the string.  fn points to the name of the file to write to
     */
    FixName( fn );
    if( type == WR_CREATE || currentFileName == NULL ||
                             FNameCmp( currentFileName, fn ) != 0 ) {
        closeCurrentFile();
        currentFileName = StrDupSafe( fn );
        open_flags = O_WRONLY | O_CREAT | O_TEXT;
        if( type == WR_APPEND ) {
            open_flags |= O_APPEND;
        } else {
            open_flags |= O_TRUNC;
        }

        currentFileHandle = open( fn, open_flags, S_IWRITE | S_IREAD );
        if( currentFileHandle == -1 ) {
            PrtMsg( ERR | OPENING_FOR_WRITE, fn );
            closeCurrentFile();
            return( RET_ERROR );
        }
    }

    if( type != WR_CREATE ) {
        *p = '\n';          /* replace null terminator with newline */
        len = (p - text) + 1;
        if( write( currentFileHandle, text, len ) != len ) {
            PrtMsg( ERR | DOING_THE_WRITE );
            closeCurrentFile();
            return( RET_ERROR );
        }
    }

    CacheRelease();     /* so that the cache is updated */

    return( RET_SUCCESS );
}


STATIC RET_T percentErase( char *arg )
/************************************/
{
    if( 0 == unlink( FixName( arg ) ) ) {
        return( RET_SUCCESS );
    }
    return( RET_ERROR );
}

STATIC RET_T percentRename( char *arg )
/************************************/
{
    char        *p;
    char        *fn1, *fn2;

    assert( arg != NULL );

    if( Glob.noexec ) {
        return( RET_SUCCESS );
    }

    /* Get first file name, must end in space but may be surrounded by double quotes */
    p = SkipWS( arg );
    fn1 = p;
    if( *p != DOUBLEQUOTE ) {
        while( isfilec( *p ) ) {
            ++p;
        }
    } else {
        ++p;    // Skip the first quote
        ++fn1;
        while( *p!= DOUBLEQUOTE && *p!= NULLCHAR ) {
             ++p;
        }
        if( *p!= NULLCHAR ) {
            *p = NULLCHAR;
            p++;
        }
    }

    if( *p == NULLCHAR || !isws( *p ) ) {
        PrtMsg( ERR | SYNTAX_ERROR_IN, percentCmds[PER_RENAME] );
        PrtMsg( INF | PRNTSTR, "First file" );
        PrtMsg( INF | PRNTSTR, p );
        return( RET_ERROR );
    }
    *p = '\0';              /* terminate first file name */
    ++p;

    /* Get second file name as well */
    p = SkipWS( p );
    fn2 = p;
    if( *p != DOUBLEQUOTE ) {
        while( isfilec( *p ) ) {
            ++p;
        }
    } else {
        ++p;    // Skip the first quote
        ++fn2;
        while( *p!= DOUBLEQUOTE && *p!= NULLCHAR ) {
             ++p;
        }
        if( *p!= NULLCHAR ) {
            *p = NULLCHAR;
            p++;
        }
    }

    if( *p != NULLCHAR && !isws( *p ) ) {
        PrtMsg( ERR | SYNTAX_ERROR_IN, percentCmds[PER_RENAME] );
        return( RET_ERROR );
    }
    *p = '\0';              /* terminate second file name */
    if( rename( fn1, fn2 )  == 0)
        return( RET_SUCCESS );
    else
        return( RET_ERROR );
}

STATIC RET_T percentCmd( const char *cmdname, char *arg )
/********************************************************
 * handle our special percent commands
 */
{
    char const * const  *key;
    char const          *ptr;
    int                 num;

    assert( cmdname != NULL && arg != NULL );

    ptr = cmdname + 1;
    key = bsearch( &ptr, percentCmds, PNUM, sizeof( char * ),
          (int (*)( const void*, const void* ))KWCompare );

    if( key == NULL ) {
        PrtMsg( ERR | UNKNOWN_PERCENT_CMD );
        closeCurrentFile();
        return( RET_ERROR );
    } else {
        num = key - (char const **)percentCmds;
    }

    if( Glob.noexec && num != PER_MAKE ) {
        return( RET_SUCCESS );
    }

    switch( num ) {
    case PER_ABORT:
        closeCurrentFile();
        exit( ExitSafe( EXIT_ERROR ) );

    case PER_APPEND:
        return( percentWrite( arg, WR_APPEND ) );

    case PER_CREATE:
        return( percentWrite( arg, WR_CREATE ) );

    case PER_ERASE:
        return( percentErase( arg ) );

    case PER_MAKE:
        return( percentMake( arg ) );

    case PER_NULL:
        break;

    case PER_QUIT:
        closeCurrentFile();
        exit( ExitSafe( EXIT_OK ) );

    case PER_RENAME:
        return( percentRename( arg ) );

    case PER_STOP:
        closeCurrentFile();
        if( !GetYes( DO_YOU_WISH_TO_CONT ) ) {
            exit( ExitSafe( EXIT_OK ) );
        }
        break;

    case PER_WRITE:
        return( percentWrite( arg, WR_WRITE ) );

    default:
        assert( FALSE );
        break;
    };

    return( RET_SUCCESS );
}

#ifdef __LINUX__
STATIC int intSystem( const char *cmd )
/**************************************
 * interruptable "system" (so that ctrl-c works)
 */
{
    pid_t   pid = fork();
    int     status;

    if( pid == -1 ) {
        return( -1 );
    }
    if( pid == 0 ) {
        execl( "/bin/sh", "sh", "-c", cmd, NULL );
        exit( 127 );
    }
    for( ;; ) {
        if( waitpid( pid, &status, 0 ) == -1 ) {
            if( errno == EINTR ) {
                continue;
            }
            status = -1;
        } else if( WIFSIGNALED( status ) ) {
            if( WTERMSIG( status ) > 0 && WTERMSIG( status ) <= 15 ) {
                PrtMsg( INF | (SIG_ERR_0 + WTERMSIG( status ) ) );
            } else {
                PrtMsg( INF | SIG_ERR_0, WTERMSIG( status ) );
            }
        }
        CheckForBreak();
        return( status );
    }
}
#endif

STATIC RET_T mySystem( const char *cmdname, const char *cmd )
/************************************************************
 * execute a command using system()
 */
{
    int retcode;

    assert( cmd != NULL );

    if( Glob.noexec ) {
        return( RET_SUCCESS );
    }

    closeCurrentFile();
#ifdef __LINUX__
    retcode = intSystem( cmd );
#else
    retcode = system( cmd );
#endif
    lastErrorLevel = (UINT8)retcode;
    if( retcode < 0 ) {
        PrtMsg( ERR | UNABLE_TO_EXEC, cmdname );
    }
    if( retcode != 0 ) {
        return( RET_ERROR );
    }
    return( RET_SUCCESS );
}


STATIC RET_T handleSet( char *cmd )
/**********************************
 * "SET" {ws}* <name> {ws}* "="[<value>]
 */
{
    char        *p;         /* we walk cmd with this        */
    char        *name;      /* beginning of variable name   */
    char        *endname;   /* end of name                  */
    ENV_TRACKER *env;       /* space allocated for envvar   */
    int         retcode;    /* from putenv                  */

    assert( cmd != NULL );

#ifdef DEVELOPMENT
    PrtMsg( DBG | INF | INTERPRETING, dosInternals[COM_SET] );
#endif

    if( Glob.noexec ) {
        return( RET_SUCCESS );
    }

    p = SkipWS( cmd + 3 );      /* find first non-ws after "SET" */

    if( *p == NULLCHAR ) {      /* just "SET" with no options... pass on */
        return( mySystem( cmd, cmd ) );
    }

    /* anything goes in a dos set name... even punctuation! */
    name = p;
    while( *p != NULLCHAR && !isws( *p ) && *p != '=' ) {
        ++p;
    }
    endname = p;

    p = SkipWS( p );            /* trim ws after name */

    if( *p != '=' || endname == name ) {
        PrtMsg( ERR | SYNTAX_ERROR_IN, dosInternals[COM_SET] );
        return( RET_ERROR );
    }

    *endname = NULLCHAR;        /* null terminate name */

    ++p;                        /* advance to character after '=' */

                        /* +1 for '=' (already +1 for '\0' in ENV_TRACKER) */
    env = MallocSafe( sizeof( *env ) + 1 + (endname - name) + strlen( p ) );

⌨️ 快捷键说明

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