2010-06-09 00:52:24 +08:00
//===-- Args.cpp ------------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
2012-12-05 08:20:57 +08:00
# include "lldb/lldb-python.h"
2010-06-09 00:52:24 +08:00
// C Includes
2010-06-09 18:59:23 +08:00
# include <cstdlib>
2010-06-09 00:52:24 +08:00
// C++ Includes
// Other libraries and framework includes
// Project includes
2010-06-16 03:49:27 +08:00
# include "lldb/Interpreter/Args.h"
2010-06-09 00:52:24 +08:00
# include "lldb/Core/Stream.h"
# include "lldb/Core/StreamFile.h"
# include "lldb/Core/StreamString.h"
2013-01-29 07:47:25 +08:00
# include "lldb/DataFormatters/FormatManager.h"
2010-06-16 03:49:27 +08:00
# include "lldb/Interpreter/Options.h"
2010-06-09 00:52:24 +08:00
# include "lldb/Interpreter/CommandReturnObject.h"
2012-12-07 06:49:16 +08:00
# include "lldb/Target/Process.h"
//#include "lldb/Target/RegisterContext.h"
2013-11-02 10:23:02 +08:00
# include "lldb/Target/Frame.h"
2012-12-07 06:49:16 +08:00
# include "lldb/Target/Target.h"
//#include "lldb/Target/Thread.h"
2010-06-09 00:52:24 +08:00
using namespace lldb ;
using namespace lldb_private ;
//----------------------------------------------------------------------
// Args constructor
//----------------------------------------------------------------------
Args : : Args ( const char * command ) :
m_args ( ) ,
2011-04-12 13:54:46 +08:00
m_argv ( ) ,
m_args_quote_char ( )
2010-06-09 00:52:24 +08:00
{
2010-12-19 11:41:24 +08:00
if ( command )
SetCommandString ( command ) ;
2010-06-09 00:52:24 +08:00
}
Args : : Args ( const char * command , size_t len ) :
m_args ( ) ,
2011-04-12 13:54:46 +08:00
m_argv ( ) ,
m_args_quote_char ( )
2010-06-09 00:52:24 +08:00
{
2010-12-19 11:41:24 +08:00
if ( command & & len )
SetCommandString ( command , len ) ;
2010-06-09 00:52:24 +08:00
}
2011-04-12 13:54:46 +08:00
//----------------------------------------------------------------------
// We have to be very careful on the copy constructor of this class
// to make sure we copy all of the string values, but we can't copy the
// rhs.m_argv into m_argv since it will point to the "const char *" c
// strings in rhs.m_args. We need to copy the string list and update our
// own m_argv appropriately.
//----------------------------------------------------------------------
Args : : Args ( const Args & rhs ) :
m_args ( rhs . m_args ) ,
m_argv ( ) ,
m_args_quote_char ( rhs . m_args_quote_char )
{
UpdateArgvFromArgs ( ) ;
}
//----------------------------------------------------------------------
// We have to be very careful on the copy constructor of this class
// to make sure we copy all of the string values, but we can't copy the
// rhs.m_argv into m_argv since it will point to the "const char *" c
// strings in rhs.m_args. We need to copy the string list and update our
// own m_argv appropriately.
//----------------------------------------------------------------------
const Args &
Args : : operator = ( const Args & rhs )
{
// Make sure we aren't assigning to self
if ( this ! = & rhs )
{
m_args = rhs . m_args ;
m_args_quote_char = rhs . m_args_quote_char ;
UpdateArgvFromArgs ( ) ;
}
return * this ;
}
2010-06-09 00:52:24 +08:00
//----------------------------------------------------------------------
// Destructor
//----------------------------------------------------------------------
Args : : ~ Args ( )
{
}
void
Args : : Dump ( Stream * s )
{
2013-01-26 02:06:21 +08:00
const size_t argc = m_argv . size ( ) ;
for ( size_t i = 0 ; i < argc ; + + i )
2010-06-09 00:52:24 +08:00
{
s - > Indent ( ) ;
const char * arg_cstr = m_argv [ i ] ;
if ( arg_cstr )
2013-01-26 02:06:21 +08:00
s - > Printf ( " argv[%zi]= \" %s \" \n " , i , arg_cstr ) ;
2010-06-09 00:52:24 +08:00
else
2013-01-26 02:06:21 +08:00
s - > Printf ( " argv[%zi]=NULL \n " , i ) ;
2010-06-09 00:52:24 +08:00
}
s - > EOL ( ) ;
}
bool
2012-04-26 06:30:32 +08:00
Args : : GetCommandString ( std : : string & command ) const
2010-06-09 00:52:24 +08:00
{
command . clear ( ) ;
2013-01-26 02:06:21 +08:00
const size_t argc = GetArgumentCount ( ) ;
for ( size_t i = 0 ; i < argc ; + + i )
2010-06-09 00:52:24 +08:00
{
if ( i > 0 )
command + = ' ' ;
command + = m_argv [ i ] ;
}
return argc > 0 ;
}
2010-12-10 08:26:54 +08:00
bool
2012-04-26 06:30:32 +08:00
Args : : GetQuotedCommandString ( std : : string & command ) const
2010-12-10 08:26:54 +08:00
{
command . clear ( ) ;
2013-01-26 02:06:21 +08:00
const size_t argc = GetArgumentCount ( ) ;
2010-12-19 11:41:24 +08:00
for ( size_t i = 0 ; i < argc ; + + i )
2010-12-10 08:26:54 +08:00
{
if ( i > 0 )
2010-12-19 11:41:24 +08:00
command . append ( 1 , ' ' ) ;
char quote_char = GetArgumentQuoteCharAtIndex ( i ) ;
if ( quote_char )
2010-12-10 08:26:54 +08:00
{
2010-12-19 11:41:24 +08:00
command . append ( 1 , quote_char ) ;
command . append ( m_argv [ i ] ) ;
command . append ( 1 , quote_char ) ;
2010-12-10 08:26:54 +08:00
}
else
2010-12-19 11:41:24 +08:00
command . append ( m_argv [ i ] ) ;
2010-12-10 08:26:54 +08:00
}
return argc > 0 ;
}
2010-06-09 00:52:24 +08:00
void
Args : : SetCommandString ( const char * command , size_t len )
{
// Use std::string to make sure we get a NULL terminated string we can use
// as "command" could point to a string within a large string....
std : : string null_terminated_command ( command , len ) ;
SetCommandString ( null_terminated_command . c_str ( ) ) ;
}
void
Args : : SetCommandString ( const char * command )
{
m_args . clear ( ) ;
m_argv . clear ( ) ;
2010-12-19 11:41:24 +08:00
m_args_quote_char . clear ( ) ;
2010-06-09 00:52:24 +08:00
if ( command & & command [ 0 ] )
{
2010-12-19 11:41:24 +08:00
static const char * k_space_separators = " \t " ;
2012-01-20 03:22:41 +08:00
static const char * k_space_separators_with_slash_and_quotes = " \t \\ ' \" " ;
2010-12-19 11:41:24 +08:00
const char * arg_end = NULL ;
const char * arg_pos ;
for ( arg_pos = command ;
arg_pos & & arg_pos [ 0 ] ;
arg_pos = arg_end )
2010-06-09 00:52:24 +08:00
{
2010-12-19 11:41:24 +08:00
// Skip any leading space separators
const char * arg_start = : : strspn ( arg_pos , k_space_separators ) + arg_pos ;
// If there were only space separators to the end of the line, then
2010-06-09 00:52:24 +08:00
// we're done.
if ( * arg_start = = ' \0 ' )
break ;
2011-01-09 04:28:42 +08:00
// Arguments can be split into multiple discontiguous pieces,
2010-12-19 11:41:24 +08:00
// for example:
// "Hello ""World"
// this would result in a single argument "Hello World" (without/
// the quotes) since the quotes would be removed and there is
// not space between the strings. So we need to keep track of the
// current start of each argument piece in "arg_piece_start"
const char * arg_piece_start = arg_start ;
arg_pos = arg_piece_start ;
2010-06-09 00:52:24 +08:00
2010-12-19 11:41:24 +08:00
std : : string arg ;
// Since we can have multiple quotes that form a single command
// in a command like: "Hello "world'!' (which will make a single
// argument "Hello world!") we remember the first quote character
// we encounter and use that for the quote character.
char first_quote_char = ' \0 ' ;
char quote_char = ' \0 ' ;
bool arg_complete = false ;
do
2010-06-09 00:52:24 +08:00
{
2010-12-19 11:41:24 +08:00
arg_end = : : strcspn ( arg_pos , k_space_separators_with_slash_and_quotes ) + arg_pos ;
2010-06-09 00:52:24 +08:00
2010-12-19 11:41:24 +08:00
switch ( arg_end [ 0 ] )
{
default :
assert ( ! " Unhandled case statement, we must handle this... " ) ;
break ;
case ' \0 ' :
// End of C string
if ( arg_piece_start & & arg_piece_start [ 0 ] )
arg . append ( arg_piece_start ) ;
arg_complete = true ;
break ;
case ' \\ ' :
// Backslash character
switch ( arg_end [ 1 ] )
2010-06-09 00:52:24 +08:00
{
2010-12-19 11:41:24 +08:00
case ' \0 ' :
arg . append ( arg_piece_start ) ;
2012-03-16 01:10:48 +08:00
+ + arg_end ;
2010-12-19 11:41:24 +08:00
arg_complete = true ;
break ;
2010-06-09 00:52:24 +08:00
2010-12-19 11:41:24 +08:00
default :
2012-07-21 08:12:58 +08:00
if ( quote_char = = ' \0 ' )
{
arg . append ( arg_piece_start , arg_end - arg_piece_start ) ;
2013-06-19 02:24:04 +08:00
if ( arg_end [ 1 ] ! = ' \0 ' )
2012-07-21 08:12:58 +08:00
{
arg . append ( arg_end + 1 , 1 ) ;
arg_pos = arg_end + 2 ;
arg_piece_start = arg_pos ;
}
}
else
arg_pos = arg_end + 2 ;
2010-06-09 00:52:24 +08:00
break ;
2010-12-19 11:41:24 +08:00
}
break ;
case ' " ' :
case ' \' ' :
case ' ` ' :
// Quote characters
if ( quote_char )
{
// We found a quote character while inside a quoted
// character argument. If it matches our current quote
// character, this ends the effect of the quotes. If it
// doesn't we ignore it.
if ( quote_char = = arg_end [ 0 ] )
{
arg . append ( arg_piece_start , arg_end - arg_piece_start ) ;
// Clear the quote character and let parsing
// continue (we need to watch for things like:
// "Hello ""World"
// "Hello "World
// "Hello "'World'
// All of which will result in a single argument "Hello World"
quote_char = ' \0 ' ; // Note that we are no longer inside quotes
arg_pos = arg_end + 1 ; // Skip the quote character
arg_piece_start = arg_pos ; // Note we are starting from later in the string
2010-06-09 00:52:24 +08:00
}
2010-12-19 11:41:24 +08:00
else
2010-06-09 00:52:24 +08:00
{
2010-12-19 11:41:24 +08:00
// different quote, skip it and keep going
arg_pos = arg_end + 1 ;
}
}
else
{
// We found the start of a quote scope.
2011-01-09 04:28:42 +08:00
// Make sure there isn't a string that precedes
2010-12-19 11:41:24 +08:00
// the start of a quote scope like:
// Hello" World"
// If so, then add the "Hello" to the arg
if ( arg_end > arg_piece_start )
arg . append ( arg_piece_start , arg_end - arg_piece_start ) ;
// Enter into a quote scope
quote_char = arg_end [ 0 ] ;
if ( first_quote_char = = ' \0 ' )
first_quote_char = quote_char ;
arg_pos = arg_end ;
2012-01-20 03:22:41 +08:00
+ + arg_pos ; // Skip the quote character
2010-12-19 11:41:24 +08:00
arg_piece_start = arg_pos ; // Note we are starting from later in the string
// Skip till the next quote character
const char * end_quote = : : strchr ( arg_piece_start , quote_char ) ;
while ( end_quote & & end_quote [ - 1 ] = = ' \\ ' )
{
// Don't skip the quote character if it is
// preceded by a '\' character
end_quote = : : strchr ( end_quote + 1 , quote_char ) ;
}
if ( end_quote )
{
if ( end_quote > arg_piece_start )
2012-01-20 03:22:41 +08:00
arg . append ( arg_piece_start , end_quote - arg_piece_start ) ;
2010-12-19 11:41:24 +08:00
// If the next character is a space or the end of
// string, this argument is complete...
if ( end_quote [ 1 ] = = ' ' | | end_quote [ 1 ] = = ' \t ' | | end_quote [ 1 ] = = ' \0 ' )
2010-06-09 00:52:24 +08:00
{
2010-12-19 11:41:24 +08:00
arg_complete = true ;
arg_end = end_quote + 1 ;
2010-06-09 00:52:24 +08:00
}
else
{
2010-12-19 11:41:24 +08:00
arg_pos = end_quote + 1 ;
arg_piece_start = arg_pos ;
2010-06-09 00:52:24 +08:00
}
2010-12-19 11:41:24 +08:00
quote_char = ' \0 ' ;
2010-06-09 00:52:24 +08:00
}
2012-03-16 01:10:48 +08:00
else
{
// Consume the rest of the string as there was no terminating quote
arg . append ( arg_piece_start ) ;
arg_end = arg_piece_start + strlen ( arg_piece_start ) ;
arg_complete = true ;
}
2010-06-09 00:52:24 +08:00
}
2010-12-19 11:41:24 +08:00
break ;
2010-06-09 00:52:24 +08:00
2010-12-19 11:41:24 +08:00
case ' ' :
case ' \t ' :
if ( quote_char )
2010-06-09 00:52:24 +08:00
{
2010-12-19 11:41:24 +08:00
// We are currently processing a quoted character and found
// a space character, skip any spaces and keep trying to find
// the end of the argument.
arg_pos = : : strspn ( arg_end , k_space_separators ) + arg_end ;
2010-06-09 00:52:24 +08:00
}
2010-12-19 11:41:24 +08:00
else
2010-06-09 00:52:24 +08:00
{
2010-12-19 11:41:24 +08:00
// We are not inside any quotes, we just found a space after an
// argument
if ( arg_end > arg_piece_start )
arg . append ( arg_piece_start , arg_end - arg_piece_start ) ;
arg_complete = true ;
2010-06-09 00:52:24 +08:00
}
2010-12-19 11:41:24 +08:00
break ;
2010-06-09 00:52:24 +08:00
}
2010-12-19 11:41:24 +08:00
} while ( ! arg_complete ) ;
2010-06-09 00:52:24 +08:00
m_args . push_back ( arg ) ;
2010-12-19 11:41:24 +08:00
m_args_quote_char . push_back ( first_quote_char ) ;
2010-06-09 00:52:24 +08:00
}
2010-12-19 11:41:24 +08:00
UpdateArgvFromArgs ( ) ;
2010-06-09 00:52:24 +08:00
}
}
void
Args : : UpdateArgsAfterOptionParsing ( )
{
// Now m_argv might be out of date with m_args, so we need to fix that
arg_cstr_collection : : const_iterator argv_pos , argv_end = m_argv . end ( ) ;
arg_sstr_collection : : iterator args_pos ;
arg_quote_char_collection : : iterator quotes_pos ;
for ( argv_pos = m_argv . begin ( ) , args_pos = m_args . begin ( ) , quotes_pos = m_args_quote_char . begin ( ) ;
argv_pos ! = argv_end & & args_pos ! = m_args . end ( ) ;
+ + argv_pos )
{
const char * argv_cstr = * argv_pos ;
if ( argv_cstr = = NULL )
break ;
while ( args_pos ! = m_args . end ( ) )
{
const char * args_cstr = args_pos - > c_str ( ) ;
if ( args_cstr = = argv_cstr )
{
// We found the argument that matches the C string in the
// vector, so we can now look for the next one
+ + args_pos ;
+ + quotes_pos ;
break ;
}
else
{
quotes_pos = m_args_quote_char . erase ( quotes_pos ) ;
args_pos = m_args . erase ( args_pos ) ;
}
}
}
if ( args_pos ! = m_args . end ( ) )
m_args . erase ( args_pos , m_args . end ( ) ) ;
if ( quotes_pos ! = m_args_quote_char . end ( ) )
m_args_quote_char . erase ( quotes_pos , m_args_quote_char . end ( ) ) ;
}
void
Args : : UpdateArgvFromArgs ( )
{
m_argv . clear ( ) ;
arg_sstr_collection : : const_iterator pos , end = m_args . end ( ) ;
for ( pos = m_args . begin ( ) ; pos ! = end ; + + pos )
m_argv . push_back ( pos - > c_str ( ) ) ;
m_argv . push_back ( NULL ) ;
2010-12-19 11:41:24 +08:00
// Make sure we have enough arg quote chars in the array
if ( m_args_quote_char . size ( ) < m_args . size ( ) )
m_args_quote_char . resize ( m_argv . size ( ) ) ;
2010-06-09 00:52:24 +08:00
}
size_t
Args : : GetArgumentCount ( ) const
{
if ( m_argv . empty ( ) )
return 0 ;
return m_argv . size ( ) - 1 ;
}
const char *
Args : : GetArgumentAtIndex ( size_t idx ) const
{
if ( idx < m_argv . size ( ) )
return m_argv [ idx ] ;
return NULL ;
}
char
Args : : GetArgumentQuoteCharAtIndex ( size_t idx ) const
{
if ( idx < m_args_quote_char . size ( ) )
return m_args_quote_char [ idx ] ;
return ' \0 ' ;
}
char * *
Args : : GetArgumentVector ( )
{
if ( ! m_argv . empty ( ) )
return ( char * * ) & m_argv [ 0 ] ;
return NULL ;
}
const char * *
Args : : GetConstArgumentVector ( ) const
{
if ( ! m_argv . empty ( ) )
return ( const char * * ) & m_argv [ 0 ] ;
return NULL ;
}
void
Args : : Shift ( )
{
// Don't pop the last NULL terminator from the argv array
if ( m_argv . size ( ) > 1 )
{
m_argv . erase ( m_argv . begin ( ) ) ;
m_args . pop_front ( ) ;
2010-12-19 11:41:24 +08:00
if ( ! m_args_quote_char . empty ( ) )
m_args_quote_char . erase ( m_args_quote_char . begin ( ) ) ;
2010-06-09 00:52:24 +08:00
}
}
const char *
Args : : Unshift ( const char * arg_cstr , char quote_char )
{
m_args . push_front ( arg_cstr ) ;
m_argv . insert ( m_argv . begin ( ) , m_args . front ( ) . c_str ( ) ) ;
m_args_quote_char . insert ( m_args_quote_char . begin ( ) , quote_char ) ;
return GetArgumentAtIndex ( 0 ) ;
}
void
Args : : AppendArguments ( const Args & rhs )
{
const size_t rhs_argc = rhs . GetArgumentCount ( ) ;
for ( size_t i = 0 ; i < rhs_argc ; + + i )
AppendArgument ( rhs . GetArgumentAtIndex ( i ) ) ;
}
2011-11-04 05:22:33 +08:00
void
Args : : AppendArguments ( const char * * argv )
{
if ( argv )
{
for ( uint32_t i = 0 ; argv [ i ] ; + + i )
AppendArgument ( argv [ i ] ) ;
}
}
2010-06-09 00:52:24 +08:00
const char *
Args : : AppendArgument ( const char * arg_cstr , char quote_char )
{
return InsertArgumentAtIndex ( GetArgumentCount ( ) , arg_cstr , quote_char ) ;
}
const char *
Args : : InsertArgumentAtIndex ( size_t idx , const char * arg_cstr , char quote_char )
{
// Since we are using a std::list to hold onto the copied C string and
// we don't have direct access to the elements, we have to iterate to
// find the value.
arg_sstr_collection : : iterator pos , end = m_args . end ( ) ;
size_t i = idx ;
for ( pos = m_args . begin ( ) ; i > 0 & & pos ! = end ; + + pos )
- - i ;
pos = m_args . insert ( pos , arg_cstr ) ;
2010-12-19 11:41:24 +08:00
if ( idx > = m_args_quote_char . size ( ) )
{
m_args_quote_char . resize ( idx + 1 ) ;
m_args_quote_char [ idx ] = quote_char ;
}
else
m_args_quote_char . insert ( m_args_quote_char . begin ( ) + idx , quote_char ) ;
2010-06-09 00:52:24 +08:00
UpdateArgvFromArgs ( ) ;
return GetArgumentAtIndex ( idx ) ;
}
const char *
Args : : ReplaceArgumentAtIndex ( size_t idx , const char * arg_cstr , char quote_char )
{
// Since we are using a std::list to hold onto the copied C string and
// we don't have direct access to the elements, we have to iterate to
// find the value.
arg_sstr_collection : : iterator pos , end = m_args . end ( ) ;
size_t i = idx ;
for ( pos = m_args . begin ( ) ; i > 0 & & pos ! = end ; + + pos )
- - i ;
if ( pos ! = end )
{
pos - > assign ( arg_cstr ) ;
assert ( idx < m_argv . size ( ) - 1 ) ;
m_argv [ idx ] = pos - > c_str ( ) ;
2010-12-19 11:41:24 +08:00
if ( idx > = m_args_quote_char . size ( ) )
m_args_quote_char . resize ( idx + 1 ) ;
2010-06-09 00:52:24 +08:00
m_args_quote_char [ idx ] = quote_char ;
return GetArgumentAtIndex ( idx ) ;
}
return NULL ;
}
void
Args : : DeleteArgumentAtIndex ( size_t idx )
{
// Since we are using a std::list to hold onto the copied C string and
// we don't have direct access to the elements, we have to iterate to
// find the value.
arg_sstr_collection : : iterator pos , end = m_args . end ( ) ;
size_t i = idx ;
for ( pos = m_args . begin ( ) ; i > 0 & & pos ! = end ; + + pos )
- - i ;
if ( pos ! = end )
{
m_args . erase ( pos ) ;
assert ( idx < m_argv . size ( ) - 1 ) ;
m_argv . erase ( m_argv . begin ( ) + idx ) ;
2010-12-19 11:41:24 +08:00
if ( idx < m_args_quote_char . size ( ) )
m_args_quote_char . erase ( m_args_quote_char . begin ( ) + idx ) ;
2010-06-09 00:52:24 +08:00
}
}
void
2013-01-26 02:06:21 +08:00
Args : : SetArguments ( size_t argc , const char * * argv )
2010-06-09 00:52:24 +08:00
{
// m_argv will be rebuilt in UpdateArgvFromArgs() below, so there is
// no need to clear it here.
m_args . clear ( ) ;
m_args_quote_char . clear ( ) ;
// First copy each string
2011-11-04 05:22:33 +08:00
for ( size_t i = 0 ; i < argc ; + + i )
2010-06-09 00:52:24 +08:00
{
m_args . push_back ( argv [ i ] ) ;
2010-12-19 11:41:24 +08:00
if ( ( argv [ i ] [ 0 ] = = ' \' ' ) | | ( argv [ i ] [ 0 ] = = ' " ' ) | | ( argv [ i ] [ 0 ] = = ' ` ' ) )
2010-06-09 00:52:24 +08:00
m_args_quote_char . push_back ( argv [ i ] [ 0 ] ) ;
else
m_args_quote_char . push_back ( ' \0 ' ) ;
}
UpdateArgvFromArgs ( ) ;
}
2011-11-04 05:22:33 +08:00
void
Args : : SetArguments ( const char * * argv )
{
// m_argv will be rebuilt in UpdateArgvFromArgs() below, so there is
// no need to clear it here.
m_args . clear ( ) ;
m_args_quote_char . clear ( ) ;
if ( argv )
{
// First copy each string
for ( size_t i = 0 ; argv [ i ] ; + + i )
{
m_args . push_back ( argv [ i ] ) ;
if ( ( argv [ i ] [ 0 ] = = ' \' ' ) | | ( argv [ i ] [ 0 ] = = ' " ' ) | | ( argv [ i ] [ 0 ] = = ' ` ' ) )
m_args_quote_char . push_back ( argv [ i ] [ 0 ] ) ;
else
m_args_quote_char . push_back ( ' \0 ' ) ;
}
}
UpdateArgvFromArgs ( ) ;
}
2010-06-09 00:52:24 +08:00
Error
Args : : ParseOptions ( Options & options )
{
StreamString sstr ;
Error error ;
2013-09-06 00:42:23 +08:00
Option * long_options = options . GetLongOptions ( ) ;
2010-06-09 00:52:24 +08:00
if ( long_options = = NULL )
{
2011-10-26 08:56:27 +08:00
error . SetErrorStringWithFormat ( " invalid long options " ) ;
2010-06-09 00:52:24 +08:00
return error ;
}
2010-07-14 08:18:15 +08:00
for ( int i = 0 ; long_options [ i ] . name ! = NULL ; + + i )
2010-06-09 00:52:24 +08:00
{
if ( long_options [ i ] . flag = = NULL )
{
2012-12-06 04:24:57 +08:00
if ( isprint8 ( long_options [ i ] . val ) )
2010-06-09 00:52:24 +08:00
{
2012-12-04 08:32:51 +08:00
sstr < < ( char ) long_options [ i ] . val ;
switch ( long_options [ i ] . has_arg )
{
default :
2013-09-06 00:42:23 +08:00
case OptionParser : : eNoArgument : break ;
case OptionParser : : eRequiredArgument : sstr < < ' : ' ; break ;
case OptionParser : : eOptionalArgument : sstr < < " :: " ; break ;
2012-12-04 08:32:51 +08:00
}
2010-06-09 00:52:24 +08:00
}
}
}
2013-09-06 00:42:23 +08:00
OptionParser : : Prepare ( ) ;
2010-06-09 00:52:24 +08:00
int val ;
while ( 1 )
{
int long_options_index = - 1 ;
2013-09-06 00:42:23 +08:00
val = OptionParser : : Parse ( GetArgumentCount ( ) ,
2013-04-05 04:35:24 +08:00
GetArgumentVector ( ) ,
sstr . GetData ( ) ,
long_options ,
& long_options_index ) ;
2010-06-09 00:52:24 +08:00
if ( val = = - 1 )
break ;
// Did we get an error?
if ( val = = ' ? ' )
{
2011-10-26 08:56:27 +08:00
error . SetErrorStringWithFormat ( " unknown or ambiguous option " ) ;
2010-06-09 00:52:24 +08:00
break ;
}
// The option auto-set itself
if ( val = = 0 )
continue ;
( ( Options * ) & options ) - > OptionSeen ( val ) ;
// Lookup the long option index
if ( long_options_index = = - 1 )
{
for ( int i = 0 ;
long_options [ i ] . name | | long_options [ i ] . has_arg | | long_options [ i ] . flag | | long_options [ i ] . val ;
+ + i )
{
if ( long_options [ i ] . val = = val )
{
long_options_index = i ;
break ;
}
}
}
// Call the callback with the option
if ( long_options_index > = 0 )
{
error = options . SetOptionValue ( long_options_index ,
2013-09-06 00:42:23 +08:00
long_options [ long_options_index ] . has_arg = = OptionParser : : eNoArgument ? NULL : OptionParser : : GetOptionArgument ( ) ) ;
2010-06-09 00:52:24 +08:00
}
else
{
2011-10-26 08:56:27 +08:00
error . SetErrorStringWithFormat ( " invalid option with value '%i' " , val ) ;
2010-06-09 00:52:24 +08:00
}
if ( error . Fail ( ) )
break ;
}
// Update our ARGV now that get options has consumed all the options
2013-09-06 00:42:23 +08:00
m_argv . erase ( m_argv . begin ( ) , m_argv . begin ( ) + OptionParser : : GetOptionIndex ( ) ) ;
2010-06-09 00:52:24 +08:00
UpdateArgsAfterOptionParsing ( ) ;
return error ;
}
void
Args : : Clear ( )
{
m_args . clear ( ) ;
m_argv . clear ( ) ;
m_args_quote_char . clear ( ) ;
}
int32_t
Args : : StringToSInt32 ( const char * s , int32_t fail_value , int base , bool * success_ptr )
{
if ( s & & s [ 0 ] )
{
char * end = NULL ;
2013-01-26 02:06:21 +08:00
const long sval = : : strtol ( s , & end , base ) ;
2010-06-09 00:52:24 +08:00
if ( * end = = ' \0 ' )
{
2013-01-26 02:06:21 +08:00
if ( success_ptr )
* success_ptr = ( ( sval < = INT32_MAX ) & & ( sval > = INT32_MIN ) ) ;
return ( int32_t ) sval ; // All characters were used, return the result
2010-06-09 00:52:24 +08:00
}
}
if ( success_ptr ) * success_ptr = false ;
return fail_value ;
}
uint32_t
Args : : StringToUInt32 ( const char * s , uint32_t fail_value , int base , bool * success_ptr )
{
if ( s & & s [ 0 ] )
{
char * end = NULL ;
2013-01-26 02:06:21 +08:00
const unsigned long uval = : : strtoul ( s , & end , base ) ;
2010-06-09 00:52:24 +08:00
if ( * end = = ' \0 ' )
{
2013-01-26 02:06:21 +08:00
if ( success_ptr )
* success_ptr = ( uval < = UINT32_MAX ) ;
return ( uint32_t ) uval ; // All characters were used, return the result
2010-06-09 00:52:24 +08:00
}
}
if ( success_ptr ) * success_ptr = false ;
return fail_value ;
}
int64_t
Args : : StringToSInt64 ( const char * s , int64_t fail_value , int base , bool * success_ptr )
{
if ( s & & s [ 0 ] )
{
char * end = NULL ;
int64_t uval = : : strtoll ( s , & end , base ) ;
if ( * end = = ' \0 ' )
{
if ( success_ptr ) * success_ptr = true ;
return uval ; // All characters were used, return the result
}
}
if ( success_ptr ) * success_ptr = false ;
return fail_value ;
}
uint64_t
Args : : StringToUInt64 ( const char * s , uint64_t fail_value , int base , bool * success_ptr )
{
if ( s & & s [ 0 ] )
{
char * end = NULL ;
uint64_t uval = : : strtoull ( s , & end , base ) ;
if ( * end = = ' \0 ' )
{
if ( success_ptr ) * success_ptr = true ;
return uval ; // All characters were used, return the result
}
}
if ( success_ptr ) * success_ptr = false ;
return fail_value ;
}
lldb : : addr_t
2012-12-07 06:49:16 +08:00
Args : : StringToAddress ( const ExecutionContext * exe_ctx , const char * s , lldb : : addr_t fail_value , Error * error_ptr )
2010-06-09 00:52:24 +08:00
{
2012-12-07 06:49:16 +08:00
bool error_set = false ;
2010-06-09 00:52:24 +08:00
if ( s & & s [ 0 ] )
{
char * end = NULL ;
lldb : : addr_t addr = : : strtoull ( s , & end , 0 ) ;
if ( * end = = ' \0 ' )
{
2012-12-07 06:49:16 +08:00
if ( error_ptr )
error_ptr - > Clear ( ) ;
2010-06-09 00:52:24 +08:00
return addr ; // All characters were used, return the result
}
// Try base 16 with no prefix...
addr = : : strtoull ( s , & end , 16 ) ;
if ( * end = = ' \0 ' )
{
2012-12-07 06:49:16 +08:00
if ( error_ptr )
error_ptr - > Clear ( ) ;
2010-06-09 00:52:24 +08:00
return addr ; // All characters were used, return the result
}
2012-12-07 06:49:16 +08:00
if ( exe_ctx )
{
Target * target = exe_ctx - > GetTargetPtr ( ) ;
if ( target )
{
lldb : : ValueObjectSP valobj_sp ;
EvaluateExpressionOptions options ;
options . SetCoerceToId ( false ) ;
options . SetUnwindOnError ( true ) ;
options . SetKeepInMemory ( false ) ;
options . SetRunOthers ( true ) ;
ExecutionResults expr_result = target - > EvaluateExpression ( s ,
exe_ctx - > GetFramePtr ( ) ,
valobj_sp ,
options ) ;
bool success = false ;
if ( expr_result = = eExecutionCompleted )
{
// Get the address to watch.
addr = valobj_sp - > GetValueAsUnsigned ( fail_value , & success ) ;
if ( success )
{
if ( error_ptr )
error_ptr - > Clear ( ) ;
return addr ;
}
else
{
if ( error_ptr )
{
error_set = true ;
error_ptr - > SetErrorStringWithFormat ( " address expression \" %s \" resulted in a value whose type can't be converted to an address: %s " , s , valobj_sp - > GetTypeName ( ) . GetCString ( ) ) ;
}
}
}
else
{
// Since the compiler can't handle things like "main + 12" we should
// try to do this for now. The compliler doesn't like adding offsets
// to function pointer types.
2013-04-04 05:37:16 +08:00
static RegularExpression g_symbol_plus_offset_regex ( " ^(.*) ( [ - \ \ + ] ) [[:space:]]*(0x[0-9A-Fa-f]+|[0-9]+)[[:space:]] * $ " ) ;
RegularExpression : : Match regex_match ( 3 ) ;
if ( g_symbol_plus_offset_regex . Execute ( s , & regex_match ) )
2012-12-07 06:49:16 +08:00
{
uint64_t offset = 0 ;
bool add = true ;
std : : string name ;
std : : string str ;
2013-04-04 05:37:16 +08:00
if ( regex_match . GetMatchAtIndex ( s , 1 , name ) )
2012-12-07 06:49:16 +08:00
{
2013-04-04 05:37:16 +08:00
if ( regex_match . GetMatchAtIndex ( s , 2 , str ) )
2012-12-07 06:49:16 +08:00
{
add = str [ 0 ] = = ' + ' ;
2013-04-04 05:37:16 +08:00
if ( regex_match . GetMatchAtIndex ( s , 3 , str ) )
2012-12-07 06:49:16 +08:00
{
offset = Args : : StringToUInt64 ( str . c_str ( ) , 0 , 0 , & success ) ;
if ( success )
{
Error error ;
addr = StringToAddress ( exe_ctx , name . c_str ( ) , LLDB_INVALID_ADDRESS , & error ) ;
if ( addr ! = LLDB_INVALID_ADDRESS )
{
if ( add )
return addr + offset ;
else
return addr - offset ;
}
}
}
}
}
}
if ( error_ptr )
{
error_set = true ;
error_ptr - > SetErrorStringWithFormat ( " address expression \" %s \" evaluation failed " , s ) ;
}
}
}
}
}
if ( error_ptr )
{
if ( ! error_set )
error_ptr - > SetErrorStringWithFormat ( " invalid address expression \" %s \" " , s ) ;
2010-06-09 00:52:24 +08:00
}
return fail_value ;
}
2013-03-06 07:52:49 +08:00
const char *
Args : : StripSpaces ( std : : string & s , bool leading , bool trailing , bool return_null_if_empty )
{
static const char * k_white_space = " \t \v " ;
if ( ! s . empty ( ) )
{
if ( leading )
{
size_t pos = s . find_first_not_of ( k_white_space ) ;
if ( pos = = std : : string : : npos )
s . clear ( ) ;
else if ( pos > 0 )
s . erase ( 0 , pos ) ;
}
if ( trailing )
{
size_t rpos = s . find_last_not_of ( k_white_space ) ;
if ( rpos ! = std : : string : : npos & & rpos + 1 < s . size ( ) )
s . erase ( rpos + 1 ) ;
}
}
if ( return_null_if_empty & & s . empty ( ) )
return NULL ;
return s . c_str ( ) ;
}
2010-06-09 00:52:24 +08:00
bool
Args : : StringToBoolean ( const char * s , bool fail_value , bool * success_ptr )
{
if ( s & & s [ 0 ] )
{
if ( : : strcasecmp ( s , " false " ) = = 0 | |
: : strcasecmp ( s , " off " ) = = 0 | |
: : strcasecmp ( s , " no " ) = = 0 | |
: : strcmp ( s , " 0 " ) = = 0 )
{
if ( success_ptr )
* success_ptr = true ;
return false ;
}
else
if ( : : strcasecmp ( s , " true " ) = = 0 | |
: : strcasecmp ( s , " on " ) = = 0 | |
: : strcasecmp ( s , " yes " ) = = 0 | |
: : strcmp ( s , " 1 " ) = = 0 )
{
if ( success_ptr ) * success_ptr = true ;
return true ;
}
}
if ( success_ptr ) * success_ptr = false ;
return fail_value ;
}
2011-03-19 09:12:21 +08:00
const char *
Args : : StringToVersion ( const char * s , uint32_t & major , uint32_t & minor , uint32_t & update )
{
major = UINT32_MAX ;
minor = UINT32_MAX ;
update = UINT32_MAX ;
if ( s & & s [ 0 ] )
{
char * pos = NULL ;
2013-01-26 02:06:21 +08:00
unsigned long uval32 = : : strtoul ( s , & pos , 0 ) ;
2011-03-19 09:12:21 +08:00
if ( pos = = s )
return s ;
major = uval32 ;
if ( * pos = = ' \0 ' )
{
return pos ; // Decoded major and got end of string
}
else if ( * pos = = ' . ' )
{
const char * minor_cstr = pos + 1 ;
uval32 = : : strtoul ( minor_cstr , & pos , 0 ) ;
if ( pos = = minor_cstr )
return pos ; // Didn't get any digits for the minor version...
minor = uval32 ;
if ( * pos = = ' . ' )
{
const char * update_cstr = pos + 1 ;
uval32 = : : strtoul ( update_cstr , & pos , 0 ) ;
if ( pos = = update_cstr )
return pos ;
update = uval32 ;
}
return pos ;
}
}
return 0 ;
}
2011-11-15 11:53:30 +08:00
const char *
Args : : GetShellSafeArgument ( const char * unsafe_arg , std : : string & safe_arg )
{
safe_arg . assign ( unsafe_arg ) ;
size_t prev_pos = 0 ;
while ( prev_pos < safe_arg . size ( ) )
{
// Escape spaces and quotes
size_t pos = safe_arg . find_first_of ( " ' \" " , prev_pos ) ;
if ( pos ! = std : : string : : npos )
{
safe_arg . insert ( pos , 1 , ' \\ ' ) ;
prev_pos = pos + 2 ;
}
else
break ;
}
return safe_arg . c_str ( ) ;
}
2011-03-19 09:12:21 +08:00
2013-01-26 02:06:21 +08:00
int64_t
2011-10-08 02:58:12 +08:00
Args : : StringToOptionEnum ( const char * s , OptionEnumValueElement * enum_values , int32_t fail_value , Error & error )
2010-06-09 00:52:24 +08:00
{
2011-10-08 02:58:12 +08:00
if ( enum_values )
2010-06-09 00:52:24 +08:00
{
2011-10-08 02:58:12 +08:00
if ( s & & s [ 0 ] )
2010-06-09 00:52:24 +08:00
{
2011-10-08 02:58:12 +08:00
for ( int i = 0 ; enum_values [ i ] . string_value ! = NULL ; i + + )
2010-06-09 00:52:24 +08:00
{
2011-10-08 02:58:12 +08:00
if ( strstr ( enum_values [ i ] . string_value , s ) = = enum_values [ i ] . string_value )
{
error . Clear ( ) ;
return enum_values [ i ] . value ;
}
2010-06-09 00:52:24 +08:00
}
}
2011-10-08 02:58:12 +08:00
StreamString strm ;
strm . PutCString ( " invalid enumeration value, valid values are: " ) ;
for ( int i = 0 ; enum_values [ i ] . string_value ! = NULL ; i + + )
{
strm . Printf ( " %s \" %s \" " ,
i > 0 ? " , " : " " ,
enum_values [ i ] . string_value ) ;
}
error . SetErrorString ( strm . GetData ( ) ) ;
}
else
{
error . SetErrorString ( " invalid enumeration argument " ) ;
2010-06-09 00:52:24 +08:00
}
return fail_value ;
}
ScriptLanguage
Args : : StringToScriptLanguage ( const char * s , ScriptLanguage fail_value , bool * success_ptr )
{
if ( s & & s [ 0 ] )
{
if ( ( : : strcasecmp ( s , " python " ) = = 0 ) | |
( : : strcasecmp ( s , " default " ) = = 0 & & eScriptLanguagePython = = eScriptLanguageDefault ) )
{
if ( success_ptr ) * success_ptr = true ;
return eScriptLanguagePython ;
}
if ( : : strcasecmp ( s , " none " ) )
{
if ( success_ptr ) * success_ptr = true ;
return eScriptLanguageNone ;
}
}
if ( success_ptr ) * success_ptr = false ;
return fail_value ;
}
Error
Args : : StringToFormat
(
const char * s ,
2011-04-29 04:55:26 +08:00
lldb : : Format & format ,
2013-01-26 02:06:21 +08:00
size_t * byte_size_ptr
2010-06-09 00:52:24 +08:00
)
{
format = eFormatInvalid ;
Error error ;
if ( s & & s [ 0 ] )
{
2011-04-29 04:55:26 +08:00
if ( byte_size_ptr )
2010-06-09 00:52:24 +08:00
{
2011-04-29 04:55:26 +08:00
if ( isdigit ( s [ 0 ] ) )
{
char * format_char = NULL ;
unsigned long byte_size = : : strtoul ( s , & format_char , 0 ) ;
if ( byte_size ! = ULONG_MAX )
* byte_size_ptr = byte_size ;
s = format_char ;
}
else
* byte_size_ptr = 0 ;
}
2011-06-24 05:22:24 +08:00
const bool partial_match_ok = true ;
if ( ! FormatManager : : GetFormatFromCString ( s , partial_match_ok , format ) )
2011-04-29 04:55:26 +08:00
{
2011-06-24 05:22:24 +08:00
StreamString error_strm ;
error_strm . Printf ( " Invalid format character or name '%s'. Valid values are: \n " , s ) ;
2011-06-24 09:12:22 +08:00
for ( Format f = eFormatDefault ; f < kNumFormats ; f = Format ( f + 1 ) )
2011-04-29 04:55:26 +08:00
{
2011-06-24 05:22:24 +08:00
char format_char = FormatManager : : GetFormatAsFormatChar ( f ) ;
if ( format_char )
error_strm . Printf ( " '%c' or " , format_char ) ;
error_strm . Printf ( " \" %s \" " , FormatManager : : GetFormatAsCString ( f ) ) ;
error_strm . EOL ( ) ;
2011-04-29 04:55:26 +08:00
}
2011-06-24 05:22:24 +08:00
if ( byte_size_ptr )
error_strm . PutCString ( " An optional byte size can precede the format character. \n " ) ;
error . SetErrorString ( error_strm . GetString ( ) . c_str ( ) ) ;
2011-04-29 04:55:26 +08:00
}
2010-06-09 00:52:24 +08:00
if ( error . Fail ( ) )
return error ;
}
else
{
2011-10-26 08:56:27 +08:00
error . SetErrorStringWithFormat ( " %s option string " , s ? " empty " : " invalid " ) ;
2010-06-09 00:52:24 +08:00
}
return error ;
}
2012-08-24 09:42:50 +08:00
lldb : : Encoding
Args : : StringToEncoding ( const char * s , lldb : : Encoding fail_value )
{
if ( s & & s [ 0 ] )
{
if ( strcmp ( s , " uint " ) = = 0 )
return eEncodingUint ;
else if ( strcmp ( s , " sint " ) = = 0 )
return eEncodingSint ;
else if ( strcmp ( s , " ieee754 " ) = = 0 )
return eEncodingIEEE754 ;
else if ( strcmp ( s , " vector " ) = = 0 )
return eEncodingVector ;
}
return fail_value ;
}
uint32_t
Args : : StringToGenericRegister ( const char * s )
{
if ( s & & s [ 0 ] )
{
if ( strcmp ( s , " pc " ) = = 0 )
return LLDB_REGNUM_GENERIC_PC ;
else if ( strcmp ( s , " sp " ) = = 0 )
return LLDB_REGNUM_GENERIC_SP ;
else if ( strcmp ( s , " fp " ) = = 0 )
return LLDB_REGNUM_GENERIC_FP ;
else if ( strcmp ( s , " ra " ) = = 0 )
return LLDB_REGNUM_GENERIC_RA ;
else if ( strcmp ( s , " flags " ) = = 0 )
return LLDB_REGNUM_GENERIC_FLAGS ;
else if ( strncmp ( s , " arg " , 3 ) = = 0 )
{
if ( s [ 3 ] & & s [ 4 ] = = ' \0 ' )
{
switch ( s [ 3 ] )
{
case ' 1 ' : return LLDB_REGNUM_GENERIC_ARG1 ;
case ' 2 ' : return LLDB_REGNUM_GENERIC_ARG2 ;
case ' 3 ' : return LLDB_REGNUM_GENERIC_ARG3 ;
case ' 4 ' : return LLDB_REGNUM_GENERIC_ARG4 ;
case ' 5 ' : return LLDB_REGNUM_GENERIC_ARG5 ;
case ' 6 ' : return LLDB_REGNUM_GENERIC_ARG6 ;
case ' 7 ' : return LLDB_REGNUM_GENERIC_ARG7 ;
case ' 8 ' : return LLDB_REGNUM_GENERIC_ARG8 ;
}
}
}
}
return LLDB_INVALID_REGNUM ;
}
2010-06-09 00:52:24 +08:00
void
Args : : LongestCommonPrefix ( std : : string & common_prefix )
{
arg_sstr_collection : : iterator pos , end = m_args . end ( ) ;
pos = m_args . begin ( ) ;
if ( pos = = end )
common_prefix . clear ( ) ;
else
common_prefix = ( * pos ) ;
for ( + + pos ; pos ! = end ; + + pos )
{
2010-07-10 04:39:50 +08:00
size_t new_size = ( * pos ) . size ( ) ;
2010-06-09 00:52:24 +08:00
// First trim common_prefix if it is longer than the current element:
if ( common_prefix . size ( ) > new_size )
common_prefix . erase ( new_size ) ;
// Then trim it at the first disparity:
2010-07-10 04:39:50 +08:00
for ( size_t i = 0 ; i < common_prefix . size ( ) ; i + + )
2010-06-09 00:52:24 +08:00
{
if ( ( * pos ) [ i ] ! = common_prefix [ i ] )
{
common_prefix . erase ( i ) ;
break ;
}
}
// If we've emptied the common prefix, we're done.
if ( common_prefix . empty ( ) )
break ;
}
}
2010-12-08 03:58:26 +08:00
size_t
2013-09-06 00:42:23 +08:00
Args : : FindArgumentIndexForOption ( Option * long_options , int long_options_index )
2010-12-08 03:58:26 +08:00
{
char short_buffer [ 3 ] ;
char long_buffer [ 255 ] ;
2012-12-04 08:32:51 +08:00
: : snprintf ( short_buffer , sizeof ( short_buffer ) , " -%c " , long_options [ long_options_index ] . val ) ;
2010-12-08 03:58:26 +08:00
: : snprintf ( long_buffer , sizeof ( long_buffer ) , " --%s " , long_options [ long_options_index ] . name ) ;
size_t end = GetArgumentCount ( ) ;
size_t idx = 0 ;
while ( idx < end )
{
if ( ( : : strncmp ( GetArgumentAtIndex ( idx ) , short_buffer , strlen ( short_buffer ) ) = = 0 )
| | ( : : strncmp ( GetArgumentAtIndex ( idx ) , long_buffer , strlen ( long_buffer ) ) = = 0 ) )
{
return idx ;
}
+ + idx ;
}
return end ;
}
bool
Args : : IsPositionalArgument ( const char * arg )
{
if ( arg = = NULL )
return false ;
bool is_positional = true ;
char * cptr = ( char * ) arg ;
if ( cptr [ 0 ] = = ' % ' )
{
+ + cptr ;
while ( isdigit ( cptr [ 0 ] ) )
+ + cptr ;
if ( cptr [ 0 ] ! = ' \0 ' )
is_positional = false ;
}
else
is_positional = false ;
return is_positional ;
}
2010-06-09 00:52:24 +08:00
void
2010-10-13 01:45:19 +08:00
Args : : ParseAliasOptions ( Options & options ,
CommandReturnObject & result ,
2010-12-10 06:52:49 +08:00
OptionArgVector * option_arg_vector ,
std : : string & raw_input_string )
2010-06-09 00:52:24 +08:00
{
StreamString sstr ;
int i ;
2013-09-06 00:42:23 +08:00
Option * long_options = options . GetLongOptions ( ) ;
2010-06-09 00:52:24 +08:00
if ( long_options = = NULL )
{
result . AppendError ( " invalid long options " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return ;
}
for ( i = 0 ; long_options [ i ] . name ! = NULL ; + + i )
{
if ( long_options [ i ] . flag = = NULL )
{
sstr < < ( char ) long_options [ i ] . val ;
switch ( long_options [ i ] . has_arg )
{
default :
2013-09-06 00:42:23 +08:00
case OptionParser : : eNoArgument :
2010-06-09 00:52:24 +08:00
break ;
2013-09-06 00:42:23 +08:00
case OptionParser : : eRequiredArgument :
2010-06-09 00:52:24 +08:00
sstr < < " : " ;
break ;
2013-09-06 00:42:23 +08:00
case OptionParser : : eOptionalArgument :
2010-06-09 00:52:24 +08:00
sstr < < " :: " ;
break ;
}
}
}
2013-09-06 00:42:23 +08:00
OptionParser : : Prepare ( ) ;
2010-06-09 00:52:24 +08:00
int val ;
while ( 1 )
{
int long_options_index = - 1 ;
2013-09-06 00:42:23 +08:00
val = OptionParser : : Parse ( GetArgumentCount ( ) ,
2013-04-05 04:35:24 +08:00
GetArgumentVector ( ) ,
sstr . GetData ( ) ,
long_options ,
& long_options_index ) ;
2010-06-09 00:52:24 +08:00
if ( val = = - 1 )
break ;
if ( val = = ' ? ' )
{
result . AppendError ( " unknown or ambiguous option " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
break ;
}
if ( val = = 0 )
continue ;
( ( Options * ) & options ) - > OptionSeen ( val ) ;
// Look up the long option index
if ( long_options_index = = - 1 )
{
for ( int j = 0 ;
long_options [ j ] . name | | long_options [ j ] . has_arg | | long_options [ j ] . flag | | long_options [ j ] . val ;
+ + j )
{
if ( long_options [ j ] . val = = val )
{
long_options_index = j ;
break ;
}
}
}
// See if the option takes an argument, and see if one was supplied.
if ( long_options_index > = 0 )
{
StreamString option_str ;
2012-12-04 08:32:51 +08:00
option_str . Printf ( " -%c " , val ) ;
2010-06-09 00:52:24 +08:00
switch ( long_options [ long_options_index ] . has_arg )
{
2013-09-06 00:42:23 +08:00
case OptionParser : : eNoArgument :
2010-12-08 03:58:26 +08:00
option_arg_vector - > push_back ( OptionArgPair ( std : : string ( option_str . GetData ( ) ) ,
2013-09-06 00:42:23 +08:00
OptionArgValue ( OptionParser : : eNoArgument , " <no-argument> " ) ) ) ;
2010-09-12 12:48:45 +08:00
result . SetStatus ( eReturnStatusSuccessFinishNoResult ) ;
2010-06-09 00:52:24 +08:00
break ;
2013-09-06 00:42:23 +08:00
case OptionParser : : eRequiredArgument :
if ( OptionParser : : GetOptionArgument ( ) ! = NULL )
2010-06-09 00:52:24 +08:00
{
option_arg_vector - > push_back ( OptionArgPair ( std : : string ( option_str . GetData ( ) ) ,
2013-09-06 00:42:23 +08:00
OptionArgValue ( OptionParser : : eRequiredArgument ,
std : : string ( OptionParser : : GetOptionArgument ( ) ) ) ) ) ;
2010-06-09 00:52:24 +08:00
result . SetStatus ( eReturnStatusSuccessFinishNoResult ) ;
}
else
{
result . AppendErrorWithFormat ( " Option '%s' is missing argument specifier. \n " ,
option_str . GetData ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
break ;
2013-09-06 00:42:23 +08:00
case OptionParser : : eOptionalArgument :
if ( OptionParser : : GetOptionArgument ( ) ! = NULL )
2010-06-09 00:52:24 +08:00
{
option_arg_vector - > push_back ( OptionArgPair ( std : : string ( option_str . GetData ( ) ) ,
2013-09-06 00:42:23 +08:00
OptionArgValue ( OptionParser : : eOptionalArgument ,
std : : string ( OptionParser : : GetOptionArgument ( ) ) ) ) ) ;
2010-06-09 00:52:24 +08:00
result . SetStatus ( eReturnStatusSuccessFinishNoResult ) ;
}
else
{
option_arg_vector - > push_back ( OptionArgPair ( std : : string ( option_str . GetData ( ) ) ,
2013-09-06 00:42:23 +08:00
OptionArgValue ( OptionParser : : eOptionalArgument , " <no-argument> " ) ) ) ;
2010-06-09 00:52:24 +08:00
result . SetStatus ( eReturnStatusSuccessFinishNoResult ) ;
}
break ;
default :
2012-12-04 08:32:51 +08:00
result . AppendErrorWithFormat ( " error with options table; invalid value in has_arg field for option '%c'. \n " , val ) ;
2010-06-09 00:52:24 +08:00
result . SetStatus ( eReturnStatusFailed ) ;
break ;
}
}
else
{
2012-12-04 08:32:51 +08:00
result . AppendErrorWithFormat ( " Invalid option with value '%c'. \n " , val ) ;
2010-06-09 00:52:24 +08:00
result . SetStatus ( eReturnStatusFailed ) ;
}
2010-10-13 01:45:19 +08:00
if ( long_options_index > = 0 )
{
// Find option in the argument list; also see if it was supposed to take an argument and if one was
2010-12-10 06:52:49 +08:00
// supplied. Remove option (and argument, if given) from the argument list. Also remove them from
// the raw_input_string, if one was passed in.
2010-12-08 03:58:26 +08:00
size_t idx = FindArgumentIndexForOption ( long_options , long_options_index ) ;
if ( idx < GetArgumentCount ( ) )
{
2010-12-10 06:52:49 +08:00
if ( raw_input_string . size ( ) > 0 )
{
const char * tmp_arg = GetArgumentAtIndex ( idx ) ;
size_t pos = raw_input_string . find ( tmp_arg ) ;
if ( pos ! = std : : string : : npos )
raw_input_string . erase ( pos , strlen ( tmp_arg ) ) ;
}
2010-12-08 03:58:26 +08:00
ReplaceArgumentAtIndex ( idx , " " ) ;
2013-09-06 00:42:23 +08:00
if ( ( long_options [ long_options_index ] . has_arg ! = OptionParser : : eNoArgument )
& & ( OptionParser : : GetOptionArgument ( ) ! = NULL )
2010-12-08 03:58:26 +08:00
& & ( idx + 1 < GetArgumentCount ( ) )
2013-09-06 00:42:23 +08:00
& & ( strcmp ( OptionParser : : GetOptionArgument ( ) , GetArgumentAtIndex ( idx + 1 ) ) = = 0 ) )
2010-12-10 06:52:49 +08:00
{
if ( raw_input_string . size ( ) > 0 )
{
const char * tmp_arg = GetArgumentAtIndex ( idx + 1 ) ;
size_t pos = raw_input_string . find ( tmp_arg ) ;
if ( pos ! = std : : string : : npos )
raw_input_string . erase ( pos , strlen ( tmp_arg ) ) ;
}
2010-12-08 03:58:26 +08:00
ReplaceArgumentAtIndex ( idx + 1 , " " ) ;
2010-12-10 06:52:49 +08:00
}
2010-12-08 03:58:26 +08:00
}
2010-10-13 01:45:19 +08:00
}
2010-06-09 00:52:24 +08:00
if ( ! result . Succeeded ( ) )
break ;
}
}
void
Args : : ParseArgsForCompletion
(
Options & options ,
2010-06-25 04:31:04 +08:00
OptionElementVector & option_element_vector ,
uint32_t cursor_index
2010-06-09 00:52:24 +08:00
)
{
StreamString sstr ;
2013-09-06 00:42:23 +08:00
Option * long_options = options . GetLongOptions ( ) ;
2010-06-09 00:52:24 +08:00
option_element_vector . clear ( ) ;
if ( long_options = = NULL )
{
return ;
}
// Leading : tells getopt to return a : for a missing option argument AND
// to suppress error messages.
sstr < < " : " ;
2010-07-14 08:18:15 +08:00
for ( int i = 0 ; long_options [ i ] . name ! = NULL ; + + i )
2010-06-09 00:52:24 +08:00
{
if ( long_options [ i ] . flag = = NULL )
{
sstr < < ( char ) long_options [ i ] . val ;
switch ( long_options [ i ] . has_arg )
{
default :
2013-09-06 00:42:23 +08:00
case OptionParser : : eNoArgument :
2010-06-09 00:52:24 +08:00
break ;
2013-09-06 00:42:23 +08:00
case OptionParser : : eRequiredArgument :
2010-06-09 00:52:24 +08:00
sstr < < " : " ;
break ;
2013-09-06 00:42:23 +08:00
case OptionParser : : eOptionalArgument :
2010-06-09 00:52:24 +08:00
sstr < < " :: " ;
break ;
}
}
}
2013-09-06 00:42:23 +08:00
OptionParser : : Prepare ( ) ;
OptionParser : : EnableError ( false ) ;
2010-06-09 00:52:24 +08:00
int val ;
const OptionDefinition * opt_defs = options . GetDefinitions ( ) ;
2013-09-06 00:42:23 +08:00
// Fooey... OptionParser::Parse permutes the GetArgumentVector to move the options to the front.
// So we have to build another Arg and pass that to OptionParser::Parse so it doesn't
2010-06-25 04:31:04 +08:00
// change the one we have.
2010-06-09 00:52:24 +08:00
2010-07-10 04:39:50 +08:00
std : : vector < const char * > dummy_vec ( GetArgumentVector ( ) , GetArgumentVector ( ) + GetArgumentCount ( ) + 1 ) ;
2010-06-09 00:52:24 +08:00
2010-06-25 04:31:04 +08:00
bool failed_once = false ;
uint32_t dash_dash_pos = - 1 ;
2010-06-09 00:52:24 +08:00
while ( 1 )
{
bool missing_argument = false ;
int long_options_index = - 1 ;
2010-06-25 04:31:04 +08:00
2013-09-06 00:42:23 +08:00
val = OptionParser : : Parse ( dummy_vec . size ( ) - 1 ,
2013-04-05 04:35:24 +08:00
( char * const * ) & dummy_vec . front ( ) ,
sstr . GetData ( ) ,
long_options ,
& long_options_index ) ;
2010-06-09 00:52:24 +08:00
if ( val = = - 1 )
2010-06-25 04:31:04 +08:00
{
// When we're completing a "--" which is the last option on line,
if ( failed_once )
break ;
failed_once = true ;
// If this is a bare "--" we mark it as such so we can complete it successfully later.
// Handling the "--" is a little tricky, since that may mean end of options or arguments, or the
// user might want to complete options by long name. I make this work by checking whether the
// cursor is in the "--" argument, and if so I assume we're completing the long option, otherwise
2013-09-06 00:42:23 +08:00
// I let it pass to OptionParser::Parse which will terminate the option parsing.
2010-06-25 04:31:04 +08:00
// Note, in either case we continue parsing the line so we can figure out what other options
// were passed. This will be useful when we come to restricting completions based on what other
// options we've seen on the line.
2013-09-06 00:42:23 +08:00
if ( OptionParser : : GetOptionIndex ( ) < dummy_vec . size ( ) - 1
& & ( strcmp ( dummy_vec [ OptionParser : : GetOptionIndex ( ) - 1 ] , " -- " ) = = 0 ) )
2010-06-25 04:31:04 +08:00
{
2013-09-06 00:42:23 +08:00
dash_dash_pos = OptionParser : : GetOptionIndex ( ) - 1 ;
if ( OptionParser : : GetOptionIndex ( ) - 1 = = cursor_index )
2010-06-25 04:31:04 +08:00
{
2013-09-06 00:42:23 +08:00
option_element_vector . push_back ( OptionArgElement ( OptionArgElement : : eBareDoubleDash , OptionParser : : GetOptionIndex ( ) - 1 ,
2010-06-25 04:31:04 +08:00
OptionArgElement : : eBareDoubleDash ) ) ;
continue ;
}
else
break ;
}
else
break ;
}
2010-06-09 00:52:24 +08:00
else if ( val = = ' ? ' )
{
2013-09-06 00:42:23 +08:00
option_element_vector . push_back ( OptionArgElement ( OptionArgElement : : eUnrecognizedArg , OptionParser : : GetOptionIndex ( ) - 1 ,
2010-06-25 04:31:04 +08:00
OptionArgElement : : eUnrecognizedArg ) ) ;
2010-06-09 00:52:24 +08:00
continue ;
}
else if ( val = = 0 )
{
continue ;
}
else if ( val = = ' : ' )
{
// This is a missing argument.
2013-09-06 00:42:23 +08:00
val = OptionParser : : GetOptionErrorCause ( ) ;
2010-06-09 00:52:24 +08:00
missing_argument = true ;
}
( ( Options * ) & options ) - > OptionSeen ( val ) ;
// Look up the long option index
if ( long_options_index = = - 1 )
{
for ( int j = 0 ;
long_options [ j ] . name | | long_options [ j ] . has_arg | | long_options [ j ] . flag | | long_options [ j ] . val ;
+ + j )
{
if ( long_options [ j ] . val = = val )
{
long_options_index = j ;
break ;
}
}
}
// See if the option takes an argument, and see if one was supplied.
if ( long_options_index > = 0 )
{
int opt_defs_index = - 1 ;
for ( int i = 0 ; ; i + + )
{
if ( opt_defs [ i ] . short_option = = 0 )
break ;
else if ( opt_defs [ i ] . short_option = = val )
{
opt_defs_index = i ;
break ;
}
}
switch ( long_options [ long_options_index ] . has_arg )
{
2013-09-06 00:42:23 +08:00
case OptionParser : : eNoArgument :
option_element_vector . push_back ( OptionArgElement ( opt_defs_index , OptionParser : : GetOptionIndex ( ) - 1 , 0 ) ) ;
2010-06-09 00:52:24 +08:00
break ;
2013-09-06 00:42:23 +08:00
case OptionParser : : eRequiredArgument :
if ( OptionParser : : GetOptionArgument ( ) ! = NULL )
2010-06-09 00:52:24 +08:00
{
int arg_index ;
if ( missing_argument )
arg_index = - 1 ;
else
2013-09-06 00:42:23 +08:00
arg_index = OptionParser : : GetOptionIndex ( ) - 1 ;
2010-06-09 00:52:24 +08:00
2013-09-06 00:42:23 +08:00
option_element_vector . push_back ( OptionArgElement ( opt_defs_index , OptionParser : : GetOptionIndex ( ) - 2 , arg_index ) ) ;
2010-06-09 00:52:24 +08:00
}
else
{
2013-09-06 00:42:23 +08:00
option_element_vector . push_back ( OptionArgElement ( opt_defs_index , OptionParser : : GetOptionIndex ( ) - 1 , - 1 ) ) ;
2010-06-09 00:52:24 +08:00
}
break ;
2013-09-06 00:42:23 +08:00
case OptionParser : : eOptionalArgument :
if ( OptionParser : : GetOptionArgument ( ) ! = NULL )
2010-06-09 00:52:24 +08:00
{
2013-09-06 00:42:23 +08:00
option_element_vector . push_back ( OptionArgElement ( opt_defs_index , OptionParser : : GetOptionIndex ( ) - 2 , OptionParser : : GetOptionIndex ( ) - 1 ) ) ;
2010-06-09 00:52:24 +08:00
}
else
{
2013-09-06 00:42:23 +08:00
option_element_vector . push_back ( OptionArgElement ( opt_defs_index , OptionParser : : GetOptionIndex ( ) - 2 , OptionParser : : GetOptionIndex ( ) - 1 ) ) ;
2010-06-09 00:52:24 +08:00
}
break ;
default :
// The options table is messed up. Here we'll just continue
2013-09-06 00:42:23 +08:00
option_element_vector . push_back ( OptionArgElement ( OptionArgElement : : eUnrecognizedArg , OptionParser : : GetOptionIndex ( ) - 1 ,
2010-06-25 04:31:04 +08:00
OptionArgElement : : eUnrecognizedArg ) ) ;
2010-06-09 00:52:24 +08:00
break ;
}
}
else
{
2013-09-06 00:42:23 +08:00
option_element_vector . push_back ( OptionArgElement ( OptionArgElement : : eUnrecognizedArg , OptionParser : : GetOptionIndex ( ) - 1 ,
2010-06-25 04:31:04 +08:00
OptionArgElement : : eUnrecognizedArg ) ) ;
2010-06-09 00:52:24 +08:00
}
}
2010-06-25 04:31:04 +08:00
// Finally we have to handle the case where the cursor index points at a single "-". We want to mark that in
2013-09-06 00:42:23 +08:00
// the option_element_vector, but only if it is not after the "--". But it turns out that OptionParser::Parse just ignores
2010-06-25 04:31:04 +08:00
// an isolated "-". So we have to look it up by hand here. We only care if it is AT the cursor position.
if ( ( dash_dash_pos = = - 1 | | cursor_index < dash_dash_pos )
& & strcmp ( GetArgumentAtIndex ( cursor_index ) , " - " ) = = 0 )
{
option_element_vector . push_back ( OptionArgElement ( OptionArgElement : : eBareDash , cursor_index ,
OptionArgElement : : eBareDash ) ) ;
}
2010-06-09 00:52:24 +08:00
}
2012-09-01 08:38:36 +08:00
void
Args : : EncodeEscapeSequences ( const char * src , std : : string & dst )
{
dst . clear ( ) ;
if ( src )
{
for ( const char * p = src ; * p ! = ' \0 ' ; + + p )
{
size_t non_special_chars = : : strcspn ( p , " \\ " ) ;
if ( non_special_chars > 0 )
{
dst . append ( p , non_special_chars ) ;
p + = non_special_chars ;
if ( * p = = ' \0 ' )
break ;
}
if ( * p = = ' \\ ' )
{
+ + p ; // skip the slash
switch ( * p )
{
case ' a ' : dst . append ( 1 , ' \a ' ) ; break ;
case ' b ' : dst . append ( 1 , ' \b ' ) ; break ;
case ' f ' : dst . append ( 1 , ' \f ' ) ; break ;
case ' n ' : dst . append ( 1 , ' \n ' ) ; break ;
case ' r ' : dst . append ( 1 , ' \r ' ) ; break ;
case ' t ' : dst . append ( 1 , ' \t ' ) ; break ;
case ' v ' : dst . append ( 1 , ' \v ' ) ; break ;
case ' \\ ' : dst . append ( 1 , ' \\ ' ) ; break ;
case ' \' ' : dst . append ( 1 , ' \' ' ) ; break ;
case ' " ' : dst . append ( 1 , ' " ' ) ; break ;
case ' 0 ' :
// 1 to 3 octal chars
{
// Make a string that can hold onto the initial zero char,
// up to 3 octal digits, and a terminating NULL.
char oct_str [ 5 ] = { ' \0 ' , ' \0 ' , ' \0 ' , ' \0 ' , ' \0 ' } ;
int i ;
for ( i = 0 ; ( p [ i ] > = ' 0 ' & & p [ i ] < = ' 7 ' ) & & i < 4 ; + + i )
oct_str [ i ] = p [ i ] ;
// We don't want to consume the last octal character since
// the main for loop will do this for us, so we advance p by
// one less than i (even if i is zero)
p + = i - 1 ;
unsigned long octal_value = : : strtoul ( oct_str , NULL , 8 ) ;
if ( octal_value < = UINT8_MAX )
{
2013-01-26 02:06:21 +08:00
dst . append ( 1 , ( char ) octal_value ) ;
2012-09-01 08:38:36 +08:00
}
}
break ;
case ' x ' :
// hex number in the format
if ( isxdigit ( p [ 1 ] ) )
{
+ + p ; // Skip the 'x'
// Make a string that can hold onto two hex chars plus a
// NULL terminator
char hex_str [ 3 ] = { * p , ' \0 ' , ' \0 ' } ;
if ( isxdigit ( p [ 1 ] ) )
{
+ + p ; // Skip the first of the two hex chars
hex_str [ 1 ] = * p ;
}
unsigned long hex_value = strtoul ( hex_str , NULL , 16 ) ;
if ( hex_value < = UINT8_MAX )
dst . append ( 1 , ( char ) hex_value ) ;
}
else
{
dst . append ( 1 , ' x ' ) ;
}
break ;
default :
// Just desensitize any other character by just printing what
// came after the '\'
dst . append ( 1 , * p ) ;
break ;
}
}
}
}
}
void
Args : : ExpandEscapedCharacters ( const char * src , std : : string & dst )
{
dst . clear ( ) ;
if ( src )
{
for ( const char * p = src ; * p ! = ' \0 ' ; + + p )
{
2012-12-06 04:24:57 +08:00
if ( isprint8 ( * p ) )
2012-09-01 08:38:36 +08:00
dst . append ( 1 , * p ) ;
else
{
switch ( * p )
{
case ' \a ' : dst . append ( " \\ a " ) ; break ;
case ' \b ' : dst . append ( " \\ b " ) ; break ;
case ' \f ' : dst . append ( " \\ f " ) ; break ;
case ' \n ' : dst . append ( " \\ n " ) ; break ;
case ' \r ' : dst . append ( " \\ r " ) ; break ;
case ' \t ' : dst . append ( " \\ t " ) ; break ;
case ' \v ' : dst . append ( " \\ v " ) ; break ;
case ' \' ' : dst . append ( " \\ ' " ) ; break ;
case ' " ' : dst . append ( " \\ \" " ) ; break ;
case ' \\ ' : dst . append ( " \\ \\ " ) ; break ;
default :
{
// Just encode as octal
dst . append ( " \\ 0 " ) ;
char octal_str [ 32 ] ;
snprintf ( octal_str , sizeof ( octal_str ) , " %o " , * p ) ;
dst . append ( octal_str ) ;
}
break ;
}
}
}
}
}