/* * Handle options which can be either /option- to disable or /option to * enable. Option-specific information is passed as parameters. Returns * non-zero if the option should be enabled or zero if it should be disabled. */ static int handle_on_off_option( int *hasBeenCalled, char *optName, int isOn ) /****************************************************************************/ { int rc = isOn; if( *hasBeenCalled ) { /*** Warn when one of /option and /option- overrides the other ***/ if( isOn ) { if( GetCharContext() == '-' ) { Warning( "Overriding /%s with /%s-", optName, optName ); rc = 0; } else { UngetCharContext(); } } else { if( GetCharContext() != '-' ) { Warning( "Overriding /%s- with /%s", optName, optName ); rc = 1; } else { UngetCharContext(); } } } else { /*** Handle /option- for the first time ***/ *hasBeenCalled = 1; if( GetCharContext() == '-' ) { rc = 0; } else { UngetCharContext(); } } return( rc ); }
/* * Parse the command string contained in the current context. */ void CmdStringParse( OPT_STORAGE *cmdOpts, int *itemsParsed ) /***********************************************************/ { int ch; char * filename; for( ;; ) { /*** Find the start of the next item ***/ CmdScanWhitespace(); ch = GetCharContext(); if( ch == '\0' ) break; MarkPosContext(); /* mark start of switch */ /*** Handle switches, command files, and input files ***/ if( ch == '-' || ch == '/' ) { /* switch */ if( OPT_PROCESS( cmdOpts ) != 0 ) { cmd_line_error(); } } else if( ch == '@' ) { /* command file */ filename = CmdScanFileNameWithoutQuotes(); PushContext(); if( OpenFileContext( filename ) ) { FatalError( "Cannot open '%s'.", filename ); } FreeMem( filename ); CmdStringParse( cmdOpts, itemsParsed ); PopContext(); } else if( ch == '"' ) { /* quoted option or file name */ ch = GetCharContext(); if( ch == '-' ) { Quoted = 1; if( OPT_PROCESS( cmdOpts ) != 0 ) { cmd_line_error(); } } else { UngetCharContext(); UngetCharContext(); filename = CmdScanFileName(); AddFile( TYPE_DEFAULT_FILE, filename ); FreeMem( filename ); } } else { /* input file */ UngetCharContext(); filename = CmdScanFileName(); AddFile( TYPE_DEFAULT_FILE, filename ); FreeMem( filename ); } (*itemsParsed)++; } CloseContext(); }
/* * Scan a number. No leading whitespace is allowed. Returns true if a * number was successfully parsed, or zero on error. */ int CmdScanNumber( unsigned *num ) /********************************/ { int digit; int numberScanned = 0; unsigned value = 0; unsigned base = 10; /* figure out if this is a hex number */ digit = GetCharContext(); if( digit == '0' ) { digit = GetCharContext(); if( digit == 'x' || digit == 'X' ) { digit = GetCharContext(); if( isxdigit( digit ) ) { base = 16; UngetCharContext(); } else { UngetCharContext(); UngetCharContext(); UngetCharContext(); } } else { UngetCharContext(); UngetCharContext(); } } else { UngetCharContext(); } /* convert the string to an integer */ for( ;; ) { digit = GetCharContext(); if( isdigit( digit ) ) { value *= base; value += digit - '0'; numberScanned = 1; } else if( base == 16 && isxdigit( digit ) ) { value *= base; value += tolower( digit ) - 'a' + 10; numberScanned = 1; } else { UngetCharContext(); break; } } if( numberScanned ) *num = value; return( numberScanned ); }
/* * Parse the command string contained in the current context. */ void CmdStringParse( OPT_STORAGE *cmdOpts, int *itemsParsed ) /***********************************************************/ { char ch; char * filename; char * str; for( ;; ) { /*** Find the start of the next item ***/ CmdScanWhitespace(); ch = GetCharContext(); if( ch == '\0' ) break; MarkPosContext(); /* mark start of switch */ /*** Handle switches, command files, and input files ***/ if( ch == '-' || ch == '/' ) { /* switch */ if( OPT_PROCESS( cmdOpts ) ) { /* * Switch didn't match, if user entered empty switch, * just be silent like MS's nmake does. */ ch = GetCharContext(); if( ch != '\0' && !isspace( ch ) ) { cmd_line_error(); } } } else if( ch == '@' ) { /* command file */ filename = CmdScanFileNameWithoutQuotes(); PushContext(); if( OpenFileContext( filename ) ) { FatalError( "Cannot open '%s'.", filename ); } FreeMem( filename ); CmdStringParse( cmdOpts, itemsParsed ); PopContext(); } else { /* targets and macros */ UngetCharContext(); str = CmdScanString(); add_string( &(cmdOpts->t010101010101_value), str, '\0' ); cmdOpts->t010101010101 = 1; } (*itemsParsed)++; } CloseContext(); }
/* * If the next character is ch, it is consumed and a non-zero value is * returned; otherwise, it is not consumed and zero is returned. */ int CmdScanRecogCharExact( int ch ) /*********************************/ { if( GetCharContext() == ch ) { return( 1 ); } else { UngetCharContext(); return( 0 ); } }
/* * If the next character is ch (in either uppercase or lowercase form), it * is consumed and a non-zero value is returned; otherwise, it is not * consumed and zero is returned. */ int CmdScanRecogChar( int ch ) /****************************/ { if( tolower( GetCharContext() ) == tolower( ch ) ) { return( 1 ); } else { UngetCharContext(); return( 0 ); } }
/* * Skip all whitespace characters, such that the next read will retrieve the * first non-whitespace character. */ void CmdScanWhitespace( void ) /****************************/ { int ch; do { ch = GetCharContext(); } while( isspace( ch ) && ch != '\0' ); if( ch != '\0' ) UngetCharContext(); }
/* * Parse combining parameters */ static int parse_combining( OPT_STORAGE *cmdOpts, int x ) /******************************************/ { char ch; x = x; /* * Make sure -L is translated correctly to -NOLOGO if it is * a first (or the only) parameter */ if( cmdOpts->l ) { cmdOpts->nologo = 1; } /* scan for combined options */ do { /* get next character */ ch = (char)toupper( (unsigned char)GetCharContext() ); switch( ch ) { case 'A': cmdOpts->a = 1; break; /* gml-option: A */ case 'B': cmdOpts->b = 1; break; /* gml-option: B */ case 'C': cmdOpts->c = 1; break; /* gml-option: C */ case 'D': cmdOpts->d = 1; break; /* gml-option: D */ case 'E': cmdOpts->e = 1; break; /* gml-option: E */ case 'I': cmdOpts->i = 1; break; /* gml-option: I */ case 'K': cmdOpts->k = 1; break; /* gml-option: K */ case 'L': cmdOpts->nologo = 1; break; /* gml-option: L */ case 'N': cmdOpts->n = 1; break; /* gml-option: N */ case 'P': cmdOpts->p = 1; break; /* gml-option: P */ case 'Q': cmdOpts->q = 1; break; /* gml-option: Q */ case 'R': cmdOpts->r = 1; break; /* gml-option: R */ case 'S': cmdOpts->s = 1; break; /* gml-option: S */ case 'T': cmdOpts->t = 1; break; /* gml-option: T */ case 'U': cmdOpts->u = 1; break; /* gml-option: U */ case 'Y': cmdOpts->y = 1; break; /* gml-option: Y */ case '\0': break; default: /* if character is space, return without an error */ if( isspace( ch ) ) return 1; return 0; } } while( ch != '\0' ); /* all went nicely, return success */ return 1; }
/* * Is this the end of an option chain? */ static int OPT_END( void ) /************************/ { int ch; ch = GetCharContext(); if( ch == '\0' ) return( 1 ); UngetCharContext(); if( isspace( ch ) ) return( 1 ); if( ch == '/' ) return( 1 ); if( ch == '-' ) return( 1 ); if( ch == '@' ) return( 1 ); if( ch == '"' ) return( 1 ); if( ch == '\'' ) return( 1 ); return( 0 ); }
/* * Scan an optional number. No leading whitespace is permitted. */ static int OPT_GET_NUMBER_DEFAULT( unsigned *p, unsigned value ) /**************************************************************/ { int ch; *p = value; ch = GetCharContext(); UngetCharContext(); if( isdigit( ch ) ) { if( CmdScanNumber( &value ) ) { *p = value; return( 1 ); } else { return( 0 ); } } return( 1 ); }
/* * Scan a string. No leading whitespace is allowed. Returns a pointer * to newly allocated memory containing the string. If leading whitespace * is found, returns NULL. Quotes embedded within a string must be escaped * by a preceding backslash; two consecutive backslashes are reduced to one. */ char *CmdScanString( void ) /*************************/ { const char quotechar = '"'; int ch; int inQuote = Quoted; /* true if inside a quoted string */ int backslash = 0; /* true if last char was a '\\' */ int start; /* context offset of string start */ char * buf = DupStrMem( "" ); size_t bufsize = 0; size_t offset = 0; /*** Return NULL if there's leading whitespace or no more data ***/ ch = GetCharContext(); if( !Quoted && isspace( ch ) ) { UngetCharContext(); return( NULL ); } else if( ch != '\0' ) { UngetCharContext(); } else { return( NULL ); } /*** Count the number of characters in the string ***/ start = GetPosContext(); for( ;; ) { ch = GetCharContext(); if( ch == 0 ) break; if( !inQuote && isspace( ch ) ) break; if( ch == quotechar ) { if( backslash ) { backslash = 0; /* handle \" within a string */ } else if( inQuote ) { if( Quoted ) { Quoted = 0; return( buf ); } inQuote = 0; /* end of a quoted portion */ } else { inQuote = 1; /* start of a quoted portion */ } buf = got_char( buf, &bufsize, offset, ch ); offset++; } else if( ch == '\\' ) { if( backslash ) { buf = got_char( buf, &bufsize, offset, ch ); offset++; backslash = 0; /* second '\\' of a pair */ if( GetCharContext() == quotechar ) buf = got_char( buf, &bufsize, offset++, '\\' ); UngetCharContext(); } else { backslash = 1; /* first '\\' of a pair */ } } else { if( backslash ) { buf = got_char( buf, &bufsize, offset, '\\' ); offset++; backslash = 0; } buf = got_char( buf, &bufsize, offset, ch ); offset++; } } if( backslash ) { /* store any leftover backslash */ buf = got_char( buf, &bufsize, offset, '\\' ); offset++; } if( ch != 0 ) UngetCharContext(); return( buf ); }
/* * Return the next character (forced to lowercase since LINK's options are * not case-sensitive) and advance to the next one. */ int OPT_GET_LOWER( void ) /***********************/ { return( tolower( (unsigned char)GetCharContext() ) ); }
/* * Return the next character and advance to the next one. */ static int OPT_GET_LOWER( void ) /******************************/ { return( GetCharContext() ); }