$infile = "switches.def";
$outfile = "switches.cpp";

if ( @ARGV )
{
	$infile = shift @ARGV;
}

if ( @ARGV )
{
	$outfile = shift @ARGV;
}

############################################################################
## Script for generating switches.cpp
##
############################################################################

open INFILE, $infile or die;
@inf = <INFILE>;
close INFILE;

unshift @inf, "=";
unshift @inf, "=bRet = SWFN_HELP( USAGE );";
unshift @inf, "this help";
unshift @inf, "help, ?";

push @out, <<LOOP_START;

BOOL SWITCHES_Init( int* pargc, char** argv )
{
BOOL bRet = TRUE;

m_iArgsCurr = *pargc - 1;
m_iArgsOrig = 1;
m_ppcArgvOrig = argv + 1;
m_ppcArgvCurr = argv + 1;

while( m_iArgsCurr )
{
if ( !bRet )
	break;

if ( SWITCHES_GetValue() )
{
bRet = TRUE;
*( m_ppcArgvOrig++ ) = * ( m_ppcArgvCurr - 1 );
m_iArgsOrig++;
}
else
{
m_szSwitch++;

bRet = TRUE;

LOOP_START

for(;;)
{
	$line = shift @inf;

	last unless defined( $line );

	chomp $line;

	$line =~ s/\s+$//;
	$line =~ s/^\s+//;

	next unless $line;

	unshift @inf, $line;

	&switch();

};

push @out, <<LOOP_END;

printf( "Invalid switch: %s\\n", *( m_ppcArgvCurr - 1 ) );
return FALSE;
} //endif
} //while

*pargc = m_iArgsOrig;
return bRet;
}
LOOP_END

if ( $CODE_INCLUDE{ 'SWFN_GETPATH' } )
{
	unshift @out, <<SWFN_GETPATH_CODE;

BOOL SWFN_GETPATH( char* szPath )
{
char* szOrigSw = m_szSwitch;

if ( !SWITCHES_GetValue() )
{
printf( "Missing value for switch '%s'\\n", szOrigSw );
return FALSE;
}

strcpy( szPath, m_szSwitch );
return TRUE;
}

SWFN_GETPATH_CODE
}

if ( $CODE_INCLUDE{ 'SWFN_NUMH' } )
{
	unshift @out, <<SWFN_NUMH_CODE;

BOOL SWFN_NUMH( int* piNum )
{
char* szOrigSw = m_szSwitch;

if ( !SWITCHES_GetValue() )
{
printf( "Missing value for switch '%s'\\n", szOrigSw );
return FALSE;
}

sscanf( m_szSwitch, "%X", piNum );

return TRUE;
}
SWFN_NUMH_CODE
}

unshift @out, <<SWFN_HELP_CODE2;
return FALSE;
}

SWFN_HELP_CODE2

$longest = 0;

foreach $line ( @help )
{
	my ( $switch, $desc, $par ) = split( /\|/, $line, 3 );

	my $len = length( $switch ) + length( $par );

	$longest = $len if ( $len > $longest );
}

$longest += 2 + 9;
foreach $line ( @help )
{
	my ( $switch, $desc, $par ) = split( /\|/, $line, 3 );

	my $len = length( $switch ) + length( $par );

	my $l = "printf( \"-$switch";

	if ( $par )
	{
		$l .= " $par";
	}

	$l .= ' ' x ( $longest - length( $l ) );

	$l .= "  -$desc\\n\" );\n";

	push @helpf, $l;

}

unshift @out, @helpf;

unshift @out, <<SWFN_HELP_CODE1;

BOOL SWFN_HELP( const char* szUsage )
{
if ( szUsage )
	printf( "%s\\n", szUsage );
SWFN_HELP_CODE1


unshift @out, <<SWITCHES_GLOBALS;

int m_iArgsCurr;
int m_iArgsOrig;
char** m_ppcArgvOrig;
char** m_ppcArgvCurr;
char* m_szSwitch;

//gets one token from cmdline
BOOL SWITCHES_GetSwitch()
{
if ( !m_iArgsCurr )
	return FALSE;

m_szSwitch = *( m_ppcArgvCurr++ );

m_iArgsCurr--;

return TRUE;
}

//gets one token, returns TRUE if value
BOOL SWITCHES_GetValue()
{
if ( !SWITCHES_GetSwitch() )
	return FALSE;

switch( *m_szSwitch )
{
case '-':
	return FALSE;
default:
	return TRUE;
}
}

SWITCHES_GLOBALS

open OUTFILE, ">$outfile";

print OUTFILE "//THIS IS A GENERATED FILE. DO NOT EDIT!!!\n";
print OUTFILE "//EDIT $infile INSTEAD!\n\n";

$indent = 0;

$bigline = join( '', @out );
@out = split( /\n/, $bigline );

foreach $line ( @out )
{
	$indent-- if ( $line =~ /}/ );

	print OUTFILE "\t" x $indent, $line, "\n";

	$indent++ if ( $line =~ /{/ );

}

close OUTFILE;

sub switch()
{
	my $switch_desc = "";

	my $switches_names = shift @inf;
	my $switches_desc = shift @inf;

	chomp $switches_desc;

	my @switches = split( /,/, $switches_names );

	foreach $switch ( @switches )
	{
		$switch =~ s/\s+$//;
		$switch =~ s/^\s+//;

		if ( defined ( $SWITCHES{ $switch } ) )
		{
			die "Duplicate switch $switch";
		}

		$SWITCHES{ $switch } = 1;

	}

	$switches_count = @switches;

	$switch_desc = $switches[ 0 ] . "|" . $switches_desc . "|";

	push @out, "if (";

	my @asc;

	foreach $switch (@switches )
	{
		push @asc, "!strcmp( m_szSwitch, \"$switch\" )";
	}

	push @out, join( " || ", @asc );

	push @out, ")";

	push @out, "\n{\n";

	my @switch_pars = ();

	for(;;)
	{
		my $par_desc = shift @inf;

		my ( $par, $code ) = split( /=/, $par_desc, 2 );

		$par =~ s/\s+$//;
		$par =~ s/^\s+//;

		$code =~ s/\s+$//;
		$code =~ s/^\s+//;

		last if ( !$par && !$code );

		if ( $code =~ /(SWFN_\w+)/ )
		{
			$CODE_INCLUDE{ $1 } = 1;
		}

		if ( $par )
		{
			push @switch_pars, $par;
		}

		push @out, $code . "\n";
	}

	push @out, "continue;\n";

	$switch_desc .= join( ' ', @switch_pars );

	push @help, $switch_desc;

	push @out, "}\n";

}