mirror of
https://github.com/NishiOwO/JWasm.git
synced 2025-04-21 16:54:39 +00:00
1092 lines
35 KiB
C
1092 lines
35 KiB
C
/****************************************************************************
|
|
*
|
|
* 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: command line argument parser
|
|
*
|
|
****************************************************************************/
|
|
|
|
//#include <stdarg.h>
|
|
#include <stddef.h>
|
|
#include <ctype.h>
|
|
|
|
#include "globals.h"
|
|
#include "memalloc.h"
|
|
#include "parser.h"
|
|
#include "msgtext.h"
|
|
#include "dbgcv.h"
|
|
#include "cmdline.h"
|
|
#include "myassert.h"
|
|
#include "input.h" /* GetFNamePart() */
|
|
|
|
//#ifdef __OSI__
|
|
// #include "ostype.h"
|
|
//#endif
|
|
|
|
#if defined(__UNIX__) || defined(__CYGWIN__) || defined(__DJGPP__)
|
|
|
|
#define HANDLECTRLZ 0
|
|
#define SWITCHCHAR 0
|
|
|
|
#else
|
|
|
|
#define HANDLECTRLZ 1
|
|
#define SWITCHCHAR 1
|
|
|
|
#endif
|
|
|
|
#ifdef __I86__
|
|
#define OPTQUAL __near
|
|
#else
|
|
#define OPTQUAL
|
|
#endif
|
|
|
|
extern char banner_printed;
|
|
|
|
struct global_options Options = {
|
|
/* quiet */ FALSE,
|
|
/* line_numbers */ FALSE,
|
|
/* debug_symbols */ 0,
|
|
/* debug_ext */ 0, /* v2.10 */
|
|
/* floating_point */ FPO_NO_EMULATION,
|
|
|
|
/* error_limit */ 50,
|
|
/* no error display */ FALSE,
|
|
/* warning_level */ 2,
|
|
/* warning_error */ FALSE,
|
|
#ifdef DEBUG_OUT
|
|
/* debug */ FALSE,
|
|
/* nobackpatch */ FALSE,
|
|
#if FASTPASS
|
|
/* nofastpass */ FALSE,
|
|
/* print_linestore */ FALSE,
|
|
#endif
|
|
/* max_passes */ 0,
|
|
/* skip_preprocessor */ 0,
|
|
/* log_all_files */ 0,
|
|
/* dump_reswords */ FALSE,
|
|
/* dump_reswords_hash */ FALSE,
|
|
/* dump_symbols */ FALSE,
|
|
/* dump_symbols_hash */ FALSE,
|
|
#endif
|
|
/* names */ {
|
|
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
|
#if BUILD_TARGET
|
|
NULL,
|
|
#endif
|
|
#if MANGLERSUPP
|
|
NULL
|
|
#endif
|
|
},
|
|
/* queues */ { NULL, NULL, NULL },
|
|
#if COCTALS
|
|
/* allow_c_octals */ FALSE,
|
|
#endif
|
|
/* no_comment_data_in_code_records */ FALSE,
|
|
/* no_opt_farcall */ FALSE,
|
|
/* no_dependencies */ // FALSE,
|
|
#if COFF_SUPPORT
|
|
/* no_file_entry */ FALSE,
|
|
/* no_static_procs */ FALSE,
|
|
/* no_section_aux_entry */ FALSE,
|
|
#endif
|
|
/* no_cdecl_decoration */ FALSE,
|
|
/* stdcall_decoration */ STDCALL_FULL,
|
|
/* no_export_decoration */ FALSE,
|
|
/* entry_decorated */ FALSE,
|
|
/* write_listing */ FALSE,
|
|
/* write_impdef */ FALSE,
|
|
/* case_sensitive */ FALSE,
|
|
/* convert_uppercase */ FALSE,
|
|
/* preprocessor_stdout */ FALSE,
|
|
/* masm51_compat */ FALSE,
|
|
/* strict_masm_compat */ FALSE,
|
|
/* masm_compat_gencode */ FALSE,
|
|
/* masm8_proc_visibility */ FALSE,
|
|
|
|
/* listif */ FALSE,
|
|
/* list_generated_code */ FALSE,
|
|
/* list_macro */ LM_LISTMACRO,
|
|
/* no_symbol_listing */ FALSE,
|
|
/* first_pass_listing */ FALSE,
|
|
|
|
/* all_symbols_public */ FALSE,
|
|
/* safeseh */ FALSE,
|
|
/* ignore_include */ FALSE,
|
|
/* output_format */ OFORMAT_OMF,
|
|
/* sub_format */ SFORMAT_NONE,
|
|
/* alignment_default */ 0,
|
|
/* langtype */ LANG_NONE,
|
|
/* model */ MODEL_NONE,
|
|
/* cpu */ P_86,
|
|
/* fastcall type */ FCT_MSC,
|
|
/* syntax check only */ FALSE,
|
|
#if MANGLERSUPP
|
|
/* naming_convention*/ NC_DO_NOTHING,
|
|
#endif
|
|
};
|
|
|
|
char *DefaultDir[NUM_FILE_TYPES] = { NULL, NULL, NULL, NULL };
|
|
//static char *DefaultExt[NUM_FILE_TYPES] = { OBJ_EXT, LST_EXT, ERR_EXT };
|
|
|
|
#define MAX_RSP_NESTING 15 /* nesting of response files */
|
|
|
|
static unsigned OptValue; /* value of option's numeric argument */
|
|
static char *OptName; /* value of option's name argument */
|
|
static const char *cmdsave[MAX_RSP_NESTING]; /* response files */
|
|
static const char *cmdbuffers[MAX_RSP_NESTING]; /* response files */
|
|
static int rspidx = 0; /* response file level */
|
|
|
|
/* array for options -0 ... -10 */
|
|
static const enum cpu_info cpuoption[] = {
|
|
P_86, P_186, P_286, P_386, /* 0-3 */
|
|
P_486, P_586, P_686, P_686 | P_MMX, /* 4-7 */
|
|
P_686 | P_MMX | P_SSE1, /* 8 */
|
|
P_686 | P_MMX | P_SSE1 | P_SSE2, /* 9 */
|
|
#if AMD64_SUPPORT
|
|
P_64, /* 10 */
|
|
#endif
|
|
};
|
|
|
|
#if 0 /* v2.10: removed, because factually never called */
|
|
static void StripQuotes( char *fname )
|
|
/************************************/
|
|
{
|
|
char *s;
|
|
char *d;
|
|
|
|
if( *fname == '"' ) {
|
|
/* string will shrink so we can reduce in place */
|
|
d = fname;
|
|
for( s = d + 1; *s && *s != '"'; ++s ) {
|
|
/* collapse double backslashes, only then look for escaped quotes */
|
|
if( s[0] == '\\' && s[1] == '\\' ) {
|
|
++s;
|
|
} else if( s[0] == '\\' && s[1] == '"' ) {
|
|
++s;
|
|
}
|
|
*d++ = *s;
|
|
}
|
|
*d = '\0';
|
|
}
|
|
}
|
|
|
|
static char *GetAFileName( void )
|
|
/*******************************/
|
|
{
|
|
DebugMsg(("GetAFileName() enter, OptName=>%s<\n", OptName ));
|
|
StripQuotes( OptName );
|
|
return( OptName );
|
|
}
|
|
#else
|
|
#define GetAFileName() OptName
|
|
#endif
|
|
|
|
#if BUILD_TARGET
|
|
static void SetTargName( char *name, unsigned len )
|
|
/*************************************************/
|
|
{
|
|
if( Options.names[OPTN_BUILD_TARGET] != NULL ) {
|
|
MemFree( Options.names[OPTN_BUILD_TARGET] );
|
|
Options.names[OPTN_BUILD_TARGET] = NULL;
|
|
}
|
|
if( name == NULL || len == 0 )
|
|
return;
|
|
Options.names[OPTN_BUILD_TARGET] = MemAlloc( len + 1 );
|
|
strcpy( Options.names[OPTN_BUILD_TARGET], name );
|
|
_strupr( Options.names[OPTN_BUILD_TARGET] );
|
|
}
|
|
#endif
|
|
|
|
/* called by -0, -1, ... argument */
|
|
|
|
static void SetCpuCmdline( enum cpu_info value, const char *parm )
|
|
/****************************************************************/
|
|
{
|
|
|
|
Options.cpu &= ~(P_CPU_MASK | P_EXT_MASK | P_PM);
|
|
Options.cpu |= value;
|
|
|
|
for( ; *parm ; parm++ ) {
|
|
if( *parm == 'p' && Options.cpu >= P_286 ) {
|
|
Options.cpu |= P_PM; /* set privileged mode */
|
|
#if MANGLERSUPP
|
|
} else if( *parm == '"' ) { /* set default mangler */
|
|
char *dest;
|
|
parm++;
|
|
dest = strchr( parm, '"' );
|
|
if( Options.names[OPTN_DEFNAME_MANGLER] != NULL ) {
|
|
MemFree( Options.names[OPTN_DEFNAME_MANGLER );
|
|
}
|
|
Options.names[OPTN_DEFNAME_MANGLER = MemAlloc( dest - parm + 1 );
|
|
dest = Options.names[OPTN_DEFNAME_MANGLER];
|
|
for( ; *parm != '"'; dest++, parm++ ) {
|
|
*dest = *parm;
|
|
}
|
|
*dest = NULLC;
|
|
#endif
|
|
} else {
|
|
EmitWarn( 1, CPU_OPTION_INVALID, parm );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* queue a text macro, include path or "forced" include files.
|
|
this is called for cmdline options -D, -I and -Fi
|
|
*/
|
|
|
|
static void queue_item( int i, const char *string )
|
|
/*************************************************/
|
|
{
|
|
struct qitem *p;
|
|
struct qitem *q;
|
|
|
|
DebugMsg(("queue_item(%u, %s) enter\n", i, string));
|
|
p = MemAlloc( sizeof(struct qitem) + strlen( string ) );
|
|
p->next = NULL;
|
|
strcpy( p->value, string );
|
|
q = Options.queues[i];
|
|
if ( q ) {
|
|
for ( ; q->next; q = q->next );
|
|
q->next = p;
|
|
} else
|
|
Options.queues[i] = p;
|
|
return;
|
|
}
|
|
|
|
static void get_fname( int type, const char *token )
|
|
/**************************************************/
|
|
/*
|
|
* called by -Fo, -Fw or -Fl (for .OBJ, .ERR or .LST filenames ).
|
|
* also called by -Fd; in this case type is > NUM_FILE_TYPES!
|
|
* v2.12: _splitpath()/_makepath() removed.
|
|
*/
|
|
{
|
|
const char *pName;
|
|
char name [ FILENAME_MAX ];
|
|
|
|
DebugMsg(("get_fname( type=%u, >%s< ) enter\n", type, token ));
|
|
//_splitpath( token, drive, dir, fname, ext );
|
|
pName = GetFNamePart( token );
|
|
/*
|
|
* If name's ending with a '\' (or '/' in Unix), it's supposed
|
|
* to be a directory name only.
|
|
*/
|
|
if( *pName == NULLC ) {
|
|
DebugMsg(("get_fname(%u, >%s< ) name is empty or a directory\n", type, token ));
|
|
/* v2.10: ensure type is < NUM_FILE_TYPES */
|
|
if ( type < NUM_FILE_TYPES ) {
|
|
if ( DefaultDir[type] )
|
|
MemFree( DefaultDir[type]);
|
|
DefaultDir[type] = MemAlloc( strlen( token ) + 1 );
|
|
strcpy( DefaultDir[type], token );
|
|
}
|
|
return;
|
|
}
|
|
/* v2.10: ensure type is < NUM_FILE_TYPES */
|
|
//if ( drive[0] == NULLC && dir[0] == NULLC && type < NUM_FILE_TYPES && DefaultDir[type] ) {
|
|
name[0] = NULLC;
|
|
if ( pName == token && type < NUM_FILE_TYPES && DefaultDir[type] ) {
|
|
DebugMsg(("get_fname: default drive+dir used: %s\n" ));
|
|
//_splitpath( DefaultDir[type], drive, dir, NULL, NULL );
|
|
strcpy( name, DefaultDir[type] );
|
|
}
|
|
strcat( name, token );
|
|
#if 0 /* v2.12: extension will be set in SetFileNames() */
|
|
if( type && type < NUM_FILE_TYPES ) {
|
|
char *pExt = GetExtPart( name );
|
|
if ( *pExt == NULLC ) {
|
|
*pExt++ = '.';
|
|
strcpy( pExt, DefaultExt[type-1] );
|
|
}
|
|
}
|
|
#endif
|
|
//_makepath( name, drive, dir, fname, pExt );
|
|
if( Options.names[type] != NULL ) {
|
|
MemFree( Options.names[type] );
|
|
}
|
|
Options.names[type] = MemAlloc( strlen( name ) + 1 );
|
|
strcpy( Options.names[type], name );
|
|
}
|
|
|
|
static void set_option_n_name( int idx, const char *name )
|
|
/********************************************************/
|
|
/* option -n: set name of
|
|
* - nd: data seg
|
|
* - nm: module name
|
|
* - nt: text seg
|
|
* - nc: code class
|
|
*/
|
|
{
|
|
if ( *name != '.' && !is_valid_id_char( *name ) ) {
|
|
EmitError( N_OPTION_NEEDS_A_NAME_PARAMETER );
|
|
return;
|
|
}
|
|
|
|
if( Options.names[idx] != NULL ) {
|
|
MemFree( Options.names[idx] );
|
|
}
|
|
Options.names[idx] = MemAlloc( strlen( name ) + 1 );
|
|
strcpy( Options.names[idx], name );
|
|
}
|
|
|
|
//static void OPTQUAL Ignore( void ) {};
|
|
|
|
#if BUILD_TARGET
|
|
static void OPTQUAL Set_bt( void ) { SetTargName( OptName, strlen(OptName) ); }
|
|
#endif
|
|
|
|
static void OPTQUAL Set_c( void ) { }
|
|
|
|
#ifdef DEBUG_OUT
|
|
static void OPTQUAL Set_ce( void ) { rspidx = 1 / rspidx; }
|
|
#endif
|
|
|
|
static void OPTQUAL Set_Cp( void ) { Options.case_sensitive = TRUE; Options.convert_uppercase = FALSE; }
|
|
static void OPTQUAL Set_Cu( void ) { Options.case_sensitive = FALSE; Options.convert_uppercase = TRUE; }
|
|
static void OPTQUAL Set_Cx( void ) { Options.case_sensitive = FALSE; Options.convert_uppercase = FALSE; }
|
|
|
|
static void OPTQUAL Set_Zd( void ) { Options.line_numbers = TRUE; }
|
|
static void OPTQUAL Set_Zi( void )
|
|
{
|
|
Set_Zd();
|
|
Options.debug_symbols = CV_SIGNATURE;
|
|
/* v2.10: added optional numeric argument for -Zi */
|
|
if ( OptValue <= CVEX_MAX )
|
|
Options.debug_ext = OptValue;
|
|
else
|
|
EmitWarn( 1, INVALID_CMDLINE_VALUE, "Zi" );
|
|
}
|
|
|
|
static void OPTQUAL Set_Zp( void )
|
|
/********************************/
|
|
{
|
|
uint_8 power;
|
|
for ( power = 0; (1 << power) <= MAX_STRUCT_ALIGN; power++ )
|
|
if ( ( 1 << power ) == OptValue ) {
|
|
Options.fieldalign = power;
|
|
return;
|
|
}
|
|
EmitWarn( 1, INVALID_CMDLINE_VALUE, "Zp" );
|
|
return;
|
|
}
|
|
|
|
static void OPTQUAL Set_D( void ) { queue_item( OPTQ_MACRO, GetAFileName() ); }
|
|
static void OPTQUAL Set_Fi( void ) { queue_item( OPTQ_FINCLUDE, GetAFileName() ); }
|
|
static void OPTQUAL Set_I( void ) { queue_item( OPTQ_INCPATH, GetAFileName() ); }
|
|
|
|
static void OPTQUAL Set_e( void ) { Options.error_limit = OptValue; }
|
|
|
|
static void OPTQUAL Set_nologo( void ) { banner_printed = TRUE; }
|
|
static void OPTQUAL Set_q( void ) { Set_nologo(); Options.quiet = TRUE; }
|
|
static void OPTQUAL Set_EP( void ) { Options.preprocessor_stdout = TRUE; Set_q(); }
|
|
|
|
#if DLLIMPORT
|
|
static void OPTQUAL Set_Fd( void ) { get_fname( OPTN_LNKDEF_FN, GetAFileName() ); Options.write_impdef = TRUE;}
|
|
#endif
|
|
static void OPTQUAL Set_Fw( void ) { get_fname( OPTN_ERR_FN, GetAFileName() ); }
|
|
static void OPTQUAL Set_Fl( void ) { get_fname( OPTN_LST_FN, GetAFileName() ); Options.write_listing = TRUE;}
|
|
static void OPTQUAL Set_Fo( void ) { get_fname( OPTN_OBJ_FN, GetAFileName() ); }
|
|
|
|
static void OPTQUAL Set_fp( void ) { Options.cpu &= ~P_FPU_MASK; Options.cpu = OptValue; }
|
|
static void OPTQUAL Set_FPx( void ) { Options.floating_point = OptValue; }
|
|
static void OPTQUAL Set_G( void ) { Options.langtype = OptValue; }
|
|
|
|
static void OPTQUAL Set_Sa( void )
|
|
/********************************/
|
|
{
|
|
Options.listif = TRUE;
|
|
Options.list_generated_code = TRUE;
|
|
Options.list_macro = LM_LISTMACROALL;
|
|
}
|
|
|
|
static void OPTQUAL Set_True( void )
|
|
/**********************************/
|
|
{
|
|
char *p = ((char *)&Options) + OptValue;
|
|
*p = TRUE;
|
|
}
|
|
|
|
static void OPTQUAL Set_m( void ) { Options.model = OptValue; }
|
|
static void OPTQUAL Set_n( void ) { set_option_n_name( OptValue, OptName ); }
|
|
|
|
#ifdef DEBUG_OUT
|
|
static void OPTQUAL Set_pm( void ) { Options.max_passes = OptValue; };
|
|
#endif
|
|
|
|
static void OPTQUAL Set_WX( void ) { Options.warning_error = TRUE; }
|
|
|
|
static void OPTQUAL Set_w( void ) { Set_WX(); Options.warning_level = 0; }
|
|
|
|
static void OPTQUAL Set_W( void )
|
|
/*******************************/
|
|
{
|
|
if ( OptValue <= 4 )
|
|
Options.warning_level = OptValue;
|
|
else
|
|
EmitWarn( 1, INVALID_CMDLINE_VALUE, "W" );
|
|
}
|
|
|
|
static void OPTQUAL Set_ofmt( void )
|
|
/**********************************/
|
|
{
|
|
Options.output_format = OptValue & 0xff;
|
|
Options.sub_format = OptValue >> 8;
|
|
}
|
|
|
|
static void OPTQUAL Set_zcm( void ) { Options.no_cdecl_decoration = FALSE; }
|
|
#if OWFC_SUPPORT
|
|
static void OPTQUAL Set_zf( void ) { Options.fctype = OptValue; }
|
|
#endif
|
|
|
|
static void OPTQUAL Set_zt( void ) { Options.stdcall_decoration = OptValue; }
|
|
#ifndef __SW_BD
|
|
static void OPTQUAL Set_h( void ) { PrintUsage(); exit(1); }
|
|
#endif
|
|
|
|
#ifdef DEBUG_OUT
|
|
static void OPTQUAL Set_dm( void )
|
|
{
|
|
int i;
|
|
for ( i = 0; i < MSG_LAST; i++ ) {
|
|
printf("%3u: %s\n", i, MsgGetEx(i) );
|
|
}
|
|
}
|
|
static void OPTQUAL Set_dt( void )
|
|
/********************************/
|
|
{
|
|
Options.debug = TRUE;
|
|
ModuleInfo.cref = TRUE; /* enable debug displays */
|
|
DebugMsg(( "debugging output on\n" ));
|
|
}
|
|
#if FASTPASS
|
|
static void OPTQUAL Set_nfp( void )
|
|
/*********************************/
|
|
{
|
|
Options.nofastpass = TRUE;
|
|
DebugMsg(( "FASTPASS disabled\n" ));
|
|
}
|
|
#endif
|
|
static void OPTQUAL Set_nbp( void )
|
|
/*********************************/
|
|
{
|
|
Options.nobackpatch = TRUE;
|
|
DebugMsg(( "backpatching disabled\n" ));
|
|
}
|
|
#endif
|
|
|
|
struct cmdloption {
|
|
const char *name;
|
|
unsigned value;
|
|
void OPTQUAL (*function)( void );
|
|
};
|
|
|
|
#define optofs( x ) offsetof( struct global_options, x )
|
|
|
|
/*
|
|
* '#': collect a number
|
|
* '$': collect an identifer[=value]
|
|
* '@': collect a filename
|
|
* '=': collect an optional '='
|
|
* '^': skip spaces before argument
|
|
*/
|
|
static struct cmdloption const cmdl_options[] = {
|
|
#ifndef __SW_BD
|
|
{ "?", 0, Set_h },
|
|
#endif
|
|
#ifdef DEBUG_OUT
|
|
{ "af", optofs( log_all_files ), Set_True },
|
|
#endif
|
|
#if BIN_SUPPORT
|
|
{ "bin", OFORMAT_BIN | (SFORMAT_NONE << 8), Set_ofmt },
|
|
#endif
|
|
#if BUILD_TARGET
|
|
{ "bt=$", 0, Set_bt },
|
|
#endif
|
|
{ "Cp", 0, Set_Cp },
|
|
{ "Cu", 0, Set_Cu },
|
|
{ "Cx", 0, Set_Cx },
|
|
#ifdef DEBUG_OUT
|
|
{ "ce", 0, Set_ce },
|
|
#endif
|
|
#if COFF_SUPPORT
|
|
{ "coff", OFORMAT_COFF | (SFORMAT_NONE << 8), Set_ofmt },
|
|
#endif
|
|
{ "c", 0, Set_c },
|
|
#if COFF_SUPPORT && DJGPP_SUPPORT
|
|
{ "djgpp", OFORMAT_COFF | (SFORMAT_DJGPP << 8), Set_ofmt },
|
|
#endif
|
|
#ifdef DEBUG_OUT
|
|
{ "dm", 0, Set_dm },
|
|
{ "drh", optofs( dump_reswords_hash ), Set_True },
|
|
{ "dr", optofs( dump_reswords ), Set_True },
|
|
{ "dsh", optofs( dump_symbols_hash ), Set_True },
|
|
{ "ds", optofs( dump_symbols ), Set_True },
|
|
{ "dt", 0, Set_dt },
|
|
#endif
|
|
{ "D^$", 0, Set_D },
|
|
#if ELF_SUPPORT
|
|
#if AMD64_SUPPORT
|
|
{ "elf64", OFORMAT_ELF | (SFORMAT_64BIT << 8), Set_ofmt },
|
|
#endif
|
|
{ "elf", OFORMAT_ELF | (SFORMAT_NONE << 8), Set_ofmt },
|
|
#endif
|
|
{ "EP", 0, Set_EP },
|
|
{ "eq", optofs( no_error_disp ), Set_True },
|
|
{ "e=#", 0, Set_e },
|
|
#if DLLIMPORT
|
|
{ "Fd=@", 0, Set_Fd },
|
|
#endif
|
|
{ "Fi=^@", 0, Set_Fi },
|
|
{ "Fl=@", 0, Set_Fl },
|
|
{ "Fo=^@", 0, Set_Fo },
|
|
{ "FPi87", FPO_NO_EMULATION, Set_FPx },
|
|
{ "FPi", FPO_EMULATION, Set_FPx },
|
|
{ "fp0", P_87, Set_fp },
|
|
{ "fp2", P_287, Set_fp },
|
|
{ "fp3", P_387, Set_fp },
|
|
#if 0
|
|
{ "fp5", P_387, Set_fp },
|
|
{ "fp6", P_387, Set_fp },
|
|
#endif
|
|
{ "fpc", P_NO87, Set_fp },
|
|
{ "Fw=^@", 0, Set_Fw },
|
|
{ "Gc", LANG_PASCAL, Set_G },
|
|
{ "Gd", LANG_C, Set_G },
|
|
{ "Gr", LANG_FASTCALL,Set_G },
|
|
{ "Gz", LANG_STDCALL, Set_G },
|
|
{ "h", 0, Set_h },
|
|
{ "I=^@", 0, Set_I },
|
|
#ifdef DEBUG_OUT
|
|
#if FASTPASS
|
|
{ "ls", optofs( print_linestore ), Set_True },
|
|
#endif
|
|
#endif
|
|
{ "mc", MODEL_COMPACT, Set_m },
|
|
{ "mf", MODEL_FLAT, Set_m },
|
|
{ "mh", MODEL_HUGE, Set_m },
|
|
{ "ml", MODEL_LARGE, Set_m },
|
|
{ "mm", MODEL_MEDIUM, Set_m },
|
|
{ "ms", MODEL_SMALL, Set_m },
|
|
{ "mt", MODEL_TINY, Set_m },
|
|
#if BIN_SUPPORT
|
|
#if MZ_SUPPORT
|
|
{ "mz", OFORMAT_BIN | (SFORMAT_MZ << 8), Set_ofmt },
|
|
#endif
|
|
#endif
|
|
#ifdef DEBUG_OUT
|
|
{ "nbp", 0, Set_nbp },
|
|
#endif
|
|
{ "nc=$", OPTN_CODE_CLASS, Set_n },
|
|
{ "nd=$", OPTN_DATA_SEG, Set_n },
|
|
#if FASTPASS && defined(DEBUG_OUT)
|
|
{ "nfp", 0, Set_nfp },
|
|
#endif
|
|
{ "nm=$", OPTN_MODULE_NAME, Set_n },
|
|
{ "nologo", 0, Set_nologo },
|
|
{ "nt=$", OPTN_TEXT_SEG, Set_n },
|
|
{ "omf", OFORMAT_OMF | (SFORMAT_NONE << 8), Set_ofmt },
|
|
#if COCTALS
|
|
{ "o", optofs( allow_c_octals ), Set_True },
|
|
#endif
|
|
#if PE_SUPPORT
|
|
{ "pe", OFORMAT_BIN | (SFORMAT_PE << 8), Set_ofmt },
|
|
#endif
|
|
#ifdef DEBUG_OUT
|
|
{ "pm=#", 0, Set_pm },
|
|
#endif
|
|
{ "q", 0, Set_q },
|
|
{ "Sa", 0, Set_Sa },
|
|
{ "Sf", optofs( first_pass_listing ), Set_True },
|
|
{ "Sg", optofs( list_generated_code ), Set_True },
|
|
{ "Sn", optofs( no_symbol_listing ), Set_True },
|
|
{ "Sx", optofs( listif ), Set_True },
|
|
#if COFF_SUPPORT
|
|
{ "safeseh",optofs( safeseh ), Set_True },
|
|
#endif
|
|
#ifdef DEBUG_OUT
|
|
{ "sp", optofs( skip_preprocessor ), Set_True },
|
|
#endif
|
|
{ "WX", 0, Set_WX },
|
|
{ "W=#", 0, Set_W },
|
|
#if AMD64_SUPPORT
|
|
{ "win64", OFORMAT_COFF | (SFORMAT_64BIT << 8), Set_ofmt },
|
|
#endif
|
|
{ "w", 0, Set_w },
|
|
{ "X", optofs( ignore_include ), Set_True },
|
|
{ "Zd", 0, Set_Zd },
|
|
{ "Zf", optofs( all_symbols_public ), Set_True },
|
|
{ "Zg", optofs( masm_compat_gencode ), Set_True },
|
|
{ "Zi=#", CVEX_NORMAL, Set_Zi },
|
|
{ "Zm", optofs( masm51_compat ), Set_True },
|
|
{ "Zne", optofs( strict_masm_compat ), Set_True },
|
|
{ "Zp=#", 0, Set_Zp },
|
|
{ "zcm", 0, Set_zcm },
|
|
{ "zcw", optofs( no_cdecl_decoration ), Set_True },
|
|
#if OWFC_SUPPORT
|
|
{ "zf0", FCT_MSC, Set_zf },
|
|
{ "zf1", FCT_WATCOMC, Set_zf },
|
|
#endif
|
|
{ "zlc", optofs( no_comment_data_in_code_records ), Set_True },
|
|
{ "zld", optofs( no_opt_farcall ), Set_True },
|
|
#if COFF_SUPPORT
|
|
{ "zlf", optofs( no_file_entry ), Set_True },
|
|
{ "zlp", optofs( no_static_procs ), Set_True }, /* v2.10: added */
|
|
{ "zls", optofs( no_section_aux_entry ), Set_True },
|
|
#endif
|
|
{ "Zs", optofs( syntax_check_only ), Set_True },
|
|
{ "zt0", STDCALL_NONE, Set_zt },
|
|
{ "zt1", STDCALL_HALF, Set_zt },
|
|
{ "zt2", STDCALL_FULL, Set_zt },
|
|
{ "Zv8", optofs( masm8_proc_visibility ), Set_True },
|
|
{ "zze", optofs( no_export_decoration ), Set_True },
|
|
#if COFF_SUPPORT
|
|
{ "zzs", optofs( entry_decorated ), Set_True },
|
|
#endif
|
|
// { NULL, 0, 0 }
|
|
};
|
|
|
|
/*
|
|
* get a "name"
|
|
* type=@ : filename ( -Fd, -Fi, -Fl, -Fo, -Fw, -I )
|
|
* type=$ : (macro) identifier [=value] ( -D, -nc, -nd, -nm, -nt )
|
|
* type=0 : something else ( -0..-10 )
|
|
*/
|
|
static const char *GetNameToken( char *dst, const char *str, int max, char type )
|
|
/*******************************************************************************/
|
|
{
|
|
bool equatefound = FALSE;
|
|
|
|
DebugMsg(("GetNameToken( %s, %u, '%c' ) enter, rspidx=%u\n", str, max, type, rspidx ));
|
|
//while( isspace( *str ) ) ++str; /* no spaces allowed! */
|
|
is_quote:
|
|
if( *str == '"' ) {
|
|
++str;
|
|
for( ; max && *str; max-- ) {
|
|
if ( *str == '"' ) {
|
|
++str;
|
|
break;
|
|
}
|
|
/* handle the \" case */
|
|
if ( *str == '\\' && *(str+1) == '"' ) {
|
|
++str;
|
|
}
|
|
*dst++ = *str++;
|
|
}
|
|
} else {
|
|
for( ; max; max-- ) {
|
|
/* v2.10: don't stop for white spaces */
|
|
//if ( *str == NULLC || *str == ' ' || *str == '\t' )
|
|
if ( *str == NULLC )
|
|
break;
|
|
/* v2.10: don't stop for white spaces if filename is expected and true cmdline is parsed */
|
|
if ( ( *str == ' ' || *str == '\t' ) && ( rspidx || type != '@' ) )
|
|
break;
|
|
if ( type == 0 )
|
|
if ( *str == '-'
|
|
#if SWITCHCHAR
|
|
|| *str == '/'
|
|
#endif
|
|
)
|
|
break;
|
|
if ( *str == '=' && type == '$' && equatefound == FALSE ) {
|
|
equatefound = TRUE;
|
|
*dst++ = *str++;
|
|
if (*str == '"')
|
|
goto is_quote;
|
|
}
|
|
*dst++ = *str++;
|
|
}
|
|
}
|
|
*dst = NULLC;
|
|
return( str );
|
|
}
|
|
|
|
/*
|
|
* A '@' was found in the cmdline. It's not an environment variable,
|
|
* so check if it is a file and, if yes, read it.
|
|
*/
|
|
|
|
static char *ReadParamFile( const char *name )
|
|
/********************************************/
|
|
{
|
|
char *env;
|
|
char *str;
|
|
FILE *file;
|
|
int len;
|
|
char ch;
|
|
|
|
DebugMsg(("ReadParamFile(%s) enter\n"));
|
|
env = NULL;
|
|
file = fopen( name, "rb" );
|
|
if( file == NULL ) {
|
|
/* v2.10: changed to fatal error */
|
|
//EmitErr( CANNOT_OPEN_FILE, name, ErrnoStr() );
|
|
Fatal( CANNOT_OPEN_FILE, name, ErrnoStr() );
|
|
return( NULL );
|
|
}
|
|
len = 0;
|
|
if ( fseek( file, 0, SEEK_END ) == 0 ) {
|
|
len = ftell( file );
|
|
rewind( file );
|
|
env = MemAlloc( len + 1 );
|
|
#if defined(__GNUC__) /* gcc warns if return value of fread() is "ignored" */
|
|
if ( fread( env, 1, len, file ) );
|
|
#else
|
|
fread( env, 1, len, file );
|
|
#endif
|
|
env[len] = NULLC;
|
|
}
|
|
fclose( file );
|
|
if ( len == 0)
|
|
return( NULL );
|
|
/* zip through characters changing \r, \n etc into ' ' */
|
|
str = env;
|
|
while( *str ) {
|
|
ch = *str;
|
|
if( ch == '\r' || ch == '\n' ) {
|
|
*str = ' ';
|
|
}
|
|
#if HANDLECTRLZ
|
|
if( ch == 0x1A ) { /* if end of file */
|
|
*str = '\0'; /* - mark end of str */
|
|
break;
|
|
}
|
|
#endif
|
|
++str;
|
|
}
|
|
return( env );
|
|
}
|
|
|
|
/* current cmdline string is done, get the next one! */
|
|
|
|
static const char *getnextcmdstring( const char **cmdline )
|
|
/*********************************************************/
|
|
{
|
|
const char **src;
|
|
const char **dst;
|
|
|
|
/* something onto the response file stack? */
|
|
if ( rspidx ) {
|
|
rspidx--;
|
|
if ( cmdbuffers[rspidx] )
|
|
MemFree( (void *)cmdbuffers[rspidx] );
|
|
return( cmdsave[rspidx] );
|
|
}
|
|
for ( dst = cmdline, src = cmdline+1; *src; )
|
|
*dst++ = *src++;
|
|
*dst = *src;
|
|
return( *cmdline );
|
|
}
|
|
|
|
static const char *GetNumber( const char *p )
|
|
/*******************************************/
|
|
{
|
|
OptValue = 0;
|
|
for( ;*p >= '0' && *p <= '9'; p++ )
|
|
OptValue = OptValue * 10 + *p - '0';
|
|
return( p );
|
|
}
|
|
|
|
#if SWITCHCHAR
|
|
#define IsOptionDelimiter( x ) (x == ' ' || x == '-' || x == '/' || x == NULLC || x == '\t' )
|
|
#else
|
|
#define IsOptionDelimiter( x ) (x == ' ' || x == '-' || x == NULLC || x == '\t' )
|
|
#endif
|
|
|
|
/* scan option table and if option is known, process it */
|
|
|
|
static void ProcessOption( const char **cmdline, char *buffer )
|
|
/*************************************************************/
|
|
{
|
|
int i;
|
|
int j;
|
|
const char *p = *cmdline;
|
|
const char *opt;
|
|
//char c;
|
|
|
|
DebugMsg(("ProcessOption(%s)\n", p ));
|
|
|
|
/* numeric option (-0, -1, ... ) handled separately since
|
|
* the value can be >= 10.
|
|
*/
|
|
if ( *p >= '0' && *p <= '9' ) {
|
|
p = GetNumber( p );
|
|
if ( OptValue < sizeof(cpuoption)/sizeof(cpuoption[0]) ) {
|
|
p = GetNameToken( buffer, p, 16, 0 ); /* get optional 'p' */
|
|
*cmdline = p;
|
|
SetCpuCmdline( cpuoption[OptValue], buffer );
|
|
return;
|
|
}
|
|
p = *cmdline; /* v2.11: restore option pointer */
|
|
}
|
|
for( i = 0; i < ( sizeof(cmdl_options) / sizeof(cmdl_options[0]) ); i++ ) {
|
|
//DebugMsg(("ProcessOption(%s): %s\n", p, opt ));
|
|
if( *p == *cmdl_options[i].name ) {
|
|
for ( opt = cmdl_options[i].name+1, j = 1 ; isalnum(*opt) && *opt == p[j]; opt++, j++ );
|
|
/* make sure end of option is reached */
|
|
if ( isalnum(*opt) )
|
|
continue;
|
|
p += j;
|
|
OptValue = cmdl_options[i].value;
|
|
//DebugMsg(("ProcessOption(%s): Option found\n", p ));
|
|
for( ;; opt++) {
|
|
switch ( *opt ) {
|
|
//case '*': /* don't know what this is supposed to do? */
|
|
case NULLC:
|
|
if ( !IsOptionDelimiter( *p ) )
|
|
goto opt_error_exit;
|
|
*cmdline = p;
|
|
cmdl_options[i].function();
|
|
return; /* option processed successfully */
|
|
break;
|
|
case '#': /* collect a number */
|
|
if( *p >= '0' && *p <= '9' )
|
|
p = GetNumber( p );
|
|
break;
|
|
case '$': /* collect an identifer+value */
|
|
case '@': /* collect a filename */
|
|
OptName = buffer;
|
|
#if 0 /* v2.05: removed */
|
|
if ( rspidx )
|
|
p = GetNameToken( buffer, p, FILENAME_MAX - 1, *opt );
|
|
else {
|
|
j = strlen( p );
|
|
memcpy( buffer, p, (j >= FILENAME_MAX) ? FILENAME_MAX : j + 1 );
|
|
p += j;
|
|
}
|
|
#else
|
|
/* v2.10: spaces in filename now handled inside GetNameToken() */
|
|
p = GetNameToken( buffer, p, FILENAME_MAX - 1, *opt );
|
|
#endif
|
|
break;
|
|
case '=': /* collect an optional '=' */
|
|
if ( *p == '=' || *p == '#' )
|
|
p++;
|
|
break;
|
|
case '^': /* skip spaces before argument */
|
|
while ( isspace(*p) ) p++;
|
|
if ( *p == NULLC ) {
|
|
p = getnextcmdstring( cmdline );
|
|
if ( p == NULL ) {
|
|
EmitWarn( 1, MISSING_ARGUMENT_FOR_CMDLINE_OPTION );
|
|
return;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
/* internal error: unknown format of option item! */
|
|
DebugMsg(( "ProcessOption: unknown option specifier: %s\n", opt ));
|
|
/**/myassert( 0 );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
opt_error_exit:
|
|
EmitWarn( 1, INVALID_CMDLINE_OPTION, *cmdline - 1 );
|
|
*cmdline = "";
|
|
return;
|
|
}
|
|
|
|
#if BUILD_TARGET
|
|
|
|
#define MAX_OS_NAME_SIZE 7
|
|
|
|
static void set_default_build_target( void )
|
|
/******************************************/
|
|
{
|
|
|
|
if( Options.names[OPTN_BUILD_TARGET] == NULL ) {
|
|
Options.names[OPTN_BUILD_TARGET] = MemAlloc( MAX_OS_NAME_SIZE + 1 );
|
|
#if defined(__OSI__)
|
|
if( __OS == OS_DOS ) {
|
|
strcpy( Options.names[OPTN_BUILD_TARGET], "DOS" );
|
|
} else if( __OS == OS_OS2 ) {
|
|
strcpy( Options.names[OPTN_BUILD_TARGET], "OS2" );
|
|
} else if( __OS == OS_NT ) {
|
|
strcpy( Options.names[OPTN_BUILD_TARGET], "NT" );
|
|
} else if( __OS == OS_WIN ) {
|
|
strcpy( Options.names[OPTN_BUILD_TARGET], "WINDOWS" );
|
|
} else {
|
|
strcpy( Options.names[OPTN_BUILD_TARGET], "XXX" );
|
|
}
|
|
#elif defined(__QNX__)
|
|
strcpy( Options.names[OPTN_BUILD_TARGET], "QNX" );
|
|
#elif defined(__LINUX__)
|
|
strcpy( Options.names[OPTN_BUILD_TARGET], "LINUX" );
|
|
#elif defined(__BSD__)
|
|
strcpy( Options.names[OPTN_BUILD_TARGET], "BSD" );
|
|
#elif defined(__OSX__) || defined(__APPLE__)
|
|
strcpy( Options.names[OPTN_BUILD_TARGET], "OSX" );
|
|
#elif defined(__DOS__)
|
|
strcpy( Options.names[OPTN_BUILD_TARGET], "DOS" );
|
|
#elif defined(__OS2__)
|
|
strcpy( Options.names[OPTN_BUILD_TARGET], "OS2" );
|
|
#elif defined(__NT__)
|
|
strcpy( Options.names[OPTN_BUILD_TARGET], "NT" );
|
|
#else
|
|
#error unknown host OS
|
|
#endif
|
|
}
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
/* parse cmdline:
|
|
* - process cmdline options
|
|
* - get filename argument
|
|
* - handle (nested) response files
|
|
*/
|
|
|
|
char * EXPQUAL ParseCmdline( const char **cmdline, int *pCntArgs )
|
|
/****************************************************************/
|
|
{
|
|
int i;
|
|
const char *str = *cmdline;
|
|
char paramfile[FILENAME_MAX];
|
|
|
|
for ( i = 0; i < NUM_FILE_TYPES; i++ )
|
|
if ( Options.names[i] != NULL ) {
|
|
MemFree( Options.names[i] );
|
|
Options.names[i] = NULL;
|
|
}
|
|
|
|
/* enable next line if debug log is to be active, but -dt cannot be set */
|
|
//Set_dt();
|
|
|
|
for( ; str; ) {
|
|
switch( *str ) {
|
|
case ' ':
|
|
case '\t':
|
|
str++;
|
|
break;
|
|
case NULLC:
|
|
str = getnextcmdstring( cmdline );
|
|
break;
|
|
case '-':
|
|
#if SWITCHCHAR
|
|
case '/':
|
|
#endif
|
|
str++;
|
|
*cmdline = str;
|
|
ProcessOption( cmdline, paramfile );
|
|
(*pCntArgs)++;
|
|
str = *cmdline;
|
|
break;
|
|
case '@':
|
|
if ( rspidx >= MAX_RSP_NESTING ) {
|
|
EmitErr( NESTING_LEVEL_TOO_DEEP );
|
|
*cmdline = "";
|
|
return( NULL );
|
|
}
|
|
str++;
|
|
#if 1 /* v2.06: was '0' in v2.05, now '1' again since it didn't work with quoted names */
|
|
/* todo: might be unnecessary since v.2.10, since GetNameToken() handles spaces inside filenames differently */
|
|
if ( rspidx ) {
|
|
cmdsave[rspidx] = GetNameToken( paramfile, str, sizeof( paramfile ) - 1, '@' );
|
|
} else {
|
|
strcpy( paramfile, str ); /* fixme: no overflow check */
|
|
cmdsave[rspidx] = str + strlen(str);
|
|
}
|
|
#else
|
|
cmdsave[rspidx] = GetNameToken( paramfile, str, sizeof( paramfile ) - 1, '@' );
|
|
#endif
|
|
cmdbuffers[rspidx] = NULL;
|
|
str = NULL;
|
|
if ( paramfile[0] )
|
|
str = getenv( paramfile );
|
|
if( str == NULL ) {
|
|
str = ReadParamFile( paramfile );
|
|
cmdbuffers[rspidx] = str;
|
|
if ( str == NULL ) {
|
|
str = cmdsave[rspidx];
|
|
break;
|
|
}
|
|
}
|
|
rspidx++;
|
|
break;
|
|
default: /* collect file name */
|
|
#if BUILD_TARGET
|
|
set_default_build_target();
|
|
#endif
|
|
#if 1 /* v2.06: activated (was removed in v2.05). Needed for quoted filenames */
|
|
if ( rspidx ) {
|
|
str = GetNameToken( paramfile, str, sizeof( paramfile ) - 1, '@' );
|
|
get_fname( OPTN_ASM_FN, paramfile );
|
|
} else {
|
|
int len;
|
|
len = strlen( str );
|
|
get_fname( OPTN_ASM_FN, str );
|
|
str += len;
|
|
}
|
|
#else
|
|
str = GetNameToken( paramfile, str, sizeof( paramfile ) - 1, '@' );
|
|
Options.names[ASM] = MemAlloc( strlen( paramfile ) + 1 );
|
|
strcpy( Options.names[ASM], paramfile );
|
|
#endif
|
|
DebugMsg(("ParseCmdLine: file=>%s< rest=>%s<\n", Options.names[ASM], str ? str : "NULL" ));
|
|
(*pCntArgs)++;
|
|
*cmdline = str;
|
|
return( Options.names[ASM] );
|
|
}
|
|
}
|
|
*cmdline = str;
|
|
return( NULL );
|
|
}
|
|
|
|
void EXPQUAL CmdlineFini( void )
|
|
/******************************/
|
|
/* Free resources allocated by cmdline options */
|
|
{
|
|
int i;
|
|
DebugMsg(("CmdLineFini enter\n" ));
|
|
for ( i = 0; i < NUM_FILE_TYPES; i++ ) {
|
|
if ( DefaultDir[i] != NULL ) {
|
|
MemFree( DefaultDir[i] );
|
|
DefaultDir[i] = NULL;
|
|
}
|
|
}
|
|
for ( i = 0; i < OPTN_LAST; i++ )
|
|
if ( Options.names[i] != NULL ) {
|
|
MemFree( Options.names[i] );
|
|
Options.names[i] = NULL;
|
|
}
|
|
for ( i = 0; i < OPTQ_LAST; i++ ) {
|
|
struct qitem *p;
|
|
struct qitem *q;
|
|
for ( q = Options.queues[i]; q; ) {
|
|
p = q->next;
|
|
MemFree( q );
|
|
q = p;
|
|
}
|
|
Options.queues[i] = NULL;
|
|
}
|
|
DebugMsg(("CmdLineFini exit\n" ));
|
|
return;
|
|
}
|
|
|