cmdutils.c

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

C
1,253
字号
    return( tostring() );
}

#define IS_WHITESPACE(ptr) (*(ptr) == ' ' || *(ptr) =='\t' || *(ptr) == '\r')

static void ExpandEnvVariable( void )
/***********************************/
/* parse the specified environment variable & deal with it */
{
    char *  envname;
    char *  env;
    char *  buff;
    size_t  envlen;

    Token.next++;
    if( !MakeToken( TOK_INCLUDE_DOT, SEP_PERCENT ) ) {
        LnkMsg( LOC+LINE+FTL+MSG_ENV_NAME_INCORRECT, NULL );
    }
    envname = tostring();
    env = GetEnvString( envname );
    if( env == NULL ) {
        LnkMsg( LOC+LINE+WRN+MSG_ENV_NOT_FOUND, "s", envname );
        _LnkFree( envname );
    } else {
        envlen = strlen( env );
        if( !IS_WHITESPACE( Token.next ) ) {
            MakeToken( TOK_INCLUDE_DOT, SEP_SPACE );
            _ChkAlloc( buff, envlen + Token.len + 1);
            memcpy( buff, env, envlen );
            memcpy( buff + envlen, Token.this, Token.len );
            buff[ Token.len + envlen ] = '\0';
        } else {
            _ChkAlloc( buff, envlen + 1 );
            memcpy( buff, env, envlen );
            buff[ envlen ] = '\0';
        }
        NewCommandSource( envname, buff, ENVIRONMENT );
    }
}

static bool CheckFence()
/**********************/
/* check for a "fence", and skip it if it is there */
{
    if( Token.thumb == REJECT ) {
        if( Token.quoted ) return( FALSE );   /* no fence inside quotes */
        if( *Token.this == '}' ) {
            Token.this++;
            return TRUE;
        }
    } else {
        return GetToken( SEP_RCURLY, 0 );
    }
    return FALSE;
}

extern bool GetToken( sep_type req, tokcontrol ctrl)
{
    return(GetTokenEx(req, ctrl, NULL, NULL));
}

