wfl.c

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

C
863
字号
/****************************************************************************
*
*                            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:  Compile and link utility for Open Watcom FORTRAN.
*
****************************************************************************/


#include "ftnstd.h"
#include "errcod.h"
#include "optflags.h"
#include "cioconst.h"
#include "banner.h"
#include "errrtns.h"

#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#ifndef __UNIX__
  #include <direct.h>
#endif
#include <process.h>
#include <malloc.h>

extern  void                    MsgBuffer(uint,char *,...);
extern  void                    ShowOptions(char *);
extern  void                    __InitResource(void);

#if _CPU == 386
  #define _CmpName        "wfc386"        // compiler name
  #define _CmpExeName     "wfc386.exe"    // compiler executable file name
  #define _LnkTmpFile     "@_WFL386_.LNK" // temporary linker directive file
  #define _WCLEnv         "WFL386"        // "wcl" environment variable
#elif _CPU == 8086
  #define _CmpName        "wfc"           // copmiler name
  #define _CmpExeName     "wfc.exe"       // compiler exe file name
  #define _LnkTmpFile     "@__WFL__.LNK"  // temporary linker directive file
  #define _WCLEnv         "WFL"           // "wcl" environment variable
#elif _CPU == _AXP
  #define _CmpName        "wfcaxp"         // copmiler name
  #define _CmpExeName     "wfcaxp.exe"     // compiler exe file name
  #define _LnkTmpFile     "@_WFLAXP_.LNK"// temporary linker directive file
  #define _WCLEnv         "WFLAXP"         // "wcl" environment variable
#elif _CPU == _PPC
  #define _CmpName        "wfcppc"         // copmiler name
  #define _CmpExeName     "wfcppc.exe"     // compiler exe file name
  #define _LnkTmpFile     "@_WFLPPC_.LNK"// temporary linker directive file
  #define _WCLEnv         "WFLPPC"         // "wcl" environment variable
#else
  #error Unknown OS/CPU
#endif

#if defined( __QNX__ )
  #define _ObjExtn        ".o"          // object file extension
#else
  #define _ObjExtn        ".obj"        // object file extension
#endif

#define _LnkName        "wlink"         // linker name
#define _LnkExeName     "wlink.exe"     // linker executable file name

#define _CVPName        "cvpack"        // Codeview pack name
#define _CVPExeName     "cvpack.exe"    // Codeview pack executable file name

#define NULL_STR        ""
#define NULLCHAR        '\0'
#define ATTR_MASK       _A_HIDDEN + _A_SYSTEM + _A_VOLID + _A_SUBDIR
                                        // mask for illegal file types
#define TRUE            1
#define FALSE           0

typedef struct list {
    char        *filename;
    struct list *next;
} list;
#if defined( __OS2__ ) || defined( __NT__ )
#define MAX_CMD 10240
#else
#define MAX_CMD 130
#endif

static  char    *Cmd;                   // command line parameters
static  char    *Word;                  // one parameter
static  char    Files[MAX_CMD];         // list of filenames from Cmd
static  char    Libs[MAX_CMD];          // list of libraries from Cmd
static  char    CmpOpts[MAX_CMD];       // list of compiler options from Cmd
static  char    CmpPath[_MAX_PATH];     // path for compiler executable file
static  char    LinkPath[_MAX_PATH];    // path for linker executable file
static  FILE    *Fp;                    // file pointer for TempFile
static  char    *LinkName;              // name for TempFile if /fd specified
static  char    *TempFile;              // temporary linker directive file
static  list    *ObjList;               // linked list of object filenames
static  char    SwitchChars[3];         // valid switch characters
static  char    ExeName[_MAX_PATH];     // name of executable
static  char    *ObjName;               // object file name pattern
static  char    *SystemName;            // system name
static  char    DebugFlag;              // debugging flag

static char *DebugOptions[] = {
    "",
    "debug dwarf\n",
    "debug dwarf\n",
    "debug watcom all\n",
    "debug codeview\n",
    "debug dwarf\n"
};

