1 /****************************************************************************
2 *
3 * Open Watcom Project
4 *
5 * Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
6 *
7 * ========================================================================
8 *
9 * This file contains Original Code and/or Modifications of Original
10 * Code as defined in and that are subject to the Sybase Open Watcom
11 * Public License version 1.0 (the 'License'). You may not use this file
12 * except in compliance with the License. BY USING THIS FILE YOU AGREE TO
13 * ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
14 * provided with the Original Code and Modifications, and is also
15 * available at www.sybase.com/developer/opensource.
16 *
17 * The Original Code and all software distributed under the License are
18 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
19 * EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
20 * ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
22 * NON-INFRINGEMENT. Please see the License for the specific language
23 * governing rights and limitations under the License.
24 *
25 * ========================================================================
26 *
27 * Description: command line argument parser
28 *
29 ****************************************************************************/
30
31 //#include <stdarg.h>
32 #include <stddef.h>
33 #include <ctype.h>
34
35 #include "globals.h"
36 #include "memalloc.h"
37 #include "parser.h"
38 #include "msgtext.h"
39 #include "dbgcv.h"
40 #include "cmdline.h"
41 #include "myassert.h"
42 #include "input.h" /* GetFNamePart() */
43
44 //#ifdef __OSI__
45 // #include "ostype.h"
46 //#endif
47
48 #if defined(__UNIX__) || defined(__CYGWIN__) || defined(__DJGPP__)
49
50 #define HANDLECTRLZ 0
51 #define SWITCHCHAR 0
52
53 #else
54
55 #define HANDLECTRLZ 1
56 #define SWITCHCHAR 1
57
58 #endif
59
60 #ifdef __I86__
61 #define OPTQUAL __near
62 #else
63 #define OPTQUAL
64 #endif
65
66 extern char banner_printed;
67
68 struct global_options Options = {
69 /* quiet */ FALSE,
70 /* line_numbers */ FALSE,
71 /* debug_symbols */ 0,
72 /* debug_ext */ 0, /* v2.10 */
73 /* floating_point */ FPO_NO_EMULATION,
74
75 /* error_limit */ 50,
76 /* no error display */ FALSE,
77 /* warning_level */ 2,
78 /* warning_error */ FALSE,
79 #ifdef DEBUG_OUT
80 /* debug */ FALSE,
81 /* nobackpatch */ FALSE,
82 #if FASTPASS
83 /* nofastpass */ FALSE,
84 /* print_linestore */ FALSE,
85 #endif
86 /* max_passes */ 0,
87 /* skip_preprocessor */ 0,
88 /* log_all_files */ 0,
89 /* dump_reswords */ FALSE,
90 /* dump_reswords_hash */ FALSE,
91 /* dump_symbols */ FALSE,
92 /* dump_symbols_hash */ FALSE,
93 #endif
94 /* names */ {
95 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
96 #if BUILD_TARGET
97 NULL,
98 #endif
99 #if MANGLERSUPP
100 NULL
101 #endif
102 },
103 /* queues */ { NULL, NULL, NULL },
104 #if COCTALS
105 /* allow_c_octals */ FALSE,
106 #endif
107 /* no_comment_data_in_code_records */ FALSE,
108 /* no_opt_farcall */ FALSE,
109 /* no_dependencies */ // FALSE,
110 #if COFF_SUPPORT
111 /* no_file_entry */ FALSE,
112 /* no_static_procs */ FALSE,
113 /* no_section_aux_entry */ FALSE,
114 #endif
115 /* no_cdecl_decoration */ FALSE,
116 /* stdcall_decoration */ STDCALL_FULL,
117 /* no_export_decoration */ FALSE,
118 /* entry_decorated */ FALSE,
119 /* write_listing */ FALSE,
120 /* write_impdef */ FALSE,
121 /* case_sensitive */ FALSE,
122 /* convert_uppercase */ FALSE,
123 /* preprocessor_stdout */ FALSE,
124 /* masm51_compat */ FALSE,
125 /* strict_masm_compat */ FALSE,
126 /* masm_compat_gencode */ FALSE,
127 /* masm8_proc_visibility */ FALSE,
128
129 /* listif */ FALSE,
130 /* list_generated_code */ FALSE,
131 /* list_macro */ LM_LISTMACRO,
132 /* no_symbol_listing */ FALSE,
133 /* first_pass_listing */ FALSE,
134 /* no_final_msg_listing */ FALSE, /* v2.13 */
135
136 /* all_symbols_public */ FALSE,
137 /* safeseh */ FALSE,
138 /* ignore_include */ FALSE,
139 /* output_format */ OFORMAT_OMF,
140 /* sub_format */ SFORMAT_NONE,
141 /* alignment_default */ 0,
142 /* langtype */ LANG_NONE,
143 /* model */ MODEL_NONE,
144 /* cpu */ P_86,
145 /* fastcall type */ FCT_MSC,
146 /* syntax check only */ FALSE,
147 #if MANGLERSUPP
148 /* naming_convention*/ NC_DO_NOTHING,
149 #endif
150 };
151
152 char *DefaultDir[NUM_FILE_TYPES] = { NULL, NULL, NULL, NULL };
153 //static char *DefaultExt[NUM_FILE_TYPES] = { OBJ_EXT, LST_EXT, ERR_EXT };
154
155 #define MAX_RSP_NESTING 15 /* nesting of response files */
156
157 static unsigned OptValue; /* value of option's numeric argument */
158 static char *OptName; /* value of option's name argument */
159 static const char *cmdsave[MAX_RSP_NESTING]; /* response files */
160 static const char *cmdbuffers[MAX_RSP_NESTING]; /* response files */
161 static int rspidx = 0; /* response file level */
162
163 /* array for options -0 ... -10 */
164 static const enum cpu_info cpuoption[] = {
165 P_86, P_186, P_286, P_386, /* 0-3 */
166 P_486, P_586, P_686, P_686 | P_MMX, /* 4-7 */
167 P_686 | P_MMX | P_SSE1, /* 8 */
168 P_686 | P_MMX | P_SSE1 | P_SSE2, /* 9 */
169 #if AMD64_SUPPORT
170 P_64, /* 10 */
171 #endif
172 };
173
174 #if 0 /* v2.10: removed, because factually never called */
StripQuotes(char * fname)175 static void StripQuotes( char *fname )
176 /************************************/
177 {
178 char *s;
179 char *d;
180
181 if( *fname == '"' ) {
182 /* string will shrink so we can reduce in place */
183 d = fname;
184 for( s = d + 1; *s && *s != '"'; ++s ) {
185 /* collapse double backslashes, only then look for escaped quotes */
186 if( s[0] == '\\' && s[1] == '\\' ) {
187 ++s;
188 } else if( s[0] == '\\' && s[1] == '"' ) {
189 ++s;
190 }
191 *d++ = *s;
192 }
193 *d = '\0';
194 }
195 }
196
GetAFileName(void)197 static char *GetAFileName( void )
198 /*******************************/
199 {
200 DebugMsg(("GetAFileName() enter, OptName=>%s<\n", OptName ));
201 StripQuotes( OptName );
202 return( OptName );
203 }
204 #else
205 #define GetAFileName() OptName
206 #endif
207
208 #if BUILD_TARGET
SetTargName(char * name,unsigned len)209 static void SetTargName( char *name, unsigned len )
210 /*************************************************/
211 {
212 if( Options.names[OPTN_BUILD_TARGET] != NULL ) {
213 MemFree( Options.names[OPTN_BUILD_TARGET] );
214 Options.names[OPTN_BUILD_TARGET] = NULL;
215 }
216 if( name == NULL || len == 0 )
217 return;
218 Options.names[OPTN_BUILD_TARGET] = MemAlloc( len + 1 );
219 strcpy( Options.names[OPTN_BUILD_TARGET], name );
220 _strupr( Options.names[OPTN_BUILD_TARGET] );
221 }
222 #endif
223
224 /* called by -0, -1, ... argument */
225
SetCpuCmdline(enum cpu_info value,const char * parm)226 static void SetCpuCmdline( enum cpu_info value, const char *parm )
227 /****************************************************************/
228 {
229
230 Options.cpu &= ~(P_CPU_MASK | P_EXT_MASK | P_PM);
231 Options.cpu |= value;
232
233 for( ; *parm ; parm++ ) {
234 if( *parm == 'p' && Options.cpu >= P_286 ) {
235 Options.cpu |= P_PM; /* set privileged mode */
236 #if MANGLERSUPP
237 } else if( *parm == '"' ) { /* set default mangler */
238 char *dest;
239 parm++;
240 dest = strchr( parm, '"' );
241 if( Options.names[OPTN_DEFNAME_MANGLER] != NULL ) {
242 MemFree( Options.names[OPTN_DEFNAME_MANGLER );
243 }
244 Options.names[OPTN_DEFNAME_MANGLER = MemAlloc( dest - parm + 1 );
245 dest = Options.names[OPTN_DEFNAME_MANGLER];
246 for( ; *parm != '"'; dest++, parm++ ) {
247 *dest = *parm;
248 }
249 *dest = NULLC;
250 #endif
251 } else {
252 EmitWarn( 1, CPU_OPTION_INVALID, parm );
253 break;
254 }
255 }
256 }
257
258 /* queue a text macro, include path or "forced" include files.
259 this is called for cmdline options -D, -I and -Fi
260 */
261
262 static void queue_item( int i, const char *string )
263 /*************************************************/
264 {
265 struct qitem *p;
266 struct qitem *q;
267
268 DebugMsg(("queue_item(%u, %s) enter\n", i, string));
269 p = MemAlloc( sizeof(struct qitem) + strlen( string ) );
270 p->next = NULL;
271 strcpy( p->value, string );
272 q = Options.queues[i];
273 if ( q ) {
274 for ( ; q->next; q = q->next );
275 q->next = p;
276 } else
277 Options.queues[i] = p;
278 return;
279 }
280
281 static void get_fname( int type, const char *token )
282 /**************************************************/
283 /*
284 * called by -Fo, -Fw or -Fl (for .OBJ, .ERR or .LST filenames ).
285 * also called by -Fd; in this case type is > NUM_FILE_TYPES!
286 * v2.12: _splitpath()/_makepath() removed.
287 */
288 {
289 const char *pName;
290 char name [ FILENAME_MAX ];
291
292 DebugMsg(("get_fname( type=%u, >%s< ) enter\n", type, token ));
293 //_splitpath( token, drive, dir, fname, ext );
294 pName = GetFNamePart( token );
295 /*
296 * If name's ending with a '\' (or '/' in Unix), it's supposed
297 * to be a directory name only.
298 */
299 if( *pName == NULLC ) {
300 DebugMsg(("get_fname(%u, >%s< ) name is empty or a directory\n", type, token ));
301 /* v2.10: ensure type is < NUM_FILE_TYPES */
302 if ( type < NUM_FILE_TYPES ) {
303 if ( DefaultDir[type] )
304 MemFree( DefaultDir[type]);
305 DefaultDir[type] = MemAlloc( strlen( token ) + 1 );
306 strcpy( DefaultDir[type], token );
307 }
308 return;
309 }
310 /* v2.10: ensure type is < NUM_FILE_TYPES */
311 //if ( drive[0] == NULLC && dir[0] == NULLC && type < NUM_FILE_TYPES && DefaultDir[type] ) {
312 name[0] = NULLC;
313 if ( pName == token && type < NUM_FILE_TYPES && DefaultDir[type] ) {
314 DebugMsg(("get_fname: default drive+dir used: %s\n" ));
315 //_splitpath( DefaultDir[type], drive, dir, NULL, NULL );
316 strcpy( name, DefaultDir[type] );
317 }
318 strcat( name, token );
319 #if 0 /* v2.12: extension will be set in SetFileNames() */
320 if( type && type < NUM_FILE_TYPES ) {
321 char *pExt = GetExtPart( name );
322 if ( *pExt == NULLC ) {
323 *pExt++ = '.';
324 strcpy( pExt, DefaultExt[type-1] );
325 }
326 }
327 #endif
328 //_makepath( name, drive, dir, fname, pExt );
329 if( Options.names[type] != NULL ) {
330 MemFree( Options.names[type] );
331 }
332 Options.names[type] = MemAlloc( strlen( name ) + 1 );
333 strcpy( Options.names[type], name );
334 }
335
336 static void set_option_n_name( int idx, const char *name )
337 /********************************************************/
338 /* option -n: set name of
339 * - nd: data seg
340 * - nm: module name
341 * - nt: text seg
342 * - nc: code class
343 */
344 {
345 if ( *name != '.' && !is_valid_id_char( *name ) ) {
346 EmitError( N_OPTION_NEEDS_A_NAME_PARAMETER );
347 return;
348 }
349
350 if( Options.names[idx] != NULL ) {
351 MemFree( Options.names[idx] );
352 }
353 Options.names[idx] = MemAlloc( strlen( name ) + 1 );
354 strcpy( Options.names[idx], name );
355 }
356
357 //static void OPTQUAL Ignore( void ) {};
358
359 #if BUILD_TARGET
360 static void OPTQUAL Set_bt( void ) { SetTargName( OptName, strlen(OptName) ); }
361 #endif
362
363 static void OPTQUAL Set_c( void ) { }
364
365 #ifdef DEBUG_OUT
366 static void OPTQUAL Set_ce( void ) { rspidx = 1 / rspidx; }
367 #endif
368
369 static void OPTQUAL Set_Cp( void ) { Options.case_sensitive = TRUE; Options.convert_uppercase = FALSE; }
370 static void OPTQUAL Set_Cu( void ) { Options.case_sensitive = FALSE; Options.convert_uppercase = TRUE; }
371 static void OPTQUAL Set_Cx( void ) { Options.case_sensitive = FALSE; Options.convert_uppercase = FALSE; }
372
373 static void OPTQUAL Set_Zd( void ) { Options.line_numbers = TRUE; }
374 static void OPTQUAL Set_Zi( void )
375 {
376 Set_Zd();
377 Options.debug_symbols = CV_SIGNATURE;
378 /* v2.10: added optional numeric argument for -Zi */
379 if ( OptValue <= CVEX_MAX )
380 Options.debug_ext = OptValue;
381 else
382 EmitWarn( 1, INVALID_CMDLINE_VALUE, "Zi" );
383 }
384
385 static void OPTQUAL Set_Zp( void )
386 /********************************/
387 {
388 uint_8 power;
389 for ( power = 0; (1 << power) <= MAX_STRUCT_ALIGN; power++ )
390 if ( ( 1 << power ) == OptValue ) {
391 Options.fieldalign = power;
392 return;
393 }
394 EmitWarn( 1, INVALID_CMDLINE_VALUE, "Zp" );
395 return;
396 }
397
398 static void OPTQUAL Set_D( void ) { queue_item( OPTQ_MACRO, GetAFileName() ); }
399 static void OPTQUAL Set_Fi( void ) { queue_item( OPTQ_FINCLUDE, GetAFileName() ); }
400 static void OPTQUAL Set_I( void ) { queue_item( OPTQ_INCPATH, GetAFileName() ); }
401
402 static void OPTQUAL Set_e( void ) { Options.error_limit = OptValue; }
403
404 static void OPTQUAL Set_nologo( void ) { banner_printed = TRUE; }
405 static void OPTQUAL Set_q( void ) { Set_nologo(); Options.quiet = TRUE; }
406 static void OPTQUAL Set_EP( void ) { Options.preprocessor_stdout = TRUE; Set_q(); }
407
408 #if DLLIMPORT
409 static void OPTQUAL Set_Fd( void ) { get_fname( OPTN_LNKDEF_FN, GetAFileName() ); Options.write_impdef = TRUE;}
410 #endif
411 static void OPTQUAL Set_Fw( void ) { get_fname( OPTN_ERR_FN, GetAFileName() ); }
412 static void OPTQUAL Set_Fl( void ) { get_fname( OPTN_LST_FN, GetAFileName() ); Options.write_listing = TRUE;}
413 static void OPTQUAL Set_Fo( void ) { get_fname( OPTN_OBJ_FN, GetAFileName() ); }
414
415 static void OPTQUAL Set_fp( void ) { Options.cpu &= ~P_FPU_MASK; Options.cpu = OptValue; }
416 static void OPTQUAL Set_FPx( void ) { Options.floating_point = OptValue; }
417 static void OPTQUAL Set_G( void ) { Options.langtype = OptValue; }
418
419 static void OPTQUAL Set_Sa( void )
420 /********************************/
421 {
422 Options.listif = TRUE;
423 Options.list_generated_code = TRUE;
424 Options.list_macro = LM_LISTMACROALL;
425 }
426
427 static void OPTQUAL Set_True( void )
428 /**********************************/
429 {
430 char *p = ((char *)&Options) + OptValue;
431 *p = TRUE;
432 }
433
434 static void OPTQUAL Set_m( void ) { Options.model = OptValue; }
435 static void OPTQUAL Set_n( void ) { set_option_n_name( OptValue, OptName ); }
436
437 #ifdef DEBUG_OUT
438 static void OPTQUAL Set_pm( void ) { Options.max_passes = OptValue; };
439 #endif
440
441 static void OPTQUAL Set_WX( void ) { Options.warning_error = TRUE; }
442
443 static void OPTQUAL Set_w( void ) { Set_WX(); Options.warning_level = 0; }
444
445 static void OPTQUAL Set_W( void )
446 /*******************************/
447 {
448 if ( OptValue <= 4 )
449 Options.warning_level = OptValue;
450 else
451 EmitWarn( 1, INVALID_CMDLINE_VALUE, "W" );
452 }
453
454 static void OPTQUAL Set_ofmt( void )
455 /**********************************/
456 {
457 Options.output_format = OptValue & 0xff;
458 Options.sub_format = OptValue >> 8;
459 }
460
461 static void OPTQUAL Set_zcm( void ) { Options.no_cdecl_decoration = FALSE; }
462 #if OWFC_SUPPORT
463 static void OPTQUAL Set_zf( void ) { Options.fctype = OptValue; }
464 #endif
465
466 static void OPTQUAL Set_zt( void ) { Options.stdcall_decoration = OptValue; }
467 #ifndef __SW_BD
468 static void OPTQUAL Set_h( void ) { PrintUsage(); exit(1); }
469 #endif
470
471 #ifdef DEBUG_OUT
472 static void OPTQUAL Set_dm( void )
473 {
474 int i;
475 for ( i = 0; i < MSG_LAST; i++ ) {
476 printf("%3u: %s\n", i, MsgGetEx(i) );
477 }
478 }
479 static void OPTQUAL Set_dt( void )
480 /********************************/
481 {
482 Options.debug = TRUE;
483 ModuleInfo.cref = TRUE; /* enable debug displays */
484 DebugMsg(( "debugging output on\n" ));
485 }
486 #if FASTPASS
487 static void OPTQUAL Set_nfp( void )
488 /*********************************/
489 {
490 Options.nofastpass = TRUE;
491 DebugMsg(( "FASTPASS disabled\n" ));
492 }
493 #endif
494 static void OPTQUAL Set_nbp( void )
495 /*********************************/
496 {
497 Options.nobackpatch = TRUE;
498 DebugMsg(( "backpatching disabled\n" ));
499 }
500 #endif
501
502 struct cmdloption {
503 const char *name;
504 unsigned value;
505 void OPTQUAL (*function)( void );
506 };
507
508 #define optofs( x ) offsetof( struct global_options, x )
509
510 /*
511 * '#': collect a number
512 * '$': collect an identifer[=value]
513 * '@': collect a filename
514 * '=': collect an optional '='
515 * '^': skip spaces before argument
516 */
517 static struct cmdloption const cmdl_options[] = {
518 #ifndef __SW_BD
519 { "?", 0, Set_h },
520 #endif
521 #ifdef DEBUG_OUT
522 { "af", optofs( log_all_files ), Set_True },
523 #endif
524 #if BIN_SUPPORT
525 { "bin", OFORMAT_BIN | (SFORMAT_NONE << 8), Set_ofmt },
526 #endif
527 #if BUILD_TARGET
528 { "bt=$", 0, Set_bt },
529 #endif
530 { "Cp", 0, Set_Cp },
531 { "Cu", 0, Set_Cu },
532 { "Cx", 0, Set_Cx },
533 #ifdef DEBUG_OUT
534 { "ce", 0, Set_ce },
535 #endif
536 #if COFF_SUPPORT
537 { "coff", OFORMAT_COFF | (SFORMAT_NONE << 8), Set_ofmt },
538 #endif
539 { "c", 0, Set_c },
540 #if COFF_SUPPORT && DJGPP_SUPPORT
541 { "djgpp", OFORMAT_COFF | (SFORMAT_DJGPP << 8), Set_ofmt },
542 #endif
543 #ifdef DEBUG_OUT
544 { "dm", 0, Set_dm },
545 { "drh", optofs( dump_reswords_hash ), Set_True },
546 { "dr", optofs( dump_reswords ), Set_True },
547 { "dsh", optofs( dump_symbols_hash ), Set_True },
548 { "ds", optofs( dump_symbols ), Set_True },
549 { "dt", 0, Set_dt },
550 #endif
551 { "D^$", 0, Set_D },
552 #if ELF_SUPPORT
553 #if AMD64_SUPPORT
554 { "elf64", OFORMAT_ELF | (SFORMAT_64BIT << 8), Set_ofmt },
555 #endif
556 { "elf", OFORMAT_ELF | (SFORMAT_NONE << 8), Set_ofmt },
557 #endif
558 { "EP", 0, Set_EP },
559 { "eq", optofs( no_error_disp ), Set_True },
560 { "e=#", 0, Set_e },
561 #if DLLIMPORT
562 { "Fd=@", 0, Set_Fd },
563 #endif
564 { "Fi=^@", 0, Set_Fi },
565 { "Fl=@", 0, Set_Fl },
566 { "Fo=^@", 0, Set_Fo },
567 { "FPi87", FPO_NO_EMULATION, Set_FPx },
568 { "FPi", FPO_EMULATION, Set_FPx },
569 { "fp0", P_87, Set_fp },
570 { "fp2", P_287, Set_fp },
571 { "fp3", P_387, Set_fp },
572 #if 0
573 { "fp5", P_387, Set_fp },
574 { "fp6", P_387, Set_fp },
575 #endif
576 { "fpc", P_NO87, Set_fp },
577 { "Fw=^@", 0, Set_Fw },
578 { "Gc", LANG_PASCAL, Set_G },
579 { "Gd", LANG_C, Set_G },
580 { "Gr", LANG_FASTCALL,Set_G },
581 { "Gz", LANG_STDCALL, Set_G },
582 { "h", 0, Set_h },
583 { "I=^@", 0, Set_I },
584 #ifdef DEBUG_OUT
585 #if FASTPASS
586 { "ls", optofs( print_linestore ), Set_True },
587 #endif
588 #endif
589 { "mc", MODEL_COMPACT, Set_m },
590 { "mf", MODEL_FLAT, Set_m },
591 { "mh", MODEL_HUGE, Set_m },
592 { "ml", MODEL_LARGE, Set_m },
593 { "mm", MODEL_MEDIUM, Set_m },
594 { "ms", MODEL_SMALL, Set_m },
595 { "mt", MODEL_TINY, Set_m },
596 #if BIN_SUPPORT
597 #if MZ_SUPPORT
598 { "mz", OFORMAT_BIN | (SFORMAT_MZ << 8), Set_ofmt },
599 #endif
600 #endif
601 #ifdef DEBUG_OUT
602 { "nbp", 0, Set_nbp },
603 #endif
604 { "nc=$", OPTN_CODE_CLASS, Set_n },
605 { "nd=$", OPTN_DATA_SEG, Set_n },
606 #if FASTPASS && defined(DEBUG_OUT)
607 { "nfp", 0, Set_nfp },
608 #endif
609 { "nm=$", OPTN_MODULE_NAME, Set_n },
610 { "nologo", 0, Set_nologo },
611 { "nt=$", OPTN_TEXT_SEG, Set_n },
612 { "omf", OFORMAT_OMF | (SFORMAT_NONE << 8), Set_ofmt },
613 #if COCTALS
614 { "o", optofs( allow_c_octals ), Set_True },
615 #endif
616 #if PE_SUPPORT
617 { "pe", OFORMAT_BIN | (SFORMAT_PE << 8), Set_ofmt },
618 #endif
619 #ifdef DEBUG_OUT
620 { "pm=#", 0, Set_pm },
621 #endif
622 { "q", 0, Set_q },
623 { "Sa", 0, Set_Sa },
624 { "Sf", optofs( first_pass_listing ), Set_True },
625 { "Sg", optofs( list_generated_code ), Set_True },
626 { "Sn", optofs( no_symbol_listing ), Set_True },
627 { "Sx", optofs( listif ), Set_True },
628 { "Sz", optofs( no_final_msg_listing), Set_True }, /* v2.13 */
629 #if COFF_SUPPORT
630 { "safeseh",optofs( safeseh ), Set_True },
631 #endif
632 #ifdef DEBUG_OUT
633 { "sp", optofs( skip_preprocessor ), Set_True },
634 #endif
635 { "WX", 0, Set_WX },
636 { "W=#", 0, Set_W },
637 #if AMD64_SUPPORT
638 { "win64", OFORMAT_COFF | (SFORMAT_64BIT << 8), Set_ofmt },
639 #endif
640 { "w", 0, Set_w },
641 { "X", optofs( ignore_include ), Set_True },
642 { "Zd", 0, Set_Zd },
643 { "Zf", optofs( all_symbols_public ), Set_True },
644 { "Zg", optofs( masm_compat_gencode ), Set_True },
645 { "Zi=#", CVEX_NORMAL, Set_Zi },
646 { "Zm", optofs( masm51_compat ), Set_True },
647 { "Zne", optofs( strict_masm_compat ), Set_True },
648 { "Zp=#", 0, Set_Zp },
649 { "zcm", 0, Set_zcm },
650 { "zcw", optofs( no_cdecl_decoration ), Set_True },
651 #if OWFC_SUPPORT
652 { "zf0", FCT_MSC, Set_zf },
653 { "zf1", FCT_WATCOMC, Set_zf },
654 #endif
655 { "zlc", optofs( no_comment_data_in_code_records ), Set_True },
656 { "zld", optofs( no_opt_farcall ), Set_True },
657 #if COFF_SUPPORT
658 { "zlf", optofs( no_file_entry ), Set_True },
659 { "zlp", optofs( no_static_procs ), Set_True }, /* v2.10: added */
660 { "zls", optofs( no_section_aux_entry ), Set_True },
661 #endif
662 { "Zs", optofs( syntax_check_only ), Set_True },
663 { "zt0", STDCALL_NONE, Set_zt },
664 { "zt1", STDCALL_HALF, Set_zt },
665 { "zt2", STDCALL_FULL, Set_zt },
666 { "Zv8", optofs( masm8_proc_visibility ), Set_True },
667 { "zze", optofs( no_export_decoration ), Set_True },
668 #if COFF_SUPPORT
669 { "zzs", optofs( entry_decorated ), Set_True },
670 #endif
671 // { NULL, 0, 0 }
672 };
673
674 /*
675 * get a "name"
676 * type=@ : filename ( -Fd, -Fi, -Fl, -Fo, -Fw, -I )
677 * type=$ : (macro) identifier [=value] ( -D, -nc, -nd, -nm, -nt )
678 * type=0 : something else ( -0..-10 )
679 */
680 static const char *GetNameToken( char *dst, const char *str, int max, char type )
681 /*******************************************************************************/
682 {
683 bool equatefound = FALSE;
684
685 DebugMsg(("GetNameToken( %s, %u, '%c' ) enter, rspidx=%u\n", str, max, type, rspidx ));
686 //while( isspace( *str ) ) ++str; /* no spaces allowed! */
687 is_quote:
688 if( *str == '"' ) {
689 ++str;
690 for( ; max && *str; max-- ) {
691 if ( *str == '"' ) {
692 ++str;
693 break;
694 }
695 /* handle the \" case */
696 if ( *str == '\\' && *(str+1) == '"' ) {
697 ++str;
698 }
699 *dst++ = *str++;
700 }
701 } else {
702 for( ; max; max-- ) {
703 /* v2.10: don't stop for white spaces */
704 //if ( *str == NULLC || *str == ' ' || *str == '\t' )
705 if ( *str == NULLC )
706 break;
707 /* v2.10: don't stop for white spaces if filename is expected and true cmdline is parsed */
708 if ( ( *str == ' ' || *str == '\t' ) && ( rspidx || type != '@' ) )
709 break;
710 if ( type == 0 )
711 if ( *str == '-'
712 #if SWITCHCHAR
713 || *str == '/'
714 #endif
715 )
716 break;
717 if ( *str == '=' && type == '$' && equatefound == FALSE ) {
718 equatefound = TRUE;
719 *dst++ = *str++;
720 if (*str == '"')
721 goto is_quote;
722 }
723 *dst++ = *str++;
724 }
725 }
726 *dst = NULLC;
727 return( str );
728 }
729
730 /*
731 * A '@' was found in the cmdline. It's not an environment variable,
732 * so check if it is a file and, if yes, read it.
733 */
734
735 static char *ReadParamFile( const char *name )
736 /********************************************/
737 {
738 char *env;
739 char *str;
740 FILE *file;
741 int len;
742 char ch;
743
744 DebugMsg(("ReadParamFile(%s) enter\n"));
745
746 env = NULL;
747 file = fopen( name, "rb" );
748 if( file == NULL ) {
749 /* v2.10: changed to fatal error */
750 //EmitErr( CANNOT_OPEN_FILE, name, ErrnoStr() );
751 Fatal( CANNOT_OPEN_FILE, name, ErrnoStr() );
752 return( NULL );
753 }
754 len = 0;
755 if ( fseek( file, 0, SEEK_END ) == 0 ) {
756 len = ftell( file );
757 rewind( file );
758 env = MemAlloc( len + 1 );
759 #if defined(__GNUC__) /* gcc warns if return value of fread() is "ignored" */
760 if ( fread( env, 1, len, file ) )
761 ; /* 2.12: semi-colon needs extra line to avoid warning msg */
762 #else
763 fread( env, 1, len, file );
764 #endif
765 env[len] = NULLC;
766 }
767 fclose( file );
768 if ( len == 0)
769 return( NULL );
770 /* zip through characters changing \r, \n etc into ' ' */
771 str = env;
772 while( *str ) {
773 ch = *str;
774 if( ch == '\r' || ch == '\n' ) {
775 *str = ' ';
776 }
777 #if HANDLECTRLZ
778 if( ch == 0x1A ) { /* if end of file */
779 *str = '\0'; /* - mark end of str */
780 break;
781 }
782 #endif
783 ++str;
784 }
785 return( env );
786 }
787
788 /* current cmdline string is done, get the next one! */
789
790 static const char *getnextcmdstring( const char **cmdline )
791 /*********************************************************/
792 {
793 const char **src;
794 const char **dst;
795
796 /* something onto the response file stack? */
797 if ( rspidx ) {
798 rspidx--;
799 if ( cmdbuffers[rspidx] )
800 MemFree( (void *)cmdbuffers[rspidx] );
801 return( cmdsave[rspidx] );
802 }
803 for ( dst = cmdline, src = cmdline+1; *src; )
804 *dst++ = *src++;
805 *dst = *src;
806 return( *cmdline );
807 }
808
809 static const char *GetNumber( const char *p )
810 /*******************************************/
811 {
812 OptValue = 0;
813 for( ;*p >= '0' && *p <= '9'; p++ )
814 OptValue = OptValue * 10 + *p - '0';
815 return( p );
816 }
817
818 #if SWITCHCHAR
819 #define IsOptionDelimiter( x ) (x == ' ' || x == '-' || x == '/' || x == NULLC || x == '\t' )
820 #else
821 #define IsOptionDelimiter( x ) (x == ' ' || x == '-' || x == NULLC || x == '\t' )
822 #endif
823
824 /* scan option table and if option is known, process it */
825
826 static void ProcessOption( const char **cmdline, char *buffer )
827 /*************************************************************/
828 {
829 int i;
830 int j;
831 const char *p = *cmdline;
832 const char *opt;
833 //char c;
834
835 DebugMsg(("ProcessOption(%s)\n", p ));
836
837 /* numeric option (-0, -1, ... ) handled separately since
838 * the value can be >= 10.
839 */
840 if ( *p >= '0' && *p <= '9' ) {
841 p = GetNumber( p );
842 if ( OptValue < sizeof(cpuoption)/sizeof(cpuoption[0]) ) {
843 p = GetNameToken( buffer, p, 16, 0 ); /* get optional 'p' */
844 *cmdline = p;
845 SetCpuCmdline( cpuoption[OptValue], buffer );
846 return;
847 }
848 p = *cmdline; /* v2.11: restore option pointer */
849 }
850 for( i = 0; i < ( sizeof(cmdl_options) / sizeof(cmdl_options[0]) ); i++ ) {
851 //DebugMsg(("ProcessOption(%s): %s\n", p, opt ));
852 if( *p == *cmdl_options[i].name ) {
853 for ( opt = cmdl_options[i].name+1, j = 1 ; isalnum(*opt) && *opt == p[j]; opt++, j++ );
854 /* make sure end of option is reached */
855 if ( isalnum(*opt) )
856 continue;
857 p += j;
858 OptValue = cmdl_options[i].value;
859 //DebugMsg(("ProcessOption(%s): Option found\n", p ));
860 for( ;; opt++) {
861 switch ( *opt ) {
862 //case '*': /* don't know what this is supposed to do? */
863 case NULLC:
864 if ( !IsOptionDelimiter( *p ) )
865 goto opt_error_exit;
866 *cmdline = p;
867 cmdl_options[i].function();
868 return; /* option processed successfully */
869 break;
870 case '#': /* collect a number */
871 if( *p >= '0' && *p <= '9' )
872 p = GetNumber( p );
873 break;
874 case '$': /* collect an identifer+value */
875 case '@': /* collect a filename */
876 OptName = buffer;
877 #if 0 /* v2.05: removed */
878 if ( rspidx )
879 p = GetNameToken( buffer, p, FILENAME_MAX - 1, *opt );
880 else {
881 j = strlen( p );
882 memcpy( buffer, p, (j >= FILENAME_MAX) ? FILENAME_MAX : j + 1 );
883 p += j;
884 }
885 #else
886 /* v2.10: spaces in filename now handled inside GetNameToken() */
887 p = GetNameToken( buffer, p, FILENAME_MAX - 1, *opt );
888 #endif
889 break;
890 case '=': /* collect an optional '=' */
891 if ( *p == '=' || *p == '#' )
892 p++;
893 break;
894 case '^': /* skip spaces before argument */
895 while ( isspace(*p) ) p++;
896 if ( *p == NULLC ) {
897 p = getnextcmdstring( cmdline );
898 if ( p == NULL ) {
899 EmitWarn( 1, MISSING_ARGUMENT_FOR_CMDLINE_OPTION );
900 return;
901 }
902 }
903 break;
904 default:
905 /* internal error: unknown format of option item! */
906 DebugMsg(( "ProcessOption: unknown option specifier: %s\n", opt ));
907 /**/myassert( 0 );
908 break;
909 }
910 }
911 }
912 }
913 opt_error_exit:
914 EmitWarn( 1, INVALID_CMDLINE_OPTION, *cmdline - 1 );
915 *cmdline = "";
916 return;
917 }
918
919 #if BUILD_TARGET
920
921 #define MAX_OS_NAME_SIZE 7
922
923 static void set_default_build_target( void )
924 /******************************************/
925 {
926
927 if( Options.names[OPTN_BUILD_TARGET] == NULL ) {
928 Options.names[OPTN_BUILD_TARGET] = MemAlloc( MAX_OS_NAME_SIZE + 1 );
929 #if defined(__OSI__)
930 if( __OS == OS_DOS ) {
931 strcpy( Options.names[OPTN_BUILD_TARGET], "DOS" );
932 } else if( __OS == OS_OS2 ) {
933 strcpy( Options.names[OPTN_BUILD_TARGET], "OS2" );
934 } else if( __OS == OS_NT ) {
935 strcpy( Options.names[OPTN_BUILD_TARGET], "NT" );
936 } else if( __OS == OS_WIN ) {
937 strcpy( Options.names[OPTN_BUILD_TARGET], "WINDOWS" );
938 } else {
939 strcpy( Options.names[OPTN_BUILD_TARGET], "XXX" );
940 }
941 #elif defined(__QNX__)
942 strcpy( Options.names[OPTN_BUILD_TARGET], "QNX" );
943 #elif defined(__LINUX__)
944 strcpy( Options.names[OPTN_BUILD_TARGET], "LINUX" );
945 #elif defined(__BSD__)
946 strcpy( Options.names[OPTN_BUILD_TARGET], "BSD" );
947 #elif defined(__OSX__) || defined(__APPLE__)
948 strcpy( Options.names[OPTN_BUILD_TARGET], "OSX" );
949 #elif defined(__DOS__)
950 strcpy( Options.names[OPTN_BUILD_TARGET], "DOS" );
951 #elif defined(__OS2__)
952 strcpy( Options.names[OPTN_BUILD_TARGET], "OS2" );
953 #elif defined(__NT__)
954 strcpy( Options.names[OPTN_BUILD_TARGET], "NT" );
955 #else
956 #error unknown host OS
957 #endif
958 }
959 return;
960 }
961 #endif
962
963 /* parse cmdline:
964 * - process cmdline options
965 * - get filename argument
966 * - handle (nested) response files
967 */
968
969 char * EXPQUAL ParseCmdline( const char **cmdline, int *pCntArgs )
970 /****************************************************************/
971 {
972 int i;
973 const char *str = *cmdline;
974 char paramfile[FILENAME_MAX];
975
976 for ( i = 0; i < NUM_FILE_TYPES; i++ )
977 if ( Options.names[i] != NULL ) {
978 MemFree( Options.names[i] );
979 Options.names[i] = NULL;
980 }
981
982 /* enable next line if debug log is to be active, but -dt cannot be set */
983 //Set_dt();
984
985 for( ; str; ) {
986 switch( *str ) {
987 case ' ':
988 case '\t':
989 str++;
990 break;
991 case NULLC:
992 str = getnextcmdstring( cmdline );
993 break;
994 case '-':
995 #if SWITCHCHAR
996 case '/':
997 #endif
998 str++;
999 *cmdline = str;
1000 ProcessOption( cmdline, paramfile );
1001 (*pCntArgs)++;
1002 str = *cmdline;
1003 break;
1004 case '@':
1005 if ( rspidx >= MAX_RSP_NESTING ) {
1006 EmitErr( NESTING_LEVEL_TOO_DEEP );
1007 *cmdline = "";
1008 return( NULL );
1009 }
1010 str++;
1011 #if 1 /* v2.06: was '0' in v2.05, now '1' again since it didn't work with quoted names */
1012 /* todo: might be unnecessary since v.2.10, since GetNameToken() handles spaces inside filenames differently */
1013 if ( rspidx ) {
1014 cmdsave[rspidx] = GetNameToken( paramfile, str, sizeof( paramfile ) - 1, '@' );
1015 } else {
1016 strcpy( paramfile, str ); /* fixme: no overflow check */
1017 cmdsave[rspidx] = str + strlen(str);
1018 }
1019 #else
1020 cmdsave[rspidx] = GetNameToken( paramfile, str, sizeof( paramfile ) - 1, '@' );
1021 #endif
1022 cmdbuffers[rspidx] = NULL;
1023 str = NULL;
1024 if ( paramfile[0] )
1025 str = getenv( paramfile );
1026 if( str == NULL ) {
1027 str = ReadParamFile( paramfile );
1028 cmdbuffers[rspidx] = str;
1029 if ( str == NULL ) {
1030 str = cmdsave[rspidx];
1031 break;
1032 }
1033 }
1034 rspidx++;
1035 break;
1036 default: /* collect file name */
1037 #if BUILD_TARGET
1038 set_default_build_target();
1039 #endif
1040 #if 1 /* v2.06: activated (was removed in v2.05). Needed for quoted filenames */
1041 if ( rspidx ) {
1042 str = GetNameToken( paramfile, str, sizeof( paramfile ) - 1, '@' );
1043 get_fname( OPTN_ASM_FN, paramfile );
1044 } else {
1045 int len;
1046 len = strlen( str );
1047 get_fname( OPTN_ASM_FN, str );
1048 str += len;
1049 }
1050 #else
1051 str = GetNameToken( paramfile, str, sizeof( paramfile ) - 1, '@' );
1052 Options.names[ASM] = MemAlloc( strlen( paramfile ) + 1 );
1053 strcpy( Options.names[ASM], paramfile );
1054 #endif
1055 DebugMsg(("ParseCmdLine: file=>%s< rest=>%s<\n", Options.names[ASM], str ? str : "NULL" ));
1056 (*pCntArgs)++;
1057 *cmdline = str;
1058 return( Options.names[ASM] );
1059 }
1060 }
1061 *cmdline = str;
1062 return( NULL );
1063 }
1064
1065 void EXPQUAL CmdlineFini( void )
1066 /******************************/
1067 /* Free resources allocated by cmdline options */
1068 {
1069 int i;
1070 DebugMsg(("CmdLineFini enter\n" ));
1071 for ( i = 0; i < NUM_FILE_TYPES; i++ ) {
1072 if ( DefaultDir[i] != NULL ) {
1073 MemFree( DefaultDir[i] );
1074 DefaultDir[i] = NULL;
1075 }
1076 }
1077 for ( i = 0; i < OPTN_LAST; i++ )
1078 if ( Options.names[i] != NULL ) {
1079 MemFree( Options.names[i] );
1080 Options.names[i] = NULL;
1081 }
1082 for ( i = 0; i < OPTQ_LAST; i++ ) {
1083 struct qitem *p;
1084 struct qitem *q;
1085 for ( q = Options.queues[i]; q; ) {
1086 p = q->next;
1087 MemFree( q );
1088 q = p;
1089 }
1090 Options.queues[i] = NULL;
1091 }
1092 DebugMsg(("CmdLineFini exit\n" ));
1093 return;
1094 }
1095
1096