extern bool GetTokenEx( sep_type req, tokcontrol ctrl, cmdfilelist *resetpoint, bool * pbreset)
/***************************************************/
/* return TRUE if no problem */
/* return FALSE if problem   */
{
    char    hmm;
    bool    ret;
    bool    need_sep;

    if( Token.thumb == REJECT ) {
        Token.thumb = OK;
        if( Token.quoted ) return( TRUE );
        Token.next = Token.this;        /* re-process last token */
    }
    need_sep = TRUE;
    for(;;) {                           /* finite state machine */

        /*
        //  carl.young
        //  We had a situation where an input file (in this case a Novell
        //  import or export file) does not have the consistent format
        //  expected from this FSM code. If the skipToNext flag is set,
        //  then we just skip to the next token and return rather than
        //  reporting an error.
        //  For reference the import files looked like:
        //      (PREFIX)
        //          symbol1,
        //          symbol2,
        //          symbolnm1,
        //          symboln
        //
        //  Note the missing comma separator after the prefix token. The
        //  prefix token(s) may also appear anywhere in the file.
        */

        if( (Token.skipToNext) && (req == SEP_COMMA) ) {
            Token.skipToNext = 0;
            need_sep = FALSE;
        }

        switch( Token.where ) {
        case MIDST:
            EatWhite();
            hmm = *Token.next;
            switch( hmm ) {
            case CTRLZ:
                Token.where = ENDOFFILE;
                break;
            case '\0':
                if( Token.how == BUFFERED
                 || Token.how == ENVIRONMENT
                 || Token.how == SYSTEM ) {
                    Token.where = ENDOFFILE;
                    break;
                }                // NOTE the fall through.
            case '\n':
                if( Token.how == BUFFERED
                 || Token.how == ENVIRONMENT
                 || Token.how == SYSTEM ) {
                    Token.next++;               // just skip this.
                } else if( Token.how == COMMANDLINE ) {
                    Token.where = ENDOFCMD;
                } else {
                    Token.where = ENDOFLINE;
                }
                Token.line++;
                break;
            case '@':
                if( req != SEP_SPACE ) {
                    Token.next++;
                    GetToken( SEP_NO, TOK_INCLUDE_DOT|TOK_IS_FILENAME );
                    StartNewFile();
                    break;
                }
                Token.next--;   /* make a token out of this */
                ret = MakeToken( ctrl, req );
                Token.quoted = FALSE;
                return( ret );
            case '#':
                Token.where = ENDOFLINE;            /* begin comment */
                Token.line++;
                break;
            case '^':
                if( req != SEP_SPACE ) {    /* if not storing system blocks */
                    Token.next++;
                    BackupParser();
                    break;
                }
                Token.next--;   /* make a token out of this */
                ret = MakeToken( ctrl, req );
                Token.quoted = FALSE;
                return( ret );
            case '%':
                if( req != SEP_SPACE ) {
                    ExpandEnvVariable();
                    break;
                }
            default:
                if( need_sep ) {
                    Token.quoted = FALSE;
                    switch( req ) {
                    case SEP_NO:
                        if( hmm == ',' || hmm == '=' ) return( FALSE );
                        break;
                    case SEP_COMMA:
                        if(hmm != ',' ) return( FALSE);
                        Token.next++;
                        break;
                    case SEP_EQUALS:
                        if( hmm != '=' ) return( FALSE );
                        Token.next++;
                        break;
                    case SEP_PERIOD:
                    case SEP_DOT_EXT:
                        if( hmm != '.' ) return( FALSE );
                        Token.next++;
                        break;
                    case SEP_PAREN:
                        if( hmm != '(' ) return( FALSE );
                        Token.next++;
                        break;
                    case SEP_LCURLY:
                        if( hmm != '{' ) return( FALSE );
                        Token.next++;
                        break;
                    case SEP_QUOTE:
                        if( hmm != '\'' ) return FALSE;
                        Token.next++;
                        Token.quoted = TRUE;
                        break;
                    case SEP_RCURLY:
                        if( hmm != '}' ) return( FALSE );
                        Token.next++;
                        return( TRUE );
                    case SEP_END:
                        return( FALSE );
                    }
                    need_sep = FALSE;
                    EatWhite();
                } else {                /*  must have good separator here */
                    if( hmm == '\'' && req != SEP_PAREN && req != SEP_SPACE ) {
                        req = SEP_QUOTE;   /* token has been quoted */
                        Token.next++;      /* don't include the quote */
                        Token.quoted = TRUE;
                    }
                    ret = MakeToken( ctrl, req );
                    return( ret );
                }
                break;
            }
            break;
        case ENDOFLINE:
            GetNewLine();
            break;
        case ENDOFFILE:
            if( Token.locked ) return( FALSE );
            RestoreCmdLine();
            if( Token.thumb == REJECT ) {
                Token.thumb = OK;
                Token.next = Token.this;        /* re-process last token */
            }
            Token.quoted = FALSE;
            if( resetpoint && (CmdFile == resetpoint) ) {
                if( *Token.next == ',' )
                    break;
                if( pbreset )
                    *pbreset = TRUE;            /* Show we have hit a file end-point for a directive */
                return FALSE;
            }
            break;
        case ENDOFCMD:
            if( CmdFile->next != NULL ) {
                RestoreParser();
                break;
            }
            Token.quoted = FALSE;
            ret = ( req == SEP_END ) ? TRUE : FALSE;
            return( ret );
        }
    }
}

static void OutPutPrompt( char *str )
/***********************************/
{
    if( QIsDevice( CmdFile->file ) ) {
        WriteStdOut( str );
    }
}

static void GetNewLine( void )
/****************************/
{
    if( Token.how == BUFFERED
     || Token.how == ENVIRONMENT
     || Token.how == SYSTEM ) {
        Token.where = MIDST;
        while( *Token.next != '\n' ) {       //go until next line found;
            if( *Token.next == '\0' || *Token.next == CTRLZ ) {
                Token.where = ENDOFFILE;
                break;
            }
            Token.next++;
        }
        Token.next++;
    } else if( Token.how == NONBUFFERED ) {
        if( QReadStr( CmdFile->file, Token.buff, MAX_REC, CmdFile->name ) ) {
            Token.where = ENDOFFILE;
        } else {
            Token.where = MIDST;
        }
        Token.next = Token.buff;
    } else {               // interactive.
        OutPutPrompt( _LinkerPrompt );
        Token.how = INTERACTIVE;
        if( QReadStr( STDIN_HANDLE, Token.buff, MAX_REC, "console" ) ) {
            Token.where = ENDOFCMD;
        } else {
            Token.where = MIDST;
        }
        Token.next = Token.buff;
    }
}