static  struct flags {
    unsigned quiet        : 1;  // compile quietly
    unsigned no_link      : 1;  // compile only, no link step
    unsigned link_for_sys : 1;  // system specified
#if _CPU == 386 || _CPU == _AXP || _CPU == _PPC
    unsigned default_win  : 1;  // OS/2 default windowed application
#else
    unsigned windows      : 1;  // Windows application
    unsigned link_for_dos : 1;  // produce DOS executable
    unsigned link_for_os2 : 1;  // produce OS/2 executable
#endif
    unsigned do_cvpack    : 1;  // do codeview cvpack
} Flags;

#if _CPU == 386
    #define     _NAME_  "F77/32 "
#elif _CPU == 8086
    #define     _NAME_  "F77/16 "
#elif _CPU == _AXP
    #define     _NAME_  "F77 Alpha AXP "
#elif _CPU == _PPC
    #define     _NAME_  "F77 PowerPC "
#else
    #error Unknown System
#endif


static  void    wfl_exit( int rc ) {
//==================================

    __ErrorFini();
    exit( rc );
}


static  void    PrintMsg( uint msg, ... ) {
//=========================================

    va_list     args;
    char        buff[LIST_BUFF_SIZE+1];

    va_start( args, msg );
    __BldErrMsg( msg, buff, args );
    va_end( args );
    puts( &buff[1] ); // skip leading blank
}


static  void    PrtBanner( void ) {
//===========================

    puts( banner1w( _NAME_ "Compile and Link Utility", _WFL_VERSION_ ) );
    puts( banner2( "1990" ) );
    puts( banner3 );
    puts( banner3a );
}


static  char    *SkipSpaces( char *ptr ) {
//========================================

    while( *ptr == ' ' ) ptr++;
    return( ptr );
}


static  void    *MemAlloc( int size ) {
//=====================================

    void            *ptr;

    ptr = malloc( size );
    if( ptr == NULL ) {
        PrintMsg( CL_OUT_OF_MEMORY );
        wfl_exit( 1 );
    }
    return( ptr );
}


void    main( int argc, char *argv[] ) {
//======================================

    int         rc;
    char        *wcl_env;
    char        *p;
    char        *q;

    argc = argc;

    __InitResource();
    __ErrorInit( argv[0] );

    CmpOpts[0] = '\0';

    SwitchChars[0] = '/';
    SwitchChars[1] = '-';
    SwitchChars[2] = '\0';

    Word = MemAlloc( MAX_CMD );
    Cmd = MemAlloc( 2*MAX_CMD ); // for "wfl" environment variable and command line

    // add "wcl" environment variable to "Cmd" unless "/y" is specified
    // in "Cmd" or the "wcl" environment string

    wcl_env = getenv( _WCLEnv );
    if( wcl_env != NULL ) {
        strcpy( Cmd, wcl_env );
        strcat( Cmd, " " );
        p = Cmd + strlen( Cmd );
        getcmd( p );
        q = Cmd;
        for(;;) {
            q = strpbrk( q, SwitchChars );
            if( q == NULL ) break;
            ++q;
            if( tolower( *q ) == 'y' ) {
                getcmd( Cmd );
                p = Cmd;
                break;
            }
        }
    } else {
        getcmd( Cmd );
        p = Cmd;
    }
    p = SkipSpaces( p );
    if( ( *p == NULLCHAR ) || ( strncmp( p, "? ", 2 ) == NULL ) ) {
        Usage();
        wfl_exit( 1 );
    }
    TempFile = _LnkTmpFile;
    Fp = fopen( &TempFile[1], "w" );
    if( Fp == NULL ) {
        PrintMsg( CL_ERROR_OPENING_TMP_FILE );
        wfl_exit( 1 );
    }
    ObjName = NULL;
    rc = Parse();
    FindPath( _CmpExeName, CmpPath );
    if( rc == 0 ) {
        if( !Flags.quiet ) {
            PrtBanner();
        }
        rc = CompLink();
    }
    if( rc == 1 ) fclose( Fp );
    if( LinkName != NULL ) {
        if( stricmp( LinkName, &TempFile[1] ) != 0 ) {
            remove( LinkName );
            rename( &TempFile[1], LinkName );
        }
    } else {
        remove( &TempFile[1] );
    }
    wfl_exit( rc == 0 ? 0 : 1 );
}


static  char    *ScanFName( char *end, int len ) {
//================================================

    for(;;) {
        if( *end == '\0' ) break;
        if( *end == ' '  ) break;
        if( *end == SwitchChars[0] ) break;
        if( *end == SwitchChars[1] ) break;
        Word[len] = *end;
        ++len;
        ++end;
    }
    Word[len] = NULLCHAR;
    return( end );
}


