@ -5,7 +5,7 @@
*/
/*
* Copyright ( c ) 2016 - 20 17 , Tomasz Sowa
* Copyright ( c ) 2016 - 20 2 1, Tomasz Sowa
* All rights reserved .
*
* Redistribution and use in source and binary forms , with or without
@ -40,100 +40,131 @@
# include "utf8/utf8.h"
# include <string.h>
// REMOVE ME
# include <iostream>
namespace PT
{
# ifdef nonexisting_value
MainSpaceParser : : MainSpaceParser ( )
{
space = 0 ;
options _space = 0 ;
use_utf8 = true ;
arguments_required _space = 0 ;
should_ use_utf8 = true ;
last_status = status_ok ;
non_option_arguments_name = L " args " ;
}
MainSpaceParser : : ~ MainSpaceParser ( )
{
}
void MainSpaceParser : : use_utf8 ( bool utf8 )
{
should_use_utf8 = utf8 ;
}
void MainSpaceParser : : UTF8( bool utf8 )
void MainSpaceParser : : set_non_options_arguments_name( const wchar_t * name )
{
use_utf8 = utf8 ;
non_option_arguments_name = name ;
}
void MainSpaceParser : : SetSpace( Space & space_ref )
void MainSpaceParser : : set_non_options_arguments_name( const std : : wstring & name )
{
space = & space_ref ;
options_space = 0 ;
non_option_arguments_name = name ;
}
std : : wstring & MainSpaceParser : : GetErrorToken ( )
std : : wstring & MainSpaceParser : : get_wrong_option ( )
{
return last_error_option ;
}
MainSpaceParser : : Status MainSpaceParser : : parse ( int argc , const char * * argv , Space & out_space )
{
return last_error_token ;
space = & out_space ;
arguments_required_space = nullptr ;
return parse ( argc , argv ) ;
}
MainSpaceParser : : Status MainSpaceParser : : Parse ( int argc , const char * * argv )
MainSpaceParser : : Status MainSpaceParser : : p arse( int argc , const char * * argv , Space & out_space , const Space & options )
{
if ( ! space )
{
return status_space_not_assigned ;
}
space = & out_space ;
arguments_required_space = & options ; ;
options_space = space - > FindSpace ( L " options " ) ;
last_status = status_ok ;
last_error_token . clear ( ) ;
return parse ( argc , argv ) ;
}
MainSpaceParser : : Status MainSpaceParser : : parse ( int argc , const char * * argv )
{
last_status = status_ok ;
last_error_option . clear ( ) ;
for ( size_t i = 1 ; i < ( size_t ) argc & & last_status = = status_ok ; )
{
Parse ( ( size_t ) argc , argv , i ) ;
p arse( ( size_t ) argc , argv , i ) ;
}
options . clear ( ) ;
option . clear ( ) ;
argument . clear ( ) ;
arguments . clear ( ) ;
return last_status ;
}
void MainSpaceParser : : Parse ( size_t argc , const char * * argv , size_t & argv_index )
void MainSpaceParser : : p arse( size_t argc , const char * * argv , size_t & argv_index )
{
const char * pchar = argv [ argv_index ] ;
if ( * pchar = = ' - ' )
{
if ( * ( pchar + 1 ) = = ' - ' & & * ( pchar + 2 ) = = 0 )
{
// two hyphens only "--"
argv_index + = 1 ;
parse_non_option_arguments ( argc , argv , argv_index ) ;
}
else
if ( * ( pchar + 1 ) = = ' - ' )
{
ParseMultiArgument ( argc , argv , argv_index ) ;
// two hyphens and a string, such as "--abc"
parse_long_option ( argc , argv , argv_index ) ;
}
else
if ( * ( pchar + 1 ) ! = 0 )
{
// one hyphen and a string, such as "-abc"
parse_short_option ( argc , argv , argv_index ) ;
}
else
{
ParseSingleArgument ( argc , argv , argv_index ) ;
parse_non_option_arguments ( argc , argv , argv_index ) ;
}
}
else
{
last_status = status_syntax_error ;
ConvertStr ( pchar , last_error_token ) ;
parse_non_option_arguments ( argc , argv , argv_index ) ;
}
}
void MainSpaceParser : : ConvertS tr( const char * src , std : : wstring & dst )
void MainSpaceParser : : convert_s tr( const char * src , std : : wstring & dst )
{
if ( use_utf8 )
if ( should_ use_utf8 )
{
PT : : UTF8ToWide ( src , dst ) ;
PT : : UTF8ToWide ( src , dst ) ;
}
else
{
@ -145,154 +176,219 @@ void MainSpaceParser::ConvertStr(const char * src, std::wstring & dst)
}
void MainSpaceParser : : ParseSingleArgument( size_t argc , const char * * argv , size_t & argv_index )
void MainSpaceParser : : convert_str( const char * src , size_t len , std : : wstring & dst )
{
ConvertStr ( argv [ argv_index ] + 1 , wide_arg ) ;
const wchar_t * wide_pchar = wide_arg . c_str ( ) ;
temp_list_val . clear ( ) ;
bool was_option = false ;
argv_index + = 1 ;
for ( ; * wide_pchar & & ! was_option ; + + wide_pchar )
if ( should_use_utf8 )
{
PT : : UTF8ToWide ( src , len , dst ) ;
}
else
{
temp_arg = * wide_pchar ;
size_t opt_size = RequireOption ( temp_arg ) ;
dst . clear ( ) ;
if ( opt_size > 0 )
{
was_option = true ;
for ( size_t i = 0 ; i < len ; + + i )
dst + = ( wchar_t ) ( unsigned char ) src [ i ] ;
}
}
if ( * ( wide_pchar + 1 ) )
{
temp_val = wide_pchar + 1 ;
temp_list_val . push_back ( temp_val ) ;
opt_size - = 1 ;
}
for ( ; opt_size > 0 & & argv_index < argc ; - - opt_size , + + argv_index )
{
ConvertStr ( argv [ argv_index ] , temp_val ) ;
temp_list_val . push_back ( temp_val ) ;
}
void MainSpaceParser : : convert_str ( const std : : wstring & src , Space & space )
{
if ( should_use_utf8 )
{
space . set_empty_wstring ( ) ;
space . value . value_wstring = src ;
}
else
{
space . set_empty_string ( ) ;
std : : string & dst = space . value . value_string ;
if ( opt_size > 0 )
{
last_status = status_reading_eof ;
last_error_token . clear ( ) ;
}
}
dst . clear ( ) ;
temp_val . clear ( ) ;
AddValueToItem ( temp_arg , temp_val , temp_list_val ) ;
for ( size_t i = 0 ; i < src . size ( ) ; + + i )
dst + = ( char ) src [ i ] ;
}
}
void MainSpaceParser : : ParseMultiArgument ( size_t argc , const char * * argv , size_t & argv_index )
void MainSpaceParser : : parse_short_option ( size_t argc , const char * * argv , size_t & argv_index )
{
ConvertStr( argv [ argv_index ] + 2 , temp_arg ) ;
argv_index + = 1 ;
convert_str( argv [ argv_index ] + 1 , options ) ;
const wchar_t * options_pchar = options . c_str ( ) ;
size_t opt_size = RequireOption ( temp_arg ) ;
temp_list_val . clear ( ) ;
arguments . clear ( ) ;
bool was_argument = false ;
argv_index + = 1 ;
if( opt_size > 0 )
for( ; * options_pchar & & ! was_argument & & last_status = = status_ok ; + + options_pchar )
{
for ( ; opt_size > 0 & & argv_index < argc ; - - opt_size , + + argv_index )
{
ConvertStr ( argv [ argv_index ] , temp_val ) ;
temp_list_val . push_back ( temp_val ) ;
}
option = * options_pchar ;
size_t args_len = how_many_arguments_required ( option ) ;
if ( opt_size > 0 )
if ( args_len > 0 )
{
last_status = status_reading_eof ;
last_error_token . clear ( ) ;
was_argument = true ;
if ( * ( options_pchar + 1 ) )
{
// first argument is directly behind the option
argument = options_pchar + 1 ;
arguments . push_back ( argument ) ;
args_len - = 1 ;
}
parse_arguments ( argc , argv , argv_index , args_len ) ;
}
}
temp_val . clear ( ) ;
AddValueToItem ( temp_arg , temp_val , temp_list_val ) ;
add_option_to_space ( option , arguments ) ;
}
}
void MainSpaceParser : : AddValueToItem ( const std : : wstring & name , const std : : wstring & empty_value , const std : : vector < std : : wstring > & list )
void MainSpaceParser : : parse_long_option ( size_t argc , const char * * argv , size_t & argv_index )
{
std : : wstring * val = space - > GetFirstValue ( name ) ;
const char * option_begin = argv [ argv_index ] + 2 ; // skip first two hyphens --
const char * option_end = option_begin ;
bool is_equal_form = false ; // is the option in the form with equal sign, such as: option=argument
if ( ! val )
while( * option_end ! = 0 & & * option_end ! = ' = ' )
{
if ( list . empty ( ) )
space - > Add ( name , empty_value ) ;
else
if ( list . size ( ) = = 1 )
space - > Add ( name , list [ 0 ] ) ;
else
space - > table [ name ] = list ; // !! IMPROVE ME there'll be a new api in space
option_end + = 1 ;
}
if ( * option_end = = ' = ' )
{
is_equal_form = true ;
convert_str ( option_begin , option_end - option_begin , option ) ;
convert_str ( option_end + 1 , argument ) ;
}
else
{
PT: : Space : : Table : : iterator i = space - > table . find ( name ) ;
PT : : Space : : Value * table_value ;
convert_str( option_begin , option ) ;
}
if ( i = = space - > table . end ( ) )
argv_index + = 1 ;
size_t args_len = how_many_arguments_required ( option ) ;
arguments . clear ( ) ;
if ( is_equal_form )
{
if ( args_len = = 0 )
{
table_value = & space - > table [ name ] ;
table_value - > push_back ( * val ) ;
//space->table_single.erase(name);
if ( ! argument . empty ( ) )
{
// report an error
last_status = status_argument_provided ;
last_error_option = option ;
}
}
else
if ( args_len = = 1 )
{
table_value = & i - > second ;
}
if ( list . empty ( ) )
{
table_value - > push_back ( empty_value ) ;
// argument can be empty in such a case: option=
// we treat it as if the argument would not be provided
if ( ! argument . empty ( ) )
{
arguments . push_back ( argument ) ;
args_len - = 1 ;
}
}
else
{
for ( const auto & list_item : list )
table_value - > push_back ( list_item ) ;
// args_len is > 1 but when using option=argument form
// we can provide only one argument
last_status = status_argument_not_provided ;
last_error_option = option ;
}
}
if ( last_status = = status_ok )
{
parse_arguments ( argc , argv , argv_index , args_len ) ;
add_option_to_space ( option , arguments ) ;
}
}
void MainSpaceParser : : parse_arguments ( size_t argc , const char * * argv , size_t & argv_index , size_t args_len )
{
for ( ; args_len > 0 & & argv_index < argc ; - - args_len , + + argv_index )
{
convert_str ( argv [ argv_index ] , argument ) ;
arguments . push_back ( argument ) ;
}
if ( args_len > 0 )
{
last_status = status_argument_not_provided ;
last_error_option = option ;
}
}
size_t MainSpaceParser : : RequireOption ( const std : : wstring & arg )
void MainSpaceParser : : parse_non_option_arguments ( size_t argc , const char * * argv , size_t & argv_index )
{
size_t res = 0 ;
Space * table_with_args = new Space ( ) ;
table_with_args - > set_empty_table ( ) ;
if ( options_space )
for( ; argv_index < argc ; + + argv_index )
{
std : : wstring * val = options_space - > GetFirstValue ( arg ) ;
convert_str ( argv [ argv_index ] , argument ) ;
table_with_args - > add ( argument ) ;
}
space - > add ( non_option_arguments_name , table_with_args ) ;
}
if ( val )
{
/*
* IMPLEMENT ME
* add a converter to convert / inttostr . h
*
*/
long res_long = wcstol ( val - > c_str ( ) , 0 , 10 ) ;
void MainSpaceParser : : add_option_to_space ( const std : : wstring & option , const std : : vector < std : : wstring > & arguments )
{
Space * option_table = space - > get_object_field ( option ) ;
if ( res_long < 0 )
res_long = 0 ;
if ( ! option_table )
{
option_table = & space - > add_empty_space ( option ) ;
}
res = ( size_t ) res_long ;
if ( ! option_table - > is_table ( ) )
{
option_table - > set_empty_table ( ) ;
}
//std::wcout << L"argument " << arg << L" needs " << res << L" options" << std::endl;
}
Space * arguments_table = new Space ( ) ;
arguments_table - > set_empty_table ( ) ;
for ( const std : : wstring & arg : arguments )
{
Space & space_arg = arguments_table - > add_empty_space ( ) ;
convert_str ( arg , space_arg ) ;
}
option_table - > add ( arguments_table ) ;
}
size_t MainSpaceParser : : how_many_arguments_required ( const std : : wstring & arg )
{
size_t res = 0 ;
if ( arguments_required_space & & arguments_required_space - > is_object ( ) )
{
long res_long = arguments_required_space - > to_llong ( arg , 0 ) ;
if ( res_long < 0 )
res_long = 0 ;
res = ( size_t ) res_long ;
// argument 'arg' needs 'res' options
}
return res ;
}
# endif
} // namespace