static void BackupParser( void )
/******************************/
/* move the parser temporarily back to a previous input source */
{
    if( CmdFile->prev == NULL ) {
        LnkMsg( LOC+LINE+WRN + MSG_NO_PREVIOUS_INPUT, NULL );
        return;
    }
    memcpy( &CmdFile->token, &Token, sizeof( tok ) );   // save current state
    CmdFile = CmdFile->prev;
    memcpy( &Token, &CmdFile->token, sizeof( tok ) ); // restore old state.
}

extern void RestoreParser( void )
/*******************************/
/* return the parser to the previous command state */
{
    if( CmdFile->next == NULL ) return;
    memcpy( &CmdFile->token, &Token, sizeof( tok ) );  /* save current state */
    CmdFile = CmdFile->next;
    memcpy( &Token, &CmdFile->token, sizeof( tok ) ); // restore old state.
}

extern void NewCommandSource( char *name, char *buff, method how )
/****************************************************************/
/* start reading from a new command source, and save the old one */
{
    cmdfilelist *   newfile;

    _ChkAlloc( newfile, sizeof( cmdfilelist ) );
    newfile->file = STDIN_HANDLE;
    if( CmdFile != NULL ) {     /* save current state */
        memcpy( &CmdFile->token, &Token, sizeof( tok ) );
        newfile->next = CmdFile->next;
        if( newfile->next != NULL ) {
            newfile->next->prev = newfile;
        }
    } else {
        newfile->next = NULL;
    }
    newfile->prev = CmdFile;
    if( newfile->prev != NULL ) {
        newfile->prev->next = newfile;
    }
    CmdFile = newfile;
    CmdFile->name = name;
    CmdFile->token.buff = buff;     /* make sure token is freed */
    CmdFile->token.how = how;       /* but only if it needs to be */
    Token.buff = buff;
    Token.next = Token.buff;
    Token.where = MIDST;
    Token.line = 1;
    Token.how = how;
    Token.thumb = OK;
    Token.locked = FALSE;
    Token.quoted = FALSE;
}

extern void SetCommandFile( f_handle file, char *fname )
/******************************************************/
/* read input from given file */
{
    unsigned long   size;
    char *          buff;

    if( QIsDevice( file ) ) {
        size = 0x10000;
    } else {
        size = QFileSize( file );
    }
    buff = NULL;
    if( size < 65510 ) {       // if can alloc a chunk big enough
        _LnkAlloc( buff, size + 1 );
        if( buff != NULL ) {
            size = QRead( file, buff, size, fname );
            *(buff + size) = '\0';
            NewCommandSource( fname, buff, BUFFERED );
        }
    }
    if( buff == NULL ) {  // if couldn't buffer for some reason.
        _ChkAlloc( buff, MAX_REC + 1 ); // have to have at least this much RAM
        NewCommandSource( fname, buff, NONBUFFERED );
        Token.where = ENDOFLINE;
        Token.line++;
    }
    CmdFile->file = file;
}

static void StartNewFile( void )
/******************************/
{
    char *      fname;
    char *      envstring;
    char *      buff;
    f_handle    file;
    size_t      envlen;

    fname = FileName( Token.this, Token.len, E_COMMAND, FALSE );
    file = QObjOpen( fname );
    if( file == NIL_HANDLE ) {
        _LnkFree( fname );
        fname = tostring();
        envstring = GetEnvString( fname );
        if( envstring != NULL ) {
            envlen = strlen( envstring );       // make a copy of envstring
            _ChkAlloc( buff, envlen + 1 );      // so we can free it
            memcpy( buff, envstring, envlen );
            buff[ envlen ] = '\0';
            NewCommandSource( fname, buff, ENVIRONMENT );
        } else {
            LnkMsg( LOC+LINE+ERR+MSG_CANT_OPEN_NO_REASON, "s", fname );
            _LnkFree( fname );
            Suicide();
        }
        return;
    } else {
        SetCommandFile( file, fname );
    }
    DEBUG(( DBG_OLD, "processing command file %s", CmdFile->name ));
}

extern void EatWhite( void )
/**************************/
{
    while( IS_WHITESPACE( Token.next ) ) {
        Token.next++;
    }
}

static int ParseNumber( char * str, int radix )
/*********************************************/
/* read a (possibly hexadecimal) number */
{

⌨️ 快捷键说明

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