static  int     Parse( void ) {
//=============================

    char        opt;
    char        *end;
    int         len;
    int         cmp_option;
    char        in_quotes;

    Flags.no_link = 0;
    Flags.link_for_sys = 0;
    Flags.quiet        = 0;
#if _CPU == 386 || _CPU == _AXP || _CPU == _PPC
    Flags.default_win  = 0;
#else
    Flags.windows      = 0;
    Flags.link_for_dos = 0;
    Flags.link_for_os2 = 0;
#endif
    Flags.do_cvpack    = 0;

    DebugFlag = 0;

    // "Cmd" will always begin with at least one
    // non-space character if we get this far

    do {
        opt = *Cmd;
        if( ( opt == SwitchChars[0] ) || ( opt == SwitchChars[1] ) ) {
            Cmd++;
        } else {
            opt = ' ';
        }
        in_quotes = FALSE;
        end = Cmd;
        for(;;) {
            if( *end == '\0' ) break;
            if( *end == '"' ) {
                if( in_quotes ) break;
                in_quotes = TRUE;
            }
            if( !in_quotes ) {
                if( *end == ' '  ) break;
                if( *end == SwitchChars[0] ) break;
                if( *end == SwitchChars[1] ) break;
            }
            ++end;
        }
        len = end - Cmd;
        if( len != 0 ) {
            if( opt == ' ' ) {  // if filename, add to list
                strncpy( Word, Cmd, len );
                Word[len] = NULLCHAR;
                strlwr( Word );
                if( strstr( Word, ".lib" ) != NULL ) {
                    strcat( Libs, Libs[0] != '\0' ? "," : " " );
                    strcat( Libs, Word );
                } else {
                    strcat( Files, Word );
                    strcat( Files, " " );
                }
            } else {            // otherwise, do option
                --len;
                strncpy( Word, Cmd + 1, len );
                Word[len] = NULLCHAR;
                cmp_option = 1; // assume its a compiler option
                switch( tolower( *Cmd ) ) {
                case 'f':       // files option
                    end = ScanFName( end, len );
                    switch( tolower( Word[0] ) ) {
                    case 'd':   // name of linker directive file
                        if( Word[1] == '\0' ) {
                            LinkName = _LnkTmpFile;
                            ++LinkName;     // skip over '@'
                            cmp_option = 0;
                        } else if( (Word[1] == '=') || (Word[1] == '#') ) {
                            MakeName( Word, ".lnk" );    // add extension
                            LinkName = strdup( Word + 2 );
                            cmp_option = 0;
                        }
                        break;
                    case 'e':   // name of exe file
                        if( ( Word[1] == '=' ) || ( Word[1] == '#' ) ) {
                            fputs( "name ", Fp );
                            Fputnl( Word + 2, Fp );
                            strcpy( ExeName, Word + 2 );
                            cmp_option = 0;
                        }
                        break;
                    case 'm':   // name of map file
                        if( Word[1] == '\0' ) {
                            fputs( "option map\n", Fp );
                            cmp_option = 0;
                        } else if( (Word[1] == '=') || (Word[1] == '#') ) {
                            fputs( "option map=", Fp );
                            Fputnl( Word + 2, Fp );
                            cmp_option = 0;
                        }
                        break;
                    case 'i':
                        if( ( Word[1] == '=' ) || ( Word[1] == '#' ) ) {
                            fputs( "@", Fp );
                            Fputnl( Word + 2, Fp );
                            cmp_option = 0;
                        }
                        break;
                    case 'o':   // name of object file
                        // parse off argument, so we get right filename
                        // in linker command file
                        if( ( Word[1] == '=' ) || ( Word[1] == '#' ) ) {
                            ObjName = strdup( &Word[2] );
                        }
                        break;
                    default:
                        break;
                    }
                    break;
                case 'k':       // stack size option
                    if( ( Word[0] == '=' ) || ( Word[0] == '#' ) ) {
                        fputs( "option stack=", Fp );
                        Fputnl( Word + 1, Fp );
                        cmp_option = 0;
                    }
                    break;

⌨️ 快捷键说明

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